@haklex/rich-diff 0.0.80 → 0.0.81
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/dist/index.mjs +437 -442
- package/dist/rich-diff.css +2 -1
- package/package.json +4 -4
package/dist/index.mjs
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { getVariantClass, ColorSchemeProvider } from "@haklex/rich-editor";
|
|
1
|
+
import { ColorSchemeProvider, getVariantClass } from "@haklex/rich-editor";
|
|
3
2
|
import { RichRenderer } from "@haklex/rich-static-renderer";
|
|
4
3
|
import { PortalThemeProvider } from "@haklex/rich-style-token";
|
|
5
4
|
import { useMemo } from "react";
|
|
5
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
6
|
+
//#region src/style.css.ts
|
|
6
7
|
var root = "xcvddd0";
|
|
7
8
|
var header = "xcvddd1";
|
|
8
9
|
var headerCell = "xcvddd2";
|
|
@@ -14,485 +15,479 @@ var cellOld = "xcvddd7";
|
|
|
14
15
|
var delete_ = "xcvddd8";
|
|
15
16
|
var insert = "xcvddd9";
|
|
16
17
|
var empty = "xcvddda";
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
18
|
+
//#endregion
|
|
19
|
+
//#region src/compute-diff.ts
|
|
20
|
+
var CHAR_DIFF_MAX_MATRIX_CELLS = 5e4;
|
|
21
|
+
var DELETE_MARK_STYLE = "background-color: color-mix(in srgb, var(--rc-alert-caution) 22%, transparent); text-decoration: line-through;";
|
|
22
|
+
var INSERT_MARK_STYLE = "background-color: color-mix(in srgb, var(--rc-alert-tip) 22%, transparent);";
|
|
20
23
|
function getNodeTypeKey(node) {
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
24
|
+
const n = node;
|
|
25
|
+
if (n.type === "heading") return `heading:${n.tag}`;
|
|
26
|
+
if (n.type === "list") return `list:${n.listType}`;
|
|
27
|
+
return n.type || "unknown";
|
|
25
28
|
}
|
|
26
29
|
function nodesEqual(a, b) {
|
|
27
|
-
|
|
30
|
+
return JSON.stringify(a) === JSON.stringify(b);
|
|
28
31
|
}
|
|
29
32
|
function isTextNode(node) {
|
|
30
|
-
|
|
31
|
-
|
|
33
|
+
const n = node;
|
|
34
|
+
return n.type === "text" && typeof n.text === "string";
|
|
32
35
|
}
|
|
33
36
|
function getChildren(node) {
|
|
34
|
-
|
|
35
|
-
|
|
37
|
+
const n = node;
|
|
38
|
+
return Array.isArray(n.children) ? n.children : null;
|
|
36
39
|
}
|
|
37
40
|
function appendStyle(baseStyle, extraStyle) {
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
+
const normalizedBase = typeof baseStyle === "string" ? baseStyle.trim() : "";
|
|
42
|
+
if (!normalizedBase) return extraStyle;
|
|
43
|
+
return `${normalizedBase}${normalizedBase.endsWith(";") ? "" : ";"} ${extraStyle}`;
|
|
41
44
|
}
|
|
42
45
|
function cloneTextNode(node, text, markKind) {
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
text,
|
|
52
|
-
style
|
|
53
|
-
};
|
|
54
|
-
return cloned;
|
|
46
|
+
let { style } = node;
|
|
47
|
+
if (markKind === "delete") style = appendStyle(style, DELETE_MARK_STYLE);
|
|
48
|
+
else if (markKind === "insert") style = appendStyle(style, INSERT_MARK_STYLE);
|
|
49
|
+
return {
|
|
50
|
+
...node,
|
|
51
|
+
text,
|
|
52
|
+
style
|
|
53
|
+
};
|
|
55
54
|
}
|
|
56
55
|
function cloneNodeWithChildren(node, children) {
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
56
|
+
return {
|
|
57
|
+
...node,
|
|
58
|
+
children
|
|
59
|
+
};
|
|
61
60
|
}
|
|
62
61
|
function decorateSubtree(node, kind) {
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
if (!children) return node;
|
|
68
|
-
return cloneNodeWithChildren(
|
|
69
|
-
node,
|
|
70
|
-
children.map((child) => decorateSubtree(child, kind))
|
|
71
|
-
);
|
|
62
|
+
if (isTextNode(node)) return cloneTextNode(node, node.text, kind);
|
|
63
|
+
const children = getChildren(node);
|
|
64
|
+
if (!children) return node;
|
|
65
|
+
return cloneNodeWithChildren(node, children.map((child) => decorateSubtree(child, kind)));
|
|
72
66
|
}
|
|
73
67
|
function reverseText(value) {
|
|
74
|
-
|
|
68
|
+
return Array.from(value).reverse().join("");
|
|
75
69
|
}
|
|
76
70
|
function mergeTextOps(ops) {
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
return merged;
|
|
71
|
+
const merged = [];
|
|
72
|
+
for (const op of ops) {
|
|
73
|
+
if (!op.text) continue;
|
|
74
|
+
const last = merged.at(-1);
|
|
75
|
+
if (last && last.kind === op.kind) last.text += op.text;
|
|
76
|
+
else merged.push({ ...op });
|
|
77
|
+
}
|
|
78
|
+
return merged;
|
|
88
79
|
}
|
|
89
80
|
function diffMiddleChars(oldChars, newChars) {
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
return mergeTextOps(forwardOps);
|
|
81
|
+
const m = oldChars.length;
|
|
82
|
+
const n = newChars.length;
|
|
83
|
+
if (m === 0 && n === 0) return [];
|
|
84
|
+
if (m === 0) return [{
|
|
85
|
+
kind: "insert",
|
|
86
|
+
text: newChars.join("")
|
|
87
|
+
}];
|
|
88
|
+
if (n === 0) return [{
|
|
89
|
+
kind: "delete",
|
|
90
|
+
text: oldChars.join("")
|
|
91
|
+
}];
|
|
92
|
+
if (m * n > CHAR_DIFF_MAX_MATRIX_CELLS) return [{
|
|
93
|
+
kind: "delete",
|
|
94
|
+
text: oldChars.join("")
|
|
95
|
+
}, {
|
|
96
|
+
kind: "insert",
|
|
97
|
+
text: newChars.join("")
|
|
98
|
+
}];
|
|
99
|
+
const dp = Array.from({ length: m + 1 }, () => Array.from({ length: n + 1 }).fill(0));
|
|
100
|
+
for (let i = 1; i <= m; i++) for (let j = 1; j <= n; j++) if (oldChars[i - 1] === newChars[j - 1]) dp[i][j] = dp[i - 1][j - 1] + 1;
|
|
101
|
+
else dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - 1]);
|
|
102
|
+
const reversedOps = [];
|
|
103
|
+
let i = m;
|
|
104
|
+
let j = n;
|
|
105
|
+
while (i > 0 && j > 0) {
|
|
106
|
+
if (oldChars[i - 1] === newChars[j - 1]) {
|
|
107
|
+
const last = reversedOps.at(-1);
|
|
108
|
+
if (last && last.kind === "equal") last.text += oldChars[i - 1];
|
|
109
|
+
else reversedOps.push({
|
|
110
|
+
kind: "equal",
|
|
111
|
+
text: oldChars[i - 1]
|
|
112
|
+
});
|
|
113
|
+
i--;
|
|
114
|
+
j--;
|
|
115
|
+
continue;
|
|
116
|
+
}
|
|
117
|
+
if (dp[i - 1][j] >= dp[i][j - 1]) {
|
|
118
|
+
const last = reversedOps.at(-1);
|
|
119
|
+
if (last && last.kind === "delete") last.text += oldChars[i - 1];
|
|
120
|
+
else reversedOps.push({
|
|
121
|
+
kind: "delete",
|
|
122
|
+
text: oldChars[i - 1]
|
|
123
|
+
});
|
|
124
|
+
i--;
|
|
125
|
+
} else {
|
|
126
|
+
const last = reversedOps.at(-1);
|
|
127
|
+
if (last && last.kind === "insert") last.text += newChars[j - 1];
|
|
128
|
+
else reversedOps.push({
|
|
129
|
+
kind: "insert",
|
|
130
|
+
text: newChars[j - 1]
|
|
131
|
+
});
|
|
132
|
+
j--;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
while (i > 0) {
|
|
136
|
+
const last = reversedOps.at(-1);
|
|
137
|
+
if (last && last.kind === "delete") last.text += oldChars[i - 1];
|
|
138
|
+
else reversedOps.push({
|
|
139
|
+
kind: "delete",
|
|
140
|
+
text: oldChars[i - 1]
|
|
141
|
+
});
|
|
142
|
+
i--;
|
|
143
|
+
}
|
|
144
|
+
while (j > 0) {
|
|
145
|
+
const last = reversedOps.at(-1);
|
|
146
|
+
if (last && last.kind === "insert") last.text += newChars[j - 1];
|
|
147
|
+
else reversedOps.push({
|
|
148
|
+
kind: "insert",
|
|
149
|
+
text: newChars[j - 1]
|
|
150
|
+
});
|
|
151
|
+
j--;
|
|
152
|
+
}
|
|
153
|
+
return mergeTextOps(reversedOps.reverse().map((op) => ({
|
|
154
|
+
kind: op.kind,
|
|
155
|
+
text: reverseText(op.text)
|
|
156
|
+
})));
|
|
167
157
|
}
|
|
168
158
|
function diffTextByChar(oldText, newText) {
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
oldChars.slice(prefix, oldSuffix + 1),
|
|
191
|
-
newChars.slice(prefix, newSuffix + 1)
|
|
192
|
-
)
|
|
193
|
-
);
|
|
194
|
-
if (oldSuffix < oldChars.length - 1) {
|
|
195
|
-
ops.push({
|
|
196
|
-
kind: "equal",
|
|
197
|
-
text: oldChars.slice(oldSuffix + 1).join("")
|
|
198
|
-
});
|
|
199
|
-
}
|
|
200
|
-
return mergeTextOps(ops);
|
|
159
|
+
const oldChars = Array.from(oldText);
|
|
160
|
+
const newChars = Array.from(newText);
|
|
161
|
+
let prefix = 0;
|
|
162
|
+
while (prefix < oldChars.length && prefix < newChars.length && oldChars[prefix] === newChars[prefix]) prefix++;
|
|
163
|
+
let oldSuffix = oldChars.length - 1;
|
|
164
|
+
let newSuffix = newChars.length - 1;
|
|
165
|
+
while (oldSuffix >= prefix && newSuffix >= prefix && oldChars[oldSuffix] === newChars[newSuffix]) {
|
|
166
|
+
oldSuffix--;
|
|
167
|
+
newSuffix--;
|
|
168
|
+
}
|
|
169
|
+
const ops = [];
|
|
170
|
+
if (prefix > 0) ops.push({
|
|
171
|
+
kind: "equal",
|
|
172
|
+
text: oldChars.slice(0, prefix).join("")
|
|
173
|
+
});
|
|
174
|
+
ops.push(...diffMiddleChars(oldChars.slice(prefix, oldSuffix + 1), newChars.slice(prefix, newSuffix + 1)));
|
|
175
|
+
if (oldSuffix < oldChars.length - 1) ops.push({
|
|
176
|
+
kind: "equal",
|
|
177
|
+
text: oldChars.slice(oldSuffix + 1).join("")
|
|
178
|
+
});
|
|
179
|
+
return mergeTextOps(ops);
|
|
201
180
|
}
|
|
202
181
|
function splitTextNodeByCharDiff(oldNode, newNode) {
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
182
|
+
const ops = diffTextByChar(oldNode.text, newNode.text);
|
|
183
|
+
const oldNodes = [];
|
|
184
|
+
const newNodes = [];
|
|
185
|
+
let changed = false;
|
|
186
|
+
for (const op of ops) {
|
|
187
|
+
if (!op.text) continue;
|
|
188
|
+
if (op.kind === "equal") {
|
|
189
|
+
oldNodes.push(cloneTextNode(oldNode, op.text));
|
|
190
|
+
newNodes.push(cloneTextNode(newNode, op.text));
|
|
191
|
+
continue;
|
|
192
|
+
}
|
|
193
|
+
changed = true;
|
|
194
|
+
if (op.kind === "delete") {
|
|
195
|
+
oldNodes.push(cloneTextNode(oldNode, op.text, "delete"));
|
|
196
|
+
continue;
|
|
197
|
+
}
|
|
198
|
+
newNodes.push(cloneTextNode(newNode, op.text, "insert"));
|
|
199
|
+
}
|
|
200
|
+
return {
|
|
201
|
+
oldNodes: oldNodes.length > 0 ? oldNodes : [oldNode],
|
|
202
|
+
newNodes: newNodes.length > 0 ? newNodes : [newNode],
|
|
203
|
+
changed
|
|
204
|
+
};
|
|
226
205
|
}
|
|
206
|
+
/**
|
|
207
|
+
* LCS-based structural alignment.
|
|
208
|
+
*
|
|
209
|
+
* Scoring:
|
|
210
|
+
* exact match → +2 (always align)
|
|
211
|
+
* type match → +1 (prefer align over skip)
|
|
212
|
+
* type mismatch → not considered (never align different types)
|
|
213
|
+
*/
|
|
227
214
|
function alignNodes(oldNodes, newNodes) {
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
215
|
+
const m = oldNodes.length;
|
|
216
|
+
const n = newNodes.length;
|
|
217
|
+
const dp = Array.from({ length: m + 1 }, () => Array.from({ length: n + 1 }).fill(0));
|
|
218
|
+
for (let i = 1; i <= m; i++) for (let j = 1; j <= n; j++) {
|
|
219
|
+
const skip = Math.max(dp[i - 1][j], dp[i][j - 1]);
|
|
220
|
+
if (getNodeTypeKey(oldNodes[i - 1]) === getNodeTypeKey(newNodes[j - 1])) {
|
|
221
|
+
const score = nodesEqual(oldNodes[i - 1], newNodes[j - 1]) ? 2 : 1;
|
|
222
|
+
dp[i][j] = Math.max(skip, dp[i - 1][j - 1] + score);
|
|
223
|
+
} else dp[i][j] = skip;
|
|
224
|
+
}
|
|
225
|
+
const ops = [];
|
|
226
|
+
let i = m;
|
|
227
|
+
let j = n;
|
|
228
|
+
while (i > 0 && j > 0) {
|
|
229
|
+
if (getNodeTypeKey(oldNodes[i - 1]) === getNodeTypeKey(newNodes[j - 1])) {
|
|
230
|
+
const exact = nodesEqual(oldNodes[i - 1], newNodes[j - 1]);
|
|
231
|
+
const score = exact ? 2 : 1;
|
|
232
|
+
if (dp[i][j] === dp[i - 1][j - 1] + score) {
|
|
233
|
+
ops.push(exact ? {
|
|
234
|
+
kind: "equal",
|
|
235
|
+
node: oldNodes[i - 1]
|
|
236
|
+
} : {
|
|
237
|
+
kind: "modify",
|
|
238
|
+
oldNode: oldNodes[i - 1],
|
|
239
|
+
newNode: newNodes[j - 1]
|
|
240
|
+
});
|
|
241
|
+
i--;
|
|
242
|
+
j--;
|
|
243
|
+
continue;
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
if (dp[i - 1][j] >= dp[i][j - 1]) {
|
|
247
|
+
ops.push({
|
|
248
|
+
kind: "delete",
|
|
249
|
+
node: oldNodes[i - 1]
|
|
250
|
+
});
|
|
251
|
+
i--;
|
|
252
|
+
} else {
|
|
253
|
+
ops.push({
|
|
254
|
+
kind: "insert",
|
|
255
|
+
node: newNodes[j - 1]
|
|
256
|
+
});
|
|
257
|
+
j--;
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
while (i > 0) ops.push({
|
|
261
|
+
kind: "delete",
|
|
262
|
+
node: oldNodes[--i]
|
|
263
|
+
});
|
|
264
|
+
while (j > 0) ops.push({
|
|
265
|
+
kind: "insert",
|
|
266
|
+
node: newNodes[--j]
|
|
267
|
+
});
|
|
268
|
+
ops.reverse();
|
|
269
|
+
return ops;
|
|
282
270
|
}
|
|
283
271
|
function diffChildrenInline(oldChildren, newChildren) {
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
return {
|
|
326
|
-
oldChildren: nextOldChildren,
|
|
327
|
-
newChildren: nextNewChildren,
|
|
328
|
-
changed
|
|
329
|
-
};
|
|
272
|
+
const ops = alignNodes(oldChildren, newChildren);
|
|
273
|
+
const nextOldChildren = [];
|
|
274
|
+
const nextNewChildren = [];
|
|
275
|
+
let changed = false;
|
|
276
|
+
for (const op of ops) switch (op.kind) {
|
|
277
|
+
case "equal":
|
|
278
|
+
nextOldChildren.push(op.node);
|
|
279
|
+
nextNewChildren.push(op.node);
|
|
280
|
+
break;
|
|
281
|
+
case "delete":
|
|
282
|
+
changed = true;
|
|
283
|
+
nextOldChildren.push(decorateSubtree(op.node, "delete"));
|
|
284
|
+
break;
|
|
285
|
+
case "insert":
|
|
286
|
+
changed = true;
|
|
287
|
+
nextNewChildren.push(decorateSubtree(op.node, "insert"));
|
|
288
|
+
break;
|
|
289
|
+
case "modify": {
|
|
290
|
+
changed = true;
|
|
291
|
+
if (isTextNode(op.oldNode) && isTextNode(op.newNode)) {
|
|
292
|
+
const textDiff = splitTextNodeByCharDiff(op.oldNode, op.newNode);
|
|
293
|
+
nextOldChildren.push(...textDiff.oldNodes);
|
|
294
|
+
nextNewChildren.push(...textDiff.newNodes);
|
|
295
|
+
break;
|
|
296
|
+
}
|
|
297
|
+
const nested = diffNodeInline(op.oldNode, op.newNode);
|
|
298
|
+
if (nested) {
|
|
299
|
+
nextOldChildren.push(nested.oldNode);
|
|
300
|
+
nextNewChildren.push(nested.newNode);
|
|
301
|
+
} else {
|
|
302
|
+
nextOldChildren.push(decorateSubtree(op.oldNode, "delete"));
|
|
303
|
+
nextNewChildren.push(decorateSubtree(op.newNode, "insert"));
|
|
304
|
+
}
|
|
305
|
+
break;
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
return {
|
|
309
|
+
oldChildren: nextOldChildren,
|
|
310
|
+
newChildren: nextNewChildren,
|
|
311
|
+
changed
|
|
312
|
+
};
|
|
330
313
|
}
|
|
331
314
|
function diffNodeInline(oldNode, newNode) {
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
315
|
+
if (getNodeTypeKey(oldNode) !== getNodeTypeKey(newNode)) return null;
|
|
316
|
+
if (nodesEqual(oldNode, newNode)) return {
|
|
317
|
+
oldNode,
|
|
318
|
+
newNode,
|
|
319
|
+
changed: false
|
|
320
|
+
};
|
|
321
|
+
const oldChildren = getChildren(oldNode);
|
|
322
|
+
const newChildren = getChildren(newNode);
|
|
323
|
+
if (!oldChildren || !newChildren) return null;
|
|
324
|
+
const childDiff = diffChildrenInline(oldChildren, newChildren);
|
|
325
|
+
if (!childDiff.changed) return {
|
|
326
|
+
oldNode,
|
|
327
|
+
newNode,
|
|
328
|
+
changed: false
|
|
329
|
+
};
|
|
330
|
+
return {
|
|
331
|
+
oldNode: cloneNodeWithChildren(oldNode, childDiff.oldChildren),
|
|
332
|
+
newNode: cloneNodeWithChildren(newNode, childDiff.newChildren),
|
|
333
|
+
changed: true
|
|
334
|
+
};
|
|
348
335
|
}
|
|
349
336
|
function diffModifiedNode(oldNode, newNode) {
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
337
|
+
const nested = diffNodeInline(oldNode, newNode);
|
|
338
|
+
if (nested) return {
|
|
339
|
+
oldNode: nested.oldNode,
|
|
340
|
+
newNode: nested.newNode
|
|
341
|
+
};
|
|
342
|
+
return {
|
|
343
|
+
oldNode: decorateSubtree(oldNode, "delete"),
|
|
344
|
+
newNode: decorateSubtree(newNode, "insert")
|
|
345
|
+
};
|
|
358
346
|
}
|
|
359
347
|
function computeDiff(oldState, newState) {
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
}
|
|
399
|
-
return hunks;
|
|
348
|
+
const ops = alignNodes(oldState.root.children, newState.root.children);
|
|
349
|
+
const hunks = [];
|
|
350
|
+
for (const op of ops) switch (op.kind) {
|
|
351
|
+
case "equal": {
|
|
352
|
+
const last = hunks.at(-1);
|
|
353
|
+
if (last && last.type === "equal") last.nodes.push(op.node);
|
|
354
|
+
else hunks.push({
|
|
355
|
+
type: "equal",
|
|
356
|
+
nodes: [op.node]
|
|
357
|
+
});
|
|
358
|
+
break;
|
|
359
|
+
}
|
|
360
|
+
case "modify":
|
|
361
|
+
{
|
|
362
|
+
const inline = diffModifiedNode(op.oldNode, op.newNode);
|
|
363
|
+
hunks.push({
|
|
364
|
+
type: "delete",
|
|
365
|
+
nodes: [inline.oldNode]
|
|
366
|
+
}, {
|
|
367
|
+
type: "insert",
|
|
368
|
+
nodes: [inline.newNode]
|
|
369
|
+
});
|
|
370
|
+
}
|
|
371
|
+
break;
|
|
372
|
+
case "delete":
|
|
373
|
+
hunks.push({
|
|
374
|
+
type: "delete",
|
|
375
|
+
nodes: [decorateSubtree(op.node, "delete")]
|
|
376
|
+
});
|
|
377
|
+
break;
|
|
378
|
+
case "insert":
|
|
379
|
+
hunks.push({
|
|
380
|
+
type: "insert",
|
|
381
|
+
nodes: [decorateSubtree(op.node, "insert")]
|
|
382
|
+
});
|
|
383
|
+
break;
|
|
384
|
+
}
|
|
385
|
+
return hunks;
|
|
400
386
|
}
|
|
387
|
+
//#endregion
|
|
388
|
+
//#region src/RichDiff.tsx
|
|
401
389
|
function buildRows(hunks) {
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
390
|
+
const rows = [];
|
|
391
|
+
let i = 0;
|
|
392
|
+
while (i < hunks.length) {
|
|
393
|
+
const hunk = hunks[i];
|
|
394
|
+
if (hunk.type === "equal") {
|
|
395
|
+
rows.push({
|
|
396
|
+
left: hunk,
|
|
397
|
+
right: hunk
|
|
398
|
+
});
|
|
399
|
+
i++;
|
|
400
|
+
} else {
|
|
401
|
+
const deletes = [];
|
|
402
|
+
const inserts = [];
|
|
403
|
+
while (i < hunks.length && hunks[i].type !== "equal") {
|
|
404
|
+
if (hunks[i].type === "delete") deletes.push(hunks[i]);
|
|
405
|
+
else inserts.push(hunks[i]);
|
|
406
|
+
i++;
|
|
407
|
+
}
|
|
408
|
+
const maxLen = Math.max(deletes.length, inserts.length);
|
|
409
|
+
for (let k = 0; k < maxLen; k++) rows.push({
|
|
410
|
+
left: k < deletes.length ? deletes[k] : null,
|
|
411
|
+
right: k < inserts.length ? inserts[k] : null
|
|
412
|
+
});
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
return rows;
|
|
427
416
|
}
|
|
428
417
|
function wrapDoc(nodes) {
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
}
|
|
438
|
-
};
|
|
418
|
+
return { root: {
|
|
419
|
+
children: nodes,
|
|
420
|
+
direction: "ltr",
|
|
421
|
+
format: "",
|
|
422
|
+
indent: 0,
|
|
423
|
+
type: "root",
|
|
424
|
+
version: 1
|
|
425
|
+
} };
|
|
439
426
|
}
|
|
440
|
-
function HunkRenderer({
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
return /* @__PURE__ */ jsx(
|
|
449
|
-
RichRenderer,
|
|
450
|
-
{
|
|
451
|
-
extraNodes,
|
|
452
|
-
rendererConfig,
|
|
453
|
-
theme,
|
|
454
|
-
value: doc,
|
|
455
|
-
variant
|
|
456
|
-
}
|
|
457
|
-
);
|
|
427
|
+
function HunkRenderer({ hunk, variant, theme, rendererConfig, extraNodes }) {
|
|
428
|
+
return /* @__PURE__ */ jsx(RichRenderer, {
|
|
429
|
+
extraNodes,
|
|
430
|
+
rendererConfig,
|
|
431
|
+
theme,
|
|
432
|
+
value: useMemo(() => wrapDoc(hunk.nodes), [hunk.nodes]),
|
|
433
|
+
variant
|
|
434
|
+
});
|
|
458
435
|
}
|
|
459
|
-
function RichDiff({
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
}
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
436
|
+
function RichDiff({ oldValue, newValue, variant = "article", theme = "light", rendererConfig, extraNodes, className }) {
|
|
437
|
+
const hunks = useMemo(() => computeDiff(oldValue, newValue), [oldValue, newValue]);
|
|
438
|
+
const rows = useMemo(() => buildRows(hunks), [hunks]);
|
|
439
|
+
const rendererProps = {
|
|
440
|
+
variant,
|
|
441
|
+
theme,
|
|
442
|
+
rendererConfig,
|
|
443
|
+
extraNodes
|
|
444
|
+
};
|
|
445
|
+
const variantClass = getVariantClass(variant);
|
|
446
|
+
return /* @__PURE__ */ jsx(PortalThemeProvider, {
|
|
447
|
+
className: variantClass,
|
|
448
|
+
theme,
|
|
449
|
+
children: /* @__PURE__ */ jsx(ColorSchemeProvider, {
|
|
450
|
+
colorScheme: theme,
|
|
451
|
+
children: /* @__PURE__ */ jsx("div", {
|
|
452
|
+
className: variantClass,
|
|
453
|
+
style: {
|
|
454
|
+
width: "100%",
|
|
455
|
+
maxWidth: "100%"
|
|
456
|
+
},
|
|
457
|
+
children: /* @__PURE__ */ jsxs("div", {
|
|
458
|
+
className: `${root} ${className ?? ""}`.trim(),
|
|
459
|
+
children: [/* @__PURE__ */ jsxs("div", {
|
|
460
|
+
className: header,
|
|
461
|
+
children: [/* @__PURE__ */ jsx("div", {
|
|
462
|
+
className: `${headerCell} ${headerOld}`,
|
|
463
|
+
children: "Old"
|
|
464
|
+
}), /* @__PURE__ */ jsx("div", {
|
|
465
|
+
className: headerCell,
|
|
466
|
+
children: "New"
|
|
467
|
+
})]
|
|
468
|
+
}), /* @__PURE__ */ jsx("div", {
|
|
469
|
+
className: body,
|
|
470
|
+
children: rows.map((row$1, i) => /* @__PURE__ */ jsxs("div", {
|
|
471
|
+
className: row,
|
|
472
|
+
children: [/* @__PURE__ */ jsx("div", {
|
|
473
|
+
className: `${cell} ${cellOld} ${row$1.left ? row$1.left.type === "delete" ? delete_ : "" : empty}`.trim(),
|
|
474
|
+
children: row$1.left && /* @__PURE__ */ jsx(HunkRenderer, {
|
|
475
|
+
hunk: row$1.left,
|
|
476
|
+
...rendererProps
|
|
477
|
+
})
|
|
478
|
+
}), /* @__PURE__ */ jsx("div", {
|
|
479
|
+
className: `${cell} ${row$1.right ? row$1.right.type === "insert" ? insert : "" : empty}`.trim(),
|
|
480
|
+
children: row$1.right && /* @__PURE__ */ jsx(HunkRenderer, {
|
|
481
|
+
hunk: row$1.right,
|
|
482
|
+
...rendererProps
|
|
483
|
+
})
|
|
484
|
+
})]
|
|
485
|
+
}, i))
|
|
486
|
+
})]
|
|
487
|
+
})
|
|
488
|
+
})
|
|
489
|
+
})
|
|
490
|
+
});
|
|
494
491
|
}
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
computeDiff
|
|
498
|
-
};
|
|
492
|
+
//#endregion
|
|
493
|
+
export { RichDiff, computeDiff };
|
package/dist/rich-diff.css
CHANGED
|
@@ -1 +1,2 @@
|
|
|
1
|
-
:root{--rc-text: #000;--rc-text-secondary: #27272a;--rc-text-tertiary: #71717a;--rc-text-quaternary: #a1a1aa;--rc-bg: #ffffff;--rc-bg-secondary: #fafafa;--rc-bg-tertiary: #f4f4f5;--rc-fill: #e8e8ec;--rc-fill-secondary: #eeeeef;--rc-fill-tertiary: #f4f4f6;--rc-fill-quaternary: #f9f9fa;--rc-border: #f4f4f5;--rc-accent: #2563eb;--rc-accent-light: #2563eb20;--rc-link: #2563eb;--rc-code-text: #3f3f46;--rc-code-bg: #f4f4f5;--rc-hr-border: #e4e4e7;--rc-quote-border: #2563eb;--rc-quote-bg: #eff6ff;--rc-alert-info: #006bb7;--rc-alert-warning: #cc5500;--rc-alert-tip: #11cc00;--rc-alert-caution: #cc0011;--rc-alert-important: #5500cc;--rc-max-width: 700px;--rc-shadow-top-bar: 0 8px 30px rgba(0, 0, 0, .12), 0 2px 8px rgba(0, 0, 0, .06);--rc-shadow-modal: 0 10px 15px -3px rgba(0,0,0,.1), 0 4px 6px -4px rgba(0,0,0,.1);--rc-shadow-menu: 0 1px 4px rgba(0,0,0,.04), 0 4px 16px rgba(0,0,0,.08);--rc-space-xs: 4px;--rc-space-sm: 8px;--rc-space-md: 16px;--rc-space-lg: 24px;--rc-space-xl: 32px;--rc-font-family-sans: "PingFang SC", "Microsoft YaHei", "Segoe UI", Roboto, Helvetica, "noto sans sc", "hiragino sans gb", -apple-system, system-ui, sans-serif, Apple Color Emoji, Segoe UI Emoji, Not Color Emoji;--rc-font-family-serif: "Noto Serif CJK SC", "Source Han Serif SC", "Source Han Serif", "source-han-serif-sc", "Songti SC", STSong, "华文宋体", serif;--rc-font-mono: "SF Mono", SFMono-Regular, ui-monospace, "DejaVu Sans Mono", Menlo, Consolas, monospace;--rc-font-size-2xs: .625em;--rc-font-size-xs: .75em;--rc-font-size-sm: .8125em;--rc-font-size-md: .875em;--rc-font-size-lg: 1.25em;--rc-font-size-base: 16px;--rc-font-size-small: 14px;--rc-line-height: 1.7;--rc-line-height-tight: 1.4;--rc-font-family: "PingFang SC", "Microsoft YaHei", "Segoe UI", Roboto, Helvetica, "noto sans sc", "hiragino sans gb", -apple-system, system-ui, sans-serif, Apple Color Emoji, Segoe UI Emoji, Not Color Emoji;--rc-radius-sm: 4px;--rc-radius-md: 8px;--rc-radius-lg: 12px}:root.dark{--rc-text: #fafafa;--rc-text-secondary: #a1a1aa;--rc-text-tertiary: #71717a;--rc-text-quaternary: #52525b;--rc-bg: #09090b;--rc-bg-secondary: #18181b;--rc-bg-tertiary: #27272a;--rc-fill: #2a2a2f;--rc-fill-secondary: #222226;--rc-fill-tertiary: #1b1b1f;--rc-fill-quaternary: #131316;--rc-border: #27272a;--rc-accent: #60a5fa;--rc-accent-light: #60a5fa20;--rc-link: #60a5fa;--rc-code-text: #e4e4e7;--rc-code-bg: #27272a;--rc-hr-border: #27272a;--rc-quote-border: #60a5fa;--rc-quote-bg: #1e3a5f;--rc-alert-info: #7db9e5;--rc-alert-warning: #da864a;--rc-alert-tip: #54da48;--rc-alert-caution: #e16973;--rc-alert-important: #9966e0;--rc-max-width: 700px;--rc-shadow-top-bar: 0 8px 30px rgba(0, 0, 0, .45), 0 2px 8px rgba(0, 0, 0, .3);--rc-shadow-modal: 0 10px 15px -3px rgba(0,0,0,.4), 0 4px 6px -4px rgba(0,0,0,.35);--rc-shadow-menu: 0 1px 4px rgba(0,0,0,.25), 0 4px 16px rgba(0,0,0,.4);--rc-space-xs: 4px;--rc-space-sm: 8px;--rc-space-md: 16px;--rc-space-lg: 24px;--rc-space-xl: 32px;--rc-font-family-sans: "PingFang SC", "Microsoft YaHei", "Segoe UI", Roboto, Helvetica, "noto sans sc", "hiragino sans gb", -apple-system, system-ui, sans-serif, Apple Color Emoji, Segoe UI Emoji, Not Color Emoji;--rc-font-family-serif: "Noto Serif CJK SC", "Source Han Serif SC", "Source Han Serif", "source-han-serif-sc", "Songti SC", STSong, "华文宋体", serif;--rc-font-mono: "SF Mono", SFMono-Regular, ui-monospace, "DejaVu Sans Mono", Menlo, Consolas, monospace;--rc-font-size-2xs: .625em;--rc-font-size-xs: .75em;--rc-font-size-sm: .8125em;--rc-font-size-md: .875em;--rc-font-size-lg: 1.25em;--rc-font-size-base: 16px;--rc-font-size-small: 14px;--rc-line-height: 1.7;--rc-line-height-tight: 1.4;--rc-font-family: "PingFang SC", "Microsoft YaHei", "Segoe UI", Roboto, Helvetica, "noto sans sc", "hiragino sans gb", -apple-system, system-ui, sans-serif, Apple Color Emoji, Segoe UI Emoji, Not Color Emoji;--rc-radius-sm: 4px;--rc-radius-md: 8px;--rc-radius-lg: 12px}.pvevj00{--rc-text: #000;--rc-text-secondary: #27272a;--rc-text-tertiary: #71717a;--rc-text-quaternary: #a1a1aa;--rc-bg: #ffffff;--rc-bg-secondary: #fafafa;--rc-bg-tertiary: #f4f4f5;--rc-fill: #e8e8ec;--rc-fill-secondary: #eeeeef;--rc-fill-tertiary: #f4f4f6;--rc-fill-quaternary: #f9f9fa;--rc-border: #f4f4f5;--rc-accent: #2563eb;--rc-accent-light: #2563eb20;--rc-link: #2563eb;--rc-code-text: #3f3f46;--rc-code-bg: #f4f4f5;--rc-hr-border: #e4e4e7;--rc-quote-border: #2563eb;--rc-quote-bg: #eff6ff;--rc-alert-info: #006bb7;--rc-alert-warning: #cc5500;--rc-alert-tip: #11cc00;--rc-alert-caution: #cc0011;--rc-alert-important: #5500cc;--rc-max-width: 700px;--rc-shadow-top-bar: 0 8px 30px rgba(0, 0, 0, .12), 0 2px 8px rgba(0, 0, 0, .06);--rc-shadow-modal: 0 10px 15px -3px rgba(0,0,0,.1), 0 4px 6px -4px rgba(0,0,0,.1);--rc-shadow-menu: 0 1px 4px rgba(0,0,0,.04), 0 4px 16px rgba(0,0,0,.08);--rc-space-xs: 4px;--rc-space-sm: 8px;--rc-space-md: 16px;--rc-space-lg: 24px;--rc-space-xl: 32px;--rc-font-family-sans: "PingFang SC", "Microsoft YaHei", "Segoe UI", Roboto, Helvetica, "noto sans sc", "hiragino sans gb", -apple-system, system-ui, sans-serif, Apple Color Emoji, Segoe UI Emoji, Not Color Emoji;--rc-font-family-serif: "Noto Serif CJK SC", "Source Han Serif SC", "Source Han Serif", "source-han-serif-sc", "Songti SC", STSong, "华文宋体", serif;--rc-font-mono: "SF Mono", SFMono-Regular, ui-monospace, "DejaVu Sans Mono", Menlo, Consolas, monospace;--rc-font-size-2xs: .625em;--rc-font-size-xs: .75em;--rc-font-size-sm: .8125em;--rc-font-size-md: .875em;--rc-font-size-lg: 1.25em;--rc-font-size-base: 16px;--rc-font-size-small: 14px;--rc-line-height: 1.7;--rc-line-height-tight: 1.4;--rc-font-family: "PingFang SC", "Microsoft YaHei", "Segoe UI", Roboto, Helvetica, "noto sans sc", "hiragino sans gb", -apple-system, system-ui, sans-serif, Apple Color Emoji, Segoe UI Emoji, Not Color Emoji;--rc-radius-sm: 4px;--rc-radius-md: 8px;--rc-radius-lg: 12px}.pvevj01{--rc-text: #000;--rc-text-secondary: #27272a;--rc-text-tertiary: #71717a;--rc-text-quaternary: #a1a1aa;--rc-bg: #ffffff;--rc-bg-secondary: #fafafa;--rc-bg-tertiary: #f4f4f5;--rc-fill: #e8e8ec;--rc-fill-secondary: #eeeeef;--rc-fill-tertiary: #f4f4f6;--rc-fill-quaternary: #f9f9fa;--rc-border: #f4f4f5;--rc-accent: #2563eb;--rc-accent-light: #2563eb20;--rc-link: #2563eb;--rc-code-text: #3f3f46;--rc-code-bg: #f4f4f5;--rc-hr-border: #e4e4e7;--rc-quote-border: #2563eb;--rc-quote-bg: #eff6ff;--rc-alert-info: #006bb7;--rc-alert-warning: #cc5500;--rc-alert-tip: #11cc00;--rc-alert-caution: #cc0011;--rc-alert-important: #5500cc;--rc-max-width: 700px;--rc-shadow-top-bar: 0 8px 30px rgba(0, 0, 0, .12), 0 2px 8px rgba(0, 0, 0, .06);--rc-shadow-modal: 0 10px 15px -3px rgba(0,0,0,.1), 0 4px 6px -4px rgba(0,0,0,.1);--rc-shadow-menu: 0 1px 4px rgba(0,0,0,.04), 0 4px 16px rgba(0,0,0,.08);--rc-space-xs: 4px;--rc-space-sm: 8px;--rc-space-md: 16px;--rc-space-lg: 24px;--rc-space-xl: 32px;--rc-font-family-sans: "PingFang SC", "Microsoft YaHei", "Segoe UI", Roboto, Helvetica, "noto sans sc", "hiragino sans gb", -apple-system, system-ui, sans-serif, Apple Color Emoji, Segoe UI Emoji, Not Color Emoji;--rc-font-family-serif: "Noto Serif CJK SC", "Source Han Serif SC", "Source Han Serif", "source-han-serif-sc", "Songti SC", STSong, "华文宋体", serif;--rc-font-mono: "SF Mono", SFMono-Regular, ui-monospace, "DejaVu Sans Mono", Menlo, Consolas, monospace;--rc-font-size-2xs: .625em;--rc-font-size-xs: .75em;--rc-font-size-sm: .8125em;--rc-font-size-md: .875em;--rc-font-size-lg: 1.25em;--rc-font-size-base: 16px;--rc-font-size-small: 14px;--rc-line-height: 1.8;--rc-line-height-tight: 1.4;--rc-font-family: "Noto Serif CJK SC", "Source Han Serif SC", "Source Han Serif", "source-han-serif-sc", "Songti SC", STSong, "华文宋体", serif;--rc-radius-sm: 4px;--rc-radius-md: 8px;--rc-radius-lg: 12px}.pvevj02{--rc-text: #000;--rc-text-secondary: #27272a;--rc-text-tertiary: #71717a;--rc-text-quaternary: #a1a1aa;--rc-bg: #ffffff;--rc-bg-secondary: #fafafa;--rc-bg-tertiary: #f4f4f5;--rc-fill: #e8e8ec;--rc-fill-secondary: #eeeeef;--rc-fill-tertiary: #f4f4f6;--rc-fill-quaternary: #f9f9fa;--rc-border: #f4f4f5;--rc-accent: #2563eb;--rc-accent-light: #2563eb20;--rc-link: #2563eb;--rc-code-text: #3f3f46;--rc-code-bg: #f4f4f5;--rc-hr-border: #e4e4e7;--rc-quote-border: #a1a1aa;--rc-quote-bg: #fafafa;--rc-alert-info: #006bb7;--rc-alert-warning: #cc5500;--rc-alert-tip: #11cc00;--rc-alert-caution: #cc0011;--rc-alert-important: #5500cc;--rc-max-width: none;--rc-shadow-top-bar: 0 8px 30px rgba(0, 0, 0, .12), 0 2px 8px rgba(0, 0, 0, .06);--rc-shadow-modal: 0 10px 15px -3px rgba(0,0,0,.1), 0 4px 6px -4px rgba(0,0,0,.1);--rc-shadow-menu: 0 1px 4px rgba(0,0,0,.04), 0 4px 16px rgba(0,0,0,.08);--rc-space-xs: 2px;--rc-space-sm: 4px;--rc-space-md: 10px;--rc-space-lg: 16px;--rc-space-xl: 20px;--rc-font-family-sans: "PingFang SC", "Microsoft YaHei", "Segoe UI", Roboto, Helvetica, "noto sans sc", "hiragino sans gb", -apple-system, system-ui, sans-serif, Apple Color Emoji, Segoe UI Emoji, Not Color Emoji;--rc-font-family-serif: "Noto Serif CJK SC", "Source Han Serif SC", "Source Han Serif", "source-han-serif-sc", "Songti SC", STSong, "华文宋体", serif;--rc-font-mono: "SF Mono", SFMono-Regular, ui-monospace, "DejaVu Sans Mono", Menlo, Consolas, monospace;--rc-font-size-2xs: .625em;--rc-font-size-xs: .75em;--rc-font-size-sm: .8125em;--rc-font-size-md: .875em;--rc-font-size-lg: 1.25em;--rc-font-size-base: 14px;--rc-font-size-small: 12px;--rc-line-height: 1.5;--rc-line-height-tight: 1.3;--rc-font-family: "PingFang SC", "Microsoft YaHei", "Segoe UI", Roboto, Helvetica, "noto sans sc", "hiragino sans gb", -apple-system, system-ui, sans-serif, Apple Color Emoji, Segoe UI Emoji, Not Color Emoji;--rc-radius-sm: 3px;--rc-radius-md: 6px;--rc-radius-lg: 12px}.dark .pvevj00,[data-theme=dark] .pvevj00,.dark.pvevj00,[data-theme=dark].pvevj00,.dark .pvevj01,[data-theme=dark] .pvevj01,.dark.pvevj01,[data-theme=dark].pvevj01,.dark .pvevj02,[data-theme=dark] .pvevj02,.dark.pvevj02,[data-theme=dark].pvevj02{--rc-text: #fafafa;--rc-text-secondary: #a1a1aa;--rc-text-tertiary: #71717a;--rc-text-quaternary: #52525b;--rc-bg: #09090b;--rc-bg-secondary: #18181b;--rc-bg-tertiary: #27272a;--rc-fill: #2a2a2f;--rc-fill-secondary: #222226;--rc-fill-tertiary: #1b1b1f;--rc-fill-quaternary: #131316;--rc-border: #27272a;--rc-accent: #60a5fa;--rc-accent-light: #60a5fa20;--rc-link: #60a5fa;--rc-code-text: #e4e4e7;--rc-code-bg: #27272a;--rc-hr-border: #27272a;--rc-quote-border: #60a5fa;--rc-quote-bg: #1e3a5f;--rc-alert-info: #7db9e5;--rc-alert-warning: #da864a;--rc-alert-tip: #54da48;--rc-alert-caution: #e16973;--rc-alert-important: #9966e0;--rc-shadow-top-bar: 0 8px 30px rgba(0, 0, 0, .45), 0 2px 8px rgba(0, 0, 0, .3);--rc-shadow-modal: 0 10px 15px -3px rgba(0,0,0,.4), 0 4px 6px -4px rgba(0,0,0,.35);--rc-shadow-menu: 0 1px 4px rgba(0,0,0,.25), 0 4px 16px rgba(0,0,0,.4)}.xcvddd0{border:1px solid var(--rc-border);border-radius:6px;overflow:hidden;font-size:14px}.xcvddd1{display:grid;grid-template-columns:1fr 1fr;border-bottom:1px solid var(--rc-border);background:var(--rc-bg-secondary)}.xcvddd2{padding:8px 16px;font-weight:600;font-size:12px;text-transform:uppercase;letter-spacing:.05em;color:var(--rc-text-secondary)}.xcvddd3{border-right:1px solid var(--rc-border)}.xcvddd4{display:flex;flex-direction:column}.xcvddd5{display:grid;grid-template-columns:1fr 1fr;border-bottom:1px solid var(--rc-border)}.xcvddd5:last-child{border-bottom:none}.xcvddd6{padding:4px 12px;min-height:32px;overflow:hidden}.xcvddd7{border-right:1px solid var(--rc-border)}.xcvddd8{background-color:color-mix(in srgb,var(--rc-alert-caution) 15%,transparent)}.xcvddd9{background-color:color-mix(in srgb,var(--rc-alert-tip) 15%,transparent)}.xcvddda{background-color:var(--rc-bg-secondary)}.xcvddd8 .rich-content__body{opacity:.85}
|
|
1
|
+
:root{--rc-text:#000;--rc-text-secondary:#27272a;--rc-text-tertiary:#71717a;--rc-text-quaternary:#a1a1aa;--rc-bg:#fff;--rc-bg-secondary:#fafafa;--rc-bg-tertiary:#f4f4f5;--rc-fill:#e8e8ec;--rc-fill-secondary:#eeeeef;--rc-fill-tertiary:#f4f4f6;--rc-fill-quaternary:#f9f9fa;--rc-border:#f4f4f5;--rc-accent:#2563eb;--rc-accent-light:#2563eb20;--rc-link:#2563eb;--rc-code-text:#3f3f46;--rc-code-bg:#f4f4f5;--rc-hr-border:#e4e4e7;--rc-quote-border:#2563eb;--rc-quote-bg:#eff6ff;--rc-alert-info:#006bb7;--rc-alert-warning:#c50;--rc-alert-tip:#1c0;--rc-alert-caution:#c01;--rc-alert-important:#50c;--rc-max-width:700px;--rc-shadow-top-bar:0 8px 30px #0000001f, 0 2px 8px #0000000f;--rc-shadow-modal:0 10px 15px -3px #0000001a, 0 4px 6px -4px #0000001a;--rc-shadow-menu:0 1px 4px #0000000a, 0 4px 16px #00000014;--rc-space-xs:4px;--rc-space-sm:8px;--rc-space-md:16px;--rc-space-lg:24px;--rc-space-xl:32px;--rc-font-family-sans:"PingFang SC", "Microsoft YaHei", "Segoe UI", Roboto, Helvetica, "noto sans sc", "hiragino sans gb", -apple-system, system-ui, sans-serif, Apple Color Emoji, Segoe UI Emoji, Not Color Emoji;--rc-font-family-serif:"Noto Serif CJK SC", "Source Han Serif SC", "Source Han Serif", "source-han-serif-sc", "Songti SC", STSong, "华文宋体", serif;--rc-font-mono:"SF Mono", SFMono-Regular, ui-monospace, "DejaVu Sans Mono", Menlo, Consolas, monospace;--rc-font-size-2xs:.625em;--rc-font-size-xs:.75em;--rc-font-size-sm:.8125em;--rc-font-size-md:.875em;--rc-font-size-lg:1.25em;--rc-font-size-base:16px;--rc-font-size-small:14px;--rc-line-height:1.7;--rc-line-height-tight:1.4;--rc-font-family:"PingFang SC", "Microsoft YaHei", "Segoe UI", Roboto, Helvetica, "noto sans sc", "hiragino sans gb", -apple-system, system-ui, sans-serif, Apple Color Emoji, Segoe UI Emoji, Not Color Emoji;--rc-radius-sm:4px;--rc-radius-md:8px;--rc-radius-lg:12px}:root.dark{--rc-text:#fafafa;--rc-text-secondary:#a1a1aa;--rc-text-tertiary:#71717a;--rc-text-quaternary:#52525b;--rc-bg:#09090b;--rc-bg-secondary:#18181b;--rc-bg-tertiary:#27272a;--rc-fill:#2a2a2f;--rc-fill-secondary:#222226;--rc-fill-tertiary:#1b1b1f;--rc-fill-quaternary:#131316;--rc-border:#27272a;--rc-accent:#60a5fa;--rc-accent-light:#60a5fa20;--rc-link:#60a5fa;--rc-code-text:#e4e4e7;--rc-code-bg:#27272a;--rc-hr-border:#27272a;--rc-quote-border:#60a5fa;--rc-quote-bg:#1e3a5f;--rc-alert-info:#7db9e5;--rc-alert-warning:#da864a;--rc-alert-tip:#54da48;--rc-alert-caution:#e16973;--rc-alert-important:#9966e0;--rc-max-width:700px;--rc-shadow-top-bar:0 8px 30px #00000073, 0 2px 8px #0000004d;--rc-shadow-modal:0 10px 15px -3px #0006, 0 4px 6px -4px #00000059;--rc-shadow-menu:0 1px 4px #00000040, 0 4px 16px #0006;--rc-space-xs:4px;--rc-space-sm:8px;--rc-space-md:16px;--rc-space-lg:24px;--rc-space-xl:32px;--rc-font-family-sans:"PingFang SC", "Microsoft YaHei", "Segoe UI", Roboto, Helvetica, "noto sans sc", "hiragino sans gb", -apple-system, system-ui, sans-serif, Apple Color Emoji, Segoe UI Emoji, Not Color Emoji;--rc-font-family-serif:"Noto Serif CJK SC", "Source Han Serif SC", "Source Han Serif", "source-han-serif-sc", "Songti SC", STSong, "华文宋体", serif;--rc-font-mono:"SF Mono", SFMono-Regular, ui-monospace, "DejaVu Sans Mono", Menlo, Consolas, monospace;--rc-font-size-2xs:.625em;--rc-font-size-xs:.75em;--rc-font-size-sm:.8125em;--rc-font-size-md:.875em;--rc-font-size-lg:1.25em;--rc-font-size-base:16px;--rc-font-size-small:14px;--rc-line-height:1.7;--rc-line-height-tight:1.4;--rc-font-family:"PingFang SC", "Microsoft YaHei", "Segoe UI", Roboto, Helvetica, "noto sans sc", "hiragino sans gb", -apple-system, system-ui, sans-serif, Apple Color Emoji, Segoe UI Emoji, Not Color Emoji;--rc-radius-sm:4px;--rc-radius-md:8px;--rc-radius-lg:12px}.pvevj00{--rc-text:#000;--rc-text-secondary:#27272a;--rc-text-tertiary:#71717a;--rc-text-quaternary:#a1a1aa;--rc-bg:#fff;--rc-bg-secondary:#fafafa;--rc-bg-tertiary:#f4f4f5;--rc-fill:#e8e8ec;--rc-fill-secondary:#eeeeef;--rc-fill-tertiary:#f4f4f6;--rc-fill-quaternary:#f9f9fa;--rc-border:#f4f4f5;--rc-accent:#2563eb;--rc-accent-light:#2563eb20;--rc-link:#2563eb;--rc-code-text:#3f3f46;--rc-code-bg:#f4f4f5;--rc-hr-border:#e4e4e7;--rc-quote-border:#2563eb;--rc-quote-bg:#eff6ff;--rc-alert-info:#006bb7;--rc-alert-warning:#c50;--rc-alert-tip:#1c0;--rc-alert-caution:#c01;--rc-alert-important:#50c;--rc-max-width:700px;--rc-shadow-top-bar:0 8px 30px #0000001f, 0 2px 8px #0000000f;--rc-shadow-modal:0 10px 15px -3px #0000001a, 0 4px 6px -4px #0000001a;--rc-shadow-menu:0 1px 4px #0000000a, 0 4px 16px #00000014;--rc-space-xs:4px;--rc-space-sm:8px;--rc-space-md:16px;--rc-space-lg:24px;--rc-space-xl:32px;--rc-font-family-sans:"PingFang SC", "Microsoft YaHei", "Segoe UI", Roboto, Helvetica, "noto sans sc", "hiragino sans gb", -apple-system, system-ui, sans-serif, Apple Color Emoji, Segoe UI Emoji, Not Color Emoji;--rc-font-family-serif:"Noto Serif CJK SC", "Source Han Serif SC", "Source Han Serif", "source-han-serif-sc", "Songti SC", STSong, "华文宋体", serif;--rc-font-mono:"SF Mono", SFMono-Regular, ui-monospace, "DejaVu Sans Mono", Menlo, Consolas, monospace;--rc-font-size-2xs:.625em;--rc-font-size-xs:.75em;--rc-font-size-sm:.8125em;--rc-font-size-md:.875em;--rc-font-size-lg:1.25em;--rc-font-size-base:16px;--rc-font-size-small:14px;--rc-line-height:1.7;--rc-line-height-tight:1.4;--rc-font-family:"PingFang SC", "Microsoft YaHei", "Segoe UI", Roboto, Helvetica, "noto sans sc", "hiragino sans gb", -apple-system, system-ui, sans-serif, Apple Color Emoji, Segoe UI Emoji, Not Color Emoji;--rc-radius-sm:4px;--rc-radius-md:8px;--rc-radius-lg:12px}.pvevj01{--rc-text:#000;--rc-text-secondary:#27272a;--rc-text-tertiary:#71717a;--rc-text-quaternary:#a1a1aa;--rc-bg:#fff;--rc-bg-secondary:#fafafa;--rc-bg-tertiary:#f4f4f5;--rc-fill:#e8e8ec;--rc-fill-secondary:#eeeeef;--rc-fill-tertiary:#f4f4f6;--rc-fill-quaternary:#f9f9fa;--rc-border:#f4f4f5;--rc-accent:#2563eb;--rc-accent-light:#2563eb20;--rc-link:#2563eb;--rc-code-text:#3f3f46;--rc-code-bg:#f4f4f5;--rc-hr-border:#e4e4e7;--rc-quote-border:#2563eb;--rc-quote-bg:#eff6ff;--rc-alert-info:#006bb7;--rc-alert-warning:#c50;--rc-alert-tip:#1c0;--rc-alert-caution:#c01;--rc-alert-important:#50c;--rc-max-width:700px;--rc-shadow-top-bar:0 8px 30px #0000001f, 0 2px 8px #0000000f;--rc-shadow-modal:0 10px 15px -3px #0000001a, 0 4px 6px -4px #0000001a;--rc-shadow-menu:0 1px 4px #0000000a, 0 4px 16px #00000014;--rc-space-xs:4px;--rc-space-sm:8px;--rc-space-md:16px;--rc-space-lg:24px;--rc-space-xl:32px;--rc-font-family-sans:"PingFang SC", "Microsoft YaHei", "Segoe UI", Roboto, Helvetica, "noto sans sc", "hiragino sans gb", -apple-system, system-ui, sans-serif, Apple Color Emoji, Segoe UI Emoji, Not Color Emoji;--rc-font-family-serif:"Noto Serif CJK SC", "Source Han Serif SC", "Source Han Serif", "source-han-serif-sc", "Songti SC", STSong, "华文宋体", serif;--rc-font-mono:"SF Mono", SFMono-Regular, ui-monospace, "DejaVu Sans Mono", Menlo, Consolas, monospace;--rc-font-size-2xs:.625em;--rc-font-size-xs:.75em;--rc-font-size-sm:.8125em;--rc-font-size-md:.875em;--rc-font-size-lg:1.25em;--rc-font-size-base:16px;--rc-font-size-small:14px;--rc-line-height:1.8;--rc-line-height-tight:1.4;--rc-font-family:"Noto Serif CJK SC", "Source Han Serif SC", "Source Han Serif", "source-han-serif-sc", "Songti SC", STSong, "华文宋体", serif;--rc-radius-sm:4px;--rc-radius-md:8px;--rc-radius-lg:12px}.pvevj02{--rc-text:#000;--rc-text-secondary:#27272a;--rc-text-tertiary:#71717a;--rc-text-quaternary:#a1a1aa;--rc-bg:#fff;--rc-bg-secondary:#fafafa;--rc-bg-tertiary:#f4f4f5;--rc-fill:#e8e8ec;--rc-fill-secondary:#eeeeef;--rc-fill-tertiary:#f4f4f6;--rc-fill-quaternary:#f9f9fa;--rc-border:#f4f4f5;--rc-accent:#2563eb;--rc-accent-light:#2563eb20;--rc-link:#2563eb;--rc-code-text:#3f3f46;--rc-code-bg:#f4f4f5;--rc-hr-border:#e4e4e7;--rc-quote-border:#a1a1aa;--rc-quote-bg:#fafafa;--rc-alert-info:#006bb7;--rc-alert-warning:#c50;--rc-alert-tip:#1c0;--rc-alert-caution:#c01;--rc-alert-important:#50c;--rc-max-width:none;--rc-shadow-top-bar:0 8px 30px #0000001f, 0 2px 8px #0000000f;--rc-shadow-modal:0 10px 15px -3px #0000001a, 0 4px 6px -4px #0000001a;--rc-shadow-menu:0 1px 4px #0000000a, 0 4px 16px #00000014;--rc-space-xs:2px;--rc-space-sm:4px;--rc-space-md:10px;--rc-space-lg:16px;--rc-space-xl:20px;--rc-font-family-sans:"PingFang SC", "Microsoft YaHei", "Segoe UI", Roboto, Helvetica, "noto sans sc", "hiragino sans gb", -apple-system, system-ui, sans-serif, Apple Color Emoji, Segoe UI Emoji, Not Color Emoji;--rc-font-family-serif:"Noto Serif CJK SC", "Source Han Serif SC", "Source Han Serif", "source-han-serif-sc", "Songti SC", STSong, "华文宋体", serif;--rc-font-mono:"SF Mono", SFMono-Regular, ui-monospace, "DejaVu Sans Mono", Menlo, Consolas, monospace;--rc-font-size-2xs:.625em;--rc-font-size-xs:.75em;--rc-font-size-sm:.8125em;--rc-font-size-md:.875em;--rc-font-size-lg:1.25em;--rc-font-size-base:14px;--rc-font-size-small:12px;--rc-line-height:1.5;--rc-line-height-tight:1.3;--rc-font-family:"PingFang SC", "Microsoft YaHei", "Segoe UI", Roboto, Helvetica, "noto sans sc", "hiragino sans gb", -apple-system, system-ui, sans-serif, Apple Color Emoji, Segoe UI Emoji, Not Color Emoji;--rc-radius-sm:3px;--rc-radius-md:6px;--rc-radius-lg:12px}.dark .pvevj00,[data-theme=dark] .pvevj00,.dark.pvevj00,[data-theme=dark].pvevj00,.dark .pvevj01,[data-theme=dark] .pvevj01,.dark.pvevj01,[data-theme=dark].pvevj01,.dark .pvevj02,[data-theme=dark] .pvevj02,.dark.pvevj02,[data-theme=dark].pvevj02{--rc-text:#fafafa;--rc-text-secondary:#a1a1aa;--rc-text-tertiary:#71717a;--rc-text-quaternary:#52525b;--rc-bg:#09090b;--rc-bg-secondary:#18181b;--rc-bg-tertiary:#27272a;--rc-fill:#2a2a2f;--rc-fill-secondary:#222226;--rc-fill-tertiary:#1b1b1f;--rc-fill-quaternary:#131316;--rc-border:#27272a;--rc-accent:#60a5fa;--rc-accent-light:#60a5fa20;--rc-link:#60a5fa;--rc-code-text:#e4e4e7;--rc-code-bg:#27272a;--rc-hr-border:#27272a;--rc-quote-border:#60a5fa;--rc-quote-bg:#1e3a5f;--rc-alert-info:#7db9e5;--rc-alert-warning:#da864a;--rc-alert-tip:#54da48;--rc-alert-caution:#e16973;--rc-alert-important:#9966e0;--rc-shadow-top-bar:0 8px 30px #00000073, 0 2px 8px #0000004d;--rc-shadow-modal:0 10px 15px -3px #0006, 0 4px 6px -4px #00000059;--rc-shadow-menu:0 1px 4px #00000040, 0 4px 16px #0006}.xcvddd0{border:1px solid var(--rc-border);border-radius:6px;font-size:14px;overflow:hidden}.xcvddd1{border-bottom:1px solid var(--rc-border);background:var(--rc-bg-secondary);grid-template-columns:1fr 1fr;display:grid}.xcvddd2{text-transform:uppercase;letter-spacing:.05em;color:var(--rc-text-secondary);padding:8px 16px;font-size:12px;font-weight:600}.xcvddd3{border-right:1px solid var(--rc-border)}.xcvddd4{flex-direction:column;display:flex}.xcvddd5{border-bottom:1px solid var(--rc-border);grid-template-columns:1fr 1fr;display:grid}.xcvddd5:last-child{border-bottom:none}.xcvddd6{min-height:32px;padding:4px 12px;overflow:hidden}.xcvddd7{border-right:1px solid var(--rc-border)}.xcvddd8{background-color:color-mix(in srgb, var(--rc-alert-caution) 15%, transparent)}.xcvddd9{background-color:color-mix(in srgb, var(--rc-alert-tip) 15%, transparent)}.xcvddda{background-color:var(--rc-bg-secondary)}.xcvddd8 .rich-content__body{opacity:.85}
|
|
2
|
+
/*$vite$:1*/
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@haklex/rich-diff",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.81",
|
|
4
4
|
"description": "Rich diff editor",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -21,9 +21,9 @@
|
|
|
21
21
|
"dist"
|
|
22
22
|
],
|
|
23
23
|
"dependencies": {
|
|
24
|
-
"@haklex/rich-editor": "0.0.
|
|
25
|
-
"@haklex/rich-static-renderer": "0.0.
|
|
26
|
-
"@haklex/rich-style-token": "0.0.
|
|
24
|
+
"@haklex/rich-editor": "0.0.81",
|
|
25
|
+
"@haklex/rich-static-renderer": "0.0.81",
|
|
26
|
+
"@haklex/rich-style-token": "0.0.81"
|
|
27
27
|
},
|
|
28
28
|
"devDependencies": {
|
|
29
29
|
"@types/react": "^19.2.14",
|