import { useCallback, useRef } from "react"; import { saveProjectFilesWithHistory } from "../utils/studioFileHistory"; import type { EditHistoryKind } from "../utils/editHistory"; import { trackStudioEvent } from "../utils/studioTelemetry"; interface RecordEditInput { label: string; kind: EditHistoryKind; coalesceKey?: string; files: Record; } interface UseEditorSaveOptions { editingPathRef: React.RefObject; projectIdRef: React.RefObject; readProjectFile: (path: string) => Promise; writeProjectFile: (path: string, content: string) => Promise; recordEdit: (input: RecordEditInput) => Promise; domEditSaveTimestampRef: React.MutableRefObject; setRefreshKey: React.Dispatch>; } export function useEditorSave({ editingPathRef, projectIdRef, readProjectFile, writeProjectFile, recordEdit, domEditSaveTimestampRef, setRefreshKey, }: UseEditorSaveOptions) { const saveRafRef = useRef(null); const refreshRafRef = useRef(null); const handleContentChange = useCallback( (content: string) => { const pid = projectIdRef.current; if (!pid) return; const path = editingPathRef.current; if (!path) return; if (saveRafRef.current != null) cancelAnimationFrame(saveRafRef.current); saveRafRef.current = requestAnimationFrame(() => { domEditSaveTimestampRef.current = Date.now(); saveProjectFilesWithHistory({ projectId: pid, label: "Edit source", kind: "source", coalesceKey: `source:${path}`, files: { [path]: content }, readFile: readProjectFile, writeFile: writeProjectFile, recordEdit, }) .then(() => { if (refreshRafRef.current != null) cancelAnimationFrame(refreshRafRef.current); refreshRafRef.current = requestAnimationFrame(() => setRefreshKey((k) => k + 1)); }) .catch((error) => { trackStudioEvent("save_failure", { source: "code_editor", error_message: error instanceof Error ? error.message : "unknown", }); }); }); }, [ domEditSaveTimestampRef, editingPathRef, projectIdRef, readProjectFile, recordEdit, setRefreshKey, writeProjectFile, ], ); return { saveRafRef, handleContentChange, }; }