@lexical/react 0.35.1-nightly.20250924.0 → 0.36.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/ExtensionComponent.d.ts +42 -0
- package/LexicalAutoEmbedPlugin.dev.js +2 -0
- package/LexicalAutoEmbedPlugin.dev.mjs +2 -0
- package/LexicalAutoEmbedPlugin.prod.js +1 -1
- package/LexicalAutoEmbedPlugin.prod.mjs +1 -1
- package/LexicalAutoLinkPlugin.d.ts +2 -17
- package/LexicalAutoLinkPlugin.dev.js +7 -309
- package/LexicalAutoLinkPlugin.dev.mjs +9 -310
- package/LexicalAutoLinkPlugin.js.flow +4 -18
- package/LexicalAutoLinkPlugin.prod.js +1 -1
- package/LexicalAutoLinkPlugin.prod.mjs +1 -1
- package/LexicalClearEditorPlugin.dev.js +2 -23
- package/LexicalClearEditorPlugin.dev.mjs +2 -23
- package/LexicalClearEditorPlugin.prod.js +1 -1
- package/LexicalClearEditorPlugin.prod.mjs +1 -1
- package/LexicalClickableLinkPlugin.dev.js +5 -70
- package/LexicalClickableLinkPlugin.dev.mjs +6 -71
- package/LexicalClickableLinkPlugin.prod.js +1 -1
- package/LexicalClickableLinkPlugin.prod.mjs +1 -1
- package/LexicalCollaborationContext.prod.js +1 -1
- package/LexicalCollaborationContext.prod.mjs +1 -1
- package/LexicalCollaborationPlugin.dev.mjs +2 -2
- package/LexicalCollaborationPlugin.prod.mjs +1 -1
- package/LexicalContentEditable.dev.js +2 -3
- package/LexicalContentEditable.dev.mjs +2 -3
- package/LexicalContentEditable.prod.js +1 -1
- package/LexicalContentEditable.prod.mjs +1 -1
- package/LexicalContextMenuPlugin.dev.js +2 -0
- package/LexicalContextMenuPlugin.dev.mjs +4 -2
- package/LexicalContextMenuPlugin.prod.js +1 -1
- package/LexicalContextMenuPlugin.prod.mjs +1 -1
- package/LexicalDecoratorBlockNode.dev.js +1 -0
- package/LexicalDecoratorBlockNode.dev.mjs +1 -0
- package/LexicalDecoratorBlockNode.js.flow +7 -0
- package/LexicalDecoratorBlockNode.prod.js +1 -1
- package/LexicalDecoratorBlockNode.prod.mjs +1 -1
- package/LexicalDraggableBlockPlugin.dev.js +6 -0
- package/LexicalDraggableBlockPlugin.dev.mjs +6 -0
- package/LexicalDraggableBlockPlugin.prod.js +1 -1
- package/LexicalDraggableBlockPlugin.prod.mjs +1 -1
- package/LexicalExtensionComponent.dev.js +53 -0
- package/LexicalExtensionComponent.dev.mjs +51 -0
- package/LexicalExtensionComponent.js +11 -0
- package/LexicalExtensionComponent.js.flow +12 -0
- package/LexicalExtensionComponent.mjs +12 -0
- package/LexicalExtensionComponent.node.mjs +10 -0
- package/LexicalExtensionComponent.prod.js +9 -0
- package/LexicalExtensionComponent.prod.mjs +9 -0
- package/LexicalExtensionComposer.d.ts +69 -0
- package/LexicalExtensionComposer.dev.js +105 -0
- package/LexicalExtensionComposer.dev.mjs +103 -0
- package/LexicalExtensionComposer.js +11 -0
- package/LexicalExtensionComposer.js.flow +20 -0
- package/LexicalExtensionComposer.mjs +12 -0
- package/LexicalExtensionComposer.node.mjs +10 -0
- package/LexicalExtensionComposer.prod.js +9 -0
- package/LexicalExtensionComposer.prod.mjs +9 -0
- package/LexicalHashtagPlugin.dev.js +1 -136
- package/LexicalHashtagPlugin.dev.mjs +3 -138
- package/LexicalHashtagPlugin.prod.js +1 -1
- package/LexicalHashtagPlugin.prod.mjs +1 -1
- package/LexicalHorizontalRuleNode.d.ts +10 -11
- package/LexicalHorizontalRuleNode.dev.js +12 -26
- package/LexicalHorizontalRuleNode.dev.mjs +14 -27
- package/LexicalHorizontalRuleNode.js.flow +2 -3
- package/LexicalHorizontalRuleNode.prod.js +1 -1
- package/LexicalHorizontalRuleNode.prod.mjs +1 -1
- package/LexicalLinkPlugin.d.ts +1 -1
- package/LexicalLinkPlugin.dev.js +7 -52
- package/LexicalLinkPlugin.dev.mjs +8 -53
- package/LexicalLinkPlugin.prod.js +1 -1
- package/LexicalLinkPlugin.prod.mjs +1 -1
- package/LexicalListPlugin.js.flow +5 -0
- package/LexicalMarkdownShortcutPlugin.dev.mjs +1 -1
- package/LexicalMarkdownShortcutPlugin.prod.mjs +1 -1
- package/LexicalNestedComposer.js.flow +10 -6
- package/LexicalNodeContextMenuPlugin.dev.js +10 -0
- package/LexicalNodeContextMenuPlugin.dev.mjs +11 -1
- package/LexicalNodeContextMenuPlugin.prod.js +1 -1
- package/LexicalNodeContextMenuPlugin.prod.mjs +1 -1
- package/LexicalNodeMenuPlugin.dev.js +2 -0
- package/LexicalNodeMenuPlugin.dev.mjs +4 -2
- package/LexicalNodeMenuPlugin.prod.js +1 -1
- package/LexicalNodeMenuPlugin.prod.mjs +1 -1
- package/LexicalPlainTextPlugin.d.ts +1 -1
- package/LexicalPlainTextPlugin.dev.js +85 -30
- package/LexicalPlainTextPlugin.dev.mjs +85 -30
- package/LexicalPlainTextPlugin.prod.js +1 -1
- package/LexicalPlainTextPlugin.prod.mjs +1 -1
- package/LexicalReactExtension.dev.js +187 -0
- package/LexicalReactExtension.dev.mjs +184 -0
- package/LexicalReactExtension.js +11 -0
- package/LexicalReactExtension.js.flow +68 -0
- package/LexicalReactExtension.mjs +13 -0
- package/LexicalReactExtension.node.mjs +11 -0
- package/LexicalReactExtension.prod.js +9 -0
- package/LexicalReactExtension.prod.mjs +9 -0
- package/LexicalReactPluginHostExtension.dev.js +189 -0
- package/LexicalReactPluginHostExtension.dev.mjs +181 -0
- package/LexicalReactPluginHostExtension.js +11 -0
- package/LexicalReactPluginHostExtension.js.flow +84 -0
- package/LexicalReactPluginHostExtension.mjs +18 -0
- package/LexicalReactPluginHostExtension.node.mjs +16 -0
- package/LexicalReactPluginHostExtension.prod.js +9 -0
- package/LexicalReactPluginHostExtension.prod.mjs +9 -0
- package/LexicalReactProviderExtension.dev.js +33 -0
- package/LexicalReactProviderExtension.dev.mjs +31 -0
- package/LexicalReactProviderExtension.js +11 -0
- package/LexicalReactProviderExtension.js.flow +12 -0
- package/LexicalReactProviderExtension.mjs +12 -0
- package/LexicalReactProviderExtension.node.mjs +10 -0
- package/LexicalReactProviderExtension.prod.js +9 -0
- package/LexicalReactProviderExtension.prod.mjs +9 -0
- package/LexicalRichTextPlugin.d.ts +1 -1
- package/LexicalRichTextPlugin.dev.js +85 -30
- package/LexicalRichTextPlugin.dev.mjs +85 -30
- package/LexicalRichTextPlugin.prod.js +1 -1
- package/LexicalRichTextPlugin.prod.mjs +1 -1
- package/LexicalTabIndentationPlugin.d.ts +2 -2
- package/LexicalTabIndentationPlugin.dev.js +3 -57
- package/LexicalTabIndentationPlugin.dev.mjs +3 -56
- package/LexicalTabIndentationPlugin.prod.js +1 -1
- package/LexicalTabIndentationPlugin.prod.mjs +1 -1
- package/LexicalTreeViewExtension.dev.js +57 -0
- package/LexicalTreeViewExtension.dev.mjs +54 -0
- package/LexicalTreeViewExtension.js +11 -0
- package/LexicalTreeViewExtension.js.flow +12 -0
- package/LexicalTreeViewExtension.mjs +13 -0
- package/LexicalTreeViewExtension.node.mjs +11 -0
- package/LexicalTreeViewExtension.prod.js +9 -0
- package/LexicalTreeViewExtension.prod.mjs +9 -0
- package/LexicalTypeaheadMenuPlugin.dev.js +2 -0
- package/LexicalTypeaheadMenuPlugin.dev.mjs +4 -2
- package/LexicalTypeaheadMenuPlugin.prod.js +1 -1
- package/LexicalTypeaheadMenuPlugin.prod.mjs +1 -1
- package/ReactExtension.d.ts +41 -0
- package/ReactPluginHostExtension.d.ts +56 -0
- package/ReactProviderExtension.d.ts +9 -0
- package/TreeViewExtension.d.ts +18 -0
- package/package.json +228 -17
- package/shared/LegacyDecorators.d.ts +23 -0
- package/shared/buildEditorComponent.d.ts +11 -0
- package/shared/mergeRefs.d.ts +2 -1
- package/shared/types.d.ts +89 -0
- package/shared/useReactDecorators.d.ts +12 -0
- package/useExtensionComponent.d.ts +10 -0
- package/useLexicalExtensionComponent.dev.js +37 -0
- package/useLexicalExtensionComponent.dev.mjs +34 -0
- package/useLexicalExtensionComponent.js +11 -0
- package/useLexicalExtensionComponent.js.flow +12 -0
- package/useLexicalExtensionComponent.mjs +13 -0
- package/useLexicalExtensionComponent.node.mjs +11 -0
- package/useLexicalExtensionComponent.prod.js +9 -0
- package/useLexicalExtensionComponent.prod.mjs +9 -0
|
@@ -6,10 +6,9 @@
|
|
|
6
6
|
*
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
|
-
import { AutoLinkNode,
|
|
9
|
+
import { AutoLinkNode, registerAutoLink } from '@lexical/link';
|
|
10
|
+
export { createLinkMatcherWithRegExp } from '@lexical/link';
|
|
10
11
|
import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext';
|
|
11
|
-
import { mergeRegister } from '@lexical/utils';
|
|
12
|
-
import { TextNode, $getSelection, $isRangeSelection, COMMAND_PRIORITY_LOW, $isTextNode, $isElementNode, $isLineBreakNode, $createTextNode, $isNodeSelection } from 'lexical';
|
|
13
12
|
import { useEffect } from 'react';
|
|
14
13
|
|
|
15
14
|
/**
|
|
@@ -26,279 +25,6 @@ function formatDevErrorMessage(message) {
|
|
|
26
25
|
throw new Error(message);
|
|
27
26
|
}
|
|
28
27
|
|
|
29
|
-
function createLinkMatcherWithRegExp(regExp, urlTransformer = text => text) {
|
|
30
|
-
return text => {
|
|
31
|
-
const match = regExp.exec(text);
|
|
32
|
-
if (match === null) {
|
|
33
|
-
return null;
|
|
34
|
-
}
|
|
35
|
-
return {
|
|
36
|
-
index: match.index,
|
|
37
|
-
length: match[0].length,
|
|
38
|
-
text: match[0],
|
|
39
|
-
url: urlTransformer(match[0])
|
|
40
|
-
};
|
|
41
|
-
};
|
|
42
|
-
}
|
|
43
|
-
function findFirstMatch(text, matchers) {
|
|
44
|
-
for (let i = 0; i < matchers.length; i++) {
|
|
45
|
-
const match = matchers[i](text);
|
|
46
|
-
if (match) {
|
|
47
|
-
return match;
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
return null;
|
|
51
|
-
}
|
|
52
|
-
const PUNCTUATION_OR_SPACE = /[.,;\s]/;
|
|
53
|
-
function isSeparator(char) {
|
|
54
|
-
return PUNCTUATION_OR_SPACE.test(char);
|
|
55
|
-
}
|
|
56
|
-
function endsWithSeparator(textContent) {
|
|
57
|
-
return isSeparator(textContent[textContent.length - 1]);
|
|
58
|
-
}
|
|
59
|
-
function startsWithSeparator(textContent) {
|
|
60
|
-
return isSeparator(textContent[0]);
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
/**
|
|
64
|
-
* Check if the text content starts with a fullstop followed by a top-level domain.
|
|
65
|
-
* Meaning if the text content can be a beginning of a top level domain.
|
|
66
|
-
* @param textContent
|
|
67
|
-
* @param isEmail
|
|
68
|
-
* @returns boolean
|
|
69
|
-
*/
|
|
70
|
-
function startsWithTLD(textContent, isEmail) {
|
|
71
|
-
if (isEmail) {
|
|
72
|
-
return /^\.[a-zA-Z]{2,}/.test(textContent);
|
|
73
|
-
} else {
|
|
74
|
-
return /^\.[a-zA-Z0-9]{1,}/.test(textContent);
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
function isPreviousNodeValid(node) {
|
|
78
|
-
let previousNode = node.getPreviousSibling();
|
|
79
|
-
if ($isElementNode(previousNode)) {
|
|
80
|
-
previousNode = previousNode.getLastDescendant();
|
|
81
|
-
}
|
|
82
|
-
return previousNode === null || $isLineBreakNode(previousNode) || $isTextNode(previousNode) && endsWithSeparator(previousNode.getTextContent());
|
|
83
|
-
}
|
|
84
|
-
function isNextNodeValid(node) {
|
|
85
|
-
let nextNode = node.getNextSibling();
|
|
86
|
-
if ($isElementNode(nextNode)) {
|
|
87
|
-
nextNode = nextNode.getFirstDescendant();
|
|
88
|
-
}
|
|
89
|
-
return nextNode === null || $isLineBreakNode(nextNode) || $isTextNode(nextNode) && startsWithSeparator(nextNode.getTextContent());
|
|
90
|
-
}
|
|
91
|
-
function isContentAroundIsValid(matchStart, matchEnd, text, nodes) {
|
|
92
|
-
const contentBeforeIsValid = matchStart > 0 ? isSeparator(text[matchStart - 1]) : isPreviousNodeValid(nodes[0]);
|
|
93
|
-
if (!contentBeforeIsValid) {
|
|
94
|
-
return false;
|
|
95
|
-
}
|
|
96
|
-
const contentAfterIsValid = matchEnd < text.length ? isSeparator(text[matchEnd]) : isNextNodeValid(nodes[nodes.length - 1]);
|
|
97
|
-
return contentAfterIsValid;
|
|
98
|
-
}
|
|
99
|
-
function extractMatchingNodes(nodes, startIndex, endIndex) {
|
|
100
|
-
const unmodifiedBeforeNodes = [];
|
|
101
|
-
const matchingNodes = [];
|
|
102
|
-
const unmodifiedAfterNodes = [];
|
|
103
|
-
let matchingOffset = 0;
|
|
104
|
-
let currentOffset = 0;
|
|
105
|
-
const currentNodes = [...nodes];
|
|
106
|
-
while (currentNodes.length > 0) {
|
|
107
|
-
const currentNode = currentNodes[0];
|
|
108
|
-
const currentNodeText = currentNode.getTextContent();
|
|
109
|
-
const currentNodeLength = currentNodeText.length;
|
|
110
|
-
const currentNodeStart = currentOffset;
|
|
111
|
-
const currentNodeEnd = currentOffset + currentNodeLength;
|
|
112
|
-
if (currentNodeEnd <= startIndex) {
|
|
113
|
-
unmodifiedBeforeNodes.push(currentNode);
|
|
114
|
-
matchingOffset += currentNodeLength;
|
|
115
|
-
} else if (currentNodeStart >= endIndex) {
|
|
116
|
-
unmodifiedAfterNodes.push(currentNode);
|
|
117
|
-
} else {
|
|
118
|
-
matchingNodes.push(currentNode);
|
|
119
|
-
}
|
|
120
|
-
currentOffset += currentNodeLength;
|
|
121
|
-
currentNodes.shift();
|
|
122
|
-
}
|
|
123
|
-
return [matchingOffset, unmodifiedBeforeNodes, matchingNodes, unmodifiedAfterNodes];
|
|
124
|
-
}
|
|
125
|
-
function $createAutoLinkNode_(nodes, startIndex, endIndex, match) {
|
|
126
|
-
const linkNode = $createAutoLinkNode(match.url, match.attributes);
|
|
127
|
-
if (nodes.length === 1) {
|
|
128
|
-
let remainingTextNode = nodes[0];
|
|
129
|
-
let linkTextNode;
|
|
130
|
-
if (startIndex === 0) {
|
|
131
|
-
[linkTextNode, remainingTextNode] = remainingTextNode.splitText(endIndex);
|
|
132
|
-
} else {
|
|
133
|
-
[, linkTextNode, remainingTextNode] = remainingTextNode.splitText(startIndex, endIndex);
|
|
134
|
-
}
|
|
135
|
-
const textNode = $createTextNode(match.text);
|
|
136
|
-
textNode.setFormat(linkTextNode.getFormat());
|
|
137
|
-
textNode.setDetail(linkTextNode.getDetail());
|
|
138
|
-
textNode.setStyle(linkTextNode.getStyle());
|
|
139
|
-
linkNode.append(textNode);
|
|
140
|
-
linkTextNode.replace(linkNode);
|
|
141
|
-
return remainingTextNode;
|
|
142
|
-
} else if (nodes.length > 1) {
|
|
143
|
-
const firstTextNode = nodes[0];
|
|
144
|
-
let offset = firstTextNode.getTextContent().length;
|
|
145
|
-
let firstLinkTextNode;
|
|
146
|
-
if (startIndex === 0) {
|
|
147
|
-
firstLinkTextNode = firstTextNode;
|
|
148
|
-
} else {
|
|
149
|
-
[, firstLinkTextNode] = firstTextNode.splitText(startIndex);
|
|
150
|
-
}
|
|
151
|
-
const linkNodes = [];
|
|
152
|
-
let remainingTextNode;
|
|
153
|
-
for (let i = 1; i < nodes.length; i++) {
|
|
154
|
-
const currentNode = nodes[i];
|
|
155
|
-
const currentNodeText = currentNode.getTextContent();
|
|
156
|
-
const currentNodeLength = currentNodeText.length;
|
|
157
|
-
const currentNodeStart = offset;
|
|
158
|
-
const currentNodeEnd = offset + currentNodeLength;
|
|
159
|
-
if (currentNodeStart < endIndex) {
|
|
160
|
-
if (currentNodeEnd <= endIndex) {
|
|
161
|
-
linkNodes.push(currentNode);
|
|
162
|
-
} else {
|
|
163
|
-
const [linkTextNode, endNode] = currentNode.splitText(endIndex - currentNodeStart);
|
|
164
|
-
linkNodes.push(linkTextNode);
|
|
165
|
-
remainingTextNode = endNode;
|
|
166
|
-
}
|
|
167
|
-
}
|
|
168
|
-
offset += currentNodeLength;
|
|
169
|
-
}
|
|
170
|
-
const selection = $getSelection();
|
|
171
|
-
const selectedTextNode = selection ? selection.getNodes().find($isTextNode) : undefined;
|
|
172
|
-
const textNode = $createTextNode(firstLinkTextNode.getTextContent());
|
|
173
|
-
textNode.setFormat(firstLinkTextNode.getFormat());
|
|
174
|
-
textNode.setDetail(firstLinkTextNode.getDetail());
|
|
175
|
-
textNode.setStyle(firstLinkTextNode.getStyle());
|
|
176
|
-
linkNode.append(textNode, ...linkNodes);
|
|
177
|
-
// it does not preserve caret position if caret was at the first text node
|
|
178
|
-
// so we need to restore caret position
|
|
179
|
-
if (selectedTextNode && selectedTextNode === firstLinkTextNode) {
|
|
180
|
-
if ($isRangeSelection(selection)) {
|
|
181
|
-
textNode.select(selection.anchor.offset, selection.focus.offset);
|
|
182
|
-
} else if ($isNodeSelection(selection)) {
|
|
183
|
-
textNode.select(0, textNode.getTextContent().length);
|
|
184
|
-
}
|
|
185
|
-
}
|
|
186
|
-
firstLinkTextNode.replace(linkNode);
|
|
187
|
-
return remainingTextNode;
|
|
188
|
-
}
|
|
189
|
-
return undefined;
|
|
190
|
-
}
|
|
191
|
-
function $handleLinkCreation(nodes, matchers, onChange) {
|
|
192
|
-
let currentNodes = [...nodes];
|
|
193
|
-
const initialText = currentNodes.map(node => node.getTextContent()).join('');
|
|
194
|
-
let text = initialText;
|
|
195
|
-
let match;
|
|
196
|
-
let invalidMatchEnd = 0;
|
|
197
|
-
while ((match = findFirstMatch(text, matchers)) && match !== null) {
|
|
198
|
-
const matchStart = match.index;
|
|
199
|
-
const matchLength = match.length;
|
|
200
|
-
const matchEnd = matchStart + matchLength;
|
|
201
|
-
const isValid = isContentAroundIsValid(invalidMatchEnd + matchStart, invalidMatchEnd + matchEnd, initialText, currentNodes);
|
|
202
|
-
if (isValid) {
|
|
203
|
-
const [matchingOffset,, matchingNodes, unmodifiedAfterNodes] = extractMatchingNodes(currentNodes, invalidMatchEnd + matchStart, invalidMatchEnd + matchEnd);
|
|
204
|
-
const actualMatchStart = invalidMatchEnd + matchStart - matchingOffset;
|
|
205
|
-
const actualMatchEnd = invalidMatchEnd + matchEnd - matchingOffset;
|
|
206
|
-
const remainingTextNode = $createAutoLinkNode_(matchingNodes, actualMatchStart, actualMatchEnd, match);
|
|
207
|
-
currentNodes = remainingTextNode ? [remainingTextNode, ...unmodifiedAfterNodes] : unmodifiedAfterNodes;
|
|
208
|
-
onChange(match.url, null);
|
|
209
|
-
invalidMatchEnd = 0;
|
|
210
|
-
} else {
|
|
211
|
-
invalidMatchEnd += matchEnd;
|
|
212
|
-
}
|
|
213
|
-
text = text.substring(matchEnd);
|
|
214
|
-
}
|
|
215
|
-
}
|
|
216
|
-
function handleLinkEdit(linkNode, matchers, onChange) {
|
|
217
|
-
// Check children are simple text
|
|
218
|
-
const children = linkNode.getChildren();
|
|
219
|
-
const childrenLength = children.length;
|
|
220
|
-
for (let i = 0; i < childrenLength; i++) {
|
|
221
|
-
const child = children[i];
|
|
222
|
-
if (!$isTextNode(child) || !child.isSimpleText()) {
|
|
223
|
-
replaceWithChildren(linkNode);
|
|
224
|
-
onChange(null, linkNode.getURL());
|
|
225
|
-
return;
|
|
226
|
-
}
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
// Check text content fully matches
|
|
230
|
-
const text = linkNode.getTextContent();
|
|
231
|
-
const match = findFirstMatch(text, matchers);
|
|
232
|
-
if (match === null || match.text !== text) {
|
|
233
|
-
replaceWithChildren(linkNode);
|
|
234
|
-
onChange(null, linkNode.getURL());
|
|
235
|
-
return;
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
// Check neighbors
|
|
239
|
-
if (!isPreviousNodeValid(linkNode) || !isNextNodeValid(linkNode)) {
|
|
240
|
-
replaceWithChildren(linkNode);
|
|
241
|
-
onChange(null, linkNode.getURL());
|
|
242
|
-
return;
|
|
243
|
-
}
|
|
244
|
-
const url = linkNode.getURL();
|
|
245
|
-
if (url !== match.url) {
|
|
246
|
-
linkNode.setURL(match.url);
|
|
247
|
-
onChange(match.url, url);
|
|
248
|
-
}
|
|
249
|
-
if (match.attributes) {
|
|
250
|
-
const rel = linkNode.getRel();
|
|
251
|
-
if (rel !== match.attributes.rel) {
|
|
252
|
-
linkNode.setRel(match.attributes.rel || null);
|
|
253
|
-
onChange(match.attributes.rel || null, rel);
|
|
254
|
-
}
|
|
255
|
-
const target = linkNode.getTarget();
|
|
256
|
-
if (target !== match.attributes.target) {
|
|
257
|
-
linkNode.setTarget(match.attributes.target || null);
|
|
258
|
-
onChange(match.attributes.target || null, target);
|
|
259
|
-
}
|
|
260
|
-
}
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
// Bad neighbors are edits in neighbor nodes that make AutoLinks incompatible.
|
|
264
|
-
// Given the creation preconditions, these can only be simple text nodes.
|
|
265
|
-
function handleBadNeighbors(textNode, matchers, onChange) {
|
|
266
|
-
const previousSibling = textNode.getPreviousSibling();
|
|
267
|
-
const nextSibling = textNode.getNextSibling();
|
|
268
|
-
const text = textNode.getTextContent();
|
|
269
|
-
if ($isAutoLinkNode(previousSibling) && !previousSibling.getIsUnlinked() && (!startsWithSeparator(text) || startsWithTLD(text, previousSibling.isEmailURI()))) {
|
|
270
|
-
previousSibling.append(textNode);
|
|
271
|
-
handleLinkEdit(previousSibling, matchers, onChange);
|
|
272
|
-
onChange(null, previousSibling.getURL());
|
|
273
|
-
}
|
|
274
|
-
if ($isAutoLinkNode(nextSibling) && !nextSibling.getIsUnlinked() && !endsWithSeparator(text)) {
|
|
275
|
-
replaceWithChildren(nextSibling);
|
|
276
|
-
handleLinkEdit(nextSibling, matchers, onChange);
|
|
277
|
-
onChange(null, nextSibling.getURL());
|
|
278
|
-
}
|
|
279
|
-
}
|
|
280
|
-
function replaceWithChildren(node) {
|
|
281
|
-
const children = node.getChildren();
|
|
282
|
-
const childrenLength = children.length;
|
|
283
|
-
for (let j = childrenLength - 1; j >= 0; j--) {
|
|
284
|
-
node.insertAfter(children[j]);
|
|
285
|
-
}
|
|
286
|
-
node.remove();
|
|
287
|
-
return children.map(child => child.getLatest());
|
|
288
|
-
}
|
|
289
|
-
function getTextNodesToMatch(textNode) {
|
|
290
|
-
// check if next siblings are simple text nodes till a node contains a space separator
|
|
291
|
-
const textNodesToMatch = [textNode];
|
|
292
|
-
let nextSibling = textNode.getNextSibling();
|
|
293
|
-
while (nextSibling !== null && $isTextNode(nextSibling) && nextSibling.isSimpleText()) {
|
|
294
|
-
textNodesToMatch.push(nextSibling);
|
|
295
|
-
if (/[\s]/.test(nextSibling.getTextContent())) {
|
|
296
|
-
break;
|
|
297
|
-
}
|
|
298
|
-
nextSibling = nextSibling.getNextSibling();
|
|
299
|
-
}
|
|
300
|
-
return textNodesToMatch;
|
|
301
|
-
}
|
|
302
28
|
function useAutoLink(editor, matchers, onChange) {
|
|
303
29
|
useEffect(() => {
|
|
304
30
|
if (!editor.hasNodes([AutoLinkNode])) {
|
|
@@ -306,39 +32,12 @@ function useAutoLink(editor, matchers, onChange) {
|
|
|
306
32
|
formatDevErrorMessage(`LexicalAutoLinkPlugin: AutoLinkNode not registered on editor`);
|
|
307
33
|
}
|
|
308
34
|
}
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
const parent = textNode.getParentOrThrow();
|
|
316
|
-
const previous = textNode.getPreviousSibling();
|
|
317
|
-
if ($isAutoLinkNode(parent) && !parent.getIsUnlinked()) {
|
|
318
|
-
handleLinkEdit(parent, matchers, onChangeWrapped);
|
|
319
|
-
} else if (!$isLinkNode(parent)) {
|
|
320
|
-
if (textNode.isSimpleText() && (startsWithSeparator(textNode.getTextContent()) || !$isAutoLinkNode(previous))) {
|
|
321
|
-
const textNodesToMatch = getTextNodesToMatch(textNode);
|
|
322
|
-
$handleLinkCreation(textNodesToMatch, matchers, onChangeWrapped);
|
|
323
|
-
}
|
|
324
|
-
handleBadNeighbors(textNode, matchers, onChangeWrapped);
|
|
325
|
-
}
|
|
326
|
-
}), editor.registerCommand(TOGGLE_LINK_COMMAND, payload => {
|
|
327
|
-
const selection = $getSelection();
|
|
328
|
-
if (payload !== null || !$isRangeSelection(selection)) {
|
|
329
|
-
return false;
|
|
330
|
-
}
|
|
331
|
-
const nodes = selection.extract();
|
|
332
|
-
nodes.forEach(node => {
|
|
333
|
-
const parent = node.getParent();
|
|
334
|
-
if ($isAutoLinkNode(parent)) {
|
|
335
|
-
// invert the value
|
|
336
|
-
parent.setIsUnlinked(!parent.getIsUnlinked());
|
|
337
|
-
parent.markDirty();
|
|
338
|
-
}
|
|
339
|
-
});
|
|
340
|
-
return false;
|
|
341
|
-
}, COMMAND_PRIORITY_LOW));
|
|
35
|
+
});
|
|
36
|
+
useEffect(() => {
|
|
37
|
+
return registerAutoLink(editor, {
|
|
38
|
+
changeHandlers: onChange ? [onChange] : [],
|
|
39
|
+
matchers
|
|
40
|
+
});
|
|
342
41
|
}, [editor, matchers, onChange]);
|
|
343
42
|
}
|
|
344
43
|
function AutoLinkPlugin({
|
|
@@ -350,4 +49,4 @@ function AutoLinkPlugin({
|
|
|
350
49
|
return null;
|
|
351
50
|
}
|
|
352
51
|
|
|
353
|
-
export { AutoLinkPlugin
|
|
52
|
+
export { AutoLinkPlugin };
|
|
@@ -7,24 +7,10 @@
|
|
|
7
7
|
* @flow strict
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
|
-
import type {LinkAttributes} from '@lexical/link';
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
type LinkMatcherResult = {
|
|
15
|
-
attributes?: LinkAttributes,
|
|
16
|
-
index: number,
|
|
17
|
-
length: number,
|
|
18
|
-
text: string,
|
|
19
|
-
url: string,
|
|
20
|
-
};
|
|
21
|
-
|
|
22
|
-
export type LinkMatcher = (text: string) => LinkMatcherResult | null;
|
|
23
|
-
|
|
24
|
-
declare export function createLinkMatcherWithRegExp(
|
|
25
|
-
regExp: RegExp,
|
|
26
|
-
urlTransformer?: (text: string) => string,
|
|
27
|
-
): LinkMatcher;
|
|
10
|
+
import type {LinkAttributes, ChangeHandler, LinkMatcher} from '@lexical/link';
|
|
11
|
+
import {createLinkMatcherWithRegExp} from '@lexical/link';
|
|
12
|
+
export {createLinkMatcherWithRegExp};
|
|
13
|
+
export type {ChangeHandler, LinkMatcher};
|
|
28
14
|
|
|
29
15
|
declare export function AutoLinkPlugin(props: {
|
|
30
16
|
matchers: Array<LinkMatcher>,
|
|
@@ -6,4 +6,4 @@
|
|
|
6
6
|
*
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
|
-
"use strict";var e=require("@lexical/link"),
|
|
9
|
+
"use strict";var e=require("@lexical/link"),r=require("@lexical/react/LexicalComposerContext"),t=require("react");function n(r,n,i){t.useEffect((()=>{r.hasNodes([e.AutoLinkNode])||function(e,...r){const t=new URL("https://lexical.dev/docs/error"),n=new URLSearchParams;n.append("code",e);for(const e of r)n.append("v",e);throw t.search=n.toString(),Error(`Minified Lexical error #${e}; visit ${t.toString()} for the full message or use the non-minified dev environment for full errors and additional helpful warnings.`)}(77)})),t.useEffect((()=>e.registerAutoLink(r,{changeHandlers:i?[i]:[],matchers:n})),[r,n,i])}exports.createLinkMatcherWithRegExp=e.createLinkMatcherWithRegExp,exports.AutoLinkPlugin=function({matchers:e,onChange:t}){const[i]=r.useLexicalComposerContext();return n(i,e,t),null};
|
|
@@ -6,4 +6,4 @@
|
|
|
6
6
|
*
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
|
-
import{AutoLinkNode as
|
|
9
|
+
import{AutoLinkNode as e,registerAutoLink as r}from"@lexical/link";export{createLinkMatcherWithRegExp}from"@lexical/link";import{useLexicalComposerContext as o}from"@lexical/react/LexicalComposerContext";import{useEffect as n}from"react";function t(o,t,i){n((()=>{o.hasNodes([e])||function(e,...r){const o=new URL("https://lexical.dev/docs/error"),n=new URLSearchParams;n.append("code",e);for(const e of r)n.append("v",e);throw o.search=n.toString(),Error(`Minified Lexical error #${e}; visit ${o.toString()} for the full message or use the non-minified dev environment for full errors and additional helpful warnings.`)}(77)})),n((()=>r(o,{changeHandlers:i?[i]:[],matchers:t})),[o,t,i])}function i({matchers:e,onChange:r}){const[n]=o();return t(n,e,r),null}export{i as AutoLinkPlugin};
|
|
@@ -8,8 +8,8 @@
|
|
|
8
8
|
|
|
9
9
|
'use strict';
|
|
10
10
|
|
|
11
|
+
var extension = require('@lexical/extension');
|
|
11
12
|
var LexicalComposerContext = require('@lexical/react/LexicalComposerContext');
|
|
12
|
-
var lexical = require('lexical');
|
|
13
13
|
var react = require('react');
|
|
14
14
|
|
|
15
15
|
/**
|
|
@@ -48,28 +48,7 @@ function ClearEditorPlugin({
|
|
|
48
48
|
onClear
|
|
49
49
|
}) {
|
|
50
50
|
const [editor] = LexicalComposerContext.useLexicalComposerContext();
|
|
51
|
-
useLayoutEffectImpl(() =>
|
|
52
|
-
return editor.registerCommand(lexical.CLEAR_EDITOR_COMMAND, payload => {
|
|
53
|
-
editor.update(() => {
|
|
54
|
-
if (onClear == null) {
|
|
55
|
-
const root = lexical.$getRoot();
|
|
56
|
-
const selection = lexical.$getSelection();
|
|
57
|
-
const paragraph = lexical.$createParagraphNode();
|
|
58
|
-
root.clear();
|
|
59
|
-
root.append(paragraph);
|
|
60
|
-
if (selection !== null) {
|
|
61
|
-
paragraph.select();
|
|
62
|
-
}
|
|
63
|
-
if (lexical.$isRangeSelection(selection)) {
|
|
64
|
-
selection.format = 0;
|
|
65
|
-
}
|
|
66
|
-
} else {
|
|
67
|
-
onClear();
|
|
68
|
-
}
|
|
69
|
-
});
|
|
70
|
-
return true;
|
|
71
|
-
}, lexical.COMMAND_PRIORITY_EDITOR);
|
|
72
|
-
}, [editor, onClear]);
|
|
51
|
+
useLayoutEffectImpl(() => extension.registerClearEditor(editor, onClear), [editor, onClear]);
|
|
73
52
|
return null;
|
|
74
53
|
}
|
|
75
54
|
|
|
@@ -6,8 +6,8 @@
|
|
|
6
6
|
*
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
|
+
import { registerClearEditor } from '@lexical/extension';
|
|
9
10
|
import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext';
|
|
10
|
-
import { CLEAR_EDITOR_COMMAND, $getRoot, $getSelection, $createParagraphNode, $isRangeSelection, COMMAND_PRIORITY_EDITOR } from 'lexical';
|
|
11
11
|
import { useLayoutEffect, useEffect } from 'react';
|
|
12
12
|
|
|
13
13
|
/**
|
|
@@ -46,28 +46,7 @@ function ClearEditorPlugin({
|
|
|
46
46
|
onClear
|
|
47
47
|
}) {
|
|
48
48
|
const [editor] = useLexicalComposerContext();
|
|
49
|
-
useLayoutEffectImpl(() =>
|
|
50
|
-
return editor.registerCommand(CLEAR_EDITOR_COMMAND, payload => {
|
|
51
|
-
editor.update(() => {
|
|
52
|
-
if (onClear == null) {
|
|
53
|
-
const root = $getRoot();
|
|
54
|
-
const selection = $getSelection();
|
|
55
|
-
const paragraph = $createParagraphNode();
|
|
56
|
-
root.clear();
|
|
57
|
-
root.append(paragraph);
|
|
58
|
-
if (selection !== null) {
|
|
59
|
-
paragraph.select();
|
|
60
|
-
}
|
|
61
|
-
if ($isRangeSelection(selection)) {
|
|
62
|
-
selection.format = 0;
|
|
63
|
-
}
|
|
64
|
-
} else {
|
|
65
|
-
onClear();
|
|
66
|
-
}
|
|
67
|
-
});
|
|
68
|
-
return true;
|
|
69
|
-
}, COMMAND_PRIORITY_EDITOR);
|
|
70
|
-
}, [editor, onClear]);
|
|
49
|
+
useLayoutEffectImpl(() => registerClearEditor(editor, onClear), [editor, onClear]);
|
|
71
50
|
return null;
|
|
72
51
|
}
|
|
73
52
|
|
|
@@ -6,4 +6,4 @@
|
|
|
6
6
|
*
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
|
-
"use strict";var e=require("@lexical/
|
|
9
|
+
"use strict";var e=require("@lexical/extension"),t=require("@lexical/react/LexicalComposerContext"),o=require("react");const r="undefined"!=typeof window&&void 0!==window.document&&void 0!==window.document.createElement?o.useLayoutEffect:o.useEffect;exports.ClearEditorPlugin=function({onClear:o}){const[i]=t.useLexicalComposerContext();return r((()=>e.registerClearEditor(i,o)),[i,o]),null};
|
|
@@ -6,4 +6,4 @@
|
|
|
6
6
|
*
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
|
-
import{
|
|
9
|
+
import{registerClearEditor as o}from"@lexical/extension";import{useLexicalComposerContext as e}from"@lexical/react/LexicalComposerContext";import{useLayoutEffect as n,useEffect as t}from"react";const i="undefined"!=typeof window&&void 0!==window.document&&void 0!==window.document.createElement?n:t;function r({onClear:n}){const[t]=e();return i((()=>o(t,n)),[t,n]),null}export{r as ClearEditorPlugin};
|
|
@@ -8,10 +8,9 @@
|
|
|
8
8
|
|
|
9
9
|
'use strict';
|
|
10
10
|
|
|
11
|
+
var extension = require('@lexical/extension');
|
|
11
12
|
var link = require('@lexical/link');
|
|
12
13
|
var LexicalComposerContext = require('@lexical/react/LexicalComposerContext');
|
|
13
|
-
var utils = require('@lexical/utils');
|
|
14
|
-
var lexical = require('lexical');
|
|
15
14
|
var react = require('react');
|
|
16
15
|
|
|
17
16
|
/**
|
|
@@ -22,80 +21,16 @@ var react = require('react');
|
|
|
22
21
|
*
|
|
23
22
|
*/
|
|
24
23
|
|
|
25
|
-
function findMatchingDOM(startNode, predicate) {
|
|
26
|
-
let node = startNode;
|
|
27
|
-
while (node != null) {
|
|
28
|
-
if (predicate(node)) {
|
|
29
|
-
return node;
|
|
30
|
-
}
|
|
31
|
-
node = node.parentNode;
|
|
32
|
-
}
|
|
33
|
-
return null;
|
|
34
|
-
}
|
|
35
24
|
function ClickableLinkPlugin({
|
|
36
25
|
newTab = true,
|
|
37
26
|
disabled = false
|
|
38
27
|
}) {
|
|
39
28
|
const [editor] = LexicalComposerContext.useLexicalComposerContext();
|
|
40
29
|
react.useEffect(() => {
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
}
|
|
46
|
-
const nearestEditor = lexical.getNearestEditorFromDOMNode(target);
|
|
47
|
-
if (nearestEditor === null) {
|
|
48
|
-
return;
|
|
49
|
-
}
|
|
50
|
-
let url = null;
|
|
51
|
-
let urlTarget = null;
|
|
52
|
-
nearestEditor.update(() => {
|
|
53
|
-
const clickedNode = lexical.$getNearestNodeFromDOMNode(target);
|
|
54
|
-
if (clickedNode !== null) {
|
|
55
|
-
const maybeLinkNode = utils.$findMatchingParent(clickedNode, lexical.$isElementNode);
|
|
56
|
-
if (!disabled) {
|
|
57
|
-
if (link.$isLinkNode(maybeLinkNode)) {
|
|
58
|
-
url = maybeLinkNode.sanitizeUrl(maybeLinkNode.getURL());
|
|
59
|
-
urlTarget = maybeLinkNode.getTarget();
|
|
60
|
-
} else {
|
|
61
|
-
const a = findMatchingDOM(target, utils.isHTMLAnchorElement);
|
|
62
|
-
if (a !== null) {
|
|
63
|
-
url = a.href;
|
|
64
|
-
urlTarget = a.target;
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
});
|
|
70
|
-
if (url === null || url === '') {
|
|
71
|
-
return;
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
// Allow user to select link text without following url
|
|
75
|
-
const selection = editor.getEditorState().read(lexical.$getSelection);
|
|
76
|
-
if (lexical.$isRangeSelection(selection) && !selection.isCollapsed()) {
|
|
77
|
-
event.preventDefault();
|
|
78
|
-
return;
|
|
79
|
-
}
|
|
80
|
-
const isMiddle = event.type === 'auxclick' && event.button === 1;
|
|
81
|
-
window.open(url, newTab || isMiddle || event.metaKey || event.ctrlKey || urlTarget === '_blank' ? '_blank' : '_self');
|
|
82
|
-
event.preventDefault();
|
|
83
|
-
};
|
|
84
|
-
const onMouseUp = event => {
|
|
85
|
-
if (event.button === 1) {
|
|
86
|
-
onClick(event);
|
|
87
|
-
}
|
|
88
|
-
};
|
|
89
|
-
return editor.registerRootListener((rootElement, prevRootElement) => {
|
|
90
|
-
if (prevRootElement !== null) {
|
|
91
|
-
prevRootElement.removeEventListener('click', onClick);
|
|
92
|
-
prevRootElement.removeEventListener('mouseup', onMouseUp);
|
|
93
|
-
}
|
|
94
|
-
if (rootElement !== null) {
|
|
95
|
-
rootElement.addEventListener('click', onClick);
|
|
96
|
-
rootElement.addEventListener('mouseup', onMouseUp);
|
|
97
|
-
}
|
|
98
|
-
});
|
|
30
|
+
return link.registerClickableLink(editor, extension.namedSignals({
|
|
31
|
+
disabled,
|
|
32
|
+
newTab
|
|
33
|
+
}));
|
|
99
34
|
}, [editor, newTab, disabled]);
|
|
100
35
|
return null;
|
|
101
36
|
}
|