@liveblocks/react-lexical 2.16.0-toolbars4 → 2.16.0-toolbars5

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 (37) hide show
  1. package/dist/comments/anchored-threads.js +2 -2
  2. package/dist/comments/anchored-threads.js.map +1 -1
  3. package/dist/comments/anchored-threads.mjs +1 -1
  4. package/dist/comments/anchored-threads.mjs.map +1 -1
  5. package/dist/index.d.mts +3 -3
  6. package/dist/index.d.ts +3 -3
  7. package/dist/index.js +2 -2
  8. package/dist/index.js.map +1 -1
  9. package/dist/index.mjs +1 -1
  10. package/dist/index.mjs.map +1 -1
  11. package/dist/is-block-node-active.js +51 -0
  12. package/dist/is-block-node-active.js.map +1 -0
  13. package/dist/is-block-node-active.mjs +49 -0
  14. package/dist/is-block-node-active.mjs.map +1 -0
  15. package/dist/liveblocks-plugin-provider.js +2 -15
  16. package/dist/liveblocks-plugin-provider.js.map +1 -1
  17. package/dist/liveblocks-plugin-provider.mjs +2 -14
  18. package/dist/liveblocks-plugin-provider.mjs.map +1 -1
  19. package/dist/toolbar/floating-toolbar.js +16 -19
  20. package/dist/toolbar/floating-toolbar.js.map +1 -1
  21. package/dist/toolbar/floating-toolbar.mjs +16 -19
  22. package/dist/toolbar/floating-toolbar.mjs.map +1 -1
  23. package/dist/toolbar/toolbar.js +30 -25
  24. package/dist/toolbar/toolbar.js.map +1 -1
  25. package/dist/toolbar/toolbar.mjs +30 -25
  26. package/dist/toolbar/toolbar.mjs.map +1 -1
  27. package/dist/use-root-element.js +21 -0
  28. package/dist/use-root-element.js.map +1 -0
  29. package/dist/use-root-element.mjs +19 -0
  30. package/dist/use-root-element.mjs.map +1 -0
  31. package/dist/version.js +1 -1
  32. package/dist/version.mjs +1 -1
  33. package/package.json +6 -6
  34. package/dist/get-active-block-element.js +0 -26
  35. package/dist/get-active-block-element.js.map +0 -1
  36. package/dist/get-active-block-element.mjs +0 -24
  37. package/dist/get-active-block-element.mjs.map +0 -1
@@ -7,7 +7,7 @@ var reactUi = require('@liveblocks/react-ui');
7
7
  var lexical = require('lexical');
8
8
  var react = require('react');
9
9
  var classnames = require('../classnames.js');
10
- var liveblocksPluginProvider = require('../liveblocks-plugin-provider.js');
10
+ var useRootElement = require('../use-root-element.js');
11
11
  var commentPluginProvider = require('./comment-plugin-provider.js');
12
12
  var threadMarkNode = require('./thread-mark-node.js');
13
13
 
@@ -136,7 +136,7 @@ function AnchoredThreads({
136
136
  }
137
137
  return () => observer.disconnect();
138
138
  }, [elements, handlePositionThreads]);
