@datalayer/lexical-loro 0.0.7 → 0.1.0
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/README.md +24 -137
- package/lib/App.d.ts +2 -0
- package/lib/App.js +141 -0
- package/lib/Editor.d.ts +2 -0
- package/lib/Editor.js +111 -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 +44 -0
- package/lib/collab/loro/Bindings.d.ts +41 -0
- package/lib/collab/loro/Bindings.js +95 -0
- package/lib/collab/loro/Debug.d.ts +33 -0
- package/lib/collab/loro/Debug.js +448 -0
- package/lib/collab/loro/LexicalCollaborationContext.d.ts +19 -0
- package/lib/collab/loro/LexicalCollaborationContext.js +48 -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 +90 -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 +97 -0
- package/lib/collab/loro/components/index.d.ts +2 -0
- package/lib/collab/loro/components/index.js +2 -0
- package/lib/collab/loro/index.d.ts +6 -0
- package/lib/collab/loro/index.js +6 -0
- package/lib/collab/loro/integrators/BaseIntegrator.d.ts +14 -0
- package/lib/collab/loro/integrators/BaseIntegrator.js +1 -0
- package/lib/collab/loro/integrators/CounterIntegrator.d.ts +23 -0
- package/lib/collab/loro/integrators/CounterIntegrator.js +40 -0
- package/lib/collab/loro/integrators/ListIntegrator.d.ts +23 -0
- package/lib/collab/loro/integrators/ListIntegrator.js +49 -0
- package/lib/collab/loro/integrators/MapIntegrator.d.ts +24 -0
- package/lib/collab/loro/integrators/MapIntegrator.js +177 -0
- package/lib/collab/loro/integrators/TextIntegrator.d.ts +25 -0
- package/lib/collab/loro/integrators/TextIntegrator.js +51 -0
- package/lib/collab/loro/integrators/TreeIntegrator.d.ts +25 -0
- package/lib/collab/loro/integrators/TreeIntegrator.js +201 -0
- package/lib/collab/loro/nodes/NodeFactory.d.ts +8 -0
- package/lib/collab/loro/nodes/NodeFactory.js +105 -0
- package/lib/collab/loro/nodes/NodesMapper.d.ts +111 -0
- package/lib/collab/loro/nodes/NodesMapper.js +258 -0
- package/lib/collab/loro/propagators/DecoratorNodePropagator.d.ts +60 -0
- package/lib/collab/loro/propagators/DecoratorNodePropagator.js +302 -0
- package/lib/collab/loro/propagators/ElementNodePropagator.d.ts +62 -0
- package/lib/collab/loro/propagators/ElementNodePropagator.js +335 -0
- package/lib/collab/loro/propagators/LineBreakNodePropagator.d.ts +57 -0
- package/lib/collab/loro/propagators/LineBreakNodePropagator.js +196 -0
- package/lib/collab/loro/propagators/RootNodePropagator.d.ts +55 -0
- package/lib/collab/loro/propagators/RootNodePropagator.js +168 -0
- package/lib/collab/loro/propagators/TextNodePropagator.d.ts +60 -0
- package/lib/collab/loro/propagators/TextNodePropagator.js +434 -0
- package/lib/collab/loro/propagators/index.d.ts +49 -0
- package/lib/collab/loro/propagators/index.js +32 -0
- package/lib/collab/loro/provider/websocket.d.ts +116 -0
- package/lib/collab/loro/provider/websocket.js +907 -0
- package/lib/collab/loro/servers/index.d.ts +0 -0
- package/lib/collab/loro/servers/index.js +0 -0
- package/lib/collab/loro/servers/ws/callback.d.ts +5 -0
- package/lib/collab/loro/servers/ws/callback.js +85 -0
- package/lib/collab/loro/servers/ws/server.d.ts +2 -0
- package/lib/collab/loro/servers/ws/server.js +25 -0
- package/lib/collab/loro/servers/ws/utils.d.ts +40 -0
- package/lib/collab/loro/servers/ws/utils.js +513 -0
- package/lib/collab/loro/sync/SyncCursors.d.ts +32 -0
- package/lib/collab/loro/sync/SyncCursors.js +435 -0
- package/lib/collab/loro/sync/SyncLexicalToLoro.d.ts +4 -0
- package/lib/collab/loro/sync/SyncLexicalToLoro.js +80 -0
- package/lib/collab/loro/sync/SyncLoroToLexical.d.ts +5 -0
- package/lib/collab/loro/sync/SyncLoroToLexical.js +96 -0
- package/lib/collab/loro/types/LexicalNodeData.d.ts +32 -0
- package/lib/collab/loro/types/LexicalNodeData.js +71 -0
- package/lib/collab/loro/useCollaboration.d.ts +12 -0
- package/lib/collab/loro/useCollaboration.js +248 -0
- package/lib/collab/loro/utils/InitialContent.d.ts +64 -0
- package/lib/collab/loro/utils/InitialContent.js +109 -0
- package/lib/collab/loro/utils/LexicalToLoro.d.ts +18 -0
- package/lib/collab/loro/utils/LexicalToLoro.js +96 -0
- package/lib/collab/loro/utils/Utils.d.ts +44 -0
- package/lib/collab/loro/utils/Utils.js +153 -0
- package/lib/collab/loro/wsProvider.d.ts +8 -0
- package/lib/collab/loro/wsProvider.js +31 -0
- package/lib/collab/utils/invariant.d.ts +1 -0
- package/lib/collab/utils/invariant.js +11 -0
- package/lib/collab/utils/simpleDiffWithCursor.d.ts +5 -0
- package/lib/collab/utils/simpleDiffWithCursor.js +31 -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 +324 -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 +41 -0
- package/lib/hooks/useFlashMessage.d.ts +2 -0
- package/lib/hooks/useFlashMessage.js +4 -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 +46 -0
- package/lib/index.d.ts +1 -1
- package/lib/index.js +1 -5
- package/lib/nodes/AutocompleteNode.d.ts +27 -0
- package/lib/nodes/AutocompleteNode.js +56 -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 +50 -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 +33 -0
- package/lib/nodes/LayoutContainerNode.d.ts +24 -0
- package/lib/nodes/LayoutContainerNode.js +91 -0
- package/lib/nodes/LayoutItemNode.d.ts +16 -0
- package/lib/nodes/LayoutItemNode.js +65 -0
- package/lib/nodes/MentionNode.d.ts +20 -0
- package/lib/nodes/MentionNode.js +81 -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 +71 -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 +50 -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 +2473 -0
- package/lib/plugins/CodeActionMenuPlugin/components/CopyButton/index.d.ts +7 -0
- package/lib/plugins/CodeActionMenuPlugin/components/CopyButton/index.js +42 -0
- package/lib/plugins/CodeActionMenuPlugin/components/PrettierButton/index.d.ts +17 -0
- package/lib/plugins/CodeActionMenuPlugin/components/PrettierButton/index.js +111 -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 +18 -0
- package/lib/plugins/CodeHighlightPrismPlugin/index.d.ts +2 -0
- package/lib/plugins/CodeHighlightPrismPlugin/index.js +10 -0
- package/lib/plugins/CodeHighlightShikiPlugin/index.d.ts +2 -0
- package/lib/plugins/CodeHighlightShikiPlugin/index.js +10 -0
- package/lib/plugins/CollapsiblePlugin/CollapsibleContainerNode.d.ts +25 -0
- package/lib/plugins/CollapsiblePlugin/CollapsibleContainerNode.js +131 -0
- package/lib/plugins/CollapsiblePlugin/CollapsibleContentNode.d.ts +16 -0
- package/lib/plugins/CollapsiblePlugin/CollapsibleContentNode.js +79 -0
- package/lib/plugins/CollapsiblePlugin/CollapsibleTitleNode.d.ts +16 -0
- package/lib/plugins/CollapsiblePlugin/CollapsibleTitleNode.js +81 -0
- package/lib/plugins/CollapsiblePlugin/CollapsibleUtils.d.ts +2 -0
- package/lib/plugins/CollapsiblePlugin/CollapsibleUtils.js +8 -0
- package/lib/plugins/CollapsiblePlugin/index.d.ts +3 -0
- package/lib/plugins/CollapsiblePlugin/index.js +128 -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 +20 -0
- package/lib/plugins/DatalayerPlugin/index.d.ts +2 -0
- package/lib/plugins/DatalayerPlugin/index.js +218 -0
- package/lib/plugins/DateTimePlugin/index.d.ts +8 -0
- package/lib/plugins/DateTimePlugin/index.js +24 -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 +33 -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 +80 -0
- package/lib/plugins/EmojisPlugin/index.d.ts +2 -0
- package/lib/plugins/EmojisPlugin/index.js +52 -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 +20 -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 +31 -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 +131 -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 +234 -0
- package/lib/plugins/MaxLengthPlugin/index.d.ts +3 -0
- package/lib/plugins/MaxLengthPlugin/index.js +37 -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 +27 -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 +112 -0
- package/lib/plugins/ShortcutsPlugin/shortcuts.d.ts +59 -0
- package/lib/plugins/ShortcutsPlugin/shortcuts.js +169 -0
- package/lib/plugins/SpecialTextPlugin/index.d.ts +2 -0
- package/lib/plugins/SpecialTextPlugin/index.js +46 -0
- package/lib/plugins/SpeechToTextPlugin/index.d.ts +5 -0
- package/lib/plugins/SpeechToTextPlugin/index.js +82 -0
- package/lib/plugins/StickyPlugin/index.d.ts +2 -0
- package/lib/plugins/StickyPlugin/index.js +12 -0
- package/lib/plugins/TabFocusPlugin/index.d.ts +1 -0
- package/lib/plugins/TabFocusPlugin/index.js +34 -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 +80 -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 +243 -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 +20 -0
- package/lib/plugins/TypingPerfPlugin/index.d.ts +2 -0
- package/lib/plugins/TypingPerfPlugin/index.js +93 -0
- package/lib/plugins/YouTubePlugin/index.d.ts +4 -0
- package/lib/plugins/YouTubePlugin/index.js +20 -0
- package/lib/server/validation.d.ts +1 -0
- package/lib/server/validation.js +111 -0
- package/lib/setupEnv.d.ts +2 -0
- package/lib/setupEnv.js +25 -0
- package/lib/themes/CommentEditorTheme.d.ts +4 -0
- package/lib/themes/CommentEditorTheme.js +7 -0
- package/lib/themes/PlaygroundEditorTheme.d.ts +4 -0
- package/lib/themes/PlaygroundEditorTheme.js +120 -0
- package/lib/themes/StickyEditorTheme.d.ts +4 -0
- package/lib/themes/StickyEditorTheme.js +7 -0
- package/lib/tyes.dt.d.ts +12 -0
- package/lib/tyes.dt.js +0 -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 +56 -0
- package/lib/utils/emoji-list.d.ts +20 -0
- package/lib/utils/emoji-list.js +16605 -0
- package/lib/utils/getDOMRangeRect.d.ts +8 -0
- package/lib/utils/getDOMRangeRect.js +22 -0
- package/lib/utils/getSelectedNode.d.ts +2 -0
- package/lib/utils/getSelectedNode.js +24 -0
- package/lib/utils/getThemeSelector.d.ts +2 -0
- package/lib/utils/getThemeSelector.js +10 -0
- package/lib/utils/isMobileWidth.d.ts +7 -0
- package/lib/utils/isMobileWidth.js +7 -0
- package/lib/utils/joinClasses.d.ts +1 -0
- package/lib/utils/joinClasses.js +3 -0
- package/lib/utils/setFloatingElemPosition.d.ts +1 -0
- package/lib/utils/setFloatingElemPosition.js +55 -0
- package/lib/utils/setFloatingElemPositionForLinkEditor.d.ts +1 -0
- package/lib/utils/setFloatingElemPositionForLinkEditor.js +32 -0
- package/lib/utils/swipe.d.ts +4 -0
- package/lib/utils/swipe.js +90 -0
- package/lib/utils/url.d.ts +2 -0
- package/lib/utils/url.js +27 -0
- package/package.json +82 -51
- package/lib/DiffMerge.d.ts +0 -39
- package/lib/DiffMerge.js +0 -437
- package/lib/LoroCollaborativePlugin.d.ts +0 -62
- package/lib/LoroCollaborativePlugin.js +0 -2826
- package/lib/stableNodeState.d.ts +0 -8
- package/lib/stableNodeState.js +0 -15
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import invariant from '../utils/invariant';
|
|
2
|
+
import { getLoroTree, generateClientID } from './utils/Utils';
|
|
3
|
+
import { initializeNodeMapper } from './nodes/NodesMapper';
|
|
4
|
+
import { setupLoroDebugging } from './Debug';
|
|
5
|
+
import { isDebugEnabled } from '../../appSettings';
|
|
6
|
+
export function createBinding(editor, provider, id, doc, docMap, excludedProperties) {
|
|
7
|
+
invariant(doc !== undefined && doc !== null, 'createBinding: doc is null or undefined');
|
|
8
|
+
// Initialize the tree - content will come from server snapshot via sync
|
|
9
|
+
const tree = getLoroTree(doc);
|
|
10
|
+
console.log('📄 Loro tree initialized, content will be populated via server sync');
|
|
11
|
+
const clientID = generateClientID(doc);
|
|
12
|
+
console.log('🏗️ BINDING DEBUG - Creating binding:', {
|
|
13
|
+
bindingId: id,
|
|
14
|
+
localPeerId: doc.peerId,
|
|
15
|
+
generatedClientID: clientID,
|
|
16
|
+
docPeerIdType: typeof doc.peerId,
|
|
17
|
+
awarenessKey: clientID.toString()
|
|
18
|
+
});
|
|
19
|
+
const binding = {
|
|
20
|
+
clientID: clientID,
|
|
21
|
+
cursors: new Map(),
|
|
22
|
+
cursorsContainer: null,
|
|
23
|
+
doc,
|
|
24
|
+
docMap,
|
|
25
|
+
editor,
|
|
26
|
+
tree,
|
|
27
|
+
excludedProperties: excludedProperties || new Map(),
|
|
28
|
+
id,
|
|
29
|
+
nodeProperties: new Map(),
|
|
30
|
+
nodeMapper: null, // Will be initialized below
|
|
31
|
+
// Initialize async commit properties
|
|
32
|
+
commitTimeout: null,
|
|
33
|
+
pendingCommit: false,
|
|
34
|
+
};
|
|
35
|
+
// Initialize the NodeMapper with the binding
|
|
36
|
+
binding.nodeMapper = initializeNodeMapper(binding);
|
|
37
|
+
// Setup debugging utilities only if debug is enabled via URL parameter
|
|
38
|
+
if (isDebugEnabled()) {
|
|
39
|
+
setupLoroDebugging(binding);
|
|
40
|
+
console.log('🐛 Loro debugging enabled via ?debug=true URL parameter');
|
|
41
|
+
}
|
|
42
|
+
return binding;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Schedules an asynchronous commit for the binding to reduce latency with large documents.
|
|
46
|
+
* Uses debouncing to prevent excessive commits during rapid mutations.
|
|
47
|
+
*
|
|
48
|
+
* @param binding - The binding to commit
|
|
49
|
+
* @param delay - Debounce delay in milliseconds (default: 100ms)
|
|
50
|
+
*/
|
|
51
|
+
export function scheduleAsyncCommit(binding, delay = 500) {
|
|
52
|
+
// Clear any existing timeout
|
|
53
|
+
if (binding.commitTimeout) {
|
|
54
|
+
clearTimeout(binding.commitTimeout);
|
|
55
|
+
}
|
|
56
|
+
// Mark that we have pending changes
|
|
57
|
+
binding.pendingCommit = true;
|
|
58
|
+
// Schedule the commit after the specified delay
|
|
59
|
+
binding.commitTimeout = setTimeout(() => {
|
|
60
|
+
if (binding.pendingCommit) {
|
|
61
|
+
try {
|
|
62
|
+
// Perform the actual commit
|
|
63
|
+
binding.doc.commit({ origin: binding.doc.peerIdStr });
|
|
64
|
+
console.log('🔄 Async commit completed for binding:', binding.id);
|
|
65
|
+
}
|
|
66
|
+
catch (error) {
|
|
67
|
+
console.error('❌ Async commit failed for binding:', binding.id, error);
|
|
68
|
+
}
|
|
69
|
+
// Reset pending state
|
|
70
|
+
binding.pendingCommit = false;
|
|
71
|
+
}
|
|
72
|
+
binding.commitTimeout = null;
|
|
73
|
+
}, delay);
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Forces an immediate commit if there are pending changes.
|
|
77
|
+
* Useful for ensuring changes are committed before important operations.
|
|
78
|
+
*
|
|
79
|
+
* @param binding - The binding to commit
|
|
80
|
+
*/
|
|
81
|
+
export function flushPendingCommit(binding) {
|
|
82
|
+
if (binding.commitTimeout) {
|
|
83
|
+
clearTimeout(binding.commitTimeout);
|
|
84
|
+
binding.commitTimeout = null;
|
|
85
|
+
}
|
|
86
|
+
if (binding.pendingCommit) {
|
|
87
|
+
binding.doc.commit({ origin: binding.doc.peerIdStr });
|
|
88
|
+
binding.pendingCommit = false;
|
|
89
|
+
console.log('🔄 Forced commit completed for binding:', binding.id);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
// Export components
|
|
93
|
+
export { LoroCollaborators, LoroCollaborationUI } from './components';
|
|
94
|
+
// Export debug utilities for development use
|
|
95
|
+
export { setupLoroDebugging, addDebugPanel, logTreeStructure, verifyTreeStructure } from './Debug';
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { Binding } from './Bindings';
|
|
2
|
+
/**
|
|
3
|
+
* Debugging utilities for Loro collaboration
|
|
4
|
+
* This module provides comprehensive debugging tools for inspecting tree structure,
|
|
5
|
+
* node mappings, and collaboration state in the Loro-Lexical integration.
|
|
6
|
+
*/
|
|
7
|
+
export interface LoroDebugger {
|
|
8
|
+
binding: Binding | null;
|
|
9
|
+
logStructure: () => void;
|
|
10
|
+
verifyStructure: () => void;
|
|
11
|
+
inspectNode: (treeId: string) => void;
|
|
12
|
+
generateTreeHTML: (nodes: any[], rootNode?: any, prefix?: string, isLast?: boolean, depth?: number) => string;
|
|
13
|
+
addDebugToPage: () => void;
|
|
14
|
+
cleanupEphemeralStore: (provider?: any) => void;
|
|
15
|
+
resetGlobalEphemeralStore: () => void;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Sets up global debugging utilities for Loro collaboration.
|
|
19
|
+
* Attaches comprehensive debugging tools to window.debugLoro for development use.
|
|
20
|
+
*/
|
|
21
|
+
export declare function setupLoroDebugging(binding: Binding): void;
|
|
22
|
+
/**
|
|
23
|
+
* Quick access function to add debug panel to page
|
|
24
|
+
*/
|
|
25
|
+
export declare function addDebugPanel(): void;
|
|
26
|
+
/**
|
|
27
|
+
* Quick access function to log tree structure
|
|
28
|
+
*/
|
|
29
|
+
export declare function logTreeStructure(): void;
|
|
30
|
+
/**
|
|
31
|
+
* Quick access function to verify tree structure
|
|
32
|
+
*/
|
|
33
|
+
export declare function verifyTreeStructure(): void;
|
|
@@ -0,0 +1,448 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sets up global debugging utilities for Loro collaboration.
|
|
3
|
+
* Attaches comprehensive debugging tools to window.debugLoro for development use.
|
|
4
|
+
*/
|
|
5
|
+
export function setupLoroDebugging(binding) {
|
|
6
|
+
// Setup global debugging for Loro
|
|
7
|
+
window.debugLoro = {
|
|
8
|
+
binding: null, // Will be set after binding is created
|
|
9
|
+
logStructure: () => {
|
|
10
|
+
const binding = window.debugLoro.binding;
|
|
11
|
+
if (binding) {
|
|
12
|
+
console.log('=== LORO TREE STRUCTURE DEBUG ===');
|
|
13
|
+
const tree = binding.tree;
|
|
14
|
+
const nodes = tree.nodes();
|
|
15
|
+
console.log(`Total nodes in tree: ${nodes.length}`);
|
|
16
|
+
// Helper function to recursively log tree structure
|
|
17
|
+
const logTreeStructure = (node, prefix = '', isLast = true, depth = 0) => {
|
|
18
|
+
const data = Object.fromEntries(node.data.entries());
|
|
19
|
+
const treeId = node.id;
|
|
20
|
+
// Get lexical key from mapper instead of node data
|
|
21
|
+
const lexicalKey = binding.nodeMapper?.getLexicalKeyByLoroId(treeId) || 'no-key';
|
|
22
|
+
const elementType = data.elementType || 'no-type';
|
|
23
|
+
const connector = depth === 0 ? '' : (isLast ? '└── ' : '├── ');
|
|
24
|
+
const nodeInfo = `TreeID(${treeId.slice(0, 8)}...) → ${lexicalKey} [${elementType}]`;
|
|
25
|
+
console.log(`${prefix}${connector}${nodeInfo}`);
|
|
26
|
+
const children = node.children();
|
|
27
|
+
if (children && children.length > 0) {
|
|
28
|
+
children.forEach((child, index) => {
|
|
29
|
+
const isLastChild = index === children.length - 1;
|
|
30
|
+
const childPrefix = prefix + (depth === 0 ? '' : (isLast ? ' ' : '│ '));
|
|
31
|
+
logTreeStructure(child, childPrefix, isLastChild, depth + 1);
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
};
|
|
35
|
+
// Find and display all root nodes
|
|
36
|
+
const rootNodes = nodes.filter((node) => {
|
|
37
|
+
const parent = node.parent();
|
|
38
|
+
const data = Object.fromEntries(node.data.entries());
|
|
39
|
+
return !parent || data.isRoot;
|
|
40
|
+
});
|
|
41
|
+
console.log(`Root nodes: ${rootNodes.length}`);
|
|
42
|
+
console.log('');
|
|
43
|
+
if (rootNodes.length === 0) {
|
|
44
|
+
console.log('⚠️ No root nodes found!');
|
|
45
|
+
}
|
|
46
|
+
else {
|
|
47
|
+
rootNodes.forEach((root, index) => {
|
|
48
|
+
const isLastRoot = index === rootNodes.length - 1;
|
|
49
|
+
logTreeStructure(root, '', isLastRoot, 0);
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
console.log('=== END LORO DEBUG ===');
|
|
53
|
+
}
|
|
54
|
+
else {
|
|
55
|
+
console.log('Loro binding not available yet');
|
|
56
|
+
}
|
|
57
|
+
},
|
|
58
|
+
verifyStructure: () => {
|
|
59
|
+
const binding = window.debugLoro.binding;
|
|
60
|
+
if (!binding)
|
|
61
|
+
return console.log('❌ Loro Binding not available');
|
|
62
|
+
console.log('🔍 LORO TREE VERIFICATION:');
|
|
63
|
+
const tree = binding.tree;
|
|
64
|
+
const nodes = tree.nodes();
|
|
65
|
+
console.log('Total nodes:', nodes.length);
|
|
66
|
+
console.log('Peer ID:', binding.doc.peerIdStr);
|
|
67
|
+
console.log('Client ID:', binding.clientID);
|
|
68
|
+
// Check mapping consistency
|
|
69
|
+
const mapper = binding.nodeMapper;
|
|
70
|
+
console.log('\n📍 Node Mappings:');
|
|
71
|
+
nodes.forEach((node, index) => {
|
|
72
|
+
const data = Object.fromEntries(node.data.entries());
|
|
73
|
+
const treeId = node.id;
|
|
74
|
+
// Get lexical key from mapper instead of node data
|
|
75
|
+
const lexicalKey = binding.nodeMapper?.getLexicalKeyByLoroId(treeId) || 'no-key';
|
|
76
|
+
console.log(`\n📍 Node ${index}:`);
|
|
77
|
+
console.log(' TreeID:', treeId);
|
|
78
|
+
console.log(' Lexical Key:', lexicalKey);
|
|
79
|
+
console.log(' Element Type:', data.elementType || 'N/A');
|
|
80
|
+
console.log(' Created At:', data.createdAt && typeof data.createdAt === 'number' ? new Date(data.createdAt).toLocaleTimeString() : 'N/A');
|
|
81
|
+
console.log(' Has Lexical Data:', data.lexical ? 'Yes' : 'No');
|
|
82
|
+
const parent = node.parent();
|
|
83
|
+
console.log(' Parent:', parent ? parent.id : 'None (Root)');
|
|
84
|
+
const children = node.children();
|
|
85
|
+
console.log(' Children Count:', children ? children.length : 0);
|
|
86
|
+
if (data.lexical && typeof data.lexical === 'string') {
|
|
87
|
+
try {
|
|
88
|
+
const parsed = JSON.parse(data.lexical);
|
|
89
|
+
console.log(' Lexical Type:', parsed.lexicalNode?.type || 'Unknown');
|
|
90
|
+
}
|
|
91
|
+
catch (e) {
|
|
92
|
+
console.log(' Lexical Data: Invalid JSON');
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
});
|
|
96
|
+
// Check for orphaned nodes
|
|
97
|
+
const orphanedNodes = nodes.filter(node => {
|
|
98
|
+
const parent = node.parent();
|
|
99
|
+
const data = Object.fromEntries(node.data.entries());
|
|
100
|
+
return !parent && !data.isRoot;
|
|
101
|
+
});
|
|
102
|
+
if (orphanedNodes.length > 0) {
|
|
103
|
+
console.log('\n⚠️ WARNING: Found orphaned nodes (no parent, not root):');
|
|
104
|
+
orphanedNodes.forEach(node => {
|
|
105
|
+
const data = Object.fromEntries(node.data.entries());
|
|
106
|
+
const lexicalKey = binding.nodeMapper?.getLexicalKeyByLoroId(node.id) || 'no-key';
|
|
107
|
+
console.log(` - ${node.id} (${lexicalKey}, ${data.elementType})`);
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
// Show parent-child relationships
|
|
111
|
+
console.log('\n🌳 Parent-Child Relationships:');
|
|
112
|
+
nodes.forEach(node => {
|
|
113
|
+
const data = Object.fromEntries(node.data.entries());
|
|
114
|
+
const parent = node.parent();
|
|
115
|
+
const children = node.children();
|
|
116
|
+
const lexicalKey = binding.nodeMapper?.getLexicalKeyByLoroId(node.id) || 'no-key';
|
|
117
|
+
console.log(`${node.id} (${lexicalKey}, ${data.elementType || 'no-type'})`);
|
|
118
|
+
console.log(` Parent: ${parent ? parent.id : 'None'}`);
|
|
119
|
+
console.log(` Children: ${children ? children.map(child => child.id).join(', ') : 'None'}`);
|
|
120
|
+
});
|
|
121
|
+
},
|
|
122
|
+
inspectNode: (treeId) => {
|
|
123
|
+
const binding = window.debugLoro.binding;
|
|
124
|
+
if (!binding)
|
|
125
|
+
return console.log('Loro binding not available');
|
|
126
|
+
const tree = binding.tree;
|
|
127
|
+
// Cast treeId to TreeID type - in practice this should work if it's a valid ID
|
|
128
|
+
const node = tree.getNodeByID(treeId);
|
|
129
|
+
if (node) {
|
|
130
|
+
const data = Object.fromEntries(node.data.entries());
|
|
131
|
+
const parent = node.parent();
|
|
132
|
+
const children = node.children();
|
|
133
|
+
// Collect lexical properties (new individual property format)
|
|
134
|
+
const lexicalProps = {};
|
|
135
|
+
Object.entries(data).forEach(([key, value]) => {
|
|
136
|
+
if (key.startsWith('lexical_')) {
|
|
137
|
+
lexicalProps[key.substring(8)] = value; // Remove 'lexical_' prefix
|
|
138
|
+
}
|
|
139
|
+
});
|
|
140
|
+
// Get lexical key from mapper instead of node data
|
|
141
|
+
const lexicalKey = binding.nodeMapper?.getLexicalKeyByLoroId(node.id) || 'no-key';
|
|
142
|
+
console.log('🔍 Loro Node Details:', {
|
|
143
|
+
treeId: node.id,
|
|
144
|
+
lexicalKey: lexicalKey,
|
|
145
|
+
elementType: data.elementType,
|
|
146
|
+
createdAt: data.createdAt && typeof data.createdAt === 'number' ? new Date(data.createdAt).toLocaleString() : 'N/A',
|
|
147
|
+
hasLexicalData: Object.keys(lexicalProps).length > 0 || !!data.lexical,
|
|
148
|
+
parent: parent ? parent.id : 'None (Root)',
|
|
149
|
+
childrenCount: children ? children.length : 0,
|
|
150
|
+
isRoot: data.isRoot || false
|
|
151
|
+
});
|
|
152
|
+
// Handle different lexical data formats
|
|
153
|
+
if (Object.keys(lexicalProps).length > 0) {
|
|
154
|
+
console.log('📄 Lexical Data (Individual Properties):', lexicalProps);
|
|
155
|
+
}
|
|
156
|
+
else if (data.lexical) {
|
|
157
|
+
if (typeof data.lexical === 'object') {
|
|
158
|
+
console.log('📄 Lexical Data (Current JSON Object):', data.lexical);
|
|
159
|
+
}
|
|
160
|
+
else if (typeof data.lexical === 'string') {
|
|
161
|
+
try {
|
|
162
|
+
const lexicalData = JSON.parse(data.lexical);
|
|
163
|
+
console.log('📄 Lexical Data (Legacy JSON String):', lexicalData);
|
|
164
|
+
}
|
|
165
|
+
catch (e) {
|
|
166
|
+
console.log('❌ Failed to parse lexical data:', e);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
else {
|
|
171
|
+
console.log('⚠️ No lexical data found for this node');
|
|
172
|
+
}
|
|
173
|
+
// Fetch and log the corresponding lexical node
|
|
174
|
+
if (lexicalKey && lexicalKey !== 'no-key' && typeof lexicalKey === 'string') {
|
|
175
|
+
try {
|
|
176
|
+
const editorState = binding.editor.getEditorState();
|
|
177
|
+
const nodeInfo = editorState.read(() => {
|
|
178
|
+
const lexicalNode = editorState._nodeMap.get(lexicalKey);
|
|
179
|
+
if (!lexicalNode) {
|
|
180
|
+
return null;
|
|
181
|
+
}
|
|
182
|
+
const info = {
|
|
183
|
+
key: lexicalNode.getKey(),
|
|
184
|
+
type: lexicalNode.getType(),
|
|
185
|
+
parent: lexicalNode.getParent()?.getKey() || 'None (Root)',
|
|
186
|
+
textContent: lexicalNode.getTextContent ? lexicalNode.getTextContent() : 'N/A',
|
|
187
|
+
serialized: lexicalNode.exportJSON()
|
|
188
|
+
};
|
|
189
|
+
// Add children info if it's an ElementNode
|
|
190
|
+
if ('getChildren' in lexicalNode && typeof lexicalNode.getChildren === 'function') {
|
|
191
|
+
info.children = lexicalNode.getChildren().map((child) => child.getKey());
|
|
192
|
+
}
|
|
193
|
+
else {
|
|
194
|
+
info.children = 'N/A (Not an ElementNode)';
|
|
195
|
+
}
|
|
196
|
+
return info;
|
|
197
|
+
});
|
|
198
|
+
if (nodeInfo) {
|
|
199
|
+
console.log('🔗 Linked Lexical Node:', nodeInfo);
|
|
200
|
+
}
|
|
201
|
+
else {
|
|
202
|
+
console.log('⚠️ No lexical node found in editor state for key:', lexicalKey, '(node may have been deleted or not yet created)');
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
catch (e) {
|
|
206
|
+
console.log('❌ Failed to fetch lexical node:', e);
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
else {
|
|
210
|
+
console.log('⚠️ No valid lexical key found for this Loro node (key:', lexicalKey, ')');
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
else {
|
|
214
|
+
console.warn(`Node with TreeID "${treeId}" not found`);
|
|
215
|
+
}
|
|
216
|
+
},
|
|
217
|
+
generateTreeHTML: (nodes, rootNode, prefix = '', isLast = true, depth = 0) => {
|
|
218
|
+
if (!rootNode) {
|
|
219
|
+
// Find root nodes
|
|
220
|
+
const rootNodes = nodes.filter(node => {
|
|
221
|
+
const parent = node.parent();
|
|
222
|
+
const data = Object.fromEntries(node.data.entries());
|
|
223
|
+
return !parent || data.isRoot;
|
|
224
|
+
});
|
|
225
|
+
if (rootNodes.length === 0)
|
|
226
|
+
return '<div style="color: #ffaa00;">No root nodes found</div>';
|
|
227
|
+
// Display all root nodes
|
|
228
|
+
let result = '';
|
|
229
|
+
rootNodes.forEach((root, index) => {
|
|
230
|
+
const isLastRoot = index === rootNodes.length - 1;
|
|
231
|
+
result += window.debugLoro.generateTreeHTML(nodes, root, '', isLastRoot, 0);
|
|
232
|
+
});
|
|
233
|
+
return result;
|
|
234
|
+
}
|
|
235
|
+
const data = Object.fromEntries(rootNode.data.entries());
|
|
236
|
+
const treeId = rootNode.id;
|
|
237
|
+
// Get lexical key from mapper instead of node data
|
|
238
|
+
const binding = window.debugLoro.binding;
|
|
239
|
+
const lexicalKey = binding?.nodeMapper?.getLexicalKeyByLoroId(treeId) || 'no-key';
|
|
240
|
+
const elementType = data.elementType || 'no-type';
|
|
241
|
+
const nodeInfo = `TreeID(${treeId.slice(0, 8)}...) → ${lexicalKey} [${elementType}]`;
|
|
242
|
+
const clickIntegrator = `onclick="window.debugLoro.inspectNode('${treeId}')"`;
|
|
243
|
+
const nodeColor = data.isRoot ? '#00ff88' : '#00ffaa';
|
|
244
|
+
const cursor = 'cursor: pointer; text-decoration: underline;';
|
|
245
|
+
// Create proper tree structure with indentation
|
|
246
|
+
const connector = depth === 0 ? '' : (isLast ? '└── ' : '├── ');
|
|
247
|
+
let result = `<div style="color: ${nodeColor}; ${cursor}" ${clickIntegrator}>${prefix}${connector}${nodeInfo}</div>`;
|
|
248
|
+
const children = rootNode.children();
|
|
249
|
+
if (children && children.length > 0) {
|
|
250
|
+
children.forEach((child, index) => {
|
|
251
|
+
const isLastChild = index === children.length - 1;
|
|
252
|
+
// Calculate prefix for children - if current node is last, use spaces, otherwise use vertical line
|
|
253
|
+
// Use for HTML spaces to ensure proper rendering
|
|
254
|
+
const childPrefix = prefix + (depth === 0 ? '' : (isLast ? ' ' : '│ '));
|
|
255
|
+
result += window.debugLoro.generateTreeHTML(nodes, child, childPrefix, isLastChild, depth + 1);
|
|
256
|
+
});
|
|
257
|
+
}
|
|
258
|
+
return result;
|
|
259
|
+
},
|
|
260
|
+
addDebugToPage: () => {
|
|
261
|
+
const binding = window.debugLoro.binding;
|
|
262
|
+
if (!binding)
|
|
263
|
+
return;
|
|
264
|
+
const tree = binding.tree;
|
|
265
|
+
const nodes = tree.nodes();
|
|
266
|
+
// Debug: log the actual structure to console as a tree
|
|
267
|
+
console.log('🟢 LORO Tree structure:');
|
|
268
|
+
console.log(` Total nodes: ${nodes.length}`);
|
|
269
|
+
console.log(` Peer ID: ${binding.doc.peerIdStr}`);
|
|
270
|
+
console.log(` Client ID: ${binding.clientID}`);
|
|
271
|
+
console.log('');
|
|
272
|
+
// Helper function to recursively log tree structure
|
|
273
|
+
const logTreeStructure = (node, prefix = '', isLast = true, depth = 0) => {
|
|
274
|
+
const data = Object.fromEntries(node.data.entries());
|
|
275
|
+
const treeId = node.id;
|
|
276
|
+
// Get lexical key from mapper instead of node data
|
|
277
|
+
const lexicalKey = binding.nodeMapper?.getLexicalKeyByLoroId(treeId) || 'no-key';
|
|
278
|
+
const elementType = data.elementType || 'no-type';
|
|
279
|
+
const connector = depth === 0 ? '' : (isLast ? '└── ' : '├── ');
|
|
280
|
+
const nodeInfo = `TreeID(${treeId.slice(0, 8)}...) → ${lexicalKey} [${elementType}]`;
|
|
281
|
+
console.log(`${prefix}${connector}${nodeInfo}`);
|
|
282
|
+
const children = node.children();
|
|
283
|
+
if (children && children.length > 0) {
|
|
284
|
+
children.forEach((child, index) => {
|
|
285
|
+
const isLastChild = index === children.length - 1;
|
|
286
|
+
const childPrefix = prefix + (depth === 0 ? '' : (isLast ? ' ' : '│ '));
|
|
287
|
+
logTreeStructure(child, childPrefix, isLastChild, depth + 1);
|
|
288
|
+
});
|
|
289
|
+
}
|
|
290
|
+
};
|
|
291
|
+
// Find and display all root nodes
|
|
292
|
+
const rootNodes = nodes.filter((node) => {
|
|
293
|
+
const parent = node.parent();
|
|
294
|
+
const data = Object.fromEntries(node.data.entries());
|
|
295
|
+
return !parent || data.isRoot;
|
|
296
|
+
});
|
|
297
|
+
if (rootNodes.length === 0) {
|
|
298
|
+
console.log(' ⚠️ No root nodes found!');
|
|
299
|
+
}
|
|
300
|
+
else {
|
|
301
|
+
rootNodes.forEach((root, index) => {
|
|
302
|
+
const isLastRoot = index === rootNodes.length - 1;
|
|
303
|
+
logTreeStructure(root, '', isLastRoot, 0);
|
|
304
|
+
});
|
|
305
|
+
}
|
|
306
|
+
console.log('🟢 Loro Tree:', tree.toJSON());
|
|
307
|
+
console.log('🟢 Lexical State:', binding.editor.getEditorState().toJSON());
|
|
308
|
+
const treeHTML = window.debugLoro.generateTreeHTML(nodes);
|
|
309
|
+
const debugDiv = document.getElementById('debug-loro') || document.createElement('div');
|
|
310
|
+
const existingDiv = document.getElementById('debug-loro');
|
|
311
|
+
// Preserve current position if panel already exists
|
|
312
|
+
let currentLeft = '10px';
|
|
313
|
+
let currentTop = '700px';
|
|
314
|
+
if (existingDiv) {
|
|
315
|
+
currentLeft = existingDiv.style.left || '10px';
|
|
316
|
+
currentTop = existingDiv.style.top || '10px';
|
|
317
|
+
}
|
|
318
|
+
debugDiv.id = 'debug-loro';
|
|
319
|
+
debugDiv.style.cssText = `position: fixed; top: ${currentTop}; left: ${currentLeft}; background: rgba(0,0,0,0.95); color: #00ff00; padding: 0; border-radius: 8px; font-family: "Courier New", monospace; font-size: 11px; z-index: 9999; max-width: 500px; max-height: 80vh; box-shadow: 0 4px 8px rgba(0,0,0,0.5); border: 1px solid #00ff00; user-select: none;`;
|
|
320
|
+
// Add drag functionality if not already added
|
|
321
|
+
if (!debugDiv.classList.contains('draggable-initialized')) {
|
|
322
|
+
debugDiv.classList.add('draggable-initialized');
|
|
323
|
+
let isDragging = false;
|
|
324
|
+
let startX = 0;
|
|
325
|
+
let startY = 0;
|
|
326
|
+
let startLeft = 0;
|
|
327
|
+
let startTop = 0;
|
|
328
|
+
debugDiv.addEventListener('mousedown', (e) => {
|
|
329
|
+
// Only start drag if clicking on the header area
|
|
330
|
+
const target = e.target;
|
|
331
|
+
const dragHandle = debugDiv.querySelector('.debug-drag-integrate');
|
|
332
|
+
if (!dragHandle || !dragHandle.contains(target))
|
|
333
|
+
return;
|
|
334
|
+
isDragging = true;
|
|
335
|
+
startX = e.clientX;
|
|
336
|
+
startY = e.clientY;
|
|
337
|
+
const rect = debugDiv.getBoundingClientRect();
|
|
338
|
+
startLeft = rect.left;
|
|
339
|
+
startTop = rect.top;
|
|
340
|
+
document.addEventListener('mousemove', onMouseMove);
|
|
341
|
+
document.addEventListener('mouseup', onMouseUp);
|
|
342
|
+
e.preventDefault();
|
|
343
|
+
});
|
|
344
|
+
function onMouseMove(e) {
|
|
345
|
+
if (!isDragging)
|
|
346
|
+
return;
|
|
347
|
+
const deltaX = e.clientX - startX;
|
|
348
|
+
const deltaY = e.clientY - startY;
|
|
349
|
+
const newLeft = Math.max(0, Math.min(window.innerWidth - debugDiv.offsetWidth, startLeft + deltaX));
|
|
350
|
+
const newTop = Math.max(0, Math.min(window.innerHeight - debugDiv.offsetHeight, startTop + deltaY));
|
|
351
|
+
debugDiv.style.left = newLeft + 'px';
|
|
352
|
+
debugDiv.style.top = newTop + 'px';
|
|
353
|
+
}
|
|
354
|
+
function onMouseUp() {
|
|
355
|
+
isDragging = false;
|
|
356
|
+
document.removeEventListener('mousemove', onMouseMove);
|
|
357
|
+
document.removeEventListener('mouseup', onMouseUp);
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
debugDiv.innerHTML = `
|
|
361
|
+
<div class="debug-drag-integrate" style="color: #00ff88; font-weight: bold; margin-bottom: 10px; border-bottom: 1px solid #00ff00; padding: 15px 15px 5px 15px; cursor: move; background: linear-gradient(90deg, rgba(0,255,136,0.1), transparent);">
|
|
362
|
+
🟢 LORO TREE <span style="float: right; font-size: 9px; color: #666;">⋮⋮ drag</span>
|
|
363
|
+
</div>
|
|
364
|
+
<div style="padding: 0 15px 15px 15px; overflow-y: auto; max-height: calc(80vh - 50px);">
|
|
365
|
+
<div style="color: #00ffaa; margin-bottom: 8px;">Total nodes: ${nodes.length}</div>
|
|
366
|
+
<div style="color: #00ff66; margin-bottom: 8px;">Peer ID: ${binding.doc.peerIdStr.slice(0, 8)}...</div>
|
|
367
|
+
<div style="color: #00ffdd; margin-bottom: 10px;">Time: ${new Date().toLocaleTimeString()}</div>
|
|
368
|
+
<div style="border-top: 1px solid #444; padding-top: 8px; line-height: 1.4; font-family: 'Courier New', monospace;">
|
|
369
|
+
${treeHTML}
|
|
370
|
+
</div>
|
|
371
|
+
<div style="margin-top: 10px; font-size: 10px; color: #666;">
|
|
372
|
+
<span onclick="window.debugLoro.addDebugToPage()" style="color: #00ffaa; cursor: pointer; text-decoration: underline;">🔄 Refresh</span> |
|
|
373
|
+
<span onclick="window.debugLoro.verifyStructure()" style="color: #00ff66; cursor: pointer; text-decoration: underline;">✅ Verify</span> |
|
|
374
|
+
<span onclick="window.debugLoro.logStructure()" style="color: #00ffdd; cursor: pointer; text-decoration: underline;">📝 Log</span> |
|
|
375
|
+
<span onclick="window.debugLoro.cleanupEphemeralStore()" style="color: #ffaa00; cursor: pointer; text-decoration: underline;">🧹 Cleanup</span> |
|
|
376
|
+
<span onclick="window.debugLoro.resetGlobalEphemeralStore()" style="color: #ff6600; cursor: pointer; text-decoration: underline;">🔄 Reset</span> |
|
|
377
|
+
<span onclick="document.getElementById('debug-loro').remove()" style="color: #ff0066; cursor: pointer; text-decoration: underline;">❌ Close</span>
|
|
378
|
+
</div>
|
|
379
|
+
</div>
|
|
380
|
+
`;
|
|
381
|
+
document.body.appendChild(debugDiv);
|
|
382
|
+
},
|
|
383
|
+
cleanupEphemeralStore: (provider) => {
|
|
384
|
+
if (!provider) {
|
|
385
|
+
console.log('⚠️ No provider passed. Usage: window.debugLoro.cleanupEphemeralStore(provider)');
|
|
386
|
+
console.log('You can get the provider from your useCollaboration hook');
|
|
387
|
+
return;
|
|
388
|
+
}
|
|
389
|
+
if (typeof provider.cleanupStaleStates !== 'function') {
|
|
390
|
+
console.log('❌ Provider does not have cleanupStaleStates method');
|
|
391
|
+
return;
|
|
392
|
+
}
|
|
393
|
+
console.log('🧹 Cleaning up stale ephemeral states...');
|
|
394
|
+
provider.cleanupStaleStates();
|
|
395
|
+
},
|
|
396
|
+
resetGlobalEphemeralStore: () => {
|
|
397
|
+
try {
|
|
398
|
+
// We need to access the WebsocketProvider class which may not be globally available
|
|
399
|
+
console.log('🔄 Attempting to reset global EphemeralStore...');
|
|
400
|
+
console.log('💡 You can also refresh the browser to clear the global store');
|
|
401
|
+
// For now, instruct user to refresh
|
|
402
|
+
alert('To reset the global ephemeral store and clear all collaborators, please refresh the browser page.');
|
|
403
|
+
}
|
|
404
|
+
catch (error) {
|
|
405
|
+
console.warn('❌ Reset failed:', error.message);
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
};
|
|
409
|
+
// Expose binding for debugging
|
|
410
|
+
window.debugLoro.binding = binding;
|
|
411
|
+
// Auto-initialize debug window after a short delay
|
|
412
|
+
setTimeout(() => {
|
|
413
|
+
window.debugLoro.addDebugToPage();
|
|
414
|
+
}, 2000); // Slightly later than Y.js to avoid overlap
|
|
415
|
+
}
|
|
416
|
+
/**
|
|
417
|
+
* Quick access function to add debug panel to page
|
|
418
|
+
*/
|
|
419
|
+
export function addDebugPanel() {
|
|
420
|
+
if (window.debugLoro?.addDebugToPage) {
|
|
421
|
+
window.debugLoro.addDebugToPage();
|
|
422
|
+
}
|
|
423
|
+
else {
|
|
424
|
+
console.warn('Debug utilities not initialized. Call setupLoroDebugging first.');
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
/**
|
|
428
|
+
* Quick access function to log tree structure
|
|
429
|
+
*/
|
|
430
|
+
export function logTreeStructure() {
|
|
431
|
+
if (window.debugLoro?.logStructure) {
|
|
432
|
+
window.debugLoro.logStructure();
|
|
433
|
+
}
|
|
434
|
+
else {
|
|
435
|
+
console.warn('Debug utilities not initialized. Call setupLoroDebugging first.');
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
/**
|
|
439
|
+
* Quick access function to verify tree structure
|
|
440
|
+
*/
|
|
441
|
+
export function verifyTreeStructure() {
|
|
442
|
+
if (window.debugLoro?.verifyStructure) {
|
|
443
|
+
window.debugLoro.verifyStructure();
|
|
444
|
+
}
|
|
445
|
+
else {
|
|
446
|
+
console.warn('Debug utilities not initialized. Call setupLoroDebugging first.');
|
|
447
|
+
}
|
|
448
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { LoroDoc } from 'loro-crdt';
|
|
2
|
+
export type CollaborationContextType = {
|
|
3
|
+
clientID: number;
|
|
4
|
+
color: string;
|
|
5
|
+
isCollabActive: boolean;
|
|
6
|
+
name: string;
|
|
7
|
+
docMap: Map<string, LoroDoc>;
|
|
8
|
+
};
|
|
9
|
+
/**
|
|
10
|
+
* Generate a deterministic name and color based on a client ID
|
|
11
|
+
* This ensures the same client ID always gets the same name across browser sessions
|
|
12
|
+
*/
|
|
13
|
+
declare function generateDeterministicUserData(clientId: number): {
|
|
14
|
+
name: string;
|
|
15
|
+
color: string;
|
|
16
|
+
};
|
|
17
|
+
export declare const CollaborationContext: import("react").Context<CollaborationContextType>;
|
|
18
|
+
export { generateDeterministicUserData };
|
|
19
|
+
export declare function useCollaborationContext(username?: string, color?: string): CollaborationContextType;
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { createContext, useContext } from 'react';
|
|
2
|
+
const ANIMAL_NAMES = [
|
|
3
|
+
'Cat', 'Dog', 'Rabbit', 'Frog', 'Fox', 'Hedgehog', 'Pigeon', 'Squirrel',
|
|
4
|
+
'Bear', 'Tiger', 'Leopard', 'Zebra', 'Wolf', 'Owl', 'Gull', 'Squid',
|
|
5
|
+
'Panda', 'Lion', 'Eagle', 'Shark', 'Dolphin', 'Penguin', 'Koala', 'Kangaroo'
|
|
6
|
+
];
|
|
7
|
+
const COLORS = [
|
|
8
|
+
'rgb(125, 50, 0)', 'rgb(100, 0, 0)', 'rgb(150, 0, 0)', 'rgb(200, 0, 0)',
|
|
9
|
+
'rgb(200, 75, 0)', 'rgb(0, 75, 0)', 'rgb(0, 125, 0)', 'rgb(75, 100, 0)',
|
|
10
|
+
'rgb(125, 100, 0)', 'rgb(0, 0, 150)', 'rgb(0, 0, 200)', 'rgb(0, 0, 250)',
|
|
11
|
+
'rgb(0, 100, 150)', 'rgb(0, 100, 100)', 'rgb(100, 0, 100)', 'rgb(150, 0, 150)',
|
|
12
|
+
'rgb(255, 99, 71)', 'rgb(60, 179, 113)', 'rgb(30, 144, 255)', 'rgb(255, 165, 0)',
|
|
13
|
+
'rgb(138, 43, 226)', 'rgb(255, 20, 147)', 'rgb(0, 191, 255)', 'rgb(50, 205, 50)'
|
|
14
|
+
];
|
|
15
|
+
/**
|
|
16
|
+
* Generate a deterministic name and color based on a client ID
|
|
17
|
+
* This ensures the same client ID always gets the same name across browser sessions
|
|
18
|
+
*/
|
|
19
|
+
function generateDeterministicUserData(clientId) {
|
|
20
|
+
// Use clientId as seed for deterministic selection
|
|
21
|
+
const nameIndex = Math.abs(clientId) % ANIMAL_NAMES.length;
|
|
22
|
+
const colorIndex = Math.abs(clientId) % COLORS.length;
|
|
23
|
+
// Add a short ID suffix for uniqueness in case of collisions
|
|
24
|
+
const shortId = Math.abs(clientId).toString().slice(-4);
|
|
25
|
+
const name = `${ANIMAL_NAMES[nameIndex]}-${shortId}`;
|
|
26
|
+
const color = COLORS[colorIndex];
|
|
27
|
+
return { name, color };
|
|
28
|
+
}
|
|
29
|
+
// Use a temporary fallback for initial context (will be updated when client connects)
|
|
30
|
+
const fallbackUserData = generateDeterministicUserData(Math.floor(Math.random() * 100000));
|
|
31
|
+
export const CollaborationContext = createContext({
|
|
32
|
+
clientID: 0,
|
|
33
|
+
color: fallbackUserData.color,
|
|
34
|
+
isCollabActive: false,
|
|
35
|
+
name: fallbackUserData.name,
|
|
36
|
+
docMap: new Map(),
|
|
37
|
+
});
|
|
38
|
+
export { generateDeterministicUserData };
|
|
39
|
+
export function useCollaborationContext(username, color) {
|
|
40
|
+
const collabContext = useContext(CollaborationContext);
|
|
41
|
+
if (username != null) {
|
|
42
|
+
collabContext.name = username;
|
|
43
|
+
}
|
|
44
|
+
if (color != null) {
|
|
45
|
+
collabContext.color = color;
|
|
46
|
+
}
|
|
47
|
+
return collabContext;
|
|
48
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { JSX } from 'react';
|
|
2
|
+
import { InitialEditorStateType } from '@lexical/react/LexicalComposer';
|
|
3
|
+
import type { LoroDoc } from 'loro-crdt';
|
|
4
|
+
import { Provider } from './State';
|
|
5
|
+
import { CursorsContainerRef } from './useCollaboration';
|
|
6
|
+
import { SyncCursorPositionsFn } from './sync/SyncCursors';
|
|
7
|
+
import { ExcludedProperties } from './Bindings';
|
|
8
|
+
type Props = {
|
|
9
|
+
id: string;
|
|
10
|
+
providerFactory: (id: string, docMap: Map<string, LoroDoc>, websocketUrl?: string) => Provider;
|
|
11
|
+
shouldBootstrap: boolean;
|
|
12
|
+
username?: string;
|
|
13
|
+
cursorColor?: string;
|
|
14
|
+
cursorsContainerRef?: CursorsContainerRef;
|
|
15
|
+
initialEditorState?: InitialEditorStateType;
|
|
16
|
+
excludedProperties?: ExcludedProperties;
|
|
17
|
+
awarenessData?: object;
|
|
18
|
+
syncCursorPositionsFn?: SyncCursorPositionsFn;
|
|
19
|
+
showCollaborators?: boolean;
|
|
20
|
+
websocketUrl?: string;
|
|
21
|
+
onInitialization?: (isInitialized: boolean) => void;
|
|
22
|
+
};
|
|
23
|
+
export declare function LoroCollaborationPlugin({ id, providerFactory, shouldBootstrap, username, cursorColor, cursorsContainerRef, initialEditorState, excludedProperties, awarenessData, syncCursorPositionsFn, showCollaborators, websocketUrl, onInitialization, }: Props): JSX.Element;
|
|
24
|
+
export {};
|