@lobehub/editor 4.3.2 → 4.4.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.
@@ -0,0 +1,22 @@
1
+ import type { SerializedEditorState } from 'lexical';
2
+ import type { CSSProperties, ReactNode } from 'react';
3
+ import type { LexicalDiffBlockRenderer } from './diff/types';
4
+ import type { LexicalRendererProps } from './types';
5
+ export type { LexicalDiffBlockRenderContext, LexicalDiffBlockRenderer, LexicalDiffCell, LexicalDiffRow, LexicalDiffRowKind, } from './diff/types';
6
+ export interface LexicalDiffProps {
7
+ blockRenderers?: Record<string, LexicalDiffBlockRenderer>;
8
+ className?: string;
9
+ extraNodes?: LexicalRendererProps['extraNodes'];
10
+ labels?: {
11
+ new?: ReactNode;
12
+ old?: ReactNode;
13
+ };
14
+ newValue: SerializedEditorState;
15
+ oldValue: SerializedEditorState;
16
+ overrides?: LexicalRendererProps['overrides'];
17
+ renderBlockDiff?: LexicalDiffBlockRenderer;
18
+ renderContext?: LexicalRendererProps['renderContext'];
19
+ style?: CSSProperties;
20
+ variant?: LexicalRendererProps['variant'];
21
+ }
22
+ export declare function LexicalDiff({ oldValue, newValue, variant, extraNodes, overrides, renderContext, labels, blockRenderers, renderBlockDiff, className, style, }: LexicalDiffProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,116 @@
1
+ import { cx } from 'antd-style';
2
+ import { useMemo } from 'react';
3
+ import { LexicalRenderer } from "./LexicalRenderer";
4
+ import { computeLexicalDiffRows } from "./diff/compute";
5
+ import { styles } from "./diff/style";
6
+ import { jsx as _jsx } from "react/jsx-runtime";
7
+ import { jsxs as _jsxs } from "react/jsx-runtime";
8
+ function wrapBlock(block) {
9
+ return {
10
+ root: {
11
+ children: [block],
12
+ direction: 'ltr',
13
+ format: '',
14
+ indent: 0,
15
+ type: 'root',
16
+ version: 1
17
+ }
18
+ };
19
+ }
20
+ function RowCell(_ref) {
21
+ var className = _ref.className,
22
+ content = _ref.content;
23
+ return /*#__PURE__*/_jsx("div", {
24
+ className: className,
25
+ children: content
26
+ });
27
+ }
28
+ export function LexicalDiff(_ref2) {
29
+ var _labels$old, _labels$new;
30
+ var oldValue = _ref2.oldValue,
31
+ newValue = _ref2.newValue,
32
+ _ref2$variant = _ref2.variant,
33
+ variant = _ref2$variant === void 0 ? 'default' : _ref2$variant,
34
+ extraNodes = _ref2.extraNodes,
35
+ overrides = _ref2.overrides,
36
+ renderContext = _ref2.renderContext,
37
+ labels = _ref2.labels,
38
+ blockRenderers = _ref2.blockRenderers,
39
+ renderBlockDiff = _ref2.renderBlockDiff,
40
+ className = _ref2.className,
41
+ style = _ref2.style;
42
+ var rows = useMemo(function () {
43
+ return computeLexicalDiffRows(oldValue, newValue);
44
+ }, [oldValue, newValue]);
45
+ var renderDefaultCell = function renderDefaultCell(block) {
46
+ if (!block) return null;
47
+ return /*#__PURE__*/_jsx(LexicalRenderer, {
48
+ extraNodes: extraNodes,
49
+ overrides: overrides,
50
+ renderContext: renderContext,
51
+ value: wrapBlock(block),
52
+ variant: variant
53
+ });
54
+ };
55
+ var renderRow = function renderRow(row, index) {
56
+ var _row$oldCell, _row$newCell, _ref3, _row$oldCell$blockTyp, _row$oldCell2, _row$newCell2, _row$oldCell3, _row$newCell3, _ref4, _row$oldCell$baseBloc, _row$oldCell4, _row$newCell4, _row$newCell$baseBloc, _row$newCell5, _row$newCell$blockTyp, _row$newCell6, _row$oldCell$baseBloc2, _row$oldCell5, _row$oldCell$blockTyp2, _row$oldCell6, _rendered$old, _rendered, _rendered$new, _rendered2;
57
+ var blockType = (_row$oldCell = row.oldCell) !== null && _row$oldCell !== void 0 && _row$oldCell.blockType && (_row$newCell = row.newCell) !== null && _row$newCell !== void 0 && _row$newCell.blockType ? row.oldCell.blockType === row.newCell.blockType ? row.oldCell.blockType : null : (_ref3 = (_row$oldCell$blockTyp = (_row$oldCell2 = row.oldCell) === null || _row$oldCell2 === void 0 ? void 0 : _row$oldCell2.blockType) !== null && _row$oldCell$blockTyp !== void 0 ? _row$oldCell$blockTyp : (_row$newCell2 = row.newCell) === null || _row$newCell2 === void 0 ? void 0 : _row$newCell2.blockType) !== null && _ref3 !== void 0 ? _ref3 : null;
58
+ var baseBlockType = (_row$oldCell3 = row.oldCell) !== null && _row$oldCell3 !== void 0 && _row$oldCell3.baseBlockType && (_row$newCell3 = row.newCell) !== null && _row$newCell3 !== void 0 && _row$newCell3.baseBlockType ? row.oldCell.baseBlockType === row.newCell.baseBlockType ? row.oldCell.baseBlockType : null : (_ref4 = (_row$oldCell$baseBloc = (_row$oldCell4 = row.oldCell) === null || _row$oldCell4 === void 0 ? void 0 : _row$oldCell4.baseBlockType) !== null && _row$oldCell$baseBloc !== void 0 ? _row$oldCell$baseBloc : (_row$newCell4 = row.newCell) === null || _row$newCell4 === void 0 ? void 0 : _row$newCell4.baseBlockType) !== null && _ref4 !== void 0 ? _ref4 : null;
59
+ var context = {
60
+ baseBlockType: baseBlockType,
61
+ blockType: blockType,
62
+ newBaseBlockType: (_row$newCell$baseBloc = (_row$newCell5 = row.newCell) === null || _row$newCell5 === void 0 ? void 0 : _row$newCell5.baseBlockType) !== null && _row$newCell$baseBloc !== void 0 ? _row$newCell$baseBloc : null,
63
+ newBlockType: (_row$newCell$blockTyp = (_row$newCell6 = row.newCell) === null || _row$newCell6 === void 0 ? void 0 : _row$newCell6.blockType) !== null && _row$newCell$blockTyp !== void 0 ? _row$newCell$blockTyp : null,
64
+ oldBaseBlockType: (_row$oldCell$baseBloc2 = (_row$oldCell5 = row.oldCell) === null || _row$oldCell5 === void 0 ? void 0 : _row$oldCell5.baseBlockType) !== null && _row$oldCell$baseBloc2 !== void 0 ? _row$oldCell$baseBloc2 : null,
65
+ oldBlockType: (_row$oldCell$blockTyp2 = (_row$oldCell6 = row.oldCell) === null || _row$oldCell6 === void 0 ? void 0 : _row$oldCell6.blockType) !== null && _row$oldCell$blockTyp2 !== void 0 ? _row$oldCell$blockTyp2 : null,
66
+ renderDefaultNew: function renderDefaultNew() {
67
+ var _row$newCell$block, _row$newCell7;
68
+ return renderDefaultCell((_row$newCell$block = (_row$newCell7 = row.newCell) === null || _row$newCell7 === void 0 ? void 0 : _row$newCell7.block) !== null && _row$newCell$block !== void 0 ? _row$newCell$block : null);
69
+ },
70
+ renderDefaultOld: function renderDefaultOld() {
71
+ var _row$oldCell$block, _row$oldCell7;
72
+ return renderDefaultCell((_row$oldCell$block = (_row$oldCell7 = row.oldCell) === null || _row$oldCell7 === void 0 ? void 0 : _row$oldCell7.block) !== null && _row$oldCell$block !== void 0 ? _row$oldCell$block : null);
73
+ },
74
+ row: row
75
+ };
76
+ var renderers = [blockType ? blockRenderers === null || blockRenderers === void 0 ? void 0 : blockRenderers[blockType] : undefined, baseBlockType && baseBlockType !== blockType ? blockRenderers === null || blockRenderers === void 0 ? void 0 : blockRenderers[baseBlockType] : undefined, renderBlockDiff];
77
+ var rendered;
78
+ for (var _i = 0, _renderers = renderers; _i < _renderers.length; _i++) {
79
+ var renderer = _renderers[_i];
80
+ if (!renderer) continue;
81
+ var next = renderer(context);
82
+ if (next === null) continue;
83
+ rendered = next;
84
+ break;
85
+ }
86
+ var oldContent = (_rendered$old = (_rendered = rendered) === null || _rendered === void 0 ? void 0 : _rendered.old) !== null && _rendered$old !== void 0 ? _rendered$old : context.renderDefaultOld();
87
+ var newContent = (_rendered$new = (_rendered2 = rendered) === null || _rendered2 === void 0 ? void 0 : _rendered2.new) !== null && _rendered$new !== void 0 ? _rendered$new : context.renderDefaultNew();
88
+ return /*#__PURE__*/_jsxs("div", {
89
+ className: styles.row,
90
+ children: [/*#__PURE__*/_jsx(RowCell, {
91
+ className: cx(styles.cell, styles.cellOld, !row.oldCell && styles.emptyCell, row.kind === 'delete' && styles.deleteCell),
92
+ content: oldContent
93
+ }), /*#__PURE__*/_jsx(RowCell, {
94
+ className: cx(styles.cell, !row.newCell && styles.emptyCell, row.kind === 'insert' && styles.insertCell),
95
+ content: newContent
96
+ })]
97
+ }, "row-".concat(index));
98
+ };
99
+ return /*#__PURE__*/_jsxs("div", {
100
+ className: cx(styles.root, className),
101
+ style: style,
102
+ children: [/*#__PURE__*/_jsxs("div", {
103
+ className: styles.header,
104
+ children: [/*#__PURE__*/_jsx("div", {
105
+ className: cx(styles.headerCell, styles.headerOld),
106
+ children: (_labels$old = labels === null || labels === void 0 ? void 0 : labels.old) !== null && _labels$old !== void 0 ? _labels$old : 'Old'
107
+ }), /*#__PURE__*/_jsx("div", {
108
+ className: styles.headerCell,
109
+ children: (_labels$new = labels === null || labels === void 0 ? void 0 : labels.new) !== null && _labels$new !== void 0 ? _labels$new : 'New'
110
+ })]
111
+ }), /*#__PURE__*/_jsx("div", {
112
+ className: styles.body,
113
+ children: rows.map(renderRow)
114
+ })]
115
+ });
116
+ }
@@ -0,0 +1,3 @@
1
+ import type { SerializedEditorState } from 'lexical';
2
+ import type { LexicalDiffRow } from './types';
3
+ export declare function computeLexicalDiffRows(oldState: SerializedEditorState, newState: SerializedEditorState): LexicalDiffRow[];
@@ -0,0 +1,510 @@
1
+ function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); }
2
+ function _toConsumableArray(arr) { return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray(arr) || _nonIterableSpread(); }
3
+ function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
4
+ function _iterableToArray(iter) { if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) return Array.from(iter); }
5
+ function _arrayWithoutHoles(arr) { if (Array.isArray(arr)) return _arrayLikeToArray(arr); }
6
+ function _createForOfIteratorHelper(o, allowArrayLike) { var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"]; if (!it) { if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e) { throw _e; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = it.call(o); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e2) { didErr = true; err = _e2; }, f: function f() { try { if (!normalCompletion && it.return != null) it.return(); } finally { if (didErr) throw err; } } }; }
7
+ function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
8
+ function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i]; return arr2; }
9
+ function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
10
+ function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
11
+ function _defineProperty(obj, key, value) { key = _toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
12
+ function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == _typeof(i) ? i : String(i); }
13
+ function _toPrimitive(t, r) { if ("object" != _typeof(t) || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != _typeof(i)) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
14
+ var CHAR_DIFF_MAX_MATRIX_CELLS = 50000;
15
+ var DELETE_MARK_STYLE = 'background-color: color-mix(in srgb, var(--ant-color-error) 18%, transparent); text-decoration: line-through;';
16
+ var INSERT_MARK_STYLE = 'background-color: color-mix(in srgb, var(--ant-color-success) 18%, transparent);';
17
+ function getBaseNodeType(node) {
18
+ if (!node) return null;
19
+ var type = node.type;
20
+ return typeof type === 'string' ? type : null;
21
+ }
22
+ function getNormalizedBlockType(node) {
23
+ if (!node) return null;
24
+ var record = node;
25
+ var type = getBaseNodeType(node);
26
+ if (!type) return null;
27
+ if (type === 'heading') return "heading:".concat(String(record.tag || 'unknown'));
28
+ if (type === 'list') return "list:".concat(String(record.listType || 'bullet'));
29
+ return type;
30
+ }
31
+ function createCell(block) {
32
+ if (!block) return null;
33
+ return {
34
+ baseBlockType: getBaseNodeType(block),
35
+ block: block,
36
+ blockType: getNormalizedBlockType(block)
37
+ };
38
+ }
39
+ function getChildren(node) {
40
+ var children = node.children;
41
+ return Array.isArray(children) ? children : null;
42
+ }
43
+ function nodesEqual(a, b) {
44
+ return JSON.stringify(a) === JSON.stringify(b);
45
+ }
46
+ function isTextNode(node) {
47
+ var record = node;
48
+ return record.type === 'text' && typeof record.text === 'string';
49
+ }
50
+ function appendStyle(baseStyle, extraStyle) {
51
+ var normalizedBase = typeof baseStyle === 'string' ? baseStyle.trim() : '';
52
+ if (!normalizedBase) return extraStyle;
53
+ return "".concat(normalizedBase).concat(normalizedBase.endsWith(';') ? '' : ';', " ").concat(extraStyle);
54
+ }
55
+ function cloneTextNode(node, text, markKind) {
56
+ var style = node.style;
57
+ if (markKind === 'delete') {
58
+ style = appendStyle(style, DELETE_MARK_STYLE);
59
+ } else if (markKind === 'insert') {
60
+ style = appendStyle(style, INSERT_MARK_STYLE);
61
+ }
62
+ return _objectSpread(_objectSpread({}, node), {}, {
63
+ style: style,
64
+ text: text
65
+ });
66
+ }
67
+ function cloneNodeWithChildren(node, children) {
68
+ return _objectSpread(_objectSpread({}, node), {}, {
69
+ children: children
70
+ });
71
+ }
72
+ function decorateSubtree(node, kind) {
73
+ if (isTextNode(node)) return cloneTextNode(node, node.text, kind);
74
+ var children = getChildren(node);
75
+ if (!children) return node;
76
+ return cloneNodeWithChildren(node, children.map(function (child) {
77
+ return decorateSubtree(child, kind);
78
+ }));
79
+ }
80
+ function reverseText(value) {
81
+ return Array.from(value).reverse().join('');
82
+ }
83
+ function mergeTextOps(ops) {
84
+ var merged = [];
85
+ var _iterator = _createForOfIteratorHelper(ops),
86
+ _step;
87
+ try {
88
+ for (_iterator.s(); !(_step = _iterator.n()).done;) {
89
+ var op = _step.value;
90
+ if (!op.text) continue;
91
+ var last = merged.at(-1);
92
+ if (last && last.kind === op.kind) {
93
+ last.text += op.text;
94
+ continue;
95
+ }
96
+ merged.push(_objectSpread({}, op));
97
+ }
98
+ } catch (err) {
99
+ _iterator.e(err);
100
+ } finally {
101
+ _iterator.f();
102
+ }
103
+ return merged;
104
+ }
105
+ function diffMiddleChars(oldChars, newChars) {
106
+ var m = oldChars.length;
107
+ var n = newChars.length;
108
+ if (m === 0 && n === 0) return [];
109
+ if (m === 0) return [{
110
+ kind: 'insert',
111
+ text: newChars.join('')
112
+ }];
113
+ if (n === 0) return [{
114
+ kind: 'delete',
115
+ text: oldChars.join('')
116
+ }];
117
+ if (m * n > CHAR_DIFF_MAX_MATRIX_CELLS) {
118
+ return [{
119
+ kind: 'delete',
120
+ text: oldChars.join('')
121
+ }, {
122
+ kind: 'insert',
123
+ text: newChars.join('')
124
+ }];
125
+ }
126
+ var dp = Array.from({
127
+ length: m + 1
128
+ }, function () {
129
+ return Array.from({
130
+ length: n + 1
131
+ }).fill(0);
132
+ });
133
+ for (var _i = 1; _i <= m; _i++) {
134
+ for (var _j = 1; _j <= n; _j++) {
135
+ if (oldChars[_i - 1] === newChars[_j - 1]) {
136
+ dp[_i][_j] = dp[_i - 1][_j - 1] + 1;
137
+ } else {
138
+ dp[_i][_j] = Math.max(dp[_i - 1][_j], dp[_i][_j - 1]);
139
+ }
140
+ }
141
+ }
142
+ var reversedOps = [];
143
+ var i = m;
144
+ var j = n;
145
+ while (i > 0 && j > 0) {
146
+ if (oldChars[i - 1] === newChars[j - 1]) {
147
+ var last = reversedOps.at(-1);
148
+ if (last && last.kind === 'equal') {
149
+ last.text += oldChars[i - 1];
150
+ } else {
151
+ reversedOps.push({
152
+ kind: 'equal',
153
+ text: oldChars[i - 1]
154
+ });
155
+ }
156
+ i--;
157
+ j--;
158
+ continue;
159
+ }
160
+ if (dp[i - 1][j] >= dp[i][j - 1]) {
161
+ var _last = reversedOps.at(-1);
162
+ if (_last && _last.kind === 'delete') {
163
+ _last.text += oldChars[i - 1];
164
+ } else {
165
+ reversedOps.push({
166
+ kind: 'delete',
167
+ text: oldChars[i - 1]
168
+ });
169
+ }
170
+ i--;
171
+ } else {
172
+ var _last2 = reversedOps.at(-1);
173
+ if (_last2 && _last2.kind === 'insert') {
174
+ _last2.text += newChars[j - 1];
175
+ } else {
176
+ reversedOps.push({
177
+ kind: 'insert',
178
+ text: newChars[j - 1]
179
+ });
180
+ }
181
+ j--;
182
+ }
183
+ }
184
+ while (i > 0) {
185
+ var _last3 = reversedOps.at(-1);
186
+ if (_last3 && _last3.kind === 'delete') {
187
+ _last3.text += oldChars[i - 1];
188
+ } else {
189
+ reversedOps.push({
190
+ kind: 'delete',
191
+ text: oldChars[i - 1]
192
+ });
193
+ }
194
+ i--;
195
+ }
196
+ while (j > 0) {
197
+ var _last4 = reversedOps.at(-1);
198
+ if (_last4 && _last4.kind === 'insert') {
199
+ _last4.text += newChars[j - 1];
200
+ } else {
201
+ reversedOps.push({
202
+ kind: 'insert',
203
+ text: newChars[j - 1]
204
+ });
205
+ }
206
+ j--;
207
+ }
208
+ return mergeTextOps(reversedOps.reverse().map(function (op) {
209
+ return {
210
+ kind: op.kind,
211
+ text: reverseText(op.text)
212
+ };
213
+ }));
214
+ }
215
+ function diffTextByChar(oldText, newText) {
216
+ var oldChars = Array.from(oldText);
217
+ var newChars = Array.from(newText);
218
+ var prefix = 0;
219
+ while (prefix < oldChars.length && prefix < newChars.length && oldChars[prefix] === newChars[prefix]) {
220
+ prefix++;
221
+ }
222
+ var oldSuffix = oldChars.length - 1;
223
+ var newSuffix = newChars.length - 1;
224
+ while (oldSuffix >= prefix && newSuffix >= prefix && oldChars[oldSuffix] === newChars[newSuffix]) {
225
+ oldSuffix--;
226
+ newSuffix--;
227
+ }
228
+ var ops = [];
229
+ if (prefix > 0) {
230
+ ops.push({
231
+ kind: 'equal',
232
+ text: oldChars.slice(0, prefix).join('')
233
+ });
234
+ }
235
+ ops.push.apply(ops, _toConsumableArray(diffMiddleChars(oldChars.slice(prefix, oldSuffix + 1), newChars.slice(prefix, newSuffix + 1))));
236
+ if (oldSuffix < oldChars.length - 1) {
237
+ ops.push({
238
+ kind: 'equal',
239
+ text: oldChars.slice(oldSuffix + 1).join('')
240
+ });
241
+ }
242
+ return mergeTextOps(ops);
243
+ }
244
+ function splitTextNodeByCharDiff(oldNode, newNode) {
245
+ var ops = diffTextByChar(oldNode.text, newNode.text);
246
+ var oldNodes = [];
247
+ var newNodes = [];
248
+ var changed = false;
249
+ var _iterator2 = _createForOfIteratorHelper(ops),
250
+ _step2;
251
+ try {
252
+ for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
253
+ var op = _step2.value;
254
+ if (!op.text) continue;
255
+ if (op.kind === 'equal') {
256
+ oldNodes.push(cloneTextNode(oldNode, op.text));
257
+ newNodes.push(cloneTextNode(newNode, op.text));
258
+ continue;
259
+ }
260
+ changed = true;
261
+ if (op.kind === 'delete') {
262
+ oldNodes.push(cloneTextNode(oldNode, op.text, 'delete'));
263
+ continue;
264
+ }
265
+ newNodes.push(cloneTextNode(newNode, op.text, 'insert'));
266
+ }
267
+ } catch (err) {
268
+ _iterator2.e(err);
269
+ } finally {
270
+ _iterator2.f();
271
+ }
272
+ return {
273
+ changed: changed,
274
+ newNodes: newNodes.length > 0 ? newNodes : [newNode],
275
+ oldNodes: oldNodes.length > 0 ? oldNodes : [oldNode]
276
+ };
277
+ }
278
+ function alignNodes(oldNodes, newNodes) {
279
+ var m = oldNodes.length;
280
+ var n = newNodes.length;
281
+ var dp = Array.from({
282
+ length: m + 1
283
+ }, function () {
284
+ return Array.from({
285
+ length: n + 1
286
+ }).fill(0);
287
+ });
288
+ for (var _i2 = 1; _i2 <= m; _i2++) {
289
+ for (var _j2 = 1; _j2 <= n; _j2++) {
290
+ var skip = Math.max(dp[_i2 - 1][_j2], dp[_i2][_j2 - 1]);
291
+ var oldType = getNormalizedBlockType(oldNodes[_i2 - 1]);
292
+ var newType = getNormalizedBlockType(newNodes[_j2 - 1]);
293
+ if (oldType && oldType === newType) {
294
+ var score = nodesEqual(oldNodes[_i2 - 1], newNodes[_j2 - 1]) ? 2 : 1;
295
+ dp[_i2][_j2] = Math.max(skip, dp[_i2 - 1][_j2 - 1] + score);
296
+ } else {
297
+ dp[_i2][_j2] = skip;
298
+ }
299
+ }
300
+ }
301
+ var ops = [];
302
+ var i = m;
303
+ var j = n;
304
+ while (i > 0 && j > 0) {
305
+ var _oldType = getNormalizedBlockType(oldNodes[i - 1]);
306
+ var _newType = getNormalizedBlockType(newNodes[j - 1]);
307
+ if (_oldType && _oldType === _newType) {
308
+ var exact = nodesEqual(oldNodes[i - 1], newNodes[j - 1]);
309
+ var _score = exact ? 2 : 1;
310
+ if (dp[i][j] === dp[i - 1][j - 1] + _score) {
311
+ ops.push(exact ? {
312
+ kind: 'equal',
313
+ node: oldNodes[i - 1]
314
+ } : {
315
+ kind: 'modify',
316
+ newNode: newNodes[j - 1],
317
+ oldNode: oldNodes[i - 1]
318
+ });
319
+ i--;
320
+ j--;
321
+ continue;
322
+ }
323
+ }
324
+ if (dp[i - 1][j] >= dp[i][j - 1]) {
325
+ ops.push({
326
+ kind: 'delete',
327
+ node: oldNodes[i - 1]
328
+ });
329
+ i--;
330
+ } else {
331
+ ops.push({
332
+ kind: 'insert',
333
+ node: newNodes[j - 1]
334
+ });
335
+ j--;
336
+ }
337
+ }
338
+ while (i > 0) {
339
+ ops.push({
340
+ kind: 'delete',
341
+ node: oldNodes[--i]
342
+ });
343
+ }
344
+ while (j > 0) {
345
+ ops.push({
346
+ kind: 'insert',
347
+ node: newNodes[--j]
348
+ });
349
+ }
350
+ return ops.reverse();
351
+ }
352
+ function diffChildrenInline(oldChildren, newChildren) {
353
+ var ops = alignNodes(oldChildren, newChildren);
354
+ var nextOldChildren = [];
355
+ var nextNewChildren = [];
356
+ var changed = false;
357
+ var _iterator3 = _createForOfIteratorHelper(ops),
358
+ _step3;
359
+ try {
360
+ for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) {
361
+ var op = _step3.value;
362
+ switch (op.kind) {
363
+ case 'equal':
364
+ {
365
+ nextOldChildren.push(op.node);
366
+ nextNewChildren.push(op.node);
367
+ break;
368
+ }
369
+ case 'delete':
370
+ {
371
+ changed = true;
372
+ nextOldChildren.push(decorateSubtree(op.node, 'delete'));
373
+ break;
374
+ }
375
+ case 'insert':
376
+ {
377
+ changed = true;
378
+ nextNewChildren.push(decorateSubtree(op.node, 'insert'));
379
+ break;
380
+ }
381
+ case 'modify':
382
+ {
383
+ changed = true;
384
+ if (isTextNode(op.oldNode) && isTextNode(op.newNode)) {
385
+ var textDiff = splitTextNodeByCharDiff(op.oldNode, op.newNode);
386
+ nextOldChildren.push.apply(nextOldChildren, _toConsumableArray(textDiff.oldNodes));
387
+ nextNewChildren.push.apply(nextNewChildren, _toConsumableArray(textDiff.newNodes));
388
+ break;
389
+ }
390
+
391
+ // Recursive descent is intentional here: same-type element nodes diff their children.
392
+ // eslint-disable-next-line @typescript-eslint/no-use-before-define
393
+ var nested = diffNodeInline(op.oldNode, op.newNode);
394
+ nextOldChildren.push(nested.oldNode);
395
+ nextNewChildren.push(nested.newNode);
396
+ break;
397
+ }
398
+ }
399
+ }
400
+ } catch (err) {
401
+ _iterator3.e(err);
402
+ } finally {
403
+ _iterator3.f();
404
+ }
405
+ return {
406
+ changed: changed,
407
+ newChildren: nextNewChildren,
408
+ oldChildren: nextOldChildren
409
+ };
410
+ }
411
+ function diffNodeInline(oldNode, newNode) {
412
+ if (nodesEqual(oldNode, newNode)) {
413
+ return {
414
+ changed: false,
415
+ newNode: newNode,
416
+ oldNode: oldNode
417
+ };
418
+ }
419
+ var oldChildren = getChildren(oldNode);
420
+ var newChildren = getChildren(newNode);
421
+ if (!oldChildren || !newChildren) {
422
+ return {
423
+ changed: true,
424
+ newNode: newNode,
425
+ oldNode: oldNode
426
+ };
427
+ }
428
+ var childDiff = diffChildrenInline(oldChildren, newChildren);
429
+ if (!childDiff.changed) {
430
+ return {
431
+ changed: false,
432
+ newNode: newNode,
433
+ oldNode: oldNode
434
+ };
435
+ }
436
+ return {
437
+ changed: true,
438
+ newNode: cloneNodeWithChildren(newNode, childDiff.newChildren),
439
+ oldNode: cloneNodeWithChildren(oldNode, childDiff.oldChildren)
440
+ };
441
+ }
442
+ function getRootChildren(state) {
443
+ return Array.isArray(state.root.children) ? _toConsumableArray(state.root.children) : [];
444
+ }
445
+ export function computeLexicalDiffRows(oldState, newState) {
446
+ var ops = alignNodes(getRootChildren(oldState), getRootChildren(newState));
447
+ var rows = [];
448
+ var index = 0;
449
+ while (index < ops.length) {
450
+ var op = ops[index];
451
+ if (op.kind === 'equal') {
452
+ rows.push({
453
+ kind: 'equal',
454
+ newCell: createCell(op.node),
455
+ oldCell: createCell(op.node)
456
+ });
457
+ index++;
458
+ continue;
459
+ }
460
+ if (op.kind === 'modify') {
461
+ var diffed = diffNodeInline(op.oldNode, op.newNode);
462
+ rows.push({
463
+ kind: 'modify',
464
+ newCell: createCell(diffed.newNode),
465
+ oldCell: createCell(diffed.oldNode)
466
+ });
467
+ index++;
468
+ continue;
469
+ }
470
+ var deletes = [];
471
+ var inserts = [];
472
+ while (index < ops.length && (ops[index].kind === 'delete' || ops[index].kind === 'insert')) {
473
+ var current = ops[index];
474
+ if (current.kind === 'delete') {
475
+ deletes.push(current.node);
476
+ } else if (current.kind === 'insert') {
477
+ inserts.push(current.node);
478
+ }
479
+ index++;
480
+ }
481
+ var maxLength = Math.max(deletes.length, inserts.length);
482
+ for (var pairIndex = 0; pairIndex < maxLength; pairIndex++) {
483
+ var _deletes$pairIndex, _inserts$pairIndex;
484
+ var oldBlock = (_deletes$pairIndex = deletes[pairIndex]) !== null && _deletes$pairIndex !== void 0 ? _deletes$pairIndex : null;
485
+ var newBlock = (_inserts$pairIndex = inserts[pairIndex]) !== null && _inserts$pairIndex !== void 0 ? _inserts$pairIndex : null;
486
+ if (oldBlock && newBlock) {
487
+ rows.push({
488
+ kind: 'modify',
489
+ newCell: createCell(newBlock),
490
+ oldCell: createCell(oldBlock)
491
+ });
492
+ continue;
493
+ }
494
+ if (oldBlock) {
495
+ rows.push({
496
+ kind: 'delete',
497
+ newCell: null,
498
+ oldCell: createCell(oldBlock)
499
+ });
500
+ continue;
501
+ }
502
+ rows.push({
503
+ kind: 'insert',
504
+ newCell: createCell(newBlock),
505
+ oldCell: null
506
+ });
507
+ }
508
+ }
509
+ return rows;
510
+ }
@@ -0,0 +1,13 @@
1
+ export declare const styles: {
2
+ body: string;
3
+ cell: string;
4
+ cellOld: string;
5
+ deleteCell: string;
6
+ emptyCell: string;
7
+ header: string;
8
+ headerCell: string;
9
+ headerOld: string;
10
+ insertCell: string;
11
+ root: string;
12
+ row: string;
13
+ };
@@ -0,0 +1,20 @@
1
+ var _templateObject, _templateObject2, _templateObject3, _templateObject4, _templateObject5, _templateObject6, _templateObject7, _templateObject8, _templateObject9, _templateObject10, _templateObject11;
2
+ function _taggedTemplateLiteral(strings, raw) { if (!raw) { raw = strings.slice(0); } return Object.freeze(Object.defineProperties(strings, { raw: { value: Object.freeze(raw) } })); }
3
+ import { createStaticStyles } from 'antd-style';
4
+ export var styles = createStaticStyles(function (_ref) {
5
+ var css = _ref.css,
6
+ cssVar = _ref.cssVar;
7
+ return {
8
+ body: css(_templateObject || (_templateObject = _taggedTemplateLiteral(["\n display: flex;\n flex-direction: column;\n background: ", ";\n "])), cssVar.colorBgContainer),
9
+ cell: css(_templateObject2 || (_templateObject2 = _taggedTemplateLiteral(["\n overflow: auto;\n min-width: 0;\n min-height: 24px;\n\n > div {\n width: 100%;\n min-width: 0;\n }\n "]))),
10
+ cellOld: css(_templateObject3 || (_templateObject3 = _taggedTemplateLiteral([""]))),
11
+ deleteCell: css(_templateObject4 || (_templateObject4 = _taggedTemplateLiteral(["\n background: color-mix(in srgb, ", " 10%, transparent);\n "])), cssVar.colorError),
12
+ emptyCell: css(_templateObject5 || (_templateObject5 = _taggedTemplateLiteral(["\n background: ", ";\n "])), cssVar.colorFillQuaternary),
13
+ header: css(_templateObject6 || (_templateObject6 = _taggedTemplateLiteral(["\n display: grid;\n grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);\n border-block-end: 1px solid ", ";\n background: ", ";\n "])), cssVar.colorBorderSecondary, cssVar.colorFillQuaternary),
14
+ headerCell: css(_templateObject7 || (_templateObject7 = _taggedTemplateLiteral(["\n padding-block: 8px;\n padding-inline: 16px;\n\n font-size: 12px;\n font-weight: 600;\n color: ", ";\n text-transform: uppercase;\n letter-spacing: 0.05em;\n "])), cssVar.colorTextSecondary),
15
+ headerOld: css(_templateObject8 || (_templateObject8 = _taggedTemplateLiteral(["\n border-inline-end: 1px solid ", ";\n "])), cssVar.colorBorderSecondary),
16
+ insertCell: css(_templateObject9 || (_templateObject9 = _taggedTemplateLiteral(["\n background: color-mix(in srgb, ", " 10%, transparent);\n "])), cssVar.colorSuccess),
17
+ root: css(_templateObject10 || (_templateObject10 = _taggedTemplateLiteral(["\n overflow: hidden;\n\n border: 1px solid ", ";\n border-radius: ", ";\n\n font-size: 14px;\n\n background: ", ";\n "])), cssVar.colorBorderSecondary, cssVar.borderRadiusSM, cssVar.colorBgContainer),
18
+ row: css(_templateObject11 || (_templateObject11 = _taggedTemplateLiteral(["\n display: grid;\n grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);\n "])))
19
+ };
20
+ });
@@ -0,0 +1,28 @@
1
+ import type { SerializedLexicalNode } from 'lexical';
2
+ import type { ReactNode } from 'react';
3
+ export type LexicalDiffRowKind = 'delete' | 'equal' | 'insert' | 'modify';
4
+ export interface LexicalDiffCell {
5
+ baseBlockType: string | null;
6
+ block: SerializedLexicalNode | null;
7
+ blockType: string | null;
8
+ }
9
+ export interface LexicalDiffRow {
10
+ kind: LexicalDiffRowKind;
11
+ newCell: LexicalDiffCell | null;
12
+ oldCell: LexicalDiffCell | null;
13
+ }
14
+ export interface LexicalDiffBlockRenderContext {
15
+ baseBlockType: string | null;
16
+ blockType: string | null;
17
+ newBaseBlockType: string | null;
18
+ newBlockType: string | null;
19
+ oldBaseBlockType: string | null;
20
+ oldBlockType: string | null;
21
+ renderDefaultNew: () => ReactNode;
22
+ renderDefaultOld: () => ReactNode;
23
+ row: LexicalDiffRow;
24
+ }
25
+ export type LexicalDiffBlockRenderer = (context: LexicalDiffBlockRenderContext) => {
26
+ new?: ReactNode;
27
+ old?: ReactNode;
28
+ } | null;
@@ -0,0 +1 @@
1
+ export {};
@@ -1,4 +1,7 @@
1
+ export type { LexicalDiffBlockRenderContext, LexicalDiffBlockRenderer, LexicalDiffCell, LexicalDiffRow, LexicalDiffRowKind, } from './diff/types';
1
2
  export { loadLanguage } from './engine/shiki';