139
- const root = liveblocksPluginProvider.useRootElement();
139
+ const root = useRootElement.useRootElement();
140
140
  react.useEffect(() => {
141
141
  if (root === null)
142
142
  return;
@@ -1 +1 @@
1
- {"version":3,"file":"anchored-threads.js","sources":["../../src/comments/anchored-threads.tsx"],"sourcesContent":["import { useLexicalComposerContext } from \"@lexical/react/LexicalComposerContext\";\nimport type { BaseMetadata, DM, ThreadData } from \"@liveblocks/core\";\nimport { useLayoutEffect } from \"@liveblocks/react/_private\";\nimport {\n Thread as DefaultThread,\n type ThreadProps,\n} from \"@liveblocks/react-ui\";\nimport { $getNodeByKey } from \"lexical\";\nimport type { ComponentPropsWithoutRef, ComponentType } from \"react\";\nimport {\n useCallback,\n useContext,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from \"react\";\n\nimport { classNames } from \"../classnames\";\nimport { useRootElement } from \"../liveblocks-plugin-provider\";\nimport {\n ActiveThreadsContext,\n type ThreadToNodesMap,\n} from \"./comment-plugin-provider\";\nimport { ThreadToNodesContext } from \"./comment-plugin-provider\";\nimport { $isThreadMarkNode } from \"./thread-mark-node\";\n\nconst DEFAULT_GAP = 20;\nconst DEFAULT_ACTIVE_THREAD_OFFSET = -12;\n\nconst GAP = `var(--lb-lexical-anchored-threads-gap, ${DEFAULT_GAP}px)`;\nconst ACTIVE_THREAD_OFFSET = `var(--lb-lexical-anchored-threads-active-thread-offset, ${DEFAULT_ACTIVE_THREAD_OFFSET}px)`;\n\ntype AnchoredThreadsComponents = {\n Thread: ComponentType<ThreadProps>;\n};\n\nexport interface AnchoredThreadsProps<M extends BaseMetadata = DM>\n extends Omit<ComponentPropsWithoutRef<\"div\">, \"children\"> {\n /**\n * The threads to display.\n */\n threads: ThreadData<M>[];\n\n /**\n * Override the component's components.\n */\n components?: Partial<AnchoredThreadsComponents>;\n}\n\n/**\n * Compares two nodes based on their position in the DOM.\n * Returns -1 if a comes before b, 1 if a comes after b, and 0 if they are the same node.\n * @param a The first node to compare\n * @param b The second node to compare\n * @returns -1 if a comes before b, 1 if a comes after b, and 0 if they are the same node.\n */\nexport function compareNodes(a: Node, b: Node): number {\n // Calculate the position of node 'b' relative to node 'a'\n const position = a.compareDocumentPosition(b);\n if (position & Node.DOCUMENT_POSITION_FOLLOWING) return -1;\n if (position & Node.DOCUMENT_POSITION_PRECEDING) return 1;\n return 0;\n}\n\nexport function AnchoredThreads({\n threads,\n components,\n className,\n style,\n ...props\n}: AnchoredThreadsProps) {\n const [editor] = useLexicalComposerContext();\n const Thread = components?.Thread ?? DefaultThread;\n const containerRef = useRef<HTMLDivElement>(null);\n\n const activeThreads = useActiveThreads();\n\n const nodes = useThreadToNodes(); // A map of thread ids to a set of thread mark nodes associated with the thread\n\n const getOrderedThreads = useCallback(() => {\n return threads\n .filter((thread) => thread.resolved === false)\n .map((thread) => {\n const keys = nodes.get(thread.id);\n if (keys === undefined || keys.size === 0) return null;\n\n const elements = Array.from(keys.values())\n .map((key) => editor.getElementByKey(key))\n .filter(Boolean) as HTMLElement[];\n if (elements.length === 0) return null;\n\n const element = elements.sort(compareNodes)[0];\n return {\n thread,\n element,\n };\n })\n .filter(\n (entry): entry is { thread: ThreadData; element: HTMLElement } =>\n entry !== null\n )\n .sort((a, b) => {\n return compareNodes(a.element, b.element);\n });\n }, [editor, threads, nodes]);\n\n // Sort threads by the position of the first element associated with the thread in the document (top to bottom, left to right)\n const orderedThreads = useMemo(getOrderedThreads, [getOrderedThreads]);\n\n const [elements, setElements] = useState<Map<string, HTMLElement>>(new Map());\n\n const [positions, setPositions] = useState<Map<string, number>>(new Map()); // A map of thread ids to their 'top' position in the document\n\n const onItemAdd = useCallback((id: string, el: HTMLElement) => {\n setElements((prev) => new Map(prev).set(id, el));\n }, []);\n\n const onItemRemove = useCallback((id: string) => {\n setElements((prev) => {\n const items = new Map(prev);\n items.delete(id);\n return items;\n });\n }, []);\n\n const handlePositionThreads = useCallback(() => {\n const container = containerRef.current;\n if (container === null) return;\n\n const orderedThreads = getOrderedThreads();\n\n // Returns an array of threads that should be positioned in ascending order - this includes threads that are active and threads that should come after the active threads\n function getAscendingThreads() {\n // If there are no active threads, all threads are ordered in ascending manner.\n if (activeThreads.length === 0) return orderedThreads;\n\n // Filter threads that are active\n const active = orderedThreads.filter(({ thread }) =>\n activeThreads.includes(thread.id)\n );\n\n // Filter threads that should come after the active threads\n const after = orderedThreads.filter(({ thread, element }) => {\n if (activeThreads.includes(thread.id)) return false;\n\n // Check if the current thread comes after any of the active threads\n const isAfter = active.some(({ element: activeElement }) => {\n return compareNodes(activeElement, element) === -1;\n });\n\n return isAfter;\n });\n\n return active.concat(after);\n }\n\n const ascending = getAscendingThreads();\n\n // Filter threads that are neither active nor come after active threads (i.e. 'other' threads)\n const descending = orderedThreads.filter(\n (entry) => !ascending.includes(entry)\n );\n\n const newPositions = new Map<string, number>();\n\n // Iterate over each thread and calculate its new position by taking into account the position of the previously positioned threads\n for (const { thread, element } of ascending) {\n const rect = element.getBoundingClientRect();\n let top = rect.top - container.getBoundingClientRect().top;\n\n for (const [id, position] of newPositions) {\n // Retrieve the element associated with the thread\n const el = elements.get(id);\n if (el === undefined) continue;\n\n if (\n top >= position &&\n top <= position + el.getBoundingClientRect().height\n ) {\n top = position + el.getBoundingClientRect().height;\n }\n }\n\n newPositions.set(thread.id, top);\n }\n\n for (const { thread, element } of descending.reverse()) {\n const rect = element.getBoundingClientRect();\n // Retrieve the element associated with the current thread\n const el = elements.get(thread.id);\n if (el === undefined) continue;\n\n let top = rect.top - container.getBoundingClientRect().top;\n for (const [, position] of newPositions) {\n if (top >= position - el.getBoundingClientRect().height) {\n top = position - el.getBoundingClientRect().height;\n }\n }\n\n newPositions.set(thread.id, top);\n }\n\n setPositions(newPositions);\n }, [getOrderedThreads, activeThreads, elements]);\n\n useLayoutEffect(() => {\n handlePositionThreads();\n }, [handlePositionThreads]);\n\n useEffect(() => {\n return editor.registerUpdateListener(() => {\n handlePositionThreads();\n });\n }, [editor, handlePositionThreads]);\n\n useEffect(() => {\n const observer = new ResizeObserver(handlePositionThreads);\n for (const element of elements.values()) {\n observer.observe(element);\n }\n\n return () => observer.disconnect();\n }, [elements, handlePositionThreads]);\n\n const root = useRootElement();\n\n useEffect(() => {\n if (root === null) return;\n const observer = new ResizeObserver(handlePositionThreads);\n\n observer.observe(root);\n return () => observer.disconnect();\n }, [root, handlePositionThreads]);\n\n if (orderedThreads.length === 0) return null;\n\n return (\n <div\n {...props}\n className={classNames(className, \"lb-root lb-lexical-anchored-threads\")}\n ref={containerRef}\n style={{\n position: \"relative\",\n ...style,\n }}\n >\n {orderedThreads.map(({ thread, element }) => {\n const rect = element.getBoundingClientRect();\n const offset = root !== null ? root.getBoundingClientRect().top : 0;\n\n let top = rect.top - offset;\n\n if (positions.has(thread.id)) {\n top = positions.get(thread.id)!;\n }\n\n const isActive = activeThreads.includes(thread.id);\n\n return (\n <ThreadWrapper\n key={thread.id}\n Thread={Thread}\n thread={thread}\n onItemAdd={onItemAdd}\n onItemRemove={onItemRemove}\n style={{\n position: \"absolute\",\n transform: `translate3d(${isActive ? ACTIVE_THREAD_OFFSET : 0}, ${top}px, 0)`,\n insetInlineStart: 0,\n inlineSize: \"100%\",\n paddingBlockEnd: GAP,\n }}\n />\n );\n })}\n </div>\n );\n}\n\ninterface ThreadWrapperProps extends ThreadProps {\n Thread: ComponentType<ThreadProps>;\n onItemAdd: (id: string, el: HTMLElement) => void;\n onItemRemove: (id: string) => void;\n}\n\nfunction ThreadWrapper({\n onItemAdd,\n onItemRemove,\n thread,\n Thread,\n className,\n ...props\n}: ThreadWrapperProps) {\n const [editor] = useLexicalComposerContext();\n const nodes = useThreadToNodes();\n const divRef = useRef<HTMLDivElement>(null);\n\n const activeThreads = useActiveThreads();\n\n const isActive = activeThreads.includes(thread.id);\n\n function handleThreadClick() {\n const keys = nodes.get(thread.id);\n if (keys === undefined || keys.size === 0) return;\n\n if (activeThreads.includes(thread.id)) return;\n\n editor.update(() => {\n const [key] = keys;\n const node = $getNodeByKey(key);\n if (!$isThreadMarkNode(node)) return;\n node.selectStart();\n });\n }\n\n useLayoutEffect(() => {\n const el = divRef.current;\n if (el === null) return;\n\n onItemAdd(thread.id, el);\n return () => {\n onItemRemove(thread.id);\n };\n }, [thread.id, onItemAdd, onItemRemove]);\n\n return (\n <div\n ref={divRef}\n className={classNames(\n \"lb-lexical-anchored-threads-thread-container\",\n className\n )}\n {...props}\n >\n <Thread\n thread={thread}\n data-state={isActive ? \"active\" : \"inactive\"}\n onClick={handleThreadClick}\n className=\"lb-lexical-anchored-threads-thread\"\n showComposer={isActive ? true : false}\n />\n </div>\n );\n}\n\nfunction useThreadToNodes(): ThreadToNodesMap {\n const threadToNodes = useContext(ThreadToNodesContext);\n if (threadToNodes === null) {\n throw new Error(\n \"AnchoredThreads component must be used within a LiveblocksPlugin component.\"\n );\n }\n return threadToNodes;\n}\n\nfunction useActiveThreads() {\n const activeThreads = useContext(ActiveThreadsContext);\n if (activeThreads === null) {\n throw new Error(\n \"AnchoredThreads component must be used within LiveblocksPlugin.\"\n );\n }\n\n return activeThreads;\n}\n"],"names":["useLexicalComposerContext","DefaultThread","useRef","useCallback","elements","useMemo","useState","orderedThreads","useLayoutEffect","useEffect","useRootElement","jsx","classNames","$getNodeByKey","$isThreadMarkNode","useContext","ThreadToNodesContext","ActiveThreadsContext"],"mappings":"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"}
1
+ {"version":3,"file":"anchored-threads.js","sources":["../../src/comments/anchored-threads.tsx"],"sourcesContent":["import { useLexicalComposerContext } from \"@lexical/react/LexicalComposerContext\";\nimport type { BaseMetadata, DM, ThreadData } from \"@liveblocks/core\";\nimport { useLayoutEffect } from \"@liveblocks/react/_private\";\nimport {\n Thread as DefaultThread,\n type ThreadProps,\n} from \"@liveblocks/react-ui\";\nimport { $getNodeByKey } from \"lexical\";\nimport type { ComponentPropsWithoutRef, ComponentType } from \"react\";\nimport {\n useCallback,\n useContext,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from \"react\";\n\nimport { classNames } from \"../classnames\";\nimport { useRootElement } from \"../use-root-element\";\nimport {\n ActiveThreadsContext,\n type ThreadToNodesMap,\n} from \"./comment-plugin-provider\";\nimport { ThreadToNodesContext } from \"./comment-plugin-provider\";\nimport { $isThreadMarkNode } from \"./thread-mark-node\";\n\nconst DEFAULT_GAP = 20;\nconst DEFAULT_ACTIVE_THREAD_OFFSET = -12;\n\nconst GAP = `var(--lb-lexical-anchored-threads-gap, ${DEFAULT_GAP}px)`;\nconst ACTIVE_THREAD_OFFSET = `var(--lb-lexical-anchored-threads-active-thread-offset, ${DEFAULT_ACTIVE_THREAD_OFFSET}px)`;\n\ntype AnchoredThreadsComponents = {\n Thread: ComponentType<ThreadProps>;\n};\n\nexport interface AnchoredThreadsProps<M extends BaseMetadata = DM>\n extends Omit<ComponentPropsWithoutRef<\"div\">, \"children\"> {\n /**\n * The threads to display.\n */\n threads: ThreadData<M>[];\n\n /**\n * Override the component's components.\n */\n components?: Partial<AnchoredThreadsComponents>;\n}\n\n/**\n * Compares two nodes based on their position in the DOM.\n * Returns -1 if a comes before b, 1 if a comes after b, and 0 if they are the same node.\n * @param a The first node to compare\n * @param b The second node to compare\n * @returns -1 if a comes before b, 1 if a comes after b, and 0 if they are the same node.\n */\nexport function compareNodes(a: Node, b: Node): number {\n // Calculate the position of node 'b' relative to node 'a'\n const position = a.compareDocumentPosition(b);\n if (position & Node.DOCUMENT_POSITION_FOLLOWING) return -1;\n if (position & Node.DOCUMENT_POSITION_PRECEDING) return 1;\n return 0;\n}\n\nexport function AnchoredThreads({\n threads,\n components,\n className,\n style,\n ...props\n}: AnchoredThreadsProps) {\n const [editor] = useLexicalComposerContext();\n const Thread = components?.Thread ?? DefaultThread;\n const containerRef = useRef<HTMLDivElement>(null);\n\n const activeThreads = useActiveThreads();\n\n const nodes = useThreadToNodes(); // A map of thread ids to a set of thread mark nodes associated with the thread\n\n const getOrderedThreads = useCallback(() => {\n return threads\n .filter((thread) => thread.resolved === false)\n .map((thread) => {\n const keys = nodes.get(thread.id);\n if (keys === undefined || keys.size === 0) return null;\n\n const elements = Array.from(keys.values())\n .map((key) => editor.getElementByKey(key))\n .filter(Boolean) as HTMLElement[];\n if (elements.length === 0) return null;\n\n const element = elements.sort(compareNodes)[0];\n return {\n thread,\n element,\n };\n })\n .filter(\n (entry): entry is { thread: ThreadData; element: HTMLElement } =>\n entry !== null\n )\n .sort((a, b) => {\n return compareNodes(a.element, b.element);\n });\n }, [editor, threads, nodes]);\n\n // Sort threads by the position of the first element associated with the thread in the document (top to bottom, left to right)\n const orderedThreads = useMemo(getOrderedThreads, [getOrderedThreads]);\n\n const [elements, setElements] = useState<Map<string, HTMLElement>>(new Map());\n\n const [positions, setPositions] = useState<Map<string, number>>(new Map()); // A map of thread ids to their 'top' position in the document\n\n const onItemAdd = useCallback((id: string, el: HTMLElement) => {\n setElements((prev) => new Map(prev).set(id, el));\n }, []);\n\n const onItemRemove = useCallback((id: string) => {\n setElements((prev) => {\n const items = new Map(prev);\n items.delete(id);\n return items;\n });\n }, []);\n\n const handlePositionThreads = useCallback(() => {\n const container = containerRef.current;\n if (container === null) return;\n\n const orderedThreads = getOrderedThreads();\n\n // Returns an array of threads that should be positioned in ascending order - this includes threads that are active and threads that should come after the active threads\n function getAscendingThreads() {\n // If there are no active threads, all threads are ordered in ascending manner.\n if (activeThreads.length === 0) return orderedThreads;\n\n // Filter threads that are active\n const active = orderedThreads.filter(({ thread }) =>\n activeThreads.includes(thread.id)\n );\n\n // Filter threads that should come after the active threads\n const after = orderedThreads.filter(({ thread, element }) => {\n if (activeThreads.includes(thread.id)) return false;\n\n // Check if the current thread comes after any of the active threads\n const isAfter = active.some(({ element: activeElement }) => {\n return compareNodes(activeElement, element) === -1;\n });\n\n return isAfter;\n });\n\n return active.concat(after);\n }\n\n const ascending = getAscendingThreads();\n\n // Filter threads that are neither active nor come after active threads (i.e. 'other' threads)\n const descending = orderedThreads.filter(\n (entry) => !ascending.includes(entry)\n );\n\n const newPositions = new Map<string, number>();\n\n // Iterate over each thread and calculate its new position by taking into account the position of the previously positioned threads\n for (const { thread, element } of ascending) {\n const rect = element.getBoundingClientRect();\n let top = rect.top - container.getBoundingClientRect().top;\n\n for (const [id, position] of newPositions) {\n // Retrieve the element associated with the thread\n const el = elements.get(id);\n if (el === undefined) continue;\n\n if (\n top >= position &&\n top <= position + el.getBoundingClientRect().height\n ) {\n top = position + el.getBoundingClientRect().height;\n }\n }\n\n newPositions.set(thread.id, top);\n }\n\n for (const { thread, element } of descending.reverse()) {\n const rect = element.getBoundingClientRect();\n // Retrieve the element associated with the current thread\n const el = elements.get(thread.id);\n if (el === undefined) continue;\n\n let top = rect.top - container.getBoundingClientRect().top;\n for (const [, position] of newPositions) {\n if (top >= position - el.getBoundingClientRect().height) {\n top = position - el.getBoundingClientRect().height;\n }\n }\n\n newPositions.set(thread.id, top);\n }\n\n setPositions(newPositions);\n }, [getOrderedThreads, activeThreads, elements]);\n\n useLayoutEffect(() => {\n handlePositionThreads();\n }, [handlePositionThreads]);\n\n useEffect(() => {\n return editor.registerUpdateListener(() => {\n handlePositionThreads();\n });\n }, [editor, handlePositionThreads]);\n\n useEffect(() => {\n const observer = new ResizeObserver(handlePositionThreads);\n for (const element of elements.values()) {\n observer.observe(element);\n }\n\n return () => observer.disconnect();\n }, [elements, handlePositionThreads]);\n\n const root = useRootElement();\n\n useEffect(() => {\n if (root === null) return;\n const observer = new ResizeObserver(handlePositionThreads);\n\n observer.observe(root);\n return () => observer.disconnect();\n }, [root, handlePositionThreads]);\n\n if (orderedThreads.length === 0) return null;\n\n return (\n <div\n {...props}\n className={classNames(className, \"lb-root lb-lexical-anchored-threads\")}\n ref={containerRef}\n style={{\n position: \"relative\",\n ...style,\n }}\n >\n {orderedThreads.map(({ thread, element }) => {\n const rect = element.getBoundingClientRect();\n const offset = root !== null ? root.getBoundingClientRect().top : 0;\n\n let top = rect.top - offset;\n\n if (positions.has(thread.id)) {\n top = positions.get(thread.id)!;\n }\n\n const isActive = activeThreads.includes(thread.id);\n\n return (\n <ThreadWrapper\n key={thread.id}\n Thread={Thread}\n thread={thread}\n onItemAdd={onItemAdd}\n onItemRemove={onItemRemove}\n style={{\n position: \"absolute\",\n transform: `translate3d(${isActive ? ACTIVE_THREAD_OFFSET : 0}, ${top}px, 0)`,\n insetInlineStart: 0,\n inlineSize: \"100%\",\n paddingBlockEnd: GAP,\n }}\n />\n );\n })}\n </div>\n );\n}\n\ninterface ThreadWrapperProps extends ThreadProps {\n Thread: ComponentType<ThreadProps>;\n onItemAdd: (id: string, el: HTMLElement) => void;\n onItemRemove: (id: string) => void;\n}\n\nfunction ThreadWrapper({\n onItemAdd,\n onItemRemove,\n thread,\n Thread,\n className,\n ...props\n}: ThreadWrapperProps) {\n const [editor] = useLexicalComposerContext();\n const nodes = useThreadToNodes();\n const divRef = useRef<HTMLDivElement>(null);\n\n const activeThreads = useActiveThreads();\n\n const isActive = activeThreads.includes(thread.id);\n\n function handleThreadClick() {\n const keys = nodes.get(thread.id);\n if (keys === undefined || keys.size === 0) return;\n\n if (activeThreads.includes(thread.id)) return;\n\n editor.update(() => {\n const [key] = keys;\n const node = $getNodeByKey(key);\n if (!$isThreadMarkNode(node)) return;\n node.selectStart();\n });\n }\n\n useLayoutEffect(() => {\n const el = divRef.current;\n if (el === null) return;\n\n onItemAdd(thread.id, el);\n return () => {\n onItemRemove(thread.id);\n };\n }, [thread.id, onItemAdd, onItemRemove]);\n\n return (\n <div\n ref={divRef}\n className={classNames(\n \"lb-lexical-anchored-threads-thread-container\",\n className\n )}\n {...props}\n >\n <Thread\n thread={thread}\n data-state={isActive ? \"active\" : \"inactive\"}\n onClick={handleThreadClick}\n className=\"lb-lexical-anchored-threads-thread\"\n showComposer={isActive ? true : false}\n />\n </div>\n );\n}\n\nfunction useThreadToNodes(): ThreadToNodesMap {\n const threadToNodes = useContext(ThreadToNodesContext);\n if (threadToNodes === null) {\n throw new Error(\n \"AnchoredThreads component must be used within a LiveblocksPlugin component.\"\n );\n }\n return threadToNodes;\n}\n\nfunction useActiveThreads() {\n const activeThreads = useContext(ActiveThreadsContext);\n if (activeThreads === null) {\n throw new Error(\n \"AnchoredThreads component must be used within LiveblocksPlugin.\"\n );\n }\n\n return activeThreads;\n}\n"],"names":["useLexicalComposerContext","DefaultThread","useRef","useCallback","elements","useMemo","useState","orderedThreads","useLayoutEffect","useEffect","useRootElement","jsx","classNames","$getNodeByKey","$isThreadMarkNode","useContext","ThreadToNodesContext","ActiveThreadsContext"],"mappings":"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"}
@@ -5,7 +5,7 @@ import { Thread } from '@liveblocks/react-ui';
5
5
  import { $getNodeByKey } from 'lexical';
6
6
  import { useRef, useCallback, useMemo, useState, useEffect, useContext } from 'react';
7
7
  import { classNames } from '../classnames.mjs';
8
- import { useRootElement } from '../liveblocks-plugin-provider.mjs';
8
+ import { useRootElement } from '../use-root-element.mjs';
9
9
  import { ThreadToNodesContext, ActiveThreadsContext } from './comment-plugin-provider.mjs';
10
10
  import { $isThreadMarkNode } from './thread-mark-node.mjs';
11
11
 
@@ -1 +1 @@
1
- {"version":3,"file":"anchored-threads.mjs","sources":["../../src/comments/anchored-threads.tsx"],"sourcesContent":["import { useLexicalComposerContext } from \"@lexical/react/LexicalComposerContext\";\nimport type { BaseMetadata, DM, ThreadData } from \"@liveblocks/core\";\nimport { useLayoutEffect } from \"@liveblocks/react/_private\";\nimport {\n Thread as DefaultThread,\n type ThreadProps,\n} from \"@liveblocks/react-ui\";\nimport { $getNodeByKey } from \"lexical\";\nimport type { ComponentPropsWithoutRef, ComponentType } from \"react\";\nimport {\n useCallback,\n useContext,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from \"react\";\n\nimport { classNames } from \"../classnames\";\nimport { useRootElement } from \"../liveblocks-plugin-provider\";\nimport {\n ActiveThreadsContext,\n type ThreadToNodesMap,\n} from \"./comment-plugin-provider\";\nimport { ThreadToNodesContext } from \"./comment-plugin-provider\";\nimport { $isThreadMarkNode } from \"./thread-mark-node\";\n\nconst DEFAULT_GAP = 20;\nconst DEFAULT_ACTIVE_THREAD_OFFSET = -12;\n\nconst GAP = `var(--lb-lexical-anchored-threads-gap, ${DEFAULT_GAP}px)`;\nconst ACTIVE_THREAD_OFFSET = `var(--lb-lexical-anchored-threads-active-thread-offset, ${DEFAULT_ACTIVE_THREAD_OFFSET}px)`;\n\ntype AnchoredThreadsComponents = {\n Thread: ComponentType<ThreadProps>;\n};\n\nexport interface AnchoredThreadsProps<M extends BaseMetadata = DM>\n extends Omit<ComponentPropsWithoutRef<\"div\">, \"children\"> {\n /**\n * The threads to display.\n */\n threads: ThreadData<M>[];\n\n /**\n * Override the component's components.\n */\n components?: Partial<AnchoredThreadsComponents>;\n}\n\n/**\n * Compares two nodes based on their position in the DOM.\n * Returns -1 if a comes before b, 1 if a comes after b, and 0 if they are the same node.\n * @param a The first node to compare\n * @param b The second node to compare\n * @returns -1 if a comes before b, 1 if a comes after b, and 0 if they are the same node.\n */\nexport function compareNodes(a: Node, b: Node): number {\n // Calculate the position of node 'b' relative to node 'a'\n const position = a.compareDocumentPosition(b);\n if (position & Node.DOCUMENT_POSITION_FOLLOWING) return -1;\n if (position & Node.DOCUMENT_POSITION_PRECEDING) return 1;\n return 0;\n}\n\nexport function AnchoredThreads({\n threads,\n components,\n className,\n style,\n ...props\n}: AnchoredThreadsProps) {\n const [editor] = useLexicalComposerContext();\n const Thread = components?.Thread ?? DefaultThread;\n const containerRef = useRef<HTMLDivElement>(null);\n\n const activeThreads = useActiveThreads();\n\n const nodes = useThreadToNodes(); // A map of thread ids to a set of thread mark nodes associated with the thread\n\n const getOrderedThreads = useCallback(() => {\n return threads\n .filter((thread) => thread.resolved === false)\n .map((thread) => {\n const keys = nodes.get(thread.id);\n if (keys === undefined || keys.size === 0) return null;\n\n const elements = Array.from(keys.values())\n .map((key) => editor.getElementByKey(key))\n .filter(Boolean) as HTMLElement[];\n if (elements.length === 0) return null;\n\n const element = elements.sort(compareNodes)[0];\n return {\n thread,\n element,\n };\n })\n .filter(\n (entry): entry is { thread: ThreadData; element: HTMLElement } =>\n entry !== null\n )\n .sort((a, b) => {\n return compareNodes(a.element, b.element);\n });\n }, [editor, threads, nodes]);\n\n // Sort threads by the position of the first element associated with the thread in the document (top to bottom, left to right)\n const orderedThreads = useMemo(getOrderedThreads, [getOrderedThreads]);\n\n const [elements, setElements] = useState<Map<string, HTMLElement>>(new Map());\n\n const [positions, setPositions] = useState<Map<string, number>>(new Map()); // A map of thread ids to their 'top' position in the document\n\n const onItemAdd = useCallback((id: string, el: HTMLElement) => {\n setElements((prev) => new Map(prev).set(id, el));\n }, []);\n\n const onItemRemove = useCallback((id: string) => {\n setElements((prev) => {\n const items = new Map(prev);\n items.delete(id);\n return items;\n });\n }, []);\n\n const handlePositionThreads = useCallback(() => {\n const container = containerRef.current;\n if (container === null) return;\n\n const orderedThreads = getOrderedThreads();\n\n // Returns an array of threads that should be positioned in ascending order - this includes threads that are active and threads that should come after the active threads\n function getAscendingThreads() {\n // If there are no active threads, all threads are ordered in ascending manner.\n if (activeThreads.length === 0) return orderedThreads;\n\n // Filter threads that are active\n const active = orderedThreads.filter(({ thread }) =>\n activeThreads.includes(thread.id)\n );\n\n // Filter threads that should come after the active threads\n const after = orderedThreads.filter(({ thread, element }) => {\n if (activeThreads.includes(thread.id)) return false;\n\n // Check if the current thread comes after any of the active threads\n const isAfter = active.some(({ element: activeElement }) => {\n return compareNodes(activeElement, element) === -1;\n });\n\n return isAfter;\n });\n\n return active.concat(after);\n }\n\n const ascending = getAscendingThreads();\n\n // Filter threads that are neither active nor come after active threads (i.e. 'other' threads)\n const descending = orderedThreads.filter(\n (entry) => !ascending.includes(entry)\n );\n\n const newPositions = new Map<string, number>();\n\n // Iterate over each thread and calculate its new position by taking into account the position of the previously positioned threads\n for (const { thread, element } of ascending) {\n const rect = element.getBoundingClientRect();\n let top = rect.top - container.getBoundingClientRect().top;\n\n for (const [id, position] of newPositions) {\n // Retrieve the element associated with the thread\n const el = elements.get(id);\n if (el === undefined) continue;\n\n if (\n top >= position &&\n top <= position + el.getBoundingClientRect().height\n ) {\n top = position + el.getBoundingClientRect().height;\n }\n }\n\n newPositions.set(thread.id, top);\n }\n\n for (const { thread, element } of descending.reverse()) {\n const rect = element.getBoundingClientRect();\n // Retrieve the element associated with the current thread\n const el = elements.get(thread.id);\n if (el === undefined) continue;\n\n let top = rect.top - container.getBoundingClientRect().top;\n for (const [, position] of newPositions) {\n if (top >= position - el.getBoundingClientRect().height) {\n top = position - el.getBoundingClientRect().height;\n }\n }\n\n newPositions.set(thread.id, top);\n }\n\n setPositions(newPositions);\n }, [getOrderedThreads, activeThreads, elements]);\n\n useLayoutEffect(() => {\n handlePositionThreads();\n }, [handlePositionThreads]);\n\n useEffect(() => {\n return editor.registerUpdateListener(() => {\n handlePositionThreads();\n });\n }, [editor, handlePositionThreads]);\n\n useEffect(() => {\n const observer = new ResizeObserver(handlePositionThreads);\n for (const element of elements.values()) {\n observer.observe(element);\n }\n\n return () => observer.disconnect();\n }, [elements, handlePositionThreads]);\n\n const root = useRootElement();\n\n useEffect(() => {\n if (root === null) return;\n const observer = new ResizeObserver(handlePositionThreads);\n\n observer.observe(root);\n return () => observer.disconnect();\n }, [root, handlePositionThreads]);\n\n if (orderedThreads.length === 0) return null;\n\n return (\n <div\n {...props}\n className={classNames(className, \"lb-root lb-lexical-anchored-threads\")}\n ref={containerRef}\n style={{\n position: \"relative\",\n ...style,\n }}\n >\n {orderedThreads.map(({ thread, element }) => {\n const rect = element.getBoundingClientRect();\n const offset = root !== null ? root.getBoundingClientRect().top : 0;\n\n let top = rect.top - offset;\n\n if (positions.has(thread.id)) {\n top = positions.get(thread.id)!;\n }\n\n const isActive = activeThreads.includes(thread.id);\n\n return (\n <ThreadWrapper\n key={thread.id}\n Thread={Thread}\n thread={thread}\n onItemAdd={onItemAdd}\n onItemRemove={onItemRemove}\n style={{\n position: \"absolute\",\n transform: `translate3d(${isActive ? ACTIVE_THREAD_OFFSET : 0}, ${top}px, 0)`,\n insetInlineStart: 0,\n inlineSize: \"100%\",\n paddingBlockEnd: GAP,\n }}\n />\n );\n })}\n </div>\n );\n}\n\ninterface ThreadWrapperProps extends ThreadProps {\n Thread: ComponentType<ThreadProps>;\n onItemAdd: (id: string, el: HTMLElement) => void;\n onItemRemove: (id: string) => void;\n}\n\nfunction ThreadWrapper({\n onItemAdd,\n onItemRemove,\n thread,\n Thread,\n className,\n ...props\n}: ThreadWrapperProps) {\n const [editor] = useLexicalComposerContext();\n const nodes = useThreadToNodes();\n const divRef = useRef<HTMLDivElement>(null);\n\n const activeThreads = useActiveThreads();\n\n const isActive = activeThreads.includes(thread.id);\n\n function handleThreadClick() {\n const keys = nodes.get(thread.id);\n if (keys === undefined || keys.size === 0) return;\n\n if (activeThreads.includes(thread.id)) return;\n\n editor.update(() => {\n const [key] = keys;\n const node = $getNodeByKey(key);\n if (!$isThreadMarkNode(node)) return;\n node.selectStart();\n });\n }\n\n useLayoutEffect(() => {\n const el = divRef.current;\n if (el === null) return;\n\n onItemAdd(thread.id, el);\n return () => {\n onItemRemove(thread.id);\n };\n }, [thread.id, onItemAdd, onItemRemove]);\n\n return (\n <div\n ref={divRef}\n className={classNames(\n \"lb-lexical-anchored-threads-thread-container\",\n className\n )}\n {...props}\n >\n <Thread\n thread={thread}\n data-state={isActive ? \"active\" : \"inactive\"}\n onClick={handleThreadClick}\n className=\"lb-lexical-anchored-threads-thread\"\n showComposer={isActive ? true : false}\n />\n </div>\n );\n}\n\nfunction useThreadToNodes(): ThreadToNodesMap {\n const threadToNodes = useContext(ThreadToNodesContext);\n if (threadToNodes === null) {\n throw new Error(\n \"AnchoredThreads component must be used within a LiveblocksPlugin component.\"\n );\n }\n return threadToNodes;\n}\n\nfunction useActiveThreads() {\n const activeThreads = useContext(ActiveThreadsContext);\n if (activeThreads === null) {\n throw new Error(\n \"AnchoredThreads component must be used within LiveblocksPlugin.\"\n );\n }\n\n return activeThreads;\n}\n"],"names":["Thread","DefaultThread","elements","orderedThreads"],"mappings":";;;;;;;;;;;AA2BA,MAAM,WAAc,GAAA,EAAA,CAAA;AACpB,MAAM,4BAA+B,GAAA,CAAA,EAAA,CAAA;AAErC,MAAM,MAAM,CAA0C,uCAAA,EAAA,WAAA,CAAA,GAAA,CAAA,CAAA;AACtD,MAAM,uBAAuB,CAA2D,wDAAA,EAAA,4BAAA,CAAA,GAAA,CAAA,CAAA;AA0BxE,SAAA,YAAA,CAAa,GAAS,CAAiB,EAAA;AAErD,EAAM,MAAA,QAAA,GAAW,CAAE,CAAA,uBAAA,CAAwB,CAAC,CAAA,CAAA;AAC5C,EAAA,IAAI,WAAW,IAAK,CAAA,2BAAA;AAA6B,IAAO,OAAA,CAAA,CAAA,CAAA;AACxD,EAAA,IAAI,WAAW,IAAK,CAAA,2BAAA;AAA6B,IAAO,OAAA,CAAA,CAAA;AACxD,EAAO,OAAA,CAAA,CAAA;AACT,CAAA;AAEO,SAAS,eAAgB,CAAA;AAAA,EAC9B,OAAA;AAAA,EACA,UAAA;AAAA,EACA,SAAA;AAAA,EACA,KAAA;AAAA,EACG,GAAA,KAAA;AACL,CAAyB,EAAA;AACvB,EAAM,MAAA,CAAC,MAAM,CAAA,GAAI,yBAA0B,EAAA,CAAA;AAC3C,EAAM,MAAAA,QAAA,GAAS,YAAY,MAAU,IAAAC,MAAA,CAAA;AACrC,EAAM,MAAA,YAAA,GAAe,OAAuB,IAAI,CAAA,CAAA;AAEhD,EAAA,MAAM,gBAAgB,gBAAiB,EAAA,CAAA;AAEvC,EAAA,MAAM,QAAQ,gBAAiB,EAAA,CAAA;AAE/B,EAAM,MAAA,iBAAA,GAAoB,YAAY,MAAM;AAC1C,IAAO,OAAA,OAAA,CACJ,MAAO,CAAA,CAAC,MAAW,KAAA,MAAA,CAAO,aAAa,KAAK,CAAA,CAC5C,GAAI,CAAA,CAAC,MAAW,KAAA;AACf,MAAA,MAAM,IAAO,GAAA,KAAA,CAAM,GAAI,CAAA,MAAA,CAAO,EAAE,CAAA,CAAA;AAChC,MAAI,IAAA,IAAA,KAAS,KAAa,CAAA,IAAA,IAAA,CAAK,IAAS,KAAA,CAAA;AAAG,QAAO,OAAA,IAAA,CAAA;AAElD,MAAA,MAAMC,YAAW,KAAM,CAAA,IAAA,CAAK,IAAK,CAAA,MAAA,EAAQ,CACtC,CAAA,GAAA,CAAI,CAAC,GAAA,KAAQ,OAAO,eAAgB,CAAA,GAAG,CAAC,CAAA,CACxC,OAAO,OAAO,CAAA,CAAA;AACjB,MAAA,IAAIA,UAAS,MAAW,KAAA,CAAA;AAAG,QAAO,OAAA,IAAA,CAAA;AAElC,MAAA,MAAM,OAAUA,GAAAA,SAAAA,CAAS,IAAK,CAAA,YAAY,CAAE,CAAA,CAAA,CAAA,CAAA;AAC5C,MAAO,OAAA;AAAA,QACL,MAAA;AAAA,QACA,OAAA;AAAA,OACF,CAAA;AAAA,KACD,CACA,CAAA,MAAA;AAAA,MACC,CAAC,UACC,KAAU,KAAA,IAAA;AAAA,KAEb,CAAA,IAAA,CAAK,CAAC,CAAA,EAAG,CAAM,KAAA;AACd,MAAA,OAAO,YAAa,CAAA,CAAA,CAAE,OAAS,EAAA,CAAA,CAAE,OAAO,CAAA,CAAA;AAAA,KACzC,CAAA,CAAA;AAAA,GACF,EAAA,CAAC,MAAQ,EAAA,OAAA,EAAS,KAAK,CAAC,CAAA,CAAA;AAG3B,EAAA,MAAM,cAAiB,GAAA,OAAA,CAAQ,iBAAmB,EAAA,CAAC,iBAAiB,CAAC,CAAA,CAAA;AAErE,EAAA,MAAM,CAAC,QAAU,EAAA,WAAW,IAAI,QAAmC,iBAAA,IAAI,KAAK,CAAA,CAAA;AAE5E,EAAA,MAAM,CAAC,SAAW,EAAA,YAAY,IAAI,QAA8B,iBAAA,IAAI,KAAK,CAAA,CAAA;AAEzE,EAAA,MAAM,SAAY,GAAA,WAAA,CAAY,CAAC,EAAA,EAAY,EAAoB,KAAA;AAC7D,IAAY,WAAA,CAAA,CAAC,SAAS,IAAI,GAAA,CAAI,IAAI,CAAE,CAAA,GAAA,CAAI,EAAI,EAAA,EAAE,CAAC,CAAA,CAAA;AAAA,GACjD,EAAG,EAAE,CAAA,CAAA;AAEL,EAAM,MAAA,YAAA,GAAe,WAAY,CAAA,CAAC,EAAe,KAAA;AAC/C,IAAA,WAAA,CAAY,CAAC,IAAS,KAAA;AACpB,MAAM,MAAA,KAAA,GAAQ,IAAI,GAAA,CAAI,IAAI,CAAA,CAAA;AAC1B,MAAA,KAAA,CAAM,OAAO,EAAE,CAAA,CAAA;AACf,MAAO,OAAA,KAAA,CAAA;AAAA,KACR,CAAA,CAAA;AAAA,GACH,EAAG,EAAE,CAAA,CAAA;AAEL,EAAM,MAAA,qBAAA,GAAwB,YAAY,MAAM;AAC9C,IAAA,MAAM,YAAY,YAAa,CAAA,OAAA,CAAA;AAC/B,IAAA,IAAI,SAAc,KAAA,IAAA;AAAM,MAAA,OAAA;AAExB,IAAA,MAAMC,kBAAiB,iBAAkB,EAAA,CAAA;AAGzC,IAAA,SAAS,mBAAsB,GAAA;AAE7B,MAAA,IAAI,cAAc,MAAW,KAAA,CAAA;AAAG,QAAOA,OAAAA,eAAAA,CAAAA;AAGvC,MAAA,MAAM,SAASA,eAAe,CAAA,MAAA;AAAA,QAAO,CAAC,EAAE,MAAA,OACtC,aAAc,CAAA,QAAA,CAAS,OAAO,EAAE,CAAA;AAAA,OAClC,CAAA;AAGA,MAAA,MAAM,QAAQA,eAAe,CAAA,MAAA,CAAO,CAAC,EAAE,MAAA,EAAQ,SAAc,KAAA;AAC3D,QAAI,IAAA,aAAA,CAAc,QAAS,CAAA,MAAA,CAAO,EAAE,CAAA;AAAG,UAAO,OAAA,KAAA,CAAA;AAG9C,QAAA,MAAM,UAAU,MAAO,CAAA,IAAA,CAAK,CAAC,EAAE,OAAA,EAAS,eAAoB,KAAA;AAC1D,UAAO,OAAA,YAAA,CAAa,aAAe,EAAA,OAAO,CAAM,KAAA,CAAA,CAAA,CAAA;AAAA,SACjD,CAAA,CAAA;AAED,QAAO,OAAA,OAAA,CAAA;AAAA,OACR,CAAA,CAAA;AAED,MAAO,OAAA,MAAA,CAAO,OAAO,KAAK,CAAA,CAAA;AAAA,KAC5B;AAEA,IAAA,MAAM,YAAY,mBAAoB,EAAA,CAAA;AAGtC,IAAA,MAAM,aAAaA,eAAe,CAAA,MAAA;AAAA,MAChC,CAAC,KAAA,KAAU,CAAC,SAAA,CAAU,SAAS,KAAK,CAAA;AAAA,KACtC,CAAA;AAEA,IAAM,MAAA,YAAA,uBAAmB,GAAoB,EAAA,CAAA;AAG7C,IAAA,KAAA,MAAW,EAAE,MAAA,EAAQ,OAAQ,EAAA,IAAK,SAAW,EAAA;AAC3C,MAAM,MAAA,IAAA,GAAO,QAAQ,qBAAsB,EAAA,CAAA;AAC3C,MAAA,IAAI,GAAM,GAAA,IAAA,CAAK,GAAM,GAAA,SAAA,CAAU,uBAAwB,CAAA,GAAA,CAAA;AAEvD,MAAA,KAAA,MAAW,CAAC,EAAA,EAAI,QAAQ,CAAA,IAAK,YAAc,EAAA;AAEzC,QAAM,MAAA,EAAA,GAAK,QAAS,CAAA,GAAA,CAAI,EAAE,CAAA,CAAA;AAC1B,QAAA,IAAI,EAAO,KAAA,KAAA,CAAA;AAAW,UAAA,SAAA;AAEtB,QAAA,IACE,OAAO,QACP,IAAA,GAAA,IAAO,WAAW,EAAG,CAAA,qBAAA,GAAwB,MAC7C,EAAA;AACA,UAAM,GAAA,GAAA,QAAA,GAAW,EAAG,CAAA,qBAAA,EAAwB,CAAA,MAAA,CAAA;AAAA,SAC9C;AAAA,OACF;AAEA,MAAa,YAAA,CAAA,GAAA,CAAI,MAAO,CAAA,EAAA,EAAI,GAAG,CAAA,CAAA;AAAA,KACjC;AAEA,IAAA,KAAA,MAAW,EAAE,MAAQ,EAAA,OAAA,EAAa,IAAA,UAAA,CAAW,SAAW,EAAA;AACtD,MAAM,MAAA,IAAA,GAAO,QAAQ,qBAAsB,EAAA,CAAA;AAE3C,MAAA,MAAM,EAAK,GAAA,QAAA,CAAS,GAAI,CAAA,MAAA,CAAO,EAAE,CAAA,CAAA;AACjC,MAAA,IAAI,EAAO,KAAA,KAAA,CAAA;AAAW,QAAA,SAAA;AAEtB,MAAA,IAAI,GAAM,GAAA,IAAA,CAAK,GAAM,GAAA,SAAA,CAAU,uBAAwB,CAAA,GAAA,CAAA;AACvD,MAAA,KAAA,MAAW,GAAG,QAAQ,CAAA,IAAK,YAAc,EAAA;AACvC,QAAA,IAAI,GAAO,IAAA,QAAA,GAAW,EAAG,CAAA,qBAAA,GAAwB,MAAQ,EAAA;AACvD,UAAM,GAAA,GAAA,QAAA,GAAW,EAAG,CAAA,qBAAA,EAAwB,CAAA,MAAA,CAAA;AAAA,SAC9C;AAAA,OACF;AAEA,MAAa,YAAA,CAAA,GAAA,CAAI,MAAO,CAAA,EAAA,EAAI,GAAG,CAAA,CAAA;AAAA,KACjC;AAEA,IAAA,YAAA,CAAa,YAAY,CAAA,CAAA;AAAA,GACxB,EAAA,CAAC,iBAAmB,EAAA,aAAA,EAAe,QAAQ,CAAC,CAAA,CAAA;AAE/C,EAAA,eAAA,CAAgB,MAAM;AACpB,IAAsB,qBAAA,EAAA,CAAA;AAAA,GACxB,EAAG,CAAC,qBAAqB,CAAC,CAAA,CAAA;AAE1B,EAAA,SAAA,CAAU,MAAM;AACd,IAAO,OAAA,MAAA,CAAO,uBAAuB,MAAM;AACzC,MAAsB,qBAAA,EAAA,CAAA;AAAA,KACvB,CAAA,CAAA;AAAA,GACA,EAAA,CAAC,MAAQ,EAAA,qBAAqB,CAAC,CAAA,CAAA;AAElC,EAAA,SAAA,CAAU,MAAM;AACd,IAAM,MAAA,QAAA,GAAW,IAAI,cAAA,CAAe,qBAAqB,CAAA,CAAA;AACzD,IAAW,KAAA,MAAA,OAAA,IAAW,QAAS,CAAA,MAAA,EAAU,EAAA;AACvC,MAAA,QAAA,CAAS,QAAQ,OAAO,CAAA,CAAA;AAAA,KAC1B;AAEA,IAAO,OAAA,MAAM,SAAS,UAAW,EAAA,CAAA;AAAA,GAChC,EAAA,CAAC,QAAU,EAAA,qBAAqB,CAAC,CAAA,CAAA;AAEpC,EAAA,MAAM,OAAO,cAAe,EAAA,CAAA;AAE5B,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,IAAI,IAAS,KAAA,IAAA;AAAM,MAAA,OAAA;AACnB,IAAM,MAAA,QAAA,GAAW,IAAI,cAAA,CAAe,qBAAqB,CAAA,CAAA;AAEzD,IAAA,QAAA,CAAS,QAAQ,IAAI,CAAA,CAAA;AACrB,IAAO,OAAA,MAAM,SAAS,UAAW,EAAA,CAAA;AAAA,GAChC,EAAA,CAAC,IAAM,EAAA,qBAAqB,CAAC,CAAA,CAAA;AAEhC,EAAA,IAAI,eAAe,MAAW,KAAA,CAAA;AAAG,IAAO,OAAA,IAAA,CAAA;AAExC,EAAA,uBACG,GAAA,CAAA,KAAA,EAAA;AAAA,IACE,GAAG,KAAA;AAAA,IACJ,SAAA,EAAW,UAAW,CAAA,SAAA,EAAW,qCAAqC,CAAA;AAAA,IACtE,GAAK,EAAA,YAAA;AAAA,IACL,KAAO,EAAA;AAAA,MACL,QAAU,EAAA,UAAA;AAAA,MACV,GAAG,KAAA;AAAA,KACL;AAAA,IAEC,yBAAe,GAAI,CAAA,CAAC,EAAE,MAAA,EAAQ,SAAc,KAAA;AAC3C,MAAM,MAAA,IAAA,GAAO,QAAQ,qBAAsB,EAAA,CAAA;AAC3C,MAAA,MAAM,SAAS,IAAS,KAAA,IAAA,GAAO,IAAK,CAAA,qBAAA,GAAwB,GAAM,GAAA,CAAA,CAAA;AAElE,MAAI,IAAA,GAAA,GAAM,KAAK,GAAM,GAAA,MAAA,CAAA;AAErB,MAAA,IAAI,SAAU,CAAA,GAAA,CAAI,MAAO,CAAA,EAAE,CAAG,EAAA;AAC5B,QAAM,GAAA,GAAA,SAAA,CAAU,GAAI,CAAA,MAAA,CAAO,EAAE,CAAA,CAAA;AAAA,OAC/B;AAEA,MAAA,MAAM,QAAW,GAAA,aAAA,CAAc,QAAS,CAAA,MAAA,CAAO,EAAE,CAAA,CAAA;AAEjD,MAAA,uBACG,GAAA,CAAA,aAAA,EAAA;AAAA,gBAECH,QAAA;AAAA,QACA,MAAA;AAAA,QACA,SAAA;AAAA,QACA,YAAA;AAAA,QACA,KAAO,EAAA;AAAA,UACL,QAAU,EAAA,UAAA;AAAA,UACV,SAAW,EAAA,CAAA,YAAA,EAAe,QAAW,GAAA,oBAAA,GAAuB,CAAM,CAAA,EAAA,EAAA,GAAA,CAAA,MAAA,CAAA;AAAA,UAClE,gBAAkB,EAAA,CAAA;AAAA,UAClB,UAAY,EAAA,MAAA;AAAA,UACZ,eAAiB,EAAA,GAAA;AAAA,SACnB;AAAA,OAAA,EAXK,OAAO,EAYd,CAAA,CAAA;AAAA,KAEH,CAAA;AAAA,GACH,CAAA,CAAA;AAEJ,CAAA;AAQA,SAAS,aAAc,CAAA;AAAA,EACrB,SAAA;AAAA,EACA,YAAA;AAAA,EACA,MAAA;AAAA,EACA,MAAA;AAAA,EACA,SAAA;AAAA,EACG,GAAA,KAAA;AACL,CAAuB,EAAA;AACrB,EAAM,MAAA,CAAC,MAAM,CAAA,GAAI,yBAA0B,EAAA,CAAA;AAC3C,EAAA,MAAM,QAAQ,gBAAiB,EAAA,CAAA;AAC/B,EAAM,MAAA,MAAA,GAAS,OAAuB,IAAI,CAAA,CAAA;AAE1C,EAAA,MAAM,gBAAgB,gBAAiB,EAAA,CAAA;AAEvC,EAAA,MAAM,QAAW,GAAA,aAAA,CAAc,QAAS,CAAA,MAAA,CAAO,EAAE,CAAA,CAAA;AAEjD,EAAA,SAAS,iBAAoB,GAAA;AAC3B,IAAA,MAAM,IAAO,GAAA,KAAA,CAAM,GAAI,CAAA,MAAA,CAAO,EAAE,CAAA,CAAA;AAChC,IAAI,IAAA,IAAA,KAAS,KAAa,CAAA,IAAA,IAAA,CAAK,IAAS,KAAA,CAAA;AAAG,MAAA,OAAA;AAE3C,IAAI,IAAA,aAAA,CAAc,QAAS,CAAA,MAAA,CAAO,EAAE,CAAA;AAAG,MAAA,OAAA;AAEvC,IAAA,MAAA,CAAO,OAAO,MAAM;AAClB,MAAM,MAAA,CAAC,GAAG,CAAI,GAAA,IAAA,CAAA;AACd,MAAM,MAAA,IAAA,GAAO,cAAc,GAAG,CAAA,CAAA;AAC9B,MAAI,IAAA,CAAC,kBAAkB,IAAI,CAAA;AAAG,QAAA,OAAA;AAC9B,MAAA,IAAA,CAAK,WAAY,EAAA,CAAA;AAAA,KAClB,CAAA,CAAA;AAAA,GACH;AAEA,EAAA,eAAA,CAAgB,MAAM;AACpB,IAAA,MAAM,KAAK,MAAO,CAAA,OAAA,CAAA;AAClB,IAAA,IAAI,EAAO,KAAA,IAAA;AAAM,MAAA,OAAA;AAEjB,IAAU,SAAA,CAAA,MAAA,CAAO,IAAI,EAAE,CAAA,CAAA;AACvB,IAAA,OAAO,MAAM;AACX,MAAA,YAAA,CAAa,OAAO,EAAE,CAAA,CAAA;AAAA,KACxB,CAAA;AAAA,KACC,CAAC,MAAA,CAAO,EAAI,EAAA,SAAA,EAAW,YAAY,CAAC,CAAA,CAAA;AAEvC,EAAA,uBACG,GAAA,CAAA,KAAA,EAAA;AAAA,IACC,GAAK,EAAA,MAAA;AAAA,IACL,SAAW,EAAA,UAAA;AAAA,MACT,8CAAA;AAAA,MACA,SAAA;AAAA,KACF;AAAA,IACC,GAAG,KAAA;AAAA,IAEJ,QAAC,kBAAA,GAAA,CAAA,MAAA,EAAA;AAAA,MACC,MAAA;AAAA,MACA,YAAA,EAAY,WAAW,QAAW,GAAA,UAAA;AAAA,MAClC,OAAS,EAAA,iBAAA;AAAA,MACT,SAAU,EAAA,oCAAA;AAAA,MACV,YAAA,EAAc,WAAW,IAAO,GAAA,KAAA;AAAA,KAClC,CAAA;AAAA,GACF,CAAA,CAAA;AAEJ,CAAA;AAEA,SAAS,gBAAqC,GAAA;AAC5C,EAAM,MAAA,aAAA,GAAgB,WAAW,oBAAoB,CAAA,CAAA;AACrD,EAAA,IAAI,kBAAkB,IAAM,EAAA;AAC1B,IAAA,MAAM,IAAI,KAAA;AAAA,MACR,6EAAA;AAAA,KACF,CAAA;AAAA,GACF;AACA,EAAO,OAAA,aAAA,CAAA;AACT,CAAA;AAEA,SAAS,gBAAmB,GAAA;AAC1B,EAAM,MAAA,aAAA,GAAgB,WAAW,oBAAoB,CAAA,CAAA;AACrD,EAAA,IAAI,kBAAkB,IAAM,EAAA;AAC1B,IAAA,MAAM,IAAI,KAAA;AAAA,MACR,iEAAA;AAAA,KACF,CAAA;AAAA,GACF;AAEA,EAAO,OAAA,aAAA,CAAA;AACT;;;;"}
1
+ {"version":3,"file":"anchored-threads.mjs","sources":["../../src/comments/anchored-threads.tsx"],"sourcesContent":["import { useLexicalComposerContext } from \"@lexical/react/LexicalComposerContext\";\nimport type { BaseMetadata, DM, ThreadData } from \"@liveblocks/core\";\nimport { useLayoutEffect } from \"@liveblocks/react/_private\";\nimport {\n Thread as DefaultThread,\n type ThreadProps,\n} from \"@liveblocks/react-ui\";\nimport { $getNodeByKey } from \"lexical\";\nimport type { ComponentPropsWithoutRef, ComponentType } from \"react\";\nimport {\n useCallback,\n useContext,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from \"react\";\n\nimport { classNames } from \"../classnames\";\nimport { useRootElement } from \"../use-root-element\";\nimport {\n ActiveThreadsContext,\n type ThreadToNodesMap,\n} from \"./comment-plugin-provider\";\nimport { ThreadToNodesContext } from \"./comment-plugin-provider\";\nimport { $isThreadMarkNode } from \"./thread-mark-node\";\n\nconst DEFAULT_GAP = 20;\nconst DEFAULT_ACTIVE_THREAD_OFFSET = -12;\n\nconst GAP = `var(--lb-lexical-anchored-threads-gap, ${DEFAULT_GAP}px)`;\nconst ACTIVE_THREAD_OFFSET = `var(--lb-lexical-anchored-threads-active-thread-offset, ${DEFAULT_ACTIVE_THREAD_OFFSET}px)`;\n\ntype AnchoredThreadsComponents = {\n Thread: ComponentType<ThreadProps>;\n};\n\nexport interface AnchoredThreadsProps<M extends BaseMetadata = DM>\n extends Omit<ComponentPropsWithoutRef<\"div\">, \"children\"> {\n /**\n * The threads to display.\n */\n threads: ThreadData<M>[];\n\n /**\n * Override the component's components.\n */\n components?: Partial<AnchoredThreadsComponents>;\n}\n\n/**\n * Compares two nodes based on their position in the DOM.\n * Returns -1 if a comes before b, 1 if a comes after b, and 0 if they are the same node.\n * @param a The first node to compare\n * @param b The second node to compare\n * @returns -1 if a comes before b, 1 if a comes after b, and 0 if they are the same node.\n */\nexport function compareNodes(a: Node, b: Node): number {\n // Calculate the position of node 'b' relative to node 'a'\n const position = a.compareDocumentPosition(b);\n if (position & Node.DOCUMENT_POSITION_FOLLOWING) return -1;\n if (position & Node.DOCUMENT_POSITION_PRECEDING) return 1;\n return 0;\n}\n\nexport function AnchoredThreads({\n threads,\n components,\n className,\n style,\n ...props\n}: AnchoredThreadsProps) {\n const [editor] = useLexicalComposerContext();\n const Thread = components?.Thread ?? DefaultThread;\n const containerRef = useRef<HTMLDivElement>(null);\n\n const activeThreads = useActiveThreads();\n\n const nodes = useThreadToNodes(); // A map of thread ids to a set of thread mark nodes associated with the thread\n\n const getOrderedThreads = useCallback(() => {\n return threads\n .filter((thread) => thread.resolved === false)\n .map((thread) => {\n const keys = nodes.get(thread.id);\n if (keys === undefined || keys.size === 0) return null;\n\n const elements = Array.from(keys.values())\n .map((key) => editor.getElementByKey(key))\n .filter(Boolean) as HTMLElement[];\n if (elements.length === 0) return null;\n\n const element = elements.sort(compareNodes)[0];\n return {\n thread,\n element,\n };\n })\n .filter(\n (entry): entry is { thread: ThreadData; element: HTMLElement } =>\n entry !== null\n )\n .sort((a, b) => {\n return compareNodes(a.element, b.element);\n });\n }, [editor, threads, nodes]);\n\n // Sort threads by the position of the first element associated with the thread in the document (top to bottom, left to right)\n const orderedThreads = useMemo(getOrderedThreads, [getOrderedThreads]);\n\n const [elements, setElements] = useState<Map<string, HTMLElement>>(new Map());\n\n const [positions, setPositions] = useState<Map<string, number>>(new Map()); // A map of thread ids to their 'top' position in the document\n\n const onItemAdd = useCallback((id: string, el: HTMLElement) => {\n setElements((prev) => new Map(prev).set(id, el));\n }, []);\n\n const onItemRemove = useCallback((id: string) => {\n setElements((prev) => {\n const items = new Map(prev);\n items.delete(id);\n return items;\n });\n }, []);\n\n const handlePositionThreads = useCallback(() => {\n const container = containerRef.current;\n if (container === null) return;\n\n const orderedThreads = getOrderedThreads();\n\n // Returns an array of threads that should be positioned in ascending order - this includes threads that are active and threads that should come after the active threads\n function getAscendingThreads() {\n // If there are no active threads, all threads are ordered in ascending manner.\n if (activeThreads.length === 0) return orderedThreads;\n\n // Filter threads that are active\n const active = orderedThreads.filter(({ thread }) =>\n activeThreads.includes(thread.id)\n );\n\n // Filter threads that should come after the active threads\n const after = orderedThreads.filter(({ thread, element }) => {\n if (activeThreads.includes(thread.id)) return false;\n\n // Check if the current thread comes after any of the active threads\n const isAfter = active.some(({ element: activeElement }) => {\n return compareNodes(activeElement, element) === -1;\n });\n\n return isAfter;\n });\n\n return active.concat(after);\n }\n\n const ascending = getAscendingThreads();\n\n // Filter threads that are neither active nor come after active threads (i.e. 'other' threads)\n const descending = orderedThreads.filter(\n (entry) => !ascending.includes(entry)\n );\n\n const newPositions = new Map<string, number>();\n\n // Iterate over each thread and calculate its new position by taking into account the position of the previously positioned threads\n for (const { thread, element } of ascending) {\n const rect = element.getBoundingClientRect();\n let top = rect.top - container.getBoundingClientRect().top;\n\n for (const [id, position] of newPositions) {\n // Retrieve the element associated with the thread\n const el = elements.get(id);\n if (el === undefined) continue;\n\n if (\n top >= position &&\n top <= position + el.getBoundingClientRect().height\n ) {\n top = position + el.getBoundingClientRect().height;\n }\n }\n\n newPositions.set(thread.id, top);\n }\n\n for (const { thread, element } of descending.reverse()) {\n const rect = element.getBoundingClientRect();\n // Retrieve the element associated with the current thread\n const el = elements.get(thread.id);\n if (el === undefined) continue;\n\n let top = rect.top - container.getBoundingClientRect().top;\n for (const [, position] of newPositions) {\n if (top >= position - el.getBoundingClientRect().height) {\n top = position - el.getBoundingClientRect().height;\n }\n }\n\n newPositions.set(thread.id, top);\n }\n\n setPositions(newPositions);\n }, [getOrderedThreads, activeThreads, elements]);\n\n useLayoutEffect(() => {\n handlePositionThreads();\n }, [handlePositionThreads]);\n\n useEffect(() => {\n return editor.registerUpdateListener(() => {\n handlePositionThreads();\n });\n }, [editor, handlePositionThreads]);\n\n useEffect(() => {\n const observer = new ResizeObserver(handlePositionThreads);\n for (const element of elements.values()) {\n observer.observe(element);\n }\n\n return () => observer.disconnect();\n }, [elements, handlePositionThreads]);\n\n const root = useRootElement();\n\n useEffect(() => {\n if (root === null) return;\n const observer = new ResizeObserver(handlePositionThreads);\n\n observer.observe(root);\n return () => observer.disconnect();\n }, [root, handlePositionThreads]);\n\n if (orderedThreads.length === 0) return null;\n\n return (\n <div\n {...props}\n className={classNames(className, \"lb-root lb-lexical-anchored-threads\")}\n ref={containerRef}\n style={{\n position: \"relative\",\n ...style,\n }}\n >\n {orderedThreads.map(({ thread, element }) => {\n const rect = element.getBoundingClientRect();\n const offset = root !== null ? root.getBoundingClientRect().top : 0;\n\n let top = rect.top - offset;\n\n if (positions.has(thread.id)) {\n top = positions.get(thread.id)!;\n }\n\n const isActive = activeThreads.includes(thread.id);\n\n return (\n <ThreadWrapper\n key={thread.id}\n Thread={Thread}\n thread={thread}\n onItemAdd={onItemAdd}\n onItemRemove={onItemRemove}\n style={{\n position: \"absolute\",\n transform: `translate3d(${isActive ? ACTIVE_THREAD_OFFSET : 0}, ${top}px, 0)`,\n insetInlineStart: 0,\n inlineSize: \"100%\",\n paddingBlockEnd: GAP,\n }}\n />\n );\n })}\n </div>\n );\n}\n\ninterface ThreadWrapperProps extends ThreadProps {\n Thread: ComponentType<ThreadProps>;\n onItemAdd: (id: string, el: HTMLElement) => void;\n onItemRemove: (id: string) => void;\n}\n\nfunction ThreadWrapper({\n onItemAdd,\n onItemRemove,\n thread,\n Thread,\n className,\n ...props\n}: ThreadWrapperProps) {\n const [editor] = useLexicalComposerContext();\n const nodes = useThreadToNodes();\n const divRef = useRef<HTMLDivElement>(null);\n\n const activeThreads = useActiveThreads();\n\n const isActive = activeThreads.includes(thread.id);\n\n function handleThreadClick() {\n const keys = nodes.get(thread.id);\n if (keys === undefined || keys.size === 0) return;\n\n if (activeThreads.includes(thread.id)) return;\n\n editor.update(() => {\n const [key] = keys;\n const node = $getNodeByKey(key);\n if (!$isThreadMarkNode(node)) return;\n node.selectStart();\n });\n }\n\n useLayoutEffect(() => {\n const el = divRef.current;\n if (el === null) return;\n\n onItemAdd(thread.id, el);\n return () => {\n onItemRemove(thread.id);\n };\n }, [thread.id, onItemAdd, onItemRemove]);\n\n return (\n <div\n ref={divRef}\n className={classNames(\n \"lb-lexical-anchored-threads-thread-container\",\n className\n )}\n {...props}\n >\n <Thread\n thread={thread}\n data-state={isActive ? \"active\" : \"inactive\"}\n onClick={handleThreadClick}\n className=\"lb-lexical-anchored-threads-thread\"\n showComposer={isActive ? true : false}\n />\n </div>\n );\n}\n\nfunction useThreadToNodes(): ThreadToNodesMap {\n const threadToNodes = useContext(ThreadToNodesContext);\n if (threadToNodes === null) {\n throw new Error(\n \"AnchoredThreads component must be used within a LiveblocksPlugin component.\"\n );\n }\n return threadToNodes;\n}\n\nfunction useActiveThreads() {\n const activeThreads = useContext(ActiveThreadsContext);\n if (activeThreads === null) {\n throw new Error(\n \"AnchoredThreads component must be used within LiveblocksPlugin.\"\n );\n }\n\n return activeThreads;\n}\n"],"names":["Thread","DefaultThread","elements","orderedThreads"],"mappings":";;;;;;;;;;;AA2BA,MAAM,WAAc,GAAA,EAAA,CAAA;AACpB,MAAM,4BAA+B,GAAA,CAAA,EAAA,CAAA;AAErC,MAAM,MAAM,CAA0C,uCAAA,EAAA,WAAA,CAAA,GAAA,CAAA,CAAA;AACtD,MAAM,uBAAuB,CAA2D,wDAAA,EAAA,4BAAA,CAAA,GAAA,CAAA,CAAA;AA0BxE,SAAA,YAAA,CAAa,GAAS,CAAiB,EAAA;AAErD,EAAM,MAAA,QAAA,GAAW,CAAE,CAAA,uBAAA,CAAwB,CAAC,CAAA,CAAA;AAC5C,EAAA,IAAI,WAAW,IAAK,CAAA,2BAAA;AAA6B,IAAO,OAAA,CAAA,CAAA,CAAA;AACxD,EAAA,IAAI,WAAW,IAAK,CAAA,2BAAA;AAA6B,IAAO,OAAA,CAAA,CAAA;AACxD,EAAO,OAAA,CAAA,CAAA;AACT,CAAA;AAEO,SAAS,eAAgB,CAAA;AAAA,EAC9B,OAAA;AAAA,EACA,UAAA;AAAA,EACA,SAAA;AAAA,EACA,KAAA;AAAA,EACG,GAAA,KAAA;AACL,CAAyB,EAAA;AACvB,EAAM,MAAA,CAAC,MAAM,CAAA,GAAI,yBAA0B,EAAA,CAAA;AAC3C,EAAM,MAAAA,QAAA,GAAS,YAAY,MAAU,IAAAC,MAAA,CAAA;AACrC,EAAM,MAAA,YAAA,GAAe,OAAuB,IAAI,CAAA,CAAA;AAEhD,EAAA,MAAM,gBAAgB,gBAAiB,EAAA,CAAA;AAEvC,EAAA,MAAM,QAAQ,gBAAiB,EAAA,CAAA;AAE/B,EAAM,MAAA,iBAAA,GAAoB,YAAY,MAAM;AAC1C,IAAO,OAAA,OAAA,CACJ,MAAO,CAAA,CAAC,MAAW,KAAA,MAAA,CAAO,aAAa,KAAK,CAAA,CAC5C,GAAI,CAAA,CAAC,MAAW,KAAA;AACf,MAAA,MAAM,IAAO,GAAA,KAAA,CAAM,GAAI,CAAA,MAAA,CAAO,EAAE,CAAA,CAAA;AAChC,MAAI,IAAA,IAAA,KAAS,KAAa,CAAA,IAAA,IAAA,CAAK,IAAS,KAAA,CAAA;AAAG,QAAO,OAAA,IAAA,CAAA;AAElD,MAAA,MAAMC,YAAW,KAAM,CAAA,IAAA,CAAK,IAAK,CAAA,MAAA,EAAQ,CACtC,CAAA,GAAA,CAAI,CAAC,GAAA,KAAQ,OAAO,eAAgB,CAAA,GAAG,CAAC,CAAA,CACxC,OAAO,OAAO,CAAA,CAAA;AACjB,MAAA,IAAIA,UAAS,MAAW,KAAA,CAAA;AAAG,QAAO,OAAA,IAAA,CAAA;AAElC,MAAA,MAAM,OAAUA,GAAAA,SAAAA,CAAS,IAAK,CAAA,YAAY,CAAE,CAAA,CAAA,CAAA,CAAA;AAC5C,MAAO,OAAA;AAAA,QACL,MAAA;AAAA,QACA,OAAA;AAAA,OACF,CAAA;AAAA,KACD,CACA,CAAA,MAAA;AAAA,MACC,CAAC,UACC,KAAU,KAAA,IAAA;AAAA,KAEb,CAAA,IAAA,CAAK,CAAC,CAAA,EAAG,CAAM,KAAA;AACd,MAAA,OAAO,YAAa,CAAA,CAAA,CAAE,OAAS,EAAA,CAAA,CAAE,OAAO,CAAA,CAAA;AAAA,KACzC,CAAA,CAAA;AAAA,GACF,EAAA,CAAC,MAAQ,EAAA,OAAA,EAAS,KAAK,CAAC,CAAA,CAAA;AAG3B,EAAA,MAAM,cAAiB,GAAA,OAAA,CAAQ,iBAAmB,EAAA,CAAC,iBAAiB,CAAC,CAAA,CAAA;AAErE,EAAA,MAAM,CAAC,QAAU,EAAA,WAAW,IAAI,QAAmC,iBAAA,IAAI,KAAK,CAAA,CAAA;AAE5E,EAAA,MAAM,CAAC,SAAW,EAAA,YAAY,IAAI,QAA8B,iBAAA,IAAI,KAAK,CAAA,CAAA;AAEzE,EAAA,MAAM,SAAY,GAAA,WAAA,CAAY,CAAC,EAAA,EAAY,EAAoB,KAAA;AAC7D,IAAY,WAAA,CAAA,CAAC,SAAS,IAAI,GAAA,CAAI,IAAI,CAAE,CAAA,GAAA,CAAI,EAAI,EAAA,EAAE,CAAC,CAAA,CAAA;AAAA,GACjD,EAAG,EAAE,CAAA,CAAA;AAEL,EAAM,MAAA,YAAA,GAAe,WAAY,CAAA,CAAC,EAAe,KAAA;AAC/C,IAAA,WAAA,CAAY,CAAC,IAAS,KAAA;AACpB,MAAM,MAAA,KAAA,GAAQ,IAAI,GAAA,CAAI,IAAI,CAAA,CAAA;AAC1B,MAAA,KAAA,CAAM,OAAO,EAAE,CAAA,CAAA;AACf,MAAO,OAAA,KAAA,CAAA;AAAA,KACR,CAAA,CAAA;AAAA,GACH,EAAG,EAAE,CAAA,CAAA;AAEL,EAAM,MAAA,qBAAA,GAAwB,YAAY,MAAM;AAC9C,IAAA,MAAM,YAAY,YAAa,CAAA,OAAA,CAAA;AAC/B,IAAA,IAAI,SAAc,KAAA,IAAA;AAAM,MAAA,OAAA;AAExB,IAAA,MAAMC,kBAAiB,iBAAkB,EAAA,CAAA;AAGzC,IAAA,SAAS,mBAAsB,GAAA;AAE7B,MAAA,IAAI,cAAc,MAAW,KAAA,CAAA;AAAG,QAAOA,OAAAA,eAAAA,CAAAA;AAGvC,MAAA,MAAM,SAASA,eAAe,CAAA,MAAA;AAAA,QAAO,CAAC,EAAE,MAAA,OACtC,aAAc,CAAA,QAAA,CAAS,OAAO,EAAE,CAAA;AAAA,OAClC,CAAA;AAGA,MAAA,MAAM,QAAQA,eAAe,CAAA,MAAA,CAAO,CAAC,EAAE,MAAA,EAAQ,SAAc,KAAA;AAC3D,QAAI,IAAA,aAAA,CAAc,QAAS,CAAA,MAAA,CAAO,EAAE,CAAA;AAAG,UAAO,OAAA,KAAA,CAAA;AAG9C,QAAA,MAAM,UAAU,MAAO,CAAA,IAAA,CAAK,CAAC,EAAE,OAAA,EAAS,eAAoB,KAAA;AAC1D,UAAO,OAAA,YAAA,CAAa,aAAe,EAAA,OAAO,CAAM,KAAA,CAAA,CAAA,CAAA;AAAA,SACjD,CAAA,CAAA;AAED,QAAO,OAAA,OAAA,CAAA;AAAA,OACR,CAAA,CAAA;AAED,MAAO,OAAA,MAAA,CAAO,OAAO,KAAK,CAAA,CAAA;AAAA,KAC5B;AAEA,IAAA,MAAM,YAAY,mBAAoB,EAAA,CAAA;AAGtC,IAAA,MAAM,aAAaA,eAAe,CAAA,MAAA;AAAA,MAChC,CAAC,KAAA,KAAU,CAAC,SAAA,CAAU,SAAS,KAAK,CAAA;AAAA,KACtC,CAAA;AAEA,IAAM,MAAA,YAAA,uBAAmB,GAAoB,EAAA,CAAA;AAG7C,IAAA,KAAA,MAAW,EAAE,MAAA,EAAQ,OAAQ,EAAA,IAAK,SAAW,EAAA;AAC3C,MAAM,MAAA,IAAA,GAAO,QAAQ,qBAAsB,EAAA,CAAA;AAC3C,MAAA,IAAI,GAAM,GAAA,IAAA,CAAK,GAAM,GAAA,SAAA,CAAU,uBAAwB,CAAA,GAAA,CAAA;AAEvD,MAAA,KAAA,MAAW,CAAC,EAAA,EAAI,QAAQ,CAAA,IAAK,YAAc,EAAA;AAEzC,QAAM,MAAA,EAAA,GAAK,QAAS,CAAA,GAAA,CAAI,EAAE,CAAA,CAAA;AAC1B,QAAA,IAAI,EAAO,KAAA,KAAA,CAAA;AAAW,UAAA,SAAA;AAEtB,QAAA,IACE,OAAO,QACP,IAAA,GAAA,IAAO,WAAW,EAAG,CAAA,qBAAA,GAAwB,MAC7C,EAAA;AACA,UAAM,GAAA,GAAA,QAAA,GAAW,EAAG,CAAA,qBAAA,EAAwB,CAAA,MAAA,CAAA;AAAA,SAC9C;AAAA,OACF;AAEA,MAAa,YAAA,CAAA,GAAA,CAAI,MAAO,CAAA,EAAA,EAAI,GAAG,CAAA,CAAA;AAAA,KACjC;AAEA,IAAA,KAAA,MAAW,EAAE,MAAQ,EAAA,OAAA,EAAa,IAAA,UAAA,CAAW,SAAW,EAAA;AACtD,MAAM,MAAA,IAAA,GAAO,QAAQ,qBAAsB,EAAA,CAAA;AAE3C,MAAA,MAAM,EAAK,GAAA,QAAA,CAAS,GAAI,CAAA,MAAA,CAAO,EAAE,CAAA,CAAA;AACjC,MAAA,IAAI,EAAO,KAAA,KAAA,CAAA;AAAW,QAAA,SAAA;AAEtB,MAAA,IAAI,GAAM,GAAA,IAAA,CAAK,GAAM,GAAA,SAAA,CAAU,uBAAwB,CAAA,GAAA,CAAA;AACvD,MAAA,KAAA,MAAW,GAAG,QAAQ,CAAA,IAAK,YAAc,EAAA;AACvC,QAAA,IAAI,GAAO,IAAA,QAAA,GAAW,EAAG,CAAA,qBAAA,GAAwB,MAAQ,EAAA;AACvD,UAAM,GAAA,GAAA,QAAA,GAAW,EAAG,CAAA,qBAAA,EAAwB,CAAA,MAAA,CAAA;AAAA,SAC9C;AAAA,OACF;AAEA,MAAa,YAAA,CAAA,GAAA,CAAI,MAAO,CAAA,EAAA,EAAI,GAAG,CAAA,CAAA;AAAA,KACjC;AAEA,IAAA,YAAA,CAAa,YAAY,CAAA,CAAA;AAAA,GACxB,EAAA,CAAC,iBAAmB,EAAA,aAAA,EAAe,QAAQ,CAAC,CAAA,CAAA;AAE/C,EAAA,eAAA,CAAgB,MAAM;AACpB,IAAsB,qBAAA,EAAA,CAAA;AAAA,GACxB,EAAG,CAAC,qBAAqB,CAAC,CAAA,CAAA;AAE1B,EAAA,SAAA,CAAU,MAAM;AACd,IAAO,OAAA,MAAA,CAAO,uBAAuB,MAAM;AACzC,MAAsB,qBAAA,EAAA,CAAA;AAAA,KACvB,CAAA,CAAA;AAAA,GACA,EAAA,CAAC,MAAQ,EAAA,qBAAqB,CAAC,CAAA,CAAA;AAElC,EAAA,SAAA,CAAU,MAAM;AACd,IAAM,MAAA,QAAA,GAAW,IAAI,cAAA,CAAe,qBAAqB,CAAA,CAAA;AACzD,IAAW,KAAA,MAAA,OAAA,IAAW,QAAS,CAAA,MAAA,EAAU,EAAA;AACvC,MAAA,QAAA,CAAS,QAAQ,OAAO,CAAA,CAAA;AAAA,KAC1B;AAEA,IAAO,OAAA,MAAM,SAAS,UAAW,EAAA,CAAA;AAAA,GAChC,EAAA,CAAC,QAAU,EAAA,qBAAqB,CAAC,CAAA,CAAA;AAEpC,EAAA,MAAM,OAAO,cAAe,EAAA,CAAA;AAE5B,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,IAAI,IAAS,KAAA,IAAA;AAAM,MAAA,OAAA;AACnB,IAAM,MAAA,QAAA,GAAW,IAAI,cAAA,CAAe,qBAAqB,CAAA,CAAA;AAEzD,IAAA,QAAA,CAAS,QAAQ,IAAI,CAAA,CAAA;AACrB,IAAO,OAAA,MAAM,SAAS,UAAW,EAAA,CAAA;AAAA,GAChC,EAAA,CAAC,IAAM,EAAA,qBAAqB,CAAC,CAAA,CAAA;AAEhC,EAAA,IAAI,eAAe,MAAW,KAAA,CAAA;AAAG,IAAO,OAAA,IAAA,CAAA;AAExC,EAAA,uBACG,GAAA,CAAA,KAAA,EAAA;AAAA,IACE,GAAG,KAAA;AAAA,IACJ,SAAA,EAAW,UAAW,CAAA,SAAA,EAAW,qCAAqC,CAAA;AAAA,IACtE,GAAK,EAAA,YAAA;AAAA,IACL,KAAO,EAAA;AAAA,MACL,QAAU,EAAA,UAAA;AAAA,MACV,GAAG,KAAA;AAAA,KACL;AAAA,IAEC,yBAAe,GAAI,CAAA,CAAC,EAAE,MAAA,EAAQ,SAAc,KAAA;AAC3C,MAAM,MAAA,IAAA,GAAO,QAAQ,qBAAsB,EAAA,CAAA;AAC3C,MAAA,MAAM,SAAS,IAAS,KAAA,IAAA,GAAO,IAAK,CAAA,qBAAA,GAAwB,GAAM,GAAA,CAAA,CAAA;AAElE,MAAI,IAAA,GAAA,GAAM,KAAK,GAAM,GAAA,MAAA,CAAA;AAErB,MAAA,IAAI,SAAU,CAAA,GAAA,CAAI,MAAO,CAAA,EAAE,CAAG,EAAA;AAC5B,QAAM,GAAA,GAAA,SAAA,CAAU,GAAI,CAAA,MAAA,CAAO,EAAE,CAAA,CAAA;AAAA,OAC/B;AAEA,MAAA,MAAM,QAAW,GAAA,aAAA,CAAc,QAAS,CAAA,MAAA,CAAO,EAAE,CAAA,CAAA;AAEjD,MAAA,uBACG,GAAA,CAAA,aAAA,EAAA;AAAA,gBAECH,QAAA;AAAA,QACA,MAAA;AAAA,QACA,SAAA;AAAA,QACA,YAAA;AAAA,QACA,KAAO,EAAA;AAAA,UACL,QAAU,EAAA,UAAA;AAAA,UACV,SAAW,EAAA,CAAA,YAAA,EAAe,QAAW,GAAA,oBAAA,GAAuB,CAAM,CAAA,EAAA,EAAA,GAAA,CAAA,MAAA,CAAA;AAAA,UAClE,gBAAkB,EAAA,CAAA;AAAA,UAClB,UAAY,EAAA,MAAA;AAAA,UACZ,eAAiB,EAAA,GAAA;AAAA,SACnB;AAAA,OAAA,EAXK,OAAO,EAYd,CAAA,CAAA;AAAA,KAEH,CAAA;AAAA,GACH,CAAA,CAAA;AAEJ,CAAA;AAQA,SAAS,aAAc,CAAA;AAAA,EACrB,SAAA;AAAA,EACA,YAAA;AAAA,EACA,MAAA;AAAA,EACA,MAAA;AAAA,EACA,SAAA;AAAA,EACG,GAAA,KAAA;AACL,CAAuB,EAAA;AACrB,EAAM,MAAA,CAAC,MAAM,CAAA,GAAI,yBAA0B,EAAA,CAAA;AAC3C,EAAA,MAAM,QAAQ,gBAAiB,EAAA,CAAA;AAC/B,EAAM,MAAA,MAAA,GAAS,OAAuB,IAAI,CAAA,CAAA;AAE1C,EAAA,MAAM,gBAAgB,gBAAiB,EAAA,CAAA;AAEvC,EAAA,MAAM,QAAW,GAAA,aAAA,CAAc,QAAS,CAAA,MAAA,CAAO,EAAE,CAAA,CAAA;AAEjD,EAAA,SAAS,iBAAoB,GAAA;AAC3B,IAAA,MAAM,IAAO,GAAA,KAAA,CAAM,GAAI,CAAA,MAAA,CAAO,EAAE,CAAA,CAAA;AAChC,IAAI,IAAA,IAAA,KAAS,KAAa,CAAA,IAAA,IAAA,CAAK,IAAS,KAAA,CAAA;AAAG,MAAA,OAAA;AAE3C,IAAI,IAAA,aAAA,CAAc,QAAS,CAAA,MAAA,CAAO,EAAE,CAAA;AAAG,MAAA,OAAA;AAEvC,IAAA,MAAA,CAAO,OAAO,MAAM;AAClB,MAAM,MAAA,CAAC,GAAG,CAAI,GAAA,IAAA,CAAA;AACd,MAAM,MAAA,IAAA,GAAO,cAAc,GAAG,CAAA,CAAA;AAC9B,MAAI,IAAA,CAAC,kBAAkB,IAAI,CAAA;AAAG,QAAA,OAAA;AAC9B,MAAA,IAAA,CAAK,WAAY,EAAA,CAAA;AAAA,KAClB,CAAA,CAAA;AAAA,GACH;AAEA,EAAA,eAAA,CAAgB,MAAM;AACpB,IAAA,MAAM,KAAK,MAAO,CAAA,OAAA,CAAA;AAClB,IAAA,IAAI,EAAO,KAAA,IAAA;AAAM,MAAA,OAAA;AAEjB,IAAU,SAAA,CAAA,MAAA,CAAO,IAAI,EAAE,CAAA,CAAA;AACvB,IAAA,OAAO,MAAM;AACX,MAAA,YAAA,CAAa,OAAO,EAAE,CAAA,CAAA;AAAA,KACxB,CAAA;AAAA,KACC,CAAC,MAAA,CAAO,EAAI,EAAA,SAAA,EAAW,YAAY,CAAC,CAAA,CAAA;AAEvC,EAAA,uBACG,GAAA,CAAA,KAAA,EAAA;AAAA,IACC,GAAK,EAAA,MAAA;AAAA,IACL,SAAW,EAAA,UAAA;AAAA,MACT,8CAAA;AAAA,MACA,SAAA;AAAA,KACF;AAAA,IACC,GAAG,KAAA;AAAA,IAEJ,QAAC,kBAAA,GAAA,CAAA,MAAA,EAAA;AAAA,MACC,MAAA;AAAA,MACA,YAAA,EAAY,WAAW,QAAW,GAAA,UAAA;AAAA,MAClC,OAAS,EAAA,iBAAA;AAAA,MACT,SAAU,EAAA,oCAAA;AAAA,MACV,YAAA,EAAc,WAAW,IAAO,GAAA,KAAA;AAAA,KAClC,CAAA;AAAA,GACF,CAAA,CAAA;AAEJ,CAAA;AAEA,SAAS,gBAAqC,GAAA;AAC5C,EAAM,MAAA,aAAA,GAAgB,WAAW,oBAAoB,CAAA,CAAA;AACrD,EAAA,IAAI,kBAAkB,IAAM,EAAA;AAC1B,IAAA,MAAM,IAAI,KAAA;AAAA,MACR,6EAAA;AAAA,KACF,CAAA;AAAA,GACF;AACA,EAAO,OAAA,aAAA,CAAA;AACT,CAAA;AAEA,SAAS,gBAAmB,GAAA;AAC1B,EAAM,MAAA,aAAA,GAAgB,WAAW,oBAAoB,CAAA,CAAA;AACrD,EAAA,IAAI,kBAAkB,IAAM,EAAA;AAC1B,IAAA,MAAM,IAAI,KAAA;AAAA,MACR,iEAAA;AAAA,KACF,CAAA;AAAA,GACF;AAEA,EAAO,OAAA,aAAA,CAAA;AACT;;;;"}
package/dist/index.d.mts CHANGED
@@ -77,7 +77,7 @@ interface FloatingThreadsProps<M extends BaseMetadata = DM> extends Omit<HTMLAtt
77
77
  }
78
78
  declare function FloatingThreads({ threads, components, ...props }: FloatingThreadsProps): react_jsx_runtime.JSX.Element | null;
79
79
 
80
- declare function getActiveBlockElement(editor: LexicalEditor): LexicalNode | null;
80
+ declare function isBlockNodeActive(editor: LexicalEditor, isActive: (node: LexicalNode) => boolean): boolean;
81
81
 
82
82
  declare function isTextFormatActive(editor: LexicalEditor, format: TextFormatType): boolean;
83
83
 
@@ -247,7 +247,7 @@ interface ToolbarBlockSelectorItem {
247
247
  * Whether this block element is currently active.
248
248
  * Set to `"default"` to display this item when no other item is active.
249
249
  */
250
- isActive: ((element: LexicalNode | null, editor: LexicalEditor) => boolean) | "default";
250
+ isActive: ((editor: LexicalEditor) => boolean) | "default";
251
251
  /**
252
252
  * A callback invoked when this item is selected.
253
253
  */
@@ -427,4 +427,4 @@ interface HistoryVersionPreviewProps extends ComponentPropsWithoutRef<"div"> {
427
427
  */
428
428
  declare const HistoryVersionPreview: react.ForwardRefExoticComponent<HistoryVersionPreviewProps & react.RefAttributes<HTMLDivElement>>;
429
429
 
430
- export { AnchoredThreads, AnchoredThreadsProps, FloatingComposer, FloatingComposerProps, FloatingThreads, FloatingThreadsProps, FloatingToolbar, FloatingToolbarProps, HistoryVersionPreview, HistoryVersionPreviewProps, LiveblocksPlugin, OPEN_FLOATING_COMPOSER_COMMAND, Toolbar, ToolbarBlockSelectorItem, ToolbarBlockSelectorProps, ToolbarButtonProps, ToolbarProps, ToolbarSeparatorProps, ToolbarToggleProps, getActiveBlockElement, isTextFormatActive, liveblocksConfig, useEditorStatus, useIsEditorReady, useIsThreadActive };
430
+ export { AnchoredThreads, AnchoredThreadsProps, FloatingComposer, FloatingComposerProps, FloatingThreads, FloatingThreadsProps, FloatingToolbar, FloatingToolbarProps, HistoryVersionPreview, HistoryVersionPreviewProps, LiveblocksPlugin, OPEN_FLOATING_COMPOSER_COMMAND, Toolbar, ToolbarBlockSelectorItem, ToolbarBlockSelectorProps, ToolbarButtonProps, ToolbarProps, ToolbarSeparatorProps, ToolbarToggleProps, isBlockNodeActive, isTextFormatActive, liveblocksConfig, useEditorStatus, useIsEditorReady, useIsThreadActive };
package/dist/index.d.ts CHANGED
@@ -77,7 +77,7 @@ interface FloatingThreadsProps<M extends BaseMetadata = DM> extends Omit<HTMLAtt
77
77
  }
78
78
  declare function FloatingThreads({ threads, components, ...props }: FloatingThreadsProps): react_jsx_runtime.JSX.Element | null;
79
79
 
80
- declare function getActiveBlockElement(editor: LexicalEditor): LexicalNode | null;
80
+ declare function isBlockNodeActive(editor: LexicalEditor, isActive: (node: LexicalNode) => boolean): boolean;
81
81
 
82
82
  declare function isTextFormatActive(editor: LexicalEditor, format: TextFormatType): boolean;
83
83
 
@@ -247,7 +247,7 @@ interface ToolbarBlockSelectorItem {
247
247
  * Whether this block element is currently active.
248
248
  * Set to `"default"` to display this item when no other item is active.
249
249
  */
250
- isActive: ((element: LexicalNode | null, editor: LexicalEditor) => boolean) | "default";
250
+ isActive: ((editor: LexicalEditor) => boolean) | "default";
251
251
  /**
252
252
  * A callback invoked when this item is selected.
253
253
  */
@@ -427,4 +427,4 @@ interface HistoryVersionPreviewProps extends ComponentPropsWithoutRef<"div"> {
427
427
  */
428
428
  declare const HistoryVersionPreview: react.ForwardRefExoticComponent<HistoryVersionPreviewProps & react.RefAttributes<HTMLDivElement>>;
429
429
 
430
- export { AnchoredThreads, AnchoredThreadsProps, FloatingComposer, FloatingComposerProps, FloatingThreads, FloatingThreadsProps, FloatingToolbar, FloatingToolbarProps, HistoryVersionPreview, HistoryVersionPreviewProps, LiveblocksPlugin, OPEN_FLOATING_COMPOSER_COMMAND, Toolbar, ToolbarBlockSelectorItem, ToolbarBlockSelectorProps, ToolbarButtonProps, ToolbarProps, ToolbarSeparatorProps, ToolbarToggleProps, getActiveBlockElement, isTextFormatActive, liveblocksConfig, useEditorStatus, useIsEditorReady, useIsThreadActive };
430
+ export { AnchoredThreads, AnchoredThreadsProps, FloatingComposer, FloatingComposerProps, FloatingThreads, FloatingThreadsProps, FloatingToolbar, FloatingToolbarProps, HistoryVersionPreview, HistoryVersionPreviewProps, LiveblocksPlugin, OPEN_FLOATING_COMPOSER_COMMAND, Toolbar, ToolbarBlockSelectorItem, ToolbarBlockSelectorProps, ToolbarButtonProps, ToolbarProps, ToolbarSeparatorProps, ToolbarToggleProps, isBlockNodeActive, isTextFormatActive, liveblocksConfig, useEditorStatus, useIsEditorReady, useIsThreadActive };
package/dist/index.js CHANGED
@@ -6,7 +6,7 @@ var anchoredThreads = require('./comments/anchored-threads.js');
6
6
  var commentPluginProvider = require('./comments/comment-plugin-provider.js');
7
7
  var floatingComposer = require('./comments/floating-composer.js');
8
8
  var floatingThreads = require('./comments/floating-threads.js');
9
- var getActiveBlockElement = require('./get-active-block-element.js');
9
+ var isBlockNodeActive = require('./is-block-node-active.js');
10
10
  var isTextFormatActive = require('./is-text-format-active.js');
11
11
  var liveblocksConfig = require('./liveblocks-config.js');
12
12
  var liveblocksPluginProvider = require('./liveblocks-plugin-provider.js');
@@ -21,7 +21,7 @@ exports.useIsThreadActive = commentPluginProvider.useIsThreadActive;
21
21
  exports.FloatingComposer = floatingComposer.FloatingComposer;
22
22
  exports.OPEN_FLOATING_COMPOSER_COMMAND = floatingComposer.OPEN_FLOATING_COMPOSER_COMMAND;
23
23
  exports.FloatingThreads = floatingThreads.FloatingThreads;
24
- exports.getActiveBlockElement = getActiveBlockElement.getActiveBlockElement;
24
+ exports.isBlockNodeActive = isBlockNodeActive.isBlockNodeActive;
25
25
  exports.isTextFormatActive = isTextFormatActive.isTextFormatActive;
26
26
  exports.liveblocksConfig = liveblocksConfig.liveblocksConfig;
27
27
  exports.LiveblocksPlugin = liveblocksPluginProvider.LiveblocksPlugin;
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":["../src/index.ts"],"sourcesContent":["import { detectDupes } from \"@liveblocks/core\";\n\nimport { PKG_FORMAT, PKG_NAME, PKG_VERSION } from \"./version\";\n\ndetectDupes(PKG_NAME, PKG_VERSION, PKG_FORMAT);\n\nexport type { AnchoredThreadsProps } from \"./comments/anchored-threads\";\nexport { AnchoredThreads } from \"./comments/anchored-threads\";\nexport { useIsThreadActive } from \"./comments/comment-plugin-provider\";\nexport type { FloatingComposerProps } from \"./comments/floating-composer\";\nexport {\n FloatingComposer,\n OPEN_FLOATING_COMPOSER_COMMAND,\n} from \"./comments/floating-composer\";\nexport type { FloatingThreadsProps } from \"./comments/floating-threads\";\nexport { FloatingThreads } from \"./comments/floating-threads\";\nexport { getActiveBlockElement } from \"./get-active-block-element\";\nexport { isTextFormatActive } from \"./is-text-format-active\";\nexport { liveblocksConfig } from \"./liveblocks-config\";\nexport {\n LiveblocksPlugin,\n useEditorStatus,\n useIsEditorReady,\n} from \"./liveblocks-plugin-provider\";\nexport type { FloatingToolbarProps } from \"./toolbar/floating-toolbar\";\nexport { FloatingToolbar } from \"./toolbar/floating-toolbar\";\nexport type {\n ToolbarBlockSelectorItem,\n ToolbarBlockSelectorProps,\n ToolbarButtonProps,\n ToolbarProps,\n ToolbarSeparatorProps,\n ToolbarToggleProps,\n} from \"./toolbar/toolbar\";\nexport { Toolbar } from \"./toolbar/toolbar\";\nexport type { HistoryVersionPreviewProps } from \"./version-history/history-version-preview\";\nexport { HistoryVersionPreview } from \"./version-history/history-version-preview\";\n"],"names":["detectDupes","PKG_NAME","PKG_VERSION","PKG_FORMAT"],"mappings":";;;;;;;;;;;;;;;;AAIAA,gBAAY,CAAAC,gBAAA,EAAUC,qBAAaC,kBAAU,CAAA;;;;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"index.js","sources":["../src/index.ts"],"sourcesContent":["import { detectDupes } from \"@liveblocks/core\";\n\nimport { PKG_FORMAT, PKG_NAME, PKG_VERSION } from \"./version\";\n\ndetectDupes(PKG_NAME, PKG_VERSION, PKG_FORMAT);\n\nexport type { AnchoredThreadsProps } from \"./comments/anchored-threads\";\nexport { AnchoredThreads } from \"./comments/anchored-threads\";\nexport { useIsThreadActive } from \"./comments/comment-plugin-provider\";\nexport type { FloatingComposerProps } from \"./comments/floating-composer\";\nexport {\n FloatingComposer,\n OPEN_FLOATING_COMPOSER_COMMAND,\n} from \"./comments/floating-composer\";\nexport type { FloatingThreadsProps } from \"./comments/floating-threads\";\nexport { FloatingThreads } from \"./comments/floating-threads\";\nexport { isBlockNodeActive } from \"./is-block-node-active\";\nexport { isTextFormatActive } from \"./is-text-format-active\";\nexport { liveblocksConfig } from \"./liveblocks-config\";\nexport {\n LiveblocksPlugin,\n useEditorStatus,\n useIsEditorReady,\n} from \"./liveblocks-plugin-provider\";\nexport type { FloatingToolbarProps } from \"./toolbar/floating-toolbar\";\nexport { FloatingToolbar } from \"./toolbar/floating-toolbar\";\nexport type {\n ToolbarBlockSelectorItem,\n ToolbarBlockSelectorProps,\n ToolbarButtonProps,\n ToolbarProps,\n ToolbarSeparatorProps,\n ToolbarToggleProps,\n} from \"./toolbar/toolbar\";\nexport { Toolbar } from \"./toolbar/toolbar\";\nexport type { HistoryVersionPreviewProps } from \"./version-history/history-version-preview\";\nexport { HistoryVersionPreview } from \"./version-history/history-version-preview\";\n"],"names":["detectDupes","PKG_NAME","PKG_VERSION","PKG_FORMAT"],"mappings":";;;;;;;;;;;;;;;;AAIAA,gBAAY,CAAAC,gBAAA,EAAUC,qBAAaC,kBAAU,CAAA;;;;;;;;;;;;;;;;;"}
package/dist/index.mjs CHANGED
@@ -4,7 +4,7 @@ export { AnchoredThreads } from './comments/anchored-threads.mjs';
4
4
  export { useIsThreadActive } from './comments/comment-plugin-provider.mjs';
5
5
  export { FloatingComposer, OPEN_FLOATING_COMPOSER_COMMAND } from './comments/floating-composer.mjs';
6
6
  export { FloatingThreads } from './comments/floating-threads.mjs';
7
- export { getActiveBlockElement } from './get-active-block-element.mjs';
7
+ export { isBlockNodeActive } from './is-block-node-active.mjs';
8
8
  export { isTextFormatActive } from './is-text-format-active.mjs';
9
9
  export { liveblocksConfig } from './liveblocks-config.mjs';
10
10
  export { LiveblocksPlugin, useEditorStatus, useIsEditorReady } from './liveblocks-plugin-provider.mjs';
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","sources":["../src/index.ts"],"sourcesContent":["import { detectDupes } from \"@liveblocks/core\";\n\nimport { PKG_FORMAT, PKG_NAME, PKG_VERSION } from \"./version\";\n\ndetectDupes(PKG_NAME, PKG_VERSION, PKG_FORMAT);\n\nexport type { AnchoredThreadsProps } from \"./comments/anchored-threads\";\nexport { AnchoredThreads } from \"./comments/anchored-threads\";\nexport { useIsThreadActive } from \"./comments/comment-plugin-provider\";\nexport type { FloatingComposerProps } from \"./comments/floating-composer\";\nexport {\n FloatingComposer,\n OPEN_FLOATING_COMPOSER_COMMAND,\n} from \"./comments/floating-composer\";\nexport type { FloatingThreadsProps } from \"./comments/floating-threads\";\nexport { FloatingThreads } from \"./comments/floating-threads\";\nexport { getActiveBlockElement } from \"./get-active-block-element\";\nexport { isTextFormatActive } from \"./is-text-format-active\";\nexport { liveblocksConfig } from \"./liveblocks-config\";\nexport {\n LiveblocksPlugin,\n useEditorStatus,\n useIsEditorReady,\n} from \"./liveblocks-plugin-provider\";\nexport type { FloatingToolbarProps } from \"./toolbar/floating-toolbar\";\nexport { FloatingToolbar } from \"./toolbar/floating-toolbar\";\nexport type {\n ToolbarBlockSelectorItem,\n ToolbarBlockSelectorProps,\n ToolbarButtonProps,\n ToolbarProps,\n ToolbarSeparatorProps,\n ToolbarToggleProps,\n} from \"./toolbar/toolbar\";\nexport { Toolbar } from \"./toolbar/toolbar\";\nexport type { HistoryVersionPreviewProps } from \"./version-history/history-version-preview\";\nexport { HistoryVersionPreview } from \"./version-history/history-version-preview\";\n"],"names":[],"mappings":";;;;;;;;;;;;;;AAIA,WAAY,CAAA,QAAA,EAAU,aAAa,UAAU,CAAA"}
1
+ {"version":3,"file":"index.mjs","sources":["../src/index.ts"],"sourcesContent":["import { detectDupes } from \"@liveblocks/core\";\n\nimport { PKG_FORMAT, PKG_NAME, PKG_VERSION } from \"./version\";\n\ndetectDupes(PKG_NAME, PKG_VERSION, PKG_FORMAT);\n\nexport type { AnchoredThreadsProps } from \"./comments/anchored-threads\";\nexport { AnchoredThreads } from \"./comments/anchored-threads\";\nexport { useIsThreadActive } from \"./comments/comment-plugin-provider\";\nexport type { FloatingComposerProps } from \"./comments/floating-composer\";\nexport {\n FloatingComposer,\n OPEN_FLOATING_COMPOSER_COMMAND,\n} from \"./comments/floating-composer\";\nexport type { FloatingThreadsProps } from \"./comments/floating-threads\";\nexport { FloatingThreads } from \"./comments/floating-threads\";\nexport { isBlockNodeActive } from \"./is-block-node-active\";\nexport { isTextFormatActive } from \"./is-text-format-active\";\nexport { liveblocksConfig } from \"./liveblocks-config\";\nexport {\n LiveblocksPlugin,\n useEditorStatus,\n useIsEditorReady,\n} from \"./liveblocks-plugin-provider\";\nexport type { FloatingToolbarProps } from \"./toolbar/floating-toolbar\";\nexport { FloatingToolbar } from \"./toolbar/floating-toolbar\";\nexport type {\n ToolbarBlockSelectorItem,\n ToolbarBlockSelectorProps,\n ToolbarButtonProps,\n ToolbarProps,\n ToolbarSeparatorProps,\n ToolbarToggleProps,\n} from \"./toolbar/toolbar\";\nexport { Toolbar } from \"./toolbar/toolbar\";\nexport type { HistoryVersionPreviewProps } from \"./version-history/history-version-preview\";\nexport { HistoryVersionPreview } from \"./version-history/history-version-preview\";\n"],"names":[],"mappings":";;;;;;;;;;;;;;AAIA,WAAY,CAAA,QAAA,EAAU,aAAa,UAAU,CAAA"}
@@ -0,0 +1,51 @@
1
+ 'use strict';
2
+
3
+ var utils = require('@lexical/utils');
4
+ var lexical = require('lexical');
5
+
6
+ function isParentRootOrShadowRoot(node) {
7
+ const parent = node.getParent();
8
+ return parent !== null && lexical.$isRootOrShadowRoot(parent);
9
+ }
10
+ const activeNodesByEditor = /* @__PURE__ */ new WeakMap();
11
+ function getActiveBlockNodes(editor) {
12
+ const currentState = editor.getEditorState();
13
+ return currentState.read(() => {
14
+ const selection = lexical.$getSelection();
15
+ if (!lexical.$isRangeSelection(selection)) {
16
+ activeNodesByEditor.delete(editor);
17
+ return [];
18
+ }
19
+ const cache = activeNodesByEditor.get(editor);
20
+ if (cache?.state === currentState) {
21
+ return cache.nodes;
22
+ }
23
+ const anchor = selection.anchor.getNode();
24
+ const focus = selection.focus.getNode();
25
+ const commonAncestor = anchor.getCommonAncestor(focus);
26
+ let activeNodes = [];
27
+ if (commonAncestor && !lexical.$isRootOrShadowRoot(commonAncestor)) {
28
+ const activeNode = isParentRootOrShadowRoot(commonAncestor) ? commonAncestor : utils.$findMatchingParent(commonAncestor, isParentRootOrShadowRoot);
29
+ if (activeNode) {
30
+ activeNodes = [activeNode];
31
+ }
32
+ } else {
33
+ activeNodes = selection.getNodes().filter((node) => lexical.$isRootOrShadowRoot(node.getParent()));
34
+ }
35
+ activeNodesByEditor.set(editor, {
36
+ state: currentState,
37
+ nodes: activeNodes
38
+ });
39
+ return activeNodes;
40
+ });
41
+ }
42
+ function isBlockNodeActive(editor, isActive) {
43
+ const activeNodes = getActiveBlockNodes(editor);
44
+ if (activeNodes.length === 0) {
45
+ return false;
46
+ }
47
+ return activeNodes.every(isActive);
48
+ }
49
+
50
+ exports.isBlockNodeActive = isBlockNodeActive;
51
+ //# sourceMappingURL=is-block-node-active.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"is-block-node-active.js","sources":["../src/is-block-node-active.ts"],"sourcesContent":["import { $findMatchingParent } from \"@lexical/utils\";\nimport type { EditorState, LexicalEditor, LexicalNode } from \"lexical\";\nimport { $getSelection, $isRangeSelection, $isRootOrShadowRoot } from \"lexical\";\n\nfunction isParentRootOrShadowRoot(node: LexicalNode) {\n const parent = node.getParent();\n\n return parent !== null && $isRootOrShadowRoot(parent);\n}\n\nconst activeNodesByEditor = new WeakMap<\n LexicalEditor,\n {\n state: EditorState;\n nodes: LexicalNode[];\n }\n>();\n\nfunction getActiveBlockNodes(editor: LexicalEditor) {\n const currentState = editor.getEditorState();\n\n return currentState.read(() => {\n const selection = $getSelection();\n\n if (!$isRangeSelection(selection)) {\n activeNodesByEditor.delete(editor);\n\n return [];\n }\n\n const cache = activeNodesByEditor.get(editor);\n\n if (cache?.state === currentState) {\n return cache.nodes;\n }\n\n const anchor = selection.anchor.getNode();\n const focus = selection.focus.getNode();\n const commonAncestor = anchor.getCommonAncestor(focus);\n\n let activeNodes: LexicalNode[] = [];\n\n if (commonAncestor && !$isRootOrShadowRoot(commonAncestor)) {\n const activeNode = isParentRootOrShadowRoot(commonAncestor)\n ? commonAncestor\n : $findMatchingParent(commonAncestor, isParentRootOrShadowRoot);\n\n if (activeNode) {\n activeNodes = [activeNode];\n }\n } else {\n activeNodes = selection\n .getNodes()\n .filter((node) => $isRootOrShadowRoot(node.getParent()));\n }\n\n activeNodesByEditor.set(editor, {\n state: currentState,\n nodes: activeNodes,\n });\n\n return activeNodes;\n });\n}\n\nexport function isBlockNodeActive(\n editor: LexicalEditor,\n isActive: (node: LexicalNode) => boolean\n): boolean {\n const activeNodes = getActiveBlockNodes(editor);\n\n if (activeNodes.length === 0) {\n return false;\n }\n\n return activeNodes.every(isActive);\n}\n"],"names":["$isRootOrShadowRoot","$getSelection","$isRangeSelection","$findMatchingParent"],"mappings":";;;;;AAIA,SAAS,yBAAyB,IAAmB,EAAA;AACnD,EAAM,MAAA,MAAA,GAAS,KAAK,SAAU,EAAA,CAAA;AAE9B,EAAO,OAAA,MAAA,KAAW,IAAQ,IAAAA,2BAAA,CAAoB,MAAM,CAAA,CAAA;AACtD,CAAA;AAEA,MAAM,mBAAA,uBAA0B,OAM9B,EAAA,CAAA;AAEF,SAAS,oBAAoB,MAAuB,EAAA;AAClD,EAAM,MAAA,YAAA,GAAe,OAAO,cAAe,EAAA,CAAA;AAE3C,EAAO,OAAA,YAAA,CAAa,KAAK,MAAM;AAC7B,IAAA,MAAM,YAAYC,qBAAc,EAAA,CAAA;AAEhC,IAAI,IAAA,CAACC,yBAAkB,CAAA,SAAS,CAAG,EAAA;AACjC,MAAA,mBAAA,CAAoB,OAAO,MAAM,CAAA,CAAA;AAEjC,MAAA,OAAO,EAAC,CAAA;AAAA,KACV;AAEA,IAAM,MAAA,KAAA,GAAQ,mBAAoB,CAAA,GAAA,CAAI,MAAM,CAAA,CAAA;AAE5C,IAAI,IAAA,KAAA,EAAO,UAAU,YAAc,EAAA;AACjC,MAAA,OAAO,KAAM,CAAA,KAAA,CAAA;AAAA,KACf;AAEA,IAAM,MAAA,MAAA,GAAS,SAAU,CAAA,MAAA,CAAO,OAAQ,EAAA,CAAA;AACxC,IAAM,MAAA,KAAA,GAAQ,SAAU,CAAA,KAAA,CAAM,OAAQ,EAAA,CAAA;AACtC,IAAM,MAAA,cAAA,GAAiB,MAAO,CAAA,iBAAA,CAAkB,KAAK,CAAA,CAAA;AAErD,IAAA,IAAI,cAA6B,EAAC,CAAA;AAElC,IAAA,IAAI,cAAkB,IAAA,CAACF,2BAAoB,CAAA,cAAc,CAAG,EAAA;AAC1D,MAAA,MAAM,aAAa,wBAAyB,CAAA,cAAc,IACtD,cACA,GAAAG,yBAAA,CAAoB,gBAAgB,wBAAwB,CAAA,CAAA;AAEhE,MAAA,IAAI,UAAY,EAAA;AACd,QAAA,WAAA,GAAc,CAAC,UAAU,CAAA,CAAA;AAAA,OAC3B;AAAA,KACK,MAAA;AACL,MAAc,WAAA,GAAA,SAAA,CACX,QAAS,EAAA,CACT,MAAO,CAAA,CAAC,SAASH,2BAAoB,CAAA,IAAA,CAAK,SAAU,EAAC,CAAC,CAAA,CAAA;AAAA,KAC3D;AAEA,IAAA,mBAAA,CAAoB,IAAI,MAAQ,EAAA;AAAA,MAC9B,KAAO,EAAA,YAAA;AAAA,MACP,KAAO,EAAA,WAAA;AAAA,KACR,CAAA,CAAA;AAED,IAAO,OAAA,WAAA,CAAA;AAAA,GACR,CAAA,CAAA;AACH,CAAA;AAEgB,SAAA,iBAAA,CACd,QACA,QACS,EAAA;AACT,EAAM,MAAA,WAAA,GAAc,oBAAoB,MAAM,CAAA,CAAA;AAE9C,EAAI,IAAA,WAAA,CAAY,WAAW,CAAG,EAAA;AAC5B,IAAO,OAAA,KAAA,CAAA;AAAA,GACT;AAEA,EAAO,OAAA,WAAA,CAAY,MAAM,QAAQ,CAAA,CAAA;AACnC;;;;"}
@@ -0,0 +1,49 @@
1
+ import { $findMatchingParent } from '@lexical/utils';
2
+ import { $isRootOrShadowRoot, $getSelection, $isRangeSelection } from 'lexical';
3
+
4
+ function isParentRootOrShadowRoot(node) {
5
+ const parent = node.getParent();
6
+ return parent !== null && $isRootOrShadowRoot(parent);
7
+ }
8
+ const activeNodesByEditor = /* @__PURE__ */ new WeakMap();
9
+ function getActiveBlockNodes(editor) {
10
+ const currentState = editor.getEditorState();
11
+ return currentState.read(() => {
12
+ const selection = $getSelection();
13
+ if (!$isRangeSelection(selection)) {
14
+ activeNodesByEditor.delete(editor);
15
+ return [];
16
+ }
17
+ const cache = activeNodesByEditor.get(editor);
18
+ if (cache?.state === currentState) {
19
+ return cache.nodes;
20
+ }
21
+ const anchor = selection.anchor.getNode();
22
+ const focus = selection.focus.getNode();
23
+ const commonAncestor = anchor.getCommonAncestor(focus);
24
+ let activeNodes = [];
25
+ if (commonAncestor && !$isRootOrShadowRoot(commonAncestor)) {
26
+ const activeNode = isParentRootOrShadowRoot(commonAncestor) ? commonAncestor : $findMatchingParent(commonAncestor, isParentRootOrShadowRoot);
27
+ if (activeNode) {
28
+ activeNodes = [activeNode];
29
+ }
30
+ } else {
31
+ activeNodes = selection.getNodes().filter((node) => $isRootOrShadowRoot(node.getParent()));
32
+ }
33
+ activeNodesByEditor.set(editor, {
34
+ state: currentState,
35
+ nodes: activeNodes
36
+ });
37
+ return activeNodes;
38
+ });
39
+ }
40
+ function isBlockNodeActive(editor, isActive) {
41
+ const activeNodes = getActiveBlockNodes(editor);
42
+ if (activeNodes.length === 0) {
43
+ return false;
44
+ }
45
+ return activeNodes.every(isActive);
46
+ }
47
+
48
+ export { isBlockNodeActive };
49
+ //# sourceMappingURL=is-block-node-active.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"is-block-node-active.mjs","sources":["../src/is-block-node-active.ts"],"sourcesContent":["import { $findMatchingParent } from \"@lexical/utils\";\nimport type { EditorState, LexicalEditor, LexicalNode } from \"lexical\";\nimport { $getSelection, $isRangeSelection, $isRootOrShadowRoot } from \"lexical\";\n\nfunction isParentRootOrShadowRoot(node: LexicalNode) {\n const parent = node.getParent();\n\n return parent !== null && $isRootOrShadowRoot(parent);\n}\n\nconst activeNodesByEditor = new WeakMap<\n LexicalEditor,\n {\n state: EditorState;\n nodes: LexicalNode[];\n }\n>();\n\nfunction getActiveBlockNodes(editor: LexicalEditor) {\n const currentState = editor.getEditorState();\n\n return currentState.read(() => {\n const selection = $getSelection();\n\n if (!$isRangeSelection(selection)) {\n activeNodesByEditor.delete(editor);\n\n return [];\n }\n\n const cache = activeNodesByEditor.get(editor);\n\n if (cache?.state === currentState) {\n return cache.nodes;\n }\n\n const anchor = selection.anchor.getNode();\n const focus = selection.focus.getNode();\n const commonAncestor = anchor.getCommonAncestor(focus);\n\n let activeNodes: LexicalNode[] = [];\n\n if (commonAncestor && !$isRootOrShadowRoot(commonAncestor)) {\n const activeNode = isParentRootOrShadowRoot(commonAncestor)\n ? commonAncestor\n : $findMatchingParent(commonAncestor, isParentRootOrShadowRoot);\n\n if (activeNode) {\n activeNodes = [activeNode];\n }\n } else {\n activeNodes = selection\n .getNodes()\n .filter((node) => $isRootOrShadowRoot(node.getParent()));\n }\n\n activeNodesByEditor.set(editor, {\n state: currentState,\n nodes: activeNodes,\n });\n\n return activeNodes;\n });\n}\n\nexport function isBlockNodeActive(\n editor: LexicalEditor,\n isActive: (node: LexicalNode) => boolean\n): boolean {\n const activeNodes = getActiveBlockNodes(editor);\n\n if (activeNodes.length === 0) {\n return false;\n }\n\n return activeNodes.every(isActive);\n}\n"],"names":[],"mappings":";;;AAIA,SAAS,yBAAyB,IAAmB,EAAA;AACnD,EAAM,MAAA,MAAA,GAAS,KAAK,SAAU,EAAA,CAAA;AAE9B,EAAO,OAAA,MAAA,KAAW,IAAQ,IAAA,mBAAA,CAAoB,MAAM,CAAA,CAAA;AACtD,CAAA;AAEA,MAAM,mBAAA,uBAA0B,OAM9B,EAAA,CAAA;AAEF,SAAS,oBAAoB,MAAuB,EAAA;AAClD,EAAM,MAAA,YAAA,GAAe,OAAO,cAAe,EAAA,CAAA;AAE3C,EAAO,OAAA,YAAA,CAAa,KAAK,MAAM;AAC7B,IAAA,MAAM,YAAY,aAAc,EAAA,CAAA;AAEhC,IAAI,IAAA,CAAC,iBAAkB,CAAA,SAAS,CAAG,EAAA;AACjC,MAAA,mBAAA,CAAoB,OAAO,MAAM,CAAA,CAAA;AAEjC,MAAA,OAAO,EAAC,CAAA;AAAA,KACV;AAEA,IAAM,MAAA,KAAA,GAAQ,mBAAoB,CAAA,GAAA,CAAI,MAAM,CAAA,CAAA;AAE5C,IAAI,IAAA,KAAA,EAAO,UAAU,YAAc,EAAA;AACjC,MAAA,OAAO,KAAM,CAAA,KAAA,CAAA;AAAA,KACf;AAEA,IAAM,MAAA,MAAA,GAAS,SAAU,CAAA,MAAA,CAAO,OAAQ,EAAA,CAAA;AACxC,IAAM,MAAA,KAAA,GAAQ,SAAU,CAAA,KAAA,CAAM,OAAQ,EAAA,CAAA;AACtC,IAAM,MAAA,cAAA,GAAiB,MAAO,CAAA,iBAAA,CAAkB,KAAK,CAAA,CAAA;AAErD,IAAA,IAAI,cAA6B,EAAC,CAAA;AAElC,IAAA,IAAI,cAAkB,IAAA,CAAC,mBAAoB,CAAA,cAAc,CAAG,EAAA;AAC1D,MAAA,MAAM,aAAa,wBAAyB,CAAA,cAAc,IACtD,cACA,GAAA,mBAAA,CAAoB,gBAAgB,wBAAwB,CAAA,CAAA;AAEhE,MAAA,IAAI,UAAY,EAAA;AACd,QAAA,WAAA,GAAc,CAAC,UAAU,CAAA,CAAA;AAAA,OAC3B;AAAA,KACK,MAAA;AACL,MAAc,WAAA,GAAA,SAAA,CACX,QAAS,EAAA,CACT,MAAO,CAAA,CAAC,SAAS,mBAAoB,CAAA,IAAA,CAAK,SAAU,EAAC,CAAC,CAAA,CAAA;AAAA,KAC3D;AAEA,IAAA,mBAAA,CAAoB,IAAI,MAAQ,EAAA;AAAA,MAC9B,KAAO,EAAA,YAAA;AAAA,MACP,KAAO,EAAA,WAAA;AAAA,KACR,CAAA,CAAA;AAED,IAAO,OAAA,WAAA,CAAA;AAAA,GACR,CAAA,CAAA;AACH,CAAA;AAEgB,SAAA,iBAAA,CACd,QACA,QACS,EAAA;AACT,EAAM,MAAA,WAAA,GAAc,oBAAoB,MAAM,CAAA,CAAA;AAE9C,EAAI,IAAA,WAAA,CAAY,WAAW,CAAG,EAAA;AAC5B,IAAO,OAAA,KAAA,CAAA;AAAA,GACT;AAEA,EAAO,OAAA,WAAA,CAAY,MAAM,QAAQ,CAAA,CAAA;AACnC;;;;"}
@@ -14,6 +14,7 @@ var commentPluginProvider = require('./comments/comment-plugin-provider.js');
14
14
  var threadMarkNode = require('./comments/thread-mark-node.js');
