@git-diff-view/react 0.1.2 → 0.1.4

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 (59) hide show
  1. package/dist/cjs/index.development.js +497 -503
  2. package/dist/cjs/index.development.js.map +1 -1
  3. package/dist/cjs/index.production.js +497 -503
  4. package/dist/cjs/index.production.js.map +1 -1
  5. package/dist/css/diff-view-pure.css +111 -0
  6. package/dist/css/diff-view.css +111 -0
  7. package/dist/esm/index.mjs +499 -506
  8. package/dist/esm/index.mjs.map +1 -1
  9. package/index.d.ts +239 -7
  10. package/package.json +2 -2
  11. package/src/_com.css +99 -0
  12. package/src/components/DiffAddWidget.tsx +4 -3
  13. package/src/components/DiffContent.tsx +6 -6
  14. package/src/components/DiffExpand.tsx +0 -2
  15. package/src/components/DiffNoNewLine.tsx +0 -2
  16. package/src/components/DiffSplitContentLineNormal.tsx +3 -4
  17. package/src/components/DiffSplitContentLineWrap.tsx +9 -10
  18. package/src/components/DiffSplitExtendLineNormal.tsx +3 -3
  19. package/src/components/DiffSplitExtendLineWrap.tsx +4 -4
  20. package/src/components/DiffSplitHunkLineNormal.tsx +0 -1
  21. package/src/components/DiffSplitHunkLineWrap.tsx +0 -1
  22. package/src/components/DiffSplitView.tsx +0 -1
  23. package/src/components/DiffSplitViewNormal.tsx +13 -12
  24. package/src/components/DiffSplitViewWrap.tsx +10 -10
  25. package/src/components/DiffSplitWidgetLineNormal.tsx +2 -2
  26. package/src/components/DiffSplitWidgetLineWrap.tsx +12 -2
  27. package/src/components/DiffUnifiedContentLine.tsx +1 -2
  28. package/src/components/DiffUnifiedExtendLine.tsx +4 -5
  29. package/src/components/DiffUnifiedHunkLine.tsx +0 -1
  30. package/src/components/DiffUnifiedView.tsx +9 -9
  31. package/src/components/DiffUnifiedWidgetLine.tsx +2 -2
  32. package/src/components/DiffView.tsx +26 -20
  33. package/src/components/DiffViewContext.ts +2 -0
  34. package/src/components/DiffViewWithMultiSelect.tsx +321 -0
  35. package/src/components/DiffWidgetContext.ts +4 -2
  36. package/src/components/tools.ts +6 -5
  37. package/src/components/v2/DiffSplitContentLineNormal_v2.tsx +4 -5
  38. package/src/components/v2/DiffSplitContentLineWrap_v2.tsx +11 -12
  39. package/src/components/v2/DiffSplitExtendLineNormal_v2.tsx +3 -3
  40. package/src/components/v2/DiffSplitExtendLineWrap_v2.tsx +4 -4
  41. package/src/components/v2/DiffSplitHunkLineNormal_v2.tsx +0 -1
  42. package/src/components/v2/DiffSplitHunkLineWrap_v2.tsx +0 -1
  43. package/src/components/v2/DiffSplitViewLineNormal_v2.tsx +0 -1
  44. package/src/components/v2/DiffSplitViewLineWrap_v2.tsx +0 -1
  45. package/src/components/v2/DiffSplitViewNormal_v2.tsx +9 -8
  46. package/src/components/v2/DiffSplitViewWrap_v2.tsx +5 -5
  47. package/src/components/v2/DiffSplitView_v2.tsx +0 -1
  48. package/src/components/v2/DiffSplitWidgetLineNormal_v2.tsx +2 -3
  49. package/src/components/v2/DiffSplitWidgetLineWrap_v2.tsx +4 -5
  50. package/src/hooks/useCallbackRef.ts +5 -10
  51. package/src/hooks/useDomWidth.ts +5 -5
  52. package/src/hooks/useIsMounted.ts +1 -0
  53. package/src/hooks/useSyncHeight.ts +3 -3
  54. package/src/hooks/useTextWidth.ts +1 -1
  55. package/src/hooks/useUnmount.ts +1 -0
  56. package/src/hooks/useUpdateEffect.ts +15 -0
  57. package/src/index.ts +1 -2
  58. package/styles/diff-view-pure.css +111 -0
  59. package/styles/diff-view.css +111 -0
package/index.d.ts CHANGED
@@ -1,10 +1,10 @@
1
1
  // Generated by dts-bundle-generator v9.5.1
2
2
 
