lexical 0.7.6 → 0.7.8
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 +122 -29
- package/Lexical.prod.js +182 -180
- package/LexicalConstants.d.ts +1 -0
- package/LexicalEditor.d.ts +1 -0
- package/LexicalNode.d.ts +4 -2
- package/index.d.ts +1 -1
- package/nodes/LexicalParagraphNode.d.ts +1 -1
- package/nodes/LexicalTextNode.d.ts +2 -1
- package/package.json +1 -1
package/Lexical.dev.js
CHANGED
|
@@ -6,6 +6,8 @@
|
|
|
6
6
|
*/
|
|
7
7
|
'use strict';
|
|
8
8
|
|
|
9
|
+
var utils = require('@lexical/utils');
|
|
10
|
+
|
|
9
11
|
/**
|
|
10
12
|
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
11
13
|
*
|
|
@@ -113,7 +115,8 @@ const IS_UNDERLINE = 1 << 3;
|
|
|
113
115
|
const IS_CODE = 1 << 4;
|
|
114
116
|
const IS_SUBSCRIPT = 1 << 5;
|
|
115
117
|
const IS_SUPERSCRIPT = 1 << 6;
|
|
116
|
-
const
|
|
118
|
+
const IS_HIGHLIGHT = 1 << 7;
|
|
119
|
+
const IS_ALL_FORMATTING = IS_BOLD | IS_ITALIC | IS_STRIKETHROUGH | IS_UNDERLINE | IS_CODE | IS_SUBSCRIPT | IS_SUPERSCRIPT | IS_HIGHLIGHT; // Text node details
|
|
117
120
|
|
|
118
121
|
const IS_DIRECTIONLESS = 1;
|
|
119
122
|
const IS_UNMERGEABLE = 1 << 1; // Element node formatting
|
|
@@ -143,6 +146,7 @@ const LTR_REGEX = new RegExp('^[^' + RTL + ']*[' + LTR + ']');
|
|
|
143
146
|
const TEXT_TYPE_TO_FORMAT = {
|
|
144
147
|
bold: IS_BOLD,
|
|
145
148
|
code: IS_CODE,
|
|
149
|
+
highlight: IS_HIGHLIGHT,
|
|
146
150
|
italic: IS_ITALIC,
|
|
147
151
|
strikethrough: IS_STRIKETHROUGH,
|
|
148
152
|
subscript: IS_SUBSCRIPT,
|
|
@@ -892,7 +896,33 @@ function $updateSelectedTextFromDOM(isCompositionEnd, editor, data) {
|
|
|
892
896
|
const node = $getNearestNodeFromDOMNode(anchorNode);
|
|
893
897
|
|
|
894
898
|
if (textContent !== null && $isTextNode(node)) {
|
|
895
|
-
|
|
899
|
+
if (node.canContainTabs()) {
|
|
900
|
+
const hasTabCharacter = textContent.includes('\t'); // At present, this condition is primarily used for code highlights when
|
|
901
|
+
// grouped together in lines (divs). If a code highlight includes a tab,
|
|
902
|
+
// the newly typed character may be missing from the DOM's textContent.
|
|
903
|
+
// Let's take an example. If a LinedCodeNode looked roughly like this:
|
|
904
|
+
// <code><div><codeHighlight /><codeHighlight /></div></code>,
|
|
905
|
+
// the following could occur when using tabs:
|
|
906
|
+
// a. /tconst --type--> 'd' at offset 1 --get--> /tconst
|
|
907
|
+
// - Missing 'd'
|
|
908
|
+
// b. /tconst --type--> 'd' at offset 3 --get--> /tcondst
|
|
909
|
+
// --type--> 'd' at offset 3 --get--> /tcondst
|
|
910
|
+
// - Missing second 'd'
|
|
911
|
+
// In these cases, we can fix the problem by manually inserting the
|
|
912
|
+
// newly typed character where we know it should have been.
|
|
913
|
+
|
|
914
|
+
if (data && data.length > 0 && hasTabCharacter) {
|
|
915
|
+
const selectionOffset = data.length;
|
|
916
|
+
const insertionOffset = anchorOffset + selectionOffset - 1;
|
|
917
|
+
const beforeInsertion = textContent.slice(0, insertionOffset);
|
|
918
|
+
const afterInsertion = textContent.slice(insertionOffset, textContent.length);
|
|
919
|
+
textContent = `${beforeInsertion}${data}${afterInsertion}`;
|
|
920
|
+
anchorOffset += selectionOffset;
|
|
921
|
+
focusOffset += selectionOffset;
|
|
922
|
+
}
|
|
923
|
+
} // Data is intentionally truthy, as we check for boolean, null and empty string.
|
|
924
|
+
|
|
925
|
+
|
|
896
926
|
if (textContent === COMPOSITION_SUFFIX && data) {
|
|
897
927
|
const offset = data.length;
|
|
898
928
|
textContent = data;
|
|
@@ -1873,12 +1903,6 @@ function createNode(key, parentDOM, insertDOM) {
|
|
|
1873
1903
|
const endIndex = childrenSize - 1;
|
|
1874
1904
|
const children = createChildrenArray(node, activeNextNodeMap);
|
|
1875
1905
|
createChildrenWithDirection(children, endIndex, node, dom);
|
|
1876
|
-
|
|
1877
|
-
if ($textContentRequiresDoubleLinebreakAtEnd(node)) {
|
|
1878
|
-
subTreeTextContent += DOUBLE_LINE_BREAK; // @ts-expect-error: internal field
|
|
1879
|
-
|
|
1880
|
-
dom.__lexicalTextContent = subTreeTextContent;
|
|
1881
|
-
}
|
|
1882
1906
|
}
|
|
1883
1907
|
|
|
1884
1908
|
const format = node.__format;
|
|
@@ -1944,18 +1968,22 @@ function createNode(key, parentDOM, insertDOM) {
|
|
|
1944
1968
|
function createChildrenWithDirection(children, endIndex, element, dom) {
|
|
1945
1969
|
const previousSubTreeDirectionedTextContent = subTreeDirectionedTextContent;
|
|
1946
1970
|
subTreeDirectionedTextContent = '';
|
|
1947
|
-
createChildren(children, 0, endIndex, dom, null);
|
|
1971
|
+
createChildren(children, element, 0, endIndex, dom, null);
|
|
1948
1972
|
reconcileBlockDirection(element, dom);
|
|
1949
1973
|
subTreeDirectionedTextContent = previousSubTreeDirectionedTextContent;
|
|
1950
1974
|
}
|
|
1951
1975
|
|
|
1952
|
-
function createChildren(children, _startIndex, endIndex, dom, insertDOM) {
|
|
1976
|
+
function createChildren(children, element, _startIndex, endIndex, dom, insertDOM) {
|
|
1953
1977
|
const previousSubTreeTextContent = subTreeTextContent;
|
|
1954
1978
|
subTreeTextContent = '';
|
|
1955
1979
|
let startIndex = _startIndex;
|
|
1956
1980
|
|
|
1957
1981
|
for (; startIndex <= endIndex; ++startIndex) {
|
|
1958
1982
|
createNode(children[startIndex], dom, insertDOM);
|
|
1983
|
+
}
|
|
1984
|
+
|
|
1985
|
+
if ($textContentRequiresDoubleLinebreakAtEnd(element)) {
|
|
1986
|
+
subTreeTextContent += DOUBLE_LINE_BREAK;
|
|
1959
1987
|
} // @ts-expect-error: internal field
|
|
1960
1988
|
|
|
1961
1989
|
|
|
@@ -2106,7 +2134,7 @@ function reconcileChildren(prevElement, nextElement, dom) {
|
|
|
2106
2134
|
|
|
2107
2135
|
if (prevChildrenSize === 0) {
|
|
2108
2136
|
if (nextChildrenSize !== 0) {
|
|
2109
|
-
createChildren(nextChildren, 0, nextChildrenSize - 1, dom, null);
|
|
2137
|
+
createChildren(nextChildren, nextElement, 0, nextChildrenSize - 1, dom, null);
|
|
2110
2138
|
}
|
|
2111
2139
|
} else if (nextChildrenSize === 0) {
|
|
2112
2140
|
if (prevChildrenSize !== 0) {
|
|
@@ -2121,7 +2149,7 @@ function reconcileChildren(prevElement, nextElement, dom) {
|
|
|
2121
2149
|
}
|
|
2122
2150
|
}
|
|
2123
2151
|
} else {
|
|
2124
|
-
reconcileNodeChildren(prevChildren, nextChildren, prevChildrenSize, nextChildrenSize, dom);
|
|
2152
|
+
reconcileNodeChildren(nextElement, prevChildren, nextChildren, prevChildrenSize, nextChildrenSize, dom);
|
|
2125
2153
|
}
|
|
2126
2154
|
}
|
|
2127
2155
|
|
|
@@ -2287,7 +2315,7 @@ function getNextSibling(element) {
|
|
|
2287
2315
|
return nextSibling;
|
|
2288
2316
|
}
|
|
2289
2317
|
|
|
2290
|
-
function reconcileNodeChildren(prevChildren, nextChildren, prevChildrenLength, nextChildrenLength, dom) {
|
|
2318
|
+
function reconcileNodeChildren(nextElement, prevChildren, nextChildren, prevChildrenLength, nextChildrenLength, dom) {
|
|
2291
2319
|
const prevEndIndex = prevChildrenLength - 1;
|
|
2292
2320
|
const nextEndIndex = nextChildrenLength - 1;
|
|
2293
2321
|
let prevChildrenSet;
|
|
@@ -2353,7 +2381,7 @@ function reconcileNodeChildren(prevChildren, nextChildren, prevChildrenLength, n
|
|
|
2353
2381
|
if (appendNewChildren && !removeOldChildren) {
|
|
2354
2382
|
const previousNode = nextChildren[nextEndIndex + 1];
|
|
2355
2383
|
const insertDOM = previousNode === undefined ? null : activeEditor$1.getElementByKey(previousNode);
|
|
2356
|
-
createChildren(nextChildren, nextIndex, nextEndIndex, dom, insertDOM);
|
|
2384
|
+
createChildren(nextChildren, nextElement, nextIndex, nextEndIndex, dom, insertDOM);
|
|
2357
2385
|
} else if (removeOldChildren && !appendNewChildren) {
|
|
2358
2386
|
destroyChildren(prevChildren, prevIndex, prevEndIndex, dom);
|
|
2359
2387
|
}
|
|
@@ -2473,7 +2501,7 @@ function $shouldPreventDefaultAndInsertText(selection, text, timeStamp, isBefore
|
|
|
2473
2501
|
// a recent beforeinput event for "textInput". If there has been one in the last
|
|
2474
2502
|
// 50ms then we proceed as normal. However, if there is not, then this is likely
|
|
2475
2503
|
// a dangling `input` event caused by execCommand('insertText').
|
|
2476
|
-
lastBeforeInputInsertTextTimeStamp < timeStamp + 50) || textLength < 2 || doesContainGrapheme(text)) && anchor.offset !== focus.offset && !anchorNode.isComposing() || // Any non standard text node.
|
|
2504
|
+
lastBeforeInputInsertTextTimeStamp < timeStamp + 50) || anchorNode.isDirty() && textLength < 2 || doesContainGrapheme(text)) && anchor.offset !== focus.offset && !anchorNode.isComposing() || // Any non standard text node.
|
|
2477
2505
|
$isTokenOrSegmented(anchorNode) || // If the text length is more than a single character and we're either
|
|
2478
2506
|
// dealing with this in "beforeinput" or where the node has already recently
|
|
2479
2507
|
// been changed (thus is dirty).
|
|
@@ -2914,7 +2942,8 @@ function onInput(event, editor) {
|
|
|
2914
2942
|
$setCompositionKey(null);
|
|
2915
2943
|
}
|
|
2916
2944
|
} else {
|
|
2917
|
-
|
|
2945
|
+
const characterData = data !== null ? data : undefined;
|
|
2946
|
+
$updateSelectedTextFromDOM(false, editor, characterData); // onInput always fires after onCompositionEnd for FF.
|
|
2918
2947
|
|
|
2919
2948
|
if (isFirefoxEndingComposition) {
|
|
2920
2949
|
onCompositionEndImpl(editor, data || undefined);
|
|
@@ -3815,7 +3844,13 @@ class RangeSelection {
|
|
|
3815
3844
|
}
|
|
3816
3845
|
|
|
3817
3846
|
if ($isElementNode(lastNode)) {
|
|
3818
|
-
|
|
3847
|
+
let lastNodeDescendant = lastNode.getDescendantByIndex(focus.offset); // We don't want to over-select, as node selection infers the child before
|
|
3848
|
+
// the last descendant, not including that descendant.
|
|
3849
|
+
|
|
3850
|
+
if (lastNodeDescendant !== null && lastNodeDescendant !== firstNode && lastNode.getChildAtIndex(focus.offset) === lastNodeDescendant) {
|
|
3851
|
+
lastNodeDescendant = lastNodeDescendant.getPreviousSibling();
|
|
3852
|
+
}
|
|
3853
|
+
|
|
3819
3854
|
lastNode = lastNodeDescendant != null ? lastNodeDescendant : lastNode;
|
|
3820
3855
|
}
|
|
3821
3856
|
|
|
@@ -3882,7 +3917,9 @@ class RangeSelection {
|
|
|
3882
3917
|
|
|
3883
3918
|
if (node === firstNode) {
|
|
3884
3919
|
if (node === lastNode) {
|
|
3885
|
-
|
|
3920
|
+
if (anchor.type !== 'element' || focus.type !== 'element' || focus.offset === anchor.offset) {
|
|
3921
|
+
text = anchorOffset < focusOffset ? text.slice(anchorOffset, focusOffset) : text.slice(focusOffset, anchorOffset);
|
|
3922
|
+
}
|
|
3886
3923
|
} else {
|
|
3887
3924
|
text = isBefore ? text.slice(anchorOffset) : text.slice(focusOffset);
|
|
3888
3925
|
}
|
|
@@ -4441,7 +4478,7 @@ class RangeSelection {
|
|
|
4441
4478
|
for (let i = 0; i < nodes.length; i++) {
|
|
4442
4479
|
const node = nodes[i];
|
|
4443
4480
|
|
|
4444
|
-
if (!$isDecoratorNode(target) && $isElementNode(node) && !node.isInline()) {
|
|
4481
|
+
if (!$isRootOrShadowRoot(target) && !$isDecoratorNode(target) && $isElementNode(node) && !node.isInline()) {
|
|
4445
4482
|
// -----
|
|
4446
4483
|
// Heuristics for the replacement or merging of elements
|
|
4447
4484
|
// -----
|
|
@@ -4581,8 +4618,27 @@ class RangeSelection {
|
|
|
4581
4618
|
}
|
|
4582
4619
|
}
|
|
4583
4620
|
} else if (!$isElementNode(node) || $isElementNode(node) && node.isInline() || $isDecoratorNode(target) && !target.isInline()) {
|
|
4584
|
-
lastNode = node;
|
|
4585
|
-
|
|
4621
|
+
lastNode = node; // when pasting top level node in the middle of paragraph
|
|
4622
|
+
// we need to split paragraph instead of placing it inline
|
|
4623
|
+
|
|
4624
|
+
if ($isRangeSelection(this) && $isDecoratorNode(node) && ($isElementNode(target) || $isTextNode(target)) && !node.isInline()) {
|
|
4625
|
+
let splitNode;
|
|
4626
|
+
let splitOffset;
|
|
4627
|
+
|
|
4628
|
+
if ($isTextNode(target)) {
|
|
4629
|
+
splitNode = target.getParentOrThrow();
|
|
4630
|
+
const [textNode] = target.splitText(anchorOffset);
|
|
4631
|
+
splitOffset = textNode.getIndexWithinParent() + 1;
|
|
4632
|
+
} else {
|
|
4633
|
+
splitNode = target;
|
|
4634
|
+
splitOffset = anchorOffset;
|
|
4635
|
+
}
|
|
4636
|
+
|
|
4637
|
+
const [, rightTree] = utils.$splitNode(splitNode, splitOffset);
|
|
4638
|
+
target = rightTree.insertBefore(node);
|
|
4639
|
+
} else {
|
|
4640
|
+
target = target.insertAfter(node, false);
|
|
4641
|
+
}
|
|
4586
4642
|
} else {
|
|
4587
4643
|
const nextTarget = target.getParentOrThrow(); // if we're inserting an Element after a LineBreak, we want to move the target to the parent
|
|
4588
4644
|
// and remove the LineBreak so we don't have empty space.
|
|
@@ -5096,7 +5152,16 @@ class RangeSelection {
|
|
|
5096
5152
|
}
|
|
5097
5153
|
}
|
|
5098
5154
|
|
|
5155
|
+
const wasCollapsed = this.isCollapsed();
|
|
5099
5156
|
this.removeText();
|
|
5157
|
+
|
|
5158
|
+
if (isBackward && !wasCollapsed && this.isCollapsed() && this.anchor.type === 'element' && this.anchor.offset === 0) {
|
|
5159
|
+
const anchorNode = this.anchor.getNode();
|
|
5160
|
+
|
|
5161
|
+
if (anchorNode.isEmpty() && $isRootNode(anchorNode.getParent())) {
|
|
5162
|
+
anchorNode.collapseAtStart(this);
|
|
5163
|
+
}
|
|
5164
|
+
}
|
|
5100
5165
|
}
|
|
5101
5166
|
|
|
5102
5167
|
deleteLine(isBackward) {
|
|
@@ -6733,14 +6798,14 @@ class LexicalNode {
|
|
|
6733
6798
|
return false;
|
|
6734
6799
|
}
|
|
6735
6800
|
|
|
6736
|
-
isSelected() {
|
|
6737
|
-
const
|
|
6801
|
+
isSelected(selection) {
|
|
6802
|
+
const targetSelection = selection || $getSelection();
|
|
6738
6803
|
|
|
6739
|
-
if (
|
|
6804
|
+
if (targetSelection == null) {
|
|
6740
6805
|
return false;
|
|
6741
6806
|
}
|
|
6742
6807
|
|
|
6743
|
-
const isSelected =
|
|
6808
|
+
const isSelected = targetSelection.getNodes().some(n => n.__key === this.__key);
|
|
6744
6809
|
|
|
6745
6810
|
if ($isTextNode(this)) {
|
|
6746
6811
|
return isSelected;
|
|
@@ -6748,7 +6813,7 @@ class LexicalNode {
|
|
|
6748
6813
|
// Without this change the image will be selected if the cursor is before or after it.
|
|
6749
6814
|
|
|
6750
6815
|
|
|
6751
|
-
if ($isRangeSelection(
|
|
6816
|
+
if ($isRangeSelection(targetSelection) && targetSelection.anchor.type === 'element' && targetSelection.focus.type === 'element' && targetSelection.anchor.key === targetSelection.focus.key && targetSelection.anchor.offset === targetSelection.focus.offset) {
|
|
6752
6817
|
return false;
|
|
6753
6818
|
}
|
|
6754
6819
|
|
|
@@ -7361,6 +7426,14 @@ class LexicalNode {
|
|
|
7361
7426
|
return nodeToInsert;
|
|
7362
7427
|
}
|
|
7363
7428
|
|
|
7429
|
+
isParentRequired() {
|
|
7430
|
+
return false;
|
|
7431
|
+
}
|
|
7432
|
+
|
|
7433
|
+
createParentElementNode() {
|
|
7434
|
+
return $createParagraphNode();
|
|
7435
|
+
}
|
|
7436
|
+
|
|
7364
7437
|
selectPrevious(anchorOffset, focusOffset) {
|
|
7365
7438
|
errorOnReadOnly();
|
|
7366
7439
|
const prevSibling = this.getPreviousSibling();
|
|
@@ -8369,6 +8442,10 @@ function getElementOuterTag(node, format) {
|
|
|
8369
8442
|
return 'code';
|
|
8370
8443
|
}
|
|
8371
8444
|
|
|
8445
|
+
if (format & IS_HIGHLIGHT) {
|
|
8446
|
+
return 'mark';
|
|
8447
|
+
}
|
|
8448
|
+
|
|
8372
8449
|
if (format & IS_SUBSCRIPT) {
|
|
8373
8450
|
return 'sub';
|
|
8374
8451
|
}
|
|
@@ -8937,6 +9014,10 @@ class TextNode extends LexicalNode {
|
|
|
8937
9014
|
return true;
|
|
8938
9015
|
}
|
|
8939
9016
|
|
|
9017
|
+
canContainTabs() {
|
|
9018
|
+
return false;
|
|
9019
|
+
}
|
|
9020
|
+
|
|
8940
9021
|
splitText(...splitOffsets) {
|
|
8941
9022
|
errorOnReadOnly();
|
|
8942
9023
|
const self = this.getLatest();
|
|
@@ -9260,7 +9341,7 @@ class ParagraphNode extends ElementNode {
|
|
|
9260
9341
|
return dom;
|
|
9261
9342
|
}
|
|
9262
9343
|
|
|
9263
|
-
updateDOM(prevNode, dom) {
|
|
9344
|
+
updateDOM(prevNode, dom, config) {
|
|
9264
9345
|
return false;
|
|
9265
9346
|
}
|
|
9266
9347
|
|
|
@@ -9356,9 +9437,20 @@ class ParagraphNode extends ElementNode {
|
|
|
9356
9437
|
|
|
9357
9438
|
}
|
|
9358
9439
|
|
|
9359
|
-
function convertParagraphElement() {
|
|
9440
|
+
function convertParagraphElement(element) {
|
|
9441
|
+
const node = $createParagraphNode();
|
|
9442
|
+
|
|
9443
|
+
if (element.style) {
|
|
9444
|
+
node.setFormat(element.style.textAlign);
|
|
9445
|
+
const indent = parseInt(element.style.textIndent, 10) / 20;
|
|
9446
|
+
|
|
9447
|
+
if (indent > 0) {
|
|
9448
|
+
node.setIndent(indent);
|
|
9449
|
+
}
|
|
9450
|
+
}
|
|
9451
|
+
|
|
9360
9452
|
return {
|
|
9361
|
-
node
|
|
9453
|
+
node
|
|
9362
9454
|
};
|
|
9363
9455
|
}
|
|
9364
9456
|
|
|
@@ -10051,3 +10143,4 @@ exports.TextNode = TextNode;
|
|
|
10051
10143
|
exports.UNDO_COMMAND = UNDO_COMMAND;
|
|
10052
10144
|
exports.createCommand = createCommand;
|
|
10053
10145
|
exports.createEditor = createEditor;
|
|
10146
|
+
exports.isSelectionWithinEditor = isSelectionWithinEditor;
|