@datalayer/lexical-loro 1.0.2 → 1.0.5

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 (402) hide show
  1. package/README.md +2 -2
  2. package/lib/App.d.ts +2 -0
  3. package/lib/App.js +141 -0
  4. package/lib/Editor.d.ts +2 -0
  5. package/lib/Editor.js +116 -0
  6. package/lib/Settings.d.ts +2 -0
  7. package/lib/Settings.js +57 -0
  8. package/lib/appSettings.d.ts +36 -0
  9. package/lib/appSettings.js +48 -0
  10. package/lib/collab/loro/Bindings.d.ts +41 -0
  11. package/lib/collab/loro/Bindings.js +99 -0
  12. package/lib/collab/loro/Debug.d.ts +33 -0
  13. package/lib/collab/loro/Debug.js +452 -0
  14. package/lib/collab/loro/LexicalCollaborationContext.d.ts +19 -0
  15. package/lib/collab/loro/LexicalCollaborationContext.js +52 -0
  16. package/lib/collab/loro/LexicalCollaborationPlugin.d.ts +29 -0
  17. package/lib/collab/loro/LexicalCollaborationPlugin.js +111 -0
  18. package/lib/collab/loro/State.d.ts +53 -0
  19. package/lib/collab/loro/State.js +94 -0
  20. package/lib/collab/loro/components/LoroCollaborationUI.d.ts +13 -0
  21. package/lib/collab/loro/components/LoroCollaborationUI.js +9 -0
  22. package/lib/collab/loro/components/LoroCollaborators.d.ts +8 -0
  23. package/lib/collab/loro/components/LoroCollaborators.js +90 -0
  24. package/lib/collab/loro/components/index.d.ts +2 -0
  25. package/lib/collab/loro/components/index.js +6 -0
  26. package/lib/collab/loro/index.d.ts +6 -0
  27. package/lib/collab/loro/index.js +10 -0
  28. package/lib/collab/loro/integrators/BaseIntegrator.d.ts +14 -0
  29. package/lib/collab/loro/integrators/BaseIntegrator.js +5 -0
  30. package/lib/collab/loro/integrators/CounterIntegrator.d.ts +23 -0
  31. package/lib/collab/loro/integrators/CounterIntegrator.js +44 -0
  32. package/lib/collab/loro/integrators/ListIntegrator.d.ts +23 -0
  33. package/lib/collab/loro/integrators/ListIntegrator.js +53 -0
  34. package/lib/collab/loro/integrators/MapIntegrator.d.ts +24 -0
  35. package/lib/collab/loro/integrators/MapIntegrator.js +235 -0
  36. package/lib/collab/loro/integrators/TextIntegrator.d.ts +25 -0
  37. package/lib/collab/loro/integrators/TextIntegrator.js +55 -0
  38. package/lib/collab/loro/integrators/TreeIntegrator.d.ts +41 -0
  39. package/lib/collab/loro/integrators/TreeIntegrator.js +293 -0
  40. package/lib/collab/loro/nodes/NodeFactory.d.ts +15 -0
  41. package/lib/collab/loro/nodes/NodeFactory.js +80 -0
  42. package/lib/collab/loro/nodes/NodesMapper.d.ts +120 -0
  43. package/lib/collab/loro/nodes/NodesMapper.js +289 -0
  44. package/lib/collab/loro/propagators/DecoratorNodePropagator.d.ts +60 -0
  45. package/lib/collab/loro/propagators/DecoratorNodePropagator.js +306 -0
  46. package/lib/collab/loro/propagators/ElementNodePropagator.d.ts +62 -0
  47. package/lib/collab/loro/propagators/ElementNodePropagator.js +393 -0
  48. package/lib/collab/loro/propagators/LineBreakNodePropagator.d.ts +57 -0
  49. package/lib/collab/loro/propagators/LineBreakNodePropagator.js +200 -0
  50. package/lib/collab/loro/propagators/RootNodePropagator.d.ts +55 -0
  51. package/lib/collab/loro/propagators/RootNodePropagator.js +174 -0
  52. package/lib/collab/loro/propagators/TextNodePropagator.d.ts +60 -0
  53. package/lib/collab/loro/propagators/TextNodePropagator.js +450 -0
  54. package/lib/collab/loro/propagators/index.d.ts +49 -0
  55. package/lib/collab/loro/propagators/index.js +30 -0
  56. package/lib/collab/loro/provider/websocket.d.ts +117 -0
  57. package/lib/collab/loro/provider/websocket.js +946 -0
  58. package/lib/collab/loro/servers/index.d.ts +0 -0
  59. package/lib/collab/loro/servers/index.js +4 -0
  60. package/lib/collab/loro/servers/ws/callback.d.ts +5 -0
  61. package/lib/collab/loro/servers/ws/callback.js +89 -0
  62. package/lib/collab/loro/servers/ws/server.d.ts +2 -0
  63. package/lib/collab/loro/servers/ws/server.js +29 -0
  64. package/lib/collab/loro/servers/ws/utils.d.ts +40 -0
  65. package/lib/collab/loro/servers/ws/utils.js +517 -0
  66. package/lib/collab/loro/sync/SyncCursors.d.ts +32 -0
  67. package/lib/collab/loro/sync/SyncCursors.js +501 -0
  68. package/lib/collab/loro/sync/SyncLexicalToLoro.d.ts +4 -0
  69. package/lib/collab/loro/sync/SyncLexicalToLoro.js +152 -0
  70. package/lib/collab/loro/sync/SyncLoroToLexical.d.ts +5 -0
  71. package/lib/collab/loro/sync/SyncLoroToLexical.js +106 -0
  72. package/lib/collab/loro/types/LexicalNodeData.d.ts +32 -0
  73. package/lib/collab/loro/types/LexicalNodeData.js +75 -0
  74. package/lib/collab/loro/useCollaboration.d.ts +12 -0
  75. package/lib/collab/loro/useCollaboration.js +405 -0
  76. package/lib/collab/loro/utils/InitialContent.d.ts +64 -0
  77. package/lib/collab/loro/utils/InitialContent.js +113 -0
  78. package/lib/collab/loro/utils/Invariant.d.ts +15 -0
  79. package/lib/collab/loro/utils/Invariant.js +24 -0
  80. package/lib/collab/loro/utils/LexicalToLoro.d.ts +18 -0
  81. package/lib/collab/loro/utils/LexicalToLoro.js +100 -0
  82. package/lib/collab/loro/utils/Utils.d.ts +44 -0
  83. package/lib/collab/loro/utils/Utils.js +157 -0
  84. package/lib/collab/loro/wsProvider.d.ts +8 -0
  85. package/lib/collab/loro/wsProvider.js +52 -0
  86. package/lib/collab/utils/invariant.d.ts +1 -0
  87. package/lib/collab/utils/invariant.js +15 -0
  88. package/lib/collab/utils/simpleDiffWithCursor.d.ts +5 -0
  89. package/lib/collab/utils/simpleDiffWithCursor.js +35 -0
  90. package/lib/collab/yjs/Bindings.d.ts +23 -0
  91. package/lib/collab/yjs/Bindings.js +26 -0
  92. package/lib/collab/yjs/Debug.d.ts +23 -0
  93. package/lib/collab/yjs/Debug.js +213 -0
  94. package/lib/collab/yjs/LexicalCollaborationContext.d.ts +10 -0
  95. package/lib/collab/yjs/LexicalCollaborationContext.js +37 -0
  96. package/lib/collab/yjs/LexicalCollaborationPlugin.d.ts +21 -0
  97. package/lib/collab/yjs/LexicalCollaborationPlugin.js +63 -0
  98. package/lib/collab/yjs/State.d.ts +51 -0
  99. package/lib/collab/yjs/State.js +35 -0
  100. package/lib/collab/yjs/nodes/AnyCollabNode.d.ts +5 -0
  101. package/lib/collab/yjs/nodes/AnyCollabNode.js +1 -0
  102. package/lib/collab/yjs/nodes/CollabDecoratorNode.d.ts +22 -0
  103. package/lib/collab/yjs/nodes/CollabDecoratorNode.js +64 -0
  104. package/lib/collab/yjs/nodes/CollabElementNode.d.ts +40 -0
  105. package/lib/collab/yjs/nodes/CollabElementNode.js +462 -0
  106. package/lib/collab/yjs/nodes/CollabLineBreakNode.d.ts +19 -0
  107. package/lib/collab/yjs/nodes/CollabLineBreakNode.js +44 -0
  108. package/lib/collab/yjs/nodes/CollabTextNode.d.ts +25 -0
  109. package/lib/collab/yjs/nodes/CollabTextNode.js +103 -0
  110. package/lib/collab/yjs/provider/websocket.d.ts +88 -0
  111. package/lib/collab/yjs/provider/websocket.js +415 -0
  112. package/lib/collab/yjs/servers/index.d.ts +0 -0
  113. package/lib/collab/yjs/servers/index.js +0 -0
  114. package/lib/collab/yjs/servers/ws/callback.d.ts +5 -0
  115. package/lib/collab/yjs/servers/ws/callback.js +72 -0
  116. package/lib/collab/yjs/servers/ws/server.d.ts +2 -0
  117. package/lib/collab/yjs/servers/ws/server.js +25 -0
  118. package/lib/collab/yjs/servers/ws/utils.d.ts +49 -0
  119. package/lib/collab/yjs/servers/ws/utils.js +284 -0
  120. package/lib/collab/yjs/sync/SyncCursors.d.ts +39 -0
  121. package/lib/collab/yjs/sync/SyncCursors.js +351 -0
  122. package/lib/collab/yjs/sync/SyncEditorStates.d.ts +10 -0
  123. package/lib/collab/yjs/sync/SyncEditorStates.js +200 -0
  124. package/lib/collab/yjs/useCollaboration.d.ts +12 -0
  125. package/lib/collab/yjs/useCollaboration.js +255 -0
  126. package/lib/collab/yjs/utils/Utils.d.ts +25 -0
  127. package/lib/collab/yjs/utils/Utils.js +402 -0
  128. package/lib/collab/yjs/wsProvider.d.ts +3 -0
  129. package/lib/collab/yjs/wsProvider.js +21 -0
  130. package/lib/commenting/index.d.ts +41 -0
  131. package/lib/commenting/index.js +328 -0
  132. package/lib/context/FlashMessageContext.d.ts +7 -0
  133. package/lib/context/FlashMessageContext.js +24 -0
  134. package/lib/context/SettingsContext.d.ts +12 -0
  135. package/lib/context/SettingsContext.js +38 -0
  136. package/lib/context/SharedHistoryContext.d.ts +11 -0
  137. package/lib/context/SharedHistoryContext.js +11 -0
  138. package/lib/context/ToolbarContext.d.ts +65 -0
  139. package/lib/context/ToolbarContext.js +84 -0
  140. package/lib/demo.d.ts +12 -0
  141. package/lib/demo.js +45 -0
  142. package/lib/hooks/useFlashMessage.d.ts +2 -0
  143. package/lib/hooks/useFlashMessage.js +8 -0
  144. package/lib/hooks/useModal.d.ts +5 -0
  145. package/lib/hooks/useModal.js +26 -0
  146. package/lib/hooks/useReport.d.ts +1 -0
  147. package/lib/hooks/useReport.js +50 -0
  148. package/lib/index.d.ts +1 -0
  149. package/lib/index.js +5 -0
  150. package/lib/nodes/AutocompleteNode.d.ts +27 -0
  151. package/lib/nodes/AutocompleteNode.js +60 -0
  152. package/lib/nodes/CounterComponent.d.ts +6 -0
  153. package/lib/nodes/CounterComponent.js +137 -0
  154. package/lib/nodes/CounterNode.d.ts +23 -0
  155. package/lib/nodes/CounterNode.js +47 -0
  156. package/lib/nodes/DateTimeNode/DateTimeComponent.d.ts +8 -0
  157. package/lib/nodes/DateTimeNode/DateTimeComponent.js +119 -0
  158. package/lib/nodes/DateTimeNode/DateTimeNode.d.ts +27 -0
  159. package/lib/nodes/DateTimeNode/DateTimeNode.js +82 -0
  160. package/lib/nodes/EmojiNode.d.ts +18 -0
  161. package/lib/nodes/EmojiNode.js +54 -0
  162. package/lib/nodes/EquationComponent.d.ts +9 -0
  163. package/lib/nodes/EquationComponent.js +75 -0
  164. package/lib/nodes/EquationNode.d.ts +26 -0
  165. package/lib/nodes/EquationNode.js +109 -0
  166. package/lib/nodes/ExcalidrawNode/ExcalidrawComponent.d.ts +8 -0
  167. package/lib/nodes/ExcalidrawNode/ExcalidrawComponent.js +110 -0
  168. package/lib/nodes/ExcalidrawNode/ExcalidrawImage.d.ts +50 -0
  169. package/lib/nodes/ExcalidrawNode/ExcalidrawImage.js +55 -0
  170. package/lib/nodes/ExcalidrawNode/index.d.ts +32 -0
  171. package/lib/nodes/ExcalidrawNode/index.js +117 -0
  172. package/lib/nodes/FigmaNode.d.ts +20 -0
  173. package/lib/nodes/FigmaNode.js +52 -0
  174. package/lib/nodes/ImageComponent.d.ts +16 -0
  175. package/lib/nodes/ImageComponent.js +272 -0
  176. package/lib/nodes/ImageNode.d.ts +50 -0
  177. package/lib/nodes/ImageNode.js +151 -0
  178. package/lib/nodes/InlineImageNode/InlineImageComponent.d.ts +26 -0
  179. package/lib/nodes/InlineImageNode/InlineImageComponent.js +161 -0
  180. package/lib/nodes/InlineImageNode/InlineImageNode.d.ts +59 -0
  181. package/lib/nodes/InlineImageNode/InlineImageNode.js +162 -0
  182. package/lib/nodes/KeywordNode.d.ts +14 -0
  183. package/lib/nodes/KeywordNode.js +37 -0
  184. package/lib/nodes/LayoutContainerNode.d.ts +24 -0
  185. package/lib/nodes/LayoutContainerNode.js +95 -0
  186. package/lib/nodes/LayoutItemNode.d.ts +16 -0
  187. package/lib/nodes/LayoutItemNode.js +69 -0
  188. package/lib/nodes/MentionNode.d.ts +20 -0
  189. package/lib/nodes/MentionNode.js +85 -0
  190. package/lib/nodes/PageBreakNode/index.d.ts +17 -0
  191. package/lib/nodes/PageBreakNode/index.js +83 -0
  192. package/lib/nodes/PlaygroundNodes.d.ts +3 -0
  193. package/lib/nodes/PlaygroundNodes.js +75 -0
  194. package/lib/nodes/PollComponent.d.ts +9 -0
  195. package/lib/nodes/PollComponent.js +85 -0
  196. package/lib/nodes/PollNode.d.ts +43 -0
  197. package/lib/nodes/PollNode.js +153 -0
  198. package/lib/nodes/SpecialTextNode.d.ts +24 -0
  199. package/lib/nodes/SpecialTextNode.js +54 -0
  200. package/lib/nodes/StickyComponent.d.ts +10 -0
  201. package/lib/nodes/StickyComponent.js +162 -0
  202. package/lib/nodes/StickyNode.d.ts +31 -0
  203. package/lib/nodes/StickyNode.js +76 -0
  204. package/lib/nodes/TweetNode.d.ts +21 -0
  205. package/lib/nodes/TweetNode.js +119 -0
  206. package/lib/nodes/YouTubeNode.d.ts +22 -0
  207. package/lib/nodes/YouTubeNode.js +84 -0
  208. package/lib/plugins/ActionsPlugin/index.d.ts +5 -0
  209. package/lib/plugins/ActionsPlugin/index.js +168 -0
  210. package/lib/plugins/AutoEmbedPlugin/index.d.ts +19 -0
  211. package/lib/plugins/AutoEmbedPlugin/index.js +158 -0
  212. package/lib/plugins/AutoLinkPlugin/index.d.ts +2 -0
  213. package/lib/plugins/AutoLinkPlugin/index.js +15 -0
  214. package/lib/plugins/AutocompletePlugin/index.d.ts +10 -0
  215. package/lib/plugins/AutocompletePlugin/index.js +2477 -0
  216. package/lib/plugins/CodeActionMenuPlugin/components/CopyButton/index.d.ts +7 -0
  217. package/lib/plugins/CodeActionMenuPlugin/components/CopyButton/index.js +46 -0
  218. package/lib/plugins/CodeActionMenuPlugin/components/PrettierButton/index.d.ts +17 -0
  219. package/lib/plugins/CodeActionMenuPlugin/components/PrettierButton/index.js +115 -0
  220. package/lib/plugins/CodeActionMenuPlugin/index.d.ts +5 -0
  221. package/lib/plugins/CodeActionMenuPlugin/index.js +104 -0
  222. package/lib/plugins/CodeActionMenuPlugin/utils.d.ts +1 -0
  223. package/lib/plugins/CodeActionMenuPlugin/utils.js +22 -0
  224. package/lib/plugins/CodeHighlightPrismPlugin/index.d.ts +2 -0
  225. package/lib/plugins/CodeHighlightPrismPlugin/index.js +14 -0
  226. package/lib/plugins/CodeHighlightShikiPlugin/index.d.ts +2 -0
  227. package/lib/plugins/CodeHighlightShikiPlugin/index.js +14 -0
  228. package/lib/plugins/CollapsiblePlugin/CollapsibleContainerNode.d.ts +25 -0
  229. package/lib/plugins/CollapsiblePlugin/CollapsibleContainerNode.js +135 -0
  230. package/lib/plugins/CollapsiblePlugin/CollapsibleContentNode.d.ts +16 -0
  231. package/lib/plugins/CollapsiblePlugin/CollapsibleContentNode.js +83 -0
  232. package/lib/plugins/CollapsiblePlugin/CollapsibleTitleNode.d.ts +16 -0
  233. package/lib/plugins/CollapsiblePlugin/CollapsibleTitleNode.js +85 -0
  234. package/lib/plugins/CollapsiblePlugin/CollapsibleUtils.d.ts +2 -0
  235. package/lib/plugins/CollapsiblePlugin/CollapsibleUtils.js +12 -0
  236. package/lib/plugins/CollapsiblePlugin/index.d.ts +3 -0
  237. package/lib/plugins/CollapsiblePlugin/index.js +132 -0
  238. package/lib/plugins/CommentPlugin/index.d.ts +9 -0
  239. package/lib/plugins/CommentPlugin/index.js +460 -0
  240. package/lib/plugins/ComponentPickerPlugin/index.d.ts +2 -0
  241. package/lib/plugins/ComponentPickerPlugin/index.js +276 -0
  242. package/lib/plugins/ContextMenuPlugin/index.d.ts +2 -0
  243. package/lib/plugins/ContextMenuPlugin/index.js +112 -0
  244. package/lib/plugins/CounterPlugin/index.d.ts +3 -0
  245. package/lib/plugins/CounterPlugin/index.js +24 -0
  246. package/lib/plugins/DateTimePlugin/index.d.ts +8 -0
  247. package/lib/plugins/DateTimePlugin/index.js +28 -0
  248. package/lib/plugins/DebugPlugin/index.d.ts +3 -0
  249. package/lib/plugins/DebugPlugin/index.js +275 -0
  250. package/lib/plugins/DocsPlugin/index.d.ts +2 -0
  251. package/lib/plugins/DocsPlugin/index.js +4 -0
  252. package/lib/plugins/DragDropPastePlugin/index.d.ts +1 -0
  253. package/lib/plugins/DragDropPastePlugin/index.js +37 -0
  254. package/lib/plugins/DraggableBlockPlugin/index.d.ts +12 -0
  255. package/lib/plugins/DraggableBlockPlugin/index.js +36 -0
  256. package/lib/plugins/EmojiPickerPlugin/index.d.ts +1 -0
  257. package/lib/plugins/EmojiPickerPlugin/index.js +84 -0
  258. package/lib/plugins/EmojisPlugin/index.d.ts +2 -0
  259. package/lib/plugins/EmojisPlugin/index.js +56 -0
  260. package/lib/plugins/EquationsPlugin/index.d.ts +14 -0
  261. package/lib/plugins/EquationsPlugin/index.js +34 -0
  262. package/lib/plugins/ExcalidrawPlugin/index.d.ts +5 -0
  263. package/lib/plugins/ExcalidrawPlugin/index.js +44 -0
  264. package/lib/plugins/FigmaPlugin/index.d.ts +4 -0
  265. package/lib/plugins/FigmaPlugin/index.js +24 -0
  266. package/lib/plugins/FloatingLinkEditorPlugin/index.d.ts +15 -0
  267. package/lib/plugins/FloatingLinkEditorPlugin/index.js +280 -0
  268. package/lib/plugins/FloatingTextFormatToolbarPlugin/index.d.ts +7 -0
  269. package/lib/plugins/FloatingTextFormatToolbarPlugin/index.js +219 -0
  270. package/lib/plugins/ImagesPlugin/index.d.ts +24 -0
  271. package/lib/plugins/ImagesPlugin/index.js +195 -0
  272. package/lib/plugins/InlineImagePlugin/index.d.ts +17 -0
  273. package/lib/plugins/InlineImagePlugin/index.js +180 -0
  274. package/lib/plugins/KeywordsPlugin/index.d.ts +2 -0
  275. package/lib/plugins/KeywordsPlugin/index.js +35 -0
  276. package/lib/plugins/LayoutPlugin/InsertLayoutDialog.d.ts +6 -0
  277. package/lib/plugins/LayoutPlugin/InsertLayoutDialog.js +21 -0
  278. package/lib/plugins/LayoutPlugin/LayoutPlugin.d.ts +7 -0
  279. package/lib/plugins/LayoutPlugin/LayoutPlugin.js +135 -0
  280. package/lib/plugins/LinkPlugin/index.d.ts +6 -0
  281. package/lib/plugins/LinkPlugin/index.js +11 -0
  282. package/lib/plugins/MarkdownShortcutPlugin/index.d.ts +2 -0
  283. package/lib/plugins/MarkdownShortcutPlugin/index.js +6 -0
  284. package/lib/plugins/MarkdownTransformers/index.d.ts +8 -0
  285. package/lib/plugins/MarkdownTransformers/index.js +238 -0
  286. package/lib/plugins/MaxLengthPlugin/index.d.ts +3 -0
  287. package/lib/plugins/MaxLengthPlugin/index.js +41 -0
  288. package/lib/plugins/MentionsPlugin/index.d.ts +2 -0
  289. package/lib/plugins/MentionsPlugin/index.js +564 -0
  290. package/lib/plugins/PageBreakPlugin/index.d.ts +4 -0
  291. package/lib/plugins/PageBreakPlugin/index.js +31 -0
  292. package/lib/plugins/PasteLogPlugin/index.d.ts +2 -0
  293. package/lib/plugins/PasteLogPlugin/index.js +27 -0
  294. package/lib/plugins/PollPlugin/index.d.ts +8 -0
  295. package/lib/plugins/PollPlugin/index.js +38 -0
  296. package/lib/plugins/ShortcutsPlugin/index.d.ts +6 -0
  297. package/lib/plugins/ShortcutsPlugin/index.js +116 -0
  298. package/lib/plugins/ShortcutsPlugin/shortcuts.d.ts +59 -0
  299. package/lib/plugins/ShortcutsPlugin/shortcuts.js +173 -0
  300. package/lib/plugins/SpecialTextPlugin/index.d.ts +2 -0
  301. package/lib/plugins/SpecialTextPlugin/index.js +50 -0
  302. package/lib/plugins/SpeechToTextPlugin/index.d.ts +5 -0
  303. package/lib/plugins/SpeechToTextPlugin/index.js +86 -0
  304. package/lib/plugins/StickyPlugin/index.d.ts +2 -0
  305. package/lib/plugins/StickyPlugin/index.js +16 -0
  306. package/lib/plugins/TabFocusPlugin/index.d.ts +1 -0
  307. package/lib/plugins/TabFocusPlugin/index.js +38 -0
  308. package/lib/plugins/TableActionMenuPlugin/index.d.ts +5 -0
  309. package/lib/plugins/TableActionMenuPlugin/index.js +492 -0
  310. package/lib/plugins/TableCellResizer/index.d.ts +3 -0
  311. package/lib/plugins/TableCellResizer/index.js +297 -0
  312. package/lib/plugins/TableHoverActionsPlugin/index.d.ts +4 -0
  313. package/lib/plugins/TableHoverActionsPlugin/index.js +188 -0
  314. package/lib/plugins/TableOfContentsPlugin/index.d.ts +2 -0
  315. package/lib/plugins/TableOfContentsPlugin/index.js +116 -0
  316. package/lib/plugins/TablePlugin.d.ts +31 -0
  317. package/lib/plugins/TablePlugin.js +63 -0
  318. package/lib/plugins/TestRecorderPlugin/index.d.ts +3 -0
  319. package/lib/plugins/TestRecorderPlugin/index.js +346 -0
  320. package/lib/plugins/ToolbarPlugin/fontSize.d.ts +9 -0
  321. package/lib/plugins/ToolbarPlugin/fontSize.js +84 -0
  322. package/lib/plugins/ToolbarPlugin/index.d.ts +9 -0
  323. package/lib/plugins/ToolbarPlugin/index.js +500 -0
  324. package/lib/plugins/ToolbarPlugin/utils.d.ts +26 -0
  325. package/lib/plugins/ToolbarPlugin/utils.js +247 -0
  326. package/lib/plugins/TreeViewPlugin/index.d.ts +2 -0
  327. package/lib/plugins/TreeViewPlugin/index.js +7 -0
  328. package/lib/plugins/TwitterPlugin/index.d.ts +4 -0
  329. package/lib/plugins/TwitterPlugin/index.js +24 -0
  330. package/lib/plugins/TypingPerfPlugin/index.d.ts +2 -0
  331. package/lib/plugins/TypingPerfPlugin/index.js +97 -0
  332. package/lib/plugins/YouTubePlugin/index.d.ts +4 -0
  333. package/lib/plugins/YouTubePlugin/index.js +24 -0
  334. package/lib/server/validation.d.ts +1 -0
  335. package/lib/server/validation.js +115 -0
  336. package/lib/setupEnv.d.ts +2 -0
  337. package/lib/setupEnv.js +29 -0
  338. package/lib/themes/CommentEditorTheme.d.ts +4 -0
  339. package/lib/themes/CommentEditorTheme.js +11 -0
  340. package/lib/themes/PlaygroundEditorTheme.d.ts +4 -0
  341. package/lib/themes/PlaygroundEditorTheme.js +124 -0
  342. package/lib/themes/StickyEditorTheme.d.ts +4 -0
  343. package/lib/themes/StickyEditorTheme.js +11 -0
  344. package/lib/tyes.dt.d.ts +12 -0
  345. package/lib/tyes.dt.js +4 -0
  346. package/lib/ui/Button.d.ts +12 -0
  347. package/lib/ui/Button.js +6 -0
  348. package/lib/ui/ColorPicker.d.ts +14 -0
  349. package/lib/ui/ColorPicker.js +219 -0
  350. package/lib/ui/ContentEditable.d.ts +9 -0
  351. package/lib/ui/ContentEditable.js +6 -0
  352. package/lib/ui/Dialog.d.ts +10 -0
  353. package/lib/ui/Dialog.js +8 -0
  354. package/lib/ui/DropDown.d.ts +18 -0
  355. package/lib/ui/DropDown.js +133 -0
  356. package/lib/ui/DropdownColorPicker.d.ts +13 -0
  357. package/lib/ui/DropdownColorPicker.js +6 -0
  358. package/lib/ui/EquationEditor.d.ts +8 -0
  359. package/lib/ui/EquationEditor.js +11 -0
  360. package/lib/ui/ExcalidrawModal.d.ts +42 -0
  361. package/lib/ui/ExcalidrawModal.js +103 -0
  362. package/lib/ui/FileInput.d.ts +10 -0
  363. package/lib/ui/FileInput.js +5 -0
  364. package/lib/ui/FlashMessage.d.ts +7 -0
  365. package/lib/ui/FlashMessage.js +6 -0
  366. package/lib/ui/ImageResizer.d.ts +17 -0
  367. package/lib/ui/ImageResizer.js +171 -0
  368. package/lib/ui/KatexEquationAlterer.d.ts +8 -0
  369. package/lib/ui/KatexEquationAlterer.js +23 -0
  370. package/lib/ui/KatexRenderer.d.ts +6 -0
  371. package/lib/ui/KatexRenderer.js +24 -0
  372. package/lib/ui/Modal.d.ts +9 -0
  373. package/lib/ui/Modal.js +48 -0
  374. package/lib/ui/Select.d.ts +8 -0
  375. package/lib/ui/Select.js +5 -0
  376. package/lib/ui/Switch.d.ts +8 -0
  377. package/lib/ui/Switch.js +6 -0
  378. package/lib/ui/TextInput.d.ts +13 -0
  379. package/lib/ui/TextInput.js +7 -0
  380. package/lib/utils/docSerialization.d.ts +3 -0
  381. package/lib/utils/docSerialization.js +60 -0
  382. package/lib/utils/emoji-list.d.ts +20 -0
  383. package/lib/utils/emoji-list.js +16609 -0
  384. package/lib/utils/getDOMRangeRect.d.ts +8 -0
  385. package/lib/utils/getDOMRangeRect.js +26 -0
  386. package/lib/utils/getSelectedNode.d.ts +2 -0
  387. package/lib/utils/getSelectedNode.js +28 -0
  388. package/lib/utils/getThemeSelector.d.ts +2 -0
  389. package/lib/utils/getThemeSelector.js +14 -0
  390. package/lib/utils/isMobileWidth.d.ts +7 -0
  391. package/lib/utils/isMobileWidth.js +11 -0
  392. package/lib/utils/joinClasses.d.ts +1 -0
  393. package/lib/utils/joinClasses.js +7 -0
  394. package/lib/utils/setFloatingElemPosition.d.ts +1 -0
  395. package/lib/utils/setFloatingElemPosition.js +59 -0
  396. package/lib/utils/setFloatingElemPositionForLinkEditor.d.ts +1 -0
  397. package/lib/utils/setFloatingElemPositionForLinkEditor.js +36 -0
  398. package/lib/utils/swipe.d.ts +4 -0
  399. package/lib/utils/swipe.js +94 -0
  400. package/lib/utils/url.d.ts +2 -0
  401. package/lib/utils/url.js +31 -0
  402. package/package.json +4 -4
