@beyondwork/docx-react-component 1.0.129 → 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 (102) hide show
  1. package/dist/api/public-types.cjs +595 -18
  2. package/dist/api/public-types.d.cts +1 -1
  3. package/dist/api/public-types.d.ts +1 -1
  4. package/dist/api/public-types.js +4 -4
  5. package/dist/api/v3.cjs +1164 -332
  6. package/dist/api/v3.d.cts +2 -2
  7. package/dist/api/v3.d.ts +2 -2
  8. package/dist/api/v3.js +13 -13
  9. package/dist/{chunk-OTQIW2TC.js → chunk-35RHOE6I.js} +105 -4
  10. package/dist/{chunk-PGKUJZXV.js → chunk-3YCQM2RV.js} +6 -6
  11. package/dist/{chunk-JJGVE5J7.js → chunk-4YCWECLZ.js} +1 -1
  12. package/dist/{chunk-EZKJXIPH.js → chunk-6TBLDBCL.js} +1 -1
  13. package/dist/{chunk-SKPTKQHF.js → chunk-7G5GR3VV.js} +122 -23
  14. package/dist/{chunk-HUIHBBAQ.js → chunk-A3GSNB4G.js} +17 -6
  15. package/dist/{chunk-5DGKFNQT.js → chunk-A66ZVUAT.js} +150 -1
  16. package/dist/{chunk-YIYM4ZAP.js → chunk-CI2TD3T4.js} +1 -1
  17. package/dist/{chunk-63FYIGCT.js → chunk-DGA7M77X.js} +2 -2
  18. package/dist/{chunk-EB6M3GE6.js → chunk-FM4K4XFJ.js} +100 -97
  19. package/dist/{chunk-VNLDQJ47.js → chunk-HYHCRMR7.js} +1 -1
  20. package/dist/{chunk-DJU2W4E4.js → chunk-KNHMXKC6.js} +2 -2
  21. package/dist/{chunk-Q3QYGKFE.js → chunk-M7YRJX6V.js} +10 -21
  22. package/dist/{chunk-KFCQYZXR.js → chunk-OVLZQ6FZ.js} +61 -0
  23. package/dist/{chunk-W34X3KBR.js → chunk-PHMWH23E.js} +1 -1
  24. package/dist/{chunk-DDN2AIGE.js → chunk-Q7Y57KOK.js} +2 -2
  25. package/dist/{chunk-LJH64PV3.js → chunk-QXKQPUOM.js} +3 -3
  26. package/dist/{chunk-CX42VC67.js → chunk-SYQWQ6FE.js} +1 -1
  27. package/dist/{chunk-5DSHUYSY.js → chunk-T5YYFDZB.js} +1 -1
  28. package/dist/{chunk-RMRTQGW3.js → chunk-THVM6EP5.js} +371 -13
  29. package/dist/{chunk-XMHSGPLN.js → chunk-VRKK2CSZ.js} +111 -90
  30. package/dist/{chunk-OL2UEHRP.js → chunk-WUDSNHWF.js} +1 -1
  31. package/dist/{chunk-XQCAMKIQ.js → chunk-WZDKNF37.js} +250 -106
  32. package/dist/{chunk-PRAZBHNF.js → chunk-YLL7MF5C.js} +15 -15
  33. package/dist/{chunk-YZDZ4FGR.js → chunk-ZVC23LKV.js} +1 -1
  34. package/dist/compare.cjs +100 -97
  35. package/dist/compare.js +3 -3
  36. package/dist/core/commands/formatting-commands.d.cts +1 -1
  37. package/dist/core/commands/formatting-commands.d.ts +1 -1
  38. package/dist/core/commands/image-commands.cjs +16 -5
  39. package/dist/core/commands/image-commands.d.cts +1 -1
  40. package/dist/core/commands/image-commands.d.ts +1 -1
  41. package/dist/core/commands/image-commands.js +5 -5
  42. package/dist/core/commands/section-layout-commands.d.cts +1 -1
  43. package/dist/core/commands/section-layout-commands.d.ts +1 -1
  44. package/dist/core/commands/style-commands.d.cts +1 -1
  45. package/dist/core/commands/style-commands.d.ts +1 -1
  46. package/dist/core/commands/table-structure-commands.cjs +16 -5
  47. package/dist/core/commands/table-structure-commands.d.cts +1 -1
  48. package/dist/core/commands/table-structure-commands.d.ts +1 -1
  49. package/dist/core/commands/table-structure-commands.js +4 -4
  50. package/dist/core/commands/text-commands.cjs +16 -5
  51. package/dist/core/commands/text-commands.d.cts +1 -1
  52. package/dist/core/commands/text-commands.d.ts +1 -1
  53. package/dist/core/commands/text-commands.js +5 -5
  54. package/dist/core/selection/mapping.d.cts +1 -1
  55. package/dist/core/selection/mapping.d.ts +1 -1
  56. package/dist/core/state/editor-state.d.cts +1 -1
  57. package/dist/core/state/editor-state.d.ts +1 -1
  58. package/dist/index.cjs +1280 -347
  59. package/dist/index.d.cts +4 -4
  60. package/dist/index.d.ts +4 -4
  61. package/dist/index.js +24 -24
  62. package/dist/io/docx-session.cjs +216 -203
  63. package/dist/io/docx-session.d.cts +3 -3
  64. package/dist/io/docx-session.d.ts +3 -3
  65. package/dist/io/docx-session.js +6 -6
  66. package/dist/legal.cjs +9 -20
  67. package/dist/legal.js +3 -3
  68. package/dist/{loader-4qsw4eIU.d.ts → loader-B-aL5HGD.d.ts} +2 -2
  69. package/dist/{loader-B8TKhmQi.d.cts → loader-DiY_ZgKl.d.cts} +2 -2
  70. package/dist/{measurement-backend-canvas-Q3MJMEYX.js → measurement-backend-canvas-F7ZYDACK.js} +1 -1
  71. package/dist/{public-types-p9b8rfy8.d.ts → public-types-DyqnxxO9.d.ts} +124 -1
  72. package/dist/{public-types-B5CRoR6f.d.cts → public-types-gvubspUI.d.cts} +124 -1
  73. package/dist/public-types.cjs +595 -18
  74. package/dist/public-types.d.cts +1 -1
  75. package/dist/public-types.d.ts +1 -1
  76. package/dist/public-types.js +4 -4
  77. package/dist/runtime/collab.d.cts +2 -2
  78. package/dist/runtime/collab.d.ts +2 -2
  79. package/dist/runtime/document-runtime.cjs +908 -129
  80. package/dist/runtime/document-runtime.d.cts +1 -1
  81. package/dist/runtime/document-runtime.d.ts +1 -1
  82. package/dist/runtime/document-runtime.js +17 -17
  83. package/dist/{session-BnGIjaex.d.cts → session-BUN6B-Vj.d.cts} +2 -2
  84. package/dist/{session-vEYKf-w3.d.ts → session-CDB0hohT.d.ts} +2 -2
  85. package/dist/session.cjs +216 -203
  86. package/dist/session.d.cts +4 -4
  87. package/dist/session.d.ts +4 -4
  88. package/dist/session.js +7 -7
  89. package/dist/tailwind.cjs +595 -18
  90. package/dist/tailwind.d.cts +1 -1
  91. package/dist/tailwind.d.ts +1 -1
  92. package/dist/tailwind.js +8 -8
  93. package/dist/{types-BLuvZ6cQ.d.cts → types-C4bz3kDU.d.cts} +1 -1
  94. package/dist/{types-Dutlyj0T.d.ts → types-VWH6CRvG.d.ts} +1 -1
  95. package/dist/ui-tailwind/editor-surface/search-plugin.d.cts +2 -2
  96. package/dist/ui-tailwind/editor-surface/search-plugin.d.ts +2 -2
  97. package/dist/ui-tailwind/editor-surface/search-plugin.js +5 -5
  98. package/dist/ui-tailwind.cjs +595 -18
  99. package/dist/ui-tailwind.d.cts +2 -2
  100. package/dist/ui-tailwind.d.ts +2 -2
  101. package/dist/ui-tailwind.js +8 -8
  102. 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,
