@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.
Files changed (149) hide show
  1. package/README.md +86 -0
  2. package/es/codemirror/components/CopyButton.js +1 -1
  3. package/es/codemirror/components/LanguageSelect.js +1 -3
  4. package/es/codemirror/components/MoreOptions.js +1 -2
  5. package/es/codemirror/components/Toolbar.js +1 -2
  6. package/es/codemirror/components/style.js +1 -1
  7. package/es/codemirror/style.js +1 -1
  8. package/es/codemirror/theme.js +1 -1
  9. package/es/editor-kernel/index.d.ts +2 -2
  10. package/es/editor-kernel/index.js +2 -2
  11. package/es/editor-kernel/react/useAnchor.js +1 -1
  12. package/es/headless/index.d.ts +5 -2
  13. package/es/headless/index.js +20 -22
  14. package/es/headless.d.ts +6 -507
  15. package/es/headless.js +903 -408
  16. package/es/i-node-identity-service-BBC_bg97.d.ts +522 -0
  17. package/es/index.d.ts +4 -2
  18. package/es/index.js +5 -2
  19. package/es/plugins/auto-complete/react/ReactAutoCompletePlugin.js +1 -1
  20. package/es/plugins/auto-complete/react/style.js +1 -1
  21. package/es/plugins/block/react/ReactBlockPlugin.js +2 -7
  22. package/es/plugins/block/react/style.js +1 -1
  23. package/es/plugins/code/react/CodeReactPlugin.js +1 -1
  24. package/es/plugins/code/react/style.js +1 -1
  25. package/es/plugins/codeblock/react/ReactCodeblockPlugin.js +1 -1
  26. package/es/plugins/codeblock/react/style.js +1 -1
  27. package/es/plugins/codemirror-block/react/CodemirrorNode.js +1 -3
  28. package/es/plugins/codemirror-block/react/MermaidPreview.js +1 -2
  29. package/es/plugins/collapsible/react/ReactCollapsiblePlugin.js +1 -1
  30. package/es/plugins/collapsible/react/style.js +74 -64
  31. package/es/plugins/common/data-source/json-data-source.js +33 -25
  32. package/es/plugins/common/data-source/text-data-source.js +6 -1
  33. package/es/plugins/common/index.d.ts +3 -1
  34. package/es/plugins/common/node/node-id.d.ts +7 -0
  35. package/es/plugins/common/node/node-id.js +484 -0
  36. package/es/plugins/common/node/node-identity-policy.d.ts +26 -0
  37. package/es/plugins/common/node/node-identity-policy.js +68 -0
  38. package/es/plugins/common/plugin/index.js +28 -2
  39. package/es/plugins/common/react/Placeholder/style.js +1 -1
  40. package/es/plugins/common/react/ReactPlainText.js +1 -1
  41. package/es/plugins/common/react/style.js +1 -1
  42. package/es/plugins/common/service/i-node-identity-service.d.ts +19 -0
  43. package/es/plugins/common/service/i-node-identity-service.js +4 -0
  44. package/es/plugins/common/service/node-identity-service.js +87 -0
  45. package/es/plugins/common/utils/index.js +3 -1
  46. package/es/plugins/file/react/components/ReactFile.js +1 -1
  47. package/es/plugins/file/react/style.js +1 -1
  48. package/es/plugins/hr/react/components/HRNode.js +1 -1
  49. package/es/plugins/hr/react/style.js +1 -1
  50. package/es/plugins/image/react/components/Image.js +1 -3
  51. package/es/plugins/image/react/components/ImageEditPopover.js +1 -3
  52. package/es/plugins/image/react/components/LazyImage.js +1 -1
  53. package/es/plugins/image/react/components/ResizeHandle.js +1 -1
  54. package/es/plugins/image/react/components/style.js +1 -1
  55. package/es/plugins/image/react/style.js +1 -1
  56. package/es/plugins/link/react/ReactLinkPlugin.js +1 -1
  57. package/es/plugins/link/react/components/LinkEdit.js +1 -3
  58. package/es/plugins/link/react/components/LinkToolbar.js +1 -1
  59. package/es/plugins/link/react/style.js +1 -1
  60. package/es/plugins/link-highlight/react/ReactLinkHighlightPlugin.js +1 -1
  61. package/es/plugins/link-highlight/react/style.js +1 -1
  62. package/es/plugins/list/plugin/index.js +7 -1
  63. package/es/plugins/list/react/style.js +1 -1
  64. package/es/plugins/litexml/command/index.d.ts +2 -2
  65. package/es/plugins/litexml/command/index.js +464 -292
  66. package/es/plugins/litexml/command/symbols.d.ts +18 -7
  67. package/es/plugins/litexml/command/symbols.js +2 -1
  68. package/es/plugins/litexml/data-source/litexml-data-source.js +34 -31
  69. package/es/plugins/litexml/diff-validation.js +68 -14
  70. package/es/plugins/litexml/index.d.ts +2 -2
  71. package/es/plugins/litexml/node/identity-policy.js +91 -0
  72. package/es/plugins/litexml/plugin/index.js +6 -0
  73. package/es/plugins/litexml/react/DiffNodeToolbar/index.js +1 -3
  74. package/es/plugins/litexml/react/DiffNodeToolbar/style.js +1 -1
  75. package/es/plugins/litexml/react/TableRowDiffToolbar.js +1 -3
  76. package/es/plugins/litexml/react/style.js +1 -1
  77. package/es/plugins/litexml/table-cell-diff.js +4 -0
  78. package/es/plugins/litexml/table-row-diff.js +4 -0
  79. package/es/plugins/litexml/utils/index.js +10 -23
  80. package/es/plugins/markdown/command/index.js +77 -4
  81. package/es/plugins/markdown/data-source/markdown-data-source.js +6 -1
  82. package/es/plugins/markdown/react/index.js +1 -1
  83. package/es/plugins/math/react/components/MathEditorContainer.js +1 -1
  84. package/es/plugins/math/react/components/MathEditorContent.js +1 -2
  85. package/es/plugins/math/react/components/Placeholder.js +1 -3
  86. package/es/plugins/math/react/style.js +1 -1
  87. package/es/plugins/mention/react/components/Mention.js +1 -1
  88. package/es/plugins/mention/react/style.js +1 -1
  89. package/es/plugins/slash/react/components/DefaultSlashMenu.js +1 -2
  90. package/es/plugins/slash/service/i-slash-service.d.ts +2 -2
  91. package/es/plugins/table/react/TableActionMenu/ActionMenu.js +1 -1
  92. package/es/plugins/table/react/TableActionMenu/index.js +1 -1
  93. package/es/plugins/table/react/TableActionMenu/style.js +1 -1
  94. package/es/plugins/table/react/TableColController.js +1 -1
  95. package/es/plugins/table/react/TableController/style.js +1 -1
  96. package/es/plugins/table/react/TableControllerButton.js +2 -2
  97. package/es/plugins/table/react/TableControllerMenu.js +2 -2
  98. package/es/plugins/table/react/TableHoverActions/index.js +1 -2
  99. package/es/plugins/table/react/TableHoverActions/style.js +1 -1
  100. package/es/plugins/table/react/TableResize/index.js +2 -2
  101. package/es/plugins/table/react/TableResize/style.js +1 -1
  102. package/es/plugins/table/react/TableRowController.js +1 -1
  103. package/es/plugins/table/react/index.js +1 -1
  104. package/es/plugins/table/react/style.js +1 -1
  105. package/es/plugins/toolbar/react/index.js +1 -2
  106. package/es/plugins/toolbar/react/style.js +1 -1
  107. package/es/plugins/yjs/plugin/index.js +5 -3
  108. package/es/plugins/yjs/plugin/utils/editor-state.js +8 -1
  109. package/es/plugins/yjs/plugin/utils/node-identity.js +106 -0
  110. package/es/plugins/yjs/service/index.js +38 -4
  111. package/es/react/ChatInput/ChatInput.js +1 -2
  112. package/es/react/ChatInput/style.js +1 -1
  113. package/es/react/ChatInput/type.d.ts +1 -1
  114. package/es/react/ChatInputActionBar/ChatInputActionBar.js +1 -2
  115. package/es/react/ChatInputActionBar/style.js +1 -1
  116. package/es/react/ChatInputActionBar/type.d.ts +1 -1
  117. package/es/react/ChatInputActions/ChatInputActions.js +1 -2
  118. package/es/react/ChatInputActions/components/ActionItem.js +1 -1
  119. package/es/react/ChatInputActions/components/ActionRender.js +1 -1
  120. package/es/react/ChatInputActions/components/CollapsedActions.js +1 -2
  121. package/es/react/ChatInputActions/style.js +1 -1
  122. package/es/react/ChatInputActions/type.d.ts +4 -4
  123. package/es/react/CodeLanguageSelect/CodeLanguageSelect.js +1 -3
  124. package/es/react/CodeLanguageSelect/style.js +1 -1
  125. package/es/react/CodeLanguageSelect/type.d.ts +1 -1
  126. package/es/react/FloatActions/FloatActions.js +1 -2
  127. package/es/react/FloatActions/components/ActionItem.js +1 -1
  128. package/es/react/FloatActions/components/ActionRender.js +1 -1
  129. package/es/react/FloatActions/components/CollapsedActions.js +1 -2
  130. package/es/react/FloatActions/style.js +1 -1
  131. package/es/react/FloatActions/type.d.ts +4 -4
  132. package/es/react/SendButton/SendButton.js +1 -2
  133. package/es/react/SendButton/components/SendIcon.js +1 -1
  134. package/es/react/SendButton/components/StopIcon.js +1 -1
  135. package/es/react/SendButton/style.js +1 -1
  136. package/es/react/SendButton/type.d.ts +1 -1
  137. package/es/renderer/LexicalDiff.js +1 -1
  138. package/es/renderer/LexicalRenderer.js +1 -1
  139. package/es/renderer/diff/compute.js +2 -2
  140. package/es/renderer/diff/style.js +1 -1
  141. package/es/renderer/engine/render-builtin-node.js +2 -2
  142. package/es/renderer/renderers/codeblock.js +1 -1
  143. package/es/renderer/renderers/horizontalrule.js +1 -1
  144. package/es/renderer/renderers/mermaid.js +1 -1
  145. package/es/renderer/style.js +1 -1
  146. package/es/{symbols-Do7jD4Tt.d.ts → symbols-Dyr9yyS0.d.ts} +18 -7
  147. package/package.json +6 -8
  148. package/scripts/postinstall-lexical-patch.cjs +0 -21
  149. package/patches/lexical@0.42.0.patch +0 -82
