@liveblocks/react-lexical 3.18.2 → 3.18.3-test2

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.
Files changed (59) hide show
  1. package/LICENSE +16 -0
  2. package/dist/comments/anchored-threads.cjs +15 -30
  3. package/dist/comments/anchored-threads.cjs.map +1 -1
  4. package/dist/comments/anchored-threads.js +15 -30
  5. package/dist/comments/anchored-threads.js.map +1 -1
  6. package/dist/comments/comment-plugin-provider.cjs +10 -20
  7. package/dist/comments/comment-plugin-provider.cjs.map +1 -1
  8. package/dist/comments/comment-plugin-provider.js +10 -20
  9. package/dist/comments/comment-plugin-provider.js.map +1 -1
  10. package/dist/comments/floating-composer.cjs +7 -14
  11. package/dist/comments/floating-composer.cjs.map +1 -1
  12. package/dist/comments/floating-composer.js +7 -14
  13. package/dist/comments/floating-composer.js.map +1 -1
  14. package/dist/comments/floating-threads.cjs +6 -12
  15. package/dist/comments/floating-threads.cjs.map +1 -1
  16. package/dist/comments/floating-threads.js +6 -12
  17. package/dist/comments/floating-threads.js.map +1 -1
  18. package/dist/comments/wrap-selection-in-thread-mark-node.cjs +5 -1
  19. package/dist/comments/wrap-selection-in-thread-mark-node.cjs.map +1 -1
  20. package/dist/comments/wrap-selection-in-thread-mark-node.js +5 -1
  21. package/dist/comments/wrap-selection-in-thread-mark-node.js.map +1 -1
  22. package/dist/create-dom-range.cjs +1 -1
  23. package/dist/create-dom-range.cjs.map +1 -1
  24. package/dist/create-dom-range.js +1 -1
  25. package/dist/create-dom-range.js.map +1 -1
  26. package/dist/liveblocks-plugin-provider.cjs +3 -5
  27. package/dist/liveblocks-plugin-provider.cjs.map +1 -1
  28. package/dist/liveblocks-plugin-provider.js +3 -5
  29. package/dist/liveblocks-plugin-provider.js.map +1 -1
  30. package/dist/mentions/mention-component.cjs +1 -2
  31. package/dist/mentions/mention-component.cjs.map +1 -1
  32. package/dist/mentions/mention-component.js +1 -2
  33. package/dist/mentions/mention-component.js.map +1 -1
  34. package/dist/mentions/mention-plugin.cjs +29 -57
  35. package/dist/mentions/mention-plugin.cjs.map +1 -1
  36. package/dist/mentions/mention-plugin.js +29 -57
  37. package/dist/mentions/mention-plugin.js.map +1 -1
  38. package/dist/mentions/suggestions.cjs +12 -24
  39. package/dist/mentions/suggestions.cjs.map +1 -1
  40. package/dist/mentions/suggestions.js +12 -24
  41. package/dist/mentions/suggestions.js.map +1 -1
  42. package/dist/toolbar/floating-toolbar.cjs +1 -2
  43. package/dist/toolbar/floating-toolbar.cjs.map +1 -1
  44. package/dist/toolbar/floating-toolbar.js +1 -2
  45. package/dist/toolbar/floating-toolbar.js.map +1 -1
  46. package/dist/toolbar/toolbar.cjs +1 -2
  47. package/dist/toolbar/toolbar.cjs.map +1 -1
  48. package/dist/toolbar/toolbar.js +1 -2
  49. package/dist/toolbar/toolbar.js.map +1 -1
  50. package/dist/version-history/history-version-preview.cjs.map +1 -1
  51. package/dist/version-history/history-version-preview.js.map +1 -1
  52. package/dist/version.cjs +1 -1
  53. package/dist/version.cjs.map +1 -1
  54. package/dist/version.js +1 -1
  55. package/dist/version.js.map +1 -1
  56. package/package.json +11 -35
  57. package/src/styles/index.css +3 -3
  58. package/styles.css +1 -1
  59. package/styles.css.map +1 -1
