@git-diff-view/react 0.0.26 → 0.0.28

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 +431 -290
  2. package/dist/cjs/index.development.js.map +1 -1
  3. package/dist/cjs/index.production.js +431 -290
  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 +362 -224
  8. package/dist/esm/index.mjs.map +1 -1
  9. package/index.d.ts +303 -23
  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,86 @@
1
+ import { addWidgetBGName, addWidgetColorName, diffFontSizeName } from "@git-diff-view/utils";
2
+ import * as React from "react";
3
+
4
+ import type { SplitSide } from "./DiffView";
5
+ import type { DiffFile } from "@git-diff-view/core";
6
+
7
+ export const DiffSplitAddWidget = ({
8
+ side,
9
+ className,
10
+ lineNumber,
11
+ onWidgetClick,
12
+ onOpenAddWidget,
13
+ }: {
14
+ index: number;
15
+ lineNumber: number;
16
+ diffFile: DiffFile;
17
+ side: SplitSide;
18
+ className?: string;
19
+ onWidgetClick?: (lineNumber: number, side: SplitSide) => void;
20
+ onOpenAddWidget: (lineNumber: number, side: SplitSide) => void;
21
+ }) => {
22
+ return (
23
+ <div
24
+ className={
25
+ "diff-add-widget-wrapper invisible select-none transition-transform hover:scale-110 group-hover:visible" +
26
+ (className ? " " + className : "")
27
+ }
28
+ style={{
29
+ width: `calc(var(${diffFontSizeName}) * 1.4)`,
30
+ height: `calc(var(${diffFontSizeName}) * 1.4)`,
31
+ }}
32
+ >
33
+ <button
34
+ className="diff-add-widget z-[1] flex h-full w-full origin-center cursor-pointer items-center justify-center rounded-md text-[1.2em]"
35
+ style={{
36
+ color: `var(${addWidgetColorName})`,
37
+ backgroundColor: `var(${addWidgetBGName})`,
38
+ }}
39
+ onClick={() => {
40
+ onOpenAddWidget(lineNumber, side);
41
+ onWidgetClick?.(lineNumber, side);
42
+ }}
43
+ >
44
+ +
45
+ </button>
46
+ </div>
47
+ );
48
+ };
49
+
50
+ export const DiffUnifiedAddWidget = ({
51
+ lineNumber,
52
+ side,
53
+ onWidgetClick,
54
+ onOpenAddWidget,
55
+ }: {
56
+ index: number;
57
+ diffFile: DiffFile;
58
+ lineNumber: number;
59
+ side: SplitSide;
60
+ onWidgetClick?: (lineNumber: number, side: SplitSide) => void;
61
+ onOpenAddWidget: (lineNumber: number, side: SplitSide) => void;
62
+ }) => {
63
+ return (
64
+ <div
65
+ className="diff-add-widget-wrapper invisible absolute left-[100%] top-[1px] translate-x-[-50%] select-none transition-transform hover:scale-110 group-hover:visible"
66
+ style={{
67
+ width: `calc(var(${diffFontSizeName}) * 1.4)`,
68
+ height: `calc(var(${diffFontSizeName}) * 1.4)`,
69
+ }}
70
+ >
71
+ <button
72
+ className="diff-add-widget z-[1] flex h-full w-full origin-center cursor-pointer items-center justify-center rounded-md text-[1.2em]"
73
+ style={{
74
+ color: `var(${addWidgetColorName})`,
75
+ backgroundColor: `var(${addWidgetBGName})`,
76
+ }}
77
+ onClick={() => {
78
+ onOpenAddWidget(lineNumber, side);
79
+ onWidgetClick?.(lineNumber, side);
80
+ }}
81
+ >
82
+ +
83
+ </button>
84
+ </div>
85
+ );
86
+ };
@@ -0,0 +1,367 @@
1
+ /* eslint-disable max-lines */
2
+ import {
3
+ DiffLineType,
4
+ getSyntaxDiffTemplate,
5
+ getSyntaxLineTemplate,
6
+ getPlainDiffTemplate,
7
+ getPlainLineTemplate,
8
+ } from "@git-diff-view/core";
9
+ import {
10
+ memoFunc,
11
+ addContentHighlightBGName,
12
+ delContentHighlightBGName,
13
+ diffFontSizeName,
14
+ getSymbol,
15
+ NewLineSymbol,
16
+ } from "@git-diff-view/utils";
17
+ import * as React from "react";
18
+
19
+ import { DiffNoNewLine } from "./DiffNoNewLine";
20
+
21
+ import type { DiffFile, DiffLine, File } from "@git-diff-view/core";
22
+
23
+ const temp = {};
24
+
25
+ const formatStringToCamelCase = (str: string) => {
26
+ if (str.startsWith("--")) return str;
27
+ const splitted = str.split("-");
28
+ if (splitted.length === 1) return splitted[0];
29
+ return (
30
+ splitted[0] +
31
+ splitted
32
+ .slice(1)
33
+ .map((word) => word[0].toUpperCase() + word.slice(1))
34
+ .join("")
35
+ );
36
+ };
37
+
38
+ export const getStyleObjectFromString = memoFunc((str: string) => {
39
+ if (!str) return temp;
40
+ const style = {};
41
+ str.split(";").forEach((el) => {
42
+ const [property, value] = el.split(":");
43
+ if (!property) return;
44
+
45
+ const formattedProperty = formatStringToCamelCase(property.trim());
46
+ style[formattedProperty] = value.trim();
47
+ });
48
+ return style;
49
+ });
50
+
51
+ const DiffString = ({
52
+ rawLine,
53
+ diffLine,
54
+ operator,
55
+ plainLine,
56
+ enableWrap,
57
+ }: {
58
+ rawLine: string;
59
+ diffLine?: DiffLine;
60
+ operator?: "add" | "del";
61
+ plainLine?: File["plainFile"][number];
62
+ enableWrap?: boolean;
63
+ }) => {
64
+ const changes = diffLine?.changes;
65
+
66
+ if (changes?.hasLineChange) {
67
+ const isNewLineSymbolChanged = changes.newLineSymbol;
68
+
69
+ if (!diffLine?.plainTemplate && typeof getPlainDiffTemplate === "function") {
70
+ getPlainDiffTemplate({ diffLine, rawLine, operator });
71
+ }
72
+
73
+ if (diffLine?.plainTemplate) {
74
+ return (
75
+ <span className="diff-line-content-raw">
76
+ <span data-template dangerouslySetInnerHTML={{ __html: diffLine.plainTemplate }} />
77
+ {isNewLineSymbolChanged === NewLineSymbol.NEWLINE && (
78
+ <span
79
+ data-no-newline-at-end-of-file-symbol
80
+ className={enableWrap ? "block !text-red-500" : "inline-block align-middle !text-red-500"}
81
+ style={{
82
+ width: `var(${diffFontSizeName})`,
83
+ height: `var(${diffFontSizeName})`,
84
+ }}
85
+ >
86
+ <DiffNoNewLine />
87
+ </span>
88
+ )}
89
+ </span>
90
+ );
91
+ } else {
92
+ // TODO remove
93
+ const range = changes.range;
94
+ const str1 = rawLine.slice(0, range.location);
95
+ const str2 = rawLine.slice(range.location, range.location + range.length);
96
+ const str3 = rawLine.slice(range.location + range.length);
97
+ const isLast = str2.includes("\n");
98
+ const _str2 = isLast ? str2.replace("\n", "").replace("\r", "") : str2;
99
+ return (
100
+ <span className="diff-line-content-raw">
101
+ <span data-range-start={range.location} data-range-end={range.location + range.length}>
102
+ {str1}
103
+ <span
104
+ data-diff-highlight
105
+ className="rounded-[0.2em]"
106
+ style={{
107
+ backgroundColor:
108
+ operator === "add" ? `var(${addContentHighlightBGName})` : `var(${delContentHighlightBGName})`,
109
+ }}
110
+ >
111
+ {isLast ? (
112
+ <>
113
+ {_str2}
114
+ <span data-newline-symbol>{getSymbol(isNewLineSymbolChanged)}</span>
115
+ </>
116
+ ) : (
117
+ str2
118
+ )}
119
+ </span>
120
+ {str3}
121
+ </span>
122
+ {isNewLineSymbolChanged === NewLineSymbol.NEWLINE && (
123
+ <span
124
+ data-no-newline-at-end-of-file-symbol
125
+ className={enableWrap ? "block !text-red-500" : "inline-block align-middle !text-red-500"}
126
+ style={{
127
+ width: `var(${diffFontSizeName})`,
128
+ height: `var(${diffFontSizeName})`,
129
+ }}
130
+ >
131
+ <DiffNoNewLine />
132
+ </span>
133
+ )}
134
+ </span>
135
+ );
136
+ }
137
+ }
138
+
139
+ if (plainLine && !plainLine?.template) {
140
+ plainLine.template = getPlainLineTemplate(plainLine.value);
141
+ }
142
+
143
+ if (plainLine?.template) {
144
+ return (
145
+ <span className="diff-line-content-raw">
146
+ <span data-template dangerouslySetInnerHTML={{ __html: plainLine.template }} />
147
+ </span>
148
+ );
149
+ }
150
+
151
+ return <span className="diff-line-content-raw">{rawLine}</span>;
152
+ };
153
+
154
+ const DiffSyntax = ({
155
+ rawLine,
156
+ diffLine,
157
+ operator,
158
+ syntaxLine,
159
+ enableWrap,
160
+ }: {
161
+ rawLine: string;
162
+ diffLine?: DiffLine;
163
+ syntaxLine?: File["syntaxFile"][number];
164
+ operator?: "add" | "del";
165
+ enableWrap?: boolean;
166
+ }) => {
167
+ if (!syntaxLine) {
168
+ return <DiffString rawLine={rawLine} diffLine={diffLine} operator={operator} />;
169
+ }
170
+
171
+ const changes = diffLine?.changes;
172
+
173
+ if (changes?.hasLineChange) {
174
+ const isNewLineSymbolChanged = changes.newLineSymbol;
175
+
176
+ if (!diffLine?.syntaxTemplate && typeof getSyntaxDiffTemplate === "function") {
177
+ getSyntaxDiffTemplate({ diffLine, syntaxLine, operator });
178
+ }
179
+
180
+ if (diffLine?.syntaxTemplate) {
181
+ return (
182
+ <span className="diff-line-syntax-raw">
183
+ <span data-template dangerouslySetInnerHTML={{ __html: diffLine.syntaxTemplate }} />
184
+ {isNewLineSymbolChanged === NewLineSymbol.NEWLINE && (
185
+ <span
186
+ data-no-newline-at-end-of-file-symbol
187
+ className={enableWrap ? "block !text-red-500" : "inline-block align-middle !text-red-500"}
188
+ style={{
189
+ width: `var(${diffFontSizeName})`,
190
+ height: `var(${diffFontSizeName})`,
191
+ }}
192
+ >
193
+ <DiffNoNewLine />
194
+ </span>
195
+ )}
196
+ </span>
197
+ );
198
+ } else {
199
+ // TODO remove
200
+ const range = changes.range;
201
+
202
+ return (
203
+ <span className="diff-line-syntax-raw">
204
+ <span data-range-start={range.location} data-range-end={range.location + range.length}>
205
+ {syntaxLine.nodeList?.map(({ node, wrapper }, index) => {
206
+ if (node.endIndex < range.location || range.location + range.length < node.startIndex) {
207
+ return (
208
+ <span
209
+ key={index}
210
+ data-start={node.startIndex}
211
+ data-end={node.endIndex}
212
+ className={wrapper?.properties?.className?.join(" ")}
213
+ style={getStyleObjectFromString(wrapper?.properties?.style || "")}
214
+ >
215
+ {node.value}
216
+ </span>
217
+ );
218
+ } else {
219
+ const index1 = range.location - node.startIndex;
220
+ const index2 = index1 < 0 ? 0 : index1;
221
+ const str1 = node.value.slice(0, index2);
222
+ const str2 = node.value.slice(index2, index1 + range.length);
223
+ const str3 = node.value.slice(index1 + range.length);
224
+ const isStart = str1.length || range.location === node.startIndex;
225
+ const isEnd = str3.length || node.endIndex === range.location + range.length - 1;
226
+ const isLast = str2.includes("\n");
227
+ const _str2 = isLast ? str2.replace("\n", "").replace("\r", "") : str2;
228
+ return (
229
+ <span
230
+ key={index}
231
+ data-start={node.startIndex}
232
+ data-end={node.endIndex}
233
+ className={wrapper?.properties?.className?.join(" ")}
234
+ style={getStyleObjectFromString(wrapper?.properties?.style || "")}
235
+ >
236
+ {str1}
237
+ <span
238
+ data-diff-highlight
239
+ style={{
240
+ backgroundColor:
241
+ operator === "add"
242
+ ? `var(${addContentHighlightBGName})`
243
+ : `var(${delContentHighlightBGName})`,
244
+ borderTopLeftRadius: isStart ? "0.2em" : undefined,
245
+ borderBottomLeftRadius: isStart ? "0.2em" : undefined,
246
+ borderTopRightRadius: isEnd || isLast ? "0.2em" : undefined,
247
+ borderBottomRightRadius: isEnd || isLast ? "0.2em" : undefined,
248
+ }}
249
+ >
250
+ {isLast ? (
251
+ <>
252
+ {_str2}
253
+ <span data-newline-symbol>{getSymbol(isNewLineSymbolChanged)}</span>
254
+ </>
255
+ ) : (
256
+ str2
257
+ )}
258
+ </span>
259
+ {str3}
260
+ </span>
261
+ );
262
+ }
263
+ })}
264
+ </span>
265
+ {isNewLineSymbolChanged === NewLineSymbol.NEWLINE && (
266
+ <span
267
+ data-no-newline-at-end-of-file-symbol
268
+ className={enableWrap ? "block !text-red-500" : "inline-block align-middle !text-red-500"}
269
+ style={{
270
+ width: `var(${diffFontSizeName})`,
271
+ height: `var(${diffFontSizeName})`,
272
+ }}
273
+ >
274
+ <DiffNoNewLine />
275
+ </span>
276
+ )}
277
+ </span>
278
+ );
279
+ }
280
+ }
281
+
282
+ if (!syntaxLine.template) {
283
+ syntaxLine.template = getSyntaxLineTemplate(syntaxLine);
284
+ }
285
+
286
+ if (syntaxLine?.template) {
287
+ return (
288
+ <span className="diff-line-syntax-raw">
289
+ <span data-template dangerouslySetInnerHTML={{ __html: syntaxLine.template }} />
290
+ </span>
291
+ );
292
+ }
293
+
294
+ return (
295
+ <span className="diff-line-syntax-raw">
296
+ {syntaxLine?.nodeList?.map(({ node, wrapper }, index) => (
297
+ <span
298
+ key={index}
299
+ data-start={node.startIndex}
300
+ data-end={node.endIndex}
301
+ className={wrapper?.properties?.className?.join(" ")}
302
+ style={getStyleObjectFromString(wrapper?.properties?.style || "")}
303
+ >
304
+ {node.value}
305
+ </span>
306
+ ))}
307
+ </span>
308
+ );
309
+ };
310
+
311
+ export const DiffContent = ({
312
+ diffLine,
313
+ rawLine,
314
+ plainLine,
315
+ syntaxLine,
316
+ enableWrap,
317
+ enableHighlight,
318
+ }: {
319
+ rawLine: string;
320
+ plainLine?: File["plainFile"][number];
321
+ syntaxLine?: File["syntaxFile"][number];
322
+ diffLine?: DiffLine;
323
+ diffFile: DiffFile;
324
+ enableWrap: boolean;
325
+ enableHighlight: boolean;
326
+ }) => {
327
+ const isAdded = diffLine?.type === DiffLineType.Add;
328
+
329
+ const isDelete = diffLine?.type === DiffLineType.Delete;
330
+
331
+ const isMaxLineLengthToIgnoreSyntax = syntaxLine?.nodeList?.length > 150;
332
+
333
+ return (
334
+ <div
335
+ className="diff-line-content-item pl-[2.0em]"
336
+ // data-val={rawLine}
337
+ style={{
338
+ whiteSpace: enableWrap ? "pre-wrap" : "pre",
339
+ wordBreak: enableWrap ? "break-all" : "initial",
340
+ }}
341
+ >
342
+ <span
343
+ data-operator={isAdded ? "+" : isDelete ? "-" : undefined}
344
+ className="diff-line-content-operator ml-[-1.5em] inline-block w-[1.5em] select-none indent-[0.2em]"
345
+ >
346
+ {isAdded ? "+" : isDelete ? "-" : " "}
347
+ </span>
348
+ {enableHighlight && syntaxLine && !isMaxLineLengthToIgnoreSyntax ? (
349
+ <DiffSyntax
350
+ operator={isAdded ? "add" : isDelete ? "del" : undefined}
351
+ rawLine={rawLine}
352
+ diffLine={diffLine}
353
+ syntaxLine={syntaxLine}
354
+ enableWrap={enableWrap}
355
+ />
356
+ ) : (
357
+ <DiffString
358
+ operator={isAdded ? "add" : isDelete ? "del" : undefined}
359
+ rawLine={rawLine}
360
+ diffLine={diffLine}
361
+ plainLine={plainLine}
362
+ enableWrap={enableWrap}
363
+ />
364
+ )}
365
+ </div>
366
+ );
367
+ };