@@ -1,26 +1,22 @@
1
- import { $isElementNode, resetRandomKey } from "lexical";
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
- const getNumericId = (id) => {
4
- if (typeof id !== "number" && typeof id !== "string") return null;
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, keepId, state);
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, charToId, idToChar };
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 s = kernel.getSelection();
42
- if (s) {
43
- newEditor.setSelection(s);
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.setEditorState(editor.parseEditorState(inode));
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/base-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/base-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,4 +1,4 @@
1
- import { createStaticStyles, cx } from "antd-style";
1
+ import { createStaticStyles, cx } from "@lobehub/ui";
2
2
  //#region src/plugins/math/react/style.ts
3
3
  const styles = createStaticStyles(({ css, cssVar }) => {
4
4
  const latex = css`
@@ -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,4 +1,4 @@
1
- import { createStaticStyles } from "antd-style";
1
+ import { createStaticStyles } from "@lobehub/ui";
2
2
  //#region src/plugins/mention/react/style.ts
3
3
  const styles = createStaticStyles(({ css, cssVar }) => ({ mention: css`
4
4
  user-select: none;
@@ -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 DropdownMenuItemType {
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/base-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";
@@ -1,4 +1,4 @@
1
- import { createStaticStyles } from "antd-style";
1
+ import { createStaticStyles } from "@lobehub/ui";
2
2
  //#region src/plugins/table/react/TableActionMenu/style.ts
3
3
  const styles = createStaticStyles(({ css }) => ({
4
4
  actionIcon: css`
@@ -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 "antd-style";
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(".ant-app") || document.body;
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(".ant-app") || document.body;
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/base-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,4 +1,4 @@
1
- import { createStaticStyles } from "antd-style";
1
+ import { createStaticStyles } from "@lobehub/ui";
2
2
  //#region src/plugins/table/react/TableHoverActions/style.ts
3
3
  const styles = createStaticStyles(({ css }) => {
4
4
  return {
@@ -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(".ant-app") || document.body;
320
+ const container = document.querySelector(`#${LOBE_THEME_APP_ID}`) || document.body;
321
321
  return createPortal(/* @__PURE__ */ jsx(TableCellResize, {
322
322
  editor,
323
323
  eventEmitter,
@@ -1,4 +1,4 @@
1
- import { createStaticStyles } from "antd-style";
1
+ import { createStaticStyles } from "@lobehub/ui";
2
2
  //#region src/plugins/table/react/TableResize/style.ts
3
3
  const styles = createStaticStyles(({ css, cssVar }) => {
4
4
  return css`
@@ -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";
@@ -1,4 +1,4 @@
1
- import { createStaticStyles } from "antd-style";
1
+ import { createStaticStyles } from "@lobehub/ui";
2
2
  //#region src/plugins/table/react/style.ts
3
3
  const styles = createStaticStyles(({ css, cssVar }) => css`
4
4
  position: relative;
@@ -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";
@@ -1,4 +1,4 @@
1
- import { createStaticStyles } from "antd-style";
1
+ import { createStaticStyles } from "@lobehub/ui";
2
2
  //#region src/plugins/toolbar/react/style.ts
3
3
  const FLOATING_TOOLBAR_Z_INDEX = 1001;
4
4
  const styles = createStaticStyles(({ css, cssVar }) => ({
@@ -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, () => void 0);
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
- editor.setEditorState(typeof initialEditorState === "string" ? editor.parseEditorState(initialEditorState) : initialEditorState, updateOptions);
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 };