@beyondwork/docx-react-component 1.0.124 → 1.0.126

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 (101) hide show
  1. package/dist/api/public-types.cjs +147 -35
  2. package/dist/api/public-types.d.cts +2 -2
  3. package/dist/api/public-types.d.ts +2 -2
  4. package/dist/api/public-types.js +3 -3
  5. package/dist/api/v3.cjs +796 -102
  6. package/dist/api/v3.d.cts +3 -3
  7. package/dist/api/v3.d.ts +3 -3
  8. package/dist/api/v3.js +10 -10
  9. package/dist/{canonical-document-CG2TgAzj.d.cts → canonical-document-CXCFCbAz.d.cts} +2 -0
  10. package/dist/{canonical-document-CG2TgAzj.d.ts → canonical-document-CXCFCbAz.d.ts} +2 -0
  11. package/dist/{chunk-PFYUJU3Q.js → chunk-2QL5DAKF.js} +98 -43
  12. package/dist/{chunk-4IPEZYQX.js → chunk-4EENH4FG.js} +1 -1
  13. package/dist/{chunk-BOHHIVQ2.js → chunk-4G3OS2H6.js} +3 -3
  14. package/dist/{chunk-A74Y5NE4.js → chunk-4YJVRIUB.js} +52 -21
  15. package/dist/{chunk-FNWKE74J.js → chunk-5DGKFNQT.js} +5 -1
  16. package/dist/{chunk-RSYN6FTS.js → chunk-6F5QW44A.js} +2 -2
  17. package/dist/{chunk-ZMRO6P3A.js → chunk-6IGWPAR4.js} +505 -44
  18. package/dist/{chunk-KOHQFZMM.js → chunk-BYSRJ4FE.js} +1 -1
  19. package/dist/{chunk-H6IL5ABU.js → chunk-CXSYRB37.js} +64 -20
  20. package/dist/{chunk-32ZAOQ54.js → chunk-D5HYZQTG.js} +1 -1
  21. package/dist/{chunk-TY4DIJO3.js → chunk-ESJ2MES5.js} +1 -1
  22. package/dist/{chunk-Q76XPPTA.js → chunk-FPRWV54X.js} +101 -14
  23. package/dist/{chunk-MPH4ZQS4.js → chunk-GL7XRYBY.js} +624 -87
  24. package/dist/{chunk-IR7QV2BX.js → chunk-KV435YXO.js} +2 -2
  25. package/dist/{chunk-N4VIXI2Z.js → chunk-MWSBGJQO.js} +137 -18
  26. package/dist/{chunk-7PC6XUNO.js → chunk-TQDQU2E3.js} +2 -2
  27. package/dist/{chunk-4B74ETJI.js → chunk-V6XVZFFH.js} +2 -2
  28. package/dist/{chunk-NAMAWCXN.js → chunk-YD2JE54B.js} +1 -1
  29. package/dist/{chunk-ZRHLLPSJ.js → chunk-YHZHPXDB.js} +85 -18
  30. package/dist/{chunk-HXHQA4BU.js → chunk-YIYM4ZAP.js} +1 -1
  31. package/dist/{chunk-LGWNN3L2.js → chunk-ZDOAUP3V.js} +2 -2
  32. package/dist/compare.d.cts +1 -1
  33. package/dist/compare.d.ts +1 -1
  34. package/dist/core/commands/formatting-commands.d.cts +2 -2
  35. package/dist/core/commands/formatting-commands.d.ts +2 -2
  36. package/dist/core/commands/image-commands.cjs +65 -20
  37. package/dist/core/commands/image-commands.d.cts +2 -2
  38. package/dist/core/commands/image-commands.d.ts +2 -2
  39. package/dist/core/commands/image-commands.js +5 -5
  40. package/dist/core/commands/section-layout-commands.d.cts +2 -2
  41. package/dist/core/commands/section-layout-commands.d.ts +2 -2
  42. package/dist/core/commands/style-commands.d.cts +2 -2
  43. package/dist/core/commands/style-commands.d.ts +2 -2
  44. package/dist/core/commands/table-structure-commands.cjs +65 -20
  45. package/dist/core/commands/table-structure-commands.d.cts +2 -2
  46. package/dist/core/commands/table-structure-commands.d.ts +2 -2
  47. package/dist/core/commands/table-structure-commands.js +4 -4
  48. package/dist/core/commands/text-commands.cjs +66 -21
  49. package/dist/core/commands/text-commands.d.cts +2 -2
  50. package/dist/core/commands/text-commands.d.ts +2 -2
  51. package/dist/core/commands/text-commands.js +5 -5
  52. package/dist/core/selection/mapping.d.cts +2 -2
  53. package/dist/core/selection/mapping.d.ts +2 -2
  54. package/dist/core/state/editor-state.d.cts +2 -2
  55. package/dist/core/state/editor-state.d.ts +2 -2
  56. package/dist/index.cjs +1677 -240
  57. package/dist/index.d.cts +5 -5
  58. package/dist/index.d.ts +5 -5
  59. package/dist/index.js +62 -25
  60. package/dist/io/docx-session.cjs +51 -20
  61. package/dist/io/docx-session.d.cts +4 -4
  62. package/dist/io/docx-session.d.ts +4 -4
  63. package/dist/io/docx-session.js +4 -4
  64. package/dist/legal.cjs +36 -12
  65. package/dist/legal.d.cts +1 -1
  66. package/dist/legal.d.ts +1 -1
  67. package/dist/legal.js +3 -3
  68. package/dist/{loader-D9y4ZRjj.d.ts → loader-CS9-9KFa.d.ts} +3 -3
  69. package/dist/{loader-D9KCtj4m.d.cts → loader-OoWJ1_17.d.cts} +3 -3
  70. package/dist/{public-types-CNnMHZM9.d.ts → public-types-BP3vqJR5.d.cts} +157 -11
  71. package/dist/{public-types-DajNGKV4.d.cts → public-types-DdcHqcow.d.ts} +157 -11
  72. package/dist/public-types.cjs +147 -35
  73. package/dist/public-types.d.cts +2 -2
  74. package/dist/public-types.d.ts +2 -2
  75. package/dist/public-types.js +3 -3
  76. package/dist/runtime/collab.d.cts +3 -3
  77. package/dist/runtime/collab.d.ts +3 -3
  78. package/dist/runtime/document-runtime.cjs +945 -134
  79. package/dist/runtime/document-runtime.d.cts +2 -2
  80. package/dist/runtime/document-runtime.d.ts +2 -2
  81. package/dist/runtime/document-runtime.js +14 -14
  82. package/dist/{session-DyQGlryH.d.cts → session-Cq-fzx3B.d.cts} +3 -3
  83. package/dist/{session-DEmaOEjA.d.ts → session-DyFQt8Ph.d.ts} +3 -3
  84. package/dist/session.cjs +51 -20
  85. package/dist/session.d.cts +5 -5
  86. package/dist/session.d.ts +5 -5
  87. package/dist/session.js +5 -5
  88. package/dist/tailwind.cjs +238 -73
  89. package/dist/tailwind.d.cts +2 -2
  90. package/dist/tailwind.d.ts +2 -2
  91. package/dist/tailwind.js +7 -7
  92. package/dist/{types-CxE1aZiv.d.cts → types-Bg7D-GD3.d.cts} +2 -2
  93. package/dist/{types-DjJNaE9c.d.ts → types-bJAgMq1M.d.ts} +2 -2
  94. package/dist/ui-tailwind/editor-surface/search-plugin.d.cts +3 -3
  95. package/dist/ui-tailwind/editor-surface/search-plugin.d.ts +3 -3
  96. package/dist/ui-tailwind/editor-surface/search-plugin.js +4 -4
  97. package/dist/ui-tailwind.cjs +238 -73
  98. package/dist/ui-tailwind.d.cts +3 -3
  99. package/dist/ui-tailwind.d.ts +3 -3
  100. package/dist/ui-tailwind.js +7 -7
  101. package/package.json +1 -1
package/dist/index.cjs CHANGED
@@ -6965,7 +6965,7 @@ function createParagraphEditableTarget(paragraph, kind, storyKey2, blockPath, ta
6965
6965
  context: { storyKey: storyKey2, insideSdt: contentControl !== void 0 },
6966
6966
  ...tableTarget
6967
6967
  }) : void 0;
