lexical 0.3.5 → 0.3.6
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 +232 -157
- package/Lexical.js.flow +2 -1
- package/Lexical.prod.js +170 -168
- package/LexicalConstants.d.ts +4 -3
- package/LexicalEditor.d.ts +9 -10
- package/LexicalNode.d.ts +7 -7
- package/LexicalSelection.d.ts +6 -6
- package/LexicalUtils.d.ts +6 -7
- package/LexicalVersion.d.ts +1 -1
- package/index.d.ts +1 -1
- package/nodes/LexicalElementNode.d.ts +1 -1
- package/nodes/LexicalTextNode.d.ts +3 -2
- package/package.json +1 -4
package/Lexical.dev.js
CHANGED
|
@@ -148,6 +148,10 @@ const TEXT_TYPE_TO_FORMAT = {
|
|
|
148
148
|
superscript: IS_SUPERSCRIPT,
|
|
149
149
|
underline: IS_UNDERLINE
|
|
150
150
|
};
|
|
151
|
+
const DETAIL_TYPE_TO_DETAIL = {
|
|
152
|
+
directionless: IS_DIRECTIONLESS,
|
|
153
|
+
unmergeable: IS_UNMERGEABLE
|
|
154
|
+
};
|
|
151
155
|
const ELEMENT_TYPE_TO_FORMAT = {
|
|
152
156
|
center: IS_ALIGN_CENTER,
|
|
153
157
|
justify: IS_ALIGN_JUSTIFY,
|
|
@@ -200,7 +204,8 @@ function initTextEntryListener() {
|
|
|
200
204
|
|
|
201
205
|
function isManagedLineBreak(dom, target, editor) {
|
|
202
206
|
return (// @ts-expect-error: internal field
|
|
203
|
-
target.__lexicalLineBreak === dom ||
|
|
207
|
+
target.__lexicalLineBreak === dom || // @ts-ignore We intentionally add this to the Node.
|
|
208
|
+
dom[`__lexicalKey_${editor._key}`] !== undefined
|
|
204
209
|
);
|
|
205
210
|
}
|
|
206
211
|
|
|
@@ -222,7 +227,10 @@ function handleTextMutation(target, node, editor) {
|
|
|
222
227
|
}
|
|
223
228
|
|
|
224
229
|
const text = target.nodeValue;
|
|
225
|
-
|
|
230
|
+
|
|
231
|
+
if (text !== null) {
|
|
232
|
+
$updateTextNodeFromDOMContent(node, text, anchorOffset, focusOffset, false);
|
|
233
|
+
}
|
|
226
234
|
}
|
|
227
235
|
|
|
228
236
|
function shouldUpdateTextNodeFromMutation(selection, targetDOM, targetNode) {
|
|
@@ -661,8 +669,9 @@ function $getNodeByKey(key, _editorState) {
|
|
|
661
669
|
return node;
|
|
662
670
|
}
|
|
663
671
|
function getNodeFromDOMNode(dom, editorState) {
|
|
664
|
-
const editor = getActiveEditor();
|
|
665
|
-
|
|
672
|
+
const editor = getActiveEditor(); // @ts-ignore We intentionally add this to the Node.
|
|
673
|
+
|
|
674
|
+
const key = dom[`__lexicalKey_${editor._key}`];
|
|
666
675
|
|
|
667
676
|
if (key !== undefined) {
|
|
668
677
|
return $getNodeByKey(key, editorState);
|
|
@@ -771,7 +780,8 @@ dom, editor) {
|
|
|
771
780
|
let node = dom;
|
|
772
781
|
|
|
773
782
|
while (node != null) {
|
|
774
|
-
|
|
783
|
+
// @ts-ignore We intentionally add this to the Node.
|
|
784
|
+
const key = node[`__lexicalKey_${editor._key}`];
|
|
775
785
|
|
|
776
786
|
if (key !== undefined) {
|
|
777
787
|
return key;
|
|
@@ -827,7 +837,9 @@ function $updateSelectedTextFromDOM(editor, isCompositionEnd, data) {
|
|
|
827
837
|
focusOffset = offset;
|
|
828
838
|
}
|
|
829
839
|
|
|
830
|
-
|
|
840
|
+
if (textContent !== null) {
|
|
841
|
+
$updateTextNodeFromDOMContent(node, textContent, anchorOffset, focusOffset, isCompositionEnd);
|
|
842
|
+
}
|
|
831
843
|
}
|
|
832
844
|
}
|
|
833
845
|
}
|
|
@@ -897,6 +909,11 @@ function $updateTextNodeFromDOMContent(textNode, textContent, anchorOffset, focu
|
|
|
897
909
|
}
|
|
898
910
|
}
|
|
899
911
|
|
|
912
|
+
function $previousSiblingDoesNotAcceptText(node) {
|
|
913
|
+
const previousSibling = node.getPreviousSibling();
|
|
914
|
+
return ($isTextNode(previousSibling) || $isElementNode(previousSibling) && previousSibling.isInline()) && !previousSibling.canInsertTextAfter();
|
|
915
|
+
}
|
|
916
|
+
|
|
900
917
|
function $shouldInsertTextAfterOrBeforeTextNode(selection, node) {
|
|
901
918
|
if (node.isSegmented()) {
|
|
902
919
|
return true;
|
|
@@ -909,7 +926,7 @@ function $shouldInsertTextAfterOrBeforeTextNode(selection, node) {
|
|
|
909
926
|
const offset = selection.anchor.offset;
|
|
910
927
|
const parent = node.getParentOrThrow();
|
|
911
928
|
const isToken = node.isToken();
|
|
912
|
-
const shouldInsertTextBefore = offset === 0 && (!node.canInsertTextBefore() || !parent.canInsertTextBefore() || isToken);
|
|
929
|
+
const shouldInsertTextBefore = offset === 0 && (!node.canInsertTextBefore() || !parent.canInsertTextBefore() || isToken || $previousSiblingDoesNotAcceptText(node));
|
|
913
930
|
const shouldInsertTextAfter = node.getTextContentSize() === offset && (!node.canInsertTextBefore() || !parent.canInsertTextBefore() || isToken);
|
|
914
931
|
return shouldInsertTextBefore || shouldInsertTextAfter;
|
|
915
932
|
} // This function is used to determine if Lexical should attempt to override
|
|
@@ -1023,6 +1040,8 @@ function isCopy(keyCode, shiftKey, metaKey, ctrlKey) {
|
|
|
1023
1040
|
if (keyCode === 67) {
|
|
1024
1041
|
return IS_APPLE ? metaKey : ctrlKey;
|
|
1025
1042
|
}
|
|
1043
|
+
|
|
1044
|
+
return false;
|
|
1026
1045
|
}
|
|
1027
1046
|
function isCut(keyCode, shiftKey, metaKey, ctrlKey) {
|
|
1028
1047
|
if (shiftKey) {
|
|
@@ -1032,6 +1051,8 @@ function isCut(keyCode, shiftKey, metaKey, ctrlKey) {
|
|
|
1032
1051
|
if (keyCode === 88) {
|
|
1033
1052
|
return IS_APPLE ? metaKey : ctrlKey;
|
|
1034
1053
|
}
|
|
1054
|
+
|
|
1055
|
+
return false;
|
|
1035
1056
|
}
|
|
1036
1057
|
|
|
1037
1058
|
function isArrowLeft(keyCode) {
|
|
@@ -1137,8 +1158,7 @@ function setMutatedNode(mutatedNodes, registeredNodes, mutationListeners, node,
|
|
|
1137
1158
|
}
|
|
1138
1159
|
function $nodesOfType(klass) {
|
|
1139
1160
|
const editorState = getActiveEditorState();
|
|
1140
|
-
const readOnly = editorState._readOnly;
|
|
1141
|
-
|
|
1161
|
+
const readOnly = editorState._readOnly;
|
|
1142
1162
|
const klassType = klass.getType();
|
|
1143
1163
|
const nodes = editorState._nodeMap;
|
|
1144
1164
|
const nodesOfType = [];
|
|
@@ -1658,10 +1678,9 @@ function reconcileBlockDirection(element, dom) {
|
|
|
1658
1678
|
|
|
1659
1679
|
if (previousDirectionTheme !== undefined) {
|
|
1660
1680
|
if (typeof previousDirectionTheme === 'string') {
|
|
1661
|
-
const classNamesArr = previousDirectionTheme.split(' ');
|
|
1662
|
-
|
|
1681
|
+
const classNamesArr = previousDirectionTheme.split(' ');
|
|
1663
1682
|
previousDirectionTheme = theme[previousDirection] = classNamesArr;
|
|
1664
|
-
} // @ts-
|
|
1683
|
+
} // @ts-ignore: intentional
|
|
1665
1684
|
|
|
1666
1685
|
|
|
1667
1686
|
classList.remove(...previousDirectionTheme);
|
|
@@ -1679,7 +1698,9 @@ function reconcileBlockDirection(element, dom) {
|
|
|
1679
1698
|
nextDirectionTheme = theme[direction] = classNamesArr;
|
|
1680
1699
|
}
|
|
1681
1700
|
|
|
1682
|
-
|
|
1701
|
+
if (nextDirectionTheme !== undefined) {
|
|
1702
|
+
classList.add(...nextDirectionTheme);
|
|
1703
|
+
}
|
|
1683
1704
|
} // Update direction
|
|
1684
1705
|
|
|
1685
1706
|
|
|
@@ -2001,20 +2022,30 @@ function reconcileRoot(prevEditorState, nextEditorState, editor, dirtyType, dirt
|
|
|
2001
2022
|
// so instead we make it seem that these values are always set.
|
|
2002
2023
|
// We also want to make sure we clear them down, otherwise we
|
|
2003
2024
|
// can leak memory.
|
|
2025
|
+
// @ts-ignore
|
|
2026
|
+
|
|
2027
|
+
activeEditor$1 = undefined; // @ts-ignore
|
|
2028
|
+
|
|
2029
|
+
activeEditorNodes = undefined; // @ts-ignore
|
|
2030
|
+
|
|
2031
|
+
activeDirtyElements = undefined; // @ts-ignore
|
|
2032
|
+
|
|
2033
|
+
activeDirtyLeaves = undefined; // @ts-ignore
|
|
2034
|
+
|
|
2035
|
+
activePrevNodeMap = undefined; // @ts-ignore
|
|
2036
|
+
|
|
2037
|
+
activeNextNodeMap = undefined; // @ts-ignore
|
|
2038
|
+
|
|
2039
|
+
activeEditorConfig = undefined; // @ts-ignore
|
|
2040
|
+
|
|
2041
|
+
activePrevKeyToDOMMap = undefined; // @ts-ignore
|
|
2004
2042
|
|
|
2005
|
-
activeEditor$1 = undefined;
|
|
2006
|
-
activeEditorNodes = undefined;
|
|
2007
|
-
activeDirtyElements = undefined;
|
|
2008
|
-
activeDirtyLeaves = undefined;
|
|
2009
|
-
activePrevNodeMap = undefined;
|
|
2010
|
-
activeNextNodeMap = undefined;
|
|
2011
|
-
activeEditorConfig = undefined;
|
|
2012
|
-
activePrevKeyToDOMMap = undefined;
|
|
2013
2043
|
mutatedNodes = undefined;
|
|
2014
2044
|
return currentMutatedNodes;
|
|
2015
2045
|
}
|
|
2016
2046
|
function storeDOMWithKey(key, dom, editor) {
|
|
2017
|
-
const keyToDOMMap = editor._keyToDOMMap;
|
|
2047
|
+
const keyToDOMMap = editor._keyToDOMMap; // @ts-ignore We intentionally add this to the Node.
|
|
2048
|
+
|
|
2018
2049
|
dom['__lexicalKey_' + editor._key] = key;
|
|
2019
2050
|
keyToDOMMap.set(key, dom);
|
|
2020
2051
|
}
|
|
@@ -2043,7 +2074,7 @@ const ANDROID_COMPOSITION_LATENCY = 30;
|
|
|
2043
2074
|
const rootElementEvents = [['keydown', onKeyDown], ['compositionstart', onCompositionStart], ['compositionend', onCompositionEnd], ['input', onInput], ['click', onClick], ['cut', PASS_THROUGH_COMMAND], ['copy', PASS_THROUGH_COMMAND], ['dragstart', PASS_THROUGH_COMMAND], ['dragover', PASS_THROUGH_COMMAND], ['paste', PASS_THROUGH_COMMAND], ['focus', PASS_THROUGH_COMMAND], ['blur', PASS_THROUGH_COMMAND], ['drop', PASS_THROUGH_COMMAND]];
|
|
2044
2075
|
|
|
2045
2076
|
if (CAN_USE_BEFORE_INPUT) {
|
|
2046
|
-
rootElementEvents.push(['beforeinput', onBeforeInput]);
|
|
2077
|
+
rootElementEvents.push(['beforeinput', (event, editor) => onBeforeInput(event, editor)]);
|
|
2047
2078
|
}
|
|
2048
2079
|
|
|
2049
2080
|
let lastKeyDownTimeStamp = 0;
|
|
@@ -2055,7 +2086,7 @@ let isFirefoxEndingComposition = false;
|
|
|
2055
2086
|
let collapsedSelectionFormat = [0, 0, 'root', 0];
|
|
2056
2087
|
|
|
2057
2088
|
function shouldSkipSelectionChange(domNode, offset) {
|
|
2058
|
-
return domNode !== null && domNode.nodeType === DOM_TEXT_TYPE && offset !== 0 && offset !== domNode.nodeValue.length;
|
|
2089
|
+
return domNode !== null && domNode.nodeValue !== null && domNode.nodeType === DOM_TEXT_TYPE && offset !== 0 && offset !== domNode.nodeValue.length;
|
|
2059
2090
|
}
|
|
2060
2091
|
|
|
2061
2092
|
function onSelectionChange(domSelection, editor, isActive) {
|
|
@@ -2157,15 +2188,19 @@ function onClick(event, editor) {
|
|
|
2157
2188
|
const anchor = selection.anchor;
|
|
2158
2189
|
const anchorNode = anchor.getNode();
|
|
2159
2190
|
|
|
2160
|
-
if (anchor.type === 'element' && anchor.offset === 0 && selection.isCollapsed() && !$isRootNode(anchorNode) && $getRoot().getChildrenSize() === 1 && anchorNode.getTopLevelElementOrThrow().isEmpty() && lastSelection !== null && selection.is(lastSelection)) {
|
|
2191
|
+
if (domSelection && anchor.type === 'element' && anchor.offset === 0 && selection.isCollapsed() && !$isRootNode(anchorNode) && $getRoot().getChildrenSize() === 1 && anchorNode.getTopLevelElementOrThrow().isEmpty() && lastSelection !== null && selection.is(lastSelection)) {
|
|
2161
2192
|
domSelection.removeAllRanges();
|
|
2162
2193
|
selection.dirty = true;
|
|
2163
2194
|
}
|
|
2164
|
-
} else if ($isNodeSelection(selection) && domSelection.isCollapsed) {
|
|
2195
|
+
} else if (domSelection && $isNodeSelection(selection) && domSelection.isCollapsed) {
|
|
2165
2196
|
const domAnchor = domSelection.anchorNode; // If the user is attempting to click selection back onto text, then
|
|
2166
2197
|
// we should attempt create a range selection.
|
|
2198
|
+
// When we click on an empty paragraph node or the end of a paragraph that ends
|
|
2199
|
+
// with an image/poll, the nodeType will be ELEMENT_NODE
|
|
2200
|
+
|
|
2201
|
+
const allowedNodeType = [DOM_ELEMENT_TYPE, DOM_TEXT_TYPE];
|
|
2167
2202
|
|
|
2168
|
-
if (domAnchor !== null && domAnchor.nodeType
|
|
2203
|
+
if (domAnchor !== null && allowedNodeType.includes(domAnchor.nodeType)) {
|
|
2169
2204
|
const newSelection = internalCreateRangeSelection(lastSelection, domSelection, editor);
|
|
2170
2205
|
$setSelection(newSelection);
|
|
2171
2206
|
}
|
|
@@ -2476,7 +2511,14 @@ function onInput(event, editor) {
|
|
|
2476
2511
|
isFirefoxEndingComposition = false;
|
|
2477
2512
|
}
|
|
2478
2513
|
|
|
2479
|
-
dispatchCommand(editor, CONTROLLED_TEXT_INSERTION_COMMAND, data);
|
|
2514
|
+
dispatchCommand(editor, CONTROLLED_TEXT_INSERTION_COMMAND, data);
|
|
2515
|
+
const textLength = data.length; // Another hack for FF, as it's possible that the IME is still
|
|
2516
|
+
// open, even though compositionend has already fired (sigh).
|
|
2517
|
+
|
|
2518
|
+
if (IS_FIREFOX && textLength > 1 && event.inputType === 'insertCompositionText' && !editor.isComposing()) {
|
|
2519
|
+
selection.anchor.offset -= textLength;
|
|
2520
|
+
} // This ensures consistency on Android.
|
|
2521
|
+
|
|
2480
2522
|
|
|
2481
2523
|
if (!IS_SAFARI && !IS_IOS && editor.isComposing()) {
|
|
2482
2524
|
lastKeyDownTimeStamp = 0;
|
|
@@ -2486,7 +2528,7 @@ function onInput(event, editor) {
|
|
|
2486
2528
|
$updateSelectedTextFromDOM(editor, false); // onInput always fires after onCompositionEnd for FF.
|
|
2487
2529
|
|
|
2488
2530
|
if (isFirefoxEndingComposition) {
|
|
2489
|
-
onCompositionEndImpl(editor, data);
|
|
2531
|
+
onCompositionEndImpl(editor, data || undefined);
|
|
2490
2532
|
isFirefoxEndingComposition = false;
|
|
2491
2533
|
}
|
|
2492
2534
|
} // Also flush any other mutations that might have occurred
|
|
@@ -2532,7 +2574,7 @@ function onCompositionEndImpl(editor, data) {
|
|
|
2532
2574
|
const node = $getNodeByKey(compositionKey);
|
|
2533
2575
|
const textNode = getDOMTextNode(editor.getElementByKey(compositionKey));
|
|
2534
2576
|
|
|
2535
|
-
if (textNode !== null && $isTextNode(node)) {
|
|
2577
|
+
if (textNode !== null && textNode.nodeValue !== null && $isTextNode(node)) {
|
|
2536
2578
|
$updateTextNodeFromDOMContent(node, textNode.nodeValue, null, null, true);
|
|
2537
2579
|
}
|
|
2538
2580
|
|
|
@@ -2696,6 +2738,11 @@ const activeNestedEditorsMap = new Map();
|
|
|
2696
2738
|
|
|
2697
2739
|
function onDocumentSelectionChange(event) {
|
|
2698
2740
|
const selection = getDOMSelection();
|
|
2741
|
+
|
|
2742
|
+
if (!selection) {
|
|
2743
|
+
return;
|
|
2744
|
+
}
|
|
2745
|
+
|
|
2699
2746
|
const nextActiveEditor = getNearestEditorFromDOMNode(selection.anchorNode);
|
|
2700
2747
|
|
|
2701
2748
|
if (nextActiveEditor === null) {
|
|
@@ -2795,7 +2842,7 @@ function removeRootElementEvents(rootElement) {
|
|
|
2795
2842
|
|
|
2796
2843
|
const editor = rootElement.__lexicalEditor;
|
|
2797
2844
|
|
|
2798
|
-
if (editor !== null
|
|
2845
|
+
if (editor !== null && editor !== undefined) {
|
|
2799
2846
|
cleanActiveNestedEditorsMap(editor); // @ts-expect-error: internal field
|
|
2800
2847
|
|
|
2801
2848
|
rootElement.__lexicalEditor = null;
|
|
@@ -3472,7 +3519,7 @@ class RangeSelection {
|
|
|
3472
3519
|
const lastIndex = selectedNodesLength - 1;
|
|
3473
3520
|
let lastNode = selectedNodes[lastIndex];
|
|
3474
3521
|
|
|
3475
|
-
if (this.isCollapsed() && startOffset === firstNodeTextLength && (firstNode.isSegmented() || firstNode.isToken() || !firstNode.canInsertTextAfter() || !firstNodeParent.canInsertTextAfter())) {
|
|
3522
|
+
if (this.isCollapsed() && startOffset === firstNodeTextLength && (firstNode.isSegmented() || firstNode.isToken() || !firstNode.canInsertTextAfter() || !firstNodeParent.canInsertTextAfter() && firstNode.getNextSibling() === null)) {
|
|
3476
3523
|
let nextSibling = firstNode.getNextSibling();
|
|
3477
3524
|
|
|
3478
3525
|
if (!$isTextNode(nextSibling) || $isTokenOrInertOrSegmented(nextSibling)) {
|
|
@@ -3493,7 +3540,7 @@ class RangeSelection {
|
|
|
3493
3540
|
this.insertText(text);
|
|
3494
3541
|
return;
|
|
3495
3542
|
}
|
|
3496
|
-
} else if (this.isCollapsed() && startOffset === 0 && (firstNode.isSegmented() || firstNode.isToken() || !firstNode.canInsertTextBefore() || !firstNodeParent.canInsertTextBefore())) {
|
|
3543
|
+
} else if (this.isCollapsed() && startOffset === 0 && (firstNode.isSegmented() || firstNode.isToken() || !firstNode.canInsertTextBefore() || !firstNodeParent.canInsertTextBefore() && firstNode.getPreviousSibling() === null)) {
|
|
3497
3544
|
let prevSibling = firstNode.getPreviousSibling();
|
|
3498
3545
|
|
|
3499
3546
|
if (!$isTextNode(prevSibling) || $isTokenOrInertOrSegmented(prevSibling)) {
|
|
@@ -3717,10 +3764,19 @@ class RangeSelection {
|
|
|
3717
3764
|
formatText(formatType) {
|
|
3718
3765
|
// TODO I wonder if this methods use selection.extract() instead?
|
|
3719
3766
|
const selectedNodes = this.getNodes();
|
|
3720
|
-
const
|
|
3721
|
-
|
|
3722
|
-
|
|
3723
|
-
|
|
3767
|
+
const selectedTextNodes = [];
|
|
3768
|
+
|
|
3769
|
+
for (const selectedNode of selectedNodes) {
|
|
3770
|
+
if ($isTextNode(selectedNode)) {
|
|
3771
|
+
selectedTextNodes.push(selectedNode);
|
|
3772
|
+
}
|
|
3773
|
+
}
|
|
3774
|
+
|
|
3775
|
+
const selectedTextNodesLength = selectedTextNodes.length;
|
|
3776
|
+
let firstIndex = 0;
|
|
3777
|
+
const lastIndex = selectedTextNodesLength - 1;
|
|
3778
|
+
let firstNode = selectedTextNodes[0];
|
|
3779
|
+
let lastNode = selectedTextNodes[lastIndex];
|
|
3724
3780
|
|
|
3725
3781
|
if (this.isCollapsed()) {
|
|
3726
3782
|
this.toggleFormat(formatType); // When changing format, we should stop composition
|
|
@@ -3731,42 +3787,22 @@ class RangeSelection {
|
|
|
3731
3787
|
|
|
3732
3788
|
const anchor = this.anchor;
|
|
3733
3789
|
const focus = this.focus;
|
|
3790
|
+
const anchorOffset = anchor.offset;
|
|
3734
3791
|
const focusOffset = focus.offset;
|
|
3735
|
-
let firstNextFormat =
|
|
3792
|
+
let firstNextFormat = firstNode.getFormatFlags(formatType, null);
|
|
3736
3793
|
let firstNodeTextLength = firstNode.getTextContent().length;
|
|
3737
|
-
|
|
3738
|
-
for (let i = 0; i < selectedNodes.length; i++) {
|
|
3739
|
-
const selectedNode = selectedNodes[i];
|
|
3740
|
-
|
|
3741
|
-
if ($isTextNode(selectedNode)) {
|
|
3742
|
-
firstNextFormat = selectedNode.getFormatFlags(formatType, null);
|
|
3743
|
-
break;
|
|
3744
|
-
}
|
|
3745
|
-
}
|
|
3746
|
-
|
|
3747
|
-
let anchorOffset = anchor.offset;
|
|
3748
|
-
let startOffset;
|
|
3749
|
-
let endOffset;
|
|
3750
3794
|
const isBefore = anchor.isBefore(focus);
|
|
3751
|
-
|
|
3752
|
-
|
|
3795
|
+
const endOffset = isBefore ? focusOffset : anchorOffset;
|
|
3796
|
+
let startOffset = isBefore ? anchorOffset : focusOffset; // This is the case where the user only selected the very end of the
|
|
3753
3797
|
// first node so we don't want to include it in the formatting change.
|
|
3754
3798
|
|
|
3755
|
-
if (startOffset === firstNode.getTextContentSize()) {
|
|
3756
|
-
|
|
3757
|
-
|
|
3758
|
-
|
|
3759
|
-
|
|
3760
|
-
|
|
3761
|
-
|
|
3762
|
-
if ($isTextNode(nextSibling)) {
|
|
3763
|
-
// we basically make the second node the firstNode, changing offsets accordingly
|
|
3764
|
-
anchorOffset = 0;
|
|
3765
|
-
startOffset = 0;
|
|
3766
|
-
firstNode = nextSibling;
|
|
3767
|
-
firstNodeTextLength = nextSibling.getTextContent().length;
|
|
3768
|
-
firstNextFormat = firstNode.getFormatFlags(formatType, null);
|
|
3769
|
-
}
|
|
3799
|
+
if (startOffset === firstNode.getTextContentSize() && selectedTextNodes.length > 1) {
|
|
3800
|
+
const nextNode = selectedTextNodes[1];
|
|
3801
|
+
startOffset = 0;
|
|
3802
|
+
firstIndex = 1;
|
|
3803
|
+
firstNode = nextNode;
|
|
3804
|
+
firstNodeTextLength = nextNode.getTextContentSize();
|
|
3805
|
+
firstNextFormat = nextNode.getFormatFlags(formatType, null);
|
|
3770
3806
|
} // This is the case where we only selected a single node
|
|
3771
3807
|
|
|
3772
3808
|
|
|
@@ -3777,10 +3813,8 @@ class RangeSelection {
|
|
|
3777
3813
|
firstNode.select(startOffset, endOffset);
|
|
3778
3814
|
this.format = firstNextFormat;
|
|
3779
3815
|
return;
|
|
3780
|
-
}
|
|
3816
|
+
} // No actual text is selected, so do nothing.
|
|
3781
3817
|
|
|
3782
|
-
startOffset = anchorOffset > focusOffset ? focusOffset : anchorOffset;
|
|
3783
|
-
endOffset = anchorOffset > focusOffset ? anchorOffset : focusOffset; // No actual text is selected, so do nothing.
|
|
3784
3818
|
|
|
3785
3819
|
if (startOffset === endOffset) {
|
|
3786
3820
|
return;
|
|
@@ -3803,7 +3837,9 @@ class RangeSelection {
|
|
|
3803
3837
|
} // multiple nodes selected.
|
|
3804
3838
|
|
|
3805
3839
|
} else {
|
|
3806
|
-
|
|
3840
|
+
// Note: startOffset !== firstNodeTextLength should only occur within rare programatic
|
|
3841
|
+
// update functions; transforms normalization ensure there's no empty text nodes.
|
|
3842
|
+
if ($isTextNode(firstNode) && startOffset !== firstNodeTextLength) {
|
|
3807
3843
|
if (startOffset !== 0) {
|
|
3808
3844
|
// the entire first node isn't selected, so split it
|
|
3809
3845
|
[, firstNode] = firstNode.splitText(startOffset);
|
|
@@ -3829,11 +3865,12 @@ class RangeSelection {
|
|
|
3829
3865
|
|
|
3830
3866
|
lastNode.setFormat(lastNextFormat);
|
|
3831
3867
|
}
|
|
3832
|
-
}
|
|
3868
|
+
}
|
|
3833
3869
|
|
|
3870
|
+
this.format = firstNextFormat | lastNextFormat; // deal with all the nodes in between
|
|
3834
3871
|
|
|
3835
|
-
for (let i = 1; i < lastIndex; i++) {
|
|
3836
|
-
const selectedNode =
|
|
3872
|
+
for (let i = firstIndex + 1; i < lastIndex; i++) {
|
|
3873
|
+
const selectedNode = selectedTextNodes[i];
|
|
3837
3874
|
const selectedNodeKey = selectedNode.__key;
|
|
3838
3875
|
|
|
3839
3876
|
if ($isTextNode(selectedNode) && selectedNodeKey !== firstNode.__key && selectedNodeKey !== lastNode.__key && !selectedNode.isToken()) {
|
|
@@ -3905,7 +3942,7 @@ class RangeSelection {
|
|
|
3905
3942
|
siblings.push(...nextSiblings);
|
|
3906
3943
|
const firstNode = nodes[0];
|
|
3907
3944
|
let didReplaceOrMerge = false;
|
|
3908
|
-
let
|
|
3945
|
+
let lastNode = null; // Time to insert the nodes!
|
|
3909
3946
|
|
|
3910
3947
|
for (let i = 0; i < nodes.length; i++) {
|
|
3911
3948
|
const node = nodes[i];
|
|
@@ -3968,18 +4005,17 @@ class RangeSelection {
|
|
|
3968
4005
|
|
|
3969
4006
|
if ($isElementNode(target)) {
|
|
3970
4007
|
for (let s = 0; s < childrenLength; s++) {
|
|
3971
|
-
|
|
3972
|
-
target.append(lastNodeInserted);
|
|
4008
|
+
target.append(children[s]);
|
|
3973
4009
|
}
|
|
3974
4010
|
} else {
|
|
3975
4011
|
for (let s = childrenLength - 1; s >= 0; s--) {
|
|
3976
|
-
|
|
3977
|
-
target.insertAfter(lastNodeInserted);
|
|
4012
|
+
target.insertAfter(children[s]);
|
|
3978
4013
|
}
|
|
3979
4014
|
|
|
3980
4015
|
target = target.getParentOrThrow();
|
|
3981
4016
|
}
|
|
3982
4017
|
|
|
4018
|
+
lastNode = children[childrenLength - 1];
|
|
3983
4019
|
element.remove();
|
|
3984
4020
|
didReplaceOrMerge = true;
|
|
3985
4021
|
|
|
@@ -4007,7 +4043,7 @@ class RangeSelection {
|
|
|
4007
4043
|
didReplaceOrMerge = false;
|
|
4008
4044
|
|
|
4009
4045
|
if ($isElementNode(target) && !target.isInline()) {
|
|
4010
|
-
|
|
4046
|
+
lastNode = node;
|
|
4011
4047
|
|
|
4012
4048
|
if ($isDecoratorNode(node) && node.isTopLevel()) {
|
|
4013
4049
|
target = target.insertAfter(node);
|
|
@@ -4040,8 +4076,8 @@ class RangeSelection {
|
|
|
4040
4076
|
target = target.insertAfter(node);
|
|
4041
4077
|
}
|
|
4042
4078
|
}
|
|
4043
|
-
} else if (!$isElementNode(node) || $isElementNode(node) && node.isInline() || $isDecoratorNode(target) && target.isTopLevel()) {
|
|
4044
|
-
|
|
4079
|
+
} else if (!$isElementNode(node) || $isElementNode(node) && node.isInline() || $isDecoratorNode(target) && target.isTopLevel() || $isLineBreakNode(target)) {
|
|
4080
|
+
lastNode = node;
|
|
4045
4081
|
target = target.insertAfter(node);
|
|
4046
4082
|
} else {
|
|
4047
4083
|
target = node.getParentOrThrow(); // Re-try again with the target being the parent
|
|
@@ -4070,7 +4106,7 @@ class RangeSelection {
|
|
|
4070
4106
|
if ($isElementNode(target)) {
|
|
4071
4107
|
// If the last node to be inserted was a text node,
|
|
4072
4108
|
// then we should attempt to move selection to that.
|
|
4073
|
-
const lastChild = $isTextNode(
|
|
4109
|
+
const lastChild = $isTextNode(lastNode) ? lastNode : target.getLastDescendant();
|
|
4074
4110
|
|
|
4075
4111
|
if (!selectStart) {
|
|
4076
4112
|
// Handle moving selection to end for elements
|
|
@@ -4084,18 +4120,26 @@ class RangeSelection {
|
|
|
4084
4120
|
}
|
|
4085
4121
|
|
|
4086
4122
|
if (siblings.length !== 0) {
|
|
4123
|
+
const originalTarget = target;
|
|
4124
|
+
|
|
4087
4125
|
for (let i = siblings.length - 1; i >= 0; i--) {
|
|
4088
4126
|
const sibling = siblings[i];
|
|
4089
4127
|
const prevParent = sibling.getParentOrThrow();
|
|
4090
4128
|
|
|
4091
|
-
if ($isElementNode(target) && !$
|
|
4092
|
-
target
|
|
4129
|
+
if ($isElementNode(target) && !$isBlockElementNode(sibling)) {
|
|
4130
|
+
if (originalTarget === target) {
|
|
4131
|
+
target.append(sibling);
|
|
4132
|
+
} else {
|
|
4133
|
+
target.insertBefore(sibling);
|
|
4134
|
+
}
|
|
4135
|
+
|
|
4093
4136
|
target = sibling;
|
|
4094
|
-
} else if (!$isElementNode(target) && !$
|
|
4137
|
+
} else if (!$isElementNode(target) && !$isBlockElementNode(sibling)) {
|
|
4095
4138
|
target.insertBefore(sibling);
|
|
4096
4139
|
target = sibling;
|
|
4097
4140
|
} else {
|
|
4098
4141
|
if ($isElementNode(sibling) && !sibling.canInsertAfter(target)) {
|
|
4142
|
+
// @ts-ignore The clone method does exist on the constructor.
|
|
4099
4143
|
const prevParentClone = prevParent.constructor.clone(prevParent);
|
|
4100
4144
|
|
|
4101
4145
|
if (!$isElementNode(prevParentClone)) {
|
|
@@ -4378,13 +4422,18 @@ class RangeSelection {
|
|
|
4378
4422
|
}
|
|
4379
4423
|
}
|
|
4380
4424
|
|
|
4381
|
-
const domSelection = getDOMSelection();
|
|
4425
|
+
const domSelection = getDOMSelection();
|
|
4426
|
+
|
|
4427
|
+
if (!domSelection) {
|
|
4428
|
+
return;
|
|
4429
|
+
} // We use the DOM selection.modify API here to "tell" us what the selection
|
|
4382
4430
|
// will be. We then use it to update the Lexical selection accordingly. This
|
|
4383
4431
|
// is much more reliable than waiting for a beforeinput and using the ranges
|
|
4384
4432
|
// from getTargetRanges(), and is also better than trying to do it ourselves
|
|
4385
4433
|
// using Intl.Segmenter or other workarounds that struggle with word segments
|
|
4386
4434
|
// and line segments (especially with word wrapping and non-Roman languages).
|
|
4387
4435
|
|
|
4436
|
+
|
|
4388
4437
|
$moveNativeSelection(domSelection, alter, isBackward ? 'backward' : 'forward', granularity); // Guard against no ranges
|
|
4389
4438
|
|
|
4390
4439
|
if (domSelection.rangeCount > 0) {
|
|
@@ -4408,7 +4457,7 @@ class RangeSelection {
|
|
|
4408
4457
|
let anchorNode = anchor.getNode();
|
|
4409
4458
|
|
|
4410
4459
|
if (!isBackward && ( // Delete forward handle case
|
|
4411
|
-
anchor.type === 'element' && anchor.offset === anchorNode.getChildrenSize() || anchor.type === 'text' && anchor.offset === anchorNode.getTextContentSize())) {
|
|
4460
|
+
anchor.type === 'element' && $isElementNode(anchorNode) && anchor.offset === anchorNode.getChildrenSize() || anchor.type === 'text' && anchor.offset === anchorNode.getTextContentSize())) {
|
|
4412
4461
|
const nextSibling = anchorNode.getNextSibling() || anchorNode.getParentOrThrow().getNextSibling();
|
|
4413
4462
|
|
|
4414
4463
|
if ($isElementNode(nextSibling) && !nextSibling.canExtractContents()) {
|
|
@@ -4509,6 +4558,8 @@ function $swapPoints(selection) {
|
|
|
4509
4558
|
}
|
|
4510
4559
|
|
|
4511
4560
|
function $moveNativeSelection(domSelection, alter, direction, granularity) {
|
|
4561
|
+
// @ts-expect-error Selection.modify() method applies a change to the current selection or cursor position,
|
|
4562
|
+
// but is still non-standard in some browsers.
|
|
4512
4563
|
domSelection.modify(alter, direction, granularity);
|
|
4513
4564
|
}
|
|
4514
4565
|
|
|
@@ -4768,6 +4819,10 @@ function internalResolveSelectionPoints(anchorDOM, anchorOffset, focusDOM, focus
|
|
|
4768
4819
|
|
|
4769
4820
|
normalizeSelectionPointsForBoundaries(resolvedAnchorPoint, resolvedFocusPoint, lastSelection);
|
|
4770
4821
|
return [resolvedAnchorPoint, resolvedFocusPoint];
|
|
4822
|
+
}
|
|
4823
|
+
|
|
4824
|
+
function $isBlockElementNode(node) {
|
|
4825
|
+
return $isElementNode(node) && !node.isInline();
|
|
4771
4826
|
} // This is used to make a selection when the existing
|
|
4772
4827
|
// selection is null, i.e. forcing selection on the editor
|
|
4773
4828
|
// when it current exists outside the editor.
|
|
@@ -5116,7 +5171,7 @@ function updateDOMSelection(prevSelection, nextSelection, editor, domSelection,
|
|
|
5116
5171
|
if (anchorOffset === nextAnchorOffset && focusOffset === nextFocusOffset && anchorDOMNode === nextAnchorNode && focusDOMNode === nextFocusNode && // Badly interpreted range selection when collapsed - #1482
|
|
5117
5172
|
!(domSelection.type === 'Range' && isCollapsed)) {
|
|
5118
5173
|
// If the root element does not have focus, ensure it has focus
|
|
5119
|
-
if (activeElement === null || !rootElement.contains(activeElement)) {
|
|
5174
|
+
if (rootElement !== null && (activeElement === null || !rootElement.contains(activeElement))) {
|
|
5120
5175
|
rootElement.focus({
|
|
5121
5176
|
preventScroll: true
|
|
5122
5177
|
});
|
|
@@ -5135,7 +5190,7 @@ function updateDOMSelection(prevSelection, nextSelection, editor, domSelection,
|
|
|
5135
5190
|
try {
|
|
5136
5191
|
domSelection.setBaseAndExtent(nextAnchorNode, nextAnchorOffset, nextFocusNode, nextFocusOffset);
|
|
5137
5192
|
|
|
5138
|
-
if (nextSelection.isCollapsed() && rootElement === activeElement) {
|
|
5193
|
+
if (nextSelection.isCollapsed() && rootElement !== null && rootElement === activeElement) {
|
|
5139
5194
|
scrollIntoViewIfNeeded(editor, anchor, rootElement, tags);
|
|
5140
5195
|
}
|
|
5141
5196
|
|
|
@@ -5317,7 +5372,6 @@ function $applyAllTransforms(editorState, editor) {
|
|
|
5317
5372
|
}
|
|
5318
5373
|
|
|
5319
5374
|
function $parseSerializedNode(serializedNode) {
|
|
5320
|
-
// $FlowFixMe: intentional cast to our internal type
|
|
5321
5375
|
const internalSerializedNode = serializedNode;
|
|
5322
5376
|
return $parseSerializedNodeImpl(internalSerializedNode, getActiveEditor()._nodes);
|
|
5323
5377
|
}
|
|
@@ -5332,14 +5386,13 @@ function $parseSerializedNodeImpl(serializedNode, registeredNodes) {
|
|
|
5332
5386
|
}
|
|
5333
5387
|
}
|
|
5334
5388
|
|
|
5335
|
-
const nodeClass = registeredNode.klass;
|
|
5389
|
+
const nodeClass = registeredNode.klass;
|
|
5336
5390
|
|
|
5337
5391
|
if (serializedNode.type !== nodeClass.getType()) {
|
|
5338
5392
|
{
|
|
5339
5393
|
throw Error(`LexicalNode: Node ${nodeClass.name} does not implement .importJSON().`);
|
|
5340
5394
|
}
|
|
5341
|
-
}
|
|
5342
|
-
|
|
5395
|
+
}
|
|
5343
5396
|
|
|
5344
5397
|
const node = nodeClass.importJSON(serializedNode);
|
|
5345
5398
|
const children = serializedNode.children;
|
|
@@ -5477,7 +5530,9 @@ function commitPendingUpdates(editor) {
|
|
|
5477
5530
|
mutatedNodes = reconcileRoot(currentEditorState, pendingEditorState, editor, dirtyType, dirtyElements, dirtyLeaves);
|
|
5478
5531
|
} catch (error) {
|
|
5479
5532
|
// Report errors
|
|
5480
|
-
|
|
5533
|
+
if (error instanceof Error) {
|
|
5534
|
+
editor._onError(error);
|
|
5535
|
+
} // Reset editor and restore incoming editor state to the DOM
|
|
5481
5536
|
|
|
5482
5537
|
|
|
5483
5538
|
if (!isAttemptingToRecoverFromReconcilerError) {
|
|
@@ -5610,6 +5665,7 @@ function triggerListeners(type, editor, isCurrentlyEnqueuingUpdates, ...payload)
|
|
|
5610
5665
|
const listeners = Array.from(editor._listeners[type]);
|
|
5611
5666
|
|
|
5612
5667
|
for (let i = 0; i < listeners.length; i++) {
|
|
5668
|
+
// @ts-ignore
|
|
5613
5669
|
listeners[i].apply(null, payload);
|
|
5614
5670
|
}
|
|
5615
5671
|
} finally {
|
|
@@ -5654,8 +5710,12 @@ function triggerEnqueuedUpdates(editor) {
|
|
|
5654
5710
|
const queuedUpdates = editor._updates;
|
|
5655
5711
|
|
|
5656
5712
|
if (queuedUpdates.length !== 0) {
|
|
5657
|
-
const
|
|
5658
|
-
|
|
5713
|
+
const queuedUpdate = queuedUpdates.shift();
|
|
5714
|
+
|
|
5715
|
+
if (queuedUpdate) {
|
|
5716
|
+
const [updateFn, options] = queuedUpdate;
|
|
5717
|
+
beginUpdate(editor, updateFn, options);
|
|
5718
|
+
}
|
|
5659
5719
|
}
|
|
5660
5720
|
}
|
|
5661
5721
|
|
|
@@ -5683,28 +5743,32 @@ function processNestedUpdates(editor, initialSkipTransforms) {
|
|
|
5683
5743
|
// empty.
|
|
5684
5744
|
|
|
5685
5745
|
while (queuedUpdates.length !== 0) {
|
|
5686
|
-
const
|
|
5687
|
-
let onUpdate;
|
|
5688
|
-
let tag;
|
|
5746
|
+
const queuedUpdate = queuedUpdates.shift();
|
|
5689
5747
|
|
|
5690
|
-
if (
|
|
5691
|
-
|
|
5692
|
-
|
|
5748
|
+
if (queuedUpdate) {
|
|
5749
|
+
const [nextUpdateFn, options] = queuedUpdate;
|
|
5750
|
+
let onUpdate;
|
|
5751
|
+
let tag;
|
|
5693
5752
|
|
|
5694
|
-
if (options
|
|
5695
|
-
|
|
5696
|
-
|
|
5753
|
+
if (options !== undefined) {
|
|
5754
|
+
onUpdate = options.onUpdate;
|
|
5755
|
+
tag = options.tag;
|
|
5697
5756
|
|
|
5698
|
-
|
|
5699
|
-
|
|
5700
|
-
|
|
5757
|
+
if (options.skipTransforms) {
|
|
5758
|
+
skipTransforms = true;
|
|
5759
|
+
}
|
|
5760
|
+
|
|
5761
|
+
if (onUpdate) {
|
|
5762
|
+
editor._deferred.push(onUpdate);
|
|
5763
|
+
}
|
|
5701
5764
|
|
|
5702
|
-
|
|
5703
|
-
|
|
5765
|
+
if (tag) {
|
|
5766
|
+
editor._updateTags.add(tag);
|
|
5767
|
+
}
|
|
5704
5768
|
}
|
|
5705
|
-
}
|
|
5706
5769
|
|
|
5707
|
-
|
|
5770
|
+
nextUpdateFn();
|
|
5771
|
+
}
|
|
5708
5772
|
}
|
|
5709
5773
|
|
|
5710
5774
|
return skipTransforms;
|
|
@@ -5724,7 +5788,7 @@ function beginUpdate(editor, updateFn, options) {
|
|
|
5724
5788
|
updateTags.add(tag);
|
|
5725
5789
|
}
|
|
5726
5790
|
|
|
5727
|
-
skipTransforms = options.skipTransforms;
|
|
5791
|
+
skipTransforms = options.skipTransforms || false;
|
|
5728
5792
|
}
|
|
5729
5793
|
|
|
5730
5794
|
if (onUpdate) {
|
|
@@ -5796,7 +5860,9 @@ function beginUpdate(editor, updateFn, options) {
|
|
|
5796
5860
|
}
|
|
5797
5861
|
} catch (error) {
|
|
5798
5862
|
// Report errors
|
|
5799
|
-
|
|
5863
|
+
if (error instanceof Error) {
|
|
5864
|
+
editor._onError(error);
|
|
5865
|
+
} // Restore existing editor state to the DOM
|
|
5800
5866
|
|
|
5801
5867
|
|
|
5802
5868
|
editor._pendingEditorState = currentEditorState;
|
|
@@ -6158,7 +6224,6 @@ class LexicalNode {
|
|
|
6158
6224
|
const b = node.getParents();
|
|
6159
6225
|
|
|
6160
6226
|
if ($isElementNode(this)) {
|
|
6161
|
-
// @ts-expect-error
|
|
6162
6227
|
a.unshift(this);
|
|
6163
6228
|
}
|
|
6164
6229
|
|
|
@@ -6871,8 +6936,12 @@ class ElementNode extends LexicalNode {
|
|
|
6871
6936
|
}
|
|
6872
6937
|
|
|
6873
6938
|
hasFormat(type) {
|
|
6874
|
-
|
|
6875
|
-
|
|
6939
|
+
if (type !== '') {
|
|
6940
|
+
const formatFlag = ELEMENT_TYPE_TO_FORMAT[type];
|
|
6941
|
+
return (this.getFormat() & formatFlag) !== 0;
|
|
6942
|
+
}
|
|
6943
|
+
|
|
6944
|
+
return false;
|
|
6876
6945
|
} // Mutators
|
|
6877
6946
|
|
|
6878
6947
|
|
|
@@ -6957,7 +7026,7 @@ class ElementNode extends LexicalNode {
|
|
|
6957
7026
|
setFormat(type) {
|
|
6958
7027
|
errorOnReadOnly();
|
|
6959
7028
|
const self = this.getWritable();
|
|
6960
|
-
self.__format = ELEMENT_TYPE_TO_FORMAT[type]
|
|
7029
|
+
self.__format = type !== '' ? ELEMENT_TYPE_TO_FORMAT[type] : 0;
|
|
6961
7030
|
return this;
|
|
6962
7031
|
}
|
|
6963
7032
|
|
|
@@ -7550,20 +7619,24 @@ function setTextContent(nextText, dom, node) {
|
|
|
7550
7619
|
dom.textContent = text;
|
|
7551
7620
|
} else {
|
|
7552
7621
|
const nodeValue = firstChild.nodeValue;
|
|
7553
|
-
if (nodeValue !== text) if (isComposing || IS_FIREFOX) {
|
|
7554
|
-
// We also use the diff composed text for general text in FF to avoid
|
|
7555
|
-
// the spellcheck red line from flickering.
|
|
7556
|
-
const [index, remove, insert] = diffComposedText(nodeValue, text);
|
|
7557
7622
|
|
|
7558
|
-
|
|
7559
|
-
|
|
7560
|
-
|
|
7561
|
-
|
|
7623
|
+
if (nodeValue !== text) {
|
|
7624
|
+
if (isComposing || IS_FIREFOX) {
|
|
7625
|
+
// We also use the diff composed text for general text in FF to avoid
|
|
7626
|
+
// We also use the diff composed text for general text in FF to avoid
|
|
7627
|
+
// the spellcheck red line from flickering.
|
|
7628
|
+
const [index, remove, insert] = diffComposedText(nodeValue, text);
|
|
7562
7629
|
|
|
7630
|
+
if (remove !== 0) {
|
|
7631
|
+
// @ts-expect-error
|
|
7632
|
+
firstChild.deleteData(index, remove);
|
|
7633
|
+
} // @ts-expect-error
|
|
7563
7634
|
|
|
7564
|
-
|
|
7565
|
-
|
|
7566
|
-
|
|
7635
|
+
|
|
7636
|
+
firstChild.insertData(index, insert);
|
|
7637
|
+
} else {
|
|
7638
|
+
firstChild.nodeValue = text;
|
|
7639
|
+
}
|
|
7567
7640
|
}
|
|
7568
7641
|
}
|
|
7569
7642
|
}
|
|
@@ -7816,19 +7889,21 @@ class TextNode extends LexicalNode {
|
|
|
7816
7889
|
|
|
7817
7890
|
selectionTransform(prevSelection, nextSelection) {
|
|
7818
7891
|
return;
|
|
7819
|
-
}
|
|
7892
|
+
} // TODO 0.4 This should just be a `string`.
|
|
7893
|
+
|
|
7820
7894
|
|
|
7821
7895
|
setFormat(format) {
|
|
7822
7896
|
errorOnReadOnly();
|
|
7823
7897
|
const self = this.getWritable();
|
|
7824
|
-
self.__format = format;
|
|
7898
|
+
self.__format = typeof format === 'string' ? TEXT_TYPE_TO_FORMAT[format] : format;
|
|
7825
7899
|
return self;
|
|
7826
|
-
}
|
|
7900
|
+
} // TODO 0.4 This should just be a `string`.
|
|
7901
|
+
|
|
7827
7902
|
|
|
7828
7903
|
setDetail(detail) {
|
|
7829
7904
|
errorOnReadOnly();
|
|
7830
7905
|
const self = this.getWritable();
|
|
7831
|
-
self.__detail = detail;
|
|
7906
|
+
self.__detail = typeof detail === 'string' ? DETAIL_TYPE_TO_DETAIL[detail] : detail;
|
|
7832
7907
|
return self;
|
|
7833
7908
|
}
|
|
7834
7909
|
|
|
@@ -8118,11 +8193,13 @@ function convertSpanElement(domNode) {
|
|
|
8118
8193
|
// domNode is a <span> since we matched it by nodeName
|
|
8119
8194
|
const span = domNode; // Google Docs uses span tags + font-weight for bold text
|
|
8120
8195
|
|
|
8121
|
-
const hasBoldFontWeight = span.style.fontWeight === '700'; // Google Docs uses span tags + text-decoration for strikethrough text
|
|
8196
|
+
const hasBoldFontWeight = span.style.fontWeight === '700'; // Google Docs uses span tags + text-decoration: line-through for strikethrough text
|
|
8122
8197
|
|
|
8123
8198
|
const hasLinethroughTextDecoration = span.style.textDecoration === 'line-through'; // Google Docs uses span tags + font-style for italic text
|
|
8124
8199
|
|
|
8125
|
-
const hasItalicFontStyle = span.style.fontStyle === 'italic';
|
|
8200
|
+
const hasItalicFontStyle = span.style.fontStyle === 'italic'; // Google Docs uses span tags + text-decoration: underline for underline text
|
|
8201
|
+
|
|
8202
|
+
const hasUnderlineTextDecoration = span.style.textDecoration === 'underline';
|
|
8126
8203
|
return {
|
|
8127
8204
|
forChild: lexicalNode => {
|
|
8128
8205
|
if ($isTextNode(lexicalNode) && hasBoldFontWeight) {
|
|
@@ -8137,6 +8214,10 @@ function convertSpanElement(domNode) {
|
|
|
8137
8214
|
lexicalNode.toggleFormat('italic');
|
|
8138
8215
|
}
|
|
8139
8216
|
|
|
8217
|
+
if ($isTextNode(lexicalNode) && hasUnderlineTextDecoration) {
|
|
8218
|
+
lexicalNode.toggleFormat('underline');
|
|
8219
|
+
}
|
|
8220
|
+
|
|
8140
8221
|
return lexicalNode;
|
|
8141
8222
|
},
|
|
8142
8223
|
node: null
|
|
@@ -8162,9 +8243,9 @@ function convertBringAttentionToElement(domNode) {
|
|
|
8162
8243
|
|
|
8163
8244
|
function convertTextDOMNode(domNode) {
|
|
8164
8245
|
const {
|
|
8165
|
-
parentElement
|
|
8166
|
-
textContent
|
|
8246
|
+
parentElement
|
|
8167
8247
|
} = domNode;
|
|
8248
|
+
const textContent = domNode.textContent || '';
|
|
8168
8249
|
const textContentTrim = textContent.trim();
|
|
8169
8250
|
const isPre = parentElement != null && parentElement.tagName.toLowerCase() === 'pre';
|
|
8170
8251
|
|
|
@@ -8261,10 +8342,8 @@ class ParagraphNode extends ElementNode {
|
|
|
8261
8342
|
element
|
|
8262
8343
|
} = super.exportDOM(editor);
|
|
8263
8344
|
|
|
8264
|
-
if (element) {
|
|
8265
|
-
|
|
8266
|
-
element.append(document.createElement('br'));
|
|
8267
|
-
}
|
|
8345
|
+
if (element && this.isEmpty()) {
|
|
8346
|
+
element.append(document.createElement('br'));
|
|
8268
8347
|
}
|
|
8269
8348
|
|
|
8270
8349
|
return {
|
|
@@ -8388,9 +8467,7 @@ function initializeConversionCache(nodes) {
|
|
|
8388
8467
|
const conversionCache = new Map();
|
|
8389
8468
|
const handledConversions = new Set();
|
|
8390
8469
|
nodes.forEach(node => {
|
|
8391
|
-
const importDOM =
|
|
8392
|
-
node.klass.importDOM != null ? // @ts-expect-error TODO Replace Class utility type with InstanceType
|
|
8393
|
-
node.klass.importDOM.bind(node.klass) : null;
|
|
8470
|
+
const importDOM = node.klass.importDOM != null ? node.klass.importDOM.bind(node.klass) : null;
|
|
8394
8471
|
|
|
8395
8472
|
if (importDOM == null || handledConversions.has(importDOM)) {
|
|
8396
8473
|
return;
|
|
@@ -8458,7 +8535,7 @@ function createEditor(editorConfig) {
|
|
|
8458
8535
|
if (proto instanceof DecoratorNode) {
|
|
8459
8536
|
// eslint-disable-next-line no-prototype-builtins
|
|
8460
8537
|
if (!proto.hasOwnProperty('decorate')) {
|
|
8461
|
-
console.warn(`${
|
|
8538
|
+
console.warn(`${proto.constructor.name} must implement "decorate" method`);
|
|
8462
8539
|
}
|
|
8463
8540
|
}
|
|
8464
8541
|
|
|
@@ -8472,8 +8549,7 @@ function createEditor(editorConfig) {
|
|
|
8472
8549
|
console.warn(`${name} should implement "exportJSON" method to ensure JSON and default HTML serialization works as expected`);
|
|
8473
8550
|
}
|
|
8474
8551
|
}
|
|
8475
|
-
}
|
|
8476
|
-
|
|
8552
|
+
}
|
|
8477
8553
|
|
|
8478
8554
|
const type = klass.getType();
|
|
8479
8555
|
registeredNodes.set(type, {
|
|
@@ -8487,7 +8563,7 @@ function createEditor(editorConfig) {
|
|
|
8487
8563
|
disableEvents,
|
|
8488
8564
|
namespace,
|
|
8489
8565
|
theme
|
|
8490
|
-
}, onError, initializeConversionCache(registeredNodes), isReadOnly);
|
|
8566
|
+
}, onError ? onError : console.error, initializeConversionCache(registeredNodes), isReadOnly);
|
|
8491
8567
|
|
|
8492
8568
|
if (initialEditorState !== undefined) {
|
|
8493
8569
|
editor._pendingEditorState = initialEditorState;
|
|
@@ -8626,7 +8702,6 @@ class LexicalEditor {
|
|
|
8626
8702
|
}
|
|
8627
8703
|
|
|
8628
8704
|
registerMutationListener(klass, listener) {
|
|
8629
|
-
// @ts-expect-error TODO Replace Class utility type with InstanceType
|
|
8630
8705
|
const registeredNode = this._nodes.get(klass.getType());
|
|
8631
8706
|
|
|
8632
8707
|
if (registeredNode === undefined) {
|
|
@@ -8643,7 +8718,6 @@ class LexicalEditor {
|
|
|
8643
8718
|
}
|
|
8644
8719
|
|
|
8645
8720
|
registerNodeTransform(klass, listener) {
|
|
8646
|
-
// @ts-expect-error TODO Replace Class utility type with InstanceType
|
|
8647
8721
|
const type = klass.getType();
|
|
8648
8722
|
|
|
8649
8723
|
const registeredNode = this._nodes.get(type);
|
|
@@ -8664,8 +8738,7 @@ class LexicalEditor {
|
|
|
8664
8738
|
|
|
8665
8739
|
hasNodes(nodes) {
|
|
8666
8740
|
for (let i = 0; i < nodes.length; i++) {
|
|
8667
|
-
const klass = nodes[i];
|
|
8668
|
-
|
|
8741
|
+
const klass = nodes[i];
|
|
8669
8742
|
const type = klass.getType();
|
|
8670
8743
|
|
|
8671
8744
|
if (!this._nodes.has(type)) {
|
|
@@ -8827,8 +8900,10 @@ class LexicalEditor {
|
|
|
8827
8900
|
}
|
|
8828
8901
|
|
|
8829
8902
|
setReadOnly(readOnly) {
|
|
8830
|
-
this._readOnly
|
|
8831
|
-
|
|
8903
|
+
if (this._readOnly !== readOnly) {
|
|
8904
|
+
this._readOnly = readOnly;
|
|
8905
|
+
triggerListeners('readonly', this, true, readOnly);
|
|
8906
|
+
}
|
|
8832
8907
|
}
|
|
8833
8908
|
|
|
8834
8909
|
toJSON() {
|
|
@@ -8846,7 +8921,7 @@ class LexicalEditor {
|
|
|
8846
8921
|
* LICENSE file in the root directory of this source tree.
|
|
8847
8922
|
*
|
|
8848
8923
|
*/
|
|
8849
|
-
const VERSION = '0.3.
|
|
8924
|
+
const VERSION = '0.3.6';
|
|
8850
8925
|
|
|
8851
8926
|
/**
|
|
8852
8927
|
* Copyright (c) Meta Platforms, Inc. and affiliates.
|