lexical 0.6.4 → 0.7.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/Lexical.dev.js +682 -369
- package/Lexical.js.flow +22 -9
- package/Lexical.prod.js +187 -180
- package/LexicalConstants.d.ts +2 -0
- package/LexicalEditor.d.ts +3 -1
- package/LexicalGC.d.ts +3 -1
- package/LexicalNode.d.ts +3 -4
- package/LexicalReconciler.d.ts +3 -1
- package/LexicalSelection.d.ts +1 -1
- package/LexicalUtils.d.ts +5 -2
- package/LexicalVersion.d.ts +1 -1
- package/index.d.ts +2 -2
- package/nodes/LexicalElementNode.d.ts +2 -4
- package/nodes/LexicalLineBreakNode.d.ts +1 -1
- package/nodes/LexicalParagraphNode.d.ts +3 -3
- package/nodes/LexicalTextNode.d.ts +4 -0
- package/package.json +1 -1
package/Lexical.dev.js
CHANGED
|
@@ -95,8 +95,8 @@ const CAN_USE_BEFORE_INPUT = CAN_USE_DOM && 'InputEvent' in window && !documentM
|
|
|
95
95
|
const IS_SAFARI = CAN_USE_DOM && /Version\/[\d.]+.*Safari/.test(navigator.userAgent);
|
|
96
96
|
const IS_IOS = CAN_USE_DOM && /iPad|iPhone|iPod/.test(navigator.userAgent) && !window.MSStream; // Keep these in case we need to use them in the future.
|
|
97
97
|
// export const IS_WINDOWS: boolean = CAN_USE_DOM && /Win/.test(navigator.platform);
|
|
98
|
-
|
|
99
|
-
// export const canUseTextInputEvent: boolean = CAN_USE_DOM && 'TextEvent' in window && !documentMode;
|
|
98
|
+
|
|
99
|
+
const IS_CHROME = CAN_USE_DOM && /^(?=.*Chrome).*/i.test(navigator.userAgent); // export const canUseTextInputEvent: boolean = CAN_USE_DOM && 'TextEvent' in window && !documentMode;
|
|
100
100
|
|
|
101
101
|
/**
|
|
102
102
|
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
@@ -133,7 +133,9 @@ const IS_UNMERGEABLE = 1 << 1; // Element node formatting
|
|
|
133
133
|
const IS_ALIGN_LEFT = 1;
|
|
134
134
|
const IS_ALIGN_CENTER = 2;
|
|
135
135
|
const IS_ALIGN_RIGHT = 3;
|
|
136
|
-
const IS_ALIGN_JUSTIFY = 4;
|
|
136
|
+
const IS_ALIGN_JUSTIFY = 4;
|
|
137
|
+
const IS_ALIGN_START = 5;
|
|
138
|
+
const IS_ALIGN_END = 6; // Reconciliation
|
|
137
139
|
|
|
138
140
|
const NON_BREAKING_SPACE = '\u00A0';
|
|
139
141
|
const ZERO_WIDTH_SPACE = '\u200b'; // For iOS/Safari we use a non breaking space, otherwise the cursor appears
|
|
@@ -165,15 +167,19 @@ const DETAIL_TYPE_TO_DETAIL = {
|
|
|
165
167
|
};
|
|
166
168
|
const ELEMENT_TYPE_TO_FORMAT = {
|
|
167
169
|
center: IS_ALIGN_CENTER,
|
|
170
|
+
end: IS_ALIGN_END,
|
|
168
171
|
justify: IS_ALIGN_JUSTIFY,
|
|
169
172
|
left: IS_ALIGN_LEFT,
|
|
170
|
-
right: IS_ALIGN_RIGHT
|
|
173
|
+
right: IS_ALIGN_RIGHT,
|
|
174
|
+
start: IS_ALIGN_START
|
|
171
175
|
};
|
|
172
176
|
const ELEMENT_FORMAT_TO_TYPE = {
|
|
173
177
|
[IS_ALIGN_CENTER]: 'center',
|
|
178
|
+
[IS_ALIGN_END]: 'end',
|
|
174
179
|
[IS_ALIGN_JUSTIFY]: 'justify',
|
|
175
180
|
[IS_ALIGN_LEFT]: 'left',
|
|
176
|
-
[IS_ALIGN_RIGHT]: 'right'
|
|
181
|
+
[IS_ALIGN_RIGHT]: 'right',
|
|
182
|
+
[IS_ALIGN_START]: 'start'
|
|
177
183
|
};
|
|
178
184
|
const TEXT_MODE_TO_TYPE = {
|
|
179
185
|
normal: IS_NORMAL,
|
|
@@ -266,6 +272,7 @@ function $flushMutations$1(editor, mutations, observer) {
|
|
|
266
272
|
// actually "on screen".
|
|
267
273
|
|
|
268
274
|
const currentEditorState = editor._editorState;
|
|
275
|
+
const blockCursorElement = editor._blockCursorElement;
|
|
269
276
|
let shouldRevertSelection = false;
|
|
270
277
|
let possibleTextForFirefoxPaste = '';
|
|
271
278
|
|
|
@@ -298,7 +305,7 @@ function $flushMutations$1(editor, mutations, observer) {
|
|
|
298
305
|
const node = getNodeFromDOMNode(addedDOM);
|
|
299
306
|
const parentDOM = addedDOM.parentNode;
|
|
300
307
|
|
|
301
|
-
if (parentDOM != null && node === null && (addedDOM.nodeName !== 'BR' || !isManagedLineBreak(addedDOM, parentDOM, editor))) {
|
|
308
|
+
if (parentDOM != null && addedDOM !== blockCursorElement && node === null && (addedDOM.nodeName !== 'BR' || !isManagedLineBreak(addedDOM, parentDOM, editor))) {
|
|
302
309
|
if (IS_FIREFOX) {
|
|
303
310
|
const possibleText = addedDOM.innerText || addedDOM.nodeValue;
|
|
304
311
|
|
|
@@ -320,7 +327,7 @@ function $flushMutations$1(editor, mutations, observer) {
|
|
|
320
327
|
for (let s = 0; s < removedDOMsLength; s++) {
|
|
321
328
|
const removedDOM = removedDOMs[s];
|
|
322
329
|
|
|
323
|
-
if (removedDOM.nodeName === 'BR' && isManagedLineBreak(removedDOM, targetDOM, editor)) {
|
|
330
|
+
if (removedDOM.nodeName === 'BR' && isManagedLineBreak(removedDOM, targetDOM, editor) || blockCursorElement === removedDOM) {
|
|
324
331
|
targetDOM.appendChild(removedDOM);
|
|
325
332
|
unremovedBRs++;
|
|
326
333
|
}
|
|
@@ -344,7 +351,7 @@ function $flushMutations$1(editor, mutations, observer) {
|
|
|
344
351
|
if (badDOMTargets.size > 0) {
|
|
345
352
|
for (const [targetDOM, targetNode] of badDOMTargets) {
|
|
346
353
|
if ($isElementNode(targetNode)) {
|
|
347
|
-
const childKeys = targetNode.
|
|
354
|
+
const childKeys = targetNode.getChildrenKeys();
|
|
348
355
|
let currentDOM = targetDOM.firstChild;
|
|
349
356
|
|
|
350
357
|
for (let s = 0; s < childKeys.length; s++) {
|
|
@@ -455,19 +462,18 @@ const scheduleMicroTask = typeof queueMicrotask === 'function' ? queueMicrotask
|
|
|
455
462
|
};
|
|
456
463
|
function $isSelectionCapturedInDecorator(node) {
|
|
457
464
|
return $isDecoratorNode($getNearestNodeFromDOMNode(node));
|
|
458
|
-
}
|
|
459
|
-
|
|
465
|
+
}
|
|
460
466
|
function isSelectionCapturedInDecoratorInput(anchorDOM) {
|
|
461
467
|
const activeElement = document.activeElement;
|
|
462
468
|
const nodeName = activeElement !== null ? activeElement.nodeName : null;
|
|
463
|
-
return
|
|
469
|
+
return $isDecoratorNode($getNearestNodeFromDOMNode(anchorDOM)) && (nodeName === 'INPUT' || nodeName === 'TEXTAREA');
|
|
464
470
|
}
|
|
465
471
|
function isSelectionWithinEditor(editor, anchorDOM, focusDOM) {
|
|
466
472
|
const rootElement = editor.getRootElement();
|
|
467
473
|
|
|
468
474
|
try {
|
|
469
475
|
return rootElement !== null && rootElement.contains(anchorDOM) && rootElement.contains(focusDOM) && // Ignore if selection is within nested editor
|
|
470
|
-
anchorDOM !== null && isSelectionCapturedInDecoratorInput(anchorDOM) && getNearestEditorFromDOMNode(anchorDOM) === editor;
|
|
476
|
+
anchorDOM !== null && !isSelectionCapturedInDecoratorInput(anchorDOM) && getNearestEditorFromDOMNode(anchorDOM) === editor;
|
|
471
477
|
} catch (error) {
|
|
472
478
|
return false;
|
|
473
479
|
}
|
|
@@ -585,22 +591,61 @@ function internalMarkParentElementsAsDirty(parentKey, nodeMap, dirtyElements) {
|
|
|
585
591
|
}
|
|
586
592
|
}
|
|
587
593
|
|
|
588
|
-
function removeFromParent(
|
|
589
|
-
const oldParent =
|
|
594
|
+
function removeFromParent(node) {
|
|
595
|
+
const oldParent = node.getParent();
|
|
590
596
|
|
|
591
597
|
if (oldParent !== null) {
|
|
598
|
+
const writableNode = node.getWritable();
|
|
592
599
|
const writableParent = oldParent.getWritable();
|
|
593
|
-
const
|
|
594
|
-
const
|
|
600
|
+
const prevSibling = node.getPreviousSibling();
|
|
601
|
+
const nextSibling = node.getNextSibling(); // TODO: this function duplicates a bunch of operations, can be simplified.
|
|
595
602
|
|
|
596
|
-
if (
|
|
597
|
-
{
|
|
598
|
-
|
|
603
|
+
if (prevSibling === null) {
|
|
604
|
+
if (nextSibling !== null) {
|
|
605
|
+
const writableNextSibling = nextSibling.getWritable();
|
|
606
|
+
writableParent.__first = nextSibling.__key;
|
|
607
|
+
writableNextSibling.__prev = null;
|
|
608
|
+
} else {
|
|
609
|
+
writableParent.__first = null;
|
|
610
|
+
}
|
|
611
|
+
} else {
|
|
612
|
+
const writablePrevSibling = prevSibling.getWritable();
|
|
613
|
+
|
|
614
|
+
if (nextSibling !== null) {
|
|
615
|
+
const writableNextSibling = nextSibling.getWritable();
|
|
616
|
+
writableNextSibling.__prev = writablePrevSibling.__key;
|
|
617
|
+
writablePrevSibling.__next = writableNextSibling.__key;
|
|
618
|
+
} else {
|
|
619
|
+
writablePrevSibling.__next = null;
|
|
620
|
+
}
|
|
621
|
+
|
|
622
|
+
writableNode.__prev = null;
|
|
623
|
+
}
|
|
624
|
+
|
|
625
|
+
if (nextSibling === null) {
|
|
626
|
+
if (prevSibling !== null) {
|
|
627
|
+
const writablePrevSibling = prevSibling.getWritable();
|
|
628
|
+
writableParent.__last = prevSibling.__key;
|
|
629
|
+
writablePrevSibling.__next = null;
|
|
630
|
+
} else {
|
|
631
|
+
writableParent.__last = null;
|
|
632
|
+
}
|
|
633
|
+
} else {
|
|
634
|
+
const writableNextSibling = nextSibling.getWritable();
|
|
635
|
+
|
|
636
|
+
if (prevSibling !== null) {
|
|
637
|
+
const writablePrevSibling = prevSibling.getWritable();
|
|
638
|
+
writablePrevSibling.__next = writableNextSibling.__key;
|
|
639
|
+
writableNextSibling.__prev = writablePrevSibling.__key;
|
|
640
|
+
} else {
|
|
641
|
+
writableNextSibling.__prev = null;
|
|
599
642
|
}
|
|
643
|
+
|
|
644
|
+
writableNode.__next = null;
|
|
600
645
|
}
|
|
601
646
|
|
|
602
|
-
|
|
603
|
-
|
|
647
|
+
writableParent.__size--;
|
|
648
|
+
writableNode.__parent = null;
|
|
604
649
|
}
|
|
605
650
|
} // Never use this function directly! It will break
|
|
606
651
|
// the cloning heuristic. Instead use node.getWritable().
|
|
@@ -1156,8 +1201,15 @@ function setMutatedNode(mutatedNodes, registeredNodes, mutationListeners, node,
|
|
|
1156
1201
|
mutatedNodes.set(klass, mutatedNodesByType);
|
|
1157
1202
|
}
|
|
1158
1203
|
|
|
1159
|
-
|
|
1160
|
-
|
|
1204
|
+
const prevMutation = mutatedNodesByType.get(nodeKey); // If the node has already been "destroyed", yet we are
|
|
1205
|
+
// re-making it, then this means a move likely happened.
|
|
1206
|
+
// We should change the mutation to be that of "updated"
|
|
1207
|
+
// instead.
|
|
1208
|
+
|
|
1209
|
+
const isMove = prevMutation === 'destroyed' && mutation === 'created';
|
|
1210
|
+
|
|
1211
|
+
if (prevMutation === undefined || isMove) {
|
|
1212
|
+
mutatedNodesByType.set(nodeKey, isMove ? 'updated' : mutation);
|
|
1161
1213
|
}
|
|
1162
1214
|
}
|
|
1163
1215
|
function $nodesOfType(klass) {
|
|
@@ -1194,7 +1246,7 @@ function resolveElement(element, isBackward, focusOffset) {
|
|
|
1194
1246
|
return block.getChildAtIndex(isBackward ? offset - 1 : offset);
|
|
1195
1247
|
}
|
|
1196
1248
|
|
|
1197
|
-
function $
|
|
1249
|
+
function $getAdjacentNode(focus, isBackward) {
|
|
1198
1250
|
const focusOffset = focus.offset;
|
|
1199
1251
|
|
|
1200
1252
|
if (focus.type === 'element') {
|
|
@@ -1425,6 +1477,96 @@ function errorOnInsertTextNodeOnRoot(node, insertNode) {
|
|
|
1425
1477
|
}
|
|
1426
1478
|
}
|
|
1427
1479
|
|
|
1480
|
+
function createBlockCursorElement(editorConfig) {
|
|
1481
|
+
const theme = editorConfig.theme;
|
|
1482
|
+
const element = document.createElement('div');
|
|
1483
|
+
element.contentEditable = 'false';
|
|
1484
|
+
element.setAttribute('data-lexical-cursor', 'true');
|
|
1485
|
+
let blockCursorTheme = theme.blockCursor;
|
|
1486
|
+
|
|
1487
|
+
if (blockCursorTheme !== undefined) {
|
|
1488
|
+
if (typeof blockCursorTheme === 'string') {
|
|
1489
|
+
const classNamesArr = blockCursorTheme.split(' '); // @ts-expect-error: intentional
|
|
1490
|
+
|
|
1491
|
+
blockCursorTheme = theme.blockCursor = classNamesArr;
|
|
1492
|
+
}
|
|
1493
|
+
|
|
1494
|
+
if (blockCursorTheme !== undefined) {
|
|
1495
|
+
element.classList.add(...blockCursorTheme);
|
|
1496
|
+
}
|
|
1497
|
+
}
|
|
1498
|
+
|
|
1499
|
+
return element;
|
|
1500
|
+
}
|
|
1501
|
+
|
|
1502
|
+
function needsBlockCursor(node) {
|
|
1503
|
+
return ($isDecoratorNode(node) || $isElementNode(node) && !node.canBeEmpty()) && !node.isInline();
|
|
1504
|
+
}
|
|
1505
|
+
|
|
1506
|
+
function removeDOMBlockCursorElement(blockCursorElement, editor, rootElement) {
|
|
1507
|
+
rootElement.style.removeProperty('caret-color');
|
|
1508
|
+
editor._blockCursorElement = null;
|
|
1509
|
+
const parentElement = blockCursorElement.parentElement;
|
|
1510
|
+
|
|
1511
|
+
if (parentElement !== null) {
|
|
1512
|
+
parentElement.removeChild(blockCursorElement);
|
|
1513
|
+
}
|
|
1514
|
+
}
|
|
1515
|
+
function updateDOMBlockCursorElement(editor, rootElement, nextSelection) {
|
|
1516
|
+
let blockCursorElement = editor._blockCursorElement;
|
|
1517
|
+
|
|
1518
|
+
if ($isRangeSelection(nextSelection) && nextSelection.isCollapsed() && nextSelection.anchor.type === 'element' && rootElement.contains(document.activeElement)) {
|
|
1519
|
+
const anchor = nextSelection.anchor;
|
|
1520
|
+
const elementNode = anchor.getNode();
|
|
1521
|
+
const offset = anchor.offset;
|
|
1522
|
+
const elementNodeSize = elementNode.getChildrenSize();
|
|
1523
|
+
let isBlockCursor = false;
|
|
1524
|
+
let insertBeforeElement = null;
|
|
1525
|
+
|
|
1526
|
+
if (offset === elementNodeSize) {
|
|
1527
|
+
const child = elementNode.getChildAtIndex(offset - 1);
|
|
1528
|
+
|
|
1529
|
+
if (needsBlockCursor(child)) {
|
|
1530
|
+
isBlockCursor = true;
|
|
1531
|
+
}
|
|
1532
|
+
} else {
|
|
1533
|
+
const child = elementNode.getChildAtIndex(offset);
|
|
1534
|
+
|
|
1535
|
+
if (needsBlockCursor(child)) {
|
|
1536
|
+
const sibling = child.getPreviousSibling();
|
|
1537
|
+
|
|
1538
|
+
if (sibling === null || needsBlockCursor(sibling)) {
|
|
1539
|
+
isBlockCursor = true;
|
|
1540
|
+
insertBeforeElement = editor.getElementByKey(child.__key);
|
|
1541
|
+
}
|
|
1542
|
+
}
|
|
1543
|
+
}
|
|
1544
|
+
|
|
1545
|
+
if (isBlockCursor) {
|
|
1546
|
+
const elementDOM = editor.getElementByKey(elementNode.__key);
|
|
1547
|
+
|
|
1548
|
+
if (blockCursorElement === null) {
|
|
1549
|
+
editor._blockCursorElement = blockCursorElement = createBlockCursorElement(editor._config);
|
|
1550
|
+
}
|
|
1551
|
+
|
|
1552
|
+
rootElement.style.caretColor = 'transparent';
|
|
1553
|
+
|
|
1554
|
+
if (insertBeforeElement === null) {
|
|
1555
|
+
elementDOM.appendChild(blockCursorElement);
|
|
1556
|
+
} else {
|
|
1557
|
+
elementDOM.insertBefore(blockCursorElement, insertBeforeElement);
|
|
1558
|
+
}
|
|
1559
|
+
|
|
1560
|
+
return;
|
|
1561
|
+
}
|
|
1562
|
+
} // Remove cursor
|
|
1563
|
+
|
|
1564
|
+
|
|
1565
|
+
if (blockCursorElement !== null) {
|
|
1566
|
+
removeDOMBlockCursorElement(blockCursorElement, editor, rootElement);
|
|
1567
|
+
}
|
|
1568
|
+
}
|
|
1569
|
+
|
|
1428
1570
|
/**
|
|
1429
1571
|
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
1430
1572
|
*
|
|
@@ -1451,12 +1593,10 @@ function $garbageCollectDetachedDecorators(editor, pendingEditorState) {
|
|
|
1451
1593
|
}
|
|
1452
1594
|
|
|
1453
1595
|
function $garbageCollectDetachedDeepChildNodes(node, parentKey, prevNodeMap, nodeMap, dirtyNodes) {
|
|
1454
|
-
|
|
1455
|
-
const childrenLength = children.length;
|
|
1596
|
+
let child = node.getFirstChild();
|
|
1456
1597
|
|
|
1457
|
-
|
|
1458
|
-
const childKey =
|
|
1459
|
-
const child = nodeMap.get(childKey);
|
|
1598
|
+
while (child !== null) {
|
|
1599
|
+
const childKey = child.__key;
|
|
1460
1600
|
|
|
1461
1601
|
if (child !== undefined && child.__parent === parentKey) {
|
|
1462
1602
|
if ($isElementNode(child)) {
|
|
@@ -1471,6 +1611,8 @@ function $garbageCollectDetachedDeepChildNodes(node, parentKey, prevNodeMap, nod
|
|
|
1471
1611
|
|
|
1472
1612
|
nodeMap.delete(childKey);
|
|
1473
1613
|
}
|
|
1614
|
+
|
|
1615
|
+
child = child.isAttached() ? child.getNextSibling() : null;
|
|
1474
1616
|
}
|
|
1475
1617
|
}
|
|
1476
1618
|
|
|
@@ -1637,7 +1779,10 @@ function destroyNode(key, parentDOM) {
|
|
|
1637
1779
|
|
|
1638
1780
|
if (parentDOM !== null) {
|
|
1639
1781
|
const dom = getPrevElementByKeyOrThrow(key);
|
|
1640
|
-
|
|
1782
|
+
|
|
1783
|
+
if (dom.parentNode === parentDOM) {
|
|
1784
|
+
parentDOM.removeChild(dom);
|
|
1785
|
+
}
|
|
1641
1786
|
} // This logic is really important, otherwise we will leak DOM nodes
|
|
1642
1787
|
// when their corresponding LexicalNodes are removed from the editor state.
|
|
1643
1788
|
|
|
@@ -1647,7 +1792,7 @@ function destroyNode(key, parentDOM) {
|
|
|
1647
1792
|
}
|
|
1648
1793
|
|
|
1649
1794
|
if ($isElementNode(node)) {
|
|
1650
|
-
const children = node
|
|
1795
|
+
const children = createChildrenArray(node, activePrevNodeMap);
|
|
1651
1796
|
destroyChildren(children, 0, children.length - 1, null);
|
|
1652
1797
|
}
|
|
1653
1798
|
|
|
@@ -1689,6 +1834,10 @@ function setElementFormat(dom, format) {
|
|
|
1689
1834
|
setTextAlign(domStyle, 'right');
|
|
1690
1835
|
} else if (format === IS_ALIGN_JUSTIFY) {
|
|
1691
1836
|
setTextAlign(domStyle, 'justify');
|
|
1837
|
+
} else if (format === IS_ALIGN_START) {
|
|
1838
|
+
setTextAlign(domStyle, 'start');
|
|
1839
|
+
} else if (format === IS_ALIGN_END) {
|
|
1840
|
+
setTextAlign(domStyle, 'end');
|
|
1692
1841
|
}
|
|
1693
1842
|
}
|
|
1694
1843
|
|
|
@@ -1714,16 +1863,15 @@ function createNode(key, parentDOM, insertDOM) {
|
|
|
1714
1863
|
|
|
1715
1864
|
if ($isElementNode(node)) {
|
|
1716
1865
|
const indent = node.__indent;
|
|
1866
|
+
const childrenSize = node.__size;
|
|
1717
1867
|
|
|
1718
1868
|
if (indent !== 0) {
|
|
1719
1869
|
setElementIndent(dom, indent);
|
|
1720
1870
|
}
|
|
1721
1871
|
|
|
1722
|
-
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
if (childrenLength !== 0) {
|
|
1726
|
-
const endIndex = childrenLength - 1;
|
|
1872
|
+
if (childrenSize !== 0) {
|
|
1873
|
+
const endIndex = childrenSize - 1;
|
|
1874
|
+
const children = createChildrenArray(node, activeNextNodeMap);
|
|
1727
1875
|
createChildrenWithDirection(children, endIndex, node, dom);
|
|
1728
1876
|
}
|
|
1729
1877
|
|
|
@@ -1734,7 +1882,7 @@ function createNode(key, parentDOM, insertDOM) {
|
|
|
1734
1882
|
}
|
|
1735
1883
|
|
|
1736
1884
|
if (!node.isInline()) {
|
|
1737
|
-
reconcileElementTerminatingLineBreak(null,
|
|
1885
|
+
reconcileElementTerminatingLineBreak(null, node, dom);
|
|
1738
1886
|
}
|
|
1739
1887
|
|
|
1740
1888
|
if ($textContentRequiresDoubleLinebreakAtEnd(node)) {
|
|
@@ -1809,16 +1957,15 @@ function createChildren(children, _startIndex, endIndex, dom, insertDOM) {
|
|
|
1809
1957
|
subTreeTextContent = previousSubTreeTextContent + subTreeTextContent;
|
|
1810
1958
|
}
|
|
1811
1959
|
|
|
1812
|
-
function isLastChildLineBreakOrDecorator(
|
|
1813
|
-
const childKey = children[children.length - 1];
|
|
1960
|
+
function isLastChildLineBreakOrDecorator(childKey, nodeMap) {
|
|
1814
1961
|
const node = nodeMap.get(childKey);
|
|
1815
1962
|
return $isLineBreakNode(node) || $isDecoratorNode(node) && node.isInline();
|
|
1816
1963
|
} // If we end an element with a LineBreakNode, then we need to add an additional <br>
|
|
1817
1964
|
|
|
1818
1965
|
|
|
1819
|
-
function reconcileElementTerminatingLineBreak(
|
|
1820
|
-
const prevLineBreak =
|
|
1821
|
-
const nextLineBreak =
|
|
1966
|
+
function reconcileElementTerminatingLineBreak(prevElement, nextElement, dom) {
|
|
1967
|
+
const prevLineBreak = prevElement !== null && (prevElement.__size === 0 || isLastChildLineBreakOrDecorator(prevElement.__last, activePrevNodeMap));
|
|
1968
|
+
const nextLineBreak = nextElement.__size === 0 || isLastChildLineBreakOrDecorator(nextElement.__last, activeNextNodeMap);
|
|
1822
1969
|
|
|
1823
1970
|
if (prevLineBreak) {
|
|
1824
1971
|
if (!nextLineBreak) {
|
|
@@ -1901,53 +2048,78 @@ function reconcileBlockDirection(element, dom) {
|
|
|
1901
2048
|
}
|
|
1902
2049
|
}
|
|
1903
2050
|
|
|
1904
|
-
function reconcileChildrenWithDirection(
|
|
2051
|
+
function reconcileChildrenWithDirection(prevElement, nextElement, dom) {
|
|
1905
2052
|
const previousSubTreeDirectionTextContent = subTreeDirectionedTextContent;
|
|
1906
2053
|
subTreeDirectionedTextContent = '';
|
|
1907
|
-
reconcileChildren(
|
|
1908
|
-
reconcileBlockDirection(
|
|
2054
|
+
reconcileChildren(prevElement, nextElement, dom);
|
|
2055
|
+
reconcileBlockDirection(nextElement, dom);
|
|
1909
2056
|
subTreeDirectionedTextContent = previousSubTreeDirectionTextContent;
|
|
1910
2057
|
}
|
|
1911
2058
|
|
|
1912
|
-
function
|
|
2059
|
+
function createChildrenArray(element, nodeMap) {
|
|
2060
|
+
const children = [];
|
|
2061
|
+
let nodeKey = element.__first;
|
|
2062
|
+
|
|
2063
|
+
while (nodeKey !== null) {
|
|
2064
|
+
const node = nodeMap.get(nodeKey);
|
|
2065
|
+
|
|
2066
|
+
if (node === undefined) {
|
|
2067
|
+
{
|
|
2068
|
+
throw Error(`createChildrenArray: node does not exist in nodeMap`);
|
|
2069
|
+
}
|
|
2070
|
+
}
|
|
2071
|
+
|
|
2072
|
+
children.push(nodeKey);
|
|
2073
|
+
nodeKey = node.__next;
|
|
2074
|
+
}
|
|
2075
|
+
|
|
2076
|
+
return children;
|
|
2077
|
+
}
|
|
2078
|
+
|
|
2079
|
+
function reconcileChildren(prevElement, nextElement, dom) {
|
|
1913
2080
|
const previousSubTreeTextContent = subTreeTextContent;
|
|
2081
|
+
const prevChildrenSize = prevElement.__size;
|
|
2082
|
+
const nextChildrenSize = nextElement.__size;
|
|
1914
2083
|
subTreeTextContent = '';
|
|
1915
|
-
const prevChildrenLength = prevChildren.length;
|
|
1916
|
-
const nextChildrenLength = nextChildren.length;
|
|
1917
2084
|
|
|
1918
|
-
if (
|
|
1919
|
-
const
|
|
1920
|
-
const
|
|
2085
|
+
if (prevChildrenSize === 1 && nextChildrenSize === 1) {
|
|
2086
|
+
const prevFirstChildKey = prevElement.__first;
|
|
2087
|
+
const nextFrstChildKey = nextElement.__first;
|
|
1921
2088
|
|
|
1922
|
-
if (
|
|
1923
|
-
reconcileNode(
|
|
2089
|
+
if (prevFirstChildKey === nextFrstChildKey) {
|
|
2090
|
+
reconcileNode(prevFirstChildKey, dom);
|
|
1924
2091
|
} else {
|
|
1925
|
-
const lastDOM = getPrevElementByKeyOrThrow(
|
|
1926
|
-
const replacementDOM = createNode(
|
|
2092
|
+
const lastDOM = getPrevElementByKeyOrThrow(prevFirstChildKey);
|
|
2093
|
+
const replacementDOM = createNode(nextFrstChildKey, null, null);
|
|
1927
2094
|
dom.replaceChild(replacementDOM, lastDOM);
|
|
1928
|
-
destroyNode(
|
|
2095
|
+
destroyNode(prevFirstChildKey, null);
|
|
1929
2096
|
}
|
|
1930
|
-
} else
|
|
1931
|
-
|
|
1932
|
-
|
|
1933
|
-
|
|
1934
|
-
|
|
1935
|
-
|
|
1936
|
-
|
|
1937
|
-
|
|
1938
|
-
|
|
1939
|
-
|
|
1940
|
-
|
|
1941
|
-
|
|
1942
|
-
|
|
1943
|
-
|
|
2097
|
+
} else {
|
|
2098
|
+
const prevChildren = createChildrenArray(prevElement, activePrevNodeMap);
|
|
2099
|
+
const nextChildren = createChildrenArray(nextElement, activeNextNodeMap);
|
|
2100
|
+
|
|
2101
|
+
if (prevChildrenSize === 0) {
|
|
2102
|
+
if (nextChildrenSize !== 0) {
|
|
2103
|
+
createChildren(nextChildren, 0, nextChildrenSize - 1, dom, null);
|
|
2104
|
+
}
|
|
2105
|
+
} else if (nextChildrenSize === 0) {
|
|
2106
|
+
if (prevChildrenSize !== 0) {
|
|
2107
|
+
// @ts-expect-error: internal field
|
|
2108
|
+
const lexicalLineBreak = dom.__lexicalLineBreak;
|
|
2109
|
+
const canUseFastPath = lexicalLineBreak == null;
|
|
2110
|
+
destroyChildren(prevChildren, 0, prevChildrenSize - 1, canUseFastPath ? null : dom);
|
|
2111
|
+
|
|
2112
|
+
if (canUseFastPath) {
|
|
2113
|
+
// Fast path for removing DOM nodes
|
|
2114
|
+
dom.textContent = '';
|
|
2115
|
+
}
|
|
1944
2116
|
}
|
|
2117
|
+
} else {
|
|
2118
|
+
reconcileNodeChildren(prevChildren, nextChildren, prevChildrenSize, nextChildrenSize, dom);
|
|
1945
2119
|
}
|
|
1946
|
-
} else {
|
|
1947
|
-
reconcileNodeChildren(prevChildren, nextChildren, prevChildrenLength, nextChildrenLength, element, dom);
|
|
1948
2120
|
}
|
|
1949
2121
|
|
|
1950
|
-
if ($textContentRequiresDoubleLinebreakAtEnd(
|
|
2122
|
+
if ($textContentRequiresDoubleLinebreakAtEnd(nextElement)) {
|
|
1951
2123
|
subTreeTextContent += DOUBLE_LINE_BREAK;
|
|
1952
2124
|
} // @ts-expect-error: internal field
|
|
1953
2125
|
|
|
@@ -2036,15 +2208,11 @@ function reconcileNode(key, parentDOM) {
|
|
|
2036
2208
|
setElementFormat(dom, nextFormat);
|
|
2037
2209
|
}
|
|
2038
2210
|
|
|
2039
|
-
|
|
2040
|
-
|
|
2041
|
-
const childrenAreDifferent = prevChildren !== nextChildren;
|
|
2042
|
-
|
|
2043
|
-
if (childrenAreDifferent || isDirty) {
|
|
2044
|
-
reconcileChildrenWithDirection(prevChildren, nextChildren, nextNode, dom);
|
|
2211
|
+
if (isDirty) {
|
|
2212
|
+
reconcileChildrenWithDirection(prevNode, nextNode, dom);
|
|
2045
2213
|
|
|
2046
2214
|
if (!$isRootNode(nextNode) && !nextNode.isInline()) {
|
|
2047
|
-
reconcileElementTerminatingLineBreak(
|
|
2215
|
+
reconcileElementTerminatingLineBreak(prevNode, nextNode, dom);
|
|
2048
2216
|
}
|
|
2049
2217
|
}
|
|
2050
2218
|
|
|
@@ -2104,10 +2272,16 @@ function getFirstChild(element) {
|
|
|
2104
2272
|
}
|
|
2105
2273
|
|
|
2106
2274
|
function getNextSibling(element) {
|
|
2107
|
-
|
|
2275
|
+
let nextSibling = element.nextSibling;
|
|
2276
|
+
|
|
2277
|
+
if (nextSibling !== null && nextSibling === activeEditor$1._blockCursorElement) {
|
|
2278
|
+
nextSibling = nextSibling.nextSibling;
|
|
2279
|
+
}
|
|
2280
|
+
|
|
2281
|
+
return nextSibling;
|
|
2108
2282
|
}
|
|
2109
2283
|
|
|
2110
|
-
function reconcileNodeChildren(prevChildren, nextChildren, prevChildrenLength, nextChildrenLength,
|
|
2284
|
+
function reconcileNodeChildren(prevChildren, nextChildren, prevChildrenLength, nextChildrenLength, dom) {
|
|
2111
2285
|
const prevEndIndex = prevChildrenLength - 1;
|
|
2112
2286
|
const nextEndIndex = nextChildrenLength - 1;
|
|
2113
2287
|
let prevChildrenSet;
|
|
@@ -3071,7 +3245,9 @@ function addRootElementEvents(rootElement, editor) {
|
|
|
3071
3245
|
return dispatchCommand(editor, FOCUS_COMMAND, event);
|
|
3072
3246
|
|
|
3073
3247
|
case 'blur':
|
|
3074
|
-
|
|
3248
|
+
{
|
|
3249
|
+
return dispatchCommand(editor, BLUR_COMMAND, event);
|
|
3250
|
+
}
|
|
3075
3251
|
|
|
3076
3252
|
case 'drop':
|
|
3077
3253
|
return dispatchCommand(editor, DROP_COMMAND, event);
|
|
@@ -3885,10 +4061,10 @@ class RangeSelection {
|
|
|
3885
4061
|
textNode.select();
|
|
3886
4062
|
|
|
3887
4063
|
if (startOffset === 0) {
|
|
3888
|
-
firstNode.insertBefore(textNode);
|
|
4064
|
+
firstNode.insertBefore(textNode, false);
|
|
3889
4065
|
} else {
|
|
3890
4066
|
const [targetNode] = firstNode.splitText(startOffset);
|
|
3891
|
-
targetNode.insertAfter(textNode);
|
|
4067
|
+
targetNode.insertAfter(textNode, false);
|
|
3892
4068
|
} // When composing, we need to adjust the anchor offset so that
|
|
3893
4069
|
// we correctly replace that right range.
|
|
3894
4070
|
|
|
@@ -3939,7 +4115,7 @@ class RangeSelection {
|
|
|
3939
4115
|
if ($isTextNode(lastNode) && !lastNode.isToken() && endOffset !== lastNode.getTextContentSize()) {
|
|
3940
4116
|
if (lastNode.isSegmented()) {
|
|
3941
4117
|
const textNode = $createTextNode(lastNode.getTextContent());
|
|
3942
|
-
lastNode.replace(textNode);
|
|
4118
|
+
lastNode.replace(textNode, false);
|
|
3943
4119
|
lastNode = textNode;
|
|
3944
4120
|
}
|
|
3945
4121
|
|
|
@@ -3982,7 +4158,7 @@ class RangeSelection {
|
|
|
3982
4158
|
if (lastNodeChild.isAttached()) {
|
|
3983
4159
|
if (!selectedNodesSet.has(lastNodeChild) || lastNodeChild.is(lastElementChild)) {
|
|
3984
4160
|
if (!firstAndLastElementsAreEqual) {
|
|
3985
|
-
insertionTarget.insertAfter(lastNodeChild);
|
|
4161
|
+
insertionTarget.insertAfter(lastNodeChild, false);
|
|
3986
4162
|
}
|
|
3987
4163
|
} else {
|
|
3988
4164
|
lastNodeChild.remove();
|
|
@@ -4027,7 +4203,7 @@ class RangeSelection {
|
|
|
4027
4203
|
} else {
|
|
4028
4204
|
const textNode = $createTextNode(text);
|
|
4029
4205
|
textNode.select();
|
|
4030
|
-
firstNode.replace(textNode);
|
|
4206
|
+
firstNode.replace(textNode, false);
|
|
4031
4207
|
} // Remove all selected nodes that haven't already been removed.
|
|
4032
4208
|
|
|
4033
4209
|
|
|
@@ -4364,7 +4540,7 @@ class RangeSelection {
|
|
|
4364
4540
|
lastNode = node;
|
|
4365
4541
|
|
|
4366
4542
|
if ($isDecoratorNode(node) && !node.isInline()) {
|
|
4367
|
-
target = target.insertAfter(node);
|
|
4543
|
+
target = target.insertAfter(node, false);
|
|
4368
4544
|
} else if (!$isElementNode(node)) {
|
|
4369
4545
|
const firstChild = target.getFirstChild();
|
|
4370
4546
|
|
|
@@ -4391,12 +4567,12 @@ class RangeSelection {
|
|
|
4391
4567
|
|
|
4392
4568
|
target = node;
|
|
4393
4569
|
} else {
|
|
4394
|
-
target = target.insertAfter(node);
|
|
4570
|
+
target = target.insertAfter(node, false);
|
|
4395
4571
|
}
|
|
4396
4572
|
}
|
|
4397
4573
|
} else if (!$isElementNode(node) || $isElementNode(node) && node.isInline() || $isDecoratorNode(target) && !target.isInline()) {
|
|
4398
4574
|
lastNode = node;
|
|
4399
|
-
target = target.insertAfter(node);
|
|
4575
|
+
target = target.insertAfter(node, false);
|
|
4400
4576
|
} else {
|
|
4401
4577
|
const nextTarget = target.getParentOrThrow(); // if we're inserting an Element after a LineBreak, we want to move the target to the parent
|
|
4402
4578
|
// and remove the LineBreak so we don't have empty space.
|
|
@@ -4550,7 +4726,7 @@ class RangeSelection {
|
|
|
4550
4726
|
paragraph.select();
|
|
4551
4727
|
|
|
4552
4728
|
if (child !== null) {
|
|
4553
|
-
child.insertBefore(paragraph);
|
|
4729
|
+
child.insertBefore(paragraph, false);
|
|
4554
4730
|
} else {
|
|
4555
4731
|
currentElement.append(paragraph);
|
|
4556
4732
|
}
|
|
@@ -4565,7 +4741,7 @@ class RangeSelection {
|
|
|
4565
4741
|
|
|
4566
4742
|
if (anchorOffset === 0 && nodesToMoveLength > 0 && currentElement.isInline()) {
|
|
4567
4743
|
const parent = currentElement.getParentOrThrow();
|
|
4568
|
-
const newElement = parent.insertNewAfter(this);
|
|
4744
|
+
const newElement = parent.insertNewAfter(this, false);
|
|
4569
4745
|
|
|
4570
4746
|
if ($isElementNode(newElement)) {
|
|
4571
4747
|
const children = parent.getChildren();
|
|
@@ -4578,7 +4754,7 @@ class RangeSelection {
|
|
|
4578
4754
|
return;
|
|
4579
4755
|
}
|
|
4580
4756
|
|
|
4581
|
-
const newElement = currentElement.insertNewAfter(this);
|
|
4757
|
+
const newElement = currentElement.insertNewAfter(this, false);
|
|
4582
4758
|
|
|
4583
4759
|
if (newElement === null) {
|
|
4584
4760
|
// Handle as a line break insertion
|
|
@@ -4710,7 +4886,7 @@ class RangeSelection {
|
|
|
4710
4886
|
const anchor = this.anchor;
|
|
4711
4887
|
const collapse = alter === 'move'; // Handle the selection movement around decorators.
|
|
4712
4888
|
|
|
4713
|
-
const possibleNode = $
|
|
4889
|
+
const possibleNode = $getAdjacentNode(focus, isBackward);
|
|
4714
4890
|
|
|
4715
4891
|
if ($isDecoratorNode(possibleNode) && !possibleNode.isIsolated()) {
|
|
4716
4892
|
// Make it possible to move selection from range selection to
|
|
@@ -4765,6 +4941,16 @@ class RangeSelection {
|
|
|
4765
4941
|
|
|
4766
4942
|
if (!domSelection) {
|
|
4767
4943
|
return;
|
|
4944
|
+
}
|
|
4945
|
+
|
|
4946
|
+
const editor = getActiveEditor();
|
|
4947
|
+
const blockCursorElement = editor._blockCursorElement;
|
|
4948
|
+
const rootElement = editor._rootElement; // Remove the block cursor element if it exists. This will ensure selection
|
|
4949
|
+
// works as intended. If we leave it in the DOM all sorts of strange bugs
|
|
4950
|
+
// occur. :/
|
|
4951
|
+
|
|
4952
|
+
if (rootElement !== null && blockCursorElement !== null && $isElementNode(possibleNode) && !possibleNode.isInline() && !possibleNode.canBeEmpty()) {
|
|
4953
|
+
removeDOMBlockCursorElement(blockCursorElement, editor, rootElement);
|
|
4768
4954
|
} // We use the DOM selection.modify API here to "tell" us what the selection
|
|
4769
4955
|
// will be. We then use it to update the Lexical selection accordingly. This
|
|
4770
4956
|
// is much more reliable than waiting for a beforeinput and using the ranges
|
|
@@ -4847,7 +5033,7 @@ class RangeSelection {
|
|
|
4847
5033
|
} // Handle the deletion around decorators.
|
|
4848
5034
|
|
|
4849
5035
|
|
|
4850
|
-
const possibleNode = $
|
|
5036
|
+
const possibleNode = $getAdjacentNode(focus, isBackward);
|
|
4851
5037
|
|
|
4852
5038
|
if ($isDecoratorNode(possibleNode) && !possibleNode.isIsolated()) {
|
|
4853
5039
|
// Make it possible to move selection from range selection to
|
|
@@ -5042,7 +5228,7 @@ function shouldResolveAncestor(resolvedElement, resolvedOffset, lastPoint) {
|
|
|
5042
5228
|
return lastPoint === null || parent === null || !parent.canBeEmpty() || parent !== lastPoint.getNode();
|
|
5043
5229
|
}
|
|
5044
5230
|
|
|
5045
|
-
function internalResolveSelectionPoint(dom, offset, lastPoint) {
|
|
5231
|
+
function internalResolveSelectionPoint(dom, offset, lastPoint, editor) {
|
|
5046
5232
|
let resolvedOffset = offset;
|
|
5047
5233
|
let resolvedNode; // If we have selection on an element, we will
|
|
5048
5234
|
// need to figure out (using the offset) what text
|
|
@@ -5063,7 +5249,16 @@ function internalResolveSelectionPoint(dom, offset, lastPoint) {
|
|
|
5063
5249
|
resolvedOffset = childNodesLength - 1;
|
|
5064
5250
|
}
|
|
5065
5251
|
|
|
5066
|
-
|
|
5252
|
+
let childDOM = childNodes[resolvedOffset];
|
|
5253
|
+
let hasBlockCursor = false;
|
|
5254
|
+
|
|
5255
|
+
if (childDOM === editor._blockCursorElement) {
|
|
5256
|
+
childDOM = childNodes[resolvedOffset + 1];
|
|
5257
|
+
hasBlockCursor = true;
|
|
5258
|
+
} else if (editor._blockCursorElement !== null) {
|
|
5259
|
+
resolvedOffset--;
|
|
5260
|
+
}
|
|
5261
|
+
|
|
5067
5262
|
resolvedNode = getNodeFromDOM(childDOM);
|
|
5068
5263
|
|
|
5069
5264
|
if ($isTextNode(resolvedNode)) {
|
|
@@ -5086,7 +5281,7 @@ function internalResolveSelectionPoint(dom, offset, lastPoint) {
|
|
|
5086
5281
|
resolvedOffset = 0;
|
|
5087
5282
|
} else {
|
|
5088
5283
|
child = descendant;
|
|
5089
|
-
resolvedElement = child.getParentOrThrow();
|
|
5284
|
+
resolvedElement = $isElementNode(child) ? child : child.getParentOrThrow();
|
|
5090
5285
|
}
|
|
5091
5286
|
}
|
|
5092
5287
|
|
|
@@ -5094,7 +5289,7 @@ function internalResolveSelectionPoint(dom, offset, lastPoint) {
|
|
|
5094
5289
|
resolvedNode = child;
|
|
5095
5290
|
resolvedElement = null;
|
|
5096
5291
|
resolvedOffset = getTextNodeOffset(child, moveSelectionToEnd);
|
|
5097
|
-
} else if (child !== resolvedElement && moveSelectionToEnd) {
|
|
5292
|
+
} else if (child !== resolvedElement && moveSelectionToEnd && !hasBlockCursor) {
|
|
5098
5293
|
resolvedOffset++;
|
|
5099
5294
|
}
|
|
5100
5295
|
} else {
|
|
@@ -5203,13 +5398,13 @@ function internalResolveSelectionPoints(anchorDOM, anchorOffset, focusDOM, focus
|
|
|
5203
5398
|
return null;
|
|
5204
5399
|
}
|
|
5205
5400
|
|
|
5206
|
-
const resolvedAnchorPoint = internalResolveSelectionPoint(anchorDOM, anchorOffset, $isRangeSelection(lastSelection) ? lastSelection.anchor : null);
|
|
5401
|
+
const resolvedAnchorPoint = internalResolveSelectionPoint(anchorDOM, anchorOffset, $isRangeSelection(lastSelection) ? lastSelection.anchor : null, editor);
|
|
5207
5402
|
|
|
5208
5403
|
if (resolvedAnchorPoint === null) {
|
|
5209
5404
|
return null;
|
|
5210
5405
|
}
|
|
5211
5406
|
|
|
5212
|
-
const resolvedFocusPoint = internalResolveSelectionPoint(focusDOM, focusOffset, $isRangeSelection(lastSelection) ? lastSelection.focus : null);
|
|
5407
|
+
const resolvedFocusPoint = internalResolveSelectionPoint(focusDOM, focusOffset, $isRangeSelection(lastSelection) ? lastSelection.focus : null, editor);
|
|
5213
5408
|
|
|
5214
5409
|
if (resolvedFocusPoint === null) {
|
|
5215
5410
|
return null;
|
|
@@ -5523,7 +5718,7 @@ function adjustPointOffsetForMergedSibling(point, isBefore, key, target, textLen
|
|
|
5523
5718
|
point.offset -= 1;
|
|
5524
5719
|
}
|
|
5525
5720
|
}
|
|
5526
|
-
function updateDOMSelection(prevSelection, nextSelection, editor, domSelection, tags, rootElement) {
|
|
5721
|
+
function updateDOMSelection(prevSelection, nextSelection, editor, domSelection, tags, rootElement, dirtyLeavesCount) {
|
|
5527
5722
|
const anchorDOMNode = domSelection.anchorNode;
|
|
5528
5723
|
const focusDOMNode = domSelection.focusNode;
|
|
5529
5724
|
const anchorOffset = domSelection.anchorOffset;
|
|
@@ -5531,7 +5726,7 @@ function updateDOMSelection(prevSelection, nextSelection, editor, domSelection,
|
|
|
5531
5726
|
const activeElement = document.activeElement; // TODO: make this not hard-coded, and add another config option
|
|
5532
5727
|
// that makes this configurable.
|
|
5533
5728
|
|
|
5534
|
-
if (tags.has('collaboration') && activeElement !== rootElement) {
|
|
5729
|
+
if (tags.has('collaboration') && activeElement !== rootElement || activeElement !== null && isSelectionCapturedInDecoratorInput(activeElement)) {
|
|
5535
5730
|
return;
|
|
5536
5731
|
}
|
|
5537
5732
|
|
|
@@ -5587,7 +5782,7 @@ function updateDOMSelection(prevSelection, nextSelection, editor, domSelection,
|
|
|
5587
5782
|
if (anchorOffset === nextAnchorOffset && focusOffset === nextFocusOffset && anchorDOMNode === nextAnchorNode && focusDOMNode === nextFocusNode && // Badly interpreted range selection when collapsed - #1482
|
|
5588
5783
|
!(domSelection.type === 'Range' && isCollapsed)) {
|
|
5589
5784
|
// If the root element does not have focus, ensure it has focus
|
|
5590
|
-
if (
|
|
5785
|
+
if (activeElement === null || !rootElement.contains(activeElement)) {
|
|
5591
5786
|
rootElement.focus({
|
|
5592
5787
|
preventScroll: true
|
|
5593
5788
|
});
|
|
@@ -5596,28 +5791,39 @@ function updateDOMSelection(prevSelection, nextSelection, editor, domSelection,
|
|
|
5596
5791
|
if (anchor.type !== 'element') {
|
|
5597
5792
|
return;
|
|
5598
5793
|
}
|
|
5599
|
-
}
|
|
5600
|
-
// a "selectionchange" event, although it will be asynchronous.
|
|
5601
|
-
|
|
5602
|
-
|
|
5603
|
-
try {
|
|
5604
|
-
domSelection.setBaseAndExtent(nextAnchorNode, nextAnchorOffset, nextFocusNode, nextFocusOffset);
|
|
5605
|
-
|
|
5606
|
-
if (!tags.has('skip-scroll-into-view') && nextSelection.isCollapsed() && rootElement !== null && rootElement === activeElement) {
|
|
5607
|
-
const selectionTarget = nextSelection instanceof RangeSelection && nextSelection.anchor.type === 'element' ? nextAnchorNode.childNodes[nextAnchorOffset] || null : domSelection.rangeCount > 0 ? domSelection.getRangeAt(0) : null;
|
|
5794
|
+
}
|
|
5608
5795
|
|
|
5609
|
-
|
|
5610
|
-
|
|
5611
|
-
|
|
5612
|
-
|
|
5796
|
+
if (!tags.has('skip-scroll-into-view')) // Apply the updated selection to the DOM. Note: this will trigger
|
|
5797
|
+
// a "selectionchange" event, although it will be asynchronous.
|
|
5798
|
+
try {
|
|
5799
|
+
// When updating more than 1000 nodes on Chrome, it's actually better to defer
|
|
5800
|
+
// updating the selection till the next frame. This is because Chrome's
|
|
5801
|
+
// Blink engine has hard limit on how many DOM nodes it can redraw in
|
|
5802
|
+
// a single cycle, so keeping it to the next frame improves performance.
|
|
5803
|
+
// The downside is that is makes the computation within Lexical more
|
|
5804
|
+
// complex, as now, we've sync update the DOM, but selection no longer
|
|
5805
|
+
// matches.
|
|
5806
|
+
if (IS_CHROME && dirtyLeavesCount > 1000) {
|
|
5807
|
+
window.requestAnimationFrame(() => domSelection.setBaseAndExtent(nextAnchorNode, nextAnchorOffset, nextFocusNode, nextFocusOffset));
|
|
5808
|
+
} else {
|
|
5809
|
+
domSelection.setBaseAndExtent(nextAnchorNode, nextAnchorOffset, nextFocusNode, nextFocusOffset);
|
|
5613
5810
|
}
|
|
5811
|
+
} catch (error) {// If we encounter an error, continue. This can sometimes
|
|
5812
|
+
// occur with FF and there's no good reason as to why it
|
|
5813
|
+
// should happen.
|
|
5614
5814
|
}
|
|
5615
5815
|
|
|
5616
|
-
|
|
5617
|
-
|
|
5618
|
-
|
|
5619
|
-
|
|
5816
|
+
if (!tags.has('skip-scroll-into-view') && nextSelection.isCollapsed() && rootElement !== null && rootElement === document.activeElement) {
|
|
5817
|
+
const selectionTarget = nextSelection instanceof RangeSelection && nextSelection.anchor.type === 'element' ? nextAnchorNode.childNodes[nextAnchorOffset] || null : domSelection.rangeCount > 0 ? domSelection.getRangeAt(0) : null;
|
|
5818
|
+
|
|
5819
|
+
if (selectionTarget !== null) {
|
|
5820
|
+
// @ts-ignore Text nodes do have getBoundingClientRect
|
|
5821
|
+
const selectionRect = selectionTarget.getBoundingClientRect();
|
|
5822
|
+
scrollIntoViewIfNeeded(editor, selectionRect, rootElement);
|
|
5823
|
+
}
|
|
5620
5824
|
}
|
|
5825
|
+
|
|
5826
|
+
markSelectionChangeFromDOMUpdate();
|
|
5621
5827
|
}
|
|
5622
5828
|
function $insertNodes(nodes, selectStart) {
|
|
5623
5829
|
let selection = $getSelection();
|
|
@@ -5650,6 +5856,11 @@ let activeEditor = null;
|
|
|
5650
5856
|
let isReadOnlyMode = false;
|
|
5651
5857
|
let isAttemptingToRecoverFromReconcilerError = false;
|
|
5652
5858
|
let infiniteTransformCount = 0;
|
|
5859
|
+
const observerOptions = {
|
|
5860
|
+
characterData: true,
|
|
5861
|
+
childList: true,
|
|
5862
|
+
subtree: true
|
|
5863
|
+
};
|
|
5653
5864
|
function isCurrentlyReadOnlyMode() {
|
|
5654
5865
|
return isReadOnlyMode;
|
|
5655
5866
|
}
|
|
@@ -5930,9 +6141,9 @@ function handleDEVOnlyPendingUpdateGuarantees(pendingEditorState) {
|
|
|
5930
6141
|
function commitPendingUpdates(editor) {
|
|
5931
6142
|
const pendingEditorState = editor._pendingEditorState;
|
|
5932
6143
|
const rootElement = editor._rootElement;
|
|
5933
|
-
const
|
|
6144
|
+
const shouldSkipDOM = editor._headless || rootElement === null;
|
|
5934
6145
|
|
|
5935
|
-
if (
|
|
6146
|
+
if (pendingEditorState === null) {
|
|
5936
6147
|
return;
|
|
5937
6148
|
} // ======
|
|
5938
6149
|
// Reconciliation has started.
|
|
@@ -5952,7 +6163,7 @@ function commitPendingUpdates(editor) {
|
|
|
5952
6163
|
editor._pendingEditorState = null;
|
|
5953
6164
|
editor._editorState = pendingEditorState;
|
|
5954
6165
|
|
|
5955
|
-
if (!
|
|
6166
|
+
if (!shouldSkipDOM && needsUpdate && observer !== null) {
|
|
5956
6167
|
activeEditor = editor;
|
|
5957
6168
|
activeEditorState = pendingEditorState;
|
|
5958
6169
|
isReadOnlyMode = false; // We don't want updates to sync block the reconciliation.
|
|
@@ -5986,11 +6197,7 @@ function commitPendingUpdates(editor) {
|
|
|
5986
6197
|
|
|
5987
6198
|
return;
|
|
5988
6199
|
} finally {
|
|
5989
|
-
observer.observe(rootElement,
|
|
5990
|
-
characterData: true,
|
|
5991
|
-
childList: true,
|
|
5992
|
-
subtree: true
|
|
5993
|
-
});
|
|
6200
|
+
observer.observe(rootElement, observerOptions);
|
|
5994
6201
|
editor._updating = previouslyUpdating;
|
|
5995
6202
|
activeEditorState = previousActiveEditorState;
|
|
5996
6203
|
isReadOnlyMode = previousReadOnlyMode;
|
|
@@ -6018,6 +6225,7 @@ function commitPendingUpdates(editor) {
|
|
|
6018
6225
|
const normalizedNodes = editor._normalizedNodes;
|
|
6019
6226
|
const tags = editor._updateTags;
|
|
6020
6227
|
const deferred = editor._deferred;
|
|
6228
|
+
const dirtyLeavesCount = dirtyLeaves.size;
|
|
6021
6229
|
|
|
6022
6230
|
if (needsUpdate) {
|
|
6023
6231
|
editor._dirtyType = NO_DIRTY_NODES;
|
|
@@ -6034,7 +6242,7 @@ function commitPendingUpdates(editor) {
|
|
|
6034
6242
|
// Reconciliation has finished. Now update selection and trigger listeners.
|
|
6035
6243
|
// ======
|
|
6036
6244
|
|
|
6037
|
-
const domSelection =
|
|
6245
|
+
const domSelection = shouldSkipDOM ? null : getDOMSelection(); // Attempt to update the DOM selection, including focusing of the root element,
|
|
6038
6246
|
// and scroll into view if needed.
|
|
6039
6247
|
|
|
6040
6248
|
if (editor._editable && // domSelection will be null in headless
|
|
@@ -6043,7 +6251,25 @@ function commitPendingUpdates(editor) {
|
|
|
6043
6251
|
activeEditorState = pendingEditorState;
|
|
6044
6252
|
|
|
6045
6253
|
try {
|
|
6046
|
-
|
|
6254
|
+
if (observer !== null) {
|
|
6255
|
+
observer.disconnect();
|
|
6256
|
+
}
|
|
6257
|
+
|
|
6258
|
+
if (needsUpdate || pendingSelection === null || pendingSelection.dirty) {
|
|
6259
|
+
const blockCursorElement = editor._blockCursorElement;
|
|
6260
|
+
|
|
6261
|
+
if (blockCursorElement !== null) {
|
|
6262
|
+
removeDOMBlockCursorElement(blockCursorElement, editor, rootElement);
|
|
6263
|
+
}
|
|
6264
|
+
|
|
6265
|
+
updateDOMSelection(currentSelection, pendingSelection, editor, domSelection, tags, rootElement, dirtyLeavesCount);
|
|
6266
|
+
}
|
|
6267
|
+
|
|
6268
|
+
updateDOMBlockCursorElement(editor, rootElement, pendingSelection);
|
|
6269
|
+
|
|
6270
|
+
if (observer !== null) {
|
|
6271
|
+
observer.observe(rootElement, observerOptions);
|
|
6272
|
+
}
|
|
6047
6273
|
} finally {
|
|
6048
6274
|
activeEditor = previousActiveEditor;
|
|
6049
6275
|
activeEditorState = previousActiveEditorState;
|
|
@@ -6344,7 +6570,10 @@ function beginUpdate(editor, updateFn, options) {
|
|
|
6344
6570
|
infiniteTransformCount = 0;
|
|
6345
6571
|
}
|
|
6346
6572
|
|
|
6347
|
-
const
|
|
6573
|
+
const windowObj = editor._window;
|
|
6574
|
+
const windowEvent = windowObj !== null ? window.event : null;
|
|
6575
|
+
const eventType = windowEvent != null ? windowEvent.type : null;
|
|
6576
|
+
const shouldUpdate = editor._dirtyType !== NO_DIRTY_NODES || editorStateHasDirtySelection(pendingEditorState, editor) || editor._blockCursorElement !== null && eventType === 'blur';
|
|
6348
6577
|
|
|
6349
6578
|
if (shouldUpdate) {
|
|
6350
6579
|
if (pendingEditorState._flushSync) {
|
|
@@ -6411,44 +6640,23 @@ function removeNode(nodeToRemove, restoreSelection, preserveEmptyParent) {
|
|
|
6411
6640
|
}
|
|
6412
6641
|
}
|
|
6413
6642
|
|
|
6414
|
-
const writableParent = parent.getWritable();
|
|
6415
|
-
const parentChildren = writableParent.__children;
|
|
6416
|
-
const index = parentChildren.indexOf(key);
|
|
6417
|
-
|
|
6418
|
-
if (index === -1) {
|
|
6419
|
-
{
|
|
6420
|
-
throw Error(`Node is not a child of its parent`);
|
|
6421
|
-
}
|
|
6422
|
-
}
|
|
6423
|
-
|
|
6424
|
-
internalMarkSiblingsAsDirty(nodeToRemove);
|
|
6425
|
-
parentChildren.splice(index, 1);
|
|
6426
|
-
const writableNodeToRemove = nodeToRemove.getWritable();
|
|
6427
|
-
writableNodeToRemove.__parent = null;
|
|
6428
|
-
|
|
6429
6643
|
if ($isRangeSelection(selection) && restoreSelection && !selectionMoved) {
|
|
6644
|
+
// Doing this is O(n) so lets avoid it unless we need to do it
|
|
6645
|
+
const index = nodeToRemove.getIndexWithinParent();
|
|
6646
|
+
removeFromParent(nodeToRemove);
|
|
6430
6647
|
$updateElementSelectionOnCreateDeleteNode(selection, parent, index, -1);
|
|
6648
|
+
} else {
|
|
6649
|
+
removeFromParent(nodeToRemove);
|
|
6431
6650
|
}
|
|
6432
6651
|
|
|
6433
6652
|
if (!preserveEmptyParent && !$isRootOrShadowRoot(parent) && !parent.canBeEmpty() && parent.isEmpty()) {
|
|
6434
6653
|
removeNode(parent, restoreSelection);
|
|
6435
6654
|
}
|
|
6436
6655
|
|
|
6437
|
-
if ($isRootNode(parent) && parent.isEmpty()) {
|
|
6656
|
+
if (restoreSelection && $isRootNode(parent) && parent.isEmpty()) {
|
|
6438
6657
|
parent.selectEnd();
|
|
6439
6658
|
}
|
|
6440
6659
|
}
|
|
6441
|
-
function $getNodeByKeyOrThrow(key) {
|
|
6442
|
-
const node = $getNodeByKey(key);
|
|
6443
|
-
|
|
6444
|
-
if (node === null) {
|
|
6445
|
-
{
|
|
6446
|
-
throw Error(`Expected node with key ${key} to exist but it's not in the nodeMap.`);
|
|
6447
|
-
}
|
|
6448
|
-
}
|
|
6449
|
-
|
|
6450
|
-
return node;
|
|
6451
|
-
}
|
|
6452
6660
|
class LexicalNode {
|
|
6453
6661
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
6454
6662
|
// Flow doesn't support abstract classes unfortunately, so we can't _force_
|
|
@@ -6544,8 +6752,19 @@ class LexicalNode {
|
|
|
6544
6752
|
return -1;
|
|
6545
6753
|
}
|
|
6546
6754
|
|
|
6547
|
-
|
|
6548
|
-
|
|
6755
|
+
let node = parent.getFirstChild();
|
|
6756
|
+
let index = 0;
|
|
6757
|
+
|
|
6758
|
+
while (node !== null) {
|
|
6759
|
+
if (this.is(node)) {
|
|
6760
|
+
return index;
|
|
6761
|
+
}
|
|
6762
|
+
|
|
6763
|
+
index++;
|
|
6764
|
+
node = node.getNextSibling();
|
|
6765
|
+
}
|
|
6766
|
+
|
|
6767
|
+
return -1;
|
|
6549
6768
|
}
|
|
6550
6769
|
|
|
6551
6770
|
getParent() {
|
|
@@ -6623,62 +6842,44 @@ class LexicalNode {
|
|
|
6623
6842
|
}
|
|
6624
6843
|
|
|
6625
6844
|
getPreviousSibling() {
|
|
6626
|
-
const
|
|
6627
|
-
|
|
6628
|
-
|
|
6629
|
-
return null;
|
|
6630
|
-
}
|
|
6631
|
-
|
|
6632
|
-
const children = parent.__children;
|
|
6633
|
-
const index = children.indexOf(this.__key);
|
|
6634
|
-
|
|
6635
|
-
if (index <= 0) {
|
|
6636
|
-
return null;
|
|
6637
|
-
}
|
|
6638
|
-
|
|
6639
|
-
return $getNodeByKey(children[index - 1]);
|
|
6845
|
+
const self = this.getLatest();
|
|
6846
|
+
const prevKey = self.__prev;
|
|
6847
|
+
return prevKey === null ? null : $getNodeByKey(prevKey);
|
|
6640
6848
|
}
|
|
6641
6849
|
|
|
6642
6850
|
getPreviousSiblings() {
|
|
6643
|
-
const
|
|
6851
|
+
const siblings = [];
|
|
6852
|
+
const parent = this.getParentOrThrow();
|
|
6853
|
+
let node = parent.getFirstChild();
|
|
6644
6854
|
|
|
6645
|
-
|
|
6646
|
-
|
|
6855
|
+
while (node !== null) {
|
|
6856
|
+
if (node.is(this)) {
|
|
6857
|
+
break;
|
|
6858
|
+
}
|
|
6859
|
+
|
|
6860
|
+
siblings.push(node);
|
|
6861
|
+
node = node.getNextSibling();
|
|
6647
6862
|
}
|
|
6648
6863
|
|
|
6649
|
-
|
|
6650
|
-
const index = children.indexOf(this.__key);
|
|
6651
|
-
return children.slice(0, index).map(childKey => $getNodeByKeyOrThrow(childKey));
|
|
6864
|
+
return siblings;
|
|
6652
6865
|
}
|
|
6653
6866
|
|
|
6654
6867
|
getNextSibling() {
|
|
6655
|
-
const
|
|
6656
|
-
|
|
6657
|
-
|
|
6658
|
-
return null;
|
|
6659
|
-
}
|
|
6660
|
-
|
|
6661
|
-
const children = parent.__children;
|
|
6662
|
-
const childrenLength = children.length;
|
|
6663
|
-
const index = children.indexOf(this.__key);
|
|
6664
|
-
|
|
6665
|
-
if (index >= childrenLength - 1) {
|
|
6666
|
-
return null;
|
|
6667
|
-
}
|
|
6668
|
-
|
|
6669
|
-
return $getNodeByKey(children[index + 1]);
|
|
6868
|
+
const self = this.getLatest();
|
|
6869
|
+
const nextKey = self.__next;
|
|
6870
|
+
return nextKey === null ? null : $getNodeByKey(nextKey);
|
|
6670
6871
|
}
|
|
6671
6872
|
|
|
6672
6873
|
getNextSiblings() {
|
|
6673
|
-
const
|
|
6874
|
+
const siblings = [];
|
|
6875
|
+
let node = this.getNextSibling();
|
|
6674
6876
|
|
|
6675
|
-
|
|
6676
|
-
|
|
6877
|
+
while (node !== null) {
|
|
6878
|
+
siblings.push(node);
|
|
6879
|
+
node = node.getNextSibling();
|
|
6677
6880
|
}
|
|
6678
6881
|
|
|
6679
|
-
|
|
6680
|
-
const index = children.indexOf(this.__key);
|
|
6681
|
-
return children.slice(index + 1).map(childKey => $getNodeByKeyOrThrow(childKey));
|
|
6882
|
+
return siblings;
|
|
6682
6883
|
}
|
|
6683
6884
|
|
|
6684
6885
|
getCommonAncestor(node) {
|
|
@@ -6739,7 +6940,7 @@ class LexicalNode {
|
|
|
6739
6940
|
const parent = node.getParentOrThrow();
|
|
6740
6941
|
|
|
6741
6942
|
if (parent === commonAncestor) {
|
|
6742
|
-
indexA =
|
|
6943
|
+
indexA = node.getIndexWithinParent();
|
|
6743
6944
|
break;
|
|
6744
6945
|
}
|
|
6745
6946
|
|
|
@@ -6752,7 +6953,7 @@ class LexicalNode {
|
|
|
6752
6953
|
const parent = node.getParentOrThrow();
|
|
6753
6954
|
|
|
6754
6955
|
if (parent === commonAncestor) {
|
|
6755
|
-
indexB =
|
|
6956
|
+
indexB = node.getIndexWithinParent();
|
|
6756
6957
|
break;
|
|
6757
6958
|
}
|
|
6758
6959
|
|
|
@@ -6898,9 +7099,13 @@ class LexicalNode {
|
|
|
6898
7099
|
|
|
6899
7100
|
const mutableNode = constructor.clone(latestNode);
|
|
6900
7101
|
mutableNode.__parent = parent;
|
|
7102
|
+
mutableNode.__next = latestNode.__next;
|
|
7103
|
+
mutableNode.__prev = latestNode.__prev;
|
|
6901
7104
|
|
|
6902
7105
|
if ($isElementNode(latestNode) && $isElementNode(mutableNode)) {
|
|
6903
|
-
mutableNode.
|
|
7106
|
+
mutableNode.__first = latestNode.__first;
|
|
7107
|
+
mutableNode.__last = latestNode.__last;
|
|
7108
|
+
mutableNode.__size = latestNode.__size;
|
|
6904
7109
|
mutableNode.__indent = latestNode.__indent;
|
|
6905
7110
|
mutableNode.__format = latestNode.__format;
|
|
6906
7111
|
mutableNode.__dir = latestNode.__dir;
|
|
@@ -6975,31 +7180,45 @@ class LexicalNode {
|
|
|
6975
7180
|
removeNode(this, true, preserveEmptyParent);
|
|
6976
7181
|
}
|
|
6977
7182
|
|
|
6978
|
-
replace(replaceWith) {
|
|
7183
|
+
replace(replaceWith, restoreSelection = true) {
|
|
6979
7184
|
errorOnReadOnly();
|
|
6980
7185
|
errorOnInsertTextNodeOnRoot(this, replaceWith);
|
|
7186
|
+
const self = this.getLatest();
|
|
6981
7187
|
const toReplaceKey = this.__key;
|
|
7188
|
+
const key = replaceWith.__key;
|
|
6982
7189
|
const writableReplaceWith = replaceWith.getWritable();
|
|
7190
|
+
const writableParent = this.getParentOrThrow().getWritable();
|
|
7191
|
+
const size = writableParent.__size;
|
|
6983
7192
|
removeFromParent(writableReplaceWith);
|
|
6984
|
-
const
|
|
6985
|
-
const
|
|
6986
|
-
const
|
|
6987
|
-
const
|
|
6988
|
-
const
|
|
7193
|
+
const prevSibling = self.getPreviousSibling();
|
|
7194
|
+
const nextSibling = self.getNextSibling();
|
|
7195
|
+
const prevKey = self.__prev;
|
|
7196
|
+
const nextKey = self.__next;
|
|
7197
|
+
const parentKey = self.__parent;
|
|
7198
|
+
removeNode(self, false);
|
|
6989
7199
|
|
|
6990
|
-
if (
|
|
6991
|
-
|
|
6992
|
-
|
|
6993
|
-
|
|
7200
|
+
if (prevSibling === null) {
|
|
7201
|
+
writableParent.__first = key;
|
|
7202
|
+
} else {
|
|
7203
|
+
const writablePrevSibling = prevSibling.getWritable();
|
|
7204
|
+
writablePrevSibling.__next = key;
|
|
6994
7205
|
}
|
|
6995
7206
|
|
|
6996
|
-
|
|
6997
|
-
|
|
6998
|
-
|
|
6999
|
-
|
|
7207
|
+
writableReplaceWith.__prev = prevKey;
|
|
7208
|
+
|
|
7209
|
+
if (nextSibling === null) {
|
|
7210
|
+
writableParent.__last = key;
|
|
7211
|
+
} else {
|
|
7212
|
+
const writableNextSibling = nextSibling.getWritable();
|
|
7213
|
+
writableNextSibling.__prev = key;
|
|
7214
|
+
}
|
|
7215
|
+
|
|
7216
|
+
writableReplaceWith.__next = nextKey;
|
|
7217
|
+
writableReplaceWith.__parent = parentKey;
|
|
7218
|
+
writableParent.__size = size;
|
|
7000
7219
|
const selection = $getSelection();
|
|
7001
7220
|
|
|
7002
|
-
if ($isRangeSelection(selection)) {
|
|
7221
|
+
if ($isRangeSelection(selection) && restoreSelection) {
|
|
7003
7222
|
const anchor = selection.anchor;
|
|
7004
7223
|
const focus = selection.focus;
|
|
7005
7224
|
|
|
@@ -7013,24 +7232,25 @@ class LexicalNode {
|
|
|
7013
7232
|
}
|
|
7014
7233
|
|
|
7015
7234
|
if ($getCompositionKey() === toReplaceKey) {
|
|
7016
|
-
$setCompositionKey(
|
|
7235
|
+
$setCompositionKey(key);
|
|
7017
7236
|
}
|
|
7018
7237
|
|
|
7019
7238
|
return writableReplaceWith;
|
|
7020
7239
|
}
|
|
7021
7240
|
|
|
7022
|
-
insertAfter(nodeToInsert) {
|
|
7241
|
+
insertAfter(nodeToInsert, restoreSelection = true) {
|
|
7023
7242
|
errorOnReadOnly();
|
|
7024
7243
|
errorOnInsertTextNodeOnRoot(this, nodeToInsert);
|
|
7025
7244
|
const writableSelf = this.getWritable();
|
|
7026
7245
|
const writableNodeToInsert = nodeToInsert.getWritable();
|
|
7027
7246
|
const oldParent = writableNodeToInsert.getParent();
|
|
7028
7247
|
const selection = $getSelection();
|
|
7029
|
-
const oldIndex = nodeToInsert.getIndexWithinParent();
|
|
7030
7248
|
let elementAnchorSelectionOnNode = false;
|
|
7031
7249
|
let elementFocusSelectionOnNode = false;
|
|
7032
7250
|
|
|
7033
7251
|
if (oldParent !== null) {
|
|
7252
|
+
// TODO: this is O(n), can we improve?
|
|
7253
|
+
const oldIndex = nodeToInsert.getIndexWithinParent();
|
|
7034
7254
|
removeFromParent(writableNodeToInsert);
|
|
7035
7255
|
|
|
7036
7256
|
if ($isRangeSelection(selection)) {
|
|
@@ -7042,22 +7262,26 @@ class LexicalNode {
|
|
|
7042
7262
|
}
|
|
7043
7263
|
}
|
|
7044
7264
|
|
|
7265
|
+
const nextSibling = this.getNextSibling();
|
|
7045
7266
|
const writableParent = this.getParentOrThrow().getWritable();
|
|
7046
7267
|
const insertKey = writableNodeToInsert.__key;
|
|
7047
|
-
|
|
7048
|
-
const children = writableParent.__children;
|
|
7049
|
-
const index = children.indexOf(writableSelf.__key);
|
|
7268
|
+
const nextKey = writableSelf.__next;
|
|
7050
7269
|
|
|
7051
|
-
if (
|
|
7052
|
-
|
|
7053
|
-
|
|
7054
|
-
|
|
7270
|
+
if (nextSibling === null) {
|
|
7271
|
+
writableParent.__last = insertKey;
|
|
7272
|
+
} else {
|
|
7273
|
+
const writableNextSibling = nextSibling.getWritable();
|
|
7274
|
+
writableNextSibling.__prev = insertKey;
|
|
7055
7275
|
}
|
|
7056
7276
|
|
|
7057
|
-
|
|
7058
|
-
|
|
7277
|
+
writableParent.__size++;
|
|
7278
|
+
writableSelf.__next = insertKey;
|
|
7279
|
+
writableNodeToInsert.__next = nextKey;
|
|
7280
|
+
writableNodeToInsert.__prev = writableSelf.__key;
|
|
7281
|
+
writableNodeToInsert.__parent = writableSelf.__parent;
|
|
7059
7282
|
|
|
7060
|
-
if ($isRangeSelection(selection)) {
|
|
7283
|
+
if (restoreSelection && $isRangeSelection(selection)) {
|
|
7284
|
+
const index = this.getIndexWithinParent();
|
|
7061
7285
|
$updateElementSelectionOnCreateDeleteNode(selection, writableParent, index + 1);
|
|
7062
7286
|
const writableParentKey = writableParent.__key;
|
|
7063
7287
|
|
|
@@ -7073,30 +7297,36 @@ class LexicalNode {
|
|
|
7073
7297
|
return nodeToInsert;
|
|
7074
7298
|
}
|
|
7075
7299
|
|
|
7076
|
-
insertBefore(nodeToInsert) {
|
|
7300
|
+
insertBefore(nodeToInsert, restoreSelection = true) {
|
|
7077
7301
|
errorOnReadOnly();
|
|
7078
7302
|
errorOnInsertTextNodeOnRoot(this, nodeToInsert);
|
|
7079
7303
|
const writableSelf = this.getWritable();
|
|
7080
7304
|
const writableNodeToInsert = nodeToInsert.getWritable();
|
|
7305
|
+
const insertKey = writableNodeToInsert.__key;
|
|
7081
7306
|
removeFromParent(writableNodeToInsert);
|
|
7307
|
+
const prevSibling = this.getPreviousSibling();
|
|
7082
7308
|
const writableParent = this.getParentOrThrow().getWritable();
|
|
7083
|
-
const
|
|
7084
|
-
writableNodeToInsert.__parent = writableSelf.__parent;
|
|
7085
|
-
const children = writableParent.__children;
|
|
7086
|
-
const index = children.indexOf(writableSelf.__key);
|
|
7309
|
+
const prevKey = writableSelf.__prev; // TODO: this is O(n), can we improve?
|
|
7087
7310
|
|
|
7088
|
-
|
|
7089
|
-
|
|
7090
|
-
|
|
7091
|
-
|
|
7311
|
+
const index = this.getIndexWithinParent();
|
|
7312
|
+
|
|
7313
|
+
if (prevSibling === null) {
|
|
7314
|
+
writableParent.__first = insertKey;
|
|
7315
|
+
} else {
|
|
7316
|
+
const writablePrevSibling = prevSibling.getWritable();
|
|
7317
|
+
writablePrevSibling.__next = insertKey;
|
|
7092
7318
|
}
|
|
7093
7319
|
|
|
7094
|
-
|
|
7095
|
-
|
|
7320
|
+
writableParent.__size++;
|
|
7321
|
+
writableSelf.__prev = insertKey;
|
|
7322
|
+
writableNodeToInsert.__prev = prevKey;
|
|
7323
|
+
writableNodeToInsert.__next = writableSelf.__key;
|
|
7324
|
+
writableNodeToInsert.__parent = writableSelf.__parent;
|
|
7096
7325
|
const selection = $getSelection();
|
|
7097
7326
|
|
|
7098
|
-
if ($isRangeSelection(selection)) {
|
|
7099
|
-
|
|
7327
|
+
if (restoreSelection && $isRangeSelection(selection)) {
|
|
7328
|
+
const parent = this.getParentOrThrow();
|
|
7329
|
+
$updateElementSelectionOnCreateDeleteNode(selection, parent, index);
|
|
7100
7330
|
}
|
|
7101
7331
|
|
|
7102
7332
|
return nodeToInsert;
|
|
@@ -7223,13 +7453,9 @@ class ElementNode extends LexicalNode {
|
|
|
7223
7453
|
|
|
7224
7454
|
/** @internal */
|
|
7225
7455
|
|
|
7226
|
-
/** @internal */
|
|
7227
|
-
|
|
7228
7456
|
/** @internal */
|
|
7229
7457
|
constructor(key) {
|
|
7230
|
-
super(key);
|
|
7231
|
-
|
|
7232
|
-
this.__children = [];
|
|
7458
|
+
super(key);
|
|
7233
7459
|
this.__first = null;
|
|
7234
7460
|
this.__last = null;
|
|
7235
7461
|
this.__size = 0;
|
|
@@ -7254,28 +7480,32 @@ class ElementNode extends LexicalNode {
|
|
|
7254
7480
|
}
|
|
7255
7481
|
|
|
7256
7482
|
getChildren() {
|
|
7257
|
-
const
|
|
7258
|
-
|
|
7259
|
-
const childrenNodes = [];
|
|
7483
|
+
const children = [];
|
|
7484
|
+
let child = this.getFirstChild();
|
|
7260
7485
|
|
|
7261
|
-
|
|
7262
|
-
|
|
7263
|
-
|
|
7264
|
-
if (childNode !== null) {
|
|
7265
|
-
childrenNodes.push(childNode);
|
|
7266
|
-
}
|
|
7486
|
+
while (child !== null) {
|
|
7487
|
+
children.push(child);
|
|
7488
|
+
child = child.getNextSibling();
|
|
7267
7489
|
}
|
|
7268
7490
|
|
|
7269
|
-
return
|
|
7491
|
+
return children;
|
|
7270
7492
|
}
|
|
7271
7493
|
|
|
7272
7494
|
getChildrenKeys() {
|
|
7273
|
-
|
|
7495
|
+
const children = [];
|
|
7496
|
+
let child = this.getFirstChild();
|
|
7497
|
+
|
|
7498
|
+
while (child !== null) {
|
|
7499
|
+
children.push(child.__key);
|
|
7500
|
+
child = child.getNextSibling();
|
|
7501
|
+
}
|
|
7502
|
+
|
|
7503
|
+
return children;
|
|
7274
7504
|
}
|
|
7275
7505
|
|
|
7276
7506
|
getChildrenSize() {
|
|
7277
7507
|
const self = this.getLatest();
|
|
7278
|
-
return self.
|
|
7508
|
+
return self.__size;
|
|
7279
7509
|
}
|
|
7280
7510
|
|
|
7281
7511
|
isEmpty() {
|
|
@@ -7290,24 +7520,25 @@ class ElementNode extends LexicalNode {
|
|
|
7290
7520
|
|
|
7291
7521
|
isLastChild() {
|
|
7292
7522
|
const self = this.getLatest();
|
|
7293
|
-
const
|
|
7294
|
-
return
|
|
7523
|
+
const parentLastChild = this.getParentOrThrow().getLastChild();
|
|
7524
|
+
return parentLastChild !== null && parentLastChild.is(self);
|
|
7295
7525
|
}
|
|
7296
7526
|
|
|
7297
7527
|
getAllTextNodes() {
|
|
7298
7528
|
const textNodes = [];
|
|
7299
|
-
|
|
7300
|
-
const children = self.__children;
|
|
7529
|
+
let child = this.getFirstChild();
|
|
7301
7530
|
|
|
7302
|
-
|
|
7303
|
-
|
|
7531
|
+
while (child !== null) {
|
|
7532
|
+
if ($isTextNode(child)) {
|
|
7533
|
+
textNodes.push(child);
|
|
7534
|
+
}
|
|
7304
7535
|
|
|
7305
|
-
if ($
|
|
7306
|
-
|
|
7307
|
-
} else if ($isElementNode(childNode)) {
|
|
7308
|
-
const subChildrenNodes = childNode.getAllTextNodes();
|
|
7536
|
+
if ($isElementNode(child)) {
|
|
7537
|
+
const subChildrenNodes = child.getAllTextNodes();
|
|
7309
7538
|
textNodes.push(...subChildrenNodes);
|
|
7310
7539
|
}
|
|
7540
|
+
|
|
7541
|
+
child = child.getNextSibling();
|
|
7311
7542
|
}
|
|
7312
7543
|
|
|
7313
7544
|
return textNodes;
|
|
@@ -7367,14 +7598,8 @@ class ElementNode extends LexicalNode {
|
|
|
7367
7598
|
|
|
7368
7599
|
getFirstChild() {
|
|
7369
7600
|
const self = this.getLatest();
|
|
7370
|
-
const
|
|
7371
|
-
|
|
7372
|
-
|
|
7373
|
-
if (childrenLength === 0) {
|
|
7374
|
-
return null;
|
|
7375
|
-
}
|
|
7376
|
-
|
|
7377
|
-
return $getNodeByKey(children[0]);
|
|
7601
|
+
const firstKey = self.__first;
|
|
7602
|
+
return firstKey === null ? null : $getNodeByKey(firstKey);
|
|
7378
7603
|
}
|
|
7379
7604
|
|
|
7380
7605
|
getFirstChildOrThrow() {
|
|
@@ -7391,14 +7616,8 @@ class ElementNode extends LexicalNode {
|
|
|
7391
7616
|
|
|
7392
7617
|
getLastChild() {
|
|
7393
7618
|
const self = this.getLatest();
|
|
7394
|
-
const
|
|
7395
|
-
|
|
7396
|
-
|
|
7397
|
-
if (childrenLength === 0) {
|
|
7398
|
-
return null;
|
|
7399
|
-
}
|
|
7400
|
-
|
|
7401
|
-
return $getNodeByKey(children[childrenLength - 1]);
|
|
7619
|
+
const lastKey = self.__last;
|
|
7620
|
+
return lastKey === null ? null : $getNodeByKey(lastKey);
|
|
7402
7621
|
}
|
|
7403
7622
|
|
|
7404
7623
|
getLastChildOrThrow() {
|
|
@@ -7414,15 +7633,39 @@ class ElementNode extends LexicalNode {
|
|
|
7414
7633
|
}
|
|
7415
7634
|
|
|
7416
7635
|
getChildAtIndex(index) {
|
|
7417
|
-
const
|
|
7418
|
-
|
|
7419
|
-
|
|
7636
|
+
const size = this.getChildrenSize();
|
|
7637
|
+
let node;
|
|
7638
|
+
let i;
|
|
7639
|
+
|
|
7640
|
+
if (index < size / 2) {
|
|
7641
|
+
node = this.getFirstChild();
|
|
7642
|
+
i = 0;
|
|
7643
|
+
|
|
7644
|
+
while (node !== null && i <= index) {
|
|
7645
|
+
if (i === index) {
|
|
7646
|
+
return node;
|
|
7647
|
+
}
|
|
7648
|
+
|
|
7649
|
+
node = node.getNextSibling();
|
|
7650
|
+
i++;
|
|
7651
|
+
}
|
|
7420
7652
|
|
|
7421
|
-
if (key === undefined) {
|
|
7422
7653
|
return null;
|
|
7423
7654
|
}
|
|
7424
7655
|
|
|
7425
|
-
|
|
7656
|
+
node = this.getLastChild();
|
|
7657
|
+
i = size - 1;
|
|
7658
|
+
|
|
7659
|
+
while (node !== null && i >= index) {
|
|
7660
|
+
if (i === index) {
|
|
7661
|
+
return node;
|
|
7662
|
+
}
|
|
7663
|
+
|
|
7664
|
+
node = node.getPreviousSibling();
|
|
7665
|
+
i--;
|
|
7666
|
+
}
|
|
7667
|
+
|
|
7668
|
+
return null;
|
|
7426
7669
|
}
|
|
7427
7670
|
|
|
7428
7671
|
getTextContent() {
|
|
@@ -7464,6 +7707,22 @@ class ElementNode extends LexicalNode {
|
|
|
7464
7707
|
let focusOffset = _focusOffset;
|
|
7465
7708
|
const childrenCount = this.getChildrenSize();
|
|
7466
7709
|
|
|
7710
|
+
if (!this.canBeEmpty()) {
|
|
7711
|
+
if (_anchorOffset === 0 && _focusOffset === 0) {
|
|
7712
|
+
const firstChild = this.getFirstChild();
|
|
7713
|
+
|
|
7714
|
+
if ($isTextNode(firstChild) || $isElementNode(firstChild)) {
|
|
7715
|
+
return firstChild.select(0, 0);
|
|
7716
|
+
}
|
|
7717
|
+
} else if ((_anchorOffset === undefined || _anchorOffset === childrenCount) && (_focusOffset === undefined || _focusOffset === childrenCount)) {
|
|
7718
|
+
const lastChild = this.getLastChild();
|
|
7719
|
+
|
|
7720
|
+
if ($isTextNode(lastChild) || $isElementNode(lastChild)) {
|
|
7721
|
+
return lastChild.select();
|
|
7722
|
+
}
|
|
7723
|
+
}
|
|
7724
|
+
}
|
|
7725
|
+
|
|
7467
7726
|
if (anchorOffset === undefined) {
|
|
7468
7727
|
anchorOffset = childrenCount;
|
|
7469
7728
|
}
|
|
@@ -7545,55 +7804,108 @@ class ElementNode extends LexicalNode {
|
|
|
7545
7804
|
}
|
|
7546
7805
|
|
|
7547
7806
|
splice(start, deleteCount, nodesToInsert) {
|
|
7807
|
+
const nodesToInsertLength = nodesToInsert.length;
|
|
7808
|
+
const oldSize = this.getChildrenSize();
|
|
7548
7809
|
const writableSelf = this.getWritable();
|
|
7549
7810
|
const writableSelfKey = writableSelf.__key;
|
|
7550
|
-
const
|
|
7551
|
-
const
|
|
7552
|
-
const
|
|
7811
|
+
const nodesToInsertKeys = [];
|
|
7812
|
+
const nodesToRemoveKeys = [];
|
|
7813
|
+
const nodeAfterRange = this.getChildAtIndex(start + deleteCount);
|
|
7814
|
+
let nodeBeforeRange = null;
|
|
7815
|
+
let newSize = oldSize - deleteCount + nodesToInsertLength;
|
|
7816
|
+
|
|
7817
|
+
if (start !== 0) {
|
|
7818
|
+
if (start === oldSize) {
|
|
7819
|
+
nodeBeforeRange = this.getLastChild();
|
|
7820
|
+
} else {
|
|
7821
|
+
const node = this.getChildAtIndex(start);
|
|
7822
|
+
|
|
7823
|
+
if (node !== null) {
|
|
7824
|
+
nodeBeforeRange = node.getPreviousSibling();
|
|
7825
|
+
}
|
|
7826
|
+
}
|
|
7827
|
+
}
|
|
7828
|
+
|
|
7829
|
+
if (deleteCount > 0) {
|
|
7830
|
+
let nodeToDelete = nodeBeforeRange === null ? this.getFirstChild() : nodeBeforeRange.getNextSibling();
|
|
7831
|
+
|
|
7832
|
+
for (let i = 0; i < deleteCount; i++) {
|
|
7833
|
+
if (nodeToDelete === null) {
|
|
7834
|
+
{
|
|
7835
|
+
throw Error(`splice: sibling not found`);
|
|
7836
|
+
}
|
|
7837
|
+
}
|
|
7838
|
+
|
|
7839
|
+
const nextSibling = nodeToDelete.getNextSibling();
|
|
7840
|
+
const nodeKeyToDelete = nodeToDelete.__key;
|
|
7841
|
+
const writableNodeToDelete = nodeToDelete.getWritable();
|
|
7842
|
+
removeFromParent(writableNodeToDelete);
|
|
7843
|
+
nodesToRemoveKeys.push(nodeKeyToDelete);
|
|
7844
|
+
nodeToDelete = nextSibling;
|
|
7845
|
+
}
|
|
7846
|
+
}
|
|
7847
|
+
|
|
7848
|
+
let prevNode = nodeBeforeRange;
|
|
7553
7849
|
|
|
7554
7850
|
for (let i = 0; i < nodesToInsertLength; i++) {
|
|
7555
7851
|
const nodeToInsert = nodesToInsert[i];
|
|
7852
|
+
|
|
7853
|
+
if (prevNode !== null && nodeToInsert.is(prevNode)) {
|
|
7854
|
+
nodeBeforeRange = prevNode = prevNode.getPreviousSibling();
|
|
7855
|
+
}
|
|
7856
|
+
|
|
7556
7857
|
const writableNodeToInsert = nodeToInsert.getWritable();
|
|
7557
7858
|
|
|
7859
|
+
if (writableNodeToInsert.__parent === writableSelfKey) {
|
|
7860
|
+
newSize--;
|
|
7861
|
+
}
|
|
7862
|
+
|
|
7863
|
+
removeFromParent(writableNodeToInsert);
|
|
7864
|
+
const nodeKeyToInsert = nodeToInsert.__key;
|
|
7865
|
+
|
|
7866
|
+
if (prevNode === null) {
|
|
7867
|
+
writableSelf.__first = nodeKeyToInsert;
|
|
7868
|
+
writableNodeToInsert.__prev = null;
|
|
7869
|
+
} else {
|
|
7870
|
+
const writablePrevNode = prevNode.getWritable();
|
|
7871
|
+
writablePrevNode.__next = nodeKeyToInsert;
|
|
7872
|
+
writableNodeToInsert.__prev = writablePrevNode.__key;
|
|
7873
|
+
}
|
|
7874
|
+
|
|
7558
7875
|
if (nodeToInsert.__key === writableSelfKey) {
|
|
7559
7876
|
{
|
|
7560
7877
|
throw Error(`append: attempting to append self`);
|
|
7561
7878
|
}
|
|
7562
|
-
}
|
|
7879
|
+
} // Set child parent to self
|
|
7563
7880
|
|
|
7564
|
-
removeFromParent(writableNodeToInsert); // Set child parent to self
|
|
7565
7881
|
|
|
7566
7882
|
writableNodeToInsert.__parent = writableSelfKey;
|
|
7567
|
-
|
|
7568
|
-
|
|
7569
|
-
} // Mark range edges siblings as dirty
|
|
7570
|
-
|
|
7571
|
-
|
|
7572
|
-
const nodeBeforeRange = this.getChildAtIndex(start - 1);
|
|
7573
|
-
|
|
7574
|
-
if (nodeBeforeRange) {
|
|
7575
|
-
internalMarkNodeAsDirty(nodeBeforeRange);
|
|
7883
|
+
nodesToInsertKeys.push(nodeKeyToInsert);
|
|
7884
|
+
prevNode = nodeToInsert;
|
|
7576
7885
|
}
|
|
7577
7886
|
|
|
7578
|
-
|
|
7579
|
-
|
|
7580
|
-
|
|
7581
|
-
|
|
7582
|
-
|
|
7583
|
-
|
|
7887
|
+
if (start + deleteCount === oldSize) {
|
|
7888
|
+
if (prevNode !== null) {
|
|
7889
|
+
const writablePrevNode = prevNode.getWritable();
|
|
7890
|
+
writablePrevNode.__next = null;
|
|
7891
|
+
writableSelf.__last = prevNode.__key;
|
|
7892
|
+
}
|
|
7893
|
+
} else if (nodeAfterRange !== null) {
|
|
7894
|
+
const writableNodeAfterRange = nodeAfterRange.getWritable();
|
|
7584
7895
|
|
|
7585
|
-
|
|
7896
|
+
if (prevNode !== null) {
|
|
7897
|
+
const writablePrevNode = prevNode.getWritable();
|
|
7898
|
+
writableNodeAfterRange.__prev = prevNode.__key;
|
|
7899
|
+
writablePrevNode.__next = nodeAfterRange.__key;
|
|
7900
|
+
} else {
|
|
7901
|
+
writableNodeAfterRange.__prev = null;
|
|
7902
|
+
}
|
|
7903
|
+
}
|
|
7586
7904
|
|
|
7587
|
-
|
|
7588
|
-
writableSelfChildren.push(...nodesToInsertKeys);
|
|
7589
|
-
nodesToRemoveKeys = [];
|
|
7590
|
-
} else {
|
|
7591
|
-
nodesToRemoveKeys = writableSelfChildren.splice(start, deleteCount, ...nodesToInsertKeys);
|
|
7592
|
-
} // In case of deletion we need to adjust selection, unlink removed nodes
|
|
7905
|
+
writableSelf.__size = newSize; // In case of deletion we need to adjust selection, unlink removed nodes
|
|
7593
7906
|
// and clean up node itself if it becomes empty. None of these needed
|
|
7594
7907
|
// for insertion-only cases
|
|
7595
7908
|
|
|
7596
|
-
|
|
7597
7909
|
if (nodesToRemoveKeys.length) {
|
|
7598
7910
|
// Adjusting selection, in case node that was anchor/focus will be deleted
|
|
7599
7911
|
const selection = $getSelection();
|
|
@@ -7601,50 +7913,21 @@ class ElementNode extends LexicalNode {
|
|
|
7601
7913
|
if ($isRangeSelection(selection)) {
|
|
7602
7914
|
const nodesToRemoveKeySet = new Set(nodesToRemoveKeys);
|
|
7603
7915
|
const nodesToInsertKeySet = new Set(nodesToInsertKeys);
|
|
7604
|
-
|
|
7605
|
-
const isPointRemoved = point => {
|
|
7606
|
-
let node = point.getNode();
|
|
7607
|
-
|
|
7608
|
-
while (node) {
|
|
7609
|
-
const nodeKey = node.__key;
|
|
7610
|
-
|
|
7611
|
-
if (nodesToRemoveKeySet.has(nodeKey) && !nodesToInsertKeySet.has(nodeKey)) {
|
|
7612
|
-
return true;
|
|
7613
|
-
}
|
|
7614
|
-
|
|
7615
|
-
node = node.getParent();
|
|
7616
|
-
}
|
|
7617
|
-
|
|
7618
|
-
return false;
|
|
7619
|
-
};
|
|
7620
|
-
|
|
7621
7916
|
const {
|
|
7622
7917
|
anchor,
|
|
7623
7918
|
focus
|
|
7624
7919
|
} = selection;
|
|
7625
7920
|
|
|
7626
|
-
if (isPointRemoved(anchor)) {
|
|
7921
|
+
if (isPointRemoved(anchor, nodesToRemoveKeySet, nodesToInsertKeySet)) {
|
|
7627
7922
|
moveSelectionPointToSibling(anchor, anchor.getNode(), this, nodeBeforeRange, nodeAfterRange);
|
|
7628
7923
|
}
|
|
7629
7924
|
|
|
7630
|
-
if (isPointRemoved(focus)) {
|
|
7925
|
+
if (isPointRemoved(focus, nodesToRemoveKeySet, nodesToInsertKeySet)) {
|
|
7631
7926
|
moveSelectionPointToSibling(focus, focus.getNode(), this, nodeBeforeRange, nodeAfterRange);
|
|
7632
|
-
} // Unlink removed nodes from current parent
|
|
7633
|
-
|
|
7634
|
-
|
|
7635
|
-
const nodesToRemoveKeysLength = nodesToRemoveKeys.length;
|
|
7636
|
-
|
|
7637
|
-
for (let i = 0; i < nodesToRemoveKeysLength; i++) {
|
|
7638
|
-
const nodeToRemove = $getNodeByKey(nodesToRemoveKeys[i]);
|
|
7639
|
-
|
|
7640
|
-
if (nodeToRemove != null) {
|
|
7641
|
-
const writableNodeToRemove = nodeToRemove.getWritable();
|
|
7642
|
-
writableNodeToRemove.__parent = null;
|
|
7643
|
-
}
|
|
7644
7927
|
} // Cleanup if node can't be empty
|
|
7645
7928
|
|
|
7646
7929
|
|
|
7647
|
-
if (
|
|
7930
|
+
if (newSize === 0 && !this.canBeEmpty() && !$isRootOrShadowRoot(this)) {
|
|
7648
7931
|
this.remove();
|
|
7649
7932
|
}
|
|
7650
7933
|
}
|
|
@@ -7666,7 +7949,7 @@ class ElementNode extends LexicalNode {
|
|
|
7666
7949
|
} // These are intended to be extends for specific element heuristics.
|
|
7667
7950
|
|
|
7668
7951
|
|
|
7669
|
-
insertNewAfter(selection) {
|
|
7952
|
+
insertNewAfter(selection, restoreSelection) {
|
|
7670
7953
|
return null;
|
|
7671
7954
|
}
|
|
7672
7955
|
|
|
@@ -7741,6 +8024,22 @@ function $isElementNode(node) {
|
|
|
7741
8024
|
return node instanceof ElementNode;
|
|
7742
8025
|
}
|
|
7743
8026
|
|
|
8027
|
+
function isPointRemoved(point, nodesToRemoveKeySet, nodesToInsertKeySet) {
|
|
8028
|
+
let node = point.getNode();
|
|
8029
|
+
|
|
8030
|
+
while (node) {
|
|
8031
|
+
const nodeKey = node.__key;
|
|
8032
|
+
|
|
8033
|
+
if (nodesToRemoveKeySet.has(nodeKey) && !nodesToInsertKeySet.has(nodeKey)) {
|
|
8034
|
+
return true;
|
|
8035
|
+
}
|
|
8036
|
+
|
|
8037
|
+
node = node.getParent();
|
|
8038
|
+
}
|
|
8039
|
+
|
|
8040
|
+
return false;
|
|
8041
|
+
}
|
|
8042
|
+
|
|
7744
8043
|
/**
|
|
7745
8044
|
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
7746
8045
|
*
|
|
@@ -8183,6 +8482,13 @@ function createTextInnerDOM(innerDOM, node, innerTag, format, text, config) {
|
|
|
8183
8482
|
|
|
8184
8483
|
|
|
8185
8484
|
class TextNode extends LexicalNode {
|
|
8485
|
+
/** @internal */
|
|
8486
|
+
|
|
8487
|
+
/** @internal */
|
|
8488
|
+
|
|
8489
|
+
/** @internal */
|
|
8490
|
+
|
|
8491
|
+
/** @internal */
|
|
8186
8492
|
static getType() {
|
|
8187
8493
|
return 'text';
|
|
8188
8494
|
}
|
|
@@ -8383,6 +8689,14 @@ class TextNode extends LexicalNode {
|
|
|
8383
8689
|
conversion: convertTextFormatElement,
|
|
8384
8690
|
priority: 0
|
|
8385
8691
|
}),
|
|
8692
|
+
sub: node => ({
|
|
8693
|
+
conversion: convertTextFormatElement,
|
|
8694
|
+
priority: 0
|
|
8695
|
+
}),
|
|
8696
|
+
sup: node => ({
|
|
8697
|
+
conversion: convertTextFormatElement,
|
|
8698
|
+
priority: 0
|
|
8699
|
+
}),
|
|
8386
8700
|
u: node => ({
|
|
8387
8701
|
conversion: convertTextFormatElement,
|
|
8388
8702
|
priority: 0
|
|
@@ -8581,7 +8895,6 @@ class TextNode extends LexicalNode {
|
|
|
8581
8895
|
|
|
8582
8896
|
const firstPart = parts[0];
|
|
8583
8897
|
const parent = self.getParentOrThrow();
|
|
8584
|
-
const parentKey = parent.__key;
|
|
8585
8898
|
let writableNode;
|
|
8586
8899
|
const format = self.getFormat();
|
|
8587
8900
|
const style = self.getStyle();
|
|
@@ -8591,7 +8904,6 @@ class TextNode extends LexicalNode {
|
|
|
8591
8904
|
if (self.isSegmented()) {
|
|
8592
8905
|
// Create a new TextNode
|
|
8593
8906
|
writableNode = $createTextNode(firstPart);
|
|
8594
|
-
writableNode.__parent = parentKey;
|
|
8595
8907
|
writableNode.__format = format;
|
|
8596
8908
|
writableNode.__style = style;
|
|
8597
8909
|
writableNode.__detail = detail;
|
|
@@ -8640,22 +8952,19 @@ class TextNode extends LexicalNode {
|
|
|
8640
8952
|
}
|
|
8641
8953
|
|
|
8642
8954
|
textSize = nextTextSize;
|
|
8643
|
-
sibling.__parent = parentKey;
|
|
8644
8955
|
splitNodes.push(sibling);
|
|
8645
8956
|
} // Insert the nodes into the parent's children
|
|
8646
8957
|
|
|
8647
8958
|
|
|
8648
8959
|
internalMarkSiblingsAsDirty(this);
|
|
8649
8960
|
const writableParent = parent.getWritable();
|
|
8650
|
-
const
|
|
8651
|
-
const insertionIndex = writableParentChildren.indexOf(key);
|
|
8652
|
-
const splitNodesKeys = splitNodes.map(splitNode => splitNode.__key);
|
|
8961
|
+
const insertionIndex = this.getIndexWithinParent();
|
|
8653
8962
|
|
|
8654
8963
|
if (hasReplacedSelf) {
|
|
8655
|
-
|
|
8964
|
+
writableParent.splice(insertionIndex, 0, splitNodes);
|
|
8656
8965
|
this.remove();
|
|
8657
8966
|
} else {
|
|
8658
|
-
|
|
8967
|
+
writableParent.splice(insertionIndex, 1, splitNodes);
|
|
8659
8968
|
}
|
|
8660
8969
|
|
|
8661
8970
|
if ($isRangeSelection(selection)) {
|
|
@@ -8804,6 +9113,8 @@ const nodeNameToTextFormat = {
|
|
|
8804
9113
|
em: 'italic',
|
|
8805
9114
|
i: 'italic',
|
|
8806
9115
|
strong: 'bold',
|
|
9116
|
+
sub: 'subscript',
|
|
9117
|
+
sup: 'superscript',
|
|
8807
9118
|
u: 'underline'
|
|
8808
9119
|
};
|
|
8809
9120
|
|
|
@@ -8927,11 +9238,11 @@ class ParagraphNode extends ElementNode {
|
|
|
8927
9238
|
} // Mutation
|
|
8928
9239
|
|
|
8929
9240
|
|
|
8930
|
-
insertNewAfter() {
|
|
9241
|
+
insertNewAfter(_, restoreSelection) {
|
|
8931
9242
|
const newElement = $createParagraphNode();
|
|
8932
9243
|
const direction = this.getDirection();
|
|
8933
9244
|
newElement.setDirection(direction);
|
|
8934
|
-
this.insertAfter(newElement);
|
|
9245
|
+
this.insertAfter(newElement, restoreSelection);
|
|
8935
9246
|
return newElement;
|
|
8936
9247
|
}
|
|
8937
9248
|
|
|
@@ -9005,6 +9316,7 @@ function resetEditor(editor, prevRootElement, nextRootElement, pendingEditorStat
|
|
|
9005
9316
|
editor._normalizedNodes = new Set();
|
|
9006
9317
|
editor._updateTags = new Set();
|
|
9007
9318
|
editor._updates = [];
|
|
9319
|
+
editor._blockCursorElement = null;
|
|
9008
9320
|
const observer = editor._observer;
|
|
9009
9321
|
|
|
9010
9322
|
if (observer !== null) {
|
|
@@ -9191,8 +9503,9 @@ class LexicalEditor {
|
|
|
9191
9503
|
// Doing so, causes e2e tests around the lock to fail.
|
|
9192
9504
|
|
|
9193
9505
|
this._editable = true;
|
|
9194
|
-
this._headless =
|
|
9506
|
+
this._headless = parentEditor !== null && parentEditor._headless;
|
|
9195
9507
|
this._window = null;
|
|
9508
|
+
this._blockCursorElement = null;
|
|
9196
9509
|
}
|
|
9197
9510
|
|
|
9198
9511
|
isComposing() {
|
|
@@ -9515,7 +9828,7 @@ class LexicalEditor {
|
|
|
9515
9828
|
* LICENSE file in the root directory of this source tree.
|
|
9516
9829
|
*
|
|
9517
9830
|
*/
|
|
9518
|
-
const VERSION = '0.
|
|
9831
|
+
const VERSION = '0.7.0';
|
|
9519
9832
|
|
|
9520
9833
|
/**
|
|
9521
9834
|
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
@@ -9576,7 +9889,7 @@ exports.$createNodeSelection = $createNodeSelection;
|
|
|
9576
9889
|
exports.$createParagraphNode = $createParagraphNode;
|
|
9577
9890
|
exports.$createRangeSelection = $createRangeSelection;
|
|
9578
9891
|
exports.$createTextNode = $createTextNode;
|
|
9579
|
-
exports.$
|
|
9892
|
+
exports.$getAdjacentNode = $getAdjacentNode;
|
|
9580
9893
|
exports.$getNearestNodeFromDOMNode = $getNearestNodeFromDOMNode;
|
|
9581
9894
|
exports.$getNearestRootOrShadowRoot = $getNearestRootOrShadowRoot;
|
|
9582
9895
|
exports.$getNodeByKey = $getNodeByKey;
|