@datalayer/lexical-loro 0.2.3 → 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,174 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) 2023-2025 Datalayer, Inc.
|
|
3
|
+
* Distributed under the terms of the MIT License.
|
|
4
|
+
*/
|
|
5
|
+
import { $getRoot } from 'lexical';
|
|
6
|
+
import { getNodeMapper } from '../nodes/NodesMapper';
|
|
7
|
+
/**
|
|
8
|
+
* Handle RootNode creation (typically only happens once during initialization)
|
|
9
|
+
*/
|
|
10
|
+
export function createRootNodeInLoro(nodeKey, lexicalNodeJSON, // JSON object from exportJSON()
|
|
11
|
+
options) {
|
|
12
|
+
const { tree, peerId } = options;
|
|
13
|
+
const mapper = getNodeMapper();
|
|
14
|
+
// Use mapper to get or create the tree node (don't pass lexicalNode to avoid context issues)
|
|
15
|
+
// Root node has no parent (undefined) and is always at index 0
|
|
16
|
+
const rootTreeNode = mapper.getLoroNodeByLexicalKey(nodeKey, undefined, // don't pass lexicalNode to avoid context issues
|
|
17
|
+
undefined, // no parent for root
|
|
18
|
+
0 // always at index 0
|
|
19
|
+
);
|
|
20
|
+
// Store complete lexical node data as clean JSON if provided
|
|
21
|
+
if (lexicalNodeJSON) {
|
|
22
|
+
try {
|
|
23
|
+
// Store complete lexical JSON without all key-related fields
|
|
24
|
+
if ('key' in lexicalNodeJSON || '__key' in lexicalNodeJSON || 'lexicalKey' in lexicalNodeJSON) {
|
|
25
|
+
const { key, __key, lexicalKey, children, ...cleanedData } = lexicalNodeJSON;
|
|
26
|
+
rootTreeNode.data.set('lexical', cleanedData);
|
|
27
|
+
}
|
|
28
|
+
else {
|
|
29
|
+
const { children, ...cleanedData } = lexicalNodeJSON;
|
|
30
|
+
rootTreeNode.data.set('lexical', cleanedData);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
catch (error) {
|
|
34
|
+
console.warn('Failed to store lexical node JSON for RootNode:', error);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
// Store only essential metadata
|
|
38
|
+
rootTreeNode.data.set('elementType', 'root');
|
|
39
|
+
rootTreeNode.data.set('createdAt', Date.now());
|
|
40
|
+
// The exported Lexical node data is already propagated by the mapper
|
|
41
|
+
// Return the TreeID from the node's ID
|
|
42
|
+
return rootTreeNode.id;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Handle RootNode updates (rarely needed since root doesn't change much)
|
|
46
|
+
*/
|
|
47
|
+
export function updateRootNodeInLoro(nodeKey, lexicalNodeJSON, // JSON object from exportJSON()
|
|
48
|
+
options) {
|
|
49
|
+
const mapper = getNodeMapper();
|
|
50
|
+
// Get the existing tree node using the mapper (don't pass lexicalNode to avoid context issues)
|
|
51
|
+
const treeNode = mapper.getLoroNodeByLexicalKey(nodeKey, undefined);
|
|
52
|
+
// Store complete lexical node data as clean JSON if provided
|
|
53
|
+
if (lexicalNodeJSON) {
|
|
54
|
+
try {
|
|
55
|
+
// Store complete lexical JSON without all key-related fields
|
|
56
|
+
if ('key' in lexicalNodeJSON || '__key' in lexicalNodeJSON || 'lexicalKey' in lexicalNodeJSON) {
|
|
57
|
+
const { key, __key, lexicalKey, children, ...cleanedData } = lexicalNodeJSON;
|
|
58
|
+
treeNode.data.set('lexical', cleanedData);
|
|
59
|
+
}
|
|
60
|
+
else {
|
|
61
|
+
const { children, ...cleanedData } = lexicalNodeJSON;
|
|
62
|
+
treeNode.data.set('lexical', cleanedData);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
catch (error) {
|
|
66
|
+
console.warn('Failed to store lexical node JSON for RootNode update:', error);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
// Update only essential metadata
|
|
70
|
+
treeNode.data.set('elementType', 'root');
|
|
71
|
+
treeNode.data.set('lastUpdated', Date.now());
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Handle RootNode deletion (should rarely happen, but included for completeness)
|
|
75
|
+
*/
|
|
76
|
+
export function deleteRootNodeInLoro(nodeKey, options) {
|
|
77
|
+
const mapper = getNodeMapper();
|
|
78
|
+
// Note: Deleting root node should be done with extreme caution
|
|
79
|
+
// as it represents the entire editor content
|
|
80
|
+
mapper.deleteMapping(nodeKey);
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Create RootNode in Lexical from Loro tree data
|
|
84
|
+
*/
|
|
85
|
+
export function createRootNodeFromLoro(treeId, options) {
|
|
86
|
+
// In Lexical, there's always exactly one root node
|
|
87
|
+
// This function would typically be called during initialization
|
|
88
|
+
const root = $getRoot();
|
|
89
|
+
// Root node already exists, just return it
|
|
90
|
+
return root;
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Update RootNode in Lexical from Loro tree data
|
|
94
|
+
*/
|
|
95
|
+
export function updateRootNodeFromLoro(treeId, options) {
|
|
96
|
+
// Root node updates are typically propagated at the document level
|
|
97
|
+
// Most changes to root would be indirect (children changes)
|
|
98
|
+
console.log('Root node update from Loro:', treeId);
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Delete RootNode in Lexical (should not happen in normal operation)
|
|
102
|
+
*/
|
|
103
|
+
export function deleteRootNodeFromLoro(treeId, options) {
|
|
104
|
+
// Root node deletion should not happen in normal circumstances
|
|
105
|
+
// This would essentially clear the entire editor
|
|
106
|
+
console.warn('Attempting to delete root node - this should not happen:', treeId);
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Utility to check if a tree node represents a RootNode
|
|
110
|
+
*/
|
|
111
|
+
export function isRootNodeInTree(treeId, tree) {
|
|
112
|
+
if (!tree.has(treeId)) {
|
|
113
|
+
return false;
|
|
114
|
+
}
|
|
115
|
+
const treeNode = tree.getNodeByID(treeId);
|
|
116
|
+
return treeNode?.data.get('nodeType') === 'root';
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Main propagate method for RootNode - propagates all mutation types
|
|
120
|
+
*/
|
|
121
|
+
export function propagateRootNode(update, mutation, nodeKey, options) {
|
|
122
|
+
const { tree, peerId } = options;
|
|
123
|
+
switch (mutation) {
|
|
124
|
+
case 'created': {
|
|
125
|
+
// Get the current editor state to find the root node
|
|
126
|
+
const currentNode = update.editorState._nodeMap.get(nodeKey);
|
|
127
|
+
if (currentNode) {
|
|
128
|
+
// Export node data as JSON object within editor context where node methods are available
|
|
129
|
+
let lexicalNodeJSON = undefined;
|
|
130
|
+
update.editorState.read(() => {
|
|
131
|
+
if (currentNode.getType() === 'root') {
|
|
132
|
+
try {
|
|
133
|
+
lexicalNodeJSON = currentNode.exportJSON();
|
|
134
|
+
}
|
|
135
|
+
catch (error) {
|
|
136
|
+
console.warn('Failed to export root node JSON:', error);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
});
|
|
140
|
+
if (lexicalNodeJSON) {
|
|
141
|
+
createRootNodeInLoro(nodeKey, lexicalNodeJSON, options);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
break;
|
|
145
|
+
}
|
|
146
|
+
case 'updated': {
|
|
147
|
+
// Root nodes typically don't change much, but we can update metadata
|
|
148
|
+
const currentNode = update.editorState._nodeMap.get(nodeKey);
|
|
149
|
+
if (currentNode) {
|
|
150
|
+
// Export node data as JSON object within editor context where node methods are available
|
|
151
|
+
let lexicalNodeJSON = undefined;
|
|
152
|
+
update.editorState.read(() => {
|
|
153
|
+
if (currentNode.getType() === 'root') {
|
|
154
|
+
try {
|
|
155
|
+
lexicalNodeJSON = currentNode.exportJSON();
|
|
156
|
+
}
|
|
157
|
+
catch (error) {
|
|
158
|
+
console.warn('Failed to export root node JSON for update:', error);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
});
|
|
162
|
+
if (lexicalNodeJSON) {
|
|
163
|
+
updateRootNodeInLoro(nodeKey, lexicalNodeJSON, options);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
break;
|
|
167
|
+
}
|
|
168
|
+
case 'destroyed': {
|
|
169
|
+
// Delete the root node from Loro tree
|
|
170
|
+
deleteRootNodeInLoro(nodeKey, options);
|
|
171
|
+
break;
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { TreeID, LoroTree } from 'loro-crdt';
|
|
2
|
+
import { TextNode, TextFormatType, UpdateListenerPayload, NodeKey, ElementNode } from 'lexical';
|
|
3
|
+
import { Binding } from '../Bindings';
|
|
4
|
+
/**
|
|
5
|
+
* TextNode Propagator for Loro Tree Collaboration
|
|
6
|
+
*
|
|
7
|
+
* TextNode characteristics:
|
|
8
|
+
* - Leaf nodes that represent text content
|
|
9
|
+
* - Can have formatting (bold, italic, underline, strikethrough, etc.)
|
|
10
|
+
* - Can have different modes: normal, token, segmented, inert
|
|
11
|
+
* - Cannot have children (always leaf nodes)
|
|
12
|
+
* - Support text content and format operations
|
|
13
|
+
*/
|
|
14
|
+
export interface TextNodeMutatorOptions {
|
|
15
|
+
binding: Binding;
|
|
16
|
+
tree: LoroTree;
|
|
17
|
+
peerId: number;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Create TextNode in Loro tree
|
|
21
|
+
*/
|
|
22
|
+
export declare function createTextNodeInLoro(nodeKey: NodeKey, textContent: string, format?: number, mode?: string, parentId?: TreeID, index?: number, lexicalNodeJSON?: any, // JSON object from exportJSON()
|
|
23
|
+
options?: TextNodeMutatorOptions): TreeID;
|
|
24
|
+
/**
|
|
25
|
+
* Update TextNode in Loro tree
|
|
26
|
+
*/
|
|
27
|
+
export declare function updateTextNodeInLoro(nodeKey: NodeKey, newTextContent?: string, format?: number, mode?: string, lexicalNodeJSON?: any, // JSON object from exportJSON()
|
|
28
|
+
options?: TextNodeMutatorOptions): void;
|
|
29
|
+
/**
|
|
30
|
+
* Delete TextNode from Loro tree
|
|
31
|
+
*/
|
|
32
|
+
export declare function deleteTextNodeInLoro(nodeKey: NodeKey, options: TextNodeMutatorOptions): void;
|
|
33
|
+
/**
|
|
34
|
+
* Create TextNode in Lexical from Loro tree data
|
|
35
|
+
*/
|
|
36
|
+
export declare function createTextNodeFromLoro(treeId: TreeID, parentNode: ElementNode, index?: number, options?: TextNodeMutatorOptions): TextNode | null;
|
|
37
|
+
/**
|
|
38
|
+
* Update TextNode in Lexical from Loro tree data
|
|
39
|
+
*/
|
|
40
|
+
export declare function updateTextNodeFromLoro(treeId: TreeID, textNode: TextNode, newParentNode?: ElementNode, newIndex?: number, options?: TextNodeMutatorOptions): void;
|
|
41
|
+
/**
|
|
42
|
+
* Delete TextNode from Lexical
|
|
43
|
+
*/
|
|
44
|
+
export declare function deleteTextNodeFromLoro(treeId: TreeID, lexicalNode: TextNode, options?: TextNodeMutatorOptions): void;
|
|
45
|
+
/**
|
|
46
|
+
* Utility to check if a tree node represents a TextNode
|
|
47
|
+
*/
|
|
48
|
+
export declare function isTextNodeInTree(treeId: TreeID, tree: LoroTree): boolean;
|
|
49
|
+
/**
|
|
50
|
+
* Get TextNode data from Loro tree
|
|
51
|
+
*/
|
|
52
|
+
export declare function getTextNodeDataFromTree(treeId: TreeID, tree: LoroTree): any;
|
|
53
|
+
/**
|
|
54
|
+
* Apply text formatting operations (bold, italic, etc.)
|
|
55
|
+
*/
|
|
56
|
+
export declare function applyTextFormatInLoro(nodeKey: NodeKey, formatType: TextFormatType, apply: boolean, options: TextNodeMutatorOptions): void;
|
|
57
|
+
/**
|
|
58
|
+
* Main propagate method for TextNode - propagates all mutation types
|
|
59
|
+
*/
|
|
60
|
+
export declare function propagateTextNode(update: UpdateListenerPayload, mutation: 'created' | 'updated' | 'destroyed', nodeKey: NodeKey, options: TextNodeMutatorOptions): void;
|
|
@@ -0,0 +1,440 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) 2023-2025 Datalayer, Inc.
|
|
3
|
+
* Distributed under the terms of the MIT License.
|
|
4
|
+
*/
|
|
5
|
+
import { $createTextNode, $isTextNode } from 'lexical';
|
|
6
|
+
import { getNodeMapper } from '../nodes/NodesMapper';
|
|
7
|
+
import { $diffTextContentAndApplyDelta } from '../utils/Utils';
|
|
8
|
+
/**
|
|
9
|
+
* Create TextNode in Loro tree
|
|
10
|
+
*/
|
|
11
|
+
export function createTextNodeInLoro(nodeKey, textContent, format, mode, parentId, index, lexicalNodeJSON, // JSON object from exportJSON()
|
|
12
|
+
options) {
|
|
13
|
+
const mapper = getNodeMapper();
|
|
14
|
+
// Debug logging for text node creation issues
|
|
15
|
+
if (!parentId) {
|
|
16
|
+
console.warn(`❌ Creating TextNode ${nodeKey} without parent in Loro tree - THIS WILL FAIL`);
|
|
17
|
+
return null; // Return early to avoid creating orphaned nodes
|
|
18
|
+
}
|
|
19
|
+
// Use mapper to get or create the tree node
|
|
20
|
+
// Note: We can't pass lexicalNode directly due to context issues, but parentId should be sufficient
|
|
21
|
+
const treeNode = mapper.getLoroNodeByLexicalKey(nodeKey, undefined, // don't pass lexicalNode to avoid context issues
|
|
22
|
+
parentId, index);
|
|
23
|
+
// Store complete lexical node data as clean JSON if provided
|
|
24
|
+
if (lexicalNodeJSON) {
|
|
25
|
+
try {
|
|
26
|
+
// Store complete lexical JSON without the key
|
|
27
|
+
if ('key' in lexicalNodeJSON || '__key' in lexicalNodeJSON || 'lexicalKey' in lexicalNodeJSON) {
|
|
28
|
+
const { key, __key, lexicalKey, children, ...cleanedData } = lexicalNodeJSON;
|
|
29
|
+
treeNode.data.set('lexical', cleanedData);
|
|
30
|
+
}
|
|
31
|
+
else {
|
|
32
|
+
const { children, ...cleanedData } = lexicalNodeJSON;
|
|
33
|
+
treeNode.data.set('lexical', cleanedData);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
catch (error) {
|
|
37
|
+
console.warn('Failed to store lexical node JSON for TextNode:', error);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
// Store only essential metadata (elementType for debug panel)
|
|
41
|
+
treeNode.data.set('elementType', 'text');
|
|
42
|
+
treeNode.data.set('createdAt', Date.now());
|
|
43
|
+
// Return the TreeID from the node's ID
|
|
44
|
+
return treeNode.id;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Update TextNode in Loro tree
|
|
48
|
+
*/
|
|
49
|
+
export function updateTextNodeInLoro(nodeKey, newTextContent, format, mode, lexicalNodeJSON, // JSON object from exportJSON()
|
|
50
|
+
options) {
|
|
51
|
+
const mapper = getNodeMapper();
|
|
52
|
+
// Get the existing tree node using the mapper
|
|
53
|
+
const treeNode = mapper.getLoroNodeByLexicalKey(nodeKey, undefined);
|
|
54
|
+
if (!treeNode) {
|
|
55
|
+
console.warn(`📝 TextNode ${nodeKey} not found in Loro, skipping update`);
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
// Note: Container validation is done in each try-catch block below since
|
|
59
|
+
// the container can be deleted between operations
|
|
60
|
+
// Store complete lexical node data as clean JSON if provided
|
|
61
|
+
if (lexicalNodeJSON) {
|
|
62
|
+
try {
|
|
63
|
+
// Store complete lexical JSON without the key
|
|
64
|
+
if ('key' in lexicalNodeJSON || '__key' in lexicalNodeJSON || 'lexicalKey' in lexicalNodeJSON) {
|
|
65
|
+
const { key, __key, lexicalKey, children, ...cleanedData } = lexicalNodeJSON;
|
|
66
|
+
treeNode.data.set('lexical', cleanedData);
|
|
67
|
+
}
|
|
68
|
+
else {
|
|
69
|
+
const { children, ...cleanedData } = lexicalNodeJSON;
|
|
70
|
+
treeNode.data.set('lexical', cleanedData);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
catch (error) {
|
|
74
|
+
// This is expected during text operations when nodes get deleted/recreated
|
|
75
|
+
console.warn(`📝 TextNode ${nodeKey} container was deleted during update, skipping (normal during text operations):`, error.message);
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
// Update only essential metadata
|
|
80
|
+
try {
|
|
81
|
+
treeNode.data.set('elementType', 'text');
|
|
82
|
+
treeNode.data.set('updatedAt', Date.now());
|
|
83
|
+
}
|
|
84
|
+
catch (error) {
|
|
85
|
+
console.warn(`📝 TextNode ${nodeKey} container deleted during metadata update (normal during text operations):`, error.message);
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
// The exported Lexical node data is already propagated by the mapper
|
|
89
|
+
// No additional JSON export needed since mapper propagates exportJSON automatically
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Delete TextNode from Loro tree
|
|
93
|
+
*/
|
|
94
|
+
export function deleteTextNodeInLoro(nodeKey, options) {
|
|
95
|
+
const mapper = getNodeMapper();
|
|
96
|
+
mapper.deleteMapping(nodeKey);
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Create TextNode in Lexical from Loro tree data
|
|
100
|
+
*/
|
|
101
|
+
export function createTextNodeFromLoro(treeId, parentNode, index, options) {
|
|
102
|
+
const { tree } = options;
|
|
103
|
+
if (!tree.has(treeId)) {
|
|
104
|
+
return null;
|
|
105
|
+
}
|
|
106
|
+
const treeNode = tree.getNodeByID(treeId);
|
|
107
|
+
if (!treeNode) {
|
|
108
|
+
return null;
|
|
109
|
+
}
|
|
110
|
+
// Get LexicalNodeData (JSON object format only)
|
|
111
|
+
const lexicalData = treeNode.data.get('lexical');
|
|
112
|
+
let textNode;
|
|
113
|
+
if (lexicalData && typeof lexicalData === 'object') {
|
|
114
|
+
try {
|
|
115
|
+
// lexicalData is a direct JSON object, use it to create a TextNode
|
|
116
|
+
const lexicalDataObj = lexicalData;
|
|
117
|
+
const textContent = lexicalDataObj.text || lexicalDataObj.__text || '';
|
|
118
|
+
const format = lexicalDataObj.format || lexicalDataObj.__format || 0;
|
|
119
|
+
const mode = lexicalDataObj.mode || lexicalDataObj.__mode || 0;
|
|
120
|
+
textNode = $createTextNode(textContent);
|
|
121
|
+
textNode.setFormat(format);
|
|
122
|
+
textNode.setMode(mode);
|
|
123
|
+
}
|
|
124
|
+
catch (error) {
|
|
125
|
+
console.warn('Failed to create TextNode from JSON data for TreeID:', treeId, error);
|
|
126
|
+
return null;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
else {
|
|
130
|
+
// No lexical JSON data found - cannot create TextNode
|
|
131
|
+
console.warn('No lexical JSON data found for TextNode TreeID:', treeId);
|
|
132
|
+
return null;
|
|
133
|
+
}
|
|
134
|
+
// Apply mode if present (only for old format)
|
|
135
|
+
if (!lexicalData || typeof lexicalData !== 'string') {
|
|
136
|
+
// const mode = treeNode.data.get('mode');
|
|
137
|
+
// if (mode && typeof textNode.setMode === 'function') {
|
|
138
|
+
// textNode.setMode(mode);
|
|
139
|
+
// }
|
|
140
|
+
}
|
|
141
|
+
// Insert into the parent at the specified index
|
|
142
|
+
if (index !== undefined && index >= 0) {
|
|
143
|
+
parentNode.splice(index, 0, [textNode]);
|
|
144
|
+
}
|
|
145
|
+
else {
|
|
146
|
+
parentNode.append(textNode);
|
|
147
|
+
}
|
|
148
|
+
return textNode;
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* Update TextNode in Lexical from Loro tree data
|
|
152
|
+
*/
|
|
153
|
+
export function updateTextNodeFromLoro(treeId, textNode, newParentNode, newIndex, options) {
|
|
154
|
+
const { tree } = options;
|
|
155
|
+
if (!tree.has(treeId)) {
|
|
156
|
+
return;
|
|
157
|
+
}
|
|
158
|
+
const treeNode = tree.getNodeByID(treeId);
|
|
159
|
+
if (!treeNode || treeNode.data.get('nodeType') !== 'text') {
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
162
|
+
// Update text content if it has changed
|
|
163
|
+
const textContent = treeNode.data.get('textContent');
|
|
164
|
+
if (textContent !== undefined && typeof textContent === 'string' &&
|
|
165
|
+
textNode.getTextContent() !== textContent) {
|
|
166
|
+
const currentText = textNode.getTextContent();
|
|
167
|
+
$diffTextContentAndApplyDelta(textNode, textNode.getKey(), currentText, textContent);
|
|
168
|
+
}
|
|
169
|
+
// Update format if it has changed
|
|
170
|
+
const format = treeNode.data.get('format');
|
|
171
|
+
if (format !== undefined && typeof format === 'number') {
|
|
172
|
+
textNode.setFormat(format);
|
|
173
|
+
}
|
|
174
|
+
// Update mode if it has changed (skip for now due to type complexity)
|
|
175
|
+
// const mode = treeNode.data.get('mode');
|
|
176
|
+
// if (mode !== undefined && typeof lexicalNode.setMode === 'function') {
|
|
177
|
+
// lexicalNode.setMode(mode);
|
|
178
|
+
// }
|
|
179
|
+
// If parent or position changed, move the node
|
|
180
|
+
if (newParentNode && newIndex !== undefined) {
|
|
181
|
+
// Remove from current location
|
|
182
|
+
textNode.remove();
|
|
183
|
+
// Insert at new location
|
|
184
|
+
newParentNode.splice(newIndex, 0, [textNode]);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
/**
|
|
188
|
+
* Delete TextNode from Lexical
|
|
189
|
+
*/
|
|
190
|
+
export function deleteTextNodeFromLoro(treeId, lexicalNode, options) {
|
|
191
|
+
if ($isTextNode(lexicalNode)) {
|
|
192
|
+
lexicalNode.remove();
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
/**
|
|
196
|
+
* Utility to check if a tree node represents a TextNode
|
|
197
|
+
*/
|
|
198
|
+
export function isTextNodeInTree(treeId, tree) {
|
|
199
|
+
if (!tree.has(treeId)) {
|
|
200
|
+
return false;
|
|
201
|
+
}
|
|
202
|
+
const treeNode = tree.getNodeByID(treeId);
|
|
203
|
+
return treeNode?.data.get('nodeType') === 'text';
|
|
204
|
+
}
|
|
205
|
+
/**
|
|
206
|
+
* Get TextNode data from Loro tree
|
|
207
|
+
*/
|
|
208
|
+
export function getTextNodeDataFromTree(treeId, tree) {
|
|
209
|
+
if (!tree.has(treeId)) {
|
|
210
|
+
return null;
|
|
211
|
+
}
|
|
212
|
+
const treeNode = tree.getNodeByID(treeId);
|
|
213
|
+
if (!treeNode || treeNode.data.get('nodeType') !== 'text') {
|
|
214
|
+
return null;
|
|
215
|
+
}
|
|
216
|
+
return {
|
|
217
|
+
nodeType: 'text',
|
|
218
|
+
textContent: treeNode.data.get('textContent'),
|
|
219
|
+
format: treeNode.data.get('format'),
|
|
220
|
+
mode: treeNode.data.get('mode'),
|
|
221
|
+
createdAt: treeNode.data.get('createdAt'),
|
|
222
|
+
lastUpdated: treeNode.data.get('lastUpdated'),
|
|
223
|
+
};
|
|
224
|
+
}
|
|
225
|
+
/**
|
|
226
|
+
* Apply text formatting operations (bold, italic, etc.)
|
|
227
|
+
*/
|
|
228
|
+
export function applyTextFormatInLoro(nodeKey, formatType, apply, options) {
|
|
229
|
+
const mapper = getNodeMapper();
|
|
230
|
+
// Get the existing Loro node from the mapper
|
|
231
|
+
const treeNode = mapper.getLoroNodeByLexicalKey(nodeKey);
|
|
232
|
+
if (!treeNode) {
|
|
233
|
+
return;
|
|
234
|
+
}
|
|
235
|
+
if (!treeNode || treeNode.data.get('nodeType') !== 'text') {
|
|
236
|
+
return;
|
|
237
|
+
}
|
|
238
|
+
// Check if the TreeNode's container is still valid
|
|
239
|
+
try {
|
|
240
|
+
// Try a simple read operation to verify the container is accessible
|
|
241
|
+
treeNode.data.get('format');
|
|
242
|
+
}
|
|
243
|
+
catch (error) {
|
|
244
|
+
console.warn(`📝 TextNode ${nodeKey} container deleted during format check (normal during text operations):`, error.message);
|
|
245
|
+
return;
|
|
246
|
+
}
|
|
247
|
+
let currentFormat = treeNode.data.get('format') || 0;
|
|
248
|
+
const formatNumber = formatType;
|
|
249
|
+
if (apply) {
|
|
250
|
+
// Add the format flag
|
|
251
|
+
currentFormat = currentFormat | formatNumber;
|
|
252
|
+
}
|
|
253
|
+
else {
|
|
254
|
+
// Remove the format flag
|
|
255
|
+
currentFormat = currentFormat & ~formatNumber;
|
|
256
|
+
}
|
|
257
|
+
try {
|
|
258
|
+
treeNode.data.set('format', currentFormat);
|
|
259
|
+
treeNode.data.set('lastUpdated', Date.now());
|
|
260
|
+
}
|
|
261
|
+
catch (error) {
|
|
262
|
+
console.warn(`📝 TextNode ${nodeKey} container deleted during format update (normal during text operations):`, error.message);
|
|
263
|
+
return;
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
/**
|
|
267
|
+
* Main propagate method for TextNode - propagates all mutation types
|
|
268
|
+
*/
|
|
269
|
+
export function propagateTextNode(update, mutation, nodeKey, options) {
|
|
270
|
+
const { tree, peerId } = options;
|
|
271
|
+
switch (mutation) {
|
|
272
|
+
case 'created': {
|
|
273
|
+
const currentNode = update.editorState._nodeMap.get(nodeKey);
|
|
274
|
+
// Check if this node already exists in Loro
|
|
275
|
+
const mapper = getNodeMapper();
|
|
276
|
+
const existingTreeID = mapper.getTreeIDByLexicalKey(nodeKey);
|
|
277
|
+
if (existingTreeID && currentNode && $isTextNode(currentNode)) {
|
|
278
|
+
// Check if the existing text node has the correct parent relationship
|
|
279
|
+
const { currentParentId, expectedParentId } = update.editorState.read(() => {
|
|
280
|
+
const parent = currentNode.getParent();
|
|
281
|
+
const expectedParentId = parent ? mapper.getTreeIDByLexicalKey(parent.getKey()) : undefined;
|
|
282
|
+
// Get the current parent from Loro tree
|
|
283
|
+
let currentParentId;
|
|
284
|
+
try {
|
|
285
|
+
const treeNode = tree.getNodeByID(existingTreeID);
|
|
286
|
+
if (treeNode) {
|
|
287
|
+
const parentNode = treeNode.parent();
|
|
288
|
+
currentParentId = parentNode ? parentNode.id.toString() : undefined;
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
catch (error) {
|
|
292
|
+
console.warn(`📝 Failed to get parent for existing TreeID ${existingTreeID}:`, error);
|
|
293
|
+
}
|
|
294
|
+
return { currentParentId, expectedParentId };
|
|
295
|
+
});
|
|
296
|
+
if (currentParentId === expectedParentId) {
|
|
297
|
+
return; // Skip creation since the parent relationship is correct
|
|
298
|
+
}
|
|
299
|
+
else {
|
|
300
|
+
// Get the actual TreeNode and its ID before deleting
|
|
301
|
+
let actualTreeID = existingTreeID;
|
|
302
|
+
try {
|
|
303
|
+
const treeNode = tree.getNodeByID(existingTreeID);
|
|
304
|
+
if (treeNode) {
|
|
305
|
+
actualTreeID = treeNode.id;
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
catch (error) {
|
|
309
|
+
console.warn(`📝 Could not get TreeNode for ${existingTreeID} during creation:`, error);
|
|
310
|
+
}
|
|
311
|
+
// Clear the old mapping first to avoid conflicts
|
|
312
|
+
mapper.deleteMapping(nodeKey);
|
|
313
|
+
// Then delete the TreeNode from Loro tree
|
|
314
|
+
try {
|
|
315
|
+
if (tree.has(actualTreeID)) {
|
|
316
|
+
tree.delete(actualTreeID);
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
catch (error) {
|
|
320
|
+
console.warn(`📝 Failed to delete TreeNode ${actualTreeID} during creation:`, error);
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
if (currentNode && $isTextNode(currentNode)) {
|
|
325
|
+
// Get parent, positioning, content, and serialized data using editor state context
|
|
326
|
+
const { parent, parentId, index, textContent, format, mode, lexicalNodeJSON } = update.editorState.read(() => {
|
|
327
|
+
const parent = currentNode.getParent();
|
|
328
|
+
// Get parentId from the mapper instead of constructing it manually
|
|
329
|
+
const mapper = getNodeMapper();
|
|
330
|
+
const parentId = parent ? mapper.getTreeIDByLexicalKey(parent.getKey()) : undefined;
|
|
331
|
+
const index = currentNode.getIndexWithinParent();
|
|
332
|
+
const textContent = currentNode.getTextContent();
|
|
333
|
+
const format = currentNode.getFormat();
|
|
334
|
+
const mode = currentNode.getMode();
|
|
335
|
+
// Export node data as JSON object within editor context where node methods are available
|
|
336
|
+
let lexicalNodeJSON = undefined;
|
|
337
|
+
try {
|
|
338
|
+
lexicalNodeJSON = currentNode.exportJSON();
|
|
339
|
+
}
|
|
340
|
+
catch (error) {
|
|
341
|
+
console.warn('Failed to export node JSON in propagateTextNode created:', error);
|
|
342
|
+
}
|
|
343
|
+
return { parent, parentId, index, textContent, format, mode, lexicalNodeJSON };
|
|
344
|
+
});
|
|
345
|
+
createTextNodeInLoro(nodeKey, textContent, format, mode, parentId, index, lexicalNodeJSON, options);
|
|
346
|
+
}
|
|
347
|
+
break;
|
|
348
|
+
}
|
|
349
|
+
case 'updated': {
|
|
350
|
+
const currentNode = update.editorState._nodeMap.get(nodeKey);
|
|
351
|
+
if (currentNode && $isTextNode(currentNode)) {
|
|
352
|
+
// First, check if this TextNode's parent has changed (like during double Enter)
|
|
353
|
+
const mapper = getNodeMapper();
|
|
354
|
+
const existingTreeID = mapper.getTreeIDByLexicalKey(nodeKey);
|
|
355
|
+
if (existingTreeID) {
|
|
356
|
+
const { currentParentId, expectedParentId, parent } = update.editorState.read(() => {
|
|
357
|
+
const parent = currentNode.getParent();
|
|
358
|
+
const expectedParentId = parent ? mapper.getTreeIDByLexicalKey(parent.getKey()) : undefined;
|
|
359
|
+
// Get the current parent from Loro tree
|
|
360
|
+
let currentParentId;
|
|
361
|
+
try {
|
|
362
|
+
const treeNode = tree.getNodeByID(existingTreeID);
|
|
363
|
+
if (treeNode) {
|
|
364
|
+
const parentNode = treeNode.parent();
|
|
365
|
+
currentParentId = parentNode ? parentNode.id.toString() : undefined;
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
catch (error) {
|
|
369
|
+
console.warn(`📝 Failed to get parent for existing TreeID ${existingTreeID} during update:`, error);
|
|
370
|
+
}
|
|
371
|
+
return { currentParentId, expectedParentId, parent };
|
|
372
|
+
});
|
|
373
|
+
if (currentParentId !== expectedParentId) {
|
|
374
|
+
// Get the actual TreeNode and its ID before deleting
|
|
375
|
+
let actualTreeID = existingTreeID;
|
|
376
|
+
try {
|
|
377
|
+
const treeNode = tree.getNodeByID(existingTreeID);
|
|
378
|
+
if (treeNode) {
|
|
379
|
+
actualTreeID = treeNode.id;
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
catch (error) {
|
|
383
|
+
console.warn(`📝 Could not get TreeNode for ${existingTreeID}:`, error);
|
|
384
|
+
}
|
|
385
|
+
// Clear the old mapping first to avoid conflicts
|
|
386
|
+
mapper.deleteMapping(nodeKey);
|
|
387
|
+
// Then delete the TreeNode from Loro tree
|
|
388
|
+
try {
|
|
389
|
+
if (tree.has(actualTreeID)) {
|
|
390
|
+
tree.delete(actualTreeID);
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
catch (error) {
|
|
394
|
+
console.warn(`📝 Failed to delete TreeNode ${actualTreeID} during update:`, error);
|
|
395
|
+
}
|
|
396
|
+
// Now recreate the TextNode with the new parent (treat as "created")
|
|
397
|
+
const { parentId, index, textContent, format, mode, lexicalNodeJSON } = update.editorState.read(() => {
|
|
398
|
+
const parentId = parent ? mapper.getTreeIDByLexicalKey(parent.getKey()) : undefined;
|
|
399
|
+
const index = currentNode.getIndexWithinParent();
|
|
400
|
+
const textContent = currentNode.getTextContent();
|
|
401
|
+
const format = currentNode.getFormat();
|
|
402
|
+
const mode = currentNode.getMode();
|
|
403
|
+
let lexicalNodeJSON = undefined;
|
|
404
|
+
try {
|
|
405
|
+
lexicalNodeJSON = currentNode.exportJSON();
|
|
406
|
+
}
|
|
407
|
+
catch (error) {
|
|
408
|
+
console.warn('Failed to export node JSON during TextNode recreation:', error);
|
|
409
|
+
}
|
|
410
|
+
return { parentId, index, textContent, format, mode, lexicalNodeJSON };
|
|
411
|
+
});
|
|
412
|
+
createTextNodeInLoro(nodeKey, textContent, format, mode, parentId, index, lexicalNodeJSON, options);
|
|
413
|
+
return; // Exit early since we recreated the node
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
// Normal update case - parent hasn't changed
|
|
417
|
+
const { textContent, format, mode, lexicalNodeJSON } = update.editorState.read(() => {
|
|
418
|
+
const textContent = currentNode.getTextContent();
|
|
419
|
+
const format = currentNode.getFormat();
|
|
420
|
+
const mode = currentNode.getMode();
|
|
421
|
+
// Export node data as JSON object within editor context where node methods are available
|
|
422
|
+
let lexicalNodeJSON = undefined;
|
|
423
|
+
try {
|
|
424
|
+
lexicalNodeJSON = currentNode.exportJSON();
|
|
425
|
+
}
|
|
426
|
+
catch (error) {
|
|
427
|
+
console.warn('Failed to export node JSON in propagateTextNode updated:', error);
|
|
428
|
+
}
|
|
429
|
+
return { textContent, format, mode, lexicalNodeJSON };
|
|
430
|
+
});
|
|
431
|
+
updateTextNodeInLoro(nodeKey, textContent, format, mode, lexicalNodeJSON, options);
|
|
432
|
+
}
|
|
433
|
+
break;
|
|
434
|
+
}
|
|
435
|
+
case 'destroyed': {
|
|
436
|
+
deleteTextNodeInLoro(nodeKey, options);
|
|
437
|
+
break;
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
}
|