@liveblocks/react-lexical 1.12.0-lexical3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (78) hide show
  1. package/dist/active-selection.js +143 -0
  2. package/dist/active-selection.js.map +1 -0
  3. package/dist/active-selection.mjs +123 -0
  4. package/dist/active-selection.mjs.map +1 -0
  5. package/dist/comments/ThreadPanel.js +26 -0
  6. package/dist/comments/ThreadPanel.js.map +1 -0
  7. package/dist/comments/ThreadPanel.mjs +24 -0
  8. package/dist/comments/ThreadPanel.mjs.map +1 -0
  9. package/dist/comments/comment-plugin-provider.js +322 -0
  10. package/dist/comments/comment-plugin-provider.js.map +1 -0
  11. package/dist/comments/comment-plugin-provider.mjs +299 -0
  12. package/dist/comments/comment-plugin-provider.mjs.map +1 -0
  13. package/dist/comments/floating-composer.js +34 -0
  14. package/dist/comments/floating-composer.js.map +1 -0
  15. package/dist/comments/floating-composer.mjs +32 -0
  16. package/dist/comments/floating-composer.mjs.map +1 -0
  17. package/dist/comments/get-thread-mark-ids.js +23 -0
  18. package/dist/comments/get-thread-mark-ids.js.map +1 -0
  19. package/dist/comments/get-thread-mark-ids.mjs +21 -0
  20. package/dist/comments/get-thread-mark-ids.mjs.map +1 -0
  21. package/dist/comments/thread-mark-node.js +138 -0
  22. package/dist/comments/thread-mark-node.js.map +1 -0
  23. package/dist/comments/thread-mark-node.mjs +134 -0
  24. package/dist/comments/thread-mark-node.mjs.map +1 -0
  25. package/dist/comments/unwrap-thread-mark-node.js +19 -0
  26. package/dist/comments/unwrap-thread-mark-node.js.map +1 -0
  27. package/dist/comments/unwrap-thread-mark-node.mjs +17 -0
  28. package/dist/comments/unwrap-thread-mark-node.mjs.map +1 -0
  29. package/dist/comments/wrap-selection-in-thread-mark-node.js +63 -0
  30. package/dist/comments/wrap-selection-in-thread-mark-node.js.map +1 -0
  31. package/dist/comments/wrap-selection-in-thread-mark-node.mjs +61 -0
  32. package/dist/comments/wrap-selection-in-thread-mark-node.mjs.map +1 -0
  33. package/dist/floating-selection-container.js +157 -0
  34. package/dist/floating-selection-container.js.map +1 -0
  35. package/dist/floating-selection-container.mjs +155 -0
  36. package/dist/floating-selection-container.mjs.map +1 -0
  37. package/dist/index.d.ts +61 -0
  38. package/dist/index.js +20 -0
  39. package/dist/index.js.map +1 -0
  40. package/dist/index.mjs +11 -0
  41. package/dist/index.mjs.map +1 -0
  42. package/dist/liveblocks-config.js +89 -0
  43. package/dist/liveblocks-config.js.map +1 -0
  44. package/dist/liveblocks-config.mjs +67 -0
  45. package/dist/liveblocks-config.mjs.map +1 -0
  46. package/dist/liveblocks-plugin-provider.js +79 -0
  47. package/dist/liveblocks-plugin-provider.js.map +1 -0
  48. package/dist/liveblocks-plugin-provider.mjs +76 -0
  49. package/dist/liveblocks-plugin-provider.mjs.map +1 -0
  50. package/dist/mentions/avatar.js +49 -0
  51. package/dist/mentions/avatar.js.map +1 -0
  52. package/dist/mentions/avatar.mjs +47 -0
  53. package/dist/mentions/avatar.mjs.map +1 -0
  54. package/dist/mentions/mention-component.js +63 -0
  55. package/dist/mentions/mention-component.js.map +1 -0
  56. package/dist/mentions/mention-component.mjs +60 -0
  57. package/dist/mentions/mention-component.mjs.map +1 -0
  58. package/dist/mentions/mention-node.js +105 -0
  59. package/dist/mentions/mention-node.js.map +1 -0
  60. package/dist/mentions/mention-node.mjs +84 -0
  61. package/dist/mentions/mention-node.mjs.map +1 -0
  62. package/dist/mentions/mention-plugin.js +291 -0
  63. package/dist/mentions/mention-plugin.js.map +1 -0
  64. package/dist/mentions/mention-plugin.mjs +284 -0
  65. package/dist/mentions/mention-plugin.mjs.map +1 -0
  66. package/dist/mentions/suggestions.js +161 -0
  67. package/dist/mentions/suggestions.js.map +1 -0
  68. package/dist/mentions/suggestions.mjs +158 -0
  69. package/dist/mentions/suggestions.mjs.map +1 -0
  70. package/dist/mentions/user.js +21 -0
  71. package/dist/mentions/user.js.map +1 -0
  72. package/dist/mentions/user.mjs +19 -0
  73. package/dist/mentions/user.mjs.map +1 -0
  74. package/dist/version.js +10 -0
  75. package/dist/version.js.map +1 -0
  76. package/dist/version.mjs +6 -0
  77. package/dist/version.mjs.map +1 -0
  78. package/package.json +102 -0
