@liveblocks/react-lexical 2.8.2 → 2.8.3-tiptap2

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.
@@ -105,6 +105,7 @@ const FloatingComposerImpl = React.forwardRef(function FloatingComposer3(props,
105
105
  event.preventDefault();
106
106
  const thread = createThread({
107
107
  body: comment.body,
108
+ attachments: comment.attachments,
108
109
  metadata: props.metadata ?? {}
109
110
  });
110
111
  onThreadCreate(thread.id);
@@ -1 +1 @@
1
- {"version":3,"file":"floating-composer.js","sources":["../../src/comments/floating-composer.tsx"],"sourcesContent":["import {\n autoUpdate,\n flip,\n hide,\n limitShift,\n offset,\n shift,\n size,\n useFloating,\n} from \"@floating-ui/react-dom\";\nimport { useLexicalComposerContext } from \"@lexical/react/LexicalComposerContext\";\nimport type { BaseMetadata, DM } from \"@liveblocks/core\";\nimport { useCreateThread } from \"@liveblocks/react\";\nimport type {\n ComposerProps,\n ComposerSubmitComment,\n} from \"@liveblocks/react-ui\";\nimport { Composer } from \"@liveblocks/react-ui\";\nimport type { LexicalCommand } from \"lexical\";\nimport {\n $getSelection,\n $isRangeSelection,\n $setSelection,\n COMMAND_PRIORITY_EDITOR,\n createCommand,\n} from \"lexical\";\nimport type { ComponentRef, FormEvent, KeyboardEvent, ReactNode } from \"react\";\nimport React, {\n forwardRef,\n useCallback,\n useEffect,\n useLayoutEffect,\n useState,\n} from \"react\";\nimport { createPortal } from \"react-dom\";\n\nimport { createDOMRange } from \"../create-dom-range\";\nimport { createRectsFromDOMRange } from \"../create-rects-from-dom-range\";\nimport $wrapSelectionInThreadMarkNode from \"./wrap-selection-in-thread-mark-node\";\n\n/**\n * Dispatching OPEN_FLOATING_COMPOSER_COMMAND will display the FloatingComposer\n *\n * @example\n * import { useLexicalComposerContext } from \"@lexical/react/LexicalComposerContext\";\n * import { OPEN_FLOATING_COMPOSER_COMMAND } from \"@liveblocks/react-lexical\";\n *\n * function Toolbar() {\n * const [editor] = useLexicalComposerContext();\n *\n * return (\n * <button\n * onClick={() => {\n * editor.dispatchCommand(OPEN_FLOATING_COMPOSER_COMMAND);\n * }}\n * >\n * 💬 New comment\n * </button>\n * );\n * }\n */\nexport const OPEN_FLOATING_COMPOSER_COMMAND: LexicalCommand<void> =\n createCommand(\"OPEN_FLOATING_COMPOSER_COMMAND\");\n\ntype ComposerElement = ComponentRef<typeof Composer>;\n\nexport type FloatingComposerProps<M extends BaseMetadata = DM> = Omit<\n ComposerProps<M>,\n \"threadId\" | \"commentId\"\n>;\n\n/**\n * Displays a `Composer` near the current lexical selection.\n *\n * To open it, dispatch `OPEN_FLOATING_COMPOSER_COMMAND`.\n *\n * Submitting a comment will attach an annotation thread at the current selection.\n * Should be nested inside `LiveblocksPlugin`.\n */\nexport const FloatingComposer = forwardRef<\n ComposerElement,\n FloatingComposerProps\n>(function FloatingComposer(props, forwardedRef) {\n const [range, setRange] = useState<Range | null>(null);\n const [editor] = useLexicalComposerContext();\n\n useEffect(() => {\n return editor.registerCommand(\n OPEN_FLOATING_COMPOSER_COMMAND,\n () => {\n const selection = $getSelection();\n if (!$isRangeSelection(selection)) return false;\n\n if (selection.isCollapsed()) return false;\n\n const { anchor, focus } = selection;\n\n const range = createDOMRange(\n editor,\n anchor.getNode(),\n anchor.offset,\n focus.getNode(),\n focus.offset\n );\n\n setRange(range);\n\n return true;\n },\n COMMAND_PRIORITY_EDITOR\n );\n }, [editor]);\n\n if (range === null) return null;\n\n return (\n <FloatingComposerImpl\n ref={forwardedRef}\n {...props}\n range={range}\n onRangeChange={setRange}\n />\n );\n});\n\ninterface FloatingComposerImplProps extends FloatingComposerProps {\n range: Range;\n onRangeChange: (range: Range | null) => void;\n}\n\nconst FloatingComposerImpl = forwardRef<\n ComposerElement,\n FloatingComposerImplProps\n>(function FloatingComposer(props, forwardedRef) {\n const {\n range,\n onRangeChange,\n onKeyDown,\n onComposerSubmit,\n ...composerProps\n } = props;\n\n const [editor] = useLexicalComposerContext();\n const createThread = useCreateThread();\n\n const $onStateRead = useCallback((): Range | null => {\n const selection = $getSelection();\n\n // If the selection is not a range selection or is collapsed, clear the range so the composer is no longer displayed.\n if (!$isRangeSelection(selection) || selection.isCollapsed()) {\n return null;\n }\n\n const { anchor, focus } = selection;\n const range = createDOMRange(\n editor,\n anchor.getNode(),\n anchor.offset,\n focus.getNode(),\n focus.offset\n );\n\n return range;\n }, [editor]);\n\n useEffect(() => {\n return editor.registerUpdateListener(({ editorState: state, tags }) => {\n // If the update is not related to collaboration, clear the range so the composer is no longer displayed.\n if (!tags.has(\"collaboration\")) {\n onRangeChange(null);\n return;\n }\n\n const range = state.read(() => $onStateRead());\n onRangeChange(range);\n });\n }, [editor, range, onRangeChange, $onStateRead]);\n\n /**\n * Create a new ThreadMarkNode and wrap the selected content in it.\n * @param threadId The id of the thread to associate with the selected content\n */\n const onThreadCreate = useCallback(\n (threadId: string) => {\n editor.update(() => {\n const selection = $getSelection();\n if (!$isRangeSelection(selection)) return;\n\n // If the selection is collapsed, we do not create a new thread node in the editor.\n if (selection.isCollapsed()) return;\n\n const isBackward = selection.isBackward();\n // Wrap content in a ThreadMarkNode\n $wrapSelectionInThreadMarkNode(selection, isBackward, threadId);\n\n // Clear the selection after wrapping\n $setSelection(null);\n });\n },\n [editor]\n );\n\n const handleComposerSubmit = useCallback(\n (comment: ComposerSubmitComment, event: FormEvent<HTMLFormElement>) => {\n onComposerSubmit?.(comment, event);\n if (event.defaultPrevented) return;\n\n event.preventDefault();\n\n const thread = createThread({\n body: comment.body,\n metadata: props.metadata ?? {},\n });\n\n onThreadCreate(thread.id);\n },\n [onThreadCreate, onComposerSubmit, props.metadata, createThread]\n );\n\n function handleKeyDown(event: KeyboardEvent<HTMLFormElement>) {\n if (event.key === \"Escape\") {\n onRangeChange(null);\n editor.focus();\n }\n onKeyDown?.(event);\n }\n\n return (\n <>\n <ActiveSelectionPortal range={range} container={document.body} />\n\n <FloatingComposerPortal range={range} container={document.body}>\n <Composer\n autoFocus\n {...composerProps}\n onKeyDown={handleKeyDown}\n onComposerSubmit={handleComposerSubmit}\n ref={forwardedRef}\n />\n </FloatingComposerPortal>\n </>\n );\n});\n\nfunction ActiveSelectionPortal({\n range,\n container,\n}: {\n range: Range;\n container: HTMLElement;\n}) {\n const {\n refs: { setReference, setFloating },\n strategy,\n x,\n y,\n } = useFloating({\n strategy: \"fixed\",\n placement: \"bottom\",\n middleware: [offset(-range.getBoundingClientRect().height)],\n whileElementsMounted: (...args) => {\n return autoUpdate(...args, {\n animationFrame: true,\n });\n },\n });\n\n useLayoutEffect(() => {\n setReference({\n getBoundingClientRect: () => range.getBoundingClientRect(),\n });\n }, [setReference, range]);\n\n const [editor] = useLexicalComposerContext();\n const rects = createRectsFromDOMRange(editor, range);\n\n return createPortal(\n <>\n <span\n ref={setFloating}\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 width: range.getBoundingClientRect().width,\n height: range.getBoundingClientRect().height,\n pointerEvents: \"none\",\n }}\n className=\"lb-root lb-portal\"\n >\n {rects.map((rect) => (\n <span\n key={JSON.stringify(rect)}\n style={{\n position: \"absolute\",\n top: rect.top - range.getBoundingClientRect().top,\n left: rect.left - range.getBoundingClientRect().left,\n width: rect.width,\n height: rect.height,\n backgroundColor: \"var(--lb-selection, rgba(0, 0, 255, 0.2))\",\n pointerEvents: \"none\",\n }}\n className=\"lb-lexical-active-selection\"\n />\n ))}\n </span>\n </>,\n container\n );\n}\n\nexport const FLOATING_COMPOSER_COLLISION_PADDING = 10;\n\nfunction FloatingComposerPortal({\n container,\n range,\n children,\n}: {\n container: HTMLElement;\n range: Range;\n children: ReactNode;\n}) {\n const {\n refs: { setReference, setFloating },\n strategy,\n x,\n y,\n } = useFloating({\n strategy: \"fixed\",\n placement: \"bottom\",\n middleware: [\n flip({ padding: FLOATING_COMPOSER_COLLISION_PADDING, crossAxis: false }),\n offset(10),\n hide({ padding: FLOATING_COMPOSER_COLLISION_PADDING }),\n shift({\n padding: FLOATING_COMPOSER_COLLISION_PADDING,\n limiter: limitShift(),\n }),\n size({ padding: FLOATING_COMPOSER_COLLISION_PADDING }),\n ],\n whileElementsMounted: (...args) => {\n return autoUpdate(...args, {\n animationFrame: true,\n });\n },\n });\n\n useLayoutEffect(() => {\n setReference({\n getBoundingClientRect: () => range.getBoundingClientRect(),\n });\n }, [range, setReference]);\n\n return createPortal(\n <div\n ref={setFloating}\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 className=\"lb-root lb-portal lb-elevation lb-lexical-floating lb-lexical-floating-composer\"\n >\n {children}\n </div>,\n container\n );\n}\n"],"names":["createCommand","forwardRef","FloatingComposer","useState","useLexicalComposerContext","useEffect","$getSelection","$isRangeSelection","range","createDOMRange","COMMAND_PRIORITY_EDITOR","useCreateThread","useCallback","$wrapSelectionInThreadMarkNode","$setSelection","Composer","useFloating","offset","autoUpdate","useLayoutEffect","createRectsFromDOMRange","createPortal","flip","hide","shift","limitShift","size"],"mappings":"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"}
1
+ {"version":3,"file":"floating-composer.js","sources":["../../src/comments/floating-composer.tsx"],"sourcesContent":["import {\n autoUpdate,\n flip,\n hide,\n limitShift,\n offset,\n shift,\n size,\n useFloating,\n} from \"@floating-ui/react-dom\";\nimport { useLexicalComposerContext } from \"@lexical/react/LexicalComposerContext\";\nimport type { BaseMetadata, DM } from \"@liveblocks/core\";\nimport { useCreateThread } from \"@liveblocks/react\";\nimport type {\n ComposerProps,\n ComposerSubmitComment,\n} from \"@liveblocks/react-ui\";\nimport { Composer } from \"@liveblocks/react-ui\";\nimport type { LexicalCommand } from \"lexical\";\nimport {\n $getSelection,\n $isRangeSelection,\n $setSelection,\n COMMAND_PRIORITY_EDITOR,\n createCommand,\n} from \"lexical\";\nimport type { ComponentRef, FormEvent, KeyboardEvent, ReactNode } from \"react\";\nimport React, {\n forwardRef,\n useCallback,\n useEffect,\n useLayoutEffect,\n useState,\n} from \"react\";\nimport { createPortal } from \"react-dom\";\n\nimport { createDOMRange } from \"../create-dom-range\";\nimport { createRectsFromDOMRange } from \"../create-rects-from-dom-range\";\nimport $wrapSelectionInThreadMarkNode from \"./wrap-selection-in-thread-mark-node\";\n\n/**\n * Dispatching OPEN_FLOATING_COMPOSER_COMMAND will display the FloatingComposer\n *\n * @example\n * import { useLexicalComposerContext } from \"@lexical/react/LexicalComposerContext\";\n * import { OPEN_FLOATING_COMPOSER_COMMAND } from \"@liveblocks/react-lexical\";\n *\n * function Toolbar() {\n * const [editor] = useLexicalComposerContext();\n *\n * return (\n * <button\n * onClick={() => {\n * editor.dispatchCommand(OPEN_FLOATING_COMPOSER_COMMAND);\n * }}\n * >\n * 💬 New comment\n * </button>\n * );\n * }\n */\nexport const OPEN_FLOATING_COMPOSER_COMMAND: LexicalCommand<void> =\n createCommand(\"OPEN_FLOATING_COMPOSER_COMMAND\");\n\ntype ComposerElement = ComponentRef<typeof Composer>;\n\nexport type FloatingComposerProps<M extends BaseMetadata = DM> = Omit<\n ComposerProps<M>,\n \"threadId\" | \"commentId\"\n>;\n\n/**\n * Displays a `Composer` near the current lexical selection.\n *\n * To open it, dispatch `OPEN_FLOATING_COMPOSER_COMMAND`.\n *\n * Submitting a comment will attach an annotation thread at the current selection.\n * Should be nested inside `LiveblocksPlugin`.\n */\nexport const FloatingComposer = forwardRef<\n ComposerElement,\n FloatingComposerProps\n>(function FloatingComposer(props, forwardedRef) {\n const [range, setRange] = useState<Range | null>(null);\n const [editor] = useLexicalComposerContext();\n\n useEffect(() => {\n return editor.registerCommand(\n OPEN_FLOATING_COMPOSER_COMMAND,\n () => {\n const selection = $getSelection();\n if (!$isRangeSelection(selection)) return false;\n\n if (selection.isCollapsed()) return false;\n\n const { anchor, focus } = selection;\n\n const range = createDOMRange(\n editor,\n anchor.getNode(),\n anchor.offset,\n focus.getNode(),\n focus.offset\n );\n\n setRange(range);\n\n return true;\n },\n COMMAND_PRIORITY_EDITOR\n );\n }, [editor]);\n\n if (range === null) return null;\n\n return (\n <FloatingComposerImpl\n ref={forwardedRef}\n {...props}\n range={range}\n onRangeChange={setRange}\n />\n );\n});\n\ninterface FloatingComposerImplProps extends FloatingComposerProps {\n range: Range;\n onRangeChange: (range: Range | null) => void;\n}\n\nconst FloatingComposerImpl = forwardRef<\n ComposerElement,\n FloatingComposerImplProps\n>(function FloatingComposer(props, forwardedRef) {\n const {\n range,\n onRangeChange,\n onKeyDown,\n onComposerSubmit,\n ...composerProps\n } = props;\n\n const [editor] = useLexicalComposerContext();\n const createThread = useCreateThread();\n\n const $onStateRead = useCallback((): Range | null => {\n const selection = $getSelection();\n\n // If the selection is not a range selection or is collapsed, clear the range so the composer is no longer displayed.\n if (!$isRangeSelection(selection) || selection.isCollapsed()) {\n return null;\n }\n\n const { anchor, focus } = selection;\n const range = createDOMRange(\n editor,\n anchor.getNode(),\n anchor.offset,\n focus.getNode(),\n focus.offset\n );\n\n return range;\n }, [editor]);\n\n useEffect(() => {\n return editor.registerUpdateListener(({ editorState: state, tags }) => {\n // If the update is not related to collaboration, clear the range so the composer is no longer displayed.\n if (!tags.has(\"collaboration\")) {\n onRangeChange(null);\n return;\n }\n\n const range = state.read(() => $onStateRead());\n onRangeChange(range);\n });\n }, [editor, range, onRangeChange, $onStateRead]);\n\n /**\n * Create a new ThreadMarkNode and wrap the selected content in it.\n * @param threadId The id of the thread to associate with the selected content\n */\n const onThreadCreate = useCallback(\n (threadId: string) => {\n editor.update(() => {\n const selection = $getSelection();\n if (!$isRangeSelection(selection)) return;\n\n // If the selection is collapsed, we do not create a new thread node in the editor.\n if (selection.isCollapsed()) return;\n\n const isBackward = selection.isBackward();\n // Wrap content in a ThreadMarkNode\n $wrapSelectionInThreadMarkNode(selection, isBackward, threadId);\n\n // Clear the selection after wrapping\n $setSelection(null);\n });\n },\n [editor]\n );\n\n const handleComposerSubmit = useCallback(\n (comment: ComposerSubmitComment, event: FormEvent<HTMLFormElement>) => {\n onComposerSubmit?.(comment, event);\n if (event.defaultPrevented) return;\n\n event.preventDefault();\n\n const thread = createThread({\n body: comment.body,\n attachments: comment.attachments,\n metadata: props.metadata ?? {},\n });\n\n onThreadCreate(thread.id);\n },\n [onThreadCreate, onComposerSubmit, props.metadata, createThread]\n );\n\n function handleKeyDown(event: KeyboardEvent<HTMLFormElement>) {\n if (event.key === \"Escape\") {\n onRangeChange(null);\n editor.focus();\n }\n onKeyDown?.(event);\n }\n\n return (\n <>\n <ActiveSelectionPortal range={range} container={document.body} />\n\n <FloatingComposerPortal range={range} container={document.body}>\n <Composer\n autoFocus\n {...composerProps}\n onKeyDown={handleKeyDown}\n onComposerSubmit={handleComposerSubmit}\n ref={forwardedRef}\n />\n </FloatingComposerPortal>\n </>\n );\n});\n\nfunction ActiveSelectionPortal({\n range,\n container,\n}: {\n range: Range;\n container: HTMLElement;\n}) {\n const {\n refs: { setReference, setFloating },\n strategy,\n x,\n y,\n } = useFloating({\n strategy: \"fixed\",\n placement: \"bottom\",\n middleware: [offset(-range.getBoundingClientRect().height)],\n whileElementsMounted: (...args) => {\n return autoUpdate(...args, {\n animationFrame: true,\n });\n },\n });\n\n useLayoutEffect(() => {\n setReference({\n getBoundingClientRect: () => range.getBoundingClientRect(),\n });\n }, [setReference, range]);\n\n const [editor] = useLexicalComposerContext();\n const rects = createRectsFromDOMRange(editor, range);\n\n return createPortal(\n <>\n <span\n ref={setFloating}\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 width: range.getBoundingClientRect().width,\n height: range.getBoundingClientRect().height,\n pointerEvents: \"none\",\n }}\n className=\"lb-root lb-portal\"\n >\n {rects.map((rect) => (\n <span\n key={JSON.stringify(rect)}\n style={{\n position: \"absolute\",\n top: rect.top - range.getBoundingClientRect().top,\n left: rect.left - range.getBoundingClientRect().left,\n width: rect.width,\n height: rect.height,\n backgroundColor: \"var(--lb-selection, rgba(0, 0, 255, 0.2))\",\n pointerEvents: \"none\",\n }}\n className=\"lb-lexical-active-selection\"\n />\n ))}\n </span>\n </>,\n container\n );\n}\n\nexport const FLOATING_COMPOSER_COLLISION_PADDING = 10;\n\nfunction FloatingComposerPortal({\n container,\n range,\n children,\n}: {\n container: HTMLElement;\n range: Range;\n children: ReactNode;\n}) {\n const {\n refs: { setReference, setFloating },\n strategy,\n x,\n y,\n } = useFloating({\n strategy: \"fixed\",\n placement: \"bottom\",\n middleware: [\n flip({ padding: FLOATING_COMPOSER_COLLISION_PADDING, crossAxis: false }),\n offset(10),\n hide({ padding: FLOATING_COMPOSER_COLLISION_PADDING }),\n shift({\n padding: FLOATING_COMPOSER_COLLISION_PADDING,\n limiter: limitShift(),\n }),\n size({ padding: FLOATING_COMPOSER_COLLISION_PADDING }),\n ],\n whileElementsMounted: (...args) => {\n return autoUpdate(...args, {\n animationFrame: true,\n });\n },\n });\n\n useLayoutEffect(() => {\n setReference({\n getBoundingClientRect: () => range.getBoundingClientRect(),\n });\n }, [range, setReference]);\n\n return createPortal(\n <div\n ref={setFloating}\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 className=\"lb-root lb-portal lb-elevation lb-lexical-floating lb-lexical-floating-composer\"\n >\n {children}\n </div>,\n container\n );\n}\n"],"names":["createCommand","forwardRef","FloatingComposer","useState","useLexicalComposerContext","useEffect","$getSelection","$isRangeSelection","range","createDOMRange","COMMAND_PRIORITY_EDITOR","useCreateThread","useCallback","$wrapSelectionInThreadMarkNode","$setSelection","Composer","useFloating","offset","autoUpdate","useLayoutEffect","createRectsFromDOMRange","createPortal","flip","hide","shift","limitShift","size"],"mappings":"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"}
@@ -103,6 +103,7 @@ const FloatingComposerImpl = forwardRef(function FloatingComposer3(props, forwar
103
103
  event.preventDefault();
104
104
  const thread = createThread({
105
105
  body: comment.body,
106
+ attachments: comment.attachments,
106
107
  metadata: props.metadata ?? {}
107
108
  });
108
109
  onThreadCreate(thread.id);
@@ -1 +1 @@
1
- {"version":3,"file":"floating-composer.mjs","sources":["../../src/comments/floating-composer.tsx"],"sourcesContent":["import {\n autoUpdate,\n flip,\n hide,\n limitShift,\n offset,\n shift,\n size,\n useFloating,\n} from \"@floating-ui/react-dom\";\nimport { useLexicalComposerContext } from \"@lexical/react/LexicalComposerContext\";\nimport type { BaseMetadata, DM } from \"@liveblocks/core\";\nimport { useCreateThread } from \"@liveblocks/react\";\nimport type {\n ComposerProps,\n ComposerSubmitComment,\n} from \"@liveblocks/react-ui\";\nimport { Composer } from \"@liveblocks/react-ui\";\nimport type { LexicalCommand } from \"lexical\";\nimport {\n $getSelection,\n $isRangeSelection,\n $setSelection,\n COMMAND_PRIORITY_EDITOR,\n createCommand,\n} from \"lexical\";\nimport type { ComponentRef, FormEvent, KeyboardEvent, ReactNode } from \"react\";\nimport React, {\n forwardRef,\n useCallback,\n useEffect,\n useLayoutEffect,\n useState,\n} from \"react\";\nimport { createPortal } from \"react-dom\";\n\nimport { createDOMRange } from \"../create-dom-range\";\nimport { createRectsFromDOMRange } from \"../create-rects-from-dom-range\";\nimport $wrapSelectionInThreadMarkNode from \"./wrap-selection-in-thread-mark-node\";\n\n/**\n * Dispatching OPEN_FLOATING_COMPOSER_COMMAND will display the FloatingComposer\n *\n * @example\n * import { useLexicalComposerContext } from \"@lexical/react/LexicalComposerContext\";\n * import { OPEN_FLOATING_COMPOSER_COMMAND } from \"@liveblocks/react-lexical\";\n *\n * function Toolbar() {\n * const [editor] = useLexicalComposerContext();\n *\n * return (\n * <button\n * onClick={() => {\n * editor.dispatchCommand(OPEN_FLOATING_COMPOSER_COMMAND);\n * }}\n * >\n * 💬 New comment\n * </button>\n * );\n * }\n */\nexport const OPEN_FLOATING_COMPOSER_COMMAND: LexicalCommand<void> =\n createCommand(\"OPEN_FLOATING_COMPOSER_COMMAND\");\n\ntype ComposerElement = ComponentRef<typeof Composer>;\n\nexport type FloatingComposerProps<M extends BaseMetadata = DM> = Omit<\n ComposerProps<M>,\n \"threadId\" | \"commentId\"\n>;\n\n/**\n * Displays a `Composer` near the current lexical selection.\n *\n * To open it, dispatch `OPEN_FLOATING_COMPOSER_COMMAND`.\n *\n * Submitting a comment will attach an annotation thread at the current selection.\n * Should be nested inside `LiveblocksPlugin`.\n */\nexport const FloatingComposer = forwardRef<\n ComposerElement,\n FloatingComposerProps\n>(function FloatingComposer(props, forwardedRef) {\n const [range, setRange] = useState<Range | null>(null);\n const [editor] = useLexicalComposerContext();\n\n useEffect(() => {\n return editor.registerCommand(\n OPEN_FLOATING_COMPOSER_COMMAND,\n () => {\n const selection = $getSelection();\n if (!$isRangeSelection(selection)) return false;\n\n if (selection.isCollapsed()) return false;\n\n const { anchor, focus } = selection;\n\n const range = createDOMRange(\n editor,\n anchor.getNode(),\n anchor.offset,\n focus.getNode(),\n focus.offset\n );\n\n setRange(range);\n\n return true;\n },\n COMMAND_PRIORITY_EDITOR\n );\n }, [editor]);\n\n if (range === null) return null;\n\n return (\n <FloatingComposerImpl\n ref={forwardedRef}\n {...props}\n range={range}\n onRangeChange={setRange}\n />\n );\n});\n\ninterface FloatingComposerImplProps extends FloatingComposerProps {\n range: Range;\n onRangeChange: (range: Range | null) => void;\n}\n\nconst FloatingComposerImpl = forwardRef<\n ComposerElement,\n FloatingComposerImplProps\n>(function FloatingComposer(props, forwardedRef) {\n const {\n range,\n onRangeChange,\n onKeyDown,\n onComposerSubmit,\n ...composerProps\n } = props;\n\n const [editor] = useLexicalComposerContext();\n const createThread = useCreateThread();\n\n const $onStateRead = useCallback((): Range | null => {\n const selection = $getSelection();\n\n // If the selection is not a range selection or is collapsed, clear the range so the composer is no longer displayed.\n if (!$isRangeSelection(selection) || selection.isCollapsed()) {\n return null;\n }\n\n const { anchor, focus } = selection;\n const range = createDOMRange(\n editor,\n anchor.getNode(),\n anchor.offset,\n focus.getNode(),\n focus.offset\n );\n\n return range;\n }, [editor]);\n\n useEffect(() => {\n return editor.registerUpdateListener(({ editorState: state, tags }) => {\n // If the update is not related to collaboration, clear the range so the composer is no longer displayed.\n if (!tags.has(\"collaboration\")) {\n onRangeChange(null);\n return;\n }\n\n const range = state.read(() => $onStateRead());\n onRangeChange(range);\n });\n }, [editor, range, onRangeChange, $onStateRead]);\n\n /**\n * Create a new ThreadMarkNode and wrap the selected content in it.\n * @param threadId The id of the thread to associate with the selected content\n */\n const onThreadCreate = useCallback(\n (threadId: string) => {\n editor.update(() => {\n const selection = $getSelection();\n if (!$isRangeSelection(selection)) return;\n\n // If the selection is collapsed, we do not create a new thread node in the editor.\n if (selection.isCollapsed()) return;\n\n const isBackward = selection.isBackward();\n // Wrap content in a ThreadMarkNode\n $wrapSelectionInThreadMarkNode(selection, isBackward, threadId);\n\n // Clear the selection after wrapping\n $setSelection(null);\n });\n },\n [editor]\n );\n\n const handleComposerSubmit = useCallback(\n (comment: ComposerSubmitComment, event: FormEvent<HTMLFormElement>) => {\n onComposerSubmit?.(comment, event);\n if (event.defaultPrevented) return;\n\n event.preventDefault();\n\n const thread = createThread({\n body: comment.body,\n metadata: props.metadata ?? {},\n });\n\n onThreadCreate(thread.id);\n },\n [onThreadCreate, onComposerSubmit, props.metadata, createThread]\n );\n\n function handleKeyDown(event: KeyboardEvent<HTMLFormElement>) {\n if (event.key === \"Escape\") {\n onRangeChange(null);\n editor.focus();\n }\n onKeyDown?.(event);\n }\n\n return (\n <>\n <ActiveSelectionPortal range={range} container={document.body} />\n\n <FloatingComposerPortal range={range} container={document.body}>\n <Composer\n autoFocus\n {...composerProps}\n onKeyDown={handleKeyDown}\n onComposerSubmit={handleComposerSubmit}\n ref={forwardedRef}\n />\n </FloatingComposerPortal>\n </>\n );\n});\n\nfunction ActiveSelectionPortal({\n range,\n container,\n}: {\n range: Range;\n container: HTMLElement;\n}) {\n const {\n refs: { setReference, setFloating },\n strategy,\n x,\n y,\n } = useFloating({\n strategy: \"fixed\",\n placement: \"bottom\",\n middleware: [offset(-range.getBoundingClientRect().height)],\n whileElementsMounted: (...args) => {\n return autoUpdate(...args, {\n animationFrame: true,\n });\n },\n });\n\n useLayoutEffect(() => {\n setReference({\n getBoundingClientRect: () => range.getBoundingClientRect(),\n });\n }, [setReference, range]);\n\n const [editor] = useLexicalComposerContext();\n const rects = createRectsFromDOMRange(editor, range);\n\n return createPortal(\n <>\n <span\n ref={setFloating}\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 width: range.getBoundingClientRect().width,\n height: range.getBoundingClientRect().height,\n pointerEvents: \"none\",\n }}\n className=\"lb-root lb-portal\"\n >\n {rects.map((rect) => (\n <span\n key={JSON.stringify(rect)}\n style={{\n position: \"absolute\",\n top: rect.top - range.getBoundingClientRect().top,\n left: rect.left - range.getBoundingClientRect().left,\n width: rect.width,\n height: rect.height,\n backgroundColor: \"var(--lb-selection, rgba(0, 0, 255, 0.2))\",\n pointerEvents: \"none\",\n }}\n className=\"lb-lexical-active-selection\"\n />\n ))}\n </span>\n </>,\n container\n );\n}\n\nexport const FLOATING_COMPOSER_COLLISION_PADDING = 10;\n\nfunction FloatingComposerPortal({\n container,\n range,\n children,\n}: {\n container: HTMLElement;\n range: Range;\n children: ReactNode;\n}) {\n const {\n refs: { setReference, setFloating },\n strategy,\n x,\n y,\n } = useFloating({\n strategy: \"fixed\",\n placement: \"bottom\",\n middleware: [\n flip({ padding: FLOATING_COMPOSER_COLLISION_PADDING, crossAxis: false }),\n offset(10),\n hide({ padding: FLOATING_COMPOSER_COLLISION_PADDING }),\n shift({\n padding: FLOATING_COMPOSER_COLLISION_PADDING,\n limiter: limitShift(),\n }),\n size({ padding: FLOATING_COMPOSER_COLLISION_PADDING }),\n ],\n whileElementsMounted: (...args) => {\n return autoUpdate(...args, {\n animationFrame: true,\n });\n },\n });\n\n useLayoutEffect(() => {\n setReference({\n getBoundingClientRect: () => range.getBoundingClientRect(),\n });\n }, [range, setReference]);\n\n return createPortal(\n <div\n ref={setFloating}\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 className=\"lb-root lb-portal lb-elevation lb-lexical-floating lb-lexical-floating-composer\"\n >\n {children}\n </div>,\n container\n );\n}\n"],"names":["FloatingComposer","range","React"],"mappings":"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"}
1
+ {"version":3,"file":"floating-composer.mjs","sources":["../../src/comments/floating-composer.tsx"],"sourcesContent":["import {\n autoUpdate,\n flip,\n hide,\n limitShift,\n offset,\n shift,\n size,\n useFloating,\n} from \"@floating-ui/react-dom\";\nimport { useLexicalComposerContext } from \"@lexical/react/LexicalComposerContext\";\nimport type { BaseMetadata, DM } from \"@liveblocks/core\";\nimport { useCreateThread } from \"@liveblocks/react\";\nimport type {\n ComposerProps,\n ComposerSubmitComment,\n} from \"@liveblocks/react-ui\";\nimport { Composer } from \"@liveblocks/react-ui\";\nimport type { LexicalCommand } from \"lexical\";\nimport {\n $getSelection,\n $isRangeSelection,\n $setSelection,\n COMMAND_PRIORITY_EDITOR,\n createCommand,\n} from \"lexical\";\nimport type { ComponentRef, FormEvent, KeyboardEvent, ReactNode } from \"react\";\nimport React, {\n forwardRef,\n useCallback,\n useEffect,\n useLayoutEffect,\n useState,\n} from \"react\";\nimport { createPortal } from \"react-dom\";\n\nimport { createDOMRange } from \"../create-dom-range\";\nimport { createRectsFromDOMRange } from \"../create-rects-from-dom-range\";\nimport $wrapSelectionInThreadMarkNode from \"./wrap-selection-in-thread-mark-node\";\n\n/**\n * Dispatching OPEN_FLOATING_COMPOSER_COMMAND will display the FloatingComposer\n *\n * @example\n * import { useLexicalComposerContext } from \"@lexical/react/LexicalComposerContext\";\n * import { OPEN_FLOATING_COMPOSER_COMMAND } from \"@liveblocks/react-lexical\";\n *\n * function Toolbar() {\n * const [editor] = useLexicalComposerContext();\n *\n * return (\n * <button\n * onClick={() => {\n * editor.dispatchCommand(OPEN_FLOATING_COMPOSER_COMMAND);\n * }}\n * >\n * 💬 New comment\n * </button>\n * );\n * }\n */\nexport const OPEN_FLOATING_COMPOSER_COMMAND: LexicalCommand<void> =\n createCommand(\"OPEN_FLOATING_COMPOSER_COMMAND\");\n\ntype ComposerElement = ComponentRef<typeof Composer>;\n\nexport type FloatingComposerProps<M extends BaseMetadata = DM> = Omit<\n ComposerProps<M>,\n \"threadId\" | \"commentId\"\n>;\n\n/**\n * Displays a `Composer` near the current lexical selection.\n *\n * To open it, dispatch `OPEN_FLOATING_COMPOSER_COMMAND`.\n *\n * Submitting a comment will attach an annotation thread at the current selection.\n * Should be nested inside `LiveblocksPlugin`.\n */\nexport const FloatingComposer = forwardRef<\n ComposerElement,\n FloatingComposerProps\n>(function FloatingComposer(props, forwardedRef) {\n const [range, setRange] = useState<Range | null>(null);\n const [editor] = useLexicalComposerContext();\n\n useEffect(() => {\n return editor.registerCommand(\n OPEN_FLOATING_COMPOSER_COMMAND,\n () => {\n const selection = $getSelection();\n if (!$isRangeSelection(selection)) return false;\n\n if (selection.isCollapsed()) return false;\n\n const { anchor, focus } = selection;\n\n const range = createDOMRange(\n editor,\n anchor.getNode(),\n anchor.offset,\n focus.getNode(),\n focus.offset\n );\n\n setRange(range);\n\n return true;\n },\n COMMAND_PRIORITY_EDITOR\n );\n }, [editor]);\n\n if (range === null) return null;\n\n return (\n <FloatingComposerImpl\n ref={forwardedRef}\n {...props}\n range={range}\n onRangeChange={setRange}\n />\n );\n});\n\ninterface FloatingComposerImplProps extends FloatingComposerProps {\n range: Range;\n onRangeChange: (range: Range | null) => void;\n}\n\nconst FloatingComposerImpl = forwardRef<\n ComposerElement,\n FloatingComposerImplProps\n>(function FloatingComposer(props, forwardedRef) {\n const {\n range,\n onRangeChange,\n onKeyDown,\n onComposerSubmit,\n ...composerProps\n } = props;\n\n const [editor] = useLexicalComposerContext();\n const createThread = useCreateThread();\n\n const $onStateRead = useCallback((): Range | null => {\n const selection = $getSelection();\n\n // If the selection is not a range selection or is collapsed, clear the range so the composer is no longer displayed.\n if (!$isRangeSelection(selection) || selection.isCollapsed()) {\n return null;\n }\n\n const { anchor, focus } = selection;\n const range = createDOMRange(\n editor,\n anchor.getNode(),\n anchor.offset,\n focus.getNode(),\n focus.offset\n );\n\n return range;\n }, [editor]);\n\n useEffect(() => {\n return editor.registerUpdateListener(({ editorState: state, tags }) => {\n // If the update is not related to collaboration, clear the range so the composer is no longer displayed.\n if (!tags.has(\"collaboration\")) {\n onRangeChange(null);\n return;\n }\n\n const range = state.read(() => $onStateRead());\n onRangeChange(range);\n });\n }, [editor, range, onRangeChange, $onStateRead]);\n\n /**\n * Create a new ThreadMarkNode and wrap the selected content in it.\n * @param threadId The id of the thread to associate with the selected content\n */\n const onThreadCreate = useCallback(\n (threadId: string) => {\n editor.update(() => {\n const selection = $getSelection();\n if (!$isRangeSelection(selection)) return;\n\n // If the selection is collapsed, we do not create a new thread node in the editor.\n if (selection.isCollapsed()) return;\n\n const isBackward = selection.isBackward();\n // Wrap content in a ThreadMarkNode\n $wrapSelectionInThreadMarkNode(selection, isBackward, threadId);\n\n // Clear the selection after wrapping\n $setSelection(null);\n });\n },\n [editor]\n );\n\n const handleComposerSubmit = useCallback(\n (comment: ComposerSubmitComment, event: FormEvent<HTMLFormElement>) => {\n onComposerSubmit?.(comment, event);\n if (event.defaultPrevented) return;\n\n event.preventDefault();\n\n const thread = createThread({\n body: comment.body,\n attachments: comment.attachments,\n metadata: props.metadata ?? {},\n });\n\n onThreadCreate(thread.id);\n },\n [onThreadCreate, onComposerSubmit, props.metadata, createThread]\n );\n\n function handleKeyDown(event: KeyboardEvent<HTMLFormElement>) {\n if (event.key === \"Escape\") {\n onRangeChange(null);\n editor.focus();\n }\n onKeyDown?.(event);\n }\n\n return (\n <>\n <ActiveSelectionPortal range={range} container={document.body} />\n\n <FloatingComposerPortal range={range} container={document.body}>\n <Composer\n autoFocus\n {...composerProps}\n onKeyDown={handleKeyDown}\n onComposerSubmit={handleComposerSubmit}\n ref={forwardedRef}\n />\n </FloatingComposerPortal>\n </>\n );\n});\n\nfunction ActiveSelectionPortal({\n range,\n container,\n}: {\n range: Range;\n container: HTMLElement;\n}) {\n const {\n refs: { setReference, setFloating },\n strategy,\n x,\n y,\n } = useFloating({\n strategy: \"fixed\",\n placement: \"bottom\",\n middleware: [offset(-range.getBoundingClientRect().height)],\n whileElementsMounted: (...args) => {\n return autoUpdate(...args, {\n animationFrame: true,\n });\n },\n });\n\n useLayoutEffect(() => {\n setReference({\n getBoundingClientRect: () => range.getBoundingClientRect(),\n });\n }, [setReference, range]);\n\n const [editor] = useLexicalComposerContext();\n const rects = createRectsFromDOMRange(editor, range);\n\n return createPortal(\n <>\n <span\n ref={setFloating}\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 width: range.getBoundingClientRect().width,\n height: range.getBoundingClientRect().height,\n pointerEvents: \"none\",\n }}\n className=\"lb-root lb-portal\"\n >\n {rects.map((rect) => (\n <span\n key={JSON.stringify(rect)}\n style={{\n position: \"absolute\",\n top: rect.top - range.getBoundingClientRect().top,\n left: rect.left - range.getBoundingClientRect().left,\n width: rect.width,\n height: rect.height,\n backgroundColor: \"var(--lb-selection, rgba(0, 0, 255, 0.2))\",\n pointerEvents: \"none\",\n }}\n className=\"lb-lexical-active-selection\"\n />\n ))}\n </span>\n </>,\n container\n );\n}\n\nexport const FLOATING_COMPOSER_COLLISION_PADDING = 10;\n\nfunction FloatingComposerPortal({\n container,\n range,\n children,\n}: {\n container: HTMLElement;\n range: Range;\n children: ReactNode;\n}) {\n const {\n refs: { setReference, setFloating },\n strategy,\n x,\n y,\n } = useFloating({\n strategy: \"fixed\",\n placement: \"bottom\",\n middleware: [\n flip({ padding: FLOATING_COMPOSER_COLLISION_PADDING, crossAxis: false }),\n offset(10),\n hide({ padding: FLOATING_COMPOSER_COLLISION_PADDING }),\n shift({\n padding: FLOATING_COMPOSER_COLLISION_PADDING,\n limiter: limitShift(),\n }),\n size({ padding: FLOATING_COMPOSER_COLLISION_PADDING }),\n ],\n whileElementsMounted: (...args) => {\n return autoUpdate(...args, {\n animationFrame: true,\n });\n },\n });\n\n useLayoutEffect(() => {\n setReference({\n getBoundingClientRect: () => range.getBoundingClientRect(),\n });\n }, [range, setReference]);\n\n return createPortal(\n <div\n ref={setFloating}\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 className=\"lb-root lb-portal lb-elevation lb-lexical-floating lb-lexical-floating-composer\"\n >\n {children}\n </div>,\n container\n );\n}\n"],"names":["FloatingComposer","range","React"],"mappings":"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"}
@@ -88,7 +88,7 @@ const LiveblocksPlugin = ({
88
88
  }
89
89
  }, []);
90
90
  React.useEffect(() => {
91
- room[core.kInternal].reportTextEditor("lexical", "root");
91
+ room[core.kInternal].reportTextEditor(core.TextEditorType.Lexical, "root");
92
92
  }, [room]);
93
93
  const self = react.useSelf();
94
94
  const providerFactory = React.useCallback(
@@ -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 { 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 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 useProvider() {\n const room = useRoom();\n\n const subscribe = useCallback(\n (onStoreChange: () => void) => {\n return room[kInternal].onProviderUpdate.subscribe(onStoreChange);\n },\n [room]\n );\n\n const getSnapshot = useCallback(() => {\n return room[kInternal].getProvider();\n }, [room]);\n\n return useSyncExternalStore(subscribe, getSnapshot, getSnapshot);\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 provider = useProvider();\n\n const subscribe = useCallback(\n (onStoreChange: () => void) => {\n if (provider === undefined) return () => {};\n provider.on(\"status\", onStoreChange);\n return () => {\n provider.off(\"status\", onStoreChange);\n };\n },\n [provider]\n );\n\n const getSnapshot = useCallback(() => {\n if (provider === undefined) {\n return \"not-loaded\";\n }\n return provider.getStatus();\n }, [provider]);\n\n return useSyncExternalStore(subscribe, getSnapshot, getSnapshot);\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 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 self = useSelf();\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 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 {self && (\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={self.info?.name ?? \"\"} // use empty string to prevent random name\n cursorColor={self.info?.color as string | undefined}\n cursorsContainerRef={containerRef}\n shouldBootstrap={true}\n />\n )}\n\n {hasResolveMentionSuggestions && <MentionPlugin />}\n <CommentPluginProvider>{children}</CommentPluginProvider>\n </>\n );\n};\n\nexport function 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","useCallback","kInternal","useSyncExternalStore","useClient","useLexicalComposerContext","useRef","ThreadMarkNode","MentionNode","useState","useFloating","autoUpdate","useEffect","useSelf","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 { CollaborationPlugin } from \"@lexical/react/LexicalCollaborationPlugin\";\nimport { useLexicalComposerContext } from \"@lexical/react/LexicalComposerContext\";\nimport type { Provider } from \"@lexical/yjs\";\nimport { kInternal, nn, TextEditorType } 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 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 useProvider() {\n const room = useRoom();\n\n const subscribe = useCallback(\n (onStoreChange: () => void) => {\n return room[kInternal].onProviderUpdate.subscribe(onStoreChange);\n },\n [room]\n );\n\n const getSnapshot = useCallback(() => {\n return room[kInternal].getProvider();\n }, [room]);\n\n return useSyncExternalStore(subscribe, getSnapshot, getSnapshot);\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 provider = useProvider();\n\n const subscribe = useCallback(\n (onStoreChange: () => void) => {\n if (provider === undefined) return () => { };\n provider.on(\"status\", onStoreChange);\n return () => {\n provider.off(\"status\", onStoreChange);\n };\n },\n [provider]\n );\n\n const getSnapshot = useCallback(() => {\n if (provider === undefined) {\n return \"not-loaded\";\n }\n return provider.getStatus();\n }, [provider]);\n\n return useSyncExternalStore(subscribe, getSnapshot, getSnapshot);\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 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(TextEditorType.Lexical, \"root\");\n }, [room]);\n\n // Get user info or allow override from props\n const self = useSelf();\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 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 {self && (\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={self.info?.name ?? \"\"} // use empty string to prevent random name\n cursorColor={self.info?.color as string | undefined}\n cursorsContainerRef={containerRef}\n shouldBootstrap={true}\n />\n )}\n\n {hasResolveMentionSuggestions && <MentionPlugin />}\n <CommentPluginProvider>{children}</CommentPluginProvider>\n </>\n );\n};\n\nexport function 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","useCallback","kInternal","useSyncExternalStore","useClient","useLexicalComposerContext","useRef","ThreadMarkNode","MentionNode","useState","useFloating","autoUpdate","useEffect","TextEditorType","useSelf","Doc","LiveblocksYjsProvider","nn","useLayoutEffect","CollaborationPlugin","MentionPlugin","CommentPluginProvider"],"mappings":"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"}
@@ -1,7 +1,7 @@
1
1
  import { useFloating, autoUpdate } from '@floating-ui/react-dom';
2
2
  import { CollaborationPlugin } from '@lexical/react/LexicalCollaborationPlugin';
3
3
  import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext';
4
- import { kInternal, nn } from '@liveblocks/core';
4
+ import { kInternal, TextEditorType, nn } from '@liveblocks/core';
5
5
  import { useRoom, useClient, useSelf } from '@liveblocks/react';
6
6
  import { LiveblocksYjsProvider } from '@liveblocks/yjs';
7
7
  import React__default, { useCallback, useRef, useState, useEffect, useLayoutEffect } from 'react';
@@ -86,7 +86,7 @@ const LiveblocksPlugin = ({
86
86
  }
87
87
  }, []);
88
88
  useEffect(() => {
89
- room[kInternal].reportTextEditor("lexical", "root");
89
+ room[kInternal].reportTextEditor(TextEditorType.Lexical, "root");
90
90
  }, [room]);
91
91
  const self = useSelf();
92
92
  const providerFactory = useCallback(
@@ -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 { 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 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 useProvider() {\n const room = useRoom();\n\n const subscribe = useCallback(\n (onStoreChange: () => void) => {\n return room[kInternal].onProviderUpdate.subscribe(onStoreChange);\n },\n [room]\n );\n\n const getSnapshot = useCallback(() => {\n return room[kInternal].getProvider();\n }, [room]);\n\n return useSyncExternalStore(subscribe, getSnapshot, getSnapshot);\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 provider = useProvider();\n\n const subscribe = useCallback(\n (onStoreChange: () => void) => {\n if (provider === undefined) return () => {};\n provider.on(\"status\", onStoreChange);\n return () => {\n provider.off(\"status\", onStoreChange);\n };\n },\n [provider]\n );\n\n const getSnapshot = useCallback(() => {\n if (provider === undefined) {\n return \"not-loaded\";\n }\n return provider.getStatus();\n }, [provider]);\n\n return useSyncExternalStore(subscribe, getSnapshot, getSnapshot);\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 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 self = useSelf();\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 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 {self && (\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={self.info?.name ?? \"\"} // use empty string to prevent random name\n cursorColor={self.info?.color as string | undefined}\n cursorsContainerRef={containerRef}\n shouldBootstrap={true}\n />\n )}\n\n {hasResolveMentionSuggestions && <MentionPlugin />}\n <CommentPluginProvider>{children}</CommentPluginProvider>\n </>\n );\n};\n\nexport function 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":["React"],"mappings":";;;;;;;;;;;;;;AAwBA,MAAM,YAAA,uBAAmB,GAGvB,EAAA,CAAA;AAeF,SAAS,WAAc,GAAA;AACrB,EAAA,MAAM,OAAO,OAAQ,EAAA,CAAA;AAErB,EAAA,MAAM,SAAY,GAAA,WAAA;AAAA,IAChB,CAAC,aAA8B,KAAA;AAC7B,MAAA,OAAO,IAAK,CAAA,SAAA,CAAA,CAAW,gBAAiB,CAAA,SAAA,CAAU,aAAa,CAAA,CAAA;AAAA,KACjE;AAAA,IACA,CAAC,IAAI,CAAA;AAAA,GACP,CAAA;AAEA,EAAM,MAAA,WAAA,GAAc,YAAY,MAAM;AACpC,IAAO,OAAA,IAAA,CAAK,WAAW,WAAY,EAAA,CAAA;AAAA,GACrC,EAAG,CAAC,IAAI,CAAC,CAAA,CAAA;AAET,EAAO,OAAA,oBAAA,CAAqB,SAAW,EAAA,WAAA,EAAa,WAAW,CAAA,CAAA;AACjE,CAAA;AAUO,SAAS,eAAgC,GAAA;AAC9C,EAAA,MAAM,WAAW,WAAY,EAAA,CAAA;AAE7B,EAAA,MAAM,SAAY,GAAA,WAAA;AAAA,IAChB,CAAC,aAA8B,KAAA;AAC7B,MAAA,IAAI,QAAa,KAAA,KAAA,CAAA;AAAW,QAAA,OAAO,MAAM;AAAA,SAAC,CAAA;AAC1C,MAAS,QAAA,CAAA,EAAA,CAAG,UAAU,aAAa,CAAA,CAAA;AACnC,MAAA,OAAO,MAAM;AACX,QAAS,QAAA,CAAA,GAAA,CAAI,UAAU,aAAa,CAAA,CAAA;AAAA,OACtC,CAAA;AAAA,KACF;AAAA,IACA,CAAC,QAAQ,CAAA;AAAA,GACX,CAAA;AAEA,EAAM,MAAA,WAAA,GAAc,YAAY,MAAM;AACpC,IAAA,IAAI,aAAa,KAAW,CAAA,EAAA;AAC1B,MAAO,OAAA,YAAA,CAAA;AAAA,KACT;AACA,IAAA,OAAO,SAAS,SAAU,EAAA,CAAA;AAAA,GAC5B,EAAG,CAAC,QAAQ,CAAC,CAAA,CAAA;AAEb,EAAO,OAAA,oBAAA,CAAqB,SAAW,EAAA,WAAA,EAAa,WAAW,CAAA,CAAA;AACjE,CAAA;AAuCO,MAAM,mBAAmB,CAAC;AAAA,EAC/B,QAAA;AACF,CAA0C,KAAA;AACxC,EAAA,MAAM,SAAS,SAAU,EAAA,CAAA;AACzB,EAAM,MAAA,4BAAA,GACJ,MAAO,CAAA,SAAA,CAAA,CAAW,yBAA8B,KAAA,KAAA,CAAA,CAAA;AAClD,EAAM,MAAA,CAAC,MAAM,CAAA,GAAI,yBAA0B,EAAA,CAAA;AAC3C,EAAA,MAAM,OAAO,OAAQ,EAAA,CAAA;AACrB,EAAM,MAAA,iBAAA,GAAoB,OAAsB,IAAI,CAAA,CAAA;AAEpD,EAAA,IAAI,CAAC,MAAO,CAAA,QAAA,CAAS,CAAC,cAAgB,EAAA,WAAW,CAAC,CAAG,EAAA;AACnD,IAAA,MAAM,IAAI,KAAA;AAAA,MACR,qNAAA;AAAA,KACF,CAAA;AAAA,GACF;AAEA,EAAA,MAAM,CAAC,YAAA,EAAc,eAAe,CAAA,GAAI,SAEtC,KAAS,CAAA,CAAA,CAAA;AAEX,EAAM,MAAA;AAAA,IACJ,IAAA,EAAM,EAAE,YAAA,EAAc,WAAY,EAAA;AAAA,IAClC,QAAA;AAAA,IACA,CAAA;AAAA,IACA,CAAA;AAAA,MACE,WAAY,CAAA;AAAA,IACd,QAAU,EAAA,OAAA;AAAA,IACV,SAAW,EAAA,QAAA;AAAA,IACX,oBAAA,EAAsB,IAAI,IAAS,KAAA;AACjC,MAAO,OAAA,UAAA,CAAW,GAAG,IAAM,EAAA;AAAA,QACzB,cAAgB,EAAA,IAAA;AAAA,OACjB,CAAA,CAAA;AAAA,KACH;AAAA,GACD,CAAA,CAAA;AAGD,EAAA,SAAA,CAAU,MAAM;AAEd,IAAI,IAAA,OAAA,CAAQ,GAAI,CAAA,QAAA,KAAa,YAAc,EAAA;AAEzC,MAAA,IAAI,CAAC,MAAA,CAAO,cAAe,EAAA,CAAE,SAAW,EAAA;AACtC,QAAQ,OAAA,CAAA,IAAA;AAAA,UACN,qFAAA;AAAA,SACF,CAAA;AAAA,OACF;AAAA,KACF;AAAA,GAIF,EAAG,EAAE,CAAA,CAAA;AAEL,EAAA,SAAA,CAAU,MAAM;AAEd,IAAK,IAAA,CAAA,SAAA,CAAA,CAAW,gBAAiB,CAAA,SAAA,EAAW,MAAM,CAAA,CAAA;AAAA,GACpD,EAAG,CAAC,IAAI,CAAC,CAAA,CAAA;AAGT,EAAA,MAAM,OAAO,OAAQ,EAAA,CAAA;AAErB,EAAA,MAAM,eAAkB,GAAA,WAAA;AAAA,IACtB,CAAC,IAAY,SAA0C,KAAA;AAGrD,MAAA,IACE,iBAAkB,CAAA,OAAA,KAAY,IAC9B,IAAA,iBAAA,CAAkB,YAAY,EAC9B,EAAA;AACA,QAAM,MAAA,gBAAA,GAAmB,YAAa,CAAA,GAAA,CAAI,EAAE,CAAA,CAAA;AAC5C,QAAA,IAAI,qBAAqB,KAAW,CAAA,EAAA;AAClC,UAAA,gBAAA,CAAiB,OAAQ,EAAA,CAAA;AAAA,SAC3B;AAAA,OACF;AAEA,MAAI,IAAA,GAAA,GAAM,SAAU,CAAA,GAAA,CAAI,EAAE,CAAA,CAAA;AAE1B,MAAA,IAAI,QAAQ,KAAW,CAAA,EAAA;AACrB,QAAA,GAAA,GAAM,IAAI,GAAI,EAAA,CAAA;AACd,QAAA,MAAM,QAAW,GAAA,IAAI,qBAAsB,CAAA,IAAA,EAAM,GAAG,CAAA,CAAA;AACpD,QAAU,SAAA,CAAA,GAAA,CAAI,IAAI,GAAG,CAAA,CAAA;AACrB,QAAa,YAAA,CAAA,GAAA,CAAI,IAAI,QAAQ,CAAA,CAAA;AAAA,OAC/B;AAEA,MAAO,OAAA,EAAA;AAAA,QACL,YAAA,CAAa,IAAI,EAAE,CAAA;AAAA,QACnB,qCAAA;AAAA,OACF,CAAA;AAAA,KACF;AAAA,IACA,CAAC,IAAI,CAAA;AAAA,GACP,CAAA;AAEA,EAAA,MAAM,OAAO,cAAe,EAAA,CAAA;AAE5B,EAAA,eAAA,CAAgB,MAAM;AACpB,IAAA,IAAI,IAAS,KAAA,IAAA;AAAM,MAAA,OAAA;AACnB,IAAa,YAAA,CAAA;AAAA,MACX,qBAAA,EAAuB,MAAM,IAAA,CAAK,qBAAsB,EAAA;AAAA,KACzD,CAAA,CAAA;AAAA,GACA,EAAA,CAAC,YAAc,EAAA,IAAI,CAAC,CAAA,CAAA;AAEvB,EAAA,MAAM,iBAAoB,GAAA,WAAA;AAAA,IACxB,CAAC,IAAyB,KAAA;AACxB,MAAA,WAAA,CAAY,IAAI,CAAA,CAAA;AAChB,MAAgB,eAAA,CAAA,EAAE,OAAS,EAAA,IAAA,EAAM,CAAA,CAAA;AAAA,KACnC;AAAA,IACA,CAAC,aAAa,eAAe,CAAA;AAAA,GAC/B,CAAA;AAEA,EAAA,mGAEKA,cAAA,CAAA,aAAA,CAAA,KAAA,EAAA;AAAA,IACC,GAAK,EAAA,iBAAA;AAAA,IACL,KAAO,EAAA;AAAA,MACL,QAAU,EAAA,QAAA;AAAA,MACV,GAAK,EAAA,CAAA;AAAA,MACL,IAAM,EAAA,CAAA;AAAA,MACN,SAAA,EAAW,eAAe,IAAK,CAAA,KAAA,CAAM,CAAC,CAAQ,CAAA,IAAA,EAAA,IAAA,CAAK,MAAM,CAAC,CAAA,CAAA,MAAA,CAAA;AAAA,MAC1D,QAAU,EAAA,aAAA;AAAA,KACZ;AAAA,GACF,CAAA,EAEC,wBACEA,cAAA,CAAA,aAAA,CAAA,mBAAA,EAAA;AAAA,IAGC,KAAK,IAAK,CAAA,EAAA;AAAA,IACV,IAAI,IAAK,CAAA,EAAA;AAAA,IACT,eAAA;AAAA,IACA,QAAA,EAAU,IAAK,CAAA,IAAA,EAAM,IAAQ,IAAA,EAAA;AAAA,IAC7B,WAAA,EAAa,KAAK,IAAM,EAAA,KAAA;AAAA,IACxB,mBAAqB,EAAA,YAAA;AAAA,IACrB,eAAiB,EAAA,IAAA;AAAA,GACnB,CAAA,EAGD,gDAAiCA,cAAA,CAAA,aAAA,CAAA,aAAA,EAAA,IAAc,mBAC/CA,cAAA,CAAA,aAAA,CAAA,qBAAA,EAAA,IAAA,EAAuB,QAAS,CACnC,CAAA,CAAA;AAEJ,EAAA;AAEO,SAAS,cAAqC,GAAA;AACnD,EAAM,MAAA,CAAC,MAAM,CAAA,GAAI,yBAA0B,EAAA,CAAA;AAE3C,EAAA,MAAM,SAAY,GAAA,WAAA;AAAA,IAChB,CAAC,aAA8B,KAAA;AAC7B,MAAO,OAAA,MAAA,CAAO,qBAAqB,aAAa,CAAA,CAAA;AAAA,KAClD;AAAA,IACA,CAAC,MAAM,CAAA;AAAA,GACT,CAAA;AAEA,EAAM,MAAA,WAAA,GAAc,YAAY,MAAM;AACpC,IAAA,OAAO,OAAO,cAAe,EAAA,CAAA;AAAA,GAC/B,EAAG,CAAC,MAAM,CAAC,CAAA,CAAA;AAEX,EAAO,OAAA,oBAAA,CAAqB,SAAW,EAAA,WAAA,EAAa,WAAW,CAAA,CAAA;AACjE;;;;"}
1
+ {"version":3,"file":"liveblocks-plugin-provider.mjs","sources":["../src/liveblocks-plugin-provider.tsx"],"sourcesContent":["import { autoUpdate, useFloating } from \"@floating-ui/react-dom\";\nimport { CollaborationPlugin } from \"@lexical/react/LexicalCollaborationPlugin\";\nimport { useLexicalComposerContext } from \"@lexical/react/LexicalComposerContext\";\nimport type { Provider } from \"@lexical/yjs\";\nimport { kInternal, nn, TextEditorType } 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 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 useProvider() {\n const room = useRoom();\n\n const subscribe = useCallback(\n (onStoreChange: () => void) => {\n return room[kInternal].onProviderUpdate.subscribe(onStoreChange);\n },\n [room]\n );\n\n const getSnapshot = useCallback(() => {\n return room[kInternal].getProvider();\n }, [room]);\n\n return useSyncExternalStore(subscribe, getSnapshot, getSnapshot);\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 provider = useProvider();\n\n const subscribe = useCallback(\n (onStoreChange: () => void) => {\n if (provider === undefined) return () => { };\n provider.on(\"status\", onStoreChange);\n return () => {\n provider.off(\"status\", onStoreChange);\n };\n },\n [provider]\n );\n\n const getSnapshot = useCallback(() => {\n if (provider === undefined) {\n return \"not-loaded\";\n }\n return provider.getStatus();\n }, [provider]);\n\n return useSyncExternalStore(subscribe, getSnapshot, getSnapshot);\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 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(TextEditorType.Lexical, \"root\");\n }, [room]);\n\n // Get user info or allow override from props\n const self = useSelf();\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 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 {self && (\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={self.info?.name ?? \"\"} // use empty string to prevent random name\n cursorColor={self.info?.color as string | undefined}\n cursorsContainerRef={containerRef}\n shouldBootstrap={true}\n />\n )}\n\n {hasResolveMentionSuggestions && <MentionPlugin />}\n <CommentPluginProvider>{children}</CommentPluginProvider>\n </>\n );\n};\n\nexport function 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":["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.8.2" === "string" && "2.8.2";
4
+ const PKG_VERSION = typeof "2.8.3-tiptap2" === "string" && "2.8.3-tiptap2";
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 ROLLUP_FORMAT: string;\n\nexport const PKG_NAME = \"@liveblocks/react-lexical\";\nexport const PKG_VERSION = typeof __VERSION__ === \"string\" && __VERSION__;\nexport const PKG_FORMAT = typeof ROLLUP_FORMAT === \"string\" && ROLLUP_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,KAAkB,QAAY,IAAA;;;;;;"}
1
+ {"version":3,"file":"version.js","sources":["../src/version.ts"],"sourcesContent":["declare const __VERSION__: string;\ndeclare const ROLLUP_FORMAT: string;\n\nexport const PKG_NAME = \"@liveblocks/react-lexical\";\nexport const PKG_VERSION = typeof __VERSION__ === \"string\" && __VERSION__;\nexport const PKG_FORMAT = typeof ROLLUP_FORMAT === \"string\" && ROLLUP_FORMAT;\n"],"names":[],"mappings":";;AAGO,MAAM,QAAW,GAAA,4BAAA;AACX,MAAA,WAAA,GAAc,OAAO,eAAA,KAAgB,QAAY,IAAA,gBAAA;AACjD,MAAA,UAAA,GAAa,OAAO,KAAA,KAAkB,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.8.2" === "string" && "2.8.2";
2
+ const PKG_VERSION = typeof "2.8.3-tiptap2" === "string" && "2.8.3-tiptap2";
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 ROLLUP_FORMAT: string;\n\nexport const PKG_NAME = \"@liveblocks/react-lexical\";\nexport const PKG_VERSION = typeof __VERSION__ === \"string\" && __VERSION__;\nexport const PKG_FORMAT = typeof ROLLUP_FORMAT === \"string\" && ROLLUP_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,KAAkB,QAAY,IAAA;;;;"}
1
+ {"version":3,"file":"version.mjs","sources":["../src/version.ts"],"sourcesContent":["declare const __VERSION__: string;\ndeclare const ROLLUP_FORMAT: string;\n\nexport const PKG_NAME = \"@liveblocks/react-lexical\";\nexport const PKG_VERSION = typeof __VERSION__ === \"string\" && __VERSION__;\nexport const PKG_FORMAT = typeof ROLLUP_FORMAT === \"string\" && ROLLUP_FORMAT;\n"],"names":[],"mappings":"AAGO,MAAM,QAAW,GAAA,4BAAA;AACX,MAAA,WAAA,GAAc,OAAO,eAAA,KAAgB,QAAY,IAAA,gBAAA;AACjD,MAAA,UAAA,GAAa,OAAO,KAAA,KAAkB,QAAY,IAAA;;;;"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@liveblocks/react-lexical",
3
- "version": "2.8.2",
3
+ "version": "2.8.3-tiptap2",
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.1",
45
- "@liveblocks/client": "2.8.2",
46
- "@liveblocks/core": "2.8.2",
47
- "@liveblocks/react": "2.8.2",
48
- "@liveblocks/react-ui": "2.8.2",
49
- "@liveblocks/yjs": "2.8.2",
45
+ "@liveblocks/client": "2.8.3-tiptap2",
46
+ "@liveblocks/core": "2.8.3-tiptap2",
47
+ "@liveblocks/react": "2.8.3-tiptap2",
48
+ "@liveblocks/react-ui": "2.8.3-tiptap2",
49
+ "@liveblocks/yjs": "2.8.3-tiptap2",
50
50
  "use-sync-external-store": "^1.2.2",
51
51
  "yjs": "^13.6.18"
52
52
  },