@beyondwork/docx-react-component 1.0.132 → 1.0.133

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 (94) hide show
  1. package/dist/api/public-types.cjs +158 -67
  2. package/dist/api/public-types.d.cts +1 -1
  3. package/dist/api/public-types.d.ts +1 -1
  4. package/dist/api/public-types.js +3 -3
  5. package/dist/api/v3.cjs +9326 -7478
  6. package/dist/api/v3.d.cts +2 -2
  7. package/dist/api/v3.d.ts +2 -2
  8. package/dist/api/v3.js +10 -10
  9. package/dist/{chunk-XYTWOJII.js → chunk-224TSMEB.js} +635 -89
  10. package/dist/{chunk-43JAPM2F.js → chunk-3JEE5RJU.js} +92 -131
  11. package/dist/{chunk-UP2KDOYE.js → chunk-57HTKX3P.js} +6 -2
  12. package/dist/{chunk-RYMMKOFI.js → chunk-5KTJKTNE.js} +32 -0
  13. package/dist/{chunk-LPLJZJT2.js → chunk-CVSD3UNK.js} +128 -69
  14. package/dist/{chunk-JVTDBX67.js → chunk-EFEW7BTT.js} +2 -2
  15. package/dist/{chunk-UFPBYJMA.js → chunk-INLRCC4N.js} +2 -2
  16. package/dist/{chunk-6736GA6J.js → chunk-KL4TZSZV.js} +1 -1
  17. package/dist/{chunk-N5FTU4HZ.js → chunk-MQ5GAJ54.js} +68 -39
  18. package/dist/{chunk-W2I47J2Q.js → chunk-NJFKPDNG.js} +216 -2
  19. package/dist/{chunk-YUHNDEV5.js → chunk-OTRVGNZQ.js} +2934 -1815
  20. package/dist/{chunk-4HGFJ6Z2.js → chunk-PZIEOEJZ.js} +1 -1
  21. package/dist/{chunk-C5LXKR54.js → chunk-QTRJLKR2.js} +1 -1
  22. package/dist/{chunk-SZ6BJA4Q.js → chunk-REFHJ2FN.js} +3 -3
  23. package/dist/{chunk-ZDYGRO2Z.js → chunk-RP76USJE.js} +1 -1
  24. package/dist/{chunk-QUTVR72L.js → chunk-S3PEKX6H.js} +246 -43
  25. package/dist/{chunk-RBWJHRNP.js → chunk-T66OS7MN.js} +8 -3
  26. package/dist/{chunk-ALWXYGXP.js → chunk-V2JF42SI.js} +2 -2
  27. package/dist/{chunk-6TLZ6CMP.js → chunk-WDDFU2N2.js} +2 -2
  28. package/dist/{chunk-U3UMKA7B.js → chunk-XBQFDBXE.js} +1 -1
  29. package/dist/{chunk-CDEZGLQ3.js → chunk-ZFCZ7XXH.js} +1 -1
  30. package/dist/core/commands/formatting-commands.d.cts +1 -1
  31. package/dist/core/commands/formatting-commands.d.ts +1 -1
  32. package/dist/core/commands/image-commands.cjs +32 -0
  33. package/dist/core/commands/image-commands.d.cts +1 -1
  34. package/dist/core/commands/image-commands.d.ts +1 -1
  35. package/dist/core/commands/image-commands.js +5 -5
  36. package/dist/core/commands/section-layout-commands.d.cts +1 -1
  37. package/dist/core/commands/section-layout-commands.d.ts +1 -1
  38. package/dist/core/commands/style-commands.d.cts +1 -1
  39. package/dist/core/commands/style-commands.d.ts +1 -1
  40. package/dist/core/commands/table-structure-commands.cjs +32 -0
  41. package/dist/core/commands/table-structure-commands.d.cts +1 -1
  42. package/dist/core/commands/table-structure-commands.d.ts +1 -1
  43. package/dist/core/commands/table-structure-commands.js +4 -4
  44. package/dist/core/commands/text-commands.cjs +99 -38
  45. package/dist/core/commands/text-commands.d.cts +12 -1
  46. package/dist/core/commands/text-commands.d.ts +12 -1
  47. package/dist/core/commands/text-commands.js +5 -5
  48. package/dist/core/selection/mapping.d.cts +1 -1
  49. package/dist/core/selection/mapping.d.ts +1 -1
  50. package/dist/core/state/editor-state.d.cts +1 -1
  51. package/dist/core/state/editor-state.d.ts +1 -1
  52. package/dist/index.cjs +4827 -2434
  53. package/dist/index.d.cts +4 -4
  54. package/dist/index.d.ts +4 -4
  55. package/dist/index.js +292 -53
  56. package/dist/io/docx-session.cjs +7 -2
  57. package/dist/io/docx-session.d.cts +3 -3
  58. package/dist/io/docx-session.d.ts +3 -3
  59. package/dist/io/docx-session.js +4 -4
  60. package/dist/legal.js +3 -3
  61. package/dist/{loader-MAa8VpzW.d.cts → loader-B2H99237.d.cts} +2 -2
  62. package/dist/{loader-CfpeEPAa.d.ts → loader-DfTjqVwn.d.ts} +2 -2
  63. package/dist/{public-types-Cjs8glST.d.ts → public-types-B5lOUIrP.d.ts} +689 -232
  64. package/dist/{public-types-KBS6JnOs.d.cts → public-types-S8gTYwKo.d.cts} +689 -232
  65. package/dist/public-types.cjs +158 -67
  66. package/dist/public-types.d.cts +1 -1
  67. package/dist/public-types.d.ts +1 -1
  68. package/dist/public-types.js +3 -3
  69. package/dist/runtime/collab.d.cts +2 -2
  70. package/dist/runtime/collab.d.ts +2 -2
  71. package/dist/runtime/document-runtime.cjs +1032 -416
  72. package/dist/runtime/document-runtime.d.cts +1 -1
  73. package/dist/runtime/document-runtime.d.ts +1 -1
  74. package/dist/runtime/document-runtime.js +14 -14
  75. package/dist/{session-CkoH8FoY.d.ts → session-CBDIOYXA.d.ts} +2 -2
  76. package/dist/{session-wwe0Gib-.d.cts → session-CR2A1hGZ.d.cts} +2 -2
  77. package/dist/session.cjs +7 -2
  78. package/dist/session.d.cts +4 -4
  79. package/dist/session.d.ts +4 -4
  80. package/dist/session.js +5 -5
  81. package/dist/tailwind.cjs +398 -105
  82. package/dist/tailwind.d.cts +1 -1
  83. package/dist/tailwind.d.ts +1 -1
  84. package/dist/tailwind.js +7 -7
  85. package/dist/{types-CH7NWqVL.d.ts → types-B-90ywjU.d.ts} +1 -1
  86. package/dist/{types-B3SGRW0w.d.cts → types-yty2K-hk.d.cts} +1 -1
  87. package/dist/ui-tailwind/editor-surface/search-plugin.d.cts +2 -2
  88. package/dist/ui-tailwind/editor-surface/search-plugin.d.ts +2 -2
  89. package/dist/ui-tailwind/editor-surface/search-plugin.js +4 -4
  90. package/dist/ui-tailwind.cjs +398 -105
  91. package/dist/ui-tailwind.d.cts +3 -2
  92. package/dist/ui-tailwind.d.ts +3 -2
  93. package/dist/ui-tailwind.js +7 -7
  94. package/package.json +1 -1
@@ -6636,7 +6636,20 @@ function sourceJoinHash(refs) {
6636
6636
  if (sourceIds.length === 0) return void 0;
6637
6637
  return hashText(sourceIds.join("\0"));
6638
6638
  }
6639
+ var numberingCatalogHashCache = /* @__PURE__ */ new WeakMap();
6640
+ var numberingTargetHashCache = /* @__PURE__ */ new WeakMap();
6639
6641
  function createNumberingCatalogRevisionHash(doc) {
6642
+ const numbering = doc.numbering;
6643
+ if (numbering !== void 0) {
6644
+ const cached = numberingCatalogHashCache.get(numbering);
6645
+ if (cached !== void 0) return cached;
6646
+ const fresh = computeNumberingCatalogRevisionHash(doc);
6647
+ numberingCatalogHashCache.set(numbering, fresh);
6648
+ return fresh;
6649
+ }
6650
+ return computeNumberingCatalogRevisionHash(doc);
6651
+ }
6652
+ function computeNumberingCatalogRevisionHash(doc) {
6640
6653
  const catalog = doc.numbering ?? { abstractDefinitions: {}, instances: {} };
6641
6654
  const abstractDefinitions = catalog.abstractDefinitions ?? {};
6642
6655
  const instances = catalog.instances ?? {};
@@ -6687,8 +6700,27 @@ function createNumberingCatalogRevisionHash(doc) {
6687
6700
  }));
6688
6701
  }
