@liveblocks/react-lexical 1.12.0-lexical4 → 2.0.0-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/classnames.js +8 -0
- package/dist/classnames.js.map +1 -0
- package/dist/classnames.mjs +6 -0
- package/dist/classnames.mjs.map +1 -0
- package/dist/comments/ThreadPanel.js +27 -7
- package/dist/comments/ThreadPanel.js.map +1 -1
- package/dist/comments/ThreadPanel.mjs +28 -8
- package/dist/comments/ThreadPanel.mjs.map +1 -1
- package/dist/comments/comment-plugin-provider.js +18 -106
- package/dist/comments/comment-plugin-provider.js.map +1 -1
- package/dist/comments/comment-plugin-provider.mjs +17 -104
- package/dist/comments/comment-plugin-provider.mjs.map +1 -1
- package/dist/comments/floating-composer.js +226 -15
- package/dist/comments/floating-composer.js.map +1 -1
- package/dist/comments/floating-composer.mjs +224 -15
- package/dist/comments/floating-composer.mjs.map +1 -1
- package/dist/comments/thread-mark-node.js +1 -16
- package/dist/comments/thread-mark-node.js.map +1 -1
- package/dist/comments/thread-mark-node.mjs +1 -16
- package/dist/comments/thread-mark-node.mjs.map +1 -1
- package/dist/create-dom-range.js +63 -0
- package/dist/create-dom-range.js.map +1 -0
- package/dist/create-dom-range.mjs +61 -0
- package/dist/create-dom-range.mjs.map +1 -0
- package/dist/create-rects-from-dom-range.js +36 -0
- package/dist/create-rects-from-dom-range.js.map +1 -0
- package/dist/create-rects-from-dom-range.mjs +34 -0
- package/dist/create-rects-from-dom-range.mjs.map +1 -0
- package/dist/index.d.mts +113 -0
- package/dist/index.d.ts +96 -44
- package/dist/index.js +9 -6
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +5 -4
- package/dist/index.mjs.map +1 -1
- package/dist/liveblocks-config.js +3 -75
- package/dist/liveblocks-config.js.map +1 -1
- package/dist/liveblocks-config.mjs +4 -56
- package/dist/liveblocks-config.mjs.map +1 -1
- package/dist/liveblocks-plugin-provider.js +12 -29
- package/dist/liveblocks-plugin-provider.js.map +1 -1
- package/dist/liveblocks-plugin-provider.mjs +13 -29
- package/dist/liveblocks-plugin-provider.mjs.map +1 -1
- package/dist/mentions/avatar.js +11 -7
- package/dist/mentions/avatar.js.map +1 -1
- package/dist/mentions/avatar.mjs +11 -7
- package/dist/mentions/avatar.mjs.map +1 -1
- package/dist/mentions/mention-component.js +5 -18
- package/dist/mentions/mention-component.js.map +1 -1
- package/dist/mentions/mention-component.mjs +7 -19
- package/dist/mentions/mention-component.mjs.map +1 -1
- package/dist/mentions/mention-node.js +77 -74
- package/dist/mentions/mention-node.js.map +1 -1
- package/dist/mentions/mention-node.mjs +76 -75
- package/dist/mentions/mention-node.mjs.map +1 -1
- package/dist/mentions/mention-plugin.js +130 -91
- package/dist/mentions/mention-plugin.js.map +1 -1
- package/dist/mentions/mention-plugin.mjs +119 -76
- package/dist/mentions/mention-plugin.mjs.map +1 -1
- package/dist/mentions/suggestions.js +34 -6
- package/dist/mentions/suggestions.js.map +1 -1
- package/dist/mentions/suggestions.mjs +28 -3
- package/dist/mentions/suggestions.mjs.map +1 -1
- package/dist/mentions/user.js +9 -6
- package/dist/mentions/user.js.map +1 -1
- package/dist/mentions/user.mjs +9 -6
- package/dist/mentions/user.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 +23 -15
- package/src/styles/constants.css +1 -0
- package/src/styles/index.css +154 -0
- package/src/styles/utils.css +6 -0
- package/styles.css +1 -0
- package/styles.css.d.ts +1 -0
- package/styles.css.map +1 -0
- package/dist/active-selection.js +0 -143
- package/dist/active-selection.js.map +0 -1
- package/dist/active-selection.mjs +0 -123
- package/dist/active-selection.mjs.map +0 -1
- package/dist/floating-selection-container.js +0 -157
- package/dist/floating-selection-container.js.map +0 -1
- package/dist/floating-selection-container.mjs +0 -155
- package/dist/floating-selection-container.mjs.map +0 -1
|
@@ -1,10 +1,15 @@
|
|
|
1
|
+
import { useFloating, flip, offset, hide, shift, limitShift, size, autoUpdate } from '@floating-ui/react-dom';
|
|
1
2
|
import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext';
|
|
2
3
|
import { kInternal } from '@liveblocks/core';
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import
|
|
4
|
+
import { useRoom } from '@liveblocks/react';
|
|
5
|
+
import { useMentionSuggestions } from '@liveblocks/react-ui';
|
|
6
|
+
import { $getSelection, $isRangeSelection, $isTextNode, $getNodeByKey, $isNodeSelection, $createTextNode, $createRangeSelection, $setSelection, $isElementNode, KEY_BACKSPACE_COMMAND, COMMAND_PRIORITY_LOW } from 'lexical';
|
|
7
|
+
import React__default, { useState, useEffect, useCallback, useLayoutEffect } from 'react';
|
|
6
8
|
import { createPortal } from 'react-dom';
|
|
7
|
-
import {
|
|
9
|
+
import { Avatar } from './avatar.mjs';
|
|
10
|
+
import { MentionNode, $isMentionNode, $createMentionNode } from './mention-node.mjs';
|
|
11
|
+
import { SuggestionsContext, OnValueSelectCallbackContext, OnResetMatchCallbackContext, List, Item } from './suggestions.mjs';
|
|
12
|
+
import { User } from './user.mjs';
|
|
8
13
|
|
|
9
14
|
const MENTION_TRIGGER = "@";
|
|
10
15
|
const PUNCTUATIONS = `\\.,\\+\\*\\?\\$\\@\\|#{}\\(\\)\\^\\-\\[\\]\\\\/!%'"~=<>_:;`;
|
|
@@ -27,8 +32,8 @@ function $getAnchorNodeTextContent() {
|
|
|
27
32
|
const anchorOffset = anchor.offset;
|
|
28
33
|
return anchorNode.getTextContent().slice(0, anchorOffset);
|
|
29
34
|
}
|
|
30
|
-
function getFullMatchOffset(documentText, entryText,
|
|
31
|
-
let triggerOffset =
|
|
35
|
+
function getFullMatchOffset(documentText, entryText, offset2) {
|
|
36
|
+
let triggerOffset = offset2;
|
|
32
37
|
for (let i = triggerOffset; i <= entryText.length; i++) {
|
|
33
38
|
if (documentText.substr(-i) === entryText.substr(0, i)) {
|
|
34
39
|
triggerOffset = i;
|
|
@@ -36,8 +41,8 @@ function getFullMatchOffset(documentText, entryText, offset) {
|
|
|
36
41
|
}
|
|
37
42
|
return triggerOffset;
|
|
38
43
|
}
|
|
39
|
-
function $isCurrentSelectionAtBoundary(
|
|
40
|
-
if (
|
|
44
|
+
function $isCurrentSelectionAtBoundary(offset2) {
|
|
45
|
+
if (offset2 !== 0)
|
|
41
46
|
return false;
|
|
42
47
|
const selection = $getSelection();
|
|
43
48
|
if (!$isRangeSelection(selection))
|
|
@@ -74,40 +79,54 @@ function $getRangeAtMatch(match) {
|
|
|
74
79
|
return null;
|
|
75
80
|
}
|
|
76
81
|
}
|
|
77
|
-
const SuggestionsContext = createContext(null);
|
|
78
|
-
const OnValueSelectCallbackContext = createContext(null);
|
|
79
|
-
const OnResetMatchCallbackContext = createContext(null);
|
|
80
82
|
function MentionPlugin() {
|
|
81
83
|
const [editor] = useLexicalComposerContext();
|
|
82
|
-
const {
|
|
83
|
-
mentions: {
|
|
84
|
-
factory: { $isMentionNode, $createMentionNode, MentionNode },
|
|
85
|
-
components: { MentionSuggestions }
|
|
86
|
-
}
|
|
87
|
-
} = useLiveblocksLexicalConfigContext();
|
|
88
84
|
if (!editor.hasNodes([MentionNode])) {
|
|
89
85
|
throw new Error("MentionPlugin: MentionNode not registered on editor");
|
|
90
86
|
}
|
|
91
87
|
const [match, setMatch] = useState(null);
|
|
92
88
|
const matchingString = match?.[3];
|
|
93
|
-
const {
|
|
94
|
-
[kInternal]: { useMentionSuggestions }
|
|
95
|
-
} = useRoomContextBundle();
|
|
96
89
|
const suggestions = useMentionSuggestions(matchingString);
|
|
90
|
+
const room = useRoom();
|
|
97
91
|
useEffect(() => {
|
|
98
|
-
function handleMutation(mutations, {
|
|
92
|
+
function $handleMutation(mutations, {
|
|
99
93
|
prevEditorState
|
|
100
94
|
}) {
|
|
101
95
|
for (const [key, mutation] of mutations) {
|
|
102
|
-
if (mutation
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
96
|
+
if (mutation === "created") {
|
|
97
|
+
editor.getEditorState().read(() => {
|
|
98
|
+
const node = $getNodeByKey(key);
|
|
99
|
+
if (node === null)
|
|
100
|
+
return;
|
|
101
|
+
if (!$isMentionNode(node))
|
|
102
|
+
return;
|
|
103
|
+
room[kInternal].createTextMention(node.getUserId(), node.getId()).catch((err) => {
|
|
104
|
+
console.error(err);
|
|
105
|
+
});
|
|
106
|
+
});
|
|
107
|
+
} else if (mutation === "destroyed") {
|
|
108
|
+
prevEditorState.read(() => {
|
|
109
|
+
const node = $getNodeByKey(key);
|
|
110
|
+
if (node === null)
|
|
111
|
+
return;
|
|
112
|
+
if (!$isMentionNode(node))
|
|
113
|
+
return;
|
|
114
|
+
room[kInternal].deleteTextMention(node.getId()).catch((err) => {
|
|
115
|
+
console.error(err);
|
|
116
|
+
});
|
|
117
|
+
});
|
|
118
|
+
}
|
|
107
119
|
}
|
|
108
120
|
}
|
|
109
|
-
return editor.registerMutationListener(
|
|
110
|
-
|
|
121
|
+
return editor.registerMutationListener(
|
|
122
|
+
MentionNode,
|
|
123
|
+
(mutations, payload) => {
|
|
124
|
+
if (payload.updateTags.has("collaboration"))
|
|
125
|
+
return;
|
|
126
|
+
$handleMutation(mutations, payload);
|
|
127
|
+
}
|
|
128
|
+
);
|
|
129
|
+
}, [editor, room]);
|
|
111
130
|
useEffect(() => {
|
|
112
131
|
function $onStateRead() {
|
|
113
132
|
const text = $getAnchorNodeTextContent();
|
|
@@ -122,6 +141,15 @@ function MentionPlugin() {
|
|
|
122
141
|
state.read($onStateRead);
|
|
123
142
|
});
|
|
124
143
|
}, [editor]);
|
|
144
|
+
useEffect(() => {
|
|
145
|
+
const root = editor.getRootElement();
|
|
146
|
+
if (root === null)
|
|
147
|
+
return;
|
|
148
|
+
root.classList.add("lb-root");
|
|
149
|
+
return () => {
|
|
150
|
+
root.classList.remove("lb-root");
|
|
151
|
+
};
|
|
152
|
+
}, [editor]);
|
|
125
153
|
useEffect(() => {
|
|
126
154
|
function $handleBackspace(event) {
|
|
127
155
|
const selection = $getSelection();
|
|
@@ -175,7 +203,7 @@ function MentionPlugin() {
|
|
|
175
203
|
$handleBackspace,
|
|
176
204
|
COMMAND_PRIORITY_LOW
|
|
177
205
|
);
|
|
178
|
-
}, [editor
|
|
206
|
+
}, [editor]);
|
|
179
207
|
const handleValueSelect = useCallback(
|
|
180
208
|
(userId) => {
|
|
181
209
|
function $onValueSelect() {
|
|
@@ -211,7 +239,7 @@ function MentionPlugin() {
|
|
|
211
239
|
}
|
|
212
240
|
editor.update($onValueSelect);
|
|
213
241
|
},
|
|
214
|
-
[editor, match
|
|
242
|
+
[editor, match]
|
|
215
243
|
);
|
|
216
244
|
if (match === null || matchingString === void 0)
|
|
217
245
|
return null;
|
|
@@ -220,7 +248,6 @@ function MentionPlugin() {
|
|
|
220
248
|
const range = editor.getEditorState().read(() => $getRangeAtMatch(match));
|
|
221
249
|
if (range === null)
|
|
222
250
|
return null;
|
|
223
|
-
const rect = range.getBoundingClientRect();
|
|
224
251
|
return createPortal(
|
|
225
252
|
/* @__PURE__ */ React__default.createElement(SuggestionsContext.Provider, {
|
|
226
253
|
value: suggestions
|
|
@@ -228,57 +255,73 @@ function MentionPlugin() {
|
|
|
228
255
|
value: handleValueSelect
|
|
229
256
|
}, /* @__PURE__ */ React__default.createElement(OnResetMatchCallbackContext.Provider, {
|
|
230
257
|
value: () => setMatch(null)
|
|
231
|
-
}, /* @__PURE__ */ React__default.createElement(
|
|
232
|
-
|
|
258
|
+
}, /* @__PURE__ */ React__default.createElement(SuggestionsPortal, {
|
|
259
|
+
range,
|
|
260
|
+
container: document.body,
|
|
233
261
|
key: matchingString
|
|
234
|
-
}, /* @__PURE__ */ React__default.createElement(
|
|
235
|
-
|
|
236
|
-
})
|
|
262
|
+
}, /* @__PURE__ */ React__default.createElement(List, {
|
|
263
|
+
className: "lb-lexical-suggestions-list lb-lexical-mention-suggestions-list"
|
|
264
|
+
}, suggestions.map((userId) => /* @__PURE__ */ React__default.createElement(Item, {
|
|
265
|
+
key: userId,
|
|
266
|
+
value: userId,
|
|
267
|
+
className: "lb-lexical-suggestions-list-item lb-lexical-mention-suggestion"
|
|
268
|
+
}, /* @__PURE__ */ React__default.createElement(Avatar, {
|
|
269
|
+
userId,
|
|
270
|
+
className: "lb-lexical-mention-suggestion-avatar"
|
|
271
|
+
}), /* @__PURE__ */ React__default.createElement(User, {
|
|
272
|
+
userId,
|
|
273
|
+
className: "lb-lexical-mention-suggestion-user"
|
|
274
|
+
})))))))),
|
|
237
275
|
document.body
|
|
238
276
|
);
|
|
239
277
|
}
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
children
|
|
278
|
+
const SUGGESTIONS_COLLISION_PADDING = 10;
|
|
279
|
+
function SuggestionsPortal({
|
|
280
|
+
children,
|
|
281
|
+
range,
|
|
282
|
+
container
|
|
243
283
|
}) {
|
|
244
|
-
const
|
|
245
|
-
|
|
284
|
+
const {
|
|
285
|
+
refs: { setReference, setFloating },
|
|
286
|
+
strategy,
|
|
287
|
+
x,
|
|
288
|
+
y
|
|
289
|
+
} = useFloating({
|
|
290
|
+
strategy: "fixed",
|
|
291
|
+
placement: "top-start",
|
|
292
|
+
middleware: [
|
|
293
|
+
flip({ padding: SUGGESTIONS_COLLISION_PADDING, crossAxis: false }),
|
|
294
|
+
offset(10),
|
|
295
|
+
hide({ padding: SUGGESTIONS_COLLISION_PADDING }),
|
|
296
|
+
shift({ padding: SUGGESTIONS_COLLISION_PADDING, limiter: limitShift() }),
|
|
297
|
+
size({ padding: SUGGESTIONS_COLLISION_PADDING })
|
|
298
|
+
],
|
|
299
|
+
whileElementsMounted: (...args) => {
|
|
300
|
+
return autoUpdate(...args, {
|
|
301
|
+
animationFrame: true
|
|
302
|
+
});
|
|
303
|
+
}
|
|
304
|
+
});
|
|
246
305
|
useLayoutEffect(() => {
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
}
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
}
|
|
266
|
-
return suggestions;
|
|
267
|
-
}
|
|
268
|
-
function useOnValueSelectCallback() {
|
|
269
|
-
const onValueSelect = useContext(OnValueSelectCallbackContext);
|
|
270
|
-
if (onValueSelect === null) {
|
|
271
|
-
throw new Error("useOnValueSelectCallback: OnValueSelectContext not found");
|
|
272
|
-
}
|
|
273
|
-
return onValueSelect;
|
|
274
|
-
}
|
|
275
|
-
function useOnResetMatchCallback() {
|
|
276
|
-
const onResetMatch = useContext(OnResetMatchCallbackContext);
|
|
277
|
-
if (onResetMatch === null) {
|
|
278
|
-
throw new Error("useOnResetMatchCallback: OnResetMatchContext not found");
|
|
279
|
-
}
|
|
280
|
-
return onResetMatch;
|
|
306
|
+
setReference({
|
|
307
|
+
getBoundingClientRect: () => range.getBoundingClientRect()
|
|
308
|
+
});
|
|
309
|
+
}, [setReference, range]);
|
|
310
|
+
return createPortal(
|
|
311
|
+
/* @__PURE__ */ React__default.createElement("div", {
|
|
312
|
+
ref: setFloating,
|
|
313
|
+
style: {
|
|
314
|
+
position: strategy,
|
|
315
|
+
top: 0,
|
|
316
|
+
left: 0,
|
|
317
|
+
transform: `translate3d(${Math.round(x)}px, ${Math.round(y)}px, 0)`,
|
|
318
|
+
minWidth: "max-content"
|
|
319
|
+
},
|
|
320
|
+
className: "lb-root lb-portal lb-elevation lb-lexical-suggestions lb-lexical-mention-suggestions"
|
|
321
|
+
}, children),
|
|
322
|
+
container
|
|
323
|
+
);
|
|
281
324
|
}
|
|
282
325
|
|
|
283
|
-
export { MentionPlugin
|
|
326
|
+
export { MentionPlugin, SUGGESTIONS_COLLISION_PADDING };
|
|
284
327
|
//# sourceMappingURL=mention-plugin.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mention-plugin.mjs","sources":["../../src/mentions/mention-plugin.tsx"],"sourcesContent":["import { useLexicalComposerContext } from \"@lexical/react/LexicalComposerContext\";\nimport { kInternal } from \"@liveblocks/core\";\nimport { useRoomContextBundle } from \"@liveblocks/react\";\nimport type { EditorState, NodeKey, NodeMutation, TextNode } from \"lexical\";\nimport {\n $createRangeSelection,\n $createTextNode,\n $getSelection,\n $isElementNode,\n $isNodeSelection,\n $isRangeSelection,\n $isTextNode,\n $setSelection,\n COMMAND_PRIORITY_LOW,\n KEY_BACKSPACE_COMMAND,\n} from \"lexical\";\nimport type { ReactNode } from \"react\";\nimport React, {\n createContext,\n useCallback,\n useContext,\n useEffect,\n useLayoutEffect,\n useRef,\n useState,\n} from \"react\";\nimport { createPortal } from \"react-dom\";\n\nimport { useLiveblocksLexicalConfigContext } from \"../liveblocks-plugin-provider\";\n\nconst MENTION_TRIGGER = \"@\";\n\nconst PUNCTUATIONS =\n \"\\\\.,\\\\+\\\\*\\\\?\\\\$\\\\@\\\\|#{}\\\\(\\\\)\\\\^\\\\-\\\\[\\\\]\\\\\\\\/!%'\\\"~=<>_:;\";\n\n// Characters we expect to see in a mention (non-space, non-punctuation).\nconst VALID_CHARACTERS = \"[^\" + MENTION_TRIGGER + PUNCTUATIONS + \"\\\\s]\";\n\nconst VALID_JOINS =\n \"(?:\" +\n \"\\\\.[ |$]|\" + // E.g. \"r. \" in \"Mr. Smith\"\n \" |\" + // E.g. \" \" in \"Josh Duck\"\n \"[\" +\n PUNCTUATIONS +\n \"]|\" + // E.g. \"-' in \"Salier-Hellendag\"\n \")\";\n\nconst LENGTH_LIMIT = 75;\n\nconst MentionRegex = new RegExp(\n \"(^|\\\\s|\\\\()(\" +\n \"[\" +\n MENTION_TRIGGER +\n \"]\" +\n \"((?:\" +\n VALID_CHARACTERS +\n VALID_JOINS +\n \"){0,\" +\n LENGTH_LIMIT +\n \"})\" +\n \")$\"\n);\n\nfunction $getAnchorNodeTextContent(): string | null {\n const selection = $getSelection();\n if (!$isRangeSelection(selection)) return null;\n\n const anchor = selection.anchor;\n if (anchor.type !== \"text\") return null;\n const anchorNode = anchor.getNode();\n if (!anchorNode.isSimpleText()) return null;\n const anchorOffset = anchor.offset;\n return anchorNode.getTextContent().slice(0, anchorOffset);\n}\n\n/**\n * Walk backwards along user input and forward through entity title to try and replace more of the user's text with entity.\n */\nfunction getFullMatchOffset(\n documentText: string,\n entryText: string,\n offset: number\n): number {\n let triggerOffset = offset;\n for (let i = triggerOffset; i <= entryText.length; i++) {\n if (documentText.substr(-i) === entryText.substr(0, i)) {\n triggerOffset = i;\n }\n }\n return triggerOffset;\n}\n\nfunction $isCurrentSelectionAtBoundary(offset: number): boolean {\n // If the offset is not zero, i.e. not at the beginning of the text node, the selection is somewhere in the middle of the entity, i.e. not at the boundary.\n if (offset !== 0) return false;\n\n // Othewise (if the offset is zero), it means the selection could be at the start of an entity. It could also be at the end of the previous entity, or it could be in a position where there are no entities at all.\n // So, we check if the previous sibling of the node at the anchor of the selection is a text entity. If it is, then the selection is at the boundary of the entity.\n const selection = $getSelection();\n\n if (!$isRangeSelection(selection)) return false;\n\n const anchor = selection.anchor.getNode();\n const prevSibling = anchor.getPreviousSibling();\n\n if (!$isTextNode(prevSibling)) return false;\n if (!prevSibling.isTextEntity()) return false;\n\n return true;\n}\n\nfunction $getRangeAtMatch(match: RegExpExecArray): globalThis.Range | null {\n const offsetWithWhitespaces = match.index + match[1].length;\n\n if ($isCurrentSelectionAtBoundary(offsetWithWhitespaces)) return null;\n\n const selection = window.getSelection();\n if (selection === null) return null;\n if (!selection.isCollapsed) return null;\n\n const anchor = selection.anchorNode;\n if (anchor === null) return null;\n\n const endOffset = selection.anchorOffset;\n if (endOffset === null) return null;\n\n const range = document.createRange();\n\n try {\n range.setStart(anchor, offsetWithWhitespaces);\n range.setEnd(anchor, endOffset);\n return range;\n } catch (error) {\n return null;\n }\n}\n\nconst SuggestionsContext = createContext<string[] | null>(null);\n\nconst OnValueSelectCallbackContext = createContext<\n ((value: string) => void) | null\n>(null);\n\nconst OnResetMatchCallbackContext = createContext<(() => void) | null>(null);\n\nexport default function MentionPlugin() {\n const [editor] = useLexicalComposerContext();\n const {\n mentions: {\n factory: { $isMentionNode, $createMentionNode, MentionNode },\n components: { MentionSuggestions },\n },\n } = useLiveblocksLexicalConfigContext();\n\n if (!editor.hasNodes([MentionNode])) {\n throw new Error(\"MentionPlugin: MentionNode not registered on editor\");\n }\n\n const [match, setMatch] = useState<RegExpExecArray | null>(null); // Represents the current match of the mention regex. A `null` value means there is no match.\n const matchingString = match?.[3];\n\n const {\n [kInternal]: { useMentionSuggestions },\n } = useRoomContextBundle();\n const suggestions = useMentionSuggestions(matchingString);\n\n useEffect(() => {\n function handleMutation(\n mutations: Map<NodeKey, NodeMutation>,\n {\n prevEditorState,\n }: {\n prevEditorState: EditorState;\n }\n ) {\n for (const [key, mutation] of mutations) {\n if (mutation !== \"destroyed\") continue;\n\n const node = prevEditorState._nodeMap.get(key);\n if (node === null) continue;\n\n // TODO\n }\n }\n\n return editor.registerMutationListener(MentionNode, handleMutation);\n }, [editor, MentionNode]);\n\n useEffect(() => {\n function $onStateRead() {\n const text = $getAnchorNodeTextContent();\n if (text === null) {\n setMatch(null);\n return;\n }\n\n const match = MentionRegex.exec(text);\n setMatch(match);\n }\n\n return editor.registerUpdateListener(({ editorState: state }) => {\n state.read($onStateRead);\n });\n }, [editor]);\n\n useEffect(() => {\n function $handleBackspace(event: KeyboardEvent): boolean {\n const selection = $getSelection();\n\n if (selection === null) return false;\n\n // If the selection is a node selection and the only node selected is a mention node, then we replace the mention node with a text node containing \"@\" and set the selection at the end of the text node.\n if ($isNodeSelection(selection)) {\n const nodes = selection.getNodes();\n if (nodes.length !== 1) return false;\n\n const node = nodes[0];\n if (!$isMentionNode(node)) return false;\n\n const text = $createTextNode(\"@\");\n node.replace(text);\n\n const newSelection = $createRangeSelection();\n newSelection.setTextNodeRange(text, 1, text, 1);\n $setSelection(newSelection);\n\n event.preventDefault();\n return true;\n } else if ($isRangeSelection(selection)) {\n if (!selection.isCollapsed()) return false;\n\n const anchor = selection.anchor.getNode();\n const prevSibling = anchor.getPreviousSibling();\n if (selection.anchor.offset === 0 && $isMentionNode(prevSibling)) {\n const text = $createTextNode(\"@\");\n prevSibling.replace(text);\n\n const newSelection = $createRangeSelection();\n newSelection.setTextNodeRange(text, 1, text, 1);\n $setSelection(newSelection);\n\n event.preventDefault();\n return true;\n } else if ($isElementNode(anchor)) {\n const child = anchor.getChildAtIndex(selection.anchor.offset - 1);\n if (!$isMentionNode(child)) return false;\n\n const text = $createTextNode(\"@\");\n child.replace(text);\n\n const newSelection = $createRangeSelection();\n newSelection.setTextNodeRange(text, 1, text, 1);\n $setSelection(newSelection);\n\n event.preventDefault();\n return true;\n }\n\n return false;\n }\n\n return false;\n }\n\n return editor.registerCommand(\n KEY_BACKSPACE_COMMAND,\n $handleBackspace,\n COMMAND_PRIORITY_LOW\n );\n }, [editor, $isMentionNode]);\n\n const handleValueSelect = useCallback(\n (userId: string) => {\n function $onValueSelect() {\n if (match === null) return;\n\n setMatch(null);\n\n const selection = $getSelection();\n\n if (!$isRangeSelection(selection)) return;\n if (!selection.isCollapsed()) return;\n\n const anchor = selection.anchor;\n if (anchor.type !== \"text\") return;\n\n const anchorNode: TextNode = anchor.getNode();\n if (!anchorNode.isSimpleText()) return;\n\n const selectionOffset = anchor.offset;\n const text = anchorNode.getTextContent().slice(0, selectionOffset);\n\n const characterOffset = match[2].length;\n const queryOffset = getFullMatchOffset(text, match[2], characterOffset);\n const startOffset = selectionOffset - queryOffset;\n if (startOffset < 0) return;\n\n const mentionNode = $createMentionNode(userId);\n\n // Split the anchor (text) node and create a new text node only containing matched text.\n if (startOffset === 0) {\n const [node] = anchorNode.splitText(selectionOffset);\n node.replace(mentionNode);\n } else {\n const [, node] = anchorNode.splitText(startOffset, selectionOffset);\n node.replace(mentionNode);\n }\n }\n\n editor.update($onValueSelect);\n },\n [editor, match, $createMentionNode]\n );\n\n if (match === null || matchingString === undefined) return null;\n\n if (suggestions === undefined || suggestions.length === 0) return null;\n\n const range = editor.getEditorState().read(() => $getRangeAtMatch(match));\n\n if (range === null) return null;\n\n const rect = range.getBoundingClientRect();\n\n return createPortal(\n <SuggestionsContext.Provider value={suggestions}>\n <OnValueSelectCallbackContext.Provider value={handleValueSelect}>\n <OnResetMatchCallbackContext.Provider value={() => setMatch(null)}>\n <SuggestionsRoot rect={rect} key={matchingString}>\n <MentionSuggestions userIds={suggestions} />\n </SuggestionsRoot>\n </OnResetMatchCallbackContext.Provider>\n </OnValueSelectCallbackContext.Provider>\n </SuggestionsContext.Provider>,\n document.body\n );\n}\n\nfunction SuggestionsRoot({\n rect,\n children,\n}: {\n rect: DOMRect;\n children: ReactNode;\n}) {\n const [editor] = useLexicalComposerContext();\n const divRef = useRef<HTMLDivElement>(null);\n\n useLayoutEffect(() => {\n const root = editor.getRootElement();\n if (root === null) return;\n\n const div = divRef.current;\n if (div === null) return;\n\n div.style.left = `${rect.left + window.scrollX}px`;\n div.style.top = `${rect.bottom + window.scrollY}px`;\n }, [editor, rect]);\n\n return (\n <div ref={divRef} style={{ position: \"absolute\" }}>\n {children}\n </div>\n );\n}\n\nexport function useSuggestions(): string[] {\n const suggestions = useContext(SuggestionsContext);\n if (suggestions === null) {\n throw new Error(\"useSuggestions: SuggestionsContext not found\");\n }\n\n return suggestions;\n}\n\nexport function useOnValueSelectCallback(): (value: string) => void {\n const onValueSelect = useContext(OnValueSelectCallbackContext);\n if (onValueSelect === null) {\n throw new Error(\"useOnValueSelectCallback: OnValueSelectContext not found\");\n }\n\n return onValueSelect;\n}\n\nexport function useOnResetMatchCallback(): () => void {\n const onResetMatch = useContext(OnResetMatchCallbackContext);\n if (onResetMatch === null) {\n throw new Error(\"useOnResetMatchCallback: OnResetMatchContext not found\");\n }\n\n return onResetMatch;\n}\n"],"names":["match","React"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"mention-plugin.mjs","sources":["../../src/mentions/mention-plugin.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 { kInternal } from \"@liveblocks/core\";\nimport { useRoom } from \"@liveblocks/react\";\nimport { useMentionSuggestions } from \"@liveblocks/react-ui\";\nimport type { EditorState, NodeKey, NodeMutation, TextNode } from \"lexical\";\nimport {\n $createRangeSelection,\n $createTextNode,\n $getNodeByKey,\n $getSelection,\n $isElementNode,\n $isNodeSelection,\n $isRangeSelection,\n $isTextNode,\n $setSelection,\n COMMAND_PRIORITY_LOW,\n KEY_BACKSPACE_COMMAND,\n} from \"lexical\";\nimport type { ReactNode } from \"react\";\nimport React, {\n useCallback,\n useEffect,\n useLayoutEffect,\n useState,\n} from \"react\";\nimport { createPortal } from \"react-dom\";\n\nimport { Avatar } from \"./avatar\";\nimport {\n $createMentionNode,\n $isMentionNode,\n MentionNode,\n} from \"./mention-node\";\nimport * as Suggestions from \"./suggestions\";\nimport {\n OnResetMatchCallbackContext,\n OnValueSelectCallbackContext,\n SuggestionsContext,\n} from \"./suggestions\";\nimport { User } from \"./user\";\n\nconst MENTION_TRIGGER = \"@\";\n\nconst PUNCTUATIONS =\n \"\\\\.,\\\\+\\\\*\\\\?\\\\$\\\\@\\\\|#{}\\\\(\\\\)\\\\^\\\\-\\\\[\\\\]\\\\\\\\/!%'\\\"~=<>_:;\";\n\n// Characters we expect to see in a mention (non-space, non-punctuation).\nconst VALID_CHARACTERS = \"[^\" + MENTION_TRIGGER + PUNCTUATIONS + \"\\\\s]\";\n\nconst VALID_JOINS =\n \"(?:\" +\n \"\\\\.[ |$]|\" + // E.g. \"r. \" in \"Mr. Smith\"\n \" |\" + // E.g. \" \" in \"Josh Duck\"\n \"[\" +\n PUNCTUATIONS +\n \"]|\" + // E.g. \"-' in \"Salier-Hellendag\"\n \")\";\n\nconst LENGTH_LIMIT = 75;\n\nconst MentionRegex = new RegExp(\n \"(^|\\\\s|\\\\()(\" +\n \"[\" +\n MENTION_TRIGGER +\n \"]\" +\n \"((?:\" +\n VALID_CHARACTERS +\n VALID_JOINS +\n \"){0,\" +\n LENGTH_LIMIT +\n \"})\" +\n \")$\"\n);\n\nfunction $getAnchorNodeTextContent(): string | null {\n const selection = $getSelection();\n if (!$isRangeSelection(selection)) return null;\n\n const anchor = selection.anchor;\n if (anchor.type !== \"text\") return null;\n const anchorNode = anchor.getNode();\n if (!anchorNode.isSimpleText()) return null;\n const anchorOffset = anchor.offset;\n return anchorNode.getTextContent().slice(0, anchorOffset);\n}\n\n/**\n * Walk backwards along user input and forward through entity title to try and replace more of the user's text with entity.\n */\nfunction getFullMatchOffset(\n documentText: string,\n entryText: string,\n offset: number\n): number {\n let triggerOffset = offset;\n for (let i = triggerOffset; i <= entryText.length; i++) {\n if (documentText.substr(-i) === entryText.substr(0, i)) {\n triggerOffset = i;\n }\n }\n return triggerOffset;\n}\n\nfunction $isCurrentSelectionAtBoundary(offset: number): boolean {\n // If the offset is not zero, i.e. not at the beginning of the text node, the selection is somewhere in the middle of the entity, i.e. not at the boundary.\n if (offset !== 0) return false;\n\n // Othewise (if the offset is zero), it means the selection could be at the start of an entity. It could also be at the end of the previous entity, or it could be in a position where there are no entities at all.\n // So, we check if the previous sibling of the node at the anchor of the selection is a text entity. If it is, then the selection is at the boundary of the entity.\n const selection = $getSelection();\n\n if (!$isRangeSelection(selection)) return false;\n\n const anchor = selection.anchor.getNode();\n const prevSibling = anchor.getPreviousSibling();\n\n if (!$isTextNode(prevSibling)) return false;\n if (!prevSibling.isTextEntity()) return false;\n\n return true;\n}\n\nfunction $getRangeAtMatch(match: RegExpExecArray): globalThis.Range | null {\n const offsetWithWhitespaces = match.index + match[1].length;\n\n if ($isCurrentSelectionAtBoundary(offsetWithWhitespaces)) return null;\n\n const selection = window.getSelection();\n if (selection === null) return null;\n if (!selection.isCollapsed) return null;\n\n const anchor = selection.anchorNode;\n if (anchor === null) return null;\n\n const endOffset = selection.anchorOffset;\n if (endOffset === null) return null;\n\n const range = document.createRange();\n\n try {\n range.setStart(anchor, offsetWithWhitespaces);\n range.setEnd(anchor, endOffset);\n return range;\n } catch (error) {\n return null;\n }\n}\n\nexport function MentionPlugin() {\n const [editor] = useLexicalComposerContext();\n\n if (!editor.hasNodes([MentionNode])) {\n throw new Error(\"MentionPlugin: MentionNode not registered on editor\");\n }\n\n const [match, setMatch] = useState<RegExpExecArray | null>(null); // Represents the current match of the mention regex. A `null` value means there is no match.\n const matchingString = match?.[3];\n\n const suggestions = useMentionSuggestions(matchingString);\n\n const room = useRoom();\n\n useEffect(() => {\n function $handleMutation(\n mutations: Map<NodeKey, NodeMutation>,\n {\n prevEditorState,\n }: {\n prevEditorState: EditorState;\n }\n ) {\n for (const [key, mutation] of mutations) {\n if (mutation === \"created\") {\n editor.getEditorState().read(() => {\n const node = $getNodeByKey(key);\n if (node === null) return;\n\n if (!$isMentionNode(node)) return;\n\n room[kInternal]\n .createTextMention(node.getUserId(), node.getId())\n .catch((err) => {\n // TODO: Handle error\n console.error(err);\n });\n });\n } else if (mutation === \"destroyed\") {\n prevEditorState.read(() => {\n const node = $getNodeByKey(key);\n if (node === null) return;\n\n if (!$isMentionNode(node)) return;\n\n room[kInternal].deleteTextMention(node.getId()).catch((err) => {\n // TODO: Handle error\n console.error(err);\n });\n });\n }\n }\n }\n\n return editor.registerMutationListener(\n MentionNode,\n (mutations, payload) => {\n if (payload.updateTags.has(\"collaboration\")) return;\n $handleMutation(mutations, payload);\n }\n );\n }, [editor, room]);\n\n useEffect(() => {\n function $onStateRead() {\n const text = $getAnchorNodeTextContent();\n if (text === null) {\n setMatch(null);\n return;\n }\n\n const match = MentionRegex.exec(text);\n setMatch(match);\n }\n\n return editor.registerUpdateListener(({ editorState: state }) => {\n state.read($onStateRead);\n });\n }, [editor]);\n\n useEffect(() => {\n const root = editor.getRootElement();\n if (root === null) return;\n\n root.classList.add(\"lb-root\");\n return () => {\n root.classList.remove(\"lb-root\");\n };\n }, [editor]);\n\n useEffect(() => {\n function $handleBackspace(event: KeyboardEvent): boolean {\n const selection = $getSelection();\n\n if (selection === null) return false;\n\n // If the selection is a node selection and the only node selected is a mention node, then we replace the mention node with a text node containing \"@\" and set the selection at the end of the text node.\n if ($isNodeSelection(selection)) {\n const nodes = selection.getNodes();\n if (nodes.length !== 1) return false;\n\n const node = nodes[0];\n if (!$isMentionNode(node)) return false;\n\n const text = $createTextNode(\"@\");\n node.replace(text);\n\n const newSelection = $createRangeSelection();\n newSelection.setTextNodeRange(text, 1, text, 1);\n $setSelection(newSelection);\n\n event.preventDefault();\n return true;\n } else if ($isRangeSelection(selection)) {\n if (!selection.isCollapsed()) return false;\n\n const anchor = selection.anchor.getNode();\n const prevSibling = anchor.getPreviousSibling();\n if (selection.anchor.offset === 0 && $isMentionNode(prevSibling)) {\n const text = $createTextNode(\"@\");\n prevSibling.replace(text);\n\n const newSelection = $createRangeSelection();\n newSelection.setTextNodeRange(text, 1, text, 1);\n $setSelection(newSelection);\n\n event.preventDefault();\n return true;\n } else if ($isElementNode(anchor)) {\n const child = anchor.getChildAtIndex(selection.anchor.offset - 1);\n if (!$isMentionNode(child)) return false;\n\n const text = $createTextNode(\"@\");\n child.replace(text);\n\n const newSelection = $createRangeSelection();\n newSelection.setTextNodeRange(text, 1, text, 1);\n $setSelection(newSelection);\n\n event.preventDefault();\n return true;\n }\n\n return false;\n }\n\n return false;\n }\n\n return editor.registerCommand(\n KEY_BACKSPACE_COMMAND,\n $handleBackspace,\n COMMAND_PRIORITY_LOW\n );\n }, [editor]);\n\n const handleValueSelect = useCallback(\n (userId: string) => {\n function $onValueSelect() {\n if (match === null) return;\n\n setMatch(null);\n\n const selection = $getSelection();\n\n if (!$isRangeSelection(selection)) return;\n if (!selection.isCollapsed()) return;\n\n const anchor = selection.anchor;\n if (anchor.type !== \"text\") return;\n\n const anchorNode: TextNode = anchor.getNode();\n if (!anchorNode.isSimpleText()) return;\n\n const selectionOffset = anchor.offset;\n const text = anchorNode.getTextContent().slice(0, selectionOffset);\n\n const characterOffset = match[2].length;\n const queryOffset = getFullMatchOffset(text, match[2], characterOffset);\n const startOffset = selectionOffset - queryOffset;\n if (startOffset < 0) return;\n\n const mentionNode = $createMentionNode(userId);\n\n // Split the anchor (text) node and create a new text node only containing matched text.\n if (startOffset === 0) {\n const [node] = anchorNode.splitText(selectionOffset);\n node.replace(mentionNode);\n } else {\n const [, node] = anchorNode.splitText(startOffset, selectionOffset);\n node.replace(mentionNode);\n }\n }\n\n editor.update($onValueSelect);\n },\n [editor, match]\n );\n\n if (match === null || matchingString === undefined) return null;\n\n if (suggestions === undefined || suggestions.length === 0) return null;\n\n const range = editor.getEditorState().read(() => $getRangeAtMatch(match));\n\n if (range === null) return null;\n\n return createPortal(\n <SuggestionsContext.Provider value={suggestions}>\n <OnValueSelectCallbackContext.Provider value={handleValueSelect}>\n <OnResetMatchCallbackContext.Provider value={() => setMatch(null)}>\n <SuggestionsPortal\n range={range}\n container={document.body}\n key={matchingString}\n >\n <Suggestions.List className=\"lb-lexical-suggestions-list lb-lexical-mention-suggestions-list\">\n {suggestions.map((userId) => (\n <Suggestions.Item\n key={userId}\n value={userId}\n className=\"lb-lexical-suggestions-list-item lb-lexical-mention-suggestion\"\n >\n <Avatar\n userId={userId}\n className=\"lb-lexical-mention-suggestion-avatar\"\n />\n <User\n userId={userId}\n className=\"lb-lexical-mention-suggestion-user\"\n />\n </Suggestions.Item>\n ))}\n </Suggestions.List>\n </SuggestionsPortal>\n </OnResetMatchCallbackContext.Provider>\n </OnValueSelectCallbackContext.Provider>\n </SuggestionsContext.Provider>,\n document.body\n );\n}\n\nexport const SUGGESTIONS_COLLISION_PADDING = 10;\n\nfunction SuggestionsPortal({\n children,\n range,\n container,\n}: {\n children: ReactNode;\n range: Range;\n container: Element;\n}) {\n const {\n refs: { setReference, setFloating },\n strategy,\n x,\n y,\n } = useFloating({\n strategy: \"fixed\",\n placement: \"top-start\",\n middleware: [\n flip({ padding: SUGGESTIONS_COLLISION_PADDING, crossAxis: false }),\n offset(10),\n hide({ padding: SUGGESTIONS_COLLISION_PADDING }),\n shift({ padding: SUGGESTIONS_COLLISION_PADDING, limiter: limitShift() }),\n size({ padding: SUGGESTIONS_COLLISION_PADDING }),\n ],\n whileElementsMounted: (...args) => {\n return autoUpdate(...args, {\n animationFrame: true,\n });\n },\n });\n\n useLayoutEffect(() => {\n setReference({\n getBoundingClientRect: () => range.getBoundingClientRect(),\n });\n }, [setReference, range]);\n\n return createPortal(\n <div\n ref={setFloating}\n style={{\n position: strategy,\n top: 0,\n left: 0,\n transform: `translate3d(${Math.round(x)}px, ${Math.round(y)}px, 0)`,\n minWidth: \"max-content\",\n }}\n className=\"lb-root lb-portal lb-elevation lb-lexical-suggestions lb-lexical-mention-suggestions\"\n >\n {children}\n </div>,\n container\n );\n}\n"],"names":["offset","match","React","Suggestions.List","Suggestions.Item"],"mappings":"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"}
|
|
@@ -3,17 +3,21 @@
|
|
|
3
3
|
var LexicalComposerContext = require('@lexical/react/LexicalComposerContext');
|
|
4
4
|
var lexical = require('lexical');
|
|
5
5
|
var React = require('react');
|
|
6
|
-
var mentionPlugin = require('./mention-plugin.js');
|
|
7
6
|
|
|
7
|
+
const SuggestionsContext = React.createContext(null);
|
|
8
|
+
const OnValueSelectCallbackContext = React.createContext(null);
|
|
9
|
+
const OnResetMatchCallbackContext = React.createContext(
|
|
10
|
+
null
|
|
11
|
+
);
|
|
8
12
|
const HighlightedIndexContext = React.createContext(null);
|
|
9
13
|
const List = React.forwardRef(
|
|
10
14
|
function(props, forwardedRef) {
|
|
11
15
|
const { children, ...divProps } = props;
|
|
12
16
|
const [editor] = LexicalComposerContext.useLexicalComposerContext();
|
|
13
17
|
const [highlightedIndex, setHighlightedIndex] = React.useState(0);
|
|
14
|
-
const values =
|
|
15
|
-
const onValueSelect =
|
|
16
|
-
const onEscapeKeyDown =
|
|
18
|
+
const values = useSuggestions();
|
|
19
|
+
const onValueSelect = useOnValueSelectCallback();
|
|
20
|
+
const onEscapeKeyDown = useOnResetMatchCallback();
|
|
17
21
|
React.useEffect(() => {
|
|
18
22
|
function onKeyArrowDown(event) {
|
|
19
23
|
if (values.length === 0)
|
|
@@ -106,8 +110,8 @@ const Item = React.forwardRef(
|
|
|
106
110
|
const { children, value, onMouseEnter, onClick, ...divProps } = props;
|
|
107
111
|
const divRef = React.useRef(null);
|
|
108
112
|
const [highlightedIndex, setHighlightedIndex] = useHighlightedIndex();
|
|
109
|
-
const suggestions =
|
|
110
|
-
const onValueSelect =
|
|
113
|
+
const suggestions = useSuggestions();
|
|
114
|
+
const onValueSelect = useOnValueSelectCallback();
|
|
111
115
|
const isHighlighted = suggestions[highlightedIndex] === value;
|
|
112
116
|
React.useImperativeHandle(
|
|
113
117
|
forwardedRef,
|
|
@@ -155,7 +159,31 @@ function useHighlightedIndex() {
|
|
|
155
159
|
}
|
|
156
160
|
return context;
|
|
157
161
|
}
|
|
162
|
+
function useSuggestions() {
|
|
163
|
+
const suggestions = React.useContext(SuggestionsContext);
|
|
164
|
+
if (suggestions === null) {
|
|
165
|
+
throw new Error("useSuggestions: SuggestionsContext not found");
|
|
166
|
+
}
|
|
167
|
+
return suggestions;
|
|
168
|
+
}
|
|
169
|
+
function useOnValueSelectCallback() {
|
|
170
|
+
const onValueSelect = React.useContext(OnValueSelectCallbackContext);
|
|
171
|
+
if (onValueSelect === null) {
|
|
172
|
+
throw new Error("useOnValueSelectCallback: OnValueSelectContext not found");
|
|
173
|
+
}
|
|
174
|
+
return onValueSelect;
|
|
175
|
+
}
|
|
176
|
+
function useOnResetMatchCallback() {
|
|
177
|
+
const onResetMatch = React.useContext(OnResetMatchCallbackContext);
|
|
178
|
+
if (onResetMatch === null) {
|
|
179
|
+
throw new Error("useOnResetMatchCallback: OnResetMatchContext not found");
|
|
180
|
+
}
|
|
181
|
+
return onResetMatch;
|
|
182
|
+
}
|
|
158
183
|
|
|
159
184
|
exports.Item = Item;
|
|
160
185
|
exports.List = List;
|
|
186
|
+
exports.OnResetMatchCallbackContext = OnResetMatchCallbackContext;
|
|
187
|
+
exports.OnValueSelectCallbackContext = OnValueSelectCallbackContext;
|
|
188
|
+
exports.SuggestionsContext = SuggestionsContext;
|
|
161
189
|
//# sourceMappingURL=suggestions.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"suggestions.js","sources":["../../src/mentions/suggestions.tsx"],"sourcesContent":["import { useLexicalComposerContext } from \"@lexical/react/LexicalComposerContext\";\nimport {\n COMMAND_PRIORITY_LOW,\n KEY_ARROW_DOWN_COMMAND,\n KEY_ARROW_UP_COMMAND,\n KEY_ENTER_COMMAND,\n KEY_ESCAPE_COMMAND,\n} from \"lexical\";\nimport type {\n Dispatch,\n HTMLAttributes,\n MouseEvent,\n ReactNode,\n SetStateAction,\n} from \"react\";\nimport React, {\n createContext,\n forwardRef,\n useEffect,\n useImperativeHandle,\n useRef,\n useState,\n} from \"react\";\n\nimport {\n useOnResetMatchCallback,\n useOnValueSelectCallback,\n useSuggestions,\n} from \"./mention-plugin\";\n\nconst HighlightedIndexContext = createContext<\n [number, Dispatch<SetStateAction<number>>] | null\n>(null);\n\nexport interface ListProps extends HTMLAttributes<HTMLDivElement> {\n children: ReactNode;\n}\n\nconst List = forwardRef<HTMLDivElement, ListProps>(\n function (props, forwardedRef) {\n const { children, ...divProps } = props;\n const [editor] = useLexicalComposerContext();\n const [highlightedIndex, setHighlightedIndex] = useState(0);\n const values = useSuggestions();\n const onValueSelect = useOnValueSelectCallback();\n const onEscapeKeyDown = useOnResetMatchCallback();\n\n useEffect(() => {\n function onKeyArrowDown(event: KeyboardEvent): boolean {\n if (values.length === 0) return true;\n if (highlightedIndex === null) return true;\n\n // If the highlighted index is at the last suggestion, then we loop back to the first suggestion, otherwise we increment the index.\n const nextIndex =\n highlightedIndex === values.length - 1 ? 0 : highlightedIndex + 1;\n setHighlightedIndex(nextIndex);\n\n event.preventDefault();\n event.stopImmediatePropagation();\n\n return true;\n }\n\n return editor.registerCommand(\n KEY_ARROW_DOWN_COMMAND,\n onKeyArrowDown,\n COMMAND_PRIORITY_LOW\n );\n }, [editor, highlightedIndex, values]);\n\n useEffect(() => {\n function onKeyArrowUp(event: KeyboardEvent): boolean {\n if (values.length === 0) return true;\n if (highlightedIndex === null) return true;\n\n // If the highlighted index is at the first suggestion, then we loop back to the last suggestion, otherwise we decrement the index.\n const nextIndex =\n highlightedIndex === 0 ? values.length - 1 : highlightedIndex - 1;\n setHighlightedIndex(nextIndex);\n\n event.preventDefault();\n event.stopImmediatePropagation();\n return true;\n }\n\n return editor.registerCommand(\n KEY_ARROW_UP_COMMAND,\n onKeyArrowUp,\n COMMAND_PRIORITY_LOW\n );\n }, [editor, highlightedIndex, values]);\n\n useEffect(() => {\n function onKeyEscape(event: KeyboardEvent): boolean {\n event.preventDefault();\n event.stopImmediatePropagation();\n\n onEscapeKeyDown();\n return true;\n }\n\n return editor.registerCommand<KeyboardEvent>(\n KEY_ESCAPE_COMMAND,\n onKeyEscape,\n COMMAND_PRIORITY_LOW\n );\n }, [editor, onEscapeKeyDown]);\n\n useEffect(() => {\n function onKeyEnter(event: KeyboardEvent | null): boolean {\n if (values.length === 0) return true;\n\n onValueSelect(values[highlightedIndex]);\n\n if (event === null) return true;\n\n event.preventDefault();\n event.stopImmediatePropagation();\n return true;\n }\n\n return editor.registerCommand(\n KEY_ENTER_COMMAND,\n onKeyEnter,\n COMMAND_PRIORITY_LOW\n );\n }, [editor, onValueSelect, highlightedIndex, values]);\n\n useEffect(() => {\n const root = editor.getRootElement();\n if (root === null) return;\n\n root.setAttribute(\n \"aria-activedescendant\",\n `typeahead-item-${highlightedIndex}`\n );\n\n return () => {\n root.removeAttribute(\"aria-activedescendant\");\n };\n }, [editor, highlightedIndex]);\n\n return (\n <HighlightedIndexContext.Provider\n value={[highlightedIndex, setHighlightedIndex]}\n >\n <div role=\"listbox\" {...divProps} ref={forwardedRef}>\n {children}\n </div>\n </HighlightedIndexContext.Provider>\n );\n }\n);\n\ninterface ItemProps extends HTMLAttributes<HTMLDivElement> {\n value: string;\n}\n\nconst Item = forwardRef<HTMLDivElement | null, ItemProps>(\n function Item(props, forwardedRef) {\n const { children, value, onMouseEnter, onClick, ...divProps } = props;\n const divRef = useRef<HTMLDivElement>(null);\n\n const [highlightedIndex, setHighlightedIndex] = useHighlightedIndex();\n const suggestions = useSuggestions();\n const onValueSelect = useOnValueSelectCallback();\n\n const isHighlighted = suggestions[highlightedIndex] === value;\n\n useImperativeHandle<HTMLDivElement | null, HTMLDivElement | null>(\n forwardedRef,\n () => divRef.current\n );\n\n useEffect(() => {\n if (!isHighlighted) return;\n\n const div = divRef.current;\n if (div === null) return;\n\n div.scrollIntoView({ block: \"nearest\" });\n }, [isHighlighted]);\n\n function handleMouseEnter(event: MouseEvent<HTMLDivElement>) {\n onMouseEnter?.(event);\n\n if (event.isDefaultPrevented()) return;\n\n const index = suggestions.indexOf(value);\n if (index === -1) return;\n\n setHighlightedIndex(index);\n }\n\n function handleClick(event: MouseEvent<HTMLDivElement>) {\n onClick?.(event);\n\n if (event.isDefaultPrevented()) return;\n\n onValueSelect(value);\n }\n\n return (\n <div\n role=\"option\"\n data-highlighted={isHighlighted || undefined}\n onMouseEnter={handleMouseEnter}\n onClick={handleClick}\n {...divProps}\n ref={divRef}\n >\n {children}\n </div>\n );\n }\n);\n\nfunction useHighlightedIndex(): [\n number,\n React.Dispatch<React.SetStateAction<number>>,\n] {\n const context = React.useContext(HighlightedIndexContext);\n if (context === null) {\n throw new Error(\n \"useHighlightedIndex must be used within a HighlightedIndexProvider\"\n );\n }\n return context;\n}\n\nexport { Item, List };\n"],"names":["createContext","forwardRef","useLexicalComposerContext","useState","useSuggestions","useOnValueSelectCallback","useOnResetMatchCallback","useEffect","KEY_ARROW_DOWN_COMMAND","COMMAND_PRIORITY_LOW","KEY_ARROW_UP_COMMAND","KEY_ESCAPE_COMMAND","KEY_ENTER_COMMAND","Item","useRef","useImperativeHandle"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"suggestions.js","sources":["../../src/mentions/suggestions.tsx"],"sourcesContent":["import { useLexicalComposerContext } from \"@lexical/react/LexicalComposerContext\";\nimport {\n COMMAND_PRIORITY_LOW,\n KEY_ARROW_DOWN_COMMAND,\n KEY_ARROW_UP_COMMAND,\n KEY_ENTER_COMMAND,\n KEY_ESCAPE_COMMAND,\n} from \"lexical\";\nimport type {\n Dispatch,\n HTMLAttributes,\n MouseEvent,\n ReactNode,\n SetStateAction,\n} from \"react\";\nimport React, {\n createContext,\n forwardRef,\n useContext,\n useEffect,\n useImperativeHandle,\n useRef,\n useState,\n} from \"react\";\n\nexport const SuggestionsContext = createContext<string[] | null>(null);\n\nexport const OnValueSelectCallbackContext = createContext<\n ((value: string) => void) | null\n>(null);\n\nexport const OnResetMatchCallbackContext = createContext<(() => void) | null>(\n null\n);\n\nconst HighlightedIndexContext = createContext<\n [number, Dispatch<SetStateAction<number>>] | null\n>(null);\n\nexport interface ListProps extends HTMLAttributes<HTMLDivElement> {\n children: ReactNode;\n}\n\nconst List = forwardRef<HTMLDivElement, ListProps>(\n function (props, forwardedRef) {\n const { children, ...divProps } = props;\n const [editor] = useLexicalComposerContext();\n const [highlightedIndex, setHighlightedIndex] = useState(0);\n const values = useSuggestions();\n const onValueSelect = useOnValueSelectCallback();\n const onEscapeKeyDown = useOnResetMatchCallback();\n\n useEffect(() => {\n function onKeyArrowDown(event: KeyboardEvent): boolean {\n if (values.length === 0) return true;\n if (highlightedIndex === null) return true;\n\n // If the highlighted index is at the last suggestion, then we loop back to the first suggestion, otherwise we increment the index.\n const nextIndex =\n highlightedIndex === values.length - 1 ? 0 : highlightedIndex + 1;\n setHighlightedIndex(nextIndex);\n\n event.preventDefault();\n event.stopImmediatePropagation();\n\n return true;\n }\n\n return editor.registerCommand(\n KEY_ARROW_DOWN_COMMAND,\n onKeyArrowDown,\n COMMAND_PRIORITY_LOW\n );\n }, [editor, highlightedIndex, values]);\n\n useEffect(() => {\n function onKeyArrowUp(event: KeyboardEvent): boolean {\n if (values.length === 0) return true;\n if (highlightedIndex === null) return true;\n\n // If the highlighted index is at the first suggestion, then we loop back to the last suggestion, otherwise we decrement the index.\n const nextIndex =\n highlightedIndex === 0 ? values.length - 1 : highlightedIndex - 1;\n setHighlightedIndex(nextIndex);\n\n event.preventDefault();\n event.stopImmediatePropagation();\n return true;\n }\n\n return editor.registerCommand(\n KEY_ARROW_UP_COMMAND,\n onKeyArrowUp,\n COMMAND_PRIORITY_LOW\n );\n }, [editor, highlightedIndex, values]);\n\n useEffect(() => {\n function onKeyEscape(event: KeyboardEvent): boolean {\n event.preventDefault();\n event.stopImmediatePropagation();\n\n onEscapeKeyDown();\n return true;\n }\n\n return editor.registerCommand<KeyboardEvent>(\n KEY_ESCAPE_COMMAND,\n onKeyEscape,\n COMMAND_PRIORITY_LOW\n );\n }, [editor, onEscapeKeyDown]);\n\n useEffect(() => {\n function onKeyEnter(event: KeyboardEvent | null): boolean {\n if (values.length === 0) return true;\n\n onValueSelect(values[highlightedIndex]);\n\n if (event === null) return true;\n\n event.preventDefault();\n event.stopImmediatePropagation();\n return true;\n }\n\n return editor.registerCommand(\n KEY_ENTER_COMMAND,\n onKeyEnter,\n COMMAND_PRIORITY_LOW\n );\n }, [editor, onValueSelect, highlightedIndex, values]);\n\n useEffect(() => {\n const root = editor.getRootElement();\n if (root === null) return;\n\n root.setAttribute(\n \"aria-activedescendant\",\n `typeahead-item-${highlightedIndex}`\n );\n\n return () => {\n root.removeAttribute(\"aria-activedescendant\");\n };\n }, [editor, highlightedIndex]);\n\n return (\n <HighlightedIndexContext.Provider\n value={[highlightedIndex, setHighlightedIndex]}\n >\n <div role=\"listbox\" {...divProps} ref={forwardedRef}>\n {children}\n </div>\n </HighlightedIndexContext.Provider>\n );\n }\n);\n\ninterface ItemProps extends HTMLAttributes<HTMLDivElement> {\n value: string;\n}\n\nconst Item = forwardRef<HTMLDivElement | null, ItemProps>(\n function Item(props, forwardedRef) {\n const { children, value, onMouseEnter, onClick, ...divProps } = props;\n const divRef = useRef<HTMLDivElement>(null);\n\n const [highlightedIndex, setHighlightedIndex] = useHighlightedIndex();\n const suggestions = useSuggestions();\n const onValueSelect = useOnValueSelectCallback();\n\n const isHighlighted = suggestions[highlightedIndex] === value;\n\n useImperativeHandle<HTMLDivElement | null, HTMLDivElement | null>(\n forwardedRef,\n () => divRef.current\n );\n\n useEffect(() => {\n if (!isHighlighted) return;\n\n const div = divRef.current;\n if (div === null) return;\n\n div.scrollIntoView({ block: \"nearest\" });\n }, [isHighlighted]);\n\n function handleMouseEnter(event: MouseEvent<HTMLDivElement>) {\n onMouseEnter?.(event);\n\n if (event.isDefaultPrevented()) return;\n\n const index = suggestions.indexOf(value);\n if (index === -1) return;\n\n setHighlightedIndex(index);\n }\n\n function handleClick(event: MouseEvent<HTMLDivElement>) {\n onClick?.(event);\n\n if (event.isDefaultPrevented()) return;\n\n onValueSelect(value);\n }\n\n return (\n <div\n role=\"option\"\n data-highlighted={isHighlighted || undefined}\n onMouseEnter={handleMouseEnter}\n onClick={handleClick}\n {...divProps}\n ref={divRef}\n >\n {children}\n </div>\n );\n }\n);\n\nfunction useHighlightedIndex(): [\n number,\n React.Dispatch<React.SetStateAction<number>>,\n] {\n const context = React.useContext(HighlightedIndexContext);\n if (context === null) {\n throw new Error(\n \"useHighlightedIndex must be used within a HighlightedIndexProvider\"\n );\n }\n return context;\n}\n\nfunction useSuggestions(): string[] {\n const suggestions = useContext(SuggestionsContext);\n if (suggestions === null) {\n throw new Error(\"useSuggestions: SuggestionsContext not found\");\n }\n\n return suggestions;\n}\n\nfunction useOnValueSelectCallback(): (value: string) => void {\n const onValueSelect = useContext(OnValueSelectCallbackContext);\n if (onValueSelect === null) {\n throw new Error(\"useOnValueSelectCallback: OnValueSelectContext not found\");\n }\n\n return onValueSelect;\n}\n\nfunction useOnResetMatchCallback(): () => void {\n const onResetMatch = useContext(OnResetMatchCallbackContext);\n if (onResetMatch === null) {\n throw new Error(\"useOnResetMatchCallback: OnResetMatchContext not found\");\n }\n\n return onResetMatch;\n}\n\nexport { Item, List };\n"],"names":["createContext","forwardRef","useLexicalComposerContext","useState","useEffect","KEY_ARROW_DOWN_COMMAND","COMMAND_PRIORITY_LOW","KEY_ARROW_UP_COMMAND","KEY_ESCAPE_COMMAND","KEY_ENTER_COMMAND","Item","useRef","useImperativeHandle","useContext"],"mappings":"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"}
|
|
@@ -1,8 +1,12 @@
|
|
|
1
1
|
import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext';
|
|
2
2
|
import { KEY_ARROW_DOWN_COMMAND, COMMAND_PRIORITY_LOW, KEY_ARROW_UP_COMMAND, KEY_ESCAPE_COMMAND, KEY_ENTER_COMMAND } from 'lexical';
|
|
3
|
-
import React__default, { createContext, forwardRef, useState, useEffect, useRef, useImperativeHandle } from 'react';
|
|
4
|
-
import { useSuggestions, useOnValueSelectCallback, useOnResetMatchCallback } from './mention-plugin.mjs';
|
|
3
|
+
import React__default, { createContext, forwardRef, useState, useEffect, useRef, useImperativeHandle, useContext } from 'react';
|
|
5
4
|
|
|
5
|
+
const SuggestionsContext = createContext(null);
|
|
6
|
+
const OnValueSelectCallbackContext = createContext(null);
|
|
7
|
+
const OnResetMatchCallbackContext = createContext(
|
|
8
|
+
null
|
|
9
|
+
);
|
|
6
10
|
const HighlightedIndexContext = createContext(null);
|
|
7
11
|
const List = forwardRef(
|
|
8
12
|
function(props, forwardedRef) {
|
|
@@ -153,6 +157,27 @@ function useHighlightedIndex() {
|
|
|
153
157
|
}
|
|
154
158
|
return context;
|
|
155
159
|
}
|
|
160
|
+
function useSuggestions() {
|
|
161
|
+
const suggestions = useContext(SuggestionsContext);
|
|
162
|
+
if (suggestions === null) {
|
|
163
|
+
throw new Error("useSuggestions: SuggestionsContext not found");
|
|
164
|
+
}
|
|
165
|
+
return suggestions;
|
|
166
|
+
}
|
|
167
|
+
function useOnValueSelectCallback() {
|
|
168
|
+
const onValueSelect = useContext(OnValueSelectCallbackContext);
|
|
169
|
+
if (onValueSelect === null) {
|
|
170
|
+
throw new Error("useOnValueSelectCallback: OnValueSelectContext not found");
|
|
171
|
+
}
|
|
172
|
+
return onValueSelect;
|
|
173
|
+
}
|
|
174
|
+
function useOnResetMatchCallback() {
|
|
175
|
+
const onResetMatch = useContext(OnResetMatchCallbackContext);
|
|
176
|
+
if (onResetMatch === null) {
|
|
177
|
+
throw new Error("useOnResetMatchCallback: OnResetMatchContext not found");
|
|
178
|
+
}
|
|
179
|
+
return onResetMatch;
|
|
180
|
+
}
|
|
156
181
|
|
|
157
|
-
export { Item, List };
|
|
182
|
+
export { Item, List, OnResetMatchCallbackContext, OnValueSelectCallbackContext, SuggestionsContext };
|
|
158
183
|
//# sourceMappingURL=suggestions.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"suggestions.mjs","sources":["../../src/mentions/suggestions.tsx"],"sourcesContent":["import { useLexicalComposerContext } from \"@lexical/react/LexicalComposerContext\";\nimport {\n COMMAND_PRIORITY_LOW,\n KEY_ARROW_DOWN_COMMAND,\n KEY_ARROW_UP_COMMAND,\n KEY_ENTER_COMMAND,\n KEY_ESCAPE_COMMAND,\n} from \"lexical\";\nimport type {\n Dispatch,\n HTMLAttributes,\n MouseEvent,\n ReactNode,\n SetStateAction,\n} from \"react\";\nimport React, {\n createContext,\n forwardRef,\n useEffect,\n useImperativeHandle,\n useRef,\n useState,\n} from \"react\";\n\nimport {\n useOnResetMatchCallback,\n useOnValueSelectCallback,\n useSuggestions,\n} from \"./mention-plugin\";\n\nconst HighlightedIndexContext = createContext<\n [number, Dispatch<SetStateAction<number>>] | null\n>(null);\n\nexport interface ListProps extends HTMLAttributes<HTMLDivElement> {\n children: ReactNode;\n}\n\nconst List = forwardRef<HTMLDivElement, ListProps>(\n function (props, forwardedRef) {\n const { children, ...divProps } = props;\n const [editor] = useLexicalComposerContext();\n const [highlightedIndex, setHighlightedIndex] = useState(0);\n const values = useSuggestions();\n const onValueSelect = useOnValueSelectCallback();\n const onEscapeKeyDown = useOnResetMatchCallback();\n\n useEffect(() => {\n function onKeyArrowDown(event: KeyboardEvent): boolean {\n if (values.length === 0) return true;\n if (highlightedIndex === null) return true;\n\n // If the highlighted index is at the last suggestion, then we loop back to the first suggestion, otherwise we increment the index.\n const nextIndex =\n highlightedIndex === values.length - 1 ? 0 : highlightedIndex + 1;\n setHighlightedIndex(nextIndex);\n\n event.preventDefault();\n event.stopImmediatePropagation();\n\n return true;\n }\n\n return editor.registerCommand(\n KEY_ARROW_DOWN_COMMAND,\n onKeyArrowDown,\n COMMAND_PRIORITY_LOW\n );\n }, [editor, highlightedIndex, values]);\n\n useEffect(() => {\n function onKeyArrowUp(event: KeyboardEvent): boolean {\n if (values.length === 0) return true;\n if (highlightedIndex === null) return true;\n\n // If the highlighted index is at the first suggestion, then we loop back to the last suggestion, otherwise we decrement the index.\n const nextIndex =\n highlightedIndex === 0 ? values.length - 1 : highlightedIndex - 1;\n setHighlightedIndex(nextIndex);\n\n event.preventDefault();\n event.stopImmediatePropagation();\n return true;\n }\n\n return editor.registerCommand(\n KEY_ARROW_UP_COMMAND,\n onKeyArrowUp,\n COMMAND_PRIORITY_LOW\n );\n }, [editor, highlightedIndex, values]);\n\n useEffect(() => {\n function onKeyEscape(event: KeyboardEvent): boolean {\n event.preventDefault();\n event.stopImmediatePropagation();\n\n onEscapeKeyDown();\n return true;\n }\n\n return editor.registerCommand<KeyboardEvent>(\n KEY_ESCAPE_COMMAND,\n onKeyEscape,\n COMMAND_PRIORITY_LOW\n );\n }, [editor, onEscapeKeyDown]);\n\n useEffect(() => {\n function onKeyEnter(event: KeyboardEvent | null): boolean {\n if (values.length === 0) return true;\n\n onValueSelect(values[highlightedIndex]);\n\n if (event === null) return true;\n\n event.preventDefault();\n event.stopImmediatePropagation();\n return true;\n }\n\n return editor.registerCommand(\n KEY_ENTER_COMMAND,\n onKeyEnter,\n COMMAND_PRIORITY_LOW\n );\n }, [editor, onValueSelect, highlightedIndex, values]);\n\n useEffect(() => {\n const root = editor.getRootElement();\n if (root === null) return;\n\n root.setAttribute(\n \"aria-activedescendant\",\n `typeahead-item-${highlightedIndex}`\n );\n\n return () => {\n root.removeAttribute(\"aria-activedescendant\");\n };\n }, [editor, highlightedIndex]);\n\n return (\n <HighlightedIndexContext.Provider\n value={[highlightedIndex, setHighlightedIndex]}\n >\n <div role=\"listbox\" {...divProps} ref={forwardedRef}>\n {children}\n </div>\n </HighlightedIndexContext.Provider>\n );\n }\n);\n\ninterface ItemProps extends HTMLAttributes<HTMLDivElement> {\n value: string;\n}\n\nconst Item = forwardRef<HTMLDivElement | null, ItemProps>(\n function Item(props, forwardedRef) {\n const { children, value, onMouseEnter, onClick, ...divProps } = props;\n const divRef = useRef<HTMLDivElement>(null);\n\n const [highlightedIndex, setHighlightedIndex] = useHighlightedIndex();\n const suggestions = useSuggestions();\n const onValueSelect = useOnValueSelectCallback();\n\n const isHighlighted = suggestions[highlightedIndex] === value;\n\n useImperativeHandle<HTMLDivElement | null, HTMLDivElement | null>(\n forwardedRef,\n () => divRef.current\n );\n\n useEffect(() => {\n if (!isHighlighted) return;\n\n const div = divRef.current;\n if (div === null) return;\n\n div.scrollIntoView({ block: \"nearest\" });\n }, [isHighlighted]);\n\n function handleMouseEnter(event: MouseEvent<HTMLDivElement>) {\n onMouseEnter?.(event);\n\n if (event.isDefaultPrevented()) return;\n\n const index = suggestions.indexOf(value);\n if (index === -1) return;\n\n setHighlightedIndex(index);\n }\n\n function handleClick(event: MouseEvent<HTMLDivElement>) {\n onClick?.(event);\n\n if (event.isDefaultPrevented()) return;\n\n onValueSelect(value);\n }\n\n return (\n <div\n role=\"option\"\n data-highlighted={isHighlighted || undefined}\n onMouseEnter={handleMouseEnter}\n onClick={handleClick}\n {...divProps}\n ref={divRef}\n >\n {children}\n </div>\n );\n }\n);\n\nfunction useHighlightedIndex(): [\n number,\n React.Dispatch<React.SetStateAction<number>>,\n] {\n const context = React.useContext(HighlightedIndexContext);\n if (context === null) {\n throw new Error(\n \"useHighlightedIndex must be used within a HighlightedIndexProvider\"\n );\n }\n return context;\n}\n\nexport { Item, List };\n"],"names":["React","Item"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"suggestions.mjs","sources":["../../src/mentions/suggestions.tsx"],"sourcesContent":["import { useLexicalComposerContext } from \"@lexical/react/LexicalComposerContext\";\nimport {\n COMMAND_PRIORITY_LOW,\n KEY_ARROW_DOWN_COMMAND,\n KEY_ARROW_UP_COMMAND,\n KEY_ENTER_COMMAND,\n KEY_ESCAPE_COMMAND,\n} from \"lexical\";\nimport type {\n Dispatch,\n HTMLAttributes,\n MouseEvent,\n ReactNode,\n SetStateAction,\n} from \"react\";\nimport React, {\n createContext,\n forwardRef,\n useContext,\n useEffect,\n useImperativeHandle,\n useRef,\n useState,\n} from \"react\";\n\nexport const SuggestionsContext = createContext<string[] | null>(null);\n\nexport const OnValueSelectCallbackContext = createContext<\n ((value: string) => void) | null\n>(null);\n\nexport const OnResetMatchCallbackContext = createContext<(() => void) | null>(\n null\n);\n\nconst HighlightedIndexContext = createContext<\n [number, Dispatch<SetStateAction<number>>] | null\n>(null);\n\nexport interface ListProps extends HTMLAttributes<HTMLDivElement> {\n children: ReactNode;\n}\n\nconst List = forwardRef<HTMLDivElement, ListProps>(\n function (props, forwardedRef) {\n const { children, ...divProps } = props;\n const [editor] = useLexicalComposerContext();\n const [highlightedIndex, setHighlightedIndex] = useState(0);\n const values = useSuggestions();\n const onValueSelect = useOnValueSelectCallback();\n const onEscapeKeyDown = useOnResetMatchCallback();\n\n useEffect(() => {\n function onKeyArrowDown(event: KeyboardEvent): boolean {\n if (values.length === 0) return true;\n if (highlightedIndex === null) return true;\n\n // If the highlighted index is at the last suggestion, then we loop back to the first suggestion, otherwise we increment the index.\n const nextIndex =\n highlightedIndex === values.length - 1 ? 0 : highlightedIndex + 1;\n setHighlightedIndex(nextIndex);\n\n event.preventDefault();\n event.stopImmediatePropagation();\n\n return true;\n }\n\n return editor.registerCommand(\n KEY_ARROW_DOWN_COMMAND,\n onKeyArrowDown,\n COMMAND_PRIORITY_LOW\n );\n }, [editor, highlightedIndex, values]);\n\n useEffect(() => {\n function onKeyArrowUp(event: KeyboardEvent): boolean {\n if (values.length === 0) return true;\n if (highlightedIndex === null) return true;\n\n // If the highlighted index is at the first suggestion, then we loop back to the last suggestion, otherwise we decrement the index.\n const nextIndex =\n highlightedIndex === 0 ? values.length - 1 : highlightedIndex - 1;\n setHighlightedIndex(nextIndex);\n\n event.preventDefault();\n event.stopImmediatePropagation();\n return true;\n }\n\n return editor.registerCommand(\n KEY_ARROW_UP_COMMAND,\n onKeyArrowUp,\n COMMAND_PRIORITY_LOW\n );\n }, [editor, highlightedIndex, values]);\n\n useEffect(() => {\n function onKeyEscape(event: KeyboardEvent): boolean {\n event.preventDefault();\n event.stopImmediatePropagation();\n\n onEscapeKeyDown();\n return true;\n }\n\n return editor.registerCommand<KeyboardEvent>(\n KEY_ESCAPE_COMMAND,\n onKeyEscape,\n COMMAND_PRIORITY_LOW\n );\n }, [editor, onEscapeKeyDown]);\n\n useEffect(() => {\n function onKeyEnter(event: KeyboardEvent | null): boolean {\n if (values.length === 0) return true;\n\n onValueSelect(values[highlightedIndex]);\n\n if (event === null) return true;\n\n event.preventDefault();\n event.stopImmediatePropagation();\n return true;\n }\n\n return editor.registerCommand(\n KEY_ENTER_COMMAND,\n onKeyEnter,\n COMMAND_PRIORITY_LOW\n );\n }, [editor, onValueSelect, highlightedIndex, values]);\n\n useEffect(() => {\n const root = editor.getRootElement();\n if (root === null) return;\n\n root.setAttribute(\n \"aria-activedescendant\",\n `typeahead-item-${highlightedIndex}`\n );\n\n return () => {\n root.removeAttribute(\"aria-activedescendant\");\n };\n }, [editor, highlightedIndex]);\n\n return (\n <HighlightedIndexContext.Provider\n value={[highlightedIndex, setHighlightedIndex]}\n >\n <div role=\"listbox\" {...divProps} ref={forwardedRef}>\n {children}\n </div>\n </HighlightedIndexContext.Provider>\n );\n }\n);\n\ninterface ItemProps extends HTMLAttributes<HTMLDivElement> {\n value: string;\n}\n\nconst Item = forwardRef<HTMLDivElement | null, ItemProps>(\n function Item(props, forwardedRef) {\n const { children, value, onMouseEnter, onClick, ...divProps } = props;\n const divRef = useRef<HTMLDivElement>(null);\n\n const [highlightedIndex, setHighlightedIndex] = useHighlightedIndex();\n const suggestions = useSuggestions();\n const onValueSelect = useOnValueSelectCallback();\n\n const isHighlighted = suggestions[highlightedIndex] === value;\n\n useImperativeHandle<HTMLDivElement | null, HTMLDivElement | null>(\n forwardedRef,\n () => divRef.current\n );\n\n useEffect(() => {\n if (!isHighlighted) return;\n\n const div = divRef.current;\n if (div === null) return;\n\n div.scrollIntoView({ block: \"nearest\" });\n }, [isHighlighted]);\n\n function handleMouseEnter(event: MouseEvent<HTMLDivElement>) {\n onMouseEnter?.(event);\n\n if (event.isDefaultPrevented()) return;\n\n const index = suggestions.indexOf(value);\n if (index === -1) return;\n\n setHighlightedIndex(index);\n }\n\n function handleClick(event: MouseEvent<HTMLDivElement>) {\n onClick?.(event);\n\n if (event.isDefaultPrevented()) return;\n\n onValueSelect(value);\n }\n\n return (\n <div\n role=\"option\"\n data-highlighted={isHighlighted || undefined}\n onMouseEnter={handleMouseEnter}\n onClick={handleClick}\n {...divProps}\n ref={divRef}\n >\n {children}\n </div>\n );\n }\n);\n\nfunction useHighlightedIndex(): [\n number,\n React.Dispatch<React.SetStateAction<number>>,\n] {\n const context = React.useContext(HighlightedIndexContext);\n if (context === null) {\n throw new Error(\n \"useHighlightedIndex must be used within a HighlightedIndexProvider\"\n );\n }\n return context;\n}\n\nfunction useSuggestions(): string[] {\n const suggestions = useContext(SuggestionsContext);\n if (suggestions === null) {\n throw new Error(\"useSuggestions: SuggestionsContext not found\");\n }\n\n return suggestions;\n}\n\nfunction useOnValueSelectCallback(): (value: string) => void {\n const onValueSelect = useContext(OnValueSelectCallbackContext);\n if (onValueSelect === null) {\n throw new Error(\"useOnValueSelectCallback: OnValueSelectContext not found\");\n }\n\n return onValueSelect;\n}\n\nfunction useOnResetMatchCallback(): () => void {\n const onResetMatch = useContext(OnResetMatchCallbackContext);\n if (onResetMatch === null) {\n throw new Error(\"useOnResetMatchCallback: OnResetMatchContext not found\");\n }\n\n return onResetMatch;\n}\n\nexport { Item, List };\n"],"names":["React","Item"],"mappings":"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"}
|