Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 347afdd

Browse files
feat!: new grid viewer created to have more flexibility
We were using table elements based on json diff kit's viewer. However for virtual list of this kind, grid based structure is way more better both for style and dom manipulation
1 parent deca570 commit 347afdd

File tree

5 files changed

+302
-97
lines changed

5 files changed

+302
-97
lines changed
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
// VirtualDiffGrid.tsx
2+
import type { InlineDiffOptions } from "json-diff-kit";
3+
import type { Dispatch } from "react";
4+
import type { ListOnScrollProps } from "react-window";
5+
6+
import React, { useCallback, useEffect, useMemo } from "react";
7+
import { VariableSizeList as List } from "react-window";
8+
9+
import type { DiffRowOrCollapsed } from "../types";
10+
11+
import { useRowHeights } from "../hooks/useRowHeights";
12+
import { COLLAPSED_ROW_HEIGHT, getRowHeightFromCSS, isCollapsed } from "../utils/constants";
13+
import RowRendererGrid from "../utils/json-diff/row-renderer-grid";
14+
15+
type VirtualDiffGridProps = {
16+
leftDiff: DiffRowOrCollapsed[];
17+
rightDiff: DiffRowOrCollapsed[];
18+
outerRef: React.RefObject<Node | null>;
19+
listRef: React.RefObject<List<any>>;
20+
height: number;
21+
inlineDiffOptions?: InlineDiffOptions;
22+
className?: string;
23+
setScrollTop: Dispatch<React.SetStateAction<number>>;
24+
onExpand: (segmentIndex: number) => void;
25+
};
26+
27+
const VirtualDiffGrid: React.FC<VirtualDiffGridProps> = ({
28+
leftDiff,
29+
rightDiff,
30+
outerRef,
31+
listRef,
32+
height,
33+
inlineDiffOptions,
34+
className,
35+
setScrollTop,
36+
onExpand,
37+
}) => {
38+
// Virtual List Data
39+
const listData = useMemo(
40+
() => ({
41+
leftDiff,
42+
rightDiff,
43+
onExpand,
44+
inlineDiffOptions,
45+
}),
46+
[leftDiff, rightDiff, onExpand, inlineDiffOptions],
47+
);
48+
49+
const classes = [
50+
"json-diff-viewer",
51+
`json-diff-viewer-theme-custom`,
52+
className,
53+
]
54+
.filter(Boolean)
55+
.join(" ");
56+
57+
// ROW HEIGHT CALCULATION
58+
const ROW_HEIGHT = useMemo(() => getRowHeightFromCSS(), []);
59+
const rowHeights = useRowHeights(leftDiff);
60+
const dynamicRowHeights = useCallback(
61+
(index: number) => {
62+
const leftLine = leftDiff[index];
63+
if (isCollapsed(leftLine))
64+
return COLLAPSED_ROW_HEIGHT;
65+
return (rowHeights[index] ?? 1) * ROW_HEIGHT;
66+
},
67+
[leftDiff, rowHeights],
68+
);
69+
70+
useEffect(() => {
71+
listRef.current?.resetAfterIndex(0, true);
72+
}, [rowHeights]);
73+
74+
return (
75+
<div className={classes}>
76+
<List
77+
height={height}
78+
width="100%"
79+
style={{ alignItems: "start" }}
80+
outerRef={outerRef}
81+
ref={listRef}
82+
className="virtual-json-diff-list-container"
83+
itemCount={Math.max(leftDiff.length, rightDiff.length)}
84+
itemSize={dynamicRowHeights}
85+
overscanCount={28}
86+
itemData={listData}
87+
onScroll={({ scrollOffset }: ListOnScrollProps) => setScrollTop(scrollOffset)}
88+
>
89+
{RowRendererGrid}
90+
</List>
91+
</div>
92+
);
93+
};
94+
95+
export default VirtualDiffGrid;

‎src/components/DiffViewer/components/VirtualizedDiffViewer.tsx‎

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import { expandSegment, hasExpandedSegments, hideAllSegments } from "../utils/js
1111
import { buildViewFromSegments, generateSegments } from "../utils/preprocessDiff";
1212
import { DiffMinimap } from "./DiffMinimap";
1313
import SearchboxHolder from "./SearchboxHolder";
14-
import VirtualDiffTable from "./VirtualDiffTable";
14+
import VirtualDiffGrid from "./VirtualDiffGrid";
1515