3
+ export type { LexicalDiffProps } from './LexicalDiff';
4
+ export { LexicalDiff } from './LexicalDiff';
2
5
  export { LexicalRenderer } from './LexicalRenderer';
3
6
  export { rendererNodes } from './nodes';
4
7
  export { createDefaultRenderers } from './renderers';
@@ -1,4 +1,5 @@
1
1
  export { loadLanguage } from "./engine/shiki";
2
+ export { LexicalDiff } from "./LexicalDiff";
2
3
  export { LexicalRenderer } from "./LexicalRenderer";
3
4
  export { rendererNodes } from "./nodes";
4
5
  export { createDefaultRenderers } from "./renderers";
@@ -13,6 +13,7 @@ import { createStaticStyles } from 'antd-style';
13
13
  import { Check, ChevronDown, ChevronRight, CopyIcon } from 'lucide-react';
14
14
  import { useCallback, useState } from 'react';
15
15
  import { highlightCode } from "../engine/shiki";
16
+ import { renderMermaidBlock } from "./mermaid";
16
17
  import { jsx as _jsx } from "react/jsx-runtime";
17
18
  import { jsxs as _jsxs } from "react/jsx-runtime";
18
19
  var useStyles = createStaticStyles(function (_ref) {
@@ -150,6 +151,10 @@ function CodeBlockRenderer(_ref3) {
150
151
  });
151
152
  }
