@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,84 +1,85 @@
|
|
|
1
1
|
import { DecoratorNode, $applyNodeReplacement } from 'lexical';
|
|
2
|
+
import { nanoid } from 'nanoid';
|
|
2
3
|
import * as React from 'react';
|
|
3
|
-
import {
|
|
4
|
+
import { Mention } from './mention-component.mjs';
|
|
5
|
+
import { User } from './user.mjs';
|
|
4
6
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
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
|
-
}
|
|
7
|
+
const MENTION_CHARACTER = "@";
|
|
8
|
+
class MentionNode extends DecoratorNode {
|
|
9
|
+
constructor(id, userId, key) {
|
|
10
|
+
super(key);
|
|
11
|
+
this.__id = id;
|
|
12
|
+
this.__userId = userId;
|
|
68
13
|
}
|
|
69
|
-
|
|
70
|
-
return
|
|
14
|
+
static getType() {
|
|
15
|
+
return "lb-mention";
|
|
71
16
|
}
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
return $applyNodeReplacement(node);
|
|
17
|
+
static clone(node) {
|
|
18
|
+
return new MentionNode(node.__id, node.__userId);
|
|
75
19
|
}
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
20
|
+
createDOM() {
|
|
21
|
+
const element = document.createElement("span");
|
|
22
|
+
element.style.display = "inline-block";
|
|
23
|
+
element.style.userSelect = "none";
|
|
24
|
+
return element;
|
|
25
|
+
}
|
|
26
|
+
updateDOM() {
|
|
27
|
+
return false;
|
|
28
|
+
}
|
|
29
|
+
static importDom() {
|
|
30
|
+
return {
|
|
31
|
+
span: () => ({
|
|
32
|
+
conversion: (element) => {
|
|
33
|
+
const value = atob(element.getAttribute("data-lexical-lb-mention"));
|
|
34
|
+
const node = $createMentionNode(value);
|
|
35
|
+
return { node };
|
|
36
|
+
},
|
|
37
|
+
priority: 1
|
|
38
|
+
})
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
exportDOM() {
|
|
42
|
+
const element = document.createElement("span");
|
|
43
|
+
const value = this.getTextContent();
|
|
44
|
+
element.setAttribute("data-lexical-lb-mention", btoa(value));
|
|
45
|
+
element.textContent = this.getTextContent();
|
|
46
|
+
return { element };
|
|
47
|
+
}
|
|
48
|
+
static importJSON(serializedNode) {
|
|
49
|
+
const node = $createMentionNode(serializedNode.userId);
|
|
50
|
+
return node;
|
|
51
|
+
}
|
|
52
|
+
exportJSON() {
|
|
53
|
+
return {
|
|
54
|
+
userId: this.__userId,
|
|
55
|
+
type: "lb-mention",
|
|
56
|
+
version: 1
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
getUserId() {
|
|
60
|
+
const self = this.getLatest();
|
|
61
|
+
return self.__userId;
|
|
62
|
+
}
|
|
63
|
+
getId() {
|
|
64
|
+
const self = this.getLatest();
|
|
65
|
+
return self.__id;
|
|
66
|
+
}
|
|
67
|
+
decorate() {
|
|
68
|
+
return /* @__PURE__ */ React.createElement(Mention, {
|
|
69
|
+
nodeKey: this.getKey()
|
|
70
|
+
}, MENTION_CHARACTER, /* @__PURE__ */ React.createElement(User, {
|
|
71
|
+
userId: this.getUserId()
|
|
72
|
+
}));
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
function $isMentionNode(node) {
|
|
76
|
+
return node instanceof MentionNode;
|
|
77
|
+
}
|
|
78
|
+
function $createMentionNode(userId) {
|
|
79
|
+
const id = `in_${nanoid()}`;
|
|
80
|
+
const node = new MentionNode(id, userId);
|
|
81
|
+
return $applyNodeReplacement(node);
|
|
81
82
|
}
|
|
82
83
|
|
|
83
|
-
export {
|
|
84
|
+
export { $createMentionNode, $isMentionNode, MentionNode };
|
|
84
85
|
//# sourceMappingURL=mention-node.mjs.map
|
|
@@ -1 +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 {
|
|
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 { nanoid } from \"nanoid\";\nimport type { JSX } from \"react\";\nimport * as React from \"react\";\n\nimport { Mention } from \"./mention-component\";\nimport { User } from \"./user\";\n\nconst MENTION_CHARACTER = \"@\";\n\nexport type SerializedMentionNode = Spread<\n {\n userId: string;\n },\n SerializedLexicalNode\n>;\nexport class MentionNode extends DecoratorNode<JSX.Element> {\n __id: string;\n __userId: string;\n\n constructor(id: string, userId: string, key?: NodeKey) {\n super(key);\n this.__id = id;\n this.__userId = userId;\n }\n\n static getType(): string {\n return \"lb-mention\";\n }\n\n static clone(node: MentionNode): MentionNode {\n return new MentionNode(node.__id, node.__userId);\n }\n\n createDOM(): HTMLElement {\n const element = document.createElement(\"span\");\n element.style.display = \"inline-block\";\n element.style.userSelect = \"none\";\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(element.getAttribute(\"data-lexical-lb-mention\")!);\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.userId);\n return node;\n }\n\n exportJSON(): SerializedMentionNode {\n return {\n userId: this.__userId,\n type: \"lb-mention\",\n version: 1,\n };\n }\n\n getUserId(): string {\n const self = this.getLatest();\n return self.__userId;\n }\n\n getId(): string {\n const self = this.getLatest();\n return self.__id;\n }\n\n decorate(): JSX.Element {\n return (\n <Mention nodeKey={this.getKey()}>\n {MENTION_CHARACTER}\n <User userId={this.getUserId()} />\n </Mention>\n );\n }\n}\n\nexport function $isMentionNode(\n node: LexicalNode | null | undefined\n): node is MentionNode {\n return node instanceof MentionNode;\n}\n\nexport function $createMentionNode(userId: string): MentionNode {\n const id = `in_${nanoid()}`;\n const node = new MentionNode(id, userId);\n return $applyNodeReplacement(node);\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -1,14 +1,17 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
var reactDom$1 = require('@floating-ui/react-dom');
|
|
5
4
|
var LexicalComposerContext = require('@lexical/react/LexicalComposerContext');
|
|
6
5
|
var core = require('@liveblocks/core');
|
|
7
6
|
var react = require('@liveblocks/react');
|
|
7
|
+
var reactUi = require('@liveblocks/react-ui');
|
|
8
8
|
var lexical = require('lexical');
|
|
9
9
|
var React = require('react');
|
|
10
10
|
var reactDom = require('react-dom');
|
|
11
|
-
var
|
|
11
|
+
var avatar = require('./avatar.js');
|
|
12
|
+
var mentionNode = require('./mention-node.js');
|
|
13
|
+
var suggestions = require('./suggestions.js');
|
|
14
|
+
var user = require('./user.js');
|
|
12
15
|
|
|
13
16
|
const MENTION_TRIGGER = "@";
|
|
14
17
|
const PUNCTUATIONS = `\\.,\\+\\*\\?\\$\\@\\|#{}\\(\\)\\^\\-\\[\\]\\\\/!%'"~=<>_:;`;
|
|
@@ -31,8 +34,8 @@ function $getAnchorNodeTextContent() {
|
|
|
31
34
|
const anchorOffset = anchor.offset;
|
|
32
35
|
return anchorNode.getTextContent().slice(0, anchorOffset);
|
|
33
36
|
}
|
|
34
|
-
function getFullMatchOffset(documentText, entryText,
|
|
35
|
-
let triggerOffset =
|
|
37
|
+
function getFullMatchOffset(documentText, entryText, offset2) {
|
|
38
|
+
let triggerOffset = offset2;
|
|
36
39
|
for (let i = triggerOffset; i <= entryText.length; i++) {
|
|
37
40
|
if (documentText.substr(-i) === entryText.substr(0, i)) {
|
|
38
41
|
triggerOffset = i;
|
|
@@ -40,8 +43,8 @@ function getFullMatchOffset(documentText, entryText, offset) {
|
|
|
40
43
|
}
|
|
41
44
|
return triggerOffset;
|
|
42
45
|
}
|
|
43
|
-
function $isCurrentSelectionAtBoundary(
|
|
44
|
-
if (
|
|
46
|
+
function $isCurrentSelectionAtBoundary(offset2) {
|
|
47
|
+
if (offset2 !== 0)
|
|
45
48
|
return false;
|
|
46
49
|
const selection = lexical.$getSelection();
|
|
47
50
|
if (!lexical.$isRangeSelection(selection))
|
|
@@ -78,40 +81,54 @@ function $getRangeAtMatch(match) {
|
|
|
78
81
|
return null;
|
|
79
82
|
}
|
|
80
83
|
}
|
|
81
|
-
const SuggestionsContext = React.createContext(null);
|
|
82
|
-
const OnValueSelectCallbackContext = React.createContext(null);
|
|
83
|
-
const OnResetMatchCallbackContext = React.createContext(null);
|
|
84
84
|
function MentionPlugin() {
|
|
85
85
|
const [editor] = LexicalComposerContext.useLexicalComposerContext();
|
|
86
|
-
|
|
87
|
-
mentions: {
|
|
88
|
-
factory: { $isMentionNode, $createMentionNode, MentionNode },
|
|
89
|
-
components: { MentionSuggestions }
|
|
90
|
-
}
|
|
91
|
-
} = liveblocksPluginProvider.useLiveblocksLexicalConfigContext();
|
|
92
|
-
if (!editor.hasNodes([MentionNode])) {
|
|
86
|
+
if (!editor.hasNodes([mentionNode.MentionNode])) {
|
|
93
87
|
throw new Error("MentionPlugin: MentionNode not registered on editor");
|
|
94
88
|
}
|
|
95
89
|
const [match, setMatch] = React.useState(null);
|
|
96
90
|
const matchingString = match?.[3];
|
|
97
|
-
const
|
|
98
|
-
|
|
99
|
-
} = react.useRoomContextBundle();
|
|
100
|
-
const suggestions = useMentionSuggestions(matchingString);
|
|
91
|
+
const suggestions$1 = reactUi.useMentionSuggestions(matchingString);
|
|
92
|
+
const room = react.useRoom();
|
|
101
93
|
React.useEffect(() => {
|
|
102
|
-
function handleMutation(mutations, {
|
|
94
|
+
function $handleMutation(mutations, {
|
|
103
95
|
prevEditorState
|
|
104
96
|
}) {
|
|
105
97
|
for (const [key, mutation] of mutations) {
|
|
106
|
-
if (mutation
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
98
|
+
if (mutation === "created") {
|
|
99
|
+
editor.getEditorState().read(() => {
|
|
100
|
+
const node = lexical.$getNodeByKey(key);
|
|
101
|
+
if (node === null)
|
|
102
|
+
return;
|
|
103
|
+
if (!mentionNode.$isMentionNode(node))
|
|
104
|
+
return;
|
|
105
|
+
room[core.kInternal].createTextMention(node.getUserId(), node.getId()).catch((err) => {
|
|
106
|
+
console.error(err);
|
|
107
|
+
});
|
|
108
|
+
});
|
|
109
|
+
} else if (mutation === "destroyed") {
|
|
110
|
+
prevEditorState.read(() => {
|
|
111
|
+
const node = lexical.$getNodeByKey(key);
|
|
112
|
+
if (node === null)
|
|
113
|
+
return;
|
|
114
|
+
if (!mentionNode.$isMentionNode(node))
|
|
115
|
+
return;
|
|
116
|
+
room[core.kInternal].deleteTextMention(node.getId()).catch((err) => {
|
|
117
|
+
console.error(err);
|
|
118
|
+
});
|
|
119
|
+
});
|
|
120
|
+
}
|
|
111
121
|
}
|
|
112
122
|
}
|
|
113
|
-
return editor.registerMutationListener(
|
|
114
|
-
|
|
123
|
+
return editor.registerMutationListener(
|
|
124
|
+
mentionNode.MentionNode,
|
|
125
|
+
(mutations, payload) => {
|
|
126
|
+
if (payload.updateTags.has("collaboration"))
|
|
127
|
+
return;
|
|
128
|
+
$handleMutation(mutations, payload);
|
|
129
|
+
}
|
|
130
|
+
);
|
|
131
|
+
}, [editor, room]);
|
|
115
132
|
React.useEffect(() => {
|
|
116
133
|
function $onStateRead() {
|
|
117
134
|
const text = $getAnchorNodeTextContent();
|
|
@@ -126,6 +143,15 @@ function MentionPlugin() {
|
|
|
126
143
|
state.read($onStateRead);
|
|
127
144
|
});
|
|
128
145
|
}, [editor]);
|
|
146
|
+
React.useEffect(() => {
|
|
147
|
+
const root = editor.getRootElement();
|
|
148
|
+
if (root === null)
|
|
149
|
+
return;
|
|
150
|
+
root.classList.add("lb-root");
|
|
151
|
+
return () => {
|
|
152
|
+
root.classList.remove("lb-root");
|
|
153
|
+
};
|
|
154
|
+
}, [editor]);
|
|
129
155
|
React.useEffect(() => {
|
|
130
156
|
function $handleBackspace(event) {
|
|
131
157
|
const selection = lexical.$getSelection();
|
|
@@ -136,7 +162,7 @@ function MentionPlugin() {
|
|
|
136
162
|
if (nodes.length !== 1)
|
|
137
163
|
return false;
|
|
138
164
|
const node = nodes[0];
|
|
139
|
-
if (
|
|
165
|
+
if (!mentionNode.$isMentionNode(node))
|
|
140
166
|
return false;
|
|
141
167
|
const text = lexical.$createTextNode("@");
|
|
142
168
|
node.replace(text);
|
|
@@ -150,7 +176,7 @@ function MentionPlugin() {
|
|
|
150
176
|
return false;
|
|
151
177
|
const anchor = selection.anchor.getNode();
|
|
152
178
|
const prevSibling = anchor.getPreviousSibling();
|
|
153
|
-
if (selection.anchor.offset === 0 &&
|
|
179
|
+
if (selection.anchor.offset === 0 && mentionNode.$isMentionNode(prevSibling)) {
|
|
154
180
|
const text = lexical.$createTextNode("@");
|
|
155
181
|
prevSibling.replace(text);
|
|
156
182
|
const newSelection = lexical.$createRangeSelection();
|
|
@@ -160,7 +186,7 @@ function MentionPlugin() {
|
|
|
160
186
|
return true;
|
|
161
187
|
} else if (lexical.$isElementNode(anchor)) {
|
|
162
188
|
const child = anchor.getChildAtIndex(selection.anchor.offset - 1);
|
|
163
|
-
if (
|
|
189
|
+
if (!mentionNode.$isMentionNode(child))
|
|
164
190
|
return false;
|
|
165
191
|
const text = lexical.$createTextNode("@");
|
|
166
192
|
child.replace(text);
|
|
@@ -179,7 +205,7 @@ function MentionPlugin() {
|
|
|
179
205
|
$handleBackspace,
|
|
180
206
|
lexical.COMMAND_PRIORITY_LOW
|
|
181
207
|
);
|
|
182
|
-
}, [editor
|
|
208
|
+
}, [editor]);
|
|
183
209
|
const handleValueSelect = React.useCallback(
|
|
184
210
|
(userId) => {
|
|
185
211
|
function $onValueSelect() {
|
|
@@ -204,88 +230,101 @@ function MentionPlugin() {
|
|
|
204
230
|
const startOffset = selectionOffset - queryOffset;
|
|
205
231
|
if (startOffset < 0)
|
|
206
232
|
return;
|
|
207
|
-
const mentionNode =
|
|
233
|
+
const mentionNode$1 = mentionNode.$createMentionNode(userId);
|
|
208
234
|
if (startOffset === 0) {
|
|
209
235
|
const [node] = anchorNode.splitText(selectionOffset);
|
|
210
|
-
node.replace(mentionNode);
|
|
236
|
+
node.replace(mentionNode$1);
|
|
211
237
|
} else {
|
|
212
238
|
const [, node] = anchorNode.splitText(startOffset, selectionOffset);
|
|
213
|
-
node.replace(mentionNode);
|
|
239
|
+
node.replace(mentionNode$1);
|
|
214
240
|
}
|
|
215
241
|
}
|
|
216
242
|
editor.update($onValueSelect);
|
|
217
243
|
},
|
|
218
|
-
[editor, match
|
|
244
|
+
[editor, match]
|
|
219
245
|
);
|
|
220
246
|
if (match === null || matchingString === void 0)
|
|
221
247
|
return null;
|
|
222
|
-
if (suggestions === void 0 || suggestions.length === 0)
|
|
248
|
+
if (suggestions$1 === void 0 || suggestions$1.length === 0)
|
|
223
249
|
return null;
|
|
224
250
|
const range = editor.getEditorState().read(() => $getRangeAtMatch(match));
|
|
225
251
|
if (range === null)
|
|
226
252
|
return null;
|
|
227
|
-
const rect = range.getBoundingClientRect();
|
|
228
253
|
return reactDom.createPortal(
|
|
229
|
-
/* @__PURE__ */ React.createElement(SuggestionsContext.Provider, {
|
|
230
|
-
value: suggestions
|
|
231
|
-
}, /* @__PURE__ */ React.createElement(OnValueSelectCallbackContext.Provider, {
|
|
254
|
+
/* @__PURE__ */ React.createElement(suggestions.SuggestionsContext.Provider, {
|
|
255
|
+
value: suggestions$1
|
|
256
|
+
}, /* @__PURE__ */ React.createElement(suggestions.OnValueSelectCallbackContext.Provider, {
|
|
232
257
|
value: handleValueSelect
|
|
233
|
-
}, /* @__PURE__ */ React.createElement(OnResetMatchCallbackContext.Provider, {
|
|
258
|
+
}, /* @__PURE__ */ React.createElement(suggestions.OnResetMatchCallbackContext.Provider, {
|
|
234
259
|
value: () => setMatch(null)
|
|
235
|
-
}, /* @__PURE__ */ React.createElement(
|
|
236
|
-
|
|
260
|
+
}, /* @__PURE__ */ React.createElement(SuggestionsPortal, {
|
|
261
|
+
range,
|
|
262
|
+
container: document.body,
|
|
237
263
|
key: matchingString
|
|
238
|
-
}, /* @__PURE__ */ React.createElement(
|
|
239
|
-
|
|
240
|
-
})
|
|
264
|
+
}, /* @__PURE__ */ React.createElement(suggestions.List, {
|
|
265
|
+
className: "lb-lexical-suggestions-list lb-lexical-mention-suggestions-list"
|
|
266
|
+
}, suggestions$1.map((userId) => /* @__PURE__ */ React.createElement(suggestions.Item, {
|
|
267
|
+
key: userId,
|
|
268
|
+
value: userId,
|
|
269
|
+
className: "lb-lexical-suggestions-list-item lb-lexical-mention-suggestion"
|
|
270
|
+
}, /* @__PURE__ */ React.createElement(avatar.Avatar, {
|
|
271
|
+
userId,
|
|
272
|
+
className: "lb-lexical-mention-suggestion-avatar"
|
|
273
|
+
}), /* @__PURE__ */ React.createElement(user.User, {
|
|
274
|
+
userId,
|
|
275
|
+
className: "lb-lexical-mention-suggestion-user"
|
|
276
|
+
})))))))),
|
|
241
277
|
document.body
|
|
242
278
|
);
|
|
243
279
|
}
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
children
|
|
280
|
+
const SUGGESTIONS_COLLISION_PADDING = 10;
|
|
281
|
+
function SuggestionsPortal({
|
|
282
|
+
children,
|
|
283
|
+
range,
|
|
284
|
+
container
|
|
247
285
|
}) {
|
|
248
|
-
const
|
|
249
|
-
|
|
286
|
+
const {
|
|
287
|
+
refs: { setReference, setFloating },
|
|
288
|
+
strategy,
|
|
289
|
+
x,
|
|
290
|
+
y
|
|
291
|
+
} = reactDom$1.useFloating({
|
|
292
|
+
strategy: "fixed",
|
|
293
|
+
placement: "top-start",
|
|
294
|
+
middleware: [
|
|
295
|
+
reactDom$1.flip({ padding: SUGGESTIONS_COLLISION_PADDING, crossAxis: false }),
|
|
296
|
+
reactDom$1.offset(10),
|
|
297
|
+
reactDom$1.hide({ padding: SUGGESTIONS_COLLISION_PADDING }),
|
|
298
|
+
reactDom$1.shift({ padding: SUGGESTIONS_COLLISION_PADDING, limiter: reactDom$1.limitShift() }),
|
|
299
|
+
reactDom$1.size({ padding: SUGGESTIONS_COLLISION_PADDING })
|
|
300
|
+
],
|
|
301
|
+
whileElementsMounted: (...args) => {
|
|
302
|
+
return reactDom$1.autoUpdate(...args, {
|
|
303
|
+
animationFrame: true
|
|
304
|
+
});
|
|
305
|
+
}
|
|
306
|
+
});
|
|
250
307
|
React.useLayoutEffect(() => {
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
}
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
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;
|
|
308
|
+
setReference({
|
|
309
|
+
getBoundingClientRect: () => range.getBoundingClientRect()
|
|
310
|
+
});
|
|
311
|
+
}, [setReference, range]);
|
|
312
|
+
return reactDom.createPortal(
|
|
313
|
+
/* @__PURE__ */ React.createElement("div", {
|
|
314
|
+
ref: setFloating,
|
|
315
|
+
style: {
|
|
316
|
+
position: strategy,
|
|
317
|
+
top: 0,
|
|
318
|
+
left: 0,
|
|
319
|
+
transform: `translate3d(${Math.round(x)}px, ${Math.round(y)}px, 0)`,
|
|
320
|
+
minWidth: "max-content"
|
|
321
|
+
},
|
|
322
|
+
className: "lb-root lb-portal lb-elevation lb-lexical-suggestions lb-lexical-mention-suggestions"
|
|
323
|
+
}, children),
|
|
324
|
+
container
|
|
325
|
+
);
|
|
285
326
|
}
|
|
286
327
|
|
|
287
|
-
exports.
|
|
288
|
-
exports.
|
|
289
|
-
exports.useOnValueSelectCallback = useOnValueSelectCallback;
|
|
290
|
-
exports.useSuggestions = useSuggestions;
|
|
328
|
+
exports.MentionPlugin = MentionPlugin;
|
|
329
|
+
exports.SUGGESTIONS_COLLISION_PADDING = SUGGESTIONS_COLLISION_PADDING;
|
|
291
330
|
//# sourceMappingURL=mention-plugin.js.map
|
|
@@ -1 +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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"}
|
|
1
|
+
{"version":3,"file":"mention-plugin.js","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":["$getSelection","$isRangeSelection","offset","$isTextNode","useLexicalComposerContext","MentionNode","useState","suggestions","useMentionSuggestions","useRoom","useEffect","$getNodeByKey","$isMentionNode","kInternal","match","$isNodeSelection","$createTextNode","$createRangeSelection","$setSelection","$isElementNode","KEY_BACKSPACE_COMMAND","COMMAND_PRIORITY_LOW","useCallback","mentionNode","$createMentionNode","createPortal","SuggestionsContext","OnValueSelectCallbackContext","OnResetMatchCallbackContext","Suggestions.List","Suggestions.Item","Avatar","User","useFloating","flip","hide","shift","limitShift","size","autoUpdate","useLayoutEffect"],"mappings":"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"}
|