UNPKG

@pierre/diffs

Version:

153 lines (152 loc) 6.23 kB
import { areOptionsEqual } from "../../utils/areOptionsEqual.js"; import { areFileTargetsEqual } from "../../utils/areFileTargetsEqual.js"; import { getLineAnnotationName } from "../../utils/getLineAnnotationName.js"; import { File } from "../../components/File.js"; import { VirtualizedFile } from "../../components/VirtualizedFile.js"; import { useStableCallback } from "./useStableCallback.js"; import { useCreateEditor } from "../EditContext.js"; import { noopRender } from "../constants.js"; import { WorkerPoolContext } from "../WorkerPoolContext.js"; import { useVirtualizer } from "../Virtualizer.js"; import { useCallback, useContext, useEffect, useLayoutEffect, useRef } from "react"; //#region src/react/utils/useFileInstance.ts const useIsomorphicLayoutEffect = typeof window === "undefined" ? useEffect : useLayoutEffect; function useFileInstance({ file, options, editorOptions, editStateKey, lineAnnotations, selectedLines, prerenderedHTML, metrics, hasGutterRenderUtility, hasCustomHeader, disableWorkerPool, edit, onEditChange: _onEditChange, onEditComplete: _onEditComplete }) { const simpleVirtualizer = useVirtualizer(); const controlledSelection = selectedLines !== void 0; const poolManager = useContext(WorkerPoolContext); const createEditor = useCreateEditor(); const handleOnEditChange = useStableCallback((event) => _onEditChange?.(event)); const onEditChange = _onEditChange != null ? handleOnEditChange : void 0; const acceptedCache = useRef(null); const handleOnEditComplete = useStableCallback((event) => { const decision = _onEditComplete?.(event) ?? "reject"; if (decision === "accept") acceptedCache.current = { file: { installed: event.file, stale: event.originalFile }, annotations: { installed: event.lineAnnotations, stale: event.originalLineAnnotations } }; return decision; }); const onEditComplete = _onEditComplete != null ? handleOnEditComplete : void 0; const instanceRef = useRef(null); const disposeEditorRef = useRef(null); const getEditor = useStableCallback(() => { if (createEditor == null) throw new Error("File: EditContext is not attached"); return createEditor("file", editorOptions ?? {}, editStateKey); }); const ref = useStableCallback((node) => { if (node != null) { if (instanceRef.current != null) throw new Error("File: An instance should not already exist when a node is created"); if (simpleVirtualizer != null) instanceRef.current = new VirtualizedFile(mergeFileOptions({ controlledSelection, hasCustomHeader, hasGutterRenderUtility, onEditChange, onEditComplete, options }), simpleVirtualizer, metrics, !disableWorkerPool ? poolManager : void 0, true); else instanceRef.current = new File(mergeFileOptions({ controlledSelection, hasCustomHeader, hasGutterRenderUtility, onEditChange, onEditComplete, options }), !disableWorkerPool ? poolManager : void 0, true); if (edit && disposeEditorRef.current == null) disposeEditorRef.current = applyEdit(instanceRef.current, getEditor); instanceRef.current.hydrate({ file, fileContainer: node, lineAnnotations, prerenderedHTML }); } else { if (instanceRef.current == null) throw new Error("File: A File instance should exist when unmounting"); instanceRef.current.cleanUp(); instanceRef.current = null; disposeEditorRef.current = null; } }); useIsomorphicLayoutEffect(() => { const { current: instance } = instanceRef; if (instance == null) return; const newOptions = mergeFileOptions({ controlledSelection, hasCustomHeader, hasGutterRenderUtility, onEditChange, onEditComplete, options }); const forceRender = newOptions !== void 0 && !areOptionsEqual(instance.options, newOptions); instance.setOptions(newOptions); if (!edit && disposeEditorRef.current != null) { const { current: disposeEditor } = disposeEditorRef; disposeEditorRef.current = null; disposeEditor(); } const resolved = resolveAcceptedValues(file, lineAnnotations, acceptedCache); instance.render({ file: resolved.file, lineAnnotations: resolved.lineAnnotations, forceRender }); if (selectedLines !== void 0) instance.setSelectedLines(selectedLines); if (edit && disposeEditorRef.current == null) disposeEditorRef.current = applyEdit(instance, getEditor); }); return { ref, getHoveredLine: useCallback(() => { return instanceRef.current?.getHoveredLine(); }, []), getAnnotationSlotName: useCallback((annotation) => instanceRef.current?.getAnnotationSlotName(annotation) ?? getLineAnnotationName(annotation), []) }; } function resolveAcceptedValues(file, lineAnnotations, acceptedCache) { const { current: accepted } = acceptedCache; if (accepted == null) return { file, lineAnnotations }; const { file: acceptedFiles, annotations: acceptedAnnotations } = accepted; let resolvedFile = file; if (acceptedFiles != null) if (areFileTargetsEqual(file, acceptedFiles.stale)) resolvedFile = acceptedFiles.installed; else accepted.file = null; let resolvedAnnotations = lineAnnotations; if (acceptedAnnotations != null) if (lineAnnotations === acceptedAnnotations.stale) resolvedAnnotations = acceptedAnnotations.installed; else accepted.annotations = null; if (accepted.file == null && accepted.annotations == null) acceptedCache.current = null; return { file: resolvedFile, lineAnnotations: resolvedAnnotations }; } function mergeFileOptions({ options, controlledSelection, hasCustomHeader, hasGutterRenderUtility, onEditChange, onEditComplete }) { if (!(controlledSelection || hasGutterRenderUtility || hasCustomHeader || onEditChange != null || onEditComplete != null)) return options; return { ...options, controlledSelection, renderCustomHeader: hasCustomHeader ? noopRender : options?.renderCustomHeader, renderGutterUtility: hasGutterRenderUtility ? noopRender : options?.renderGutterUtility, onEditChange, onEditComplete }; } function applyEdit(instance, getEditor) { const editor = getEditor(); try { return editor.edit(instance); } catch (error) { editor.cleanUp(); throw error; } } //#endregion export { useFileInstance }; //# sourceMappingURL=useFileInstance.js.map