@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,106 @@
1
+ /*
2
+ * Copyright (c) 2025-2026 Datalayer, Inc.
3
+ * Distributed under the terms of the MIT License.
4
+ */
5
+ import { $addUpdateTag, $createParagraphNode, $getRoot, $getSelection, $isRangeSelection, $setSelection, SKIP_COLLAB_TAG, SKIP_SCROLL_INTO_VIEW_TAG } from 'lexical';
6
+ import { $syncLocalCursorPosition, syncCursorPositions, syncLexicalSelectionToLoro } from './SyncCursors';
7
+ // Import the new diff integrators
8
+ import { TreeIntegrator } from '../integrators/TreeIntegrator';
9
+ import { MapIntegrator } from '../integrators/MapIntegrator';
10
+ import { ListIntegrator } from '../integrators/ListIntegrator';
11
+ import { TextIntegrator } from '../integrators/TextIntegrator';
12
+ import { CounterIntegrator } from '../integrators/CounterIntegrator';
13
+ import { $moveSelectionToPreviousNode, doesSelectionNeedRecovering } from '../utils/Utils';
14
+ // Create singleton instances of the diff integrators (created once, reused across calls)
15
+ const treeIntegrator = new TreeIntegrator();
16
+ const mapIntegrator = new MapIntegrator();
17
+ const listIntegrator = new ListIntegrator();
18
+ const textIntegrator = new TextIntegrator();
19
+ const counterIntegrator = new CounterIntegrator();
20
+ export function syncLoroToLexical(binding, provider, eventBatch, isFromUndoManger, syncCursorPositionsFn = syncCursorPositions) {
21
+ const editor = binding.editor;
22
+ const currentEditorState = editor._editorState;
23
+ // Batch all events into a single discrete editor.update() to avoid race conditions
24
+ // Using discrete: true ensures immediate synchronous commit before other operations
25
+ binding.editor.update(() => {
26
+ // Clear selection temporarily to avoid cursor position conflicts during text updates
27
+ const currentSelection = $getSelection();
28
+ if (currentSelection) {
29
+ $setSelection(null);
30
+ }
31
+ // Process Loro events and apply them to Lexical using the appropriate integrators
32
+ eventBatch.events.forEach((event, index) => {
33
+ try {
34
+ switch (event.diff.type) {
35
+ case 'tree':
36
+ // Call internal method that doesn't wrap in editor.update()
37
+ treeIntegrator.integrateInternal(event.diff, binding, provider);
38
+ break;
39
+ case 'map':
40
+ // Call internal method that doesn't wrap in editor.update()
41
+ if (event.target) {
42
+ mapIntegrator.integrateWithContextInternal(event.diff, event.target, binding, provider);
43
+ }
44
+ else {
45
+ mapIntegrator.integrateInternal(event.diff, binding, provider);
46
+ }
47
+ break;
48
+ case 'list':
49
+ listIntegrator.integrateInternal(event.diff, binding, provider);
50
+ break;
51
+ case 'text':
52
+ textIntegrator.integrateInternal(event.diff, binding, provider);
53
+ break;
54
+ case 'counter':
55
+ counterIntegrator.integrateInternal(event.diff, binding, provider);
56
+ break;
57
+ default:
58
+ throw new Error(`Unsupported event diff type: ${event.diff.type}. Supported types are: 'tree', 'map', 'list', 'text', 'counter'.`);
59
+ }
60
+ }
61
+ catch (err) {
62
+ console.error('[SEED-DEBUG] syncLoroToLexical: integrator threw for event', index, 'diffType=', event.diff?.type, 'target=', String(event?.target), 'diff=', JSON.stringify(event.diff), err);
63
+ throw err;
64
+ }
65
+ });
66
+ const selection = $getSelection();
67
+ if ($isRangeSelection(selection)) {
68
+ if (doesSelectionNeedRecovering(selection)) {
69
+ const prevSelection = currentEditorState._selection;
70
+ if ($isRangeSelection(prevSelection)) {
71
+ $syncLocalCursorPosition(binding, provider);
72
+ if (doesSelectionNeedRecovering(selection)) {
73
+ // If the selected node is deleted, move the selection to the previous or parent node.
74
+ const anchorNodeKey = selection.anchor.key;
75
+ $moveSelectionToPreviousNode(anchorNodeKey, currentEditorState);
76
+ }
77
+ }
78
+ syncLexicalSelectionToLoro(binding, provider, prevSelection, $getSelection());
79
+ }
80
+ else {
81
+ $syncLocalCursorPosition(binding, provider);
82
+ }
83
+ }
84
+ if (!isFromUndoManger) {
85
+ // If it is an external change, we don't want the current scroll position to get changed
86
+ // since the user might've intentionally scrolled somewhere else in the document.
87
+ $addUpdateTag(SKIP_SCROLL_INTO_VIEW_TAG);
88
+ }
89
+ }, {
90
+ onUpdate: () => {
91
+ syncCursorPositionsFn(binding, provider);
92
+ // If there was a collision on the top level paragraph
93
+ // we need to re-add a paragraph. To ensure this insertion properly syncs with other clients,
94
+ // it must be placed outside of the update block above that has tags 'collaboration' or 'historic'.
95
+ editor.update(() => {
96
+ if ($getRoot().getChildrenSize() === 0) {
97
+ $getRoot().append($createParagraphNode());
98
+ }
99
+ });
100
+ },
101
+ // discrete: true,
102
+ skipTransforms: true,
103
+ // tag: isFromUndoManger ? HISTORIC_TAG : COLLABORATION_TAG,
104
+ tag: SKIP_COLLAB_TAG
105
+ });
106
+ }
@@ -0,0 +1,32 @@
1
+ import { LexicalNode } from 'lexical';
2
+ /**
3
+ * Data structure stored in Loro tree node data
4
+ */
5
+ export interface LexicalNodeData {
6
+ lexicalNode: LexicalNode;
7
+ }
8
+ /**
9
+ * Helper functions for working with LexicalNodeData
10
+ */
11
+ export declare class LexicalNodeDataHelper {
12
+ /**
13
+ * Create LexicalNodeData from a Lexical node
14
+ */
15
+ static create(lexicalNode: LexicalNode): LexicalNodeData;
16
+ /**
17
+ * Serialize LexicalNodeData for storage in Loro
18
+ */
19
+ static serialize(data: LexicalNodeData): string;
20
+ /**
21
+ * Deserialize LexicalNodeData from Loro storage
22
+ */
23
+ static deserialize(serialized: string): LexicalNodeData | null;
24
+ /**
25
+ * Extract the LexicalNode from LexicalNodeData
26
+ */
27
+ static getLexicalNode(data: LexicalNodeData): LexicalNode;
28
+ /**
29
+ * Get node type from LexicalNodeData
30
+ */
31
+ static getNodeType(data: LexicalNodeData): string;
32
+ }
@@ -0,0 +1,75 @@
1
+ /*
2
+ * Copyright (c) 2025-2026 Datalayer, Inc.
3
+ * Distributed under the terms of the MIT License.
4
+ */
5
+ /**
6
+ * Helper functions for working with LexicalNodeData
7
+ */
8
+ export class LexicalNodeDataHelper {
9
+ /**
10
+ * Create LexicalNodeData from a Lexical node
11
+ */
12
+ static create(lexicalNode) {
13
+ return {
14
+ lexicalNode
15
+ };
16
+ }
17
+ /**
18
+ * Serialize LexicalNodeData for storage in Loro
19
+ */
20
+ static serialize(data) {
21
+ try {
22
+ return JSON.stringify({
23
+ lexicalNode: data.lexicalNode.exportJSON()
24
+ });
25
+ }
26
+ catch (error) {
27
+ console.warn('Failed to serialize LexicalNodeData:', error);
28
+ return JSON.stringify({
29
+ lexicalNode: {
30
+ type: data.lexicalNode.getType(),
31
+ key: data.lexicalNode.getKey()
32
+ }
33
+ });
34
+ }
35
+ }
36
+ /**
37
+ * Deserialize LexicalNodeData from Loro storage
38
+ */
39
+ static deserialize(serialized) {
40
+ try {
41
+ const parsed = JSON.parse(serialized);
42
+ // Validate that we have the expected structure
43
+ if (!parsed || !parsed.lexicalNode) {
44
+ console.warn('Invalid LexicalNodeData structure:', parsed);
45
+ return null;
46
+ }
47
+ return {
48
+ lexicalNode: parsed.lexicalNode
49
+ };
50
+ }
51
+ catch (error) {
52
+ console.warn('Failed to deserialize LexicalNodeData:', error);
53
+ return null;
54
+ }
55
+ }
56
+ /**
57
+ * Extract the LexicalNode from LexicalNodeData
58
+ */
59
+ static getLexicalNode(data) {
60
+ return data.lexicalNode;
61
+ }
62
+ /**
63
+ * Get node type from LexicalNodeData
64
+ */
65
+ static getNodeType(data) {
66
+ // Handle both actual Lexical nodes (with getType method) and deserialized JSON objects
67
+ if (typeof data.lexicalNode.getType === 'function') {
68
+ return data.lexicalNode.getType();
69
+ }
70
+ else {
71
+ // Fallback to direct property access for deserialized JSON
72
+ return data.lexicalNode.__type || 'unknown';
73
+ }
74
+ }
75
+ }
@@ -0,0 +1,12 @@
1
+ import * as React from 'react';
2
+ import type { JSX } from 'react';
3
+ import type { LexicalEditor } from 'lexical';
4
+ import { InitialEditorStateType } from '@lexical/react/LexicalComposer';
5
+ import { LoroDoc } from 'loro-crdt';
6
+ import type { Provider } from './State';
7
+ import { Binding } from './Bindings';
8
+ import { SyncCursorPositionsFn } from './sync/SyncCursors';
9
+ export type CursorsContainerRef = React.MutableRefObject<HTMLElement | null>;
10
+ export declare function useCollaboration(editor: LexicalEditor, id: string, provider: Provider, docMap: Map<string, LoroDoc>, name: string, color: string, shouldBootstrap: boolean, binding: Binding, setDoc: React.Dispatch<React.SetStateAction<LoroDoc | undefined>>, cursorsContainerRef?: CursorsContainerRef, initialEditorState?: InitialEditorStateType, awarenessData?: object, syncCursorPositionsFn?: SyncCursorPositionsFn, onInitialization?: (isInitialized: boolean) => void): JSX.Element;
11
+ export declare function useFocusTracking(editor: LexicalEditor, provider: Provider, name: string, color: string, awarenessData?: object): void;
12
+ export declare function useHistory(editor: LexicalEditor, binding: Binding): () => void;
@@ -0,0 +1,405 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ /*
3
+ * Copyright (c) 2025-2026 Datalayer, Inc.
4
+ * Distributed under the terms of the MIT License.
5
+ */
6
+ import * as React from 'react';
7
+ import { useCallback, useEffect, useMemo, useRef } from 'react';
8
+ import { createPortal } from 'react-dom';
9
+ import { mergeRegister } from '@lexical/utils';
10
+ import { $getNodeByKey, $getRoot, $parseSerializedNode, $setSelection, BLUR_COMMAND, CAN_REDO_COMMAND, CAN_UNDO_COMMAND, COMMAND_PRIORITY_EDITOR, FOCUS_COMMAND, HISTORY_MERGE_TAG, REDO_COMMAND, SKIP_COLLAB_TAG, UNDO_COMMAND, } from 'lexical';
11
+ import { CONNECTED_COMMAND, createUndoManager, initLocalState, setLocalStateFocus, TOGGLE_CONNECT_COMMAND, } from './State';
12
+ import { syncLexicalToLoro } from './sync/SyncLexicalToLoro';
13
+ import { syncLoroToLexical } from './sync/SyncLoroToLexical';
14
+ import { syncCursorPositions } from './sync/SyncCursors';
15
+ export function useCollaboration(editor, id, provider, docMap, name, color, shouldBootstrap, binding, setDoc, cursorsContainerRef, initialEditorState, awarenessData, syncCursorPositionsFn = syncCursorPositions, onInitialization) {
16
+ const isReloadingDoc = useRef(false);
17
+ const connect = useCallback(() => provider.connect(), [provider]);
18
+ const disconnect = useCallback(() => {
19
+ try {
20
+ provider.disconnect();
21
+ }
22
+ catch (e) {
23
+ // Do nothing
24
+ }
25
+ }, [provider]);
26
+ useEffect(() => {
27
+ const { awareness } = provider;
28
+ const onStatus = ({ status }) => {
29
+ editor.dispatchCommand(CONNECTED_COMMAND, status === 'connected');
30
+ };
31
+ const onSync = (isSynced) => {
32
+ console.log('[SEED-DEBUG] onSync: isSynced=', isSynced, 'shouldBootstrap=', shouldBootstrap, 'isReloadingDoc=', isReloadingDoc.current);
33
+ if (shouldBootstrap &&
34
+ isSynced &&
35
+ isReloadingDoc.current === false) {
36
+ initializeEditor(editor, initialEditorState);
37
+ // Call the initialization callback after initializing the editor
38
+ if (onInitialization) {
39
+ onInitialization(true);
40
+ }
41
+ }
42
+ isReloadingDoc.current = false;
43
+ };
44
+ const onAwarenessUpdate = () => {
45
+ syncCursorPositionsFn(binding, provider);
46
+ };
47
+ initLocalState(provider, name, color, document.activeElement === editor.getRootElement(), awarenessData || {});
48
+ const onProviderDocReload = (doc) => {
49
+ clearEditorSkipCollab(editor, binding);
50
+ setDoc(doc);
51
+ docMap.set(id, doc);
52
+ isReloadingDoc.current = true;
53
+ };
54
+ provider.on('reload', onProviderDocReload);
55
+ provider.on('status', onStatus);
56
+ provider.on('sync', onSync);
57
+ awareness.on('update', onAwarenessUpdate);
58
+ const onLoroUpdates = (eventBatch) => {
59
+ // Only skip if the origin is from this specific editor's changes.
60
+ // We set 'lexical-edit' as origin when making changes from this editor.
61
+ // So we should skip only if the origin is 'lexical-edit' (our own changes).
62
+ if (eventBatch.origin !== binding.doc.peerIdStr) {
63
+ // Check if this change is from the undo manager
64
+ // const isFromUndoManger = origin instanceof UndoManager;
65
+ const isFromUndoManager = false;
66
+ syncLoroToLexical(binding, provider, eventBatch, isFromUndoManager, syncCursorPositionsFn);
67
+ }
68
+ };
69
+ // This updates the local editor state when we receive updates from other clients.
70
+ const unsubscribe = binding.doc.subscribe(onLoroUpdates);
71
+ // Lexical only includes a node type in `update.mutatedNodes` when that type
72
+ // has at least one registered mutation listener. Our Lexical→Loro sync
73
+ // relies entirely on `mutatedNodes`, so any node type without a listener is
74
+ // invisible to collaboration. In particular, the bootstrap seed runs before
75
+ // other plugins mount and register their own mutation listeners, so its
76
+ // commits produced an empty `mutatedNodes` and never propagated to peers.
77
+ // Register a no-op mutation listener for every node type registered on this
78
+ // editor so `mutatedNodes` is always fully populated (this mirrors how the
79
+ // Yjs binding stays independent of other plugins).
80
+ const mutationListenerCleanups = [];
81
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
82
+ const registeredNodes = editor._nodes;
83
+ console.log('[SEED-DEBUG] registering mutation listeners; registeredNodes=', registeredNodes ? registeredNodes.size : 'undefined');
84
+ if (registeredNodes) {
85
+ registeredNodes.forEach((registered) => {
86
+ if (registered && registered.klass) {
87
+ mutationListenerCleanups.push(
88
+ // eslint-disable-next-line @typescript-eslint/no-empty-function
89
+ editor.registerMutationListener(registered.klass, () => { }, {
90
+ skipInitialization: true,
91
+ }));
92
+ }
93
+ });
94
+ }
95
+ console.log('[SEED-DEBUG] mutation listeners registered=', mutationListenerCleanups.length, 'editor._listeners.mutation.size=',
96
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
97
+ editor._listeners?.mutation?.size);
98
+ const removeListener = editor.registerUpdateListener((update) => {
99
+ let __mn = 0;
100
+ if (update.mutatedNodes) {
101
+ update.mutatedNodes.forEach((m) => {
102
+ __mn += m.size;
103
+ });
104
+ }
105
+ console.log('[SEED-DEBUG] updateListener fired; tags=', Array.from(update.tags), 'mutatedNodes=', update.mutatedNodes ? 'map' : 'null', 'count=', __mn, 'dirtyElements=', update.dirtyElements?.size, 'dirtyLeaves=', update.dirtyLeaves?.size);
106
+ if (update.tags.has(SKIP_COLLAB_TAG) === false) {
107
+ syncLexicalToLoro(binding, provider, update);
108
+ }
109
+ });
110
+ const connectionPromise = connect();
111
+ return () => {
112
+ if (isReloadingDoc.current === false) {
113
+ if (connectionPromise) {
114
+ connectionPromise.then(disconnect);
115
+ }
116
+ else {
117
+ // Workaround for race condition in StrictMode. It's possible there
118
+ // is a different race for the above case where connect returns a
119
+ // promise, but we don't have an example of that in-repo.
120
+ // It's possible that there is a similar issue with
121
+ // TOGGLE_CONNECT_COMMAND below when the provider connect returns a
122
+ // promise.
123
+ // https://github.com/facebook/lexical/issues/6640
124
+ disconnect();
125
+ }
126
+ }
127
+ provider.off('sync', onSync);
128
+ provider.off('status', onStatus);
129
+ provider.off('reload', onProviderDocReload);
130
+ awareness.off('update', onAwarenessUpdate);
131
+ // Unsubscribe from Loro document changes
132
+ unsubscribe?.();
133
+ docMap.delete(id);
134
+ removeListener();
135
+ mutationListenerCleanups.forEach((cleanup) => cleanup());
136
+ };
137
+ }, [
138
+ binding,
139
+ color,
140
+ connect,
141
+ disconnect,
142
+ docMap,
143
+ editor,
144
+ id,
145
+ initialEditorState,
146
+ name,
147
+ provider,
148
+ shouldBootstrap,
149
+ awarenessData,
150
+ setDoc,
151
+ syncCursorPositionsFn,
152
+ onInitialization,
153
+ ]);
154
+ const cursorsContainer = useMemo(() => {
155
+ const ref = (element) => {
156
+ binding.cursorsContainer = element;
157
+ };
158
+ return createPortal(_jsx("div", { ref: ref, style: {
159
+ position: 'fixed',
160
+ top: 0,
161
+ left: 0,
162
+ width: '100vw',
163
+ height: '100vh',
164
+ pointerEvents: 'none',
165
+ zIndex: 1000,
166
+ overflow: 'visible',
167
+ } }), (cursorsContainerRef && cursorsContainerRef.current) || document.body);
168
+ }, [binding, cursorsContainerRef]);
169
+ useEffect(() => {
170
+ return editor.registerCommand(TOGGLE_CONNECT_COMMAND, (payload) => {
171
+ const shouldConnect = payload;
172
+ if (shouldConnect) {
173
+ connect();
174
+ }
175
+ else {
176
+ disconnect();
177
+ }
178
+ return true;
179
+ }, COMMAND_PRIORITY_EDITOR);
180
+ }, [connect, disconnect, editor]);
181
+ return cursorsContainer;
182
+ }
183
+ export function useFocusTracking(editor, provider, name, color, awarenessData) {
184
+ useEffect(() => {
185
+ return mergeRegister(editor.registerCommand(FOCUS_COMMAND, () => {
186
+ setLocalStateFocus(provider, name, color, true, awarenessData || {});
187
+ return false;
188
+ }, COMMAND_PRIORITY_EDITOR), editor.registerCommand(BLUR_COMMAND, () => {
189
+ setLocalStateFocus(provider, name, color, false, awarenessData || {});
190
+ return false;
191
+ }, COMMAND_PRIORITY_EDITOR));
192
+ }, [color, editor, name, provider, awarenessData]);
193
+ }
194
+ export function useHistory(editor, binding) {
195
+ const undoManager = useMemo(() => createUndoManager(binding), [binding]);
196
+ useEffect(() => {
197
+ const undo = () => {
198
+ undoManager.undo();
199
+ };
200
+ const redo = () => {
201
+ undoManager.redo();
202
+ };
203
+ return mergeRegister(editor.registerCommand(UNDO_COMMAND, () => {
204
+ undo();
205
+ return true;
206
+ }, COMMAND_PRIORITY_EDITOR), editor.registerCommand(REDO_COMMAND, () => {
207
+ redo();
208
+ return true;
209
+ }, COMMAND_PRIORITY_EDITOR));
210
+ });
211
+ const clearHistory = useCallback(() => {
212
+ undoManager.clear();
213
+ }, [undoManager]);
214
+ // Exposing undo and redo states
215
+ React.useEffect(() => {
216
+ const updateUndoRedoStates = () => {
217
+ editor.dispatchCommand(CAN_UNDO_COMMAND, undoManager.canUndo());
218
+ editor.dispatchCommand(CAN_REDO_COMMAND, undoManager.canRedo());
219
+ };
220
+ // Initial state update
221
+ updateUndoRedoStates();
222
+ // Loro UndoManager doesn't have event listeners like YJS
223
+ // We would need to check state periodically or after operations
224
+ // For now, update after each operation
225
+ return () => {
226
+ // No cleanup needed for Loro UndoManager events
227
+ };
228
+ }, [editor, undoManager]);
229
+ return clearHistory;
230
+ }
231
+ function initializeEditor(editor, initialEditorState) {
232
+ // Text used by the server-side default scaffold that fresh rooms are
233
+ // pre-seeded with. When a room only contains this scaffold it should be
234
+ // treated as empty so the host app's real initial content can replace it.
235
+ const PLACEHOLDER_TEXTS = new Set([
236
+ 'Lexical with Loro',
237
+ 'Welcome to Lexical with Loro',
238
+ 'Type something...',
239
+ ]);
240
+ const hasMeaningfulContent = () => {
241
+ const root = $getRoot();
242
+ const children = root.getChildren();
243
+ if (children.length === 0) {
244
+ return false;
245
+ }
246
+ for (const child of children) {
247
+ const type = child.getType();
248
+ const text = child.getTextContent().trim();
249
+ if (text.length > 0) {
250
+ // Ignore the known default scaffold text so it can be overwritten by
251
+ // the host app's initial content on a freshly created room.
252
+ if (!PLACEHOLDER_TEXTS.has(text)) {
253
+ return true;
254
+ }
255
+ continue;
256
+ }
257
+ // Ignore known scaffold placeholders used by some host apps before
258
+ // collaboration bootstrap fills the real initial document.
259
+ if (type !== 'paragraph' && type !== 'jupyter-output') {
260
+ return true;
261
+ }
262
+ }
263
+ return false;
264
+ };
265
+ // Only seed a room whose sole content is the (empty/scaffold) default.
266
+ let shouldSeed = false;
267
+ editor.getEditorState().read(() => {
268
+ shouldSeed = !hasMeaningfulContent();
269
+ });
270
+ console.log('[SEED-DEBUG] initializeEditor: shouldSeed=', shouldSeed, 'hasInitialState=', !!initialEditorState, 'type=', typeof initialEditorState);
271
+ if (!shouldSeed || !initialEditorState) {
272
+ return;
273
+ }
274
+ // Preferred path: a serialized editor state (string). Seed it INCREMENTALLY,
275
+ // exactly as a human collaborator would build the document — append each
276
+ // top-level block in its own commit, then remove the scaffold blocks one by
277
+ // one. Each small, well-formed commit produces clean per-node "created"
278
+ // mutations that the Loro binding propagates reliably. A single bulk
279
+ // clear()+append emitted one large, malformed batch that failed to integrate
280
+ // on remote peers (inline nodes arriving without a resolved parent), which is
281
+ // why the second editor never received the initial content.
282
+ if (typeof initialEditorState === 'string') {
283
+ let serializedChildren = [];
284
+ try {
285
+ const serialized = JSON.parse(initialEditorState);
286
+ serializedChildren = serialized?.root?.children ?? [];
287
+ }
288
+ catch (error) {
289
+ // Not a rebuildable serialized state → fall back to a whole-state swap.
290
+ editor.update(() => {
291
+ editor.setEditorState(editor.parseEditorState(initialEditorState), {
292
+ tag: HISTORY_MERGE_TAG,
293
+ });
294
+ }, { tag: HISTORY_MERGE_TAG });
295
+ return;
296
+ }
297
+ // IMPORTANT: every seed update below is committed with `discrete: true`.
298
+ // The remote snapshot import runs `editor.update({tag: SKIP_COLLAB_TAG})`
299
+ // and that update is still queued when this bootstrap runs. Without
300
+ // `discrete`, Lexical coalesces the queued remote update together with our
301
+ // seed updates into a single reconciliation and unions their tags, so the
302
+ // seed batch inherits `skip-collab` and the collab sync ignores it. A
303
+ // leading discrete no-op flushes the pending remote (skip-collab) update on
304
+ // its own, and each discrete seed update then commits as its own
305
+ // reconciliation carrying only `history-merge`, so it propagates to peers.
306
+ // eslint-disable-next-line @typescript-eslint/no-empty-function
307
+ editor.update(() => { }, { tag: HISTORY_MERGE_TAG, discrete: true });
308
+ // Clear any pending selection first: it may point at scaffold nodes we are
309
+ // about to remove, which would otherwise crash selection-reading plugins
310
+ // (e.g. the typeahead menu).
311
+ editor.update(() => {
312
+ $setSelection(null);
313
+ }, { tag: HISTORY_MERGE_TAG, discrete: true });
314
+ // Capture the scaffold blocks AFTER the leading discrete flush, so any
315
+ // late-arriving remote scaffold nodes are included. We remove them BEFORE
316
+ // appending the real content: the scaffold's position in the Loro tree does
317
+ // not necessarily line up with its Lexical index, so appending after it
318
+ // makes the computed Loro insertion index drift out of range. Removing the
319
+ // scaffold first leaves both trees at an aligned empty root, after which
320
+ // each appended block sits at a matching index in Lexical and Loro.
321
+ let scaffoldKeys = [];
322
+ editor.getEditorState().read(() => {
323
+ scaffoldKeys = $getRoot()
324
+ .getChildren()
325
+ .map(child => child.getKey());
326
+ });
327
+ console.log('[SEED-DEBUG] initializeEditor: seeding', serializedChildren.length, 'blocks, removing', scaffoldKeys.length, 'scaffold blocks first');
328
+ // Remove the scaffold blocks one by one so both trees reach an aligned
329
+ // empty root before we append the real content.
330
+ for (const key of scaffoldKeys) {
331
+ editor.update(() => {
332
+ const node = $getNodeByKey(key);
333
+ if (node) {
334
+ node.remove();
335
+ }
336
+ }, { tag: HISTORY_MERGE_TAG, discrete: true });
337
+ }
338
+ // Append the real content block by block into the now-empty, aligned root
339
+ // (each commit ≈ one collaborator action).
340
+ let __blockIndex = 0;
341
+ for (const serializedNode of serializedChildren) {
342
+ const __idx = __blockIndex++;
343
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
344
+ const __type = serializedNode?.type;
345
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
346
+ const __childTypes = Array.isArray(serializedNode?.children)
347
+ ? // eslint-disable-next-line @typescript-eslint/no-explicit-any
348
+ serializedNode.children.map((c) => c?.type)
349
+ : [];
350
+ editor.update(() => {
351
+ const root = $getRoot();
352
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
353
+ root.append($parseSerializedNode(serializedNode));
354
+ }, { tag: HISTORY_MERGE_TAG, discrete: true });
355
+ console.log('[SEED-DEBUG] appended block', __idx, 'type=', __type, 'children=', __childTypes);
356
+ }
357
+ return;
358
+ }
359
+ // Non-string fallbacks (EditorState object or builder function).
360
+ editor.update(() => {
361
+ if (!hasMeaningfulContent()) {
362
+ if (typeof initialEditorState === 'object') {
363
+ editor.setEditorState(initialEditorState, {
364
+ tag: HISTORY_MERGE_TAG,
365
+ });
366
+ }
367
+ else if (typeof initialEditorState === 'function') {
368
+ initialEditorState(editor);
369
+ }
370
+ }
371
+ }, { tag: HISTORY_MERGE_TAG });
372
+ }
373
+ function clearEditorSkipCollab(editor, binding) {
374
+ // reset editor state
375
+ editor.update(() => {
376
+ const root = $getRoot();
377
+ root.clear();
378
+ root.select();
379
+ }, {
380
+ tag: SKIP_COLLAB_TAG,
381
+ });
382
+ if (binding.cursors == null) {
383
+ return;
384
+ }
385
+ const cursors = binding.cursors;
386
+ if (cursors == null) {
387
+ return;
388
+ }
389
+ const cursorsContainer = binding.cursorsContainer;
390
+ if (cursorsContainer == null) {
391
+ return;
392
+ }
393
+ // reset cursors in dom
394
+ const cursorsArr = Array.from(cursors.values());
395
+ for (let i = 0; i < cursorsArr.length; i++) {
396
+ const cursor = cursorsArr[i];
397
+ const selection = cursor.selection;
398
+ if (selection && selection.selections != null) {
399
+ const selections = selection.selections;
400
+ for (let j = 0; j < selections.length; j++) {
401
+ cursorsContainer.removeChild(selections[i]);
402
+ }
403
+ }
404
+ }
405
+ }