react-diff-viewer-continued 4.2.0 → 4.3.0

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.
@@ -15,7 +15,8 @@
15
15
  "Bash(pnpm run build:*)",
16
16
  "Bash(pnpm exec vitest:*)",
17
17
  "Bash(grep:*)",
18
- "Bash(pnpm run test:*)"
18
+ "Bash(pnpm run test:*)",
19
+ "Bash(npm run *)"
19
20
  ],
20
21
  "deny": [],
21
22
  "ask": []
@@ -0,0 +1,36 @@
1
+ name: Deploy GitHub Pages
2
+
3
+ on:
4
+ release:
5
+ types: [published]
6
+ workflow_dispatch:
7
+
8
+ permissions:
9
+ contents: write
10
+
11
+ jobs:
12
+ deploy:
13
+ runs-on: ubuntu-latest
14
+ steps:
15
+ - uses: actions/checkout@v4
16
+
17
+ - uses: pnpm/action-setup@v4
18
+ with:
19
+ version: latest
20
+
21
+ - uses: actions/setup-node@v4
22
+ with:
23
+ node-version: 'lts/*'
24
+ cache: 'pnpm'
25
+
26
+ - run: pnpm install
27
+
28
+ - name: Configure git
29
+ run: |
30
+ git config --global user.email "github-actions[bot]@users.noreply.github.com"
31
+ git config --global user.name "github-actions[bot]"
32
+
33
+ - name: Deploy examples to GitHub Pages
34
+ run: pnpm publish:examples
35
+ env:
36
+ GITHUB_REPO_URL: https://x-access-token:${{ secrets.GITHUB_TOKEN }}@github.com/${{ github.repository }}.git
@@ -33,16 +33,8 @@ jobs:
33
33
  - run: pnpm install
34
34
  - run: pnpm build
35
35
 
36
- # Upgrade npm for provenance support (GitHub runners ship with old npm)
37
- - run: npm install -g npm@latest
38
-
39
- - name: Publish to npm
40
- run: pnpm publish --access public --provenance --no-git-checks
41
- env:
42
- NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
43
-
44
- # Create GitHub release with changelog notes
45
- - name: Create GitHub release
36
+ - name: Publish and create GitHub release
46
37
  run: pnpm just-release
47
38
  env:
48
39
  GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
40
+ NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
@@ -31,8 +31,8 @@ jobs:
31
31
  - name: Install dependencies
32
32
  run: pnpm i
33
33
 
34
- - name: Build worker bundle
35
- run: pnpm run build:worker
34
+ - name: Build
35
+ run: pnpm run build
36
36
 
37
37
  - name: Run unit tests
38
38
  run: pnpm run test
package/CHANGELOG.md CHANGED
@@ -1,5 +1,46 @@
1
1
  # Changelog
2
2
 
3
+ ## 4.3.0 (2026-07-10)
4
+
5
+ ### Features
6
+
7
+ - export default light and dark theme variables
8
+
9
+ ### Bug Fixes
10
+
11
+ - do not do extra publish step, just release publishes
12
+ - make exports immutable
13
+ - freeze dark theme variables and add export-existence tests
14
+ - add GitHub Pages deployment workflow and Vite base path
15
+ - isolate diff table from host table CSS (daisyui/bootstrap)
16
+ - bump js-yaml to ^4.2.0 (CVE-2026-53550)
17
+ - clear remaining audit advisories in dev toolchain
18
+
19
+ ### Documentation
20
+
21
+ - add overscan, disableWorker, and loading overlay to README
22
+
23
+ ### Chores
24
+
25
+ - make pnpm canonical (drop npm lockfile, approve builds)
26
+
27
+ ## 4.2.2 (2026-04-23)
28
+
29
+ ### Bug Fixes
30
+
31
+ - strict typescript types, and visible loader
32
+
33
+ ## 4.2.1 (2026-04-23)
34
+
35
+ ### Bug Fixes
36
+
37
+ - make overscan configurable
38
+ - handle ' HTML entity in diff view to prevent "undefined" suffix
39
+ - mousedown and mouseup
40
+ - do not show content while scrolling fast outside the overscan area
41
+ - update dependencies
42
+ - clean up old package-lock.json
43
+
3
44
  ## 4.2.0 (2026-03-10)
4
45
 
5
46
  ### Features
