@pierre/diffs 1.6.0-beta.1 → 1.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/CodeView.d.ts +3 -2
- package/dist/components/CodeView.d.ts.map +1 -1
- package/dist/components/CodeView.js +18 -14
- package/dist/components/CodeView.js.map +1 -1
- package/dist/components/File.d.ts +31 -9
- package/dist/components/File.d.ts.map +1 -1
- package/dist/components/File.js +165 -84
- package/dist/components/File.js.map +1 -1
- package/dist/components/FileDiff.d.ts +32 -9
- package/dist/components/FileDiff.d.ts.map +1 -1
- package/dist/components/FileDiff.js +213 -124
- package/dist/components/FileDiff.js.map +1 -1
- package/dist/components/UnresolvedFile.d.ts +14 -4
- package/dist/components/UnresolvedFile.d.ts.map +1 -1
- package/dist/components/UnresolvedFile.js +35 -16
- package/dist/components/UnresolvedFile.js.map +1 -1
- package/dist/components/VirtualizedFile.d.ts +3 -2
- package/dist/components/VirtualizedFile.d.ts.map +1 -1
- package/dist/components/VirtualizedFile.js +28 -20
- package/dist/components/VirtualizedFile.js.map +1 -1
- package/dist/components/VirtualizedFileDiff.d.ts +3 -2
- package/dist/components/VirtualizedFileDiff.d.ts.map +1 -1
- package/dist/components/VirtualizedFileDiff.js +31 -24
- package/dist/components/VirtualizedFileDiff.js.map +1 -1
- package/dist/constants.d.ts +2 -1
- package/dist/constants.d.ts.map +1 -1
- package/dist/constants.js +2 -1
- package/dist/constants.js.map +1 -1
- package/dist/editor/platform.d.ts +1 -1
- package/dist/editor/platform.js +5 -4
- package/dist/editor/platform.js.map +1 -1
- package/dist/editor/selection.d.ts +2 -2
- package/dist/editor/selection.d.ts.map +1 -1
- package/dist/editor/selection.js +31 -6
- package/dist/editor/selection.js.map +1 -1
- package/dist/highlighter/shared_highlighter.d.ts +2 -1
- package/dist/highlighter/shared_highlighter.d.ts.map +1 -1
- package/dist/highlighter/shared_highlighter.js +2 -2
- package/dist/highlighter/shared_highlighter.js.map +1 -1
- package/dist/index.d.ts +10 -5
- package/dist/index.js +8 -3
- package/dist/react/CodeView.d.ts +4 -3
- package/dist/react/CodeView.d.ts.map +1 -1
- package/dist/react/CodeView.js +48 -39
- package/dist/react/CodeView.js.map +1 -1
- package/dist/react/File.js +3 -3
- package/dist/react/File.js.map +1 -1
- package/dist/react/FileDiff.js +3 -3
- package/dist/react/FileDiff.js.map +1 -1
- package/dist/react/MultiFileDiff.js +2 -2
- package/dist/react/MultiFileDiff.js.map +1 -1
- package/dist/react/PatchDiff.js +3 -3
- package/dist/react/PatchDiff.js.map +1 -1
- package/dist/react/UnresolvedFile.js +2 -2
- package/dist/react/UnresolvedFile.js.map +1 -1
- package/dist/react/index.d.ts +2 -2
- package/dist/react/types.d.ts +4 -2
- package/dist/react/types.d.ts.map +1 -1
- package/dist/react/utils/renderDiffChildren.js +1 -1
- package/dist/react/utils/renderDiffChildren.js.map +1 -1
- package/dist/react/utils/renderFileChildren.js +1 -1
- package/dist/react/utils/renderFileChildren.js.map +1 -1
- package/dist/react/utils/useFileDiffInstance.d.ts +1 -0
- package/dist/react/utils/useFileDiffInstance.d.ts.map +1 -1
- package/dist/react/utils/useFileDiffInstance.js +29 -24
- package/dist/react/utils/useFileDiffInstance.js.map +1 -1
- package/dist/react/utils/useFileInstance.d.ts +2 -0
- package/dist/react/utils/useFileInstance.d.ts.map +1 -1
- package/dist/react/utils/useFileInstance.js +38 -28
- package/dist/react/utils/useFileInstance.js.map +1 -1
- package/dist/react/utils/useForceUpdate.d.ts +5 -0
- package/dist/react/utils/useForceUpdate.d.ts.map +1 -0
- package/dist/react/utils/useForceUpdate.js +27 -0
- package/dist/react/utils/useForceUpdate.js.map +1 -0
- package/dist/react/utils/useNextRenderData.d.ts +9 -0
- package/dist/react/utils/useNextRenderData.d.ts.map +1 -0
- package/dist/react/utils/useNextRenderData.js +9 -0
- package/dist/react/utils/useNextRenderData.js.map +1 -0
- package/dist/react/utils/useUnresolvedFileInstance.d.ts +1 -0
- package/dist/react/utils/useUnresolvedFileInstance.d.ts.map +1 -1
- package/dist/react/utils/useUnresolvedFileInstance.js +26 -11
- package/dist/react/utils/useUnresolvedFileInstance.js.map +1 -1
- package/dist/renderers/DiffHunksRenderer.d.ts +2 -1
- package/dist/renderers/DiffHunksRenderer.d.ts.map +1 -1
- package/dist/renderers/DiffHunksRenderer.js +62 -32
- package/dist/renderers/DiffHunksRenderer.js.map +1 -1
- package/dist/renderers/FileRenderer.d.ts +4 -1
- package/dist/renderers/FileRenderer.d.ts.map +1 -1
- package/dist/renderers/FileRenderer.js +55 -30
- package/dist/renderers/FileRenderer.js.map +1 -1
- package/dist/renderers/UnresolvedFileHunksRenderer.d.ts.map +1 -1
- package/dist/renderers/UnresolvedFileHunksRenderer.js +1 -1
- package/dist/renderers/UnresolvedFileHunksRenderer.js.map +1 -1
- package/dist/ssr/FileDiffReact.js +1 -1
- package/dist/types.d.ts +10 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/utils/canUseWASM.d.ts +13 -0
- package/dist/utils/canUseWASM.d.ts.map +1 -0
- package/dist/utils/canUseWASM.js +59 -0
- package/dist/utils/canUseWASM.js.map +1 -0
- package/dist/utils/getCodeViewItemRenderData.d.ts +10 -0
- package/dist/utils/getCodeViewItemRenderData.d.ts.map +1 -0
- package/dist/utils/getCodeViewItemRenderData.js +19 -0
- package/dist/utils/getCodeViewItemRenderData.js.map +1 -0
- package/dist/utils/hastToHtml.d.ts +2 -2
- package/dist/utils/hastToHtml.js +2 -2
- package/dist/utils/hastToHtml.js.map +1 -1
- package/dist/utils/hydratePartialDiff.js +4 -0
- package/dist/utils/hydratePartialDiff.js.map +1 -1
- package/dist/utils/parseMergeConflictDiffFromFile.d.ts.map +1 -1
- package/dist/utils/parseMergeConflictDiffFromFile.js +2 -0
- package/dist/utils/parseMergeConflictDiffFromFile.js.map +1 -1
- package/dist/utils/parsePatchFiles.d.ts.map +1 -1
- package/dist/utils/parsePatchFiles.js +24 -4
- package/dist/utils/parsePatchFiles.js.map +1 -1
- package/dist/utils/renderTokenLines.d.ts +6 -1
- package/dist/utils/renderTokenLines.d.ts.map +1 -1
- package/dist/utils/renderTokenLines.js +4 -0
- package/dist/utils/renderTokenLines.js.map +1 -1
- package/dist/utils/resolveRegion.js +20 -10
- package/dist/utils/resolveRegion.js.map +1 -1
- package/dist/utils/tokenStyle.d.ts +5 -1
- package/dist/utils/tokenStyle.d.ts.map +1 -1
- package/dist/utils/tokenStyle.js +5 -1
- package/dist/utils/tokenStyle.js.map +1 -1
- package/dist/utils/tokensToHtml.d.ts +5 -2
- package/dist/utils/tokensToHtml.d.ts.map +1 -1
- package/dist/utils/tokensToHtml.js +5 -2
- package/dist/utils/tokensToHtml.js.map +1 -1
- package/dist/utils/updateDiffHunks.d.ts +2 -2
- package/dist/utils/updateDiffHunks.d.ts.map +1 -1
- package/dist/utils/updateDiffHunks.js +7 -3
- package/dist/utils/updateDiffHunks.js.map +1 -1
- package/dist/worker/WorkerPoolManager.d.ts +12 -0
- package/dist/worker/WorkerPoolManager.d.ts.map +1 -1
- package/dist/worker/WorkerPoolManager.js +99 -21
- package/dist/worker/WorkerPoolManager.js.map +1 -1
- package/dist/worker/{highlights-sAHlxqlf.js → highlights-CpZm9DAR.js} +2 -2
- package/dist/worker/{highlights-sAHlxqlf.js.map → highlights-CpZm9DAR.js.map} +1 -1
- package/dist/worker/{shiki-Bx2JpdqZ.js → shiki-Ci4cdHsM.js} +2 -2
- package/dist/worker/{shiki-Bx2JpdqZ.js.map → shiki-Ci4cdHsM.js.map} +1 -1
- package/dist/worker/{stream-tokenizer-YZ6M1qSx.js → stream-tokenizer-DK9xp5M5.js} +8 -5
- package/dist/worker/stream-tokenizer-DK9xp5M5.js.map +1 -0
- package/dist/worker/types.d.ts +11 -0
- package/dist/worker/types.d.ts.map +1 -1
- package/dist/worker/worker-portable.js +4 -4
- package/dist/worker/worker-portable.js.map +1 -1
- package/dist/worker/worker.js +12 -3
- package/dist/worker/worker.js.map +1 -1
- package/package.json +28 -30
- package/dist/worker/stream-tokenizer-YZ6M1qSx.js.map +0 -1
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { EMPTY_LINE_ANNOTATIONS } from "../../constants.js";
|
|
1
2
|
import { areOptionsEqual } from "../../utils/areOptionsEqual.js";
|
|
2
3
|
import { areFileTargetsEqual } from "../../utils/areFileTargetsEqual.js";
|
|
3
4
|
import { getLineAnnotationName } from "../../utils/getLineAnnotationName.js";
|
|
@@ -8,6 +9,8 @@ import { useCreateEditor } from "../EditContext.js";
|
|
|
8
9
|
import { noopRender } from "../constants.js";
|
|
9
10
|
import { WorkerPoolContext } from "../WorkerPoolContext.js";
|
|
10
11
|
import { useVirtualizer } from "../Virtualizer.js";
|
|
12
|
+
import { useForceUpdate } from "./useForceUpdate.js";
|
|
13
|
+
import { useNextRenderData } from "./useNextRenderData.js";
|
|
11
14
|
import { useCallback, useContext, useEffect, useLayoutEffect, useRef } from "react";
|
|
12
15
|
//#region src/react/utils/useFileInstance.ts
|
|
13
16
|
const useIsomorphicLayoutEffect = typeof window === "undefined" ? useEffect : useLayoutEffect;
|
|
@@ -35,6 +38,12 @@ function useFileInstance({ file, options, editorOptions, editStateKey, lineAnnot
|
|
|
35
38
|
});
|
|
36
39
|
const onEditComplete = _onEditComplete != null ? handleOnEditComplete : void 0;
|
|
37
40
|
const instanceRef = useRef(null);
|
|
41
|
+
const forceUpdate = useForceUpdate();
|
|
42
|
+
const accepted = useAcceptedValues(acceptedCache, file, lineAnnotations);
|
|
43
|
+
const renderData = useNextRenderData(instanceRef, accepted) ?? {
|
|
44
|
+
file,
|
|
45
|
+
lineAnnotations: lineAnnotations ?? EMPTY_LINE_ANNOTATIONS
|
|
46
|
+
};
|
|
38
47
|
const disposeEditorRef = useRef(null);
|
|
39
48
|
const getEditor = useStableCallback(() => {
|
|
40
49
|
if (createEditor == null) throw new Error("File: EditContext is not attached");
|
|
@@ -50,7 +59,7 @@ function useFileInstance({ file, options, editorOptions, editStateKey, lineAnnot
|
|
|
50
59
|
onEditChange,
|
|
51
60
|
onEditComplete,
|
|
52
61
|
options
|
|
53
|
-
}), simpleVirtualizer, metrics, !disableWorkerPool ? poolManager : void 0,
|
|
62
|
+
}), simpleVirtualizer, metrics, !disableWorkerPool ? poolManager : void 0, forceUpdate);
|
|
54
63
|
else instanceRef.current = new File(mergeFileOptions({
|
|
55
64
|
controlledSelection,
|
|
56
65
|
hasCustomHeader,
|
|
@@ -58,7 +67,7 @@ function useFileInstance({ file, options, editorOptions, editStateKey, lineAnnot
|
|
|
58
67
|
onEditChange,
|
|
59
68
|
onEditComplete,
|
|
60
69
|
options
|
|
61
|
-
}), !disableWorkerPool ? poolManager : void 0,
|
|
70
|
+
}), !disableWorkerPool ? poolManager : void 0, forceUpdate);
|
|
62
71
|
if (edit && disposeEditorRef.current == null) disposeEditorRef.current = applyEdit(instanceRef.current, getEditor);
|
|
63
72
|
instanceRef.current.hydrate({
|
|
64
73
|
file,
|
|
@@ -84,7 +93,7 @@ function useFileInstance({ file, options, editorOptions, editStateKey, lineAnnot
|
|
|
84
93
|
onEditComplete,
|
|
85
94
|
options
|
|
86
95
|
});
|
|
87
|
-
const forceRender =
|
|
96
|
+
const forceRender = !areOptionsEqual(instance.options, newOptions);
|
|
88
97
|
instance.setOptions(newOptions);
|
|
89
98
|
if (!edit && disposeEditorRef.current != null) {
|
|
90
99
|
const { current: disposeEditor } = disposeEditorRef;
|
|
@@ -98,41 +107,42 @@ function useFileInstance({ file, options, editorOptions, editStateKey, lineAnnot
|
|
|
98
107
|
forceRender
|
|
99
108
|
});
|
|
100
109
|
if (selectedLines !== void 0) instance.setSelectedLines(selectedLines);
|
|
101
|
-
if (edit && disposeEditorRef.current == null)
|
|
110
|
+
if (edit && disposeEditorRef.current == null) {
|
|
111
|
+
disposeEditorRef.current = applyEdit(instance, getEditor);
|
|
112
|
+
forceUpdate();
|
|
113
|
+
}
|
|
102
114
|
});
|
|
115
|
+
const getHoveredLine = useCallback(() => {
|
|
116
|
+
return instanceRef.current?.getHoveredLine();
|
|
117
|
+
}, []);
|
|
118
|
+
const getAnnotationSlotName = useCallback((annotation) => instanceRef.current?.getAnnotationSlotName(annotation) ?? getLineAnnotationName(annotation), []);
|
|
103
119
|
return {
|
|
120
|
+
...renderData,
|
|
104
121
|
ref,
|
|
105
|
-
getHoveredLine
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
122
|
+
getHoveredLine,
|
|
123
|
+
getAnnotationSlotName
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
function useAcceptedValues(acceptedCache, file, lineAnnotations) {
|
|
127
|
+
"use no memo";
|
|
128
|
+
return getAcceptedValues(file, lineAnnotations, acceptedCache.current);
|
|
129
|
+
}
|
|
130
|
+
function getAcceptedValues(file, lineAnnotations, accepted) {
|
|
131
|
+
return {
|
|
132
|
+
file: accepted?.file != null && areFileTargetsEqual(file, accepted.file.stale) ? accepted.file.installed : file,
|
|
133
|
+
lineAnnotations: accepted?.annotations != null && lineAnnotations === accepted.annotations.stale ? accepted.annotations.installed : lineAnnotations
|
|
109
134
|
};
|
|
110
135
|
}
|
|
111
136
|
function resolveAcceptedValues(file, lineAnnotations, acceptedCache) {
|
|
112
137
|
const { current: accepted } = acceptedCache;
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
const { file: acceptedFiles, annotations: acceptedAnnotations } = accepted;
|
|
118
|
-
let resolvedFile = file;
|
|
119
|
-
if (acceptedFiles != null) {
|
|
120
|
-
if (areFileTargetsEqual(file, acceptedFiles.stale)) resolvedFile = acceptedFiles.installed;
|
|
121
|
-
else accepted.file = null;
|
|
122
|
-
}
|
|
123
|
-
let resolvedAnnotations = lineAnnotations;
|
|
124
|
-
if (acceptedAnnotations != null) {
|
|
125
|
-
if (lineAnnotations === acceptedAnnotations.stale) resolvedAnnotations = acceptedAnnotations.installed;
|
|
126
|
-
else accepted.annotations = null;
|
|
127
|
-
}
|
|
138
|
+
const resolved = getAcceptedValues(file, lineAnnotations, accepted);
|
|
139
|
+
if (accepted == null) return resolved;
|
|
140
|
+
if (accepted.file != null && !areFileTargetsEqual(file, accepted.file.stale)) accepted.file = null;
|
|
141
|
+
if (lineAnnotations !== accepted.annotations?.stale) accepted.annotations = null;
|
|
128
142
|
if (accepted.file == null && accepted.annotations == null) acceptedCache.current = null;
|
|
129
|
-
return
|
|
130
|
-
file: resolvedFile,
|
|
131
|
-
lineAnnotations: resolvedAnnotations
|
|
132
|
-
};
|
|
143
|
+
return resolved;
|
|
133
144
|
}
|
|
134
145
|
function mergeFileOptions({ options, controlledSelection, hasCustomHeader, hasGutterRenderUtility, onEditChange, onEditComplete }) {
|
|
135
|
-
if (!(controlledSelection || hasGutterRenderUtility || hasCustomHeader || onEditChange != null || onEditComplete != null)) return options;
|
|
136
146
|
return {
|
|
137
147
|
...options,
|
|
138
148
|
controlledSelection,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useFileInstance.js","names":[],"sources":["../../../src/react/utils/useFileInstance.ts"],"sourcesContent":["import {\n type RefObject,\n useCallback,\n useContext,\n useEffect,\n useLayoutEffect,\n useRef,\n} from 'react';\n\nimport {\n File,\n type FileEditChangeHandler,\n type FileEditCompleteEvent,\n type FileEditCompleteHandler,\n type FileOptions,\n} from '../../components/File';\nimport { VirtualizedFile } from '../../components/VirtualizedFile';\nimport type { Editor, EditorChangeEvent, EditorOptions } from '../../edit';\nimport type { GetHoveredLineResult } from '../../managers/InteractionManager';\nimport type {\n FileContents,\n LineAnnotation,\n SelectedLineRange,\n VirtualFileMetrics,\n} from '../../types';\nimport { areFileTargetsEqual } from '../../utils/areFileTargetsEqual';\nimport { areOptionsEqual } from '../../utils/areOptionsEqual';\nimport { getLineAnnotationName } from '../../utils/getLineAnnotationName';\nimport { noopRender } from '../constants';\nimport { useCreateEditor } from '../EditContext';\nimport { useVirtualizer } from '../Virtualizer';\nimport { WorkerPoolContext } from '../WorkerPoolContext';\nimport { useStableCallback } from './useStableCallback';\n\nconst useIsomorphicLayoutEffect =\n typeof window === 'undefined' ? useEffect : useLayoutEffect;\n\ninterface AcceptedCompletion<LAnnotation> {\n file: {\n installed: FileContents;\n stale: FileContents;\n } | null;\n annotations: {\n installed: LineAnnotation<LAnnotation>[] | undefined;\n stale: LineAnnotation<LAnnotation>[];\n } | null;\n}\n\ninterface UseFileInstanceProps<LAnnotation, Caret> {\n file: FileContents;\n options: FileOptions<LAnnotation, Caret> | undefined;\n editorOptions: EditorOptions<'file', LAnnotation, Caret> | undefined;\n editStateKey: string | undefined;\n lineAnnotations: LineAnnotation<LAnnotation>[] | undefined;\n selectedLines: SelectedLineRange | null | undefined;\n prerenderedHTML: string | undefined;\n metrics?: VirtualFileMetrics;\n hasGutterRenderUtility: boolean;\n hasCustomHeader: boolean;\n disableWorkerPool: boolean;\n edit: boolean;\n onEditChange?: FileEditChangeHandler<LAnnotation, Caret>;\n onEditComplete?: FileEditCompleteHandler<LAnnotation, Caret>;\n}\n\ninterface UseFileInstanceReturn<LAnnotation> {\n ref(node: HTMLElement | null): void;\n getHoveredLine(): GetHoveredLineResult<'file'> | undefined;\n getAnnotationSlotName(annotation: LineAnnotation<LAnnotation>): string;\n}\n\nexport function useFileInstance<LAnnotation, Caret>({\n file,\n options,\n editorOptions,\n editStateKey,\n lineAnnotations,\n selectedLines,\n prerenderedHTML,\n metrics,\n hasGutterRenderUtility,\n hasCustomHeader,\n disableWorkerPool,\n edit,\n onEditChange: _onEditChange,\n onEditComplete: _onEditComplete,\n}: UseFileInstanceProps<\n LAnnotation,\n Caret\n>): UseFileInstanceReturn<LAnnotation> {\n const simpleVirtualizer = useVirtualizer();\n const controlledSelection = selectedLines !== undefined;\n const poolManager = useContext(WorkerPoolContext);\n const createEditor = useCreateEditor<LAnnotation, Caret>();\n const handleOnEditChange = useStableCallback(\n (event: EditorChangeEvent<'file', LAnnotation, Caret>) =>\n _onEditChange?.(event)\n );\n const onEditChange = _onEditChange != null ? handleOnEditChange : undefined;\n // An accepted completion installs its file on the instance immediately,\n // but the file/lineAnnotations props stay pre-edit until the owner's state\n // update lands. This holds the accepted values so the renders in between do\n // not repaint pre-edit state.\n const acceptedCache = useRef<AcceptedCompletion<LAnnotation> | null>(null);\n const handleOnEditComplete = useStableCallback(\n (event: FileEditCompleteEvent<LAnnotation, Caret>) => {\n const decision = _onEditComplete?.(event) ?? 'reject';\n if (decision === 'accept') {\n acceptedCache.current = {\n file: { installed: event.file, stale: event.originalFile },\n annotations: {\n installed: event.lineAnnotations,\n stale: event.originalLineAnnotations,\n },\n };\n }\n return decision;\n }\n );\n const onEditComplete =\n _onEditComplete != null ? handleOnEditComplete : undefined;\n const instanceRef = useRef<\n File<LAnnotation, Caret> | VirtualizedFile<LAnnotation, Caret> | null\n >(null);\n const disposeEditorRef = useRef<() => void>(null);\n const getEditor = useStableCallback(() => {\n if (createEditor == null) {\n throw new Error('File: EditContext is not attached');\n }\n return createEditor('file', editorOptions ?? {}, editStateKey);\n });\n const ref = useStableCallback((node: HTMLElement | null) => {\n if (node != null) {\n if (instanceRef.current != null) {\n throw new Error(\n 'File: An instance should not already exist when a node is created'\n );\n }\n if (simpleVirtualizer != null) {\n instanceRef.current = new VirtualizedFile(\n mergeFileOptions({\n controlledSelection,\n hasCustomHeader,\n hasGutterRenderUtility,\n onEditChange,\n onEditComplete,\n options,\n }),\n simpleVirtualizer,\n metrics,\n !disableWorkerPool ? poolManager : undefined,\n true\n );\n } else {\n instanceRef.current = new File(\n mergeFileOptions({\n controlledSelection,\n hasCustomHeader,\n hasGutterRenderUtility,\n onEditChange,\n onEditComplete,\n options,\n }),\n !disableWorkerPool ? poolManager : undefined,\n true\n );\n }\n if (edit && disposeEditorRef.current == null) {\n disposeEditorRef.current = applyEdit(instanceRef.current, getEditor);\n }\n void instanceRef.current.hydrate({\n file,\n fileContainer: node,\n lineAnnotations,\n prerenderedHTML,\n });\n } else {\n if (instanceRef.current == null) {\n throw new Error('File: A File instance should exist when unmounting');\n }\n instanceRef.current.cleanUp();\n instanceRef.current = null;\n disposeEditorRef.current = null;\n }\n });\n\n useIsomorphicLayoutEffect(() => {\n const { current: instance } = instanceRef;\n if (instance == null) return;\n const newOptions = mergeFileOptions({\n controlledSelection,\n hasCustomHeader,\n hasGutterRenderUtility,\n onEditChange,\n onEditComplete,\n options,\n });\n // setOptions(undefined) is a no-op, so an undefined merge result never\n // requires a forced render — comparing it against the instance's\n // constructor-default options would force a full render on every commit.\n const forceRender =\n newOptions !== undefined &&\n !areOptionsEqual(instance.options, newOptions);\n instance.setOptions(newOptions);\n // Detach editor before rendering if required\n if (!edit && disposeEditorRef.current != null) {\n const { current: disposeEditor } = disposeEditorRef;\n disposeEditorRef.current = null;\n disposeEditor();\n }\n const resolved = resolveAcceptedValues(\n file,\n lineAnnotations,\n acceptedCache\n );\n void instance.render({\n file: resolved.file,\n lineAnnotations: resolved.lineAnnotations,\n forceRender,\n });\n if (selectedLines !== undefined) {\n instance.setSelectedLines(selectedLines);\n }\n // Attach editor after rendering if required\n if (edit && disposeEditorRef.current == null) {\n disposeEditorRef.current = applyEdit(instance, getEditor);\n }\n });\n\n const getHoveredLine = useCallback(():\n | GetHoveredLineResult<'file'>\n | undefined => {\n return instanceRef.current?.getHoveredLine();\n }, []);\n const getAnnotationSlotName = useCallback(\n (annotation: LineAnnotation<LAnnotation>): string =>\n instanceRef.current?.getAnnotationSlotName(annotation) ??\n getLineAnnotationName(annotation),\n []\n );\n return { ref, getHoveredLine, getAnnotationSlotName };\n}\n\n// Return the installed values in place of props that still match their stale\n// counterparts. Any other prop value clears its half, and the ref clears once\n// both halves have.\nfunction resolveAcceptedValues<LAnnotation>(\n file: FileContents,\n lineAnnotations: LineAnnotation<LAnnotation>[] | undefined,\n acceptedCache: RefObject<AcceptedCompletion<LAnnotation> | null>\n): {\n file: FileContents;\n lineAnnotations: LineAnnotation<LAnnotation>[] | undefined;\n} {\n const { current: accepted } = acceptedCache;\n if (accepted == null) {\n return { file, lineAnnotations };\n }\n const { file: acceptedFiles, annotations: acceptedAnnotations } = accepted;\n let resolvedFile = file;\n if (acceptedFiles != null) {\n if (areFileTargetsEqual(file, acceptedFiles.stale)) {\n resolvedFile = acceptedFiles.installed;\n } else {\n accepted.file = null;\n }\n }\n let resolvedAnnotations = lineAnnotations;\n if (acceptedAnnotations != null) {\n if (lineAnnotations === acceptedAnnotations.stale) {\n resolvedAnnotations = acceptedAnnotations.installed;\n } else {\n accepted.annotations = null;\n }\n }\n if (accepted.file == null && accepted.annotations == null) {\n acceptedCache.current = null;\n }\n return { file: resolvedFile, lineAnnotations: resolvedAnnotations };\n}\n\ninterface MergeFileOptionsProps<LAnnotation, Caret> {\n options: FileOptions<LAnnotation, Caret> | undefined;\n controlledSelection: boolean;\n hasGutterRenderUtility: boolean;\n hasCustomHeader: boolean;\n onEditChange: FileEditChangeHandler<LAnnotation, Caret> | undefined;\n onEditComplete: FileEditCompleteHandler<LAnnotation, Caret> | undefined;\n}\n\nfunction mergeFileOptions<LAnnotation, Caret>({\n options,\n controlledSelection,\n hasCustomHeader,\n hasGutterRenderUtility,\n onEditChange,\n onEditComplete,\n}: MergeFileOptionsProps<LAnnotation, Caret>):\n | FileOptions<LAnnotation, Caret>\n | undefined {\n const needsReactOverrides =\n controlledSelection ||\n hasGutterRenderUtility ||\n hasCustomHeader ||\n onEditChange != null ||\n onEditComplete != null;\n\n if (!needsReactOverrides) {\n return options;\n }\n\n return {\n ...options,\n controlledSelection,\n renderCustomHeader: hasCustomHeader\n ? noopRender\n : options?.renderCustomHeader,\n renderGutterUtility: hasGutterRenderUtility\n ? noopRender\n : options?.renderGutterUtility,\n onEditChange,\n onEditComplete,\n };\n}\n\nfunction applyEdit<LAnnotation, Caret>(\n instance: File<LAnnotation, Caret>,\n getEditor: () => Editor<'file', LAnnotation, Caret>\n): () => void {\n const editor = getEditor();\n try {\n return editor.edit(instance);\n } catch (error) {\n editor.cleanUp();\n throw error;\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"useFileInstance.js","names":[],"sources":["../../../src/react/utils/useFileInstance.ts"],"sourcesContent":["import {\n type RefObject,\n useCallback,\n useContext,\n useEffect,\n useLayoutEffect,\n useRef,\n} from 'react';\n\nimport {\n File,\n type FileEditChangeHandler,\n type FileEditCompleteEvent,\n type FileEditCompleteHandler,\n type FileOptions,\n type FileRenderInput,\n} from '../../components/File';\nimport { VirtualizedFile } from '../../components/VirtualizedFile';\nimport { EMPTY_LINE_ANNOTATIONS } from '../../constants';\nimport type { Editor, EditorChangeEvent, EditorOptions } from '../../edit';\nimport type { GetHoveredLineResult } from '../../managers/InteractionManager';\nimport type {\n FileContents,\n LineAnnotation,\n SelectedLineRange,\n VirtualFileMetrics,\n} from '../../types';\nimport { areFileTargetsEqual } from '../../utils/areFileTargetsEqual';\nimport { areOptionsEqual } from '../../utils/areOptionsEqual';\nimport { getLineAnnotationName } from '../../utils/getLineAnnotationName';\nimport { noopRender } from '../constants';\nimport { useCreateEditor } from '../EditContext';\nimport { useVirtualizer } from '../Virtualizer';\nimport { WorkerPoolContext } from '../WorkerPoolContext';\nimport { useForceUpdate } from './useForceUpdate';\nimport { useNextRenderData } from './useNextRenderData';\nimport { useStableCallback } from './useStableCallback';\n\nconst useIsomorphicLayoutEffect =\n typeof window === 'undefined' ? useEffect : useLayoutEffect;\n\ninterface AcceptedCompletion<LAnnotation> {\n file: {\n installed: FileContents;\n stale: FileContents;\n } | null;\n annotations: {\n installed: LineAnnotation<LAnnotation>[] | undefined;\n stale: LineAnnotation<LAnnotation>[];\n } | null;\n}\n\ninterface UseFileInstanceProps<LAnnotation, Caret> {\n file: FileContents;\n options: FileOptions<LAnnotation, Caret> | undefined;\n editorOptions: EditorOptions<'file', LAnnotation, Caret> | undefined;\n editStateKey: string | undefined;\n lineAnnotations: LineAnnotation<LAnnotation>[] | undefined;\n selectedLines: SelectedLineRange | null | undefined;\n prerenderedHTML: string | undefined;\n metrics?: VirtualFileMetrics;\n hasGutterRenderUtility: boolean;\n hasCustomHeader: boolean;\n disableWorkerPool: boolean;\n edit: boolean;\n onEditChange?: FileEditChangeHandler<LAnnotation, Caret>;\n onEditComplete?: FileEditCompleteHandler<LAnnotation, Caret>;\n}\n\ninterface UseFileInstanceReturn<LAnnotation> {\n file: FileContents;\n lineAnnotations: LineAnnotation<LAnnotation>[];\n ref(node: HTMLElement | null): void;\n getHoveredLine(): GetHoveredLineResult<'file'> | undefined;\n getAnnotationSlotName(annotation: LineAnnotation<LAnnotation>): string;\n}\n\nexport function useFileInstance<LAnnotation, Caret>({\n file,\n options,\n editorOptions,\n editStateKey,\n lineAnnotations,\n selectedLines,\n prerenderedHTML,\n metrics,\n hasGutterRenderUtility,\n hasCustomHeader,\n disableWorkerPool,\n edit,\n onEditChange: _onEditChange,\n onEditComplete: _onEditComplete,\n}: UseFileInstanceProps<\n LAnnotation,\n Caret\n>): UseFileInstanceReturn<LAnnotation> {\n const simpleVirtualizer = useVirtualizer();\n const controlledSelection = selectedLines !== undefined;\n const poolManager = useContext(WorkerPoolContext);\n const createEditor = useCreateEditor<LAnnotation, Caret>();\n const handleOnEditChange = useStableCallback(\n (event: EditorChangeEvent<'file', LAnnotation, Caret>) =>\n _onEditChange?.(event)\n );\n const onEditChange = _onEditChange != null ? handleOnEditChange : undefined;\n // When an edit is accepted, the instance switches to the edited file right\n // away, but the file and lineAnnotations props keep their pre-edit values\n // until the parent passes new ones. This keeps the accepted values so the\n // renders in between don't show the pre-edit file again.\n const acceptedCache = useRef<AcceptedCompletion<LAnnotation> | null>(null);\n const handleOnEditComplete = useStableCallback(\n (event: FileEditCompleteEvent<LAnnotation, Caret>) => {\n const decision = _onEditComplete?.(event) ?? 'reject';\n if (decision === 'accept') {\n acceptedCache.current = {\n file: { installed: event.file, stale: event.originalFile },\n annotations: {\n installed: event.lineAnnotations,\n stale: event.originalLineAnnotations,\n },\n };\n }\n return decision;\n }\n );\n const onEditComplete =\n _onEditComplete != null ? handleOnEditComplete : undefined;\n const instanceRef = useRef<\n File<LAnnotation, Caret> | VirtualizedFile<LAnnotation, Caret> | null\n >(null);\n const forceUpdate = useForceUpdate();\n const accepted = useAcceptedValues(acceptedCache, file, lineAnnotations);\n const renderData = useNextRenderData(instanceRef, accepted) ?? {\n file,\n lineAnnotations: lineAnnotations ?? EMPTY_LINE_ANNOTATIONS,\n };\n const disposeEditorRef = useRef<() => void>(null);\n const getEditor = useStableCallback(() => {\n if (createEditor == null) {\n throw new Error('File: EditContext is not attached');\n }\n return createEditor('file', editorOptions ?? {}, editStateKey);\n });\n const ref = useStableCallback((node: HTMLElement | null) => {\n if (node != null) {\n if (instanceRef.current != null) {\n throw new Error(\n 'File: An instance should not already exist when a node is created'\n );\n }\n if (simpleVirtualizer != null) {\n instanceRef.current = new VirtualizedFile(\n mergeFileOptions({\n controlledSelection,\n hasCustomHeader,\n hasGutterRenderUtility,\n onEditChange,\n onEditComplete,\n options,\n }),\n simpleVirtualizer,\n metrics,\n !disableWorkerPool ? poolManager : undefined,\n forceUpdate\n );\n } else {\n instanceRef.current = new File(\n mergeFileOptions({\n controlledSelection,\n hasCustomHeader,\n hasGutterRenderUtility,\n onEditChange,\n onEditComplete,\n options,\n }),\n !disableWorkerPool ? poolManager : undefined,\n forceUpdate\n );\n }\n if (edit && disposeEditorRef.current == null) {\n disposeEditorRef.current = applyEdit(instanceRef.current, getEditor);\n }\n void instanceRef.current.hydrate({\n file,\n fileContainer: node,\n lineAnnotations,\n prerenderedHTML,\n });\n } else {\n if (instanceRef.current == null) {\n throw new Error('File: A File instance should exist when unmounting');\n }\n instanceRef.current.cleanUp();\n instanceRef.current = null;\n disposeEditorRef.current = null;\n }\n });\n\n useIsomorphicLayoutEffect(() => {\n const { current: instance } = instanceRef;\n if (instance == null) return;\n const newOptions = mergeFileOptions({\n controlledSelection,\n hasCustomHeader,\n hasGutterRenderUtility,\n onEditChange,\n onEditComplete,\n options,\n });\n const forceRender = !areOptionsEqual(instance.options, newOptions);\n instance.setOptions(newOptions);\n // Detach the editor before rendering when editing turns off\n if (!edit && disposeEditorRef.current != null) {\n const { current: disposeEditor } = disposeEditorRef;\n disposeEditorRef.current = null;\n disposeEditor();\n }\n const resolved = resolveAcceptedValues(\n file,\n lineAnnotations,\n acceptedCache\n );\n void instance.render({\n file: resolved.file,\n lineAnnotations: resolved.lineAnnotations,\n forceRender,\n });\n if (selectedLines !== undefined) {\n instance.setSelectedLines(selectedLines);\n }\n // Attach the editor after rendering when editing turns on. The editor can\n // show content that is still highlighting, so render the children again\n // from the edit session.\n if (edit && disposeEditorRef.current == null) {\n disposeEditorRef.current = applyEdit(instance, getEditor);\n forceUpdate();\n }\n });\n\n const getHoveredLine = useCallback(():\n | GetHoveredLineResult<'file'>\n | undefined => {\n return instanceRef.current?.getHoveredLine();\n }, []);\n const getAnnotationSlotName = useCallback(\n (annotation: LineAnnotation<LAnnotation>): string =>\n instanceRef.current?.getAnnotationSlotName(annotation) ??\n getLineAnnotationName(annotation),\n []\n );\n return { ...renderData, ref, getHoveredLine, getAnnotationSlotName };\n}\n\n// Read the accepted values on every render. Entries are only removed in the\n// effect, by resolveAcceptedValues. The cache changes without new props, so\n// this must not be memoized.\nfunction useAcceptedValues<LAnnotation>(\n acceptedCache: RefObject<AcceptedCompletion<LAnnotation> | null>,\n file: FileContents,\n lineAnnotations: LineAnnotation<LAnnotation>[] | undefined\n): FileRenderInput<LAnnotation> {\n 'use no memo';\n // oxlint-disable-next-line react/refs -- the cache changes without new props\n return getAcceptedValues(file, lineAnnotations, acceptedCache.current);\n}\n\n// Use the accepted values for props that still hold their pre-edit values.\nfunction getAcceptedValues<LAnnotation>(\n file: FileContents,\n lineAnnotations: LineAnnotation<LAnnotation>[] | undefined,\n accepted: AcceptedCompletion<LAnnotation> | null\n): FileRenderInput<LAnnotation> {\n return {\n file:\n accepted?.file != null && areFileTargetsEqual(file, accepted.file.stale)\n ? accepted.file.installed\n : file,\n lineAnnotations:\n accepted?.annotations != null &&\n lineAnnotations === accepted.annotations.stale\n ? accepted.annotations.installed\n : lineAnnotations,\n };\n}\n\n// Return the accepted values, and drop each one once its prop no longer holds\n// the pre-edit value. The cache is cleared once both are dropped.\nfunction resolveAcceptedValues<LAnnotation>(\n file: FileContents,\n lineAnnotations: LineAnnotation<LAnnotation>[] | undefined,\n acceptedCache: RefObject<AcceptedCompletion<LAnnotation> | null>\n): FileRenderInput<LAnnotation> {\n const { current: accepted } = acceptedCache;\n const resolved = getAcceptedValues(file, lineAnnotations, accepted);\n if (accepted == null) {\n return resolved;\n }\n if (\n accepted.file != null &&\n !areFileTargetsEqual(file, accepted.file.stale)\n ) {\n accepted.file = null;\n }\n if (lineAnnotations !== accepted.annotations?.stale) {\n accepted.annotations = null;\n }\n if (accepted.file == null && accepted.annotations == null) {\n acceptedCache.current = null;\n }\n return resolved;\n}\n\ninterface MergeFileOptionsProps<LAnnotation, Caret> {\n options: FileOptions<LAnnotation, Caret> | undefined;\n controlledSelection: boolean;\n hasGutterRenderUtility: boolean;\n hasCustomHeader: boolean;\n onEditChange: FileEditChangeHandler<LAnnotation, Caret> | undefined;\n onEditComplete: FileEditCompleteHandler<LAnnotation, Caret> | undefined;\n}\n\nfunction mergeFileOptions<LAnnotation, Caret>({\n options,\n controlledSelection,\n hasCustomHeader,\n hasGutterRenderUtility,\n onEditChange,\n onEditComplete,\n}: MergeFileOptionsProps<LAnnotation, Caret>): FileOptions<LAnnotation, Caret> {\n return {\n ...options,\n controlledSelection,\n renderCustomHeader: hasCustomHeader\n ? noopRender\n : options?.renderCustomHeader,\n renderGutterUtility: hasGutterRenderUtility\n ? noopRender\n : options?.renderGutterUtility,\n onEditChange,\n onEditComplete,\n };\n}\n\n// Attach an editor to the instance, cleaning the editor up if attaching throws.\nfunction applyEdit<LAnnotation, Caret>(\n instance: File<LAnnotation, Caret>,\n getEditor: () => Editor<'file', LAnnotation, Caret>\n): () => void {\n const editor = getEditor();\n try {\n return editor.edit(instance);\n } catch (error) {\n editor.cleanUp();\n throw error;\n }\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useForceUpdate.d.ts","names":[],"sources":["../../../src/react/utils/useForceUpdate.ts"],"mappings":";iBAGgB"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { useState, useSyncExternalStore } from "react";
|
|
2
|
+
//#region src/react/utils/useForceUpdate.ts
|
|
3
|
+
function useForceUpdate() {
|
|
4
|
+
const [store] = useState(() => {
|
|
5
|
+
let version = 0;
|
|
6
|
+
let listener;
|
|
7
|
+
return {
|
|
8
|
+
getSnapshot: () => version,
|
|
9
|
+
subscribe(next) {
|
|
10
|
+
listener = next;
|
|
11
|
+
return () => {
|
|
12
|
+
listener = void 0;
|
|
13
|
+
};
|
|
14
|
+
},
|
|
15
|
+
forceUpdate() {
|
|
16
|
+
version++;
|
|
17
|
+
listener?.();
|
|
18
|
+
}
|
|
19
|
+
};
|
|
20
|
+
});
|
|
21
|
+
useSyncExternalStore(store.subscribe, store.getSnapshot, store.getSnapshot);
|
|
22
|
+
return store.forceUpdate;
|
|
23
|
+
}
|
|
24
|
+
//#endregion
|
|
25
|
+
export { useForceUpdate };
|
|
26
|
+
|
|
27
|
+
//# sourceMappingURL=useForceUpdate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useForceUpdate.js","names":[],"sources":["../../../src/react/utils/useForceUpdate.ts"],"sourcesContent":["import { useState, useSyncExternalStore } from 'react';\n\n// A helper hook to force a react component to re-render\nexport function useForceUpdate(): () => void {\n const [store] = useState(() => {\n let version = 0;\n let listener: (() => void) | undefined;\n return {\n getSnapshot: () => version,\n subscribe(next: () => void) {\n listener = next;\n return () => {\n listener = undefined;\n };\n },\n forceUpdate() {\n version++;\n listener?.();\n },\n };\n });\n useSyncExternalStore(store.subscribe, store.getSnapshot, store.getSnapshot);\n return store.forceUpdate;\n}\n"],"mappings":";;AAGA,SAAgB,iBAA6B;CAC3C,MAAM,CAAC,SAAS,eAAe;EAC7B,IAAI,UAAU;EACd,IAAI;EACJ,OAAO;GACL,mBAAmB;GACnB,UAAU,MAAkB;IAC1B,WAAW;IACX,aAAa;KACX,WAAW,KAAA;IACb;GACF;GACA,cAAc;IACZ;IACA,WAAW;GACb;EACF;CACF,CAAC;CACD,qBAAqB,MAAM,WAAW,MAAM,aAAa,MAAM,WAAW;CAC1E,OAAO,MAAM;AACf"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { RefObject } from "react";
|
|
2
|
+
//#region src/react/utils/useNextRenderData.d.ts
|
|
3
|
+
interface NextRenderDataSource<TInput, TData> {
|
|
4
|
+
__getNextRenderData(input: TInput): TData;
|
|
5
|
+
}
|
|
6
|
+
declare function useNextRenderData<TInput, TData>(instanceRef: RefObject<NextRenderDataSource<TInput, TData> | null>, input: TInput): TData | undefined;
|
|
7
|
+
//#endregion
|
|
8
|
+
export { useNextRenderData };
|
|
9
|
+
//# sourceMappingURL=useNextRenderData.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useNextRenderData.d.ts","names":[],"sources":["../../../src/react/utils/useNextRenderData.ts"],"mappings":";;UAEU,qBAAqB,QAAQ;EACrC,oBAAoB,OAAO,SAAS;;iBAMtB,kBAAkB,QAAQ,OACxC,aAAa,UAAU,qBAAqB,QAAQ,gBACpD,OAAO,SACN"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
//#region src/react/utils/useNextRenderData.ts
|
|
2
|
+
function useNextRenderData(instanceRef, input) {
|
|
3
|
+
"use no memo";
|
|
4
|
+
return instanceRef.current?.__getNextRenderData(input);
|
|
5
|
+
}
|
|
6
|
+
//#endregion
|
|
7
|
+
export { useNextRenderData };
|
|
8
|
+
|
|
9
|
+
//# sourceMappingURL=useNextRenderData.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useNextRenderData.js","names":[],"sources":["../../../src/react/utils/useNextRenderData.ts"],"sourcesContent":["import type { RefObject } from 'react';\n\ninterface NextRenderDataSource<TInput, TData> {\n __getNextRenderData(input: TInput): TData;\n}\n\n// Read the data the instance will display once render() receives this input.\n// The instance can change it without new props, so this must not be memoized.\n// Returns undefined before the instance exists.\nexport function useNextRenderData<TInput, TData>(\n instanceRef: RefObject<NextRenderDataSource<TInput, TData> | null>,\n input: TInput\n): TData | undefined {\n 'use no memo';\n // oxlint-disable-next-line react/refs -- the instance changes without new props\n return instanceRef.current?.__getNextRenderData(input);\n}\n"],"mappings":";AASA,SAAgB,kBACd,aACA,OACmB;CACnB;CAEA,OAAO,YAAY,SAAS,oBAAoB,KAAK;AACvD"}
|
|
@@ -16,6 +16,7 @@ interface UseUnresolvedFileInstanceProps<LAnnotation> {
|
|
|
16
16
|
disableWorkerPool: boolean;
|
|
17
17
|
}
|
|
18
18
|
interface UseUnresolvedFileInstanceReturn<LAnnotation> {
|
|
19
|
+
lineAnnotations: DiffLineAnnotation<LAnnotation>[];
|
|
19
20
|
fileDiff: FileDiffMetadata;
|
|
20
21
|
actions: (MergeConflictDiffAction | undefined)[];
|
|
21
22
|
markerRows: MergeConflictMarkerRow[];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useUnresolvedFileInstance.d.ts","names":[],"sources":["../../../src/react/utils/useUnresolvedFileInstance.ts"],"mappings":";;;;;;
|
|
1
|
+
{"version":3,"file":"useUnresolvedFileInstance.d.ts","names":[],"sources":["../../../src/react/utils/useUnresolvedFileInstance.ts"],"mappings":";;;;;;UAuCU,+BAA+B;EACvC,MAAM;EACN,UAAU,2BAA2B;EACrC,iBAAiB,mBAAmB;EACpC,eAAe;EACf;EACA;EACA;EACA;EACA;;UAGQ,gCAAgC;EACxC,iBAAiB,mBAAmB;EACpC,UAAU;EACV,UAAU;EACV,YAAY;EACZ,IAAI,MAAM;EACV,kBAAkB;EAClB,eAAe,eAAe;;iBAGhB,0BAA0B,eACxC,MACA,SACA,iBACA,eACA,iBACA,oBACA,wBACA,iBACA,qBACC,+BAA+B,eAAe,gCAAgC"}
|
|
@@ -1,9 +1,12 @@
|
|
|
1
|
+
import { EMPTY_LINE_ANNOTATIONS } from "../../constants.js";
|
|
1
2
|
import { areOptionsEqual } from "../../utils/areOptionsEqual.js";
|
|
2
3
|
import { parseMergeConflictDiffFromFile } from "../../utils/parseMergeConflictDiffFromFile.js";
|
|
3
4
|
import { UnresolvedFile } from "../../components/UnresolvedFile.js";
|
|
4
5
|
import { useStableCallback } from "./useStableCallback.js";
|
|
5
6
|
import { noopRender } from "../constants.js";
|
|
6
7
|
import { WorkerPoolContext } from "../WorkerPoolContext.js";
|
|
8
|
+
import { useForceUpdate } from "./useForceUpdate.js";
|
|
9
|
+
import { useNextRenderData } from "./useNextRenderData.js";
|
|
7
10
|
import { useCallback, useContext, useEffect, useLayoutEffect, useRef, useState } from "react";
|
|
8
11
|
//#region src/react/utils/useUnresolvedFileInstance.ts
|
|
9
12
|
const useIsomorphicLayoutEffect = typeof window === "undefined" ? useEffect : useLayoutEffect;
|
|
@@ -30,6 +33,18 @@ function useUnresolvedFileInstance({ file, options, lineAnnotations, selectedLin
|
|
|
30
33
|
const controlledSelection = selectedLines !== void 0;
|
|
31
34
|
const poolManager = useContext(WorkerPoolContext);
|
|
32
35
|
const instanceRef = useRef(null);
|
|
36
|
+
const forceUpdate = useForceUpdate();
|
|
37
|
+
const renderData = useNextRenderData(instanceRef, {
|
|
38
|
+
fileDiff,
|
|
39
|
+
actions,
|
|
40
|
+
markerRows,
|
|
41
|
+
lineAnnotations
|
|
42
|
+
}) ?? {
|
|
43
|
+
fileDiff,
|
|
44
|
+
actions,
|
|
45
|
+
markerRows,
|
|
46
|
+
lineAnnotations: lineAnnotations ?? EMPTY_LINE_ANNOTATIONS
|
|
47
|
+
};
|
|
33
48
|
const ref = useStableCallback((fileContainer) => {
|
|
34
49
|
if (fileContainer != null) {
|
|
35
50
|
if (instanceRef.current != null) throw new Error("useUnresolvedFileInstance: An instance should not already exist when a node is created");
|
|
@@ -40,7 +55,7 @@ function useUnresolvedFileInstance({ file, options, lineAnnotations, selectedLin
|
|
|
40
55
|
hasGutterRenderUtility,
|
|
41
56
|
onMergeConflictAction,
|
|
42
57
|
options
|
|
43
|
-
}), !disableWorkerPool ? poolManager : void 0,
|
|
58
|
+
}), !disableWorkerPool ? poolManager : void 0, forceUpdate);
|
|
44
59
|
instanceRef.current.hydrate({
|
|
45
60
|
fileDiff,
|
|
46
61
|
actions,
|
|
@@ -66,7 +81,7 @@ function useUnresolvedFileInstance({ file, options, lineAnnotations, selectedLin
|
|
|
66
81
|
onMergeConflictAction,
|
|
67
82
|
options
|
|
68
83
|
});
|
|
69
|
-
const forceRender =
|
|
84
|
+
const forceRender = !areOptionsEqual(instance.options, newOptions);
|
|
70
85
|
instance.setOptions(newOptions);
|
|
71
86
|
instance.render({
|
|
72
87
|
fileDiff,
|
|
@@ -77,17 +92,17 @@ function useUnresolvedFileInstance({ file, options, lineAnnotations, selectedLin
|
|
|
77
92
|
});
|
|
78
93
|
if (selectedLines !== void 0) instance.setSelectedLines(selectedLines);
|
|
79
94
|
});
|
|
95
|
+
const getHoveredLine = useCallback(() => {
|
|
96
|
+
return instanceRef.current?.getHoveredLine();
|
|
97
|
+
}, []);
|
|
98
|
+
const getInstance = useCallback(() => {
|
|
99
|
+
return instanceRef.current ?? void 0;
|
|
100
|
+
}, []);
|
|
80
101
|
return {
|
|
102
|
+
...renderData,
|
|
81
103
|
ref,
|
|
82
|
-
getHoveredLine
|
|
83
|
-
|
|
84
|
-
}, []),
|
|
85
|
-
fileDiff,
|
|
86
|
-
actions,
|
|
87
|
-
markerRows,
|
|
88
|
-
getInstance: useCallback(() => {
|
|
89
|
-
return instanceRef.current ?? void 0;
|
|
90
|
-
}, [])
|
|
104
|
+
getHoveredLine,
|
|
105
|
+
getInstance
|
|
91
106
|
};
|
|
92
107
|
}
|
|
93
108
|
function mergeUnresolvedOptions({ options, controlledSelection, onMergeConflictAction, hasConflictUtility, hasCustomHeader, hasGutterRenderUtility }) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useUnresolvedFileInstance.js","names":["UnresolvedFileClass"],"sources":["../../../src/react/utils/useUnresolvedFileInstance.ts"],"sourcesContent":["import {\n useCallback,\n useContext,\n useEffect,\n useLayoutEffect,\n useRef,\n useState,\n} from 'react';\n\nimport {\n UnresolvedFile,\n UnresolvedFile as UnresolvedFileClass,\n type UnresolvedFileOptions,\n} from '../../components/UnresolvedFile';\nimport type { GetHoveredLineResult } from '../../managers/InteractionManager';\nimport type {\n DiffLineAnnotation,\n FileContents,\n FileDiffMetadata,\n MergeConflictActionPayload,\n MergeConflictMarkerRow,\n SelectedLineRange,\n} from '../../types';\nimport { areOptionsEqual } from '../../utils/areOptionsEqual';\nimport {\n type MergeConflictDiffAction,\n parseMergeConflictDiffFromFile,\n} from '../../utils/parseMergeConflictDiffFromFile';\nimport { noopRender } from '../constants';\nimport type { UnresolvedFileReactOptions } from '../UnresolvedFile';\nimport { WorkerPoolContext } from '../WorkerPoolContext';\nimport { useStableCallback } from './useStableCallback';\n\nconst useIsomorphicLayoutEffect =\n typeof window === 'undefined' ? useEffect : useLayoutEffect;\n\ninterface UseUnresolvedFileInstanceProps<LAnnotation> {\n file: FileContents;\n options?: UnresolvedFileReactOptions<LAnnotation>;\n lineAnnotations: DiffLineAnnotation<LAnnotation>[] | undefined;\n selectedLines: SelectedLineRange | null | undefined;\n prerenderedHTML: string | undefined;\n hasConflictUtility: boolean;\n hasGutterRenderUtility: boolean;\n hasCustomHeader: boolean;\n disableWorkerPool: boolean;\n}\n\ninterface UseUnresolvedFileInstanceReturn<LAnnotation> {\n fileDiff: FileDiffMetadata;\n actions: (MergeConflictDiffAction | undefined)[];\n markerRows: MergeConflictMarkerRow[];\n ref(node: HTMLElement | null): void;\n getHoveredLine(): GetHoveredLineResult<'diff'> | undefined;\n getInstance(): UnresolvedFile<LAnnotation> | undefined;\n}\n\nexport function useUnresolvedFileInstance<LAnnotation>({\n file,\n options,\n lineAnnotations,\n selectedLines,\n prerenderedHTML,\n hasConflictUtility,\n hasGutterRenderUtility,\n hasCustomHeader,\n disableWorkerPool,\n}: UseUnresolvedFileInstanceProps<LAnnotation>): UseUnresolvedFileInstanceReturn<LAnnotation> {\n const [{ fileDiff, actions, markerRows }, setState] = useState(() => {\n const { fileDiff, actions, markerRows } = parseMergeConflictDiffFromFile(\n file,\n options?.maxContextLines\n );\n return { fileDiff, actions, markerRows };\n });\n // UnresolvedFile is intentionally uncontrolled in React. Keep an internal\n // source-of-truth file so sequential conflict actions apply to the latest\n // resolved contents rather than the initial prop value.\n const onMergeConflictAction = useStableCallback(\n (\n payload: MergeConflictActionPayload,\n instance: UnresolvedFile<LAnnotation>\n ) => {\n setState((prevState) => {\n const { fileDiff, actions, markerRows } =\n instance.resolveConflict(\n payload.conflict.conflictIndex,\n payload.resolution,\n prevState.fileDiff\n ) ?? {};\n if (fileDiff == null || actions == null || markerRows == null) {\n return prevState;\n } else {\n return { fileDiff, actions, markerRows };\n }\n });\n }\n );\n const controlledSelection = selectedLines !== undefined;\n const poolManager = useContext(WorkerPoolContext);\n const instanceRef = useRef<UnresolvedFileClass<LAnnotation> | null>(null);\n const ref = useStableCallback((fileContainer: HTMLElement | null) => {\n if (fileContainer != null) {\n if (instanceRef.current != null) {\n throw new Error(\n 'useUnresolvedFileInstance: An instance should not already exist when a node is created'\n );\n }\n instanceRef.current = new UnresolvedFileClass(\n mergeUnresolvedOptions({\n controlledSelection,\n hasConflictUtility,\n hasCustomHeader,\n hasGutterRenderUtility,\n onMergeConflictAction,\n options,\n }),\n !disableWorkerPool ? poolManager : undefined,\n
|
|
1
|
+
{"version":3,"file":"useUnresolvedFileInstance.js","names":["UnresolvedFileClass"],"sources":["../../../src/react/utils/useUnresolvedFileInstance.ts"],"sourcesContent":["import {\n useCallback,\n useContext,\n useEffect,\n useLayoutEffect,\n useRef,\n useState,\n} from 'react';\n\nimport {\n UnresolvedFile,\n UnresolvedFile as UnresolvedFileClass,\n type UnresolvedFileOptions,\n} from '../../components/UnresolvedFile';\nimport { EMPTY_LINE_ANNOTATIONS } from '../../constants';\nimport type { GetHoveredLineResult } from '../../managers/InteractionManager';\nimport type {\n DiffLineAnnotation,\n FileContents,\n FileDiffMetadata,\n MergeConflictActionPayload,\n MergeConflictMarkerRow,\n SelectedLineRange,\n} from '../../types';\nimport { areOptionsEqual } from '../../utils/areOptionsEqual';\nimport {\n type MergeConflictDiffAction,\n parseMergeConflictDiffFromFile,\n} from '../../utils/parseMergeConflictDiffFromFile';\nimport { noopRender } from '../constants';\nimport type { UnresolvedFileReactOptions } from '../UnresolvedFile';\nimport { WorkerPoolContext } from '../WorkerPoolContext';\nimport { useForceUpdate } from './useForceUpdate';\nimport { useNextRenderData } from './useNextRenderData';\nimport { useStableCallback } from './useStableCallback';\n\nconst useIsomorphicLayoutEffect =\n typeof window === 'undefined' ? useEffect : useLayoutEffect;\n\ninterface UseUnresolvedFileInstanceProps<LAnnotation> {\n file: FileContents;\n options?: UnresolvedFileReactOptions<LAnnotation>;\n lineAnnotations: DiffLineAnnotation<LAnnotation>[] | undefined;\n selectedLines: SelectedLineRange | null | undefined;\n prerenderedHTML: string | undefined;\n hasConflictUtility: boolean;\n hasGutterRenderUtility: boolean;\n hasCustomHeader: boolean;\n disableWorkerPool: boolean;\n}\n\ninterface UseUnresolvedFileInstanceReturn<LAnnotation> {\n lineAnnotations: DiffLineAnnotation<LAnnotation>[];\n fileDiff: FileDiffMetadata;\n actions: (MergeConflictDiffAction | undefined)[];\n markerRows: MergeConflictMarkerRow[];\n ref(node: HTMLElement | null): void;\n getHoveredLine(): GetHoveredLineResult<'diff'> | undefined;\n getInstance(): UnresolvedFile<LAnnotation> | undefined;\n}\n\nexport function useUnresolvedFileInstance<LAnnotation>({\n file,\n options,\n lineAnnotations,\n selectedLines,\n prerenderedHTML,\n hasConflictUtility,\n hasGutterRenderUtility,\n hasCustomHeader,\n disableWorkerPool,\n}: UseUnresolvedFileInstanceProps<LAnnotation>): UseUnresolvedFileInstanceReturn<LAnnotation> {\n const [{ fileDiff, actions, markerRows }, setState] = useState(() => {\n const { fileDiff, actions, markerRows } = parseMergeConflictDiffFromFile(\n file,\n options?.maxContextLines\n );\n return { fileDiff, actions, markerRows };\n });\n // UnresolvedFile is intentionally uncontrolled in React. Keep an internal\n // source-of-truth file so sequential conflict actions apply to the latest\n // resolved contents rather than the initial prop value.\n const onMergeConflictAction = useStableCallback(\n (\n payload: MergeConflictActionPayload,\n instance: UnresolvedFile<LAnnotation>\n ) => {\n setState((prevState) => {\n const { fileDiff, actions, markerRows } =\n instance.resolveConflict(\n payload.conflict.conflictIndex,\n payload.resolution,\n prevState.fileDiff\n ) ?? {};\n if (fileDiff == null || actions == null || markerRows == null) {\n return prevState;\n } else {\n return { fileDiff, actions, markerRows };\n }\n });\n }\n );\n const controlledSelection = selectedLines !== undefined;\n const poolManager = useContext(WorkerPoolContext);\n const instanceRef = useRef<UnresolvedFileClass<LAnnotation> | null>(null);\n const forceUpdate = useForceUpdate();\n const renderData = useNextRenderData(instanceRef, {\n fileDiff,\n actions,\n markerRows,\n lineAnnotations,\n }) ?? {\n fileDiff,\n actions,\n markerRows,\n lineAnnotations: lineAnnotations ?? EMPTY_LINE_ANNOTATIONS,\n };\n const ref = useStableCallback((fileContainer: HTMLElement | null) => {\n if (fileContainer != null) {\n if (instanceRef.current != null) {\n throw new Error(\n 'useUnresolvedFileInstance: An instance should not already exist when a node is created'\n );\n }\n instanceRef.current = new UnresolvedFileClass(\n mergeUnresolvedOptions({\n controlledSelection,\n hasConflictUtility,\n hasCustomHeader,\n hasGutterRenderUtility,\n onMergeConflictAction,\n options,\n }),\n !disableWorkerPool ? poolManager : undefined,\n forceUpdate\n );\n void instanceRef.current.hydrate({\n fileDiff,\n actions,\n markerRows,\n fileContainer,\n lineAnnotations,\n prerenderedHTML,\n });\n } else {\n if (instanceRef.current == null) {\n throw new Error(\n 'useUnresolvedFileInstance: A UnresolvedFile instance should exist when unmounting'\n );\n }\n instanceRef.current.cleanUp();\n instanceRef.current = null;\n }\n });\n\n useIsomorphicLayoutEffect(() => {\n if (instanceRef.current == null) return;\n const instance = instanceRef.current;\n const newOptions = mergeUnresolvedOptions({\n controlledSelection,\n hasConflictUtility,\n hasCustomHeader,\n hasGutterRenderUtility,\n onMergeConflictAction,\n options,\n });\n const forceRender = !areOptionsEqual(instance.options, newOptions);\n instance.setOptions(newOptions);\n void instance.render({\n fileDiff,\n actions,\n markerRows,\n lineAnnotations,\n forceRender,\n });\n if (selectedLines !== undefined) {\n instance.setSelectedLines(selectedLines);\n }\n });\n\n const getHoveredLine = useCallback(():\n | GetHoveredLineResult<'diff'>\n | undefined => {\n return instanceRef.current?.getHoveredLine();\n }, []);\n\n const getInstance = useCallback(() => {\n return instanceRef.current ?? undefined;\n }, []);\n\n return { ...renderData, ref, getHoveredLine, getInstance };\n}\n\ninterface MergeUnresolvedOptionsProps<LAnnotation> {\n options: UnresolvedFileReactOptions<LAnnotation> | undefined;\n controlledSelection: boolean;\n onMergeConflictAction: UnresolvedFileOptions<LAnnotation>['onMergeConflictAction'];\n hasConflictUtility: boolean;\n hasGutterRenderUtility: boolean;\n hasCustomHeader: boolean;\n}\n\nfunction mergeUnresolvedOptions<LAnnotation>({\n options,\n controlledSelection,\n onMergeConflictAction,\n hasConflictUtility,\n hasCustomHeader,\n hasGutterRenderUtility,\n}: MergeUnresolvedOptionsProps<LAnnotation>): UnresolvedFileOptions<LAnnotation> {\n return {\n ...options,\n controlledSelection,\n onMergeConflictAction,\n hunkSeparators:\n options?.hunkSeparators === 'custom'\n ? noopRender\n : options?.hunkSeparators,\n // Add a placeholder type for the custom render\n mergeConflictActionsType:\n hasConflictUtility || options?.mergeConflictActionsType === 'custom'\n ? noopRender\n : options?.mergeConflictActionsType,\n renderCustomHeader: hasCustomHeader ? noopRender : undefined,\n renderGutterUtility: hasGutterRenderUtility ? noopRender : undefined,\n };\n}\n"],"mappings":";;;;;;;;;;;AAoCA,MAAM,4BACJ,OAAO,WAAW,cAAc,YAAY;AAwB9C,SAAgB,0BAAuC,EACrD,MACA,SACA,iBACA,eACA,iBACA,oBACA,wBACA,iBACA,qBAC4F;CAC5F,MAAM,CAAC,EAAE,UAAU,SAAS,cAAc,YAAY,eAAe;EACnE,MAAM,EAAE,UAAU,SAAS,eAAe,+BACxC,MACA,SAAS,eACX;EACA,OAAO;GAAE;GAAU;GAAS;EAAW;CACzC,CAAC;CAID,MAAM,wBAAwB,mBAE1B,SACA,aACG;EACH,UAAU,cAAc;GACtB,MAAM,EAAE,UAAU,SAAS,eACzB,SAAS,gBACP,QAAQ,SAAS,eACjB,QAAQ,YACR,UAAU,QACZ,KAAK,CAAC;GACR,IAAI,YAAY,QAAQ,WAAW,QAAQ,cAAc,MACvD,OAAO;QAEP,OAAO;IAAE;IAAU;IAAS;GAAW;EAE3C,CAAC;CACH,CACF;CACA,MAAM,sBAAsB,kBAAkB,KAAA;CAC9C,MAAM,cAAc,WAAW,iBAAiB;CAChD,MAAM,cAAc,OAAgD,IAAI;CACxE,MAAM,cAAc,eAAe;CACnC,MAAM,aAAa,kBAAkB,aAAa;EAChD;EACA;EACA;EACA;CACF,CAAC,KAAK;EACJ;EACA;EACA;EACA,iBAAiB,mBAAmB;CACtC;CACA,MAAM,MAAM,mBAAmB,kBAAsC;EACnE,IAAI,iBAAiB,MAAM;GACzB,IAAI,YAAY,WAAW,MACzB,MAAM,IAAI,MACR,wFACF;GAEF,YAAY,UAAU,IAAIA,eACxB,uBAAuB;IACrB;IACA;IACA;IACA;IACA;IACA;GACF,CAAC,GACD,CAAC,oBAAoB,cAAc,KAAA,GACnC,WACF;GACA,YAAiB,QAAQ,QAAQ;IAC/B;IACA;IACA;IACA;IACA;IACA;GACF,CAAC;EACH,OAAO;GACL,IAAI,YAAY,WAAW,MACzB,MAAM,IAAI,MACR,mFACF;GAEF,YAAY,QAAQ,QAAQ;GAC5B,YAAY,UAAU;EACxB;CACF,CAAC;CAED,gCAAgC;EAC9B,IAAI,YAAY,WAAW,MAAM;EACjC,MAAM,WAAW,YAAY;EAC7B,MAAM,aAAa,uBAAuB;GACxC;GACA;GACA;GACA;GACA;GACA;EACF,CAAC;EACD,MAAM,cAAc,CAAC,gBAAgB,SAAS,SAAS,UAAU;EACjE,SAAS,WAAW,UAAU;EAC9B,SAAc,OAAO;GACnB;GACA;GACA;GACA;GACA;EACF,CAAC;EACD,IAAI,kBAAkB,KAAA,GACpB,SAAS,iBAAiB,aAAa;CAE3C,CAAC;CAED,MAAM,iBAAiB,kBAEN;EACf,OAAO,YAAY,SAAS,eAAe;CAC7C,GAAG,CAAC,CAAC;CAEL,MAAM,cAAc,kBAAkB;EACpC,OAAO,YAAY,WAAW,KAAA;CAChC,GAAG,CAAC,CAAC;CAEL,OAAO;EAAE,GAAG;EAAY;EAAK;EAAgB;CAAY;AAC3D;AAWA,SAAS,uBAAoC,EAC3C,SACA,qBACA,uBACA,oBACA,iBACA,0BAC+E;CAC/E,OAAO;EACL,GAAG;EACH;EACA;EACA,gBACE,SAAS,mBAAmB,WACxB,aACA,SAAS;EAEf,0BACE,sBAAsB,SAAS,6BAA6B,WACxD,aACA,SAAS;EACf,oBAAoB,kBAAkB,aAAa,KAAA;EACnD,qBAAqB,yBAAyB,aAAa,KAAA;CAC7D;AACF"}
|
|
@@ -78,7 +78,6 @@ declare class DiffHunksRenderer<LAnnotation = undefined> {
|
|
|
78
78
|
private onRenderUpdate?;
|
|
79
79
|
private workerManager?;
|
|
80
80
|
readonly __id: string;
|
|
81
|
-
private highlighter;
|
|
82
81
|
private diff;
|
|
83
82
|
private expandedHunks;
|
|
84
83
|
private deletionAnnotations;
|
|
@@ -148,6 +147,8 @@ declare class DiffHunksRenderer<LAnnotation = undefined> {
|
|
|
148
147
|
protected getOptionsWithDefaults(): DiffHunksRendererOptionsWithDefaults;
|
|
149
148
|
initializeHighlighter(): Promise<DiffsHighlighter>;
|
|
150
149
|
hydrate(diff: FileDiffMetadata | undefined): void;
|
|
150
|
+
private getHighlightWorkerManager;
|
|
151
|
+
private cacheHighlightResult;
|
|
151
152
|
private getLocalHighlightTheme;
|
|
152
153
|
getEffectiveCodeOptions(): Pick<BaseCodeOptions, 'theme' | 'tokenizeMaxLineLength'>;
|
|
153
154
|
private getRenderOptions;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DiffHunksRenderer.d.ts","names":[],"sources":["../../src/renderers/DiffHunksRenderer.ts"],"mappings":";;;;;;;;
|
|
1
|
+
{"version":3,"file":"DiffHunksRenderer.d.ts","names":[],"sources":["../../src/renderers/DiffHunksRenderer.ts"],"mappings":";;;;;;;;UAuJiB,iCAAiC;EAChD,mBAAmB;;UAGJ,6CAA6C,KAC5D;EAGA,kBAAkB;;UAGH;EACf;EACA,UAAU;EACV;EACA;;UAGe;EACf;EACA;EACA;;UAGe;EACf,gBAAgB;EAChB,mBAAmB;EACnB,oBAAoB;;UAUL;EACf;EACA;EACA;EACA;EACA;EACA,eAAe;EACf,eAAe;;UAGA;EACf,SAAS;EACT,QAAQ;;UAGO;EACf,UAAU;EACV,UAAU;;UAGK;EACf,SAAS;EACT,QAAQ;;UAGO;EACf,SAAS;EACT,QAAQ;;UAGO;EACf,UAAU;EACV,kBAAkB;EAClB,mBAAmB;EACnB,oBAAoB;EACpB,qBAAqB;EACrB,oBAAoB;EACpB,qBAAqB;EACrB,UAAU;EACV;EACA,SAAS;EACT,eAAe;EACf;EACA;EACA;EACA;EACA;EACA;;cAKW,kBAAkB;EA+BpB,SAAS;UACR;UAGA;UACA;WAnCD;UAKD;UAEA;UAEA;UACA;UAEA;UACA;UAGA;UAGA;UAQA;EAER,YACS,UAAS,0BACR,sBACN,YAAY,mBAAmB,yBAEzB,8CACA,gBAAgB;EAGnB;EAQA;;;;;;;;;;EA2BA,iBACL,MAAM,kBACN,eAAe;;EA0EV;;;;EAWA;;;;;;;;;;EAiBA,4BAA4B;UA0C3B;MA4BG,aAAa;EAIjB;EAMA,WAAW,SAAS;EAIpB,aAAa,SAAS,QAAQ;EAI9B,WACL,eACA,WAAW,qBACX;EA0BK,gBAAgB,oBAAoB;EAIpC,uBAAuB,YAAY;;EAKnC,oBACL,eAAe,YAAY;EAKtB,mBACL,iBAAiB,mBAAmB;;;;;;;EAyB/B,kBACL,YAAY,YAAY,MAAM,oBAC9B,6BACA,mCACA,uBAAuB,6BACvB;UAwKM;EAWD,oBACL,cAAc,0BAA0B;UAoElC;UA6BA;UAaA;YAOE,2BACR,YACC,6BAA6B;YAStB,yBACR,MACA,QACC,2BAA2B;UAetB;YAKU,iCAChB,KAAK,wBACF;YAGa,+BAChB,KAAK,wBACF;YAEK,0BAA0B;EAiD7B,yBAAyB,QAAQ;EAYjC,QAAQ,MAAM;UAwCb;UAWA;UAUA;EAQD,2BAA2B,KAChC;UAeM;;;;;;EA2CD,qBAAqB,MAAM,mBAAmB;UAwB7C;EA+BD,WACL,OAAM,8BACN,cAAa,cACZ;EAuJU,YACX,MAAM,kBACN,cAAa,cACZ,QAAQ;YASD,iBACR,gBACA,oBACA,mBAAmB,sBAClB;UAeW;UA2BN;EA6CD,mBACL,MAAM,kBACN,QAAQ,kBACR,SAAS,mBACT;UAQM;UAqCA;UAgBA;UAuBA;EAaD,iBAAiB;UAIhB;UAIA;EAmjBD,cACL,6CACA,QAAQ,oBACP;EAyBI,cACL,QAAQ,mBACR,WAAU,mBACT;EAkDI,eACL,QAAQ,mBACR,eAAc;EAKT,kBACL,UAAU,kBACV;UAqBM;UAiEA;UA+DA;UASA"}
|