react-diff-viewer-continued 4.1.0 → 4.1.2
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/.claude/settings.local.json +8 -1
- package/.github/workflows/release.yml +3 -0
- package/CHANGELOG.md +13 -0
- package/lib/cjs/src/compute-lines.d.ts +0 -12
- package/lib/cjs/src/compute-lines.js +58 -9
- package/lib/cjs/src/index.d.ts +44 -0
- package/lib/cjs/src/index.js +270 -24
- package/lib/cjs/src/styles.d.ts +1 -0
- package/lib/cjs/src/styles.js +15 -0
- package/lib/cjs/src/workerBundle.d.ts +5 -0
- package/lib/cjs/src/workerBundle.js +7 -0
- package/lib/esm/src/compute-lines.js +58 -9
- package/lib/esm/src/index.js +265 -23
- package/lib/esm/src/styles.js +15 -0
- package/lib/esm/src/workerBundle.js +7 -0
- package/package.json +4 -2
- package/scripts/build-worker.js +50 -0
|
@@ -8,7 +8,14 @@
|
|
|
8
8
|
"Bash(pnpm test:*)",
|
|
9
9
|
"Bash(CI=1 pnpm test:*)",
|
|
10
10
|
"Bash(CI=1 npm test:*)",
|
|
11
|
-
"Bash(pnpm remove:*)"
|
|
11
|
+
"Bash(pnpm remove:*)",
|
|
12
|
+
"Bash(npm test:*)",
|
|
13
|
+
"Bash(npx tsc:*)",
|
|
14
|
+
"Bash(ls:*)",
|
|
15
|
+
"Bash(pnpm run build:*)",
|
|
16
|
+
"Bash(pnpm exec vitest:*)",
|
|
17
|
+
"Bash(grep:*)",
|
|
18
|
+
"Bash(pnpm run test:*)"
|
|
12
19
|
],
|
|
13
20
|
"deny": [],
|
|
14
21
|
"ask": []
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,18 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 4.1.2 (2026-02-07)
|
|
4
|
+
|
|
5
|
+
### Bug Fixes
|
|
6
|
+
|
|
7
|
+
- fix virtualization offsets and missing key display on structural json diff
|
|
8
|
+
- bundle worker code as a blob
|
|
9
|
+
|
|
10
|
+
## 4.1.1 (2026-02-07)
|
|
11
|
+
|
|
12
|
+
### Bug Fixes
|
|
13
|
+
|
|
14
|
+
- fix problem with missing worker in compiled version
|
|
15
|
+
|
|
3
16
|
## 4.1.0 (2026-02-04)
|
|
4
17
|
|
|
5
18
|
### Features
|
|
@@ -64,17 +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
|
-
/**
|
|
68
|
-
* Computes line diff information using a Web Worker to avoid blocking the UI thread.
|
|
69
|
-
* This offloads the expensive `computeLineInformation` logic to a separate thread.
|
|
70
|
-
*
|
|
71
|
-
* @param oldString Old string to compare.
|
|
72
|
-
* @param newString New string to compare with old string.
|
|
73
|
-
* @param disableWordDiff Flag to enable/disable word diff.
|
|
74
|
-
* @param lineCompareMethod JsDiff text diff method from https://github.com/kpdecker/jsdiff/tree/v4.0.1#api
|
|
75
|
-
* @param linesOffset line number to start counting from
|
|
76
|
-
* @param showLines lines that are always shown, regardless of diff
|
|
77
|
-
* @returns Promise<ComputedLineInformation> - Resolves with line-by-line diff data from the worker.
|
|
78
|
-
*/
|
|
79
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>;
|
|
80
68
|
export { computeLineInformation, computeLineInformationWorker, computeDiff };
|
|
@@ -151,9 +151,22 @@ function diffObjects(oldObj, newObj, indent, format = 'json') {
|
|
|
151
151
|
// Values differ - recursively diff them
|
|
152
152
|
const keyPrefix = innerIndent + JSON.stringify(key) + ': ';
|
|
153
153
|
const valueDiff = diffStructurally(oldObj[key], newObj[key], indent + 1, format);
|
|
154
|
-
// Prepend key to
|
|
154
|
+
// Prepend key to the appropriate changes
|
|
155
155
|
if (valueDiff.length > 0) {
|
|
156
|
-
valueDiff[0].
|
|
156
|
+
if (!valueDiff[0].removed && !valueDiff[0].added) {
|
|
157
|
+
// First change is neutral (e.g., opening brace of nested object) - prepend key to it only
|
|
158
|
+
valueDiff[0].value = keyPrefix + valueDiff[0].value;
|
|
159
|
+
}
|
|
160
|
+
else {
|
|
161
|
+
// First change is removed or added - this is a primitive value change
|
|
162
|
+
// Both the removed (old) and added (new) lines need the key
|
|
163
|
+
const firstRemoved = valueDiff.find(c => c.removed);
|
|
164
|
+
const firstAdded = valueDiff.find(c => c.added);
|
|
165
|
+
if (firstRemoved)
|
|
166
|
+
firstRemoved.value = keyPrefix + firstRemoved.value;
|
|
167
|
+
if (firstAdded)
|
|
168
|
+
firstAdded.value = keyPrefix + firstAdded.value;
|
|
169
|
+
}
|
|
157
170
|
}
|
|
158
171
|
// Add comma to last change if needed
|
|
159
172
|
if (comma && valueDiff.length > 0) {
|
|
@@ -489,20 +502,56 @@ const computeLineInformation = (oldString, newString, disableWordDiff = false, l
|
|
|
489
502
|
* @param showLines lines that are always shown, regardless of diff
|
|
490
503
|
* @returns Promise<ComputedLineInformation> - Resolves with line-by-line diff data from the worker.
|
|
491
504
|
*/
|
|
505
|
+
// Import the bundled worker code (generated by scripts/build-worker.js)
|
|
506
|
+
import { WORKER_CODE } from './workerBundle';
|
|
507
|
+
// Cached Blob URL for the worker - created once and reused
|
|
508
|
+
let workerBlobUrl = null;
|
|
509
|
+
let workerAvailable = null;
|
|
510
|
+
// Create a Blob URL from the bundled worker code
|
|
511
|
+
const getWorkerBlobUrl = () => {
|
|
512
|
+
if (workerBlobUrl !== null)
|
|
513
|
+
return workerBlobUrl;
|
|
514
|
+
if (typeof Worker === 'undefined' || typeof Blob === 'undefined' || typeof URL === 'undefined') {
|
|
515
|
+
workerAvailable = false;
|
|
516
|
+
return null;
|
|
517
|
+
}
|
|
518
|
+
try {
|
|
519
|
+
const blob = new Blob([WORKER_CODE], { type: 'application/javascript' });
|
|
520
|
+
workerBlobUrl = URL.createObjectURL(blob);
|
|
521
|
+
workerAvailable = true;
|
|
522
|
+
}
|
|
523
|
+
catch (_a) {
|
|
524
|
+
workerAvailable = false;
|
|
525
|
+
workerBlobUrl = null;
|
|
526
|
+
}
|
|
527
|
+
return workerBlobUrl;
|
|
528
|
+
};
|
|
492
529
|
const computeLineInformationWorker = (oldString, newString, disableWordDiff = false, lineCompareMethod = DiffMethod.CHARS, linesOffset = 0, showLines = [], deferWordDiff = false) => {
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
530
|
+
const fallback = () => computeLineInformation(oldString, newString, disableWordDiff, lineCompareMethod, linesOffset, showLines, deferWordDiff);
|
|
531
|
+
const blobUrl = getWorkerBlobUrl();
|
|
532
|
+
if (!blobUrl) {
|
|
533
|
+
return Promise.resolve(fallback());
|
|
496
534
|
}
|
|
497
|
-
return new Promise((resolve
|
|
498
|
-
|
|
535
|
+
return new Promise((resolve) => {
|
|
536
|
+
let worker;
|
|
537
|
+
try {
|
|
538
|
+
worker = new Worker(blobUrl);
|
|
539
|
+
}
|
|
540
|
+
catch (_a) {
|
|
541
|
+
// Worker instantiation failed - fall back to synchronous computation
|
|
542
|
+
workerAvailable = false;
|
|
543
|
+
resolve(fallback());
|
|
544
|
+
return;
|
|
545
|
+
}
|
|
499
546
|
worker.onmessage = (e) => {
|
|
500
547
|
resolve(e.data);
|
|
501
548
|
worker.terminate();
|
|
502
549
|
};
|
|
503
|
-
worker.onerror = (
|
|
504
|
-
|
|
550
|
+
worker.onerror = () => {
|
|
551
|
+
// Worker error - fall back and mark as unavailable for future calls
|
|
552
|
+
workerAvailable = false;
|
|
505
553
|
worker.terminate();
|
|
554
|
+
resolve(fallback());
|
|
506
555
|
};
|
|
507
556
|
worker.postMessage({ oldString, newString, disableWordDiff, lineCompareMethod, linesOffset, showLines, deferWordDiff });
|
|
508
557
|
});
|
package/lib/cjs/src/index.d.ts
CHANGED
|
@@ -65,6 +65,10 @@ export interface ReactDiffViewerProps {
|
|
|
65
65
|
* Hide the summary bar (expand/collapse button, change count, filename)
|
|
66
66
|
*/
|
|
67
67
|
hideSummary?: boolean;
|
|
68
|
+
/**
|
|
69
|
+
* Show debug overlay with virtualization info (for development)
|
|
70
|
+
*/
|
|
71
|
+
showDebugInfo?: boolean;
|
|
68
72
|
}
|
|
69
73
|
export interface ReactDiffViewerState {
|
|
70
74
|
expandedBlocks?: number[];
|
|
@@ -73,10 +77,17 @@ export interface ReactDiffViewerState {
|
|
|
73
77
|
computedDiffResult: Record<string, ComputedDiffResult>;
|
|
74
78
|
isLoading: boolean;
|
|
75
79
|
visibleStartRow: number;
|
|
80
|
+
contentColumnWidth: number | null;
|
|
81
|
+
charWidth: number | null;
|
|
82
|
+
cumulativeOffsets: number[] | null;
|
|
76
83
|
}
|
|
77
84
|
declare class DiffViewer extends React.Component<ReactDiffViewerProps, ReactDiffViewerState> {
|
|
78
85
|
private styles;
|
|
79
86
|
private wordDiffCache;
|
|
87
|
+
private contentColumnRef;
|
|
88
|
+
private charMeasureRef;
|
|
89
|
+
private stickyHeaderRef;
|
|
90
|
+
private resizeObserver;
|
|
80
91
|
static defaultProps: ReactDiffViewerProps;
|
|
81
92
|
constructor(props: ReactDiffViewerProps);
|
|
82
93
|
/**
|
|
@@ -94,6 +105,38 @@ declare class DiffViewer extends React.Component<ReactDiffViewerProps, ReactDiff
|
|
|
94
105
|
* this value is used to expand/fold unmodified code.
|
|
95
106
|
*/
|
|
96
107
|
private onBlockExpand;
|
|
108
|
+
/**
|
|
109
|
+
* Gets the height of the sticky header, if present.
|
|
110
|
+
*/
|
|
111
|
+
private getStickyHeaderHeight;
|
|
112
|
+
/**
|
|
113
|
+
* Measures the width of a single character in the monospace font.
|
|
114
|
+
* Falls back to 7.2px if measurement fails.
|
|
115
|
+
*/
|
|
116
|
+
private measureCharWidth;
|
|
117
|
+
/**
|
|
118
|
+
* Measures the available width for content in a content column.
|
|
119
|
+
* Falls back to estimating from container width if direct measurement fails.
|
|
120
|
+
*/
|
|
121
|
+
private measureContentColumnWidth;
|
|
122
|
+
/**
|
|
123
|
+
* Gets the text length from a value that may be a string or DiffInformation array.
|
|
124
|
+
*/
|
|
125
|
+
private getTextLength;
|
|
126
|
+
/**
|
|
127
|
+
* Builds cumulative vertical offsets for each line based on character count and column width.
|
|
128
|
+
* This allows accurate scroll position calculations with variable row heights.
|
|
129
|
+
*/
|
|
130
|
+
private buildCumulativeOffsets;
|
|
131
|
+
/**
|
|
132
|
+
* Binary search to find the line index at a given scroll offset.
|
|
133
|
+
*/
|
|
134
|
+
private findLineAtOffset;
|
|
135
|
+
/**
|
|
136
|
+
* Recalculates cumulative offsets based on current measurements.
|
|
137
|
+
* Called on resize and when blocks are expanded/collapsed.
|
|
138
|
+
*/
|
|
139
|
+
private recalculateOffsets;
|
|
97
140
|
/**
|
|
98
141
|
* Computes final styles for the diff viewer. It combines the default styles with the user
|
|
99
142
|
* supplied overrides. The computed styles are cached with performance in mind.
|
|
@@ -200,6 +243,7 @@ declare class DiffViewer extends React.Component<ReactDiffViewerProps, ReactDiff
|
|
|
200
243
|
private renderDiff;
|
|
201
244
|
componentDidUpdate(prevProps: ReactDiffViewerProps): void;
|
|
202
245
|
componentDidMount(): void;
|
|
246
|
+
componentWillUnmount(): void;
|
|
203
247
|
render: () => ReactElement;
|
|
204
248
|
}
|
|
205
249
|
export default DiffViewer;
|