6689
6702
  function createNumberingTargetRevisionHash(doc) {
6703
+ const numbering = doc.numbering;
6704
+ const styles = doc.styles;
6705
+ if (numbering !== void 0 && styles !== void 0) {
6706
+ let inner = numberingTargetHashCache.get(numbering);
6707
+ if (inner === void 0) {
6708
+ inner = /* @__PURE__ */ new WeakMap();
6709
+ numberingTargetHashCache.set(numbering, inner);
6710
+ }
6711
+ const cached = inner.get(styles);
6712
+ if (cached !== void 0) return cached;
6713
+ const fresh = computeNumberingTargetRevisionHash(doc);
6714
+ inner.set(styles, fresh);
6715
+ return fresh;
6716
+ }
6717
+ return computeNumberingTargetRevisionHash(doc);
6718
+ }
6719
+ function computeNumberingTargetRevisionHash(doc) {
6690
6720
  const paragraphStyles = doc.styles?.paragraphs ?? {};
6691
6721
  return hashText(JSON.stringify({
6722
+ // Reuses the memoized catalog hash on the hot path so a typing edit
6723
+ // pays for the catalog hash at most once across both helpers.
6692
6724
  numberingCatalogHash: createNumberingCatalogRevisionHash(doc),
6693
6725
  paragraphStyleNumbering: Object.keys(paragraphStyles).sort().map((styleId) => {
6694
6726
  const style = paragraphStyles[styleId];
@@ -10790,8 +10822,8 @@ function toLayoutTabStops(tabStops, source) {
10790
10822
  }
10791
10823
  function mergeLayoutTabStops(...groups) {
10792
10824
  const byKey = /* @__PURE__ */ new Map();
10793
- for (const group of groups) {
10794
- for (const tabStop of group ?? []) {
10825
+ for (const group2 of groups) {
10826
+ for (const tabStop of group2 ?? []) {
10795
10827
  const key = [
10796
10828
  tabStop.source,
10797
10829
  tabStop.positionTwips,
@@ -11376,7 +11408,7 @@ function collectParagraphCompatFlags(paragraph) {
11376
11408
  return flags;
11377
11409
  }
11378
11410
  function mergeCompatFlags(...groups) {
11379
- return [...new Set(groups.flatMap((group) => group ?? []))].sort();
11411
+ return [...new Set(groups.flatMap((group2) => group2 ?? []))].sort();
11380
11412
  }
11381
11413
  function buildRevisionRangeIndex(doc) {
11382
11414
  const records = [];
@@ -13586,7 +13618,38 @@ var TextTransactionError = class extends Error {
13586
13618
  this.code = code;
13587
13619
  }
13588
13620
  };
13621
+ function isUsableScopeSurface(surface, document2) {
13622
+ if (surface.viewportBlockRanges !== null) return false;
13623
+ const root = document2.content;
13624
+ if (!root || root.type !== "doc" || !Array.isArray(root.children)) {
13625
+ return false;
13626
+ }
13627
+ return surface.blocks.length === root.children.length;
13628
+ }
13629
+ function createScopeSurfaceCache(document2, selection, precomputedSurface, telemetry) {
13630
+ let cached;
13631
+ if (precomputedSurface && isUsableScopeSurface(precomputedSurface, document2)) {
13632
+ cached = precomputedSurface;
13633
+ telemetry?.onPrecomputedSurfaceHit?.();
13634
+ }
13635
+ return {
13636
+ get() {
13637
+ if (cached) return cached;
13638
+ telemetry?.onScopeSurfaceBuild?.();
13639
+ cached = createEditorSurfaceSnapshot(document2, selection, void 0, {
13640
+ editableTargetsByBlockPath: NO_EDITABLE_TARGETS_INDEX
13641
+ });
13642
+ return cached;
13643
+ }
13644
+ };
13645
+ }
13589
13646
  function applyTextTransaction(document2, selection, intent, options) {
13647
+ const scopeSurfaceCache = createScopeSurfaceCache(
13648
+ document2,
13649
+ selection,
13650
+ options.precomputedSurface,
13651
+ options.surfaceTelemetry
13652
+ );
13590
13653
  if (options.textTarget) {
13591
13654
  if (options.textTarget.kind === "hyperlink-display") {
13592
13655
  const targetedHyperlinkResult = tryApplyHyperlinkDisplayTransaction(
@@ -13622,7 +13685,8 @@ function applyTextTransaction(document2, selection, intent, options) {
13622
13685
  document2,
13623
13686
  selection,
13624
13687
  intent,
13625
- options
13688
+ options,
13689
+ scopeSurfaceCache
13626
13690
  );
13627
13691
  if (targetedTableResult) {
13628
13692
  return targetedTableResult;
@@ -13636,7 +13700,8 @@ function applyTextTransaction(document2, selection, intent, options) {
13636
13700
  const tableStructureRefusal = resolveTargetlessTableStructureInsertRefusal(
13637
13701
  document2,
13638
13702
  selection,
13639
- intent
13703
+ intent,
13704
+ scopeSurfaceCache
13640
13705
  );
13641
13706
  if (tableStructureRefusal) {
13642
13707
  throw new TextTransactionError("unsupported_content", tableStructureRefusal);
@@ -13646,7 +13711,8 @@ function applyTextTransaction(document2, selection, intent, options) {
13646
13711
  document2,
13647
13712
  selection,
13648
13713
  intent,
13649
- options
13714
+ options,
13715
+ scopeSurfaceCache
13650
13716
  );
13651
13717
  if (topLevelParagraphResult) {
13652
13718
  return topLevelParagraphResult;
@@ -13655,7 +13721,8 @@ function applyTextTransaction(document2, selection, intent, options) {
13655
13721
  document2,
13656
13722
  selection,
13657
13723
  intent,
13658
- options
13724
+ options,
13725
+ scopeSurfaceCache
13659
13726
  );
13660
13727
  if (sdtScopedResult) {
13661
13728
  return sdtScopedResult;
@@ -13664,7 +13731,8 @@ function applyTextTransaction(document2, selection, intent, options) {
13664
13731
  document2,
13665
13732
  selection,
13666
13733
  intent,
13667
- options
13734
+ options,
13735
+ scopeSurfaceCache
13668
13736
  );
13669
13737
  if (tableScopedResult) {
13670
13738
  return tableScopedResult;
@@ -13717,9 +13785,9 @@ function applyLinearTextTransaction(document2, selection, intent, options) {
13717
13785
  storyText: createPlainText(nextStory)
13718
13786
  };
13719
13787
  }
13720
- function tryApplyTableParagraphTransaction(document2, selection, intent, options) {
13788
+ function tryApplyTableParagraphTransaction(document2, selection, intent, options, scopeSurfaceCache) {
13721
13789
  const tableTarget = options.textTarget?.kind === "table-paragraph" ? options.textTarget : void 0;
13722
- const scope = resolveTableParagraphScope(document2, selection, tableTarget);
13790
+ const scope = resolveTableParagraphScope(document2, selection, tableTarget, scopeSurfaceCache);
13723
13791
  if (!scope) {
13724
13792
  return null;
13725
13793
  }
@@ -13842,7 +13910,11 @@ function tryApplyTargetedTextLeafTransaction(document2, selection, intent, optio
13842
13910
  };
13843
13911
  }
13844
13912
  function tryApplyHyperlinkDisplayTransaction(document2, selection, intent, options) {
13845
- const scope = resolveTargetedHyperlinkDisplayScope(document2, selection, options.textTarget);
13913
+ const scope = resolveTargetedHyperlinkDisplayScope(
13914
+ document2,
13915
+ selection,
13916
+ options.textTarget
13917
+ );
13846
13918
  if (!scope) {
13847
13919
  return null;
13848
13920
  }
@@ -13900,8 +13972,8 @@ function tryApplyHyperlinkDisplayTransaction(document2, selection, intent, optio
13900
13972
  storyText: localResult.storyText
13901
13973
  };
13902
13974
  }
13903
- function tryApplyTopLevelSdtParagraphTransaction(document2, selection, intent, options) {
13904
- const scope = resolveTopLevelSdtParagraphScope(document2, selection);
13975
+ function tryApplyTopLevelSdtParagraphTransaction(document2, selection, intent, options, scopeSurfaceCache) {
13976
+ const scope = resolveTopLevelSdtParagraphScope(document2, selection, scopeSurfaceCache);
13905
13977
  if (!scope) {
13906
13978
  return null;
13907
13979
  }
@@ -13953,8 +14025,8 @@ function tryApplyTopLevelSdtParagraphTransaction(document2, selection, intent, o
13953
14025
  storyText: localResult.storyText
13954
14026
  };
13955
14027
  }
13956
- function tryApplyTopLevelParagraphTransaction(document2, selection, intent, options) {
13957
- const scope = resolveTopLevelParagraphScope(document2, selection);
14028
+ function tryApplyTopLevelParagraphTransaction(document2, selection, intent, options, scopeSurfaceCache) {
14029
+ const scope = resolveTopLevelParagraphScope(document2, selection, scopeSurfaceCache);
13958
14030
  if (!scope) {
13959
14031
  return null;
13960
14032
  }
@@ -14064,17 +14136,15 @@ function resolveTargetedHyperlinkDisplayScope(document2, selection, target) {
14064
14136
  replace: resolved.replace
14065
14137
  };
14066
14138
  }
14067
- function resolveTableParagraphScope(document2, selection, target) {
14139
+ function resolveTableParagraphScope(document2, selection, target, scopeSurfaceCache) {
14068
14140
  if (target) {
14069
- return resolveTargetedTableParagraphScope(document2, selection, target);
14141
+ return resolveTargetedTableParagraphScope(document2, selection, target, scopeSurfaceCache);
14070
14142
  }
14071
14143
  const root = document2.content;
14072
14144
  if (!root || root.type !== "doc" || !Array.isArray(root.children)) {
14073
14145
  return null;
14074
14146
  }
14075
- const surface = createEditorSurfaceSnapshot(document2, selection, void 0, {
14076
- editableTargetsByBlockPath: NO_EDITABLE_TARGETS_INDEX
14077
- });
14147
+ const surface = scopeSurfaceCache.get();
14078
14148
  const selectionFrom = Math.min(selection.anchor, selection.head);
14079
14149
  const selectionTo = Math.max(selection.anchor, selection.head);
14080
14150
  for (let blockIndex = 0; blockIndex < root.children.length; blockIndex += 1) {
@@ -14179,7 +14249,7 @@ function resolveTableParagraphScope(document2, selection, target) {
14179
14249
  }
14180
14250
  return null;
14181
14251
  }
14182
- function resolveTargetlessTableStructureInsertRefusal(document2, selection, intent) {
14252
+ function resolveTargetlessTableStructureInsertRefusal(document2, selection, intent, scopeSurfaceCache) {
14183
14253
  if (!isCollapsedInsertIntent(intent, selection)) {
14184
14254
  return null;
14185
14255
  }
@@ -14187,9 +14257,7 @@ function resolveTargetlessTableStructureInsertRefusal(document2, selection, inte
14187
14257
  if (!root || root.type !== "doc" || !Array.isArray(root.children)) {
14188
14258
  return null;
14189
14259
  }
14190
- const surface = createEditorSurfaceSnapshot(document2, selection, void 0, {
14191
- editableTargetsByBlockPath: NO_EDITABLE_TARGETS_INDEX
14192
- });
14260
+ const surface = scopeSurfaceCache.get();
14193
14261
  if (!selectionTouchesTableStructureBoundary(surface.blocks, selection.anchor)) {
14194
14262
  return null;
14195
14263
  }
@@ -14203,7 +14271,7 @@ function isCollapsedInsertIntent(intent, selection) {
14203
14271
  const rangeTo = intent.range ? Math.max(intent.range.from, intent.range.to) : Math.max(selection.anchor, selection.head);
14204
14272
  return rangeFrom === rangeTo;
14205
14273
  }
14206
- function resolveTargetedTableParagraphScope(document2, selection, target) {
14274
+ function resolveTargetedTableParagraphScope(document2, selection, target, scopeSurfaceCache) {
14207
14275
  const root = document2.content;
14208
14276
  if (!root || root.type !== "doc" || !Array.isArray(root.children)) {
14209
14277
  return null;
@@ -14216,7 +14284,8 @@ function resolveTargetedTableParagraphScope(document2, selection, target) {
14216
14284
  root,
14217
14285
  document2,
14218
14286
  selection,
14219
- target
14287
+ target,
14288
+ scopeSurfaceCache
14220
14289
  );
14221
14290
  if (targetScope) {
14222
14291
  return targetScope;
@@ -14239,9 +14308,7 @@ function resolveTargetedTableParagraphScope(document2, selection, target) {
14239
14308
  if (cell.verticalMerge === "continue") {
14240
14309
  return "unsupported";
14241
14310
  }
14242
- const surface = createEditorSurfaceSnapshot(document2, selection, void 0, {
14243
- editableTargetsByBlockPath: NO_EDITABLE_TARGETS_INDEX
14244
- });
14311
+ const surface = scopeSurfaceCache.get();
14245
14312
  const surfaceBlock = surface.blocks[target.tableBlockIndex];
14246
14313
  const surfaceRow = surfaceBlock?.kind === "table" ? surfaceBlock.rows[target.rowIndex] : void 0;
14247
14314
  const surfaceCell = surfaceRow?.cells[target.cellIndex];
@@ -14305,16 +14372,14 @@ function resolveTargetedTableParagraphScope(document2, selection, target) {
14305
14372
  }
14306
14373
  };
14307
14374
  }
14308
- function resolveTargetedTableParagraphScopeByPath(root, document2, selection, target) {
14375
+ function resolveTargetedTableParagraphScopeByPath(root, document2, selection, target, scopeSurfaceCache) {
14309
14376
  if (!target.blockPath) return null;
14310
14377
  const tokens = parseCanonicalBlockPath(target.blockPath);
14311
14378
  if (!tokens) return null;
14312
14379
  const resolved = resolveBlockPathInCanonicalBlocks(root.children, tokens, 0);
14313
14380
  if (!resolved || resolved.block.type !== "paragraph") return null;
14314
14381
  if (resolved.hasVerticalMergeContinuation) return null;
14315
- const surface = createEditorSurfaceSnapshot(document2, selection, void 0, {
14316
- editableTargetsByBlockPath: NO_EDITABLE_TARGETS_INDEX
14317
- });
14382
+ const surface = scopeSurfaceCache.get();
14318
14383
  const surfaceResolved = resolveBlockPathInSurfaceBlocks(surface.blocks, tokens, 0);
14319
14384
  if (!surfaceResolved || surfaceResolved.kind !== "paragraph") return null;
14320
14385
  if (surfaceResolved.hasVerticalMergeContinuation) return null;
@@ -14769,14 +14834,12 @@ function resolveBlockPathInSurfaceBlocks(blocks, tokens, tokenIndex, hasVertical
14769
14834
  hasVerticalMergeContinuation || cell.verticalMerge === "continue"
14770
14835
  );
14771
14836
  }
14772
- function resolveTopLevelParagraphScope(document2, selection) {
14837
+ function resolveTopLevelParagraphScope(document2, selection, scopeSurfaceCache) {
14773
14838
  const root = document2.content;
14774
14839
  if (!root || root.type !== "doc" || !Array.isArray(root.children)) {
14775
14840
  return null;
14776
14841
  }
14777
- const surface = createEditorSurfaceSnapshot(document2, selection, void 0, {
14778
- editableTargetsByBlockPath: NO_EDITABLE_TARGETS_INDEX
14779
- });
14842
+ const surface = scopeSurfaceCache.get();
14780
14843
  const selectionFrom = Math.min(selection.anchor, selection.head);
14781
14844
  const selectionTo = Math.max(selection.anchor, selection.head);
14782
14845
  for (let blockIndex = 0; blockIndex < root.children.length; blockIndex += 1) {
@@ -14805,14 +14868,12 @@ function resolveTopLevelParagraphScope(document2, selection) {
14805
14868
  }
14806
14869
  return null;
14807
14870
  }
14808
- function resolveTopLevelSdtParagraphScope(document2, selection) {
14871
+ function resolveTopLevelSdtParagraphScope(document2, selection, scopeSurfaceCache) {
14809
14872
  const root = document2.content;
14810
14873
  if (!root || root.type !== "doc" || !Array.isArray(root.children)) {
14811
14874
  return null;
14812
14875
  }
14813
- const surface = createEditorSurfaceSnapshot(document2, selection, void 0, {
14814
- editableTargetsByBlockPath: NO_EDITABLE_TARGETS_INDEX
14815
- });
14876
+ const surface = scopeSurfaceCache.get();
14816
14877
  const selectionFrom = Math.min(selection.anchor, selection.head);
14817
14878
  const selectionTo = Math.max(selection.anchor, selection.head);
14818
14879
  for (let blockIndex = 0; blockIndex < root.children.length; blockIndex += 1) {
@@ -15564,7 +15625,7 @@ function getTableCellRange(table, cell) {
15564
15625
  function breadcrumbItemsEqual(left, right) {
15565
15626
  return left.kind === right.kind && left.label === right.label && left.from === right.from && left.to === right.to;
15566
15627
  }
15567
- function applyFormattingOperationToDocument(document2, snapshot, operation) {
15628
+ function applyFormattingOperationToDocument(document2, snapshot, operation2) {
15568
15629
  const surface = snapshot.surface;
15569
15630
  if (!surface) {
15570
15631
  return {
@@ -15578,7 +15639,7 @@ function applyFormattingOperationToDocument(document2, snapshot, operation) {
15578
15639
  let changed = false;
15579
15640
  const selectionFrom = Math.min(snapshot.selection.anchor, snapshot.selection.head);
15580
15641
  const selectionTo = Math.max(snapshot.selection.anchor, snapshot.selection.head);
15581
- if (operation.type === "set-alignment" || operation.type === "indent" || operation.type === "outdent") {
15642
+ if (operation2.type === "set-alignment" || operation2.type === "indent" || operation2.type === "outdent") {
15582
15643
  visitParagraphBindings(root.children, surface.blocks, (paragraph, paragraphSurface) => {
15583
15644
  if (!selectionTouchesRange(
15584
15645
  snapshot.selection.anchor,
@@ -15588,7 +15649,7 @@ function applyFormattingOperationToDocument(document2, snapshot, operation) {
15588
15649
  )) {
15589
15650
  return;
15590
15651
  }
15591
- const paragraphChanged = operation.type === "set-alignment" ? applyAlignment(paragraph, operation.alignment) : applyIndentation(paragraph, operation.type === "indent" ? 1 : -1);
15652
+ const paragraphChanged = operation2.type === "set-alignment" ? applyAlignment(paragraph, operation2.alignment) : applyIndentation(paragraph, operation2.type === "indent" ? 1 : -1);
15592
15653
  changed = changed || paragraphChanged;
15593
15654
  });
15594
15655
  return {
@@ -15604,7 +15665,7 @@ function applyFormattingOperationToDocument(document2, snapshot, operation) {
15604
15665
  changed: false
15605
15666
  };
15606
15667
  }
15607
- const nextMarks = resolveMarkUpdater(snapshot, operation);
15668
+ const nextMarks = resolveMarkUpdater(snapshot, operation2);
15608
15669
  visitParagraphBindings(root.children, surface.blocks, (paragraph, paragraphSurface) => {
15609
15670
  if (!rangesOverlap(
15610
15671
  selectionFrom,
@@ -15633,10 +15694,10 @@ function applyFormattingOperationToDocument(document2, snapshot, operation) {
15633
15694
  changed
15634
15695
  };
15635
15696
  }
15636
- function applyTextMarkOperationToDocumentRange(document2, range, operation) {
15697
+ function applyTextMarkOperationToDocumentRange(document2, range, operation2) {
15637
15698
  const inputFrom = Math.min(range.from, range.to);
15638
15699
  const inputTo = Math.max(range.from, range.to);
15639
- const expandedRange = operation.type === "clear-mark" && operation.expandToFullHighlight === true ? expandRangeToCanonicalHighlightExtent(document2, inputFrom, inputTo) : { from: inputFrom, to: inputTo };
15700
+ const expandedRange = operation2.type === "clear-mark" && operation2.expandToFullHighlight === true ? expandRangeToCanonicalHighlightExtent(document2, inputFrom, inputTo) : { from: inputFrom, to: inputTo };
15640
15701
  const selectionFrom = expandedRange.from;
15641
15702
  const selectionTo = expandedRange.to;
15642
15703
  const selection = {
@@ -15655,17 +15716,17 @@ function applyTextMarkOperationToDocumentRange(document2, range, operation) {
15655
15716
  }
15656
15717
  const nextDocument = structuredClone(document2);
15657
15718
  const root = nextDocument.content;
15658
- const updateMarks = resolveTextMarkRangeUpdater(operation);
15719
+ const updateMarks = resolveTextMarkRangeUpdater(operation2);
15659
15720
  let changed = false;
15660
15721
  let cursor = 0;
15661
15722
  for (let blockIndex = 0; blockIndex < root.children.length; blockIndex += 1) {
15662
15723
  const block = root.children[blockIndex];
15663
15724
  const blockFrom = cursor;
15664
- const blockLength = block?.type === "paragraph" ? block.children.reduce(
15725
+ const blockLength2 = block?.type === "paragraph" ? block.children.reduce(
15665
15726
  (total, child) => total + inlineNodeLength(child),
15666
15727
  0
15667
15728
  ) : 1;
15668
- const blockTo = blockFrom + blockLength;
15729
+ const blockTo = blockFrom + blockLength2;
15669
15730
  if (block?.type === "paragraph" && rangesOverlap(selectionFrom, selectionTo, blockFrom, blockTo)) {
15670
15731
  const transformed = transformInlineNodes(
15671
15732
  block.children,
@@ -15698,11 +15759,11 @@ function expandRangeToCanonicalHighlightExtent(document2, inputFrom, inputTo) {
15698
15759
  for (let blockIndex = 0; blockIndex < root.children.length; blockIndex += 1) {
15699
15760
  const block = root.children[blockIndex];
15700
15761
  const blockFrom = cursor;
15701
- const blockLength = block.type === "paragraph" ? block.children.reduce(
15762
+ const blockLength2 = block.type === "paragraph" ? block.children.reduce(
15702
15763
  (total, child) => total + inlineNodeLength(child),
15703
15764
  0
15704
15765
  ) : 1;
15705
- const blockTo = blockFrom + blockLength;
15766
+ const blockTo = blockFrom + blockLength2;
15706
15767
  if (block.type === "paragraph" && rangesOverlap(inputFrom, inputTo, blockFrom, blockTo)) {
15707
15768
  const spans = collectInlineHighlightSpans(block.children, blockFrom).spans;
15708
15769
  const expanded = expandRangeWithinHighlightSpans(spans, inputFrom, inputTo);
@@ -15791,39 +15852,39 @@ function marksHaveVisualHighlight(marks) {
15791
15852
  (mark) => mark.type === "highlight" || mark.type === "backgroundColor"
15792
15853
  ) ?? false;
15793
15854
  }
15794
- function resolveTextMarkRangeUpdater(operation) {
15795
- if (operation.type === "set-mark") {
15855
+ function resolveTextMarkRangeUpdater(operation2) {
15856
+ if (operation2.type === "set-mark") {
15796
15857
  return (marks) => {
15797
15858
  const nextMarks = cloneMarks3(marks).filter(
15798
- (candidate) => candidate.type !== operation.mark.type
15859
+ (candidate) => candidate.type !== operation2.mark.type
15799
15860
  );
15800
- nextMarks.push({ ...operation.mark });
15861
+ nextMarks.push({ ...operation2.mark });
15801
15862
  return nextMarks.length > 0 ? nextMarks : void 0;
15802
15863
  };
15803
15864
  }
15804
15865
  return (marks) => {
15805
15866
  const nextMarks = cloneMarks3(marks).filter((candidate) => {
15806
- if (operation.mark === "visualHighlight") {
15867
+ if (operation2.mark === "visualHighlight") {
15807
15868
  return candidate.type !== "highlight" && candidate.type !== "backgroundColor";
15808
15869
  }
15809
- return candidate.type !== operation.mark;
15870
+ return candidate.type !== operation2.mark;
15810
15871
  });
15811
15872
  return nextMarks.length > 0 ? nextMarks : void 0;
15812
15873
  };
15813
15874
  }
15814
- function resolveMarkUpdater(snapshot, operation) {
15875
+ function resolveMarkUpdater(snapshot, operation2) {
15815
15876
  const formatting = getFormattingStateFromRenderSnapshot(snapshot);
15816
- switch (operation.type) {
15877
+ switch (operation2.type) {
15817
15878
  case "toggle":
15818
- return (marks) => toggleMarks(marks, operation.mark, !formatting[operation.mark]);
15879
+ return (marks) => toggleMarks(marks, operation2.mark, !formatting[operation2.mark]);
15819
15880
  case "set-font-family":
15820
- return (marks) => setMarkValue(marks, "fontFamily", sanitizeFontFamily(operation.fontFamily));
15881
+ return (marks) => setMarkValue(marks, "fontFamily", sanitizeFontFamily(operation2.fontFamily));
15821
15882
  case "set-font-size":
15822
- return (marks) => setMarkValue(marks, "fontSize", sanitizeFontSize(operation.size));
15883
+ return (marks) => setMarkValue(marks, "fontSize", sanitizeFontSize(operation2.size));
15823
15884
  case "set-text-color":
15824
- return (marks) => setMarkValue(marks, "textColor", sanitizeColor(operation.color));
15885
+ return (marks) => setMarkValue(marks, "textColor", sanitizeColor(operation2.color));
15825
15886
  case "set-highlight-color":
15826
- return (marks) => setMarkValue(marks, "backgroundColor", sanitizeColor(operation.color));
15887
+ return (marks) => setMarkValue(marks, "backgroundColor", sanitizeColor(operation2.color));
15827
15888
  }
15828
15889
  }
15829
15890
  function applyAlignment(paragraph, alignment) {
@@ -17158,7 +17219,7 @@ function findCellIndexAtColumn(row2, logicalColumn) {
17158
17219
  }
17159
17220
 
17160
17221
  // src/core/commands/table-structure-commands.ts
17161
- function applyTableStructureOperation(document2, snapshot, selectionDescriptor, operation) {
17222
+ function applyTableStructureOperation(document2, snapshot, selectionDescriptor, operation2) {
17162
17223
  const root = document2.content;
17163
17224
  const fallbackSelection = toInternalSelectionSnapshot(snapshot.selection);
17164
17225
  if (!root || root.type !== "doc") {
@@ -17172,11 +17233,11 @@ function applyTableStructureOperation(document2, snapshot, selectionDescriptor,
17172
17233
  if (!target || target.type !== "table") {
17173
17234
  return createNoopStructuralMutation(document2, fallbackSelection);
17174
17235
  }
17175
- switch (operation.type) {
17236
+ switch (operation2.type) {
17176
17237
  case "delete-table":
17177
17238
  return deleteTableBlock(document2, root, effectiveSelection.tableBlockIndex, fallbackSelection);
17178
17239
  case "set-cell-background":
17179
- return setCellBackground(document2, root, target, effectiveSelection, operation.color, fallbackSelection);
17240
+ return setCellBackground(document2, root, target, effectiveSelection, operation2.color, fallbackSelection);
17180
17241
  case "split-cell":
17181
17242
  return splitSelectedCell(document2, root, target, effectiveSelection, fallbackSelection);
17182
17243
  case "merge-cells":
@@ -17194,20 +17255,20 @@ function applyTableStructureOperation(document2, snapshot, selectionDescriptor,
17194
17255
  case "delete-column":
17195
17256
  return deleteColumn(document2, root, target, effectiveSelection, fallbackSelection);
17196
17257
  case "set-table-width":
17197
- return patchTable(document2, root, target, effectiveSelection, { width: operation.width }, fallbackSelection);
17258
+ return patchTable(document2, root, target, effectiveSelection, { width: operation2.width }, fallbackSelection);
17198
17259
  case "set-table-alignment":
17199
- return patchTable(document2, root, target, effectiveSelection, { alignment: operation.alignment }, fallbackSelection);
17260
+ return patchTable(document2, root, target, effectiveSelection, { alignment: operation2.alignment }, fallbackSelection);
17200
17261
  case "set-table-indent":
17201
- return patchTable(document2, root, target, effectiveSelection, { indent: operation.indent }, fallbackSelection);
17262
+ return patchTable(document2, root, target, effectiveSelection, { indent: operation2.indent }, fallbackSelection);
17202
17263
  case "set-table-layout-mode":
17203
- return patchTable(document2, root, target, effectiveSelection, { layoutMode: operation.mode }, fallbackSelection);
17264
+ return patchTable(document2, root, target, effectiveSelection, { layoutMode: operation2.mode }, fallbackSelection);
17204
17265
  case "set-table-cell-margins":
17205
17266
  return patchTable(
17206
17267
  document2,
17207
17268
  root,
17208
17269
  target,
17209
17270
  effectiveSelection,
17210
- { cellMargins: mergeTableCellMargins(target.cellMargins, operation.margins) },
17271
+ { cellMargins: mergeTableCellMargins(target.cellMargins, operation2.margins) },
17211
17272
  fallbackSelection
17212
17273
  );
17213
17274
  case "set-table-borders":
@@ -17216,7 +17277,7 @@ function applyTableStructureOperation(document2, snapshot, selectionDescriptor,
17216
17277
  root,
17217
17278
  target,
17218
17279
  effectiveSelection,
17219
- { borders: mergeTableBorders(target.borders, operation.borders) },
17280
+ { borders: mergeTableBorders(target.borders, operation2.borders) },
17220
17281
  fallbackSelection
17221
17282
  );
17222
17283
  case "set-table-style":
@@ -17225,7 +17286,7 @@ function applyTableStructureOperation(document2, snapshot, selectionDescriptor,
17225
17286
  root,
17226
17287
  target,
17227
17288
  effectiveSelection,
17228
- { styleId: operation.styleId ?? void 0 },
17289
+ { styleId: operation2.styleId ?? void 0 },
17229
17290
  fallbackSelection
17230
17291
  );
17231
17292
  case "set-table-caption":
@@ -17234,7 +17295,7 @@ function applyTableStructureOperation(document2, snapshot, selectionDescriptor,
17234
17295
  root,
17235
17296
  target,
17236
17297
  effectiveSelection,
17237
- { caption: operation.caption ?? void 0 },
17298
+ { caption: operation2.caption ?? void 0 },
17238
17299
  fallbackSelection
17239
17300
  );
17240
17301
  case "set-table-description":
@@ -17243,82 +17304,82 @@ function applyTableStructureOperation(document2, snapshot, selectionDescriptor,
17243
17304
  root,
17244
17305
  target,
17245
17306
  effectiveSelection,
17246
- { description: operation.description ?? void 0 },
17307
+ { description: operation2.description ?? void 0 },
17247
17308
  fallbackSelection
17248
17309
  );
17249
17310
  case "set-column-width":
17250
- return setColumnWidth(document2, root, target, effectiveSelection, operation.columnIndex, operation.twips, fallbackSelection);
17311
+ return setColumnWidth(document2, root, target, effectiveSelection, operation2.columnIndex, operation2.twips, fallbackSelection);
17251
17312
  case "distribute-columns-evenly":
17252
- return distributeColumnsEvenly(document2, root, target, effectiveSelection, operation.columnRange, fallbackSelection);
17313
+ return distributeColumnsEvenly(document2, root, target, effectiveSelection, operation2.columnRange, fallbackSelection);
17253
17314
  case "set-row-height":
17254
- return patchRow(document2, root, target, effectiveSelection, operation.rowIndex, {
17255
- height: operation.twips,
17256
- heightRule: operation.rule
17315
+ return patchRow(document2, root, target, effectiveSelection, operation2.rowIndex, {
17316
+ height: operation2.twips,
17317
+ heightRule: operation2.rule
17257
17318
  }, fallbackSelection);
17258
17319
  case "set-row-cant-split":
17259
- return patchRow(document2, root, target, effectiveSelection, operation.rowIndex, {
17260
- cantSplit: operation.value
17320
+ return patchRow(document2, root, target, effectiveSelection, operation2.rowIndex, {
17321
+ cantSplit: operation2.value
17261
17322
  }, fallbackSelection);
17262
17323
  case "set-row-is-header":
17263
- return patchRow(document2, root, target, effectiveSelection, operation.rowIndex, {
17264
- isHeader: operation.value
17324
+ return patchRow(document2, root, target, effectiveSelection, operation2.rowIndex, {
17325
+ isHeader: operation2.value
17265
17326
  }, fallbackSelection);
17266
17327
  case "set-row-alignment":
17267
- return patchRow(document2, root, target, effectiveSelection, operation.rowIndex, {
17268
- horizontalAlignment: operation.alignment
17328
+ return patchRow(document2, root, target, effectiveSelection, operation2.rowIndex, {
17329
+ horizontalAlignment: operation2.alignment
17269
17330
  }, fallbackSelection);
17270
17331
  case "insert-rows":
17271
- return insertRows(document2, root, target, effectiveSelection, operation.rowIndex, operation.at, operation.count, fallbackSelection);
17332
+ return insertRows(document2, root, target, effectiveSelection, operation2.rowIndex, operation2.at, operation2.count, fallbackSelection);
17272
17333
  case "insert-columns":
17273
- return insertColumns(document2, root, target, effectiveSelection, operation.columnIndex, operation.at, operation.count, operation.widths, fallbackSelection);
17334
+ return insertColumns(document2, root, target, effectiveSelection, operation2.columnIndex, operation2.at, operation2.count, operation2.widths, fallbackSelection);
17274
17335
  case "set-cell-borders":
17275
- return patchCells(document2, root, target, effectiveSelection, operation.locator, (cell) => ({
17336
+ return patchCells(document2, root, target, effectiveSelection, operation2.locator, (cell) => ({
17276
17337
  ...cell,
17277
- borders: mergeCellBorders(cell.borders, operation.borders)
17338
+ borders: mergeCellBorders(cell.borders, operation2.borders)
17278
17339
  }), fallbackSelection);
17279
17340
  case "set-cell-shading":
17280
- return patchCells(document2, root, target, effectiveSelection, operation.locator, (cell) => {
17281
- if (operation.shading === null) {
17341
+ return patchCells(document2, root, target, effectiveSelection, operation2.locator, (cell) => {
17342
+ if (operation2.shading === null) {
17282
17343
  const { shading: _drop, ...rest } = cell;
17283
17344
  return rest;
17284
17345
  }
17285
- return { ...cell, shading: { ...cell.shading ?? {}, ...operation.shading } };
17346
+ return { ...cell, shading: { ...cell.shading ?? {}, ...operation2.shading } };
17286
17347
  }, fallbackSelection);
17287
17348
  case "clear-cell-shading":
17288
- return patchCells(document2, root, target, effectiveSelection, operation.locator, (cell) => {
17349
+ return patchCells(document2, root, target, effectiveSelection, operation2.locator, (cell) => {
17289
17350
  const { shading: _drop, ...rest } = cell;
17290
17351
  return rest;
17291
17352
  }, fallbackSelection);
17292
17353
  case "set-cell-margins":
17293
- return patchCells(document2, root, target, effectiveSelection, operation.locator, (cell) => ({
17354
+ return patchCells(document2, root, target, effectiveSelection, operation2.locator, (cell) => ({
17294
17355
  ...cell,
17295
- margins: { ...cell.margins ?? {}, ...operation.margins }
17356
+ margins: { ...cell.margins ?? {}, ...operation2.margins }
17296
17357
  }), fallbackSelection);
17297
17358
  case "set-cell-vertical-align":
17298
- return patchCells(document2, root, target, effectiveSelection, operation.locator, (cell) => ({
17359
+ return patchCells(document2, root, target, effectiveSelection, operation2.locator, (cell) => ({
17299
17360
  ...cell,
17300
- verticalAlign: operation.align
17361
+ verticalAlign: operation2.align
17301
17362
  }), fallbackSelection);
17302
17363
  case "set-cell-text-direction":
17303
- return patchCells(document2, root, target, effectiveSelection, operation.locator, (cell) => ({
17364
+ return patchCells(document2, root, target, effectiveSelection, operation2.locator, (cell) => ({
17304
17365
  ...cell,
17305
- textDirection: operation.direction
17366
+ textDirection: operation2.direction
17306
17367
  }), fallbackSelection);
17307
17368
  case "set-cell-no-wrap":
17308
- return patchCells(document2, root, target, effectiveSelection, operation.locator, (cell) => ({
17369
+ return patchCells(document2, root, target, effectiveSelection, operation2.locator, (cell) => ({
17309
17370
  ...cell,
17310
- noWrap: operation.value
17371
+ noWrap: operation2.value
17311
17372
  }), fallbackSelection);
17312
17373
  case "set-cell-fit-text":
17313
- return patchCells(document2, root, target, effectiveSelection, operation.locator, (cell) => ({
17374
+ return patchCells(document2, root, target, effectiveSelection, operation2.locator, (cell) => ({
17314
17375
  ...cell,
17315
- fitText: operation.value
17376
+ fitText: operation2.value
17316
17377
  }), fallbackSelection);
17317
17378
  default:
17318
17379
  return createNoopStructuralMutation(document2, fallbackSelection);
17319
17380
  }
17320
17381
  }
17321
- function applyTableStructureOperationForEditableTarget(document2, snapshot, selectionDescriptor, operation, targetRef) {
17382
+ function applyTableStructureOperationForEditableTarget(document2, snapshot, selectionDescriptor, operation2, targetRef) {
17322
17383
  const tableIdentity = targetRef.table;
17323
17384
  const fallbackSelection = toInternalSelectionSnapshot(snapshot.selection);
17324
17385
  if (!tableIdentity || targetRef.commandFamily !== "table-structure") {
@@ -17353,7 +17414,7 @@ function applyTableStructureOperationForEditableTarget(document2, snapshot, sele
17353
17414
  localDocument,
17354
17415
  snapshot,
17355
17416
  { ...effectiveSelection, tableBlockIndex: 0 },
17356
- operation
17417
+ operation2
17357
17418
  );
17358
17419
  if (!localResult.changed) {
17359
17420
  return createNoopStructuralMutation(document2, fallbackSelection);
@@ -21027,13 +21088,14 @@ function mapRecordAnchor(anchor, mapping) {
21027
21088
  return toPublicAnchorProjection(mapAnchor(toInternalAnchorProjection(anchor), mapping));
21028
21089
  }
21029
21090
  function withCommandTextTarget(context, command) {
21030
- if (!command.textTarget || context.textTarget === command.textTarget) {
21031
- return context;
21091
+ let next = context;
21092
+ if (next.precomputedSurface === void 0 && next.renderSnapshot?.surface !== void 0) {
21093
+ next = { ...next, precomputedSurface: next.renderSnapshot.surface };
21032
21094
  }
21033
- return {
21034
- ...context,
21035
- textTarget: command.textTarget
21036
- };
21095
+ if (command.textTarget && next.textTarget !== command.textTarget) {
21096
+ next = { ...next, textTarget: command.textTarget };
21097
+ }
21098
+ return next;
21037
21099
  }
21038
21100
  function listCommandContext(context) {
21039
21101
  return {
@@ -24427,9 +24489,9 @@ function createSuggestionsSnapshot(trackedChanges) {
24427
24489
  const groups = /* @__PURE__ */ new Map();
24428
24490
  for (const revision of trackedChanges.revisions) {
24429
24491
  const suggestionId = revision.suggestionId ?? revision.revisionId;
24430
- const group = groups.get(suggestionId);
24431
- if (group) {
24432
- group.push(revision);
24492
+ const group2 = groups.get(suggestionId);
24493
+ if (group2) {
24494
+ group2.push(revision);
24433
24495
  } else {
24434
24496
  groups.set(suggestionId, [revision]);
24435
24497
  }
@@ -24476,15 +24538,15 @@ function createSuggestionsSnapshot(trackedChanges) {
24476
24538
  };
24477
24539
  }
24478
24540
 
24479
- // src/runtime/workflow/scope-resolver.ts
24480
- function inlineLength(node) {
24541
+ // src/core/commands/scope-coordinate-walk.ts
24542
+ function inlineLengthForScopeCoordinates(node) {
24481
24543
  switch (node.type) {
24482
24544
  case "text":
24483
24545
  return Array.from(node.text).length;
24484
24546
  case "hyperlink":
24485
24547
  case "field":
24486
24548
  return node.children.reduce(
24487
- (total, child) => total + inlineLength(child),
24549
+ (total, child) => total + inlineLengthForScopeCoordinates(child),
24488
24550
  0
24489
24551
  );
24490
24552
  case "bookmark_start":
@@ -24496,29 +24558,241 @@ function inlineLength(node) {
24496
24558
  return 1;
24497
24559
  }
24498
24560
  }
24499
- function walkParagraphs2(document2) {
24500
- const envelope = document2;
24501
- const root = "content" in envelope ? envelope.content : document2;
24502
- const out = [];
24561
+ function paragraphLengthForScopeCoordinates(paragraph) {
24562
+ return paragraph.children.reduce(
24563
+ (total, child) => total + inlineLengthForScopeCoordinates(child),
24564
+ 0
24565
+ );
24566
+ }
24567
+ function computeScopeStoryLayout(document2) {
24568
+ const root = document2.content;
24569
+ const paragraphSlots = [];
24570
+ const blockSlots = [];
24571
+ if (!root || root.type !== "doc") {
24572
+ return { paragraphSlots, blockSlots, storyLength: 0 };
24573
+ }
24503
24574
  let cursor = 0;
24504
24575
  for (let index = 0; index < root.children.length; index += 1) {
24505
24576
  const block = root.children[index];
24506
- if (block && block.type === "paragraph") {
24507
- out.push({ paragraph: block, from: cursor });
24508
- cursor += block.children.reduce(
24509
- (total, child) => total + inlineLength(child),
24510
- 0
24511
- );
24512
- } else if (block && block.type === "table") {
24513
- cursor += 1;
24514
- } else {
24577
+ if (!block) continue;
24578
+ cursor = walkBlockForScopeCoordinates(
24579
+ block,
24580
+ cursor,
24581
+ [{ kind: "block", index }],
24582
+ index,
24583
+ paragraphSlots,
24584
+ blockSlots
24585
+ );
24586
+ if (index < root.children.length - 1 && root.children[index + 1]?.type === "paragraph") {
24515
24587
  cursor += 1;
24516
24588
  }
24517
- if (index < root.children.length - 1) {
24518
- cursor += 1;
24589
+ }
24590
+ return { paragraphSlots, blockSlots, storyLength: cursor };
24591
+ }
24592
+ function findParagraphSlotAtPosition(layout, position, edge) {
24593
+ const matches = layout.paragraphSlots.filter(
24594
+ (slot) => position >= slot.from && position <= slot.to
24595
+ );
24596
+ if (matches.length === 0) return null;
24597
+ if (edge === "start") {
24598
+ return matches.find((slot) => slot.from === position) ?? matches.find((slot) => position > slot.from && position <= slot.to) ?? matches[0];
24599
+ }
24600
+ return matches.find((slot) => slot.to === position) ?? matches.find((slot) => position >= slot.from && position < slot.to) ?? matches[matches.length - 1];
24601
+ }
24602
+ function findOwningBlockSlotAtPosition(layout, position) {
24603
+ const matches = layout.blockSlots.filter(
24604
+ (slot) => position >= slot.from && position <= slot.to
24605
+ );
24606
+ if (matches.length === 0) return null;
24607
+ return matches.reduce(
24608
+ (best, slot) => slot.path.length >= best.path.length ? slot : best
24609
+ );
24610
+ }
24611
+ function sameScopeParagraphPath(a, b) {
24612
+ return scopeParagraphPathKey(a) === scopeParagraphPathKey(b);
24613
+ }
24614
+ function replaceParagraphChildrenAtPath(root, path, children) {
24615
+ return {
24616
+ ...root,
24617
+ children: replaceInBlockList(root.children, path, children)
24618
+ };
24619
+ }
24620
+ function removeScopeMarkersFromBlockList(blocks, scopeId) {
24621
+ let mutated = false;
24622
+ const nextBlocks = blocks.map((block) => {
24623
+ const result = removeScopeMarkersFromBlock(block, scopeId);
24624
+ if (result.mutated) mutated = true;
24625
+ return result.block;
24626
+ });
24627
+ return { blocks: nextBlocks, mutated };
24628
+ }
24629
+ function walkBlockForScopeCoordinates(block, cursor, path, rootBlockIndex, paragraphSlots, blockSlots) {
24630
+ const from = cursor;
24631
+ if (block.type === "paragraph") {
24632
+ const to2 = cursor + paragraphLengthForScopeCoordinates(block);
24633
+ const slot = { path, rootBlockIndex, kind: block.type, from, to: to2 };
24634
+ blockSlots.push(slot);
24635
+ paragraphSlots.push({ ...slot, paragraph: block });
24636
+ return to2;
24637
+ }
24638
+ if (block.type === "table") {
24639
+ let innerCursor = cursor;
24640
+ for (let rowIndex = 0; rowIndex < block.rows.length; rowIndex += 1) {
24641
+ const row2 = block.rows[rowIndex];
24642
+ for (let cellIndex = 0; cellIndex < row2.cells.length; cellIndex += 1) {
24643
+ const cell = row2.cells[cellIndex];
24644
+ for (let childIndex = 0; childIndex < cell.children.length; childIndex += 1) {
24645
+ const child = cell.children[childIndex];
24646
+ innerCursor = walkBlockForScopeCoordinates(
24647
+ child,
24648
+ innerCursor,
24649
+ [
24650
+ ...path,
24651
+ { kind: "tableCell", rowIndex, cellIndex },
24652
+ { kind: "block", index: childIndex }
24653
+ ],
24654
+ rootBlockIndex,
24655
+ paragraphSlots,
24656
+ blockSlots
24657
+ );
24658
+ }
24659
+ }
24519
24660
  }
24661
+ blockSlots.push({
24662
+ path,
24663
+ rootBlockIndex,
24664
+ kind: block.type,
24665
+ from,
24666
+ to: innerCursor
24667
+ });
24668
+ return innerCursor;
24520
24669
  }
24521
- return out;
24670
+ if (block.type === "sdt") {
24671
+ const descriptor = describeStructuredWrapperBlock(block, {
24672
+ projectVisibleTocContentControls: true
24673
+ });
24674
+ if (descriptor) {
24675
+ const to2 = cursor + 1;
24676
+ blockSlots.push({ path, rootBlockIndex, kind: block.type, from, to: to2 });
24677
+ return to2;
24678
+ }
24679
+ let innerCursor = cursor;
24680
+ for (let childIndex = 0; childIndex < block.children.length; childIndex += 1) {
24681
+ const child = block.children[childIndex];
24682
+ innerCursor = walkBlockForScopeCoordinates(
24683
+ child,
24684
+ innerCursor,
24685
+ [...path, { kind: "sdtChildren" }, { kind: "block", index: childIndex }],
24686
+ rootBlockIndex,
24687
+ paragraphSlots,
24688
+ blockSlots
24689
+ );
24690
+ }
24691
+ blockSlots.push({
24692
+ path,
24693
+ rootBlockIndex,
24694
+ kind: block.type,
24695
+ from,
24696
+ to: innerCursor
24697
+ });
24698
+ return innerCursor;
24699
+ }
24700
+ const to = cursor + 1;
24701
+ blockSlots.push({ path, rootBlockIndex, kind: block.type, from, to });
24702
+ return to;
24703
+ }
24704
+ function replaceInBlockList(blocks, path, children) {
24705
+ const [head, ...rest] = path;
24706
+ if (!head || head.kind !== "block") return [...blocks];
24707
+ return blocks.map((block, index) => {
24708
+ if (index !== head.index) return block;
24709
+ if (rest.length === 0) {
24710
+ return block.type === "paragraph" ? { ...block, children } : block;
24711
+ }
24712
+ return replaceInsideBlock(block, rest, children);
24713
+ });
24714
+ }
24715
+ function replaceInsideBlock(block, path, children) {
24716
+ const [head, ...rest] = path;
24717
+ if (!head) return block;
24718
+ if (block.type === "table" && head.kind === "tableCell") {
24719
+ const rows = block.rows.map((row2, rowIndex) => {
24720
+ if (rowIndex !== head.rowIndex) return row2;
24721
+ const cells = row2.cells.map((cell, cellIndex) => {
24722
+ if (cellIndex !== head.cellIndex) return cell;
24723
+ return {
24724
+ ...cell,
24725
+ children: replaceInBlockList(cell.children, rest, children)
24726
+ };
24727
+ });
24728
+ return { ...row2, cells };
24729
+ });
24730
+ return { ...block, rows };
24731
+ }
24732
+ if (block.type === "sdt" && head.kind === "sdtChildren") {
24733
+ return {
24734
+ ...block,
24735
+ children: replaceInBlockList(block.children, rest, children)
24736
+ };
24737
+ }
24738
+ return block;
24739
+ }
24740
+ function removeScopeMarkersFromBlock(block, scopeId) {
24741
+ if (block.type === "paragraph") {
24742
+ const kept = block.children.filter((child) => {
24743
+ return !((child.type === "scope_marker_start" || child.type === "scope_marker_end") && child.scopeId === scopeId);
24744
+ });
24745
+ if (kept.length === block.children.length) {
24746
+ return { block, mutated: false };
24747
+ }
24748
+ return { block: { ...block, children: kept }, mutated: true };
24749
+ }
24750
+ if (block.type === "table") {
24751
+ let mutated = false;
24752
+ const rows = block.rows.map((row2) => {
24753
+ let rowMutated = false;
24754
+ const cells = row2.cells.map((cell) => {
24755
+ const result = removeScopeMarkersFromBlockList(cell.children, scopeId);
24756
+ if (result.mutated) {
24757
+ mutated = true;
24758
+ rowMutated = true;
24759
+ }
24760
+ return result.mutated ? { ...cell, children: result.blocks } : cell;
24761
+ });
24762
+ return rowMutated ? { ...row2, cells } : row2;
24763
+ });
24764
+ return mutated ? { block: { ...block, rows }, mutated: true } : { block, mutated: false };
24765
+ }
24766
+ if (block.type === "sdt") {
24767
+ const result = removeScopeMarkersFromBlockList(block.children, scopeId);
24768
+ return result.mutated ? { block: { ...block, children: result.blocks }, mutated: true } : { block, mutated: false };
24769
+ }
24770
+ if (block.type === "custom_xml") {
24771
+ const result = removeScopeMarkersFromBlockList(block.children, scopeId);
24772
+ return result.mutated ? { block: { ...block, children: result.blocks }, mutated: true } : { block, mutated: false };
24773
+ }
24774
+ return { block, mutated: false };
24775
+ }
24776
+ function scopeParagraphPathKey(path) {
24777
+ return path.map((step) => {
24778
+ if (step.kind === "block") return `b:${step.index}`;
24779
+ if (step.kind === "tableCell") {
24780
+ return `tc:${step.rowIndex}:${step.cellIndex}`;
24781
+ }
24782
+ return "sdt";
24783
+ }).join("/");
24784
+ }
24785
+
24786
+ // src/runtime/workflow/scope-resolver.ts
24787
+ function walkParagraphs2(document2) {
24788
+ const envelope = document2;
24789
+ return computeScopeStoryLayout(envelope).paragraphSlots.map((slot) => ({
24790
+ paragraph: slot.paragraph,
24791
+ from: slot.from
24792
+ }));
24793
+ }
24794
+ function inlineLength(node) {
24795
+ return inlineLengthForScopeCoordinates(node);
24522
24796
  }
24523
24797
  function collectScopeLocations(document2) {
24524
24798
  const locations = /* @__PURE__ */ new Map();
@@ -25718,7 +25992,7 @@ function buildFormattingDebugEntry(inputs) {
25718
25992
  }
25719
25993
 
25720
25994
  // src/runtime/layout/layout-engine-version.ts
25721
- var LAYOUT_ENGINE_VERSION = 93;
25995
+ var LAYOUT_ENGINE_VERSION = 94;
25722
25996
 
25723
25997
  // src/runtime/layout/compat-input-ledger.ts
25724
25998
  var DEFAULT_COMPATIBILITY_MODE = 15;
@@ -26929,9 +27203,13 @@ function appendFragmentLayoutObjectSemanticEntries(input) {
26929
27203
  numberingCanonicalAddressKey: numbering.canonicalAddressKey,
26930
27204
  numberingListAddressKey: numbering.listAddressKey,
26931
27205
  numberingMarkerText: numbering.markerText,
27206
+ numberingMarkerTextPosture: numbering.markerTextPosture,
26932
27207
  numberingMarkerSuffix: numbering.markerSuffix,
26933
27208
  numberingFormat: numbering.format,
26934
27209
  numberingFormatPosture: numbering.formatPosture,
27210
+ numberingPicBulletId: numbering.picBulletId,
27211
+ numberingPicBulletMediaId: numbering.picBulletMediaId,
27212
+ numberingPictureBulletPosture: numbering.pictureBulletPosture,
26935
27213
  numberingUnavailableReasons: numbering.unavailableReasons,
26936
27214
  markerGlyphRect: markerProjection.rect,
26937
27215
  markerLaneRect: markerProjection.markerLaneRect,
@@ -33849,9 +34127,9 @@ function messageForPostureBlocker(blocker) {
33849
34127
  return void 0;
33850
34128
  }
33851
34129
  }
33852
- function auditFact(target, category, reason, operation) {
34130
+ function auditFact(target, category, reason, operation2) {
33853
34131
  return {
33854
- operation: operation ?? auditOperationForTarget(target),
34132
+ operation: operation2 ?? auditOperationForTarget(target),
33855
34133
  category,
33856
34134
  dispatch: "blocked-before-mutation",
33857
34135
  reason
@@ -33942,25 +34220,43 @@ function computeBlockPositions(document2) {
33942
34220
  let cursor = 0;
33943
34221
  for (let index = 0; index < root.children.length; index += 1) {
33944
34222
  const block = root.children[index];
34223
+ if (!block) continue;
33945
34224
  const from = cursor;
33946
- let length = 0;
33947
- if (block && block.type === "paragraph") {
33948
- length = block.children.reduce(
33949
- (total, child) => total + inlineLength2(child),
33950
- 0
33951
- );
33952
- } else {
33953
- length = 1;
33954
- }
33955
- cursor += length;
33956
- const to = cursor;
33957
- out.push({ blockIndex: index, from, to });
33958
- if (index < root.children.length - 1) {
34225
+ cursor += blockLength(block);
34226
+ out.push({ blockIndex: index, from, to: cursor });
34227
+ if (index < root.children.length - 1 && root.children[index + 1]?.type === "paragraph") {
33959
34228
  cursor += 1;
33960
34229
  }
33961
34230
  }
33962
34231
  return out;
33963
34232
  }
34233
+ function blockLength(block) {
34234
+ if (block.type === "paragraph") {
34235
+ return block.children.reduce(
34236
+ (total, child) => total + inlineLength2(child),
34237
+ 0
34238
+ );
34239
+ }
34240
+ if (block.type === "table") {
34241
+ let total = 0;
34242
+ for (const row2 of block.rows) {
34243
+ for (const cell of row2.cells) {
34244
+ for (const child of cell.children) {
34245
+ total += blockLength(child);
34246
+ }
34247
+ }
34248
+ }
34249
+ return total;
34250
+ }
34251
+ if (block.type === "sdt") {
34252
+ const descriptor = describeStructuredWrapperBlock(block, {
34253
+ projectVisibleTocContentControls: true
34254
+ });
34255
+ if (descriptor) return 1;
34256
+ return block.children.reduce((total, child) => total + blockLength(child), 0);
34257
+ }
34258
+ return 1;
34259
+ }
33964
34260
  function computeInlinePositions(document2, blocks) {
33965
34261
  const envelope = document2;
33966
34262
  const root = "content" in envelope ? envelope.content : document2;
@@ -34177,8 +34473,8 @@ function deriveReplaceability(kind, provenance) {
34177
34473
  if (kind === "scope") {
34178
34474
  if (provenance === "marker-backed") {
34179
34475
  return {
34180
- level: "preserve-only",
34181
- reason: "multi-paragraph-replace-not-implemented"
34476
+ level: "text-only",
34477
+ reason: "marker-backed-multi-paragraph-preserves-anchor"
34182
34478
  };
34183
34479
  }
34184
34480
  return {
@@ -35340,6 +35636,54 @@ function compileScopeKind(entry, options) {
35340
35636
  partial: true
35341
35637
  };
35342
35638
  }
35639
+ function compileScopeReplacement(entry, proposed, options) {
35640
+ if (entry.handle.provenance !== "marker-backed" || proposed.operation !== "replace" || options.posture !== "direct-edit") {
35641
+ return null;
35642
+ }
35643
+ const markerRange = buildScopePositionMap(options.document).markerScopes.get(
35644
+ entry.handle.scopeId
35645
+ );
35646
+ if (!markerRange) return null;
35647
+ if (proposed.proposedContent.kind === "text") {
35648
+ const text = proposed.proposedContent.text ?? "";
35649
+ return {
35650
+ scopeId: entry.handle.scopeId,
35651
+ targetKind: "scope",
35652
+ operation: proposed.operation,
35653
+ steps: Object.freeze([
35654
+ {
35655
+ kind: "text-replace",
35656
+ summary: `replace multi-paragraph scope ${entry.handle.scopeId} text [${markerRange.from}..${markerRange.to}] (len ${text.length})`,
35657
+ range: { from: markerRange.from, to: markerRange.to },
35658
+ text,
35659
+ ...proposed.formatting ? { formatting: proposed.formatting } : {}
35660
+ }
35661
+ ]),
35662
+ ...proposed.preserve ? { preserve: proposed.preserve } : {},
35663
+ posture: options.posture
35664
+ };
35665
+ }
35666
+ if (proposed.proposedContent.kind === "structured") {
35667
+ const fragment = proposed.proposedContent.structured;
35668
+ if (!isStructuredReplacementContent(fragment)) return null;
35669
+ return {
35670
+ scopeId: entry.handle.scopeId,
35671
+ targetKind: "scope",
35672
+ operation: proposed.operation,
35673
+ steps: Object.freeze([
35674
+ {
35675
+ kind: "fragment-replace",
35676
+ summary: `replace multi-paragraph scope ${entry.handle.scopeId} with structured fragment [${markerRange.from}..${markerRange.to}] (${fragment.blocks.length} block(s))`,
35677
+ range: { from: markerRange.from, to: markerRange.to },
35678
+ fragment
35679
+ }
35680
+ ]),
35681
+ ...proposed.preserve ? { preserve: proposed.preserve } : {},
35682
+ posture: options.posture
35683
+ };
35684
+ }
35685
+ return null;
35686
+ }
35343
35687
 
35344
35688
  // src/runtime/scopes/scope-kinds/table.ts
35345
35689
  function compileTableScope(entry, options = {}) {
@@ -36244,31 +36588,6 @@ function deriveScopeAdjacentGeometryEvidence(scope, entry, provider) {
36244
36588
  };
36245
36589
  }
36246
36590
 
36247
- // src/runtime/scopes/multi-paragraph-refusal.ts
36248
- var MULTI_PARAGRAPH_REPLACEMENT_REFUSAL = "compile-refused:scope:multi-paragraph-replace-not-implemented";
36249
- function shapeBlocker(shape) {
36250
- switch (shape) {
36251
- case "text":
36252
- return "compile-refused:scope:multi-paragraph-text-replace-not-implemented";
36253
- case "fragment":
36254
- return "compile-refused:scope:multi-paragraph-fragment-replace-not-implemented";
36255
- default:
36256
- return "compile-refused:scope:multi-paragraph-replace-shape-not-implemented";
36257
- }
36258
- }
36259
- function multiParagraphReplacementBlockers(shape = "unknown") {
36260
- return Object.freeze([
36261
- MULTI_PARAGRAPH_REPLACEMENT_REFUSAL,
36262
- shapeBlocker(shape),
36263
- "capability:scope:block-granular-replacement-lowering-required",
36264
- "capability:scope:provenance:marker-backed-required",
36265
- "capability:scope:layout-completeness-required",
36266
- "capability:scope:geometry-completeness-required",
36267
- "capability:scope:continuation-state-required",
36268
- "capability:scope:preservation-verdict-required"
36269
- ]);
36270
- }
36271
-
36272
36591
  // src/runtime/scopes/capabilities.ts
36273
36592
  var PARAGRAPH_LIKE = /* @__PURE__ */ new Set([
36274
36593
  "paragraph",
@@ -36485,10 +36804,9 @@ function replaceTextCapability(scope, context) {
36485
36804
  if (guard) return blocked(guard);
36486
36805
  if (scope.kind === "list-item") {
36487
36806
  return blocked(
36488
- "compile-blocked:list-text:authoritative-readback-required",
36807
+ "compile-blocked:list-text:exact-list-text-handle-required",
36489
36808
  [
36490
- "capability:list-item:authoritative-readback-required",
36491
- "capability:list-text:export-persistent-target-required"
36809
+ "capability:list-item:exact-list-text-handle-required"
36492
36810
  ]
36493
36811
  );
36494
36812
  }
@@ -36503,6 +36821,19 @@ function replaceTextCapability(scope, context) {
36503
36821
  generatedOrLinked
36504
36822
  );
36505
36823
  }
36824
+ if (scope.kind === "scope") {
36825
+ if (scope.workflow.effectiveMode === "suggest") {
36826
+ return unsupported(
36827
+ "compile-refused:scope:multi-paragraph-suggesting-not-implemented",
36828
+ ["compile-refused:scope:multi-paragraph-suggesting-not-implemented"],
36829
+ ["guard:suggest-mode", ...evidenceWarnings(context)]
36830
+ );
36831
+ }
36832
+ return supported(
36833
+ "compile-supported:scope:multi-paragraph-text-replace",
36834
+ evidenceWarnings(context)
36835
+ );
36836
+ }
36506
36837
  if (!PARAGRAPH_LIKE.has(scope.kind)) {
36507
36838
  if (scope.kind === "table-cell") {
36508
36839
  if (context?.tableCellTextRange?.status === "ok") {
@@ -36524,12 +36855,8 @@ function replaceTextCapability(scope, context) {
36524
36855
  ]
36525
36856
  );
36526
36857
  }
36527
- const reason = scope.kind === "scope" && scope.replaceability.reason ? MULTI_PARAGRAPH_REPLACEMENT_REFUSAL : `compile-refused:${scope.kind}`;
36528
- return unsupported(
36529
- reason,
36530
- scope.kind === "scope" ? multiParagraphReplacementBlockers("text") : [reason],
36531
- evidenceWarnings(context)
36532
- );
36858
+ const reason = `compile-refused:${scope.kind}`;
36859
+ return unsupported(reason, [reason], evidenceWarnings(context));
36533
36860
  }
36534
36861
  if (scope.replaceability.level === "blocked" || scope.replaceability.level === "preserve-only" || scope.replaceability.level === "formatting-only") {
36535
36862
  const reason = scope.replaceability.reason ? `replaceability:${scope.replaceability.reason}` : `replaceability:${scope.replaceability.level}`;
@@ -36557,14 +36884,25 @@ function replaceFragmentCapability(scope, context) {
36557
36884
  generatedOrLinked
36558
36885
  );
36559
36886
  }
36560
- if (!PARAGRAPH_LIKE.has(scope.kind)) {
36561
- const reason = scope.kind === "scope" && scope.replaceability.reason ? MULTI_PARAGRAPH_REPLACEMENT_REFUSAL : `compile-refused:${scope.kind}`;
36562
- return unsupported(
36563
- reason,
36564
- scope.kind === "scope" ? multiParagraphReplacementBlockers("fragment") : [reason],
36887
+ if (scope.kind === "scope") {
36888
+ if (scope.workflow.effectiveMode === "suggest") {
36889
+ return unsupported(
36890
+ "compile-refused:scope:multi-paragraph-structured-suggesting-not-implemented",
36891
+ [
36892
+ "compile-refused:scope:multi-paragraph-structured-suggesting-not-implemented"
36893
+ ],
36894
+ ["guard:suggest-mode", ...evidenceWarnings(context)]
36895
+ );
36896
+ }
36897
+ return supported(
36898
+ "compile-supported:scope:multi-paragraph-fragment-replace",
36565
36899
  evidenceWarnings(context)
36566
36900
  );
36567
36901
  }
36902
+ if (!PARAGRAPH_LIKE.has(scope.kind)) {
36903
+ const reason = `compile-refused:${scope.kind}`;
36904
+ return unsupported(reason, [reason], evidenceWarnings(context));
36905
+ }
36568
36906
  if (scope.workflow.effectiveMode === "suggest") {
36569
36907
  return unsupported(
36570
36908
  `compile-refused:${scope.kind}:structured-suggesting-not-implemented`,
@@ -39155,6 +39493,231 @@ function compileScopeBundleById(scopeId, inputs) {
39155
39493
  return compileScopeBundle(compiled, { ...inputs, scopes });
39156
39494
  }
39157
39495
 
39496
+ // src/runtime/scopes/editable-graph.ts
39497
+ function uniq(values) {
39498
+ return Object.freeze([...new Set(values.filter(Boolean))]);
39499
+ }
39500
+ function commandFamilyForTarget(target) {
39501
+ const intents = target.runtimeCommand.intents;
39502
+ if (target.table?.operationScope === "text" && target.runtimeCommand.commandFamily === "text-leaf") {
39503
+ return "table-text";
39504
+ }
39505
+ if (intents.some((intent) => intent.startsWith("table-"))) {
39506
+ if (intents.some((intent) => intent.includes("structure"))) {
39507
+ return "table-structure";
39508
+ }
39509
+ return "table-text";
39510
+ }
39511
+ if (intents.some((intent) => intent.startsWith("list-"))) {
39512
+ if (intents.some((intent) => intent.includes("structure"))) {
39513
+ return "list-structure";
39514
+ }
39515
+ return "list-text";
39516
+ }
39517
+ return target.runtimeCommand.commandFamily;
39518
+ }
39519
+ function familyForTarget(target) {
39520
+ if (target.runtimeCommand.intents.some(
39521
+ (intent) => intent === "table-structure-action" || intent === "table-merge-cells" || intent === "table-split-cell" || intent === "list-structure-action"
39522
+ )) {
39523
+ return "structure";
39524
+ }
39525
+ if (target.runtimeCommand.intents.some(
39526
+ (intent) => intent === "field-update" || intent === "toc-refresh" || intent === "hyperlink-update" || intent === "bookmark-update" || intent === "custom-xml-update"
39527
+ )) {
39528
+ return "value";
39529
+ }
39530
+ if (target.runtimeCommand.commandFamily === "object" || target.runtimeCommand.intents.some(
39531
+ (intent) => intent === "object-edit" || intent === "image-layout" || intent === "image-frame" || intent === "chart-edit" || intent === "embedded-content-update"
39532
+ )) {
39533
+ return "object";
39534
+ }
39535
+ if (target.runtimeCommand.commandFamily === "metadata") return "metadata";
39536
+ if (target.runtimeCommand.commandFamily === "preserve-only-refusal" || target.posture.preserveOnly || target.kind === "opaque-content") {
39537
+ return "preservation";
39538
+ }
39539
+ return "text";
39540
+ }
39541
+ function statusForTarget(target, family) {
39542
+ if (family === "preservation") return "preserve";
39543
+ if (target.runtimeCommand.status === "supported" && target.runtimeCommand.actionHandle) {
39544
+ return "ready";
39545
+ }
39546
+ if (target.runtimeCommand.status === "supported") return "diagnostic";
39547
+ return "needs-command";
39548
+ }
39549
+ function blockersForTarget(target) {
39550
+ return uniq([
39551
+ ...target.posture.blockers,
39552
+ ...target.runtimeTextCommand.blockers ?? [],
39553
+ ...target.runtimeCommand.blockers ?? [],
39554
+ ...target.workflowBlockers?.map((blocker) => blocker.blocker) ?? []
39555
+ ]);
39556
+ }
39557
+ function projectEditableTarget(target) {
39558
+ const family = familyForTarget(target);
39559
+ const commandFamily = commandFamilyForTarget(target);
39560
+ return Object.freeze({
39561
+ targetId: target.targetKey,
39562
+ family,
39563
+ kind: target.kind,
39564
+ relation: target.relation,
39565
+ status: statusForTarget(target, family),
39566
+ commandFamily,
39567
+ ...target.runtimeCommand.actionHandle ? { actionHandle: target.runtimeCommand.actionHandle } : {},
39568
+ ...target.runtimeCommand.canonicalAddress ? { canonicalAddress: target.runtimeCommand.canonicalAddress } : {},
39569
+ ...target.readback ? { readback: target.readback } : {},
39570
+ blockers: blockersForTarget(target),
39571
+ warnings: Object.freeze([]),
39572
+ intents: Object.freeze([...target.runtimeCommand.intents])
39573
+ });
39574
+ }
39575
+ function projectTableAction(action) {
39576
+ const family = action.family === "table-structure" ? "structure" : "text";
39577
+ const blockers = uniq(action.blockers ?? []);
39578
+ return Object.freeze({
39579
+ targetId: action.handle,
39580
+ family,
39581
+ kind: action.targetKind,
39582
+ relation: action.relation,
39583
+ status: action.status === "supported" && action.actionHandle ? "ready" : action.status === "supported" ? "diagnostic" : "needs-command",
39584
+ commandFamily: action.family,
39585
+ ...action.actionHandle ? { actionHandle: action.actionHandle } : {},
39586
+ ...action.canonicalAddress ? { canonicalAddress: action.canonicalAddress } : {},
39587
+ ...action.readback ? { readback: action.readback } : {},
39588
+ blockers,
39589
+ warnings: Object.freeze([...action.warnings ?? []]),
39590
+ intents: Object.freeze([...action.intents])
39591
+ });
39592
+ }
39593
+ function metadataTarget(bundle) {
39594
+ return Object.freeze({
39595
+ targetId: `${bundle.scope.handle.scopeId}:metadata`,
39596
+ family: "metadata",
39597
+ kind: "scope-metadata",
39598
+ status: "ready",
39599
+ commandFamily: "metadata",
39600
+ actionHandle: `scope-metadata:${bundle.scope.handle.scopeId}`,
39601
+ blockers: Object.freeze([]),
39602
+ warnings: Object.freeze([]),
39603
+ intents: Object.freeze(["metadata-update"])
39604
+ });
39605
+ }
39606
+ function scopeReplacementTarget(bundle) {
39607
+ const verdict = bundle.evidence.capabilities?.canReplaceText;
39608
+ if (!verdict?.supported) return null;
39609
+ return Object.freeze({
39610
+ targetId: `${bundle.scope.handle.scopeId}:scope-replace-text`,
39611
+ family: "text",
39612
+ kind: `${bundle.scope.kind}:scope-replacement`,
39613
+ relation: "exact-scope",
39614
+ status: "ready",
39615
+ commandFamily: "scope-replacement",
39616
+ blockers: Object.freeze([]),
39617
+ warnings: Object.freeze([...verdict.warnings ?? []]),
39618
+ intents: Object.freeze(["text-leaf-edit"])
39619
+ });
39620
+ }
39621
+ function group(targets, family) {
39622
+ return Object.freeze(targets.filter((target) => target.family === family));
39623
+ }
39624
+ function operation(kind, targets) {
39625
+ const ready = targets.filter((target) => target.status === "ready");
39626
+ const pending = targets.filter((target) => target.status === "needs-command");
39627
+ return Object.freeze({
39628
+ kind,
39629
+ status: ready.length > 0 ? "ready" : pending.length > 0 ? "needs-command" : "needs-target",
39630
+ targetIds: Object.freeze(ready.map((target) => target.targetId)),
39631
+ commandFamilies: uniq(ready.map((target) => target.commandFamily ?? ""))
39632
+ });
39633
+ }
39634
+ function contentModelFor(textTargets, valueTargets, structureTargets, objectTargets) {
39635
+ const families = [
39636
+ textTargets.length > 0 ? "text" : "",
39637
+ valueTargets.length > 0 ? "value" : "",
39638
+ structureTargets.length > 0 ? "structure" : "",
39639
+ objectTargets.length > 0 ? "object" : ""
39640
+ ].filter(Boolean);
39641
+ if (families.length === 0) return "metadata";
39642
+ if (families.length > 1) return "mixed";
39643
+ return families[0];
39644
+ }
39645
+ function summaryFor(model, targets) {
39646
+ const ready = targets.filter((target) => target.status === "ready").length;
39647
+ const needsCommand = targets.filter(
39648
+ (target) => target.status === "needs-command"
39649
+ ).length;
39650
+ const preserve = targets.filter((target) => target.status === "preserve").length;
39651
+ return `${model} scope editable graph: ${ready} ready target(s), ${needsCommand} target(s) needing command, ${preserve} preserve target(s)`;
39652
+ }
39653
+ function compileScopeEditableGraph(bundle) {
39654
+ const scopeTextTarget = scopeReplacementTarget(bundle);
39655
+ const projected = [
39656
+ ...bundle.evidence.editableTargets?.entries.map(projectEditableTarget) ?? [],
39657
+ ...bundle.evidence.table?.actions.map(projectTableAction) ?? [],
39658
+ ...scopeTextTarget ? [scopeTextTarget] : [],
39659
+ metadataTarget(bundle)
39660
+ ];
39661
+ const byId = /* @__PURE__ */ new Map();
39662
+ for (const target of projected) {
39663
+ const existing = byId.get(target.targetId);
39664
+ if (!existing || existing.status !== "ready") {
39665
+ byId.set(target.targetId, target);
39666
+ }
39667
+ }
39668
+ const targets = Object.freeze([...byId.values()]);
39669
+ const textTargets = group(targets, "text");
39670
+ const valueTargets = group(targets, "value");
39671
+ const structureTargets = group(targets, "structure");
39672
+ const objectTargets = group(targets, "object");
39673
+ const metadataTargets = group(targets, "metadata");
39674
+ const preservationTargets = group(targets, "preservation");
39675
+ const contentModel = contentModelFor(
39676
+ textTargets,
39677
+ valueTargets,
39678
+ structureTargets,
39679
+ objectTargets
39680
+ );
39681
+ const operations = Object.freeze([
39682
+ operation("replace-text", textTargets),
39683
+ operation("replace-value", valueTargets),
39684
+ operation("edit-structure", structureTargets),
39685
+ operation("edit-object", objectTargets),
39686
+ operation("attach-metadata", metadataTargets)
39687
+ ]);
39688
+ const readyTargetCount = targets.filter((target) => target.status === "ready").length;
39689
+ const needsCommandTargetCount = targets.filter(
39690
+ (target) => target.status === "needs-command"
39691
+ ).length;
39692
+ const preserveTargetCount = targets.filter(
39693
+ (target) => target.status === "preserve"
39694
+ ).length;
39695
+ const blockers = uniq(targets.flatMap((target) => target.blockers));
39696
+ const warnings = uniq(targets.flatMap((target) => target.warnings));
39697
+ const readiness = Object.freeze({
39698
+ status: readyTargetCount > metadataTargets.length ? needsCommandTargetCount > 0 || preserveTargetCount > 0 ? "partial" : "ready" : "metadata-only",
39699
+ readyTargetCount,
39700
+ needsCommandTargetCount,
39701
+ preserveTargetCount,
39702
+ blockers,
39703
+ warnings
39704
+ });
39705
+ return Object.freeze({
39706
+ scope: bundle.scope.handle,
39707
+ contentModel,
39708
+ targets,
39709
+ textTargets,
39710
+ valueTargets,
39711
+ structureTargets,
39712
+ objectTargets,
39713
+ metadataTargets,
39714
+ preservationTargets,
39715
+ operations,
39716
+ readiness,
39717
+ summary: summaryFor(contentModel, targets)
39718
+ });
39719
+ }
39720
+
39158
39721
  // src/runtime/scopes/issue-lifecycle.ts
39159
39722
  function documentHash(doc) {
39160
39723
  let textLength = 0;
@@ -39307,11 +39870,11 @@ function computePreservationVerdict(document2, range, positionMap) {
39307
39870
  }
39308
39871
 
39309
39872
  // src/runtime/scopes/action-validation.ts
39310
- function inferActionId(operation, content) {
39311
- if (operation === "formatting") {
39873
+ function inferActionId(operation2, content) {
39874
+ if (operation2 === "formatting") {
39312
39875
  return "fix_formatting";
39313
39876
  }
39314
- switch (operation) {
39877
+ switch (operation2) {
39315
39878
  case "replace":
39316
39879
  return content.kind === "text" ? "rewrite_paragraph" : "generate_text";
39317
39880
  case "insert-before":
@@ -39462,11 +40025,11 @@ function collectCapabilityVerdict(inputs, blockedReasons, warnings) {
39462
40025
  }
39463
40026
  }
39464
40027
  if (inputs.scope.kind === "list-item" && inputs.operation === "replace" && inputs.proposedContent.kind === "text") {
39465
- const code = "capability:list-item:authoritative-readback-required";
40028
+ const code = "capability:list-item:exact-list-text-handle-required";
39466
40029
  blockedReasons.push(code);
39467
40030
  warnings.push({
39468
40031
  code,
39469
- message: "list-item flat text replacement is blocked until the runtime validates an export-persistent list text command path",
40032
+ message: "list-item flat text replacement is blocked unless the caller uses an exact list-text action handle",
39470
40033
  source: "capability"
39471
40034
  });
39472
40035
  }
@@ -39703,11 +40266,44 @@ function compileReplacement(inputs) {
39703
40266
  inputs.posture,
39704
40267
  inputs.tableCellTextRange
39705
40268
  );
40269
+ case "scope":
40270
+ if (inputs.enumeratedScope.kind === "scope") {
40271
+ return compileScopeReplacement(inputs.enumeratedScope, inputs.proposed, {
40272
+ document: inputs.document,
40273
+ posture: inputs.posture
40274
+ });
40275
+ }
40276
+ return null;
39706
40277
  default:
39707
40278
  return null;
39708
40279
  }
39709
40280
  }
39710
40281
 
40282
+ // src/runtime/scopes/multi-paragraph-refusal.ts
40283
+ var MULTI_PARAGRAPH_REPLACEMENT_REFUSAL = "compile-refused:scope:multi-paragraph-replace-not-implemented";
40284
+ function shapeBlocker(shape) {
40285
+ switch (shape) {
40286
+ case "text":
40287
+ return "compile-refused:scope:multi-paragraph-text-replace-not-implemented";
40288
+ case "fragment":
40289
+ return "compile-refused:scope:multi-paragraph-fragment-replace-not-implemented";
40290
+ default:
40291
+ return "compile-refused:scope:multi-paragraph-replace-shape-not-implemented";
40292
+ }
40293
+ }
40294
+ function multiParagraphReplacementBlockers(shape = "unknown") {
40295
+ return Object.freeze([
40296
+ MULTI_PARAGRAPH_REPLACEMENT_REFUSAL,
40297
+ shapeBlocker(shape),
40298
+ "capability:scope:block-granular-replacement-lowering-required",
40299
+ "capability:scope:provenance:marker-backed-required",
40300
+ "capability:scope:layout-completeness-required",
40301
+ "capability:scope:geometry-completeness-required",
40302
+ "capability:scope:continuation-state-required",
40303
+ "capability:scope:preservation-verdict-required"
40304
+ ]);
40305
+ }
40306
+
39711
40307
  // src/runtime/scopes/replacement/apply.ts
39712
40308
  function documentHash2(doc) {
39713
40309
  let hash = 2166136261;
@@ -39870,14 +40466,18 @@ function applyScopeReplacement(inputs) {
39870
40466
  });
39871
40467
  if (!plan) {
39872
40468
  const paragraphLike = resolvedScope.kind === "paragraph" || resolvedScope.kind === "heading" || resolvedScope.kind === "list-item";
39873
- const blockers = resolvedScope.kind === "scope" ? multiParagraphReplacementBlockers(
40469
+ const blockers = resolvedScope.kind === "scope" && posture === "suggest-mode" ? [
40470
+ proposed.proposedContent.kind === "structured" ? "compile-refused:scope:multi-paragraph-structured-suggesting-not-implemented" : "compile-refused:scope:multi-paragraph-suggesting-not-implemented"
40471
+ ] : resolvedScope.kind === "scope" && proposed.operation !== "replace" ? [
40472
+ `compile-refused:scope:operation-not-implemented:${proposed.operation}`
40473
+ ] : resolvedScope.kind === "scope" ? multiParagraphReplacementBlockers(
39874
40474
  proposed.proposedContent.kind === "structured" ? "fragment" : "text"
39875
40475
  ) : paragraphLike && proposed.operation === "replace" && proposed.preserve?.opaqueFragments === true ? [
39876
40476
  `compile-refused:${resolvedScope.kind}:opaque-preserving-text-target-unavailable`
39877
40477
  ] : resolvedScope.kind === "table-cell" ? [tableCellRefusalBlocker(tableCellTextRange)] : paragraphLike && proposed.operation !== "replace" ? [
39878
40478
  `compile-refused:${resolvedScope.kind}:operation-not-implemented:${proposed.operation}`
39879
40479
  ] : [`compile-refused:${resolvedScope.kind}`];
39880
- const blocker = resolvedScope.kind === "scope" ? MULTI_PARAGRAPH_REPLACEMENT_REFUSAL : blockers[0] ?? `compile-refused:${resolvedScope.kind}`;
40480
+ const blocker = blockers[0] ?? `compile-refused:${resolvedScope.kind}`;
39881
40481
  const refused = {
39882
40482
  safe: false,
39883
40483
  posture: "hard-refusal",
@@ -40356,10 +40956,10 @@ function createScopeCompilerService(runtime) {
40356
40956
  emitMetadataAudit(request) {
40357
40957
  try {
40358
40958
  const snapshot = request.targetScopeSnapshot;
40359
- const operation = "annotate";
40959
+ const operation2 = "annotate";
40360
40960
  const proposed = {
40361
40961
  targetHandle: snapshot.handle,
40362
- operation,
40962
+ operation: operation2,
40363
40963
  proposedContent: {
40364
40964
  kind: "structured",
40365
40965
  structured: {
@@ -40434,6 +41034,10 @@ function createScopeCompilerService(runtime) {
40434
41034
  ...editableTargetCache ? { editableTargetCache } : {}
40435
41035
  });
40436
41036
  },
41037
+ compileEditableGraphById(scopeId, nowUtc) {
41038
+ const bundle = this.compileBundleById(scopeId, nowUtc);
41039
+ return bundle ? compileScopeEditableGraph(bundle) : null;
41040
+ },
40437
41041
  buildReplacementScope(targetHandle, input) {
40438
41042
  return proposeReplacement({
40439
41043
  targetHandle,
@@ -47368,11 +47972,45 @@ function createLayoutEngine(options = {}) {
47368
47972
  const telemetryBus = options.telemetryBus;
47369
47973
  const dirtyFieldFamilies = /* @__PURE__ */ new Set();
47370
47974
  const listeners = /* @__PURE__ */ new Set();
47371
- let cachedKey = null;
47372
- let cachedGraph = null;
47373
- let cachedFormatting = null;
47374
- let cachedMapper = null;
47975
+ let cachedFull = null;
47976
+ let cachedWindowed = null;
47375
47977
  let previousPageCount = 0;
47978
+ function isFullViewportKey(key) {
47979
+ return key === FULL_VIEWPORT_WINDOW_KEY;
47980
+ }
47981
+ function getCachedSlot(viewportWindowKeyValue) {
47982
+ return isFullViewportKey(viewportWindowKeyValue) ? cachedFull : cachedWindowed;
47983
+ }
47984
+ function preferredCachedGraph() {
47985
+ return cachedFull?.graph ?? cachedWindowed?.graph ?? null;
47986
+ }
47987
+ function clearAllSlots() {
47988
+ cachedFull = null;
47989
+ cachedWindowed = null;
47990
+ }
47991
+ function clearWindowedSlot() {
47992
+ cachedWindowed = null;
47993
+ }
47994
+ function evictStaleSiblingSlot(freshKey) {
47995
+ const sibling = isFullViewportKey(freshKey.viewportWindowKey) ? cachedWindowed : cachedFull;
47996
+ if (sibling === null) return;
47997
+ if (sibling.key.content === freshKey.content && sibling.key.styles === freshKey.styles && sibling.key.subParts === freshKey.subParts) {
47998
+ return;
47999
+ }
48000
+ if (isFullViewportKey(freshKey.viewportWindowKey)) {
48001
+ cachedWindowed = null;
48002
+ } else {
48003
+ cachedFull = null;
48004
+ }
48005
+ }
48006
+ function commitSlot(slot) {
48007
+ if (isFullViewportKey(slot.key.viewportWindowKey)) {
48008
+ cachedFull = slot;
48009
+ } else {
48010
+ cachedWindowed = slot;
48011
+ }
48012
+ evictStaleSiblingSlot(slot.key);
48013
+ }
47376
48014
  let pendingInvalidation = null;
47377
48015
  function emit(event) {
47378
48016
  for (const listener of listeners) {
@@ -47518,27 +48156,31 @@ function createLayoutEngine(options = {}) {
47518
48156
  subParts: document2.subParts,
47519
48157
  anchors: layoutInputs.anchors
47520
48158
  });
48159
+ const priorGraphForMaterialization = preferredCachedGraph();
47521
48160
  const graph = applyViewportWindowMaterialization(
47522
48161
  measuredGraph,
47523
48162
  viewportWindow,
47524
- cachedGraph
48163
+ priorGraphForMaterialization
47525
48164
  );
47526
- const dirtyFamilies = computeFieldDirtiness(cachedGraph, graph);
48165
+ const priorGraphForFieldDirtiness = preferredCachedGraph();
48166
+ const dirtyFamilies = computeFieldDirtiness(priorGraphForFieldDirtiness, graph);
47527
48167
  for (const family of dirtyFamilies) {
47528
48168
  dirtyFieldFamilies.add(family);
47529
48169
  }
47530
48170
  const formatting = buildResolvedFormattingState(document2, mainSurface);
47531
48171
  const currentPageCount = graph.contentPageCount;
47532
48172
  const pageCountDelta = currentPageCount !== previousPageCount ? { previous: previousPageCount, current: currentPageCount } : void 0;
47533
- cachedKey = {
47534
- content: document2.content,
47535
- styles: document2.styles,
47536
- subParts: document2.subParts,
47537
- viewportWindowKey: viewportWindowKey(viewportWindow)
47538
- };
47539
- cachedGraph = graph;
47540
- cachedFormatting = formatting;
47541
- cachedMapper = createPageFragmentMapper(graph);
48173
+ commitSlot({
48174
+ key: {
48175
+ content: document2.content,
48176
+ styles: document2.styles,
48177
+ subParts: document2.subParts,
48178
+ viewportWindowKey: viewportWindowKey(viewportWindow)
48179
+ },
48180
+ graph,
48181
+ formatting,
48182
+ mapper: createPageFragmentMapper(graph)
48183
+ });
47542
48184
  if (pageCountDelta) {
47543
48185
  emit({
47544
48186
  kind: "page_count_changed",
@@ -47579,7 +48221,7 @@ function createLayoutEngine(options = {}) {
47579
48221
  return graph;
47580
48222
  }
47581
48223
  function incrementalRelayout(input, pending) {
47582
- const priorGraph = cachedGraph;
48224
+ const priorGraph = cachedFull?.graph ?? null;
47583
48225
  const range = pending.result.dirtyPageRange;
47584
48226
  if (!priorGraph || !range) return null;
47585
48227
  const telemetryOn = telemetryBus?.isEnabled("layout") ?? false;
@@ -47672,6 +48314,22 @@ function createLayoutEngine(options = {}) {
47672
48314
  deriveDocumentPageSnapshots(splicedGraph)
47673
48315
  );
47674
48316
  const pageCountDelta = currentPageCount !== previousPageCount ? { previous: previousPageCount, current: currentPageCount } : void 0;
48317
+ const priorMapper = cachedFull?.mapper ?? null;
48318
+ commitSlot({
48319
+ key: {
48320
+ content: document2.content,
48321
+ styles: document2.styles,
48322
+ subParts: document2.subParts,
48323
+ viewportWindowKey: FULL_VIEWPORT_WINDOW_KEY
48324
+ },
48325
+ graph: splicedGraph,
48326
+ formatting,
48327
+ mapper: rebuildMapper(
48328
+ priorMapper ?? createPageFragmentMapper(splicedGraph),
48329
+ splicedGraph,
48330
+ firstDirty
48331
+ )
48332
+ });
47675
48333
  if (pageCountDelta) {
47676
48334
  emit({
47677
48335
  kind: "page_count_changed",
@@ -47701,19 +48359,6 @@ function createLayoutEngine(options = {}) {
47701
48359
  ...dirtyFamilies.length > 0 ? { dirtyFieldFamilies: dirtyFamilies } : {},
47702
48360
  ...pageCountDelta ? { pageCountDelta } : {}
47703
48361
  });
47704
- cachedKey = {
47705
- content: document2.content,
47706
- styles: document2.styles,
47707
- subParts: document2.subParts,
47708
- viewportWindowKey: FULL_VIEWPORT_WINDOW_KEY
47709
- };
47710
- cachedGraph = splicedGraph;
47711
- cachedFormatting = formatting;
47712
- cachedMapper = rebuildMapper(
47713
- cachedMapper ?? createPageFragmentMapper(splicedGraph),
47714
- splicedGraph,
47715
- firstDirty
47716
- );
47717
48362
  if (telemetryOn) {
47718
48363
  emitRecomputeCompleted(
47719
48364
  "bounded",
@@ -47730,13 +48375,14 @@ function createLayoutEngine(options = {}) {
47730
48375
  const document2 = input.document;
47731
48376
  const normalizedWindow = normalizeViewportPageWindow(input.viewportPageWindow);
47732
48377
  const currentViewportWindowKey = viewportWindowKey(normalizedWindow);
47733
- const keyEqual = cachedGraph !== null && cachedKey !== null && cachedKey.content === document2.content && cachedKey.styles === document2.styles && cachedKey.subParts === document2.subParts && cachedKey.viewportWindowKey === currentViewportWindowKey;
48378
+ const slot = getCachedSlot(currentViewportWindowKey);
48379
+ const keyEqual = slot !== null && slot.key.content === document2.content && slot.key.styles === document2.styles && slot.key.subParts === document2.subParts && slot.key.viewportWindowKey === currentViewportWindowKey;
47734
48380
  if (keyEqual && pendingInvalidation === null) {
47735
- return cachedGraph;
48381
+ return slot.graph;
47736
48382
  }
47737
48383
  const pending = pendingInvalidation;
47738
48384
  pendingInvalidation = null;
47739
- if (pending !== null && pending.result.scope === "bounded" && cachedGraph !== null && normalizedWindow === void 0) {
48385
+ if (pending !== null && pending.result.scope === "bounded" && cachedFull !== null && normalizedWindow === void 0) {
47740
48386
  const spliced = incrementalRelayout(input, pending);
47741
48387
  if (spliced !== null) {
47742
48388
  return spliced;
@@ -47745,16 +48391,39 @@ function createLayoutEngine(options = {}) {
47745
48391
  }
47746
48392
  return fullRebuild(input, pending?.reason);
47747
48393
  }
48394
+ function ensureSlotMapperAndFormatting(slot, document2) {
48395
+ if (slot.mapper === null) {
48396
+ slot.mapper = createPageFragmentMapper(slot.graph);
48397
+ }
48398
+ if (slot.formatting === null) {
48399
+ const mainSurface = createEditorSurfaceSnapshot(
48400
+ document2,
48401
+ createSelectionSnapshot(0, 0),
48402
+ MAIN_STORY_TARGET
48403
+ );
48404
+ slot.formatting = buildResolvedFormattingState(document2, mainSurface);
48405
+ }
48406
+ }
47748
48407
  function getMapper(input) {
47749
48408
  getGraphInternal(input);
47750
- return cachedMapper;
48409
+ const currentViewportWindowKey = viewportWindowKey(
48410
+ normalizeViewportPageWindow(input.viewportPageWindow)
48411
+ );
48412
+ const slot = getCachedSlot(currentViewportWindowKey);
48413
+ ensureSlotMapperAndFormatting(slot, input.document);
48414
+ return slot.mapper;
47751
48415
  }
47752
48416
  function getFormatting(input) {
47753
48417
  getGraphInternal(input);
47754
- return cachedFormatting;
48418
+ const currentViewportWindowKey = viewportWindowKey(
48419
+ normalizeViewportPageWindow(input.viewportPageWindow)
48420
+ );
48421
+ const slot = getCachedSlot(currentViewportWindowKey);
48422
+ ensureSlotMapperAndFormatting(slot, input.document);
48423
+ return slot.formatting;
47755
48424
  }
47756
48425
  if (autoUpgradeToCanvas && options.measurementProvider === void 0 && typeof document !== "undefined" && typeof HTMLCanvasElement !== "undefined") {
47757
- const readCachedRevision = () => cachedGraph?.revision ?? 0;
48426
+ const readCachedRevision = () => preferredCachedGraph()?.revision ?? 0;
47758
48427
  void (async () => {
47759
48428
  try {
47760
48429
  const mod = await Promise.resolve().then(() => (init_measurement_backend_canvas(), measurement_backend_canvas_exports));
@@ -47764,10 +48433,7 @@ function createLayoutEngine(options = {}) {
47764
48433
  options.measurementCache,
47765
48434
  telemetryBus
47766
48435
  );
47767
- cachedKey = null;
47768
- cachedGraph = null;
47769
- cachedFormatting = null;
47770
- cachedMapper = null;
48436
+ clearAllSlots();
47771
48437
  emit({
47772
48438
  kind: "measurement_backend_ready",
47773
48439
  revision: readCachedRevision(),
@@ -47811,22 +48477,19 @@ function createLayoutEngine(options = {}) {
47811
48477
  return getMapper(input);
47812
48478
  },
47813
48479
  invalidate(reason) {
47814
- const result = analyzeInvalidation(reason, cachedGraph);
48480
+ const result = analyzeInvalidation(reason, preferredCachedGraph());
47815
48481
  for (const family of result.dirtyFieldFamilies) {
47816
48482
  dirtyFieldFamilies.add(family);
47817
48483
  }
47818
48484
  if (result.scope === "bounded") {
47819
48485
  pendingInvalidation = { reason, result };
47820
48486
  } else {
47821
- cachedKey = null;
47822
- cachedGraph = null;
47823
- cachedFormatting = null;
47824
- cachedMapper = null;
48487
+ clearAllSlots();
47825
48488
  pendingInvalidation = { reason, result };
47826
48489
  }
47827
48490
  },
47828
48491
  analyzeInvalidation(reason) {
47829
- return analyzeInvalidation(reason, cachedGraph);
48492
+ return analyzeInvalidation(reason, preferredCachedGraph());
47830
48493
  },
47831
48494
  getDirtyFieldFamilies() {
47832
48495
  return Array.from(dirtyFieldFamilies);
@@ -47854,14 +48517,11 @@ function createLayoutEngine(options = {}) {
47854
48517
  telemetryBus
47855
48518
  );
47856
48519
  if (previousFidelity !== provider.fidelity) {
47857
- cachedKey = null;
47858
- cachedGraph = null;
47859
- cachedFormatting = null;
47860
- cachedMapper = null;
48520
+ clearAllSlots();
47861
48521
  }
47862
48522
  emit({
47863
48523
  kind: "measurement_backend_ready",
47864
- revision: cachedGraph?.revision ?? 0,
48524
+ revision: preferredCachedGraph()?.revision ?? 0,
47865
48525
  fidelity: provider.fidelity
47866
48526
  });
47867
48527
  },
@@ -47876,30 +48536,33 @@ function createLayoutEngine(options = {}) {
47876
48536
  */
47877
48537
  invalidateMeasurementCache() {
47878
48538
  measurementProvider.invalidateCache();
47879
- cachedKey = null;
47880
- cachedGraph = null;
47881
- cachedFormatting = null;
47882
- cachedMapper = null;
48539
+ clearAllSlots();
47883
48540
  },
47884
48541
  getMeasurementCacheStats() {
47885
48542
  if (!isCachedLayoutMeasurementProvider(measurementProvider)) return null;
47886
48543
  return measurementProvider.measurementCacheStats();
47887
48544
  },
47888
48545
  /**
47889
- * L7 Phase 2.5 — seed the cached graph from a prerender envelope.
47890
- * Populates both `cachedGraph` and `cachedKey` (keyed on the provided
47891
- * document's identity-equal slots) so the next getPageGraph query
47892
- * returns the seeded graph directly. Any subsequent mutation
47893
- * invalidates normally through the existing path.
48546
+ * L7 Phase 2.5 — seed the full-slot cached graph from a prerender
48547
+ * envelope. Populates the full slot (graph + key, with formatting and
48548
+ * mapper computed lazily on first read) so the next viewport-
48549
+ * independent `getPageGraph` query returns the seeded graph directly.
48550
+ * Any subsequent mutation invalidates normally through the existing
48551
+ * path; sibling eviction in `commitSlot` clears `cachedWindowed` if
48552
+ * it carried a different document tuple.
47894
48553
  */
47895
48554
  seedCachedGraph(graph, document2) {
47896
- cachedGraph = graph;
47897
- cachedKey = {
47898
- content: document2.content,
47899
- styles: document2.styles,
47900
- subParts: document2.subParts,
47901
- viewportWindowKey: FULL_VIEWPORT_WINDOW_KEY
47902
- };
48555
+ commitSlot({
48556
+ key: {
48557
+ content: document2.content,
48558
+ styles: document2.styles,
48559
+ subParts: document2.subParts,
48560
+ viewportWindowKey: FULL_VIEWPORT_WINDOW_KEY
48561
+ },
48562
+ graph,
48563
+ formatting: null,
48564
+ mapper: null
48565
+ });
47903
48566
  previousPageCount = graph.contentPageCount;
47904
48567
  }
47905
48568
  };
@@ -48167,7 +48830,7 @@ function attachScopeCardModel(input) {
48167
48830
  primaryAnchorRect: null,
48168
48831
  ...anchor ? { anchor } : {},
48169
48832
  ...issue ? { issue } : {},
48170
- suggestionGroupIds: suggestionGroups.map((group) => group.groupId),
48833
+ suggestionGroupIds: suggestionGroups.map((group2) => group2.groupId),
48171
48834
  suggestionGroups,
48172
48835
  reviewActionCount: reviewActions.length,
48173
48836
  reviewActions,
@@ -48178,7 +48841,7 @@ function attachScopeCardModel(input) {
48178
48841
  }
48179
48842
  function resolveSuggestionGroupsForIssue(issueId, suggestions) {
48180
48843
  if (!issueId || !suggestions?.groups) return [];
48181
- return suggestions.groups.filter((group) => group.issueId === issueId);
48844
+ return suggestions.groups.filter((group2) => group2.issueId === issueId);
48182
48845
  }
48183
48846
  function resolveReviewActionsForIssue(issueId, metadata, externalResolutions) {
48184
48847
  if (!issueId || !metadata || metadata.length === 0) return [];
@@ -48253,39 +48916,8 @@ function insertScopeMarkers(document2, params) {
48253
48916
  to: normalizedTo
48254
48917
  };
48255
48918
  }
48256
- const paraSlots = [];
48257
- let cursor = 0;
48258
- let fromBlockIndex = -1;
48259
- let fromBlockKind = null;
48260
- let toBlockIndex = -1;
48261
- let toBlockKind = null;
48262
- let storyLength = 0;
48263
- for (let i = 0; i < root.children.length; i += 1) {
48264
- const block = root.children[i];
48265
- const blockFrom = cursor;
48266
- let blockLength;
48267
- if (block.type === "paragraph") {
48268
- blockLength = block.children.reduce(
48269
- (total, child) => total + inlineLength4(child),
48270
- 0
48271
- );
48272
- paraSlots.push({ index: i, from: blockFrom, to: blockFrom + blockLength });
48273
- } else {
48274
- blockLength = 1;
48275
- }
48276
- const blockTo = blockFrom + blockLength;
48277
- if (fromBlockIndex === -1 && normalizedFrom >= blockFrom && normalizedFrom <= blockTo) {
48278
- fromBlockIndex = i;
48279
- fromBlockKind = block.type;
48280
- }
48281
- if (toBlockIndex === -1 && normalizedTo >= blockFrom && normalizedTo <= blockTo) {
48282
- toBlockIndex = i;
48283
- toBlockKind = block.type;
48284
- }
48285
- cursor = blockTo;
48286
- if (i < root.children.length - 1) cursor += 1;
48287
- storyLength = cursor;
48288
- }
48919
+ const layout = computeScopeStoryLayout(document2);
48920
+ const storyLength = layout.storyLength;
48289
48921
  if (normalizedFrom < 0 || normalizedTo > storyLength) {
48290
48922
  return {
48291
48923
  status: "range-out-of-bounds",
@@ -48295,73 +48927,71 @@ function insertScopeMarkers(document2, params) {
48295
48927
  storyLength
48296
48928
  };
48297
48929
  }
48298
- if (fromBlockIndex === -1 || toBlockIndex === -1) {
48299
- return {
48300
- status: "range-out-of-bounds",
48301
- scopeId,
48302
- from: normalizedFrom,
48303
- to: normalizedTo,
48304
- storyLength
48305
- };
48306
- }
48307
- if (fromBlockKind !== "paragraph" || toBlockKind !== "paragraph") {
48308
- const nonParaIndex = fromBlockKind !== "paragraph" ? fromBlockIndex : toBlockIndex;
48309
- const nonParaKind = fromBlockKind !== "paragraph" ? fromBlockKind : toBlockKind;
48930
+ const startSlot = findParagraphSlotAtPosition(
48931
+ layout,
48932
+ normalizedFrom,
48933
+ "start"
48934
+ );
48935
+ const endSlot = findParagraphSlotAtPosition(layout, normalizedTo, "end");
48936
+ if (!startSlot || !endSlot) {
48937
+ const offenderPosition = !startSlot ? normalizedFrom : normalizedTo;
48938
+ const owner = findOwningBlockSlotAtPosition(layout, offenderPosition);
48310
48939
  return {
48311
48940
  status: "non-paragraph-target",
48312
48941
  scopeId,
48313
48942
  from: normalizedFrom,
48314
48943
  to: normalizedTo,
48315
- blockIndex: nonParaIndex,
48316
- blockKind: nonParaKind ?? "unknown"
48944
+ blockIndex: owner?.rootBlockIndex ?? -1,
48945
+ blockKind: owner?.kind ?? "unknown"
48317
48946
  };
48318
48947
  }
48319
- const startSlot = paraSlots.find((s) => s.index === fromBlockIndex);
48320
- const endSlot = paraSlots.find((s) => s.index === toBlockIndex);
48321
- if (startSlot.index === endSlot.index) {
48948
+ if (sameScopeParagraphPath(startSlot.path, endSlot.path)) {
48322
48949
  const newChildren = injectMarkersIntoInlineList(
48323
- root.children[startSlot.index].children,
48950
+ startSlot.paragraph.children,
48324
48951
  scopeId,
48325
48952
  normalizedFrom - startSlot.from,
48326
48953
  normalizedTo - startSlot.from,
48327
48954
  "both"
48328
48955
  );
48329
- const children2 = root.children.map(
48330
- (block, i) => i === startSlot.index ? { ...block, children: newChildren } : block
48956
+ const nextRoot = replaceParagraphChildrenAtPath(
48957
+ root,
48958
+ startSlot.path,
48959
+ newChildren
48331
48960
  );
48332
48961
  return {
48333
48962
  status: "planted",
48334
- document: { ...document2, content: { ...root, children: children2 } },
48963
+ document: { ...document2, content: nextRoot },
48335
48964
  scopeId,
48336
48965
  plantedRange: { from: normalizedFrom, to: normalizedTo }
48337
48966
  };
48338
48967
  }
48339
- const children = root.children.map((block, i) => {
48340
- if (i === startSlot.index) {
48341
- const newChildren = injectMarkersIntoInlineList(
48342
- block.children,
48343
- scopeId,
48344
- normalizedFrom - startSlot.from,
48345
- Number.POSITIVE_INFINITY,
48346
- "start-only"
48347
- );
48348
- return { ...block, children: newChildren };
48349
- }
48350
- if (i === endSlot.index) {
48351
- const newChildren = injectMarkersIntoInlineList(
48352
- block.children,
48353
- scopeId,
48354
- Number.NEGATIVE_INFINITY,
48355
- normalizedTo - endSlot.from,
48356
- "end-only"
48357
- );
48358
- return { ...block, children: newChildren };
48359
- }
48360
- return block;
48361
- });
48968
+ const startChildren = injectMarkersIntoInlineList(
48969
+ startSlot.paragraph.children,
48970
+ scopeId,
48971
+ normalizedFrom - startSlot.from,
48972
+ Number.POSITIVE_INFINITY,
48973
+ "start-only"
48974
+ );
48975
+ const endChildren = injectMarkersIntoInlineList(
48976
+ endSlot.paragraph.children,
48977
+ scopeId,
48978
+ Number.NEGATIVE_INFINITY,
48979
+ normalizedTo - endSlot.from,
48980
+ "end-only"
48981
+ );
48982
+ const rootWithStart = replaceParagraphChildrenAtPath(
48983
+ root,
48984
+ startSlot.path,
48985
+ startChildren
48986
+ );
48987
+ const rootWithBoth = replaceParagraphChildrenAtPath(
48988
+ rootWithStart,
48989
+ endSlot.path,
48990
+ endChildren
48991
+ );
48362
48992
  return {
48363
48993
  status: "planted",
48364
- document: { ...document2, content: { ...root, children } },
48994
+ document: { ...document2, content: rootWithBoth },
48365
48995
  scopeId,
48366
48996
  plantedRange: { from: normalizedFrom, to: normalizedTo }
48367
48997
  };
@@ -48369,43 +48999,15 @@ function insertScopeMarkers(document2, params) {
48369
48999
  function removeScopeMarkers(document2, scopeId) {
48370
49000
  const root = document2.content;
48371
49001
  if (!root || root.type !== "doc") return document2;
48372
- let mutated = false;
48373
- const children = root.children.map((block) => {
48374
- if (block.type !== "paragraph") return block;
48375
- const kept = block.children.filter((child) => {
48376
- if ((child.type === "scope_marker_start" || child.type === "scope_marker_end") && child.scopeId === scopeId) {
48377
- mutated = true;
48378
- return false;
48379
- }
48380
- return true;
48381
- });
48382
- if (kept.length === block.children.length) return block;
48383
- return { ...block, children: kept };
48384
- });
48385
- if (!mutated) return document2;
49002
+ const result = removeScopeMarkersFromBlockList(root.children, scopeId);
49003
+ if (!result.mutated) return document2;
48386
49004
  return {
48387
49005
  ...document2,
48388
- content: { ...root, children }
49006
+ content: { ...root, children: result.blocks }
48389
49007
  };
48390
49008
  }
48391
49009
  function inlineLength4(node) {
48392
- switch (node.type) {
48393
- case "text":
48394
- return Array.from(node.text).length;
48395
- case "hyperlink":
48396
- case "field":
48397
- return node.children.reduce(
48398
- (total, child) => total + inlineLength4(child),
48399
- 0
48400
- );
48401
- case "bookmark_start":
48402
- case "bookmark_end":
48403
- case "scope_marker_start":
48404
- case "scope_marker_end":
48405
- return 0;
48406
- default:
48407
- return 1;
48408
- }
49010
+ return inlineLengthForScopeCoordinates(node);
48409
49011
  }
48410
49012
  function injectMarkersIntoInlineList(inlines, scopeId, startOffset, endOffset, mode) {
48411
49013
  const start = { type: "scope_marker_start", scopeId };
@@ -48673,11 +49275,11 @@ function projectEntries(kind, input) {
48673
49275
  }
48674
49276
  function projectIssueEntries(input) {
48675
49277
  const suggestionGroupsByIssueId = /* @__PURE__ */ new Map();
48676
- for (const group of input.suggestions?.groups ?? []) {
48677
- if (!group.issueId) continue;
48678
- const ids = suggestionGroupsByIssueId.get(group.issueId) ?? [];
48679
- ids.push(group.groupId);
48680
- suggestionGroupsByIssueId.set(group.issueId, ids);
49278
+ for (const group2 of input.suggestions?.groups ?? []) {
49279
+ if (!group2.issueId) continue;
49280
+ const ids = suggestionGroupsByIssueId.get(group2.issueId) ?? [];
49281
+ ids.push(group2.groupId);
49282
+ suggestionGroupsByIssueId.set(group2.issueId, ids);
48681
49283
  }
48682
49284
  return (input.workflowMarkup?.metadata ?? []).filter((entry) => entry.metadataId === ISSUE_METADATA_ID).map((entry) => {
48683
49285
  const issueValue = isRecord3(entry.value) ? entry.value : void 0;
@@ -51038,13 +51640,13 @@ function createLayoutFacet(input) {
51038
51640
  createSelectionSnapshot(0, 0)
51039
51641
  );
51040
51642
  let cursor = 0;
51041
- for (const group of groups) {
51042
- for (let i = 0; i < group.count; i += 1) {
51643
+ for (const group2 of groups) {
51644
+ for (let i = 0; i < group2.count; i += 1) {
51043
51645
  const blockSnapshot = surface.blocks[cursor + i];
51044
51646
  if (!blockSnapshot) continue;
51045
51647
  blocks.push({
51046
51648
  blockId: blockSnapshot.blockId,
51047
- fragmentId: `endnote-${group.noteId}-${i}`,
51649
+ fragmentId: `endnote-${group2.noteId}-${i}`,
51048
51650
  pageIndex: -1,
51049
51651
  regionKind: "endnote-area",
51050
51652
  runtimeFromOffset: blockSnapshot.from,
@@ -51053,7 +51655,7 @@ function createLayoutFacet(input) {
51053
51655
  blockSnapshot
51054
51656
  });
51055
51657
  }
51056
- cursor += group.count;
51658
+ cursor += group2.count;
51057
51659
  }
51058
51660
  }
51059
51661
  }
@@ -52448,9 +53050,9 @@ function resolveFootnoteAreaRegionBlocks(node, document2) {
52448
53050
  );
52449
53051
  const blocks = [];
52450
53052
  let cursor = 0;
52451
- for (const group of groups) {
52452
- const fragmentBase = group.allocation.fragmentId ?? `note-${node.pageIndex}-${group.allocation.noteId}`;
52453
- for (let i = 0; i < group.count; i += 1) {
53053
+ for (const group2 of groups) {
53054
+ const fragmentBase = group2.allocation.fragmentId ?? `note-${node.pageIndex}-${group2.allocation.noteId}`;
53055
+ for (let i = 0; i < group2.count; i += 1) {
52454
53056
  const blockSnapshot = surface.blocks[cursor + i];
52455
53057
  if (!blockSnapshot) continue;
52456
53058
  blocks.push({
@@ -52460,11 +53062,11 @@ function resolveFootnoteAreaRegionBlocks(node, document2) {
52460
53062
  regionKind: "footnote-area",
52461
53063
  runtimeFromOffset: blockSnapshot.from,
52462
53064
  runtimeToOffset: blockSnapshot.to,
52463
- heightTwips: group.allocation.reservedHeightTwips,
53065
+ heightTwips: group2.allocation.reservedHeightTwips,
52464
53066
  blockSnapshot
52465
53067
  });
52466
53068
  }
52467
- cursor += group.count;
53069
+ cursor += group2.count;
52468
53070
  }
52469
53071
  return Object.freeze(blocks);
52470
53072
  }
@@ -55251,6 +55853,14 @@ function createDocumentRuntime(options) {
55251
55853
  let effectiveMarkupModeProvider;
55252
55854
  const perfCounters = new PerfCounters();
55253
55855
  const hotEditTraces = new HotEditTraceRecorder();
55856
+ const scopeSurfaceTelemetry = {
55857
+ onPrecomputedSurfaceHit: () => {
55858
+ perfCounters.increment("surface.scope.precomputedSurfaceHit");
55859
+ },
55860
+ onScopeSurfaceBuild: () => {
55861
+ perfCounters.increment("surface.scope.builds");
55862
+ }
55863
+ };
55254
55864
  let cachedHotEditPolicy = null;
55255
55865
  function getHotEditPolicy() {
55256
55866
  if (cachedHotEditPolicy?.document === state.document) {
@@ -55699,7 +56309,7 @@ function createDocumentRuntime(options) {
55699
56309
  viewportRangesKey: rangesKey,
55700
56310
  snapshot: surface
55701
56311
  };
55702
- const fullSurface = fullSurfaceForCache ?? (surface.viewportBlockRanges === null ? surface : void 0);
56312
+ const fullSurface = fullSurfaceForCache?.viewportBlockRanges === null ? fullSurfaceForCache : surface.viewportBlockRanges === null ? surface : void 0;
55703
56313
  if (fullSurface) {
55704
56314
  cachedFullSurface = {
55705
56315
  content: state.document.content,
@@ -57262,6 +57872,7 @@ function createDocumentRuntime(options) {
57262
57872
  documentMode: workflowCoordinator.getEffectiveDocumentMode(commandSelection),
57263
57873
  defaultAuthorId: defaultAuthorId ?? void 0,
57264
57874
  renderSnapshot: cachedRenderSnapshot,
57875
+ surfaceTelemetry: scopeSurfaceTelemetry,
57265
57876
  activeStoryKey: canonicalEditableTargetStoryKey(activeStory),
57266
57877
  editableTargetCache: editableTargetBlockCache,
57267
57878
  ...resolvedFragmentTextTarget ? { textTarget: resolvedFragmentTextTarget } : {}
@@ -57631,9 +58242,9 @@ function createDocumentRuntime(options) {
57631
58242
  emitError(toRuntimeError(error));
57632
58243
  }
57633
58244
  },
57634
- applyFormattingOperation(operation) {
58245
+ applyFormattingOperation(operation2) {
57635
58246
  try {
57636
- const commandName = getFormattingOperationCommandName(operation);
58247
+ const commandName = getFormattingOperationCommandName(operation2);
57637
58248
  const snapshot = cachedRenderSnapshot;
57638
58249
  if (!snapshot.isReady || snapshot.readOnly || snapshot.fatalError) {
57639
58250
  return;
@@ -57661,11 +58272,11 @@ function createDocumentRuntime(options) {
57661
58272
  };
57662
58273
  const suggesting = workflowCoordinator.getEffectiveDocumentMode(state.selection) === "suggesting";
57663
58274
  const timestamp = clock();
57664
- if (snapshot.selection.isCollapsed && operation.type !== "set-alignment" && operation.type !== "indent" && operation.type !== "outdent") {
58275
+ if (snapshot.selection.isCollapsed && operation2.type !== "set-alignment" && operation2.type !== "indent" && operation2.type !== "outdent") {
57665
58276
  const storyKey2 = storyTargetKey(activeStory);
57666
58277
  const nextMarks = updatePendingInsertionMarks(
57667
58278
  pendingInsertionMarksByStory.get(storyKey2)?.marks ?? marksFromFormattingState(getFormattingStateFromRenderSnapshot(snapshot)),
57668
- operation
58279
+ operation2
57669
58280
  );
57670
58281
  if (nextMarks && nextMarks.length > 0) {
57671
58282
  pendingInsertionMarksByStory.set(storyKey2, {
@@ -57680,7 +58291,7 @@ function createDocumentRuntime(options) {
57680
58291
  return;
57681
58292
  }
57682
58293
  if (suggesting) {
57683
- if (operation.type === "set-alignment" || operation.type === "indent" || operation.type === "outdent") {
58294
+ if (operation2.type === "set-alignment" || operation2.type === "indent" || operation2.type === "outdent") {
57684
58295
  const paragraphContext = resolveActiveParagraphContext(localSnapshot);
57685
58296
  if (!paragraphContext) {
57686
58297
  return;
@@ -57689,7 +58300,7 @@ function createDocumentRuntime(options) {
57689
58300
  const result3 = applyFormattingOperationToDocument(
57690
58301
  localDocument,
57691
58302
  localSnapshot,
57692
- operation
58303
+ operation2
57693
58304
  );
57694
58305
  if (!result3.changed) {
57695
58306
  return;
@@ -57736,7 +58347,7 @@ function createDocumentRuntime(options) {
57736
58347
  const result2 = applyFormattingOperationToDocument(
57737
58348
  localDocument,
57738
58349
  localSnapshot,
57739
- operation
58350
+ operation2
57740
58351
  );
57741
58352
  if (!result2.changed) {
57742
58353
  return;
@@ -57771,7 +58382,7 @@ function createDocumentRuntime(options) {
57771
58382
  const result = applyFormattingOperationToDocument(
57772
58383
  localDocument,
57773
58384
  localSnapshot,
57774
- operation
58385
+ operation2
57775
58386
  );
57776
58387
  if (!result.changed) {
57777
58388
  return;
@@ -58018,7 +58629,7 @@ function createDocumentRuntime(options) {
58018
58629
  if (step.kind !== "formatting-apply" || !step.range || !step.formattingAction) {
58019
58630
  continue;
58020
58631
  }
58021
- const operation = step.formattingAction.kind === "clear-mark" ? {
58632
+ const operation2 = step.formattingAction.kind === "clear-mark" ? {
58022
58633
  type: "clear-mark",
58023
58634
  mark: step.formattingAction.mark,
58024
58635
  ...step.formattingAction.expandToFullHighlight === true ? { expandToFullHighlight: true } : {}
@@ -58029,7 +58640,7 @@ function createDocumentRuntime(options) {
58029
58640
  const result = applyTextMarkOperationToDocumentRange(
58030
58641
  state.document,
58031
58642
  step.range,
58032
- operation
58643
+ operation2
58033
58644
  );
58034
58645
  if (!result.changed) {
58035
58646
  continue;
@@ -59534,7 +60145,8 @@ function createDocumentRuntime(options) {
59534
60145
  applyViewportRanges(getSelectionCorridorViewportRanges(cachedRenderSnapshot.surface));
59535
60146
  }
59536
60147
  const tValidation0 = performance.now();
59537
- const patchedFullLocalTextSurface = useLocalTextCommitSnapshot ? tryPatchLocalTextSurface(cachedRenderSnapshot.surface, transaction.mapping) : null;
60148
+ const patchSourceSurface = getReusableCachedFullSurface(previous.document, activeStory) ?? cachedRenderSnapshot.surface;
60149
+ const patchedFullLocalTextSurface = useLocalTextCommitSnapshot ? tryPatchLocalTextSurface(patchSourceSurface, transaction.mapping) : null;
59538
60150
  const patchedLocalTextSurface = patchedFullLocalTextSurface ? createLocalTextCorridorSurfaceFromFullSurface(patchedFullLocalTextSurface) : null;
59539
60151
  if (patchedLocalTextSurface) {
59540
60152
  cachePatchedLocalTextSurface(
@@ -59878,11 +60490,14 @@ function createDocumentRuntime(options) {
59878
60490
  }
59879
60491
  const listBoundaryDeleteUsesStoryText = targetResolution?.kind === "accepted" && editableTarget?.listAddress?.operationScope === "list-text" && isTopLevelMainStoryBlockPath(editableTarget.blockPath) && selection.isCollapsed && (commandForDispatch.type === "text.delete-backward" && selection.anchor === targetResolution.range.from || commandForDispatch.type === "text.delete-forward" && selection.anchor === targetResolution.range.to);
59880
60492
  const textTarget = targetResolution?.kind === "accepted" && !listBoundaryDeleteUsesStoryText ? targetResolution.textTarget : legacyTextTarget;
60493
+ const fullScopeSurface = cachedFullSurface?.snapshot;
59881
60494
  const context = {
59882
60495
  timestamp,
59883
60496
  documentMode: textOptions.documentModeOverride ?? workflowCoordinator.getEffectiveDocumentMode(selection),
59884
60497
  defaultAuthorId: defaultAuthorId ?? void 0,
59885
60498
  renderSnapshot: cachedRenderSnapshot,
60499
+ surfaceTelemetry: scopeSurfaceTelemetry,
60500
+ ...fullScopeSurface ? { precomputedSurface: fullScopeSurface } : {},
59886
60501
  activeStoryKey: canonicalEditableTargetStoryKey(activeStory),
59887
60502
  editableTargetCache: editableTargetBlockCache,
59888
60503
  activeStorySize: cachedRenderSnapshot.surface?.storySize,
@@ -60208,6 +60823,7 @@ function createDocumentRuntime(options) {
60208
60823
  documentMode: workflowCoordinator.getEffectiveDocumentMode(state.selection),
60209
60824
  defaultAuthorId: defaultAuthorId ?? void 0,
60210
60825
  renderSnapshot: cachedRenderSnapshot,
60826
+ surfaceTelemetry: scopeSurfaceTelemetry,
60211
60827
  activeStoryKey: canonicalEditableTargetStoryKey(activeStory),
60212
60828
  editableTargetCache: editableTargetBlockCache
60213
60829
  };
@@ -60612,22 +61228,22 @@ function marksFromFormattingState(formatting) {
60612
61228
  }
60613
61229
  return marks;
60614
61230
  }
60615
- function updatePendingInsertionMarks(currentMarks, operation) {
60616
- switch (operation.type) {
61231
+ function updatePendingInsertionMarks(currentMarks, operation2) {
61232
+ switch (operation2.type) {
60617
61233
  case "toggle":
60618
- return togglePendingMark(currentMarks, operation.mark);
61234
+ return togglePendingMark(currentMarks, operation2.mark);
60619
61235
  case "set-font-family":
60620
- return setPendingMarkValue(currentMarks, "fontFamily", operation.fontFamily?.trim() || null);
61236
+ return setPendingMarkValue(currentMarks, "fontFamily", operation2.fontFamily?.trim() || null);
60621
61237
  case "set-font-size":
60622
61238
  return setPendingMarkValue(
60623
61239
  currentMarks,
60624
61240
  "fontSize",
60625
- typeof operation.size === "number" && Number.isFinite(operation.size) ? Math.round(operation.size * 2) : null
61241
+ typeof operation2.size === "number" && Number.isFinite(operation2.size) ? Math.round(operation2.size * 2) : null
60626
61242
  );
60627
61243
  case "set-text-color":
60628
- return setPendingMarkValue(currentMarks, "textColor", normalizePendingColor(operation.color));
61244
+ return setPendingMarkValue(currentMarks, "textColor", normalizePendingColor(operation2.color));
60629
61245
  case "set-highlight-color":
60630
- return setPendingMarkValue(currentMarks, "backgroundColor", normalizePendingColor(operation.color));
61246
+ return setPendingMarkValue(currentMarks, "backgroundColor", normalizePendingColor(operation2.color));
60631
61247
  }
60632
61248
  }
60633
61249
  function togglePendingMark(marks, mark) {
@@ -62790,10 +63406,10 @@ function toInternalSelectionSnapshot2(selection) {
62790
63406
  )
62791
63407
  };
62792
63408
  }
62793
- function getFormattingOperationCommandName(operation) {
62794
- switch (operation.type) {
63409
+ function getFormattingOperationCommandName(operation2) {
63410
+ switch (operation2.type) {
62795
63411
  case "toggle":
62796
- return `toggle${operation.mark.charAt(0).toUpperCase()}${operation.mark.slice(1)}`;
63412
+ return `toggle${operation2.mark.charAt(0).toUpperCase()}${operation2.mark.slice(1)}`;
62797
63413
  case "set-font-family":
62798
63414
  return "setFontFamily";
62799
63415
  case "set-font-size":