@@ -0,0 +1,84 @@
1
+ import { DecoratorNode, $applyNodeReplacement } from 'lexical';
2
+ import * as React from 'react';
3
+ import { MentionWrapper } from './mention-component.mjs';
4
+
5
+ function createMentionNodeFactory(Component) {
6
+ class MentionNode extends DecoratorNode {
7
+ constructor(value, key) {
8
+ super(key);
9
+ this.__id = value;
10
+ }
11
+ static getType() {
12
+ return "lb-mention";
13
+ }
14
+ static clone(node) {
15
+ return new MentionNode(node.__id);
16
+ }
17
+ createDOM() {
18
+ const element = document.createElement("span");
19
+ element.style.display = "inline-block";
20
+ return element;
21
+ }
22
+ updateDOM() {
23
+ return false;
24
+ }
25
+ static importDom() {
26
+ return {
27
+ span: () => ({
28
+ conversion: (element) => {
29
+ const value = atob(
30
+ element.getAttribute("data-lexical-lb-mention")
31
+ );
32
+ const node = $createMentionNode(value);
33
+ return { node };
34
+ },
35
+ priority: 1
36
+ })
37
+ };
38
+ }
39
+ exportDOM() {
40
+ const element = document.createElement("span");
41
+ const value = this.getTextContent();
42
+ element.setAttribute("data-lexical-lb-mention", btoa(value));
43
+ element.textContent = this.getTextContent();
44
+ return { element };
45
+ }
46
+ static importJSON(serializedNode) {
47
+ const node = $createMentionNode(serializedNode.value);
48
+ return node;
49
+ }
50
+ exportJSON() {
51
+ return {
52
+ value: this.getTextContent(),
53
+ type: "lb-mention",
54
+ version: 1
55
+ };
56
+ }
57
+ getTextContent() {
58
+ const self = this.getLatest();
59
+ return self.__id;
60
+ }
61
+ decorate() {
62
+ return /* @__PURE__ */ React.createElement(MentionWrapper, {
63
+ nodeKey: this.getKey()
64
+ }, /* @__PURE__ */ React.createElement(Component, {
65
+ userId: this.__id
66
+ }));
67
+ }
68
+ }
69
+ function $isMentionNode(node) {
70
+ return node instanceof MentionNode;
71
+ }
72
+ function $createMentionNode(id) {
73
+ const node = new MentionNode(id);
74
+ return $applyNodeReplacement(node);
75
+ }
76
+ return {
77
+ MentionNode,
78
+ $isMentionNode,
79
+ $createMentionNode
80
+ };
81
+ }
82
+
83
+ export { createMentionNodeFactory };
84
+ //# sourceMappingURL=mention-node.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mention-node.mjs","sources":["../../src/mentions/mention-node.tsx"],"sourcesContent":["import type {\n DOMConversionMap,\n DOMExportOutput,\n LexicalNode,\n NodeKey,\n SerializedLexicalNode,\n Spread,\n} from \"lexical\";\nimport { $applyNodeReplacement, DecoratorNode } from \"lexical\";\nimport type { ComponentType, JSX } from \"react\";\nimport * as React from \"react\";\n\nimport type { MentionProps } from \"../liveblocks-config\";\nimport { MentionWrapper } from \"./mention-component\";\n\nexport type SerializedMentionNode = Spread<\n {\n value: string;\n },\n SerializedLexicalNode\n>;\n\nexport function createMentionNodeFactory(\n Component: ComponentType<MentionProps>\n): any {\n class MentionNode extends DecoratorNode<JSX.Element> {\n __id: string;\n\n constructor(value: string, key?: NodeKey) {\n super(key);\n this.__id = value;\n }\n\n static getType(): string {\n return \"lb-mention\";\n }\n\n static clone(node: MentionNode): MentionNode {\n return new MentionNode(node.__id);\n }\n\n createDOM(): HTMLElement {\n const element = document.createElement(\"span\");\n element.style.display = \"inline-block\";\n return element;\n }\n\n updateDOM(): boolean {\n return false;\n }\n\n static importDom(): DOMConversionMap<HTMLElement> | null {\n return {\n span: () => ({\n conversion: (element) => {\n const value = atob(\n element.getAttribute(\"data-lexical-lb-mention\")!\n );\n const node = $createMentionNode(value);\n return { node };\n },\n priority: 1,\n }),\n };\n }\n\n exportDOM(): DOMExportOutput {\n const element = document.createElement(\"span\");\n const value = this.getTextContent();\n element.setAttribute(\"data-lexical-lb-mention\", btoa(value));\n element.textContent = this.getTextContent();\n return { element };\n }\n\n static importJSON(serializedNode: SerializedMentionNode): MentionNode {\n const node = $createMentionNode(serializedNode.value);\n return node;\n }\n\n exportJSON(): SerializedMentionNode {\n return {\n value: this.getTextContent(),\n type: \"lb-mention\",\n version: 1,\n };\n }\n\n getTextContent(): string {\n const self = this.getLatest();\n return self.__id;\n }\n\n decorate(): JSX.Element {\n return (\n <MentionWrapper nodeKey={this.getKey()}>\n <Component userId={this.__id} />\n </MentionWrapper>\n );\n }\n }\n\n function $isMentionNode(\n node: LexicalNode | null | undefined\n ): node is MentionNode {\n return node instanceof MentionNode;\n }\n\n function $createMentionNode(id: string): MentionNode {\n const node = new MentionNode(id);\n return $applyNodeReplacement(node);\n }\n\n return {\n MentionNode,\n $isMentionNode,\n $createMentionNode,\n };\n}\n"],"names":[],"mappings":"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"}
@@ -0,0 +1,291 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, '__esModule', { value: true });
4
+
5
+ var LexicalComposerContext = require('@lexical/react/LexicalComposerContext');
6
+ var core = require('@liveblocks/core');
7
+ var react = require('@liveblocks/react');
8
+ var lexical = require('lexical');
9
+ var React = require('react');
10
+ var reactDom = require('react-dom');
11
+ var liveblocksPluginProvider = require('../liveblocks-plugin-provider.js');
12
+
13
+ const MENTION_TRIGGER = "@";
14
+ const PUNCTUATIONS = `\\.,\\+\\*\\?\\$\\@\\|#{}\\(\\)\\^\\-\\[\\]\\\\/!%'"~=<>_:;`;
15
+ const VALID_CHARACTERS = "[^" + MENTION_TRIGGER + PUNCTUATIONS + "\\s]";
16
+ const VALID_JOINS = "(?:\\.[ |$]| |[" + PUNCTUATIONS + "]|)";
17
+ const LENGTH_LIMIT = 75;
18
+ const MentionRegex = new RegExp(
19
+ "(^|\\s|\\()([" + MENTION_TRIGGER + "]((?:" + VALID_CHARACTERS + VALID_JOINS + "){0," + LENGTH_LIMIT + "}))$"
20
+ );
21
+ function $getAnchorNodeTextContent() {
22
+ const selection = lexical.$getSelection();
23
+ if (!lexical.$isRangeSelection(selection))
24
+ return null;
25
+ const anchor = selection.anchor;
26
+ if (anchor.type !== "text")
27
+ return null;
28
+ const anchorNode = anchor.getNode();
29
+ if (!anchorNode.isSimpleText())
30
+ return null;
31
+ const anchorOffset = anchor.offset;
32
+ return anchorNode.getTextContent().slice(0, anchorOffset);
33
+ }
34
+ function getFullMatchOffset(documentText, entryText, offset) {
35
+ let triggerOffset = offset;
36
+ for (let i = triggerOffset; i <= entryText.length; i++) {
37
+ if (documentText.substr(-i) === entryText.substr(0, i)) {
38
+ triggerOffset = i;
39
+ }
40
+ }
41
+ return triggerOffset;
42
+ }
43
+ function $isCurrentSelectionAtBoundary(offset) {
44
+ if (offset !== 0)
45
+ return false;
46
+ const selection = lexical.$getSelection();
47
+ if (!lexical.$isRangeSelection(selection))
48
+ return false;
49
+ const anchor = selection.anchor.getNode();
50
+ const prevSibling = anchor.getPreviousSibling();
51
+ if (!lexical.$isTextNode(prevSibling))
52
+ return false;
53
+ if (!prevSibling.isTextEntity())
54
+ return false;
55
+ return true;
56
+ }
57
+ function $getRangeAtMatch(match) {
58
+ const offsetWithWhitespaces = match.index + match[1].length;
59
+ if ($isCurrentSelectionAtBoundary(offsetWithWhitespaces))
60
+ return null;
61
+ const selection = window.getSelection();
62
+ if (selection === null)
63
+ return null;
64
+ if (!selection.isCollapsed)
65
+ return null;
66
+ const anchor = selection.anchorNode;
67
+ if (anchor === null)
68
+ return null;
69
+ const endOffset = selection.anchorOffset;
70
+ if (endOffset === null)
71
+ return null;
72
+ const range = document.createRange();
73
+ try {
74
+ range.setStart(anchor, offsetWithWhitespaces);
75
+ range.setEnd(anchor, endOffset);
76
+ return range;
77
+ } catch (error) {
78
+ return null;
79
+ }
80
+ }
81
+ const SuggestionsContext = React.createContext(null);
82
+ const OnValueSelectCallbackContext = React.createContext(null);
83
+ const OnResetMatchCallbackContext = React.createContext(null);
84
+ function MentionPlugin() {
85
+ const [editor] = LexicalComposerContext.useLexicalComposerContext();
86
+ const {
87
+ mentions: {
88
+ factory: { $isMentionNode, $createMentionNode, MentionNode },
89
+ components: { MentionSuggestions }
90
+ }
91
+ } = liveblocksPluginProvider.useLiveblocksLexicalConfigContext();
92
+ if (!editor.hasNodes([MentionNode])) {
93
+ throw new Error("MentionPlugin: MentionNode not registered on editor");
94
+ }
95
+ const [match, setMatch] = React.useState(null);
96
+ const matchingString = match?.[3];
97
+ const {
98
+ [core.kInternal]: { useMentionSuggestions }
99
+ } = react.useRoomContextBundle();
100
+ const suggestions = useMentionSuggestions(matchingString);
101
+ React.useEffect(() => {
102
+ function handleMutation(mutations, {
103
+ prevEditorState
104
+ }) {
105
+ for (const [key, mutation] of mutations) {
106
+ if (mutation !== "destroyed")
107
+ continue;
108
+ const node = prevEditorState._nodeMap.get(key);
109
+ if (node === null)
110
+ continue;
111
+ }
112
+ }
113
+ return editor.registerMutationListener(MentionNode, handleMutation);
114
+ }, [editor, MentionNode]);
115
+ React.useEffect(() => {
116
+ function $onStateRead() {
117
+ const text = $getAnchorNodeTextContent();
118
+ if (text === null) {
119
+ setMatch(null);
120
+ return;
121
+ }
122
+ const match2 = MentionRegex.exec(text);
123
+ setMatch(match2);
124
+ }
125
+ return editor.registerUpdateListener(({ editorState: state }) => {
126
+ state.read($onStateRead);
127
+ });
128
+ }, [editor]);
129
+ React.useEffect(() => {
130
+ function $handleBackspace(event) {
131
+ const selection = lexical.$getSelection();
132
+ if (selection === null)
133
+ return false;
134
+ if (lexical.$isNodeSelection(selection)) {
135
+ const nodes = selection.getNodes();
136
+ if (nodes.length !== 1)
137
+ return false;
138
+ const node = nodes[0];
139
+ if (!$isMentionNode(node))
140
+ return false;
141
+ const text = lexical.$createTextNode("@");
142
+ node.replace(text);
143
+ const newSelection = lexical.$createRangeSelection();
144
+ newSelection.setTextNodeRange(text, 1, text, 1);
145
+ lexical.$setSelection(newSelection);
146
+ event.preventDefault();
147
+ return true;
148
+ } else if (lexical.$isRangeSelection(selection)) {
149
+ if (!selection.isCollapsed())
150
+ return false;
151
+ const anchor = selection.anchor.getNode();
152
+ const prevSibling = anchor.getPreviousSibling();
153
+ if (selection.anchor.offset === 0 && $isMentionNode(prevSibling)) {
154
+ const text = lexical.$createTextNode("@");
155
+ prevSibling.replace(text);
156
+ const newSelection = lexical.$createRangeSelection();
157
+ newSelection.setTextNodeRange(text, 1, text, 1);
158
+ lexical.$setSelection(newSelection);
159
+ event.preventDefault();
160
+ return true;
161
+ } else if (lexical.$isElementNode(anchor)) {
162
+ const child = anchor.getChildAtIndex(selection.anchor.offset - 1);
163
+ if (!$isMentionNode(child))
164
+ return false;
165
+ const text = lexical.$createTextNode("@");
166
+ child.replace(text);
167
+ const newSelection = lexical.$createRangeSelection();
168
+ newSelection.setTextNodeRange(text, 1, text, 1);
169
+ lexical.$setSelection(newSelection);
170
+ event.preventDefault();
171
+ return true;
172
+ }
173
+ return false;
174
+ }
175
+ return false;
176
+ }
177
+ return editor.registerCommand(
178
+ lexical.KEY_BACKSPACE_COMMAND,
179
+ $handleBackspace,
180
+ lexical.COMMAND_PRIORITY_LOW
181
+ );
182
+ }, [editor, $isMentionNode]);
183
+ const handleValueSelect = React.useCallback(
184
+ (userId) => {
185
+ function $onValueSelect() {
186
+ if (match === null)
187
+ return;
188
+ setMatch(null);
189
+ const selection = lexical.$getSelection();
190
+ if (!lexical.$isRangeSelection(selection))
191
+ return;
192
+ if (!selection.isCollapsed())
193
+ return;
194
+ const anchor = selection.anchor;
195
+ if (anchor.type !== "text")
196
+ return;
197
+ const anchorNode = anchor.getNode();
198
+ if (!anchorNode.isSimpleText())
199
+ return;
200
+ const selectionOffset = anchor.offset;
201
+ const text = anchorNode.getTextContent().slice(0, selectionOffset);
202
+ const characterOffset = match[2].length;
203
+ const queryOffset = getFullMatchOffset(text, match[2], characterOffset);
204
+ const startOffset = selectionOffset - queryOffset;
205
+ if (startOffset < 0)
206
+ return;
207
+ const mentionNode = $createMentionNode(userId);
208
+ if (startOffset === 0) {
209
+ const [node] = anchorNode.splitText(selectionOffset);
210
+ node.replace(mentionNode);
211
+ } else {
212
+ const [, node] = anchorNode.splitText(startOffset, selectionOffset);
213
+ node.replace(mentionNode);
214
+ }
215
+ }
216
+ editor.update($onValueSelect);
217
+ },
218
+ [editor, match, $createMentionNode]
219
+ );
220
+ if (match === null || matchingString === void 0)
221
+ return null;
222
+ if (suggestions === void 0 || suggestions.length === 0)
223
+ return null;
224
+ const range = editor.getEditorState().read(() => $getRangeAtMatch(match));
225
+ if (range === null)
226
+ return null;
227
+ const rect = range.getBoundingClientRect();
228
+ return reactDom.createPortal(
229
+ /* @__PURE__ */ React.createElement(SuggestionsContext.Provider, {
230
+ value: suggestions
231
+ }, /* @__PURE__ */ React.createElement(OnValueSelectCallbackContext.Provider, {
232
+ value: handleValueSelect
233
+ }, /* @__PURE__ */ React.createElement(OnResetMatchCallbackContext.Provider, {
234
+ value: () => setMatch(null)
235
+ }, /* @__PURE__ */ React.createElement(SuggestionsRoot, {
236
+ rect,
237
+ key: matchingString
238
+ }, /* @__PURE__ */ React.createElement(MentionSuggestions, {
239
+ userIds: suggestions
240
+ }))))),
241
+ document.body
242
+ );
243
+ }
244
+ function SuggestionsRoot({
245
+ rect,
246
+ children
247
+ }) {
248
+ const [editor] = LexicalComposerContext.useLexicalComposerContext();
249
+ const divRef = React.useRef(null);
250
+ React.useLayoutEffect(() => {
251
+ const root = editor.getRootElement();
252
+ if (root === null)
253
+ return;
254
+ const div = divRef.current;
255
+ if (div === null)
256
+ return;
257
+ div.style.left = `${rect.left + window.scrollX}px`;
258
+ div.style.top = `${rect.bottom + window.scrollY}px`;
259
+ }, [editor, rect]);
260
+ return /* @__PURE__ */ React.createElement("div", {
261
+ ref: divRef,
262
+ style: { position: "absolute" }
263
+ }, children);
264
+ }
265
+ function useSuggestions() {
266
+ const suggestions = React.useContext(SuggestionsContext);
267
+ if (suggestions === null) {
268
+ throw new Error("useSuggestions: SuggestionsContext not found");
269
+ }
270
+ return suggestions;
271
+ }
272
+ function useOnValueSelectCallback() {
273
+ const onValueSelect = React.useContext(OnValueSelectCallbackContext);
274
+ if (onValueSelect === null) {
275
+ throw new Error("useOnValueSelectCallback: OnValueSelectContext not found");
276
+ }
277
+ return onValueSelect;
278
+ }
279
+ function useOnResetMatchCallback() {
280
+ const onResetMatch = React.useContext(OnResetMatchCallbackContext);
281
+ if (onResetMatch === null) {
282
+ throw new Error("useOnResetMatchCallback: OnResetMatchContext not found");
283
+ }
284
+ return onResetMatch;
285
+ }
286
+
287
+ exports.default = MentionPlugin;
288
+ exports.useOnResetMatchCallback = useOnResetMatchCallback;
289
+ exports.useOnValueSelectCallback = useOnValueSelectCallback;
290
+ exports.useSuggestions = useSuggestions;
291
+ //# sourceMappingURL=mention-plugin.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mention-plugin.js","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":["$getSelection","$isRangeSelection","$isTextNode","createContext","useLexicalComposerContext","useLiveblocksLexicalConfigContext","useState","kInternal","useRoomContextBundle","useEffect","match","$isNodeSelection","$createTextNode","$createRangeSelection","$setSelection","$isElementNode","KEY_BACKSPACE_COMMAND","COMMAND_PRIORITY_LOW","useCallback","createPortal","useRef","useLayoutEffect","useContext"],"mappings":"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"}