6968
- const listAddress = tableIdentity === void 0 && paragraph.numbering !== void 0 ? createCanonicalAddress({
6968
+ const listAddress = paragraph.numbering !== void 0 ? createCanonicalAddress({
6969
6969
  addressKind: "list-item-text",
6970
6970
  storyKey: storyKey2,
6971
6971
  staleCheckKind: "paragraph",
@@ -6999,6 +6999,7 @@ function createParagraphEditableTarget(paragraph, kind, storyKey2, blockPath, ta
6999
6999
  ...contentControl !== void 0 ? { contentControl } : {},
7000
7000
  ...tableIdentity !== void 0 ? { table: tableIdentity } : {},
7001
7001
  ...editableOwner !== void 0 ? { editableOwner } : {},
7002
+ ...listAddress !== void 0 ? { listAddress } : {},
7002
7003
  ...tableIdentity !== void 0 ? {
7003
7004
  canonicalAddress: createTableTargetCanonicalAddress(
7004
7005
  tableIdentity,
@@ -7862,6 +7863,9 @@ function validateEditableTargetRef(value, path = "$") {
7862
7863
  if (record.canonicalAddress !== void 0) {
7863
7864
  validateTargetCanonicalAddress(record.canonicalAddress, `${path}.canonicalAddress`, issues);
7864
7865
  }
7866
+ if (record.listAddress !== void 0) {
7867
+ validateTargetCanonicalAddress(record.listAddress, `${path}.listAddress`, issues);
7868
+ }
7865
7869
  const staleCheck = asPlainObject(record.staleCheck, `${path}.staleCheck`, issues);
7866
7870
  if (staleCheck) {
7867
7871
  if (staleCheck.paragraphTextHash !== void 0) {
@@ -9850,6 +9854,7 @@ function mergeLevelDefinition(base, override, startOverride, fallbackLevel) {
9850
9854
  );
9851
9855
  const runProperties = override?.runProperties ?? base?.runProperties;
9852
9856
  const restartAfterLevel = override?.restartAfterLevel ?? base?.restartAfterLevel;
9857
+ const picBulletId = override?.picBulletId ?? base?.picBulletId;
9853
9858
  return {
9854
9859
  level,
9855
9860
  format,
@@ -9860,7 +9865,8 @@ function mergeLevelDefinition(base, override, startOverride, fallbackLevel) {
9860
9865
  ...override?.suffix ?? base?.suffix ? { suffix: override?.suffix ?? base?.suffix } : {},
9861
9866
  ...paragraphGeometry ? { paragraphGeometry } : {},
9862
9867
  ...runProperties ? { runProperties } : {},
9863
- ...restartAfterLevel !== void 0 ? { restartAfterLevel } : {}
9868
+ ...restartAfterLevel !== void 0 ? { restartAfterLevel } : {},
9869
+ ...picBulletId !== void 0 ? { picBulletId } : {}
9864
9870
  };
9865
9871
  }
9866
9872
  function withDefaultStartAt(level) {
@@ -9988,7 +9994,7 @@ function resolveHangingWidth(indentation) {
9988
9994
  // src/runtime/formatting/numbering/prefix.ts
9989
9995
  function createNumberingPrefixResolver(catalog) {
9990
9996
  const sequenceStates = /* @__PURE__ */ new Map();
9991
- function resolveInternal(numbering, paragraph) {
9997
+ function resolveInternal(numbering, paragraph, options = {}) {
9992
9998
  const resolved = resolveNumberingDefinitionSet(
9993
9999
  catalog,
9994
10000
  paragraph?.numbering ?? numbering,
@@ -10001,29 +10007,44 @@ function createNumberingPrefixResolver(catalog) {
10001
10007
  if (!resolvedNumbering) {
10002
10008
  return null;
10003
10009
  }
10004
- const sequenceState = getSequenceState(sequenceStates, resolvedNumbering.numberingInstanceId);
10005
- advanceSequence(sequenceState, resolved.effectiveLevel.level, resolved.effectiveLevels);
10010
+ const advance = options.advance !== false;
10011
+ const sequenceState = getSequenceState(
10012
+ sequenceStates,
10013
+ resolvedNumbering.numberingInstanceId,
10014
+ { create: advance }
10015
+ );
10016
+ if (!sequenceState) {
10017
+ return null;
10018
+ }
10019
+ const workingState = advance ? sequenceState : cloneSequenceState(sequenceState);
10020
+ advanceSequence(workingState, resolved.effectiveLevel.level, resolved.effectiveLevels);
10021
+ const currentCounter = workingState.counters[resolved.effectiveLevel.level];
10006
10022
  const effectiveLevelDefs = resolved.effectiveLevel.isLegalNumbering ? new Map(
10007
10023
  Array.from(resolved.effectiveLevels.entries()).map(([level, definition]) => [
10008
10024
  level,
10009
10025
  { ...definition, format: "decimal" }
10010
10026
  ])
10011
10027
  ) : resolved.effectiveLevels;
10028
+ const picBulletId = resolved.effectiveLevel.picBulletId;
10012
10029
  const text = renderLevelText(
10013
10030
  resolved.effectiveLevel.text,
10014
- sequenceState.counters,
10031
+ workingState.counters,
10015
10032
  effectiveLevelDefs
10016
10033
  );
10017
- if (resolved.effectiveLevel.format !== "none" && text === null) {
10034
+ if (picBulletId == null && resolved.effectiveLevel.format !== "none" && text === null) {
10018
10035
  return null;
10019
10036
  }
10020
10037
  const visibleText = resolved.effectiveLevel.format === "none" ? null : text;
10021
- const picBulletId = resolved.effectiveLevel.picBulletId;
10038
+ const formatPosture = getNumberingFormatPosture(
10039
+ resolved.effectiveLevel.format,
10040
+ currentCounter
10041
+ );
10022
10042
  const picBulletMediaId = picBulletId != null ? catalog.numPicBullets?.[picBulletId]?.mediaId : void 0;
10023
10043
  return {
10024
10044
  text: visibleText,
10025
10045
  level: resolved.effectiveLevel.level,
10026
10046
  format: resolved.effectiveLevel.format,
10047
+ ...formatPosture !== void 0 ? { formatPosture } : {},
10027
10048
  startAt: resolved.effectiveLevel.startAt ?? DEFAULT_NUMBERING_START_AT,
10028
10049
  ...resolved.effectiveLevel.suffix ? { suffix: resolved.effectiveLevel.suffix } : {},
10029
10050
  ...resolved.effectiveLevel.paragraphStyleId ? { paragraphStyleId: resolved.effectiveLevel.paragraphStyleId } : {},
@@ -10034,23 +10055,26 @@ function createNumberingPrefixResolver(catalog) {
10034
10055
  };
10035
10056
  }
10036
10057
  return {
10037
- resolve(numbering) {
10038
- const result = resolveInternal(numbering);
10058
+ resolve(numbering, options) {
10059
+ const result = resolveInternal(numbering, void 0, options);
10039
10060
  return result?.text ?? null;
10040
10061
  },
10041
- resolveDetailed(numbering, paragraph) {
10042
- return resolveInternal(numbering, paragraph);
10062
+ resolveDetailed(numbering, paragraph, options) {
10063
+ return resolveInternal(numbering, paragraph, options);
10043
10064
  },
10044
- resolveParagraph(paragraph) {
10045
- return resolveInternal(paragraph.numbering, paragraph);
10065
+ resolveParagraph(paragraph, options) {
10066
+ return resolveInternal(paragraph.numbering, paragraph, options);
10046
10067
  }
10047
10068
  };
10048
10069
  }
10049
- function getSequenceState(states, numberingInstanceId) {
10070
+ function getSequenceState(states, numberingInstanceId, options = { create: true }) {
10050
10071
  const existing = states.get(numberingInstanceId);
10051
10072
  if (existing) {
10052
10073
  return existing;
10053
10074
  }
10075
+ if (options.create === false) {
10076
+ return { counters: [], lastLevel: null };
10077
+ }
10054
10078
  const created = {
10055
10079
  counters: [],
10056
10080
  lastLevel: null
@@ -10058,6 +10082,12 @@ function getSequenceState(states, numberingInstanceId) {
10058
10082
  states.set(numberingInstanceId, created);
10059
10083
  return created;
10060
10084
  }
10085
+ function cloneSequenceState(state) {
10086
+ return {
10087
+ counters: [...state.counters],
10088
+ lastLevel: state.lastLevel
10089
+ };
10090
+ }
10061
10091
  function advanceSequence(state, currentLevel, levelDefinitions) {
10062
10092
  for (let level = currentLevel + 1; level < state.counters.length; level += 1) {
10063
10093
  if (shouldResetDeeperLevel(level, currentLevel, levelDefinitions)) {
@@ -10089,6 +10119,25 @@ function shouldResetDeeperLevel(level, triggeringLevel, levelDefinitions) {
10089
10119
  function getLevelStartAt(level, levelDefinitions) {
10090
10120
  return levelDefinitions.get(level)?.startAt ?? DEFAULT_NUMBERING_START_AT;
10091
10121
  }
10122
+ function getNumberingFormatPosture(format, value) {
10123
+ if (!isSupportedNumberingFormat(format)) {
10124
+ return {
10125
+ status: "approximated",
10126
+ requestedFormat: format,
10127
+ renderedFormat: "decimal",
10128
+ reason: "unsupported-numbering-format-decimal-fallback"
10129
+ };
10130
+ }
10131
+ if (value !== void 0 && ((format === "upperRoman" || format === "lowerRoman") && (value <= 0 || value >= 4e3) || (format === "cardinalText" || format === "ordinalText") && (!Number.isInteger(value) || value < 1 || value > 999) || (format === "upperLetter" || format === "lowerLetter" || format === "chicago") && value < 1)) {
10132
+ return {
10133
+ status: "approximated",
10134
+ requestedFormat: format,
10135
+ renderedFormat: "decimal",
10136
+ reason: "numbering-format-range-decimal-fallback"
10137
+ };
10138
+ }
10139
+ return void 0;
10140
+ }
10092
10141
  function renderLevelText(text, counters, levelDefinitions) {
10093
10142
  if (!text) {
10094
10143
  return null;
@@ -10931,6 +10980,7 @@ function toNumberingLayoutInput(numbering) {
10931
10980
  associatedTabStops: toLayoutTabStops(numbering.geometry.tabStops, "numbering"),
10932
10981
  level: numbering.level,
10933
10982
  format: numbering.format,
10983
+ ...numbering.formatPosture !== void 0 ? { formatPosture: { ...numbering.formatPosture } } : {},
10934
10984
  startAt: numbering.startAt,
10935
10985
  ...numbering.isLegalNumbering ? { isLegalNumbering: true } : {},
10936
10986
  ...numbering.picBulletMediaId ? { pictureBulletMediaId: numbering.picBulletMediaId } : {}
@@ -11160,13 +11210,10 @@ var FormattingContextImpl = class {
11160
11210
  const effectiveNumbering = this.resolveEffectiveParagraphNumbering(para);
11161
11211
  if (!effectiveNumbering) return null;
11162
11212
  if (!emitGeometry) {
11163
- if (advance) this.numbering.resolve(effectiveNumbering);
11213
+ this.numbering.resolve(effectiveNumbering, { advance });
11164
11214
  return null;
11165
11215
  }
11166
- if (!advance) {
11167
- console.warn("[formatting-context] resolveParagraphNumbering({advance:false}) is not supported; counter always advances");
11168
- }
11169
- return this.numbering.resolveDetailed(effectiveNumbering, para);
11216
+ return this.numbering.resolveDetailed(effectiveNumbering, para, { advance });
11170
11217
  }
11171
11218
  resolveNumberingLayoutInput(para, options = {}) {
11172
11219
  return toNumberingLayoutInput(this.resolveParagraphNumbering(para, options));
@@ -13442,6 +13489,7 @@ function toSurfaceResolvedNumbering(numbering) {
13442
13489
  return {
13443
13490
  level: numbering.level,
13444
13491
  format: numbering.format,
13492
+ ...numbering.formatPosture !== void 0 ? { formatPosture: { ...numbering.formatPosture } } : {},
13445
13493
  ...numbering.text !== null ? { text: numbering.text } : {},
13446
13494
  startAt: numbering.startAt,
13447
13495
  ...numbering.paragraphStyleId ? { paragraphStyleId: numbering.paragraphStyleId } : {},
@@ -18161,8 +18209,9 @@ function projectSurfaceBlocksToPageFragments(surface, pages, splits, columnByBlo
18161
18209
  const perPageCounter = /* @__PURE__ */ new Map();
18162
18210
  const fieldRegionsByParagraphIndex = buildFieldRegionsByParagraphIndex(fieldRegions);
18163
18211
  const generatedTargets = buildGeneratedTargets(editableTargets);
18212
+ const numberingTargets = buildNumberingTargets(editableTargets);
18164
18213
  const bookmarkRanges = buildBookmarkRanges(editableTargets);
18165
- const numberingByParagraphIndex = buildNumberingByParagraphIndex(numberingInputs);
18214
+ const numberingIndex = buildNumberingInputIndex(numberingInputs);
18166
18215
  const pushFragment = (pageIndex, fragment) => {
18167
18216
  const existing = byPage.get(pageIndex);
18168
18217
  if (existing) {
@@ -18198,8 +18247,9 @@ function projectSurfaceBlocksToPageFragments(surface, pages, splits, columnByBlo
18198
18247
  },
18199
18248
  fieldRegionsByParagraphIndex,
18200
18249
  generatedTargets,
18250
+ numberingTargets,
18201
18251
  bookmarkRanges,
18202
- numberingByParagraphIndex,
18252
+ numberingIndex,
18203
18253
  blockPath
18204
18254
  );
18205
18255
  continue;
@@ -18220,8 +18270,9 @@ function projectSurfaceBlocksToPageFragments(surface, pages, splits, columnByBlo
18220
18270
  },
18221
18271
  fieldRegionsByParagraphIndex,
18222
18272
  generatedTargets,
18273
+ numberingTargets,
18223
18274
  bookmarkRanges,
18224
- numberingByParagraphIndex,
18275
+ numberingIndex,
18225
18276
  blockPath
18226
18277
  );
18227
18278
  continue;
@@ -18253,8 +18304,9 @@ function projectSurfaceBlocksToPageFragments(surface, pages, splits, columnByBlo
18253
18304
  paginationRole: "whole",
18254
18305
  fieldRegionsByParagraphIndex,
18255
18306
  generatedTargets,
18307
+ numberingTargets,
18256
18308
  bookmarkRanges,
18257
- numberingByParagraphIndex,
18309
+ numberingIndex,
18258
18310
  blockPath
18259
18311
  }),
18260
18312
  ...columnIndex !== void 0 ? { columnIndex } : {}
@@ -18401,7 +18453,7 @@ function buildRunAnchorsForLine(input) {
18401
18453
  }
18402
18454
  return anchors;
18403
18455
  }
18404
- function emitSlicedParagraph(block, slices, emit2, fieldRegionsByParagraphIndex = /* @__PURE__ */ new Map(), generatedTargets = [], bookmarkRanges = [], numberingByParagraphIndex = /* @__PURE__ */ new Map(), blockPath) {
18456
+ function emitSlicedParagraph(block, slices, emit2, fieldRegionsByParagraphIndex = /* @__PURE__ */ new Map(), generatedTargets = [], numberingTargets = [], bookmarkRanges = [], numberingIndex = EMPTY_NUMBERING_INPUT_INDEX, blockPath) {
18405
18457
  for (let i = 0; i < slices.length; i += 1) {
18406
18458
  const slice = slices[i];
18407
18459
  const heightTwips = slice.heightTwips ?? estimateSliceHeightFromLines(slice.lineRange);
@@ -18426,8 +18478,9 @@ function emitSlicedParagraph(block, slices, emit2, fieldRegionsByParagraphIndex
18426
18478
  paginationRole: slice.lineRange.from > 0 ? "continuation" : "slice",
18427
18479
  fieldRegionsByParagraphIndex,
18428
18480
  generatedTargets,
18481
+ numberingTargets,
18429
18482
  bookmarkRanges,
18430
- numberingByParagraphIndex,
18483
+ numberingIndex,
18431
18484
  blockPath
18432
18485
  })
18433
18486
  };
@@ -18448,7 +18501,7 @@ function estimateSliceHeightFromLines(lineRange) {
18448
18501
  const lines = Math.max(0, lineRange.to - lineRange.from);
18449
18502
  return lines * 240;
18450
18503
  }
18451
- function emitSlicedTable(block, slices, emit2, fieldRegionsByParagraphIndex = /* @__PURE__ */ new Map(), generatedTargets = [], bookmarkRanges = [], numberingByParagraphIndex = /* @__PURE__ */ new Map(), blockPath) {
18504
+ function emitSlicedTable(block, slices, emit2, fieldRegionsByParagraphIndex = /* @__PURE__ */ new Map(), generatedTargets = [], numberingTargets = [], bookmarkRanges = [], numberingIndex = EMPTY_NUMBERING_INPUT_INDEX, blockPath) {
18452
18505
  for (let i = 0; i < slices.length; i += 1) {
18453
18506
  const slice = slices[i];
18454
18507
  const heightTwips = slice.heightTwips ?? estimateSliceHeightFromRows(slice.rowRange);
@@ -18472,8 +18525,9 @@ function emitSlicedTable(block, slices, emit2, fieldRegionsByParagraphIndex = /*
18472
18525
  paginationRole: slice.rowRange.from > 0 ? "continuation" : "slice",
18473
18526
  fieldRegionsByParagraphIndex,
18474
18527
  generatedTargets,
18528
+ numberingTargets,
18475
18529
  bookmarkRanges,
18476
- numberingByParagraphIndex,
18530
+ numberingIndex,
18477
18531
  blockPath
18478
18532
  }),
18479
18533
  ...slice.columnIndex !== void 0 ? { columnIndex: slice.columnIndex } : {}
@@ -18547,7 +18601,8 @@ function buildFragmentLayoutObject(input) {
18547
18601
  const numberingRows = collectNumberingLayoutFactsForBlock(
18548
18602
  input.block,
18549
18603
  input.blockPath,
18550
- input.numberingByParagraphIndex
18604
+ input.numberingIndex,
18605
+ input.numberingTargets
18551
18606
  );
18552
18607
  const numbering = input.block.kind === "paragraph" ? numberingRows[0] : void 0;
18553
18608
  const fieldRegions = collectFieldRegionLayoutFacts(
@@ -18718,6 +18773,11 @@ function buildGeneratedTargets(targets) {
18718
18773
  (target) => target.kind === "field-result-text" || target.kind === "hyperlink-text" || target.kind === "hyperlink-destination" || target.kind === "bookmark-anchor" || target.kind === "bookmark-content-range"
18719
18774
  );
18720
18775
  }
18776
+ function buildNumberingTargets(targets) {
18777
+ return targets.filter(
18778
+ (target) => target.listAddress !== void 0 || target.canonicalAddress?.addressKind === "list-item-text"
18779
+ );
18780
+ }
18721
18781
  function buildBookmarkRanges(targets) {
18722
18782
  const anchors = /* @__PURE__ */ new Map();
18723
18783
  const contentRanges = /* @__PURE__ */ new Map();
@@ -18765,14 +18825,27 @@ function buildBookmarkRanges(targets) {
18765
18825
  }
18766
18826
  return ranges;
18767
18827
  }
18768
- function buildNumberingByParagraphIndex(numberingInputs) {
18828
+ var EMPTY_NUMBERING_INPUT_INDEX = {
18829
+ byNumberingKey: /* @__PURE__ */ new Map(),
18830
+ byBlockPath: /* @__PURE__ */ new Map(),
18831
+ byParagraphIndex: /* @__PURE__ */ new Map()
18832
+ };
18833
+ function buildNumberingInputIndex(numberingInputs) {
18834
+ const byNumberingKey = /* @__PURE__ */ new Map();
18835
+ const byBlockPath = /* @__PURE__ */ new Map();
18769
18836
  const byParagraph = /* @__PURE__ */ new Map();
18770
18837
  for (const input of numberingInputs) {
18838
+ if (!byNumberingKey.has(input.numberingKey)) {
18839
+ byNumberingKey.set(input.numberingKey, input);
18840
+ }
18841
+ if (!byBlockPath.has(input.blockPath)) {
18842
+ byBlockPath.set(input.blockPath, input);
18843
+ }
18771
18844
  if (!byParagraph.has(input.paragraphIndex)) {
18772
18845
  byParagraph.set(input.paragraphIndex, input);
18773
18846
  }
18774
18847
  }
18775
- return byParagraph;
18848
+ return { byNumberingKey, byBlockPath, byParagraphIndex: byParagraph };
18776
18849
  }
18777
18850
  function collectBookmarkRangeLayoutFacts(fragmentId, blockPath, bookmarkRanges) {
18778
18851
  if (!blockPath || !bookmarkRanges || bookmarkRanges.length === 0) return [];
@@ -18853,6 +18926,7 @@ function collectNumberingLayoutFacts(block) {
18853
18926
  ...block.numbering?.numberingInstanceId !== void 0 ? { numberingInstanceId: block.numbering.numberingInstanceId } : {},
18854
18927
  ...block.numbering?.level !== void 0 ? { level: block.numbering.level } : {},
18855
18928
  ...block.resolvedNumbering?.format !== void 0 ? { format: block.resolvedNumbering.format } : {},
18929
+ ...block.resolvedNumbering?.formatPosture !== void 0 ? { formatPosture: { ...block.resolvedNumbering.formatPosture } } : {},
18856
18930
  ...block.numberingPrefix !== void 0 ? { markerText: block.numberingPrefix } : {},
18857
18931
  ...block.numberingSuffix !== void 0 ? { markerSuffix: block.numberingSuffix } : {},
18858
18932
  ...block.resolvedNumbering?.geometry.markerJustification !== void 0 ? { markerJustification: block.resolvedNumbering.geometry.markerJustification } : {},
@@ -18880,15 +18954,21 @@ function collectNumberingLayoutFacts(block) {
18880
18954
  } : {}
18881
18955
  };
18882
18956
  }
18883
- function collectNumberingLayoutFactsForBlock(block, blockPath, numberingByParagraphIndex) {
18957
+ function collectNumberingLayoutFactsForBlock(block, blockPath, numberingIndex, numberingTargets = []) {
18884
18958
  const rows = [];
18885
18959
  const seen = /* @__PURE__ */ new Set();
18886
18960
  visitParagraphBlocks(block, (paragraph, context) => {
18887
18961
  const numbering = collectNumberingLayoutFacts(paragraph);
18888
18962
  if (!numbering) return;
18889
18963
  const paragraphIndex = parseParagraphBlockIndex(paragraph.blockId);
18890
- const canonical = paragraphIndex !== void 0 ? numberingByParagraphIndex?.get(paragraphIndex) : void 0;
18891
18964
  const numberingKey = context.path !== void 0 ? `main:${context.path}:numbering` : void 0;
18965
+ const canonical = lookupNumberingInput(
18966
+ numberingIndex,
18967
+ numberingKey,
18968
+ context.path,
18969
+ paragraphIndex
18970
+ );
18971
+ const target = findNumberingTarget(numberingTargets, context.path);
18892
18972
  const numberingLayoutId = numberingKey ?? [
18893
18973
  "numbering",
18894
18974
  paragraph.blockId,
@@ -18897,6 +18977,7 @@ function collectNumberingLayoutFactsForBlock(block, blockPath, numberingByParagr
18897
18977
  ].join(":");
18898
18978
  if (seen.has(numberingLayoutId)) return;
18899
18979
  seen.add(numberingLayoutId);
18980
+ const unavailableReasons = collectNumberingUnavailableReasons(numbering, canonical);
18900
18981
  rows.push({
18901
18982
  numberingLayoutId,
18902
18983
  ...numberingKey !== void 0 ? { numberingKey } : {},
@@ -18904,6 +18985,10 @@ function collectNumberingLayoutFactsForBlock(block, blockPath, numberingByParagr
18904
18985
  ...canonical?.blockPath !== void 0 ? { sourceBlockPath: canonical.blockPath } : context.path !== void 0 ? { sourceBlockPath: context.path } : {},
18905
18986
  sourceBlockId: paragraph.blockId,
18906
18987
  ...paragraphIndex !== void 0 ? { paragraphIndex } : {},
18988
+ ...target?.targetKey !== void 0 ? { targetKey: target.targetKey } : {},
18989
+ ...target?.kind !== void 0 ? { targetKind: target.kind } : {},
18990
+ ...target?.canonicalAddress?.addressKey !== void 0 ? { canonicalAddressKey: target.canonicalAddress.addressKey } : {},
18991
+ ...target?.listAddress?.addressKey !== void 0 ? { listAddressKey: target.listAddress.addressKey } : {},
18907
18992
  ...canonical?.sourceRef !== void 0 ? { sourceRef: { ...canonical.sourceRef } } : {},
18908
18993
  ...canonical?.numberingSourceRef !== void 0 ? { numberingSourceRef: { ...canonical.numberingSourceRef } } : {},
18909
18994
  ...canonical?.numberingOrigin !== void 0 ? { numberingOrigin: canonical.numberingOrigin } : {},
@@ -18911,11 +18996,41 @@ function collectNumberingLayoutFactsForBlock(block, blockPath, numberingByParagr
18911
18996
  ...canonical?.numberingInstanceSourceRef !== void 0 ? { numberingInstanceSourceRef: { ...canonical.numberingInstanceSourceRef } } : {},
18912
18997
  ...canonical?.abstractNumberingId !== void 0 ? { abstractNumberingId: canonical.abstractNumberingId } : {},
18913
18998
  ...canonical?.abstractNumberingSourceRef !== void 0 ? { abstractNumberingSourceRef: { ...canonical.abstractNumberingSourceRef } } : {},
18914
- ...numbering
18999
+ ...numbering,
19000
+ ...unavailableReasons.length > 0 ? { unavailableReasons } : {}
18915
19001
  });
18916
19002
  }, blockPath);
18917
19003
  return rows;
18918
19004
  }
19005
+ function findNumberingTarget(numberingTargets, blockPath) {
19006
+ if (blockPath === void 0) return void 0;
19007
+ return numberingTargets.find((target) => target.blockPath === blockPath);
19008
+ }
19009
+ function lookupNumberingInput(numberingIndex, numberingKey, blockPath, paragraphIndex) {
19010
+ if (!numberingIndex) return void 0;
19011
+ if (numberingKey !== void 0) {
19012
+ const byKey = numberingIndex.byNumberingKey.get(numberingKey);
19013
+ if (byKey !== void 0) return byKey;
19014
+ }
19015
+ if (blockPath !== void 0) {
19016
+ const byPath = numberingIndex.byBlockPath.get(blockPath);
19017
+ if (byPath !== void 0) return byPath;
19018
+ }
19019
+ return paragraphIndex !== void 0 ? numberingIndex.byParagraphIndex.get(paragraphIndex) : void 0;
19020
+ }
19021
+ function collectNumberingUnavailableReasons(numbering, canonical) {
19022
+ const reasons = [];
19023
+ if (canonical === void 0) {
19024
+ reasons.push("canonical-numbering-input-missing");
19025
+ }
19026
+ if (numbering.markerLane === void 0) {
19027
+ reasons.push("numbering-marker-lane-unavailable");
19028
+ }
19029
+ if (numbering.textColumn === void 0) {
19030
+ reasons.push("numbering-text-column-unavailable");
19031
+ }
19032
+ return reasons;
19033
+ }
18919
19034
  function findPageIndexForOffset(pages, offset) {
18920
19035
  for (let i = 0; i < pages.length; i += 1) {
18921
19036
  const page = pages[i];
@@ -19320,8 +19435,8 @@ async function createCanvasProvider(fontLoader) {
19320
19435
  }
19321
19436
 
19322
19437
  // src/runtime/layout/layout-engine-version.ts
19323
- var LAYOUT_ENGINE_VERSION = 87;
19324
- var LAYCACHE_SCHEMA_VERSION = 11;
19438
+ var LAYOUT_ENGINE_VERSION = 88;
19439
+ var LAYCACHE_SCHEMA_VERSION = 12;
19325
19440
 
19326
19441
  // src/runtime/layout/layout-engine-instance.ts
19327
19442
  var FULL_VIEWPORT_WINDOW_KEY = "full";
@@ -21886,19 +22001,19 @@ function clamp(value, min, max) {
21886
22001
  }
21887
22002
 
21888
22003
  // src/core/commands/list-commands.ts
21889
- function toggleNumberedList(document2, paragraphIndexes, context) {
21890
- return toggleListKind(document2, paragraphIndexes, "numbered", context);
22004
+ function toggleNumberedList(document2, paragraphIndexes, context, options = {}) {
22005
+ return toggleListKind(document2, paragraphIndexes, "numbered", context, options);
21891
22006
  }
21892
- function toggleBulletedList(document2, paragraphIndexes, context) {
21893
- return toggleListKind(document2, paragraphIndexes, "bulleted", context);
22007
+ function toggleBulletedList(document2, paragraphIndexes, context, options = {}) {
22008
+ return toggleListKind(document2, paragraphIndexes, "bulleted", context, options);
21894
22009
  }
21895
- function indentListItems(document2, paragraphIndexes, context) {
21896
- return adjustListLevels(document2, paragraphIndexes, 1, context);
22010
+ function indentListItems(document2, paragraphIndexes, context, options = {}) {
22011
+ return adjustListLevels(document2, paragraphIndexes, 1, context, options);
21897
22012
  }
21898
- function outdentListItems(document2, paragraphIndexes, context) {
21899
- return adjustListLevels(document2, paragraphIndexes, -1, context);
22013
+ function outdentListItems(document2, paragraphIndexes, context, options = {}) {
22014
+ return adjustListLevels(document2, paragraphIndexes, -1, context, options);
21900
22015
  }
21901
- function splitListParagraph(document2, paragraphIndex, paragraphIsEmpty, context) {
22016
+ function splitListParagraph(document2, paragraphIndex, paragraphIsEmpty, context, options = {}) {
21902
22017
  if (!paragraphIsEmpty) {
21903
22018
  return {
21904
22019
  document: document2,
@@ -21908,7 +22023,30 @@ function splitListParagraph(document2, paragraphIndex, paragraphIsEmpty, context
21908
22023
  }
21909
22024
  const working = cloneEnvelope(document2, context.timestamp);
21910
22025
  const paragraphs = captureEditableParagraphs(working);
21911
- const target = paragraphs[paragraphIndex];
22026
+ const resolved = resolveListCommandParagraphIndexes(
22027
+ working,
22028
+ paragraphs,
22029
+ [paragraphIndex],
22030
+ context,
22031
+ normalizeListCommandTargets(options)
22032
+ );
22033
+ if (resolved.blockedReason) {
22034
+ return {
22035
+ document: working,
22036
+ affectedParagraphIndexes: [],
22037
+ action: "blocked",
22038
+ blockedReason: resolved.blockedReason
22039
+ };
22040
+ }
22041
+ const resolvedParagraphIndex = resolved.paragraphIndexes[0];
22042
+ if (resolvedParagraphIndex === void 0) {
22043
+ return {
22044
+ document: working,
22045
+ affectedParagraphIndexes: [],
22046
+ action: "split"
22047
+ };
22048
+ }
22049
+ const target = paragraphs[resolvedParagraphIndex];
21912
22050
  if (!target?.numbering) {
21913
22051
  return {
21914
22052
  document: working,
@@ -21923,21 +22061,44 @@ function splitListParagraph(document2, paragraphIndex, paragraphIsEmpty, context
21923
22061
  };
21924
22062
  return {
21925
22063
  document: working,
21926
- affectedParagraphIndexes: [paragraphIndex],
22064
+ affectedParagraphIndexes: [resolvedParagraphIndex],
21927
22065
  action: "outdented"
21928
22066
  };
21929
22067
  }
21930
22068
  delete target.numbering;
21931
22069
  return {
21932
22070
  document: working,
21933
- affectedParagraphIndexes: [paragraphIndex],
22071
+ affectedParagraphIndexes: [resolvedParagraphIndex],
21934
22072
  action: "removed"
21935
22073
  };
21936
22074
  }
21937
- function backspaceAtListStart(document2, paragraphIndex, context) {
22075
+ function backspaceAtListStart(document2, paragraphIndex, context, options = {}) {
21938
22076
  const working = cloneEnvelope(document2, context.timestamp);
21939
22077
  const paragraphs = captureEditableParagraphs(working);
21940
- const target = paragraphs[paragraphIndex];
22078
+ const resolved = resolveListCommandParagraphIndexes(
22079
+ working,
22080
+ paragraphs,
22081
+ [paragraphIndex],
22082
+ context,
22083
+ normalizeListCommandTargets(options)
22084
+ );
22085
+ if (resolved.blockedReason) {
22086
+ return {
22087
+ document: working,
22088
+ affectedParagraphIndexes: [],
22089
+ handled: true,
22090
+ blockedReason: resolved.blockedReason
22091
+ };
22092
+ }
22093
+ const resolvedParagraphIndex = resolved.paragraphIndexes[0];
22094
+ if (resolvedParagraphIndex === void 0) {
22095
+ return {
22096
+ document: working,
22097
+ affectedParagraphIndexes: [],
22098
+ handled: false
22099
+ };
22100
+ }
22101
+ const target = paragraphs[resolvedParagraphIndex];
21941
22102
  if (!target?.numbering) {
21942
22103
  return {
21943
22104
  document: working,
@@ -21955,14 +22116,35 @@ function backspaceAtListStart(document2, paragraphIndex, context) {
21955
22116
  }
21956
22117
  return {
21957
22118
  document: working,
21958
- affectedParagraphIndexes: [paragraphIndex],
22119
+ affectedParagraphIndexes: [resolvedParagraphIndex],
21959
22120
  handled: true
21960
22121
  };
21961
22122
  }
21962
- function restartNumbering(document2, paragraphIndex, context, startAt = 1) {
22123
+ function restartNumbering(document2, paragraphIndex, context, startAt = 1, options = {}) {
21963
22124
  const working = cloneEnvelope(document2, context.timestamp);
21964
22125
  const paragraphs = captureEditableParagraphs(working);
21965
- const target = paragraphs[paragraphIndex];
22126
+ const resolved = resolveListCommandParagraphIndexes(
22127
+ working,
22128
+ paragraphs,
22129
+ [paragraphIndex],
22130
+ context,
22131
+ normalizeListCommandTargets(options)
22132
+ );
22133
+ if (resolved.blockedReason) {
22134
+ return {
22135
+ document: working,
22136
+ affectedParagraphIndexes: [],
22137
+ blockedReason: resolved.blockedReason
22138
+ };
22139
+ }
22140
+ const resolvedParagraphIndex = resolved.paragraphIndexes[0];
22141
+ if (resolvedParagraphIndex === void 0) {
22142
+ return {
22143
+ document: working,
22144
+ affectedParagraphIndexes: []
22145
+ };
22146
+ }
22147
+ const target = paragraphs[resolvedParagraphIndex];
21966
22148
  if (!target?.numbering) {
21967
22149
  return {
21968
22150
  document: working,
@@ -21987,7 +22169,7 @@ function restartNumbering(document2, paragraphIndex, context, startAt = 1) {
21987
22169
  })
21988
22170
  };
21989
22171
  const affectedParagraphIndexes = [];
21990
- for (let index = paragraphIndex; index < paragraphs.length; index += 1) {
22172
+ for (let index = resolvedParagraphIndex; index < paragraphs.length; index += 1) {
21991
22173
  const paragraph = paragraphs[index];
21992
22174
  if (!paragraph?.numbering) {
21993
22175
  break;
@@ -22008,10 +22190,31 @@ function restartNumbering(document2, paragraphIndex, context, startAt = 1) {
22008
22190
  createdNumberingInstanceId: numberingInstanceId
22009
22191
  };
22010
22192
  }
22011
- function continueNumbering(document2, paragraphIndex, context) {
22193
+ function continueNumbering(document2, paragraphIndex, context, options = {}) {
22012
22194
  const working = cloneEnvelope(document2, context.timestamp);
22013
22195
  const paragraphs = captureEditableParagraphs(working);
22014
- const target = paragraphs[paragraphIndex];
22196
+ const resolved = resolveListCommandParagraphIndexes(
22197
+ working,
22198
+ paragraphs,
22199
+ [paragraphIndex],
22200
+ context,
22201
+ normalizeListCommandTargets(options)
22202
+ );
22203
+ if (resolved.blockedReason) {
22204
+ return {
22205
+ document: working,
22206
+ affectedParagraphIndexes: [],
22207
+ blockedReason: resolved.blockedReason
22208
+ };
22209
+ }
22210
+ const resolvedParagraphIndex = resolved.paragraphIndexes[0];
22211
+ if (resolvedParagraphIndex === void 0) {
22212
+ return {
22213
+ document: working,
22214
+ affectedParagraphIndexes: []
22215
+ };
22216
+ }
22217
+ const target = paragraphs[resolvedParagraphIndex];
22015
22218
  if (!target?.numbering) {
22016
22219
  return {
22017
22220
  document: working,
@@ -22030,7 +22233,7 @@ function continueNumbering(document2, paragraphIndex, context) {
22030
22233
  const compatibleInstanceId = findPreviousCompatibleInstance(
22031
22234
  paragraphs,
22032
22235
  catalog,
22033
- paragraphIndex,
22236
+ resolvedParagraphIndex,
22034
22237
  currentKind
22035
22238
  );
22036
22239
  if (!compatibleInstanceId || compatibleInstanceId === currentInstanceId) {
@@ -22040,7 +22243,7 @@ function continueNumbering(document2, paragraphIndex, context) {
22040
22243
  };
22041
22244
  }
22042
22245
  const affectedParagraphIndexes = [];
22043
- for (let index = paragraphIndex; index < paragraphs.length; index += 1) {
22246
+ for (let index = resolvedParagraphIndex; index < paragraphs.length; index += 1) {
22044
22247
  const paragraph = paragraphs[index];
22045
22248
  if (!paragraph?.numbering) {
22046
22249
  break;
@@ -22061,10 +22264,24 @@ function continueNumbering(document2, paragraphIndex, context) {
22061
22264
  createdNumberingInstanceId: compatibleInstanceId
22062
22265
  };
22063
22266
  }
22064
- function toggleListKind(document2, paragraphIndexes, kind, context) {
22267
+ function toggleListKind(document2, paragraphIndexes, kind, context, options) {
22065
22268
  const working = cloneEnvelope(document2, context.timestamp);
22066
22269
  const paragraphs = captureEditableParagraphs(working);
22067
- const normalizedIndexes = normalizeParagraphIndexes(paragraphs, paragraphIndexes);
22270
+ const resolved = resolveListCommandParagraphIndexes(
22271
+ working,
22272
+ paragraphs,
22273
+ paragraphIndexes,
22274
+ context,
22275
+ normalizeListCommandTargets(options)
22276
+ );
22277
+ if (resolved.blockedReason) {
22278
+ return {
22279
+ document: working,
22280
+ affectedParagraphIndexes: [],
22281
+ blockedReason: resolved.blockedReason
22282
+ };
22283
+ }
22284
+ const normalizedIndexes = resolved.paragraphIndexes;
22068
22285
  if (normalizedIndexes.length === 0) {
22069
22286
  return {
22070
22287
  document: working,
@@ -22101,10 +22318,24 @@ function toggleListKind(document2, paragraphIndexes, kind, context) {
22101
22318
  createdNumberingInstanceId: numberingInstanceId
22102
22319
  };
22103
22320
  }
22104
- function adjustListLevels(document2, paragraphIndexes, delta, context) {
22321
+ function adjustListLevels(document2, paragraphIndexes, delta, context, options) {
22105
22322
  const working = cloneEnvelope(document2, context.timestamp);
22106
22323
  const paragraphs = captureEditableParagraphs(working);
22107
- const affectedParagraphIndexes = normalizeParagraphIndexes(paragraphs, paragraphIndexes).filter(
22324
+ const resolved = resolveListCommandParagraphIndexes(
22325
+ working,
22326
+ paragraphs,
22327
+ paragraphIndexes,
22328
+ context,
22329
+ normalizeListCommandTargets(options)
22330
+ );
22331
+ if (resolved.blockedReason) {
22332
+ return {
22333
+ document: working,
22334
+ affectedParagraphIndexes: [],
22335
+ blockedReason: resolved.blockedReason
22336
+ };
22337
+ }
22338
+ const affectedParagraphIndexes = resolved.paragraphIndexes.filter(
22108
22339
  (index) => Boolean(paragraphs[index]?.numbering)
22109
22340
  );
22110
22341
  for (const index of affectedParagraphIndexes) {
@@ -22122,6 +22353,121 @@ function adjustListLevels(document2, paragraphIndexes, delta, context) {
22122
22353
  affectedParagraphIndexes
22123
22354
  };
22124
22355
  }
22356
+ function normalizeListCommandTargets(options) {
22357
+ if (options.editableTargets !== void 0) return options.editableTargets;
22358
+ return options.editableTarget ? [options.editableTarget] : [];
22359
+ }
22360
+ function resolveListCommandParagraphIndexes(document2, paragraphs, paragraphIndexes, context, editableTargets) {
22361
+ if (editableTargets.length === 0) {
22362
+ return { paragraphIndexes: normalizeParagraphIndexes(paragraphs, paragraphIndexes) };
22363
+ }
22364
+ const currentTargets = collectEditableTargetRefs(document2, context.editableTargetCache);
22365
+ const paragraphIndexByTargetKey = /* @__PURE__ */ new Map();
22366
+ let paragraphIndex = 0;
22367
+ for (const target of currentTargets) {
22368
+ if (!isParagraphTextTarget(target)) continue;
22369
+ if (!paragraphIndexByTargetKey.has(target.targetKey)) {
22370
+ paragraphIndexByTargetKey.set(target.targetKey, paragraphIndex);
22371
+ paragraphIndex += 1;
22372
+ }
22373
+ }
22374
+ const resolvedIndexes = [];
22375
+ for (const target of editableTargets) {
22376
+ const blockedReason = validateListCommandTarget(target, currentTargets, context);
22377
+ if (blockedReason) return { paragraphIndexes: [], blockedReason };
22378
+ const current = findCurrentListCommandTarget(target, currentTargets);
22379
+ if (!current) {
22380
+ return {
22381
+ paragraphIndexes: [],
22382
+ blockedReason: {
22383
+ code: "list_target_not_found",
22384
+ message: "List editable target no longer resolves in the current canonical document."
22385
+ }
22386
+ };
22387
+ }
22388
+ if (!sameResolvedListCommandTarget(target, current)) {
22389
+ return {
22390
+ paragraphIndexes: [],
22391
+ blockedReason: {
22392
+ code: "list_target_stale",
22393
+ message: "List editable target is stale for the current canonical document."
22394
+ }
22395
+ };
22396
+ }
22397
+ const currentIndex = paragraphIndexByTargetKey.get(current.targetKey);
22398
+ if (currentIndex === void 0) {
22399
+ return {
22400
+ paragraphIndexes: [],
22401
+ blockedReason: {
22402
+ code: "list_target_position_unavailable",
22403
+ message: "List editable target resolved but could not be mapped to a current paragraph."
22404
+ }
22405
+ };
22406
+ }
22407
+ resolvedIndexes.push(currentIndex);
22408
+ }
22409
+ return { paragraphIndexes: normalizeParagraphIndexes(paragraphs, resolvedIndexes) };
22410
+ }
22411
+ function validateListCommandTarget(target, currentTargets, context) {
22412
+ const shapeIssues = validateEditableTargetRef(target);
22413
+ if (shapeIssues.length > 0) {
22414
+ return {
22415
+ code: "list_target_malformed",
22416
+ message: `List editable target is malformed: ${shapeIssues[0]?.path ?? "$"}.`
22417
+ };
22418
+ }
22419
+ if (context.activeStoryKey !== void 0 && target.storyKey !== context.activeStoryKey) {
22420
+ return {
22421
+ code: "list_target_wrong_story",
22422
+ message: "List editable target does not belong to the active story."
22423
+ };
22424
+ }
22425
+ if (target.commandFamily !== "text-leaf" || target.listAddress === void 0) {
22426
+ return {
22427
+ code: "list_target_required",
22428
+ message: "List commands require a validated list item editable target."
22429
+ };
22430
+ }
22431
+ if (target.editability !== "editable" || target.posture.blockers.length > 0) {
22432
+ return {
22433
+ code: "list_target_non_editable",
22434
+ message: target.posture.blockers.length > 0 ? `List editable target is not editable: ${target.posture.blockers.join(", ")}.` : "List editable target is not editable."
22435
+ };
22436
+ }
22437
+ if (!findCurrentListCommandTarget(target, currentTargets)) {
22438
+ return {
22439
+ code: "list_target_not_found",
22440
+ message: "List editable target no longer resolves in the current canonical document."
22441
+ };
22442
+ }
22443
+ return void 0;
22444
+ }
22445
+ function findCurrentListCommandTarget(target, currentTargets) {
22446
+ return currentTargets.find(
22447
+ (candidate) => isParagraphTextTarget(candidate) && candidate.listAddress !== void 0 && (candidate.targetKey === target.targetKey || candidate.listAddress.addressKey === target.listAddress?.addressKey)
22448
+ );
22449
+ }
22450
+ function sameResolvedListCommandTarget(left, right) {
22451
+ return left.kind === right.kind && left.storyKey === right.storyKey && left.blockPath === right.blockPath && left.leafPath === right.leafPath && left.commandFamily === right.commandFamily && left.editability === right.editability && left.staleCheck.paragraphTextHash === right.staleCheck.paragraphTextHash && left.staleCheck.paragraphTextLength === right.staleCheck.paragraphTextLength && left.staleCheck.inlineCount === right.staleCheck.inlineCount && left.staleCheck.blockType === right.staleCheck.blockType && left.listAddress?.addressKey === right.listAddress?.addressKey && left.listAddress?.resolver?.staleHash === right.listAddress?.resolver?.staleHash && jsonStable(left.sourceRef) === jsonStable(right.sourceRef);
22452
+ }
22453
+ function isParagraphTextTarget(target) {
22454
+ return target.commandFamily === "text-leaf" && target.staleCheck.blockType === "paragraph" && target.leafPath.endsWith("/inline");
22455
+ }
22456
+ function jsonStable(value) {
22457
+ return JSON.stringify(sortJson(value));
22458
+ }
22459
+ function sortJson(value) {
22460
+ if (Array.isArray(value)) return value.map(sortJson);
22461
+ if (value && typeof value === "object") {
22462
+ const record = value;
22463
+ const sorted = {};
22464
+ for (const key of Object.keys(record).sort()) {
22465
+ sorted[key] = sortJson(record[key]);
22466
+ }
22467
+ return sorted;
22468
+ }
22469
+ return value;
22470
+ }
22125
22471
  function ensureDefaultInstance(catalog, kind) {
22126
22472
  const existing = Object.values(catalog.instances).find(
22127
22473
  (instance) => getListKind(catalog, instance.numberingInstanceId) === kind
@@ -22287,7 +22633,8 @@ function applyListAwareTextCommand(context, command, deps) {
22287
22633
  const result = indentListItems(
22288
22634
  context.localDocument,
22289
22635
  [paragraphContext.paragraphIndex],
22290
- { timestamp: context.timestamp }
22636
+ listCommandContext(context),
22637
+ listCommandTargetOptions(context, paragraphContext)
22291
22638
  );
22292
22639
  return createListMutationResult(result, context.localSnapshot.selection, deps);
22293
22640
  }
@@ -22295,7 +22642,8 @@ function applyListAwareTextCommand(context, command, deps) {
22295
22642
  const result = outdentListItems(
22296
22643
  context.localDocument,
22297
22644
  [paragraphContext.paragraphIndex],
22298
- { timestamp: context.timestamp }
22645
+ listCommandContext(context),
22646
+ listCommandTargetOptions(context, paragraphContext)
22299
22647
  );
22300
22648
  return createListMutationResult(result, context.localSnapshot.selection, deps);
22301
22649
  }
@@ -22306,7 +22654,8 @@ function applyListAwareTextCommand(context, command, deps) {
22306
22654
  const result = backspaceAtListStart(
22307
22655
  context.localDocument,
22308
22656
  paragraphContext.paragraphIndex,
22309
- { timestamp: context.timestamp }
22657
+ listCommandContext(context),
22658
+ listCommandTargetOptions(context, paragraphContext)
22310
22659
  );
22311
22660
  return result.handled ? createListMutationResult(result, context.localSnapshot.selection, deps) : null;
22312
22661
  }
@@ -22318,14 +22667,30 @@ function applyListAwareTextCommand(context, command, deps) {
22318
22667
  context.localDocument,
22319
22668
  paragraphContext.paragraphIndex,
22320
22669
  true,
22321
- { timestamp: context.timestamp }
22670
+ listCommandContext(context),
22671
+ listCommandTargetOptions(context, paragraphContext)
22322
22672
  );
22673
+ if (result.blockedReason) {
22674
+ return createListMutationResult(result, context.localSnapshot.selection, deps);
22675
+ }
22323
22676
  return result.action === "split" ? null : createListMutationResult(result, context.localSnapshot.selection, deps);
22324
22677
  }
22325
22678
  default:
22326
22679
  return null;
22327
22680
  }
22328
22681
  }
22682
+ function listCommandContext(context) {
22683
+ return {
22684
+ timestamp: context.timestamp,
22685
+ ...context.activeStory.kind === "main" ? { activeStoryKey: "main" } : {}
22686
+ };
22687
+ }
22688
+ function listCommandTargetOptions(context, paragraphContext) {
22689
+ if (context.activeStory.kind !== "main" || !paragraphContext.paragraph.editableTarget) {
22690
+ return {};
22691
+ }
22692
+ return { editableTargets: [paragraphContext.paragraph.editableTarget] };
22693
+ }
22329
22694
  function createListMutationResult(result, selection, deps) {
22330
22695
  return {
22331
22696
  changed: result.affectedParagraphIndexes.length > 0,
@@ -26518,7 +26883,7 @@ function parseCanonicalTextLeafPath(path) {
26518
26883
  if (normalized[offset] !== "/") return null;
26519
26884
  offset += 1;
26520
26885
  }
26521
- return tokens.some((token) => token.kind === "txbx") ? tokens : null;
26886
+ return tokens.length > 0 ? tokens : null;
26522
26887
  }
26523
26888
  function parseCanonicalHyperlinkPath(path) {
26524
26889
  const blockStart = path.indexOf("/block[");
@@ -33493,7 +33858,7 @@ function validateResult(result, context) {
33493
33858
  return { ...result, selection: validated };
33494
33859
  }
33495
33860
  function getPostMutationMaxOffset(result, context) {
33496
- if (typeof context.activeStorySize !== "number" || context.textTarget?.kind === "text-leaf") {
33861
+ if (typeof context.activeStorySize !== "number" || isTargetLocalTextLeaf(context.textTarget)) {
33497
33862
  return result.storyText.length;
33498
33863
  }
33499
33864
  let storySize = context.activeStorySize;
@@ -33502,6 +33867,9 @@ function getPostMutationMaxOffset(result, context) {
33502
33867
  }
33503
33868
  return Math.max(result.storyText.length, storySize);
33504
33869
  }
33870
+ function isTargetLocalTextLeaf(textTarget) {
33871
+ return textTarget?.kind === "text-leaf" && textTarget.blockPath.includes("/txbx/");
33872
+ }
33505
33873
  var editLayer = {
33506
33874
  applyTextInsert(doc, selection, text, context, formatting) {
33507
33875
  return validateResult(insertText(doc, selection, text, context, formatting), context);
@@ -33764,6 +34132,13 @@ function withCommandTextTarget(context, command) {
33764
34132
  textTarget: command.textTarget
33765
34133
  };
33766
34134
  }
34135
+ function listCommandContext2(context) {
34136
+ return {
34137
+ timestamp: context.timestamp,
34138
+ ...context.activeStoryKey !== void 0 ? { activeStoryKey: context.activeStoryKey } : {},
34139
+ ...context.editableTargetCache !== void 0 ? { editableTargetCache: context.editableTargetCache } : {}
34140
+ };
34141
+ }
33767
34142
  function executeEditorCommand(state, command, context) {
33768
34143
  switch (command.type) {
33769
34144
  case "selection.set":
@@ -34405,7 +34780,17 @@ function executeEditorCommand(state, command, context) {
34405
34780
  });
34406
34781
  }
34407
34782
  case "list.toggle": {
34408
- const result = command.kind === "bulleted" ? toggleBulletedList(state.document, command.paragraphIndexes, { timestamp: context.timestamp }) : toggleNumberedList(state.document, command.paragraphIndexes, { timestamp: context.timestamp });
34783
+ const result = command.kind === "bulleted" ? toggleBulletedList(
34784
+ state.document,
34785
+ command.paragraphIndexes ?? [],
34786
+ listCommandContext2(context),
34787
+ { editableTargets: command.editableTargets }
34788
+ ) : toggleNumberedList(
34789
+ state.document,
34790
+ command.paragraphIndexes ?? [],
34791
+ listCommandContext2(context),
34792
+ { editableTargets: command.editableTargets }
34793
+ );
34409
34794
  return buildDocumentReplaceTransaction(state, context, {
34410
34795
  changed: result.affectedParagraphIndexes.length > 0,
34411
34796
  document: result.document,
@@ -34413,7 +34798,12 @@ function executeEditorCommand(state, command, context) {
34413
34798
  });
34414
34799
  }
34415
34800
  case "list.indent": {
34416
- const result = indentListItems(state.document, command.paragraphIndexes, { timestamp: context.timestamp });
34801
+ const result = indentListItems(
34802
+ state.document,
34803
+ command.paragraphIndexes ?? [],
34804
+ listCommandContext2(context),
34805
+ { editableTargets: command.editableTargets }
34806
+ );
34417
34807
  return buildDocumentReplaceTransaction(state, context, {
34418
34808
  changed: result.affectedParagraphIndexes.length > 0,
34419
34809
  document: result.document,
@@ -34421,7 +34811,12 @@ function executeEditorCommand(state, command, context) {
34421
34811
  });
34422
34812
  }
34423
34813
  case "list.outdent": {
34424
- const result = outdentListItems(state.document, command.paragraphIndexes, { timestamp: context.timestamp });
34814
+ const result = outdentListItems(
34815
+ state.document,
34816
+ command.paragraphIndexes ?? [],
34817
+ listCommandContext2(context),
34818
+ { editableTargets: command.editableTargets }
34819
+ );
34425
34820
  return buildDocumentReplaceTransaction(state, context, {
34426
34821
  changed: result.affectedParagraphIndexes.length > 0,
34427
34822
  document: result.document,
@@ -34431,9 +34826,10 @@ function executeEditorCommand(state, command, context) {
34431
34826
  case "list.restart-numbering": {
34432
34827
  const result = restartNumbering(
34433
34828
  state.document,
34434
- command.paragraphIndex,
34435
- { timestamp: context.timestamp },
34436
- command.startAt
34829
+ command.paragraphIndex ?? -1,
34830
+ listCommandContext2(context),
34831
+ command.startAt,
34832
+ { editableTarget: command.editableTarget }
34437
34833
  );
34438
34834
  return buildDocumentReplaceTransaction(state, context, {
34439
34835
  changed: result.affectedParagraphIndexes.length > 0,
@@ -34444,8 +34840,9 @@ function executeEditorCommand(state, command, context) {
34444
34840
  case "list.continue-numbering": {
34445
34841
  const result = continueNumbering(
34446
34842
  state.document,
34447
- command.paragraphIndex,
34448
- { timestamp: context.timestamp }
34843
+ command.paragraphIndex ?? -1,
34844
+ listCommandContext2(context),
34845
+ { editableTarget: command.editableTarget }
34449
34846
  );
34450
34847
  return buildDocumentReplaceTransaction(state, context, {
34451
34848
  changed: result.affectedParagraphIndexes.length > 0,
@@ -38407,6 +38804,27 @@ function hitTestRegion(index, region, point) {
38407
38804
  (target2) => target2.regionId === region.regionId
38408
38805
  );
38409
38806
  const containing = targets.filter((target2) => containsPoint(target2.rect, point));
38807
+ const generatedTarget = containing.find(
38808
+ (target2) => target2.generatedContentKind === "numbering-marker"
38809
+ );
38810
+ if (generatedTarget) {
38811
+ const anchorHit2 = firstLineAnchor(index, generatedTarget)?.runtimeOffset !== void 0 ? {
38812
+ runtimeOffset: firstLineAnchor(index, generatedTarget).runtimeOffset,
38813
+ assoc: "before"
38814
+ } : resolveLineAnchorHit(index, generatedTarget, point);
38815
+ return {
38816
+ pageIndex: generatedTarget.pageIndex,
38817
+ regionKind: generatedTarget.regionKind,
38818
+ blockId: generatedTarget.blockId,
38819
+ fragmentId: generatedTarget.fragmentId,
38820
+ lineIndex: generatedTarget.lineIndex,
38821
+ runtimeOffset: anchorHit2?.runtimeOffset ?? 0,
38822
+ assoc: "before",
38823
+ generatedContentKind: generatedTarget.generatedContentKind,
38824
+ generatedContentBoundary: generatedTarget.generatedContentBoundary?.policy,
38825
+ semanticEntryId: generatedTarget.targetId.startsWith("hit:") ? generatedTarget.targetId.slice("hit:".length) : generatedTarget.targetId
38826
+ };
38827
+ }
38410
38828
  const target = nearestTarget(containing, point) ?? nearestTarget(targets, point);
38411
38829
  if (!target) return null;
38412
38830
  const anchorHit = resolveLineAnchorHit(index, target, point);
@@ -38783,6 +39201,7 @@ function projectGeometryIndexFromFrame(frame, options) {
38783
39201
  identities,
38784
39202
  storyKey: storyKey2,
38785
39203
  entries: semanticEntries,
39204
+ hitTargets,
38786
39205
  projectedBlocksByStory,
38787
39206
  projectedCommandTargetsByKey,
38788
39207
  precision,
@@ -39053,6 +39472,7 @@ function appendBlockSemanticEntries(input) {
39053
39472
  identities,
39054
39473
  storyKey: storyKey2,
39055
39474
  entries,
39475
+ hitTargets,
39056
39476
  projectedBlocksByStory,
39057
39477
  projectedCommandTargetsByKey,
39058
39478
  precision,
@@ -39082,6 +39502,7 @@ function appendBlockSemanticEntries(input) {
39082
39502
  block,
39083
39503
  sourceIdentity: sliceIdentity,
39084
39504
  entries,
39505
+ hitTargets,
39085
39506
  projectedCommandTargetsByKey,
39086
39507
  precision,
39087
39508
  frameCompleteness,
@@ -39263,6 +39684,7 @@ function appendFragmentLayoutObjectSemanticEntries(input) {
39263
39684
  block,
39264
39685
  sourceIdentity,
39265
39686
  entries,
39687
+ hitTargets,
39266
39688
  projectedCommandTargetsByKey,
39267
39689
  precision,
39268
39690
  frameCompleteness,
@@ -39347,18 +39769,57 @@ function appendFragmentLayoutObjectSemanticEntries(input) {
39347
39769
  }
39348
39770
  return;
39349
39771
  }
39350
- if (layoutObject.kind === "numbered-paragraph") {
39351
- const markerProjection = resolveNumberingMarkerProjection(block);
39772
+ const numberingRows = layoutObject.numberingRows && layoutObject.numberingRows.length > 0 ? layoutObject.numberingRows : layoutObject.kind === "numbered-paragraph" && layoutObject.numbering ? [layoutObject.numbering] : [];
39773
+ for (let index = 0; index < numberingRows.length; index += 1) {
39774
+ const numbering = numberingRows[index];
39775
+ const markerProjection = resolveNumberingMarkerProjection(block, numbering);
39776
+ const entryId = layoutObject.kind === "numbered-paragraph" && index === 0 ? `semantic:numbering-marker:${base.sliceId}` : `semantic:numbering-marker:${base.sliceId}:${stableGeometryId(
39777
+ numbering.numberingLayoutId ?? numbering.numberingKey ?? String(index)
39778
+ )}`;
39779
+ const source = numberingSourceIdentity(numbering, sourceIdentity);
39352
39780
  entries.push({
39353
39781
  ...base,
39354
- entryId: `semantic:numbering-marker:${base.sliceId}`,
39782
+ entryId,
39355
39783
  kind: "numbering-marker",
39356
39784
  layoutObjectId: layoutObject.objectId,
39785
+ numberingLayoutId: numbering.numberingLayoutId,
39786
+ numberingKey: numbering.numberingKey,
39787
+ numberingTargetKey: numbering.targetKey,
39788
+ numberingTargetKind: numbering.targetKind,
39789
+ numberingCanonicalAddressKey: numbering.canonicalAddressKey,
39790
+ numberingListAddressKey: numbering.listAddressKey,
39791
+ numberingMarkerText: numbering.markerText,
39792
+ numberingMarkerSuffix: numbering.markerSuffix,
39793
+ numberingFormat: numbering.format,
39794
+ numberingFormatPosture: numbering.formatPosture,
39795
+ numberingUnavailableReasons: numbering.unavailableReasons,
39796
+ markerGlyphRect: markerProjection.rect,
39797
+ markerLaneRect: markerProjection.markerLaneRect,
39798
+ textColumnRect: markerProjection.textColumnRect,
39799
+ markerBoundary: markerProjection.markerBoundary,
39357
39800
  rect: markerProjection.rect,
39358
39801
  status: markerProjection.status,
39359
39802
  precision: markerProjection.precision,
39360
39803
  frameCompleteness,
39361
- ...sourceIdentity ? { sourceIdentity } : {}
39804
+ ...source ? { sourceIdentity: source } : {}
39805
+ });
39806
+ hitTargets.push({
39807
+ targetId: `hit:${entryId}`,
39808
+ pageId: base.pageId,
39809
+ pageIndex: base.pageIndex,
39810
+ regionId: base.regionId,
39811
+ regionKind: base.regionKind,
39812
+ blockId: base.blockId,
39813
+ fragmentId: base.fragmentId,
39814
+ lineIndex: firstLineIndex(block),
39815
+ rect: markerProjection.rect,
39816
+ precision: markerProjection.precision,
39817
+ generatedContentKind: "numbering-marker",
39818
+ generatedContentBoundary: {
39819
+ policy: "snap-to-authored-text",
39820
+ authoredTextStartsAtPx: markerProjection.markerBoundary.authoredTextStartsAtPx,
39821
+ selectionPolicy: "exclude-generated-marker"
39822
+ }
39362
39823
  });
39363
39824
  recordPrecision(precision, markerProjection.precision);
39364
39825
  }
@@ -39449,8 +39910,8 @@ function bookmarkRangeSourceIdentity(fact, fallback) {
39449
39910
  joinKind: "block-scoped"
39450
39911
  };
39451
39912
  }
39452
- function resolveNumberingMarkerProjection(block) {
39453
- const metadata = resolveNumberingMarkerProjectionMetadata(block);
39913
+ function resolveNumberingMarkerProjection(block, numbering) {
39914
+ const metadata = resolveNumberingMarkerProjectionMetadata(block, numbering);
39454
39915
  const blockFrame = block.frame;
39455
39916
  if (metadata.markerLane && metadata.measuredWidthTwips !== void 0) {
39456
39917
  const markerLane = metadata.markerLane;
@@ -39461,14 +39922,25 @@ function resolveNumberingMarkerProjection(block) {
39461
39922
  const rawRightPx = rawLeftPx + markerLane.widthTwips * pxPerTwip;
39462
39923
  const leftPx = clamp3(rawLeftPx, blockLeftPx, blockRightPx);
39463
39924
  const rightPx = clamp3(rawRightPx, leftPx, blockRightPx);
39925
+ const markerLaneRect = {
39926
+ leftPx,
39927
+ topPx: blockFrame.topPx,
39928
+ widthPx: rightPx - leftPx,
39929
+ heightPx: blockFrame.heightPx,
39930
+ space: "frame",
39931
+ precision: metadata.precision
39932
+ };
39933
+ const textColumnRect = metadata.textColumn ? projectTextColumnRect(blockFrame, metadata.measuredWidthTwips, metadata.textColumn) : void 0;
39464
39934
  return {
39465
- rect: {
39466
- leftPx,
39467
- topPx: blockFrame.topPx,
39468
- widthPx: rightPx - leftPx,
39469
- heightPx: blockFrame.heightPx,
39470
- space: "frame",
39471
- precision: metadata.precision
39935
+ rect: markerLaneRect,
39936
+ markerLaneRect,
39937
+ ...textColumnRect ? { textColumnRect } : {},
39938
+ markerBoundary: {
39939
+ generatedContent: "numbering-marker",
39940
+ caretPolicy: "snap-to-authored-text",
39941
+ selectionPolicy: "exclude-marker-unless-list-item-action",
39942
+ coordinateSpace: "frame-px",
39943
+ ...textColumnRect ? { authoredTextStartsAtPx: textColumnRect.leftPx } : {}
39472
39944
  },
39473
39945
  precision: metadata.precision,
39474
39946
  status: metadata.status
@@ -39487,20 +39959,28 @@ function resolveNumberingMarkerProjection(block) {
39487
39959
  space: "frame",
39488
39960
  precision: metadata.precision
39489
39961
  },
39962
+ markerBoundary: {
39963
+ generatedContent: "numbering-marker",
39964
+ caretPolicy: "snap-to-authored-text",
39965
+ selectionPolicy: "exclude-marker-unless-list-item-action",
39966
+ coordinateSpace: "frame-px"
39967
+ },
39490
39968
  precision: metadata.precision,
39491
39969
  status: metadata.status
39492
39970
  };
39493
39971
  }
39494
- function resolveNumberingMarkerProjectionMetadata(block) {
39972
+ function resolveNumberingMarkerProjectionMetadata(block, numbering) {
39495
39973
  const blockFrame = block.frame;
39496
39974
  const layoutObject = block.fragment.layoutObject;
39497
- const markerLane = layoutObject?.kind === "numbered-paragraph" ? layoutObject.numbering?.markerLane : void 0;
39975
+ const markerLane = numbering?.markerLane ?? (layoutObject?.kind === "numbered-paragraph" ? layoutObject.numbering?.markerLane : void 0);
39976
+ const textColumn = numbering?.textColumn ?? (layoutObject?.kind === "numbered-paragraph" ? layoutObject.numbering?.textColumn : void 0);
39498
39977
  const measuredWidthTwips = layoutObject?.measuredExtentTwips.widthTwips;
39499
39978
  if (markerLane && markerLane.widthTwips > 0 && measuredWidthTwips !== void 0 && measuredWidthTwips > 0 && Number.isFinite(blockFrame.widthPx)) {
39500
39979
  return {
39501
39980
  precision: "within-tolerance",
39502
39981
  status: "realized",
39503
39982
  markerLane,
39983
+ ...textColumn ? { textColumn } : {},
39504
39984
  measuredWidthTwips
39505
39985
  };
39506
39986
  }
@@ -39509,6 +39989,42 @@ function resolveNumberingMarkerProjectionMetadata(block) {
39509
39989
  status: "requires-rehydration"
39510
39990
  };
39511
39991
  }
39992
+ function projectTextColumnRect(blockFrame, measuredWidthTwips, textColumn) {
39993
+ if (measuredWidthTwips <= 0 || !Number.isFinite(blockFrame.widthPx)) {
39994
+ return void 0;
39995
+ }
39996
+ const pxPerTwip = blockFrame.widthPx / measuredWidthTwips;
39997
+ const leftPx = blockFrame.leftPx + textColumn.startTwips * pxPerTwip;
39998
+ const rightInsetPx = (textColumn.rightTwips ?? 0) * pxPerTwip;
39999
+ const rightPx = blockFrame.leftPx + blockFrame.widthPx - rightInsetPx;
40000
+ if (rightPx < leftPx) return void 0;
40001
+ return {
40002
+ leftPx,
40003
+ topPx: blockFrame.topPx,
40004
+ widthPx: rightPx - leftPx,
40005
+ heightPx: blockFrame.heightPx,
40006
+ space: "frame",
40007
+ precision: "within-tolerance"
40008
+ };
40009
+ }
40010
+ function numberingSourceIdentity(numbering, fallback) {
40011
+ const storyKey2 = numbering.storyKey ?? fallback?.storyKey;
40012
+ if (!storyKey2) return fallback;
40013
+ return {
40014
+ storyKey: storyKey2,
40015
+ ...numbering.sourceBlockPath ?? fallback?.blockPath ? { blockPath: numbering.sourceBlockPath ?? fallback?.blockPath } : {},
40016
+ ...numbering.numberingKey ?? fallback?.scopeKey ? { scopeKey: numbering.numberingKey ?? fallback?.scopeKey } : {},
40017
+ ...numbering.numberingInstanceId ?? fallback?.scopeId ? { scopeId: numbering.numberingInstanceId ?? fallback?.scopeId } : {},
40018
+ ...numbering.numberingSourceRef ?? numbering.sourceRef ?? fallback?.sourceRef ? { sourceRef: numbering.numberingSourceRef ?? numbering.sourceRef ?? fallback?.sourceRef } : {},
40019
+ joinKind: "block-scoped"
40020
+ };
40021
+ }
40022
+ function stableGeometryId(value) {
40023
+ return value.replace(/[^A-Za-z0-9_.:-]+/gu, "_");
40024
+ }
40025
+ function firstLineIndex(block) {
40026
+ return block.lines[0]?.line.lineIndex ?? 0;
40027
+ }
39512
40028
  function countBlockSemanticEntries(block) {
39513
40029
  const counts = createPrecisionCounts();
39514
40030
  const layoutObject = block.fragment.layoutObject;
@@ -45908,6 +46424,24 @@ function refusalIdForPostureBlocker(target, blocker2) {
45908
46424
  return "editable_target_opaque_content";
45909
46425
  case "synthetic-layout-cell":
45910
46426
  return "editable_target_synthetic_layout_cell";
46427
+ case "list-text-readback-missing":
46428
+ return "list_text_readback_missing";
46429
+ case "list-structure-command-missing":
46430
+ return "list_structure_command_missing";
46431
+ case "list-target-stale":
46432
+ return "list_target_stale";
46433
+ case "list-secondary-story-unsupported":
46434
+ return "list_secondary_story_unsupported";
46435
+ case "list-table-target-missing":
46436
+ return "list_table_target_missing";
46437
+ case "list-export-persistence-missing":
46438
+ return "list_export_persistence_missing";
46439
+ case "numbering-format-unsupported":
46440
+ return "numbering_format_unsupported";
46441
+ case "picture-bullet-preserve-only":
46442
+ return "picture_bullet_preserve_only";
46443
+ case "marker-geometry-unavailable":
46444
+ return "marker_geometry_unavailable";
45911
46445
  case "unmodeled-target":
45912
46446
  return target.commandFamily === "link-bookmark" ? "editable_target_linked_content_unmodeled" : "editable_target_unmodeled";
45913
46447
  }
@@ -45930,12 +46464,42 @@ function auditCategoryForPostureBlocker(target, blocker2) {
45930
46464
  return target.commandFamily === "link-bookmark" ? "linked-content" : "unsupported-command";
45931
46465
  case "synthetic-layout-cell":
45932
46466
  return "synthetic-cell";
46467
+ case "list-target-stale":
46468
+ return "stale-ref";
46469
+ case "picture-bullet-preserve-only":
46470
+ case "list-export-persistence-missing":
46471
+ return "preserve-only";
46472
+ case "list-text-readback-missing":
46473
+ case "list-structure-command-missing":
46474
+ case "list-secondary-story-unsupported":
46475
+ case "list-table-target-missing":
46476
+ case "numbering-format-unsupported":
46477
+ case "marker-geometry-unavailable":
46478
+ return "unsupported-command";
45933
46479
  }
45934
46480
  }
45935
46481
  function messageForPostureBlocker(blocker2) {
45936
46482
  switch (blocker2) {
45937
46483
  case "synthetic-layout-cell":
45938
46484
  return "Hidden vertical-merge continuation or synthetic layout cells are not editable targets.";
46485
+ case "list-text-readback-missing":
46486
+ return "List text edits need an authoritative list-item text target before mutation.";
46487
+ case "list-structure-command-missing":
46488
+ return "List structure changes need a supported list command envelope before mutation.";
46489
+ case "list-target-stale":
46490
+ return "List target identity is stale for the current canonical document.";
46491
+ case "list-secondary-story-unsupported":
46492
+ return "List edits in this secondary story are not yet supported.";
46493
+ case "list-table-target-missing":
46494
+ return "Table-contained list item is missing a command-safe list target.";
46495
+ case "list-export-persistence-missing":
46496
+ return "List mutation is blocked until export/reopen persistence is available.";
46497
+ case "numbering-format-unsupported":
46498
+ return "Numbering format is unsupported for this list command.";
46499
+ case "picture-bullet-preserve-only":
46500
+ return "Picture bullet lists are preserve-only until picture bullet mutation is supported.";
46501
+ case "marker-geometry-unavailable":
46502
+ return "List marker geometry is unavailable for this target.";
45939
46503
  default:
45940
46504
  return void 0;
45941
46505
  }
@@ -47219,6 +47783,21 @@ function compileParagraphScope(entry, options = {}) {
47219
47783
  partial: true
47220
47784
  };
47221
47785
  }
47786
+ function storyKeyFromHandle(handle) {
47787
+ const target = handle.storyTarget;
47788
+ if (target.kind === "main") return "main";
47789
+ return null;
47790
+ }
47791
+ function textLeafEditableTargetHint(entry, semanticBlockRange) {
47792
+ const storyKey2 = storyKeyFromHandle(entry.handle);
47793
+ if (!storyKey2) return void 0;
47794
+ return {
47795
+ kind: "text-leaf",
47796
+ storyKey: storyKey2,
47797
+ blockPath: `${storyKey2}/block[${entry.blockIndex}]`,
47798
+ semanticBlockRange
47799
+ };
47800
+ }
47222
47801
  function compileParagraphReplacement(entry, proposed, options) {
47223
47802
  if (proposed.operation !== "replace" && proposed.operation !== "insert-before" && proposed.operation !== "insert-after") {
47224
47803
  return null;
@@ -47274,6 +47853,7 @@ function compileParagraphReplacement(entry, proposed, options) {
47274
47853
  {
47275
47854
  kind: stepKind,
47276
47855
  summary: stepKind === "text-replace" ? actionSummary : `suggest-mode ${actionSummary}`,
47856
+ ...textLeafEditableTargetHint(entry, blockRange) ? { editableTargetHint: textLeafEditableTargetHint(entry, blockRange) } : {},
47277
47857
  range: { from: operationRange.from, to: operationRange.to },
47278
47858
  text,
47279
47859
  ...proposed.formatting ? { formatting: proposed.formatting } : {}
@@ -47301,6 +47881,7 @@ function compileParagraphReplacement(entry, proposed, options) {
47301
47881
  {
47302
47882
  kind: "fragment-replace",
47303
47883
  summary: actionSummary,
47884
+ ...textLeafEditableTargetHint(entry, blockRange) ? { editableTargetHint: textLeafEditableTargetHint(entry, blockRange) } : {},
47304
47885
  range: { from: operationRange.from, to: operationRange.to },
47305
47886
  fragment
47306
47887
  }
@@ -49223,14 +49804,17 @@ function paragraphHasBookmarkId(paragraph, bookmarkId) {
49223
49804
  function commandActionHandleForAddress(commandFamily, address) {
49224
49805
  return address ? `scope-command:${commandFamily}:${address.addressKey}` : void 0;
49225
49806
  }
49226
- function withCommandAction(evidence, target) {
49227
- if (evidence.status !== "supported" || !target.canonicalAddress) return evidence;
49807
+ function withCommandAction(evidence, target, canonicalAddress = target.canonicalAddress) {
49808
+ if (evidence.status !== "supported" || !canonicalAddress) return evidence;
49228
49809
  return {
49229
49810
  ...evidence,
49230
- actionHandle: commandActionHandleForAddress(target.commandFamily, target.canonicalAddress),
49231
- canonicalAddress: target.canonicalAddress
49811
+ actionHandle: commandActionHandleForAddress(target.commandFamily, canonicalAddress),
49812
+ canonicalAddress
49232
49813
  };
49233
49814
  }
49815
+ function commandAddressForTarget(target, scopeKind) {
49816
+ return scopeKind === "list-item" && target.listAddress !== void 0 ? target.listAddress : target.canonicalAddress;
49817
+ }
49234
49818
  function runtimeTextCommandEvidence(target, workflowBlockers) {
49235
49819
  const shapeIssues = validateEditableTargetRef(target);
49236
49820
  if (shapeIssues.length > 0) {
@@ -49283,6 +49867,9 @@ var TABLE_TEXT_TARGET_KINDS2 = /* @__PURE__ */ new Set([
49283
49867
  var LIST_TEXT_TARGET_KINDS2 = /* @__PURE__ */ new Set([
49284
49868
  "paragraph-text",
49285
49869
  "sdt-paragraph-text",
49870
+ "table-cell-paragraph-text",
49871
+ "nested-table-cell-paragraph-text",
49872
+ "sdt-table-cell-paragraph-text",
49286
49873
  "secondary-story-paragraph-text"
49287
49874
  ]);
49288
49875
  function tableTextScopeReplacementPosture(target) {
@@ -49333,7 +49920,7 @@ function runtimeCommandEvidence(target, workflowBlockers, textCommand, scopeKind
49333
49920
  intents: commandIntentsForTarget(target, scopeKind),
49334
49921
  reason: textCommand.reason,
49335
49922
  ...textCommand.blockers ? { blockers: textCommand.blockers } : {}
49336
- }, target);
49923
+ }, target, commandAddressForTarget(target, scopeKind));
49337
49924
  }
49338
49925
  if (target.commandFamily === "comment-revision") {
49339
49926
  const isOpen = target.review?.status === "open";
@@ -55385,6 +55972,16 @@ function createLayoutFacet(input) {
55385
55972
  function currentGraph() {
55386
55973
  return engine.getPageGraph(getQueryInput());
55387
55974
  }
55975
+ function fullGraphForViewportIndependentReads() {
55976
+ const query = getQueryInput();
55977
+ if (!query.viewportPageWindow) {
55978
+ return engine.getPageGraph(query);
55979
+ }
55980
+ return engine.getPageGraph({
55981
+ document: query.document,
55982
+ ...query.viewState ? { viewState: query.viewState } : {}
55983
+ });
55984
+ }
55388
55985
  function currentMapper() {
55389
55986
  return engine.getFragmentMapper(getQueryInput());
55390
55987
  }
@@ -55522,7 +56119,7 @@ function createLayoutFacet(input) {
55522
56119
  return graph.sections.map((section) => toPublicSectionNode(graph, section.index)).filter((node) => node !== null);
55523
56120
  },
55524
56121
  getPageForOffset(offset, story) {
55525
- const graph = currentGraph();
56122
+ const graph = fullGraphForViewportIndependentReads();
55526
56123
  const page = findPageForOffsetAndStory(graph, offset, story);
55527
56124
  return page ? toPublicPageNode(page, graph) : null;
55528
56125
  },
@@ -55834,7 +56431,7 @@ function createLayoutFacet(input) {
55834
56431
  return null;
55835
56432
  },
55836
56433
  getBlockHeightsTwips() {
55837
- const graph = currentGraph();
56434
+ const graph = fullGraphForViewportIndependentReads();
55838
56435
  if (blockHeightsCache.revision === graph.revision && blockHeightsCache.map) {
55839
56436
  return blockHeightsCache.map;
55840
56437
  }
@@ -58602,7 +59199,8 @@ async function collectEditorStateForSerialize(args) {
58602
59199
  // src/io/ooxml/parse-bookmark-references.ts
58603
59200
  var HYPERLINK_ANCHOR_RE = /<(?:\w+:)?hyperlink\b[^>]*\bw:anchor\s*=\s*"([^"]*)"/gi;
58604
59201
  var INSTR_TEXT_RE = /<(?:\w+:)?instrText\b[^>]*>([\s\S]*?)<\/(?:\w+:)?instrText>/gi;
58605
- var FLD_SIMPLE_INSTR_RE = /<(?:\w+:)?fldSimple\b[^>]*(?:\bw:instr|\binstr)\s*=\s*(["'])([\s\S]*?)\1/gi;
59202
+ var FLD_SIMPLE_INSTR_DOUBLE_RE = /<(?:\w+:)?fldSimple\b[^>]*?\b(?:w:)?instr\s*=\s*"([^"]*)"/gi;
59203
+ var FLD_SIMPLE_INSTR_SINGLE_RE = /<(?:\w+:)?fldSimple\b[^>]*?\b(?:w:)?instr\s*=\s*'([^']*)'/gi;
58606
59204
  var TOC_FIELD_RE = /\bTOC\b/;
58607
59205
  var REFLIKE_FIELD_RE = /\b(?:HYPERLINK|REF|PAGEREF|NOTEREF)\s+([A-Za-z0-9_:.\-]+)/g;
58608
59206
  var DATA_BINDING_RE = /<(?:\w+:)?dataBinding\b/i;
@@ -58621,11 +59219,22 @@ function scanBookmarkReferences(documentXml, callerAllowlist = []) {
58621
59219
  }
58622
59220
  INSTR_TEXT_RE.lastIndex = 0;
58623
59221
  while ((m = INSTR_TEXT_RE.exec(documentXml)) !== null) {
58624
- if (scanInstructionText(m[1] ?? "", retained)) retainAllToc = true;
59222
+ const instrText = m[1] ?? "";
59223
+ scanFieldInstruction(instrText, retained, () => {
59224
+ retainAllToc = true;
59225
+ });
59226
+ }
59227
+ FLD_SIMPLE_INSTR_DOUBLE_RE.lastIndex = 0;
59228
+ while ((m = FLD_SIMPLE_INSTR_DOUBLE_RE.exec(documentXml)) !== null) {
59229
+ scanFieldInstruction(decodeXmlAttribute(m[1] ?? ""), retained, () => {
59230
+ retainAllToc = true;
59231
+ });
58625
59232
  }
58626
- FLD_SIMPLE_INSTR_RE.lastIndex = 0;
58627
- while ((m = FLD_SIMPLE_INSTR_RE.exec(documentXml)) !== null) {
58628
- if (scanInstructionText(m[2] ?? "", retained)) retainAllToc = true;
59233
+ FLD_SIMPLE_INSTR_SINGLE_RE.lastIndex = 0;
59234
+ while ((m = FLD_SIMPLE_INSTR_SINGLE_RE.exec(documentXml)) !== null) {
59235
+ scanFieldInstruction(decodeXmlAttribute(m[1] ?? ""), retained, () => {
59236
+ retainAllToc = true;
59237
+ });
58629
59238
  }
58630
59239
  retainRevisionBoundedBookmarks(documentXml, retained);
58631
59240
  return {
@@ -58634,14 +59243,16 @@ function scanBookmarkReferences(documentXml, callerAllowlist = []) {
58634
59243
  retainAll
58635
59244
  };
58636
59245
  }
58637
- function scanInstructionText(instrText, retained) {
58638
- const hasTocField = TOC_FIELD_RE.test(instrText);
59246
+ function scanFieldInstruction(instrText, retained, retainToc) {
59247
+ if (TOC_FIELD_RE.test(instrText)) retainToc();
58639
59248
  REFLIKE_FIELD_RE.lastIndex = 0;
58640
59249
  let r;
58641
59250
  while ((r = REFLIKE_FIELD_RE.exec(instrText)) !== null) {
58642
59251
  if (r[1]) retained.add(r[1]);
58643
59252
  }
58644
- return hasTocField;
59253
+ }
59254
+ function decodeXmlAttribute(value) {
59255
+ return value.replace(/&quot;/g, '"').replace(/&apos;/g, "'").replace(/&lt;/g, "<").replace(/&gt;/g, ">").replace(/&amp;/g, "&");
58645
59256
  }
58646
59257
  function retainRevisionBoundedBookmarks(documentXml, retained) {
58647
59258
  const starts = /* @__PURE__ */ new Map();
@@ -58994,18 +59605,23 @@ function parseNumberingXml(xml, context) {
58994
59605
  const abstractDefinitions = {};
58995
59606
  const instances = {};
58996
59607
  const numPicBullets = {};
59608
+ const topLevelOrdinals = /* @__PURE__ */ new Map();
58997
59609
  for (const child of numberingElement.children) {
58998
59610
  if (child.type !== "element") {
58999
59611
  continue;
59000
59612
  }
59001
- if (localName(child.name) === "numPicBullet") {
59613
+ const childName = localName(child.name);
59614
+ const childOrdinal = (topLevelOrdinals.get(childName) ?? 0) + 1;
59615
+ topLevelOrdinals.set(childName, childOrdinal);
59616
+ const childXmlPath = `/numbering[1]/${childName}[${childOrdinal}]`;
59617
+ if (childName === "numPicBullet") {
59002
59618
  const rawId = readStringAttr(child, "w:numPicBulletId");
59003
59619
  if (rawId) {
59004
- numPicBullets[rawId] = readNumPicBullet(child, rawId, context);
59620
+ numPicBullets[rawId] = readNumPicBullet(child, rawId, context, childXmlPath);
59005
59621
  }
59006
59622
  continue;
59007
59623
  }
59008
- switch (localName(child.name)) {
59624
+ switch (childName) {
59009
59625
  case "abstractNum": {
59010
59626
  const rawId = readStringAttr(child, "w:abstractNumId");
59011
59627
  if (!rawId) {
@@ -59025,7 +59641,7 @@ function parseNumberingXml(xml, context) {
59025
59641
  const numStyleLink = numStyleLinkEl ? readStringAttr(numStyleLinkEl, "w:val") : void 0;
59026
59642
  abstractDefinitions[abstractNumberingId] = {
59027
59643
  abstractNumberingId,
59028
- ...context?.partPath !== void 0 ? { sourceRef: createNumberingSourceRef(context.partPath, "abstractNum", rawId) } : {},
59644
+ ...context?.partPath !== void 0 ? { sourceRef: createNumberingSourceRef(context.partPath, "abstractNum", rawId, childXmlPath) } : {},
59029
59645
  levels: readLevels(child),
59030
59646
  ...nsid ? { nsid } : {},
59031
59647
  ...multiLevelType ? { multiLevelType } : {},
@@ -59045,7 +59661,7 @@ function parseNumberingXml(xml, context) {
59045
59661
  const numberingInstanceId = toCanonicalNumberingInstanceId(rawId);
59046
59662
  instances[numberingInstanceId] = {
59047
59663
  numberingInstanceId,
59048
- ...context?.partPath !== void 0 ? { sourceRef: createNumberingSourceRef(context.partPath, "num", rawId) } : {},
59664
+ ...context?.partPath !== void 0 ? { sourceRef: createNumberingSourceRef(context.partPath, "num", rawId, childXmlPath) } : {},
59049
59665
  abstractNumberingId: toCanonicalAbstractNumberingId(rawAbstractId),
59050
59666
  overrides: readOverrides(child)
59051
59667
  };
@@ -59059,15 +59675,16 @@ function parseNumberingXml(xml, context) {
59059
59675
  ...Object.keys(numPicBullets).length > 0 ? { numPicBullets } : {}
59060
59676
  };
59061
59677
  }
59062
- function createNumberingSourceRef(partPath, element, rawId) {
59678
+ function createNumberingSourceRef(partPath, element, rawId, xmlPath) {
59063
59679
  return {
59064
59680
  sourceId: `part:${partPath}#${element}:${rawId}`,
59065
59681
  partPath,
59066
59682
  storyKind: "numbering",
59067
- element
59683
+ element,
59684
+ ...xmlPath !== void 0 ? { xmlPath } : {}
59068
59685
  };
59069
59686
  }
59070
- function readNumPicBullet(node, numPicBulletId, context) {
59687
+ function readNumPicBullet(node, numPicBulletId, context, xmlPath) {
59071
59688
  let widthEmu;
59072
59689
  let heightEmu;
59073
59690
  let mediaId;
@@ -59130,6 +59747,7 @@ function readNumPicBullet(node, numPicBulletId, context) {
59130
59747
  }
59131
59748
  return {
59132
59749
  numPicBulletId,
59750
+ ...context?.partPath !== void 0 ? { sourceRef: createNumberingSourceRef(context.partPath, "numPicBullet", numPicBulletId, xmlPath) } : {},
59133
59751
  rawXml: serializeXmlElementToString(node),
59134
59752
  ...widthEmu !== void 0 ? { widthEmu } : {},
59135
59753
  ...heightEmu !== void 0 ? { heightEmu } : {},
@@ -63096,7 +63714,11 @@ function parseBodyChild(node, sourceXml, relationshipMap, relationships, mediaPa
63096
63714
  switch (localName(child.name)) {
63097
63715
  case "pPr":
63098
63716
  styleId = readParagraphStyleId(child);
63099
- numbering = readParagraphNumbering(child, sourcePartPath);
63717
+ numbering = readParagraphNumbering(
63718
+ child,
63719
+ sourcePartPath,
63720
+ `${sourceXmlPath}/pPr[${countPriorElementSiblingsByName(node, child) + 1}]`
63721
+ );
63100
63722
  alignment = readParagraphAlignment(child);
63101
63723
  spacing = readParagraphSpacing2(child);
63102
63724
  contextualSpacing = readOptionalOnOffParagraphProperty(child, "contextualSpacing");
@@ -64179,7 +64801,7 @@ function readParagraphStyleId(node) {
64179
64801
  }
64180
64802
  return void 0;
64181
64803
  }
64182
- function readParagraphNumbering(node, sourcePartPath) {
64804
+ function readParagraphNumbering(node, sourcePartPath, sourceXmlPath) {
64183
64805
  const numberingProperties = node.children.find(
64184
64806
  (child) => child.type === "element" && localName(child.name) === "numPr"
64185
64807
  );
@@ -64199,16 +64821,22 @@ function readParagraphNumbering(node, sourcePartPath) {
64199
64821
  }
64200
64822
  return {
64201
64823
  numberingInstanceId: toCanonicalNumberingInstanceId(rawInstanceId),
64202
- sourceRef: createElementSourceRef(sourcePartPath, "numPr", numberingProperties),
64824
+ sourceRef: createElementSourceRef(
64825
+ sourcePartPath,
64826
+ "numPr",
64827
+ numberingProperties,
64828
+ sourceXmlPath !== void 0 ? `${sourceXmlPath}/numPr[${countPriorElementSiblingsByName(node, numberingProperties) + 1}]` : void 0
64829
+ ),
64203
64830
  level: Number.parseInt(rawLevel, 10)
64204
64831
  };
64205
64832
  }
64206
- function createElementSourceRef(partPath, element, node) {
64833
+ function createElementSourceRef(partPath, element, node, xmlPath) {
64207
64834
  return {
64208
64835
  sourceId: `part:${partPath}#${element}:${node.start}`,
64209
64836
  partPath,
64210
64837
  storyKind: storyKindFromPartPath(partPath),
64211
64838
  element,
64839
+ ...xmlPath !== void 0 ? { xmlPath } : {},
64212
64840
  startOffset: node.start,
64213
64841
  endOffset: node.end
64214
64842
  };
@@ -66367,7 +66995,8 @@ function rejectCommand(code, message) {
66367
66995
  };
66368
66996
  }
66369
66997
  function sameResolvedTarget2(left, right) {
66370
- return left.kind === right.kind && left.storyKey === right.storyKey && left.blockPath === right.blockPath && left.leafPath === right.leafPath && left.commandFamily === right.commandFamily && left.editability === right.editability && sameTextTargetStaleCheck(left, right) && left.staleCheck.inlineCount === right.staleCheck.inlineCount && left.staleCheck.targetHash === right.staleCheck.targetHash && left.staleCheck.targetTextLength === right.staleCheck.targetTextLength && left.staleCheck.childCount === right.staleCheck.childCount && left.staleCheck.blockType === right.staleCheck.blockType && left.staleCheck.wordParaId === right.staleCheck.wordParaId && left.staleCheck.wordTextId === right.staleCheck.wordTextId && jsonStable(left.staleCheck.sourceRef) === jsonStable(right.staleCheck.sourceRef) && jsonStable(left.sourceRef) === jsonStable(right.sourceRef) && jsonStable(left.table) === jsonStable(right.table) && jsonStable(left.editableOwner) === jsonStable(right.editableOwner);
66998
+ const textTargetLengthDrift = hasTextTargetLengthDrift(left, right);
66999
+ return left.kind === right.kind && left.storyKey === right.storyKey && left.blockPath === right.blockPath && left.leafPath === right.leafPath && left.commandFamily === right.commandFamily && left.editability === right.editability && sameTextTargetStaleCheck(left, right) && left.staleCheck.inlineCount === right.staleCheck.inlineCount && left.staleCheck.targetHash === right.staleCheck.targetHash && left.staleCheck.targetTextLength === right.staleCheck.targetTextLength && left.staleCheck.childCount === right.staleCheck.childCount && left.staleCheck.blockType === right.staleCheck.blockType && left.staleCheck.wordParaId === right.staleCheck.wordParaId && left.staleCheck.wordTextId === right.staleCheck.wordTextId && (textTargetLengthDrift || jsonStable2(left.staleCheck.sourceRef) === jsonStable2(right.staleCheck.sourceRef)) && (textTargetLengthDrift || jsonStable2(left.sourceRef) === jsonStable2(right.sourceRef)) && jsonStable2(left.table) === jsonStable2(right.table) && jsonStable2(left.editableOwner) === jsonStable2(right.editableOwner);
66371
67000
  }
66372
67001
  function sameTextTargetStaleCheck(left, right) {
66373
67002
  if (left.staleCheck.paragraphTextHash === right.staleCheck.paragraphTextHash && left.staleCheck.paragraphTextLength === right.staleCheck.paragraphTextLength) {
@@ -66375,6 +67004,9 @@ function sameTextTargetStaleCheck(left, right) {
66375
67004
  }
66376
67005
  return left.commandFamily === "text-leaf" && left.staleCheck.paragraphTextLength !== void 0 && right.staleCheck.paragraphTextLength !== void 0 && left.staleCheck.paragraphTextLength !== right.staleCheck.paragraphTextLength;
66377
67006
  }
67007
+ function hasTextTargetLengthDrift(left, right) {
67008
+ return left.commandFamily === "text-leaf" && left.staleCheck.paragraphTextLength !== void 0 && right.staleCheck.paragraphTextLength !== void 0 && left.staleCheck.paragraphTextLength !== right.staleCheck.paragraphTextLength;
67009
+ }
66378
67010
  function locateTargetRange(document2, surface, target) {
66379
67011
  if (target.kind === "hyperlink-text") {
66380
67012
  return locateHyperlinkDisplayRange(document2, surface, target);
@@ -66405,19 +67037,19 @@ function locateTargetRange(document2, surface, target) {
66405
67037
  if (!sdt || sdt.kind !== "sdt_block") return null;
66406
67038
  const paragraph = sdt.children[sdtPath.childIndex];
66407
67039
  if (!paragraph || paragraph.kind !== "paragraph") return null;
66408
- return { from: paragraph.from, to: paragraph.to };
67040
+ return textLeafTargetRange(target, paragraph.from, paragraph.to);
66409
67041
  }
66410
67042
  const paragraphPath = parseTopLevelParagraphPath(target.blockPath);
66411
67043
  if (paragraphPath) {
66412
67044
  const paragraph = surface[paragraphPath.blockIndex];
66413
67045
  if (!paragraph || paragraph.kind !== "paragraph") return null;
66414
- return { from: paragraph.from, to: paragraph.to };
67046
+ return textLeafTargetRange(target, paragraph.from, paragraph.to);
66415
67047
  }
66416
67048
  const secondaryParagraphPath = parseSecondaryStoryParagraphPath(target.blockPath);
66417
67049
  if (secondaryParagraphPath) {
66418
67050
  const paragraph = surface[secondaryParagraphPath.blockIndex];
66419
67051
  if (!paragraph || paragraph.kind !== "paragraph") return null;
66420
- return { from: paragraph.from, to: paragraph.to };
67052
+ return textLeafTargetRange(target, paragraph.from, paragraph.to);
66421
67053
  }
66422
67054
  if (target.kind === "textbox-paragraph-text") {
66423
67055
  return {
@@ -66433,6 +67065,18 @@ function locateTargetRange(document2, surface, target) {
66433
67065
  }
66434
67066
  return null;
66435
67067
  }
67068
+ function textLeafTargetRange(target, from, to) {
67069
+ return {
67070
+ from,
67071
+ to,
67072
+ textTarget: {
67073
+ kind: "text-leaf",
67074
+ blockPath: target.blockPath,
67075
+ paragraphStart: from,
67076
+ paragraphEnd: to
67077
+ }
67078
+ };
67079
+ }
66436
67080
  function locateHyperlinkDisplayRange(document2, surface, target) {
66437
67081
  const canonical = resolveHyperlinkDisplayPath(document2, target.blockPath);
66438
67082
  if (!canonical) return null;
@@ -66654,7 +67298,7 @@ function resolveBlockPathInSurfaceBlocks2(blocks, tokens, tokenIndex, hasVertica
66654
67298
  hasVerticalMergeContinuation || cell.verticalMerge === "continue"
66655
67299
  );
66656
67300
  }
66657
- function jsonStable(value) {
67301
+ function jsonStable2(value) {
66658
67302
  return value === void 0 ? "" : JSON.stringify(value);
66659
67303
  }
66660
67304
 
@@ -66791,20 +67435,20 @@ function tableAnchorCell(table) {
66791
67435
  };
66792
67436
  }
66793
67437
  function sameResolvedTableStructureTarget(left, right) {
66794
- return left.kind === right.kind && left.storyKey === right.storyKey && left.blockPath === right.blockPath && left.leafPath === right.leafPath && left.commandFamily === right.commandFamily && left.editability === right.editability && left.staleCheck.targetHash === right.staleCheck.targetHash && left.staleCheck.childCount === right.staleCheck.childCount && left.staleCheck.blockType === right.staleCheck.blockType && jsonStable2(left.staleCheck.sourceRef) === jsonStable2(right.staleCheck.sourceRef) && jsonStable2(left.sourceRef) === jsonStable2(right.sourceRef) && jsonStable2(left.table) === jsonStable2(right.table);
67438
+ return left.kind === right.kind && left.storyKey === right.storyKey && left.blockPath === right.blockPath && left.leafPath === right.leafPath && left.commandFamily === right.commandFamily && left.editability === right.editability && left.staleCheck.targetHash === right.staleCheck.targetHash && left.staleCheck.childCount === right.staleCheck.childCount && left.staleCheck.blockType === right.staleCheck.blockType && jsonStable3(left.staleCheck.sourceRef) === jsonStable3(right.staleCheck.sourceRef) && jsonStable3(left.sourceRef) === jsonStable3(right.sourceRef) && jsonStable3(left.table) === jsonStable3(right.table);
66795
67439
  }
66796
- function jsonStable2(value) {
66797
- return JSON.stringify(sortJson(value));
67440
+ function jsonStable3(value) {
67441
+ return JSON.stringify(sortJson2(value));
66798
67442
  }
66799
- function sortJson(value) {
67443
+ function sortJson2(value) {
66800
67444
  if (Array.isArray(value)) {
66801
- return value.map(sortJson);
67445
+ return value.map(sortJson2);
66802
67446
  }
66803
67447
  if (value && typeof value === "object") {
66804
67448
  const record = value;
66805
67449
  const sorted = {};
66806
67450
  for (const key of Object.keys(record).sort()) {
66807
- sorted[key] = sortJson(record[key]);
67451
+ sorted[key] = sortJson2(record[key]);
66808
67452
  }
66809
67453
  return sorted;
66810
67454
  }
@@ -66813,6 +67457,8 @@ function sortJson(value) {
66813
67457
 
66814
67458
  // src/runtime/document-runtime.ts
66815
67459
  var CANONICAL_BLOCK_REFS_SYMBOL2 = /* @__PURE__ */ Symbol.for("wre.canonical-block-refs");
67460
+ var LOCAL_TEXT_PATCH_MAX_SHIFTED_SURFACE_NODES = 5e3;
67461
+ var LOCAL_TEXT_PATCH_MAX_SHIFTED_NODES_PER_BLOCK = 256;
66816
67462
  function getLocalTextPatchMetadata(mapping) {
66817
67463
  const metadata = mapping.metadata?.localTextPatch;
66818
67464
  if (!metadata || typeof metadata !== "object") {
@@ -66985,8 +67631,10 @@ function createDocumentRuntime(options) {
66985
67631
  void upgradeMeasurementProvider(layoutEngine, fontLoader);
66986
67632
  let renderKernelRef = null;
66987
67633
  let runtimeRef = null;
67634
+ const normalizedInitialSurfaceViewportRanges = options.initialSurfaceViewportBlockRanges && options.initialSurfaceViewportBlockRanges.length > 0 ? normalizeViewportRanges(options.initialSurfaceViewportBlockRanges) : null;
67635
+ let initialSurfaceViewportBlockRanges = normalizedInitialSurfaceViewportRanges && normalizedInitialSurfaceViewportRanges.length > 0 ? normalizedInitialSurfaceViewportRanges : null;
66988
67636
  let viewportBlockRanges = null;
66989
- let viewportRangesKey = serializeViewportRanges(null);
67637
+ let viewportRangesKey = serializeViewportRanges(viewportBlockRanges);
66990
67638
  let viewportBlocksPerPageEstimate = null;
66991
67639
  const EDITING_CORRIDOR_BLOCK_RADIUS = 8;
66992
67640
  const getRuntimeForLayoutFacet = () => {
@@ -67226,10 +67874,11 @@ function createDocumentRuntime(options) {
67226
67874
  const cachedContextAnalyticsSnapshots = /* @__PURE__ */ new Map();
67227
67875
  let lastEmittedContextAnalyticsSnapshots;
67228
67876
  function getCachedFullSurface(document2, nextActiveStory) {
67229
- const activeStoryKey = storyTargetKey(nextActiveStory);
67230
- if (cachedFullSurface && cachedFullSurface.content === document2.content && cachedFullSurface.subParts === document2.subParts && cachedFullSurface.styles === document2.styles && cachedFullSurface.numbering === document2.numbering && cachedFullSurface.media === document2.media && cachedFullSurface.preservation === document2.preservation && cachedFullSurface.review === document2.review && cachedFullSurface.effectiveMarkupModeProvider === effectiveMarkupModeProvider && cachedFullSurface.activeStoryKey === activeStoryKey) {
67231
- return cachedFullSurface.snapshot;
67877
+ const cached = getReusableCachedFullSurface(document2, nextActiveStory);
67878
+ if (cached) {
67879
+ return cached;
67232
67880
  }
67881
+ const activeStoryKey = storyTargetKey(nextActiveStory);
67233
67882
  const snapshot = createEditorSurfaceSnapshot(document2, state.selection, nextActiveStory, {
67234
67883
  viewportBlockRanges: null,
67235
67884
  editableTargetsByBlockPath: getEditableTargetsByBlockPath(document2),
@@ -67251,6 +67900,13 @@ function createDocumentRuntime(options) {
67251
67900
  };
67252
67901
  return snapshot;
67253
67902
  }
67903
+ function getReusableCachedFullSurface(document2, nextActiveStory) {
67904
+ const activeStoryKey = storyTargetKey(nextActiveStory);
67905
+ if (cachedFullSurface && cachedFullSurface.content === document2.content && cachedFullSurface.subParts === document2.subParts && cachedFullSurface.styles === document2.styles && cachedFullSurface.numbering === document2.numbering && cachedFullSurface.media === document2.media && cachedFullSurface.preservation === document2.preservation && cachedFullSurface.review === document2.review && cachedFullSurface.effectiveMarkupModeProvider === effectiveMarkupModeProvider && cachedFullSurface.activeStoryKey === activeStoryKey) {
67906
+ return cachedFullSurface.snapshot;
67907
+ }
67908
+ return void 0;
67909
+ }
67254
67910
  function getCachedSurface(document2, nextActiveStory, options2 = {}) {
67255
67911
  const activeStoryKey = storyTargetKey(nextActiveStory);
67256
67912
  const surfaceViewportRanges = "viewportBlockRangesOverride" in options2 ? options2.viewportBlockRangesOverride ?? null : viewportBlockRanges;
@@ -67261,12 +67917,20 @@ function createDocumentRuntime(options) {
67261
67917
  }
67262
67918
  const snapshot = createEditorSurfaceSnapshot(document2, state.selection, nextActiveStory, {
67263
67919
  viewportBlockRanges: surfaceViewportRanges,
67264
- editableTargetsByBlockPath: options2.editableTargetsByBlockPathOverride ?? getEditableTargetsByBlockPath(document2),
67920
+ editableTargetsByBlockPath: options2.editableTargetsByBlockPathOverride ?? getEditableTargetsByBlockPathForRanges(
67921
+ document2,
67922
+ activeStoryKey,
67923
+ surfaceViewportRanges
67924
+ ),
67265
67925
  ...effectiveMarkupModeProvider ? { getEffectiveMarkupMode: effectiveMarkupModeProvider } : {}
67266
67926
  });
67267
67927
  recordPerfSample("snapshot.surface");
67268
67928
  incrementInvalidationCounter("runtime.snapshot.surfaceMisses");
67269
- const enrichedSnapshot = options2.enrichCulledPlaceholders === false ? snapshot : enrichCulledPlaceholdersWithHeights(snapshot);
67929
+ const enrichedSnapshot = options2.enrichCulledPlaceholders === false ? snapshot : enrichCulledPlaceholdersWithHeights(
67930
+ snapshot,
67931
+ document2,
67932
+ nextActiveStory
67933
+ );
67270
67934
  if (surfaceViewportRanges === null) {
67271
67935
  cachedFullSurface = {
67272
67936
  content: document2.content,
@@ -67324,7 +67988,7 @@ function createDocumentRuntime(options) {
67324
67988
  }
67325
67989
  return -1;
67326
67990
  }
67327
- function cachePatchedLocalTextSurface(surface) {
67991
+ function cachePatchedLocalTextSurface(surface, fullSurfaceForCache) {
67328
67992
  const activeStoryKey = storyTargetKey(activeStory);
67329
67993
  const rangesKey = serializeViewportRanges(surface.viewportBlockRanges);
67330
67994
  cachedSurface = {
@@ -67340,7 +68004,8 @@ function createDocumentRuntime(options) {
67340
68004
  viewportRangesKey: rangesKey,
67341
68005
  snapshot: surface
67342
68006
  };
67343
- if (surface.viewportBlockRanges === null) {
68007
+ const fullSurface = fullSurfaceForCache ?? (surface.viewportBlockRanges === null ? surface : void 0);
68008
+ if (fullSurface) {
67344
68009
  cachedFullSurface = {
67345
68010
  content: state.document.content,
67346
68011
  subParts: state.document.subParts,
@@ -67351,11 +68016,15 @@ function createDocumentRuntime(options) {
67351
68016
  review: state.document.review,
67352
68017
  effectiveMarkupModeProvider,
67353
68018
  activeStoryKey,
67354
- snapshot: surface
68019
+ snapshot: fullSurface
67355
68020
  };
67356
68021
  }
67357
68022
  cachedSurfaceFingerprint = `${activeStoryKey}|${rangesKey}|${String(state.selection.anchor)}:${String(state.selection.head)}`;
67358
68023
  }
68024
+ function createLocalTextCorridorSurfaceFromFullSurface(fullSurface) {
68025
+ const ranges = getSelectionCorridorViewportRanges(fullSurface);
68026
+ return ranges ? createViewportCulledSurfaceFromFullSurface(fullSurface, ranges) : fullSurface;
68027
+ }
67359
68028
  function tryPatchLocalTextSurface(previousSurface, mapping) {
67360
68029
  const tTotal0 = performance.now();
67361
68030
  try {
@@ -67391,6 +68060,13 @@ function createDocumentRuntime(options) {
67391
68060
  perfCounters.increment("surface.localText.patchMiss");
67392
68061
  return null;
67393
68062
  }
68063
+ const shiftBudget = estimateLocalTextPatchShiftBudget(previousSurface.blocks, blockIndex + 1);
68064
+ perfCounters.increment("surface.localText.shiftedBlocks", shiftBudget.shiftedBlocks);
68065
+ perfCounters.increment("surface.localText.shiftedNodes", shiftBudget.shiftedNodes);
68066
+ if (!shiftBudget.withinBudget) {
68067
+ perfCounters.increment("surface.localText.patchBudgetFallback");
68068
+ return null;
68069
+ }
67394
68070
  const segmentIndex = block.segments.findIndex(
67395
68071
  (segment2) => segment2.kind === "text" && editFrom >= segment2.from && editTo <= segment2.to
67396
68072
  );
@@ -67498,7 +68174,83 @@ function createDocumentRuntime(options) {
67498
68174
  };
67499
68175
  }
67500
68176
  }
67501
- function enrichCulledPlaceholdersWithHeights(snapshot) {
68177
+ function estimateLocalTextPatchShiftBudget(blocks, startIndex) {
68178
+ const shiftedBlocks = Math.max(0, blocks.length - startIndex);
68179
+ let shiftedNodes = 0;
68180
+ for (let index = startIndex; index < blocks.length; index += 1) {
68181
+ const shiftedBlockNodes = countSurfaceShiftNodesUpTo(
68182
+ blocks[index],
68183
+ Math.min(
68184
+ LOCAL_TEXT_PATCH_MAX_SHIFTED_NODES_PER_BLOCK,
68185
+ LOCAL_TEXT_PATCH_MAX_SHIFTED_SURFACE_NODES - shiftedNodes
68186
+ ) + 1
68187
+ );
68188
+ shiftedNodes += shiftedBlockNodes;
68189
+ if (shiftedBlockNodes > LOCAL_TEXT_PATCH_MAX_SHIFTED_NODES_PER_BLOCK) {
68190
+ return {
68191
+ shiftedBlocks,
68192
+ shiftedNodes,
68193
+ withinBudget: false
68194
+ };
68195
+ }
68196
+ if (shiftedNodes > LOCAL_TEXT_PATCH_MAX_SHIFTED_SURFACE_NODES) {
68197
+ return {
68198
+ shiftedBlocks,
68199
+ shiftedNodes,
68200
+ withinBudget: false
68201
+ };
68202
+ }
68203
+ }
68204
+ return {
68205
+ shiftedBlocks,
68206
+ shiftedNodes,
68207
+ withinBudget: true
68208
+ };
68209
+ }
68210
+ function countSurfaceShiftNodesUpTo(block, limit) {
68211
+ if (limit <= 0) {
68212
+ return 1;
68213
+ }
68214
+ switch (block.kind) {
68215
+ case "paragraph":
68216
+ return 1 + block.segments.length;
68217
+ case "opaque_block":
68218
+ return 1;
68219
+ case "sdt_block": {
68220
+ let total = 1;
68221
+ for (const child of block.children) {
68222
+ total += countSurfaceShiftNodesUpTo(child, limit - total);
68223
+ if (total > limit) {
68224
+ return total;
68225
+ }
68226
+ }
68227
+ return total;
68228
+ }
68229
+ case "table": {
68230
+ let total = 1;
68231
+ for (const row2 of block.rows) {
68232
+ total += 1;
68233
+ if (total > limit) {
68234
+ return total;
68235
+ }
68236
+ for (const cell of row2.cells) {
68237
+ total += 1;
68238
+ if (total > limit) {
68239
+ return total;
68240
+ }
68241
+ for (const child of cell.content) {
68242
+ total += countSurfaceShiftNodesUpTo(child, limit - total);
68243
+ if (total > limit) {
68244
+ return total;
68245
+ }
68246
+ }
68247
+ }
68248
+ }
68249
+ return total;
68250
+ }
68251
+ }
68252
+ }
68253
+ function enrichCulledPlaceholdersWithHeights(snapshot, document2, nextActiveStory, fullSurfaceForPlaceholders) {
67502
68254
  let heights;
67503
68255
  try {
67504
68256
  heights = layoutFacet.getBlockHeightsTwips();
@@ -67506,17 +68258,19 @@ function createDocumentRuntime(options) {
67506
68258
  return snapshot;
67507
68259
  }
67508
68260
  if (heights.size === 0) return snapshot;
68261
+ const fullSurface = fullSurfaceForPlaceholders ?? getReusableCachedFullSurface(document2, nextActiveStory);
68262
+ if (!fullSurface) return snapshot;
67509
68263
  let changed = false;
67510
68264
  const enrichedBlocks = snapshot.blocks.map((block) => {
67511
68265
  if (block.kind !== "opaque_block" || block.state !== "placeholder-culled") {
67512
68266
  return block;
67513
68267
  }
67514
- const realBlockIdFromOffset = resolveBlockIdFromRuntimeOffset(
67515
- layoutFacet,
67516
- block.from
68268
+ const realBlock = resolveFullSurfaceBlockForPlaceholder(
68269
+ fullSurface,
68270
+ block
67517
68271
  );
67518
- if (!realBlockIdFromOffset) return block;
67519
- const heightTwips = heights.get(realBlockIdFromOffset);
68272
+ if (!realBlock) return block;
68273
+ const heightTwips = heights.get(realBlock.blockId);
67520
68274
  if (typeof heightTwips !== "number" || heightTwips <= 0) return block;
67521
68275
  changed = true;
67522
68276
  return { ...block, placeholderHeightTwips: heightTwips };
@@ -67524,13 +68278,20 @@ function createDocumentRuntime(options) {
67524
68278
  if (!changed) return snapshot;
67525
68279
  return { ...snapshot, blocks: enrichedBlocks };
67526
68280
  }
67527
- function resolveBlockIdFromRuntimeOffset(facet, runtimeOffset) {
67528
- try {
67529
- const frag = facet.getFragmentForOffset?.(runtimeOffset);
67530
- return frag?.blockId ?? null;
67531
- } catch {
67532
- return null;
68281
+ function resolveFullSurfaceBlockForPlaceholder(fullSurface, placeholder) {
68282
+ const index = parsePlaceholderCulledIndex(placeholder.blockId);
68283
+ if (index !== null) {
68284
+ return fullSurface.blocks[index] ?? null;
67533
68285
  }
68286
+ return fullSurface.blocks.find(
68287
+ (block) => block.from === placeholder.from && block.to === placeholder.to
68288
+ ) ?? null;
68289
+ }
68290
+ function parsePlaceholderCulledIndex(blockId) {
68291
+ const match = /^placeholder-culled-(\d+)$/.exec(blockId);
68292
+ if (!match) return null;
68293
+ const index = Number(match[1]);
68294
+ return Number.isSafeInteger(index) ? index : null;
67534
68295
  }
67535
68296
  function getCachedFieldSnapshot(document2) {
67536
68297
  const blockCount = document2.content.children.length;
@@ -68095,7 +68856,14 @@ function createDocumentRuntime(options) {
68095
68856
  revisionToken: state.revisionToken
68096
68857
  });
68097
68858
  perfCounters.increment("refresh.all");
68098
- const surface = timeFacet("surface", () => getCachedSurface(state.document, activeStory));
68859
+ const firstSurfaceViewportBlockRanges = initialSurfaceViewportBlockRanges;
68860
+ initialSurfaceViewportBlockRanges = null;
68861
+ const surface = timeFacet(
68862
+ "surface",
68863
+ () => firstSurfaceViewportBlockRanges ? getCachedSurface(state.document, activeStory, {
68864
+ viewportBlockRangesOverride: firstSurfaceViewportBlockRanges
68865
+ }) : getCachedSurface(state.document, activeStory)
68866
+ );
68099
68867
  const snapshot = {
68100
68868
  documentId: state.documentId,
68101
68869
  sessionId: state.sessionId,
@@ -68193,8 +68961,10 @@ function createDocumentRuntime(options) {
68193
68961
  if (options2.forceProjection) {
68194
68962
  cachedFullSurface = void 0;
68195
68963
  }
68196
- const newSurface = viewportBlockRanges !== null && options2.forceProjection !== true ? createViewportCulledSurfaceFromFullSurface(
68197
- getCachedFullSurface(state.document, activeStory),
68964
+ const reusableFullSurface = viewportBlockRanges !== null && options2.forceProjection !== true ? getReusableCachedFullSurface(state.document, activeStory) : void 0;
68965
+ const derivedFromFull = viewportBlockRanges !== null && reusableFullSurface !== void 0;
68966
+ const projectedSurface = derivedFromFull ? createViewportCulledSurfaceFromFullSurface(
68967
+ reusableFullSurface,
68198
68968
  viewportBlockRanges
68199
68969
  ) : createEditorSurfaceSnapshot(
68200
68970
  state.document,
@@ -68202,11 +68972,21 @@ function createDocumentRuntime(options) {
68202
68972
  activeStory,
68203
68973
  {
68204
68974
  viewportBlockRanges,
68205
- editableTargetsByBlockPath: getEditableTargetsByBlockPath(state.document),
68975
+ editableTargetsByBlockPath: getEditableTargetsByBlockPathForRanges(
68976
+ state.document,
68977
+ activeStoryKey,
68978
+ viewportBlockRanges
68979
+ ),
68206
68980
  ...effectiveMarkupModeProvider ? { getEffectiveMarkupMode: effectiveMarkupModeProvider } : {}
68207
68981
  }
68208
68982
  );
68209
- if (viewportBlockRanges !== null && options2.forceProjection !== true) {
68983
+ const newSurface = viewportBlockRanges !== null ? enrichCulledPlaceholdersWithHeights(
68984
+ projectedSurface,
68985
+ state.document,
68986
+ activeStory,
68987
+ reusableFullSurface
68988
+ ) : projectedSurface;
68989
+ if (derivedFromFull) {
68210
68990
  perfCounters.increment("runtime.viewport.derivedSurfaceRefreshes");
68211
68991
  } else {
68212
68992
  recordPerfSample("snapshot.surface");
@@ -68750,6 +69530,8 @@ function createDocumentRuntime(options) {
68750
69530
  documentMode: workflowCoordinator.getEffectiveDocumentMode(commandSelection),
68751
69531
  defaultAuthorId: defaultAuthorId ?? void 0,
68752
69532
  renderSnapshot: cachedRenderSnapshot,
69533
+ activeStoryKey: canonicalEditableTargetStoryKey(activeStory),
69534
+ editableTargetCache: editableTargetBlockCache,
68753
69535
  ...resolvedFragmentTextTarget ? { textTarget: resolvedFragmentTextTarget } : {}
68754
69536
  };
68755
69537
  const preSelection = commandSelection;
@@ -69277,12 +70059,86 @@ function createDocumentRuntime(options) {
69277
70059
  }
69278
70060
  },
69279
70061
  applyScopeReplacement(plan) {
70062
+ const resolveEditableTargetHint = (hint) => {
70063
+ if (!hint) return void 0;
70064
+ const activeStoryKey = storyTargetKey(activeStory);
70065
+ if (hint.storyKey !== activeStoryKey) return null;
70066
+ const currentTargets = collectEditableTargetRefs(
70067
+ state.document,
70068
+ editableTargetBlockCache
70069
+ );
70070
+ const target = currentTargets.find(
70071
+ (target2) => target2.storyKey === hint.storyKey && target2.blockPath === hint.blockPath && target2.commandFamily === "text-leaf"
70072
+ );
70073
+ if (!target) return null;
70074
+ const fallbackTextTarget = {
70075
+ kind: "text-leaf",
70076
+ blockPath: target.blockPath,
70077
+ paragraphStart: hint.semanticBlockRange.from,
70078
+ paragraphEnd: hint.semanticBlockRange.to
70079
+ };
70080
+ const resolved = resolveEditableTextTarget({
70081
+ document: state.document,
70082
+ surface: cachedRenderSnapshot.surface?.blocks ?? [],
70083
+ target,
70084
+ activeStoryKey,
70085
+ editableTargetCache: editableTargetBlockCache
70086
+ });
70087
+ if (resolved.kind === "rejected") {
70088
+ return {
70089
+ textTarget: fallbackTextTarget,
70090
+ range: hint.semanticBlockRange
70091
+ };
70092
+ }
70093
+ return {
70094
+ target,
70095
+ textTarget: resolved.textTarget ?? fallbackTextTarget,
70096
+ range: resolved.range
70097
+ };
70098
+ };
70099
+ const mapSemanticStepRangeToEditableTarget = (stepRange, hint, editableRange) => {
70100
+ if (!hint || !editableRange) return stepRange;
70101
+ const semanticFrom = hint.semanticBlockRange.from;
70102
+ const semanticTo = hint.semanticBlockRange.to;
70103
+ const localFrom = Math.max(0, stepRange.from - semanticFrom);
70104
+ const localTo = Math.max(localFrom, stepRange.to - semanticFrom);
70105
+ const semanticLength = Math.max(0, semanticTo - semanticFrom);
70106
+ const editableLength = Math.max(0, editableRange.to - editableRange.from);
70107
+ if (semanticLength === editableLength) {
70108
+ return {
70109
+ from: editableRange.from + localFrom,
70110
+ to: editableRange.from + localTo
70111
+ };
70112
+ }
70113
+ if (stepRange.from === semanticFrom && stepRange.to === semanticTo) {
70114
+ return editableRange;
70115
+ }
70116
+ return stepRange;
70117
+ };
69280
70118
  for (const step of plan.steps) {
69281
70119
  if (step.kind === "text-replace" && step.range && typeof step.text === "string") {
70120
+ const editableTarget = resolveEditableTargetHint(step.editableTargetHint);
70121
+ if (editableTarget === null) {
70122
+ emit2({
70123
+ type: "command_blocked",
70124
+ documentId: state.documentId,
70125
+ command: "applyScopeReplacement",
70126
+ reasons: [{
70127
+ code: "unsupported_surface",
70128
+ message: "Scope replacement editable target no longer resolves."
70129
+ }]
70130
+ });
70131
+ continue;
70132
+ }
70133
+ const dispatchRange = mapSemanticStepRangeToEditableTarget(
70134
+ step.range,
70135
+ step.editableTargetHint,
70136
+ editableTarget?.range
70137
+ );
69282
70138
  const anchor = {
69283
70139
  kind: "range",
69284
- from: step.range.from,
69285
- to: step.range.to,
70140
+ from: dispatchRange.from,
70141
+ to: dispatchRange.to,
69286
70142
  assoc: { start: -1, end: 1 }
69287
70143
  };
69288
70144
  const timestamp = clock();
@@ -69291,6 +70147,8 @@ function createDocumentRuntime(options) {
69291
70147
  {
69292
70148
  type: "text.insert",
69293
70149
  text: step.text,
70150
+ ...editableTarget?.target ? { editableTarget: editableTarget.target } : {},
70151
+ ...editableTarget?.textTarget ? { textTarget: editableTarget.textTarget } : {},
69294
70152
  ...step.formatting ? { formatting: step.formatting } : {},
69295
70153
  origin: createOrigin("api", timestamp)
69296
70154
  },
@@ -69328,10 +70186,28 @@ function createDocumentRuntime(options) {
69328
70186
  emitError(toRuntimeError(error));
69329
70187
  }
69330
70188
  } else if (step.kind === "text-insert-tracked" && step.range && typeof step.text === "string") {
70189
+ const editableTarget = resolveEditableTargetHint(step.editableTargetHint);
70190
+ if (editableTarget === null) {
70191
+ emit2({
70192
+ type: "command_blocked",
70193
+ documentId: state.documentId,
70194
+ command: "applyScopeReplacement",
70195
+ reasons: [{
70196
+ code: "unsupported_surface",
70197
+ message: "Scope replacement editable target no longer resolves."
70198
+ }]
70199
+ });
70200
+ continue;
70201
+ }
70202
+ const dispatchRange = mapSemanticStepRangeToEditableTarget(
70203
+ step.range,
70204
+ step.editableTargetHint,
70205
+ editableTarget?.range
70206
+ );
69331
70207
  const anchor = {
69332
70208
  kind: "range",
69333
- from: step.range.from,
69334
- to: step.range.to,
70209
+ from: dispatchRange.from,
70210
+ to: dispatchRange.to,
69335
70211
  assoc: { start: -1, end: 1 }
69336
70212
  };
69337
70213
  const timestamp = clock();
@@ -69340,6 +70216,8 @@ function createDocumentRuntime(options) {
69340
70216
  {
69341
70217
  type: "text.insert",
69342
70218
  text: step.text,
70219
+ ...editableTarget?.target ? { editableTarget: editableTarget.target } : {},
70220
+ ...editableTarget?.textTarget ? { textTarget: editableTarget.textTarget } : {},
69343
70221
  ...step.formatting ? { formatting: step.formatting } : {},
69344
70222
  origin: createOrigin("api", timestamp)
69345
70223
  },
@@ -69354,10 +70232,28 @@ function createDocumentRuntime(options) {
69354
70232
  emitError(toRuntimeError(error));
69355
70233
  }
69356
70234
  } else if (step.kind === "text-delete-tracked" && step.range && step.range.to > step.range.from) {
70235
+ const editableTarget = resolveEditableTargetHint(step.editableTargetHint);
70236
+ if (editableTarget === null) {
70237
+ emit2({
70238
+ type: "command_blocked",
70239
+ documentId: state.documentId,
70240
+ command: "applyScopeReplacement",
70241
+ reasons: [{
70242
+ code: "unsupported_surface",
70243
+ message: "Scope replacement editable target no longer resolves."
70244
+ }]
70245
+ });
70246
+ continue;
70247
+ }
70248
+ const dispatchRange = mapSemanticStepRangeToEditableTarget(
70249
+ step.range,
70250
+ step.editableTargetHint,
70251
+ editableTarget?.range
70252
+ );
69357
70253
  const anchor = {
69358
70254
  kind: "range",
69359
- from: step.range.from,
69360
- to: step.range.to,
70255
+ from: dispatchRange.from,
70256
+ to: dispatchRange.to,
69361
70257
  assoc: { start: -1, end: 1 }
69362
70258
  };
69363
70259
  const timestamp = clock();
@@ -69365,6 +70261,8 @@ function createDocumentRuntime(options) {
69365
70261
  applyTextCommandInActiveStory(
69366
70262
  {
69367
70263
  type: "text.delete-forward",
70264
+ ...editableTarget?.target ? { editableTarget: editableTarget.target } : {},
70265
+ ...editableTarget?.textTarget ? { textTarget: editableTarget.textTarget } : {},
69368
70266
  origin: createOrigin("api", timestamp)
69369
70267
  },
69370
70268
  {
@@ -70885,9 +71783,13 @@ function createDocumentRuntime(options) {
70885
71783
  applyViewportRanges(getSelectionCorridorViewportRanges(cachedRenderSnapshot.surface));
70886
71784
  }
70887
71785
  const tValidation0 = performance.now();
70888
- const patchedLocalTextSurface = useLocalTextCommitSnapshot ? tryPatchLocalTextSurface(cachedRenderSnapshot.surface, transaction.mapping) : null;
71786
+ const patchedFullLocalTextSurface = useLocalTextCommitSnapshot ? tryPatchLocalTextSurface(cachedRenderSnapshot.surface, transaction.mapping) : null;
71787
+ const patchedLocalTextSurface = patchedFullLocalTextSurface ? createLocalTextCorridorSurfaceFromFullSurface(patchedFullLocalTextSurface) : null;
70889
71788
  if (patchedLocalTextSurface) {
70890
- cachePatchedLocalTextSurface(patchedLocalTextSurface);
71789
+ cachePatchedLocalTextSurface(
71790
+ patchedLocalTextSurface,
71791
+ patchedFullLocalTextSurface ?? void 0
71792
+ );
70891
71793
  perfCounters.increment("commit.localTextValidation.storySizeOnly");
70892
71794
  }
70893
71795
  const localTextViewportRanges = useLocalTextCommitSnapshot && !patchedLocalTextSurface ? getSelectionCorridorViewportRanges(cachedRenderSnapshot.surface) : void 0;
@@ -70927,7 +71829,8 @@ function createDocumentRuntime(options) {
70927
71829
  cachedRenderSnapshot = useLocalTextCommitSnapshot ? refreshLocalTextCommitSnapshot(surfaceForValidation, transaction.mapping) : refreshRenderSnapshot();
70928
71830
  perfCounters.increment("commit.refresh.us", Math.round((performance.now() - tRefresh0) * 1e3));
70929
71831
  const tNotify0 = performance.now();
70930
- deferNextContextAnalyticsEmit = useLocalTextCommitSnapshot;
71832
+ const shouldDeferContextAnalyticsEmit = transaction.markDirty && transaction.mapping.steps.length > 0;
71833
+ deferNextContextAnalyticsEmit = shouldDeferContextAnalyticsEmit;
70931
71834
  try {
70932
71835
  notify(previous, state, {
70933
71836
  ...transaction,
@@ -71228,6 +72131,8 @@ function createDocumentRuntime(options) {
71228
72131
  documentMode: textOptions.documentModeOverride ?? workflowCoordinator.getEffectiveDocumentMode(selection),
71229
72132
  defaultAuthorId: defaultAuthorId ?? void 0,
71230
72133
  renderSnapshot: cachedRenderSnapshot,
72134
+ activeStoryKey: canonicalEditableTargetStoryKey(activeStory),
72135
+ editableTargetCache: editableTargetBlockCache,
71231
72136
  activeStorySize: cachedRenderSnapshot.surface?.storySize,
71232
72137
  textTarget,
71233
72138
  rejectTargetlessTableStructureInsert: true
@@ -71528,7 +72433,9 @@ function createDocumentRuntime(options) {
71528
72433
  timestamp: clock(),
71529
72434
  documentMode: workflowCoordinator.getEffectiveDocumentMode(state.selection),
71530
72435
  defaultAuthorId: defaultAuthorId ?? void 0,
71531
- renderSnapshot: cachedRenderSnapshot
72436
+ renderSnapshot: cachedRenderSnapshot,
72437
+ activeStoryKey: canonicalEditableTargetStoryKey(activeStory),
72438
+ editableTargetCache: editableTargetBlockCache
71532
72439
  };
71533
72440
  try {
71534
72441
  const transaction = executeEditorCommand(
@@ -89321,6 +90228,12 @@ function openDocxSync(opts) {
89321
90228
  return loadDocxSessionSync(opts);
89322
90229
  }
89323
90230
 
90231
+ // src/api/mounted-surface-residency.ts
90232
+ var MOUNTED_SURFACE_VIEWPORT_BLOCK_THRESHOLD = 250;
90233
+ function shouldUseMountedSurfaceViewportCulling(totalBlockCount) {
90234
+ return totalBlockCount > MOUNTED_SURFACE_VIEWPORT_BLOCK_THRESHOLD;
90235
+ }
90236
+
89324
90237
  // src/ui/browser-export.ts
89325
90238
  function withExportDelivery(result, delivery) {
89326
90239
  return {
@@ -89891,6 +90804,9 @@ function createRuntime(args, handlers = {}) {
89891
90804
  )
89892
90805
  ));
89893
90806
  const runtimeSessionState = snapshotExportResolution?.barrier ? applySessionExportBarrier(initialSessionState, snapshotExportResolution.barrier) : initialSessionState;
90807
+ const initialSurfaceViewportBlockRanges = getMountedInitialSurfaceViewportBlockRanges(
90808
+ runtimeSessionState
90809
+ );
89894
90810
  const baseRuntime = createDocumentRuntime({
89895
90811
  documentId: args.documentId,
89896
90812
  initialSessionState: runtimeSessionState,
@@ -89902,6 +90818,7 @@ function createRuntime(args, handlers = {}) {
89902
90818
  fatalError: docxSession?.fatalError,
89903
90819
  protectionSnapshot: docxSession?.protectionSnapshot,
89904
90820
  ...args.source.preloadedLaycacheGraph ? { seedLayoutCache: args.source.preloadedLaycacheGraph } : {},
90821
+ ...initialSurfaceViewportBlockRanges ? { initialSurfaceViewportBlockRanges } : {},
89905
90822
  exportDocx: async (sessionState, options) => {
89906
90823
  if (docxSession) {
89907
90824
  return docxSession.exportDocx(sessionState, options);
@@ -89984,6 +90901,18 @@ function createRuntime(args, handlers = {}) {
89984
90901
  });
89985
90902
  return runtime;
89986
90903
  }
90904
+ function getMountedInitialSurfaceViewportBlockRanges(sessionState) {
90905
+ const blockCount = sessionState.canonicalDocument.content.children.length;
90906
+ if (!shouldUseMountedSurfaceViewportCulling(blockCount)) {
90907
+ return void 0;
90908
+ }
90909
+ return Object.freeze([
90910
+ Object.freeze({
90911
+ start: 0,
90912
+ end: MOUNTED_SURFACE_VIEWPORT_BLOCK_THRESHOLD
90913
+ })
90914
+ ]);
90915
+ }
89987
90916
  function createLoadingSnapshot(documentId, readOnly, sourceLabel) {
89988
90917
  return {
89989
90918
  documentId,
@@ -106337,26 +107266,42 @@ function resolveTopBarCommentAvailability(input) {
106337
107266
 
106338
107267
  // src/ui-tailwind/review-workspace/use-status-bar-page-facts.ts
106339
107268
  var import_react39 = require("react");
106340
- function useStatusBarPageFacts(options) {
106341
- const { layoutFacet, selectionPosition, activeStory, renderFrameRevision } = options;
106342
- return (0, import_react39.useMemo)(() => {
106343
- const facet = layoutFacet;
106344
- if (!facet) {
106345
- return {
106346
- displayPageNumber: null,
106347
- pageCount: null,
106348
- measurementFidelity: void 0
106349
- };
106350
- }
106351
- const pageRef = facet.getPageForOffset(selectionPosition, activeStory);
106352
- const displayPageNumber = pageRef !== null && typeof pageRef.pageIndex === "number" ? facet.getDisplayPageNumber(pageRef.pageIndex) ?? pageRef.pageIndex + 1 : null;
106353
- const pageCount = facet.getPageCount();
107269
+ function resolveStatusBarPageFacts(options) {
107270
+ const { layoutFacet: facet, selectionPosition, activeStory, viewportPageIndexRange } = options;
107271
+ if (!facet) {
106354
107272
  return {
106355
- displayPageNumber,
106356
- pageCount,
106357
- measurementFidelity: facet.getMeasurementFidelity()
107273
+ displayPageNumber: null,
107274
+ pageCount: null,
107275
+ measurementFidelity: void 0
106358
107276
  };
106359
- }, [layoutFacet, selectionPosition, activeStory, renderFrameRevision]);
107277
+ }
107278
+ const pageCount = facet.getPageCount();
107279
+ const viewportPageIndex = viewportPageIndexRange && viewportPageIndexRange.start >= 0 && viewportPageIndexRange.start < pageCount ? viewportPageIndexRange.start : null;
107280
+ const pageRef = viewportPageIndex !== null ? { pageIndex: viewportPageIndex } : facet.getPageForOffset(selectionPosition, activeStory);
107281
+ const displayPageNumber = normalizeStatusDisplayPageNumber(
107282
+ pageRef !== null && typeof pageRef.pageIndex === "number" ? facet.getDisplayPageNumber(pageRef.pageIndex) : null,
107283
+ pageRef !== null && typeof pageRef.pageIndex === "number" ? pageRef.pageIndex : null
107284
+ );
107285
+ return {
107286
+ displayPageNumber,
107287
+ pageCount,
107288
+ measurementFidelity: facet.getMeasurementFidelity()
107289
+ };
107290
+ }
107291
+ function normalizeStatusDisplayPageNumber(displayPageNumber, pageIndex) {
107292
+ if (pageIndex === null) return null;
107293
+ return typeof displayPageNumber === "number" && displayPageNumber > 0 ? displayPageNumber : pageIndex + 1;
107294
+ }
107295
+ function useStatusBarPageFacts(options) {
107296
+ const { layoutFacet, selectionPosition, activeStory, renderFrameRevision, viewportPageIndexRange } = options;
107297
+ return (0, import_react39.useMemo)(() => {
107298
+ return resolveStatusBarPageFacts({
107299
+ layoutFacet,
107300
+ selectionPosition,
107301
+ activeStory,
107302
+ viewportPageIndexRange
107303
+ });
107304
+ }, [layoutFacet, selectionPosition, activeStory, viewportPageIndexRange, renderFrameRevision]);
106360
107305
  }
106361
107306
 
106362
107307
  // src/ui-tailwind/review-workspace/use-grabbed-segment-offsets.ts
@@ -107364,7 +108309,7 @@ function pageMarkersEqual(a, b) {
107364
108309
  }
107365
108310
  return true;
107366
108311
  }
107367
- function useGeometryVisiblePageIndexRange(input) {
108312
+ function useGeometryVisiblePageIndexRanges(input) {
107368
108313
  const {
107369
108314
  scrollRoot,
107370
108315
  geometryFacet,
@@ -107374,10 +108319,12 @@ function useGeometryVisiblePageIndexRange(input) {
107374
108319
  renderFrameRevision,
107375
108320
  viewportScale
107376
108321
  } = input;
107377
- const [range, setRange] = (0, import_react46.useState)(null);
108322
+ const [ranges, setRanges] = (0, import_react46.useState)({ visiblePageIndexRange: null, viewportPageIndexRange: null });
107378
108323
  (0, import_react46.useEffect)(() => {
107379
108324
  if (!scrollRoot || !geometryFacet) {
107380
- setRange((prev) => prev === null ? prev : null);
108325
+ setRanges(
108326
+ (prev) => prev.visiblePageIndexRange === null && prev.viewportPageIndexRange === null ? prev : { visiblePageIndexRange: null, viewportPageIndexRange: null }
108327
+ );
107381
108328
  return void 0;
107382
108329
  }
107383
108330
  const runtime = scrollRoot.ownerDocument?.defaultView;
@@ -107387,7 +108334,7 @@ function useGeometryVisiblePageIndexRange(input) {
107387
108334
  if (disposed) return;
107388
108335
  const pageCount = layoutFacet?.getPageCount() ?? pageMarkerCount;
107389
108336
  const scale = typeof viewportScale === "number" && Number.isFinite(viewportScale) && viewportScale > 0 ? viewportScale : 1;
107390
- const next = resolveVisiblePageIndexRangeFromViewport({
108337
+ const nextVisible = resolveVisiblePageIndexRangeFromViewport({
107391
108338
  pageCount,
107392
108339
  viewportTopPx: scrollRoot.scrollTop / scale,
107393
108340
  viewportHeightPx: scrollRoot.clientHeight / scale,
@@ -107397,7 +108344,22 @@ function useGeometryVisiblePageIndexRange(input) {
107397
108344
  return page ? page.frame : null;
107398
108345
  }
107399
108346
  });
107400
- setRange((prev) => pageRangeEqual(prev, next) ? prev : next);
108347
+ const nextViewport = resolveVisiblePageIndexRangeFromViewport({
108348
+ pageCount,
108349
+ viewportTopPx: scrollRoot.scrollTop / scale,
108350
+ viewportHeightPx: scrollRoot.clientHeight / scale,
108351
+ overscanPages: 0,
108352
+ getPageFrame: (pageIndex) => {
108353
+ const page = geometryFacet.getPage(pageIndex);
108354
+ return page ? page.frame : null;
108355
+ }
108356
+ });
108357
+ setRanges(
108358
+ (prev) => pageRangeEqual(prev.visiblePageIndexRange, nextVisible) && pageRangeEqual(prev.viewportPageIndexRange, nextViewport) ? prev : {
108359
+ visiblePageIndexRange: nextVisible,
108360
+ viewportPageIndexRange: nextViewport
108361
+ }
108362
+ );
107401
108363
  };
107402
108364
  const schedule = () => {
107403
108365
  if (disposed || rafHandle !== null) return;
@@ -107434,7 +108396,7 @@ function useGeometryVisiblePageIndexRange(input) {
107434
108396
  scrollRoot,
107435
108397
  viewportScale
107436
108398
  ]);
107437
- return range;
108399
+ return ranges;
107438
108400
  }
107439
108401
  function shouldUseCompatibilityPageMarkerScan(input) {
107440
108402
  return !input.geometryFacet || !input.layoutFacet;
@@ -107535,7 +108497,11 @@ function usePageMarkers(options) {
107535
108497
  pageMarkers,
107536
108498
  overscanPages
107537
108499
  });
107538
- const geometryVisiblePageIndexRange = useGeometryVisiblePageIndexRange({
108500
+ const markerViewportPageIndexRange = useVisiblePageIndexRange({
108501
+ pageMarkers,
108502
+ overscanPages: 0
108503
+ });
108504
+ const geometryPageIndexRanges = useGeometryVisiblePageIndexRanges({
107539
108505
  scrollRoot: pageStackScrollRoot,
107540
108506
  geometryFacet,
107541
108507
  layoutFacet,
@@ -107544,7 +108510,8 @@ function usePageMarkers(options) {
107544
108510
  renderFrameRevision,
107545
108511
  viewportScale
107546
108512
  });
107547
- const visiblePageIndexRange = geometryVisiblePageIndexRange ?? markerVisiblePageIndexRange;
108513
+ const visiblePageIndexRange = geometryPageIndexRanges.visiblePageIndexRange ?? markerVisiblePageIndexRange;
108514
+ const viewportPageIndexRange = geometryPageIndexRanges.viewportPageIndexRange ?? markerViewportPageIndexRange;
107548
108515
  const visibleBlockRangesFromPageOffsets = (0, import_react46.useMemo)(
107549
108516
  () => visiblePageIndexRange && layoutFacet ? resolveVisibleBlockRangesFromPageOffsets({
107550
108517
  blocks: snapshot.surface?.blocks ?? [],
@@ -107580,9 +108547,11 @@ function usePageMarkers(options) {
107580
108547
  ]
107581
108548
  );
107582
108549
  const visibleBlockRanges = visibleBlockRangesFromPageOffsets ?? visibleBlockRangesFromPageRange ?? markerVisibleBlockRanges;
108550
+ const totalBlockCount = snapshot.surface?.blocks.length ?? 0;
108551
+ const shouldCullSurface = shouldUseMountedSurfaceViewportCulling(totalBlockCount);
107583
108552
  const visibleRangesKey = (0, import_react46.useMemo)(
107584
- () => visibleBlockRanges.map((r) => `${r.start}:${r.end}`).join("|"),
107585
- [visibleBlockRanges]
108553
+ () => shouldCullSurface ? visibleBlockRanges.map((r) => `${r.start}:${r.end}`).join("|") : "full",
108554
+ [shouldCullSurface, visibleBlockRanges]
107586
108555
  );
107587
108556
  (0, import_react46.useEffect)(() => {
107588
108557
  if (!layoutFacet) return;
@@ -107591,13 +108560,19 @@ function usePageMarkers(options) {
107591
108560
  layoutFacet.requestViewportRefresh();
107592
108561
  return;
107593
108562
  }
108563
+ if (!shouldCullSurface) {
108564
+ layoutFacet.setVisibleBlockRanges([]);
108565
+ layoutFacet.requestViewportRefresh();
108566
+ return;
108567
+ }
107594
108568
  layoutFacet.setVisibleBlockRanges(visibleBlockRanges);
107595
108569
  layoutFacet.requestViewportRefresh();
107596
- }, [layoutFacet, visibleRangesKey]);
108570
+ }, [layoutFacet, shouldCullSurface, visibleRangesKey]);
107597
108571
  return {
107598
108572
  pageMarkers,
107599
108573
  visibleBlockRanges,
107600
- visiblePageIndexRange: VIEWPORT_CULLING_ENABLED ? visiblePageIndexRange : null
108574
+ visiblePageIndexRange: VIEWPORT_CULLING_ENABLED ? visiblePageIndexRange : null,
108575
+ viewportPageIndexRange: VIEWPORT_CULLING_ENABLED ? viewportPageIndexRange : null
107601
108576
  };
107602
108577
  }
107603
108578
 
@@ -110024,11 +110999,20 @@ function TwReviewWorkspace(inputProps) {
110024
110999
  selectionToolbarRootRef
110025
111000
  });
110026
111001
  const activePage = props.documentNavigation?.pages[props.documentNavigation.activePageIndex] ?? null;
111002
+ const { visiblePageIndexRange, viewportPageIndexRange } = usePageMarkers({
111003
+ pageStackScrollRoot,
111004
+ snapshot,
111005
+ layoutFacet: props.layoutFacet,
111006
+ geometryFacet: props.geometryFacet,
111007
+ renderFrameRevision,
111008
+ viewportScale: zoomScale
111009
+ });
110027
111010
  const grabbedSegmentOffsets = useGrabbedSegmentOffsets(snapshot);
110028
111011
  const statusBarPageFacts = useStatusBarPageFacts({
110029
111012
  layoutFacet: props.layoutFacet,
110030
111013
  selectionPosition,
110031
111014
  activeStory: snapshot.activeStory,
111015
+ viewportPageIndexRange,
110032
111016
  renderFrameRevision
110033
111017
  });
110034
111018
  const hidePageBorderForActiveEditing = isPageWorkspace && snapshot.activeStory.kind === "main" && shouldHidePageBorderForSelection(viewState.selection);
@@ -110054,14 +111038,6 @@ function TwReviewWorkspace(inputProps) {
110054
111038
  });
110055
111039
  const suppressFloatingToolDuringEditorInput = viewState.editorRole === "editor" && viewState.selection.isCollapsed;
110056
111040
  const shouldRenderFloatingSelectionTool = chromeVisibility.selectionOverlay && gatedSelectionTool && !suppressFloatingToolDuringEditorInput && shouldRenderSelectionToolKind(scopedChromePolicy, gatedSelectionTool.kind);
110057
- const { visiblePageIndexRange } = usePageMarkers({
110058
- pageStackScrollRoot,
110059
- snapshot,
110060
- layoutFacet: props.layoutFacet,
110061
- geometryFacet: props.geometryFacet,
110062
- renderFrameRevision,
110063
- viewportScale: zoomScale
110064
- });
110065
111041
  const { dismissSelectionToolbar, runWithSelectionToolbarDismiss } = useWorkspaceSideEffects({
110066
111042
  layoutFacet: props.layoutFacet,
110067
111043
  activeParagraphLayout,
@@ -127403,6 +128379,17 @@ var hyperlinkDestinationEditMetadata = actionMethodMetadata(
127403
128379
  expectedDelta: "hyperlink destination changes"
127404
128380
  }
127405
128381
  );
128382
+ var hyperlinkTextEditMetadata = actionMethodMetadata(
128383
+ "hyperlinkTextEdit",
128384
+ "mutate",
128385
+ "actions-link-bookmark",
128386
+ "Edit supported hyperlink display text through the L07 text-leaf command target; broad carrier scope rewrite remains refused.",
128387
+ {
128388
+ uiVisible: true,
128389
+ expectsUxResponse: "inline-change",
128390
+ expectedDelta: "hyperlink display text changes"
128391
+ }
128392
+ );
127406
128393
  var listOperationMetadata = actionMethodMetadata(
127407
128394
  "listOperation",
127408
128395
  "mutate",
@@ -127462,6 +128449,7 @@ var ACTION_METHODS = Object.freeze([
127462
128449
  "tocRefresh",
127463
128450
  "bookmarkEdit",
127464
128451
  "hyperlinkDestinationEdit",
128452
+ "hyperlinkTextEdit",
127465
128453
  "listOperation",
127466
128454
  "tableFragment",
127467
128455
  "tableSelection",
@@ -127471,6 +128459,9 @@ var DEFAULT_LOCATE_LIMIT = 20;
127471
128459
  var DEFAULT_REWRITE_ALL_LIMIT = 10;
127472
128460
  var DEFAULT_TABLE_TEXT_SCOPE_LIMIT = 3;
127473
128461
  var DEFAULT_PLAN_STEP_LIMIT = 20;
128462
+ function documentContentHash(runtime) {
128463
+ return JSON.stringify(runtime.getCanonicalDocument().content);
128464
+ }
127474
128465
  function createActionsFamily(runtime) {
127475
128466
  const category = {
127476
128467
  discover(input) {
@@ -127717,6 +128708,14 @@ function createActionsFamily(runtime) {
127717
128708
  ...readback ? { text: readback.text, excerpt: excerpt(readback.text) } : {}
127718
128709
  };
127719
128710
  }
128711
+ if (resolved.target.kind === "editable-text") {
128712
+ return {
128713
+ status: "read",
128714
+ target: summarizeTarget(resolved.target),
128715
+ text: resolved.target.readback.text,
128716
+ excerpt: excerpt(resolved.target.readback.text)
128717
+ };
128718
+ }
127720
128719
  const text = resolved.target.scope.content.text;
127721
128720
  return {
127722
128721
  status: "read",
@@ -127797,6 +128796,31 @@ function createActionsFamily(runtime) {
127797
128796
  input
127798
128797
  );
127799
128798
  },
128799
+ hyperlinkTextEdit(input) {
128800
+ if (input.text === void 0) {
128801
+ return blockedApply(
128802
+ "actions:hyperlink-text-edit:text-required",
128803
+ "input",
128804
+ "Hyperlink display text edit actions require a text value.",
128805
+ "Retry with a text string."
128806
+ );
128807
+ }
128808
+ const resolved = resolveTarget(runtime, input.target);
128809
+ if (!resolved.ok) return blockedApplyFromResolution(resolved);
128810
+ if (resolved.target.kind !== "editable-text" || resolved.target.targetKind !== "hyperlink-text") {
128811
+ return blockedApply(
128812
+ "actions:hyperlink-text-edit:hyperlink-text-handle-required",
128813
+ "unsupported",
128814
+ "Hyperlink display text edits require an exact hyperlink-text actionHandle.",
128815
+ "Call ai.actions.locateAll and retry with a returned scope-command:text-leaf actionHandle."
128816
+ );
128817
+ }
128818
+ return applyEditableTextRewrite(runtime, resolved.target, {
128819
+ text: input.text,
128820
+ actorId: input.actorId,
128821
+ origin: input.origin
128822
+ });
128823
+ },
127800
128824
  listOperation(input) {
127801
128825
  return applyListOperation(runtime, input);
127802
128826
  },
@@ -127845,6 +128869,7 @@ function runPlan(runtime, input) {
127845
128869
  for (const step of input.steps) {
127846
128870
  const result = runPlanStep(runtime, mode, step, input);
127847
128871
  results.push(result);
128872
+ if (isSuspectMutationStep(result)) break;
127848
128873
  if (stopOnBlocker && (result.status === "blocked" || result.status === "unsupported")) {
127849
128874
  break;
127850
128875
  }
@@ -127909,24 +128934,27 @@ function runPlanStep(runtime, mode, step, plan) {
127909
128934
  ...before.readback ? { beforeReadback: before.readback } : {}
127910
128935
  };
127911
128936
  }
128937
+ const documentHashBeforeApply = documentContentHash(runtime);
127912
128938
  const applied = applyPlanStep(runtime, step, plan);
128939
+ const documentHashAfterApply = documentContentHash(runtime);
128940
+ const projectedApply = !applied.applied && documentHashAfterApply !== documentHashBeforeApply ? withSuspectMutationApplyResult(applied, step.id, applied.target ?? before.target) : applied;
127913
128941
  const after = step.kind === "flag" ? before : step.target ? readPlanTarget(runtime, step.target) : before;
127914
128942
  return {
127915
128943
  id: step.id,
127916
128944
  kind: step.kind,
127917
- status: applied.status === "unsupported" ? "unsupported" : applied.applied ? "applied" : "blocked",
127918
- applied: applied.applied,
127919
- changed: applied.changed,
127920
- ...applied.target ?? before.target ? { target: applied.target ?? before.target } : {},
128945
+ status: projectedApply.status === "unsupported" ? "unsupported" : projectedApply.applied ? "applied" : "blocked",
128946
+ applied: projectedApply.applied,
128947
+ changed: projectedApply.changed,
128948
+ ...projectedApply.target ?? before.target ? { target: projectedApply.target ?? before.target } : {},
127921
128949
  ...before.tableAction ? { tableAction: before.tableAction } : {},
127922
128950
  ...before.readback ? { beforeReadback: before.readback } : {},
127923
128951
  ...after.ok && after.readback ? { afterReadback: after.readback } : {},
127924
- ...applied.proposalId ? { proposalId: applied.proposalId } : {},
127925
- ...applied.posture ? { posture: applied.posture } : {},
127926
- ...applied.blockers ? { blockers: applied.blockers } : {},
127927
- ...applied.blockerDetails ? { blockerDetails: applied.blockerDetails } : {},
127928
- ...applied.auditReference ? { auditReference: applied.auditReference } : {},
127929
- ...applied.commandReference ? { commandReference: applied.commandReference } : {}
128952
+ ...projectedApply.proposalId ? { proposalId: projectedApply.proposalId } : {},
128953
+ ...projectedApply.posture ? { posture: projectedApply.posture } : {},
128954
+ ...projectedApply.blockers ? { blockers: projectedApply.blockers } : {},
128955
+ ...projectedApply.blockerDetails ? { blockerDetails: projectedApply.blockerDetails } : {},
128956
+ ...projectedApply.auditReference ? { auditReference: projectedApply.auditReference } : {},
128957
+ ...projectedApply.commandReference ? { commandReference: projectedApply.commandReference } : {}
127930
128958
  };
127931
128959
  }
127932
128960
  function runPlanTableActionStep(runtime, mode, step, plan) {
@@ -128054,6 +129082,23 @@ function locateAll(runtime, input) {
128054
129082
  isEmpty: text.trim().length === 0
128055
129083
  });
128056
129084
  }
129085
+ if (matches.length < limit && !input.kind) {
129086
+ for (const scope of scopes) {
129087
+ if (matches.length >= limit) break;
129088
+ for (const action of editableTextActionsForScope(runtime, scope.handle)) {
129089
+ if (matches.length >= limit) break;
129090
+ if (!textMatches(action.readback.text, input.query, input.matchCase)) continue;
129091
+ matches.push({
129092
+ kind: action.targetKind,
129093
+ text: action.readback.text,
129094
+ excerpt: excerpt(action.readback.text),
129095
+ actionHandle: action.actionHandle,
129096
+ readback: action.readback,
129097
+ isEmpty: action.readback.isEmpty
129098
+ });
129099
+ }
129100
+ }
129101
+ }
128057
129102
  if (matches.length < limit && shouldScanTableText) {
128058
129103
  const tableTextScopeLimit = Math.max(
128059
129104
  0,
@@ -128088,23 +129133,27 @@ function locateAll(runtime, input) {
128088
129133
  function resolveTarget(runtime, target) {
128089
129134
  if ("actionHandle" in target) {
128090
129135
  const action = findTableAction(runtime, target.actionHandle);
128091
- if (!action) {
128092
- return blockedResolution(
128093
- `actions:target:action-handle-not-found:${target.actionHandle}`,
128094
- "unresolved-target",
128095
- "No current table text action matches the supplied actionHandle.",
128096
- "Call ai.actions.locateAll or ai.listTableActions again and retry with a fresh actionHandle."
128097
- );
129136
+ if (action) {
129137
+ if (action.family !== "table-text") {
129138
+ return blockedResolution(
129139
+ `actions:target:action-handle-not-text:${target.actionHandle}`,
129140
+ "unsupported",
129141
+ "This actionHandle is not a table text action.",
129142
+ "Use table structure handles with ai.applyTableAction, or use a table text actionHandle for rewrite."
129143
+ );
129144
+ }
129145
+ return { ok: true, target: { kind: "table-text", action } };
128098
129146
  }
128099
- if (action.family !== "table-text") {
128100
- return blockedResolution(
128101
- `actions:target:action-handle-not-text:${target.actionHandle}`,
128102
- "unsupported",
128103
- "This actionHandle is not a table text action.",
128104
- "Use table structure handles with ai.applyTableAction, or use a table text actionHandle for rewrite."
128105
- );
129147
+ const editableTextAction = findEditableTextAction(runtime, target.actionHandle);
129148
+ if (editableTextAction) {
129149
+ return { ok: true, target: editableTextAction };
128106
129150
  }
128107
- return { ok: true, target: { kind: "table-text", action } };
129151
+ return blockedResolution(
129152
+ `actions:target:action-handle-not-found:${target.actionHandle}`,
129153
+ "unresolved-target",
129154
+ "No current table text or editable text action matches the supplied actionHandle.",
129155
+ "Call ai.actions.locateAll again and retry with a fresh actionHandle."
129156
+ );
128108
129157
  }
128109
129158
  if ("handle" in target) {
128110
129159
  const compiled = createScopeCompilerService(runtime).compileScopeById(target.handle.scopeId);
@@ -128189,7 +129238,21 @@ function applyRewrite(runtime, target, input) {
128189
129238
  ...result2.afterReadback ? { afterReadback: result2.afterReadback } : {}
128190
129239
  };
128191
129240
  }
129241
+ if (target.kind === "editable-text") {
129242
+ return applyEditableTextRewrite(runtime, target, input);
129243
+ }
129244
+ const rewriteBlocker = scopeRewriteCapabilityBlocker(target.scope);
129245
+ if (rewriteBlocker) {
129246
+ return blockedApply(
129247
+ rewriteBlocker.code,
129248
+ rewriteBlocker.category,
129249
+ rewriteBlocker.message,
129250
+ rewriteBlocker.nextStep,
129251
+ [rewriteBlocker]
129252
+ );
129253
+ }
128192
129254
  const beforeText = target.scope.content.text;
129255
+ const documentHashBeforeApply = documentContentHash(runtime);
128193
129256
  const result = createReplacementFamily(runtime).applyReplacementScope({
128194
129257
  targetScopeId: target.handle.scopeId,
128195
129258
  operation: "replace",
@@ -128201,7 +129264,22 @@ function applyRewrite(runtime, target, input) {
128201
129264
  ...input.origin ? { origin: input.origin } : {},
128202
129265
  ...input.proposalId ? { proposalId: input.proposalId } : {}
128203
129266
  });
128204
- return projectRewriteScopeResult(runtime, result, target, beforeText, input.text);
129267
+ const documentMutated = documentContentHash(runtime) !== documentHashBeforeApply;
129268
+ if (!result.applied) {
129269
+ return documentMutated ? withSuspectMutationApplyResult(
129270
+ projectApplyResult(result, target),
129271
+ target.handle.scopeId,
129272
+ summarizeTarget(target)
129273
+ ) : projectApplyResult(result, target);
129274
+ }
129275
+ return projectRewriteScopeResult(
129276
+ runtime,
129277
+ result,
129278
+ target,
129279
+ beforeText,
129280
+ input.text,
129281
+ documentMutated
129282
+ );
128205
129283
  }
128206
129284
  function projectApplyResult(result, target) {
128207
129285
  return {
@@ -128222,7 +129300,79 @@ function projectApplyResult(result, target) {
128222
129300
  ...result.auditReference ? { auditReference: result.auditReference } : {}
128223
129301
  };
128224
129302
  }
128225
- function projectRewriteScopeResult(runtime, result, target, beforeText, proposedText) {
129303
+ function applyEditableTextRewrite(runtime, target, input) {
129304
+ const before = runtime.getCanonicalDocument();
129305
+ runtime.dispatch({
129306
+ type: "selection.set",
129307
+ selection: target.selection,
129308
+ origin: actionOrigin(runtime, input)
129309
+ });
129310
+ runtime.applyActiveStoryTextCommand({
129311
+ type: "text.insert",
129312
+ text: input.text,
129313
+ editableTarget: target.editableTarget,
129314
+ origin: actionOrigin(runtime, input)
129315
+ });
129316
+ const changed = runtime.getCanonicalDocument() !== before;
129317
+ if (!changed) {
129318
+ return blockedApply(
129319
+ `actions:editable-text:runtime-noop:${target.actionHandle}`,
129320
+ "blocked",
129321
+ "The editable text command was accepted but produced no document change.",
129322
+ "Refresh the action handle with ai.actions.locateAll and retry; route persistent failures to L07 text command support.",
129323
+ [
129324
+ blockerWithOwner(
129325
+ `actions:editable-text:runtime-noop:${target.actionHandle}`,
129326
+ "blocked",
129327
+ "The editable text command was accepted but produced no document change.",
129328
+ "Refresh the action handle with ai.actions.locateAll and retry; route persistent failures to L07 text command support.",
129329
+ "L07 runtime text command support"
129330
+ )
129331
+ ]
129332
+ );
129333
+ }
129334
+ const afterTarget = findEditableTextActionByTargetKey(
129335
+ runtime,
129336
+ target.editableTarget.targetKey
129337
+ );
129338
+ const afterReadback = afterTarget?.readback ?? editableTextTargetState(
129339
+ runtime.getCanonicalDocument(),
129340
+ target.editableTarget
129341
+ )?.readback;
129342
+ if (!afterReadback || afterReadback.text !== input.text) {
129343
+ return {
129344
+ status: "blocked",
129345
+ applied: false,
129346
+ changed: true,
129347
+ target: summarizeTarget(afterTarget ?? target),
129348
+ posture: "suspect-readback",
129349
+ blockers: Object.freeze([`actions:editable-text:readback-mismatch:${target.actionHandle}`]),
129350
+ blockerDetails: Object.freeze([
129351
+ blocker(
129352
+ `actions:editable-text:readback-mismatch:${target.actionHandle}`,
129353
+ "blocked",
129354
+ "The editable text command changed the document, but exact target readback did not match the proposed text.",
129355
+ "Treat the mutation as suspect. Re-read the target and export before claiming success."
129356
+ )
129357
+ ]),
129358
+ ...afterReadback ? { afterReadback } : {}
129359
+ };
129360
+ }
129361
+ return {
129362
+ status: "applied",
129363
+ applied: true,
129364
+ changed: true,
129365
+ target: summarizeTarget(afterTarget ?? { ...target, readback: afterReadback }),
129366
+ commandReference: {
129367
+ command: "text.insert",
129368
+ actorId: input.actorId ?? "v3-ai-api",
129369
+ origin: input.origin ?? "agent",
129370
+ emittedAtUtc: currentAuditTimestamp(runtime)
129371
+ },
129372
+ afterReadback
129373
+ };
129374
+ }
129375
+ function projectRewriteScopeResult(runtime, result, target, beforeText, proposedText, documentMutated) {
128226
129376
  if (!result.applied) return projectApplyResult(result, target);
128227
129377
  const compiledAfter = createScopeCompilerService(runtime).compileScopeById(
128228
129378
  target.handle.scopeId
@@ -128233,7 +129383,8 @@ function projectRewriteScopeResult(runtime, result, target, beforeText, proposed
128233
129383
  target,
128234
129384
  `actions:rewrite:authoritative-readback-unresolvable:${target.handle.scopeId}`,
128235
129385
  "The replacement primitive reported success, but the target scope could not be re-read afterwards.",
128236
- "Treat the mutation as untrusted. Re-locate the target and retry only after the scope resolves, or create an issue flag instead."
129386
+ "Treat the mutation as untrusted. Re-locate the target and retry only after the scope resolves, or create an issue flag instead.",
129387
+ documentMutated
128237
129388
  );
128238
129389
  }
128239
129390
  const afterText = compiledAfter.scope.content.text;
@@ -128245,7 +129396,8 @@ function projectRewriteScopeResult(runtime, result, target, beforeText, proposed
128245
129396
  { ...target, scope: compiledAfter.scope, handle: compiledAfter.scope.handle },
128246
129397
  `actions:rewrite:authoritative-readback-unchanged:${target.handle.scopeId}`,
128247
129398
  "The replacement primitive reported success, but authoritative scope readback showed unchanged text.",
128248
- "Treat the mutation as not applied. Retry with a narrower scope or create an issue flag; do not claim the replacement succeeded."
129399
+ "Treat the mutation as not applied. Retry with a narrower scope or create an issue flag; do not claim the replacement succeeded.",
129400
+ documentMutated
128249
129401
  );
128250
129402
  }
128251
129403
  if (!expectedPresent) {
@@ -128254,7 +129406,8 @@ function projectRewriteScopeResult(runtime, result, target, beforeText, proposed
128254
129406
  { ...target, scope: compiledAfter.scope, handle: compiledAfter.scope.handle },
128255
129407
  `actions:rewrite:authoritative-readback-mismatch:${target.handle.scopeId}`,
128256
129408
  "The replacement primitive reported success, but authoritative scope readback did not contain the proposed text.",
128257
- "Treat the mutation as suspect. Re-read the target, inspect the exported package when available, and retry only with a verified target."
129409
+ "Treat the mutation as suspect. Re-read the target, inspect the exported package when available, and retry only with a verified target.",
129410
+ documentMutated
128258
129411
  );
128259
129412
  }
128260
129413
  return {
@@ -128271,17 +129424,27 @@ function projectRewriteScopeResult(runtime, result, target, beforeText, proposed
128271
129424
  ...result.auditReference ? { auditReference: result.auditReference } : {}
128272
129425
  };
128273
129426
  }
128274
- function blockedRewriteReadback(result, target, code, message, nextStep) {
129427
+ function blockedRewriteReadback(result, target, code, message, nextStep, documentMutated = false) {
128275
129428
  const detail = blocker(code, "blocked", message, nextStep);
129429
+ const details = documentMutated ? [
129430
+ detail,
129431
+ blockerWithOwner(
129432
+ `actions:rewrite:suspect-mutation:${target.handle.scopeId}`,
129433
+ "blocked",
129434
+ "The document changed even though authoritative target readback failed.",
129435
+ "Abort the plan, inspect the export/readback evidence, and route the target to L08/L07 scope edit-target mapping before retrying.",
129436
+ "L08 semantic scopes and L07 runtime text commands"
129437
+ )
129438
+ ] : [detail];
128276
129439
  return {
128277
129440
  status: "blocked",
128278
129441
  applied: false,
128279
- changed: false,
129442
+ changed: documentMutated,
128280
129443
  target: summarizeTarget(target),
128281
129444
  proposalId: result.proposalId,
128282
- posture: "suspect-readback",
128283
- blockers: Object.freeze([detail.code]),
128284
- blockerDetails: Object.freeze([detail]),
129445
+ posture: documentMutated ? "suspect-mutation" : "suspect-readback",
129446
+ blockers: Object.freeze(details.map((entry) => entry.code)),
129447
+ blockerDetails: Object.freeze(details),
128285
129448
  ...result.auditReference ? { auditReference: result.auditReference } : {}
128286
129449
  };
128287
129450
  }
@@ -128297,11 +129460,23 @@ function summarizeTarget(target) {
128297
129460
  canMark: false
128298
129461
  };
128299
129462
  }
129463
+ if (target.kind === "editable-text") {
129464
+ return {
129465
+ kind: target.targetKind,
129466
+ handle: target.ownerHandle,
129467
+ actionHandle: target.actionHandle,
129468
+ readback: target.readback,
129469
+ canRewriteText: true,
129470
+ canInsertAdjacentText: false,
129471
+ canFlag: false,
129472
+ canMark: false
129473
+ };
129474
+ }
128300
129475
  return {
128301
129476
  kind: target.scope.kind,
128302
129477
  handle: target.handle,
128303
129478
  canRewriteText: canRewriteScopeText(target.scope),
128304
- canInsertAdjacentText: canRewriteScopeText(target.scope),
129479
+ canInsertAdjacentText: canInsertAdjacentScopeText(target.scope),
128305
129480
  canFlag: true,
128306
129481
  canMark: canMarkScope(target.scope)
128307
129482
  };
@@ -128313,6 +129488,34 @@ function tableTextActionsForScope(runtime, handle) {
128313
129488
  });
128314
129489
  return result.actions.filter((action) => action.family === "table-text");
128315
129490
  }
129491
+ function editableTextActionsForScope(runtime, handle) {
129492
+ const bundle = createScopeCompilerService(runtime).compileBundleById(
129493
+ handle.scopeId,
129494
+ currentAuditTimestamp(runtime)
129495
+ );
129496
+ const entries = bundle?.evidence.editableTargets?.entries ?? [];
129497
+ const currentTargets = collectEditableTargetRefs(runtime.getCanonicalDocument());
129498
+ const actions2 = [];
129499
+ for (const entry of entries) {
129500
+ if (entry.kind !== "hyperlink-text" || entry.commandFamily !== "text-leaf" || entry.runtimeCommand.status !== "supported" || !entry.runtimeCommand.actionHandle) {
129501
+ continue;
129502
+ }
129503
+ const currentTarget = currentTargets.find((target) => target.targetKey === entry.targetKey);
129504
+ if (!currentTarget || currentTarget.kind !== "hyperlink-text") continue;
129505
+ const targetState = editableTextTargetState(runtime.getCanonicalDocument(), currentTarget);
129506
+ if (!targetState) continue;
129507
+ actions2.push({
129508
+ kind: "editable-text",
129509
+ targetKind: "hyperlink-text",
129510
+ actionHandle: entry.runtimeCommand.actionHandle,
129511
+ editableTarget: currentTarget,
129512
+ ownerHandle: handle,
129513
+ readback: targetState.readback,
129514
+ selection: targetState.selection
129515
+ });
129516
+ }
129517
+ return Object.freeze(actions2);
129518
+ }
128316
129519
  function findTableAction(runtime, actionHandle) {
128317
129520
  const action = findAnyTableAction(runtime, actionHandle);
128318
129521
  return action?.family === "table-text" ? action : null;
@@ -128332,6 +129535,27 @@ function findAnyTableAction(runtime, actionHandle) {
128332
129535
  }
128333
129536
  return null;
128334
129537
  }
129538
+ function findEditableTextAction(runtime, actionHandle) {
129539
+ if (!actionHandle.startsWith("scope-command:text-leaf:")) return null;
129540
+ const compiler = createScopeCompilerService(runtime);
129541
+ for (const scope of compiler.compileAllScopes()) {
129542
+ const action = editableTextActionsForScope(runtime, scope.handle).find(
129543
+ (candidate) => candidate.actionHandle === actionHandle
129544
+ );
129545
+ if (action) return action;
129546
+ }
129547
+ return null;
129548
+ }
129549
+ function findEditableTextActionByTargetKey(runtime, targetKey) {
129550
+ const compiler = createScopeCompilerService(runtime);
129551
+ for (const scope of compiler.compileAllScopes()) {
129552
+ const action = editableTextActionsForScope(runtime, scope.handle).find(
129553
+ (candidate) => candidate.editableTarget.targetKey === targetKey
129554
+ );
129555
+ if (action) return action;
129556
+ }
129557
+ return null;
129558
+ }
128335
129559
  function readDocumentPlanTarget(runtime) {
128336
129560
  const document2 = createInspectFamily(runtime).inspectDocument();
128337
129561
  return {
@@ -128388,6 +129612,18 @@ function readPlanTarget(runtime, target) {
128388
129612
  ])
128389
129613
  };
128390
129614
  }
129615
+ const editableText = findEditableTextAction(runtime, target.actionHandle);
129616
+ if (editableText) {
129617
+ return {
129618
+ ok: true,
129619
+ target: summarizeTarget(editableText),
129620
+ readback: {
129621
+ text: editableText.readback.text,
129622
+ excerpt: excerpt(editableText.readback.text),
129623
+ isEmpty: editableText.readback.isEmpty
129624
+ }
129625
+ };
129626
+ }
128391
129627
  return readPlanTableAction(runtime, target.actionHandle);
128392
129628
  }
128393
129629
  function readPlanTableAction(runtime, actionHandle) {
@@ -128450,6 +129686,15 @@ function checkPlanStepCapability(runtime, step, before) {
128450
129686
  "Regenerate the plan with a ScopeHandle or opaque actionHandle returned by L09."
128451
129687
  );
128452
129688
  }
129689
+ if (step.kind === "rewrite" && target.kind === "list-item") {
129690
+ return blockerWithOwner(
129691
+ "capability:list-item:authoritative-readback-required",
129692
+ "blocked",
129693
+ "List-item text replacement is not yet backed by an authoritative mutation/readback route.",
129694
+ "Use listOperation for numbering changes, or create an issue/explanation until L08/L07 list-item text replacement is proven.",
129695
+ "L08 semantic scopes and L07 runtime text commands"
129696
+ );
129697
+ }
128453
129698
  if (step.kind === "rewrite" && !target.canRewriteText) {
128454
129699
  return blocker(
128455
129700
  `actions:plan:target-not-rewriteable:${step.id}`,
@@ -128482,7 +129727,20 @@ function checkPlanStepCapability(runtime, step, before) {
128482
129727
  "Use a supported semantic scope or create an issue flag instead."
128483
129728
  );
128484
129729
  }
128485
- if (step.kind === "fieldRefresh" || step.kind === "tocRefresh" || step.kind === "bookmarkEdit" || step.kind === "hyperlinkDestinationEdit") {
129730
+ if (step.kind === "fieldRefresh" || step.kind === "tocRefresh" || step.kind === "bookmarkEdit" || step.kind === "hyperlinkDestinationEdit" || step.kind === "hyperlinkTextEdit") {
129731
+ if (step.kind === "hyperlinkTextEdit") {
129732
+ const resolved2 = resolveTarget(runtime, step.target);
129733
+ if (!resolved2.ok) return resolved2.blockerDetails[0] ?? null;
129734
+ if (resolved2.target.kind !== "editable-text" || resolved2.target.targetKind !== "hyperlink-text") {
129735
+ return blocker(
129736
+ `actions:hyperlink-text-edit:hyperlink-text-handle-required:${step.id}`,
129737
+ "unsupported",
129738
+ "Hyperlink display text plan steps require an exact hyperlink-text actionHandle.",
129739
+ "Regenerate the plan with a scope-command:text-leaf actionHandle returned by ai.actions.locateAll."
129740
+ );
129741
+ }
129742
+ return null;
129743
+ }
128486
129744
  const resolved = resolveScopeExactTarget(runtime, step.target, step.kind);
128487
129745
  if (!resolved.ok) return resolved.blockerDetails[0] ?? null;
128488
129746
  const targetRef = resolveModeledEditableTarget(runtime, resolved.target, step.kind);
@@ -128587,6 +129845,13 @@ function applyPlanStep(runtime, step, plan) {
128587
129845
  actorId: step.actorId ?? plan.actorId,
128588
129846
  origin: step.origin ?? plan.origin
128589
129847
  });
129848
+ case "hyperlinkTextEdit":
129849
+ return createActionsFamily(runtime).actions.hyperlinkTextEdit({
129850
+ target: step.target,
129851
+ text: step.text,
129852
+ actorId: step.actorId ?? plan.actorId,
129853
+ origin: step.origin ?? plan.origin
129854
+ });
128590
129855
  case "listOperation":
128591
129856
  return createActionsFamily(runtime).actions.listOperation({
128592
129857
  target: step.target,
@@ -128903,11 +130168,159 @@ function isTableFamilyScope(kind) {
128903
130168
  return kind === "table" || kind === "table-row" || kind === "table-cell";
128904
130169
  }
128905
130170
  function canRewriteScopeText(scope) {
130171
+ return !isTableFamilyScope(scope.kind) && scope.kind !== "list-item" && (scope.replaceability.level === "full" || scope.replaceability.level === "text-only");
130172
+ }
130173
+ function canInsertAdjacentScopeText(scope) {
128906
130174
  return !isTableFamilyScope(scope.kind) && (scope.replaceability.level === "full" || scope.replaceability.level === "text-only");
128907
130175
  }
130176
+ function scopeRewriteCapabilityBlocker(scope) {
130177
+ if (scope.kind === "list-item") {
130178
+ return blockerWithOwner(
130179
+ "capability:list-item:authoritative-readback-required",
130180
+ "blocked",
130181
+ "List-item text replacement is not yet backed by an authoritative mutation/readback route.",
130182
+ "Use listOperation for numbering changes, or create an issue/explanation until L08/L07 list-item text replacement is proven.",
130183
+ "L08 semantic scopes and L07 runtime text commands"
130184
+ );
130185
+ }
130186
+ if (!canRewriteScopeText(scope)) {
130187
+ return blocker(
130188
+ `actions:rewrite:target-not-rewriteable:${scope.handle.scopeId}`,
130189
+ "unsupported",
130190
+ "The target capability posture does not allow text rewrite.",
130191
+ "Use a supported text target, table text actionHandle, or create an issue flag instead."
130192
+ );
130193
+ }
130194
+ return null;
130195
+ }
128908
130196
  function canMarkScope(scope) {
128909
130197
  return !isTableFamilyScope(scope.kind) && scope.replaceability.level !== "blocked" && scope.replaceability.level !== "preserve-only";
128910
130198
  }
130199
+ function editableTextTargetState(document2, target) {
130200
+ if (target.kind !== "hyperlink-text") return void 0;
130201
+ const resolved = resolveHyperlinkTarget(document2, target);
130202
+ if (!resolved) return void 0;
130203
+ const text = collectInlineText3(resolved.hyperlink.children);
130204
+ return {
130205
+ readback: { text, isEmpty: text.length === 0 },
130206
+ selection: {
130207
+ anchor: resolved.from,
130208
+ head: resolved.to,
130209
+ isCollapsed: resolved.from === resolved.to,
130210
+ activeRange: {
130211
+ kind: "range",
130212
+ from: resolved.from,
130213
+ to: resolved.to,
130214
+ assoc: { start: -1, end: 1 }
130215
+ }
130216
+ }
130217
+ };
130218
+ }
130219
+ function resolveHyperlinkTarget(document2, target) {
130220
+ const parsed = parseBlockInlinePath(target.blockPath);
130221
+ if (!parsed) return null;
130222
+ let blocks = document2.content.children;
130223
+ let block;
130224
+ let row2;
130225
+ let offset = 0;
130226
+ for (const token of parsed) {
130227
+ switch (token.kind) {
130228
+ case "block":
130229
+ for (let index = 0; index < token.index; index += 1) {
130230
+ offset += blockTextLength(blocks[index]);
130231
+ }
130232
+ block = blocks[token.index];
130233
+ row2 = void 0;
130234
+ if (!block) return null;
130235
+ break;
130236
+ case "row":
130237
+ if (block?.type !== "table") return null;
130238
+ row2 = block.rows[token.index];
130239
+ block = void 0;
130240
+ if (!row2) return null;
130241
+ break;
130242
+ case "cell": {
130243
+ const cell = row2?.cells[token.index];
130244
+ if (!cell) return null;
130245
+ blocks = cell.children;
130246
+ block = void 0;
130247
+ row2 = void 0;
130248
+ break;
130249
+ }
130250
+ case "inline": {
130251
+ if (block?.type !== "paragraph") return null;
130252
+ for (let index = 0; index < token.index; index += 1) {
130253
+ offset += inlineTextLength(block.children[index]);
130254
+ }
130255
+ const inline = block.children[token.index];
130256
+ if (inline?.type !== "hyperlink") return null;
130257
+ const length = collectInlineText3(inline.children).length;
130258
+ return { hyperlink: inline, from: offset, to: offset + length };
130259
+ }
130260
+ }
130261
+ }
130262
+ return null;
130263
+ }
130264
+ function parseBlockInlinePath(path) {
130265
+ if (!path.startsWith("main/")) return null;
130266
+ const tokens = [];
130267
+ const re = /(block|row|cell|inline)\[(\d+)\]/gu;
130268
+ let match;
130269
+ while ((match = re.exec(path)) !== null) {
130270
+ const kind = match[1];
130271
+ tokens.push({ kind, index: Number(match[2]) });
130272
+ }
130273
+ return tokens.length > 0 ? Object.freeze(tokens) : null;
130274
+ }
130275
+ function collectInlineText3(inlines) {
130276
+ let text = "";
130277
+ for (const inline of inlines) {
130278
+ switch (inline.type) {
130279
+ case "text":
130280
+ text += inline.text;
130281
+ break;
130282
+ case "hyperlink":
130283
+ case "field":
130284
+ text += collectInlineText3(inline.children);
130285
+ break;
130286
+ default:
130287
+ break;
130288
+ }
130289
+ }
130290
+ return text;
130291
+ }
130292
+ function blockTextLength(block) {
130293
+ if (!block) return 0;
130294
+ switch (block.type) {
130295
+ case "paragraph":
130296
+ return collectInlineText3(block.children).length;
130297
+ case "table":
130298
+ return block.rows.reduce(
130299
+ (rowSum, row2) => rowSum + row2.cells.reduce(
130300
+ (cellSum, cell) => cellSum + cell.children.reduce((blockSum, child) => blockSum + blockTextLength(child), 0),
130301
+ 0
130302
+ ),
130303
+ 0
130304
+ );
130305
+ case "sdt":
130306
+ case "custom_xml":
130307
+ return block.children.reduce((sum, child) => sum + blockTextLength(child), 0);
130308
+ default:
130309
+ return 0;
130310
+ }
130311
+ }
130312
+ function inlineTextLength(inline) {
130313
+ if (!inline) return 0;
130314
+ switch (inline.type) {
130315
+ case "text":
130316
+ return inline.text.length;
130317
+ case "hyperlink":
130318
+ case "field":
130319
+ return collectInlineText3(inline.children).length;
130320
+ default:
130321
+ return 0;
130322
+ }
130323
+ }
128911
130324
  function textMatches(text, query, matchCase) {
128912
130325
  if (matchCase) return text.includes(query);
128913
130326
  return text.toLocaleLowerCase().includes(query.toLocaleLowerCase());
@@ -128966,6 +130379,30 @@ function blockedApplyFromResolution(resolution) {
128966
130379
  blockerDetails: resolution.blockerDetails
128967
130380
  };
128968
130381
  }
130382
+ function withSuspectMutationApplyResult(result, stepOrScopeId, target) {
130383
+ const detail = blockerWithOwner(
130384
+ `actions:plan:suspect-mutation:${stepOrScopeId}`,
130385
+ "blocked",
130386
+ "The document changed even though the action did not return an applied result.",
130387
+ "Abort the remaining plan, inspect authoritative readback/export evidence, and route the target to the owning edit-target/readback layer before retrying.",
130388
+ "L08 semantic scopes and L07 runtime text commands"
130389
+ );
130390
+ return {
130391
+ ...result,
130392
+ status: "blocked",
130393
+ applied: false,
130394
+ changed: true,
130395
+ ...target ? { target } : {},
130396
+ posture: "suspect-mutation",
130397
+ blockers: Object.freeze([...result.blockers ?? [], detail.code]),
130398
+ blockerDetails: Object.freeze([...result.blockerDetails ?? [], detail])
130399
+ };
130400
+ }
130401
+ function isSuspectMutationStep(step) {
130402
+ return step.posture === "suspect-mutation" || (step.blockers ?? []).some(
130403
+ (code) => code.startsWith("actions:plan:suspect-mutation:") || code.startsWith("actions:rewrite:suspect-mutation:")
130404
+ );
130405
+ }
128969
130406
  function blockedPlan(mode, code, category, message, nextStep) {
128970
130407
  const detail = blocker(code, category, message, nextStep);
128971
130408
  return {