Skip to content

Commit 5f545b4

Browse files
Merge pull request #10 from Zhang-JiahangH/phase1
feat: add compatibility for react-diff-viewer now
2 parents 4c2eba4 + 726be83 commit 5f545b4

12 files changed

Lines changed: 1429 additions & 315 deletions

File tree

README.md

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -52,9 +52,26 @@ export function App() {
5252

5353
| Prop | Type | Default | Description |
5454
| --- | --- | --- | --- |
55-
| `original` | `string` | - | Original text content |
56-
| `modified` | `string` | - | Modified text content |
55+
| `original` | `string` | - | Original text content (new API) |
56+
| `modified` | `string` | - | Modified text content (new API) |
57+
| `oldValue` | `string` | - | Compatibility API: same as `original` |
58+
| `newValue` | `string` | - | Compatibility API: same as `modified` |
59+
| `splitView` | `boolean` | `true` | `true` for side-by-side, `false` for unified/inline |
60+
| `showDiffOnly` | `boolean` | `true` | Show only changed lines with collapsible unchanged blocks |
5761
| `contextLines` | `number` | `2` | Number of unchanged lines kept around diff hunks |
62+
| `extraLinesSurroundingDiff` | `number` | - | Compatibility API alias for context lines |
63+
| `hideLineNumbers` | `boolean` | `false` | Hide line number columns |
64+
| `highlightLines` | `Array<'L-n' \| 'R-n' \| range>` | - | Highlight specific lines (`L-3`, `R-5`, `L-10-15`) |
65+
| `onLineNumberClick` | `(lineId) => void` | - | Called when a line number is clicked |
66+
| `renderContent` | `(line: string) => ReactNode` | - | Custom line content renderer (syntax highlighting etc.) |
67+
| `compareMethod` | `"CHARS" \| "WORDS" \| "WORDS_WITH_SPACE" \| "LINES" \| "TRIMMED_LINES" \| "SENTENCES" \| "CSS"` | `"LINES"` | Diff compare strategy |
68+
| `disableWordDiff` | `boolean` | `false` | Disable inline word-level diff highlighting |
69+
| `leftTitle` | `ReactNode` | - | Left pane title (split view) |
70+
| `rightTitle` | `ReactNode` | - | Right pane title (split view) |
71+
| `linesOffset` | `number` | `0` | Add offset to displayed line numbers |
72+
| `useDarkTheme` | `boolean` | `false` | Built-in dark theme |
73+
| `styles` | `Partial<DiffViewerStyles>` | - | Override style slots |
74+
| `codeFoldMessageRenderer` | `({ hiddenCount, expanded }) => ReactNode` | - | Custom fold button content renderer |
5875
| `height` | `number \| string` | `500` | Viewport height of the virtual list |
5976
| `locale` | `DiffViewerLocale` | - | UI text localization |
6077
| `language` | `string` | - | Reserved field for future language-related extensions |
@@ -83,11 +100,11 @@ Metrics:
83100
- initial render time
84101
- memory usage (`usedJSHeapSize`)
85102

86-
Quick highlights from latest report:
103+
Quick highlights from the latest report (`2026-04-08T06:45:43.686Z`):
87104

88-
- At `10k` lines: ~`60 FPS`, `187.2 ms` initial render, `9.5 MB` memory.
89-
- At `50k/100k` lines: `react-diff-viewer` and `react-diff-viewer-continued` timeout.
90-
- At `100k` lines: `141.1 MB` (`react-virtualized-diff`) vs `1297.0 MB` (`react-diff-view`).
105+
- At `10k` lines (`react-virtualized-diff`): `60.8 FPS`, `127.0 ms` initial render, `9.5 MB` memory.
106+
- At `50k/100k` lines: `react-diff-viewer` and `react-diff-viewer-continued` both timeout (`60000 ms` per case).
107+
- At `100k` lines: `104.0 MB` (`react-virtualized-diff`) vs `1297.0 MB` (`react-diff-view`).
91108

92109
Run benchmark:
93110

README.zh-CN.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -83,11 +83,11 @@ export function App() {
8383
- 首次渲染时间
8484
- 内存占用(`usedJSHeapSize`
8585

86-
最新结果亮点:
86+
最新结果亮点`2026-04-08T06:45:43.686Z`
8787

88-
- `10k`:约 `60 FPS`,首渲染 `187.2 ms`,内存 `9.5 MB`
89-
- `50k/100k` 行:`react-diff-viewer``react-diff-viewer-continued` 超时
90-
- `100k` 行:本库 `141.1 MB``react-diff-view``1297.0 MB`
88+
- `10k``react-virtualized-diff`):`60.8 FPS`,首渲染 `127.0 ms`,内存 `9.5 MB`
89+
- `50k/100k` 行:`react-diff-viewer``react-diff-viewer-continued` 均超时(单 case 超时 `60000 ms`
90+
- `100k` 行:本库 `104.0 MB``react-diff-view``1297.0 MB`
9191

9292
运行方式:
9393

apps/demo/src/components/PlaygroundControls.tsx

Lines changed: 189 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,17 @@ export type DemoState = {
44
dataset: DatasetKey;
55
contextLines: number;
66
height: number;
7+
splitView: boolean;
8+
showDiffOnly: boolean;
9+
hideLineNumbers: boolean;
10+
useCompatApi: boolean;
11+
enableRenderContent: boolean;
12+
enableHighlight: boolean;
13+
compareMethod: 'LINES' | 'WORDS' | 'CHARS';
14+
disableWordDiff: boolean;
15+
useDarkTheme: boolean;
16+
linesOffset: number;
17+
useCustomFoldRenderer: boolean;
718
};
819

920
type PlaygroundControlsProps = {
@@ -82,6 +93,184 @@ export default function PlaygroundControls(props: PlaygroundControlsProps) {
8293
/>
8394
</div>
8495

96+
<div className="control-panel__section">
97+
<label className="toggle-row" htmlFor="splitView">
98+
<input
99+
id="splitView"
100+
type="checkbox"
101+
checked={value.splitView}
102+
onChange={(event) =>
103+
onChange({
104+
...value,
105+
splitView: event.target.checked,
106+
})
107+
}
108+
/>
109+
<span>Split view (`splitView`)</span>
110+
</label>
111+
112+
<label className="toggle-row" htmlFor="showDiffOnly">
113+
<input
114+
id="showDiffOnly"
115+
type="checkbox"
116+
checked={value.showDiffOnly}
117+
onChange={(event) =>
118+
onChange({
119+
...value,
120+
showDiffOnly: event.target.checked,
121+
})
122+
}
123+
/>
124+
<span>Show diff only (`showDiffOnly`)</span>
125+
</label>
126+
127+
<label className="toggle-row" htmlFor="hideLineNumbers">
128+
<input
129+
id="hideLineNumbers"
130+
type="checkbox"
131+
checked={value.hideLineNumbers}
132+
onChange={(event) =>
133+
onChange({
134+
...value,
135+
hideLineNumbers: event.target.checked,
136+
})
137+
}
138+
/>
139+
<span>Hide line numbers (`hideLineNumbers`)</span>
140+
</label>
141+
142+
<label className="toggle-row" htmlFor="useCompatApi">
143+
<input
144+
id="useCompatApi"
145+
type="checkbox"
146+
checked={value.useCompatApi}
147+
onChange={(event) =>
148+
onChange({
149+
...value,
150+
useCompatApi: event.target.checked,
151+
})
152+
}
153+
/>
154+
<span>Use legacy `oldValue/newValue` props</span>
155+
</label>
156+
157+
<label className="toggle-row" htmlFor="enableRenderContent">
158+
<input
159+
id="enableRenderContent"
160+
type="checkbox"
161+
checked={value.enableRenderContent}
162+
onChange={(event) =>
163+
onChange({
164+
...value,
165+
enableRenderContent: event.target.checked,
166+
})
167+
}
168+
/>
169+
<span>Enable `renderContent` formatter</span>
170+
</label>
171+
172+
<label className="toggle-row" htmlFor="enableHighlight">
173+
<input
174+
id="enableHighlight"
175+
type="checkbox"
176+
checked={value.enableHighlight}
177+
onChange={(event) =>
178+
onChange({
179+
...value,
180+
enableHighlight: event.target.checked,
181+
})
182+
}
183+
/>
184+
<span>Enable `highlightLines` preset</span>
185+
</label>
186+
</div>
187+
188+
189+
<div className="control-panel__section">
190+
<label className="field-label" htmlFor="compareMethod">
191+
Compare method
192+
</label>
193+
<select
194+
id="compareMethod"
195+
className="field-input"
196+
value={value.compareMethod}
197+
onChange={(event) =>
198+
onChange({
199+
...value,
200+
compareMethod: event.target.value as DemoState['compareMethod'],
201+
})
202+
}
203+
>
204+
<option value="LINES">LINES</option>
205+
<option value="WORDS">WORDS</option>
206+
{/* <option value="CHARS">CHARS</option> */}
207+
</select>
208+
209+
<label className="toggle-row" htmlFor="disableWordDiff">
210+
<input
211+
id="disableWordDiff"
212+
type="checkbox"
213+
checked={value.disableWordDiff}
214+
onChange={(event) =>
215+
onChange({
216+
...value,
217+
disableWordDiff: event.target.checked,
218+
})
219+
}
220+
/>
221+
<span>Disable word diff (`disableWordDiff`)</span>
222+
</label>
223+
224+
<label className="toggle-row" htmlFor="useDarkTheme">
225+
<input
226+
id="useDarkTheme"
227+
type="checkbox"
228+
checked={value.useDarkTheme}
229+
onChange={(event) =>
230+
onChange({
231+
...value,
232+
useDarkTheme: event.target.checked,
233+
})
234+
}
235+
/>
236+
<span>Use dark theme (`useDarkTheme`)</span>
237+
</label>
238+
239+
<label className="toggle-row" htmlFor="useCustomFoldRenderer">
240+
<input
241+
id="useCustomFoldRenderer"
242+
type="checkbox"
243+
checked={value.useCustomFoldRenderer}
244+
onChange={(event) =>
245+
onChange({
246+
...value,
247+
useCustomFoldRenderer: event.target.checked,
248+
})
249+
}
250+
/>
251+
<span>Custom fold renderer (`codeFoldMessageRenderer`)</span>
252+
</label>
253+
254+
<label className="field-label" htmlFor="linesOffset">
255+
Line offset: {value.linesOffset}
256+
</label>
257+
<input
258+
id="linesOffset"
259+
className="field-range"
260+
type="range"
261+
min={0}
262+
max={200}
263+
step={1}
264+
value={value.linesOffset}
265+
onChange={(event) =>
266+
onChange({
267+
...value,
268+
linesOffset: Number(event.target.value),
269+
})
270+
}
271+
/>
272+
</div>
273+
85274
<button type="button" className="button button--primary button--block" onClick={onRunStressTest}>
86275
Run 100k stress test
87276
</button>

0 commit comments

Comments
 (0)