@beyondwork/docx-react-component 1.0.121 → 1.0.123

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 +318 -32
  2. package/dist/api/public-types.d.cts +2 -2
  3. package/dist/api/public-types.d.ts +2 -2
  4. package/dist/api/public-types.js +3 -3
  5. package/dist/api/v3.cjs +349 -62
  6. package/dist/api/v3.d.cts +3 -3
  7. package/dist/api/v3.d.ts +3 -3
  8. package/dist/api/v3.js +10 -10
  9. package/dist/{canonical-document-ByIqTd4s.d.cts → canonical-document-CG2TgAzj.d.cts} +1 -1
  10. package/dist/{canonical-document-ByIqTd4s.d.ts → canonical-document-CG2TgAzj.d.ts} +1 -1
  11. package/dist/{chunk-B4YHWFE3.js → chunk-32ZAOQ54.js} +1 -1
  12. package/dist/{chunk-QNGJRZ2D.js → chunk-4IPEZYQX.js} +1 -1
  13. package/dist/{chunk-3OFSP2IX.js → chunk-BOHHIVQ2.js} +3 -3
  14. package/dist/{chunk-EMDH4IQN.js → chunk-E5IBDE5E.js} +4 -3
  15. package/dist/{chunk-TFSXOIAI.js → chunk-FNWKE74J.js} +43 -3
  16. package/dist/{chunk-IT2DK3A7.js → chunk-H2YQKA55.js} +9 -7
  17. package/dist/{chunk-3TUQCHYT.js → chunk-H6IL5ABU.js} +47 -7
  18. package/dist/{chunk-GON2DNTE.js → chunk-HXHQA4BU.js} +1 -1
  19. package/dist/{chunk-3OHVK2D6.js → chunk-IR7QV2BX.js} +17 -1
  20. package/dist/{chunk-ZKSDVHGH.js → chunk-KOHQFZMM.js} +1 -1
  21. package/dist/{chunk-XVFENXLK.js → chunk-LGWNN3L2.js} +2 -2
  22. package/dist/{chunk-TMU7JMXX.js → chunk-MB7RJBSN.js} +9 -21
  23. package/dist/{chunk-UWDWGQH5.js → chunk-ML4A4WUN.js} +1 -1
  24. package/dist/{chunk-GZW2ERUO.js → chunk-N4VIXI2Z.js} +3 -3
  25. package/dist/{chunk-S4ANOS2M.js → chunk-NNPVA5VL.js} +2 -2
  26. package/dist/{chunk-QFU7ZOAD.js → chunk-PFYUJU3Q.js} +176 -36
  27. package/dist/{chunk-37SEJQ3G.js → chunk-RSYN6FTS.js} +2 -2
  28. package/dist/{chunk-OBCP6VTG.js → chunk-RWERZWHR.js} +1 -1
  29. package/dist/{chunk-UHQOUTAX.js → chunk-SGSJ4DQA.js} +377 -50
  30. package/dist/{chunk-PCXTMEGY.js → chunk-UHJLCPLU.js} +24 -14
  31. package/dist/{chunk-G3B2OBCZ.js → chunk-ZRHLLPSJ.js} +271 -26
  32. package/dist/compare.d.cts +1 -1
  33. package/dist/compare.d.ts +1 -1
  34. package/dist/core/commands/formatting-commands.d.cts +2 -2
  35. package/dist/core/commands/formatting-commands.d.ts +2 -2
  36. package/dist/core/commands/image-commands.cjs +50 -9
  37. package/dist/core/commands/image-commands.d.cts +2 -2
  38. package/dist/core/commands/image-commands.d.ts +2 -2
  39. package/dist/core/commands/image-commands.js +5 -5
  40. package/dist/core/commands/section-layout-commands.d.cts +2 -2
  41. package/dist/core/commands/section-layout-commands.d.ts +2 -2
  42. package/dist/core/commands/style-commands.d.cts +2 -2
  43. package/dist/core/commands/style-commands.d.ts +2 -2
  44. package/dist/core/commands/table-structure-commands.cjs +50 -9
  45. package/dist/core/commands/table-structure-commands.d.cts +2 -2
  46. package/dist/core/commands/table-structure-commands.d.ts +2 -2
  47. package/dist/core/commands/table-structure-commands.js +4 -4
  48. package/dist/core/commands/text-commands.cjs +66 -9
  49. package/dist/core/commands/text-commands.d.cts +3 -2
  50. package/dist/core/commands/text-commands.d.ts +3 -2
  51. package/dist/core/commands/text-commands.js +5 -5
  52. package/dist/core/selection/mapping.d.cts +2 -2
  53. package/dist/core/selection/mapping.d.ts +2 -2
  54. package/dist/core/state/editor-state.d.cts +2 -2
  55. package/dist/core/state/editor-state.d.ts +2 -2
  56. package/dist/index.cjs +1196 -197
  57. package/dist/index.d.cts +5 -5
  58. package/dist/index.d.ts +5 -5
  59. package/dist/index.js +278 -85
  60. package/dist/io/docx-session.cjs +10 -21
  61. package/dist/io/docx-session.d.cts +4 -4
  62. package/dist/io/docx-session.d.ts +4 -4
  63. package/dist/io/docx-session.js +4 -4
  64. package/dist/legal.cjs +8 -20
  65. package/dist/legal.d.cts +1 -1
  66. package/dist/legal.d.ts +1 -1
  67. package/dist/legal.js +3 -3
  68. package/dist/{loader-BF8ju_LK.d.ts → loader-D9KCtj4m.d.cts} +4 -22
  69. package/dist/{loader-g54WRvj1.d.cts → loader-D9y4ZRjj.d.ts} +4 -22
  70. package/dist/{public-types-Dl1jiWjk.d.ts → public-types-CNnMHZM9.d.ts} +263 -213
  71. package/dist/{public-types-D_y4Ptcj.d.cts → public-types-DajNGKV4.d.cts} +263 -213
  72. package/dist/public-types.cjs +318 -32
  73. package/dist/public-types.d.cts +2 -2
  74. package/dist/public-types.d.ts +2 -2
  75. package/dist/public-types.js +3 -3
  76. package/dist/runtime/collab.d.cts +3 -3
  77. package/dist/runtime/collab.d.ts +3 -3
  78. package/dist/runtime/document-runtime.cjs +752 -77
  79. package/dist/runtime/document-runtime.d.cts +2 -2
  80. package/dist/runtime/document-runtime.d.ts +2 -2
  81. package/dist/runtime/document-runtime.js +14 -14
  82. package/dist/{session-C1EPAkcI.d.ts → session-DEmaOEjA.d.ts} +3 -3
  83. package/dist/{session-D15QOO0Q.d.cts → session-DyQGlryH.d.cts} +3 -3
  84. package/dist/session.cjs +12 -618
  85. package/dist/session.d.cts +5 -5
  86. package/dist/session.d.ts +5 -5
  87. package/dist/session.js +7 -9
  88. package/dist/tailwind.cjs +489 -63
  89. package/dist/tailwind.d.cts +2 -2
  90. package/dist/tailwind.d.ts +2 -2
  91. package/dist/tailwind.js +7 -7
  92. package/dist/{types-BoSRp2Vg.d.cts → types-CxE1aZiv.d.cts} +2 -2
  93. package/dist/{types-DEvRwq9C.d.ts → types-DjJNaE9c.d.ts} +2 -2
  94. package/dist/ui-tailwind/editor-surface/search-plugin.d.cts +3 -3
  95. package/dist/ui-tailwind/editor-surface/search-plugin.d.ts +3 -3
  96. package/dist/ui-tailwind/editor-surface/search-plugin.js +4 -4
  97. package/dist/ui-tailwind/theme/tokens.css +387 -0
  98. package/dist/ui-tailwind.cjs +489 -63
  99. package/dist/ui-tailwind.d.cts +3 -3
  100. package/dist/ui-tailwind.d.ts +3 -3
  101. package/dist/ui-tailwind.js +7 -7
  102. package/package.json +7 -3
package/dist/index.cjs CHANGED
@@ -6325,6 +6325,28 @@ function collectEditableTargetRefs(doc, cache) {
6325
6325
  collectReviewEditableTargets(doc, targets);
6326
6326
  return targets;
6327
6327
  }
