@liveblocks/react-lexical 2.16.0-toolbars5 → 2.17.0-channels1

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 (57) 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/comments/floating-composer.js +2 -4
  6. package/dist/comments/floating-composer.js.map +1 -1
  7. package/dist/comments/floating-composer.mjs +2 -4
  8. package/dist/comments/floating-composer.mjs.map +1 -1
  9. package/dist/index.d.mts +3 -239
  10. package/dist/index.d.ts +3 -239
  11. package/dist/index.js +0 -8
  12. package/dist/index.js.map +1 -1
  13. package/dist/index.mjs +0 -4
  14. package/dist/index.mjs.map +1 -1
  15. package/dist/liveblocks-plugin-provider.js +15 -2
  16. package/dist/liveblocks-plugin-provider.js.map +1 -1
  17. package/dist/liveblocks-plugin-provider.mjs +14 -2
  18. package/dist/liveblocks-plugin-provider.mjs.map +1 -1
  19. package/dist/version-history/history-version-preview.js +10 -3
  20. package/dist/version-history/history-version-preview.js.map +1 -1
  21. package/dist/version-history/history-version-preview.mjs +10 -3
  22. package/dist/version-history/history-version-preview.mjs.map +1 -1
  23. package/dist/version.js +1 -1
  24. package/dist/version.mjs +1 -1
  25. package/package.json +6 -10
  26. package/src/styles/constants.css +1 -1
  27. package/src/styles/index.css +6 -44
  28. package/styles.css +1 -1
  29. package/styles.css.map +1 -1
  30. package/dist/is-block-node-active.js +0 -51
  31. package/dist/is-block-node-active.js.map +0 -1
  32. package/dist/is-block-node-active.mjs +0 -49
  33. package/dist/is-block-node-active.mjs.map +0 -1
  34. package/dist/is-command-registered.js +0 -11
  35. package/dist/is-command-registered.js.map +0 -1
  36. package/dist/is-command-registered.mjs +0 -9
  37. package/dist/is-command-registered.mjs.map +0 -1
  38. package/dist/is-text-format-active.js +0 -16
  39. package/dist/is-text-format-active.js.map +0 -1
  40. package/dist/is-text-format-active.mjs +0 -14
  41. package/dist/is-text-format-active.mjs.map +0 -1
  42. package/dist/toolbar/floating-toolbar.js +0 -309
  43. package/dist/toolbar/floating-toolbar.js.map +0 -1
  44. package/dist/toolbar/floating-toolbar.mjs +0 -306
  45. package/dist/toolbar/floating-toolbar.mjs.map +0 -1
  46. package/dist/toolbar/shared.js +0 -39
  47. package/dist/toolbar/shared.js.map +0 -1
  48. package/dist/toolbar/shared.mjs +0 -36
  49. package/dist/toolbar/shared.mjs.map +0 -1
  50. package/dist/toolbar/toolbar.js +0 -448
  51. package/dist/toolbar/toolbar.js.map +0 -1
  52. package/dist/toolbar/toolbar.mjs +0 -423
  53. package/dist/toolbar/toolbar.mjs.map +0 -1
  54. package/dist/use-root-element.js +0 -21
  55. package/dist/use-root-element.js.map +0 -1
  56. package/dist/use-root-element.mjs +0 -19
  57. package/dist/use-root-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 useRootElement = require('../use-root-element.js');
10
+ var liveblocksPluginProvider = require('../liveblocks-plugin-provider.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 = useRootElement.useRootElement();
139
+ const root = liveblocksPluginProvider.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 \"../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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"}
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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"}
@@ -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 '../use-root-element.mjs';
8
+ import { useRootElement } from '../liveblocks-plugin-provider.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 \"../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":"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"}
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":"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"}
@@ -115,13 +115,11 @@ const FloatingComposerImpl = react.forwardRef(function FloatingComposer3(props,
115
115
  [onThreadCreate, onComposerSubmit, props.metadata, createThread]
116
116
  );
117
117
  function handleKeyDown(event) {
118
- onKeyDown?.(event);
119
- if (event.isDefaultPrevented())
120
- return;
121
118
  if (event.key === "Escape") {
122
119
  onRangeChange(null);
123
120
  editor.focus();
124
121
  }
122
+ onKeyDown?.(event);
125
123
  }
126
124
  return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, {
127
125
  children: [
@@ -194,7 +192,7 @@ function ActiveSelectionPortal({
194
192
  backgroundColor: "var(--lb-selection, rgba(0, 0, 255, 0.2))",
195
193
  pointerEvents: "none"
196
194
  },
197
- className: "lb-selection lb-lexical-active-selection"
195
+ className: "lb-lexical-active-selection"
198
196
  }, JSON.stringify(rect)))
199
197
  })
200
198
  }),
