@git-diff-view/react 0.0.26 → 0.0.27

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.
Files changed (65) hide show
  1. package/dist/cjs/index.development.js +419 -287
  2. package/dist/cjs/index.development.js.map +1 -1
  3. package/dist/cjs/index.production.js +419 -287
  4. package/dist/cjs/index.production.js.map +1 -1
  5. package/dist/css/diff-view-pure.css +4 -0
  6. package/dist/css/diff-view.css +4 -0
  7. package/dist/esm/index.mjs +353 -224
  8. package/dist/esm/index.mjs.map +1 -1
  9. package/index.d.ts +296 -16
  10. package/package.json +4 -3
  11. package/src/_base.css +3 -0
  12. package/src/_base_pure.css +2 -0
  13. package/src/_com.css +172 -0
  14. package/src/_theme.css +2 -0
  15. package/src/components/DiffAddWidget.tsx +86 -0
  16. package/src/components/DiffContent.tsx +367 -0
  17. package/src/components/DiffContent_v2.tsx +344 -0
  18. package/src/components/DiffExpand.tsx +25 -0
  19. package/src/components/DiffNoNewLine.tsx +10 -0
  20. package/src/components/DiffSplitContentLineNormal.tsx +164 -0
  21. package/src/components/DiffSplitContentLineWrap.tsx +234 -0
  22. package/src/components/DiffSplitExtendLineNormal.tsx +150 -0
  23. package/src/components/DiffSplitExtendLineWrap.tsx +133 -0
  24. package/src/components/DiffSplitHunkLineNormal.tsx +316 -0
  25. package/src/components/DiffSplitHunkLineWrap.tsx +340 -0
  26. package/src/components/DiffSplitView.tsx +46 -0
  27. package/src/components/DiffSplitViewNormal.tsx +205 -0
  28. package/src/components/DiffSplitViewWrap.tsx +141 -0
  29. package/src/components/DiffSplitWidgetLineNormal.tsx +149 -0
  30. package/src/components/DiffSplitWidgetLineWrap.tsx +127 -0
  31. package/src/components/DiffUnifiedContentLine.tsx +342 -0
  32. package/src/components/DiffUnifiedExtendLine.tsx +103 -0
  33. package/src/components/DiffUnifiedHunkLine.tsx +148 -0
  34. package/src/components/DiffUnifiedView.tsx +159 -0
  35. package/src/components/DiffUnifiedWidgetLine.tsx +104 -0
  36. package/src/components/DiffView.tsx +365 -0
  37. package/src/components/DiffViewContext.ts +11 -0
  38. package/src/components/DiffWidgetContext.ts +17 -0
  39. package/src/components/tools.ts +132 -0
  40. package/src/components/v2/DiffSplitContentLineNormal_v2.tsx +152 -0
  41. package/src/components/v2/DiffSplitContentLineWrap_v2.tsx +259 -0
  42. package/src/components/v2/DiffSplitExtendLineNormal_v2.tsx +146 -0
  43. package/src/components/v2/DiffSplitExtendLineWrap_v2.tsx +123 -0
  44. package/src/components/v2/DiffSplitHunkLineNormal_v2.tsx +302 -0
  45. package/src/components/v2/DiffSplitHunkLineWrap_v2.tsx +326 -0
  46. package/src/components/v2/DiffSplitViewLineNormal_v2.tsx +33 -0
  47. package/src/components/v2/DiffSplitViewLineWrap_v2.tsx +24 -0
  48. package/src/components/v2/DiffSplitViewNormal_v2.tsx +159 -0
  49. package/src/components/v2/DiffSplitViewWrap_v2.tsx +104 -0
  50. package/src/components/v2/DiffSplitView_v2.tsx +47 -0
  51. package/src/components/v2/DiffSplitWidgetLineNormal_v2.tsx +132 -0
  52. package/src/components/v2/DiffSplitWidgetLineWrap_v2.tsx +119 -0
  53. package/src/global.d.ts +12 -0
  54. package/src/hooks/useCallbackRef.ts +18 -0
  55. package/src/hooks/useDomWidth.ts +67 -0
  56. package/src/hooks/useIsMounted.ts +11 -0
  57. package/src/hooks/useSafeLayout.ts +5 -0
  58. package/src/hooks/useSyncHeight.ts +87 -0
  59. package/src/hooks/useTextWidth.ts +27 -0
  60. package/src/hooks/useUnmount.ts +10 -0
  61. package/src/index.ts +3 -0
  62. package/src/tailwind.css +3 -0
  63. package/src/tailwind_pure.css +3 -0
  64. package/styles/diff-view-pure.css +4 -0
  65. package/styles/diff-view.css +4 -0