6328
+ function collectEditableTargetRefsForStoryBlockRanges(doc, storyKey2, ranges, cache) {
6329
+ const targets = [];
6330
+ const context = collectStoryBlockContexts(doc).find((entry) => entry.storyKey === storyKey2);
6331
+ if (!context) return targets;
6332
+ const normalized = normalizeEditableTargetRanges(ranges, context.blocks.length);
6333
+ for (const range of normalized) {
6334
+ collectEditableTargetsInBlocks(
6335
+ context.blocks.slice(range.start, range.end),
6336
+ {
6337
+ storyKey: context.storyKey,
6338
+ basePath: context.basePath,
6339
+ insideSdt: false,
6340
+ insideTextBox: false,
6341
+ tableDepth: 0
6342
+ },
6343
+ targets,
6344
+ cache,
6345
+ range.start
6346
+ );
6347
+ }
6348
+ return targets;
6349
+ }
6328
6350
  function createEditableTargetBlockCache() {
6329
6351
  const map = /* @__PURE__ */ new WeakMap();
6330
6352
  return {
@@ -6360,12 +6382,13 @@ function buildBlockCacheSignature(context, blockIndex) {
6360
6382
  owner?.targetKey ?? ""
6361
6383
  ].join("|");
6362
6384
  }
6363
- function collectEditableTargetsInBlocks(blocks, context, targets, cache) {
6385
+ function collectEditableTargetsInBlocks(blocks, context, targets, cache, blockIndexOffset = 0) {
6364
6386
  for (let blockIndex = 0; blockIndex < blocks.length; blockIndex += 1) {
6365
6387
  const block = blocks[blockIndex];
6366
6388
  if (!block) continue;
6367
- const blockPath = `${context.basePath}/block[${blockIndex}]`;
6368
- const signature = cache !== void 0 ? buildBlockCacheSignature(context, blockIndex) : "";
6389
+ const absoluteBlockIndex = blockIndex + blockIndexOffset;
6390
+ const blockPath = `${context.basePath}/block[${absoluteBlockIndex}]`;
6391
+ const signature = cache !== void 0 ? buildBlockCacheSignature(context, absoluteBlockIndex) : "";
6369
6392
  if (cache !== void 0) {
6370
6393
  const cached = cache.get(block);
6371
6394
  if (cached !== void 0 && cached.blockPath === blockPath && cached.signature === signature) {
@@ -6549,6 +6572,22 @@ function collectEditableTargetsInTable(table, tablePath, context, targets, cache
6549
6572
  }
6550
6573
  }
6551
6574
  }
6575
+ function normalizeEditableTargetRanges(ranges, blockCount) {
6576
+ const normalized = [];
6577
+ const sortedRanges = [...ranges].sort((left, right) => left.start - right.start || left.end - right.end);
6578
+ for (const range of sortedRanges) {
6579
+ const start = Math.max(0, Math.min(blockCount, Math.floor(range.start)));
6580
+ const end = Math.max(start, Math.min(blockCount, Math.ceil(range.end)));
6581
+ if (start === end) continue;
6582
+ const previous = normalized[normalized.length - 1];
6583
+ if (previous && start <= previous.end) {
6584
+ previous.end = Math.max(previous.end, end);
6585
+ } else {
6586
+ normalized.push({ start, end });
6587
+ }
6588
+ }
6589
+ return normalized;
6590
+ }
6552
6591
  function findVerticalMergeOwner(owners, gridColumnStart2, gridSpan) {
6553
6592
  return owners.find(
6554
6593
  (owner) => owner.gridColumnStart === gridColumnStart2 && owner.gridSpan === gridSpan
@@ -11864,6 +11903,8 @@ function createSurfaceBlock(block, document2, cursor, counters, formattingContex
11864
11903
  formattingContext,
11865
11904
  promoteSecondaryStoryTextBoxes,
11866
11905
  cullBuild,
11906
+ editableTargetsByBlockPath,
11907
+ blockPath,
11867
11908
  blockPath !== void 0 ? editableTargetsByBlockPath.get(blockPath) : void 0
11868
11909
  );
11869
11910
  }
@@ -12270,7 +12311,7 @@ function getRecursableSdtBlockedReasonCode(block) {
12270
12311
  ].filter(Boolean).join(" ").toLowerCase();
12271
12312
  return searchText.includes("table of contents") || /\btoc\b/u.test(searchText) ? "workflow_preserve_only" : null;
12272
12313
  }
12273
- function createParagraphBlock(paragraphIndex, paragraph, document2, start, formattingContext, promoteSecondaryStoryTextBoxes, cullBuild = false, editableTarget) {
12314
+ function createParagraphBlock(paragraphIndex, paragraph, document2, start, formattingContext, promoteSecondaryStoryTextBoxes, cullBuild = false, editableTargetsByBlockPath = EMPTY_EDITABLE_TARGETS_BY_BLOCK_PATH, blockPath, editableTarget) {
12274
12315
  const themeResolver = formattingContext.theme;
12275
12316
  const effectiveNumbering = formattingContext.resolveEffectiveParagraphNumbering(paragraph);
12276
12317
  let resolvedNumbering = null;
@@ -12335,6 +12376,8 @@ function createParagraphBlock(paragraphIndex, paragraph, document2, start, forma
12335
12376
  document2,
12336
12377
  cursor,
12337
12378
  promoteSecondaryStoryTextBoxes,
12379
+ blockPath !== void 0 ? `${blockPath}/inline[${childIndex}]` : void 0,
12380
+ editableTargetsByBlockPath,
12338
12381
  void 0,
12339
12382
  cullBuild,
12340
12383
  themeResolver,
@@ -12391,7 +12434,7 @@ function isVisibleTocResultInline(node) {
12391
12434
  return false;
12392
12435
  }
12393
12436
  }
12394
- function appendInlineSegments(paragraph, node, document2, start, promoteSecondaryStoryTextBoxes, hyperlinkHref, cullBuild = false, themeResolver, formattingContext) {
12437
+ function appendInlineSegments(paragraph, node, document2, start, promoteSecondaryStoryTextBoxes, inlinePath, editableTargetsByBlockPath = EMPTY_EDITABLE_TARGETS_BY_BLOCK_PATH, hyperlinkHref, cullBuild = false, themeResolver, formattingContext) {
12395
12438
  switch (node.type) {
12396
12439
  case "text": {
12397
12440
  const cloned = node.marks ? cloneMarks2(node.marks) : { marks: [] };
@@ -12444,13 +12487,16 @@ function appendInlineSegments(paragraph, node, document2, start, promoteSecondar
12444
12487
  return { nextCursor: start + 1, lockedFragmentIds: [] };
12445
12488
  case "hyperlink": {
12446
12489
  let cursor = start;
12447
- for (const child of node.children) {
12490
+ for (let childIndex = 0; childIndex < node.children.length; childIndex += 1) {
12491
+ const child = node.children[childIndex];
12448
12492
  const result = appendInlineSegments(
12449
12493
  paragraph,
12450
12494
  child,
12451
12495
  document2,
12452
12496
  cursor,
12453
12497
  promoteSecondaryStoryTextBoxes,
12498
+ inlinePath !== void 0 ? `${inlinePath}/child[${childIndex}]` : void 0,
12499
+ editableTargetsByBlockPath,
12454
12500
  node.href,
12455
12501
  cullBuild,
12456
12502
  themeResolver,
@@ -12509,6 +12555,33 @@ function appendInlineSegments(paragraph, node, document2, start, promoteSecondar
12509
12555
  if (isMicrosoftSensitivityLabelShape(node)) {
12510
12556
  return { nextCursor: start + 1, lockedFragmentIds: [] };
12511
12557
  }
12558
+ if (node.isTextBox && node.txbxBlocks !== void 0) {
12559
+ const txbxTextSegment = extractTxbxFirstTextSegment(node.txbxBlocks);
12560
+ const txbxText = txbxTextSegment?.text ?? node.text;
12561
+ const txbxBody = surfaceTextBoxBodyFromShape(
12562
+ node,
12563
+ void 0,
12564
+ inlinePath,
12565
+ editableTargetsByBlockPath
12566
+ );
12567
+ paragraph.segments.push({
12568
+ segmentId: `${paragraph.blockId}-segment-${paragraph.segments.length}`,
12569
+ kind: "shape",
12570
+ from: start,
12571
+ to: start + 1,
12572
+ label: "Text box",
12573
+ detail: createShapeDetail(node),
12574
+ ...node.geometry !== void 0 ? { geometry: node.geometry } : {},
12575
+ isTextBox: true,
12576
+ ...node.textBoxBody ? { textBoxBody: node.textBoxBody } : {},
12577
+ ...node.preserveOnlyObject ? { preserveOnlyObject: surfacePreserveOnlyObject(node.preserveOnlyObject) } : {},
12578
+ ...txbxText ? { txbxText } : {},
12579
+ ...txbxBody ? { txbxBody } : {},
12580
+ ...txbxTextSegment?.marks && txbxTextSegment.marks.length > 0 ? { txbxMarks: txbxTextSegment.marks } : {},
12581
+ ...txbxTextSegment?.markAttrs ? { txbxMarkAttrs: txbxTextSegment.markAttrs } : {}
12582
+ });
12583
+ return { nextCursor: start + 1, lockedFragmentIds: [] };
12584
+ }
12512
12585
  if (promoteSecondaryStoryTextBoxes && node.isTextBox && node.text) {
12513
12586
  return appendTextBoxSegment(
12514
12587
  paragraph,
@@ -12568,7 +12641,7 @@ function appendInlineSegments(paragraph, node, document2, start, promoteSecondar
12568
12641
  const anchor = surfaceAnchorFromGeometry(node.anchor);
12569
12642
  const txbxTextSegment = c.isTextBox ? extractTxbxFirstTextSegment(c.txbxBlocks) : void 0;
12570
12643
  const txbxText = txbxTextSegment?.text ?? (c.isTextBox ? c.text : void 0);
12571
- const txbxBody = c.isTextBox ? surfaceTextBoxBodyFromShape(c, node.sourceRef) : void 0;
12644
+ const txbxBody = c.isTextBox ? surfaceTextBoxBodyFromShape(c, node.sourceRef, inlinePath, editableTargetsByBlockPath) : void 0;
12572
12645
  const surfaceFill = c.fill;
12573
12646
  paragraph.segments.push({
12574
12647
  segmentId: `${paragraph.blockId}-segment-${paragraph.segments.length}`,
@@ -12745,13 +12818,16 @@ function appendInlineSegments(paragraph, node, document2, start, promoteSecondar
12745
12818
  const refHyperlinkHref = (node.fieldFamily === "REF" || node.fieldFamily === "PAGEREF" || node.fieldFamily === "NOTEREF") && node.switches?.hyperlink === true && node.fieldTarget ? `#${node.fieldTarget}` : void 0;
12746
12819
  let cursor = start;
12747
12820
  const lockedIds = [];
12748
- for (const child of node.children) {
12821
+ for (let childIndex = 0; childIndex < node.children.length; childIndex += 1) {
12822
+ const child = node.children[childIndex];
12749
12823
  const result = appendInlineSegments(
12750
12824
  paragraph,
12751
12825
  child,
12752
12826
  document2,
12753
12827
  cursor,
12754
12828
  promoteSecondaryStoryTextBoxes,
12829
+ inlinePath !== void 0 ? `${inlinePath}/child[${childIndex}]` : void 0,
12830
+ editableTargetsByBlockPath,
12755
12831
  refHyperlinkHref ?? hyperlinkHref,
12756
12832
  cullBuild,
12757
12833
  themeResolver,
@@ -12998,7 +13074,7 @@ function extractTxbxFirstTextSegment(blocks) {
12998
13074
  }
12999
13075
  return void 0;
13000
13076
  }
13001
- function surfaceTextBoxBodyFromShape(shape, sourceRef) {
13077
+ function surfaceTextBoxBodyFromShape(shape, sourceRef, inlinePath, editableTargetsByBlockPath = EMPTY_EDITABLE_TARGETS_BY_BLOCK_PATH) {
13002
13078
  if (!shape.isTextBox && shape.txbxContentXml === void 0 && shape.txbxBlocks === void 0) {
13003
13079
  return void 0;
13004
13080
  }
@@ -13024,9 +13100,12 @@ function surfaceTextBoxBodyFromShape(shape, sourceRef) {
13024
13100
  (run, inlineIndex) => surfaceTextBoxRunFromLegacyRun(run, inlineIndex)
13025
13101
  ) ?? [];
13026
13102
  const text = runs.map((run) => run.text ?? "").join("");
13103
+ const blockPath = inlinePath !== void 0 ? `${inlinePath}/txbx/block[${blockIndex}]` : void 0;
13104
+ const editableTarget = blockPath !== void 0 ? editableTargetsByBlockPath.get(blockPath) : void 0;
13027
13105
  return [{
13028
13106
  ...block.sourceRef !== void 0 ? { sourceRef: block.sourceRef } : {},
13029
13107
  blockIndex,
13108
+ ...editableTarget !== void 0 ? { editableTarget } : {},
13030
13109
  text,
13031
13110
  textLength: Array.from(text).length,
13032
13111
  ...block.borders !== void 0 ? { borders: block.borders } : {},
@@ -16710,6 +16789,7 @@ function buildPageGraph(inputOrPages, sectionsArg, storiesArg) {
16710
16789
  regions,
16711
16790
  divergences: frameDivergences,
16712
16791
  subParts: input.subParts,
16792
+ anchors: input.anchors,
16713
16793
  pageFieldCounts
16714
16794
  });
16715
16795
  const divergences = builtFrame.divergences;
@@ -16876,6 +16956,7 @@ function buildPageFrame(input) {
16876
16956
  stories: input.stories,
16877
16957
  regions,
16878
16958
  subParts: input.subParts,
16959
+ anchors: input.anchors,
16879
16960
  pageFieldCounts: input.pageFieldCounts
16880
16961
  });
16881
16962
  const divergences = [...input.divergences, ...pageLocalStoryResult.divergences];
@@ -16913,6 +16994,7 @@ function buildPageLocalStoryInstances(input) {
16913
16994
  input.stories.header,
16914
16995
  input.regions.header,
16915
16996
  findHeaderFooterPart(input.subParts?.headers, input.stories.header),
16997
+ input.anchors,
16916
16998
  input.pageFieldCounts
16917
16999
  );
16918
17000
  instances.push(built.instance);
@@ -16929,6 +17011,7 @@ function buildPageLocalStoryInstances(input) {
16929
17011
  input.stories.footer,
16930
17012
  input.regions.footer,
16931
17013
  findHeaderFooterPart(input.subParts?.footers, input.stories.footer),
17014
+ input.anchors,
16932
17015
  input.pageFieldCounts
16933
17016
  );
16934
17017
  instances.push(built.instance);
@@ -16936,7 +17019,7 @@ function buildPageLocalStoryInstances(input) {
16936
17019
  }
16937
17020
  return { instances, divergences };
16938
17021
  }
16939
- function buildPageLocalStoryInstance(frameId, pageId, pageIndex, sectionIndex, displayPageNumber, layout, target, region, source, pageFieldCounts) {
17022
+ function buildPageLocalStoryInstance(frameId, pageId, pageIndex, sectionIndex, displayPageNumber, layout, target, region, source, anchors, pageFieldCounts) {
16940
17023
  const measuredFrameHeightTwips = region?.heightTwips ?? 0;
16941
17024
  const sectionPart = target.sectionIndex === void 0 ? "section-unknown" : `section-${target.sectionIndex}`;
16942
17025
  const instanceId = `${frameId}:${target.kind}:${target.variant}:${target.relationshipId}`;
@@ -16957,7 +17040,9 @@ function buildPageLocalStoryInstance(frameId, pageId, pageIndex, sectionIndex, d
16957
17040
  kind: target.kind,
16958
17041
  variant: target.variant,
16959
17042
  relationshipId: target.relationshipId,
16960
- region
17043
+ region,
17044
+ storyBasePath: `${target.kind}:${source.partPath ?? `word/${target.kind}${target.relationshipId}.xml`}`,
17045
+ anchorsByInlinePath: buildAnchorsByInlinePath(anchors)
16961
17046
  }) : { objects: [], divergences: [] };
16962
17047
  const signature = buildPageLocalStorySignature({
16963
17048
  kind: target.kind,
@@ -17011,6 +17096,23 @@ function buildPageLocalStorySignature(input) {
17011
17096
  object.anchorRectTwips?.yTwips ?? "",
17012
17097
  object.anchorRectTwips?.widthTwips ?? "",
17013
17098
  object.anchorRectTwips?.heightTwips ?? "",
17099
+ object.textBoxBody?.bodyKey ?? "",
17100
+ object.textBoxBody?.status ?? "",
17101
+ object.textBoxBody?.unavailableReason ?? "",
17102
+ object.textBoxBody?.contentRectTwips?.xTwips ?? "",
17103
+ object.textBoxBody?.contentRectTwips?.yTwips ?? "",
17104
+ object.textBoxBody?.contentRectTwips?.widthTwips ?? "",
17105
+ object.textBoxBody?.contentRectTwips?.heightTwips ?? "",
17106
+ object.textBoxBody?.paragraphs.map(
17107
+ (paragraph) => [
17108
+ paragraph.paragraphKey,
17109
+ paragraph.rectTwips?.xTwips ?? "",
17110
+ paragraph.rectTwips?.yTwips ?? "",
17111
+ paragraph.rectTwips?.widthTwips ?? "",
17112
+ paragraph.rectTwips?.heightTwips ?? "",
17113
+ paragraph.unavailableReason ?? ""
17114
+ ].join("/")
17115
+ ).join(",") ?? "",
17014
17116
  object.relationshipIds?.join(",") ?? "",
17015
17117
  object.mediaIds?.join(",") ?? "",
17016
17118
  object.wrapMode ?? "",
@@ -17155,6 +17257,10 @@ function truncatePageLocalStoryPreview(text) {
17155
17257
  if (text.length <= MAX_PAGE_LOCAL_STORY_PREVIEW_CHARS) return text;
17156
17258
  return `${text.slice(0, MAX_PAGE_LOCAL_STORY_PREVIEW_CHARS - 1).trimEnd()}\u2026`;
17157
17259
  }
17260
+ function buildAnchorsByInlinePath(anchors) {
17261
+ if (!anchors || anchors.length === 0) return void 0;
17262
+ return new Map(anchors.map((anchor) => [anchor.inlinePath, anchor]));
17263
+ }
17158
17264
  function collectStoryAnchoredObjects(blocks, context) {
17159
17265
  const objects = [];
17160
17266
  const divergences = [];
@@ -17198,26 +17304,45 @@ function collectStoryAnchoredObjects(blocks, context) {
17198
17304
  });
17199
17305
  ordinal += 1;
17200
17306
  };
17201
- const visitBlock = (block) => {
17307
+ const visitBlocks = (blocksToVisit, basePath) => {
17308
+ for (let blockIndex = 0; blockIndex < blocksToVisit.length; blockIndex += 1) {
17309
+ const block = blocksToVisit[blockIndex];
17310
+ if (!block) continue;
17311
+ visitBlock(block, `${basePath}/block[${blockIndex}]`);
17312
+ }
17313
+ };
17314
+ const visitBlock = (block, blockPath) => {
17202
17315
  switch (block.type) {
17203
17316
  case "paragraph":
17204
- for (const child of block.children) visitInline(child);
17317
+ visitInlines(block.children, blockPath, `${blockPath}/inline`);
17205
17318
  break;
17206
17319
  case "table":
17207
- for (const row2 of block.rows) {
17208
- for (const cell of row2.cells) {
17209
- for (const child of cell.children) visitBlock(child);
17320
+ for (let rowIndex = 0; rowIndex < block.rows.length; rowIndex += 1) {
17321
+ const row2 = block.rows[rowIndex];
17322
+ if (!row2) continue;
17323
+ for (let cellIndex = 0; cellIndex < row2.cells.length; cellIndex += 1) {
17324
+ const cell = row2.cells[cellIndex];
17325
+ if (!cell) continue;
17326
+ visitBlocks(cell.children, `${blockPath}/row[${rowIndex}]/cell[${cellIndex}]`);
17210
17327
  }
17211
17328
  }
17212
17329
  break;
17213
17330
  case "sdt":
17214
- for (const child of block.children) visitBlock(child);
17331
+ case "custom_xml":
17332
+ visitBlocks(block.children, blockPath);
17215
17333
  break;
17216
17334
  default:
17217
17335
  break;
17218
17336
  }
17219
17337
  };
17220
- const visitInline = (inline) => {
17338
+ const visitInlines = (inlines, blockPath, basePath) => {
17339
+ for (let inlineIndex = 0; inlineIndex < inlines.length; inlineIndex += 1) {
17340
+ const inline = inlines[inlineIndex];
17341
+ if (!inline) continue;
17342
+ visitInline(inline, blockPath, `${basePath}[${inlineIndex}]`);
17343
+ }
17344
+ };
17345
+ const visitInline = (inline, blockPath, inlinePath) => {
17221
17346
  switch (inline.type) {
17222
17347
  case "image": {
17223
17348
  pushObject({
@@ -17238,17 +17363,27 @@ function collectStoryAnchoredObjects(blocks, context) {
17238
17363
  inline.anchor.extent.widthEmu,
17239
17364
  inline.anchor.extent.heightEmu
17240
17365
  );
17366
+ const anchorRectTwips = resolveObjectAnchorRectTwips(
17367
+ context.region,
17368
+ extentTwips,
17369
+ inline.anchor.positionH,
17370
+ inline.anchor.positionV
17371
+ );
17372
+ const canonicalAnchor = context.anchorsByInlinePath?.get(inlinePath);
17373
+ const textBoxBody = buildDrawingFrameTextBoxBodyFacts(
17374
+ inline,
17375
+ canonicalAnchor,
17376
+ inlinePath,
17377
+ display,
17378
+ anchorRectTwips
17379
+ );
17241
17380
  pushObject({
17242
17381
  objectId: getDrawingFrameObjectId(inline, context.storyKey, ordinal),
17243
17382
  sourceType: "drawing-frame",
17244
17383
  display,
17245
17384
  extentTwips,
17246
- anchorRectTwips: resolveObjectAnchorRectTwips(
17247
- context.region,
17248
- extentTwips,
17249
- inline.anchor.positionH,
17250
- inline.anchor.positionV
17251
- ),
17385
+ anchorRectTwips,
17386
+ ...textBoxBody ? { textBoxBody } : {},
17252
17387
  ...relationshipIds.length > 0 ? { relationshipIds } : {},
17253
17388
  ...inline.content.type === "picture" && inline.content.mediaId ? { mediaIds: [inline.content.mediaId] } : {},
17254
17389
  preserveOnly: Boolean(preserveHint),
@@ -17256,7 +17391,7 @@ function collectStoryAnchoredObjects(blocks, context) {
17256
17391
  wrapMode: inline.anchor.wrapMode
17257
17392
  });
17258
17393
  if (inline.content.type === "shape") {
17259
- for (const child of inline.content.txbxBlocks ?? []) visitBlock(child);
17394
+ visitBlocks(inline.content.txbxBlocks ?? [], `${inlinePath}/txbx`);
17260
17395
  }
17261
17396
  break;
17262
17397
  }
@@ -17283,10 +17418,11 @@ function collectStoryAnchoredObjects(blocks, context) {
17283
17418
  } : {},
17284
17419
  ...preserveHint?.relationshipIds ? { relationshipIds: [...preserveHint.relationshipIds] } : {},
17285
17420
  preserveOnly: Boolean(preserveHint),
17286
- ...preserveHint ? { preserveHint } : {}
17421
+ ...preserveHint ? { preserveHint } : {},
17422
+ ...inline.type === "vml_shape" && inline.text ? { textBoxBody: buildUnsupportedVmlTextBoxFacts(inline, inlinePath) } : {}
17287
17423
  });
17288
17424
  if (inline.type === "shape") {
17289
- for (const child of inline.txbxBlocks ?? []) visitBlock(child);
17425
+ visitBlocks(inline.txbxBlocks ?? [], `${inlinePath}/txbx`);
17290
17426
  }
17291
17427
  break;
17292
17428
  }
@@ -17308,16 +17444,16 @@ function collectStoryAnchoredObjects(blocks, context) {
17308
17444
  });
17309
17445
  break;
17310
17446
  case "field":
17311
- for (const child of inline.children) visitInline(child);
17447
+ visitInlines(inline.children, blockPath, `${inlinePath}/child`);
17312
17448
  break;
17313
17449
  case "hyperlink":
17314
- for (const child of inline.children) visitInline(child);
17450
+ visitInlines(inline.children, blockPath, `${inlinePath}/child`);
17315
17451
  break;
17316
17452
  default:
17317
17453
  break;
17318
17454
  }
17319
17455
  };
17320
- for (const block of blocks) visitBlock(block);
17456
+ visitBlocks(blocks, context.storyBasePath);
17321
17457
  return { objects, divergences };
17322
17458
  }
17323
17459
  function getDrawingFramePreserveHint(inline) {
@@ -17325,6 +17461,170 @@ function getDrawingFramePreserveHint(inline) {
17325
17461
  if (content.type === "picture") return void 0;
17326
17462
  return content.preserveOnlyObject;
17327
17463
  }
17464
+ function buildDrawingFrameTextBoxBodyFacts(inline, canonicalAnchor, inlinePath, display, anchorRectTwips) {
17465
+ if (inline.content.type !== "shape") return void 0;
17466
+ const content = inline.content;
17467
+ const canonicalBody = canonicalAnchor?.textBoxBody;
17468
+ const hasTextBoxContent = Boolean(
17469
+ canonicalBody || content.isTextBox || content.textBoxBody || content.txbxBlocks?.length
17470
+ );
17471
+ if (!hasTextBoxContent) return void 0;
17472
+ if (!canonicalBody) {
17473
+ return unavailableTextBoxBodyFacts(
17474
+ `${canonicalAnchor?.objectKey ?? inlinePath}:txbx`,
17475
+ "unmodeled-txbx-blocks",
17476
+ content.textBoxBody,
17477
+ content.txbxBlocks?.length ?? 0,
17478
+ countParagraphBlocks(content.txbxBlocks ?? []),
17479
+ 0
17480
+ );
17481
+ }
17482
+ if (display !== "floating") {
17483
+ return unavailableTextBoxBodyFactsFromCanonical(canonicalBody, "inline-textbox");
17484
+ }
17485
+ if (!anchorRectTwips) {
17486
+ return unavailableTextBoxBodyFactsFromCanonical(canonicalBody, "missing-anchor-rect");
17487
+ }
17488
+ if (canonicalBody.status !== "modeled") {
17489
+ return unavailableTextBoxBodyFactsFromCanonical(
17490
+ canonicalBody,
17491
+ normalizeTextBoxBodyUnavailableReason(canonicalBody.unavailableReason)
17492
+ );
17493
+ }
17494
+ const bodyInsetsTwips = textBoxInsetsTwips(canonicalBody.bodyProperties);
17495
+ if (!bodyInsetsTwips) {
17496
+ return unavailableTextBoxBodyFactsFromCanonical(canonicalBody, "missing-body-insets");
17497
+ }
17498
+ const contentRectTwips = rect(
17499
+ anchorRectTwips.xTwips + bodyInsetsTwips.leftTwips,
17500
+ anchorRectTwips.yTwips + bodyInsetsTwips.topTwips,
17501
+ Math.max(0, anchorRectTwips.widthTwips - bodyInsetsTwips.leftTwips - bodyInsetsTwips.rightTwips),
17502
+ Math.max(0, anchorRectTwips.heightTwips - bodyInsetsTwips.topTwips - bodyInsetsTwips.bottomTwips)
17503
+ );
17504
+ return {
17505
+ bodyKey: canonicalBody.bodyKey,
17506
+ status: "modeled",
17507
+ ...canonicalBody.bodyProperties ? { bodyProperties: { ...canonicalBody.bodyProperties } } : {},
17508
+ bodyInsetsTwips,
17509
+ contentRectTwips,
17510
+ blockCount: canonicalBody.blockCount,
17511
+ paragraphCount: canonicalBody.paragraphCount,
17512
+ unsupportedBlockCount: canonicalBody.unsupportedBlockCount,
17513
+ paragraphs: buildTextBoxParagraphFacts(canonicalBody, contentRectTwips)
17514
+ };
17515
+ }
17516
+ function unavailableTextBoxBodyFactsFromCanonical(body, reason) {
17517
+ return {
17518
+ bodyKey: body.bodyKey,
17519
+ status: body.status === "preserve-only" ? "preserve-only" : "unavailable",
17520
+ unavailableReason: reason,
17521
+ ...body.bodyProperties ? { bodyProperties: { ...body.bodyProperties } } : {},
17522
+ blockCount: body.blockCount,
17523
+ paragraphCount: body.paragraphCount,
17524
+ unsupportedBlockCount: body.unsupportedBlockCount,
17525
+ paragraphs: body.paragraphs.map((paragraph) => ({
17526
+ paragraphKey: paragraph.paragraphKey,
17527
+ blockPath: paragraph.blockPath,
17528
+ blockIndex: paragraph.blockIndex,
17529
+ unavailableReason: reason,
17530
+ ...paragraph.styleId !== void 0 ? { styleId: paragraph.styleId } : {},
17531
+ ...paragraph.alignment !== void 0 ? { alignment: paragraph.alignment } : {},
17532
+ textLength: paragraph.textLength,
17533
+ runCount: paragraph.runCount
17534
+ }))
17535
+ };
17536
+ }
17537
+ function unavailableTextBoxBodyFacts(bodyKey, reason, bodyProperties, blockCount, paragraphCount, unsupportedBlockCount) {
17538
+ return {
17539
+ bodyKey,
17540
+ status: "unavailable",
17541
+ unavailableReason: reason,
17542
+ ...bodyProperties ? { bodyProperties: { ...bodyProperties } } : {},
17543
+ blockCount,
17544
+ paragraphCount,
17545
+ unsupportedBlockCount,
17546
+ paragraphs: []
17547
+ };
17548
+ }
17549
+ function buildUnsupportedVmlTextBoxFacts(inline, inlinePath) {
17550
+ const hasText = Boolean(inline.text?.length);
17551
+ return {
17552
+ bodyKey: `${inline.preserveOnlyObject?.sourceId ?? inlinePath}:vml-textbox`,
17553
+ status: "unavailable",
17554
+ unavailableReason: "unsupported-vml-textbox",
17555
+ blockCount: hasText ? 1 : 0,
17556
+ paragraphCount: hasText ? 1 : 0,
17557
+ unsupportedBlockCount: hasText ? 1 : 0,
17558
+ paragraphs: []
17559
+ };
17560
+ }
17561
+ function buildTextBoxParagraphFacts(body, contentRectTwips) {
17562
+ const paragraphCount = body.paragraphs.length;
17563
+ if (paragraphCount === 0) return [];
17564
+ const baseHeight = Math.floor(contentRectTwips.heightTwips / paragraphCount);
17565
+ return body.paragraphs.map((paragraph, index) => {
17566
+ const yTwips = contentRectTwips.yTwips + baseHeight * index;
17567
+ const heightTwips = index === paragraphCount - 1 ? Math.max(0, contentRectTwips.yTwips + contentRectTwips.heightTwips - yTwips) : Math.max(0, baseHeight);
17568
+ return {
17569
+ paragraphKey: paragraph.paragraphKey,
17570
+ blockPath: paragraph.blockPath,
17571
+ blockIndex: paragraph.blockIndex,
17572
+ rectTwips: rect(
17573
+ contentRectTwips.xTwips,
17574
+ yTwips,
17575
+ contentRectTwips.widthTwips,
17576
+ heightTwips
17577
+ ),
17578
+ ...paragraph.styleId !== void 0 ? { styleId: paragraph.styleId } : {},
17579
+ ...paragraph.alignment !== void 0 ? { alignment: paragraph.alignment } : {},
17580
+ textLength: paragraph.textLength,
17581
+ runCount: paragraph.runCount
17582
+ };
17583
+ });
17584
+ }
17585
+ function textBoxInsetsTwips(bodyProperties) {
17586
+ if (!bodyProperties || bodyProperties.insetLeftEmu === void 0 || bodyProperties.insetTopEmu === void 0 || bodyProperties.insetRightEmu === void 0 || bodyProperties.insetBottomEmu === void 0) {
17587
+ return void 0;
17588
+ }
17589
+ return {
17590
+ leftTwips: Math.max(0, Math.round(bodyProperties.insetLeftEmu / EMUS_PER_TWIP)),
17591
+ topTwips: Math.max(0, Math.round(bodyProperties.insetTopEmu / EMUS_PER_TWIP)),
17592
+ rightTwips: Math.max(0, Math.round(bodyProperties.insetRightEmu / EMUS_PER_TWIP)),
17593
+ bottomTwips: Math.max(0, Math.round(bodyProperties.insetBottomEmu / EMUS_PER_TWIP))
17594
+ };
17595
+ }
17596
+ function normalizeTextBoxBodyUnavailableReason(reason) {
17597
+ switch (reason) {
17598
+ case "txbx-blocks-unavailable":
17599
+ case "empty-body":
17600
+ case "unsupported-content":
17601
+ return reason;
17602
+ default:
17603
+ return "unmodeled-txbx-blocks";
17604
+ }
17605
+ }
17606
+ function countParagraphBlocks(blocks) {
17607
+ let count = 0;
17608
+ const visit = (block) => {
17609
+ if (block.type === "paragraph") {
17610
+ count += 1;
17611
+ return;
17612
+ }
17613
+ if (block.type === "table") {
17614
+ for (const row2 of block.rows) {
17615
+ for (const cell of row2.cells) {
17616
+ for (const child of cell.children) visit(child);
17617
+ }
17618
+ }
17619
+ return;
17620
+ }
17621
+ if (block.type === "sdt" || block.type === "custom_xml") {
17622
+ for (const child of block.children) visit(child);
17623
+ }
17624
+ };
17625
+ for (const block of blocks) visit(block);
17626
+ return count;
17627
+ }
17328
17628
  function collectDrawingRelationshipIds(inline) {
17329
17629
  const content = inline.content;
17330
17630
  if (content.type === "picture") return [content.blipRef];
@@ -17653,12 +17953,34 @@ function freezePageFrame(frame) {
17653
17953
  for (const story of frame.pageLocalStories) {
17654
17954
  Object.freeze(story.resolvedFields);
17655
17955
  Object.freeze(story.previewParts);
17956
+ for (const object of story.anchoredObjects) {
17957
+ freezeStoryAnchoredObject(object);
17958
+ }
17656
17959
  Object.freeze(story.anchoredObjects);
17657
17960
  Object.freeze(story);
17658
17961
  }
17659
17962
  Object.freeze(frame.pageLocalStories);
17660
17963
  Object.freeze(frame);
17661
17964
  }
17965
+ function freezeStoryAnchoredObject(object) {
17966
+ if (object.extentTwips) Object.freeze(object.extentTwips);
17967
+ if (object.anchorRectTwips) Object.freeze(object.anchorRectTwips);
17968
+ if (object.relationshipIds) Object.freeze(object.relationshipIds);
17969
+ if (object.mediaIds) Object.freeze(object.mediaIds);
17970
+ if (object.textBoxBody) {
17971
+ if (object.textBoxBody.bodyProperties) Object.freeze(object.textBoxBody.bodyProperties);
17972
+ if (object.textBoxBody.bodyInsetsTwips) Object.freeze(object.textBoxBody.bodyInsetsTwips);
17973
+ if (object.textBoxBody.contentRectTwips) Object.freeze(object.textBoxBody.contentRectTwips);
17974
+ for (const paragraph of object.textBoxBody.paragraphs) {
17975
+ if (paragraph.rectTwips) Object.freeze(paragraph.rectTwips);
17976
+ Object.freeze(paragraph);
17977
+ }
17978
+ Object.freeze(object.textBoxBody.paragraphs);
17979
+ Object.freeze(object.textBoxBody);
17980
+ }
17981
+ Object.freeze(object.divergenceIds);
17982
+ Object.freeze(object);
17983
+ }
17662
17984
  function normalizePageLocalStoryFieldsForPages(pages) {
17663
17985
  const pageFieldCounts = buildPageFieldCounts(pages);
17664
17986
  return pages.map((page) => {
@@ -18999,7 +19321,7 @@ async function createCanvasProvider(fontLoader) {
18999
19321
 
19000
19322
  // src/runtime/layout/layout-engine-version.ts
19001
19323
  var LAYOUT_ENGINE_VERSION = 87;
19002
- var LAYCACHE_SCHEMA_VERSION = 10;
19324
+ var LAYCACHE_SCHEMA_VERSION = 11;
19003
19325
 
19004
19326
  // src/runtime/layout/layout-engine-instance.ts
19005
19327
  var FULL_VIEWPORT_WINDOW_KEY = "full";
@@ -19345,7 +19667,8 @@ function createLayoutEngine(options = {}) {
19345
19667
  fragmentsByPageIndex,
19346
19668
  lineBoxesByPageIndex,
19347
19669
  noteAllocationsByPageIndex: pageStack.noteAllocationsByPageIndex,
19348
- subParts: document2.subParts
19670
+ subParts: document2.subParts,
19671
+ anchors: layoutInputs.anchors
19349
19672
  });
19350
19673
  const graph = applyViewportWindowMaterialization(
19351
19674
  measuredGraph,
@@ -19480,7 +19803,8 @@ function createLayoutEngine(options = {}) {
19480
19803
  fragmentsByPageIndex: freshFragmentsByPageIndex,
19481
19804
  lineBoxesByPageIndex: freshLineBoxesByPageIndex,
19482
19805
  noteAllocationsByPageIndex: freshResult.noteAllocationsByPageIndex,
19483
- subParts: document2.subParts
19806
+ subParts: document2.subParts,
19807
+ anchors: layoutInputs.anchors
19484
19808
  });
19485
19809
  const freshNodes = freshGraph.pages;
19486
19810
  const splicedGraph = spliceGraph(priorGraph, freshNodes, firstDirty, convergedTailStart);
@@ -25539,6 +25863,7 @@ function applyLinearTextTransaction(document2, selection, intent, options) {
25539
25863
  metadata: {
25540
25864
  affectsComments: true,
25541
25865
  affectsRevisions: true,
25866
+ ...createLocalTextPatchMetadata(story.units, unitFrom, unitTo, insertionUnits),
25542
25867
  ...containsParagraphBoundaryChange(story, normalizedRange, insertionUnits) ? { invalidatesStructures: true } : {}
25543
25868
  }
25544
25869
  },
@@ -25606,6 +25931,21 @@ function tryApplyTableParagraphTransaction(document2, selection, intent, options
25606
25931
  storyText: localResult.storyText
25607
25932
  };
25608
25933
  }
25934
+ function createLocalTextPatchMetadata(units, unitFrom, unitTo, insertionUnits) {
25935
+ if (!insertionUnits.every((unit) => unit.kind === "text")) {
25936
+ return {};
25937
+ }
25938
+ for (let index = unitFrom; index < unitTo; index += 1) {
25939
+ if (units[index]?.kind !== "text") {
25940
+ return {};
25941
+ }
25942
+ }
25943
+ return {
25944
+ localTextPatch: {
25945
+ insertedText: insertionUnits.map((unit) => unit.kind === "text" ? unit.value : "").join("")
25946
+ }
25947
+ };
25948
+ }
25609
25949
  function tryApplyTargetedTextLeafTransaction(document2, selection, intent, options) {
25610
25950
  const scope = resolveTargetedTextLeafScope(document2, selection, options.textTarget);
25611
25951
  if (!scope) {
@@ -30509,14 +30849,13 @@ var TOOLBAR_CHROME_REGISTRY = [
30509
30849
  surfaces: ["top-toolbar"],
30510
30850
  group: "text",
30511
30851
  presets: ["advanced", "review", "workflow"],
30512
- roles: ALL_ROLES,
30852
+ roles: EDITOR_AND_REVIEW,
30513
30853
  fullPlacement: "inline",
30514
30854
  compactPlacement: "overflow",
30515
30855
  runtimeBehavior: "formatting",
30516
30856
  rolePlacement: {
30517
30857
  editor: "inline",
30518
- review: "inline",
30519
- workflow: "overflow"
30858
+ review: "overflow"
30520
30859
  }
30521
30860
  },
30522
30861
  {
@@ -30524,14 +30863,13 @@ var TOOLBAR_CHROME_REGISTRY = [
30524
30863
  surfaces: ["top-toolbar"],
30525
30864
  group: "text",
30526
30865
  presets: ["simple", "advanced", "review", "workflow"],
30527
- roles: ALL_ROLES,
30866
+ roles: EDITOR_AND_REVIEW,
30528
30867
  fullPlacement: "inline",
30529
30868
  compactPlacement: "inline",
30530
30869
  runtimeBehavior: "formatting",
30531
30870
  rolePlacement: {
30532
30871
  editor: "inline",
30533
- review: "inline",
30534
- workflow: "overflow"
30872
+ review: "overflow"
30535
30873
  }
30536
30874
  },
30537
30875
  {
@@ -30658,10 +30996,9 @@ var TOOLBAR_CHROME_REGISTRY = [
30658
30996
  surfaces: ["top-toolbar"],
30659
30997
  group: "review",
30660
30998
  presets: ["simple", "advanced", "review", "workflow"],
30661
- // Visible in every role, but editor/review roles render it inside the
30662
- // role action region (see ROLE_ACTION_SETS) and the right cluster
30663
- // suppresses it via `isChromeItemOwnedByRoleRegion` to avoid duplication.
30664
- roles: ALL_ROLES,
30999
+ // Comment authoring belongs to Edit / Review. Workflow mode keeps scope
31000
+ // and work-item controls primary instead of carrying review chrome.
31001
+ roles: EDITOR_AND_REVIEW,
30665
31002
  fullPlacement: "inline",
30666
31003
  compactPlacement: "inline",
30667
31004
  runtimeBehavior: "comment"
@@ -33137,8 +33474,8 @@ function isNodeSelectableSegment(segment) {
33137
33474
  }
33138
33475
 
33139
33476
  // src/runtime/edit-ops/index.ts
33140
- function validateResult(result) {
33141
- const maxOffset = result.storyText.length;
33477
+ function validateResult(result, context) {
33478
+ const maxOffset = getPostMutationMaxOffset(result, context);
33142
33479
  const options = result.selection.activeRange.kind === "node" ? {
33143
33480
  isValidNodeTarget: createSurfaceNodeSelectionProbe(
33144
33481
  createEditorSurfaceSnapshot(result.document, result.selection)
@@ -33155,24 +33492,34 @@ function validateResult(result) {
33155
33492
  }
33156
33493
  return { ...result, selection: validated };
33157
33494
  }
33495
+ function getPostMutationMaxOffset(result, context) {
33496
+ if (typeof context.activeStorySize !== "number" || context.textTarget?.kind === "text-leaf") {
33497
+ return result.storyText.length;
33498
+ }
33499
+ let storySize = context.activeStorySize;
33500
+ for (const step of result.mapping.steps) {
33501
+ storySize += step.insertSize - Math.max(0, step.to - step.from);
33502
+ }
33503
+ return Math.max(result.storyText.length, storySize);
33504
+ }
33158
33505
  var editLayer = {
33159
33506
  applyTextInsert(doc, selection, text, context, formatting) {
33160
- return validateResult(insertText(doc, selection, text, context, formatting));
33507
+ return validateResult(insertText(doc, selection, text, context, formatting), context);
33161
33508
  },
33162
33509
  applyDeleteBackward(doc, selection, context) {
33163
- return validateResult(deleteSelectionOrBackward(doc, selection, context));
33510
+ return validateResult(deleteSelectionOrBackward(doc, selection, context), context);
33164
33511
  },
33165
33512
  applyDeleteForward(doc, selection, context) {
33166
- return validateResult(deleteSelectionOrForward(doc, selection, context));
33513
+ return validateResult(deleteSelectionOrForward(doc, selection, context), context);
33167
33514
  },
33168
33515
  applyInsertTab(doc, selection, context) {
33169
- return validateResult(insertTab(doc, selection, context));
33516
+ return validateResult(insertTab(doc, selection, context), context);
33170
33517
  },
33171
33518
  applyInsertHardBreak(doc, selection, context) {
33172
- return validateResult(insertHardBreak(doc, selection, context));
33519
+ return validateResult(insertHardBreak(doc, selection, context), context);
33173
33520
  },
33174
33521
  applySplitParagraph(doc, selection, context) {
33175
- return validateResult(splitParagraph(doc, selection, context));
33522
+ return validateResult(splitParagraph(doc, selection, context), context);
33176
33523
  }
33177
33524
  };
33178
33525
 
@@ -49506,7 +49853,7 @@ function deriveScopeEditableTargetEvidence(document2, scope, entry, options = {}
49506
49853
  facts.push(projectWorkflowBlockerFact(fact));
49507
49854
  factsByTargetKey.set(fact.targetKey, facts);
49508
49855
  }
49509
- const entries = collectEditableTargetRefs(document2).map((target) => {
49856
+ const entries = collectEditableTargetRefs(document2, options.editableTargetCache).map((target) => {
49510
49857
  const relation = relationForTarget(target, scope, entry);
49511
49858
  if (!relation) return null;
49512
49859
  const workflowBlockers = Object.freeze(
@@ -50485,7 +50832,8 @@ function composeEvidence(inputs) {
50485
50832
  scope,
50486
50833
  entry,
50487
50834
  {
50488
- ...inputs.editableTargetBlockerFacts ? { workflowBlockerFacts: inputs.editableTargetBlockerFacts } : {}
50835
+ ...inputs.editableTargetBlockerFacts ? { workflowBlockerFacts: inputs.editableTargetBlockerFacts } : {},
50836
+ ...inputs.editableTargetCache ? { editableTargetCache: inputs.editableTargetCache } : {}
50489
50837
  }
50490
50838
  ) : void 0;
50491
50839
  const contentControls = deriveScopeContentControlEvidence(document2, selfRange);
@@ -50574,7 +50922,8 @@ function compileScopeBundle(scope, inputs) {
50574
50922
  ...inputs.layout ? { layout: inputs.layout } : {},
50575
50923
  ...inputs.adjacentGeometry ? { adjacentGeometry: inputs.adjacentGeometry } : {},
50576
50924
  ...inputs.tableCellTextRange ? { tableCellTextRange: inputs.tableCellTextRange } : {},
50577
- ...inputs.editableTargetBlockerFacts ? { editableTargetBlockerFacts: inputs.editableTargetBlockerFacts } : {}
50925
+ ...inputs.editableTargetBlockerFacts ? { editableTargetBlockerFacts: inputs.editableTargetBlockerFacts } : {},
50926
+ ...inputs.editableTargetCache ? { editableTargetCache: inputs.editableTargetCache } : {}
50578
50927
  });
50579
50928
  return {
50580
50929
  scope,
@@ -51810,7 +52159,7 @@ function createScopeCompilerService(runtime) {
51810
52159
  const interactionGuard = runtime.getInteractionGuardSnapshot?.();
51811
52160
  const activeStory = runtime.getActiveStory?.();
51812
52161
  const editableTargetBlockerFacts = deriveWorkflowEditableTargetBlockerFacts({
51813
- targets: collectEditableTargetRefs(document2),
52162
+ targets: collectEditableTargetRefs(document2, runtime.getEditableTargetCache?.()),
51814
52163
  ...interactionGuard ? { guard: interactionGuard } : {},
51815
52164
  ...runtime.getProtectionSnapshot ? { protectionSnapshot: runtime.getProtectionSnapshot() } : {},
51816
52165
  ...activeStory ? { activeStoryKey: storyKeyForEditableTarget(activeStory) } : {}
@@ -51821,6 +52170,7 @@ function createScopeCompilerService(runtime) {
51821
52170
  runtime.getRenderSnapshot?.()
51822
52171
  )
51823
52172
  }) : void 0;
52173
+ const editableTargetCache = runtime.getEditableTargetCache?.();
51824
52174
  return compileScopeBundleById(scopeId, {
51825
52175
  document: document2,
51826
52176
  ...overlay ? { overlay } : {},
@@ -51830,7 +52180,8 @@ function createScopeCompilerService(runtime) {
51830
52180
  editableTargetBlockerFacts,
51831
52181
  ...runtime.geometry ? { geometry: runtime.geometry } : {},
51832
52182
  ...layout ? { layout } : {},
51833
- tableCellTextRange
52183
+ tableCellTextRange,
52184
+ ...editableTargetCache ? { editableTargetCache } : {}
51834
52185
  });
51835
52186
  },
51836
52187
  buildReplacementScope(targetHandle, input) {
@@ -55671,12 +56022,37 @@ function toPublicStoryAnchoredObject(object) {
55671
56022
  }
55672
56023
  } : {},
55673
56024
  ...object.anchorRectTwips ? { anchorRectTwips: toPublicTwipsRect(object.anchorRectTwips) } : {},
56025
+ ...object.textBoxBody ? { textBoxBody: toPublicTextBoxBodyFacts(object.textBoxBody) } : {},
55674
56026
  ...object.relationshipIds ? { relationshipIds: [...object.relationshipIds] } : {},
55675
56027
  ...object.mediaIds ? { mediaIds: [...object.mediaIds] } : {},
55676
56028
  preserveOnly: object.preserveOnly,
55677
56029
  divergenceIds: [...object.divergenceIds]
55678
56030
  };
55679
56031
  }
56032
+ function toPublicTextBoxBodyFacts(textBoxBody) {
56033
+ return {
56034
+ bodyKey: textBoxBody.bodyKey,
56035
+ status: textBoxBody.status,
56036
+ ...textBoxBody.unavailableReason !== void 0 ? { unavailableReason: textBoxBody.unavailableReason } : {},
56037
+ ...textBoxBody.bodyProperties ? { bodyProperties: { ...textBoxBody.bodyProperties } } : {},
56038
+ ...textBoxBody.bodyInsetsTwips ? { bodyInsetsTwips: { ...textBoxBody.bodyInsetsTwips } } : {},
56039
+ ...textBoxBody.contentRectTwips ? { contentRectTwips: toPublicTwipsRect(textBoxBody.contentRectTwips) } : {},
56040
+ blockCount: textBoxBody.blockCount,
56041
+ paragraphCount: textBoxBody.paragraphCount,
56042
+ unsupportedBlockCount: textBoxBody.unsupportedBlockCount,
56043
+ paragraphs: textBoxBody.paragraphs.map((paragraph) => ({
56044
+ paragraphKey: paragraph.paragraphKey,
56045
+ blockPath: paragraph.blockPath,
56046
+ blockIndex: paragraph.blockIndex,
56047
+ ...paragraph.rectTwips ? { rectTwips: toPublicTwipsRect(paragraph.rectTwips) } : {},
56048
+ ...paragraph.unavailableReason !== void 0 ? { unavailableReason: paragraph.unavailableReason } : {},
56049
+ ...paragraph.styleId !== void 0 ? { styleId: paragraph.styleId } : {},
56050
+ ...paragraph.alignment !== void 0 ? { alignment: paragraph.alignment } : {},
56051
+ textLength: paragraph.textLength,
56052
+ runCount: paragraph.runCount
56053
+ }))
56054
+ };
56055
+ }
55680
56056
  function toPublicLayoutDivergence(divergence) {
55681
56057
  return {
55682
56058
  divergenceId: divergence.divergenceId,
@@ -58226,7 +58602,6 @@ async function collectEditorStateForSerialize(args) {
58226
58602
  // src/io/ooxml/parse-bookmark-references.ts
58227
58603
  var HYPERLINK_ANCHOR_RE = /<(?:\w+:)?hyperlink\b[^>]*\bw:anchor\s*=\s*"([^"]*)"/gi;
58228
58604
  var INSTR_TEXT_RE = /<(?:\w+:)?instrText\b[^>]*>([\s\S]*?)<\/(?:\w+:)?instrText>/gi;
58229
- var SIMPLE_FIELD_INSTR_RE = /<(?:\w+:)?fldSimple\b[^>]*\bw:instr\s*=\s*"([^"]*)"/gi;
58230
58605
  var TOC_FIELD_RE = /\bTOC\b/;
58231
58606
  var REFLIKE_FIELD_RE = /\b(?:HYPERLINK|REF|PAGEREF|NOTEREF)\s+([A-Za-z0-9_:.\-]+)/g;
58232
58607
  var DATA_BINDING_RE = /<(?:\w+:)?dataBinding\b/i;
@@ -58245,14 +58620,12 @@ function scanBookmarkReferences(documentXml, callerAllowlist = []) {
58245
58620
  }
58246
58621
  INSTR_TEXT_RE.lastIndex = 0;
58247
58622
  while ((m = INSTR_TEXT_RE.exec(documentXml)) !== null) {
58248
- if (scanInstructionForRetainedBookmarks(m[1] ?? "", retained)) {
58249
- retainAllToc = true;
58250
- }
58251
- }
58252
- SIMPLE_FIELD_INSTR_RE.lastIndex = 0;
58253
- while ((m = SIMPLE_FIELD_INSTR_RE.exec(documentXml)) !== null) {
58254
- if (scanInstructionForRetainedBookmarks(m[1] ?? "", retained)) {
58255
- retainAllToc = true;
58623
+ const instrText = m[1] ?? "";
58624
+ if (TOC_FIELD_RE.test(instrText)) retainAllToc = true;
58625
+ REFLIKE_FIELD_RE.lastIndex = 0;
58626
+ let r;
58627
+ while ((r = REFLIKE_FIELD_RE.exec(instrText)) !== null) {
58628
+ if (r[1]) retained.add(r[1]);
58256
58629
  }
58257
58630
  }
58258
58631
  retainRevisionBoundedBookmarks(documentXml, retained);
@@ -58262,15 +58635,6 @@ function scanBookmarkReferences(documentXml, callerAllowlist = []) {
58262
58635
  retainAll
58263
58636
  };
58264
58637
  }
58265
- function scanInstructionForRetainedBookmarks(instruction, retained) {
58266
- const hasTocField = TOC_FIELD_RE.test(instruction);
58267
- REFLIKE_FIELD_RE.lastIndex = 0;
58268
- let r;
58269
- while ((r = REFLIKE_FIELD_RE.exec(instruction)) !== null) {
58270
- if (r[1]) retained.add(r[1]);
58271
- }
58272
- return hasTocField;
58273
- }
58274
58638
  function retainRevisionBoundedBookmarks(documentXml, retained) {
58275
58639
  const starts = /* @__PURE__ */ new Map();
58276
58640
  BOOKMARK_START_RE.lastIndex = 0;
@@ -61767,7 +62131,7 @@ var SAFE_TABLE_FIELD_FAMILIES = /* @__PURE__ */ new Set([
61767
62131
  "FORMULA"
61768
62132
  ]);
61769
62133
  var RISKY_TABLE_MARKUP_RE = /<w:(ins|del|moveFrom|moveTo|rPrChange|pPrChange|tblPrChange|trPrChange|tcPrChange|sectPrChange|cellIns|cellDel|cellMerge|smartTag)\b/;
61770
- var SIMPLE_FIELD_INSTR_RE2 = /\bw:instr="([^"]*)"/g;
62134
+ var SIMPLE_FIELD_INSTR_RE = /\bw:instr="([^"]*)"/g;
61771
62135
  var COMPLEX_FIELD_TOKEN_RE = /<(?:\w+:)?fldChar\b[^>]*?(?:\w+:)?fldCharType="(begin|separate|end)"[^>]*?(?:\/>|>[\s\S]*?<\/(?:\w+:)?fldChar>)|<(?:\w+:)?instrText\b[^>]*>([\s\S]*?)<\/(?:\w+:)?instrText>/gu;
61772
62136
  function decodeXmlEntities4(text) {
61773
62137
  return text.replace(/&lt;/g, "<").replace(/&gt;/g, ">").replace(/&quot;/g, '"').replace(/&apos;/g, "'").replace(/&amp;/g, "&");
@@ -61808,7 +62172,7 @@ function isSafeTableFieldInstruction(instruction) {
61808
62172
  }
61809
62173
  function tableRequiresOpaquePreservation(rawXml) {
61810
62174
  if (RISKY_TABLE_MARKUP_RE.test(rawXml)) return true;
61811
- const simpleInstructions = [...rawXml.matchAll(SIMPLE_FIELD_INSTR_RE2)].map(
62175
+ const simpleInstructions = [...rawXml.matchAll(SIMPLE_FIELD_INSTR_RE)].map(
61812
62176
  (match) => match[1] ?? ""
61813
62177
  );
61814
62178
  const complexInstructions = extractComplexFieldInstructionsFromRaw(rawXml);
@@ -65811,7 +66175,7 @@ function resolveEditableTextTarget(input) {
65811
66175
  "Editable target ref does not belong to the active story."
65812
66176
  );
65813
66177
  }
65814
- const currentTargets = collectEditableTargetRefs(input.document);
66178
+ const currentTargets = collectEditableTargetRefs(input.document, input.editableTargetCache);
65815
66179
  const current = currentTargets.find(
65816
66180
  (candidate) => candidate.targetKey === input.target.targetKey
65817
66181
  );
@@ -65920,7 +66284,7 @@ function resolveEditableCommandTarget(input) {
65920
66284
  `Editable target kind "${input.target.kind}" is not supported by this command.`
65921
66285
  );
65922
66286
  }
65923
- const currentTargets = collectEditableTargetRefs(input.document);
66287
+ const currentTargets = collectEditableTargetRefs(input.document, input.editableTargetCache);
65924
66288
  const current = currentTargets.find(
65925
66289
  (candidate) => candidate.targetKey === input.target?.targetKey
65926
66290
  );
@@ -65995,7 +66359,13 @@ function rejectCommand(code, message) {
65995
66359
  };
65996
66360
  }
65997
66361
  function sameResolvedTarget2(left, right) {
65998
- return left.kind === right.kind && left.storyKey === right.storyKey && left.blockPath === right.blockPath && left.leafPath === right.leafPath && left.commandFamily === right.commandFamily && left.editability === right.editability && left.staleCheck.paragraphTextHash === right.staleCheck.paragraphTextHash && left.staleCheck.paragraphTextLength === right.staleCheck.paragraphTextLength && left.staleCheck.inlineCount === right.staleCheck.inlineCount && left.staleCheck.targetHash === right.staleCheck.targetHash && left.staleCheck.targetTextLength === right.staleCheck.targetTextLength && left.staleCheck.childCount === right.staleCheck.childCount && left.staleCheck.blockType === right.staleCheck.blockType && left.staleCheck.wordParaId === right.staleCheck.wordParaId && left.staleCheck.wordTextId === right.staleCheck.wordTextId && jsonStable(left.staleCheck.sourceRef) === jsonStable(right.staleCheck.sourceRef) && jsonStable(left.sourceRef) === jsonStable(right.sourceRef) && jsonStable(left.table) === jsonStable(right.table) && jsonStable(left.editableOwner) === jsonStable(right.editableOwner);
66362
+ return left.kind === right.kind && left.storyKey === right.storyKey && left.blockPath === right.blockPath && left.leafPath === right.leafPath && left.commandFamily === right.commandFamily && left.editability === right.editability && sameTextTargetStaleCheck(left, right) && left.staleCheck.inlineCount === right.staleCheck.inlineCount && left.staleCheck.targetHash === right.staleCheck.targetHash && left.staleCheck.targetTextLength === right.staleCheck.targetTextLength && left.staleCheck.childCount === right.staleCheck.childCount && left.staleCheck.blockType === right.staleCheck.blockType && left.staleCheck.wordParaId === right.staleCheck.wordParaId && left.staleCheck.wordTextId === right.staleCheck.wordTextId && jsonStable(left.staleCheck.sourceRef) === jsonStable(right.staleCheck.sourceRef) && jsonStable(left.sourceRef) === jsonStable(right.sourceRef) && jsonStable(left.table) === jsonStable(right.table) && jsonStable(left.editableOwner) === jsonStable(right.editableOwner);
66363
+ }
66364
+ function sameTextTargetStaleCheck(left, right) {
66365
+ if (left.staleCheck.paragraphTextHash === right.staleCheck.paragraphTextHash && left.staleCheck.paragraphTextLength === right.staleCheck.paragraphTextLength) {
66366
+ return true;
66367
+ }
66368
+ return left.commandFamily === "text-leaf" && left.staleCheck.paragraphTextLength !== void 0 && right.staleCheck.paragraphTextLength !== void 0 && left.staleCheck.paragraphTextLength !== right.staleCheck.paragraphTextLength;
65999
66369
  }
66000
66370
  function locateTargetRange(document2, surface, target) {
66001
66371
  if (target.kind === "hyperlink-text") {
@@ -66314,7 +66684,7 @@ function resolveEditableTableStructureTarget(input) {
66314
66684
  `Editable target is not editable${input.target.posture.blockers.length > 0 ? `: ${input.target.posture.blockers.join(", ")}` : "."}`
66315
66685
  );
66316
66686
  }
66317
- const current = collectEditableTargetRefs(input.document).find(
66687
+ const current = collectEditableTargetRefs(input.document, input.editableTargetCache).find(
66318
66688
  (candidate) => candidate.targetKey === input.target?.targetKey
66319
66689
  );
66320
66690
  if (!current) {
@@ -66434,6 +66804,26 @@ function sortJson(value) {
66434
66804
  }
66435
66805
 
66436
66806
  // src/runtime/document-runtime.ts
66807
+ var CANONICAL_BLOCK_REFS_SYMBOL2 = /* @__PURE__ */ Symbol.for("wre.canonical-block-refs");
66808
+ function getLocalTextPatchMetadata(mapping) {
66809
+ const metadata = mapping.metadata?.localTextPatch;
66810
+ if (!metadata || typeof metadata !== "object") {
66811
+ return null;
66812
+ }
66813
+ const insertedText = metadata.insertedText;
66814
+ return typeof insertedText === "string" ? { insertedText } : null;
66815
+ }
66816
+ function getSurfaceCanonicalBlockRefs(snapshot) {
66817
+ return snapshot[CANONICAL_BLOCK_REFS_SYMBOL2];
66818
+ }
66819
+ function attachSurfaceCanonicalBlockRefs(snapshot, refs) {
66820
+ Object.defineProperty(snapshot, CANONICAL_BLOCK_REFS_SYMBOL2, {
66821
+ value: refs,
66822
+ enumerable: false,
66823
+ configurable: true,
66824
+ writable: false
66825
+ });
66826
+ }
66437
66827
  function normalizeViewportRanges(ranges) {
66438
66828
  const cleaned = ranges.filter((r) => Number.isFinite(r.start) && Number.isFinite(r.end) && r.end > r.start).map((r) => ({ start: r.start, end: r.end }));
66439
66829
  if (cleaned.length === 0) return Object.freeze([]);
@@ -66797,6 +67187,22 @@ function createDocumentRuntime(options) {
66797
67187
  cachedEditableTargetMap = { document: document2, map: byBlockPath };
66798
67188
  return byBlockPath;
66799
67189
  }
67190
+ function getEditableTargetsByBlockPathForRanges(document2, storyKey2, ranges) {
67191
+ if (ranges === null) return getEditableTargetsByBlockPath(document2);
67192
+ perfCounters.increment("runtime.editableTargets.boundedBuilds");
67193
+ const targets = collectEditableTargetRefsForStoryBlockRanges(
67194
+ document2,
67195
+ storyKey2,
67196
+ ranges,
67197
+ editableTargetBlockCache
67198
+ );
67199
+ if (targets.length === 0) return /* @__PURE__ */ new Map();
67200
+ const byBlockPath = /* @__PURE__ */ new Map();
67201
+ for (const target of targets) {
67202
+ byBlockPath.set(target.blockPath, target);
67203
+ }
67204
+ return byBlockPath;
67205
+ }
66800
67206
  function invalidateEditableTargetMap() {
66801
67207
  cachedEditableTargetMap = null;
66802
67208
  }
@@ -66847,7 +67253,7 @@ function createDocumentRuntime(options) {
66847
67253
  }
66848
67254
  const snapshot = createEditorSurfaceSnapshot(document2, state.selection, nextActiveStory, {
66849
67255
  viewportBlockRanges: surfaceViewportRanges,
66850
- editableTargetsByBlockPath: getEditableTargetsByBlockPath(document2),
67256
+ editableTargetsByBlockPath: options2.editableTargetsByBlockPathOverride ?? getEditableTargetsByBlockPath(document2),
66851
67257
  ...effectiveMarkupModeProvider ? { getEffectiveMarkupMode: effectiveMarkupModeProvider } : {}
66852
67258
  });
66853
67259
  recordPerfSample("snapshot.surface");
@@ -66910,6 +67316,180 @@ function createDocumentRuntime(options) {
66910
67316
  }
66911
67317
  return -1;
66912
67318
  }
67319
+ function cachePatchedLocalTextSurface(surface) {
67320
+ const activeStoryKey = storyTargetKey(activeStory);
67321
+ const rangesKey = serializeViewportRanges(surface.viewportBlockRanges);
67322
+ cachedSurface = {
67323
+ content: state.document.content,
67324
+ subParts: state.document.subParts,
67325
+ styles: state.document.styles,
67326
+ numbering: state.document.numbering,
67327
+ media: state.document.media,
67328
+ preservation: state.document.preservation,
67329
+ review: state.document.review,
67330
+ effectiveMarkupModeProvider,
67331
+ activeStoryKey,
67332
+ viewportRangesKey: rangesKey,
67333
+ snapshot: surface
67334
+ };
67335
+ if (surface.viewportBlockRanges === null) {
67336
+ cachedFullSurface = {
67337
+ content: state.document.content,
67338
+ subParts: state.document.subParts,
67339
+ styles: state.document.styles,
67340
+ numbering: state.document.numbering,
67341
+ media: state.document.media,
67342
+ preservation: state.document.preservation,
67343
+ review: state.document.review,
67344
+ effectiveMarkupModeProvider,
67345
+ activeStoryKey,
67346
+ snapshot: surface
67347
+ };
67348
+ }
67349
+ cachedSurfaceFingerprint = `${activeStoryKey}|${rangesKey}|${String(state.selection.anchor)}:${String(state.selection.head)}`;
67350
+ }
67351
+ function tryPatchLocalTextSurface(previousSurface, mapping) {
67352
+ const tTotal0 = performance.now();
67353
+ try {
67354
+ if (!previousSurface || activeStory.kind !== "main") {
67355
+ perfCounters.increment("surface.localText.patchMiss");
67356
+ return null;
67357
+ }
67358
+ const patch = getLocalTextPatchMetadata(mapping);
67359
+ if (!patch || mapping.steps.length !== 1) {
67360
+ perfCounters.increment("surface.localText.patchMiss");
67361
+ return null;
67362
+ }
67363
+ const step = mapping.steps[0];
67364
+ if (patch.insertedText.length !== step.insertSize) {
67365
+ perfCounters.increment("surface.localText.patchMiss");
67366
+ return null;
67367
+ }
67368
+ const editFrom = step.from;
67369
+ const editTo = step.to;
67370
+ if (editTo < editFrom || editFrom < 0) {
67371
+ perfCounters.increment("surface.localText.patchMiss");
67372
+ return null;
67373
+ }
67374
+ const blockIndex = previousSurface.blocks.findIndex(
67375
+ (block2) => block2.kind === "paragraph" && editFrom >= block2.from && editTo <= block2.to
67376
+ );
67377
+ if (blockIndex < 0) {
67378
+ perfCounters.increment("surface.localText.patchMiss");
67379
+ return null;
67380
+ }
67381
+ const block = previousSurface.blocks[blockIndex];
67382
+ if (block.kind !== "paragraph") {
67383
+ perfCounters.increment("surface.localText.patchMiss");
67384
+ return null;
67385
+ }
67386
+ const segmentIndex = block.segments.findIndex(
67387
+ (segment2) => segment2.kind === "text" && editFrom >= segment2.from && editTo <= segment2.to
67388
+ );
67389
+ if (segmentIndex < 0) {
67390
+ perfCounters.increment("surface.localText.patchMiss");
67391
+ return null;
67392
+ }
67393
+ const segment = block.segments[segmentIndex];
67394
+ if (segment.kind !== "text") {
67395
+ perfCounters.increment("surface.localText.patchMiss");
67396
+ return null;
67397
+ }
67398
+ if (segment.text.length !== segment.to - segment.from) {
67399
+ perfCounters.increment("surface.localText.patchMiss");
67400
+ return null;
67401
+ }
67402
+ const localFrom = editFrom - segment.from;
67403
+ const localTo = editTo - segment.from;
67404
+ const delta = patch.insertedText.length - (editTo - editFrom);
67405
+ const nextText = segment.text.slice(0, localFrom) + patch.insertedText + segment.text.slice(localTo);
67406
+ const nextSegments = block.segments.map((candidate, index) => {
67407
+ if (index < segmentIndex) return candidate;
67408
+ if (index === segmentIndex) {
67409
+ return {
67410
+ ...segment,
67411
+ text: nextText,
67412
+ to: segment.to + delta
67413
+ };
67414
+ }
67415
+ return shiftSurfaceInlineSegment(candidate, delta);
67416
+ });
67417
+ const nextBlock = {
67418
+ ...block,
67419
+ to: block.to + delta,
67420
+ segments: nextSegments
67421
+ };
67422
+ const nextBlocks = previousSurface.blocks.map((candidate, index) => {
67423
+ if (index < blockIndex) return candidate;
67424
+ if (index === blockIndex) return nextBlock;
67425
+ return shiftSurfaceBlock(candidate, delta);
67426
+ });
67427
+ const nextPlainText = previousSurface.plainText.slice(0, editFrom) + patch.insertedText + previousSurface.plainText.slice(editTo);
67428
+ const nextSurface = {
67429
+ ...previousSurface,
67430
+ storySize: previousSurface.storySize + delta,
67431
+ plainText: nextPlainText,
67432
+ blocks: nextBlocks
67433
+ };
67434
+ const refs = getSurfaceCanonicalBlockRefs(previousSurface);
67435
+ if (refs) {
67436
+ const nextRefs = [...refs];
67437
+ nextRefs[blockIndex] = state.document.content.children[blockIndex] ?? null;
67438
+ attachSurfaceCanonicalBlockRefs(nextSurface, nextRefs);
67439
+ }
67440
+ perfCounters.increment("surface.localText.patchHit");
67441
+ perfCounters.increment("surface.localText.patchDelta", delta);
67442
+ return nextSurface;
67443
+ } finally {
67444
+ perfCounters.increment("surface.localText.total.us", Math.round((performance.now() - tTotal0) * 1e3));
67445
+ }
67446
+ }
67447
+ function shiftSurfaceInlineSegment(segment, delta) {
67448
+ if (delta === 0) return segment;
67449
+ return {
67450
+ ...segment,
67451
+ from: segment.from + delta,
67452
+ to: segment.to + delta
67453
+ };
67454
+ }
67455
+ function shiftSurfaceBlock(block, delta) {
67456
+ if (delta === 0) return block;
67457
+ switch (block.kind) {
67458
+ case "paragraph":
67459
+ return {
67460
+ ...block,
67461
+ from: block.from + delta,
67462
+ to: block.to + delta,
67463
+ segments: block.segments.map((segment) => shiftSurfaceInlineSegment(segment, delta))
67464
+ };
67465
+ case "table":
67466
+ return {
67467
+ ...block,
67468
+ from: block.from + delta,
67469
+ to: block.to + delta,
67470
+ rows: block.rows.map((row2) => ({
67471
+ ...row2,
67472
+ cells: row2.cells.map((cell) => ({
67473
+ ...cell,
67474
+ content: cell.content.map((child) => shiftSurfaceBlock(child, delta))
67475
+ }))
67476
+ }))
67477
+ };
67478
+ case "sdt_block":
67479
+ return {
67480
+ ...block,
67481
+ from: block.from + delta,
67482
+ to: block.to + delta,
67483
+ children: block.children.map((child) => shiftSurfaceBlock(child, delta))
67484
+ };
67485
+ case "opaque_block":
67486
+ return {
67487
+ ...block,
67488
+ from: block.from + delta,
67489
+ to: block.to + delta
67490
+ };
67491
+ }
67492
+ }
66913
67493
  function enrichCulledPlaceholdersWithHeights(snapshot) {
66914
67494
  let heights;
66915
67495
  try {
@@ -67795,7 +68375,8 @@ function createDocumentRuntime(options) {
67795
68375
  document: document2,
67796
68376
  target: command.editableTarget,
67797
68377
  activeStoryKey: canonicalEditableTargetStoryKey(storyTarget),
67798
- selectionDescriptor: command.selectionDescriptor
68378
+ selectionDescriptor: command.selectionDescriptor,
68379
+ editableTargetCache: editableTargetBlockCache
67799
68380
  });
67800
68381
  if (resolution.kind === "rejected") {
67801
68382
  emit2({
@@ -67858,7 +68439,8 @@ function createDocumentRuntime(options) {
67858
68439
  document: document2,
67859
68440
  surface,
67860
68441
  target,
67861
- activeStoryKey: canonicalEditableTargetStoryKey(storyTarget)
68442
+ activeStoryKey: canonicalEditableTargetStoryKey(storyTarget),
68443
+ editableTargetCache: editableTargetBlockCache
67862
68444
  });
67863
68445
  if (resolution.kind === "rejected") {
67864
68446
  emit2({
@@ -67888,7 +68470,8 @@ function createDocumentRuntime(options) {
67888
68470
  document: document2,
67889
68471
  surface,
67890
68472
  target: command.editableTarget,
67891
- activeStoryKey: canonicalEditableTargetStoryKey(storyTarget)
68473
+ activeStoryKey: canonicalEditableTargetStoryKey(storyTarget),
68474
+ editableTargetCache: editableTargetBlockCache
67892
68475
  });
67893
68476
  if (resolution.kind === "rejected") {
67894
68477
  emit2({
@@ -67916,7 +68499,8 @@ function createDocumentRuntime(options) {
67916
68499
  activeStoryKey: canonicalEditableTargetStoryKey(storyTarget),
67917
68500
  commandFamilies: command.type === "field.refresh" || command.type === "toc.refresh" ? ["field"] : ["link-bookmark"],
67918
68501
  targetKinds: targetKindsForModeledCommand(command.type),
67919
- allowGeneratedPosture: true
68502
+ allowGeneratedPosture: true,
68503
+ editableTargetCache: editableTargetBlockCache
67920
68504
  });
67921
68505
  if (resolution.kind === "rejected") {
67922
68506
  emit2({
@@ -67958,7 +68542,8 @@ function createDocumentRuntime(options) {
67958
68542
  baseState.selection.head,
67959
68543
  storyTarget,
67960
68544
  getFullPageGraph(),
67961
- command.options
68545
+ command.options,
68546
+ command.editableTarget
67962
68547
  );
67963
68548
  if (!refreshed2.changed) return null;
67964
68549
  cachedFieldSnapshotEntry = null;
@@ -68000,6 +68585,9 @@ function createDocumentRuntime(options) {
68000
68585
  );
68001
68586
  }
68002
68587
  const runtime = {
68588
+ getEditableTargetCache() {
68589
+ return editableTargetBlockCache;
68590
+ },
68003
68591
  subscribe(listener) {
68004
68592
  listeners.add(listener);
68005
68593
  return () => {
@@ -70203,6 +70791,12 @@ function createDocumentRuntime(options) {
70203
70791
  }
70204
70792
  return !effects.commentAdded && !effects.commentResolved && !effects.commentReopened && !effects.commentReplyAdded && !effects.commentBodyEdited && !effects.changeAccepted && !effects.changeRejected && !effects.revisionAuthored && !effects.commandBlocked;
70205
70793
  }
70794
+ function canSkipOverlaySyncForLocalText(transaction) {
70795
+ if (transaction.mapping.steps.length !== 1) return false;
70796
+ if (transaction.mapping.metadata?.invalidatesStructures) return false;
70797
+ if (transaction.mapping.metadata?.scopeTagTouches) return false;
70798
+ return getLocalTextPatchMetadata(transaction.mapping) !== null;
70799
+ }
70206
70800
  function applyTransactionToState(transaction, options2 = {}) {
70207
70801
  const effects = transaction.effects;
70208
70802
  const selectionUnchanged = transaction.nextState.selection === state.selection;
@@ -70224,9 +70818,28 @@ function createDocumentRuntime(options) {
70224
70818
  state = finalizeState(transaction.nextState, transaction.markDirty, clock());
70225
70819
  perfCounters.increment("commit.finalizeState.us", Math.round((performance.now() - tFinalize0) * 1e3));
70226
70820
  storySelections.set(storyTargetKey(activeStory), state.selection);
70821
+ const tClassify0 = performance.now();
70822
+ const useLocalTextCommitSnapshot = options2.allowLocalTextFastPath === true && shouldUseLocalTextCommitSnapshot(
70823
+ previous,
70824
+ state,
70825
+ transaction,
70826
+ transaction.effects
70827
+ );
70828
+ perfCounters.increment("commit.refreshClassify.us", Math.round((performance.now() - tClassify0) * 1e3));
70227
70829
  const tOverlay0 = performance.now();
70228
- overlayStore.replaceOverlay(overlayStore.getOverlay(), state.document);
70229
- const detachedWorkflowScopeWarnings = syncDetachedWorkflowScopeWarningsInState();
70830
+ const skipOverlaySync = useLocalTextCommitSnapshot && canSkipOverlaySyncForLocalText(transaction);
70831
+ const detachedWorkflowScopeWarnings = skipOverlaySync ? { added: [], cleared: [] } : (() => {
70832
+ const tReplace0 = performance.now();
70833
+ overlayStore.replaceOverlay(overlayStore.getOverlay(), state.document);
70834
+ perfCounters.increment("commit.overlaySync.replaceOverlay.us", Math.round((performance.now() - tReplace0) * 1e3));
70835
+ const tWarnings0 = performance.now();
70836
+ const result = syncDetachedWorkflowScopeWarningsInState();
70837
+ perfCounters.increment("commit.overlaySync.detachedWarnings.us", Math.round((performance.now() - tWarnings0) * 1e3));
70838
+ return result;
70839
+ })();
70840
+ if (skipOverlaySync) {
70841
+ perfCounters.increment("commit.overlaySync.skipped");
70842
+ }
70230
70843
  perfCounters.increment("commit.overlaySync.us", Math.round((performance.now() - tOverlay0) * 1e3));
70231
70844
  const tInvalidate0 = performance.now();
70232
70845
  if (transaction.markDirty && transaction.mapping.steps.length > 0) {
@@ -70260,22 +70873,34 @@ function createDocumentRuntime(options) {
70260
70873
  ...detachedWorkflowScopeWarnings.cleared
70261
70874
  ]
70262
70875
  };
70263
- const tClassify0 = performance.now();
70264
- const useLocalTextCommitSnapshot = options2.allowLocalTextFastPath === true && shouldUseLocalTextCommitSnapshot(
70265
- previous,
70266
- state,
70267
- transaction,
70268
- notifyEffects
70269
- );
70270
- perfCounters.increment("commit.refreshClassify.us", Math.round((performance.now() - tClassify0) * 1e3));
70271
70876
  if (!useLocalTextCommitSnapshot && transaction.markDirty && previous.document !== state.document) {
70272
70877
  applyViewportRanges(getSelectionCorridorViewportRanges(cachedRenderSnapshot.surface));
70273
70878
  }
70274
70879
  const tValidation0 = performance.now();
70275
- const surfaceForValidation = useLocalTextCommitSnapshot ? getCachedSurface(state.document, activeStory, {
70276
- viewportBlockRangesOverride: getSelectionCorridorViewportRanges(cachedRenderSnapshot.surface),
70277
- enrichCulledPlaceholders: false
70278
- }) : getCachedSurface(state.document, activeStory);
70880
+ const patchedLocalTextSurface = useLocalTextCommitSnapshot ? tryPatchLocalTextSurface(cachedRenderSnapshot.surface, transaction.mapping) : null;
70881
+ if (patchedLocalTextSurface) {
70882
+ cachePatchedLocalTextSurface(patchedLocalTextSurface);
70883
+ perfCounters.increment("commit.localTextValidation.storySizeOnly");
70884
+ }
70885
+ const localTextViewportRanges = useLocalTextCommitSnapshot && !patchedLocalTextSurface ? getSelectionCorridorViewportRanges(cachedRenderSnapshot.surface) : void 0;
70886
+ const localTextEditableTargetsByBlockPath = useLocalTextCommitSnapshot && !patchedLocalTextSurface ? getEditableTargetsByBlockPathForRanges(
70887
+ state.document,
70888
+ storyTargetKey(activeStory),
70889
+ localTextViewportRanges ?? null
70890
+ ) : void 0;
70891
+ const surfaceForValidation = patchedLocalTextSurface ? patchedLocalTextSurface : useLocalTextCommitSnapshot ? (() => {
70892
+ const tSurface0 = performance.now();
70893
+ try {
70894
+ perfCounters.increment("surface.localText.fullProjectionFallback");
70895
+ return getCachedSurface(state.document, activeStory, {
70896
+ viewportBlockRangesOverride: localTextViewportRanges,
70897
+ enrichCulledPlaceholders: false,
70898
+ editableTargetsByBlockPathOverride: localTextEditableTargetsByBlockPath
70899
+ });
70900
+ } finally {
70901
+ perfCounters.increment("surface.localText.fullProjection.us", Math.round((performance.now() - tSurface0) * 1e3));
70902
+ }
70903
+ })() : getCachedSurface(state.document, activeStory);
70279
70904
  const validationOptions = state.selection.activeRange.kind === "node" ? {
70280
70905
  isValidNodeTarget: createSurfaceNodeSelectionProbe(surfaceForValidation)
70281
70906
  } : void 0;
@@ -70542,7 +71167,8 @@ function createDocumentRuntime(options) {
70542
71167
  selection,
70543
71168
  surface: cachedRenderSnapshot.surface?.blocks ?? [],
70544
71169
  target: editableTarget,
70545
- activeStoryKey: canonicalEditableTargetStoryKey(activeStory)
71170
+ activeStoryKey: canonicalEditableTargetStoryKey(activeStory),
71171
+ editableTargetCache: editableTargetBlockCache
70546
71172
  }) : null;
70547
71173
  if (targetResolution?.kind === "rejected") {
70548
71174
  const blockedReason = targetResolution.blockedReason;
@@ -70594,6 +71220,7 @@ function createDocumentRuntime(options) {
70594
71220
  documentMode: textOptions.documentModeOverride ?? workflowCoordinator.getEffectiveDocumentMode(selection),
70595
71221
  defaultAuthorId: defaultAuthorId ?? void 0,
70596
71222
  renderSnapshot: cachedRenderSnapshot,
71223
+ activeStorySize: cachedRenderSnapshot.surface?.storySize,
70597
71224
  textTarget,
70598
71225
  rejectTargetlessTableStructureInsert: true
70599
71226
  };
@@ -72008,15 +72635,12 @@ function flattenInlineDisplayText(children) {
72008
72635
  }
72009
72636
  }).join("");
72010
72637
  }
72011
- function refreshDocumentFields(document2, selectionHead, activeStory, pageGraph, options) {
72638
+ function refreshDocumentFields(document2, selectionHead, activeStory, pageGraph, options, target) {
72012
72639
  const supportedOnly = options?.supportedOnly ?? true;
72013
72640
  const bookmarkMap = buildBookmarkNameMap(document2);
72014
72641
  const paragraphs = collectParagraphContexts(document2.content.children);
72015
- const activePageIndex = resolveActivePageIndexFromPageGraph(
72016
- pageGraph,
72017
- selectionHead,
72018
- activeStory
72019
- );
72642
+ void selectionHead;
72643
+ void activeStory;
72020
72644
  let updatedCount = 0;
72021
72645
  let changed = false;
72022
72646
  let changedFrom;
@@ -72026,19 +72650,27 @@ function refreshDocumentFields(document2, selectionHead, activeStory, pageGraph,
72026
72650
  let storyChangedFrom;
72027
72651
  let storyChangedTo;
72028
72652
  const refreshed = refreshBlocksWithCursor(blocks, (field, range) => {
72653
+ if (target !== void 0 && !fieldMatchesRefreshTarget(field, target)) {
72654
+ return field;
72655
+ }
72029
72656
  if (!field.fieldFamily || !isSupportedFieldFamily(field.fieldFamily)) {
72030
72657
  return field;
72031
72658
  }
72032
72659
  if (supportedOnly && field.fieldFamily === "TOC") {
72033
72660
  return field;
72034
72661
  }
72662
+ const fieldPageIndex = resolveActivePageIndexFromPageGraph(
72663
+ pageGraph,
72664
+ range.from,
72665
+ storyTarget
72666
+ );
72035
72667
  const display = resolveSupportedFieldDisplay(
72036
72668
  field,
72037
72669
  document2,
72038
72670
  bookmarkMap,
72039
72671
  paragraphs,
72040
72672
  pageGraph,
72041
- activePageIndex,
72673
+ fieldPageIndex,
72042
72674
  storyTarget
72043
72675
  );
72044
72676
  if (!display) {
@@ -72188,6 +72820,34 @@ function refreshDocumentFields(document2, selectionHead, activeStory, pageGraph,
72188
72820
  ...protectionSelection ? { protectionSelection } : {}
72189
72821
  };
72190
72822
  }
72823
+ function fieldMatchesRefreshTarget(field, target) {
72824
+ if (target.kind !== "field-result-text" && target.kind !== "field-region-refresh") {
72825
+ return false;
72826
+ }
72827
+ const targetField = target.field;
72828
+ if (targetField?.canonicalFieldId !== void 0) {
72829
+ return field.canonicalFieldId === targetField.canonicalFieldId;
72830
+ }
72831
+ const resultText = flattenInlineDisplayText(field.children);
72832
+ const fieldResultHash = sha256TextHex(`${field.instruction}\0${resultText}`);
72833
+ if (target.kind === "field-result-text" && target.staleCheck.targetHash !== void 0) {
72834
+ return target.staleCheck.targetHash === fieldResultHash;
72835
+ }
72836
+ if (targetField?.fieldFamily !== void 0 && targetField.fieldFamily !== field.fieldFamily) {
72837
+ return false;
72838
+ }
72839
+ if (targetField?.fieldTarget !== void 0 && targetField.fieldTarget !== field.fieldTarget) {
72840
+ return false;
72841
+ }
72842
+ if (target.staleCheck.sourceRef !== void 0 || target.sourceRef !== void 0) {
72843
+ return sourceRefsEqual(target.staleCheck.sourceRef ?? target.sourceRef, field.sourceRef);
72844
+ }
72845
+ return false;
72846
+ }
72847
+ function sourceRefsEqual(left, right) {
72848
+ if (left === void 0 || right === void 0) return false;
72849
+ return left.sourceId === right.sourceId && left.partPath === right.partPath && left.storyKind === right.storyKind && left.element === right.element && left.xmlPath === right.xmlPath && left.tableCellPath === right.tableCellPath && left.tableDepth === right.tableDepth && left.ordinal === right.ordinal && left.startOffset === right.startOffset && left.endOffset === right.endOffset;
72850
+ }
72191
72851
  function refreshDocumentTableOfContents(document2, selectionHead, activeStory, options, resolveDisplayPageNumber, navigationSnapshot) {
72192
72852
  const selectedRegion = selectTocRegion(document2.fieldRegistry?.tocRegions, options?.tocId);
72193
72853
  const refreshMode = options?.mode ?? "regenerate";
@@ -83401,7 +84061,8 @@ function parseCommentDefinitions(commentsXml, extensions, durableIds) {
83401
84061
  const createdAt = normalizeImportedTimestamp2(
83402
84062
  readStringAttr(child, "w:date")
83403
84063
  );
83404
- const initials = readStringAttr(child, "w:initials");
84064
+ const rawInitials = readStringAttr(child, "w:initials");
84065
+ const initials = rawInitials !== void 0 && rawInitials.trim().length > 0 ? rawInitials : void 0;
83405
84066
  const paragraphNodes = child.children.filter(
83406
84067
  (node) => node.type === "element" && localName(node.name) === "p"
83407
84068
  );
@@ -91465,12 +92126,16 @@ function TwToolbar(props) {
91465
92126
  const showUpdateActions = isToolbarChromeItemVisible(scopedChromePolicy, "update-actions");
91466
92127
  const showSidebarToggle = (props.showSidebarToggle ?? false) && isToolbarChromeItemVisible(scopedChromePolicy, "sidebar-toggle");
91467
92128
  const showStyleSelectorsInRow = getToolbarChromePlacement(scopedChromePolicy, "text-style-selectors") === "inline";
92129
+ const showStyleSelectorsInOverflow = getToolbarChromePlacement(scopedChromePolicy, "text-style-selectors") === "overflow";
92130
+ const showInlineFormattingInOverflow = getToolbarChromePlacement(scopedChromePolicy, "inline-formatting") === "overflow";
92131
+ const showTextColorsInOverflow = getToolbarChromePlacement(scopedChromePolicy, "text-colors") === "overflow";
92132
+ const showParagraphAlignmentInOverflow = getToolbarChromePlacement(scopedChromePolicy, "paragraph-alignment") === "overflow";
91468
92133
  const showListActionsInRow = getToolbarChromePlacement(scopedChromePolicy, "list-actions") === "inline";
91469
92134
  const showSpacingActionsInRow = getToolbarChromePlacement(scopedChromePolicy, "indentation") === "inline";
91470
92135
  const showListContinuationInRow = getToolbarChromePlacement(scopedChromePolicy, "list-continuation") === "inline";
91471
92136
  const showInsertActionsInRow = getToolbarChromePlacement(scopedChromePolicy, "insert-actions") === "inline";
91472
92137
  const showUpdateActionsInRow = getToolbarChromePlacement(scopedChromePolicy, "update-actions") === "inline";
91473
- const showCompactOverflow = getToolbarChromePlacement(scopedChromePolicy, "text-style-selectors") === "overflow" || getToolbarChromePlacement(scopedChromePolicy, "list-actions") === "overflow" || getToolbarChromePlacement(scopedChromePolicy, "indentation") === "overflow" || getToolbarChromePlacement(scopedChromePolicy, "list-continuation") === "overflow" || getToolbarChromePlacement(scopedChromePolicy, "insert-actions") === "overflow" || getToolbarChromePlacement(scopedChromePolicy, "update-actions") === "overflow";
92138
+ const showCompactOverflow = getToolbarChromePlacement(scopedChromePolicy, "text-style-selectors") === "overflow" || getToolbarChromePlacement(scopedChromePolicy, "inline-formatting") === "overflow" || getToolbarChromePlacement(scopedChromePolicy, "text-colors") === "overflow" || getToolbarChromePlacement(scopedChromePolicy, "paragraph-alignment") === "overflow" || getToolbarChromePlacement(scopedChromePolicy, "list-actions") === "overflow" || getToolbarChromePlacement(scopedChromePolicy, "indentation") === "overflow" || getToolbarChromePlacement(scopedChromePolicy, "list-continuation") === "overflow" || getToolbarChromePlacement(scopedChromePolicy, "insert-actions") === "overflow" || getToolbarChromePlacement(scopedChromePolicy, "update-actions") === "overflow";
91474
92139
  const showPostFormattingDivider = showListActionsInRow || showSpacingActionsInRow || showInsertActionsInRow || showUpdateActionsInRow || showCompactOverflow;
91475
92140
  const zoomLabel = typeof zoomLevel === "number" ? `${zoomLevel}%` : zoomLevel === "pageWidth" ? "Fit width" : "Fit page";
91476
92141
  const showZoomSteppers = responsiveTier === "wide";
@@ -91765,14 +92430,26 @@ function TwToolbar(props) {
91765
92430
  insertDisabledReason,
91766
92431
  paragraphStyles,
91767
92432
  showInsertMenu: getToolbarChromePlacement(scopedChromePolicy, "insert-actions") === "overflow",
92433
+ showInlineFormatting: showInlineFormattingInOverflow,
91768
92434
  showListActions: getToolbarChromePlacement(scopedChromePolicy, "list-actions") === "overflow",
91769
92435
  showParagraphActions: getToolbarChromePlacement(scopedChromePolicy, "indentation") === "overflow",
92436
+ showParagraphAlignment: showParagraphAlignmentInOverflow,
91770
92437
  showListContinuation: getToolbarChromePlacement(scopedChromePolicy, "list-continuation") === "overflow",
91771
- showStyleSelectors: getToolbarChromePlacement(scopedChromePolicy, "text-style-selectors") === "overflow",
92438
+ showStyleSelectors: showStyleSelectorsInOverflow,
92439
+ showTextColors: showTextColorsInOverflow,
91772
92440
  showUpdateActions: getToolbarChromePlacement(scopedChromePolicy, "update-actions") === "overflow",
91773
92441
  onSetParagraphStyle: props.onSetParagraphStyle,
91774
92442
  onSetFontFamily: props.onSetFontFamily,
91775
92443
  onSetFontSize: props.onSetFontSize,
92444
+ onToggleBold: props.onToggleBold,
92445
+ onToggleItalic: props.onToggleItalic,
92446
+ onToggleUnderline: props.onToggleUnderline,
92447
+ onToggleStrikethrough: props.onToggleStrikethrough,
92448
+ onToggleSuperscript: props.onToggleSuperscript,
92449
+ onToggleSubscript: props.onToggleSubscript,
92450
+ onSetTextColor: props.onSetTextColor,
92451
+ onSetHighlightColor: props.onSetHighlightColor,
92452
+ onSetAlignment: props.onSetAlignment,
91776
92453
  onToggleBulletedList: props.onToggleBulletedList,
91777
92454
  onToggleNumberedList: props.onToggleNumberedList,
91778
92455
  onOutdent: props.onOutdent,
@@ -92282,8 +92959,8 @@ function ToolbarFontSizeSelect(props) {
92282
92959
  function ToolbarCompactOverflow(props) {
92283
92960
  const [open, setOpen] = import_react7.default.useState(false);
92284
92961
  const overflowGroups = [
92285
- props.showStyleSelectors ? "Format" : null,
92286
- props.showListActions || props.showParagraphActions || props.showListContinuation ? "Paragraph" : null,
92962
+ props.showStyleSelectors || props.showInlineFormatting || props.showTextColors ? "Format" : null,
92963
+ props.showListActions || props.showParagraphActions || props.showParagraphAlignment || props.showListContinuation ? "Paragraph" : null,
92287
92964
  props.showInsertMenu ? "Insert" : null,
92288
92965
  props.showUpdateActions ? "Update" : null
92289
92966
  ].filter((label) => Boolean(label));
@@ -92368,6 +93045,129 @@ function ToolbarCompactOverflow(props) {
92368
93045
  ] })
92369
93046
  ] })
92370
93047
  ] }) : null,
93048
+ props.showInlineFormatting || props.showTextColors ? /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "space-y-1", children: [
93049
+ !props.showStyleSelectors ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "px-1 text-[10px] font-semibold uppercase tracking-[var(--tracking-status)] text-tertiary", children: "Text" }) : null,
93050
+ props.showInlineFormatting ? /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_jsx_runtime7.Fragment, { children: [
93051
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
93052
+ ToolbarMenuButton,
93053
+ {
93054
+ ariaLabel: "Bold",
93055
+ disabled: !props.canEdit || !props.onToggleBold,
93056
+ disabledReason: props.editDisabledReason,
93057
+ icon: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_lucide_react6.Bold, { className: "h-3.5 w-3.5" }),
93058
+ label: "Bold",
93059
+ onClick: () => {
93060
+ props.onToggleBold?.();
93061
+ setOpen(false);
93062
+ }
93063
+ }
93064
+ ),
93065
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
93066
+ ToolbarMenuButton,
93067
+ {
93068
+ ariaLabel: "Italic",
93069
+ disabled: !props.canEdit || !props.onToggleItalic,
93070
+ disabledReason: props.editDisabledReason,
93071
+ icon: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_lucide_react6.Italic, { className: "h-3.5 w-3.5" }),
93072
+ label: "Italic",
93073
+ onClick: () => {
93074
+ props.onToggleItalic?.();
93075
+ setOpen(false);
93076
+ }
93077
+ }
93078
+ ),
93079
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
93080
+ ToolbarMenuButton,
93081
+ {
93082
+ ariaLabel: "Underline",
93083
+ disabled: !props.canEdit || !props.onToggleUnderline,
93084
+ disabledReason: props.editDisabledReason,
93085
+ icon: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_lucide_react6.Underline, { className: "h-3.5 w-3.5" }),
93086
+ label: "Underline",
93087
+ onClick: () => {
93088
+ props.onToggleUnderline?.();
93089
+ setOpen(false);
93090
+ }
93091
+ }
93092
+ ),
93093
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
93094
+ ToolbarMenuButton,
93095
+ {
93096
+ ariaLabel: "Strikethrough",
93097
+ disabled: !props.canEdit || !props.onToggleStrikethrough,
93098
+ disabledReason: props.editDisabledReason,
93099
+ icon: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_lucide_react6.Strikethrough, { className: "h-3.5 w-3.5" }),
93100
+ label: "Strikethrough",
93101
+ onClick: () => {
93102
+ props.onToggleStrikethrough?.();
93103
+ setOpen(false);
93104
+ }
93105
+ }
93106
+ ),
93107
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
93108
+ ToolbarMenuButton,
93109
+ {
93110
+ ariaLabel: "Superscript",
93111
+ disabled: !props.canEdit || !props.onToggleSuperscript,
93112
+ disabledReason: props.editDisabledReason,
93113
+ icon: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_lucide_react6.Superscript, { className: "h-3.5 w-3.5" }),
93114
+ label: "Superscript",
93115
+ onClick: () => {
93116
+ props.onToggleSuperscript?.();
93117
+ setOpen(false);
93118
+ }
93119
+ }
93120
+ ),
93121
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
93122
+ ToolbarMenuButton,
93123
+ {
93124
+ ariaLabel: "Subscript",
93125
+ disabled: !props.canEdit || !props.onToggleSubscript,
93126
+ disabledReason: props.editDisabledReason,
93127
+ icon: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_lucide_react6.Subscript, { className: "h-3.5 w-3.5" }),
93128
+ label: "Subscript",
93129
+ onClick: () => {
93130
+ props.onToggleSubscript?.();
93131
+ setOpen(false);
93132
+ }
93133
+ }
93134
+ )
93135
+ ] }) : null,
93136
+ props.showTextColors ? /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "grid grid-cols-2 gap-2 px-1 pt-1", children: [
93137
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
93138
+ ToolbarColorPopover,
93139
+ {
93140
+ ariaLabel: "Text color",
93141
+ colors: TEXT_COLORS.map((value) => ({ value, label: value })),
93142
+ disabled: !props.canEdit || !props.onSetTextColor,
93143
+ disabledReason: props.editDisabledReason,
93144
+ icon: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_lucide_react6.Baseline, { className: "h-3.5 w-3.5" }),
93145
+ onSelect: (value) => {
93146
+ if (value) {
93147
+ props.onSetTextColor?.(value);
93148
+ setOpen(false);
93149
+ }
93150
+ },
93151
+ title: "Text color"
93152
+ }
93153
+ ),
93154
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
93155
+ ToolbarColorPopover,
93156
+ {
93157
+ ariaLabel: "Highlight color",
93158
+ colors: HIGHLIGHT_COLORS.map((entry) => ({ value: entry.value, label: entry.label })),
93159
+ disabled: !props.canEdit || !props.onSetHighlightColor,
93160
+ disabledReason: props.editDisabledReason,
93161
+ icon: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_lucide_react6.Highlighter, { className: "h-3.5 w-3.5" }),
93162
+ onSelect: (value) => {
93163
+ props.onSetHighlightColor?.(value);
93164
+ setOpen(false);
93165
+ },
93166
+ title: "Highlight color"
93167
+ }
93168
+ )
93169
+ ] }) : null
93170
+ ] }) : null,
92371
93171
  props.showListActions ? /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "space-y-1", children: [
92372
93172
  /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "px-1 text-[10px] font-semibold uppercase tracking-[var(--tracking-status)] text-tertiary", children: "Structure" }),
92373
93173
  /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
@@ -92399,8 +93199,20 @@ function ToolbarCompactOverflow(props) {
92399
93199
  }
92400
93200
  )
92401
93201
  ] }) : null,
92402
- props.showParagraphActions || props.showListContinuation && props.activeListContext ? /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "space-y-1", children: [
93202
+ props.showParagraphActions || props.showParagraphAlignment || props.showListContinuation && props.activeListContext ? /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "space-y-1", children: [
92403
93203
  /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "px-1 text-[10px] font-semibold uppercase tracking-[var(--tracking-status)] text-tertiary", children: "Paragraph" }),
93204
+ props.showParagraphAlignment ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "px-1 pb-1", children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
93205
+ ToolbarAlignmentPopover,
93206
+ {
93207
+ activeAlignment: props.formattingState?.alignment,
93208
+ disabled: !props.canEdit || !props.onSetAlignment,
93209
+ disabledReason: props.editDisabledReason,
93210
+ onSelect: (alignment) => {
93211
+ props.onSetAlignment?.(alignment);
93212
+ setOpen(false);
93213
+ }
93214
+ }
93215
+ ) }) : null,
92404
93216
  props.showParagraphActions ? /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_jsx_runtime7.Fragment, { children: [
92405
93217
  /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
92406
93218
  ToolbarMenuButton,
@@ -100897,10 +101709,7 @@ var TwPageStackOverlayLayer = ({
100897
101709
  null
100898
101710
  );
100899
101711
  if (warm) {
100900
- return extendPageOverlayRectsAcrossTableBoundaryGaps(
100901
- warm,
100902
- containsTableBoundaryRisk(scrollRoot) ? collectTableEmbeddedBoundaryIndices(scrollRoot) : []
100903
- );
101712
+ return warm;
100904
101713
  }
100905
101714
  }
100906
101715
  return resolveSkeletalPageOverlayRectsFromLayout(facet);
@@ -100941,7 +101750,7 @@ var TwPageStackOverlayLayer = ({
100941
101750
  );
100942
101751
  if (uiRects !== null) {
100943
101752
  incrementInvalidationCounter("overlay.page.ui_api.hit");
100944
- setRectsIfChanged(reconcilePaperRectsWithFlow(uiRects, pageCount));
101753
+ setRectsIfChanged(uiRects);
100945
101754
  return;
100946
101755
  }
100947
101756
  incrementInvalidationCounter("overlay.page.ui_api.fallthrough");
@@ -100956,7 +101765,7 @@ var TwPageStackOverlayLayer = ({
100956
101765
  );
100957
101766
  if (geometryRects !== null) {
100958
101767
  incrementInvalidationCounter("overlay.page.geometry.hit");
100959
- setRectsIfChanged(reconcilePaperRectsWithFlow(geometryRects, pageCount));
101768
+ setRectsIfChanged(geometryRects);
100960
101769
  return;
100961
101770
  }
100962
101771
  incrementInvalidationCounter("overlay.page.geometry.fallthrough");
@@ -101325,11 +102134,6 @@ function buildParagraphStyle(block) {
101325
102134
  style[cssKey] = `${width} ${bStyle} ${color}`;
101326
102135
  }
101327
102136
  }
101328
- if (block.pageBreakBefore) {
101329
- style.borderTop = "2px dashed rgba(0,0,0,0.1)";
101330
- style.paddingTop = "8px";
101331
- style.marginTop = "16px";
101332
- }
101333
102137
  const framePr = block.frameProperties;
101334
102138
  const hasPosition = typeof framePr?.xTwips === "number" || typeof framePr?.yTwips === "number" || typeof framePr?.xAlign === "string" || typeof framePr?.yAlign === "string";
101335
102139
  if (framePr && framePr.dropCap !== "drop" && framePr.dropCap !== "margin" && hasPosition) {
@@ -103141,7 +103945,7 @@ var TwPageStackChromeLayerInner = ({
103141
103945
  const [activeStoryPageIndex, setActiveStoryPageIndex] = import_react32.default.useState(null);
103142
103946
  const refreshRectsNow = import_react32.default.useCallback(() => {
103143
103947
  const pageCount = facet.getPageCount();
103144
- const reconcileRects = (baseRects) => reconcilePageStackRectsWithFlow({
103948
+ const reconcileDomRects = (baseRects) => reconcilePageStackRectsWithFlow({
103145
103949
  baseRects,
103146
103950
  pageCount,
103147
103951
  scrollRoot,
@@ -103149,7 +103953,7 @@ var TwPageStackChromeLayerInner = ({
103149
103953
  });
103150
103954
  const uiRects = resolveUiPageRects(pageCount);
103151
103955
  if (uiRects !== null) {
103152
- setRects(reconcileRects(uiRects));
103956
+ setRects(uiRects);
103153
103957
  return;
103154
103958
  }
103155
103959
  if (geometryFacet) {
@@ -103159,7 +103963,7 @@ var TwPageStackChromeLayerInner = ({
103159
103963
  visiblePageIndexRange
103160
103964
  );
103161
103965
  if (geometryRects !== null) {
103162
- setRects(reconcileRects(geometryRects));
103966
+ setRects(geometryRects);
103163
103967
  return;
103164
103968
  }
103165
103969
  setRects([]);
@@ -103187,7 +103991,7 @@ var TwPageStackChromeLayerInner = ({
103187
103991
  visiblePageIndexRange
103188
103992
  });
103189
103993
  setRects(
103190
- reconcileRects(domRects)
103994
+ reconcileDomRects(domRects)
103191
103995
  );
103192
103996
  } else {
103193
103997
  const widgets = measureWidgetsViaOffsetChain(scrollRoot, {
@@ -103202,7 +104006,7 @@ var TwPageStackChromeLayerInner = ({
103202
104006
  visiblePageIndexRange
103203
104007
  });
103204
104008
  setRects(
103205
- reconcileRects(domRects)
104009
+ reconcileDomRects(domRects)
103206
104010
  );
103207
104011
  }
103208
104012
  }, [facet, geometryFacet, resolveUiPageRects, scrollRoot, visiblePageIndexRange]);
@@ -110924,7 +111728,6 @@ var editorSchema = new import_prosemirror_model.Schema({
110924
111728
  }
110925
111729
  }
110926
111730
  const pageBreak = node.attrs.pageBreakBefore;
110927
- if (pageBreak) styles.push("border-top: 2px dashed rgba(0,0,0,0.1); padding-top: 8px; margin-top: 16px");
110928
111731
  const framePr = node.attrs.frameProperties;
110929
111732
  const hasPosition = typeof framePr?.xTwips === "number" || typeof framePr?.yTwips === "number" || typeof framePr?.xAlign === "string" || typeof framePr?.yAlign === "string";
110930
111733
  if (framePr && framePr.dropCap !== "drop" && framePr.dropCap !== "margin" && hasPosition) {
@@ -110988,15 +111791,7 @@ var editorSchema = new import_prosemirror_model.Schema({
110988
111791
  const numberingPicBulletSrc = node.attrs.numberingPicBulletSrc;
110989
111792
  const children = [];
110990
111793
  if (pageBreak) {
110991
- children.push([
110992
- "span",
110993
- {
110994
- class: "mb-2 inline-flex items-center gap-2 text-[10px] font-medium uppercase tracking-[var(--tracking-eyebrow)] text-tertiary",
110995
- contenteditable: "false",
110996
- "data-page-break-before": "true"
110997
- },
110998
- "Page break"
110999
- ]);
111794
+ attrs["data-page-break-before"] = "true";
111000
111795
  }
111001
111796
  if (numberingPrefix || numberingPicBulletSrc) {
111002
111797
  const hasResolvedMarkerWidth = typeof numberingMarkerWidth === "number" && numberingMarkerWidth > 0;
@@ -111321,7 +112116,6 @@ var editorSchema = new import_prosemirror_model.Schema({
111321
112116
  "section",
111322
112117
  {
111323
112118
  class: "my-0 border-0 bg-transparent p-0",
111324
- style: "min-height:var(--wre-page-frame-height-px,1056px);position:relative",
111325
112119
  "data-node-type": "sdt_block",
111326
112120
  "data-sdt-page-break": "true"
111327
112121
  },
@@ -111677,6 +112471,34 @@ var editorSchema = new import_prosemirror_model.Schema({
111677
112471
  ];
111678
112472
  }
111679
112473
  },
112474
+ textbox_inline: {
112475
+ inline: true,
112476
+ group: "inline",
112477
+ content: "text*",
112478
+ marks: "_",
112479
+ selectable: true,
112480
+ isolating: true,
112481
+ attrs: {
112482
+ label: { default: "Text box" },
112483
+ detail: { default: null },
112484
+ targetKey: { default: null },
112485
+ geometry: { default: null }
112486
+ },
112487
+ toDOM(node) {
112488
+ const title = node.attrs.detail ?? node.attrs.label;
112489
+ return [
112490
+ "span",
112491
+ {
112492
+ class: "inline-block min-w-[2ch] max-w-full align-middle mx-0.5 rounded-[2px] border border-border bg-surface px-1 py-0.5 text-primary",
112493
+ "data-node-type": "textbox_inline",
112494
+ "data-editable-target-key": node.attrs.targetKey ?? "",
112495
+ "data-shape-geometry": node.attrs.geometry ?? "",
112496
+ title
112497
+ },
112498
+ 0
112499
+ ];
112500
+ }
112501
+ },
111680
112502
  wordart_atom: {
111681
112503
  inline: true,
111682
112504
  group: "inline",
@@ -112055,16 +112877,16 @@ function buildPositionMap(surface) {
112055
112877
  const pmDocSize = walkBlocks2(surface.blocks, 1, entries, protectedInlineEntries, { rootLevel: true });
112056
112878
  const runtimeStorySize = surface.storySize;
112057
112879
  const runtimeToPm = (runtimePos) => {
112058
- const firstEditable = entries.find(isRuntimeRestorableEntry);
112880
+ const firstEditable = entries.find(isStoryRuntimeRestorableEntry);
112059
112881
  if (runtimePos <= 0) {
112060
112882
  return firstEditable?.pmStart ?? 1;
112061
112883
  }
112062
112884
  if (runtimePos >= runtimeStorySize) {
112063
- return lastRestorableEntry(entries)?.pmEnd ?? pmDocSize - 1;
112885
+ return lastStoryRestorableEntry(entries)?.pmEnd ?? pmDocSize - 1;
112064
112886
  }
112065
112887
  let previous = null;
112066
112888
  for (const entry of entries) {
112067
- if (!isRuntimeRestorableEntry(entry)) {
112889
+ if (!isStoryRuntimeRestorableEntry(entry)) {
112068
112890
  continue;
112069
112891
  }
112070
112892
  if (entry.runtimeStart === entry.runtimeEnd && runtimePos === entry.runtimeStart) {
@@ -112078,12 +112900,12 @@ function buildPositionMap(surface) {
112078
112900
  }
112079
112901
  previous = entry;
112080
112902
  }
112081
- return lastRestorableEntry(entries)?.pmEnd ?? 1;
112903
+ return lastStoryRestorableEntry(entries)?.pmEnd ?? 1;
112082
112904
  };
112083
112905
  return {
112084
112906
  runtimeToPm,
112085
112907
  runtimeToPmWithContext(input) {
112086
- const targetEntry = input.editableTarget ? findRestorableEntryForTarget(entries, input.editableTarget) : void 0;
112908
+ const targetEntry = input.editableTarget ? findRestorableEntryForTarget(entries, input.editableTarget, input.runtimePos) : void 0;
112087
112909
  if (targetEntry) {
112088
112910
  return pmForRuntimeInTargetEntry(targetEntry, input.runtimePos, protectedInlineEntries);
112089
112911
  }
@@ -112184,7 +113006,7 @@ function isEditablePmRange(entries, protectedInlineEntries, pmDocSize, runtimeSt
112184
113006
  if (entry.editable === false) return false;
112185
113007
  }
112186
113008
  for (const entry of protectedInlineEntries) {
112187
- if (pmRangeTouchesEntry(start, end, entry)) return false;
113009
+ if (entry.editable === false && pmRangeTouchesEntry(start, end, entry)) return false;
112188
113010
  }
112189
113011
  return true;
112190
113012
  }
@@ -112192,9 +113014,9 @@ function protectedInlineEntryAtPm(protectedInlineEntries, pmPos) {
112192
113014
  return protectedInlineEntries.find((entry) => pmPos > entry.pmStart && pmPos < entry.pmEnd);
112193
113015
  }
112194
113016
  function pmForRuntimeInTargetEntry(entry, runtimePos, protectedInlineEntries) {
112195
- const runtimeDelta = Math.max(
112196
- 0,
112197
- Math.min(runtimePos - entry.runtimeStart, entry.runtimeEnd - entry.runtimeStart)
113017
+ const runtimeDelta = Math.min(
113018
+ runtimePos - entry.runtimeStart,
113019
+ entry.runtimeEnd - entry.runtimeStart
112198
113020
  );
112199
113021
  let pmPos = entry.pmStart + runtimeDelta;
112200
113022
  for (const protectedEntry of protectedInlineEntries) {
@@ -112223,10 +113045,13 @@ function nearestRuntimeGapPm(runtimePos, previous, next) {
112223
113045
  function isRuntimeRestorableEntry(entry) {
112224
113046
  return entry.editable !== false && entry.restorable !== false;
112225
113047
  }
112226
- function lastRestorableEntry(entries) {
113048
+ function isStoryRuntimeRestorableEntry(entry) {
113049
+ return isRuntimeRestorableEntry(entry) && entry.runtimeSpace !== "target";
113050
+ }
113051
+ function lastStoryRestorableEntry(entries) {
112227
113052
  for (let index = entries.length - 1; index >= 0; index -= 1) {
112228
113053
  const entry = entries[index];
112229
- if (isRuntimeRestorableEntry(entry)) {
113054
+ if (isStoryRuntimeRestorableEntry(entry)) {
112230
113055
  return entry;
112231
113056
  }
112232
113057
  }
@@ -112257,27 +113082,90 @@ function walkBlocks2(blocks, pmCursor, entries, protectedInlineEntries, context)
112257
113082
  const runtimeLength = block.to - block.from;
112258
113083
  const tableCell = context.tableCell ?? tableCellFromEditableTarget(block.editableTarget);
112259
113084
  const editable = context.editable !== false;
112260
- entries.push({
112261
- runtimeStart: block.from,
112262
- pmStart: pmContentStart,
112263
- runtimeEnd: block.to,
112264
- pmEnd: pmContentStart + runtimeLength,
112265
- editable,
112266
- insideTable: context.insideTable === true || context.tableCell !== void 0,
112267
- editableTarget: block.editableTarget,
112268
- textTarget: editable && tableCell ? {
112269
- kind: "table-paragraph",
112270
- tableBlockIndex: tableCell.tableBlockIndex,
112271
- rowIndex: tableCell.rowIndex,
112272
- cellIndex: tableCell.cellIndex,
112273
- childIndex: blockIndex,
112274
- paragraphStart: block.from,
112275
- paragraphEnd: block.to,
112276
- ...block.editableTarget ? { blockPath: block.editableTarget.blockPath } : {}
112277
- } : void 0
112278
- });
112279
- addProtectedInlineEntries(block, pmContentStart, protectedInlineEntries);
112280
- nextPmCursor += runtimeLength + 2;
113085
+ const textTarget = editable && tableCell ? {
113086
+ kind: "table-paragraph",
113087
+ tableBlockIndex: tableCell.tableBlockIndex,
113088
+ rowIndex: tableCell.rowIndex,
113089
+ cellIndex: tableCell.cellIndex,
113090
+ childIndex: blockIndex,
113091
+ paragraphStart: block.from,
113092
+ paragraphEnd: block.to,
113093
+ ...block.editableTarget ? { blockPath: block.editableTarget.blockPath } : {}
113094
+ } : void 0;
113095
+ const insideTable = context.insideTable === true || context.tableCell !== void 0;
113096
+ let pmSegmentCursor = pmContentStart;
113097
+ let emittedStoryEntry = false;
113098
+ if (block.editableTarget !== void 0) {
113099
+ entries.push({
113100
+ runtimeStart: block.from,
113101
+ pmStart: pmContentStart,
113102
+ runtimeEnd: block.from,
113103
+ pmEnd: pmContentStart,
113104
+ editable,
113105
+ insideTable,
113106
+ runtimeSpace: "target",
113107
+ editableTarget: block.editableTarget,
113108
+ textTarget
113109
+ });
113110
+ }
113111
+ for (const segment of block.segments) {
113112
+ const pmSize = pmSizeForSegment(segment);
113113
+ const textBoxParagraph = firstEditableTextBoxParagraph(segment);
113114
+ if (textBoxParagraph?.editableTarget) {
113115
+ const textLength = Math.max(0, textBoxParagraph.textLength);
113116
+ const textStart = pmSegmentCursor + 1;
113117
+ entries.push({
113118
+ runtimeStart: 0,
113119
+ pmStart: textStart,
113120
+ runtimeEnd: textLength,
113121
+ pmEnd: textStart + textLength,
113122
+ editable: true,
113123
+ restorable: true,
113124
+ runtimeSpace: "target",
113125
+ editableTarget: textBoxParagraph.editableTarget
113126
+ });
113127
+ } else if (isStoryTextSegment(segment)) {
113128
+ entries.push({
113129
+ runtimeStart: segment.from,
113130
+ pmStart: pmSegmentCursor,
113131
+ runtimeEnd: segment.to,
113132
+ pmEnd: pmSegmentCursor + Math.max(0, segment.to - segment.from),
113133
+ editable,
113134
+ insideTable,
113135
+ editableTarget: block.editableTarget,
113136
+ textTarget
113137
+ });
113138
+ emittedStoryEntry = true;
113139
+ }
113140
+ addProtectedInlineEntryForSegment(segment, pmSegmentCursor, protectedInlineEntries);
113141
+ pmSegmentCursor += pmSize;
113142
+ }
113143
+ if (block.editableTarget !== void 0 && block.to !== block.from) {
113144
+ entries.push({
113145
+ runtimeStart: block.to,
113146
+ pmStart: pmSegmentCursor,
113147
+ runtimeEnd: block.to,
113148
+ pmEnd: pmSegmentCursor,
113149
+ editable,
113150
+ insideTable,
113151
+ runtimeSpace: "target",
113152
+ editableTarget: block.editableTarget,
113153
+ textTarget
113154
+ });
113155
+ }
113156
+ if (!emittedStoryEntry || runtimeLength === 0) {
113157
+ entries.push({
113158
+ runtimeStart: block.from,
113159
+ pmStart: pmContentStart,
113160
+ runtimeEnd: block.to,
113161
+ pmEnd: pmContentStart,
113162
+ editable,
113163
+ insideTable,
113164
+ editableTarget: block.editableTarget,
113165
+ textTarget
113166
+ });
113167
+ }
113168
+ nextPmCursor += pmSegmentCursor - pmContentStart + 2;
112281
113169
  break;
112282
113170
  }
112283
113171
  case "opaque_block": {
@@ -112334,21 +113222,39 @@ function walkBlocks2(blocks, pmCursor, entries, protectedInlineEntries, context)
112334
113222
  }
112335
113223
  return nextPmCursor;
112336
113224
  }
112337
- function addProtectedInlineEntries(block, pmContentStart, protectedInlineEntries) {
112338
- for (const segment of block.segments) {
112339
- if (segment.kind !== "opaque_inline" && segment.kind !== "shape") {
112340
- continue;
112341
- }
112342
- const runtimeLength = Math.max(1, segment.to - segment.from);
112343
- const pmStart = pmContentStart + Math.max(0, segment.from - block.from);
112344
- protectedInlineEntries.push({
112345
- runtimeStart: segment.from,
112346
- pmStart,
112347
- runtimeEnd: segment.to,
112348
- pmEnd: pmStart + runtimeLength,
112349
- editable: false
112350
- });
113225
+ function pmSizeForSegment(segment) {
113226
+ const textBoxParagraph = firstEditableTextBoxParagraph(segment);
113227
+ if (textBoxParagraph) {
113228
+ return Math.max(0, textBoxParagraph.textLength) + 2;
113229
+ }
113230
+ return Math.max(1, segment.to - segment.from);
113231
+ }
113232
+ function isStoryTextSegment(segment) {
113233
+ return segment.kind === "text" || segment.kind === "tab" || segment.kind === "hard_break";
113234
+ }
113235
+ function firstEditableTextBoxParagraph(segment) {
113236
+ if (segment.kind !== "shape" || segment.isTextBox !== true || segment.txbxBody?.status !== "modeled") {
113237
+ return null;
112351
113238
  }
113239
+ return segment.txbxBody.paragraphs.find(
113240
+ (paragraph) => paragraph.editableTarget?.editability === "editable" && paragraph.editableTarget.posture.blockers.length === 0
113241
+ ) ?? null;
113242
+ }
113243
+ function addProtectedInlineEntryForSegment(segment, pmStart, protectedInlineEntries) {
113244
+ if (segment.kind !== "opaque_inline" && segment.kind !== "shape") {
113245
+ return;
113246
+ }
113247
+ if (firstEditableTextBoxParagraph(segment)) {
113248
+ return;
113249
+ }
113250
+ const runtimeLength = Math.max(1, segment.to - segment.from);
113251
+ protectedInlineEntries.push({
113252
+ runtimeStart: segment.from,
113253
+ pmStart,
113254
+ runtimeEnd: segment.to,
113255
+ pmEnd: pmStart + runtimeLength,
113256
+ editable: false
113257
+ });
112352
113258
  }
112353
113259
  function hasEditableTargetInBlocks(blocks) {
112354
113260
  for (const block of blocks) {
@@ -112379,21 +113285,46 @@ function findInertEntryForTarget(entries, target) {
112379
113285
  return entry.editable === false && candidate?.targetKey === target.targetKey && candidate.storyKey === target.storyKey && candidate.blockPath === target.blockPath && candidate.leafPath === target.leafPath && candidate.kind === target.kind;
112380
113286
  });
112381
113287
  }
112382
- function findRestorableEntryForTarget(entries, target) {
113288
+ function findRestorableEntryForTarget(entries, target, runtimePos) {
112383
113289
  if ("editableOwner" in target && target.editableOwner && isSyntheticLayoutContinuationTarget2(target)) {
112384
- return findRestorableEntryForOwner(entries, target.editableOwner);
113290
+ return findRestorableEntryForOwner(entries, target.editableOwner, runtimePos);
112385
113291
  }
112386
- return entries.find((entry) => {
113292
+ return selectRestorableEntryForRuntime(entries, runtimePos, (entry) => {
112387
113293
  const candidate = entry.editableTarget;
112388
113294
  return isRuntimeRestorableEntry(entry) && candidate?.targetKey === target.targetKey && candidate.storyKey === target.storyKey && candidate.blockPath === target.blockPath && candidate.leafPath === target.leafPath && candidate.kind === target.kind;
112389
113295
  });
112390
113296
  }
112391
- function findRestorableEntryForOwner(entries, owner) {
112392
- return entries.find((entry) => {
113297
+ function findRestorableEntryForOwner(entries, owner, runtimePos) {
113298
+ return selectRestorableEntryForRuntime(entries, runtimePos, (entry) => {
112393
113299
  const candidate = entry.editableTarget;
112394
113300
  return isRuntimeRestorableEntry(entry) && candidate?.targetKey === owner.targetKey && candidate.storyKey === owner.storyKey && candidate.blockPath === owner.blockPath && candidate.leafPath === owner.leafPath && candidate.kind === owner.kind && candidate.commandFamily === owner.commandFamily;
112395
113301
  });
112396
113302
  }
113303
+ function selectRestorableEntryForRuntime(entries, runtimePos, predicate) {
113304
+ const candidates = entries.filter(predicate);
113305
+ if (candidates.length === 0 || runtimePos === void 0) {
113306
+ return candidates[0];
113307
+ }
113308
+ const containing = candidates.filter(
113309
+ (entry) => runtimePos >= entry.runtimeStart && runtimePos <= entry.runtimeEnd
113310
+ );
113311
+ if (containing.length > 0) {
113312
+ return containing.sort(
113313
+ (left, right) => left.runtimeEnd - left.runtimeStart - (right.runtimeEnd - right.runtimeStart)
113314
+ )[0];
113315
+ }
113316
+ return candidates.sort((left, right) => {
113317
+ const leftDistance = Math.min(
113318
+ Math.abs(runtimePos - left.runtimeStart),
113319
+ Math.abs(runtimePos - left.runtimeEnd)
113320
+ );
113321
+ const rightDistance = Math.min(
113322
+ Math.abs(runtimePos - right.runtimeStart),
113323
+ Math.abs(runtimePos - right.runtimeEnd)
113324
+ );
113325
+ return leftDistance - rightDistance;
113326
+ })[0];
113327
+ }
112397
113328
  function isSyntheticLayoutContinuationTarget2(target) {
112398
113329
  return target.commandFamily === "text-leaf" && target.table?.operationScope === "text" && target.table.verticalMerge === "continue" && target.posture.blockers.includes("synthetic-layout-cell");
112399
113330
  }
@@ -113078,9 +114009,9 @@ function createChartFamily(_runtime) {
113078
114009
  }
113079
114010
 
113080
114011
  // src/ui-tailwind/editor-surface/pm-state-from-snapshot.ts
113081
- var CANONICAL_BLOCK_REFS_SYMBOL2 = /* @__PURE__ */ Symbol.for("wre.canonical-block-refs");
114012
+ var CANONICAL_BLOCK_REFS_SYMBOL3 = /* @__PURE__ */ Symbol.for("wre.canonical-block-refs");
113082
114013
  function getCanonicalBlockRefs2(snapshot) {
113083
- const refs = snapshot[CANONICAL_BLOCK_REFS_SYMBOL2];
114014
+ const refs = snapshot[CANONICAL_BLOCK_REFS_SYMBOL3];
113084
114015
  return refs ?? null;
113085
114016
  }
113086
114017
  var pmNodeCache = /* @__PURE__ */ new WeakMap();
@@ -113515,6 +114446,24 @@ function buildInlineContent(segment, mediaPreviews, showUnsupportedObjectPreview
113515
114446
  case "opaque_inline":
113516
114447
  return [buildOpaqueInlineOrComplexAtom(segment, mediaPreviews, showUnsupportedObjectPreviews)];
113517
114448
  case "shape": {
114449
+ const textBoxParagraph = firstEditableTextBoxParagraph2(segment);
114450
+ if (textBoxParagraph) {
114451
+ const content = textBoxParagraph.runs.flatMap(
114452
+ (run) => textBoxRunToPMNodes(run)
114453
+ );
114454
+ const fallbackContent = content.length > 0 && textBoxParagraph.text.length > 0 ? content : textBoxParagraph.text.length > 0 ? [editorSchema.text(textBoxParagraph.text)] : [];
114455
+ return [
114456
+ editorSchema.nodes.textbox_inline.create(
114457
+ {
114458
+ label: segment.label,
114459
+ detail: segment.detail,
114460
+ targetKey: textBoxParagraph.editableTarget?.targetKey ?? null,
114461
+ geometry: segment.geometry ?? null
114462
+ },
114463
+ fallbackContent
114464
+ )
114465
+ ];
114466
+ }
113518
114467
  const renderInPageOverlay = renderAbsoluteFloatingObjectsInPageOverlay && shouldRenderAbsoluteFloatingImageInPageOverlay(segment.anchor);
113519
114468
  return [
113520
114469
  editorSchema.nodes.shape_atom.create({
@@ -113555,6 +114504,28 @@ function buildInlineContent(segment, mediaPreviews, showUnsupportedObjectPreview
113555
114504
  return [];
113556
114505
  }
113557
114506
  }
114507
+ function firstEditableTextBoxParagraph2(segment) {
114508
+ if (segment.isTextBox !== true || segment.txbxBody?.status !== "modeled") {
114509
+ return null;
114510
+ }
114511
+ return segment.txbxBody.paragraphs.find(
114512
+ (paragraph) => paragraph.editableTarget?.editability === "editable" && paragraph.editableTarget.posture.blockers.length === 0
114513
+ ) ?? null;
114514
+ }
114515
+ function textBoxRunToPMNodes(run) {
114516
+ if (run.kind !== "text" || !run.text) return [];
114517
+ const segment = {
114518
+ segmentId: `textbox-run-${run.inlineIndex}`,
114519
+ kind: "text",
114520
+ from: 0,
114521
+ to: run.textLength ?? Array.from(run.text).length,
114522
+ text: run.text,
114523
+ ...run.marks && run.marks.length > 0 ? { marks: run.marks } : {},
114524
+ ...run.markAttrs ? { markAttrs: run.markAttrs } : {}
114525
+ };
114526
+ const marks = applyEffectiveMarks(segment, editorSchema);
114527
+ return [editorSchema.text(run.text, marks.length > 0 ? marks : void 0)];
114528
+ }
113558
114529
  function buildTable(block, mediaPreviews, showUnsupportedObjectPreviews, renderAbsoluteFloatingObjectsInPageOverlay) {
113559
114530
  const rows = [];
113560
114531
  for (const row2 of block.rows) {
@@ -115130,13 +116101,20 @@ function createPredictedPositionMap(canonical, pendingOps) {
115130
116101
  },
115131
116102
  pmToRuntimeWithContext(pmPos) {
115132
116103
  let adjusted = pmPos;
115133
- for (const op of pendingOps) {
115134
- const opPmStart = canonical.runtimeToPm(op.fromRuntime);
116104
+ for (let index = 0; index < pendingOps.length; index += 1) {
116105
+ const op = pendingOps[index];
116106
+ const opPmStart = canonical.runtimeToPm(
116107
+ canonicalRuntimeForPredictedOp(pendingOps, index)
116108
+ );
115135
116109
  if (adjusted > opPmStart) {
115136
116110
  adjusted -= opSizeDelta(op);
115137
116111
  }
115138
116112
  }
115139
- return canonical.pmToRuntimeWithContext(Math.max(1, adjusted));
116113
+ const context = canonical.pmToRuntimeWithContext(Math.max(1, adjusted));
116114
+ return {
116115
+ ...context,
116116
+ runtimePos: applyPendingOpsToCanonicalRuntime(context.runtimePos, pendingOps)
116117
+ };
115140
116118
  },
115141
116119
  ...canonical.isPmRangeEditable ? {
115142
116120
  isPmRangeEditable(fromPm, toPm) {
@@ -115156,6 +116134,25 @@ function createPredictedPositionMap(canonical, pendingOps) {
115156
116134
  }
115157
116135
  };
115158
116136
  }
116137
+ function canonicalRuntimeForPredictedOp(pendingOps, opIndex) {
116138
+ let runtimePos = pendingOps[opIndex]?.fromRuntime ?? 0;
116139
+ for (let index = 0; index < opIndex; index += 1) {
116140
+ const op = pendingOps[index];
116141
+ if (op.fromRuntime <= runtimePos) {
116142
+ runtimePos -= opSizeDelta(op);
116143
+ }
116144
+ }
116145
+ return Math.max(0, runtimePos);
116146
+ }
116147
+ function applyPendingOpsToCanonicalRuntime(runtimePos, pendingOps) {
116148
+ let transformed = runtimePos;
116149
+ for (const op of pendingOps) {
116150
+ if (op.fromRuntime <= transformed) {
116151
+ transformed += opSizeDelta(op);
116152
+ }
116153
+ }
116154
+ return Math.max(0, transformed);
116155
+ }
115159
116156
  function totalDelta(pendingOps) {
115160
116157
  let delta = 0;
115161
116158
  for (const op of pendingOps) {
@@ -123387,6 +124384,8 @@ function toV3PageLocalStoryObject(object) {
123387
124384
  heightTwips: object.extentTwips.heightTwips
123388
124385
  }
123389
124386
  } : {},
124387
+ ...object.anchorRectTwips ? { anchorRectTwips: cloneRect2(object.anchorRectTwips) } : {},
124388
+ ...object.textBoxBody ? { textBoxBody: object.textBoxBody } : {},
123390
124389
  ...object.relationshipIds ? { relationshipIds: [...object.relationshipIds] } : {},
123391
124390
  ...object.mediaIds ? { mediaIds: [...object.mediaIds] } : {},
123392
124391
  preserveOnly: object.preserveOnly,