@bochenw/react-diff-viewer-continued 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.
- package/LICENSE +21 -0
- package/README.md +521 -0
- package/lib/cjs/src/comment-row.d.ts +33 -0
- package/lib/cjs/src/comment-row.js +58 -0
- package/lib/cjs/src/compute-hidden-blocks.d.ts +13 -0
- package/lib/cjs/src/compute-hidden-blocks.js +36 -0
- package/lib/cjs/src/compute-lines.d.ts +68 -0
- package/lib/cjs/src/compute-lines.js +559 -0
- package/lib/cjs/src/computeWorker.d.ts +1 -0
- package/lib/cjs/src/computeWorker.js +10 -0
- package/lib/cjs/src/diff-row.d.ts +40 -0
- package/lib/cjs/src/diff-row.js +136 -0
- package/lib/cjs/src/expand.d.ts +1 -0
- package/lib/cjs/src/expand.js +4 -0
- package/lib/cjs/src/fold.d.ts +1 -0
- package/lib/cjs/src/fold.js +4 -0
- package/lib/cjs/src/index.d.ts +236 -0
- package/lib/cjs/src/index.js +783 -0
- package/lib/cjs/src/line-number-prefix.d.ts +4 -0
- package/lib/cjs/src/line-number-prefix.js +5 -0
- package/lib/cjs/src/render-word-diff.d.ts +22 -0
- package/lib/cjs/src/render-word-diff.js +212 -0
- package/lib/cjs/src/skipped-line-indicator.d.ts +29 -0
- package/lib/cjs/src/skipped-line-indicator.js +29 -0
- package/lib/cjs/src/styles.d.ts +102 -0
- package/lib/cjs/src/styles.js +430 -0
- package/lib/cjs/src/workerBundle.d.ts +5 -0
- package/lib/cjs/src/workerBundle.js +7 -0
- package/lib/esm/src/comment-row.js +58 -0
- package/lib/esm/src/compute-hidden-blocks.js +36 -0
- package/lib/esm/src/compute-lines.js +559 -0
- package/lib/esm/src/computeWorker.js +10 -0
- package/lib/esm/src/diff-row.js +136 -0
- package/lib/esm/src/expand.js +4 -0
- package/lib/esm/src/fold.js +4 -0
- package/lib/esm/src/index.js +780 -0
- package/lib/esm/src/line-number-prefix.js +5 -0
- package/lib/esm/src/render-word-diff.js +211 -0
- package/lib/esm/src/skipped-line-indicator.js +29 -0
- package/lib/esm/src/styles.js +431 -0
- package/lib/esm/src/workerBundle.js +7 -0
- package/package.json +90 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2023 Bart Riepe
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,521 @@
|
|
|
1
|
+
<img src='https://github.com/Aeolun/react-diff-viewer-continued/raw/main/logo_dark.png' width="100%" alt='React Diff Viewer' />
|
|
2
|
+
|
|
3
|
+
<br/>
|
|
4
|
+
|
|
5
|
+
<!-- ALL-CONTRIBUTORS-BADGE:START - Do not remove or modify this section -->
|
|
6
|
+
[](#contributors-)
|
|
7
|
+
<!-- ALL-CONTRIBUTORS-BADGE:END -->
|
|
8
|
+
|
|
9
|
+
[](https://www.npmjs.com/package/react-diff-viewer-continued)
|
|
10
|
+
[](https://www.npmjs.com/package/react-diff-viewer-continued)
|
|
11
|
+
[](https://github.com/aeolun/react-diff-viewer-continued/blob/main/LICENSE)
|
|
12
|
+
|
|
13
|
+
A simple and beautiful text diff viewer component made with [Diff](https://github.com/kpdecker/jsdiff) and [React](https://reactjs.org).
|
|
14
|
+
|
|
15
|
+

|
|
16
|
+
|
|
17
|
+
Inspired by the Github diff viewer, it includes features like split view, inline view, word diff, line highlight and more. It is highly customizable and it supports almost all languages.
|
|
18
|
+
|
|
19
|
+
Most credit goes to [Pranesh Ravi](https://praneshravi.in) who created the [original diff viewer](https://github.com/praneshr/react-diff-viewer). I've just made a few modifications and updated the dependencies so they work with modern stacks.
|
|
20
|
+
|
|
21
|
+
## Install
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
yarn add react-diff-viewer-continued
|
|
25
|
+
|
|
26
|
+
# or
|
|
27
|
+
|
|
28
|
+
npm i react-diff-viewer-continued
|
|
29
|
+
|
|
30
|
+
# or
|
|
31
|
+
|
|
32
|
+
pnpm add react-diff-viewer-continued
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## Usage
|
|
36
|
+
|
|
37
|
+
```javascript
|
|
38
|
+
import React, { PureComponent } from 'react';
|
|
39
|
+
import ReactDiffViewer from 'react-diff-viewer-continued';
|
|
40
|
+
|
|
41
|
+
const oldCode = `
|
|
42
|
+
const a = 10
|
|
43
|
+
const b = 10
|
|
44
|
+
const c = () => console.log('foo')
|
|
45
|
+
|
|
46
|
+
if(a > 10) {
|
|
47
|
+
console.log('bar')
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
console.log('done')
|
|
51
|
+
`;
|
|
52
|
+
const newCode = `
|
|
53
|
+
const a = 10
|
|
54
|
+
const boo = 10
|
|
55
|
+
|
|
56
|
+
if(a === 10) {
|
|
57
|
+
console.log('bar')
|
|
58
|
+
}
|
|
59
|
+
`;
|
|
60
|
+
|
|
61
|
+
class Diff extends PureComponent {
|
|
62
|
+
render = () => {
|
|
63
|
+
return (
|
|
64
|
+
<ReactDiffViewer oldValue={oldCode} newValue={newCode} splitView={true} />
|
|
65
|
+
);
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
## Props
|
|
71
|
+
|
|
72
|
+
| Prop | Type | Default | Description |
|
|
73
|
+
|---------------------------|---------------------------|--------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
|
74
|
+
| oldValue | `string \| Object` | `''` | Old value as string (or Object if using `DiffMethod.JSON`). |
|
|
75
|
+
| newValue | `string \| Object` | `''` | New value as string (or Object if using `DiffMethod.JSON`). |
|
|
76
|
+
| splitView | `boolean` | `true` | Switch between `unified` and `split` view. |
|
|
77
|
+
| disableWordDiff | `boolean` | `false` | Show and hide word diff in a diff line. |
|
|
78
|
+
| compareMethod | `DiffMethod \| (string, string) => diff.Change[]` | `DiffMethod.CHARS` | JsDiff text diff method. See [Text block diff comparison](#text-block-diff-comparison). **Important:** For JSON files use `DiffMethod.JSON`, for YAML files use `DiffMethod.YAML` - these use optimized structural comparison that is significantly faster than generic text diff for large files. |
|
|
79
|
+
| renderGutter | `(diffData) => ReactNode` | `undefined` | Function that can be used to render an extra gutter with various information next to the line number. |
|
|
80
|
+
| hideLineNumbers | `boolean` | `false` | Show and hide line numbers. |
|
|
81
|
+
| alwaysShowLines | `string[]` | `[]` | List of lines to always be shown, regardless of diff status. Line numbers are prefixed with `L` and `R` for the left and right section of the diff viewer, respectively. For example, `L-20` means 20th line in the left pane. `extraLinesSurroundingDiff` applies to these lines as well. |
|
|
82
|
+
| renderContent | `function` | `undefined` | Render Prop API to render code in the diff viewer. Helpful for [syntax highlighting](#syntax-highlighting). |
|
|
83
|
+
| onLineNumberClick | `function` | `undefined` | Event handler for line number click. `(lineId: string, event: MouseEvent) => void` |
|
|
84
|
+
| highlightLines | `string[]` | `[]` | List of lines to be highlighted. Works together with `onLineNumberClick`. Line numbers are prefixed with `L` and `R` for the left and right section of the diff viewer, respectively. For example, `L-20` means 20th line in the left pane. To highlight a range of line numbers, pass the prefixed line number as an array. For example, `[L-2, L-3, L-4, L-5]` will highlight the lines `2-5` in the left pane. |
|
|
85
|
+
| showDiffOnly | `boolean` | `true` | Shows only the diffed lines and folds the unchanged lines. |
|
|
86
|
+
| extraLinesSurroundingDiff | `number` | `3` | Number of extra unchanged lines surrounding the diff. Works along with `showDiffOnly`. |
|
|
87
|
+
| codeFoldMessageRenderer | `function` | `undefined` | Render Prop API to render code fold message. `(totalFoldedLines: number, leftStartLineNumber: number, rightStartLineNumber: number) => ReactElement` |
|
|
88
|
+
| styles | `object` | `{}` | To override style variables and styles. Learn more about [overriding styles](#overriding-styles). |
|
|
89
|
+
| useDarkTheme | `boolean` | `false` | To enable/disable dark theme. |
|
|
90
|
+
| leftTitle | `string \| ReactElement` | `undefined` | Column title for left section of the diff in split view. This will be used as the only title in inline view. |
|
|
91
|
+
| rightTitle | `string \| ReactElement` | `undefined` | Column title for right section of the diff in split view. This will be ignored in inline view. |
|
|
92
|
+
| linesOffset | `number` | `0` | Number to start count code lines from. |
|
|
93
|
+
| summary | `string \| ReactElement` | `undefined` | Text or element to display in the summary bar (e.g., filename). |
|
|
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. |
|
|
97
|
+
| nonce | `string` | `''` | Nonce to use for inline styles (for CSP). |
|
|
98
|
+
|
|
99
|
+
## Instance Methods
|
|
100
|
+
|
|
101
|
+
`resetCodeBlocks()` - Resets the expanded code blocks to its initial state. Returns `true` on successful reset and `false` during unsuccessful reset.
|
|
102
|
+
|
|
103
|
+
## Large Diffs and Performance
|
|
104
|
+
|
|
105
|
+
For large files (thousands of lines), the diff viewer provides several features to maintain good performance:
|
|
106
|
+
|
|
107
|
+
### Virtualization with infiniteLoading
|
|
108
|
+
|
|
109
|
+
Enable virtualization to only render visible rows:
|
|
110
|
+
|
|
111
|
+
```javascript
|
|
112
|
+
<ReactDiffViewer
|
|
113
|
+
oldValue={largeOldFile}
|
|
114
|
+
newValue={largeNewFile}
|
|
115
|
+
infiniteLoading={{
|
|
116
|
+
pageSize: 20,
|
|
117
|
+
containerHeight: '80vh'
|
|
118
|
+
}}
|
|
119
|
+
loadingElement={() => (
|
|
120
|
+
<div style={{ padding: '20px', textAlign: 'center' }}>
|
|
121
|
+
Computing diff...
|
|
122
|
+
</div>
|
|
123
|
+
)}
|
|
124
|
+
/>
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
When `infiniteLoading` is enabled:
|
|
128
|
+
- Only visible rows are rendered (virtualization)
|
|
129
|
+
- Word-level diffs are computed on-demand as lines become visible
|
|
130
|
+
- A loading element can be shown while the initial diff is computed
|
|
131
|
+
|
|
132
|
+
### Use optimized diff methods for structured data
|
|
133
|
+
|
|
134
|
+
For JSON and YAML files, always use the dedicated diff methods:
|
|
135
|
+
|
|
136
|
+
```javascript
|
|
137
|
+
// For JSON files - up to 100x faster for large files
|
|
138
|
+
<ReactDiffViewer
|
|
139
|
+
oldValue={jsonObject}
|
|
140
|
+
newValue={newJsonObject}
|
|
141
|
+
compareMethod={DiffMethod.JSON}
|
|
142
|
+
/>
|
|
143
|
+
|
|
144
|
+
// For YAML files
|
|
145
|
+
<ReactDiffViewer
|
|
146
|
+
oldValue={yamlString}
|
|
147
|
+
newValue={newYamlString}
|
|
148
|
+
compareMethod={DiffMethod.YAML}
|
|
149
|
+
/>
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
See [JSON and YAML diffing](#json-and-yaml-diffing) for more details.
|
|
153
|
+
|
|
154
|
+
## Syntax Highlighting
|
|
155
|
+
|
|
156
|
+
Syntax highlighting is a bit tricky when combined with diff. Here, React Diff Viewer provides a simple render prop API to handle syntax highlighting. Use `renderContent(content: string) => JSX.Element` and your favorite syntax highlighting library to achieve this.
|
|
157
|
+
|
|
158
|
+
An example using [Prism JS](https://prismjs.com)
|
|
159
|
+
|
|
160
|
+
```html
|
|
161
|
+
// Load Prism CSS
|
|
162
|
+
<link
|
|
163
|
+
href="https://cdnjs.cloudflare.com/ajax/libs/prism/1.15.0/prism.min.css"
|
|
164
|
+
/>
|
|
165
|
+
|
|
166
|
+
// Load Prism JS
|
|
167
|
+
<script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.15.0/prism.min.js"></script>
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
```javascript
|
|
171
|
+
import React, { PureComponent } from 'react';
|
|
172
|
+
import ReactDiffViewer from 'react-diff-viewer-continued';
|
|
173
|
+
|
|
174
|
+
const oldCode = `
|
|
175
|
+
const a = 10
|
|
176
|
+
const b = 10
|
|
177
|
+
const c = () => console.log('foo')
|
|
178
|
+
|
|
179
|
+
if(a > 10) {
|
|
180
|
+
console.log('bar')
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
console.log('done')
|
|
184
|
+
`;
|
|
185
|
+
const newCode = `
|
|
186
|
+
const a = 10
|
|
187
|
+
const boo = 10
|
|
188
|
+
|
|
189
|
+
if(a === 10) {
|
|
190
|
+
console.log('bar')
|
|
191
|
+
}
|
|
192
|
+
`;
|
|
193
|
+
|
|
194
|
+
class Diff extends PureComponent {
|
|
195
|
+
highlightSyntax = (str) => (
|
|
196
|
+
<pre
|
|
197
|
+
style={{ display: 'inline' }}
|
|
198
|
+
dangerouslySetInnerHTML={{
|
|
199
|
+
__html: Prism.highlight(str, Prism.languages.javascript),
|
|
200
|
+
}}
|
|
201
|
+
/>
|
|
202
|
+
);
|
|
203
|
+
|
|
204
|
+
render = () => {
|
|
205
|
+
return (
|
|
206
|
+
<ReactDiffViewer
|
|
207
|
+
oldValue={oldCode}
|
|
208
|
+
newValue={newCode}
|
|
209
|
+
splitView={true}
|
|
210
|
+
renderContent={this.highlightSyntax}
|
|
211
|
+
/>
|
|
212
|
+
);
|
|
213
|
+
};
|
|
214
|
+
}
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
## Text block diff comparison
|
|
218
|
+
|
|
219
|
+
Different styles of text block diffing are possible by using the enums corresponding to various JsDiff methods ([learn more](https://github.com/kpdecker/jsdiff/tree/v4.0.1#api)). The supported methods are as follows.
|
|
220
|
+
|
|
221
|
+
```javascript
|
|
222
|
+
enum DiffMethod {
|
|
223
|
+
CHARS = 'diffChars',
|
|
224
|
+
WORDS = 'diffWords',
|
|
225
|
+
WORDS_WITH_SPACE = 'diffWordsWithSpace',
|
|
226
|
+
LINES = 'diffLines',
|
|
227
|
+
TRIMMED_LINES = 'diffTrimmedLines',
|
|
228
|
+
SENTENCES = 'diffSentences',
|
|
229
|
+
CSS = 'diffCss',
|
|
230
|
+
JSON = 'diffJson', // Optimized for JSON files
|
|
231
|
+
YAML = 'diffYaml', // Optimized for YAML files
|
|
232
|
+
}
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
### JSON and YAML diffing
|
|
236
|
+
|
|
237
|
+
For JSON and YAML files, use the dedicated `DiffMethod.JSON` and `DiffMethod.YAML` methods. These use an optimized structural comparison algorithm that is **significantly faster** than generic text diff for large files.
|
|
238
|
+
|
|
239
|
+
**Why use these methods?**
|
|
240
|
+
|
|
241
|
+
Generic text diff algorithms (like `CHARS` or `WORDS`) compare files character-by-character using the Myers diff algorithm, which has O(ND) complexity where N is the file size and D is the number of differences. For large JSON/YAML files (thousands of lines), this can take several seconds or even freeze the browser.
|
|
242
|
+
|
|
243
|
+
The `JSON` and `YAML` methods instead:
|
|
244
|
+
1. Parse the data structure
|
|
245
|
+
2. Compare objects/arrays structurally
|
|
246
|
+
3. Only run text diff on the parts that actually differ
|
|
247
|
+
|
|
248
|
+
This reduces comparison time from seconds to milliseconds for typical configuration files.
|
|
249
|
+
|
|
250
|
+
```javascript
|
|
251
|
+
import React from 'react';
|
|
252
|
+
import ReactDiffViewer, { DiffMethod } from 'react-diff-viewer-continued';
|
|
253
|
+
|
|
254
|
+
// For JSON - can pass objects directly
|
|
255
|
+
const oldJson = { name: "Original", items: [1, 2, 3] };
|
|
256
|
+
const newJson = { name: "Updated", items: [1, 2, 3, 4] };
|
|
257
|
+
|
|
258
|
+
// For YAML - pass as strings
|
|
259
|
+
const oldYaml = `
|
|
260
|
+
name: Original
|
|
261
|
+
items:
|
|
262
|
+
- 1
|
|
263
|
+
- 2
|
|
264
|
+
`;
|
|
265
|
+
const newYaml = `
|
|
266
|
+
name: Updated
|
|
267
|
+
items:
|
|
268
|
+
- 1
|
|
269
|
+
- 2
|
|
270
|
+
- 3
|
|
271
|
+
`;
|
|
272
|
+
|
|
273
|
+
function JsonDiff() {
|
|
274
|
+
return (
|
|
275
|
+
<ReactDiffViewer
|
|
276
|
+
oldValue={oldJson}
|
|
277
|
+
newValue={newJson}
|
|
278
|
+
compareMethod={DiffMethod.JSON}
|
|
279
|
+
splitView={true}
|
|
280
|
+
/>
|
|
281
|
+
);
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
function YamlDiff() {
|
|
285
|
+
return (
|
|
286
|
+
<ReactDiffViewer
|
|
287
|
+
oldValue={oldYaml}
|
|
288
|
+
newValue={newYaml}
|
|
289
|
+
compareMethod={DiffMethod.YAML}
|
|
290
|
+
splitView={true}
|
|
291
|
+
/>
|
|
292
|
+
);
|
|
293
|
+
}
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
### Other diff methods
|
|
297
|
+
|
|
298
|
+
For regular code or text files, use the standard diff methods:
|
|
299
|
+
|
|
300
|
+
```javascript
|
|
301
|
+
import React, { PureComponent } from 'react';
|
|
302
|
+
import ReactDiffViewer, { DiffMethod } from 'react-diff-viewer-continued';
|
|
303
|
+
|
|
304
|
+
const oldCode = `
|
|
305
|
+
const a = 10
|
|
306
|
+
const b = 10
|
|
307
|
+
`;
|
|
308
|
+
const newCode = `
|
|
309
|
+
const a = 10
|
|
310
|
+
const boo = 10
|
|
311
|
+
`;
|
|
312
|
+
|
|
313
|
+
class Diff extends PureComponent {
|
|
314
|
+
render = () => {
|
|
315
|
+
return (
|
|
316
|
+
<ReactDiffViewer
|
|
317
|
+
oldValue={oldCode}
|
|
318
|
+
newValue={newCode}
|
|
319
|
+
compareMethod={DiffMethod.WORDS}
|
|
320
|
+
splitView={true}
|
|
321
|
+
/>
|
|
322
|
+
);
|
|
323
|
+
};
|
|
324
|
+
}
|
|
325
|
+
```
|
|
326
|
+
|
|
327
|
+
## Overriding Styles
|
|
328
|
+
|
|
329
|
+
React Diff Viewer uses [emotion](https://emotion.sh/) for styling. It also offers a simple way to override styles and style variables. You can supply different variables for both light and dark themes. Styles will be common for both themes.
|
|
330
|
+
|
|
331
|
+
Below are the default style variables and style object keys.
|
|
332
|
+
|
|
333
|
+
```javascript
|
|
334
|
+
|
|
335
|
+
// Default variables and style keys
|
|
336
|
+
|
|
337
|
+
const defaultStyles = {
|
|
338
|
+
variables: {
|
|
339
|
+
light: {
|
|
340
|
+
diffViewerBackground: '#fff',
|
|
341
|
+
diffViewerColor: '#212529',
|
|
342
|
+
addedBackground: '#e6ffed',
|
|
343
|
+
addedColor: '#24292e',
|
|
344
|
+
removedBackground: '#ffeef0',
|
|
345
|
+
removedColor: '#24292e',
|
|
346
|
+
wordAddedBackground: '#acf2bd',
|
|
347
|
+
wordRemovedBackground: '#fdb8c0',
|
|
348
|
+
addedGutterBackground: '#cdffd8',
|
|
349
|
+
removedGutterBackground: '#ffdce0',
|
|
350
|
+
gutterBackground: '#f7f7f7',
|
|
351
|
+
gutterBackgroundDark: '#f3f1f1',
|
|
352
|
+
highlightBackground: '#fffbdd',
|
|
353
|
+
highlightGutterBackground: '#fff5b1',
|
|
354
|
+
codeFoldGutterBackground: '#dbedff',
|
|
355
|
+
codeFoldBackground: '#f1f8ff',
|
|
356
|
+
emptyLineBackground: '#fafbfc',
|
|
357
|
+
gutterColor: '#212529',
|
|
358
|
+
addedGutterColor: '#212529',
|
|
359
|
+
removedGutterColor: '#212529',
|
|
360
|
+
codeFoldContentColor: '#212529',
|
|
361
|
+
diffViewerTitleBackground: '#fafbfc',
|
|
362
|
+
diffViewerTitleColor: '#212529',
|
|
363
|
+
diffViewerTitleBorderColor: '#eee',
|
|
364
|
+
},
|
|
365
|
+
dark: {
|
|
366
|
+
diffViewerBackground: '#2e303c',
|
|
367
|
+
diffViewerColor: '#FFF',
|
|
368
|
+
addedBackground: '#044B53',
|
|
369
|
+
addedColor: 'white',
|
|
370
|
+
removedBackground: '#632F34',
|
|
371
|
+
removedColor: 'white',
|
|
372
|
+
wordAddedBackground: '#055d67',
|
|
373
|
+
wordRemovedBackground: '#7d383f',
|
|
374
|
+
addedGutterBackground: '#034148',
|
|
375
|
+
removedGutterBackground: '#632b30',
|
|
376
|
+
gutterBackground: '#2c2f3a',
|
|
377
|
+
gutterBackgroundDark: '#262933',
|
|
378
|
+
highlightBackground: '#2a3967',
|
|
379
|
+
highlightGutterBackground: '#2d4077',
|
|
380
|
+
codeFoldGutterBackground: '#21232b',
|
|
381
|
+
codeFoldBackground: '#262831',
|
|
382
|
+
emptyLineBackground: '#363946',
|
|
383
|
+
gutterColor: '#464c67',
|
|
384
|
+
addedGutterColor: '#8c8c8c',
|
|
385
|
+
removedGutterColor: '#8c8c8c',
|
|
386
|
+
codeFoldContentColor: '#555a7b',
|
|
387
|
+
diffViewerTitleBackground: '#2f323e',
|
|
388
|
+
diffViewerTitleColor: '#555a7b',
|
|
389
|
+
diffViewerTitleBorderColor: '#353846',
|
|
390
|
+
}
|
|
391
|
+
},
|
|
392
|
+
diffContainer?: {}, // style object
|
|
393
|
+
diffRemoved?: {}, // style object
|
|
394
|
+
diffAdded?: {}, // style object
|
|
395
|
+
marker?: {}, // style object
|
|
396
|
+
emptyGutter?: {}, // style object
|
|
397
|
+
highlightedLine?: {}, // style object
|
|
398
|
+
lineNumber?: {}, // style object
|
|
399
|
+
highlightedGutter?: {}, // style object
|
|
400
|
+
contentText?: {}, // style object
|
|
401
|
+
gutter?: {}, // style object
|
|
402
|
+
line?: {}, // style object
|
|
403
|
+
wordDiff?: {}, // style object
|
|
404
|
+
wordAdded?: {}, // style object
|
|
405
|
+
wordRemoved?: {}, // style object
|
|
406
|
+
codeFoldGutter?: {}, // style object
|
|
407
|
+
codeFold?: {}, // style object
|
|
408
|
+
emptyLine?: {}, // style object
|
|
409
|
+
content?: {}, // style object
|
|
410
|
+
titleBlock?: {}, // style object
|
|
411
|
+
splitView?: {}, // style object
|
|
412
|
+
}
|
|
413
|
+
```
|
|
414
|
+
|
|
415
|
+
To override any style, just pass the new style object to the `styles` prop. New style will be computed using `Object.assign(default, override)`.
|
|
416
|
+
|
|
417
|
+
For keys other than `variables`, the value can either be an object or string interpolation.
|
|
418
|
+
|
|
419
|
+
```javascript
|
|
420
|
+
import React, { PureComponent } from 'react';
|
|
421
|
+
import ReactDiffViewer from 'react-diff-viewer-continued';
|
|
422
|
+
|
|
423
|
+
const oldCode = `
|
|
424
|
+
const a = 10
|
|
425
|
+
const b = 10
|
|
426
|
+
const c = () => console.log('foo')
|
|
427
|
+
|
|
428
|
+
if(a > 10) {
|
|
429
|
+
console.log('bar')
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
console.log('done')
|
|
433
|
+
`;
|
|
434
|
+
const newCode = `
|
|
435
|
+
const a = 10
|
|
436
|
+
const boo = 10
|
|
437
|
+
|
|
438
|
+
if(a === 10) {
|
|
439
|
+
console.log('bar')
|
|
440
|
+
}
|
|
441
|
+
`;
|
|
442
|
+
|
|
443
|
+
class Diff extends PureComponent {
|
|
444
|
+
highlightSyntax = (str) => (
|
|
445
|
+
<span
|
|
446
|
+
style={{ display: 'inline' }}
|
|
447
|
+
dangerouslySetInnerHTML={{
|
|
448
|
+
__html: Prism.highlight(str, Prism.languages.javascript),
|
|
449
|
+
}}
|
|
450
|
+
/>
|
|
451
|
+
);
|
|
452
|
+
|
|
453
|
+
render = () => {
|
|
454
|
+
const newStyles = {
|
|
455
|
+
variables: {
|
|
456
|
+
dark: {
|
|
457
|
+
highlightBackground: '#fefed5',
|
|
458
|
+
highlightGutterBackground: '#ffcd3c',
|
|
459
|
+
},
|
|
460
|
+
},
|
|
461
|
+
line: {
|
|
462
|
+
padding: '10px 2px',
|
|
463
|
+
'&:hover': {
|
|
464
|
+
background: '#a26ea1',
|
|
465
|
+
},
|
|
466
|
+
},
|
|
467
|
+
};
|
|
468
|
+
|
|
469
|
+
return (
|
|
470
|
+
<ReactDiffViewer
|
|
471
|
+
styles={newStyles}
|
|
472
|
+
oldValue={oldCode}
|
|
473
|
+
newValue={newCode}
|
|
474
|
+
splitView={true}
|
|
475
|
+
renderContent={this.highlightSyntax}
|
|
476
|
+
/>
|
|
477
|
+
);
|
|
478
|
+
};
|
|
479
|
+
}
|
|
480
|
+
```
|
|
481
|
+
|
|
482
|
+
## Local Development
|
|
483
|
+
|
|
484
|
+
```bash
|
|
485
|
+
pnpm install
|
|
486
|
+
pnpm build # or use yarn build:watch
|
|
487
|
+
pnpm start:examples
|
|
488
|
+
```
|
|
489
|
+
|
|
490
|
+
Check package.json for more build scripts.
|
|
491
|
+
|
|
492
|
+
## Contributors
|
|
493
|
+
|
|
494
|
+
<!-- ALL-CONTRIBUTORS-LIST:START - Do not remove or modify this section -->
|
|
495
|
+
<!-- prettier-ignore-start -->
|
|
496
|
+
<!-- markdownlint-disable -->
|
|
497
|
+
<table>
|
|
498
|
+
<tbody>
|
|
499
|
+
<tr>
|
|
500
|
+
<td align="center" valign="top" width="14.28%"><a href="https://github.com/ericmorgan1"><img src="https://avatars.githubusercontent.com/u/10346191?v=4?s=100" width="100px;" alt="Eric M."/><br /><sub><b>Eric M.</b></sub></a><br /><a href="https://github.com/Aeolun/react-diff-viewer-continued/commits?author=ericmorgan1" title="Code">💻</a></td>
|
|
501
|
+
<td align="center" valign="top" width="14.28%"><a href="https://github.com/spyroid"><img src="https://avatars.githubusercontent.com/u/844495?v=4?s=100" width="100px;" alt="Andrei Kovalevsky"/><br /><sub><b>Andrei Kovalevsky</b></sub></a><br /><a href="https://github.com/Aeolun/react-diff-viewer-continued/commits?author=spyroid" title="Code">💻</a></td>
|
|
502
|
+
<td align="center" valign="top" width="14.28%"><a href="http://kimbiyam.me"><img src="https://avatars.githubusercontent.com/u/59679962?v=4?s=100" width="100px;" alt="Chang Hyun Kim"/><br /><sub><b>Chang Hyun Kim</b></sub></a><br /><a href="https://github.com/Aeolun/react-diff-viewer-continued/commits?author=KimBiYam" title="Code">💻</a></td>
|
|
503
|
+
</tr>
|
|
504
|
+
</tbody>
|
|
505
|
+
</table>
|
|
506
|
+
|
|
507
|
+
<!-- markdownlint-restore -->
|
|
508
|
+
<!-- prettier-ignore-end -->
|
|
509
|
+
|
|
510
|
+
<!-- ALL-CONTRIBUTORS-LIST:END -->
|
|
511
|
+
<!-- prettier-ignore-start -->
|
|
512
|
+
<!-- markdownlint-disable -->
|
|
513
|
+
|
|
514
|
+
<!-- markdownlint-restore -->
|
|
515
|
+
<!-- prettier-ignore-end -->
|
|
516
|
+
|
|
517
|
+
<!-- ALL-CONTRIBUTORS-LIST:END -->
|
|
518
|
+
|
|
519
|
+
## License
|
|
520
|
+
|
|
521
|
+
MIT
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import type { ReactElement } from "react";
|
|
3
|
+
import { LineNumberPrefix } from "./line-number-prefix.js";
|
|
4
|
+
import type { ReactDiffViewerStyles } from "./styles.js";
|
|
5
|
+
/**
|
|
6
|
+
* Data passed to the renderComment render prop so consumers know
|
|
7
|
+
* the context of the line they are rendering a comment for.
|
|
8
|
+
*/
|
|
9
|
+
export interface CommentRenderData {
|
|
10
|
+
lineId: string;
|
|
11
|
+
lineNumber: number;
|
|
12
|
+
prefix: LineNumberPrefix;
|
|
13
|
+
side: "left" | "right";
|
|
14
|
+
splitView: boolean;
|
|
15
|
+
styles: ReactDiffViewerStyles;
|
|
16
|
+
}
|
|
17
|
+
export interface CommentRowProps {
|
|
18
|
+
lineId: string;
|
|
19
|
+
lineNumber: number;
|
|
20
|
+
prefix: LineNumberPrefix;
|
|
21
|
+
splitView: boolean;
|
|
22
|
+
hideLineNumbers: boolean;
|
|
23
|
+
hasRenderGutter: boolean;
|
|
24
|
+
styles: ReactDiffViewerStyles;
|
|
25
|
+
renderComment: (data: CommentRenderData) => ReactElement | null;
|
|
26
|
+
trRef?: (el: HTMLTableRowElement | null) => void;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Memoized component that renders a comment row below a diff line.
|
|
30
|
+
* Renders a full-width <tr> with a single <td> spanning all columns.
|
|
31
|
+
* The consumer's renderComment provides the actual comment UI.
|
|
32
|
+
*/
|
|
33
|
+
export declare const CommentRow: React.NamedExoticComponent<CommentRowProps>;
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import * as React from "react";
|
|
3
|
+
import { LineNumberPrefix } from "./line-number-prefix.js";
|
|
4
|
+
/**
|
|
5
|
+
* Custom equality function for React.memo — compares data props and renderComment reference.
|
|
6
|
+
* Skips trRef since it's a stable cached callback.
|
|
7
|
+
*/
|
|
8
|
+
function commentRowPropsAreEqual(prev, next) {
|
|
9
|
+
return (prev.lineId === next.lineId &&
|
|
10
|
+
prev.lineNumber === next.lineNumber &&
|
|
11
|
+
prev.prefix === next.prefix &&
|
|
12
|
+
prev.splitView === next.splitView &&
|
|
13
|
+
prev.hideLineNumbers === next.hideLineNumbers &&
|
|
14
|
+
prev.hasRenderGutter === next.hasRenderGutter &&
|
|
15
|
+
prev.styles === next.styles &&
|
|
16
|
+
prev.renderComment === next.renderComment);
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Calculates the total number of columns for the comment cell's colSpan.
|
|
20
|
+
*/
|
|
21
|
+
function getColSpan(splitView, hideLineNumbers, hasRenderGutter) {
|
|
22
|
+
if (splitView) {
|
|
23
|
+
// Split: [gutter?] [renderGutter?] [marker] [content] | [gutter?] [renderGutter?] [marker] [content]
|
|
24
|
+
let span = 4; // marker + content on each side
|
|
25
|
+
if (!hideLineNumbers)
|
|
26
|
+
span += 2; // gutter on each side
|
|
27
|
+
if (hasRenderGutter)
|
|
28
|
+
span += 2; // renderGutter on each side
|
|
29
|
+
return span;
|
|
30
|
+
}
|
|
31
|
+
// Unified: [gutter?] [gutter?] [renderGutter?] [marker] [content]
|
|
32
|
+
let span = 2; // marker + content
|
|
33
|
+
if (!hideLineNumbers)
|
|
34
|
+
span += 2; // two gutter columns
|
|
35
|
+
if (hasRenderGutter)
|
|
36
|
+
span += 1;
|
|
37
|
+
return span;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Memoized component that renders a comment row below a diff line.
|
|
41
|
+
* Renders a full-width <tr> with a single <td> spanning all columns.
|
|
42
|
+
* The consumer's renderComment provides the actual comment UI.
|
|
43
|
+
*/
|
|
44
|
+
export const CommentRow = React.memo(function CommentRow({ lineId, lineNumber, prefix, splitView, hideLineNumbers, hasRenderGutter, styles, renderComment, trRef, }) {
|
|
45
|
+
const colSpan = getColSpan(splitView, hideLineNumbers, hasRenderGutter);
|
|
46
|
+
const side = prefix === LineNumberPrefix.LEFT ? "left" : "right";
|
|
47
|
+
const content = renderComment({
|
|
48
|
+
lineId,
|
|
49
|
+
lineNumber,
|
|
50
|
+
prefix,
|
|
51
|
+
side,
|
|
52
|
+
splitView,
|
|
53
|
+
styles,
|
|
54
|
+
});
|
|
55
|
+
if (content === null)
|
|
56
|
+
return null;
|
|
57
|
+
return (_jsx("tr", { ref: trRef, className: styles.commentRow, "data-comment-line": lineId, children: _jsx("td", { colSpan: colSpan, className: styles.commentCell, children: content }) }));
|
|
58
|
+
}, commentRowPropsAreEqual);
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { type LineInformation } from "./compute-lines.js";
|
|
2
|
+
export interface Block {
|
|
3
|
+
index: number;
|
|
4
|
+
startLine: number;
|
|
5
|
+
endLine: number;
|
|
6
|
+
lines: number;
|
|
7
|
+
}
|
|
8
|
+
interface HiddenBlocks {
|
|
9
|
+
lineBlocks: Record<number, number>;
|
|
10
|
+
blocks: Block[];
|
|
11
|
+
}
|
|
12
|
+
export declare function computeHiddenBlocks(lineInformation: LineInformation[], diffLines: number[], extraLines: number): HiddenBlocks;
|
|
13
|
+
export {};
|