@liveblocks/react-lexical 2.2.2 → 2.2.3-alpha2
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 +245 -0
- package/dist/comments/anchored-threads.js.map +1 -0
- package/dist/comments/anchored-threads.mjs +242 -0
- package/dist/comments/anchored-threads.mjs.map +1 -0
- package/dist/comments/comment-plugin-provider.js +11 -6
- package/dist/comments/comment-plugin-provider.js.map +1 -1
- package/dist/comments/comment-plugin-provider.mjs +12 -8
- package/dist/comments/comment-plugin-provider.mjs.map +1 -1
- package/dist/comments/floating-composer.js +2 -2
- package/dist/comments/floating-composer.js.map +1 -1
- package/dist/comments/floating-composer.mjs +2 -2
- package/dist/comments/floating-composer.mjs.map +1 -1
- package/dist/comments/floating-threads.js +219 -0
- package/dist/comments/floating-threads.js.map +1 -0
- package/dist/comments/floating-threads.mjs +216 -0
- package/dist/comments/floating-threads.mjs.map +1 -0
- package/dist/index.d.mts +34 -4
- package/dist/index.d.ts +34 -4
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +2 -0
- package/dist/index.mjs.map +1 -1
- package/dist/liveblocks-plugin-provider.js +1 -0
- package/dist/liveblocks-plugin-provider.js.map +1 -1
- package/dist/liveblocks-plugin-provider.mjs +1 -1
- package/dist/liveblocks-plugin-provider.mjs.map +1 -1
- package/dist/version.js +1 -1
- package/dist/version.js.map +1 -1
- package/dist/version.mjs +1 -1
- package/dist/version.mjs.map +1 -1
- package/package.json +6 -6
- package/src/styles/constants.css +8 -0
- package/src/styles/index.css +76 -13
- package/styles.css +1 -1
- package/styles.css.map +1 -1
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var reactDom = require('@floating-ui/react-dom');
|
|
4
|
+
var LexicalComposerContext = require('@lexical/react/LexicalComposerContext');
|
|
5
|
+
var reactUi = require('@liveblocks/react-ui');
|
|
6
|
+
var lexical = require('lexical');
|
|
7
|
+
var React = require('react');
|
|
8
|
+
var reactDom$1 = require('react-dom');
|
|
9
|
+
var index_js = require('use-sync-external-store/shim/index.js');
|
|
10
|
+
var classnames = require('../classnames.js');
|
|
11
|
+
var anchoredThreads = require('./anchored-threads.js');
|
|
12
|
+
var commentPluginProvider = require('./comment-plugin-provider.js');
|
|
13
|
+
|
|
14
|
+
function FloatingThreads({
|
|
15
|
+
threads,
|
|
16
|
+
components,
|
|
17
|
+
...divProps
|
|
18
|
+
}) {
|
|
19
|
+
const activeThreads = useActiveThreads();
|
|
20
|
+
const Thread = components?.Thread ?? reactUi.Thread;
|
|
21
|
+
const [editor] = LexicalComposerContext.useLexicalComposerContext();
|
|
22
|
+
const nodes = useThreadToNodes();
|
|
23
|
+
const [range, setRange] = React.useState(null);
|
|
24
|
+
const handleUpdateRange = React.useCallback(() => {
|
|
25
|
+
function getActiveRange() {
|
|
26
|
+
function getActiveElements() {
|
|
27
|
+
const activeElements2 = /* @__PURE__ */ new Set();
|
|
28
|
+
for (const thread of activeThreads) {
|
|
29
|
+
const keys = nodes.get(thread);
|
|
30
|
+
if (keys === void 0)
|
|
31
|
+
continue;
|
|
32
|
+
for (const key of keys) {
|
|
33
|
+
const element = editor.getElementByKey(key);
|
|
34
|
+
if (element === null)
|
|
35
|
+
continue;
|
|
36
|
+
activeElements2.add(element);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
return activeElements2;
|
|
40
|
+
}
|
|
41
|
+
const activeElements = getActiveElements();
|
|
42
|
+
const sortedElements = Array.from(activeElements).sort(anchoredThreads.compareNodes);
|
|
43
|
+
if (sortedElements.length === 0)
|
|
44
|
+
return null;
|
|
45
|
+
const range3 = document.createRange();
|
|
46
|
+
range3.setStartBefore(sortedElements[0]);
|
|
47
|
+
range3.setEndAfter(sortedElements[sortedElements.length - 1]);
|
|
48
|
+
return range3;
|
|
49
|
+
}
|
|
50
|
+
const active = (threads ?? []).filter(
|
|
51
|
+
(thread) => activeThreads.includes(thread.id)
|
|
52
|
+
);
|
|
53
|
+
const range2 = getActiveRange();
|
|
54
|
+
if (range2 === null) {
|
|
55
|
+
setRange(null);
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
setRange({ range: range2, threads: active });
|
|
59
|
+
}, [activeThreads, nodes, editor, threads]);
|
|
60
|
+
React.useEffect(() => {
|
|
61
|
+
handleUpdateRange();
|
|
62
|
+
}, [handleUpdateRange]);
|
|
63
|
+
React.useEffect(() => {
|
|
64
|
+
return editor.registerUpdateListener(handleUpdateRange);
|
|
65
|
+
}, [editor, handleUpdateRange]);
|
|
66
|
+
const handleEscapeKeydown = React.useCallback(() => {
|
|
67
|
+
if (range === null)
|
|
68
|
+
return false;
|
|
69
|
+
setRange(null);
|
|
70
|
+
return true;
|
|
71
|
+
}, [range]);
|
|
72
|
+
React.useEffect(() => {
|
|
73
|
+
return editor.registerCommand(
|
|
74
|
+
lexical.KEY_ESCAPE_COMMAND,
|
|
75
|
+
handleEscapeKeydown,
|
|
76
|
+
lexical.COMMAND_PRIORITY_HIGH
|
|
77
|
+
);
|
|
78
|
+
}, [editor, handleEscapeKeydown]);
|
|
79
|
+
const isCollapsed = useIsSelectionCollapsed();
|
|
80
|
+
if (range === null || isCollapsed === null || !isCollapsed)
|
|
81
|
+
return null;
|
|
82
|
+
return /* @__PURE__ */ React.createElement(FloatingThreadPortal, {
|
|
83
|
+
range: range.range,
|
|
84
|
+
container: document.body,
|
|
85
|
+
...divProps
|
|
86
|
+
}, range.threads.map((thread) => /* @__PURE__ */ React.createElement(ThreadWrapper, {
|
|
87
|
+
key: thread.id,
|
|
88
|
+
thread,
|
|
89
|
+
Thread,
|
|
90
|
+
onEscapeKeydown: handleEscapeKeydown,
|
|
91
|
+
className: "lb-lexical-floating-threads-thread"
|
|
92
|
+
})));
|
|
93
|
+
}
|
|
94
|
+
const FLOATING_THREAD_COLLISION_PADDING = 10;
|
|
95
|
+
function FloatingThreadPortal(props) {
|
|
96
|
+
const { container, range, children, className, style, ...divProps } = props;
|
|
97
|
+
const {
|
|
98
|
+
refs: { setReference, setFloating },
|
|
99
|
+
strategy,
|
|
100
|
+
x,
|
|
101
|
+
y
|
|
102
|
+
} = reactDom.useFloating({
|
|
103
|
+
strategy: "absolute",
|
|
104
|
+
placement: "bottom",
|
|
105
|
+
middleware: [
|
|
106
|
+
reactDom.flip({ padding: FLOATING_THREAD_COLLISION_PADDING, crossAxis: false }),
|
|
107
|
+
reactDom.offset(10),
|
|
108
|
+
reactDom.hide({ padding: FLOATING_THREAD_COLLISION_PADDING }),
|
|
109
|
+
reactDom.shift({
|
|
110
|
+
padding: FLOATING_THREAD_COLLISION_PADDING,
|
|
111
|
+
limiter: reactDom.limitShift()
|
|
112
|
+
}),
|
|
113
|
+
reactDom.size({
|
|
114
|
+
padding: FLOATING_THREAD_COLLISION_PADDING,
|
|
115
|
+
apply({ availableWidth, availableHeight, elements }) {
|
|
116
|
+
elements.floating.style.setProperty(
|
|
117
|
+
"--lb-lexical-floating-threads-available-width",
|
|
118
|
+
`${availableWidth}px`
|
|
119
|
+
);
|
|
120
|
+
elements.floating.style.setProperty(
|
|
121
|
+
"--lb-lexical-floating-threads-available-height",
|
|
122
|
+
`${availableHeight}px`
|
|
123
|
+
);
|
|
124
|
+
}
|
|
125
|
+
})
|
|
126
|
+
],
|
|
127
|
+
whileElementsMounted: (...args) => {
|
|
128
|
+
return reactDom.autoUpdate(...args, {
|
|
129
|
+
animationFrame: true
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
});
|
|
133
|
+
React.useLayoutEffect(() => {
|
|
134
|
+
setReference({
|
|
135
|
+
getBoundingClientRect: () => range.getBoundingClientRect()
|
|
136
|
+
});
|
|
137
|
+
}, [setReference, range]);
|
|
138
|
+
return reactDom$1.createPortal(
|
|
139
|
+
/* @__PURE__ */ React.createElement("div", {
|
|
140
|
+
ref: setFloating,
|
|
141
|
+
...divProps,
|
|
142
|
+
style: {
|
|
143
|
+
...style,
|
|
144
|
+
position: strategy,
|
|
145
|
+
top: 0,
|
|
146
|
+
left: 0,
|
|
147
|
+
transform: `translate3d(${Math.round(x)}px, ${Math.round(y)}px, 0)`,
|
|
148
|
+
minWidth: "max-content"
|
|
149
|
+
},
|
|
150
|
+
className: classnames.classNames(
|
|
151
|
+
"lb-root lb-portal lb-elevation lb-lexical-floating lb-lexical-floating-threads",
|
|
152
|
+
className
|
|
153
|
+
)
|
|
154
|
+
}, children),
|
|
155
|
+
container
|
|
156
|
+
);
|
|
157
|
+
}
|
|
158
|
+
function ThreadWrapper({
|
|
159
|
+
thread,
|
|
160
|
+
Thread,
|
|
161
|
+
onEscapeKeydown,
|
|
162
|
+
onKeyDown,
|
|
163
|
+
...threadProps
|
|
164
|
+
}) {
|
|
165
|
+
const handleKeyDown = React.useCallback(
|
|
166
|
+
(event) => {
|
|
167
|
+
onKeyDown?.(event);
|
|
168
|
+
if (event.key === "Escape") {
|
|
169
|
+
onEscapeKeydown();
|
|
170
|
+
}
|
|
171
|
+
},
|
|
172
|
+
[onEscapeKeydown, onKeyDown]
|
|
173
|
+
);
|
|
174
|
+
return /* @__PURE__ */ React.createElement(Thread, {
|
|
175
|
+
thread,
|
|
176
|
+
onKeyDown: handleKeyDown,
|
|
177
|
+
...threadProps
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
function useThreadToNodes() {
|
|
181
|
+
const threadToNodes = React.useContext(commentPluginProvider.ThreadToNodesContext);
|
|
182
|
+
if (threadToNodes === null) {
|
|
183
|
+
throw new Error(
|
|
184
|
+
"FloatingThreads component must be used within a LiveblocksPlugin component."
|
|
185
|
+
);
|
|
186
|
+
}
|
|
187
|
+
return threadToNodes;
|
|
188
|
+
}
|
|
189
|
+
function useIsSelectionCollapsed() {
|
|
190
|
+
const [editor] = LexicalComposerContext.useLexicalComposerContext();
|
|
191
|
+
const subscribe = React.useCallback(
|
|
192
|
+
(onStoreChange) => {
|
|
193
|
+
return editor.registerUpdateListener(onStoreChange);
|
|
194
|
+
},
|
|
195
|
+
[editor]
|
|
196
|
+
);
|
|
197
|
+
const getSnapshot = React.useCallback(() => {
|
|
198
|
+
return editor.getEditorState().read(() => {
|
|
199
|
+
const selection = lexical.$getSelection();
|
|
200
|
+
if (selection === null)
|
|
201
|
+
return null;
|
|
202
|
+
return selection.isCollapsed();
|
|
203
|
+
});
|
|
204
|
+
}, [editor]);
|
|
205
|
+
return index_js.useSyncExternalStore(subscribe, getSnapshot, getSnapshot);
|
|
206
|
+
}
|
|
207
|
+
function useActiveThreads() {
|
|
208
|
+
const activeThreads = React.useContext(commentPluginProvider.ActiveThreadsContext);
|
|
209
|
+
if (activeThreads === null) {
|
|
210
|
+
throw new Error(
|
|
211
|
+
"FloatingThreads component must be used within LiveblocksPlugin."
|
|
212
|
+
);
|
|
213
|
+
}
|
|
214
|
+
return activeThreads;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
exports.FLOATING_THREAD_COLLISION_PADDING = FLOATING_THREAD_COLLISION_PADDING;
|
|
218
|
+
exports.FloatingThreads = FloatingThreads;
|
|
219
|
+
//# sourceMappingURL=floating-threads.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"floating-threads.js","sources":["../../src/comments/floating-threads.tsx"],"sourcesContent":["import {\n autoUpdate,\n flip,\n hide,\n limitShift,\n offset,\n shift,\n size,\n useFloating,\n} from \"@floating-ui/react-dom\";\nimport { useLexicalComposerContext } from \"@lexical/react/LexicalComposerContext\";\nimport type { BaseMetadata, DM, ThreadData } from \"@liveblocks/core\";\nimport {\n Thread as DefaultThread,\n type ThreadProps,\n} from \"@liveblocks/react-ui\";\nimport {\n $getSelection,\n COMMAND_PRIORITY_HIGH,\n KEY_ESCAPE_COMMAND,\n} from \"lexical\";\nimport React, {\n type ComponentType,\n type HTMLAttributes,\n type KeyboardEvent,\n type ReactNode,\n useCallback,\n useContext,\n useEffect,\n useLayoutEffect,\n useState,\n} from \"react\";\nimport { createPortal } from \"react-dom\";\nimport { useSyncExternalStore } from \"use-sync-external-store/shim/index.js\";\n\nimport { classNames } from \"../classnames\";\nimport { compareNodes } from \"./anchored-threads\";\nimport {\n ActiveThreadsContext,\n type ThreadToNodesMap,\n} from \"./comment-plugin-provider\";\nimport { ThreadToNodesContext } from \"./comment-plugin-provider\";\n\ntype ThreadPanelComponents = {\n Thread: ComponentType<ThreadProps>;\n};\n\nexport interface FloatingThreadsProps<M extends BaseMetadata = DM>\n extends Omit<HTMLAttributes<HTMLDivElement>, \"children\"> {\n /**\n * The threads to display.\n */\n threads: ThreadData<M>[];\n\n /**\n * Override the component's components.\n */\n components?: Partial<ThreadPanelComponents>;\n}\n\nexport function FloatingThreads({\n threads,\n components,\n ...divProps\n}: FloatingThreadsProps) {\n const activeThreads = useActiveThreads();\n\n const Thread = components?.Thread ?? DefaultThread;\n\n const [editor] = useLexicalComposerContext();\n const nodes = useThreadToNodes(); // A map of thread ids to a set of thread mark nodes associated with the thread\n\n const [range, setRange] = useState<{\n range: Range;\n threads: ThreadData[];\n } | null>(null);\n\n const handleUpdateRange = useCallback(() => {\n function getActiveRange(): Range | null {\n function getActiveElements() {\n const activeElements = new Set<HTMLElement>();\n\n for (const thread of activeThreads) {\n const keys = nodes.get(thread);\n if (keys === undefined) continue;\n\n for (const key of keys) {\n const element = editor.getElementByKey(key);\n if (element === null) continue;\n activeElements.add(element);\n }\n }\n return activeElements;\n }\n\n const activeElements = getActiveElements();\n\n const sortedElements = Array.from(activeElements).sort(compareNodes);\n if (sortedElements.length === 0) return null;\n\n const range = document.createRange();\n range.setStartBefore(sortedElements[0]);\n range.setEndAfter(sortedElements[sortedElements.length - 1]);\n\n return range;\n }\n\n const active = (threads ?? []).filter((thread) =>\n activeThreads.includes(thread.id)\n );\n\n const range = getActiveRange();\n if (range === null) {\n setRange(null);\n return;\n }\n\n setRange({ range, threads: active });\n }, [activeThreads, nodes, editor, threads]);\n\n useEffect(() => {\n handleUpdateRange();\n }, [handleUpdateRange]);\n\n useEffect(() => {\n return editor.registerUpdateListener(handleUpdateRange);\n }, [editor, handleUpdateRange]);\n\n const handleEscapeKeydown = useCallback((): boolean => {\n if (range === null) return false;\n setRange(null);\n return true;\n }, [range]);\n\n useEffect(() => {\n return editor.registerCommand(\n KEY_ESCAPE_COMMAND,\n handleEscapeKeydown,\n COMMAND_PRIORITY_HIGH\n );\n }, [editor, handleEscapeKeydown]);\n\n const isCollapsed = useIsSelectionCollapsed();\n\n if (range === null || isCollapsed === null || !isCollapsed) return null;\n\n return (\n <FloatingThreadPortal\n range={range.range}\n container={document.body}\n {...divProps}\n >\n {range.threads.map((thread) => (\n <ThreadWrapper\n key={thread.id}\n thread={thread}\n Thread={Thread}\n onEscapeKeydown={handleEscapeKeydown}\n className=\"lb-lexical-floating-threads-thread\"\n />\n ))}\n </FloatingThreadPortal>\n );\n}\n\ninterface FloatingThreadPortalProps\n extends Omit<HTMLAttributes<HTMLDivElement>, \"children\"> {\n range: Range;\n container: HTMLElement;\n children: ReactNode;\n}\n\nexport const FLOATING_THREAD_COLLISION_PADDING = 10;\n\nfunction FloatingThreadPortal(props: FloatingThreadPortalProps) {\n const { container, range, children, className, style, ...divProps } = props;\n\n const {\n refs: { setReference, setFloating },\n strategy,\n x,\n y,\n } = useFloating({\n strategy: \"absolute\",\n placement: \"bottom\",\n middleware: [\n flip({ padding: FLOATING_THREAD_COLLISION_PADDING, crossAxis: false }),\n offset(10),\n hide({ padding: FLOATING_THREAD_COLLISION_PADDING }),\n shift({\n padding: FLOATING_THREAD_COLLISION_PADDING,\n limiter: limitShift(),\n }),\n size({\n padding: FLOATING_THREAD_COLLISION_PADDING,\n apply({ availableWidth, availableHeight, elements }) {\n elements.floating.style.setProperty(\n \"--lb-lexical-floating-threads-available-width\",\n `${availableWidth}px`\n );\n elements.floating.style.setProperty(\n \"--lb-lexical-floating-threads-available-height\",\n `${availableHeight}px`\n );\n },\n }),\n ],\n whileElementsMounted: (...args) => {\n return autoUpdate(...args, {\n animationFrame: true,\n });\n },\n });\n\n useLayoutEffect(() => {\n setReference({\n getBoundingClientRect: () => range.getBoundingClientRect(),\n });\n }, [setReference, range]);\n\n return createPortal(\n <div\n ref={setFloating}\n {...divProps}\n style={{\n ...style,\n position: strategy,\n top: 0,\n left: 0,\n transform: `translate3d(${Math.round(x)}px, ${Math.round(y)}px, 0)`,\n minWidth: \"max-content\",\n }}\n className={classNames(\n \"lb-root lb-portal lb-elevation lb-lexical-floating lb-lexical-floating-threads\",\n className\n )}\n >\n {children}\n </div>,\n container\n );\n}\n\ninterface ThreadWrapperProps extends ThreadProps {\n thread: ThreadData;\n Thread: ComponentType<ThreadProps>;\n onEscapeKeydown: () => void;\n}\n\nfunction ThreadWrapper({\n thread,\n Thread,\n onEscapeKeydown,\n onKeyDown,\n ...threadProps\n}: ThreadWrapperProps) {\n const handleKeyDown = useCallback(\n (event: KeyboardEvent<HTMLDivElement>) => {\n onKeyDown?.(event);\n\n // TODO: Add ability to preventDefault on keydown to override the default behavior, e.g. to show an alert dialog\n if (event.key === \"Escape\") {\n onEscapeKeydown();\n }\n },\n [onEscapeKeydown, onKeyDown]\n );\n\n return <Thread thread={thread} onKeyDown={handleKeyDown} {...threadProps} />;\n}\n\nfunction useThreadToNodes(): ThreadToNodesMap {\n const threadToNodes = useContext(ThreadToNodesContext);\n if (threadToNodes === null) {\n throw new Error(\n \"FloatingThreads component must be used within a LiveblocksPlugin component.\"\n );\n }\n return threadToNodes;\n}\n\nfunction useIsSelectionCollapsed(): boolean | null {\n const [editor] = useLexicalComposerContext();\n\n const subscribe = useCallback(\n (onStoreChange: () => void) => {\n return editor.registerUpdateListener(onStoreChange);\n },\n [editor]\n );\n\n const getSnapshot = useCallback(() => {\n return editor.getEditorState().read(() => {\n const selection = $getSelection();\n if (selection === null) return null;\n return selection.isCollapsed();\n });\n }, [editor]);\n\n return useSyncExternalStore(subscribe, getSnapshot, getSnapshot);\n}\n\nfunction useActiveThreads() {\n const activeThreads = useContext(ActiveThreadsContext);\n if (activeThreads === null) {\n throw new Error(\n \"FloatingThreads component must be used within LiveblocksPlugin.\"\n );\n }\n\n return activeThreads;\n}\n"],"names":["DefaultThread","useLexicalComposerContext","useState","useCallback","activeElements","compareNodes","range","useEffect","KEY_ESCAPE_COMMAND","COMMAND_PRIORITY_HIGH","useFloating","flip","offset","hide","shift","limitShift","size","autoUpdate","useLayoutEffect","createPortal","classNames","useContext","ThreadToNodesContext","$getSelection","useSyncExternalStore","ActiveThreadsContext"],"mappings":"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"}
|
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
import { useFloating, flip, offset, hide, shift, limitShift, size, autoUpdate } from '@floating-ui/react-dom';
|
|
2
|
+
import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext';
|
|
3
|
+
import { Thread } from '@liveblocks/react-ui';
|
|
4
|
+
import { KEY_ESCAPE_COMMAND, COMMAND_PRIORITY_HIGH, $getSelection } from 'lexical';
|
|
5
|
+
import React__default, { useState, useCallback, useEffect, useLayoutEffect, useContext } from 'react';
|
|
6
|
+
import { createPortal } from 'react-dom';
|
|
7
|
+
import { useSyncExternalStore } from 'use-sync-external-store/shim/index.js';
|
|
8
|
+
import { classNames } from '../classnames.mjs';
|
|
9
|
+
import { compareNodes } from './anchored-threads.mjs';
|
|
10
|
+
import { ThreadToNodesContext, ActiveThreadsContext } from './comment-plugin-provider.mjs';
|
|
11
|
+
|
|
12
|
+
function FloatingThreads({
|
|
13
|
+
threads,
|
|
14
|
+
components,
|
|
15
|
+
...divProps
|
|
16
|
+
}) {
|
|
17
|
+
const activeThreads = useActiveThreads();
|
|
18
|
+
const Thread$1 = components?.Thread ?? Thread;
|
|
19
|
+
const [editor] = useLexicalComposerContext();
|
|
20
|
+
const nodes = useThreadToNodes();
|
|
21
|
+
const [range, setRange] = useState(null);
|
|
22
|
+
const handleUpdateRange = useCallback(() => {
|
|
23
|
+
function getActiveRange() {
|
|
24
|
+
function getActiveElements() {
|
|
25
|
+
const activeElements2 = /* @__PURE__ */ new Set();
|
|
26
|
+
for (const thread of activeThreads) {
|
|
27
|
+
const keys = nodes.get(thread);
|
|
28
|
+
if (keys === void 0)
|
|
29
|
+
continue;
|
|
30
|
+
for (const key of keys) {
|
|
31
|
+
const element = editor.getElementByKey(key);
|
|
32
|
+
if (element === null)
|
|
33
|
+
continue;
|
|
34
|
+
activeElements2.add(element);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
return activeElements2;
|
|
38
|
+
}
|
|
39
|
+
const activeElements = getActiveElements();
|
|
40
|
+
const sortedElements = Array.from(activeElements).sort(compareNodes);
|
|
41
|
+
if (sortedElements.length === 0)
|
|
42
|
+
return null;
|
|
43
|
+
const range3 = document.createRange();
|
|
44
|
+
range3.setStartBefore(sortedElements[0]);
|
|
45
|
+
range3.setEndAfter(sortedElements[sortedElements.length - 1]);
|
|
46
|
+
return range3;
|
|
47
|
+
}
|
|
48
|
+
const active = (threads ?? []).filter(
|
|
49
|
+
(thread) => activeThreads.includes(thread.id)
|
|
50
|
+
);
|
|
51
|
+
const range2 = getActiveRange();
|
|
52
|
+
if (range2 === null) {
|
|
53
|
+
setRange(null);
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
setRange({ range: range2, threads: active });
|
|
57
|
+
}, [activeThreads, nodes, editor, threads]);
|
|
58
|
+
useEffect(() => {
|
|
59
|
+
handleUpdateRange();
|
|
60
|
+
}, [handleUpdateRange]);
|
|
61
|
+
useEffect(() => {
|
|
62
|
+
return editor.registerUpdateListener(handleUpdateRange);
|
|
63
|
+
}, [editor, handleUpdateRange]);
|
|
64
|
+
const handleEscapeKeydown = useCallback(() => {
|
|
65
|
+
if (range === null)
|
|
66
|
+
return false;
|
|
67
|
+
setRange(null);
|
|
68
|
+
return true;
|
|
69
|
+
}, [range]);
|
|
70
|
+
useEffect(() => {
|
|
71
|
+
return editor.registerCommand(
|
|
72
|
+
KEY_ESCAPE_COMMAND,
|
|
73
|
+
handleEscapeKeydown,
|
|
74
|
+
COMMAND_PRIORITY_HIGH
|
|
75
|
+
);
|
|
76
|
+
}, [editor, handleEscapeKeydown]);
|
|
77
|
+
const isCollapsed = useIsSelectionCollapsed();
|
|
78
|
+
if (range === null || isCollapsed === null || !isCollapsed)
|
|
79
|
+
return null;
|
|
80
|
+
return /* @__PURE__ */ React__default.createElement(FloatingThreadPortal, {
|
|
81
|
+
range: range.range,
|
|
82
|
+
container: document.body,
|
|
83
|
+
...divProps
|
|
84
|
+
}, range.threads.map((thread) => /* @__PURE__ */ React__default.createElement(ThreadWrapper, {
|
|
85
|
+
key: thread.id,
|
|
86
|
+
thread,
|
|
87
|
+
Thread: Thread$1,
|
|
88
|
+
onEscapeKeydown: handleEscapeKeydown,
|
|
89
|
+
className: "lb-lexical-floating-threads-thread"
|
|
90
|
+
})));
|
|
91
|
+
}
|
|
92
|
+
const FLOATING_THREAD_COLLISION_PADDING = 10;
|
|
93
|
+
function FloatingThreadPortal(props) {
|
|
94
|
+
const { container, range, children, className, style, ...divProps } = props;
|
|
95
|
+
const {
|
|
96
|
+
refs: { setReference, setFloating },
|
|
97
|
+
strategy,
|
|
98
|
+
x,
|
|
99
|
+
y
|
|
100
|
+
} = useFloating({
|
|
101
|
+
strategy: "absolute",
|
|
102
|
+
placement: "bottom",
|
|
103
|
+
middleware: [
|
|
104
|
+
flip({ padding: FLOATING_THREAD_COLLISION_PADDING, crossAxis: false }),
|
|
105
|
+
offset(10),
|
|
106
|
+
hide({ padding: FLOATING_THREAD_COLLISION_PADDING }),
|
|
107
|
+
shift({
|
|
108
|
+
padding: FLOATING_THREAD_COLLISION_PADDING,
|
|
109
|
+
limiter: limitShift()
|
|
110
|
+
}),
|
|
111
|
+
size({
|
|
112
|
+
padding: FLOATING_THREAD_COLLISION_PADDING,
|
|
113
|
+
apply({ availableWidth, availableHeight, elements }) {
|
|
114
|
+
elements.floating.style.setProperty(
|
|
115
|
+
"--lb-lexical-floating-threads-available-width",
|
|
116
|
+
`${availableWidth}px`
|
|
117
|
+
);
|
|
118
|
+
elements.floating.style.setProperty(
|
|
119
|
+
"--lb-lexical-floating-threads-available-height",
|
|
120
|
+
`${availableHeight}px`
|
|
121
|
+
);
|
|
122
|
+
}
|
|
123
|
+
})
|
|
124
|
+
],
|
|
125
|
+
whileElementsMounted: (...args) => {
|
|
126
|
+
return autoUpdate(...args, {
|
|
127
|
+
animationFrame: true
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
});
|
|
131
|
+
useLayoutEffect(() => {
|
|
132
|
+
setReference({
|
|
133
|
+
getBoundingClientRect: () => range.getBoundingClientRect()
|
|
134
|
+
});
|
|
135
|
+
}, [setReference, range]);
|
|
136
|
+
return createPortal(
|
|
137
|
+
/* @__PURE__ */ React__default.createElement("div", {
|
|
138
|
+
ref: setFloating,
|
|
139
|
+
...divProps,
|
|
140
|
+
style: {
|
|
141
|
+
...style,
|
|
142
|
+
position: strategy,
|
|
143
|
+
top: 0,
|
|
144
|
+
left: 0,
|
|
145
|
+
transform: `translate3d(${Math.round(x)}px, ${Math.round(y)}px, 0)`,
|
|
146
|
+
minWidth: "max-content"
|
|
147
|
+
},
|
|
148
|
+
className: classNames(
|
|
149
|
+
"lb-root lb-portal lb-elevation lb-lexical-floating lb-lexical-floating-threads",
|
|
150
|
+
className
|
|
151
|
+
)
|
|
152
|
+
}, children),
|
|
153
|
+
container
|
|
154
|
+
);
|
|
155
|
+
}
|
|
156
|
+
function ThreadWrapper({
|
|
157
|
+
thread,
|
|
158
|
+
Thread,
|
|
159
|
+
onEscapeKeydown,
|
|
160
|
+
onKeyDown,
|
|
161
|
+
...threadProps
|
|
162
|
+
}) {
|
|
163
|
+
const handleKeyDown = useCallback(
|
|
164
|
+
(event) => {
|
|
165
|
+
onKeyDown?.(event);
|
|
166
|
+
if (event.key === "Escape") {
|
|
167
|
+
onEscapeKeydown();
|
|
168
|
+
}
|
|
169
|
+
},
|
|
170
|
+
[onEscapeKeydown, onKeyDown]
|
|
171
|
+
);
|
|
172
|
+
return /* @__PURE__ */ React__default.createElement(Thread, {
|
|
173
|
+
thread,
|
|
174
|
+
onKeyDown: handleKeyDown,
|
|
175
|
+
...threadProps
|
|
176
|
+
});
|
|
177
|
+
}
|
|
178
|
+
function useThreadToNodes() {
|
|
179
|
+
const threadToNodes = useContext(ThreadToNodesContext);
|
|
180
|
+
if (threadToNodes === null) {
|
|
181
|
+
throw new Error(
|
|
182
|
+
"FloatingThreads component must be used within a LiveblocksPlugin component."
|
|
183
|
+
);
|
|
184
|
+
}
|
|
185
|
+
return threadToNodes;
|
|
186
|
+
}
|
|
187
|
+
function useIsSelectionCollapsed() {
|
|
188
|
+
const [editor] = useLexicalComposerContext();
|
|
189
|
+
const subscribe = useCallback(
|
|
190
|
+
(onStoreChange) => {
|
|
191
|
+
return editor.registerUpdateListener(onStoreChange);
|
|
192
|
+
},
|
|
193
|
+
[editor]
|
|
194
|
+
);
|
|
195
|
+
const getSnapshot = useCallback(() => {
|
|
196
|
+
return editor.getEditorState().read(() => {
|
|
197
|
+
const selection = $getSelection();
|
|
198
|
+
if (selection === null)
|
|
199
|
+
return null;
|
|
200
|
+
return selection.isCollapsed();
|
|
201
|
+
});
|
|
202
|
+
}, [editor]);
|
|
203
|
+
return useSyncExternalStore(subscribe, getSnapshot, getSnapshot);
|
|
204
|
+
}
|
|
205
|
+
function useActiveThreads() {
|
|
206
|
+
const activeThreads = useContext(ActiveThreadsContext);
|
|
207
|
+
if (activeThreads === null) {
|
|
208
|
+
throw new Error(
|
|
209
|
+
"FloatingThreads component must be used within LiveblocksPlugin."
|
|
210
|
+
);
|
|
211
|
+
}
|
|
212
|
+
return activeThreads;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
export { FLOATING_THREAD_COLLISION_PADDING, FloatingThreads };
|
|
216
|
+
//# sourceMappingURL=floating-threads.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"floating-threads.mjs","sources":["../../src/comments/floating-threads.tsx"],"sourcesContent":["import {\n autoUpdate,\n flip,\n hide,\n limitShift,\n offset,\n shift,\n size,\n useFloating,\n} from \"@floating-ui/react-dom\";\nimport { useLexicalComposerContext } from \"@lexical/react/LexicalComposerContext\";\nimport type { BaseMetadata, DM, ThreadData } from \"@liveblocks/core\";\nimport {\n Thread as DefaultThread,\n type ThreadProps,\n} from \"@liveblocks/react-ui\";\nimport {\n $getSelection,\n COMMAND_PRIORITY_HIGH,\n KEY_ESCAPE_COMMAND,\n} from \"lexical\";\nimport React, {\n type ComponentType,\n type HTMLAttributes,\n type KeyboardEvent,\n type ReactNode,\n useCallback,\n useContext,\n useEffect,\n useLayoutEffect,\n useState,\n} from \"react\";\nimport { createPortal } from \"react-dom\";\nimport { useSyncExternalStore } from \"use-sync-external-store/shim/index.js\";\n\nimport { classNames } from \"../classnames\";\nimport { compareNodes } from \"./anchored-threads\";\nimport {\n ActiveThreadsContext,\n type ThreadToNodesMap,\n} from \"./comment-plugin-provider\";\nimport { ThreadToNodesContext } from \"./comment-plugin-provider\";\n\ntype ThreadPanelComponents = {\n Thread: ComponentType<ThreadProps>;\n};\n\nexport interface FloatingThreadsProps<M extends BaseMetadata = DM>\n extends Omit<HTMLAttributes<HTMLDivElement>, \"children\"> {\n /**\n * The threads to display.\n */\n threads: ThreadData<M>[];\n\n /**\n * Override the component's components.\n */\n components?: Partial<ThreadPanelComponents>;\n}\n\nexport function FloatingThreads({\n threads,\n components,\n ...divProps\n}: FloatingThreadsProps) {\n const activeThreads = useActiveThreads();\n\n const Thread = components?.Thread ?? DefaultThread;\n\n const [editor] = useLexicalComposerContext();\n const nodes = useThreadToNodes(); // A map of thread ids to a set of thread mark nodes associated with the thread\n\n const [range, setRange] = useState<{\n range: Range;\n threads: ThreadData[];\n } | null>(null);\n\n const handleUpdateRange = useCallback(() => {\n function getActiveRange(): Range | null {\n function getActiveElements() {\n const activeElements = new Set<HTMLElement>();\n\n for (const thread of activeThreads) {\n const keys = nodes.get(thread);\n if (keys === undefined) continue;\n\n for (const key of keys) {\n const element = editor.getElementByKey(key);\n if (element === null) continue;\n activeElements.add(element);\n }\n }\n return activeElements;\n }\n\n const activeElements = getActiveElements();\n\n const sortedElements = Array.from(activeElements).sort(compareNodes);\n if (sortedElements.length === 0) return null;\n\n const range = document.createRange();\n range.setStartBefore(sortedElements[0]);\n range.setEndAfter(sortedElements[sortedElements.length - 1]);\n\n return range;\n }\n\n const active = (threads ?? []).filter((thread) =>\n activeThreads.includes(thread.id)\n );\n\n const range = getActiveRange();\n if (range === null) {\n setRange(null);\n return;\n }\n\n setRange({ range, threads: active });\n }, [activeThreads, nodes, editor, threads]);\n\n useEffect(() => {\n handleUpdateRange();\n }, [handleUpdateRange]);\n\n useEffect(() => {\n return editor.registerUpdateListener(handleUpdateRange);\n }, [editor, handleUpdateRange]);\n\n const handleEscapeKeydown = useCallback((): boolean => {\n if (range === null) return false;\n setRange(null);\n return true;\n }, [range]);\n\n useEffect(() => {\n return editor.registerCommand(\n KEY_ESCAPE_COMMAND,\n handleEscapeKeydown,\n COMMAND_PRIORITY_HIGH\n );\n }, [editor, handleEscapeKeydown]);\n\n const isCollapsed = useIsSelectionCollapsed();\n\n if (range === null || isCollapsed === null || !isCollapsed) return null;\n\n return (\n <FloatingThreadPortal\n range={range.range}\n container={document.body}\n {...divProps}\n >\n {range.threads.map((thread) => (\n <ThreadWrapper\n key={thread.id}\n thread={thread}\n Thread={Thread}\n onEscapeKeydown={handleEscapeKeydown}\n className=\"lb-lexical-floating-threads-thread\"\n />\n ))}\n </FloatingThreadPortal>\n );\n}\n\ninterface FloatingThreadPortalProps\n extends Omit<HTMLAttributes<HTMLDivElement>, \"children\"> {\n range: Range;\n container: HTMLElement;\n children: ReactNode;\n}\n\nexport const FLOATING_THREAD_COLLISION_PADDING = 10;\n\nfunction FloatingThreadPortal(props: FloatingThreadPortalProps) {\n const { container, range, children, className, style, ...divProps } = props;\n\n const {\n refs: { setReference, setFloating },\n strategy,\n x,\n y,\n } = useFloating({\n strategy: \"absolute\",\n placement: \"bottom\",\n middleware: [\n flip({ padding: FLOATING_THREAD_COLLISION_PADDING, crossAxis: false }),\n offset(10),\n hide({ padding: FLOATING_THREAD_COLLISION_PADDING }),\n shift({\n padding: FLOATING_THREAD_COLLISION_PADDING,\n limiter: limitShift(),\n }),\n size({\n padding: FLOATING_THREAD_COLLISION_PADDING,\n apply({ availableWidth, availableHeight, elements }) {\n elements.floating.style.setProperty(\n \"--lb-lexical-floating-threads-available-width\",\n `${availableWidth}px`\n );\n elements.floating.style.setProperty(\n \"--lb-lexical-floating-threads-available-height\",\n `${availableHeight}px`\n );\n },\n }),\n ],\n whileElementsMounted: (...args) => {\n return autoUpdate(...args, {\n animationFrame: true,\n });\n },\n });\n\n useLayoutEffect(() => {\n setReference({\n getBoundingClientRect: () => range.getBoundingClientRect(),\n });\n }, [setReference, range]);\n\n return createPortal(\n <div\n ref={setFloating}\n {...divProps}\n style={{\n ...style,\n position: strategy,\n top: 0,\n left: 0,\n transform: `translate3d(${Math.round(x)}px, ${Math.round(y)}px, 0)`,\n minWidth: \"max-content\",\n }}\n className={classNames(\n \"lb-root lb-portal lb-elevation lb-lexical-floating lb-lexical-floating-threads\",\n className\n )}\n >\n {children}\n </div>,\n container\n );\n}\n\ninterface ThreadWrapperProps extends ThreadProps {\n thread: ThreadData;\n Thread: ComponentType<ThreadProps>;\n onEscapeKeydown: () => void;\n}\n\nfunction ThreadWrapper({\n thread,\n Thread,\n onEscapeKeydown,\n onKeyDown,\n ...threadProps\n}: ThreadWrapperProps) {\n const handleKeyDown = useCallback(\n (event: KeyboardEvent<HTMLDivElement>) => {\n onKeyDown?.(event);\n\n // TODO: Add ability to preventDefault on keydown to override the default behavior, e.g. to show an alert dialog\n if (event.key === \"Escape\") {\n onEscapeKeydown();\n }\n },\n [onEscapeKeydown, onKeyDown]\n );\n\n return <Thread thread={thread} onKeyDown={handleKeyDown} {...threadProps} />;\n}\n\nfunction useThreadToNodes(): ThreadToNodesMap {\n const threadToNodes = useContext(ThreadToNodesContext);\n if (threadToNodes === null) {\n throw new Error(\n \"FloatingThreads component must be used within a LiveblocksPlugin component.\"\n );\n }\n return threadToNodes;\n}\n\nfunction useIsSelectionCollapsed(): boolean | null {\n const [editor] = useLexicalComposerContext();\n\n const subscribe = useCallback(\n (onStoreChange: () => void) => {\n return editor.registerUpdateListener(onStoreChange);\n },\n [editor]\n );\n\n const getSnapshot = useCallback(() => {\n return editor.getEditorState().read(() => {\n const selection = $getSelection();\n if (selection === null) return null;\n return selection.isCollapsed();\n });\n }, [editor]);\n\n return useSyncExternalStore(subscribe, getSnapshot, getSnapshot);\n}\n\nfunction useActiveThreads() {\n const activeThreads = useContext(ActiveThreadsContext);\n if (activeThreads === null) {\n throw new Error(\n \"FloatingThreads component must be used within LiveblocksPlugin.\"\n );\n }\n\n return activeThreads;\n}\n"],"names":["Thread","DefaultThread","activeElements","range","React"],"mappings":"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"}
|
package/dist/index.d.mts
CHANGED
|
@@ -1,10 +1,25 @@
|
|
|
1
|
-
import { BaseMetadata, DM } from '@liveblocks/core';
|
|
2
|
-
import { ComposerProps } from '@liveblocks/react-ui';
|
|
1
|
+
import { BaseMetadata, DM, ThreadData } from '@liveblocks/core';
|
|
2
|
+
import { ThreadProps, ComposerProps } from '@liveblocks/react-ui';
|
|
3
|
+
import React, { ComponentPropsWithoutRef, ComponentType, HTMLAttributes } from 'react';
|
|
3
4
|
import * as lexical from 'lexical';
|
|
4
5
|
import { LexicalCommand } from 'lexical';
|
|
5
|
-
import React from 'react';
|
|
6
6
|
import { InitialConfigType } from '@lexical/react/LexicalComposer';
|
|
7
7
|
|
|
8
|
+
declare type AnchoredThreadsComponents = {
|
|
9
|
+
Thread: ComponentType<ThreadProps>;
|
|
10
|
+
};
|
|
11
|
+
interface AnchoredThreadsProps<M extends BaseMetadata = DM> extends Omit<ComponentPropsWithoutRef<"div">, "children"> {
|
|
12
|
+
/**
|
|
13
|
+
* The threads to display.
|
|
14
|
+
*/
|
|
15
|
+
threads: ThreadData<M>[];
|
|
16
|
+
/**
|
|
17
|
+
* Override the component's components.
|
|
18
|
+
*/
|
|
19
|
+
components?: Partial<AnchoredThreadsComponents>;
|
|
20
|
+
}
|
|
21
|
+
declare function AnchoredThreads({ threads, components, className, style, ...divProps }: AnchoredThreadsProps): React.JSX.Element;
|
|
22
|
+
|
|
8
23
|
/**
|
|
9
24
|
* Returns whether the associated thread annotation for the given thread id is selected or not in the editor.
|
|
10
25
|
* @param threadId The id of the thread to check if the associated annotation is selected or not.
|
|
@@ -45,6 +60,21 @@ declare type FloatingComposerProps<M extends BaseMetadata = DM> = Omit<ComposerP
|
|
|
45
60
|
*/
|
|
46
61
|
declare const FloatingComposer: React.ForwardRefExoticComponent<FloatingComposerProps<BaseMetadata> & React.RefAttributes<HTMLFormElement>>;
|
|
47
62
|
|
|
63
|
+
declare type ThreadPanelComponents = {
|
|
64
|
+
Thread: ComponentType<ThreadProps>;
|
|
65
|
+
};
|
|
66
|
+
interface FloatingThreadsProps<M extends BaseMetadata = DM> extends Omit<HTMLAttributes<HTMLDivElement>, "children"> {
|
|
67
|
+
/**
|
|
68
|
+
* The threads to display.
|
|
69
|
+
*/
|
|
70
|
+
threads: ThreadData<M>[];
|
|
71
|
+
/**
|
|
72
|
+
* Override the component's components.
|
|
73
|
+
*/
|
|
74
|
+
components?: Partial<ThreadPanelComponents>;
|
|
75
|
+
}
|
|
76
|
+
declare function FloatingThreads({ threads, components, ...divProps }: FloatingThreadsProps): React.JSX.Element | null;
|
|
77
|
+
|
|
48
78
|
/**
|
|
49
79
|
* Function that takes a Lexical editor config and modifies it to add the necessary
|
|
50
80
|
* `nodes` and `theme` to make `LiveblocksPlugin` works correctly.
|
|
@@ -140,4 +170,4 @@ declare type LiveblocksPluginProps = {
|
|
|
140
170
|
*/
|
|
141
171
|
declare const LiveblocksPlugin: ({ children, }: LiveblocksPluginProps) => JSX.Element;
|
|
142
172
|
|
|
143
|
-
export { FloatingComposer, LiveblocksPlugin, OPEN_FLOATING_COMPOSER_COMMAND, liveblocksConfig, useEditorStatus, useIsThreadActive };
|
|
173
|
+
export { AnchoredThreads, AnchoredThreadsProps, FloatingComposer, FloatingComposerProps, FloatingThreads, FloatingThreadsProps, LiveblocksPlugin, OPEN_FLOATING_COMPOSER_COMMAND, liveblocksConfig, useEditorStatus, useIsThreadActive };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,10 +1,25 @@
|
|
|
1
|
-
import { BaseMetadata, DM } from '@liveblocks/core';
|
|
2
|
-
import { ComposerProps } from '@liveblocks/react-ui';
|
|
1
|
+
import { BaseMetadata, DM, ThreadData } from '@liveblocks/core';
|
|
2
|
+
import { ThreadProps, ComposerProps } from '@liveblocks/react-ui';
|
|
3
|
+
import React, { ComponentPropsWithoutRef, ComponentType, HTMLAttributes } from 'react';
|
|
3
4
|
import * as lexical from 'lexical';
|
|
4
5
|
import { LexicalCommand } from 'lexical';
|
|
5
|
-
import React from 'react';
|
|
6
6
|
import { InitialConfigType } from '@lexical/react/LexicalComposer';
|
|
7
7
|
|
|
8
|
+
declare type AnchoredThreadsComponents = {
|
|
9
|
+
Thread: ComponentType<ThreadProps>;
|
|
10
|
+
};
|
|
11
|
+
interface AnchoredThreadsProps<M extends BaseMetadata = DM> extends Omit<ComponentPropsWithoutRef<"div">, "children"> {
|
|
12
|
+
/**
|
|
13
|
+
* The threads to display.
|
|
14
|
+
*/
|
|
15
|
+
threads: ThreadData<M>[];
|
|
16
|
+
/**
|
|
17
|
+
* Override the component's components.
|
|
18
|
+
*/
|
|
19
|
+
components?: Partial<AnchoredThreadsComponents>;
|
|
20
|
+
}
|
|
21
|
+
declare function AnchoredThreads({ threads, components, className, style, ...divProps }: AnchoredThreadsProps): React.JSX.Element;
|
|
22
|
+
|
|
8
23
|
/**
|
|
9
24
|
* Returns whether the associated thread annotation for the given thread id is selected or not in the editor.
|
|
10
25
|
* @param threadId The id of the thread to check if the associated annotation is selected or not.
|
|
@@ -45,6 +60,21 @@ declare type FloatingComposerProps<M extends BaseMetadata = DM> = Omit<ComposerP
|
|
|
45
60
|
*/
|
|
46
61
|
declare const FloatingComposer: React.ForwardRefExoticComponent<FloatingComposerProps<BaseMetadata> & React.RefAttributes<HTMLFormElement>>;
|
|
47
62
|
|
|
63
|
+
declare type ThreadPanelComponents = {
|
|
64
|
+
Thread: ComponentType<ThreadProps>;
|
|
65
|
+
};
|
|
66
|
+
interface FloatingThreadsProps<M extends BaseMetadata = DM> extends Omit<HTMLAttributes<HTMLDivElement>, "children"> {
|
|
67
|
+
/**
|
|
68
|
+
* The threads to display.
|
|
69
|
+
*/
|
|
70
|
+
threads: ThreadData<M>[];
|
|
71
|
+
/**
|
|
72
|
+
* Override the component's components.
|
|
73
|
+
*/
|
|
74
|
+
components?: Partial<ThreadPanelComponents>;
|
|
75
|
+
}
|
|
76
|
+
declare function FloatingThreads({ threads, components, ...divProps }: FloatingThreadsProps): React.JSX.Element | null;
|
|
77
|
+
|
|
48
78
|
/**
|
|
49
79
|
* Function that takes a Lexical editor config and modifies it to add the necessary
|
|
50
80
|
* `nodes` and `theme` to make `LiveblocksPlugin` works correctly.
|
|
@@ -140,4 +170,4 @@ declare type LiveblocksPluginProps = {
|
|
|
140
170
|
*/
|
|
141
171
|
declare const LiveblocksPlugin: ({ children, }: LiveblocksPluginProps) => JSX.Element;
|
|
142
172
|
|
|
143
|
-
export { FloatingComposer, LiveblocksPlugin, OPEN_FLOATING_COMPOSER_COMMAND, liveblocksConfig, useEditorStatus, useIsThreadActive };
|
|
173
|
+
export { AnchoredThreads, AnchoredThreadsProps, FloatingComposer, FloatingComposerProps, FloatingThreads, FloatingThreadsProps, LiveblocksPlugin, OPEN_FLOATING_COMPOSER_COMMAND, liveblocksConfig, useEditorStatus, useIsThreadActive };
|
package/dist/index.js
CHANGED
|
@@ -2,16 +2,20 @@
|
|
|
2
2
|
|
|
3
3
|
var core = require('@liveblocks/core');
|
|
4
4
|
var version = require('./version.js');
|
|
5
|
+
var anchoredThreads = require('./comments/anchored-threads.js');
|
|
5
6
|
var commentPluginProvider = require('./comments/comment-plugin-provider.js');
|
|
6
7
|
var floatingComposer = require('./comments/floating-composer.js');
|
|
8
|
+
var floatingThreads = require('./comments/floating-threads.js');
|
|
7
9
|
var liveblocksConfig = require('./liveblocks-config.js');
|
|
8
10
|
var liveblocksPluginProvider = require('./liveblocks-plugin-provider.js');
|
|
9
11
|
|
|
10
12
|
core.detectDupes(version.PKG_NAME, version.PKG_VERSION, version.PKG_FORMAT);
|
|
11
13
|
|
|
14
|
+
exports.AnchoredThreads = anchoredThreads.AnchoredThreads;
|
|
12
15
|
exports.useIsThreadActive = commentPluginProvider.useIsThreadActive;
|
|
13
16
|
exports.FloatingComposer = floatingComposer.FloatingComposer;
|
|
14
17
|
exports.OPEN_FLOATING_COMPOSER_COMMAND = floatingComposer.OPEN_FLOATING_COMPOSER_COMMAND;
|
|
18
|
+
exports.FloatingThreads = floatingThreads.FloatingThreads;
|
|
15
19
|
exports.liveblocksConfig = liveblocksConfig.liveblocksConfig;
|
|
16
20
|
exports.LiveblocksPlugin = liveblocksPluginProvider.LiveblocksPlugin;
|
|
17
21
|
exports.useEditorStatus = liveblocksPluginProvider.useEditorStatus;
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":["../src/index.ts"],"sourcesContent":["import { detectDupes } from \"@liveblocks/core\";\n\nimport { PKG_FORMAT, PKG_NAME, PKG_VERSION } from \"./version\";\n\ndetectDupes(PKG_NAME, PKG_VERSION, PKG_FORMAT);\n\nexport { useIsThreadActive } from \"./comments/comment-plugin-provider\";\nexport {\n FloatingComposer,\n OPEN_FLOATING_COMPOSER_COMMAND,\n} from \"./comments/floating-composer\";\nexport { liveblocksConfig } from \"./liveblocks-config\";\nexport {\n LiveblocksPlugin,\n useEditorStatus,\n} from \"./liveblocks-plugin-provider\";\n"],"names":["detectDupes","PKG_NAME","PKG_VERSION","PKG_FORMAT"],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../src/index.ts"],"sourcesContent":["import { detectDupes } from \"@liveblocks/core\";\n\nimport { PKG_FORMAT, PKG_NAME, PKG_VERSION } from \"./version\";\n\ndetectDupes(PKG_NAME, PKG_VERSION, PKG_FORMAT);\n\nexport type { AnchoredThreadsProps } from \"./comments/anchored-threads\";\nexport { AnchoredThreads } from \"./comments/anchored-threads\";\nexport { useIsThreadActive } from \"./comments/comment-plugin-provider\";\nexport type { FloatingComposerProps } from \"./comments/floating-composer\";\nexport {\n FloatingComposer,\n OPEN_FLOATING_COMPOSER_COMMAND,\n} from \"./comments/floating-composer\";\nexport type { FloatingThreadsProps } from \"./comments/floating-threads\";\nexport { FloatingThreads } from \"./comments/floating-threads\";\nexport { liveblocksConfig } from \"./liveblocks-config\";\nexport {\n LiveblocksPlugin,\n useEditorStatus,\n} from \"./liveblocks-plugin-provider\";\n"],"names":["detectDupes","PKG_NAME","PKG_VERSION","PKG_FORMAT"],"mappings":";;;;;;;;;;;AAIAA,gBAAY,CAAAC,gBAAA,EAAUC,qBAAaC,kBAAU,CAAA;;;;;;;;;;;"}
|
package/dist/index.mjs
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { detectDupes } from '@liveblocks/core';
|
|
2
2
|
import { PKG_NAME, PKG_VERSION, PKG_FORMAT } from './version.mjs';
|
|
3
|
+
export { AnchoredThreads } from './comments/anchored-threads.mjs';
|
|
3
4
|
export { useIsThreadActive } from './comments/comment-plugin-provider.mjs';
|
|
4
5
|
export { FloatingComposer, OPEN_FLOATING_COMPOSER_COMMAND } from './comments/floating-composer.mjs';
|
|
6
|
+
export { FloatingThreads } from './comments/floating-threads.mjs';
|
|
5
7
|
export { liveblocksConfig } from './liveblocks-config.mjs';
|
|
6
8
|
export { LiveblocksPlugin, useEditorStatus } from './liveblocks-plugin-provider.mjs';
|
|
7
9
|
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","sources":["../src/index.ts"],"sourcesContent":["import { detectDupes } from \"@liveblocks/core\";\n\nimport { PKG_FORMAT, PKG_NAME, PKG_VERSION } from \"./version\";\n\ndetectDupes(PKG_NAME, PKG_VERSION, PKG_FORMAT);\n\nexport { useIsThreadActive } from \"./comments/comment-plugin-provider\";\nexport {\n FloatingComposer,\n OPEN_FLOATING_COMPOSER_COMMAND,\n} from \"./comments/floating-composer\";\nexport { liveblocksConfig } from \"./liveblocks-config\";\nexport {\n LiveblocksPlugin,\n useEditorStatus,\n} from \"./liveblocks-plugin-provider\";\n"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.mjs","sources":["../src/index.ts"],"sourcesContent":["import { detectDupes } from \"@liveblocks/core\";\n\nimport { PKG_FORMAT, PKG_NAME, PKG_VERSION } from \"./version\";\n\ndetectDupes(PKG_NAME, PKG_VERSION, PKG_FORMAT);\n\nexport type { AnchoredThreadsProps } from \"./comments/anchored-threads\";\nexport { AnchoredThreads } from \"./comments/anchored-threads\";\nexport { useIsThreadActive } from \"./comments/comment-plugin-provider\";\nexport type { FloatingComposerProps } from \"./comments/floating-composer\";\nexport {\n FloatingComposer,\n OPEN_FLOATING_COMPOSER_COMMAND,\n} from \"./comments/floating-composer\";\nexport type { FloatingThreadsProps } from \"./comments/floating-threads\";\nexport { FloatingThreads } from \"./comments/floating-threads\";\nexport { liveblocksConfig } from \"./liveblocks-config\";\nexport {\n LiveblocksPlugin,\n useEditorStatus,\n} from \"./liveblocks-plugin-provider\";\n"],"names":[],"mappings":";;;;;;;;;AAIA,WAAY,CAAA,QAAA,EAAU,aAAa,UAAU,CAAA"}
|