@mx-space/cli 0.13.1 → 0.13.2

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.
Files changed (58) hide show
  1. package/README.md +59 -0
  2. package/ROADMAP.md +10 -7
  3. package/dist/{Lexical.dev-By5dOKBN.mjs → Lexical.dev-BsbWMhb3.mjs} +2265 -429
  4. package/dist/{Lexical.node-fXM8Jp7p.mjs → Lexical.node-DnR_u_Ke.mjs} +47 -10
  5. package/dist/Lexical.prod-B7L8eVsO.mjs +6816 -0
  6. package/dist/{LexicalClipboard.dev--HxGoSkO.mjs → LexicalClipboard.dev-BGSFbuTA.mjs} +131 -39
  7. package/dist/{LexicalClipboard.node-C3mRbrmW.mjs → LexicalClipboard.node-CUD_tpWb.mjs} +2 -2
  8. package/dist/LexicalClipboard.prod-DQXfRt3h.mjs +429 -0
  9. package/dist/{LexicalCodeCore.dev-DjSrd4A4.mjs → LexicalCodeCore.dev-B9lK_GSN.mjs} +81 -67
  10. package/dist/LexicalCodeCore.prod-CNWMPXhg.mjs +651 -0
  11. package/dist/LexicalDragon.dev-DRm2bGZ1.mjs +186 -0
  12. package/dist/{LexicalDragon.node-BVhw4C7s.mjs → LexicalDragon.node-d8gPruly.mjs} +3 -2
  13. package/dist/LexicalDragon.prod-ey3uKDJF.mjs +121 -0
  14. package/dist/{LexicalExtension.dev-BPNyvGqe.mjs → LexicalExtension.dev-CXtOJb83.mjs} +349 -35
  15. package/dist/{LexicalExtension.node-BVlcrgOx.mjs → LexicalExtension.node-CMsupJZs.mjs} +9 -4
  16. package/dist/{LexicalExtension.prod-DFKbiNt-.mjs → LexicalExtension.prod-BCLGhzcg.mjs} +477 -328
  17. package/dist/{LexicalHeadless.dev-B-cj7Pr5.mjs → LexicalHeadless.dev-yVDOBd64.mjs} +2 -2
  18. package/dist/{LexicalHeadless.prod-Byp1vNzT.mjs → LexicalHeadless.prod-B8qauuEA.mjs} +2 -2
  19. package/dist/{LexicalHtml.dev-prBAwszN.mjs → LexicalHtml.dev-3rdckXIU.mjs} +323 -265
  20. package/dist/{LexicalHtml.node-BvNF96jZ.mjs → LexicalHtml.node-DagZUjQ_.mjs} +6 -4
  21. package/dist/{LexicalHtml.prod-Sz3CW1ht.mjs → LexicalHtml.prod-B5AQaJDb.mjs} +354 -352
  22. package/dist/{LexicalLink.dev-NySTYhVR.mjs → LexicalLink.dev-CspSwLNB.mjs} +69 -58
  23. package/dist/{LexicalLink.prod-BuCM8gts.mjs → LexicalLink.prod-Da-ZW6H5.mjs} +210 -211
  24. package/dist/{LexicalList.dev-DIMOvSFD.mjs → LexicalList.dev-CNXmV6v8.mjs} +246 -198
  25. package/dist/LexicalList.prod-DgQzj4v9.mjs +944 -0
  26. package/dist/{LexicalMarkdown.dev-C7aylvCG.mjs → LexicalMarkdown.dev-0XURdo96.mjs} +129 -37
  27. package/dist/LexicalMarkdown.prod-qUsIQfJx.mjs +932 -0
  28. package/dist/{LexicalRichText.dev-DfICq6lU.mjs → LexicalRichText.dev-BqsEA7I9.mjs} +151 -122
  29. package/dist/{LexicalRichText.node-Bg9jND3Q.mjs → LexicalRichText.node-D73RR0Ck.mjs} +8 -11
  30. package/dist/LexicalRichText.prod-4Atyd7OR.mjs +538 -0
  31. package/dist/{LexicalSelection.dev-DGjj12wW.mjs → LexicalSelection.dev-DK5xfxKP.mjs} +10 -9
  32. package/dist/{LexicalSelection.node-BU5L4193.mjs → LexicalSelection.node-pyZyrANz.mjs} +4 -4
  33. package/dist/{LexicalSelection.prod-D-PwRbyK.mjs → LexicalSelection.prod-C5GrCbDC.mjs} +144 -146
  34. package/dist/{LexicalTable.dev-ChP7cugd.mjs → LexicalTable.dev-DiR_4rdI.mjs} +184 -119
  35. package/dist/LexicalTable.prod-Cbc5EasT.mjs +2336 -0
  36. package/dist/{LexicalUtils.dev-BiFU3789.mjs → LexicalUtils.dev-jhPjn1vQ.mjs} +375 -35
  37. package/dist/{LexicalUtils.node-j3Llm7Y3.mjs → LexicalUtils.node-Ck74ludK.mjs} +24 -12
  38. package/dist/LexicalUtils.prod-nuTBxnk_.mjs +504 -0
  39. package/dist/bin/mxs.mjs +1 -1
  40. package/dist/esm-BumPuCXw.mjs +2 -0
  41. package/dist/{esm-DFrz5rIo.mjs → esm-DupC6TTP.mjs} +214 -179
  42. package/dist/index.d.mts +46 -17
  43. package/dist/index.mjs +1 -1
  44. package/dist/{mxs-DXpzbUf4.mjs → mxs-BgAyMQdq.mjs} +8384 -6209
  45. package/package.json +17 -17
  46. package/skills/commands-ai.md +115 -0
  47. package/skills/overview.md +1 -0
  48. package/dist/Lexical.prod-BlCvXPGa.mjs +0 -6088
  49. package/dist/LexicalClipboard.prod-DNJzFMcT.mjs +0 -371
  50. package/dist/LexicalCodeCore.prod-DTDShkR3.mjs +0 -642
  51. package/dist/LexicalDragon.dev-DwprRH0z.mjs +0 -88
  52. package/dist/LexicalDragon.prod-nh4J-8vn.mjs +0 -59
  53. package/dist/LexicalList.prod-MVqfA6Vo.mjs +0 -925
  54. package/dist/LexicalMarkdown.prod-CfQSM406.mjs +0 -868
  55. package/dist/LexicalRichText.prod-GsFzCK-o.mjs +0 -550
  56. package/dist/LexicalTable.prod-Bpr9YRXp.mjs +0 -2311
  57. package/dist/LexicalUtils.prod-DCvrA78p.mjs +0 -373
  58. package/dist/esm-DXO9Afik.mjs +0 -2
@@ -1,4 +1,4 @@
1
- //#region ../../node_modules/.pnpm/lexical@0.45.0/node_modules/lexical/dist/Lexical.dev.mjs
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
- const after = super.getFirstChildAnchor();
319
- const firstChild = after ? after.nextSibling : this.element.firstChild;
320
- return firstChild !== null && firstChild === $getActiveBlockCursorElement() ? firstChild : after;
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.45.0+dev.esm";
451
+ envLexicalVersion = "0.46.0+dev.esm";
438
452
  } catch (_unused) {}
439
- const LEXICAL_VERSION = envLexicalVersion ?? "0.45.0+source";
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
- let child = node.getFirstChild();
685
- while (child !== null) {
686
- const childKey = child.__key;
687
- if (child.__parent === parentKey) {
688
- if ($isElementNode(child)) $garbageCollectDetachedDeepChildNodes(child, childKey, prevNodeMap, nodeMap, nodeMapDelete, dirtyNodes);
689
- if (!prevNodeMap.has(childKey)) dirtyNodes.delete(childKey);
690
- nodeMapDelete.push(childKey);
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
- nodeMap.delete(nodeKey);
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.getEditorState().read(() => {
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 (domSelection !== null && domSelection.anchorNode === target) {
753
- anchorOffset = domSelection.anchorOffset;
754
- focusOffset = domSelection.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, rootElement) {
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
- } else if (dom === rootElement) return [rootElement, internalGetRoot(editorState)];
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, rootElement);
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 `'latest'`,
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 `'direct'` to read the state from a previous version of the node.
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 'direct' does not
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 'latest' will read the latest version of the node state, 'direct' will read the version that is stored on this LexicalNode which not reflect the version used in the current editor state
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 = "latest") {
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, 'direct')`.
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 `'direct'`
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, "direct");
1037
- const prevValue = $getState(prevNode, stateConfig, "direct");
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 (let klass = typeof nodeConfig === "function" ? nodeConfig : nodeConfig.replace; klass.prototype && klass.prototype.getType !== void 0; klass = Object.getPrototypeOf(klass)) {
1104
- const { ownNodeConfig } = getStaticNodeConfig(klass);
1105
- if (ownNodeConfig && ownNodeConfig.stateConfigs) for (const requiredStateConfig of ownNodeConfig.stateConfigs) {
1106
- let stateConfig;
1107
- if ("stateConfig" in requiredStateConfig) {
1108
- stateConfig = requiredStateConfig.stateConfig;
1109
- if (requiredStateConfig.flat) flatKeys.add(stateConfig.key);
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 = 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) setMutatedNode(mutatedNodes, activeEditorNodes, activeMutationListeners, node, "destroyed");
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.getParentOrThrow();
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 && prevNode.__parent !== node.__parent) {
1883
+ if (prevNode !== void 0) {
1734
1884
  const existingDOM = activePrevKeyToDOMMap.get(key);
1735
1885
  if (existingDOM !== void 0) {
1736
- slot.insertChild(existingDOM);
1737
- return $reconcileNode(key, slot.element);
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)) dom.setAttribute("data-lexical-decorator", "true");
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
- cacheDom.__lexicalTextContent = cachedParentText.slice(0, cachedParentText.length - oldSuffixLength) + newSuffix;
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 newParentText = cachedParentText.slice(0, cachedParentText.length - oldSuffixLength) + newSuffix;
2088
- cacheDom.__lexicalTextContent = newParentText;
2089
- subTreeTextContent = previousSubTreeTextContent + newParentText;
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 rootElementsRegistered = /* @__PURE__ */ new WeakMap();
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
- const domSelection = getDOMSelection(getWindow(editor));
2609
- const domAnchorNode = domSelection !== null ? domSelection.anchorNode : null;
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) || domSelection !== null && domTargetRange !== null && (!domTargetRange.collapsed || domTargetRange.startContainer !== domSelection.anchorNode || domTargetRange.startOffset !== domSelection.anchorOffset) || !anchorNode.isComposing() && (anchorNode.getFormat() !== selection.format || anchorNode.getStyle() !== selection.style) || $shouldInsertTextAfterOrBeforeTextNode(selection, anchorNode);
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" && domSelection.anchorNode === domSelection.focusNode) selection.dirty = true;
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.target;
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 (!$isSelectionCapturedInDecorator(target)) isSelectionChangeFromMouseDown = true;
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
- dispatchCommand(editor, BEFORE_INPUT_COMMAND, event);
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
- if (data != null && $isRangeSelection(selection) && $shouldPreventDefaultAndInsertText(selection, targetRange, data, event.timeStamp, false)) {
2973
- if (isFirefoxEndingComposition) {
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
- if (domSelection === null) return true;
2980
- const isBackward = selection.isBackward();
2981
- const startOffset = isBackward ? selection.anchor.offset : selection.focus.offset;
2982
- const endOffset = isBackward ? selection.focus.offset : selection.anchor.offset;
2983
- if (!CAN_USE_BEFORE_INPUT || selection.isCollapsed() || !$isTextNode(anchorNode) || domSelection.anchorNode === null || anchorNode.getTextContent().slice(0, startOffset) + data + anchorNode.getTextContent().slice(startOffset + endOffset) !== getAnchorTextFromDOM(domSelection.anchorNode)) dispatchCommand(editor, CONTROLLED_TEXT_INSERTION_COMMAND, data);
2984
- const textLength = data.length;
2985
- if (IS_FIREFOX && textLength > 1 && event.inputType === "insertCompositionText" && !editor.isComposing()) {
2986
- selection.anchor.offset -= textLength;
2987
- selection._cachedNodes = null;
2988
- selection._cachedIsBackward = null;
2989
- }
2990
- if (IS_ANDROID_CHROME && editor.isComposing()) {
2991
- lastKeyDownTimeStamp = 0;
2992
- $setCompositionKey(null);
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
- } else {
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 (domSelection !== null && domSelection.anchorNode === textNode) {
3037
- anchorOffset = domSelection.anchorOffset;
3038
- focusOffset = domSelection.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 nextActiveEditor = getNearestEditorFromDOMNode(domSelection.anchorNode);
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
- const documentRootElementsCount = rootElementsRegistered.get(doc) ?? 0;
3204
- if (documentRootElementsCount < 1) doc.addEventListener("selectionchange", onDocumentSelectionChange);
3205
- rootElementsRegistered.set(doc, documentRootElementsCount + 1);
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 documentRootElementsCount = rootElementsRegistered.get(doc);
3244
- if (documentRootElementsCount === void 0) {
3524
+ const registration = documentRegistrations.get(doc);
3525
+ if (registration === void 0) {
3245
3526
  rootElementNotRegisteredWarning();
3246
3527
  return;
3247
3528
  }
3248
- const newCount = documentRootElementsCount - 1;
3529
+ const newCount = registration.rootElementCount - 1;
3249
3530
  if (!(newCount >= 0)) formatDevErrorMessage(`Root element count less than 0`);
3250
3531
  rootElementToDocument.delete(rootElement);
3251
- rootElementsRegistered.set(doc, newCount);
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) return;
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 || Object.getPrototypeOf(this.constructor);
3454
- Object.assign(config, {
3455
- extends: parentKlass,
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 "previous" siblings - that is, the node that comes
3677
- * before this one in the same parent.
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 the "previous" siblings - that is, the nodes that come between
3686
- * this one and the first child of it's parent, inclusive.
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 "next" siblings - that is, the node that comes
3703
- * after this one in the same parent
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 "next" siblings - that is, the nodes that come between this
3712
- * one and the last child of it's parent, inclusive.
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 IMPORTANT_REG_EXP = /\s*!important\s*$/i;
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
- for (let i = 0; i < css.length; i++) {
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 (isParsingValue) currentValue += char;
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 (isParsingValue) currentValue += char;
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 (isParsingValue) currentValue += char;
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 priority = IMPORTANT_REG_EXP.test(value) ? "important" : "";
4430
- const nextValue = priority === "" ? value : value.replace(IMPORTANT_REG_EXP, "").trim();
4431
- domStyle.setProperty(property, nextValue, priority);
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
- setTextContent(text) {
5405
- if (!(text === " " || text === "")) formatDevErrorMessage(`TabNode does not support setTextContent`);
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 = $isRootNode(element) ? $createParagraphNode().append(textNode) : textNode;
5525
- if (placementNode === null) element.append(target);
5526
- else placementNode.insertBefore(target);
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
- if (node.isEmpty()) prevWasElement = false;
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
- let nextSibling = firstNode.getNextSibling();
5855
- if (!$isTextNode(nextSibling) || !nextSibling.canInsertTextBefore() || $isTokenOrSegmented(nextSibling)) {
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
- let prevSibling = firstNode.getPreviousSibling();
5870
- if (!$isTextNode(prevSibling) || $isTokenOrSegmented(prevSibling)) {
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 !== "") {
@@ -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
- if (this.anchor.key === "root") {
6119
- this.insertParagraph();
6120
- const selection = $getSelection();
6121
- if (!$isRangeSelection(selection)) formatDevErrorMessage(`Expected RangeSelection after insertParagraph`);
6122
- return selection.insertNodes(nodes);
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
- if (this.anchor.key === "root") {
6627
+ const anchorNode = this.anchor.getNode();
6628
+ if (this.anchor.type === "element" && $isRootOrShadowRoot(anchorNode)) {
6177
6629
  const paragraph = $createParagraphNode();
6178
- $getRoot().splice(this.anchor.offset, 0, [paragraph]);
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 range = domSelection.getRangeAt(0);
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.anchorNode !== range.startContainer || domSelection.anchorOffset !== range.startOffset) $swapPoints(this);
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 (state.type === "merge-next-block" && (caret.origin.isKeyboardSelectable() || !caret.origin.isInline()) && $isElementNode(initialRange.anchor.origin) && initialRange.anchor.origin.isEmpty()) {
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 !== editor.getRootElement() && !$isSelectionCapturedInDecorator(dom)) dirty = true;
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 index = resolvedElement.getIndexWithinParent();
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 = resolvedElement.getParentOrThrow();
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
- anchorDOM = domSelection.anchorNode;
6807
- focusDOM = domSelection.focusNode;
6808
- anchorOffset = domSelection.anchorOffset;
6809
- focusOffset = domSelection.focusOffset;
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 activeElement = document.activeElement;
6993
- if (tags.has("collaboration") && activeElement !== rootElement || activeElement !== null && isSelectionCapturedInDecoratorInput(activeElement)) return;
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, domSelection.anchorNode, domSelection.focusNode)) domSelection.removeAllRanges();
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) && domSelection.anchorOffset === nextAnchorOffset && domSelection.focusOffset === nextFocusOffset && domSelection.anchorNode === nextAnchorNode && domSelection.focusNode === nextFocusNode) {
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
- if (!tags.has("skip-selection-focus")) rootElement.focus({ preventScroll: true });
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") && (document.activeElement === null || !rootElement.contains(document.activeElement))) rootElement.focus({ preventScroll: true });
7025
- if (!tags.has("skip-scroll-into-view") && nextSelection.isCollapsed() && rootElement !== null && rootElement === document.activeElement) {
7026
- const selectionTarget = $isRangeSelection(nextSelection) && nextSelection.anchor.type === "element" ? nextAnchorNode.childNodes[nextAnchorOffset] || null : domSelection.rangeCount > 0 ? domSelection.getRangeAt(0) : null;
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 instanceof Text) {
7030
- const range = document.createRange();
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
- const isLineBreakNode = $isLineBreakNode(node);
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
- if (isLineBreakNode) continue;
7712
+ const nextNode = nodes[i + 1];
7713
+ if ($isLineBreakNode(node) && (nextNode === void 0 || !$isInlineRunNode(nextNode))) continue;
7139
7714
  }
7140
- if (currentBlock !== null) currentBlock.append(node);
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.querySelectorAll("[contenteditable]")) {
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
- try {
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 = 0;
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(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
- constructor(nodeMap, selection) {
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) prevRootElement.textContent = "";
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
- let currentKlass = klass;
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 !== "function") {
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
  *
@@ -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.parentElement;
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) tags.add(tag);
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
- if (tag != null) tags.add(tag);
9319
- if (!this._updating) $commitPendingUpdates(this);
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. Any pending updates will be flushed immediately before
9337
- * the read.
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
- read(callbackFn) {
9341
- $commitPendingUpdates(this);
9342
- return this.getEditorState().read(callbackFn, { editor: this });
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 $isSelectionCapturedInDecorator(node) {
9458
- return $isDecoratorNode($getNearestNodeFromDOMNode(node));
9459
- }
9460
- function isSelectionCapturedInDecoratorInput(anchorDOM) {
9461
- const activeElement = document.activeElement;
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 $isDecoratorNode($getNearestNodeFromDOMNode(anchorDOM)) && (nodeName === "INPUT" || nodeName === "TEXTAREA" || activeElement.contentEditable === "true" && getEditorPropertyFromDOMNode(activeElement) == null);
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
- return rootElement !== null && rootElement.contains(anchorDOM) && rootElement.contains(focusDOM) && anchorDOM !== null && !isSelectionCapturedInDecoratorInput(anchorDOM) && getNearestEditorFromDOMNode(anchorDOM) === editor;
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 editor = getActiveEditor();
9740
- const nodeKey = getNodeKeyFromDOMTree(dom, editor);
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 anchorNode = domSelection.anchorNode;
9780
- let { anchorOffset, focusOffset } = domSelection;
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 rootNode = anchor.getNode().getTopLevelElementOrThrow().getParentOrThrow();
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
- * @deprecated Use {@link LexicalEditor.registerMutationListener} with `skipInitialization: false` instead.
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
- return isDocumentFragment(parentElement) ? parentElement.host : parentElement;
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 parent = node.getParentOrThrow();
10250
- while (parent !== null) {
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
- parent = parent.getParentOrThrow();
11218
+ current = parent;
10253
11219
  }
10254
- return parent;
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(document.activeElement)) {
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 nodeConfigRecord = PROTOTYPE_CONFIG_METHOD in klass.prototype ? klass.prototype[PROTOTYPE_CONFIG_METHOD]() : void 0;
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 for (const [k, v] of Object.entries(nodeConfigRecord)) {
10721
- ownNodeType = k;
10722
- ownNodeConfig = v;
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
- return {
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
- return MODE_PREDICATE[mode](node) ? null : node;
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 };