@pierre/diffs
Version:
153 lines (152 loc) • 6.23 kB
JavaScript
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