@@ -1 +1 @@
1
- {"version":3,"file":"floating-composer.js","sources":["../../src/comments/floating-composer.tsx"],"sourcesContent":["import {\n autoUpdate,\n flip,\n hide,\n limitShift,\n offset,\n shift,\n size,\n useFloating,\n} from \"@floating-ui/react-dom\";\nimport { useLexicalComposerContext } from \"@lexical/react/LexicalComposerContext\";\nimport type { BaseMetadata, DM } from \"@liveblocks/core\";\nimport { useCreateThread } from \"@liveblocks/react\";\nimport { useLayoutEffect } from \"@liveblocks/react/_private\";\nimport type {\n ComposerProps,\n ComposerSubmitComment,\n} from \"@liveblocks/react-ui\";\nimport { Composer } from \"@liveblocks/react-ui\";\nimport type { LexicalCommand } from \"lexical\";\nimport {\n $getSelection,\n $isRangeSelection,\n $setSelection,\n COMMAND_PRIORITY_EDITOR,\n createCommand,\n} from \"lexical\";\nimport type { ComponentRef, FormEvent, KeyboardEvent, ReactNode } from \"react\";\nimport { forwardRef, useCallback, useEffect, useState } from \"react\";\nimport { createPortal } from \"react-dom\";\n\nimport { createDOMRange } from \"../create-dom-range\";\nimport { createRectsFromDOMRange } from \"../create-rects-from-dom-range\";\nimport $wrapSelectionInThreadMarkNode from \"./wrap-selection-in-thread-mark-node\";\n\n/**\n * Dispatching OPEN_FLOATING_COMPOSER_COMMAND will display the FloatingComposer\n *\n * @example\n * import { useLexicalComposerContext } from \"@lexical/react/LexicalComposerContext\";\n * import { OPEN_FLOATING_COMPOSER_COMMAND } from \"@liveblocks/react-lexical\";\n *\n * function Toolbar() {\n * const [editor] = useLexicalComposerContext();\n *\n * return (\n * <button\n * onClick={() => {\n * editor.dispatchCommand(OPEN_FLOATING_COMPOSER_COMMAND);\n * }}\n * >\n * 💬 New comment\n * </button>\n * );\n * }\n */\nexport const OPEN_FLOATING_COMPOSER_COMMAND: LexicalCommand<void> =\n createCommand(\"OPEN_FLOATING_COMPOSER_COMMAND\");\n\ntype ComposerElement = ComponentRef<typeof Composer>;\n\nexport type FloatingComposerProps<M extends BaseMetadata = DM> = Omit<\n ComposerProps<M>,\n \"threadId\" | \"commentId\"\n>;\n\n/**\n * Displays a `Composer` near the current lexical selection.\n *\n * To open it, dispatch `OPEN_FLOATING_COMPOSER_COMMAND`.\n *\n * Submitting a comment will attach an annotation thread at the current selection.\n * Should be nested inside `LiveblocksPlugin`.\n */\nexport const FloatingComposer = forwardRef<\n ComposerElement,\n FloatingComposerProps\n>(function FloatingComposer(props, forwardedRef) {\n const [range, setRange] = useState<Range | null>(null);\n const [editor] = useLexicalComposerContext();\n\n useEffect(() => {\n return editor.registerCommand(\n OPEN_FLOATING_COMPOSER_COMMAND,\n () => {\n const selection = $getSelection();\n if (!$isRangeSelection(selection)) return false;\n\n if (selection.isCollapsed()) return false;\n\n const { anchor, focus } = selection;\n\n const range = createDOMRange(\n editor,\n anchor.getNode(),\n anchor.offset,\n focus.getNode(),\n focus.offset\n );\n\n setRange(range);\n\n return true;\n },\n COMMAND_PRIORITY_EDITOR\n );\n }, [editor]);\n\n if (range === null) return null;\n\n return (\n <FloatingComposerImpl\n ref={forwardedRef}\n {...props}\n range={range}\n onRangeChange={setRange}\n />\n );\n});\n\ninterface FloatingComposerImplProps extends FloatingComposerProps {\n range: Range;\n onRangeChange: (range: Range | null) => void;\n}\n\nconst FloatingComposerImpl = forwardRef<\n ComposerElement,\n FloatingComposerImplProps\n>(function FloatingComposer(props, forwardedRef) {\n const {\n range,\n onRangeChange,\n onKeyDown,\n onComposerSubmit,\n ...composerProps\n } = props;\n\n const [editor] = useLexicalComposerContext();\n const createThread = useCreateThread();\n\n const $onStateRead = useCallback((): Range | null => {\n const selection = $getSelection();\n\n // If the selection is not a range selection or is collapsed, clear the range so the composer is no longer displayed.\n if (!$isRangeSelection(selection) || selection.isCollapsed()) {\n return null;\n }\n\n const { anchor, focus } = selection;\n const range = createDOMRange(\n editor,\n anchor.getNode(),\n anchor.offset,\n focus.getNode(),\n focus.offset\n );\n\n return range;\n }, [editor]);\n\n useEffect(() => {\n return editor.registerUpdateListener(({ editorState: state, tags }) => {\n // If the update is not related to collaboration, clear the range so the composer is no longer displayed.\n if (!tags.has(\"collaboration\")) {\n onRangeChange(null);\n return;\n }\n\n const range = state.read(() => $onStateRead());\n onRangeChange(range);\n });\n }, [editor, range, onRangeChange, $onStateRead]);\n\n /**\n * Create a new ThreadMarkNode and wrap the selected content in it.\n * @param threadId The id of the thread to associate with the selected content\n */\n const onThreadCreate = useCallback(\n (threadId: string) => {\n editor.update(() => {\n const selection = $getSelection();\n if (!$isRangeSelection(selection)) return;\n\n // If the selection is collapsed, we do not create a new thread node in the editor.\n if (selection.isCollapsed()) return;\n\n const isBackward = selection.isBackward();\n // Wrap content in a ThreadMarkNode\n $wrapSelectionInThreadMarkNode(selection, isBackward, threadId);\n\n // Clear the selection after wrapping\n $setSelection(null);\n });\n },\n [editor]\n );\n\n const handleComposerSubmit = useCallback(\n (comment: ComposerSubmitComment, event: FormEvent<HTMLFormElement>) => {\n onComposerSubmit?.(comment, event);\n if (event.defaultPrevented) return;\n\n event.preventDefault();\n\n const thread = createThread({\n body: comment.body,\n attachments: comment.attachments,\n metadata: props.metadata ?? {},\n });\n\n onThreadCreate(thread.id);\n },\n [onThreadCreate, onComposerSubmit, props.metadata, createThread]\n );\n\n function handleKeyDown(event: KeyboardEvent<HTMLFormElement>) {\n onKeyDown?.(event);\n\n if (event.isDefaultPrevented()) return;\n\n if (event.key === \"Escape\") {\n onRangeChange(null);\n editor.focus();\n }\n }\n\n return (\n <>\n <ActiveSelectionPortal range={range} container={document.body} />\n\n <FloatingComposerPortal range={range} container={document.body}>\n <Composer\n autoFocus\n {...composerProps}\n onKeyDown={handleKeyDown}\n onComposerSubmit={handleComposerSubmit}\n ref={forwardedRef}\n />\n </FloatingComposerPortal>\n </>\n );\n});\n\nfunction ActiveSelectionPortal({\n range,\n container,\n}: {\n range: Range;\n container: HTMLElement;\n}) {\n const {\n refs: { setReference, setFloating },\n strategy,\n x,\n y,\n } = useFloating({\n strategy: \"fixed\",\n placement: \"bottom\",\n middleware: [offset(-range.getBoundingClientRect().height)],\n whileElementsMounted: (...args) => {\n return autoUpdate(...args, {\n animationFrame: true,\n });\n },\n });\n\n useLayoutEffect(() => {\n setReference({\n getBoundingClientRect: () => range.getBoundingClientRect(),\n });\n }, [setReference, range]);\n\n const [editor] = useLexicalComposerContext();\n const rects = createRectsFromDOMRange(editor, range);\n\n return createPortal(\n <>\n <span\n ref={setFloating}\n style={{\n position: strategy,\n top: 0,\n left: 0,\n transform: `translate3d(${Math.round(x)}px, ${Math.round(y)}px, 0)`,\n minWidth: \"max-content\",\n width: range.getBoundingClientRect().width,\n height: range.getBoundingClientRect().height,\n pointerEvents: \"none\",\n }}\n className=\"lb-root lb-portal\"\n >\n {rects.map((rect) => (\n <span\n key={JSON.stringify(rect)}\n style={{\n position: \"absolute\",\n top: rect.top - range.getBoundingClientRect().top,\n left: rect.left - range.getBoundingClientRect().left,\n width: rect.width,\n height: rect.height,\n backgroundColor: \"var(--lb-selection, rgba(0, 0, 255, 0.2))\",\n pointerEvents: \"none\",\n }}\n className=\"lb-selection lb-lexical-active-selection\"\n />\n ))}\n </span>\n </>,\n container\n );\n}\n\nexport const FLOATING_COMPOSER_COLLISION_PADDING = 10;\n\nfunction FloatingComposerPortal({\n container,\n range,\n children,\n}: {\n container: HTMLElement;\n range: Range;\n children: ReactNode;\n}) {\n const {\n refs: { setReference, setFloating },\n strategy,\n x,\n y,\n } = useFloating({\n strategy: \"fixed\",\n placement: \"bottom\",\n middleware: [\n flip({ padding: FLOATING_COMPOSER_COLLISION_PADDING, crossAxis: false }),\n offset(10),\n hide({ padding: FLOATING_COMPOSER_COLLISION_PADDING }),\n shift({\n padding: FLOATING_COMPOSER_COLLISION_PADDING,\n limiter: limitShift(),\n }),\n size({ padding: FLOATING_COMPOSER_COLLISION_PADDING }),\n ],\n whileElementsMounted: (...args) => {\n return autoUpdate(...args, {\n animationFrame: true,\n });\n },\n });\n\n useLayoutEffect(() => {\n setReference({\n getBoundingClientRect: () => range.getBoundingClientRect(),\n });\n }, [range, setReference]);\n\n return createPortal(\n <div\n ref={setFloating}\n style={{\n position: strategy,\n top: 0,\n left: 0,\n transform: `translate3d(${Math.round(x)}px, ${Math.round(y)}px, 0)`,\n minWidth: \"max-content\",\n }}\n className=\"lb-root lb-portal lb-elevation lb-lexical-floating lb-lexical-floating-composer\"\n >\n {children}\n </div>,\n container\n );\n}\n"],"names":["createCommand","forwardRef","FloatingComposer","useState","useLexicalComposerContext","useEffect","$getSelection","$isRangeSelection","range","createDOMRange","COMMAND_PRIORITY_EDITOR","jsx","useCreateThread","useCallback","$wrapSelectionInThreadMarkNode","$setSelection","jsxs","Fragment","Composer","useFloating","offset","autoUpdate","useLayoutEffect","createRectsFromDOMRange","createPortal","flip","hide","shift","limitShift","size"],"mappings":"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"}
1
+ {"version":3,"file":"floating-composer.js","sources":["../../src/comments/floating-composer.tsx"],"sourcesContent":["import {\n autoUpdate,\n flip,\n hide,\n limitShift,\n offset,\n shift,\n size,\n useFloating,\n} from \"@floating-ui/react-dom\";\nimport { useLexicalComposerContext } from \"@lexical/react/LexicalComposerContext\";\nimport type { BaseMetadata, DM } from \"@liveblocks/core\";\nimport { useCreateThread } from \"@liveblocks/react\";\nimport { useLayoutEffect } from \"@liveblocks/react/_private\";\nimport type {\n ComposerProps,\n ComposerSubmitComment,\n} from \"@liveblocks/react-ui\";\nimport { Composer } from \"@liveblocks/react-ui\";\nimport type { LexicalCommand } from \"lexical\";\nimport {\n $getSelection,\n $isRangeSelection,\n $setSelection,\n COMMAND_PRIORITY_EDITOR,\n createCommand,\n} from \"lexical\";\nimport type { ComponentRef, FormEvent, KeyboardEvent, ReactNode } from \"react\";\nimport { forwardRef, useCallback, useEffect, useState } from \"react\";\nimport { createPortal } from \"react-dom\";\n\nimport { createDOMRange } from \"../create-dom-range\";\nimport { createRectsFromDOMRange } from \"../create-rects-from-dom-range\";\nimport $wrapSelectionInThreadMarkNode from \"./wrap-selection-in-thread-mark-node\";\n\n/**\n * Dispatching OPEN_FLOATING_COMPOSER_COMMAND will display the FloatingComposer\n *\n * @example\n * import { useLexicalComposerContext } from \"@lexical/react/LexicalComposerContext\";\n * import { OPEN_FLOATING_COMPOSER_COMMAND } from \"@liveblocks/react-lexical\";\n *\n * function Toolbar() {\n * const [editor] = useLexicalComposerContext();\n *\n * return (\n * <button\n * onClick={() => {\n * editor.dispatchCommand(OPEN_FLOATING_COMPOSER_COMMAND);\n * }}\n * >\n * 💬 New comment\n * </button>\n * );\n * }\n */\nexport const OPEN_FLOATING_COMPOSER_COMMAND: LexicalCommand<void> =\n createCommand(\"OPEN_FLOATING_COMPOSER_COMMAND\");\n\ntype ComposerElement = ComponentRef<typeof Composer>;\n\nexport type FloatingComposerProps<M extends BaseMetadata = DM> = Omit<\n ComposerProps<M>,\n \"threadId\" | \"commentId\"\n>;\n\n/**\n * Displays a `Composer` near the current lexical selection.\n *\n * To open it, dispatch `OPEN_FLOATING_COMPOSER_COMMAND`.\n *\n * Submitting a comment will attach an annotation thread at the current selection.\n * Should be nested inside `LiveblocksPlugin`.\n */\nexport const FloatingComposer = forwardRef<\n ComposerElement,\n FloatingComposerProps\n>(function FloatingComposer(props, forwardedRef) {\n const [range, setRange] = useState<Range | null>(null);\n const [editor] = useLexicalComposerContext();\n\n useEffect(() => {\n return editor.registerCommand(\n OPEN_FLOATING_COMPOSER_COMMAND,\n () => {\n const selection = $getSelection();\n if (!$isRangeSelection(selection)) return false;\n\n if (selection.isCollapsed()) return false;\n\n const { anchor, focus } = selection;\n\n const range = createDOMRange(\n editor,\n anchor.getNode(),\n anchor.offset,\n focus.getNode(),\n focus.offset\n );\n\n setRange(range);\n\n return true;\n },\n COMMAND_PRIORITY_EDITOR\n );\n }, [editor]);\n\n if (range === null) return null;\n\n return (\n <FloatingComposerImpl\n ref={forwardedRef}\n {...props}\n range={range}\n onRangeChange={setRange}\n />\n );\n});\n\ninterface FloatingComposerImplProps extends FloatingComposerProps {\n range: Range;\n onRangeChange: (range: Range | null) => void;\n}\n\nconst FloatingComposerImpl = forwardRef<\n ComposerElement,\n FloatingComposerImplProps\n>(function FloatingComposer(props, forwardedRef) {\n const {\n range,\n onRangeChange,\n onKeyDown,\n onComposerSubmit,\n ...composerProps\n } = props;\n\n const [editor] = useLexicalComposerContext();\n const createThread = useCreateThread();\n\n const $onStateRead = useCallback((): Range | null => {\n const selection = $getSelection();\n\n // If the selection is not a range selection or is collapsed, clear the range so the composer is no longer displayed.\n if (!$isRangeSelection(selection) || selection.isCollapsed()) {\n return null;\n }\n\n const { anchor, focus } = selection;\n const range = createDOMRange(\n editor,\n anchor.getNode(),\n anchor.offset,\n focus.getNode(),\n focus.offset\n );\n\n return range;\n }, [editor]);\n\n useEffect(() => {\n return editor.registerUpdateListener(({ editorState: state, tags }) => {\n // If the update is not related to collaboration, clear the range so the composer is no longer displayed.\n if (!tags.has(\"collaboration\")) {\n onRangeChange(null);\n return;\n }\n\n const range = state.read(() => $onStateRead());\n onRangeChange(range);\n });\n }, [editor, range, onRangeChange, $onStateRead]);\n\n /**\n * Create a new ThreadMarkNode and wrap the selected content in it.\n * @param threadId The id of the thread to associate with the selected content\n */\n const onThreadCreate = useCallback(\n (threadId: string) => {\n editor.update(() => {\n const selection = $getSelection();\n if (!$isRangeSelection(selection)) return;\n\n // If the selection is collapsed, we do not create a new thread node in the editor.\n if (selection.isCollapsed()) return;\n\n const isBackward = selection.isBackward();\n // Wrap content in a ThreadMarkNode\n $wrapSelectionInThreadMarkNode(selection, isBackward, threadId);\n\n // Clear the selection after wrapping\n $setSelection(null);\n });\n },\n [editor]\n );\n\n const handleComposerSubmit = useCallback(\n (comment: ComposerSubmitComment, event: FormEvent<HTMLFormElement>) => {\n onComposerSubmit?.(comment, event);\n if (event.defaultPrevented) return;\n\n event.preventDefault();\n\n const thread = createThread({\n body: comment.body,\n attachments: comment.attachments,\n metadata: props.metadata ?? {},\n });\n\n onThreadCreate(thread.id);\n },\n [onThreadCreate, onComposerSubmit, props.metadata, createThread]\n );\n\n function handleKeyDown(event: KeyboardEvent<HTMLFormElement>) {\n if (event.key === \"Escape\") {\n onRangeChange(null);\n editor.focus();\n }\n onKeyDown?.(event);\n }\n\n return (\n <>\n <ActiveSelectionPortal range={range} container={document.body} />\n\n <FloatingComposerPortal range={range} container={document.body}>\n <Composer\n autoFocus\n {...composerProps}\n onKeyDown={handleKeyDown}\n onComposerSubmit={handleComposerSubmit}\n ref={forwardedRef}\n />\n </FloatingComposerPortal>\n </>\n );\n});\n\nfunction ActiveSelectionPortal({\n range,\n container,\n}: {\n range: Range;\n container: HTMLElement;\n}) {\n const {\n refs: { setReference, setFloating },\n strategy,\n x,\n y,\n } = useFloating({\n strategy: \"fixed\",\n placement: \"bottom\",\n middleware: [offset(-range.getBoundingClientRect().height)],\n whileElementsMounted: (...args) => {\n return autoUpdate(...args, {\n animationFrame: true,\n });\n },\n });\n\n useLayoutEffect(() => {\n setReference({\n getBoundingClientRect: () => range.getBoundingClientRect(),\n });\n }, [setReference, range]);\n\n const [editor] = useLexicalComposerContext();\n const rects = createRectsFromDOMRange(editor, range);\n\n return createPortal(\n <>\n <span\n ref={setFloating}\n style={{\n position: strategy,\n top: 0,\n left: 0,\n transform: `translate3d(${Math.round(x)}px, ${Math.round(y)}px, 0)`,\n minWidth: \"max-content\",\n width: range.getBoundingClientRect().width,\n height: range.getBoundingClientRect().height,\n pointerEvents: \"none\",\n }}\n className=\"lb-root lb-portal\"\n >\n {rects.map((rect) => (\n <span\n key={JSON.stringify(rect)}\n style={{\n position: \"absolute\",\n top: rect.top - range.getBoundingClientRect().top,\n left: rect.left - range.getBoundingClientRect().left,\n width: rect.width,\n height: rect.height,\n backgroundColor: \"var(--lb-selection, rgba(0, 0, 255, 0.2))\",\n pointerEvents: \"none\",\n }}\n className=\"lb-lexical-active-selection\"\n />\n ))}\n </span>\n </>,\n container\n );\n}\n\nexport const FLOATING_COMPOSER_COLLISION_PADDING = 10;\n\nfunction FloatingComposerPortal({\n container,\n range,\n children,\n}: {\n container: HTMLElement;\n range: Range;\n children: ReactNode;\n}) {\n const {\n refs: { setReference, setFloating },\n strategy,\n x,\n y,\n } = useFloating({\n strategy: \"fixed\",\n placement: \"bottom\",\n middleware: [\n flip({ padding: FLOATING_COMPOSER_COLLISION_PADDING, crossAxis: false }),\n offset(10),\n hide({ padding: FLOATING_COMPOSER_COLLISION_PADDING }),\n shift({\n padding: FLOATING_COMPOSER_COLLISION_PADDING,\n limiter: limitShift(),\n }),\n size({ padding: FLOATING_COMPOSER_COLLISION_PADDING }),\n ],\n whileElementsMounted: (...args) => {\n return autoUpdate(...args, {\n animationFrame: true,\n });\n },\n });\n\n useLayoutEffect(() => {\n setReference({\n getBoundingClientRect: () => range.getBoundingClientRect(),\n });\n }, [range, setReference]);\n\n return createPortal(\n <div\n ref={setFloating}\n style={{\n position: strategy,\n top: 0,\n left: 0,\n transform: `translate3d(${Math.round(x)}px, ${Math.round(y)}px, 0)`,\n minWidth: \"max-content\",\n }}\n className=\"lb-root lb-portal lb-elevation lb-lexical-floating lb-lexical-floating-composer\"\n >\n {children}\n </div>,\n container\n );\n}\n"],"names":["createCommand","forwardRef","FloatingComposer","useState","useLexicalComposerContext","useEffect","$getSelection","$isRangeSelection","range","createDOMRange","COMMAND_PRIORITY_EDITOR","jsx","useCreateThread","useCallback","$wrapSelectionInThreadMarkNode","$setSelection","jsxs","Fragment","Composer","useFloating","offset","autoUpdate","useLayoutEffect","createRectsFromDOMRange","createPortal","flip","hide","shift","limitShift","size"],"mappings":"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"}
@@ -113,13 +113,11 @@ const FloatingComposerImpl = forwardRef(function FloatingComposer3(props, forwar
113
113
  [onThreadCreate, onComposerSubmit, props.metadata, createThread]
114
114
  );
115
115
  function handleKeyDown(event) {
116
- onKeyDown?.(event);
117
- if (event.isDefaultPrevented())
118
- return;
119
116
  if (event.key === "Escape") {
120
117
  onRangeChange(null);
121
118
  editor.focus();
122
119
  }
120
+ onKeyDown?.(event);
123
121
  }
124
122
  return /* @__PURE__ */ jsxs(Fragment, {
125
123
  children: [
@@ -192,7 +190,7 @@ function ActiveSelectionPortal({
192
190
  backgroundColor: "var(--lb-selection, rgba(0, 0, 255, 0.2))",
193
191
  pointerEvents: "none"
194
192
  },
195
- className: "lb-selection lb-lexical-active-selection"
193
+ className: "lb-lexical-active-selection"
196
194
  }, JSON.stringify(rect)))
197
195
  })
