@datalayer/lexical-loro 0.2.4 β 0.2.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.
- package/lib/App.d.ts +2 -0
- package/lib/App.js +141 -0
- package/lib/Editor.d.ts +2 -0
- package/lib/Editor.js +115 -0
- package/lib/Settings.d.ts +2 -0
- package/lib/Settings.js +57 -0
- package/lib/appSettings.d.ts +36 -0
- package/lib/appSettings.js +48 -0
- package/lib/collab/loro/Bindings.d.ts +41 -0
- package/lib/collab/loro/Bindings.js +99 -0
- package/lib/collab/loro/Debug.d.ts +33 -0
- package/lib/collab/loro/Debug.js +452 -0
- package/lib/collab/loro/LexicalCollaborationContext.d.ts +19 -0
- package/lib/collab/loro/LexicalCollaborationContext.js +52 -0
- package/lib/collab/loro/LexicalCollaborationPlugin.d.ts +24 -0
- package/lib/collab/loro/LexicalCollaborationPlugin.js +83 -0
- package/lib/collab/loro/State.d.ts +53 -0
- package/lib/collab/loro/State.js +94 -0
- package/lib/collab/loro/components/LoroCollaborationUI.d.ts +13 -0
- package/lib/collab/loro/components/LoroCollaborationUI.js +9 -0
- package/lib/collab/loro/components/LoroCollaborators.d.ts +8 -0
- package/lib/collab/loro/components/LoroCollaborators.js +102 -0
- package/lib/collab/loro/components/index.d.ts +2 -0
- package/lib/collab/loro/components/index.js +6 -0
- package/lib/collab/loro/index.d.ts +6 -0
- package/lib/collab/loro/index.js +10 -0
- package/lib/collab/loro/integrators/BaseIntegrator.d.ts +14 -0
- package/lib/collab/loro/integrators/BaseIntegrator.js +5 -0
- package/lib/collab/loro/integrators/CounterIntegrator.d.ts +23 -0
- package/lib/collab/loro/integrators/CounterIntegrator.js +44 -0
- package/lib/collab/loro/integrators/ListIntegrator.d.ts +23 -0
- package/lib/collab/loro/integrators/ListIntegrator.js +53 -0
- package/lib/collab/loro/integrators/MapIntegrator.d.ts +24 -0
- package/lib/collab/loro/integrators/MapIntegrator.js +235 -0
- package/lib/collab/loro/integrators/TextIntegrator.d.ts +25 -0
- package/lib/collab/loro/integrators/TextIntegrator.js +55 -0
- package/lib/collab/loro/integrators/TreeIntegrator.d.ts +36 -0
- package/lib/collab/loro/integrators/TreeIntegrator.js +251 -0
- package/lib/collab/loro/nodes/NodeFactory.d.ts +15 -0
- package/lib/collab/loro/nodes/NodeFactory.js +101 -0
- package/lib/collab/loro/nodes/NodesMapper.d.ts +120 -0
- package/lib/collab/loro/nodes/NodesMapper.js +277 -0
- package/lib/collab/loro/propagators/DecoratorNodePropagator.d.ts +60 -0
- package/lib/collab/loro/propagators/DecoratorNodePropagator.js +306 -0
- package/lib/collab/loro/propagators/ElementNodePropagator.d.ts +62 -0
- package/lib/collab/loro/propagators/ElementNodePropagator.js +326 -0
- package/lib/collab/loro/propagators/LineBreakNodePropagator.d.ts +57 -0
- package/lib/collab/loro/propagators/LineBreakNodePropagator.js +200 -0
- package/lib/collab/loro/propagators/RootNodePropagator.d.ts +55 -0
- package/lib/collab/loro/propagators/RootNodePropagator.js +174 -0
- package/lib/collab/loro/propagators/TextNodePropagator.d.ts +60 -0
- package/lib/collab/loro/propagators/TextNodePropagator.js +440 -0
- package/lib/collab/loro/propagators/index.d.ts +49 -0
- package/lib/collab/loro/propagators/index.js +30 -0
- package/lib/collab/loro/provider/websocket.d.ts +116 -0
- package/lib/collab/loro/provider/websocket.js +911 -0
- package/lib/collab/loro/servers/index.d.ts +0 -0
- package/lib/collab/loro/servers/index.js +4 -0
- package/lib/collab/loro/servers/ws/callback.d.ts +5 -0
- package/lib/collab/loro/servers/ws/callback.js +89 -0
- package/lib/collab/loro/servers/ws/server.d.ts +2 -0
- package/lib/collab/loro/servers/ws/server.js +29 -0
- package/lib/collab/loro/servers/ws/utils.d.ts +40 -0
- package/lib/collab/loro/servers/ws/utils.js +517 -0
- package/lib/collab/loro/sync/SyncCursors.d.ts +32 -0
- package/lib/collab/loro/sync/SyncCursors.js +475 -0
- package/lib/collab/loro/sync/SyncLexicalToLoro.d.ts +4 -0
- package/lib/collab/loro/sync/SyncLexicalToLoro.js +113 -0
- package/lib/collab/loro/sync/SyncLoroToLexical.d.ts +5 -0
- package/lib/collab/loro/sync/SyncLoroToLexical.js +100 -0
- package/lib/collab/loro/types/LexicalNodeData.d.ts +32 -0
- package/lib/collab/loro/types/LexicalNodeData.js +75 -0
- package/lib/collab/loro/useCollaboration.d.ts +12 -0
- package/lib/collab/loro/useCollaboration.js +260 -0
- package/lib/collab/loro/utils/InitialContent.d.ts +64 -0
- package/lib/collab/loro/utils/InitialContent.js +113 -0
- package/lib/collab/loro/utils/LexicalToLoro.d.ts +18 -0
- package/lib/collab/loro/utils/LexicalToLoro.js +100 -0
- package/lib/collab/loro/utils/Utils.d.ts +44 -0
- package/lib/collab/loro/utils/Utils.js +157 -0
- package/lib/collab/loro/wsProvider.d.ts +8 -0
- package/lib/collab/loro/wsProvider.js +35 -0
- package/lib/collab/utils/invariant.d.ts +1 -0
- package/lib/collab/utils/invariant.js +15 -0
- package/lib/collab/utils/simpleDiffWithCursor.d.ts +5 -0
- package/lib/collab/utils/simpleDiffWithCursor.js +35 -0
- package/lib/collab/yjs/Bindings.d.ts +23 -0
- package/lib/collab/yjs/Bindings.js +26 -0
- package/lib/collab/yjs/Debug.d.ts +23 -0
- package/lib/collab/yjs/Debug.js +213 -0
- package/lib/collab/yjs/LexicalCollaborationContext.d.ts +10 -0
- package/lib/collab/yjs/LexicalCollaborationContext.js +37 -0
- package/lib/collab/yjs/LexicalCollaborationPlugin.d.ts +21 -0
- package/lib/collab/yjs/LexicalCollaborationPlugin.js +63 -0
- package/lib/collab/yjs/State.d.ts +51 -0
- package/lib/collab/yjs/State.js +35 -0
- package/lib/collab/yjs/nodes/AnyCollabNode.d.ts +5 -0
- package/lib/collab/yjs/nodes/AnyCollabNode.js +1 -0
- package/lib/collab/yjs/nodes/CollabDecoratorNode.d.ts +22 -0
- package/lib/collab/yjs/nodes/CollabDecoratorNode.js +64 -0
- package/lib/collab/yjs/nodes/CollabElementNode.d.ts +40 -0
- package/lib/collab/yjs/nodes/CollabElementNode.js +462 -0
- package/lib/collab/yjs/nodes/CollabLineBreakNode.d.ts +19 -0
- package/lib/collab/yjs/nodes/CollabLineBreakNode.js +44 -0
- package/lib/collab/yjs/nodes/CollabTextNode.d.ts +25 -0
- package/lib/collab/yjs/nodes/CollabTextNode.js +103 -0
- package/lib/collab/yjs/provider/websocket.d.ts +88 -0
- package/lib/collab/yjs/provider/websocket.js +415 -0
- package/lib/collab/yjs/servers/index.d.ts +0 -0
- package/lib/collab/yjs/servers/index.js +0 -0
- package/lib/collab/yjs/servers/ws/callback.d.ts +5 -0
- package/lib/collab/yjs/servers/ws/callback.js +72 -0
- package/lib/collab/yjs/servers/ws/server.d.ts +2 -0
- package/lib/collab/yjs/servers/ws/server.js +25 -0
- package/lib/collab/yjs/servers/ws/utils.d.ts +49 -0
- package/lib/collab/yjs/servers/ws/utils.js +284 -0
- package/lib/collab/yjs/sync/SyncCursors.d.ts +39 -0
- package/lib/collab/yjs/sync/SyncCursors.js +351 -0
- package/lib/collab/yjs/sync/SyncEditorStates.d.ts +10 -0
- package/lib/collab/yjs/sync/SyncEditorStates.js +200 -0
- package/lib/collab/yjs/useCollaboration.d.ts +12 -0
- package/lib/collab/yjs/useCollaboration.js +255 -0
- package/lib/collab/yjs/utils/Utils.d.ts +25 -0
- package/lib/collab/yjs/utils/Utils.js +402 -0
- package/lib/collab/yjs/wsProvider.d.ts +3 -0
- package/lib/collab/yjs/wsProvider.js +21 -0
- package/lib/commenting/index.d.ts +41 -0
- package/lib/commenting/index.js +328 -0
- package/lib/context/FlashMessageContext.d.ts +7 -0
- package/lib/context/FlashMessageContext.js +24 -0
- package/lib/context/SettingsContext.d.ts +12 -0
- package/lib/context/SettingsContext.js +38 -0
- package/lib/context/SharedHistoryContext.d.ts +11 -0
- package/lib/context/SharedHistoryContext.js +11 -0
- package/lib/context/ToolbarContext.d.ts +65 -0
- package/lib/context/ToolbarContext.js +84 -0
- package/lib/demo.d.ts +12 -0
- package/lib/demo.js +45 -0
- package/lib/hooks/useFlashMessage.d.ts +2 -0
- package/lib/hooks/useFlashMessage.js +8 -0
- package/lib/hooks/useModal.d.ts +5 -0
- package/lib/hooks/useModal.js +26 -0
- package/lib/hooks/useReport.d.ts +1 -0
- package/lib/hooks/useReport.js +50 -0
- package/lib/index.d.ts +1 -0
- package/lib/index.js +5 -0
- package/lib/nodes/AutocompleteNode.d.ts +27 -0
- package/lib/nodes/AutocompleteNode.js +60 -0
- package/lib/nodes/CounterComponent.d.ts +6 -0
- package/lib/nodes/CounterComponent.js +137 -0
- package/lib/nodes/CounterNode.d.ts +23 -0
- package/lib/nodes/CounterNode.js +47 -0
- package/lib/nodes/DateTimeNode/DateTimeComponent.d.ts +8 -0
- package/lib/nodes/DateTimeNode/DateTimeComponent.js +119 -0
- package/lib/nodes/DateTimeNode/DateTimeNode.d.ts +27 -0
- package/lib/nodes/DateTimeNode/DateTimeNode.js +82 -0
- package/lib/nodes/EmojiNode.d.ts +18 -0
- package/lib/nodes/EmojiNode.js +54 -0
- package/lib/nodes/EquationComponent.d.ts +9 -0
- package/lib/nodes/EquationComponent.js +75 -0
- package/lib/nodes/EquationNode.d.ts +26 -0
- package/lib/nodes/EquationNode.js +109 -0
- package/lib/nodes/ExcalidrawNode/ExcalidrawComponent.d.ts +8 -0
- package/lib/nodes/ExcalidrawNode/ExcalidrawComponent.js +110 -0
- package/lib/nodes/ExcalidrawNode/ExcalidrawImage.d.ts +50 -0
- package/lib/nodes/ExcalidrawNode/ExcalidrawImage.js +55 -0
- package/lib/nodes/ExcalidrawNode/index.d.ts +32 -0
- package/lib/nodes/ExcalidrawNode/index.js +117 -0
- package/lib/nodes/FigmaNode.d.ts +20 -0
- package/lib/nodes/FigmaNode.js +52 -0
- package/lib/nodes/ImageComponent.d.ts +16 -0
- package/lib/nodes/ImageComponent.js +272 -0
- package/lib/nodes/ImageNode.d.ts +50 -0
- package/lib/nodes/ImageNode.js +151 -0
- package/lib/nodes/InlineImageNode/InlineImageComponent.d.ts +26 -0
- package/lib/nodes/InlineImageNode/InlineImageComponent.js +161 -0
- package/lib/nodes/InlineImageNode/InlineImageNode.d.ts +59 -0
- package/lib/nodes/InlineImageNode/InlineImageNode.js +162 -0
- package/lib/nodes/KeywordNode.d.ts +14 -0
- package/lib/nodes/KeywordNode.js +37 -0
- package/lib/nodes/LayoutContainerNode.d.ts +24 -0
- package/lib/nodes/LayoutContainerNode.js +95 -0
- package/lib/nodes/LayoutItemNode.d.ts +16 -0
- package/lib/nodes/LayoutItemNode.js +69 -0
- package/lib/nodes/MentionNode.d.ts +20 -0
- package/lib/nodes/MentionNode.js +85 -0
- package/lib/nodes/PageBreakNode/index.d.ts +17 -0
- package/lib/nodes/PageBreakNode/index.js +83 -0
- package/lib/nodes/PlaygroundNodes.d.ts +3 -0
- package/lib/nodes/PlaygroundNodes.js +75 -0
- package/lib/nodes/PollComponent.d.ts +9 -0
- package/lib/nodes/PollComponent.js +85 -0
- package/lib/nodes/PollNode.d.ts +43 -0
- package/lib/nodes/PollNode.js +153 -0
- package/lib/nodes/SpecialTextNode.d.ts +24 -0
- package/lib/nodes/SpecialTextNode.js +54 -0
- package/lib/nodes/StickyComponent.d.ts +10 -0
- package/lib/nodes/StickyComponent.js +162 -0
- package/lib/nodes/StickyNode.d.ts +31 -0
- package/lib/nodes/StickyNode.js +76 -0
- package/lib/nodes/TweetNode.d.ts +21 -0
- package/lib/nodes/TweetNode.js +119 -0
- package/lib/nodes/YouTubeNode.d.ts +22 -0
- package/lib/nodes/YouTubeNode.js +84 -0
- package/lib/plugins/ActionsPlugin/index.d.ts +5 -0
- package/lib/plugins/ActionsPlugin/index.js +168 -0
- package/lib/plugins/AutoEmbedPlugin/index.d.ts +19 -0
- package/lib/plugins/AutoEmbedPlugin/index.js +158 -0
- package/lib/plugins/AutoLinkPlugin/index.d.ts +2 -0
- package/lib/plugins/AutoLinkPlugin/index.js +15 -0
- package/lib/plugins/AutocompletePlugin/index.d.ts +10 -0
- package/lib/plugins/AutocompletePlugin/index.js +2477 -0
- package/lib/plugins/CodeActionMenuPlugin/components/CopyButton/index.d.ts +7 -0
- package/lib/plugins/CodeActionMenuPlugin/components/CopyButton/index.js +46 -0
- package/lib/plugins/CodeActionMenuPlugin/components/PrettierButton/index.d.ts +17 -0
- package/lib/plugins/CodeActionMenuPlugin/components/PrettierButton/index.js +115 -0
- package/lib/plugins/CodeActionMenuPlugin/index.d.ts +5 -0
- package/lib/plugins/CodeActionMenuPlugin/index.js +104 -0
- package/lib/plugins/CodeActionMenuPlugin/utils.d.ts +1 -0
- package/lib/plugins/CodeActionMenuPlugin/utils.js +22 -0
- package/lib/plugins/CodeHighlightPrismPlugin/index.d.ts +2 -0
- package/lib/plugins/CodeHighlightPrismPlugin/index.js +14 -0
- package/lib/plugins/CodeHighlightShikiPlugin/index.d.ts +2 -0
- package/lib/plugins/CodeHighlightShikiPlugin/index.js +14 -0
- package/lib/plugins/CollapsiblePlugin/CollapsibleContainerNode.d.ts +25 -0
- package/lib/plugins/CollapsiblePlugin/CollapsibleContainerNode.js +135 -0
- package/lib/plugins/CollapsiblePlugin/CollapsibleContentNode.d.ts +16 -0
- package/lib/plugins/CollapsiblePlugin/CollapsibleContentNode.js +83 -0
- package/lib/plugins/CollapsiblePlugin/CollapsibleTitleNode.d.ts +16 -0
- package/lib/plugins/CollapsiblePlugin/CollapsibleTitleNode.js +85 -0
- package/lib/plugins/CollapsiblePlugin/CollapsibleUtils.d.ts +2 -0
- package/lib/plugins/CollapsiblePlugin/CollapsibleUtils.js +12 -0
- package/lib/plugins/CollapsiblePlugin/index.d.ts +3 -0
- package/lib/plugins/CollapsiblePlugin/index.js +132 -0
- package/lib/plugins/CommentPlugin/index.d.ts +9 -0
- package/lib/plugins/CommentPlugin/index.js +460 -0
- package/lib/plugins/ComponentPickerPlugin/index.d.ts +2 -0
- package/lib/plugins/ComponentPickerPlugin/index.js +276 -0
- package/lib/plugins/ContextMenuPlugin/index.d.ts +2 -0
- package/lib/plugins/ContextMenuPlugin/index.js +112 -0
- package/lib/plugins/CounterPlugin/index.d.ts +3 -0
- package/lib/plugins/CounterPlugin/index.js +24 -0
- package/lib/plugins/DateTimePlugin/index.d.ts +8 -0
- package/lib/plugins/DateTimePlugin/index.js +28 -0
- package/lib/plugins/DebugPlugin/index.d.ts +3 -0
- package/lib/plugins/DebugPlugin/index.js +219 -0
- package/lib/plugins/DocsPlugin/index.d.ts +2 -0
- package/lib/plugins/DocsPlugin/index.js +4 -0
- package/lib/plugins/DragDropPastePlugin/index.d.ts +1 -0
- package/lib/plugins/DragDropPastePlugin/index.js +37 -0
- package/lib/plugins/DraggableBlockPlugin/index.d.ts +12 -0
- package/lib/plugins/DraggableBlockPlugin/index.js +36 -0
- package/lib/plugins/EmojiPickerPlugin/index.d.ts +1 -0
- package/lib/plugins/EmojiPickerPlugin/index.js +84 -0
- package/lib/plugins/EmojisPlugin/index.d.ts +2 -0
- package/lib/plugins/EmojisPlugin/index.js +56 -0
- package/lib/plugins/EquationsPlugin/index.d.ts +14 -0
- package/lib/plugins/EquationsPlugin/index.js +34 -0
- package/lib/plugins/ExcalidrawPlugin/index.d.ts +5 -0
- package/lib/plugins/ExcalidrawPlugin/index.js +44 -0
- package/lib/plugins/FigmaPlugin/index.d.ts +4 -0
- package/lib/plugins/FigmaPlugin/index.js +24 -0
- package/lib/plugins/FloatingLinkEditorPlugin/index.d.ts +15 -0
- package/lib/plugins/FloatingLinkEditorPlugin/index.js +280 -0
- package/lib/plugins/FloatingTextFormatToolbarPlugin/index.d.ts +7 -0
- package/lib/plugins/FloatingTextFormatToolbarPlugin/index.js +219 -0
- package/lib/plugins/ImagesPlugin/index.d.ts +24 -0
- package/lib/plugins/ImagesPlugin/index.js +195 -0
- package/lib/plugins/InlineImagePlugin/index.d.ts +17 -0
- package/lib/plugins/InlineImagePlugin/index.js +180 -0
- package/lib/plugins/KeywordsPlugin/index.d.ts +2 -0
- package/lib/plugins/KeywordsPlugin/index.js +35 -0
- package/lib/plugins/LayoutPlugin/InsertLayoutDialog.d.ts +6 -0
- package/lib/plugins/LayoutPlugin/InsertLayoutDialog.js +21 -0
- package/lib/plugins/LayoutPlugin/LayoutPlugin.d.ts +7 -0
- package/lib/plugins/LayoutPlugin/LayoutPlugin.js +135 -0
- package/lib/plugins/LinkPlugin/index.d.ts +6 -0
- package/lib/plugins/LinkPlugin/index.js +11 -0
- package/lib/plugins/MarkdownShortcutPlugin/index.d.ts +2 -0
- package/lib/plugins/MarkdownShortcutPlugin/index.js +6 -0
- package/lib/plugins/MarkdownTransformers/index.d.ts +8 -0
- package/lib/plugins/MarkdownTransformers/index.js +238 -0
- package/lib/plugins/MaxLengthPlugin/index.d.ts +3 -0
- package/lib/plugins/MaxLengthPlugin/index.js +41 -0
- package/lib/plugins/MentionsPlugin/index.d.ts +2 -0
- package/lib/plugins/MentionsPlugin/index.js +564 -0
- package/lib/plugins/PageBreakPlugin/index.d.ts +4 -0
- package/lib/plugins/PageBreakPlugin/index.js +31 -0
- package/lib/plugins/PasteLogPlugin/index.d.ts +2 -0
- package/lib/plugins/PasteLogPlugin/index.js +27 -0
- package/lib/plugins/PollPlugin/index.d.ts +8 -0
- package/lib/plugins/PollPlugin/index.js +38 -0
- package/lib/plugins/ShortcutsPlugin/index.d.ts +6 -0
- package/lib/plugins/ShortcutsPlugin/index.js +116 -0
- package/lib/plugins/ShortcutsPlugin/shortcuts.d.ts +59 -0
- package/lib/plugins/ShortcutsPlugin/shortcuts.js +173 -0
- package/lib/plugins/SpecialTextPlugin/index.d.ts +2 -0
- package/lib/plugins/SpecialTextPlugin/index.js +50 -0
- package/lib/plugins/SpeechToTextPlugin/index.d.ts +5 -0
- package/lib/plugins/SpeechToTextPlugin/index.js +86 -0
- package/lib/plugins/StickyPlugin/index.d.ts +2 -0
- package/lib/plugins/StickyPlugin/index.js +16 -0
- package/lib/plugins/TabFocusPlugin/index.d.ts +1 -0
- package/lib/plugins/TabFocusPlugin/index.js +38 -0
- package/lib/plugins/TableActionMenuPlugin/index.d.ts +5 -0
- package/lib/plugins/TableActionMenuPlugin/index.js +492 -0
- package/lib/plugins/TableCellResizer/index.d.ts +3 -0
- package/lib/plugins/TableCellResizer/index.js +297 -0
- package/lib/plugins/TableHoverActionsPlugin/index.d.ts +4 -0
- package/lib/plugins/TableHoverActionsPlugin/index.js +188 -0
- package/lib/plugins/TableOfContentsPlugin/index.d.ts +2 -0
- package/lib/plugins/TableOfContentsPlugin/index.js +116 -0
- package/lib/plugins/TablePlugin.d.ts +31 -0
- package/lib/plugins/TablePlugin.js +63 -0
- package/lib/plugins/TestRecorderPlugin/index.d.ts +3 -0
- package/lib/plugins/TestRecorderPlugin/index.js +346 -0
- package/lib/plugins/ToolbarPlugin/fontSize.d.ts +9 -0
- package/lib/plugins/ToolbarPlugin/fontSize.js +84 -0
- package/lib/plugins/ToolbarPlugin/index.d.ts +9 -0
- package/lib/plugins/ToolbarPlugin/index.js +500 -0
- package/lib/plugins/ToolbarPlugin/utils.d.ts +26 -0
- package/lib/plugins/ToolbarPlugin/utils.js +247 -0
- package/lib/plugins/TreeViewPlugin/index.d.ts +2 -0
- package/lib/plugins/TreeViewPlugin/index.js +7 -0
- package/lib/plugins/TwitterPlugin/index.d.ts +4 -0
- package/lib/plugins/TwitterPlugin/index.js +24 -0
- package/lib/plugins/TypingPerfPlugin/index.d.ts +2 -0
- package/lib/plugins/TypingPerfPlugin/index.js +97 -0
- package/lib/plugins/YouTubePlugin/index.d.ts +4 -0
- package/lib/plugins/YouTubePlugin/index.js +24 -0
- package/lib/server/validation.d.ts +1 -0
- package/lib/server/validation.js +115 -0
- package/lib/setupEnv.d.ts +2 -0
- package/lib/setupEnv.js +29 -0
- package/lib/themes/CommentEditorTheme.d.ts +4 -0
- package/lib/themes/CommentEditorTheme.js +11 -0
- package/lib/themes/PlaygroundEditorTheme.d.ts +4 -0
- package/lib/themes/PlaygroundEditorTheme.js +124 -0
- package/lib/themes/StickyEditorTheme.d.ts +4 -0
- package/lib/themes/StickyEditorTheme.js +11 -0
- package/lib/tyes.dt.d.ts +12 -0
- package/lib/tyes.dt.js +4 -0
- package/lib/ui/Button.d.ts +12 -0
- package/lib/ui/Button.js +6 -0
- package/lib/ui/ColorPicker.d.ts +14 -0
- package/lib/ui/ColorPicker.js +219 -0
- package/lib/ui/ContentEditable.d.ts +9 -0
- package/lib/ui/ContentEditable.js +6 -0
- package/lib/ui/Dialog.d.ts +10 -0
- package/lib/ui/Dialog.js +8 -0
- package/lib/ui/DropDown.d.ts +18 -0
- package/lib/ui/DropDown.js +133 -0
- package/lib/ui/DropdownColorPicker.d.ts +13 -0
- package/lib/ui/DropdownColorPicker.js +6 -0
- package/lib/ui/EquationEditor.d.ts +8 -0
- package/lib/ui/EquationEditor.js +11 -0
- package/lib/ui/ExcalidrawModal.d.ts +42 -0
- package/lib/ui/ExcalidrawModal.js +103 -0
- package/lib/ui/FileInput.d.ts +10 -0
- package/lib/ui/FileInput.js +5 -0
- package/lib/ui/FlashMessage.d.ts +7 -0
- package/lib/ui/FlashMessage.js +6 -0
- package/lib/ui/ImageResizer.d.ts +17 -0
- package/lib/ui/ImageResizer.js +171 -0
- package/lib/ui/KatexEquationAlterer.d.ts +8 -0
- package/lib/ui/KatexEquationAlterer.js +23 -0
- package/lib/ui/KatexRenderer.d.ts +6 -0
- package/lib/ui/KatexRenderer.js +24 -0
- package/lib/ui/Modal.d.ts +9 -0
- package/lib/ui/Modal.js +48 -0
- package/lib/ui/Select.d.ts +8 -0
- package/lib/ui/Select.js +5 -0
- package/lib/ui/Switch.d.ts +8 -0
- package/lib/ui/Switch.js +6 -0
- package/lib/ui/TextInput.d.ts +13 -0
- package/lib/ui/TextInput.js +7 -0
- package/lib/utils/docSerialization.d.ts +3 -0
- package/lib/utils/docSerialization.js +60 -0
- package/lib/utils/emoji-list.d.ts +20 -0
- package/lib/utils/emoji-list.js +16609 -0
- package/lib/utils/getDOMRangeRect.d.ts +8 -0
- package/lib/utils/getDOMRangeRect.js +26 -0
- package/lib/utils/getSelectedNode.d.ts +2 -0
- package/lib/utils/getSelectedNode.js +28 -0
- package/lib/utils/getThemeSelector.d.ts +2 -0
- package/lib/utils/getThemeSelector.js +14 -0
- package/lib/utils/isMobileWidth.d.ts +7 -0
- package/lib/utils/isMobileWidth.js +11 -0
- package/lib/utils/joinClasses.d.ts +1 -0
- package/lib/utils/joinClasses.js +7 -0
- package/lib/utils/setFloatingElemPosition.d.ts +1 -0
- package/lib/utils/setFloatingElemPosition.js +59 -0
- package/lib/utils/setFloatingElemPositionForLinkEditor.d.ts +1 -0
- package/lib/utils/setFloatingElemPositionForLinkEditor.js +36 -0
- package/lib/utils/swipe.d.ts +4 -0
- package/lib/utils/swipe.js +94 -0
- package/lib/utils/url.d.ts +2 -0
- package/lib/utils/url.js +31 -0
- package/package.json +1 -1
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) 2023-2025 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) 2023-2025 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,36 @@
|
|
|
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
|
+
private integrateMove;
|
|
23
|
+
private integrateDelete;
|
|
24
|
+
/**
|
|
25
|
+
* Topologically sort create operations so that parent nodes are created
|
|
26
|
+
* before their children.
|
|
27
|
+
*
|
|
28
|
+
* Computes depth using the `parent` field from the diff operations
|
|
29
|
+
* themselves rather than querying the Loro tree API (which may behave
|
|
30
|
+
* unexpectedly during event processing). For each create op, we count
|
|
31
|
+
* how many of its ancestors are also being created in this same batch.
|
|
32
|
+
* Ties at the same depth preserve the original diff order (stable sort).
|
|
33
|
+
*/
|
|
34
|
+
private topologicalSortCreates;
|
|
35
|
+
}
|
|
36
|
+
export {};
|
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) 2023-2025 Datalayer, Inc.
|
|
3
|
+
* Distributed under the terms of the MIT License.
|
|
4
|
+
*/
|
|
5
|
+
import { $getRoot, $getNodeByKey, $isElementNode } from 'lexical';
|
|
6
|
+
import { parseTreeID } from '../utils/Utils';
|
|
7
|
+
import { createLexicalNodeFromLoro } from '../nodes/NodeFactory';
|
|
8
|
+
/**
|
|
9
|
+
* Simplified tree diff integrater that trusts Loro's CRDT conflict resolution
|
|
10
|
+
* and applies operations directly without complex filtering or context classification
|
|
11
|
+
*/
|
|
12
|
+
export class TreeIntegrator {
|
|
13
|
+
integrate(diff, binding, provider) {
|
|
14
|
+
// Batch all changes in a single editor update
|
|
15
|
+
binding.editor.update(() => {
|
|
16
|
+
this.integrateInternal(diff, binding, provider);
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
// Internal method that can be called when already inside editor.update()
|
|
20
|
+
integrateInternal(diff, binding, provider) {
|
|
21
|
+
// Separate operations by action type
|
|
22
|
+
const deletes = [];
|
|
23
|
+
const creates = [];
|
|
24
|
+
const moves = [];
|
|
25
|
+
for (const op of diff.diff) {
|
|
26
|
+
switch (op.action) {
|
|
27
|
+
case 'delete':
|
|
28
|
+
deletes.push(op);
|
|
29
|
+
break;
|
|
30
|
+
case 'create':
|
|
31
|
+
creates.push(op);
|
|
32
|
+
break;
|
|
33
|
+
case 'move':
|
|
34
|
+
moves.push(op);
|
|
35
|
+
break;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
// Topologically sort create operations so parents are created before children.
|
|
39
|
+
// Without this, a TableCellNode may arrive before its parent TableRowNode,
|
|
40
|
+
// causing the cell to fall back to $getRoot() and appear on one flat line.
|
|
41
|
+
const sortedCreates = this.topologicalSortCreates(creates, binding);
|
|
42
|
+
// Execute: deletes β creates (parent-first) β moves
|
|
43
|
+
const operations = [...deletes, ...sortedCreates, ...moves];
|
|
44
|
+
operations.forEach(operation => {
|
|
45
|
+
switch (operation.action) {
|
|
46
|
+
case 'create':
|
|
47
|
+
this.integrateCreate(operation, binding, provider);
|
|
48
|
+
break;
|
|
49
|
+
case 'move':
|
|
50
|
+
this.integrateMove(operation, binding, provider);
|
|
51
|
+
break;
|
|
52
|
+
case 'delete':
|
|
53
|
+
this.integrateDelete(operation, binding, provider);
|
|
54
|
+
break;
|
|
55
|
+
default:
|
|
56
|
+
console.warn(`π³ Unknown tree operation: ${operation.action}`);
|
|
57
|
+
}
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
integrateCreate(operation, binding, provider) {
|
|
61
|
+
try {
|
|
62
|
+
let { nodeKey } = parseTreeID(operation.target);
|
|
63
|
+
// Skip root node creation - root is integrated during initial setup
|
|
64
|
+
// But ensure the root mapping exists
|
|
65
|
+
// Only treat as root if it's actually a root-type node in Loro
|
|
66
|
+
if (nodeKey === "0") {
|
|
67
|
+
const treeNode = binding.tree.getNodeByID(operation.target);
|
|
68
|
+
const elementType = treeNode?.data.get('elementType');
|
|
69
|
+
if (elementType === 'root' || !elementType) {
|
|
70
|
+
const root = $getRoot();
|
|
71
|
+
binding.nodeMapper.setMapping(root.getKey(), operation.target);
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
// If nodeKey is "0" but it's not actually a root element, continue with normal processing
|
|
75
|
+
}
|
|
76
|
+
// Check if node already exists and if it's the same TreeID
|
|
77
|
+
const existingNode = $getNodeByKey(nodeKey);
|
|
78
|
+
if (existingNode) {
|
|
79
|
+
const existingTreeID = binding.nodeMapper.getTreeIDByLexicalKey(nodeKey);
|
|
80
|
+
if (existingTreeID === operation.target) {
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
else {
|
|
84
|
+
// Don't reuse existing keys for different TreeIDs - let Lexical generate a fresh one
|
|
85
|
+
nodeKey = undefined; // Let createLexicalNodeFromLoro generate a fresh key
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
// Create Lexical node from Loro data
|
|
89
|
+
const lexicalNode = createLexicalNodeFromLoro(operation.target, binding.tree, binding);
|
|
90
|
+
if (!lexicalNode) {
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
// Find parent node
|
|
94
|
+
let parentNode;
|
|
95
|
+
if (operation.parent) {
|
|
96
|
+
const parentKey = binding.nodeMapper.getLexicalKeyByLoroId(operation.parent);
|
|
97
|
+
const parentLexicalNode = parentKey ? $getNodeByKey(parentKey) : null;
|
|
98
|
+
if (parentLexicalNode && $isElementNode(parentLexicalNode)) {
|
|
99
|
+
parentNode = parentLexicalNode;
|
|
100
|
+
}
|
|
101
|
+
else {
|
|
102
|
+
console.warn(`π³ Parent NOT found for ${lexicalNode.getType()} target=${operation.target} parent=${operation.parent} parentKey=${parentKey} parentFound=${!!parentLexicalNode} isElement=${parentLexicalNode ? $isElementNode(parentLexicalNode) : 'N/A'}`);
|
|
103
|
+
// For text nodes, we MUST have a proper parent element
|
|
104
|
+
if (lexicalNode.getType() === 'text') {
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
parentNode = $getRoot();
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
else {
|
|
111
|
+
parentNode = $getRoot();
|
|
112
|
+
}
|
|
113
|
+
// Normal insertion
|
|
114
|
+
if (operation.index !== undefined) {
|
|
115
|
+
parentNode.splice(operation.index, 0, [lexicalNode]);
|
|
116
|
+
}
|
|
117
|
+
else {
|
|
118
|
+
parentNode.append(lexicalNode);
|
|
119
|
+
}
|
|
120
|
+
// Set up mapping
|
|
121
|
+
binding.nodeMapper.setMapping(lexicalNode.getKey(), operation.target);
|
|
122
|
+
}
|
|
123
|
+
catch (error) {
|
|
124
|
+
console.warn(`π³ Error creating node for ${operation.target}:`, error);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
integrateMove(operation, binding, provider) {
|
|
128
|
+
try {
|
|
129
|
+
const lexicalKey = binding.nodeMapper.getLexicalKeyByLoroId(operation.target);
|
|
130
|
+
if (!lexicalKey) {
|
|
131
|
+
console.warn(`π³ No Lexical key found for move target ${operation.target}`);
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
134
|
+
const nodeToMove = $getNodeByKey(lexicalKey);
|
|
135
|
+
if (!nodeToMove) {
|
|
136
|
+
console.warn(`π³ Node to move not found: ${lexicalKey}`);
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
139
|
+
// Find new parent
|
|
140
|
+
let newParent;
|
|
141
|
+
if (operation.parent) {
|
|
142
|
+
const parentKey = binding.nodeMapper.getLexicalKeyByLoroId(operation.parent);
|
|
143
|
+
const parentNode = parentKey ? $getNodeByKey(parentKey) : null;
|
|
144
|
+
if (parentNode && $isElementNode(parentNode)) {
|
|
145
|
+
newParent = parentNode;
|
|
146
|
+
}
|
|
147
|
+
else {
|
|
148
|
+
// For text nodes, we can't move them to root - skip this move operation
|
|
149
|
+
// The node is already in the correct position from our create fix
|
|
150
|
+
if (nodeToMove.getType() === 'text') {
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
newParent = $getRoot();
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
else {
|
|
157
|
+
// For text nodes without a parent, skip the move
|
|
158
|
+
if (nodeToMove.getType() === 'text') {
|
|
159
|
+
return;
|
|
160
|
+
}
|
|
161
|
+
newParent = $getRoot();
|
|
162
|
+
}
|
|
163
|
+
// Remove from current position and insert at new position
|
|
164
|
+
nodeToMove.remove();
|
|
165
|
+
if (operation.index !== undefined) {
|
|
166
|
+
newParent.splice(operation.index, 0, [nodeToMove]);
|
|
167
|
+
}
|
|
168
|
+
else {
|
|
169
|
+
newParent.append(nodeToMove);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
catch (error) {
|
|
173
|
+
console.warn(`π³ Error moving node ${operation.target}:`, error);
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
integrateDelete(operation, binding, provider) {
|
|
177
|
+
try {
|
|
178
|
+
const lexicalKey = binding.nodeMapper.getLexicalKeyByLoroId(operation.target);
|
|
179
|
+
if (!lexicalKey) {
|
|
180
|
+
console.warn(`π³ No Lexical key found for delete target ${operation.target}`);
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
183
|
+
const nodeToDelete = $getNodeByKey(lexicalKey);
|
|
184
|
+
if (!nodeToDelete) {
|
|
185
|
+
console.warn(`π³ Node to delete not found: ${lexicalKey}`);
|
|
186
|
+
return;
|
|
187
|
+
}
|
|
188
|
+
// Remove from Lexical tree
|
|
189
|
+
nodeToDelete.remove();
|
|
190
|
+
// Clean up mapping only β do NOT call deleteMapping() here because
|
|
191
|
+
// the Loro tree has already processed this deletion from the remote
|
|
192
|
+
// peer. Calling tree.delete() again would throw "is deleted or does
|
|
193
|
+
// not exist".
|
|
194
|
+
binding.nodeMapper.removeMappingForKey(lexicalKey);
|
|
195
|
+
}
|
|
196
|
+
catch (error) {
|
|
197
|
+
console.warn(`π³ Error deleting node ${operation.target}:`, error);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
/**
|
|
201
|
+
* Topologically sort create operations so that parent nodes are created
|
|
202
|
+
* before their children.
|
|
203
|
+
*
|
|
204
|
+
* Computes depth using the `parent` field from the diff operations
|
|
205
|
+
* themselves rather than querying the Loro tree API (which may behave
|
|
206
|
+
* unexpectedly during event processing). For each create op, we count
|
|
207
|
+
* how many of its ancestors are also being created in this same batch.
|
|
208
|
+
* Ties at the same depth preserve the original diff order (stable sort).
|
|
209
|
+
*/
|
|
210
|
+
topologicalSortCreates(creates, binding) {
|
|
211
|
+
if (creates.length <= 1)
|
|
212
|
+
return creates;
|
|
213
|
+
// Build lookup: target β parent (only for operations in this batch)
|
|
214
|
+
const batchTargets = new Set(creates.map(op => String(op.target)));
|
|
215
|
+
const parentOf = new Map();
|
|
216
|
+
for (const op of creates) {
|
|
217
|
+
if (op.parent) {
|
|
218
|
+
parentOf.set(String(op.target), String(op.parent));
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
const depthCache = new Map();
|
|
222
|
+
const getDepth = (targetStr) => {
|
|
223
|
+
if (depthCache.has(targetStr))
|
|
224
|
+
return depthCache.get(targetStr);
|
|
225
|
+
let depth = 0;
|
|
226
|
+
let current = targetStr;
|
|
227
|
+
const visited = new Set();
|
|
228
|
+
// Walk up the parent chain; count only ancestors that are also being
|
|
229
|
+
// created in this batch (i.e. don't exist yet and must come first).
|
|
230
|
+
while (parentOf.has(current)) {
|
|
231
|
+
const parent = parentOf.get(current);
|
|
232
|
+
if (visited.has(parent))
|
|
233
|
+
break; // cycle guard
|
|
234
|
+
visited.add(parent);
|
|
235
|
+
if (batchTargets.has(parent)) {
|
|
236
|
+
depth++;
|
|
237
|
+
current = parent;
|
|
238
|
+
}
|
|
239
|
+
else {
|
|
240
|
+
break; // parent already exists locally β stop counting
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
depthCache.set(targetStr, depth);
|
|
244
|
+
return depth;
|
|
245
|
+
};
|
|
246
|
+
// Tag each operation with its original index (for stable tie-breaking)
|
|
247
|
+
const tagged = creates.map((op, i) => ({ op, depth: getDepth(String(op.target)), idx: i }));
|
|
248
|
+
tagged.sort((a, b) => a.depth - b.depth || a.idx - b.idx);
|
|
249
|
+
return tagged.map(t => t.op);
|
|
250
|
+
}
|
|
251
|
+
}
|
|
@@ -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;
|