@beyondwork/docx-react-component 1.0.128 → 1.0.130

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 (108) hide show
  1. package/dist/api/public-types.cjs +809 -78
  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 +4 -4
  5. package/dist/api/v3.cjs +2059 -402
  6. package/dist/api/v3.d.cts +3 -3
  7. package/dist/api/v3.d.ts +3 -3
  8. package/dist/api/v3.js +13 -13
  9. package/dist/{canonical-document-CXCFCbAz.d.cts → canonical-document-BMtONpgf.d.cts} +6 -0
  10. package/dist/{canonical-document-CXCFCbAz.d.ts → canonical-document-BMtONpgf.d.ts} +6 -0
  11. package/dist/{chunk-MWSBGJQO.js → chunk-35RHOE6I.js} +105 -4
  12. package/dist/{chunk-2QL5DAKF.js → chunk-3YCQM2RV.js} +6 -6
  13. package/dist/{chunk-ESJ2MES5.js → chunk-4YCWECLZ.js} +1 -1
  14. package/dist/{chunk-4EENH4FG.js → chunk-6TBLDBCL.js} +1 -1
  15. package/dist/{chunk-XRACP43Q.js → chunk-7G5GR3VV.js} +469 -32
  16. package/dist/{chunk-CXSYRB37.js → chunk-A3GSNB4G.js} +183 -55
  17. package/dist/{chunk-5DGKFNQT.js → chunk-A66ZVUAT.js} +150 -1
  18. package/dist/{chunk-YIYM4ZAP.js → chunk-CI2TD3T4.js} +1 -1
  19. package/dist/{chunk-TQDQU2E3.js → chunk-DGA7M77X.js} +2 -2
  20. package/dist/{chunk-EB6M3GE6.js → chunk-FM4K4XFJ.js} +100 -97
  21. package/dist/{chunk-D5HYZQTG.js → chunk-HYHCRMR7.js} +1 -1
  22. package/dist/{chunk-6F5QW44A.js → chunk-KNHMXKC6.js} +2 -2
  23. package/dist/{chunk-4YJVRIUB.js → chunk-M7YRJX6V.js} +61 -29
  24. package/dist/{chunk-KFCQYZXR.js → chunk-OVLZQ6FZ.js} +61 -0
  25. package/dist/{chunk-BYSRJ4FE.js → chunk-PHMWH23E.js} +1 -1
  26. package/dist/{chunk-ZDOAUP3V.js → chunk-Q7Y57KOK.js} +2 -2
  27. package/dist/{chunk-LZVBNDGU.js → chunk-QXKQPUOM.js} +3 -3
  28. package/dist/{chunk-CX42VC67.js → chunk-SYQWQ6FE.js} +1 -1
  29. package/dist/{chunk-KV435YXO.js → chunk-T5YYFDZB.js} +1 -1
  30. package/dist/{chunk-YHZHPXDB.js → chunk-THVM6EP5.js} +419 -24
  31. package/dist/{chunk-V6XVZFFH.js → chunk-VRKK2CSZ.js} +111 -90
  32. package/dist/{chunk-OL2UEHRP.js → chunk-WUDSNHWF.js} +1 -1
  33. package/dist/{chunk-LCYYR57Q.js → chunk-WZDKNF37.js} +666 -107
  34. package/dist/{chunk-6EROGFUF.js → chunk-YLL7MF5C.js} +444 -131
  35. package/dist/{chunk-YD2JE54B.js → chunk-ZVC23LKV.js} +1 -1
  36. package/dist/compare.cjs +100 -97
  37. package/dist/compare.d.cts +1 -1
  38. package/dist/compare.d.ts +1 -1
  39. package/dist/compare.js +3 -3
  40. package/dist/core/commands/formatting-commands.d.cts +2 -2
  41. package/dist/core/commands/formatting-commands.d.ts +2 -2
  42. package/dist/core/commands/image-commands.cjs +182 -54
  43. package/dist/core/commands/image-commands.d.cts +2 -2
  44. package/dist/core/commands/image-commands.d.ts +2 -2
  45. package/dist/core/commands/image-commands.js +5 -5
  46. package/dist/core/commands/section-layout-commands.d.cts +2 -2
  47. package/dist/core/commands/section-layout-commands.d.ts +2 -2
  48. package/dist/core/commands/style-commands.d.cts +2 -2
  49. package/dist/core/commands/style-commands.d.ts +2 -2
  50. package/dist/core/commands/table-structure-commands.cjs +182 -54
  51. package/dist/core/commands/table-structure-commands.d.cts +2 -2
  52. package/dist/core/commands/table-structure-commands.d.ts +2 -2
  53. package/dist/core/commands/table-structure-commands.js +4 -4
  54. package/dist/core/commands/text-commands.cjs +182 -54
  55. package/dist/core/commands/text-commands.d.cts +2 -2
  56. package/dist/core/commands/text-commands.d.ts +2 -2
  57. package/dist/core/commands/text-commands.js +5 -5
  58. package/dist/core/selection/mapping.d.cts +2 -2
  59. package/dist/core/selection/mapping.d.ts +2 -2
  60. package/dist/core/state/editor-state.d.cts +2 -2
  61. package/dist/core/state/editor-state.d.ts +2 -2
  62. package/dist/index.cjs +2765 -557
  63. package/dist/index.d.cts +5 -5
  64. package/dist/index.d.ts +5 -5
  65. package/dist/index.js +52 -28
  66. package/dist/io/docx-session.cjs +267 -211
  67. package/dist/io/docx-session.d.cts +4 -4
  68. package/dist/io/docx-session.d.ts +4 -4
  69. package/dist/io/docx-session.js +6 -6
  70. package/dist/legal.cjs +9 -20
  71. package/dist/legal.d.cts +1 -1
  72. package/dist/legal.d.ts +1 -1
  73. package/dist/legal.js +3 -3
  74. package/dist/{loader-19ct2Be0.d.ts → loader-B-aL5HGD.d.ts} +3 -3
  75. package/dist/{loader-CoXQ2wGd.d.cts → loader-DiY_ZgKl.d.cts} +3 -3
  76. package/dist/{measurement-backend-canvas-Q3MJMEYX.js → measurement-backend-canvas-F7ZYDACK.js} +1 -1
  77. package/dist/{public-types-B-CskQen.d.cts → public-types-DyqnxxO9.d.ts} +252 -2
  78. package/dist/{public-types-7KZsNGE2.d.ts → public-types-gvubspUI.d.cts} +252 -2
  79. package/dist/public-types.cjs +809 -78
  80. package/dist/public-types.d.cts +2 -2
  81. package/dist/public-types.d.ts +2 -2
  82. package/dist/public-types.js +4 -4
  83. package/dist/runtime/collab.d.cts +3 -3
  84. package/dist/runtime/collab.d.ts +3 -3
  85. package/dist/runtime/document-runtime.cjs +1887 -313
  86. package/dist/runtime/document-runtime.d.cts +2 -2
  87. package/dist/runtime/document-runtime.d.ts +2 -2
  88. package/dist/runtime/document-runtime.js +17 -17
  89. package/dist/{session-B5015J4v.d.cts → session-BUN6B-Vj.d.cts} +3 -3
  90. package/dist/{session-C2i8-d6v.d.ts → session-CDB0hohT.d.ts} +3 -3
  91. package/dist/session.cjs +267 -211
  92. package/dist/session.d.cts +5 -5
  93. package/dist/session.d.ts +5 -5
  94. package/dist/session.js +7 -7
  95. package/dist/tailwind.cjs +809 -78
  96. package/dist/tailwind.d.cts +2 -2
  97. package/dist/tailwind.d.ts +2 -2
  98. package/dist/tailwind.js +8 -8
  99. package/dist/{types-DNhN0WeN.d.cts → types-C4bz3kDU.d.cts} +2 -2
  100. package/dist/{types-yvrQuGX9.d.ts → types-VWH6CRvG.d.ts} +2 -2
  101. package/dist/ui-tailwind/editor-surface/search-plugin.d.cts +3 -3
  102. package/dist/ui-tailwind/editor-surface/search-plugin.d.ts +3 -3
  103. package/dist/ui-tailwind/editor-surface/search-plugin.js +5 -5
  104. package/dist/ui-tailwind.cjs +809 -78
  105. package/dist/ui-tailwind.d.cts +3 -3
  106. package/dist/ui-tailwind.d.ts +3 -3
  107. package/dist/ui-tailwind.js +8 -8
  108. package/package.json +1 -1
