@lexical/react 0.1.9 → 0.1.12
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 +5 -44
- package/DEPRECATED_useLexical.prod.js +1 -2
- package/DEPRECATED_useLexicalAutoFormatter.dev.js +87 -41
- package/DEPRECATED_useLexicalAutoFormatter.prod.js +20 -18
- package/DEPRECATED_useLexicalCharacterLimit.dev.js +22 -19
- package/DEPRECATED_useLexicalCharacterLimit.prod.js +8 -8
- package/DEPRECATED_useLexicalEditor.dev.js +1 -25
- package/DEPRECATED_useLexicalEditor.prod.js +1 -1
- package/DEPRECATED_useLexicalHistory.dev.js +1 -1
- package/DEPRECATED_useLexicalHistory.prod.js +2 -2
- package/DEPRECATED_useLexicalList.dev.js +6 -0
- package/DEPRECATED_useLexicalList.prod.js +1 -1
- package/DEPRECATED_useLexicalPlainText.dev.js +81 -89
- package/DEPRECATED_useLexicalPlainText.prod.js +15 -16
- package/DEPRECATED_useLexicalRichText.dev.js +98 -592
- package/DEPRECATED_useLexicalRichText.prod.js +17 -29
- package/LexicalAutoFormatterPlugin.d.ts +9 -0
- package/LexicalAutoFormatterPlugin.dev.js +87 -41
- package/LexicalAutoFormatterPlugin.js.flow +10 -0
- package/LexicalAutoFormatterPlugin.prod.js +21 -19
- package/LexicalAutoLinkPlugin.d.ts +20 -0
- package/LexicalAutoLinkPlugin.js.flow +23 -0
- package/LexicalCharacterLimitPlugin.d.ts +11 -0
- package/LexicalCharacterLimitPlugin.dev.js +22 -19
- 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 -11
- package/LexicalCollaborationPlugin.js.flow +55 -0
- package/LexicalCollaborationPlugin.prod.js +7 -7
- package/LexicalComposer.d.ts +22 -0
- package/LexicalComposer.dev.js +29 -5
- package/LexicalComposer.js.flow +24 -0
- package/LexicalComposer.prod.js +3 -3
- 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.dev.js +1 -1
- package/LexicalHistoryPlugin.js.flow +34 -0
- package/LexicalHistoryPlugin.prod.js +2 -2
- 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 +20 -0
- package/LexicalNestedComposer.js.flow +21 -0
- package/LexicalOnChangePlugin.d.ts +12 -0
- package/LexicalOnChangePlugin.js.flow +14 -0
- package/LexicalPlainTextPlugin.d.ts +15 -0
- package/LexicalPlainTextPlugin.dev.js +77 -84
- package/LexicalPlainTextPlugin.js.flow +18 -0
- package/LexicalPlainTextPlugin.prod.js +12 -12
- package/LexicalRichTextPlugin.d.ts +15 -0
- package/LexicalRichTextPlugin.dev.js +93 -586
- package/LexicalRichTextPlugin.js.flow +18 -0
- package/LexicalRichTextPlugin.prod.js +13 -25
- package/LexicalTablePlugin.d.ts +9 -0
- package/LexicalTablePlugin.dev.js +23 -1
- package/LexicalTablePlugin.js.flow +10 -0
- package/LexicalTablePlugin.prod.js +4 -3
- package/LexicalTreeView.d.ts +17 -0
- package/LexicalTreeView.dev.js +10 -2
- package/LexicalTreeView.js.flow +19 -0
- package/LexicalTreeView.prod.js +9 -8
- package/README.md +0 -1
- package/package.json +6 -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.dev.js +70 -0
- package/useLexicalNodeSelection.js +9 -0
- package/useLexicalNodeSelection.js.flow +14 -0
- package/useLexicalNodeSelection.prod.js +8 -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
|
@@ -9,10 +9,7 @@
|
|
|
9
9
|
var withSubscriptions = require('@lexical/react/withSubscriptions');
|
|
10
10
|
var lexical = require('lexical');
|
|
11
11
|
var react = require('react');
|
|
12
|
-
var
|
|
13
|
-
var CodeNode = require('lexical/CodeNode');
|
|
14
|
-
var HeadingNode = require('lexical/HeadingNode');
|
|
15
|
-
var LinkNode = require('lexical/LinkNode');
|
|
12
|
+
var clipboard = require('@lexical/clipboard');
|
|
16
13
|
|
|
17
14
|
/**
|
|
18
15
|
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
@@ -30,7 +27,7 @@ const COMPOSING_CHARACTER = 1;
|
|
|
30
27
|
const INSERT_CHARACTER_AFTER_SELECTION = 2;
|
|
31
28
|
const DELETE_CHARACTER_BEFORE_SELECTION = 3;
|
|
32
29
|
const DELETE_CHARACTER_AFTER_SELECTION = 4;
|
|
33
|
-
const EditorPriority
|
|
30
|
+
const EditorPriority = 0;
|
|
34
31
|
|
|
35
32
|
function getDirtyNodes(editorState, dirtyLeavesSet, dirtyElementsSet) {
|
|
36
33
|
const dirtyLeaves = Array.from(dirtyLeavesSet);
|
|
@@ -77,7 +74,7 @@ function getChangeType(prevEditorState, nextEditorState, dirtyLeavesSet, dirtyEl
|
|
|
77
74
|
return COMPOSING_CHARACTER;
|
|
78
75
|
}
|
|
79
76
|
|
|
80
|
-
if (nextSelection
|
|
77
|
+
if (!lexical.$isRangeSelection(nextSelection) || !lexical.$isRangeSelection(prevSelection) || !prevSelection.isCollapsed() || !nextSelection.isCollapsed()) {
|
|
81
78
|
return OTHER;
|
|
82
79
|
}
|
|
83
80
|
|
|
@@ -319,7 +316,7 @@ function useHistory(editor, externalHistoryState, delay = 1000) {
|
|
|
319
316
|
}
|
|
320
317
|
};
|
|
321
318
|
|
|
322
|
-
return withSubscriptions(editor.addListener('command', applyCommand, EditorPriority
|
|
319
|
+
return withSubscriptions(editor.addListener('command', applyCommand, EditorPriority), editor.addListener('update', applyChange));
|
|
323
320
|
}, [clearHistory, delay, editor, historyState]);
|
|
324
321
|
}
|
|
325
322
|
function createEmptyHistoryState() {
|
|
@@ -351,182 +348,6 @@ function useLexicalHistory(editor, externalHistoryState, delay = 1000) {
|
|
|
351
348
|
*
|
|
352
349
|
*/
|
|
353
350
|
|
|
354
|
-
function $cloneWithProperties(node) {
|
|
355
|
-
const latest = node.getLatest();
|
|
356
|
-
const constructor = latest.constructor;
|
|
357
|
-
const clone = constructor.clone(latest);
|
|
358
|
-
clone.__parent = latest.__parent;
|
|
359
|
-
|
|
360
|
-
if (lexical.$isElementNode(latest) && lexical.$isElementNode(clone)) {
|
|
361
|
-
clone.__children = Array.from(latest.__children);
|
|
362
|
-
clone.__format = latest.__format;
|
|
363
|
-
clone.__indent = latest.__indent;
|
|
364
|
-
clone.__dir = latest.__dir;
|
|
365
|
-
} else if (lexical.$isTextNode(latest) && lexical.$isTextNode(clone)) {
|
|
366
|
-
clone.__format = latest.__format;
|
|
367
|
-
clone.__style = latest.__style;
|
|
368
|
-
clone.__mode = latest.__mode;
|
|
369
|
-
clone.__detail = latest.__detail;
|
|
370
|
-
} else if (lexical.$isDecoratorNode(latest) && lexical.$isDecoratorNode(clone)) {
|
|
371
|
-
clone.__state = latest.__state;
|
|
372
|
-
} // $FlowFixMe
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
return clone;
|
|
376
|
-
}
|
|
377
|
-
|
|
378
|
-
function $getIndexFromPossibleClone(node, parent, nodeMap) {
|
|
379
|
-
const parentClone = nodeMap.get(parent.getKey());
|
|
380
|
-
|
|
381
|
-
if (lexical.$isElementNode(parentClone)) {
|
|
382
|
-
return parentClone.__children.indexOf(node.getKey());
|
|
383
|
-
}
|
|
384
|
-
|
|
385
|
-
return node.getIndexWithinParent();
|
|
386
|
-
}
|
|
387
|
-
|
|
388
|
-
function $getParentAvoidingExcludedElements(node) {
|
|
389
|
-
let parent = node.getParent();
|
|
390
|
-
|
|
391
|
-
while (parent !== null && parent.excludeFromCopy()) {
|
|
392
|
-
parent = parent.getParent();
|
|
393
|
-
}
|
|
394
|
-
|
|
395
|
-
return parent;
|
|
396
|
-
}
|
|
397
|
-
|
|
398
|
-
function $copyLeafNodeBranchToRoot(leaf, startingOffset, isLeftSide, range, nodeMap) {
|
|
399
|
-
let node = leaf;
|
|
400
|
-
let offset = startingOffset;
|
|
401
|
-
|
|
402
|
-
while (node !== null) {
|
|
403
|
-
const parent = $getParentAvoidingExcludedElements(node);
|
|
404
|
-
|
|
405
|
-
if (parent === null) {
|
|
406
|
-
break;
|
|
407
|
-
}
|
|
408
|
-
|
|
409
|
-
if (!lexical.$isElementNode(node) || !node.excludeFromCopy()) {
|
|
410
|
-
const key = node.getKey();
|
|
411
|
-
let clone = nodeMap.get(key);
|
|
412
|
-
const needsClone = clone === undefined;
|
|
413
|
-
|
|
414
|
-
if (needsClone) {
|
|
415
|
-
clone = $cloneWithProperties(node);
|
|
416
|
-
nodeMap.set(key, clone);
|
|
417
|
-
}
|
|
418
|
-
|
|
419
|
-
if (lexical.$isTextNode(clone) && !clone.isSegmented() && !clone.isToken()) {
|
|
420
|
-
clone.__text = clone.__text.slice(isLeftSide ? offset : 0, isLeftSide ? undefined : offset);
|
|
421
|
-
} else if (lexical.$isElementNode(clone)) {
|
|
422
|
-
clone.__children = clone.__children.slice(isLeftSide ? offset : 0, isLeftSide ? undefined : offset + 1);
|
|
423
|
-
}
|
|
424
|
-
|
|
425
|
-
if (lexical.$isRootNode(parent)) {
|
|
426
|
-
if (needsClone) {
|
|
427
|
-
// We only want to collect a range of top level nodes.
|
|
428
|
-
// So if the parent is the root, we know this is a top level.
|
|
429
|
-
range.push(key);
|
|
430
|
-
}
|
|
431
|
-
|
|
432
|
-
break;
|
|
433
|
-
}
|
|
434
|
-
}
|
|
435
|
-
|
|
436
|
-
offset = $getIndexFromPossibleClone(node, parent, nodeMap);
|
|
437
|
-
node = parent;
|
|
438
|
-
}
|
|
439
|
-
}
|
|
440
|
-
|
|
441
|
-
function $cloneContents(selection) {
|
|
442
|
-
const anchor = selection.anchor;
|
|
443
|
-
const focus = selection.focus;
|
|
444
|
-
const anchorOffset = anchor.getCharacterOffset();
|
|
445
|
-
const focusOffset = focus.getCharacterOffset();
|
|
446
|
-
const anchorNode = anchor.getNode();
|
|
447
|
-
const focusNode = focus.getNode();
|
|
448
|
-
const anchorNodeParent = anchorNode.getParentOrThrow(); // Handle a single text node extraction
|
|
449
|
-
|
|
450
|
-
if (anchorNode === focusNode && lexical.$isTextNode(anchorNode) && (anchorNodeParent.canBeEmpty() || anchorNodeParent.getChildrenSize() > 1)) {
|
|
451
|
-
const clonedFirstNode = $cloneWithProperties(anchorNode);
|
|
452
|
-
const isBefore = focusOffset > anchorOffset;
|
|
453
|
-
const startOffset = isBefore ? anchorOffset : focusOffset;
|
|
454
|
-
const endOffset = isBefore ? focusOffset : anchorOffset;
|
|
455
|
-
clonedFirstNode.__text = clonedFirstNode.__text.slice(startOffset, endOffset);
|
|
456
|
-
const key = clonedFirstNode.getKey();
|
|
457
|
-
return {
|
|
458
|
-
nodeMap: [[key, clonedFirstNode]],
|
|
459
|
-
range: [key]
|
|
460
|
-
};
|
|
461
|
-
}
|
|
462
|
-
|
|
463
|
-
const nodes = selection.getNodes();
|
|
464
|
-
|
|
465
|
-
if (nodes.length === 0) {
|
|
466
|
-
return {
|
|
467
|
-
nodeMap: [],
|
|
468
|
-
range: []
|
|
469
|
-
};
|
|
470
|
-
} // Check if we can use the parent of the nodes, if the
|
|
471
|
-
// parent can't be empty, then it's important that we
|
|
472
|
-
// also copy that element node along with its children.
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
let nodesLength = nodes.length;
|
|
476
|
-
const firstNode = nodes[0];
|
|
477
|
-
const firstNodeParent = firstNode.getParent();
|
|
478
|
-
|
|
479
|
-
if (firstNodeParent !== null && (!firstNodeParent.canBeEmpty() || lexical.$isRootNode(firstNodeParent))) {
|
|
480
|
-
const parentChildren = firstNodeParent.__children;
|
|
481
|
-
const parentChildrenLength = parentChildren.length;
|
|
482
|
-
|
|
483
|
-
if (parentChildrenLength === nodesLength) {
|
|
484
|
-
let areTheSame = true;
|
|
485
|
-
|
|
486
|
-
for (let i = 0; i < parentChildren.length; i++) {
|
|
487
|
-
if (parentChildren[i] !== nodes[i].__key) {
|
|
488
|
-
areTheSame = false;
|
|
489
|
-
break;
|
|
490
|
-
}
|
|
491
|
-
}
|
|
492
|
-
|
|
493
|
-
if (areTheSame) {
|
|
494
|
-
nodesLength++;
|
|
495
|
-
nodes.push(firstNodeParent);
|
|
496
|
-
}
|
|
497
|
-
}
|
|
498
|
-
}
|
|
499
|
-
|
|
500
|
-
const lastNode = nodes[nodesLength - 1];
|
|
501
|
-
const isBefore = anchor.isBefore(focus);
|
|
502
|
-
const nodeMap = new Map();
|
|
503
|
-
const range = []; // Do first node to root
|
|
504
|
-
|
|
505
|
-
$copyLeafNodeBranchToRoot(firstNode, isBefore ? anchorOffset : focusOffset, true, range, nodeMap); // Copy all nodes between
|
|
506
|
-
|
|
507
|
-
for (let i = 0; i < nodesLength; i++) {
|
|
508
|
-
const node = nodes[i];
|
|
509
|
-
const key = node.getKey();
|
|
510
|
-
|
|
511
|
-
if (!nodeMap.has(key) && (!lexical.$isElementNode(node) || !node.excludeFromCopy())) {
|
|
512
|
-
const clone = $cloneWithProperties(node);
|
|
513
|
-
|
|
514
|
-
if (lexical.$isRootNode(node.getParent())) {
|
|
515
|
-
range.push(node.getKey());
|
|
516
|
-
}
|
|
517
|
-
|
|
518
|
-
nodeMap.set(key, clone);
|
|
519
|
-
}
|
|
520
|
-
} // Do last node to root
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
$copyLeafNodeBranchToRoot(lastNode, isBefore ? focusOffset : anchorOffset, false, range, nodeMap);
|
|
524
|
-
return {
|
|
525
|
-
nodeMap: Array.from(nodeMap.entries()),
|
|
526
|
-
range
|
|
527
|
-
};
|
|
528
|
-
}
|
|
529
|
-
|
|
530
351
|
function $moveCaretSelection(selection, isHoldingShift, isBackward, granularity) {
|
|
531
352
|
selection.modify(isHoldingShift ? 'extend' : 'move', isBackward, granularity);
|
|
532
353
|
}
|
|
@@ -539,6 +360,10 @@ function $moveCharacter(selection, isHoldingShift, isBackward) {
|
|
|
539
360
|
const isRTL = $isParentElementRTL(selection);
|
|
540
361
|
$moveCaretSelection(selection, isHoldingShift, isBackward ? !isRTL : isRTL, 'character');
|
|
541
362
|
}
|
|
363
|
+
function $shouldOverrideDefaultCharacterSelection(selection, isBackward) {
|
|
364
|
+
const possibleNode = lexical.$getDecoratorNode(selection.focus, isBackward);
|
|
365
|
+
return lexical.$isDecoratorNode(possibleNode) && !possibleNode.isIsolated();
|
|
366
|
+
}
|
|
542
367
|
|
|
543
368
|
/**
|
|
544
369
|
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
@@ -548,46 +373,7 @@ function $moveCharacter(selection, isHoldingShift, isBackward) {
|
|
|
548
373
|
*
|
|
549
374
|
*
|
|
550
375
|
*/
|
|
551
|
-
|
|
552
|
-
const parent = element.getParent();
|
|
553
|
-
let offset = focusOffset;
|
|
554
|
-
let block = element;
|
|
555
|
-
|
|
556
|
-
if (parent !== null) {
|
|
557
|
-
if (isBackward && focusOffset === 0) {
|
|
558
|
-
offset = block.getIndexWithinParent();
|
|
559
|
-
block = parent;
|
|
560
|
-
} else if (!isBackward && focusOffset === block.getChildrenSize()) {
|
|
561
|
-
offset = block.getIndexWithinParent() + 1;
|
|
562
|
-
block = parent;
|
|
563
|
-
}
|
|
564
|
-
}
|
|
565
|
-
|
|
566
|
-
return block.getChildAtIndex(isBackward ? offset - 1 : offset);
|
|
567
|
-
}
|
|
568
|
-
|
|
569
|
-
function getPossibleDecoratorNode(focus, isBackward) {
|
|
570
|
-
const focusOffset = focus.offset;
|
|
571
|
-
|
|
572
|
-
if (focus.type === 'element') {
|
|
573
|
-
const block = focus.getNode();
|
|
574
|
-
return resolveElement(block, isBackward, focusOffset);
|
|
575
|
-
} else {
|
|
576
|
-
const focusNode = focus.getNode();
|
|
577
|
-
|
|
578
|
-
if (isBackward && focusOffset === 0 || !isBackward && focusOffset === focusNode.getTextContentSize()) {
|
|
579
|
-
const possibleNode = isBackward ? focusNode.getPreviousSibling() : focusNode.getNextSibling();
|
|
580
|
-
|
|
581
|
-
if (possibleNode === null) {
|
|
582
|
-
return resolveElement(focusNode.getParentOrThrow(), isBackward, focusNode.getIndexWithinParent() + (isBackward ? 0 : 1));
|
|
583
|
-
}
|
|
584
|
-
|
|
585
|
-
return possibleNode;
|
|
586
|
-
}
|
|
587
|
-
}
|
|
588
|
-
|
|
589
|
-
return null;
|
|
590
|
-
}
|
|
376
|
+
const CAN_USE_DOM = typeof window !== 'undefined' && typeof window.document !== 'undefined' && typeof window.document.createElement !== 'undefined';
|
|
591
377
|
|
|
592
378
|
/**
|
|
593
379
|
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
@@ -597,345 +383,23 @@ function getPossibleDecoratorNode(focus, isBackward) {
|
|
|
597
383
|
*
|
|
598
384
|
*
|
|
599
385
|
*/
|
|
386
|
+
const useLayoutEffectImpl = CAN_USE_DOM ? react.useLayoutEffect : react.useEffect;
|
|
387
|
+
var useLayoutEffect = useLayoutEffectImpl;
|
|
600
388
|
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
a: domNode => {
|
|
610
|
-
let node;
|
|
611
|
-
|
|
612
|
-
if (domNode instanceof HTMLAnchorElement) {
|
|
613
|
-
node = LinkNode.$createLinkNode(domNode.href);
|
|
614
|
-
} else {
|
|
615
|
-
node = lexical.$createTextNode(domNode.textContent);
|
|
616
|
-
}
|
|
617
|
-
|
|
618
|
-
return {
|
|
619
|
-
node
|
|
620
|
-
};
|
|
621
|
-
},
|
|
622
|
-
b: domNode => {
|
|
623
|
-
// $FlowFixMe[incompatible-type] domNode is a <b> since we matched it by nodeName
|
|
624
|
-
const b = domNode; // Google Docs wraps all copied HTML in a <b> with font-weight normal
|
|
625
|
-
|
|
626
|
-
const hasNormalFontWeight = b.style.fontWeight === 'normal';
|
|
627
|
-
return {
|
|
628
|
-
forChild: lexicalNode => {
|
|
629
|
-
if (lexical.$isTextNode(lexicalNode) && !hasNormalFontWeight) {
|
|
630
|
-
lexicalNode.toggleFormat('bold');
|
|
631
|
-
}
|
|
632
|
-
},
|
|
633
|
-
node: null
|
|
634
|
-
};
|
|
635
|
-
},
|
|
636
|
-
br: () => ({
|
|
637
|
-
node: lexical.$createLineBreakNode()
|
|
638
|
-
}),
|
|
639
|
-
div: domNode => {
|
|
640
|
-
// $FlowFixMe[incompatible-type] domNode is a <div> since we matched it by nodeName
|
|
641
|
-
const div = domNode;
|
|
642
|
-
return {
|
|
643
|
-
after: childLexicalNodes => {
|
|
644
|
-
const domParent = domNode.parentNode;
|
|
645
|
-
|
|
646
|
-
if (domParent != null && domNode !== domParent.lastChild) {
|
|
647
|
-
childLexicalNodes.push(lexical.$createLineBreakNode());
|
|
648
|
-
}
|
|
649
|
-
|
|
650
|
-
return childLexicalNodes;
|
|
651
|
-
},
|
|
652
|
-
node: isCodeElement(div) ? CodeNode.$createCodeNode() : null
|
|
653
|
-
};
|
|
654
|
-
},
|
|
655
|
-
em: domNode => {
|
|
656
|
-
return {
|
|
657
|
-
forChild: lexicalNode => {
|
|
658
|
-
if (lexical.$isTextNode(lexicalNode)) {
|
|
659
|
-
lexicalNode.toggleFormat('italic');
|
|
660
|
-
}
|
|
661
|
-
},
|
|
662
|
-
node: null
|
|
663
|
-
};
|
|
664
|
-
},
|
|
665
|
-
h1: () => ({
|
|
666
|
-
node: HeadingNode.$createHeadingNode('h1')
|
|
667
|
-
}),
|
|
668
|
-
h2: () => ({
|
|
669
|
-
node: HeadingNode.$createHeadingNode('h2')
|
|
670
|
-
}),
|
|
671
|
-
h3: () => ({
|
|
672
|
-
node: HeadingNode.$createHeadingNode('h3')
|
|
673
|
-
}),
|
|
674
|
-
h4: () => ({
|
|
675
|
-
node: HeadingNode.$createHeadingNode('h4')
|
|
676
|
-
}),
|
|
677
|
-
h5: () => ({
|
|
678
|
-
node: HeadingNode.$createHeadingNode('h5')
|
|
679
|
-
}),
|
|
680
|
-
i: domNode => {
|
|
681
|
-
return {
|
|
682
|
-
forChild: lexicalNode => {
|
|
683
|
-
if (lexical.$isTextNode(lexicalNode)) {
|
|
684
|
-
lexicalNode.toggleFormat('italic');
|
|
685
|
-
}
|
|
686
|
-
},
|
|
687
|
-
node: null
|
|
688
|
-
};
|
|
689
|
-
},
|
|
690
|
-
li: () => ({
|
|
691
|
-
node: list.$createListItemNode()
|
|
692
|
-
}),
|
|
693
|
-
ol: () => ({
|
|
694
|
-
node: list.$createListNode('ol')
|
|
695
|
-
}),
|
|
696
|
-
p: () => ({
|
|
697
|
-
node: lexical.$createParagraphNode()
|
|
698
|
-
}),
|
|
699
|
-
pre: domNode => ({
|
|
700
|
-
node: CodeNode.$createCodeNode()
|
|
701
|
-
}),
|
|
702
|
-
span: domNode => {
|
|
703
|
-
// $FlowFixMe[incompatible-type] domNode is a <span> since we matched it by nodeName
|
|
704
|
-
const span = domNode; // Google Docs uses span tags + font-weight for bold text
|
|
705
|
-
|
|
706
|
-
const hasBoldFontWeight = span.style.fontWeight === '700';
|
|
707
|
-
return {
|
|
708
|
-
forChild: lexicalNode => {
|
|
709
|
-
if (lexical.$isTextNode(lexicalNode) && hasBoldFontWeight) {
|
|
710
|
-
lexicalNode.toggleFormat('bold');
|
|
711
|
-
}
|
|
712
|
-
},
|
|
713
|
-
node: null
|
|
714
|
-
};
|
|
715
|
-
},
|
|
716
|
-
strong: domNode => {
|
|
717
|
-
return {
|
|
718
|
-
forChild: lexicalNode => {
|
|
719
|
-
if (lexical.$isTextNode(lexicalNode)) {
|
|
720
|
-
lexicalNode.toggleFormat('bold');
|
|
721
|
-
}
|
|
722
|
-
},
|
|
723
|
-
node: null
|
|
724
|
-
};
|
|
725
|
-
},
|
|
726
|
-
table: domNode => {
|
|
727
|
-
// $FlowFixMe[incompatible-type] domNode is a <table> since we matched it by nodeName
|
|
728
|
-
const table = domNode;
|
|
729
|
-
const isGitHubCodeTable = table.classList.contains('js-file-line-container');
|
|
730
|
-
return {
|
|
731
|
-
node: isGitHubCodeTable ? CodeNode.$createCodeNode() : null
|
|
732
|
-
};
|
|
733
|
-
},
|
|
734
|
-
td: domNode => {
|
|
735
|
-
// $FlowFixMe[incompatible-type] domNode is a <table> since we matched it by nodeName
|
|
736
|
-
const cell = domNode;
|
|
737
|
-
const isGitHubCodeCell = cell.classList.contains('js-file-line');
|
|
738
|
-
return {
|
|
739
|
-
after: childLexicalNodes => {
|
|
740
|
-
if (isGitHubCodeCell && cell.parentNode && cell.parentNode.nextSibling) {
|
|
741
|
-
// Append newline between code lines
|
|
742
|
-
childLexicalNodes.push(lexical.$createLineBreakNode());
|
|
743
|
-
}
|
|
744
|
-
|
|
745
|
-
return childLexicalNodes;
|
|
746
|
-
},
|
|
747
|
-
node: null
|
|
748
|
-
};
|
|
749
|
-
},
|
|
750
|
-
u: domNode => {
|
|
751
|
-
return {
|
|
752
|
-
forChild: lexicalNode => {
|
|
753
|
-
if (lexical.$isTextNode(lexicalNode)) {
|
|
754
|
-
lexicalNode.toggleFormat('underline');
|
|
755
|
-
}
|
|
756
|
-
},
|
|
757
|
-
node: null
|
|
758
|
-
};
|
|
759
|
-
},
|
|
760
|
-
ul: () => ({
|
|
761
|
-
node: list.$createListNode('ul')
|
|
762
|
-
})
|
|
763
|
-
};
|
|
764
|
-
|
|
765
|
-
function $generateNodes(nodeRange) {
|
|
766
|
-
const {
|
|
767
|
-
range,
|
|
768
|
-
nodeMap
|
|
769
|
-
} = nodeRange;
|
|
770
|
-
const parsedNodeMap = new Map(nodeMap);
|
|
771
|
-
const nodes = [];
|
|
772
|
-
|
|
773
|
-
for (let i = 0; i < range.length; i++) {
|
|
774
|
-
const key = range[i];
|
|
775
|
-
const parsedNode = parsedNodeMap.get(key);
|
|
776
|
-
|
|
777
|
-
if (parsedNode !== undefined) {
|
|
778
|
-
const node = lexical.$createNodeFromParse(parsedNode, parsedNodeMap);
|
|
779
|
-
nodes.push(node);
|
|
780
|
-
}
|
|
781
|
-
}
|
|
782
|
-
|
|
783
|
-
return nodes;
|
|
784
|
-
}
|
|
785
|
-
|
|
786
|
-
function $createNodesFromDOM(node, conversionMap, editor, forChildMap = new Map()) {
|
|
787
|
-
let lexicalNodes = [];
|
|
788
|
-
let currentLexicalNode = null;
|
|
789
|
-
const nodeName = node.nodeName.toLowerCase();
|
|
790
|
-
const customHtmlTransforms = editor._config.htmlTransforms || {};
|
|
791
|
-
const transformFunction = customHtmlTransforms[nodeName] || conversionMap[nodeName];
|
|
792
|
-
const transformOutput = transformFunction ? transformFunction(node) : null;
|
|
793
|
-
let postTransform = null;
|
|
794
|
-
|
|
795
|
-
if (transformOutput !== null) {
|
|
796
|
-
postTransform = transformOutput.after;
|
|
797
|
-
currentLexicalNode = transformOutput.node;
|
|
798
|
-
|
|
799
|
-
if (currentLexicalNode !== null) {
|
|
800
|
-
lexicalNodes.push(currentLexicalNode);
|
|
801
|
-
const forChildFunctions = Array.from(forChildMap.values());
|
|
802
|
-
|
|
803
|
-
for (let i = 0; i < forChildFunctions.length; i++) {
|
|
804
|
-
forChildFunctions[i](currentLexicalNode);
|
|
805
|
-
}
|
|
806
|
-
}
|
|
807
|
-
|
|
808
|
-
if (transformOutput.forChild != null) {
|
|
809
|
-
forChildMap.set(nodeName, transformOutput.forChild);
|
|
810
|
-
}
|
|
811
|
-
} // If the DOM node doesn't have a transformer, we don't know what
|
|
812
|
-
// to do with it but we still need to process any childNodes.
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
const children = node.childNodes;
|
|
816
|
-
let childLexicalNodes = [];
|
|
817
|
-
|
|
818
|
-
for (let i = 0; i < children.length; i++) {
|
|
819
|
-
childLexicalNodes.push(...$createNodesFromDOM(children[i], conversionMap, editor, forChildMap));
|
|
820
|
-
}
|
|
821
|
-
|
|
822
|
-
if (postTransform != null) {
|
|
823
|
-
childLexicalNodes = postTransform(childLexicalNodes);
|
|
824
|
-
}
|
|
825
|
-
|
|
826
|
-
if (currentLexicalNode == null) {
|
|
827
|
-
// If it hasn't been converted to a LexicalNode, we hoist its children
|
|
828
|
-
// up to the same level as it.
|
|
829
|
-
lexicalNodes = lexicalNodes.concat(childLexicalNodes);
|
|
830
|
-
} else {
|
|
831
|
-
if (lexical.$isElementNode(currentLexicalNode)) {
|
|
832
|
-
// If the current node is a ElementNode after conversion,
|
|
833
|
-
// we can append all the children to it.
|
|
834
|
-
currentLexicalNode.append(...childLexicalNodes);
|
|
835
|
-
}
|
|
836
|
-
}
|
|
837
|
-
|
|
838
|
-
return lexicalNodes;
|
|
839
|
-
}
|
|
840
|
-
|
|
841
|
-
function $generateNodesFromDOM(dom, conversionMap, editor) {
|
|
842
|
-
let lexicalNodes = [];
|
|
843
|
-
const elements = dom.body ? Array.from(dom.body.childNodes) : [];
|
|
844
|
-
const elementsLength = elements.length;
|
|
845
|
-
|
|
846
|
-
for (let i = 0; i < elementsLength; i++) {
|
|
847
|
-
const lexicalNode = $createNodesFromDOM(elements[i], conversionMap, editor);
|
|
848
|
-
|
|
849
|
-
if (lexicalNode !== null) {
|
|
850
|
-
lexicalNodes = lexicalNodes.concat(lexicalNode);
|
|
851
|
-
}
|
|
852
|
-
}
|
|
853
|
-
|
|
854
|
-
return lexicalNodes;
|
|
855
|
-
}
|
|
856
|
-
|
|
857
|
-
function $insertDataTransferForRichText(dataTransfer, selection, editor) {
|
|
858
|
-
const lexicalNodesString = dataTransfer.getData('application/x-lexical-editor');
|
|
859
|
-
|
|
860
|
-
if (lexicalNodesString) {
|
|
861
|
-
const namespace = editor._config.namespace;
|
|
862
|
-
|
|
863
|
-
try {
|
|
864
|
-
const lexicalClipboardData = JSON.parse(lexicalNodesString);
|
|
865
|
-
|
|
866
|
-
if (lexicalClipboardData.namespace === namespace) {
|
|
867
|
-
const nodeRange = lexicalClipboardData.state;
|
|
868
|
-
const nodes = $generateNodes(nodeRange);
|
|
869
|
-
selection.insertNodes(nodes);
|
|
870
|
-
return;
|
|
871
|
-
}
|
|
872
|
-
} catch (e) {// Malformed, missing nodes..
|
|
873
|
-
}
|
|
874
|
-
}
|
|
875
|
-
|
|
876
|
-
const textHtmlMimeType = 'text/html';
|
|
877
|
-
const htmlString = dataTransfer.getData(textHtmlMimeType);
|
|
878
|
-
|
|
879
|
-
if (htmlString) {
|
|
880
|
-
const parser = new DOMParser();
|
|
881
|
-
const dom = parser.parseFromString(htmlString, textHtmlMimeType);
|
|
882
|
-
const nodes = $generateNodesFromDOM(dom, DOM_NODE_NAME_TO_LEXICAL_NODE, editor); // Wrap text and inline nodes in paragraph nodes so we have all blocks at the top-level
|
|
883
|
-
|
|
884
|
-
const topLevelBlocks = [];
|
|
885
|
-
let currentBlock = null;
|
|
886
|
-
|
|
887
|
-
for (let i = 0; i < nodes.length; i++) {
|
|
888
|
-
const node = nodes[i];
|
|
889
|
-
|
|
890
|
-
if (!lexical.$isElementNode(node) || node.isInline()) {
|
|
891
|
-
if (currentBlock === null) {
|
|
892
|
-
currentBlock = lexical.$createParagraphNode();
|
|
893
|
-
topLevelBlocks.push(currentBlock);
|
|
894
|
-
}
|
|
895
|
-
|
|
896
|
-
if (currentBlock !== null) {
|
|
897
|
-
currentBlock.append(node);
|
|
898
|
-
}
|
|
899
|
-
} else {
|
|
900
|
-
topLevelBlocks.push(node);
|
|
901
|
-
currentBlock = null;
|
|
902
|
-
}
|
|
903
|
-
}
|
|
904
|
-
|
|
905
|
-
selection.insertNodes(topLevelBlocks);
|
|
906
|
-
return;
|
|
907
|
-
}
|
|
908
|
-
|
|
909
|
-
$insertDataTransferForPlainText(dataTransfer, selection);
|
|
910
|
-
}
|
|
911
|
-
function $insertDataTransferForPlainText(dataTransfer, selection) {
|
|
912
|
-
const text = dataTransfer.getData('text/plain');
|
|
913
|
-
|
|
914
|
-
if (text != null) {
|
|
915
|
-
selection.insertRawText(text);
|
|
916
|
-
}
|
|
917
|
-
}
|
|
918
|
-
function $shouldOverrideDefaultCharacterSelection(selection, isBackward) {
|
|
919
|
-
const possibleNode = getPossibleDecoratorNode(selection.focus, isBackward);
|
|
920
|
-
return lexical.$isDecoratorNode(possibleNode) && !possibleNode.isIsolated();
|
|
921
|
-
}
|
|
922
|
-
function onPasteForRichText(event, editor) {
|
|
923
|
-
event.preventDefault();
|
|
924
|
-
editor.update(() => {
|
|
925
|
-
const selection = lexical.$getSelection();
|
|
926
|
-
const clipboardData = event.clipboardData;
|
|
927
|
-
|
|
928
|
-
if (clipboardData != null && selection !== null) {
|
|
929
|
-
$insertDataTransferForRichText(clipboardData, selection, editor);
|
|
930
|
-
}
|
|
931
|
-
});
|
|
932
|
-
}
|
|
389
|
+
/**
|
|
390
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
391
|
+
*
|
|
392
|
+
* This source code is licensed under the MIT license found in the
|
|
393
|
+
* LICENSE file in the root directory of this source tree.
|
|
394
|
+
*
|
|
395
|
+
*
|
|
396
|
+
*/
|
|
933
397
|
function onCutForRichText(event, editor) {
|
|
934
398
|
onCopyForRichText(event, editor);
|
|
935
399
|
editor.update(() => {
|
|
936
400
|
const selection = lexical.$getSelection();
|
|
937
401
|
|
|
938
|
-
if (selection
|
|
402
|
+
if (lexical.$isRangeSelection(selection)) {
|
|
939
403
|
selection.removeText();
|
|
940
404
|
}
|
|
941
405
|
});
|
|
@@ -948,41 +412,33 @@ function onCopyForRichText(event, editor) {
|
|
|
948
412
|
|
|
949
413
|
if (selection !== null) {
|
|
950
414
|
if (clipboardData != null) {
|
|
951
|
-
const
|
|
415
|
+
const htmlString = clipboard.getHtmlContent(editor);
|
|
416
|
+
const lexicalString = clipboard.$getLexicalContent(editor);
|
|
952
417
|
|
|
953
|
-
if (
|
|
954
|
-
|
|
418
|
+
if (htmlString !== null) {
|
|
419
|
+
clipboardData.setData('text/html', htmlString);
|
|
955
420
|
}
|
|
956
421
|
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
if (range) {
|
|
960
|
-
const container = document.createElement('div');
|
|
961
|
-
const frag = range.cloneContents();
|
|
962
|
-
container.appendChild(frag);
|
|
963
|
-
clipboardData.setData('text/html', container.innerHTML);
|
|
422
|
+
if (lexicalString !== null) {
|
|
423
|
+
clipboardData.setData('application/x-lexical-editor', lexicalString);
|
|
964
424
|
}
|
|
965
425
|
|
|
966
426
|
clipboardData.setData('text/plain', selection.getTextContent());
|
|
967
|
-
const namespace = editor._config.namespace;
|
|
968
|
-
clipboardData.setData('application/x-lexical-editor', JSON.stringify({
|
|
969
|
-
namespace,
|
|
970
|
-
state: $cloneContents(selection)
|
|
971
|
-
}));
|
|
972
427
|
}
|
|
973
428
|
}
|
|
974
429
|
});
|
|
975
430
|
}
|
|
431
|
+
function onPasteForRichText(event, editor) {
|
|
432
|
+
event.preventDefault();
|
|
433
|
+
editor.update(() => {
|
|
434
|
+
const selection = lexical.$getSelection();
|
|
435
|
+
const clipboardData = event.clipboardData;
|
|
976
436
|
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
*
|
|
983
|
-
*
|
|
984
|
-
*/
|
|
985
|
-
const CAN_USE_DOM = typeof window !== 'undefined' && typeof window.document !== 'undefined' && typeof window.document.createElement !== 'undefined';
|
|
437
|
+
if (clipboardData != null && lexical.$isRangeSelection(selection)) {
|
|
438
|
+
clipboard.$insertDataTransferForRichText(clipboardData, selection, editor);
|
|
439
|
+
}
|
|
440
|
+
});
|
|
441
|
+
}
|
|
986
442
|
|
|
987
443
|
/**
|
|
988
444
|
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
@@ -992,8 +448,53 @@ const CAN_USE_DOM = typeof window !== 'undefined' && typeof window.document !==
|
|
|
992
448
|
*
|
|
993
449
|
*
|
|
994
450
|
*/
|
|
995
|
-
|
|
996
|
-
|
|
451
|
+
// Convoluted logic to make this work with Flow. Order matters.
|
|
452
|
+
const options = {
|
|
453
|
+
tag: 'history-merge'
|
|
454
|
+
};
|
|
455
|
+
const setEditorOptions = options;
|
|
456
|
+
const updateOptions = options;
|
|
457
|
+
function initializeEditor(editor, initialEditorState) {
|
|
458
|
+
if (initialEditorState === null) {
|
|
459
|
+
return;
|
|
460
|
+
} else if (initialEditorState === undefined) {
|
|
461
|
+
editor.update(() => {
|
|
462
|
+
const root = lexical.$getRoot();
|
|
463
|
+
const firstChild = root.getFirstChild();
|
|
464
|
+
|
|
465
|
+
if (firstChild === null) {
|
|
466
|
+
const paragraph = lexical.$createParagraphNode();
|
|
467
|
+
root.append(paragraph);
|
|
468
|
+
const activeElement = document.activeElement;
|
|
469
|
+
|
|
470
|
+
if (lexical.$getSelection() !== null || activeElement !== null && activeElement === editor.getRootElement()) {
|
|
471
|
+
paragraph.select();
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
}, updateOptions);
|
|
475
|
+
} else if (initialEditorState !== null) {
|
|
476
|
+
switch (typeof initialEditorState) {
|
|
477
|
+
case 'string':
|
|
478
|
+
{
|
|
479
|
+
const parsedEditorState = editor.parseEditorState(initialEditorState);
|
|
480
|
+
editor.setEditorState(parsedEditorState, setEditorOptions);
|
|
481
|
+
break;
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
case 'object':
|
|
485
|
+
{
|
|
486
|
+
editor.setEditorState(initialEditorState, setEditorOptions);
|
|
487
|
+
break;
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
case 'function':
|
|
491
|
+
{
|
|
492
|
+
editor.update(initialEditorState, updateOptions);
|
|
493
|
+
break;
|
|
494
|
+
}
|
|
495
|
+
}
|
|
496
|
+
}
|
|
497
|
+
}
|
|
997
498
|
|
|
998
499
|
/**
|
|
999
500
|
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
@@ -1034,7 +535,7 @@ function useLexicalDragonSupport(editor) {
|
|
|
1034
535
|
editor.update(() => {
|
|
1035
536
|
const selection = lexical.$getSelection();
|
|
1036
537
|
|
|
1037
|
-
if (selection
|
|
538
|
+
if (lexical.$isRangeSelection(selection)) {
|
|
1038
539
|
const anchor = selection.anchor;
|
|
1039
540
|
let anchorNode = anchor.getNode();
|
|
1040
541
|
let setSelStart = 0;
|
|
@@ -1091,13 +592,17 @@ function useLexicalDragonSupport(editor) {
|
|
|
1091
592
|
*
|
|
1092
593
|
*
|
|
1093
594
|
*/
|
|
1094
|
-
|
|
1095
|
-
function useRichTextSetup(editor) {
|
|
595
|
+
function useRichTextSetup(editor, initialEditorState) {
|
|
1096
596
|
useLayoutEffect(() => {
|
|
1097
597
|
const removeListener = editor.addListener('command', (type, payload) => {
|
|
1098
598
|
const selection = lexical.$getSelection();
|
|
1099
599
|
|
|
1100
|
-
if (
|
|
600
|
+
if (type === 'click' && lexical.$isNodeSelection(selection)) {
|
|
601
|
+
selection.clear();
|
|
602
|
+
return true;
|
|
603
|
+
}
|
|
604
|
+
|
|
605
|
+
if (!lexical.$isRangeSelection(selection)) {
|
|
1101
606
|
return false;
|
|
1102
607
|
}
|
|
1103
608
|
|
|
@@ -1133,7 +638,7 @@ function useRichTextSetup(editor) {
|
|
|
1133
638
|
const dataTransfer = eventOrText.dataTransfer;
|
|
1134
639
|
|
|
1135
640
|
if (dataTransfer != null) {
|
|
1136
|
-
|
|
641
|
+
clipboard.$insertDataTransferForRichText(dataTransfer, selection, editor);
|
|
1137
642
|
} else {
|
|
1138
643
|
const data = eventOrText.data;
|
|
1139
644
|
|
|
@@ -1326,9 +831,10 @@ function useRichTextSetup(editor) {
|
|
|
1326
831
|
}
|
|
1327
832
|
|
|
1328
833
|
return false;
|
|
1329
|
-
},
|
|
1330
|
-
editor
|
|
1331
|
-
return removeListener;
|
|
834
|
+
}, 0);
|
|
835
|
+
initializeEditor(editor, initialEditorState);
|
|
836
|
+
return removeListener; // We only do this for init
|
|
837
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
1332
838
|
}, [editor]);
|
|
1333
839
|
useLexicalDragonSupport(editor);
|
|
1334
840
|
}
|
|
@@ -1341,8 +847,8 @@ function useRichTextSetup(editor) {
|
|
|
1341
847
|
*
|
|
1342
848
|
*
|
|
1343
849
|
*/
|
|
1344
|
-
function useLexicalRichText(editor, externalHistoryState) {
|
|
1345
|
-
useRichTextSetup(editor);
|
|
850
|
+
function useLexicalRichText(editor, externalHistoryState, initialEditorState) {
|
|
851
|
+
useRichTextSetup(editor, initialEditorState);
|
|
1346
852
|
useLexicalHistory(editor, externalHistoryState);
|
|
1347
853
|
}
|
|
1348
854
|
|