@liveblocks/react-lexical 2.0.0-alpha4 → 2.0.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.
@@ -1 +1 @@
1
- {"version":3,"file":"thread-mark-node.js","sources":["../../src/comments/thread-mark-node.ts"],"sourcesContent":["/**\n * MIT License\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n * \n * The above copyright notice and this permission notice shall be included in all\n * copies or substantial portions of the Software.\n * \n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\nimport type {\n BaseSelection,\n LexicalNode,\n NodeKey,\n RangeSelection,\n SerializedElementNode,\n Spread,\n} from \"lexical\";\nimport { $applyNodeReplacement, $isRangeSelection, ElementNode } from \"lexical\";\n\nexport type SerializedThreadMarkNode = Spread<\n {\n ids: Array<string>;\n },\n SerializedElementNode\n>;\n\nexport class ThreadMarkNode extends ElementNode {\n /** @internal */\n __ids: Array<string>; // The ids of the threads that this mark is associated with\n\n static getType(): string {\n return \"lb-thread-mark\";\n }\n\n static clone(node: ThreadMarkNode): ThreadMarkNode {\n return new ThreadMarkNode(Array.from(node.__ids), node.__key);\n }\n\n static importDOM(): null {\n return null;\n }\n\n static importJSON(serializedNode: SerializedThreadMarkNode): ThreadMarkNode {\n const node = $createThreadMarkNode(serializedNode.ids);\n node.setFormat(serializedNode.format);\n node.setIndent(serializedNode.indent);\n node.setDirection(serializedNode.direction);\n return node;\n }\n\n exportJSON(): SerializedThreadMarkNode {\n return {\n ...super.exportJSON(),\n ids: this.getIDs(),\n type: \"lb-thread-mark\",\n version: 1,\n };\n }\n\n constructor(ids: Array<string>, key?: NodeKey) {\n super(key);\n this.__ids = ids || [];\n }\n\n createDOM(): HTMLElement {\n const element = document.createElement(\"span\");\n return element;\n }\n\n updateDOM(): boolean {\n return false;\n }\n\n hasID(id: string): boolean {\n const ids = this.getIDs();\n for (let i = 0; i < ids.length; i++) {\n if (id === ids[i]) {\n return true;\n }\n }\n return false;\n }\n\n getIDs(): Array<string> {\n const self = this.getLatest();\n return $isThreadMarkNode(self) ? self.__ids : [];\n }\n\n addID(id: string): void {\n const self = this.getWritable();\n if ($isThreadMarkNode(self)) {\n const ids = self.__ids;\n self.__ids = ids;\n for (let i = 0; i < ids.length; i++) {\n // If we already have it, don't add again\n if (id === ids[i]) {\n return;\n }\n }\n ids.push(id);\n }\n }\n\n deleteID(id: string): void {\n const self = this.getWritable();\n if ($isThreadMarkNode(self)) {\n const ids = self.__ids;\n self.__ids = ids;\n for (let i = 0; i < ids.length; i++) {\n if (id === ids[i]) {\n ids.splice(i, 1);\n return;\n }\n }\n }\n }\n\n insertNewAfter(\n _: RangeSelection,\n restoreSelection = true\n ): null | ElementNode {\n const markNode = $createThreadMarkNode(this.__ids);\n this.insertAfter(markNode, restoreSelection);\n return markNode;\n }\n\n canInsertTextBefore(): false {\n return false;\n }\n\n canInsertTextAfter(): false {\n return false;\n }\n\n canBeEmpty(): false {\n return false;\n }\n\n isInline(): true {\n return true;\n }\n\n extractWithChild(\n _: LexicalNode,\n selection: BaseSelection,\n destination: \"clone\" | \"html\"\n ): boolean {\n if (!$isRangeSelection(selection) || destination === \"html\") {\n return false;\n }\n const anchor = selection.anchor;\n const focus = selection.focus;\n const anchorNode = anchor.getNode();\n const focusNode = focus.getNode();\n const isBackward = selection.isBackward();\n const selectionLength = isBackward\n ? anchor.offset - focus.offset\n : focus.offset - anchor.offset;\n return (\n this.isParentOf(anchorNode) &&\n this.isParentOf(focusNode) &&\n this.getTextContent().length === selectionLength\n );\n }\n\n excludeFromCopy(destination: \"clone\" | \"html\"): boolean {\n return destination !== \"clone\";\n }\n}\n\nexport function $createThreadMarkNode(ids: Array<string>): ThreadMarkNode {\n return $applyNodeReplacement(new ThreadMarkNode(ids));\n}\n\nexport function $isThreadMarkNode(\n node: LexicalNode | null\n): node is ThreadMarkNode {\n return node instanceof ThreadMarkNode;\n}\n"],"names":["ElementNode","$isRangeSelection","$applyNodeReplacement"],"mappings":"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"}
1
+ {"version":3,"file":"thread-mark-node.js","sources":["../../src/comments/thread-mark-node.ts"],"sourcesContent":["import type {\n BaseSelection,\n LexicalNode,\n NodeKey,\n RangeSelection,\n SerializedElementNode,\n Spread,\n} from \"lexical\";\nimport { $applyNodeReplacement, $isRangeSelection, ElementNode } from \"lexical\";\n\nexport type SerializedThreadMarkNode = Spread<\n {\n ids: Array<string>;\n },\n SerializedElementNode\n>;\n\nexport class ThreadMarkNode extends ElementNode {\n /** @internal */\n __ids: Array<string>; // The ids of the threads that this mark is associated with\n\n static getType(): string {\n return \"lb-thread-mark\";\n }\n\n static clone(node: ThreadMarkNode): ThreadMarkNode {\n return new ThreadMarkNode(Array.from(node.__ids), node.__key);\n }\n\n static importDOM(): null {\n return null;\n }\n\n static importJSON(serializedNode: SerializedThreadMarkNode): ThreadMarkNode {\n const node = $createThreadMarkNode(serializedNode.ids);\n node.setFormat(serializedNode.format);\n node.setIndent(serializedNode.indent);\n node.setDirection(serializedNode.direction);\n return node;\n }\n\n exportJSON(): SerializedThreadMarkNode {\n return {\n ...super.exportJSON(),\n ids: this.getIDs(),\n type: \"lb-thread-mark\",\n version: 1,\n };\n }\n\n constructor(ids: Array<string>, key?: NodeKey) {\n super(key);\n this.__ids = ids || [];\n }\n\n createDOM(): HTMLElement {\n const element = document.createElement(\"span\");\n return element;\n }\n\n updateDOM(): boolean {\n return false;\n }\n\n hasID(id: string): boolean {\n const ids = this.getIDs();\n for (let i = 0; i < ids.length; i++) {\n if (id === ids[i]) {\n return true;\n }\n }\n return false;\n }\n\n getIDs(): Array<string> {\n const self = this.getLatest();\n return $isThreadMarkNode(self) ? self.__ids : [];\n }\n\n addID(id: string): void {\n const self = this.getWritable();\n if ($isThreadMarkNode(self)) {\n const ids = self.__ids;\n self.__ids = ids;\n for (let i = 0; i < ids.length; i++) {\n // If we already have it, don't add again\n if (id === ids[i]) {\n return;\n }\n }\n ids.push(id);\n }\n }\n\n deleteID(id: string): void {\n const self = this.getWritable();\n if ($isThreadMarkNode(self)) {\n const ids = self.__ids;\n self.__ids = ids;\n for (let i = 0; i < ids.length; i++) {\n if (id === ids[i]) {\n ids.splice(i, 1);\n return;\n }\n }\n }\n }\n\n insertNewAfter(\n _: RangeSelection,\n restoreSelection = true\n ): null | ElementNode {\n const markNode = $createThreadMarkNode(this.__ids);\n this.insertAfter(markNode, restoreSelection);\n return markNode;\n }\n\n canInsertTextBefore(): false {\n return false;\n }\n\n canInsertTextAfter(): false {\n return false;\n }\n\n canBeEmpty(): false {\n return false;\n }\n\n isInline(): true {\n return true;\n }\n\n extractWithChild(\n _: LexicalNode,\n selection: BaseSelection,\n destination: \"clone\" | \"html\"\n ): boolean {\n if (!$isRangeSelection(selection) || destination === \"html\") {\n return false;\n }\n const anchor = selection.anchor;\n const focus = selection.focus;\n const anchorNode = anchor.getNode();\n const focusNode = focus.getNode();\n const isBackward = selection.isBackward();\n const selectionLength = isBackward\n ? anchor.offset - focus.offset\n : focus.offset - anchor.offset;\n return (\n this.isParentOf(anchorNode) &&\n this.isParentOf(focusNode) &&\n this.getTextContent().length === selectionLength\n );\n }\n\n excludeFromCopy(destination: \"clone\" | \"html\"): boolean {\n return destination !== \"clone\";\n }\n}\n\nexport function $createThreadMarkNode(ids: Array<string>): ThreadMarkNode {\n return $applyNodeReplacement(new ThreadMarkNode(ids));\n}\n\nexport function $isThreadMarkNode(\n node: LexicalNode | null\n): node is ThreadMarkNode {\n return node instanceof ThreadMarkNode;\n}\n"],"names":["ElementNode","$isRangeSelection","$applyNodeReplacement"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"thread-mark-node.mjs","sources":["../../src/comments/thread-mark-node.ts"],"sourcesContent":["/**\n * MIT License\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n * \n * The above copyright notice and this permission notice shall be included in all\n * copies or substantial portions of the Software.\n * \n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\nimport type {\n BaseSelection,\n LexicalNode,\n NodeKey,\n RangeSelection,\n SerializedElementNode,\n Spread,\n} from \"lexical\";\nimport { $applyNodeReplacement, $isRangeSelection, ElementNode } from \"lexical\";\n\nexport type SerializedThreadMarkNode = Spread<\n {\n ids: Array<string>;\n },\n SerializedElementNode\n>;\n\nexport class ThreadMarkNode extends ElementNode {\n /** @internal */\n __ids: Array<string>; // The ids of the threads that this mark is associated with\n\n static getType(): string {\n return \"lb-thread-mark\";\n }\n\n static clone(node: ThreadMarkNode): ThreadMarkNode {\n return new ThreadMarkNode(Array.from(node.__ids), node.__key);\n }\n\n static importDOM(): null {\n return null;\n }\n\n static importJSON(serializedNode: SerializedThreadMarkNode): ThreadMarkNode {\n const node = $createThreadMarkNode(serializedNode.ids);\n node.setFormat(serializedNode.format);\n node.setIndent(serializedNode.indent);\n node.setDirection(serializedNode.direction);\n return node;\n }\n\n exportJSON(): SerializedThreadMarkNode {\n return {\n ...super.exportJSON(),\n ids: this.getIDs(),\n type: \"lb-thread-mark\",\n version: 1,\n };\n }\n\n constructor(ids: Array<string>, key?: NodeKey) {\n super(key);\n this.__ids = ids || [];\n }\n\n createDOM(): HTMLElement {\n const element = document.createElement(\"span\");\n return element;\n }\n\n updateDOM(): boolean {\n return false;\n }\n\n hasID(id: string): boolean {\n const ids = this.getIDs();\n for (let i = 0; i < ids.length; i++) {\n if (id === ids[i]) {\n return true;\n }\n }\n return false;\n }\n\n getIDs(): Array<string> {\n const self = this.getLatest();\n return $isThreadMarkNode(self) ? self.__ids : [];\n }\n\n addID(id: string): void {\n const self = this.getWritable();\n if ($isThreadMarkNode(self)) {\n const ids = self.__ids;\n self.__ids = ids;\n for (let i = 0; i < ids.length; i++) {\n // If we already have it, don't add again\n if (id === ids[i]) {\n return;\n }\n }\n ids.push(id);\n }\n }\n\n deleteID(id: string): void {\n const self = this.getWritable();\n if ($isThreadMarkNode(self)) {\n const ids = self.__ids;\n self.__ids = ids;\n for (let i = 0; i < ids.length; i++) {\n if (id === ids[i]) {\n ids.splice(i, 1);\n return;\n }\n }\n }\n }\n\n insertNewAfter(\n _: RangeSelection,\n restoreSelection = true\n ): null | ElementNode {\n const markNode = $createThreadMarkNode(this.__ids);\n this.insertAfter(markNode, restoreSelection);\n return markNode;\n }\n\n canInsertTextBefore(): false {\n return false;\n }\n\n canInsertTextAfter(): false {\n return false;\n }\n\n canBeEmpty(): false {\n return false;\n }\n\n isInline(): true {\n return true;\n }\n\n extractWithChild(\n _: LexicalNode,\n selection: BaseSelection,\n destination: \"clone\" | \"html\"\n ): boolean {\n if (!$isRangeSelection(selection) || destination === \"html\") {\n return false;\n }\n const anchor = selection.anchor;\n const focus = selection.focus;\n const anchorNode = anchor.getNode();\n const focusNode = focus.getNode();\n const isBackward = selection.isBackward();\n const selectionLength = isBackward\n ? anchor.offset - focus.offset\n : focus.offset - anchor.offset;\n return (\n this.isParentOf(anchorNode) &&\n this.isParentOf(focusNode) &&\n this.getTextContent().length === selectionLength\n );\n }\n\n excludeFromCopy(destination: \"clone\" | \"html\"): boolean {\n return destination !== \"clone\";\n }\n}\n\nexport function $createThreadMarkNode(ids: Array<string>): ThreadMarkNode {\n return $applyNodeReplacement(new ThreadMarkNode(ids));\n}\n\nexport function $isThreadMarkNode(\n node: LexicalNode | null\n): node is ThreadMarkNode {\n return node instanceof ThreadMarkNode;\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"thread-mark-node.mjs","sources":["../../src/comments/thread-mark-node.ts"],"sourcesContent":["import type {\n BaseSelection,\n LexicalNode,\n NodeKey,\n RangeSelection,\n SerializedElementNode,\n Spread,\n} from \"lexical\";\nimport { $applyNodeReplacement, $isRangeSelection, ElementNode } from \"lexical\";\n\nexport type SerializedThreadMarkNode = Spread<\n {\n ids: Array<string>;\n },\n SerializedElementNode\n>;\n\nexport class ThreadMarkNode extends ElementNode {\n /** @internal */\n __ids: Array<string>; // The ids of the threads that this mark is associated with\n\n static getType(): string {\n return \"lb-thread-mark\";\n }\n\n static clone(node: ThreadMarkNode): ThreadMarkNode {\n return new ThreadMarkNode(Array.from(node.__ids), node.__key);\n }\n\n static importDOM(): null {\n return null;\n }\n\n static importJSON(serializedNode: SerializedThreadMarkNode): ThreadMarkNode {\n const node = $createThreadMarkNode(serializedNode.ids);\n node.setFormat(serializedNode.format);\n node.setIndent(serializedNode.indent);\n node.setDirection(serializedNode.direction);\n return node;\n }\n\n exportJSON(): SerializedThreadMarkNode {\n return {\n ...super.exportJSON(),\n ids: this.getIDs(),\n type: \"lb-thread-mark\",\n version: 1,\n };\n }\n\n constructor(ids: Array<string>, key?: NodeKey) {\n super(key);\n this.__ids = ids || [];\n }\n\n createDOM(): HTMLElement {\n const element = document.createElement(\"span\");\n return element;\n }\n\n updateDOM(): boolean {\n return false;\n }\n\n hasID(id: string): boolean {\n const ids = this.getIDs();\n for (let i = 0; i < ids.length; i++) {\n if (id === ids[i]) {\n return true;\n }\n }\n return false;\n }\n\n getIDs(): Array<string> {\n const self = this.getLatest();\n return $isThreadMarkNode(self) ? self.__ids : [];\n }\n\n addID(id: string): void {\n const self = this.getWritable();\n if ($isThreadMarkNode(self)) {\n const ids = self.__ids;\n self.__ids = ids;\n for (let i = 0; i < ids.length; i++) {\n // If we already have it, don't add again\n if (id === ids[i]) {\n return;\n }\n }\n ids.push(id);\n }\n }\n\n deleteID(id: string): void {\n const self = this.getWritable();\n if ($isThreadMarkNode(self)) {\n const ids = self.__ids;\n self.__ids = ids;\n for (let i = 0; i < ids.length; i++) {\n if (id === ids[i]) {\n ids.splice(i, 1);\n return;\n }\n }\n }\n }\n\n insertNewAfter(\n _: RangeSelection,\n restoreSelection = true\n ): null | ElementNode {\n const markNode = $createThreadMarkNode(this.__ids);\n this.insertAfter(markNode, restoreSelection);\n return markNode;\n }\n\n canInsertTextBefore(): false {\n return false;\n }\n\n canInsertTextAfter(): false {\n return false;\n }\n\n canBeEmpty(): false {\n return false;\n }\n\n isInline(): true {\n return true;\n }\n\n extractWithChild(\n _: LexicalNode,\n selection: BaseSelection,\n destination: \"clone\" | \"html\"\n ): boolean {\n if (!$isRangeSelection(selection) || destination === \"html\") {\n return false;\n }\n const anchor = selection.anchor;\n const focus = selection.focus;\n const anchorNode = anchor.getNode();\n const focusNode = focus.getNode();\n const isBackward = selection.isBackward();\n const selectionLength = isBackward\n ? anchor.offset - focus.offset\n : focus.offset - anchor.offset;\n return (\n this.isParentOf(anchorNode) &&\n this.isParentOf(focusNode) &&\n this.getTextContent().length === selectionLength\n );\n }\n\n excludeFromCopy(destination: \"clone\" | \"html\"): boolean {\n return destination !== \"clone\";\n }\n}\n\nexport function $createThreadMarkNode(ids: Array<string>): ThreadMarkNode {\n return $applyNodeReplacement(new ThreadMarkNode(ids));\n}\n\nexport function $isThreadMarkNode(\n node: LexicalNode | null\n): node is ThreadMarkNode {\n return node instanceof ThreadMarkNode;\n}\n"],"names":[],"mappings":"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"}
@@ -8,6 +8,7 @@ var core = require('@liveblocks/core');
8
8
  var react = require('@liveblocks/react');
9
9
  var yjs$1 = require('@liveblocks/yjs');
10
10
  var React = require('react');
11
+ var index_js = require('use-sync-external-store/shim/index.js');
11
12
  var yjs = require('yjs');
12
13
  var commentPluginProvider = require('./comments/comment-plugin-provider.js');
13
14
  var threadMarkNode = require('./comments/thread-mark-node.js');
@@ -106,14 +107,14 @@ const LiveblocksPlugin = ({
106
107
  React.useEffect(() => {
107
108
  collabContext.name = username || "";
108
109
  }, [collabContext, username]);
110
+ const root = useRootElement();
109
111
  React.useLayoutEffect(() => {
110
- const editable = editor.getRootElement();
111
- if (editable === null)
112
+ if (root === null)
112
113
  return;
113
114
  setReference({
114
- getBoundingClientRect: () => editable.getBoundingClientRect()
115
+ getBoundingClientRect: () => root.getBoundingClientRect()
115
116
  });
116
- }, [setReference, editor]);
117
+ }, [setReference, root]);
117
118
  const handleFloatingRef = React.useCallback(
118
119
  (node) => {
119
120
  setFloating(node);
@@ -140,6 +141,19 @@ const LiveblocksPlugin = ({
140
141
  shouldBootstrap: true
141
142
  }), hasResolveMentionSuggestions && /* @__PURE__ */ React.createElement(mentionPlugin.MentionPlugin, null), /* @__PURE__ */ React.createElement(commentPluginProvider.CommentPluginProvider, null, children));
142
143
  };
144
+ function useRootElement() {
145
+ const [editor] = LexicalComposerContext.useLexicalComposerContext();
146
+ const subscribe = React.useCallback(
147
+ (onStoreChange) => {
148
+ return editor.registerRootListener(onStoreChange);
149
+ },
150
+ [editor]
151
+ );
152
+ const getSnapshot = React.useCallback(() => {
153
+ return editor.getRootElement();
154
+ }, [editor]);
155
+ return index_js.useSyncExternalStore(subscribe, getSnapshot, getSnapshot);
156
+ }
143
157
 
144
158
  exports.LiveblocksPlugin = LiveblocksPlugin;
145
159
  exports.useEditorStatus = useEditorStatus;
@@ -1 +1 @@
1
- {"version":3,"file":"liveblocks-plugin-provider.js","sources":["../src/liveblocks-plugin-provider.tsx"],"sourcesContent":["import { autoUpdate, useFloating } from \"@floating-ui/react-dom\";\nimport { CollaborationContext } from \"@lexical/react/LexicalCollaborationContext\";\nimport { CollaborationPlugin } from \"@lexical/react/LexicalCollaborationPlugin\";\nimport { useLexicalComposerContext } from \"@lexical/react/LexicalComposerContext\";\nimport type { Provider } from \"@lexical/yjs\";\nimport { kInternal, nn } from \"@liveblocks/core\";\nimport { useClient, useRoom, useSelf } from \"@liveblocks/react\";\nimport { LiveblocksYjsProvider } from \"@liveblocks/yjs\";\nimport type { MutableRefObject } from \"react\";\nimport React, {\n useCallback,\n useContext,\n useEffect,\n useLayoutEffect,\n useRef,\n useState,\n} from \"react\";\nimport { Doc } from \"yjs\";\n\nimport { CommentPluginProvider } from \"./comments/comment-plugin-provider\";\nimport { ThreadMarkNode } from \"./comments/thread-mark-node\";\nimport { MentionNode } from \"./mentions/mention-node\";\nimport { MentionPlugin } from \"./mentions/mention-plugin\";\n\n// TODO: Replace by ref once I understand why useRef is not stable (?!)\nconst providersMap = new Map<\n string,\n LiveblocksYjsProvider<never, never, never, never, never>\n>();\n\nexport type EditorStatus =\n /* The editor state is not loaded and has not been requested. */\n | \"not-loaded\"\n /* The editor state is loading from Liveblocks servers */\n | \"loading\"\n /**\n * Not working yet! Will be available in a future release.\n * Some editor state modifications has not been acknowledged yet by the server\n */\n | \"synchronizing\"\n /* The editor state is sync with Liveblocks servers */\n | \"synchronized\";\n\nfunction getEditorStatus(\n provider?: LiveblocksYjsProvider<never, never, never, never, never>\n) {\n if (provider === undefined) {\n return \"not-loaded\";\n }\n\n return provider.synced ? \"synchronized\" : \"loading\";\n}\n\n/**\n * Get the storage status.\n *\n * - `not-loaded`: Initial state when entering the room.\n * - `loading`: Once the editor state has been requested by LiveblocksPlugin.\n * - `synchronizing`: Not working yet! Will be available in a future release.\n * - `synchronized`: The editor state is sync with Liveblocks servers.\n */\nexport function useEditorStatus(): EditorStatus {\n const room = useRoom();\n const provider = providersMap.get(room.id);\n\n const [status, setStatus] = useState<EditorStatus>(getEditorStatus(provider));\n\n useEffect(() => {\n const provider = providersMap.get(room.id);\n\n setStatus(getEditorStatus(provider));\n\n if (provider === undefined) {\n return;\n }\n\n const cb = () => setStatus(getEditorStatus(provider));\n\n provider.on(\"sync\", cb);\n\n return () => provider.off(\"sync\", cb);\n }, [room]);\n\n return status;\n}\n\nexport type LiveblocksPluginProps = {\n children?: React.ReactNode;\n};\n\n/**\n * Liveblocks plugin for Lexical that adds collaboration to your editor.\n *\n * `LiveblocksPlugin` should always be nested inside `LexicalComposer`.\n *\n * @example\n *\n * import { LexicalComposer } from \"@lexical/react/LexicalComposer\";\n * import { RichTextPlugin } from \"@lexical/react/LexicalRichTextPlugin\";\n * import { ContentEditable } from \"@lexical/react/LexicalContentEditable\";\n * import { LexicalErrorBoundary } from \"@lexical/react/LexicalErrorBoundary\";\n * import { liveblocksConfig, LiveblocksPlugin } from \"@liveblocks/react-lexical\";\n *\n * const initialConfig = liveblocksConfig({\n * namespace: \"MyEditor\",\n * theme: {},\n * nodes: [],\n * onError: (err) => console.error(err),\n * });\n *\n * function Editor() {\n * return (\n * <LexicalComposer initialConfig={initialConfig}>\n * <LiveblocksPlugin />\n * <RichTextPlugin\n * contentEditable={<ContentEditable />}\n * placeholder={<div>Enter some text...</div>}\n * ErrorBoundary={LexicalErrorBoundary}\n * />\n * </LexicalComposer>\n * );\n * }\n */\nexport const LiveblocksPlugin = ({\n children,\n}: LiveblocksPluginProps): JSX.Element => {\n const client = useClient();\n const hasResolveMentionSuggestions =\n client[kInternal].resolveMentionSuggestions !== undefined;\n const [editor] = useLexicalComposerContext();\n const room = useRoom();\n const collabContext = useContext(CollaborationContext);\n const previousRoomIdRef = useRef<string | null>(null);\n\n if (!editor.hasNodes([ThreadMarkNode, MentionNode])) {\n throw new Error(\n \"LiveblocksPlugin requires Lexical configuration to be wrapped in the `liveblocksConfig(options)` function. For more information: https://liveblocks.io/docs/api-reference/liveblocks-react-lexical#liveblocksConfig\"\n );\n }\n\n const [containerRef, setContainerRef] = useState<\n MutableRefObject<HTMLDivElement | null> | undefined\n >(undefined);\n\n const {\n refs: { setReference, setFloating },\n strategy,\n x,\n y,\n } = useFloating({\n strategy: \"fixed\",\n placement: \"bottom\",\n whileElementsMounted: (...args) => {\n return autoUpdate(...args, {\n animationFrame: true,\n });\n },\n });\n\n // Warn users if initialConfig.editorState, set on the composer, is not null\n useEffect(() => {\n // only in dev mode\n if (process.env.NODE_ENV !== \"production\") {\n // A user should not even be set an emptyState, but when passing null, getEditorState still has initial empty state\n if (!editor.getEditorState().isEmpty()) {\n console.warn(\n \"Warning: LiveblocksPlugin: editorState in initialConfig detected, but must be null.\"\n );\n }\n }\n\n // we know editor is already defined as we're inside LexicalComposer, and we only want this running the first time\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n useEffect(() => {\n // Report that this is lexical and root is the rootKey\n room[kInternal].reportTextEditor(\"lexical\", \"root\");\n }, [room]);\n\n // Get user info or allow override from props\n const info = useSelf((me) => me.info);\n const username = info?.name || \"\"; // use empty string to prevent random name\n const cursorcolor = info?.color as string | undefined;\n\n const providerFactory = useCallback(\n (id: string, yjsDocMap: Map<string, Doc>): Provider => {\n // Destroy previously used provider to avoid memory leaks\n // TODO: Find a way to destroy the last used provider on unmount (while working with StrictMode)\n if (\n previousRoomIdRef.current !== null &&\n previousRoomIdRef.current !== id\n ) {\n const previousProvider = providersMap.get(id);\n if (previousProvider !== undefined) {\n previousProvider.destroy();\n }\n }\n\n let doc = yjsDocMap.get(id);\n\n if (doc === undefined) {\n doc = new Doc();\n const provider = new LiveblocksYjsProvider(room, doc);\n yjsDocMap.set(id, doc);\n providersMap.set(id, provider);\n }\n\n return nn(\n providersMap.get(id),\n \"Internal error. Should never happen\"\n ) as Provider;\n },\n [room]\n );\n\n useEffect(() => {\n collabContext.name = username || \"\";\n }, [collabContext, username]);\n\n useLayoutEffect(() => {\n const editable = editor.getRootElement();\n if (editable === null) return;\n\n setReference({\n getBoundingClientRect: () => editable.getBoundingClientRect(),\n });\n }, [setReference, editor]);\n\n const handleFloatingRef = useCallback(\n (node: HTMLDivElement) => {\n setFloating(node);\n setContainerRef({ current: node });\n },\n [setFloating, setContainerRef]\n );\n\n return (\n <>\n <div\n ref={handleFloatingRef}\n style={{\n position: strategy,\n top: 0,\n left: 0,\n transform: `translate3d(${Math.round(x)}px, ${Math.round(y)}px, 0)`,\n minWidth: \"max-content\",\n }}\n />\n\n <CollaborationPlugin\n // Setting the key allows us to reset the internal Y.doc used by useYjsCollaboration\n // without implementing `reload` event\n key={room.id}\n id={room.id}\n providerFactory={providerFactory}\n username={username}\n cursorColor={cursorcolor}\n cursorsContainerRef={containerRef}\n shouldBootstrap={true}\n />\n\n {hasResolveMentionSuggestions && <MentionPlugin />}\n\n <CommentPluginProvider>{children}</CommentPluginProvider>\n </>\n );\n};\n"],"names":["useRoom","useState","useEffect","provider","useClient","kInternal","useLexicalComposerContext","useContext","CollaborationContext","useRef","ThreadMarkNode","MentionNode","useFloating","autoUpdate","useSelf","useCallback","Doc","LiveblocksYjsProvider","nn","useLayoutEffect","CollaborationPlugin","MentionPlugin","CommentPluginProvider"],"mappings":"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"}
1
+ {"version":3,"file":"liveblocks-plugin-provider.js","sources":["../src/liveblocks-plugin-provider.tsx"],"sourcesContent":["import { autoUpdate, useFloating } from \"@floating-ui/react-dom\";\nimport { CollaborationContext } from \"@lexical/react/LexicalCollaborationContext\";\nimport { CollaborationPlugin } from \"@lexical/react/LexicalCollaborationPlugin\";\nimport { useLexicalComposerContext } from \"@lexical/react/LexicalComposerContext\";\nimport type { Provider } from \"@lexical/yjs\";\nimport { kInternal, nn } from \"@liveblocks/core\";\nimport { useClient, useRoom, useSelf } from \"@liveblocks/react\";\nimport { LiveblocksYjsProvider } from \"@liveblocks/yjs\";\nimport type { MutableRefObject } from \"react\";\nimport React, {\n useCallback,\n useContext,\n useEffect,\n useLayoutEffect,\n useRef,\n useState,\n} from \"react\";\nimport { useSyncExternalStore } from \"use-sync-external-store/shim/index.js\";\nimport { Doc } from \"yjs\";\n\nimport { CommentPluginProvider } from \"./comments/comment-plugin-provider\";\nimport { ThreadMarkNode } from \"./comments/thread-mark-node\";\nimport { MentionNode } from \"./mentions/mention-node\";\nimport { MentionPlugin } from \"./mentions/mention-plugin\";\n\n// TODO: Replace by ref once I understand why useRef is not stable (?!)\nconst providersMap = new Map<\n string,\n LiveblocksYjsProvider<never, never, never, never, never>\n>();\n\nexport type EditorStatus =\n /* The editor state is not loaded and has not been requested. */\n | \"not-loaded\"\n /* The editor state is loading from Liveblocks servers */\n | \"loading\"\n /**\n * Not working yet! Will be available in a future release.\n * Some editor state modifications has not been acknowledged yet by the server\n */\n | \"synchronizing\"\n /* The editor state is sync with Liveblocks servers */\n | \"synchronized\";\n\nfunction getEditorStatus(\n provider?: LiveblocksYjsProvider<never, never, never, never, never>\n) {\n if (provider === undefined) {\n return \"not-loaded\";\n }\n\n return provider.synced ? \"synchronized\" : \"loading\";\n}\n\n/**\n * Get the storage status.\n *\n * - `not-loaded`: Initial state when entering the room.\n * - `loading`: Once the editor state has been requested by LiveblocksPlugin.\n * - `synchronizing`: Not working yet! Will be available in a future release.\n * - `synchronized`: The editor state is sync with Liveblocks servers.\n */\nexport function useEditorStatus(): EditorStatus {\n const room = useRoom();\n const provider = providersMap.get(room.id);\n\n const [status, setStatus] = useState<EditorStatus>(getEditorStatus(provider));\n\n useEffect(() => {\n const provider = providersMap.get(room.id);\n\n setStatus(getEditorStatus(provider));\n\n if (provider === undefined) {\n return;\n }\n\n const cb = () => setStatus(getEditorStatus(provider));\n\n provider.on(\"sync\", cb);\n\n return () => provider.off(\"sync\", cb);\n }, [room]);\n\n return status;\n}\n\nexport type LiveblocksPluginProps = {\n children?: React.ReactNode;\n};\n\n/**\n * Liveblocks plugin for Lexical that adds collaboration to your editor.\n *\n * `LiveblocksPlugin` should always be nested inside `LexicalComposer`.\n *\n * @example\n *\n * import { LexicalComposer } from \"@lexical/react/LexicalComposer\";\n * import { RichTextPlugin } from \"@lexical/react/LexicalRichTextPlugin\";\n * import { ContentEditable } from \"@lexical/react/LexicalContentEditable\";\n * import { LexicalErrorBoundary } from \"@lexical/react/LexicalErrorBoundary\";\n * import { liveblocksConfig, LiveblocksPlugin } from \"@liveblocks/react-lexical\";\n *\n * const initialConfig = liveblocksConfig({\n * namespace: \"MyEditor\",\n * theme: {},\n * nodes: [],\n * onError: (err) => console.error(err),\n * });\n *\n * function Editor() {\n * return (\n * <LexicalComposer initialConfig={initialConfig}>\n * <LiveblocksPlugin />\n * <RichTextPlugin\n * contentEditable={<ContentEditable />}\n * placeholder={<div>Enter some text...</div>}\n * ErrorBoundary={LexicalErrorBoundary}\n * />\n * </LexicalComposer>\n * );\n * }\n */\nexport const LiveblocksPlugin = ({\n children,\n}: LiveblocksPluginProps): JSX.Element => {\n const client = useClient();\n const hasResolveMentionSuggestions =\n client[kInternal].resolveMentionSuggestions !== undefined;\n const [editor] = useLexicalComposerContext();\n const room = useRoom();\n const collabContext = useContext(CollaborationContext);\n const previousRoomIdRef = useRef<string | null>(null);\n\n if (!editor.hasNodes([ThreadMarkNode, MentionNode])) {\n throw new Error(\n \"LiveblocksPlugin requires Lexical configuration to be wrapped in the `liveblocksConfig(options)` function. For more information: https://liveblocks.io/docs/api-reference/liveblocks-react-lexical#liveblocksConfig\"\n );\n }\n\n const [containerRef, setContainerRef] = useState<\n MutableRefObject<HTMLDivElement | null> | undefined\n >(undefined);\n\n const {\n refs: { setReference, setFloating },\n strategy,\n x,\n y,\n } = useFloating({\n strategy: \"fixed\",\n placement: \"bottom\",\n whileElementsMounted: (...args) => {\n return autoUpdate(...args, {\n animationFrame: true,\n });\n },\n });\n\n // Warn users if initialConfig.editorState, set on the composer, is not null\n useEffect(() => {\n // only in dev mode\n if (process.env.NODE_ENV !== \"production\") {\n // A user should not even be set an emptyState, but when passing null, getEditorState still has initial empty state\n if (!editor.getEditorState().isEmpty()) {\n console.warn(\n \"Warning: LiveblocksPlugin: editorState in initialConfig detected, but must be null.\"\n );\n }\n }\n\n // we know editor is already defined as we're inside LexicalComposer, and we only want this running the first time\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n useEffect(() => {\n // Report that this is lexical and root is the rootKey\n room[kInternal].reportTextEditor(\"lexical\", \"root\");\n }, [room]);\n\n // Get user info or allow override from props\n const info = useSelf((me) => me.info);\n const username = info?.name || \"\"; // use empty string to prevent random name\n const cursorcolor = info?.color as string | undefined;\n\n const providerFactory = useCallback(\n (id: string, yjsDocMap: Map<string, Doc>): Provider => {\n // Destroy previously used provider to avoid memory leaks\n // TODO: Find a way to destroy the last used provider on unmount (while working with StrictMode)\n if (\n previousRoomIdRef.current !== null &&\n previousRoomIdRef.current !== id\n ) {\n const previousProvider = providersMap.get(id);\n if (previousProvider !== undefined) {\n previousProvider.destroy();\n }\n }\n\n let doc = yjsDocMap.get(id);\n\n if (doc === undefined) {\n doc = new Doc();\n const provider = new LiveblocksYjsProvider(room, doc);\n yjsDocMap.set(id, doc);\n providersMap.set(id, provider);\n }\n\n return nn(\n providersMap.get(id),\n \"Internal error. Should never happen\"\n ) as Provider;\n },\n [room]\n );\n\n useEffect(() => {\n collabContext.name = username || \"\";\n }, [collabContext, username]);\n\n const root = useRootElement();\n\n useLayoutEffect(() => {\n if (root === null) return;\n setReference({\n getBoundingClientRect: () => root.getBoundingClientRect(),\n });\n }, [setReference, root]);\n\n const handleFloatingRef = useCallback(\n (node: HTMLDivElement) => {\n setFloating(node);\n setContainerRef({ current: node });\n },\n [setFloating, setContainerRef]\n );\n\n return (\n <>\n <div\n ref={handleFloatingRef}\n style={{\n position: strategy,\n top: 0,\n left: 0,\n transform: `translate3d(${Math.round(x)}px, ${Math.round(y)}px, 0)`,\n minWidth: \"max-content\",\n }}\n />\n\n <CollaborationPlugin\n // Setting the key allows us to reset the internal Y.doc used by useYjsCollaboration\n // without implementing `reload` event\n key={room.id}\n id={room.id}\n providerFactory={providerFactory}\n username={username}\n cursorColor={cursorcolor}\n cursorsContainerRef={containerRef}\n shouldBootstrap={true}\n />\n\n {hasResolveMentionSuggestions && <MentionPlugin />}\n\n <CommentPluginProvider>{children}</CommentPluginProvider>\n </>\n );\n};\n\nfunction useRootElement(): HTMLElement | null {\n const [editor] = useLexicalComposerContext();\n\n const subscribe = useCallback(\n (onStoreChange: () => void) => {\n return editor.registerRootListener(onStoreChange);\n },\n [editor]\n );\n\n const getSnapshot = useCallback(() => {\n return editor.getRootElement();\n }, [editor]);\n\n return useSyncExternalStore(subscribe, getSnapshot, getSnapshot);\n}\n"],"names":["useRoom","useState","useEffect","provider","useClient","kInternal","useLexicalComposerContext","useContext","CollaborationContext","useRef","ThreadMarkNode","MentionNode","useFloating","autoUpdate","useSelf","useCallback","Doc","LiveblocksYjsProvider","nn","useLayoutEffect","CollaborationPlugin","MentionPlugin","CommentPluginProvider","useSyncExternalStore"],"mappings":"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"}
@@ -6,6 +6,7 @@ import { kInternal, nn } from '@liveblocks/core';
6
6
  import { useRoom, useClient, useSelf } from '@liveblocks/react';
7
7
  import { LiveblocksYjsProvider } from '@liveblocks/yjs';
8
8
  import React__default, { useState, useEffect, useContext, useRef, useCallback, useLayoutEffect } from 'react';
9
+ import { useSyncExternalStore } from 'use-sync-external-store/shim/index.js';
9
10
  import { Doc } from 'yjs';
10
11
  import { CommentPluginProvider } from './comments/comment-plugin-provider.mjs';
11
12
  import { ThreadMarkNode } from './comments/thread-mark-node.mjs';
@@ -104,14 +105,14 @@ const LiveblocksPlugin = ({
104
105
  useEffect(() => {
105
106
  collabContext.name = username || "";
106
107
  }, [collabContext, username]);
108
+ const root = useRootElement();
107
109
  useLayoutEffect(() => {
108
- const editable = editor.getRootElement();
109
- if (editable === null)
110
+ if (root === null)
110
111
  return;
111
112
  setReference({
112
- getBoundingClientRect: () => editable.getBoundingClientRect()
113
+ getBoundingClientRect: () => root.getBoundingClientRect()
113
114
  });
114
- }, [setReference, editor]);
115
+ }, [setReference, root]);
115
116
  const handleFloatingRef = useCallback(
116
117
  (node) => {
117
118
  setFloating(node);
@@ -138,6 +139,19 @@ const LiveblocksPlugin = ({
138
139
  shouldBootstrap: true
139
140
  }), hasResolveMentionSuggestions && /* @__PURE__ */ React__default.createElement(MentionPlugin, null), /* @__PURE__ */ React__default.createElement(CommentPluginProvider, null, children));
140
141
  };
142
+ function useRootElement() {
143
+ const [editor] = useLexicalComposerContext();
144
+ const subscribe = useCallback(
145
+ (onStoreChange) => {
146
+ return editor.registerRootListener(onStoreChange);
147
+ },
148
+ [editor]
149
+ );
150
+ const getSnapshot = useCallback(() => {
151
+ return editor.getRootElement();
152
+ }, [editor]);
153
+ return useSyncExternalStore(subscribe, getSnapshot, getSnapshot);
154
+ }
141
155
 
142
156
  export { LiveblocksPlugin, useEditorStatus };
143
157
  //# sourceMappingURL=liveblocks-plugin-provider.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"liveblocks-plugin-provider.mjs","sources":["../src/liveblocks-plugin-provider.tsx"],"sourcesContent":["import { autoUpdate, useFloating } from \"@floating-ui/react-dom\";\nimport { CollaborationContext } from \"@lexical/react/LexicalCollaborationContext\";\nimport { CollaborationPlugin } from \"@lexical/react/LexicalCollaborationPlugin\";\nimport { useLexicalComposerContext } from \"@lexical/react/LexicalComposerContext\";\nimport type { Provider } from \"@lexical/yjs\";\nimport { kInternal, nn } from \"@liveblocks/core\";\nimport { useClient, useRoom, useSelf } from \"@liveblocks/react\";\nimport { LiveblocksYjsProvider } from \"@liveblocks/yjs\";\nimport type { MutableRefObject } from \"react\";\nimport React, {\n useCallback,\n useContext,\n useEffect,\n useLayoutEffect,\n useRef,\n useState,\n} from \"react\";\nimport { Doc } from \"yjs\";\n\nimport { CommentPluginProvider } from \"./comments/comment-plugin-provider\";\nimport { ThreadMarkNode } from \"./comments/thread-mark-node\";\nimport { MentionNode } from \"./mentions/mention-node\";\nimport { MentionPlugin } from \"./mentions/mention-plugin\";\n\n// TODO: Replace by ref once I understand why useRef is not stable (?!)\nconst providersMap = new Map<\n string,\n LiveblocksYjsProvider<never, never, never, never, never>\n>();\n\nexport type EditorStatus =\n /* The editor state is not loaded and has not been requested. */\n | \"not-loaded\"\n /* The editor state is loading from Liveblocks servers */\n | \"loading\"\n /**\n * Not working yet! Will be available in a future release.\n * Some editor state modifications has not been acknowledged yet by the server\n */\n | \"synchronizing\"\n /* The editor state is sync with Liveblocks servers */\n | \"synchronized\";\n\nfunction getEditorStatus(\n provider?: LiveblocksYjsProvider<never, never, never, never, never>\n) {\n if (provider === undefined) {\n return \"not-loaded\";\n }\n\n return provider.synced ? \"synchronized\" : \"loading\";\n}\n\n/**\n * Get the storage status.\n *\n * - `not-loaded`: Initial state when entering the room.\n * - `loading`: Once the editor state has been requested by LiveblocksPlugin.\n * - `synchronizing`: Not working yet! Will be available in a future release.\n * - `synchronized`: The editor state is sync with Liveblocks servers.\n */\nexport function useEditorStatus(): EditorStatus {\n const room = useRoom();\n const provider = providersMap.get(room.id);\n\n const [status, setStatus] = useState<EditorStatus>(getEditorStatus(provider));\n\n useEffect(() => {\n const provider = providersMap.get(room.id);\n\n setStatus(getEditorStatus(provider));\n\n if (provider === undefined) {\n return;\n }\n\n const cb = () => setStatus(getEditorStatus(provider));\n\n provider.on(\"sync\", cb);\n\n return () => provider.off(\"sync\", cb);\n }, [room]);\n\n return status;\n}\n\nexport type LiveblocksPluginProps = {\n children?: React.ReactNode;\n};\n\n/**\n * Liveblocks plugin for Lexical that adds collaboration to your editor.\n *\n * `LiveblocksPlugin` should always be nested inside `LexicalComposer`.\n *\n * @example\n *\n * import { LexicalComposer } from \"@lexical/react/LexicalComposer\";\n * import { RichTextPlugin } from \"@lexical/react/LexicalRichTextPlugin\";\n * import { ContentEditable } from \"@lexical/react/LexicalContentEditable\";\n * import { LexicalErrorBoundary } from \"@lexical/react/LexicalErrorBoundary\";\n * import { liveblocksConfig, LiveblocksPlugin } from \"@liveblocks/react-lexical\";\n *\n * const initialConfig = liveblocksConfig({\n * namespace: \"MyEditor\",\n * theme: {},\n * nodes: [],\n * onError: (err) => console.error(err),\n * });\n *\n * function Editor() {\n * return (\n * <LexicalComposer initialConfig={initialConfig}>\n * <LiveblocksPlugin />\n * <RichTextPlugin\n * contentEditable={<ContentEditable />}\n * placeholder={<div>Enter some text...</div>}\n * ErrorBoundary={LexicalErrorBoundary}\n * />\n * </LexicalComposer>\n * );\n * }\n */\nexport const LiveblocksPlugin = ({\n children,\n}: LiveblocksPluginProps): JSX.Element => {\n const client = useClient();\n const hasResolveMentionSuggestions =\n client[kInternal].resolveMentionSuggestions !== undefined;\n const [editor] = useLexicalComposerContext();\n const room = useRoom();\n const collabContext = useContext(CollaborationContext);\n const previousRoomIdRef = useRef<string | null>(null);\n\n if (!editor.hasNodes([ThreadMarkNode, MentionNode])) {\n throw new Error(\n \"LiveblocksPlugin requires Lexical configuration to be wrapped in the `liveblocksConfig(options)` function. For more information: https://liveblocks.io/docs/api-reference/liveblocks-react-lexical#liveblocksConfig\"\n );\n }\n\n const [containerRef, setContainerRef] = useState<\n MutableRefObject<HTMLDivElement | null> | undefined\n >(undefined);\n\n const {\n refs: { setReference, setFloating },\n strategy,\n x,\n y,\n } = useFloating({\n strategy: \"fixed\",\n placement: \"bottom\",\n whileElementsMounted: (...args) => {\n return autoUpdate(...args, {\n animationFrame: true,\n });\n },\n });\n\n // Warn users if initialConfig.editorState, set on the composer, is not null\n useEffect(() => {\n // only in dev mode\n if (process.env.NODE_ENV !== \"production\") {\n // A user should not even be set an emptyState, but when passing null, getEditorState still has initial empty state\n if (!editor.getEditorState().isEmpty()) {\n console.warn(\n \"Warning: LiveblocksPlugin: editorState in initialConfig detected, but must be null.\"\n );\n }\n }\n\n // we know editor is already defined as we're inside LexicalComposer, and we only want this running the first time\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n useEffect(() => {\n // Report that this is lexical and root is the rootKey\n room[kInternal].reportTextEditor(\"lexical\", \"root\");\n }, [room]);\n\n // Get user info or allow override from props\n const info = useSelf((me) => me.info);\n const username = info?.name || \"\"; // use empty string to prevent random name\n const cursorcolor = info?.color as string | undefined;\n\n const providerFactory = useCallback(\n (id: string, yjsDocMap: Map<string, Doc>): Provider => {\n // Destroy previously used provider to avoid memory leaks\n // TODO: Find a way to destroy the last used provider on unmount (while working with StrictMode)\n if (\n previousRoomIdRef.current !== null &&\n previousRoomIdRef.current !== id\n ) {\n const previousProvider = providersMap.get(id);\n if (previousProvider !== undefined) {\n previousProvider.destroy();\n }\n }\n\n let doc = yjsDocMap.get(id);\n\n if (doc === undefined) {\n doc = new Doc();\n const provider = new LiveblocksYjsProvider(room, doc);\n yjsDocMap.set(id, doc);\n providersMap.set(id, provider);\n }\n\n return nn(\n providersMap.get(id),\n \"Internal error. Should never happen\"\n ) as Provider;\n },\n [room]\n );\n\n useEffect(() => {\n collabContext.name = username || \"\";\n }, [collabContext, username]);\n\n useLayoutEffect(() => {\n const editable = editor.getRootElement();\n if (editable === null) return;\n\n setReference({\n getBoundingClientRect: () => editable.getBoundingClientRect(),\n });\n }, [setReference, editor]);\n\n const handleFloatingRef = useCallback(\n (node: HTMLDivElement) => {\n setFloating(node);\n setContainerRef({ current: node });\n },\n [setFloating, setContainerRef]\n );\n\n return (\n <>\n <div\n ref={handleFloatingRef}\n style={{\n position: strategy,\n top: 0,\n left: 0,\n transform: `translate3d(${Math.round(x)}px, ${Math.round(y)}px, 0)`,\n minWidth: \"max-content\",\n }}\n />\n\n <CollaborationPlugin\n // Setting the key allows us to reset the internal Y.doc used by useYjsCollaboration\n // without implementing `reload` event\n key={room.id}\n id={room.id}\n providerFactory={providerFactory}\n username={username}\n cursorColor={cursorcolor}\n cursorsContainerRef={containerRef}\n shouldBootstrap={true}\n />\n\n {hasResolveMentionSuggestions && <MentionPlugin />}\n\n <CommentPluginProvider>{children}</CommentPluginProvider>\n </>\n );\n};\n"],"names":["provider","React"],"mappings":"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"}
1
+ {"version":3,"file":"liveblocks-plugin-provider.mjs","sources":["../src/liveblocks-plugin-provider.tsx"],"sourcesContent":["import { autoUpdate, useFloating } from \"@floating-ui/react-dom\";\nimport { CollaborationContext } from \"@lexical/react/LexicalCollaborationContext\";\nimport { CollaborationPlugin } from \"@lexical/react/LexicalCollaborationPlugin\";\nimport { useLexicalComposerContext } from \"@lexical/react/LexicalComposerContext\";\nimport type { Provider } from \"@lexical/yjs\";\nimport { kInternal, nn } from \"@liveblocks/core\";\nimport { useClient, useRoom, useSelf } from \"@liveblocks/react\";\nimport { LiveblocksYjsProvider } from \"@liveblocks/yjs\";\nimport type { MutableRefObject } from \"react\";\nimport React, {\n useCallback,\n useContext,\n useEffect,\n useLayoutEffect,\n useRef,\n useState,\n} from \"react\";\nimport { useSyncExternalStore } from \"use-sync-external-store/shim/index.js\";\nimport { Doc } from \"yjs\";\n\nimport { CommentPluginProvider } from \"./comments/comment-plugin-provider\";\nimport { ThreadMarkNode } from \"./comments/thread-mark-node\";\nimport { MentionNode } from \"./mentions/mention-node\";\nimport { MentionPlugin } from \"./mentions/mention-plugin\";\n\n// TODO: Replace by ref once I understand why useRef is not stable (?!)\nconst providersMap = new Map<\n string,\n LiveblocksYjsProvider<never, never, never, never, never>\n>();\n\nexport type EditorStatus =\n /* The editor state is not loaded and has not been requested. */\n | \"not-loaded\"\n /* The editor state is loading from Liveblocks servers */\n | \"loading\"\n /**\n * Not working yet! Will be available in a future release.\n * Some editor state modifications has not been acknowledged yet by the server\n */\n | \"synchronizing\"\n /* The editor state is sync with Liveblocks servers */\n | \"synchronized\";\n\nfunction getEditorStatus(\n provider?: LiveblocksYjsProvider<never, never, never, never, never>\n) {\n if (provider === undefined) {\n return \"not-loaded\";\n }\n\n return provider.synced ? \"synchronized\" : \"loading\";\n}\n\n/**\n * Get the storage status.\n *\n * - `not-loaded`: Initial state when entering the room.\n * - `loading`: Once the editor state has been requested by LiveblocksPlugin.\n * - `synchronizing`: Not working yet! Will be available in a future release.\n * - `synchronized`: The editor state is sync with Liveblocks servers.\n */\nexport function useEditorStatus(): EditorStatus {\n const room = useRoom();\n const provider = providersMap.get(room.id);\n\n const [status, setStatus] = useState<EditorStatus>(getEditorStatus(provider));\n\n useEffect(() => {\n const provider = providersMap.get(room.id);\n\n setStatus(getEditorStatus(provider));\n\n if (provider === undefined) {\n return;\n }\n\n const cb = () => setStatus(getEditorStatus(provider));\n\n provider.on(\"sync\", cb);\n\n return () => provider.off(\"sync\", cb);\n }, [room]);\n\n return status;\n}\n\nexport type LiveblocksPluginProps = {\n children?: React.ReactNode;\n};\n\n/**\n * Liveblocks plugin for Lexical that adds collaboration to your editor.\n *\n * `LiveblocksPlugin` should always be nested inside `LexicalComposer`.\n *\n * @example\n *\n * import { LexicalComposer } from \"@lexical/react/LexicalComposer\";\n * import { RichTextPlugin } from \"@lexical/react/LexicalRichTextPlugin\";\n * import { ContentEditable } from \"@lexical/react/LexicalContentEditable\";\n * import { LexicalErrorBoundary } from \"@lexical/react/LexicalErrorBoundary\";\n * import { liveblocksConfig, LiveblocksPlugin } from \"@liveblocks/react-lexical\";\n *\n * const initialConfig = liveblocksConfig({\n * namespace: \"MyEditor\",\n * theme: {},\n * nodes: [],\n * onError: (err) => console.error(err),\n * });\n *\n * function Editor() {\n * return (\n * <LexicalComposer initialConfig={initialConfig}>\n * <LiveblocksPlugin />\n * <RichTextPlugin\n * contentEditable={<ContentEditable />}\n * placeholder={<div>Enter some text...</div>}\n * ErrorBoundary={LexicalErrorBoundary}\n * />\n * </LexicalComposer>\n * );\n * }\n */\nexport const LiveblocksPlugin = ({\n children,\n}: LiveblocksPluginProps): JSX.Element => {\n const client = useClient();\n const hasResolveMentionSuggestions =\n client[kInternal].resolveMentionSuggestions !== undefined;\n const [editor] = useLexicalComposerContext();\n const room = useRoom();\n const collabContext = useContext(CollaborationContext);\n const previousRoomIdRef = useRef<string | null>(null);\n\n if (!editor.hasNodes([ThreadMarkNode, MentionNode])) {\n throw new Error(\n \"LiveblocksPlugin requires Lexical configuration to be wrapped in the `liveblocksConfig(options)` function. For more information: https://liveblocks.io/docs/api-reference/liveblocks-react-lexical#liveblocksConfig\"\n );\n }\n\n const [containerRef, setContainerRef] = useState<\n MutableRefObject<HTMLDivElement | null> | undefined\n >(undefined);\n\n const {\n refs: { setReference, setFloating },\n strategy,\n x,\n y,\n } = useFloating({\n strategy: \"fixed\",\n placement: \"bottom\",\n whileElementsMounted: (...args) => {\n return autoUpdate(...args, {\n animationFrame: true,\n });\n },\n });\n\n // Warn users if initialConfig.editorState, set on the composer, is not null\n useEffect(() => {\n // only in dev mode\n if (process.env.NODE_ENV !== \"production\") {\n // A user should not even be set an emptyState, but when passing null, getEditorState still has initial empty state\n if (!editor.getEditorState().isEmpty()) {\n console.warn(\n \"Warning: LiveblocksPlugin: editorState in initialConfig detected, but must be null.\"\n );\n }\n }\n\n // we know editor is already defined as we're inside LexicalComposer, and we only want this running the first time\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n useEffect(() => {\n // Report that this is lexical and root is the rootKey\n room[kInternal].reportTextEditor(\"lexical\", \"root\");\n }, [room]);\n\n // Get user info or allow override from props\n const info = useSelf((me) => me.info);\n const username = info?.name || \"\"; // use empty string to prevent random name\n const cursorcolor = info?.color as string | undefined;\n\n const providerFactory = useCallback(\n (id: string, yjsDocMap: Map<string, Doc>): Provider => {\n // Destroy previously used provider to avoid memory leaks\n // TODO: Find a way to destroy the last used provider on unmount (while working with StrictMode)\n if (\n previousRoomIdRef.current !== null &&\n previousRoomIdRef.current !== id\n ) {\n const previousProvider = providersMap.get(id);\n if (previousProvider !== undefined) {\n previousProvider.destroy();\n }\n }\n\n let doc = yjsDocMap.get(id);\n\n if (doc === undefined) {\n doc = new Doc();\n const provider = new LiveblocksYjsProvider(room, doc);\n yjsDocMap.set(id, doc);\n providersMap.set(id, provider);\n }\n\n return nn(\n providersMap.get(id),\n \"Internal error. Should never happen\"\n ) as Provider;\n },\n [room]\n );\n\n useEffect(() => {\n collabContext.name = username || \"\";\n }, [collabContext, username]);\n\n const root = useRootElement();\n\n useLayoutEffect(() => {\n if (root === null) return;\n setReference({\n getBoundingClientRect: () => root.getBoundingClientRect(),\n });\n }, [setReference, root]);\n\n const handleFloatingRef = useCallback(\n (node: HTMLDivElement) => {\n setFloating(node);\n setContainerRef({ current: node });\n },\n [setFloating, setContainerRef]\n );\n\n return (\n <>\n <div\n ref={handleFloatingRef}\n style={{\n position: strategy,\n top: 0,\n left: 0,\n transform: `translate3d(${Math.round(x)}px, ${Math.round(y)}px, 0)`,\n minWidth: \"max-content\",\n }}\n />\n\n <CollaborationPlugin\n // Setting the key allows us to reset the internal Y.doc used by useYjsCollaboration\n // without implementing `reload` event\n key={room.id}\n id={room.id}\n providerFactory={providerFactory}\n username={username}\n cursorColor={cursorcolor}\n cursorsContainerRef={containerRef}\n shouldBootstrap={true}\n />\n\n {hasResolveMentionSuggestions && <MentionPlugin />}\n\n <CommentPluginProvider>{children}</CommentPluginProvider>\n </>\n );\n};\n\nfunction useRootElement(): HTMLElement | null {\n const [editor] = useLexicalComposerContext();\n\n const subscribe = useCallback(\n (onStoreChange: () => void) => {\n return editor.registerRootListener(onStoreChange);\n },\n [editor]\n );\n\n const getSnapshot = useCallback(() => {\n return editor.getRootElement();\n }, [editor]);\n\n return useSyncExternalStore(subscribe, getSnapshot, getSnapshot);\n}\n"],"names":["provider","React"],"mappings":"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"}
package/dist/version.js CHANGED
@@ -1,7 +1,7 @@
1
1
  'use strict';
2
2
 
3
3
  const PKG_NAME = "@liveblocks/react-lexical";
4
- const PKG_VERSION = typeof "2.0.0-alpha4" === "string" && "2.0.0-alpha4";
4
+ const PKG_VERSION = typeof "2.0.0" === "string" && "2.0.0";
5
5
  const PKG_FORMAT = typeof "cjs" === "string" && "cjs";
6
6
 
7
7
  exports.PKG_FORMAT = PKG_FORMAT;
@@ -1 +1 @@
1
- {"version":3,"file":"version.js","sources":["../src/version.ts"],"sourcesContent":["declare const __VERSION__: string;\ndeclare const TSUP_FORMAT: string;\n\nexport const PKG_NAME = \"@liveblocks/react-lexical\";\nexport const PKG_VERSION = typeof __VERSION__ === \"string\" && __VERSION__;\nexport const PKG_FORMAT = typeof TSUP_FORMAT === \"string\" && TSUP_FORMAT;\n"],"names":[],"mappings":";;AAGO,MAAM,QAAW,GAAA,4BAAA;AACX,MAAA,WAAA,GAAc,OAAO,cAAA,KAAgB,QAAY,IAAA,eAAA;AACjD,MAAA,UAAA,GAAa,OAAO,KAAA,KAAgB,QAAY,IAAA;;;;;;"}
1
+ {"version":3,"file":"version.js","sources":["../src/version.ts"],"sourcesContent":["declare const __VERSION__: string;\ndeclare const TSUP_FORMAT: string;\n\nexport const PKG_NAME = \"@liveblocks/react-lexical\";\nexport const PKG_VERSION = typeof __VERSION__ === \"string\" && __VERSION__;\nexport const PKG_FORMAT = typeof TSUP_FORMAT === \"string\" && TSUP_FORMAT;\n"],"names":[],"mappings":";;AAGO,MAAM,QAAW,GAAA,4BAAA;AACX,MAAA,WAAA,GAAc,OAAO,OAAA,KAAgB,QAAY,IAAA,QAAA;AACjD,MAAA,UAAA,GAAa,OAAO,KAAA,KAAgB,QAAY,IAAA;;;;;;"}
package/dist/version.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  const PKG_NAME = "@liveblocks/react-lexical";
2
- const PKG_VERSION = typeof "2.0.0-alpha4" === "string" && "2.0.0-alpha4";
2
+ const PKG_VERSION = typeof "2.0.0" === "string" && "2.0.0";
3
3
  const PKG_FORMAT = typeof "esm" === "string" && "esm";
4
4
 
5
5
  export { PKG_FORMAT, PKG_NAME, PKG_VERSION };
@@ -1 +1 @@
1
- {"version":3,"file":"version.mjs","sources":["../src/version.ts"],"sourcesContent":["declare const __VERSION__: string;\ndeclare const TSUP_FORMAT: string;\n\nexport const PKG_NAME = \"@liveblocks/react-lexical\";\nexport const PKG_VERSION = typeof __VERSION__ === \"string\" && __VERSION__;\nexport const PKG_FORMAT = typeof TSUP_FORMAT === \"string\" && TSUP_FORMAT;\n"],"names":[],"mappings":"AAGO,MAAM,QAAW,GAAA,4BAAA;AACX,MAAA,WAAA,GAAc,OAAO,cAAA,KAAgB,QAAY,IAAA,eAAA;AACjD,MAAA,UAAA,GAAa,OAAO,KAAA,KAAgB,QAAY,IAAA;;;;"}
1
+ {"version":3,"file":"version.mjs","sources":["../src/version.ts"],"sourcesContent":["declare const __VERSION__: string;\ndeclare const TSUP_FORMAT: string;\n\nexport const PKG_NAME = \"@liveblocks/react-lexical\";\nexport const PKG_VERSION = typeof __VERSION__ === \"string\" && __VERSION__;\nexport const PKG_FORMAT = typeof TSUP_FORMAT === \"string\" && TSUP_FORMAT;\n"],"names":[],"mappings":"AAGO,MAAM,QAAW,GAAA,4BAAA;AACX,MAAA,WAAA,GAAc,OAAO,OAAA,KAAgB,QAAY,IAAA,QAAA;AACjD,MAAA,UAAA,GAAa,OAAO,KAAA,KAAgB,QAAY,IAAA;;;;"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@liveblocks/react-lexical",
3
- "version": "2.0.0-alpha4",
3
+ "version": "2.0.0",
4
4
  "description": "A lexical react plugin to enable collaboration, comments, live cursors, and more.",
5
5
  "license": "Apache-2.0",
6
6
  "type": "commonjs",
@@ -42,11 +42,11 @@
42
42
  },
43
43
  "dependencies": {
44
44
  "@floating-ui/react-dom": "^2.1.0",
45
- "@liveblocks/client": "2.0.0-alpha4",
46
- "@liveblocks/core": "2.0.0-alpha4",
47
- "@liveblocks/react": "2.0.0-alpha4",
48
- "@liveblocks/react-ui": "2.0.0-alpha4",
49
- "@liveblocks/yjs": "2.0.0-alpha4",
45
+ "@liveblocks/client": "2.0.0",
46
+ "@liveblocks/core": "2.0.0",
47
+ "@liveblocks/react": "2.0.0",
48
+ "@liveblocks/react-ui": "2.0.0",
49
+ "@liveblocks/yjs": "2.0.0",
50
50
  "nanoid": "^3",
51
51
  "use-sync-external-store": "^1.2.2",
52
52
  "yjs": "^13.6.14"