@lexical/react 0.7.7 → 0.7.9
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/DEPRECATED_useLexical.dev.js +3 -4
- package/DEPRECATED_useLexicalCanShowPlaceholder.dev.js +1 -3
- package/DEPRECATED_useLexicalCharacterLimit.dev.js +7 -39
- package/DEPRECATED_useLexicalEditor.dev.js +1 -3
- package/DEPRECATED_useLexicalPlainText.dev.js +4 -1
- package/DEPRECATED_useLexicalRichText.dev.js +4 -1
- package/LexicalAutoEmbedPlugin.dev.js +0 -11
- package/LexicalAutoFocusPlugin.dev.js +0 -1
- package/LexicalAutoLinkPlugin.dev.js +7 -50
- package/LexicalBlockWithAlignableContents.dev.js +0 -11
- package/LexicalCharacterLimitPlugin.dev.js +7 -46
- package/LexicalCheckListPlugin.dev.js +10 -48
- package/LexicalClearEditorPlugin.dev.js +1 -1
- package/LexicalCollaborationContext.dev.js +0 -3
- package/LexicalCollaborationPlugin.dev.js +6 -34
- package/LexicalComposer.dev.js +6 -10
- package/LexicalComposerContext.dev.js +0 -6
- package/LexicalContentEditable.dev.js +3 -1
- package/LexicalDecoratorBlockNode.dev.js +0 -5
- package/LexicalHashtagPlugin.dev.js +73 -43
- package/LexicalHorizontalRuleNode.dev.js +0 -22
- package/LexicalHorizontalRulePlugin.dev.js +0 -4
- package/LexicalLinkPlugin.dev.js +4 -10
- package/LexicalListPlugin.dev.js +0 -2
- package/LexicalMarkdownShortcutPlugin.dev.js +2 -2
- package/LexicalNestedComposer.dev.js +6 -11
- package/LexicalNodeEventPlugin.dev.js +5 -3
- package/LexicalOnChangePlugin.dev.js +1 -1
- package/LexicalPlainTextPlugin.dev.js +8 -12
- package/LexicalRichTextPlugin.dev.js +8 -12
- package/LexicalTabIndentationPlugin.dev.js +1 -3
- package/LexicalTableOfContents__EXPERIMENTAL.dev.js +5 -33
- package/LexicalTablePlugin.dev.js +5 -19
- package/LexicalTreeView.dev.js +12 -61
- package/LexicalTypeaheadMenuPlugin.dev.js +23 -108
- package/LexicalTypeaheadMenuPlugin.prod.js +18 -18
- package/package.json +19 -19
- package/useLexicalEditable.dev.js +1 -5
- package/useLexicalIsTextContentEmpty.dev.js +1 -0
- package/useLexicalNodeSelection.dev.js +0 -7
- package/useLexicalSubscription.dev.js +1 -3
|
@@ -18,6 +18,7 @@ var utils = require('@lexical/utils');
|
|
|
18
18
|
* LICENSE file in the root directory of this source tree.
|
|
19
19
|
*
|
|
20
20
|
*/
|
|
21
|
+
|
|
21
22
|
const CAN_USE_DOM = typeof window !== 'undefined' && typeof window.document !== 'undefined' && typeof window.document.createElement !== 'undefined';
|
|
22
23
|
|
|
23
24
|
/**
|
|
@@ -37,12 +38,10 @@ var useLayoutEffect = useLayoutEffectImpl;
|
|
|
37
38
|
* LICENSE file in the root directory of this source tree.
|
|
38
39
|
*
|
|
39
40
|
*/
|
|
40
|
-
|
|
41
41
|
function canShowPlaceholderFromCurrentEditorState(editor) {
|
|
42
42
|
const currentCanShowPlaceholder = editor.getEditorState().read(text.$canShowPlaceholderCurry(editor.isComposing()));
|
|
43
43
|
return currentCanShowPlaceholder;
|
|
44
44
|
}
|
|
45
|
-
|
|
46
45
|
function useCanShowPlaceholder(editor) {
|
|
47
46
|
const [canShowPlaceholder, setCanShowPlaceholder] = react.useState(() => canShowPlaceholderFromCurrentEditorState(editor));
|
|
48
47
|
useLayoutEffect(() => {
|
|
@@ -50,7 +49,6 @@ function useCanShowPlaceholder(editor) {
|
|
|
50
49
|
const currentCanShowPlaceholder = canShowPlaceholderFromCurrentEditorState(editor);
|
|
51
50
|
setCanShowPlaceholder(currentCanShowPlaceholder);
|
|
52
51
|
}
|
|
53
|
-
|
|
54
52
|
resetCanShowPlaceholder();
|
|
55
53
|
return utils.mergeRegister(editor.registerUpdateListener(() => {
|
|
56
54
|
resetCanShowPlaceholder();
|
|
@@ -95,7 +93,8 @@ function useLexicalEditor(editor) {
|
|
|
95
93
|
*
|
|
96
94
|
*/
|
|
97
95
|
function useLexical(editorConfig) {
|
|
98
|
-
const editor = react.useMemo(() => lexical.createEditor(editorConfig),
|
|
96
|
+
const editor = react.useMemo(() => lexical.createEditor(editorConfig),
|
|
97
|
+
// Init
|
|
99
98
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
100
99
|
[]);
|
|
101
100
|
const [rootElementRef, showPlaceholder] = useLexicalEditor(editor);
|
|
@@ -17,6 +17,7 @@ var react = require('react');
|
|
|
17
17
|
* LICENSE file in the root directory of this source tree.
|
|
18
18
|
*
|
|
19
19
|
*/
|
|
20
|
+
|
|
20
21
|
const CAN_USE_DOM = typeof window !== 'undefined' && typeof window.document !== 'undefined' && typeof window.document.createElement !== 'undefined';
|
|
21
22
|
|
|
22
23
|
/**
|
|
@@ -36,12 +37,10 @@ var useLayoutEffect = useLayoutEffectImpl;
|
|
|
36
37
|
* LICENSE file in the root directory of this source tree.
|
|
37
38
|
*
|
|
38
39
|
*/
|
|
39
|
-
|
|
40
40
|
function canShowPlaceholderFromCurrentEditorState(editor) {
|
|
41
41
|
const currentCanShowPlaceholder = editor.getEditorState().read(text.$canShowPlaceholderCurry(editor.isComposing()));
|
|
42
42
|
return currentCanShowPlaceholder;
|
|
43
43
|
}
|
|
44
|
-
|
|
45
44
|
function useCanShowPlaceholder(editor) {
|
|
46
45
|
const [canShowPlaceholder, setCanShowPlaceholder] = react.useState(() => canShowPlaceholderFromCurrentEditorState(editor));
|
|
47
46
|
useLayoutEffect(() => {
|
|
@@ -49,7 +48,6 @@ function useCanShowPlaceholder(editor) {
|
|
|
49
48
|
const currentCanShowPlaceholder = canShowPlaceholderFromCurrentEditorState(editor);
|
|
50
49
|
setCanShowPlaceholder(currentCanShowPlaceholder);
|
|
51
50
|
}
|
|
52
|
-
|
|
53
51
|
resetCanShowPlaceholder();
|
|
54
52
|
return utils.mergeRegister(editor.registerUpdateListener(() => {
|
|
55
53
|
resetCanShowPlaceholder();
|
|
@@ -44,16 +44,13 @@ function useCharacterLimit(editor, maxCharacters, optional = Object.freeze({}))
|
|
|
44
44
|
}) => {
|
|
45
45
|
const isComposing = editor.isComposing();
|
|
46
46
|
const hasDirtyLeaves = dirtyLeaves.size > 0;
|
|
47
|
-
|
|
48
47
|
if (isComposing || !hasDirtyLeaves) {
|
|
49
48
|
return;
|
|
50
49
|
}
|
|
51
|
-
|
|
52
50
|
const textLength = strlen(text$1);
|
|
53
51
|
const textLengthAboveThreshold = textLength > maxCharacters || lastComputedTextLength !== null && lastComputedTextLength > maxCharacters;
|
|
54
52
|
const diff = maxCharacters - textLength;
|
|
55
53
|
remainingCharacters(diff);
|
|
56
|
-
|
|
57
54
|
if (lastComputedTextLength === null || textLengthAboveThreshold) {
|
|
58
55
|
const offset = findOffset(text$1, maxCharacters, strlen);
|
|
59
56
|
editor.update(() => {
|
|
@@ -62,75 +59,62 @@ function useCharacterLimit(editor, maxCharacters, optional = Object.freeze({}))
|
|
|
62
59
|
tag: 'history-merge'
|
|
63
60
|
});
|
|
64
61
|
}
|
|
65
|
-
|
|
66
62
|
lastComputedTextLength = textLength;
|
|
67
63
|
}));
|
|
68
64
|
}, [editor, maxCharacters, remainingCharacters, strlen]);
|
|
69
65
|
}
|
|
70
|
-
|
|
71
66
|
function findOffset(text, maxCharacters, strlen) {
|
|
72
67
|
// @ts-ignore This is due to be added in a later version of TS
|
|
73
68
|
const Segmenter = Intl.Segmenter;
|
|
74
69
|
let offsetUtf16 = 0;
|
|
75
70
|
let offset = 0;
|
|
76
|
-
|
|
77
71
|
if (typeof Segmenter === 'function') {
|
|
78
72
|
const segmenter = new Segmenter();
|
|
79
73
|
const graphemes = segmenter.segment(text);
|
|
80
|
-
|
|
81
74
|
for (const {
|
|
82
75
|
segment: grapheme
|
|
83
76
|
} of graphemes) {
|
|
84
77
|
const nextOffset = offset + strlen(grapheme);
|
|
85
|
-
|
|
86
78
|
if (nextOffset > maxCharacters) {
|
|
87
79
|
break;
|
|
88
80
|
}
|
|
89
|
-
|
|
90
81
|
offset = nextOffset;
|
|
91
82
|
offsetUtf16 += grapheme.length;
|
|
92
83
|
}
|
|
93
84
|
} else {
|
|
94
85
|
const codepoints = Array.from(text);
|
|
95
86
|
const codepointsLength = codepoints.length;
|
|
96
|
-
|
|
97
87
|
for (let i = 0; i < codepointsLength; i++) {
|
|
98
88
|
const codepoint = codepoints[i];
|
|
99
89
|
const nextOffset = offset + strlen(codepoint);
|
|
100
|
-
|
|
101
90
|
if (nextOffset > maxCharacters) {
|
|
102
91
|
break;
|
|
103
92
|
}
|
|
104
|
-
|
|
105
93
|
offset = nextOffset;
|
|
106
94
|
offsetUtf16 += codepoint.length;
|
|
107
95
|
}
|
|
108
96
|
}
|
|
109
|
-
|
|
110
97
|
return offsetUtf16;
|
|
111
98
|
}
|
|
112
|
-
|
|
113
99
|
function $wrapOverflowedNodes(offset) {
|
|
114
100
|
const dfsNodes = utils.$dfs();
|
|
115
101
|
const dfsNodesLength = dfsNodes.length;
|
|
116
102
|
let accumulatedLength = 0;
|
|
117
|
-
|
|
118
103
|
for (let i = 0; i < dfsNodesLength; i += 1) {
|
|
119
104
|
const {
|
|
120
105
|
node
|
|
121
106
|
} = dfsNodes[i];
|
|
122
|
-
|
|
123
107
|
if (overflow.$isOverflowNode(node)) {
|
|
124
108
|
const previousLength = accumulatedLength;
|
|
125
109
|
const nextLength = accumulatedLength + node.getTextContentSize();
|
|
126
|
-
|
|
127
110
|
if (nextLength <= offset) {
|
|
128
111
|
const parent = node.getParent();
|
|
129
112
|
const previousSibling = node.getPreviousSibling();
|
|
130
113
|
const nextSibling = node.getNextSibling();
|
|
131
114
|
$unwrapNode(node);
|
|
132
|
-
const selection = lexical.$getSelection();
|
|
115
|
+
const selection = lexical.$getSelection();
|
|
133
116
|
|
|
117
|
+
// Restore selection when the overflow children are removed
|
|
134
118
|
if (lexical.$isRangeSelection(selection) && (!selection.anchor.getNode().isAttached() || !selection.focus.getNode().isAttached())) {
|
|
135
119
|
if (lexical.$isTextNode(previousSibling)) {
|
|
136
120
|
previousSibling.select();
|
|
@@ -143,12 +127,11 @@ function $wrapOverflowedNodes(offset) {
|
|
|
143
127
|
} else if (previousLength < offset) {
|
|
144
128
|
const descendant = node.getFirstDescendant();
|
|
145
129
|
const descendantLength = descendant !== null ? descendant.getTextContentSize() : 0;
|
|
146
|
-
const previousPlusDescendantLength = previousLength + descendantLength;
|
|
130
|
+
const previousPlusDescendantLength = previousLength + descendantLength;
|
|
131
|
+
// For simple text we can redimension the overflow into a smaller and more accurate
|
|
147
132
|
// container
|
|
148
|
-
|
|
149
133
|
const firstDescendantIsSimpleText = lexical.$isTextNode(descendant) && descendant.isSimpleText();
|
|
150
134
|
const firstDescendantDoesNotOverflow = previousPlusDescendantLength <= offset;
|
|
151
|
-
|
|
152
135
|
if (firstDescendantIsSimpleText || firstDescendantDoesNotOverflow) {
|
|
153
136
|
$unwrapNode(node);
|
|
154
137
|
}
|
|
@@ -156,59 +139,49 @@ function $wrapOverflowedNodes(offset) {
|
|
|
156
139
|
} else if (lexical.$isLeafNode(node)) {
|
|
157
140
|
const previousAccumulatedLength = accumulatedLength;
|
|
158
141
|
accumulatedLength += node.getTextContentSize();
|
|
159
|
-
|
|
160
142
|
if (accumulatedLength > offset && !overflow.$isOverflowNode(node.getParent())) {
|
|
161
143
|
const previousSelection = lexical.$getSelection();
|
|
162
|
-
let overflowNode;
|
|
163
|
-
// on the split point
|
|
144
|
+
let overflowNode;
|
|
164
145
|
|
|
146
|
+
// For simple text we can improve the limit accuracy by splitting the TextNode
|
|
147
|
+
// on the split point
|
|
165
148
|
if (previousAccumulatedLength < offset && lexical.$isTextNode(node) && node.isSimpleText()) {
|
|
166
149
|
const [, overflowedText] = node.splitText(offset - previousAccumulatedLength);
|
|
167
150
|
overflowNode = $wrapNode(overflowedText);
|
|
168
151
|
} else {
|
|
169
152
|
overflowNode = $wrapNode(node);
|
|
170
153
|
}
|
|
171
|
-
|
|
172
154
|
if (previousSelection !== null) {
|
|
173
155
|
lexical.$setSelection(previousSelection);
|
|
174
156
|
}
|
|
175
|
-
|
|
176
157
|
mergePrevious(overflowNode);
|
|
177
158
|
}
|
|
178
159
|
}
|
|
179
160
|
}
|
|
180
161
|
}
|
|
181
|
-
|
|
182
162
|
function $wrapNode(node) {
|
|
183
163
|
const overflowNode = overflow.$createOverflowNode();
|
|
184
164
|
node.insertBefore(overflowNode);
|
|
185
165
|
overflowNode.append(node);
|
|
186
166
|
return overflowNode;
|
|
187
167
|
}
|
|
188
|
-
|
|
189
168
|
function $unwrapNode(node) {
|
|
190
169
|
const children = node.getChildren();
|
|
191
170
|
const childrenLength = children.length;
|
|
192
|
-
|
|
193
171
|
for (let i = 0; i < childrenLength; i++) {
|
|
194
172
|
node.insertBefore(children[i]);
|
|
195
173
|
}
|
|
196
|
-
|
|
197
174
|
node.remove();
|
|
198
175
|
return childrenLength > 0 ? children[childrenLength - 1] : null;
|
|
199
176
|
}
|
|
200
|
-
|
|
201
177
|
function mergePrevious(overflowNode) {
|
|
202
178
|
const previousNode = overflowNode.getPreviousSibling();
|
|
203
|
-
|
|
204
179
|
if (!overflow.$isOverflowNode(previousNode)) {
|
|
205
180
|
return;
|
|
206
181
|
}
|
|
207
|
-
|
|
208
182
|
const firstChild = overflowNode.getFirstChild();
|
|
209
183
|
const previousNodeChildren = previousNode.getChildren();
|
|
210
184
|
const previousNodeChildrenLength = previousNodeChildren.length;
|
|
211
|
-
|
|
212
185
|
if (firstChild === null) {
|
|
213
186
|
overflowNode.append(...previousNodeChildren);
|
|
214
187
|
} else {
|
|
@@ -216,28 +189,23 @@ function mergePrevious(overflowNode) {
|
|
|
216
189
|
firstChild.insertBefore(previousNodeChildren[i]);
|
|
217
190
|
}
|
|
218
191
|
}
|
|
219
|
-
|
|
220
192
|
const selection = lexical.$getSelection();
|
|
221
|
-
|
|
222
193
|
if (lexical.$isRangeSelection(selection)) {
|
|
223
194
|
const anchor = selection.anchor;
|
|
224
195
|
const anchorNode = anchor.getNode();
|
|
225
196
|
const focus = selection.focus;
|
|
226
197
|
const focusNode = anchor.getNode();
|
|
227
|
-
|
|
228
198
|
if (anchorNode.is(previousNode)) {
|
|
229
199
|
anchor.set(overflowNode.getKey(), anchor.offset, 'element');
|
|
230
200
|
} else if (anchorNode.is(overflowNode)) {
|
|
231
201
|
anchor.set(overflowNode.getKey(), previousNodeChildrenLength + anchor.offset, 'element');
|
|
232
202
|
}
|
|
233
|
-
|
|
234
203
|
if (focusNode.is(previousNode)) {
|
|
235
204
|
focus.set(overflowNode.getKey(), focus.offset, 'element');
|
|
236
205
|
} else if (focusNode.is(overflowNode)) {
|
|
237
206
|
focus.set(overflowNode.getKey(), previousNodeChildrenLength + focus.offset, 'element');
|
|
238
207
|
}
|
|
239
208
|
}
|
|
240
|
-
|
|
241
209
|
previousNode.remove();
|
|
242
210
|
}
|
|
243
211
|
|
|
@@ -17,6 +17,7 @@ var utils = require('@lexical/utils');
|
|
|
17
17
|
* LICENSE file in the root directory of this source tree.
|
|
18
18
|
*
|
|
19
19
|
*/
|
|
20
|
+
|
|
20
21
|
const CAN_USE_DOM = typeof window !== 'undefined' && typeof window.document !== 'undefined' && typeof window.document.createElement !== 'undefined';
|
|
21
22
|
|
|
22
23
|
/**
|
|
@@ -36,12 +37,10 @@ var useLayoutEffect = useLayoutEffectImpl;
|
|
|
36
37
|
* LICENSE file in the root directory of this source tree.
|
|
37
38
|
*
|
|
38
39
|
*/
|
|
39
|
-
|
|
40
40
|
function canShowPlaceholderFromCurrentEditorState(editor) {
|
|
41
41
|
const currentCanShowPlaceholder = editor.getEditorState().read(text.$canShowPlaceholderCurry(editor.isComposing()));
|
|
42
42
|
return currentCanShowPlaceholder;
|
|
43
43
|
}
|
|
44
|
-
|
|
45
44
|
function useCanShowPlaceholder(editor) {
|
|
46
45
|
const [canShowPlaceholder, setCanShowPlaceholder] = react.useState(() => canShowPlaceholderFromCurrentEditorState(editor));
|
|
47
46
|
useLayoutEffect(() => {
|
|
@@ -49,7 +48,6 @@ function useCanShowPlaceholder(editor) {
|
|
|
49
48
|
const currentCanShowPlaceholder = canShowPlaceholderFromCurrentEditorState(editor);
|
|
50
49
|
setCanShowPlaceholder(currentCanShowPlaceholder);
|
|
51
50
|
}
|
|
52
|
-
|
|
53
51
|
resetCanShowPlaceholder();
|
|
54
52
|
return utils.mergeRegister(editor.registerUpdateListener(() => {
|
|
55
53
|
resetCanShowPlaceholder();
|
|
@@ -44,6 +44,7 @@ function useLexicalHistory(editor, externalHistoryState, delay = 1000) {
|
|
|
44
44
|
* LICENSE file in the root directory of this source tree.
|
|
45
45
|
*
|
|
46
46
|
*/
|
|
47
|
+
|
|
47
48
|
const CAN_USE_DOM = typeof window !== 'undefined' && typeof window.document !== 'undefined' && typeof window.document.createElement !== 'undefined';
|
|
48
49
|
|
|
49
50
|
/**
|
|
@@ -65,7 +66,9 @@ var useLayoutEffect = useLayoutEffectImpl;
|
|
|
65
66
|
*/
|
|
66
67
|
function usePlainTextSetup(editor) {
|
|
67
68
|
useLayoutEffect(() => {
|
|
68
|
-
return utils.mergeRegister(plainText.registerPlainText(editor), dragon.registerDragonSupport(editor));
|
|
69
|
+
return utils.mergeRegister(plainText.registerPlainText(editor), dragon.registerDragonSupport(editor));
|
|
70
|
+
|
|
71
|
+
// We only do this for init
|
|
69
72
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
70
73
|
}, [editor]);
|
|
71
74
|
}
|
|
@@ -44,6 +44,7 @@ function useLexicalHistory(editor, externalHistoryState, delay = 1000) {
|
|
|
44
44
|
* LICENSE file in the root directory of this source tree.
|
|
45
45
|
*
|
|
46
46
|
*/
|
|
47
|
+
|
|
47
48
|
const CAN_USE_DOM = typeof window !== 'undefined' && typeof window.document !== 'undefined' && typeof window.document.createElement !== 'undefined';
|
|
48
49
|
|
|
49
50
|
/**
|
|
@@ -65,7 +66,9 @@ var useLayoutEffect = useLayoutEffectImpl;
|
|
|
65
66
|
*/
|
|
66
67
|
function useRichTextSetup(editor) {
|
|
67
68
|
useLayoutEffect(() => {
|
|
68
|
-
return utils.mergeRegister(richText.registerRichText(editor), dragon.registerDragonSupport(editor));
|
|
69
|
+
return utils.mergeRegister(richText.registerRichText(editor), dragon.registerDragonSupport(editor));
|
|
70
|
+
|
|
71
|
+
// We only do this for init
|
|
69
72
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
70
73
|
}, [editor]);
|
|
71
74
|
}
|
|
@@ -28,7 +28,6 @@ class AutoEmbedOption extends LexicalTypeaheadMenuPlugin.TypeaheadOption {
|
|
|
28
28
|
this.title = title;
|
|
29
29
|
this.onSelect = options.onSelect.bind(this);
|
|
30
30
|
}
|
|
31
|
-
|
|
32
31
|
}
|
|
33
32
|
function LexicalAutoEmbedPlugin({
|
|
34
33
|
embedConfigs,
|
|
@@ -46,12 +45,10 @@ function LexicalAutoEmbedPlugin({
|
|
|
46
45
|
const checkIfLinkNodeIsEmbeddable = React.useCallback(key => {
|
|
47
46
|
editor.getEditorState().read(async () => {
|
|
48
47
|
const linkNode = lexical.$getNodeByKey(key);
|
|
49
|
-
|
|
50
48
|
if (link.$isLinkNode(linkNode)) {
|
|
51
49
|
for (let i = 0; i < embedConfigs.length; i++) {
|
|
52
50
|
const embedConfig = embedConfigs[i];
|
|
53
51
|
const urlMatch = await Promise.resolve(embedConfig.parseUrl(linkNode.__url));
|
|
54
|
-
|
|
55
52
|
if (urlMatch != null) {
|
|
56
53
|
setActiveEmbedConfig(embedConfig);
|
|
57
54
|
setNodeKey(linkNode.getKey());
|
|
@@ -73,7 +70,6 @@ function LexicalAutoEmbedPlugin({
|
|
|
73
70
|
}
|
|
74
71
|
}
|
|
75
72
|
};
|
|
76
|
-
|
|
77
73
|
return utils.mergeRegister(...[link.LinkNode, link.AutoLinkNode].map(Klass => editor.registerMutationListener(Klass, (...args) => listener(...args))));
|
|
78
74
|
}, [checkIfLinkNodeIsEmbeddable, editor, embedConfigs, nodeKey, reset]);
|
|
79
75
|
React.useEffect(() => {
|
|
@@ -81,12 +77,10 @@ function LexicalAutoEmbedPlugin({
|
|
|
81
77
|
const embedConfig = embedConfigs.find(({
|
|
82
78
|
type
|
|
83
79
|
}) => type === embedConfigType);
|
|
84
|
-
|
|
85
80
|
if (embedConfig) {
|
|
86
81
|
onOpenEmbedModalForConfig(embedConfig);
|
|
87
82
|
return true;
|
|
88
83
|
}
|
|
89
|
-
|
|
90
84
|
return false;
|
|
91
85
|
}, lexical.COMMAND_PRIORITY_EDITOR);
|
|
92
86
|
}, [editor, embedConfigs, onOpenEmbedModalForConfig]);
|
|
@@ -94,21 +88,16 @@ function LexicalAutoEmbedPlugin({
|
|
|
94
88
|
if (activeEmbedConfig != null && nodeKey != null) {
|
|
95
89
|
const linkNode = editor.getEditorState().read(() => {
|
|
96
90
|
const node = lexical.$getNodeByKey(nodeKey);
|
|
97
|
-
|
|
98
91
|
if (link.$isLinkNode(node)) {
|
|
99
92
|
return node;
|
|
100
93
|
}
|
|
101
|
-
|
|
102
94
|
return null;
|
|
103
95
|
});
|
|
104
|
-
|
|
105
96
|
if (link.$isLinkNode(linkNode)) {
|
|
106
97
|
const result = await Promise.resolve(activeEmbedConfig.parseUrl(linkNode.__url));
|
|
107
|
-
|
|
108
98
|
if (result != null) {
|
|
109
99
|
editor.update(() => {
|
|
110
100
|
activeEmbedConfig.insertNode(editor, result);
|
|
111
|
-
|
|
112
101
|
if (linkNode.isAttached()) {
|
|
113
102
|
linkNode.remove();
|
|
114
103
|
}
|
|
@@ -28,7 +28,6 @@ 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
|
-
|
|
32
31
|
if (rootElement !== null && (activeElement === null || !rootElement.contains(activeElement))) {
|
|
33
32
|
// Note: preventScroll won't work in Webkit.
|
|
34
33
|
rootElement.focus({
|
|
@@ -19,86 +19,65 @@ var react = require('react');
|
|
|
19
19
|
* LICENSE file in the root directory of this source tree.
|
|
20
20
|
*
|
|
21
21
|
*/
|
|
22
|
-
|
|
23
22
|
function findFirstMatch(text, matchers) {
|
|
24
23
|
for (let i = 0; i < matchers.length; i++) {
|
|
25
24
|
const match = matchers[i](text);
|
|
26
|
-
|
|
27
25
|
if (match) {
|
|
28
26
|
return match;
|
|
29
27
|
}
|
|
30
28
|
}
|
|
31
|
-
|
|
32
29
|
return null;
|
|
33
30
|
}
|
|
34
|
-
|
|
35
31
|
const PUNCTUATION_OR_SPACE = /[.,;\s]/;
|
|
36
|
-
|
|
37
32
|
function isSeparator(char) {
|
|
38
33
|
return PUNCTUATION_OR_SPACE.test(char);
|
|
39
34
|
}
|
|
40
|
-
|
|
41
35
|
function endsWithSeparator(textContent) {
|
|
42
36
|
return isSeparator(textContent[textContent.length - 1]);
|
|
43
37
|
}
|
|
44
|
-
|
|
45
38
|
function startsWithSeparator(textContent) {
|
|
46
39
|
return isSeparator(textContent[0]);
|
|
47
40
|
}
|
|
48
|
-
|
|
49
41
|
function isPreviousNodeValid(node) {
|
|
50
42
|
let previousNode = node.getPreviousSibling();
|
|
51
|
-
|
|
52
43
|
if (lexical.$isElementNode(previousNode)) {
|
|
53
44
|
previousNode = previousNode.getLastDescendant();
|
|
54
45
|
}
|
|
55
|
-
|
|
56
46
|
return previousNode === null || lexical.$isLineBreakNode(previousNode) || lexical.$isTextNode(previousNode) && endsWithSeparator(previousNode.getTextContent());
|
|
57
47
|
}
|
|
58
|
-
|
|
59
48
|
function isNextNodeValid(node) {
|
|
60
49
|
let nextNode = node.getNextSibling();
|
|
61
|
-
|
|
62
50
|
if (lexical.$isElementNode(nextNode)) {
|
|
63
51
|
nextNode = nextNode.getFirstDescendant();
|
|
64
52
|
}
|
|
65
|
-
|
|
66
53
|
return nextNode === null || lexical.$isLineBreakNode(nextNode) || lexical.$isTextNode(nextNode) && startsWithSeparator(nextNode.getTextContent());
|
|
67
54
|
}
|
|
68
|
-
|
|
69
55
|
function isContentAroundIsValid(matchStart, matchEnd, text, node) {
|
|
70
56
|
const contentBeforeIsValid = matchStart > 0 ? isSeparator(text[matchStart - 1]) : isPreviousNodeValid(node);
|
|
71
|
-
|
|
72
57
|
if (!contentBeforeIsValid) {
|
|
73
58
|
return false;
|
|
74
59
|
}
|
|
75
|
-
|
|
76
60
|
const contentAfterIsValid = matchEnd < text.length ? isSeparator(text[matchEnd]) : isNextNodeValid(node);
|
|
77
61
|
return contentAfterIsValid;
|
|
78
62
|
}
|
|
79
|
-
|
|
80
63
|
function handleLinkCreation(node, matchers, onChange) {
|
|
81
64
|
const nodeText = node.getTextContent();
|
|
82
65
|
let text = nodeText;
|
|
83
66
|
let invalidMatchEnd = 0;
|
|
84
67
|
let remainingTextNode = node;
|
|
85
68
|
let match;
|
|
86
|
-
|
|
87
69
|
while ((match = findFirstMatch(text, matchers)) && match !== null) {
|
|
88
70
|
const matchStart = match.index;
|
|
89
71
|
const matchLength = match.length;
|
|
90
72
|
const matchEnd = matchStart + matchLength;
|
|
91
73
|
const isValid = isContentAroundIsValid(invalidMatchEnd + matchStart, invalidMatchEnd + matchEnd, nodeText, node);
|
|
92
|
-
|
|
93
74
|
if (isValid) {
|
|
94
75
|
let linkTextNode;
|
|
95
|
-
|
|
96
76
|
if (invalidMatchEnd + matchStart === 0) {
|
|
97
77
|
[linkTextNode, remainingTextNode] = remainingTextNode.splitText(invalidMatchEnd + matchLength);
|
|
98
78
|
} else {
|
|
99
79
|
[, linkTextNode, remainingTextNode] = remainingTextNode.splitText(invalidMatchEnd + matchStart, invalidMatchEnd + matchStart + matchLength);
|
|
100
80
|
}
|
|
101
|
-
|
|
102
81
|
const linkNode = link.$createAutoLinkNode(match.url, match.attributes);
|
|
103
82
|
const textNode = lexical.$createTextNode(match.text);
|
|
104
83
|
textNode.setFormat(linkTextNode.getFormat());
|
|
@@ -110,97 +89,80 @@ function handleLinkCreation(node, matchers, onChange) {
|
|
|
110
89
|
} else {
|
|
111
90
|
invalidMatchEnd += matchEnd;
|
|
112
91
|
}
|
|
113
|
-
|
|
114
92
|
text = text.substring(matchEnd);
|
|
115
93
|
}
|
|
116
94
|
}
|
|
117
|
-
|
|
118
95
|
function handleLinkEdit(linkNode, matchers, onChange) {
|
|
119
96
|
// Check children are simple text
|
|
120
97
|
const children = linkNode.getChildren();
|
|
121
98
|
const childrenLength = children.length;
|
|
122
|
-
|
|
123
99
|
for (let i = 0; i < childrenLength; i++) {
|
|
124
100
|
const child = children[i];
|
|
125
|
-
|
|
126
101
|
if (!lexical.$isTextNode(child) || !child.isSimpleText()) {
|
|
127
102
|
replaceWithChildren(linkNode);
|
|
128
103
|
onChange(null, linkNode.getURL());
|
|
129
104
|
return;
|
|
130
105
|
}
|
|
131
|
-
}
|
|
132
|
-
|
|
106
|
+
}
|
|
133
107
|
|
|
108
|
+
// Check text content fully matches
|
|
134
109
|
const text = linkNode.getTextContent();
|
|
135
110
|
const match = findFirstMatch(text, matchers);
|
|
136
|
-
|
|
137
111
|
if (match === null || match.text !== text) {
|
|
138
112
|
replaceWithChildren(linkNode);
|
|
139
113
|
onChange(null, linkNode.getURL());
|
|
140
114
|
return;
|
|
141
|
-
}
|
|
142
|
-
|
|
115
|
+
}
|
|
143
116
|
|
|
117
|
+
// Check neighbors
|
|
144
118
|
if (!isPreviousNodeValid(linkNode) || !isNextNodeValid(linkNode)) {
|
|
145
119
|
replaceWithChildren(linkNode);
|
|
146
120
|
onChange(null, linkNode.getURL());
|
|
147
121
|
return;
|
|
148
122
|
}
|
|
149
|
-
|
|
150
123
|
const url = linkNode.getURL();
|
|
151
|
-
|
|
152
124
|
if (url !== match.url) {
|
|
153
125
|
linkNode.setURL(match.url);
|
|
154
126
|
onChange(match.url, url);
|
|
155
127
|
}
|
|
156
|
-
|
|
157
128
|
if (match.attributes) {
|
|
158
129
|
const rel = linkNode.getRel();
|
|
159
|
-
|
|
160
130
|
if (rel !== match.attributes.rel) {
|
|
161
131
|
linkNode.setRel(match.attributes.rel || null);
|
|
162
132
|
onChange(match.attributes.rel || null, rel);
|
|
163
133
|
}
|
|
164
|
-
|
|
165
134
|
const target = linkNode.getTarget();
|
|
166
|
-
|
|
167
135
|
if (target !== match.attributes.target) {
|
|
168
136
|
linkNode.setTarget(match.attributes.target || null);
|
|
169
137
|
onChange(match.attributes.target || null, target);
|
|
170
138
|
}
|
|
171
139
|
}
|
|
172
|
-
}
|
|
173
|
-
// Given the creation preconditions, these can only be simple text nodes.
|
|
174
|
-
|
|
140
|
+
}
|
|
175
141
|
|
|
142
|
+
// Bad neighbours are edits in neighbor nodes that make AutoLinks incompatible.
|
|
143
|
+
// Given the creation preconditions, these can only be simple text nodes.
|
|
176
144
|
function handleBadNeighbors(textNode, onChange) {
|
|
177
145
|
const previousSibling = textNode.getPreviousSibling();
|
|
178
146
|
const nextSibling = textNode.getNextSibling();
|
|
179
147
|
const text = textNode.getTextContent();
|
|
180
|
-
|
|
181
148
|
if (link.$isAutoLinkNode(previousSibling) && !startsWithSeparator(text)) {
|
|
182
149
|
replaceWithChildren(previousSibling);
|
|
183
150
|
onChange(null, previousSibling.getURL());
|
|
184
151
|
}
|
|
185
|
-
|
|
186
152
|
if (link.$isAutoLinkNode(nextSibling) && !endsWithSeparator(text)) {
|
|
187
153
|
replaceWithChildren(nextSibling);
|
|
188
154
|
onChange(null, nextSibling.getURL());
|
|
189
155
|
}
|
|
190
156
|
}
|
|
191
|
-
|
|
192
157
|
function replaceWithChildren(node) {
|
|
193
158
|
const children = node.getChildren();
|
|
194
159
|
const childrenLength = children.length;
|
|
195
|
-
|
|
196
160
|
for (let j = childrenLength - 1; j >= 0; j--) {
|
|
197
161
|
node.insertAfter(children[j]);
|
|
198
162
|
}
|
|
199
|
-
|
|
200
163
|
node.remove();
|
|
201
164
|
return children.map(child => child.getLatest());
|
|
202
165
|
}
|
|
203
|
-
|
|
204
166
|
function useAutoLink(editor, matchers, onChange) {
|
|
205
167
|
react.useEffect(() => {
|
|
206
168
|
if (!editor.hasNodes([link.AutoLinkNode])) {
|
|
@@ -208,29 +170,24 @@ function useAutoLink(editor, matchers, onChange) {
|
|
|
208
170
|
throw Error(`LexicalAutoLinkPlugin: AutoLinkNode not registered on editor`);
|
|
209
171
|
}
|
|
210
172
|
}
|
|
211
|
-
|
|
212
173
|
const onChangeWrapped = (url, prevUrl) => {
|
|
213
174
|
if (onChange) {
|
|
214
175
|
onChange(url, prevUrl);
|
|
215
176
|
}
|
|
216
177
|
};
|
|
217
|
-
|
|
218
178
|
return utils.mergeRegister(editor.registerNodeTransform(lexical.TextNode, textNode => {
|
|
219
179
|
const parent = textNode.getParentOrThrow();
|
|
220
|
-
|
|
221
180
|
if (link.$isAutoLinkNode(parent)) {
|
|
222
181
|
handleLinkEdit(parent, matchers, onChangeWrapped);
|
|
223
182
|
} else if (!link.$isLinkNode(parent)) {
|
|
224
183
|
if (textNode.isSimpleText()) {
|
|
225
184
|
handleLinkCreation(textNode, matchers, onChangeWrapped);
|
|
226
185
|
}
|
|
227
|
-
|
|
228
186
|
handleBadNeighbors(textNode, onChangeWrapped);
|
|
229
187
|
}
|
|
230
188
|
}));
|
|
231
189
|
}, [editor, matchers, onChange]);
|
|
232
190
|
}
|
|
233
|
-
|
|
234
191
|
function AutoLinkPlugin({
|
|
235
192
|
matchers,
|
|
236
193
|
onChange
|
|
@@ -34,31 +34,25 @@ function BlockWithAlignableContents({
|
|
|
34
34
|
event.preventDefault();
|
|
35
35
|
editor.update(() => {
|
|
36
36
|
const node = lexical.$getNodeByKey(nodeKey);
|
|
37
|
-
|
|
38
37
|
if (lexical.$isDecoratorNode(node)) {
|
|
39
38
|
node.remove();
|
|
40
39
|
}
|
|
41
|
-
|
|
42
40
|
setSelected(false);
|
|
43
41
|
});
|
|
44
42
|
}
|
|
45
|
-
|
|
46
43
|
return false;
|
|
47
44
|
}, [editor, isSelected, nodeKey, setSelected]);
|
|
48
45
|
React.useEffect(() => {
|
|
49
46
|
return utils.mergeRegister(editor.registerCommand(lexical.FORMAT_ELEMENT_COMMAND, formatType => {
|
|
50
47
|
if (isSelected) {
|
|
51
48
|
const selection = lexical.$getSelection();
|
|
52
|
-
|
|
53
49
|
if (lexical.$isNodeSelection(selection)) {
|
|
54
50
|
const node = lexical.$getNodeByKey(nodeKey);
|
|
55
|
-
|
|
56
51
|
if (LexicalDecoratorBlockNode.$isDecoratorBlockNode(node)) {
|
|
57
52
|
node.setFormat(formatType);
|
|
58
53
|
}
|
|
59
54
|
} else if (lexical.$isRangeSelection(selection)) {
|
|
60
55
|
const nodes = selection.getNodes();
|
|
61
|
-
|
|
62
56
|
for (const node of nodes) {
|
|
63
57
|
if (LexicalDecoratorBlockNode.$isDecoratorBlockNode(node)) {
|
|
64
58
|
node.setFormat(formatType);
|
|
@@ -68,23 +62,18 @@ function BlockWithAlignableContents({
|
|
|
68
62
|
}
|
|
69
63
|
}
|
|
70
64
|
}
|
|
71
|
-
|
|
72
65
|
return true;
|
|
73
66
|
}
|
|
74
|
-
|
|
75
67
|
return false;
|
|
76
68
|
}, lexical.COMMAND_PRIORITY_LOW), editor.registerCommand(lexical.CLICK_COMMAND, event => {
|
|
77
69
|
if (event.target === ref.current) {
|
|
78
70
|
event.preventDefault();
|
|
79
|
-
|
|
80
71
|
if (!event.shiftKey) {
|
|
81
72
|
clearSelection();
|
|
82
73
|
}
|
|
83
|
-
|
|
84
74
|
setSelected(!isSelected);
|
|
85
75
|
return true;
|
|
86
76
|
}
|
|
87
|
-
|
|
88
77
|
return false;
|
|
89
78
|
}, 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));
|
|
90
79
|
}, [clearSelection, editor, isSelected, nodeKey, onDelete, setSelected]);
|