@@ -25,12 +25,10 @@ function FloatingThreads({
25
25
  const activeElements2 = /* @__PURE__ */ new Set();
26
26
  for (const thread of activeThreads) {
27
27
  const keys = nodes.get(thread);
28
- if (keys === void 0)
29
- continue;
28
+ if (keys === void 0) continue;
30
29
  for (const key of keys) {
31
30
  const element = editor.getElementByKey(key);
32
- if (element === null)
33
- continue;
31
+ if (element === null) continue;
34
32
  activeElements2.add(element);
35
33
  }
36
34
  }
@@ -38,8 +36,7 @@ function FloatingThreads({
38
36
  }
39
37
  const activeElements = getActiveElements();
40
38
  const sortedElements = Array.from(activeElements).sort(compareNodes);
41
- if (sortedElements.length === 0)
42
- return null;
39
+ if (sortedElements.length === 0) return null;
43
40
  const range3 = document.createRange();
44
41
  range3.setStartBefore(sortedElements[0]);
45
42
  range3.setEndAfter(sortedElements[sortedElements.length - 1]);
@@ -62,8 +59,7 @@ function FloatingThreads({
62
59
  return editor.registerUpdateListener(handleUpdateRange);
63
60
  }, [editor, handleUpdateRange]);
64
61
  const handleEscapeKeydown = useCallback(() => {
65
- if (range === null)
66
- return false;
62
+ if (range === null) return false;
67
63
  setRange(null);
68
64
  return true;
69
65
  }, [range]);
@@ -75,8 +71,7 @@ function FloatingThreads({
75
71
  );
76
72
  }, [editor, handleEscapeKeydown]);
77
73
  const isCollapsed = useIsSelectionCollapsed();
78
- if (range === null || isCollapsed === null || !isCollapsed)
79
- return null;
74
+ if (range === null || isCollapsed === null || !isCollapsed) return null;
80
75
  return /* @__PURE__ */ jsx(FloatingThreadPortal, { range: range.range, ...props, children: range.threads.map((thread) => /* @__PURE__ */ jsx(
81
76
  ThreadWrapper,
82
77
  {
@@ -196,8 +191,7 @@ function useIsSelectionCollapsed() {
196
191
  const getSnapshot = useCallback(() => {
197
192
  return editor.getEditorState().read(() => {
198
193
  const selection = $getSelection();
199
- if (selection === null)
200
- return null;
194
+ if (selection === null) return null;
201
195
  return selection.isCollapsed();
202
196
  });
203
197
  }, [editor]);
@@ -1 +1 @@
1
- {"version":3,"file":"floating-threads.js","sources":["../../src/comments/floating-threads.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, ThreadData } from \"@liveblocks/client\";\nimport type { DCM, DTM } from \"@liveblocks/core\";\nimport { useLayoutEffect } from \"@liveblocks/react/_private\";\nimport {\n Thread as DefaultThread,\n type ThreadProps,\n} from \"@liveblocks/react-ui\";\nimport { cn, Portal, useStableComponent } from \"@liveblocks/react-ui/_private\";\nimport {\n $getSelection,\n COMMAND_PRIORITY_HIGH,\n KEY_ESCAPE_COMMAND,\n} from \"lexical\";\nimport {\n type ComponentType,\n type HTMLAttributes,\n type KeyboardEvent,\n type ReactNode,\n useCallback,\n useContext,\n useEffect,\n useState,\n useSyncExternalStore,\n} from \"react\";\n\nimport { compareNodes } from \"./anchored-threads\";\nimport {\n ActiveThreadsContext,\n type ThreadToNodesMap,\n} from \"./comment-plugin-provider\";\nimport { ThreadToNodesContext } from \"./comment-plugin-provider\";\n\ntype FloatingThreadsComponents = {\n Thread: ComponentType<ThreadProps>;\n};\n\nexport interface FloatingThreadsProps<\n TM extends BaseMetadata = DTM,\n CM extends BaseMetadata = DCM,\n> extends Omit<HTMLAttributes<HTMLDivElement>, \"children\"> {\n /**\n * The threads to display.\n */\n threads: ThreadData<TM, CM>[];\n\n /**\n * Override the component's components.\n */\n components?: Partial<FloatingThreadsComponents>;\n}\n\nexport function FloatingThreads({\n threads,\n components,\n ...props\n}: FloatingThreadsProps) {\n const activeThreads = useActiveThreads();\n\n const Thread = useStableComponent(components?.Thread, DefaultThread);\n\n const [editor] = useLexicalComposerContext();\n const nodes = useThreadToNodes(); // A map of thread ids to a set of thread mark nodes associated with the thread\n\n const [range, setRange] = useState<{\n range: Range;\n threads: ThreadData[];\n } | null>(null);\n\n const handleUpdateRange = useCallback(() => {\n function getActiveRange(): Range | null {\n function getActiveElements() {\n const activeElements = new Set<HTMLElement>();\n\n for (const thread of activeThreads) {\n const keys = nodes.get(thread);\n if (keys === undefined) continue;\n\n for (const key of keys) {\n const element = editor.getElementByKey(key);\n if (element === null) continue;\n activeElements.add(element);\n }\n }\n return activeElements;\n }\n\n const activeElements = getActiveElements();\n\n const sortedElements = Array.from(activeElements).sort(compareNodes);\n if (sortedElements.length === 0) return null;\n\n const range = document.createRange();\n range.setStartBefore(sortedElements[0]);\n range.setEndAfter(sortedElements[sortedElements.length - 1]);\n\n return range;\n }\n\n const active = (threads ?? []).filter((thread) =>\n activeThreads.includes(thread.id)\n );\n\n const range = getActiveRange();\n if (range === null) {\n setRange(null);\n return;\n }\n\n setRange({ range, threads: active });\n }, [activeThreads, nodes, editor, threads]);\n\n useEffect(() => {\n handleUpdateRange();\n }, [handleUpdateRange]);\n\n useEffect(() => {\n return editor.registerUpdateListener(handleUpdateRange);\n }, [editor, handleUpdateRange]);\n\n const handleEscapeKeydown = useCallback((): boolean => {\n if (range === null) return false;\n setRange(null);\n return true;\n }, [range]);\n\n useEffect(() => {\n return editor.registerCommand(\n KEY_ESCAPE_COMMAND,\n handleEscapeKeydown,\n COMMAND_PRIORITY_HIGH\n );\n }, [editor, handleEscapeKeydown]);\n\n const isCollapsed = useIsSelectionCollapsed();\n\n if (range === null || isCollapsed === null || !isCollapsed) return null;\n\n return (\n <FloatingThreadPortal range={range.range} {...props}>\n {range.threads.map((thread) => (\n <ThreadWrapper\n key={thread.id}\n thread={thread}\n Thread={Thread}\n onEscapeKeydown={handleEscapeKeydown}\n className=\"lb-lexical-floating-threads-thread\"\n />\n ))}\n </FloatingThreadPortal>\n );\n}\n\ninterface FloatingThreadPortalProps\n extends Omit<HTMLAttributes<HTMLDivElement>, \"children\"> {\n range: Range;\n children: ReactNode;\n}\n\nexport const FLOATING_THREAD_COLLISION_PADDING = 10;\n\nfunction FloatingThreadPortal({\n range,\n children,\n className,\n style,\n ...props\n}: FloatingThreadPortalProps) {\n const {\n refs: { setReference, setFloating },\n strategy,\n x,\n y,\n } = useFloating({\n strategy: \"absolute\",\n placement: \"bottom\",\n middleware: [\n flip({ padding: FLOATING_THREAD_COLLISION_PADDING, crossAxis: false }),\n offset(10),\n hide({ padding: FLOATING_THREAD_COLLISION_PADDING }),\n shift({\n padding: FLOATING_THREAD_COLLISION_PADDING,\n limiter: limitShift(),\n }),\n size({\n padding: FLOATING_THREAD_COLLISION_PADDING,\n apply({ availableWidth, availableHeight, elements }) {\n elements.floating.style.setProperty(\n \"--lb-lexical-floating-threads-available-width\",\n `${availableWidth}px`\n );\n elements.floating.style.setProperty(\n \"--lb-lexical-floating-threads-available-height\",\n `${availableHeight}px`\n );\n },\n }),\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 }, [setReference, range]);\n\n return (\n <Portal asChild>\n <div\n ref={setFloating}\n {...props}\n style={{\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={cn(\n \"lb-root lb-portal lb-elevation lb-lexical-floating lb-lexical-floating-threads\",\n className\n )}\n >\n {children}\n </div>\n </Portal>\n );\n}\n\ninterface ThreadWrapperProps extends ThreadProps {\n thread: ThreadData;\n Thread: ComponentType<ThreadProps>;\n onEscapeKeydown: () => void;\n}\n\nfunction ThreadWrapper({\n thread,\n Thread,\n onEscapeKeydown,\n onKeyDown,\n ...threadProps\n}: ThreadWrapperProps) {\n const handleKeyDown = useCallback(\n (event: KeyboardEvent<HTMLDivElement>) => {\n onKeyDown?.(event);\n\n // TODO: Add ability to preventDefault on keydown to override the default behavior, e.g. to show an alert dialog\n if (event.key === \"Escape\") {\n onEscapeKeydown();\n }\n },\n [onEscapeKeydown, onKeyDown]\n );\n\n return <Thread thread={thread} onKeyDown={handleKeyDown} {...threadProps} />;\n}\n\nfunction useThreadToNodes(): ThreadToNodesMap {\n const threadToNodes = useContext(ThreadToNodesContext);\n if (threadToNodes === null) {\n throw new Error(\n \"FloatingThreads component must be used within a LiveblocksPlugin component.\"\n );\n }\n return threadToNodes;\n}\n\nfunction useIsSelectionCollapsed(): boolean | null {\n const [editor] = useLexicalComposerContext();\n\n const subscribe = useCallback(\n (onStoreChange: () => void) => {\n return editor.registerUpdateListener(onStoreChange);\n },\n [editor]\n );\n\n const getSnapshot = useCallback(() => {\n return editor.getEditorState().read(() => {\n const selection = $getSelection();\n if (selection === null) return null;\n return selection.isCollapsed();\n });\n }, [editor]);\n\n return useSyncExternalStore(subscribe, getSnapshot, getSnapshot);\n}\n\nfunction useActiveThreads() {\n const activeThreads = useContext(ActiveThreadsContext);\n if (activeThreads === null) {\n throw new Error(\n \"FloatingThreads component must be used within LiveblocksPlugin.\"\n );\n }\n\n return activeThreads;\n}\n"],"names":["Thread","DefaultThread","activeElements","range"],"mappings":"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"}
1
+ {"version":3,"file":"floating-threads.js","sources":["../../src/comments/floating-threads.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, ThreadData } from \"@liveblocks/client\";\nimport type { DCM, DTM } from \"@liveblocks/core\";\nimport { useLayoutEffect } from \"@liveblocks/react/_private\";\nimport {\n Thread as DefaultThread,\n type ThreadProps,\n} from \"@liveblocks/react-ui\";\nimport { cn, Portal, useStableComponent } from \"@liveblocks/react-ui/_private\";\nimport {\n $getSelection,\n COMMAND_PRIORITY_HIGH,\n KEY_ESCAPE_COMMAND,\n} from \"lexical\";\nimport {\n type ComponentType,\n type HTMLAttributes,\n type KeyboardEvent,\n type ReactNode,\n useCallback,\n useContext,\n useEffect,\n useState,\n useSyncExternalStore,\n} from \"react\";\n\nimport { compareNodes } from \"./anchored-threads\";\nimport {\n ActiveThreadsContext,\n type ThreadToNodesMap,\n} from \"./comment-plugin-provider\";\nimport { ThreadToNodesContext } from \"./comment-plugin-provider\";\n\ntype FloatingThreadsComponents = {\n Thread: ComponentType<ThreadProps>;\n};\n\nexport interface FloatingThreadsProps<\n TM extends BaseMetadata = DTM,\n CM extends BaseMetadata = DCM,\n> extends Omit<HTMLAttributes<HTMLDivElement>, \"children\"> {\n /**\n * The threads to display.\n */\n threads: ThreadData<TM, CM>[];\n\n /**\n * Override the component's components.\n */\n components?: Partial<FloatingThreadsComponents>;\n}\n\nexport function FloatingThreads({\n threads,\n components,\n ...props\n}: FloatingThreadsProps) {\n const activeThreads = useActiveThreads();\n\n const Thread = useStableComponent(components?.Thread, DefaultThread);\n\n const [editor] = useLexicalComposerContext();\n const nodes = useThreadToNodes(); // A map of thread ids to a set of thread mark nodes associated with the thread\n\n const [range, setRange] = useState<{\n range: Range;\n threads: ThreadData[];\n } | null>(null);\n\n const handleUpdateRange = useCallback(() => {\n function getActiveRange(): Range | null {\n function getActiveElements() {\n const activeElements = new Set<HTMLElement>();\n\n for (const thread of activeThreads) {\n const keys = nodes.get(thread);\n if (keys === undefined) continue;\n\n for (const key of keys) {\n const element = editor.getElementByKey(key);\n if (element === null) continue;\n activeElements.add(element);\n }\n }\n return activeElements;\n }\n\n const activeElements = getActiveElements();\n\n const sortedElements = Array.from(activeElements).sort(compareNodes);\n if (sortedElements.length === 0) return null;\n\n const range = document.createRange();\n range.setStartBefore(sortedElements[0]);\n range.setEndAfter(sortedElements[sortedElements.length - 1]);\n\n return range;\n }\n\n const active = (threads ?? []).filter((thread) =>\n activeThreads.includes(thread.id)\n );\n\n const range = getActiveRange();\n if (range === null) {\n setRange(null);\n return;\n }\n\n setRange({ range, threads: active });\n }, [activeThreads, nodes, editor, threads]);\n\n useEffect(() => {\n handleUpdateRange();\n }, [handleUpdateRange]);\n\n useEffect(() => {\n return editor.registerUpdateListener(handleUpdateRange);\n }, [editor, handleUpdateRange]);\n\n const handleEscapeKeydown = useCallback((): boolean => {\n if (range === null) return false;\n setRange(null);\n return true;\n }, [range]);\n\n useEffect(() => {\n return editor.registerCommand(\n KEY_ESCAPE_COMMAND,\n handleEscapeKeydown,\n COMMAND_PRIORITY_HIGH\n );\n }, [editor, handleEscapeKeydown]);\n\n const isCollapsed = useIsSelectionCollapsed();\n\n if (range === null || isCollapsed === null || !isCollapsed) return null;\n\n return (\n <FloatingThreadPortal range={range.range} {...props}>\n {range.threads.map((thread) => (\n <ThreadWrapper\n key={thread.id}\n thread={thread}\n Thread={Thread}\n onEscapeKeydown={handleEscapeKeydown}\n className=\"lb-lexical-floating-threads-thread\"\n />\n ))}\n </FloatingThreadPortal>\n );\n}\n\ninterface FloatingThreadPortalProps extends Omit<\n HTMLAttributes<HTMLDivElement>,\n \"children\"\n> {\n range: Range;\n children: ReactNode;\n}\n\nexport const FLOATING_THREAD_COLLISION_PADDING = 10;\n\nfunction FloatingThreadPortal({\n range,\n children,\n className,\n style,\n ...props\n}: FloatingThreadPortalProps) {\n const {\n refs: { setReference, setFloating },\n strategy,\n x,\n y,\n } = useFloating({\n strategy: \"absolute\",\n placement: \"bottom\",\n middleware: [\n flip({ padding: FLOATING_THREAD_COLLISION_PADDING, crossAxis: false }),\n offset(10),\n hide({ padding: FLOATING_THREAD_COLLISION_PADDING }),\n shift({\n padding: FLOATING_THREAD_COLLISION_PADDING,\n limiter: limitShift(),\n }),\n size({\n padding: FLOATING_THREAD_COLLISION_PADDING,\n apply({ availableWidth, availableHeight, elements }) {\n elements.floating.style.setProperty(\n \"--lb-lexical-floating-threads-available-width\",\n `${availableWidth}px`\n );\n elements.floating.style.setProperty(\n \"--lb-lexical-floating-threads-available-height\",\n `${availableHeight}px`\n );\n },\n }),\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 }, [setReference, range]);\n\n return (\n <Portal asChild>\n <div\n ref={setFloating}\n {...props}\n style={{\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={cn(\n \"lb-root lb-portal lb-elevation lb-lexical-floating lb-lexical-floating-threads\",\n className\n )}\n >\n {children}\n </div>\n </Portal>\n );\n}\n\ninterface ThreadWrapperProps extends ThreadProps {\n thread: ThreadData;\n Thread: ComponentType<ThreadProps>;\n onEscapeKeydown: () => void;\n}\n\nfunction ThreadWrapper({\n thread,\n Thread,\n onEscapeKeydown,\n onKeyDown,\n ...threadProps\n}: ThreadWrapperProps) {\n const handleKeyDown = useCallback(\n (event: KeyboardEvent<HTMLDivElement>) => {\n onKeyDown?.(event);\n\n // TODO: Add ability to preventDefault on keydown to override the default behavior, e.g. to show an alert dialog\n if (event.key === \"Escape\") {\n onEscapeKeydown();\n }\n },\n [onEscapeKeydown, onKeyDown]\n );\n\n return <Thread thread={thread} onKeyDown={handleKeyDown} {...threadProps} />;\n}\n\nfunction useThreadToNodes(): ThreadToNodesMap {\n const threadToNodes = useContext(ThreadToNodesContext);\n if (threadToNodes === null) {\n throw new Error(\n \"FloatingThreads component must be used within a LiveblocksPlugin component.\"\n );\n }\n return threadToNodes;\n}\n\nfunction useIsSelectionCollapsed(): boolean | null {\n const [editor] = useLexicalComposerContext();\n\n const subscribe = useCallback(\n (onStoreChange: () => void) => {\n return editor.registerUpdateListener(onStoreChange);\n },\n [editor]\n );\n\n const getSnapshot = useCallback(() => {\n return editor.getEditorState().read(() => {\n const selection = $getSelection();\n if (selection === null) return null;\n return selection.isCollapsed();\n });\n }, [editor]);\n\n return useSyncExternalStore(subscribe, getSnapshot, getSnapshot);\n}\n\nfunction useActiveThreads() {\n const activeThreads = useContext(ActiveThreadsContext);\n if (activeThreads === null) {\n throw new Error(\n \"FloatingThreads component must be used within LiveblocksPlugin.\"\n );\n }\n\n return activeThreads;\n}\n"],"names":["Thread","DefaultThread","activeElements","range"],"mappings":"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"}
@@ -55,7 +55,11 @@ function $wrapSelectionInThreadMarkNode(selection, isBackward, id, createNode) {
55
55
  }
56
56
  }
57
57
  if (lexical.$isElementNode(lastCreatedMarkNode)) {
58
- isBackward ? lastCreatedMarkNode.selectStart() : lastCreatedMarkNode.selectEnd();
58
+ if (isBackward) {
59
+ lastCreatedMarkNode.selectStart();
60
+ } else {
61
+ lastCreatedMarkNode.selectEnd();
62
+ }
59
63
  }
60
64
  }
61
65
 
@@ -1 +1 @@
1
- {"version":3,"file":"wrap-selection-in-thread-mark-node.cjs","sources":["../../src/comments/wrap-selection-in-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 { LexicalNode, RangeSelection } from \"lexical\";\nimport { $isElementNode, $isTextNode } from \"lexical\";\n\nimport type { ThreadMarkNode } from \"./thread-mark-node\";\nimport { $createThreadMarkNode, $isThreadMarkNode } from \"./thread-mark-node\";\n\nexport default function $wrapSelectionInThreadMarkNode(\n selection: RangeSelection,\n isBackward: boolean,\n id: string,\n createNode?: (ids: Array<string>) => ThreadMarkNode\n): void {\n const nodes = selection.getNodes();\n const anchorOffset = selection.anchor.offset;\n const focusOffset = selection.focus.offset;\n const nodesLength = nodes.length;\n const startOffset = isBackward ? focusOffset : anchorOffset;\n const endOffset = isBackward ? anchorOffset : focusOffset;\n let currentNodeParent;\n let lastCreatedMarkNode;\n\n // We only want wrap adjacent text nodes, line break nodes\n // and inline element nodes. For decorator nodes and block\n // element nodes, we step out of their boundary and start\n // again after, if there are more nodes.\n for (let i = 0; i < nodesLength; i++) {\n const node = nodes[i];\n if (\n $isElementNode(lastCreatedMarkNode) &&\n lastCreatedMarkNode.isParentOf(node)\n ) {\n // If the current node is a child of the last created mark node, there is nothing to do here\n continue;\n }\n const isFirstNode = i === 0;\n const isLastNode = i === nodesLength - 1;\n let targetNode: LexicalNode | null = null;\n\n if ($isTextNode(node)) {\n // Case 1: The node is a text node and we can split it\n const textContentSize = node.getTextContentSize();\n const startTextOffset = isFirstNode ? startOffset : 0;\n const endTextOffset = isLastNode ? endOffset : textContentSize;\n if (startTextOffset === 0 && endTextOffset === 0) {\n continue;\n }\n const splitNodes = node.splitText(startTextOffset, endTextOffset);\n targetNode =\n splitNodes.length > 1 &&\n (splitNodes.length === 3 ||\n (isFirstNode && !isLastNode) ||\n endTextOffset === textContentSize)\n ? splitNodes[1]\n : splitNodes[0];\n } else if ($isThreadMarkNode(node)) {\n // Case 2: the node is a mark node and we can ignore it as a target,\n // moving on to its children. Note that when we make a mark inside\n // another mark, it may utlimately be unnested by a call to\n // `registerNestedElementResolver<MarkNode>` somewhere else in the\n // codebase.\n\n continue;\n } else if ($isElementNode(node) && node.isInline()) {\n // Case 3: inline element nodes can be added in their entirety to the new\n // mark\n targetNode = node;\n }\n\n if (targetNode !== null) {\n // Now that we have a target node for wrapping with a mark, we can run\n // through special cases.\n if (targetNode && targetNode.is(currentNodeParent)) {\n // The current node is a child of the target node to be wrapped, there\n // is nothing to do here.\n continue;\n }\n const parentNode = targetNode.getParent();\n if (parentNode === null || !parentNode.is(currentNodeParent)) {\n // If the parent node is not the current node's parent node, we can\n // clear the last created mark node.\n lastCreatedMarkNode = undefined;\n }\n\n currentNodeParent = parentNode;\n\n if (lastCreatedMarkNode === undefined) {\n // If we don't have a created mark node, we can make one\n const createMarkNode = createNode || $createThreadMarkNode;\n lastCreatedMarkNode = createMarkNode([id]);\n targetNode.insertBefore(lastCreatedMarkNode);\n }\n\n // Add the target node to be wrapped in the latest created mark node\n lastCreatedMarkNode.append(targetNode);\n } else {\n // If we don't have a target node to wrap we can clear our state and\n // continue on with the next node\n currentNodeParent = undefined;\n lastCreatedMarkNode = undefined;\n }\n }\n // Make selection collapsed at the end\n if ($isElementNode(lastCreatedMarkNode)) {\n // eslint-disable-next-line no-unused-expressions\n isBackward\n ? lastCreatedMarkNode.selectStart()\n : lastCreatedMarkNode.selectEnd();\n }\n}\n"],"names":["$isElementNode","$isTextNode","$isThreadMarkNode","$createThreadMarkNode"],"mappings":"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"}
1
+ {"version":3,"file":"wrap-selection-in-thread-mark-node.cjs","sources":["../../src/comments/wrap-selection-in-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 { LexicalNode, RangeSelection } from \"lexical\";\nimport { $isElementNode, $isTextNode } from \"lexical\";\n\nimport type { ThreadMarkNode } from \"./thread-mark-node\";\nimport { $createThreadMarkNode, $isThreadMarkNode } from \"./thread-mark-node\";\n\nexport default function $wrapSelectionInThreadMarkNode(\n selection: RangeSelection,\n isBackward: boolean,\n id: string,\n createNode?: (ids: Array<string>) => ThreadMarkNode\n): void {\n const nodes = selection.getNodes();\n const anchorOffset = selection.anchor.offset;\n const focusOffset = selection.focus.offset;\n const nodesLength = nodes.length;\n const startOffset = isBackward ? focusOffset : anchorOffset;\n const endOffset = isBackward ? anchorOffset : focusOffset;\n let currentNodeParent;\n let lastCreatedMarkNode;\n\n // We only want wrap adjacent text nodes, line break nodes\n // and inline element nodes. For decorator nodes and block\n // element nodes, we step out of their boundary and start\n // again after, if there are more nodes.\n for (let i = 0; i < nodesLength; i++) {\n const node = nodes[i];\n if (\n $isElementNode(lastCreatedMarkNode) &&\n lastCreatedMarkNode.isParentOf(node)\n ) {\n // If the current node is a child of the last created mark node, there is nothing to do here\n continue;\n }\n const isFirstNode = i === 0;\n const isLastNode = i === nodesLength - 1;\n let targetNode: LexicalNode | null = null;\n\n if ($isTextNode(node)) {\n // Case 1: The node is a text node and we can split it\n const textContentSize = node.getTextContentSize();\n const startTextOffset = isFirstNode ? startOffset : 0;\n const endTextOffset = isLastNode ? endOffset : textContentSize;\n if (startTextOffset === 0 && endTextOffset === 0) {\n continue;\n }\n const splitNodes = node.splitText(startTextOffset, endTextOffset);\n targetNode =\n splitNodes.length > 1 &&\n (splitNodes.length === 3 ||\n (isFirstNode && !isLastNode) ||\n endTextOffset === textContentSize)\n ? splitNodes[1]\n : splitNodes[0];\n } else if ($isThreadMarkNode(node)) {\n // Case 2: the node is a mark node and we can ignore it as a target,\n // moving on to its children. Note that when we make a mark inside\n // another mark, it may utlimately be unnested by a call to\n // `registerNestedElementResolver<MarkNode>` somewhere else in the\n // codebase.\n\n continue;\n } else if ($isElementNode(node) && node.isInline()) {\n // Case 3: inline element nodes can be added in their entirety to the new\n // mark\n targetNode = node;\n }\n\n if (targetNode !== null) {\n // Now that we have a target node for wrapping with a mark, we can run\n // through special cases.\n if (targetNode && targetNode.is(currentNodeParent)) {\n // The current node is a child of the target node to be wrapped, there\n // is nothing to do here.\n continue;\n }\n const parentNode = targetNode.getParent();\n if (parentNode === null || !parentNode.is(currentNodeParent)) {\n // If the parent node is not the current node's parent node, we can\n // clear the last created mark node.\n lastCreatedMarkNode = undefined;\n }\n\n currentNodeParent = parentNode;\n\n if (lastCreatedMarkNode === undefined) {\n // If we don't have a created mark node, we can make one\n const createMarkNode = createNode || $createThreadMarkNode;\n lastCreatedMarkNode = createMarkNode([id]);\n targetNode.insertBefore(lastCreatedMarkNode);\n }\n\n // Add the target node to be wrapped in the latest created mark node\n lastCreatedMarkNode.append(targetNode);\n } else {\n // If we don't have a target node to wrap we can clear our state and\n // continue on with the next node\n currentNodeParent = undefined;\n lastCreatedMarkNode = undefined;\n }\n }\n // Make selection collapsed at the end\n if ($isElementNode(lastCreatedMarkNode)) {\n if (isBackward) {\n lastCreatedMarkNode.selectStart();\n } else {\n lastCreatedMarkNode.selectEnd();\n }\n }\n}\n"],"names":["$isElementNode","$isTextNode","$isThreadMarkNode","$createThreadMarkNode"],"mappings":"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"}
@@ -53,7 +53,11 @@ function $wrapSelectionInThreadMarkNode(selection, isBackward, id, createNode) {
53
53
  }
54
54
  }
55
55
  if ($isElementNode(lastCreatedMarkNode)) {
56
- isBackward ? lastCreatedMarkNode.selectStart() : lastCreatedMarkNode.selectEnd();
56
+ if (isBackward) {
57
+ lastCreatedMarkNode.selectStart();
58
+ } else {
59
+ lastCreatedMarkNode.selectEnd();
60
+ }
57
61
  }
58
62
  }
59
63
 
@@ -1 +1 @@
1
- {"version":3,"file":"wrap-selection-in-thread-mark-node.js","sources":["../../src/comments/wrap-selection-in-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 { LexicalNode, RangeSelection } from \"lexical\";\nimport { $isElementNode, $isTextNode } from \"lexical\";\n\nimport type { ThreadMarkNode } from \"./thread-mark-node\";\nimport { $createThreadMarkNode, $isThreadMarkNode } from \"./thread-mark-node\";\n\nexport default function $wrapSelectionInThreadMarkNode(\n selection: RangeSelection,\n isBackward: boolean,\n id: string,\n createNode?: (ids: Array<string>) => ThreadMarkNode\n): void {\n const nodes = selection.getNodes();\n const anchorOffset = selection.anchor.offset;\n const focusOffset = selection.focus.offset;\n const nodesLength = nodes.length;\n const startOffset = isBackward ? focusOffset : anchorOffset;\n const endOffset = isBackward ? anchorOffset : focusOffset;\n let currentNodeParent;\n let lastCreatedMarkNode;\n\n // We only want wrap adjacent text nodes, line break nodes\n // and inline element nodes. For decorator nodes and block\n // element nodes, we step out of their boundary and start\n // again after, if there are more nodes.\n for (let i = 0; i < nodesLength; i++) {\n const node = nodes[i];\n if (\n $isElementNode(lastCreatedMarkNode) &&\n lastCreatedMarkNode.isParentOf(node)\n ) {\n // If the current node is a child of the last created mark node, there is nothing to do here\n continue;\n }\n const isFirstNode = i === 0;\n const isLastNode = i === nodesLength - 1;\n let targetNode: LexicalNode | null = null;\n\n if ($isTextNode(node)) {\n // Case 1: The node is a text node and we can split it\n const textContentSize = node.getTextContentSize();\n const startTextOffset = isFirstNode ? startOffset : 0;\n const endTextOffset = isLastNode ? endOffset : textContentSize;\n if (startTextOffset === 0 && endTextOffset === 0) {\n continue;\n }\n const splitNodes = node.splitText(startTextOffset, endTextOffset);\n targetNode =\n splitNodes.length > 1 &&\n (splitNodes.length === 3 ||\n (isFirstNode && !isLastNode) ||\n endTextOffset === textContentSize)\n ? splitNodes[1]\n : splitNodes[0];\n } else if ($isThreadMarkNode(node)) {\n // Case 2: the node is a mark node and we can ignore it as a target,\n // moving on to its children. Note that when we make a mark inside\n // another mark, it may utlimately be unnested by a call to\n // `registerNestedElementResolver<MarkNode>` somewhere else in the\n // codebase.\n\n continue;\n } else if ($isElementNode(node) && node.isInline()) {\n // Case 3: inline element nodes can be added in their entirety to the new\n // mark\n targetNode = node;\n }\n\n if (targetNode !== null) {\n // Now that we have a target node for wrapping with a mark, we can run\n // through special cases.\n if (targetNode && targetNode.is(currentNodeParent)) {\n // The current node is a child of the target node to be wrapped, there\n // is nothing to do here.\n continue;\n }\n const parentNode = targetNode.getParent();\n if (parentNode === null || !parentNode.is(currentNodeParent)) {\n // If the parent node is not the current node's parent node, we can\n // clear the last created mark node.\n lastCreatedMarkNode = undefined;\n }\n\n currentNodeParent = parentNode;\n\n if (lastCreatedMarkNode === undefined) {\n // If we don't have a created mark node, we can make one\n const createMarkNode = createNode || $createThreadMarkNode;\n lastCreatedMarkNode = createMarkNode([id]);\n targetNode.insertBefore(lastCreatedMarkNode);\n }\n\n // Add the target node to be wrapped in the latest created mark node\n lastCreatedMarkNode.append(targetNode);\n } else {\n // If we don't have a target node to wrap we can clear our state and\n // continue on with the next node\n currentNodeParent = undefined;\n lastCreatedMarkNode = undefined;\n }\n }\n // Make selection collapsed at the end\n if ($isElementNode(lastCreatedMarkNode)) {\n // eslint-disable-next-line no-unused-expressions\n isBackward\n ? lastCreatedMarkNode.selectStart()\n : lastCreatedMarkNode.selectEnd();\n }\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"wrap-selection-in-thread-mark-node.js","sources":["../../src/comments/wrap-selection-in-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 { LexicalNode, RangeSelection } from \"lexical\";\nimport { $isElementNode, $isTextNode } from \"lexical\";\n\nimport type { ThreadMarkNode } from \"./thread-mark-node\";\nimport { $createThreadMarkNode, $isThreadMarkNode } from \"./thread-mark-node\";\n\nexport default function $wrapSelectionInThreadMarkNode(\n selection: RangeSelection,\n isBackward: boolean,\n id: string,\n createNode?: (ids: Array<string>) => ThreadMarkNode\n): void {\n const nodes = selection.getNodes();\n const anchorOffset = selection.anchor.offset;\n const focusOffset = selection.focus.offset;\n const nodesLength = nodes.length;\n const startOffset = isBackward ? focusOffset : anchorOffset;\n const endOffset = isBackward ? anchorOffset : focusOffset;\n let currentNodeParent;\n let lastCreatedMarkNode;\n\n // We only want wrap adjacent text nodes, line break nodes\n // and inline element nodes. For decorator nodes and block\n // element nodes, we step out of their boundary and start\n // again after, if there are more nodes.\n for (let i = 0; i < nodesLength; i++) {\n const node = nodes[i];\n if (\n $isElementNode(lastCreatedMarkNode) &&\n lastCreatedMarkNode.isParentOf(node)\n ) {\n // If the current node is a child of the last created mark node, there is nothing to do here\n continue;\n }\n const isFirstNode = i === 0;\n const isLastNode = i === nodesLength - 1;\n let targetNode: LexicalNode | null = null;\n\n if ($isTextNode(node)) {\n // Case 1: The node is a text node and we can split it\n const textContentSize = node.getTextContentSize();\n const startTextOffset = isFirstNode ? startOffset : 0;\n const endTextOffset = isLastNode ? endOffset : textContentSize;\n if (startTextOffset === 0 && endTextOffset === 0) {\n continue;\n }\n const splitNodes = node.splitText(startTextOffset, endTextOffset);\n targetNode =\n splitNodes.length > 1 &&\n (splitNodes.length === 3 ||\n (isFirstNode && !isLastNode) ||\n endTextOffset === textContentSize)\n ? splitNodes[1]\n : splitNodes[0];\n } else if ($isThreadMarkNode(node)) {\n // Case 2: the node is a mark node and we can ignore it as a target,\n // moving on to its children. Note that when we make a mark inside\n // another mark, it may utlimately be unnested by a call to\n // `registerNestedElementResolver<MarkNode>` somewhere else in the\n // codebase.\n\n continue;\n } else if ($isElementNode(node) && node.isInline()) {\n // Case 3: inline element nodes can be added in their entirety to the new\n // mark\n targetNode = node;\n }\n\n if (targetNode !== null) {\n // Now that we have a target node for wrapping with a mark, we can run\n // through special cases.\n if (targetNode && targetNode.is(currentNodeParent)) {\n // The current node is a child of the target node to be wrapped, there\n // is nothing to do here.\n continue;\n }\n const parentNode = targetNode.getParent();\n if (parentNode === null || !parentNode.is(currentNodeParent)) {\n // If the parent node is not the current node's parent node, we can\n // clear the last created mark node.\n lastCreatedMarkNode = undefined;\n }\n\n currentNodeParent = parentNode;\n\n if (lastCreatedMarkNode === undefined) {\n // If we don't have a created mark node, we can make one\n const createMarkNode = createNode || $createThreadMarkNode;\n lastCreatedMarkNode = createMarkNode([id]);\n targetNode.insertBefore(lastCreatedMarkNode);\n }\n\n // Add the target node to be wrapped in the latest created mark node\n lastCreatedMarkNode.append(targetNode);\n } else {\n // If we don't have a target node to wrap we can clear our state and\n // continue on with the next node\n currentNodeParent = undefined;\n lastCreatedMarkNode = undefined;\n }\n }\n // Make selection collapsed at the end\n if ($isElementNode(lastCreatedMarkNode)) {\n if (isBackward) {\n lastCreatedMarkNode.selectStart();\n } else {\n lastCreatedMarkNode.selectEnd();\n }\n }\n}\n"],"names":[],"mappings":"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"}
@@ -49,7 +49,7 @@ function createDOMRange(editor, anchorNode, _anchorOffset, focusNode, _focusOffs
49
49
  try {
50
50
  range.setStart(anchorDOM, anchorOffset);
51
51
  range.setEnd(focusDOM, focusOffset);
52
- } catch (e) {
52
+ } catch {
53
53
  return null;
54
54
  }
55
55
  if (range.collapsed && (anchorOffset !== focusOffset || anchorKey !== focusKey)) {
@@ -1 +1 @@
1
- {"version":3,"file":"create-dom-range.cjs","sources":["../src/create-dom-range.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 { LexicalEditor, LexicalNode } from \"lexical\";\nimport { $isTextNode } from \"lexical\";\n\nfunction getDOMTextNode(element: Node | null): Text | null {\n let node = element;\n\n while (node !== null) {\n if (node.nodeType === Node.TEXT_NODE) {\n return node as Text;\n }\n\n node = node.firstChild;\n }\n\n return null;\n}\n\nfunction getDOMIndexWithinParent(node: ChildNode): [ParentNode, number] {\n const parent = node.parentNode;\n\n if (parent === null) {\n throw new Error(\"Should never happen\");\n }\n\n return [parent, Array.from(parent.childNodes).indexOf(node)];\n}\n\n/**\n * Creates a selection range for the DOM.\n * @param editor - The lexical editor.\n * @param anchorNode - The anchor node of a selection.\n * @param _anchorOffset - The amount of space offset from the anchor to the focus.\n * @param focusNode - The current focus.\n * @param _focusOffset - The amount of space offset from the focus to the anchor.\n * @returns The range of selection for the DOM that was created.\n */\nexport function createDOMRange(\n editor: LexicalEditor,\n anchorNode: LexicalNode,\n _anchorOffset: number,\n focusNode: LexicalNode,\n _focusOffset: number\n): Range | null {\n const anchorKey = anchorNode.getKey();\n const focusKey = focusNode.getKey();\n const range = document.createRange();\n let anchorDOM: Node | Text | null = editor.getElementByKey(anchorKey);\n let focusDOM: Node | Text | null = editor.getElementByKey(focusKey);\n let anchorOffset = _anchorOffset;\n let focusOffset = _focusOffset;\n\n if ($isTextNode(anchorNode)) {\n anchorDOM = getDOMTextNode(anchorDOM);\n }\n\n if ($isTextNode(focusNode)) {\n focusDOM = getDOMTextNode(focusDOM);\n }\n\n if (\n anchorNode === undefined ||\n focusNode === undefined ||\n anchorDOM === null ||\n focusDOM === null\n ) {\n return null;\n }\n\n if (anchorDOM.nodeName === \"BR\") {\n [anchorDOM, anchorOffset] = getDOMIndexWithinParent(anchorDOM as ChildNode);\n }\n\n if (focusDOM.nodeName === \"BR\") {\n [focusDOM, focusOffset] = getDOMIndexWithinParent(focusDOM as ChildNode);\n }\n\n const firstChild = anchorDOM.firstChild;\n\n if (\n anchorDOM === focusDOM &&\n firstChild !== null &&\n firstChild.nodeName === \"BR\" &&\n anchorOffset === 0 &&\n focusOffset === 0\n ) {\n focusOffset = 1;\n }\n\n try {\n range.setStart(anchorDOM, anchorOffset);\n range.setEnd(focusDOM, focusOffset);\n } catch (e) {\n return null;\n }\n\n if (\n range.collapsed &&\n (anchorOffset !== focusOffset || anchorKey !== focusKey)\n ) {\n // Range is backwards, we need to reverse it\n range.setStart(focusDOM, focusOffset);\n range.setEnd(anchorDOM, anchorOffset);\n }\n\n return range;\n}\n"],"names":["$isTextNode"],"mappings":"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"}
1
+ {"version":3,"file":"create-dom-range.cjs","sources":["../src/create-dom-range.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 { LexicalEditor, LexicalNode } from \"lexical\";\nimport { $isTextNode } from \"lexical\";\n\nfunction getDOMTextNode(element: Node | null): Text | null {\n let node = element;\n\n while (node !== null) {\n if (node.nodeType === Node.TEXT_NODE) {\n return node as Text;\n }\n\n node = node.firstChild;\n }\n\n return null;\n}\n\nfunction getDOMIndexWithinParent(node: ChildNode): [ParentNode, number] {\n const parent = node.parentNode;\n\n if (parent === null) {\n throw new Error(\"Should never happen\");\n }\n\n return [parent, Array.from(parent.childNodes).indexOf(node)];\n}\n\n/**\n * Creates a selection range for the DOM.\n * @param editor - The lexical editor.\n * @param anchorNode - The anchor node of a selection.\n * @param _anchorOffset - The amount of space offset from the anchor to the focus.\n * @param focusNode - The current focus.\n * @param _focusOffset - The amount of space offset from the focus to the anchor.\n * @returns The range of selection for the DOM that was created.\n */\nexport function createDOMRange(\n editor: LexicalEditor,\n anchorNode: LexicalNode,\n _anchorOffset: number,\n focusNode: LexicalNode,\n _focusOffset: number\n): Range | null {\n const anchorKey = anchorNode.getKey();\n const focusKey = focusNode.getKey();\n const range = document.createRange();\n let anchorDOM: Node | Text | null = editor.getElementByKey(anchorKey);\n let focusDOM: Node | Text | null = editor.getElementByKey(focusKey);\n let anchorOffset = _anchorOffset;\n let focusOffset = _focusOffset;\n\n if ($isTextNode(anchorNode)) {\n anchorDOM = getDOMTextNode(anchorDOM);\n }\n\n if ($isTextNode(focusNode)) {\n focusDOM = getDOMTextNode(focusDOM);\n }\n\n if (\n anchorNode === undefined ||\n focusNode === undefined ||\n anchorDOM === null ||\n focusDOM === null\n ) {\n return null;\n }\n\n if (anchorDOM.nodeName === \"BR\") {\n [anchorDOM, anchorOffset] = getDOMIndexWithinParent(anchorDOM as ChildNode);\n }\n\n if (focusDOM.nodeName === \"BR\") {\n [focusDOM, focusOffset] = getDOMIndexWithinParent(focusDOM as ChildNode);\n }\n\n const firstChild = anchorDOM.firstChild;\n\n if (\n anchorDOM === focusDOM &&\n firstChild !== null &&\n firstChild.nodeName === \"BR\" &&\n anchorOffset === 0 &&\n focusOffset === 0\n ) {\n focusOffset = 1;\n }\n\n try {\n range.setStart(anchorDOM, anchorOffset);\n range.setEnd(focusDOM, focusOffset);\n } catch {\n return null;\n }\n\n if (\n range.collapsed &&\n (anchorOffset !== focusOffset || anchorKey !== focusKey)\n ) {\n // Range is backwards, we need to reverse it\n range.setStart(focusDOM, focusOffset);\n range.setEnd(anchorDOM, anchorOffset);\n }\n\n return range;\n}\n"],"names":["$isTextNode"],"mappings":"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"}
@@ -47,7 +47,7 @@ function createDOMRange(editor, anchorNode, _anchorOffset, focusNode, _focusOffs
47
47
  try {
48
48
  range.setStart(anchorDOM, anchorOffset);
49
49
  range.setEnd(focusDOM, focusOffset);
50
- } catch (e) {
50
+ } catch {
51
51
  return null;
52
52
  }
53
53
  if (range.collapsed && (anchorOffset !== focusOffset || anchorKey !== focusKey)) {
@@ -1 +1 @@
1
- {"version":3,"file":"create-dom-range.js","sources":["../src/create-dom-range.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 { LexicalEditor, LexicalNode } from \"lexical\";\nimport { $isTextNode } from \"lexical\";\n\nfunction getDOMTextNode(element: Node | null): Text | null {\n let node = element;\n\n while (node !== null) {\n if (node.nodeType === Node.TEXT_NODE) {\n return node as Text;\n }\n\n node = node.firstChild;\n }\n\n return null;\n}\n\nfunction getDOMIndexWithinParent(node: ChildNode): [ParentNode, number] {\n const parent = node.parentNode;\n\n if (parent === null) {\n throw new Error(\"Should never happen\");\n }\n\n return [parent, Array.from(parent.childNodes).indexOf(node)];\n}\n\n/**\n * Creates a selection range for the DOM.\n * @param editor - The lexical editor.\n * @param anchorNode - The anchor node of a selection.\n * @param _anchorOffset - The amount of space offset from the anchor to the focus.\n * @param focusNode - The current focus.\n * @param _focusOffset - The amount of space offset from the focus to the anchor.\n * @returns The range of selection for the DOM that was created.\n */\nexport function createDOMRange(\n editor: LexicalEditor,\n anchorNode: LexicalNode,\n _anchorOffset: number,\n focusNode: LexicalNode,\n _focusOffset: number\n): Range | null {\n const anchorKey = anchorNode.getKey();\n const focusKey = focusNode.getKey();\n const range = document.createRange();\n let anchorDOM: Node | Text | null = editor.getElementByKey(anchorKey);\n let focusDOM: Node | Text | null = editor.getElementByKey(focusKey);\n let anchorOffset = _anchorOffset;\n let focusOffset = _focusOffset;\n\n if ($isTextNode(anchorNode)) {\n anchorDOM = getDOMTextNode(anchorDOM);\n }\n\n if ($isTextNode(focusNode)) {\n focusDOM = getDOMTextNode(focusDOM);\n }\n\n if (\n anchorNode === undefined ||\n focusNode === undefined ||\n anchorDOM === null ||\n focusDOM === null\n ) {\n return null;\n }\n\n if (anchorDOM.nodeName === \"BR\") {\n [anchorDOM, anchorOffset] = getDOMIndexWithinParent(anchorDOM as ChildNode);\n }\n\n if (focusDOM.nodeName === \"BR\") {\n [focusDOM, focusOffset] = getDOMIndexWithinParent(focusDOM as ChildNode);\n }\n\n const firstChild = anchorDOM.firstChild;\n\n if (\n anchorDOM === focusDOM &&\n firstChild !== null &&\n firstChild.nodeName === \"BR\" &&\n anchorOffset === 0 &&\n focusOffset === 0\n ) {\n focusOffset = 1;\n }\n\n try {\n range.setStart(anchorDOM, anchorOffset);\n range.setEnd(focusDOM, focusOffset);\n } catch (e) {\n return null;\n }\n\n if (\n range.collapsed &&\n (anchorOffset !== focusOffset || anchorKey !== focusKey)\n ) {\n // Range is backwards, we need to reverse it\n range.setStart(focusDOM, focusOffset);\n range.setEnd(anchorDOM, anchorOffset);\n }\n\n return range;\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"create-dom-range.js","sources":["../src/create-dom-range.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 { LexicalEditor, LexicalNode } from \"lexical\";\nimport { $isTextNode } from \"lexical\";\n\nfunction getDOMTextNode(element: Node | null): Text | null {\n let node = element;\n\n while (node !== null) {\n if (node.nodeType === Node.TEXT_NODE) {\n return node as Text;\n }\n\n node = node.firstChild;\n }\n\n return null;\n}\n\nfunction getDOMIndexWithinParent(node: ChildNode): [ParentNode, number] {\n const parent = node.parentNode;\n\n if (parent === null) {\n throw new Error(\"Should never happen\");\n }\n\n return [parent, Array.from(parent.childNodes).indexOf(node)];\n}\n\n/**\n * Creates a selection range for the DOM.\n * @param editor - The lexical editor.\n * @param anchorNode - The anchor node of a selection.\n * @param _anchorOffset - The amount of space offset from the anchor to the focus.\n * @param focusNode - The current focus.\n * @param _focusOffset - The amount of space offset from the focus to the anchor.\n * @returns The range of selection for the DOM that was created.\n */\nexport function createDOMRange(\n editor: LexicalEditor,\n anchorNode: LexicalNode,\n _anchorOffset: number,\n focusNode: LexicalNode,\n _focusOffset: number\n): Range | null {\n const anchorKey = anchorNode.getKey();\n const focusKey = focusNode.getKey();\n const range = document.createRange();\n let anchorDOM: Node | Text | null = editor.getElementByKey(anchorKey);\n let focusDOM: Node | Text | null = editor.getElementByKey(focusKey);\n let anchorOffset = _anchorOffset;\n let focusOffset = _focusOffset;\n\n if ($isTextNode(anchorNode)) {\n anchorDOM = getDOMTextNode(anchorDOM);\n }\n\n if ($isTextNode(focusNode)) {\n focusDOM = getDOMTextNode(focusDOM);\n }\n\n if (\n anchorNode === undefined ||\n focusNode === undefined ||\n anchorDOM === null ||\n focusDOM === null\n ) {\n return null;\n }\n\n if (anchorDOM.nodeName === \"BR\") {\n [anchorDOM, anchorOffset] = getDOMIndexWithinParent(anchorDOM as ChildNode);\n }\n\n if (focusDOM.nodeName === \"BR\") {\n [focusDOM, focusOffset] = getDOMIndexWithinParent(focusDOM as ChildNode);\n }\n\n const firstChild = anchorDOM.firstChild;\n\n if (\n anchorDOM === focusDOM &&\n firstChild !== null &&\n firstChild.nodeName === \"BR\" &&\n anchorOffset === 0 &&\n focusOffset === 0\n ) {\n focusOffset = 1;\n }\n\n try {\n range.setStart(anchorDOM, anchorOffset);\n range.setEnd(focusDOM, focusOffset);\n } catch {\n return null;\n }\n\n if (\n range.collapsed &&\n (anchorOffset !== focusOffset || anchorKey !== focusKey)\n ) {\n // Range is backwards, we need to reverse it\n range.setStart(focusDOM, focusOffset);\n range.setEnd(anchorDOM, anchorOffset);\n }\n\n return range;\n}\n"],"names":[],"mappings":"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"}
@@ -24,9 +24,8 @@ function useIsEditorReady() {
24
24
  }, [yjsProvider]);
25
25
  const subscribe = react.useCallback(
26
26
  (callback) => {
27
- if (yjsProvider === void 0)
28
- return () => {
29
- };
27
+ if (yjsProvider === void 0) return () => {
28
+ };
30
29
  yjsProvider.on("status", callback);
31
30
  return () => {
32
31
  yjsProvider.off("status", callback);
@@ -83,8 +82,7 @@ const LiveblocksPlugin = ({
83
82
  );
84
83
  const root = useRootElement.useRootElement();
85
84
  _private.useLayoutEffect(() => {
86
- if (root === null)
87
- return;
85
+ if (root === null) return;
88
86
  setReference({
89
87
  getBoundingClientRect: () => root.getBoundingClientRect()
90
88
  });
@@ -1 +1 @@
1
- {"version":3,"file":"liveblocks-plugin-provider.cjs","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 { TextEditorType } from \"@liveblocks/core\";\nimport { useRoom, useSelf } from \"@liveblocks/react\";\nimport {\n useLayoutEffect,\n useReportTextEditor,\n useResolveMentionSuggestions,\n useYjsProvider,\n} from \"@liveblocks/react/_private\";\nimport { getYjsProviderForRoom } from \"@liveblocks/yjs\";\nimport type { MutableRefObject, ReactNode } from \"react\";\nimport { useCallback, useEffect, useState, useSyncExternalStore } from \"react\";\nimport type { Doc } from \"yjs\";\n\nimport { CommentPluginProvider } from \"./comments/comment-plugin-provider\";\nimport { ThreadMarkNode } from \"./comments/thread-mark-node\";\nimport { GroupMentionNode } from \"./mentions/group-mention-node\";\nimport { MentionNode } from \"./mentions/mention-node\";\nimport { MentionPlugin } from \"./mentions/mention-plugin\";\nimport { useRootElement } from \"./use-root-element\";\n\n/**\n * Returns whether the editor has loaded the initial text contents from the\n * server and is ready to be used.\n */\nexport function useIsEditorReady(): boolean {\n const yjsProvider = useYjsProvider();\n\n const getSnapshot = useCallback(() => {\n const status = yjsProvider?.getStatus();\n return status === \"synchronizing\" || status === \"synchronized\";\n }, [yjsProvider]);\n\n const subscribe = useCallback(\n (callback: () => void) => {\n if (yjsProvider === undefined) return () => { };\n yjsProvider.on(\"status\", callback);\n return () => {\n yjsProvider.off(\"status\", callback);\n };\n },\n [yjsProvider]\n );\n\n return useSyncExternalStore(subscribe, getSnapshot, getSnapshot);\n}\n\nexport type LiveblocksPluginProps = {\n children?: 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 isResolveMentionSuggestionsDefined =\n useResolveMentionSuggestions() !== undefined;\n const [editor] = useLexicalComposerContext();\n const room = useRoom();\n\n if (!editor.hasNodes([ThreadMarkNode, MentionNode, GroupMentionNode])) {\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 useReportTextEditor(TextEditorType.Lexical, \"root\");\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 const provider = getYjsProviderForRoom(room, {}, true);\n yjsDocMap.set(id, provider.getYDoc());\n\n\n return provider 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 className=\"lb-root lb-lexical-cursors\"\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 {isResolveMentionSuggestionsDefined && <MentionPlugin />}\n <CommentPluginProvider>{children}</CommentPluginProvider>\n </>\n );\n};\n"],"names":["useYjsProvider","useCallback","useSyncExternalStore","useResolveMentionSuggestions","useLexicalComposerContext","useRoom","ThreadMarkNode","MentionNode","GroupMentionNode","useState","useFloating","autoUpdate","useEffect","useReportTextEditor","TextEditorType","useSelf","getYjsProviderForRoom","useRootElement","useLayoutEffect","jsxs","Fragment","jsx","CollaborationPlugin","MentionPlugin","CommentPluginProvider"],"mappings":"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"}
1
+ {"version":3,"file":"liveblocks-plugin-provider.cjs","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 { TextEditorType } from \"@liveblocks/core\";\nimport { useRoom, useSelf } from \"@liveblocks/react\";\nimport {\n useLayoutEffect,\n useReportTextEditor,\n useResolveMentionSuggestions,\n useYjsProvider,\n} from \"@liveblocks/react/_private\";\nimport { getYjsProviderForRoom } from \"@liveblocks/yjs\";\nimport type { MutableRefObject, ReactNode } from \"react\";\nimport { useCallback, useEffect, useState, useSyncExternalStore } from \"react\";\nimport type { Doc } from \"yjs\";\n\nimport { CommentPluginProvider } from \"./comments/comment-plugin-provider\";\nimport { ThreadMarkNode } from \"./comments/thread-mark-node\";\nimport { GroupMentionNode } from \"./mentions/group-mention-node\";\nimport { MentionNode } from \"./mentions/mention-node\";\nimport { MentionPlugin } from \"./mentions/mention-plugin\";\nimport { useRootElement } from \"./use-root-element\";\n\n/**\n * Returns whether the editor has loaded the initial text contents from the\n * server and is ready to be used.\n */\nexport function useIsEditorReady(): boolean {\n const yjsProvider = useYjsProvider();\n\n const getSnapshot = useCallback(() => {\n const status = yjsProvider?.getStatus();\n return status === \"synchronizing\" || status === \"synchronized\";\n }, [yjsProvider]);\n\n const subscribe = useCallback(\n (callback: () => void) => {\n if (yjsProvider === undefined) return () => {};\n yjsProvider.on(\"status\", callback);\n return () => {\n yjsProvider.off(\"status\", callback);\n };\n },\n [yjsProvider]\n );\n\n return useSyncExternalStore(subscribe, getSnapshot, getSnapshot);\n}\n\nexport type LiveblocksPluginProps = {\n children?: 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 isResolveMentionSuggestionsDefined =\n useResolveMentionSuggestions() !== undefined;\n const [editor] = useLexicalComposerContext();\n const room = useRoom();\n\n if (!editor.hasNodes([ThreadMarkNode, MentionNode, GroupMentionNode])) {\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 useReportTextEditor(TextEditorType.Lexical, \"root\");\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 const provider = getYjsProviderForRoom(room, {}, true);\n yjsDocMap.set(id, provider.getYDoc());\n\n return provider 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 className=\"lb-root lb-lexical-cursors\"\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 {isResolveMentionSuggestionsDefined && <MentionPlugin />}\n <CommentPluginProvider>{children}</CommentPluginProvider>\n </>\n );\n};\n"],"names":["useYjsProvider","useCallback","useSyncExternalStore","useResolveMentionSuggestions","useLexicalComposerContext","useRoom","ThreadMarkNode","MentionNode","GroupMentionNode","useState","useFloating","autoUpdate","useEffect","useReportTextEditor","TextEditorType","useSelf","getYjsProviderForRoom","useRootElement","useLayoutEffect","jsxs","Fragment","jsx","CollaborationPlugin","MentionPlugin","CommentPluginProvider"],"mappings":"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"}
@@ -22,9 +22,8 @@ function useIsEditorReady() {
22
22
  }, [yjsProvider]);
23
23
  const subscribe = useCallback(
24
24
  (callback) => {
25
- if (yjsProvider === void 0)
26
- return () => {
27
- };
25
+ if (yjsProvider === void 0) return () => {
26
+ };
28
27
  yjsProvider.on("status", callback);
29
28
  return () => {
30
29
  yjsProvider.off("status", callback);
@@ -81,8 +80,7 @@ const LiveblocksPlugin = ({
81
80
  );
82
81
  const root = useRootElement();
83
82
  useLayoutEffect(() => {
84
- if (root === null)
85
- return;
83
+ if (root === null) return;
86
84
  setReference({
87
85
  getBoundingClientRect: () => root.getBoundingClientRect()
88
86
  });
@@ -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 { TextEditorType } from \"@liveblocks/core\";\nimport { useRoom, useSelf } from \"@liveblocks/react\";\nimport {\n useLayoutEffect,\n useReportTextEditor,\n useResolveMentionSuggestions,\n useYjsProvider,\n} from \"@liveblocks/react/_private\";\nimport { getYjsProviderForRoom } from \"@liveblocks/yjs\";\nimport type { MutableRefObject, ReactNode } from \"react\";\nimport { useCallback, useEffect, useState, useSyncExternalStore } from \"react\";\nimport type { Doc } from \"yjs\";\n\nimport { CommentPluginProvider } from \"./comments/comment-plugin-provider\";\nimport { ThreadMarkNode } from \"./comments/thread-mark-node\";\nimport { GroupMentionNode } from \"./mentions/group-mention-node\";\nimport { MentionNode } from \"./mentions/mention-node\";\nimport { MentionPlugin } from \"./mentions/mention-plugin\";\nimport { useRootElement } from \"./use-root-element\";\n\n/**\n * Returns whether the editor has loaded the initial text contents from the\n * server and is ready to be used.\n */\nexport function useIsEditorReady(): boolean {\n const yjsProvider = useYjsProvider();\n\n const getSnapshot = useCallback(() => {\n const status = yjsProvider?.getStatus();\n return status === \"synchronizing\" || status === \"synchronized\";\n }, [yjsProvider]);\n\n const subscribe = useCallback(\n (callback: () => void) => {\n if (yjsProvider === undefined) return () => { };\n yjsProvider.on(\"status\", callback);\n return () => {\n yjsProvider.off(\"status\", callback);\n };\n },\n [yjsProvider]\n );\n\n return useSyncExternalStore(subscribe, getSnapshot, getSnapshot);\n}\n\nexport type LiveblocksPluginProps = {\n children?: 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 isResolveMentionSuggestionsDefined =\n useResolveMentionSuggestions() !== undefined;\n const [editor] = useLexicalComposerContext();\n const room = useRoom();\n\n if (!editor.hasNodes([ThreadMarkNode, MentionNode, GroupMentionNode])) {\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 useReportTextEditor(TextEditorType.Lexical, \"root\");\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 const provider = getYjsProviderForRoom(room, {}, true);\n yjsDocMap.set(id, provider.getYDoc());\n\n\n return provider 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 className=\"lb-root lb-lexical-cursors\"\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 {isResolveMentionSuggestionsDefined && <MentionPlugin />}\n <CommentPluginProvider>{children}</CommentPluginProvider>\n </>\n );\n};\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;AA4BO,SAAS,gBAA4B,GAAA;AAC1C,EAAA,MAAM,cAAc,cAAe,EAAA,CAAA;AAEnC,EAAM,MAAA,WAAA,GAAc,YAAY,MAAM;AACpC,IAAM,MAAA,MAAA,GAAS,aAAa,SAAU,EAAA,CAAA;AACtC,IAAO,OAAA,MAAA,KAAW,mBAAmB,MAAW,KAAA,cAAA,CAAA;AAAA,GAClD,EAAG,CAAC,WAAW,CAAC,CAAA,CAAA;AAEhB,EAAA,MAAM,SAAY,GAAA,WAAA;AAAA,IAChB,CAAC,QAAyB,KAAA;AACxB,MAAA,IAAI,WAAgB,KAAA,KAAA,CAAA;AAAW,QAAA,OAAO,MAAM;AAAA,SAAE,CAAA;AAC9C,MAAY,WAAA,CAAA,EAAA,CAAG,UAAU,QAAQ,CAAA,CAAA;AACjC,MAAA,OAAO,MAAM;AACX,QAAY,WAAA,CAAA,GAAA,CAAI,UAAU,QAAQ,CAAA,CAAA;AAAA,OACpC,CAAA;AAAA,KACF;AAAA,IACA,CAAC,WAAW,CAAA;AAAA,GACd,CAAA;AAEA,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,EAAM,MAAA,kCAAA,GACJ,8BAAmC,KAAA,KAAA,CAAA,CAAA;AACrC,EAAM,MAAA,CAAC,MAAM,CAAA,GAAI,yBAA0B,EAAA,CAAA;AAC3C,EAAA,MAAM,OAAO,OAAQ,EAAA,CAAA;AAErB,EAAI,IAAA,CAAC,OAAO,QAAS,CAAA,CAAC,gBAAgB,WAAa,EAAA,gBAAgB,CAAC,CAAG,EAAA;AACrE,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,EAAoB,mBAAA,CAAA,cAAA,CAAe,SAAS,MAAM,CAAA,CAAA;AAGlD,EAAA,MAAM,OAAO,OAAQ,EAAA,CAAA;AAErB,EAAA,MAAM,eAAkB,GAAA,WAAA;AAAA,IACtB,CAAC,IAAY,SAA0C,KAAA;AACrD,MAAA,MAAM,QAAW,GAAA,qBAAA,CAAsB,IAAM,EAAA,IAAI,IAAI,CAAA,CAAA;AACrD,MAAA,SAAA,CAAU,GAAI,CAAA,EAAA,EAAI,QAAS,CAAA,OAAA,EAAS,CAAA,CAAA;AAGpC,MAAO,OAAA,QAAA,CAAA;AAAA,KACT;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,uBAEI,IAAA,CAAA,QAAA,EAAA,EAAA,QAAA,EAAA;AAAA,oBAAA,GAAA;AAAA,MAAC,KAAA;AAAA,MAAA;AAAA,QACC,GAAK,EAAA,iBAAA;AAAA,QACL,SAAU,EAAA,4BAAA;AAAA,QACV,KAAO,EAAA;AAAA,UACL,QAAU,EAAA,QAAA;AAAA,UACV,GAAK,EAAA,CAAA;AAAA,UACL,IAAM,EAAA,CAAA;AAAA,UACN,SAAA,EAAW,CAAe,YAAA,EAAA,IAAA,CAAK,KAAM,CAAA,CAAC,CAAC,CAAO,IAAA,EAAA,IAAA,CAAK,KAAM,CAAA,CAAC,CAAC,CAAA,MAAA,CAAA;AAAA,UAC3D,QAAU,EAAA,aAAA;AAAA,SACZ;AAAA,OAAA;AAAA,KACF;AAAA,IAEC,IACC,oBAAA,GAAA;AAAA,MAAC,mBAAA;AAAA,MAAA;AAAA,QAIC,IAAI,IAAK,CAAA,EAAA;AAAA,QACT,eAAA;AAAA,QACA,QAAA,EAAU,IAAK,CAAA,IAAA,EAAM,IAAQ,IAAA,EAAA;AAAA,QAC7B,WAAA,EAAa,KAAK,IAAM,EAAA,KAAA;AAAA,QACxB,mBAAqB,EAAA,YAAA;AAAA,QACrB,eAAiB,EAAA,IAAA;AAAA,OAAA;AAAA,MANZ,IAAK,CAAA,EAAA;AAAA,KAOZ;AAAA,IAGD,kCAAA,wBAAuC,aAAc,EAAA,EAAA,CAAA;AAAA,oBACtD,GAAA,CAAC,yBAAuB,QAAS,EAAA,CAAA;AAAA,GACnC,EAAA,CAAA,CAAA;AAEJ;;;;"}
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 { TextEditorType } from \"@liveblocks/core\";\nimport { useRoom, useSelf } from \"@liveblocks/react\";\nimport {\n useLayoutEffect,\n useReportTextEditor,\n useResolveMentionSuggestions,\n useYjsProvider,\n} from \"@liveblocks/react/_private\";\nimport { getYjsProviderForRoom } from \"@liveblocks/yjs\";\nimport type { MutableRefObject, ReactNode } from \"react\";\nimport { useCallback, useEffect, useState, useSyncExternalStore } from \"react\";\nimport type { Doc } from \"yjs\";\n\nimport { CommentPluginProvider } from \"./comments/comment-plugin-provider\";\nimport { ThreadMarkNode } from \"./comments/thread-mark-node\";\nimport { GroupMentionNode } from \"./mentions/group-mention-node\";\nimport { MentionNode } from \"./mentions/mention-node\";\nimport { MentionPlugin } from \"./mentions/mention-plugin\";\nimport { useRootElement } from \"./use-root-element\";\n\n/**\n * Returns whether the editor has loaded the initial text contents from the\n * server and is ready to be used.\n */\nexport function useIsEditorReady(): boolean {\n const yjsProvider = useYjsProvider();\n\n const getSnapshot = useCallback(() => {\n const status = yjsProvider?.getStatus();\n return status === \"synchronizing\" || status === \"synchronized\";\n }, [yjsProvider]);\n\n const subscribe = useCallback(\n (callback: () => void) => {\n if (yjsProvider === undefined) return () => {};\n yjsProvider.on(\"status\", callback);\n return () => {\n yjsProvider.off(\"status\", callback);\n };\n },\n [yjsProvider]\n );\n\n return useSyncExternalStore(subscribe, getSnapshot, getSnapshot);\n}\n\nexport type LiveblocksPluginProps = {\n children?: 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 isResolveMentionSuggestionsDefined =\n useResolveMentionSuggestions() !== undefined;\n const [editor] = useLexicalComposerContext();\n const room = useRoom();\n\n if (!editor.hasNodes([ThreadMarkNode, MentionNode, GroupMentionNode])) {\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 useReportTextEditor(TextEditorType.Lexical, \"root\");\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 const provider = getYjsProviderForRoom(room, {}, true);\n yjsDocMap.set(id, provider.getYDoc());\n\n return provider 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 className=\"lb-root lb-lexical-cursors\"\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 {isResolveMentionSuggestionsDefined && <MentionPlugin />}\n <CommentPluginProvider>{children}</CommentPluginProvider>\n </>\n );\n};\n"],"names":[],"mappings":"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"}
@@ -37,8 +37,7 @@ const Mention = react.forwardRef(
37
37
  );
38
38
  function $isNodeSelected(key) {
39
39
  const node = lexical.$getNodeByKey(key);
40
- if (node === null)
41
- return false;
40
+ if (node === null) return false;
42
41
  return node.isSelected();
43
42
  }
44
43
  function useIsNodeSelected(key) {
@@ -1 +1 @@
1
- {"version":3,"file":"mention-component.cjs","sources":["../../src/mentions/mention-component.tsx"],"sourcesContent":["import { useLexicalComposerContext } from \"@lexical/react/LexicalComposerContext\";\nimport { cn } from \"@liveblocks/react-ui/_private\";\nimport type { NodeKey } from \"lexical\";\nimport { $createNodeSelection, $getNodeByKey, $setSelection } from \"lexical\";\nimport {\n type ComponentPropsWithoutRef,\n forwardRef,\n type MouseEvent,\n} from \"react\";\nimport { useCallback, useSyncExternalStore } from \"react\";\n\ninterface MentionProps extends ComponentPropsWithoutRef<\"span\"> {\n nodeKey: NodeKey;\n}\n\nexport const Mention = forwardRef<HTMLSpanElement, MentionProps>(\n ({ nodeKey, children, className, ...props }, forwardedRef) => {\n const [editor] = useLexicalComposerContext();\n const isSelected = useIsNodeSelected(nodeKey);\n\n const handleClick = useCallback(\n (event: MouseEvent) => {\n editor.update(() => {\n event.stopPropagation();\n event.preventDefault();\n\n const selection = $createNodeSelection();\n selection.add(nodeKey);\n $setSelection(selection);\n });\n },\n [editor, nodeKey]\n );\n\n return (\n <span\n onClick={handleClick}\n data-selected={isSelected ? \"\" : undefined}\n className={cn(\"lb-root lb-mention lb-lexical-mention\", className)}\n ref={forwardedRef}\n {...props}\n >\n {children}\n </span>\n );\n }\n);\n\nfunction $isNodeSelected(key: NodeKey): boolean {\n const node = $getNodeByKey(key);\n if (node === null) return false;\n return node.isSelected();\n}\n\nfunction useIsNodeSelected(key: NodeKey) {\n const [editor] = useLexicalComposerContext();\n\n const subscribe = useCallback(\n (onStoreChange: () => void) => {\n return editor.registerUpdateListener(onStoreChange);\n },\n [editor]\n );\n\n const getSnapshot = useCallback(() => {\n return editor.getEditorState().read(() => $isNodeSelected(key));\n }, [editor, key]);\n\n return useSyncExternalStore(subscribe, getSnapshot, getSnapshot);\n}\n"],"names":["forwardRef","useLexicalComposerContext","useCallback","$createNodeSelection","$setSelection","jsx","cn","$getNodeByKey","useSyncExternalStore"],"mappings":";;;;;;;;AAeO,MAAM,OAAU,GAAAA,gBAAA;AAAA,EACrB,CAAC,EAAE,OAAS,EAAA,QAAA,EAAU,WAAW,GAAG,KAAA,IAAS,YAAiB,KAAA;AAC5D,IAAM,MAAA,CAAC,MAAM,CAAA,GAAIC,gDAA0B,EAAA,CAAA;AAC3C,IAAM,MAAA,UAAA,GAAa,kBAAkB,OAAO,CAAA,CAAA;AAE5C,IAAA,MAAM,WAAc,GAAAC,iBAAA;AAAA,MAClB,CAAC,KAAsB,KAAA;AACrB,QAAA,MAAA,CAAO,OAAO,MAAM;AAClB,UAAA,KAAA,CAAM,eAAgB,EAAA,CAAA;AACtB,UAAA,KAAA,CAAM,cAAe,EAAA,CAAA;AAErB,UAAA,MAAM,YAAYC,4BAAqB,EAAA,CAAA;AACvC,UAAA,SAAA,CAAU,IAAI,OAAO,CAAA,CAAA;AACrB,UAAAC,qBAAA,CAAc,SAAS,CAAA,CAAA;AAAA,SACxB,CAAA,CAAA;AAAA,OACH;AAAA,MACA,CAAC,QAAQ,OAAO,CAAA;AAAA,KAClB,CAAA;AAEA,IACE,uBAAAC,cAAA;AAAA,MAAC,MAAA;AAAA,MAAA;AAAA,QACC,OAAS,EAAA,WAAA;AAAA,QACT,eAAA,EAAe,aAAa,EAAK,GAAA,KAAA,CAAA;AAAA,QACjC,SAAA,EAAWC,WAAG,CAAA,uCAAA,EAAyC,SAAS,CAAA;AAAA,QAChE,GAAK,EAAA,YAAA;AAAA,QACJ,GAAG,KAAA;AAAA,QAEH,QAAA;AAAA,OAAA;AAAA,KACH,CAAA;AAAA,GAEJ;AACF,EAAA;AAEA,SAAS,gBAAgB,GAAuB,EAAA;AAC9C,EAAM,MAAA,IAAA,GAAOC,sBAAc,GAAG,CAAA,CAAA;AAC9B,EAAA,IAAI,IAAS,KAAA,IAAA;AAAM,IAAO,OAAA,KAAA,CAAA;AAC1B,EAAA,OAAO,KAAK,UAAW,EAAA,CAAA;AACzB,CAAA;AAEA,SAAS,kBAAkB,GAAc,EAAA;AACvC,EAAM,MAAA,CAAC,MAAM,CAAA,GAAIN,gDAA0B,EAAA,CAAA;AAE3C,EAAA,MAAM,SAAY,GAAAC,iBAAA;AAAA,IAChB,CAAC,aAA8B,KAAA;AAC7B,MAAO,OAAA,MAAA,CAAO,uBAAuB,aAAa,CAAA,CAAA;AAAA,KACpD;AAAA,IACA,CAAC,MAAM,CAAA;AAAA,GACT,CAAA;AAEA,EAAM,MAAA,WAAA,GAAcA,kBAAY,MAAM;AACpC,IAAA,OAAO,OAAO,cAAe,EAAA,CAAE,KAAK,MAAM,eAAA,CAAgB,GAAG,CAAC,CAAA,CAAA;AAAA,GAC7D,EAAA,CAAC,MAAQ,EAAA,GAAG,CAAC,CAAA,CAAA;AAEhB,EAAO,OAAAM,0BAAA,CAAqB,SAAW,EAAA,WAAA,EAAa,WAAW,CAAA,CAAA;AACjE;;;;"}
1
+ {"version":3,"file":"mention-component.cjs","sources":["../../src/mentions/mention-component.tsx"],"sourcesContent":["import { useLexicalComposerContext } from \"@lexical/react/LexicalComposerContext\";\nimport { cn } from \"@liveblocks/react-ui/_private\";\nimport type { NodeKey } from \"lexical\";\nimport { $createNodeSelection, $getNodeByKey, $setSelection } from \"lexical\";\nimport {\n type ComponentPropsWithoutRef,\n forwardRef,\n type MouseEvent,\n} from \"react\";\nimport { useCallback, useSyncExternalStore } from \"react\";\n\ninterface MentionProps extends ComponentPropsWithoutRef<\"span\"> {\n nodeKey: NodeKey;\n}\n\nexport const Mention = forwardRef<HTMLSpanElement, MentionProps>(\n ({ nodeKey, children, className, ...props }, forwardedRef) => {\n const [editor] = useLexicalComposerContext();\n const isSelected = useIsNodeSelected(nodeKey);\n\n const handleClick = useCallback(\n (event: MouseEvent) => {\n editor.update(() => {\n event.stopPropagation();\n event.preventDefault();\n\n const selection = $createNodeSelection();\n selection.add(nodeKey);\n $setSelection(selection);\n });\n },\n [editor, nodeKey]\n );\n\n return (\n <span\n onClick={handleClick}\n data-selected={isSelected ? \"\" : undefined}\n className={cn(\"lb-root lb-mention lb-lexical-mention\", className)}\n ref={forwardedRef}\n {...props}\n >\n {children}\n </span>\n );\n }\n);\n\nfunction $isNodeSelected(key: NodeKey): boolean {\n const node = $getNodeByKey(key);\n if (node === null) return false;\n return node.isSelected();\n}\n\nfunction useIsNodeSelected(key: NodeKey) {\n const [editor] = useLexicalComposerContext();\n\n const subscribe = useCallback(\n (onStoreChange: () => void) => {\n return editor.registerUpdateListener(onStoreChange);\n },\n [editor]\n );\n\n const getSnapshot = useCallback(() => {\n return editor.getEditorState().read(() => $isNodeSelected(key));\n }, [editor, key]);\n\n return useSyncExternalStore(subscribe, getSnapshot, getSnapshot);\n}\n"],"names":["forwardRef","useLexicalComposerContext","useCallback","$createNodeSelection","$setSelection","jsx","cn","$getNodeByKey","useSyncExternalStore"],"mappings":";;;;;;;;AAeO,MAAM,OAAU,GAAAA,gBAAA;AAAA,EACrB,CAAC,EAAE,OAAS,EAAA,QAAA,EAAU,WAAW,GAAG,KAAA,IAAS,YAAiB,KAAA;AAC5D,IAAM,MAAA,CAAC,MAAM,CAAA,GAAIC,gDAA0B,EAAA,CAAA;AAC3C,IAAM,MAAA,UAAA,GAAa,kBAAkB,OAAO,CAAA,CAAA;AAE5C,IAAA,MAAM,WAAc,GAAAC,iBAAA;AAAA,MAClB,CAAC,KAAsB,KAAA;AACrB,QAAA,MAAA,CAAO,OAAO,MAAM;AAClB,UAAA,KAAA,CAAM,eAAgB,EAAA,CAAA;AACtB,UAAA,KAAA,CAAM,cAAe,EAAA,CAAA;AAErB,UAAA,MAAM,YAAYC,4BAAqB,EAAA,CAAA;AACvC,UAAA,SAAA,CAAU,IAAI,OAAO,CAAA,CAAA;AACrB,UAAAC,qBAAA,CAAc,SAAS,CAAA,CAAA;AAAA,SACxB,CAAA,CAAA;AAAA,OACH;AAAA,MACA,CAAC,QAAQ,OAAO,CAAA;AAAA,KAClB,CAAA;AAEA,IACE,uBAAAC,cAAA;AAAA,MAAC,MAAA;AAAA,MAAA;AAAA,QACC,OAAS,EAAA,WAAA;AAAA,QACT,eAAA,EAAe,aAAa,EAAK,GAAA,KAAA,CAAA;AAAA,QACjC,SAAA,EAAWC,WAAG,CAAA,uCAAA,EAAyC,SAAS,CAAA;AAAA,QAChE,GAAK,EAAA,YAAA;AAAA,QACJ,GAAG,KAAA;AAAA,QAEH,QAAA;AAAA,OAAA;AAAA,KACH,CAAA;AAAA,GAEJ;AACF,EAAA;AAEA,SAAS,gBAAgB,GAAuB,EAAA;AAC9C,EAAM,MAAA,IAAA,GAAOC,sBAAc,GAAG,CAAA,CAAA;AAC9B,EAAI,IAAA,IAAA,KAAS,MAAa,OAAA,KAAA,CAAA;AAC1B,EAAA,OAAO,KAAK,UAAW,EAAA,CAAA;AACzB,CAAA;AAEA,SAAS,kBAAkB,GAAc,EAAA;AACvC,EAAM,MAAA,CAAC,MAAM,CAAA,GAAIN,gDAA0B,EAAA,CAAA;AAE3C,EAAA,MAAM,SAAY,GAAAC,iBAAA;AAAA,IAChB,CAAC,aAA8B,KAAA;AAC7B,MAAO,OAAA,MAAA,CAAO,uBAAuB,aAAa,CAAA,CAAA;AAAA,KACpD;AAAA,IACA,CAAC,MAAM,CAAA;AAAA,GACT,CAAA;AAEA,EAAM,MAAA,WAAA,GAAcA,kBAAY,MAAM;AACpC,IAAA,OAAO,OAAO,cAAe,EAAA,CAAE,KAAK,MAAM,eAAA,CAAgB,GAAG,CAAC,CAAA,CAAA;AAAA,GAC7D,EAAA,CAAC,MAAQ,EAAA,GAAG,CAAC,CAAA,CAAA;AAEhB,EAAO,OAAAM,0BAAA,CAAqB,SAAW,EAAA,WAAA,EAAa,WAAW,CAAA,CAAA;AACjE;;;;"}
@@ -35,8 +35,7 @@ const Mention = forwardRef(
35
35
  );
36
36
  function $isNodeSelected(key) {
37
37
  const node = $getNodeByKey(key);
38
- if (node === null)
39
- return false;
38
+ if (node === null) return false;
40
39
  return node.isSelected();
41
40
  }
42
41
  function useIsNodeSelected(key) {
@@ -1 +1 @@
1
- {"version":3,"file":"mention-component.js","sources":["../../src/mentions/mention-component.tsx"],"sourcesContent":["import { useLexicalComposerContext } from \"@lexical/react/LexicalComposerContext\";\nimport { cn } from \"@liveblocks/react-ui/_private\";\nimport type { NodeKey } from \"lexical\";\nimport { $createNodeSelection, $getNodeByKey, $setSelection } from \"lexical\";\nimport {\n type ComponentPropsWithoutRef,\n forwardRef,\n type MouseEvent,\n} from \"react\";\nimport { useCallback, useSyncExternalStore } from \"react\";\n\ninterface MentionProps extends ComponentPropsWithoutRef<\"span\"> {\n nodeKey: NodeKey;\n}\n\nexport const Mention = forwardRef<HTMLSpanElement, MentionProps>(\n ({ nodeKey, children, className, ...props }, forwardedRef) => {\n const [editor] = useLexicalComposerContext();\n const isSelected = useIsNodeSelected(nodeKey);\n\n const handleClick = useCallback(\n (event: MouseEvent) => {\n editor.update(() => {\n event.stopPropagation();\n event.preventDefault();\n\n const selection = $createNodeSelection();\n selection.add(nodeKey);\n $setSelection(selection);\n });\n },\n [editor, nodeKey]\n );\n\n return (\n <span\n onClick={handleClick}\n data-selected={isSelected ? \"\" : undefined}\n className={cn(\"lb-root lb-mention lb-lexical-mention\", className)}\n ref={forwardedRef}\n {...props}\n >\n {children}\n </span>\n );\n }\n);\n\nfunction $isNodeSelected(key: NodeKey): boolean {\n const node = $getNodeByKey(key);\n if (node === null) return false;\n return node.isSelected();\n}\n\nfunction useIsNodeSelected(key: NodeKey) {\n const [editor] = useLexicalComposerContext();\n\n const subscribe = useCallback(\n (onStoreChange: () => void) => {\n return editor.registerUpdateListener(onStoreChange);\n },\n [editor]\n );\n\n const getSnapshot = useCallback(() => {\n return editor.getEditorState().read(() => $isNodeSelected(key));\n }, [editor, key]);\n\n return useSyncExternalStore(subscribe, getSnapshot, getSnapshot);\n}\n"],"names":[],"mappings":";;;;;;AAeO,MAAM,OAAU,GAAA,UAAA;AAAA,EACrB,CAAC,EAAE,OAAS,EAAA,QAAA,EAAU,WAAW,GAAG,KAAA,IAAS,YAAiB,KAAA;AAC5D,IAAM,MAAA,CAAC,MAAM,CAAA,GAAI,yBAA0B,EAAA,CAAA;AAC3C,IAAM,MAAA,UAAA,GAAa,kBAAkB,OAAO,CAAA,CAAA;AAE5C,IAAA,MAAM,WAAc,GAAA,WAAA;AAAA,MAClB,CAAC,KAAsB,KAAA;AACrB,QAAA,MAAA,CAAO,OAAO,MAAM;AAClB,UAAA,KAAA,CAAM,eAAgB,EAAA,CAAA;AACtB,UAAA,KAAA,CAAM,cAAe,EAAA,CAAA;AAErB,UAAA,MAAM,YAAY,oBAAqB,EAAA,CAAA;AACvC,UAAA,SAAA,CAAU,IAAI,OAAO,CAAA,CAAA;AACrB,UAAA,aAAA,CAAc,SAAS,CAAA,CAAA;AAAA,SACxB,CAAA,CAAA;AAAA,OACH;AAAA,MACA,CAAC,QAAQ,OAAO,CAAA;AAAA,KAClB,CAAA;AAEA,IACE,uBAAA,GAAA;AAAA,MAAC,MAAA;AAAA,MAAA;AAAA,QACC,OAAS,EAAA,WAAA;AAAA,QACT,eAAA,EAAe,aAAa,EAAK,GAAA,KAAA,CAAA;AAAA,QACjC,SAAA,EAAW,EAAG,CAAA,uCAAA,EAAyC,SAAS,CAAA;AAAA,QAChE,GAAK,EAAA,YAAA;AAAA,QACJ,GAAG,KAAA;AAAA,QAEH,QAAA;AAAA,OAAA;AAAA,KACH,CAAA;AAAA,GAEJ;AACF,EAAA;AAEA,SAAS,gBAAgB,GAAuB,EAAA;AAC9C,EAAM,MAAA,IAAA,GAAO,cAAc,GAAG,CAAA,CAAA;AAC9B,EAAA,IAAI,IAAS,KAAA,IAAA;AAAM,IAAO,OAAA,KAAA,CAAA;AAC1B,EAAA,OAAO,KAAK,UAAW,EAAA,CAAA;AACzB,CAAA;AAEA,SAAS,kBAAkB,GAAc,EAAA;AACvC,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,uBAAuB,aAAa,CAAA,CAAA;AAAA,KACpD;AAAA,IACA,CAAC,MAAM,CAAA;AAAA,GACT,CAAA;AAEA,EAAM,MAAA,WAAA,GAAc,YAAY,MAAM;AACpC,IAAA,OAAO,OAAO,cAAe,EAAA,CAAE,KAAK,MAAM,eAAA,CAAgB,GAAG,CAAC,CAAA,CAAA;AAAA,GAC7D,EAAA,CAAC,MAAQ,EAAA,GAAG,CAAC,CAAA,CAAA;AAEhB,EAAO,OAAA,oBAAA,CAAqB,SAAW,EAAA,WAAA,EAAa,WAAW,CAAA,CAAA;AACjE;;;;"}
1
+ {"version":3,"file":"mention-component.js","sources":["../../src/mentions/mention-component.tsx"],"sourcesContent":["import { useLexicalComposerContext } from \"@lexical/react/LexicalComposerContext\";\nimport { cn } from \"@liveblocks/react-ui/_private\";\nimport type { NodeKey } from \"lexical\";\nimport { $createNodeSelection, $getNodeByKey, $setSelection } from \"lexical\";\nimport {\n type ComponentPropsWithoutRef,\n forwardRef,\n type MouseEvent,\n} from \"react\";\nimport { useCallback, useSyncExternalStore } from \"react\";\n\ninterface MentionProps extends ComponentPropsWithoutRef<\"span\"> {\n nodeKey: NodeKey;\n}\n\nexport const Mention = forwardRef<HTMLSpanElement, MentionProps>(\n ({ nodeKey, children, className, ...props }, forwardedRef) => {\n const [editor] = useLexicalComposerContext();\n const isSelected = useIsNodeSelected(nodeKey);\n\n const handleClick = useCallback(\n (event: MouseEvent) => {\n editor.update(() => {\n event.stopPropagation();\n event.preventDefault();\n\n const selection = $createNodeSelection();\n selection.add(nodeKey);\n $setSelection(selection);\n });\n },\n [editor, nodeKey]\n );\n\n return (\n <span\n onClick={handleClick}\n data-selected={isSelected ? \"\" : undefined}\n className={cn(\"lb-root lb-mention lb-lexical-mention\", className)}\n ref={forwardedRef}\n {...props}\n >\n {children}\n </span>\n );\n }\n);\n\nfunction $isNodeSelected(key: NodeKey): boolean {\n const node = $getNodeByKey(key);\n if (node === null) return false;\n return node.isSelected();\n}\n\nfunction useIsNodeSelected(key: NodeKey) {\n const [editor] = useLexicalComposerContext();\n\n const subscribe = useCallback(\n (onStoreChange: () => void) => {\n return editor.registerUpdateListener(onStoreChange);\n },\n [editor]\n );\n\n const getSnapshot = useCallback(() => {\n return editor.getEditorState().read(() => $isNodeSelected(key));\n }, [editor, key]);\n\n return useSyncExternalStore(subscribe, getSnapshot, getSnapshot);\n}\n"],"names":[],"mappings":";;;;;;AAeO,MAAM,OAAU,GAAA,UAAA;AAAA,EACrB,CAAC,EAAE,OAAS,EAAA,QAAA,EAAU,WAAW,GAAG,KAAA,IAAS,YAAiB,KAAA;AAC5D,IAAM,MAAA,CAAC,MAAM,CAAA,GAAI,yBAA0B,EAAA,CAAA;AAC3C,IAAM,MAAA,UAAA,GAAa,kBAAkB,OAAO,CAAA,CAAA;AAE5C,IAAA,MAAM,WAAc,GAAA,WAAA;AAAA,MAClB,CAAC,KAAsB,KAAA;AACrB,QAAA,MAAA,CAAO,OAAO,MAAM;AAClB,UAAA,KAAA,CAAM,eAAgB,EAAA,CAAA;AACtB,UAAA,KAAA,CAAM,cAAe,EAAA,CAAA;AAErB,UAAA,MAAM,YAAY,oBAAqB,EAAA,CAAA;AACvC,UAAA,SAAA,CAAU,IAAI,OAAO,CAAA,CAAA;AACrB,UAAA,aAAA,CAAc,SAAS,CAAA,CAAA;AAAA,SACxB,CAAA,CAAA;AAAA,OACH;AAAA,MACA,CAAC,QAAQ,OAAO,CAAA;AAAA,KAClB,CAAA;AAEA,IACE,uBAAA,GAAA;AAAA,MAAC,MAAA;AAAA,MAAA;AAAA,QACC,OAAS,EAAA,WAAA;AAAA,QACT,eAAA,EAAe,aAAa,EAAK,GAAA,KAAA,CAAA;AAAA,QACjC,SAAA,EAAW,EAAG,CAAA,uCAAA,EAAyC,SAAS,CAAA;AAAA,QAChE,GAAK,EAAA,YAAA;AAAA,QACJ,GAAG,KAAA;AAAA,QAEH,QAAA;AAAA,OAAA;AAAA,KACH,CAAA;AAAA,GAEJ;AACF,EAAA;AAEA,SAAS,gBAAgB,GAAuB,EAAA;AAC9C,EAAM,MAAA,IAAA,GAAO,cAAc,GAAG,CAAA,CAAA;AAC9B,EAAI,IAAA,IAAA,KAAS,MAAa,OAAA,KAAA,CAAA;AAC1B,EAAA,OAAO,KAAK,UAAW,EAAA,CAAA;AACzB,CAAA;AAEA,SAAS,kBAAkB,GAAc,EAAA;AACvC,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,uBAAuB,aAAa,CAAA,CAAA;AAAA,KACpD;AAAA,IACA,CAAC,MAAM,CAAA;AAAA,GACT,CAAA;AAEA,EAAM,MAAA,WAAA,GAAc,YAAY,MAAM;AACpC,IAAA,OAAO,OAAO,cAAe,EAAA,CAAE,KAAK,MAAM,eAAA,CAAgB,GAAG,CAAC,CAAA,CAAA;AAAA,GAC7D,EAAA,CAAC,MAAQ,EAAA,GAAG,CAAC,CAAA,CAAA;AAEhB,EAAO,OAAA,oBAAA,CAAqB,SAAW,EAAA,WAAA,EAAa,WAAW,CAAA,CAAA;AACjE;;;;"}