15
15
  var mentionNode = require('./mentions/mention-node.js');
16
16
  var mentionPlugin = require('./mentions/mention-plugin.js');
17
+ var useRootElement = require('./use-root-element.js');
17
18
 
18
19
  const providersMap = /* @__PURE__ */ new Map();
19
20
  function useEditorStatus() {
@@ -118,7 +119,7 @@ const LiveblocksPlugin = ({
118
119
  },
119
120
  [room]
120
121
  );
121
- const root = useRootElement();
122
+ const root = useRootElement.useRootElement();
122
123
  _private.useLayoutEffect(() => {
123
124
  if (root === null)
124
125
  return;
@@ -160,22 +161,8 @@ const LiveblocksPlugin = ({
160
161
  ]
161
162
  });
162
163
  };
163
- function useRootElement() {
164
- const [editor] = LexicalComposerContext.useLexicalComposerContext();
165
- const subscribe = react.useCallback(
166
- (onStoreChange) => {
167
- return editor.registerRootListener(onStoreChange);
168
- },
169
- [editor]
170
- );
171
- const getSnapshot = react.useCallback(() => {
172
- return editor.getRootElement();
173
- }, [editor]);
174
- return react.useSyncExternalStore(subscribe, getSnapshot, getSnapshot);
175
- }
176
164
 
177
165
  exports.LiveblocksPlugin = LiveblocksPlugin;
178
166
  exports.useEditorStatus = useEditorStatus;
179
167
  exports.useIsEditorReady = useIsEditorReady;
180
- exports.useRootElement = useRootElement;
181
168
  //# sourceMappingURL=liveblocks-plugin-provider.js.map
@@ -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 { nn, 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 { LiveblocksYjsProvider } from \"@liveblocks/yjs\";\nimport type { MutableRefObject, ReactNode } from \"react\";\nimport {\n useCallback,\n useEffect,\n useRef,\n useState,\n useSyncExternalStore,\n} from \"react\";\nimport { Doc } from \"yjs\";\n\nimport { CommentPluginProvider } from \"./comments/comment-plugin-provider\";\nimport { ThreadMarkNode } from \"./comments/thread-mark-node\";\nimport { MentionNode } from \"./mentions/mention-node\";\nimport { MentionPlugin } from \"./mentions/mention-plugin\";\n\n// TODO: Replace by ref once I understand why useRef is not stable (?!)\nconst providersMap = new Map<\n string,\n LiveblocksYjsProvider<never, never, never, never, never>\n>();\n\nexport type EditorStatus =\n /* The editor state is not loaded and has not been requested. */\n | \"not-loaded\"\n /* The editor state is loading from Liveblocks servers */\n | \"loading\"\n /**\n * Not working yet! Will be available in a future release.\n * Some editor state modifications has not been acknowledged yet by the server\n */\n | \"synchronizing\"\n /* The editor state is sync with Liveblocks servers */\n | \"synchronized\";\n\n/**\n * Get the storage status.\n *\n * - `not-loaded`: Initial state when entering the room.\n * - `loading`: Once the editor state has been requested by LiveblocksPlugin.\n * - `synchronizing`: Not working yet! Will be available in a future release.\n * - `synchronized`: The editor state is sync with Liveblocks servers.\n *\n * @deprecated Prefer `useIsEditorReady` or `useSyncStatus` (from @liveblocks/react)\n */\nexport function useEditorStatus(): EditorStatus {\n const provider = useYjsProvider();\n\n const subscribe = useCallback(\n (onStoreChange: () => void) => {\n if (provider === undefined) return () => {};\n provider.on(\"status\", onStoreChange);\n return () => {\n provider.off(\"status\", onStoreChange);\n };\n },\n [provider]\n );\n\n const getSnapshot = useCallback(() => {\n if (provider === undefined) {\n return \"not-loaded\";\n }\n return provider.getStatus();\n }, [provider]);\n\n return useSyncExternalStore(subscribe, getSnapshot, getSnapshot);\n}\n\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 const previousRoomIdRef = useRef<string | null>(null);\n\n if (!editor.hasNodes([ThreadMarkNode, MentionNode])) {\n throw new Error(\n \"LiveblocksPlugin requires Lexical configuration to be wrapped in the `liveblocksConfig(options)` function. For more information: https://liveblocks.io/docs/api-reference/liveblocks-react-lexical#liveblocksConfig\"\n );\n }\n\n const [containerRef, setContainerRef] = useState<\n MutableRefObject<HTMLDivElement | null> | undefined\n >(undefined);\n\n const {\n refs: { setReference, setFloating },\n strategy,\n x,\n y,\n } = useFloating({\n strategy: \"fixed\",\n placement: \"bottom\",\n whileElementsMounted: (...args) => {\n return autoUpdate(...args, {\n animationFrame: true,\n });\n },\n });\n\n // Warn users if initialConfig.editorState, set on the composer, is not null\n useEffect(() => {\n // only in dev mode\n if (process.env.NODE_ENV !== \"production\") {\n // A user should not even be set an emptyState, but when passing null, getEditorState still has initial empty state\n if (!editor.getEditorState().isEmpty()) {\n console.warn(\n \"Warning: LiveblocksPlugin: editorState in initialConfig detected, but must be null.\"\n );\n }\n }\n\n // we know editor is already defined as we're inside LexicalComposer, and we only want this running the first time\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n 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 // Destroy previously used provider to avoid memory leaks\n // TODO: Find a way to destroy the last used provider on unmount (while working with StrictMode)\n if (\n previousRoomIdRef.current !== null &&\n previousRoomIdRef.current !== id\n ) {\n const previousProvider = providersMap.get(id);\n if (previousProvider !== undefined) {\n previousProvider.destroy();\n }\n }\n\n let doc = yjsDocMap.get(id);\n\n if (doc === undefined) {\n doc = new Doc();\n const provider = new LiveblocksYjsProvider(room, doc);\n yjsDocMap.set(id, doc);\n providersMap.set(id, provider);\n }\n\n return nn(\n providersMap.get(id),\n \"Internal error. Should never happen\"\n ) as Provider;\n },\n [room]\n );\n\n const root = useRootElement();\n\n useLayoutEffect(() => {\n if (root === null) return;\n setReference({\n getBoundingClientRect: () => root.getBoundingClientRect(),\n });\n }, [setReference, root]);\n\n const handleFloatingRef = useCallback(\n (node: HTMLDivElement) => {\n setFloating(node);\n setContainerRef({ current: node });\n },\n [setFloating, setContainerRef]\n );\n\n return (\n <>\n <div\n ref={handleFloatingRef}\n style={{\n position: strategy,\n top: 0,\n left: 0,\n transform: `translate3d(${Math.round(x)}px, ${Math.round(y)}px, 0)`,\n minWidth: \"max-content\",\n }}\n />\n\n {self && (\n <CollaborationPlugin\n // Setting the key allows us to reset the internal Y.doc used by useYjsCollaboration\n // without implementing `reload` event\n key={room.id}\n id={room.id}\n providerFactory={providerFactory}\n username={self.info?.name ?? \"\"} // use empty string to prevent random name\n cursorColor={self.info?.color as string | undefined}\n cursorsContainerRef={containerRef}\n shouldBootstrap={true}\n />\n )}\n\n {isResolveMentionSuggestionsDefined && <MentionPlugin />}\n <CommentPluginProvider>{children}</CommentPluginProvider>\n </>\n );\n};\n\nexport function useRootElement(): HTMLElement | null {\n const [editor] = useLexicalComposerContext();\n\n const subscribe = useCallback(\n (onStoreChange: () => void) => {\n return editor.registerRootListener(onStoreChange);\n },\n [editor]\n );\n\n const getSnapshot = useCallback(() => {\n return editor.getRootElement();\n }, [editor]);\n\n return useSyncExternalStore(subscribe, getSnapshot, getSnapshot);\n}\n"],"names":["useYjsProvider","useCallback","useSyncExternalStore","useResolveMentionSuggestions","useLexicalComposerContext","useRoom","useRef","ThreadMarkNode","MentionNode","useState","useFloating","autoUpdate","useEffect","useReportTextEditor","TextEditorType","useSelf","Doc","LiveblocksYjsProvider","nn","useLayoutEffect","jsxs","Fragment","jsx","CollaborationPlugin","MentionPlugin","CommentPluginProvider"],"mappings":"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"}
1
+ {"version":3,"file":"liveblocks-plugin-provider.js","sources":["../src/liveblocks-plugin-provider.tsx"],"sourcesContent":["import { autoUpdate, useFloating } from \"@floating-ui/react-dom\";\nimport { CollaborationPlugin } from \"@lexical/react/LexicalCollaborationPlugin\";\nimport { useLexicalComposerContext } from \"@lexical/react/LexicalComposerContext\";\nimport type { Provider } from \"@lexical/yjs\";\nimport { nn, 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 { LiveblocksYjsProvider } from \"@liveblocks/yjs\";\nimport type { MutableRefObject, ReactNode } from \"react\";\nimport {\n useCallback,\n useEffect,\n useRef,\n useState,\n useSyncExternalStore,\n} from \"react\";\nimport { Doc } from \"yjs\";\n\nimport { CommentPluginProvider } from \"./comments/comment-plugin-provider\";\nimport { ThreadMarkNode } from \"./comments/thread-mark-node\";\nimport { MentionNode } from \"./mentions/mention-node\";\nimport { MentionPlugin } from \"./mentions/mention-plugin\";\nimport { useRootElement } from \"./use-root-element\";\n\n// TODO: Replace by ref once I understand why useRef is not stable (?!)\nconst providersMap = new Map<\n string,\n LiveblocksYjsProvider<never, never, never, never, never>\n>();\n\nexport type EditorStatus =\n /* The editor state is not loaded and has not been requested. */\n | \"not-loaded\"\n /* The editor state is loading from Liveblocks servers */\n | \"loading\"\n /**\n * Not working yet! Will be available in a future release.\n * Some editor state modifications has not been acknowledged yet by the server\n */\n | \"synchronizing\"\n /* The editor state is sync with Liveblocks servers */\n | \"synchronized\";\n\n/**\n * Get the storage status.\n *\n * - `not-loaded`: Initial state when entering the room.\n * - `loading`: Once the editor state has been requested by LiveblocksPlugin.\n * - `synchronizing`: Not working yet! Will be available in a future release.\n * - `synchronized`: The editor state is sync with Liveblocks servers.\n *\n * @deprecated Prefer `useIsEditorReady` or `useSyncStatus` (from @liveblocks/react)\n */\nexport function useEditorStatus(): EditorStatus {\n const provider = useYjsProvider();\n\n const subscribe = useCallback(\n (onStoreChange: () => void) => {\n if (provider === undefined) return () => {};\n provider.on(\"status\", onStoreChange);\n return () => {\n provider.off(\"status\", onStoreChange);\n };\n },\n [provider]\n );\n\n const getSnapshot = useCallback(() => {\n if (provider === undefined) {\n return \"not-loaded\";\n }\n return provider.getStatus();\n }, [provider]);\n\n return useSyncExternalStore(subscribe, getSnapshot, getSnapshot);\n}\n\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 const previousRoomIdRef = useRef<string | null>(null);\n\n if (!editor.hasNodes([ThreadMarkNode, MentionNode])) {\n throw new Error(\n \"LiveblocksPlugin requires Lexical configuration to be wrapped in the `liveblocksConfig(options)` function. For more information: https://liveblocks.io/docs/api-reference/liveblocks-react-lexical#liveblocksConfig\"\n );\n }\n\n const [containerRef, setContainerRef] = useState<\n MutableRefObject<HTMLDivElement | null> | undefined\n >(undefined);\n\n const {\n refs: { setReference, setFloating },\n strategy,\n x,\n y,\n } = useFloating({\n strategy: \"fixed\",\n placement: \"bottom\",\n whileElementsMounted: (...args) => {\n return autoUpdate(...args, {\n animationFrame: true,\n });\n },\n });\n\n // Warn users if initialConfig.editorState, set on the composer, is not null\n useEffect(() => {\n // only in dev mode\n if (process.env.NODE_ENV !== \"production\") {\n // A user should not even be set an emptyState, but when passing null, getEditorState still has initial empty state\n if (!editor.getEditorState().isEmpty()) {\n console.warn(\n \"Warning: LiveblocksPlugin: editorState in initialConfig detected, but must be null.\"\n );\n }\n }\n\n // we know editor is already defined as we're inside LexicalComposer, and we only want this running the first time\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n 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 // Destroy previously used provider to avoid memory leaks\n // TODO: Find a way to destroy the last used provider on unmount (while working with StrictMode)\n if (\n previousRoomIdRef.current !== null &&\n previousRoomIdRef.current !== id\n ) {\n const previousProvider = providersMap.get(id);\n if (previousProvider !== undefined) {\n previousProvider.destroy();\n }\n }\n\n let doc = yjsDocMap.get(id);\n\n if (doc === undefined) {\n doc = new Doc();\n const provider = new LiveblocksYjsProvider(room, doc);\n yjsDocMap.set(id, doc);\n providersMap.set(id, provider);\n }\n\n return nn(\n providersMap.get(id),\n \"Internal error. Should never happen\"\n ) as Provider;\n },\n [room]\n );\n\n const root = useRootElement();\n\n useLayoutEffect(() => {\n if (root === null) return;\n setReference({\n getBoundingClientRect: () => root.getBoundingClientRect(),\n });\n }, [setReference, root]);\n\n const handleFloatingRef = useCallback(\n (node: HTMLDivElement) => {\n setFloating(node);\n setContainerRef({ current: node });\n },\n [setFloating, setContainerRef]\n );\n\n return (\n <>\n <div\n ref={handleFloatingRef}\n style={{\n position: strategy,\n top: 0,\n left: 0,\n transform: `translate3d(${Math.round(x)}px, ${Math.round(y)}px, 0)`,\n minWidth: \"max-content\",\n }}\n />\n\n {self && (\n <CollaborationPlugin\n // Setting the key allows us to reset the internal Y.doc used by useYjsCollaboration\n // without implementing `reload` event\n key={room.id}\n id={room.id}\n providerFactory={providerFactory}\n username={self.info?.name ?? \"\"} // use empty string to prevent random name\n cursorColor={self.info?.color as string | undefined}\n cursorsContainerRef={containerRef}\n shouldBootstrap={true}\n />\n )}\n\n {isResolveMentionSuggestionsDefined && <MentionPlugin />}\n <CommentPluginProvider>{children}</CommentPluginProvider>\n </>\n );\n};\n"],"names":["useYjsProvider","useCallback","useSyncExternalStore","useResolveMentionSuggestions","useLexicalComposerContext","useRoom","useRef","ThreadMarkNode","MentionNode","useState","useFloating","autoUpdate","useEffect","useReportTextEditor","TextEditorType","useSelf","Doc","LiveblocksYjsProvider","nn","useRootElement","useLayoutEffect","jsxs","Fragment","jsx","CollaborationPlugin","MentionPlugin","CommentPluginProvider"],"mappings":";;;;;;;;;;;;;;;;;;AA8BA,MAAM,YAAA,uBAAmB,GAGvB,EAAA,CAAA;AAyBK,SAAS,eAAgC,GAAA;AAC9C,EAAA,MAAM,WAAWA,uBAAe,EAAA,CAAA;AAEhC,EAAA,MAAM,SAAY,GAAAC,iBAAA;AAAA,IAChB,CAAC,aAA8B,KAAA;AAC7B,MAAA,IAAI,QAAa,KAAA,KAAA,CAAA;AAAW,QAAA,OAAO,MAAM;AAAA,SAAC,CAAA;AAC1C,MAAS,QAAA,CAAA,EAAA,CAAG,UAAU,aAAa,CAAA,CAAA;AACnC,MAAA,OAAO,MAAM;AACX,QAAS,QAAA,CAAA,GAAA,CAAI,UAAU,aAAa,CAAA,CAAA;AAAA,OACtC,CAAA;AAAA,KACF;AAAA,IACA,CAAC,QAAQ,CAAA;AAAA,GACX,CAAA;AAEA,EAAM,MAAA,WAAA,GAAcA,kBAAY,MAAM;AACpC,IAAA,IAAI,aAAa,KAAW,CAAA,EAAA;AAC1B,MAAO,OAAA,YAAA,CAAA;AAAA,KACT;AACA,IAAA,OAAO,SAAS,SAAU,EAAA,CAAA;AAAA,GAC5B,EAAG,CAAC,QAAQ,CAAC,CAAA,CAAA;AAEb,EAAO,OAAAC,0BAAA,CAAqB,SAAW,EAAA,WAAA,EAAa,WAAW,CAAA,CAAA;AACjE,CAAA;AAMO,SAAS,gBAA4B,GAAA;AAC1C,EAAA,MAAM,cAAcF,uBAAe,EAAA,CAAA;AAEnC,EAAM,MAAA,WAAA,GAAcC,kBAAY,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,GAAAA,iBAAA;AAAA,IAChB,CAAC,QAAyB,KAAA;AACxB,MAAA,IAAI,WAAgB,KAAA,KAAA,CAAA;AAAW,QAAA,OAAO,MAAM;AAAA,SAAC,CAAA;AAC7C,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,OAAAC,0BAAA,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,GACJC,uCAAmC,KAAA,KAAA,CAAA,CAAA;AACrC,EAAM,MAAA,CAAC,MAAM,CAAA,GAAIC,gDAA0B,EAAA,CAAA;AAC3C,EAAA,MAAM,OAAOC,eAAQ,EAAA,CAAA;AACrB,EAAM,MAAA,iBAAA,GAAoBC,aAAsB,IAAI,CAAA,CAAA;AAEpD,EAAA,IAAI,CAAC,MAAO,CAAA,QAAA,CAAS,CAACC,6BAAgB,EAAAC,uBAAW,CAAC,CAAG,EAAA;AACnD,IAAA,MAAM,IAAI,KAAA;AAAA,MACR,qNAAA;AAAA,KACF,CAAA;AAAA,GACF;AAEA,EAAA,MAAM,CAAC,YAAA,EAAc,eAAe,CAAA,GAAIC,eAEtC,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,MACEC,oBAAY,CAAA;AAAA,IACd,QAAU,EAAA,OAAA;AAAA,IACV,SAAW,EAAA,QAAA;AAAA,IACX,oBAAA,EAAsB,IAAI,IAAS,KAAA;AACjC,MAAO,OAAAC,mBAAA,CAAW,GAAG,IAAM,EAAA;AAAA,QACzB,cAAgB,EAAA,IAAA;AAAA,OACjB,CAAA,CAAA;AAAA,KACH;AAAA,GACD,CAAA,CAAA;AAGD,EAAAC,eAAA,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,EAAoBC,4BAAA,CAAAC,mBAAA,CAAe,SAAS,MAAM,CAAA,CAAA;AAGlD,EAAA,MAAM,OAAOC,eAAQ,EAAA,CAAA;AAErB,EAAA,MAAM,eAAkB,GAAAd,iBAAA;AAAA,IACtB,CAAC,IAAY,SAA0C,KAAA;AAGrD,MAAA,IACE,iBAAkB,CAAA,OAAA,KAAY,IAC9B,IAAA,iBAAA,CAAkB,YAAY,EAC9B,EAAA;AACA,QAAM,MAAA,gBAAA,GAAmB,YAAa,CAAA,GAAA,CAAI,EAAE,CAAA,CAAA;AAC5C,QAAA,IAAI,qBAAqB,KAAW,CAAA,EAAA;AAClC,UAAA,gBAAA,CAAiB,OAAQ,EAAA,CAAA;AAAA,SAC3B;AAAA,OACF;AAEA,MAAI,IAAA,GAAA,GAAM,SAAU,CAAA,GAAA,CAAI,EAAE,CAAA,CAAA;AAE1B,MAAA,IAAI,QAAQ,KAAW,CAAA,EAAA;AACrB,QAAA,GAAA,GAAM,IAAIe,OAAI,EAAA,CAAA;AACd,QAAA,MAAM,QAAW,GAAA,IAAIC,2BAAsB,CAAA,IAAA,EAAM,GAAG,CAAA,CAAA;AACpD,QAAU,SAAA,CAAA,GAAA,CAAI,IAAI,GAAG,CAAA,CAAA;AACrB,QAAa,YAAA,CAAA,GAAA,CAAI,IAAI,QAAQ,CAAA,CAAA;AAAA,OAC/B;AAEA,MAAO,OAAAC,OAAA;AAAA,QACL,YAAA,CAAa,IAAI,EAAE,CAAA;AAAA,QACnB,qCAAA;AAAA,OACF,CAAA;AAAA,KACF;AAAA,IACA,CAAC,IAAI,CAAA;AAAA,GACP,CAAA;AAEA,EAAA,MAAM,OAAOC,6BAAe,EAAA,CAAA;AAE5B,EAAAC,wBAAA,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,GAAAnB,iBAAA;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,EACE,uBAAAoB,eAAA,CAAAC,mBAAA,EAAA;AAAA,IACE,QAAA,EAAA;AAAA,sBAACC,cAAA,CAAA,KAAA,EAAA;AAAA,QACC,GAAK,EAAA,iBAAA;AAAA,QACL,KAAO,EAAA;AAAA,UACL,QAAU,EAAA,QAAA;AAAA,UACV,GAAK,EAAA,CAAA;AAAA,UACL,IAAM,EAAA,CAAA;AAAA,UACN,SAAA,EAAW,eAAe,IAAK,CAAA,KAAA,CAAM,CAAC,CAAQ,CAAA,IAAA,EAAA,IAAA,CAAK,MAAM,CAAC,CAAA,CAAA,MAAA,CAAA;AAAA,UAC1D,QAAU,EAAA,aAAA;AAAA,SACZ;AAAA,OACF,CAAA;AAAA,MAEC,wBACEA,cAAA,CAAAC,8CAAA,EAAA;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,EANZ,KAAK,EAOZ,CAAA;AAAA,MAGD,kCAAA,mCAAuCC,2BAAc,EAAA,EAAA,CAAA;AAAA,sBACrDF,cAAA,CAAAG,2CAAA,EAAA;AAAA,QAAuB,QAAA;AAAA,OAAS,CAAA;AAAA,KAAA;AAAA,GACnC,CAAA,CAAA;AAEJ;;;;;;"}
@@ -12,6 +12,7 @@ import { CommentPluginProvider } from './comments/comment-plugin-provider.mjs';
12
12
  import { ThreadMarkNode } from './comments/thread-mark-node.mjs';
13
13
  import { MentionNode } from './mentions/mention-node.mjs';
14
14
  import { MentionPlugin } from './mentions/mention-plugin.mjs';
15
+ import { useRootElement } from './use-root-element.mjs';
15
16
 
16
17
  const providersMap = /* @__PURE__ */ new Map();
17
18
  function useEditorStatus() {
@@ -158,19 +159,6 @@ const LiveblocksPlugin = ({
158
159
  ]
159
160
  });
160
161
  };
161
- function useRootElement() {
162
- const [editor] = useLexicalComposerContext();
163
- const subscribe = useCallback(
164
- (onStoreChange) => {
165
- return editor.registerRootListener(onStoreChange);
166
- },
167
- [editor]
168
- );
169
- const getSnapshot = useCallback(() => {
170
- return editor.getRootElement();
171
- }, [editor]);
172
- return useSyncExternalStore(subscribe, getSnapshot, getSnapshot);
173
- }
174
162
 
175
- export { LiveblocksPlugin, useEditorStatus, useIsEditorReady, useRootElement };
163
+ export { LiveblocksPlugin, useEditorStatus, useIsEditorReady };
176
164
  //# sourceMappingURL=liveblocks-plugin-provider.mjs.map