@lobehub/editor 4.29.1 → 5.0.0-beta.1
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/README.md +86 -0
- package/es/codemirror/components/CopyButton.js +1 -1
- package/es/codemirror/components/LanguageSelect.js +1 -3
- package/es/codemirror/components/MoreOptions.js +1 -2
- package/es/codemirror/components/Toolbar.js +1 -2
- package/es/codemirror/components/style.js +1 -1
- package/es/codemirror/style.js +1 -1
- package/es/codemirror/theme.js +1 -1
- package/es/editor-kernel/index.d.ts +2 -2
- package/es/editor-kernel/index.js +2 -2
- package/es/editor-kernel/react/useAnchor.js +1 -1
- package/es/headless/index.d.ts +5 -2
- package/es/headless/index.js +20 -22
- package/es/headless.d.ts +6 -507
- package/es/headless.js +903 -408
- package/es/i-node-identity-service-BBC_bg97.d.ts +522 -0
- package/es/index.d.ts +4 -2
- package/es/index.js +5 -2
- package/es/plugins/auto-complete/react/ReactAutoCompletePlugin.js +1 -1
- package/es/plugins/auto-complete/react/style.js +1 -1
- package/es/plugins/block/react/ReactBlockPlugin.js +2 -7
- package/es/plugins/block/react/style.js +1 -1
- package/es/plugins/code/react/CodeReactPlugin.js +1 -1
- package/es/plugins/code/react/style.js +1 -1
- package/es/plugins/codeblock/react/ReactCodeblockPlugin.js +1 -1
- package/es/plugins/codeblock/react/style.js +1 -1
- package/es/plugins/codemirror-block/react/CodemirrorNode.js +1 -3
- package/es/plugins/codemirror-block/react/MermaidPreview.js +1 -2
- package/es/plugins/collapsible/react/ReactCollapsiblePlugin.js +1 -1
- package/es/plugins/collapsible/react/style.js +74 -64
- package/es/plugins/common/data-source/json-data-source.js +33 -25
- package/es/plugins/common/data-source/text-data-source.js +6 -1
- package/es/plugins/common/index.d.ts +3 -1
- package/es/plugins/common/node/node-id.d.ts +7 -0
- package/es/plugins/common/node/node-id.js +484 -0
- package/es/plugins/common/node/node-identity-policy.d.ts +26 -0
- package/es/plugins/common/node/node-identity-policy.js +68 -0
- package/es/plugins/common/plugin/index.js +28 -2
- package/es/plugins/common/react/Placeholder/style.js +1 -1
- package/es/plugins/common/react/ReactPlainText.js +1 -1
- package/es/plugins/common/react/style.js +1 -1
- package/es/plugins/common/service/i-node-identity-service.d.ts +19 -0
- package/es/plugins/common/service/i-node-identity-service.js +4 -0
- package/es/plugins/common/service/node-identity-service.js +87 -0
- package/es/plugins/common/utils/index.js +3 -1
- package/es/plugins/file/react/components/ReactFile.js +1 -1
- package/es/plugins/file/react/style.js +1 -1
- package/es/plugins/hr/react/components/HRNode.js +1 -1
- package/es/plugins/hr/react/style.js +1 -1
- package/es/plugins/image/react/components/Image.js +1 -3
- package/es/plugins/image/react/components/ImageEditPopover.js +1 -3
- package/es/plugins/image/react/components/LazyImage.js +1 -1
- package/es/plugins/image/react/components/ResizeHandle.js +1 -1
- package/es/plugins/image/react/components/style.js +1 -1
- package/es/plugins/image/react/style.js +1 -1
- package/es/plugins/link/react/ReactLinkPlugin.js +1 -1
- package/es/plugins/link/react/components/LinkEdit.js +1 -3
- package/es/plugins/link/react/components/LinkToolbar.js +1 -1
- package/es/plugins/link/react/style.js +1 -1
- package/es/plugins/link-highlight/react/ReactLinkHighlightPlugin.js +1 -1
- package/es/plugins/link-highlight/react/style.js +1 -1
- package/es/plugins/list/plugin/index.js +7 -1
- package/es/plugins/list/react/style.js +1 -1
- package/es/plugins/litexml/command/index.d.ts +2 -2
- package/es/plugins/litexml/command/index.js +464 -292
- package/es/plugins/litexml/command/symbols.d.ts +18 -7
- package/es/plugins/litexml/command/symbols.js +2 -1
- package/es/plugins/litexml/data-source/litexml-data-source.js +34 -31
- package/es/plugins/litexml/diff-validation.js +68 -14
- package/es/plugins/litexml/index.d.ts +2 -2
- package/es/plugins/litexml/node/identity-policy.js +91 -0
- package/es/plugins/litexml/plugin/index.js +6 -0
- package/es/plugins/litexml/react/DiffNodeToolbar/index.js +1 -3
- package/es/plugins/litexml/react/DiffNodeToolbar/style.js +1 -1
- package/es/plugins/litexml/react/TableRowDiffToolbar.js +1 -3
- package/es/plugins/litexml/react/style.js +1 -1
- package/es/plugins/litexml/table-cell-diff.js +4 -0
- package/es/plugins/litexml/table-row-diff.js +4 -0
- package/es/plugins/litexml/utils/index.js +10 -23
- package/es/plugins/markdown/command/index.js +77 -4
- package/es/plugins/markdown/data-source/markdown-data-source.js +6 -1
- package/es/plugins/markdown/react/index.js +1 -1
- package/es/plugins/math/react/components/MathEditorContainer.js +1 -1
- package/es/plugins/math/react/components/MathEditorContent.js +1 -2
- package/es/plugins/math/react/components/Placeholder.js +1 -3
- package/es/plugins/math/react/style.js +1 -1
- package/es/plugins/mention/react/components/Mention.js +1 -1
- package/es/plugins/mention/react/style.js +1 -1
- package/es/plugins/slash/react/components/DefaultSlashMenu.js +1 -2
- package/es/plugins/slash/service/i-slash-service.d.ts +2 -2
- package/es/plugins/table/react/TableActionMenu/ActionMenu.js +1 -1
- package/es/plugins/table/react/TableActionMenu/index.js +1 -1
- package/es/plugins/table/react/TableActionMenu/style.js +1 -1
- package/es/plugins/table/react/TableColController.js +1 -1
- package/es/plugins/table/react/TableController/style.js +1 -1
- package/es/plugins/table/react/TableControllerButton.js +2 -2
- package/es/plugins/table/react/TableControllerMenu.js +2 -2
- package/es/plugins/table/react/TableHoverActions/index.js +1 -2
- package/es/plugins/table/react/TableHoverActions/style.js +1 -1
- package/es/plugins/table/react/TableResize/index.js +2 -2
- package/es/plugins/table/react/TableResize/style.js +1 -1
- package/es/plugins/table/react/TableRowController.js +1 -1
- package/es/plugins/table/react/index.js +1 -1
- package/es/plugins/table/react/style.js +1 -1
- package/es/plugins/toolbar/react/index.js +1 -2
- package/es/plugins/toolbar/react/style.js +1 -1
- package/es/plugins/yjs/plugin/index.js +5 -3
- package/es/plugins/yjs/plugin/utils/editor-state.js +8 -1
- package/es/plugins/yjs/plugin/utils/node-identity.js +106 -0
- package/es/plugins/yjs/service/index.js +38 -4
- package/es/react/ChatInput/ChatInput.js +1 -2
- package/es/react/ChatInput/style.js +1 -1
- package/es/react/ChatInput/type.d.ts +1 -1
- package/es/react/ChatInputActionBar/ChatInputActionBar.js +1 -2
- package/es/react/ChatInputActionBar/style.js +1 -1
- package/es/react/ChatInputActionBar/type.d.ts +1 -1
- package/es/react/ChatInputActions/ChatInputActions.js +1 -2
- package/es/react/ChatInputActions/components/ActionItem.js +1 -1
- package/es/react/ChatInputActions/components/ActionRender.js +1 -1
- package/es/react/ChatInputActions/components/CollapsedActions.js +1 -2
- package/es/react/ChatInputActions/style.js +1 -1
- package/es/react/ChatInputActions/type.d.ts +4 -4
- package/es/react/CodeLanguageSelect/CodeLanguageSelect.js +1 -3
- package/es/react/CodeLanguageSelect/style.js +1 -1
- package/es/react/CodeLanguageSelect/type.d.ts +1 -1
- package/es/react/FloatActions/FloatActions.js +1 -2
- package/es/react/FloatActions/components/ActionItem.js +1 -1
- package/es/react/FloatActions/components/ActionRender.js +1 -1
- package/es/react/FloatActions/components/CollapsedActions.js +1 -2
- package/es/react/FloatActions/style.js +1 -1
- package/es/react/FloatActions/type.d.ts +4 -4
- package/es/react/SendButton/SendButton.js +1 -2
- package/es/react/SendButton/components/SendIcon.js +1 -1
- package/es/react/SendButton/components/StopIcon.js +1 -1
- package/es/react/SendButton/style.js +1 -1
- package/es/react/SendButton/type.d.ts +1 -1
- package/es/renderer/LexicalDiff.js +1 -1
- package/es/renderer/LexicalRenderer.js +1 -1
- package/es/renderer/diff/compute.js +2 -2
- package/es/renderer/diff/style.js +1 -1
- package/es/renderer/engine/render-builtin-node.js +2 -2
- package/es/renderer/renderers/codeblock.js +1 -1
- package/es/renderer/renderers/horizontalrule.js +1 -1
- package/es/renderer/renderers/mermaid.js +1 -1
- package/es/renderer/style.js +1 -1
- package/es/{symbols-Do7jD4Tt.d.ts → symbols-Dyr9yyS0.d.ts} +18 -7
- package/package.json +6 -8
- package/scripts/postinstall-lexical-patch.cjs +0 -21
- package/patches/lexical@0.42.0.patch +0 -82
|
@@ -1,26 +1,22 @@
|
|
|
1
|
-
import { $
|
|
1
|
+
import { $clearNodeId, $getNodeId, $setNodeId, init_node_id, isValidContentNodeId } from "../../common/node/node-id.js";
|
|
2
|
+
import { $isElementNode } from "lexical";
|
|
2
3
|
//#region src/plugins/litexml/utils/index.ts
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
const numericId = Number(id);
|
|
6
|
-
return Number.isInteger(numericId) && numericId >= 0 ? numericId : null;
|
|
7
|
-
};
|
|
8
|
-
function $parseSerializedNodeImpl(serializedNode, editor, keepId = false, state = null) {
|
|
4
|
+
init_node_id();
|
|
5
|
+
function $parseSerializedNodeImpl(serializedNode, editor) {
|
|
9
6
|
const type = serializedNode.type;
|
|
10
7
|
const registeredNode = editor._nodes.get(type);
|
|
11
8
|
if (registeredNode === void 0) throw new Error(`parseEditorState: type "${type}" not found`);
|
|
12
9
|
const nodeClass = registeredNode.klass;
|
|
13
10
|
if (serializedNode.type !== nodeClass.getType()) throw new Error(`LexicalNode: Node ${nodeClass.name} does not implement .importJSON().`);
|
|
14
|
-
if (keepId) {
|
|
15
|
-
const id = getNumericId(serializedNode.id);
|
|
16
|
-
if (id !== null) resetRandomKey(id);
|
|
17
|
-
}
|
|
18
11
|
const node = nodeClass.importJSON(serializedNode);
|
|
12
|
+
const nodeId = isValidContentNodeId(serializedNode.id) ? serializedNode.id : $getNodeId(node);
|
|
13
|
+
if (isValidContentNodeId(nodeId)) $setNodeId(node, nodeId);
|
|
14
|
+
else if (nodeId) $clearNodeId(node);
|
|
19
15
|
const children = serializedNode.children;
|
|
20
16
|
if ($isElementNode(node) && Array.isArray(children)) {
|
|
21
17
|
const childNodes = [];
|
|
22
18
|
for (const serializedJSONChildNode of children) {
|
|
23
|
-
const childNode = $parseSerializedNodeImpl(serializedJSONChildNode, editor
|
|
19
|
+
const childNode = $parseSerializedNodeImpl(serializedJSONChildNode, editor);
|
|
24
20
|
childNodes.push(childNode);
|
|
25
21
|
}
|
|
26
22
|
node.append(...childNodes);
|
|
@@ -30,6 +26,7 @@ function $parseSerializedNodeImpl(serializedNode, editor, keepId = false, state
|
|
|
30
26
|
function exportNodeToJSON(node) {
|
|
31
27
|
const serializedNode = node.exportJSON();
|
|
32
28
|
const nodeClass = node.constructor;
|
|
29
|
+
serializedNode.id = $getNodeId(node);
|
|
33
30
|
if (serializedNode.type !== nodeClass.getType()) throw new Error(`LexicalNode: Node ${nodeClass.name} does not match the serialized type. Check if .exportJSON() is implemented and it is returning the correct type.`);
|
|
34
31
|
if ($isElementNode(node)) {
|
|
35
32
|
const serializedChildren = serializedNode.children;
|
|
@@ -45,15 +42,5 @@ function exportNodeToJSON(node) {
|
|
|
45
42
|
function $cloneNode(node, editor) {
|
|
46
43
|
return $parseSerializedNodeImpl(exportNodeToJSON(node), editor);
|
|
47
44
|
}
|
|
48
|
-
const maxId = 1679616;
|
|
49
|
-
const startId = 1e6;
|
|
50
|
-
const step = 7211;
|
|
51
|
-
const modInverse = 1394051;
|
|
52
|
-
function idToChar(id) {
|
|
53
|
-
return ((Number(id) * step + startId) % maxId).toString(36).padStart(4, "0");
|
|
54
|
-
}
|
|
55
|
-
function charToId(char) {
|
|
56
|
-
return String((parseInt(char, 36) - startId + maxId) * modInverse % maxId);
|
|
57
|
-
}
|
|
58
45
|
//#endregion
|
|
59
|
-
export { $cloneNode, $parseSerializedNodeImpl
|
|
46
|
+
export { $cloneNode, $parseSerializedNodeImpl };
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import { createDebugLogger, init_debug } from "../../../utils/debug.js";
|
|
2
|
+
import { $findNodeById, $getNodeId, init_node_id } from "../../common/node/node-id.js";
|
|
2
3
|
import { parseMarkdownToLexical } from "../data-source/markdown/parse.js";
|
|
3
4
|
import { $generateNodesFromSerializedNodes, $insertGeneratedNodes } from "../utils/index.js";
|
|
4
|
-
import { $getSelection, $isRangeSelection, COMMAND_PRIORITY_HIGH, HISTORIC_TAG, HISTORY_PUSH_TAG, createCommand } from "lexical";
|
|
5
|
+
import { $getNodeByKey, $getRoot, $getSelection, $isElementNode, $isRangeSelection, $isRootNode, $isTextNode, COMMAND_PRIORITY_HIGH, HISTORIC_TAG, HISTORY_PUSH_TAG, createCommand } from "lexical";
|
|
5
6
|
import { mergeRegister } from "@lexical/utils";
|
|
6
7
|
//#region src/plugins/markdown/command/index.ts
|
|
8
|
+
init_node_id();
|
|
7
9
|
init_debug();
|
|
8
10
|
const logger = createDebugLogger("plugin", "markdown");
|
|
9
11
|
const INSERT_MARKDOWN_COMMAND = createCommand("INSERT_MARKDOWN_COMMAND");
|
|
@@ -16,6 +18,74 @@ const SPICAL_TEXT = "";
|
|
|
16
18
|
const getLineNumber = (content, charIndex) => {
|
|
17
19
|
return content.slice(0, Math.max(0, charIndex)).split("\n").length;
|
|
18
20
|
};
|
|
21
|
+
function getNodeReferenceForKey(editor, key) {
|
|
22
|
+
return editor.getEditorState().read(() => {
|
|
23
|
+
const node = $getNodeByKey(key);
|
|
24
|
+
if (!node) return null;
|
|
25
|
+
if ($isRootNode(node)) return { kind: "root" };
|
|
26
|
+
const id = $getNodeId(node);
|
|
27
|
+
return id ? {
|
|
28
|
+
id,
|
|
29
|
+
kind: "node"
|
|
30
|
+
} : null;
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
function getNodeKeyForReference(editor, reference, offset) {
|
|
34
|
+
return editor.getEditorState().read(() => {
|
|
35
|
+
if (reference.kind === "node") {
|
|
36
|
+
const node = $findNodeById(reference.id);
|
|
37
|
+
return node ? {
|
|
38
|
+
key: node.getKey(),
|
|
39
|
+
offset
|
|
40
|
+
} : void 0;
|
|
41
|
+
}
|
|
42
|
+
const root = $getRoot();
|
|
43
|
+
const findBoundaryText = (node, first) => {
|
|
44
|
+
if ($isTextNode(node)) return node;
|
|
45
|
+
if (!$isElementNode(node)) return null;
|
|
46
|
+
const children = node.getChildren();
|
|
47
|
+
const orderedChildren = first ? children : [...children].reverse();
|
|
48
|
+
for (const child of orderedChildren) {
|
|
49
|
+
const textNode = findBoundaryText(child, first);
|
|
50
|
+
if (textNode) return textNode;
|
|
51
|
+
}
|
|
52
|
+
return null;
|
|
53
|
+
};
|
|
54
|
+
if (offset === 0) {
|
|
55
|
+
const firstText = findBoundaryText(root, true);
|
|
56
|
+
if (firstText) return {
|
|
57
|
+
key: firstText.getKey(),
|
|
58
|
+
offset: 0
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
if (offset === root.getChildrenSize()) {
|
|
62
|
+
const lastText = findBoundaryText(root, false);
|
|
63
|
+
if (lastText) return {
|
|
64
|
+
key: lastText.getKey(),
|
|
65
|
+
offset: lastText.getTextContentSize()
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
return {
|
|
69
|
+
key: root.getKey(),
|
|
70
|
+
offset
|
|
71
|
+
};
|
|
72
|
+
}, { editor });
|
|
73
|
+
}
|
|
74
|
+
function mapSelectionToEditor(selection, sourceEditor, targetEditor) {
|
|
75
|
+
const startReference = getNodeReferenceForKey(sourceEditor, selection.startNodeId);
|
|
76
|
+
const endReference = getNodeReferenceForKey(sourceEditor, selection.endNodeId);
|
|
77
|
+
if (!startReference || !endReference) return null;
|
|
78
|
+
const startPoint = getNodeKeyForReference(targetEditor, startReference, selection.startOffset);
|
|
79
|
+
const endPoint = getNodeKeyForReference(targetEditor, endReference, selection.endOffset);
|
|
80
|
+
if (!startPoint || !endPoint) return null;
|
|
81
|
+
return {
|
|
82
|
+
...selection,
|
|
83
|
+
endNodeId: endPoint.key,
|
|
84
|
+
endOffset: endPoint.offset,
|
|
85
|
+
startNodeId: startPoint.key,
|
|
86
|
+
startOffset: startPoint.offset
|
|
87
|
+
};
|
|
88
|
+
}
|
|
19
89
|
function registerMarkdownCommand(editor, kernel, service) {
|
|
20
90
|
return mergeRegister(editor.registerCommand(INSERT_MARKDOWN_COMMAND, (payload) => {
|
|
21
91
|
const { markdown } = payload;
|
|
@@ -38,9 +108,12 @@ function registerMarkdownCommand(editor, kernel, service) {
|
|
|
38
108
|
return false;
|
|
39
109
|
}, COMMAND_PRIORITY_HIGH), editor.registerCommand(GET_MARKDOWN_SELECTION_COMMAND, (payload) => {
|
|
40
110
|
const newEditor = kernel.cloneNodeEditor();
|
|
41
|
-
const
|
|
42
|
-
|
|
43
|
-
|
|
111
|
+
const sourceEditor = kernel.getLexicalEditor();
|
|
112
|
+
const selection = kernel.getSelection();
|
|
113
|
+
const targetEditor = newEditor.getLexicalEditor();
|
|
114
|
+
const mappedSelection = sourceEditor && targetEditor && selection ? mapSelectionToEditor(selection, sourceEditor, targetEditor) : null;
|
|
115
|
+
if (mappedSelection && targetEditor) {
|
|
116
|
+
newEditor.setSelection(mappedSelection);
|
|
44
117
|
newEditor.getLexicalEditor()?.update(() => {
|
|
45
118
|
const sel = $getSelection();
|
|
46
119
|
if (!sel) return;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { INodeHelper, init_helper } from "../../../editor-kernel/inode/helper.js";
|
|
2
|
+
import { $normalizeNodeIds, init_node_id } from "../../common/node/node-id.js";
|
|
2
3
|
import DataSource from "../../../editor-kernel/data-source.js";
|
|
3
4
|
import { INodeService } from "../../inode/service/index.js";
|
|
4
5
|
import { logger } from "../utils/logger.js";
|
|
@@ -10,6 +11,7 @@ import { remark } from "remark";
|
|
|
10
11
|
import remarkGfm from "remark-gfm";
|
|
11
12
|
//#region src/plugins/markdown/data-source/markdown-data-source.ts
|
|
12
13
|
init_helper();
|
|
14
|
+
init_node_id();
|
|
13
15
|
var MarkdownDataSource = class extends DataSource {
|
|
14
16
|
formatMarkdown(markdown) {
|
|
15
17
|
try {
|
|
@@ -37,7 +39,10 @@ var MarkdownDataSource = class extends DataSource {
|
|
|
37
39
|
const inode = { root: parseMarkdownToLexical(data, this.markdownService.markdownReaders) };
|
|
38
40
|
this.getService?.(INodeService)?.processNodeTree(inode);
|
|
39
41
|
logger.debug("Parsed Lexical State:", inode);
|
|
40
|
-
editor.
|
|
42
|
+
const editorState = editor.parseEditorState(inode, () => {
|
|
43
|
+
$normalizeNodeIds($getRoot());
|
|
44
|
+
});
|
|
45
|
+
editor.setEditorState(editorState);
|
|
41
46
|
}
|
|
42
47
|
write(editor, options) {
|
|
43
48
|
if (options?.selection) return editor.getEditorState().read(() => {
|
|
@@ -3,8 +3,8 @@ import { useLexicalComposerContext } from "../../../editor-kernel/react/react-co
|
|
|
3
3
|
import { INodePlugin } from "../../inode/plugin/index.js";
|
|
4
4
|
import { MarkdownPlugin } from "../plugin/index.js";
|
|
5
5
|
import { useTranslation } from "../../../editor-kernel/react/useTranslation.js";
|
|
6
|
-
import { useLayoutEffect } from "react";
|
|
7
6
|
import { toast } from "@lobehub/ui";
|
|
7
|
+
import { useLayoutEffect } from "react";
|
|
8
8
|
//#region src/plugins/markdown/react/index.tsx
|
|
9
9
|
const ReactMarkdownPlugin = () => {
|
|
10
10
|
const [editor] = useLexicalComposerContext();
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { cleanPosition, updatePosition } from "../../../../utils/updatePosition.js";
|
|
2
2
|
import { styles } from "../style.js";
|
|
3
|
+
import { Flexbox, Popover } from "@lobehub/ui";
|
|
3
4
|
import { memo, useCallback, useEffect, useRef, useState } from "react";
|
|
4
5
|
import { jsx } from "react/jsx-runtime";
|
|
5
|
-
import { Flexbox, Popover } from "@lobehub/ui";
|
|
6
6
|
//#region src/plugins/math/react/components/MathEditorContainer.tsx
|
|
7
7
|
const MathEditorContainer = memo(({ children, isBlockMode, mathDOM, onFocus, prev }) => {
|
|
8
8
|
const anchorRef = useRef(null);
|
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
import { CONTROL_OR_META, init_sys } from "../../../../common/sys.js";
|
|
2
2
|
import { useTranslation } from "../../../../editor-kernel/react/useTranslation.js";
|
|
3
3
|
import { styles } from "../style.js";
|
|
4
|
-
import { Button, Text, TextArea } from "@lobehub/ui
|
|
4
|
+
import { Button, Flexbox, Hotkey, Text, TextArea } from "@lobehub/ui";
|
|
5
5
|
import { memo, useCallback, useEffect, useRef, useState } from "react";
|
|
6
6
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
7
|
-
import { Flexbox, Hotkey } from "@lobehub/ui";
|
|
8
7
|
import { isModifierMatch } from "lexical";
|
|
9
8
|
import { renderToString } from "katex";
|
|
10
9
|
//#region src/plugins/math/react/components/MathEditorContent.tsx
|
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
import { useTranslation } from "../../../../editor-kernel/react/useTranslation.js";
|
|
2
2
|
import { styles } from "../style.js";
|
|
3
|
-
import { Text } from "@lobehub/ui
|
|
3
|
+
import { Center, Text, cx } from "@lobehub/ui";
|
|
4
4
|
import { jsx } from "react/jsx-runtime";
|
|
5
|
-
import { Center } from "@lobehub/ui";
|
|
6
|
-
import { cx } from "antd-style";
|
|
7
5
|
//#region src/plugins/math/react/components/Placeholder.tsx
|
|
8
6
|
const Placeholder = ({ mathBlock }) => {
|
|
9
7
|
const t = useTranslation();
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { useLexicalNodeSelection } from "../../../../editor-kernel/react/useLexicalNodeSelection.js";
|
|
2
|
+
import { cx } from "@lobehub/ui";
|
|
2
3
|
import { useCallback, useEffect, useRef } from "react";
|
|
3
4
|
import { jsxs } from "react/jsx-runtime";
|
|
4
|
-
import { cx } from "antd-style";
|
|
5
5
|
import { CLICK_COMMAND, COMMAND_PRIORITY_LOW } from "lexical";
|
|
6
6
|
//#region src/plugins/mention/react/components/Mention.tsx
|
|
7
7
|
const Mention = ({ node, editor, className }) => {
|
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { flattenSlashOptions, isSlashDividerOption, isSlashSectionOption } from "../../service/i-slash-service.js";
|
|
3
3
|
import { shouldShowLoadingPlaceholder } from "./menuLoading.js";
|
|
4
|
+
import { Icon, LOBE_THEME_APP_ID, createStaticStyles, menuSharedStyles } from "@lobehub/ui";
|
|
4
5
|
import { isValidElement, useEffect, useLayoutEffect, useMemo, useRef } from "react";
|
|
5
6
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
6
|
-
import { Icon, LOBE_THEME_APP_ID, menuSharedStyles } from "@lobehub/ui";
|
|
7
|
-
import { createStaticStyles } from "antd-style";
|
|
8
7
|
import { createPortal } from "react-dom";
|
|
9
8
|
import { autoUpdate, flip, offset, shift, size, useFloating } from "@floating-ui/react";
|
|
10
9
|
//#region src/plugins/slash/react/components/DefaultSlashMenu.tsx
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import { IEditor, IServiceID } from "../../../types/kernel.js";
|
|
2
2
|
import "../../../types/index.js";
|
|
3
3
|
import "../utils/utils.js";
|
|
4
|
+
import { MenuItemType } from "@lobehub/ui";
|
|
4
5
|
import { ReactNode } from "react";
|
|
5
|
-
import { DropdownMenuItemType } from "@lobehub/ui";
|
|
6
6
|
import Fuse, { IFuseOptions } from "fuse.js";
|
|
7
7
|
//#region src/plugins/slash/service/i-slash-service.d.ts
|
|
8
8
|
type ISlashDividerOption = {
|
|
9
9
|
type: 'divider';
|
|
10
10
|
};
|
|
11
|
-
interface ISlashMenuOption extends
|
|
11
|
+
interface ISlashMenuOption extends MenuItemType {
|
|
12
12
|
description?: ReactNode;
|
|
13
13
|
layout?: 'compact' | 'tile' | 'wide';
|
|
14
14
|
metadata?: Record<string, any>;
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { useTranslation } from "../../../../editor-kernel/react/useTranslation.js";
|
|
2
2
|
import { $canUnmerge, $selectLastDescendant, computeSelectionCount, currentCellBackgroundColor } from "./utils.js";
|
|
3
|
+
import { DropdownMenu } from "@lobehub/ui";
|
|
3
4
|
import { Grid2X2XIcon, PanelBottomCloseIcon, PanelLeftCloseIcon, PanelRightCloseIcon, PanelTopCloseIcon, TableColumnsSplitIcon, TableRowsSplitIcon } from "lucide-react";
|
|
4
5
|
import { memo, useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
5
6
|
import { jsx } from "react/jsx-runtime";
|
|
6
|
-
import { DropdownMenu } from "@lobehub/ui";
|
|
7
7
|
import { $computeTableMapSkipCellCheck, $deleteTableColumnAtSelection, $deleteTableRowAtSelection, $getTableColumnIndexFromTableCellNode, $getTableNodeFromLexicalNodeOrThrow, $getTableRowIndexFromTableCellNode, $insertTableColumnAtSelection, $insertTableRowAtSelection, $isTableCellNode, $isTableSelection, $mergeCells, $unmergeCell, TableCellHeaderStates, TableCellNode, getTableElement, getTableObserverFromTableElement } from "@lexical/table";
|
|
8
8
|
import { $getSelection, $setSelection } from "lexical";
|
|
9
9
|
//#region src/plugins/table/react/TableActionMenu/ActionMenu.tsx
|
|
@@ -2,7 +2,7 @@ import { useAnchor } from "../../../../editor-kernel/react/useAnchor.js";
|
|
|
2
2
|
import { cleanPosition, updatePosition } from "../../../../utils/updatePosition.js";
|
|
3
3
|
import TableActionMenu$1 from "./ActionMenu.js";
|
|
4
4
|
import { styles } from "./style.js";
|
|
5
|
-
import { ActionIcon } from "@lobehub/ui
|
|
5
|
+
import { ActionIcon } from "@lobehub/ui";
|
|
6
6
|
import { ChevronDown } from "lucide-react";
|
|
7
7
|
import { memo, useCallback, useEffect, useRef, useState } from "react";
|
|
8
8
|
import { jsx } from "react/jsx-runtime";
|
|
@@ -6,9 +6,9 @@ import { styles } from "./TableController/style.js";
|
|
|
6
6
|
import { createTableDragImage } from "./TableController/utils.js";
|
|
7
7
|
import TableControllerMenu from "./TableControllerMenu.js";
|
|
8
8
|
import TableInsertButton from "./TableInsertButton.js";
|
|
9
|
+
import { cx } from "@lobehub/ui";
|
|
9
10
|
import { memo, useCallback, useEffect, useRef, useState } from "react";
|
|
10
11
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
11
|
-
import { cx } from "antd-style";
|
|
12
12
|
import { $computeTableMapSkipCellCheck } from "@lexical/table";
|
|
13
13
|
//#region src/plugins/table/react/TableColController.tsx
|
|
14
14
|
const INSERT_BUTTON_HIDE_DELAY = 160;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { createStaticStyles } from "
|
|
1
|
+
import { createStaticStyles } from "@lobehub/ui";
|
|
2
2
|
//#region src/plugins/table/react/TableController/style.ts
|
|
3
3
|
const styles = createStaticStyles(({ css, cssVar }) => {
|
|
4
4
|
const selectedBackground = `color-mix(in srgb, ${cssVar.colorPrimaryBg} 72%, ${cssVar.colorPrimary} 28%)`;
|
|
@@ -1,12 +1,12 @@
|
|
|
1
|
+
import { LOBE_THEME_APP_ID, cx } from "@lobehub/ui";
|
|
1
2
|
import { memo, useEffect, useState } from "react";
|
|
2
3
|
import { jsx } from "react/jsx-runtime";
|
|
3
|
-
import { cx } from "antd-style";
|
|
4
4
|
import { createPortal } from "react-dom";
|
|
5
5
|
//#region src/plugins/table/react/TableControllerButton.tsx
|
|
6
6
|
const BUTTON_SIZE = 24;
|
|
7
7
|
const getPortalContainer = () => {
|
|
8
8
|
if (typeof document === "undefined") return null;
|
|
9
|
-
return document.querySelector(
|
|
9
|
+
return document.querySelector(`#${LOBE_THEME_APP_ID}`) || document.body;
|
|
10
10
|
};
|
|
11
11
|
const getButtonStyle = (reference, position, offset = 0, gap) => {
|
|
12
12
|
if (!reference) return {};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { styles } from "./TableController/style.js";
|
|
2
|
+
import { LOBE_THEME_APP_ID, cx } from "@lobehub/ui";
|
|
2
3
|
import { memo, useEffect, useRef, useState } from "react";
|
|
3
4
|
import { jsx } from "react/jsx-runtime";
|
|
4
|
-
import { cx } from "antd-style";
|
|
5
5
|
import { createPortal } from "react-dom";
|
|
6
6
|
//#region src/plugins/table/react/TableControllerMenu.tsx
|
|
7
7
|
const MENU_GAP = 8;
|
|
@@ -12,7 +12,7 @@ const isSeparatorItem = (item) => {
|
|
|
12
12
|
};
|
|
13
13
|
const getPortalContainer = () => {
|
|
14
14
|
if (typeof document === "undefined") return null;
|
|
15
|
-
return document.querySelector(
|
|
15
|
+
return document.querySelector(`#${LOBE_THEME_APP_ID}`) || document.body;
|
|
16
16
|
};
|
|
17
17
|
const getMenuStyle = (anchorElement, items, position, menuElement) => {
|
|
18
18
|
if (!anchorElement || typeof window === "undefined") return {};
|
|
@@ -2,11 +2,10 @@ import { useLexicalComposerContext } from "../../../../editor-kernel/react/react
|
|
|
2
2
|
import { useAnchor } from "../../../../editor-kernel/react/useAnchor.js";
|
|
3
3
|
import { styles } from "./style.js";
|
|
4
4
|
import { getMouseInfo, useDebounce } from "./utils.js";
|
|
5
|
-
import { ActionIcon } from "@lobehub/ui
|
|
5
|
+
import { ActionIcon, cx } from "@lobehub/ui";
|
|
6
6
|
import { PlusIcon } from "lucide-react";
|
|
7
7
|
import { memo, useEffect, useMemo, useRef, useState } from "react";
|
|
8
8
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
9
|
-
import { cx } from "antd-style";
|
|
10
9
|
import { $getTableAndElementByKey, $getTableColumnIndexFromTableCellNode, $getTableRowIndexFromTableCellNode, $insertTableColumnAtSelection, $insertTableRowAtSelection, $isTableCellNode, $isTableNode, TableNode, getTableElement } from "@lexical/table";
|
|
11
10
|
import { $getNearestNodeFromDOMNode } from "lexical";
|
|
12
11
|
import { $findMatchingParent, mergeRegister } from "@lexical/utils";
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { createDefaultTableColWidths, syncTableWidthDOM } from "../../utils/index.js";
|
|
2
2
|
import { styles } from "./style.js";
|
|
3
3
|
import { getCellColumnIndex, getCellNodeHeight } from "./utils.js";
|
|
4
|
+
import { LOBE_THEME_APP_ID, cssVar, cx } from "@lobehub/ui";
|
|
4
5
|
import { memo, useCallback, useEffect, useRef, useState } from "react";
|
|
5
6
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
6
|
-
import { cssVar, cx } from "antd-style";
|
|
7
7
|
import { $computeTableMapSkipCellCheck, $getTableNodeFromLexicalNodeOrThrow, $getTableRowIndexFromTableCellNode, $isTableCellNode, $isTableNode, $isTableRowNode, TableNode, getDOMCellFromTarget, getTableElement } from "@lexical/table";
|
|
8
8
|
import { $getNearestNodeFromDOMNode, $getNodeByKey, HISTORIC_TAG, SKIP_SCROLL_INTO_VIEW_TAG, isHTMLElement } from "lexical";
|
|
9
9
|
import { calculateZoomLevel, mergeRegister } from "@lexical/utils";
|
|
@@ -317,7 +317,7 @@ const TableCellResize = memo(({ editor, eventEmitter, resizeMode }) => {
|
|
|
317
317
|
});
|
|
318
318
|
var TableResize_default = memo(({ editor, eventEmitter, resizeMode }) => {
|
|
319
319
|
if (typeof document === "undefined") return null;
|
|
320
|
-
const container = document.querySelector(
|
|
320
|
+
const container = document.querySelector(`#${LOBE_THEME_APP_ID}`) || document.body;
|
|
321
321
|
return createPortal(/* @__PURE__ */ jsx(TableCellResize, {
|
|
322
322
|
editor,
|
|
323
323
|
eventEmitter,
|
|
@@ -5,9 +5,9 @@ import { styles } from "./TableController/style.js";
|
|
|
5
5
|
import { createTableDragImage } from "./TableController/utils.js";
|
|
6
6
|
import TableControllerMenu from "./TableControllerMenu.js";
|
|
7
7
|
import TableInsertButton from "./TableInsertButton.js";
|
|
8
|
+
import { cx } from "@lobehub/ui";
|
|
8
9
|
import { memo, useCallback, useEffect, useRef, useState } from "react";
|
|
9
10
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
10
|
-
import { cx } from "antd-style";
|
|
11
11
|
import { $computeTableMapSkipCellCheck } from "@lexical/table";
|
|
12
12
|
//#region src/plugins/table/react/TableRowController.tsx
|
|
13
13
|
const INSERT_BUTTON_HIDE_DELAY = 160;
|
|
@@ -14,9 +14,9 @@ import TableResize_default from "./TableResize/index.js";
|
|
|
14
14
|
import TableRowController from "./TableRowController.js";
|
|
15
15
|
import { useAutoFitPastedTable } from "./useAutoFitPastedTable.js";
|
|
16
16
|
import { useScrollFocusedTableCellIntoView } from "./useScrollFocusedTableCellIntoView.js";
|
|
17
|
+
import { cx } from "@lobehub/ui";
|
|
17
18
|
import { useCallback, useEffect, useLayoutEffect, useMemo, useState } from "react";
|
|
18
19
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
19
|
-
import { cx } from "antd-style";
|
|
20
20
|
import { $findTableNode, $getElementForTableNode, $isTableNode, $isTableSelection } from "@lexical/table";
|
|
21
21
|
import EventEmitter from "eventemitter3";
|
|
22
22
|
import { $getNodeByKey, $getSelection, $isRangeSelection } from "lexical";
|
|
@@ -6,10 +6,9 @@ import { HIDE_TOOLBAR_COMMAND, registerToolbarCommand } from "../command/index.j
|
|
|
6
6
|
import { getDOMRangeRect } from "../utils/getDOMRangeRect.js";
|
|
7
7
|
import { setFloatingElemPosition } from "../utils/setFloatingElemPosition.js";
|
|
8
8
|
import { styles } from "./style.js";
|
|
9
|
+
import { Block, LOBE_THEME_APP_ID, cx, useThemeMode } from "@lobehub/ui";
|
|
9
10
|
import { useCallback, useRef, useState } from "react";
|
|
10
11
|
import { jsx } from "react/jsx-runtime";
|
|
11
|
-
import { Block, LOBE_THEME_APP_ID } from "@lobehub/ui";
|
|
12
|
-
import { cx, useThemeMode } from "antd-style";
|
|
13
12
|
import { $getSelection, COMMAND_PRIORITY_LOW, SELECTION_CHANGE_COMMAND, getDOMSelection } from "lexical";
|
|
14
13
|
import { mergeRegister } from "@lexical/utils";
|
|
15
14
|
import { createPortal } from "react-dom";
|
|
@@ -5,6 +5,7 @@ import { hydrateLexicalFromYjsState, syncCurrentEditorStateToYjs } from "./utils
|
|
|
5
5
|
import { IYjsService, YjsService } from "../service/index.js";
|
|
6
6
|
import { getAwarenessUsers } from "./utils/awareness.js";
|
|
7
7
|
import { registerYjsHistory } from "./utils/history.js";
|
|
8
|
+
import { isNodeIdReconciliationOrigin, reconcileSharedNodeIds } from "./utils/node-identity.js";
|
|
8
9
|
import { $getRoot, COLLABORATION_TAG, COMMAND_PRIORITY_CRITICAL, SKIP_COLLAB_TAG } from "lexical";
|
|
9
10
|
import { UndoManager } from "yjs";
|
|
10
11
|
import { CONNECTED_COMMAND, TOGGLE_CONNECT_COMMAND, createBinding, syncLexicalUpdateToYjs, syncYjsChangesToLexical } from "@lexical/yjs";
|
|
@@ -89,7 +90,8 @@ const YjsPlugin = class extends KernelPlugin {
|
|
|
89
90
|
return;
|
|
90
91
|
}
|
|
91
92
|
if (binding.root.isEmpty() && binding.root._xmlText._length > 0) {
|
|
92
|
-
hydrateLexicalFromYjsState(binding);
|
|
93
|
+
hydrateLexicalFromYjsState(binding, { discrete: true });
|
|
94
|
+
reconcileSharedNodeIds(binding);
|
|
93
95
|
return;
|
|
94
96
|
}
|
|
95
97
|
this.bootstrapCurrentEditorState?.();
|
|
@@ -122,8 +124,8 @@ const YjsPlugin = class extends KernelPlugin {
|
|
|
122
124
|
}
|
|
123
125
|
registerYjsTreeSync(binding, provider) {
|
|
124
126
|
const onYjsTreeChanges = (events, transaction) => {
|
|
125
|
-
if (transaction.origin === binding) return;
|
|
126
|
-
syncYjsChangesToLexical(binding, provider, events, transaction.origin instanceof UndoManager, () =>
|
|
127
|
+
if (transaction.origin === binding || isNodeIdReconciliationOrigin(binding, transaction.origin)) return;
|
|
128
|
+
syncYjsChangesToLexical(binding, provider, events, transaction.origin instanceof UndoManager, () => reconcileSharedNodeIds(binding));
|
|
127
129
|
};
|
|
128
130
|
binding.root.getSharedType().observeDeep(onYjsTreeChanges);
|
|
129
131
|
this.register(() => {
|
|
@@ -1,5 +1,7 @@
|
|
|
1
|
+
import { $normalizeNodeIds, init_node_id, migrateSerializedNodeIds } from "../../../common/node/node-id.js";
|
|
1
2
|
import { $createParagraphNode, $getRoot, HISTORY_MERGE_TAG, SKIP_COLLAB_TAG } from "lexical";
|
|
2
3
|
//#region src/plugins/yjs/plugin/utils/editor-state.ts
|
|
4
|
+
init_node_id();
|
|
3
5
|
function initializeEditor(editor, initialEditorState, options = {}) {
|
|
4
6
|
const { discrete, skipIfNotEmpty = true, tag = HISTORY_MERGE_TAG } = options;
|
|
5
7
|
const updateOptions = Object.keys({
|
|
@@ -13,7 +15,12 @@ function initializeEditor(editor, initialEditorState, options = {}) {
|
|
|
13
15
|
if (editor.getEditorState().read(() => {
|
|
14
16
|
return skipIfNotEmpty && !$getRoot().isEmpty();
|
|
15
17
|
})) return;
|
|
16
|
-
|
|
18
|
+
const serializedState = typeof initialEditorState === "string" ? JSON.parse(initialEditorState) : initialEditorState.toJSON();
|
|
19
|
+
migrateSerializedNodeIds(serializedState.root);
|
|
20
|
+
const parsedState = editor.parseEditorState(serializedState, () => {
|
|
21
|
+
$normalizeNodeIds($getRoot());
|
|
22
|
+
});
|
|
23
|
+
editor.setEditorState(parsedState, updateOptions);
|
|
17
24
|
return;
|
|
18
25
|
}
|
|
19
26
|
editor.update(() => {
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import { $getNodeIdentityPolicy, init_node_identity_policy } from "../../../common/node/node-identity-policy.js";
|
|
2
|
+
import { $getNodeId, $normalizeNodeIds, init_node_id } from "../../../common/node/node-id.js";
|
|
3
|
+
import { $getRoot, $isElementNode, COLLABORATION_TAG, HISTORIC_TAG } from "lexical";
|
|
4
|
+
import { Map as Map$1, createRelativePositionFromTypeIndex } from "yjs";
|
|
5
|
+
//#region src/plugins/yjs/plugin/utils/node-identity.ts
|
|
6
|
+
init_node_id();
|
|
7
|
+
init_node_identity_policy();
|
|
8
|
+
const reconciliationOrigins = /* @__PURE__ */ new WeakMap();
|
|
9
|
+
function getReconciliationOrigin(binding) {
|
|
10
|
+
let origin = reconciliationOrigins.get(binding);
|
|
11
|
+
if (!origin) {
|
|
12
|
+
origin = { type: "lobe-editor-node-id-reconciliation" };
|
|
13
|
+
reconciliationOrigins.set(binding, origin);
|
|
14
|
+
}
|
|
15
|
+
return origin;
|
|
16
|
+
}
|
|
17
|
+
function isNodeIdReconciliationOrigin(binding, origin) {
|
|
18
|
+
const reconciliationOrigin = reconciliationOrigins.get(binding);
|
|
19
|
+
return reconciliationOrigin !== void 0 && origin === reconciliationOrigin;
|
|
20
|
+
}
|
|
21
|
+
function getSharedNodeState(sharedType) {
|
|
22
|
+
const state = sharedType instanceof Map$1 ? sharedType.get("__state") : sharedType.getAttribute("__state");
|
|
23
|
+
return state instanceof Map$1 ? state : void 0;
|
|
24
|
+
}
|
|
25
|
+
function setSharedNodeState(sharedType, state) {
|
|
26
|
+
if (sharedType instanceof Map$1) sharedType.set("__state", state);
|
|
27
|
+
else sharedType.setAttribute("__state", state);
|
|
28
|
+
}
|
|
29
|
+
function getStableSharedIdentity(binding, node) {
|
|
30
|
+
const sharedType = binding.collabNodeMap.get(node.getKey())?.getSharedType();
|
|
31
|
+
if (!sharedType) return void 0;
|
|
32
|
+
const id = createRelativePositionFromTypeIndex(sharedType, 0).type;
|
|
33
|
+
if (!id) return void 0;
|
|
34
|
+
return `${id.client.toString(36).padStart(7, "0")}:${id.clock.toString(36).padStart(11, "0")}`;
|
|
35
|
+
}
|
|
36
|
+
function hasRepairableSharedIdIssues(binding) {
|
|
37
|
+
const editor = binding.editor;
|
|
38
|
+
return editor.getEditorState().read(() => {
|
|
39
|
+
const policy = $getNodeIdentityPolicy();
|
|
40
|
+
const groups = /* @__PURE__ */ new Map();
|
|
41
|
+
let hasMappedMissingId = false;
|
|
42
|
+
const visit = (node) => {
|
|
43
|
+
if (policy.isIdentityNode(node)) {
|
|
44
|
+
const nodeId = $getNodeId(node);
|
|
45
|
+
if (!nodeId) {
|
|
46
|
+
if (getStableSharedIdentity(binding, node)) hasMappedMissingId = true;
|
|
47
|
+
} else {
|
|
48
|
+
const group = groups.get(nodeId) || [];
|
|
49
|
+
group.push(node);
|
|
50
|
+
groups.set(nodeId, group);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
if ($isElementNode(node)) node.getChildren().forEach(visit);
|
|
54
|
+
};
|
|
55
|
+
visit($getRoot());
|
|
56
|
+
if (hasMappedMissingId) return true;
|
|
57
|
+
for (const group of groups.values()) {
|
|
58
|
+
if (group.length < 2 || group.length === 2 && policy.canShareId(group[0], group[1])) continue;
|
|
59
|
+
const identities = group.map((node) => getStableSharedIdentity(binding, node));
|
|
60
|
+
if (identities.every((identity) => Boolean(identity)) && new Set(identities).size === identities.length) return true;
|
|
61
|
+
}
|
|
62
|
+
return false;
|
|
63
|
+
}, { editor });
|
|
64
|
+
}
|
|
65
|
+
function writeRepairedNodeIds(binding, repairs) {
|
|
66
|
+
if (repairs.length === 0) return;
|
|
67
|
+
binding.doc.transact(() => {
|
|
68
|
+
for (const repair of repairs) {
|
|
69
|
+
const sharedType = binding.collabNodeMap.get(repair.nodeKey)?.getSharedType();
|
|
70
|
+
if (!sharedType) continue;
|
|
71
|
+
const existingState = getSharedNodeState(sharedType);
|
|
72
|
+
const state = existingState ?? new Map$1();
|
|
73
|
+
const currentProperties = existingState?.get("properties");
|
|
74
|
+
const properties = currentProperties && typeof currentProperties === "object" && !Array.isArray(currentProperties) ? currentProperties : {};
|
|
75
|
+
state.set("properties", {
|
|
76
|
+
...properties,
|
|
77
|
+
nodeId: repair.nodeId
|
|
78
|
+
});
|
|
79
|
+
if (!existingState) setSharedNodeState(sharedType, state);
|
|
80
|
+
}
|
|
81
|
+
}, getReconciliationOrigin(binding));
|
|
82
|
+
}
|
|
83
|
+
/** Repair shared ID collisions only after the binding has mapped their Yjs types. */
|
|
84
|
+
function reconcileSharedNodeIds(binding) {
|
|
85
|
+
if (!hasRepairableSharedIdIssues(binding)) return;
|
|
86
|
+
const repairs = [];
|
|
87
|
+
binding.editor.update(() => {
|
|
88
|
+
$normalizeNodeIds($getRoot(), {
|
|
89
|
+
onRepair: (node, previousId, nodeId) => {
|
|
90
|
+
if (previousId !== nodeId) repairs.push({
|
|
91
|
+
nodeId,
|
|
92
|
+
nodeKey: node.getKey()
|
|
93
|
+
});
|
|
94
|
+
},
|
|
95
|
+
stableDuplicateRepair: true,
|
|
96
|
+
stableOwnershipKey: (node) => getStableSharedIdentity(binding, node)
|
|
97
|
+
});
|
|
98
|
+
}, {
|
|
99
|
+
discrete: true,
|
|
100
|
+
onUpdate: () => writeRepairedNodeIds(binding, repairs),
|
|
101
|
+
skipTransforms: true,
|
|
102
|
+
tag: [COLLABORATION_TAG, HISTORIC_TAG]
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
//#endregion
|
|
106
|
+
export { isNodeIdReconciliationOrigin, reconcileSharedNodeIds };
|