@lexical/react 0.1.10 → 0.1.13
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 -7
- package/DEPRECATED_useLexical.prod.js +1 -1
- package/DEPRECATED_useLexicalAutoFormatter.dev.js +83 -37
- package/DEPRECATED_useLexicalAutoFormatter.prod.js +20 -19
- package/DEPRECATED_useLexicalCharacterLimit.dev.js +20 -17
- package/DEPRECATED_useLexicalCharacterLimit.prod.js +8 -8
- package/DEPRECATED_useLexicalList.dev.js +6 -0
- package/DEPRECATED_useLexicalList.prod.js +1 -1
- package/DEPRECATED_useLexicalPlainText.dev.js +84 -75
- package/DEPRECATED_useLexicalPlainText.prod.js +15 -15
- package/DEPRECATED_useLexicalRichText.dev.js +96 -438
- package/DEPRECATED_useLexicalRichText.prod.js +17 -26
- package/LexicalAutoFormatterPlugin.d.ts +9 -0
- package/LexicalAutoFormatterPlugin.dev.js +83 -37
- package/LexicalAutoFormatterPlugin.js.flow +10 -0
- package/LexicalAutoFormatterPlugin.prod.js +21 -20
- package/LexicalAutoLinkPlugin.d.ts +20 -0
- package/LexicalAutoLinkPlugin.js.flow +23 -0
- package/LexicalCharacterLimitPlugin.d.ts +11 -0
- package/LexicalCharacterLimitPlugin.dev.js +20 -17
- package/LexicalCharacterLimitPlugin.js.flow +12 -0
- package/LexicalCharacterLimitPlugin.prod.js +9 -8
- package/LexicalClearEditorPlugin.d.ts +14 -0
- package/LexicalClearEditorPlugin.dev.js +73 -0
- package/LexicalClearEditorPlugin.js +9 -0
- package/LexicalClearEditorPlugin.js.flow +14 -0
- package/LexicalClearEditorPlugin.prod.js +8 -0
- package/LexicalCollaborationPlugin.d.ts +49 -0
- package/LexicalCollaborationPlugin.dev.js +21 -13
- package/LexicalCollaborationPlugin.js.flow +55 -0
- package/LexicalCollaborationPlugin.prod.js +7 -7
- package/LexicalComposer.d.ts +22 -0
- package/LexicalComposer.dev.js +32 -3
- package/LexicalComposer.js.flow +24 -0
- package/LexicalComposer.prod.js +3 -2
- package/LexicalComposerContext.d.ts +24 -0
- package/LexicalComposerContext.js.flow +27 -0
- package/LexicalContentEditable.d.ts +32 -0
- package/LexicalContentEditable.dev.js +35 -8
- package/LexicalContentEditable.js.flow +35 -0
- package/LexicalContentEditable.prod.js +3 -3
- package/LexicalHashtagPlugin.d.ts +9 -0
- package/LexicalHashtagPlugin.js.flow +10 -0
- package/LexicalHistoryPlugin.d.ts +29 -0
- package/LexicalHistoryPlugin.js.flow +34 -0
- package/LexicalHorizontalRuleNode.d.ts +23 -0
- package/LexicalHorizontalRuleNode.js.flow +25 -0
- package/LexicalLinkPlugin.d.ts +9 -0
- package/LexicalLinkPlugin.js.flow +10 -0
- package/LexicalListPlugin.d.ts +9 -0
- package/LexicalListPlugin.dev.js +6 -0
- package/LexicalListPlugin.js.flow +10 -0
- package/LexicalListPlugin.prod.js +2 -2
- package/LexicalNestedComposer.d.ts +17 -0
- package/LexicalNestedComposer.dev.js +21 -11
- package/LexicalNestedComposer.js.flow +18 -0
- package/LexicalNestedComposer.prod.js +3 -2
- package/LexicalOnChangePlugin.d.ts +12 -0
- package/LexicalOnChangePlugin.js.flow +14 -0
- package/LexicalPlainTextPlugin.d.ts +15 -0
- package/LexicalPlainTextPlugin.dev.js +73 -84
- package/LexicalPlainTextPlugin.js.flow +18 -0
- package/LexicalPlainTextPlugin.prod.js +12 -12
- package/LexicalRichTextPlugin.d.ts +15 -0
- package/LexicalRichTextPlugin.dev.js +85 -447
- package/LexicalRichTextPlugin.js.flow +18 -0
- package/LexicalRichTextPlugin.prod.js +13 -22
- package/LexicalTablePlugin.d.ts +9 -0
- package/LexicalTablePlugin.dev.js +22 -0
- package/LexicalTablePlugin.js.flow +10 -0
- package/LexicalTablePlugin.prod.js +4 -3
- package/LexicalTreeView.d.ts +17 -0
- package/LexicalTreeView.js.flow +19 -0
- package/README.md +0 -1
- package/package.json +9 -5
- package/useLexicalDecoratorMap.d.ts +14 -0
- package/useLexicalDecoratorMap.js.flow +16 -0
- package/useLexicalIsTextContentEmpty.d.ts +13 -0
- package/useLexicalIsTextContentEmpty.js.flow +15 -0
- package/useLexicalNodeSelection.d.ts +12 -0
- package/useLexicalNodeSelection.js.flow +14 -0
- package/withSubscriptions.d.ts +12 -0
- package/withSubscriptions.js.flow +13 -0
- package/LexicalBootstrapPlugin.dev.js +0 -122
- package/LexicalBootstrapPlugin.js +0 -9
- package/LexicalBootstrapPlugin.prod.js +0 -8
|
@@ -10,6 +10,7 @@ var LexicalComposerContext = require('@lexical/react/LexicalComposerContext');
|
|
|
10
10
|
var React = require('react');
|
|
11
11
|
var lexical = require('lexical');
|
|
12
12
|
var reactDom = require('react-dom');
|
|
13
|
+
var clipboard = require('@lexical/clipboard');
|
|
13
14
|
|
|
14
15
|
/**
|
|
15
16
|
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
@@ -169,188 +170,6 @@ function useDecorators(editor) {
|
|
|
169
170
|
*
|
|
170
171
|
*/
|
|
171
172
|
|
|
172
|
-
function $cloneWithProperties(node) {
|
|
173
|
-
const latest = node.getLatest();
|
|
174
|
-
const constructor = latest.constructor;
|
|
175
|
-
const clone = constructor.clone(latest);
|
|
176
|
-
clone.__parent = latest.__parent;
|
|
177
|
-
|
|
178
|
-
if (lexical.$isElementNode(latest) && lexical.$isElementNode(clone)) {
|
|
179
|
-
clone.__children = Array.from(latest.__children);
|
|
180
|
-
clone.__format = latest.__format;
|
|
181
|
-
clone.__indent = latest.__indent;
|
|
182
|
-
clone.__dir = latest.__dir;
|
|
183
|
-
} else if (lexical.$isTextNode(latest) && lexical.$isTextNode(clone)) {
|
|
184
|
-
clone.__format = latest.__format;
|
|
185
|
-
clone.__style = latest.__style;
|
|
186
|
-
clone.__mode = latest.__mode;
|
|
187
|
-
clone.__detail = latest.__detail;
|
|
188
|
-
} else if (lexical.$isDecoratorNode(latest) && lexical.$isDecoratorNode(clone)) {
|
|
189
|
-
clone.__state = latest.__state;
|
|
190
|
-
} // $FlowFixMe
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
return clone;
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
function $getIndexFromPossibleClone(node, parent, nodeMap) {
|
|
197
|
-
const parentClone = nodeMap.get(parent.getKey());
|
|
198
|
-
|
|
199
|
-
if (lexical.$isElementNode(parentClone)) {
|
|
200
|
-
return parentClone.__children.indexOf(node.getKey());
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
return node.getIndexWithinParent();
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
function $getParentAvoidingExcludedElements(node) {
|
|
207
|
-
let parent = node.getParent();
|
|
208
|
-
|
|
209
|
-
while (parent !== null && parent.excludeFromCopy()) {
|
|
210
|
-
parent = parent.getParent();
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
return parent;
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
function $copyLeafNodeBranchToRoot(leaf, startingOffset, isLeftSide, range, nodeMap) {
|
|
217
|
-
let node = leaf;
|
|
218
|
-
let offset = startingOffset;
|
|
219
|
-
|
|
220
|
-
while (node !== null) {
|
|
221
|
-
const parent = $getParentAvoidingExcludedElements(node);
|
|
222
|
-
|
|
223
|
-
if (parent === null) {
|
|
224
|
-
break;
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
if (!lexical.$isElementNode(node) || !node.excludeFromCopy()) {
|
|
228
|
-
const key = node.getKey();
|
|
229
|
-
let clone = nodeMap.get(key);
|
|
230
|
-
const needsClone = clone === undefined;
|
|
231
|
-
|
|
232
|
-
if (needsClone) {
|
|
233
|
-
clone = $cloneWithProperties(node);
|
|
234
|
-
nodeMap.set(key, clone);
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
if (lexical.$isTextNode(clone) && !clone.isSegmented() && !clone.isToken()) {
|
|
238
|
-
clone.__text = clone.__text.slice(isLeftSide ? offset : 0, isLeftSide ? undefined : offset);
|
|
239
|
-
} else if (lexical.$isElementNode(clone)) {
|
|
240
|
-
clone.__children = clone.__children.slice(isLeftSide ? offset : 0, isLeftSide ? undefined : offset + 1);
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
if (lexical.$isRootNode(parent)) {
|
|
244
|
-
if (needsClone) {
|
|
245
|
-
// We only want to collect a range of top level nodes.
|
|
246
|
-
// So if the parent is the root, we know this is a top level.
|
|
247
|
-
range.push(key);
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
break;
|
|
251
|
-
}
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
offset = $getIndexFromPossibleClone(node, parent, nodeMap);
|
|
255
|
-
node = parent;
|
|
256
|
-
}
|
|
257
|
-
}
|
|
258
|
-
|
|
259
|
-
function $cloneContents(selection) {
|
|
260
|
-
if (!lexical.$isRangeSelection(selection)) {
|
|
261
|
-
{
|
|
262
|
-
throw Error(`TODO`);
|
|
263
|
-
}
|
|
264
|
-
}
|
|
265
|
-
|
|
266
|
-
const anchor = selection.anchor;
|
|
267
|
-
const focus = selection.focus;
|
|
268
|
-
const anchorOffset = anchor.getCharacterOffset();
|
|
269
|
-
const focusOffset = focus.getCharacterOffset();
|
|
270
|
-
const anchorNode = anchor.getNode();
|
|
271
|
-
const focusNode = focus.getNode();
|
|
272
|
-
const anchorNodeParent = anchorNode.getParentOrThrow(); // Handle a single text node extraction
|
|
273
|
-
|
|
274
|
-
if (anchorNode === focusNode && lexical.$isTextNode(anchorNode) && (anchorNodeParent.canBeEmpty() || anchorNodeParent.getChildrenSize() > 1)) {
|
|
275
|
-
const clonedFirstNode = $cloneWithProperties(anchorNode);
|
|
276
|
-
const isBefore = focusOffset > anchorOffset;
|
|
277
|
-
const startOffset = isBefore ? anchorOffset : focusOffset;
|
|
278
|
-
const endOffset = isBefore ? focusOffset : anchorOffset;
|
|
279
|
-
clonedFirstNode.__text = clonedFirstNode.__text.slice(startOffset, endOffset);
|
|
280
|
-
const key = clonedFirstNode.getKey();
|
|
281
|
-
return {
|
|
282
|
-
nodeMap: [[key, clonedFirstNode]],
|
|
283
|
-
range: [key]
|
|
284
|
-
};
|
|
285
|
-
}
|
|
286
|
-
|
|
287
|
-
const nodes = selection.getNodes();
|
|
288
|
-
|
|
289
|
-
if (nodes.length === 0) {
|
|
290
|
-
return {
|
|
291
|
-
nodeMap: [],
|
|
292
|
-
range: []
|
|
293
|
-
};
|
|
294
|
-
} // Check if we can use the parent of the nodes, if the
|
|
295
|
-
// parent can't be empty, then it's important that we
|
|
296
|
-
// also copy that element node along with its children.
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
let nodesLength = nodes.length;
|
|
300
|
-
const firstNode = nodes[0];
|
|
301
|
-
const firstNodeParent = firstNode.getParent();
|
|
302
|
-
|
|
303
|
-
if (firstNodeParent !== null && (!firstNodeParent.canBeEmpty() || lexical.$isRootNode(firstNodeParent))) {
|
|
304
|
-
const parentChildren = firstNodeParent.__children;
|
|
305
|
-
const parentChildrenLength = parentChildren.length;
|
|
306
|
-
|
|
307
|
-
if (parentChildrenLength === nodesLength) {
|
|
308
|
-
let areTheSame = true;
|
|
309
|
-
|
|
310
|
-
for (let i = 0; i < parentChildren.length; i++) {
|
|
311
|
-
if (parentChildren[i] !== nodes[i].__key) {
|
|
312
|
-
areTheSame = false;
|
|
313
|
-
break;
|
|
314
|
-
}
|
|
315
|
-
}
|
|
316
|
-
|
|
317
|
-
if (areTheSame) {
|
|
318
|
-
nodesLength++;
|
|
319
|
-
nodes.push(firstNodeParent);
|
|
320
|
-
}
|
|
321
|
-
}
|
|
322
|
-
}
|
|
323
|
-
|
|
324
|
-
const lastNode = nodes[nodesLength - 1];
|
|
325
|
-
const isBefore = anchor.isBefore(focus);
|
|
326
|
-
const nodeMap = new Map();
|
|
327
|
-
const range = []; // Do first node to root
|
|
328
|
-
|
|
329
|
-
$copyLeafNodeBranchToRoot(firstNode, isBefore ? anchorOffset : focusOffset, true, range, nodeMap); // Copy all nodes between
|
|
330
|
-
|
|
331
|
-
for (let i = 0; i < nodesLength; i++) {
|
|
332
|
-
const node = nodes[i];
|
|
333
|
-
const key = node.getKey();
|
|
334
|
-
|
|
335
|
-
if (!nodeMap.has(key) && (!lexical.$isElementNode(node) || !node.excludeFromCopy())) {
|
|
336
|
-
const clone = $cloneWithProperties(node);
|
|
337
|
-
|
|
338
|
-
if (lexical.$isRootNode(node.getParent())) {
|
|
339
|
-
range.push(node.getKey());
|
|
340
|
-
}
|
|
341
|
-
|
|
342
|
-
nodeMap.set(key, clone);
|
|
343
|
-
}
|
|
344
|
-
} // Do last node to root
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
$copyLeafNodeBranchToRoot(lastNode, isBefore ? focusOffset : anchorOffset, false, range, nodeMap);
|
|
348
|
-
return {
|
|
349
|
-
nodeMap: Array.from(nodeMap.entries()),
|
|
350
|
-
range
|
|
351
|
-
};
|
|
352
|
-
}
|
|
353
|
-
|
|
354
173
|
function $moveCaretSelection(selection, isHoldingShift, isBackward, granularity) {
|
|
355
174
|
selection.modify(isHoldingShift ? 'extend' : 'move', isBackward, granularity);
|
|
356
175
|
}
|
|
@@ -363,54 +182,9 @@ function $moveCharacter(selection, isHoldingShift, isBackward) {
|
|
|
363
182
|
const isRTL = $isParentElementRTL(selection);
|
|
364
183
|
$moveCaretSelection(selection, isHoldingShift, isBackward ? !isRTL : isRTL, 'character');
|
|
365
184
|
}
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
*
|
|
370
|
-
* This source code is licensed under the MIT license found in the
|
|
371
|
-
* LICENSE file in the root directory of this source tree.
|
|
372
|
-
*
|
|
373
|
-
*
|
|
374
|
-
*/
|
|
375
|
-
function resolveElement(element, isBackward, focusOffset) {
|
|
376
|
-
const parent = element.getParent();
|
|
377
|
-
let offset = focusOffset;
|
|
378
|
-
let block = element;
|
|
379
|
-
|
|
380
|
-
if (parent !== null) {
|
|
381
|
-
if (isBackward && focusOffset === 0) {
|
|
382
|
-
offset = block.getIndexWithinParent();
|
|
383
|
-
block = parent;
|
|
384
|
-
} else if (!isBackward && focusOffset === block.getChildrenSize()) {
|
|
385
|
-
offset = block.getIndexWithinParent() + 1;
|
|
386
|
-
block = parent;
|
|
387
|
-
}
|
|
388
|
-
}
|
|
389
|
-
|
|
390
|
-
return block.getChildAtIndex(isBackward ? offset - 1 : offset);
|
|
391
|
-
}
|
|
392
|
-
|
|
393
|
-
function getPossibleDecoratorNode(focus, isBackward) {
|
|
394
|
-
const focusOffset = focus.offset;
|
|
395
|
-
|
|
396
|
-
if (focus.type === 'element') {
|
|
397
|
-
const block = focus.getNode();
|
|
398
|
-
return resolveElement(block, isBackward, focusOffset);
|
|
399
|
-
} else {
|
|
400
|
-
const focusNode = focus.getNode();
|
|
401
|
-
|
|
402
|
-
if (isBackward && focusOffset === 0 || !isBackward && focusOffset === focusNode.getTextContentSize()) {
|
|
403
|
-
const possibleNode = isBackward ? focusNode.getPreviousSibling() : focusNode.getNextSibling();
|
|
404
|
-
|
|
405
|
-
if (possibleNode === null) {
|
|
406
|
-
return resolveElement(focusNode.getParentOrThrow(), isBackward, focusNode.getIndexWithinParent() + (isBackward ? 0 : 1));
|
|
407
|
-
}
|
|
408
|
-
|
|
409
|
-
return possibleNode;
|
|
410
|
-
}
|
|
411
|
-
}
|
|
412
|
-
|
|
413
|
-
return null;
|
|
185
|
+
function $shouldOverrideDefaultCharacterSelection(selection, isBackward) {
|
|
186
|
+
const possibleNode = lexical.$getDecoratorNode(selection.focus, isBackward);
|
|
187
|
+
return lexical.$isDecoratorNode(possibleNode) && !possibleNode.isIsolated();
|
|
414
188
|
}
|
|
415
189
|
|
|
416
190
|
/**
|
|
@@ -421,185 +195,39 @@ function getPossibleDecoratorNode(focus, isBackward) {
|
|
|
421
195
|
*
|
|
422
196
|
*
|
|
423
197
|
*/
|
|
198
|
+
function onCutForRichText(event, editor) {
|
|
199
|
+
onCopyForRichText(event, editor);
|
|
200
|
+
editor.update(() => {
|
|
201
|
+
const selection = lexical.$getSelection();
|
|
424
202
|
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
range,
|
|
428
|
-
nodeMap
|
|
429
|
-
} = nodeRange;
|
|
430
|
-
const parsedNodeMap = new Map(nodeMap);
|
|
431
|
-
const nodes = [];
|
|
432
|
-
|
|
433
|
-
for (let i = 0; i < range.length; i++) {
|
|
434
|
-
const key = range[i];
|
|
435
|
-
const parsedNode = parsedNodeMap.get(key);
|
|
436
|
-
|
|
437
|
-
if (parsedNode !== undefined) {
|
|
438
|
-
const node = lexical.$createNodeFromParse(parsedNode, parsedNodeMap);
|
|
439
|
-
nodes.push(node);
|
|
203
|
+
if (lexical.$isRangeSelection(selection)) {
|
|
204
|
+
selection.removeText();
|
|
440
205
|
}
|
|
441
|
-
}
|
|
442
|
-
|
|
443
|
-
return nodes;
|
|
206
|
+
});
|
|
444
207
|
}
|
|
208
|
+
function onCopyForRichText(event, editor) {
|
|
209
|
+
event.preventDefault();
|
|
210
|
+
editor.update(() => {
|
|
211
|
+
const clipboardData = event.clipboardData;
|
|
212
|
+
const selection = lexical.$getSelection();
|
|
445
213
|
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
const cachedConversions = editor._htmlConversions.get(nodeName.toLowerCase());
|
|
452
|
-
|
|
453
|
-
let currentConversion = null;
|
|
454
|
-
|
|
455
|
-
if (cachedConversions !== undefined) {
|
|
456
|
-
cachedConversions.forEach(cachedConversion => {
|
|
457
|
-
const domConversion = cachedConversion(domNode);
|
|
214
|
+
if (selection !== null) {
|
|
215
|
+
if (clipboardData != null) {
|
|
216
|
+
const htmlString = clipboard.getHtmlContent(editor);
|
|
217
|
+
const lexicalString = clipboard.$getLexicalContent(editor);
|
|
458
218
|
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
currentConversion = domConversion;
|
|
219
|
+
if (htmlString !== null) {
|
|
220
|
+
clipboardData.setData('text/html', htmlString);
|
|
462
221
|
}
|
|
463
|
-
}
|
|
464
|
-
});
|
|
465
|
-
}
|
|
466
|
-
|
|
467
|
-
return currentConversion !== null ? currentConversion.conversion : null;
|
|
468
|
-
}
|
|
469
|
-
|
|
470
|
-
function $createNodesFromDOM(node, editor, forChildMap = new Map()) {
|
|
471
|
-
let lexicalNodes = [];
|
|
472
|
-
let currentLexicalNode = null;
|
|
473
|
-
const transformFunction = getConversionFunction(node, editor);
|
|
474
|
-
const transformOutput = transformFunction ? transformFunction(node) : null;
|
|
475
|
-
let postTransform = null;
|
|
476
|
-
|
|
477
|
-
if (transformOutput !== null) {
|
|
478
|
-
postTransform = transformOutput.after;
|
|
479
|
-
currentLexicalNode = transformOutput.node;
|
|
480
|
-
|
|
481
|
-
if (currentLexicalNode !== null) {
|
|
482
|
-
lexicalNodes.push(currentLexicalNode);
|
|
483
|
-
const forChildFunctions = Array.from(forChildMap.values());
|
|
484
|
-
|
|
485
|
-
for (let i = 0; i < forChildFunctions.length; i++) {
|
|
486
|
-
forChildFunctions[i](currentLexicalNode);
|
|
487
|
-
}
|
|
488
|
-
}
|
|
489
|
-
|
|
490
|
-
if (transformOutput.forChild != null) {
|
|
491
|
-
forChildMap.set(node.nodeName, transformOutput.forChild);
|
|
492
|
-
}
|
|
493
|
-
} // If the DOM node doesn't have a transformer, we don't know what
|
|
494
|
-
// to do with it but we still need to process any childNodes.
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
const children = node.childNodes;
|
|
498
|
-
let childLexicalNodes = [];
|
|
499
|
-
|
|
500
|
-
for (let i = 0; i < children.length; i++) {
|
|
501
|
-
childLexicalNodes.push(...$createNodesFromDOM(children[i], editor, forChildMap));
|
|
502
|
-
}
|
|
503
|
-
|
|
504
|
-
if (postTransform != null) {
|
|
505
|
-
childLexicalNodes = postTransform(childLexicalNodes);
|
|
506
|
-
}
|
|
507
|
-
|
|
508
|
-
if (currentLexicalNode == null) {
|
|
509
|
-
// If it hasn't been converted to a LexicalNode, we hoist its children
|
|
510
|
-
// up to the same level as it.
|
|
511
|
-
lexicalNodes = lexicalNodes.concat(childLexicalNodes);
|
|
512
|
-
} else {
|
|
513
|
-
if (lexical.$isElementNode(currentLexicalNode)) {
|
|
514
|
-
// If the current node is a ElementNode after conversion,
|
|
515
|
-
// we can append all the children to it.
|
|
516
|
-
currentLexicalNode.append(...childLexicalNodes);
|
|
517
|
-
}
|
|
518
|
-
}
|
|
519
|
-
|
|
520
|
-
return lexicalNodes;
|
|
521
|
-
}
|
|
522
222
|
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
const elements = dom.body ? Array.from(dom.body.childNodes) : [];
|
|
526
|
-
const elementsLength = elements.length;
|
|
527
|
-
|
|
528
|
-
for (let i = 0; i < elementsLength; i++) {
|
|
529
|
-
const lexicalNode = $createNodesFromDOM(elements[i], editor);
|
|
530
|
-
|
|
531
|
-
if (lexicalNode !== null) {
|
|
532
|
-
lexicalNodes = lexicalNodes.concat(lexicalNode);
|
|
533
|
-
}
|
|
534
|
-
}
|
|
535
|
-
|
|
536
|
-
return lexicalNodes;
|
|
537
|
-
}
|
|
538
|
-
|
|
539
|
-
function $insertDataTransferForRichText(dataTransfer, selection, editor) {
|
|
540
|
-
const lexicalNodesString = dataTransfer.getData('application/x-lexical-editor');
|
|
541
|
-
|
|
542
|
-
if (lexicalNodesString) {
|
|
543
|
-
const namespace = editor._config.namespace;
|
|
544
|
-
|
|
545
|
-
try {
|
|
546
|
-
const lexicalClipboardData = JSON.parse(lexicalNodesString);
|
|
547
|
-
|
|
548
|
-
if (lexicalClipboardData.namespace === namespace) {
|
|
549
|
-
const nodeRange = lexicalClipboardData.state;
|
|
550
|
-
const nodes = $generateNodes(nodeRange);
|
|
551
|
-
selection.insertNodes(nodes);
|
|
552
|
-
return;
|
|
553
|
-
}
|
|
554
|
-
} catch (e) {// Malformed, missing nodes..
|
|
555
|
-
}
|
|
556
|
-
}
|
|
557
|
-
|
|
558
|
-
const textHtmlMimeType = 'text/html';
|
|
559
|
-
const htmlString = dataTransfer.getData(textHtmlMimeType);
|
|
560
|
-
|
|
561
|
-
if (htmlString) {
|
|
562
|
-
const parser = new DOMParser();
|
|
563
|
-
const dom = parser.parseFromString(htmlString, textHtmlMimeType);
|
|
564
|
-
const nodes = $generateNodesFromDOM(dom, editor); // Wrap text and inline nodes in paragraph nodes so we have all blocks at the top-level
|
|
565
|
-
|
|
566
|
-
const topLevelBlocks = [];
|
|
567
|
-
let currentBlock = null;
|
|
568
|
-
|
|
569
|
-
for (let i = 0; i < nodes.length; i++) {
|
|
570
|
-
const node = nodes[i];
|
|
571
|
-
|
|
572
|
-
if (!lexical.$isElementNode(node) || node.isInline()) {
|
|
573
|
-
if (currentBlock === null) {
|
|
574
|
-
currentBlock = lexical.$createParagraphNode();
|
|
575
|
-
topLevelBlocks.push(currentBlock);
|
|
223
|
+
if (lexicalString !== null) {
|
|
224
|
+
clipboardData.setData('application/x-lexical-editor', lexicalString);
|
|
576
225
|
}
|
|
577
226
|
|
|
578
|
-
|
|
579
|
-
currentBlock.append(node);
|
|
580
|
-
}
|
|
581
|
-
} else {
|
|
582
|
-
topLevelBlocks.push(node);
|
|
583
|
-
currentBlock = null;
|
|
227
|
+
clipboardData.setData('text/plain', selection.getTextContent());
|
|
584
228
|
}
|
|
585
229
|
}
|
|
586
|
-
|
|
587
|
-
selection.insertNodes(topLevelBlocks);
|
|
588
|
-
return;
|
|
589
|
-
}
|
|
590
|
-
|
|
591
|
-
$insertDataTransferForPlainText(dataTransfer, selection);
|
|
592
|
-
}
|
|
593
|
-
function $insertDataTransferForPlainText(dataTransfer, selection) {
|
|
594
|
-
const text = dataTransfer.getData('text/plain');
|
|
595
|
-
|
|
596
|
-
if (text != null) {
|
|
597
|
-
selection.insertRawText(text);
|
|
598
|
-
}
|
|
599
|
-
}
|
|
600
|
-
function $shouldOverrideDefaultCharacterSelection(selection, isBackward) {
|
|
601
|
-
const possibleNode = getPossibleDecoratorNode(selection.focus, isBackward);
|
|
602
|
-
return lexical.$isDecoratorNode(possibleNode) && !possibleNode.isIsolated();
|
|
230
|
+
});
|
|
603
231
|
}
|
|
604
232
|
function onPasteForRichText(event, editor) {
|
|
605
233
|
event.preventDefault();
|
|
@@ -608,52 +236,65 @@ function onPasteForRichText(event, editor) {
|
|
|
608
236
|
const clipboardData = event.clipboardData;
|
|
609
237
|
|
|
610
238
|
if (clipboardData != null && lexical.$isRangeSelection(selection)) {
|
|
611
|
-
|
|
612
|
-
}
|
|
613
|
-
});
|
|
614
|
-
}
|
|
615
|
-
function onCutForRichText(event, editor) {
|
|
616
|
-
onCopyForRichText(event, editor);
|
|
617
|
-
editor.update(() => {
|
|
618
|
-
const selection = lexical.$getSelection();
|
|
619
|
-
|
|
620
|
-
if (lexical.$isRangeSelection(selection)) {
|
|
621
|
-
selection.removeText();
|
|
239
|
+
clipboard.$insertDataTransferForRichText(clipboardData, selection, editor);
|
|
622
240
|
}
|
|
623
241
|
});
|
|
624
242
|
}
|
|
625
|
-
function onCopyForRichText(event, editor) {
|
|
626
|
-
event.preventDefault();
|
|
627
|
-
editor.update(() => {
|
|
628
|
-
const clipboardData = event.clipboardData;
|
|
629
|
-
const selection = lexical.$getSelection();
|
|
630
|
-
|
|
631
|
-
if (selection !== null) {
|
|
632
|
-
if (clipboardData != null) {
|
|
633
|
-
const domSelection = window.getSelection(); // If we haven't selected a range, then don't copy anything
|
|
634
243
|
|
|
635
|
-
|
|
636
|
-
|
|
244
|
+
/**
|
|
245
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
246
|
+
*
|
|
247
|
+
* This source code is licensed under the MIT license found in the
|
|
248
|
+
* LICENSE file in the root directory of this source tree.
|
|
249
|
+
*
|
|
250
|
+
*
|
|
251
|
+
*/
|
|
252
|
+
// Convoluted logic to make this work with Flow. Order matters.
|
|
253
|
+
const options = {
|
|
254
|
+
tag: 'history-merge'
|
|
255
|
+
};
|
|
256
|
+
const setEditorOptions = options;
|
|
257
|
+
const updateOptions = options;
|
|
258
|
+
function initializeEditor(editor, initialEditorState) {
|
|
259
|
+
if (initialEditorState === null) {
|
|
260
|
+
return;
|
|
261
|
+
} else if (initialEditorState === undefined) {
|
|
262
|
+
editor.update(() => {
|
|
263
|
+
const root = lexical.$getRoot();
|
|
264
|
+
const firstChild = root.getFirstChild();
|
|
265
|
+
|
|
266
|
+
if (firstChild === null) {
|
|
267
|
+
const paragraph = lexical.$createParagraphNode();
|
|
268
|
+
root.append(paragraph);
|
|
269
|
+
const activeElement = document.activeElement;
|
|
270
|
+
|
|
271
|
+
if (lexical.$getSelection() !== null || activeElement !== null && activeElement === editor.getRootElement()) {
|
|
272
|
+
paragraph.select();
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
}, updateOptions);
|
|
276
|
+
} else if (initialEditorState !== null) {
|
|
277
|
+
switch (typeof initialEditorState) {
|
|
278
|
+
case 'string':
|
|
279
|
+
{
|
|
280
|
+
const parsedEditorState = editor.parseEditorState(initialEditorState);
|
|
281
|
+
editor.setEditorState(parsedEditorState, setEditorOptions);
|
|
282
|
+
break;
|
|
637
283
|
}
|
|
638
284
|
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
const frag = range.cloneContents();
|
|
644
|
-
container.appendChild(frag);
|
|
645
|
-
clipboardData.setData('text/html', container.innerHTML);
|
|
285
|
+
case 'object':
|
|
286
|
+
{
|
|
287
|
+
editor.setEditorState(initialEditorState, setEditorOptions);
|
|
288
|
+
break;
|
|
646
289
|
}
|
|
647
290
|
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
}));
|
|
654
|
-
}
|
|
291
|
+
case 'function':
|
|
292
|
+
{
|
|
293
|
+
editor.update(initialEditorState, updateOptions);
|
|
294
|
+
break;
|
|
295
|
+
}
|
|
655
296
|
}
|
|
656
|
-
}
|
|
297
|
+
}
|
|
657
298
|
}
|
|
658
299
|
|
|
659
300
|
/**
|
|
@@ -752,8 +393,8 @@ function useLexicalDragonSupport(editor) {
|
|
|
752
393
|
*
|
|
753
394
|
*
|
|
754
395
|
*/
|
|
755
|
-
function useRichTextSetup(editor) {
|
|
756
|
-
|
|
396
|
+
function useRichTextSetup(editor, initialEditorState) {
|
|
397
|
+
useLayoutEffect(() => {
|
|
757
398
|
const removeListener = editor.addListener('command', (type, payload) => {
|
|
758
399
|
const selection = lexical.$getSelection();
|
|
759
400
|
|
|
@@ -798,7 +439,7 @@ function useRichTextSetup(editor) {
|
|
|
798
439
|
const dataTransfer = eventOrText.dataTransfer;
|
|
799
440
|
|
|
800
441
|
if (dataTransfer != null) {
|
|
801
|
-
|
|
442
|
+
clipboard.$insertDataTransferForRichText(dataTransfer, selection, editor);
|
|
802
443
|
} else {
|
|
803
444
|
const data = eventOrText.data;
|
|
804
445
|
|
|
@@ -992,13 +633,9 @@ function useRichTextSetup(editor) {
|
|
|
992
633
|
|
|
993
634
|
return false;
|
|
994
635
|
}, 0);
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
console.warn('bootstrapEditor command was not handled. Did you forget to add <BootstrapPlugin />?');
|
|
999
|
-
}
|
|
1000
|
-
|
|
1001
|
-
return removeListener;
|
|
636
|
+
initializeEditor(editor, initialEditorState);
|
|
637
|
+
return removeListener; // We only do this for init
|
|
638
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
1002
639
|
}, [editor]);
|
|
1003
640
|
useLexicalDragonSupport(editor);
|
|
1004
641
|
}
|
|
@@ -1013,11 +650,12 @@ function useRichTextSetup(editor) {
|
|
|
1013
650
|
*/
|
|
1014
651
|
function RichTextPlugin({
|
|
1015
652
|
contentEditable,
|
|
1016
|
-
placeholder
|
|
653
|
+
placeholder,
|
|
654
|
+
initialEditorState
|
|
1017
655
|
}) {
|
|
1018
656
|
const [editor] = LexicalComposerContext.useLexicalComposerContext();
|
|
1019
657
|
const showPlaceholder = useLexicalCanShowPlaceholder(editor);
|
|
1020
|
-
useRichTextSetup(editor);
|
|
658
|
+
useRichTextSetup(editor, initialEditorState);
|
|
1021
659
|
const decorators = useDecorators(editor);
|
|
1022
660
|
return /*#__PURE__*/React.createElement(React.Fragment, null, contentEditable, showPlaceholder && placeholder, decorators);
|
|
1023
661
|
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*
|
|
7
|
+
* @flow strict
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import type {EditorState} from 'lexical';
|
|
11
|
+
|
|
12
|
+
type InitialEditorStateType = null | string | EditorState | (() => void);
|
|
13
|
+
|
|
14
|
+
declare export default function RichTextPlugin({
|
|
15
|
+
contentEditable: React$Node,
|
|
16
|
+
initialEditorState?: InitialEditorStateType,
|
|
17
|
+
placeholder: React$Node,
|
|
18
|
+
}): React$Node;
|