@@ -6842,7 +7050,7 @@ function buildEffectiveLayoutFormatting(input) {
6842
7050
  };
6843
7051
  }
6844
7052
  function createStructuralHash(value) {
6845
- const stable = stableStringify(value);
7053
+ const stable = stableStringify2(value);
6846
7054
  let hash = 2166136261;
6847
7055
  for (let i = 0; i < stable.length; i += 1) {
6848
7056
  hash ^= stable.charCodeAt(i);
@@ -6850,16 +7058,16 @@ function createStructuralHash(value) {
6850
7058
  }
6851
7059
  return `fnv1a32:${(hash >>> 0).toString(16).padStart(8, "0")}`;
6852
7060
  }
6853
- function stableStringify(value) {
7061
+ function stableStringify2(value) {
6854
7062
  if (value === null || typeof value !== "object") {
6855
7063
  return JSON.stringify(value);
6856
7064
  }
6857
7065
  if (Array.isArray(value)) {
6858
- return `[${value.map((entry) => stableStringify(entry)).join(",")}]`;
7066
+ return `[${value.map((entry) => stableStringify2(entry)).join(",")}]`;
6859
7067
  }
6860
7068
  const record = value;
6861
7069
  const keys = Object.keys(record).filter((key) => record[key] !== void 0).sort();
6862
- return `{${keys.map((key) => `${JSON.stringify(key)}:${stableStringify(record[key])}`).join(",")}}`;
7070
+ return `{${keys.map((key) => `${JSON.stringify(key)}:${stableStringify2(record[key])}`).join(",")}}`;
6863
7071
  }
6864
7072
 
6865
7073
  // src/runtime/formatting/formatting-context.ts
@@ -7368,6 +7576,7 @@ function createEditorSurfaceSnapshot(document2, _selection, activeStory = { kind
7368
7576
  ...options.authorColorPalette ? { authorColorPalette: options.authorColorPalette } : {}
7369
7577
  });
7370
7578
  const editableTargetsByBlockPath = options.editableTargetsByBlockPath ?? indexEditableTargetsByBlockPath(document2);
7579
+ const layoutIdentitiesByBlockPath = options.layoutIdentitiesByBlockPath;
7371
7580
  const activeStoryBlockPathBase = getActiveStoryBlockPathBase(document2, activeStory);
7372
7581
  chartModelStore.beginBuildPass(document2);
7373
7582
  const unsupportedNumberingFormatsSeen = options.emitFormattingTelemetry ? /* @__PURE__ */ new Set() : null;
@@ -7391,6 +7600,7 @@ function createEditorSurfaceSnapshot(document2, _selection, activeStory = { kind
7391
7600
  activeStory.kind !== "main",
7392
7601
  !isInViewport,
7393
7602
  editableTargetsByBlockPath,
7603
+ layoutIdentitiesByBlockPath,
7394
7604
  `${activeStoryBlockPathBase}/block[${index}]`
7395
7605
  );
7396
7606
  if (isInViewport) {
@@ -7457,7 +7667,7 @@ function isIndexInAnyRange(index, ranges) {
7457
7667
  }
7458
7668
  return false;
7459
7669
  }
7460
- 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) {
7461
7671
  if (block.type === "opaque_block") {
7462
7672
  const fragment = getOpaqueFragment(document2.preservation, block.fragmentId);
7463
7673
  const descriptor = fragment ? describeOpaqueFragment(fragment) : null;
@@ -7494,6 +7704,7 @@ function createSurfaceBlock(block, document2, cursor, counters, formattingContex
7494
7704
  promoteSecondaryStoryTextBoxes,
7495
7705
  cullBuild,
7496
7706
  editableTargetsByBlockPath,
7707
+ layoutIdentitiesByBlockPath,
7497
7708
  blockPath
7498
7709
  );
7499
7710
  }
@@ -7534,6 +7745,7 @@ function createSurfaceBlock(block, document2, cursor, counters, formattingContex
7534
7745
  promoteSecondaryStoryTextBoxes,
7535
7746
  cullBuild,
7536
7747
  editableTargetsByBlockPath,
7748
+ layoutIdentitiesByBlockPath,
7537
7749
  blockPath
7538
7750
  );
7539
7751
  }
@@ -7616,10 +7828,11 @@ function createSurfaceBlock(block, document2, cursor, counters, formattingContex
7616
7828
  cullBuild,
7617
7829
  editableTargetsByBlockPath,
7618
7830
  blockPath,
7619
- 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
7620
7833
  );
7621
7834
  }
7622
- 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) {
7623
7836
  const lockedFragmentIds = [];
7624
7837
  let innerCursor = cursor;
7625
7838
  if (cullBuild) {
@@ -7636,6 +7849,7 @@ function createTableBlock(tableIndex, table, document2, cursor, counters, format
7636
7849
  promoteSecondaryStoryTextBoxes,
7637
7850
  true,
7638
7851
  editableTargetsByBlockPath,
7852
+ layoutIdentitiesByBlockPath,
7639
7853
  tablePath !== void 0 ? `${tablePath}/row[${rowIndex}]/cell[${cellIndex}]/block[${childIndex}]` : void 0
7640
7854
  );
7641
7855
  lockedFragmentIds.push(...result.lockedFragmentIds);
@@ -7651,6 +7865,7 @@ function createTableBlock(tableIndex, table, document2, cursor, counters, format
7651
7865
  to: innerCursor,
7652
7866
  styleId: table.styleId,
7653
7867
  ...table.sourceRef !== void 0 ? { sourceRef: table.sourceRef } : {},
7868
+ ...tablePath !== void 0 && layoutIdentitiesByBlockPath?.get(tablePath) !== void 0 ? { layoutIdentity: layoutIdentitiesByBlockPath.get(tablePath) } : {},
7654
7869
  gridColumns: table.gridColumns,
7655
7870
  rows: []
7656
7871
  },
@@ -7688,6 +7903,7 @@ function createTableBlock(tableIndex, table, document2, cursor, counters, format
7688
7903
  promoteSecondaryStoryTextBoxes,
7689
7904
  cullBuild,
7690
7905
  editableTargetsByBlockPath,
7906
+ layoutIdentitiesByBlockPath,
7691
7907
  tablePath !== void 0 ? `${tablePath}/row[${rowIndex}]/cell[${cellIndex}]/block[${childIndex}]` : void 0
7692
7908
  );
7693
7909
  cellContent.push(result.block);
@@ -7776,6 +7992,7 @@ function createTableBlock(tableIndex, table, document2, cursor, counters, format
7776
7992
  to: innerCursor,
7777
7993
  styleId: table.styleId,
7778
7994
  ...table.sourceRef !== void 0 ? { sourceRef: table.sourceRef } : {},
7995
+ ...tablePath !== void 0 && layoutIdentitiesByBlockPath?.get(tablePath) !== void 0 ? { layoutIdentity: layoutIdentitiesByBlockPath.get(tablePath) } : {},
7779
7996
  gridColumns: table.gridColumns,
7780
7997
  ...gridColumnsRelative ? { gridColumnsRelative } : {},
7781
7998
  ...resolvedTable.table?.alignment ? { alignment: resolvedTable.table.alignment } : {},
@@ -7963,7 +8180,7 @@ function resolveCellBorderStyles(borders, tableBorders, position) {
7963
8180
  if (left) result.borderLeft = left;
7964
8181
  return result;
7965
8182
  }
7966
- 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) {
7967
8184
  const children = [];
7968
8185
  const lockedFragmentIds = [];
7969
8186
  let innerCursor = cursor;
@@ -7980,6 +8197,7 @@ function createSdtBlock(sdtIndex, block, document2, cursor, counters, formatting
7980
8197
  promoteSecondaryStoryTextBoxes,
7981
8198
  cullBuild,
7982
8199
  editableTargetsByBlockPath,
8200
+ layoutIdentitiesByBlockPath,
7983
8201
  sdtPath !== void 0 ? `${sdtPath}/block[${childIndex}]` : void 0
7984
8202
  );
7985
8203
  children.push(result.block);
@@ -8022,7 +8240,7 @@ function getRecursableSdtBlockedReasonCode(block) {
8022
8240
  ].filter(Boolean).join(" ").toLowerCase();
8023
8241
  return searchText.includes("table of contents") || /\btoc\b/u.test(searchText) ? "workflow_preserve_only" : null;
8024
8242
  }
8025
- 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) {
8026
8244
  const themeResolver = formattingContext.theme;
8027
8245
  const effectiveNumbering = formattingContext.resolveEffectiveParagraphNumbering(paragraph);
8028
8246
  let resolvedNumbering = null;
@@ -8045,6 +8263,7 @@ function createParagraphBlock(paragraphIndex, paragraph, document2, start, forma
8045
8263
  from: start,
8046
8264
  to: start,
8047
8265
  ...editableTarget !== void 0 ? { editableTarget } : {},
8266
+ ...layoutIdentity !== void 0 ? { layoutIdentity } : {},
8048
8267
  ...paragraph.styleId ? { styleId: paragraph.styleId } : {},
8049
8268
  ...effectiveNumbering ? { numbering: effectiveNumbering } : {},
8050
8269
  ...resolvedNumbering ? {
@@ -14668,12 +14887,330 @@ function createEmpiricalProvider() {
14668
14887
  return createEmpiricalBackend();
14669
14888
  }
14670
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
+
14671
15202
  // src/runtime/layout/layout-engine-version.ts
14672
- var LAYOUT_ENGINE_VERSION = 89;
15203
+ var LAYOUT_ENGINE_VERSION = 93;
14673
15204
 
14674
15205
  // src/runtime/layout/layout-engine-instance.ts
14675
15206
  var FULL_VIEWPORT_WINDOW_KEY = "full";
14676
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
+ }
14677
15214
  function normalizeViewportPageWindow(window2) {
14678
15215
  if (!window2) return void 0;
14679
15216
  const buffer = Number.isFinite(window2.bufferPages) ? Math.max(0, Math.floor(window2.bufferPages ?? 0)) : DEFAULT_VIEWPORT_PAGE_WINDOW_BUFFER;
@@ -14869,8 +15406,22 @@ function recordFullRebuildReason(reasonKind) {
14869
15406
  probe.invalidationCounts[totalKey] = (probe.invalidationCounts[totalKey] ?? 0) + 1;
14870
15407
  probe.invalidationCounts[byReasonKey] = (probe.invalidationCounts[byReasonKey] ?? 0) + 1;
14871
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
+ }
14872
15419
  function createLayoutEngine(options = {}) {
14873
- let measurementProvider = options.measurementProvider ?? createEmpiricalMeasurementProvider();
15420
+ let measurementProvider = wrapMeasurementProvider(
15421
+ options.measurementProvider ?? createEmpiricalMeasurementProvider(),
15422
+ options.measurementCache,
15423
+ options.telemetryBus
15424
+ );
14874
15425
  const autoUpgradeToCanvas = options.autoUpgradeToCanvasBackend !== false;
14875
15426
  const telemetryBus = options.telemetryBus;
14876
15427
  const dirtyFieldFamilies = /* @__PURE__ */ new Set();
@@ -14970,13 +15521,20 @@ function createLayoutEngine(options = {}) {
14970
15521
  const pageCountBeforeRecompute = previousPageCount;
14971
15522
  const document2 = input.document;
14972
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
+ );
14973
15531
  const mainSurface = createEditorSurfaceSnapshot(
14974
15532
  document2,
14975
15533
  createSelectionSnapshot(0, 0),
14976
- MAIN_STORY_TARGET
15534
+ MAIN_STORY_TARGET,
15535
+ { editableTargetsByBlockPath, layoutIdentitiesByBlockPath }
14977
15536
  );
14978
15537
  const sections = buildResolvedSections(document2);
14979
- const layoutInputs = collectCanonicalLayoutInputs(document2);
14980
15538
  const fieldRegions = layoutInputs.fieldRegions;
14981
15539
  const pageStack = buildPageStackWithSplits(
14982
15540
  document2,
@@ -15088,10 +15646,18 @@ function createLayoutEngine(options = {}) {
15088
15646
  const firstDirty = range.firstPageIndex;
15089
15647
  if (firstDirty < 0 || firstDirty >= priorGraph.pages.length) return null;
15090
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
+ );
15091
15656
  const mainSurface = createEditorSurfaceSnapshot(
15092
15657
  document2,
15093
15658
  createSelectionSnapshot(0, 0),
15094
- MAIN_STORY_TARGET
15659
+ MAIN_STORY_TARGET,
15660
+ { editableTargetsByBlockPath, layoutIdentitiesByBlockPath }
15095
15661
  );
15096
15662
  const sections = buildResolvedSections(document2);
15097
15663
  const dirtyPage = priorGraph.pages[firstDirty];
@@ -15120,7 +15686,6 @@ function createLayoutEngine(options = {}) {
15120
15686
  const freshSnapshotsToRebuild = freshSnapshots.slice(0, convergenceIndex);
15121
15687
  const convergedTailStart = convergenceIndex < freshSnapshots.length ? firstDirty + convergenceIndex : void 0;
15122
15688
  const freshStories = resolvePageStories(freshSnapshotsToRebuild);
15123
- const layoutInputs = collectCanonicalLayoutInputs(document2);
15124
15689
  const fieldRegions = layoutInputs.fieldRegions;
15125
15690
  const freshBodyFragmentsByPageIndex = projectSurfaceBlocksToPageFragments(
15126
15691
  mainSurface,
@@ -15252,7 +15817,11 @@ function createLayoutEngine(options = {}) {
15252
15817
  try {
15253
15818
  const mod = await Promise.resolve().then(() => (init_measurement_backend_canvas(), measurement_backend_canvas_exports));
15254
15819
  const canvasProvider = mod.createCanvasBackend();
15255
- measurementProvider = canvasProvider;
15820
+ measurementProvider = wrapMeasurementProvider(
15821
+ canvasProvider,
15822
+ options.measurementCache,
15823
+ telemetryBus
15824
+ );
15256
15825
  cachedKey = null;
15257
15826
  cachedGraph = null;
15258
15827
  cachedFormatting = null;
@@ -15337,7 +15906,11 @@ function createLayoutEngine(options = {}) {
15337
15906
  },
15338
15907
  swapMeasurementProvider(provider) {
15339
15908
  const previousFidelity = measurementProvider.fidelity;
15340
- measurementProvider = provider;
15909
+ measurementProvider = wrapMeasurementProvider(
15910
+ provider,
15911
+ options.measurementCache,
15912
+ telemetryBus
15913
+ );
15341
15914
  if (previousFidelity !== provider.fidelity) {
15342
15915
  cachedKey = null;
15343
15916
  cachedGraph = null;
@@ -15366,6 +15939,10 @@ function createLayoutEngine(options = {}) {
15366
15939
  cachedFormatting = null;
15367
15940
  cachedMapper = null;
15368
15941
  },
15942
+ getMeasurementCacheStats() {
15943
+ if (!isCachedLayoutMeasurementProvider(measurementProvider)) return null;
15944
+ return measurementProvider.measurementCacheStats();
15945
+ },
15369
15946
  /**
15370
15947
  * L7 Phase 2.5 — seed the cached graph from a prerender envelope.
15371
15948
  * Populates both `cachedGraph` and `cachedKey` (keyed on the provided