@@ -0,0 +1,205 @@
1
+ /* eslint-disable @typescript-eslint/ban-ts-comment */
2
+ import { getSplitContentLines, type DiffFile } from "@git-diff-view/core";
3
+ import {
4
+ removeAllSelection,
5
+ syncScroll,
6
+ diffFontSizeName,
7
+ borderColorName,
8
+ diffAsideWidthName,
9
+ } from "@git-diff-view/utils";
10
+ import { Fragment, memo, useEffect, useRef } from "react";
11
+ import * as React from "react";
12
+ import { useSyncExternalStore } from "use-sync-external-store/shim/index.js";
13
+
14
+ import { useTextWidth } from "../hooks/useTextWidth";
15
+
16
+ import { DiffSplitContentLine } from "./DiffSplitContentLineNormal";
17
+ import { DiffSplitExtendLine } from "./DiffSplitExtendLineNormal";
18
+ import { DiffSplitHunkLine } from "./DiffSplitHunkLineNormal";
19
+ import { DiffSplitWidgetLine } from "./DiffSplitWidgetLineNormal";
20
+ import { SplitSide } from "./DiffView";
21
+ import { useDiffViewContext } from "./DiffViewContext";
22
+
23
+ import type { MouseEventHandler } from "react";
24
+
25
+ const DiffSplitViewTable = ({
26
+ side,
27
+ diffFile,
28
+ enableAddWidget,
29
+ enableHighlight,
30
+ onMouseDown,
31
+ }: {
32
+ side: SplitSide;
33
+ diffFile: DiffFile;
34
+ enableHighlight: boolean;
35
+ enableAddWidget: boolean;
36
+ onMouseDown?: MouseEventHandler<HTMLTableSectionElement>;
37
+ }) => {
38
+ const className = side === SplitSide.new ? "new-diff-table" : "old-diff-table";
39
+
40
+ const lines = getSplitContentLines(diffFile);
41
+
42
+ return (
43
+ <table className={className + " w-full border-collapse border-spacing-0"} data-mode={SplitSide[side]}>
44
+ <colgroup>
45
+ <col className={`diff-table-${SplitSide[side]}-num-col`} />
46
+ <col className={`diff-table-${SplitSide[side]}-content-col`} />
47
+ </colgroup>
48
+ <thead className="hidden">
49
+ <tr>
50
+ <th scope="col">{SplitSide[side]} line number</th>
51
+ <th scope="col">{SplitSide[side]} line content</th>
52
+ </tr>
53
+ </thead>
54
+ <tbody className="diff-table-body leading-[1.4]" onMouseDownCapture={onMouseDown}>
55
+ {lines.map((line) => (
56
+ <Fragment key={line.index}>
57
+ <DiffSplitHunkLine index={line.index} side={side} lineNumber={line.lineNumber} diffFile={diffFile} />
58
+ <DiffSplitContentLine
59
+ index={line.index}
60
+ side={side}
61
+ lineNumber={line.lineNumber}
62
+ diffFile={diffFile}
63
+ enableAddWidget={enableAddWidget}
64
+ enableHighlight={enableHighlight}
65
+ />
66
+ <DiffSplitWidgetLine index={line.index} side={side} lineNumber={line.lineNumber} diffFile={diffFile} />
67
+ <DiffSplitExtendLine index={line.index} side={side} lineNumber={line.lineNumber} diffFile={diffFile} />
68
+ </Fragment>
69
+ ))}
70
+ <DiffSplitHunkLine
71
+ side={side}
72
+ index={diffFile.splitLineLength}
73
+ lineNumber={diffFile.splitLineLength}
74
+ diffFile={diffFile}
75
+ />
76
+ </tbody>
77
+ </table>
78
+ );
79
+ };
80
+
81
+ export const DiffSplitViewNormal = memo(({ diffFile }: { diffFile: DiffFile }) => {
82
+ const ref1 = useRef<HTMLDivElement>(null);
83
+
84
+ const ref2 = useRef<HTMLDivElement>(null);
85
+
86
+ const ref = useRef<HTMLStyleElement>();
87
+
88
+ const splitLineLength = Math.max(diffFile.splitLineLength, diffFile.fileLineLength);
89
+
90
+ const { useDiffContext } = useDiffViewContext();
91
+
92
+ const { fontSize, enableAddWidget, enableHighlight } = useDiffContext.useShallowStableSelector((s) => ({
93
+ fontSize: s.fontSize,
94
+ enableAddWidget: s.enableAddWidget,
95
+ enableHighlight: s.enableHighlight,
96
+ }));
97
+
98
+ useSyncExternalStore(diffFile.subscribe, diffFile.getUpdateCount, diffFile.getUpdateCount);
99
+
100
+ useEffect(() => {
101
+ const left = ref1.current;
102
+ const right = ref2.current;
103
+ if (!left || !right) return;
104
+ return syncScroll(left, right);
105
+ }, []);
106
+
107
+ const font = React.useMemo(
108
+ () => ({ fontSize: fontSize + "px", fontFamily: "Menlo, Consolas, monospace" }),
109
+ [fontSize]
110
+ );
111
+
112
+ const _width = useTextWidth({
113
+ text: splitLineLength.toString(),
114
+ font,
115
+ });
116
+
117
+ const width = Math.max(40, _width + 25);
118
+
119
+ const setStyle = (side: SplitSide) => {
120
+ if (!ref.current) return;
121
+ if (!side) {
122
+ ref.current.textContent = "";
123
+ } else {
124
+ const id = `diff-root${diffFile.getId()}`;
125
+ ref.current.textContent = `#${id} [data-state="extend"] {user-select: none} \n#${id} [data-state="hunk"] {user-select: none} \n#${id} [data-state="widget"] {user-select: none}`;
126
+ }
127
+ };
128
+
129
+ const onMouseDown: MouseEventHandler<HTMLTableSectionElement> = (e) => {
130
+ let ele = e.target;
131
+
132
+ // need remove all the selection
133
+ if (ele && ele instanceof HTMLElement && ele.nodeName === "BUTTON") {
134
+ removeAllSelection();
135
+ return;
136
+ }
137
+
138
+ while (ele && ele instanceof HTMLElement) {
139
+ const state = ele.getAttribute("data-state");
140
+ const side = ele.getAttribute("data-side");
141
+ if (side) {
142
+ setStyle(SplitSide[side]);
143
+ removeAllSelection();
144
+ }
145
+ if (state) {
146
+ if (state === "extend" || state === "hunk" || state === "widget") {
147
+ setStyle(undefined);
148
+ removeAllSelection();
149
+ return;
150
+ } else {
151
+ return;
152
+ }
153
+ }
154
+
155
+ ele = ele.parentElement;
156
+ }
157
+ };
158
+
159
+ return (
160
+ <div className="split-diff-view split-diff-view-normal flex w-full basis-[50%]">
161
+ <style data-select-style ref={ref} />
162
+ <div
163
+ className="old-diff-table-wrapper diff-table-scroll-container w-full overflow-x-auto overflow-y-hidden"
164
+ ref={ref1}
165
+ style={{
166
+ // @ts-ignore
167
+ [diffAsideWidthName]: `${Math.round(width)}px`,
168
+ overscrollBehaviorX: "none",
169
+ fontFamily: "Menlo, Consolas, monospace",
170
+ fontSize: `var(${diffFontSizeName})`,
171
+ }}
172
+ >
173
+ <DiffSplitViewTable
174
+ side={SplitSide.old}
175
+ diffFile={diffFile}
176
+ enableAddWidget={enableAddWidget}
177
+ enableHighlight={enableHighlight}
178
+ onMouseDown={onMouseDown}
179
+ />
180
+ </div>
181
+ <div className="diff-split-line w-[1.5px]" style={{ backgroundColor: `var(${borderColorName})` }} />
182
+ <div
183
+ className="new-diff-table-wrapper diff-table-scroll-container w-full overflow-x-auto overflow-y-hidden"
184
+ ref={ref2}
185
+ style={{
186
+ // @ts-ignore
187
+ [diffAsideWidthName]: `${Math.round(width)}px`,
188
+ overscrollBehaviorX: "none",
189
+ fontFamily: "Menlo, Consolas, monospace",
190
+ fontSize: `var(${diffFontSizeName})`,
191
+ }}
192
+ >
193
+ <DiffSplitViewTable
194
+ side={SplitSide.new}
195
+ diffFile={diffFile}
196
+ enableAddWidget={enableAddWidget}
197
+ enableHighlight={enableHighlight}
198
+ onMouseDown={onMouseDown}
199
+ />
200
+ </div>
201
+ </div>
202
+ );
203
+ });
204
+
205
+ DiffSplitViewNormal.displayName = "DiffSplitViewNormal";
@@ -0,0 +1,141 @@
1
+ /* eslint-disable @typescript-eslint/ban-ts-comment */
2
+ import { type DiffFile, getSplitContentLines } from "@git-diff-view/core";
3
+ import { diffAsideWidthName, diffFontSizeName, removeAllSelection } from "@git-diff-view/utils";
4
+ import { Fragment, memo, useMemo, useRef } from "react";
5
+ import * as React from "react";
6
+ // SEE https://github.com/facebook/react/pull/25231
7
+ import { useSyncExternalStore } from "use-sync-external-store/shim/index.js";
8
+
9
+ import { SplitSide } from "..";
10
+ import { useTextWidth } from "../hooks/useTextWidth";
11
+
12
+ import { DiffSplitContentLine } from "./DiffSplitContentLineWrap";
13
+ import { DiffSplitExtendLine } from "./DiffSplitExtendLineWrap";
14
+ import { DiffSplitHunkLine } from "./DiffSplitHunkLineWrap";
15
+ import { DiffSplitWidgetLine } from "./DiffSplitWidgetLineWrap";
16
+ import { useDiffViewContext } from "./DiffViewContext";
17
+
18
+ import type { MouseEventHandler } from "react";
19
+
20
+ export const DiffSplitViewWrap = memo(({ diffFile }: { diffFile: DiffFile }) => {
21
+ const splitLineLength = Math.max(diffFile.splitLineLength, diffFile.fileLineLength);
22
+
23
+ const { useDiffContext } = useDiffViewContext();
24
+
25
+ const ref = useRef<HTMLStyleElement>(null);
26
+
27
+ const { fontSize, enableAddWidget, enableHighlight } = useDiffContext.useShallowStableSelector((s) => ({
28
+ fontSize: s.fontSize,
29
+ enableAddWidget: s.enableAddWidget,
30
+ enableHighlight: s.enableHighlight,
31
+ }));
32
+
33
+ useSyncExternalStore(diffFile.subscribe, diffFile.getUpdateCount, diffFile.getUpdateCount);
34
+
35
+ const font = useMemo(() => ({ fontSize: fontSize + "px", fontFamily: "Menlo, Consolas, monospace" }), [fontSize]);
36
+
37
+ const _width = useTextWidth({
38
+ text: splitLineLength.toString(),
39
+ font,
40
+ });
41
+
42
+ const width = Math.max(40, _width + 25);
43
+
44
+ const lines = getSplitContentLines(diffFile);
45
+
46
+ const setStyle = (side: SplitSide) => {
47
+ if (!ref.current) return;
48
+ if (!side) {
49
+ ref.current.textContent = "";
50
+ } else {
51
+ const id = `diff-root${diffFile.getId()}`;
52
+ const targetSide = side === SplitSide.old ? SplitSide.new : SplitSide.old;
53
+ ref.current.textContent = `#${id} [data-side="${SplitSide[targetSide]}"] {user-select: none} \n#${id} [data-state="extend"] {user-select: none} \n#${id} [data-state="hunk"] {user-select: none} \n#${id} [data-state="widget"] {user-select: none}`;
54
+ }
55
+ };
56
+
57
+ const onMouseDown: MouseEventHandler<HTMLTableSectionElement> = (e) => {
58
+ let ele = e.target;
59
+
60
+ // need remove all the selection
61
+ if (ele && ele instanceof HTMLElement && ele.nodeName === "BUTTON") {
62
+ removeAllSelection();
63
+ return;
64
+ }
65
+
66
+ while (ele && ele instanceof HTMLElement) {
67
+ const state = ele.getAttribute("data-state");
68
+ const side = ele.getAttribute("data-side");
69
+ if (side) {
70
+ setStyle(SplitSide[side]);
71
+ removeAllSelection();
72
+ }
73
+ if (state) {
74
+ if (state === "extend" || state === "hunk" || state === "widget") {
75
+ setStyle(undefined);
76
+ removeAllSelection();
77
+ return;
78
+ } else {
79
+ return;
80
+ }
81
+ }
82
+
83
+ ele = ele.parentElement;
84
+ }
85
+ };
86
+
87
+ return (
88
+ <div className="split-diff-view split-diff-view-wrap w-full">
89
+ <div
90
+ className="diff-table-wrapper w-full"
91
+ style={{
92
+ // @ts-ignore
93
+ [diffAsideWidthName]: `${Math.round(width)}px`,
94
+ fontFamily: "Menlo, Consolas, monospace",
95
+ fontSize: `var(${diffFontSizeName})`,
96
+ }}
97
+ >
98
+ <style data-select-style ref={ref} />
99
+ <table className="diff-table w-full table-fixed border-collapse border-spacing-0">
100
+ <colgroup>
101
+ <col className="diff-table-old-num-col" width={Math.round(width)} />
102
+ <col className="diff-table-old-content-col" />
103
+ <col className="diff-table-new-num-col" width={Math.round(width)} />
104
+ <col className="diff-table-new-content-col" />
105
+ </colgroup>
106
+ <thead className="hidden">
107
+ <tr>
108
+ <th scope="col">old line number</th>
109
+ <th scope="col">old line content</th>
110
+ <th scope="col">new line number</th>
111
+ <th scope="col">new line content</th>
112
+ </tr>
113
+ </thead>
114
+ <tbody className="diff-table-body leading-[1.4]" onMouseDownCapture={onMouseDown}>
115
+ {lines.map((line) => (
116
+ <Fragment key={line.index}>
117
+ <DiffSplitHunkLine index={line.index} lineNumber={line.lineNumber} diffFile={diffFile} />
118
+ <DiffSplitContentLine
119
+ index={line.index}
120
+ lineNumber={line.lineNumber}
121
+ diffFile={diffFile}
122
+ enableAddWidget={enableAddWidget}
123
+ enableHighlight={enableHighlight}
124
+ />
125
+ <DiffSplitWidgetLine index={line.index} lineNumber={line.lineNumber} diffFile={diffFile} />
126
+ <DiffSplitExtendLine index={line.index} lineNumber={line.lineNumber} diffFile={diffFile} />
127
+ </Fragment>
128
+ ))}
129
+ <DiffSplitHunkLine
130
+ index={diffFile.splitLineLength}
131
+ lineNumber={diffFile.splitLineLength}
132
+ diffFile={diffFile}
133
+ />
134
+ </tbody>
135
+ </table>
136
+ </div>
137
+ </div>
138
+ );
139
+ });
140
+
141
+ DiffSplitViewWrap.displayName = "DiffSplitViewWrap";
@@ -0,0 +1,149 @@
1
+ import { emptyBGName } from "@git-diff-view/utils";
2
+ import * as React from "react";
3
+
4
+ import { SplitSide } from "..";
5
+ import { useDomWidth } from "../hooks/useDomWidth";
6
+ import { useSyncHeight } from "../hooks/useSyncHeight";
7
+
8
+ import { useDiffViewContext } from "./DiffViewContext";
9
+ import { useDiffWidgetContext } from "./DiffWidgetContext";
10
+
11
+ import type { DiffFile } from "@git-diff-view/core";
12
+
13
+ const InternalDiffSplitWidgetLine = ({
14
+ index,
15
+ side,
16
+ diffFile,
17
+ lineNumber,
18
+ }: {
19
+ index: number;
20
+ side: SplitSide;
21
+ diffFile: DiffFile;
22
+ lineNumber: number;
23
+ }) => {
24
+ const { useWidget } = useDiffWidgetContext();
25
+
26
+ const { useDiffContext } = useDiffViewContext();
27
+
28
+ const oldLine = diffFile.getSplitLeftLine(index);
29
+
30
+ const newLine = diffFile.getSplitRightLine(index);
31
+
32
+ const widgetSide = useWidget.getReadonlyState().widgetSide;
33
+
34
+ const widgetLineNumber = useWidget.getReadonlyState().widgetLineNumber;
35
+
36
+ const setWidget = useWidget.getReadonlyState().setWidget;
37
+
38
+ const oldLineWidget = oldLine.lineNumber && widgetSide === SplitSide.old && widgetLineNumber === oldLine.lineNumber;
39
+
40
+ const newLineWidget = newLine.lineNumber && widgetSide === SplitSide.new && widgetLineNumber === newLine.lineNumber;
41
+
42
+ const currentLine = side === SplitSide.old ? oldLine : newLine;
43
+
44
+ const otherSide = side === SplitSide.old ? SplitSide.new : SplitSide.old;
45
+
46
+ const currentHasWidget = side === SplitSide.old ? oldLineWidget : newLineWidget;
47
+
48
+ const hasWidget = oldLineWidget || newLineWidget;
49
+
50
+ const renderWidgetLine = useDiffContext.useShallowStableSelector((s) => s.renderWidgetLine);
51
+
52
+ const currentWidgetRendered =
53
+ currentHasWidget &&
54
+ renderWidgetLine?.({
55
+ diffFile,
56
+ side,
57
+ lineNumber: currentLine.lineNumber,
58
+ onClose: () => setWidget({}),
59
+ });
60
+
61
+ useSyncHeight({
62
+ selector: `div[data-line="${lineNumber}-widget-content"]`,
63
+ wrapper: `tr[data-line="${lineNumber}-widget"]`,
64
+ side: SplitSide[currentHasWidget ? side : otherSide],
65
+ enable: hasWidget && typeof renderWidgetLine === "function",
66
+ });
67
+
68
+ const width = useDomWidth({
69
+ selector: side === SplitSide.old ? ".old-diff-table-wrapper" : ".new-diff-table-wrapper",
70
+ enable: !!currentHasWidget && typeof renderWidgetLine === "function",
71
+ });
72
+
73
+ if (!renderWidgetLine) return null;
74
+
75
+ return (
76
+ <tr
77
+ data-line={`${lineNumber}-widget`}
78
+ data-state="widget"
79
+ data-side={SplitSide[side]}
80
+ className="diff-line diff-line-widget"
81
+ >
82
+ {currentHasWidget ? (
83
+ <td className={`diff-line-widget-${SplitSide[side]}-content p-0`} colSpan={2}>
84
+ <div
85
+ data-line={`${lineNumber}-widget-content`}
86
+ data-side={SplitSide[side]}
87
+ className="diff-line-widget-wrapper sticky left-0 z-[1]"
88
+ style={{ width }}
89
+ >
90
+ {width > 0 && currentWidgetRendered}
91
+ </div>
92
+ </td>
93
+ ) : (
94
+ <td
95
+ className={`diff-line-widget-${SplitSide[side]}-placeholder p-0`}
96
+ style={{ backgroundColor: `var(${emptyBGName})` }}
97
+ colSpan={2}
98
+ >
99
+ <div data-line={`${lineNumber}-widget-content`} data-side={SplitSide[side]} />
100
+ </td>
101
+ )}
102
+ </tr>
103
+ );
104
+ };
105
+
106
+ // TODO! improve performance
107
+ export const DiffSplitWidgetLine = ({
108
+ index,
109
+ side,
110
+ diffFile,
111
+ lineNumber,
112
+ }: {
113
+ index: number;
114
+ side: SplitSide;
115
+ diffFile: DiffFile;
116
+ lineNumber: number;
117
+ }) => {
118
+ const { useWidget } = useDiffWidgetContext();
119
+
120
+ const currentIsShow = useWidget.useShallowSelector(
121
+ React.useCallback(
122
+ (s) => {
123
+ const widgetLineNumber = s.widgetLineNumber;
124
+
125
+ const widgetSide = s.widgetSide;
126
+
127
+ const oldLine = diffFile.getSplitLeftLine(index);
128
+
129
+ const newLine = diffFile.getSplitRightLine(index);
130
+
131
+ const oldLineWidget =
132
+ oldLine.lineNumber && widgetSide === SplitSide.old && widgetLineNumber === oldLine.lineNumber;
133
+
134
+ const newLineWidget =
135
+ newLine.lineNumber && widgetSide === SplitSide.new && widgetLineNumber === newLine.lineNumber;
136
+
137
+ const currentIsShow = oldLineWidget || newLineWidget;
138
+
139
+ return currentIsShow;
140
+ },
141
+ [diffFile, index]
142
+ ),
143
+ (p, c) => p === c
144
+ );
145
+
146
+ if (!currentIsShow) return null;
147
+
148
+ return <InternalDiffSplitWidgetLine index={index} side={side} diffFile={diffFile} lineNumber={lineNumber} />;
149
+ };
@@ -0,0 +1,127 @@
1
+ import { borderColorName, emptyBGName } from "@git-diff-view/utils";
2
+ import * as React from "react";
3
+
4
+ import { SplitSide } from "..";
5
+
6
+ import { useDiffViewContext } from "./DiffViewContext";
7
+ import { useDiffWidgetContext } from "./DiffWidgetContext";
8
+
9
+ import type { DiffFile } from "@git-diff-view/core";
10
+
11
+ const InternalDiffSplitWidgetLine = ({
12
+ index,
13
+ diffFile,
14
+ lineNumber,
15
+ }: {
16
+ index: number;
17
+ diffFile: DiffFile;
18
+ lineNumber: number;
19
+ }) => {
20
+ const { useWidget } = useDiffWidgetContext();
21
+
22
+ const setWidget = useWidget.getReadonlyState().setWidget;
23
+
24
+ const { useDiffContext } = useDiffViewContext();
25
+
26
+ const renderWidgetLine = useDiffContext.useShallowStableSelector((s) => s.renderWidgetLine);
27
+
28
+ const oldLine = diffFile.getSplitLeftLine(index);
29
+
30
+ const newLine = diffFile.getSplitRightLine(index);
31
+
32
+ const widgetSide = useWidget.getReadonlyState().widgetSide;
33
+
34
+ const widgetLineNumber = useWidget.getReadonlyState().widgetLineNumber;
35
+
36
+ const oldLineWidget = oldLine.lineNumber && widgetSide === SplitSide.old && widgetLineNumber === oldLine.lineNumber;
37
+
38
+ const newLineWidget = newLine.lineNumber && widgetSide === SplitSide.new && widgetLineNumber === newLine.lineNumber;
39
+
40
+ const oldWidgetRendered =
41
+ oldLineWidget &&
42
+ renderWidgetLine?.({ diffFile, side: SplitSide.old, lineNumber: oldLine.lineNumber, onClose: () => setWidget({}) });
43
+
44
+ const newWidgetRendered =
45
+ newLineWidget &&
46
+ renderWidgetLine?.({ diffFile, side: SplitSide.new, lineNumber: newLine.lineNumber, onClose: () => setWidget({}) });
47
+
48
+ if (!renderWidgetLine) return null;
49
+
50
+ return (
51
+ <tr data-line={`${lineNumber}-widget`} data-state="widget" className="diff-line diff-line-widget">
52
+ {oldWidgetRendered ? (
53
+ <td className="diff-line-widget-old-content p-0" colSpan={2}>
54
+ <div className="diff-line-widget-wrapper">{oldWidgetRendered}</div>
55
+ </td>
56
+ ) : (
57
+ <td
58
+ className="diff-line-widget-old-placeholder select-none p-0"
59
+ style={{ backgroundColor: `var(${emptyBGName})` }}
60
+ colSpan={2}
61
+ />
62
+ )}
63
+ {newWidgetRendered ? (
64
+ <td
65
+ className="diff-line-widget-new-content border-l-[1px] p-0"
66
+ colSpan={2}
67
+ style={{ borderLeftColor: `var(${borderColorName})`, borderLeftStyle: "solid" }}
68
+ >
69
+ <div className="diff-line-widget-wrapper">{newWidgetRendered}</div>
70
+ </td>
71
+ ) : (
72
+ <td
73
+ className="diff-line-widget-new-placeholder select-none border-l-[1px] p-0"
74
+ style={{
75
+ backgroundColor: `var(${emptyBGName})`,
76
+ borderLeftColor: `var(${borderColorName})`,
77
+ borderLeftStyle: "solid",
78
+ }}
79
+ colSpan={2}
80
+ />
81
+ )}
82
+ </tr>
83
+ );
84
+ };
85
+
86
+ // TODO! improve performance
87
+ export const DiffSplitWidgetLine = ({
88
+ index,
89
+ diffFile,
90
+ lineNumber,
91
+ }: {
92
+ index: number;
93
+ diffFile: DiffFile;
94
+ lineNumber: number;
95
+ }) => {
96
+ const { useWidget } = useDiffWidgetContext();
97
+
98
+ const currentIsShow = useWidget.useShallowSelector(
99
+ React.useCallback(
100
+ (s) => {
101
+ const widgetLineNumber = s.widgetLineNumber;
102
+
103
+ const widgetSide = s.widgetSide;
104
+
105
+ const oldLine = diffFile.getSplitLeftLine(index);
106
+
107
+ const newLine = diffFile.getSplitRightLine(index);
108
+
109
+ const oldLineWidget =
110
+ oldLine.lineNumber && widgetSide === SplitSide.old && widgetLineNumber === oldLine.lineNumber;
111
+
112
+ const newLineWidget =
113
+ newLine.lineNumber && widgetSide === SplitSide.new && widgetLineNumber === newLine.lineNumber;
114
+
115
+ const currentIsShow = oldLineWidget || newLineWidget;
116
+
117
+ return currentIsShow;
118
+ },
119
+ [diffFile, index]
120
+ ),
121
+ (p, c) => p === c
122
+ );
123
+
124
+ if (!currentIsShow) return null;
125
+
126
+ return <InternalDiffSplitWidgetLine index={index} diffFile={diffFile} lineNumber={lineNumber} />;
127
+ };