package/README.md CHANGED
@@ -92,8 +92,9 @@ class Diff extends PureComponent {
92
92
  | linesOffset | `number` | `0` | Number to start count code lines from. |
93
93
  | summary | `string \| ReactElement` | `undefined` | Text or element to display in the summary bar (e.g., filename). |
94
94
  | hideSummary | `boolean` | `false` | Hide the summary bar (expand/collapse button, change count, summary text). |
95
- | infiniteLoading | `{ pageSize: number, containerHeight: string }` | `undefined` | Enable virtualization for large diffs. When enabled, only visible rows are rendered. `containerHeight` sets the scrollable container height (e.g., `'500px'` or `'80vh'`). |
96
- | loadingElement | `() => ReactElement` | `undefined` | Function that returns an element to display while the diff is being computed. Useful with `infiniteLoading` for large files. |
95
+ | infiniteLoading | `{ pageSize: number, containerHeight: string, overscan?: number }` | `undefined` | Enable virtualization for large diffs. When enabled, only visible rows are rendered. `containerHeight` sets the scrollable container height (e.g., `'500px'` or `'80vh'`). `overscan` controls how many extra rows to render above and below the viewport (default `20`). |
96
+ | loadingElement | `() => ReactElement` | `undefined` | Function that returns an element to display while the diff is being computed or when content is hidden during fast scrolling. Useful with `infiniteLoading` for large files. |
97
+ | disableWorker | `boolean` | `false` | Disable the Web Worker used for diff computation, falling back to synchronous computation on the main thread. Useful when the worker bundle fails to load in certain bundler configurations. |
97
98
  | nonce | `string` | `''` | Nonce to use for inline styles (for CSP). |
98
99
 
99
100
  ## Instance Methods
@@ -114,7 +115,8 @@ Enable virtualization to only render visible rows:
114
115
  newValue={largeNewFile}
115
116
  infiniteLoading={{
116
117
  pageSize: 20,
117
- containerHeight: '80vh'
118
+ containerHeight: '80vh',
119
+ overscan: 20,
118
120
  }}
119
121
  loadingElement={() => (
120
122
  <div style={{ padding: '20px', textAlign: 'center' }}>
@@ -23,8 +23,8 @@ export interface DiffInformation {
23
23
  rawValue?: string;
24
24
  }
25
25
  export interface LineInformation {
26
- left?: DiffInformation;
27
- right?: DiffInformation;
26
+ left: DiffInformation;
27
+ right: DiffInformation;
28
28
  }
29
29
  export interface ComputedLineInformation {
30
30
  lineInformation: LineInformation[];
@@ -37,7 +37,7 @@ export interface ComputedDiffInformation {
37
37
  export interface JsDiffChangeObject {
38
38
  added?: boolean;
39
39
  removed?: boolean;
40
- value?: string;
40
+ value: string;
41
41
  }
42
42
  /**
43
43
  * Computes word diff information in the line.
@@ -64,5 +64,5 @@ declare const computeDiff: (oldValue: string | Record<string, unknown>, newValue
64
64
  * @param showLines lines that are always shown, regardless of diff
65
65
  */
66
66
  declare const computeLineInformation: (oldString: string | Record<string, unknown>, newString: string | Record<string, unknown>, disableWordDiff?: boolean, lineCompareMethod?: DiffMethod | ((oldStr: string, newStr: string) => diff.Change[]), linesOffset?: number, showLines?: string[], deferWordDiff?: boolean) => ComputedLineInformation;
67
- declare const computeLineInformationWorker: (oldString: string | Record<string, unknown>, newString: string | Record<string, unknown>, disableWordDiff?: boolean, lineCompareMethod?: DiffMethod | ((oldStr: string, newStr: string) => diff.Change[]), linesOffset?: number, showLines?: string[], deferWordDiff?: boolean) => Promise<ComputedLineInformation>;
67
+ declare const computeLineInformationWorker: (oldString: string | Record<string, unknown>, newString: string | Record<string, unknown>, disableWordDiff?: boolean, lineCompareMethod?: DiffMethod | ((oldStr: string, newStr: string) => diff.Change[]), linesOffset?: number, showLines?: string[], deferWordDiff?: boolean, disableWorker?: boolean) => Promise<ComputedLineInformation>;
68
68
  export { computeLineInformation, computeLineInformationWorker, computeDiff };
@@ -305,24 +305,17 @@ const computeDiff = (oldValue, newValue, compareMethod = DiffMethod.CHARS) => {
305
305
  right: [],
306
306
  };
307
307
  diffArray.forEach(({ added, removed, value }) => {
308
- const diffInformation = {};
309
308
  if (added) {
310
- diffInformation.type = DiffType.ADDED;
311
- diffInformation.value = value;
312
- computedDiff.right.push(diffInformation);
309
+ computedDiff.right.push({ type: DiffType.ADDED, value });
313
310
  }
314
- if (removed) {
315
- diffInformation.type = DiffType.REMOVED;
316
- diffInformation.value = value;
317
- computedDiff.left.push(diffInformation);
311
+ else if (removed) {
312
+ computedDiff.left.push({ type: DiffType.REMOVED, value });
318
313
  }
319
- if (!removed && !added) {
320
- diffInformation.type = DiffType.DEFAULT;
321
- diffInformation.value = value;
322
- computedDiff.right.push(diffInformation);
323
- computedDiff.left.push(diffInformation);
314
+ else {
315
+ const info = { type: DiffType.DEFAULT, value };
316
+ computedDiff.right.push(info);
317
+ computedDiff.left.push(info);
324
318
  }
325
- return diffInformation;
326
319
  });
327
320
  return computedDiff;
328
321
  };
@@ -477,7 +470,7 @@ const computeLineInformation = (oldString, newString, disableWordDiff = false, l
477
470
  }
478
471
  return { right, left };
479
472
  })
480
- .filter(Boolean);
473
+ .filter((x) => x != null);
481
474
  };
482
475
  diffArray.forEach(({ added, removed, value }, index) => {
483
476
  lineInformation = [
@@ -502,20 +495,21 @@ const computeLineInformation = (oldString, newString, disableWordDiff = false, l
502
495
  * @param showLines lines that are always shown, regardless of diff
503
496
  * @returns Promise<ComputedLineInformation> - Resolves with line-by-line diff data from the worker.
504
497
  */
505
- // Import the bundled worker code (generated by scripts/build-worker.js)
506
- import { WORKER_CODE } from './workerBundle.js';
507
498
  // Cached Blob URL for the worker - created once and reused
508
499
  let workerBlobUrl = null;
509
500
  let workerAvailable = null;
510
- // Create a Blob URL from the bundled worker code
511
- const getWorkerBlobUrl = () => {
501
+ // Lazily import and create a Blob URL from the bundled worker code
502
+ const getWorkerBlobUrl = async () => {
512
503
  if (workerBlobUrl !== null)
513
504
  return workerBlobUrl;
505
+ if (workerAvailable === false)
506
+ return null;
514
507
  if (typeof Worker === 'undefined' || typeof Blob === 'undefined' || typeof URL === 'undefined') {
515
508
  workerAvailable = false;
516
509
  return null;
517
510
  }
518
511
  try {
512
+ const { WORKER_CODE } = await import('./workerBundle.js');
519
513
  const blob = new Blob([WORKER_CODE], { type: 'application/javascript' });
520
514
  workerBlobUrl = URL.createObjectURL(blob);
521
515
  workerAvailable = true;
@@ -526,9 +520,12 @@ const getWorkerBlobUrl = () => {
526
520
  }
527
521
  return workerBlobUrl;
528
522
  };
529
- const computeLineInformationWorker = (oldString, newString, disableWordDiff = false, lineCompareMethod = DiffMethod.CHARS, linesOffset = 0, showLines = [], deferWordDiff = false) => {
523
+ const computeLineInformationWorker = async (oldString, newString, disableWordDiff = false, lineCompareMethod = DiffMethod.CHARS, linesOffset = 0, showLines = [], deferWordDiff = false, disableWorker = false) => {
530
524
  const fallback = () => computeLineInformation(oldString, newString, disableWordDiff, lineCompareMethod, linesOffset, showLines, deferWordDiff);
531
- const blobUrl = getWorkerBlobUrl();
525
+ if (disableWorker) {
526
+ return Promise.resolve(fallback());
527
+ }
528
+ const blobUrl = await getWorkerBlobUrl();
532
529
  if (!blobUrl) {
533
530
  return Promise.resolve(fallback());
534
531
  }
@@ -538,7 +535,6 @@ const computeLineInformationWorker = (oldString, newString, disableWordDiff = fa
538
535
  worker = new Worker(blobUrl);
539
536
  }
540
537
  catch (_a) {
541
- // Worker instantiation failed - fall back to synchronous computation
542
538
  workerAvailable = false;
543
539
  resolve(fallback());
544
540
  return;
@@ -548,7 +544,6 @@ const computeLineInformationWorker = (oldString, newString, disableWordDiff = fa
548
544
  worker.terminate();
549
545
  };
550
546
  worker.onerror = () => {
551
- // Worker error - fall back and mark as unavailable for future calls
552
547
  workerAvailable = false;
553
548
  worker.terminate();
554
549
  resolve(fallback());
@@ -3,7 +3,7 @@ import type { ReactElement, RefObject } from "react";
3
3
  import type { Change } from "diff";
4
4
  import { type Block } from "./compute-hidden-blocks.js";
5
5
  import { type DiffInformation, DiffMethod, DiffType, type LineInformation } from "./compute-lines.js";
6
- import { type ReactDiffViewerStyles, type ReactDiffViewerStylesOverride } from "./styles.js";
6
+ import { type ReactDiffViewerStyles, type ReactDiffViewerStylesOverride, type ReactDiffViewerStylesVariables } from "./styles.js";
7
7
  export declare enum LineNumberPrefix {
8
8
  LEFT = "L",
9
9
  RIGHT = "R"
@@ -11,6 +11,7 @@ export declare enum LineNumberPrefix {
11
11
  export interface InfiniteLoadingProps {
12
12
  pageSize: number;
13
13
  containerHeight: string;
14
+ overscan?: number;
14
15
  }
15
16
  export interface ComputedDiffResult {
16
17
  lineInformation: LineInformation[];
@@ -39,8 +40,8 @@ export interface ReactDiffViewerProps {
39
40
  type: DiffType;
40
41
  prefix: LineNumberPrefix;
41
42
  value: string | DiffInformation[];
42
- additionalLineNumber: number;
43
- additionalPrefix: LineNumberPrefix;
43
+ additionalLineNumber?: number;
44
+ additionalPrefix?: LineNumberPrefix;
44
45
  styles: ReactDiffViewerStyles;
45
46
  }) => ReactElement;
46
47
  highlightLines?: string[];
@@ -69,17 +70,23 @@ export interface ReactDiffViewerProps {
69
70
  * Show debug overlay with virtualization info (for development)
70
71
  */
71
72
  showDebugInfo?: boolean;
73
+ /**
74
+ * Disable Web Worker for diff computation, using synchronous fallback instead.
75
+ * Useful when the worker bundle fails to load in certain bundler configurations.
76
+ */
77
+ disableWorker?: boolean;
72
78
  }
73
79
  export interface ReactDiffViewerState {
74
- expandedBlocks?: number[];
80
+ expandedBlocks: number[];
75
81
  noSelect?: "left" | "right";
76
- scrollableContainerRef: RefObject<HTMLDivElement>;
82
+ scrollableContainerRef: RefObject<HTMLDivElement | null>;
77
83
  computedDiffResult: Record<string, ComputedDiffResult>;
78
84
  isLoading: boolean;
79
85
  visibleStartRow: number;
80
86
  contentColumnWidth: number | null;
81
87
  charWidth: number | null;
82
88
  cumulativeOffsets: number[] | null;
89
+ isScrolling: boolean;
83
90
  }
84
91
  declare class DiffViewer extends React.Component<ReactDiffViewerProps, ReactDiffViewerState> {
85
92
  private styles;
@@ -88,6 +95,8 @@ declare class DiffViewer extends React.Component<ReactDiffViewerProps, ReactDiff
88
95
  private charMeasureRef;
89
96
  private stickyHeaderRef;
90
97
  private resizeObserver;
98
+ private scrollDebounceTimer;
99
+ private lastRenderedRange;
91
100
  static defaultProps: ReactDiffViewerProps;
92
101
  constructor(props: ReactDiffViewerProps);
93
102
  /**
@@ -249,4 +258,5 @@ declare class DiffViewer extends React.Component<ReactDiffViewerProps, ReactDiff
249
258
  export default DiffViewer;
250
259
  export { DiffMethod };
251
260
  export { default as computeStyles } from "./styles.js";
252
- export type { ReactDiffViewerStylesOverride, ReactDiffViewerStyles };
261
+ export { defaultLightThemeVariables, defaultDarkThemeVariables, } from "./styles.js";
262
+ export type { ReactDiffViewerStylesOverride, ReactDiffViewerStyles, ReactDiffViewerStylesVariables };