@@ -0,0 +1,235 @@
1
+ /*
2
+ * Copyright (c) 2025-2026 Datalayer, Inc.
3
+ * Distributed under the terms of the MIT License.
4
+ */
5
+ import { $getNodeByKey, $isDecoratorNode } from 'lexical';
6
+ import { $diffTextContentAndApplyDelta } from '../utils/Utils';
7
+ /**
8
+ * Handles map data changes (node properties, metadata updates)
9
+ */
10
+ export class MapIntegrator {
11
+ integrate(diff, binding, provider) {
12
+ // Handle updated properties
13
+ if (diff.updated) {
14
+ Object.entries(diff.updated).forEach(([key, value]) => {
15
+ this.integratePropertyUpdate(key, value, binding, provider);
16
+ });
17
+ }
18
+ // Handle deleted properties
19
+ if (diff.deleted) {
20
+ diff.deleted.forEach((key) => {
21
+ this.integratePropertyDelete(key, binding, provider);
22
+ });
23
+ }
24
+ }
25
+ // Enhanced integrate method with TreeID context
26
+ integrateWithContext(diff, treeId, binding, provider) {
27
+ this.integrateWithContextInternal(diff, treeId, binding, provider);
28
+ }
29
+ // Internal method for use when already inside editor.update()
30
+ integrateInternal(diff, binding, provider) {
31
+ // Handle updated properties
32
+ if (diff.updated) {
33
+ Object.entries(diff.updated).forEach(([key, value]) => {
34
+ this.integratePropertyUpdate(key, value, binding, provider);
35
+ });
36
+ }
37
+ // Handle deleted properties
38
+ if (diff.deleted) {
39
+ diff.deleted.forEach((key) => {
40
+ this.integratePropertyDelete(key, binding, provider);
41
+ });
42
+ }
43
+ }
44
+ // Internal method for use when already inside editor.update() with context
45
+ integrateWithContextInternal(diff, treeId, binding, provider) {
46
+ // Handle updated properties with TreeID context
47
+ if (diff.updated) {
48
+ Object.entries(diff.updated).forEach(([key, value]) => {
49
+ this.integratePropertyUpdateWithContextInternal(key, value, treeId, binding, provider);
50
+ });
51
+ }
52
+ // Handle deleted properties
53
+ if (diff.deleted) {
54
+ diff.deleted.forEach((key) => {
55
+ this.integratePropertyDelete(key, binding, provider);
56
+ });
57
+ }
58
+ }
59
+ integratePropertyUpdateWithContext(key, value, treeId, binding, provider) {
60
+ // Handle specific property updates with TreeID context
61
+ switch (key) {
62
+ case 'lexical':
63
+ this.integrateLexicalDataUpdateWithContext(value, treeId, binding);
64
+ break;
65
+ case 'textContent':
66
+ // Text content updates should be integrated via lexical data updates
67
+ break;
68
+ case 'elementType':
69
+ // Element type changes are rare, mostly for debugging
70
+ break;
71
+ default:
72
+ //
73
+ }
74
+ }
75
+ // Internal version for use when already inside editor.update()
76
+ integratePropertyUpdateWithContextInternal(key, value, treeId, binding, provider) {
77
+ // Handle specific property updates with TreeID context
78
+ switch (key) {
79
+ case 'lexical':
80
+ // Extract TreeID and call internal method directly (already inside editor.update())
81
+ let actualTreeID = treeId;
82
+ if (typeof treeId === 'string' && treeId.startsWith('cid:')) {
83
+ const parts = treeId.split(':');
84
+ if (parts.length >= 3) {
85
+ actualTreeID = parts[1];
86
+ }
87
+ }
88
+ const lexicalKey = binding.nodeMapper.getLexicalKeyByLoroId(actualTreeID);
89
+ if (lexicalKey) {
90
+ this.integrateLexicalDataUpdateInternal(value, lexicalKey, actualTreeID, binding);
91
+ }
92
+ break;
93
+ case 'textContent':
94
+ // Text content updates should be integrated via lexical data updates
95
+ break;
96
+ case 'elementType':
97
+ // Element type changes are rare, mostly for debugging
98
+ break;
99
+ default:
100
+ // Generic property update with context
101
+ break;
102
+ }
103
+ }
104
+ integratePropertyUpdate(key, value, binding, provider) {
105
+ // Handle specific property updates
106
+ switch (key) {
107
+ case 'lexical':
108
+ // Use targeted update only - the broad heuristic causes scrambling
109
+ break;
110
+ case 'textContent':
111
+ // Text content updates should be integrated via lexical data updates
112
+ break;
113
+ case 'elementType':
114
+ // Element type changes are rare, mostly for debugging
115
+ break;
116
+ default:
117
+ // Generic property update
118
+ break;
119
+ }
120
+ }
121
+ integratePropertyDelete(key, binding, provider) {
122
+ // Handle specific property deletions
123
+ switch (key) {
124
+ case 'lexical':
125
+ break;
126
+ default:
127
+ // Generic property deleted
128
+ break;
129
+ }
130
+ }
131
+ integrateLexicalDataUpdateWithContext(lexicalData, treeId, binding) {
132
+ // Extract the actual TreeID from container ID format
133
+ // Container ID format: "cid:6@7648424808278730813:Map"
134
+ // TreeID format: "6@7648424808278730813"
135
+ let actualTreeID = treeId;
136
+ if (typeof treeId === 'string' && treeId.startsWith('cid:')) {
137
+ const parts = treeId.split(':');
138
+ if (parts.length >= 3) {
139
+ actualTreeID = parts[1]; // Extract "6@7648424808278730813" from "cid:6@7648424808278730813:Map"
140
+ }
141
+ }
142
+ // Use the TreeID to find the specific Lexical node
143
+ const lexicalKey = binding.nodeMapper.getLexicalKeyByLoroId(actualTreeID);
144
+ if (!lexicalKey) {
145
+ return;
146
+ }
147
+ if (lexicalData && typeof lexicalData === 'object') {
148
+ binding.editor.update(() => {
149
+ this.integrateLexicalDataUpdateInternal(lexicalData, lexicalKey, actualTreeID, binding);
150
+ });
151
+ }
152
+ }
153
+ // Internal method for use when already inside editor.update()
154
+ integrateLexicalDataUpdateInternal(lexicalData, lexicalKey, treeId, binding) {
155
+ // Handle Loro container objects that need conversion to plain JS
156
+ let data = lexicalData;
157
+ if (data && typeof data === 'object' && typeof data.toJSON === 'function') {
158
+ data = data.toJSON();
159
+ }
160
+ const targetNode = $getNodeByKey(lexicalKey);
161
+ if (!targetNode) {
162
+ return;
163
+ }
164
+ const targetType = targetNode.getType();
165
+ const textContent = data.__text || data.text || data.textContent;
166
+ if (targetType === 'text' && textContent !== undefined) {
167
+ // Text nodes: use diff approach to preserve cursor position
168
+ const textNode = targetNode;
169
+ const currentText = textNode.getTextContent();
170
+ if (currentText !== textContent) {
171
+ $diffTextContentAndApplyDelta(textNode, lexicalKey, currentText, textContent);
172
+ }
173
+ // Apply text-specific properties
174
+ if (data.format !== undefined) {
175
+ textNode.setFormat(data.format);
176
+ }
177
+ if (data.style !== undefined) {
178
+ textNode.setStyle(data.style);
179
+ }
180
+ }
181
+ else if ($isDecoratorNode(targetNode)) {
182
+ // Decorator nodes (excalidraw, images, counters, JupyterCellNode, …):
183
+ // Many decorator implementations do NOT override `updateFromJSON` for
184
+ // their custom properties — they only set them in the constructor via
185
+ // `importJSON`. Since decorators are leaf nodes (no children), it is
186
+ // safe to replace the whole node with a fresh `importJSON` instance.
187
+ try {
188
+ const registeredNodes = binding.editor._nodes;
189
+ const nodeInfo = registeredNodes.get(targetType);
190
+ if (!nodeInfo) {
191
+ console.warn(` MapIntegrator: Node type '${targetType}' not registered`);
192
+ return;
193
+ }
194
+ const serializedData = { ...data };
195
+ if (!serializedData.type)
196
+ serializedData.type = targetType;
197
+ if (serializedData.version === undefined)
198
+ serializedData.version = 1;
199
+ if (!('children' in serializedData))
200
+ serializedData.children = [];
201
+ const newNode = nodeInfo.klass.importJSON(serializedData);
202
+ targetNode.replace(newNode);
203
+ // Update bidirectional mapping: old key → remove, new key → treeId
204
+ // Use removeMappingForKey (not deleteMapping) because we are on the
205
+ // integration side — the Loro tree node must NOT be deleted; we are
206
+ // only swapping which Lexical key points to it.
207
+ binding.nodeMapper.removeMappingForKey(lexicalKey);
208
+ binding.nodeMapper.setMapping(newNode.getKey(), treeId);
209
+ }
210
+ catch (error) {
211
+ console.warn(` MapIntegrator: importJSON+replace failed for decorator ${targetType} node ${lexicalKey}:`, error);
212
+ }
213
+ }
214
+ else {
215
+ try {
216
+ const serializedData = { ...data };
217
+ if (!serializedData.type) {
218
+ serializedData.type = targetType;
219
+ }
220
+ if (serializedData.version === undefined) {
221
+ serializedData.version = 1;
222
+ }
223
+ // Provide empty children (TreeIntegrator manages children separately)
224
+ if (!('children' in serializedData)) {
225
+ serializedData.children = [];
226
+ }
227
+ const writable = targetNode.getWritable();
228
+ writable.updateFromJSON(serializedData);
229
+ }
230
+ catch (error) {
231
+ console.warn(` MapIntegrator: updateFromJSON failed for ${targetType} node ${lexicalKey}:`, error);
232
+ }
233
+ }
234
+ }
235
+ }
@@ -0,0 +1,25 @@
1
+ import { BaseIntegrator } from './BaseIntegrator';
2
+ import { Binding } from '../Bindings';
3
+ import { Provider } from '../State';
4
+ interface TextDiff {
5
+ type: 'text';
6
+ diff?: Array<{
7
+ type: 'insert' | 'delete' | 'retain';
8
+ index?: number;
9
+ length?: number;
10
+ value?: string;
11
+ attributes?: any;
12
+ }>;
13
+ }
14
+ /**
15
+ * Handles text changes (character insertions, deletions, formatting)
16
+ */
17
+ export declare class TextIntegrator implements BaseIntegrator<TextDiff> {
18
+ integrate(diff: TextDiff, binding: Binding, provider: Provider): void;
19
+ integrateInternal(diff: TextDiff, binding: Binding, provider: Provider): void;
20
+ private integrateTextInsert;
21
+ private integrateTextDelete;
22
+ private integrateTextRetain;
23
+ private applyTextFormatting;
24
+ }
25
+ export {};
@@ -0,0 +1,55 @@
1
+ /*
2
+ * Copyright (c) 2025-2026 Datalayer, Inc.
3
+ * Distributed under the terms of the MIT License.
4
+ */
5
+ /**
6
+ * Handles text changes (character insertions, deletions, formatting)
7
+ */
8
+ export class TextIntegrator {
9
+ integrate(diff, binding, provider) {
10
+ this.integrateInternal(diff, binding, provider);
11
+ }
12
+ // Internal method for use when already inside editor.update()
13
+ integrateInternal(diff, binding, provider) {
14
+ if (diff.diff) {
15
+ diff.diff.forEach((change) => {
16
+ switch (change.type) {
17
+ case 'insert':
18
+ this.integrateTextInsert(change, binding, provider);
19
+ break;
20
+ case 'delete':
21
+ this.integrateTextDelete(change, binding, provider);
22
+ break;
23
+ case 'retain':
24
+ this.integrateTextRetain(change, binding, provider);
25
+ break;
26
+ default:
27
+ console.warn(` Unknown text change type: ${change.type}`);
28
+ }
29
+ });
30
+ }
31
+ }
32
+ integrateTextInsert(change, binding, provider) {
33
+ // To integrate text insertion, we need to know which TextNode this applies to
34
+ // This information should come from the event context or be tracked separately
35
+ // For now, this is a placeholder - in a complete implementation,
36
+ // we would need to identify the target TextNode and update it
37
+ }
38
+ integrateTextDelete(change, binding, provider) {
39
+ // Similar to insert, we need target node context for text deletion
40
+ }
41
+ integrateTextRetain(change, binding, provider) {
42
+ if (change.attributes) {
43
+ // Handle text formatting changes
44
+ this.applyTextFormatting({ ...change, attributes: change.attributes }, binding, provider);
45
+ }
46
+ }
47
+ applyTextFormatting(change, binding, provider) {
48
+ // Text formatting in Lexical is typically integrated through TextNode format property
49
+ // This would need to be coordinated with the specific TextNode being modified
50
+ // Example formatting attributes might include:
51
+ // - bold, italic, underline
52
+ // - font size, color
53
+ // - etc.
54
+ }
55
+ }
@@ -0,0 +1,41 @@
1
+ import { TreeID } from 'loro-crdt';
2
+ import { BaseIntegrator } from './BaseIntegrator';
3
+ import { Binding } from '../Bindings';
4
+ import { Provider } from '../State';
5
+ interface TreeDiff {
6
+ type: 'tree';
7
+ diff: Array<{
8
+ action: 'create' | 'move' | 'delete';
9
+ target: TreeID;
10
+ parent?: TreeID;
11
+ index?: number;
12
+ }>;
13
+ }
14
+ /**
15
+ * Simplified tree diff integrater that trusts Loro's CRDT conflict resolution
16
+ * and applies operations directly without complex filtering or context classification
17
+ */
18
+ export declare class TreeIntegrator implements BaseIntegrator<TreeDiff> {
19
+ integrate(diff: TreeDiff, binding: Binding, provider: Provider): void;
20
+ integrateInternal(diff: TreeDiff, binding: Binding, provider: Provider): void;
21
+ private integrateCreate;
22
+ /** Only element and decorator nodes may be inserted directly under the root. */
23
+ private canBeRootChild;
24
+ /** Insert a child into a parent element at an optional index. */
25
+ private insertChild;
26
+ private integrateMove;
27
+ private integrateDelete;
28
+ private collectDescendantKeys;
29
+ /**
30
+ * Topologically sort create operations so that parent nodes are created
31
+ * before their children.
32
+ *
33
+ * Computes depth using the `parent` field from the diff operations
34
+ * themselves rather than querying the Loro tree API (which may behave
35
+ * unexpectedly during event processing). For each create op, we count
36
+ * how many of its ancestors are also being created in this same batch.
37
+ * Ties at the same depth preserve the original diff order (stable sort).
38
+ */
39
+ private topologicalSortCreates;
40
+ }
41
+ export {};
@@ -0,0 +1,293 @@
1
+ /*
2
+ * Copyright (c) 2025-2026 Datalayer, Inc.
3
+ * Distributed under the terms of the MIT License.
4
+ */
5
+ import { $getRoot, $getNodeByKey, $isElementNode, $isDecoratorNode, } from 'lexical';
6
+ import { parseTreeID } from '../utils/Utils';
7
+ import { createLexicalNodeFromLoro } from '../nodes/NodeFactory';
8
+ import { invariant } from '../utils/Invariant';
9
+ /**
10
+ * Simplified tree diff integrater that trusts Loro's CRDT conflict resolution
11
+ * and applies operations directly without complex filtering or context classification
12
+ */
13
+ export class TreeIntegrator {
14
+ integrate(diff, binding, provider) {
15
+ // Batch all changes in a single editor update
16
+ binding.editor.update(() => {
17
+ this.integrateInternal(diff, binding, provider);
18
+ });
19
+ }
20
+ // Internal method that can be called when already inside editor.update()
21
+ integrateInternal(diff, binding, provider) {
22
+ // Separate operations by action type
23
+ const deletes = [];
24
+ const creates = [];
25
+ const moves = [];
26
+ for (const op of diff.diff) {
27
+ switch (op.action) {
28
+ case 'delete':
29
+ deletes.push(op);
30
+ break;
31
+ case 'create':
32
+ creates.push(op);
33
+ break;
34
+ case 'move':
35
+ moves.push(op);
36
+ break;
37
+ }
38
+ }
39
+ // Loro often splits a node's placement into a parentless `create` followed
40
+ // by a `move` that supplies the real parent/index. Inline nodes (text,
41
+ // linebreak) can never live at the root — not even transiently — so fold
42
+ // the move's parent/index back into the create and drop the now-redundant
43
+ // move. This resolves the placement up front instead of skipping the node.
44
+ const moveByTarget = new Map();
45
+ for (const mv of moves) {
46
+ moveByTarget.set(String(mv.target), mv);
47
+ }
48
+ const foldedMoveTargets = new Set();
49
+ for (const cr of creates) {
50
+ if (cr.parent === undefined) {
51
+ const mv = moveByTarget.get(String(cr.target));
52
+ if (mv && mv.parent !== undefined) {
53
+ cr.parent = mv.parent;
54
+ cr.index = mv.index;
55
+ foldedMoveTargets.add(String(cr.target));
56
+ }
57
+ }
58
+ }
59
+ const effectiveMoves = moves.filter(mv => !foldedMoveTargets.has(String(mv.target)));
60
+ // Topologically sort create operations so parents are created before children.
61
+ // Without this, a TableCellNode may arrive before its parent TableRowNode,
62
+ // causing the cell to fall back to $getRoot() and appear on one flat line.
63
+ const sortedCreates = this.topologicalSortCreates(creates, binding);
64
+ // Phase 1: deletes.
65
+ deletes.forEach(op => this.integrateDelete(op, binding, provider));
66
+ // Phase 2: creates (parent-first, with deferral).
67
+ //
68
+ // Topological sort orders parents before children *within this batch*, but
69
+ // a child may still reference a parent whose Lexical mapping is not yet
70
+ // established (deeply nested tables, list items inside quotes, Jupyter
71
+ // cells, …). Rather than dropping such a node onto the root — which throws
72
+ // for inline nodes like text/linebreak ("Only element or decorator nodes
73
+ // can be inserted to the root node") and corrupts the document — we defer
74
+ // it and retry until a full pass makes no further progress.
75
+ //
76
+ // Created Lexical nodes are cached so deferred retries reuse the same
77
+ // instance instead of importing (and registering) duplicate nodes.
78
+ const nodeCache = new Map();
79
+ let pending = sortedCreates;
80
+ while (pending.length > 0) {
81
+ const stillPending = [];
82
+ for (const op of pending) {
83
+ if (this.integrateCreate(op, binding, provider, nodeCache) === 'deferred') {
84
+ stillPending.push(op);
85
+ }
86
+ }
87
+ if (stillPending.length === pending.length) {
88
+ // No progress in a full pass: every remaining node references a parent
89
+ // that never arrived in this batch. This is a real ordering/data bug.
90
+ // Surface it instead of dropping the nodes onto the root (or silently
91
+ // discarding inline nodes, which would lose user content).
92
+ invariant(false, 'TreeIntegrator: create operations reference parents missing from the batch', {
93
+ pending: stillPending.map(op => ({
94
+ target: String(op.target),
95
+ parent: op.parent ? String(op.parent) : null,
96
+ })),
97
+ });
98
+ }
99
+ pending = stillPending;
100
+ }
101
+ // Phase 3: moves (those not already folded into a create above).
102
+ effectiveMoves.forEach(op => this.integrateMove(op, binding, provider));
103
+ }
104
+ integrateCreate(operation, binding, provider, nodeCache) {
105
+ let { nodeKey } = parseTreeID(operation.target);
106
+ // Root node creation is integrated during initial setup. Only treat as
107
+ // root if it's actually a root-type node in Loro.
108
+ if (nodeKey === "0") {
109
+ const treeNode = binding.tree.getNodeByID(operation.target);
110
+ const elementType = treeNode?.data.get('elementType');
111
+ if (elementType === 'root' || !elementType) {
112
+ const root = $getRoot();
113
+ binding.nodeMapper.setMapping(root.getKey(), operation.target);
114
+ return 'created';
115
+ }
116
+ // nodeKey is "0" but not an actual root element — fall through.
117
+ }
118
+ // Node already exists with the same TreeID → idempotent, nothing to do.
119
+ const existingNode = $getNodeByKey(nodeKey);
120
+ if (existingNode) {
121
+ const existingTreeID = binding.nodeMapper.getTreeIDByLexicalKey(nodeKey);
122
+ if (existingTreeID === operation.target) {
123
+ return 'created';
124
+ }
125
+ // Different TreeID reuses this key — let Lexical assign a fresh one.
126
+ nodeKey = undefined;
127
+ }
128
+ // Create the Lexical node once and cache it, so deferred retries reuse
129
+ // the same instance instead of importing duplicate nodes.
130
+ const cacheKey = String(operation.target);
131
+ let lexicalNode = nodeCache.get(cacheKey);
132
+ if (lexicalNode === undefined) {
133
+ lexicalNode = createLexicalNodeFromLoro(operation.target, binding.tree, binding);
134
+ nodeCache.set(cacheKey, lexicalNode);
135
+ }
136
+ invariant(lexicalNode != null, 'integrateCreate: failed to materialise Lexical node from Loro data', { target: cacheKey });
137
+ if (operation.parent) {
138
+ const parentKey = binding.nodeMapper.getLexicalKeyByLoroId(operation.parent);
139
+ const parentLexicalNode = parentKey ? $getNodeByKey(parentKey) : null;
140
+ // Parent expected but not mapped yet → defer until it is created. This is
141
+ // legitimate ordering (a later pass/batch supplies the parent), not an
142
+ // error that hides a bug.
143
+ if (!(parentLexicalNode && $isElementNode(parentLexicalNode))) {
144
+ return 'deferred';
145
+ }
146
+ this.insertChild(parentLexicalNode, lexicalNode, operation.index);
147
+ }
148
+ else {
149
+ // No parent → root. Only element/decorator nodes may live at the root; an
150
+ // inline node without a parent is a structural bug, not something to skip.
151
+ invariant(this.canBeRootChild(lexicalNode), 'integrateCreate: inline node has no parent (cannot live at root)', { target: cacheKey, nodeType: lexicalNode.getType() });
152
+ this.insertChild($getRoot(), lexicalNode, operation.index);
153
+ }
154
+ binding.nodeMapper.setMapping(lexicalNode.getKey(), operation.target);
155
+ return 'created';
156
+ }
157
+ /** Only element and decorator nodes may be inserted directly under the root. */
158
+ canBeRootChild(node) {
159
+ return $isElementNode(node) || $isDecoratorNode(node);
160
+ }
161
+ /** Insert a child into a parent element at an optional index. */
162
+ insertChild(parent, child, index) {
163
+ if (index !== undefined) {
164
+ parent.splice(index, 0, [child]);
165
+ }
166
+ else {
167
+ parent.append(child);
168
+ }
169
+ }
170
+ integrateMove(operation, binding, provider) {
171
+ const lexicalKey = binding.nodeMapper.getLexicalKeyByLoroId(operation.target);
172
+ invariant(lexicalKey != null, 'integrateMove: no Lexical key for move target', { target: String(operation.target) });
173
+ const nodeToMove = $getNodeByKey(lexicalKey);
174
+ invariant(nodeToMove != null, 'integrateMove: node to move not found', { lexicalKey });
175
+ // Resolve the new parent.
176
+ let newParent;
177
+ if (operation.parent) {
178
+ const parentKey = binding.nodeMapper.getLexicalKeyByLoroId(operation.parent);
179
+ const parentNode = parentKey ? $getNodeByKey(parentKey) : null;
180
+ invariant(parentNode != null && $isElementNode(parentNode), 'integrateMove: move target parent is not a mapped element', { target: String(operation.target), parent: String(operation.parent) });
181
+ newParent = parentNode;
182
+ }
183
+ else {
184
+ // No parent → root, only valid for element/decorator nodes.
185
+ invariant(this.canBeRootChild(nodeToMove), 'integrateMove: inline node cannot be moved to the root', { lexicalKey, nodeType: nodeToMove.getType() });
186
+ newParent = $getRoot();
187
+ }
188
+ // Remove from current position and insert at new position.
189
+ nodeToMove.remove();
190
+ if (operation.index !== undefined) {
191
+ newParent.splice(operation.index, 0, [nodeToMove]);
192
+ }
193
+ else {
194
+ newParent.append(nodeToMove);
195
+ }
196
+ }
197
+ integrateDelete(operation, binding, provider) {
198
+ const lexicalKey = binding.nodeMapper.getLexicalKeyByLoroId(operation.target);
199
+ // Parent-first delete batches can make child mappings stale before their
200
+ // own delete ops arrive. Missing mapping here is therefore benign.
201
+ if (!lexicalKey) {
202
+ return;
203
+ }
204
+ const nodeToDelete = $getNodeByKey(lexicalKey);
205
+ // Node may already be gone due to an ancestor deletion in this same batch.
206
+ if (!nodeToDelete) {
207
+ binding.nodeMapper.removeMappingForKey(lexicalKey);
208
+ return;
209
+ }
210
+ // The root is never deletable in Lexical; a delete resolving to it means a
211
+ // mapping is wrong upstream — surface it rather than silently ignoring.
212
+ if (nodeToDelete === $getRoot()) {
213
+ return;
214
+ }
215
+ // Clean descendant mappings first so later child-delete ops in the same
216
+ // batch become harmless no-ops instead of failing with stale mappings.
217
+ const descendantKeys = this.collectDescendantKeys(nodeToDelete);
218
+ for (const key of descendantKeys) {
219
+ binding.nodeMapper.removeMappingForKey(key);
220
+ }
221
+ // Remove from the Lexical tree.
222
+ nodeToDelete.remove();
223
+ // Clean up mapping only — the Loro tree already processed this deletion
224
+ // from the remote peer; calling tree.delete() again would throw.
225
+ binding.nodeMapper.removeMappingForKey(lexicalKey);
226
+ }
227
+ collectDescendantKeys(node) {
228
+ if (!$isElementNode(node)) {
229
+ return [];
230
+ }
231
+ const keys = [];
232
+ const stack = [...node.getChildren()];
233
+ while (stack.length > 0) {
234
+ const current = stack.pop();
235
+ keys.push(current.getKey());
236
+ if ($isElementNode(current)) {
237
+ stack.push(...current.getChildren());
238
+ }
239
+ }
240
+ return keys;
241
+ }
242
+ /**
243
+ * Topologically sort create operations so that parent nodes are created
244
+ * before their children.
245
+ *
246
+ * Computes depth using the `parent` field from the diff operations
247
+ * themselves rather than querying the Loro tree API (which may behave
248
+ * unexpectedly during event processing). For each create op, we count
249
+ * how many of its ancestors are also being created in this same batch.
250
+ * Ties at the same depth preserve the original diff order (stable sort).
251
+ */
252
+ topologicalSortCreates(creates, binding) {
253
+ if (creates.length <= 1)
254
+ return creates;
255
+ // Build lookup: target → parent (only for operations in this batch)
256
+ const batchTargets = new Set(creates.map(op => String(op.target)));
257
+ const parentOf = new Map();
258
+ for (const op of creates) {
259
+ if (op.parent) {
260
+ parentOf.set(String(op.target), String(op.parent));
261
+ }
262
+ }
263
+ const depthCache = new Map();
264
+ const getDepth = (targetStr) => {
265
+ if (depthCache.has(targetStr))
266
+ return depthCache.get(targetStr);
267
+ let depth = 0;
268
+ let current = targetStr;
269
+ const visited = new Set();
270
+ // Walk up the parent chain; count only ancestors that are also being
271
+ // created in this batch (i.e. don't exist yet and must come first).
272
+ while (parentOf.has(current)) {
273
+ const parent = parentOf.get(current);
274
+ if (visited.has(parent))
275
+ break; // cycle guard
276
+ visited.add(parent);
277
+ if (batchTargets.has(parent)) {
278
+ depth++;
279
+ current = parent;
280
+ }
281
+ else {
282
+ break; // parent already exists locally — stop counting
283
+ }
284
+ }
285
+ depthCache.set(targetStr, depth);
286
+ return depth;
287
+ };
288
+ // Tag each operation with its original index (for stable tie-breaking)
289
+ const tagged = creates.map((op, i) => ({ op, depth: getDepth(String(op.target)), idx: i }));
290
+ tagged.sort((a, b) => a.depth - b.depth || a.idx - b.idx);
291
+ return tagged.map(t => t.op);
292
+ }
293
+ }
@@ -0,0 +1,15 @@
1
+ import { TreeID, LoroTree } from 'loro-crdt';
2
+ import { LexicalNode, NodeKey } from 'lexical';
3
+ import { Binding } from '../Bindings';
4
+ /**
5
+ * Factory function to create Lexical nodes from Loro TreeID.
6
+ *
7
+ * Uses the registered node's static `importJSON()` method, which is the
8
+ * canonical Lexical API for restoring nodes from serialized data. This works
9
+ * generically for ALL node types — built-in (paragraph, heading, table,
10
+ * list, quote, code…), decorator (excalidraw, image, counter…), and any
11
+ * externally-defined custom nodes (e.g. JupyterCellNode) as long as they
12
+ * are registered with the editor and implement the standard `importJSON`
13
+ * static method required by Lexical's serialization contract.
14
+ */
15
+ export declare function createLexicalNodeFromLoro(treeId: TreeID, loroTree: LoroTree, binding: Binding, parentKey?: NodeKey, nodeDataFromDiff?: any): LexicalNode | null;