@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
@@ -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 fnv1a(stableStringify(value)).toString(36);
305
+ }
306
+ function stableStringify(value) {
307
+ if (value === null || typeof value !== "object") return JSON.stringify(value);
308
+ if (Array.isArray(value)) {
309
+ return `[${value.map((item) => stableStringify(item)).join(",")}]`;
310
+ }
311
+ if (value instanceof Map) {
312
+ return stableStringify(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)}:${stableStringify(object[key])}`).join(",")}}`;
317
+ }
318
+ function fnv1a(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"() {
@@ -2525,6 +2585,7 @@ function collectCanonicalLayoutInputs(doc) {
2525
2585
  const blockContexts = collectStoryBlockContexts(doc);
2526
2586
  return {
2527
2587
  stories: collectCanonicalStoryIdentities(doc),
2588
+ layoutIdentities: collectLayoutInputIdentities(doc, blockContexts),
2528
2589
  fieldRegions: collectCanonicalFieldRegionIdentities(doc),
2529
2590
  numbering: collectCanonicalNumberingLayoutInputs(doc, blockContexts),
2530
2591
  tables: collectCanonicalTableLayoutInputs(blockContexts),
@@ -2533,6 +2594,116 @@ function collectCanonicalLayoutInputs(doc) {
2533
2594
  editableTargets: collectEditableTargetRefs(doc)
2534
2595
  };
2535
2596
  }
2597
+ function collectLayoutInputIdentities(doc, contexts = collectStoryBlockContexts(doc)) {
2598
+ const identities = [];
2599
+ const editableTargets = collectEditableTargetRefs(doc);
2600
+ const editableByStoryBlock = new Map(
2601
+ editableTargets.map((target) => [`${target.storyKey}:${target.blockPath}`, target])
2602
+ );
2603
+ for (const context of contexts) {
2604
+ walkBlocks(context.blocks, context.storyKey, context.basePath, {
2605
+ paragraph(paragraph, blockPath) {
2606
+ const styleNumbering = paragraph.numbering === void 0 && paragraph.styleId !== void 0 ? resolveParagraphStyleNumbering(doc, paragraph.styleId) : void 0;
2607
+ const numbering = paragraph.numbering ?? styleNumbering;
2608
+ const editableTargetRef = editableByStoryBlock.get(`${context.storyKey}:${blockPath}`);
2609
+ identities.push(
2610
+ createLayoutInputIdentity({
2611
+ storyKey: context.storyKey,
2612
+ blockPath,
2613
+ block: paragraph,
2614
+ ...editableTargetRef !== void 0 ? { editableTargetRef } : {},
2615
+ ...numbering !== void 0 ? {
2616
+ list: {
2617
+ numberingInstanceId: numbering.numberingInstanceId,
2618
+ level: numbering.level ?? 0,
2619
+ ...paragraph.numbering?.sourceRef !== void 0 ? { markerSourceRef: paragraph.numbering.sourceRef } : {}
2620
+ }
2621
+ } : {}
2622
+ })
2623
+ );
2624
+ },
2625
+ table(table, blockPath) {
2626
+ identities.push(
2627
+ createLayoutInputIdentity({
2628
+ storyKey: context.storyKey,
2629
+ blockPath,
2630
+ block: table,
2631
+ table: { tableBlockPath: blockPath }
2632
+ })
2633
+ );
2634
+ },
2635
+ inline(inline, blockPath, inlinePath) {
2636
+ const objectId = objectIdForInline(inline);
2637
+ if (!objectId) return;
2638
+ const sourceRef = sourceRefForInline(inline);
2639
+ identities.push({
2640
+ storyKey: context.storyKey,
2641
+ blockPath,
2642
+ blockId: `${context.storyKey}:${inlinePath}`,
2643
+ ...sourceRef !== void 0 ? { sourceRef } : {},
2644
+ object: {
2645
+ objectId,
2646
+ ...sourceRef !== void 0 ? { anchorSourceRef: sourceRef } : {}
2647
+ }
2648
+ });
2649
+ }
2650
+ });
2651
+ }
2652
+ return identities;
2653
+ }
2654
+ function createLayoutInputIdentity(input) {
2655
+ const sourceRef = sourceRefForBlock(input.block);
2656
+ 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}`;
2657
+ return {
2658
+ storyKey: input.storyKey,
2659
+ blockPath: input.blockPath,
2660
+ blockId,
2661
+ ...sourceRef !== void 0 ? { sourceRef } : {},
2662
+ ...input.editableTargetRef !== void 0 ? { editableTargetRef: input.editableTargetRef } : {},
2663
+ ...input.table !== void 0 ? { table: input.table } : {},
2664
+ ...input.list !== void 0 ? { list: input.list } : {}
2665
+ };
2666
+ }
2667
+ function sourceRefForBlock(block) {
2668
+ return "sourceRef" in block ? block.sourceRef : void 0;
2669
+ }
2670
+ function sourceRefForInline(inline) {
2671
+ return "sourceRef" in inline ? inline.sourceRef : void 0;
2672
+ }
2673
+ function objectIdForInline(inline) {
2674
+ switch (inline.type) {
2675
+ case "image":
2676
+ return inline.mediaId;
2677
+ case "drawing_frame":
2678
+ return objectIdForDrawingContent(inline.content) ?? inline.sourceRef?.sourceId;
2679
+ case "shape":
2680
+ case "vml_shape":
2681
+ case "wordart":
2682
+ return inline.preserveOnlyObject?.sourceId ?? `raw:${sha256TextHex(inline.rawXml).slice(0, 16)}`;
2683
+ case "chart_preview":
2684
+ case "smartart_preview":
2685
+ return inline.previewMediaId ?? `raw:${sha256TextHex(inline.rawXml).slice(0, 16)}`;
2686
+ case "ole_embed":
2687
+ return inline.relationshipId ?? inline.id ?? inline.sourceRef?.sourceId;
2688
+ case "opaque_inline":
2689
+ return inline.fragmentId;
2690
+ default:
2691
+ return void 0;
2692
+ }
2693
+ }
2694
+ function objectIdForDrawingContent(content) {
2695
+ switch (content.type) {
2696
+ case "picture":
2697
+ return content.mediaId ?? content.packagePartName ?? content.blipRef;
2698
+ case "chart_preview":
2699
+ case "smartart_preview":
2700
+ return content.previewMediaId ?? `raw:${sha256TextHex(content.rawXml).slice(0, 16)}`;
2701
+ case "shape":
2702
+ return content.preserveOnlyObject?.sourceId ?? `raw:${sha256TextHex(content.rawXml).slice(0, 16)}`;
2703
+ case "opaque":
2704
+ return content.preserveOnlyObject?.sourceId ?? `raw:${sha256TextHex(content.rawXml).slice(0, 16)}`;
2705
+ }
2706
+ }
2536
2707
  function collectEditableTargetRefs(doc, cache) {
2537
2708
  const targets = [];
2538
2709
  for (const context of collectStoryBlockContexts(doc)) {
@@ -4102,6 +4273,16 @@ function collectCanonicalNumberingLayoutInputs(doc, contexts = collectStoryBlock
4102
4273
  const instance = doc.numbering.instances[numbering.numberingInstanceId];
4103
4274
  const abstractDefinition = instance?.abstractNumberingId === void 0 ? void 0 : doc.numbering.abstractDefinitions[instance.abstractNumberingId];
4104
4275
  inputs.push({
4276
+ identity: createLayoutInputIdentity({
4277
+ storyKey: context.storyKey,
4278
+ blockPath,
4279
+ block: paragraph,
4280
+ list: {
4281
+ numberingInstanceId: numbering.numberingInstanceId,
4282
+ level: numbering.level ?? 0,
4283
+ ...paragraph.numbering?.sourceRef !== void 0 ? { markerSourceRef: paragraph.numbering.sourceRef } : {}
4284
+ }
4285
+ }),
4105
4286
  numberingKey: `${context.storyKey}:${blockPath}:numbering`,
4106
4287
  storyKey: context.storyKey,
4107
4288
  blockPath,
@@ -4403,6 +4584,12 @@ function projectTableLayoutInput(table, storyKey, blockPath) {
4403
4584
  (row, rowIndex) => projectTableRowLayoutInput(row, tableKey, rowIndex)
4404
4585
  );
4405
4586
  return {
4587
+ identity: createLayoutInputIdentity({
4588
+ storyKey,
4589
+ blockPath,
4590
+ block: table,
4591
+ table: { tableBlockPath: blockPath }
4592
+ }),
4406
4593
  tableKey,
4407
4594
  storyKey,
4408
4595
  blockPath,
@@ -4490,6 +4677,16 @@ function projectDrawingFrameAnchor(node, storyKey, blockPath, inlinePath) {
4490
4677
  const objectKey = `${storyKey}:${inlinePath}`;
4491
4678
  const textBoxBody = projectTextBoxBodyLayoutInput(content, objectKey, sourceRef, `${inlinePath}/txbx`);
4492
4679
  return {
4680
+ identity: {
4681
+ storyKey,
4682
+ blockPath,
4683
+ blockId: objectKey,
4684
+ ...sourceRef !== void 0 ? { sourceRef } : {},
4685
+ object: {
4686
+ objectId: objectKey,
4687
+ ...sourceRef !== void 0 ? { anchorSourceRef: sourceRef } : {}
4688
+ }
4689
+ },
4493
4690
  objectKey,
4494
4691
  storyKey,
4495
4692
  blockPath,
@@ -4611,8 +4808,19 @@ function projectTextBoxRunLayoutInput(inline, paragraphKey, inlineIndex) {
4611
4808
  }
4612
4809
  function projectLegacyImageAnchor(doc, node, storyKey, blockPath, inlinePath) {
4613
4810
  const media = doc.media.items[node.mediaId];
4811
+ const objectKey = `${storyKey}:${inlinePath}`;
4614
4812
  return {
4615
- objectKey: `${storyKey}:${inlinePath}`,
4813
+ identity: {
4814
+ storyKey,
4815
+ blockPath,
4816
+ blockId: objectKey,
4817
+ ...node.sourceRef !== void 0 ? { sourceRef: node.sourceRef } : {},
4818
+ object: {
4819
+ objectId: objectKey,
4820
+ ...node.sourceRef !== void 0 ? { anchorSourceRef: node.sourceRef } : {}
4821
+ }
4822
+ },
4823
+ objectKey,
4616
4824
  storyKey,
4617
4825
  blockPath,
4618
4826
  inlinePath,
@@ -5749,12 +5957,13 @@ function getLevelStartAt(level, levelDefinitions) {
5749
5957
  return levelDefinitions.get(level)?.startAt ?? DEFAULT_NUMBERING_START_AT;
5750
5958
  }
5751
5959
  function getNumberingFormatPosture(format, value) {
5752
- if (!isSupportedNumberingFormat(format)) {
5960
+ const registryEntry = getNumberingFormatRegistryEntry(format);
5961
+ if (!registryEntry || registryEntry.renderSupport === "approximated") {
5753
5962
  return {
5754
5963
  status: "approximated",
5755
5964
  requestedFormat: format,
5756
5965
  renderedFormat: "decimal",
5757
- reason: "unsupported-numbering-format-decimal-fallback"
5966
+ reason: registryEntry?.fallbackReason ?? "unsupported-numbering-format-decimal-fallback"
5758
5967
  };
5759
5968
  }
5760
5969
  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)) {
@@ -5785,56 +5994,148 @@ function renderLevelText(text, counters, levelDefinitions) {
5785
5994
  });
5786
5995
  return rendered.trim().length > 0 ? rendered : null;
5787
5996
  }
5788
- var SUPPORTED_NUMBERING_FORMATS = /* @__PURE__ */ new Set([
5789
- "decimal",
5790
- "decimalZero",
5791
- "upperLetter",
5792
- "lowerLetter",
5793
- "upperRoman",
5794
- "lowerRoman",
5795
- "hex",
5796
- "ordinal",
5797
- "cardinalText",
5798
- "ordinalText",
5799
- "chicago",
5800
- "bullet",
5801
- "none"
5802
- ]);
5803
5997
  function isSupportedNumberingFormat(format) {
5804
- return SUPPORTED_NUMBERING_FORMATS.has(format);
5998
+ return getNumberingFormatRegistryEntry(format)?.renderSupport === "supported";
5999
+ }
6000
+ function getNumberingFormatRegistryEntry(format) {
6001
+ return NUMBERING_FORMAT_REGISTRY.get(format);
5805
6002
  }
5806
6003
  function formatCounter(value, format) {
5807
- switch (format) {
5808
- case "decimal":
5809
- return String(value);
5810
- case "decimalZero":
5811
- return String(value).padStart(2, "0");
5812
- case "upperLetter":
5813
- return toAlphabetic2(value).toUpperCase();
5814
- case "lowerLetter":
5815
- return toAlphabetic2(value).toLowerCase();
5816
- case "upperRoman":
5817
- return toRoman2(value).toUpperCase();
5818
- case "lowerRoman":
5819
- return toRoman2(value).toLowerCase();
5820
- case "hex":
5821
- return value >= 0 ? value.toString(16).toUpperCase() : String(value);
5822
- case "ordinal":
5823
- return toOrdinal2(value);
5824
- case "cardinalText":
5825
- return toCardinalText2(value);
5826
- case "ordinalText":
5827
- return toOrdinalText2(value);
5828
- case "chicago":
5829
- return toChicago2(value);
5830
- case "bullet":
5831
- return "";
5832
- case "none":
5833
- return "";
5834
- default:
5835
- return String(value);
5836
- }
6004
+ return getNumberingFormatRegistryEntry(format)?.render(value) ?? String(value);
5837
6005
  }
6006
+ var exactNumberingFormatEntries = [
6007
+ {
6008
+ format: "decimal",
6009
+ renderSupport: "supported",
6010
+ renderedFormat: "decimal",
6011
+ supportsMutation: true,
6012
+ render: (value) => String(value)
6013
+ },
6014
+ {
6015
+ format: "decimalZero",
6016
+ renderSupport: "supported",
6017
+ renderedFormat: "decimalZero",
6018
+ supportsMutation: true,
6019
+ render: (value) => String(value).padStart(2, "0")
6020
+ },
6021
+ {
6022
+ format: "upperLetter",
6023
+ renderSupport: "supported",
6024
+ renderedFormat: "upperLetter",
6025
+ supportsMutation: true,
6026
+ render: (value) => toAlphabetic2(value).toUpperCase()
6027
+ },
6028
+ {
6029
+ format: "lowerLetter",
6030
+ renderSupport: "supported",
6031
+ renderedFormat: "lowerLetter",
6032
+ supportsMutation: true,
6033
+ render: (value) => toAlphabetic2(value).toLowerCase()
6034
+ },
6035
+ {
6036
+ format: "upperRoman",
6037
+ renderSupport: "supported",
6038
+ renderedFormat: "upperRoman",
6039
+ supportsMutation: true,
6040
+ render: (value) => toRoman2(value).toUpperCase()
6041
+ },
6042
+ {
6043
+ format: "lowerRoman",
6044
+ renderSupport: "supported",
6045
+ renderedFormat: "lowerRoman",
6046
+ supportsMutation: true,
6047
+ render: (value) => toRoman2(value).toLowerCase()
6048
+ },
6049
+ {
6050
+ format: "hex",
6051
+ renderSupport: "supported",
6052
+ renderedFormat: "hex",
6053
+ supportsMutation: true,
6054
+ render: (value) => value >= 0 ? value.toString(16).toUpperCase() : String(value)
6055
+ },
6056
+ {
6057
+ format: "ordinal",
6058
+ renderSupport: "supported",
6059
+ renderedFormat: "ordinal",
6060
+ supportsMutation: true,
6061
+ render: toOrdinal2
6062
+ },
6063
+ {
6064
+ format: "cardinalText",
6065
+ renderSupport: "supported",
6066
+ renderedFormat: "cardinalText",
6067
+ supportsMutation: true,
6068
+ render: toCardinalText2
6069
+ },
6070
+ {
6071
+ format: "ordinalText",
6072
+ renderSupport: "supported",
6073
+ renderedFormat: "ordinalText",
6074
+ supportsMutation: true,
6075
+ render: toOrdinalText2
6076
+ },
6077
+ {
6078
+ format: "chicago",
6079
+ renderSupport: "supported",
6080
+ renderedFormat: "chicago",
6081
+ supportsMutation: true,
6082
+ render: toChicago2
6083
+ },
6084
+ {
6085
+ format: "bullet",
6086
+ renderSupport: "supported",
6087
+ renderedFormat: "bullet",
6088
+ supportsMutation: true,
6089
+ render: () => ""
6090
+ },
6091
+ {
6092
+ format: "none",
6093
+ renderSupport: "supported",
6094
+ renderedFormat: "none",
6095
+ supportsMutation: true,
6096
+ render: () => ""
6097
+ }
6098
+ ];
6099
+ var approximatedDecimalFormats = [
6100
+ "decimalEnclosedCircle",
6101
+ "decimalEnclosedFullstop",
6102
+ "decimalEnclosedParen",
6103
+ "decimalFullWidth",
6104
+ "decimalHalfWidth",
6105
+ "aiueo",
6106
+ "iroha",
6107
+ "ganada",
6108
+ "chosung",
6109
+ "russianLower",
6110
+ "russianUpper",
6111
+ "hebrew1",
6112
+ "hebrew2",
6113
+ "arabicAlpha",
6114
+ "arabicAbjad",
6115
+ "thaiLetters",
6116
+ "thaiNumbers",
6117
+ "hindiLetters",
6118
+ "hindiNumbers",
6119
+ "ideographDigital",
6120
+ "ideographTraditional",
6121
+ "chineseCounting",
6122
+ "japaneseCounting",
6123
+ "japaneseLegal"
6124
+ ];
6125
+ var approximatedNumberingFormatEntries = approximatedDecimalFormats.map((format) => ({
6126
+ format,
6127
+ renderSupport: "approximated",
6128
+ renderedFormat: "decimal",
6129
+ supportsMutation: false,
6130
+ fallbackReason: "unsupported-numbering-format-decimal-fallback",
6131
+ render: (value) => String(value)
6132
+ }));
6133
+ var NUMBERING_FORMAT_REGISTRY = new Map(
6134
+ [...exactNumberingFormatEntries, ...approximatedNumberingFormatEntries].map((entry) => [
6135
+ entry.format,
6136
+ entry
6137
+ ])
6138
+ );
5838
6139
  function toOrdinal2(value) {
5839
6140
  if (value <= 0) return String(value);
5840
6141
  const lastTwo = value % 100;
@@ -6488,12 +6789,36 @@ var DEFAULT_HYPERLINK_COLOR_HEX = "0563C1";
6488
6789
  function resolveHyperlinkRunFormatting(input, catalog, resolver) {
6489
6790
  const augmentedInput = input.characterStyleId === void 0 ? { ...input, characterStyleId: HYPERLINK_CHARACTER_STYLE_ID } : input;
6490
6791
  const cascade = resolveEffectiveRunFormatting(augmentedInput, catalog);
6491
- const resolvedColor = resolveHyperlinkColorHex(cascade, resolver);
6792
+ const resolvedColor = resolveHyperlinkColorHex(
6793
+ stripInheritedColorHexForImplicitHyperlink(input, catalog, cascade),
6794
+ resolver
6795
+ );
6492
6796
  if (resolvedColor && resolvedColor !== cascade.colorHex) {
6493
6797
  return { ...cascade, colorHex: resolvedColor };
6494
6798
  }
6495
6799
  return cascade;
6496
6800
  }
6801
+ function hasDirectNonAutoColor(input) {
6802
+ return Boolean(input.direct?.colorHex && input.direct.colorHex !== "auto");
6803
+ }
6804
+ function characterStyleDeclaresColorHex(styleId, catalog) {
6805
+ if (!catalog) return false;
6806
+ const chain = resolveCharacterStyleChain(styleId, catalog);
6807
+ return chain.some((chainStyleId) => {
6808
+ const colorHex = catalog.characters[chainStyleId]?.runProperties?.colorHex;
6809
+ return Boolean(colorHex && colorHex !== "auto");
6810
+ });
6811
+ }
6812
+ function stripInheritedColorHexForImplicitHyperlink(originalInput, catalog, cascade) {
6813
+ if (originalInput.characterStyleId !== void 0 || hasDirectNonAutoColor(originalInput) || !cascade.colorHex || cascade.colorHex === "auto" || characterStyleDeclaresColorHex(HYPERLINK_CHARACTER_STYLE_ID, catalog)) {
6814
+ return cascade;
6815
+ }
6816
+ const inheritedCascade = resolveEffectiveRunFormatting(originalInput, catalog);
6817
+ if (inheritedCascade.colorHex !== cascade.colorHex) {
6818
+ return cascade;
6819
+ }
6820
+ return { ...cascade, colorHex: void 0 };
6821
+ }
6497
6822
  function resolveHyperlinkColorHex(cascade, resolver) {
6498
6823
  if (cascade.colorHex && cascade.colorHex !== "auto") {
6499
6824
  return cascade.colorHex;
@@ -6725,7 +7050,7 @@ function buildEffectiveLayoutFormatting(input) {
6725
7050
  };
6726
7051
  }
6727
7052
  function createStructuralHash(value) {
6728
- const stable = stableStringify(value);
7053
+ const stable = stableStringify2(value);
6729
7054
  let hash = 2166136261;
6730
7055
  for (let i = 0; i < stable.length; i += 1) {
6731
7056
  hash ^= stable.charCodeAt(i);
@@ -6733,16 +7058,16 @@ function createStructuralHash(value) {
6733
7058
  }
6734
7059
  return `fnv1a32:${(hash >>> 0).toString(16).padStart(8, "0")}`;
6735
7060
  }
6736
- function stableStringify(value) {
7061
+ function stableStringify2(value) {
6737
7062
  if (value === null || typeof value !== "object") {
6738
7063
  return JSON.stringify(value);
6739
7064
  }
6740
7065
  if (Array.isArray(value)) {
6741
- return `[${value.map((entry) => stableStringify(entry)).join(",")}]`;
7066
+ return `[${value.map((entry) => stableStringify2(entry)).join(",")}]`;
6742
7067
  }
6743
7068
  const record = value;
6744
7069
  const keys = Object.keys(record).filter((key) => record[key] !== void 0).sort();
6745
- return `{${keys.map((key) => `${JSON.stringify(key)}:${stableStringify(record[key])}`).join(",")}}`;
7070
+ return `{${keys.map((key) => `${JSON.stringify(key)}:${stableStringify2(record[key])}`).join(",")}}`;
6746
7071
  }
6747
7072
 
6748
7073
  // src/runtime/formatting/formatting-context.ts
@@ -7251,6 +7576,7 @@ function createEditorSurfaceSnapshot(document2, _selection, activeStory = { kind
7251
7576
  ...options.authorColorPalette ? { authorColorPalette: options.authorColorPalette } : {}
7252
7577
  });
7253
7578
  const editableTargetsByBlockPath = options.editableTargetsByBlockPath ?? indexEditableTargetsByBlockPath(document2);
7579
+ const layoutIdentitiesByBlockPath = options.layoutIdentitiesByBlockPath;
7254
7580
  const activeStoryBlockPathBase = getActiveStoryBlockPathBase(document2, activeStory);
7255
7581
  chartModelStore.beginBuildPass(document2);
7256
7582
  const unsupportedNumberingFormatsSeen = options.emitFormattingTelemetry ? /* @__PURE__ */ new Set() : null;
@@ -7274,6 +7600,7 @@ function createEditorSurfaceSnapshot(document2, _selection, activeStory = { kind
7274
7600
  activeStory.kind !== "main",
7275
7601
  !isInViewport,
7276
7602
  editableTargetsByBlockPath,
7603
+ layoutIdentitiesByBlockPath,
7277
7604
  `${activeStoryBlockPathBase}/block[${index}]`
7278
7605
  );
7279
7606
  if (isInViewport) {
@@ -7340,7 +7667,7 @@ function isIndexInAnyRange(index, ranges) {
7340
7667
  }
7341
7668
  return false;
7342
7669
  }
7343
- function createSurfaceBlock(block, document2, cursor, counters, formattingContext, promoteSecondaryStoryTextBoxes, cullBuild = false, editableTargetsByBlockPath = EMPTY_EDITABLE_TARGETS_BY_BLOCK_PATH, blockPath) {
7670
+ function createSurfaceBlock(block, document2, cursor, counters, formattingContext, promoteSecondaryStoryTextBoxes, cullBuild = false, editableTargetsByBlockPath = EMPTY_EDITABLE_TARGETS_BY_BLOCK_PATH, layoutIdentitiesByBlockPath, blockPath) {
7344
7671
  if (block.type === "opaque_block") {
7345
7672
  const fragment = getOpaqueFragment(document2.preservation, block.fragmentId);
7346
7673
  const descriptor = fragment ? describeOpaqueFragment(fragment) : null;
@@ -7377,6 +7704,7 @@ function createSurfaceBlock(block, document2, cursor, counters, formattingContex
7377
7704
  promoteSecondaryStoryTextBoxes,
7378
7705
  cullBuild,
7379
7706
  editableTargetsByBlockPath,
7707
+ layoutIdentitiesByBlockPath,
7380
7708
  blockPath
7381
7709
  );
7382
7710
  }
@@ -7417,6 +7745,7 @@ function createSurfaceBlock(block, document2, cursor, counters, formattingContex
7417
7745
  promoteSecondaryStoryTextBoxes,
7418
7746
  cullBuild,
7419
7747
  editableTargetsByBlockPath,
7748
+ layoutIdentitiesByBlockPath,
7420
7749
  blockPath
7421
7750
  );
7422
7751
  }
@@ -7499,10 +7828,11 @@ function createSurfaceBlock(block, document2, cursor, counters, formattingContex
7499
7828
  cullBuild,
7500
7829
  editableTargetsByBlockPath,
7501
7830
  blockPath,
7502
- blockPath !== void 0 ? editableTargetsByBlockPath.get(blockPath) : void 0
7831
+ blockPath !== void 0 ? editableTargetsByBlockPath.get(blockPath) : void 0,
7832
+ blockPath !== void 0 ? layoutIdentitiesByBlockPath?.get(blockPath) : void 0
7503
7833
  );
7504
7834
  }
7505
- function createTableBlock(tableIndex, table, document2, cursor, counters, formattingContext, promoteSecondaryStoryTextBoxes, cullBuild = false, editableTargetsByBlockPath = EMPTY_EDITABLE_TARGETS_BY_BLOCK_PATH, tablePath) {
7835
+ function createTableBlock(tableIndex, table, document2, cursor, counters, formattingContext, promoteSecondaryStoryTextBoxes, cullBuild = false, editableTargetsByBlockPath = EMPTY_EDITABLE_TARGETS_BY_BLOCK_PATH, layoutIdentitiesByBlockPath, tablePath) {
7506
7836
  const lockedFragmentIds = [];
7507
7837
  let innerCursor = cursor;
7508
7838
  if (cullBuild) {
@@ -7519,6 +7849,7 @@ function createTableBlock(tableIndex, table, document2, cursor, counters, format
7519
7849
  promoteSecondaryStoryTextBoxes,
7520
7850
  true,
7521
7851
  editableTargetsByBlockPath,
7852
+ layoutIdentitiesByBlockPath,
7522
7853
  tablePath !== void 0 ? `${tablePath}/row[${rowIndex}]/cell[${cellIndex}]/block[${childIndex}]` : void 0
7523
7854
  );
7524
7855
  lockedFragmentIds.push(...result.lockedFragmentIds);
@@ -7534,6 +7865,7 @@ function createTableBlock(tableIndex, table, document2, cursor, counters, format
7534
7865
  to: innerCursor,
7535
7866
  styleId: table.styleId,
7536
7867
  ...table.sourceRef !== void 0 ? { sourceRef: table.sourceRef } : {},
7868
+ ...tablePath !== void 0 && layoutIdentitiesByBlockPath?.get(tablePath) !== void 0 ? { layoutIdentity: layoutIdentitiesByBlockPath.get(tablePath) } : {},
7537
7869
  gridColumns: table.gridColumns,
7538
7870
  rows: []
7539
7871
  },
@@ -7571,6 +7903,7 @@ function createTableBlock(tableIndex, table, document2, cursor, counters, format
7571
7903
  promoteSecondaryStoryTextBoxes,
7572
7904
  cullBuild,
7573
7905
  editableTargetsByBlockPath,
7906
+ layoutIdentitiesByBlockPath,
7574
7907
  tablePath !== void 0 ? `${tablePath}/row[${rowIndex}]/cell[${cellIndex}]/block[${childIndex}]` : void 0
7575
7908
  );
7576
7909
  cellContent.push(result.block);
@@ -7659,6 +7992,7 @@ function createTableBlock(tableIndex, table, document2, cursor, counters, format
7659
7992
  to: innerCursor,
7660
7993
  styleId: table.styleId,
7661
7994
  ...table.sourceRef !== void 0 ? { sourceRef: table.sourceRef } : {},
7995
+ ...tablePath !== void 0 && layoutIdentitiesByBlockPath?.get(tablePath) !== void 0 ? { layoutIdentity: layoutIdentitiesByBlockPath.get(tablePath) } : {},
7662
7996
  gridColumns: table.gridColumns,
7663
7997
  ...gridColumnsRelative ? { gridColumnsRelative } : {},
7664
7998
  ...resolvedTable.table?.alignment ? { alignment: resolvedTable.table.alignment } : {},
@@ -7846,7 +8180,7 @@ function resolveCellBorderStyles(borders, tableBorders, position) {
7846
8180
  if (left) result.borderLeft = left;
7847
8181
  return result;
7848
8182
  }
7849
- function createSdtBlock(sdtIndex, block, document2, cursor, counters, formattingContext, promoteSecondaryStoryTextBoxes, cullBuild = false, editableTargetsByBlockPath = EMPTY_EDITABLE_TARGETS_BY_BLOCK_PATH, sdtPath) {
8183
+ function createSdtBlock(sdtIndex, block, document2, cursor, counters, formattingContext, promoteSecondaryStoryTextBoxes, cullBuild = false, editableTargetsByBlockPath = EMPTY_EDITABLE_TARGETS_BY_BLOCK_PATH, layoutIdentitiesByBlockPath, sdtPath) {
7850
8184
  const children = [];
7851
8185
  const lockedFragmentIds = [];
7852
8186
  let innerCursor = cursor;
@@ -7863,6 +8197,7 @@ function createSdtBlock(sdtIndex, block, document2, cursor, counters, formatting
7863
8197
  promoteSecondaryStoryTextBoxes,
7864
8198
  cullBuild,
7865
8199
  editableTargetsByBlockPath,
8200
+ layoutIdentitiesByBlockPath,
7866
8201
  sdtPath !== void 0 ? `${sdtPath}/block[${childIndex}]` : void 0
7867
8202
  );
7868
8203
  children.push(result.block);
@@ -7905,7 +8240,7 @@ function getRecursableSdtBlockedReasonCode(block) {
7905
8240
  ].filter(Boolean).join(" ").toLowerCase();
7906
8241
  return searchText.includes("table of contents") || /\btoc\b/u.test(searchText) ? "workflow_preserve_only" : null;
7907
8242
  }
7908
- function createParagraphBlock(paragraphIndex, paragraph, document2, start, formattingContext, promoteSecondaryStoryTextBoxes, cullBuild = false, editableTargetsByBlockPath = EMPTY_EDITABLE_TARGETS_BY_BLOCK_PATH, blockPath, editableTarget) {
8243
+ function createParagraphBlock(paragraphIndex, paragraph, document2, start, formattingContext, promoteSecondaryStoryTextBoxes, cullBuild = false, editableTargetsByBlockPath = EMPTY_EDITABLE_TARGETS_BY_BLOCK_PATH, blockPath, editableTarget, layoutIdentity) {
7909
8244
  const themeResolver = formattingContext.theme;
7910
8245
  const effectiveNumbering = formattingContext.resolveEffectiveParagraphNumbering(paragraph);
7911
8246
  let resolvedNumbering = null;
@@ -7928,6 +8263,7 @@ function createParagraphBlock(paragraphIndex, paragraph, document2, start, forma
7928
8263
  from: start,
7929
8264
  to: start,
7930
8265
  ...editableTarget !== void 0 ? { editableTarget } : {},
8266
+ ...layoutIdentity !== void 0 ? { layoutIdentity } : {},
7931
8267
  ...paragraph.styleId ? { styleId: paragraph.styleId } : {},
7932
8268
  ...effectiveNumbering ? { numbering: effectiveNumbering } : {},
7933
8269
  ...resolvedNumbering ? {
@@ -11703,6 +12039,14 @@ function paginateSectionBlocksWithSplits(section, blocks, layout, footnotes, mea
11703
12039
  pushPage(block.from);
11704
12040
  continue;
11705
12041
  }
12042
+ if (isStandalonePageBreakParagraph(block)) {
12043
+ if (columnHeight > 0) {
12044
+ pushPage(nextBoundary);
12045
+ } else {
12046
+ pageStart = Math.max(pageStart, Math.min(nextBoundary, section.end));
12047
+ }
12048
+ break;
12049
+ }
11706
12050
  const effectiveNoteHeight = estimateFootnoteReservation(
11707
12051
  block,
11708
12052
  footnotes,
@@ -11877,6 +12221,21 @@ function hasPageBreak(block) {
11877
12221
  }
11878
12222
  return nestedBlocks(block).some(hasPageBreak);
11879
12223
  }
12224
+ function isStandalonePageBreakParagraph(block) {
12225
+ if (block.kind !== "paragraph") return false;
12226
+ let sawPageBreak = false;
12227
+ for (const segment of block.segments) {
12228
+ if (segment.kind === "opaque_inline" && segment.label === "Page break") {
12229
+ sawPageBreak = true;
12230
+ continue;
12231
+ }
12232
+ if (segment.kind === "text" && segment.text.trim().length === 0) {
12233
+ continue;
12234
+ }
12235
+ return false;
12236
+ }
12237
+ return sawPageBreak;
12238
+ }
11880
12239
  function nestedBlocks(block) {
11881
12240
  if (block.kind === "sdt_block") {
11882
12241
  return block.children;
@@ -13338,6 +13697,9 @@ function projectSurfaceBlocksToPageFragments(surface, pages, splits, columnByBlo
13338
13697
  for (let blockIndex = 0; blockIndex < surface.blocks.length; blockIndex += 1) {
13339
13698
  const block = surface.blocks[blockIndex];
13340
13699
  const blockPath = `main/block[${blockIndex}]`;
13700
+ if (isStandalonePageBreakParagraph2(block)) {
13701
+ continue;
13702
+ }
13341
13703
  if (block.kind === "table") {
13342
13704
  const tableSliceList = splits?.tablesByBlockId.get(block.blockId);
13343
13705
  if (tableSliceList && tableSliceList.length > 1) {
@@ -13423,6 +13785,23 @@ function projectSurfaceBlocksToPageFragments(surface, pages, splits, columnByBlo
13423
13785
  }
13424
13786
  return byPage;
13425
13787
  }
13788
+ function isStandalonePageBreakParagraph2(block) {
13789
+ if (block.kind !== "paragraph") {
13790
+ return false;
13791
+ }
13792
+ let sawPageBreak = false;
13793
+ for (const segment of block.segments) {
13794
+ if (segment.kind === "opaque_inline" && segment.label === "Page break") {
13795
+ sawPageBreak = true;
13796
+ continue;
13797
+ }
13798
+ if (segment.kind === "text" && segment.text.trim().length === 0) {
13799
+ continue;
13800
+ }
13801
+ return false;
13802
+ }
13803
+ return sawPageBreak;
13804
+ }
13426
13805
  function projectLineBoxesForPageFragments(pages, fragmentsByPageIndex, fragmentMeasurementsByPageIndex, surface) {
13427
13806
  const byPage = /* @__PURE__ */ new Map();
13428
13807
  const blocksById = surface ? new Map(surface.blocks.map((block) => [block.blockId, block])) : /* @__PURE__ */ new Map();
@@ -13935,13 +14314,11 @@ function buildBookmarkRanges(targets) {
13935
14314
  }
13936
14315
  var EMPTY_NUMBERING_INPUT_INDEX = {
13937
14316
  byNumberingKey: /* @__PURE__ */ new Map(),
13938
- byBlockPath: /* @__PURE__ */ new Map(),
13939
- byParagraphIndex: /* @__PURE__ */ new Map()
14317
+ byBlockPath: /* @__PURE__ */ new Map()
13940
14318
  };
13941
14319
  function buildNumberingInputIndex(numberingInputs) {
13942
14320
  const byNumberingKey = /* @__PURE__ */ new Map();
13943
14321
  const byBlockPath = /* @__PURE__ */ new Map();
13944
- const byParagraph = /* @__PURE__ */ new Map();
13945
14322
  for (const input of numberingInputs) {
13946
14323
  if (!byNumberingKey.has(input.numberingKey)) {
13947
14324
  byNumberingKey.set(input.numberingKey, input);
@@ -13949,11 +14326,8 @@ function buildNumberingInputIndex(numberingInputs) {
13949
14326
  if (!byBlockPath.has(input.blockPath)) {
13950
14327
  byBlockPath.set(input.blockPath, input);
13951
14328
  }
13952
- if (!byParagraph.has(input.paragraphIndex)) {
13953
- byParagraph.set(input.paragraphIndex, input);
13954
- }
13955
14329
  }
13956
- return { byNumberingKey, byBlockPath, byParagraphIndex: byParagraph };
14330
+ return { byNumberingKey, byBlockPath };
13957
14331
  }
13958
14332
  function collectBookmarkRangeLayoutFacts(fragmentId, blockPath, bookmarkRanges) {
13959
14333
  if (!blockPath || !bookmarkRanges || bookmarkRanges.length === 0) return [];
@@ -14073,8 +14447,7 @@ function collectNumberingLayoutFactsForBlock(block, blockPath, numberingIndex, n
14073
14447
  const canonical = lookupNumberingInput(
14074
14448
  numberingIndex,
14075
14449
  numberingKey,
14076
- context.path,
14077
- paragraphIndex
14450
+ context.path
14078
14451
  );
14079
14452
  const target = findNumberingTarget(numberingTargets, context.path);
14080
14453
  const numberingLayoutId = numberingKey ?? [
@@ -14114,7 +14487,7 @@ function findNumberingTarget(numberingTargets, blockPath) {
14114
14487
  if (blockPath === void 0) return void 0;
14115
14488
  return numberingTargets.find((target) => target.blockPath === blockPath);
14116
14489
  }
14117
- function lookupNumberingInput(numberingIndex, numberingKey, blockPath, paragraphIndex) {
14490
+ function lookupNumberingInput(numberingIndex, numberingKey, blockPath) {
14118
14491
  if (!numberingIndex) return void 0;
14119
14492
  if (numberingKey !== void 0) {
14120
14493
  const byKey = numberingIndex.byNumberingKey.get(numberingKey);
@@ -14124,7 +14497,7 @@ function lookupNumberingInput(numberingIndex, numberingKey, blockPath, paragraph
14124
14497
  const byPath = numberingIndex.byBlockPath.get(blockPath);
14125
14498
  if (byPath !== void 0) return byPath;
14126
14499
  }
14127
- return paragraphIndex !== void 0 ? numberingIndex.byParagraphIndex.get(paragraphIndex) : void 0;
14500
+ return void 0;
14128
14501
  }
14129
14502
  function collectNumberingUnavailableReasons(numbering, canonical) {
14130
14503
  const reasons = [];
@@ -14514,12 +14887,330 @@ function createEmpiricalProvider() {
14514
14887
  return createEmpiricalBackend();
14515
14888
  }
14516
14889
 
14890
+ // src/runtime/layout/persistent-layout-measurement-cache.ts
14891
+ init_resolved_formatting_state();
14892
+ var DEFAULT_MAX_ENTRIES = 1e4;
14893
+ var DEFAULT_MAX_ESTIMATED_BYTES = 50 * 1024 * 1024;
14894
+ function createPersistentLayoutMeasurementCache(options = {}) {
14895
+ const maxEntries = Math.max(1, options.maxEntries ?? DEFAULT_MAX_ENTRIES);
14896
+ const maxEstimatedBytes = Math.max(
14897
+ 1024,
14898
+ options.maxEstimatedBytes ?? DEFAULT_MAX_ESTIMATED_BYTES
14899
+ );
14900
+ const entries = /* @__PURE__ */ new Map();
14901
+ const counters = {
14902
+ hits: 0,
14903
+ misses: 0,
14904
+ sets: 0,
14905
+ evictions: 0,
14906
+ clears: 0,
14907
+ estimatedBytes: 0,
14908
+ invalidatedByReason: {}
14909
+ };
14910
+ function evictOldest() {
14911
+ const oldest = entries.keys().next();
14912
+ if (oldest.done) return;
14913
+ const entry = entries.get(oldest.value);
14914
+ if (entry) {
14915
+ counters.estimatedBytes -= entry.estimatedBytes;
14916
+ }
14917
+ entries.delete(oldest.value);
14918
+ counters.evictions += 1;
14919
+ }
14920
+ return {
14921
+ get(key) {
14922
+ const cacheKey = serializeCacheKey(key);
14923
+ const entry = entries.get(cacheKey);
14924
+ if (!entry) {
14925
+ counters.misses += 1;
14926
+ return void 0;
14927
+ }
14928
+ entries.delete(cacheKey);
14929
+ entries.set(cacheKey, entry);
14930
+ counters.hits += 1;
14931
+ return entry.value;
14932
+ },
14933
+ set(key, value) {
14934
+ const cacheKey = serializeCacheKey(key);
14935
+ const previous = entries.get(cacheKey);
14936
+ if (previous) {
14937
+ counters.estimatedBytes -= previous.estimatedBytes;
14938
+ entries.delete(cacheKey);
14939
+ }
14940
+ const estimatedBytes = estimateBytes(key, value);
14941
+ entries.set(cacheKey, { key, value, estimatedBytes });
14942
+ counters.estimatedBytes += estimatedBytes;
14943
+ counters.sets += 1;
14944
+ while (entries.size > maxEntries || counters.estimatedBytes > maxEstimatedBytes) {
14945
+ evictOldest();
14946
+ }
14947
+ },
14948
+ invalidate(reason, predicate) {
14949
+ if (!predicate) {
14950
+ const removed2 = entries.size;
14951
+ counters.estimatedBytes = 0;
14952
+ entries.clear();
14953
+ counters.invalidatedByReason[reason] = (counters.invalidatedByReason[reason] ?? 0) + removed2;
14954
+ return;
14955
+ }
14956
+ let removed = 0;
14957
+ for (const [cacheKey, entry] of entries) {
14958
+ if (!predicate(entry.key)) continue;
14959
+ counters.estimatedBytes -= entry.estimatedBytes;
14960
+ entries.delete(cacheKey);
14961
+ removed += 1;
14962
+ }
14963
+ counters.invalidatedByReason[reason] = (counters.invalidatedByReason[reason] ?? 0) + removed;
14964
+ },
14965
+ clear(reason) {
14966
+ const removed = entries.size;
14967
+ counters.estimatedBytes = 0;
14968
+ entries.clear();
14969
+ counters.clears += 1;
14970
+ counters.invalidatedByReason[reason] = (counters.invalidatedByReason[reason] ?? 0) + removed;
14971
+ },
14972
+ stats() {
14973
+ return {
14974
+ hits: counters.hits,
14975
+ misses: counters.misses,
14976
+ sets: counters.sets,
14977
+ evictions: counters.evictions,
14978
+ clears: counters.clears,
14979
+ size: entries.size,
14980
+ estimatedBytes: Math.max(0, counters.estimatedBytes),
14981
+ invalidatedByReason: { ...counters.invalidatedByReason }
14982
+ };
14983
+ }
14984
+ };
14985
+ }
14986
+ function createCachedLayoutMeasurementProvider(delegate, options = {}) {
14987
+ const cache = options.cache ?? createPersistentLayoutMeasurementCache(options);
14988
+ function emitCounter(type, key) {
14989
+ const telemetryBus = options.telemetryBus;
14990
+ if (!telemetryBus?.isEnabled("layout")) return;
14991
+ telemetryBus.emitLazy("layout", () => ({
14992
+ type,
14993
+ payload: key ? {
14994
+ measurementKind: key.measurementKind,
14995
+ blockId: key.blockId,
14996
+ backendVersion: key.backendVersion
14997
+ } : void 0
14998
+ }));
14999
+ }
15000
+ return {
15001
+ get fidelity() {
15002
+ return delegate.fidelity;
15003
+ },
15004
+ measurementCache: cache,
15005
+ measurementCacheStats() {
15006
+ return cache.stats();
15007
+ },
15008
+ whenReady() {
15009
+ return delegate.whenReady();
15010
+ },
15011
+ measureLineFragments(input) {
15012
+ const key = buildLineFragmentsKey(input, delegate, options);
15013
+ const cached = cache.get(key);
15014
+ if (cached) {
15015
+ emitCounter("pageRender.measurement.hit", key);
15016
+ return cloneMeasuredLineFragments(cached);
15017
+ }
15018
+ emitCounter("pageRender.measurement.miss", key);
15019
+ const measured = delegate.measureLineFragments(input);
15020
+ cache.set(key, cloneMeasuredLineFragments(measured));
15021
+ return measured;
15022
+ },
15023
+ measureInlineObject(input) {
15024
+ const key = buildInlineObjectKey(input, delegate, options);
15025
+ const cached = cache.get(key);
15026
+ if (cached) {
15027
+ emitCounter("pageRender.measurement.hit", key);
15028
+ return { ...cached };
15029
+ }
15030
+ emitCounter("pageRender.measurement.miss", key);
15031
+ const measured = delegate.measureInlineObject(input);
15032
+ cache.set(key, { ...measured });
15033
+ return measured;
15034
+ },
15035
+ measureTableBlock(input) {
15036
+ const key = buildTableBlockKey(input, delegate, options);
15037
+ const cached = cache.get(key);
15038
+ if (cached) {
15039
+ emitCounter("pageRender.measurement.hit", key);
15040
+ return cloneMeasuredTableBlock(cached);
15041
+ }
15042
+ emitCounter("pageRender.measurement.miss", key);
15043
+ const measured = delegate.measureTableBlock(input);
15044
+ cache.set(key, cloneMeasuredTableBlock(measured));
15045
+ return measured;
15046
+ },
15047
+ invalidateCache() {
15048
+ delegate.invalidateCache();
15049
+ cache.clear("provider.invalidateCache");
15050
+ emitCounter("pageRender.measurement.invalidated.provider.invalidateCache");
15051
+ }
15052
+ };
15053
+ }
15054
+ function isCachedLayoutMeasurementProvider(provider) {
15055
+ return typeof provider.measurementCacheStats === "function";
15056
+ }
15057
+ function buildLineFragmentsKey(input, delegate, options) {
15058
+ const block = input.block;
15059
+ const identity = measurementIdentityForBlock(block);
15060
+ return {
15061
+ measurementKind: "line-fragments",
15062
+ blockId: identity.blockId,
15063
+ blockPath: identity.blockPath,
15064
+ contentHash: hashStable2({
15065
+ kind: block.kind,
15066
+ identity: identity.identityHash,
15067
+ segments: block.segments,
15068
+ numbering: block.numbering,
15069
+ numberingPrefix: block.numberingPrefix,
15070
+ numberingSuffix: block.numberingSuffix,
15071
+ resolvedNumbering: block.resolvedNumbering
15072
+ }),
15073
+ formattingHash: createLayoutReadyFormattingSnapshot(
15074
+ input.formatting,
15075
+ input.runs
15076
+ ).hash,
15077
+ constraintsHash: hashStable2({ columnWidth: input.columnWidth }),
15078
+ sectionHash: resolveOptionValue(options.sectionHash, "section:provider-input"),
15079
+ fontEpoch: resolveOptionValue(options.fontEpoch, "font:default"),
15080
+ backendVersion: resolveOptionValue(options.backendVersion, delegate.fidelity),
15081
+ displayModeHash: resolveOptionValue(options.displayModeHash, "display:default")
15082
+ };
15083
+ }
15084
+ function buildInlineObjectKey(input, delegate, options) {
15085
+ return {
15086
+ measurementKind: "inline-object",
15087
+ blockId: "inline-object",
15088
+ blockPath: "inline-object",
15089
+ contentHash: hashStable2({ display: input.display }),
15090
+ formattingHash: "format:none",
15091
+ constraintsHash: hashStable2({
15092
+ widthTwips: input.widthTwips,
15093
+ heightTwips: input.heightTwips
15094
+ }),
15095
+ sectionHash: resolveOptionValue(options.sectionHash, "section:provider-input"),
15096
+ fontEpoch: resolveOptionValue(options.fontEpoch, "font:default"),
15097
+ backendVersion: resolveOptionValue(options.backendVersion, delegate.fidelity),
15098
+ displayModeHash: resolveOptionValue(options.displayModeHash, "display:default")
15099
+ };
15100
+ }
15101
+ function buildTableBlockKey(input, delegate, options) {
15102
+ const block = input.block;
15103
+ const identity = measurementIdentityForBlock(block);
15104
+ return {
15105
+ measurementKind: "table-block",
15106
+ blockId: identity.blockId,
15107
+ blockPath: identity.blockPath,
15108
+ contentHash: hashStable2({
15109
+ kind: block.kind,
15110
+ identity: identity.identityHash,
15111
+ rows: block.rows,
15112
+ gridColumns: block.gridColumns,
15113
+ gridColumnsRelative: block.gridColumnsRelative,
15114
+ tableResolved: block.tableResolved,
15115
+ tblLook: block.tblLook
15116
+ }),
15117
+ formattingHash: hashStable2({
15118
+ styleId: block.styleId,
15119
+ alignment: block.alignment
15120
+ }),
15121
+ constraintsHash: hashStable2({ columnWidth: input.columnWidth }),
15122
+ sectionHash: resolveOptionValue(options.sectionHash, "section:provider-input"),
15123
+ fontEpoch: resolveOptionValue(options.fontEpoch, "font:default"),
15124
+ backendVersion: resolveOptionValue(options.backendVersion, delegate.fidelity),
15125
+ displayModeHash: resolveOptionValue(options.displayModeHash, "display:default")
15126
+ };
15127
+ }
15128
+ function measurementIdentityForBlock(block) {
15129
+ const identity = block.layoutIdentity;
15130
+ if (!identity) {
15131
+ return {
15132
+ blockId: block.blockId,
15133
+ blockPath: blockPathForBlock(block),
15134
+ identityHash: "identity:legacy"
15135
+ };
15136
+ }
15137
+ return {
15138
+ blockId: identity.blockId,
15139
+ blockPath: identity.blockPath,
15140
+ identityHash: hashStable2({
15141
+ storyKey: identity.storyKey,
15142
+ blockId: identity.blockId,
15143
+ blockPath: identity.blockPath,
15144
+ sourceRef: identity.sourceRef,
15145
+ table: identity.table,
15146
+ list: identity.list,
15147
+ field: identity.field,
15148
+ object: identity.object
15149
+ })
15150
+ };
15151
+ }
15152
+ function blockPathForBlock(block) {
15153
+ return `${block.from}:${block.to}`;
15154
+ }
15155
+ function resolveOptionValue(option, fallback) {
15156
+ if (typeof option === "function") return option();
15157
+ return option ?? fallback;
15158
+ }
15159
+ function serializeCacheKey(key) {
15160
+ return stableStringify3(key);
15161
+ }
15162
+ function estimateBytes(key, value) {
15163
+ return stableStringify3(key).length + stableStringify3(value).length;
15164
+ }
15165
+ function cloneMeasuredLineFragments(value) {
15166
+ return {
15167
+ lineCount: value.lineCount,
15168
+ maxLineWidth: value.maxLineWidth,
15169
+ lineHeights: [...value.lineHeights]
15170
+ };
15171
+ }
15172
+ function cloneMeasuredTableBlock(value) {
15173
+ return {
15174
+ totalHeightTwips: value.totalHeightTwips,
15175
+ rowHeights: [...value.rowHeights]
15176
+ };
15177
+ }
15178
+ function hashStable2(value) {
15179
+ return fnv1a2(stableStringify3(value)).toString(36);
15180
+ }
15181
+ function stableStringify3(value) {
15182
+ if (value === null || typeof value !== "object") return JSON.stringify(value);
15183
+ if (Array.isArray(value)) {
15184
+ return `[${value.map((item) => stableStringify3(item)).join(",")}]`;
15185
+ }
15186
+ if (value instanceof Map) {
15187
+ return stableStringify3(Array.from(value.entries()));
15188
+ }
15189
+ const object = value;
15190
+ const keys = Object.keys(object).filter((key) => object[key] !== void 0 && typeof object[key] !== "function").sort();
15191
+ return `{${keys.map((key) => `${JSON.stringify(key)}:${stableStringify3(object[key])}`).join(",")}}`;
15192
+ }
15193
+ function fnv1a2(input) {
15194
+ let hash = 2166136261;
15195
+ for (let i = 0; i < input.length; i += 1) {
15196
+ hash ^= input.charCodeAt(i);
15197
+ hash = Math.imul(hash, 16777619);
15198
+ }
15199
+ return hash >>> 0;
15200
+ }
15201
+
14517
15202
  // src/runtime/layout/layout-engine-version.ts
14518
- var LAYOUT_ENGINE_VERSION = 88;
15203
+ var LAYOUT_ENGINE_VERSION = 93;
14519
15204
 
14520
15205
  // src/runtime/layout/layout-engine-instance.ts
14521
15206
  var FULL_VIEWPORT_WINDOW_KEY = "full";
14522
15207
  var DEFAULT_VIEWPORT_PAGE_WINDOW_BUFFER = 1;
15208
+ function indexLayoutIdentitiesByBlockPath(identities) {
15209
+ return new Map(identities.map((identity) => [identity.blockPath, identity]));
15210
+ }
15211
+ function indexEditableTargetsByBlockPath2(targets) {
15212
+ return new Map(targets.map((target) => [target.blockPath, target]));
15213
+ }
14523
15214
  function normalizeViewportPageWindow(window2) {
14524
15215
  if (!window2) return void 0;
14525
15216
  const buffer = Number.isFinite(window2.bufferPages) ? Math.max(0, Math.floor(window2.bufferPages ?? 0)) : DEFAULT_VIEWPORT_PAGE_WINDOW_BUFFER;
@@ -14715,8 +15406,22 @@ function recordFullRebuildReason(reasonKind) {
14715
15406
  probe.invalidationCounts[totalKey] = (probe.invalidationCounts[totalKey] ?? 0) + 1;
14716
15407
  probe.invalidationCounts[byReasonKey] = (probe.invalidationCounts[byReasonKey] ?? 0) + 1;
14717
15408
  }
15409
+ function wrapMeasurementProvider(provider, measurementCache, telemetryBus) {
15410
+ if (!measurementCache || isCachedLayoutMeasurementProvider(provider)) {
15411
+ return provider;
15412
+ }
15413
+ const cacheOptions = measurementCache === true ? {} : measurementCache;
15414
+ return createCachedLayoutMeasurementProvider(provider, {
15415
+ ...cacheOptions,
15416
+ ...telemetryBus ? { telemetryBus } : {}
15417
+ });
15418
+ }
14718
15419
  function createLayoutEngine(options = {}) {
14719
- let measurementProvider = options.measurementProvider ?? createEmpiricalMeasurementProvider();
15420
+ let measurementProvider = wrapMeasurementProvider(
15421
+ options.measurementProvider ?? createEmpiricalMeasurementProvider(),
15422
+ options.measurementCache,
15423
+ options.telemetryBus
15424
+ );
14720
15425
  const autoUpgradeToCanvas = options.autoUpgradeToCanvasBackend !== false;
14721
15426
  const telemetryBus = options.telemetryBus;
14722
15427
  const dirtyFieldFamilies = /* @__PURE__ */ new Set();
@@ -14816,13 +15521,20 @@ function createLayoutEngine(options = {}) {
14816
15521
  const pageCountBeforeRecompute = previousPageCount;
14817
15522
  const document2 = input.document;
14818
15523
  const viewportWindow = normalizeViewportPageWindow(input.viewportPageWindow);
15524
+ const layoutInputs = collectCanonicalLayoutInputs(document2);
15525
+ const layoutIdentitiesByBlockPath = indexLayoutIdentitiesByBlockPath(
15526
+ layoutInputs.layoutIdentities
15527
+ );
15528
+ const editableTargetsByBlockPath = indexEditableTargetsByBlockPath2(
15529
+ layoutInputs.editableTargets
15530
+ );
14819
15531
  const mainSurface = createEditorSurfaceSnapshot(
14820
15532
  document2,
14821
15533
  createSelectionSnapshot(0, 0),
14822
- MAIN_STORY_TARGET
15534
+ MAIN_STORY_TARGET,
15535
+ { editableTargetsByBlockPath, layoutIdentitiesByBlockPath }
14823
15536
  );
14824
15537
  const sections = buildResolvedSections(document2);
14825
- const layoutInputs = collectCanonicalLayoutInputs(document2);
14826
15538
  const fieldRegions = layoutInputs.fieldRegions;
14827
15539
  const pageStack = buildPageStackWithSplits(
14828
15540
  document2,
@@ -14934,10 +15646,18 @@ function createLayoutEngine(options = {}) {
14934
15646
  const firstDirty = range.firstPageIndex;
14935
15647
  if (firstDirty < 0 || firstDirty >= priorGraph.pages.length) return null;
14936
15648
  const document2 = input.document;
15649
+ const layoutInputs = collectCanonicalLayoutInputs(document2);
15650
+ const layoutIdentitiesByBlockPath = indexLayoutIdentitiesByBlockPath(
15651
+ layoutInputs.layoutIdentities
15652
+ );
15653
+ const editableTargetsByBlockPath = indexEditableTargetsByBlockPath2(
15654
+ layoutInputs.editableTargets
15655
+ );
14937
15656
  const mainSurface = createEditorSurfaceSnapshot(
14938
15657
  document2,
14939
15658
  createSelectionSnapshot(0, 0),
14940
- MAIN_STORY_TARGET
15659
+ MAIN_STORY_TARGET,
15660
+ { editableTargetsByBlockPath, layoutIdentitiesByBlockPath }
14941
15661
  );
14942
15662
  const sections = buildResolvedSections(document2);
14943
15663
  const dirtyPage = priorGraph.pages[firstDirty];
@@ -14966,7 +15686,6 @@ function createLayoutEngine(options = {}) {
14966
15686
  const freshSnapshotsToRebuild = freshSnapshots.slice(0, convergenceIndex);
14967
15687
  const convergedTailStart = convergenceIndex < freshSnapshots.length ? firstDirty + convergenceIndex : void 0;
14968
15688
  const freshStories = resolvePageStories(freshSnapshotsToRebuild);
14969
- const layoutInputs = collectCanonicalLayoutInputs(document2);
14970
15689
  const fieldRegions = layoutInputs.fieldRegions;
14971
15690
  const freshBodyFragmentsByPageIndex = projectSurfaceBlocksToPageFragments(
14972
15691
  mainSurface,
@@ -15098,7 +15817,11 @@ function createLayoutEngine(options = {}) {
15098
15817
  try {
15099
15818
  const mod = await Promise.resolve().then(() => (init_measurement_backend_canvas(), measurement_backend_canvas_exports));
15100
15819
  const canvasProvider = mod.createCanvasBackend();
15101
- measurementProvider = canvasProvider;
15820
+ measurementProvider = wrapMeasurementProvider(
15821
+ canvasProvider,
15822
+ options.measurementCache,
15823
+ telemetryBus
15824
+ );
15102
15825
  cachedKey = null;
15103
15826
  cachedGraph = null;
15104
15827
  cachedFormatting = null;
@@ -15183,7 +15906,11 @@ function createLayoutEngine(options = {}) {
15183
15906
  },
15184
15907
  swapMeasurementProvider(provider) {
15185
15908
  const previousFidelity = measurementProvider.fidelity;
15186
- measurementProvider = provider;
15909
+ measurementProvider = wrapMeasurementProvider(
15910
+ provider,
15911
+ options.measurementCache,
15912
+ telemetryBus
15913
+ );
15187
15914
  if (previousFidelity !== provider.fidelity) {
15188
15915
  cachedKey = null;
15189
15916
  cachedGraph = null;
@@ -15212,6 +15939,10 @@ function createLayoutEngine(options = {}) {
15212
15939
  cachedFormatting = null;
15213
15940
  cachedMapper = null;
15214
15941
  },
15942
+ getMeasurementCacheStats() {
15943
+ if (!isCachedLayoutMeasurementProvider(measurementProvider)) return null;
15944
+ return measurementProvider.measurementCacheStats();
15945
+ },
15215
15946
  /**
15216
15947
  * L7 Phase 2.5 — seed the cached graph from a prerender envelope.
15217
15948
  * Populates both `cachedGraph` and `cachedKey` (keyed on the provided