@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
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import cn from "classnames";
|
|
3
|
+
import * as React from "react";
|
|
4
|
+
import { DiffMethod, DiffType, } from "./compute-lines.js";
|
|
5
|
+
/**
|
|
6
|
+
* Applies diff styling (ins/del tags) to pre-highlighted HTML by walking through
|
|
7
|
+
* the HTML and wrapping text portions based on character positions in the diff.
|
|
8
|
+
*/
|
|
9
|
+
export function applyDiffToHighlightedHtml(html, diffArray, styles) {
|
|
10
|
+
const ranges = [];
|
|
11
|
+
let pos = 0;
|
|
12
|
+
for (const diff of diffArray) {
|
|
13
|
+
const value = typeof diff.value === "string" ? diff.value : "";
|
|
14
|
+
if (value.length > 0) {
|
|
15
|
+
ranges.push({ start: pos, end: pos + value.length, type: diff.type });
|
|
16
|
+
pos += value.length;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
const segments = [];
|
|
20
|
+
let i = 0;
|
|
21
|
+
while (i < html.length) {
|
|
22
|
+
if (html[i] === "<") {
|
|
23
|
+
const tagEnd = html.indexOf(">", i);
|
|
24
|
+
if (tagEnd === -1) {
|
|
25
|
+
// Malformed HTML, treat rest as text
|
|
26
|
+
segments.push({ type: "text", content: html.slice(i) });
|
|
27
|
+
break;
|
|
28
|
+
}
|
|
29
|
+
segments.push({ type: "tag", content: html.slice(i, tagEnd + 1) });
|
|
30
|
+
i = tagEnd + 1;
|
|
31
|
+
}
|
|
32
|
+
else {
|
|
33
|
+
// Find the next tag or end of string
|
|
34
|
+
let textEnd = html.indexOf("<", i);
|
|
35
|
+
if (textEnd === -1)
|
|
36
|
+
textEnd = html.length;
|
|
37
|
+
segments.push({ type: "text", content: html.slice(i, textEnd) });
|
|
38
|
+
i = textEnd;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
// Helper to decode HTML entities for character counting
|
|
42
|
+
function decodeEntities(text) {
|
|
43
|
+
return text
|
|
44
|
+
.replace(/</g, "<")
|
|
45
|
+
.replace(/>/g, ">")
|
|
46
|
+
.replace(/&/g, "&")
|
|
47
|
+
.replace(/"/g, '"')
|
|
48
|
+
.replace(/'/g, "'")
|
|
49
|
+
.replace(/'/g, "'")
|
|
50
|
+
.replace(/ /g, "\u00A0");
|
|
51
|
+
}
|
|
52
|
+
// Helper to get the wrapper tag for a diff type
|
|
53
|
+
function getWrapper(type) {
|
|
54
|
+
if (type === DiffType.ADDED) {
|
|
55
|
+
return {
|
|
56
|
+
open: `<ins class="${styles.wordDiff} ${styles.wordAdded}">`,
|
|
57
|
+
close: "</ins>",
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
if (type === DiffType.REMOVED) {
|
|
61
|
+
return {
|
|
62
|
+
open: `<del class="${styles.wordDiff} ${styles.wordRemoved}">`,
|
|
63
|
+
close: "</del>",
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
return {
|
|
67
|
+
open: `<span class="${styles.wordDiff}">`,
|
|
68
|
+
close: "</span>",
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
// Process segments, tracking text position
|
|
72
|
+
let textPos = 0;
|
|
73
|
+
let result = "";
|
|
74
|
+
for (const segment of segments) {
|
|
75
|
+
if (segment.type === "tag") {
|
|
76
|
+
result += segment.content;
|
|
77
|
+
}
|
|
78
|
+
else {
|
|
79
|
+
// Text segment - we need to split it according to diff ranges
|
|
80
|
+
const text = segment.content;
|
|
81
|
+
const decodedText = decodeEntities(text);
|
|
82
|
+
// Walk through the text, character by character (in decoded form)
|
|
83
|
+
// but output the original encoded form
|
|
84
|
+
let localDecodedPos = 0;
|
|
85
|
+
let localEncodedPos = 0;
|
|
86
|
+
while (localDecodedPos < decodedText.length) {
|
|
87
|
+
const globalPos = textPos + localDecodedPos;
|
|
88
|
+
// Find the range that covers this position
|
|
89
|
+
const range = ranges.find((r) => globalPos >= r.start && globalPos < r.end);
|
|
90
|
+
if (!range) {
|
|
91
|
+
// No range covers this position (shouldn't happen, but be safe)
|
|
92
|
+
// Just output the character
|
|
93
|
+
const char = text[localEncodedPos];
|
|
94
|
+
result += char;
|
|
95
|
+
localEncodedPos++;
|
|
96
|
+
localDecodedPos++;
|
|
97
|
+
continue;
|
|
98
|
+
}
|
|
99
|
+
// How many decoded characters until the end of this range?
|
|
100
|
+
const charsUntilRangeEnd = range.end - globalPos;
|
|
101
|
+
// How many decoded characters until the end of this text segment?
|
|
102
|
+
const charsUntilTextEnd = decodedText.length - localDecodedPos;
|
|
103
|
+
// Take the minimum
|
|
104
|
+
const charsToTake = Math.min(charsUntilRangeEnd, charsUntilTextEnd);
|
|
105
|
+
// Now we need to find the corresponding encoded substring
|
|
106
|
+
// Walk through encoded text, counting decoded characters
|
|
107
|
+
let encodedChunkEnd = localEncodedPos;
|
|
108
|
+
let decodedCount = 0;
|
|
109
|
+
while (decodedCount < charsToTake && encodedChunkEnd < text.length) {
|
|
110
|
+
if (text[encodedChunkEnd] === "&") {
|
|
111
|
+
// Find entity end
|
|
112
|
+
const entityEnd = text.indexOf(";", encodedChunkEnd);
|
|
113
|
+
if (entityEnd !== -1 && entityEnd - encodedChunkEnd < 10) {
|
|
114
|
+
encodedChunkEnd = entityEnd + 1;
|
|
115
|
+
}
|
|
116
|
+
else {
|
|
117
|
+
encodedChunkEnd++;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
else {
|
|
121
|
+
encodedChunkEnd++;
|
|
122
|
+
}
|
|
123
|
+
decodedCount++;
|
|
124
|
+
}
|
|
125
|
+
const chunk = text.slice(localEncodedPos, encodedChunkEnd);
|
|
126
|
+
const wrapper = getWrapper(range.type);
|
|
127
|
+
if (wrapper) {
|
|
128
|
+
result += wrapper.open + chunk + wrapper.close;
|
|
129
|
+
}
|
|
130
|
+
else {
|
|
131
|
+
result += chunk;
|
|
132
|
+
}
|
|
133
|
+
localEncodedPos = encodedChunkEnd;
|
|
134
|
+
localDecodedPos += charsToTake;
|
|
135
|
+
}
|
|
136
|
+
textPos += decodedText.length;
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
return result;
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Checks if the current compare method should show word-level highlighting.
|
|
143
|
+
*/
|
|
144
|
+
function shouldHighlightWordDiff(compareMethod) {
|
|
145
|
+
return (compareMethod === DiffMethod.CHARS ||
|
|
146
|
+
compareMethod === DiffMethod.WORDS ||
|
|
147
|
+
compareMethod === DiffMethod.WORDS_WITH_SPACE ||
|
|
148
|
+
compareMethod === DiffMethod.JSON ||
|
|
149
|
+
compareMethod === DiffMethod.YAML);
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* Maps over the word diff and constructs the required React elements to show word diff.
|
|
153
|
+
*
|
|
154
|
+
* @param diffArray Word diff information derived from line information.
|
|
155
|
+
* @param styles Computed styles for the diff viewer.
|
|
156
|
+
* @param compareMethod The diff comparison method being used.
|
|
157
|
+
* @param renderer Optional renderer to format diff words. Useful for syntax highlighting.
|
|
158
|
+
*/
|
|
159
|
+
export function renderWordDiff(diffArray, styles, compareMethod, renderer) {
|
|
160
|
+
const showHighlight = shouldHighlightWordDiff(compareMethod);
|
|
161
|
+
// Reconstruct the full line from diff chunks
|
|
162
|
+
const fullLine = diffArray
|
|
163
|
+
.map((d) => (typeof d.value === "string" ? d.value : ""))
|
|
164
|
+
.join("");
|
|
165
|
+
// For very long lines (>500 chars), skip fancy processing - just render plain text
|
|
166
|
+
// without word-level highlighting to avoid performance issues
|
|
167
|
+
const MAX_LINE_LENGTH = 500;
|
|
168
|
+
if (fullLine.length > MAX_LINE_LENGTH) {
|
|
169
|
+
return [_jsx("span", { children: fullLine }, "long-line")];
|
|
170
|
+
}
|
|
171
|
+
// If we have a renderer, try to highlight the full line first,
|
|
172
|
+
// then apply diff styling to preserve proper tokenization.
|
|
173
|
+
if (renderer) {
|
|
174
|
+
// Get the syntax-highlighted content
|
|
175
|
+
const highlighted = renderer(fullLine);
|
|
176
|
+
// Check if the renderer uses dangerouslySetInnerHTML (common with Prism, highlight.js, etc.)
|
|
177
|
+
const htmlContent = highlighted?.props?.dangerouslySetInnerHTML?.__html;
|
|
178
|
+
if (typeof htmlContent === "string") {
|
|
179
|
+
// Apply diff styling to the highlighted HTML
|
|
180
|
+
const styledHtml = applyDiffToHighlightedHtml(htmlContent, diffArray, {
|
|
181
|
+
wordDiff: styles.wordDiff,
|
|
182
|
+
wordAdded: showHighlight ? styles.wordAdded : "",
|
|
183
|
+
wordRemoved: showHighlight ? styles.wordRemoved : "",
|
|
184
|
+
});
|
|
185
|
+
// Clone the element with the modified HTML
|
|
186
|
+
return [
|
|
187
|
+
React.cloneElement(highlighted, {
|
|
188
|
+
key: "highlighted-diff",
|
|
189
|
+
dangerouslySetInnerHTML: { __html: styledHtml },
|
|
190
|
+
}),
|
|
191
|
+
];
|
|
192
|
+
}
|
|
193
|
+
// Renderer doesn't use dangerouslySetInnerHTML - fall through to per-chunk rendering
|
|
194
|
+
}
|
|
195
|
+
// Fallback: render each chunk separately (used for JSON/YAML or non-HTML renderers)
|
|
196
|
+
return diffArray.map((wordDiff, i) => {
|
|
197
|
+
let content;
|
|
198
|
+
if (typeof wordDiff.value === "string") {
|
|
199
|
+
content = wordDiff.value;
|
|
200
|
+
}
|
|
201
|
+
else {
|
|
202
|
+
// If wordDiff.value is DiffInformation[], we don't handle it. See c0c99f5712.
|
|
203
|
+
content = undefined;
|
|
204
|
+
}
|
|
205
|
+
return wordDiff.type === DiffType.ADDED ? (_jsx("ins", { className: cn(styles.wordDiff, {
|
|
206
|
+
[styles.wordAdded]: showHighlight,
|
|
207
|
+
}), children: content }, i)) : wordDiff.type === DiffType.REMOVED ? (_jsx("del", { className: cn(styles.wordDiff, {
|
|
208
|
+
[styles.wordRemoved]: showHighlight,
|
|
209
|
+
}), children: content }, i)) : (_jsx("span", { className: cn(styles.wordDiff), children: content }, i));
|
|
210
|
+
});
|
|
211
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import cn from "classnames";
|
|
3
|
+
import * as React from "react";
|
|
4
|
+
import { Expand } from "./expand.js";
|
|
5
|
+
/**
|
|
6
|
+
* Custom equality function for React.memo — skips comparing callback/render props.
|
|
7
|
+
*/
|
|
8
|
+
function skippedLineIndicatorPropsAreEqual(prev, next) {
|
|
9
|
+
return (prev.num === next.num &&
|
|
10
|
+
prev.blockNumber === next.blockNumber &&
|
|
11
|
+
prev.leftBlockLineNumber === next.leftBlockLineNumber &&
|
|
12
|
+
prev.rightBlockLineNumber === next.rightBlockLineNumber &&
|
|
13
|
+
prev.hideLineNumbers === next.hideLineNumbers &&
|
|
14
|
+
prev.splitView === next.splitView &&
|
|
15
|
+
prev.styles === next.styles);
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Memoized component that renders the code fold / skipped line indicator row.
|
|
19
|
+
*/
|
|
20
|
+
export const SkippedLineIndicator = React.memo(function SkippedLineIndicator({ num, blockNumber, leftBlockLineNumber, rightBlockLineNumber, hideLineNumbers, splitView, styles, onBlockClick, codeFoldMessageRenderer, renderGutter, }) {
|
|
21
|
+
const handleClick = () => onBlockClick(blockNumber);
|
|
22
|
+
const message = codeFoldMessageRenderer ? (codeFoldMessageRenderer(num, leftBlockLineNumber, rightBlockLineNumber)) : (_jsxs("span", { className: styles.codeFoldContent, children: ["@@ -", leftBlockLineNumber - num, ",", num, " +", rightBlockLineNumber - num, ",", num, " @@"] }));
|
|
23
|
+
const content = (_jsx("td", { className: styles.codeFoldContentContainer, children: _jsx("button", { type: "button", className: styles.codeFoldExpandButton, onClick: handleClick, tabIndex: 0, children: message }) }));
|
|
24
|
+
const isUnifiedViewWithoutLineNumbers = !splitView && !hideLineNumbers;
|
|
25
|
+
const expandGutter = (_jsx("td", { className: styles.codeFoldGutter, children: _jsx(Expand, {}) }));
|
|
26
|
+
return (_jsxs("tr", { className: styles.codeFold, onClick: handleClick, role: "button", tabIndex: 0, children: [!hideLineNumbers && expandGutter, renderGutter ? (_jsx("td", { className: styles.codeFoldGutter })) : null, _jsx("td", { className: cn({
|
|
27
|
+
[styles.codeFoldGutter]: isUnifiedViewWithoutLineNumbers,
|
|
28
|
+
}) }), isUnifiedViewWithoutLineNumbers ? (_jsxs(React.Fragment, { children: [_jsx("td", {}), content] })) : (_jsxs(React.Fragment, { children: [content, renderGutter ? _jsx("td", {}) : null, _jsx("td", {}), _jsx("td", {}), !hideLineNumbers ? _jsx("td", {}) : null] }))] }, `${leftBlockLineNumber}-${rightBlockLineNumber}`));
|
|
29
|
+
}, skippedLineIndicatorPropsAreEqual);
|
|
@@ -0,0 +1,431 @@
|
|
|
1
|
+
import createEmotion from "@emotion/css/create-instance";
|
|
2
|
+
export default (styleOverride, useDarkTheme = false, nonce = "") => {
|
|
3
|
+
const { variables: overrideVariables = {}, ...styles } = styleOverride;
|
|
4
|
+
const themeVariables = {
|
|
5
|
+
light: {
|
|
6
|
+
...{
|
|
7
|
+
diffViewerBackground: "#fff",
|
|
8
|
+
diffViewerColor: "#212529",
|
|
9
|
+
addedBackground: "#e6ffed",
|
|
10
|
+
addedColor: "#24292e",
|
|
11
|
+
removedBackground: "#ffeef0",
|
|
12
|
+
removedColor: "#24292e",
|
|
13
|
+
changedBackground: "#fffbdd",
|
|
14
|
+
wordAddedBackground: "#acf2bd",
|
|
15
|
+
wordRemovedBackground: "#fdb8c0",
|
|
16
|
+
addedGutterBackground: "#cdffd8",
|
|
17
|
+
removedGutterBackground: "#ffdce0",
|
|
18
|
+
gutterBackground: "#f7f7f7",
|
|
19
|
+
gutterBackgroundDark: "#f3f1f1",
|
|
20
|
+
highlightBackground: "#fffbdd",
|
|
21
|
+
highlightGutterBackground: "#fff5b1",
|
|
22
|
+
codeFoldGutterBackground: "#dbedff",
|
|
23
|
+
codeFoldBackground: "#f1f8ff",
|
|
24
|
+
emptyLineBackground: "#fafbfc",
|
|
25
|
+
gutterColor: "#212529",
|
|
26
|
+
addedGutterColor: "#212529",
|
|
27
|
+
removedGutterColor: "#212529",
|
|
28
|
+
codeFoldContentColor: "#212529",
|
|
29
|
+
diffViewerTitleBackground: "#fafbfc",
|
|
30
|
+
diffViewerTitleColor: "#212529",
|
|
31
|
+
diffViewerTitleBorderColor: "#eee",
|
|
32
|
+
},
|
|
33
|
+
...(overrideVariables.light || {}),
|
|
34
|
+
},
|
|
35
|
+
dark: {
|
|
36
|
+
...{
|
|
37
|
+
diffViewerBackground: "#2e303c",
|
|
38
|
+
diffViewerColor: "#FFF",
|
|
39
|
+
addedBackground: "#2ea04326",
|
|
40
|
+
addedColor: "white",
|
|
41
|
+
removedBackground: "#f851491a",
|
|
42
|
+
removedColor: "white",
|
|
43
|
+
changedBackground: "#3e302c",
|
|
44
|
+
wordAddedBackground: "#2ea04366",
|
|
45
|
+
wordRemovedBackground: "#f8514966",
|
|
46
|
+
addedGutterBackground: "#3fb9504d",
|
|
47
|
+
removedGutterBackground: "#f851494d",
|
|
48
|
+
gutterBackground: "#2c2f3a",
|
|
49
|
+
gutterBackgroundDark: "#262933",
|
|
50
|
+
highlightBackground: "#2a3967",
|
|
51
|
+
highlightGutterBackground: "#2d4077",
|
|
52
|
+
codeFoldGutterBackground: "#262831",
|
|
53
|
+
codeFoldBackground: "#262831",
|
|
54
|
+
emptyLineBackground: "#363946",
|
|
55
|
+
gutterColor: "#f0f6fc",
|
|
56
|
+
addedGutterColor: "#f0f6fc",
|
|
57
|
+
removedGutterColor: "#f0f6fc",
|
|
58
|
+
codeFoldContentColor: "#9198a1",
|
|
59
|
+
diffViewerTitleBackground: "#2f323e",
|
|
60
|
+
diffViewerTitleColor: "#f0f6fc",
|
|
61
|
+
diffViewerTitleBorderColor: "#353846",
|
|
62
|
+
},
|
|
63
|
+
...(overrideVariables.dark || {}),
|
|
64
|
+
},
|
|
65
|
+
};
|
|
66
|
+
const variables = useDarkTheme ? themeVariables.dark : themeVariables.light;
|
|
67
|
+
const { css, cx } = createEmotion({ key: "react-diff", nonce });
|
|
68
|
+
const content = css({
|
|
69
|
+
width: "auto",
|
|
70
|
+
overflow: "hidden",
|
|
71
|
+
label: "content",
|
|
72
|
+
});
|
|
73
|
+
const splitView = css({
|
|
74
|
+
label: "split-view",
|
|
75
|
+
});
|
|
76
|
+
const stickyHeader = css({
|
|
77
|
+
position: "sticky",
|
|
78
|
+
top: 0,
|
|
79
|
+
zIndex: 2,
|
|
80
|
+
label: "sticky-header",
|
|
81
|
+
});
|
|
82
|
+
const summary = css({
|
|
83
|
+
background: variables.diffViewerTitleBackground,
|
|
84
|
+
color: variables.diffViewerTitleColor,
|
|
85
|
+
padding: "0.5em 1em",
|
|
86
|
+
display: "flex",
|
|
87
|
+
alignItems: "center",
|
|
88
|
+
gap: "0.5em",
|
|
89
|
+
fontFamily: "monospace",
|
|
90
|
+
fontSize: 12,
|
|
91
|
+
fill: variables.diffViewerTitleColor,
|
|
92
|
+
});
|
|
93
|
+
const columnHeaders = css({
|
|
94
|
+
display: "flex",
|
|
95
|
+
label: "column-headers",
|
|
96
|
+
});
|
|
97
|
+
const diffContainer = css({
|
|
98
|
+
width: "100%",
|
|
99
|
+
minWidth: "1000px",
|
|
100
|
+
overflowX: "auto",
|
|
101
|
+
tableLayout: "fixed",
|
|
102
|
+
fontSize: 12,
|
|
103
|
+
background: variables.diffViewerBackground,
|
|
104
|
+
pre: {
|
|
105
|
+
margin: 0,
|
|
106
|
+
whiteSpace: "pre-wrap",
|
|
107
|
+
lineHeight: "1.6em",
|
|
108
|
+
width: "fit-content",
|
|
109
|
+
},
|
|
110
|
+
label: "diff-container",
|
|
111
|
+
borderCollapse: "collapse",
|
|
112
|
+
"@media (max-width: 768px)": {
|
|
113
|
+
minWidth: "unset",
|
|
114
|
+
},
|
|
115
|
+
});
|
|
116
|
+
const lineContent = css({
|
|
117
|
+
overflow: "hidden",
|
|
118
|
+
width: "100%",
|
|
119
|
+
});
|
|
120
|
+
const contentText = css({
|
|
121
|
+
color: variables.diffViewerColor,
|
|
122
|
+
whiteSpace: "pre-wrap",
|
|
123
|
+
fontFamily: "monospace",
|
|
124
|
+
lineBreak: "anywhere",
|
|
125
|
+
textDecoration: "none",
|
|
126
|
+
label: "content-text",
|
|
127
|
+
});
|
|
128
|
+
const unselectable = css({
|
|
129
|
+
userSelect: "none",
|
|
130
|
+
label: "unselectable",
|
|
131
|
+
});
|
|
132
|
+
const noWrap = css({
|
|
133
|
+
label: "no-wrap",
|
|
134
|
+
pre: {
|
|
135
|
+
whiteSpace: "pre",
|
|
136
|
+
},
|
|
137
|
+
[`.${contentText}`]: {
|
|
138
|
+
whiteSpace: "pre",
|
|
139
|
+
lineBreak: "auto",
|
|
140
|
+
},
|
|
141
|
+
});
|
|
142
|
+
const allExpandButton = css({
|
|
143
|
+
background: "transparent",
|
|
144
|
+
border: "none",
|
|
145
|
+
cursor: "pointer",
|
|
146
|
+
display: "flex",
|
|
147
|
+
alignItems: "center",
|
|
148
|
+
justifyContent: "center",
|
|
149
|
+
margin: 0,
|
|
150
|
+
label: "all-expand-button",
|
|
151
|
+
":hover": {
|
|
152
|
+
fill: variables.addedGutterColor,
|
|
153
|
+
},
|
|
154
|
+
":focus": {
|
|
155
|
+
outline: `1px ${variables.addedGutterColor} solid`,
|
|
156
|
+
},
|
|
157
|
+
});
|
|
158
|
+
const titleBlock = css({
|
|
159
|
+
background: variables.diffViewerTitleBackground,
|
|
160
|
+
padding: "0.5em",
|
|
161
|
+
lineHeight: "1.4em",
|
|
162
|
+
height: "2.4em",
|
|
163
|
+
overflow: "hidden",
|
|
164
|
+
width: "50%",
|
|
165
|
+
borderBottom: `1px solid ${variables.diffViewerTitleBorderColor}`,
|
|
166
|
+
boxSizing: "border-box",
|
|
167
|
+
fontSize: 12,
|
|
168
|
+
label: "title-block",
|
|
169
|
+
":only-child": {
|
|
170
|
+
width: "100%",
|
|
171
|
+
},
|
|
172
|
+
":last-child:not(:only-child)": {
|
|
173
|
+
borderLeft: `1px solid ${variables.diffViewerTitleBorderColor}`,
|
|
174
|
+
},
|
|
175
|
+
[`.${contentText}`]: {
|
|
176
|
+
color: variables.diffViewerTitleColor,
|
|
177
|
+
},
|
|
178
|
+
});
|
|
179
|
+
const lineNumber = css({
|
|
180
|
+
color: variables.gutterColor,
|
|
181
|
+
label: "line-number",
|
|
182
|
+
});
|
|
183
|
+
const diffRemoved = css({
|
|
184
|
+
background: variables.removedBackground,
|
|
185
|
+
color: variables.removedColor,
|
|
186
|
+
pre: {
|
|
187
|
+
color: variables.removedColor,
|
|
188
|
+
},
|
|
189
|
+
[`.${lineNumber}`]: {
|
|
190
|
+
color: variables.removedGutterColor,
|
|
191
|
+
},
|
|
192
|
+
label: "diff-removed",
|
|
193
|
+
});
|
|
194
|
+
const diffAdded = css({
|
|
195
|
+
background: variables.addedBackground,
|
|
196
|
+
color: variables.addedColor,
|
|
197
|
+
pre: {
|
|
198
|
+
color: variables.addedColor,
|
|
199
|
+
},
|
|
200
|
+
[`.${lineNumber}`]: {
|
|
201
|
+
color: variables.addedGutterColor,
|
|
202
|
+
},
|
|
203
|
+
label: "diff-added",
|
|
204
|
+
});
|
|
205
|
+
const diffChanged = css({
|
|
206
|
+
background: variables.changedBackground,
|
|
207
|
+
[`.${lineNumber}`]: {
|
|
208
|
+
color: variables.gutterColor,
|
|
209
|
+
},
|
|
210
|
+
label: "diff-changed",
|
|
211
|
+
});
|
|
212
|
+
const wordDiff = css({
|
|
213
|
+
display: "inline",
|
|
214
|
+
textDecoration: "none",
|
|
215
|
+
label: "word-diff",
|
|
216
|
+
});
|
|
217
|
+
const wordAdded = css({
|
|
218
|
+
background: variables.wordAddedBackground,
|
|
219
|
+
label: "word-added",
|
|
220
|
+
});
|
|
221
|
+
const wordRemoved = css({
|
|
222
|
+
background: variables.wordRemovedBackground,
|
|
223
|
+
label: "word-removed",
|
|
224
|
+
});
|
|
225
|
+
const codeFoldGutter = css({
|
|
226
|
+
backgroundColor: variables.codeFoldGutterBackground,
|
|
227
|
+
label: "code-fold-gutter",
|
|
228
|
+
minWidth: "50px",
|
|
229
|
+
width: "50px",
|
|
230
|
+
textAlign: "center",
|
|
231
|
+
fill: variables.codeFoldContentColor,
|
|
232
|
+
});
|
|
233
|
+
const codeFoldContentContainer = css({
|
|
234
|
+
padding: "",
|
|
235
|
+
});
|
|
236
|
+
const codeFoldExpandButton = css({
|
|
237
|
+
background: variables.codeFoldBackground,
|
|
238
|
+
cursor: "pointer",
|
|
239
|
+
display: "inline",
|
|
240
|
+
margin: 0,
|
|
241
|
+
border: "none",
|
|
242
|
+
fill: variables.codeFoldContentColor,
|
|
243
|
+
label: "code-fold-expand-button",
|
|
244
|
+
});
|
|
245
|
+
const codeFoldContent = css({
|
|
246
|
+
color: variables.codeFoldContentColor,
|
|
247
|
+
fontFamily: "monospace",
|
|
248
|
+
label: "code-fold-content",
|
|
249
|
+
});
|
|
250
|
+
const block = css({
|
|
251
|
+
display: "block",
|
|
252
|
+
width: "10px",
|
|
253
|
+
height: "10px",
|
|
254
|
+
backgroundColor: "#ddd",
|
|
255
|
+
borderWidth: "1px",
|
|
256
|
+
borderStyle: "solid",
|
|
257
|
+
borderColor: variables.diffViewerTitleBorderColor,
|
|
258
|
+
});
|
|
259
|
+
const blockAddition = css({
|
|
260
|
+
backgroundColor: variables.wordAddedBackground,
|
|
261
|
+
});
|
|
262
|
+
const blockDeletion = css({
|
|
263
|
+
backgroundColor: variables.wordRemovedBackground,
|
|
264
|
+
});
|
|
265
|
+
const codeFold = css({
|
|
266
|
+
backgroundColor: variables.codeFoldBackground,
|
|
267
|
+
fontSize: 12,
|
|
268
|
+
alignItems: "center",
|
|
269
|
+
userSelect: "none",
|
|
270
|
+
fontWeight: 700,
|
|
271
|
+
cursor: "pointer",
|
|
272
|
+
label: "code-fold",
|
|
273
|
+
"&:hover": {
|
|
274
|
+
color: variables.diffViewerColor,
|
|
275
|
+
fill: variables.diffViewerColor,
|
|
276
|
+
"& *": {
|
|
277
|
+
color: variables.diffViewerColor,
|
|
278
|
+
fill: variables.diffViewerColor,
|
|
279
|
+
},
|
|
280
|
+
},
|
|
281
|
+
a: {
|
|
282
|
+
textDecoration: "underline !important",
|
|
283
|
+
cursor: "pointer",
|
|
284
|
+
pre: {
|
|
285
|
+
display: "inline",
|
|
286
|
+
},
|
|
287
|
+
},
|
|
288
|
+
});
|
|
289
|
+
const emptyLine = css({
|
|
290
|
+
backgroundColor: variables.emptyLineBackground,
|
|
291
|
+
label: "empty-line",
|
|
292
|
+
});
|
|
293
|
+
const commentRow = css({
|
|
294
|
+
label: "comment-row",
|
|
295
|
+
borderTop: `1px solid ${variables.diffViewerTitleBorderColor}`,
|
|
296
|
+
borderBottom: `1px solid ${variables.diffViewerTitleBorderColor}`,
|
|
297
|
+
backgroundColor: variables.diffViewerBackground,
|
|
298
|
+
});
|
|
299
|
+
const commentCell = css({
|
|
300
|
+
label: "comment-cell",
|
|
301
|
+
padding: 0,
|
|
302
|
+
});
|
|
303
|
+
const marker = css({
|
|
304
|
+
width: 28,
|
|
305
|
+
paddingLeft: 10,
|
|
306
|
+
paddingRight: 10,
|
|
307
|
+
userSelect: "none",
|
|
308
|
+
label: "marker",
|
|
309
|
+
[`&.${diffAdded}`]: {
|
|
310
|
+
pre: {
|
|
311
|
+
color: variables.addedColor,
|
|
312
|
+
},
|
|
313
|
+
},
|
|
314
|
+
[`&.${diffRemoved}`]: {
|
|
315
|
+
pre: {
|
|
316
|
+
color: variables.removedColor,
|
|
317
|
+
},
|
|
318
|
+
},
|
|
319
|
+
});
|
|
320
|
+
const highlightedLine = css({
|
|
321
|
+
background: variables.highlightBackground,
|
|
322
|
+
label: "highlighted-line",
|
|
323
|
+
[`.${wordAdded}, .${wordRemoved}`]: {
|
|
324
|
+
backgroundColor: "initial",
|
|
325
|
+
},
|
|
326
|
+
});
|
|
327
|
+
const highlightedGutter = css({
|
|
328
|
+
label: "highlighted-gutter",
|
|
329
|
+
});
|
|
330
|
+
const gutter = css({
|
|
331
|
+
userSelect: "none",
|
|
332
|
+
minWidth: 50,
|
|
333
|
+
width: "50px",
|
|
334
|
+
padding: "0 10px",
|
|
335
|
+
whiteSpace: "nowrap",
|
|
336
|
+
label: "gutter",
|
|
337
|
+
textAlign: "center",
|
|
338
|
+
color: variables.gutterColor,
|
|
339
|
+
background: variables.gutterBackground,
|
|
340
|
+
"&:hover": {
|
|
341
|
+
cursor: "pointer",
|
|
342
|
+
background: variables.gutterBackgroundDark,
|
|
343
|
+
pre: {
|
|
344
|
+
opacity: 1,
|
|
345
|
+
},
|
|
346
|
+
},
|
|
347
|
+
pre: {
|
|
348
|
+
opacity: 0.5,
|
|
349
|
+
textAlign: "center",
|
|
350
|
+
width: "100%",
|
|
351
|
+
},
|
|
352
|
+
[`&.${diffAdded}`]: {
|
|
353
|
+
background: variables.addedGutterBackground,
|
|
354
|
+
},
|
|
355
|
+
[`&.${diffRemoved}`]: {
|
|
356
|
+
background: variables.removedGutterBackground,
|
|
357
|
+
},
|
|
358
|
+
[`&.${highlightedGutter}`]: {
|
|
359
|
+
background: variables.highlightGutterBackground,
|
|
360
|
+
"&:hover": {
|
|
361
|
+
background: variables.highlightGutterBackground,
|
|
362
|
+
},
|
|
363
|
+
},
|
|
364
|
+
});
|
|
365
|
+
const emptyGutter = css({
|
|
366
|
+
"&:hover": {
|
|
367
|
+
background: variables.gutterBackground,
|
|
368
|
+
cursor: "initial",
|
|
369
|
+
},
|
|
370
|
+
label: "empty-gutter",
|
|
371
|
+
});
|
|
372
|
+
const line = css({
|
|
373
|
+
verticalAlign: "baseline",
|
|
374
|
+
label: "line",
|
|
375
|
+
textDecoration: "none",
|
|
376
|
+
});
|
|
377
|
+
const column = css({});
|
|
378
|
+
const defaultStyles = {
|
|
379
|
+
diffContainer,
|
|
380
|
+
diffRemoved,
|
|
381
|
+
diffAdded,
|
|
382
|
+
diffChanged,
|
|
383
|
+
splitView,
|
|
384
|
+
marker,
|
|
385
|
+
highlightedGutter,
|
|
386
|
+
highlightedLine,
|
|
387
|
+
gutter,
|
|
388
|
+
line,
|
|
389
|
+
lineContent,
|
|
390
|
+
wordDiff,
|
|
391
|
+
wordAdded,
|
|
392
|
+
summary,
|
|
393
|
+
block,
|
|
394
|
+
blockAddition,
|
|
395
|
+
blockDeletion,
|
|
396
|
+
wordRemoved,
|
|
397
|
+
noSelect: unselectable,
|
|
398
|
+
noWrap,
|
|
399
|
+
codeFoldGutter,
|
|
400
|
+
codeFoldExpandButton,
|
|
401
|
+
codeFoldContentContainer,
|
|
402
|
+
codeFold,
|
|
403
|
+
emptyGutter,
|
|
404
|
+
emptyLine,
|
|
405
|
+
lineNumber,
|
|
406
|
+
contentText,
|
|
407
|
+
content,
|
|
408
|
+
column,
|
|
409
|
+
codeFoldContent,
|
|
410
|
+
stickyHeader,
|
|
411
|
+
columnHeaders,
|
|
412
|
+
titleBlock,
|
|
413
|
+
allExpandButton,
|
|
414
|
+
commentRow,
|
|
415
|
+
commentCell,
|
|
416
|
+
};
|
|
417
|
+
const computerOverrideStyles = Object.keys(styles).reduce((acc, key) => ({
|
|
418
|
+
...acc,
|
|
419
|
+
...{
|
|
420
|
+
[key]: css(styles[key]),
|
|
421
|
+
},
|
|
422
|
+
}), {});
|
|
423
|
+
return Object.keys(defaultStyles).reduce((acc, key) => ({
|
|
424
|
+
...acc,
|
|
425
|
+
...{
|
|
426
|
+
[key]: computerOverrideStyles[key]
|
|
427
|
+
? cx(defaultStyles[key], computerOverrideStyles[key])
|
|
428
|
+
: defaultStyles[key],
|
|
429
|
+
},
|
|
430
|
+
}), {});
|
|
431
|
+
};
|