152
153
  export function renderCodeBlock(node, key, children) {
154
+ var language = (node.language || '').toLowerCase();
155
+ if (language === 'mermaid') {
156
+ return renderMermaidBlock(node, key);
157
+ }
153
158
  return /*#__PURE__*/_jsx(CodeBlockRenderer, {
154
159
  codeChildren: children,
155
160
  node: node
@@ -0,0 +1,2 @@
1
+ import { type ReactNode } from 'react';
2
+ export declare function renderMermaidBlock(node: Record<string, any>, key: string): ReactNode;
@@ -0,0 +1,18 @@
1
+ 'use client';
2
+
3
+ import { Mermaid } from '@lobehub/ui';
4
+ import { jsx as _jsx } from "react/jsx-runtime";
5
+ export function renderMermaidBlock(node, key) {
6
+ var code = node.code || '';
7
+ return /*#__PURE__*/_jsx(Mermaid, {
8
+ animated: false,
9
+ defaultExpand: true,
10
+ fullFeatured: true,
11
+ style: {
12
+ width: '100%'
13
+ },
14
+ theme: "lobe-theme",
15
+ variant: "filled",
16
+ children: code
17
+ }, key);
18
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lobehub/editor",
3
- "version": "4.3.2",
3
+ "version": "4.4.0",
4
4
  "description": "A powerful and extensible rich text editor built on Meta's Lexical framework, providing a modern editing experience with React integration.",
5
5
  "keywords": [
6
6
  "lobehub",
@@ -86,6 +86,7 @@
86
86
  "katex": "^0.16.27",
87
87
  "lexical": "^0.39.0",
88
88
  "lucide-react": "^0.562.0",
89
+ "mermaid": "^11.13.0",
89
90
  "polished": "^4.3.1",
90
91
  "re-resizable": "^6.11.2",
91
92
  "react-error-boundary": "^6.0.2",