@lexical/react 0.8.1 → 0.9.0
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/LexicalAutoEmbedPlugin.d.ts +1 -0
- package/LexicalAutoEmbedPlugin.dev.js +11 -0
- package/LexicalAutoFocusPlugin.dev.js +1 -0
- package/LexicalAutoLinkPlugin.d.ts +1 -0
- package/LexicalAutoLinkPlugin.dev.js +50 -7
- package/LexicalBlockWithAlignableContents.dev.js +13 -2
- package/LexicalBlockWithAlignableContents.prod.js +4 -4
- package/LexicalCharacterLimitPlugin.d.ts +1 -0
- package/LexicalCharacterLimitPlugin.dev.js +46 -7
- package/LexicalCheckListPlugin.dev.js +48 -10
- package/LexicalClearEditorPlugin.d.ts +1 -0
- package/LexicalClearEditorPlugin.dev.js +1 -1
- package/LexicalCollaborationContext.dev.js +3 -0
- package/LexicalCollaborationPlugin.d.ts +3 -2
- package/LexicalCollaborationPlugin.dev.js +35 -6
- package/LexicalComposer.d.ts +1 -0
- package/LexicalComposer.dev.js +10 -6
- package/LexicalComposerContext.dev.js +6 -0
- package/LexicalContentEditable.dev.js +0 -1
- package/LexicalDecoratorBlockNode.d.ts +1 -0
- package/LexicalDecoratorBlockNode.dev.js +5 -0
- package/LexicalErrorBoundary.d.ts +1 -0
- package/LexicalHashtagPlugin.d.ts +1 -0
- package/LexicalHashtagPlugin.dev.js +43 -73
- package/LexicalHorizontalRuleNode.d.ts +1 -0
- package/LexicalHorizontalRuleNode.dev.js +22 -0
- package/LexicalHorizontalRulePlugin.dev.js +4 -0
- package/LexicalLinkPlugin.dev.js +10 -4
- package/LexicalListPlugin.dev.js +2 -0
- package/LexicalMarkdownShortcutPlugin.dev.js +2 -2
- package/LexicalNestedComposer.dev.js +12 -6
- package/LexicalNestedComposer.prod.js +2 -2
- package/LexicalNodeEventPlugin.dev.js +3 -5
- package/LexicalOnChangePlugin.dev.js +1 -1
- package/LexicalPlainTextPlugin.d.ts +1 -0
- package/LexicalPlainTextPlugin.dev.js +12 -8
- package/LexicalRichTextPlugin.d.ts +1 -0
- package/LexicalRichTextPlugin.dev.js +12 -8
- package/LexicalTabIndentationPlugin.dev.js +3 -1
- package/{LexicalTableOfContents__EXPERIMENTAL.d.ts → LexicalTableOfContents.d.ts} +1 -0
- package/{LexicalTableOfContents__EXPERIMENTAL.dev.js → LexicalTableOfContents.dev.js} +33 -5
- package/{DEPRECATED_useLexical.js → LexicalTableOfContents.js} +2 -2
- package/LexicalTablePlugin.d.ts +1 -0
- package/LexicalTablePlugin.dev.js +19 -5
- package/LexicalTreeView.d.ts +1 -0
- package/LexicalTreeView.dev.js +113 -21
- package/LexicalTreeView.prod.js +16 -15
- package/LexicalTypeaheadMenuPlugin.dev.js +123 -17
- package/LexicalTypeaheadMenuPlugin.prod.js +18 -18
- package/package.json +19 -19
- package/shared/useYjsCollaboration.d.ts +3 -4
- package/useLexicalEditable.dev.js +5 -1
- package/useLexicalIsTextContentEmpty.dev.js +0 -1
- package/useLexicalNodeSelection.dev.js +7 -0
- package/useLexicalSubscription.dev.js +3 -1
- package/DEPRECATED_useLexical.d.ts +0 -18
- package/DEPRECATED_useLexical.dev.js +0 -104
- package/DEPRECATED_useLexical.js.flow +0 -25
- package/DEPRECATED_useLexical.prod.js +0 -8
- package/DEPRECATED_useLexicalCanShowPlaceholder.d.ts +0 -9
- package/DEPRECATED_useLexicalCanShowPlaceholder.dev.js +0 -72
- package/DEPRECATED_useLexicalCanShowPlaceholder.js +0 -9
- package/DEPRECATED_useLexicalCanShowPlaceholder.js.flow +0 -15
- package/DEPRECATED_useLexicalCanShowPlaceholder.prod.js +0 -8
- package/DEPRECATED_useLexicalCharacterLimit.d.ts +0 -8
- package/DEPRECATED_useLexicalCharacterLimit.dev.js +0 -213
- package/DEPRECATED_useLexicalCharacterLimit.js +0 -9
- package/DEPRECATED_useLexicalCharacterLimit.js.flow +0 -31
- package/DEPRECATED_useLexicalCharacterLimit.prod.js +0 -13
- package/DEPRECATED_useLexicalEditor.d.ts +0 -9
- package/DEPRECATED_useLexicalEditor.dev.js +0 -87
- package/DEPRECATED_useLexicalEditor.js +0 -9
- package/DEPRECATED_useLexicalEditor.prod.js +0 -8
- package/DEPRECATED_useLexicalHistory.d.ts +0 -12
- package/DEPRECATED_useLexicalHistory.dev.js +0 -38
- package/DEPRECATED_useLexicalHistory.js +0 -9
- package/DEPRECATED_useLexicalHistory.js.flow +0 -34
- package/DEPRECATED_useLexicalHistory.prod.js +0 -7
- package/DEPRECATED_useLexicalPlainText.d.ts +0 -10
- package/DEPRECATED_useLexicalPlainText.dev.js +0 -88
- package/DEPRECATED_useLexicalPlainText.js +0 -9
- package/DEPRECATED_useLexicalPlainText.js.flow +0 -17
- package/DEPRECATED_useLexicalPlainText.prod.js +0 -8
- package/DEPRECATED_useLexicalRichText.d.ts +0 -10
- package/DEPRECATED_useLexicalRichText.dev.js +0 -88
- package/DEPRECATED_useLexicalRichText.js +0 -9
- package/DEPRECATED_useLexicalRichText.js.flow +0 -17
- package/DEPRECATED_useLexicalRichText.prod.js +0 -8
- package/LexicalTableOfContents__EXPERIMENTAL.js +0 -9
- /package/{LexicalTableOfContents__EXPERIMENTAL.js.flow → LexicalTableOfContents.js.flow} +0 -0
- /package/{LexicalTableOfContents__EXPERIMENTAL.prod.js → LexicalTableOfContents.prod.js} +0 -0
|
@@ -28,6 +28,7 @@ class AutoEmbedOption extends LexicalTypeaheadMenuPlugin.TypeaheadOption {
|
|
|
28
28
|
this.title = title;
|
|
29
29
|
this.onSelect = options.onSelect.bind(this);
|
|
30
30
|
}
|
|
31
|
+
|
|
31
32
|
}
|
|
32
33
|
function LexicalAutoEmbedPlugin({
|
|
33
34
|
embedConfigs,
|
|
@@ -45,10 +46,12 @@ function LexicalAutoEmbedPlugin({
|
|
|
45
46
|
const checkIfLinkNodeIsEmbeddable = React.useCallback(key => {
|
|
46
47
|
editor.getEditorState().read(async () => {
|
|
47
48
|
const linkNode = lexical.$getNodeByKey(key);
|
|
49
|
+
|
|
48
50
|
if (link.$isLinkNode(linkNode)) {
|
|
49
51
|
for (let i = 0; i < embedConfigs.length; i++) {
|
|
50
52
|
const embedConfig = embedConfigs[i];
|
|
51
53
|
const urlMatch = await Promise.resolve(embedConfig.parseUrl(linkNode.__url));
|
|
54
|
+
|
|
52
55
|
if (urlMatch != null) {
|
|
53
56
|
setActiveEmbedConfig(embedConfig);
|
|
54
57
|
setNodeKey(linkNode.getKey());
|
|
@@ -70,6 +73,7 @@ function LexicalAutoEmbedPlugin({
|
|
|
70
73
|
}
|
|
71
74
|
}
|
|
72
75
|
};
|
|
76
|
+
|
|
73
77
|
return utils.mergeRegister(...[link.LinkNode, link.AutoLinkNode].map(Klass => editor.registerMutationListener(Klass, (...args) => listener(...args))));
|
|
74
78
|
}, [checkIfLinkNodeIsEmbeddable, editor, embedConfigs, nodeKey, reset]);
|
|
75
79
|
React.useEffect(() => {
|
|
@@ -77,10 +81,12 @@ function LexicalAutoEmbedPlugin({
|
|
|
77
81
|
const embedConfig = embedConfigs.find(({
|
|
78
82
|
type
|
|
79
83
|
}) => type === embedConfigType);
|
|
84
|
+
|
|
80
85
|
if (embedConfig) {
|
|
81
86
|
onOpenEmbedModalForConfig(embedConfig);
|
|
82
87
|
return true;
|
|
83
88
|
}
|
|
89
|
+
|
|
84
90
|
return false;
|
|
85
91
|
}, lexical.COMMAND_PRIORITY_EDITOR);
|
|
86
92
|
}, [editor, embedConfigs, onOpenEmbedModalForConfig]);
|
|
@@ -88,16 +94,21 @@ function LexicalAutoEmbedPlugin({
|
|
|
88
94
|
if (activeEmbedConfig != null && nodeKey != null) {
|
|
89
95
|
const linkNode = editor.getEditorState().read(() => {
|
|
90
96
|
const node = lexical.$getNodeByKey(nodeKey);
|
|
97
|
+
|
|
91
98
|
if (link.$isLinkNode(node)) {
|
|
92
99
|
return node;
|
|
93
100
|
}
|
|
101
|
+
|
|
94
102
|
return null;
|
|
95
103
|
});
|
|
104
|
+
|
|
96
105
|
if (link.$isLinkNode(linkNode)) {
|
|
97
106
|
const result = await Promise.resolve(activeEmbedConfig.parseUrl(linkNode.__url));
|
|
107
|
+
|
|
98
108
|
if (result != null) {
|
|
99
109
|
editor.update(() => {
|
|
100
110
|
activeEmbedConfig.insertNode(editor, result);
|
|
111
|
+
|
|
101
112
|
if (linkNode.isAttached()) {
|
|
102
113
|
linkNode.remove();
|
|
103
114
|
}
|
|
@@ -28,6 +28,7 @@ function AutoFocusPlugin({
|
|
|
28
28
|
// of this plugin, which should preserve focus too.
|
|
29
29
|
const activeElement = document.activeElement;
|
|
30
30
|
const rootElement = editor.getRootElement();
|
|
31
|
+
|
|
31
32
|
if (rootElement !== null && (activeElement === null || !rootElement.contains(activeElement))) {
|
|
32
33
|
// Note: preventScroll won't work in Webkit.
|
|
33
34
|
rootElement.focus({
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
* LICENSE file in the root directory of this source tree.
|
|
6
6
|
*
|
|
7
7
|
*/
|
|
8
|
+
/// <reference types="react" />
|
|
8
9
|
import type { LinkAttributes } from '@lexical/link';
|
|
9
10
|
declare type ChangeHandler = (url: string | null, prevUrl: string | null) => void;
|
|
10
11
|
declare type LinkMatcherResult = {
|
|
@@ -19,65 +19,86 @@ var react = require('react');
|
|
|
19
19
|
* LICENSE file in the root directory of this source tree.
|
|
20
20
|
*
|
|
21
21
|
*/
|
|
22
|
+
|
|
22
23
|
function findFirstMatch(text, matchers) {
|
|
23
24
|
for (let i = 0; i < matchers.length; i++) {
|
|
24
25
|
const match = matchers[i](text);
|
|
26
|
+
|
|
25
27
|
if (match) {
|
|
26
28
|
return match;
|
|
27
29
|
}
|
|
28
30
|
}
|
|
31
|
+
|
|
29
32
|
return null;
|
|
30
33
|
}
|
|
34
|
+
|
|
31
35
|
const PUNCTUATION_OR_SPACE = /[.,;\s]/;
|
|
36
|
+
|
|
32
37
|
function isSeparator(char) {
|
|
33
38
|
return PUNCTUATION_OR_SPACE.test(char);
|
|
34
39
|
}
|
|
40
|
+
|
|
35
41
|
function endsWithSeparator(textContent) {
|
|
36
42
|
return isSeparator(textContent[textContent.length - 1]);
|
|
37
43
|
}
|
|
44
|
+
|
|
38
45
|
function startsWithSeparator(textContent) {
|
|
39
46
|
return isSeparator(textContent[0]);
|
|
40
47
|
}
|
|
48
|
+
|
|
41
49
|
function isPreviousNodeValid(node) {
|
|
42
50
|
let previousNode = node.getPreviousSibling();
|
|
51
|
+
|
|
43
52
|
if (lexical.$isElementNode(previousNode)) {
|
|
44
53
|
previousNode = previousNode.getLastDescendant();
|
|
45
54
|
}
|
|
55
|
+
|
|
46
56
|
return previousNode === null || lexical.$isLineBreakNode(previousNode) || lexical.$isTextNode(previousNode) && endsWithSeparator(previousNode.getTextContent());
|
|
47
57
|
}
|
|
58
|
+
|
|
48
59
|
function isNextNodeValid(node) {
|
|
49
60
|
let nextNode = node.getNextSibling();
|
|
61
|
+
|
|
50
62
|
if (lexical.$isElementNode(nextNode)) {
|
|
51
63
|
nextNode = nextNode.getFirstDescendant();
|
|
52
64
|
}
|
|
65
|
+
|
|
53
66
|
return nextNode === null || lexical.$isLineBreakNode(nextNode) || lexical.$isTextNode(nextNode) && startsWithSeparator(nextNode.getTextContent());
|
|
54
67
|
}
|
|
68
|
+
|
|
55
69
|
function isContentAroundIsValid(matchStart, matchEnd, text, node) {
|
|
56
70
|
const contentBeforeIsValid = matchStart > 0 ? isSeparator(text[matchStart - 1]) : isPreviousNodeValid(node);
|
|
71
|
+
|
|
57
72
|
if (!contentBeforeIsValid) {
|
|
58
73
|
return false;
|
|
59
74
|
}
|
|
75
|
+
|
|
60
76
|
const contentAfterIsValid = matchEnd < text.length ? isSeparator(text[matchEnd]) : isNextNodeValid(node);
|
|
61
77
|
return contentAfterIsValid;
|
|
62
78
|
}
|
|
79
|
+
|
|
63
80
|
function handleLinkCreation(node, matchers, onChange) {
|
|
64
81
|
const nodeText = node.getTextContent();
|
|
65
82
|
let text = nodeText;
|
|
66
83
|
let invalidMatchEnd = 0;
|
|
67
84
|
let remainingTextNode = node;
|
|
68
85
|
let match;
|
|
86
|
+
|
|
69
87
|
while ((match = findFirstMatch(text, matchers)) && match !== null) {
|
|
70
88
|
const matchStart = match.index;
|
|
71
89
|
const matchLength = match.length;
|
|
72
90
|
const matchEnd = matchStart + matchLength;
|
|
73
91
|
const isValid = isContentAroundIsValid(invalidMatchEnd + matchStart, invalidMatchEnd + matchEnd, nodeText, node);
|
|
92
|
+
|
|
74
93
|
if (isValid) {
|
|
75
94
|
let linkTextNode;
|
|
95
|
+
|
|
76
96
|
if (invalidMatchEnd + matchStart === 0) {
|
|
77
97
|
[linkTextNode, remainingTextNode] = remainingTextNode.splitText(invalidMatchEnd + matchLength);
|
|
78
98
|
} else {
|
|
79
99
|
[, linkTextNode, remainingTextNode] = remainingTextNode.splitText(invalidMatchEnd + matchStart, invalidMatchEnd + matchStart + matchLength);
|
|
80
100
|
}
|
|
101
|
+
|
|
81
102
|
const linkNode = link.$createAutoLinkNode(match.url, match.attributes);
|
|
82
103
|
const textNode = lexical.$createTextNode(match.text);
|
|
83
104
|
textNode.setFormat(linkTextNode.getFormat());
|
|
@@ -89,82 +110,99 @@ function handleLinkCreation(node, matchers, onChange) {
|
|
|
89
110
|
} else {
|
|
90
111
|
invalidMatchEnd += matchEnd;
|
|
91
112
|
}
|
|
113
|
+
|
|
92
114
|
text = text.substring(matchEnd);
|
|
93
115
|
}
|
|
94
116
|
}
|
|
117
|
+
|
|
95
118
|
function handleLinkEdit(linkNode, matchers, onChange) {
|
|
96
119
|
// Check children are simple text
|
|
97
120
|
const children = linkNode.getChildren();
|
|
98
121
|
const childrenLength = children.length;
|
|
122
|
+
|
|
99
123
|
for (let i = 0; i < childrenLength; i++) {
|
|
100
124
|
const child = children[i];
|
|
125
|
+
|
|
101
126
|
if (!lexical.$isTextNode(child) || !child.isSimpleText()) {
|
|
102
127
|
replaceWithChildren(linkNode);
|
|
103
128
|
onChange(null, linkNode.getURL());
|
|
104
129
|
return;
|
|
105
130
|
}
|
|
106
|
-
}
|
|
131
|
+
} // Check text content fully matches
|
|
132
|
+
|
|
107
133
|
|
|
108
|
-
// Check text content fully matches
|
|
109
134
|
const text = linkNode.getTextContent();
|
|
110
135
|
const match = findFirstMatch(text, matchers);
|
|
136
|
+
|
|
111
137
|
if (match === null || match.text !== text) {
|
|
112
138
|
replaceWithChildren(linkNode);
|
|
113
139
|
onChange(null, linkNode.getURL());
|
|
114
140
|
return;
|
|
115
|
-
}
|
|
141
|
+
} // Check neighbors
|
|
142
|
+
|
|
116
143
|
|
|
117
|
-
// Check neighbors
|
|
118
144
|
if (!isPreviousNodeValid(linkNode) || !isNextNodeValid(linkNode)) {
|
|
119
145
|
replaceWithChildren(linkNode);
|
|
120
146
|
onChange(null, linkNode.getURL());
|
|
121
147
|
return;
|
|
122
148
|
}
|
|
149
|
+
|
|
123
150
|
const url = linkNode.getURL();
|
|
151
|
+
|
|
124
152
|
if (url !== match.url) {
|
|
125
153
|
linkNode.setURL(match.url);
|
|
126
154
|
onChange(match.url, url);
|
|
127
155
|
}
|
|
156
|
+
|
|
128
157
|
if (match.attributes) {
|
|
129
158
|
const rel = linkNode.getRel();
|
|
159
|
+
|
|
130
160
|
if (rel !== match.attributes.rel) {
|
|
131
161
|
linkNode.setRel(match.attributes.rel || null);
|
|
132
162
|
onChange(match.attributes.rel || null, rel);
|
|
133
163
|
}
|
|
164
|
+
|
|
134
165
|
const target = linkNode.getTarget();
|
|
166
|
+
|
|
135
167
|
if (target !== match.attributes.target) {
|
|
136
168
|
linkNode.setTarget(match.attributes.target || null);
|
|
137
169
|
onChange(match.attributes.target || null, target);
|
|
138
170
|
}
|
|
139
171
|
}
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
// Bad neighbours are edits in neighbor nodes that make AutoLinks incompatible.
|
|
172
|
+
} // Bad neighbours are edits in neighbor nodes that make AutoLinks incompatible.
|
|
143
173
|
// Given the creation preconditions, these can only be simple text nodes.
|
|
174
|
+
|
|
175
|
+
|
|
144
176
|
function handleBadNeighbors(textNode, matchers, onChange) {
|
|
145
177
|
const previousSibling = textNode.getPreviousSibling();
|
|
146
178
|
const nextSibling = textNode.getNextSibling();
|
|
147
179
|
const text = textNode.getTextContent();
|
|
180
|
+
|
|
148
181
|
if (link.$isAutoLinkNode(previousSibling) && !startsWithSeparator(text)) {
|
|
149
182
|
previousSibling.append(textNode);
|
|
150
183
|
handleLinkEdit(previousSibling, matchers, onChange);
|
|
151
184
|
onChange(null, previousSibling.getURL());
|
|
152
185
|
}
|
|
186
|
+
|
|
153
187
|
if (link.$isAutoLinkNode(nextSibling) && !endsWithSeparator(text)) {
|
|
154
188
|
replaceWithChildren(nextSibling);
|
|
155
189
|
handleLinkEdit(nextSibling, matchers, onChange);
|
|
156
190
|
onChange(null, nextSibling.getURL());
|
|
157
191
|
}
|
|
158
192
|
}
|
|
193
|
+
|
|
159
194
|
function replaceWithChildren(node) {
|
|
160
195
|
const children = node.getChildren();
|
|
161
196
|
const childrenLength = children.length;
|
|
197
|
+
|
|
162
198
|
for (let j = childrenLength - 1; j >= 0; j--) {
|
|
163
199
|
node.insertAfter(children[j]);
|
|
164
200
|
}
|
|
201
|
+
|
|
165
202
|
node.remove();
|
|
166
203
|
return children.map(child => child.getLatest());
|
|
167
204
|
}
|
|
205
|
+
|
|
168
206
|
function useAutoLink(editor, matchers, onChange) {
|
|
169
207
|
react.useEffect(() => {
|
|
170
208
|
if (!editor.hasNodes([link.AutoLinkNode])) {
|
|
@@ -172,25 +210,30 @@ function useAutoLink(editor, matchers, onChange) {
|
|
|
172
210
|
throw Error(`LexicalAutoLinkPlugin: AutoLinkNode not registered on editor`);
|
|
173
211
|
}
|
|
174
212
|
}
|
|
213
|
+
|
|
175
214
|
const onChangeWrapped = (url, prevUrl) => {
|
|
176
215
|
if (onChange) {
|
|
177
216
|
onChange(url, prevUrl);
|
|
178
217
|
}
|
|
179
218
|
};
|
|
219
|
+
|
|
180
220
|
return utils.mergeRegister(editor.registerNodeTransform(lexical.TextNode, textNode => {
|
|
181
221
|
const parent = textNode.getParentOrThrow();
|
|
182
222
|
const previous = textNode.getPreviousSibling();
|
|
223
|
+
|
|
183
224
|
if (link.$isAutoLinkNode(parent)) {
|
|
184
225
|
handleLinkEdit(parent, matchers, onChangeWrapped);
|
|
185
226
|
} else if (!link.$isLinkNode(parent)) {
|
|
186
227
|
if (textNode.isSimpleText() && (startsWithSeparator(textNode.getTextContent()) || !link.$isAutoLinkNode(previous))) {
|
|
187
228
|
handleLinkCreation(textNode, matchers, onChangeWrapped);
|
|
188
229
|
}
|
|
230
|
+
|
|
189
231
|
handleBadNeighbors(textNode, matchers, onChangeWrapped);
|
|
190
232
|
}
|
|
191
233
|
}));
|
|
192
234
|
}, [editor, matchers, onChange]);
|
|
193
235
|
}
|
|
236
|
+
|
|
194
237
|
function AutoLinkPlugin({
|
|
195
238
|
matchers,
|
|
196
239
|
onChange
|
|
@@ -34,25 +34,31 @@ function BlockWithAlignableContents({
|
|
|
34
34
|
event.preventDefault();
|
|
35
35
|
editor.update(() => {
|
|
36
36
|
const node = lexical.$getNodeByKey(nodeKey);
|
|
37
|
+
if (node === null) return;
|
|
38
|
+
lexical.$setSelection(node.selectPrevious());
|
|
39
|
+
|
|
37
40
|
if (lexical.$isDecoratorNode(node)) {
|
|
38
41
|
node.remove();
|
|
39
42
|
}
|
|
40
|
-
setSelected(false);
|
|
41
43
|
});
|
|
42
44
|
}
|
|
45
|
+
|
|
43
46
|
return false;
|
|
44
|
-
}, [editor, isSelected, nodeKey
|
|
47
|
+
}, [editor, isSelected, nodeKey]);
|
|
45
48
|
React.useEffect(() => {
|
|
46
49
|
return utils.mergeRegister(editor.registerCommand(lexical.FORMAT_ELEMENT_COMMAND, formatType => {
|
|
47
50
|
if (isSelected) {
|
|
48
51
|
const selection = lexical.$getSelection();
|
|
52
|
+
|
|
49
53
|
if (lexical.$isNodeSelection(selection)) {
|
|
50
54
|
const node = lexical.$getNodeByKey(nodeKey);
|
|
55
|
+
|
|
51
56
|
if (LexicalDecoratorBlockNode.$isDecoratorBlockNode(node)) {
|
|
52
57
|
node.setFormat(formatType);
|
|
53
58
|
}
|
|
54
59
|
} else if (lexical.$isRangeSelection(selection)) {
|
|
55
60
|
const nodes = selection.getNodes();
|
|
61
|
+
|
|
56
62
|
for (const node of nodes) {
|
|
57
63
|
if (LexicalDecoratorBlockNode.$isDecoratorBlockNode(node)) {
|
|
58
64
|
node.setFormat(formatType);
|
|
@@ -62,18 +68,23 @@ function BlockWithAlignableContents({
|
|
|
62
68
|
}
|
|
63
69
|
}
|
|
64
70
|
}
|
|
71
|
+
|
|
65
72
|
return true;
|
|
66
73
|
}
|
|
74
|
+
|
|
67
75
|
return false;
|
|
68
76
|
}, lexical.COMMAND_PRIORITY_LOW), editor.registerCommand(lexical.CLICK_COMMAND, event => {
|
|
69
77
|
if (event.target === ref.current) {
|
|
70
78
|
event.preventDefault();
|
|
79
|
+
|
|
71
80
|
if (!event.shiftKey) {
|
|
72
81
|
clearSelection();
|
|
73
82
|
}
|
|
83
|
+
|
|
74
84
|
setSelected(!isSelected);
|
|
75
85
|
return true;
|
|
76
86
|
}
|
|
87
|
+
|
|
77
88
|
return false;
|
|
78
89
|
}, lexical.COMMAND_PRIORITY_LOW), editor.registerCommand(lexical.KEY_DELETE_COMMAND, onDelete, lexical.COMMAND_PRIORITY_LOW), editor.registerCommand(lexical.KEY_BACKSPACE_COMMAND, onDelete, lexical.COMMAND_PRIORITY_LOW));
|
|
79
90
|
}, [clearSelection, editor, isSelected, nodeKey, onDelete, setSelected]);
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* This source code is licensed under the MIT license found in the
|
|
5
5
|
* LICENSE file in the root directory of this source tree.
|
|
6
6
|
*/
|
|
7
|
-
'use strict';var a=require("@lexical/react/LexicalComposerContext"),h=require("@lexical/react/LexicalDecoratorBlockNode"),
|
|
8
|
-
exports.BlockWithAlignableContents=function({children:w,format:
|
|
9
|
-
u.$getNodeByKey(g);h.$isDecoratorBlockNode(f)&&f.setFormat(
|
|
10
|
-
u.COMMAND_PRIORITY_LOW)),[r,d,e,g,
|
|
7
|
+
'use strict';var a=require("@lexical/react/LexicalComposerContext"),h=require("@lexical/react/LexicalDecoratorBlockNode"),l=require("@lexical/react/useLexicalNodeSelection"),m=require("@lexical/utils"),u=require("lexical"),v=require("react");
|
|
8
|
+
exports.BlockWithAlignableContents=function({children:w,format:n,nodeKey:g,className:p}){let [d]=a.useLexicalComposerContext(),[e,q,r]=l.useLexicalNodeSelection(g),t=v.useRef(null),k=v.useCallback(c=>{e&&u.$isNodeSelection(u.$getSelection())&&(c.preventDefault(),d.update(()=>{const b=u.$getNodeByKey(g);null!==b&&(u.$setSelection(b.selectPrevious()),u.$isDecoratorNode(b)&&b.remove())}));return!1},[d,e,g]);v.useEffect(()=>m.mergeRegister(d.registerCommand(u.FORMAT_ELEMENT_COMMAND,c=>{if(e){var b=u.$getSelection();
|
|
9
|
+
if(u.$isNodeSelection(b)){var f=u.$getNodeByKey(g);h.$isDecoratorBlockNode(f)&&f.setFormat(c)}else if(u.$isRangeSelection(b)){b=b.getNodes();for(f of b)h.$isDecoratorBlockNode(f)?f.setFormat(c):m.$getNearestBlockElementAncestorOrThrow(f).setFormat(c)}return!0}return!1},u.COMMAND_PRIORITY_LOW),d.registerCommand(u.CLICK_COMMAND,c=>c.target===t.current?(c.preventDefault(),c.shiftKey||r(),q(!e),!0):!1,u.COMMAND_PRIORITY_LOW),d.registerCommand(u.KEY_DELETE_COMMAND,k,u.COMMAND_PRIORITY_LOW),d.registerCommand(u.KEY_BACKSPACE_COMMAND,
|
|
10
|
+
k,u.COMMAND_PRIORITY_LOW)),[r,d,e,g,k,q]);return v.createElement("div",{className:[p.base,e?p.focus:null].filter(Boolean).join(" "),ref:t,style:{textAlign:n?n:void 0}},w)}
|
|
@@ -45,13 +45,16 @@ function useCharacterLimit(editor, maxCharacters, optional = Object.freeze({}))
|
|
|
45
45
|
}) => {
|
|
46
46
|
const isComposing = editor.isComposing();
|
|
47
47
|
const hasDirtyLeaves = dirtyLeaves.size > 0;
|
|
48
|
+
|
|
48
49
|
if (isComposing || !hasDirtyLeaves) {
|
|
49
50
|
return;
|
|
50
51
|
}
|
|
52
|
+
|
|
51
53
|
const textLength = strlen(text$1);
|
|
52
54
|
const textLengthAboveThreshold = textLength > maxCharacters || lastComputedTextLength !== null && lastComputedTextLength > maxCharacters;
|
|
53
55
|
const diff = maxCharacters - textLength;
|
|
54
56
|
remainingCharacters(diff);
|
|
57
|
+
|
|
55
58
|
if (lastComputedTextLength === null || textLengthAboveThreshold) {
|
|
56
59
|
const offset = findOffset(text$1, maxCharacters, strlen);
|
|
57
60
|
editor.update(() => {
|
|
@@ -60,62 +63,75 @@ function useCharacterLimit(editor, maxCharacters, optional = Object.freeze({}))
|
|
|
60
63
|
tag: 'history-merge'
|
|
61
64
|
});
|
|
62
65
|
}
|
|
66
|
+
|
|
63
67
|
lastComputedTextLength = textLength;
|
|
64
68
|
}));
|
|
65
69
|
}, [editor, maxCharacters, remainingCharacters, strlen]);
|
|
66
70
|
}
|
|
71
|
+
|
|
67
72
|
function findOffset(text, maxCharacters, strlen) {
|
|
68
73
|
// @ts-ignore This is due to be added in a later version of TS
|
|
69
74
|
const Segmenter = Intl.Segmenter;
|
|
70
75
|
let offsetUtf16 = 0;
|
|
71
76
|
let offset = 0;
|
|
77
|
+
|
|
72
78
|
if (typeof Segmenter === 'function') {
|
|
73
79
|
const segmenter = new Segmenter();
|
|
74
80
|
const graphemes = segmenter.segment(text);
|
|
81
|
+
|
|
75
82
|
for (const {
|
|
76
83
|
segment: grapheme
|
|
77
84
|
} of graphemes) {
|
|
78
85
|
const nextOffset = offset + strlen(grapheme);
|
|
86
|
+
|
|
79
87
|
if (nextOffset > maxCharacters) {
|
|
80
88
|
break;
|
|
81
89
|
}
|
|
90
|
+
|
|
82
91
|
offset = nextOffset;
|
|
83
92
|
offsetUtf16 += grapheme.length;
|
|
84
93
|
}
|
|
85
94
|
} else {
|
|
86
95
|
const codepoints = Array.from(text);
|
|
87
96
|
const codepointsLength = codepoints.length;
|
|
97
|
+
|
|
88
98
|
for (let i = 0; i < codepointsLength; i++) {
|
|
89
99
|
const codepoint = codepoints[i];
|
|
90
100
|
const nextOffset = offset + strlen(codepoint);
|
|
101
|
+
|
|
91
102
|
if (nextOffset > maxCharacters) {
|
|
92
103
|
break;
|
|
93
104
|
}
|
|
105
|
+
|
|
94
106
|
offset = nextOffset;
|
|
95
107
|
offsetUtf16 += codepoint.length;
|
|
96
108
|
}
|
|
97
109
|
}
|
|
110
|
+
|
|
98
111
|
return offsetUtf16;
|
|
99
112
|
}
|
|
113
|
+
|
|
100
114
|
function $wrapOverflowedNodes(offset) {
|
|
101
115
|
const dfsNodes = utils.$dfs();
|
|
102
116
|
const dfsNodesLength = dfsNodes.length;
|
|
103
117
|
let accumulatedLength = 0;
|
|
118
|
+
|
|
104
119
|
for (let i = 0; i < dfsNodesLength; i += 1) {
|
|
105
120
|
const {
|
|
106
121
|
node
|
|
107
122
|
} = dfsNodes[i];
|
|
123
|
+
|
|
108
124
|
if (overflow.$isOverflowNode(node)) {
|
|
109
125
|
const previousLength = accumulatedLength;
|
|
110
126
|
const nextLength = accumulatedLength + node.getTextContentSize();
|
|
127
|
+
|
|
111
128
|
if (nextLength <= offset) {
|
|
112
129
|
const parent = node.getParent();
|
|
113
130
|
const previousSibling = node.getPreviousSibling();
|
|
114
131
|
const nextSibling = node.getNextSibling();
|
|
115
132
|
$unwrapNode(node);
|
|
116
|
-
const selection = lexical.$getSelection();
|
|
133
|
+
const selection = lexical.$getSelection(); // Restore selection when the overflow children are removed
|
|
117
134
|
|
|
118
|
-
// Restore selection when the overflow children are removed
|
|
119
135
|
if (lexical.$isRangeSelection(selection) && (!selection.anchor.getNode().isAttached() || !selection.focus.getNode().isAttached())) {
|
|
120
136
|
if (lexical.$isTextNode(previousSibling)) {
|
|
121
137
|
previousSibling.select();
|
|
@@ -128,11 +144,12 @@ function $wrapOverflowedNodes(offset) {
|
|
|
128
144
|
} else if (previousLength < offset) {
|
|
129
145
|
const descendant = node.getFirstDescendant();
|
|
130
146
|
const descendantLength = descendant !== null ? descendant.getTextContentSize() : 0;
|
|
131
|
-
const previousPlusDescendantLength = previousLength + descendantLength;
|
|
132
|
-
// For simple text we can redimension the overflow into a smaller and more accurate
|
|
147
|
+
const previousPlusDescendantLength = previousLength + descendantLength; // For simple text we can redimension the overflow into a smaller and more accurate
|
|
133
148
|
// container
|
|
149
|
+
|
|
134
150
|
const firstDescendantIsSimpleText = lexical.$isTextNode(descendant) && descendant.isSimpleText();
|
|
135
151
|
const firstDescendantDoesNotOverflow = previousPlusDescendantLength <= offset;
|
|
152
|
+
|
|
136
153
|
if (firstDescendantIsSimpleText || firstDescendantDoesNotOverflow) {
|
|
137
154
|
$unwrapNode(node);
|
|
138
155
|
}
|
|
@@ -140,49 +157,59 @@ function $wrapOverflowedNodes(offset) {
|
|
|
140
157
|
} else if (lexical.$isLeafNode(node)) {
|
|
141
158
|
const previousAccumulatedLength = accumulatedLength;
|
|
142
159
|
accumulatedLength += node.getTextContentSize();
|
|
160
|
+
|
|
143
161
|
if (accumulatedLength > offset && !overflow.$isOverflowNode(node.getParent())) {
|
|
144
162
|
const previousSelection = lexical.$getSelection();
|
|
145
|
-
let overflowNode;
|
|
146
|
-
|
|
147
|
-
// For simple text we can improve the limit accuracy by splitting the TextNode
|
|
163
|
+
let overflowNode; // For simple text we can improve the limit accuracy by splitting the TextNode
|
|
148
164
|
// on the split point
|
|
165
|
+
|
|
149
166
|
if (previousAccumulatedLength < offset && lexical.$isTextNode(node) && node.isSimpleText()) {
|
|
150
167
|
const [, overflowedText] = node.splitText(offset - previousAccumulatedLength);
|
|
151
168
|
overflowNode = $wrapNode(overflowedText);
|
|
152
169
|
} else {
|
|
153
170
|
overflowNode = $wrapNode(node);
|
|
154
171
|
}
|
|
172
|
+
|
|
155
173
|
if (previousSelection !== null) {
|
|
156
174
|
lexical.$setSelection(previousSelection);
|
|
157
175
|
}
|
|
176
|
+
|
|
158
177
|
mergePrevious(overflowNode);
|
|
159
178
|
}
|
|
160
179
|
}
|
|
161
180
|
}
|
|
162
181
|
}
|
|
182
|
+
|
|
163
183
|
function $wrapNode(node) {
|
|
164
184
|
const overflowNode = overflow.$createOverflowNode();
|
|
165
185
|
node.insertBefore(overflowNode);
|
|
166
186
|
overflowNode.append(node);
|
|
167
187
|
return overflowNode;
|
|
168
188
|
}
|
|
189
|
+
|
|
169
190
|
function $unwrapNode(node) {
|
|
170
191
|
const children = node.getChildren();
|
|
171
192
|
const childrenLength = children.length;
|
|
193
|
+
|
|
172
194
|
for (let i = 0; i < childrenLength; i++) {
|
|
173
195
|
node.insertBefore(children[i]);
|
|
174
196
|
}
|
|
197
|
+
|
|
175
198
|
node.remove();
|
|
176
199
|
return childrenLength > 0 ? children[childrenLength - 1] : null;
|
|
177
200
|
}
|
|
201
|
+
|
|
178
202
|
function mergePrevious(overflowNode) {
|
|
179
203
|
const previousNode = overflowNode.getPreviousSibling();
|
|
204
|
+
|
|
180
205
|
if (!overflow.$isOverflowNode(previousNode)) {
|
|
181
206
|
return;
|
|
182
207
|
}
|
|
208
|
+
|
|
183
209
|
const firstChild = overflowNode.getFirstChild();
|
|
184
210
|
const previousNodeChildren = previousNode.getChildren();
|
|
185
211
|
const previousNodeChildrenLength = previousNodeChildren.length;
|
|
212
|
+
|
|
186
213
|
if (firstChild === null) {
|
|
187
214
|
overflowNode.append(...previousNodeChildren);
|
|
188
215
|
} else {
|
|
@@ -190,23 +217,28 @@ function mergePrevious(overflowNode) {
|
|
|
190
217
|
firstChild.insertBefore(previousNodeChildren[i]);
|
|
191
218
|
}
|
|
192
219
|
}
|
|
220
|
+
|
|
193
221
|
const selection = lexical.$getSelection();
|
|
222
|
+
|
|
194
223
|
if (lexical.$isRangeSelection(selection)) {
|
|
195
224
|
const anchor = selection.anchor;
|
|
196
225
|
const anchorNode = anchor.getNode();
|
|
197
226
|
const focus = selection.focus;
|
|
198
227
|
const focusNode = anchor.getNode();
|
|
228
|
+
|
|
199
229
|
if (anchorNode.is(previousNode)) {
|
|
200
230
|
anchor.set(overflowNode.getKey(), anchor.offset, 'element');
|
|
201
231
|
} else if (anchorNode.is(overflowNode)) {
|
|
202
232
|
anchor.set(overflowNode.getKey(), previousNodeChildrenLength + anchor.offset, 'element');
|
|
203
233
|
}
|
|
234
|
+
|
|
204
235
|
if (focusNode.is(previousNode)) {
|
|
205
236
|
focus.set(overflowNode.getKey(), focus.offset, 'element');
|
|
206
237
|
} else if (focusNode.is(overflowNode)) {
|
|
207
238
|
focus.set(overflowNode.getKey(), previousNodeChildrenLength + focus.offset, 'element');
|
|
208
239
|
}
|
|
209
240
|
}
|
|
241
|
+
|
|
210
242
|
previousNode.remove();
|
|
211
243
|
}
|
|
212
244
|
|
|
@@ -219,24 +251,31 @@ function mergePrevious(overflowNode) {
|
|
|
219
251
|
*/
|
|
220
252
|
const CHARACTER_LIMIT = 5;
|
|
221
253
|
let textEncoderInstance = null;
|
|
254
|
+
|
|
222
255
|
function textEncoder() {
|
|
223
256
|
if (window.TextEncoder === undefined) {
|
|
224
257
|
return null;
|
|
225
258
|
}
|
|
259
|
+
|
|
226
260
|
if (textEncoderInstance === null) {
|
|
227
261
|
textEncoderInstance = new window.TextEncoder();
|
|
228
262
|
}
|
|
263
|
+
|
|
229
264
|
return textEncoderInstance;
|
|
230
265
|
}
|
|
266
|
+
|
|
231
267
|
function utf8Length(text) {
|
|
232
268
|
const currentTextEncoder = textEncoder();
|
|
269
|
+
|
|
233
270
|
if (currentTextEncoder === null) {
|
|
234
271
|
// http://stackoverflow.com/a/5515960/210370
|
|
235
272
|
const m = encodeURIComponent(text).match(/%[89ABab]/g);
|
|
236
273
|
return text.length + (m ? m.length : 0);
|
|
237
274
|
}
|
|
275
|
+
|
|
238
276
|
return currentTextEncoder.encode(text).length;
|
|
239
277
|
}
|
|
278
|
+
|
|
240
279
|
function CharacterLimitPlugin({
|
|
241
280
|
charset = 'UTF-16',
|
|
242
281
|
maxLength = CHARACTER_LIMIT
|