198
196
  }),
@@ -1 +1 @@
1
- {"version":3,"file":"floating-composer.mjs","sources":["../../src/comments/floating-composer.tsx"],"sourcesContent":["import {\n autoUpdate,\n flip,\n hide,\n limitShift,\n offset,\n shift,\n size,\n useFloating,\n} from \"@floating-ui/react-dom\";\nimport { useLexicalComposerContext } from \"@lexical/react/LexicalComposerContext\";\nimport type { BaseMetadata, DM } from \"@liveblocks/core\";\nimport { useCreateThread } from \"@liveblocks/react\";\nimport { useLayoutEffect } from \"@liveblocks/react/_private\";\nimport type {\n ComposerProps,\n ComposerSubmitComment,\n} from \"@liveblocks/react-ui\";\nimport { Composer } from \"@liveblocks/react-ui\";\nimport type { LexicalCommand } from \"lexical\";\nimport {\n $getSelection,\n $isRangeSelection,\n $setSelection,\n COMMAND_PRIORITY_EDITOR,\n createCommand,\n} from \"lexical\";\nimport type { ComponentRef, FormEvent, KeyboardEvent, ReactNode } from \"react\";\nimport { forwardRef, useCallback, useEffect, useState } from \"react\";\nimport { createPortal } from \"react-dom\";\n\nimport { createDOMRange } from \"../create-dom-range\";\nimport { createRectsFromDOMRange } from \"../create-rects-from-dom-range\";\nimport $wrapSelectionInThreadMarkNode from \"./wrap-selection-in-thread-mark-node\";\n\n/**\n * Dispatching OPEN_FLOATING_COMPOSER_COMMAND will display the FloatingComposer\n *\n * @example\n * import { useLexicalComposerContext } from \"@lexical/react/LexicalComposerContext\";\n * import { OPEN_FLOATING_COMPOSER_COMMAND } from \"@liveblocks/react-lexical\";\n *\n * function Toolbar() {\n * const [editor] = useLexicalComposerContext();\n *\n * return (\n * <button\n * onClick={() => {\n * editor.dispatchCommand(OPEN_FLOATING_COMPOSER_COMMAND);\n * }}\n * >\n * 💬 New comment\n * </button>\n * );\n * }\n */\nexport const OPEN_FLOATING_COMPOSER_COMMAND: LexicalCommand<void> =\n createCommand(\"OPEN_FLOATING_COMPOSER_COMMAND\");\n\ntype ComposerElement = ComponentRef<typeof Composer>;\n\nexport type FloatingComposerProps<M extends BaseMetadata = DM> = Omit<\n ComposerProps<M>,\n \"threadId\" | \"commentId\"\n>;\n\n/**\n * Displays a `Composer` near the current lexical selection.\n *\n * To open it, dispatch `OPEN_FLOATING_COMPOSER_COMMAND`.\n *\n * Submitting a comment will attach an annotation thread at the current selection.\n * Should be nested inside `LiveblocksPlugin`.\n */\nexport const FloatingComposer = forwardRef<\n ComposerElement,\n FloatingComposerProps\n>(function FloatingComposer(props, forwardedRef) {\n const [range, setRange] = useState<Range | null>(null);\n const [editor] = useLexicalComposerContext();\n\n useEffect(() => {\n return editor.registerCommand(\n OPEN_FLOATING_COMPOSER_COMMAND,\n () => {\n const selection = $getSelection();\n if (!$isRangeSelection(selection)) return false;\n\n if (selection.isCollapsed()) return false;\n\n const { anchor, focus } = selection;\n\n const range = createDOMRange(\n editor,\n anchor.getNode(),\n anchor.offset,\n focus.getNode(),\n focus.offset\n );\n\n setRange(range);\n\n return true;\n },\n COMMAND_PRIORITY_EDITOR\n );\n }, [editor]);\n\n if (range === null) return null;\n\n return (\n <FloatingComposerImpl\n ref={forwardedRef}\n {...props}\n range={range}\n onRangeChange={setRange}\n />\n );\n});\n\ninterface FloatingComposerImplProps extends FloatingComposerProps {\n range: Range;\n onRangeChange: (range: Range | null) => void;\n}\n\nconst FloatingComposerImpl = forwardRef<\n ComposerElement,\n FloatingComposerImplProps\n>(function FloatingComposer(props, forwardedRef) {\n const {\n range,\n onRangeChange,\n onKeyDown,\n onComposerSubmit,\n ...composerProps\n } = props;\n\n const [editor] = useLexicalComposerContext();\n const createThread = useCreateThread();\n\n const $onStateRead = useCallback((): Range | null => {\n const selection = $getSelection();\n\n // If the selection is not a range selection or is collapsed, clear the range so the composer is no longer displayed.\n if (!$isRangeSelection(selection) || selection.isCollapsed()) {\n return null;\n }\n\n const { anchor, focus } = selection;\n const range = createDOMRange(\n editor,\n anchor.getNode(),\n anchor.offset,\n focus.getNode(),\n focus.offset\n );\n\n return range;\n }, [editor]);\n\n useEffect(() => {\n return editor.registerUpdateListener(({ editorState: state, tags }) => {\n // If the update is not related to collaboration, clear the range so the composer is no longer displayed.\n if (!tags.has(\"collaboration\")) {\n onRangeChange(null);\n return;\n }\n\n const range = state.read(() => $onStateRead());\n onRangeChange(range);\n });\n }, [editor, range, onRangeChange, $onStateRead]);\n\n /**\n * Create a new ThreadMarkNode and wrap the selected content in it.\n * @param threadId The id of the thread to associate with the selected content\n */\n const onThreadCreate = useCallback(\n (threadId: string) => {\n editor.update(() => {\n const selection = $getSelection();\n if (!$isRangeSelection(selection)) return;\n\n // If the selection is collapsed, we do not create a new thread node in the editor.\n if (selection.isCollapsed()) return;\n\n const isBackward = selection.isBackward();\n // Wrap content in a ThreadMarkNode\n $wrapSelectionInThreadMarkNode(selection, isBackward, threadId);\n\n // Clear the selection after wrapping\n $setSelection(null);\n });\n },\n [editor]\n );\n\n const handleComposerSubmit = useCallback(\n (comment: ComposerSubmitComment, event: FormEvent<HTMLFormElement>) => {\n onComposerSubmit?.(comment, event);\n if (event.defaultPrevented) return;\n\n event.preventDefault();\n\n const thread = createThread({\n body: comment.body,\n attachments: comment.attachments,\n metadata: props.metadata ?? {},\n });\n\n onThreadCreate(thread.id);\n },\n [onThreadCreate, onComposerSubmit, props.metadata, createThread]\n );\n\n function handleKeyDown(event: KeyboardEvent<HTMLFormElement>) {\n onKeyDown?.(event);\n\n if (event.isDefaultPrevented()) return;\n\n if (event.key === \"Escape\") {\n onRangeChange(null);\n editor.focus();\n }\n }\n\n return (\n <>\n <ActiveSelectionPortal range={range} container={document.body} />\n\n <FloatingComposerPortal range={range} container={document.body}>\n <Composer\n autoFocus\n {...composerProps}\n onKeyDown={handleKeyDown}\n onComposerSubmit={handleComposerSubmit}\n ref={forwardedRef}\n />\n </FloatingComposerPortal>\n </>\n );\n});\n\nfunction ActiveSelectionPortal({\n range,\n container,\n}: {\n range: Range;\n container: HTMLElement;\n}) {\n const {\n refs: { setReference, setFloating },\n strategy,\n x,\n y,\n } = useFloating({\n strategy: \"fixed\",\n placement: \"bottom\",\n middleware: [offset(-range.getBoundingClientRect().height)],\n whileElementsMounted: (...args) => {\n return autoUpdate(...args, {\n animationFrame: true,\n });\n },\n });\n\n useLayoutEffect(() => {\n setReference({\n getBoundingClientRect: () => range.getBoundingClientRect(),\n });\n }, [setReference, range]);\n\n const [editor] = useLexicalComposerContext();\n const rects = createRectsFromDOMRange(editor, range);\n\n return createPortal(\n <>\n <span\n ref={setFloating}\n style={{\n position: strategy,\n top: 0,\n left: 0,\n transform: `translate3d(${Math.round(x)}px, ${Math.round(y)}px, 0)`,\n minWidth: \"max-content\",\n width: range.getBoundingClientRect().width,\n height: range.getBoundingClientRect().height,\n pointerEvents: \"none\",\n }}\n className=\"lb-root lb-portal\"\n >\n {rects.map((rect) => (\n <span\n key={JSON.stringify(rect)}\n style={{\n position: \"absolute\",\n top: rect.top - range.getBoundingClientRect().top,\n left: rect.left - range.getBoundingClientRect().left,\n width: rect.width,\n height: rect.height,\n backgroundColor: \"var(--lb-selection, rgba(0, 0, 255, 0.2))\",\n pointerEvents: \"none\",\n }}\n className=\"lb-selection lb-lexical-active-selection\"\n />\n ))}\n </span>\n </>,\n container\n );\n}\n\nexport const FLOATING_COMPOSER_COLLISION_PADDING = 10;\n\nfunction FloatingComposerPortal({\n container,\n range,\n children,\n}: {\n container: HTMLElement;\n range: Range;\n children: ReactNode;\n}) {\n const {\n refs: { setReference, setFloating },\n strategy,\n x,\n y,\n } = useFloating({\n strategy: \"fixed\",\n placement: \"bottom\",\n middleware: [\n flip({ padding: FLOATING_COMPOSER_COLLISION_PADDING, crossAxis: false }),\n offset(10),\n hide({ padding: FLOATING_COMPOSER_COLLISION_PADDING }),\n shift({\n padding: FLOATING_COMPOSER_COLLISION_PADDING,\n limiter: limitShift(),\n }),\n size({ padding: FLOATING_COMPOSER_COLLISION_PADDING }),\n ],\n whileElementsMounted: (...args) => {\n return autoUpdate(...args, {\n animationFrame: true,\n });\n },\n });\n\n useLayoutEffect(() => {\n setReference({\n getBoundingClientRect: () => range.getBoundingClientRect(),\n });\n }, [range, setReference]);\n\n return createPortal(\n <div\n ref={setFloating}\n style={{\n position: strategy,\n top: 0,\n left: 0,\n transform: `translate3d(${Math.round(x)}px, ${Math.round(y)}px, 0)`,\n minWidth: \"max-content\",\n }}\n className=\"lb-root lb-portal lb-elevation lb-lexical-floating lb-lexical-floating-composer\"\n >\n {children}\n </div>,\n container\n );\n}\n"],"names":["FloatingComposer","range"],"mappings":"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"}
1
+ {"version":3,"file":"floating-composer.mjs","sources":["../../src/comments/floating-composer.tsx"],"sourcesContent":["import {\n autoUpdate,\n flip,\n hide,\n limitShift,\n offset,\n shift,\n size,\n useFloating,\n} from \"@floating-ui/react-dom\";\nimport { useLexicalComposerContext } from \"@lexical/react/LexicalComposerContext\";\nimport type { BaseMetadata, DM } from \"@liveblocks/core\";\nimport { useCreateThread } from \"@liveblocks/react\";\nimport { useLayoutEffect } from \"@liveblocks/react/_private\";\nimport type {\n ComposerProps,\n ComposerSubmitComment,\n} from \"@liveblocks/react-ui\";\nimport { Composer } from \"@liveblocks/react-ui\";\nimport type { LexicalCommand } from \"lexical\";\nimport {\n $getSelection,\n $isRangeSelection,\n $setSelection,\n COMMAND_PRIORITY_EDITOR,\n createCommand,\n} from \"lexical\";\nimport type { ComponentRef, FormEvent, KeyboardEvent, ReactNode } from \"react\";\nimport { forwardRef, useCallback, useEffect, useState } from \"react\";\nimport { createPortal } from \"react-dom\";\n\nimport { createDOMRange } from \"../create-dom-range\";\nimport { createRectsFromDOMRange } from \"../create-rects-from-dom-range\";\nimport $wrapSelectionInThreadMarkNode from \"./wrap-selection-in-thread-mark-node\";\n\n/**\n * Dispatching OPEN_FLOATING_COMPOSER_COMMAND will display the FloatingComposer\n *\n * @example\n * import { useLexicalComposerContext } from \"@lexical/react/LexicalComposerContext\";\n * import { OPEN_FLOATING_COMPOSER_COMMAND } from \"@liveblocks/react-lexical\";\n *\n * function Toolbar() {\n * const [editor] = useLexicalComposerContext();\n *\n * return (\n * <button\n * onClick={() => {\n * editor.dispatchCommand(OPEN_FLOATING_COMPOSER_COMMAND);\n * }}\n * >\n * 💬 New comment\n * </button>\n * );\n * }\n */\nexport const OPEN_FLOATING_COMPOSER_COMMAND: LexicalCommand<void> =\n createCommand(\"OPEN_FLOATING_COMPOSER_COMMAND\");\n\ntype ComposerElement = ComponentRef<typeof Composer>;\n\nexport type FloatingComposerProps<M extends BaseMetadata = DM> = Omit<\n ComposerProps<M>,\n \"threadId\" | \"commentId\"\n>;\n\n/**\n * Displays a `Composer` near the current lexical selection.\n *\n * To open it, dispatch `OPEN_FLOATING_COMPOSER_COMMAND`.\n *\n * Submitting a comment will attach an annotation thread at the current selection.\n * Should be nested inside `LiveblocksPlugin`.\n */\nexport const FloatingComposer = forwardRef<\n ComposerElement,\n FloatingComposerProps\n>(function FloatingComposer(props, forwardedRef) {\n const [range, setRange] = useState<Range | null>(null);\n const [editor] = useLexicalComposerContext();\n\n useEffect(() => {\n return editor.registerCommand(\n OPEN_FLOATING_COMPOSER_COMMAND,\n () => {\n const selection = $getSelection();\n if (!$isRangeSelection(selection)) return false;\n\n if (selection.isCollapsed()) return false;\n\n const { anchor, focus } = selection;\n\n const range = createDOMRange(\n editor,\n anchor.getNode(),\n anchor.offset,\n focus.getNode(),\n focus.offset\n );\n\n setRange(range);\n\n return true;\n },\n COMMAND_PRIORITY_EDITOR\n );\n }, [editor]);\n\n if (range === null) return null;\n\n return (\n <FloatingComposerImpl\n ref={forwardedRef}\n {...props}\n range={range}\n onRangeChange={setRange}\n />\n );\n});\n\ninterface FloatingComposerImplProps extends FloatingComposerProps {\n range: Range;\n onRangeChange: (range: Range | null) => void;\n}\n\nconst FloatingComposerImpl = forwardRef<\n ComposerElement,\n FloatingComposerImplProps\n>(function FloatingComposer(props, forwardedRef) {\n const {\n range,\n onRangeChange,\n onKeyDown,\n onComposerSubmit,\n ...composerProps\n } = props;\n\n const [editor] = useLexicalComposerContext();\n const createThread = useCreateThread();\n\n const $onStateRead = useCallback((): Range | null => {\n const selection = $getSelection();\n\n // If the selection is not a range selection or is collapsed, clear the range so the composer is no longer displayed.\n if (!$isRangeSelection(selection) || selection.isCollapsed()) {\n return null;\n }\n\n const { anchor, focus } = selection;\n const range = createDOMRange(\n editor,\n anchor.getNode(),\n anchor.offset,\n focus.getNode(),\n focus.offset\n );\n\n return range;\n }, [editor]);\n\n useEffect(() => {\n return editor.registerUpdateListener(({ editorState: state, tags }) => {\n // If the update is not related to collaboration, clear the range so the composer is no longer displayed.\n if (!tags.has(\"collaboration\")) {\n onRangeChange(null);\n return;\n }\n\n const range = state.read(() => $onStateRead());\n onRangeChange(range);\n });\n }, [editor, range, onRangeChange, $onStateRead]);\n\n /**\n * Create a new ThreadMarkNode and wrap the selected content in it.\n * @param threadId The id of the thread to associate with the selected content\n */\n const onThreadCreate = useCallback(\n (threadId: string) => {\n editor.update(() => {\n const selection = $getSelection();\n if (!$isRangeSelection(selection)) return;\n\n // If the selection is collapsed, we do not create a new thread node in the editor.\n if (selection.isCollapsed()) return;\n\n const isBackward = selection.isBackward();\n // Wrap content in a ThreadMarkNode\n $wrapSelectionInThreadMarkNode(selection, isBackward, threadId);\n\n // Clear the selection after wrapping\n $setSelection(null);\n });\n },\n [editor]\n );\n\n const handleComposerSubmit = useCallback(\n (comment: ComposerSubmitComment, event: FormEvent<HTMLFormElement>) => {\n onComposerSubmit?.(comment, event);\n if (event.defaultPrevented) return;\n\n event.preventDefault();\n\n const thread = createThread({\n body: comment.body,\n attachments: comment.attachments,\n metadata: props.metadata ?? {},\n });\n\n onThreadCreate(thread.id);\n },\n [onThreadCreate, onComposerSubmit, props.metadata, createThread]\n );\n\n function handleKeyDown(event: KeyboardEvent<HTMLFormElement>) {\n if (event.key === \"Escape\") {\n onRangeChange(null);\n editor.focus();\n }\n onKeyDown?.(event);\n }\n\n return (\n <>\n <ActiveSelectionPortal range={range} container={document.body} />\n\n <FloatingComposerPortal range={range} container={document.body}>\n <Composer\n autoFocus\n {...composerProps}\n onKeyDown={handleKeyDown}\n onComposerSubmit={handleComposerSubmit}\n ref={forwardedRef}\n />\n </FloatingComposerPortal>\n </>\n );\n});\n\nfunction ActiveSelectionPortal({\n range,\n container,\n}: {\n range: Range;\n container: HTMLElement;\n}) {\n const {\n refs: { setReference, setFloating },\n strategy,\n x,\n y,\n } = useFloating({\n strategy: \"fixed\",\n placement: \"bottom\",\n middleware: [offset(-range.getBoundingClientRect().height)],\n whileElementsMounted: (...args) => {\n return autoUpdate(...args, {\n animationFrame: true,\n });\n },\n });\n\n useLayoutEffect(() => {\n setReference({\n getBoundingClientRect: () => range.getBoundingClientRect(),\n });\n }, [setReference, range]);\n\n const [editor] = useLexicalComposerContext();\n const rects = createRectsFromDOMRange(editor, range);\n\n return createPortal(\n <>\n <span\n ref={setFloating}\n style={{\n position: strategy,\n top: 0,\n left: 0,\n transform: `translate3d(${Math.round(x)}px, ${Math.round(y)}px, 0)`,\n minWidth: \"max-content\",\n width: range.getBoundingClientRect().width,\n height: range.getBoundingClientRect().height,\n pointerEvents: \"none\",\n }}\n className=\"lb-root lb-portal\"\n >\n {rects.map((rect) => (\n <span\n key={JSON.stringify(rect)}\n style={{\n position: \"absolute\",\n top: rect.top - range.getBoundingClientRect().top,\n left: rect.left - range.getBoundingClientRect().left,\n width: rect.width,\n height: rect.height,\n backgroundColor: \"var(--lb-selection, rgba(0, 0, 255, 0.2))\",\n pointerEvents: \"none\",\n }}\n className=\"lb-lexical-active-selection\"\n />\n ))}\n </span>\n </>,\n container\n );\n}\n\nexport const FLOATING_COMPOSER_COLLISION_PADDING = 10;\n\nfunction FloatingComposerPortal({\n container,\n range,\n children,\n}: {\n container: HTMLElement;\n range: Range;\n children: ReactNode;\n}) {\n const {\n refs: { setReference, setFloating },\n strategy,\n x,\n y,\n } = useFloating({\n strategy: \"fixed\",\n placement: \"bottom\",\n middleware: [\n flip({ padding: FLOATING_COMPOSER_COLLISION_PADDING, crossAxis: false }),\n offset(10),\n hide({ padding: FLOATING_COMPOSER_COLLISION_PADDING }),\n shift({\n padding: FLOATING_COMPOSER_COLLISION_PADDING,\n limiter: limitShift(),\n }),\n size({ padding: FLOATING_COMPOSER_COLLISION_PADDING }),\n ],\n whileElementsMounted: (...args) => {\n return autoUpdate(...args, {\n animationFrame: true,\n });\n },\n });\n\n useLayoutEffect(() => {\n setReference({\n getBoundingClientRect: () => range.getBoundingClientRect(),\n });\n }, [range, setReference]);\n\n return createPortal(\n <div\n ref={setFloating}\n style={{\n position: strategy,\n top: 0,\n left: 0,\n transform: `translate3d(${Math.round(x)}px, ${Math.round(y)}px, 0)`,\n minWidth: \"max-content\",\n }}\n className=\"lb-root lb-portal lb-elevation lb-lexical-floating lb-lexical-floating-composer\"\n >\n {children}\n </div>,\n container\n );\n}\n"],"names":["FloatingComposer","range"],"mappings":"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"}