@git-diff-view/react 0.1.3 → 0.1.5
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/cjs/index.development.js +497 -503
- package/dist/cjs/index.development.js.map +1 -1
- package/dist/cjs/index.production.js +497 -503
- package/dist/cjs/index.production.js.map +1 -1
- package/dist/css/diff-view-pure.css +111 -0
- package/dist/css/diff-view.css +111 -0
- package/dist/esm/index.mjs +499 -506
- package/dist/esm/index.mjs.map +1 -1
- package/index.d.ts +239 -7
- package/package.json +2 -2
- package/src/_com.css +99 -0
- package/src/components/DiffAddWidget.tsx +4 -3
- package/src/components/DiffContent.tsx +6 -6
- package/src/components/DiffExpand.tsx +0 -2
- package/src/components/DiffNoNewLine.tsx +0 -2
- package/src/components/DiffSplitContentLineNormal.tsx +3 -4
- package/src/components/DiffSplitContentLineWrap.tsx +9 -10
- package/src/components/DiffSplitExtendLineNormal.tsx +3 -3
- package/src/components/DiffSplitExtendLineWrap.tsx +4 -4
- package/src/components/DiffSplitHunkLineNormal.tsx +0 -1
- package/src/components/DiffSplitHunkLineWrap.tsx +0 -1
- package/src/components/DiffSplitView.tsx +0 -1
- package/src/components/DiffSplitViewNormal.tsx +13 -12
- package/src/components/DiffSplitViewWrap.tsx +10 -10
- package/src/components/DiffSplitWidgetLineNormal.tsx +2 -2
- package/src/components/DiffSplitWidgetLineWrap.tsx +12 -2
- package/src/components/DiffUnifiedContentLine.tsx +1 -2
- package/src/components/DiffUnifiedExtendLine.tsx +4 -5
- package/src/components/DiffUnifiedHunkLine.tsx +0 -1
- package/src/components/DiffUnifiedView.tsx +9 -9
- package/src/components/DiffUnifiedWidgetLine.tsx +2 -2
- package/src/components/DiffView.tsx +26 -20
- package/src/components/DiffViewContext.ts +2 -0
- package/src/components/DiffViewWithMultiSelect.tsx +321 -0
- package/src/components/DiffWidgetContext.ts +4 -2
- package/src/components/tools.ts +6 -5
- package/src/components/v2/DiffSplitContentLineNormal_v2.tsx +4 -5
- package/src/components/v2/DiffSplitContentLineWrap_v2.tsx +11 -12
- package/src/components/v2/DiffSplitExtendLineNormal_v2.tsx +3 -3
- package/src/components/v2/DiffSplitExtendLineWrap_v2.tsx +4 -4
- package/src/components/v2/DiffSplitHunkLineNormal_v2.tsx +0 -1
- package/src/components/v2/DiffSplitHunkLineWrap_v2.tsx +0 -1
- package/src/components/v2/DiffSplitViewLineNormal_v2.tsx +0 -1
- package/src/components/v2/DiffSplitViewLineWrap_v2.tsx +0 -1
- package/src/components/v2/DiffSplitViewNormal_v2.tsx +9 -8
- package/src/components/v2/DiffSplitViewWrap_v2.tsx +5 -5
- package/src/components/v2/DiffSplitView_v2.tsx +0 -1
- package/src/components/v2/DiffSplitWidgetLineNormal_v2.tsx +2 -3
- package/src/components/v2/DiffSplitWidgetLineWrap_v2.tsx +4 -5
- package/src/hooks/useCallbackRef.ts +13 -0
- package/src/hooks/useDomWidth.ts +5 -5
- package/src/hooks/useIsMounted.ts +1 -0
- package/src/hooks/useSyncHeight.ts +3 -3
- package/src/hooks/useTextWidth.ts +1 -1
- package/src/hooks/useUnmount.ts +1 -0
- package/src/hooks/useUpdateEffect.ts +15 -0
- package/src/index.ts +1 -2
- package/styles/diff-view-pure.css +111 -0
- package/styles/diff-view.css +111 -0
|
@@ -0,0 +1,321 @@
|
|
|
1
|
+
import { useCallback, useEffect, useMemo, useRef, useImperativeHandle, forwardRef } from "react";
|
|
2
|
+
|
|
3
|
+
import { multiSelectClassNames, createDiffMultiSelectManager } from "..";
|
|
4
|
+
import { useCallbackRef } from "../hooks/useCallbackRef";
|
|
5
|
+
import { useUpdateEffect } from "../hooks/useUpdateEffect";
|
|
6
|
+
|
|
7
|
+
import { DiffModeEnum, DiffView, SplitSide } from "./DiffView";
|
|
8
|
+
|
|
9
|
+
import type {
|
|
10
|
+
MultiSelectResult,
|
|
11
|
+
LineRange,
|
|
12
|
+
MultiSelectState,
|
|
13
|
+
DiffFile,
|
|
14
|
+
DiffMultiSelectManager,
|
|
15
|
+
MultiSelectOptions,
|
|
16
|
+
extendDataToPreselectedLines,
|
|
17
|
+
} from "..";
|
|
18
|
+
import type { DiffViewProps } from "./DiffView";
|
|
19
|
+
import type { ForwardedRef, ReactNode } from "react";
|
|
20
|
+
|
|
21
|
+
export interface DiffViewWithMultiSelectProps<T = unknown> extends Omit<
|
|
22
|
+
DiffViewProps<T>,
|
|
23
|
+
"renderWidgetLine" | "onAddWidgetClick"
|
|
24
|
+
> {
|
|
25
|
+
/**
|
|
26
|
+
* Enable multi-select feature
|
|
27
|
+
* @default true
|
|
28
|
+
*/
|
|
29
|
+
enableMultiSelect?: boolean;
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Callback when multi-line selection is complete
|
|
33
|
+
* Use this to open a comment dialog or handle the selection
|
|
34
|
+
*/
|
|
35
|
+
onMultiSelectComplete?: (result: MultiSelectResult) => void;
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Callback when selection changes (during drag)
|
|
39
|
+
*/
|
|
40
|
+
onMultiSelectChange?: (range: LineRange | null, state: MultiSelectState) => void;
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Custom function to scope selection to one hunk
|
|
44
|
+
* Return the scoped range or null to cancel selection
|
|
45
|
+
*/
|
|
46
|
+
scopeMultiSelectToHunk?: (range: LineRange) => LineRange | null;
|
|
47
|
+
|
|
48
|
+
onAddWidgetClick?: (props: { lineNumber: number; fromLineNumber?: number; side: SplitSide }) => void;
|
|
49
|
+
|
|
50
|
+
renderWidgetLine?: (props: {
|
|
51
|
+
lineNumber: number;
|
|
52
|
+
fromLineNumber: number;
|
|
53
|
+
side: SplitSide;
|
|
54
|
+
diffFile: DiffFile;
|
|
55
|
+
onClose: () => void;
|
|
56
|
+
}) => ReactNode;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export interface DiffViewWithMultiSelectRef {
|
|
60
|
+
getDiffFileInstance: () => DiffFile | null;
|
|
61
|
+
getSelectionResult: () => MultiSelectResult | null;
|
|
62
|
+
getSelectionState: () => MultiSelectState;
|
|
63
|
+
clearSelection: () => void;
|
|
64
|
+
setPreselectedLines: (lines: { old: number[]; new: number[] }) => void;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
type MultiResult = ReturnType<typeof extendDataToPreselectedLines>;
|
|
68
|
+
|
|
69
|
+
/* eslint-disable @typescript-eslint/no-unnecessary-type-constraint */
|
|
70
|
+
const InternalDiffViewWithMultiSelect = <T extends unknown>(
|
|
71
|
+
props: DiffViewWithMultiSelectProps<T>,
|
|
72
|
+
ref: ForwardedRef<DiffViewWithMultiSelectRef>
|
|
73
|
+
) => {
|
|
74
|
+
const {
|
|
75
|
+
enableMultiSelect = true,
|
|
76
|
+
extendData,
|
|
77
|
+
onMultiSelectComplete,
|
|
78
|
+
onMultiSelectChange,
|
|
79
|
+
scopeMultiSelectToHunk,
|
|
80
|
+
renderWidgetLine,
|
|
81
|
+
onAddWidgetClick,
|
|
82
|
+
diffViewMode = DiffModeEnum.SplitGitHub,
|
|
83
|
+
...restProps
|
|
84
|
+
} = props;
|
|
85
|
+
|
|
86
|
+
const memoSelectChange = useCallbackRef(onMultiSelectChange);
|
|
87
|
+
|
|
88
|
+
const memoSelectComplete = useCallbackRef(onMultiSelectComplete);
|
|
89
|
+
|
|
90
|
+
const memoScopeSelectToHunk = useCallbackRef(scopeMultiSelectToHunk);
|
|
91
|
+
|
|
92
|
+
const containerRef = useRef<HTMLDivElement>(null);
|
|
93
|
+
const diffViewRef = useRef<{ getDiffFileInstance: () => DiffFile | null }>(null);
|
|
94
|
+
const managerRef = useRef<DiffMultiSelectManager | null>(null);
|
|
95
|
+
|
|
96
|
+
const multiResultRef = useRef<MultiResult>(undefined);
|
|
97
|
+
|
|
98
|
+
const isUnifiedMode = !(diffViewMode & DiffModeEnum.Split);
|
|
99
|
+
|
|
100
|
+
const updateMultiResult = useCallback((result?: MultiResult) => {
|
|
101
|
+
multiResultRef.current = result;
|
|
102
|
+
managerRef.current?.setPreselectedLines(result || { old: [], new: [] });
|
|
103
|
+
}, []);
|
|
104
|
+
|
|
105
|
+
useUpdateEffect(() => {
|
|
106
|
+
updateMultiResult(undefined);
|
|
107
|
+
}, [props.diffViewWrap, diffViewMode]);
|
|
108
|
+
|
|
109
|
+
const getDiffFile = useCallback(() => {
|
|
110
|
+
return diffViewRef.current?.getDiffFileInstance() ?? null;
|
|
111
|
+
}, []);
|
|
112
|
+
|
|
113
|
+
useEffect(() => {
|
|
114
|
+
const container = containerRef.current;
|
|
115
|
+
const diffFile = getDiffFile();
|
|
116
|
+
|
|
117
|
+
if (!container || !diffFile || !enableMultiSelect) {
|
|
118
|
+
managerRef.current?.destroy();
|
|
119
|
+
managerRef.current = null;
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
const managerOptions: MultiSelectOptions = {
|
|
124
|
+
enabled: enableMultiSelect,
|
|
125
|
+
isUnifiedMode,
|
|
126
|
+
selectedClassName: multiSelectClassNames.selected,
|
|
127
|
+
onSelectionChange: (range, state) => {
|
|
128
|
+
if (state.isSelecting) {
|
|
129
|
+
containerRef.current?.classList.add(multiSelectClassNames.selecting);
|
|
130
|
+
} else {
|
|
131
|
+
containerRef.current?.classList.remove(multiSelectClassNames.selecting);
|
|
132
|
+
}
|
|
133
|
+
if (state.isSelecting && multiResultRef.current) {
|
|
134
|
+
updateMultiResult(undefined);
|
|
135
|
+
}
|
|
136
|
+
memoSelectChange?.(range, state);
|
|
137
|
+
},
|
|
138
|
+
onSelectionComplete: (result) => {
|
|
139
|
+
containerRef.current?.classList.remove(multiSelectClassNames.selecting);
|
|
140
|
+
if (result && result.lines.length > 0) {
|
|
141
|
+
memoSelectComplete?.(result);
|
|
142
|
+
const finalResult = {
|
|
143
|
+
[result.range.side as "old" | "new"]: [result.range.startLineNumber, result.range.endLineNumber],
|
|
144
|
+
} as MultiResult;
|
|
145
|
+
updateMultiResult(finalResult);
|
|
146
|
+
} else {
|
|
147
|
+
updateMultiResult(undefined);
|
|
148
|
+
}
|
|
149
|
+
},
|
|
150
|
+
scopeToHunk: memoScopeSelectToHunk,
|
|
151
|
+
};
|
|
152
|
+
|
|
153
|
+
if (managerRef.current) {
|
|
154
|
+
managerRef.current.updateContainer(container);
|
|
155
|
+
managerRef.current.updateDiffFile(diffFile);
|
|
156
|
+
managerRef.current.updateOptions(managerOptions);
|
|
157
|
+
} else {
|
|
158
|
+
managerRef.current = createDiffMultiSelectManager(container, diffFile, managerOptions);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
return () => {
|
|
162
|
+
managerRef.current?.destroy();
|
|
163
|
+
managerRef.current = null;
|
|
164
|
+
};
|
|
165
|
+
}, [
|
|
166
|
+
enableMultiSelect,
|
|
167
|
+
isUnifiedMode,
|
|
168
|
+
memoScopeSelectToHunk,
|
|
169
|
+
memoSelectChange,
|
|
170
|
+
memoSelectComplete,
|
|
171
|
+
getDiffFile,
|
|
172
|
+
updateMultiResult,
|
|
173
|
+
]);
|
|
174
|
+
|
|
175
|
+
const convertedExtendData = useMemo(() => {
|
|
176
|
+
if (!extendData) return undefined;
|
|
177
|
+
|
|
178
|
+
const result: { oldFile?: Record<string, { data: T }>; newFile?: Record<string, { data: T }> } = {};
|
|
179
|
+
|
|
180
|
+
if (extendData.oldFile) {
|
|
181
|
+
result.oldFile = {};
|
|
182
|
+
for (const [key, value] of Object.entries(extendData.oldFile)) {
|
|
183
|
+
result.oldFile[key] = { data: value.data };
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
if (extendData.newFile) {
|
|
188
|
+
result.newFile = {};
|
|
189
|
+
for (const [key, value] of Object.entries(extendData.newFile)) {
|
|
190
|
+
result.newFile[key] = { data: value.data };
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
return result;
|
|
195
|
+
}, [extendData]);
|
|
196
|
+
|
|
197
|
+
const internalRenderWidgetLine = useCallback(
|
|
198
|
+
({
|
|
199
|
+
lineNumber,
|
|
200
|
+
side,
|
|
201
|
+
diffFile,
|
|
202
|
+
onClose,
|
|
203
|
+
}: {
|
|
204
|
+
lineNumber: number;
|
|
205
|
+
side: SplitSide;
|
|
206
|
+
diffFile: DiffFile;
|
|
207
|
+
onClose: () => void;
|
|
208
|
+
}) => {
|
|
209
|
+
if (!renderWidgetLine) return null;
|
|
210
|
+
|
|
211
|
+
const sideKey = side === SplitSide.old ? "old" : "new";
|
|
212
|
+
const multiResultItem = multiResultRef.current?.[sideKey] as number[];
|
|
213
|
+
const fromLineNumber = multiResultItem ? Math.min(...multiResultItem) : lineNumber;
|
|
214
|
+
const toLineNumber = multiResultItem ? Math.max(...multiResultItem) : lineNumber;
|
|
215
|
+
|
|
216
|
+
return renderWidgetLine({
|
|
217
|
+
lineNumber: toLineNumber,
|
|
218
|
+
fromLineNumber,
|
|
219
|
+
side,
|
|
220
|
+
diffFile,
|
|
221
|
+
onClose,
|
|
222
|
+
});
|
|
223
|
+
},
|
|
224
|
+
[renderWidgetLine]
|
|
225
|
+
);
|
|
226
|
+
|
|
227
|
+
const getSelectionResult = useCallback(() => {
|
|
228
|
+
return managerRef.current?.getSelectionResult() ?? null;
|
|
229
|
+
}, []);
|
|
230
|
+
|
|
231
|
+
const getSelectionState = useCallback(() => {
|
|
232
|
+
return (
|
|
233
|
+
managerRef.current?.getState() ?? {
|
|
234
|
+
isSelecting: false,
|
|
235
|
+
startInfo: null,
|
|
236
|
+
currentRange: null,
|
|
237
|
+
}
|
|
238
|
+
);
|
|
239
|
+
}, []);
|
|
240
|
+
|
|
241
|
+
const clearSelection = useCallback(() => {
|
|
242
|
+
managerRef.current?.clearSelection();
|
|
243
|
+
}, []);
|
|
244
|
+
|
|
245
|
+
const setPreselectedLines = updateMultiResult;
|
|
246
|
+
|
|
247
|
+
useImperativeHandle(
|
|
248
|
+
ref,
|
|
249
|
+
() => ({
|
|
250
|
+
getDiffFileInstance: getDiffFile,
|
|
251
|
+
getSelectionResult,
|
|
252
|
+
getSelectionState,
|
|
253
|
+
clearSelection,
|
|
254
|
+
setPreselectedLines,
|
|
255
|
+
}),
|
|
256
|
+
[getDiffFile, getSelectionResult, getSelectionState, clearSelection, setPreselectedLines]
|
|
257
|
+
);
|
|
258
|
+
|
|
259
|
+
return (
|
|
260
|
+
<div ref={containerRef} className="diff-multiselect-wrapper">
|
|
261
|
+
<DiffView
|
|
262
|
+
ref={diffViewRef}
|
|
263
|
+
{...restProps}
|
|
264
|
+
diffViewMode={diffViewMode}
|
|
265
|
+
extendData={convertedExtendData}
|
|
266
|
+
onAddWidgetClick={(lineNum: number, side: SplitSide) => {
|
|
267
|
+
managerRef.current?.clearSelection();
|
|
268
|
+
const multiResult = multiResultRef.current;
|
|
269
|
+
if (multiResult) {
|
|
270
|
+
const currentSide = SplitSide[side] as unknown as "new" | "old";
|
|
271
|
+
const currentMultiResult = multiResult[currentSide] as number[];
|
|
272
|
+
const otherSide = currentSide === "new" ? "old" : "new";
|
|
273
|
+
const otherMultiResult = multiResult[otherSide] as number[];
|
|
274
|
+
if (currentMultiResult?.length) {
|
|
275
|
+
const max = Math.max(...currentMultiResult);
|
|
276
|
+
if (max === lineNum) {
|
|
277
|
+
const finalResult = { [currentSide]: currentMultiResult };
|
|
278
|
+
updateMultiResult(finalResult as MultiResult);
|
|
279
|
+
onAddWidgetClick?.({ lineNumber: max, fromLineNumber: Math.min(...currentMultiResult), side });
|
|
280
|
+
return;
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
if (isUnifiedMode && otherMultiResult?.length) {
|
|
284
|
+
const max = Math.max(...otherMultiResult);
|
|
285
|
+
const diffFile = getDiffFile();
|
|
286
|
+
const index = diffFile.getUnifiedLineIndexByLineNumber(lineNum, side);
|
|
287
|
+
const unifiedItem = diffFile.getUnifiedLine(index);
|
|
288
|
+
const otherSideLineNum = side === SplitSide.old ? unifiedItem.newLineNumber : unifiedItem.oldLineNumber;
|
|
289
|
+
if (max === otherSideLineNum) {
|
|
290
|
+
const finalResult = { [otherSide]: otherMultiResult };
|
|
291
|
+
updateMultiResult(finalResult as MultiResult);
|
|
292
|
+
onAddWidgetClick?.({
|
|
293
|
+
lineNumber: max,
|
|
294
|
+
fromLineNumber: Math.min(...otherMultiResult),
|
|
295
|
+
side: otherSide === "old" ? SplitSide.old : SplitSide.new,
|
|
296
|
+
});
|
|
297
|
+
return;
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
updateMultiResult(undefined);
|
|
301
|
+
onAddWidgetClick?.({ lineNumber: lineNum, fromLineNumber: lineNum, side });
|
|
302
|
+
} else {
|
|
303
|
+
updateMultiResult(undefined);
|
|
304
|
+
onAddWidgetClick?.({ lineNumber: lineNum, fromLineNumber: lineNum, side });
|
|
305
|
+
}
|
|
306
|
+
}}
|
|
307
|
+
renderWidgetLine={renderWidgetLine ? internalRenderWidgetLine : undefined}
|
|
308
|
+
/>
|
|
309
|
+
</div>
|
|
310
|
+
);
|
|
311
|
+
};
|
|
312
|
+
|
|
313
|
+
// type helper function
|
|
314
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
315
|
+
function ReactDiffView<T>(
|
|
316
|
+
_props: DiffViewWithMultiSelectProps<T> & { ref?: ForwardedRef<DiffViewWithMultiSelectRef> }
|
|
317
|
+
) {
|
|
318
|
+
return <></>;
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
export const DiffViewWithMultiSelect = forwardRef(InternalDiffViewWithMultiSelect) as typeof ReactDiffView;
|
|
@@ -5,11 +5,13 @@ import type { Ref, UseSelectorWithStore } from "reactivity-store";
|
|
|
5
5
|
|
|
6
6
|
export const DiffWidgetContext = createContext<{
|
|
7
7
|
useWidget: UseSelectorWithStore<{
|
|
8
|
-
widgetSide: Ref<SplitSide>;
|
|
9
|
-
widgetLineNumber: Ref<number>;
|
|
8
|
+
widgetSide: Ref<SplitSide | undefined>;
|
|
9
|
+
widgetLineNumber: Ref<number | undefined>;
|
|
10
10
|
|
|
11
11
|
setWidget: (props: { side?: SplitSide; lineNumber?: number }) => void;
|
|
12
12
|
}>;
|
|
13
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
14
|
+
// @ts-ignore
|
|
13
15
|
}>(null);
|
|
14
16
|
|
|
15
17
|
DiffWidgetContext.displayName = "DiffWidgetContext";
|
package/src/components/tools.ts
CHANGED
|
@@ -42,7 +42,8 @@ export const createDiffConfigStore = (props: DiffViewProps<any> & { isMounted: b
|
|
|
42
42
|
newFile: { ...props.extendData?.newFile },
|
|
43
43
|
});
|
|
44
44
|
|
|
45
|
-
const setExtendData = (
|
|
45
|
+
const setExtendData = (__extendData: DiffViewProps<any>["extendData"]) => {
|
|
46
|
+
const _extendData = __extendData || {};
|
|
46
47
|
const existOldKeys = Object.keys(extendData.value.oldFile || {});
|
|
47
48
|
const inComingOldKeys = Object.keys(_extendData.oldFile || {});
|
|
48
49
|
for (const key of existOldKeys) {
|
|
@@ -51,7 +52,7 @@ export const createDiffConfigStore = (props: DiffViewProps<any> & { isMounted: b
|
|
|
51
52
|
}
|
|
52
53
|
}
|
|
53
54
|
for (const key of inComingOldKeys) {
|
|
54
|
-
extendData.value.oldFile[key] = _extendData.oldFile[key];
|
|
55
|
+
extendData.value.oldFile[key] = _extendData.oldFile![key];
|
|
55
56
|
}
|
|
56
57
|
const existNewKeys = Object.keys(extendData.value.newFile || {});
|
|
57
58
|
const inComingNewKeys = Object.keys(_extendData.newFile || {});
|
|
@@ -61,7 +62,7 @@ export const createDiffConfigStore = (props: DiffViewProps<any> & { isMounted: b
|
|
|
61
62
|
}
|
|
62
63
|
}
|
|
63
64
|
for (const key of inComingNewKeys) {
|
|
64
|
-
extendData.value.newFile[key] = _extendData.newFile[key];
|
|
65
|
+
extendData.value.newFile[key] = _extendData.newFile![key];
|
|
65
66
|
}
|
|
66
67
|
};
|
|
67
68
|
|
|
@@ -119,9 +120,9 @@ export const createDiffConfigStore = (props: DiffViewProps<any> & { isMounted: b
|
|
|
119
120
|
|
|
120
121
|
export const createDiffWidgetStore = (useDiffContextRef: RefObject<ReturnType<typeof createDiffConfigStore>>) => {
|
|
121
122
|
return createStore(() => {
|
|
122
|
-
const widgetSide = ref<SplitSide>(undefined);
|
|
123
|
+
const widgetSide = ref<SplitSide | undefined>(undefined);
|
|
123
124
|
|
|
124
|
-
const widgetLineNumber = ref<number>(undefined);
|
|
125
|
+
const widgetLineNumber = ref<number | undefined>(undefined);
|
|
125
126
|
|
|
126
127
|
const setWidget = ({ side, lineNumber }: { side?: SplitSide; lineNumber?: number }) => {
|
|
127
128
|
const { renderWidgetLine } = useDiffContextRef.current?.getReadonlyState?.() || {};
|
|
@@ -7,7 +7,6 @@ import {
|
|
|
7
7
|
diffAsideWidthName,
|
|
8
8
|
expandLineNumberColorName,
|
|
9
9
|
} from "@git-diff-view/utils";
|
|
10
|
-
import * as React from "react";
|
|
11
10
|
|
|
12
11
|
import { DiffSplitAddWidget } from "../DiffAddWidget";
|
|
13
12
|
import { DiffContent } from "../DiffContent";
|
|
@@ -62,9 +61,9 @@ const InternalDiffSplitLine = ({
|
|
|
62
61
|
|
|
63
62
|
const lineNumberBG = getLineNumberBG(isAdded, isDelete, hasDiff);
|
|
64
63
|
|
|
65
|
-
const plainLine = getCurrentPlainLine(currentLine.lineNumber);
|
|
64
|
+
const plainLine = getCurrentPlainLine(currentLine.lineNumber ?? -1);
|
|
66
65
|
|
|
67
|
-
const syntaxLine = getCurrentSyntaxLine(currentLine.lineNumber);
|
|
66
|
+
const syntaxLine = getCurrentSyntaxLine(currentLine.lineNumber ?? -1);
|
|
68
67
|
|
|
69
68
|
return (
|
|
70
69
|
<div
|
|
@@ -88,7 +87,7 @@ const InternalDiffSplitLine = ({
|
|
|
88
87
|
{hasDiff && enableAddWidget && (
|
|
89
88
|
<DiffSplitAddWidget
|
|
90
89
|
index={index}
|
|
91
|
-
lineNumber={currentLine.lineNumber}
|
|
90
|
+
lineNumber={currentLine.lineNumber ?? -1}
|
|
92
91
|
side={side}
|
|
93
92
|
diffFile={diffFile}
|
|
94
93
|
onWidgetClick={(...props) => onAddWidgetClick.current?.(...props)}
|
|
@@ -115,7 +114,7 @@ const InternalDiffSplitLine = ({
|
|
|
115
114
|
diffLine={currentLine.diff}
|
|
116
115
|
plainLine={plainLine}
|
|
117
116
|
syntaxLine={syntaxLine}
|
|
118
|
-
enableHighlight={enableHighlight}
|
|
117
|
+
enableHighlight={!!enableHighlight}
|
|
119
118
|
/>
|
|
120
119
|
</div>
|
|
121
120
|
</>
|
|
@@ -8,7 +8,6 @@ import {
|
|
|
8
8
|
diffAsideWidthName,
|
|
9
9
|
expandLineNumberColorName,
|
|
10
10
|
} from "@git-diff-view/utils";
|
|
11
|
-
import * as React from "react";
|
|
12
11
|
|
|
13
12
|
import { DiffSplitAddWidget } from "../DiffAddWidget";
|
|
14
13
|
import { DiffContent } from "../DiffContent";
|
|
@@ -29,13 +28,13 @@ const InternalDiffSplitLine = ({
|
|
|
29
28
|
|
|
30
29
|
const newLine = diffFile.getSplitRightLine(index);
|
|
31
30
|
|
|
32
|
-
const oldSyntaxLine = diffFile.getOldSyntaxLine(oldLine?.lineNumber);
|
|
31
|
+
const oldSyntaxLine = diffFile.getOldSyntaxLine(oldLine?.lineNumber ?? -1);
|
|
33
32
|
|
|
34
|
-
const newSyntaxLine = diffFile.getNewSyntaxLine(newLine?.lineNumber);
|
|
33
|
+
const newSyntaxLine = diffFile.getNewSyntaxLine(newLine?.lineNumber ?? -1);
|
|
35
34
|
|
|
36
|
-
const oldPlainLine = diffFile.getOldPlainLine(oldLine.lineNumber);
|
|
35
|
+
const oldPlainLine = diffFile.getOldPlainLine(oldLine.lineNumber ?? -1);
|
|
37
36
|
|
|
38
|
-
const newPlainLine = diffFile.getNewPlainLine(newLine.lineNumber);
|
|
37
|
+
const newPlainLine = diffFile.getNewPlainLine(newLine.lineNumber ?? -1);
|
|
39
38
|
|
|
40
39
|
const hasDiff = !!oldLine?.diff || !!newLine?.diff;
|
|
41
40
|
|
|
@@ -87,7 +86,7 @@ const InternalDiffSplitLine = ({
|
|
|
87
86
|
{hasDiff && enableAddWidget && (
|
|
88
87
|
<DiffSplitAddWidget
|
|
89
88
|
index={index}
|
|
90
|
-
lineNumber={oldLine.lineNumber}
|
|
89
|
+
lineNumber={oldLine.lineNumber ?? -1}
|
|
91
90
|
side={SplitSide.old}
|
|
92
91
|
diffFile={diffFile}
|
|
93
92
|
onWidgetClick={(...props) => onAddWidgetClick.current?.(...props)}
|
|
@@ -111,7 +110,7 @@ const InternalDiffSplitLine = ({
|
|
|
111
110
|
{hasDiff && enableAddWidget && (
|
|
112
111
|
<DiffSplitAddWidget
|
|
113
112
|
index={index}
|
|
114
|
-
lineNumber={oldLine.lineNumber}
|
|
113
|
+
lineNumber={oldLine.lineNumber ?? -1}
|
|
115
114
|
side={SplitSide.old}
|
|
116
115
|
diffFile={diffFile}
|
|
117
116
|
onWidgetClick={(...props) => onAddWidgetClick.current?.(...props)}
|
|
@@ -122,11 +121,11 @@ const InternalDiffSplitLine = ({
|
|
|
122
121
|
<DiffContent
|
|
123
122
|
enableWrap={true}
|
|
124
123
|
diffFile={diffFile}
|
|
125
|
-
rawLine={oldLine.value}
|
|
124
|
+
rawLine={oldLine.value || ""}
|
|
126
125
|
diffLine={oldLine.diff}
|
|
127
126
|
plainLine={oldPlainLine}
|
|
128
127
|
syntaxLine={oldSyntaxLine}
|
|
129
|
-
enableHighlight={enableHighlight}
|
|
128
|
+
enableHighlight={!!enableHighlight}
|
|
130
129
|
/>
|
|
131
130
|
</div>
|
|
132
131
|
</>
|
|
@@ -170,7 +169,7 @@ const InternalDiffSplitLine = ({
|
|
|
170
169
|
{hasDiff && enableAddWidget && (
|
|
171
170
|
<DiffSplitAddWidget
|
|
172
171
|
index={index}
|
|
173
|
-
lineNumber={newLine.lineNumber}
|
|
172
|
+
lineNumber={newLine.lineNumber ?? -1}
|
|
174
173
|
side={SplitSide.new}
|
|
175
174
|
diffFile={diffFile}
|
|
176
175
|
onWidgetClick={(...props) => onAddWidgetClick.current?.(...props)}
|
|
@@ -194,7 +193,7 @@ const InternalDiffSplitLine = ({
|
|
|
194
193
|
{hasDiff && enableAddWidget && (
|
|
195
194
|
<DiffSplitAddWidget
|
|
196
195
|
index={index}
|
|
197
|
-
lineNumber={newLine.lineNumber}
|
|
196
|
+
lineNumber={newLine.lineNumber ?? -1}
|
|
198
197
|
side={SplitSide.new}
|
|
199
198
|
diffFile={diffFile}
|
|
200
199
|
onWidgetClick={(...props) => onAddWidgetClick.current?.(...props)}
|
|
@@ -209,7 +208,7 @@ const InternalDiffSplitLine = ({
|
|
|
209
208
|
diffLine={newLine.diff}
|
|
210
209
|
plainLine={newPlainLine}
|
|
211
210
|
syntaxLine={newSyntaxLine}
|
|
212
|
-
enableHighlight={enableHighlight}
|
|
211
|
+
enableHighlight={!!enableHighlight}
|
|
213
212
|
/>
|
|
214
213
|
</div>
|
|
215
214
|
</>
|
|
@@ -77,7 +77,7 @@ const InternalDiffSplitExtendLine = ({
|
|
|
77
77
|
renderExtendLine?.({
|
|
78
78
|
diffFile,
|
|
79
79
|
side,
|
|
80
|
-
lineNumber: currentLineNumber,
|
|
80
|
+
lineNumber: currentLineNumber ?? -1,
|
|
81
81
|
data: currentExtend?.data,
|
|
82
82
|
onUpdate: diffFile.notifyAll,
|
|
83
83
|
})}
|
|
@@ -115,8 +115,8 @@ export const DiffSplitExtendLine = ({
|
|
|
115
115
|
const { oldLineExtend, newLineExtend } = useDiffContext(
|
|
116
116
|
React.useCallback(
|
|
117
117
|
(s) => ({
|
|
118
|
-
oldLineExtend: s.extendData?.oldFile?.[oldLine?.lineNumber],
|
|
119
|
-
newLineExtend: s.extendData?.newFile?.[newLine?.lineNumber],
|
|
118
|
+
oldLineExtend: s.extendData?.oldFile?.[oldLine?.lineNumber ?? -1],
|
|
119
|
+
newLineExtend: s.extendData?.newFile?.[newLine?.lineNumber ?? -1],
|
|
120
120
|
}),
|
|
121
121
|
[oldLine?.lineNumber, newLine?.lineNumber]
|
|
122
122
|
)
|
|
@@ -35,7 +35,7 @@ const InternalDiffSplitExtendLine = ({
|
|
|
35
35
|
renderExtendLine?.({
|
|
36
36
|
diffFile,
|
|
37
37
|
side: SplitSide.old,
|
|
38
|
-
lineNumber: oldLine.lineNumber,
|
|
38
|
+
lineNumber: oldLine.lineNumber ?? -1,
|
|
39
39
|
data: oldLineExtend.data,
|
|
40
40
|
onUpdate: diffFile.notifyAll,
|
|
41
41
|
});
|
|
@@ -45,7 +45,7 @@ const InternalDiffSplitExtendLine = ({
|
|
|
45
45
|
renderExtendLine?.({
|
|
46
46
|
diffFile,
|
|
47
47
|
side: SplitSide.new,
|
|
48
|
-
lineNumber: newLine.lineNumber,
|
|
48
|
+
lineNumber: newLine.lineNumber ?? -1,
|
|
49
49
|
data: newLineExtend.data,
|
|
50
50
|
onUpdate: diffFile.notifyAll,
|
|
51
51
|
});
|
|
@@ -95,8 +95,8 @@ export const DiffSplitExtendLine = ({
|
|
|
95
95
|
const { oldLineExtend, newLineExtend } = useDiffContext(
|
|
96
96
|
React.useCallback(
|
|
97
97
|
(s) => ({
|
|
98
|
-
oldLineExtend: s.extendData?.oldFile?.[oldLine?.lineNumber],
|
|
99
|
-
newLineExtend: s.extendData?.newFile?.[newLine?.lineNumber],
|
|
98
|
+
oldLineExtend: s.extendData?.oldFile?.[oldLine?.lineNumber ?? -1],
|
|
99
|
+
newLineExtend: s.extendData?.newFile?.[newLine?.lineNumber ?? -1],
|
|
100
100
|
}),
|
|
101
101
|
[oldLine?.lineNumber, newLine?.lineNumber]
|
|
102
102
|
)
|
|
@@ -9,6 +9,7 @@ import {
|
|
|
9
9
|
} from "@git-diff-view/utils";
|
|
10
10
|
import { memo, useEffect, useRef } from "react";
|
|
11
11
|
import * as React from "react";
|
|
12
|
+
// @ts-ignore
|
|
12
13
|
import { useSyncExternalStore } from "use-sync-external-store/shim/index.js";
|
|
13
14
|
|
|
14
15
|
import { useTextWidth } from "../../hooks/useTextWidth";
|
|
@@ -53,9 +54,9 @@ export const DiffSplitViewNormal = memo(({ diffFile }: { diffFile: DiffFile }) =
|
|
|
53
54
|
|
|
54
55
|
const ref2 = useRef<HTMLDivElement>(null);
|
|
55
56
|
|
|
56
|
-
const ref = useRef<HTMLStyleElement>();
|
|
57
|
+
const ref = useRef<HTMLStyleElement>(null);
|
|
57
58
|
|
|
58
|
-
const tempRef = useRef<SplitSide>();
|
|
59
|
+
const tempRef = useRef<SplitSide>(undefined);
|
|
59
60
|
|
|
60
61
|
const splitLineLength = Math.max(diffFile.splitLineLength, diffFile.fileLineLength);
|
|
61
62
|
|
|
@@ -84,7 +85,7 @@ export const DiffSplitViewNormal = memo(({ diffFile }: { diffFile: DiffFile }) =
|
|
|
84
85
|
|
|
85
86
|
const width = Math.max(40, _width + 25);
|
|
86
87
|
|
|
87
|
-
const setStyle = (side
|
|
88
|
+
const setStyle = (side?: SplitSide) => {
|
|
88
89
|
if (!ref.current) return;
|
|
89
90
|
if (!side) {
|
|
90
91
|
ref.current.textContent = "";
|
|
@@ -95,7 +96,7 @@ export const DiffSplitViewNormal = memo(({ diffFile }: { diffFile: DiffFile }) =
|
|
|
95
96
|
};
|
|
96
97
|
|
|
97
98
|
const onMouseDown: MouseEventHandler<HTMLTableSectionElement> = (e) => {
|
|
98
|
-
let ele = e.target;
|
|
99
|
+
let ele: Element | null = e.target as Element;
|
|
99
100
|
|
|
100
101
|
// need remove all the selection
|
|
101
102
|
if (ele && ele instanceof HTMLElement && ele.nodeName === "BUTTON") {
|
|
@@ -105,11 +106,11 @@ export const DiffSplitViewNormal = memo(({ diffFile }: { diffFile: DiffFile }) =
|
|
|
105
106
|
|
|
106
107
|
while (ele && ele instanceof HTMLElement) {
|
|
107
108
|
const state = ele.getAttribute("data-state");
|
|
108
|
-
const side = ele.getAttribute("data-side");
|
|
109
|
+
const side = ele.getAttribute("data-side") as unknown as SplitSide;
|
|
109
110
|
if (side) {
|
|
110
|
-
if (tempRef.current !== SplitSide[side]) {
|
|
111
|
-
tempRef.current = SplitSide[side];
|
|
112
|
-
setStyle(SplitSide[side]);
|
|
111
|
+
if (tempRef.current !== (SplitSide[side] as unknown as SplitSide)) {
|
|
112
|
+
tempRef.current = SplitSide[side] as unknown as SplitSide;
|
|
113
|
+
setStyle(SplitSide[side] as unknown as SplitSide);
|
|
113
114
|
removeAllSelection();
|
|
114
115
|
}
|
|
115
116
|
}
|
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
import { type DiffFile, getSplitLines } from "@git-diff-view/core";
|
|
3
3
|
import { removeAllSelection, diffFontSizeName, diffAsideWidthName } from "@git-diff-view/utils";
|
|
4
4
|
import { memo, useMemo, useRef } from "react";
|
|
5
|
-
import * as React from "react";
|
|
6
5
|
// SEE https://github.com/facebook/react/pull/25231
|
|
6
|
+
// @ts-ignore
|
|
7
7
|
import { useSyncExternalStore } from "use-sync-external-store/shim/index.js";
|
|
8
8
|
|
|
9
9
|
import { useTextWidth } from "../../hooks/useTextWidth";
|
|
@@ -36,7 +36,7 @@ export const DiffSplitViewWrap = memo(({ diffFile }: { diffFile: DiffFile }) =>
|
|
|
36
36
|
|
|
37
37
|
const lines = getSplitLines(diffFile);
|
|
38
38
|
|
|
39
|
-
const setStyle = (side
|
|
39
|
+
const setStyle = (side?: SplitSide) => {
|
|
40
40
|
if (!ref.current) return;
|
|
41
41
|
if (!side) {
|
|
42
42
|
ref.current.textContent = "";
|
|
@@ -48,7 +48,7 @@ export const DiffSplitViewWrap = memo(({ diffFile }: { diffFile: DiffFile }) =>
|
|
|
48
48
|
};
|
|
49
49
|
|
|
50
50
|
const onMouseDown: MouseEventHandler<HTMLTableSectionElement> = (e) => {
|
|
51
|
-
let ele = e.target;
|
|
51
|
+
let ele: Element | null = e.target as Element;
|
|
52
52
|
|
|
53
53
|
// need remove all the selection
|
|
54
54
|
if (ele && ele instanceof HTMLElement && ele.nodeName === "BUTTON") {
|
|
@@ -58,9 +58,9 @@ export const DiffSplitViewWrap = memo(({ diffFile }: { diffFile: DiffFile }) =>
|
|
|
58
58
|
|
|
59
59
|
while (ele && ele instanceof HTMLElement) {
|
|
60
60
|
const state = ele.getAttribute("data-state");
|
|
61
|
-
const side = ele.getAttribute("data-side");
|
|
61
|
+
const side = ele.getAttribute("data-side") as unknown as SplitSide;
|
|
62
62
|
if (side) {
|
|
63
|
-
setStyle(SplitSide[side]);
|
|
63
|
+
setStyle(SplitSide[side] as unknown as SplitSide);
|
|
64
64
|
removeAllSelection();
|
|
65
65
|
}
|
|
66
66
|
if (state) {
|