@liveblocks/react-lexical 2.18.2 → 2.18.4-uns1
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/{classnames.mjs → classnames.cjs} +4 -2
- package/dist/{classnames.mjs.map → classnames.cjs.map} +1 -1
- package/dist/classnames.js +1 -3
- package/dist/classnames.js.map +1 -1
- package/dist/comments/{anchored-threads.mjs → anchored-threads.cjs} +44 -41
- package/dist/comments/{anchored-threads.mjs.map → anchored-threads.cjs.map} +1 -1
- package/dist/comments/anchored-threads.js +40 -43
- package/dist/comments/anchored-threads.js.map +1 -1
- package/dist/comments/{comment-plugin-provider.mjs → comment-plugin-provider.cjs} +62 -55
- package/dist/comments/{comment-plugin-provider.mjs.map → comment-plugin-provider.cjs.map} +1 -1
- package/dist/comments/comment-plugin-provider.js +54 -61
- package/dist/comments/comment-plugin-provider.js.map +1 -1
- package/dist/comments/{floating-composer.mjs → floating-composer.cjs} +68 -64
- package/dist/comments/{floating-composer.mjs.map → floating-composer.cjs.map} +1 -1
- package/dist/comments/floating-composer.js +63 -67
- package/dist/comments/floating-composer.js.map +1 -1
- package/dist/comments/{floating-threads.mjs → floating-threads.cjs} +51 -48
- package/dist/comments/{floating-threads.mjs.map → floating-threads.cjs.map} +1 -1
- package/dist/comments/floating-threads.js +47 -50
- package/dist/comments/floating-threads.js.map +1 -1
- package/dist/comments/get-thread-mark-ids.cjs +23 -0
- package/dist/comments/{get-thread-mark-ids.mjs.map → get-thread-mark-ids.cjs.map} +1 -1
- package/dist/comments/get-thread-mark-ids.js +6 -8
- package/dist/comments/get-thread-mark-ids.js.map +1 -1
- package/dist/comments/{thread-mark-node.mjs → thread-mark-node.cjs} +10 -6
- package/dist/comments/{thread-mark-node.mjs.map → thread-mark-node.cjs.map} +1 -1
- package/dist/comments/thread-mark-node.js +5 -9
- package/dist/comments/thread-mark-node.js.map +1 -1
- package/dist/comments/{unwrap-thread-mark-node.mjs → unwrap-thread-mark-node.cjs} +4 -2
- package/dist/comments/unwrap-thread-mark-node.cjs.map +1 -0
- package/dist/comments/unwrap-thread-mark-node.js +1 -3
- package/dist/comments/unwrap-thread-mark-node.js.map +1 -1
- package/dist/comments/{wrap-selection-in-thread-mark-node.mjs → wrap-selection-in-thread-mark-node.cjs} +12 -10
- package/dist/comments/{wrap-selection-in-thread-mark-node.mjs.map → wrap-selection-in-thread-mark-node.cjs.map} +1 -1
- package/dist/comments/wrap-selection-in-thread-mark-node.js +9 -11
- package/dist/comments/wrap-selection-in-thread-mark-node.js.map +1 -1
- package/dist/{create-dom-range.mjs → create-dom-range.cjs} +7 -5
- package/dist/{create-dom-range.mjs.map → create-dom-range.cjs.map} +1 -1
- package/dist/create-dom-range.js +4 -6
- package/dist/create-dom-range.js.map +1 -1
- package/dist/{create-rects-from-dom-range.mjs → create-rects-from-dom-range.cjs} +4 -2
- package/dist/{create-rects-from-dom-range.mjs.map → create-rects-from-dom-range.cjs.map} +1 -1
- package/dist/create-rects-from-dom-range.js +1 -3
- package/dist/create-rects-from-dom-range.js.map +1 -1
- package/dist/index.cjs +33 -0
- package/dist/{index.mjs.map → index.cjs.map} +1 -1
- package/dist/{index.d.mts → index.d.cts} +0 -1
- package/dist/index.d.ts +0 -1
- package/dist/index.js +14 -31
- package/dist/index.js.map +1 -1
- package/dist/{is-block-node-active.mjs → is-block-node-active.cjs} +12 -10
- package/dist/{is-block-node-active.mjs.map → is-block-node-active.cjs.map} +1 -1
- package/dist/is-block-node-active.js +9 -11
- package/dist/is-block-node-active.js.map +1 -1
- package/dist/is-command-registered.cjs +11 -0
- package/dist/{is-command-registered.mjs.map → is-command-registered.cjs.map} +1 -1
- package/dist/is-command-registered.js +3 -5
- package/dist/is-command-registered.js.map +1 -1
- package/dist/is-text-format-active.cjs +16 -0
- package/dist/{is-text-format-active.mjs.map → is-text-format-active.cjs.map} +1 -1
- package/dist/is-text-format-active.js +4 -6
- package/dist/is-text-format-active.js.map +1 -1
- package/dist/liveblocks-config.cjs +17 -0
- package/dist/{liveblocks-config.mjs.map → liveblocks-config.cjs.map} +1 -1
- package/dist/liveblocks-config.js +4 -6
- package/dist/liveblocks-config.js.map +1 -1
- package/dist/liveblocks-plugin-provider.cjs +151 -0
- package/dist/liveblocks-plugin-provider.cjs.map +1 -0
- package/dist/liveblocks-plugin-provider.js +45 -66
- package/dist/liveblocks-plugin-provider.js.map +1 -1
- package/dist/mentions/{avatar.mjs → avatar.cjs} +16 -14
- package/dist/mentions/avatar.cjs.map +1 -0
- package/dist/mentions/avatar.js +13 -15
- package/dist/mentions/avatar.js.map +1 -1
- package/dist/mentions/mention-component.cjs +51 -0
- package/dist/mentions/{mention-component.mjs.map → mention-component.cjs.map} +1 -1
- package/dist/mentions/mention-component.js +14 -16
- package/dist/mentions/mention-component.js.map +1 -1
- package/dist/mentions/{mention-node.mjs → mention-node.cjs} +17 -13
- package/dist/mentions/mention-node.cjs.map +1 -0
- package/dist/mentions/mention-node.js +12 -16
- package/dist/mentions/mention-node.js.map +1 -1
- package/dist/mentions/{mention-plugin.mjs → mention-plugin.cjs} +81 -78
- package/dist/mentions/{mention-plugin.mjs.map → mention-plugin.cjs.map} +1 -1
- package/dist/mentions/mention-plugin.js +77 -80
- package/dist/mentions/mention-plugin.js.map +1 -1
- package/dist/mentions/{suggestions.mjs → suggestions.cjs} +43 -37
- package/dist/mentions/{suggestions.mjs.map → suggestions.cjs.map} +1 -1
- package/dist/mentions/suggestions.js +36 -42
- package/dist/mentions/suggestions.js.map +1 -1
- package/dist/mentions/user.cjs +26 -0
- package/dist/mentions/{user.mjs.map → user.cjs.map} +1 -1
- package/dist/mentions/user.js +11 -13
- package/dist/mentions/user.js.map +1 -1
- package/dist/toolbar/{floating-toolbar.mjs → floating-toolbar.cjs} +73 -70
- package/dist/toolbar/{floating-toolbar.mjs.map → floating-toolbar.cjs.map} +1 -1
- package/dist/toolbar/floating-toolbar.js +69 -72
- package/dist/toolbar/floating-toolbar.js.map +1 -1
- package/dist/toolbar/shared.cjs +36 -0
- package/dist/toolbar/{shared.mjs.map → shared.cjs.map} +1 -1
- package/dist/toolbar/shared.js +12 -15
- package/dist/toolbar/shared.js.map +1 -1
- package/dist/toolbar/toolbar.cjs +433 -0
- package/dist/toolbar/{toolbar.mjs.map → toolbar.cjs.map} +1 -1
- package/dist/toolbar/toolbar.js +131 -156
- package/dist/toolbar/toolbar.js.map +1 -1
- package/dist/use-root-element.cjs +21 -0
- package/dist/use-root-element.cjs.map +1 -0
- package/dist/use-root-element.js +7 -9
- package/dist/use-root-element.js.map +1 -1
- package/dist/version-history/{history-version-preview.mjs → history-version-preview.cjs} +53 -50
- package/dist/version-history/history-version-preview.cjs.map +1 -0
- package/dist/version-history/history-version-preview.js +50 -51
- package/dist/version-history/history-version-preview.js.map +1 -1
- package/dist/version.cjs +10 -0
- package/dist/{version.mjs.map → version.cjs.map} +1 -1
- package/dist/version.js +3 -7
- package/dist/version.js.map +1 -1
- package/package.json +24 -23
- package/styles.css.d.cts +1 -0
- package/dist/comments/get-thread-mark-ids.mjs +0 -21
- package/dist/comments/unwrap-thread-mark-node.mjs.map +0 -1
- package/dist/index.mjs +0 -16
- package/dist/is-command-registered.mjs +0 -9
- package/dist/is-text-format-active.mjs +0 -14
- package/dist/liveblocks-config.mjs +0 -15
- package/dist/liveblocks-plugin-provider.mjs +0 -164
- package/dist/liveblocks-plugin-provider.mjs.map +0 -1
- package/dist/mentions/avatar.mjs.map +0 -1
- package/dist/mentions/mention-component.mjs +0 -49
- package/dist/mentions/mention-node.mjs.map +0 -1
- package/dist/mentions/user.mjs +0 -24
- package/dist/toolbar/shared.mjs +0 -33
- package/dist/toolbar/toolbar.mjs +0 -408
- package/dist/use-root-element.mjs +0 -19
- package/dist/use-root-element.mjs.map +0 -1
- package/dist/version-history/history-version-preview.mjs.map +0 -1
- package/dist/version.mjs +0 -6
|
@@ -1,70 +1,72 @@
|
|
|
1
|
-
|
|
2
|
-
import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext';
|
|
3
|
-
import { addClassNamesToElement, removeClassNamesFromElement, registerNestedElementResolver } from '@lexical/utils';
|
|
4
|
-
import { shallow } from '@liveblocks/client';
|
|
5
|
-
import { useClient, useRoom, useErrorListener } from '@liveblocks/react';
|
|
6
|
-
import { getUmbrellaStoreForClient, useSignal } from '@liveblocks/react/_private';
|
|
7
|
-
import { $getNodeByKey, $isRangeSelection, $isTextNode, $getSelection } from 'lexical';
|
|
8
|
-
import { createContext, useState, useCallback, useEffect, useContext } from 'react';
|
|
9
|
-
import $getThreadMarkIds from './get-thread-mark-ids.mjs';
|
|
10
|
-
import { $isThreadMarkNode, ThreadMarkNode, $createThreadMarkNode } from './thread-mark-node.mjs';
|
|
11
|
-
import $unwrapThreadMarkNode from './unwrap-thread-mark-node.mjs';
|
|
1
|
+
'use strict';
|
|
12
2
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
3
|
+
var jsxRuntime = require('react/jsx-runtime');
|
|
4
|
+
var LexicalComposerContext = require('@lexical/react/LexicalComposerContext');
|
|
5
|
+
var utils = require('@lexical/utils');
|
|
6
|
+
var client = require('@liveblocks/client');
|
|
7
|
+
var react$1 = require('@liveblocks/react');
|
|
8
|
+
var _private = require('@liveblocks/react/_private');
|
|
9
|
+
var lexical = require('lexical');
|
|
10
|
+
var react = require('react');
|
|
11
|
+
var getThreadMarkIds = require('./get-thread-mark-ids.cjs');
|
|
12
|
+
var threadMarkNode = require('./thread-mark-node.cjs');
|
|
13
|
+
var unwrapThreadMarkNode = require('./unwrap-thread-mark-node.cjs');
|
|
14
|
+
|
|
15
|
+
const OnDeleteThreadCallback = react.createContext(null);
|
|
16
|
+
const ActiveThreadsContext = react.createContext(null);
|
|
17
|
+
const IsActiveThreadContext = react.createContext(null);
|
|
18
|
+
const ThreadToNodesContext = react.createContext(
|
|
17
19
|
null
|
|
18
20
|
);
|
|
19
21
|
function CommentPluginProvider({ children }) {
|
|
20
|
-
const [editor, context] = useLexicalComposerContext();
|
|
21
|
-
const [threadToNodes, setThreadToNodes] = useState(
|
|
22
|
+
const [editor, context] = LexicalComposerContext.useLexicalComposerContext();
|
|
23
|
+
const [threadToNodes, setThreadToNodes] = react.useState(
|
|
22
24
|
/* @__PURE__ */ new Map()
|
|
23
25
|
);
|
|
24
|
-
const [activeThreads, setActiveThreads] = useState([]);
|
|
25
|
-
const client = useClient();
|
|
26
|
-
const room = useRoom();
|
|
27
|
-
const isThreadActive = useCallback(
|
|
26
|
+
const [activeThreads, setActiveThreads] = react.useState([]);
|
|
27
|
+
const client$1 = react$1.useClient();
|
|
28
|
+
const room = react$1.useRoom();
|
|
29
|
+
const isThreadActive = react.useCallback(
|
|
28
30
|
(threadId) => {
|
|
29
31
|
return activeThreads.includes(threadId);
|
|
30
32
|
},
|
|
31
33
|
[activeThreads]
|
|
32
34
|
);
|
|
33
|
-
const handleThreadDelete = useCallback(
|
|
35
|
+
const handleThreadDelete = react.useCallback(
|
|
34
36
|
(threadId) => {
|
|
35
37
|
editor.update(() => {
|
|
36
38
|
const keys = threadToNodes.get(threadId);
|
|
37
39
|
if (keys === void 0)
|
|
38
40
|
return;
|
|
39
41
|
for (const key of keys) {
|
|
40
|
-
const node =
|
|
41
|
-
if (
|
|
42
|
+
const node = lexical.$getNodeByKey(key);
|
|
43
|
+
if (!threadMarkNode.$isThreadMarkNode(node))
|
|
42
44
|
continue;
|
|
43
45
|
node.deleteID(threadId);
|
|
44
46
|
if (node.getIDs().length === 0) {
|
|
45
|
-
|
|
47
|
+
unwrapThreadMarkNode(node);
|
|
46
48
|
}
|
|
47
49
|
}
|
|
48
50
|
});
|
|
49
51
|
},
|
|
50
52
|
[editor, threadToNodes]
|
|
51
53
|
);
|
|
52
|
-
useErrorListener((err) => {
|
|
54
|
+
react$1.useErrorListener((err) => {
|
|
53
55
|
if (err.context.type === "CREATE_THREAD_ERROR" && err.context.roomId === room.id) {
|
|
54
56
|
handleThreadDelete(err.context.threadId);
|
|
55
57
|
}
|
|
56
58
|
});
|
|
57
|
-
const store = getUmbrellaStoreForClient(client);
|
|
59
|
+
const store = _private.getUmbrellaStoreForClient(client$1);
|
|
58
60
|
const roomId = room.id;
|
|
59
|
-
const threadIds = useSignal(
|
|
61
|
+
const threadIds = _private.useSignal(
|
|
60
62
|
store.outputs.threads,
|
|
61
|
-
useCallback(
|
|
63
|
+
react.useCallback(
|
|
62
64
|
(state) => state.findMany(roomId, { resolved: false }, "asc").map((thread) => thread.id),
|
|
63
65
|
[roomId]
|
|
64
66
|
),
|
|
65
|
-
shallow
|
|
67
|
+
client.shallow
|
|
66
68
|
);
|
|
67
|
-
useEffect(() => {
|
|
69
|
+
react.useEffect(() => {
|
|
68
70
|
function getThreadMarkElements() {
|
|
69
71
|
const activeElements = /* @__PURE__ */ new Set();
|
|
70
72
|
for (const id of threadIds) {
|
|
@@ -87,15 +89,15 @@ function CommentPluginProvider({ children }) {
|
|
|
87
89
|
classNames.push(theme.liveblocks.threadMark);
|
|
88
90
|
}
|
|
89
91
|
elements.forEach((element) => {
|
|
90
|
-
addClassNamesToElement(element, ...classNames);
|
|
92
|
+
utils.addClassNamesToElement(element, ...classNames);
|
|
91
93
|
});
|
|
92
94
|
return () => {
|
|
93
95
|
elements.forEach((element) => {
|
|
94
|
-
removeClassNamesFromElement(element, ...classNames);
|
|
96
|
+
utils.removeClassNamesFromElement(element, ...classNames);
|
|
95
97
|
});
|
|
96
98
|
};
|
|
97
99
|
}, [context, editor, threadToNodes, threadIds]);
|
|
98
|
-
useEffect(() => {
|
|
100
|
+
react.useEffect(() => {
|
|
99
101
|
function onMutation(mutations) {
|
|
100
102
|
const state = editor.getEditorState();
|
|
101
103
|
setThreadToNodes((prev) => {
|
|
@@ -107,8 +109,8 @@ function CommentPluginProvider({ children }) {
|
|
|
107
109
|
nodes.delete(key);
|
|
108
110
|
}
|
|
109
111
|
} else if (mutation === "created" || mutation === "updated") {
|
|
110
|
-
const node =
|
|
111
|
-
if (
|
|
112
|
+
const node = lexical.$getNodeByKey(key);
|
|
113
|
+
if (!threadMarkNode.$isThreadMarkNode(node))
|
|
112
114
|
continue;
|
|
113
115
|
const threadIds2 = node.getIDs();
|
|
114
116
|
for (const id of threadIds2) {
|
|
@@ -122,21 +124,21 @@ function CommentPluginProvider({ children }) {
|
|
|
122
124
|
return updatedMap;
|
|
123
125
|
});
|
|
124
126
|
}
|
|
125
|
-
return editor.registerMutationListener(ThreadMarkNode, onMutation);
|
|
127
|
+
return editor.registerMutationListener(threadMarkNode.ThreadMarkNode, onMutation);
|
|
126
128
|
}, [editor]);
|
|
127
|
-
useEffect(() => {
|
|
129
|
+
react.useEffect(() => {
|
|
128
130
|
function $getThreadIds(selection) {
|
|
129
131
|
if (selection === null)
|
|
130
132
|
return [];
|
|
131
|
-
if (
|
|
133
|
+
if (!lexical.$isRangeSelection(selection))
|
|
132
134
|
return [];
|
|
133
135
|
const anchor = selection.anchor.getNode();
|
|
134
|
-
if (
|
|
136
|
+
if (!lexical.$isTextNode(anchor))
|
|
135
137
|
return [];
|
|
136
|
-
return
|
|
138
|
+
return getThreadMarkIds(anchor, selection.anchor.offset) ?? [];
|
|
137
139
|
}
|
|
138
140
|
function $onStateRead() {
|
|
139
|
-
const selection =
|
|
141
|
+
const selection = lexical.$getSelection();
|
|
140
142
|
const threadIds2 = $getThreadIds(selection).filter((id) => {
|
|
141
143
|
return store.outputs.threads.get().findMany(roomId, { resolved: false }, "asc").some((thread) => thread.id === id);
|
|
142
144
|
});
|
|
@@ -154,8 +156,8 @@ function CommentPluginProvider({ children }) {
|
|
|
154
156
|
unregisterUpdateListener();
|
|
155
157
|
unsubscribeCache();
|
|
156
158
|
};
|
|
157
|
-
}, [editor, client, roomId, store]);
|
|
158
|
-
useEffect(() => {
|
|
159
|
+
}, [editor, client$1, roomId, store]);
|
|
160
|
+
react.useEffect(() => {
|
|
159
161
|
function getActiveElements() {
|
|
160
162
|
const activeElements2 = /* @__PURE__ */ new Set();
|
|
161
163
|
for (const thread of activeThreads) {
|
|
@@ -181,12 +183,12 @@ function CommentPluginProvider({ children }) {
|
|
|
181
183
|
});
|
|
182
184
|
};
|
|
183
185
|
}, [activeThreads, editor, threadToNodes]);
|
|
184
|
-
useEffect(() => {
|
|
185
|
-
return registerNestedElementResolver(
|
|
186
|
+
react.useEffect(() => {
|
|
187
|
+
return utils.registerNestedElementResolver(
|
|
186
188
|
editor,
|
|
187
|
-
ThreadMarkNode,
|
|
189
|
+
threadMarkNode.ThreadMarkNode,
|
|
188
190
|
(from) => {
|
|
189
|
-
return
|
|
191
|
+
return threadMarkNode.$createThreadMarkNode(from.getIDs());
|
|
190
192
|
},
|
|
191
193
|
(from, to) => {
|
|
192
194
|
const ids = from.getIDs();
|
|
@@ -196,13 +198,13 @@ function CommentPluginProvider({ children }) {
|
|
|
196
198
|
}
|
|
197
199
|
);
|
|
198
200
|
}, [editor]);
|
|
199
|
-
return /* @__PURE__ */ jsx(OnDeleteThreadCallback.Provider, {
|
|
201
|
+
return /* @__PURE__ */ jsxRuntime.jsx(OnDeleteThreadCallback.Provider, {
|
|
200
202
|
value: handleThreadDelete,
|
|
201
|
-
children: /* @__PURE__ */ jsx(ActiveThreadsContext.Provider, {
|
|
203
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(ActiveThreadsContext.Provider, {
|
|
202
204
|
value: activeThreads,
|
|
203
|
-
children: /* @__PURE__ */ jsx(IsActiveThreadContext.Provider, {
|
|
205
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(IsActiveThreadContext.Provider, {
|
|
204
206
|
value: isThreadActive,
|
|
205
|
-
children: /* @__PURE__ */ jsx(ThreadToNodesContext.Provider, {
|
|
207
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(ThreadToNodesContext.Provider, {
|
|
206
208
|
value: threadToNodes,
|
|
207
209
|
children
|
|
208
210
|
})
|
|
@@ -211,7 +213,7 @@ function CommentPluginProvider({ children }) {
|
|
|
211
213
|
});
|
|
212
214
|
}
|
|
213
215
|
function useIsThreadActive(threadId) {
|
|
214
|
-
const isActive = useContext(IsActiveThreadContext);
|
|
216
|
+
const isActive = react.useContext(IsActiveThreadContext);
|
|
215
217
|
if (isActive === null) {
|
|
216
218
|
throw new Error(
|
|
217
219
|
"useIsThreadActive must be used within LiveblocksPlugin. For more information: https://liveblocks.io/docs/api-reference/liveblocks-react-lexical#useIsThreadActive"
|
|
@@ -220,5 +222,10 @@ function useIsThreadActive(threadId) {
|
|
|
220
222
|
return isActive(threadId);
|
|
221
223
|
}
|
|
222
224
|
|
|
223
|
-
|
|
224
|
-
|
|
225
|
+
exports.ActiveThreadsContext = ActiveThreadsContext;
|
|
226
|
+
exports.CommentPluginProvider = CommentPluginProvider;
|
|
227
|
+
exports.IsActiveThreadContext = IsActiveThreadContext;
|
|
228
|
+
exports.OnDeleteThreadCallback = OnDeleteThreadCallback;
|
|
229
|
+
exports.ThreadToNodesContext = ThreadToNodesContext;
|
|
230
|
+
exports.useIsThreadActive = useIsThreadActive;
|
|
231
|
+
//# sourceMappingURL=comment-plugin-provider.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"comment-plugin-provider.mjs","sources":["../../src/comments/comment-plugin-provider.tsx"],"sourcesContent":["import { useLexicalComposerContext } from \"@lexical/react/LexicalComposerContext\";\nimport {\n addClassNamesToElement,\n registerNestedElementResolver,\n removeClassNamesFromElement,\n} from \"@lexical/utils\";\nimport { shallow } from \"@liveblocks/client\";\nimport { useClient, useErrorListener, useRoom } from \"@liveblocks/react\";\nimport {\n getUmbrellaStoreForClient,\n useSignal,\n} from \"@liveblocks/react/_private\";\nimport type { BaseSelection, NodeKey, NodeMutation } from \"lexical\";\nimport {\n $getNodeByKey,\n $getSelection,\n $isRangeSelection,\n $isTextNode,\n} from \"lexical\";\nimport type { PropsWithChildren } from \"react\";\nimport {\n createContext,\n useCallback,\n useContext,\n useEffect,\n useState,\n} from \"react\";\n\nimport $getThreadMarkIds from \"./get-thread-mark-ids\";\nimport {\n $createThreadMarkNode,\n $isThreadMarkNode,\n ThreadMarkNode,\n} from \"./thread-mark-node\";\nimport $unwrapThreadMarkNode from \"./unwrap-thread-mark-node\";\n\nexport const OnDeleteThreadCallback = createContext<\n ((threadId: string) => void) | null\n>(null);\n\nexport const ActiveThreadsContext = createContext<string[] | null>(null);\n\nexport const IsActiveThreadContext = createContext<\n ((threadId: string) => boolean) | null\n>(null);\n\nexport type ThreadToNodesMap = Map<string, Set<NodeKey>>;\n\nexport const ThreadToNodesContext = createContext<ThreadToNodesMap | null>(\n null\n);\n\nexport function CommentPluginProvider({ children }: PropsWithChildren) {\n const [editor, context] = useLexicalComposerContext();\n\n const [threadToNodes, setThreadToNodes] = useState<ThreadToNodesMap>(\n new Map()\n ); // A map from thread id to a set of (thread mark) node keys that are associated with the thread\n\n const [activeThreads, setActiveThreads] = useState<string[]>([]); // The threads that are currently active (or selected) in the editor\n\n const client = useClient();\n\n const room = useRoom();\n\n const isThreadActive = useCallback(\n (threadId: string) => {\n return activeThreads.includes(threadId);\n },\n [activeThreads]\n );\n\n /**\n * Remove the thread id from the associated nodes and unwrap the nodes if they are no longer associated with any threads.\n * @param threadId The id of the thread to remove\n */\n const handleThreadDelete = useCallback(\n (threadId: string) => {\n editor.update(() => {\n // Retrieve node keys associated with the thread\n const keys = threadToNodes.get(threadId);\n if (keys === undefined) return;\n\n // Iterate over each thread node and disassociate the thread if from the node and unwrap the node if it is no longer associated with any threads\n for (const key of keys) {\n const node = $getNodeByKey(key);\n if (!$isThreadMarkNode(node)) continue;\n node.deleteID(threadId);\n\n if (node.getIDs().length === 0) {\n $unwrapThreadMarkNode(node);\n }\n }\n });\n },\n [editor, threadToNodes]\n );\n\n useErrorListener((err) => {\n // If thread creation fails, we remove the thread id from the associated nodes and unwrap the nodes if they are no longer associated with any threads\n if (\n err.context.type === \"CREATE_THREAD_ERROR\" &&\n err.context.roomId === room.id\n ) {\n handleThreadDelete(err.context.threadId);\n }\n });\n\n const store = getUmbrellaStoreForClient(client);\n\n const roomId = room.id;\n const threadIds = useSignal(\n store.outputs.threads,\n useCallback(\n (state) =>\n state\n .findMany(roomId, { resolved: false }, \"asc\")\n .map((thread) => thread.id),\n [roomId]\n ),\n shallow\n );\n\n /**\n * Only add styles to the thread mark elements that currently have threads associated with them.\n */\n useEffect(() => {\n function getThreadMarkElements() {\n const activeElements = new Set<HTMLElement>();\n\n for (const id of threadIds) {\n const keys = threadToNodes.get(id);\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 elements = getThreadMarkElements();\n\n const theme = context.getTheme();\n\n const classNames = [\"lb-root\", \"lb-lexical-thread-mark\"];\n if (theme && theme.liveblocks && \"threadMark\" in theme.liveblocks) {\n classNames.push((theme.liveblocks as { threadMark: string }).threadMark);\n }\n\n elements.forEach((element) => {\n addClassNamesToElement(element, ...classNames);\n });\n\n return () => {\n elements.forEach((element) => {\n removeClassNamesFromElement(element, ...classNames);\n });\n };\n }, [context, editor, threadToNodes, threadIds]);\n\n /**\n * Register a mutation listener that listens for mutations on 'ThreadMarkNode's and updates the map of thread to node keys accordingly.\n */\n useEffect(() => {\n function onMutation(mutations: Map<string, NodeMutation>) {\n const state = editor.getEditorState();\n setThreadToNodes((prev) => {\n const updatedMap = new Map(prev);\n state.read(() => {\n for (const [key, mutation] of mutations) {\n // If the node is destroyed, we remove its key from the map of thread to node keys\n if (mutation === \"destroyed\") {\n for (const [, nodes] of updatedMap) {\n nodes.delete(key);\n }\n }\n // Otherwise, if a new node is created or an existing node is updated, we update the map of thread to node keys to include the new/updated node\n else if (mutation === \"created\" || mutation === \"updated\") {\n const node = $getNodeByKey(key);\n if (!$isThreadMarkNode(node)) continue;\n\n const threadIds = node.getIDs();\n\n for (const id of threadIds) {\n const keys = updatedMap.get(id) ?? new Set();\n keys.add(key);\n updatedMap.set(id, keys);\n }\n }\n }\n });\n return updatedMap;\n });\n }\n\n return editor.registerMutationListener(ThreadMarkNode, onMutation);\n }, [editor]);\n\n /**\n * Register an update listener that listens for changes in the selection and updates the active threads accordingly.\n */\n useEffect(() => {\n function $getThreadIds(selection: BaseSelection | null): string[] {\n if (selection === null) return [];\n\n if (!$isRangeSelection(selection)) return [];\n\n const anchor = selection.anchor.getNode();\n if (!$isTextNode(anchor)) return [];\n\n return $getThreadMarkIds(anchor, selection.anchor.offset) ?? [];\n }\n\n function $onStateRead() {\n const selection = $getSelection();\n\n const threadIds = $getThreadIds(selection).filter((id) => {\n return store.outputs.threads\n .get()\n .findMany(roomId, { resolved: false }, \"asc\")\n .some((thread) => thread.id === id);\n });\n setActiveThreads(threadIds);\n }\n\n const unsubscribeCache = store.outputs.threads.subscribe(() => {\n editor.getEditorState().read($onStateRead);\n });\n\n const unregisterUpdateListener = editor.registerUpdateListener(\n ({ editorState: state }) => {\n state.read($onStateRead);\n }\n );\n\n return () => {\n unregisterUpdateListener();\n unsubscribeCache();\n };\n }, [editor, client, roomId, store]);\n\n /**\n * When active threads change, we add a data-state attribute and set it to \"active\" for all HTML elements that are associated with the active threads.\n */\n useEffect(() => {\n function getActiveElements() {\n const activeElements = new Set<HTMLElement>();\n\n for (const thread of activeThreads) {\n const keys = threadToNodes.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 activeElements.forEach((element) => {\n element.setAttribute(\"data-state\", \"active\");\n });\n\n return () => {\n activeElements.forEach((element) => {\n element.removeAttribute(\"data-state\");\n });\n };\n }, [activeThreads, editor, threadToNodes]);\n\n useEffect(() => {\n return registerNestedElementResolver<ThreadMarkNode>(\n editor,\n ThreadMarkNode,\n (from: ThreadMarkNode) => {\n return $createThreadMarkNode(from.getIDs());\n },\n (from: ThreadMarkNode, to: ThreadMarkNode) => {\n const ids = from.getIDs();\n ids.forEach((id) => {\n to.addID(id);\n });\n }\n );\n }, [editor]);\n\n return (\n <OnDeleteThreadCallback.Provider value={handleThreadDelete}>\n <ActiveThreadsContext.Provider value={activeThreads}>\n <IsActiveThreadContext.Provider value={isThreadActive}>\n <ThreadToNodesContext.Provider value={threadToNodes}>\n {children}\n </ThreadToNodesContext.Provider>\n </IsActiveThreadContext.Provider>\n </ActiveThreadsContext.Provider>\n </OnDeleteThreadCallback.Provider>\n );\n}\n\n/**\n * Returns whether the associated thread annotation for the given thread id is selected or not in the editor.\n * @param threadId The id of the thread to check if the associated annotation is selected or not.\n * @returns true if the associated annotation for the thread is selected, false otherwise.\n */\nexport function useIsThreadActive(threadId: string): boolean {\n const isActive = useContext(IsActiveThreadContext);\n if (isActive === null) {\n throw new Error(\n \"useIsThreadActive must be used within LiveblocksPlugin. For more information: https://liveblocks.io/docs/api-reference/liveblocks-react-lexical#useIsThreadActive\"\n );\n }\n\n return isActive(threadId);\n}\n"],"names":["threadIds","activeElements"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"comment-plugin-provider.cjs","sources":["../../src/comments/comment-plugin-provider.tsx"],"sourcesContent":["import { useLexicalComposerContext } from \"@lexical/react/LexicalComposerContext\";\nimport {\n addClassNamesToElement,\n registerNestedElementResolver,\n removeClassNamesFromElement,\n} from \"@lexical/utils\";\nimport { shallow } from \"@liveblocks/client\";\nimport { useClient, useErrorListener, useRoom } from \"@liveblocks/react\";\nimport {\n getUmbrellaStoreForClient,\n useSignal,\n} from \"@liveblocks/react/_private\";\nimport type { BaseSelection, NodeKey, NodeMutation } from \"lexical\";\nimport {\n $getNodeByKey,\n $getSelection,\n $isRangeSelection,\n $isTextNode,\n} from \"lexical\";\nimport type { PropsWithChildren } from \"react\";\nimport {\n createContext,\n useCallback,\n useContext,\n useEffect,\n useState,\n} from \"react\";\n\nimport $getThreadMarkIds from \"./get-thread-mark-ids\";\nimport {\n $createThreadMarkNode,\n $isThreadMarkNode,\n ThreadMarkNode,\n} from \"./thread-mark-node\";\nimport $unwrapThreadMarkNode from \"./unwrap-thread-mark-node\";\n\nexport const OnDeleteThreadCallback = createContext<\n ((threadId: string) => void) | null\n>(null);\n\nexport const ActiveThreadsContext = createContext<string[] | null>(null);\n\nexport const IsActiveThreadContext = createContext<\n ((threadId: string) => boolean) | null\n>(null);\n\nexport type ThreadToNodesMap = Map<string, Set<NodeKey>>;\n\nexport const ThreadToNodesContext = createContext<ThreadToNodesMap | null>(\n null\n);\n\nexport function CommentPluginProvider({ children }: PropsWithChildren) {\n const [editor, context] = useLexicalComposerContext();\n\n const [threadToNodes, setThreadToNodes] = useState<ThreadToNodesMap>(\n new Map()\n ); // A map from thread id to a set of (thread mark) node keys that are associated with the thread\n\n const [activeThreads, setActiveThreads] = useState<string[]>([]); // The threads that are currently active (or selected) in the editor\n\n const client = useClient();\n\n const room = useRoom();\n\n const isThreadActive = useCallback(\n (threadId: string) => {\n return activeThreads.includes(threadId);\n },\n [activeThreads]\n );\n\n /**\n * Remove the thread id from the associated nodes and unwrap the nodes if they are no longer associated with any threads.\n * @param threadId The id of the thread to remove\n */\n const handleThreadDelete = useCallback(\n (threadId: string) => {\n editor.update(() => {\n // Retrieve node keys associated with the thread\n const keys = threadToNodes.get(threadId);\n if (keys === undefined) return;\n\n // Iterate over each thread node and disassociate the thread if from the node and unwrap the node if it is no longer associated with any threads\n for (const key of keys) {\n const node = $getNodeByKey(key);\n if (!$isThreadMarkNode(node)) continue;\n node.deleteID(threadId);\n\n if (node.getIDs().length === 0) {\n $unwrapThreadMarkNode(node);\n }\n }\n });\n },\n [editor, threadToNodes]\n );\n\n useErrorListener((err) => {\n // If thread creation fails, we remove the thread id from the associated nodes and unwrap the nodes if they are no longer associated with any threads\n if (\n err.context.type === \"CREATE_THREAD_ERROR\" &&\n err.context.roomId === room.id\n ) {\n handleThreadDelete(err.context.threadId);\n }\n });\n\n const store = getUmbrellaStoreForClient(client);\n\n const roomId = room.id;\n const threadIds = useSignal(\n store.outputs.threads,\n useCallback(\n (state) =>\n state\n .findMany(roomId, { resolved: false }, \"asc\")\n .map((thread) => thread.id),\n [roomId]\n ),\n shallow\n );\n\n /**\n * Only add styles to the thread mark elements that currently have threads associated with them.\n */\n useEffect(() => {\n function getThreadMarkElements() {\n const activeElements = new Set<HTMLElement>();\n\n for (const id of threadIds) {\n const keys = threadToNodes.get(id);\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 elements = getThreadMarkElements();\n\n const theme = context.getTheme();\n\n const classNames = [\"lb-root\", \"lb-lexical-thread-mark\"];\n if (theme && theme.liveblocks && \"threadMark\" in theme.liveblocks) {\n classNames.push((theme.liveblocks as { threadMark: string }).threadMark);\n }\n\n elements.forEach((element) => {\n addClassNamesToElement(element, ...classNames);\n });\n\n return () => {\n elements.forEach((element) => {\n removeClassNamesFromElement(element, ...classNames);\n });\n };\n }, [context, editor, threadToNodes, threadIds]);\n\n /**\n * Register a mutation listener that listens for mutations on 'ThreadMarkNode's and updates the map of thread to node keys accordingly.\n */\n useEffect(() => {\n function onMutation(mutations: Map<string, NodeMutation>) {\n const state = editor.getEditorState();\n setThreadToNodes((prev) => {\n const updatedMap = new Map(prev);\n state.read(() => {\n for (const [key, mutation] of mutations) {\n // If the node is destroyed, we remove its key from the map of thread to node keys\n if (mutation === \"destroyed\") {\n for (const [, nodes] of updatedMap) {\n nodes.delete(key);\n }\n }\n // Otherwise, if a new node is created or an existing node is updated, we update the map of thread to node keys to include the new/updated node\n else if (mutation === \"created\" || mutation === \"updated\") {\n const node = $getNodeByKey(key);\n if (!$isThreadMarkNode(node)) continue;\n\n const threadIds = node.getIDs();\n\n for (const id of threadIds) {\n const keys = updatedMap.get(id) ?? new Set();\n keys.add(key);\n updatedMap.set(id, keys);\n }\n }\n }\n });\n return updatedMap;\n });\n }\n\n return editor.registerMutationListener(ThreadMarkNode, onMutation);\n }, [editor]);\n\n /**\n * Register an update listener that listens for changes in the selection and updates the active threads accordingly.\n */\n useEffect(() => {\n function $getThreadIds(selection: BaseSelection | null): string[] {\n if (selection === null) return [];\n\n if (!$isRangeSelection(selection)) return [];\n\n const anchor = selection.anchor.getNode();\n if (!$isTextNode(anchor)) return [];\n\n return $getThreadMarkIds(anchor, selection.anchor.offset) ?? [];\n }\n\n function $onStateRead() {\n const selection = $getSelection();\n\n const threadIds = $getThreadIds(selection).filter((id) => {\n return store.outputs.threads\n .get()\n .findMany(roomId, { resolved: false }, \"asc\")\n .some((thread) => thread.id === id);\n });\n setActiveThreads(threadIds);\n }\n\n const unsubscribeCache = store.outputs.threads.subscribe(() => {\n editor.getEditorState().read($onStateRead);\n });\n\n const unregisterUpdateListener = editor.registerUpdateListener(\n ({ editorState: state }) => {\n state.read($onStateRead);\n }\n );\n\n return () => {\n unregisterUpdateListener();\n unsubscribeCache();\n };\n }, [editor, client, roomId, store]);\n\n /**\n * When active threads change, we add a data-state attribute and set it to \"active\" for all HTML elements that are associated with the active threads.\n */\n useEffect(() => {\n function getActiveElements() {\n const activeElements = new Set<HTMLElement>();\n\n for (const thread of activeThreads) {\n const keys = threadToNodes.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 activeElements.forEach((element) => {\n element.setAttribute(\"data-state\", \"active\");\n });\n\n return () => {\n activeElements.forEach((element) => {\n element.removeAttribute(\"data-state\");\n });\n };\n }, [activeThreads, editor, threadToNodes]);\n\n useEffect(() => {\n return registerNestedElementResolver<ThreadMarkNode>(\n editor,\n ThreadMarkNode,\n (from: ThreadMarkNode) => {\n return $createThreadMarkNode(from.getIDs());\n },\n (from: ThreadMarkNode, to: ThreadMarkNode) => {\n const ids = from.getIDs();\n ids.forEach((id) => {\n to.addID(id);\n });\n }\n );\n }, [editor]);\n\n return (\n <OnDeleteThreadCallback.Provider value={handleThreadDelete}>\n <ActiveThreadsContext.Provider value={activeThreads}>\n <IsActiveThreadContext.Provider value={isThreadActive}>\n <ThreadToNodesContext.Provider value={threadToNodes}>\n {children}\n </ThreadToNodesContext.Provider>\n </IsActiveThreadContext.Provider>\n </ActiveThreadsContext.Provider>\n </OnDeleteThreadCallback.Provider>\n );\n}\n\n/**\n * Returns whether the associated thread annotation for the given thread id is selected or not in the editor.\n * @param threadId The id of the thread to check if the associated annotation is selected or not.\n * @returns true if the associated annotation for the thread is selected, false otherwise.\n */\nexport function useIsThreadActive(threadId: string): boolean {\n const isActive = useContext(IsActiveThreadContext);\n if (isActive === null) {\n throw new Error(\n \"useIsThreadActive must be used within LiveblocksPlugin. For more information: https://liveblocks.io/docs/api-reference/liveblocks-react-lexical#useIsThreadActive\"\n );\n }\n\n return isActive(threadId);\n}\n"],"names":["createContext","useLexicalComposerContext","useState","client","useClient","useRoom","useCallback","$getNodeByKey","$isThreadMarkNode","$unwrapThreadMarkNode","useErrorListener","getUmbrellaStoreForClient","useSignal","shallow","useEffect","addClassNamesToElement","removeClassNamesFromElement","threadIds","ThreadMarkNode","$isRangeSelection","$isTextNode","$getThreadMarkIds","$getSelection","activeElements","registerNestedElementResolver","$createThreadMarkNode","jsx","useContext"],"mappings":"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"}
|
|
@@ -1,72 +1,70 @@
|
|
|
1
|
-
|
|
1
|
+
import { jsx } from 'react/jsx-runtime';
|
|
2
|
+
import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext';
|
|
3
|
+
import { addClassNamesToElement, removeClassNamesFromElement, registerNestedElementResolver } from '@lexical/utils';
|
|
4
|
+
import { shallow } from '@liveblocks/client';
|
|
5
|
+
import { useClient, useRoom, useErrorListener } from '@liveblocks/react';
|
|
6
|
+
import { getUmbrellaStoreForClient, useSignal } from '@liveblocks/react/_private';
|
|
7
|
+
import { $getNodeByKey, $isRangeSelection, $isTextNode, $getSelection } from 'lexical';
|
|
8
|
+
import { createContext, useState, useCallback, useEffect, useContext } from 'react';
|
|
9
|
+
import $getThreadMarkIds from './get-thread-mark-ids.js';
|
|
10
|
+
import { $isThreadMarkNode, ThreadMarkNode, $createThreadMarkNode } from './thread-mark-node.js';
|
|
11
|
+
import $unwrapThreadMarkNode from './unwrap-thread-mark-node.js';
|
|
2
12
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
var react$1 = require('@liveblocks/react');
|
|
8
|
-
var _private = require('@liveblocks/react/_private');
|
|
9
|
-
var lexical = require('lexical');
|
|
10
|
-
var react = require('react');
|
|
11
|
-
var getThreadMarkIds = require('./get-thread-mark-ids.js');
|
|
12
|
-
var threadMarkNode = require('./thread-mark-node.js');
|
|
13
|
-
var unwrapThreadMarkNode = require('./unwrap-thread-mark-node.js');
|
|
14
|
-
|
|
15
|
-
const OnDeleteThreadCallback = react.createContext(null);
|
|
16
|
-
const ActiveThreadsContext = react.createContext(null);
|
|
17
|
-
const IsActiveThreadContext = react.createContext(null);
|
|
18
|
-
const ThreadToNodesContext = react.createContext(
|
|
13
|
+
const OnDeleteThreadCallback = createContext(null);
|
|
14
|
+
const ActiveThreadsContext = createContext(null);
|
|
15
|
+
const IsActiveThreadContext = createContext(null);
|
|
16
|
+
const ThreadToNodesContext = createContext(
|
|
19
17
|
null
|
|
20
18
|
);
|
|
21
19
|
function CommentPluginProvider({ children }) {
|
|
22
|
-
const [editor, context] =
|
|
23
|
-
const [threadToNodes, setThreadToNodes] =
|
|
20
|
+
const [editor, context] = useLexicalComposerContext();
|
|
21
|
+
const [threadToNodes, setThreadToNodes] = useState(
|
|
24
22
|
/* @__PURE__ */ new Map()
|
|
25
23
|
);
|
|
26
|
-
const [activeThreads, setActiveThreads] =
|
|
27
|
-
const client
|
|
28
|
-
const room =
|
|
29
|
-
const isThreadActive =
|
|
24
|
+
const [activeThreads, setActiveThreads] = useState([]);
|
|
25
|
+
const client = useClient();
|
|
26
|
+
const room = useRoom();
|
|
27
|
+
const isThreadActive = useCallback(
|
|
30
28
|
(threadId) => {
|
|
31
29
|
return activeThreads.includes(threadId);
|
|
32
30
|
},
|
|
33
31
|
[activeThreads]
|
|
34
32
|
);
|
|
35
|
-
const handleThreadDelete =
|
|
33
|
+
const handleThreadDelete = useCallback(
|
|
36
34
|
(threadId) => {
|
|
37
35
|
editor.update(() => {
|
|
38
36
|
const keys = threadToNodes.get(threadId);
|
|
39
37
|
if (keys === void 0)
|
|
40
38
|
return;
|
|
41
39
|
for (const key of keys) {
|
|
42
|
-
const node =
|
|
43
|
-
if (
|
|
40
|
+
const node = $getNodeByKey(key);
|
|
41
|
+
if (!$isThreadMarkNode(node))
|
|
44
42
|
continue;
|
|
45
43
|
node.deleteID(threadId);
|
|
46
44
|
if (node.getIDs().length === 0) {
|
|
47
|
-
unwrapThreadMarkNode(node);
|
|
45
|
+
$unwrapThreadMarkNode(node);
|
|
48
46
|
}
|
|
49
47
|
}
|
|
50
48
|
});
|
|
51
49
|
},
|
|
52
50
|
[editor, threadToNodes]
|
|
53
51
|
);
|
|
54
|
-
|
|
52
|
+
useErrorListener((err) => {
|
|
55
53
|
if (err.context.type === "CREATE_THREAD_ERROR" && err.context.roomId === room.id) {
|
|
56
54
|
handleThreadDelete(err.context.threadId);
|
|
57
55
|
}
|
|
58
56
|
});
|
|
59
|
-
const store =
|
|
57
|
+
const store = getUmbrellaStoreForClient(client);
|
|
60
58
|
const roomId = room.id;
|
|
61
|
-
const threadIds =
|
|
59
|
+
const threadIds = useSignal(
|
|
62
60
|
store.outputs.threads,
|
|
63
|
-
|
|
61
|
+
useCallback(
|
|
64
62
|
(state) => state.findMany(roomId, { resolved: false }, "asc").map((thread) => thread.id),
|
|
65
63
|
[roomId]
|
|
66
64
|
),
|
|
67
|
-
|
|
65
|
+
shallow
|
|
68
66
|
);
|
|
69
|
-
|
|
67
|
+
useEffect(() => {
|
|
70
68
|
function getThreadMarkElements() {
|
|
71
69
|
const activeElements = /* @__PURE__ */ new Set();
|
|
72
70
|
for (const id of threadIds) {
|
|
@@ -89,15 +87,15 @@ function CommentPluginProvider({ children }) {
|
|
|
89
87
|
classNames.push(theme.liveblocks.threadMark);
|
|
90
88
|
}
|
|
91
89
|
elements.forEach((element) => {
|
|
92
|
-
|
|
90
|
+
addClassNamesToElement(element, ...classNames);
|
|
93
91
|
});
|
|
94
92
|
return () => {
|
|
95
93
|
elements.forEach((element) => {
|
|
96
|
-
|
|
94
|
+
removeClassNamesFromElement(element, ...classNames);
|
|
97
95
|
});
|
|
98
96
|
};
|
|
99
97
|
}, [context, editor, threadToNodes, threadIds]);
|
|
100
|
-
|
|
98
|
+
useEffect(() => {
|
|
101
99
|
function onMutation(mutations) {
|
|
102
100
|
const state = editor.getEditorState();
|
|
103
101
|
setThreadToNodes((prev) => {
|
|
@@ -109,8 +107,8 @@ function CommentPluginProvider({ children }) {
|
|
|
109
107
|
nodes.delete(key);
|
|
110
108
|
}
|
|
111
109
|
} else if (mutation === "created" || mutation === "updated") {
|
|
112
|
-
const node =
|
|
113
|
-
if (
|
|
110
|
+
const node = $getNodeByKey(key);
|
|
111
|
+
if (!$isThreadMarkNode(node))
|
|
114
112
|
continue;
|
|
115
113
|
const threadIds2 = node.getIDs();
|
|
116
114
|
for (const id of threadIds2) {
|
|
@@ -124,21 +122,21 @@ function CommentPluginProvider({ children }) {
|
|
|
124
122
|
return updatedMap;
|
|
125
123
|
});
|
|
126
124
|
}
|
|
127
|
-
return editor.registerMutationListener(
|
|
125
|
+
return editor.registerMutationListener(ThreadMarkNode, onMutation);
|
|
128
126
|
}, [editor]);
|
|
129
|
-
|
|
127
|
+
useEffect(() => {
|
|
130
128
|
function $getThreadIds(selection) {
|
|
131
129
|
if (selection === null)
|
|
132
130
|
return [];
|
|
133
|
-
if (
|
|
131
|
+
if (!$isRangeSelection(selection))
|
|
134
132
|
return [];
|
|
135
133
|
const anchor = selection.anchor.getNode();
|
|
136
|
-
if (
|
|
134
|
+
if (!$isTextNode(anchor))
|
|
137
135
|
return [];
|
|
138
|
-
return getThreadMarkIds(anchor, selection.anchor.offset) ?? [];
|
|
136
|
+
return $getThreadMarkIds(anchor, selection.anchor.offset) ?? [];
|
|
139
137
|
}
|
|
140
138
|
function $onStateRead() {
|
|
141
|
-
const selection =
|
|
139
|
+
const selection = $getSelection();
|
|
142
140
|
const threadIds2 = $getThreadIds(selection).filter((id) => {
|
|
143
141
|
return store.outputs.threads.get().findMany(roomId, { resolved: false }, "asc").some((thread) => thread.id === id);
|
|
144
142
|
});
|
|
@@ -156,8 +154,8 @@ function CommentPluginProvider({ children }) {
|
|
|
156
154
|
unregisterUpdateListener();
|
|
157
155
|
unsubscribeCache();
|
|
158
156
|
};
|
|
159
|
-
}, [editor, client
|
|
160
|
-
|
|
157
|
+
}, [editor, client, roomId, store]);
|
|
158
|
+
useEffect(() => {
|
|
161
159
|
function getActiveElements() {
|
|
162
160
|
const activeElements2 = /* @__PURE__ */ new Set();
|
|
163
161
|
for (const thread of activeThreads) {
|
|
@@ -183,12 +181,12 @@ function CommentPluginProvider({ children }) {
|
|
|
183
181
|
});
|
|
184
182
|
};
|
|
185
183
|
}, [activeThreads, editor, threadToNodes]);
|
|
186
|
-
|
|
187
|
-
return
|
|
184
|
+
useEffect(() => {
|
|
185
|
+
return registerNestedElementResolver(
|
|
188
186
|
editor,
|
|
189
|
-
|
|
187
|
+
ThreadMarkNode,
|
|
190
188
|
(from) => {
|
|
191
|
-
return
|
|
189
|
+
return $createThreadMarkNode(from.getIDs());
|
|
192
190
|
},
|
|
193
191
|
(from, to) => {
|
|
194
192
|
const ids = from.getIDs();
|
|
@@ -198,13 +196,13 @@ function CommentPluginProvider({ children }) {
|
|
|
198
196
|
}
|
|
199
197
|
);
|
|
200
198
|
}, [editor]);
|
|
201
|
-
return /* @__PURE__ */
|
|
199
|
+
return /* @__PURE__ */ jsx(OnDeleteThreadCallback.Provider, {
|
|
202
200
|
value: handleThreadDelete,
|
|
203
|
-
children: /* @__PURE__ */
|
|
201
|
+
children: /* @__PURE__ */ jsx(ActiveThreadsContext.Provider, {
|
|
204
202
|
value: activeThreads,
|
|
205
|
-
children: /* @__PURE__ */
|
|
203
|
+
children: /* @__PURE__ */ jsx(IsActiveThreadContext.Provider, {
|
|
206
204
|
value: isThreadActive,
|
|
207
|
-
children: /* @__PURE__ */
|
|
205
|
+
children: /* @__PURE__ */ jsx(ThreadToNodesContext.Provider, {
|
|
208
206
|
value: threadToNodes,
|
|
209
207
|
children
|
|
210
208
|
})
|
|
@@ -213,7 +211,7 @@ function CommentPluginProvider({ children }) {
|
|
|
213
211
|
});
|
|
214
212
|
}
|
|
215
213
|
function useIsThreadActive(threadId) {
|
|
216
|
-
const isActive =
|
|
214
|
+
const isActive = useContext(IsActiveThreadContext);
|
|
217
215
|
if (isActive === null) {
|
|
218
216
|
throw new Error(
|
|
219
217
|
"useIsThreadActive must be used within LiveblocksPlugin. For more information: https://liveblocks.io/docs/api-reference/liveblocks-react-lexical#useIsThreadActive"
|
|
@@ -222,10 +220,5 @@ function useIsThreadActive(threadId) {
|
|
|
222
220
|
return isActive(threadId);
|
|
223
221
|
}
|
|
224
222
|
|
|
225
|
-
|
|
226
|
-
exports.CommentPluginProvider = CommentPluginProvider;
|
|
227
|
-
exports.IsActiveThreadContext = IsActiveThreadContext;
|
|
228
|
-
exports.OnDeleteThreadCallback = OnDeleteThreadCallback;
|
|
229
|
-
exports.ThreadToNodesContext = ThreadToNodesContext;
|
|
230
|
-
exports.useIsThreadActive = useIsThreadActive;
|
|
223
|
+
export { ActiveThreadsContext, CommentPluginProvider, IsActiveThreadContext, OnDeleteThreadCallback, ThreadToNodesContext, useIsThreadActive };
|
|
231
224
|
//# sourceMappingURL=comment-plugin-provider.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"comment-plugin-provider.js","sources":["../../src/comments/comment-plugin-provider.tsx"],"sourcesContent":["import { useLexicalComposerContext } from \"@lexical/react/LexicalComposerContext\";\nimport {\n addClassNamesToElement,\n registerNestedElementResolver,\n removeClassNamesFromElement,\n} from \"@lexical/utils\";\nimport { shallow } from \"@liveblocks/client\";\nimport { useClient, useErrorListener, useRoom } from \"@liveblocks/react\";\nimport {\n getUmbrellaStoreForClient,\n useSignal,\n} from \"@liveblocks/react/_private\";\nimport type { BaseSelection, NodeKey, NodeMutation } from \"lexical\";\nimport {\n $getNodeByKey,\n $getSelection,\n $isRangeSelection,\n $isTextNode,\n} from \"lexical\";\nimport type { PropsWithChildren } from \"react\";\nimport {\n createContext,\n useCallback,\n useContext,\n useEffect,\n useState,\n} from \"react\";\n\nimport $getThreadMarkIds from \"./get-thread-mark-ids\";\nimport {\n $createThreadMarkNode,\n $isThreadMarkNode,\n ThreadMarkNode,\n} from \"./thread-mark-node\";\nimport $unwrapThreadMarkNode from \"./unwrap-thread-mark-node\";\n\nexport const OnDeleteThreadCallback = createContext<\n ((threadId: string) => void) | null\n>(null);\n\nexport const ActiveThreadsContext = createContext<string[] | null>(null);\n\nexport const IsActiveThreadContext = createContext<\n ((threadId: string) => boolean) | null\n>(null);\n\nexport type ThreadToNodesMap = Map<string, Set<NodeKey>>;\n\nexport const ThreadToNodesContext = createContext<ThreadToNodesMap | null>(\n null\n);\n\nexport function CommentPluginProvider({ children }: PropsWithChildren) {\n const [editor, context] = useLexicalComposerContext();\n\n const [threadToNodes, setThreadToNodes] = useState<ThreadToNodesMap>(\n new Map()\n ); // A map from thread id to a set of (thread mark) node keys that are associated with the thread\n\n const [activeThreads, setActiveThreads] = useState<string[]>([]); // The threads that are currently active (or selected) in the editor\n\n const client = useClient();\n\n const room = useRoom();\n\n const isThreadActive = useCallback(\n (threadId: string) => {\n return activeThreads.includes(threadId);\n },\n [activeThreads]\n );\n\n /**\n * Remove the thread id from the associated nodes and unwrap the nodes if they are no longer associated with any threads.\n * @param threadId The id of the thread to remove\n */\n const handleThreadDelete = useCallback(\n (threadId: string) => {\n editor.update(() => {\n // Retrieve node keys associated with the thread\n const keys = threadToNodes.get(threadId);\n if (keys === undefined) return;\n\n // Iterate over each thread node and disassociate the thread if from the node and unwrap the node if it is no longer associated with any threads\n for (const key of keys) {\n const node = $getNodeByKey(key);\n if (!$isThreadMarkNode(node)) continue;\n node.deleteID(threadId);\n\n if (node.getIDs().length === 0) {\n $unwrapThreadMarkNode(node);\n }\n }\n });\n },\n [editor, threadToNodes]\n );\n\n useErrorListener((err) => {\n // If thread creation fails, we remove the thread id from the associated nodes and unwrap the nodes if they are no longer associated with any threads\n if (\n err.context.type === \"CREATE_THREAD_ERROR\" &&\n err.context.roomId === room.id\n ) {\n handleThreadDelete(err.context.threadId);\n }\n });\n\n const store = getUmbrellaStoreForClient(client);\n\n const roomId = room.id;\n const threadIds = useSignal(\n store.outputs.threads,\n useCallback(\n (state) =>\n state\n .findMany(roomId, { resolved: false }, \"asc\")\n .map((thread) => thread.id),\n [roomId]\n ),\n shallow\n );\n\n /**\n * Only add styles to the thread mark elements that currently have threads associated with them.\n */\n useEffect(() => {\n function getThreadMarkElements() {\n const activeElements = new Set<HTMLElement>();\n\n for (const id of threadIds) {\n const keys = threadToNodes.get(id);\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 elements = getThreadMarkElements();\n\n const theme = context.getTheme();\n\n const classNames = [\"lb-root\", \"lb-lexical-thread-mark\"];\n if (theme && theme.liveblocks && \"threadMark\" in theme.liveblocks) {\n classNames.push((theme.liveblocks as { threadMark: string }).threadMark);\n }\n\n elements.forEach((element) => {\n addClassNamesToElement(element, ...classNames);\n });\n\n return () => {\n elements.forEach((element) => {\n removeClassNamesFromElement(element, ...classNames);\n });\n };\n }, [context, editor, threadToNodes, threadIds]);\n\n /**\n * Register a mutation listener that listens for mutations on 'ThreadMarkNode's and updates the map of thread to node keys accordingly.\n */\n useEffect(() => {\n function onMutation(mutations: Map<string, NodeMutation>) {\n const state = editor.getEditorState();\n setThreadToNodes((prev) => {\n const updatedMap = new Map(prev);\n state.read(() => {\n for (const [key, mutation] of mutations) {\n // If the node is destroyed, we remove its key from the map of thread to node keys\n if (mutation === \"destroyed\") {\n for (const [, nodes] of updatedMap) {\n nodes.delete(key);\n }\n }\n // Otherwise, if a new node is created or an existing node is updated, we update the map of thread to node keys to include the new/updated node\n else if (mutation === \"created\" || mutation === \"updated\") {\n const node = $getNodeByKey(key);\n if (!$isThreadMarkNode(node)) continue;\n\n const threadIds = node.getIDs();\n\n for (const id of threadIds) {\n const keys = updatedMap.get(id) ?? new Set();\n keys.add(key);\n updatedMap.set(id, keys);\n }\n }\n }\n });\n return updatedMap;\n });\n }\n\n return editor.registerMutationListener(ThreadMarkNode, onMutation);\n }, [editor]);\n\n /**\n * Register an update listener that listens for changes in the selection and updates the active threads accordingly.\n */\n useEffect(() => {\n function $getThreadIds(selection: BaseSelection | null): string[] {\n if (selection === null) return [];\n\n if (!$isRangeSelection(selection)) return [];\n\n const anchor = selection.anchor.getNode();\n if (!$isTextNode(anchor)) return [];\n\n return $getThreadMarkIds(anchor, selection.anchor.offset) ?? [];\n }\n\n function $onStateRead() {\n const selection = $getSelection();\n\n const threadIds = $getThreadIds(selection).filter((id) => {\n return store.outputs.threads\n .get()\n .findMany(roomId, { resolved: false }, \"asc\")\n .some((thread) => thread.id === id);\n });\n setActiveThreads(threadIds);\n }\n\n const unsubscribeCache = store.outputs.threads.subscribe(() => {\n editor.getEditorState().read($onStateRead);\n });\n\n const unregisterUpdateListener = editor.registerUpdateListener(\n ({ editorState: state }) => {\n state.read($onStateRead);\n }\n );\n\n return () => {\n unregisterUpdateListener();\n unsubscribeCache();\n };\n }, [editor, client, roomId, store]);\n\n /**\n * When active threads change, we add a data-state attribute and set it to \"active\" for all HTML elements that are associated with the active threads.\n */\n useEffect(() => {\n function getActiveElements() {\n const activeElements = new Set<HTMLElement>();\n\n for (const thread of activeThreads) {\n const keys = threadToNodes.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 activeElements.forEach((element) => {\n element.setAttribute(\"data-state\", \"active\");\n });\n\n return () => {\n activeElements.forEach((element) => {\n element.removeAttribute(\"data-state\");\n });\n };\n }, [activeThreads, editor, threadToNodes]);\n\n useEffect(() => {\n return registerNestedElementResolver<ThreadMarkNode>(\n editor,\n ThreadMarkNode,\n (from: ThreadMarkNode) => {\n return $createThreadMarkNode(from.getIDs());\n },\n (from: ThreadMarkNode, to: ThreadMarkNode) => {\n const ids = from.getIDs();\n ids.forEach((id) => {\n to.addID(id);\n });\n }\n );\n }, [editor]);\n\n return (\n <OnDeleteThreadCallback.Provider value={handleThreadDelete}>\n <ActiveThreadsContext.Provider value={activeThreads}>\n <IsActiveThreadContext.Provider value={isThreadActive}>\n <ThreadToNodesContext.Provider value={threadToNodes}>\n {children}\n </ThreadToNodesContext.Provider>\n </IsActiveThreadContext.Provider>\n </ActiveThreadsContext.Provider>\n </OnDeleteThreadCallback.Provider>\n );\n}\n\n/**\n * Returns whether the associated thread annotation for the given thread id is selected or not in the editor.\n * @param threadId The id of the thread to check if the associated annotation is selected or not.\n * @returns true if the associated annotation for the thread is selected, false otherwise.\n */\nexport function useIsThreadActive(threadId: string): boolean {\n const isActive = useContext(IsActiveThreadContext);\n if (isActive === null) {\n throw new Error(\n \"useIsThreadActive must be used within LiveblocksPlugin. For more information: https://liveblocks.io/docs/api-reference/liveblocks-react-lexical#useIsThreadActive\"\n );\n }\n\n return isActive(threadId);\n}\n"],"names":["createContext","useLexicalComposerContext","useState","client","useClient","useRoom","useCallback","$getNodeByKey","$isThreadMarkNode","$unwrapThreadMarkNode","useErrorListener","getUmbrellaStoreForClient","useSignal","shallow","useEffect","addClassNamesToElement","removeClassNamesFromElement","threadIds","ThreadMarkNode","$isRangeSelection","$isTextNode","$getThreadMarkIds","$getSelection","activeElements","registerNestedElementResolver","$createThreadMarkNode","jsx","useContext"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"comment-plugin-provider.js","sources":["../../src/comments/comment-plugin-provider.tsx"],"sourcesContent":["import { useLexicalComposerContext } from \"@lexical/react/LexicalComposerContext\";\nimport {\n addClassNamesToElement,\n registerNestedElementResolver,\n removeClassNamesFromElement,\n} from \"@lexical/utils\";\nimport { shallow } from \"@liveblocks/client\";\nimport { useClient, useErrorListener, useRoom } from \"@liveblocks/react\";\nimport {\n getUmbrellaStoreForClient,\n useSignal,\n} from \"@liveblocks/react/_private\";\nimport type { BaseSelection, NodeKey, NodeMutation } from \"lexical\";\nimport {\n $getNodeByKey,\n $getSelection,\n $isRangeSelection,\n $isTextNode,\n} from \"lexical\";\nimport type { PropsWithChildren } from \"react\";\nimport {\n createContext,\n useCallback,\n useContext,\n useEffect,\n useState,\n} from \"react\";\n\nimport $getThreadMarkIds from \"./get-thread-mark-ids\";\nimport {\n $createThreadMarkNode,\n $isThreadMarkNode,\n ThreadMarkNode,\n} from \"./thread-mark-node\";\nimport $unwrapThreadMarkNode from \"./unwrap-thread-mark-node\";\n\nexport const OnDeleteThreadCallback = createContext<\n ((threadId: string) => void) | null\n>(null);\n\nexport const ActiveThreadsContext = createContext<string[] | null>(null);\n\nexport const IsActiveThreadContext = createContext<\n ((threadId: string) => boolean) | null\n>(null);\n\nexport type ThreadToNodesMap = Map<string, Set<NodeKey>>;\n\nexport const ThreadToNodesContext = createContext<ThreadToNodesMap | null>(\n null\n);\n\nexport function CommentPluginProvider({ children }: PropsWithChildren) {\n const [editor, context] = useLexicalComposerContext();\n\n const [threadToNodes, setThreadToNodes] = useState<ThreadToNodesMap>(\n new Map()\n ); // A map from thread id to a set of (thread mark) node keys that are associated with the thread\n\n const [activeThreads, setActiveThreads] = useState<string[]>([]); // The threads that are currently active (or selected) in the editor\n\n const client = useClient();\n\n const room = useRoom();\n\n const isThreadActive = useCallback(\n (threadId: string) => {\n return activeThreads.includes(threadId);\n },\n [activeThreads]\n );\n\n /**\n * Remove the thread id from the associated nodes and unwrap the nodes if they are no longer associated with any threads.\n * @param threadId The id of the thread to remove\n */\n const handleThreadDelete = useCallback(\n (threadId: string) => {\n editor.update(() => {\n // Retrieve node keys associated with the thread\n const keys = threadToNodes.get(threadId);\n if (keys === undefined) return;\n\n // Iterate over each thread node and disassociate the thread if from the node and unwrap the node if it is no longer associated with any threads\n for (const key of keys) {\n const node = $getNodeByKey(key);\n if (!$isThreadMarkNode(node)) continue;\n node.deleteID(threadId);\n\n if (node.getIDs().length === 0) {\n $unwrapThreadMarkNode(node);\n }\n }\n });\n },\n [editor, threadToNodes]\n );\n\n useErrorListener((err) => {\n // If thread creation fails, we remove the thread id from the associated nodes and unwrap the nodes if they are no longer associated with any threads\n if (\n err.context.type === \"CREATE_THREAD_ERROR\" &&\n err.context.roomId === room.id\n ) {\n handleThreadDelete(err.context.threadId);\n }\n });\n\n const store = getUmbrellaStoreForClient(client);\n\n const roomId = room.id;\n const threadIds = useSignal(\n store.outputs.threads,\n useCallback(\n (state) =>\n state\n .findMany(roomId, { resolved: false }, \"asc\")\n .map((thread) => thread.id),\n [roomId]\n ),\n shallow\n );\n\n /**\n * Only add styles to the thread mark elements that currently have threads associated with them.\n */\n useEffect(() => {\n function getThreadMarkElements() {\n const activeElements = new Set<HTMLElement>();\n\n for (const id of threadIds) {\n const keys = threadToNodes.get(id);\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 elements = getThreadMarkElements();\n\n const theme = context.getTheme();\n\n const classNames = [\"lb-root\", \"lb-lexical-thread-mark\"];\n if (theme && theme.liveblocks && \"threadMark\" in theme.liveblocks) {\n classNames.push((theme.liveblocks as { threadMark: string }).threadMark);\n }\n\n elements.forEach((element) => {\n addClassNamesToElement(element, ...classNames);\n });\n\n return () => {\n elements.forEach((element) => {\n removeClassNamesFromElement(element, ...classNames);\n });\n };\n }, [context, editor, threadToNodes, threadIds]);\n\n /**\n * Register a mutation listener that listens for mutations on 'ThreadMarkNode's and updates the map of thread to node keys accordingly.\n */\n useEffect(() => {\n function onMutation(mutations: Map<string, NodeMutation>) {\n const state = editor.getEditorState();\n setThreadToNodes((prev) => {\n const updatedMap = new Map(prev);\n state.read(() => {\n for (const [key, mutation] of mutations) {\n // If the node is destroyed, we remove its key from the map of thread to node keys\n if (mutation === \"destroyed\") {\n for (const [, nodes] of updatedMap) {\n nodes.delete(key);\n }\n }\n // Otherwise, if a new node is created or an existing node is updated, we update the map of thread to node keys to include the new/updated node\n else if (mutation === \"created\" || mutation === \"updated\") {\n const node = $getNodeByKey(key);\n if (!$isThreadMarkNode(node)) continue;\n\n const threadIds = node.getIDs();\n\n for (const id of threadIds) {\n const keys = updatedMap.get(id) ?? new Set();\n keys.add(key);\n updatedMap.set(id, keys);\n }\n }\n }\n });\n return updatedMap;\n });\n }\n\n return editor.registerMutationListener(ThreadMarkNode, onMutation);\n }, [editor]);\n\n /**\n * Register an update listener that listens for changes in the selection and updates the active threads accordingly.\n */\n useEffect(() => {\n function $getThreadIds(selection: BaseSelection | null): string[] {\n if (selection === null) return [];\n\n if (!$isRangeSelection(selection)) return [];\n\n const anchor = selection.anchor.getNode();\n if (!$isTextNode(anchor)) return [];\n\n return $getThreadMarkIds(anchor, selection.anchor.offset) ?? [];\n }\n\n function $onStateRead() {\n const selection = $getSelection();\n\n const threadIds = $getThreadIds(selection).filter((id) => {\n return store.outputs.threads\n .get()\n .findMany(roomId, { resolved: false }, \"asc\")\n .some((thread) => thread.id === id);\n });\n setActiveThreads(threadIds);\n }\n\n const unsubscribeCache = store.outputs.threads.subscribe(() => {\n editor.getEditorState().read($onStateRead);\n });\n\n const unregisterUpdateListener = editor.registerUpdateListener(\n ({ editorState: state }) => {\n state.read($onStateRead);\n }\n );\n\n return () => {\n unregisterUpdateListener();\n unsubscribeCache();\n };\n }, [editor, client, roomId, store]);\n\n /**\n * When active threads change, we add a data-state attribute and set it to \"active\" for all HTML elements that are associated with the active threads.\n */\n useEffect(() => {\n function getActiveElements() {\n const activeElements = new Set<HTMLElement>();\n\n for (const thread of activeThreads) {\n const keys = threadToNodes.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 activeElements.forEach((element) => {\n element.setAttribute(\"data-state\", \"active\");\n });\n\n return () => {\n activeElements.forEach((element) => {\n element.removeAttribute(\"data-state\");\n });\n };\n }, [activeThreads, editor, threadToNodes]);\n\n useEffect(() => {\n return registerNestedElementResolver<ThreadMarkNode>(\n editor,\n ThreadMarkNode,\n (from: ThreadMarkNode) => {\n return $createThreadMarkNode(from.getIDs());\n },\n (from: ThreadMarkNode, to: ThreadMarkNode) => {\n const ids = from.getIDs();\n ids.forEach((id) => {\n to.addID(id);\n });\n }\n );\n }, [editor]);\n\n return (\n <OnDeleteThreadCallback.Provider value={handleThreadDelete}>\n <ActiveThreadsContext.Provider value={activeThreads}>\n <IsActiveThreadContext.Provider value={isThreadActive}>\n <ThreadToNodesContext.Provider value={threadToNodes}>\n {children}\n </ThreadToNodesContext.Provider>\n </IsActiveThreadContext.Provider>\n </ActiveThreadsContext.Provider>\n </OnDeleteThreadCallback.Provider>\n );\n}\n\n/**\n * Returns whether the associated thread annotation for the given thread id is selected or not in the editor.\n * @param threadId The id of the thread to check if the associated annotation is selected or not.\n * @returns true if the associated annotation for the thread is selected, false otherwise.\n */\nexport function useIsThreadActive(threadId: string): boolean {\n const isActive = useContext(IsActiveThreadContext);\n if (isActive === null) {\n throw new Error(\n \"useIsThreadActive must be used within LiveblocksPlugin. For more information: https://liveblocks.io/docs/api-reference/liveblocks-react-lexical#useIsThreadActive\"\n );\n }\n\n return isActive(threadId);\n}\n"],"names":["threadIds","activeElements"],"mappings":"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"}
|