3
3
  import { Root } from 'hast';
4
- import { CSSProperties, ForwardedRef, ReactNode, RefObject } from 'react';
4
+ import { CSSProperties, ForwardedRef, JSX, ReactNode, RefObject } from 'react';
5
5
 
6
6
  declare class Cache$1<K, V> extends Map<K, V> {
7
- name: string;
7
+ name?: string;
8
8
  get maxLength(): number;
9
9
  setMaxLength(length: number): void;
10
10
  set(key: K, value: V): this;
@@ -31,6 +31,9 @@ declare class File$1 {
31
31
  static createInstance(data: File$1): File$1;
32
32
  constructor(row: string, lang: DiffHighlighterLang, fileName?: string);
33
33
  constructor(row: string, lang: string, fileName?: string);
34
+ initId(): void;
35
+ getId(): string;
36
+ clearId(): void;
34
37
  doSyntax({ registerHighlighter, theme, }: {
35
38
  registerHighlighter?: Omit<DiffHighlighter, "getHighlighterEngine">;
36
39
  theme?: "light" | "dark";
@@ -274,6 +277,9 @@ export declare class DiffFile {
274
277
  theme: "light" | "dark";
275
278
  };
276
279
  _mergeFullBundle: (data: ReturnType<DiffFile["_getFullBundle"]>, notifyUpdate?: boolean) => void;
280
+ _getAllListener: () => ((() => void) & {
281
+ isSyncExternal?: boolean;
282
+ })[];
277
283
  _destroy: () => void;
278
284
  clear: () => void;
279
285
  }
@@ -331,6 +337,48 @@ export declare class DiffLine {
331
337
  equals(other: DiffLine): boolean;
332
338
  clone(text: string): DiffLine;
333
339
  }
340
+ /**
341
+ * Framework-agnostic multi-select manager for diff views
342
+ * Handles mouse events and selection state management
343
+ */
344
+ export declare class DiffMultiSelectManager {
345
+ constructor(container: HTMLElement, diffFile: DiffFileForMultiSelect, options?: MultiSelectOptions);
346
+ /**
347
+ * Get the current selection result with line data from DiffFile
348
+ */
349
+ getSelectionResult(): MultiSelectResult | null;
350
+ /**
351
+ * Get the current selection state
352
+ */
353
+ getState(): MultiSelectState;
354
+ /**
355
+ * Set preselected lines (e.g., from existing comments)
356
+ */
357
+ setPreselectedLines(lines: {
358
+ old?: number[];
359
+ new?: number[];
360
+ }): void;
361
+ /**
362
+ * Clear the current selection
363
+ */
364
+ clearSelection(): void;
365
+ /**
366
+ * Update options
367
+ */
368
+ updateOptions(options: Partial<MultiSelectOptions>): void;
369
+ /**
370
+ * Update the DiffFile instance
371
+ */
372
+ updateDiffFile(diffFile: DiffFileForMultiSelect): void;
373
+ /**
374
+ * Update the container element
375
+ */
376
+ updateContainer(container: HTMLElement): void;
377
+ /**
378
+ * Destroy the manager and cleanup event listeners
379
+ */
380
+ destroy(): void;
381
+ }
334
382
  /**
335
383
  * A parser for the GNU unified diff format
336
384
  *
@@ -459,6 +507,7 @@ export declare class DiffParser {
459
507
  */
460
508
  parse(text: string): IRawDiff;
461
509
  }
510
+ export declare const DEFAULT_SELECTED_CLASS = "diff-multi-select-active";
462
511
  /** How many new lines will be added to a diff hunk by default. */
463
512
  export declare const DefaultDiffExpansionStep = 40;
464
513
  export declare const _cacheMap: Cache$1<string, File$1>;
@@ -494,13 +543,13 @@ export declare const getSplitLines: (diffFile: DiffFile) => DiffSplitLineItem[];
494
543
  export declare const getSyntaxDiffTemplate: ({ diffFile, diffLine, syntaxLine, operator, }: {
495
544
  diffFile: DiffFile;
496
545
  diffLine: DiffLine;
497
- syntaxLine: SyntaxLine;
546
+ syntaxLine: SyntaxLine | null;
498
547
  operator: "add" | "del";
499
548
  }) => void;
500
549
  export declare const getSyntaxDiffTemplateByFastDiff: ({ diffFile, diffLine, syntaxLine, operator, }: {
501
550
  diffFile: DiffFile;
502
551
  diffLine: DiffLine;
503
- syntaxLine: SyntaxLine;
552
+ syntaxLine: SyntaxLine | null;
504
553
  operator: "add" | "del";
505
554
  }) => void;
506
555
  export declare const getSyntaxLineTemplate: (line: SyntaxLine) => string;
@@ -520,6 +569,13 @@ export declare const highlighter: DiffHighlighter;
520
569
  * ```
521
570
  */
522
571
  export declare const isTransformEnabled: () => boolean;
572
+ /**
573
+ * CSS class names used for multi-select styling
574
+ */
575
+ export declare const multiSelectClassNames: {
576
+ readonly selected: "diff-multi-select-active";
577
+ readonly selecting: "diff-multi-selecting";
578
+ };
523
579
  export declare const parseInstance: DiffParser;
524
580
  export declare const processAST: (ast: DiffAST) => {
525
581
  syntaxFileObject: Record<number, SyntaxLine>;
@@ -632,18 +688,81 @@ export declare enum SplitSide {
632
688
  }
633
689
  export declare function _getAST(raw: string, fileName?: string, lang?: DiffHighlighterLang, theme?: "light" | "dark"): DiffAST;
634
690
  export declare function _getAST(raw: string, fileName?: string, lang?: string, theme?: "light" | "dark"): DiffAST;
691
+ /**
692
+ * Factory function to create a multi-select manager
693
+ */
694
+ export declare function createDiffMultiSelectManager(container: HTMLElement, diffFile: DiffFileForMultiSelect, options?: MultiSelectOptions): DiffMultiSelectManager;
635
695
  export declare function diffChanges(addition: DiffLine, deletion: DiffLine): {
636
696
  addRange: DiffRange;
637
697
  delRange: DiffRange;
638
698
  };
639
699
  export declare function escapeHtml(string: unknown): string;
700
+ /**
701
+ * Convert extendData to preselected lines format
702
+ * Use this when you have existing comments/annotations on lines
703
+ */
704
+ export declare function extendDataToPreselectedLines<T>(extendData?: {
705
+ oldFile?: Record<string, {
706
+ data: T;
707
+ fromLine?: number;
708
+ }>;
709
+ newFile?: Record<string, {
710
+ data: T;
711
+ fromLine?: number;
712
+ }>;
713
+ }): {
714
+ old: number[] | undefined;
715
+ new: number[] | undefined;
716
+ };
640
717
  export declare function getFile(raw: string, lang: DiffHighlighterLang, theme: "light" | "dark", fileName?: string, uuid?: string): File$1;
641
718
  export declare function getFile(raw: string, lang: string, theme: "light" | "dark", fileName?: string, uuid?: string): File$1;
719
+ /**
720
+ * Get line number from a split mode line number cell element
721
+ */
722
+ export declare function getLineNumberFromElement_Split(el: HTMLElement | null): number | null;
723
+ /**
724
+ * Get line numbers from a unified mode element
725
+ */
726
+ export declare function getLineNumbersFromElement_Unified(el: HTMLElement | null): {
727
+ old?: number;
728
+ new?: number;
729
+ } | null;
730
+ /**
731
+ * Find the number holder element from a target element in split mode
732
+ */
733
+ export declare function getNumberHolderElement_Split(el: HTMLElement | null, inMouseDown?: boolean): HTMLElement | null;
734
+ /**
735
+ * Get selected lines data from DiffFile for split mode
736
+ */
737
+ export declare function getSelectedLinesFromDiffFile_Split(diffFile: DiffFileForMultiSelect, range: LineRange): SelectedLine[];
738
+ /**
739
+ * Get selected lines data from DiffFile for unified mode
740
+ */
741
+ export declare function getSelectedLinesFromDiffFile_Unified(diffFile: DiffFileForMultiSelect, range: LineRange): SelectedLine[];
742
+ /**
743
+ * Get side (old/new) from a split mode element
744
+ */
745
+ export declare function getSideFromElement_Split(el: HTMLElement | null): MultiSelectSide | null;
746
+ /**
747
+ * Ensure start <= end in a range
748
+ */
749
+ export declare function normalizeRange<T extends {
750
+ startLineNumber: number;
751
+ endLineNumber: number;
752
+ }>(range: T): T;
642
753
  /** Get the changed ranges in the strings, relative to each other. */
643
754
  export declare function relativeChanges(addition: DiffLine, deletion: DiffLine): {
644
755
  addRange: IRange;
645
756
  delRange: IRange;
646
757
  };
758
+ /**
759
+ * Update visual selection state for split mode
760
+ */
761
+ export declare function updateSelectionVisual_Split(container: HTMLElement | null, selectedRange: LineRange | null, diffFile: DiffFile | null, preselectedLines?: PreselectedLineType, className?: string): void;
762
+ /**
763
+ * Update visual selection state for unified mode
764
+ */
765
+ export declare function updateSelectionVisual_Unified(container: HTMLElement | null, selectedRange: LineRange | null, diffFile: DiffFile | null, preselectedLines?: PreselectedLineType, className?: string): void;
647
766
  export declare let composeLen: number;
648
767
  export interface DiffHunkItem extends DiffLineItem {
649
768
  isFirst: boolean;
@@ -711,6 +830,63 @@ export interface IRawDiff {
711
830
  /** Whether or not the diff has invisible bidi characters */
712
831
  readonly hasHiddenBidiChars: boolean;
713
832
  }
833
+ export interface LineRange {
834
+ side: MultiSelectSide;
835
+ startLineNumber: number;
836
+ endLineNumber: number;
837
+ }
838
+ export interface MultiSelectOptions {
839
+ /**
840
+ * Enable multi-select feature
841
+ * @default true
842
+ */
843
+ enabled?: boolean;
844
+ /**
845
+ * Callback when selection changes (for visual updates)
846
+ */
847
+ onSelectionChange?: (range: LineRange | null, state: MultiSelectState) => void;
848
+ /**
849
+ * Callback when selection is complete (mouseup)
850
+ * Provides the selected range and line data from DiffFile
851
+ */
852
+ onSelectionComplete?: (result: MultiSelectResult | null) => void;
853
+ /**
854
+ * Custom function to scope selection to one hunk
855
+ * Return the scoped range or null to cancel selection
856
+ */
857
+ scopeToHunk?: (range: LineRange) => LineRange | null;
858
+ /**
859
+ * CSS class to add to selected cells
860
+ * @default "diff-multi-select-active"
861
+ */
862
+ selectedClassName?: string;
863
+ /**
864
+ * Whether it's unified mode
865
+ * @default false
866
+ */
867
+ isUnifiedMode?: boolean;
868
+ }
869
+ export interface MultiSelectResult {
870
+ range: LineRange;
871
+ lines: SelectedLine[];
872
+ }
873
+ export interface MultiSelectState {
874
+ isSelecting: boolean;
875
+ startInfo: {
876
+ lineNumber: number;
877
+ side: MultiSelectSide;
878
+ } | null;
879
+ currentRange: LineRange | null;
880
+ }
881
+ export interface SelectedLine {
882
+ index: number;
883
+ lineNumber: number;
884
+ value?: string;
885
+ isHide?: boolean;
886
+ isDelete?: boolean;
887
+ isAdd?: boolean;
888
+ isContext?: boolean;
889
+ }
714
890
  export interface SplitLineItem {
715
891
  lineNumber?: number;
716
892
  value?: string;
@@ -727,6 +903,10 @@ export interface UnifiedLineItem {
727
903
  _isHidden?: boolean;
728
904
  }
729
905
  export type DiffAST = Root;
906
+ /**
907
+ * Type alias for DiffFile used by multi-select
908
+ */
909
+ export type DiffFileForMultiSelect = DiffFile;
730
910
  export type DiffFileHighlighter = Omit<DiffHighlighter, "getHighlighterEngine">;
731
911
  export type DiffHighlighter = {
732
912
  name: string;
@@ -787,6 +967,11 @@ export type HunkLineInfo = {
787
967
  _endHiddenIndex: number;
788
968
  _plainText: string;
789
969
  };
970
+ export type MultiSelectSide = "old" | "new";
971
+ export type PreselectedLineType = {
972
+ old?: number[];
973
+ new?: number[];
974
+ };
790
975
  export type SyntaxLine = {
791
976
  value: string;
792
977
  lineNumber: number;
@@ -870,7 +1055,7 @@ declare const createDiffConfigStore: (props: DiffViewProps<any> & {
870
1055
  };
871
1056
  };
872
1057
  }>;
873
- setExtendData: (_extendData: DiffViewProps<any>["extendData"]) => void;
1058
+ setExtendData: (__extendData: DiffViewProps<any>["extendData"]) => void;
874
1059
  renderWidgetLine: import("reactivity-store").Ref<({ diffFile, side, lineNumber, onClose, }: {
875
1060
  lineNumber: number;
876
1061
  side: SplitSide;
@@ -1020,16 +1205,63 @@ export type DiffViewProps_2<T> = Omit<DiffViewProps<T>, "data"> & {
1020
1205
  };
1021
1206
  declare function ReactDiffView<T>(props: DiffViewProps_1<T> & {
1022
1207
  ref?: ForwardedRef<{
1023
- getDiffFileInstance: () => DiffFile;
1208
+ getDiffFileInstance: () => DiffFile | null;
1024
1209
  }>;
1025
1210
  }): JSX.Element;
1026
1211
  declare function ReactDiffView<T>(props: DiffViewProps_2<T> & {
1027
1212
  ref?: ForwardedRef<{
1028
- getDiffFileInstance: () => DiffFile;
1213
+ getDiffFileInstance: () => DiffFile | null;
1029
1214
  }>;
1030
1215
  }): JSX.Element;
1031
1216
  export declare const DiffView: typeof ReactDiffView;
1032
1217
  export declare const version: string;
1218
+ export interface DiffViewWithMultiSelectProps<T = unknown> extends Omit<DiffViewProps<T>, "renderWidgetLine" | "onAddWidgetClick"> {
1219
+ /**
1220
+ * Enable multi-select feature
1221
+ * @default true
1222
+ */
1223
+ enableMultiSelect?: boolean;
1224
+ /**
1225
+ * Callback when multi-line selection is complete
1226
+ * Use this to open a comment dialog or handle the selection
1227
+ */
1228
+ onMultiSelectComplete?: (result: MultiSelectResult) => void;
1229
+ /**
1230
+ * Callback when selection changes (during drag)
1231
+ */
1232
+ onMultiSelectChange?: (range: LineRange | null, state: MultiSelectState) => void;
1233
+ /**
1234
+ * Custom function to scope selection to one hunk
1235
+ * Return the scoped range or null to cancel selection
1236
+ */
1237
+ scopeMultiSelectToHunk?: (range: LineRange) => LineRange | null;
1238
+ onAddWidgetClick?: (props: {
1239
+ lineNumber: number;
1240
+ fromLineNumber?: number;
1241
+ side: SplitSide;
1242
+ }) => void;
1243
+ renderWidgetLine?: (props: {
1244
+ lineNumber: number;
1245
+ fromLineNumber: number;
1246
+ side: SplitSide;
1247
+ diffFile: DiffFile;
1248
+ onClose: () => void;
1249
+ }) => ReactNode;
1250
+ }
1251
+ export interface DiffViewWithMultiSelectRef {
1252
+ getDiffFileInstance: () => DiffFile | null;
1253
+ getSelectionResult: () => MultiSelectResult | null;
1254
+ getSelectionState: () => MultiSelectState;
1255
+ clearSelection: () => void;
1256
+ setPreselectedLines: (lines: {
1257
+ old: number[];
1258
+ new: number[];
1259
+ }) => void;
1260
+ }
1261
+ declare function ReactDiffView$1<T>(_props: DiffViewWithMultiSelectProps<T> & {
1262
+ ref?: ForwardedRef<DiffViewWithMultiSelectRef>;
1263
+ }): import("react/jsx-runtime").JSX.Element;
1264
+ export declare const DiffViewWithMultiSelect: typeof ReactDiffView$1;
1033
1265
 
1034
1266
  export {
1035
1267
  File$1 as File,
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "description": "@git-diff-view/react",
4
4
  "author": "MrWangJustToDo",
5
5
  "license": "MIT",
6
- "version": "0.1.2",
6
+ "version": "0.1.4",
7
7
  "main": "index.js",
8
8
  "types": "index.d.ts",
9
9
  "files": [
@@ -61,7 +61,7 @@
61
61
  "react diff component"
62
62
  ],
63
63
  "dependencies": {
64
- "@git-diff-view/core": "^0.1.2",
64
+ "@git-diff-view/core": "^0.1.4",
65
65
  "@types/hast": "^3.0.0",
66
66
  "fast-diff": "^1.3.0",
67
67
  "highlight.js": "^11.11.0",
package/src/_com.css CHANGED
@@ -167,6 +167,11 @@ td {
167
167
  display: block;
168
168
  }
169
169
 
170
+ .diff-line-extend-wrapper,
171
+ .diff-line-widget-wrapper {
172
+ display: flow-root;
173
+ }
174
+
170
175
  .diff-line-extend-wrapper * {
171
176
  color: initial;
172
177
  }
@@ -174,3 +179,97 @@ td {
174
179
  .diff-line-widget-wrapper * {
175
180
  color: initial;
176
181
  }
182
+
183
+ /* Multi-select styles for line range selection */
184
+ .diff-multi-select-active.diff-line-new-num,
185
+ .diff-multi-select-active.diff-line-old-num,
186
+ .diff-multi-select-active.diff-line-num {
187
+ z-index: 2;
188
+ }
189
+
190
+ .diff-multi-select-active.diff-line-content,
191
+ .diff-multi-select-active.diff-line-new-content,
192
+ .diff-multi-select-active.diff-line-old-content {
193
+ position: relative;
194
+ }
195
+
196
+ .diff-multi-select-active.diff-line-new-num::after,
197
+ .diff-multi-select-active.diff-line-old-num::after,
198
+ .diff-multi-select-active.diff-line-num::after {
199
+ content: "";
200
+ position: absolute;
201
+ z-index: 1;
202
+ inset: 0;
203
+ opacity: 0.15;
204
+ background-color: var(--diff-multi-select-bg, #f0c000);
205
+ pointer-events: none;
206
+ }
207
+
208
+ .diff-multi-select-active.diff-line-new-num::before,
209
+ .diff-multi-select-active.diff-line-old-num::before,
210
+ .diff-multi-select-active.diff-line-num::before {
211
+ content: "";
212
+ z-index: 2;
213
+ position: absolute;
214
+ top: 0;
215
+ bottom: 0;
216
+ right: -2px;
217
+ width: 4px;
218
+ background-color: var(--diff-multi-select-border, #2588fa);
219
+ }
220
+
221
+ .diff-multi-select-active.diff-line-new-content::after,
222
+ .diff-multi-select-active.diff-line-old-content::after,
223
+ .diff-multi-select-active.diff-line-content::after {
224
+ content: "";
225
+ position: absolute;
226
+ z-index: 1;
227
+ inset: 0;
228
+ opacity: 0.15;
229
+ background-color: var(--diff-multi-select-bg, #f0c000);
230
+ pointer-events: none;
231
+ }
232
+
233
+ /* Multi-select: ensure proper positioning for line number cells */
234
+ .diff-multi-selecting .diff-line-old-num,
235
+ .diff-multi-selecting .diff-line-new-num,
236
+ .diff-multi-selecting .diff-line-num {
237
+ user-select: none;
238
+ }
239
+
240
+ .diff-multi-selecting .diff-line-old-content,
241
+ .diff-multi-selecting .diff-line-new-content,
242
+ .diff-multi-selecting .diff-line-content {
243
+ user-select: none;
244
+ }
245
+
246
+ /* Prevent text selection during multi-line selection */
247
+ .diff-multi-selecting {
248
+ user-select: none;
249
+ }
250
+
251
+ .diff-multi-selecting * {
252
+ user-select: none;
253
+ }
254
+
255
+ /* Hide addWidget button during active dragging selection */
256
+ .diff-multi-selecting .diff-add-widget-wrapper {
257
+ display: none;
258
+ }
259
+
260
+ /* Ensure addWidget button is above selection overlay */
261
+ .diff-multiselect-wrapper .diff-add-widget-wrapper {
262
+ z-index: 10 !important;
263
+ }
264
+
265
+ /* Line number span should not interfere with click events */
266
+ .diff-line-new-num span[data-line-num],
267
+ .diff-line-old-num span[data-line-num] {
268
+ pointer-events: none;
269
+ }
270
+
271
+ .diff-multiselect-wrapper .diff-line-old-num,
272
+ .diff-multiselect-wrapper .diff-line-new-num,
273
+ .diff-multiselect-wrapper .diff-line-num {
274
+ cursor: pointer;
275
+ }
@@ -1,5 +1,4 @@
1
1
  import { addWidgetBGName, addWidgetColorName, diffFontSizeName } from "@git-diff-view/utils";
2
- import * as React from "react";
3
2
 
4
3
  import { SplitSide } from "./DiffView";
5
4
 
@@ -39,7 +38,8 @@ export const DiffSplitAddWidget = ({
39
38
  color: `var(${addWidgetColorName})`,
40
39
  backgroundColor: `var(${addWidgetBGName})`,
41
40
  }}
42
- onClick={() => {
41
+ onMouseDown={(e) => {
42
+ e.stopPropagation();
43
43
  onOpenAddWidget(lineNumber, side);
44
44
  onWidgetClick?.(lineNumber, side);
45
45
  }}
@@ -79,7 +79,8 @@ export const DiffUnifiedAddWidget = ({
79
79
  color: `var(${addWidgetColorName})`,
80
80
  backgroundColor: `var(${addWidgetBGName})`,
81
81
  }}
82
- onClick={() => {
82
+ onMouseDown={(e) => {
83
+ e.stopPropagation();
83
84
  onOpenAddWidget(lineNumber, side);
84
85
  onWidgetClick?.(lineNumber, side);
85
86
  }}
@@ -1,4 +1,3 @@
1
- /* eslint-disable max-lines */
2
1
  import {
3
2
  DiffLineType,
4
3
  getSyntaxDiffTemplate,
@@ -7,7 +6,6 @@ import {
7
6
  getPlainLineTemplate,
8
7
  } from "@git-diff-view/core";
9
8
  import { memoFunc, diffFontSizeName, NewLineSymbol } from "@git-diff-view/utils";
10
- import * as React from "react";
11
9
 
12
10
  import { DiffNoNewLine } from "./DiffNoNewLine";
13
11
 
@@ -30,7 +28,7 @@ const formatStringToCamelCase = (str: string) => {
30
28
 
31
29
  export const getStyleObjectFromString = memoFunc((str: string) => {
32
30
  if (!str) return temp;
33
- const style = {};
31
+ const style: Record<string, string> = {};
34
32
  str.split(";").forEach((el) => {
35
33
  const [property, value] = el.split(":");
36
34
  if (!property) return;
@@ -60,7 +58,7 @@ const DiffString = ({
60
58
  const isNewLineSymbolChanged = changes.newLineSymbol;
61
59
 
62
60
  if (!diffLine?.plainTemplate && typeof getPlainDiffTemplate === "function") {
63
- getPlainDiffTemplate({ diffLine, rawLine, operator });
61
+ getPlainDiffTemplate({ diffLine: diffLine!, rawLine, operator: operator! });
64
62
  }
65
63
 
66
64
  if (diffLine?.plainTemplate) {
@@ -85,6 +83,7 @@ const DiffString = ({
85
83
  }
86
84
 
87
85
  if (plainLine && !plainLine?.template) {
86
+ // eslint-disable-next-line react-hooks/immutability
88
87
  plainLine.template = getPlainLineTemplate(plainLine.value);
89
88
  }
90
89
 
@@ -124,7 +123,7 @@ const DiffSyntax = ({
124
123
  const isNewLineSymbolChanged = changes.newLineSymbol;
125
124
 
126
125
  if (!diffLine?.syntaxTemplate && typeof getSyntaxDiffTemplate === "function") {
127
- getSyntaxDiffTemplate({ diffFile, diffLine, syntaxLine, operator });
126
+ getSyntaxDiffTemplate({ diffFile, diffLine: diffLine!, syntaxLine, operator: operator! });
128
127
  }
129
128
 
130
129
  if (diffLine?.syntaxTemplate) {
@@ -149,6 +148,7 @@ const DiffSyntax = ({
149
148
  }
150
149
 
151
150
  if (!syntaxLine.template) {
151
+ // eslint-disable-next-line react-hooks/immutability
152
152
  syntaxLine.template = getSyntaxLineTemplate(syntaxLine);
153
153
  }
154
154
 
@@ -198,7 +198,7 @@ export const DiffContent = ({
198
198
 
199
199
  const isDelete = diffLine?.type === DiffLineType.Delete;
200
200
 
201
- const isMaxLineLengthToIgnoreSyntax = syntaxLine?.nodeList?.length > 150;
201
+ const isMaxLineLengthToIgnoreSyntax = syntaxLine && syntaxLine?.nodeList?.length > 150;
202
202
 
203
203
  return (
204
204
  <div
@@ -1,5 +1,3 @@
1
- import * as React from "react";
2
-
3
1
  export const ExpandDown = ({ className }: { className?: string }) => {
4
2
  return (
5
3
  <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" className={className}>
@@ -1,5 +1,3 @@
1
- import * as React from "react";
2
-
3
1
  export const DiffNoNewLine = () => {
4
2
  return (
5
3
  <svg aria-label="No newline at end of file" role="img" viewBox="0 0 16 16" version="1.1" fill="currentColor">
@@ -7,7 +7,6 @@ import {
7
7
  emptyBGName,
8
8
  expandLineNumberColorName,
9
9
  } from "@git-diff-view/utils";
10
- import * as React from "react";
11
10
 
12
11
  import { SplitSide } from "..";
13
12
 
@@ -63,9 +62,9 @@ const InternalDiffSplitLine = ({
63
62
 
64
63
  const lineNumberBG = getLineNumberBG(isAdded, isDelete, hasDiff);
65
64
 
66
- const syntaxLine = getCurrentSyntaxLine(currentLine.lineNumber);
65
+ const syntaxLine = getCurrentSyntaxLine(currentLine.lineNumber ?? -1);
67
66
 
68
- const plainLine = getCurrentPlainLine(currentLine.lineNumber);
67
+ const plainLine = getCurrentPlainLine(currentLine.lineNumber ?? -1);
69
68
 
70
69
  return (
71
70
  <tr
@@ -89,7 +88,7 @@ const InternalDiffSplitLine = ({
89
88
  {hasDiff && enableAddWidget && (
90
89
  <DiffSplitAddWidget
91
90
  index={index}
92
- lineNumber={currentLine.lineNumber}
91
+ lineNumber={currentLine.lineNumber ?? -1}
93
92
  side={side}
94
93
  diffFile={diffFile}
95
94
  onWidgetClick={(...props) => onAddWidgetClick.current?.(...props)}
@@ -7,7 +7,6 @@ import {
7
7
  borderColorName,
8
8
  expandLineNumberColorName,
9
9
  } from "@git-diff-view/utils";
10
- import * as React from "react";
11
10
 
12
11
  import { SplitSide } from "..";
13
12
 
@@ -33,13 +32,13 @@ const InternalDiffSplitLine = ({
33
32
 
34
33
  const newLine = diffFile.getSplitRightLine(index);
35
34
 
36
- const oldSyntaxLine = diffFile.getOldSyntaxLine(oldLine?.lineNumber);
35
+ const oldSyntaxLine = diffFile.getOldSyntaxLine(oldLine?.lineNumber ?? -1);
37
36
 
38
- const oldPlainLine = diffFile.getOldPlainLine(oldLine.lineNumber);
37
+ const oldPlainLine = diffFile.getOldPlainLine(oldLine.lineNumber ?? -1);
39
38
 
40
- const newSyntaxLine = diffFile.getNewSyntaxLine(newLine?.lineNumber);
39
+ const newSyntaxLine = diffFile.getNewSyntaxLine(newLine?.lineNumber ?? -1);
41
40
 
42
- const newPlainLine = diffFile.getNewPlainLine(newLine.lineNumber);
41
+ const newPlainLine = diffFile.getNewPlainLine(newLine.lineNumber ?? -1);
43
42
 
44
43
  const hasDiff = !!oldLine?.diff || !!newLine?.diff;
45
44
 
@@ -84,7 +83,7 @@ const InternalDiffSplitLine = ({
84
83
  {hasDiff && enableAddWidget && (
85
84
  <DiffSplitAddWidget
86
85
  index={index}
87
- lineNumber={oldLine.lineNumber}
86
+ lineNumber={oldLine.lineNumber ?? -1}
88
87
  side={SplitSide.old}
89
88
  diffFile={diffFile}
90
89
  onWidgetClick={(...props) => onAddWidgetClick.current?.(...props)}
@@ -104,7 +103,7 @@ const InternalDiffSplitLine = ({
104
103
  {hasDiff && enableAddWidget && (
105
104
  <DiffSplitAddWidget
106
105
  index={index}
107
- lineNumber={oldLine.lineNumber}
106
+ lineNumber={oldLine.lineNumber ?? -1}
108
107
  side={SplitSide.old}
109
108
  diffFile={diffFile}
110
109
  onWidgetClick={(...props) => onAddWidgetClick.current?.(...props)}
@@ -115,7 +114,7 @@ const InternalDiffSplitLine = ({
115
114
  <DiffContent
116
115
  enableWrap={true}
117
116
  diffFile={diffFile}
118
- rawLine={oldLine.value}
117
+ rawLine={oldLine.value || ""}
119
118
  diffLine={oldLine.diff}
120
119
  plainLine={oldPlainLine}
121
120
  syntaxLine={oldSyntaxLine}
@@ -148,7 +147,7 @@ const InternalDiffSplitLine = ({
148
147
  {hasDiff && enableAddWidget && (
149
148
  <DiffSplitAddWidget
150
149
  index={index}
151
- lineNumber={newLine.lineNumber}
150
+ lineNumber={newLine.lineNumber ?? -1}
152
151
  side={SplitSide.new}
153
152
  diffFile={diffFile}
154
153
  onWidgetClick={(...props) => onAddWidgetClick.current?.(...props)}
@@ -168,7 +167,7 @@ const InternalDiffSplitLine = ({
168
167
  {hasDiff && enableAddWidget && (
169
168
  <DiffSplitAddWidget
170
169
  index={index}
171
- lineNumber={newLine.lineNumber}
170
+ lineNumber={newLine.lineNumber ?? -1}
172
171
  side={SplitSide.new}
173
172
  diffFile={diffFile}
174
173
  onWidgetClick={(...props) => onAddWidgetClick.current?.(...props)}