package/dist/api/v3.cjs CHANGED
@@ -21,6 +21,43 @@ var __copyProps = (to, from, except, desc) => {
21
21
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
22
22
 
23
23
  // src/runtime/layout/resolved-formatting-state.ts
24
+ function createLayoutReadyFormattingSnapshot(formatting, runs = /* @__PURE__ */ new Map()) {
25
+ const snapshot = {
26
+ version: 1,
27
+ paragraph: {
28
+ spacingBefore: formatting.spacingBefore,
29
+ spacingAfter: formatting.spacingAfter,
30
+ lineHeight: formatting.lineHeight,
31
+ lineRule: formatting.lineRule,
32
+ indentLeft: formatting.indentLeft,
33
+ indentRight: formatting.indentRight,
34
+ firstLineIndent: formatting.firstLineIndent,
35
+ hangingIndent: formatting.hangingIndent,
36
+ fontSizeHalfPoints: formatting.fontSizeHalfPoints,
37
+ averageCharWidthTwips: formatting.averageCharWidthTwips,
38
+ tabStops: formatting.tabStops.map((tab) => ({ ...tab })),
39
+ defaultTabInterval: formatting.defaultTabInterval,
40
+ keepNext: formatting.keepNext,
41
+ keepLines: formatting.keepLines,
42
+ pageBreakBefore: formatting.pageBreakBefore,
43
+ widowControl: formatting.widowControl,
44
+ contextualSpacing: formatting.contextualSpacing,
45
+ ...formatting.numberingMarkerBox ? { numberingMarkerBox: { ...formatting.numberingMarkerBox } } : {}
46
+ },
47
+ runs: Array.from(runs.entries()).map(([runId, run]) => ({
48
+ runId,
49
+ ...run.fontFamily ? { fontFamily: run.fontFamily } : {},
50
+ ...typeof run.fontSizeHalfPoints === "number" ? { fontSizeHalfPoints: run.fontSizeHalfPoints } : {},
51
+ bold: Boolean(run.bold),
52
+ italic: Boolean(run.italic),
53
+ verticalAlign: run.verticalAlign ?? "baseline"
54
+ })).sort((a, b) => a.runId.localeCompare(b.runId))
55
+ };
56
+ return {
57
+ ...snapshot,
58
+ hash: hashStable(snapshot)
59
+ };
60
+ }
24
61
  function resolveBlockFormatting(block, defaultTabInterval = 720, themeFonts) {
25
62
  if (block.kind !== "paragraph") {
26
63
  return null;
@@ -263,6 +300,29 @@ function buildRunFormattingMap(block) {
263
300
  }
264
301
  return runs;
265
302
  }
303
+ function hashStable(value) {
304
+ return fnv1a2(stableStringify3(value)).toString(36);
305
+ }
306
+ function stableStringify3(value) {
307
+ if (value === null || typeof value !== "object") return JSON.stringify(value);
308
+ if (Array.isArray(value)) {
309
+ return `[${value.map((item) => stableStringify3(item)).join(",")}]`;
310
+ }
311
+ if (value instanceof Map) {
312
+ return stableStringify3(Array.from(value.entries()));
313
+ }
314
+ const object = value;
315
+ const keys = Object.keys(object).filter((key) => object[key] !== void 0 && typeof object[key] !== "function").sort();
316
+ return `{${keys.map((key) => `${JSON.stringify(key)}:${stableStringify3(object[key])}`).join(",")}}`;
317
+ }
318
+ function fnv1a2(input) {
319
+ let hash = 2166136261;
320
+ for (let i = 0; i < input.length; i += 1) {
321
+ hash ^= input.charCodeAt(i);
322
+ hash = Math.imul(hash, 16777619);
323
+ }
324
+ return hash >>> 0;
325
+ }
266
326
  var FONT_AVG_CHAR_WIDTH, DEFAULT_FONT_AVG_CHAR_WIDTH, DEFAULT_FONT_SIZE_HALF_POINTS, DEFAULT_LINE_HEIGHT_FACTOR, TWIPS_PER_POINT;
267
327
  var init_resolved_formatting_state = __esm({
268
328
  "src/runtime/layout/resolved-formatting-state.ts"() {
@@ -3591,26 +3651,35 @@ function buildParagraphPropertiesXml(paragraph) {
3591
3651
  if (frameXml) children.push(frameXml);
3592
3652
  }
3593
3653
  pushOnOffParagraphProperty(children, "widowControl", paragraph.widowControl);
3594
- if (paragraph.outlineLevel !== void 0) {
3595
- children.push(`<w:outlineLvl w:val="${paragraph.outlineLevel}"/>`);
3596
- }
3597
3654
  if (paragraph.numbering) {
3598
3655
  children.push(serializeParagraphNumberingProperties(paragraph.numbering));
3599
3656
  }
3657
+ pushOnOffParagraphProperty(children, "suppressLineNumbers", paragraph.suppressLineNumbers);
3658
+ if (paragraph.borders) {
3659
+ const bordersXml = serializeParagraphBorders(paragraph.borders);
3660
+ if (bordersXml) children.push(bordersXml);
3661
+ }
3662
+ if (paragraph.shading) {
3663
+ const shadingXml = serializeParagraphShading(paragraph.shading);
3664
+ if (shadingXml) children.push(shadingXml);
3665
+ }
3666
+ if (paragraph.tabStops && paragraph.tabStops.length > 0) {
3667
+ const tabsXml = paragraph.tabStops.map((tab) => {
3668
+ const leaderAttr = tab.leader ? ` w:leader="${escapeXmlAttribute2(tab.leader)}"` : "";
3669
+ return `<w:tab w:val="${escapeXmlAttribute2(tab.align)}" w:pos="${twip(tab.position)}"${leaderAttr}/>`;
3670
+ }).join("");
3671
+ children.push(`<w:tabs>${tabsXml}</w:tabs>`);
3672
+ }
3673
+ pushOnOffParagraphProperty(children, "bidi", paragraph.bidi);
3600
3674
  if (paragraph.spacing) {
3601
3675
  const s = paragraph.spacing;
3602
3676
  const attrs = [];
3603
3677
  if (s.before !== void 0) attrs.push(`w:before="${twip(s.before)}"`);
3604
3678
  if (s.after !== void 0) attrs.push(`w:after="${twip(s.after)}"`);
3605
3679
  if (s.line !== void 0) attrs.push(`w:line="${twip(s.line)}"`);
3606
- if (s.lineRule !== void 0) attrs.push(`w:lineRule="${s.lineRule}"`);
3680
+ if (s.lineRule !== void 0) attrs.push(`w:lineRule="${escapeXmlAttribute2(s.lineRule)}"`);
3607
3681
  if (attrs.length > 0) children.push(`<w:spacing ${attrs.join(" ")}/>`);
3608
3682
  }
3609
- if (paragraph.contextualSpacing === true) {
3610
- children.push("<w:contextualSpacing/>");
3611
- } else if (paragraph.contextualSpacing === false) {
3612
- children.push(`<w:contextualSpacing w:val="false"/>`);
3613
- }
3614
3683
  if (paragraph.indentation) {
3615
3684
  const ind = paragraph.indentation;
3616
3685
  const attrs = [];
@@ -3620,33 +3689,20 @@ function buildParagraphPropertiesXml(paragraph) {
3620
3689
  if (ind.hanging !== void 0) attrs.push(`w:hanging="${twip(ind.hanging)}"`);
3621
3690
  if (attrs.length > 0) children.push(`<w:ind ${attrs.join(" ")}/>`);
3622
3691
  }
3623
- if (paragraph.alignment) {
3624
- children.push(`<w:jc w:val="${paragraph.alignment}"/>`);
3692
+ if (paragraph.contextualSpacing === true) {
3693
+ children.push("<w:contextualSpacing/>");
3694
+ } else if (paragraph.contextualSpacing === false) {
3695
+ children.push(`<w:contextualSpacing w:val="false"/>`);
3625
3696
  }
3626
- if (paragraph.borders) {
3627
- const bordersXml = serializeParagraphBorders(paragraph.borders);
3628
- if (bordersXml) {
3629
- children.push(bordersXml);
3630
- }
3697
+ if (paragraph.alignment) {
3698
+ children.push(`<w:jc w:val="${escapeXmlAttribute2(paragraph.alignment)}"/>`);
3631
3699
  }
3632
- if (paragraph.shading) {
3633
- const shadingXml = serializeParagraphShading(paragraph.shading);
3634
- if (shadingXml) {
3635
- children.push(shadingXml);
3636
- }
3700
+ if (paragraph.outlineLevel !== void 0) {
3701
+ children.push(`<w:outlineLvl w:val="${paragraph.outlineLevel}"/>`);
3637
3702
  }
3638
- pushOnOffParagraphProperty(children, "bidi", paragraph.bidi);
3639
- pushOnOffParagraphProperty(children, "suppressLineNumbers", paragraph.suppressLineNumbers);
3640
3703
  if (paragraph.cnfStyle) {
3641
3704
  children.push(`<w:cnfStyle w:val="${escapeXmlAttribute2(paragraph.cnfStyle)}"/>`);
3642
3705
  }
3643
- if (paragraph.tabStops && paragraph.tabStops.length > 0) {
3644
- const tabsXml = paragraph.tabStops.map((tab) => {
3645
- const leaderAttr = tab.leader ? ` w:leader="${tab.leader}"` : "";
3646
- return `<w:tab w:val="${tab.align}" w:pos="${twip(tab.position)}"${leaderAttr}/>`;
3647
- }).join("");
3648
- children.push(`<w:tabs>${tabsXml}</w:tabs>`);
3649
- }
3650
3706
  if (children.length === 0) return "";
3651
3707
  return `<w:pPr>${children.join("")}</w:pPr>`;
3652
3708
  }
@@ -4211,79 +4267,86 @@ function serializeRunProperties(marks) {
4211
4267
  if (!marks || marks.length === 0) {
4212
4268
  return "";
4213
4269
  }
4270
+ const orderedTypes = [
4271
+ "fontFamily",
4272
+ "bold",
4273
+ "italic",
4274
+ "allCaps",
4275
+ "smallCaps",
4276
+ "strikethrough",
4277
+ "doubleStrikethrough",
4278
+ "shadow",
4279
+ "emboss",
4280
+ "imprint",
4281
+ "vanish",
4282
+ "textColor",
4283
+ "charSpacing",
4284
+ "kerning",
4285
+ "position",
4286
+ "fontSize",
4287
+ "highlight",
4288
+ "underline",
4289
+ "backgroundColor",
4290
+ "lang",
4291
+ "textFill"
4292
+ ];
4214
4293
  const markParts = [];
4215
- for (const mark of marks) {
4216
- switch (mark.type) {
4217
- case "bold":
4218
- markParts.push("<w:b/>");
4219
- break;
4220
- case "italic":
4221
- markParts.push("<w:i/>");
4222
- break;
4223
- case "underline":
4224
- markParts.push(`<w:u w:val="single"/>`);
4225
- break;
4226
- case "strikethrough":
4227
- markParts.push("<w:strike/>");
4228
- break;
4229
- case "doubleStrikethrough":
4230
- markParts.push("<w:dstrike/>");
4231
- break;
4232
- case "vanish":
4233
- markParts.push("<w:vanish/>");
4234
- break;
4235
- case "lang":
4236
- markParts.push(`<w:lang w:val="${escapeXmlAttribute2(mark.val)}"/>`);
4237
- break;
4238
- case "highlight":
4239
- markParts.push(`<w:highlight w:val="${escapeXmlAttribute2(mark.val)}"/>`);
4240
- break;
4241
- case "backgroundColor":
4242
- markParts.push(
4243
- `<w:shd w:val="clear" w:color="auto" w:fill="${escapeXmlAttribute2(mark.color)}"/>`
4244
- );
4245
- break;
4246
- case "charSpacing":
4247
- markParts.push(`<w:spacing w:val="${mark.val}"/>`);
4248
- break;
4249
- case "kerning":
4250
- markParts.push(`<w:kern w:val="${mark.val}"/>`);
4251
- break;
4252
- case "emboss":
4253
- markParts.push("<w:emboss/>");
4254
- break;
4255
- case "imprint":
4256
- markParts.push("<w:imprint/>");
4257
- break;
4258
- case "shadow":
4259
- markParts.push("<w:shadow/>");
4260
- break;
4261
- case "position":
4262
- markParts.push(`<w:position w:val="${mark.val}"/>`);
4263
- break;
4264
- case "textFill":
4265
- markParts.push(mark.xml);
4266
- break;
4267
- case "fontFamily":
4268
- markParts.push(`<w:rFonts w:ascii="${escapeXmlAttribute2(mark.val)}" w:hAnsi="${escapeXmlAttribute2(mark.val)}"/>`);
4269
- break;
4270
- case "fontSize":
4271
- markParts.push(`<w:sz w:val="${mark.val}"/>`);
4272
- break;
4273
- case "textColor":
4274
- markParts.push(`<w:color w:val="${escapeXmlAttribute2(mark.color)}"/>`);
4275
- break;
4276
- case "smallCaps":
4277
- markParts.push("<w:smallCaps/>");
4278
- break;
4279
- case "allCaps":
4280
- markParts.push("<w:caps/>");
4281
- break;
4294
+ for (const type of orderedTypes) {
4295
+ for (const mark of marks) {
4296
+ if (mark.type !== type) continue;
4297
+ const xml = serializeRunPropertyMark(mark);
4298
+ if (xml) markParts.push(xml);
4282
4299
  }
4283
4300
  }
4284
4301
  const children = markParts.join("");
4285
4302
  return children.length > 0 ? `<w:rPr>${children}</w:rPr>` : "";
4286
4303
  }
4304
+ function serializeRunPropertyMark(mark) {
4305
+ switch (mark.type) {
4306
+ case "bold":
4307
+ return "<w:b/>";
4308
+ case "italic":
4309
+ return "<w:i/>";
4310
+ case "underline":
4311
+ return `<w:u w:val="single"/>`;
4312
+ case "strikethrough":
4313
+ return "<w:strike/>";
4314
+ case "doubleStrikethrough":
4315
+ return "<w:dstrike/>";
4316
+ case "vanish":
4317
+ return "<w:vanish/>";
4318
+ case "lang":
4319
+ return `<w:lang w:val="${escapeXmlAttribute2(mark.val)}"/>`;
4320
+ case "highlight":
4321
+ return `<w:highlight w:val="${escapeXmlAttribute2(mark.val)}"/>`;
4322
+ case "backgroundColor":
4323
+ return `<w:shd w:val="clear" w:color="auto" w:fill="${escapeXmlAttribute2(mark.color)}"/>`;
4324
+ case "charSpacing":
4325
+ return `<w:spacing w:val="${mark.val}"/>`;
4326
+ case "kerning":
4327
+ return `<w:kern w:val="${mark.val}"/>`;
4328
+ case "emboss":
4329
+ return "<w:emboss/>";
4330
+ case "imprint":
4331
+ return "<w:imprint/>";
4332
+ case "shadow":
4333
+ return "<w:shadow/>";
4334
+ case "position":
4335
+ return `<w:position w:val="${mark.val}"/>`;
4336
+ case "textFill":
4337
+ return mark.xml;
4338
+ case "fontFamily":
4339
+ return `<w:rFonts w:ascii="${escapeXmlAttribute2(mark.val)}" w:hAnsi="${escapeXmlAttribute2(mark.val)}"/>`;
4340
+ case "fontSize":
4341
+ return `<w:sz w:val="${mark.val}"/>`;
4342
+ case "textColor":
4343
+ return `<w:color w:val="${escapeXmlAttribute2(mark.color)}"/>`;
4344
+ case "smallCaps":
4345
+ return "<w:smallCaps/>";
4346
+ case "allCaps":
4347
+ return "<w:caps/>";
4348
+ }
4349
+ }
4287
4350
  function requiresPreservedSpace(text) {
4288
4351
  return /^\s/.test(text) || /\s$/.test(text) || text.includes(" ");
4289
4352
  }
@@ -7391,6 +7454,13 @@ function buildParagraphPropertiesXml2(paragraph) {
7391
7454
  const frameXml = buildFrameXml(paragraph.frameProperties);
7392
7455
  if (frameXml) parts.push(frameXml);
7393
7456
  }
7457
+ if (paragraph.tabStops && paragraph.tabStops.length > 0) {
7458
+ const tabsXml = paragraph.tabStops.map((tab) => {
7459
+ const leaderAttr = tab.leader ? ` w:leader="${escapeXmlAttribute2(tab.leader)}"` : "";
7460
+ return `<w:tab w:val="${escapeXmlAttribute2(tab.align)}" w:pos="${twip(tab.position)}"${leaderAttr}/>`;
7461
+ }).join("");
7462
+ parts.push(`<w:tabs>${tabsXml}</w:tabs>`);
7463
+ }
7394
7464
  if (paragraph.spacing) {
7395
7465
  const s = paragraph.spacing;
7396
7466
  const attrs = [];
@@ -7412,13 +7482,6 @@ function buildParagraphPropertiesXml2(paragraph) {
7412
7482
  if (paragraph.alignment) {
7413
7483
  parts.push(`<w:jc w:val="${escapeXmlAttribute2(paragraph.alignment)}"/>`);
7414
7484
  }
7415
- if (paragraph.tabStops && paragraph.tabStops.length > 0) {
7416
- const tabsXml = paragraph.tabStops.map((tab) => {
7417
- const leaderAttr = tab.leader ? ` w:leader="${escapeXmlAttribute2(tab.leader)}"` : "";
7418
- return `<w:tab w:val="${tab.align}" w:pos="${twip(tab.position)}"${leaderAttr}/>`;
7419
- }).join("");
7420
- parts.push(`<w:tabs>${tabsXml}</w:tabs>`);
7421
- }
7422
7485
  return parts.length > 0 ? `<w:pPr>${parts.join("")}</w:pPr>` : "";
7423
7486
  }
7424
7487
  function serializeInlineNode2(node) {
@@ -7487,51 +7550,60 @@ function buildRunPropertiesXml2(marks) {
7487
7550
  if (!marks || marks.length === 0) {
7488
7551
  return "";
7489
7552
  }
7553
+ const orderedTypes = [
7554
+ "fontFamily",
7555
+ "bold",
7556
+ "italic",
7557
+ "allCaps",
7558
+ "smallCaps",
7559
+ "strikethrough",
7560
+ "doubleStrikethrough",
7561
+ "textColor",
7562
+ "fontSize",
7563
+ "highlight",
7564
+ "underline",
7565
+ "backgroundColor"
7566
+ ];
7490
7567
  const parts = [];
7491
- for (const mark of marks) {
7492
- switch (mark.type) {
7493
- case "bold":
7494
- parts.push("<w:b/>");
7495
- break;
7496
- case "italic":
7497
- parts.push("<w:i/>");
7498
- break;
7499
- case "underline":
7500
- parts.push('<w:u w:val="single"/>');
7501
- break;
7502
- case "strikethrough":
7503
- parts.push("<w:strike/>");
7504
- break;
7505
- case "doubleStrikethrough":
7506
- parts.push("<w:dstrike/>");
7507
- break;
7508
- case "fontFamily":
7509
- parts.push(`<w:rFonts w:ascii="${escapeXmlAttribute2(mark.val)}" w:hAnsi="${escapeXmlAttribute2(mark.val)}"/>`);
7510
- break;
7511
- case "fontSize":
7512
- parts.push(`<w:sz w:val="${twip(mark.val)}"/>`);
7513
- break;
7514
- case "textColor":
7515
- parts.push(`<w:color w:val="${escapeXmlAttribute2(mark.color)}"/>`);
7516
- break;
7517
- case "highlight":
7518
- parts.push(`<w:highlight w:val="${escapeXmlAttribute2(mark.val)}"/>`);
7519
- break;
7520
- case "backgroundColor":
7521
- parts.push(`<w:shd w:val="clear" w:color="auto" w:fill="${escapeXmlAttribute2(mark.color)}"/>`);
7522
- break;
7523
- case "smallCaps":
7524
- parts.push("<w:smallCaps/>");
7525
- break;
7526
- case "allCaps":
7527
- parts.push("<w:caps/>");
7528
- break;
7529
- default:
7530
- break;
7568
+ for (const type of orderedTypes) {
7569
+ for (const mark of marks) {
7570
+ if (mark.type !== type) continue;
7571
+ const xml = serializeRunPropertyMark2(mark);
7572
+ if (xml) parts.push(xml);
7531
7573
  }
7532
7574
  }
7533
7575
  return parts.length > 0 ? `<w:rPr>${parts.join("")}</w:rPr>` : "";
7534
7576
  }
7577
+ function serializeRunPropertyMark2(mark) {
7578
+ switch (mark.type) {
7579
+ case "bold":
7580
+ return "<w:b/>";
7581
+ case "italic":
7582
+ return "<w:i/>";
7583
+ case "underline":
7584
+ return `<w:u w:val="single"/>`;
7585
+ case "strikethrough":
7586
+ return "<w:strike/>";
7587
+ case "doubleStrikethrough":
7588
+ return "<w:dstrike/>";
7589
+ case "fontFamily":
7590
+ return `<w:rFonts w:ascii="${escapeXmlAttribute2(mark.val)}" w:hAnsi="${escapeXmlAttribute2(mark.val)}"/>`;
7591
+ case "fontSize":
7592
+ return `<w:sz w:val="${twip(mark.val)}"/>`;
7593
+ case "textColor":
7594
+ return `<w:color w:val="${escapeXmlAttribute2(mark.color)}"/>`;
7595
+ case "highlight":
7596
+ return `<w:highlight w:val="${escapeXmlAttribute2(mark.val)}"/>`;
7597
+ case "backgroundColor":
7598
+ return `<w:shd w:val="clear" w:color="auto" w:fill="${escapeXmlAttribute2(mark.color)}"/>`;
7599
+ case "smallCaps":
7600
+ return "<w:smallCaps/>";
7601
+ case "allCaps":
7602
+ return "<w:caps/>";
7603
+ default:
7604
+ return "";
7605
+ }
7606
+ }
7535
7607
  function requiresPreservedSpace3(text) {
7536
7608
  return text.length > 0 && (text[0] === " " || text[text.length - 1] === " " || text.includes(" "));
7537
7609
  }
@@ -7705,9 +7777,6 @@ function buildParagraphPropertiesXml3(paragraph) {
7705
7777
  const frameXml = buildFrameXml(paragraph.frameProperties);
7706
7778
  if (frameXml) parts.push(frameXml);
7707
7779
  }
7708
- if (paragraph.alignment) {
7709
- parts.push(`<w:jc w:val="${escapeXmlAttribute2(paragraph.alignment)}"/>`);
7710
- }
7711
7780
  if (paragraph.spacing) {
7712
7781
  const attrs = [];
7713
7782
  if (paragraph.spacing.before !== void 0) attrs.push(`w:before="${twip(paragraph.spacing.before)}"`);
@@ -7728,6 +7797,9 @@ function buildParagraphPropertiesXml3(paragraph) {
7728
7797
  parts.push(`<w:ind ${attrs.join(" ")}/>`);
7729
7798
  }
7730
7799
  }
7800
+ if (paragraph.alignment) {
7801
+ parts.push(`<w:jc w:val="${escapeXmlAttribute2(paragraph.alignment)}"/>`);
7802
+ }
7731
7803
  return parts.length > 0 ? `<w:pPr>${parts.join("")}</w:pPr>` : "";
7732
7804
  }
7733
7805
  function serializeInlineNode3(node) {
@@ -7788,47 +7860,59 @@ function buildRunPropertiesXml3(marks) {
7788
7860
  if (!marks || marks.length === 0) {
7789
7861
  return "";
7790
7862
  }
7791
- const parts = [];
7863
+ const orderedTypes = [
7864
+ "fontFamily",
7865
+ "bold",
7866
+ "italic",
7867
+ "allCaps",
7868
+ "smallCaps",
7869
+ "strikethrough",
7870
+ "doubleStrikethrough",
7871
+ "textColor",
7872
+ "fontSize",
7873
+ "underline"
7874
+ ];
7875
+ const supportedTypes = new Set(orderedTypes);
7792
7876
  for (const mark of marks) {
7793
- switch (mark.type) {
7794
- case "bold":
7795
- parts.push("<w:b/>");
7796
- break;
7797
- case "italic":
7798
- parts.push("<w:i/>");
7799
- break;
7800
- case "underline":
7801
- parts.push('<w:u w:val="single"/>');
7802
- break;
7803
- case "strikethrough":
7804
- parts.push("<w:strike/>");
7805
- break;
7806
- case "doubleStrikethrough":
7807
- parts.push("<w:dstrike/>");
7808
- break;
7809
- case "fontFamily":
7810
- parts.push(
7811
- `<w:rFonts w:ascii="${escapeXmlAttribute2(mark.val)}" w:hAnsi="${escapeXmlAttribute2(mark.val)}"/>`
7812
- );
7813
- break;
7814
- case "fontSize":
7815
- parts.push(`<w:sz w:val="${twip(mark.val)}"/>`);
7816
- break;
7817
- case "textColor":
7818
- parts.push(`<w:color w:val="${escapeXmlAttribute2(mark.color)}"/>`);
7819
- break;
7820
- case "smallCaps":
7821
- parts.push("<w:smallCaps/>");
7822
- break;
7823
- case "allCaps":
7824
- parts.push("<w:caps/>");
7825
- break;
7826
- default:
7827
- throw new Error(`Cannot safely serialize ${mark.type} marks in note sub-parts.`);
7877
+ if (!supportedTypes.has(mark.type)) {
7878
+ throw new Error(`Cannot safely serialize ${mark.type} marks in note sub-parts.`);
7879
+ }
7880
+ }
7881
+ const parts = [];
7882
+ for (const type of orderedTypes) {
7883
+ for (const mark of marks) {
7884
+ if (mark.type !== type) continue;
7885
+ parts.push(serializeRunPropertyMark3(mark));
7828
7886
  }
7829
7887
  }
7830
7888
  return parts.length > 0 ? `<w:rPr>${parts.join("")}</w:rPr>` : "";
7831
7889
  }
7890
+ function serializeRunPropertyMark3(mark) {
7891
+ switch (mark.type) {
7892
+ case "bold":
7893
+ return "<w:b/>";
7894
+ case "italic":
7895
+ return "<w:i/>";
7896
+ case "underline":
7897
+ return `<w:u w:val="single"/>`;
7898
+ case "strikethrough":
7899
+ return "<w:strike/>";
7900
+ case "doubleStrikethrough":
7901
+ return "<w:dstrike/>";
7902
+ case "fontFamily":
7903
+ return `<w:rFonts w:ascii="${escapeXmlAttribute2(mark.val)}" w:hAnsi="${escapeXmlAttribute2(mark.val)}"/>`;
7904
+ case "fontSize":
7905
+ return `<w:sz w:val="${twip(mark.val)}"/>`;
7906
+ case "textColor":
7907
+ return `<w:color w:val="${escapeXmlAttribute2(mark.color)}"/>`;
7908
+ case "smallCaps":
7909
+ return "<w:smallCaps/>";
7910
+ case "allCaps":
7911
+ return "<w:caps/>";
7912
+ default:
7913
+ throw new Error(`Cannot safely serialize ${mark.type} marks in note sub-parts.`);
7914
+ }
7915
+ }
7832
7916
  function compareNoteIds(left, right) {
7833
7917
  return Number.parseInt(left.noteId, 10) - Number.parseInt(right.noteId, 10);
7834
7918
  }
@@ -12816,6 +12900,7 @@ function collectCanonicalLayoutInputs(doc) {
12816
12900
  const blockContexts = collectStoryBlockContexts(doc);
12817
12901
  return {
12818
12902
  stories: collectCanonicalStoryIdentities(doc),
12903
+ layoutIdentities: collectLayoutInputIdentities(doc, blockContexts),
12819
12904
  fieldRegions: collectCanonicalFieldRegionIdentities(doc),
12820
12905
  numbering: collectCanonicalNumberingLayoutInputs(doc, blockContexts),
12821
12906
  tables: collectCanonicalTableLayoutInputs(blockContexts),
@@ -12824,6 +12909,116 @@ function collectCanonicalLayoutInputs(doc) {
12824
12909
  editableTargets: collectEditableTargetRefs(doc)
12825
12910
  };
12826
12911
  }
12912
+ function collectLayoutInputIdentities(doc, contexts = collectStoryBlockContexts(doc)) {
12913
+ const identities = [];
12914
+ const editableTargets = collectEditableTargetRefs(doc);
12915
+ const editableByStoryBlock = new Map(
12916
+ editableTargets.map((target) => [`${target.storyKey}:${target.blockPath}`, target])
12917
+ );
12918
+ for (const context of contexts) {
12919
+ walkBlocks(context.blocks, context.storyKey, context.basePath, {
12920
+ paragraph(paragraph, blockPath) {
12921
+ const styleNumbering = paragraph.numbering === void 0 && paragraph.styleId !== void 0 ? resolveParagraphStyleNumbering(doc, paragraph.styleId) : void 0;
12922
+ const numbering = paragraph.numbering ?? styleNumbering;
12923
+ const editableTargetRef = editableByStoryBlock.get(`${context.storyKey}:${blockPath}`);
12924
+ identities.push(
12925
+ createLayoutInputIdentity({
12926
+ storyKey: context.storyKey,
12927
+ blockPath,
12928
+ block: paragraph,
12929
+ ...editableTargetRef !== void 0 ? { editableTargetRef } : {},
12930
+ ...numbering !== void 0 ? {
12931
+ list: {
12932
+ numberingInstanceId: numbering.numberingInstanceId,
12933
+ level: numbering.level ?? 0,
12934
+ ...paragraph.numbering?.sourceRef !== void 0 ? { markerSourceRef: paragraph.numbering.sourceRef } : {}
12935
+ }
12936
+ } : {}
12937
+ })
12938
+ );
12939
+ },
12940
+ table(table, blockPath) {
12941
+ identities.push(
12942
+ createLayoutInputIdentity({
12943
+ storyKey: context.storyKey,
12944
+ blockPath,
12945
+ block: table,
12946
+ table: { tableBlockPath: blockPath }
12947
+ })
12948
+ );
12949
+ },
12950
+ inline(inline, blockPath, inlinePath) {
12951
+ const objectId = objectIdForInline(inline);
12952
+ if (!objectId) return;
12953
+ const sourceRef = sourceRefForInline(inline);
12954
+ identities.push({
12955
+ storyKey: context.storyKey,
12956
+ blockPath,
12957
+ blockId: `${context.storyKey}:${inlinePath}`,
12958
+ ...sourceRef !== void 0 ? { sourceRef } : {},
12959
+ object: {
12960
+ objectId,
12961
+ ...sourceRef !== void 0 ? { anchorSourceRef: sourceRef } : {}
12962
+ }
12963
+ });
12964
+ }
12965
+ });
12966
+ }
12967
+ return identities;
12968
+ }
12969
+ function createLayoutInputIdentity(input) {
12970
+ const sourceRef = sourceRefForBlock(input.block);
12971
+ const blockId = input.block.type === "paragraph" && input.block.wordExtensionIds?.paraId ? `para:${input.block.wordExtensionIds.paraId}` : sourceRef?.sourceId !== void 0 ? `source:${sourceRef.sourceId}` : `${input.storyKey}:${input.blockPath}`;
12972
+ return {
12973
+ storyKey: input.storyKey,
12974
+ blockPath: input.blockPath,
12975
+ blockId,
12976
+ ...sourceRef !== void 0 ? { sourceRef } : {},
12977
+ ...input.editableTargetRef !== void 0 ? { editableTargetRef: input.editableTargetRef } : {},
12978
+ ...input.table !== void 0 ? { table: input.table } : {},
12979
+ ...input.list !== void 0 ? { list: input.list } : {}
12980
+ };
12981
+ }
12982
+ function sourceRefForBlock(block) {
12983
+ return "sourceRef" in block ? block.sourceRef : void 0;
12984
+ }
12985
+ function sourceRefForInline(inline) {
12986
+ return "sourceRef" in inline ? inline.sourceRef : void 0;
12987
+ }
12988
+ function objectIdForInline(inline) {
12989
+ switch (inline.type) {
12990
+ case "image":
12991
+ return inline.mediaId;
12992
+ case "drawing_frame":
12993
+ return objectIdForDrawingContent(inline.content) ?? inline.sourceRef?.sourceId;
12994
+ case "shape":
12995
+ case "vml_shape":
12996
+ case "wordart":
12997
+ return inline.preserveOnlyObject?.sourceId ?? `raw:${sha256TextHex(inline.rawXml).slice(0, 16)}`;
12998
+ case "chart_preview":
12999
+ case "smartart_preview":
13000
+ return inline.previewMediaId ?? `raw:${sha256TextHex(inline.rawXml).slice(0, 16)}`;
13001
+ case "ole_embed":
13002
+ return inline.relationshipId ?? inline.id ?? inline.sourceRef?.sourceId;
13003
+ case "opaque_inline":
13004
+ return inline.fragmentId;
13005
+ default:
13006
+ return void 0;
13007
+ }
13008
+ }
13009
+ function objectIdForDrawingContent(content) {
13010
+ switch (content.type) {
13011
+ case "picture":
13012
+ return content.mediaId ?? content.packagePartName ?? content.blipRef;
13013
+ case "chart_preview":
13014
+ case "smartart_preview":
13015
+ return content.previewMediaId ?? `raw:${sha256TextHex(content.rawXml).slice(0, 16)}`;
13016
+ case "shape":
13017
+ return content.preserveOnlyObject?.sourceId ?? `raw:${sha256TextHex(content.rawXml).slice(0, 16)}`;
13018
+ case "opaque":
13019
+ return content.preserveOnlyObject?.sourceId ?? `raw:${sha256TextHex(content.rawXml).slice(0, 16)}`;
13020
+ }
13021
+ }
12827
13022
  function collectEditableTargetRefs(doc, cache) {
12828
13023
  const targets = [];
12829
13024
  for (const context of collectStoryBlockContexts(doc)) {
@@ -14923,6 +15118,16 @@ function collectCanonicalNumberingLayoutInputs(doc, contexts = collectStoryBlock
14923
15118
  const instance = doc.numbering.instances[numbering.numberingInstanceId];
14924
15119
  const abstractDefinition = instance?.abstractNumberingId === void 0 ? void 0 : doc.numbering.abstractDefinitions[instance.abstractNumberingId];
14925
15120
  inputs.push({
15121
+ identity: createLayoutInputIdentity({
15122
+ storyKey: context.storyKey,
15123
+ blockPath,
15124
+ block: paragraph,
15125
+ list: {
15126
+ numberingInstanceId: numbering.numberingInstanceId,
15127
+ level: numbering.level ?? 0,
15128
+ ...paragraph.numbering?.sourceRef !== void 0 ? { markerSourceRef: paragraph.numbering.sourceRef } : {}
15129
+ }
15130
+ }),
14926
15131
  numberingKey: `${context.storyKey}:${blockPath}:numbering`,
14927
15132
  storyKey: context.storyKey,
14928
15133
  blockPath,
@@ -15224,6 +15429,12 @@ function projectTableLayoutInput(table, storyKey, blockPath) {
15224
15429
  (row, rowIndex) => projectTableRowLayoutInput(row, tableKey, rowIndex)
15225
15430
  );
15226
15431
  return {
15432
+ identity: createLayoutInputIdentity({
15433
+ storyKey,
15434
+ blockPath,
15435
+ block: table,
15436
+ table: { tableBlockPath: blockPath }
15437
+ }),
15227
15438
  tableKey,
15228
15439
  storyKey,
15229
15440
  blockPath,
@@ -15311,6 +15522,16 @@ function projectDrawingFrameAnchor(node, storyKey, blockPath, inlinePath) {
15311
15522
  const objectKey = `${storyKey}:${inlinePath}`;
15312
15523
  const textBoxBody = projectTextBoxBodyLayoutInput(content, objectKey, sourceRef, `${inlinePath}/txbx`);
15313
15524
  return {
15525
+ identity: {
15526
+ storyKey,
15527
+ blockPath,
15528
+ blockId: objectKey,
15529
+ ...sourceRef !== void 0 ? { sourceRef } : {},
15530
+ object: {
15531
+ objectId: objectKey,
15532
+ ...sourceRef !== void 0 ? { anchorSourceRef: sourceRef } : {}
15533
+ }
15534
+ },
15314
15535
  objectKey,
15315
15536
  storyKey,
15316
15537
  blockPath,
@@ -15432,8 +15653,19 @@ function projectTextBoxRunLayoutInput(inline, paragraphKey, inlineIndex) {
15432
15653
  }
15433
15654
  function projectLegacyImageAnchor(doc, node, storyKey, blockPath, inlinePath) {
15434
15655
  const media = doc.media.items[node.mediaId];
15656
+ const objectKey = `${storyKey}:${inlinePath}`;
15435
15657
  return {
15436
- objectKey: `${storyKey}:${inlinePath}`,
15658
+ identity: {
15659
+ storyKey,
15660
+ blockPath,
15661
+ blockId: objectKey,
15662
+ ...node.sourceRef !== void 0 ? { sourceRef: node.sourceRef } : {},
15663
+ object: {
15664
+ objectId: objectKey,
15665
+ ...node.sourceRef !== void 0 ? { anchorSourceRef: node.sourceRef } : {}
15666
+ }
15667
+ },
15668
+ objectKey,
15437
15669
  storyKey,
15438
15670
  blockPath,
15439
15671
  inlinePath,
@@ -18409,8 +18641,7 @@ function resolveContentType(path, contentTypes) {
18409
18641
  // src/io/ooxml/parse-bookmark-references.ts
18410
18642
  var HYPERLINK_ANCHOR_RE = /<(?:\w+:)?hyperlink\b[^>]*\bw:anchor\s*=\s*"([^"]*)"/gi;
18411
18643
  var INSTR_TEXT_RE = /<(?:\w+:)?instrText\b[^>]*>([\s\S]*?)<\/(?:\w+:)?instrText>/gi;
18412
- var FLD_SIMPLE_INSTR_DOUBLE_RE = /<(?:\w+:)?fldSimple\b[^>]*?\b(?:w:)?instr\s*=\s*"([^"]*)"/gi;
18413
- var FLD_SIMPLE_INSTR_SINGLE_RE = /<(?:\w+:)?fldSimple\b[^>]*?\b(?:w:)?instr\s*=\s*'([^']*)'/gi;
18644
+ var FLD_SIMPLE_INSTR_RE = /<(?:\w+:)?fldSimple\b[^>]*\bw:instr\s*=\s*(["'])([\s\S]*?)\1/gi;
18414
18645
  var TOC_FIELD_RE = /\bTOC\b/;
18415
18646
  var REFLIKE_FIELD_RE = /\b(?:HYPERLINK|REF|PAGEREF|NOTEREF)\s+([A-Za-z0-9_:.\-]+)/g;
18416
18647
  var DATA_BINDING_RE = /<(?:\w+:)?dataBinding\b/i;
@@ -18429,21 +18660,14 @@ function scanBookmarkReferences(documentXml, callerAllowlist = []) {
18429
18660
  }
18430
18661
  INSTR_TEXT_RE.lastIndex = 0;
18431
18662
  while ((m = INSTR_TEXT_RE.exec(documentXml)) !== null) {
18432
- const instrText = m[1] ?? "";
18433
- scanFieldInstruction(instrText, retained, () => {
18434
- retainAllToc = true;
18663
+ retainInstructionReferences(m[1] ?? "", retained, (value) => {
18664
+ retainAllToc = retainAllToc || value;
18435
18665
  });
18436
18666
  }
18437
- FLD_SIMPLE_INSTR_DOUBLE_RE.lastIndex = 0;
18438
- while ((m = FLD_SIMPLE_INSTR_DOUBLE_RE.exec(documentXml)) !== null) {
18439
- scanFieldInstruction(decodeXmlAttribute(m[1] ?? ""), retained, () => {
18440
- retainAllToc = true;
18441
- });
18442
- }
18443
- FLD_SIMPLE_INSTR_SINGLE_RE.lastIndex = 0;
18444
- while ((m = FLD_SIMPLE_INSTR_SINGLE_RE.exec(documentXml)) !== null) {
18445
- scanFieldInstruction(decodeXmlAttribute(m[1] ?? ""), retained, () => {
18446
- retainAllToc = true;
18667
+ FLD_SIMPLE_INSTR_RE.lastIndex = 0;
18668
+ while ((m = FLD_SIMPLE_INSTR_RE.exec(documentXml)) !== null) {
18669
+ retainInstructionReferences(m[2] ?? "", retained, (value) => {
18670
+ retainAllToc = retainAllToc || value;
18447
18671
  });
18448
18672
  }
18449
18673
  retainRevisionBoundedBookmarks(documentXml, retained);
@@ -18453,17 +18677,14 @@ function scanBookmarkReferences(documentXml, callerAllowlist = []) {
18453
18677
  retainAll
18454
18678
  };
18455
18679
  }
18456
- function scanFieldInstruction(instrText, retained, retainToc) {
18457
- if (TOC_FIELD_RE.test(instrText)) retainToc();
18680
+ function retainInstructionReferences(instrText, retained, setRetainAllToc) {
18681
+ if (TOC_FIELD_RE.test(instrText)) setRetainAllToc(true);
18458
18682
  REFLIKE_FIELD_RE.lastIndex = 0;
18459
18683
  let r;
18460
18684
  while ((r = REFLIKE_FIELD_RE.exec(instrText)) !== null) {
18461
18685
  if (r[1]) retained.add(r[1]);
18462
18686
  }
18463
18687
  }
18464
- function decodeXmlAttribute(value) {
18465
- return value.replace(/&quot;/g, '"').replace(/&apos;/g, "'").replace(/&lt;/g, "<").replace(/&gt;/g, ">").replace(/&amp;/g, "&");
18466
- }
18467
18688
  function retainRevisionBoundedBookmarks(documentXml, retained) {
18468
18689
  const starts = /* @__PURE__ */ new Map();
18469
18690
  BOOKMARK_START_RE.lastIndex = 0;
@@ -18852,7 +19073,7 @@ function parseNumberingXml(xml, context) {
18852
19073
  abstractDefinitions[abstractNumberingId] = {
18853
19074
  abstractNumberingId,
18854
19075
  ...context?.partPath !== void 0 ? { sourceRef: createNumberingSourceRef(context.partPath, "abstractNum", rawId, childXmlPath) } : {},
18855
- levels: readLevels(child),
19076
+ levels: readLevels(child, context, childXmlPath, rawId),
18856
19077
  ...nsid ? { nsid } : {},
18857
19078
  ...multiLevelType ? { multiLevelType } : {},
18858
19079
  ...tplc ? { tplc } : {},
@@ -18873,7 +19094,7 @@ function parseNumberingXml(xml, context) {
18873
19094
  numberingInstanceId,
18874
19095
  ...context?.partPath !== void 0 ? { sourceRef: createNumberingSourceRef(context.partPath, "num", rawId, childXmlPath) } : {},
18875
19096
  abstractNumberingId: toCanonicalAbstractNumberingId(rawAbstractId),
18876
- overrides: readOverrides(child)
19097
+ overrides: readOverrides(child, context, childXmlPath, rawId)
18877
19098
  };
18878
19099
  break;
18879
19100
  }
@@ -18894,6 +19115,16 @@ function createNumberingSourceRef(partPath, element, rawId, xmlPath) {
18894
19115
  ...xmlPath !== void 0 ? { xmlPath } : {}
18895
19116
  };
18896
19117
  }
19118
+ function createNumberingChildSourceRef(partPath, element, sourceIdSuffix, xmlPath) {
19119
+ if (partPath === void 0) return void 0;
19120
+ return {
19121
+ sourceId: `part:${partPath}#${sourceIdSuffix}`,
19122
+ partPath,
19123
+ storyKind: "numbering",
19124
+ element,
19125
+ ...xmlPath !== void 0 ? { xmlPath } : {}
19126
+ };
19127
+ }
18897
19128
  function readNumPicBullet(node, numPicBulletId, context, xmlPath) {
18898
19129
  let widthEmu;
18899
19130
  let heightEmu;
@@ -18970,18 +19201,29 @@ function toCanonicalAbstractNumberingId(value) {
18970
19201
  function toCanonicalNumberingInstanceId(value) {
18971
19202
  return value.startsWith("num:") ? value : `num:${value}`;
18972
19203
  }
18973
- function readLevels(abstractNode) {
19204
+ function readLevels(abstractNode, context, abstractXmlPath, rawAbstractId) {
18974
19205
  const levels = [];
19206
+ let levelOrdinal = 0;
18975
19207
  for (const child of abstractNode.children) {
18976
19208
  if (child.type !== "element" || localName(child.name) !== "lvl") {
18977
19209
  continue;
18978
19210
  }
19211
+ levelOrdinal += 1;
18979
19212
  const rawLevel = readStringAttr(child, "w:ilvl");
18980
19213
  const level = rawLevel === void 0 ? void 0 : parseInteger(rawLevel);
18981
19214
  if (level === void 0) {
18982
19215
  continue;
18983
19216
  }
18984
- const definition = readLevelDefinition(child, level);
19217
+ const definition = readLevelDefinition(
19218
+ child,
19219
+ level,
19220
+ createNumberingChildSourceRef(
19221
+ context?.partPath,
19222
+ "lvl",
19223
+ `abstractNum:${rawAbstractId}:lvl:${level}`,
19224
+ `${abstractXmlPath}/lvl[${levelOrdinal}]`
19225
+ )
19226
+ );
18985
19227
  if (!definition) {
18986
19228
  continue;
18987
19229
  }
@@ -18989,12 +19231,14 @@ function readLevels(abstractNode) {
18989
19231
  }
18990
19232
  return levels.sort((left, right) => left.level - right.level);
18991
19233
  }
18992
- function readOverrides(numNode) {
19234
+ function readOverrides(numNode, context, numXmlPath, rawNumId) {
18993
19235
  const overrides = [];
19236
+ let overrideOrdinal = 0;
18994
19237
  for (const child of numNode.children) {
18995
19238
  if (child.type !== "element" || localName(child.name) !== "lvlOverride") {
18996
19239
  continue;
18997
19240
  }
19241
+ overrideOrdinal += 1;
18998
19242
  const rawLevel = readStringAttr(child, "w:ilvl");
18999
19243
  const level = rawLevel === void 0 ? void 0 : parseInteger(rawLevel);
19000
19244
  if (level === void 0) {
@@ -19004,8 +19248,26 @@ function readOverrides(numNode) {
19004
19248
  const rawStart = startOverrideNode ? readStringAttr(startOverrideNode, "w:val") : void 0;
19005
19249
  const startAt = rawStart === void 0 ? void 0 : parseInteger(rawStart);
19006
19250
  const levelDefinitionNode = findChildElementOptional2(child, "lvl");
19007
- const levelDefinition = levelDefinitionNode ? readLevelOverrideDefinition(levelDefinitionNode, level) : void 0;
19251
+ const overrideXmlPath = `${numXmlPath}/lvlOverride[${overrideOrdinal}]`;
19252
+ const levelDefinition = levelDefinitionNode ? readLevelOverrideDefinition(
19253
+ levelDefinitionNode,
19254
+ level,
19255
+ createNumberingChildSourceRef(
19256
+ context?.partPath,
19257
+ "lvl",
19258
+ `num:${rawNumId}:lvlOverride:${level}:lvl`,
19259
+ `${overrideXmlPath}/lvl[1]`
19260
+ )
19261
+ ) : void 0;
19008
19262
  overrides.push({
19263
+ ...context?.partPath !== void 0 ? {
19264
+ sourceRef: createNumberingChildSourceRef(
19265
+ context.partPath,
19266
+ "lvlOverride",
19267
+ `num:${rawNumId}:lvlOverride:${level}`,
19268
+ overrideXmlPath
19269
+ )
19270
+ } : {},
19009
19271
  level,
19010
19272
  ...startAt !== void 0 ? { startAt } : {},
19011
19273
  ...levelDefinition ? { levelDefinition } : {}
@@ -19013,7 +19275,7 @@ function readOverrides(numNode) {
19013
19275
  }
19014
19276
  return overrides.sort((left, right) => left.level - right.level);
19015
19277
  }
19016
- function readLevelDefinition(levelNode, fallbackLevel) {
19278
+ function readLevelDefinition(levelNode, fallbackLevel, sourceRef) {
19017
19279
  const rawLevel = readStringAttr(levelNode, "w:ilvl");
19018
19280
  const level = rawLevel === void 0 ? fallbackLevel : parseInteger(rawLevel);
19019
19281
  if (level === void 0) {
@@ -19043,6 +19305,7 @@ function readLevelDefinition(levelNode, fallbackLevel) {
19043
19305
  const lvlPicBulletNode = findChildElementOptional2(levelNode, "lvlPicBulletId");
19044
19306
  const picBulletId = lvlPicBulletNode ? readStringAttr(lvlPicBulletNode, "w:val") : void 0;
19045
19307
  return {
19308
+ ...sourceRef ? { sourceRef } : {},
19046
19309
  level,
19047
19310
  format,
19048
19311
  text,
@@ -19056,7 +19319,7 @@ function readLevelDefinition(levelNode, fallbackLevel) {
19056
19319
  ...picBulletId !== void 0 ? { picBulletId } : {}
19057
19320
  };
19058
19321
  }
19059
- function readLevelOverrideDefinition(levelNode, fallbackLevel) {
19322
+ function readLevelOverrideDefinition(levelNode, fallbackLevel, sourceRef) {
19060
19323
  const rawLevel = readStringAttr(levelNode, "w:ilvl");
19061
19324
  const level = rawLevel === void 0 ? fallbackLevel : parseInteger(rawLevel);
19062
19325
  if (level === void 0) {
@@ -19090,6 +19353,7 @@ function readLevelOverrideDefinition(levelNode, fallbackLevel) {
19090
19353
  return void 0;
19091
19354
  }
19092
19355
  return {
19356
+ ...sourceRef ? { sourceRef } : {},
19093
19357
  level,
19094
19358
  ...startAt !== void 0 ? { startAt } : {},
19095
19359
  ...format !== void 0 ? { format } : {},
@@ -32578,7 +32842,7 @@ async function computeStructuralHash(blocks) {
32578
32842
  }
32579
32843
 
32580
32844
  // src/runtime/layout/layout-engine-version.ts
32581
- var LAYOUT_ENGINE_VERSION = 88;
32845
+ var LAYOUT_ENGINE_VERSION = 93;
32582
32846
  var LAYCACHE_SCHEMA_VERSION = 12;
32583
32847
 
32584
32848
  // src/runtime/prerender/customxml-cache.ts
@@ -33232,6 +33496,15 @@ var LIST_TEXT_TARGET_KINDS = /* @__PURE__ */ new Set([
33232
33496
  "sdt-paragraph-text",
33233
33497
  "secondary-story-paragraph-text"
33234
33498
  ]);
33499
+ var OBJECT_COMMAND_INTENTS = /* @__PURE__ */ new Set([
33500
+ "image-layout",
33501
+ "image-frame",
33502
+ "chart-edit",
33503
+ "custom-xml-update",
33504
+ "embedded-content-update",
33505
+ "opaque-content-preserve",
33506
+ "object-edit"
33507
+ ]);
33235
33508
  function freezeList(values) {
33236
33509
  return Object.freeze([...values]);
33237
33510
  }
@@ -33776,6 +34049,35 @@ function listStructureCapability(scope, context) {
33776
34049
  ]
33777
34050
  );
33778
34051
  }
34052
+ function objectEditCapability(context) {
34053
+ const objectTargets = (context?.editableTargets?.entries ?? []).filter(
34054
+ (entry) => entry.kind === "object-anchor" || entry.kind === "custom-xml-content" || entry.kind === "opaque-content" || entry.commandFamily === "object" || entry.commandFamily === "preserve-only-refusal" || entry.runtimeCommand.intents.some((intent) => OBJECT_COMMAND_INTENTS.has(intent))
34055
+ );
34056
+ const supportedTargets = objectTargets.filter(
34057
+ (entry) => entry.runtimeCommand.status === "supported" && entry.runtimeCommand.intents.some((intent) => OBJECT_COMMAND_INTENTS.has(intent))
34058
+ );
34059
+ if (supportedTargets.length > 0) {
34060
+ return supportedCommand(
34061
+ "compile-supported:object-edit:editable-target",
34062
+ supportedTargets
34063
+ );
34064
+ }
34065
+ if (objectTargets.length > 0) {
34066
+ const blockers = commandTargetBlockers(objectTargets);
34067
+ return blocked(
34068
+ "compile-blocked:object-edit:target-ref-blocked",
34069
+ blockers.length > 0 ? blockers : ["compile-blocked:object-edit:target-ref-blocked"]
34070
+ );
34071
+ }
34072
+ return unsupported(
34073
+ "compile-unsupported:object-edit:no-target-family",
34074
+ [
34075
+ "compile-unsupported:object-edit:no-target-family",
34076
+ "capability:object-edit:l02-object-target-required",
34077
+ "capability:object-edit:l07-command-support-required"
34078
+ ]
34079
+ );
34080
+ }
33779
34081
  function deriveScopeCapabilities(scope, context = {}) {
33780
34082
  return {
33781
34083
  canReplaceText: replaceTextCapability(scope, context),
@@ -33792,7 +34094,8 @@ function deriveScopeCapabilities(scope, context = {}) {
33792
34094
  canEditTableStructure: tableStructureCapability(scope, context),
33793
34095
  canUseTableContinuationEvidence: tableContinuationEvidenceCapability(scope, context),
33794
34096
  canEditListText: listTextCapability(scope, context),
33795
- canEditListStructure: listStructureCapability(scope, context)
34097
+ canEditListStructure: listStructureCapability(scope, context),
34098
+ canEditObject: objectEditCapability(context)
33796
34099
  };
33797
34100
  }
33798
34101
 
@@ -34041,6 +34344,12 @@ function resolveScopeRange(entry, handle, positionMap) {
34041
34344
  if (inlineRange) return inlineRange;
34042
34345
  return positionMap.blocks.get(entry.blockIndex) ?? null;
34043
34346
  }
34347
+ case "image": {
34348
+ const key = `${entry.blockIndex}:${entry.inlineIndex}`;
34349
+ const inlineRange = positionMap.inlines.get(key);
34350
+ if (inlineRange) return inlineRange;
34351
+ return positionMap.blocks.get(entry.blockIndex) ?? null;
34352
+ }
34044
34353
  case "comment-thread":
34045
34354
  return anchorToRange(entry.thread.anchor);
34046
34355
  case "revision":
@@ -34167,6 +34476,11 @@ function tokensForScope(entry) {
34167
34476
  { kind: "row", index: entry.rowIndex },
34168
34477
  { kind: "cell", index: entry.cellIndex }
34169
34478
  ]);
34479
+ case "image":
34480
+ return Object.freeze([
34481
+ { kind: "block", index: entry.blockIndex },
34482
+ { kind: "inline", index: entry.inlineIndex }
34483
+ ]);
34170
34484
  default:
34171
34485
  return null;
34172
34486
  }
@@ -34250,6 +34564,19 @@ function paragraphHasBookmarkId(paragraph, bookmarkId) {
34250
34564
  function commandActionHandleForAddress(commandFamily, address) {
34251
34565
  return address ? `scope-command:${commandFamily}:${address.addressKey}` : void 0;
34252
34566
  }
34567
+ function layoutIdentityIndexes(document2) {
34568
+ const byTargetKey = /* @__PURE__ */ new Map();
34569
+ const byStoryBlockPath = /* @__PURE__ */ new Map();
34570
+ for (const identity of collectLayoutInputIdentities(document2)) {
34571
+ byStoryBlockPath.set(`${identity.storyKey}:${identity.blockPath}`, identity);
34572
+ const targetKey = identity.editableTargetRef?.targetKey;
34573
+ if (targetKey) byTargetKey.set(targetKey, identity);
34574
+ }
34575
+ return { byTargetKey, byStoryBlockPath };
34576
+ }
34577
+ function layoutIdentityForTarget(target, indexes) {
34578
+ return indexes.byTargetKey.get(target.targetKey) ?? indexes.byStoryBlockPath.get(`${target.storyKey}:${target.blockPath}`);
34579
+ }
34253
34580
  function withCommandAction(evidence, target, canonicalAddress = target.canonicalAddress) {
34254
34581
  if (evidence.status !== "supported" || !canonicalAddress) return evidence;
34255
34582
  return {
@@ -34261,6 +34588,24 @@ function withCommandAction(evidence, target, canonicalAddress = target.canonical
34261
34588
  function commandAddressForTarget(target, scopeKind) {
34262
34589
  return scopeKind === "list-item" && target.listAddress !== void 0 ? target.listAddress : target.canonicalAddress;
34263
34590
  }
34591
+ function freezeCommandIntents(intents) {
34592
+ return Object.freeze([...new Set(intents)]);
34593
+ }
34594
+ function relatedListActionHandlesForTarget(target, primaryAddress) {
34595
+ if (target.commandFamily !== "text-leaf" || target.listAddress === void 0 || !LIST_TEXT_TARGET_KINDS2.has(target.kind) || target.listAddress.addressKey === primaryAddress?.addressKey) {
34596
+ return void 0;
34597
+ }
34598
+ const actionHandle = commandActionHandleForAddress(target.commandFamily, target.listAddress);
34599
+ if (!actionHandle) return void 0;
34600
+ return Object.freeze([
34601
+ {
34602
+ actionHandle,
34603
+ canonicalAddress: target.listAddress,
34604
+ intents: freezeCommandIntents(["list-text-edit", "list-structure-action"]),
34605
+ reason: "l07:list-address-target-supported"
34606
+ }
34607
+ ]);
34608
+ }
34264
34609
  function runtimeTextCommandEvidence(target, workflowBlockers) {
34265
34610
  const shapeIssues = validateEditableTargetRef(target);
34266
34611
  if (shapeIssues.length > 0) {
@@ -34360,13 +34705,16 @@ function runtimeCommandEvidence(target, workflowBlockers, textCommand, scopeKind
34360
34705
  };
34361
34706
  }
34362
34707
  if (target.commandFamily === "text-leaf") {
34708
+ const canonicalAddress = commandAddressForTarget(target, scopeKind);
34709
+ const relatedActionHandles = relatedListActionHandlesForTarget(target, canonicalAddress);
34363
34710
  return withCommandAction({
34364
34711
  status: textCommand.status,
34365
34712
  commandFamily: target.commandFamily,
34366
34713
  intents: commandIntentsForTarget(target, scopeKind),
34367
34714
  reason: textCommand.reason,
34715
+ ...relatedActionHandles !== void 0 ? { relatedActionHandles } : {},
34368
34716
  ...textCommand.blockers ? { blockers: textCommand.blockers } : {}
34369
- }, target, commandAddressForTarget(target, scopeKind));
34717
+ }, target, canonicalAddress);
34370
34718
  }
34371
34719
  if (target.commandFamily === "comment-revision") {
34372
34720
  const isOpen = target.review?.status === "open";
@@ -34691,19 +35039,21 @@ function commandIntentsForTarget(target, scopeKind) {
34691
35039
  if (target.kind === "hyperlink-text") {
34692
35040
  return Object.freeze(["text-leaf-edit", "hyperlink-display-text-edit"]);
34693
35041
  }
34694
- if (target.table?.operationScope === "text") {
34695
- return Object.freeze([
34696
- "text-leaf-edit",
34697
- "table-text-paste",
34698
- "table-text-drop",
34699
- "table-structured-fragment-paste",
34700
- "table-structured-fragment-drop"
34701
- ]);
34702
- }
34703
- if (scopeKind === "list-item" && LIST_TEXT_TARGET_KINDS2.has(target.kind)) {
34704
- return Object.freeze(["text-leaf-edit", "list-text-edit", "list-structure-action"]);
35042
+ {
35043
+ const intents = ["text-leaf-edit"];
35044
+ if (target.table?.operationScope === "text") {
35045
+ intents.push(
35046
+ "table-text-paste",
35047
+ "table-text-drop",
35048
+ "table-structured-fragment-paste",
35049
+ "table-structured-fragment-drop"
35050
+ );
35051
+ }
35052
+ if ((scopeKind === "list-item" || target.listAddress !== void 0) && LIST_TEXT_TARGET_KINDS2.has(target.kind)) {
35053
+ intents.push("list-text-edit", "list-structure-action");
35054
+ }
35055
+ return freezeCommandIntents(intents);
34705
35056
  }
34706
- return Object.freeze(["text-leaf-edit"]);
34707
35057
  case "field":
34708
35058
  return Object.freeze(
34709
35059
  target.field?.fieldFamily === "TOC" ? ["toc-refresh", "field-update"] : ["field-update"]
@@ -34850,7 +35200,7 @@ function readbackForTarget(document2, target, runtimeTextCommand) {
34850
35200
  source: "canonical-text-leaf"
34851
35201
  };
34852
35202
  }
34853
- function projectTarget(document2, target, relation, workflowBlockers, scopeKind) {
35203
+ function projectTarget(document2, target, relation, workflowBlockers, scopeKind, layoutIdentity) {
34854
35204
  const runtimeTextCommand = runtimeTextCommandEvidence(target, workflowBlockers);
34855
35205
  const readback = readbackForTarget(document2, target, runtimeTextCommand);
34856
35206
  return {
@@ -34871,6 +35221,7 @@ function projectTarget(document2, target, relation, workflowBlockers, scopeKind)
34871
35221
  ...target.table ? { table: target.table } : {},
34872
35222
  ...target.editableOwner ? { editableOwner: target.editableOwner } : {},
34873
35223
  ...target.canonicalAddress ? { canonicalAddress: target.canonicalAddress } : {},
35224
+ ...layoutIdentity ? { layoutIdentity } : {},
34874
35225
  staleCheck: target.staleCheck,
34875
35226
  posture: target.posture,
34876
35227
  ...workflowBlockers.length > 0 ? { workflowBlockers: Object.freeze([...workflowBlockers]) } : {},
@@ -34886,7 +35237,7 @@ function deriveScopeEditableTargetEvidence(document2, scope, entry, options = {}
34886
35237
  facts.push(projectWorkflowBlockerFact(fact));
34887
35238
  factsByTargetKey.set(fact.targetKey, facts);
34888
35239
  }
34889
- const entries = collectEditableTargetRefs(document2, options.editableTargetCache).map((target) => {
35240
+ const relatedTargets = collectEditableTargetRefs(document2, options.editableTargetCache).map((target) => {
34890
35241
  const relation = relationForTarget(target, scope, entry);
34891
35242
  if (!relation) return null;
34892
35243
  const workflowBlockers = Object.freeze(
@@ -34894,8 +35245,19 @@ function deriveScopeEditableTargetEvidence(document2, scope, entry, options = {}
34894
35245
  (left, right) => left.source.localeCompare(right.source) || left.blocker.localeCompare(right.blocker) || left.refusalId.localeCompare(right.refusalId)
34895
35246
  )
34896
35247
  );
34897
- return projectTarget(document2, target, relation, workflowBlockers, scope.kind);
34898
- }).filter((target) => target !== null).sort((a, b) => a.targetKey.localeCompare(b.targetKey));
35248
+ return { target, relation, workflowBlockers };
35249
+ }).filter((target) => target !== null);
35250
+ const layoutIndexes = relatedTargets.length > 0 ? layoutIdentityIndexes(document2) : void 0;
35251
+ const entries = relatedTargets.map(
35252
+ ({ target, relation, workflowBlockers }) => projectTarget(
35253
+ document2,
35254
+ target,
35255
+ relation,
35256
+ workflowBlockers,
35257
+ scope.kind,
35258
+ layoutIndexes ? layoutIdentityForTarget(target, layoutIndexes) : void 0
35259
+ )
35260
+ ).sort((a, b) => a.targetKey.localeCompare(b.targetKey));
34899
35261
  const blockers = /* @__PURE__ */ new Set();
34900
35262
  let supportedTextTargetCount = 0;
34901
35263
  for (const target of entries) {
@@ -35913,6 +36275,11 @@ function deriveReplaceability(kind, provenance) {
35913
36275
  level: "preserve-only",
35914
36276
  reason: "field-result-is-computed-preserve-only"
35915
36277
  };
36278
+ case "image":
36279
+ return {
36280
+ level: "preserve-only",
36281
+ reason: "image-object-command-required"
36282
+ };
35916
36283
  case "comment-thread":
35917
36284
  return {
35918
36285
  level: "preserve-only",
@@ -37093,12 +37460,13 @@ function getLevelStartAt(level, levelDefinitions) {
37093
37460
  return levelDefinitions.get(level)?.startAt ?? DEFAULT_NUMBERING_START_AT;
37094
37461
  }
37095
37462
  function getNumberingFormatPosture(format, value) {
37096
- if (!isSupportedNumberingFormat(format)) {
37463
+ const registryEntry = getNumberingFormatRegistryEntry(format);
37464
+ if (!registryEntry || registryEntry.renderSupport === "approximated") {
37097
37465
  return {
37098
37466
  status: "approximated",
37099
37467
  requestedFormat: format,
37100
37468
  renderedFormat: "decimal",
37101
- reason: "unsupported-numbering-format-decimal-fallback"
37469
+ reason: registryEntry?.fallbackReason ?? "unsupported-numbering-format-decimal-fallback"
37102
37470
  };
37103
37471
  }
37104
37472
  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)) {
@@ -37129,56 +37497,148 @@ function renderLevelText(text, counters, levelDefinitions) {
37129
37497
  });
37130
37498
  return rendered.trim().length > 0 ? rendered : null;
37131
37499
  }
37132
- var SUPPORTED_NUMBERING_FORMATS = /* @__PURE__ */ new Set([
37133
- "decimal",
37134
- "decimalZero",
37135
- "upperLetter",
37136
- "lowerLetter",
37137
- "upperRoman",
37138
- "lowerRoman",
37139
- "hex",
37140
- "ordinal",
37141
- "cardinalText",
37142
- "ordinalText",
37143
- "chicago",
37144
- "bullet",
37145
- "none"
37146
- ]);
37147
37500
  function isSupportedNumberingFormat(format) {
37148
- return SUPPORTED_NUMBERING_FORMATS.has(format);
37501
+ return getNumberingFormatRegistryEntry(format)?.renderSupport === "supported";
37502
+ }
37503
+ function getNumberingFormatRegistryEntry(format) {
37504
+ return NUMBERING_FORMAT_REGISTRY.get(format);
37149
37505
  }
37150
37506
  function formatCounter(value, format) {
37151
- switch (format) {
37152
- case "decimal":
37153
- return String(value);
37154
- case "decimalZero":
37155
- return String(value).padStart(2, "0");
37156
- case "upperLetter":
37157
- return toAlphabetic2(value).toUpperCase();
37158
- case "lowerLetter":
37159
- return toAlphabetic2(value).toLowerCase();
37160
- case "upperRoman":
37161
- return toRoman2(value).toUpperCase();
37162
- case "lowerRoman":
37163
- return toRoman2(value).toLowerCase();
37164
- case "hex":
37165
- return value >= 0 ? value.toString(16).toUpperCase() : String(value);
37166
- case "ordinal":
37167
- return toOrdinal2(value);
37168
- case "cardinalText":
37169
- return toCardinalText2(value);
37170
- case "ordinalText":
37171
- return toOrdinalText2(value);
37172
- case "chicago":
37173
- return toChicago2(value);
37174
- case "bullet":
37175
- return "";
37176
- case "none":
37177
- return "";
37178
- default:
37179
- return String(value);
37180
- }
37507
+ return getNumberingFormatRegistryEntry(format)?.render(value) ?? String(value);
37181
37508
  }
37509
+ var exactNumberingFormatEntries = [
37510
+ {
37511
+ format: "decimal",
37512
+ renderSupport: "supported",
37513
+ renderedFormat: "decimal",
37514
+ supportsMutation: true,
37515
+ render: (value) => String(value)
37516
+ },
37517
+ {
37518
+ format: "decimalZero",
37519
+ renderSupport: "supported",
37520
+ renderedFormat: "decimalZero",
37521
+ supportsMutation: true,
37522
+ render: (value) => String(value).padStart(2, "0")
37523
+ },
37524
+ {
37525
+ format: "upperLetter",
37526
+ renderSupport: "supported",
37527
+ renderedFormat: "upperLetter",
37528
+ supportsMutation: true,
37529
+ render: (value) => toAlphabetic2(value).toUpperCase()
37530
+ },
37531
+ {
37532
+ format: "lowerLetter",
37533
+ renderSupport: "supported",
37534
+ renderedFormat: "lowerLetter",
37535
+ supportsMutation: true,
37536
+ render: (value) => toAlphabetic2(value).toLowerCase()
37537
+ },
37538
+ {
37539
+ format: "upperRoman",
37540
+ renderSupport: "supported",
37541
+ renderedFormat: "upperRoman",
37542
+ supportsMutation: true,
37543
+ render: (value) => toRoman2(value).toUpperCase()
37544
+ },
37545
+ {
37546
+ format: "lowerRoman",
37547
+ renderSupport: "supported",
37548
+ renderedFormat: "lowerRoman",
37549
+ supportsMutation: true,
37550
+ render: (value) => toRoman2(value).toLowerCase()
37551
+ },
37552
+ {
37553
+ format: "hex",
37554
+ renderSupport: "supported",
37555
+ renderedFormat: "hex",
37556
+ supportsMutation: true,
37557
+ render: (value) => value >= 0 ? value.toString(16).toUpperCase() : String(value)
37558
+ },
37559
+ {
37560
+ format: "ordinal",
37561
+ renderSupport: "supported",
37562
+ renderedFormat: "ordinal",
37563
+ supportsMutation: true,
37564
+ render: toOrdinal2
37565
+ },
37566
+ {
37567
+ format: "cardinalText",
37568
+ renderSupport: "supported",
37569
+ renderedFormat: "cardinalText",
37570
+ supportsMutation: true,
37571
+ render: toCardinalText2
37572
+ },
37573
+ {
37574
+ format: "ordinalText",
37575
+ renderSupport: "supported",
37576
+ renderedFormat: "ordinalText",
37577
+ supportsMutation: true,
37578
+ render: toOrdinalText2
37579
+ },
37580
+ {
37581
+ format: "chicago",
37582
+ renderSupport: "supported",
37583
+ renderedFormat: "chicago",
37584
+ supportsMutation: true,
37585
+ render: toChicago2
37586
+ },
37587
+ {
37588
+ format: "bullet",
37589
+ renderSupport: "supported",
37590
+ renderedFormat: "bullet",
37591
+ supportsMutation: true,
37592
+ render: () => ""
37593
+ },
37594
+ {
37595
+ format: "none",
37596
+ renderSupport: "supported",
37597
+ renderedFormat: "none",
37598
+ supportsMutation: true,
37599
+ render: () => ""
37600
+ }
37601
+ ];
37602
+ var approximatedDecimalFormats = [
37603
+ "decimalEnclosedCircle",
37604
+ "decimalEnclosedFullstop",
37605
+ "decimalEnclosedParen",
37606
+ "decimalFullWidth",
37607
+ "decimalHalfWidth",
37608
+ "aiueo",
37609
+ "iroha",
37610
+ "ganada",
37611
+ "chosung",
37612
+ "russianLower",
37613
+ "russianUpper",
37614
+ "hebrew1",
37615
+ "hebrew2",
37616
+ "arabicAlpha",
37617
+ "arabicAbjad",
37618
+ "thaiLetters",
37619
+ "thaiNumbers",
37620
+ "hindiLetters",
37621
+ "hindiNumbers",
37622
+ "ideographDigital",
37623
+ "ideographTraditional",
37624
+ "chineseCounting",
37625
+ "japaneseCounting",
37626
+ "japaneseLegal"
37627
+ ];
37628
+ var approximatedNumberingFormatEntries = approximatedDecimalFormats.map((format) => ({
37629
+ format,
37630
+ renderSupport: "approximated",
37631
+ renderedFormat: "decimal",
37632
+ supportsMutation: false,
37633
+ fallbackReason: "unsupported-numbering-format-decimal-fallback",
37634
+ render: (value) => String(value)
37635
+ }));
37636
+ var NUMBERING_FORMAT_REGISTRY = new Map(
37637
+ [...exactNumberingFormatEntries, ...approximatedNumberingFormatEntries].map((entry) => [
37638
+ entry.format,
37639
+ entry
37640
+ ])
37641
+ );
37182
37642
  function toOrdinal2(value) {
37183
37643
  if (value <= 0) return String(value);
37184
37644
  const lastTwo = value % 100;
@@ -37832,12 +38292,36 @@ var DEFAULT_HYPERLINK_COLOR_HEX = "0563C1";
37832
38292
  function resolveHyperlinkRunFormatting(input, catalog, resolver) {
37833
38293
  const augmentedInput = input.characterStyleId === void 0 ? { ...input, characterStyleId: HYPERLINK_CHARACTER_STYLE_ID } : input;
37834
38294
  const cascade = resolveEffectiveRunFormatting(augmentedInput, catalog);
37835
- const resolvedColor = resolveHyperlinkColorHex(cascade, resolver);
38295
+ const resolvedColor = resolveHyperlinkColorHex(
38296
+ stripInheritedColorHexForImplicitHyperlink(input, catalog, cascade),
38297
+ resolver
38298
+ );
37836
38299
  if (resolvedColor && resolvedColor !== cascade.colorHex) {
37837
38300
  return { ...cascade, colorHex: resolvedColor };
37838
38301
  }
37839
38302
  return cascade;
37840
38303
  }
38304
+ function hasDirectNonAutoColor(input) {
38305
+ return Boolean(input.direct?.colorHex && input.direct.colorHex !== "auto");
38306
+ }
38307
+ function characterStyleDeclaresColorHex(styleId, catalog) {
38308
+ if (!catalog) return false;
38309
+ const chain = resolveCharacterStyleChain(styleId, catalog);
38310
+ return chain.some((chainStyleId) => {
38311
+ const colorHex = catalog.characters[chainStyleId]?.runProperties?.colorHex;
38312
+ return Boolean(colorHex && colorHex !== "auto");
38313
+ });
38314
+ }
38315
+ function stripInheritedColorHexForImplicitHyperlink(originalInput, catalog, cascade) {
38316
+ if (originalInput.characterStyleId !== void 0 || hasDirectNonAutoColor(originalInput) || !cascade.colorHex || cascade.colorHex === "auto" || characterStyleDeclaresColorHex(HYPERLINK_CHARACTER_STYLE_ID, catalog)) {
38317
+ return cascade;
38318
+ }
38319
+ const inheritedCascade = resolveEffectiveRunFormatting(originalInput, catalog);
38320
+ if (inheritedCascade.colorHex !== cascade.colorHex) {
38321
+ return cascade;
38322
+ }
38323
+ return { ...cascade, colorHex: void 0 };
38324
+ }
37841
38325
  function resolveHyperlinkColorHex(cascade, resolver) {
37842
38326
  if (cascade.colorHex && cascade.colorHex !== "auto") {
37843
38327
  return cascade.colorHex;
@@ -39092,6 +39576,55 @@ function compileHeadingScope(entry, options = {}) {
39092
39576
  };
39093
39577
  }
39094
39578
 
39579
+ // src/runtime/scopes/scope-kinds/image.ts
39580
+ function imageAltText(image) {
39581
+ if (image.type === "image") return image.altText ?? "";
39582
+ return image.anchor.docPr?.descr ?? image.anchor.docPr?.name ?? "";
39583
+ }
39584
+ function imageMediaId(image) {
39585
+ if (image.type === "image") return image.mediaId;
39586
+ return image.content.type === "picture" ? image.content.mediaId : void 0;
39587
+ }
39588
+ function imageDisplay(image) {
39589
+ if (image.type === "image") return image.display;
39590
+ return image.anchor.display;
39591
+ }
39592
+ function imageSourceKind(image) {
39593
+ return image.type === "image" ? "legacy-image" : "drawing-picture";
39594
+ }
39595
+ function compileImageScope(entry) {
39596
+ const { handle, image } = entry;
39597
+ const altText = imageAltText(image);
39598
+ const mediaId = imageMediaId(image);
39599
+ const display = imageDisplay(image);
39600
+ const sourceKind = imageSourceKind(image);
39601
+ return {
39602
+ handle,
39603
+ kind: "image",
39604
+ classifications: entry.classifications,
39605
+ content: {
39606
+ text: altText,
39607
+ excerpt: buildExcerpt(altText),
39608
+ authority: "structural-summary"
39609
+ },
39610
+ formatting: {},
39611
+ layout: display ? { flowKind: display } : {},
39612
+ geometry: {},
39613
+ workflow: { scopeIds: [], effectiveMode: "edit" },
39614
+ replaceability: deriveReplaceability("image", handle.provenance),
39615
+ audit: {
39616
+ source: "runtime",
39617
+ derivedFrom: [
39618
+ "canonical",
39619
+ `image-source:${sourceKind}`,
39620
+ ...mediaId ? [`media-id:${mediaId}`] : []
39621
+ ],
39622
+ confidence: "medium"
39623
+ },
39624
+ partial: true
39625
+ };
39626
+ }
39627
+
39095
39628
  // src/runtime/scopes/scope-kinds/list-item.ts
39096
39629
  function compileListItemScope(entry, options = {}) {
39097
39630
  const { handle, paragraph } = entry;
@@ -39675,6 +40208,8 @@ function compileScope(entry, optionsOrCatalog) {
39675
40208
  });
39676
40209
  case "field":
39677
40210
  return compileFieldScope(entry);
40211
+ case "image":
40212
+ return compileImageScope(entry);
39678
40213
  case "comment-thread":
39679
40214
  return compileCommentThreadScope(entry);
39680
40215
  case "revision":
@@ -39863,6 +40398,44 @@ function enumerateFieldsInParagraph(paragraph, blockIndex, documentId, parentSco
39863
40398
  }
39864
40399
  return out;
39865
40400
  }
40401
+ function isImageInline(child) {
40402
+ return child.type === "image" || child.type === "drawing_frame" && child.content.type === "picture";
40403
+ }
40404
+ function enumerateImagesInParagraph(paragraph, blockIndex, documentId, parentScopeId) {
40405
+ const out = [];
40406
+ for (let i = 0; i < paragraph.children.length; i += 1) {
40407
+ const child = paragraph.children[i];
40408
+ if (!isImageInline(child)) continue;
40409
+ const semanticPath = [
40410
+ "body",
40411
+ "paragraph",
40412
+ String(blockIndex),
40413
+ "image",
40414
+ String(i)
40415
+ ];
40416
+ const scopeId = `image:${blockIndex}:${i}`;
40417
+ const handle = {
40418
+ scopeId,
40419
+ documentId,
40420
+ storyTarget: MAIN_STORY,
40421
+ semanticPath,
40422
+ parentScopeId,
40423
+ stableRef: { kind: "semantic-path", value: semanticPath.join("/") },
40424
+ provenance: "derived",
40425
+ rangePrecision: "canonical"
40426
+ };
40427
+ out.push({
40428
+ kind: "image",
40429
+ handle,
40430
+ image: child,
40431
+ paragraph,
40432
+ blockIndex,
40433
+ inlineIndex: i,
40434
+ classifications: Object.freeze([])
40435
+ });
40436
+ }
40437
+ return out;
40438
+ }
39866
40439
  function enumerateCommentThreads(document2, documentId) {
39867
40440
  const review = document2.review;
39868
40441
  const comments = review?.comments;
@@ -39993,6 +40566,8 @@ function enumerateScopes(document2, inputs = {}) {
39993
40566
  });
39994
40567
  const fields = enumerateFieldsInParagraph(block, index, documentId, scopeId);
39995
40568
  for (const field of fields) results.push(field);
40569
+ const images = enumerateImagesInParagraph(block, index, documentId, scopeId);
40570
+ for (const image of images) results.push(image);
39996
40571
  continue;
39997
40572
  }
39998
40573
  if (block.type === "table") {
@@ -40444,6 +41019,114 @@ function createIssue(runtime, input) {
40444
41019
  };
40445
41020
  }
40446
41021
 
41022
+ // src/runtime/scopes/object-evidence.ts
41023
+ var OBJECT_INTENTS = /* @__PURE__ */ new Set([
41024
+ "image-layout",
41025
+ "image-frame",
41026
+ "chart-edit",
41027
+ "custom-xml-update",
41028
+ "embedded-content-update",
41029
+ "opaque-content-preserve",
41030
+ "object-edit",
41031
+ "preserve-only-refusal"
41032
+ ]);
41033
+ function unique2(values) {
41034
+ return Object.freeze([...new Set(values.filter((value) => value.length > 0))]);
41035
+ }
41036
+ function isObjectTarget(entry) {
41037
+ return entry.object !== void 0 || entry.kind === "object-anchor" || entry.kind === "custom-xml-content" || entry.kind === "opaque-content" || entry.commandFamily === "object" || entry.runtimeCommand.intents.some((intent) => OBJECT_INTENTS.has(intent));
41038
+ }
41039
+ function blockersFor(entry) {
41040
+ return unique2([
41041
+ ...entry.posture.blockers,
41042
+ ...entry.runtimeCommand.blockers ?? [],
41043
+ ...entry.runtimeTextCommand.blockers ?? [],
41044
+ ...(entry.workflowBlockers ?? []).flatMap((blocker2) => [
41045
+ blocker2.blocker,
41046
+ blocker2.refusalId
41047
+ ]),
41048
+ entry.runtimeCommand.status === "blocked" ? entry.runtimeCommand.reason : ""
41049
+ ]);
41050
+ }
41051
+ function projectEntry2(entry) {
41052
+ const blockers = blockersFor(entry);
41053
+ return {
41054
+ targetKey: entry.targetKey,
41055
+ kind: entry.kind,
41056
+ ...entry.object?.objectKind ? { objectKind: entry.object.objectKind } : {},
41057
+ relation: entry.relation,
41058
+ commandFamily: entry.commandFamily,
41059
+ editability: entry.editability,
41060
+ ...entry.sourceRef ? { sourceRef: entry.sourceRef } : {},
41061
+ ...entry.object ? { object: entry.object } : {},
41062
+ runtimeCommand: entry.runtimeCommand,
41063
+ blockers,
41064
+ ...entry.posture.preserveOnly ? { preserveOnly: true } : {}
41065
+ };
41066
+ }
41067
+ function familyKindFor(entry) {
41068
+ return entry.objectKind ?? "unknown";
41069
+ }
41070
+ function familyStatusFor(entries) {
41071
+ if (entries.some((entry) => entry.runtimeCommand.status === "supported")) {
41072
+ return "supported";
41073
+ }
41074
+ if (entries.length > 0 && entries.every(
41075
+ (entry) => entry.preserveOnly === true || entry.commandFamily === "preserve-only-refusal"
41076
+ )) {
41077
+ return "preserve-only";
41078
+ }
41079
+ return "blocked";
41080
+ }
41081
+ function summarizeFamily(objectKind, entries) {
41082
+ const sortedEntries = [...entries].sort(
41083
+ (left, right) => left.targetKey.localeCompare(right.targetKey)
41084
+ );
41085
+ const preserveOnly = sortedEntries.some((entry) => entry.preserveOnly === true);
41086
+ return {
41087
+ objectKind,
41088
+ status: familyStatusFor(sortedEntries),
41089
+ count: sortedEntries.length,
41090
+ targetKeys: unique2(sortedEntries.map((entry) => entry.targetKey)),
41091
+ relations: unique2(sortedEntries.map((entry) => entry.relation)),
41092
+ commandFamilies: unique2(sortedEntries.map((entry) => entry.commandFamily)),
41093
+ runtimeIntents: unique2(
41094
+ sortedEntries.flatMap((entry) => [...entry.runtimeCommand.intents])
41095
+ ),
41096
+ blockers: unique2(sortedEntries.flatMap((entry) => [...entry.blockers])),
41097
+ ...preserveOnly ? { preserveOnly: true } : {}
41098
+ };
41099
+ }
41100
+ function summarizeFamilies(entries) {
41101
+ const byFamily = /* @__PURE__ */ new Map();
41102
+ for (const entry of entries) {
41103
+ const objectKind = familyKindFor(entry);
41104
+ const bucket = byFamily.get(objectKind);
41105
+ if (bucket) {
41106
+ bucket.push(entry);
41107
+ continue;
41108
+ }
41109
+ byFamily.set(objectKind, [entry]);
41110
+ }
41111
+ return Object.freeze(
41112
+ [...byFamily.entries()].map(([objectKind, familyEntries]) => summarizeFamily(objectKind, familyEntries)).sort((left, right) => left.objectKind.localeCompare(right.objectKind))
41113
+ );
41114
+ }
41115
+ function deriveScopeObjectEvidence(editableTargets) {
41116
+ const entries = Object.freeze(
41117
+ [...editableTargets?.entries ?? []].filter(isObjectTarget).map(projectEntry2).sort((left, right) => left.targetKey.localeCompare(right.targetKey))
41118
+ );
41119
+ const blockers = unique2(entries.flatMap((entry) => [...entry.blockers]));
41120
+ const families = summarizeFamilies(entries);
41121
+ return {
41122
+ status: entries.length > 0 ? "present" : "none",
41123
+ count: entries.length,
41124
+ blockers,
41125
+ families,
41126
+ entries
41127
+ };
41128
+ }
41129
+
40447
41130
  // src/runtime/scopes/evidence.ts
40448
41131
  function anchorRange(anchor) {
40449
41132
  switch (anchor.kind) {
@@ -40626,6 +41309,7 @@ function composeEvidence(inputs) {
40626
41309
  ...editableTargets ? { editableTargets } : {},
40627
41310
  layout
40628
41311
  });
41312
+ const objects = deriveScopeObjectEvidence(editableTargets);
40629
41313
  return {
40630
41314
  formattingSummary: formattingSummaryOf(scope),
40631
41315
  reviewItemIds,
@@ -40636,6 +41320,7 @@ function composeEvidence(inputs) {
40636
41320
  ...adjacentGeometry ? { adjacentGeometry } : {},
40637
41321
  visualization: deriveScopeVisualization(scope),
40638
41322
  ...editableTargets ? { editableTargets } : {},
41323
+ objects,
40639
41324
  ...table ? { table } : {},
40640
41325
  contentControls,
40641
41326
  capabilities,
@@ -40832,6 +41517,10 @@ function extractNLHaystack(entry) {
40832
41517
  }
40833
41518
  return out.slice(0, 200).toLowerCase();
40834
41519
  }
41520
+ case "image": {
41521
+ const text = entry.image.type === "image" ? entry.image.altText ?? "" : entry.image.anchor.docPr?.descr ?? entry.image.anchor.docPr?.name ?? "";
41522
+ return text.slice(0, 200).toLowerCase();
41523
+ }
40835
41524
  case "table":
40836
41525
  case "table-row":
40837
41526
  case "table-cell":
@@ -46433,6 +47122,7 @@ function createEditorSurfaceSnapshot(document2, _selection, activeStory = { kind
46433
47122
  ...options.authorColorPalette ? { authorColorPalette: options.authorColorPalette } : {}
46434
47123
  });
46435
47124
  const editableTargetsByBlockPath = options.editableTargetsByBlockPath ?? indexEditableTargetsByBlockPath(document2);
47125
+ const layoutIdentitiesByBlockPath = options.layoutIdentitiesByBlockPath;
46436
47126
  const activeStoryBlockPathBase = getActiveStoryBlockPathBase(document2, activeStory);
46437
47127
  chartModelStore.beginBuildPass(document2);
46438
47128
  const unsupportedNumberingFormatsSeen = options.emitFormattingTelemetry ? /* @__PURE__ */ new Set() : null;
@@ -46456,6 +47146,7 @@ function createEditorSurfaceSnapshot(document2, _selection, activeStory = { kind
46456
47146
  activeStory.kind !== "main",
46457
47147
  !isInViewport,
46458
47148
  editableTargetsByBlockPath,
47149
+ layoutIdentitiesByBlockPath,
46459
47150
  `${activeStoryBlockPathBase}/block[${index}]`
46460
47151
  );
46461
47152
  if (isInViewport) {
@@ -46522,7 +47213,7 @@ function isIndexInAnyRange(index, ranges) {
46522
47213
  }
46523
47214
  return false;
46524
47215
  }
46525
- function createSurfaceBlock(block, document2, cursor, counters, formattingContext, promoteSecondaryStoryTextBoxes, cullBuild = false, editableTargetsByBlockPath = EMPTY_EDITABLE_TARGETS_BY_BLOCK_PATH, blockPath) {
47216
+ function createSurfaceBlock(block, document2, cursor, counters, formattingContext, promoteSecondaryStoryTextBoxes, cullBuild = false, editableTargetsByBlockPath = EMPTY_EDITABLE_TARGETS_BY_BLOCK_PATH, layoutIdentitiesByBlockPath, blockPath) {
46526
47217
  if (block.type === "opaque_block") {
46527
47218
  const fragment = getOpaqueFragment(document2.preservation, block.fragmentId);
46528
47219
  const descriptor = fragment ? describeOpaqueFragment(fragment) : null;
@@ -46559,6 +47250,7 @@ function createSurfaceBlock(block, document2, cursor, counters, formattingContex
46559
47250
  promoteSecondaryStoryTextBoxes,
46560
47251
  cullBuild,
46561
47252
  editableTargetsByBlockPath,
47253
+ layoutIdentitiesByBlockPath,
46562
47254
  blockPath
46563
47255
  );
46564
47256
  }
@@ -46599,6 +47291,7 @@ function createSurfaceBlock(block, document2, cursor, counters, formattingContex
46599
47291
  promoteSecondaryStoryTextBoxes,
46600
47292
  cullBuild,
46601
47293
  editableTargetsByBlockPath,
47294
+ layoutIdentitiesByBlockPath,
46602
47295
  blockPath
46603
47296
  );
46604
47297
  }
@@ -46681,10 +47374,11 @@ function createSurfaceBlock(block, document2, cursor, counters, formattingContex
46681
47374
  cullBuild,
46682
47375
  editableTargetsByBlockPath,
46683
47376
  blockPath,
46684
- blockPath !== void 0 ? editableTargetsByBlockPath.get(blockPath) : void 0
47377
+ blockPath !== void 0 ? editableTargetsByBlockPath.get(blockPath) : void 0,
47378
+ blockPath !== void 0 ? layoutIdentitiesByBlockPath?.get(blockPath) : void 0
46685
47379
  );
46686
47380
  }
46687
- function createTableBlock(tableIndex, table, document2, cursor, counters, formattingContext, promoteSecondaryStoryTextBoxes, cullBuild = false, editableTargetsByBlockPath = EMPTY_EDITABLE_TARGETS_BY_BLOCK_PATH, tablePath) {
47381
+ function createTableBlock(tableIndex, table, document2, cursor, counters, formattingContext, promoteSecondaryStoryTextBoxes, cullBuild = false, editableTargetsByBlockPath = EMPTY_EDITABLE_TARGETS_BY_BLOCK_PATH, layoutIdentitiesByBlockPath, tablePath) {
46688
47382
  const lockedFragmentIds = [];
46689
47383
  let innerCursor = cursor;
46690
47384
  if (cullBuild) {
@@ -46701,6 +47395,7 @@ function createTableBlock(tableIndex, table, document2, cursor, counters, format
46701
47395
  promoteSecondaryStoryTextBoxes,
46702
47396
  true,
46703
47397
  editableTargetsByBlockPath,
47398
+ layoutIdentitiesByBlockPath,
46704
47399
  tablePath !== void 0 ? `${tablePath}/row[${rowIndex}]/cell[${cellIndex}]/block[${childIndex}]` : void 0
46705
47400
  );
46706
47401
  lockedFragmentIds.push(...result.lockedFragmentIds);
@@ -46716,6 +47411,7 @@ function createTableBlock(tableIndex, table, document2, cursor, counters, format
46716
47411
  to: innerCursor,
46717
47412
  styleId: table.styleId,
46718
47413
  ...table.sourceRef !== void 0 ? { sourceRef: table.sourceRef } : {},
47414
+ ...tablePath !== void 0 && layoutIdentitiesByBlockPath?.get(tablePath) !== void 0 ? { layoutIdentity: layoutIdentitiesByBlockPath.get(tablePath) } : {},
46719
47415
  gridColumns: table.gridColumns,
46720
47416
  rows: []
46721
47417
  },
@@ -46753,6 +47449,7 @@ function createTableBlock(tableIndex, table, document2, cursor, counters, format
46753
47449
  promoteSecondaryStoryTextBoxes,
46754
47450
  cullBuild,
46755
47451
  editableTargetsByBlockPath,
47452
+ layoutIdentitiesByBlockPath,
46756
47453
  tablePath !== void 0 ? `${tablePath}/row[${rowIndex}]/cell[${cellIndex}]/block[${childIndex}]` : void 0
46757
47454
  );
46758
47455
  cellContent.push(result.block);
@@ -46841,6 +47538,7 @@ function createTableBlock(tableIndex, table, document2, cursor, counters, format
46841
47538
  to: innerCursor,
46842
47539
  styleId: table.styleId,
46843
47540
  ...table.sourceRef !== void 0 ? { sourceRef: table.sourceRef } : {},
47541
+ ...tablePath !== void 0 && layoutIdentitiesByBlockPath?.get(tablePath) !== void 0 ? { layoutIdentity: layoutIdentitiesByBlockPath.get(tablePath) } : {},
46844
47542
  gridColumns: table.gridColumns,
46845
47543
  ...gridColumnsRelative ? { gridColumnsRelative } : {},
46846
47544
  ...resolvedTable.table?.alignment ? { alignment: resolvedTable.table.alignment } : {},
@@ -47028,7 +47726,7 @@ function resolveCellBorderStyles(borders, tableBorders, position) {
47028
47726
  if (left) result.borderLeft = left;
47029
47727
  return result;
47030
47728
  }
47031
- function createSdtBlock(sdtIndex, block, document2, cursor, counters, formattingContext, promoteSecondaryStoryTextBoxes, cullBuild = false, editableTargetsByBlockPath = EMPTY_EDITABLE_TARGETS_BY_BLOCK_PATH, sdtPath) {
47729
+ function createSdtBlock(sdtIndex, block, document2, cursor, counters, formattingContext, promoteSecondaryStoryTextBoxes, cullBuild = false, editableTargetsByBlockPath = EMPTY_EDITABLE_TARGETS_BY_BLOCK_PATH, layoutIdentitiesByBlockPath, sdtPath) {
47032
47730
  const children = [];
47033
47731
  const lockedFragmentIds = [];
47034
47732
  let innerCursor = cursor;
@@ -47045,6 +47743,7 @@ function createSdtBlock(sdtIndex, block, document2, cursor, counters, formatting
47045
47743
  promoteSecondaryStoryTextBoxes,
47046
47744
  cullBuild,
47047
47745
  editableTargetsByBlockPath,
47746
+ layoutIdentitiesByBlockPath,
47048
47747
  sdtPath !== void 0 ? `${sdtPath}/block[${childIndex}]` : void 0
47049
47748
  );
47050
47749
  children.push(result.block);
@@ -47087,7 +47786,7 @@ function getRecursableSdtBlockedReasonCode(block) {
47087
47786
  ].filter(Boolean).join(" ").toLowerCase();
47088
47787
  return searchText.includes("table of contents") || /\btoc\b/u.test(searchText) ? "workflow_preserve_only" : null;
47089
47788
  }
47090
- function createParagraphBlock(paragraphIndex, paragraph, document2, start, formattingContext, promoteSecondaryStoryTextBoxes, cullBuild = false, editableTargetsByBlockPath = EMPTY_EDITABLE_TARGETS_BY_BLOCK_PATH, blockPath, editableTarget) {
47789
+ function createParagraphBlock(paragraphIndex, paragraph, document2, start, formattingContext, promoteSecondaryStoryTextBoxes, cullBuild = false, editableTargetsByBlockPath = EMPTY_EDITABLE_TARGETS_BY_BLOCK_PATH, blockPath, editableTarget, layoutIdentity) {
47091
47790
  const themeResolver = formattingContext.theme;
47092
47791
  const effectiveNumbering = formattingContext.resolveEffectiveParagraphNumbering(paragraph);
47093
47792
  let resolvedNumbering = null;
@@ -47110,6 +47809,7 @@ function createParagraphBlock(paragraphIndex, paragraph, document2, start, forma
47110
47809
  from: start,
47111
47810
  to: start,
47112
47811
  ...editableTarget !== void 0 ? { editableTarget } : {},
47812
+ ...layoutIdentity !== void 0 ? { layoutIdentity } : {},
47113
47813
  ...paragraph.styleId ? { styleId: paragraph.styleId } : {},
47114
47814
  ...effectiveNumbering ? { numbering: effectiveNumbering } : {},
47115
47815
  ...resolvedNumbering ? {
@@ -50928,6 +51628,14 @@ function paginateSectionBlocksWithSplits(section, blocks, layout, footnotes, mea
50928
51628
  pushPage(block.from);
50929
51629
  continue;
50930
51630
  }
51631
+ if (isStandalonePageBreakParagraph(block)) {
51632
+ if (columnHeight > 0) {
51633
+ pushPage(nextBoundary);
51634
+ } else {
51635
+ pageStart = Math.max(pageStart, Math.min(nextBoundary, section.end));
51636
+ }
51637
+ break;
51638
+ }
50931
51639
  const effectiveNoteHeight = estimateFootnoteReservation(
50932
51640
  block,
50933
51641
  footnotes,
@@ -51102,6 +51810,21 @@ function hasPageBreak(block) {
51102
51810
  }
51103
51811
  return nestedBlocks(block).some(hasPageBreak);
51104
51812
  }
51813
+ function isStandalonePageBreakParagraph(block) {
51814
+ if (block.kind !== "paragraph") return false;
51815
+ let sawPageBreak = false;
51816
+ for (const segment of block.segments) {
51817
+ if (segment.kind === "opaque_inline" && segment.label === "Page break") {
51818
+ sawPageBreak = true;
51819
+ continue;
51820
+ }
51821
+ if (segment.kind === "text" && segment.text.trim().length === 0) {
51822
+ continue;
51823
+ }
51824
+ return false;
51825
+ }
51826
+ return sawPageBreak;
51827
+ }
51105
51828
  function nestedBlocks(block) {
51106
51829
  if (block.kind === "sdt_block") {
51107
51830
  return block.children;
@@ -52563,6 +53286,9 @@ function projectSurfaceBlocksToPageFragments(surface, pages, splits, columnByBlo
52563
53286
  for (let blockIndex = 0; blockIndex < surface.blocks.length; blockIndex += 1) {
52564
53287
  const block = surface.blocks[blockIndex];
52565
53288
  const blockPath = `main/block[${blockIndex}]`;
53289
+ if (isStandalonePageBreakParagraph2(block)) {
53290
+ continue;
53291
+ }
52566
53292
  if (block.kind === "table") {
52567
53293
  const tableSliceList = splits?.tablesByBlockId.get(block.blockId);
52568
53294
  if (tableSliceList && tableSliceList.length > 1) {
@@ -52648,6 +53374,23 @@ function projectSurfaceBlocksToPageFragments(surface, pages, splits, columnByBlo
52648
53374
  }
52649
53375
  return byPage;
52650
53376
  }
53377
+ function isStandalonePageBreakParagraph2(block) {
53378
+ if (block.kind !== "paragraph") {
53379
+ return false;
53380
+ }
53381
+ let sawPageBreak = false;
53382
+ for (const segment of block.segments) {
53383
+ if (segment.kind === "opaque_inline" && segment.label === "Page break") {
53384
+ sawPageBreak = true;
53385
+ continue;
53386
+ }
53387
+ if (segment.kind === "text" && segment.text.trim().length === 0) {
53388
+ continue;
53389
+ }
53390
+ return false;
53391
+ }
53392
+ return sawPageBreak;
53393
+ }
52651
53394
  function projectLineBoxesForPageFragments(pages, fragmentsByPageIndex, fragmentMeasurementsByPageIndex, surface) {
52652
53395
  const byPage = /* @__PURE__ */ new Map();
52653
53396
  const blocksById = surface ? new Map(surface.blocks.map((block) => [block.blockId, block])) : /* @__PURE__ */ new Map();
@@ -53160,13 +53903,11 @@ function buildBookmarkRanges(targets) {
53160
53903
  }
53161
53904
  var EMPTY_NUMBERING_INPUT_INDEX = {
53162
53905
  byNumberingKey: /* @__PURE__ */ new Map(),
53163
- byBlockPath: /* @__PURE__ */ new Map(),
53164
- byParagraphIndex: /* @__PURE__ */ new Map()
53906
+ byBlockPath: /* @__PURE__ */ new Map()
53165
53907
  };
53166
53908
  function buildNumberingInputIndex(numberingInputs) {
53167
53909
  const byNumberingKey = /* @__PURE__ */ new Map();
53168
53910
  const byBlockPath = /* @__PURE__ */ new Map();
53169
- const byParagraph = /* @__PURE__ */ new Map();
53170
53911
  for (const input of numberingInputs) {
53171
53912
  if (!byNumberingKey.has(input.numberingKey)) {
53172
53913
  byNumberingKey.set(input.numberingKey, input);
@@ -53174,11 +53915,8 @@ function buildNumberingInputIndex(numberingInputs) {
53174
53915
  if (!byBlockPath.has(input.blockPath)) {
53175
53916
  byBlockPath.set(input.blockPath, input);
53176
53917
  }
53177
- if (!byParagraph.has(input.paragraphIndex)) {
53178
- byParagraph.set(input.paragraphIndex, input);
53179
- }
53180
53918
  }
53181
- return { byNumberingKey, byBlockPath, byParagraphIndex: byParagraph };
53919
+ return { byNumberingKey, byBlockPath };
53182
53920
  }
53183
53921
  function collectBookmarkRangeLayoutFacts(fragmentId, blockPath, bookmarkRanges) {
53184
53922
  if (!blockPath || !bookmarkRanges || bookmarkRanges.length === 0) return [];
@@ -53298,8 +54036,7 @@ function collectNumberingLayoutFactsForBlock(block, blockPath, numberingIndex, n
53298
54036
  const canonical = lookupNumberingInput(
53299
54037
  numberingIndex,
53300
54038
  numberingKey,
53301
- context.path,
53302
- paragraphIndex
54039
+ context.path
53303
54040
  );
53304
54041
  const target = findNumberingTarget(numberingTargets, context.path);
53305
54042
  const numberingLayoutId = numberingKey ?? [
@@ -53339,7 +54076,7 @@ function findNumberingTarget(numberingTargets, blockPath) {
53339
54076
  if (blockPath === void 0) return void 0;
53340
54077
  return numberingTargets.find((target) => target.blockPath === blockPath);
53341
54078
  }
53342
- function lookupNumberingInput(numberingIndex, numberingKey, blockPath, paragraphIndex) {
54079
+ function lookupNumberingInput(numberingIndex, numberingKey, blockPath) {
53343
54080
  if (!numberingIndex) return void 0;
53344
54081
  if (numberingKey !== void 0) {
53345
54082
  const byKey = numberingIndex.byNumberingKey.get(numberingKey);
@@ -53349,7 +54086,7 @@ function lookupNumberingInput(numberingIndex, numberingKey, blockPath, paragraph
53349
54086
  const byPath = numberingIndex.byBlockPath.get(blockPath);
53350
54087
  if (byPath !== void 0) return byPath;
53351
54088
  }
53352
- return paragraphIndex !== void 0 ? numberingIndex.byParagraphIndex.get(paragraphIndex) : void 0;
54089
+ return void 0;
53353
54090
  }
53354
54091
  function collectNumberingUnavailableReasons(numbering, canonical) {
53355
54092
  const reasons = [];
@@ -53739,9 +54476,327 @@ function createEmpiricalProvider() {
53739
54476
  return createEmpiricalBackend();
53740
54477
  }
53741
54478
 
54479
+ // src/runtime/layout/persistent-layout-measurement-cache.ts
54480
+ init_resolved_formatting_state();
54481
+ var DEFAULT_MAX_ENTRIES = 1e4;
54482
+ var DEFAULT_MAX_ESTIMATED_BYTES = 50 * 1024 * 1024;
54483
+ function createPersistentLayoutMeasurementCache(options = {}) {
54484
+ const maxEntries = Math.max(1, options.maxEntries ?? DEFAULT_MAX_ENTRIES);
54485
+ const maxEstimatedBytes = Math.max(
54486
+ 1024,
54487
+ options.maxEstimatedBytes ?? DEFAULT_MAX_ESTIMATED_BYTES
54488
+ );
54489
+ const entries = /* @__PURE__ */ new Map();
54490
+ const counters = {
54491
+ hits: 0,
54492
+ misses: 0,
54493
+ sets: 0,
54494
+ evictions: 0,
54495
+ clears: 0,
54496
+ estimatedBytes: 0,
54497
+ invalidatedByReason: {}
54498
+ };
54499
+ function evictOldest() {
54500
+ const oldest = entries.keys().next();
54501
+ if (oldest.done) return;
54502
+ const entry = entries.get(oldest.value);
54503
+ if (entry) {
54504
+ counters.estimatedBytes -= entry.estimatedBytes;
54505
+ }
54506
+ entries.delete(oldest.value);
54507
+ counters.evictions += 1;
54508
+ }
54509
+ return {
54510
+ get(key) {
54511
+ const cacheKey = serializeCacheKey(key);
54512
+ const entry = entries.get(cacheKey);
54513
+ if (!entry) {
54514
+ counters.misses += 1;
54515
+ return void 0;
54516
+ }
54517
+ entries.delete(cacheKey);
54518
+ entries.set(cacheKey, entry);
54519
+ counters.hits += 1;
54520
+ return entry.value;
54521
+ },
54522
+ set(key, value) {
54523
+ const cacheKey = serializeCacheKey(key);
54524
+ const previous = entries.get(cacheKey);
54525
+ if (previous) {
54526
+ counters.estimatedBytes -= previous.estimatedBytes;
54527
+ entries.delete(cacheKey);
54528
+ }
54529
+ const estimatedBytes = estimateBytes(key, value);
54530
+ entries.set(cacheKey, { key, value, estimatedBytes });
54531
+ counters.estimatedBytes += estimatedBytes;
54532
+ counters.sets += 1;
54533
+ while (entries.size > maxEntries || counters.estimatedBytes > maxEstimatedBytes) {
54534
+ evictOldest();
54535
+ }
54536
+ },
54537
+ invalidate(reason, predicate) {
54538
+ if (!predicate) {
54539
+ const removed2 = entries.size;
54540
+ counters.estimatedBytes = 0;
54541
+ entries.clear();
54542
+ counters.invalidatedByReason[reason] = (counters.invalidatedByReason[reason] ?? 0) + removed2;
54543
+ return;
54544
+ }
54545
+ let removed = 0;
54546
+ for (const [cacheKey, entry] of entries) {
54547
+ if (!predicate(entry.key)) continue;
54548
+ counters.estimatedBytes -= entry.estimatedBytes;
54549
+ entries.delete(cacheKey);
54550
+ removed += 1;
54551
+ }
54552
+ counters.invalidatedByReason[reason] = (counters.invalidatedByReason[reason] ?? 0) + removed;
54553
+ },
54554
+ clear(reason) {
54555
+ const removed = entries.size;
54556
+ counters.estimatedBytes = 0;
54557
+ entries.clear();
54558
+ counters.clears += 1;
54559
+ counters.invalidatedByReason[reason] = (counters.invalidatedByReason[reason] ?? 0) + removed;
54560
+ },
54561
+ stats() {
54562
+ return {
54563
+ hits: counters.hits,
54564
+ misses: counters.misses,
54565
+ sets: counters.sets,
54566
+ evictions: counters.evictions,
54567
+ clears: counters.clears,
54568
+ size: entries.size,
54569
+ estimatedBytes: Math.max(0, counters.estimatedBytes),
54570
+ invalidatedByReason: { ...counters.invalidatedByReason }
54571
+ };
54572
+ }
54573
+ };
54574
+ }
54575
+ function createCachedLayoutMeasurementProvider(delegate, options = {}) {
54576
+ const cache = options.cache ?? createPersistentLayoutMeasurementCache(options);
54577
+ function emitCounter(type, key) {
54578
+ const telemetryBus = options.telemetryBus;
54579
+ if (!telemetryBus?.isEnabled("layout")) return;
54580
+ telemetryBus.emitLazy("layout", () => ({
54581
+ type,
54582
+ payload: key ? {
54583
+ measurementKind: key.measurementKind,
54584
+ blockId: key.blockId,
54585
+ backendVersion: key.backendVersion
54586
+ } : void 0
54587
+ }));
54588
+ }
54589
+ return {
54590
+ get fidelity() {
54591
+ return delegate.fidelity;
54592
+ },
54593
+ measurementCache: cache,
54594
+ measurementCacheStats() {
54595
+ return cache.stats();
54596
+ },
54597
+ whenReady() {
54598
+ return delegate.whenReady();
54599
+ },
54600
+ measureLineFragments(input) {
54601
+ const key = buildLineFragmentsKey(input, delegate, options);
54602
+ const cached = cache.get(key);
54603
+ if (cached) {
54604
+ emitCounter("pageRender.measurement.hit", key);
54605
+ return cloneMeasuredLineFragments(cached);
54606
+ }
54607
+ emitCounter("pageRender.measurement.miss", key);
54608
+ const measured = delegate.measureLineFragments(input);
54609
+ cache.set(key, cloneMeasuredLineFragments(measured));
54610
+ return measured;
54611
+ },
54612
+ measureInlineObject(input) {
54613
+ const key = buildInlineObjectKey(input, delegate, options);
54614
+ const cached = cache.get(key);
54615
+ if (cached) {
54616
+ emitCounter("pageRender.measurement.hit", key);
54617
+ return { ...cached };
54618
+ }
54619
+ emitCounter("pageRender.measurement.miss", key);
54620
+ const measured = delegate.measureInlineObject(input);
54621
+ cache.set(key, { ...measured });
54622
+ return measured;
54623
+ },
54624
+ measureTableBlock(input) {
54625
+ const key = buildTableBlockKey(input, delegate, options);
54626
+ const cached = cache.get(key);
54627
+ if (cached) {
54628
+ emitCounter("pageRender.measurement.hit", key);
54629
+ return cloneMeasuredTableBlock(cached);
54630
+ }
54631
+ emitCounter("pageRender.measurement.miss", key);
54632
+ const measured = delegate.measureTableBlock(input);
54633
+ cache.set(key, cloneMeasuredTableBlock(measured));
54634
+ return measured;
54635
+ },
54636
+ invalidateCache() {
54637
+ delegate.invalidateCache();
54638
+ cache.clear("provider.invalidateCache");
54639
+ emitCounter("pageRender.measurement.invalidated.provider.invalidateCache");
54640
+ }
54641
+ };
54642
+ }
54643
+ function isCachedLayoutMeasurementProvider(provider) {
54644
+ return typeof provider.measurementCacheStats === "function";
54645
+ }
54646
+ function buildLineFragmentsKey(input, delegate, options) {
54647
+ const block = input.block;
54648
+ const identity = measurementIdentityForBlock(block);
54649
+ return {
54650
+ measurementKind: "line-fragments",
54651
+ blockId: identity.blockId,
54652
+ blockPath: identity.blockPath,
54653
+ contentHash: hashStable2({
54654
+ kind: block.kind,
54655
+ identity: identity.identityHash,
54656
+ segments: block.segments,
54657
+ numbering: block.numbering,
54658
+ numberingPrefix: block.numberingPrefix,
54659
+ numberingSuffix: block.numberingSuffix,
54660
+ resolvedNumbering: block.resolvedNumbering
54661
+ }),
54662
+ formattingHash: createLayoutReadyFormattingSnapshot(
54663
+ input.formatting,
54664
+ input.runs
54665
+ ).hash,
54666
+ constraintsHash: hashStable2({ columnWidth: input.columnWidth }),
54667
+ sectionHash: resolveOptionValue(options.sectionHash, "section:provider-input"),
54668
+ fontEpoch: resolveOptionValue(options.fontEpoch, "font:default"),
54669
+ backendVersion: resolveOptionValue(options.backendVersion, delegate.fidelity),
54670
+ displayModeHash: resolveOptionValue(options.displayModeHash, "display:default")
54671
+ };
54672
+ }
54673
+ function buildInlineObjectKey(input, delegate, options) {
54674
+ return {
54675
+ measurementKind: "inline-object",
54676
+ blockId: "inline-object",
54677
+ blockPath: "inline-object",
54678
+ contentHash: hashStable2({ display: input.display }),
54679
+ formattingHash: "format:none",
54680
+ constraintsHash: hashStable2({
54681
+ widthTwips: input.widthTwips,
54682
+ heightTwips: input.heightTwips
54683
+ }),
54684
+ sectionHash: resolveOptionValue(options.sectionHash, "section:provider-input"),
54685
+ fontEpoch: resolveOptionValue(options.fontEpoch, "font:default"),
54686
+ backendVersion: resolveOptionValue(options.backendVersion, delegate.fidelity),
54687
+ displayModeHash: resolveOptionValue(options.displayModeHash, "display:default")
54688
+ };
54689
+ }
54690
+ function buildTableBlockKey(input, delegate, options) {
54691
+ const block = input.block;
54692
+ const identity = measurementIdentityForBlock(block);
54693
+ return {
54694
+ measurementKind: "table-block",
54695
+ blockId: identity.blockId,
54696
+ blockPath: identity.blockPath,
54697
+ contentHash: hashStable2({
54698
+ kind: block.kind,
54699
+ identity: identity.identityHash,
54700
+ rows: block.rows,
54701
+ gridColumns: block.gridColumns,
54702
+ gridColumnsRelative: block.gridColumnsRelative,
54703
+ tableResolved: block.tableResolved,
54704
+ tblLook: block.tblLook
54705
+ }),
54706
+ formattingHash: hashStable2({
54707
+ styleId: block.styleId,
54708
+ alignment: block.alignment
54709
+ }),
54710
+ constraintsHash: hashStable2({ columnWidth: input.columnWidth }),
54711
+ sectionHash: resolveOptionValue(options.sectionHash, "section:provider-input"),
54712
+ fontEpoch: resolveOptionValue(options.fontEpoch, "font:default"),
54713
+ backendVersion: resolveOptionValue(options.backendVersion, delegate.fidelity),
54714
+ displayModeHash: resolveOptionValue(options.displayModeHash, "display:default")
54715
+ };
54716
+ }
54717
+ function measurementIdentityForBlock(block) {
54718
+ const identity = block.layoutIdentity;
54719
+ if (!identity) {
54720
+ return {
54721
+ blockId: block.blockId,
54722
+ blockPath: blockPathForBlock(block),
54723
+ identityHash: "identity:legacy"
54724
+ };
54725
+ }
54726
+ return {
54727
+ blockId: identity.blockId,
54728
+ blockPath: identity.blockPath,
54729
+ identityHash: hashStable2({
54730
+ storyKey: identity.storyKey,
54731
+ blockId: identity.blockId,
54732
+ blockPath: identity.blockPath,
54733
+ sourceRef: identity.sourceRef,
54734
+ table: identity.table,
54735
+ list: identity.list,
54736
+ field: identity.field,
54737
+ object: identity.object
54738
+ })
54739
+ };
54740
+ }
54741
+ function blockPathForBlock(block) {
54742
+ return `${block.from}:${block.to}`;
54743
+ }
54744
+ function resolveOptionValue(option, fallback) {
54745
+ if (typeof option === "function") return option();
54746
+ return option ?? fallback;
54747
+ }
54748
+ function serializeCacheKey(key) {
54749
+ return stableStringify4(key);
54750
+ }
54751
+ function estimateBytes(key, value) {
54752
+ return stableStringify4(key).length + stableStringify4(value).length;
54753
+ }
54754
+ function cloneMeasuredLineFragments(value) {
54755
+ return {
54756
+ lineCount: value.lineCount,
54757
+ maxLineWidth: value.maxLineWidth,
54758
+ lineHeights: [...value.lineHeights]
54759
+ };
54760
+ }
54761
+ function cloneMeasuredTableBlock(value) {
54762
+ return {
54763
+ totalHeightTwips: value.totalHeightTwips,
54764
+ rowHeights: [...value.rowHeights]
54765
+ };
54766
+ }
54767
+ function hashStable2(value) {
54768
+ return fnv1a3(stableStringify4(value)).toString(36);
54769
+ }
54770
+ function stableStringify4(value) {
54771
+ if (value === null || typeof value !== "object") return JSON.stringify(value);
54772
+ if (Array.isArray(value)) {
54773
+ return `[${value.map((item) => stableStringify4(item)).join(",")}]`;
54774
+ }
54775
+ if (value instanceof Map) {
54776
+ return stableStringify4(Array.from(value.entries()));
54777
+ }
54778
+ const object = value;
54779
+ const keys = Object.keys(object).filter((key) => object[key] !== void 0 && typeof object[key] !== "function").sort();
54780
+ return `{${keys.map((key) => `${JSON.stringify(key)}:${stableStringify4(object[key])}`).join(",")}}`;
54781
+ }
54782
+ function fnv1a3(input) {
54783
+ let hash = 2166136261;
54784
+ for (let i = 0; i < input.length; i += 1) {
54785
+ hash ^= input.charCodeAt(i);
54786
+ hash = Math.imul(hash, 16777619);
54787
+ }
54788
+ return hash >>> 0;
54789
+ }
54790
+
53742
54791
  // src/runtime/layout/layout-engine-instance.ts
53743
54792
  var FULL_VIEWPORT_WINDOW_KEY = "full";
53744
54793
  var DEFAULT_VIEWPORT_PAGE_WINDOW_BUFFER = 1;
54794
+ function indexLayoutIdentitiesByBlockPath(identities) {
54795
+ return new Map(identities.map((identity) => [identity.blockPath, identity]));
54796
+ }
54797
+ function indexEditableTargetsByBlockPath2(targets) {
54798
+ return new Map(targets.map((target) => [target.blockPath, target]));
54799
+ }
53745
54800
  function normalizeViewportPageWindow(window2) {
53746
54801
  if (!window2) return void 0;
53747
54802
  const buffer = Number.isFinite(window2.bufferPages) ? Math.max(0, Math.floor(window2.bufferPages ?? 0)) : DEFAULT_VIEWPORT_PAGE_WINDOW_BUFFER;
@@ -53937,8 +54992,22 @@ function recordFullRebuildReason(reasonKind) {
53937
54992
  probe.invalidationCounts[totalKey] = (probe.invalidationCounts[totalKey] ?? 0) + 1;
53938
54993
  probe.invalidationCounts[byReasonKey] = (probe.invalidationCounts[byReasonKey] ?? 0) + 1;
53939
54994
  }
54995
+ function wrapMeasurementProvider(provider, measurementCache, telemetryBus) {
54996
+ if (!measurementCache || isCachedLayoutMeasurementProvider(provider)) {
54997
+ return provider;
54998
+ }
54999
+ const cacheOptions = measurementCache === true ? {} : measurementCache;
55000
+ return createCachedLayoutMeasurementProvider(provider, {
55001
+ ...cacheOptions,
55002
+ ...telemetryBus ? { telemetryBus } : {}
55003
+ });
55004
+ }
53940
55005
  function createLayoutEngine(options = {}) {
53941
- let measurementProvider = options.measurementProvider ?? createEmpiricalMeasurementProvider();
55006
+ let measurementProvider = wrapMeasurementProvider(
55007
+ options.measurementProvider ?? createEmpiricalMeasurementProvider(),
55008
+ options.measurementCache,
55009
+ options.telemetryBus
55010
+ );
53942
55011
  const autoUpgradeToCanvas = options.autoUpgradeToCanvasBackend !== false;
53943
55012
  const telemetryBus = options.telemetryBus;
53944
55013
  const dirtyFieldFamilies = /* @__PURE__ */ new Set();
@@ -54038,13 +55107,20 @@ function createLayoutEngine(options = {}) {
54038
55107
  const pageCountBeforeRecompute = previousPageCount;
54039
55108
  const document2 = input.document;
54040
55109
  const viewportWindow = normalizeViewportPageWindow(input.viewportPageWindow);
55110
+ const layoutInputs = collectCanonicalLayoutInputs(document2);
55111
+ const layoutIdentitiesByBlockPath = indexLayoutIdentitiesByBlockPath(
55112
+ layoutInputs.layoutIdentities
55113
+ );
55114
+ const editableTargetsByBlockPath = indexEditableTargetsByBlockPath2(
55115
+ layoutInputs.editableTargets
55116
+ );
54041
55117
  const mainSurface = createEditorSurfaceSnapshot(
54042
55118
  document2,
54043
55119
  createSelectionSnapshot(0, 0),
54044
- MAIN_STORY_TARGET
55120
+ MAIN_STORY_TARGET,
55121
+ { editableTargetsByBlockPath, layoutIdentitiesByBlockPath }
54045
55122
  );
54046
55123
  const sections = buildResolvedSections(document2);
54047
- const layoutInputs = collectCanonicalLayoutInputs(document2);
54048
55124
  const fieldRegions = layoutInputs.fieldRegions;
54049
55125
  const pageStack = buildPageStackWithSplits(
54050
55126
  document2,
@@ -54156,10 +55232,18 @@ function createLayoutEngine(options = {}) {
54156
55232
  const firstDirty = range.firstPageIndex;
54157
55233
  if (firstDirty < 0 || firstDirty >= priorGraph.pages.length) return null;
54158
55234
  const document2 = input.document;
55235
+ const layoutInputs = collectCanonicalLayoutInputs(document2);
55236
+ const layoutIdentitiesByBlockPath = indexLayoutIdentitiesByBlockPath(
55237
+ layoutInputs.layoutIdentities
55238
+ );
55239
+ const editableTargetsByBlockPath = indexEditableTargetsByBlockPath2(
55240
+ layoutInputs.editableTargets
55241
+ );
54159
55242
  const mainSurface = createEditorSurfaceSnapshot(
54160
55243
  document2,
54161
55244
  createSelectionSnapshot(0, 0),
54162
- MAIN_STORY_TARGET
55245
+ MAIN_STORY_TARGET,
55246
+ { editableTargetsByBlockPath, layoutIdentitiesByBlockPath }
54163
55247
  );
54164
55248
  const sections = buildResolvedSections(document2);
54165
55249
  const dirtyPage = priorGraph.pages[firstDirty];
@@ -54188,7 +55272,6 @@ function createLayoutEngine(options = {}) {
54188
55272
  const freshSnapshotsToRebuild = freshSnapshots.slice(0, convergenceIndex);
54189
55273
  const convergedTailStart = convergenceIndex < freshSnapshots.length ? firstDirty + convergenceIndex : void 0;
54190
55274
  const freshStories = resolvePageStories(freshSnapshotsToRebuild);
54191
- const layoutInputs = collectCanonicalLayoutInputs(document2);
54192
55275
  const fieldRegions = layoutInputs.fieldRegions;
54193
55276
  const freshBodyFragmentsByPageIndex = projectSurfaceBlocksToPageFragments(
54194
55277
  mainSurface,
@@ -54320,7 +55403,11 @@ function createLayoutEngine(options = {}) {
54320
55403
  try {
54321
55404
  const mod = await Promise.resolve().then(() => (init_measurement_backend_canvas(), measurement_backend_canvas_exports));
54322
55405
  const canvasProvider = mod.createCanvasBackend();
54323
- measurementProvider = canvasProvider;
55406
+ measurementProvider = wrapMeasurementProvider(
55407
+ canvasProvider,
55408
+ options.measurementCache,
55409
+ telemetryBus
55410
+ );
54324
55411
  cachedKey = null;
54325
55412
  cachedGraph = null;
54326
55413
  cachedFormatting = null;
@@ -54405,7 +55492,11 @@ function createLayoutEngine(options = {}) {
54405
55492
  },
54406
55493
  swapMeasurementProvider(provider) {
54407
55494
  const previousFidelity = measurementProvider.fidelity;
54408
- measurementProvider = provider;
55495
+ measurementProvider = wrapMeasurementProvider(
55496
+ provider,
55497
+ options.measurementCache,
55498
+ telemetryBus
55499
+ );
54409
55500
  if (previousFidelity !== provider.fidelity) {
54410
55501
  cachedKey = null;
54411
55502
  cachedGraph = null;
@@ -54434,6 +55525,10 @@ function createLayoutEngine(options = {}) {
54434
55525
  cachedFormatting = null;
54435
55526
  cachedMapper = null;
54436
55527
  },
55528
+ getMeasurementCacheStats() {
55529
+ if (!isCachedLayoutMeasurementProvider(measurementProvider)) return null;
55530
+ return measurementProvider.measurementCacheStats();
55531
+ },
54437
55532
  /**
54438
55533
  * L7 Phase 2.5 — seed the cached graph from a prerender envelope.
54439
55534
  * Populates both `cachedGraph` and `cachedKey` (keyed on the provided
@@ -55047,6 +56142,400 @@ function createViewportFamily(runtime) {
55047
56142
  };
55048
56143
  }
55049
56144
 
56145
+ // src/io/ooxml/numbering-catalog-mutation.ts
56146
+ function getListKind(catalog, numberingInstanceId) {
56147
+ const instance = catalog.instances[numberingInstanceId];
56148
+ const definition = instance ? catalog.abstractDefinitions[instance.abstractNumberingId] : void 0;
56149
+ const levelZero = definition?.levels.find((level) => level.level === 0);
56150
+ if (!levelZero) return void 0;
56151
+ return levelZero.format === "bullet" ? "bulleted" : "numbered";
56152
+ }
56153
+
56154
+ // src/api/v3/runtime/lists.ts
56155
+ var SUPPORTED_COMMANDS = [
56156
+ "toggle-numbered",
56157
+ "toggle-bulleted",
56158
+ "indent",
56159
+ "outdent",
56160
+ "restart-numbering",
56161
+ "continue-numbering"
56162
+ ];
56163
+ var UNSUPPORTED_COMMANDS = [
56164
+ "create",
56165
+ "attach",
56166
+ "detach",
56167
+ "join",
56168
+ "separate",
56169
+ "split",
56170
+ "set-value",
56171
+ "apply-template",
56172
+ "capture-template",
56173
+ "apply-preset",
56174
+ "set-level-numbering",
56175
+ "set-level-bullet",
56176
+ "set-level-picture-bullet",
56177
+ "set-level-alignment",
56178
+ "set-level-indents",
56179
+ "set-level-trailing-character",
56180
+ "set-level-marker-font",
56181
+ "set-level-text",
56182
+ "set-level-start",
56183
+ "set-level-layout",
56184
+ "convert-to-text",
56185
+ "paste-fragment",
56186
+ "drop-fragment"
56187
+ ];
56188
+ var applyCommandMetadata = {
56189
+ name: "runtime.lists.applyCommand",
56190
+ status: "live-with-adapter",
56191
+ sourceLayer: "runtime-core",
56192
+ liveEvidence: {
56193
+ runnerTest: "test/api/v3/runtime/lists.test.ts",
56194
+ commit: "refactor-07-runtime-lists-namespace"
56195
+ },
56196
+ uxIntent: {
56197
+ uiVisible: true,
56198
+ expectsUxResponse: "surface-refresh",
56199
+ expectedDelta: "list structure changes through the L07 list command surface"
56200
+ },
56201
+ agentMetadata: { readOrMutate: "mutate", boundedScope: "scope", auditCategory: "list-command" },
56202
+ stateClass: "A-canonical",
56203
+ persistsTo: "canonical",
56204
+ broadcastsVia: "crdt",
56205
+ rwdReference: "\xA7Runtime API \xA7 runtime.lists.applyCommand. Dispatches only proven L07 list commands through opaque list targets; future commands return owner-routed blockers until command/export/readback support lands."
56206
+ };
56207
+ function createListsFamily(runtime) {
56208
+ return {
56209
+ list(input = {}) {
56210
+ const document2 = runtime.getCanonicalDocument();
56211
+ const rows = currentListTargets(document2).filter((entry) => input.storyKey === void 0 || entry.target.storyKey === input.storyKey).map((entry) => toReadback(document2, entry.target, entry.paragraph));
56212
+ return input.limit === void 0 ? rows : rows.slice(0, Math.max(0, input.limit));
56213
+ },
56214
+ get(input) {
56215
+ const resolved = resolveCurrentListTarget(runtime.getCanonicalDocument(), input);
56216
+ return resolved.kind === "resolved" ? toReadback(runtime.getCanonicalDocument(), resolved.target, resolved.paragraph) : null;
56217
+ },
56218
+ previewCommand(input) {
56219
+ return previewListCommand(runtime.getCanonicalDocument(), input);
56220
+ },
56221
+ applyCommand(input) {
56222
+ const preview = previewListCommand(runtime.getCanonicalDocument(), input);
56223
+ if (!preview.supported || !preview.target) {
56224
+ return {
56225
+ applied: false,
56226
+ command: input.command,
56227
+ before: preview.target,
56228
+ blockers: preview.blockers
56229
+ };
56230
+ }
56231
+ const resolved = resolveCurrentListTarget(runtime.getCanonicalDocument(), {
56232
+ addressKey: preview.target.addressKey
56233
+ });
56234
+ if (resolved.kind !== "resolved") {
56235
+ return {
56236
+ applied: false,
56237
+ command: input.command,
56238
+ before: preview.target,
56239
+ blockers: [resolved.blocker]
56240
+ };
56241
+ }
56242
+ const command = editorCommandForListCommand(
56243
+ input.command,
56244
+ resolved.target,
56245
+ runtime.now(),
56246
+ input.startAt
56247
+ );
56248
+ if (!command) {
56249
+ return {
56250
+ applied: false,
56251
+ command: input.command,
56252
+ before: preview.target,
56253
+ blockers: [
56254
+ unsupportedCommandBlocker(input.command, {
56255
+ targetKey: preview.target.targetKey,
56256
+ addressKey: preview.target.addressKey
56257
+ })
56258
+ ]
56259
+ };
56260
+ }
56261
+ const beforeDocument = runtime.getCanonicalDocument();
56262
+ runtime.dispatch(command);
56263
+ const afterDocument = runtime.getCanonicalDocument();
56264
+ const after = resolveCurrentListTarget(afterDocument, { targetKey: preview.target.targetKey });
56265
+ emitUxResponse(runtime, {
56266
+ apiFn: applyCommandMetadata.name,
56267
+ intent: applyCommandMetadata.uxIntent.expectedDelta ?? "",
56268
+ mockOrLive: "live",
56269
+ uiVisible: true,
56270
+ expectedDelta: applyCommandMetadata.uxIntent.expectedDelta
56271
+ });
56272
+ return {
56273
+ applied: beforeDocument !== afterDocument,
56274
+ command: input.command,
56275
+ before: preview.target,
56276
+ ...after.kind === "resolved" ? { after: toReadback(afterDocument, after.target, after.paragraph) } : {},
56277
+ blockers: []
56278
+ };
56279
+ }
56280
+ };
56281
+ }
56282
+ function previewListCommand(document2, input) {
56283
+ const resolved = resolveCurrentListTarget(document2, input);
56284
+ if (resolved.kind !== "resolved") {
56285
+ return {
56286
+ command: input.command,
56287
+ supported: false,
56288
+ affectedTargets: [],
56289
+ blockers: [resolved.blocker]
56290
+ };
56291
+ }
56292
+ const target = toReadback(document2, resolved.target, resolved.paragraph);
56293
+ const targetRef = { targetKey: target.targetKey, addressKey: target.addressKey };
56294
+ if (!SUPPORTED_COMMANDS.includes(input.command)) {
56295
+ return {
56296
+ command: input.command,
56297
+ supported: false,
56298
+ target,
56299
+ affectedTargets: [target],
56300
+ blockers: [unsupportedCommandBlocker(input.command, targetRef)]
56301
+ };
56302
+ }
56303
+ const canContinuePrevious = canContinuePreviousSequence(document2, resolved.paragraphIndex);
56304
+ const canJoin = canJoinPreviousSequence(document2, resolved.paragraphIndex);
56305
+ const blockers = [];
56306
+ if (input.command === "continue-numbering" && !canContinuePrevious) {
56307
+ blockers.push({
56308
+ code: "list-continue-target-missing",
56309
+ ownerLayer: "L07",
56310
+ message: "No previous compatible list sequence is available for continue-numbering.",
56311
+ ...targetRef
56312
+ });
56313
+ }
56314
+ return {
56315
+ command: input.command,
56316
+ supported: blockers.length === 0,
56317
+ target,
56318
+ affectedTargets: [target],
56319
+ blockers,
56320
+ canJoin,
56321
+ canContinuePrevious
56322
+ };
56323
+ }
56324
+ function editorCommandForListCommand(command, editableTarget, timestamp, startAt) {
56325
+ const origin = { source: "api", timestamp };
56326
+ switch (command) {
56327
+ case "toggle-numbered":
56328
+ return { type: "list.toggle", kind: "numbered", editableTargets: [editableTarget], origin };
56329
+ case "toggle-bulleted":
56330
+ return { type: "list.toggle", kind: "bulleted", editableTargets: [editableTarget], origin };
56331
+ case "indent":
56332
+ return { type: "list.indent", editableTargets: [editableTarget], origin };
56333
+ case "outdent":
56334
+ return { type: "list.outdent", editableTargets: [editableTarget], origin };
56335
+ case "restart-numbering":
56336
+ return {
56337
+ type: "list.restart-numbering",
56338
+ editableTarget,
56339
+ ...startAt !== void 0 ? { startAt } : {},
56340
+ origin
56341
+ };
56342
+ case "continue-numbering":
56343
+ return { type: "list.continue-numbering", editableTarget, origin };
56344
+ default:
56345
+ return void 0;
56346
+ }
56347
+ }
56348
+ function resolveCurrentListTarget(document2, input) {
56349
+ if (input.editableTarget) {
56350
+ const shapeIssues = validateEditableTargetRef(input.editableTarget);
56351
+ if (shapeIssues.length > 0) {
56352
+ return {
56353
+ kind: "blocked",
56354
+ blocker: {
56355
+ code: "list-target-malformed",
56356
+ ownerLayer: "L07",
56357
+ message: `List target is malformed: ${shapeIssues[0]?.path ?? "$"}.`,
56358
+ targetKey: input.editableTarget.targetKey,
56359
+ addressKey: input.editableTarget.listAddress?.addressKey
56360
+ }
56361
+ };
56362
+ }
56363
+ }
56364
+ const requestedTargetKey = input.editableTarget?.targetKey ?? input.targetKey;
56365
+ const requestedAddressKey = input.editableTarget?.listAddress?.addressKey ?? input.addressKey;
56366
+ if (!requestedTargetKey && !requestedAddressKey) {
56367
+ return {
56368
+ kind: "blocked",
56369
+ blocker: {
56370
+ code: "list-target-required",
56371
+ ownerLayer: "L07",
56372
+ message: "runtime.lists requires a targetKey, addressKey, or editableTarget."
56373
+ }
56374
+ };
56375
+ }
56376
+ const currentTargets = currentListTargets(document2);
56377
+ const resolved = currentTargets.find(
56378
+ ({ target }) => requestedTargetKey !== void 0 && target.targetKey === requestedTargetKey || requestedAddressKey !== void 0 && target.listAddress?.addressKey === requestedAddressKey
56379
+ );
56380
+ if (!resolved) {
56381
+ return {
56382
+ kind: "blocked",
56383
+ blocker: {
56384
+ code: "list-target-not-found",
56385
+ ownerLayer: "L07",
56386
+ message: "List target no longer resolves in the current canonical document.",
56387
+ ...requestedTargetKey !== void 0 ? { targetKey: requestedTargetKey } : {},
56388
+ ...requestedAddressKey !== void 0 ? { addressKey: requestedAddressKey } : {}
56389
+ }
56390
+ };
56391
+ }
56392
+ if (input.editableTarget && !sameTargetStaleHash(input.editableTarget, resolved.target)) {
56393
+ return {
56394
+ kind: "blocked",
56395
+ blocker: {
56396
+ code: "list-target-stale",
56397
+ ownerLayer: "L07",
56398
+ message: "List target resolved by identity but stale discriminators changed.",
56399
+ targetKey: input.editableTarget.targetKey,
56400
+ addressKey: input.editableTarget.listAddress?.addressKey
56401
+ }
56402
+ };
56403
+ }
56404
+ if (resolved.target.editability !== "editable" || resolved.target.posture.blockers.length > 0) {
56405
+ return {
56406
+ kind: "blocked",
56407
+ blocker: {
56408
+ code: "list-target-non-editable",
56409
+ ownerLayer: "L07",
56410
+ message: resolved.target.posture.blockers.length > 0 ? `List target is not editable: ${resolved.target.posture.blockers.join(", ")}.` : "List target is not editable.",
56411
+ targetKey: resolved.target.targetKey,
56412
+ addressKey: resolved.target.listAddress?.addressKey
56413
+ }
56414
+ };
56415
+ }
56416
+ return { kind: "resolved", ...resolved };
56417
+ }
56418
+ function currentListTargets(document2) {
56419
+ const paragraphs = collectParagraphEntries(document2.content.children, "main");
56420
+ const targets = collectEditableTargetRefs(document2).filter(isListTextTarget);
56421
+ const byBlockPath = /* @__PURE__ */ new Map();
56422
+ for (const target of targets) byBlockPath.set(target.blockPath, target);
56423
+ const out = [];
56424
+ for (let paragraphIndex = 0; paragraphIndex < paragraphs.length; paragraphIndex += 1) {
56425
+ const entry = paragraphs[paragraphIndex];
56426
+ if (!entry?.paragraph.numbering) continue;
56427
+ const target = byBlockPath.get(entry.blockPath);
56428
+ if (!target) continue;
56429
+ out.push({ target, paragraph: entry.paragraph, paragraphIndex });
56430
+ }
56431
+ return out;
56432
+ }
56433
+ function collectParagraphEntries(blocks, basePath) {
56434
+ const out = [];
56435
+ collectParagraphEntriesInto(blocks, basePath, out);
56436
+ return out;
56437
+ }
56438
+ function collectParagraphEntriesInto(blocks, basePath, out) {
56439
+ for (let blockIndex = 0; blockIndex < blocks.length; blockIndex += 1) {
56440
+ const block = blocks[blockIndex];
56441
+ if (!block) continue;
56442
+ const blockPath = `${basePath}/block[${blockIndex}]`;
56443
+ switch (block.type) {
56444
+ case "paragraph":
56445
+ out.push({ paragraph: block, blockPath });
56446
+ break;
56447
+ case "table":
56448
+ for (let rowIndex = 0; rowIndex < block.rows.length; rowIndex += 1) {
56449
+ const row = block.rows[rowIndex];
56450
+ if (!row) continue;
56451
+ for (let cellIndex = 0; cellIndex < row.cells.length; cellIndex += 1) {
56452
+ const cell = row.cells[cellIndex];
56453
+ if (!cell) continue;
56454
+ collectParagraphEntriesInto(
56455
+ cell.children,
56456
+ `${blockPath}/row[${rowIndex}]/cell[${cellIndex}]`,
56457
+ out
56458
+ );
56459
+ }
56460
+ }
56461
+ break;
56462
+ case "sdt":
56463
+ collectParagraphEntriesInto(block.children, blockPath, out);
56464
+ break;
56465
+ case "custom_xml":
56466
+ break;
56467
+ default:
56468
+ break;
56469
+ }
56470
+ }
56471
+ }
56472
+ function isListTextTarget(target) {
56473
+ return target.commandFamily === "text-leaf" && target.listAddress?.operationScope === "list-text" && target.listAddress.addressKind === "list-item-text";
56474
+ }
56475
+ function sameTargetStaleHash(left, right) {
56476
+ return left.targetKey === right.targetKey && left.listAddress?.addressKey === right.listAddress?.addressKey && left.listAddress?.resolver?.staleHash === right.listAddress?.resolver?.staleHash && left.staleCheck.paragraphTextHash === right.staleCheck.paragraphTextHash && left.staleCheck.paragraphTextLength === right.staleCheck.paragraphTextLength && left.staleCheck.inlineCount === right.staleCheck.inlineCount;
56477
+ }
56478
+ function toReadback(document2, target, paragraph) {
56479
+ const numbering = paragraph.numbering;
56480
+ const instance = document2.numbering.instances[numbering.numberingInstanceId];
56481
+ const listKind = instance ? getListKind(document2.numbering, numbering.numberingInstanceId) : void 0;
56482
+ return {
56483
+ targetKey: target.targetKey,
56484
+ actionHandle: `list-action:${target.listAddress.addressKey}`,
56485
+ kind: target.kind,
56486
+ storyKey: target.storyKey,
56487
+ blockPath: target.blockPath,
56488
+ leafPath: target.leafPath,
56489
+ addressKey: target.listAddress.addressKey,
56490
+ numberingInstanceId: numbering.numberingInstanceId,
56491
+ ...instance?.abstractNumberingId ? { abstractNumberingId: instance.abstractNumberingId } : {},
56492
+ level: numbering.level,
56493
+ ...listKind ? { listKind } : {},
56494
+ editability: target.editability,
56495
+ blockers: target.posture.blockers,
56496
+ supportedCommands: SUPPORTED_COMMANDS,
56497
+ unsupportedCommands: UNSUPPORTED_COMMANDS,
56498
+ staleDiscriminators: {
56499
+ paragraphTextHash: target.staleCheck.paragraphTextHash,
56500
+ paragraphTextLength: target.staleCheck.paragraphTextLength,
56501
+ inlineCount: target.staleCheck.inlineCount,
56502
+ listAddressStaleHash: target.listAddress?.resolver?.staleHash
56503
+ }
56504
+ };
56505
+ }
56506
+ function canContinuePreviousSequence(document2, paragraphIndex) {
56507
+ const paragraphs = collectParagraphEntries(document2.content.children, "main");
56508
+ const current = paragraphs[paragraphIndex]?.paragraph;
56509
+ if (!current?.numbering) return false;
56510
+ const currentKind = getListKind(document2.numbering, current.numbering.numberingInstanceId);
56511
+ if (!currentKind) return false;
56512
+ for (let index = paragraphIndex - 1; index >= 0; index -= 1) {
56513
+ const previous = paragraphs[index]?.paragraph;
56514
+ if (!previous?.numbering) continue;
56515
+ const previousKind = getListKind(document2.numbering, previous.numbering.numberingInstanceId);
56516
+ return previousKind === currentKind && previous.numbering.numberingInstanceId !== current.numbering.numberingInstanceId;
56517
+ }
56518
+ return false;
56519
+ }
56520
+ function canJoinPreviousSequence(document2, paragraphIndex) {
56521
+ const paragraphs = collectParagraphEntries(document2.content.children, "main");
56522
+ const current = paragraphs[paragraphIndex]?.paragraph;
56523
+ const previous = paragraphs[paragraphIndex - 1]?.paragraph;
56524
+ if (!current?.numbering || !previous?.numbering) return false;
56525
+ const currentKind = getListKind(document2.numbering, current.numbering.numberingInstanceId);
56526
+ const previousKind = getListKind(document2.numbering, previous.numbering.numberingInstanceId);
56527
+ return Boolean(currentKind) && currentKind === previousKind && current.numbering.numberingInstanceId !== previous.numbering.numberingInstanceId;
56528
+ }
56529
+ function unsupportedCommandBlocker(command, target) {
56530
+ return {
56531
+ code: "list-command-unsupported",
56532
+ ownerLayer: "L07",
56533
+ message: `runtime.lists.${command} is reserved but not implemented by the L07 command surface yet.`,
56534
+ ...target.targetKey !== void 0 ? { targetKey: target.targetKey } : {},
56535
+ ...target.addressKey !== void 0 ? { addressKey: target.addressKey } : {}
56536
+ };
56537
+ }
56538
+
55050
56539
  // src/api/v3/ai/_pe2-evidence.ts
55051
56540
  function copyCoverage(coverage) {
55052
56541
  return {
@@ -57400,6 +58889,17 @@ function createTableActionFamily(runtime) {
57400
58889
  operationScope: target.table?.operationScope
57401
58890
  });
57402
58891
  }
58892
+ if (fragmentContent && fragmentContent.blocks.length === 0) {
58893
+ return blockedResult(input, proposalId, {
58894
+ code: `table-action-structured-fragment-empty:${input.operation.kind}`,
58895
+ category: "unsupported-operation",
58896
+ message: "Structured table text actions require a canonical document fragment with at least one block.",
58897
+ nextStep: 'Retry with operation.content.kind="structured" and a CanonicalDocumentFragment whose blocks array contains the paragraph or table content to paste/drop.',
58898
+ actionHandle: input.actionHandle,
58899
+ operation: input.operation.kind,
58900
+ operationScope: target.table?.operationScope
58901
+ });
58902
+ }
57403
58903
  const resolution2 = resolveEditableTextTarget({
57404
58904
  document: runtime.getCanonicalDocument(),
57405
58905
  surface: runtime.getRenderSnapshot().surface?.blocks ?? [],
@@ -57422,6 +58922,7 @@ function createTableActionFamily(runtime) {
57422
58922
  runtime.dispatch({
57423
58923
  type: "fragment.insert",
57424
58924
  fragment: fragmentContent,
58925
+ selection: createSelectionSnapshot(resolution2.range.to, resolution2.range.to),
57425
58926
  editableTarget: target,
57426
58927
  origin: { source: "api", timestamp: nowUtc }
57427
58928
  });
@@ -57434,6 +58935,17 @@ function createTableActionFamily(runtime) {
57434
58935
  });
57435
58936
  }
57436
58937
  const changed2 = runtime.getCanonicalDocument() !== before2;
58938
+ if (!changed2) {
58939
+ return blockedResult(input, proposalId, {
58940
+ code: `table-action-noop:${input.operation.kind}:${input.actionHandle}`,
58941
+ category: "runtime-noop",
58942
+ message: "The runtime accepted the table text target but the operation produced no document change.",
58943
+ nextStep: "Refresh the table action list and verify the target is still editable, the payload is non-empty when required, and structured fragments are dispatched through a command-safe table text action.",
58944
+ actionHandle: input.actionHandle,
58945
+ operation: input.operation.kind,
58946
+ operationScope: target.table?.operationScope
58947
+ });
58948
+ }
57437
58949
  const afterReadback = tableTextReadback(readEditableTargetText(runtime.getCanonicalDocument(), target));
57438
58950
  return {
57439
58951
  proposalId,
@@ -58041,7 +59553,7 @@ var listOperationMetadata = actionMethodMetadata(
58041
59553
  "listOperation",
58042
59554
  "mutate",
58043
59555
  "actions-list-operation",
58044
- "Apply list toggle, indent, outdent, restart, or continue-numbering commands to paragraph-like scope handles.",
59556
+ "Apply list toggle, indent, outdent, restart, or continue-numbering commands through opaque list action handles or command-safe list scope targets.",
58045
59557
  {
58046
59558
  uiVisible: true,
58047
59559
  expectsUxResponse: "inline-change",
@@ -59776,25 +61288,16 @@ function checkPlanStepCapability(runtime, step, before) {
59776
61288
  return null;
59777
61289
  }
59778
61290
  if (step.kind === "listOperation") {
59779
- const resolved = resolveScopeExactTarget(runtime, step.target, step.kind);
61291
+ const resolved = resolveListOperationTarget(runtime, step.target);
59780
61292
  if (!resolved.ok) return resolved.blockerDetails[0] ?? null;
59781
- const scope = resolved.target.scope;
59782
- if (scope.kind !== "list-item" && scope.kind !== "paragraph" && scope.kind !== "heading") {
59783
- return blocker(
59784
- `actions:list-operation:target-kind-unsupported:${scope.kind}`,
59785
- "unsupported",
59786
- "List operations require a paragraph-like scope handle.",
59787
- "Use ai.actions.locateAll or ai.listScopes to select a paragraph, heading, or list-item handle."
59788
- );
59789
- }
59790
- if (paragraphIndexFromHandle(scope.handle) === null) {
59791
- return blockerWithOwner(
59792
- `actions:list-operation:paragraph-index-unresolved:${scope.handle.scopeId}`,
59793
- "blocked",
59794
- "The list operation target did not resolve to a current paragraph index.",
59795
- "Refresh the scope handle and retry; route persistent failures to L08 scope resolution.",
59796
- "L08 semantic scope compiler"
59797
- );
61293
+ const command = runtimeListCommandForOperation(step.operation);
61294
+ const preview = createListsFamily(runtime).previewCommand({
61295
+ ...resolved.input,
61296
+ command,
61297
+ ...step.operation.kind === "restart-numbering" && step.operation.startAt !== void 0 ? { startAt: step.operation.startAt } : {}
61298
+ });
61299
+ if (preview.blockers.length > 0) {
61300
+ return listBlockerDetails("actions:list-operation:preflight", preview.blockers)[0] ?? null;
59798
61301
  }
59799
61302
  return null;
59800
61303
  }
@@ -59951,70 +61454,253 @@ function applyModeledCommand(runtime, targetInput, kind, commandInput, reference
59951
61454
  };
59952
61455
  }
59953
61456
  function applyListOperation(runtime, input) {
59954
- const resolvedScope = resolveScopeExactTarget(runtime, input.target, "listOperation");
59955
- if (!resolvedScope.ok) return blockedApplyFromResolution(resolvedScope);
61457
+ const resolvedTarget = resolveListOperationTarget(runtime, input.target);
61458
+ if (!resolvedTarget.ok) return blockedApplyFromResolution(resolvedTarget);
61459
+ const command = runtimeListCommandForOperation(input.operation);
61460
+ const result = createListsFamily(runtime).applyCommand({
61461
+ ...resolvedTarget.input,
61462
+ command,
61463
+ ...input.operation.kind === "restart-numbering" && input.operation.startAt !== void 0 ? { startAt: input.operation.startAt } : {}
61464
+ });
61465
+ if (!result.applied) {
61466
+ const details = result.blockers.length > 0 ? listBlockerDetails("actions:list-operation", result.blockers) : [
61467
+ blockerWithOwner(
61468
+ `actions:list-operation:runtime-noop:${resolvedTarget.before?.addressKey ?? "unknown"}`,
61469
+ "blocked",
61470
+ "The runtime list command produced no document change for the selected list target.",
61471
+ "Refresh the list action handle and retry; route persistent failures with before/after readback to L07 runtime list commands.",
61472
+ "L07 runtime list commands"
61473
+ )
61474
+ ];
61475
+ return {
61476
+ status: details.some((detail) => detail.category === "unsupported") ? "unsupported" : "blocked",
61477
+ applied: false,
61478
+ changed: false,
61479
+ target: summarizeListTarget(resolvedTarget, result.before ?? resolvedTarget.before),
61480
+ blockers: Object.freeze(details.map((detail) => detail.code)),
61481
+ blockerDetails: Object.freeze(details),
61482
+ listReadback: listOperationReadback(result, resolvedTarget.before)
61483
+ };
61484
+ }
61485
+ const compiledAfter = resolvedTarget.scopeHandle ? createScopeCompilerService(runtime).compileScopeById(resolvedTarget.scopeHandle.scopeId) : null;
61486
+ const target = compiledAfter ? summarizeTarget({ kind: "scope", scope: compiledAfter.scope, handle: compiledAfter.scope.handle }) : summarizeListTarget(resolvedTarget, result.after ?? result.before ?? resolvedTarget.before);
61487
+ return {
61488
+ status: "applied",
61489
+ applied: true,
61490
+ changed: result.applied,
61491
+ target,
61492
+ commandReference: {
61493
+ command: commandReferenceForListCommand(result.command),
61494
+ actorId: input.actorId ?? "v3-ai-api",
61495
+ origin: input.origin ?? "agent",
61496
+ emittedAtUtc: currentAuditTimestamp(runtime)
61497
+ },
61498
+ listReadback: listOperationReadback(result, resolvedTarget.before)
61499
+ };
61500
+ }
61501
+ function resolveListOperationTarget(runtime, targetInput) {
61502
+ const lists = createListsFamily(runtime);
61503
+ if ("actionHandle" in targetInput) {
61504
+ const addressKey = listAddressKeyFromActionHandle(targetInput.actionHandle);
61505
+ if (!addressKey) {
61506
+ const detail = blockerWithOwner(
61507
+ `actions:list-operation:action-handle-malformed:${targetInput.actionHandle}`,
61508
+ "unsupported",
61509
+ "List operations require an opaque list action handle from runtime.lists or list editable-target evidence.",
61510
+ "Call runtime.lists.list or refresh the scope bundle and retry with a list-action:* or scope-command:text-leaf:* list handle.",
61511
+ "L07 runtime list commands and L08 semantic scopes"
61512
+ );
61513
+ return {
61514
+ ok: false,
61515
+ blockers: Object.freeze([detail.code]),
61516
+ blockerDetails: Object.freeze([detail])
61517
+ };
61518
+ }
61519
+ const before2 = lists.get({ addressKey });
61520
+ if (!before2) {
61521
+ const detail = blockerWithOwner(
61522
+ `actions:list-operation:action-handle-not-found:${targetInput.actionHandle}`,
61523
+ "unresolved-target",
61524
+ "No current list target matches the supplied opaque action handle.",
61525
+ "Refresh runtime.lists.list or the scope bundle, then retry with the current list action handle.",
61526
+ "L07 runtime list commands"
61527
+ );
61528
+ return {
61529
+ ok: false,
61530
+ blockers: Object.freeze([detail.code]),
61531
+ blockerDetails: Object.freeze([detail])
61532
+ };
61533
+ }
61534
+ return { ok: true, input: { addressKey }, before: before2 };
61535
+ }
61536
+ const resolvedScope = resolveScopeExactTarget(runtime, targetInput, "listOperation");
61537
+ if (!resolvedScope.ok) return resolvedScope;
59956
61538
  const scope = resolvedScope.target.scope;
59957
61539
  if (scope.kind !== "list-item" && scope.kind !== "paragraph" && scope.kind !== "heading") {
59958
- return blockedApply(
61540
+ const detail = blocker(
59959
61541
  `actions:list-operation:target-kind-unsupported:${scope.kind}`,
59960
61542
  "unsupported",
59961
- "List operations require a paragraph-like scope handle.",
59962
- "Use ai.actions.locateAll or ai.listScopes to select a paragraph, heading, or list-item handle."
61543
+ "List operations require a list item or command-safe paragraph-like scope target.",
61544
+ "Use ai.actions.locateAll, ai.listScopes, or runtime.lists.list to select a current list item target."
59963
61545
  );
61546
+ return {
61547
+ ok: false,
61548
+ blockers: Object.freeze([detail.code]),
61549
+ blockerDetails: Object.freeze([detail])
61550
+ };
59964
61551
  }
59965
- const paragraphIndex = paragraphIndexFromHandle(scope.handle);
59966
- if (paragraphIndex === null) {
59967
- return blockedApply(
59968
- `actions:list-operation:paragraph-index-unresolved:${scope.handle.scopeId}`,
61552
+ const bundle = createScopeCompilerService(runtime).compileBundleById(
61553
+ scope.handle.scopeId,
61554
+ currentAuditTimestamp(runtime)
61555
+ );
61556
+ const entries = bundle?.evidence.editableTargets?.entries ?? [];
61557
+ const listEntry = entries.find(
61558
+ (entry) => entry.commandFamily === "text-leaf" && entry.runtimeCommand.status === "supported" && entry.runtimeCommand.intents.includes("list-structure-action") && entry.runtimeCommand.canonicalAddress?.operationScope === "list-text" && entry.runtimeCommand.canonicalAddress.addressKind === "list-item-text"
61559
+ );
61560
+ if (!listEntry) {
61561
+ const detail = blockerWithOwner(
61562
+ `actions:list-operation:list-target-missing:${scope.handle.scopeId}`,
59969
61563
  "blocked",
59970
- "The list operation target did not resolve to a current paragraph index.",
59971
- "Refresh the scope handle and retry; route persistent failures to L08 scope resolution.",
59972
- [
59973
- blockerWithOwner(
59974
- `actions:list-operation:paragraph-index-unresolved:${scope.handle.scopeId}`,
59975
- "blocked",
59976
- "The list operation target did not resolve to a current paragraph index.",
59977
- "Refresh the scope handle and retry; route persistent failures to L08 scope resolution.",
59978
- "L08 semantic scope compiler"
59979
- )
59980
- ]
61564
+ "The selected scope does not expose a command-safe list structure target.",
61565
+ "Refresh the scope bundle and route missing list editable-target evidence to L08/L07; do not derive a paragraph index from the scope handle.",
61566
+ "L08 semantic scopes and L07 runtime list commands"
59981
61567
  );
61568
+ return {
61569
+ ok: false,
61570
+ blockers: Object.freeze([detail.code]),
61571
+ blockerDetails: Object.freeze([detail])
61572
+ };
59982
61573
  }
59983
- const command = listCommandForOperation(input.operation, paragraphIndex, actionOrigin(runtime, input));
59984
- const before = runtime.getCanonicalDocument();
59985
- runtime.dispatch(command);
59986
- const changed = runtime.getCanonicalDocument() !== before;
59987
- if (!changed) {
59988
- return blockedApply(
59989
- `actions:list-operation:runtime-noop:${scope.handle.scopeId}`,
61574
+ const currentTarget = collectEditableTargetRefs(runtime.getCanonicalDocument()).find(
61575
+ (target) => target.targetKey === listEntry.targetKey || target.listAddress?.addressKey === listEntry.runtimeCommand.canonicalAddress?.addressKey
61576
+ );
61577
+ if (!currentTarget) {
61578
+ const detail = blockerWithOwner(
61579
+ `actions:list-operation:list-target-not-current:${scope.handle.scopeId}`,
61580
+ "unresolved-target",
61581
+ "The list editable target evidence is stale in the current document.",
61582
+ "Refresh the scope bundle and retry with the current opaque list target.",
61583
+ "L08 semantic scopes and L07 runtime list commands"
61584
+ );
61585
+ return {
61586
+ ok: false,
61587
+ blockers: Object.freeze([detail.code]),
61588
+ blockerDetails: Object.freeze([detail])
61589
+ };
61590
+ }
61591
+ const before = lists.get({ editableTarget: currentTarget });
61592
+ if (!before) {
61593
+ const detail = blockerWithOwner(
61594
+ `actions:list-operation:list-readback-missing:${scope.handle.scopeId}`,
59990
61595
  "blocked",
59991
- "The list runtime command produced no document change for the selected scope.",
59992
- "Select a list-compatible paragraph and retry, or route to L03/L07 list command support with the scope handle.",
59993
- [
59994
- blockerWithOwner(
59995
- `actions:list-operation:runtime-noop:${scope.handle.scopeId}`,
59996
- "blocked",
59997
- "The list runtime command produced no document change for the selected scope.",
59998
- "Select a list-compatible paragraph and retry, or route to L03/L07 list command support with the scope handle.",
59999
- "L03 numbering/list semantics and L07 runtime list commands"
60000
- )
60001
- ]
61596
+ "The list target was present in scope evidence but runtime.lists could not produce readback.",
61597
+ "Route the target with editable-target evidence to L07 runtime list readback.",
61598
+ "L07 runtime list commands"
60002
61599
  );
61600
+ return {
61601
+ ok: false,
61602
+ blockers: Object.freeze([detail.code]),
61603
+ blockerDetails: Object.freeze([detail])
61604
+ };
60003
61605
  }
60004
- const compiledAfter = createScopeCompilerService(runtime).compileScopeById(scope.handle.scopeId);
60005
61606
  return {
60006
- status: "applied",
60007
- applied: true,
60008
- changed: true,
60009
- target: compiledAfter ? summarizeTarget({ kind: "scope", scope: compiledAfter.scope, handle: compiledAfter.scope.handle }) : summarizeTarget(resolvedScope.target),
60010
- commandReference: {
60011
- command: command.type,
60012
- actorId: input.actorId ?? "v3-ai-api",
60013
- origin: input.origin ?? "agent",
60014
- emittedAtUtc: command.origin?.timestamp ?? currentAuditTimestamp(runtime)
60015
- }
61607
+ ok: true,
61608
+ input: { editableTarget: currentTarget },
61609
+ before,
61610
+ scopeHandle: scope.handle
60016
61611
  };
60017
61612
  }
61613
+ function listAddressKeyFromActionHandle(actionHandle) {
61614
+ const listPrefix = "list-action:";
61615
+ if (actionHandle.startsWith(listPrefix)) return actionHandle.slice(listPrefix.length) || null;
61616
+ const scopeCommandPrefix = "scope-command:text-leaf:";
61617
+ if (actionHandle.startsWith(scopeCommandPrefix)) {
61618
+ return actionHandle.slice(scopeCommandPrefix.length) || null;
61619
+ }
61620
+ return null;
61621
+ }
61622
+ function runtimeListCommandForOperation(operation) {
61623
+ switch (operation.kind) {
61624
+ case "toggle":
61625
+ return operation.listKind === "numbered" ? "toggle-numbered" : "toggle-bulleted";
61626
+ case "indent":
61627
+ return "indent";
61628
+ case "outdent":
61629
+ return "outdent";
61630
+ case "restart-numbering":
61631
+ return "restart-numbering";
61632
+ case "continue-numbering":
61633
+ return "continue-numbering";
61634
+ }
61635
+ }
61636
+ function commandReferenceForListCommand(command) {
61637
+ switch (command) {
61638
+ case "toggle-numbered":
61639
+ case "toggle-bulleted":
61640
+ return "list.toggle";
61641
+ case "indent":
61642
+ return "list.indent";
61643
+ case "outdent":
61644
+ return "list.outdent";
61645
+ case "restart-numbering":
61646
+ return "list.restart-numbering";
61647
+ case "continue-numbering":
61648
+ return "list.continue-numbering";
61649
+ default:
61650
+ return "list.toggle";
61651
+ }
61652
+ }
61653
+ function listOperationReadback(result, fallbackBefore) {
61654
+ const before = sanitizeListReadback(result.before ?? fallbackBefore);
61655
+ const after = sanitizeListReadback(result.after);
61656
+ return {
61657
+ ...before ? { before } : {},
61658
+ ...after ? { after } : {}
61659
+ };
61660
+ }
61661
+ function sanitizeListReadback(readback) {
61662
+ if (!readback) return void 0;
61663
+ return {
61664
+ actionHandle: readback.actionHandle,
61665
+ kind: readback.kind,
61666
+ storyKey: readback.storyKey,
61667
+ addressKey: readback.addressKey,
61668
+ numberingInstanceId: readback.numberingInstanceId,
61669
+ ...readback.abstractNumberingId ? { abstractNumberingId: readback.abstractNumberingId } : {},
61670
+ level: readback.level,
61671
+ ...readback.listKind ? { listKind: readback.listKind } : {},
61672
+ editability: readback.editability,
61673
+ blockers: readback.blockers,
61674
+ supportedCommands: readback.supportedCommands,
61675
+ unsupportedCommands: readback.unsupportedCommands,
61676
+ staleDiscriminators: readback.staleDiscriminators
61677
+ };
61678
+ }
61679
+ function summarizeListTarget(target, readback) {
61680
+ const current = readback ?? target.before;
61681
+ return {
61682
+ kind: "list-item",
61683
+ ...target.scopeHandle ? { handle: target.scopeHandle } : {},
61684
+ ...current?.actionHandle ? { actionHandle: current.actionHandle } : {},
61685
+ canRewriteText: current?.editability === "editable" && (current.blockers.length ?? 0) === 0,
61686
+ canInsertAdjacentText: false,
61687
+ canFlag: Boolean(target.scopeHandle),
61688
+ canMark: Boolean(target.scopeHandle)
61689
+ };
61690
+ }
61691
+ function listBlockerDetails(prefix, blockers) {
61692
+ return Object.freeze(
61693
+ blockers.map(
61694
+ (entry) => blockerWithOwner(
61695
+ `${prefix}:${entry.code}:${entry.addressKey ?? entry.targetKey ?? "unknown"}`,
61696
+ entry.code === "list-command-unsupported" ? "unsupported" : "blocked",
61697
+ entry.message,
61698
+ "Refresh the opaque list target/readback and route persistent blockers to the owning runtime list layer.",
61699
+ entry.ownerLayer === "L07" ? "L07 runtime list commands" : entry.ownerLayer
61700
+ )
61701
+ )
61702
+ );
61703
+ }
60018
61704
  function projectTableApplyResult(result) {
60019
61705
  return {
60020
61706
  status: result.applied ? "applied" : "blocked",
@@ -60142,36 +61828,6 @@ function tableSelectionStepHasDescriptor(operation) {
60142
61828
  operation && "selectionDescriptor" in operation && operation.selectionDescriptor
60143
61829
  );
60144
61830
  }
60145
- function listCommandForOperation(operation, paragraphIndex, origin) {
60146
- switch (operation.kind) {
60147
- case "toggle":
60148
- return {
60149
- type: "list.toggle",
60150
- kind: operation.listKind,
60151
- paragraphIndexes: [paragraphIndex],
60152
- origin
60153
- };
60154
- case "indent":
60155
- return { type: "list.indent", paragraphIndexes: [paragraphIndex], origin };
60156
- case "outdent":
60157
- return { type: "list.outdent", paragraphIndexes: [paragraphIndex], origin };
60158
- case "restart-numbering":
60159
- return {
60160
- type: "list.restart-numbering",
60161
- paragraphIndex,
60162
- ...operation.startAt !== void 0 ? { startAt: operation.startAt } : {},
60163
- origin
60164
- };
60165
- case "continue-numbering":
60166
- return { type: "list.continue-numbering", paragraphIndex, origin };
60167
- }
60168
- }
60169
- function paragraphIndexFromHandle(handle) {
60170
- const raw = handle.semanticPath[handle.semanticPath.length - 1];
60171
- if (raw === void 0) return null;
60172
- const index = Number(raw);
60173
- return Number.isSafeInteger(index) && index >= 0 ? index : null;
60174
- }
60175
61831
  function actionOrigin(runtime, input) {
60176
61832
  return { source: "api", timestamp: currentAuditTimestamp(runtime) };
60177
61833
  }
@@ -62615,7 +64271,8 @@ function createApiV3(handle, opts) {
62615
64271
  chart: createChartFamily(handle),
62616
64272
  search: createSearchFamily(handle),
62617
64273
  table: createTableFamily(handle),
62618
- viewport: createViewportFamily(handle)
64274
+ viewport: createViewportFamily(handle),
64275
+ lists: createListsFamily(handle)
62619
64276
  };
62620
64277
  const ui = opts?.ui ? createUiApi(handle, opts.ui) : void 0;
62621
64278
  const api = ui ? { runtime, ai, ui } : { runtime, ai };