@liveblocks/react-lexical 2.14.0 → 2.15.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/comments/anchored-threads.js +52 -50
- package/dist/comments/anchored-threads.js.map +1 -1
- package/dist/comments/anchored-threads.mjs +36 -34
- package/dist/comments/anchored-threads.mjs.map +1 -1
- package/dist/comments/comment-plugin-provider.js +46 -63
- package/dist/comments/comment-plugin-provider.js.map +1 -1
- package/dist/comments/comment-plugin-provider.mjs +29 -28
- package/dist/comments/comment-plugin-provider.mjs.map +1 -1
- package/dist/comments/floating-composer.js +66 -56
- package/dist/comments/floating-composer.js.map +1 -1
- package/dist/comments/floating-composer.mjs +54 -44
- package/dist/comments/floating-composer.mjs.map +1 -1
- package/dist/comments/floating-threads.js +29 -28
- package/dist/comments/floating-threads.js.map +1 -1
- package/dist/comments/floating-threads.mjs +16 -15
- package/dist/comments/floating-threads.mjs.map +1 -1
- package/dist/comments/thread-mark-node.js +5 -4
- package/dist/comments/thread-mark-node.js.map +1 -1
- package/dist/comments/thread-mark-node.mjs +5 -4
- package/dist/comments/thread-mark-node.mjs.map +1 -1
- package/dist/index.d.mts +8 -6
- package/dist/index.d.ts +8 -6
- package/dist/liveblocks-plugin-provider.js +49 -55
- package/dist/liveblocks-plugin-provider.js.map +1 -1
- package/dist/liveblocks-plugin-provider.mjs +32 -38
- package/dist/liveblocks-plugin-provider.mjs.map +1 -1
- package/dist/mentions/avatar.js +24 -17
- package/dist/mentions/avatar.js.map +1 -1
- package/dist/mentions/avatar.mjs +21 -14
- package/dist/mentions/avatar.mjs.map +1 -1
- package/dist/mentions/mention-component.js +9 -8
- package/dist/mentions/mention-component.js.map +1 -1
- package/dist/mentions/mention-component.mjs +6 -5
- package/dist/mentions/mention-component.mjs.map +1 -1
- package/dist/mentions/mention-node.js +12 -25
- package/dist/mentions/mention-node.js.map +1 -1
- package/dist/mentions/mention-node.mjs +12 -6
- package/dist/mentions/mention-node.mjs.map +1 -1
- package/dist/mentions/mention-plugin.js +47 -41
- package/dist/mentions/mention-plugin.js.map +1 -1
- package/dist/mentions/mention-plugin.mjs +42 -36
- package/dist/mentions/mention-plugin.mjs.map +1 -1
- package/dist/mentions/suggestions.js +34 -30
- package/dist/mentions/suggestions.js.map +1 -1
- package/dist/mentions/suggestions.mjs +16 -12
- package/dist/mentions/suggestions.mjs.map +1 -1
- package/dist/mentions/user.js +9 -7
- package/dist/mentions/user.js.map +1 -1
- package/dist/mentions/user.mjs +6 -4
- package/dist/mentions/user.mjs.map +1 -1
- package/dist/version-history/history-version-preview.js +77 -54
- package/dist/version-history/history-version-preview.js.map +1 -1
- package/dist/version-history/history-version-preview.mjs +70 -47
- package/dist/version-history/history-version-preview.mjs.map +1 -1
- package/dist/version.js +1 -1
- package/dist/version.mjs +1 -1
- package/package.json +12 -19
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
+
var jsxRuntime = require('react/jsx-runtime');
|
|
3
4
|
var LexicalComposerContext = require('@lexical/react/LexicalComposerContext');
|
|
4
5
|
var reactUi = require('@liveblocks/react-ui');
|
|
5
6
|
var lexical = require('lexical');
|
|
6
|
-
var
|
|
7
|
+
var react = require('react');
|
|
7
8
|
var classnames = require('../classnames.js');
|
|
8
9
|
var liveblocksPluginProvider = require('../liveblocks-plugin-provider.js');
|
|
9
10
|
var commentPluginProvider = require('./comment-plugin-provider.js');
|
|
@@ -30,10 +31,10 @@ function AnchoredThreads({
|
|
|
30
31
|
}) {
|
|
31
32
|
const [editor] = LexicalComposerContext.useLexicalComposerContext();
|
|
32
33
|
const Thread = components?.Thread ?? reactUi.Thread;
|
|
33
|
-
const containerRef =
|
|
34
|
+
const containerRef = react.useRef(null);
|
|
34
35
|
const activeThreads = useActiveThreads();
|
|
35
36
|
const nodes = useThreadToNodes();
|
|
36
|
-
const getOrderedThreads =
|
|
37
|
+
const getOrderedThreads = react.useCallback(() => {
|
|
37
38
|
return threads.filter((thread) => thread.resolved === false).map((thread) => {
|
|
38
39
|
const keys = nodes.get(thread.id);
|
|
39
40
|
if (keys === void 0 || keys.size === 0)
|
|
@@ -52,20 +53,20 @@ function AnchoredThreads({
|
|
|
52
53
|
return compareNodes(a.element, b.element);
|
|
53
54
|
});
|
|
54
55
|
}, [editor, threads, nodes]);
|
|
55
|
-
const orderedThreads =
|
|
56
|
-
const [elements, setElements] =
|
|
57
|
-
const [positions, setPositions] =
|
|
58
|
-
const onItemAdd =
|
|
56
|
+
const orderedThreads = react.useMemo(getOrderedThreads, [getOrderedThreads]);
|
|
57
|
+
const [elements, setElements] = react.useState(/* @__PURE__ */ new Map());
|
|
58
|
+
const [positions, setPositions] = react.useState(/* @__PURE__ */ new Map());
|
|
59
|
+
const onItemAdd = react.useCallback((id, el) => {
|
|
59
60
|
setElements((prev) => new Map(prev).set(id, el));
|
|
60
61
|
}, []);
|
|
61
|
-
const onItemRemove =
|
|
62
|
+
const onItemRemove = react.useCallback((id) => {
|
|
62
63
|
setElements((prev) => {
|
|
63
64
|
const items = new Map(prev);
|
|
64
65
|
items.delete(id);
|
|
65
66
|
return items;
|
|
66
67
|
});
|
|
67
68
|
}, []);
|
|
68
|
-
const handlePositionThreads =
|
|
69
|
+
const handlePositionThreads = react.useCallback(() => {
|
|
69
70
|
const container = containerRef.current;
|
|
70
71
|
if (container === null)
|
|
71
72
|
return;
|
|
@@ -119,15 +120,15 @@ function AnchoredThreads({
|
|
|
119
120
|
}
|
|
120
121
|
setPositions(newPositions);
|
|
121
122
|
}, [getOrderedThreads, activeThreads, elements]);
|
|
122
|
-
|
|
123
|
+
react.useLayoutEffect(() => {
|
|
123
124
|
handlePositionThreads();
|
|
124
125
|
}, [handlePositionThreads]);
|
|
125
|
-
|
|
126
|
+
react.useEffect(() => {
|
|
126
127
|
return editor.registerUpdateListener(() => {
|
|
127
128
|
handlePositionThreads();
|
|
128
129
|
});
|
|
129
130
|
}, [editor, handlePositionThreads]);
|
|
130
|
-
|
|
131
|
+
react.useEffect(() => {
|
|
131
132
|
const observer = new ResizeObserver(handlePositionThreads);
|
|
132
133
|
for (const element of elements.values()) {
|
|
133
134
|
observer.observe(element);
|
|
@@ -135,7 +136,7 @@ function AnchoredThreads({
|
|
|
135
136
|
return () => observer.disconnect();
|
|
136
137
|
}, [elements, handlePositionThreads]);
|
|
137
138
|
const root = liveblocksPluginProvider.useRootElement();
|
|
138
|
-
|
|
139
|
+
react.useEffect(() => {
|
|
139
140
|
if (root === null)
|
|
140
141
|
return;
|
|
141
142
|
const observer = new ResizeObserver(handlePositionThreads);
|
|
@@ -144,37 +145,37 @@ function AnchoredThreads({
|
|
|
144
145
|
}, [root, handlePositionThreads]);
|
|
145
146
|
if (orderedThreads.length === 0)
|
|
146
147
|
return null;
|
|
147
|
-
return /* @__PURE__ */
|
|
148
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", {
|
|
148
149
|
...props,
|
|
149
150
|
className: classnames.classNames(className, "lb-root lb-lexical-anchored-threads"),
|
|
150
151
|
ref: containerRef,
|
|
151
152
|
style: {
|
|
152
153
|
position: "relative",
|
|
153
154
|
...style
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
}
|
|
162
|
-
const isActive = activeThreads.includes(thread.id);
|
|
163
|
-
return /* @__PURE__ */ React.createElement(ThreadWrapper, {
|
|
164
|
-
key: thread.id,
|
|
165
|
-
Thread,
|
|
166
|
-
thread,
|
|
167
|
-
onItemAdd,
|
|
168
|
-
onItemRemove,
|
|
169
|
-
style: {
|
|
170
|
-
position: "absolute",
|
|
171
|
-
transform: `translate3d(${isActive ? ACTIVE_THREAD_OFFSET : 0}, ${top}px, 0)`,
|
|
172
|
-
insetInlineStart: 0,
|
|
173
|
-
inlineSize: "100%",
|
|
174
|
-
paddingBlockEnd: GAP
|
|
155
|
+
},
|
|
156
|
+
children: orderedThreads.map(({ thread, element }) => {
|
|
157
|
+
const rect = element.getBoundingClientRect();
|
|
158
|
+
const offset = root !== null ? root.getBoundingClientRect().top : 0;
|
|
159
|
+
let top = rect.top - offset;
|
|
160
|
+
if (positions.has(thread.id)) {
|
|
161
|
+
top = positions.get(thread.id);
|
|
175
162
|
}
|
|
176
|
-
|
|
177
|
-
|
|
163
|
+
const isActive = activeThreads.includes(thread.id);
|
|
164
|
+
return /* @__PURE__ */ jsxRuntime.jsx(ThreadWrapper, {
|
|
165
|
+
Thread,
|
|
166
|
+
thread,
|
|
167
|
+
onItemAdd,
|
|
168
|
+
onItemRemove,
|
|
169
|
+
style: {
|
|
170
|
+
position: "absolute",
|
|
171
|
+
transform: `translate3d(${isActive ? ACTIVE_THREAD_OFFSET : 0}, ${top}px, 0)`,
|
|
172
|
+
insetInlineStart: 0,
|
|
173
|
+
inlineSize: "100%",
|
|
174
|
+
paddingBlockEnd: GAP
|
|
175
|
+
}
|
|
176
|
+
}, thread.id);
|
|
177
|
+
})
|
|
178
|
+
});
|
|
178
179
|
}
|
|
179
180
|
function ThreadWrapper({
|
|
180
181
|
onItemAdd,
|
|
@@ -186,7 +187,7 @@ function ThreadWrapper({
|
|
|
186
187
|
}) {
|
|
187
188
|
const [editor] = LexicalComposerContext.useLexicalComposerContext();
|
|
188
189
|
const nodes = useThreadToNodes();
|
|
189
|
-
const divRef =
|
|
190
|
+
const divRef = react.useRef(null);
|
|
190
191
|
const activeThreads = useActiveThreads();
|
|
191
192
|
const isActive = activeThreads.includes(thread.id);
|
|
192
193
|
function handleThreadClick() {
|
|
@@ -203,7 +204,7 @@ function ThreadWrapper({
|
|
|
203
204
|
node.selectStart();
|
|
204
205
|
});
|
|
205
206
|
}
|
|
206
|
-
|
|
207
|
+
react.useLayoutEffect(() => {
|
|
207
208
|
const el = divRef.current;
|
|
208
209
|
if (el === null)
|
|
209
210
|
return;
|
|
@@ -212,23 +213,24 @@ function ThreadWrapper({
|
|
|
212
213
|
onItemRemove(thread.id);
|
|
213
214
|
};
|
|
214
215
|
}, [thread.id, onItemAdd, onItemRemove]);
|
|
215
|
-
return /* @__PURE__ */
|
|
216
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", {
|
|
216
217
|
ref: divRef,
|
|
217
218
|
className: classnames.classNames(
|
|
218
219
|
"lb-lexical-anchored-threads-thread-container",
|
|
219
220
|
className
|
|
220
221
|
),
|
|
221
|
-
...props
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
222
|
+
...props,
|
|
223
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(Thread, {
|
|
224
|
+
thread,
|
|
225
|
+
"data-state": isActive ? "active" : "inactive",
|
|
226
|
+
onClick: handleThreadClick,
|
|
227
|
+
className: "lb-lexical-anchored-threads-thread",
|
|
228
|
+
showComposer: isActive ? true : false
|
|
229
|
+
})
|
|
230
|
+
});
|
|
229
231
|
}
|
|
230
232
|
function useThreadToNodes() {
|
|
231
|
-
const threadToNodes =
|
|
233
|
+
const threadToNodes = react.useContext(commentPluginProvider.ThreadToNodesContext);
|
|
232
234
|
if (threadToNodes === null) {
|
|
233
235
|
throw new Error(
|
|
234
236
|
"AnchoredThreads component must be used within a LiveblocksPlugin component."
|
|
@@ -237,7 +239,7 @@ function useThreadToNodes() {
|
|
|
237
239
|
return threadToNodes;
|
|
238
240
|
}
|
|
239
241
|
function useActiveThreads() {
|
|
240
|
-
const activeThreads =
|
|
242
|
+
const activeThreads = react.useContext(commentPluginProvider.ActiveThreadsContext);
|
|
241
243
|
if (activeThreads === null) {
|
|
242
244
|
throw new Error(
|
|
243
245
|
"AnchoredThreads component must be used within LiveblocksPlugin."
|
|
@@ -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 {\n Thread as DefaultThread,\n type ThreadProps,\n} from \"@liveblocks/react-ui\";\nimport { $getNodeByKey } from \"lexical\";\nimport type { ComponentPropsWithoutRef, ComponentType } from \"react\";\nimport React, {\n useCallback,\n useContext,\n useEffect,\n useLayoutEffect,\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","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 {\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 useLayoutEffect,\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":";;;;;;;;;;;;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,GAAIA,gDAA0B,EAAA,CAAA;AAC3C,EAAM,MAAA,MAAA,GAAS,YAAY,MAAU,IAAAC,cAAA,CAAA;AACrC,EAAM,MAAA,YAAA,GAAeC,aAAuB,IAAI,CAAA,CAAA;AAEhD,EAAA,MAAM,gBAAgB,gBAAiB,EAAA,CAAA;AAEvC,EAAA,MAAM,QAAQ,gBAAiB,EAAA,CAAA;AAE/B,EAAM,MAAA,iBAAA,GAAoBC,kBAAY,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,GAAAC,aAAA,CAAQ,iBAAmB,EAAA,CAAC,iBAAiB,CAAC,CAAA,CAAA;AAErE,EAAA,MAAM,CAAC,QAAU,EAAA,WAAW,IAAIC,cAAmC,iBAAA,IAAI,KAAK,CAAA,CAAA;AAE5E,EAAA,MAAM,CAAC,SAAW,EAAA,YAAY,IAAIA,cAA8B,iBAAA,IAAI,KAAK,CAAA,CAAA;AAEzE,EAAA,MAAM,SAAY,GAAAH,iBAAA,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,GAAeA,iBAAY,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,GAAwBA,kBAAY,MAAM;AAC9C,IAAA,MAAM,YAAY,YAAa,CAAA,OAAA,CAAA;AAC/B,IAAA,IAAI,SAAc,KAAA,IAAA;AAAM,MAAA,OAAA;AAExB,IAAA,MAAMI,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,EAAAC,qBAAA,CAAgB,MAAM;AACpB,IAAsB,qBAAA,EAAA,CAAA;AAAA,GACxB,EAAG,CAAC,qBAAqB,CAAC,CAAA,CAAA;AAE1B,EAAAC,eAAA,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,EAAAA,eAAA,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,OAAOC,uCAAe,EAAA,CAAA;AAE5B,EAAAD,eAAA,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,uBACGE,cAAA,CAAA,KAAA,EAAA;AAAA,IACE,GAAG,KAAA;AAAA,IACJ,SAAA,EAAWC,qBAAW,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,uBACGD,cAAA,CAAA,aAAA,EAAA;AAAA,QAEC,MAAA;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,GAAIX,gDAA0B,EAAA,CAAA;AAC3C,EAAA,MAAM,QAAQ,gBAAiB,EAAA,CAAA;AAC/B,EAAM,MAAA,MAAA,GAASE,aAAuB,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,GAAOW,sBAAc,GAAG,CAAA,CAAA;AAC9B,MAAI,IAAA,CAACC,iCAAkB,IAAI,CAAA;AAAG,QAAA,OAAA;AAC9B,MAAA,IAAA,CAAK,WAAY,EAAA,CAAA;AAAA,KAClB,CAAA,CAAA;AAAA,GACH;AAEA,EAAAN,qBAAA,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,uBACGG,cAAA,CAAA,KAAA,EAAA;AAAA,IACC,GAAK,EAAA,MAAA;AAAA,IACL,SAAW,EAAAC,qBAAA;AAAA,MACT,8CAAA;AAAA,MACA,SAAA;AAAA,KACF;AAAA,IACC,GAAG,KAAA;AAAA,IAEJ,QAAC,kBAAAD,cAAA,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,GAAgBI,iBAAWC,0CAAoB,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,GAAgBD,iBAAWE,0CAAoB,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,7 +1,8 @@
|
|
|
1
|
+
import { jsx } from 'react/jsx-runtime';
|
|
1
2
|
import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext';
|
|
2
3
|
import { Thread } from '@liveblocks/react-ui';
|
|
3
4
|
import { $getNodeByKey } from 'lexical';
|
|
4
|
-
import
|
|
5
|
+
import { useRef, useCallback, useMemo, useState, useLayoutEffect, useEffect, useContext } from 'react';
|
|
5
6
|
import { classNames } from '../classnames.mjs';
|
|
6
7
|
import { useRootElement } from '../liveblocks-plugin-provider.mjs';
|
|
7
8
|
import { ThreadToNodesContext, ActiveThreadsContext } from './comment-plugin-provider.mjs';
|
|
@@ -142,37 +143,37 @@ function AnchoredThreads({
|
|
|
142
143
|
}, [root, handlePositionThreads]);
|
|
143
144
|
if (orderedThreads.length === 0)
|
|
144
145
|
return null;
|
|
145
|
-
return /* @__PURE__ */
|
|
146
|
+
return /* @__PURE__ */ jsx("div", {
|
|
146
147
|
...props,
|
|
147
148
|
className: classNames(className, "lb-root lb-lexical-anchored-threads"),
|
|
148
149
|
ref: containerRef,
|
|
149
150
|
style: {
|
|
150
151
|
position: "relative",
|
|
151
152
|
...style
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
}
|
|
160
|
-
const isActive = activeThreads.includes(thread.id);
|
|
161
|
-
return /* @__PURE__ */ React__default.createElement(ThreadWrapper, {
|
|
162
|
-
key: thread.id,
|
|
163
|
-
Thread: Thread$1,
|
|
164
|
-
thread,
|
|
165
|
-
onItemAdd,
|
|
166
|
-
onItemRemove,
|
|
167
|
-
style: {
|
|
168
|
-
position: "absolute",
|
|
169
|
-
transform: `translate3d(${isActive ? ACTIVE_THREAD_OFFSET : 0}, ${top}px, 0)`,
|
|
170
|
-
insetInlineStart: 0,
|
|
171
|
-
inlineSize: "100%",
|
|
172
|
-
paddingBlockEnd: GAP
|
|
153
|
+
},
|
|
154
|
+
children: orderedThreads.map(({ thread, element }) => {
|
|
155
|
+
const rect = element.getBoundingClientRect();
|
|
156
|
+
const offset = root !== null ? root.getBoundingClientRect().top : 0;
|
|
157
|
+
let top = rect.top - offset;
|
|
158
|
+
if (positions.has(thread.id)) {
|
|
159
|
+
top = positions.get(thread.id);
|
|
173
160
|
}
|
|
174
|
-
|
|
175
|
-
|
|
161
|
+
const isActive = activeThreads.includes(thread.id);
|
|
162
|
+
return /* @__PURE__ */ jsx(ThreadWrapper, {
|
|
163
|
+
Thread: Thread$1,
|
|
164
|
+
thread,
|
|
165
|
+
onItemAdd,
|
|
166
|
+
onItemRemove,
|
|
167
|
+
style: {
|
|
168
|
+
position: "absolute",
|
|
169
|
+
transform: `translate3d(${isActive ? ACTIVE_THREAD_OFFSET : 0}, ${top}px, 0)`,
|
|
170
|
+
insetInlineStart: 0,
|
|
171
|
+
inlineSize: "100%",
|
|
172
|
+
paddingBlockEnd: GAP
|
|
173
|
+
}
|
|
174
|
+
}, thread.id);
|
|
175
|
+
})
|
|
176
|
+
});
|
|
176
177
|
}
|
|
177
178
|
function ThreadWrapper({
|
|
178
179
|
onItemAdd,
|
|
@@ -210,20 +211,21 @@ function ThreadWrapper({
|
|
|
210
211
|
onItemRemove(thread.id);
|
|
211
212
|
};
|
|
212
213
|
}, [thread.id, onItemAdd, onItemRemove]);
|
|
213
|
-
return /* @__PURE__ */
|
|
214
|
+
return /* @__PURE__ */ jsx("div", {
|
|
214
215
|
ref: divRef,
|
|
215
216
|
className: classNames(
|
|
216
217
|
"lb-lexical-anchored-threads-thread-container",
|
|
217
218
|
className
|
|
218
219
|
),
|
|
219
|
-
...props
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
220
|
+
...props,
|
|
221
|
+
children: /* @__PURE__ */ jsx(Thread, {
|
|
222
|
+
thread,
|
|
223
|
+
"data-state": isActive ? "active" : "inactive",
|
|
224
|
+
onClick: handleThreadClick,
|
|
225
|
+
className: "lb-lexical-anchored-threads-thread",
|
|
226
|
+
showComposer: isActive ? true : false
|
|
227
|
+
})
|
|
228
|
+
});
|
|
227
229
|
}
|
|
228
230
|
function useThreadToNodes() {
|
|
229
231
|
const threadToNodes = useContext(ThreadToNodesContext);
|
|
@@ -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 {\n Thread as DefaultThread,\n type ThreadProps,\n} from \"@liveblocks/react-ui\";\nimport { $getNodeByKey } from \"lexical\";\nimport type { ComponentPropsWithoutRef, ComponentType } from \"react\";\nimport React, {\n useCallback,\n useContext,\n useEffect,\n useLayoutEffect,\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","React"],"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 {\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 useLayoutEffect,\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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"}
|