@mx-space/cli 0.13.1 → 0.13.3
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/README.md +60 -1
- package/ROADMAP.md +11 -8
- package/dist/{Lexical.dev-By5dOKBN.mjs → Lexical.dev-DTxuYHmG.mjs} +2267 -431
- package/dist/{Lexical.node-fXM8Jp7p.mjs → Lexical.node-BlCLnfA6.mjs} +47 -10
- package/dist/Lexical.prod-CeB9UQuo.mjs +6816 -0
- package/dist/{LexicalClipboard.dev--HxGoSkO.mjs → LexicalClipboard.dev-CdFkLR_D.mjs} +131 -39
- package/dist/{LexicalClipboard.node-C3mRbrmW.mjs → LexicalClipboard.node-ktUajxsv.mjs} +2 -2
- package/dist/LexicalClipboard.prod-DliyLofW.mjs +429 -0
- package/dist/{LexicalCodeCore.dev-DjSrd4A4.mjs → LexicalCodeCore.dev-CL9tHWJX.mjs} +81 -67
- package/dist/LexicalCodeCore.prod-BoMSJc29.mjs +651 -0
- package/dist/LexicalDragon.dev-CqW7Aq5H.mjs +186 -0
- package/dist/{LexicalDragon.node-BVhw4C7s.mjs → LexicalDragon.node-DLXctJyy.mjs} +3 -2
- package/dist/LexicalDragon.prod-DHI3T6n5.mjs +121 -0
- package/dist/{LexicalExtension.dev-BPNyvGqe.mjs → LexicalExtension.dev-BP-18zns.mjs} +352 -38
- package/dist/{LexicalExtension.node-BVlcrgOx.mjs → LexicalExtension.node-BWH6xbzG.mjs} +9 -4
- package/dist/{LexicalExtension.prod-DFKbiNt-.mjs → LexicalExtension.prod-Cs6OgrDn.mjs} +479 -330
- package/dist/{LexicalHeadless.dev-B-cj7Pr5.mjs → LexicalHeadless.dev-DJp__UcP.mjs} +2 -2
- package/dist/{LexicalHeadless.prod-Byp1vNzT.mjs → LexicalHeadless.prod-o0v9cIu5.mjs} +2 -2
- package/dist/{LexicalHtml.dev-prBAwszN.mjs → LexicalHtml.dev-DoymwFpG.mjs} +327 -269
- package/dist/{LexicalHtml.node-BvNF96jZ.mjs → LexicalHtml.node-CVkbWtUA.mjs} +6 -4
- package/dist/{LexicalHtml.prod-Sz3CW1ht.mjs → LexicalHtml.prod-C2b3z99k.mjs} +355 -353
- package/dist/{LexicalLink.dev-NySTYhVR.mjs → LexicalLink.dev-7cgLOLIe.mjs} +70 -59
- package/dist/{LexicalLink.prod-BuCM8gts.mjs → LexicalLink.prod-DWFgoXHR.mjs} +211 -212
- package/dist/{LexicalList.dev-DIMOvSFD.mjs → LexicalList.dev-Ci2iOxFx.mjs} +246 -198
- package/dist/LexicalList.prod-D0xX5d3G.mjs +944 -0
- package/dist/{LexicalMarkdown.dev-C7aylvCG.mjs → LexicalMarkdown.dev-C0ZYCyuR.mjs} +130 -38
- package/dist/LexicalMarkdown.prod-0M-Nc-rh.mjs +932 -0
- package/dist/{LexicalRichText.dev-DfICq6lU.mjs → LexicalRichText.dev-Cnr1kDym.mjs} +151 -122
- package/dist/{LexicalRichText.node-Bg9jND3Q.mjs → LexicalRichText.node-BUJZAiap.mjs} +8 -11
- package/dist/LexicalRichText.prod-BfbMQ9uM.mjs +538 -0
- package/dist/{LexicalSelection.dev-DGjj12wW.mjs → LexicalSelection.dev-C4L7l8OB.mjs} +10 -9
- package/dist/{LexicalSelection.node-BU5L4193.mjs → LexicalSelection.node-CLKroUMQ.mjs} +4 -4
- package/dist/{LexicalSelection.prod-D-PwRbyK.mjs → LexicalSelection.prod-DzFqpTlw.mjs} +144 -146
- package/dist/{LexicalTable.dev-ChP7cugd.mjs → LexicalTable.dev-Cc9-zqKa.mjs} +186 -121
- package/dist/LexicalTable.prod-BgO4nCxy.mjs +2336 -0
- package/dist/{LexicalUtils.dev-BiFU3789.mjs → LexicalUtils.dev-BRgK0L6G.mjs} +375 -35
- package/dist/{LexicalUtils.node-j3Llm7Y3.mjs → LexicalUtils.node-BVAwOkL4.mjs} +24 -12
- package/dist/LexicalUtils.prod-C1gtvVDP.mjs +504 -0
- package/dist/bin/mxs.mjs +1 -1
- package/dist/{esm-DFrz5rIo.mjs → esm-BNu4sUWV.mjs} +220 -185
- package/dist/esm-jbwcVZth.mjs +2 -0
- package/dist/index.d.mts +46 -17
- package/dist/index.mjs +1 -1
- package/dist/{mxs-DXpzbUf4.mjs → mxs-zPvjkoNC.mjs} +8235 -6041
- package/dist/vendor/litexml/cli.mjs +24150 -0
- package/dist/vendor/litexml/litexml-html-preview-client.css +8862 -0
- package/dist/vendor/litexml/litexml-html-preview-client.js +163816 -0
- package/dist/vendor/litexml/style.css +96 -0
- package/package.json +21 -22
- package/skills/commands-ai.md +115 -0
- package/skills/commands-preview.md +3 -3
- package/skills/overview.md +1 -0
- package/dist/Lexical.prod-BlCvXPGa.mjs +0 -6088
- package/dist/LexicalClipboard.prod-DNJzFMcT.mjs +0 -371
- package/dist/LexicalCodeCore.prod-DTDShkR3.mjs +0 -642
- package/dist/LexicalDragon.dev-DwprRH0z.mjs +0 -88
- package/dist/LexicalDragon.prod-nh4J-8vn.mjs +0 -59
- package/dist/LexicalList.prod-MVqfA6Vo.mjs +0 -925
- package/dist/LexicalMarkdown.prod-CfQSM406.mjs +0 -868
- package/dist/LexicalRichText.prod-GsFzCK-o.mjs +0 -550
- package/dist/LexicalTable.prod-Bpr9YRXp.mjs +0 -2311
- package/dist/LexicalUtils.prod-DCvrA78p.mjs +0 -373
- package/dist/esm-DXO9Afik.mjs +0 -2
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
//#region ../../node_modules/.pnpm/lexical@0.
|
|
1
|
+
//#region ../../node_modules/.pnpm/lexical@0.46.0_typescript@6.0.3/node_modules/lexical/dist/Lexical.dev.mjs
|
|
2
2
|
/**
|
|
3
3
|
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
4
4
|
*
|
|
@@ -135,6 +135,14 @@ function $getActiveBlockCursorElement() {
|
|
|
135
135
|
return $getEditor()._blockCursorElement;
|
|
136
136
|
}
|
|
137
137
|
/**
|
|
138
|
+
* A slot value renders slots-first into its own `[data-lexical-slot]`
|
|
139
|
+
* container, prepended ahead of the host's linked-list children. The leading
|
|
140
|
+
* boundary skips these so they are never counted as managed children.
|
|
141
|
+
*/
|
|
142
|
+
function isSlotContainerDOM(node) {
|
|
143
|
+
return node !== null && node.nodeType === 1 && node.hasAttribute("data-lexical-slot");
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
138
146
|
* Base class for DOM slots — a pointer to the content-bearing element of a
|
|
139
147
|
* node's DOM, plus optional `before` / `after` boundaries marking where the
|
|
140
148
|
* lexical-managed content sits inside that element.
|
|
@@ -315,9 +323,14 @@ var ElementDOMSlot = class ElementDOMSlot extends DOMSlot {
|
|
|
315
323
|
* a block cursor among their children, so the base slot stays editor-free.
|
|
316
324
|
*/
|
|
317
325
|
getFirstChildAnchor() {
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
326
|
+
let anchor = super.getFirstChildAnchor();
|
|
327
|
+
let node = anchor ? anchor.nextSibling : this.element.firstChild;
|
|
328
|
+
while (isSlotContainerDOM(node)) {
|
|
329
|
+
anchor = node;
|
|
330
|
+
node = node.nextSibling;
|
|
331
|
+
}
|
|
332
|
+
const firstChild = anchor ? anchor.nextSibling : this.element.firstChild;
|
|
333
|
+
return firstChild !== null && firstChild === $getActiveBlockCursorElement() ? firstChild : anchor;
|
|
321
334
|
}
|
|
322
335
|
/**
|
|
323
336
|
* @internal
|
|
@@ -356,10 +369,11 @@ var ElementDOMSlot = class ElementDOMSlot extends DOMSlot {
|
|
|
356
369
|
const element = this.element;
|
|
357
370
|
const before = this.before;
|
|
358
371
|
const br = document.createElement("br");
|
|
372
|
+
br.setAttribute("data-lexical-managed-linebreak", "true");
|
|
359
373
|
element.insertBefore(br, before);
|
|
360
374
|
if (webkitHack) {
|
|
361
375
|
const img = document.createElement("img");
|
|
362
|
-
img.setAttribute("data-lexical-linebreak", "true");
|
|
376
|
+
img.setAttribute("data-lexical-managed-linebreak", "true");
|
|
363
377
|
img.style.setProperty("display", "inline", "important");
|
|
364
378
|
img.style.setProperty("border", "0px", "important");
|
|
365
379
|
img.style.setProperty("margin", "0px", "important");
|
|
@@ -434,9 +448,9 @@ function indexPath(root, child) {
|
|
|
434
448
|
*/
|
|
435
449
|
let envLexicalVersion;
|
|
436
450
|
try {
|
|
437
|
-
envLexicalVersion = "0.
|
|
451
|
+
envLexicalVersion = "0.46.0+dev.esm";
|
|
438
452
|
} catch (_unused) {}
|
|
439
|
-
const LEXICAL_VERSION = envLexicalVersion ?? "
|
|
453
|
+
const LEXICAL_VERSION = envLexicalVersion ?? "\"<unknown>+source\"";
|
|
440
454
|
/**
|
|
441
455
|
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
442
456
|
*
|
|
@@ -681,15 +695,25 @@ function $garbageCollectDetachedDecorators(editor, pendingEditorState) {
|
|
|
681
695
|
}
|
|
682
696
|
}
|
|
683
697
|
function $garbageCollectDetachedDeepChildNodes(node, parentKey, prevNodeMap, nodeMap, nodeMapDelete, dirtyNodes) {
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
if (
|
|
689
|
-
|
|
690
|
-
|
|
698
|
+
if ($isElementNode(node)) {
|
|
699
|
+
let child = node.getFirstChild();
|
|
700
|
+
while (child !== null) {
|
|
701
|
+
const childKey = child.__key;
|
|
702
|
+
if (child.__parent === parentKey) {
|
|
703
|
+
if ($isElementNode(child) || $isSlotHost(child) && child.__slots !== null) $garbageCollectDetachedDeepChildNodes(child, childKey, prevNodeMap, nodeMap, nodeMapDelete, dirtyNodes);
|
|
704
|
+
if (!prevNodeMap.has(childKey)) dirtyNodes.delete(childKey);
|
|
705
|
+
nodeMapDelete.push(childKey);
|
|
706
|
+
}
|
|
707
|
+
child = child.getNextSibling();
|
|
708
|
+
}
|
|
709
|
+
}
|
|
710
|
+
for (const slotKey of $isSlotHost(node) && node.__slots !== null ? node.__slots.values() : []) {
|
|
711
|
+
const slotNode = nodeMap.get(slotKey);
|
|
712
|
+
if (slotNode !== void 0 && $isSlotChild(slotNode) && slotNode.__slotHost === parentKey) {
|
|
713
|
+
if ($isElementNode(slotNode) || $isSlotHost(slotNode) && slotNode.__slots !== null) $garbageCollectDetachedDeepChildNodes(slotNode, slotKey, prevNodeMap, nodeMap, nodeMapDelete, dirtyNodes);
|
|
714
|
+
if (!prevNodeMap.has(slotKey)) dirtyNodes.delete(slotKey);
|
|
715
|
+
nodeMapDelete.push(slotKey);
|
|
691
716
|
}
|
|
692
|
-
child = child.getNextSibling();
|
|
693
717
|
}
|
|
694
718
|
}
|
|
695
719
|
function $garbageCollectDetachedNodes(prevEditorState, editorState, dirtyLeaves, dirtyElements) {
|
|
@@ -706,14 +730,18 @@ function $garbageCollectDetachedNodes(prevEditorState, editorState, dirtyLeaves,
|
|
|
706
730
|
}
|
|
707
731
|
}
|
|
708
732
|
}
|
|
709
|
-
for (const nodeKey of nodeMapDelete) nodeMap.delete(nodeKey);
|
|
710
733
|
for (const nodeKey of dirtyLeaves) {
|
|
711
734
|
const node = nodeMap.get(nodeKey);
|
|
712
735
|
if (node !== void 0 && !node.isAttached()) {
|
|
736
|
+
if ($isSlotHost(node) && node.__slots !== null) $garbageCollectDetachedDeepChildNodes(node, nodeKey, prevNodeMap, nodeMap, nodeMapDelete, dirtyLeaves);
|
|
713
737
|
if (!prevNodeMap.has(nodeKey)) dirtyLeaves.delete(nodeKey);
|
|
714
|
-
|
|
738
|
+
nodeMapDelete.push(nodeKey);
|
|
715
739
|
}
|
|
716
740
|
}
|
|
741
|
+
for (const nodeKey of nodeMapDelete) nodeMap.delete(nodeKey);
|
|
742
|
+
const editor = getActiveEditor();
|
|
743
|
+
const compositionKey = editor._compositionKey;
|
|
744
|
+
if (compositionKey !== null && !nodeMap.has(compositionKey)) editor._compositionKey = null;
|
|
717
745
|
}
|
|
718
746
|
/**
|
|
719
747
|
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
@@ -740,18 +768,19 @@ function isManagedLineBreak(dom, target, editor) {
|
|
|
740
768
|
return lexicalLineBreak && (dom === lexicalLineBreak || isBR && dom.previousSibling === lexicalLineBreak) || isBR && getNodeKeyFromDOMNode(dom, editor) !== void 0;
|
|
741
769
|
}
|
|
742
770
|
function getLastSelection(editor) {
|
|
743
|
-
return editor.
|
|
771
|
+
return editor.read("latest", () => {
|
|
744
772
|
const selection = $getSelection();
|
|
745
773
|
return selection !== null ? selection.clone() : null;
|
|
746
774
|
});
|
|
747
775
|
}
|
|
748
776
|
function $handleTextMutation(target, node, editor) {
|
|
749
777
|
const domSelection = getDOMSelection(getWindow(editor));
|
|
778
|
+
const domSelectionPoints = domSelection && getDOMSelectionPoints(domSelection, editor._rootElement);
|
|
750
779
|
let anchorOffset = null;
|
|
751
780
|
let focusOffset = null;
|
|
752
|
-
if (
|
|
753
|
-
anchorOffset =
|
|
754
|
-
focusOffset =
|
|
781
|
+
if (domSelectionPoints !== null && domSelectionPoints.anchorNode === target) {
|
|
782
|
+
anchorOffset = domSelectionPoints.anchorOffset;
|
|
783
|
+
focusOffset = domSelectionPoints.focusOffset;
|
|
755
784
|
}
|
|
756
785
|
const text = target.nodeValue;
|
|
757
786
|
if (text !== null) $updateTextNodeFromDOMContent(node, text, anchorOffset, focusOffset, false);
|
|
@@ -763,13 +792,13 @@ function shouldUpdateTextNodeFromMutation(selection, targetDOM, targetNode) {
|
|
|
763
792
|
}
|
|
764
793
|
return isDOMTextNode(targetDOM) && targetNode.isAttached();
|
|
765
794
|
}
|
|
766
|
-
function $getNearestManagedNodePairFromDOMNode(startingDOM, editor, editorState
|
|
795
|
+
function $getNearestManagedNodePairFromDOMNode(startingDOM, editor, editorState) {
|
|
767
796
|
for (let dom = startingDOM; dom && !isDOMUnmanaged(dom); dom = getParentElement(dom)) {
|
|
768
797
|
const key = getNodeKeyFromDOMNode(dom, editor);
|
|
769
798
|
if (key !== void 0) {
|
|
770
799
|
const node = $getNodeByKey(key, editorState);
|
|
771
800
|
if (node) return $isDecoratorNode(node) || !isHTMLElement(dom) ? void 0 : [dom, node];
|
|
772
|
-
}
|
|
801
|
+
}
|
|
773
802
|
}
|
|
774
803
|
}
|
|
775
804
|
function flushMutations(editor, mutations, observer) {
|
|
@@ -779,7 +808,6 @@ function flushMutations(editor, mutations, observer) {
|
|
|
779
808
|
updateEditorSync(editor, () => {
|
|
780
809
|
const selection = $getSelection() || getLastSelection(editor);
|
|
781
810
|
const badDOMTargets = /* @__PURE__ */ new Map();
|
|
782
|
-
const rootElement = editor.getRootElement();
|
|
783
811
|
const currentEditorState = editor._editorState;
|
|
784
812
|
const blockCursorElement = editor._blockCursorElement;
|
|
785
813
|
let shouldRevertSelection = false;
|
|
@@ -788,7 +816,7 @@ function flushMutations(editor, mutations, observer) {
|
|
|
788
816
|
const mutation = mutations[i];
|
|
789
817
|
const type = mutation.type;
|
|
790
818
|
const targetDOM = mutation.target;
|
|
791
|
-
const pair = $getNearestManagedNodePairFromDOMNode(targetDOM, editor, currentEditorState
|
|
819
|
+
const pair = $getNearestManagedNodePairFromDOMNode(targetDOM, editor, currentEditorState);
|
|
792
820
|
if (!pair) continue;
|
|
793
821
|
const [nodeDOM, targetNode] = pair;
|
|
794
822
|
if (type === "characterData") {
|
|
@@ -800,7 +828,7 @@ function flushMutations(editor, mutations, observer) {
|
|
|
800
828
|
const addedDOM = addedDOMs[s];
|
|
801
829
|
const node = $getNodeFromDOMNode(addedDOM);
|
|
802
830
|
const parentDOM = addedDOM.parentNode;
|
|
803
|
-
if (parentDOM != null && addedDOM !== blockCursorElement && node === null && !isManagedLineBreak(addedDOM, parentDOM, editor) && !isDOMUnmanaged(addedDOM)) {
|
|
831
|
+
if (parentDOM != null && addedDOM !== blockCursorElement && node === null && !isManagedLineBreak(addedDOM, parentDOM, editor) && !(editor._slotsUsed && isHTMLElement(addedDOM) && addedDOM.hasAttribute("data-lexical-slot")) && !isDOMUnmanaged(addedDOM)) {
|
|
804
832
|
if (IS_FIREFOX) {
|
|
805
833
|
const possibleText = (isHTMLElement(addedDOM) ? addedDOM.innerText : null) || addedDOM.nodeValue;
|
|
806
834
|
if (possibleText) possibleTextForFirefoxPaste += possibleText;
|
|
@@ -858,6 +886,17 @@ function initMutationObserver(editor) {
|
|
|
858
886
|
});
|
|
859
887
|
}
|
|
860
888
|
/**
|
|
889
|
+
* Read the state directly from the given object without `node.getLatest()`.
|
|
890
|
+
* Safe to use outside of editor state context or to read a previous version,
|
|
891
|
+
* equivalent to reading the property directly.
|
|
892
|
+
*/
|
|
893
|
+
const NODE_STATE_DIRECT = "direct";
|
|
894
|
+
/**
|
|
895
|
+
* Use `node.getLatest()` before reading the state, per the lexical convention
|
|
896
|
+
* of only working with the latest version of a node.
|
|
897
|
+
*/
|
|
898
|
+
const NODE_STATE_LATEST = "latest";
|
|
899
|
+
/**
|
|
861
900
|
* Get the value type (V) from a StateConfig
|
|
862
901
|
*/
|
|
863
902
|
/**
|
|
@@ -996,21 +1035,21 @@ function createState(key, valueConfig) {
|
|
|
996
1035
|
* state on the given node, and will return `stateConfig.defaultValue` if the
|
|
997
1036
|
* state has never been set on this node.
|
|
998
1037
|
*
|
|
999
|
-
* The `version` parameter is optional and should generally be
|
|
1038
|
+
* The `version` parameter is optional and should generally be {@link NODE_STATE_LATEST},
|
|
1000
1039
|
* consistent with the behavior of other node methods and functions,
|
|
1001
1040
|
* but for certain use cases such as `updateDOM` you may have a need to
|
|
1002
|
-
* use
|
|
1041
|
+
* use {@link NODE_STATE_DIRECT} to read the state from a previous version of the node.
|
|
1003
1042
|
*
|
|
1004
|
-
* For very advanced use cases, you can expect that
|
|
1043
|
+
* For very advanced use cases, you can expect that {@link NODE_STATE_DIRECT} does not
|
|
1005
1044
|
* require an editor state, just like directly accessing other properties
|
|
1006
1045
|
* of a node without an accessor (e.g. `textNode.__text`).
|
|
1007
1046
|
*
|
|
1008
1047
|
* @param node Any LexicalNode
|
|
1009
1048
|
* @param stateConfig The configuration of the state to read
|
|
1010
|
-
* @param version The default value
|
|
1049
|
+
* @param version The default value {@link NODE_STATE_LATEST} will read the latest version of the node state, {@link NODE_STATE_DIRECT} will read the version that is stored on this LexicalNode which not reflect the version used in the current editor state
|
|
1011
1050
|
* @returns The current value from the state, or the default value provided by the configuration.
|
|
1012
1051
|
*/
|
|
1013
|
-
function $getState(node, stateConfig, version =
|
|
1052
|
+
function $getState(node, stateConfig, version = NODE_STATE_LATEST) {
|
|
1014
1053
|
const state = (version === "latest" ? node.getLatest() : node).__state;
|
|
1015
1054
|
if (state) {
|
|
1016
1055
|
$checkCollision(node, stateConfig, state);
|
|
@@ -1020,11 +1059,11 @@ function $getState(node, stateConfig, version = "latest") {
|
|
|
1020
1059
|
}
|
|
1021
1060
|
/**
|
|
1022
1061
|
* Given two versions of a node and a stateConfig, compare their state values
|
|
1023
|
-
* using `$getState(nodeVersion, stateConfig,
|
|
1062
|
+
* using `$getState(nodeVersion, stateConfig, NODE_STATE_DIRECT)`.
|
|
1024
1063
|
* If the values are equal according to `stateConfig.isEqual`, return `null`,
|
|
1025
1064
|
* otherwise return `[value, prevValue]`.
|
|
1026
1065
|
*
|
|
1027
|
-
* This is useful for implementing updateDOM. Note that the `
|
|
1066
|
+
* This is useful for implementing updateDOM. Note that the `NODE_STATE_DIRECT`
|
|
1028
1067
|
* version argument is used for both nodes.
|
|
1029
1068
|
*
|
|
1030
1069
|
* @param node Any LexicalNode
|
|
@@ -1033,8 +1072,8 @@ function $getState(node, stateConfig, version = "latest") {
|
|
|
1033
1072
|
* @returns `[value, prevValue]` if changed, otherwise `null`
|
|
1034
1073
|
*/
|
|
1035
1074
|
function $getStateChange(node, prevNode, stateConfig) {
|
|
1036
|
-
const value = $getState(node, stateConfig,
|
|
1037
|
-
const prevValue = $getState(prevNode, stateConfig,
|
|
1075
|
+
const value = $getState(node, stateConfig, NODE_STATE_DIRECT);
|
|
1076
|
+
const prevValue = $getState(prevNode, stateConfig, NODE_STATE_DIRECT);
|
|
1038
1077
|
return stateConfig.isEqual(value, prevValue) ? null : [value, prevValue];
|
|
1039
1078
|
}
|
|
1040
1079
|
/**
|
|
@@ -1100,16 +1139,13 @@ function $checkCollision(node, stateConfig, state) {
|
|
|
1100
1139
|
function createSharedNodeState(nodeConfig) {
|
|
1101
1140
|
const sharedConfigMap = /* @__PURE__ */ new Map();
|
|
1102
1141
|
const flatKeys = /* @__PURE__ */ new Set();
|
|
1103
|
-
for (
|
|
1104
|
-
|
|
1105
|
-
if (
|
|
1106
|
-
|
|
1107
|
-
if (
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
} else stateConfig = requiredStateConfig;
|
|
1111
|
-
sharedConfigMap.set(stateConfig.key, stateConfig);
|
|
1112
|
-
}
|
|
1142
|
+
for (const { ownNodeConfig } of iterStaticNodeConfigChain(typeof nodeConfig === "function" ? nodeConfig : nodeConfig.replace)) if (ownNodeConfig && ownNodeConfig.stateConfigs) for (const requiredStateConfig of ownNodeConfig.stateConfigs) {
|
|
1143
|
+
let stateConfig;
|
|
1144
|
+
if ("stateConfig" in requiredStateConfig) {
|
|
1145
|
+
stateConfig = requiredStateConfig.stateConfig;
|
|
1146
|
+
if (requiredStateConfig.flat) flatKeys.add(stateConfig.key);
|
|
1147
|
+
} else stateConfig = requiredStateConfig;
|
|
1148
|
+
sharedConfigMap.set(stateConfig.key, stateConfig);
|
|
1113
1149
|
}
|
|
1114
1150
|
return {
|
|
1115
1151
|
flatKeys,
|
|
@@ -1117,6 +1153,19 @@ function createSharedNodeState(nodeConfig) {
|
|
|
1117
1153
|
};
|
|
1118
1154
|
}
|
|
1119
1155
|
/**
|
|
1156
|
+
* Keys that must never be written into an {@link UnknownStateRecord} from
|
|
1157
|
+
* serialized (potentially untrusted) input. Writing a `__proto__` entry would
|
|
1158
|
+
* re-parent the record's prototype, and because {@link NodeState.getValue}
|
|
1159
|
+
* resolves keys with the `in` operator (which walks the prototype chain) an
|
|
1160
|
+
* attacker could otherwise inject arbitrary state values via a crafted
|
|
1161
|
+
* `__proto__`. These are never produced by {@link createState}.
|
|
1162
|
+
*/
|
|
1163
|
+
const UNSAFE_STATE_KEYS = /* @__PURE__ */ new Set([
|
|
1164
|
+
"__proto__",
|
|
1165
|
+
"constructor",
|
|
1166
|
+
"prototype"
|
|
1167
|
+
]);
|
|
1168
|
+
/**
|
|
1120
1169
|
* @internal
|
|
1121
1170
|
*
|
|
1122
1171
|
* A Map of string keys to state configurations to be shared across nodes
|
|
@@ -1299,6 +1348,7 @@ var NodeState = class NodeState {
|
|
|
1299
1348
|
* @param v The unknown value from an UnknownStateRecord
|
|
1300
1349
|
*/
|
|
1301
1350
|
updateFromUnknown(k, v) {
|
|
1351
|
+
if (UNSAFE_STATE_KEYS.has(k)) return;
|
|
1302
1352
|
const stateConfig = this.sharedNodeState.sharedConfigMap.get(k);
|
|
1303
1353
|
if (stateConfig) this.updateFromKnown(stateConfig, stateConfig.parse(v));
|
|
1304
1354
|
else {
|
|
@@ -1418,6 +1468,7 @@ function coerceToJSON(v) {
|
|
|
1418
1468
|
function parseAndPruneNextUnknownState(sharedConfigMap, nextKnownState, unknownState) {
|
|
1419
1469
|
let nextUnknownState = void 0;
|
|
1420
1470
|
if (unknownState) for (const [k, v] of Object.entries(unknownState)) {
|
|
1471
|
+
if (UNSAFE_STATE_KEYS.has(k)) continue;
|
|
1421
1472
|
const stateConfig = sharedConfigMap.get(k);
|
|
1422
1473
|
if (stateConfig) {
|
|
1423
1474
|
if (!nextKnownState.has(stateConfig)) nextKnownState.set(stateConfig, stateConfig.parse(v));
|
|
@@ -1681,7 +1732,14 @@ function $destroyNode(key, parentDOM) {
|
|
|
1681
1732
|
const children = $createChildrenArray(node, activePrevNodeMap);
|
|
1682
1733
|
$destroyChildren(children, 0, children.length - 1, null);
|
|
1683
1734
|
}
|
|
1684
|
-
if (node !== void 0)
|
|
1735
|
+
if (node !== void 0) {
|
|
1736
|
+
for (const slotKey of $readSlots(node).values()) {
|
|
1737
|
+
const container = $slotContainerForKey(slotKey);
|
|
1738
|
+
$destroyNode(slotKey, null);
|
|
1739
|
+
if (container !== null) container.remove();
|
|
1740
|
+
}
|
|
1741
|
+
setMutatedNode(mutatedNodes, activeEditorNodes, activeMutationListeners, node, "destroyed");
|
|
1742
|
+
}
|
|
1685
1743
|
}
|
|
1686
1744
|
function $destroyChildren(children, _startIndex, endIndex, dom) {
|
|
1687
1745
|
for (let startIndex = _startIndex; startIndex <= endIndex; ++startIndex) {
|
|
@@ -1716,7 +1774,8 @@ function $getReconciledDirection(node) {
|
|
|
1716
1774
|
const direction = node.__dir;
|
|
1717
1775
|
if (direction !== null) return direction;
|
|
1718
1776
|
if ($isRootNode(node)) return null;
|
|
1719
|
-
const parent = node.
|
|
1777
|
+
const parent = node.getParent();
|
|
1778
|
+
if (parent === null) return "auto";
|
|
1720
1779
|
if (!$isRootOrShadowRoot(parent) || parent.__dir !== null) return null;
|
|
1721
1780
|
return "auto";
|
|
1722
1781
|
}
|
|
@@ -1725,34 +1784,145 @@ function $setElementDirection(dom, node) {
|
|
|
1725
1784
|
if (direction !== null) dom.dir = direction;
|
|
1726
1785
|
else dom.removeAttribute("dir");
|
|
1727
1786
|
}
|
|
1787
|
+
function createSlotDOM(name) {
|
|
1788
|
+
const container = document.createElement("div");
|
|
1789
|
+
container.setAttribute("data-lexical-slot", name);
|
|
1790
|
+
container.style.display = "none";
|
|
1791
|
+
return container;
|
|
1792
|
+
}
|
|
1793
|
+
function $applySlotEditable(hostDom, decoratorHost, container) {
|
|
1794
|
+
if (decoratorHost || hostDom.contentEditable === "false") $markSlotEditable(container, activeEditor$1);
|
|
1795
|
+
else container.removeAttribute("contenteditable");
|
|
1796
|
+
}
|
|
1797
|
+
function $mountSlotChildren(node, hostDom, slots) {
|
|
1798
|
+
const previousSubTreeTextContent = subTreeTextContent;
|
|
1799
|
+
const outerSaved = $beginCaptureGuard();
|
|
1800
|
+
subTreeTextContent = "";
|
|
1801
|
+
let totalText = "";
|
|
1802
|
+
const decoratorHost = $isDecoratorNode(node);
|
|
1803
|
+
for (const [name, slotKey] of slots) {
|
|
1804
|
+
const container = createSlotDOM(name);
|
|
1805
|
+
$applySlotEditable(hostDom, decoratorHost, container);
|
|
1806
|
+
hostDom.appendChild(container);
|
|
1807
|
+
subTreeTextContent = "";
|
|
1808
|
+
const saved = $beginCaptureGuard();
|
|
1809
|
+
$createNode(slotKey, $getDOMSlot(node, container, activeEditor$1));
|
|
1810
|
+
$endCaptureGuard(saved);
|
|
1811
|
+
$applySlotTarget(node, name, hostDom, container);
|
|
1812
|
+
totalText += subTreeTextContent;
|
|
1813
|
+
}
|
|
1814
|
+
$endCaptureGuard(outerSaved);
|
|
1815
|
+
subTreeTextContent = previousSubTreeTextContent;
|
|
1816
|
+
return totalText;
|
|
1817
|
+
}
|
|
1818
|
+
function $readSlots(node) {
|
|
1819
|
+
return $isSlotHost(node) && node.__slots !== null ? node.__slots : EMPTY_SLOTS;
|
|
1820
|
+
}
|
|
1821
|
+
function $applySlotTarget(node, name, hostDom, container) {
|
|
1822
|
+
const target = activeEditorDOMRenderConfig.$getSlotTargetElement(node, name, hostDom, activeEditor$1);
|
|
1823
|
+
if (target !== null) {
|
|
1824
|
+
if (container.parentElement !== target) target.appendChild(container);
|
|
1825
|
+
container.style.display = "";
|
|
1826
|
+
}
|
|
1827
|
+
}
|
|
1828
|
+
function $slotContainerForKey(slotKey) {
|
|
1829
|
+
const slotDom = activePrevKeyToDOMMap.get(slotKey);
|
|
1830
|
+
return slotDom !== void 0 ? slotDom.parentElement : null;
|
|
1831
|
+
}
|
|
1832
|
+
function $reconcileSlotChildren(prevNode, nextNode, hostDom) {
|
|
1833
|
+
const prevSlots = $readSlots(prevNode);
|
|
1834
|
+
const nextSlots = $readSlots(nextNode);
|
|
1835
|
+
for (const [name, prevSlotKey] of prevSlots) if (!nextSlots.has(name)) {
|
|
1836
|
+
const staleContainer = $slotContainerForKey(prevSlotKey);
|
|
1837
|
+
$destroyNode(prevSlotKey, null);
|
|
1838
|
+
if (staleContainer !== null) staleContainer.remove();
|
|
1839
|
+
}
|
|
1840
|
+
const previousSubTreeTextContent = subTreeTextContent;
|
|
1841
|
+
const outerSaved = $beginCaptureGuard();
|
|
1842
|
+
let totalText = "";
|
|
1843
|
+
let prevContainer = null;
|
|
1844
|
+
const decoratorHost = $isDecoratorNode(nextNode);
|
|
1845
|
+
for (const [name, nextSlotKey] of nextSlots) {
|
|
1846
|
+
const prevSlotKey = prevSlots.get(name);
|
|
1847
|
+
let container = prevSlotKey !== void 0 ? $slotContainerForKey(prevSlotKey) : null;
|
|
1848
|
+
subTreeTextContent = "";
|
|
1849
|
+
const saved = $beginCaptureGuard();
|
|
1850
|
+
if (container === null) {
|
|
1851
|
+
container = createSlotDOM(name);
|
|
1852
|
+
let firstNonSlot = null;
|
|
1853
|
+
for (const child of hostDom.children) if (!child.hasAttribute("data-lexical-slot")) {
|
|
1854
|
+
firstNonSlot = child;
|
|
1855
|
+
break;
|
|
1856
|
+
}
|
|
1857
|
+
hostDom.insertBefore(container, firstNonSlot);
|
|
1858
|
+
$createNode(nextSlotKey, $getDOMSlot(nextNode, container, activeEditor$1));
|
|
1859
|
+
} else if (prevSlotKey === nextSlotKey) $reconcileNode(nextSlotKey, container);
|
|
1860
|
+
else {
|
|
1861
|
+
if (prevSlotKey !== void 0) $destroyNode(prevSlotKey, container);
|
|
1862
|
+
$createNode(nextSlotKey, $getDOMSlot(nextNode, container, activeEditor$1));
|
|
1863
|
+
}
|
|
1864
|
+
$endCaptureGuard(saved);
|
|
1865
|
+
$applySlotEditable(hostDom, decoratorHost, container);
|
|
1866
|
+
$applySlotTarget(nextNode, name, hostDom, container);
|
|
1867
|
+
totalText += subTreeTextContent;
|
|
1868
|
+
if (container.parentElement === hostDom) {
|
|
1869
|
+
const anchor = prevContainer === null ? hostDom.firstChild : prevContainer.nextSibling;
|
|
1870
|
+
if (anchor !== container) hostDom.insertBefore(container, anchor);
|
|
1871
|
+
prevContainer = container;
|
|
1872
|
+
}
|
|
1873
|
+
}
|
|
1874
|
+
$endCaptureGuard(outerSaved);
|
|
1875
|
+
subTreeTextContent = previousSubTreeTextContent;
|
|
1876
|
+
return totalText;
|
|
1877
|
+
}
|
|
1728
1878
|
function $createNode(key, slot) {
|
|
1729
1879
|
const node = activeNextNodeMap.get(key);
|
|
1730
1880
|
if (node === void 0) formatDevErrorMessage(`createNode: node does not exist in nodeMap`);
|
|
1731
1881
|
if (slot !== null) {
|
|
1732
1882
|
const prevNode = activePrevNodeMap.get(key);
|
|
1733
|
-
if (prevNode !== void 0
|
|
1883
|
+
if (prevNode !== void 0) {
|
|
1734
1884
|
const existingDOM = activePrevKeyToDOMMap.get(key);
|
|
1735
1885
|
if (existingDOM !== void 0) {
|
|
1736
|
-
|
|
1737
|
-
|
|
1886
|
+
const prevSlotHost = $isSlotChild(prevNode) ? prevNode.__slotHost : null;
|
|
1887
|
+
const nextSlotHost = $isSlotChild(node) ? node.__slotHost : null;
|
|
1888
|
+
const modelMoved = prevNode.__parent !== node.__parent || prevSlotHost !== nextSlotHost;
|
|
1889
|
+
const slotChildDomDetached = nextSlotHost !== null && existingDOM.parentElement !== slot.element;
|
|
1890
|
+
if (modelMoved || slotChildDomDetached) {
|
|
1891
|
+
slot.insertChild(existingDOM);
|
|
1892
|
+
return $reconcileNode(key, slot.element);
|
|
1893
|
+
}
|
|
1738
1894
|
}
|
|
1739
1895
|
}
|
|
1740
1896
|
}
|
|
1741
1897
|
const dom = activeEditorDOMRenderConfig.$createDOM(node, activeEditor$1);
|
|
1742
1898
|
storeDOMWithKey(key, dom, activeEditor$1);
|
|
1743
1899
|
if ($isTextNode(node)) dom.setAttribute("data-lexical-text", "true");
|
|
1744
|
-
else if ($isDecoratorNode(node))
|
|
1900
|
+
else if ($isDecoratorNode(node)) {
|
|
1901
|
+
dom.setAttribute("data-lexical-decorator", "true");
|
|
1902
|
+
setDOMUnmanaged(dom, { captureSelection: true });
|
|
1903
|
+
}
|
|
1745
1904
|
if ($isElementNode(node)) {
|
|
1746
1905
|
const indent = node.__indent;
|
|
1747
1906
|
const childrenSize = node.__size;
|
|
1748
1907
|
$setElementDirection(dom, node);
|
|
1749
1908
|
if (indent !== 0) setElementIndent(dom, indent);
|
|
1909
|
+
const slots = $readSlots(node);
|
|
1910
|
+
const slotTextContent = slots.size > 0 ? $mountSlotChildren(node, dom, slots) : "";
|
|
1750
1911
|
if (childrenSize === 0) {
|
|
1751
|
-
dom.__lexicalTextContent =
|
|
1912
|
+
dom.__lexicalTextContent = slotTextContent;
|
|
1752
1913
|
dom.__lexicalFirstTextKey = null;
|
|
1914
|
+
subTreeTextContent += slotTextContent;
|
|
1915
|
+
if (slots.size > 0) dom.__lexicalSlotTextLength = slotTextContent.length;
|
|
1753
1916
|
} else {
|
|
1917
|
+
const outerBefore = subTreeTextContent;
|
|
1754
1918
|
const endIndex = childrenSize - 1;
|
|
1755
1919
|
$createChildren($createChildrenArray(node, activeNextNodeMap), node, 0, endIndex, $getDOMSlot(node, dom, activeEditor$1));
|
|
1920
|
+
if (slotTextContent !== "") {
|
|
1921
|
+
const childText = dom.__lexicalTextContent || "";
|
|
1922
|
+
dom.__lexicalTextContent = slotTextContent + childText;
|
|
1923
|
+
subTreeTextContent = outerBefore + slotTextContent + childText;
|
|
1924
|
+
}
|
|
1925
|
+
if (slots.size > 0) dom.__lexicalSlotTextLength = slotTextContent.length;
|
|
1756
1926
|
}
|
|
1757
1927
|
const format = node.__format;
|
|
1758
1928
|
if (format !== 0) setElementFormat(dom, format);
|
|
@@ -1763,6 +1933,8 @@ function $createNode(key, slot) {
|
|
|
1763
1933
|
const decorator = node.decorate(activeEditor$1, activeEditorConfig);
|
|
1764
1934
|
if (decorator !== null) reconcileDecorator(key, decorator);
|
|
1765
1935
|
dom.contentEditable = "false";
|
|
1936
|
+
const slots = $readSlots(node);
|
|
1937
|
+
if (slots.size > 0) $mountSlotChildren(node, dom, slots);
|
|
1766
1938
|
}
|
|
1767
1939
|
subTreeTextContent += text;
|
|
1768
1940
|
}
|
|
@@ -1801,21 +1973,21 @@ function $createChildren(children, element, _startIndex, endIndex, slot) {
|
|
|
1801
1973
|
subTreeTextContent = previousSubTreeTextContent + subTreeTextContent;
|
|
1802
1974
|
$endCaptureGuard(outerSaved);
|
|
1803
1975
|
}
|
|
1804
|
-
function isLastChildLineBreakOrDecorator(element, nodeMap) {
|
|
1976
|
+
function $isLastChildLineBreakOrDecorator(element, nodeMap) {
|
|
1805
1977
|
if (element) {
|
|
1806
1978
|
const lastKey = element.__last;
|
|
1807
1979
|
if (lastKey) {
|
|
1808
1980
|
const node = nodeMap.get(lastKey);
|
|
1809
1981
|
if (node) return $isLineBreakNode(node) ? "line-break" : $isDecoratorNode(node) && node.isInline() ? "decorator" : null;
|
|
1810
1982
|
}
|
|
1811
|
-
return "empty";
|
|
1983
|
+
return $readSlots(element).size > 0 ? null : "empty";
|
|
1812
1984
|
}
|
|
1813
1985
|
return null;
|
|
1814
1986
|
}
|
|
1815
1987
|
function $reconcileElementTerminatingLineBreak(prevElement, nextElement, dom) {
|
|
1816
1988
|
const slot = $getDOMSlot(nextElement, dom, activeEditor$1);
|
|
1817
1989
|
const prevLineBreak = slot.element.__lexicalLastChildKind ?? null;
|
|
1818
|
-
const nextLineBreak = isLastChildLineBreakOrDecorator(nextElement, activeNextNodeMap);
|
|
1990
|
+
const nextLineBreak = $isLastChildLineBreakOrDecorator(nextElement, activeNextNodeMap);
|
|
1819
1991
|
if (prevLineBreak !== nextLineBreak) slot.setManagedLineBreak(nextLineBreak);
|
|
1820
1992
|
}
|
|
1821
1993
|
function reconcileTextFormat(element) {
|
|
@@ -1982,7 +2154,9 @@ function $tryReconcileSuffixWithSizeDelta(prevElement, nextElement, slot, cacheD
|
|
|
1982
2154
|
newSuffix += text;
|
|
1983
2155
|
if (i < k - 1 && $isElementNode(node) && !node.isInline()) newSuffix += DOUBLE_LINE_BREAK;
|
|
1984
2156
|
}
|
|
1985
|
-
|
|
2157
|
+
const slotLen = cacheDom.__lexicalSlotTextLength || 0;
|
|
2158
|
+
const prevChildText = slotLen > 0 ? cachedParentText.slice(slotLen) : cachedParentText;
|
|
2159
|
+
cacheDom.__lexicalTextContent = prevChildText.slice(0, prevChildText.length - oldSuffixLength) + newSuffix;
|
|
1986
2160
|
return true;
|
|
1987
2161
|
}
|
|
1988
2162
|
/**
|
|
@@ -2084,9 +2258,11 @@ function $reconcileChildren(prevElement, nextElement, slot) {
|
|
|
2084
2258
|
cur = node.__next;
|
|
2085
2259
|
i++;
|
|
2086
2260
|
}
|
|
2087
|
-
const
|
|
2088
|
-
|
|
2089
|
-
|
|
2261
|
+
const slotLen = cacheDom.__lexicalSlotTextLength || 0;
|
|
2262
|
+
const prevChildText = slotLen > 0 ? cachedParentText.slice(slotLen) : cachedParentText;
|
|
2263
|
+
const newChildText = prevChildText.slice(0, prevChildText.length - oldSuffixLength) + newSuffix;
|
|
2264
|
+
cacheDom.__lexicalTextContent = newChildText;
|
|
2265
|
+
subTreeTextContent = previousSubTreeTextContent + newChildText;
|
|
2090
2266
|
$resolveSuffixPathFormat(nextElement, cacheDom, dirtyChildren);
|
|
2091
2267
|
return;
|
|
2092
2268
|
}
|
|
@@ -2172,7 +2348,7 @@ function $reconcileChildren(prevElement, nextElement, slot) {
|
|
|
2172
2348
|
if (nextChildrenSize !== 0) $createChildren(nextChildren, nextElement, 0, nextChildrenSize - 1, slot);
|
|
2173
2349
|
} else if (nextChildrenSize === 0) {
|
|
2174
2350
|
if (prevChildrenSize !== 0) {
|
|
2175
|
-
const canUseFastPath = slot.after == null && slot.before == null && slot.element.__lexicalLineBreak == null;
|
|
2351
|
+
const canUseFastPath = slot.after == null && slot.before == null && $readSlots(nextElement).size === 0 && slot.element.__lexicalLineBreak == null;
|
|
2176
2352
|
$destroyChildren(prevChildren, 0, prevChildrenSize - 1, canUseFastPath ? null : dom);
|
|
2177
2353
|
if (canUseFastPath) dom.textContent = "";
|
|
2178
2354
|
}
|
|
@@ -2213,9 +2389,17 @@ function $reconcileNode(key, parentDOM) {
|
|
|
2213
2389
|
if (treatAllNodesAsDirty || nextIndent !== prevNode.__indent) setElementIndent(dom, nextIndent);
|
|
2214
2390
|
const nextFormat = nextNode.__format;
|
|
2215
2391
|
if (treatAllNodesAsDirty || nextFormat !== prevNode.__format) setElementFormat(dom, nextFormat);
|
|
2392
|
+
const slotTextContent = isDirty && ($readSlots(nextNode).size > 0 || $readSlots(prevNode).size > 0) ? $reconcileSlotChildren(prevNode, nextNode, dom) : "";
|
|
2216
2393
|
if (isDirty) {
|
|
2394
|
+
const outerBefore = subTreeTextContent;
|
|
2217
2395
|
$reconcileChildrenWithDirection(prevNode, nextNode, dom);
|
|
2218
2396
|
if (!$isRootNode(nextNode) && !nextNode.isInline()) $reconcileElementTerminatingLineBreak(prevNode, nextNode, dom);
|
|
2397
|
+
if (slotTextContent !== "") {
|
|
2398
|
+
const childText = dom.__lexicalTextContent || "";
|
|
2399
|
+
dom.__lexicalTextContent = slotTextContent + childText;
|
|
2400
|
+
subTreeTextContent = outerBefore + slotTextContent + childText;
|
|
2401
|
+
dom.__lexicalSlotTextLength = slotTextContent.length;
|
|
2402
|
+
} else if ($readSlots(nextNode).size > 0 || $readSlots(prevNode).size > 0) dom.__lexicalSlotTextLength = 0;
|
|
2219
2403
|
} else {
|
|
2220
2404
|
const previousSubTreeTextContent = dom.__lexicalTextContent;
|
|
2221
2405
|
if (!(typeof previousSubTreeTextContent === "string")) formatDevErrorMessage(`reconcileNode: missing __lexicalTextContent on cloned non-dirty element of type ${prevNode.getType()}`);
|
|
@@ -2233,6 +2417,7 @@ function $reconcileNode(key, parentDOM) {
|
|
|
2233
2417
|
if ($isDecoratorNode(nextNode)) {
|
|
2234
2418
|
const decorator = nextNode.decorate(activeEditor$1, activeEditorConfig);
|
|
2235
2419
|
if (decorator !== null) reconcileDecorator(key, decorator);
|
|
2420
|
+
if (isDirty && ($readSlots(nextNode).size > 0 || $readSlots(prevNode).size > 0)) $reconcileSlotChildren(prevNode, nextNode, dom);
|
|
2236
2421
|
}
|
|
2237
2422
|
subTreeTextContent += text;
|
|
2238
2423
|
}
|
|
@@ -2411,153 +2596,153 @@ function warnOnlyOnce(message) {
|
|
|
2411
2596
|
function createCommand(type) {
|
|
2412
2597
|
return { type };
|
|
2413
2598
|
}
|
|
2414
|
-
const SELECTION_CHANGE_COMMAND = createCommand("SELECTION_CHANGE_COMMAND");
|
|
2415
|
-
const SELECTION_INSERT_CLIPBOARD_NODES_COMMAND = createCommand("SELECTION_INSERT_CLIPBOARD_NODES_COMMAND");
|
|
2416
|
-
const CLICK_COMMAND = createCommand("CLICK_COMMAND");
|
|
2417
|
-
const BEFORE_INPUT_COMMAND = createCommand("BEFORE_INPUT_COMMAND");
|
|
2418
|
-
const INPUT_COMMAND = createCommand("INPUT_COMMAND");
|
|
2419
|
-
const COMPOSITION_START_COMMAND = createCommand("COMPOSITION_START_COMMAND");
|
|
2420
|
-
const COMPOSITION_END_COMMAND = createCommand("COMPOSITION_END_COMMAND");
|
|
2599
|
+
const SELECTION_CHANGE_COMMAND = /* @__PURE__ */ createCommand("SELECTION_CHANGE_COMMAND");
|
|
2600
|
+
const SELECTION_INSERT_CLIPBOARD_NODES_COMMAND = /* @__PURE__ */ createCommand("SELECTION_INSERT_CLIPBOARD_NODES_COMMAND");
|
|
2601
|
+
const CLICK_COMMAND = /* @__PURE__ */ createCommand("CLICK_COMMAND");
|
|
2602
|
+
const BEFORE_INPUT_COMMAND = /* @__PURE__ */ createCommand("BEFORE_INPUT_COMMAND");
|
|
2603
|
+
const INPUT_COMMAND = /* @__PURE__ */ createCommand("INPUT_COMMAND");
|
|
2604
|
+
const COMPOSITION_START_COMMAND = /* @__PURE__ */ createCommand("COMPOSITION_START_COMMAND");
|
|
2605
|
+
const COMPOSITION_END_COMMAND = /* @__PURE__ */ createCommand("COMPOSITION_END_COMMAND");
|
|
2421
2606
|
/**
|
|
2422
2607
|
* Dispatched to delete a character, the payload will be `true` if the deletion
|
|
2423
2608
|
* is backwards (backspace or delete on macOS) and `false` if forwards
|
|
2424
2609
|
* (delete or Fn+Delete on macOS).
|
|
2425
2610
|
*/
|
|
2426
|
-
const DELETE_CHARACTER_COMMAND = createCommand("DELETE_CHARACTER_COMMAND");
|
|
2611
|
+
const DELETE_CHARACTER_COMMAND = /* @__PURE__ */ createCommand("DELETE_CHARACTER_COMMAND");
|
|
2427
2612
|
/**
|
|
2428
2613
|
* Dispatched to insert a line break. With a false payload the
|
|
2429
2614
|
* cursor moves to the new line (Shift+Enter), with a true payload the cursor
|
|
2430
2615
|
* does not move (Ctrl+O on macOS).
|
|
2431
2616
|
*/
|
|
2432
|
-
const INSERT_LINE_BREAK_COMMAND = createCommand("INSERT_LINE_BREAK_COMMAND");
|
|
2433
|
-
const INSERT_PARAGRAPH_COMMAND = createCommand("INSERT_PARAGRAPH_COMMAND");
|
|
2434
|
-
const CONTROLLED_TEXT_INSERTION_COMMAND = createCommand("CONTROLLED_TEXT_INSERTION_COMMAND");
|
|
2435
|
-
const PASTE_COMMAND = createCommand("PASTE_COMMAND");
|
|
2436
|
-
const REMOVE_TEXT_COMMAND = createCommand("REMOVE_TEXT_COMMAND");
|
|
2617
|
+
const INSERT_LINE_BREAK_COMMAND = /* @__PURE__ */ createCommand("INSERT_LINE_BREAK_COMMAND");
|
|
2618
|
+
const INSERT_PARAGRAPH_COMMAND = /* @__PURE__ */ createCommand("INSERT_PARAGRAPH_COMMAND");
|
|
2619
|
+
const CONTROLLED_TEXT_INSERTION_COMMAND = /* @__PURE__ */ createCommand("CONTROLLED_TEXT_INSERTION_COMMAND");
|
|
2620
|
+
const PASTE_COMMAND = /* @__PURE__ */ createCommand("PASTE_COMMAND");
|
|
2621
|
+
const REMOVE_TEXT_COMMAND = /* @__PURE__ */ createCommand("REMOVE_TEXT_COMMAND");
|
|
2437
2622
|
/**
|
|
2438
2623
|
* Dispatched to delete a word, the payload will be `true` if the deletion is
|
|
2439
2624
|
* backwards (Ctrl+Backspace or Opt+Delete on macOS), and `false` if
|
|
2440
2625
|
* forwards (Ctrl+Delete or Fn+Opt+Delete on macOS).
|
|
2441
2626
|
*/
|
|
2442
|
-
const DELETE_WORD_COMMAND = createCommand("DELETE_WORD_COMMAND");
|
|
2627
|
+
const DELETE_WORD_COMMAND = /* @__PURE__ */ createCommand("DELETE_WORD_COMMAND");
|
|
2443
2628
|
/**
|
|
2444
2629
|
* Dispatched to delete a line, the payload will be `true` if the deletion is
|
|
2445
2630
|
* backwards (Cmd+Delete on macOS), and `false` if forwards
|
|
2446
2631
|
* (Fn+Cmd+Delete on macOS).
|
|
2447
2632
|
*/
|
|
2448
|
-
const DELETE_LINE_COMMAND = createCommand("DELETE_LINE_COMMAND");
|
|
2633
|
+
const DELETE_LINE_COMMAND = /* @__PURE__ */ createCommand("DELETE_LINE_COMMAND");
|
|
2449
2634
|
/**
|
|
2450
2635
|
* Dispatched to format the selected text.
|
|
2451
2636
|
*/
|
|
2452
|
-
const FORMAT_TEXT_COMMAND = createCommand("FORMAT_TEXT_COMMAND");
|
|
2637
|
+
const FORMAT_TEXT_COMMAND = /* @__PURE__ */ createCommand("FORMAT_TEXT_COMMAND");
|
|
2453
2638
|
/**
|
|
2454
2639
|
* Dispatched on undo (Cmd+Z on macOS, Ctrl+Z elsewhere).
|
|
2455
2640
|
*/
|
|
2456
|
-
const UNDO_COMMAND = createCommand("UNDO_COMMAND");
|
|
2641
|
+
const UNDO_COMMAND = /* @__PURE__ */ createCommand("UNDO_COMMAND");
|
|
2457
2642
|
/**
|
|
2458
2643
|
* Dispatched on redo (Shift+Cmd+Z on macOS, Shift+Ctrl+Z or Ctrl+Y elsewhere).
|
|
2459
2644
|
*/
|
|
2460
|
-
const REDO_COMMAND = createCommand("REDO_COMMAND");
|
|
2645
|
+
const REDO_COMMAND = /* @__PURE__ */ createCommand("REDO_COMMAND");
|
|
2461
2646
|
/**
|
|
2462
2647
|
* Dispatched when any key is pressed.
|
|
2463
2648
|
*/
|
|
2464
|
-
const KEY_DOWN_COMMAND = createCommand("KEYDOWN_COMMAND");
|
|
2649
|
+
const KEY_DOWN_COMMAND = /* @__PURE__ */ createCommand("KEYDOWN_COMMAND");
|
|
2465
2650
|
/**
|
|
2466
2651
|
* Dispatched when the `'ArrowRight'` key is pressed.
|
|
2467
2652
|
* The shift modifier key may also be down.
|
|
2468
2653
|
*/
|
|
2469
|
-
const KEY_ARROW_RIGHT_COMMAND = createCommand("KEY_ARROW_RIGHT_COMMAND");
|
|
2654
|
+
const KEY_ARROW_RIGHT_COMMAND = /* @__PURE__ */ createCommand("KEY_ARROW_RIGHT_COMMAND");
|
|
2470
2655
|
/**
|
|
2471
2656
|
* Dispatched when the move to end keyboard shortcut is pressed,
|
|
2472
2657
|
* (Cmd+Right on macOS; Ctrl+Right elsewhere).
|
|
2473
2658
|
*/
|
|
2474
|
-
const MOVE_TO_END = createCommand("MOVE_TO_END");
|
|
2659
|
+
const MOVE_TO_END = /* @__PURE__ */ createCommand("MOVE_TO_END");
|
|
2475
2660
|
/**
|
|
2476
2661
|
* Dispatched when the `'ArrowLeft'` key is pressed.
|
|
2477
2662
|
* The shift modifier key may also be down.
|
|
2478
2663
|
*/
|
|
2479
|
-
const KEY_ARROW_LEFT_COMMAND = createCommand("KEY_ARROW_LEFT_COMMAND");
|
|
2664
|
+
const KEY_ARROW_LEFT_COMMAND = /* @__PURE__ */ createCommand("KEY_ARROW_LEFT_COMMAND");
|
|
2480
2665
|
/**
|
|
2481
2666
|
* Dispatched when the move to start keyboard shortcut is pressed,
|
|
2482
2667
|
* (Cmd+Left on macOS; Ctrl+Left elsewhere).
|
|
2483
2668
|
*/
|
|
2484
|
-
const MOVE_TO_START = createCommand("MOVE_TO_START");
|
|
2669
|
+
const MOVE_TO_START = /* @__PURE__ */ createCommand("MOVE_TO_START");
|
|
2485
2670
|
/**
|
|
2486
2671
|
* Dispatched when the `'ArrowUp'` key is pressed.
|
|
2487
2672
|
* The shift and/or alt (option) modifier keys may also be down.
|
|
2488
2673
|
*/
|
|
2489
|
-
const KEY_ARROW_UP_COMMAND = createCommand("KEY_ARROW_UP_COMMAND");
|
|
2674
|
+
const KEY_ARROW_UP_COMMAND = /* @__PURE__ */ createCommand("KEY_ARROW_UP_COMMAND");
|
|
2490
2675
|
/**
|
|
2491
2676
|
* Dispatched when the `'ArrowDown'` key is pressed.
|
|
2492
2677
|
* The shift and/or alt (option) modifier keys may also be down.
|
|
2493
2678
|
*/
|
|
2494
|
-
const KEY_ARROW_DOWN_COMMAND = createCommand("KEY_ARROW_DOWN_COMMAND");
|
|
2679
|
+
const KEY_ARROW_DOWN_COMMAND = /* @__PURE__ */ createCommand("KEY_ARROW_DOWN_COMMAND");
|
|
2495
2680
|
/**
|
|
2496
2681
|
* Dispatched when the enter key is pressed, may also be called with a null
|
|
2497
2682
|
* payload when the intent is to insert a newline. The shift modifier key
|
|
2498
2683
|
* must be down, any other modifier keys may also be down.
|
|
2499
2684
|
*/
|
|
2500
|
-
const KEY_ENTER_COMMAND = createCommand("KEY_ENTER_COMMAND");
|
|
2685
|
+
const KEY_ENTER_COMMAND = /* @__PURE__ */ createCommand("KEY_ENTER_COMMAND");
|
|
2501
2686
|
/**
|
|
2502
2687
|
* Dispatched whenever the space (`' '`) key is pressed, any modifier
|
|
2503
2688
|
* keys may be down.
|
|
2504
2689
|
*/
|
|
2505
|
-
const KEY_SPACE_COMMAND = createCommand("KEY_SPACE_COMMAND");
|
|
2690
|
+
const KEY_SPACE_COMMAND = /* @__PURE__ */ createCommand("KEY_SPACE_COMMAND");
|
|
2506
2691
|
/**
|
|
2507
2692
|
* Dispatched whenever the `'Backspace'` key is pressed, the shift
|
|
2508
2693
|
* modifier key may be down.
|
|
2509
2694
|
*/
|
|
2510
|
-
const KEY_BACKSPACE_COMMAND = createCommand("KEY_BACKSPACE_COMMAND");
|
|
2695
|
+
const KEY_BACKSPACE_COMMAND = /* @__PURE__ */ createCommand("KEY_BACKSPACE_COMMAND");
|
|
2511
2696
|
/**
|
|
2512
2697
|
* Dispatched whenever the `'Escape'` key is pressed, any modifier
|
|
2513
2698
|
* keys may be down.
|
|
2514
2699
|
*/
|
|
2515
|
-
const KEY_ESCAPE_COMMAND = createCommand("KEY_ESCAPE_COMMAND");
|
|
2700
|
+
const KEY_ESCAPE_COMMAND = /* @__PURE__ */ createCommand("KEY_ESCAPE_COMMAND");
|
|
2516
2701
|
/**
|
|
2517
2702
|
* Dispatched whenever the `'Delete'` key is pressed (Fn+Delete on macOS).
|
|
2518
2703
|
*/
|
|
2519
|
-
const KEY_DELETE_COMMAND = createCommand("KEY_DELETE_COMMAND");
|
|
2704
|
+
const KEY_DELETE_COMMAND = /* @__PURE__ */ createCommand("KEY_DELETE_COMMAND");
|
|
2520
2705
|
/**
|
|
2521
2706
|
* Dispatched whenever the `'Tab'` key is pressed. The shift modifier key
|
|
2522
2707
|
* may be down.
|
|
2523
2708
|
*/
|
|
2524
|
-
const KEY_TAB_COMMAND = createCommand("KEY_TAB_COMMAND");
|
|
2525
|
-
const INSERT_TAB_COMMAND = createCommand("INSERT_TAB_COMMAND");
|
|
2526
|
-
const INDENT_CONTENT_COMMAND = createCommand("INDENT_CONTENT_COMMAND");
|
|
2527
|
-
const OUTDENT_CONTENT_COMMAND = createCommand("OUTDENT_CONTENT_COMMAND");
|
|
2528
|
-
const DROP_COMMAND = createCommand("DROP_COMMAND");
|
|
2529
|
-
const FORMAT_ELEMENT_COMMAND = createCommand("FORMAT_ELEMENT_COMMAND");
|
|
2530
|
-
const DRAGSTART_COMMAND = createCommand("DRAGSTART_COMMAND");
|
|
2531
|
-
const DRAGOVER_COMMAND = createCommand("DRAGOVER_COMMAND");
|
|
2532
|
-
const DRAGEND_COMMAND = createCommand("DRAGEND_COMMAND");
|
|
2709
|
+
const KEY_TAB_COMMAND = /* @__PURE__ */ createCommand("KEY_TAB_COMMAND");
|
|
2710
|
+
const INSERT_TAB_COMMAND = /* @__PURE__ */ createCommand("INSERT_TAB_COMMAND");
|
|
2711
|
+
const INDENT_CONTENT_COMMAND = /* @__PURE__ */ createCommand("INDENT_CONTENT_COMMAND");
|
|
2712
|
+
const OUTDENT_CONTENT_COMMAND = /* @__PURE__ */ createCommand("OUTDENT_CONTENT_COMMAND");
|
|
2713
|
+
const DROP_COMMAND = /* @__PURE__ */ createCommand("DROP_COMMAND");
|
|
2714
|
+
const FORMAT_ELEMENT_COMMAND = /* @__PURE__ */ createCommand("FORMAT_ELEMENT_COMMAND");
|
|
2715
|
+
const DRAGSTART_COMMAND = /* @__PURE__ */ createCommand("DRAGSTART_COMMAND");
|
|
2716
|
+
const DRAGOVER_COMMAND = /* @__PURE__ */ createCommand("DRAGOVER_COMMAND");
|
|
2717
|
+
const DRAGEND_COMMAND = /* @__PURE__ */ createCommand("DRAGEND_COMMAND");
|
|
2533
2718
|
/**
|
|
2534
2719
|
* Dispatched on a copy event, either via the clipboard or a KeyboardEvent
|
|
2535
2720
|
* (Cmd+C on macOS, Ctrl+C elsewhere).
|
|
2536
2721
|
*/
|
|
2537
|
-
const COPY_COMMAND = createCommand("COPY_COMMAND");
|
|
2722
|
+
const COPY_COMMAND = /* @__PURE__ */ createCommand("COPY_COMMAND");
|
|
2538
2723
|
/**
|
|
2539
2724
|
* Dispatched on a cut event, either via the clipboard or a KeyboardEvent
|
|
2540
2725
|
* (Cmd+X on macOS, Ctrl+X elsewhere).
|
|
2541
2726
|
*/
|
|
2542
|
-
const CUT_COMMAND = createCommand("CUT_COMMAND");
|
|
2727
|
+
const CUT_COMMAND = /* @__PURE__ */ createCommand("CUT_COMMAND");
|
|
2543
2728
|
/**
|
|
2544
2729
|
* Dispatched on the select all keyboard shortcut
|
|
2545
2730
|
* (Cmd+A on macOS, Ctrl+A elsehwere).
|
|
2546
2731
|
*/
|
|
2547
|
-
const SELECT_ALL_COMMAND = createCommand("SELECT_ALL_COMMAND");
|
|
2548
|
-
const CLEAR_EDITOR_COMMAND = createCommand("CLEAR_EDITOR_COMMAND");
|
|
2549
|
-
const CLEAR_HISTORY_COMMAND = createCommand("CLEAR_HISTORY_COMMAND");
|
|
2550
|
-
const CAN_REDO_COMMAND = createCommand("CAN_REDO_COMMAND");
|
|
2551
|
-
const CAN_UNDO_COMMAND = createCommand("CAN_UNDO_COMMAND");
|
|
2552
|
-
const FOCUS_COMMAND = createCommand("FOCUS_COMMAND");
|
|
2553
|
-
const BLUR_COMMAND = createCommand("BLUR_COMMAND");
|
|
2732
|
+
const SELECT_ALL_COMMAND = /* @__PURE__ */ createCommand("SELECT_ALL_COMMAND");
|
|
2733
|
+
const CLEAR_EDITOR_COMMAND = /* @__PURE__ */ createCommand("CLEAR_EDITOR_COMMAND");
|
|
2734
|
+
const CLEAR_HISTORY_COMMAND = /* @__PURE__ */ createCommand("CLEAR_HISTORY_COMMAND");
|
|
2735
|
+
const CAN_REDO_COMMAND = /* @__PURE__ */ createCommand("CAN_REDO_COMMAND");
|
|
2736
|
+
const CAN_UNDO_COMMAND = /* @__PURE__ */ createCommand("CAN_UNDO_COMMAND");
|
|
2737
|
+
const FOCUS_COMMAND = /* @__PURE__ */ createCommand("FOCUS_COMMAND");
|
|
2738
|
+
const BLUR_COMMAND = /* @__PURE__ */ createCommand("BLUR_COMMAND");
|
|
2554
2739
|
/**
|
|
2555
2740
|
* @deprecated in v0.31.0, use KEY_DOWN_COMMAND and check for modifiers
|
|
2556
2741
|
* directly.
|
|
2557
2742
|
*
|
|
2558
2743
|
* Dispatched after any KeyboardEvent when modifiers are pressed
|
|
2559
2744
|
*/
|
|
2560
|
-
const KEY_MODIFIER_COMMAND = createCommand("KEY_MODIFIER_COMMAND");
|
|
2745
|
+
const KEY_MODIFIER_COMMAND = /* @__PURE__ */ createCommand("KEY_MODIFIER_COMMAND");
|
|
2561
2746
|
const PASS_THROUGH_COMMAND = Object.freeze({});
|
|
2562
2747
|
const ANDROID_COMPOSITION_LATENCY = 30;
|
|
2563
2748
|
const rootElementEvents = [
|
|
@@ -2585,7 +2770,7 @@ let unprocessedBeforeInputData = null;
|
|
|
2585
2770
|
let isInsertTextAfterHandledSelectionCommand = false;
|
|
2586
2771
|
let handledSelectionCommandTimeoutId = null;
|
|
2587
2772
|
const rootElementToDocument = /* @__PURE__ */ new WeakMap();
|
|
2588
|
-
const
|
|
2773
|
+
const documentRegistrations = /* @__PURE__ */ new WeakMap();
|
|
2589
2774
|
let isSelectionChangeFromDOMUpdate = false;
|
|
2590
2775
|
let isSelectionChangeFromMouseDown = false;
|
|
2591
2776
|
let isInsertLineBreak = false;
|
|
@@ -2600,23 +2785,28 @@ let collapsedSelectionFormat = [
|
|
|
2600
2785
|
"root",
|
|
2601
2786
|
0
|
|
2602
2787
|
];
|
|
2603
|
-
function $shouldPreventDefaultAndInsertText(selection, domTargetRange, text, timeStamp, isBeforeInput) {
|
|
2788
|
+
function $shouldPreventDefaultAndInsertText(selection, domTargetRange, text, timeStamp, isBeforeInput, cachedDOMSelectionPoints) {
|
|
2604
2789
|
const anchor = selection.anchor;
|
|
2605
2790
|
const focus = selection.focus;
|
|
2606
2791
|
const anchorNode = anchor.getNode();
|
|
2607
2792
|
const editor = getActiveEditor();
|
|
2608
|
-
|
|
2609
|
-
|
|
2793
|
+
let domSelectionPoints;
|
|
2794
|
+
if (cachedDOMSelectionPoints !== void 0) domSelectionPoints = cachedDOMSelectionPoints;
|
|
2795
|
+
else {
|
|
2796
|
+
const domSelection = getDOMSelection(getWindow(editor));
|
|
2797
|
+
domSelectionPoints = domSelection !== null ? getDOMSelectionPoints(domSelection, editor._rootElement) : null;
|
|
2798
|
+
}
|
|
2799
|
+
const domAnchorNode = domSelectionPoints !== null ? domSelectionPoints.anchorNode : null;
|
|
2610
2800
|
const anchorKey = anchor.key;
|
|
2611
2801
|
const backingAnchorElement = editor.getElementByKey(anchorKey);
|
|
2612
2802
|
const textLength = text.length;
|
|
2613
|
-
return anchorKey !== focus.key || !$isTextNode(anchorNode) || (!isBeforeInput && (!CAN_USE_BEFORE_INPUT || lastBeforeInputInsertTextTimeStamp < timeStamp + 50) || anchorNode.isDirty() && textLength < 2 || doesContainSurrogatePair(text)) && anchor.offset !== focus.offset && !anchorNode.isComposing() || $isTokenOrSegmented(anchorNode) || anchorNode.isDirty() && textLength > 1 || (isBeforeInput || !CAN_USE_BEFORE_INPUT) && backingAnchorElement !== null && !anchorNode.isComposing() && domAnchorNode !== $getDOMTextNode(anchorNode, backingAnchorElement, editor) ||
|
|
2803
|
+
return anchorKey !== focus.key || !$isTextNode(anchorNode) || (!isBeforeInput && (!CAN_USE_BEFORE_INPUT || lastBeforeInputInsertTextTimeStamp < timeStamp + 50) || anchorNode.isDirty() && textLength < 2 || doesContainSurrogatePair(text)) && anchor.offset !== focus.offset && !anchorNode.isComposing() || $isTokenOrSegmented(anchorNode) || anchorNode.isDirty() && textLength > 1 || (isBeforeInput || !CAN_USE_BEFORE_INPUT) && backingAnchorElement !== null && !anchorNode.isComposing() && domAnchorNode !== $getDOMTextNode(anchorNode, backingAnchorElement, editor) || domSelectionPoints !== null && domTargetRange !== null && (!domTargetRange.collapsed || domTargetRange.startContainer !== domSelectionPoints.anchorNode || domTargetRange.startOffset !== domSelectionPoints.anchorOffset) || !anchorNode.isComposing() && (anchorNode.getFormat() !== selection.format || anchorNode.getStyle() !== selection.style) || $shouldInsertTextAfterOrBeforeTextNode(selection, anchorNode);
|
|
2614
2804
|
}
|
|
2615
2805
|
function shouldSkipSelectionChange(domNode, offset) {
|
|
2616
2806
|
return isDOMTextNode(domNode) && domNode.nodeValue !== null && offset !== 0 && offset !== domNode.nodeValue.length;
|
|
2617
2807
|
}
|
|
2618
2808
|
function onSelectionChange(domSelection, editor, isActive) {
|
|
2619
|
-
const { anchorNode: anchorDOM, anchorOffset, focusNode: focusDOM, focusOffset } = domSelection;
|
|
2809
|
+
const { anchorNode: anchorDOM, anchorOffset, focusNode: focusDOM, focusOffset } = getDOMSelectionPoints(domSelection, editor._rootElement);
|
|
2620
2810
|
if (isSelectionChangeFromDOMUpdate) {
|
|
2621
2811
|
isSelectionChangeFromDOMUpdate = false;
|
|
2622
2812
|
if (shouldSkipSelectionChange(anchorDOM, anchorOffset) && shouldSkipSelectionChange(focusDOM, focusOffset) && !postDeleteSelectionToRestore) return;
|
|
@@ -2641,7 +2831,7 @@ function onSelectionChange(domSelection, editor, isActive) {
|
|
|
2641
2831
|
const anchor = selection.anchor;
|
|
2642
2832
|
const anchorNode = anchor.getNode();
|
|
2643
2833
|
if (selection.isCollapsed()) {
|
|
2644
|
-
if (domSelection.type === "Range" &&
|
|
2834
|
+
if (domSelection.type === "Range" && anchorDOM === focusDOM) selection.dirty = true;
|
|
2645
2835
|
const windowEvent = getWindow(editor).event;
|
|
2646
2836
|
const currentTimeStamp = windowEvent ? windowEvent.timeStamp : performance.now();
|
|
2647
2837
|
const [lastFormat, lastStyle, lastOffset, lastKey, timeStamp] = collapsedSelectionFormat;
|
|
@@ -2711,7 +2901,7 @@ function onClick(event, editor) {
|
|
|
2711
2901
|
selection.dirty = true;
|
|
2712
2902
|
}
|
|
2713
2903
|
} else if (event.pointerType === "touch" || event.pointerType === "pen") {
|
|
2714
|
-
const domAnchorNode = domSelection.anchorNode;
|
|
2904
|
+
const domAnchorNode = getDOMSelectionPoints(domSelection, editor._rootElement).anchorNode;
|
|
2715
2905
|
if (isHTMLElement(domAnchorNode) || isDOMTextNode(domAnchorNode)) $setSelection($internalCreateRangeSelection(lastSelection, domSelection, editor, event));
|
|
2716
2906
|
}
|
|
2717
2907
|
}
|
|
@@ -2719,10 +2909,10 @@ function onClick(event, editor) {
|
|
|
2719
2909
|
});
|
|
2720
2910
|
}
|
|
2721
2911
|
function onPointerDown(event, editor) {
|
|
2722
|
-
const target = event
|
|
2912
|
+
const target = getComposedEventTarget(event);
|
|
2723
2913
|
const pointerType = event.pointerType;
|
|
2724
2914
|
if (isDOMNode(target) && pointerType !== "touch" && pointerType !== "pen" && event.button === 0) updateEditorSync(editor, () => {
|
|
2725
|
-
if (
|
|
2915
|
+
if (!isDOMCapturingSelection(target, editor)) isSelectionChangeFromMouseDown = true;
|
|
2726
2916
|
});
|
|
2727
2917
|
}
|
|
2728
2918
|
function getTargetRange(event) {
|
|
@@ -2779,11 +2969,34 @@ function registerDefaultCommandHandlers(editor) {
|
|
|
2779
2969
|
editor.registerCommand(COMPOSITION_END_COMMAND, $handleCompositionEnd, 0);
|
|
2780
2970
|
editor.registerCommand(KEY_DOWN_COMMAND, $handleKeyDown, 0);
|
|
2781
2971
|
}
|
|
2972
|
+
/**
|
|
2973
|
+
* Returns true when a `beforeinput` / `input` event belongs to a native
|
|
2974
|
+
* control (e.g. an `<input>` or `<textarea>`, or any other subtree marked with
|
|
2975
|
+
* `setDOMUnmanaged({captureSelection: true})`) inside a decorator whose
|
|
2976
|
+
* selection is owned by the browser rather than managed by Lexical. Turning
|
|
2977
|
+
* such an event into a Lexical command would insert text into the editor
|
|
2978
|
+
* instead of the focused control.
|
|
2979
|
+
*
|
|
2980
|
+
* Two signals are checked because Firefox 152 changed how it dispatches
|
|
2981
|
+
* `beforeinput` for these controls (#8738): the event is retargeted off of the
|
|
2982
|
+
* focused control, so its composed target no longer points at it. The deep
|
|
2983
|
+
* active element still does, and is used as a fallback.
|
|
2984
|
+
*/
|
|
2985
|
+
function isInputEventTargetingCapturedSelection(event, editor) {
|
|
2986
|
+
const composedTarget = getComposedEventTarget(event);
|
|
2987
|
+
if (isHTMLElement(composedTarget) && isDOMCapturingSelection(composedTarget, editor)) return true;
|
|
2988
|
+
const rootElement = editor.getRootElement();
|
|
2989
|
+
if (rootElement === null) return false;
|
|
2990
|
+
const activeElement = getActiveElementDeep(rootElement.ownerDocument);
|
|
2991
|
+
return activeElement !== null && rootElement.contains(activeElement) && isDOMCapturingSelection(activeElement, editor);
|
|
2992
|
+
}
|
|
2782
2993
|
function onBeforeInput(event, editor) {
|
|
2783
2994
|
const inputType = event.inputType;
|
|
2784
2995
|
if (inputType === "deleteCompositionText" || IS_FIREFOX && isFirefoxClipboardEvents(editor)) return;
|
|
2785
2996
|
else if (inputType === "insertCompositionText") return;
|
|
2786
|
-
|
|
2997
|
+
updateEditorSync(editor, () => {
|
|
2998
|
+
if (!isInputEventTargetingCapturedSelection(event, editor)) dispatchCommand(editor, BEFORE_INPUT_COMMAND, event);
|
|
2999
|
+
}, { event });
|
|
2787
3000
|
}
|
|
2788
3001
|
function $handleBeforeInput(event) {
|
|
2789
3002
|
const inputType = event.inputType;
|
|
@@ -2959,42 +3172,48 @@ function onInput(event, editor) {
|
|
|
2959
3172
|
event.stopPropagation();
|
|
2960
3173
|
clearHandledSelectionCommandInsertText();
|
|
2961
3174
|
updateEditorSync(editor, () => {
|
|
2962
|
-
editor.dispatchCommand(INPUT_COMMAND, event);
|
|
3175
|
+
if (!isInputEventTargetingCapturedSelection(event, editor)) editor.dispatchCommand(INPUT_COMMAND, event);
|
|
2963
3176
|
}, { event });
|
|
2964
3177
|
unprocessedBeforeInputData = null;
|
|
2965
3178
|
}
|
|
2966
3179
|
function $handleInput(event) {
|
|
2967
|
-
if (isHTMLElement(event.target) && $isSelectionCapturedInDecorator(event.target)) return true;
|
|
2968
3180
|
const editor = getActiveEditor();
|
|
2969
3181
|
const selection = $getSelection();
|
|
2970
3182
|
const data = event.data;
|
|
2971
3183
|
const targetRange = getTargetRange(event);
|
|
2972
|
-
|
|
2973
|
-
|
|
2974
|
-
$onCompositionEndImpl(editor, data);
|
|
2975
|
-
isFirefoxEndingComposition = false;
|
|
2976
|
-
}
|
|
2977
|
-
const anchorNode = selection.anchor.getNode();
|
|
3184
|
+
let handled = false;
|
|
3185
|
+
if (data != null && $isRangeSelection(selection)) {
|
|
2978
3186
|
const domSelection = getDOMSelection(getWindow(editor));
|
|
2979
|
-
|
|
2980
|
-
|
|
2981
|
-
|
|
2982
|
-
|
|
2983
|
-
|
|
2984
|
-
|
|
2985
|
-
|
|
2986
|
-
selection.anchor.
|
|
2987
|
-
|
|
2988
|
-
|
|
2989
|
-
|
|
2990
|
-
|
|
2991
|
-
|
|
2992
|
-
|
|
3187
|
+
const domSelectionPoints = domSelection !== null ? getDOMSelectionPoints(domSelection, editor._rootElement) : null;
|
|
3188
|
+
if ($shouldPreventDefaultAndInsertText(selection, targetRange, data, event.timeStamp, false, domSelectionPoints)) {
|
|
3189
|
+
handled = true;
|
|
3190
|
+
if (isFirefoxEndingComposition) {
|
|
3191
|
+
$onCompositionEndImpl(editor, data);
|
|
3192
|
+
isFirefoxEndingComposition = false;
|
|
3193
|
+
}
|
|
3194
|
+
const anchorNode = selection.anchor.getNode();
|
|
3195
|
+
if (domSelection === null || domSelectionPoints === null) return true;
|
|
3196
|
+
const isBackward = selection.isBackward();
|
|
3197
|
+
const startOffset = isBackward ? selection.anchor.offset : selection.focus.offset;
|
|
3198
|
+
const endOffset = isBackward ? selection.focus.offset : selection.anchor.offset;
|
|
3199
|
+
if (!CAN_USE_BEFORE_INPUT || selection.isCollapsed() || !$isTextNode(anchorNode) || domSelectionPoints.anchorNode === null || anchorNode.getTextContent().slice(0, startOffset) + data + anchorNode.getTextContent().slice(startOffset + endOffset) !== getAnchorTextFromDOM(domSelectionPoints.anchorNode)) dispatchCommand(editor, CONTROLLED_TEXT_INSERTION_COMMAND, data);
|
|
3200
|
+
const textLength = data.length;
|
|
3201
|
+
if (IS_FIREFOX && textLength > 1 && event.inputType === "insertCompositionText" && !editor.isComposing()) {
|
|
3202
|
+
selection.anchor.offset -= textLength;
|
|
3203
|
+
selection._cachedNodes = null;
|
|
3204
|
+
selection._cachedIsBackward = null;
|
|
3205
|
+
}
|
|
3206
|
+
if (IS_ANDROID_CHROME && editor.isComposing()) {
|
|
3207
|
+
lastKeyDownTimeStamp = 0;
|
|
3208
|
+
$setCompositionKey(null);
|
|
3209
|
+
}
|
|
2993
3210
|
}
|
|
2994
|
-
}
|
|
3211
|
+
}
|
|
3212
|
+
if (!handled) {
|
|
2995
3213
|
$updateSelectedTextFromDOM(false, editor, data !== null ? data : void 0);
|
|
2996
3214
|
if (isFirefoxEndingComposition) {
|
|
2997
3215
|
$onCompositionEndImpl(editor, data || void 0);
|
|
3216
|
+
$addUpdateTag(COMPOSITION_END_TAG);
|
|
2998
3217
|
isFirefoxEndingComposition = false;
|
|
2999
3218
|
}
|
|
3000
3219
|
}
|
|
@@ -3031,11 +3250,12 @@ function $onCompositionEndImpl(editor, data) {
|
|
|
3031
3250
|
const textNode = domElement !== null && $isTextNode(node) ? $getDOMTextNode(node, domElement, editor) : null;
|
|
3032
3251
|
if (textNode !== null && textNode.nodeValue !== null && $isTextNode(node)) {
|
|
3033
3252
|
const domSelection = getDOMSelection(getWindow(editor));
|
|
3253
|
+
const domSelectionPoints = domSelection && getDOMSelectionPoints(domSelection, editor._rootElement);
|
|
3034
3254
|
let anchorOffset = null;
|
|
3035
3255
|
let focusOffset = null;
|
|
3036
|
-
if (
|
|
3037
|
-
anchorOffset =
|
|
3038
|
-
focusOffset =
|
|
3256
|
+
if (domSelectionPoints !== null && domSelectionPoints.anchorNode === textNode) {
|
|
3257
|
+
anchorOffset = domSelectionPoints.anchorOffset;
|
|
3258
|
+
focusOffset = domSelectionPoints.focusOffset;
|
|
3039
3259
|
}
|
|
3040
3260
|
$updateTextNodeFromDOMContent(node, textNode.nodeValue, anchorOffset, focusOffset, true);
|
|
3041
3261
|
}
|
|
@@ -3170,13 +3390,64 @@ const activeNestedEditorsMap = /* @__PURE__ */ new Map();
|
|
|
3170
3390
|
function onDocumentSelectionChange(event) {
|
|
3171
3391
|
const domSelection = getDOMSelectionFromTarget(event.target);
|
|
3172
3392
|
if (domSelection === null) return;
|
|
3173
|
-
const
|
|
3393
|
+
const ownerDocument = getDOMOwnerDocument(event.target);
|
|
3394
|
+
let nextActiveEditor = null;
|
|
3395
|
+
let resolvedAnchorNode = null;
|
|
3396
|
+
if (ownerDocument !== null) {
|
|
3397
|
+
const registration = documentRegistrations.get(ownerDocument);
|
|
3398
|
+
if (registration !== void 0) {
|
|
3399
|
+
const editorsForDoc = registration.editors;
|
|
3400
|
+
let hasShadow = registration.hasShadowEditor;
|
|
3401
|
+
if (hasShadow === void 0) {
|
|
3402
|
+
hasShadow = false;
|
|
3403
|
+
for (const ed of editorsForDoc) if (ed._rootElement !== null && isDOMShadowRoot(ed._rootElement.getRootNode())) {
|
|
3404
|
+
hasShadow = true;
|
|
3405
|
+
break;
|
|
3406
|
+
}
|
|
3407
|
+
registration.hasShadowEditor = hasShadow;
|
|
3408
|
+
}
|
|
3409
|
+
if (!hasShadow) {
|
|
3410
|
+
const anchorNode = domSelection.anchorNode;
|
|
3411
|
+
if (anchorNode !== null && !(isHTMLElement(anchorNode) && anchorNode.shadowRoot !== null)) {
|
|
3412
|
+
nextActiveEditor = getNearestEditorFromDOMNode(anchorNode);
|
|
3413
|
+
if (nextActiveEditor !== null) resolvedAnchorNode = anchorNode;
|
|
3414
|
+
}
|
|
3415
|
+
} else {
|
|
3416
|
+
let deferredLightEditor = null;
|
|
3417
|
+
let deferredLightAnchor = null;
|
|
3418
|
+
for (const candidate of editorsForDoc) {
|
|
3419
|
+
const candidateRoot = candidate._rootElement;
|
|
3420
|
+
if (candidateRoot === null) continue;
|
|
3421
|
+
const anchorNode = getDOMSelectionPoints(domSelection, candidateRoot).anchorNode;
|
|
3422
|
+
if (anchorNode === null) continue;
|
|
3423
|
+
if (getNearestEditorFromDOMNode(anchorNode) !== candidate) continue;
|
|
3424
|
+
if (isDOMShadowRoot(candidateRoot.getRootNode())) {
|
|
3425
|
+
nextActiveEditor = candidate;
|
|
3426
|
+
resolvedAnchorNode = anchorNode;
|
|
3427
|
+
break;
|
|
3428
|
+
}
|
|
3429
|
+
if (deferredLightEditor === null) {
|
|
3430
|
+
deferredLightEditor = candidate;
|
|
3431
|
+
deferredLightAnchor = anchorNode;
|
|
3432
|
+
}
|
|
3433
|
+
}
|
|
3434
|
+
if (nextActiveEditor === null && deferredLightEditor !== null) {
|
|
3435
|
+
nextActiveEditor = deferredLightEditor;
|
|
3436
|
+
resolvedAnchorNode = deferredLightAnchor;
|
|
3437
|
+
}
|
|
3438
|
+
}
|
|
3439
|
+
}
|
|
3440
|
+
if (nextActiveEditor === null) {
|
|
3441
|
+
const activeElement = getActiveElementDeep(ownerDocument);
|
|
3442
|
+
nextActiveEditor = activeElement !== null ? getNearestEditorFromDOMNode(activeElement) : null;
|
|
3443
|
+
}
|
|
3444
|
+
}
|
|
3174
3445
|
if (nextActiveEditor === null) return;
|
|
3175
3446
|
if (isSelectionChangeFromMouseDown) {
|
|
3176
3447
|
isSelectionChangeFromMouseDown = false;
|
|
3177
3448
|
updateEditorSync(nextActiveEditor, () => {
|
|
3178
3449
|
const lastSelection = $getPreviousSelection();
|
|
3179
|
-
const domAnchorNode = domSelection.anchorNode;
|
|
3450
|
+
const domAnchorNode = resolvedAnchorNode ?? getDOMSelectionPoints(domSelection, nextActiveEditor._rootElement).anchorNode;
|
|
3180
3451
|
if (isHTMLElement(domAnchorNode) || isDOMTextNode(domAnchorNode)) $setSelection($internalCreateRangeSelection(lastSelection, domSelection, nextActiveEditor, event));
|
|
3181
3452
|
});
|
|
3182
3453
|
}
|
|
@@ -3200,9 +3471,19 @@ function hasStoppedLexicalPropagation(event) {
|
|
|
3200
3471
|
function addRootElementEvents(rootElement, editor) {
|
|
3201
3472
|
const doc = rootElement.ownerDocument;
|
|
3202
3473
|
rootElementToDocument.set(rootElement, doc);
|
|
3203
|
-
|
|
3204
|
-
if (
|
|
3205
|
-
|
|
3474
|
+
let registration = documentRegistrations.get(doc);
|
|
3475
|
+
if (registration === void 0) {
|
|
3476
|
+
registration = {
|
|
3477
|
+
editors: /* @__PURE__ */ new Set(),
|
|
3478
|
+
hasShadowEditor: void 0,
|
|
3479
|
+
rootElementCount: 0
|
|
3480
|
+
};
|
|
3481
|
+
documentRegistrations.set(doc, registration);
|
|
3482
|
+
}
|
|
3483
|
+
if (registration.rootElementCount < 1) doc.addEventListener("selectionchange", onDocumentSelectionChange);
|
|
3484
|
+
registration.rootElementCount += 1;
|
|
3485
|
+
registration.editors.add(editor);
|
|
3486
|
+
registration.hasShadowEditor = void 0;
|
|
3206
3487
|
rootElement.__lexicalEditor = editor;
|
|
3207
3488
|
const removeHandles = getRootElementRemoveHandles(rootElement);
|
|
3208
3489
|
for (let i = 0; i < rootElementEvents.length; i++) {
|
|
@@ -3240,19 +3521,21 @@ function removeRootElementEvents(rootElement) {
|
|
|
3240
3521
|
rootElementNotRegisteredWarning();
|
|
3241
3522
|
return;
|
|
3242
3523
|
}
|
|
3243
|
-
const
|
|
3244
|
-
if (
|
|
3524
|
+
const registration = documentRegistrations.get(doc);
|
|
3525
|
+
if (registration === void 0) {
|
|
3245
3526
|
rootElementNotRegisteredWarning();
|
|
3246
3527
|
return;
|
|
3247
3528
|
}
|
|
3248
|
-
const newCount =
|
|
3529
|
+
const newCount = registration.rootElementCount - 1;
|
|
3249
3530
|
if (!(newCount >= 0)) formatDevErrorMessage(`Root element count less than 0`);
|
|
3250
3531
|
rootElementToDocument.delete(rootElement);
|
|
3251
|
-
|
|
3532
|
+
registration.rootElementCount = newCount;
|
|
3252
3533
|
if (newCount === 0) doc.removeEventListener("selectionchange", onDocumentSelectionChange);
|
|
3253
3534
|
const editor = getEditorPropertyFromDOMNode(rootElement);
|
|
3254
3535
|
if (isLexicalEditor(editor)) {
|
|
3255
3536
|
cleanActiveNestedEditorsMap(editor);
|
|
3537
|
+
registration.editors.delete(editor);
|
|
3538
|
+
registration.hasShadowEditor = void 0;
|
|
3256
3539
|
rootElement.__lexicalEditor = null;
|
|
3257
3540
|
} else if (editor) formatDevErrorMessage(`Attempted to remove event handlers from a node that does not belong to this build of Lexical`);
|
|
3258
3541
|
const removeHandles = getRootElementRemoveHandles(rootElement);
|
|
@@ -3297,6 +3580,15 @@ function markCollapsedSelectionFormat(format, style, offset, key, timeStamp) {
|
|
|
3297
3580
|
/**
|
|
3298
3581
|
* This is the type of LexicalNode.$config() that can be
|
|
3299
3582
|
* overridden by subclasses.
|
|
3583
|
+
*
|
|
3584
|
+
* Concrete nodes are keyed by their string `type`. An abstract base class
|
|
3585
|
+
* (such as ElementNode or DecoratorNode) has no concrete node `type`, so when
|
|
3586
|
+
* it needs to declare configuration that is shared with its concrete
|
|
3587
|
+
* subclasses (for example required {@link RequiredNodeStateConfig} state or a
|
|
3588
|
+
* `$transform`) it is keyed instead by a well-known symbol, by convention
|
|
3589
|
+
* `Symbol.for(<NodeClassName>)` (e.g. `Symbol.for('ElementNode')`). The
|
|
3590
|
+
* descriptive, globally-registered symbol keeps the config easy to find in a
|
|
3591
|
+
* debugger and can never collide with a real node `type`.
|
|
3300
3592
|
*/
|
|
3301
3593
|
/**
|
|
3302
3594
|
* Used to extract the node and type from a StaticNodeConfigRecord
|
|
@@ -3307,8 +3599,97 @@ function markCollapsedSelectionFormat(format, style, offset, key, timeStamp) {
|
|
|
3307
3599
|
/**
|
|
3308
3600
|
* @internal
|
|
3309
3601
|
*
|
|
3602
|
+
* Type-only key under which a {@link StaticNodeConfigRecord} carries the node's
|
|
3603
|
+
* own (most-derived) `type` as a nullary accessor `() => Type`.
|
|
3604
|
+
*
|
|
3605
|
+
* TypeScript's type system is structural, so a node subclass that adds no
|
|
3606
|
+
* type-distinguishable members over its base (e.g. {@link TabNode} over
|
|
3607
|
+
* {@link TextNode}, which only overrides methods with identical signatures) is
|
|
3608
|
+
* structurally identical to that base despite being a distinct class — the
|
|
3609
|
+
* negative branch of an `instanceof`-style guard like `$isTabNode()` would
|
|
3610
|
+
* otherwise collapse to `never` because TypeScript concludes the base is also
|
|
3611
|
+
* assignable to the subclass.
|
|
3612
|
+
*
|
|
3613
|
+
* Encoding the type as a *function* (rather than a bare `Type`) lets the
|
|
3614
|
+
* accessor accumulate down the `extends` chain by intersection: a subclass'
|
|
3615
|
+
* record is `ParentRecord & {[STATIC_NODE_TYPE]: () => OwnType}`, so the key
|
|
3616
|
+
* holds `(() => ParentType) & (() => OwnType)`. TypeScript resolves an
|
|
3617
|
+
* intersection of call signatures as an overload set, which has two effects:
|
|
3618
|
+
*
|
|
3619
|
+
* - {@link GetStaticNodeType} reads `ReturnType<...>`, which selects the *last*
|
|
3620
|
+
* overload — the most-derived own `type` — rather than a union of the chain.
|
|
3621
|
+
* - A node stays assignable to each of its ancestors (the intersection
|
|
3622
|
+
* satisfies every `() => AncestorType`) while an ancestor is not assignable
|
|
3623
|
+
* to it (it lacks the `() => OwnType` signature), so guards narrow correctly
|
|
3624
|
+
* at every level of the hierarchy — not just one.
|
|
3625
|
+
*
|
|
3626
|
+
* This keeps the node classes themselves nominally distinguishable along their
|
|
3627
|
+
* real hierarchy; it is not a cross-cutting trait marker. The accessor is never
|
|
3628
|
+
* read at runtime — `config()` does not set this key — so it is `declare`-only
|
|
3629
|
+
* and carries no runtime cost. It is `@internal` (surfaced via the
|
|
3630
|
+
* {@link StaticNodeTypeAccessor} interface so that inferred `$config()` return
|
|
3631
|
+
* types remain nameable in generated declaration files) and a node never
|
|
3632
|
+
* references it. Distinction is automatic for any node that declares its
|
|
3633
|
+
* `extends`; a subclass adds nothing by hand.
|
|
3634
|
+
*/
|
|
3635
|
+
/**
|
|
3636
|
+
* @internal
|
|
3637
|
+
*
|
|
3638
|
+
* Carries a node's own `type` under the {@link STATIC_NODE_TYPE} accessor. This
|
|
3639
|
+
* is an `interface` (rather than an inline object type) on purpose: it is never
|
|
3640
|
+
* inlined in generated declaration files, so a subclass' `$config()` return type
|
|
3641
|
+
* references it by name (`StaticNodeTypeAccessor<'tab'>`) and the symbol key
|
|
3642
|
+
* stays encapsulated here rather than leaking — unnamed — into every node's
|
|
3643
|
+
* `.d.ts`.
|
|
3644
|
+
*/
|
|
3645
|
+
/**
|
|
3646
|
+
* @internal
|
|
3647
|
+
*
|
|
3648
|
+
* Type-only key under which a {@link StaticNodeConfigRecord} carries the node's
|
|
3649
|
+
* own configuration (the value passed to {@link LexicalNode.config}) as a
|
|
3650
|
+
* nullary accessor `() => Config`.
|
|
3651
|
+
*
|
|
3652
|
+
* This mirrors {@link STATIC_NODE_TYPE}: encoding the config as a *function*
|
|
3653
|
+
* lets it accumulate down the `extends` chain by call-signature intersection so
|
|
3654
|
+
* that `ReturnType<...>` resolves the most-derived own config. It exists so that
|
|
3655
|
+
* an abstract base class keyed by a symbol — which has no string `type` to index
|
|
3656
|
+
* the record by — can still expose its own config to the state-config
|
|
3657
|
+
* collectors, and so that such a base's symbol-keyed `$config()` return remains
|
|
3658
|
+
* a valid override of an accessor-bearing superclass `$config()` (it inherits
|
|
3659
|
+
* the superclass record, hence that record's {@link STATIC_NODE_TYPE} accessor).
|
|
3660
|
+
* Never read at runtime — `config()` does not set this key — so it is
|
|
3661
|
+
* `declare`-only and carries no runtime cost.
|
|
3662
|
+
*/
|
|
3663
|
+
/**
|
|
3664
|
+
* @internal
|
|
3665
|
+
*
|
|
3666
|
+
* Carries a node's own config under the {@link STATIC_NODE_CONFIG} accessor.
|
|
3667
|
+
* Like {@link StaticNodeTypeAccessor} this is a named `interface` so the symbol
|
|
3668
|
+
* key stays encapsulated and inferred `$config()` return types remain nameable
|
|
3669
|
+
* in generated declaration files.
|
|
3670
|
+
*/
|
|
3671
|
+
/**
|
|
3672
|
+
* @internal
|
|
3673
|
+
*
|
|
3310
3674
|
* This is the more specific type than BaseStaticNodeConfig that a subclass
|
|
3311
|
-
* should return from $config()
|
|
3675
|
+
* should return from $config().
|
|
3676
|
+
*
|
|
3677
|
+
* A node that declares its `extends` accumulates the configuration of its
|
|
3678
|
+
* superclass and records its own `type` under {@link STATIC_NODE_TYPE} and its
|
|
3679
|
+
* own config under {@link STATIC_NODE_CONFIG}, so that it is nominally distinct
|
|
3680
|
+
* from — yet still assignable to — that superclass, and so the state-config
|
|
3681
|
+
* collectors can read its own config without indexing by `type`.
|
|
3682
|
+
*/
|
|
3683
|
+
/**
|
|
3684
|
+
* @internal
|
|
3685
|
+
*
|
|
3686
|
+
* The record returned by {@link LexicalNode.config} for an abstract base class
|
|
3687
|
+
* keyed by a symbol. Unlike {@link StaticNodeConfigRecord} it records no string
|
|
3688
|
+
* `type` and adds no {@link STATIC_NODE_TYPE} accessor (an abstract base has no
|
|
3689
|
+
* concrete node type), but it does inherit its superclass record and expose its
|
|
3690
|
+
* own config under {@link STATIC_NODE_CONFIG}. Inheriting the superclass record
|
|
3691
|
+
* is what keeps the override valid when the superclass is a concrete node whose
|
|
3692
|
+
* `$config()` return already carries a {@link STATIC_NODE_TYPE} accessor.
|
|
3312
3693
|
*/
|
|
3313
3694
|
/**
|
|
3314
3695
|
* Extract the type from a node based on its $config
|
|
@@ -3320,6 +3701,16 @@ function markCollapsedSelectionFormat(format, style, offset, key, timeStamp) {
|
|
|
3320
3701
|
* ```
|
|
3321
3702
|
*/
|
|
3322
3703
|
/**
|
|
3704
|
+
* @internal
|
|
3705
|
+
*
|
|
3706
|
+
* A node's own config (the value it passed to {@link LexicalNode.config}), read
|
|
3707
|
+
* from the {@link STATIC_NODE_CONFIG} accessor, or `never` for a node whose
|
|
3708
|
+
* `$config()` does not set that accessor (a legacy node, or one whose record
|
|
3709
|
+
* uses the {@link BaseStaticNodeConfig} fallback). Unlike indexing the record by
|
|
3710
|
+
* a resolved string `type`, this also resolves the own config of an abstract
|
|
3711
|
+
* base class keyed by a symbol.
|
|
3712
|
+
*/
|
|
3713
|
+
/**
|
|
3323
3714
|
* The most precise type we can infer for the JSON that will
|
|
3324
3715
|
* be produced by T.exportJSON().
|
|
3325
3716
|
*
|
|
@@ -3334,7 +3725,10 @@ function $removeNode(nodeToRemove, restoreSelection, preserveEmptyParent) {
|
|
|
3334
3725
|
errorOnReadOnly();
|
|
3335
3726
|
const key = nodeToRemove.__key;
|
|
3336
3727
|
const parent = nodeToRemove.getParent();
|
|
3337
|
-
if (parent === null)
|
|
3728
|
+
if (parent === null) {
|
|
3729
|
+
if (!($getSlotHostKey(nodeToRemove) === null)) formatDevErrorMessage(`$removeNode: node ${key} is slotted into host ${String($getSlotHostKey(nodeToRemove))}; use removeSlot on the host instead of remove().`);
|
|
3730
|
+
return;
|
|
3731
|
+
}
|
|
3338
3732
|
const selection = $maybeMoveChildrenSelectionToParent(nodeToRemove);
|
|
3339
3733
|
let selectionMoved = false;
|
|
3340
3734
|
if ($isRangeSelection(selection) && restoreSelection) {
|
|
@@ -3351,9 +3745,9 @@ function $removeNode(nodeToRemove, restoreSelection, preserveEmptyParent) {
|
|
|
3351
3745
|
} else if ($isNodeSelection(selection) && restoreSelection && nodeToRemove.isSelected()) nodeToRemove.selectPrevious();
|
|
3352
3746
|
if ($isRangeSelection(selection) && restoreSelection && !selectionMoved) {
|
|
3353
3747
|
const index = nodeToRemove.getIndexWithinParent();
|
|
3354
|
-
removeFromParent(nodeToRemove);
|
|
3748
|
+
$removeFromParent(nodeToRemove);
|
|
3355
3749
|
$updateElementSelectionOnCreateDeleteNode(selection, parent, index, -1);
|
|
3356
|
-
} else removeFromParent(nodeToRemove);
|
|
3750
|
+
} else $removeFromParent(nodeToRemove);
|
|
3357
3751
|
if (!preserveEmptyParent && !$isRootOrShadowRoot(parent) && !parent.canBeEmpty() && parent.isEmpty()) $removeNode(parent, restoreSelection);
|
|
3358
3752
|
if (restoreSelection && selection && $isRootNode(parent) && parent.isEmpty()) parent.selectEnd();
|
|
3359
3753
|
}
|
|
@@ -3390,6 +3784,23 @@ const NON_ENUMERABLE_PROP_DESC = {
|
|
|
3390
3784
|
value: void 0,
|
|
3391
3785
|
writable: true
|
|
3392
3786
|
};
|
|
3787
|
+
/**
|
|
3788
|
+
* A node that can host named slots, implemented by {@link ElementNode} and
|
|
3789
|
+
* {@link DecoratorNode}. The map is allocated lazily (null until the first
|
|
3790
|
+
* {@link $setSlot}) since most nodes have none. Declaring this off the base
|
|
3791
|
+
* {@link LexicalNode} is what lets {@link $setSlot} / {@link $removeSlot}
|
|
3792
|
+
* reject a non-host at compile time.
|
|
3793
|
+
*
|
|
3794
|
+
* @experimental
|
|
3795
|
+
*/
|
|
3796
|
+
/**
|
|
3797
|
+
* A node that can occupy a named slot, implemented by {@link ElementNode} and
|
|
3798
|
+
* {@link DecoratorNode}. Its up-pointer is `__slotHost` rather than `__parent`
|
|
3799
|
+
* (the two are mutually exclusive), so the slot boundary behaves like a shadow
|
|
3800
|
+
* root.
|
|
3801
|
+
*
|
|
3802
|
+
* @experimental
|
|
3803
|
+
*/
|
|
3393
3804
|
var LexicalNode = class {
|
|
3394
3805
|
/** @internal Allow us to look up the type including static props */
|
|
3395
3806
|
/** @internal */
|
|
@@ -3448,13 +3859,15 @@ var LexicalNode = class {
|
|
|
3448
3859
|
* This is a convenience method for $config that
|
|
3449
3860
|
* aids in type inference. See {@link LexicalNode.$config}
|
|
3450
3861
|
* for example usage.
|
|
3862
|
+
*
|
|
3863
|
+
* An abstract base class that has no concrete node `type` may pass a
|
|
3864
|
+
* well-known symbol (by convention `Symbol.for(<NodeClassName>)`) instead of
|
|
3865
|
+
* a string `type` to declare configuration shared with its subclasses.
|
|
3451
3866
|
*/
|
|
3452
3867
|
config(type, config) {
|
|
3453
|
-
const parentKlass = config.extends ||
|
|
3454
|
-
Object.assign(config, {
|
|
3455
|
-
|
|
3456
|
-
type
|
|
3457
|
-
});
|
|
3868
|
+
const parentKlass = config.extends || getSuperclassOf(this.constructor);
|
|
3869
|
+
Object.assign(config, { extends: parentKlass });
|
|
3870
|
+
if (typeof type === "string") Object.assign(config, { type });
|
|
3458
3871
|
return { [type]: config };
|
|
3459
3872
|
}
|
|
3460
3873
|
/**
|
|
@@ -3554,7 +3967,7 @@ var LexicalNode = class {
|
|
|
3554
3967
|
if (nodeKey === "root") return true;
|
|
3555
3968
|
const node = $getNodeByKey(nodeKey);
|
|
3556
3969
|
if (node === null) break;
|
|
3557
|
-
nodeKey = node.__parent;
|
|
3970
|
+
nodeKey = node.__parent !== null ? node.__parent : $getSlotHostKey(node);
|
|
3558
3971
|
}
|
|
3559
3972
|
return false;
|
|
3560
3973
|
}
|
|
@@ -3604,6 +4017,12 @@ var LexicalNode = class {
|
|
|
3604
4017
|
/**
|
|
3605
4018
|
* Returns the parent of this node, or null if none is found.
|
|
3606
4019
|
*/
|
|
4020
|
+
/**
|
|
4021
|
+
* @deprecated The type parameter is an unchecked and unsafe cast,
|
|
4022
|
+
* equivalent to `node.getParent() as T | null`, and will be removed
|
|
4023
|
+
* in a future release. Call this method without a type argument and
|
|
4024
|
+
* narrow the result with a type guard instead.
|
|
4025
|
+
*/
|
|
3607
4026
|
getParent() {
|
|
3608
4027
|
const parent = this.getLatest().__parent;
|
|
3609
4028
|
if (parent === null) return null;
|
|
@@ -3612,6 +4031,12 @@ var LexicalNode = class {
|
|
|
3612
4031
|
/**
|
|
3613
4032
|
* Returns the parent of this node, or throws if none is found.
|
|
3614
4033
|
*/
|
|
4034
|
+
/**
|
|
4035
|
+
* @deprecated The type parameter is an unchecked and unsafe cast,
|
|
4036
|
+
* equivalent to `node.getParentOrThrow() as T`, and will be removed
|
|
4037
|
+
* in a future release. Call this method without a type argument and
|
|
4038
|
+
* narrow the result with a type guard instead.
|
|
4039
|
+
*/
|
|
3615
4040
|
getParentOrThrow() {
|
|
3616
4041
|
const parent = this.getParent();
|
|
3617
4042
|
if (parent === null) formatDevErrorMessage(`Expected node ${this.__key} to have a parent.`);
|
|
@@ -3626,7 +4051,7 @@ var LexicalNode = class {
|
|
|
3626
4051
|
let node = this;
|
|
3627
4052
|
while (node !== null) {
|
|
3628
4053
|
const parent = node.getParent();
|
|
3629
|
-
if ($isRootOrShadowRoot(parent)) {
|
|
4054
|
+
if ($isRootOrShadowRoot(parent) || $getSlotHostKey(node) !== null) {
|
|
3630
4055
|
if (!($isElementNode(node) || node === this && $isDecoratorNode(node))) formatDevErrorMessage(`Children of root nodes must be elements or decorators`);
|
|
3631
4056
|
return node;
|
|
3632
4057
|
}
|
|
@@ -3673,18 +4098,28 @@ var LexicalNode = class {
|
|
|
3673
4098
|
return parents;
|
|
3674
4099
|
}
|
|
3675
4100
|
/**
|
|
3676
|
-
* Returns the
|
|
3677
|
-
*
|
|
3678
|
-
|
|
4101
|
+
* Returns the node before this one in the same parent, or null
|
|
4102
|
+
* if there is no such node.
|
|
4103
|
+
*/
|
|
4104
|
+
/**
|
|
4105
|
+
* @deprecated The type parameter is an unchecked and unsafe cast,
|
|
4106
|
+
* equivalent to `node.getPreviousSibling() as T | null`, and will be
|
|
4107
|
+
* removed in a future release. Call this method without a type argument
|
|
4108
|
+
* and narrow the result with a type guard instead.
|
|
3679
4109
|
*/
|
|
3680
4110
|
getPreviousSibling() {
|
|
3681
4111
|
const prevKey = this.getLatest().__prev;
|
|
3682
4112
|
return prevKey === null ? null : $getNodeByKey(prevKey);
|
|
3683
4113
|
}
|
|
3684
4114
|
/**
|
|
3685
|
-
* Returns
|
|
3686
|
-
*
|
|
3687
|
-
|
|
4115
|
+
* Returns all nodes before this one in the same parent,
|
|
4116
|
+
* in document order.
|
|
4117
|
+
*/
|
|
4118
|
+
/**
|
|
4119
|
+
* @deprecated The type parameter is an unchecked and unsafe cast,
|
|
4120
|
+
* equivalent to `node.getPreviousSiblings() as T[]`, and will be
|
|
4121
|
+
* removed in a future release. Call this method without a type argument
|
|
4122
|
+
* and narrow the results with a type guard instead.
|
|
3688
4123
|
*/
|
|
3689
4124
|
getPreviousSiblings() {
|
|
3690
4125
|
const siblings = [];
|
|
@@ -3699,18 +4134,28 @@ var LexicalNode = class {
|
|
|
3699
4134
|
return siblings;
|
|
3700
4135
|
}
|
|
3701
4136
|
/**
|
|
3702
|
-
* Returns the
|
|
3703
|
-
*
|
|
3704
|
-
|
|
4137
|
+
* Returns the node after this one in the same parent, or null
|
|
4138
|
+
* if there is no such node.
|
|
4139
|
+
*/
|
|
4140
|
+
/**
|
|
4141
|
+
* @deprecated The type parameter is an unchecked and unsafe cast,
|
|
4142
|
+
* equivalent to `node.getNextSibling() as T | null`, and will be
|
|
4143
|
+
* removed in a future release. Call this method without a type argument
|
|
4144
|
+
* and narrow the result with a type guard instead.
|
|
3705
4145
|
*/
|
|
3706
4146
|
getNextSibling() {
|
|
3707
4147
|
const nextKey = this.getLatest().__next;
|
|
3708
4148
|
return nextKey === null ? null : $getNodeByKey(nextKey);
|
|
3709
4149
|
}
|
|
3710
4150
|
/**
|
|
3711
|
-
* Returns all
|
|
3712
|
-
*
|
|
3713
|
-
|
|
4151
|
+
* Returns all nodes after this one in the same parent,
|
|
4152
|
+
* in document order.
|
|
4153
|
+
*/
|
|
4154
|
+
/**
|
|
4155
|
+
* @deprecated The type parameter is an unchecked and unsafe cast,
|
|
4156
|
+
* equivalent to `node.getNextSiblings() as T[]`, and will be
|
|
4157
|
+
* removed in a future release. Call this method without a type argument
|
|
4158
|
+
* and narrow the results with a type guard instead.
|
|
3714
4159
|
*/
|
|
3715
4160
|
getNextSiblings() {
|
|
3716
4161
|
const siblings = [];
|
|
@@ -3873,7 +4318,7 @@ var LexicalNode = class {
|
|
|
3873
4318
|
*
|
|
3874
4319
|
*/
|
|
3875
4320
|
getTextContent() {
|
|
3876
|
-
return
|
|
4321
|
+
return $getSlotsTextContent(this);
|
|
3877
4322
|
}
|
|
3878
4323
|
/**
|
|
3879
4324
|
* Returns the length of the string produced by calling getTextContent on this node.
|
|
@@ -4034,10 +4479,11 @@ var LexicalNode = class {
|
|
|
4034
4479
|
const key = replaceWith.__key;
|
|
4035
4480
|
const writableReplaceWith = replaceWith.getWritable();
|
|
4036
4481
|
const writableParent = this.getParentOrThrow().getWritable();
|
|
4482
|
+
$errorOnSlotCycleChild(writableParent, writableReplaceWith);
|
|
4037
4483
|
const size = writableParent.__size;
|
|
4038
4484
|
const replaceWithOldParent = writableReplaceWith.getParent();
|
|
4039
4485
|
const replaceWithOldIndex = replaceWithOldParent !== null ? writableReplaceWith.getIndexWithinParent() : -1;
|
|
4040
|
-
removeFromParent(writableReplaceWith);
|
|
4486
|
+
$removeFromParent(writableReplaceWith);
|
|
4041
4487
|
if (replaceWithOldParent !== null && $isRangeSelection(selection)) $updateElementSelectionOnCreateDeleteNode(selection, replaceWithOldParent, replaceWithOldIndex, -1);
|
|
4042
4488
|
const prevSibling = self.getPreviousSibling();
|
|
4043
4489
|
const nextSibling = self.getNextSibling();
|
|
@@ -4065,6 +4511,17 @@ var LexicalNode = class {
|
|
|
4065
4511
|
prevSizeBeforeChildrenTransfer = writableReplaceWith.getChildrenSize();
|
|
4066
4512
|
writableReplaceWith.splice(prevSizeBeforeChildrenTransfer, 0, this.getChildren());
|
|
4067
4513
|
}
|
|
4514
|
+
const slotNames = $getSlotNames(this);
|
|
4515
|
+
if (slotNames.length > 0) {
|
|
4516
|
+
if (!$isSlotHost(this) || !$isSlotHost(writableReplaceWith)) formatDevErrorMessage(`replace: node ${this.__key} has slots but ${writableReplaceWith.__key} cannot host them; only ElementNodes and DecoratorNodes can host slots.`);
|
|
4517
|
+
for (const slotName of slotNames) {
|
|
4518
|
+
const slot = $getSlot(this, slotName);
|
|
4519
|
+
if (slot !== null) {
|
|
4520
|
+
$removeSlot(this, slotName);
|
|
4521
|
+
$setSlot(writableReplaceWith, slotName, slot);
|
|
4522
|
+
}
|
|
4523
|
+
}
|
|
4524
|
+
}
|
|
4068
4525
|
if ($isRangeSelection(selection)) {
|
|
4069
4526
|
$setSelection(selection);
|
|
4070
4527
|
const anchor = selection.anchor;
|
|
@@ -4089,6 +4546,7 @@ var LexicalNode = class {
|
|
|
4089
4546
|
errorOnInsertTextNodeOnRoot(this, nodeToInsert);
|
|
4090
4547
|
const writableSelf = this.getWritable();
|
|
4091
4548
|
const writableNodeToInsert = nodeToInsert.getWritable();
|
|
4549
|
+
$errorOnSlotCycleChild(this.getParentOrThrow(), writableNodeToInsert);
|
|
4092
4550
|
const oldParent = writableNodeToInsert.getParent();
|
|
4093
4551
|
const selection = $getSelection();
|
|
4094
4552
|
let elementAnchorSelectionOnNode = false;
|
|
@@ -4102,9 +4560,9 @@ var LexicalNode = class {
|
|
|
4102
4560
|
elementAnchorSelectionOnNode = anchor.type === "element" && anchor.key === oldParentKey && anchor.offset === oldIndex + 1;
|
|
4103
4561
|
elementFocusSelectionOnNode = focus.type === "element" && focus.key === oldParentKey && focus.offset === oldIndex + 1;
|
|
4104
4562
|
}
|
|
4105
|
-
removeFromParent(writableNodeToInsert);
|
|
4563
|
+
$removeFromParent(writableNodeToInsert);
|
|
4106
4564
|
if (restoreSelection && $isRangeSelection(selection)) $updateElementSelectionOnCreateDeleteNode(selection, oldParent, oldIndex, -1);
|
|
4107
|
-
}
|
|
4565
|
+
} else $removeFromParent(writableNodeToInsert);
|
|
4108
4566
|
const nextSibling = this.getNextSibling();
|
|
4109
4567
|
const writableParent = this.getParentOrThrow().getWritable();
|
|
4110
4568
|
const insertKey = writableNodeToInsert.__key;
|
|
@@ -4140,11 +4598,12 @@ var LexicalNode = class {
|
|
|
4140
4598
|
errorOnInsertTextNodeOnRoot(this, nodeToInsert);
|
|
4141
4599
|
const writableSelf = this.getWritable();
|
|
4142
4600
|
const writableNodeToInsert = nodeToInsert.getWritable();
|
|
4601
|
+
$errorOnSlotCycleChild(this.getParentOrThrow(), writableNodeToInsert);
|
|
4143
4602
|
const insertKey = writableNodeToInsert.__key;
|
|
4144
4603
|
const selection = $getSelection();
|
|
4145
4604
|
const insertOldParent = writableNodeToInsert.getParent();
|
|
4146
4605
|
const insertOldIndex = insertOldParent !== null ? writableNodeToInsert.getIndexWithinParent() : -1;
|
|
4147
|
-
removeFromParent(writableNodeToInsert);
|
|
4606
|
+
$removeFromParent(writableNodeToInsert);
|
|
4148
4607
|
if (insertOldParent !== null && restoreSelection && $isRangeSelection(selection)) $updateElementSelectionOnCreateDeleteNode(selection, insertOldParent, insertOldIndex, -1);
|
|
4149
4608
|
const prevSibling = this.getPreviousSibling();
|
|
4150
4609
|
const writableParent = this.getParentOrThrow().getWritable();
|
|
@@ -4193,6 +4652,8 @@ var LexicalNode = class {
|
|
|
4193
4652
|
* */
|
|
4194
4653
|
selectPrevious(anchorOffset, focusOffset) {
|
|
4195
4654
|
errorOnReadOnly();
|
|
4655
|
+
const slotHost = $getSlotHost(this);
|
|
4656
|
+
if (slotHost !== null) return slotHost.selectPrevious(anchorOffset, focusOffset);
|
|
4196
4657
|
const prevSibling = this.getPreviousSibling();
|
|
4197
4658
|
const parent = this.getParentOrThrow();
|
|
4198
4659
|
if (prevSibling === null) return parent.select(0, 0);
|
|
@@ -4211,6 +4672,8 @@ var LexicalNode = class {
|
|
|
4211
4672
|
* */
|
|
4212
4673
|
selectNext(anchorOffset, focusOffset) {
|
|
4213
4674
|
errorOnReadOnly();
|
|
4675
|
+
const slotHost = $getSlotHost(this);
|
|
4676
|
+
if (slotHost !== null) return slotHost.selectNext(anchorOffset, focusOffset);
|
|
4214
4677
|
const nextSibling = this.getNextSibling();
|
|
4215
4678
|
const parent = this.getParentOrThrow();
|
|
4216
4679
|
if (nextSibling === null) return parent.select();
|
|
@@ -4298,6 +4761,10 @@ const HISTORY_MERGE_TAG = "history-merge";
|
|
|
4298
4761
|
*/
|
|
4299
4762
|
const PASTE_TAG = "paste";
|
|
4300
4763
|
/**
|
|
4764
|
+
* Indicates that the update is related to a cut operation
|
|
4765
|
+
*/
|
|
4766
|
+
const CUT_TAG = "cut";
|
|
4767
|
+
/**
|
|
4301
4768
|
* Indicates that the update is related to collaborative editing
|
|
4302
4769
|
*/
|
|
4303
4770
|
const COLLABORATION_TAG = "collaboration";
|
|
@@ -4341,7 +4808,7 @@ const COMPOSITION_END_TAG = "composition-end";
|
|
|
4341
4808
|
* LICENSE file in the root directory of this source tree.
|
|
4342
4809
|
*
|
|
4343
4810
|
*/
|
|
4344
|
-
const
|
|
4811
|
+
const IMPORTANT_FLAG = "!important";
|
|
4345
4812
|
/**
|
|
4346
4813
|
* Parses inline CSS text into an object that is compatible with
|
|
4347
4814
|
* `CSSStyleDeclaration.setProperty()`.
|
|
@@ -4359,7 +4826,9 @@ function getStyleObjectFromCSS(css) {
|
|
|
4359
4826
|
let isEscaped = false;
|
|
4360
4827
|
let isParsingValue = false;
|
|
4361
4828
|
let parenthesisDepth = 0;
|
|
4362
|
-
|
|
4829
|
+
const length = css.length;
|
|
4830
|
+
let chunkStart = -1;
|
|
4831
|
+
for (let i = 0; i < length; i++) {
|
|
4363
4832
|
const char = css[i];
|
|
4364
4833
|
if (inComment) {
|
|
4365
4834
|
if (char === "*" && css[i + 1] === "/") {
|
|
@@ -4369,46 +4838,55 @@ function getStyleObjectFromCSS(css) {
|
|
|
4369
4838
|
continue;
|
|
4370
4839
|
}
|
|
4371
4840
|
if (isEscaped) {
|
|
4372
|
-
if (
|
|
4373
|
-
else currentProperty += char;
|
|
4841
|
+
if (chunkStart === -1) chunkStart = i;
|
|
4374
4842
|
isEscaped = false;
|
|
4375
4843
|
continue;
|
|
4376
4844
|
}
|
|
4377
4845
|
if (currentQuote !== null) {
|
|
4378
|
-
if (
|
|
4379
|
-
else currentProperty += char;
|
|
4846
|
+
if (chunkStart === -1) chunkStart = i;
|
|
4380
4847
|
if (char === "\\") isEscaped = true;
|
|
4381
4848
|
else if (char === currentQuote) currentQuote = null;
|
|
4382
4849
|
continue;
|
|
4383
4850
|
}
|
|
4384
4851
|
if (char === "/" && css[i + 1] === "*") {
|
|
4852
|
+
if (chunkStart !== -1) {
|
|
4853
|
+
if (isParsingValue) currentValue += css.slice(chunkStart, i);
|
|
4854
|
+
else currentProperty += css.slice(chunkStart, i);
|
|
4855
|
+
chunkStart = -1;
|
|
4856
|
+
}
|
|
4385
4857
|
inComment = true;
|
|
4386
4858
|
i++;
|
|
4387
4859
|
continue;
|
|
4388
4860
|
}
|
|
4389
4861
|
if (char === "\"" || char === "'") {
|
|
4862
|
+
if (chunkStart === -1) chunkStart = i;
|
|
4390
4863
|
currentQuote = char;
|
|
4391
|
-
if (isParsingValue) currentValue += char;
|
|
4392
|
-
else currentProperty += char;
|
|
4393
4864
|
continue;
|
|
4394
4865
|
}
|
|
4395
4866
|
if (char === "(") {
|
|
4867
|
+
if (chunkStart === -1) chunkStart = i;
|
|
4396
4868
|
parenthesisDepth++;
|
|
4397
|
-
if (isParsingValue) currentValue += char;
|
|
4398
|
-
else currentProperty += char;
|
|
4399
4869
|
continue;
|
|
4400
4870
|
}
|
|
4401
4871
|
if (char === ")") {
|
|
4872
|
+
if (chunkStart === -1) chunkStart = i;
|
|
4402
4873
|
parenthesisDepth = Math.max(0, parenthesisDepth - 1);
|
|
4403
|
-
if (isParsingValue) currentValue += char;
|
|
4404
|
-
else currentProperty += char;
|
|
4405
4874
|
continue;
|
|
4406
4875
|
}
|
|
4407
4876
|
if (!isParsingValue && char === ":" && parenthesisDepth === 0) {
|
|
4877
|
+
if (chunkStart !== -1) {
|
|
4878
|
+
currentProperty += css.slice(chunkStart, i);
|
|
4879
|
+
chunkStart = -1;
|
|
4880
|
+
}
|
|
4408
4881
|
isParsingValue = true;
|
|
4409
4882
|
continue;
|
|
4410
4883
|
}
|
|
4411
4884
|
if (char === ";" && parenthesisDepth === 0) {
|
|
4885
|
+
if (chunkStart !== -1) {
|
|
4886
|
+
if (isParsingValue) currentValue += css.slice(chunkStart, i);
|
|
4887
|
+
else currentProperty += css.slice(chunkStart, i);
|
|
4888
|
+
chunkStart = -1;
|
|
4889
|
+
}
|
|
4412
4890
|
const property = currentProperty.trim();
|
|
4413
4891
|
const value = currentValue.trim();
|
|
4414
4892
|
if (property !== "" && value !== "") styles[property] = value;
|
|
@@ -4417,18 +4895,20 @@ function getStyleObjectFromCSS(css) {
|
|
|
4417
4895
|
isParsingValue = false;
|
|
4418
4896
|
continue;
|
|
4419
4897
|
}
|
|
4420
|
-
if (
|
|
4421
|
-
else currentProperty += char;
|
|
4898
|
+
if (chunkStart === -1) chunkStart = i;
|
|
4422
4899
|
}
|
|
4900
|
+
if (chunkStart !== -1) if (isParsingValue) currentValue += css.slice(chunkStart, length);
|
|
4901
|
+
else currentProperty += css.slice(chunkStart, length);
|
|
4423
4902
|
const property = currentProperty.trim();
|
|
4424
4903
|
const value = currentValue.trim();
|
|
4425
4904
|
if (property !== "" && value !== "") styles[property] = value;
|
|
4426
4905
|
return styles;
|
|
4427
4906
|
}
|
|
4428
4907
|
function setDOMStyleProperty(domStyle, property, value) {
|
|
4429
|
-
const
|
|
4430
|
-
const
|
|
4431
|
-
domStyle.setProperty(property,
|
|
4908
|
+
const trimmedValue = value.trimEnd();
|
|
4909
|
+
const flagStart = trimmedValue.length - 10;
|
|
4910
|
+
if (flagStart >= 0 && trimmedValue.slice(flagStart).toLowerCase() === IMPORTANT_FLAG) domStyle.setProperty(property, trimmedValue.slice(0, flagStart).trim(), "important");
|
|
4911
|
+
else domStyle.setProperty(property, value, "");
|
|
4432
4912
|
}
|
|
4433
4913
|
/**
|
|
4434
4914
|
* Applies a style object to a DOM style declaration using
|
|
@@ -4461,83 +4941,6 @@ function setDOMStyleFromCSS(domStyle, cssText, prevCSSText = "") {
|
|
|
4461
4941
|
}
|
|
4462
4942
|
for (const property in prevCSS) domStyle.removeProperty(property);
|
|
4463
4943
|
}
|
|
4464
|
-
/**
|
|
4465
|
-
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
4466
|
-
*
|
|
4467
|
-
* This source code is licensed under the MIT license found in the
|
|
4468
|
-
* LICENSE file in the root directory of this source tree.
|
|
4469
|
-
*
|
|
4470
|
-
*/
|
|
4471
|
-
/** @noInheritDoc */
|
|
4472
|
-
var LineBreakNode = class LineBreakNode extends LexicalNode {
|
|
4473
|
-
/** @internal */
|
|
4474
|
-
static getType() {
|
|
4475
|
-
return "linebreak";
|
|
4476
|
-
}
|
|
4477
|
-
static clone(node) {
|
|
4478
|
-
return new LineBreakNode(node.__key);
|
|
4479
|
-
}
|
|
4480
|
-
constructor(key) {
|
|
4481
|
-
super(key);
|
|
4482
|
-
}
|
|
4483
|
-
getTextContent() {
|
|
4484
|
-
return "\n";
|
|
4485
|
-
}
|
|
4486
|
-
createDOM() {
|
|
4487
|
-
return document.createElement("br");
|
|
4488
|
-
}
|
|
4489
|
-
updateDOM() {
|
|
4490
|
-
return false;
|
|
4491
|
-
}
|
|
4492
|
-
isInline() {
|
|
4493
|
-
return true;
|
|
4494
|
-
}
|
|
4495
|
-
static importDOM() {
|
|
4496
|
-
return { br: (node) => {
|
|
4497
|
-
if (isOnlyChildInBlockNode(node) || isLastChildInBlockNode(node)) return null;
|
|
4498
|
-
return {
|
|
4499
|
-
conversion: $convertLineBreakElement,
|
|
4500
|
-
priority: 0
|
|
4501
|
-
};
|
|
4502
|
-
} };
|
|
4503
|
-
}
|
|
4504
|
-
static importJSON(serializedLineBreakNode) {
|
|
4505
|
-
return $createLineBreakNode().updateFromJSON(serializedLineBreakNode);
|
|
4506
|
-
}
|
|
4507
|
-
};
|
|
4508
|
-
function $convertLineBreakElement(node) {
|
|
4509
|
-
return { node: $createLineBreakNode() };
|
|
4510
|
-
}
|
|
4511
|
-
function $createLineBreakNode() {
|
|
4512
|
-
return $applyNodeReplacement(new LineBreakNode());
|
|
4513
|
-
}
|
|
4514
|
-
function $isLineBreakNode(node) {
|
|
4515
|
-
return node instanceof LineBreakNode;
|
|
4516
|
-
}
|
|
4517
|
-
function isOnlyChildInBlockNode(node) {
|
|
4518
|
-
const parentElement = node.parentElement;
|
|
4519
|
-
if (parentElement !== null && isBlockDomNode(parentElement)) {
|
|
4520
|
-
const firstChild = parentElement.firstChild;
|
|
4521
|
-
if (firstChild === node || firstChild.nextSibling === node && isWhitespaceDomTextNode(firstChild)) {
|
|
4522
|
-
const lastChild = parentElement.lastChild;
|
|
4523
|
-
if (lastChild === node || lastChild.previousSibling === node && isWhitespaceDomTextNode(lastChild)) return true;
|
|
4524
|
-
}
|
|
4525
|
-
}
|
|
4526
|
-
return false;
|
|
4527
|
-
}
|
|
4528
|
-
function isLastChildInBlockNode(node) {
|
|
4529
|
-
const parentElement = node.parentElement;
|
|
4530
|
-
if (parentElement !== null && isBlockDomNode(parentElement)) {
|
|
4531
|
-
const firstChild = parentElement.firstChild;
|
|
4532
|
-
if (firstChild === node || firstChild.nextSibling === node && isWhitespaceDomTextNode(firstChild)) return false;
|
|
4533
|
-
const lastChild = parentElement.lastChild;
|
|
4534
|
-
if (lastChild === node || lastChild.previousSibling === node && isWhitespaceDomTextNode(lastChild)) return true;
|
|
4535
|
-
}
|
|
4536
|
-
return false;
|
|
4537
|
-
}
|
|
4538
|
-
function isWhitespaceDomTextNode(node) {
|
|
4539
|
-
return isDOMTextNode(node) && /^( |\t|\r?\n)+$/.test(node.textContent || "");
|
|
4540
|
-
}
|
|
4541
4944
|
function getElementOuterTag(node, format) {
|
|
4542
4945
|
if (format & 16) return "code";
|
|
4543
4946
|
if (format & 128) return "mark";
|
|
@@ -5273,18 +5676,7 @@ function $convertTextDOMNode(domNode) {
|
|
|
5273
5676
|
const domNode_ = domNode;
|
|
5274
5677
|
if (!(domNode.parentElement !== null)) formatDevErrorMessage(`Expected parentElement of Text not to be null`);
|
|
5275
5678
|
let textContent = domNode_.textContent || "";
|
|
5276
|
-
if (findParentPreDOMNode(domNode_) !== null) {
|
|
5277
|
-
const parts = textContent.split(/(\r?\n|\t)/);
|
|
5278
|
-
const nodes = [];
|
|
5279
|
-
const length = parts.length;
|
|
5280
|
-
for (let i = 0; i < length; i++) {
|
|
5281
|
-
const part = parts[i];
|
|
5282
|
-
if (part === "\n" || part === "\r\n") nodes.push($createLineBreakNode());
|
|
5283
|
-
else if (part === " ") nodes.push($createTabNode());
|
|
5284
|
-
else if (part !== "") nodes.push($createTextNode(part));
|
|
5285
|
-
}
|
|
5286
|
-
return { node: nodes };
|
|
5287
|
-
}
|
|
5679
|
+
if (findParentPreDOMNode(domNode_) !== null) return { node: $generateNodesFromRawText(textContent) };
|
|
5288
5680
|
textContent = textContent.replace(/\r/g, "").replace(/[ \t\n]+/g, " ");
|
|
5289
5681
|
if (textContent === "") return { node: null };
|
|
5290
5682
|
if (textContent[0] === " ") {
|
|
@@ -5401,8 +5793,11 @@ var TabNode = class TabNode extends TextNode {
|
|
|
5401
5793
|
static importJSON(serializedTabNode) {
|
|
5402
5794
|
return $createTabNode().updateFromJSON(serializedTabNode);
|
|
5403
5795
|
}
|
|
5404
|
-
|
|
5405
|
-
|
|
5796
|
+
/**
|
|
5797
|
+
* Always normalizes the stored content to `'\t'` regardless of input — see
|
|
5798
|
+
* comment below for the rationale.
|
|
5799
|
+
*/
|
|
5800
|
+
setTextContent(_text) {
|
|
5406
5801
|
return super.setTextContent(" ");
|
|
5407
5802
|
}
|
|
5408
5803
|
spliceText(offset, delCount, newText, moveSelection) {
|
|
@@ -5520,11 +5915,14 @@ function $transferStartingElementPointToTextPoint(start, end, format, style) {
|
|
|
5520
5915
|
textNode.setFormat(format);
|
|
5521
5916
|
textNode.setStyle(style);
|
|
5522
5917
|
if ($isParagraphNode(placementNode)) placementNode.splice(0, 0, [textNode]);
|
|
5523
|
-
else {
|
|
5524
|
-
const target = $
|
|
5525
|
-
|
|
5526
|
-
|
|
5527
|
-
|
|
5918
|
+
else if (placementNode !== null) {
|
|
5919
|
+
const target = $isRootOrShadowRoot(element) ? $createParagraphNode().append(textNode) : textNode;
|
|
5920
|
+
placementNode.insertBefore(target);
|
|
5921
|
+
} else if ($isRootOrShadowRoot(element)) {
|
|
5922
|
+
const lastChild = element.getLastChild();
|
|
5923
|
+
if ($isElementNode(lastChild) && !lastChild.isInline() && lastChild.isEmpty()) lastChild.append(textNode);
|
|
5924
|
+
else element.append($createParagraphNode().append(textNode));
|
|
5925
|
+
} else element.append(textNode);
|
|
5528
5926
|
if (start.is(end)) end.set(textNode.__key, 0, "text");
|
|
5529
5927
|
start.set(textNode.__key, 0, "text");
|
|
5530
5928
|
}
|
|
@@ -5585,8 +5983,9 @@ var NodeSelection = class NodeSelection {
|
|
|
5585
5983
|
insertRawText(text) {}
|
|
5586
5984
|
insertText() {}
|
|
5587
5985
|
insertNodes(nodes) {
|
|
5588
|
-
const selectedNodes = this.getNodes();
|
|
5986
|
+
const selectedNodes = this.getNodes().filter((node) => $getSlotHostKey(node) === null);
|
|
5589
5987
|
const selectedNodesLength = selectedNodes.length;
|
|
5988
|
+
if (selectedNodesLength === 0) return;
|
|
5590
5989
|
const lastSelectedNode = selectedNodes[selectedNodesLength - 1];
|
|
5591
5990
|
let selectionAtEnd;
|
|
5592
5991
|
if ($isTextNode(lastSelectedNode)) selectionAtEnd = lastSelectedNode.select();
|
|
@@ -5621,7 +6020,7 @@ var NodeSelection = class NodeSelection {
|
|
|
5621
6020
|
* location of the first node.
|
|
5622
6021
|
*/
|
|
5623
6022
|
deleteNodes() {
|
|
5624
|
-
const nodes = this.getNodes();
|
|
6023
|
+
const nodes = this.getNodes().filter((node) => $getSlotHostKey(node) === null);
|
|
5625
6024
|
if (($getSelection() || $getPreviousSelection()) === this && nodes[0]) {
|
|
5626
6025
|
const firstCaret = $getSiblingCaret(nodes[0], "next");
|
|
5627
6026
|
$setSelectionFromCaretRange($getCaretRange(firstCaret, firstCaret));
|
|
@@ -5729,7 +6128,15 @@ var RangeSelection = class RangeSelection {
|
|
|
5729
6128
|
const node = nodes[i];
|
|
5730
6129
|
if ($isElementNode(node) && !node.isInline()) {
|
|
5731
6130
|
if (!prevWasElement) textContent += "\n";
|
|
5732
|
-
|
|
6131
|
+
let slotText = "";
|
|
6132
|
+
for (const slotName of $getSlotNames(node)) {
|
|
6133
|
+
const slot = $getSlot(node, slotName);
|
|
6134
|
+
if (slot !== null) slotText += slot.getTextContent();
|
|
6135
|
+
}
|
|
6136
|
+
if (slotText !== "") {
|
|
6137
|
+
textContent += slotText;
|
|
6138
|
+
prevWasElement = false;
|
|
6139
|
+
} else if (node.isEmpty()) prevWasElement = false;
|
|
5733
6140
|
else prevWasElement = true;
|
|
5734
6141
|
} else {
|
|
5735
6142
|
prevWasElement = false;
|
|
@@ -5851,14 +6258,15 @@ var RangeSelection = class RangeSelection {
|
|
|
5851
6258
|
endPoint.set(firstPoint.key, endOffset, "text");
|
|
5852
6259
|
}
|
|
5853
6260
|
if (this.isCollapsed() && startOffset === firstNodeTextLength && ($isTokenOrSegmented(firstNode) || !firstNode.canInsertTextAfter() || !firstNodeParent.canInsertTextAfter() && firstNode.getNextSibling() === null)) {
|
|
5854
|
-
|
|
5855
|
-
|
|
6261
|
+
const candidateNextSibling = firstNode.getNextSibling();
|
|
6262
|
+
let nextSibling;
|
|
6263
|
+
if (!$isTextNode(candidateNextSibling) || !candidateNextSibling.canInsertTextBefore() || $isTokenOrSegmented(candidateNextSibling)) {
|
|
5856
6264
|
nextSibling = $createTextNode();
|
|
5857
6265
|
nextSibling.setFormat(format);
|
|
5858
6266
|
nextSibling.setStyle(style);
|
|
5859
6267
|
if (!firstNodeParent.canInsertTextAfter()) firstNodeParent.insertAfter(nextSibling);
|
|
5860
6268
|
else firstNode.insertAfter(nextSibling);
|
|
5861
|
-
}
|
|
6269
|
+
} else nextSibling = candidateNextSibling;
|
|
5862
6270
|
nextSibling.select(0, 0);
|
|
5863
6271
|
firstNode = nextSibling;
|
|
5864
6272
|
if (text !== "") {
|
|
@@ -5866,13 +6274,14 @@ var RangeSelection = class RangeSelection {
|
|
|
5866
6274
|
return;
|
|
5867
6275
|
}
|
|
5868
6276
|
} else if (this.isCollapsed() && startOffset === 0 && ($isTokenOrSegmented(firstNode) || !firstNode.canInsertTextBefore() || !firstNodeParent.canInsertTextBefore() && firstNode.getPreviousSibling() === null)) {
|
|
5869
|
-
|
|
5870
|
-
|
|
6277
|
+
const candidatePrevSibling = firstNode.getPreviousSibling();
|
|
6278
|
+
let prevSibling;
|
|
6279
|
+
if (!$isTextNode(candidatePrevSibling) || $isTokenOrSegmented(candidatePrevSibling)) {
|
|
5871
6280
|
prevSibling = $createTextNode();
|
|
5872
6281
|
prevSibling.setFormat(format);
|
|
5873
6282
|
if (!firstNodeParent.canInsertTextBefore()) firstNodeParent.insertBefore(prevSibling);
|
|
5874
6283
|
else firstNode.insertBefore(prevSibling);
|
|
5875
|
-
}
|
|
6284
|
+
} else prevSibling = candidatePrevSibling;
|
|
5876
6285
|
prevSibling.select();
|
|
5877
6286
|
firstNode = prevSibling;
|
|
5878
6287
|
if (text !== "") {
|
|
@@ -5943,7 +6352,7 @@ var RangeSelection = class RangeSelection {
|
|
|
5943
6352
|
}
|
|
5944
6353
|
}
|
|
5945
6354
|
} else {
|
|
5946
|
-
const markedNodeKeysForKeep = new Set([...firstNode.getParentKeys(), ...lastNode.getParentKeys()]);
|
|
6355
|
+
const markedNodeKeysForKeep = /* @__PURE__ */ new Set([...firstNode.getParentKeys(), ...lastNode.getParentKeys()]);
|
|
5947
6356
|
const firstElement = $isElementNode(firstNode) ? firstNode : firstNode.getParentOrThrow();
|
|
5948
6357
|
let lastElement = $isElementNode(lastNode) ? lastNode : lastNode.getParentOrThrow();
|
|
5949
6358
|
let lastElementChild = lastNode;
|
|
@@ -6115,11 +6524,27 @@ var RangeSelection = class RangeSelection {
|
|
|
6115
6524
|
insertNodes(nodes) {
|
|
6116
6525
|
if (nodes.length === 0) return;
|
|
6117
6526
|
if (!this.isCollapsed()) this.removeText();
|
|
6118
|
-
|
|
6119
|
-
|
|
6120
|
-
|
|
6121
|
-
if (
|
|
6122
|
-
|
|
6527
|
+
const anchorNode = this.anchor.getNode();
|
|
6528
|
+
if (this.anchor.type === "element" && $isElementNode(anchorNode) && $getSlotHostKey(anchorNode) !== null) {
|
|
6529
|
+
let firstChild = anchorNode.isShadowRoot() ? anchorNode.getFirstChild() ?? anchorNode.append($createParagraphNode()).getFirstChild() : anchorNode.getFirstChild();
|
|
6530
|
+
if (anchorNode.isShadowRoot() && firstChild !== null && !$isElementNode(firstChild)) {
|
|
6531
|
+
const seed = $createParagraphNode();
|
|
6532
|
+
firstChild.insertBefore(seed);
|
|
6533
|
+
firstChild = seed;
|
|
6534
|
+
}
|
|
6535
|
+
if (firstChild !== null) {
|
|
6536
|
+
firstChild.selectStart();
|
|
6537
|
+
const redirected = $getSelection();
|
|
6538
|
+
if (!$isRangeSelection(redirected)) formatDevErrorMessage(`Expected RangeSelection after redirecting into slot subtree`);
|
|
6539
|
+
return redirected.insertNodes(nodes);
|
|
6540
|
+
}
|
|
6541
|
+
}
|
|
6542
|
+
if (this.anchor.type === "element" && $isRootOrShadowRoot(anchorNode)) {
|
|
6543
|
+
const blocksParent = $wrapInlineNodes(nodes);
|
|
6544
|
+
const nodeToSelect = blocksParent.getLastDescendant();
|
|
6545
|
+
anchorNode.splice(this.anchor.offset, 0, blocksParent.getChildren());
|
|
6546
|
+
if (nodeToSelect !== null) nodeToSelect.selectEnd();
|
|
6547
|
+
return;
|
|
6123
6548
|
}
|
|
6124
6549
|
const firstNode = (this.isBackward() ? this.focus : this.anchor).getNode();
|
|
6125
6550
|
const firstBlock = $findMatchingParent(firstNode, INTERNAL_$isBlock);
|
|
@@ -6141,6 +6566,32 @@ var RangeSelection = class RangeSelection {
|
|
|
6141
6566
|
last.selectEnd();
|
|
6142
6567
|
return;
|
|
6143
6568
|
}
|
|
6569
|
+
if ($isElementNode(firstBlock) && $getSlotHostKey(firstBlock) !== null) {
|
|
6570
|
+
const index = $removeTextAndSplitBlock(this);
|
|
6571
|
+
const inlineNodes = $extractInlineFromBlocks(nodes);
|
|
6572
|
+
firstBlock.splice(index, 0, inlineNodes);
|
|
6573
|
+
const lastInserted = inlineNodes[inlineNodes.length - 1];
|
|
6574
|
+
if (lastInserted !== void 0) lastInserted.selectEnd();
|
|
6575
|
+
else firstBlock.select(index, index);
|
|
6576
|
+
return;
|
|
6577
|
+
}
|
|
6578
|
+
if (firstBlock === null) {
|
|
6579
|
+
const blocksParent = $wrapInlineNodes(nodes);
|
|
6580
|
+
const nodeToSelect = blocksParent.getLastDescendant();
|
|
6581
|
+
let caret = $caretFromPoint(this.anchor, "next");
|
|
6582
|
+
for (const block of blocksParent.getChildren()) caret = $insertNodeToNearestRootAtCaret(block, caret);
|
|
6583
|
+
if (nodeToSelect !== null) nodeToSelect.selectEnd();
|
|
6584
|
+
return;
|
|
6585
|
+
}
|
|
6586
|
+
if ($isElementNode(firstBlock) && !firstBlock.isParentRequired() && !$isRootOrShadowRoot(firstBlock.getParentOrThrow())) {
|
|
6587
|
+
const index = $removeTextAndSplitBlock(this);
|
|
6588
|
+
const inlineNodes = $extractInlineFromBlocks(nodes);
|
|
6589
|
+
firstBlock.splice(index, 0, inlineNodes);
|
|
6590
|
+
const lastInserted = inlineNodes[inlineNodes.length - 1];
|
|
6591
|
+
if (lastInserted !== void 0) lastInserted.selectEnd();
|
|
6592
|
+
else firstBlock.select(index, index);
|
|
6593
|
+
return;
|
|
6594
|
+
}
|
|
6144
6595
|
const blocksParent = $wrapInlineNodes(nodes);
|
|
6145
6596
|
const nodeToSelect = blocksParent.getLastDescendant();
|
|
6146
6597
|
const blocks = blocksParent.getChildren();
|
|
@@ -6173,14 +6624,16 @@ var RangeSelection = class RangeSelection {
|
|
|
6173
6624
|
* @returns the newly inserted node.
|
|
6174
6625
|
*/
|
|
6175
6626
|
insertParagraph() {
|
|
6176
|
-
|
|
6627
|
+
const anchorNode = this.anchor.getNode();
|
|
6628
|
+
if (this.anchor.type === "element" && $isRootOrShadowRoot(anchorNode)) {
|
|
6177
6629
|
const paragraph = $createParagraphNode();
|
|
6178
|
-
|
|
6630
|
+
anchorNode.splice(this.anchor.offset, 0, [paragraph]);
|
|
6179
6631
|
paragraph.select();
|
|
6180
6632
|
return paragraph;
|
|
6181
6633
|
}
|
|
6182
6634
|
const index = $removeTextAndSplitBlock(this);
|
|
6183
6635
|
const block = $findMatchingParent(this.anchor.getNode(), INTERNAL_$isBlock);
|
|
6636
|
+
if (block !== null && $getSlotHostKey(block) !== null) return null;
|
|
6184
6637
|
if (!$isElementNode(block)) formatDevErrorMessage(`Expected ancestor to be a block ElementNode`);
|
|
6185
6638
|
const firstToAppend = block.getChildAtIndex(index);
|
|
6186
6639
|
const nodesToInsert = firstToAppend ? [firstToAppend, ...firstToAppend.getNextSiblings()] : [];
|
|
@@ -6289,7 +6742,8 @@ var RangeSelection = class RangeSelection {
|
|
|
6289
6742
|
}
|
|
6290
6743
|
moveNativeSelection(domSelection, alter, isBackward ? "backward" : "forward", granularity);
|
|
6291
6744
|
if (domSelection.rangeCount > 0) {
|
|
6292
|
-
const
|
|
6745
|
+
const composedRange = getComposedStaticRange(domSelection, editor._rootElement);
|
|
6746
|
+
const range = composedRange || domSelection.getRangeAt(0);
|
|
6293
6747
|
const anchorNode = this.anchor.getNode();
|
|
6294
6748
|
const root = $isRootNode(anchorNode) ? anchorNode : $getNearestRootOrShadowRoot(anchorNode);
|
|
6295
6749
|
this.applyDOMRange(range);
|
|
@@ -6312,7 +6766,7 @@ var RangeSelection = class RangeSelection {
|
|
|
6312
6766
|
if ($isElementNode(lastValidNode)) lastValidNode.selectEnd();
|
|
6313
6767
|
else lastValidNode.getParentOrThrow().selectEnd();
|
|
6314
6768
|
}
|
|
6315
|
-
if (domSelection.
|
|
6769
|
+
if (!(composedRange ? domSelection.direction !== "backward" : domSelection.anchorNode === range.startContainer && domSelection.anchorOffset === range.startOffset)) $swapPoints(this);
|
|
6316
6770
|
}
|
|
6317
6771
|
}
|
|
6318
6772
|
if (granularity === "lineboundary") $modifySelectionAroundDecoratorsAndBlocks(this, alter, isBackward, granularity, "decorators");
|
|
@@ -6374,7 +6828,14 @@ var RangeSelection = class RangeSelection {
|
|
|
6374
6828
|
continue;
|
|
6375
6829
|
} else if ($isDecoratorNode(caret.origin)) {
|
|
6376
6830
|
if (caret.origin.isIsolated());
|
|
6377
|
-
else if (
|
|
6831
|
+
else if ($getSlotNames(caret.origin).length > 0) {
|
|
6832
|
+
if ($isElementNode(initialRange.anchor.origin) && initialRange.anchor.origin.isEmpty()) {
|
|
6833
|
+
initialRange.anchor.origin.remove();
|
|
6834
|
+
const nodeSelection = $createNodeSelection();
|
|
6835
|
+
nodeSelection.add(caret.origin.getKey());
|
|
6836
|
+
$setSelection(nodeSelection);
|
|
6837
|
+
}
|
|
6838
|
+
} else if (state.type === "merge-next-block" && (caret.origin.isKeyboardSelectable() || !caret.origin.isInline()) && $isElementNode(initialRange.anchor.origin) && initialRange.anchor.origin.isEmpty()) {
|
|
6378
6839
|
initialRange.anchor.origin.remove();
|
|
6379
6840
|
const nodeSelection = $createNodeSelection();
|
|
6380
6841
|
nodeSelection.add(caret.origin.getKey());
|
|
@@ -6386,6 +6847,7 @@ var RangeSelection = class RangeSelection {
|
|
|
6386
6847
|
}
|
|
6387
6848
|
if (state.type === "merge-block") {
|
|
6388
6849
|
const { caret, block } = state;
|
|
6850
|
+
if ($getSlotNames(block).length > 0) return;
|
|
6389
6851
|
if (caret.origin.isEmpty() && !block.isEmpty() && caret.origin.getParent() === block.getParent()) {
|
|
6390
6852
|
caret.origin.remove(true);
|
|
6391
6853
|
return;
|
|
@@ -6393,6 +6855,11 @@ var RangeSelection = class RangeSelection {
|
|
|
6393
6855
|
$updateRangeSelectionFromCaretRange(this, $getCaretRange(!caret.origin.isEmpty() && block.isEmpty() ? $rewindSiblingCaret($getSiblingCaret(block, caret.direction)) : initialRange.anchor, caret));
|
|
6394
6856
|
return this.removeText();
|
|
6395
6857
|
}
|
|
6858
|
+
for (let node = anchor.getNode(); node !== null;) {
|
|
6859
|
+
if ($getSlotHostKey(node) !== null) return;
|
|
6860
|
+
if ($isElementNode(node) && node.isShadowRoot()) break;
|
|
6861
|
+
node = node.getParent();
|
|
6862
|
+
}
|
|
6396
6863
|
}
|
|
6397
6864
|
const focus = this.focus;
|
|
6398
6865
|
this.modify("extend", isBackward, "character");
|
|
@@ -6432,6 +6899,12 @@ var RangeSelection = class RangeSelection {
|
|
|
6432
6899
|
* @param isBackward whether or not the selection is backwards.
|
|
6433
6900
|
*/
|
|
6434
6901
|
deleteLine(isBackward) {
|
|
6902
|
+
const anchorSlotFrame = $getPointSlotFrame(this.anchor);
|
|
6903
|
+
if (anchorSlotFrame !== null && $isDecoratorNode($getSlotHost(anchorSlotFrame))) {
|
|
6904
|
+
if (!this.isCollapsed()) this.focus.set(this.anchor.key, this.anchor.offset, this.anchor.type);
|
|
6905
|
+
this.deleteCharacter(isBackward);
|
|
6906
|
+
return;
|
|
6907
|
+
}
|
|
6435
6908
|
if (this.isCollapsed()) this.modify("extend", isBackward, "lineboundary");
|
|
6436
6909
|
if (this.isCollapsed()) this.deleteCharacter(isBackward);
|
|
6437
6910
|
else this.removeText();
|
|
@@ -6654,7 +7127,7 @@ function $internalResolveSelectionPoint(dom, offset, lastPoint, editor) {
|
|
|
6654
7127
|
moveSelectionToEnd = true;
|
|
6655
7128
|
resolvedOffset = childNodesLength - 1;
|
|
6656
7129
|
}
|
|
6657
|
-
if (getNodeKeyFromDOMNode(dom, editor) === void 0 && dom
|
|
7130
|
+
if (getNodeKeyFromDOMNode(dom, editor) === void 0 && !isDOMCapturingSelection(dom, editor)) dirty = true;
|
|
6658
7131
|
let childDOM = childNodes[resolvedOffset];
|
|
6659
7132
|
let hasBlockCursor = false;
|
|
6660
7133
|
if (childDOM === blockCursorElement) {
|
|
@@ -6697,7 +7170,9 @@ function $internalResolveSelectionPoint(dom, offset, lastPoint, editor) {
|
|
|
6697
7170
|
resolvedOffset = Math.min(resolvedElement.getChildrenSize(), resolvedOffset + 1);
|
|
6698
7171
|
}
|
|
6699
7172
|
} else {
|
|
6700
|
-
const
|
|
7173
|
+
const slotHost = $getSlotHost(resolvedElement);
|
|
7174
|
+
const anchorNode = slotHost !== null ? slotHost : resolvedElement;
|
|
7175
|
+
const index = anchorNode.getIndexWithinParent();
|
|
6701
7176
|
const elementDOM = editor.getElementByKey(resolvedElement.getKey());
|
|
6702
7177
|
let position = "after";
|
|
6703
7178
|
if (elementDOM !== null && $getNodeFromDOM(dom) === resolvedElement) {
|
|
@@ -6706,7 +7181,7 @@ function $internalResolveSelectionPoint(dom, offset, lastPoint, editor) {
|
|
|
6706
7181
|
else if (offset === 0 && $isDecoratorNode(resolvedElement)) position = "before";
|
|
6707
7182
|
}
|
|
6708
7183
|
resolvedOffset = position === "before" ? index : index + 1;
|
|
6709
|
-
resolvedElement =
|
|
7184
|
+
resolvedElement = anchorNode.getParentOrThrow();
|
|
6710
7185
|
}
|
|
6711
7186
|
if ($isElementNode(resolvedElement)) return [$createPoint(resolvedElement.__key, resolvedOffset, "element"), dirty];
|
|
6712
7187
|
}
|
|
@@ -6746,6 +7221,74 @@ function $normalizeSelectionPointsForBoundaries(anchor, focus, lastSelection) {
|
|
|
6746
7221
|
if (isCollapsed) focus.set(anchor.key, anchor.offset, anchor.type);
|
|
6747
7222
|
}
|
|
6748
7223
|
}
|
|
7224
|
+
function $getPointSlotFrame(point) {
|
|
7225
|
+
const node = $getNodeByKey(point.key);
|
|
7226
|
+
return node === null ? null : $getSlotFrame(node);
|
|
7227
|
+
}
|
|
7228
|
+
function $slotStraddleFocusAfterAnchor(anchorPoint, focusPoint, anchorFrame, focusFrame) {
|
|
7229
|
+
if (anchorFrame !== null && focusFrame !== null) {
|
|
7230
|
+
const anchorHost = $getSlotHost(anchorFrame);
|
|
7231
|
+
const focusHost = $getSlotHost(focusFrame);
|
|
7232
|
+
if (anchorHost !== null && anchorHost.is(focusHost)) {
|
|
7233
|
+
for (const slotKey of $getSlotMap(anchorHost).values()) {
|
|
7234
|
+
if (slotKey === anchorFrame.getKey()) return true;
|
|
7235
|
+
if (slotKey === focusFrame.getKey()) return false;
|
|
7236
|
+
}
|
|
7237
|
+
return true;
|
|
7238
|
+
}
|
|
7239
|
+
return anchorHost !== null && focusHost !== null ? anchorHost.isBefore(focusHost) : true;
|
|
7240
|
+
}
|
|
7241
|
+
if (anchorFrame !== null) {
|
|
7242
|
+
const anchorHost = $getSlotHost(anchorFrame);
|
|
7243
|
+
const focusNode = $getNodeByKey(focusPoint.key);
|
|
7244
|
+
if (anchorHost === null || focusNode === null) return true;
|
|
7245
|
+
if (anchorHost.is(focusNode) || anchorHost.isParentOf(focusNode)) return true;
|
|
7246
|
+
return anchorHost.isBefore(focusNode);
|
|
7247
|
+
}
|
|
7248
|
+
const focusHost = $getSlotHost(focusFrame);
|
|
7249
|
+
const anchorNode = $getNodeByKey(anchorPoint.key);
|
|
7250
|
+
if (focusHost === null || anchorNode === null) return false;
|
|
7251
|
+
if (focusHost.is(anchorNode) || focusHost.isParentOf(anchorNode)) return false;
|
|
7252
|
+
return anchorNode.isBefore(focusHost);
|
|
7253
|
+
}
|
|
7254
|
+
function $clampSelectionPointsToSlotFrame(anchorPoint, focusPoint, resolveFocusAfterAnchor) {
|
|
7255
|
+
const anchorFrame = $getPointSlotFrame(anchorPoint);
|
|
7256
|
+
const focusFrame = $getPointSlotFrame(focusPoint);
|
|
7257
|
+
if (anchorFrame === focusFrame || anchorFrame !== null && focusFrame !== null && anchorFrame.is(focusFrame)) return false;
|
|
7258
|
+
const focusAfterAnchor = resolveFocusAfterAnchor(anchorFrame, focusFrame);
|
|
7259
|
+
if (anchorFrame !== null) {
|
|
7260
|
+
if ($isElementNode(anchorFrame)) focusPoint.set(anchorFrame.getKey(), focusAfterAnchor ? anchorFrame.getChildrenSize() : 0, "element");
|
|
7261
|
+
else focusPoint.set(anchorFrame.getKey(), focusAfterAnchor ? anchorFrame.getTextContentSize() : 0, "text");
|
|
7262
|
+
return true;
|
|
7263
|
+
}
|
|
7264
|
+
const host = $getSlotHost(focusFrame);
|
|
7265
|
+
if (host === null) return false;
|
|
7266
|
+
const hostParent = host.getParent();
|
|
7267
|
+
if (hostParent === null) return false;
|
|
7268
|
+
const hostIndex = host.getIndexWithinParent();
|
|
7269
|
+
focusPoint.set(hostParent.getKey(), focusAfterAnchor ? hostIndex + 1 : hostIndex, "element");
|
|
7270
|
+
return true;
|
|
7271
|
+
}
|
|
7272
|
+
/**
|
|
7273
|
+
* Programmatic counterpart of the DOM-read clamp: applied when a
|
|
7274
|
+
* RangeSelection is committed via $setSelection so an API-built selection
|
|
7275
|
+
* cannot straddle a slot boundary either. Direction comes from the model
|
|
7276
|
+
* comparator (slots-first content order), not the caret system — a
|
|
7277
|
+
* straddling pair has no common ancestor through __parent, so the caret
|
|
7278
|
+
* comparison would throw (that integration is the deferred caret-slot work),
|
|
7279
|
+
* and not from the DOM either, since $setSelection also runs in headless
|
|
7280
|
+
* mode where there is no DOM. Marks the selection dirty when it mutates a
|
|
7281
|
+
* point. No-op for non-slot trees (both frames null), evaluated before any
|
|
7282
|
+
* direction work, so non-slot and headless callers are unaffected.
|
|
7283
|
+
*
|
|
7284
|
+
* @experimental named-slots
|
|
7285
|
+
* @internal
|
|
7286
|
+
*/
|
|
7287
|
+
function $clampRangeSelectionToSlotFrame(selection) {
|
|
7288
|
+
const clamped = $clampSelectionPointsToSlotFrame(selection.anchor, selection.focus, (anchorFrame, focusFrame) => $slotStraddleFocusAfterAnchor(selection.anchor, selection.focus, anchorFrame, focusFrame));
|
|
7289
|
+
if (clamped) selection.dirty = true;
|
|
7290
|
+
return clamped;
|
|
7291
|
+
}
|
|
6749
7292
|
function $internalResolveSelectionPoints(anchorDOM, anchorOffset, focusDOM, focusOffset, editor, lastSelection) {
|
|
6750
7293
|
if (anchorDOM === null || focusDOM === null || !isSelectionWithinEditor(editor, anchorDOM, focusDOM)) return null;
|
|
6751
7294
|
const resolvedAnchor = $internalResolveSelectionPoint(anchorDOM, anchorOffset, $isRangeSelection(lastSelection) ? lastSelection.anchor : null, editor);
|
|
@@ -6761,11 +7304,12 @@ function $internalResolveSelectionPoints(anchorDOM, anchorOffset, focusDOM, focu
|
|
|
6761
7304
|
const focusNode = $getNodeFromDOM(focusDOM);
|
|
6762
7305
|
if ($isDecoratorNode(anchorNode) && $isDecoratorNode(focusNode)) return null;
|
|
6763
7306
|
}
|
|
7307
|
+
const slotClamped = editor._slotsUsed && $clampSelectionPointsToSlotFrame(resolvedAnchorPoint, resolvedFocusPoint, () => (anchorDOM.compareDocumentPosition(focusDOM) & Node.DOCUMENT_POSITION_FOLLOWING) !== 0);
|
|
6764
7308
|
$normalizeSelectionPointsForBoundaries(resolvedAnchorPoint, resolvedFocusPoint);
|
|
6765
7309
|
return [
|
|
6766
7310
|
resolvedAnchorPoint,
|
|
6767
7311
|
resolvedFocusPoint,
|
|
6768
|
-
anchorDirty || focusDirty
|
|
7312
|
+
anchorDirty || focusDirty || slotClamped
|
|
6769
7313
|
];
|
|
6770
7314
|
}
|
|
6771
7315
|
function $isBlockElementNode(node) {
|
|
@@ -6803,10 +7347,11 @@ function $internalCreateRangeSelection(lastSelection, domSelection, editor, even
|
|
|
6803
7347
|
let anchorDOM, focusDOM, anchorOffset, focusOffset;
|
|
6804
7348
|
if (!$isRangeSelection(lastSelection) || useDOMSelection) {
|
|
6805
7349
|
if (domSelection === null) return null;
|
|
6806
|
-
|
|
6807
|
-
|
|
6808
|
-
|
|
6809
|
-
|
|
7350
|
+
const points = getDOMSelectionPoints(domSelection, editor._rootElement);
|
|
7351
|
+
anchorDOM = points.anchorNode;
|
|
7352
|
+
focusDOM = points.focusNode;
|
|
7353
|
+
anchorOffset = points.anchorOffset;
|
|
7354
|
+
focusOffset = points.focusOffset;
|
|
6810
7355
|
if ((isSelectionChange || eventType === void 0) && $isRangeSelection(lastSelection) && !isSelectionWithinEditor(editor, anchorDOM, focusDOM)) return lastSelection.clone();
|
|
6811
7356
|
} else return lastSelection.clone();
|
|
6812
7357
|
const resolvedSelectionPoints = $internalResolveSelectionPoints(anchorDOM, anchorOffset, focusDOM, focusOffset, editor, lastSelection);
|
|
@@ -6989,10 +7534,17 @@ function $getElementAndOffsetForPoint(editor, node, offset) {
|
|
|
6989
7534
|
}
|
|
6990
7535
|
/** @internal */
|
|
6991
7536
|
function $updateDOMSelection(prevSelection, nextSelection, editor, domSelection, tags, rootElement) {
|
|
6992
|
-
const
|
|
6993
|
-
|
|
7537
|
+
const rootForActive = rootElement.getRootNode();
|
|
7538
|
+
const activeElement = isDOMDocumentNode(rootForActive) || isDOMShadowRoot(rootForActive) ? getActiveElementDeep(rootForActive) : null;
|
|
7539
|
+
if (tags.has("collaboration") && activeElement !== rootElement || activeElement !== null && $isSelectionCapturedInDecoratorInput(activeElement, activeElement)) return;
|
|
7540
|
+
const currentPoints = getDOMSelectionPoints(domSelection, rootElement);
|
|
7541
|
+
let currentRangeCache;
|
|
7542
|
+
const getCurrentRange = () => {
|
|
7543
|
+
if (currentRangeCache === void 0) currentRangeCache = getDOMSelectionRange(domSelection, rootElement);
|
|
7544
|
+
return currentRangeCache;
|
|
7545
|
+
};
|
|
6994
7546
|
if (!$isRangeSelection(nextSelection)) {
|
|
6995
|
-
if (prevSelection !== null && isSelectionWithinEditor(editor,
|
|
7547
|
+
if (prevSelection !== null && isSelectionWithinEditor(editor, currentPoints.anchorNode, currentPoints.focusNode)) domSelection.removeAllRanges();
|
|
6996
7548
|
return;
|
|
6997
7549
|
}
|
|
6998
7550
|
const anchor = nextSelection.anchor;
|
|
@@ -7014,20 +7566,28 @@ function $updateDOMSelection(prevSelection, nextSelection, editor, domSelection,
|
|
|
7014
7566
|
if (focus.type === "text") nextFocusNode = $isTextNode(focusNode) ? $getDOMTextNode(focusNode, focusDOM, editor) : null;
|
|
7015
7567
|
if (nextAnchorNode === null || nextFocusNode === null) return;
|
|
7016
7568
|
if (isCollapsed && (prevSelection === null || anchorFormatOrStyleChanged || $isRangeSelection(prevSelection) && (prevSelection.format !== nextFormat || prevSelection.style !== nextStyle))) markCollapsedSelectionFormat(nextFormat, nextStyle, nextAnchorOffset, anchor.key, performance.now());
|
|
7017
|
-
if (!(domSelection.type === "Range" && isCollapsed) &&
|
|
7569
|
+
if (!(domSelection.type === "Range" && isCollapsed) && currentPoints.anchorOffset === nextAnchorOffset && currentPoints.focusOffset === nextFocusOffset && currentPoints.anchorNode === nextAnchorNode && currentPoints.focusNode === nextFocusNode) {
|
|
7018
7570
|
if (activeElement === null || !rootElement.contains(activeElement)) {
|
|
7019
|
-
|
|
7571
|
+
const focusEditor = activeElement !== null ? getNearestEditorFromDOMNode(activeElement) : null;
|
|
7572
|
+
if ((focusEditor === null || focusEditor === editor) && !tags.has("skip-selection-focus")) rootElement.focus({ preventScroll: true });
|
|
7020
7573
|
}
|
|
7021
7574
|
if (anchor.type !== "element") return;
|
|
7022
7575
|
}
|
|
7023
7576
|
setDOMSelectionBaseAndExtent(domSelection, nextAnchorNode, nextAnchorOffset, nextFocusNode, nextFocusOffset);
|
|
7024
|
-
if (IS_FIREFOX && nextSelection.isCollapsed() && rootElement !== null && !tags.has("skip-selection-focus")
|
|
7025
|
-
|
|
7026
|
-
|
|
7577
|
+
if (IS_FIREFOX && nextSelection.isCollapsed() && rootElement !== null && !tags.has("skip-selection-focus")) {
|
|
7578
|
+
const focusedElement = getActiveElement(rootElement);
|
|
7579
|
+
if (focusedElement === null || !rootElement.contains(focusedElement)) {
|
|
7580
|
+
const deepFocusedElement = getActiveElementDeep(rootElement.ownerDocument);
|
|
7581
|
+
const focusEditor = deepFocusedElement !== null ? getNearestEditorFromDOMNode(deepFocusedElement) : null;
|
|
7582
|
+
if (focusEditor === null || focusEditor === editor) rootElement.focus({ preventScroll: true });
|
|
7583
|
+
}
|
|
7584
|
+
}
|
|
7585
|
+
if (!tags.has("skip-scroll-into-view") && nextSelection.isCollapsed() && rootElement !== null && rootElement === getActiveElement(rootElement)) {
|
|
7586
|
+
const selectionTarget = $isRangeSelection(nextSelection) && nextSelection.anchor.type === "element" ? nextAnchorNode.childNodes[nextAnchorOffset] || null : getCurrentRange();
|
|
7027
7587
|
if (selectionTarget !== null) {
|
|
7028
7588
|
let selectionRect;
|
|
7029
|
-
if (selectionTarget
|
|
7030
|
-
const range =
|
|
7589
|
+
if (isDOMTextNode(selectionTarget)) {
|
|
7590
|
+
const range = selectionTarget.ownerDocument.createRange();
|
|
7031
7591
|
range.selectNode(selectionTarget);
|
|
7032
7592
|
selectionRect = range.getBoundingClientRect();
|
|
7033
7593
|
} else selectionRect = selectionTarget.getBoundingClientRect();
|
|
@@ -7086,6 +7646,18 @@ function $getTextContent() {
|
|
|
7086
7646
|
if (selection === null) return "";
|
|
7087
7647
|
return selection.getTextContent();
|
|
7088
7648
|
}
|
|
7649
|
+
function $extractInlineFromBlocks(nodes) {
|
|
7650
|
+
const inlineNodes = [];
|
|
7651
|
+
for (const node of nodes) {
|
|
7652
|
+
if ($isLineBreakNode(node)) continue;
|
|
7653
|
+
if (($isElementNode(node) || $isDecoratorNode(node)) && !node.isInline()) {
|
|
7654
|
+
if ($isElementNode(node)) inlineNodes.push(...$extractInlineFromBlocks(node.getChildren()));
|
|
7655
|
+
continue;
|
|
7656
|
+
}
|
|
7657
|
+
inlineNodes.push(node);
|
|
7658
|
+
}
|
|
7659
|
+
return inlineNodes;
|
|
7660
|
+
}
|
|
7089
7661
|
function $removeTextAndSplitBlock(selection) {
|
|
7090
7662
|
let selection_ = selection;
|
|
7091
7663
|
if (!selection.isCollapsed()) selection_.removeText();
|
|
@@ -7095,7 +7667,7 @@ function $removeTextAndSplitBlock(selection) {
|
|
|
7095
7667
|
const anchor = selection_.anchor;
|
|
7096
7668
|
let node = anchor.getNode();
|
|
7097
7669
|
let offset = anchor.offset;
|
|
7098
|
-
while (!INTERNAL_$isBlock(node)) {
|
|
7670
|
+
while (!INTERNAL_$isBlock(node) && $getSlotHostKey(node) === null) {
|
|
7099
7671
|
const prevNode = node;
|
|
7100
7672
|
[node, offset] = $splitNodeAtPoint(node, offset);
|
|
7101
7673
|
if (prevNode.is(node)) break;
|
|
@@ -7125,19 +7697,22 @@ function $splitNodeAtPoint(node, offset) {
|
|
|
7125
7697
|
}
|
|
7126
7698
|
return [parent, node.getIndexWithinParent() + 1];
|
|
7127
7699
|
}
|
|
7700
|
+
function $isInlineRunNode(node) {
|
|
7701
|
+
return $isLineBreakNode(node) || $isInlineElementOrDecoratorNode(node) || $isTextNode(node) || node.isParentRequired();
|
|
7702
|
+
}
|
|
7128
7703
|
function $wrapInlineNodes(nodes) {
|
|
7129
7704
|
const virtualRoot = $createParagraphNode();
|
|
7130
7705
|
let currentBlock = null;
|
|
7131
7706
|
for (let i = 0; i < nodes.length; i++) {
|
|
7132
7707
|
const node = nodes[i];
|
|
7133
|
-
|
|
7134
|
-
if (isLineBreakNode || $isDecoratorNode(node) && node.isInline() || $isElementNode(node) && node.isInline() || $isTextNode(node) || node.isParentRequired()) {
|
|
7708
|
+
if ($isInlineRunNode(node)) {
|
|
7135
7709
|
if (currentBlock === null) {
|
|
7136
7710
|
currentBlock = node.createParentElementNode();
|
|
7137
7711
|
virtualRoot.append(currentBlock);
|
|
7138
|
-
|
|
7712
|
+
const nextNode = nodes[i + 1];
|
|
7713
|
+
if ($isLineBreakNode(node) && (nextNode === void 0 || !$isInlineRunNode(nextNode))) continue;
|
|
7139
7714
|
}
|
|
7140
|
-
|
|
7715
|
+
currentBlock.append(node);
|
|
7141
7716
|
} else {
|
|
7142
7717
|
virtualRoot.append(node);
|
|
7143
7718
|
currentBlock = null;
|
|
@@ -7242,6 +7817,8 @@ let activeEditorState = null;
|
|
|
7242
7817
|
let activeEditor = null;
|
|
7243
7818
|
let isReadOnlyMode = false;
|
|
7244
7819
|
let isAttemptingToRecoverFromReconcilerError = false;
|
|
7820
|
+
let isCommittingPendingUpdates = false;
|
|
7821
|
+
const editorsWithPendingCascadeReset = /* @__PURE__ */ new Set();
|
|
7245
7822
|
let infiniteTransformCount = 0;
|
|
7246
7823
|
const observerOptions = {
|
|
7247
7824
|
characterData: true,
|
|
@@ -7261,6 +7838,11 @@ function getActiveEditorState() {
|
|
|
7261
7838
|
if (activeEditorState === null) formatDevErrorMessage(`Unable to find an active editor state. State helpers or node methods can only be used synchronously during the callback of editor.update(), editor.read(), or editorState.read().${collectBuildInformation()}`);
|
|
7262
7839
|
return activeEditorState;
|
|
7263
7840
|
}
|
|
7841
|
+
/** @internal */
|
|
7842
|
+
function $assumeActiveEditor(editor) {
|
|
7843
|
+
if (getActiveEditorState() !== null && activeEditor === null) activeEditor = editor;
|
|
7844
|
+
if (!(activeEditor === editor)) formatDevErrorMessage(`The given editor argument does not match $getEditor() in this context. Use editor.getEditorState().read(..., {editor}) if this cross-editor call is intentional.`);
|
|
7845
|
+
}
|
|
7264
7846
|
function getActiveEditor() {
|
|
7265
7847
|
if (activeEditor === null) formatDevErrorMessage(`Unable to find an active editor. This method can only be used synchronously during the callback of editor.update(), editor.read(), or editor.getEditorState().read(..., {editor}).${collectBuildInformation()}`);
|
|
7266
7848
|
return activeEditor;
|
|
@@ -7281,7 +7863,7 @@ function collectBuildInformation() {
|
|
|
7281
7863
|
let compatibleEditors = 0;
|
|
7282
7864
|
const incompatibleEditors = /* @__PURE__ */ new Set();
|
|
7283
7865
|
const thisVersion = LexicalEditor.version;
|
|
7284
|
-
if (typeof window !== "undefined") for (const node of document
|
|
7866
|
+
if (typeof window !== "undefined") for (const node of findAllLexicalElementsDeep(document)) {
|
|
7285
7867
|
const editor = getEditorPropertyFromDOMNode(node);
|
|
7286
7868
|
if (isLexicalEditor(editor)) compatibleEditors++;
|
|
7287
7869
|
else if (editor) {
|
|
@@ -7404,6 +7986,11 @@ function $parseSerializedNodeImpl(serializedNode, registeredNodes) {
|
|
|
7404
7986
|
const childNode = $parseSerializedNodeImpl(serializedJSONChildNode, registeredNodes);
|
|
7405
7987
|
node.append(childNode);
|
|
7406
7988
|
}
|
|
7989
|
+
const slots = serializedNode.$slots;
|
|
7990
|
+
if (slots) {
|
|
7991
|
+
if (!$isSlotHost(node)) formatDevErrorMessage(`$parseSerializedNode: node ${nodeClass.name} has slots but is not a valid slot host; only ElementNodes and DecoratorNodes can host slots.`);
|
|
7992
|
+
for (const name in slots) $setSlot(node, name, $parseSerializedNodeImpl(slots[name], registeredNodes));
|
|
7993
|
+
}
|
|
7407
7994
|
return node;
|
|
7408
7995
|
}
|
|
7409
7996
|
function parseEditorState(serializedEditorState, editor, updateFn) {
|
|
@@ -7429,6 +8016,7 @@ function parseEditorState(serializedEditorState, editor, updateFn) {
|
|
|
7429
8016
|
$parseSerializedNodeImpl(serializedNode, registeredNodes);
|
|
7430
8017
|
if (updateFn) updateFn();
|
|
7431
8018
|
editorState._readOnly = true;
|
|
8019
|
+
editorState._parsed = true;
|
|
7432
8020
|
handleDEVOnlyPendingUpdateGuarantees(editorState);
|
|
7433
8021
|
} catch (error) {
|
|
7434
8022
|
if (error instanceof Error) editor._onError(error);
|
|
@@ -7471,6 +8059,15 @@ function handleDEVOnlyPendingUpdateGuarantees(pendingEditorState) {
|
|
|
7471
8059
|
};
|
|
7472
8060
|
}
|
|
7473
8061
|
function $commitPendingUpdates(editor, recoveryEditorState) {
|
|
8062
|
+
const previouslyCommitting = isCommittingPendingUpdates;
|
|
8063
|
+
isCommittingPendingUpdates = true;
|
|
8064
|
+
try {
|
|
8065
|
+
$commitPendingUpdatesImpl(editor, recoveryEditorState);
|
|
8066
|
+
} finally {
|
|
8067
|
+
isCommittingPendingUpdates = previouslyCommitting;
|
|
8068
|
+
}
|
|
8069
|
+
}
|
|
8070
|
+
function $commitPendingUpdatesImpl(editor, recoveryEditorState) {
|
|
7474
8071
|
const pendingEditorState = editor._pendingEditorState;
|
|
7475
8072
|
const rootElement = editor._rootElement;
|
|
7476
8073
|
const shouldSkipDOM = editor._headless || rootElement === null;
|
|
@@ -7540,8 +8137,8 @@ function $commitPendingUpdates(editor, recoveryEditorState) {
|
|
|
7540
8137
|
editor._dirtyLeaves = /* @__PURE__ */ new Set();
|
|
7541
8138
|
editor._dirtyElements = /* @__PURE__ */ new Map();
|
|
7542
8139
|
editor._normalizedNodes = /* @__PURE__ */ new Set();
|
|
7543
|
-
editor._updateTags = /* @__PURE__ */ new Set();
|
|
7544
8140
|
}
|
|
8141
|
+
editor._updateTags = /* @__PURE__ */ new Set();
|
|
7545
8142
|
$garbageCollectDetachedDecorators(editor, pendingEditorState);
|
|
7546
8143
|
const domSelection = shouldSkipDOM ? null : getDOMSelection(getWindow(editor));
|
|
7547
8144
|
if (editor._editable && domSelection !== null && (needsUpdate || pendingSelection === null || pendingSelection.dirty || !pendingSelection.is(currentSelection)) && rootElement !== null && !tags.has("skip-dom-selection")) {
|
|
@@ -7624,6 +8221,9 @@ function triggerListeners(type, editor, isCurrentlyEnqueuingUpdates, ...payload)
|
|
|
7624
8221
|
function triggerCommandListeners(editor, type, payload, fromEditor) {
|
|
7625
8222
|
const editors = getEditorsToPropagate(editor);
|
|
7626
8223
|
let updatingParentEditor;
|
|
8224
|
+
if (!isCommittingPendingUpdates) {
|
|
8225
|
+
for (let e = 0; e < editors.length; e++) if (!editors[e]._updating) editors[e]._cascadeCount = 0;
|
|
8226
|
+
}
|
|
7627
8227
|
for (let i = 4; i >= 0; i--) for (let e = 0; e < editors.length; e++) {
|
|
7628
8228
|
const currentEditor = editors[e];
|
|
7629
8229
|
if (e > 0 && currentEditor._updating) {
|
|
@@ -7650,20 +8250,25 @@ function triggerCommandListeners(editor, type, payload, fromEditor) {
|
|
|
7650
8250
|
});
|
|
7651
8251
|
return false;
|
|
7652
8252
|
}
|
|
8253
|
+
function scheduleCascadeReset(editor) {
|
|
8254
|
+
if (editorsWithPendingCascadeReset.has(editor)) return;
|
|
8255
|
+
editorsWithPendingCascadeReset.add(editor);
|
|
8256
|
+
setTimeout(() => {
|
|
8257
|
+
editorsWithPendingCascadeReset.delete(editor);
|
|
8258
|
+
editor._cascadeCount = 0;
|
|
8259
|
+
}, 0);
|
|
8260
|
+
}
|
|
7653
8261
|
function $triggerEnqueuedUpdates(editor) {
|
|
7654
8262
|
const queuedUpdates = editor._updates;
|
|
7655
8263
|
if (queuedUpdates.length === 0) {
|
|
7656
8264
|
editor._cascadeCount = 0;
|
|
7657
8265
|
return;
|
|
7658
8266
|
}
|
|
8267
|
+
scheduleCascadeReset(editor);
|
|
7659
8268
|
if (editor._cascadeCount++ > 99) {
|
|
7660
8269
|
editor._updates = [];
|
|
7661
8270
|
editor._cascadeCount = 0;
|
|
7662
|
-
|
|
7663
|
-
formatDevErrorMessage(`One or more update listeners are endlessly enqueueing more updates. May have encountered infinite recursion caused by update listeners that trigger additional updates without a stop condition.`);
|
|
7664
|
-
} catch (error) {
|
|
7665
|
-
if (error instanceof Error) editor._onError(error);
|
|
7666
|
-
}
|
|
8271
|
+
editor._onWarn(/* @__PURE__ */ new Error(`One or more update listeners are endlessly enqueueing more updates. May have encountered infinite recursion caused by update listeners that trigger additional updates without a stop condition. Editor namespace: ${editor._config.namespace}`));
|
|
7667
8272
|
return;
|
|
7668
8273
|
}
|
|
7669
8274
|
const queuedUpdate = queuedUpdates.shift();
|
|
@@ -7756,6 +8361,7 @@ function $beginUpdate(editor, updateFn, options) {
|
|
|
7756
8361
|
if (startingCompositionKey !== editor._compositionKey) pendingEditorState._flushSync = true;
|
|
7757
8362
|
const pendingSelection = pendingEditorState._selection;
|
|
7758
8363
|
if ($isRangeSelection(pendingSelection)) {
|
|
8364
|
+
if (editor._slotsUsed) $clampRangeSelectionToSlotFrame(pendingSelection);
|
|
7759
8365
|
const pendingNodeMap = pendingEditorState._nodeMap;
|
|
7760
8366
|
const anchorKey = pendingSelection.anchor.key;
|
|
7761
8367
|
const focusKey = pendingSelection.focus.key;
|
|
@@ -7808,6 +8414,26 @@ function updateEditor(editor, updateFn, options) {
|
|
|
7808
8414
|
if (editor._updating) editor._updates.push([updateFn, options]);
|
|
7809
8415
|
else $beginUpdate(editor, updateFn, options);
|
|
7810
8416
|
}
|
|
8417
|
+
/**
|
|
8418
|
+
* Wrap any shadow-root child of `node` that is neither an ElementNode nor a
|
|
8419
|
+
* DecoratorNode in a paragraph, so the slot-frame invariant set by
|
|
8420
|
+
* `getTopLevelElement` continues to hold for external inputs (URL doc
|
|
8421
|
+
* payloads, imported JSON, paste round-trips) that may carry shapes the
|
|
8422
|
+
* in-editor mutation paths can no longer produce.
|
|
8423
|
+
*
|
|
8424
|
+
* Single-node helper: runs as the `$config` `$transform` on ElementNode so
|
|
8425
|
+
* the existing dirty-node transform cycle drives the normalization. The
|
|
8426
|
+
* in-editor mutation paths (insertText, insertNodes, append/splice via the
|
|
8427
|
+
* public API) still fail-fast on the invariant.
|
|
8428
|
+
*
|
|
8429
|
+
* @internal
|
|
8430
|
+
*/
|
|
8431
|
+
function $normalizeShadowRootChildren(node) {
|
|
8432
|
+
if ($isRootOrShadowRoot(node)) {
|
|
8433
|
+
let block = null;
|
|
8434
|
+
for (const child of node.getChildren()) block = child.isInline() ? (block || child.replace(child.createParentElementNode())).append(child) : null;
|
|
8435
|
+
}
|
|
8436
|
+
}
|
|
7811
8437
|
/** @noInheritDoc */
|
|
7812
8438
|
var ElementNode = class extends LexicalNode {
|
|
7813
8439
|
/** @internal */
|
|
@@ -7829,6 +8455,16 @@ var ElementNode = class extends LexicalNode {
|
|
|
7829
8455
|
__textFormat;
|
|
7830
8456
|
/** @internal */
|
|
7831
8457
|
__textStyle;
|
|
8458
|
+
/** @internal */
|
|
8459
|
+
__slotHost;
|
|
8460
|
+
/** @internal */
|
|
8461
|
+
__slots;
|
|
8462
|
+
$config() {
|
|
8463
|
+
return this.config(Symbol.for("ElementNode"), {
|
|
8464
|
+
$transform: $normalizeShadowRootChildren,
|
|
8465
|
+
extends: LexicalNode
|
|
8466
|
+
});
|
|
8467
|
+
}
|
|
7832
8468
|
constructor(key) {
|
|
7833
8469
|
super(key);
|
|
7834
8470
|
this.__first = null;
|
|
@@ -7840,6 +8476,8 @@ var ElementNode = class extends LexicalNode {
|
|
|
7840
8476
|
this.__dir = null;
|
|
7841
8477
|
this.__textFormat = 0;
|
|
7842
8478
|
this.__textStyle = "";
|
|
8479
|
+
this.__slotHost = null;
|
|
8480
|
+
this.__slots = null;
|
|
7843
8481
|
}
|
|
7844
8482
|
afterCloneFrom(prevNode) {
|
|
7845
8483
|
super.afterCloneFrom(prevNode);
|
|
@@ -7847,6 +8485,9 @@ var ElementNode = class extends LexicalNode {
|
|
|
7847
8485
|
this.__first = prevNode.__first;
|
|
7848
8486
|
this.__last = prevNode.__last;
|
|
7849
8487
|
this.__size = prevNode.__size;
|
|
8488
|
+
this.__slotHost = prevNode.__slotHost;
|
|
8489
|
+
if (!(this.__slotHost === null || this.__parent === null)) formatDevErrorMessage(`ElementNode: node ${this.__key} is both slotted into host ${String(this.__slotHost)} and a child of parent ${String(this.__parent)}; __slotHost and __parent are mutually exclusive`);
|
|
8490
|
+
this.__slots = prevNode.__slots;
|
|
7850
8491
|
}
|
|
7851
8492
|
this.__indent = prevNode.__indent;
|
|
7852
8493
|
this.__format = prevNode.__format;
|
|
@@ -7867,6 +8508,15 @@ var ElementNode = class extends LexicalNode {
|
|
|
7867
8508
|
getIndent() {
|
|
7868
8509
|
return this.getLatest().__indent;
|
|
7869
8510
|
}
|
|
8511
|
+
/**
|
|
8512
|
+
* Returns the children of this node, in document order.
|
|
8513
|
+
*/
|
|
8514
|
+
/**
|
|
8515
|
+
* @deprecated The type parameter is an unchecked and unsafe cast,
|
|
8516
|
+
* equivalent to `element.getChildren() as T[]`, and will be
|
|
8517
|
+
* removed in a future release. Call this method without a type argument
|
|
8518
|
+
* and narrow the results with a type guard instead.
|
|
8519
|
+
*/
|
|
7870
8520
|
getChildren() {
|
|
7871
8521
|
const children = [];
|
|
7872
8522
|
let child = this.getFirstChild();
|
|
@@ -7889,7 +8539,7 @@ var ElementNode = class extends LexicalNode {
|
|
|
7889
8539
|
return this.getLatest().__size;
|
|
7890
8540
|
}
|
|
7891
8541
|
isEmpty() {
|
|
7892
|
-
return this.getChildrenSize() === 0;
|
|
8542
|
+
return this.getChildrenSize() === 0 && $getSlotNames(this).length === 0;
|
|
7893
8543
|
}
|
|
7894
8544
|
isDirty() {
|
|
7895
8545
|
const dirtyElements = getActiveEditor()._dirtyElements;
|
|
@@ -7902,6 +8552,10 @@ var ElementNode = class extends LexicalNode {
|
|
|
7902
8552
|
}
|
|
7903
8553
|
getAllTextNodes() {
|
|
7904
8554
|
const textNodes = [];
|
|
8555
|
+
for (const name of $getSlotNames(this)) {
|
|
8556
|
+
const slot = $getSlot(this, name);
|
|
8557
|
+
if ($isElementNode(slot)) textNodes.push(...slot.getAllTextNodes());
|
|
8558
|
+
}
|
|
7905
8559
|
let child = this.getFirstChild();
|
|
7906
8560
|
while (child !== null) {
|
|
7907
8561
|
if ($isTextNode(child)) textNodes.push(child);
|
|
@@ -7913,6 +8567,19 @@ var ElementNode = class extends LexicalNode {
|
|
|
7913
8567
|
}
|
|
7914
8568
|
return textNodes;
|
|
7915
8569
|
}
|
|
8570
|
+
/**
|
|
8571
|
+
* Returns the deepest first descendant of this node,
|
|
8572
|
+
* or null if it has no children.
|
|
8573
|
+
*
|
|
8574
|
+
* Descendant navigation is children-only by design: it feeds selectStart /
|
|
8575
|
+
* selectEnd and selection, which must not see slots (slots are isolated).
|
|
8576
|
+
*/
|
|
8577
|
+
/**
|
|
8578
|
+
* @deprecated The type parameter is an unchecked and unsafe cast,
|
|
8579
|
+
* equivalent to `element.getFirstDescendant() as T | null`, and will be
|
|
8580
|
+
* removed in a future release. Call this method without a type argument
|
|
8581
|
+
* and narrow the result with a type guard instead.
|
|
8582
|
+
*/
|
|
7916
8583
|
getFirstDescendant() {
|
|
7917
8584
|
let node = this.getFirstChild();
|
|
7918
8585
|
while ($isElementNode(node)) {
|
|
@@ -7922,6 +8589,16 @@ var ElementNode = class extends LexicalNode {
|
|
|
7922
8589
|
}
|
|
7923
8590
|
return node;
|
|
7924
8591
|
}
|
|
8592
|
+
/**
|
|
8593
|
+
* Returns the deepest last descendant of this node,
|
|
8594
|
+
* or null if it has no children.
|
|
8595
|
+
*/
|
|
8596
|
+
/**
|
|
8597
|
+
* @deprecated The type parameter is an unchecked and unsafe cast,
|
|
8598
|
+
* equivalent to `element.getLastDescendant() as T | null`, and will be
|
|
8599
|
+
* removed in a future release. Call this method without a type argument
|
|
8600
|
+
* and narrow the result with a type guard instead.
|
|
8601
|
+
*/
|
|
7925
8602
|
getLastDescendant() {
|
|
7926
8603
|
let node = this.getLastChild();
|
|
7927
8604
|
while ($isElementNode(node)) {
|
|
@@ -7931,6 +8608,16 @@ var ElementNode = class extends LexicalNode {
|
|
|
7931
8608
|
}
|
|
7932
8609
|
return node;
|
|
7933
8610
|
}
|
|
8611
|
+
/**
|
|
8612
|
+
* Returns the deepest descendant corresponding to the child at the given
|
|
8613
|
+
* index, or null if this node has no children.
|
|
8614
|
+
*/
|
|
8615
|
+
/**
|
|
8616
|
+
* @deprecated The type parameter is an unchecked and unsafe cast,
|
|
8617
|
+
* equivalent to `element.getDescendantByIndex(index) as T | null`, and
|
|
8618
|
+
* will be removed in a future release. Call this method without a type
|
|
8619
|
+
* argument and narrow the result with a type guard instead.
|
|
8620
|
+
*/
|
|
7934
8621
|
getDescendantByIndex(index) {
|
|
7935
8622
|
const children = this.getChildren();
|
|
7936
8623
|
const childrenLength = children.length;
|
|
@@ -7941,24 +8628,70 @@ var ElementNode = class extends LexicalNode {
|
|
|
7941
8628
|
const resolvedNode = children[index];
|
|
7942
8629
|
return $isElementNode(resolvedNode) && resolvedNode.getFirstDescendant() || resolvedNode || null;
|
|
7943
8630
|
}
|
|
8631
|
+
/**
|
|
8632
|
+
* Returns the first child of this node, or null if it has no children.
|
|
8633
|
+
*/
|
|
8634
|
+
/**
|
|
8635
|
+
* @deprecated The type parameter is an unchecked and unsafe cast,
|
|
8636
|
+
* equivalent to `element.getFirstChild() as T | null`, and will be
|
|
8637
|
+
* removed in a future release. Call this method without a type argument
|
|
8638
|
+
* and narrow the result with a type guard instead.
|
|
8639
|
+
*/
|
|
7944
8640
|
getFirstChild() {
|
|
7945
8641
|
const firstKey = this.getLatest().__first;
|
|
7946
8642
|
return firstKey === null ? null : $getNodeByKey(firstKey);
|
|
7947
8643
|
}
|
|
8644
|
+
/**
|
|
8645
|
+
* Returns the first child of this node, or throws if it has no children.
|
|
8646
|
+
*/
|
|
8647
|
+
/**
|
|
8648
|
+
* @deprecated The type parameter is an unchecked and unsafe cast,
|
|
8649
|
+
* equivalent to `element.getFirstChildOrThrow() as T`, and will be
|
|
8650
|
+
* removed in a future release. Call this method without a type argument
|
|
8651
|
+
* and narrow the result with a type guard instead.
|
|
8652
|
+
*/
|
|
7948
8653
|
getFirstChildOrThrow() {
|
|
7949
8654
|
const firstChild = this.getFirstChild();
|
|
7950
8655
|
if (firstChild === null) formatDevErrorMessage(`Expected node ${this.__key} to have a first child.`);
|
|
7951
8656
|
return firstChild;
|
|
7952
8657
|
}
|
|
8658
|
+
/**
|
|
8659
|
+
* Returns the last child of this node, or null if it has no children.
|
|
8660
|
+
*/
|
|
8661
|
+
/**
|
|
8662
|
+
* @deprecated The type parameter is an unchecked and unsafe cast,
|
|
8663
|
+
* equivalent to `element.getLastChild() as T | null`, and will be
|
|
8664
|
+
* removed in a future release. Call this method without a type argument
|
|
8665
|
+
* and narrow the result with a type guard instead.
|
|
8666
|
+
*/
|
|
7953
8667
|
getLastChild() {
|
|
7954
8668
|
const lastKey = this.getLatest().__last;
|
|
7955
8669
|
return lastKey === null ? null : $getNodeByKey(lastKey);
|
|
7956
8670
|
}
|
|
8671
|
+
/**
|
|
8672
|
+
* Returns the last child of this node, or throws if it has no children.
|
|
8673
|
+
*/
|
|
8674
|
+
/**
|
|
8675
|
+
* @deprecated The type parameter is an unchecked and unsafe cast,
|
|
8676
|
+
* equivalent to `element.getLastChildOrThrow() as T`, and will be
|
|
8677
|
+
* removed in a future release. Call this method without a type argument
|
|
8678
|
+
* and narrow the result with a type guard instead.
|
|
8679
|
+
*/
|
|
7957
8680
|
getLastChildOrThrow() {
|
|
7958
8681
|
const lastChild = this.getLastChild();
|
|
7959
8682
|
if (lastChild === null) formatDevErrorMessage(`Expected node ${this.__key} to have a last child.`);
|
|
7960
8683
|
return lastChild;
|
|
7961
8684
|
}
|
|
8685
|
+
/**
|
|
8686
|
+
* Returns the child of this node at the given index, or null if
|
|
8687
|
+
* the index is out of range.
|
|
8688
|
+
*/
|
|
8689
|
+
/**
|
|
8690
|
+
* @deprecated The type parameter is an unchecked and unsafe cast,
|
|
8691
|
+
* equivalent to `element.getChildAtIndex(index) as T | null`, and will
|
|
8692
|
+
* be removed in a future release. Call this method without a type
|
|
8693
|
+
* argument and narrow the result with a type guard instead.
|
|
8694
|
+
*/
|
|
7962
8695
|
getChildAtIndex(index) {
|
|
7963
8696
|
const size = this.getChildrenSize();
|
|
7964
8697
|
let node;
|
|
@@ -7983,7 +8716,7 @@ var ElementNode = class extends LexicalNode {
|
|
|
7983
8716
|
return null;
|
|
7984
8717
|
}
|
|
7985
8718
|
getTextContent() {
|
|
7986
|
-
let textContent =
|
|
8719
|
+
let textContent = $getSlotsTextContent(this);
|
|
7987
8720
|
const children = this.getChildren();
|
|
7988
8721
|
const childrenLength = children.length;
|
|
7989
8722
|
for (let i = 0; i < childrenLength; i++) {
|
|
@@ -7994,7 +8727,7 @@ var ElementNode = class extends LexicalNode {
|
|
|
7994
8727
|
return textContent;
|
|
7995
8728
|
}
|
|
7996
8729
|
getTextContentSize() {
|
|
7997
|
-
let textContentSize =
|
|
8730
|
+
let textContentSize = $getSlotsTextContentSize(this);
|
|
7998
8731
|
const children = this.getChildren();
|
|
7999
8732
|
const childrenLength = children.length;
|
|
8000
8733
|
for (let i = 0; i < childrenLength; i++) {
|
|
@@ -8110,6 +8843,7 @@ var ElementNode = class extends LexicalNode {
|
|
|
8110
8843
|
const oldSize = this.getChildrenSize();
|
|
8111
8844
|
const writableSelf = this.getWritable();
|
|
8112
8845
|
if (!(start + deleteCount <= oldSize)) formatDevErrorMessage(`ElementNode.splice: start + deleteCount > oldSize (${String(start)} + ${String(deleteCount)} > ${String(oldSize)})`);
|
|
8846
|
+
for (const nodeToInsert of nodesToInsert) $errorOnSlotCycleChild(writableSelf, nodeToInsert);
|
|
8113
8847
|
const writableSelfKey = writableSelf.__key;
|
|
8114
8848
|
const nodesToInsertKeys = [];
|
|
8115
8849
|
const nodesToRemoveKeys = [];
|
|
@@ -8127,7 +8861,7 @@ var ElementNode = class extends LexicalNode {
|
|
|
8127
8861
|
if (nodeToDelete === null) formatDevErrorMessage(`splice: sibling not found`);
|
|
8128
8862
|
const nextSibling = nodeToDelete.getNextSibling();
|
|
8129
8863
|
const nodeKeyToDelete = nodeToDelete.__key;
|
|
8130
|
-
removeFromParent(nodeToDelete.getWritable());
|
|
8864
|
+
$removeFromParent(nodeToDelete.getWritable());
|
|
8131
8865
|
nodesToRemoveKeys.push(nodeKeyToDelete);
|
|
8132
8866
|
nodeToDelete = nextSibling;
|
|
8133
8867
|
}
|
|
@@ -8137,7 +8871,7 @@ var ElementNode = class extends LexicalNode {
|
|
|
8137
8871
|
if (prevNode !== null && nodeToInsert.is(prevNode)) nodeBeforeRange = prevNode = prevNode.getPreviousSibling();
|
|
8138
8872
|
const writableNodeToInsert = nodeToInsert.getWritable();
|
|
8139
8873
|
if (writableNodeToInsert.__parent === writableSelfKey) newSize--;
|
|
8140
|
-
removeFromParent(writableNodeToInsert);
|
|
8874
|
+
$removeFromParent(writableNodeToInsert);
|
|
8141
8875
|
const nodeKeyToInsert = nodeToInsert.__key;
|
|
8142
8876
|
if (prevNode === null) {
|
|
8143
8877
|
writableSelf.__first = nodeKeyToInsert;
|
|
@@ -8312,16 +9046,26 @@ function isPointRemoved(point, nodesToRemoveKeySet, nodesToInsertKeySet) {
|
|
|
8312
9046
|
}
|
|
8313
9047
|
return false;
|
|
8314
9048
|
}
|
|
8315
|
-
/**
|
|
8316
|
-
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
8317
|
-
*
|
|
8318
|
-
* This source code is licensed under the MIT license found in the
|
|
8319
|
-
* LICENSE file in the root directory of this source tree.
|
|
8320
|
-
*
|
|
8321
|
-
*/
|
|
8322
9049
|
/** @noInheritDoc */
|
|
8323
9050
|
var DecoratorNode = class extends LexicalNode {
|
|
8324
9051
|
/** @internal */
|
|
9052
|
+
/** @internal */
|
|
9053
|
+
__slotHost;
|
|
9054
|
+
/** @internal */
|
|
9055
|
+
__slots;
|
|
9056
|
+
constructor(key) {
|
|
9057
|
+
super(key);
|
|
9058
|
+
this.__slotHost = null;
|
|
9059
|
+
this.__slots = null;
|
|
9060
|
+
}
|
|
9061
|
+
afterCloneFrom(prevNode) {
|
|
9062
|
+
super.afterCloneFrom(prevNode);
|
|
9063
|
+
if (this.__key === prevNode.__key) {
|
|
9064
|
+
this.__slotHost = prevNode.__slotHost;
|
|
9065
|
+
if (!(this.__slotHost === null || this.__parent === null)) formatDevErrorMessage(`DecoratorNode: node ${this.__key} is both slotted into host ${String(this.__slotHost)} and a child of parent ${String(this.__parent)}; __slotHost and __parent are mutually exclusive`);
|
|
9066
|
+
this.__slots = prevNode.__slots;
|
|
9067
|
+
}
|
|
9068
|
+
}
|
|
8325
9069
|
/**
|
|
8326
9070
|
* The returned value is added to the LexicalEditor._decorators
|
|
8327
9071
|
*/
|
|
@@ -8403,12 +9147,12 @@ function editorStateHasDirtySelection(editorState, editor) {
|
|
|
8403
9147
|
return false;
|
|
8404
9148
|
}
|
|
8405
9149
|
function cloneEditorState(current) {
|
|
8406
|
-
return new EditorState(cloneMap(current._nodeMap));
|
|
9150
|
+
return new EditorState(cloneMap(current._nodeMap), null, current._slotsUsed);
|
|
8407
9151
|
}
|
|
8408
9152
|
function createEmptyEditorState() {
|
|
8409
|
-
return new EditorState(new Map([["root", $createRootNode()]]));
|
|
9153
|
+
return new EditorState(/* @__PURE__ */ new Map([["root", $createRootNode()]]), null, false);
|
|
8410
9154
|
}
|
|
8411
|
-
function exportNodeToJSON(node) {
|
|
9155
|
+
function $exportNodeToJSON(node) {
|
|
8412
9156
|
const serializedNode = node.exportJSON();
|
|
8413
9157
|
const nodeClass = node.constructor;
|
|
8414
9158
|
if (serializedNode.type !== nodeClass.getType()) formatDevErrorMessage(`LexicalNode: Node ${nodeClass.name} does not match the serialized type. Check if .exportJSON() is implemented and it is returning the correct type.`);
|
|
@@ -8418,10 +9162,20 @@ function exportNodeToJSON(node) {
|
|
|
8418
9162
|
const children = node.getChildren();
|
|
8419
9163
|
for (let i = 0; i < children.length; i++) {
|
|
8420
9164
|
const child = children[i];
|
|
8421
|
-
const serializedChildNode = exportNodeToJSON(child);
|
|
9165
|
+
const serializedChildNode = $exportNodeToJSON(child);
|
|
8422
9166
|
serializedChildren.push(serializedChildNode);
|
|
8423
9167
|
}
|
|
8424
9168
|
}
|
|
9169
|
+
const slotNames = $getSlotNames(node);
|
|
9170
|
+
if (slotNames.length > 0) {
|
|
9171
|
+
const serializedSlots = {};
|
|
9172
|
+
for (const name of slotNames) {
|
|
9173
|
+
const slotNode = $getSlot(node, name);
|
|
9174
|
+
if (!(slotNode !== null)) formatDevErrorMessage(`LexicalNode: Node ${nodeClass.name} has slot "${name}" but it resolved to no node during export.`);
|
|
9175
|
+
serializedSlots[name] = $exportNodeToJSON(slotNode);
|
|
9176
|
+
}
|
|
9177
|
+
serializedNode.$slots = serializedSlots;
|
|
9178
|
+
}
|
|
8425
9179
|
return serializedNode;
|
|
8426
9180
|
}
|
|
8427
9181
|
/**
|
|
@@ -8435,11 +9189,22 @@ var EditorState = class EditorState {
|
|
|
8435
9189
|
_selection;
|
|
8436
9190
|
_flushSync;
|
|
8437
9191
|
_readOnly;
|
|
8438
|
-
|
|
9192
|
+
/**
|
|
9193
|
+
* True if this EditorState was parsed without running transforms
|
|
9194
|
+
*/
|
|
9195
|
+
_parsed;
|
|
9196
|
+
/**
|
|
9197
|
+
* True if this EditorState or the LexicalEditor that created it has
|
|
9198
|
+
* ever used slots
|
|
9199
|
+
*/
|
|
9200
|
+
_slotsUsed;
|
|
9201
|
+
constructor(nodeMap, selection = null, slotsUsed = false) {
|
|
8439
9202
|
this._nodeMap = nodeMap;
|
|
8440
9203
|
this._selection = selection || null;
|
|
8441
9204
|
this._flushSync = false;
|
|
8442
9205
|
this._readOnly = false;
|
|
9206
|
+
this._parsed = false;
|
|
9207
|
+
this._slotsUsed = slotsUsed;
|
|
8443
9208
|
}
|
|
8444
9209
|
isEmpty() {
|
|
8445
9210
|
return this._nodeMap.size === 1 && this._selection === null;
|
|
@@ -8448,12 +9213,12 @@ var EditorState = class EditorState {
|
|
|
8448
9213
|
return readEditorState(options && options.editor || null, this, callbackFn);
|
|
8449
9214
|
}
|
|
8450
9215
|
clone(selection) {
|
|
8451
|
-
const editorState = new EditorState(this._nodeMap, selection === void 0 ? this._selection : selection);
|
|
9216
|
+
const editorState = new EditorState(this._nodeMap, selection === void 0 ? this._selection : selection, this._slotsUsed);
|
|
8452
9217
|
editorState._readOnly = true;
|
|
8453
9218
|
return editorState;
|
|
8454
9219
|
}
|
|
8455
9220
|
toJSON() {
|
|
8456
|
-
return readEditorState(null, this, () => ({ root: exportNodeToJSON($getRoot()) }));
|
|
9221
|
+
return readEditorState(null, this, () => ({ root: $exportNodeToJSON($getRoot()) }));
|
|
8457
9222
|
}
|
|
8458
9223
|
};
|
|
8459
9224
|
/**
|
|
@@ -8480,6 +9245,99 @@ var ArtificialNode__DO_NOT_USE = class extends ElementNode {
|
|
|
8480
9245
|
*
|
|
8481
9246
|
*/
|
|
8482
9247
|
/** @noInheritDoc */
|
|
9248
|
+
var LineBreakNode = class LineBreakNode extends LexicalNode {
|
|
9249
|
+
/** @internal */
|
|
9250
|
+
static getType() {
|
|
9251
|
+
return "linebreak";
|
|
9252
|
+
}
|
|
9253
|
+
static clone(node) {
|
|
9254
|
+
return new LineBreakNode(node.__key);
|
|
9255
|
+
}
|
|
9256
|
+
constructor(key) {
|
|
9257
|
+
super(key);
|
|
9258
|
+
}
|
|
9259
|
+
getTextContent() {
|
|
9260
|
+
return "\n";
|
|
9261
|
+
}
|
|
9262
|
+
createDOM() {
|
|
9263
|
+
return document.createElement("br");
|
|
9264
|
+
}
|
|
9265
|
+
updateDOM() {
|
|
9266
|
+
return false;
|
|
9267
|
+
}
|
|
9268
|
+
isInline() {
|
|
9269
|
+
return true;
|
|
9270
|
+
}
|
|
9271
|
+
static importDOM() {
|
|
9272
|
+
return { br: (node) => {
|
|
9273
|
+
if (isOnlyChildInBlockNode(node) || isLastChildInBlockNode(node)) return null;
|
|
9274
|
+
return {
|
|
9275
|
+
conversion: $convertLineBreakElement,
|
|
9276
|
+
priority: 0
|
|
9277
|
+
};
|
|
9278
|
+
} };
|
|
9279
|
+
}
|
|
9280
|
+
static importJSON(serializedLineBreakNode) {
|
|
9281
|
+
return $createLineBreakNode().updateFromJSON(serializedLineBreakNode);
|
|
9282
|
+
}
|
|
9283
|
+
};
|
|
9284
|
+
function $convertLineBreakElement(node) {
|
|
9285
|
+
return { node: $createLineBreakNode() };
|
|
9286
|
+
}
|
|
9287
|
+
function $createLineBreakNode() {
|
|
9288
|
+
return $applyNodeReplacement(new LineBreakNode());
|
|
9289
|
+
}
|
|
9290
|
+
function $isLineBreakNode(node) {
|
|
9291
|
+
return node instanceof LineBreakNode;
|
|
9292
|
+
}
|
|
9293
|
+
/**
|
|
9294
|
+
* True when `node` is the sole non-whitespace child of a block DOM
|
|
9295
|
+
* element. Used by the LineBreak importer to drop stray `<br>` elements
|
|
9296
|
+
* that the legacy `$generateNodesFromDOM` also skipped (matches the
|
|
9297
|
+
* behavior of `LineBreakNode.importDOM`).
|
|
9298
|
+
*
|
|
9299
|
+
* @experimental
|
|
9300
|
+
*/
|
|
9301
|
+
function isOnlyChildInBlockNode(node) {
|
|
9302
|
+
const parentElement = node.parentElement;
|
|
9303
|
+
if (parentElement !== null && isBlockDomNode(parentElement)) {
|
|
9304
|
+
const firstChild = parentElement.firstChild;
|
|
9305
|
+
if (firstChild === node || firstChild.nextSibling === node && isWhitespaceDomTextNode(firstChild)) {
|
|
9306
|
+
const lastChild = parentElement.lastChild;
|
|
9307
|
+
if (lastChild === node || lastChild.previousSibling === node && isWhitespaceDomTextNode(lastChild)) return true;
|
|
9308
|
+
}
|
|
9309
|
+
}
|
|
9310
|
+
return false;
|
|
9311
|
+
}
|
|
9312
|
+
/**
|
|
9313
|
+
* True when `node` is the trailing non-whitespace child of a block DOM
|
|
9314
|
+
* element (excluding the only-child case). Used by the LineBreak
|
|
9315
|
+
* importer to drop trailing `<br>` elements like the Apple-interchange
|
|
9316
|
+
* clipboard artifact (matches `LineBreakNode.importDOM`).
|
|
9317
|
+
*
|
|
9318
|
+
* @experimental
|
|
9319
|
+
*/
|
|
9320
|
+
function isLastChildInBlockNode(node) {
|
|
9321
|
+
const parentElement = node.parentElement;
|
|
9322
|
+
if (parentElement !== null && isBlockDomNode(parentElement)) {
|
|
9323
|
+
const firstChild = parentElement.firstChild;
|
|
9324
|
+
if (firstChild === node || firstChild.nextSibling === node && isWhitespaceDomTextNode(firstChild)) return false;
|
|
9325
|
+
const lastChild = parentElement.lastChild;
|
|
9326
|
+
if (lastChild === node || lastChild.previousSibling === node && isWhitespaceDomTextNode(lastChild)) return true;
|
|
9327
|
+
}
|
|
9328
|
+
return false;
|
|
9329
|
+
}
|
|
9330
|
+
function isWhitespaceDomTextNode(node) {
|
|
9331
|
+
return isDOMTextNode(node) && /^( |\t|\r?\n)+$/.test(node.textContent || "");
|
|
9332
|
+
}
|
|
9333
|
+
/**
|
|
9334
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
9335
|
+
*
|
|
9336
|
+
* This source code is licensed under the MIT license found in the
|
|
9337
|
+
* LICENSE file in the root directory of this source tree.
|
|
9338
|
+
*
|
|
9339
|
+
*/
|
|
9340
|
+
/** @noInheritDoc */
|
|
8483
9341
|
var ParagraphNode = class ParagraphNode extends ElementNode {
|
|
8484
9342
|
/** @internal */
|
|
8485
9343
|
static getType() {
|
|
@@ -8577,6 +9435,20 @@ function $isParagraphNode(node) {
|
|
|
8577
9435
|
return node instanceof ParagraphNode;
|
|
8578
9436
|
}
|
|
8579
9437
|
/**
|
|
9438
|
+
* Controls which editor state {@link LexicalEditor.read} observes and whether
|
|
9439
|
+
* pending updates are flushed before the read.
|
|
9440
|
+
*
|
|
9441
|
+
* - `'force-commit'` (the default) flushes any pending updates immediately
|
|
9442
|
+
* before the read, so it always observes a fully committed and reconciled
|
|
9443
|
+
* state.
|
|
9444
|
+
* - `'pending'` reads the pending state if it exists, otherwise the committed
|
|
9445
|
+
* state, without flushing. This is safe to call when an update may already
|
|
9446
|
+
* be in progress at the cost of possibly observing an uncommitted state
|
|
9447
|
+
* before node transforms, DOM reconciliation, etc. have run.
|
|
9448
|
+
* - `'latest'` reads the latest committed state without flushing pending
|
|
9449
|
+
* updates, equivalent to `editor.getEditorState().read(callbackFn, {editor})`.
|
|
9450
|
+
*/
|
|
9451
|
+
/**
|
|
8580
9452
|
* Configuration entry passed in {@link CreateEditorArgs.nodes} to substitute
|
|
8581
9453
|
* a core node class with a custom subclass. The replacement class itself
|
|
8582
9454
|
* must also appear in `nodes`.
|
|
@@ -8596,6 +9468,17 @@ function $isParagraphNode(node) {
|
|
|
8596
9468
|
* without manual `instanceof` checks.
|
|
8597
9469
|
*/
|
|
8598
9470
|
/** @internal @experimental */
|
|
9471
|
+
/**
|
|
9472
|
+
* Default {@link CreateEditorArgs.onWarn} handler. Used for recoverable,
|
|
9473
|
+
* warn-level conditions (e.g. the update-recursion guard tripping) that the
|
|
9474
|
+
* editor has already recovered from. Throws in development so the condition is
|
|
9475
|
+
* impossible to miss, and only `console.warn`s in production so it is not
|
|
9476
|
+
* reported as a fatal error. Embedders can override this via `onWarn` to route
|
|
9477
|
+
* the condition to their own telemetry at warn severity.
|
|
9478
|
+
*/
|
|
9479
|
+
function defaultOnWarn(error) {
|
|
9480
|
+
throw error;
|
|
9481
|
+
}
|
|
8599
9482
|
const DEFAULT_SKIP_INITIALIZATION = false;
|
|
8600
9483
|
/**
|
|
8601
9484
|
* The payload passed to an UpdateListener
|
|
@@ -8707,10 +9590,14 @@ function resetEditor(editor, prevRootElement, nextRootElement, pendingEditorStat
|
|
|
8707
9590
|
observer.disconnect();
|
|
8708
9591
|
editor._observer = null;
|
|
8709
9592
|
}
|
|
8710
|
-
if (prevRootElement !== null)
|
|
9593
|
+
if (prevRootElement !== null) {
|
|
9594
|
+
prevRootElement.textContent = "";
|
|
9595
|
+
clearNodeKeyOnDOMNode(prevRootElement, editor);
|
|
9596
|
+
}
|
|
8711
9597
|
if (nextRootElement !== null) {
|
|
8712
9598
|
nextRootElement.textContent = "";
|
|
8713
9599
|
keyNodeMap.set("root", nextRootElement);
|
|
9600
|
+
setNodeKeyOnDOMNode(nextRootElement, editor, "root");
|
|
8714
9601
|
}
|
|
8715
9602
|
}
|
|
8716
9603
|
function initializeConversionCache(nodes, additionalConversions) {
|
|
@@ -8740,9 +9627,7 @@ function initializeConversionCache(nodes, additionalConversions) {
|
|
|
8740
9627
|
function getTransformSetFromKlass(klass) {
|
|
8741
9628
|
const transforms = /* @__PURE__ */ new Set();
|
|
8742
9629
|
const staticTransforms = /* @__PURE__ */ new Set();
|
|
8743
|
-
|
|
8744
|
-
while (currentKlass) {
|
|
8745
|
-
const { ownNodeConfig } = getStaticNodeConfig(currentKlass);
|
|
9630
|
+
for (const { klass: currentKlass, ownNodeConfig } of iterStaticNodeConfigChain(klass)) {
|
|
8746
9631
|
const staticTransform = currentKlass.transform;
|
|
8747
9632
|
if (!staticTransforms.has(staticTransform)) {
|
|
8748
9633
|
staticTransforms.add(staticTransform);
|
|
@@ -8752,10 +9637,6 @@ function getTransformSetFromKlass(klass) {
|
|
|
8752
9637
|
if (ownNodeConfig) {
|
|
8753
9638
|
const $transform = ownNodeConfig.$transform;
|
|
8754
9639
|
if ($transform) transforms.add($transform);
|
|
8755
|
-
currentKlass = ownNodeConfig.extends;
|
|
8756
|
-
} else {
|
|
8757
|
-
const parent = Object.getPrototypeOf(currentKlass);
|
|
8758
|
-
currentKlass = parent.prototype instanceof LexicalNode && parent !== LexicalNode ? parent : void 0;
|
|
8759
9640
|
}
|
|
8760
9641
|
}
|
|
8761
9642
|
return transforms;
|
|
@@ -8770,6 +9651,7 @@ const DEFAULT_EDITOR_DOM_CONFIG = {
|
|
|
8770
9651
|
},
|
|
8771
9652
|
$extractWithChild: (node, childNode, selection, destination, _editor) => $isElementNode(node) && node.extractWithChild(childNode, selection, destination),
|
|
8772
9653
|
$getDOMSlot: (node, dom, _editor) => node.getDOMSlot(dom),
|
|
9654
|
+
$getSlotTargetElement: (_node, _slotName, _hostDom, _editor) => null,
|
|
8773
9655
|
$shouldExclude: (node, _selection, _editor) => $isElementNode(node) && node.excludeFromCopy("html"),
|
|
8774
9656
|
$shouldInclude: (node, selection, _editor) => selection ? node.isSelected(selection) : true,
|
|
8775
9657
|
$updateDOM: (nextNode, prevNode, dom, editor) => nextNode.updateDOM(prevNode, dom, editor._config)
|
|
@@ -8799,7 +9681,7 @@ function createEditor(editorConfig) {
|
|
|
8799
9681
|
ArtificialNode__DO_NOT_USE,
|
|
8800
9682
|
...config.nodes || []
|
|
8801
9683
|
];
|
|
8802
|
-
const { onError, html } = config;
|
|
9684
|
+
const { onError, onWarn, html } = config;
|
|
8803
9685
|
const isEditable = config.editable !== void 0 ? config.editable : true;
|
|
8804
9686
|
let registeredNodes;
|
|
8805
9687
|
if (editorConfig === void 0 && activeEditor !== null) registeredNodes = activeEditor._nodes;
|
|
@@ -8809,12 +9691,19 @@ function createEditor(editorConfig) {
|
|
|
8809
9691
|
let klass = nodes[i];
|
|
8810
9692
|
let replace = null;
|
|
8811
9693
|
let replaceWithKlass = null;
|
|
8812
|
-
if (typeof klass
|
|
9694
|
+
if (klass && typeof klass === "object") {
|
|
8813
9695
|
const options = klass;
|
|
8814
9696
|
klass = options.replace;
|
|
8815
9697
|
replace = options.with;
|
|
8816
9698
|
replaceWithKlass = options.withKlass || null;
|
|
8817
9699
|
}
|
|
9700
|
+
if (typeof klass !== "function" || !klass.prototype || !(klass === LexicalNode || klass.prototype instanceof LexicalNode)) {
|
|
9701
|
+
let version = "<unknown>";
|
|
9702
|
+
try {
|
|
9703
|
+
version = JSON.parse(LEXICAL_VERSION);
|
|
9704
|
+
} catch (_unused) {}
|
|
9705
|
+
formatDevErrorMessage(`createEditor: nodes[${String(i - nodes.length + (config.nodes ? config.nodes.length : 0))}] ${typeof klass === "function" ? `${klass.name}${typeof klass.getType === "function" ? ` (type ${String(klass.getType())})` : ""}` : String(klass)} is not a constructor that subclasses LexicalNode from the lexical package used by this editor (${String(version)})`);
|
|
9706
|
+
}
|
|
8818
9707
|
getStaticNodeConfig(klass);
|
|
8819
9708
|
{
|
|
8820
9709
|
const name = klass.name;
|
|
@@ -8826,7 +9715,6 @@ function createEditor(editorConfig) {
|
|
|
8826
9715
|
["getType", "clone"].forEach((method) => {
|
|
8827
9716
|
if (!hasOwnStaticMethod(klass, method)) console.warn(`${name} must implement static "${method}" method`);
|
|
8828
9717
|
});
|
|
8829
|
-
if (!hasOwnStaticMethod(klass, "importDOM") && hasOwnExportDOM(klass)) console.warn(`${name} should implement "importDOM" if using a custom "exportDOM" method to ensure HTML serialization (important for copy & paste) works as expected`);
|
|
8830
9718
|
if (!hasOwnStaticMethod(klass, "importJSON")) console.warn(`${name} should implement "importJSON" method to ensure JSON and default HTML serialization works as expected`);
|
|
8831
9719
|
}
|
|
8832
9720
|
}
|
|
@@ -8850,7 +9738,7 @@ function createEditor(editorConfig) {
|
|
|
8850
9738
|
},
|
|
8851
9739
|
namespace,
|
|
8852
9740
|
theme
|
|
8853
|
-
}, onError ? onError : console.error, initializeConversionCache(registeredNodes, html ? html.import : void 0), isEditable, editorConfig);
|
|
9741
|
+
}, onError ? onError : console.error, onWarn ? onWarn : defaultOnWarn, initializeConversionCache(registeredNodes, html ? html.import : void 0), isEditable, editorConfig);
|
|
8854
9742
|
if (initialEditorState !== void 0) {
|
|
8855
9743
|
editor._pendingEditorState = initialEditorState;
|
|
8856
9744
|
editor._dirtyType = FULL_RECONCILE;
|
|
@@ -8929,6 +9817,8 @@ var LexicalEditor = class {
|
|
|
8929
9817
|
/** @internal */
|
|
8930
9818
|
_onError;
|
|
8931
9819
|
/** @internal */
|
|
9820
|
+
_onWarn;
|
|
9821
|
+
/** @internal */
|
|
8932
9822
|
_htmlConversions;
|
|
8933
9823
|
/** @internal */
|
|
8934
9824
|
_window;
|
|
@@ -8936,10 +9826,21 @@ var LexicalEditor = class {
|
|
|
8936
9826
|
_editable;
|
|
8937
9827
|
/** @internal */
|
|
8938
9828
|
_blockCursorElement;
|
|
9829
|
+
/**
|
|
9830
|
+
* @internal @experimental
|
|
9831
|
+
*
|
|
9832
|
+
* Latches to `true` the first time {@link $setSlot} runs in this
|
|
9833
|
+
* editor. Gates the commit-time slot-containment clamp so editors that never
|
|
9834
|
+
* use slots skip the per-update frame walk entirely. The latch persists for
|
|
9835
|
+
* the lifetime of the editor instance — `resetEditor` and `setEditorState`
|
|
9836
|
+
* do not clear it, so an editor that once used slots keeps paying the clamp
|
|
9837
|
+
* cost even after switching to a slot-free state.
|
|
9838
|
+
*/
|
|
9839
|
+
_slotsUsed;
|
|
8939
9840
|
/** @internal */
|
|
8940
9841
|
_createEditorArgs;
|
|
8941
9842
|
/** @internal */
|
|
8942
|
-
constructor(editorState, parentEditor, nodes, config, onError, htmlConversions, editable, createEditorArgs) {
|
|
9843
|
+
constructor(editorState, parentEditor, nodes, config, onError, onWarn, htmlConversions, editable, createEditorArgs) {
|
|
8943
9844
|
this._createEditorArgs = createEditorArgs;
|
|
8944
9845
|
this._parentEditor = parentEditor;
|
|
8945
9846
|
this._rootElement = null;
|
|
@@ -8973,11 +9874,13 @@ var LexicalEditor = class {
|
|
|
8973
9874
|
this._observer = null;
|
|
8974
9875
|
this._key = createUID();
|
|
8975
9876
|
this._onError = onError;
|
|
9877
|
+
this._onWarn = onWarn;
|
|
8976
9878
|
this._htmlConversions = htmlConversions;
|
|
8977
9879
|
this._editable = editable;
|
|
8978
9880
|
this._headless = parentEditor !== null && parentEditor._headless;
|
|
8979
9881
|
this._window = null;
|
|
8980
9882
|
this._blockCursorElement = null;
|
|
9883
|
+
this._slotsUsed = false;
|
|
8981
9884
|
}
|
|
8982
9885
|
/**
|
|
8983
9886
|
*
|
|
@@ -9151,7 +10054,7 @@ var LexicalEditor = class {
|
|
|
9151
10054
|
if (nodeMutationMap.size > 0) listener(nodeMutationMap, {
|
|
9152
10055
|
dirtyLeaves: /* @__PURE__ */ new Set(),
|
|
9153
10056
|
prevEditorState,
|
|
9154
|
-
updateTags: new Set(["registerMutationListener"])
|
|
10057
|
+
updateTags: /* @__PURE__ */ new Set(["registerMutationListener"])
|
|
9155
10058
|
});
|
|
9156
10059
|
}
|
|
9157
10060
|
/** @internal */
|
|
@@ -9265,7 +10168,7 @@ var LexicalEditor = class {
|
|
|
9265
10168
|
if (!this._config.disableEvents) addRootElementEvents(nextRootElement, this);
|
|
9266
10169
|
if (classNames != null) nextRootElement.classList.add(...classNames);
|
|
9267
10170
|
{
|
|
9268
|
-
const nextRootElementParent = nextRootElement
|
|
10171
|
+
const nextRootElementParent = getParentElement(nextRootElement);
|
|
9269
10172
|
if (nextRootElementParent != null && ["flex", "inline-flex"].includes(getComputedStyle(nextRootElementParent).display)) console.warn(`When using "display: flex" or "display: inline-flex" on an element containing content editable, Chrome may have unwanted focusing behavior when clicking outside of it. Consider wrapping the content editable within a non-flex element.`);
|
|
9270
10173
|
}
|
|
9271
10174
|
} else {
|
|
@@ -9305,18 +10208,21 @@ var LexicalEditor = class {
|
|
|
9305
10208
|
}
|
|
9306
10209
|
flushRootMutations(this);
|
|
9307
10210
|
const pendingEditorState = this._pendingEditorState;
|
|
9308
|
-
const tags = this._updateTags;
|
|
9309
10211
|
const tag = options !== void 0 ? options.tag : null;
|
|
9310
10212
|
if (pendingEditorState !== null && !pendingEditorState.isEmpty()) {
|
|
9311
|
-
if (tag != null)
|
|
10213
|
+
if (tag != null) this._updateTags.add(tag);
|
|
9312
10214
|
$commitPendingUpdates(this);
|
|
9313
10215
|
}
|
|
9314
10216
|
this._pendingEditorState = writableEditorState;
|
|
9315
10217
|
this._dirtyType = FULL_RECONCILE;
|
|
9316
10218
|
this._dirtyElements.set("root", false);
|
|
9317
10219
|
this._compositionKey = null;
|
|
9318
|
-
|
|
9319
|
-
|
|
10220
|
+
this._slotsUsed = this._slotsUsed || editorState._slotsUsed;
|
|
10221
|
+
updateEditorSync(this, () => {
|
|
10222
|
+
if (tag) this._updateTags.add(tag);
|
|
10223
|
+
if (editorState._parsed) for (const [key, node] of writableEditorState._nodeMap.entries()) if ($isElementNode(node)) this._dirtyElements.set(key, true);
|
|
10224
|
+
else this._dirtyLeaves.add(key);
|
|
10225
|
+
}, { discrete: this._updating ? void 0 : true });
|
|
9320
10226
|
}
|
|
9321
10227
|
/**
|
|
9322
10228
|
* Parses a SerializedEditorState (usually produced by {@link EditorState.toJSON}) and returns
|
|
@@ -9333,13 +10239,25 @@ var LexicalEditor = class {
|
|
|
9333
10239
|
* Executes a read of the editor's state, with the
|
|
9334
10240
|
* editor context available (useful for exporting and read-only DOM
|
|
9335
10241
|
* operations). Much like update, but prevents any mutation of the
|
|
9336
|
-
* editor's state.
|
|
9337
|
-
*
|
|
10242
|
+
* editor's state.
|
|
10243
|
+
*
|
|
10244
|
+
* When called with a single argument the `mode` defaults to
|
|
10245
|
+
* `'force-commit'`, which flushes any pending updates immediately before the
|
|
10246
|
+
* read so it always observes a fully committed and reconciled state. See
|
|
10247
|
+
* {@link EditorReadMode} for the behavior of the other modes (`'pending'`
|
|
10248
|
+
* and `'latest'`).
|
|
9338
10249
|
* @param callbackFn - A function that has access to read-only editor state.
|
|
9339
10250
|
*/
|
|
9340
|
-
|
|
9341
|
-
|
|
9342
|
-
|
|
10251
|
+
/**
|
|
10252
|
+
* Executes a read of the editor's state in the given `mode`, with the editor
|
|
10253
|
+
* context available. See {@link EditorReadMode} for the available modes.
|
|
10254
|
+
* @param mode - Which editor state to read and whether to flush first.
|
|
10255
|
+
* @param callbackFn - A function that has access to read-only editor state.
|
|
10256
|
+
*/
|
|
10257
|
+
read(...args) {
|
|
10258
|
+
const [mode, callbackFn] = args.length === 1 ? ["force-commit", args[0]] : args;
|
|
10259
|
+
if (mode === "force-commit") $commitPendingUpdates(this);
|
|
10260
|
+
return (mode === "pending" ? this._pendingEditorState || this._editorState : this.getEditorState()).read(callbackFn, { editor: this });
|
|
9343
10261
|
}
|
|
9344
10262
|
/**
|
|
9345
10263
|
* Executes an update to the editor state. The updateFn callback is the ONLY place
|
|
@@ -9404,6 +10322,7 @@ var LexicalEditor = class {
|
|
|
9404
10322
|
if (this._editable !== editable) {
|
|
9405
10323
|
this._editable = editable;
|
|
9406
10324
|
triggerListeners("editable", this, true, editable);
|
|
10325
|
+
if (this._slotsUsed) this.update(() => $fullReconcile());
|
|
9407
10326
|
}
|
|
9408
10327
|
}
|
|
9409
10328
|
/**
|
|
@@ -9454,22 +10373,28 @@ function getRegisteredNode(editor, nodeType) {
|
|
|
9454
10373
|
const scheduleMicroTask = typeof queueMicrotask === "function" ? queueMicrotask : (fn) => {
|
|
9455
10374
|
Promise.resolve().then(fn);
|
|
9456
10375
|
};
|
|
9457
|
-
function $
|
|
9458
|
-
|
|
9459
|
-
|
|
9460
|
-
|
|
9461
|
-
|
|
10376
|
+
function $isSelectionCapturedInDecoratorInput(anchorDOM, preResolvedActiveElement) {
|
|
10377
|
+
const activeElement = preResolvedActiveElement !== void 0 ? preResolvedActiveElement : (() => {
|
|
10378
|
+
const root = anchorDOM.getRootNode();
|
|
10379
|
+
return isDOMDocumentNode(root) || isDOMShadowRoot(root) ? getActiveElementDeep(root) : null;
|
|
10380
|
+
})();
|
|
9462
10381
|
if (!isHTMLElement(activeElement)) return false;
|
|
10382
|
+
if (activeElement.hasAttribute("data-lexical-slot")) return false;
|
|
10383
|
+
const nearestNode = $getNearestNodeFromDOMNode(activeElement);
|
|
9463
10384
|
const nodeName = activeElement.nodeName;
|
|
9464
|
-
return $
|
|
10385
|
+
return $isLexicalNode(nearestNode) && (nodeName === "INPUT" || nodeName === "TEXTAREA" || activeElement.contentEditable === "true" && getEditorPropertyFromDOMNode(activeElement) == null);
|
|
9465
10386
|
}
|
|
10387
|
+
/** @deprecated renamed to {@link $isSelectionCapturedInDecoratorInput} by @lexical/eslint-plugin rules-of-lexical */
|
|
10388
|
+
const isSelectionCapturedInDecoratorInput = $isSelectionCapturedInDecoratorInput;
|
|
9466
10389
|
function isSelectionWithinEditor(editor, anchorDOM, focusDOM) {
|
|
9467
10390
|
const rootElement = editor.getRootElement();
|
|
10391
|
+
if (!rootElement) return false;
|
|
9468
10392
|
try {
|
|
9469
|
-
|
|
10393
|
+
if (!anchorDOM || !rootElement.contains(anchorDOM) || !rootElement.contains(focusDOM)) return false;
|
|
9470
10394
|
} catch (_error) {
|
|
9471
10395
|
return false;
|
|
9472
10396
|
}
|
|
10397
|
+
return getNearestEditorFromDOMNode(anchorDOM) === editor && editor.read("latest", () => !$isSelectionCapturedInDecoratorInput(anchorDOM));
|
|
9473
10398
|
}
|
|
9474
10399
|
/**
|
|
9475
10400
|
* @returns true if the given argument is a LexicalEditor instance from this build of Lexical
|
|
@@ -9587,7 +10512,7 @@ function internalMarkParentElementsAsDirty(parentKey, nodeMap, dirtyElements) {
|
|
|
9587
10512
|
const node = nodeMap.get(nextParentKey);
|
|
9588
10513
|
if (node === void 0) break;
|
|
9589
10514
|
dirtyElements.set(nextParentKey, false);
|
|
9590
|
-
nextParentKey = node.__parent;
|
|
10515
|
+
nextParentKey = node.__parent !== null ? node.__parent : $isSlotChild(node) ? node.__slotHost : null;
|
|
9591
10516
|
}
|
|
9592
10517
|
}
|
|
9593
10518
|
/**
|
|
@@ -9603,7 +10528,8 @@ function internalMarkParentElementsAsDirty(parentKey, nodeMap, dirtyElements) {
|
|
|
9603
10528
|
* This function is for internal use of the library.
|
|
9604
10529
|
* Please do not use it as it may change in the future.
|
|
9605
10530
|
*/
|
|
9606
|
-
function removeFromParent(node) {
|
|
10531
|
+
function $removeFromParent(node) {
|
|
10532
|
+
if (!($getSlotHostKey(node) === null)) formatDevErrorMessage(`$removeFromParent: node ${node.__key} is slotted into host ${String($getSlotHostKey(node))}; a slotted node and a child are mutually exclusive. Remove it from its slot first.`);
|
|
9607
10533
|
const oldParent = node.getParent();
|
|
9608
10534
|
if (oldParent !== null) {
|
|
9609
10535
|
const writableNode = node.getWritable();
|
|
@@ -9624,11 +10550,13 @@ function removeFromParent(node) {
|
|
|
9624
10550
|
writableParent.__size--;
|
|
9625
10551
|
}
|
|
9626
10552
|
}
|
|
10553
|
+
/** @deprecated renamed to {@link $removeFromParent} by @lexical/eslint-plugin rules-of-lexical */
|
|
10554
|
+
const removeFromParent = $removeFromParent;
|
|
9627
10555
|
function internalMarkNodeAsDirty(node) {
|
|
9628
10556
|
errorOnInfiniteTransforms();
|
|
9629
10557
|
if (!!$isEphemeral(node)) formatDevErrorMessage(`internalMarkNodeAsDirty: Ephemeral nodes must not be marked as dirty (key ${node.__key} type ${node.__type})`);
|
|
9630
10558
|
const latest = node.getLatest();
|
|
9631
|
-
const parent = latest.__parent;
|
|
10559
|
+
const parent = latest.__parent !== null ? latest.__parent : $isSlotChild(latest) ? latest.__slotHost : null;
|
|
9632
10560
|
const editorState = getActiveEditorState();
|
|
9633
10561
|
const editor = getActiveEditor();
|
|
9634
10562
|
const nodeMap = editorState._nodeMap;
|
|
@@ -9665,6 +10593,16 @@ function $getCompositionKey() {
|
|
|
9665
10593
|
if (isCurrentlyReadOnlyMode()) return null;
|
|
9666
10594
|
return getActiveEditor()._compositionKey;
|
|
9667
10595
|
}
|
|
10596
|
+
/**
|
|
10597
|
+
* Returns the node with the given key from the active EditorState
|
|
10598
|
+
* (or the given EditorState), or null if it does not exist.
|
|
10599
|
+
*/
|
|
10600
|
+
/**
|
|
10601
|
+
* @deprecated The type parameter is an unchecked and unsafe cast,
|
|
10602
|
+
* equivalent to `$getNodeByKey(key) as T | null`, and will be removed
|
|
10603
|
+
* in a future release. Call this function without a type argument and
|
|
10604
|
+
* narrow the result with a type guard instead.
|
|
10605
|
+
*/
|
|
9668
10606
|
function $getNodeByKey(key, _editorState) {
|
|
9669
10607
|
const node = (_editorState || getActiveEditorState())._nodeMap.get(key);
|
|
9670
10608
|
if (node === void 0) return null;
|
|
@@ -9679,6 +10617,10 @@ function setNodeKeyOnDOMNode(dom, editor, key) {
|
|
|
9679
10617
|
const prop = `__lexicalKey_${editor._key}`;
|
|
9680
10618
|
dom[prop] = key;
|
|
9681
10619
|
}
|
|
10620
|
+
function clearNodeKeyOnDOMNode(dom, editor) {
|
|
10621
|
+
const prop = `__lexicalKey_${editor._key}`;
|
|
10622
|
+
delete dom[prop];
|
|
10623
|
+
}
|
|
9682
10624
|
function getNodeKeyFromDOMNode(dom, editor) {
|
|
9683
10625
|
return dom[`__lexicalKey_${editor._key}`];
|
|
9684
10626
|
}
|
|
@@ -9728,6 +10670,7 @@ function $setSelection(selection) {
|
|
|
9728
10670
|
if (Object.isFrozen(selection)) formatDevErrorMessage(`$setSelection called on frozen selection object. Ensure selection is cloned before passing in.`);
|
|
9729
10671
|
selection.dirty = true;
|
|
9730
10672
|
selection.setCachedNodes(null);
|
|
10673
|
+
if ($isRangeSelection(selection) && getActiveEditor()._slotsUsed) $clampRangeSelectionToSlotFrame(selection);
|
|
9731
10674
|
}
|
|
9732
10675
|
editorState._selection = selection;
|
|
9733
10676
|
}
|
|
@@ -9736,12 +10679,8 @@ function $flushMutations() {
|
|
|
9736
10679
|
flushRootMutations(getActiveEditor());
|
|
9737
10680
|
}
|
|
9738
10681
|
function $getNodeFromDOM(dom) {
|
|
9739
|
-
const
|
|
9740
|
-
|
|
9741
|
-
if (nodeKey === null) {
|
|
9742
|
-
if (dom === editor.getRootElement()) return $getNodeByKey("root");
|
|
9743
|
-
return null;
|
|
9744
|
-
}
|
|
10682
|
+
const nodeKey = getNodeKeyFromDOMTree(dom, getActiveEditor());
|
|
10683
|
+
if (nodeKey === null) return null;
|
|
9745
10684
|
return $getNodeByKey(nodeKey);
|
|
9746
10685
|
}
|
|
9747
10686
|
function getNodeKeyFromDOMTree(dom, editor) {
|
|
@@ -9776,8 +10715,9 @@ function getAnchorTextFromDOM(anchorNode) {
|
|
|
9776
10715
|
function $updateSelectedTextFromDOM(isCompositionEnd, editor, data) {
|
|
9777
10716
|
const domSelection = getDOMSelection(getWindow(editor));
|
|
9778
10717
|
if (domSelection === null) return;
|
|
9779
|
-
const
|
|
9780
|
-
|
|
10718
|
+
const points = getDOMSelectionPoints(domSelection, editor._rootElement);
|
|
10719
|
+
const anchorNode = points.anchorNode;
|
|
10720
|
+
let { anchorOffset, focusOffset } = points;
|
|
9781
10721
|
if (anchorNode !== null) {
|
|
9782
10722
|
let textContent = getAnchorTextFromDOM(anchorNode);
|
|
9783
10723
|
const node = $getNearestNodeFromDOMNode(anchorNode);
|
|
@@ -9811,13 +10751,15 @@ function $updateTextNodeFromDOMContent(textNode, textContent, anchorOffset, focu
|
|
|
9811
10751
|
}
|
|
9812
10752
|
const prevTextContent = node.getTextContent();
|
|
9813
10753
|
if (compositionEnd || normalizedTextContent !== prevTextContent) {
|
|
10754
|
+
const selection = $getSelection();
|
|
9814
10755
|
if (normalizedTextContent === "") {
|
|
9815
10756
|
$setCompositionKey(null);
|
|
9816
10757
|
if (!IS_SAFARI && !IS_IOS && !IS_APPLE_WEBKIT) {
|
|
9817
10758
|
const editor = getActiveEditor();
|
|
10759
|
+
$setTextContentWithSelection(node, "", selection);
|
|
9818
10760
|
setTimeout(() => {
|
|
9819
10761
|
editor.update(() => {
|
|
9820
|
-
if (node.isAttached()) node.remove();
|
|
10762
|
+
if (node.isAttached() && node.getTextContent() === "") node.remove();
|
|
9821
10763
|
});
|
|
9822
10764
|
}, 20);
|
|
9823
10765
|
} else node.remove();
|
|
@@ -9832,7 +10774,6 @@ function $updateTextNodeFromDOMContent(textNode, textContent, anchorOffset, focu
|
|
|
9832
10774
|
node.markDirty();
|
|
9833
10775
|
return;
|
|
9834
10776
|
}
|
|
9835
|
-
const selection = $getSelection();
|
|
9836
10777
|
if (!$isRangeSelection(selection) || anchorOffset === null || focusOffset === null) {
|
|
9837
10778
|
$setTextContentWithSelection(node, normalizedTextContent, selection);
|
|
9838
10779
|
return;
|
|
@@ -10049,7 +10990,24 @@ function $selectAll(selection) {
|
|
|
10049
10990
|
if ($isRangeSelection(selection)) {
|
|
10050
10991
|
const anchor = selection.anchor;
|
|
10051
10992
|
const focus = selection.focus;
|
|
10052
|
-
const
|
|
10993
|
+
const anchorNode = anchor.getNode();
|
|
10994
|
+
if ($isRootNode(anchorNode)) {
|
|
10995
|
+
anchor.set(anchorNode.getKey(), 0, "element");
|
|
10996
|
+
focus.set(anchorNode.getKey(), anchorNode.getChildrenSize(), "element");
|
|
10997
|
+
$normalizeSelection(selection);
|
|
10998
|
+
return selection;
|
|
10999
|
+
}
|
|
11000
|
+
const topParent = anchorNode.getTopLevelElementOrThrow();
|
|
11001
|
+
const parent = topParent.getParent();
|
|
11002
|
+
if (parent === null) {
|
|
11003
|
+
if ($isElementNode(topParent)) {
|
|
11004
|
+
anchor.set(topParent.getKey(), 0, "element");
|
|
11005
|
+
focus.set(topParent.getKey(), topParent.getChildrenSize(), "element");
|
|
11006
|
+
$normalizeSelection(selection);
|
|
11007
|
+
}
|
|
11008
|
+
return selection;
|
|
11009
|
+
}
|
|
11010
|
+
const rootNode = parent;
|
|
10053
11011
|
anchor.set(rootNode.getKey(), 0, "element");
|
|
10054
11012
|
focus.set(rootNode.getKey(), rootNode.getChildrenSize(), "element");
|
|
10055
11013
|
$normalizeSelection(selection);
|
|
@@ -10090,7 +11048,11 @@ function setMutatedNode(mutatedNodes, registeredNodes, mutationListeners, node,
|
|
|
10090
11048
|
if (prevMutation === void 0 || isMove) mutatedNodesByType.set(nodeKey, isMove ? "updated" : mutation);
|
|
10091
11049
|
}
|
|
10092
11050
|
/**
|
|
10093
|
-
*
|
|
11051
|
+
* Returns all nodes of the given type in the active editor state.
|
|
11052
|
+
*
|
|
11053
|
+
* Consider {@link LexicalEditor.registerMutationListener} with
|
|
11054
|
+
* `skipInitialization: false` instead if you need to track these nodes over
|
|
11055
|
+
* time rather than read them once.
|
|
10094
11056
|
*/
|
|
10095
11057
|
function $nodesOfType(klass) {
|
|
10096
11058
|
const klassType = klass.getType();
|
|
@@ -10147,7 +11109,9 @@ function getElementByKeyOrThrow(editor, key) {
|
|
|
10147
11109
|
}
|
|
10148
11110
|
function getParentElement(node) {
|
|
10149
11111
|
const parentElement = node.assignedSlot || node.parentElement;
|
|
10150
|
-
|
|
11112
|
+
if (parentElement !== null) return parentElement;
|
|
11113
|
+
const parentNode = node.parentNode;
|
|
11114
|
+
return isDOMShadowRoot(parentNode) ? parentNode.host : null;
|
|
10151
11115
|
}
|
|
10152
11116
|
function getDOMOwnerDocument(target) {
|
|
10153
11117
|
return isDOMDocumentNode(target) ? target : isHTMLElement(target) ? target.ownerDocument : null;
|
|
@@ -10246,12 +11210,14 @@ function $isInlineElementOrDecoratorNode(node) {
|
|
|
10246
11210
|
return $isElementNode(node) && node.isInline() || $isDecoratorNode(node) && node.isInline();
|
|
10247
11211
|
}
|
|
10248
11212
|
function $getNearestRootOrShadowRoot(node) {
|
|
10249
|
-
let
|
|
10250
|
-
while (
|
|
11213
|
+
let current = node.getLatest();
|
|
11214
|
+
while (current !== null) {
|
|
11215
|
+
if ($getSlotHostKey(current) !== null && $isElementNode(current)) return current;
|
|
11216
|
+
const parent = current.getParentOrThrow();
|
|
10251
11217
|
if ($isRootOrShadowRoot(parent)) return parent;
|
|
10252
|
-
|
|
11218
|
+
current = parent;
|
|
10253
11219
|
}
|
|
10254
|
-
return
|
|
11220
|
+
return current;
|
|
10255
11221
|
}
|
|
10256
11222
|
function $isRootOrShadowRoot(node) {
|
|
10257
11223
|
return $isRootNode(node) || $isElementNode(node) && node.isShadowRoot();
|
|
@@ -10294,6 +11260,16 @@ function $applyNodeReplacement(node) {
|
|
|
10294
11260
|
function errorOnInsertTextNodeOnRoot(node, insertNode) {
|
|
10295
11261
|
if ($isRootNode(node.getParent()) && !$isElementNode(insertNode) && !$isDecoratorNode(insertNode)) formatDevErrorMessage(`Only element or decorator nodes can be inserted in to the root node`);
|
|
10296
11262
|
}
|
|
11263
|
+
/**
|
|
11264
|
+
* Returns the node with the given key from the active EditorState,
|
|
11265
|
+
* or throws if it does not exist.
|
|
11266
|
+
*/
|
|
11267
|
+
/**
|
|
11268
|
+
* @deprecated The type parameter is an unchecked and unsafe cast,
|
|
11269
|
+
* equivalent to `$getNodeByKeyOrThrow(key) as N`, and will be removed
|
|
11270
|
+
* in a future release. Call this function without a type argument and
|
|
11271
|
+
* narrow the result with a type guard instead.
|
|
11272
|
+
*/
|
|
10297
11273
|
function $getNodeByKeyOrThrow(key) {
|
|
10298
11274
|
const node = $getNodeByKey(key);
|
|
10299
11275
|
if (node === null) formatDevErrorMessage(`Expected node with key ${key} to exist but it's not in the nodeMap.`);
|
|
@@ -10322,7 +11298,7 @@ function removeDOMBlockCursorElement(blockCursorElement, editor, rootElement) {
|
|
|
10322
11298
|
}
|
|
10323
11299
|
function $updateDOMBlockCursorElement(editor, rootElement, nextSelection) {
|
|
10324
11300
|
let blockCursorElement = editor._blockCursorElement;
|
|
10325
|
-
if ($isRangeSelection(nextSelection) && nextSelection.isCollapsed() && nextSelection.anchor.type === "element" && rootElement.contains(
|
|
11301
|
+
if ($isRangeSelection(nextSelection) && nextSelection.isCollapsed() && nextSelection.anchor.type === "element" && rootElement.contains(getActiveElement(rootElement))) {
|
|
10326
11302
|
const anchor = nextSelection.anchor;
|
|
10327
11303
|
const elementNode = anchor.getNode();
|
|
10328
11304
|
const offset = anchor.offset;
|
|
@@ -10372,6 +11348,306 @@ function getDOMSelectionFromTarget(eventTarget) {
|
|
|
10372
11348
|
const defaultView = getDefaultView(eventTarget);
|
|
10373
11349
|
return defaultView ? defaultView.getSelection() : null;
|
|
10374
11350
|
}
|
|
11351
|
+
/**
|
|
11352
|
+
* @param node A value that may be a DOM ShadowRoot.
|
|
11353
|
+
* @returns True if node is a DOM ShadowRoot (an open or closed shadow tree
|
|
11354
|
+
* root), false otherwise. A ShadowRoot is a DocumentFragment with a host.
|
|
11355
|
+
*
|
|
11356
|
+
* @experimental Shape may change as shadow DOM support stabilizes.
|
|
11357
|
+
*/
|
|
11358
|
+
function isDOMShadowRoot(node) {
|
|
11359
|
+
return isDocumentFragment(node) && "host" in node;
|
|
11360
|
+
}
|
|
11361
|
+
/**
|
|
11362
|
+
* Collects the DOM ShadowRoots between `node` and its document, innermost
|
|
11363
|
+
* first. Returns an empty array when `node` is in the light DOM (its root is
|
|
11364
|
+
* the Document) or is detached.
|
|
11365
|
+
*
|
|
11366
|
+
* Uses the standard {@link https://developer.mozilla.org/docs/Web/API/Node/getRootNode | Node.getRootNode}
|
|
11367
|
+
* and `ShadowRoot.host` platform APIs to walk out of any nested shadow trees.
|
|
11368
|
+
*
|
|
11369
|
+
* @param node The DOM node to start from (typically the editor root element).
|
|
11370
|
+
* @returns The enclosing ShadowRoots, innermost first.
|
|
11371
|
+
*
|
|
11372
|
+
* @experimental Shape may change as shadow DOM support stabilizes.
|
|
11373
|
+
*/
|
|
11374
|
+
const EMPTY_SHADOW_ROOTS = [];
|
|
11375
|
+
function getDOMShadowRoots(node) {
|
|
11376
|
+
const root = node.getRootNode();
|
|
11377
|
+
if (root === node || !isDOMShadowRoot(root)) return EMPTY_SHADOW_ROOTS;
|
|
11378
|
+
const shadowRoots = [root];
|
|
11379
|
+
let current = root.host;
|
|
11380
|
+
for (;;) {
|
|
11381
|
+
const nextRoot = current.getRootNode();
|
|
11382
|
+
if (nextRoot === current || !isDOMShadowRoot(nextRoot)) break;
|
|
11383
|
+
shadowRoots.push(nextRoot);
|
|
11384
|
+
current = nextRoot.host;
|
|
11385
|
+
}
|
|
11386
|
+
return shadowRoots;
|
|
11387
|
+
}
|
|
11388
|
+
/**
|
|
11389
|
+
* Walks `root` and every open shadow root nested inside it, yielding each
|
|
11390
|
+
* element that matches `selector`. `querySelectorAll` does not pierce
|
|
11391
|
+
* shadow boundaries on its own; this descent does.
|
|
11392
|
+
*
|
|
11393
|
+
* @internal
|
|
11394
|
+
*/
|
|
11395
|
+
function* findAllLexicalElementsDeep(initialRoot) {
|
|
11396
|
+
const roots = [initialRoot];
|
|
11397
|
+
let root;
|
|
11398
|
+
while (root = roots.pop()) {
|
|
11399
|
+
yield* root.querySelectorAll("[data-lexical-editor=\"true\"]");
|
|
11400
|
+
const walker = (isDOMDocumentNode(root) ? root : root.ownerDocument).createTreeWalker(root, NodeFilter.SHOW_ELEMENT);
|
|
11401
|
+
let el;
|
|
11402
|
+
while (el = walker.nextNode()) if (el.shadowRoot) roots.push(el.shadowRoot);
|
|
11403
|
+
}
|
|
11404
|
+
}
|
|
11405
|
+
/**
|
|
11406
|
+
* Resolves the document that hosts an editor's root element, falling
|
|
11407
|
+
* back to the global `document` when the editor isn't mounted. Use this
|
|
11408
|
+
* over `editor.getRootElement()?.ownerDocument ?? document` so iframe /
|
|
11409
|
+
* shadow-mounted editors land in the right realm.
|
|
11410
|
+
*
|
|
11411
|
+
* @internal
|
|
11412
|
+
*/
|
|
11413
|
+
function getRootOwnerDocument(rootElement) {
|
|
11414
|
+
return rootElement !== null ? rootElement.ownerDocument : document;
|
|
11415
|
+
}
|
|
11416
|
+
/**
|
|
11417
|
+
* A subset of `Selection` covering the four boundary-point fields Lexical
|
|
11418
|
+
* reads plus `direction`. Designed so a `Selection` instance can be returned
|
|
11419
|
+
* where a `DOMSelectionBoundaryPoints` is expected (see {@link getDOMSelectionPoints}).
|
|
11420
|
+
*
|
|
11421
|
+
* `direction` is the standard
|
|
11422
|
+
* {@link https://developer.mozilla.org/docs/Web/API/Selection/direction | Selection.direction}
|
|
11423
|
+
* pass-through: `'forward'` / `'backward'` / `'none'` when the engine
|
|
11424
|
+
* implements it, or `undefined` when a future engine ships
|
|
11425
|
+
* `getComposedRanges` without `direction` (no current shipping
|
|
11426
|
+
* configuration matches — every engine that ships the former also ships
|
|
11427
|
+
* the latter). In the undefined case anchor/focus default to the composed
|
|
11428
|
+
* StaticRange's tree order; callers needing strict backward fidelity
|
|
11429
|
+
* inside a shadow root should check `direction !== undefined`.
|
|
11430
|
+
*
|
|
11431
|
+
* @experimental Shape may change as shadow DOM support stabilizes.
|
|
11432
|
+
*/
|
|
11433
|
+
/**
|
|
11434
|
+
* Resolves a DOM Selection's range through any DOM ShadowRoots enclosing
|
|
11435
|
+
* `rootElement`, using the standard
|
|
11436
|
+
* {@link https://developer.mozilla.org/docs/Web/API/Selection/getComposedRanges | Selection.getComposedRanges}
|
|
11437
|
+
* platform API.
|
|
11438
|
+
*
|
|
11439
|
+
* When a selection is inside a shadow tree the browser retargets
|
|
11440
|
+
* `Selection.getRangeAt`/`anchorNode`/`focusNode` to the shadow host, which
|
|
11441
|
+
* hides the real nodes Lexical needs to resolve. Passing the enclosing shadow
|
|
11442
|
+
* roots to `getComposedRanges` returns the un-retargeted boundary points as a
|
|
11443
|
+
* {@link https://developer.mozilla.org/docs/Web/API/StaticRange | StaticRange}
|
|
11444
|
+
* (in tree order, i.e. start before end).
|
|
11445
|
+
*
|
|
11446
|
+
* @returns The composed StaticRange, or `null` when `rootElement` is in the
|
|
11447
|
+
* light DOM, the platform does not implement `getComposedRanges`, or there
|
|
11448
|
+
* is no selection.
|
|
11449
|
+
*
|
|
11450
|
+
* @experimental Shape may change as shadow DOM support stabilizes.
|
|
11451
|
+
*/
|
|
11452
|
+
function getComposedStaticRange(domSelection, rootElement) {
|
|
11453
|
+
if (rootElement === null || typeof domSelection.getComposedRanges !== "function") return null;
|
|
11454
|
+
const shadowRoots = getDOMShadowRoots(rootElement);
|
|
11455
|
+
if (shadowRoots.length === 0) return null;
|
|
11456
|
+
const getComposedRanges = domSelection.getComposedRanges;
|
|
11457
|
+
try {
|
|
11458
|
+
const dictRange = getComposedRanges.call(domSelection, { shadowRoots })[0];
|
|
11459
|
+
if (dictRange !== void 0) return dictRange;
|
|
11460
|
+
} catch (_error) {}
|
|
11461
|
+
try {
|
|
11462
|
+
const variadicRange = getComposedRanges.apply(domSelection, shadowRoots)[0];
|
|
11463
|
+
if (variadicRange !== void 0) return variadicRange;
|
|
11464
|
+
} catch (_error) {}
|
|
11465
|
+
return null;
|
|
11466
|
+
}
|
|
11467
|
+
/**
|
|
11468
|
+
* Returns a live DOM Range for the Selection, resolved through any DOM
|
|
11469
|
+
* ShadowRoots enclosing `rootElement`. Inside a shadow tree
|
|
11470
|
+
* `Selection.getRangeAt(0)` is retargeted to the shadow host, so this builds a
|
|
11471
|
+
* Range from the composed boundary points instead (see
|
|
11472
|
+
* {@link getComposedStaticRange}); in the light DOM it returns
|
|
11473
|
+
* `getRangeAt(0)` unchanged. Use this instead of `getRangeAt(0)` when the
|
|
11474
|
+
* Range is needed for layout (e.g. `getBoundingClientRect`), which a
|
|
11475
|
+
* StaticRange cannot provide.
|
|
11476
|
+
*
|
|
11477
|
+
* @returns A live Range, or null when the selection has no ranges.
|
|
11478
|
+
*
|
|
11479
|
+
* @experimental Shape may change as shadow DOM support stabilizes.
|
|
11480
|
+
*/
|
|
11481
|
+
function getDOMSelectionRange(domSelection, rootElement) {
|
|
11482
|
+
const staticRange = getComposedStaticRange(domSelection, rootElement);
|
|
11483
|
+
if (staticRange !== null) {
|
|
11484
|
+
const range = staticRangeToLiveRange(staticRange);
|
|
11485
|
+
if (range !== null) return range;
|
|
11486
|
+
}
|
|
11487
|
+
return domSelection.rangeCount > 0 ? domSelection.getRangeAt(0) : null;
|
|
11488
|
+
}
|
|
11489
|
+
/**
|
|
11490
|
+
* Resolves a DOM Selection's anchor/focus boundary points through any DOM
|
|
11491
|
+
* ShadowRoots enclosing `rootElement`. Inside a shadow tree the boundary
|
|
11492
|
+
* points come from {@link getComposedStaticRange} mapped back onto
|
|
11493
|
+
* anchor/focus with the standard
|
|
11494
|
+
* {@link https://developer.mozilla.org/docs/Web/API/Selection/direction | Selection.direction};
|
|
11495
|
+
* in the light DOM (or when `getComposedRanges` is unavailable) the Selection's
|
|
11496
|
+
* own anchorNode/focusNode are already correct, so the Selection is returned
|
|
11497
|
+
* as-is (it satisfies {@link DOMSelectionBoundaryPoints}).
|
|
11498
|
+
*
|
|
11499
|
+
* Use this instead of reading `Selection.anchorNode`/`focusNode` directly,
|
|
11500
|
+
* which are retargeted to the shadow host inside a shadow tree.
|
|
11501
|
+
*
|
|
11502
|
+
* @remarks
|
|
11503
|
+
* The two return paths have different read semantics:
|
|
11504
|
+
* - light DOM: the return aliases `domSelection`, so subsequent reads
|
|
11505
|
+
* reflect any post-call selection changes. The aliasing is intentional;
|
|
11506
|
+
* each `Selection` property read forces a synchronous style/layout
|
|
11507
|
+
* recalculation, so `$updateDOMSelection` defers these reads until they
|
|
11508
|
+
* are actually needed.
|
|
11509
|
+
* - shadow DOM: the return is a snapshot taken at call time, including
|
|
11510
|
+
* `direction`. If a future engine ships `getComposedRanges` without
|
|
11511
|
+
* `Selection.direction` (no current shipping configuration matches),
|
|
11512
|
+
* the snapshot's `direction` is `undefined` and anchor/focus default
|
|
11513
|
+
* to the StaticRange's tree order — a backward selection will appear
|
|
11514
|
+
* forward.
|
|
11515
|
+
*
|
|
11516
|
+
* Read the four points immediately after the call, or compare identity
|
|
11517
|
+
* via `points === domSelection` to detect when the return aliases
|
|
11518
|
+
* `domSelection`, rather than caching the returned reference across
|
|
11519
|
+
* selection mutations.
|
|
11520
|
+
*
|
|
11521
|
+
* @experimental Shape may change as shadow DOM support stabilizes.
|
|
11522
|
+
*/
|
|
11523
|
+
function getDOMSelectionPoints(domSelection, rootElement) {
|
|
11524
|
+
const staticRange = getComposedStaticRange(domSelection, rootElement);
|
|
11525
|
+
if (staticRange === null) return domSelection;
|
|
11526
|
+
return staticRangeToPoints(staticRange, readDirection(domSelection));
|
|
11527
|
+
}
|
|
11528
|
+
/**
|
|
11529
|
+
* Resolves the live DOM Range (for layout reads like `getBoundingClientRect`)
|
|
11530
|
+
* and the anchor/focus boundary points in one pass, sharing a single
|
|
11531
|
+
* {@link getComposedStaticRange} read rather than computing it twice as a
|
|
11532
|
+
* call to {@link getDOMSelectionRange} followed by {@link getDOMSelectionPoints}
|
|
11533
|
+
* would. Use this at sites that need both shapes from the same selection.
|
|
11534
|
+
*
|
|
11535
|
+
* @returns The composed Range plus the boundary points; the Range is null
|
|
11536
|
+
* when the selection has no ranges.
|
|
11537
|
+
*
|
|
11538
|
+
* @experimental Shape may change as shadow DOM support stabilizes.
|
|
11539
|
+
*/
|
|
11540
|
+
function getDOMSelectionRangeAndPoints(domSelection, rootElement) {
|
|
11541
|
+
const staticRange = getComposedStaticRange(domSelection, rootElement);
|
|
11542
|
+
if (staticRange === null) return {
|
|
11543
|
+
points: domSelection,
|
|
11544
|
+
range: domSelection.rangeCount > 0 ? domSelection.getRangeAt(0) : null
|
|
11545
|
+
};
|
|
11546
|
+
const range = staticRangeToLiveRange(staticRange) ?? (domSelection.rangeCount > 0 ? domSelection.getRangeAt(0) : null);
|
|
11547
|
+
return {
|
|
11548
|
+
points: staticRangeToPoints(staticRange, readDirection(domSelection)),
|
|
11549
|
+
range
|
|
11550
|
+
};
|
|
11551
|
+
}
|
|
11552
|
+
function staticRangeToLiveRange(staticRange) {
|
|
11553
|
+
const doc = staticRange.startContainer.ownerDocument;
|
|
11554
|
+
if (doc === null) return null;
|
|
11555
|
+
const range = doc.createRange();
|
|
11556
|
+
try {
|
|
11557
|
+
range.setStart(staticRange.startContainer, staticRange.startOffset);
|
|
11558
|
+
range.setEnd(staticRange.endContainer, staticRange.endOffset);
|
|
11559
|
+
return range;
|
|
11560
|
+
} catch (_error) {
|
|
11561
|
+
return null;
|
|
11562
|
+
}
|
|
11563
|
+
}
|
|
11564
|
+
function staticRangeToPoints(staticRange, direction) {
|
|
11565
|
+
const { startContainer, startOffset, endContainer, endOffset } = staticRange;
|
|
11566
|
+
return direction === "backward" ? {
|
|
11567
|
+
anchorNode: endContainer,
|
|
11568
|
+
anchorOffset: endOffset,
|
|
11569
|
+
direction,
|
|
11570
|
+
focusNode: startContainer,
|
|
11571
|
+
focusOffset: startOffset
|
|
11572
|
+
} : {
|
|
11573
|
+
anchorNode: startContainer,
|
|
11574
|
+
anchorOffset: startOffset,
|
|
11575
|
+
direction,
|
|
11576
|
+
focusNode: endContainer,
|
|
11577
|
+
focusOffset: endOffset
|
|
11578
|
+
};
|
|
11579
|
+
}
|
|
11580
|
+
function readDirection(domSelection) {
|
|
11581
|
+
return domSelection.direction;
|
|
11582
|
+
}
|
|
11583
|
+
/**
|
|
11584
|
+
* Returns the focused element within the same Document or ShadowRoot as
|
|
11585
|
+
* `node`, using the standard `DocumentOrShadowRoot.activeElement`.
|
|
11586
|
+
*
|
|
11587
|
+
* Unlike `document.activeElement` — which is retargeted to the outermost
|
|
11588
|
+
* shadow host when focus is inside a shadow tree — this returns the focused
|
|
11589
|
+
* element within `node`'s own tree (e.g. the editor's contentEditable when it
|
|
11590
|
+
* lives inside a shadow root).
|
|
11591
|
+
*
|
|
11592
|
+
* @param node A node whose tree's active element is wanted.
|
|
11593
|
+
* @returns The active element, or null.
|
|
11594
|
+
*
|
|
11595
|
+
* @experimental Shape may change as shadow DOM support stabilizes.
|
|
11596
|
+
*/
|
|
11597
|
+
function getActiveElement(node) {
|
|
11598
|
+
const root = node.getRootNode();
|
|
11599
|
+
return isDOMDocumentNode(root) || isDOMShadowRoot(root) ? root.activeElement : null;
|
|
11600
|
+
}
|
|
11601
|
+
/**
|
|
11602
|
+
* Descends from `root.activeElement` through nested open ShadowRoots to the
|
|
11603
|
+
* deepest focused element. `document.activeElement` only reports the outermost
|
|
11604
|
+
* shadow host; this walks into the shadow trees via `ShadowRoot.activeElement`
|
|
11605
|
+
* to find the element that actually has focus.
|
|
11606
|
+
*
|
|
11607
|
+
* @param root The Document or ShadowRoot to start from.
|
|
11608
|
+
* @returns The deepest active element, or null.
|
|
11609
|
+
*
|
|
11610
|
+
* @experimental Shape may change as shadow DOM support stabilizes.
|
|
11611
|
+
*/
|
|
11612
|
+
function getActiveElementDeep(root) {
|
|
11613
|
+
let active = root.activeElement;
|
|
11614
|
+
while (active !== null && active.shadowRoot !== null) {
|
|
11615
|
+
const inner = active.shadowRoot.activeElement;
|
|
11616
|
+
if (inner === null) break;
|
|
11617
|
+
active = inner;
|
|
11618
|
+
}
|
|
11619
|
+
return active;
|
|
11620
|
+
}
|
|
11621
|
+
/**
|
|
11622
|
+
* Returns the un-retargeted event target — the real element the user
|
|
11623
|
+
* interacted with — for events observed by a listener above an enclosing
|
|
11624
|
+
* DOM shadow root. `Event.target` is retargeted to the outermost shadow
|
|
11625
|
+
* host in that case, hiding the actual element; `composedPath()[0]`
|
|
11626
|
+
* returns the original target for `composed: true` events (most
|
|
11627
|
+
* user-agent UI events: click, mousedown, pointerdown, focusin, etc.).
|
|
11628
|
+
* Falls back to `event.target` when `composedPath` is unavailable or
|
|
11629
|
+
* returns an empty array (e.g. the event has already finished
|
|
11630
|
+
* dispatching).
|
|
11631
|
+
*
|
|
11632
|
+
* Pairs with the shadow-aware helpers above
|
|
11633
|
+
* ({@link getDOMSelectionPoints}, {@link getActiveElement}) for the
|
|
11634
|
+
* event side of the shadow boundary — useful when an
|
|
11635
|
+
* `Element.contains(target)` check needs to test against an editor root
|
|
11636
|
+
* inside a shadow tree.
|
|
11637
|
+
*
|
|
11638
|
+
* @param event The dispatched event.
|
|
11639
|
+
* @returns The un-retargeted target, or null when the event has none.
|
|
11640
|
+
*
|
|
11641
|
+
* @experimental Shape may change as shadow DOM support stabilizes.
|
|
11642
|
+
*/
|
|
11643
|
+
function getComposedEventTarget(event) {
|
|
11644
|
+
const target = event.target;
|
|
11645
|
+
if (target !== null && isHTMLElement(target) && target.shadowRoot !== null && typeof event.composedPath === "function") {
|
|
11646
|
+
const path = event.composedPath();
|
|
11647
|
+
if (path.length > 0) return path[0];
|
|
11648
|
+
}
|
|
11649
|
+
return target;
|
|
11650
|
+
}
|
|
10375
11651
|
function $splitNode(node, offset) {
|
|
10376
11652
|
let startNode = node.getChildAtIndex(offset);
|
|
10377
11653
|
if (startNode == null) startNode = node;
|
|
@@ -10520,6 +11796,73 @@ function $getDOMSlot(node, dom, editor = $getEditor()) {
|
|
|
10520
11796
|
return slot;
|
|
10521
11797
|
}
|
|
10522
11798
|
/**
|
|
11799
|
+
* @internal
|
|
11800
|
+
*
|
|
11801
|
+
* Returns the scaffolding container element that `host`'s named slot renders
|
|
11802
|
+
* into, or null if the slot is empty or not yet rendered. The container is the
|
|
11803
|
+
* parent of the slotted node's DOM, resolved by key so it is found wherever it
|
|
11804
|
+
* sits — the reconciler parks it as a hidden placeholder in the host DOM, and
|
|
11805
|
+
* an explicit mount ({@link mountSlotContainer}) may relocate it; this lookup
|
|
11806
|
+
* still resolves it after that relocation. Editor-time analog of the
|
|
11807
|
+
* reconciler's internal `$slotContainerForKey`, which resolves the same
|
|
11808
|
+
* container from the reconcile-time DOM map instead of
|
|
11809
|
+
* `editor.getElementByKey`.
|
|
11810
|
+
*/
|
|
11811
|
+
function $getSlotContainer(host, name, editor = $getEditor()) {
|
|
11812
|
+
const slot = $getSlot(host, name);
|
|
11813
|
+
if (slot === null) return null;
|
|
11814
|
+
const slotDom = editor.getElementByKey(slot.getKey());
|
|
11815
|
+
return slotDom !== null ? slotDom.parentElement : null;
|
|
11816
|
+
}
|
|
11817
|
+
/**
|
|
11818
|
+
* @experimental
|
|
11819
|
+
*
|
|
11820
|
+
* Attach a host's named-slot container to `target` and make it visible.
|
|
11821
|
+
* The reconciler renders every slot subtree synchronously into a hidden
|
|
11822
|
+
* (`display: 'none'`) placeholder container parked slots-first in the host
|
|
11823
|
+
* DOM; nothing is visible until the host explicitly attaches the container
|
|
11824
|
+
* somewhere — mirroring how `getDOMSlot` gives an element control over where
|
|
11825
|
+
* its linked-list children render. This helper moves the container into
|
|
11826
|
+
* `target` (a no-op when it is already there, so mounting in place just
|
|
11827
|
+
* reveals it) and clears the inline `display` so the container renders as a
|
|
11828
|
+
* normal block that stylesheets may restyle. It deliberately does NOT use
|
|
11829
|
+
* `display: 'contents'`: Chromium cannot reliably edit inside a boxless
|
|
11830
|
+
* contenteditable subtree (caret hit-testing resolves clicks to a
|
|
11831
|
+
* neighboring box and native text insertion is dropped).
|
|
11832
|
+
*
|
|
11833
|
+
* Idempotent and framework-independent: lexical-react's `useLexicalSlotRef`
|
|
11834
|
+
* wraps it, and a node class or extension can call it directly (e.g. from a
|
|
11835
|
+
* mutation listener) to control slot placement without React.
|
|
11836
|
+
*
|
|
11837
|
+
* @returns the container, or null when the slot (or its DOM) does not exist
|
|
11838
|
+
* yet — e.g. before the host's first reconciliation.
|
|
11839
|
+
*/
|
|
11840
|
+
function mountSlotContainer(editor, nodeKey, slotName, target) {
|
|
11841
|
+
const container = editor.read("latest", () => {
|
|
11842
|
+
const host = $getNodeByKey(nodeKey);
|
|
11843
|
+
return host !== null ? $getSlotContainer(host, slotName, editor) : null;
|
|
11844
|
+
});
|
|
11845
|
+
if (container !== null) {
|
|
11846
|
+
if (container.parentElement !== target) target.appendChild(container);
|
|
11847
|
+
container.style.display = "";
|
|
11848
|
+
}
|
|
11849
|
+
return container;
|
|
11850
|
+
}
|
|
11851
|
+
/**
|
|
11852
|
+
* @experimental
|
|
11853
|
+
*
|
|
11854
|
+
* Reverse of {@link mountSlotContainer}: hide `container` again and park it
|
|
11855
|
+
* back in the host's DOM as the leading hidden placeholder, where the
|
|
11856
|
+
* reconciler manages it. Call when the mount target goes away while the host
|
|
11857
|
+
* remains (e.g. chrome unmount) so the slot subtree stays in the document
|
|
11858
|
+
* instead of leaving with the detached target.
|
|
11859
|
+
*/
|
|
11860
|
+
function unmountSlotContainer(editor, nodeKey, container) {
|
|
11861
|
+
container.style.display = "none";
|
|
11862
|
+
const hostDom = editor.getElementByKey(nodeKey);
|
|
11863
|
+
if (hostDom !== null && container.parentElement !== hostDom) hostDom.insertBefore(container, hostDom.firstChild);
|
|
11864
|
+
}
|
|
11865
|
+
/**
|
|
10523
11866
|
* @experimental
|
|
10524
11867
|
*
|
|
10525
11868
|
* Type guard narrowing a {@link DOMSlot} to an {@link ElementDOMSlot}, which
|
|
@@ -10595,6 +11938,14 @@ function $cloneWithProperties(latestNode) {
|
|
|
10595
11938
|
mutableNode.afterCloneFrom(latestNode);
|
|
10596
11939
|
if (!(mutableNode.__key === latestNode.__key)) formatDevErrorMessage(`$cloneWithProperties: ${constructor.name}.clone(node) (with type '${constructor.getType()}') did not return a node with the same key, make sure to specify node.__key as the last argument to the constructor`);
|
|
10597
11940
|
if (!(mutableNode.__parent === latestNode.__parent && mutableNode.__next === latestNode.__next && mutableNode.__prev === latestNode.__prev)) formatDevErrorMessage(`$cloneWithProperties: ${constructor.name}.clone(node) (with type '${constructor.getType()}') overrode afterCloneFrom but did not call super.afterCloneFrom(prevNode)`);
|
|
11941
|
+
if ($isSlotChild(mutableNode) && $isSlotChild(latestNode)) {
|
|
11942
|
+
if (!(mutableNode.__slotHost === latestNode.__slotHost)) formatDevErrorMessage(`$cloneWithProperties: ${constructor.name}.clone(node) (with type '${constructor.getType()}') overrode afterCloneFrom but did not preserve __slotHost`);
|
|
11943
|
+
}
|
|
11944
|
+
if ($isSlotHost(mutableNode) && $isSlotHost(latestNode)) {
|
|
11945
|
+
const mutSlots = mutableNode.__slots;
|
|
11946
|
+
const latSlots = latestNode.__slots;
|
|
11947
|
+
if (!(mutSlots === latSlots || mutSlots !== null && latSlots !== null && mutSlots.size === latSlots.size && Array.from(mutSlots).every(([k, v]) => latSlots.get(k) === v))) formatDevErrorMessage(`$cloneWithProperties: ${constructor.name}.clone(node) (with type '${constructor.getType()}') overrode afterCloneFrom but did not preserve __slots`);
|
|
11948
|
+
}
|
|
10598
11949
|
return mutableNode;
|
|
10599
11950
|
}
|
|
10600
11951
|
/**
|
|
@@ -10656,15 +12007,25 @@ function $setFormatFromDOM(node, domNode) {
|
|
|
10656
12007
|
return alignment && alignment in ELEMENT_TYPE_TO_FORMAT ? node.setFormat(alignment) : node;
|
|
10657
12008
|
}
|
|
10658
12009
|
/**
|
|
12010
|
+
* Options accepted by {@link setDOMUnmanaged}.
|
|
12011
|
+
*
|
|
12012
|
+
* @experimental
|
|
12013
|
+
*/
|
|
12014
|
+
/**
|
|
10659
12015
|
* Mark this DOM element as unmanaged by lexical's mutation observer (like
|
|
10660
12016
|
* decorator nodes are). Extensions that inject non-lexical decoration
|
|
10661
12017
|
* elements into a node's DOM should mark them so the mutation observer
|
|
10662
12018
|
* doesn't evict them as "unknown DOM children" during cleanup.
|
|
10663
12019
|
*
|
|
12020
|
+
* Pass `{captureSelection: true}` to additionally treat the subtree's
|
|
12021
|
+
* window selection as decorator-like, so resolution does not force-sync
|
|
12022
|
+
* the caret out of unmanaged DOM (see {@link isDOMCapturingSelection}).
|
|
12023
|
+
*
|
|
10664
12024
|
* @experimental
|
|
10665
12025
|
*/
|
|
10666
|
-
function setDOMUnmanaged(elementDom) {
|
|
12026
|
+
function setDOMUnmanaged(elementDom, options) {
|
|
10667
12027
|
elementDom.__lexicalUnmanaged = true;
|
|
12028
|
+
if (options && options.captureSelection !== void 0) elementDom.__lexicalCapturedSelection = options.captureSelection;
|
|
10668
12029
|
}
|
|
10669
12030
|
/**
|
|
10670
12031
|
* True if this DOM node was marked with {@link setDOMUnmanaged}.
|
|
@@ -10675,6 +12036,50 @@ function isDOMUnmanaged(elementDom) {
|
|
|
10675
12036
|
return elementDom.__lexicalUnmanaged === true;
|
|
10676
12037
|
}
|
|
10677
12038
|
/**
|
|
12039
|
+
* Mark a DOM element as a named-slot editable island: set its `contentEditable`
|
|
12040
|
+
* to follow the editor's editable state. A slot rendered inside a non-editable
|
|
12041
|
+
* host (a decorator, or a `contentEditable=false` element shell) does not track
|
|
12042
|
+
* the editor on its own, so its container carries an explicit `contentEditable`;
|
|
12043
|
+
* {@link $fullReconcile} re-applies this when {@link LexicalEditor.setEditable}
|
|
12044
|
+
* toggles. Call it for any other editable island an app attaches itself (e.g. a
|
|
12045
|
+
* `getDOMSlot` children element rendered inside a `contentEditable=false` shell).
|
|
12046
|
+
*
|
|
12047
|
+
* @experimental
|
|
12048
|
+
*/
|
|
12049
|
+
function $markSlotEditable(element, editor = $getEditor()) {
|
|
12050
|
+
const editable = editor.isEditable();
|
|
12051
|
+
element.contentEditable = editable ? "true" : "false";
|
|
12052
|
+
if (editable) element.__lexicalEditor = editor;
|
|
12053
|
+
else delete element.__lexicalEditor;
|
|
12054
|
+
}
|
|
12055
|
+
/**
|
|
12056
|
+
* True if the DOM node sits inside a subtree marked with
|
|
12057
|
+
* `{captureSelection: true}` via {@link setDOMUnmanaged}. Walks ancestors
|
|
12058
|
+
* so any descendant of a marked subtree (e.g. an `<input>` inside a marked
|
|
12059
|
+
* `<div>`) reports as captured too.
|
|
12060
|
+
*
|
|
12061
|
+
* The walk aborts at the first DOM node that corresponds to a Lexical
|
|
12062
|
+
* node in `editor` — that boundary is the implicit owner of the subtree's
|
|
12063
|
+
* selection, so a captureSelection marker above it (in non-Lexical
|
|
12064
|
+
* scaffolding around the editor) does not leak in.
|
|
12065
|
+
*
|
|
12066
|
+
* DecoratorNode DOM is marked with `setDOMUnmanaged({captureSelection:
|
|
12067
|
+
* true})` by the reconciler, so decorator subtrees also report as
|
|
12068
|
+
* captured here.
|
|
12069
|
+
*
|
|
12070
|
+
* @experimental
|
|
12071
|
+
*/
|
|
12072
|
+
function isDOMCapturingSelection(elementDom, editor) {
|
|
12073
|
+
let dom = elementDom;
|
|
12074
|
+
while (dom != null) {
|
|
12075
|
+
if (dom.__lexicalCapturedSelection === true) return true;
|
|
12076
|
+
if (isHTMLElement(dom) && dom.hasAttribute("data-lexical-slot")) return false;
|
|
12077
|
+
if (getNodeKeyFromDOMNode(dom, editor) !== void 0) return false;
|
|
12078
|
+
dom = getParentElement(dom);
|
|
12079
|
+
}
|
|
12080
|
+
return false;
|
|
12081
|
+
}
|
|
12082
|
+
/**
|
|
10678
12083
|
* @internal
|
|
10679
12084
|
*
|
|
10680
12085
|
* Object.hasOwn ponyfill
|
|
@@ -10688,12 +12093,6 @@ function hasOwn(o, k) {
|
|
|
10688
12093
|
function hasOwnStaticMethod(klass, k) {
|
|
10689
12094
|
return hasOwn(klass, k) && klass[k] !== LexicalNode[k];
|
|
10690
12095
|
}
|
|
10691
|
-
/**
|
|
10692
|
-
* @internal
|
|
10693
|
-
*/
|
|
10694
|
-
function hasOwnExportDOM(klass) {
|
|
10695
|
-
return hasOwn(klass.prototype, "exportDOM");
|
|
10696
|
-
}
|
|
10697
12096
|
/** @internal */
|
|
10698
12097
|
function isAbstractNodeClass(klass) {
|
|
10699
12098
|
if (!(klass === LexicalNode || klass.prototype instanceof LexicalNode)) {
|
|
@@ -10709,17 +12108,29 @@ function isAbstractNodeClass(klass) {
|
|
|
10709
12108
|
}
|
|
10710
12109
|
return klass === DecoratorNode || klass === ElementNode || klass === LexicalNode;
|
|
10711
12110
|
}
|
|
12111
|
+
const STATIC_NODE_CONFIG_CACHE = /* @__PURE__ */ new WeakMap();
|
|
10712
12112
|
/** @internal */
|
|
10713
12113
|
function getStaticNodeConfig(klass) {
|
|
10714
|
-
const
|
|
12114
|
+
const cache = STATIC_NODE_CONFIG_CACHE.get(klass);
|
|
12115
|
+
if (cache) return cache;
|
|
12116
|
+
const nodeConfigRecord = klass.prototype != null && PROTOTYPE_CONFIG_METHOD in klass.prototype ? klass.prototype[PROTOTYPE_CONFIG_METHOD]() : void 0;
|
|
10715
12117
|
const isAbstract = isAbstractNodeClass(klass);
|
|
10716
12118
|
const nodeType = !isAbstract && hasOwnStaticMethod(klass, "getType") ? klass.getType() : void 0;
|
|
10717
12119
|
let ownNodeConfig;
|
|
10718
12120
|
let ownNodeType = nodeType;
|
|
10719
12121
|
if (nodeConfigRecord) if (nodeType) ownNodeConfig = nodeConfigRecord[nodeType];
|
|
10720
|
-
else
|
|
10721
|
-
|
|
10722
|
-
|
|
12122
|
+
else {
|
|
12123
|
+
for (const [k, v] of Object.entries(nodeConfigRecord)) {
|
|
12124
|
+
ownNodeType = k;
|
|
12125
|
+
ownNodeConfig = v;
|
|
12126
|
+
}
|
|
12127
|
+
if (!ownNodeConfig) for (const symbolKey of Object.getOwnPropertySymbols(nodeConfigRecord)) {
|
|
12128
|
+
const symbolConfig = nodeConfigRecord[symbolKey];
|
|
12129
|
+
if (symbolConfig) {
|
|
12130
|
+
ownNodeConfig = symbolConfig;
|
|
12131
|
+
break;
|
|
12132
|
+
}
|
|
12133
|
+
}
|
|
10723
12134
|
}
|
|
10724
12135
|
if (!isAbstract && ownNodeType) {
|
|
10725
12136
|
if (!hasOwnStaticMethod(klass, "getType")) klass.getType = () => ownNodeType;
|
|
@@ -10743,10 +12154,53 @@ function getStaticNodeConfig(klass) {
|
|
|
10743
12154
|
if (importDOM) klass.importDOM = () => importDOM;
|
|
10744
12155
|
}
|
|
10745
12156
|
}
|
|
10746
|
-
|
|
12157
|
+
const result = {
|
|
12158
|
+
klass,
|
|
10747
12159
|
ownNodeConfig,
|
|
10748
12160
|
ownNodeType
|
|
10749
12161
|
};
|
|
12162
|
+
STATIC_NODE_CONFIG_CACHE.set(klass, result);
|
|
12163
|
+
return result;
|
|
12164
|
+
}
|
|
12165
|
+
/**
|
|
12166
|
+
* Collect all configuration for this class and its superclasses
|
|
12167
|
+
*
|
|
12168
|
+
* @internal
|
|
12169
|
+
*/
|
|
12170
|
+
function* iterStaticNodeConfigChain(klass) {
|
|
12171
|
+
for (let current = klass; current && (current === LexicalNode || $isLexicalNode(current.prototype));) {
|
|
12172
|
+
const config = getStaticNodeConfig(current);
|
|
12173
|
+
yield config;
|
|
12174
|
+
current = config.ownNodeConfig && config.ownNodeConfig.extends || getSuperclassOf(current);
|
|
12175
|
+
}
|
|
12176
|
+
}
|
|
12177
|
+
/**
|
|
12178
|
+
* Build a map from each registered node type to the set of registered node
|
|
12179
|
+
* types that are it or extend it (including the type itself). For every node
|
|
12180
|
+
* class in `nodes`, its prototype chain is walked and the class's own type is
|
|
12181
|
+
* added to the bucket of each registered ancestor type it inherits from.
|
|
12182
|
+
*
|
|
12183
|
+
* The result lets callers expand a base node type to all of its registered
|
|
12184
|
+
* subclass types up front, so a subclass instance can be matched by type
|
|
12185
|
+
* without a runtime `instanceof`.
|
|
12186
|
+
*
|
|
12187
|
+
* @experimental
|
|
12188
|
+
*/
|
|
12189
|
+
function getRegisteredSubtypeMap(nodes) {
|
|
12190
|
+
const subtypes = /* @__PURE__ */ new Map();
|
|
12191
|
+
const klassByType = /* @__PURE__ */ new Map();
|
|
12192
|
+
for (const klass of nodes) {
|
|
12193
|
+
const { ownNodeType } = getStaticNodeConfig(klass);
|
|
12194
|
+
if (ownNodeType) {
|
|
12195
|
+
klassByType.set(ownNodeType, klass);
|
|
12196
|
+
subtypes.set(ownNodeType, /* @__PURE__ */ new Set());
|
|
12197
|
+
}
|
|
12198
|
+
}
|
|
12199
|
+
for (const [type, klass] of klassByType) for (const { ownNodeType } of iterStaticNodeConfigChain(klass)) {
|
|
12200
|
+
const bucket = ownNodeType && subtypes.get(ownNodeType);
|
|
12201
|
+
if (bucket) bucket.add(type);
|
|
12202
|
+
}
|
|
12203
|
+
return subtypes;
|
|
10750
12204
|
}
|
|
10751
12205
|
/**
|
|
10752
12206
|
* Create an node from its class.
|
|
@@ -10801,6 +12255,362 @@ function $createChildrenArray(element, nodeMap) {
|
|
|
10801
12255
|
return children;
|
|
10802
12256
|
}
|
|
10803
12257
|
/**
|
|
12258
|
+
* Look up the superclass of this class, prefer
|
|
12259
|
+
* {@link iterStaticNodeConfigChain} when implementing loops.
|
|
12260
|
+
*
|
|
12261
|
+
* @internal
|
|
12262
|
+
*/
|
|
12263
|
+
function getSuperclassOf(klass) {
|
|
12264
|
+
const viaStatic = Object.getPrototypeOf(klass);
|
|
12265
|
+
if (typeof viaStatic === "function" && viaStatic !== Function.prototype) return viaStatic;
|
|
12266
|
+
const parentProto = klass.prototype && Object.getPrototypeOf(klass.prototype);
|
|
12267
|
+
return parentProto ? parentProto.constructor : null;
|
|
12268
|
+
}
|
|
12269
|
+
/**
|
|
12270
|
+
* Shared empty slot map. Reads coalesce here when a host's `__slots` is null
|
|
12271
|
+
* (lazy allocation), so non-slot trees don't pay a per-node allocation cost.
|
|
12272
|
+
*
|
|
12273
|
+
* @internal
|
|
12274
|
+
*/
|
|
12275
|
+
const EMPTY_SLOTS = /* @__PURE__ */ new Map();
|
|
12276
|
+
/**
|
|
12277
|
+
* Shape predicate: true when `node` carries the host's `__slots` field — i.e.
|
|
12278
|
+
* it is an {@link ElementNode} or a {@link DecoratorNode}. Narrows to
|
|
12279
|
+
* {@link SlotHostNode} so the mutation helpers' compile-time host requirement
|
|
12280
|
+
* is satisfied. This is a type guard only; the value-level invariant on what
|
|
12281
|
+
* may actually be slotted is enforced by {@link $setSlot} (shadow-root
|
|
12282
|
+
* ElementNode or non-inline DecoratorNode).
|
|
12283
|
+
*
|
|
12284
|
+
* @experimental
|
|
12285
|
+
*/
|
|
12286
|
+
function $isSlotHost(node) {
|
|
12287
|
+
return $isElementNode(node) || $isDecoratorNode(node);
|
|
12288
|
+
}
|
|
12289
|
+
/**
|
|
12290
|
+
* Shape predicate: true when `node` carries the child's `__slotHost` field —
|
|
12291
|
+
* i.e. it is an {@link ElementNode} or a {@link DecoratorNode}. Narrows to
|
|
12292
|
+
* {@link SlotChildNode}. This is a type guard only; {@link $setSlot} rejects
|
|
12293
|
+
* inline values at runtime. The slot link acts as a virtual shadow root, so
|
|
12294
|
+
* any non-inline block — shadow root or not — can occupy a slot.
|
|
12295
|
+
*
|
|
12296
|
+
* @experimental
|
|
12297
|
+
*/
|
|
12298
|
+
function $isSlotChild(node) {
|
|
12299
|
+
return $isElementNode(node) || $isDecoratorNode(node);
|
|
12300
|
+
}
|
|
12301
|
+
/**
|
|
12302
|
+
* Returns the key of the host this node is slotted into, or null when the node
|
|
12303
|
+
* is not slotted. Accepts any node and narrows internally so generic callers
|
|
12304
|
+
* (removal guard, up-walk, GC, caret) don't have to. Exposes a raw key, so it
|
|
12305
|
+
* stays internal to the package; public callers use {@link $getSlotHost}.
|
|
12306
|
+
*
|
|
12307
|
+
* @internal
|
|
12308
|
+
*/
|
|
12309
|
+
function $getSlotHostKey(node) {
|
|
12310
|
+
const latest = node.getLatest();
|
|
12311
|
+
return $isSlotChild(latest) ? latest.__slotHost : null;
|
|
12312
|
+
}
|
|
12313
|
+
/**
|
|
12314
|
+
* Returns the host element when this node occupies one of its named slots,
|
|
12315
|
+
* or null if this node is not slotted. The up-link is kept separate from
|
|
12316
|
+
* {@link LexicalNode.getParent} so the slot boundary behaves like a shadow
|
|
12317
|
+
* root.
|
|
12318
|
+
*
|
|
12319
|
+
* @experimental
|
|
12320
|
+
*/
|
|
12321
|
+
function $getSlotHost(node) {
|
|
12322
|
+
const slotHostKey = $getSlotHostKey(node);
|
|
12323
|
+
if (slotHostKey === null) return null;
|
|
12324
|
+
const host = $getNodeByKey(slotHostKey);
|
|
12325
|
+
if (!($isElementNode(host) || $isDecoratorNode(host))) formatDevErrorMessage(`slotHost must be an ElementNode or a DecoratorNode`);
|
|
12326
|
+
return host;
|
|
12327
|
+
}
|
|
12328
|
+
/**
|
|
12329
|
+
* Returns the slot name this node occupies on its host, or null when the node
|
|
12330
|
+
* is not a slot value. Mirrors {@link LexicalNode#getIndexWithinParent} for
|
|
12331
|
+
* slot children — answers "which named slot does this node sit in?".
|
|
12332
|
+
*
|
|
12333
|
+
* @experimental
|
|
12334
|
+
*/
|
|
12335
|
+
function $getSlotNameWithinHost(slotChild) {
|
|
12336
|
+
const host = $getSlotHost(slotChild);
|
|
12337
|
+
if (host === null) return null;
|
|
12338
|
+
const childKey = slotChild.getLatest().__key;
|
|
12339
|
+
for (const [name, key] of $getSlotMap(host)) if (key === childKey) return name;
|
|
12340
|
+
return null;
|
|
12341
|
+
}
|
|
12342
|
+
/**
|
|
12343
|
+
* Returns the slot value (the "slot frame") whose isolated subtree contains
|
|
12344
|
+
* `node`, or `node` itself when it is a slot value, or null when the node is
|
|
12345
|
+
* not inside any slot. The walk follows `getParent()` and naturally stops at a
|
|
12346
|
+
* slot value because a slotted node's `__parent` is null. Non-slot trees have
|
|
12347
|
+
* `__slotHost === null` everywhere, so this always returns null there.
|
|
12348
|
+
*
|
|
12349
|
+
* Selection-driven exporters use this to find the isolated subtree a
|
|
12350
|
+
* RangeSelection lives in (a selection inside a slot never contains the host,
|
|
12351
|
+
* so a root-children walk alone would miss it).
|
|
12352
|
+
*
|
|
12353
|
+
* @experimental
|
|
12354
|
+
*/
|
|
12355
|
+
function $getSlotFrame(node) {
|
|
12356
|
+
let current = node.getLatest();
|
|
12357
|
+
while (current !== null) {
|
|
12358
|
+
if ($getSlotHostKey(current) !== null) return current;
|
|
12359
|
+
current = current.getParent();
|
|
12360
|
+
}
|
|
12361
|
+
return null;
|
|
12362
|
+
}
|
|
12363
|
+
/**
|
|
12364
|
+
* Returns the latest slot map (name -> child key, insertion order). Exposes raw
|
|
12365
|
+
* keys, so it stays internal to the package; public callers use
|
|
12366
|
+
* {@link $getSlotNames} / {@link $getSlot}.
|
|
12367
|
+
*
|
|
12368
|
+
* @internal
|
|
12369
|
+
*/
|
|
12370
|
+
function $getSlotMap(node) {
|
|
12371
|
+
const latest = node.getLatest();
|
|
12372
|
+
return $isSlotHost(latest) && latest.__slots !== null ? latest.__slots : EMPTY_SLOTS;
|
|
12373
|
+
}
|
|
12374
|
+
/**
|
|
12375
|
+
* Returns the names of this node's occupied slots, in insertion order. Empty
|
|
12376
|
+
* when the node hosts no slots.
|
|
12377
|
+
*
|
|
12378
|
+
* @experimental
|
|
12379
|
+
*/
|
|
12380
|
+
function $getSlotNames(node) {
|
|
12381
|
+
return Array.from($getSlotMap(node).keys());
|
|
12382
|
+
}
|
|
12383
|
+
/**
|
|
12384
|
+
* Slot-name hint for a host node's slot accessors: the names declared in the
|
|
12385
|
+
* host class's `$config().slots` (for editor autocomplete) unioned with `string`
|
|
12386
|
+
* — every string is still accepted (slots take undeclared names at runtime), the
|
|
12387
|
+
* declared names just surface as suggestions. A class declaring no slots, or a
|
|
12388
|
+
* subclass that inherits them without redeclaring, resolves to plain `string`.
|
|
12389
|
+
*
|
|
12390
|
+
* @experimental
|
|
12391
|
+
*/
|
|
12392
|
+
/**
|
|
12393
|
+
* Returns the node occupying the named slot, or null if the slot is empty.
|
|
12394
|
+
* Slots are a shadow-root-isolated channel kept separate from children; see
|
|
12395
|
+
* {@link $getSlotHost} for the reverse up-link.
|
|
12396
|
+
*
|
|
12397
|
+
* @experimental
|
|
12398
|
+
*/
|
|
12399
|
+
function $getSlot(node, name) {
|
|
12400
|
+
const key = $getSlotMap(node).get(name);
|
|
12401
|
+
return key === void 0 ? null : $getNodeByKey(key);
|
|
12402
|
+
}
|
|
12403
|
+
const RESERVED_SLOT_NAMES = [
|
|
12404
|
+
"__proto__",
|
|
12405
|
+
"constructor",
|
|
12406
|
+
"prototype"
|
|
12407
|
+
];
|
|
12408
|
+
const SLOT_MAP_OWNER = Symbol("slotMapOwner");
|
|
12409
|
+
function $getWritableSlots(writableHost) {
|
|
12410
|
+
let slots = writableHost.__slots;
|
|
12411
|
+
if (slots === null || slots[SLOT_MAP_OWNER] !== writableHost) {
|
|
12412
|
+
slots = new Map(slots);
|
|
12413
|
+
slots[SLOT_MAP_OWNER] = writableHost;
|
|
12414
|
+
writableHost.__slots = slots;
|
|
12415
|
+
}
|
|
12416
|
+
return slots;
|
|
12417
|
+
}
|
|
12418
|
+
const slotRankCache = /* @__PURE__ */ new WeakMap();
|
|
12419
|
+
const EMPTY_DECLARED_SLOTS = [];
|
|
12420
|
+
/**
|
|
12421
|
+
* Returns the canonical slot declaration for a node class: the `slots` array
|
|
12422
|
+
* from the nearest {@link StaticNodeConfigValue} in its prototype chain (a
|
|
12423
|
+
* subclass redeclaration overrides its ancestors'), or an empty array when
|
|
12424
|
+
* nothing is declared. The declaration is an ordering vocabulary, not a
|
|
12425
|
+
* schema — occupied names outside it are still valid and sort after the
|
|
12426
|
+
* declared names in code-unit order.
|
|
12427
|
+
*
|
|
12428
|
+
* @experimental named-slots
|
|
12429
|
+
*/
|
|
12430
|
+
function getDeclaredSlots(klass) {
|
|
12431
|
+
for (const { ownNodeConfig } of iterStaticNodeConfigChain(klass)) {
|
|
12432
|
+
const declared = ownNodeConfig && ownNodeConfig.slots;
|
|
12433
|
+
if (declared) return declared;
|
|
12434
|
+
}
|
|
12435
|
+
return EMPTY_DECLARED_SLOTS;
|
|
12436
|
+
}
|
|
12437
|
+
/**
|
|
12438
|
+
* @internal
|
|
12439
|
+
*
|
|
12440
|
+
* Concatenated text of a node's named slots, read slots-first (in slot Map
|
|
12441
|
+
* order). Shared by the getTextContent implementations so ElementNode and
|
|
12442
|
+
* DecoratorNode hosts fold their slot text the same way; a node with no
|
|
12443
|
+
* slots returns the empty string. A free function (not a LexicalNode method)
|
|
12444
|
+
* so the framework-owned name cannot collide with a subclass's own members.
|
|
12445
|
+
*/
|
|
12446
|
+
function $getSlotsTextContent(node) {
|
|
12447
|
+
let textContent = "";
|
|
12448
|
+
for (const name of $getSlotNames(node)) {
|
|
12449
|
+
const slot = $getSlot(node, name);
|
|
12450
|
+
if (slot !== null) textContent += slot.getTextContent();
|
|
12451
|
+
}
|
|
12452
|
+
return textContent;
|
|
12453
|
+
}
|
|
12454
|
+
/**
|
|
12455
|
+
* @internal
|
|
12456
|
+
*
|
|
12457
|
+
* Size counterpart to {@link $getSlotsTextContent}, summing each slot's
|
|
12458
|
+
* getTextContentSize (which a slot subtree may override independently of its
|
|
12459
|
+
* text length) slots-first.
|
|
12460
|
+
*/
|
|
12461
|
+
function $getSlotsTextContentSize(node) {
|
|
12462
|
+
let textContentSize = 0;
|
|
12463
|
+
for (const name of $getSlotNames(node)) {
|
|
12464
|
+
const slot = $getSlot(node, name);
|
|
12465
|
+
if (slot !== null) textContentSize += slot.getTextContentSize();
|
|
12466
|
+
}
|
|
12467
|
+
return textContentSize;
|
|
12468
|
+
}
|
|
12469
|
+
function getDeclaredSlotRank(klass) {
|
|
12470
|
+
let rank = slotRankCache.get(klass);
|
|
12471
|
+
if (rank === void 0) {
|
|
12472
|
+
const declared = getDeclaredSlots(klass);
|
|
12473
|
+
const built = /* @__PURE__ */ new Map();
|
|
12474
|
+
for (const name of declared) {
|
|
12475
|
+
if (!!RESERVED_SLOT_NAMES.includes(name)) formatDevErrorMessage(`getDeclaredSlotRank: ${klass.name} declares reserved slot name "${name}"; __proto__, constructor, and prototype break the plain-object serialization of slots`);
|
|
12476
|
+
if (!!built.has(name)) formatDevErrorMessage(`getDeclaredSlotRank: ${klass.name} declares slot name "${name}" more than once; the canonical order would be ambiguous`);
|
|
12477
|
+
built.set(name, built.size);
|
|
12478
|
+
}
|
|
12479
|
+
rank = built;
|
|
12480
|
+
slotRankCache.set(klass, rank);
|
|
12481
|
+
}
|
|
12482
|
+
return rank;
|
|
12483
|
+
}
|
|
12484
|
+
function compareSlotNames(a, b, rank) {
|
|
12485
|
+
const rankA = rank.get(a);
|
|
12486
|
+
const rankB = rank.get(b);
|
|
12487
|
+
if (rankA !== void 0) return rankB !== void 0 ? rankA - rankB : -1;
|
|
12488
|
+
if (rankB !== void 0) return 1;
|
|
12489
|
+
return a < b ? -1 : a > b ? 1 : 0;
|
|
12490
|
+
}
|
|
12491
|
+
function $canonicalizeSlotOrder(host) {
|
|
12492
|
+
const slots = host.__slots;
|
|
12493
|
+
if (slots === null || slots.size < 2) return;
|
|
12494
|
+
const rank = getDeclaredSlotRank(host.constructor);
|
|
12495
|
+
let previous = null;
|
|
12496
|
+
let sorted = true;
|
|
12497
|
+
for (const name of slots.keys()) {
|
|
12498
|
+
if (previous !== null && compareSlotNames(previous, name, rank) > 0) {
|
|
12499
|
+
sorted = false;
|
|
12500
|
+
break;
|
|
12501
|
+
}
|
|
12502
|
+
previous = name;
|
|
12503
|
+
}
|
|
12504
|
+
if (sorted) return;
|
|
12505
|
+
const entries = Array.from(slots).sort(([a], [b]) => compareSlotNames(a, b, rank));
|
|
12506
|
+
slots.clear();
|
|
12507
|
+
for (const [name, key] of entries) slots.set(name, key);
|
|
12508
|
+
}
|
|
12509
|
+
/**
|
|
12510
|
+
* Places `node` into the named slot of `host`, replacing any existing value
|
|
12511
|
+
* under that name. Move semantics, mirroring `ElementNode.append` /
|
|
12512
|
+
* `insertBefore`: the value is detached from wherever it currently lives —
|
|
12513
|
+
* a child of another element, or a slot on this or another host (a node's two
|
|
12514
|
+
* up-links, `__parent` and `__slotHost`, are mutually exclusive, so it holds
|
|
12515
|
+
* exactly one) — before linking, so re-slotting never requires an explicit
|
|
12516
|
+
* remove first. The replaced value, if any, is detached.
|
|
12517
|
+
*
|
|
12518
|
+
* A slot value must be a non-inline {@link ElementNode} or a non-inline
|
|
12519
|
+
* {@link DecoratorNode}: the slot link itself acts as a virtual shadow root
|
|
12520
|
+
* between the host and the value, so the value does not need to be a shadow
|
|
12521
|
+
* root — a plain block (e.g. a ParagraphNode subclass serving as a
|
|
12522
|
+
* single-line field) is a valid slot value, and selection, traversal, and
|
|
12523
|
+
* editing treat its slot boundary exactly like a shadow-root boundary.
|
|
12524
|
+
*
|
|
12525
|
+
* `host` is constrained to {@link SlotHostNode} so a non-host is rejected at
|
|
12526
|
+
* compile time.
|
|
12527
|
+
*
|
|
12528
|
+
* @experimental
|
|
12529
|
+
*/
|
|
12530
|
+
function $setSlot(host, name, node) {
|
|
12531
|
+
if (!(name !== "__proto__" && name !== "constructor" && name !== "prototype")) formatDevErrorMessage(`$setSlot: "${name}" is a reserved slot name; __proto__, constructor, and prototype break the plain-object serialization of slots`);
|
|
12532
|
+
const latestHost = host.getLatest();
|
|
12533
|
+
if (latestHost.__slots !== null && latestHost.__slots.get(name) === node.getLatest().__key) return latestHost;
|
|
12534
|
+
if (!(($isElementNode(node) || $isDecoratorNode(node)) && !node.isInline())) formatDevErrorMessage(`$setSlot: node ${node.__key} is not a valid slot value; a slot value must be a non-inline ElementNode or DecoratorNode (the slot link itself is the shadow boundary).`);
|
|
12535
|
+
if (!!$isSlotAncestorOrSelf(node, host)) formatDevErrorMessage(`$setSlot: node ${node.__key} cannot be slotted into ${host.__key}; a node may not host itself or an ancestor reached through children or slot up-links — the slot up-link would form a cycle that loops isAttached/GC.`);
|
|
12536
|
+
const writableSelf = host.getWritable();
|
|
12537
|
+
const slots = $getWritableSlots(writableSelf);
|
|
12538
|
+
const previousKey = slots.get(name);
|
|
12539
|
+
if (previousKey !== void 0) $detachSlottedNode(previousKey);
|
|
12540
|
+
const writableNode = node.getWritable();
|
|
12541
|
+
const previousHost = $getSlotHost(writableNode);
|
|
12542
|
+
if (previousHost !== null) {
|
|
12543
|
+
const previousName = $getSlotNameWithinHost(writableNode);
|
|
12544
|
+
if (previousName !== null) $getWritableSlots(previousHost.getWritable()).delete(previousName);
|
|
12545
|
+
writableNode.__slotHost = null;
|
|
12546
|
+
}
|
|
12547
|
+
$removeFromParent(writableNode);
|
|
12548
|
+
writableNode.__slotHost = writableSelf.__key;
|
|
12549
|
+
slots.set(name, writableNode.__key);
|
|
12550
|
+
$canonicalizeSlotOrder(writableSelf);
|
|
12551
|
+
$setSlotsUsed();
|
|
12552
|
+
return writableSelf;
|
|
12553
|
+
}
|
|
12554
|
+
function $setSlotsUsed() {
|
|
12555
|
+
const editor = $getEditor();
|
|
12556
|
+
editor._slotsUsed = true;
|
|
12557
|
+
if (editor._pendingEditorState) editor._pendingEditorState._slotsUsed = true;
|
|
12558
|
+
}
|
|
12559
|
+
/**
|
|
12560
|
+
* Removes the named slot from `host`, detaching its value (its slot up-link is
|
|
12561
|
+
* cleared). No-op if the slot is empty. `host` is constrained to
|
|
12562
|
+
* {@link SlotHostNode} so a non-host is rejected at compile time.
|
|
12563
|
+
*
|
|
12564
|
+
* @experimental
|
|
12565
|
+
*/
|
|
12566
|
+
function $removeSlot(host, name) {
|
|
12567
|
+
const writableSelf = host.getWritable();
|
|
12568
|
+
if (writableSelf.__slots === null) return writableSelf;
|
|
12569
|
+
const previousKey = writableSelf.__slots.get(name);
|
|
12570
|
+
if (previousKey !== void 0) {
|
|
12571
|
+
$detachSlottedNode(previousKey);
|
|
12572
|
+
$getWritableSlots(writableSelf).delete(name);
|
|
12573
|
+
}
|
|
12574
|
+
return writableSelf;
|
|
12575
|
+
}
|
|
12576
|
+
function $isSlotAncestorOrSelf(node, host) {
|
|
12577
|
+
let key = host.__key;
|
|
12578
|
+
while (key !== null) {
|
|
12579
|
+
if (key === node.__key) return true;
|
|
12580
|
+
const current = $getNodeByKey(key);
|
|
12581
|
+
if (current === null) break;
|
|
12582
|
+
key = current.__parent !== null ? current.__parent : $getSlotHostKey(current);
|
|
12583
|
+
}
|
|
12584
|
+
return false;
|
|
12585
|
+
}
|
|
12586
|
+
/**
|
|
12587
|
+
* @internal
|
|
12588
|
+
*
|
|
12589
|
+
* Reverse guard of {@link $setSlot}'s cycle invariant for the children
|
|
12590
|
+
* channel: inserting `child` under `parent` must not close a cycle through a
|
|
12591
|
+
* slot up-link (e.g. `slotValue.append(host)` would make `host.__parent`
|
|
12592
|
+
* reach `slotValue` while `slotValue.__slotHost` reaches `host`, looping
|
|
12593
|
+
* isAttached/GC — and hanging the commit itself). Called from the child
|
|
12594
|
+
* attachment points (ElementNode.splice, insertBefore/insertAfter/replace).
|
|
12595
|
+
* __DEV__-only and gated on the editor slot latch: the up-walk is an O(depth)
|
|
12596
|
+
* cost on the hot children path, and like {@link $setSlot}'s direct guard it
|
|
12597
|
+
* only catches direct local programmer error (collab/JSON can't alias a host
|
|
12598
|
+
* into its own slot value), so production matches the unguarded children
|
|
12599
|
+
* channel's own ancestor-append behavior.
|
|
12600
|
+
*/
|
|
12601
|
+
function $errorOnSlotCycleChild(parent, child) {
|
|
12602
|
+
if (!$getEditor()._slotsUsed) return;
|
|
12603
|
+
if (!!$isSlotAncestorOrSelf(child, parent)) formatDevErrorMessage(`insert: node ${child.__key} cannot become a child of ${parent.__key}; the parent is reachable from the node through slot up-links, so the insertion would form a cycle that loops isAttached/GC.`);
|
|
12604
|
+
}
|
|
12605
|
+
function $detachSlottedNode(slotKey) {
|
|
12606
|
+
const previous = $getNodeByKey(slotKey);
|
|
12607
|
+
if (previous === null) return;
|
|
12608
|
+
const writablePrevious = previous.getWritable();
|
|
12609
|
+
if (!$isSlotChild(writablePrevious)) formatDevErrorMessage(`detach: slotted node ${slotKey} must be an ElementNode or a DecoratorNode`);
|
|
12610
|
+
writablePrevious.__slotHost = null;
|
|
12611
|
+
writablePrevious.remove();
|
|
12612
|
+
}
|
|
12613
|
+
/**
|
|
10804
12614
|
* The direction of a caret, 'next' points towards the end of the document
|
|
10805
12615
|
* and 'previous' points towards the beginning
|
|
10806
12616
|
*/
|
|
@@ -11017,7 +12827,8 @@ function flipDirection(direction) {
|
|
|
11017
12827
|
return FLIP_DIRECTION[direction];
|
|
11018
12828
|
}
|
|
11019
12829
|
function $filterByMode(node, mode = "root") {
|
|
11020
|
-
|
|
12830
|
+
if (node === null || MODE_PREDICATE[mode](node)) return null;
|
|
12831
|
+
return $getSlotHostKey(node) === null ? node : null;
|
|
11021
12832
|
}
|
|
11022
12833
|
var AbstractSiblingCaret = class AbstractSiblingCaret extends AbstractCaret {
|
|
11023
12834
|
type = "sibling";
|
|
@@ -11727,6 +13538,7 @@ function $getBlockMergeTargets(anchor, focus, seenStart) {
|
|
|
11727
13538
|
};
|
|
11728
13539
|
const anchorBlock = $getBlock(anchorElements, INTERNAL_$isBlock);
|
|
11729
13540
|
const focusBlock = anchorBlock && $getBlock(focusElements, (node) => seenStart.has(node.getKey()) && INTERNAL_$isBlock(node));
|
|
13541
|
+
if (focusBlock && $getSlotNames(focusBlock).length > 0) return null;
|
|
11730
13542
|
return anchorBlock && focusBlock ? [anchorBlock, focusBlock] : null;
|
|
11731
13543
|
}
|
|
11732
13544
|
/**
|
|
@@ -11900,6 +13712,30 @@ function $splitAtPointCaretNext(pointCaret, { $copyElementNode = $copyNode, $spl
|
|
|
11900
13712
|
return parentCaret;
|
|
11901
13713
|
}
|
|
11902
13714
|
/**
|
|
13715
|
+
* If the insertion caret is the root/shadow root node (see {@link $isRootOrShadowRoot}),
|
|
13716
|
+
* the node will be inserted there, otherwise the parent nodes will be split according to the
|
|
13717
|
+
* given options.
|
|
13718
|
+
* @param node - The node to be inserted
|
|
13719
|
+
* @param caret - The location to insert or split from
|
|
13720
|
+
* @returns The node after its insertion
|
|
13721
|
+
*/
|
|
13722
|
+
function $insertNodeToNearestRootAtCaret(node, caret, options) {
|
|
13723
|
+
let insertCaret = $getCaretInDirection(caret, "next");
|
|
13724
|
+
if ($isTextPointCaret(insertCaret)) {
|
|
13725
|
+
if (insertCaret.offset === 0) insertCaret = $getSiblingCaret(insertCaret.origin, "previous").getFlipped();
|
|
13726
|
+
else if (insertCaret.offset === insertCaret.origin.getTextContentSize()) insertCaret = $getSiblingCaret(insertCaret.origin, "next");
|
|
13727
|
+
}
|
|
13728
|
+
if (insertCaret.origin.is(node)) {
|
|
13729
|
+
if (!$isSiblingCaret(insertCaret)) formatDevErrorMessage(`$insertNodeToNearestRootAtCaret node ${node.getKey()} of type ${node.getType()} can not be inserted into itself`);
|
|
13730
|
+
insertCaret = $rewindSiblingCaret(insertCaret);
|
|
13731
|
+
}
|
|
13732
|
+
if (node.is(insertCaret.getNodeAtCaret()) || node.is(insertCaret.getFlipped().getNodeAtCaret())) node.remove(true);
|
|
13733
|
+
for (let nextCaret = insertCaret; nextCaret; nextCaret = $splitAtPointCaretNext(nextCaret, options)) insertCaret = nextCaret;
|
|
13734
|
+
if (!!$isTextPointCaret(insertCaret)) formatDevErrorMessage(`$insertNodeToNearestRootAtCaret: An unattached TextNode can not be split`);
|
|
13735
|
+
insertCaret.insert(node.isInline() ? $createParagraphNode().append(node) : node);
|
|
13736
|
+
return $getCaretInDirection($getSiblingCaret(node.getLatest(), "next"), caret.direction);
|
|
13737
|
+
}
|
|
13738
|
+
/**
|
|
11903
13739
|
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
11904
13740
|
*
|
|
11905
13741
|
* This source code is licensed under the MIT license found in the
|
|
@@ -12117,4 +13953,4 @@ function mergeRegister(...func) {
|
|
|
12117
13953
|
};
|
|
12118
13954
|
}
|
|
12119
13955
|
//#endregion
|
|
12120
|
-
export { $addUpdateTag, $applyNodeReplacement, $caretFromPoint, $caretRangeFromSelection, $cloneWithProperties, $cloneWithPropertiesEphemeral, $comparePointCaretNext, $copyNode, $create, $createChildrenArray, $createLineBreakNode, $createNodeSelection, $createParagraphNode, $createPoint, $createRangeSelection, $createRangeSelectionFromDom, $createTabNode, $createTextNode, $extendCaretToRange, $findMatchingParent, $fullReconcile, $generateNodesFromRawText, $getAdjacentChildCaret, $getAdjacentNode, $getAdjacentSiblingOrParentSiblingCaret, $getCaretInDirection, $getCaretRange, $getCaretRangeInDirection, $getCharacterOffsets, $getChildCaret, $getChildCaretAtIndex, $getChildCaretOrSelf, $getCollapsedCaretRange, $getCommonAncestor, $getCommonAncestorResultBranchOrder, $getDOMSlot, $getDOMTextNode, $getEditor, $getEditorDOMRenderConfig, $getNearestNodeFromDOMNode, $getNearestRootOrShadowRoot, $getNodeByKey, $getNodeByKeyOrThrow, $getNodeFromDOMNode, $getPreviousSelection, $getRoot, $getSelection, $getSiblingCaret, $getState, $getStateChange, $getTextContent, $getTextNodeOffset, $getTextPointCaret, $getTextPointCaretSlice, $getWritableNodeState, $hasAncestor, $hasUpdateTag, $insertNodes, $isBlockElementNode, $isChildCaret, $isDecoratorNode, $isEditorState, $isElementDOMSlot, $isElementNode, $isExtendableTextPointCaret, $isInlineElementOrDecoratorNode, $isLeafNode, $isLexicalNode, $isLineBreakNode, $isNodeCaret, $isNodeSelection, $isParagraphNode, $isRangeSelection, $isRootNode, $isRootOrShadowRoot, $isSiblingCaret, $isTabNode, $isTextNode, $isTextPointCaret, $isTextPointCaretSlice, $isTokenOrSegmented, $isTokenOrTab, $nodesOfType, $normalizeCaret, $normalizeSelection as $normalizeSelection__EXPERIMENTAL, $onUpdate, $parseSerializedNode, $removeTextFromCaretRange, $rewindSiblingCaret, $selectAll, $setCompositionKey, $setDirectionFromDOM, $setFormatFromDOM, $setPointFromCaret, $setSelection, $setSelectionFromCaretRange, $setState, $splitAtPointCaretNext, $splitNode, $updateDOMSelection, $updateRangeSelectionFromCaretRange, ArtificialNode__DO_NOT_USE, BEFORE_INPUT_COMMAND, BLUR_COMMAND, CAN_REDO_COMMAND, CAN_UNDO_COMMAND, CAN_USE_BEFORE_INPUT, CAN_USE_DOM, CLEAR_EDITOR_COMMAND, CLEAR_HISTORY_COMMAND, CLICK_COMMAND, COLLABORATION_TAG, COMMAND_PRIORITY_BEFORE_CRITICAL, COMMAND_PRIORITY_BEFORE_EDITOR, COMMAND_PRIORITY_BEFORE_HIGH, COMMAND_PRIORITY_BEFORE_LOW, COMMAND_PRIORITY_BEFORE_NORMAL, COMMAND_PRIORITY_CRITICAL, COMMAND_PRIORITY_EDITOR, COMMAND_PRIORITY_HIGH, COMMAND_PRIORITY_LOW, COMMAND_PRIORITY_NORMAL, COMPOSITION_END_COMMAND, COMPOSITION_END_TAG, COMPOSITION_START_COMMAND, COMPOSITION_START_TAG, CONTROLLED_TEXT_INSERTION_COMMAND, COPY_COMMAND, CUT_COMMAND, DEFAULT_EDITOR_DOM_CONFIG, DELETE_CHARACTER_COMMAND, DELETE_LINE_COMMAND, DELETE_WORD_COMMAND, DRAGEND_COMMAND, DRAGOVER_COMMAND, DRAGSTART_COMMAND, DROP_COMMAND, DecoratorNode, ElementNode, FOCUS_COMMAND, FORMAT_ELEMENT_COMMAND, FORMAT_TEXT_COMMAND, HISTORIC_TAG, HISTORY_MERGE_TAG, HISTORY_PUSH_TAG, INDENT_CONTENT_COMMAND, INPUT_COMMAND, INSERT_LINE_BREAK_COMMAND, INSERT_PARAGRAPH_COMMAND, INSERT_TAB_COMMAND, INTERNAL_$isBlock, IS_ALL_FORMATTING, IS_ANDROID, IS_ANDROID_CHROME, IS_APPLE, IS_APPLE_WEBKIT, IS_BOLD, IS_CHROME, IS_CODE, IS_FIREFOX, IS_HIGHLIGHT, IS_IOS, IS_ITALIC, IS_SAFARI, IS_STRIKETHROUGH, IS_SUBSCRIPT, IS_SUPERSCRIPT, IS_UNDERLINE, KEY_ARROW_DOWN_COMMAND, KEY_ARROW_LEFT_COMMAND, KEY_ARROW_RIGHT_COMMAND, KEY_ARROW_UP_COMMAND, KEY_BACKSPACE_COMMAND, KEY_DELETE_COMMAND, KEY_DOWN_COMMAND, KEY_ENTER_COMMAND, KEY_ESCAPE_COMMAND, KEY_MODIFIER_COMMAND, KEY_SPACE_COMMAND, KEY_TAB_COMMAND, LineBreakNode, MOVE_TO_END, MOVE_TO_START, NODE_STATE_KEY, OUTDENT_CONTENT_COMMAND, PASTE_COMMAND, PASTE_TAG, ParagraphNode, REDO_COMMAND, REMOVE_TEXT_COMMAND, RootNode, SELECTION_CHANGE_COMMAND, SELECTION_INSERT_CLIPBOARD_NODES_COMMAND, SELECT_ALL_COMMAND, SKIP_COLLAB_TAG, SKIP_DOM_SELECTION_TAG, SKIP_SCROLL_INTO_VIEW_TAG, SKIP_SELECTION_FOCUS_TAG, TEXT_TYPE_TO_FORMAT, TabNode, TextNode, UNDO_COMMAND, addClassNamesToElement, buildImportMap, configExtension, createCommand, createEditor, createSharedNodeState, createState, declarePeerDependency, defineExtension, flipDirection, getDOMOwnerDocument, getDOMSelection, getDOMSelectionFromTarget, getDOMTextNode, getEditorPropertyFromDOMNode, getNearestEditorFromDOMNode, getRegisteredNode, getRegisteredNodeOrThrow, getStaticNodeConfig, getStyleObjectFromCSS, getTextDirection, getTransformSetFromKlass, isBlockDomNode, isCurrentlyReadOnlyMode, isDOMDocumentNode, isDOMNode, isDOMTextNode, isDOMUnmanaged, isDocumentFragment, isExactShortcutMatch, isHTMLAnchorElement, isHTMLElement, isHTMLTableCellElement, isHTMLTableRowElement, isInlineDomNode, isLexicalEditor, isModifierMatch, isSelectionCapturedInDecoratorInput, isSelectionWithinEditor, makeStepwiseIterator, mergeRegister, normalizeClassNames, removeClassNamesFromElement, removeFromParent, resetRandomKey, safeCast, setDOMStyleFromCSS, setDOMStyleObject, setDOMUnmanaged, setNodeIndentFromDOM, shallowMergeConfig, stopLexicalPropagation, toggleTextFormatType, tokenizeRawText };
|
|
13956
|
+
export { $addUpdateTag, $applyNodeReplacement, $assumeActiveEditor, $caretFromPoint, $caretRangeFromSelection, $cloneWithProperties, $cloneWithPropertiesEphemeral, $comparePointCaretNext, $copyNode, $create, $createChildrenArray, $createLineBreakNode, $createNodeSelection, $createParagraphNode, $createPoint, $createRangeSelection, $createRangeSelectionFromDom, $createTabNode, $createTextNode, $extendCaretToRange, $findMatchingParent, $fullReconcile, $generateNodesFromRawText, $getAdjacentChildCaret, $getAdjacentNode, $getAdjacentSiblingOrParentSiblingCaret, $getCaretInDirection, $getCaretRange, $getCaretRangeInDirection, $getCharacterOffsets, $getChildCaret, $getChildCaretAtIndex, $getChildCaretOrSelf, $getCollapsedCaretRange, $getCommonAncestor, $getCommonAncestorResultBranchOrder, $getDOMSlot, $getDOMTextNode, $getEditor, $getEditorDOMRenderConfig, $getNearestNodeFromDOMNode, $getNearestRootOrShadowRoot, $getNodeByKey, $getNodeByKeyOrThrow, $getNodeFromDOMNode, $getPreviousSelection, $getRoot, $getSelection, $getSiblingCaret, $getSlot, $getSlotFrame, $getSlotHost, $getSlotNameWithinHost, $getSlotNames, $getState, $getStateChange, $getTextContent, $getTextNodeOffset, $getTextPointCaret, $getTextPointCaretSlice, $getWritableNodeState, $hasAncestor, $hasUpdateTag, $insertNodeToNearestRootAtCaret, $insertNodes, $isBlockElementNode, $isChildCaret, $isDecoratorNode, $isEditorState, $isElementDOMSlot, $isElementNode, $isExtendableTextPointCaret, $isInlineElementOrDecoratorNode, $isLeafNode, $isLexicalNode, $isLineBreakNode, $isNodeCaret, $isNodeSelection, $isParagraphNode, $isRangeSelection, $isRootNode, $isRootOrShadowRoot, $isSelectionCapturedInDecoratorInput, $isSiblingCaret, $isSlotChild, $isSlotHost, $isTabNode, $isTextNode, $isTextPointCaret, $isTextPointCaretSlice, $isTokenOrSegmented, $isTokenOrTab, $markSlotEditable, $nodesOfType, $normalizeCaret, $normalizeSelection as $normalizeSelection__EXPERIMENTAL, $onUpdate, $parseSerializedNode, $removeFromParent, $removeSlot, $removeTextFromCaretRange, $rewindSiblingCaret, $selectAll, $setCompositionKey, $setDirectionFromDOM, $setFormatFromDOM, $setPointFromCaret, $setSelection, $setSelectionFromCaretRange, $setSlot, $setState, $splitAtPointCaretNext, $splitNode, $updateDOMSelection, $updateRangeSelectionFromCaretRange, ArtificialNode__DO_NOT_USE, BEFORE_INPUT_COMMAND, BLUR_COMMAND, CAN_REDO_COMMAND, CAN_UNDO_COMMAND, CAN_USE_BEFORE_INPUT, CAN_USE_DOM, CLEAR_EDITOR_COMMAND, CLEAR_HISTORY_COMMAND, CLICK_COMMAND, COLLABORATION_TAG, COMMAND_PRIORITY_BEFORE_CRITICAL, COMMAND_PRIORITY_BEFORE_EDITOR, COMMAND_PRIORITY_BEFORE_HIGH, COMMAND_PRIORITY_BEFORE_LOW, COMMAND_PRIORITY_BEFORE_NORMAL, COMMAND_PRIORITY_CRITICAL, COMMAND_PRIORITY_EDITOR, COMMAND_PRIORITY_HIGH, COMMAND_PRIORITY_LOW, COMMAND_PRIORITY_NORMAL, COMPOSITION_END_COMMAND, COMPOSITION_END_TAG, COMPOSITION_START_COMMAND, COMPOSITION_START_TAG, CONTROLLED_TEXT_INSERTION_COMMAND, COPY_COMMAND, CUT_COMMAND, CUT_TAG, DEFAULT_EDITOR_DOM_CONFIG, DELETE_CHARACTER_COMMAND, DELETE_LINE_COMMAND, DELETE_WORD_COMMAND, DRAGEND_COMMAND, DRAGOVER_COMMAND, DRAGSTART_COMMAND, DROP_COMMAND, DecoratorNode, ElementNode, FOCUS_COMMAND, FORMAT_ELEMENT_COMMAND, FORMAT_TEXT_COMMAND, HISTORIC_TAG, HISTORY_MERGE_TAG, HISTORY_PUSH_TAG, INDENT_CONTENT_COMMAND, INPUT_COMMAND, INSERT_LINE_BREAK_COMMAND, INSERT_PARAGRAPH_COMMAND, INSERT_TAB_COMMAND, INTERNAL_$isBlock, IS_ALL_FORMATTING, IS_ANDROID, IS_ANDROID_CHROME, IS_APPLE, IS_APPLE_WEBKIT, IS_BOLD, IS_CHROME, IS_CODE, IS_FIREFOX, IS_HIGHLIGHT, IS_IOS, IS_ITALIC, IS_SAFARI, IS_STRIKETHROUGH, IS_SUBSCRIPT, IS_SUPERSCRIPT, IS_UNDERLINE, KEY_ARROW_DOWN_COMMAND, KEY_ARROW_LEFT_COMMAND, KEY_ARROW_RIGHT_COMMAND, KEY_ARROW_UP_COMMAND, KEY_BACKSPACE_COMMAND, KEY_DELETE_COMMAND, KEY_DOWN_COMMAND, KEY_ENTER_COMMAND, KEY_ESCAPE_COMMAND, KEY_MODIFIER_COMMAND, KEY_SPACE_COMMAND, KEY_TAB_COMMAND, LineBreakNode, MOVE_TO_END, MOVE_TO_START, NODE_STATE_DIRECT, NODE_STATE_KEY, NODE_STATE_LATEST, OUTDENT_CONTENT_COMMAND, PASTE_COMMAND, PASTE_TAG, ParagraphNode, REDO_COMMAND, REMOVE_TEXT_COMMAND, RootNode, SELECTION_CHANGE_COMMAND, SELECTION_INSERT_CLIPBOARD_NODES_COMMAND, SELECT_ALL_COMMAND, SKIP_COLLAB_TAG, SKIP_DOM_SELECTION_TAG, SKIP_SCROLL_INTO_VIEW_TAG, SKIP_SELECTION_FOCUS_TAG, TEXT_TYPE_TO_FORMAT, TabNode, TextNode, UNDO_COMMAND, addClassNamesToElement, buildImportMap, configExtension, createCommand, createEditor, createSharedNodeState, createState, declarePeerDependency, defineExtension, findAllLexicalElementsDeep, flipDirection, getActiveElement, getActiveElementDeep, getComposedEventTarget, getComposedStaticRange, getDOMOwnerDocument, getDOMSelection, getDOMSelectionFromTarget, getDOMSelectionPoints, getDOMSelectionRange, getDOMSelectionRangeAndPoints, getDOMShadowRoots, getDOMTextNode, getDeclaredSlots, getEditorPropertyFromDOMNode, getNearestEditorFromDOMNode, getParentElement, getRegisteredNode, getRegisteredNodeOrThrow, getRegisteredSubtypeMap, getRootOwnerDocument, getStaticNodeConfig, getStyleObjectFromCSS, getTextDirection, getTransformSetFromKlass, isBlockDomNode, isCurrentlyReadOnlyMode, isDOMCapturingSelection, isDOMDocumentNode, isDOMNode, isDOMShadowRoot, isDOMTextNode, isDOMUnmanaged, isDocumentFragment, isExactShortcutMatch, isHTMLAnchorElement, isHTMLElement, isHTMLTableCellElement, isHTMLTableRowElement, isInlineDomNode, isLastChildInBlockNode, isLexicalEditor, isModifierMatch, isOnlyChildInBlockNode, isSelectionCapturedInDecoratorInput, isSelectionWithinEditor, iterStaticNodeConfigChain, makeStepwiseIterator, mergeRegister, mountSlotContainer, normalizeClassNames, removeClassNamesFromElement, removeFromParent, resetRandomKey, safeCast, setDOMStyleFromCSS, setDOMStyleObject, setDOMUnmanaged, setNodeIndentFromDOM, shallowMergeConfig, stopLexicalPropagation, toggleTextFormatType, tokenizeRawText, unmountSlotContainer };
|