1616
export const VirtualizedDiffViewer: React.FC<VirtualizedDiffViewerProps> = ({
1717
oldValue,
@@ -115,8 +115,7 @@ export const VirtualizedDiffViewer: React.FC<VirtualizedDiffViewerProps> = ({
115115

116116
{/* List & Minimap */}
117117
<div style={{ display: "flex", gap: "8px", position: "relative" }}>
118-
119-
<VirtualDiffTable
118+
<VirtualDiffGrid
120119
outerRef={outerRef}
121120
listRef={listRef}
122121
leftDiff={leftView}

‎src/components/DiffViewer/styles/JsonDiffCustomTheme.css‎

Lines changed: 66 additions & 94 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,6 @@
1616
padding-bottom: 12px;
1717
}
1818

19-
.json-diff-viewer-virtual pre {
20-
overflow-x: auto;
21-
white-space: pre;
22-
}
23-
2419
.json-diff-viewer.json-diff-viewer-theme-custom {
2520
background: #282a36;
2621
color: #f8f8f2;
@@ -31,108 +26,40 @@
3126
"Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
3227
}
3328

34-
.json-diff-viewer.json-diff-viewer-theme-custom tr td {
35-
max-width: min-content;
36-
vertical-align: unset;
37-
padding: 0;
38-
}
39-
40-
.json-diff-viewer.json-diff-viewer-theme-custom tr td.line-number {
41-
color: #999;
42-
padding: 2px;
43-
padding-right: 6px;
44-
text-align: right;
45-
}
46-
47-
.json-diff-viewer.json-diff-viewer-theme-custom table {
48-
table-layout: fixed;
49-
width: 100%;
50-
}
51-
52-
.json-diff-viewer.json-diff-viewer-theme-custom tr td:nth-child(1),
53-
.json-diff-viewer.json-diff-viewer-theme-custom tr td:nth-child(3) {
54-
width: 30px !important;
55-
min-width: 30px;
56-
max-width: 30px;
57-
overflow: hidden;
58-
text-overflow: ellipsis;
59-
}
60-
61-
.json-diff-viewer.json-diff-viewer-theme-custom tr td:nth-child(2),
62-
.json-diff-viewer.json-diff-viewer-theme-custom tr td:nth-child(4) {
63-
width: auto;
64-
width: 50%;
65-
overflow-wrap: anywhere;
66-
}
67-
68-
.json-diff-viewer.json-diff-viewer-theme-custom tr td pre {
69-
font-family:
70-
-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif,
71-
"Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
72-
overflow: hidden;
73-
margin: 0;
74-
padding-left: 4px;
75-
margin-right: 29px;
76-
font-size: 12px;
77-
min-width: 300px;
78-
line-height: var(--diff-row-height);
79-
white-space: pre-wrap;
80-
word-break: break-all;
81-
}
82-
8329
/* ADD REMOVE MODIFY COLORS */
84-
.json-diff-viewer.json-diff-viewer-theme-custom tr.line-add {
30+
.json-diff-viewer.json-diff-viewer-theme-custom .line-add {
8531
border-left: 1px solid #a5ff99;
8632
background: rgba(100, 182, 67, 0.08);
8733
}
8834

89-
.json-diff-viewer.json-diff-viewer-theme-custom tr.line-remove {
35+
.json-diff-viewer.json-diff-viewer-theme-custom .line-remove {
9036
border-left: 1px solid #ffaa99;
9137
background: rgba(160, 128, 100, 0.08);
9238
}
9339

94-
.json-diff-viewer.json-diff-viewer-theme-custom tr.line-modify {
40+
.json-diff-viewer.json-diff-viewer-theme-custom .line-modify {
9541
border-left: 1px solid #ecff99;
9642
background: rgba(182, 180, 67, 0.08);
9743
}
9844

99-
.json-diff-viewer.json-diff-viewer-theme-custom tr.empty-equal-cell {
45+
.json-diff-viewer.json-diff-viewer-theme-custom .empty-equal-cell {
10046
opacity: 0.4;
10147
background: repeating-linear-gradient(-53deg, rgb(69, 69, 70), rgb(69, 69, 70) 1.5px, #282a36 1.5px, #282a36 4px);
10248
background-attachment: fixed;
10349
}
10450

105-
.json-diff-viewer.json-diff-viewer-theme-custom tr .line-number {
106-
background: unset;
107-
padding: 0 4px;
108-
border-left: 0;
109-
border-bottom: none;
110-
}
111-
112-
.json-diff-viewer.json-diff-viewer-theme-custom tr.expand-line td {
113-
text-align: center;
114-
}
115-
11651
/* EDITOR COLORS */
117-
.json-diff-viewer.json-diff-viewer-theme-custom trtdprespan.inline-diff-add {
52+
.json-diff-viewer.json-diff-viewer-theme-custom .inline-diff-add {
11853
background: rgba(0, 0, 0, 0.08);
11954
text-decoration: underline;
12055
word-break: break-all;
12156
}
122-
.json-diff-viewer.json-diff-viewer-theme-custom trtdprespan.inline-diff-remove {
57+
.json-diff-viewer.json-diff-viewer-theme-custom .inline-diff-remove {
12358
background: rgba(0, 0, 0, 0.08);
12459
text-decoration: line-through;
12560
word-break: break-all;
12661
}
12762

128-
.json-diff-viewer.json-diff-viewer-theme-custom tr:hover {
129-
background: #53535f54;
130-
}
131-
132-
.json-diff-viewer.json-diff-viewer-theme-custom tr.expand-line button {
133-
color: #1e616d;
134-
}
135-
13663
.json-diff-viewer.json-diff-viewer-theme-custom .string {
13764
color: #e6db74;
13865
}
@@ -173,20 +100,6 @@
173100
outline: 4px auto -webkit-focus-ring-color;
174101
}
175102

176-
.collapsed-button {
177-
background-color: #262626;
178-
}
179-
180-
tr.collapsed-button td {
181-
max-width: unset !important;
182-
width: 50%;
183-
}
184-
185-
tr.collapsed-button .expand-button-container {
186-
display: flex;
187-
justify-content: center;
188-
}
189-
190103
.collapsed-button button {
191104
height: 20px;
192105
color: rgba(255, 255, 255, 0.7);
@@ -336,7 +249,6 @@ tr.collapsed-button .expand-button-container {
336249

337250
.diff-viewer-container .minimap-overlay .left-map-holder {
338251
justify-content: flex-end;
339-
min-width: 334px;
340252
}
341253

342254
.diff-viewer-container .minimap-overlay .right-map-holder {
@@ -351,3 +263,63 @@ tr.collapsed-button .expand-button-container {
351263
.diff-viewer-container .minimap-overlay .minimap-wrapper:hover {
352264
opacity: 0.85;
353265
}
266+
267+
/* row container */
268+
.json-diff-viewer.json-diff-viewer-theme-custom .grid-row .cell {
269+
padding: 0;
270+
vertical-align: unset;
271+
overflow: hidden;
272+
box-sizing: border-box;
273+
}
274+
275+
/* line-number cell styling (mimic old td.line-number) */
276+
.json-diff-viewer.json-diff-viewer-theme-custom .grid-row .line-number {
277+
background: unset;
278+
border-left: 0;
279+
border-bottom: none;
280+
color: #999;
281+
padding: 2px;
282+
padding-right: 6px;
283+
text-align: right;
284+
width: 30px;
285+
overflow: hidden;
286+
text-overflow: ellipsis;
287+
}
288+
289+
/* content cells (2nd and 4th column) */
290+
.json-diff-viewer.json-diff-viewer-theme-custom .grid-row .cell:nth-child(2),
291+
.json-diff-viewer.json-diff-viewer-theme-custom .grid-row .cell:nth-child(4) {
292+
width: auto;
293+
overflow-wrap: anywhere;
294+
}
295+
296+
/* pre inside the cell */
297+
.json-diff-viewer.json-diff-viewer-theme-custom .grid-row .cell pre {
298+
font-family:
299+
-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif,
300+
"Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
301+
overflow: hidden;
302+
margin: 0;
303+
padding-left: 4px;
304+
margin-right: 29px;
305+
font-size: 12px;
306+
line-height: var(--diff-row-height);
307+
white-space: pre-wrap;
308+
word-break: break-all;
309+
min-width: 0; /* important for flexbox/grid overflow */
310+
}
311+
312+
/* collapsed button visuals */
313+
.json-diff-viewer.json-diff-viewer-theme-custom .grid-row.collapsed-button {
314+
background-color: #262626;
315+
}
316+
317+
.json-diff-viewer.json-diff-viewer-theme-custom .grid-row.collapsed-button .expand-button-container {
318+
display: flex;
319+
justify-content: center;
320+
}
321+
322+
/* preserve hover */
323+
.json-diff-viewer.json-diff-viewer-theme-custom .grid-row:hover {
324+
background: #53535f54;
325+
}

‎src/components/DiffViewer/utils/constants.ts‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,4 +34,7 @@ export function equalEmptyLine(cell: DiffRow) {
3434
if (cell.type === "equal" && cell.text.trim() === "") {
3535
return "empty-equal-cell";
3636
}
37+
else {
38+
return "";
39+
}
3740
}

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /