@mx-space/cli 0.7.7 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. package/dist/{Lexical.dev-rcxzwpir.mjs → Lexical.dev-By5dOKBN.mjs} +1486 -356
  2. package/dist/{Lexical.node-BUsI9gWr.mjs → Lexical.node-fXM8Jp7p.mjs} +39 -17
  3. package/dist/{Lexical.prod-C8HtkSD6.mjs → Lexical.prod-BlCvXPGa.mjs} +2279 -1768
  4. package/dist/LexicalClipboard.dev--HxGoSkO.mjs +915 -0
  5. package/dist/{LexicalClipboard.node-CO-MCKx5.mjs → LexicalClipboard.node-C3mRbrmW.mjs} +10 -3
  6. package/dist/LexicalClipboard.prod-DNJzFMcT.mjs +371 -0
  7. package/dist/LexicalCodeCore.dev-DjSrd4A4.mjs +1109 -0
  8. package/dist/LexicalCodeCore.prod-DTDShkR3.mjs +642 -0
  9. package/dist/{LexicalDragon.dev-gBP8WSRS.mjs → LexicalDragon.dev-DwprRH0z.mjs} +3 -3
  10. package/dist/{LexicalDragon.node-OG6G55nl.mjs → LexicalDragon.node-BVhw4C7s.mjs} +2 -2
  11. package/dist/{LexicalDragon.prod-DP-_Q8cv.mjs → LexicalDragon.prod-nh4J-8vn.mjs} +3 -3
  12. package/dist/{LexicalExtension.dev-DVbjljrm.mjs → LexicalExtension.dev-BPNyvGqe.mjs} +335 -6
  13. package/dist/{LexicalExtension.node-CF3EAPN7.mjs → LexicalExtension.node-BVlcrgOx.mjs} +15 -8
  14. package/dist/{LexicalExtension.prod-DklHHErZ.mjs → LexicalExtension.prod-DFKbiNt-.mjs} +375 -265
  15. package/dist/{LexicalHeadless.dev-DdWLM7Nl.mjs → LexicalHeadless.dev-B-cj7Pr5.mjs} +2 -2
  16. package/dist/{LexicalHeadless.prod-CoiiTDzR.mjs → LexicalHeadless.prod-Byp1vNzT.mjs} +2 -2
  17. package/dist/LexicalHtml.dev-prBAwszN.mjs +2424 -0
  18. package/dist/LexicalHtml.node-BvNF96jZ.mjs +56 -0
  19. package/dist/LexicalHtml.prod-Sz3CW1ht.mjs +1207 -0
  20. package/dist/{LexicalLink.dev-BS1Bf-yD.mjs → LexicalLink.dev-NySTYhVR.mjs} +42 -8
  21. package/dist/{LexicalLink.prod-B_crkoHP.mjs → LexicalLink.prod-BuCM8gts.mjs} +209 -191
  22. package/dist/{LexicalList.dev-OMqmcnQ-.mjs → LexicalList.dev-DIMOvSFD.mjs} +252 -80
  23. package/dist/{LexicalList.prod-CpL1s8vS.mjs → LexicalList.prod-MVqfA6Vo.mjs} +364 -278
  24. package/dist/{LexicalMarkdown.dev-BHSdx_Gr.mjs → LexicalMarkdown.dev-C7aylvCG.mjs} +729 -552
  25. package/dist/LexicalMarkdown.prod-CfQSM406.mjs +868 -0
  26. package/dist/{LexicalRichText.dev-Bz9A_WbM.mjs → LexicalRichText.dev-DfICq6lU.mjs} +272 -77
  27. package/dist/{LexicalRichText.node-DDpwfE-P.mjs → LexicalRichText.node-Bg9jND3Q.mjs} +21 -8
  28. package/dist/LexicalRichText.prod-GsFzCK-o.mjs +550 -0
  29. package/dist/{LexicalSelection.dev-CQ380fnD.mjs → LexicalSelection.dev-DGjj12wW.mjs} +50 -38
  30. package/dist/{LexicalSelection.node-DesBMjIE.mjs → LexicalSelection.node-BU5L4193.mjs} +4 -4
  31. package/dist/{LexicalSelection.prod-D2jivCDB.mjs → LexicalSelection.prod-D-PwRbyK.mjs} +158 -140
  32. package/dist/{LexicalTable.dev-Ca7mQ7Jk.mjs → LexicalTable.dev-ChP7cugd.mjs} +215 -53
  33. package/dist/{LexicalTable.prod-DyPAcC7y.mjs → LexicalTable.prod-Bpr9YRXp.mjs} +668 -573
  34. package/dist/{LexicalUtils.dev-HxM8F0g6.mjs → LexicalUtils.dev-BiFU3789.mjs} +10 -47
  35. package/dist/{LexicalUtils.node-lCWjRjoG.mjs → LexicalUtils.node-j3Llm7Y3.mjs} +2 -2
  36. package/dist/{LexicalUtils.prod-Bti5w4ki.mjs → LexicalUtils.prod-DCvrA78p.mjs} +103 -105
  37. package/dist/bin/mxs.d.mts +1 -1
  38. package/dist/bin/mxs.mjs +1 -1
  39. package/dist/esm-By7trG9K.mjs +2 -0
  40. package/dist/{esm-CK9m5JKX.mjs → esm-Dg-WhPCe.mjs} +989 -989
  41. package/dist/index.d.mts +22 -2
  42. package/dist/index.mjs +1 -1
  43. package/dist/{mxs-vbxEu09D.mjs → mxs-DT0oYk6U.mjs} +10387 -8278
  44. package/package.json +18 -17
  45. package/dist/LexicalClipboard.dev-BpqRwTLP.mjs +0 -494
  46. package/dist/LexicalClipboard.prod-B_xdeiAC.mjs +0 -291
  47. package/dist/LexicalCodeCore.dev-7_cexm39.mjs +0 -537
  48. package/dist/LexicalCodeCore.prod-Bd6WFHcO.mjs +0 -381
  49. package/dist/LexicalHtml.dev-C3ZSWBFZ.mjs +0 -684
  50. package/dist/LexicalHtml.node-D0TD152E.mjs +0 -24
  51. package/dist/LexicalHtml.prod-CX47X0zl.mjs +0 -430
  52. package/dist/LexicalMarkdown.prod-C-S7Ii6-.mjs +0 -754
  53. package/dist/LexicalRichText.prod-C8qXACDL.mjs +0 -427
  54. package/dist/esm-DRbkkY3r.mjs +0 -2
  55. /package/dist/{mxs-CM8-6uAr.d.mts → mxs-iqJBopvE.d.mts} +0 -0
@@ -1,4 +1,4 @@
1
- //#region ../../node_modules/.pnpm/lexical@0.44.0/node_modules/lexical/Lexical.dev.mjs
1
+ //#region ../../node_modules/.pnpm/lexical@0.45.0/node_modules/lexical/dist/Lexical.dev.mjs
2
2
  /**
3
3
  * Copyright (c) Meta Platforms, Inc. and affiliates.
4
4
  *
@@ -24,13 +24,6 @@ function formatDevErrorMessage(message) {
24
24
  *
25
25
  */
26
26
  const CAN_USE_DOM = typeof window !== "undefined" && typeof window.document !== "undefined" && typeof window.document.createElement !== "undefined";
27
- /**
28
- * Copyright (c) Meta Platforms, Inc. and affiliates.
29
- *
30
- * This source code is licensed under the MIT license found in the
31
- * LICENSE file in the root directory of this source tree.
32
- *
33
- */
34
27
  const documentMode = CAN_USE_DOM && "documentMode" in document ? document.documentMode : null;
35
28
  const IS_APPLE = CAN_USE_DOM && /Mac|iPod|iPhone|iPad/.test(navigator.platform);
36
29
  const IS_FIREFOX = CAN_USE_DOM && /^(?!.*Seamonkey)(?=.*Firefox).*/i.test(navigator.userAgent);
@@ -82,9 +75,8 @@ const NON_BREAKING_SPACE = "\xA0";
82
75
  const COMPOSITION_SUFFIX = IS_SAFARI || IS_IOS || IS_APPLE_WEBKIT ? NON_BREAKING_SPACE : "​";
83
76
  const DOUBLE_LINE_BREAK = "\n\n";
84
77
  const COMPOSITION_START_CHAR = IS_FIREFOX ? NON_BREAKING_SPACE : COMPOSITION_SUFFIX;
85
- const RTL = "֑-߿יִ-﷽ﹰ-ﻼ";
86
78
  const RTL_REGEX = /* @__PURE__ */ new RegExp("^[^A-Za-zÀ-ÖØ-öø-ʸ̀-֐ࠀ-῿‎Ⰰ-﬜︀-﹯﻽-￿]*[֑-߿יִ-﷽ﹰ-ﻼ]");
87
- const LTR_REGEX = new RegExp("^[^" + RTL + "]*[A-Za-zÀ-ÖØ-öø-ʸ̀-֐ࠀ-῿‎Ⰰ-﬜︀-﹯﻽-￿]");
79
+ const LTR_REGEX = /* @__PURE__ */ new RegExp("^[^֑-߿יִ-﷽ﹰ-ﻼ]*[A-Za-zÀ-ÖØ-öø-ʸ̀-֐ࠀ-῿‎Ⰰ-﬜︀-﹯﻽-￿]");
88
80
  const TEXT_TYPE_TO_FORMAT = {
89
81
  bold: 1,
90
82
  capitalize: IS_CAPITALIZE,
@@ -131,6 +123,321 @@ const TEXT_TYPE_TO_MODE = {
131
123
  const NODE_STATE_KEY = "$";
132
124
  const PROTOTYPE_CONFIG_METHOD = "$config";
133
125
  /**
126
+ * The editor has at most one block cursor element
127
+ * ({@link LexicalEditor._blockCursorElement}) — a transient, non-lexical
128
+ * element the selection layer inserts among an ElementNode's children when a
129
+ * collapsed element selection is adjacent to a node that can't host the caret
130
+ * (a block decorator, or a non-empty-capable block). Slots must skip it so it
131
+ * is never mistaken for managed content. There is only ever one, read from the
132
+ * active editor.
133
+ */
134
+ function $getActiveBlockCursorElement() {
135
+ return $getEditor()._blockCursorElement;
136
+ }
137
+ /**
138
+ * Base class for DOM slots — a pointer to the content-bearing element of a
139
+ * node's DOM, plus optional `before` / `after` boundaries marking where the
140
+ * lexical-managed content sits inside that element.
141
+ *
142
+ * For ElementNode children management see {@link ElementDOMSlot}. For
143
+ * non-Element nodes (TextNode, LineBreakNode, DecoratorNode) the slot still
144
+ * supports an internal `before` / `after` so subclasses can prepend or
145
+ * append non-lexical siblings around the content node and the reconciler /
146
+ * `setTextContent` route the actual content through the slot.
147
+ *
148
+ * @experimental
149
+ */
150
+ var DOMSlot = class DOMSlot {
151
+ /** The content-bearing element of the node's DOM. */
152
+ element;
153
+ /** Upper boundary: the lexical-managed range ends before this node. */
154
+ before;
155
+ /** Lower boundary: the lexical-managed range starts after this node. */
156
+ after;
157
+ constructor(element, before, after) {
158
+ this.element = element;
159
+ this.before = before || null;
160
+ this.after = after || null;
161
+ }
162
+ /** Return a new slot with `before` updated. */
163
+ withBefore(before) {
164
+ return new DOMSlot(this.element, before, this.after);
165
+ }
166
+ /** Return a new slot with `after` updated. */
167
+ withAfter(after) {
168
+ return new DOMSlot(this.element, this.before, after);
169
+ }
170
+ /** Return a new slot with `element` updated. */
171
+ withElement(element) {
172
+ if (this.element === element) return this;
173
+ return new DOMSlot(element, this.before, this.after);
174
+ }
175
+ /**
176
+ * Insert the given node before `this.before` (if defined) or append it to
177
+ * `this.element` otherwise. Subclasses may override to respect additional
178
+ * boundaries (e.g. `ElementDOMSlot` also keeps the managed line break at
179
+ * the end).
180
+ */
181
+ insertChild(dom) {
182
+ const before = this.getInsertionAnchor();
183
+ if (!(before === null || before.parentElement === this.element)) formatDevErrorMessage(`DOMSlot.insertChild: before is not in element`);
184
+ this.element.insertBefore(dom, before);
185
+ return this;
186
+ }
187
+ /**
188
+ * Remove the given child from `this.element`. Throws if it was not a child.
189
+ */
190
+ removeChild(dom) {
191
+ if (!(dom.parentElement === this.element)) formatDevErrorMessage(`DOMSlot.removeChild: dom is not in element`);
192
+ this.element.removeChild(dom);
193
+ return this;
194
+ }
195
+ /**
196
+ * Replace `prevDom` with `dom`. Throws if `prevDom` is not a child.
197
+ */
198
+ replaceChild(dom, prevDom) {
199
+ if (!(prevDom.parentElement === this.element)) formatDevErrorMessage(`DOMSlot.replaceChild: prevDom is not in element`);
200
+ this.element.replaceChild(dom, prevDom);
201
+ return this;
202
+ }
203
+ /**
204
+ * Returns the first managed child (the first node in
205
+ * `this.element` that is not a non-lexical prelude / decoration), or
206
+ * `null` if there is none. Subclasses may override to also skip
207
+ * reconciler-managed scaffolding such as the managed line break.
208
+ */
209
+ getFirstChild() {
210
+ const anchor = this.getFirstChildAnchor();
211
+ const firstChild = anchor ? anchor.nextSibling : this.element.firstChild;
212
+ return firstChild === this.getInsertionAnchor() ? null : firstChild;
213
+ }
214
+ /**
215
+ * @internal
216
+ *
217
+ * The leading-boundary counterpart to {@link getInsertionAnchor}: the node
218
+ * the lexical-managed range starts immediately after (its `nextSibling` is
219
+ * the first managed child), or `null` when managed children begin at
220
+ * `this.element.firstChild`. The base slot uses `this.after`; subclasses
221
+ * extend it to skip leading non-lexical scaffolding (e.g. the block cursor).
222
+ */
223
+ getFirstChildAnchor() {
224
+ return this.after;
225
+ }
226
+ /**
227
+ * Map a DOM selection point landing at or inside `leafDOM` (the node's
228
+ * keyed DOM) to whether the caret is positioned BEFORE or AFTER the
229
+ * node in document order. The default implementation derives the
230
+ * boundary from `this.element`'s index inside `leafDOM`:
231
+ *
232
+ * - When `this.element === leafDOM` (no wrap exposed an inner content
233
+ * element via `withElement`): only a DOM caret directly on
234
+ * `leafDOM` at offset 0 counts as "before". Matches the historical
235
+ * decorator rule.
236
+ * - When `this.element !== leafDOM` (wrap pattern that exposed the
237
+ * inner content element via `withElement`, e.g. a `<br>` inside a
238
+ * decoration `<span>`): caret positions at or before the content
239
+ * element are "before", later positions are "after". Handles
240
+ * nested wraps by walking each side up to its top-level child of
241
+ * `leafDOM`.
242
+ *
243
+ * Symmetric with {@link ElementDOMSlot.resolveChildIndex}, which
244
+ * performs the analogous mapping for ElementNode children. Together
245
+ * they let the slot abstraction own all DOM-offset to lexical-offset
246
+ * translation.
247
+ *
248
+ * @internal
249
+ */
250
+ resolveLeafPosition(leafDOM, initialDOM, initialOffset) {
251
+ if (this.element === leafDOM) return initialDOM === leafDOM && initialOffset === 0 ? "before" : "after";
252
+ const innerChild = $topLevelChildOf(leafDOM, this.element);
253
+ if (innerChild === null) return "after";
254
+ const innerIndex = Array.prototype.indexOf.call(leafDOM.childNodes, innerChild);
255
+ if (innerIndex < 0) return "after";
256
+ if (initialDOM === leafDOM) return initialOffset <= innerIndex ? "before" : "after";
257
+ const initialChild = $topLevelChildOf(leafDOM, initialDOM);
258
+ if (initialChild === null) return "after";
259
+ const childIndex = Array.prototype.indexOf.call(leafDOM.childNodes, initialChild);
260
+ return childIndex >= 0 && childIndex <= innerIndex ? "before" : "after";
261
+ }
262
+ /**
263
+ * @internal
264
+ *
265
+ * The node managed children are inserted before, or `null` to append.
266
+ * Subclasses widen this to reserve trailing scaffolding (e.g.
267
+ * {@link ElementDOMSlot} keeps the managed line break last).
268
+ */
269
+ getInsertionAnchor() {
270
+ return this.before;
271
+ }
272
+ };
273
+ function $topLevelChildOf(parent, descendant) {
274
+ let node = descendant;
275
+ while (node !== null && node.parentNode !== parent) node = node.parentNode;
276
+ return node;
277
+ }
278
+ /**
279
+ * A utility class for managing the DOM children of an ElementNode.
280
+ *
281
+ * Extends {@link DOMSlot} with ElementNode-specific scaffolding — the
282
+ * reconciler-managed line break that keeps empty elements selectable, and
283
+ * the offset / index resolution helpers needed when mapping DOM selections
284
+ * onto lexical positions. The base `before` / `after` boundaries and the
285
+ * children mutation helpers (`insertChild`, `removeChild`, …) live on
286
+ * {@link DOMSlot}.
287
+ */
288
+ var ElementDOMSlot = class ElementDOMSlot extends DOMSlot {
289
+ /** Return a new slot with `before` updated, preserving subclass type. */
290
+ withBefore(before) {
291
+ return new ElementDOMSlot(this.element, before, this.after);
292
+ }
293
+ /** Return a new slot with `after` updated, preserving subclass type. */
294
+ withAfter(after) {
295
+ return new ElementDOMSlot(this.element, this.before, after);
296
+ }
297
+ /** Return a new slot with `element` updated, preserving subclass type. */
298
+ withElement(element) {
299
+ if (this.element === element) return this;
300
+ return new ElementDOMSlot(element, this.before, this.after);
301
+ }
302
+ /**
303
+ * @internal
304
+ */
305
+ getInsertionAnchor() {
306
+ return super.getInsertionAnchor() || this.getManagedLineBreak();
307
+ }
308
+ /**
309
+ * @internal
310
+ *
311
+ * Extends the leading boundary to skip the editor's transient block cursor
312
+ * when it sits at the head of the managed range (a collapsed element
313
+ * selection at offset 0), mirroring how {@link getInsertionAnchor} extends
314
+ * the trailing boundary past the managed line break. Only ElementNodes host
315
+ * a block cursor among their children, so the base slot stays editor-free.
316
+ */
317
+ getFirstChildAnchor() {
318
+ const after = super.getFirstChildAnchor();
319
+ const firstChild = after ? after.nextSibling : this.element.firstChild;
320
+ return firstChild !== null && firstChild === $getActiveBlockCursorElement() ? firstChild : after;
321
+ }
322
+ /**
323
+ * @internal
324
+ */
325
+ getManagedLineBreak() {
326
+ return this.element.__lexicalLineBreak || null;
327
+ }
328
+ /** @internal */
329
+ setManagedLineBreak(lineBreakType) {
330
+ const element = this.element;
331
+ element.__lexicalLastChildKind = lineBreakType;
332
+ if (lineBreakType === null) this.removeManagedLineBreak();
333
+ else {
334
+ const webkitHack = lineBreakType === "decorator" && (IS_APPLE_WEBKIT || IS_IOS || IS_SAFARI);
335
+ this.insertManagedLineBreak(webkitHack);
336
+ }
337
+ }
338
+ /** @internal */
339
+ removeManagedLineBreak() {
340
+ const br = this.getManagedLineBreak();
341
+ if (br) {
342
+ const element = this.element;
343
+ const sibling = br.nodeName === "IMG" ? br.nextSibling : null;
344
+ if (sibling) element.removeChild(sibling);
345
+ element.removeChild(br);
346
+ element.__lexicalLineBreak = void 0;
347
+ }
348
+ }
349
+ /** @internal */
350
+ insertManagedLineBreak(webkitHack) {
351
+ const prevBreak = this.getManagedLineBreak();
352
+ if (prevBreak) {
353
+ if (webkitHack === (prevBreak.nodeName === "IMG")) return;
354
+ this.removeManagedLineBreak();
355
+ }
356
+ const element = this.element;
357
+ const before = this.before;
358
+ const br = document.createElement("br");
359
+ element.insertBefore(br, before);
360
+ if (webkitHack) {
361
+ const img = document.createElement("img");
362
+ img.setAttribute("data-lexical-linebreak", "true");
363
+ img.style.setProperty("display", "inline", "important");
364
+ img.style.setProperty("border", "0px", "important");
365
+ img.style.setProperty("margin", "0px", "important");
366
+ img.alt = "";
367
+ element.insertBefore(img, br);
368
+ element.__lexicalLineBreak = img;
369
+ } else element.__lexicalLineBreak = br;
370
+ }
371
+ /**
372
+ * @internal
373
+ *
374
+ * The DOM child index at which the first managed child appears — i.e. the
375
+ * count of leading non-lexical nodes (the `this.after` region, plus the
376
+ * block cursor when it sits at the head). Walks forward from the start,
377
+ * stopping at the first managed child, or at the trailing boundary
378
+ * (`this.before` / the managed line break via {@link getInsertionAnchor})
379
+ * when there are no managed children.
380
+ */
381
+ getFirstChildOffset() {
382
+ const firstChild = this.getFirstChild();
383
+ const insertionAnchor = this.getInsertionAnchor();
384
+ let i = 0;
385
+ for (let node = this.element.firstChild; node !== null && node !== firstChild && node !== insertionAnchor; node = node.nextSibling) i++;
386
+ return i;
387
+ }
388
+ /**
389
+ * @internal
390
+ */
391
+ resolveChildIndex(element, elementDOM, initialDOM, initialOffset) {
392
+ if (initialDOM === this.element) {
393
+ const firstChildOffset = this.getFirstChildOffset();
394
+ const blockCursor = $getActiveBlockCursorElement();
395
+ const childNodes = this.element.childNodes;
396
+ const limit = Math.min(initialOffset, childNodes.length);
397
+ let idx = 0;
398
+ for (let i = firstChildOffset; i < limit; i++) if (childNodes[i] !== blockCursor) idx++;
399
+ return [element, Math.min(idx, element.getChildrenSize())];
400
+ }
401
+ const initialPath = indexPath(elementDOM, initialDOM);
402
+ initialPath.push(initialOffset);
403
+ const elementPath = indexPath(elementDOM, this.element);
404
+ let offset = element.getIndexWithinParent();
405
+ for (let i = 0; i < elementPath.length; i++) {
406
+ const target = initialPath[i];
407
+ const source = elementPath[i];
408
+ if (target === void 0 || target < source) break;
409
+ else if (target > source) {
410
+ offset += 1;
411
+ break;
412
+ }
413
+ }
414
+ return [element.getParentOrThrow(), offset];
415
+ }
416
+ };
417
+ function indexPath(root, child) {
418
+ const path = [];
419
+ let node = child;
420
+ for (; node !== root && node !== null; node = node.parentNode) {
421
+ let i = 0;
422
+ for (let sibling = node.previousSibling; sibling !== null; sibling = sibling.previousSibling) i++;
423
+ path.push(i);
424
+ }
425
+ if (!(node === root)) formatDevErrorMessage(`indexPath: root is not a parent of child`);
426
+ return path.reverse();
427
+ }
428
+ /**
429
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
430
+ *
431
+ * This source code is licensed under the MIT license found in the
432
+ * LICENSE file in the root directory of this source tree.
433
+ *
434
+ */
435
+ let envLexicalVersion;
436
+ try {
437
+ envLexicalVersion = "0.45.0+dev.esm";
438
+ } catch (_unused) {}
439
+ const LEXICAL_VERSION = envLexicalVersion ?? "0.45.0+source";
440
+ /**
134
441
  * Copyright (c) Meta Platforms, Inc. and affiliates.
135
442
  *
136
443
  * This source code is licensed under the MIT license found in the
@@ -178,6 +485,191 @@ var DequeSet = class {
178
485
  * LICENSE file in the root directory of this source tree.
179
486
  *
180
487
  */
488
+ const TOMBSTONE = null;
489
+ const GEN_MAP_SIZE_THRESHOLD = 1e3;
490
+ /**
491
+ * @internal
492
+ *
493
+ * Create a copy of the given Map, returning either a fresh Map or a clone
494
+ * of a copy-on-write GenMap depending on the source type and size.
495
+ *
496
+ * - If the source is already a GenMap, returns `map.clone()` (O(1)).
497
+ * - If the source is a plain Map below the threshold, returns
498
+ * `new Map(map)` to avoid the GenMap overhead on small docs.
499
+ * - Otherwise wraps a fresh GenMap around the source.
500
+ */
501
+ function cloneMap(map, minGenMapSize = GEN_MAP_SIZE_THRESHOLD) {
502
+ if (map instanceof GenMap) return map.clone();
503
+ if (map.size < minGenMapSize) return new Map(map);
504
+ return new GenMap().init(new Map(map), void 0, map.size);
505
+ }
506
+ /**
507
+ * @internal
508
+ *
509
+ * A copy-on-write Map suitable for cloning large collections cheaply.
510
+ *
511
+ * Before being written to, a GenMap shares its `_old` and `_nursery` Maps
512
+ * with the GenMap it was cloned from. On first write it either compacts
513
+ * (folds `_nursery` into a new `_old`) or shallow-copies `_nursery`,
514
+ * isolating subsequent writes from sibling clones.
515
+ *
516
+ * `_old` is the immutable snapshot from the most recent compaction;
517
+ * `_nursery` holds writes since the last compaction (deletions stored as
518
+ * `TOMBSTONE`). `_mutable` tracks whether `_nursery` may be written to
519
+ * directly or must first be cloned.
520
+ *
521
+ * Implements the full `Map<K, V>` interface; methods not documented
522
+ * individually behave as their native `Map` counterparts.
523
+ */
524
+ var GenMap = class GenMap {
525
+ _mutable = false;
526
+ _old = void 0;
527
+ _nursery = void 0;
528
+ _size = 0;
529
+ /**
530
+ * Returns a new GenMap that initially shares `_old` and `_nursery`
531
+ * with this one. Marks both as not-mutable so the next write on either
532
+ * side triggers a copy-on-write of the nursery before mutating.
533
+ */
534
+ clone() {
535
+ this._mutable = false;
536
+ return new GenMap().init(this._old, this._nursery, this._size);
537
+ }
538
+ init(old, nursery, size) {
539
+ this._old = old;
540
+ this._nursery = nursery;
541
+ this._size = size;
542
+ return this;
543
+ }
544
+ get size() {
545
+ return this._size;
546
+ }
547
+ has(key) {
548
+ return this.get(key) !== void 0;
549
+ }
550
+ /**
551
+ * Returns the raw value for `key`, including TOMBSTONE for keys deleted
552
+ * since the last compaction. Used internally to distinguish "missing"
553
+ * from "deleted" without doing a second lookup.
554
+ */
555
+ getWithTombstone(key) {
556
+ const v = this._nursery && this._nursery.get(key);
557
+ if (v !== void 0) return v;
558
+ return this._old && this._old.get(key);
559
+ }
560
+ get(key) {
561
+ const v = this.getWithTombstone(key);
562
+ return v === TOMBSTONE ? void 0 : v;
563
+ }
564
+ shouldCompact() {
565
+ return this._nursery !== void 0 && this._nursery.size * 2 > this._size;
566
+ }
567
+ /**
568
+ * Returns the nursery for in-place writes. If this GenMap is currently
569
+ * sharing its nursery with an ancestor clone, this either compacts (if
570
+ * the nursery has grown large enough) or makes a shallow copy.
571
+ */
572
+ getNursery() {
573
+ if (!this._mutable || !this._nursery) {
574
+ this.compact();
575
+ this._nursery = new Map(this._nursery);
576
+ this._mutable = true;
577
+ }
578
+ return this._nursery;
579
+ }
580
+ /**
581
+ * Fold the nursery into a new `_old` snapshot when it has grown large
582
+ * enough that lookup overhead outweighs the savings from sharing.
583
+ * Triggered automatically from `getNursery` once `_nursery.size * 2 >
584
+ * _size`; can be forced via `compact(true)`.
585
+ */
586
+ compact(force = false) {
587
+ if (this._nursery && this._nursery.size > 0 && (force || this.shouldCompact())) {
588
+ const compact = new Map(this._old);
589
+ for (const [k, v] of this._nursery) if (v !== TOMBSTONE) compact.set(k, v);
590
+ else compact.delete(k);
591
+ this._old = compact;
592
+ this._nursery = void 0;
593
+ }
594
+ this._mutable = false;
595
+ return this;
596
+ }
597
+ set(key, value) {
598
+ const v = this.getWithTombstone(key);
599
+ if (v === value) return this;
600
+ const nursery = this.getNursery();
601
+ if (v === TOMBSTONE || v === void 0) {
602
+ this._size++;
603
+ if (v === TOMBSTONE) nursery.delete(key);
604
+ }
605
+ nursery.set(key, value);
606
+ return this;
607
+ }
608
+ delete(key) {
609
+ const deleted = this.has(key);
610
+ if (deleted) {
611
+ this.getNursery().set(key, TOMBSTONE);
612
+ this._size--;
613
+ }
614
+ return deleted;
615
+ }
616
+ getOrInsert(key, defaultValue) {
617
+ const existing = this.get(key);
618
+ if (existing !== void 0) return existing;
619
+ this.set(key, defaultValue);
620
+ return defaultValue;
621
+ }
622
+ getOrInsertComputed(key, computer) {
623
+ const existing = this.get(key);
624
+ if (existing !== void 0) return existing;
625
+ const value = computer(key);
626
+ this.set(key, value);
627
+ return value;
628
+ }
629
+ clear() {
630
+ this._mutable = false;
631
+ this._old = void 0;
632
+ this._nursery = void 0;
633
+ this._size = 0;
634
+ }
635
+ *keys() {
636
+ for (const pair of this.entries()) yield pair[0];
637
+ }
638
+ *values() {
639
+ for (const pair of this.entries()) yield pair[1];
640
+ }
641
+ *entries() {
642
+ const nursery = this._nursery;
643
+ const old = this._old;
644
+ if (old) for (const pair of old) {
645
+ const k = pair[0];
646
+ const v = nursery ? nursery.get(k) : void 0;
647
+ if (v === TOMBSTONE) continue;
648
+ else if (v !== void 0) pair[1] = v;
649
+ yield pair;
650
+ }
651
+ if (nursery) {
652
+ for (const pair of nursery) if (pair[1] !== TOMBSTONE && !(old && old.has(pair[0]))) yield pair;
653
+ }
654
+ }
655
+ forEach(callbackfn, thisArg) {
656
+ if (thisArg !== void 0) callbackfn = callbackfn.bind(thisArg);
657
+ for (const [k, v] of this.entries()) callbackfn(v, k, this);
658
+ }
659
+ get [Symbol.toStringTag]() {
660
+ return "GenMap";
661
+ }
662
+ [Symbol.iterator]() {
663
+ return this.entries();
664
+ }
665
+ };
666
+ /**
667
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
668
+ *
669
+ * This source code is licensed under the MIT license found in the
670
+ * LICENSE file in the root directory of this source tree.
671
+ *
672
+ */
181
673
  function $garbageCollectDetachedDecorators(editor, pendingEditorState) {
182
674
  const currentDecorators = editor._decorators;
183
675
  let decorators = editor._pendingDecorators || currentDecorators;
@@ -308,7 +800,7 @@ function flushMutations(editor, mutations, observer) {
308
800
  const addedDOM = addedDOMs[s];
309
801
  const node = $getNodeFromDOMNode(addedDOM);
310
802
  const parentDOM = addedDOM.parentNode;
311
- if (parentDOM != null && addedDOM !== blockCursorElement && node === null && !isManagedLineBreak(addedDOM, parentDOM, editor)) {
803
+ if (parentDOM != null && addedDOM !== blockCursorElement && node === null && !isManagedLineBreak(addedDOM, parentDOM, editor) && !isDOMUnmanaged(addedDOM)) {
312
804
  if (IS_FIREFOX) {
313
805
  const possibleText = (isHTMLElement(addedDOM) ? addedDOM.innerText : null) || addedDOM.nodeValue;
314
806
  if (possibleText) possibleTextForFirefoxPaste += possibleText;
@@ -587,7 +1079,7 @@ function $setState(node, stateConfig, valueOrUpdater) {
587
1079
  * @internal
588
1080
  *
589
1081
  * Register the config to this node's sharedConfigMap and throw an exception in
590
- * `true` when a collision is detected.
1082
+ * `__DEV__` when a collision is detected.
591
1083
  */
592
1084
  function $checkCollision(node, stateConfig, state) {
593
1085
  {
@@ -1055,9 +1547,112 @@ function $normalizePoint(point) {
1055
1547
  point.set(nextNode.__key, nextOffsetAtEnd ? nextNode.getChildrenSize() : 0, "element", true);
1056
1548
  }
1057
1549
  }
1550
+ /**
1551
+ * @internal
1552
+ *
1553
+ * A reconcile-managed cache of `getTextContentSize()` for leaf nodes.
1554
+ *
1555
+ * Stored as a Symbol-keyed property on the node instance itself so that
1556
+ * read/write are direct slot access. The slot is pre-allocated to
1557
+ * `undefined` as a non-enumerable property in the LexicalNode constructor
1558
+ * so all instances share the same V8 hidden-class shape and the setter is
1559
+ * a stable inline cache hit instead of a per-instance shape transition.
1560
+ *
1561
+ * ElementNodes are NOT stored here: an element can be dirty without being
1562
+ * cloned (a descendant edit marks ancestors dirty via
1563
+ * `internalMarkParentElementsAsDirty` but does not `getWritable()` them), so
1564
+ * the same — DEV-frozen — instance would need its size rewritten when its
1565
+ * text changes, which the skip-if-set guard cannot do. Element sizes come
1566
+ * from `dom.__lexicalTextContent` instead (see `$prevSuffixTextSize`).
1567
+ *
1568
+ * Leaf writes are skipped when the slot is already not `undefined`. The
1569
+ * setter is only re-entered for the same instance via cross-parent moves
1570
+ * (where the leaf is reused in a new parent without going through
1571
+ * `getWritable` — text is unchanged, so the prior cycle's value is still
1572
+ * correct). A leaf whose text actually changed went through
1573
+ * `getWritable()` and produced a fresh clone via `static clone(node)` ->
1574
+ * ctor -> fresh `undefined` slot, so the setter writes through normally.
1575
+ *
1576
+ * The reconciler sets this on every reconciled leaf at the end of
1577
+ * `$reconcileNode` (and on every newly-created leaf in `$createNode`), so
1578
+ * the previous editor state's leaves always carry a valid cached size from
1579
+ * the cycle that just committed.
1580
+ *
1581
+ * Suffix-incremental fast path reads this off the previous-state instance
1582
+ * to get the pre-reconcile size of dirty children in O(1), avoiding both
1583
+ * the `getLatest()` -> next-state trap and a recursive prev-tree walk.
1584
+ */
1585
+ const CACHED_TEXT_SIZE_KEY = Symbol.for("@lexical/CachedTextSize");
1586
+ function $prevSuffixTextSize(startKey, count) {
1587
+ return activePrevEditorState.read(() => {
1588
+ let size = 0;
1589
+ let cur = startKey;
1590
+ for (let i = 0; i < count && cur !== null; i++) {
1591
+ const prevNode = activePrevNodeMap.get(cur);
1592
+ if (!(prevNode !== void 0)) formatDevErrorMessage(`prevSuffixTextSize: missing prev node for key ${cur}`);
1593
+ if ($isElementNode(prevNode)) {
1594
+ const nextNode = activeNextNodeMap.get(cur);
1595
+ if (nextNode !== void 0 && $isElementNode(nextNode) && nextNode.__parent !== prevNode.__parent) size += prevNode.getTextContentSize();
1596
+ else {
1597
+ const keyedDom = activePrevKeyToDOMMap.get(cur);
1598
+ const cached = keyedDom && keyedDom.__lexicalTextContent;
1599
+ if (!(typeof cached === "string")) formatDevErrorMessage(`prevSuffixTextSize: missing __lexicalTextContent for ElementNode of type ${prevNode.getType()}`);
1600
+ size += cached.length;
1601
+ }
1602
+ if (i < count - 1 && !prevNode.isInline()) size += 2;
1603
+ } else {
1604
+ const cached = prevNode[CACHED_TEXT_SIZE_KEY];
1605
+ if (!(cached !== void 0)) formatDevErrorMessage(`prevSuffixTextSize: missing cached size for leaf ${prevNode.getType()} key ${cur}`);
1606
+ size += cached;
1607
+ }
1608
+ cur = prevNode.__next;
1609
+ }
1610
+ return size;
1611
+ }, { editor: activeEditor$1 });
1612
+ }
1613
+ function $setCachedTextSize(node) {
1614
+ if ($isElementNode(node)) return;
1615
+ if (node[CACHED_TEXT_SIZE_KEY] !== void 0) return;
1616
+ node[CACHED_TEXT_SIZE_KEY] = $isTextNode(node) ? node.__text.length : node.getTextContentSize();
1617
+ }
1618
+ /**
1619
+ * Minimum children count for the suffix-incremental fast path to engage.
1620
+ * The fast path adds bookkeeping (cache lookups, suffix walks, splice) that
1621
+ * a few-children parent's general walk would beat — gate by a threshold so
1622
+ * the overhead only kicks in where the prefix preservation pays for it.
1623
+ * Tuned via `editorCycle.bench`.
1624
+ */
1625
+ const MIN_FAST_PATH_CHILDREN = 4;
1058
1626
  let subTreeTextContent = "";
1059
1627
  let subTreeTextFormat = null;
1060
1628
  let subTreeTextStyle = null;
1629
+ let subTreeFirstTextKey = null;
1630
+ function $beginCaptureGuard() {
1631
+ return {
1632
+ firstTextKey: subTreeFirstTextKey,
1633
+ format: subTreeTextFormat,
1634
+ style: subTreeTextStyle
1635
+ };
1636
+ }
1637
+ function $endCaptureGuard(saved) {
1638
+ if (saved.firstTextKey !== null) {
1639
+ subTreeTextFormat = saved.format;
1640
+ subTreeTextStyle = saved.style;
1641
+ subTreeFirstTextKey = saved.firstTextKey;
1642
+ }
1643
+ }
1644
+ function $bubbleChildFirstText(childKeyedDom) {
1645
+ if (subTreeFirstTextKey !== null) return;
1646
+ const childFirstKey = childKeyedDom.__lexicalFirstTextKey;
1647
+ if (!(childFirstKey !== void 0)) formatDevErrorMessage(`$bubbleChildFirstText: missing __lexicalFirstTextKey on element keyed DOM`);
1648
+ if (childFirstKey === null) return;
1649
+ const textNode = activeNextNodeMap.get(childFirstKey);
1650
+ if ($isTextNode(textNode)) {
1651
+ subTreeTextFormat = textNode.getFormat();
1652
+ subTreeTextStyle = textNode.getStyle();
1653
+ subTreeFirstTextKey = childFirstKey;
1654
+ }
1655
+ }
1061
1656
  let activeEditorConfig;
1062
1657
  let activeEditor$1;
1063
1658
  let activeEditorNodes;
@@ -1067,17 +1662,21 @@ let activeMutationListeners;
1067
1662
  let activeDirtyElements;
1068
1663
  let activeDirtyLeaves;
1069
1664
  let activePrevNodeMap;
1665
+ let activePrevEditorState;
1070
1666
  let activeNextNodeMap;
1071
1667
  let activePrevKeyToDOMMap;
1668
+ let activeDirtyChildrenByParent;
1072
1669
  let mutatedNodes;
1073
1670
  let activeEditorDOMRenderConfig;
1074
1671
  function $destroyNode(key, parentDOM) {
1075
1672
  const node = activePrevNodeMap.get(key);
1673
+ const isMoved = activeNextNodeMap.has(key);
1076
1674
  if (parentDOM !== null) {
1077
1675
  const dom = getPrevElementByKeyOrThrow(key);
1078
1676
  if (dom.parentNode === parentDOM) parentDOM.removeChild(dom);
1079
1677
  }
1080
- if (!activeNextNodeMap.has(key)) activeEditor$1._keyToDOMMap.delete(key);
1678
+ if (isMoved) return;
1679
+ activeEditor$1._keyToDOMMap.delete(key);
1081
1680
  if ($isElementNode(node)) {
1082
1681
  const children = $createChildrenArray(node, activePrevNodeMap);
1083
1682
  $destroyChildren(children, 0, children.length - 1, null);
@@ -1101,12 +1700,7 @@ function setElementIndent(dom, indent) {
1101
1700
  if (indent > 0 && !elementHasClassName) dom.classList.add(indentClassName);
1102
1701
  else if (indent < 1 && elementHasClassName) dom.classList.remove(indentClassName);
1103
1702
  }
1104
- if (indent === 0) {
1105
- dom.style.setProperty("padding-inline-start", "");
1106
- return;
1107
- }
1108
- const indentationBaseValue = getComputedStyle(activeEditor$1._rootElement || dom).getPropertyValue("--lexical-indent-base-value") || DEFAULT_INDENT_VALUE;
1109
- dom.style.setProperty("padding-inline-start", `calc(${indent} * ${indentationBaseValue})`);
1703
+ dom.style.setProperty("padding-inline-start", indent === 0 ? "" : `calc(${indent} * var(--lexical-indent-base-value, ${DEFAULT_INDENT_VALUE}))`);
1110
1704
  }
1111
1705
  function setElementFormat(dom, format) {
1112
1706
  const domStyle = dom.style;
@@ -1123,7 +1717,7 @@ function $getReconciledDirection(node) {
1123
1717
  if (direction !== null) return direction;
1124
1718
  if ($isRootNode(node)) return null;
1125
1719
  const parent = node.getParentOrThrow();
1126
- if (!$isRootNode(parent) || parent.__dir !== null) return null;
1720
+ if (!$isRootOrShadowRoot(parent) || parent.__dir !== null) return null;
1127
1721
  return "auto";
1128
1722
  }
1129
1723
  function $setElementDirection(dom, node) {
@@ -1134,6 +1728,16 @@ function $setElementDirection(dom, node) {
1134
1728
  function $createNode(key, slot) {
1135
1729
  const node = activeNextNodeMap.get(key);
1136
1730
  if (node === void 0) formatDevErrorMessage(`createNode: node does not exist in nodeMap`);
1731
+ if (slot !== null) {
1732
+ const prevNode = activePrevNodeMap.get(key);
1733
+ if (prevNode !== void 0 && prevNode.__parent !== node.__parent) {
1734
+ const existingDOM = activePrevKeyToDOMMap.get(key);
1735
+ if (existingDOM !== void 0) {
1736
+ slot.insertChild(existingDOM);
1737
+ return $reconcileNode(key, slot.element);
1738
+ }
1739
+ }
1740
+ }
1137
1741
  const dom = activeEditorDOMRenderConfig.$createDOM(node, activeEditor$1);
1138
1742
  storeDOMWithKey(key, dom, activeEditor$1);
1139
1743
  if ($isTextNode(node)) dom.setAttribute("data-lexical-text", "true");
@@ -1143,9 +1747,12 @@ function $createNode(key, slot) {
1143
1747
  const childrenSize = node.__size;
1144
1748
  $setElementDirection(dom, node);
1145
1749
  if (indent !== 0) setElementIndent(dom, indent);
1146
- if (childrenSize !== 0) {
1750
+ if (childrenSize === 0) {
1751
+ dom.__lexicalTextContent = "";
1752
+ dom.__lexicalFirstTextKey = null;
1753
+ } else {
1147
1754
  const endIndex = childrenSize - 1;
1148
- $createChildren($createChildrenArray(node, activeNextNodeMap), node, 0, endIndex, activeEditorDOMRenderConfig.$getDOMSlot(node, dom, activeEditor$1));
1755
+ $createChildren($createChildrenArray(node, activeNextNodeMap), node, 0, endIndex, $getDOMSlot(node, dom, activeEditor$1));
1149
1756
  }
1150
1757
  const format = node.__format;
1151
1758
  if (format !== 0) setElementFormat(dom, format);
@@ -1161,27 +1768,38 @@ function $createNode(key, slot) {
1161
1768
  }
1162
1769
  if (slot !== null) slot.insertChild(dom);
1163
1770
  activeEditorDOMRenderConfig.$decorateDOM(node, null, dom, activeEditor$1);
1771
+ $setCachedTextSize(node);
1164
1772
  Object.freeze(node);
1165
1773
  setMutatedNode(mutatedNodes, activeEditorNodes, activeMutationListeners, node, "created");
1166
1774
  return dom;
1167
1775
  }
1168
1776
  function $createChildren(children, element, _startIndex, endIndex, slot) {
1169
1777
  const previousSubTreeTextContent = subTreeTextContent;
1778
+ const outerSaved = $beginCaptureGuard();
1170
1779
  subTreeTextContent = "";
1780
+ subTreeTextFormat = null;
1781
+ subTreeTextStyle = null;
1782
+ subTreeFirstTextKey = null;
1171
1783
  let startIndex = _startIndex;
1172
1784
  for (; startIndex <= endIndex; ++startIndex) {
1785
+ const saved = $beginCaptureGuard();
1173
1786
  $createNode(children[startIndex], slot);
1174
1787
  const node = activeNextNodeMap.get(children[startIndex]);
1175
1788
  if (node !== null && $isTextNode(node)) {
1176
1789
  if (subTreeTextFormat === null) {
1177
1790
  subTreeTextFormat = node.getFormat();
1178
1791
  subTreeTextStyle = node.getStyle();
1792
+ subTreeFirstTextKey = node.__key;
1179
1793
  }
1180
1794
  } else if ($isElementNode(node) && startIndex < endIndex && !node.isInline()) subTreeTextContent += DOUBLE_LINE_BREAK;
1795
+ $endCaptureGuard(saved);
1181
1796
  }
1182
- const dom = slot.element;
1183
- dom.__lexicalTextContent = subTreeTextContent;
1797
+ const cacheDom = activeEditor$1._keyToDOMMap.get(element.__key);
1798
+ if (!(cacheDom !== void 0)) formatDevErrorMessage(`$createChildren: Element with key ${element.__key} missing from keyToDOMMap`);
1799
+ cacheDom.__lexicalTextContent = subTreeTextContent;
1800
+ cacheDom.__lexicalFirstTextKey = subTreeFirstTextKey;
1184
1801
  subTreeTextContent = previousSubTreeTextContent + subTreeTextContent;
1802
+ $endCaptureGuard(outerSaved);
1185
1803
  }
1186
1804
  function isLastChildLineBreakOrDecorator(element, nodeMap) {
1187
1805
  if (element) {
@@ -1195,9 +1813,10 @@ function isLastChildLineBreakOrDecorator(element, nodeMap) {
1195
1813
  return null;
1196
1814
  }
1197
1815
  function $reconcileElementTerminatingLineBreak(prevElement, nextElement, dom) {
1198
- const prevLineBreak = isLastChildLineBreakOrDecorator(prevElement, activePrevNodeMap);
1816
+ const slot = $getDOMSlot(nextElement, dom, activeEditor$1);
1817
+ const prevLineBreak = slot.element.__lexicalLastChildKind ?? null;
1199
1818
  const nextLineBreak = isLastChildLineBreakOrDecorator(nextElement, activeNextNodeMap);
1200
- if (prevLineBreak !== nextLineBreak) activeEditorDOMRenderConfig.$getDOMSlot(nextElement, dom, activeEditor$1).setManagedLineBreak(nextLineBreak);
1819
+ if (prevLineBreak !== nextLineBreak) slot.setManagedLineBreak(nextLineBreak);
1201
1820
  }
1202
1821
  function reconcileTextFormat(element) {
1203
1822
  if (subTreeTextFormat != null && subTreeTextFormat !== element.__textFormat && !activeEditorStateReadOnly) element.setTextFormat(subTreeTextFormat);
@@ -1208,9 +1827,210 @@ function reconcileTextStyle(element) {
1208
1827
  function $reconcileChildrenWithDirection(prevElement, nextElement, dom) {
1209
1828
  subTreeTextFormat = null;
1210
1829
  subTreeTextStyle = null;
1211
- $reconcileChildren(prevElement, nextElement, activeEditorDOMRenderConfig.$getDOMSlot(nextElement, dom, activeEditor$1));
1212
- reconcileTextFormat(nextElement);
1213
- reconcileTextStyle(nextElement);
1830
+ subTreeFirstTextKey = null;
1831
+ $reconcileChildren(prevElement, nextElement, $getDOMSlot(nextElement, dom, activeEditor$1));
1832
+ if (!$isRootOrShadowRoot(nextElement)) {
1833
+ reconcileTextFormat(nextElement);
1834
+ reconcileTextStyle(nextElement);
1835
+ }
1836
+ }
1837
+ function $buildDirtyChildrenByParent() {
1838
+ const map = /* @__PURE__ */ new Map();
1839
+ const addKeysToMap = (keys) => {
1840
+ for (const key of keys) {
1841
+ const node = activeNextNodeMap.get(key);
1842
+ if (node === void 0) continue;
1843
+ const parentKey = node.__parent;
1844
+ if (parentKey === null) continue;
1845
+ let set = map.get(parentKey);
1846
+ if (set === void 0) {
1847
+ set = /* @__PURE__ */ new Set();
1848
+ map.set(parentKey, set);
1849
+ }
1850
+ set.add(key);
1851
+ }
1852
+ };
1853
+ addKeysToMap(activeDirtyElements.keys());
1854
+ addKeysToMap(activeDirtyLeaves);
1855
+ return map;
1856
+ }
1857
+ function $suffixStartIfContiguous(parent, dirty) {
1858
+ const k = dirty.size;
1859
+ if (k === 0 || k >= parent.__size) return null;
1860
+ let cur = parent.__last;
1861
+ let suffixStart = null;
1862
+ let i = 0;
1863
+ while (cur !== null && i < k) {
1864
+ if (!dirty.has(cur)) return null;
1865
+ suffixStart = cur;
1866
+ const node = activeNextNodeMap.get(cur);
1867
+ if (node === void 0) return null;
1868
+ cur = node.__prev;
1869
+ i++;
1870
+ }
1871
+ if (i !== k) return null;
1872
+ if (cur !== null && dirty.has(cur)) return null;
1873
+ return suffixStart;
1874
+ }
1875
+ function $tryReconcileSuffixWithSizeDelta(prevElement, nextElement, slot, cacheDom, cachedParentText, suffixStartKey, k, sizeDelta) {
1876
+ if (sizeDelta !== 1 && sizeDelta !== -1) return false;
1877
+ if (k !== (sizeDelta === 1 ? 2 : 1)) return false;
1878
+ const kPrime = k - sizeDelta;
1879
+ let prevSuffixStartKey = prevElement.__last;
1880
+ for (let i = 0; i < kPrime - 1; i++) {
1881
+ if (prevSuffixStartKey === null) return false;
1882
+ const node = activePrevNodeMap.get(prevSuffixStartKey);
1883
+ if (node === void 0) return false;
1884
+ prevSuffixStartKey = node.__prev;
1885
+ }
1886
+ if (prevSuffixStartKey === null) return false;
1887
+ const nextStartNode = activeNextNodeMap.get(suffixStartKey);
1888
+ const prevStartNode = activePrevNodeMap.get(prevSuffixStartKey);
1889
+ if (nextStartNode === void 0 || prevStartNode === void 0) return false;
1890
+ if (nextStartNode.__prev !== prevStartNode.__prev) return false;
1891
+ const nextSuffixKeys = [];
1892
+ let cur = suffixStartKey;
1893
+ for (let i = 0; i < k; i++) {
1894
+ if (cur === null) return false;
1895
+ nextSuffixKeys.push(cur);
1896
+ const node = activeNextNodeMap.get(cur);
1897
+ cur = node ? node.__next : null;
1898
+ }
1899
+ const prevSuffixKeys = [];
1900
+ cur = prevSuffixStartKey;
1901
+ for (let i = 0; i < kPrime; i++) {
1902
+ if (cur === null) return false;
1903
+ prevSuffixKeys.push(cur);
1904
+ const node = activePrevNodeMap.get(cur);
1905
+ cur = node ? node.__next : null;
1906
+ }
1907
+ const prevSet = new Set(prevSuffixKeys);
1908
+ const nextSet = new Set(nextSuffixKeys);
1909
+ const ops = [];
1910
+ let pi = 0;
1911
+ let ni = 0;
1912
+ while (pi < kPrime && ni < k) if (nextSuffixKeys[ni] === prevSuffixKeys[pi]) {
1913
+ ops.push({
1914
+ key: nextSuffixKeys[ni],
1915
+ kind: "reconcile"
1916
+ });
1917
+ pi++;
1918
+ ni++;
1919
+ } else if (!nextSet.has(prevSuffixKeys[pi])) {
1920
+ ops.push({
1921
+ key: prevSuffixKeys[pi],
1922
+ kind: "destroy"
1923
+ });
1924
+ pi++;
1925
+ } else if (!prevSet.has(nextSuffixKeys[ni])) {
1926
+ ops.push({
1927
+ key: nextSuffixKeys[ni],
1928
+ kind: "create",
1929
+ nextIndex: ni
1930
+ });
1931
+ ni++;
1932
+ } else return false;
1933
+ while (pi < kPrime) ops.push({
1934
+ key: prevSuffixKeys[pi++],
1935
+ kind: "destroy"
1936
+ });
1937
+ while (ni < k) {
1938
+ ops.push({
1939
+ key: nextSuffixKeys[ni],
1940
+ kind: "create",
1941
+ nextIndex: ni
1942
+ });
1943
+ ni++;
1944
+ }
1945
+ const oldSuffixLength = $prevSuffixTextSize(prevSuffixStartKey, kPrime);
1946
+ for (const op of ops) {
1947
+ const saved = $beginCaptureGuard();
1948
+ if (op.kind === "reconcile") $reconcileNode(op.key, slot.element);
1949
+ else if (op.kind === "destroy") $destroyNode(op.key, slot.element);
1950
+ else {
1951
+ let beforeDOM = null;
1952
+ for (let j = op.nextIndex + 1; j < k; j++) {
1953
+ const siblingDOM = activeEditor$1._keyToDOMMap.get(nextSuffixKeys[j]);
1954
+ if (siblingDOM !== void 0) {
1955
+ beforeDOM = siblingDOM;
1956
+ break;
1957
+ }
1958
+ }
1959
+ $createNode(op.key, slot.withBefore(beforeDOM ?? slot.before));
1960
+ }
1961
+ if (op.kind !== "destroy") {
1962
+ const opNode = activeNextNodeMap.get(op.key);
1963
+ if (opNode && $isTextNode(opNode) && subTreeTextFormat === null) {
1964
+ subTreeTextFormat = opNode.getFormat();
1965
+ subTreeTextStyle = opNode.getStyle();
1966
+ subTreeFirstTextKey = opNode.__key;
1967
+ }
1968
+ }
1969
+ $endCaptureGuard(saved);
1970
+ }
1971
+ let newSuffix = "";
1972
+ for (let i = 0; i < k; i++) {
1973
+ const node = activeNextNodeMap.get(nextSuffixKeys[i]);
1974
+ if (node === void 0) return false;
1975
+ let text;
1976
+ if ($isElementNode(node)) {
1977
+ const childKeyedDom = activeEditor$1._keyToDOMMap.get(nextSuffixKeys[i]);
1978
+ const cached = childKeyedDom && childKeyedDom.__lexicalTextContent;
1979
+ if (!(typeof cached === "string")) formatDevErrorMessage(`tryReconcileSuffixWithSizeDelta: missing __lexicalTextContent on child of type ${node.getType()} after suffix reconcile`);
1980
+ text = cached;
1981
+ } else text = node.getTextContent();
1982
+ newSuffix += text;
1983
+ if (i < k - 1 && $isElementNode(node) && !node.isInline()) newSuffix += DOUBLE_LINE_BREAK;
1984
+ }
1985
+ cacheDom.__lexicalTextContent = cachedParentText.slice(0, cachedParentText.length - oldSuffixLength) + newSuffix;
1986
+ return true;
1987
+ }
1988
+ /**
1989
+ * Decide whether the post-suffix-walk values of `subTreeTextFormat` /
1990
+ * `subTreeTextStyle` should be kept (the prefix has no text descendant
1991
+ * and the suffix carries the canonical first text) or replaced with the
1992
+ * prev-cycle's canonical values (the prefix is still authoritative).
1993
+ *
1994
+ * The cached `__lexicalFirstTextKey` on `dom` is the deep TextNode key
1995
+ * recorded when this element's children were last walked. We climb its
1996
+ * ancestor chain in next-state until we reach a direct child of
1997
+ * `nextElement`, then probe `dirtyChildren`: if that direct child is
1998
+ * dirty (or the cached key is missing from the next map), the cached
1999
+ * key has been moved into the suffix's subtree or destroyed, so the
2000
+ * suffix-derived values are authoritative. Otherwise the prefix is
2001
+ * canonical and we recover format/style from the live text node, which
2002
+ * lets `reconcileTextFormat` / `reconcileTextStyle` no-op via their
2003
+ * existing equality check against the parent's `__textFormat` /
2004
+ * `__textStyle`.
2005
+ *
2006
+ * Walk depth is bounded by tree depth from the text node to the
2007
+ * reconciled element (typically 1 — text directly under a paragraph).
2008
+ * Always refreshes the cache for the next cycle.
2009
+ */
2010
+ function $resolveSuffixPathFormat(nextElement, dom, dirtyChildren) {
2011
+ const cachedFirstTextKey = dom.__lexicalFirstTextKey;
2012
+ if (cachedFirstTextKey != null) {
2013
+ const parentKey = nextElement.__key;
2014
+ let ancestor = cachedFirstTextKey;
2015
+ while (ancestor !== null) {
2016
+ const node = activeNextNodeMap.get(ancestor);
2017
+ if (node === void 0) {
2018
+ ancestor = null;
2019
+ break;
2020
+ }
2021
+ if (node.__parent === parentKey) break;
2022
+ ancestor = node.__parent;
2023
+ }
2024
+ if (ancestor !== null && !dirtyChildren.has(ancestor)) {
2025
+ const textNode = activeNextNodeMap.get(cachedFirstTextKey);
2026
+ if ($isTextNode(textNode)) {
2027
+ subTreeTextFormat = textNode.getFormat();
2028
+ subTreeTextStyle = textNode.getStyle();
2029
+ return;
2030
+ }
2031
+ }
2032
+ }
2033
+ dom.__lexicalFirstTextKey = subTreeFirstTextKey;
1214
2034
  }
1215
2035
  function $reconcileChildren(prevElement, nextElement, slot) {
1216
2036
  const previousSubTreeTextContent = subTreeTextContent;
@@ -1218,6 +2038,105 @@ function $reconcileChildren(prevElement, nextElement, slot) {
1218
2038
  const nextChildrenSize = nextElement.__size;
1219
2039
  subTreeTextContent = "";
1220
2040
  const dom = slot.element;
2041
+ const cacheDom = activeEditor$1._keyToDOMMap.get(nextElement.__key);
2042
+ if (!(cacheDom !== void 0)) formatDevErrorMessage(`$reconcileChildren: Element with key ${nextElement.__key} missing from keyToDOMMap`);
2043
+ const sizeDelta = nextChildrenSize - prevChildrenSize;
2044
+ if (!treatAllNodesAsDirty && Math.abs(sizeDelta) <= 1 && prevChildrenSize >= MIN_FAST_PATH_CHILDREN && prevElement.__first === nextElement.__first && (sizeDelta !== 0 || !activeEditor$1._cloneNotNeeded.has(prevElement.__key))) {
2045
+ const cachedParentText = cacheDom.__lexicalTextContent;
2046
+ const dirtyChildren = activeDirtyChildrenByParent.get(prevElement.__key);
2047
+ if (!treatAllNodesAsDirty && typeof cachedParentText === "string" && dirtyChildren !== void 0) {
2048
+ const suffixStartKey = $suffixStartIfContiguous(nextElement, dirtyChildren);
2049
+ if (suffixStartKey !== null) {
2050
+ const k = dirtyChildren.size;
2051
+ if (sizeDelta === 0) {
2052
+ const oldSuffixLength = $prevSuffixTextSize(suffixStartKey, k);
2053
+ let cur = suffixStartKey;
2054
+ let i = 0;
2055
+ while (cur !== null && i < k) {
2056
+ const node = activeNextNodeMap.get(cur);
2057
+ if (node === void 0) break;
2058
+ const saved = $beginCaptureGuard();
2059
+ $reconcileNode(cur, dom);
2060
+ if ($isTextNode(node) && subTreeTextFormat === null) {
2061
+ subTreeTextFormat = node.getFormat();
2062
+ subTreeTextStyle = node.getStyle();
2063
+ subTreeFirstTextKey = node.__key;
2064
+ }
2065
+ $endCaptureGuard(saved);
2066
+ cur = node.__next;
2067
+ i++;
2068
+ }
2069
+ let newSuffix = "";
2070
+ cur = suffixStartKey;
2071
+ i = 0;
2072
+ while (cur !== null && i < k) {
2073
+ const node = activeNextNodeMap.get(cur);
2074
+ if (node === void 0) break;
2075
+ let text;
2076
+ if ($isElementNode(node)) {
2077
+ const childKeyedDom = activeEditor$1._keyToDOMMap.get(cur);
2078
+ const cached = childKeyedDom && childKeyedDom.__lexicalTextContent;
2079
+ if (!(typeof cached === "string")) formatDevErrorMessage(`reconcileChildren same-size suffix: missing __lexicalTextContent on child of type ${node.getType()} after reconcile`);
2080
+ text = cached;
2081
+ } else text = node.getTextContent();
2082
+ newSuffix += text;
2083
+ if (i < k - 1 && $isElementNode(node) && !node.isInline()) newSuffix += DOUBLE_LINE_BREAK;
2084
+ cur = node.__next;
2085
+ i++;
2086
+ }
2087
+ const newParentText = cachedParentText.slice(0, cachedParentText.length - oldSuffixLength) + newSuffix;
2088
+ cacheDom.__lexicalTextContent = newParentText;
2089
+ subTreeTextContent = previousSubTreeTextContent + newParentText;
2090
+ $resolveSuffixPathFormat(nextElement, cacheDom, dirtyChildren);
2091
+ return;
2092
+ }
2093
+ if ($tryReconcileSuffixWithSizeDelta(prevElement, nextElement, slot, cacheDom, cachedParentText, suffixStartKey, k, sizeDelta)) {
2094
+ const newCachedText = cacheDom.__lexicalTextContent;
2095
+ if (!(typeof newCachedText === "string")) formatDevErrorMessage(`reconcileChildren: $tryReconcileSuffixWithSizeDelta returned true without writing __lexicalTextContent`);
2096
+ subTreeTextContent = previousSubTreeTextContent + newCachedText;
2097
+ $resolveSuffixPathFormat(nextElement, cacheDom, dirtyChildren);
2098
+ return;
2099
+ }
2100
+ }
2101
+ }
2102
+ if (sizeDelta === 0) {
2103
+ let nodeKey = prevElement.__first;
2104
+ let i = 0;
2105
+ while (nodeKey !== null) {
2106
+ const node = activeNextNodeMap.get(nodeKey);
2107
+ if (node === void 0) break;
2108
+ const isDirty = treatAllNodesAsDirty || activeDirtyLeaves.has(nodeKey) || activeDirtyElements.has(nodeKey);
2109
+ const saved = $beginCaptureGuard();
2110
+ if (isDirty) $reconcileNode(nodeKey, dom);
2111
+ else {
2112
+ let text;
2113
+ let childKeyedDom;
2114
+ if ($isElementNode(node)) {
2115
+ childKeyedDom = activePrevKeyToDOMMap.get(nodeKey);
2116
+ const cached = childKeyedDom && childKeyedDom.__lexicalTextContent;
2117
+ if (!(typeof cached === "string")) formatDevErrorMessage(`reconcileChildren structurally-clean walk: missing __lexicalTextContent on non-dirty child of type ${node.getType()}`);
2118
+ text = cached;
2119
+ } else text = node.getTextContent();
2120
+ subTreeTextContent += text;
2121
+ if (childKeyedDom !== void 0) $bubbleChildFirstText(childKeyedDom);
2122
+ }
2123
+ if ($isTextNode(node)) {
2124
+ if (subTreeTextFormat === null) {
2125
+ subTreeTextFormat = node.getFormat();
2126
+ subTreeTextStyle = node.getStyle();
2127
+ subTreeFirstTextKey = node.__key;
2128
+ }
2129
+ } else if ($isElementNode(node) && i < nextChildrenSize - 1 && !node.isInline()) subTreeTextContent += DOUBLE_LINE_BREAK;
2130
+ $endCaptureGuard(saved);
2131
+ nodeKey = node.__next;
2132
+ i++;
2133
+ }
2134
+ cacheDom.__lexicalTextContent = subTreeTextContent;
2135
+ cacheDom.__lexicalFirstTextKey = subTreeFirstTextKey;
2136
+ subTreeTextContent = previousSubTreeTextContent + subTreeTextContent;
2137
+ return;
2138
+ }
2139
+ }
1221
2140
  if (prevChildrenSize === 1 && nextChildrenSize === 1) {
1222
2141
  const prevFirstChildKey = prevElement.__first;
1223
2142
  const nextFirstChildKey = nextElement.__first;
@@ -1226,7 +2145,8 @@ function $reconcileChildren(prevElement, nextElement, slot) {
1226
2145
  const lastDOM = getPrevElementByKeyOrThrow(prevFirstChildKey);
1227
2146
  const replacementDOM = $createNode(nextFirstChildKey, null);
1228
2147
  try {
1229
- dom.replaceChild(replacementDOM, lastDOM);
2148
+ if (lastDOM.parentNode === dom) dom.replaceChild(replacementDOM, lastDOM);
2149
+ else slot.insertChild(replacementDOM);
1230
2150
  } catch (error) {
1231
2151
  if (typeof error === "object" && error != null) {
1232
2152
  const msg = `${error.toString()} Parent: ${dom.tagName}, new child: {tag: ${replacementDOM.tagName} key: ${nextFirstChildKey}}, old child: {tag: ${lastDOM.tagName}, key: ${prevFirstChildKey}}.`;
@@ -1240,6 +2160,7 @@ function $reconcileChildren(prevElement, nextElement, slot) {
1240
2160
  if (subTreeTextFormat === null) {
1241
2161
  subTreeTextFormat = nextChildNode.getFormat();
1242
2162
  subTreeTextStyle = nextChildNode.getStyle();
2163
+ subTreeFirstTextKey = nextChildNode.__key;
1243
2164
  }
1244
2165
  }
1245
2166
  } else {
@@ -1257,7 +2178,8 @@ function $reconcileChildren(prevElement, nextElement, slot) {
1257
2178
  }
1258
2179
  } else $reconcileNodeChildren(nextElement, prevChildren, nextChildren, prevChildrenSize, nextChildrenSize, slot);
1259
2180
  }
1260
- dom.__lexicalTextContent = subTreeTextContent;
2181
+ cacheDom.__lexicalTextContent = subTreeTextContent;
2182
+ cacheDom.__lexicalFirstTextKey = subTreeFirstTextKey;
1261
2183
  subTreeTextContent = previousSubTreeTextContent + subTreeTextContent;
1262
2184
  }
1263
2185
  function $reconcileNode(key, parentDOM) {
@@ -1270,11 +2192,9 @@ function $reconcileNode(key, parentDOM) {
1270
2192
  let text;
1271
2193
  if ($isElementNode(prevNode)) {
1272
2194
  const previousSubTreeTextContent = dom.__lexicalTextContent;
1273
- if (typeof previousSubTreeTextContent === "string") text = previousSubTreeTextContent;
1274
- else {
1275
- text = prevNode.getTextContent();
1276
- dom.__lexicalTextContent = text;
1277
- }
2195
+ if (!(typeof previousSubTreeTextContent === "string")) formatDevErrorMessage(`reconcileNode: missing __lexicalTextContent on non-dirty element of type ${prevNode.getType()}`);
2196
+ text = previousSubTreeTextContent;
2197
+ $bubbleChildFirstText(dom);
1278
2198
  } else text = prevNode.getTextContent();
1279
2199
  subTreeTextContent += text;
1280
2200
  return dom;
@@ -1298,15 +2218,11 @@ function $reconcileNode(key, parentDOM) {
1298
2218
  if (!$isRootNode(nextNode) && !nextNode.isInline()) $reconcileElementTerminatingLineBreak(prevNode, nextNode, dom);
1299
2219
  } else {
1300
2220
  const previousSubTreeTextContent = dom.__lexicalTextContent;
1301
- let text;
1302
- if (typeof previousSubTreeTextContent === "string") text = previousSubTreeTextContent;
1303
- else {
1304
- text = prevNode.getTextContent();
1305
- dom.__lexicalTextContent = text;
1306
- }
1307
- subTreeTextContent += text;
2221
+ if (!(typeof previousSubTreeTextContent === "string")) formatDevErrorMessage(`reconcileNode: missing __lexicalTextContent on cloned non-dirty element of type ${prevNode.getType()}`);
2222
+ subTreeTextContent += previousSubTreeTextContent;
2223
+ $bubbleChildFirstText(dom);
1308
2224
  }
1309
- if (treatAllNodesAsDirty || nextNode.__dir !== prevNode.__dir) {
2225
+ if (treatAllNodesAsDirty || nextNode.__dir !== prevNode.__dir || nextNode.__parent !== prevNode.__parent) {
1310
2226
  $setElementDirection(dom, nextNode);
1311
2227
  if ($isRootNode(nextNode) && !treatAllNodesAsDirty) {
1312
2228
  for (const child of nextNode.getChildren()) if ($isElementNode(child)) $setElementDirection(getElementByKeyOrThrow(activeEditor$1, child.getKey()), child);
@@ -1320,12 +2236,16 @@ function $reconcileNode(key, parentDOM) {
1320
2236
  }
1321
2237
  subTreeTextContent += text;
1322
2238
  }
1323
- if (!activeEditorStateReadOnly && $isRootNode(nextNode) && nextNode.__cachedText !== subTreeTextContent) {
1324
- const nextRootNode = nextNode.getWritable();
1325
- nextRootNode.__cachedText = subTreeTextContent;
1326
- nextNode = nextRootNode;
2239
+ if (!activeEditorStateReadOnly && $isRootNode(nextNode)) {
2240
+ const latestRoot = nextNode.getLatest();
2241
+ if (latestRoot.__cachedText !== subTreeTextContent) {
2242
+ const nextRootNode = latestRoot.getWritable();
2243
+ nextRootNode.__cachedText = subTreeTextContent;
2244
+ nextNode = nextRootNode;
2245
+ }
1327
2246
  }
1328
2247
  activeEditorDOMRenderConfig.$decorateDOM(nextNode, prevNode, dom, activeEditor$1);
2248
+ $setCachedTextSize(nextNode);
1329
2249
  Object.freeze(nextNode);
1330
2250
  return dom;
1331
2251
  }
@@ -1359,6 +2279,7 @@ function $reconcileNodeChildren(nextElement, prevChildren, nextChildren, prevChi
1359
2279
  while (prevIndex <= prevEndIndex && nextIndex <= nextEndIndex) {
1360
2280
  const prevKey = prevChildren[prevIndex];
1361
2281
  const nextKey = nextChildren[nextIndex];
2282
+ const saved = $beginCaptureGuard();
1362
2283
  if (prevKey === nextKey) {
1363
2284
  siblingDOM = getNextSibling($reconcileNode(nextKey, slot.element));
1364
2285
  prevIndex++;
@@ -1368,6 +2289,7 @@ function $reconcileNodeChildren(nextElement, prevChildren, nextChildren, prevChi
1368
2289
  if (prevChildrenSet === void 0) prevChildrenSet = childrenSet(prevChildren, prevIndex);
1369
2290
  else if (!prevChildrenSet.has(prevKey)) {
1370
2291
  prevIndex++;
2292
+ $endCaptureGuard(saved);
1371
2293
  continue;
1372
2294
  }
1373
2295
  if (!nextChildrenSet.has(prevKey)) {
@@ -1375,14 +2297,15 @@ function $reconcileNodeChildren(nextElement, prevChildren, nextChildren, prevChi
1375
2297
  $destroyNode(prevKey, slot.element);
1376
2298
  prevIndex++;
1377
2299
  prevChildrenSet.delete(prevKey);
2300
+ $endCaptureGuard(saved);
1378
2301
  continue;
1379
2302
  }
1380
2303
  if (!prevChildrenSet.has(nextKey)) {
1381
- $createNode(nextKey, slot.withBefore(siblingDOM));
2304
+ $createNode(nextKey, slot.withBefore(siblingDOM ?? slot.before));
1382
2305
  nextIndex++;
1383
2306
  } else {
1384
2307
  const childDOM = getElementByKeyOrThrow(activeEditor$1, nextKey);
1385
- if (childDOM !== siblingDOM) slot.withBefore(siblingDOM).insertChild(childDOM);
2308
+ if (childDOM !== siblingDOM) slot.withBefore(siblingDOM ?? slot.before).insertChild(childDOM);
1386
2309
  siblingDOM = getNextSibling($reconcileNode(nextKey, slot.element));
1387
2310
  prevIndex++;
1388
2311
  nextIndex++;
@@ -1393,19 +2316,24 @@ function $reconcileNodeChildren(nextElement, prevChildren, nextChildren, prevChi
1393
2316
  if (subTreeTextFormat === null) {
1394
2317
  subTreeTextFormat = node.getFormat();
1395
2318
  subTreeTextStyle = node.getStyle();
2319
+ subTreeFirstTextKey = node.__key;
1396
2320
  }
1397
2321
  } else if ($isElementNode(node) && nextIndex <= nextEndIndex && !node.isInline()) subTreeTextContent += DOUBLE_LINE_BREAK;
2322
+ $endCaptureGuard(saved);
1398
2323
  }
1399
2324
  const appendNewChildren = prevIndex > prevEndIndex;
1400
2325
  const removeOldChildren = nextIndex > nextEndIndex;
1401
2326
  if (appendNewChildren && !removeOldChildren) {
1402
2327
  const previousNode = nextChildren[nextEndIndex + 1];
1403
2328
  const insertDOM = previousNode === void 0 ? null : activeEditor$1.getElementByKey(previousNode);
1404
- $createChildren(nextChildren, nextElement, nextIndex, nextEndIndex, slot.withBefore(insertDOM));
2329
+ $createChildren(nextChildren, nextElement, nextIndex, nextEndIndex, slot.withBefore(insertDOM ?? slot.before));
1405
2330
  } else if (removeOldChildren && !appendNewChildren) $destroyChildren(prevChildren, prevIndex, prevEndIndex, slot.element);
1406
2331
  }
1407
2332
  function $reconcileRoot(prevEditorState, nextEditorState, editor, dirtyType, dirtyElements, dirtyLeaves) {
1408
2333
  subTreeTextContent = "";
2334
+ subTreeTextFormat = null;
2335
+ subTreeTextStyle = null;
2336
+ subTreeFirstTextKey = null;
1409
2337
  treatAllNodesAsDirty = dirtyType === FULL_RECONCILE;
1410
2338
  activeEditor$1 = editor;
1411
2339
  activeEditorConfig = editor._config;
@@ -1415,9 +2343,11 @@ function $reconcileRoot(prevEditorState, nextEditorState, editor, dirtyType, dir
1415
2343
  activeDirtyElements = dirtyElements;
1416
2344
  activeDirtyLeaves = dirtyLeaves;
1417
2345
  activePrevNodeMap = prevEditorState._nodeMap;
2346
+ activePrevEditorState = prevEditorState;
1418
2347
  activeNextNodeMap = nextEditorState._nodeMap;
1419
2348
  activeEditorStateReadOnly = nextEditorState._readOnly;
1420
- activePrevKeyToDOMMap = new Map(editor._keyToDOMMap);
2349
+ activePrevKeyToDOMMap = cloneMap(editor._keyToDOMMap);
2350
+ activeDirtyChildrenByParent = $buildDirtyChildrenByParent();
1421
2351
  const currentMutatedNodes = /* @__PURE__ */ new Map();
1422
2352
  mutatedNodes = currentMutatedNodes;
1423
2353
  $reconcileNode("root", null);
@@ -1426,9 +2356,11 @@ function $reconcileRoot(prevEditorState, nextEditorState, editor, dirtyType, dir
1426
2356
  activeDirtyElements = void 0;
1427
2357
  activeDirtyLeaves = void 0;
1428
2358
  activePrevNodeMap = void 0;
2359
+ activePrevEditorState = void 0;
1429
2360
  activeNextNodeMap = void 0;
1430
2361
  activeEditorConfig = void 0;
1431
2362
  activePrevKeyToDOMMap = void 0;
2363
+ activeDirtyChildrenByParent = void 0;
1432
2364
  mutatedNodes = void 0;
1433
2365
  activeEditorDOMRenderConfig = DEFAULT_EDITOR_DOM_CONFIG;
1434
2366
  return currentMutatedNodes;
@@ -1650,6 +2582,8 @@ let lastKeyDownTimeStamp = 0;
1650
2582
  let lastKeyCode = null;
1651
2583
  let lastBeforeInputInsertTextTimeStamp = 0;
1652
2584
  let unprocessedBeforeInputData = null;
2585
+ let isInsertTextAfterHandledSelectionCommand = false;
2586
+ let handledSelectionCommandTimeoutId = null;
1653
2587
  const rootElementToDocument = /* @__PURE__ */ new WeakMap();
1654
2588
  const rootElementsRegistered = /* @__PURE__ */ new WeakMap();
1655
2589
  let isSelectionChangeFromDOMUpdate = false;
@@ -1676,7 +2610,7 @@ function $shouldPreventDefaultAndInsertText(selection, domTargetRange, text, tim
1676
2610
  const anchorKey = anchor.key;
1677
2611
  const backingAnchorElement = editor.getElementByKey(anchorKey);
1678
2612
  const textLength = text.length;
1679
- 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(backingAnchorElement) || 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);
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);
1680
2614
  }
1681
2615
  function shouldSkipSelectionChange(domNode, offset) {
1682
2616
  return isDOMTextNode(domNode) && domNode.nodeValue !== null && offset !== 0 && offset !== domNode.nodeValue.length;
@@ -1775,11 +2709,6 @@ function onClick(event, editor) {
1775
2709
  if (anchor.type === "element" && anchor.offset === 0 && selection.isCollapsed() && !$isRootNode(anchorNode) && $getRoot().getChildrenSize() === 1 && anchorNode.getTopLevelElementOrThrow().isEmpty() && lastSelection !== null && selection.is(lastSelection)) {
1776
2710
  domSelection.removeAllRanges();
1777
2711
  selection.dirty = true;
1778
- } else if (event.detail === 3 && !selection.isCollapsed()) {
1779
- if (anchorNode !== selection.focus.getNode()) {
1780
- const parentNode = $findMatchingParent(anchorNode, (node) => $isElementNode(node) && !node.isInline());
1781
- if ($isElementNode(parentNode)) parentNode.select(0);
1782
- }
1783
2712
  }
1784
2713
  } else if (event.pointerType === "touch" || event.pointerType === "pen") {
1785
2714
  const domAnchorNode = domSelection.anchorNode;
@@ -1802,12 +2731,47 @@ function getTargetRange(event) {
1802
2731
  if (targetRanges.length === 0) return null;
1803
2732
  return targetRanges[0];
1804
2733
  }
2734
+ function $maybeMoveSelectionPastTrailingAcceptanceBoundary(insertedText) {
2735
+ if (insertedText == null || insertedText.length <= 1 || lastKeyCode == null) return;
2736
+ const characterToSearchFor = lastKeyCode.length === 1 ? lastKeyCode : lastKeyCode === "Enter" ? "\n" : lastKeyCode === "Tab" ? " " : null;
2737
+ if (!characterToSearchFor) return;
2738
+ const selection = $getSelection();
2739
+ if (!$isRangeSelection(selection) || !selection.isCollapsed()) return;
2740
+ const anchorNode = selection.anchor.getNode();
2741
+ if (!$isTextNode(anchorNode)) return;
2742
+ const { offset } = selection.anchor;
2743
+ if (anchorNode.getTextContentSize() === offset) {
2744
+ const nextSibling = anchorNode.getNextSibling();
2745
+ if (characterToSearchFor === "\n") {
2746
+ if ($isLineBreakNode(nextSibling)) nextSibling.selectEnd();
2747
+ else if (!nextSibling) {
2748
+ const block = $findMatchingParent(anchorNode, $isBlockElementNode);
2749
+ const nextBlock = block && block.getNextSibling();
2750
+ if ($isElementNode(nextBlock)) nextBlock.selectStart();
2751
+ }
2752
+ } else if (characterToSearchFor === " ") {
2753
+ if ($isTabNode(nextSibling)) nextSibling.selectEnd();
2754
+ } else if ($isTextNode(nextSibling) && nextSibling.getTextContent()[0] === characterToSearchFor) nextSibling.select(1, 1);
2755
+ } else if (anchorNode.getTextContent()[offset] === characterToSearchFor) anchorNode.select(offset + 1, offset + 1);
2756
+ }
1805
2757
  function $canRemoveText(anchorNode, focusNode) {
1806
2758
  return anchorNode !== focusNode || $isElementNode(anchorNode) || $isElementNode(focusNode) || !$isTokenOrTab(anchorNode) || !$isTokenOrTab(focusNode);
1807
2759
  }
1808
2760
  function isPossiblyAndroidKeyPress(timeStamp) {
1809
2761
  return lastKeyCode === "MediaLast" && timeStamp < lastKeyDownTimeStamp + ANDROID_COMPOSITION_LATENCY;
1810
2762
  }
2763
+ function clearHandledSelectionCommandInsertText() {
2764
+ isInsertTextAfterHandledSelectionCommand = false;
2765
+ if (handledSelectionCommandTimeoutId !== null) {
2766
+ clearTimeout(handledSelectionCommandTimeoutId);
2767
+ handledSelectionCommandTimeoutId = null;
2768
+ }
2769
+ }
2770
+ function markHandledSelectionCommandInsertText() {
2771
+ clearHandledSelectionCommandInsertText();
2772
+ isInsertTextAfterHandledSelectionCommand = true;
2773
+ handledSelectionCommandTimeoutId = setTimeout(clearHandledSelectionCommandInsertText, 0);
2774
+ }
1811
2775
  function registerDefaultCommandHandlers(editor) {
1812
2776
  editor.registerCommand(BEFORE_INPUT_COMMAND, $handleBeforeInput, 0);
1813
2777
  editor.registerCommand(INPUT_COMMAND, $handleInput, 0);
@@ -1826,6 +2790,16 @@ function $handleBeforeInput(event) {
1826
2790
  const targetRange = getTargetRange(event);
1827
2791
  const editor = getActiveEditor();
1828
2792
  const selection = $getSelection();
2793
+ if (inputType === "insertText" && event.data && isInsertTextAfterHandledSelectionCommand) {
2794
+ clearHandledSelectionCommandInsertText();
2795
+ event.preventDefault();
2796
+ if ($isRangeSelection(selection) && !selection.isCollapsed()) {
2797
+ const point = selection.isBackward() ? selection.anchor : selection.focus;
2798
+ selection.anchor.set(point.key, point.offset, point.type);
2799
+ selection.focus.set(point.key, point.offset, point.type);
2800
+ }
2801
+ return true;
2802
+ }
1829
2803
  if (inputType === "deleteContentBackward") {
1830
2804
  if (selection === null) {
1831
2805
  const prevSelection = $getPreviousSelection();
@@ -1850,6 +2824,14 @@ function $handleBeforeInput(event) {
1850
2824
  }
1851
2825
  } else {
1852
2826
  $setCompositionKey(null);
2827
+ if (IS_IOS && targetRange !== null && !targetRange.collapsed) {
2828
+ selection.applyDOMRange(targetRange);
2829
+ if (!selection.isCollapsed()) {
2830
+ event.preventDefault();
2831
+ selection.removeText();
2832
+ return true;
2833
+ }
2834
+ }
1853
2835
  event.preventDefault();
1854
2836
  const selectedNode = selection.anchor.getNode();
1855
2837
  const selectedNodeText = selectedNode.getTextContent();
@@ -1892,6 +2874,7 @@ function $handleBeforeInput(event) {
1892
2874
  } else if (data != null && $shouldPreventDefaultAndInsertText(selection, targetRange, data, event.timeStamp, true)) {
1893
2875
  event.preventDefault();
1894
2876
  dispatchCommand(editor, CONTROLLED_TEXT_INSERTION_COMMAND, data);
2877
+ $maybeMoveSelectionPastTrailingAcceptanceBoundary(data);
1895
2878
  } else unprocessedBeforeInputData = data;
1896
2879
  lastBeforeInputInsertTextTimeStamp = event.timeStamp;
1897
2880
  return true;
@@ -1902,6 +2885,7 @@ function $handleBeforeInput(event) {
1902
2885
  case "insertFromDrop":
1903
2886
  case "insertReplacementText":
1904
2887
  dispatchCommand(editor, CONTROLLED_TEXT_INSERTION_COMMAND, event);
2888
+ $maybeMoveSelectionPastTrailingAcceptanceBoundary((event.dataTransfer ? event.dataTransfer.getData("text/plain") : null) ?? event.data);
1905
2889
  break;
1906
2890
  case "insertFromComposition":
1907
2891
  $setCompositionKey(null);
@@ -1973,6 +2957,7 @@ function $handleBeforeInput(event) {
1973
2957
  }
1974
2958
  function onInput(event, editor) {
1975
2959
  event.stopPropagation();
2960
+ clearHandledSelectionCommandInsertText();
1976
2961
  updateEditorSync(editor, () => {
1977
2962
  editor.dispatchCommand(INPUT_COMMAND, event);
1978
2963
  }, { event });
@@ -1997,7 +2982,11 @@ function $handleInput(event) {
1997
2982
  const endOffset = isBackward ? selection.focus.offset : selection.anchor.offset;
1998
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);
1999
2984
  const textLength = data.length;
2000
- if (IS_FIREFOX && textLength > 1 && event.inputType === "insertCompositionText" && !editor.isComposing()) selection.anchor.offset -= textLength;
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
+ }
2001
2990
  if (IS_ANDROID_CHROME && editor.isComposing()) {
2002
2991
  lastKeyDownTimeStamp = 0;
2003
2992
  $setCompositionKey(null);
@@ -2038,7 +3027,8 @@ function $onCompositionEndImpl(editor, data) {
2038
3027
  if (compositionKey !== null && data != null) {
2039
3028
  if (data === "") {
2040
3029
  const node = $getNodeByKey(compositionKey);
2041
- const textNode = getDOMTextNode(editor.getElementByKey(compositionKey));
3030
+ const domElement = editor.getElementByKey(compositionKey);
3031
+ const textNode = domElement !== null && $isTextNode(node) ? $getDOMTextNode(node, domElement, editor) : null;
2042
3032
  if (textNode !== null && textNode.nodeValue !== null && $isTextNode(node)) {
2043
3033
  const domSelection = getDOMSelection(getWindow(editor));
2044
3034
  let anchorOffset = null;
@@ -2074,6 +3064,7 @@ function onCompositionEnd(event, editor) {
2074
3064
  function onKeyDown(event, editor) {
2075
3065
  lastKeyDownTimeStamp = event.timeStamp;
2076
3066
  lastKeyCode = event.key;
3067
+ if (event.key !== "Backspace") clearHandledSelectionCommandInsertText();
2077
3068
  if (editor.isComposing()) return;
2078
3069
  dispatchCommand(editor, KEY_DOWN_COMMAND, event);
2079
3070
  }
@@ -2109,8 +3100,9 @@ function $handleKeyDown(event) {
2109
3100
  } else if (isParagraph(event)) {
2110
3101
  isInsertLineBreak = false;
2111
3102
  dispatchCommand(editor, KEY_ENTER_COMMAND, event);
2112
- } else if (isDeleteBackward(event)) if (isBackspace(event)) dispatchCommand(editor, KEY_BACKSPACE_COMMAND, event);
2113
- else {
3103
+ } else if (isDeleteBackward(event)) if (isBackspace(event)) {
3104
+ if (dispatchCommand(editor, KEY_BACKSPACE_COMMAND, event)) markHandledSelectionCommandInsertText();
3105
+ } else {
2114
3106
  event.preventDefault();
2115
3107
  dispatchCommand(editor, DELETE_CHARACTER_COMMAND, true);
2116
3108
  }
@@ -2150,20 +3142,17 @@ function $handleKeyDown(event) {
2150
3142
  dispatchCommand(editor, REDO_COMMAND, void 0);
2151
3143
  } else {
2152
3144
  const prevSelection = editor._editorState._selection;
2153
- if (prevSelection !== null && !$isRangeSelection(prevSelection)) {
3145
+ if (isSelectAll(event)) {
3146
+ event.preventDefault();
3147
+ if (dispatchCommand(editor, SELECT_ALL_COMMAND, event)) markHandledSelectionCommandInsertText();
3148
+ } else if (prevSelection !== null && !$isRangeSelection(prevSelection)) {
2154
3149
  if (isCopy(event)) {
2155
3150
  event.preventDefault();
2156
3151
  dispatchCommand(editor, COPY_COMMAND, event);
2157
3152
  } else if (isCut(event)) {
2158
3153
  event.preventDefault();
2159
3154
  dispatchCommand(editor, CUT_COMMAND, event);
2160
- } else if (isSelectAll(event)) {
2161
- event.preventDefault();
2162
- dispatchCommand(editor, SELECT_ALL_COMMAND, event);
2163
3155
  }
2164
- } else if (isSelectAll(event)) {
2165
- event.preventDefault();
2166
- dispatchCommand(editor, SELECT_ALL_COMMAND, event);
2167
3156
  }
2168
3157
  }
2169
3158
  if (isModifier(event)) editor.dispatchCommand(KEY_MODIFIER_COMMAND, event);
@@ -2201,6 +3190,7 @@ function onDocumentSelectionChange(event) {
2201
3190
  if (nextActiveEditor !== rootEditor) activeNestedEditorsMap.set(rootEditorKey, nextActiveEditor);
2202
3191
  else if (activeNestedEditor) activeNestedEditorsMap.delete(rootEditorKey);
2203
3192
  }
3193
+ /** @internal */
2204
3194
  function stopLexicalPropagation(event) {
2205
3195
  event._lexicalHandled = true;
2206
3196
  }
@@ -2393,6 +3383,13 @@ function $markEphemeral(node) {
2393
3383
  node[EPHEMERAL] = true;
2394
3384
  return node;
2395
3385
  }
3386
+ /** @internal */
3387
+ const NON_ENUMERABLE_PROP_DESC = {
3388
+ configurable: true,
3389
+ enumerable: false,
3390
+ value: void 0,
3391
+ writable: true
3392
+ };
2396
3393
  var LexicalNode = class {
2397
3394
  /** @internal Allow us to look up the type including static props */
2398
3395
  /** @internal */
@@ -2407,6 +3404,8 @@ var LexicalNode = class {
2407
3404
  __next;
2408
3405
  /** @internal */
2409
3406
  __state;
3407
+ /** @internal */
3408
+ [CACHED_TEXT_SIZE_KEY];
2410
3409
  /**
2411
3410
  * Returns the string type of this node. Every node must
2412
3411
  * implement this and it MUST BE UNIQUE amongst nodes registered
@@ -2530,12 +3529,8 @@ var LexicalNode = class {
2530
3529
  this.__parent = null;
2531
3530
  this.__prev = null;
2532
3531
  this.__next = null;
2533
- Object.defineProperty(this, "__state", {
2534
- configurable: true,
2535
- enumerable: false,
2536
- value: void 0,
2537
- writable: true
2538
- });
3532
+ Object.defineProperty(this, "__state", NON_ENUMERABLE_PROP_DESC);
3533
+ Object.defineProperty(this, CACHED_TEXT_SIZE_KEY, NON_ENUMERABLE_PROP_DESC);
2539
3534
  $setNodeKey(this, key);
2540
3535
  if (this.__type !== "root") errorOnTypeKlassMismatch(this.__type, this.constructor);
2541
3536
  }
@@ -2916,6 +3911,23 @@ var LexicalNode = class {
2916
3911
  formatDevErrorMessage(`updateDOM: base method not extended`);
2917
3912
  }
2918
3913
  /**
3914
+ * Returns a {@link DOMSlot} pointing at the content-bearing element of this
3915
+ * node's DOM. The default returns a slot wrapping the keyed DOM as-is.
3916
+ *
3917
+ * Override this when {@link createDOM} returns a wrapper around the
3918
+ * content-bearing element (e.g. `<span><br/></span>` for a styled line
3919
+ * break), so selection / reconciliation logic can target the inner element.
3920
+ *
3921
+ * {@link ElementNode} overrides this to return an {@link ElementDOMSlot}
3922
+ * with children-management semantics (used by the reconciler to place
3923
+ * managed children).
3924
+ *
3925
+ * @experimental
3926
+ */
3927
+ getDOMSlot(element) {
3928
+ return new DOMSlot(element);
3929
+ }
3930
+ /**
2919
3931
  * Controls how the this node is serialized to HTML. This is important for
2920
3932
  * copy and paste between Lexical and non-Lexical editors, or Lexical editors with different namespaces,
2921
3933
  * in which case the primary transfer format is HTML. It's also important if you're serializing
@@ -3023,7 +4035,10 @@ var LexicalNode = class {
3023
4035
  const writableReplaceWith = replaceWith.getWritable();
3024
4036
  const writableParent = this.getParentOrThrow().getWritable();
3025
4037
  const size = writableParent.__size;
4038
+ const replaceWithOldParent = writableReplaceWith.getParent();
4039
+ const replaceWithOldIndex = replaceWithOldParent !== null ? writableReplaceWith.getIndexWithinParent() : -1;
3026
4040
  removeFromParent(writableReplaceWith);
4041
+ if (replaceWithOldParent !== null && $isRangeSelection(selection)) $updateElementSelectionOnCreateDeleteNode(selection, replaceWithOldParent, replaceWithOldIndex, -1);
3027
4042
  const prevSibling = self.getPreviousSibling();
3028
4043
  const nextSibling = self.getNextSibling();
3029
4044
  const prevKey = self.__prev;
@@ -3044,18 +4059,20 @@ var LexicalNode = class {
3044
4059
  writableReplaceWith.__next = nextKey;
3045
4060
  writableReplaceWith.__parent = parentKey;
3046
4061
  writableParent.__size = size;
4062
+ let prevSizeBeforeChildrenTransfer = 0;
3047
4063
  if (includeChildren) {
3048
4064
  if (!($isElementNode(this) && $isElementNode(writableReplaceWith))) formatDevErrorMessage(`includeChildren should only be true for ElementNodes`);
3049
- this.getChildren().forEach((child) => {
3050
- writableReplaceWith.append(child);
3051
- });
4065
+ prevSizeBeforeChildrenTransfer = writableReplaceWith.getChildrenSize();
4066
+ writableReplaceWith.splice(prevSizeBeforeChildrenTransfer, 0, this.getChildren());
3052
4067
  }
3053
4068
  if ($isRangeSelection(selection)) {
3054
4069
  $setSelection(selection);
3055
4070
  const anchor = selection.anchor;
3056
4071
  const focus = selection.focus;
3057
- if (anchor.key === toReplaceKey) $moveSelectionPointToEnd(anchor, writableReplaceWith);
3058
- if (focus.key === toReplaceKey) $moveSelectionPointToEnd(focus, writableReplaceWith);
4072
+ if (anchor.key === toReplaceKey) if (includeChildren && anchor.type === "element") anchor.set(writableReplaceWith.__key, prevSizeBeforeChildrenTransfer + anchor.offset, "element");
4073
+ else $moveSelectionPointToEnd(anchor, writableReplaceWith);
4074
+ if (focus.key === toReplaceKey) if (includeChildren && focus.type === "element") focus.set(writableReplaceWith.__key, prevSizeBeforeChildrenTransfer + focus.offset, "element");
4075
+ else $moveSelectionPointToEnd(focus, writableReplaceWith);
3059
4076
  }
3060
4077
  if ($getCompositionKey() === toReplaceKey) $setCompositionKey(key);
3061
4078
  return writableReplaceWith;
@@ -3078,7 +4095,6 @@ var LexicalNode = class {
3078
4095
  let elementFocusSelectionOnNode = false;
3079
4096
  if (oldParent !== null) {
3080
4097
  const oldIndex = nodeToInsert.getIndexWithinParent();
3081
- removeFromParent(writableNodeToInsert);
3082
4098
  if ($isRangeSelection(selection)) {
3083
4099
  const oldParentKey = oldParent.__key;
3084
4100
  const anchor = selection.anchor;
@@ -3086,6 +4102,8 @@ var LexicalNode = class {
3086
4102
  elementAnchorSelectionOnNode = anchor.type === "element" && anchor.key === oldParentKey && anchor.offset === oldIndex + 1;
3087
4103
  elementFocusSelectionOnNode = focus.type === "element" && focus.key === oldParentKey && focus.offset === oldIndex + 1;
3088
4104
  }
4105
+ removeFromParent(writableNodeToInsert);
4106
+ if (restoreSelection && $isRangeSelection(selection)) $updateElementSelectionOnCreateDeleteNode(selection, oldParent, oldIndex, -1);
3089
4107
  }
3090
4108
  const nextSibling = this.getNextSibling();
3091
4109
  const writableParent = this.getParentOrThrow().getWritable();
@@ -3123,7 +4141,11 @@ var LexicalNode = class {
3123
4141
  const writableSelf = this.getWritable();
3124
4142
  const writableNodeToInsert = nodeToInsert.getWritable();
3125
4143
  const insertKey = writableNodeToInsert.__key;
4144
+ const selection = $getSelection();
4145
+ const insertOldParent = writableNodeToInsert.getParent();
4146
+ const insertOldIndex = insertOldParent !== null ? writableNodeToInsert.getIndexWithinParent() : -1;
3126
4147
  removeFromParent(writableNodeToInsert);
4148
+ if (insertOldParent !== null && restoreSelection && $isRangeSelection(selection)) $updateElementSelectionOnCreateDeleteNode(selection, insertOldParent, insertOldIndex, -1);
3127
4149
  const prevSibling = this.getPreviousSibling();
3128
4150
  const writableParent = this.getParentOrThrow().getWritable();
3129
4151
  const prevKey = writableSelf.__prev;
@@ -3138,7 +4160,6 @@ var LexicalNode = class {
3138
4160
  writableNodeToInsert.__prev = prevKey;
3139
4161
  writableNodeToInsert.__next = writableSelf.__key;
3140
4162
  writableNodeToInsert.__parent = writableSelf.__parent;
3141
- const selection = $getSelection();
3142
4163
  if (restoreSelection && $isRangeSelection(selection)) $updateElementSelectionOnCreateDeleteNode(selection, this.getParentOrThrow(), index);
3143
4164
  return nodeToInsert;
3144
4165
  }
@@ -3570,22 +4591,27 @@ function diffComposedText(a, b) {
3570
4591
  b.slice(left, bLength - right)
3571
4592
  ];
3572
4593
  }
3573
- function setTextContent(nextText, dom, node) {
3574
- const firstChild = dom.firstChild;
4594
+ function $setTextContent(nextText, dom, node) {
3575
4595
  const isComposing = node.isComposing();
3576
4596
  const text = nextText + (isComposing ? COMPOSITION_SUFFIX : "");
3577
- if (firstChild == null) dom.textContent = text;
3578
- else {
3579
- const nodeValue = firstChild.nodeValue;
3580
- if (nodeValue !== text) if (isComposing || IS_FIREFOX) {
3581
- const [index, remove, insert] = diffComposedText(nodeValue, text);
3582
- if (remove !== 0) firstChild.deleteData(index, remove);
3583
- firstChild.insertData(index, insert);
3584
- } else firstChild.nodeValue = text;
4597
+ const editor = $getEditor();
4598
+ const slot = $getEditorDOMRenderConfig(editor).$getDOMSlot(node, dom, editor);
4599
+ const firstChild = slot.getFirstChild();
4600
+ if (firstChild === null || firstChild.nodeType !== Node.TEXT_NODE) {
4601
+ slot.insertChild(document.createTextNode(text));
4602
+ return;
3585
4603
  }
3586
- }
3587
- function createTextInnerDOM(innerDOM, node, innerTag, format, text, config) {
3588
- setTextContent(text, innerDOM, node);
4604
+ const textChild = firstChild;
4605
+ const nodeValue = textChild.nodeValue;
4606
+ if (nodeValue === text) return;
4607
+ if (isComposing || IS_FIREFOX) {
4608
+ const [index, remove, insert] = diffComposedText(nodeValue, text);
4609
+ if (remove !== 0) textChild.deleteData(index, remove);
4610
+ textChild.insertData(index, insert);
4611
+ } else textChild.nodeValue = text;
4612
+ }
4613
+ function $createTextInnerDOM(innerDOM, node, innerTag, format, text, config) {
4614
+ $setTextContent(text, innerDOM, node);
3589
4615
  const textClassNames = config.theme.text;
3590
4616
  if (textClassNames !== void 0) setTextThemeClassNames(innerTag, 0, format, innerDOM, textClassNames);
3591
4617
  }
@@ -3770,7 +4796,7 @@ var TextNode = class TextNode extends LexicalNode {
3770
4796
  dom.appendChild(innerDOM);
3771
4797
  }
3772
4798
  const text = this.__text;
3773
- createTextInnerDOM(innerDOM, this, innerTag, format, text, config);
4799
+ $createTextInnerDOM(innerDOM, this, innerTag, format, text, config);
3774
4800
  const style = this.__style;
3775
4801
  if (style !== "") setDOMStyleFromCSS(dom.style, style);
3776
4802
  return dom;
@@ -3788,7 +4814,7 @@ var TextNode = class TextNode extends LexicalNode {
3788
4814
  const prevInnerDOM = dom.firstChild;
3789
4815
  if (prevInnerDOM == null) formatDevErrorMessage(`updateDOM: prevInnerDOM is null or undefined`);
3790
4816
  const nextInnerDOM = document.createElement(nextInnerTag);
3791
- createTextInnerDOM(nextInnerDOM, this, nextInnerTag, nextFormat, nextText, config);
4817
+ $createTextInnerDOM(nextInnerDOM, this, nextInnerTag, nextFormat, nextText, config);
3792
4818
  dom.replaceChild(nextInnerDOM, prevInnerDOM);
3793
4819
  return false;
3794
4820
  }
@@ -3799,7 +4825,7 @@ var TextNode = class TextNode extends LexicalNode {
3799
4825
  if (innerDOM == null) formatDevErrorMessage(`updateDOM: innerDOM is null or undefined`);
3800
4826
  }
3801
4827
  }
3802
- setTextContent(nextText, innerDOM, this);
4828
+ $setTextContent(nextText, innerDOM, this);
3803
4829
  const textClassNames = config.theme.text;
3804
4830
  if (textClassNames !== void 0 && prevFormat !== nextFormat) setTextThemeClassNames(nextInnerTag, prevFormat, nextFormat, innerDOM, textClassNames);
3805
4831
  const prevStyle = prevNode.__style;
@@ -4447,6 +5473,7 @@ var Point = class {
4447
5473
  if ($getCompositionKey() === oldKey) $setCompositionKey(key);
4448
5474
  if (selection !== null) {
4449
5475
  selection.setCachedNodes(null);
5476
+ if ($isRangeSelection(selection)) selection._cachedIsBackward = null;
4450
5477
  selection.dirty = true;
4451
5478
  }
4452
5479
  }
@@ -4611,6 +5638,8 @@ var RangeSelection = class RangeSelection {
4611
5638
  anchor;
4612
5639
  focus;
4613
5640
  _cachedNodes;
5641
+ /** @internal */
5642
+ _cachedIsBackward;
4614
5643
  dirty;
4615
5644
  constructor(anchor, focus, format, style) {
4616
5645
  this.anchor = anchor;
@@ -4618,6 +5647,7 @@ var RangeSelection = class RangeSelection {
4618
5647
  anchor._selection = this;
4619
5648
  focus._selection = this;
4620
5649
  this._cachedNodes = null;
5650
+ this._cachedIsBackward = null;
4621
5651
  this.format = format;
4622
5652
  this.style = style;
4623
5653
  this.dirty = false;
@@ -4677,6 +5707,7 @@ var RangeSelection = class RangeSelection {
4677
5707
  setTextNodeRange(anchorNode, anchorOffset, focusNode, focusOffset) {
4678
5708
  this.anchor.set(anchorNode.__key, anchorOffset, "text");
4679
5709
  this.focus.set(focusNode.__key, focusOffset, "text");
5710
+ return this;
4680
5711
  }
4681
5712
  /**
4682
5713
  * Gets the (plain) text content of all the nodes in the selection.
@@ -4725,9 +5756,10 @@ var RangeSelection = class RangeSelection {
4725
5756
  const lastSelection = editor.getEditorState()._selection;
4726
5757
  const resolvedSelectionPoints = $internalResolveSelectionPoints(range.startContainer, range.startOffset, range.endContainer, range.endOffset, editor, lastSelection);
4727
5758
  if (resolvedSelectionPoints === null) return;
4728
- const [anchorPoint, focusPoint] = resolvedSelectionPoints;
5759
+ const [anchorPoint, focusPoint, dirty] = resolvedSelectionPoints;
4729
5760
  this.anchor.set(anchorPoint.key, anchorPoint.offset, anchorPoint.type, true);
4730
5761
  this.focus.set(focusPoint.key, focusPoint.offset, focusPoint.type, true);
5762
+ if (dirty) this.dirty = true;
4731
5763
  $normalizeSelection(this);
4732
5764
  }
4733
5765
  /**
@@ -4785,16 +5817,7 @@ var RangeSelection = class RangeSelection {
4785
5817
  * @param text the text to insert into the Selection
4786
5818
  */
4787
5819
  insertRawText(text) {
4788
- const parts = text.split(/(\r?\n|\t)/);
4789
- const nodes = [];
4790
- const length = parts.length;
4791
- for (let i = 0; i < length; i++) {
4792
- const part = parts[i];
4793
- if (part === "\n" || part === "\r\n") nodes.push($createLineBreakNode());
4794
- else if (part === " ") nodes.push($createTabNode());
4795
- else nodes.push($createTextNode(part));
4796
- }
4797
- this.insertNodes(nodes);
5820
+ this.insertNodes($generateNodesFromRawText(text));
4798
5821
  }
4799
5822
  /**
4800
5823
  * Insert the provided text into the EditorState at the current Selection.
@@ -4892,7 +5915,11 @@ var RangeSelection = class RangeSelection {
4892
5915
  const [targetNode] = firstNode.splitText(startOffset);
4893
5916
  targetNode.insertAfter(textNode, false);
4894
5917
  }
4895
- if (textNode.isComposing() && this.anchor.type === "text") this.anchor.offset -= text.length;
5918
+ if (textNode.isComposing() && this.anchor.type === "text") {
5919
+ this.anchor.offset -= text.length;
5920
+ this._cachedNodes = null;
5921
+ this._cachedIsBackward = null;
5922
+ }
4896
5923
  return;
4897
5924
  }
4898
5925
  else if ($isTabNode(firstNode)) {
@@ -4909,7 +5936,11 @@ var RangeSelection = class RangeSelection {
4909
5936
  else if (this.anchor.type === "text") {
4910
5937
  this.format = firstNodeFormat;
4911
5938
  this.style = firstNodeStyle;
4912
- if (firstNode.isComposing()) this.anchor.offset -= text.length;
5939
+ if (firstNode.isComposing()) {
5940
+ this.anchor.offset -= text.length;
5941
+ this._cachedNodes = null;
5942
+ this._cachedIsBackward = null;
5943
+ }
4913
5944
  }
4914
5945
  } else {
4915
5946
  const markedNodeKeysForKeep = new Set([...firstNode.getParentKeys(), ...lastNode.getParentKeys()]);
@@ -4964,7 +5995,11 @@ var RangeSelection = class RangeSelection {
4964
5995
  else if (this.anchor.type === "text") {
4965
5996
  this.format = firstNode.getFormat();
4966
5997
  this.style = firstNode.getStyle();
4967
- if (firstNode.isComposing()) this.anchor.offset -= text.length;
5998
+ if (firstNode.isComposing()) {
5999
+ this.anchor.offset -= text.length;
6000
+ this._cachedNodes = null;
6001
+ this._cachedIsBackward = null;
6002
+ }
4968
6003
  }
4969
6004
  } else if (startOffset === firstNodeTextLength) firstNode.select();
4970
6005
  else {
@@ -5238,10 +6273,18 @@ var RangeSelection = class RangeSelection {
5238
6273
  const focusNode = this.focus.getNode();
5239
6274
  if (rootElement !== null && blockCursorElement !== null && $isElementNode(focusNode) && !focusNode.isInline() && !focusNode.canBeEmpty()) removeDOMBlockCursorElement(blockCursorElement, editor, rootElement);
5240
6275
  if (this.dirty) {
5241
- let nextAnchorDOM = getElementByKeyOrThrow(editor, this.anchor.key);
5242
- let nextFocusDOM = getElementByKeyOrThrow(editor, this.focus.key);
5243
- if (this.anchor.type === "text") nextAnchorDOM = getDOMTextNode(nextAnchorDOM);
5244
- if (this.focus.type === "text") nextFocusDOM = getDOMTextNode(nextFocusDOM);
6276
+ const anchorKeyedDOM = getElementByKeyOrThrow(editor, this.anchor.key);
6277
+ const focusKeyedDOM = getElementByKeyOrThrow(editor, this.focus.key);
6278
+ let nextAnchorDOM = anchorKeyedDOM;
6279
+ let nextFocusDOM = focusKeyedDOM;
6280
+ if (this.anchor.type === "text") {
6281
+ const node = this.anchor.getNode();
6282
+ nextAnchorDOM = $isTextNode(node) ? $getDOMTextNode(node, anchorKeyedDOM, editor) : null;
6283
+ }
6284
+ if (this.focus.type === "text") {
6285
+ const node = this.focus.getNode();
6286
+ nextFocusDOM = $isTextNode(node) ? $getDOMTextNode(node, focusKeyedDOM, editor) : null;
6287
+ }
5245
6288
  if (nextAnchorDOM && nextFocusDOM) setDOMSelectionBaseAndExtent(domSelection, nextAnchorDOM, this.anchor.offset, nextFocusDOM, this.focus.offset);
5246
6289
  }
5247
6290
  moveNativeSelection(domSelection, alter, isBackward ? "backward" : "forward", granularity);
@@ -5343,6 +6386,10 @@ var RangeSelection = class RangeSelection {
5343
6386
  }
5344
6387
  if (state.type === "merge-block") {
5345
6388
  const { caret, block } = state;
6389
+ if (caret.origin.isEmpty() && !block.isEmpty() && caret.origin.getParent() === block.getParent()) {
6390
+ caret.origin.remove(true);
6391
+ return;
6392
+ }
5346
6393
  $updateRangeSelectionFromCaretRange(this, $getCaretRange(!caret.origin.isEmpty() && block.isEmpty() ? $rewindSiblingCaret($getSiblingCaret(block, caret.direction)) : initialRange.anchor, caret));
5347
6394
  return this.removeText();
5348
6395
  }
@@ -5411,7 +6458,11 @@ var RangeSelection = class RangeSelection {
5411
6458
  * @returns true if the Selection is backwards, false otherwise.
5412
6459
  */
5413
6460
  isBackward() {
5414
- return this.focus.isBefore(this.anchor);
6461
+ const cached = this._cachedIsBackward;
6462
+ if (cached !== null) return cached;
6463
+ const isBackward = this.focus.isBefore(this.anchor);
6464
+ if (!isCurrentlyReadOnlyMode()) this._cachedIsBackward = isBackward;
6465
+ return isBackward;
5415
6466
  }
5416
6467
  getStartEndPoints() {
5417
6468
  return [this.anchor, this.focus];
@@ -5593,15 +6644,17 @@ function shouldResolveAncestor(resolvedElement, resolvedOffset, lastPoint) {
5593
6644
  function $internalResolveSelectionPoint(dom, offset, lastPoint, editor) {
5594
6645
  let resolvedOffset = offset;
5595
6646
  let resolvedNode;
6647
+ let dirty = false;
5596
6648
  if (isHTMLElement(dom)) {
5597
6649
  let moveSelectionToEnd = false;
5598
6650
  const childNodes = dom.childNodes;
5599
6651
  const childNodesLength = childNodes.length;
5600
6652
  const blockCursorElement = editor._blockCursorElement;
5601
- if (resolvedOffset === childNodesLength) {
6653
+ if (resolvedOffset === childNodesLength && childNodesLength > 0) {
5602
6654
  moveSelectionToEnd = true;
5603
6655
  resolvedOffset = childNodesLength - 1;
5604
6656
  }
6657
+ if (getNodeKeyFromDOMNode(dom, editor) === void 0 && dom !== editor.getRootElement() && !$isSelectionCapturedInDecorator(dom)) dirty = true;
5605
6658
  let childDOM = childNodes[resolvedOffset];
5606
6659
  let hasBlockCursor = false;
5607
6660
  if (childDOM === blockCursorElement) {
@@ -5621,7 +6674,7 @@ function $internalResolveSelectionPoint(dom, offset, lastPoint, editor) {
5621
6674
  if ($isElementNode(resolvedElement)) {
5622
6675
  const elementDOM = editor.getElementByKey(resolvedElement.getKey());
5623
6676
  if (!(elementDOM !== null)) formatDevErrorMessage(`$internalResolveSelectionPoint: node in DOM but not keyToDOMMap`);
5624
- const slot = $getEditorDOMRenderConfig(editor).$getDOMSlot(resolvedElement, elementDOM, editor);
6677
+ const slot = $getDOMSlot(resolvedElement, elementDOM, editor);
5625
6678
  [resolvedElement, resolvedOffset] = slot.resolveChildIndex(resolvedElement, elementDOM, dom, offset);
5626
6679
  if (!$isElementNode(resolvedElement)) formatDevErrorMessage(`$internalResolveSelectionPoint: resolvedElement is not an ElementNode`);
5627
6680
  if (moveSelectionToEnd && resolvedOffset >= resolvedElement.getChildrenSize()) resolvedOffset = Math.max(0, resolvedElement.getChildrenSize() - 1);
@@ -5645,15 +6698,21 @@ function $internalResolveSelectionPoint(dom, offset, lastPoint, editor) {
5645
6698
  }
5646
6699
  } else {
5647
6700
  const index = resolvedElement.getIndexWithinParent();
5648
- if (offset === 0 && $isDecoratorNode(resolvedElement) && $getNodeFromDOM(dom) === resolvedElement) resolvedOffset = index;
5649
- else resolvedOffset = index + 1;
6701
+ const elementDOM = editor.getElementByKey(resolvedElement.getKey());
6702
+ let position = "after";
6703
+ if (elementDOM !== null && $getNodeFromDOM(dom) === resolvedElement) {
6704
+ const slot = $getDOMSlot(resolvedElement, elementDOM, editor);
6705
+ if (slot.element !== elementDOM) position = slot.resolveLeafPosition(elementDOM, dom, offset);
6706
+ else if (offset === 0 && $isDecoratorNode(resolvedElement)) position = "before";
6707
+ }
6708
+ resolvedOffset = position === "before" ? index : index + 1;
5650
6709
  resolvedElement = resolvedElement.getParentOrThrow();
5651
6710
  }
5652
- if ($isElementNode(resolvedElement)) return $createPoint(resolvedElement.__key, resolvedOffset, "element");
6711
+ if ($isElementNode(resolvedElement)) return [$createPoint(resolvedElement.__key, resolvedOffset, "element"), dirty];
5653
6712
  }
5654
6713
  } else resolvedNode = $getNodeFromDOM(dom);
5655
6714
  if (!$isTextNode(resolvedNode)) return null;
5656
- return $createPoint(resolvedNode.__key, $getTextNodeOffset(resolvedNode, resolvedOffset, "clamp"), "text");
6715
+ return [$createPoint(resolvedNode.__key, $getTextNodeOffset(resolvedNode, resolvedOffset, "clamp"), "text"), dirty];
5657
6716
  }
5658
6717
  function resolveSelectionPointOnBoundary(point, isBackward, isCollapsed) {
5659
6718
  const offset = point.offset;
@@ -5689,10 +6748,12 @@ function $normalizeSelectionPointsForBoundaries(anchor, focus, lastSelection) {
5689
6748
  }
5690
6749
  function $internalResolveSelectionPoints(anchorDOM, anchorOffset, focusDOM, focusOffset, editor, lastSelection) {
5691
6750
  if (anchorDOM === null || focusDOM === null || !isSelectionWithinEditor(editor, anchorDOM, focusDOM)) return null;
5692
- const resolvedAnchorPoint = $internalResolveSelectionPoint(anchorDOM, anchorOffset, $isRangeSelection(lastSelection) ? lastSelection.anchor : null, editor);
5693
- if (resolvedAnchorPoint === null) return null;
5694
- const resolvedFocusPoint = $internalResolveSelectionPoint(focusDOM, focusOffset, $isRangeSelection(lastSelection) ? lastSelection.focus : null, editor);
5695
- if (resolvedFocusPoint === null) return null;
6751
+ const resolvedAnchor = $internalResolveSelectionPoint(anchorDOM, anchorOffset, $isRangeSelection(lastSelection) ? lastSelection.anchor : null, editor);
6752
+ if (resolvedAnchor === null) return null;
6753
+ const resolvedFocus = $internalResolveSelectionPoint(focusDOM, focusOffset, $isRangeSelection(lastSelection) ? lastSelection.focus : null, editor);
6754
+ if (resolvedFocus === null) return null;
6755
+ const [resolvedAnchorPoint, anchorDirty] = resolvedAnchor;
6756
+ const [resolvedFocusPoint, focusDirty] = resolvedFocus;
5696
6757
  $validatePoint("anchor", resolvedAnchorPoint);
5697
6758
  $validatePoint("focus", resolvedFocusPoint);
5698
6759
  if (resolvedAnchorPoint.type === "element" && resolvedFocusPoint.type === "element") {
@@ -5701,7 +6762,11 @@ function $internalResolveSelectionPoints(anchorDOM, anchorOffset, focusDOM, focu
5701
6762
  if ($isDecoratorNode(anchorNode) && $isDecoratorNode(focusNode)) return null;
5702
6763
  }
5703
6764
  $normalizeSelectionPointsForBoundaries(resolvedAnchorPoint, resolvedFocusPoint);
5704
- return [resolvedAnchorPoint, resolvedFocusPoint];
6765
+ return [
6766
+ resolvedAnchorPoint,
6767
+ resolvedFocusPoint,
6768
+ anchorDirty || focusDirty
6769
+ ];
5705
6770
  }
5706
6771
  function $isBlockElementNode(node) {
5707
6772
  return $isElementNode(node) && !node.isInline();
@@ -5746,7 +6811,7 @@ function $internalCreateRangeSelection(lastSelection, domSelection, editor, even
5746
6811
  } else return lastSelection.clone();
5747
6812
  const resolvedSelectionPoints = $internalResolveSelectionPoints(anchorDOM, anchorOffset, focusDOM, focusOffset, editor, lastSelection);
5748
6813
  if (resolvedSelectionPoints === null) return null;
5749
- const [resolvedAnchorPoint, resolvedFocusPoint] = resolvedSelectionPoints;
6814
+ const [resolvedAnchorPoint, resolvedFocusPoint, dirty] = resolvedSelectionPoints;
5750
6815
  let format = 0;
5751
6816
  let style = "";
5752
6817
  if ($isRangeSelection(lastSelection)) {
@@ -5765,7 +6830,9 @@ function $internalCreateRangeSelection(lastSelection, domSelection, editor, even
5765
6830
  }
5766
6831
  }
5767
6832
  }
5768
- return new RangeSelection(resolvedAnchorPoint, resolvedFocusPoint, format, style);
6833
+ const newSelection = new RangeSelection(resolvedAnchorPoint, resolvedFocusPoint, format, style);
6834
+ if (dirty) newSelection.dirty = true;
6835
+ return newSelection;
5769
6836
  }
5770
6837
  function $validatePoint(name, point) {
5771
6838
  const node = $getNodeByKey(point.key);
@@ -5915,20 +6982,17 @@ function setDOMSelectionBaseAndExtent(domSelection, nextAnchorDOM, nextAnchorOff
5915
6982
  function $getElementAndOffsetForPoint(editor, node, offset) {
5916
6983
  const element = getElementByKeyOrThrow(editor, node.getKey());
5917
6984
  if ($isElementNode(node)) {
5918
- const slot = $getEditorDOMRenderConfig(editor).$getDOMSlot(node, element, editor);
6985
+ const slot = $getDOMSlot(node, element, editor);
5919
6986
  return [slot.element, offset + slot.getFirstChildOffset()];
5920
6987
  }
5921
6988
  return [element, offset];
5922
6989
  }
5923
- function $updateDOMSelection(prevSelection, nextSelection, editor, domSelection, tags, rootElement, nodeCount) {
5924
- const anchorDOMNode = domSelection.anchorNode;
5925
- const focusDOMNode = domSelection.focusNode;
5926
- const anchorOffset = domSelection.anchorOffset;
5927
- const focusOffset = domSelection.focusOffset;
6990
+ /** @internal */
6991
+ function $updateDOMSelection(prevSelection, nextSelection, editor, domSelection, tags, rootElement) {
5928
6992
  const activeElement = document.activeElement;
5929
6993
  if (tags.has("collaboration") && activeElement !== rootElement || activeElement !== null && isSelectionCapturedInDecoratorInput(activeElement)) return;
5930
6994
  if (!$isRangeSelection(nextSelection)) {
5931
- if (prevSelection !== null && isSelectionWithinEditor(editor, anchorDOMNode, focusDOMNode)) domSelection.removeAllRanges();
6995
+ if (prevSelection !== null && isSelectionWithinEditor(editor, domSelection.anchorNode, domSelection.focusNode)) domSelection.removeAllRanges();
5932
6996
  return;
5933
6997
  }
5934
6998
  const anchor = nextSelection.anchor;
@@ -5944,13 +7008,13 @@ function $updateDOMSelection(prevSelection, nextSelection, editor, domSelection,
5944
7008
  let nextFocusNode = focusDOM;
5945
7009
  let anchorFormatOrStyleChanged = false;
5946
7010
  if (anchor.type === "text") {
5947
- nextAnchorNode = getDOMTextNode(anchorDOM);
7011
+ nextAnchorNode = $isTextNode(anchorNode) ? $getDOMTextNode(anchorNode, anchorDOM, editor) : null;
5948
7012
  anchorFormatOrStyleChanged = anchorNode.getFormat() !== nextFormat || anchorNode.getStyle() !== nextStyle;
5949
7013
  } else if ($isRangeSelection(prevSelection) && prevSelection.anchor.type === "text") anchorFormatOrStyleChanged = true;
5950
- if (focus.type === "text") nextFocusNode = getDOMTextNode(focusDOM);
7014
+ if (focus.type === "text") nextFocusNode = $isTextNode(focusNode) ? $getDOMTextNode(focusNode, focusDOM, editor) : null;
5951
7015
  if (nextAnchorNode === null || nextFocusNode === null) return;
5952
7016
  if (isCollapsed && (prevSelection === null || anchorFormatOrStyleChanged || $isRangeSelection(prevSelection) && (prevSelection.format !== nextFormat || prevSelection.style !== nextStyle))) markCollapsedSelectionFormat(nextFormat, nextStyle, nextAnchorOffset, anchor.key, performance.now());
5953
- if (anchorOffset === nextAnchorOffset && focusOffset === nextFocusOffset && anchorDOMNode === nextAnchorNode && focusDOMNode === nextFocusNode && !(domSelection.type === "Range" && isCollapsed)) {
7017
+ if (!(domSelection.type === "Range" && isCollapsed) && domSelection.anchorOffset === nextAnchorOffset && domSelection.focusOffset === nextFocusOffset && domSelection.anchorNode === nextAnchorNode && domSelection.focusNode === nextFocusNode) {
5954
7018
  if (activeElement === null || !rootElement.contains(activeElement)) {
5955
7019
  if (!tags.has("skip-selection-focus")) rootElement.focus({ preventScroll: true });
5956
7020
  }
@@ -5977,6 +7041,46 @@ function $insertNodes(nodes) {
5977
7041
  if (selection === null) selection = $getRoot().selectEnd();
5978
7042
  selection.insertNodes(nodes);
5979
7043
  }
7044
+ /**
7045
+ * Push-lexer visitor passed to {@link tokenizeRawText}. The tokenizer
7046
+ * invokes one callback per token it emits; empty text runs are
7047
+ * suppressed, so `text` is only invoked with a non-empty string.
7048
+ */
7049
+ /**
7050
+ * Push-lex a raw text string into `linebreak` (`\n` / `\r\n`), `tab`
7051
+ * (`\t`), and `text` (everything else) tokens, dispatching each to the
7052
+ * matching callback on `visitor` in source order.
7053
+ *
7054
+ * Shared by {@link $generateNodesFromRawText} (which builds
7055
+ * `LineBreakNode` / `TabNode` / `TextNode` siblings) and by
7056
+ * `@lexical/clipboard`'s default `text/plain` clipboard importer
7057
+ * (which maps `linebreak` to a real paragraph break via
7058
+ * `insertParagraph` so multi-line plain text becomes multi-paragraph
7059
+ * rich text). Empty text runs are dropped so callers don't need to
7060
+ * special-case them.
7061
+ */
7062
+ function tokenizeRawText(text, visitor) {
7063
+ for (const part of text.split(/(\r?\n|\t)/)) if (part === "\n" || part === "\r\n") visitor.linebreak();
7064
+ else if (part === " ") visitor.tab();
7065
+ else if (part !== "") visitor.text(part);
7066
+ }
7067
+ /**
7068
+ * Convert a raw text string into a flat array of `TextNode`,
7069
+ * `LineBreakNode`, and `TabNode` siblings, splitting on `\n`, `\r\n`,
7070
+ * and `\t`. Use this when you need the same `\n` / `\t` → real-node
7071
+ * conversion that {@link RangeSelection.insertRawText} performs but
7072
+ * without a selection — e.g. when building a `CodeNode`'s children
7073
+ * inside a DOM-import rule.
7074
+ */
7075
+ function $generateNodesFromRawText(text) {
7076
+ const nodes = [];
7077
+ tokenizeRawText(text, {
7078
+ linebreak: () => nodes.push($createLineBreakNode()),
7079
+ tab: () => nodes.push($createTabNode()),
7080
+ text: (part) => nodes.push($createTextNode(part))
7081
+ });
7082
+ return nodes;
7083
+ }
5980
7084
  function $getTextContent() {
5981
7085
  const selection = $getSelection();
5982
7086
  if (selection === null) return "";
@@ -6161,6 +7265,18 @@ function getActiveEditor() {
6161
7265
  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()}`);
6162
7266
  return activeEditor;
6163
7267
  }
7268
+ /**
7269
+ * Schedule a full reconcile of the active editor, so that every node is
7270
+ * re-rendered through the current {@link EditorDOMRenderConfig} on the next
7271
+ * commit. Unlike {@link LexicalNode.markDirty}, this does not clone or
7272
+ * otherwise mutate the node map, so no mutation/collaboration listeners
7273
+ * observe a change. Must be called within an `editor.update`.
7274
+ *
7275
+ * @internal
7276
+ */
7277
+ function $fullReconcile() {
7278
+ getActiveEditor()._dirtyType = FULL_RECONCILE;
7279
+ }
6164
7280
  function collectBuildInformation() {
6165
7281
  let compatibleEditors = 0;
6166
7282
  const incompatibleEditors = /* @__PURE__ */ new Set();
@@ -6302,7 +7418,7 @@ function parseEditorState(serializedEditorState, editor, updateFn) {
6302
7418
  editor._dirtyElements = /* @__PURE__ */ new Map();
6303
7419
  editor._dirtyLeaves = /* @__PURE__ */ new Set();
6304
7420
  editor._cloneNotNeeded = /* @__PURE__ */ new Set();
6305
- editor._dirtyType = 0;
7421
+ editor._dirtyType = NO_DIRTY_NODES;
6306
7422
  activeEditorState = editorState;
6307
7423
  isReadOnlyMode = false;
6308
7424
  activeEditor = editor;
@@ -6438,7 +7554,7 @@ function $commitPendingUpdates(editor, recoveryEditorState) {
6438
7554
  if (blockCursorElement !== null) removeDOMBlockCursorElement(blockCursorElement, editor, rootElement);
6439
7555
  $updateDOMSelection(currentSelection, pendingSelection, editor, domSelection, tags, rootElement);
6440
7556
  }
6441
- updateDOMBlockCursorElement(editor, rootElement, pendingSelection);
7557
+ $updateDOMBlockCursorElement(editor, rootElement, pendingSelection);
6442
7558
  } finally {
6443
7559
  if (observer !== null) observer.observe(rootElement, observerOptions);
6444
7560
  activeEditor = previousActiveEditor;
@@ -6536,12 +7652,24 @@ function triggerCommandListeners(editor, type, payload, fromEditor) {
6536
7652
  }
6537
7653
  function $triggerEnqueuedUpdates(editor) {
6538
7654
  const queuedUpdates = editor._updates;
6539
- if (queuedUpdates.length !== 0) {
6540
- const queuedUpdate = queuedUpdates.shift();
6541
- if (queuedUpdate) {
6542
- const [updateFn, options] = queuedUpdate;
6543
- $beginUpdate(editor, updateFn, options);
7655
+ if (queuedUpdates.length === 0) {
7656
+ editor._cascadeCount = 0;
7657
+ return;
7658
+ }
7659
+ if (editor._cascadeCount++ > 99) {
7660
+ editor._updates = [];
7661
+ 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);
6544
7666
  }
7667
+ return;
7668
+ }
7669
+ const queuedUpdate = queuedUpdates.shift();
7670
+ if (queuedUpdate) {
7671
+ const [updateFn, options] = queuedUpdate;
7672
+ $beginUpdate(editor, updateFn, options);
6545
7673
  }
6546
7674
  }
6547
7675
  function triggerDeferredUpdateCallbacks(editor, deferred) {
@@ -6680,167 +7808,6 @@ function updateEditor(editor, updateFn, options) {
6680
7808
  if (editor._updating) editor._updates.push([updateFn, options]);
6681
7809
  else $beginUpdate(editor, updateFn, options);
6682
7810
  }
6683
- /**
6684
- * A utility class for managing the DOM children of an ElementNode
6685
- */
6686
- var ElementDOMSlot = class ElementDOMSlot {
6687
- element;
6688
- before;
6689
- after;
6690
- constructor(element, before, after) {
6691
- this.element = element;
6692
- this.before = before || null;
6693
- this.after = after || null;
6694
- }
6695
- /**
6696
- * Return a new ElementDOMSlot where all managed children will be inserted before this node
6697
- */
6698
- withBefore(before) {
6699
- return new ElementDOMSlot(this.element, before, this.after);
6700
- }
6701
- /**
6702
- * Return a new ElementDOMSlot where all managed children will be inserted after this node
6703
- */
6704
- withAfter(after) {
6705
- return new ElementDOMSlot(this.element, this.before, after);
6706
- }
6707
- /**
6708
- * Return a new ElementDOMSlot with an updated root element
6709
- */
6710
- withElement(element) {
6711
- if (this.element === element) return this;
6712
- return new ElementDOMSlot(element, this.before, this.after);
6713
- }
6714
- /**
6715
- * Insert the given child before this.before and any reconciler managed line break node,
6716
- * or append it if this.before is not defined
6717
- */
6718
- insertChild(dom) {
6719
- const before = this.before || this.getManagedLineBreak();
6720
- if (!(before === null || before.parentElement === this.element)) formatDevErrorMessage(`ElementDOMSlot.insertChild: before is not in element`);
6721
- this.element.insertBefore(dom, before);
6722
- return this;
6723
- }
6724
- /**
6725
- * Remove the managed child from this container, will throw if it was not already there
6726
- */
6727
- removeChild(dom) {
6728
- if (!(dom.parentElement === this.element)) formatDevErrorMessage(`ElementDOMSlot.removeChild: dom is not in element`);
6729
- this.element.removeChild(dom);
6730
- return this;
6731
- }
6732
- /**
6733
- * Replace managed child prevDom with dom. Will throw if prevDom is not a child
6734
- *
6735
- * @param dom The new node to replace prevDom
6736
- * @param prevDom the node that will be replaced
6737
- */
6738
- replaceChild(dom, prevDom) {
6739
- if (!(prevDom.parentElement === this.element)) formatDevErrorMessage(`ElementDOMSlot.replaceChild: prevDom is not in element`);
6740
- this.element.replaceChild(dom, prevDom);
6741
- return this;
6742
- }
6743
- /**
6744
- * Returns the first managed child of this node,
6745
- * which will either be this.after.nextSibling or this.element.firstChild,
6746
- * and will never be this.before if it is defined.
6747
- */
6748
- getFirstChild() {
6749
- const firstChild = this.after ? this.after.nextSibling : this.element.firstChild;
6750
- return firstChild === this.before || firstChild === this.getManagedLineBreak() ? null : firstChild;
6751
- }
6752
- /**
6753
- * @internal
6754
- */
6755
- getManagedLineBreak() {
6756
- return this.element.__lexicalLineBreak || null;
6757
- }
6758
- /** @internal */
6759
- setManagedLineBreak(lineBreakType) {
6760
- if (lineBreakType === null) this.removeManagedLineBreak();
6761
- else {
6762
- const webkitHack = lineBreakType === "decorator" && (IS_APPLE_WEBKIT || IS_IOS || IS_SAFARI);
6763
- this.insertManagedLineBreak(webkitHack);
6764
- }
6765
- }
6766
- /** @internal */
6767
- removeManagedLineBreak() {
6768
- const br = this.getManagedLineBreak();
6769
- if (br) {
6770
- const element = this.element;
6771
- const sibling = br.nodeName === "IMG" ? br.nextSibling : null;
6772
- if (sibling) element.removeChild(sibling);
6773
- element.removeChild(br);
6774
- element.__lexicalLineBreak = void 0;
6775
- }
6776
- }
6777
- /** @internal */
6778
- insertManagedLineBreak(webkitHack) {
6779
- const prevBreak = this.getManagedLineBreak();
6780
- if (prevBreak) {
6781
- if (webkitHack === (prevBreak.nodeName === "IMG")) return;
6782
- this.removeManagedLineBreak();
6783
- }
6784
- const element = this.element;
6785
- const before = this.before;
6786
- const br = document.createElement("br");
6787
- element.insertBefore(br, before);
6788
- if (webkitHack) {
6789
- const img = document.createElement("img");
6790
- img.setAttribute("data-lexical-linebreak", "true");
6791
- img.style.setProperty("display", "inline", "important");
6792
- img.style.setProperty("border", "0px", "important");
6793
- img.style.setProperty("margin", "0px", "important");
6794
- img.alt = "";
6795
- element.insertBefore(img, br);
6796
- element.__lexicalLineBreak = img;
6797
- } else element.__lexicalLineBreak = br;
6798
- }
6799
- /**
6800
- * @internal
6801
- *
6802
- * Returns the offset of the first child
6803
- */
6804
- getFirstChildOffset() {
6805
- let i = 0;
6806
- for (let node = this.after; node !== null; node = node.previousSibling) i++;
6807
- return i;
6808
- }
6809
- /**
6810
- * @internal
6811
- */
6812
- resolveChildIndex(element, elementDOM, initialDOM, initialOffset) {
6813
- if (initialDOM === this.element) {
6814
- const firstChildOffset = this.getFirstChildOffset();
6815
- return [element, Math.min(firstChildOffset + element.getChildrenSize(), Math.max(firstChildOffset, initialOffset))];
6816
- }
6817
- const initialPath = indexPath(elementDOM, initialDOM);
6818
- initialPath.push(initialOffset);
6819
- const elementPath = indexPath(elementDOM, this.element);
6820
- let offset = element.getIndexWithinParent();
6821
- for (let i = 0; i < elementPath.length; i++) {
6822
- const target = initialPath[i];
6823
- const source = elementPath[i];
6824
- if (target === void 0 || target < source) break;
6825
- else if (target > source) {
6826
- offset += 1;
6827
- break;
6828
- }
6829
- }
6830
- return [element.getParentOrThrow(), offset];
6831
- }
6832
- };
6833
- function indexPath(root, child) {
6834
- const path = [];
6835
- let node = child;
6836
- for (; node !== root && node !== null; node = node.parentNode) {
6837
- let i = 0;
6838
- for (let sibling = node.previousSibling; sibling !== null; sibling = sibling.previousSibling) i++;
6839
- path.push(i);
6840
- }
6841
- if (!(node === root)) formatDevErrorMessage(`indexPath: root is not a parent of child`);
6842
- return path.reverse();
6843
- }
6844
7811
  /** @noInheritDoc */
6845
7812
  var ElementNode = class extends LexicalNode {
6846
7813
  /** @internal */
@@ -7214,12 +8181,12 @@ var ElementNode = class extends LexicalNode {
7214
8181
  return writableSelf;
7215
8182
  }
7216
8183
  /**
7217
- * @internal
8184
+ * @experimental
7218
8185
  *
7219
- * An experimental API that an ElementNode can override to control where its
7220
- * children are inserted into the DOM, this is useful to add a wrapping node
7221
- * or accessory nodes before or after the children. The root of the node returned
7222
- * by createDOM must still be exactly one HTMLElement.
8186
+ * An ElementNode subclass can override this to control where its children
8187
+ * are inserted into the DOM, e.g. to add a wrapping node or accessory nodes
8188
+ * before or after the children. The root of the node returned by createDOM
8189
+ * must still be exactly one HTMLElement.
7223
8190
  */
7224
8191
  getDOMSlot(element) {
7225
8192
  return new ElementDOMSlot(element);
@@ -7228,7 +8195,10 @@ var ElementNode = class extends LexicalNode {
7228
8195
  const { element } = super.exportDOM(editor);
7229
8196
  if (isHTMLElement(element)) {
7230
8197
  const indent = this.getIndent();
7231
- if (indent > 0) element.style.paddingInlineStart = `${indent * 40}px`;
8198
+ if (indent > 0) {
8199
+ element.style.paddingInlineStart = `${indent * 40}px`;
8200
+ element.setAttribute("data-lexical-indent", String(indent));
8201
+ }
7232
8202
  const direction = this.getDirection();
7233
8203
  if (direction) element.dir = direction;
7234
8204
  }
@@ -7282,6 +8252,10 @@ var ElementNode = class extends LexicalNode {
7282
8252
  canInsertTextAfter() {
7283
8253
  return true;
7284
8254
  }
8255
+ /**
8256
+ * If the method is overridden and returns true, ensure that `canBeEmpty()`
8257
+ * returns false for the inline node to work correctly
8258
+ */
7285
8259
  isInline() {
7286
8260
  return false;
7287
8261
  }
@@ -7313,7 +8287,7 @@ var ElementNode = class extends LexicalNode {
7313
8287
  }
7314
8288
  /** @internal */
7315
8289
  reconcileObservedMutation(dom, editor) {
7316
- const slot = $getEditorDOMRenderConfig(editor).$getDOMSlot(this, dom, editor);
8290
+ const slot = $getDOMSlot(this, dom, editor);
7317
8291
  let currentDOM = slot.getFirstChild();
7318
8292
  for (let currentNode = this.getFirstChild(); currentNode; currentNode = currentNode.getNextSibling()) {
7319
8293
  const correctDOM = editor.getElementByKey(currentNode.getKey());
@@ -7386,10 +8360,7 @@ var RootNode = class RootNode extends ElementNode {
7386
8360
  }
7387
8361
  getTextContent() {
7388
8362
  const cachedText = this.__cachedText;
7389
- if (isCurrentlyReadOnlyMode() || getActiveEditor()._dirtyType === NO_DIRTY_NODES) {
7390
- if (cachedText !== null) return cachedText;
7391
- }
7392
- return super.getTextContent();
8363
+ return cachedText !== null && (isCurrentlyReadOnlyMode() || getActiveEditor()._dirtyType === NO_DIRTY_NODES) ? cachedText : super.getTextContent();
7393
8364
  }
7394
8365
  remove() {
7395
8366
  formatDevErrorMessage(`remove: cannot be called on root nodes`);
@@ -7432,7 +8403,7 @@ function editorStateHasDirtySelection(editorState, editor) {
7432
8403
  return false;
7433
8404
  }
7434
8405
  function cloneEditorState(current) {
7435
- return new EditorState(new Map(current._nodeMap));
8406
+ return new EditorState(cloneMap(current._nodeMap));
7436
8407
  }
7437
8408
  function createEmptyEditorState() {
7438
8409
  return new EditorState(new Map([["root", $createRootNode()]]));
@@ -7588,16 +8559,15 @@ var ParagraphNode = class ParagraphNode extends ElementNode {
7588
8559
  };
7589
8560
  function $convertParagraphElement(element) {
7590
8561
  const node = $createParagraphNode();
7591
- if (element.style) {
7592
- node.setFormat(element.style.textAlign);
7593
- setNodeIndentFromDOM(element, node);
7594
- }
8562
+ $setFormatFromDOM(node, element);
8563
+ setNodeIndentFromDOM(element, node);
7595
8564
  if (node.getFormatType() === "") {
7596
8565
  const align = element.getAttribute("align");
7597
8566
  if (align) {
7598
8567
  if (align && align in ELEMENT_TYPE_TO_FORMAT) node.setFormat(align);
7599
8568
  }
7600
8569
  }
8570
+ $setDirectionFromDOM(node, element);
7601
8571
  return { node };
7602
8572
  }
7603
8573
  function $createParagraphNode() {
@@ -7607,8 +8577,24 @@ function $isParagraphNode(node) {
7607
8577
  return node instanceof ParagraphNode;
7608
8578
  }
7609
8579
  /**
8580
+ * Configuration entry passed in {@link CreateEditorArgs.nodes} to substitute
8581
+ * a core node class with a custom subclass. The replacement class itself
8582
+ * must also appear in `nodes`.
8583
+ *
8584
+ * See [Node Replacement](https://lexical.dev/docs/concepts/node-replacement).
8585
+ */
8586
+ /**
7610
8587
  * A LexicalNode class or LexicalNodeReplacement configuration
7611
8588
  */
8589
+ /**
8590
+ * @experimental
8591
+ *
8592
+ * The slot type produced by `$getDOMSlot` for a given node, narrowed via
8593
+ * the node's static class: `ElementNode` resolves to {@link ElementDOMSlot}
8594
+ * (with children-management methods), other nodes to the base
8595
+ * {@link DOMSlot}. Callers passing a known node type get the narrowed slot
8596
+ * without manual `instanceof` checks.
8597
+ */
7612
8598
  /** @internal @experimental */
7613
8599
  const DEFAULT_SKIP_INITIALIZATION = false;
7614
8600
  /**
@@ -7690,7 +8676,16 @@ function normalizePriority(priority) {
7690
8676
  * }
7691
8677
  * ```
7692
8678
  */
7693
- function resetEditor(editor, prevRootElement, nextRootElement, pendingEditorState) {
8679
+ /** @internal */
8680
+ /**
8681
+ * @internal
8682
+ *
8683
+ * Resets the editor's transient state — DOM mappings, dirty tracking,
8684
+ * composition, and (by default) the queued updates and tags — while
8685
+ * applying the given pendingEditorState. Used during root element
8686
+ * transitions and reconciler error recovery.
8687
+ */
8688
+ function resetEditor(editor, prevRootElement, nextRootElement, pendingEditorState, options) {
7694
8689
  const keyNodeMap = editor._keyToDOMMap;
7695
8690
  keyNodeMap.clear();
7696
8691
  editor._editorState = createEmptyEditorState();
@@ -7701,8 +8696,11 @@ function resetEditor(editor, prevRootElement, nextRootElement, pendingEditorStat
7701
8696
  editor._dirtyLeaves = /* @__PURE__ */ new Set();
7702
8697
  editor._dirtyElements.clear();
7703
8698
  editor._normalizedNodes = /* @__PURE__ */ new Set();
7704
- editor._updateTags = /* @__PURE__ */ new Set();
7705
- editor._updates = [];
8699
+ if (!options || !options.preserveUpdateQueue) {
8700
+ editor._updateTags = /* @__PURE__ */ new Set();
8701
+ editor._updates = [];
8702
+ editor._cascadeCount = 0;
8703
+ }
7706
8704
  editor._blockCursorElement = null;
7707
8705
  const observer = editor._observer;
7708
8706
  if (observer !== null) {
@@ -7771,10 +8769,7 @@ const DEFAULT_EDITOR_DOM_CONFIG = {
7771
8769
  return registeredNode && registeredNode.exportDOM !== void 0 ? registeredNode.exportDOM(editor, node) : node.exportDOM(editor);
7772
8770
  },
7773
8771
  $extractWithChild: (node, childNode, selection, destination, _editor) => $isElementNode(node) && node.extractWithChild(childNode, selection, destination),
7774
- $getDOMSlot: (node, dom, _editor) => {
7775
- if (!$isElementNode(node)) formatDevErrorMessage(`$getDOMSlot called on a non-ElementNode (key ${node.getKey()} type ${node.getType()})`);
7776
- return node.getDOMSlot(dom);
7777
- },
8772
+ $getDOMSlot: (node, dom, _editor) => node.getDOMSlot(dom),
7778
8773
  $shouldExclude: (node, _selection, _editor) => $isElementNode(node) && node.excludeFromCopy("html"),
7779
8774
  $shouldInclude: (node, selection, _editor) => selection ? node.isSelected(selection) : true,
7780
8775
  $updateDOM: (nextNode, prevNode, dom, editor) => nextNode.updateDOM(prevNode, dom, editor._config)
@@ -7902,6 +8897,8 @@ var LexicalEditor = class {
7902
8897
  /** @internal */
7903
8898
  _updating;
7904
8899
  /** @internal */
8900
+ _cascadeCount;
8901
+ /** @internal */
7905
8902
  _listeners;
7906
8903
  /** @internal */
7907
8904
  _commands;
@@ -7950,9 +8947,10 @@ var LexicalEditor = class {
7950
8947
  this._pendingEditorState = null;
7951
8948
  this._compositionKey = null;
7952
8949
  this._deferred = [];
7953
- this._keyToDOMMap = /* @__PURE__ */ new Map();
8950
+ this._keyToDOMMap = new GenMap();
7954
8951
  this._updates = [];
7955
8952
  this._updating = false;
8953
+ this._cascadeCount = 0;
7956
8954
  this._listeners = {
7957
8955
  decorator: /* @__PURE__ */ new Map(),
7958
8956
  editable: /* @__PURE__ */ new Map(),
@@ -8247,7 +9245,7 @@ var LexicalEditor = class {
8247
9245
  const classNames = getCachedClassNameArray(this._config.theme, "root");
8248
9246
  const pendingEditorState = this._pendingEditorState || this._editorState;
8249
9247
  this._rootElement = nextRootElement;
8250
- resetEditor(this, prevRootElement, nextRootElement, pendingEditorState);
9248
+ resetEditor(this, prevRootElement, nextRootElement, pendingEditorState, { preserveUpdateQueue: true });
8251
9249
  if (prevRootElement !== null) {
8252
9250
  if (!this._config.disableEvents) removeRootElementEvents(prevRootElement);
8253
9251
  if (classNames != null) prevRootElement.classList.remove(...classNames);
@@ -8421,7 +9419,7 @@ var LexicalEditor = class {
8421
9419
  return { editorState: this._editorState.toJSON() };
8422
9420
  }
8423
9421
  };
8424
- LexicalEditor.version = "0.44.0+dev.esm";
9422
+ LexicalEditor.version = LEXICAL_VERSION;
8425
9423
  let pendingNodeToClone = null;
8426
9424
  function setPendingNodeToClone(pendingNode) {
8427
9425
  pendingNodeToClone = pendingNode;
@@ -8569,7 +9567,7 @@ function $setNodeKey(node, existingKey) {
8569
9567
  if ($isElementNode(node)) editor._dirtyElements.set(key, true);
8570
9568
  else editor._dirtyLeaves.add(key);
8571
9569
  editor._cloneNotNeeded.add(key);
8572
- editor._dirtyType = HAS_DIRTY_NODES;
9570
+ if (editor._dirtyType === NO_DIRTY_NODES) editor._dirtyType = HAS_DIRTY_NODES;
8573
9571
  node.__key = key;
8574
9572
  }
8575
9573
  function errorOnNodeKeyConstructorMismatch(node, existingKey, pendingNode) {
@@ -8596,6 +9594,12 @@ function internalMarkParentElementsAsDirty(parentKey, nodeMap, dirtyElements) {
8596
9594
  * Removes a node from its parent, updating all necessary pointers and links.
8597
9595
  * @internal
8598
9596
  *
9597
+ * This function does not adjust the editor's current selection. Callers
9598
+ * that need element-anchored offsets in the old parent to track the child
9599
+ * count change must call `$updateElementSelectionOnCreateDeleteNode` (with
9600
+ * `times = -1`) after invoking this — see `$removeNode`, `replace`,
9601
+ * `insertBefore`, and `insertAfter` for the pattern.
9602
+ *
8599
9603
  * This function is for internal use of the library.
8600
9604
  * Please do not use it as it may change in the future.
8601
9605
  */
@@ -8631,7 +9635,7 @@ function internalMarkNodeAsDirty(node) {
8631
9635
  const dirtyElements = editor._dirtyElements;
8632
9636
  if (parent !== null) internalMarkParentElementsAsDirty(parent, nodeMap, dirtyElements);
8633
9637
  const key = latest.__key;
8634
- editor._dirtyType = HAS_DIRTY_NODES;
9638
+ if (editor._dirtyType === NO_DIRTY_NODES) editor._dirtyType = HAS_DIRTY_NODES;
8635
9639
  if ($isElementNode(node)) dirtyElements.set(key, true);
8636
9640
  else editor._dirtyLeaves.add(key);
8637
9641
  }
@@ -8847,9 +9851,17 @@ function $setTextContentWithSelection(node, textContent, selection) {
8847
9851
  node.setTextContent(textContent);
8848
9852
  if ($isRangeSelection(selection)) {
8849
9853
  const key = node.getKey();
9854
+ let pointMutated = false;
8850
9855
  for (const k of ["anchor", "focus"]) {
8851
9856
  const pt = selection[k];
8852
- if (pt.type === "text" && pt.key === key) pt.offset = $getTextNodeOffset(node, pt.offset, "clamp");
9857
+ if (pt.type === "text" && pt.key === key) {
9858
+ pt.offset = $getTextNodeOffset(node, pt.offset, "clamp");
9859
+ pointMutated = true;
9860
+ }
9861
+ }
9862
+ if (pointMutated) {
9863
+ selection._cachedNodes = null;
9864
+ selection._cachedIsBackward = null;
8853
9865
  }
8854
9866
  }
8855
9867
  }
@@ -8988,13 +10000,19 @@ function isMoveBackward(event) {
8988
10000
  return isExactShortcutMatch(event, "ArrowLeft", { shiftKey: "any" });
8989
10001
  }
8990
10002
  function isMoveToStart(event) {
8991
- return isExactShortcutMatch(event, "ArrowLeft", CONTROL_OR_META);
10003
+ return isExactShortcutMatch(event, "ArrowLeft", {
10004
+ ...CONTROL_OR_META,
10005
+ shiftKey: "any"
10006
+ });
8992
10007
  }
8993
10008
  function isMoveForward(event) {
8994
10009
  return isExactShortcutMatch(event, "ArrowRight", { shiftKey: "any" });
8995
10010
  }
8996
10011
  function isMoveToEnd(event) {
8997
- return isExactShortcutMatch(event, "ArrowRight", CONTROL_OR_META);
10012
+ return isExactShortcutMatch(event, "ArrowRight", {
10013
+ ...CONTROL_OR_META,
10014
+ shiftKey: "any"
10015
+ });
8998
10016
  }
8999
10017
  function isMoveUp(event) {
9000
10018
  return isExactShortcutMatch(event, "ArrowUp", {
@@ -9145,8 +10163,15 @@ function scrollIntoViewIfNeeded(editor, selectionRect, rootElement) {
9145
10163
  while (element !== null) {
9146
10164
  const isBodyElement = element === doc.body;
9147
10165
  if (isBodyElement) {
9148
- targetTop = 0;
9149
- targetBottom = getWindow(editor).innerHeight;
10166
+ const visualViewport = defaultView.visualViewport;
10167
+ if (visualViewport) {
10168
+ const offsetTop = visualViewport.offsetTop;
10169
+ targetTop = offsetTop;
10170
+ targetBottom = offsetTop + visualViewport.height;
10171
+ } else {
10172
+ targetTop = 0;
10173
+ targetBottom = getWindow(editor).innerHeight;
10174
+ }
9150
10175
  const computedStyle = defaultView.getComputedStyle(doc.documentElement);
9151
10176
  const scrollPaddingTop = parseFloat(computedStyle.scrollPaddingTop);
9152
10177
  const scrollPaddingBottom = parseFloat(computedStyle.scrollPaddingBottom);
@@ -9295,7 +10320,7 @@ function removeDOMBlockCursorElement(blockCursorElement, editor, rootElement) {
9295
10320
  const parentElement = blockCursorElement.parentElement;
9296
10321
  if (parentElement !== null) parentElement.removeChild(blockCursorElement);
9297
10322
  }
9298
- function updateDOMBlockCursorElement(editor, rootElement, nextSelection) {
10323
+ function $updateDOMBlockCursorElement(editor, rootElement, nextSelection) {
9299
10324
  let blockCursorElement = editor._blockCursorElement;
9300
10325
  if ($isRangeSelection(nextSelection) && nextSelection.isCollapsed() && nextSelection.anchor.type === "element" && rootElement.contains(document.activeElement)) {
9301
10326
  const anchor = nextSelection.anchor;
@@ -9317,7 +10342,7 @@ function updateDOMBlockCursorElement(editor, rootElement, nextSelection) {
9317
10342
  }
9318
10343
  }
9319
10344
  if (isBlockCursor) {
9320
- const elementDOM = editor.getElementByKey(elementNode.__key);
10345
+ const elementDOM = $getDOMSlot(elementNode, editor.getElementByKey(elementNode.__key), editor).element;
9321
10346
  if (blockCursorElement === null) editor._blockCursorElement = blockCursorElement = createBlockCursorElement(editor._config);
9322
10347
  rootElement.style.caretColor = "transparent";
9323
10348
  if (insertBeforeElement === null) elementDOM.appendChild(blockCursorElement);
@@ -9386,6 +10411,21 @@ function isHTMLAnchorElement(x) {
9386
10411
  }
9387
10412
  /**
9388
10413
  * @param x - The element being tested
10414
+ * @returns Returns true if x is an HTML `<tr>` element, false otherwise
10415
+ */
10416
+ function isHTMLTableRowElement(x) {
10417
+ return isHTMLElement(x) && x.tagName === "TR";
10418
+ }
10419
+ /**
10420
+ * @param x - The element being tested
10421
+ * @returns Returns true if x is an HTML `<td>` or `<th>` element, false
10422
+ * otherwise
10423
+ */
10424
+ function isHTMLTableCellElement(x) {
10425
+ return isHTMLElement(x) && (x.tagName === "TD" || x.tagName === "TH");
10426
+ }
10427
+ /**
10428
+ * @param x - The element being tested
9389
10429
  * @returns Returns true if x is an HTML element, false otherwise.
9390
10430
  */
9391
10431
  function isHTMLElement(x) {
@@ -9405,18 +10445,23 @@ function isDOMNode(x) {
9405
10445
  function isDocumentFragment(x) {
9406
10446
  return isDOMNode(x) && x.nodeType === DOM_DOCUMENT_FRAGMENT_TYPE;
9407
10447
  }
10448
+ const INLINE_TAG_RE = /^(a|abbr|acronym|b|cite|code|del|em|i|ins|kbd|label|mark|output|q|ruby|s|samp|span|strong|sub|sup|time|u|tt|var|#text)$/i;
9408
10449
  /**
9409
10450
  *
9410
10451
  * @param node - the Dom Node to check
9411
10452
  * @returns if the Dom Node is an inline node
9412
10453
  */
9413
10454
  function isInlineDomNode(node) {
9414
- const inlineNodes = /* @__PURE__ */ new RegExp(/^(a|abbr|acronym|b|cite|code|del|em|i|ins|kbd|label|mark|output|q|ruby|s|samp|span|strong|sub|sup|time|u|tt|var|#text)$/, "i");
9415
- return node.nodeName.match(inlineNodes) !== null;
10455
+ return isHTMLElement(node) && node.style.display.startsWith("inline") ? true : INLINE_TAG_RE.test(node.nodeName);
9416
10456
  }
10457
+ const BLOCK_TAG_RE = /^(address|article|aside|blockquote|canvas|dd|div|dl|dt|fieldset|figcaption|figure|footer|form|h1|h2|h3|h4|h5|h6|header|hr|li|main|nav|noscript|ol|p|pre|section|table|td|tfoot|ul|video)$/i;
10458
+ /**
10459
+ *
10460
+ * @param node - the Dom Node to check
10461
+ * @returns if the Dom Node is a block node
10462
+ */
9417
10463
  function isBlockDomNode(node) {
9418
- const blockNodes = /* @__PURE__ */ new RegExp(/^(address|article|aside|blockquote|canvas|dd|div|dl|dt|fieldset|figcaption|figure|footer|form|h1|h2|h3|h4|h5|h6|header|hr|li|main|nav|noscript|ol|p|pre|section|table|td|tfoot|ul|video)$/, "i");
9419
- return node.nodeName.match(blockNodes) !== null;
10464
+ return isHTMLElement(node) && node.style.display.startsWith("inline") ? false : BLOCK_TAG_RE.test(node.nodeName);
9420
10465
  }
9421
10466
  /**
9422
10467
  * @internal
@@ -9446,11 +10491,57 @@ function $getEditor() {
9446
10491
  return getActiveEditor();
9447
10492
  }
9448
10493
  /**
9449
- * @internal @experimental
10494
+ * @experimental
10495
+ *
10496
+ * Read the editor's `$getDOMSlot` configuration (defaulting to the base
10497
+ * implementation when no override is registered via {@link DOMRenderExtension}).
10498
+ * Cross-package consumers (`@lexical/utils`, `@lexical/react`) use this to
10499
+ * route selection / DOM lookups through extension-configured slots.
9450
10500
  */
9451
10501
  function $getEditorDOMRenderConfig(editor = $getEditor()) {
9452
10502
  return editor._config.dom || DEFAULT_EDITOR_DOM_CONFIG;
9453
10503
  }
10504
+ /**
10505
+ * @experimental
10506
+ *
10507
+ * Resolve the DOM slot for a node through the configured `$getDOMSlot` hook,
10508
+ * narrowing the return type via {@link DOMSlotForNode}: for an `ElementNode`
10509
+ * the result is an {@link ElementDOMSlot} (with children-management methods),
10510
+ * for non-Element nodes the base {@link DOMSlot} pointing at the keyed DOM.
10511
+ *
10512
+ * Invariants if an extension override returns a slot that doesn't match the
10513
+ * expected narrow type for the node (extension contract violation).
10514
+ */
10515
+ function $getDOMSlot(node, dom, editor = $getEditor()) {
10516
+ const slot = $getEditorDOMRenderConfig(editor).$getDOMSlot(node, dom, editor);
10517
+ if ($isElementNode(node)) {
10518
+ if (!$isElementDOMSlot(slot)) formatDevErrorMessage(`$getDOMSlot: expected ElementDOMSlot for ElementNode (key ${node.getKey()} type ${node.getType()})`);
10519
+ }
10520
+ return slot;
10521
+ }
10522
+ /**
10523
+ * @experimental
10524
+ *
10525
+ * Type guard narrowing a {@link DOMSlot} to an {@link ElementDOMSlot}, which
10526
+ * exposes children-management methods like `insertChild` and the managed
10527
+ * line-break helpers.
10528
+ */
10529
+ function $isElementDOMSlot(slot) {
10530
+ return slot instanceof ElementDOMSlot;
10531
+ }
10532
+ /**
10533
+ * @experimental
10534
+ *
10535
+ * Resolve the actual text DOM (`Text`) for a `TextNode` through the
10536
+ * configured `$getDOMSlot` hook. Unlike the plain {@link getDOMTextNode}
10537
+ * which descends the first child chain from a raw element, this routes
10538
+ * through the slot so an extension wrapping the text node's keyed DOM
10539
+ * (e.g. one that injects a `contentEditable=false` sibling before the
10540
+ * text) still points at the correct content element.
10541
+ */
10542
+ function $getDOMTextNode(node, dom, editor = $getEditor()) {
10543
+ return getDOMTextNode($getDOMSlot(node, dom, editor).element);
10544
+ }
9454
10545
  /** @internal */
9455
10546
  /**
9456
10547
  * @internal
@@ -9522,24 +10613,63 @@ function $cloneWithPropertiesEphemeral(latestNode) {
9522
10613
  return $markEphemeral($cloneWithProperties(latestNode));
9523
10614
  }
9524
10615
  function setNodeIndentFromDOM(elementDom, elementNode) {
10616
+ const indentAttr = elementDom.getAttribute("data-lexical-indent");
10617
+ if (indentAttr !== null) {
10618
+ const parsed = parseInt(indentAttr, 10);
10619
+ if (Number.isFinite(parsed) && parsed >= 0) {
10620
+ elementNode.setIndent(parsed);
10621
+ return;
10622
+ }
10623
+ }
9525
10624
  const indentSize = parseInt(elementDom.style.paddingInlineStart, 10) || 0;
9526
10625
  const indent = Math.round(indentSize / 40);
9527
10626
  elementNode.setIndent(indent);
9528
10627
  }
9529
10628
  /**
9530
- * @internal
10629
+ * Reads the `dir` attribute from a DOM element and applies it to the given
10630
+ * ElementNode via {@link ElementNode.setDirection} when it is a valid direction
10631
+ * value (`'ltr'` or `'rtl'`). Other values, including missing or empty `dir`,
10632
+ * leave the node unchanged. Useful inside `importDOM` converters to preserve
10633
+ * explicit text direction from imported HTML.
10634
+ *
10635
+ * @param node - The ElementNode to update.
10636
+ * @param domNode - The source HTMLElement whose `dir` attribute is read.
10637
+ * @returns The node, with its direction set when the source `dir` was valid.
10638
+ */
10639
+ function $setDirectionFromDOM(node, domNode) {
10640
+ const dir = domNode.getAttribute("dir");
10641
+ return dir === "ltr" || dir === "rtl" ? node.setDirection(dir) : node;
10642
+ }
10643
+ /**
10644
+ * Reads the `style` and CSS `textAlign` property from a DOM element
10645
+ * and set format to the given ElementNode via {@link ElementNode.setFormat}
10646
+ * when it is a valid alignment value {@link ElementFormatType}
10647
+ * Other values, including missing or empty, leave the node unchanged.
10648
+ * Useful inside `importDOM` converters to preserve explicit alignment from imported HTML.
10649
+ *
10650
+ * @param node - The ElementNode to update.
10651
+ * @param domNode - The source HTMLElement whose `style` property is read.
10652
+ * @returns The node, with its align format set when the source `style.textAlign` was valid.
10653
+ */
10654
+ function $setFormatFromDOM(node, domNode) {
10655
+ const alignment = domNode.style.textAlign;
10656
+ return alignment && alignment in ELEMENT_TYPE_TO_FORMAT ? node.setFormat(alignment) : node;
10657
+ }
10658
+ /**
10659
+ * Mark this DOM element as unmanaged by lexical's mutation observer (like
10660
+ * decorator nodes are). Extensions that inject non-lexical decoration
10661
+ * elements into a node's DOM should mark them so the mutation observer
10662
+ * doesn't evict them as "unknown DOM children" during cleanup.
9531
10663
  *
9532
- * Mark this node as unmanaged by lexical's mutation observer like
9533
- * decorator nodes
10664
+ * @experimental
9534
10665
  */
9535
10666
  function setDOMUnmanaged(elementDom) {
9536
- const el = elementDom;
9537
- el.__lexicalUnmanaged = true;
10667
+ elementDom.__lexicalUnmanaged = true;
9538
10668
  }
9539
10669
  /**
9540
- * @internal
10670
+ * True if this DOM node was marked with {@link setDOMUnmanaged}.
9541
10671
  *
9542
- * True if this DOM node was marked with {@link setDOMUnmanaged}
10672
+ * @experimental
9543
10673
  */
9544
10674
  function isDOMUnmanaged(elementDom) {
9545
10675
  return elementDom.__lexicalUnmanaged === true;
@@ -10987,4 +12117,4 @@ function mergeRegister(...func) {
10987
12117
  };
10988
12118
  }
10989
12119
  //#endregion
10990
- export { $addUpdateTag, $applyNodeReplacement, $caretFromPoint, $caretRangeFromSelection, $cloneWithProperties, $cloneWithPropertiesEphemeral, $comparePointCaretNext, $copyNode, $create, $createChildrenArray, $createLineBreakNode, $createNodeSelection, $createParagraphNode, $createPoint, $createRangeSelection, $createRangeSelectionFromDom, $createTabNode, $createTextNode, $extendCaretToRange, $findMatchingParent, $getAdjacentChildCaret, $getAdjacentNode, $getAdjacentSiblingOrParentSiblingCaret, $getCaretInDirection, $getCaretRange, $getCaretRangeInDirection, $getCharacterOffsets, $getChildCaret, $getChildCaretAtIndex, $getChildCaretOrSelf, $getCollapsedCaretRange, $getCommonAncestor, $getCommonAncestorResultBranchOrder, $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, $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, $setPointFromCaret, $setSelection, $setSelectionFromCaretRange, $setState, $splitAtPointCaretNext, $splitNode, $updateRangeSelectionFromCaretRange, ArtificialNode__DO_NOT_USE, BEFORE_INPUT_COMMAND, BLUR_COMMAND, CAN_REDO_COMMAND, CAN_UNDO_COMMAND, 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_BOLD, IS_CODE, IS_HIGHLIGHT, IS_ITALIC, 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, isInlineDomNode, isLexicalEditor, isModifierMatch, isSelectionCapturedInDecoratorInput, isSelectionWithinEditor, makeStepwiseIterator, mergeRegister, normalizeClassNames, removeClassNamesFromElement, removeFromParent, resetRandomKey, safeCast, setDOMStyleFromCSS, setDOMStyleObject, setDOMUnmanaged, setNodeIndentFromDOM, shallowMergeConfig, toggleTextFormatType };
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 };