@beyondwork/docx-react-component 1.0.132 → 1.0.134

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 (94) hide show
  1. package/dist/api/public-types.cjs +161 -68
  2. package/dist/api/public-types.d.cts +1 -1
  3. package/dist/api/public-types.d.ts +1 -1
  4. package/dist/api/public-types.js +3 -3
  5. package/dist/api/v3.cjs +9878 -7387
  6. package/dist/api/v3.d.cts +2 -2
  7. package/dist/api/v3.d.ts +2 -2
  8. package/dist/api/v3.js +10 -10
  9. package/dist/{chunk-QUTVR72L.js → chunk-3YR47WTD.js} +296 -587
  10. package/dist/{chunk-RYMMKOFI.js → chunk-5KTJKTNE.js} +32 -0
  11. package/dist/{chunk-UP2KDOYE.js → chunk-74R5B2EZ.js} +6 -2
  12. package/dist/{chunk-6736GA6J.js → chunk-7Y6JCIK3.js} +1 -1
  13. package/dist/{chunk-43JAPM2F.js → chunk-EBSI6VQX.js} +546 -144
  14. package/dist/{chunk-JVTDBX67.js → chunk-EFEW7BTT.js} +2 -2
  15. package/dist/{chunk-YUHNDEV5.js → chunk-ESEEWELA.js} +3534 -1870
  16. package/dist/{chunk-XYTWOJII.js → chunk-IJD6D7HU.js} +745 -103
  17. package/dist/{chunk-UFPBYJMA.js → chunk-INLRCC4N.js} +2 -2
  18. package/dist/{chunk-N5FTU4HZ.js → chunk-MQ5GAJ54.js} +68 -39
  19. package/dist/{chunk-W2I47J2Q.js → chunk-NJFKPDNG.js} +216 -2
  20. package/dist/{chunk-LPLJZJT2.js → chunk-O4EDZR44.js} +131 -70
  21. package/dist/{chunk-4HGFJ6Z2.js → chunk-PZIEOEJZ.js} +1 -1
  22. package/dist/{chunk-C5LXKR54.js → chunk-QTRJLKR2.js} +1 -1
  23. package/dist/{chunk-SZ6BJA4Q.js → chunk-REFHJ2FN.js} +3 -3
  24. package/dist/{chunk-ZDYGRO2Z.js → chunk-RP76USJE.js} +1 -1
  25. package/dist/{chunk-RBWJHRNP.js → chunk-T66OS7MN.js} +8 -3
  26. package/dist/{chunk-ALWXYGXP.js → chunk-V2JF42SI.js} +2 -2
  27. package/dist/{chunk-CDEZGLQ3.js → chunk-VA24T4EB.js} +1 -1
  28. package/dist/{chunk-6TLZ6CMP.js → chunk-WDDFU2N2.js} +2 -2
  29. package/dist/{chunk-U3UMKA7B.js → chunk-XBQFDBXE.js} +1 -1
  30. package/dist/core/commands/formatting-commands.d.cts +1 -1
  31. package/dist/core/commands/formatting-commands.d.ts +1 -1
  32. package/dist/core/commands/image-commands.cjs +32 -0
  33. package/dist/core/commands/image-commands.d.cts +1 -1
  34. package/dist/core/commands/image-commands.d.ts +1 -1
  35. package/dist/core/commands/image-commands.js +5 -5
  36. package/dist/core/commands/section-layout-commands.d.cts +1 -1
  37. package/dist/core/commands/section-layout-commands.d.ts +1 -1
  38. package/dist/core/commands/style-commands.d.cts +1 -1
  39. package/dist/core/commands/style-commands.d.ts +1 -1
  40. package/dist/core/commands/table-structure-commands.cjs +32 -0
  41. package/dist/core/commands/table-structure-commands.d.cts +1 -1
  42. package/dist/core/commands/table-structure-commands.d.ts +1 -1
  43. package/dist/core/commands/table-structure-commands.js +4 -4
  44. package/dist/core/commands/text-commands.cjs +99 -38
  45. package/dist/core/commands/text-commands.d.cts +12 -1
  46. package/dist/core/commands/text-commands.d.ts +12 -1
  47. package/dist/core/commands/text-commands.js +5 -5
  48. package/dist/core/selection/mapping.d.cts +1 -1
  49. package/dist/core/selection/mapping.d.ts +1 -1
  50. package/dist/core/state/editor-state.d.cts +1 -1
  51. package/dist/core/state/editor-state.d.ts +1 -1
  52. package/dist/index.cjs +5365 -2298
  53. package/dist/index.d.cts +4 -4
  54. package/dist/index.d.ts +4 -4
  55. package/dist/index.js +388 -63
  56. package/dist/io/docx-session.cjs +7 -2
  57. package/dist/io/docx-session.d.cts +3 -3
  58. package/dist/io/docx-session.d.ts +3 -3
  59. package/dist/io/docx-session.js +4 -4
  60. package/dist/legal.js +3 -3
  61. package/dist/{loader-MAa8VpzW.d.cts → loader-CK3lZy4h.d.cts} +2 -2
  62. package/dist/{loader-CfpeEPAa.d.ts → loader-CQXplstv.d.ts} +2 -2
  63. package/dist/{public-types-KBS6JnOs.d.cts → public-types-BR1SYK2F.d.cts} +783 -189
  64. package/dist/{public-types-Cjs8glST.d.ts → public-types-DXNZVKrS.d.ts} +783 -189
  65. package/dist/public-types.cjs +161 -68
  66. package/dist/public-types.d.cts +1 -1
  67. package/dist/public-types.d.ts +1 -1
  68. package/dist/public-types.js +3 -3
  69. package/dist/runtime/collab.d.cts +2 -2
  70. package/dist/runtime/collab.d.ts +2 -2
  71. package/dist/runtime/document-runtime.cjs +1597 -444
  72. package/dist/runtime/document-runtime.d.cts +1 -1
  73. package/dist/runtime/document-runtime.d.ts +1 -1
  74. package/dist/runtime/document-runtime.js +14 -14
  75. package/dist/{session-CkoH8FoY.d.ts → session-C9UjrhJF.d.ts} +2 -2
  76. package/dist/{session-wwe0Gib-.d.cts → session-CSbwkgII.d.cts} +2 -2
  77. package/dist/session.cjs +7 -2
  78. package/dist/session.d.cts +4 -4
  79. package/dist/session.d.ts +4 -4
  80. package/dist/session.js +5 -5
  81. package/dist/tailwind.cjs +451 -650
  82. package/dist/tailwind.d.cts +1 -1
  83. package/dist/tailwind.d.ts +1 -1
  84. package/dist/tailwind.js +7 -7
  85. package/dist/{types-B3SGRW0w.d.cts → types-CZtAueri.d.cts} +1 -1
  86. package/dist/{types-CH7NWqVL.d.ts → types-RzkCXDNV.d.ts} +1 -1
  87. package/dist/ui-tailwind/editor-surface/search-plugin.d.cts +2 -2
  88. package/dist/ui-tailwind/editor-surface/search-plugin.d.ts +2 -2
  89. package/dist/ui-tailwind/editor-surface/search-plugin.js +4 -4
  90. package/dist/ui-tailwind.cjs +451 -650
  91. package/dist/ui-tailwind.d.cts +3 -2
  92. package/dist/ui-tailwind.d.ts +3 -2
  93. package/dist/ui-tailwind.js +7 -7
  94. package/package.json +1 -1
package/dist/tailwind.cjs CHANGED
@@ -876,18 +876,7 @@ function findScrollAnchor(root, options) {
876
876
  offsetWithinBlock: viewportTopFramePx - blockTop
877
877
  };
878
878
  }
879
- }
880
- const rootRect = root.getBoundingClientRect();
881
- const rootTop = rootRect.top;
882
- for (const block of blocks) {
883
- const rect2 = block.getBoundingClientRect();
884
- if (rect2.bottom < rootTop) continue;
885
- const blockId = block.getAttribute("data-block-id");
886
- if (!blockId) continue;
887
- return {
888
- blockId,
889
- offsetWithinBlock: rootTop - rect2.top
890
- };
879
+ return null;
891
880
  }
892
881
  return null;
893
882
  }
@@ -905,17 +894,9 @@ function resolveScrollTopForAnchor(root, anchor, options) {
905
894
  const rect2 = geometry.rects[0];
906
895
  return rect2.topPx + anchor.offsetWithinBlock;
907
896
  }
897
+ return null;
908
898
  }
909
- const selector = `[data-block-id="${cssEscape(anchor.blockId)}"]`;
910
- const block = root.querySelector(selector);
911
- if (!block) return null;
912
- const rootRect = root.getBoundingClientRect();
913
- const blockRect = block.getBoundingClientRect();
914
- const delta = blockRect.top - rootRect.top + anchor.offsetWithinBlock;
915
- return root.scrollTop + delta;
916
- }
917
- function cssEscape(value) {
918
- return value.replace(/[^a-zA-Z0-9_-]/g, (ch) => `\\${ch}`);
899
+ return null;
919
900
  }
920
901
 
921
902
  // src/ui/headless/chrome-registry.ts
@@ -2668,6 +2649,43 @@ function TwToolbar(props) {
2668
2649
  const showPostFormattingDivider = showListActionsInRow || showSpacingActionsInRow || showInsertActionsInRow || showUpdateActionsInRow || showCompactOverflow;
2669
2650
  const zoomLabel = typeof zoomLevel === "number" ? `${zoomLevel}%` : zoomLevel === "pageWidth" ? "Fit width" : "Fit page";
2670
2651
  const showZoomSteppers = responsiveTier === "wide";
2652
+ const bulletedListState = resolveListCommandControl({
2653
+ canEdit,
2654
+ editDisabledReason,
2655
+ callback: props.onToggleBulletedList,
2656
+ availability: getListCommandAvailability(props.activeListReadback, "toggle-bulleted")
2657
+ });
2658
+ const numberedListState = resolveListCommandControl({
2659
+ canEdit,
2660
+ editDisabledReason,
2661
+ callback: props.onToggleNumberedList,
2662
+ availability: getListCommandAvailability(props.activeListReadback, "toggle-numbered")
2663
+ });
2664
+ const outdentState = resolveListCommandControl({
2665
+ canEdit,
2666
+ editDisabledReason,
2667
+ callback: props.onOutdent,
2668
+ availability: getListCommandAvailability(props.activeListReadback, "outdent")
2669
+ });
2670
+ const indentState = resolveListCommandControl({
2671
+ canEdit,
2672
+ editDisabledReason,
2673
+ callback: props.onIndent,
2674
+ availability: getListCommandAvailability(props.activeListReadback, "indent")
2675
+ });
2676
+ const restartNumberingState = resolveListCommandControl({
2677
+ canEdit,
2678
+ editDisabledReason,
2679
+ callback: props.onRestartNumbering,
2680
+ availability: getListCommandAvailability(props.activeListReadback, "restart-numbering")
2681
+ });
2682
+ const continueNumberingState = resolveListCommandControl({
2683
+ canEdit,
2684
+ editDisabledReason,
2685
+ callback: props.onContinueNumbering,
2686
+ availability: getListCommandAvailability(props.activeListReadback, "continue-numbering")
2687
+ });
2688
+ const activeListKind = props.activeListReadback?.listKind;
2671
2689
  return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
2672
2690
  "header",
2673
2691
  {
@@ -2683,7 +2701,7 @@ function TwToolbar(props) {
2683
2701
  },
2684
2702
  className: [
2685
2703
  "shrink-0 rounded-[var(--radius-sm)] border border-[var(--color-border-subtle)]",
2686
- "bg-[var(--color-bg-chrome)] px-2.5",
2704
+ "bg-[var(--color-bg-chrome)] px-2.5 shadow-[var(--shadow-soft)]",
2687
2705
  isCompact ? "flex min-h-10 flex-wrap items-center gap-1.5 py-1.5" : "flex items-center gap-1"
2688
2706
  ].join(" "),
2689
2707
  children: [
@@ -2852,9 +2870,9 @@ function TwToolbar(props) {
2852
2870
  {
2853
2871
  icon: import_lucide_react5.List,
2854
2872
  label: "Bulleted list",
2855
- active: Boolean(props.activeListContext && !props.activeListContext.isOrdered),
2856
- disabled: !canEdit || !props.onToggleBulletedList,
2857
- disabledReason: editDisabledReason,
2873
+ active: activeListKind ? activeListKind === "bulleted" : Boolean(props.activeListContext && !props.activeListContext.isOrdered),
2874
+ disabled: bulletedListState.disabled,
2875
+ disabledReason: bulletedListState.disabledReason,
2858
2876
  onClick: props.onToggleBulletedList
2859
2877
  }
2860
2878
  ),
@@ -2863,9 +2881,9 @@ function TwToolbar(props) {
2863
2881
  {
2864
2882
  icon: import_lucide_react5.Rows3,
2865
2883
  label: "Numbered list",
2866
- active: Boolean(props.activeListContext?.isOrdered),
2867
- disabled: !canEdit || !props.onToggleNumberedList,
2868
- disabledReason: editDisabledReason,
2884
+ active: activeListKind ? activeListKind === "numbered" : Boolean(props.activeListContext?.isOrdered),
2885
+ disabled: numberedListState.disabled,
2886
+ disabledReason: numberedListState.disabledReason,
2869
2887
  onClick: props.onToggleNumberedList
2870
2888
  }
2871
2889
  )
@@ -2876,8 +2894,8 @@ function TwToolbar(props) {
2876
2894
  {
2877
2895
  icon: import_lucide_react5.Outdent,
2878
2896
  label: "Outdent",
2879
- disabled: !canEdit || !props.onOutdent,
2880
- disabledReason: editDisabledReason,
2897
+ disabled: outdentState.disabled,
2898
+ disabledReason: outdentState.disabledReason,
2881
2899
  onClick: props.onOutdent
2882
2900
  }
2883
2901
  ),
@@ -2886,8 +2904,8 @@ function TwToolbar(props) {
2886
2904
  {
2887
2905
  icon: import_lucide_react5.Indent,
2888
2906
  label: "Indent",
2889
- disabled: !canEdit || !props.onIndent,
2890
- disabledReason: editDisabledReason,
2907
+ disabled: indentState.disabled,
2908
+ disabledReason: indentState.disabledReason,
2891
2909
  onClick: props.onIndent
2892
2910
  }
2893
2911
  )
@@ -2897,8 +2915,8 @@ function TwToolbar(props) {
2897
2915
  ToolbarTextButton,
2898
2916
  {
2899
2917
  ariaLabel: "Restart numbering",
2900
- disabled: !canEdit || !props.onRestartNumbering,
2901
- disabledReason: editDisabledReason,
2918
+ disabled: restartNumberingState.disabled,
2919
+ disabledReason: restartNumberingState.disabledReason,
2902
2920
  onClick: props.onRestartNumbering,
2903
2921
  children: "Restart"
2904
2922
  }
@@ -2907,8 +2925,8 @@ function TwToolbar(props) {
2907
2925
  ToolbarTextButton,
2908
2926
  {
2909
2927
  ariaLabel: "Continue numbering",
2910
- disabled: !canEdit || !props.onContinueNumbering,
2911
- disabledReason: editDisabledReason,
2928
+ disabled: continueNumberingState.disabled,
2929
+ disabledReason: continueNumberingState.disabledReason,
2912
2930
  onClick: props.onContinueNumbering,
2913
2931
  children: "Continue"
2914
2932
  }
@@ -2952,6 +2970,7 @@ function TwToolbar(props) {
2952
2970
  ToolbarCompactOverflow,
2953
2971
  {
2954
2972
  activeListContext: props.activeListContext,
2973
+ activeListReadback: props.activeListReadback,
2955
2974
  canEdit,
2956
2975
  canInsertStructural,
2957
2976
  editDisabledReason,
@@ -3485,8 +3504,59 @@ function ToolbarFontSizeSelect(props) {
3485
3504
  }
3486
3505
  );
3487
3506
  }
3507
+ function getListCommandAvailability(readback, command) {
3508
+ return readback?.commandSupport.find((entry) => entry.command === command);
3509
+ }
3510
+ function resolveListCommandControl(input) {
3511
+ if (!input.canEdit) {
3512
+ return { disabled: true, disabledReason: input.editDisabledReason };
3513
+ }
3514
+ if (!input.callback) {
3515
+ return { disabled: true };
3516
+ }
3517
+ if (input.availability?.enabled === false) {
3518
+ return { disabled: true, disabledReason: input.availability.reason };
3519
+ }
3520
+ return { disabled: false };
3521
+ }
3488
3522
  function ToolbarCompactOverflow(props) {
3489
3523
  const [open, setOpen] = import_react4.default.useState(false);
3524
+ const bulletedListState = resolveListCommandControl({
3525
+ canEdit: props.canEdit,
3526
+ editDisabledReason: props.editDisabledReason,
3527
+ callback: props.onToggleBulletedList,
3528
+ availability: getListCommandAvailability(props.activeListReadback, "toggle-bulleted")
3529
+ });
3530
+ const numberedListState = resolveListCommandControl({
3531
+ canEdit: props.canEdit,
3532
+ editDisabledReason: props.editDisabledReason,
3533
+ callback: props.onToggleNumberedList,
3534
+ availability: getListCommandAvailability(props.activeListReadback, "toggle-numbered")
3535
+ });
3536
+ const outdentState = resolveListCommandControl({
3537
+ canEdit: props.canEdit,
3538
+ editDisabledReason: props.editDisabledReason,
3539
+ callback: props.onOutdent,
3540
+ availability: getListCommandAvailability(props.activeListReadback, "outdent")
3541
+ });
3542
+ const indentState = resolveListCommandControl({
3543
+ canEdit: props.canEdit,
3544
+ editDisabledReason: props.editDisabledReason,
3545
+ callback: props.onIndent,
3546
+ availability: getListCommandAvailability(props.activeListReadback, "indent")
3547
+ });
3548
+ const restartNumberingState = resolveListCommandControl({
3549
+ canEdit: props.canEdit,
3550
+ editDisabledReason: props.editDisabledReason,
3551
+ callback: props.onRestartNumbering,
3552
+ availability: getListCommandAvailability(props.activeListReadback, "restart-numbering")
3553
+ });
3554
+ const continueNumberingState = resolveListCommandControl({
3555
+ canEdit: props.canEdit,
3556
+ editDisabledReason: props.editDisabledReason,
3557
+ callback: props.onContinueNumbering,
3558
+ availability: getListCommandAvailability(props.activeListReadback, "continue-numbering")
3559
+ });
3490
3560
  const overflowGroups = [
3491
3561
  props.showStyleSelectors || props.showInlineFormatting || props.showTextColors ? "Format" : null,
3492
3562
  props.showListActions || props.showParagraphActions || props.showParagraphAlignment || props.showListContinuation ? "Paragraph" : null,
@@ -3703,8 +3773,8 @@ function ToolbarCompactOverflow(props) {
3703
3773
  ToolbarMenuButton,
3704
3774
  {
3705
3775
  ariaLabel: "Bulleted list",
3706
- disabled: !props.canEdit || !props.onToggleBulletedList,
3707
- disabledReason: props.editDisabledReason,
3776
+ disabled: bulletedListState.disabled,
3777
+ disabledReason: bulletedListState.disabledReason,
3708
3778
  icon: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_lucide_react5.List, { className: "h-3.5 w-3.5" }),
3709
3779
  label: "Bulleted list",
3710
3780
  onClick: () => {
@@ -3717,8 +3787,8 @@ function ToolbarCompactOverflow(props) {
3717
3787
  ToolbarMenuButton,
3718
3788
  {
3719
3789
  ariaLabel: "Numbered list",
3720
- disabled: !props.canEdit || !props.onToggleNumberedList,
3721
- disabledReason: props.editDisabledReason,
3790
+ disabled: numberedListState.disabled,
3791
+ disabledReason: numberedListState.disabledReason,
3722
3792
  icon: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_lucide_react5.Rows3, { className: "h-3.5 w-3.5" }),
3723
3793
  label: "Numbered list",
3724
3794
  onClick: () => {
@@ -3747,8 +3817,8 @@ function ToolbarCompactOverflow(props) {
3747
3817
  ToolbarMenuButton,
3748
3818
  {
3749
3819
  ariaLabel: "Outdent",
3750
- disabled: !props.canEdit || !props.onOutdent,
3751
- disabledReason: props.editDisabledReason,
3820
+ disabled: outdentState.disabled,
3821
+ disabledReason: outdentState.disabledReason,
3752
3822
  icon: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_lucide_react5.Outdent, { className: "h-3.5 w-3.5" }),
3753
3823
  label: "Outdent",
3754
3824
  onClick: () => {
@@ -3761,8 +3831,8 @@ function ToolbarCompactOverflow(props) {
3761
3831
  ToolbarMenuButton,
3762
3832
  {
3763
3833
  ariaLabel: "Indent",
3764
- disabled: !props.canEdit || !props.onIndent,
3765
- disabledReason: props.editDisabledReason,
3834
+ disabled: indentState.disabled,
3835
+ disabledReason: indentState.disabledReason,
3766
3836
  icon: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_lucide_react5.Indent, { className: "h-3.5 w-3.5" }),
3767
3837
  label: "Indent",
3768
3838
  onClick: () => {
@@ -3777,8 +3847,8 @@ function ToolbarCompactOverflow(props) {
3777
3847
  ToolbarMenuButton,
3778
3848
  {
3779
3849
  ariaLabel: "Restart numbering",
3780
- disabled: !props.canEdit || !props.onRestartNumbering,
3781
- disabledReason: props.editDisabledReason,
3850
+ disabled: restartNumberingState.disabled,
3851
+ disabledReason: restartNumberingState.disabledReason,
3782
3852
  icon: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_lucide_react5.Rows3, { className: "h-3.5 w-3.5" }),
3783
3853
  label: "Restart numbering",
3784
3854
  onClick: () => {
@@ -3791,8 +3861,8 @@ function ToolbarCompactOverflow(props) {
3791
3861
  ToolbarMenuButton,
3792
3862
  {
3793
3863
  ariaLabel: "Continue numbering",
3794
- disabled: !props.canEdit || !props.onContinueNumbering,
3795
- disabledReason: props.editDisabledReason,
3864
+ disabled: continueNumberingState.disabled,
3865
+ disabledReason: continueNumberingState.disabledReason,
3796
3866
  icon: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_lucide_react5.Rows3, { className: "h-3.5 w-3.5" }),
3797
3867
  label: "Continue numbering",
3798
3868
  onClick: () => {
@@ -9131,7 +9201,20 @@ function sourceJoinHash(refs) {
9131
9201
  if (sourceIds.length === 0) return void 0;
9132
9202
  return hashText(sourceIds.join("\0"));
9133
9203
  }
9204
+ var numberingCatalogHashCache = /* @__PURE__ */ new WeakMap();
9205
+ var numberingTargetHashCache = /* @__PURE__ */ new WeakMap();
9134
9206
  function createNumberingCatalogRevisionHash(doc) {
9207
+ const numbering = doc.numbering;
9208
+ if (numbering !== void 0) {
9209
+ const cached = numberingCatalogHashCache.get(numbering);
9210
+ if (cached !== void 0) return cached;
9211
+ const fresh = computeNumberingCatalogRevisionHash(doc);
9212
+ numberingCatalogHashCache.set(numbering, fresh);
9213
+ return fresh;
9214
+ }
9215
+ return computeNumberingCatalogRevisionHash(doc);
9216
+ }
9217
+ function computeNumberingCatalogRevisionHash(doc) {
9135
9218
  const catalog = doc.numbering ?? { abstractDefinitions: {}, instances: {} };
9136
9219
  const abstractDefinitions = catalog.abstractDefinitions ?? {};
9137
9220
  const instances = catalog.instances ?? {};
@@ -9182,8 +9265,27 @@ function createNumberingCatalogRevisionHash(doc) {
9182
9265
  }));
9183
9266
  }
9184
9267
  function createNumberingTargetRevisionHash(doc) {
9268
+ const numbering = doc.numbering;
9269
+ const styles = doc.styles;
9270
+ if (numbering !== void 0 && styles !== void 0) {
9271
+ let inner = numberingTargetHashCache.get(numbering);
9272
+ if (inner === void 0) {
9273
+ inner = /* @__PURE__ */ new WeakMap();
9274
+ numberingTargetHashCache.set(numbering, inner);
9275
+ }
9276
+ const cached = inner.get(styles);
9277
+ if (cached !== void 0) return cached;
9278
+ const fresh = computeNumberingTargetRevisionHash(doc);
9279
+ inner.set(styles, fresh);
9280
+ return fresh;
9281
+ }
9282
+ return computeNumberingTargetRevisionHash(doc);
9283
+ }
9284
+ function computeNumberingTargetRevisionHash(doc) {
9185
9285
  const paragraphStyles = doc.styles?.paragraphs ?? {};
9186
9286
  return hashText(JSON.stringify({
9287
+ // Reuses the memoized catalog hash on the hot path so a typing edit
9288
+ // pays for the catalog hash at most once across both helpers.
9187
9289
  numberingCatalogHash: createNumberingCatalogRevisionHash(doc),
9188
9290
  paragraphStyleNumbering: Object.keys(paragraphStyles).sort().map((styleId) => {
9189
9291
  const style = paragraphStyles[styleId];
@@ -12675,6 +12777,7 @@ var PICTURE_EFFECT_SCHEME_ALIASES = {
12675
12777
  bg2: "lt2"
12676
12778
  };
12677
12779
  var EMPTY_EDITABLE_TARGETS_BY_BLOCK_PATH = /* @__PURE__ */ new Map();
12780
+ var NO_EDITABLE_TARGETS_INDEX = EMPTY_EDITABLE_TARGETS_BY_BLOCK_PATH;
12678
12781
  function indexEditableTargetsByBlockPath(document2) {
12679
12782
  const targets = collectEditableTargetRefs(document2);
12680
12783
  if (targets.length === 0) return EMPTY_EDITABLE_TARGETS_BY_BLOCK_PATH;
@@ -14891,7 +14994,8 @@ function buildResolvedSections(document2) {
14891
14994
  const mainSurface = createEditorSurfaceSnapshot(
14892
14995
  document2,
14893
14996
  createSelectionSnapshot(0, 0),
14894
- MAIN_STORY_TARGET
14997
+ MAIN_STORY_TARGET,
14998
+ { editableTargetsByBlockPath: NO_EDITABLE_TARGETS_INDEX }
14895
14999
  );
14896
15000
  const sections = [];
14897
15001
  let sectionStart = 0;
@@ -20368,7 +20472,7 @@ function fnv1a2(input) {
20368
20472
  }
20369
20473
 
20370
20474
  // src/runtime/layout/layout-engine-version.ts
20371
- var LAYOUT_ENGINE_VERSION = 93;
20475
+ var LAYOUT_ENGINE_VERSION = 94;
20372
20476
 
20373
20477
  // src/runtime/layout/layout-engine-instance.ts
20374
20478
  var FULL_VIEWPORT_WINDOW_KEY = "full";
@@ -20594,11 +20698,45 @@ function createLayoutEngine(options = {}) {
20594
20698
  const telemetryBus = options.telemetryBus;
20595
20699
  const dirtyFieldFamilies = /* @__PURE__ */ new Set();
20596
20700
  const listeners = /* @__PURE__ */ new Set();
20597
- let cachedKey = null;
20598
- let cachedGraph = null;
20599
- let cachedFormatting = null;
20600
- let cachedMapper = null;
20701
+ let cachedFull = null;
20702
+ let cachedWindowed = null;
20601
20703
  let previousPageCount = 0;
20704
+ function isFullViewportKey(key) {
20705
+ return key === FULL_VIEWPORT_WINDOW_KEY;
20706
+ }
20707
+ function getCachedSlot(viewportWindowKeyValue) {
20708
+ return isFullViewportKey(viewportWindowKeyValue) ? cachedFull : cachedWindowed;
20709
+ }
20710
+ function preferredCachedGraph() {
20711
+ return cachedFull?.graph ?? cachedWindowed?.graph ?? null;
20712
+ }
20713
+ function clearAllSlots() {
20714
+ cachedFull = null;
20715
+ cachedWindowed = null;
20716
+ }
20717
+ function clearWindowedSlot() {
20718
+ cachedWindowed = null;
20719
+ }
20720
+ function evictStaleSiblingSlot(freshKey) {
20721
+ const sibling = isFullViewportKey(freshKey.viewportWindowKey) ? cachedWindowed : cachedFull;
20722
+ if (sibling === null) return;
20723
+ if (sibling.key.content === freshKey.content && sibling.key.styles === freshKey.styles && sibling.key.subParts === freshKey.subParts) {
20724
+ return;
20725
+ }
20726
+ if (isFullViewportKey(freshKey.viewportWindowKey)) {
20727
+ cachedWindowed = null;
20728
+ } else {
20729
+ cachedFull = null;
20730
+ }
20731
+ }
20732
+ function commitSlot(slot) {
20733
+ if (isFullViewportKey(slot.key.viewportWindowKey)) {
20734
+ cachedFull = slot;
20735
+ } else {
20736
+ cachedWindowed = slot;
20737
+ }
20738
+ evictStaleSiblingSlot(slot.key);
20739
+ }
20602
20740
  let pendingInvalidation = null;
20603
20741
  function emit(event) {
20604
20742
  for (const listener of listeners) {
@@ -20744,27 +20882,31 @@ function createLayoutEngine(options = {}) {
20744
20882
  subParts: document2.subParts,
20745
20883
  anchors: layoutInputs.anchors
20746
20884
  });
20885
+ const priorGraphForMaterialization = preferredCachedGraph();
20747
20886
  const graph = applyViewportWindowMaterialization(
20748
20887
  measuredGraph,
20749
20888
  viewportWindow,
20750
- cachedGraph
20889
+ priorGraphForMaterialization
20751
20890
  );
20752
- const dirtyFamilies = computeFieldDirtiness(cachedGraph, graph);
20891
+ const priorGraphForFieldDirtiness = preferredCachedGraph();
20892
+ const dirtyFamilies = computeFieldDirtiness(priorGraphForFieldDirtiness, graph);
20753
20893
  for (const family of dirtyFamilies) {
20754
20894
  dirtyFieldFamilies.add(family);
20755
20895
  }
20756
20896
  const formatting = buildResolvedFormattingState(document2, mainSurface);
20757
20897
  const currentPageCount = graph.contentPageCount;
20758
20898
  const pageCountDelta = currentPageCount !== previousPageCount ? { previous: previousPageCount, current: currentPageCount } : void 0;
20759
- cachedKey = {
20760
- content: document2.content,
20761
- styles: document2.styles,
20762
- subParts: document2.subParts,
20763
- viewportWindowKey: viewportWindowKey(viewportWindow)
20764
- };
20765
- cachedGraph = graph;
20766
- cachedFormatting = formatting;
20767
- cachedMapper = createPageFragmentMapper(graph);
20899
+ commitSlot({
20900
+ key: {
20901
+ content: document2.content,
20902
+ styles: document2.styles,
20903
+ subParts: document2.subParts,
20904
+ viewportWindowKey: viewportWindowKey(viewportWindow)
20905
+ },
20906
+ graph,
20907
+ formatting,
20908
+ mapper: createPageFragmentMapper(graph)
20909
+ });
20768
20910
  if (pageCountDelta) {
20769
20911
  emit({
20770
20912
  kind: "page_count_changed",
@@ -20805,7 +20947,7 @@ function createLayoutEngine(options = {}) {
20805
20947
  return graph;
20806
20948
  }
20807
20949
  function incrementalRelayout(input, pending) {
20808
- const priorGraph = cachedGraph;
20950
+ const priorGraph = cachedFull?.graph ?? null;
20809
20951
  const range = pending.result.dirtyPageRange;
20810
20952
  if (!priorGraph || !range) return null;
20811
20953
  const telemetryOn = telemetryBus?.isEnabled("layout") ?? false;
@@ -20898,6 +21040,22 @@ function createLayoutEngine(options = {}) {
20898
21040
  deriveDocumentPageSnapshots(splicedGraph)
20899
21041
  );
20900
21042
  const pageCountDelta = currentPageCount !== previousPageCount ? { previous: previousPageCount, current: currentPageCount } : void 0;
21043
+ const priorMapper = cachedFull?.mapper ?? null;
21044
+ commitSlot({
21045
+ key: {
21046
+ content: document2.content,
21047
+ styles: document2.styles,
21048
+ subParts: document2.subParts,
21049
+ viewportWindowKey: FULL_VIEWPORT_WINDOW_KEY
21050
+ },
21051
+ graph: splicedGraph,
21052
+ formatting,
21053
+ mapper: rebuildMapper(
21054
+ priorMapper ?? createPageFragmentMapper(splicedGraph),
21055
+ splicedGraph,
21056
+ firstDirty
21057
+ )
21058
+ });
20901
21059
  if (pageCountDelta) {
20902
21060
  emit({
20903
21061
  kind: "page_count_changed",
@@ -20927,19 +21085,6 @@ function createLayoutEngine(options = {}) {
20927
21085
  ...dirtyFamilies.length > 0 ? { dirtyFieldFamilies: dirtyFamilies } : {},
20928
21086
  ...pageCountDelta ? { pageCountDelta } : {}
20929
21087
  });
20930
- cachedKey = {
20931
- content: document2.content,
20932
- styles: document2.styles,
20933
- subParts: document2.subParts,
20934
- viewportWindowKey: FULL_VIEWPORT_WINDOW_KEY
20935
- };
20936
- cachedGraph = splicedGraph;
20937
- cachedFormatting = formatting;
20938
- cachedMapper = rebuildMapper(
20939
- cachedMapper ?? createPageFragmentMapper(splicedGraph),
20940
- splicedGraph,
20941
- firstDirty
20942
- );
20943
21088
  if (telemetryOn) {
20944
21089
  emitRecomputeCompleted(
20945
21090
  "bounded",
@@ -20956,13 +21101,14 @@ function createLayoutEngine(options = {}) {
20956
21101
  const document2 = input.document;
20957
21102
  const normalizedWindow = normalizeViewportPageWindow(input.viewportPageWindow);
20958
21103
  const currentViewportWindowKey = viewportWindowKey(normalizedWindow);
20959
- const keyEqual = cachedGraph !== null && cachedKey !== null && cachedKey.content === document2.content && cachedKey.styles === document2.styles && cachedKey.subParts === document2.subParts && cachedKey.viewportWindowKey === currentViewportWindowKey;
21104
+ const slot = getCachedSlot(currentViewportWindowKey);
21105
+ const keyEqual = slot !== null && slot.key.content === document2.content && slot.key.styles === document2.styles && slot.key.subParts === document2.subParts && slot.key.viewportWindowKey === currentViewportWindowKey;
20960
21106
  if (keyEqual && pendingInvalidation === null) {
20961
- return cachedGraph;
21107
+ return slot.graph;
20962
21108
  }
20963
21109
  const pending = pendingInvalidation;
20964
21110
  pendingInvalidation = null;
20965
- if (pending !== null && pending.result.scope === "bounded" && cachedGraph !== null && normalizedWindow === void 0) {
21111
+ if (pending !== null && pending.result.scope === "bounded" && cachedFull !== null && normalizedWindow === void 0) {
20966
21112
  const spliced = incrementalRelayout(input, pending);
20967
21113
  if (spliced !== null) {
20968
21114
  return spliced;
@@ -20971,16 +21117,39 @@ function createLayoutEngine(options = {}) {
20971
21117
  }
20972
21118
  return fullRebuild(input, pending?.reason);
20973
21119
  }
21120
+ function ensureSlotMapperAndFormatting(slot, document2) {
21121
+ if (slot.mapper === null) {
21122
+ slot.mapper = createPageFragmentMapper(slot.graph);
21123
+ }
21124
+ if (slot.formatting === null) {
21125
+ const mainSurface = createEditorSurfaceSnapshot(
21126
+ document2,
21127
+ createSelectionSnapshot(0, 0),
21128
+ MAIN_STORY_TARGET
21129
+ );
21130
+ slot.formatting = buildResolvedFormattingState(document2, mainSurface);
21131
+ }
21132
+ }
20974
21133
  function getMapper(input) {
20975
21134
  getGraphInternal(input);
20976
- return cachedMapper;
21135
+ const currentViewportWindowKey = viewportWindowKey(
21136
+ normalizeViewportPageWindow(input.viewportPageWindow)
21137
+ );
21138
+ const slot = getCachedSlot(currentViewportWindowKey);
21139
+ ensureSlotMapperAndFormatting(slot, input.document);
21140
+ return slot.mapper;
20977
21141
  }
20978
21142
  function getFormatting(input) {
20979
21143
  getGraphInternal(input);
20980
- return cachedFormatting;
21144
+ const currentViewportWindowKey = viewportWindowKey(
21145
+ normalizeViewportPageWindow(input.viewportPageWindow)
21146
+ );
21147
+ const slot = getCachedSlot(currentViewportWindowKey);
21148
+ ensureSlotMapperAndFormatting(slot, input.document);
21149
+ return slot.formatting;
20981
21150
  }
20982
21151
  if (autoUpgradeToCanvas && options.measurementProvider === void 0 && typeof document !== "undefined" && typeof HTMLCanvasElement !== "undefined") {
20983
- const readCachedRevision = () => cachedGraph?.revision ?? 0;
21152
+ const readCachedRevision = () => preferredCachedGraph()?.revision ?? 0;
20984
21153
  void (async () => {
20985
21154
  try {
20986
21155
  const mod = await Promise.resolve().then(() => (init_measurement_backend_canvas(), measurement_backend_canvas_exports));
@@ -20990,10 +21159,7 @@ function createLayoutEngine(options = {}) {
20990
21159
  options.measurementCache,
20991
21160
  telemetryBus
20992
21161
  );
20993
- cachedKey = null;
20994
- cachedGraph = null;
20995
- cachedFormatting = null;
20996
- cachedMapper = null;
21162
+ clearAllSlots();
20997
21163
  emit({
20998
21164
  kind: "measurement_backend_ready",
20999
21165
  revision: readCachedRevision(),
@@ -21037,22 +21203,19 @@ function createLayoutEngine(options = {}) {
21037
21203
  return getMapper(input);
21038
21204
  },
21039
21205
  invalidate(reason) {
21040
- const result = analyzeInvalidation(reason, cachedGraph);
21206
+ const result = analyzeInvalidation(reason, preferredCachedGraph());
21041
21207
  for (const family of result.dirtyFieldFamilies) {
21042
21208
  dirtyFieldFamilies.add(family);
21043
21209
  }
21044
21210
  if (result.scope === "bounded") {
21045
21211
  pendingInvalidation = { reason, result };
21046
21212
  } else {
21047
- cachedKey = null;
21048
- cachedGraph = null;
21049
- cachedFormatting = null;
21050
- cachedMapper = null;
21213
+ clearAllSlots();
21051
21214
  pendingInvalidation = { reason, result };
21052
21215
  }
21053
21216
  },
21054
21217
  analyzeInvalidation(reason) {
21055
- return analyzeInvalidation(reason, cachedGraph);
21218
+ return analyzeInvalidation(reason, preferredCachedGraph());
21056
21219
  },
21057
21220
  getDirtyFieldFamilies() {
21058
21221
  return Array.from(dirtyFieldFamilies);
@@ -21080,14 +21243,11 @@ function createLayoutEngine(options = {}) {
21080
21243
  telemetryBus
21081
21244
  );
21082
21245
  if (previousFidelity !== provider.fidelity) {
21083
- cachedKey = null;
21084
- cachedGraph = null;
21085
- cachedFormatting = null;
21086
- cachedMapper = null;
21246
+ clearAllSlots();
21087
21247
  }
21088
21248
  emit({
21089
21249
  kind: "measurement_backend_ready",
21090
- revision: cachedGraph?.revision ?? 0,
21250
+ revision: preferredCachedGraph()?.revision ?? 0,
21091
21251
  fidelity: provider.fidelity
21092
21252
  });
21093
21253
  },
@@ -21102,30 +21262,33 @@ function createLayoutEngine(options = {}) {
21102
21262
  */
21103
21263
  invalidateMeasurementCache() {
21104
21264
  measurementProvider.invalidateCache();
21105
- cachedKey = null;
21106
- cachedGraph = null;
21107
- cachedFormatting = null;
21108
- cachedMapper = null;
21265
+ clearAllSlots();
21109
21266
  },
21110
21267
  getMeasurementCacheStats() {
21111
21268
  if (!isCachedLayoutMeasurementProvider(measurementProvider)) return null;
21112
21269
  return measurementProvider.measurementCacheStats();
21113
21270
  },
21114
21271
  /**
21115
- * L7 Phase 2.5 — seed the cached graph from a prerender envelope.
21116
- * Populates both `cachedGraph` and `cachedKey` (keyed on the provided
21117
- * document's identity-equal slots) so the next getPageGraph query
21118
- * returns the seeded graph directly. Any subsequent mutation
21119
- * invalidates normally through the existing path.
21272
+ * L7 Phase 2.5 — seed the full-slot cached graph from a prerender
21273
+ * envelope. Populates the full slot (graph + key, with formatting and
21274
+ * mapper computed lazily on first read) so the next viewport-
21275
+ * independent `getPageGraph` query returns the seeded graph directly.
21276
+ * Any subsequent mutation invalidates normally through the existing
21277
+ * path; sibling eviction in `commitSlot` clears `cachedWindowed` if
21278
+ * it carried a different document tuple.
21120
21279
  */
21121
21280
  seedCachedGraph(graph, document2) {
21122
- cachedGraph = graph;
21123
- cachedKey = {
21124
- content: document2.content,
21125
- styles: document2.styles,
21126
- subParts: document2.subParts,
21127
- viewportWindowKey: FULL_VIEWPORT_WINDOW_KEY
21128
- };
21281
+ commitSlot({
21282
+ key: {
21283
+ content: document2.content,
21284
+ styles: document2.styles,
21285
+ subParts: document2.subParts,
21286
+ viewportWindowKey: FULL_VIEWPORT_WINDOW_KEY
21287
+ },
21288
+ graph,
21289
+ formatting: null,
21290
+ mapper: null
21291
+ });
21129
21292
  previousPageCount = graph.contentPageCount;
21130
21293
  }
21131
21294
  };
@@ -22032,7 +22195,17 @@ function TwSelectionToolStructure(props) {
22032
22195
  onSetCellVerticalAlign: props.onSetCellVerticalAlign
22033
22196
  }
22034
22197
  );
22035
- case "list":
22198
+ case "list": {
22199
+ const continueState = resolveListToolbarButtonState({
22200
+ canMutate: props.model.canMutate,
22201
+ callback: props.onContinueNumbering,
22202
+ availability: getListCommandAvailability2(props.activeListReadback, "continue-numbering")
22203
+ });
22204
+ const restartState = resolveListToolbarButtonState({
22205
+ canMutate: props.model.canMutate,
22206
+ callback: props.onRestartNumbering,
22207
+ availability: getListCommandAvailability2(props.activeListReadback, "restart-numbering")
22208
+ });
22036
22209
  return /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(
22037
22210
  "div",
22038
22211
  {
@@ -22044,7 +22217,8 @@ function TwSelectionToolStructure(props) {
22044
22217
  ToolbarButton3,
22045
22218
  {
22046
22219
  ariaLabel: "Continue numbering",
22047
- disabled: !props.model.canMutate || !props.onContinueNumbering,
22220
+ disabled: continueState.disabled,
22221
+ disabledReason: continueState.disabledReason,
22048
22222
  onClick: props.onContinueNumbering,
22049
22223
  children: "Continue"
22050
22224
  }
@@ -22053,7 +22227,8 @@ function TwSelectionToolStructure(props) {
22053
22227
  ToolbarButton3,
22054
22228
  {
22055
22229
  ariaLabel: "Restart numbering",
22056
- disabled: !props.model.canMutate || !props.onRestartNumbering,
22230
+ disabled: restartState.disabled,
22231
+ disabledReason: restartState.disabledReason,
22057
22232
  onClick: props.onRestartNumbering,
22058
22233
  children: "Restart"
22059
22234
  }
@@ -22061,15 +22236,31 @@ function TwSelectionToolStructure(props) {
22061
22236
  ]
22062
22237
  }
22063
22238
  );
22239
+ }
22240
+ }
22241
+ }
22242
+ function getListCommandAvailability2(readback, command) {
22243
+ return readback?.commandSupport.find((entry) => entry.command === command);
22244
+ }
22245
+ function resolveListToolbarButtonState(input) {
22246
+ if (!input.canMutate || !input.callback) {
22247
+ return { disabled: true };
22064
22248
  }
22249
+ if (input.availability?.enabled === false) {
22250
+ return { disabled: true, disabledReason: input.availability.reason };
22251
+ }
22252
+ return { disabled: false };
22065
22253
  }
22066
22254
  function ToolbarButton3(props) {
22255
+ const disabledReason = props.disabled && props.disabledReason ? props.disabledReason : void 0;
22067
22256
  return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
22068
22257
  "button",
22069
22258
  {
22070
22259
  type: "button",
22071
22260
  "aria-label": props.ariaLabel,
22072
22261
  disabled: props.disabled,
22262
+ "data-disabled-reason": disabledReason,
22263
+ title: disabledReason ? `Not available: ${disabledReason}` : void 0,
22073
22264
  onMouseDown: preserveEditorSelectionMouseDown,
22074
22265
  onClick: props.onClick,
22075
22266
  className: "inline-flex h-7 items-center rounded-md border border-border px-2 text-[length:var(--text-xs)] font-medium text-secondary transition-colors hover:bg-surface disabled:cursor-not-allowed disabled:opacity-40",
@@ -22458,6 +22649,7 @@ function renderTool(props, tool, density) {
22458
22649
  onSetImageFrame: props.onSetImageFrame,
22459
22650
  onRestartNumbering: props.onRestartNumbering,
22460
22651
  onContinueNumbering: props.onContinueNumbering,
22652
+ activeListReadback: props.activeListReadback,
22461
22653
  onToggleRowHeader: props.onToggleRowHeader,
22462
22654
  onToggleRowCantSplit: props.onToggleRowCantSplit,
22463
22655
  onDistributeColumnsEvenly: props.onDistributeColumnsEvenly,
@@ -24419,6 +24611,7 @@ var EDITOR_ACTION_REGISTRY = [
24419
24611
  group: "clipboard",
24420
24612
  targetKinds: [
24421
24613
  "plain-text",
24614
+ "list-item",
24422
24615
  "table-cell",
24423
24616
  "image",
24424
24617
  "hyperlink",
@@ -24437,9 +24630,11 @@ var EDITOR_ACTION_REGISTRY = [
24437
24630
  group: "clipboard",
24438
24631
  targetKinds: [
24439
24632
  "plain-text",
24633
+ "list-item",
24440
24634
  "table-cell",
24441
24635
  "image",
24442
24636
  "hyperlink",
24637
+ "generated-field",
24443
24638
  "suggestion",
24444
24639
  "comment-anchor",
24445
24640
  "opaque-block",
@@ -24454,6 +24649,7 @@ var EDITOR_ACTION_REGISTRY = [
24454
24649
  group: "clipboard",
24455
24650
  targetKinds: [
24456
24651
  "plain-text",
24652
+ "list-item",
24457
24653
  "table-cell",
24458
24654
  "hyperlink",
24459
24655
  "suggestion",
@@ -24614,28 +24810,28 @@ var EDITOR_ACTION_REGISTRY = [
24614
24810
  id: "list-bulleted",
24615
24811
  label: "Bulleted list",
24616
24812
  group: "formatting",
24617
- targetKinds: ["plain-text", "table-cell"],
24813
+ targetKinds: ["list-item", "plain-text", "table-cell"],
24618
24814
  callback: "onToggleBulletedList"
24619
24815
  }),
24620
24816
  mk({
24621
24817
  id: "list-numbered",
24622
24818
  label: "Numbered list",
24623
24819
  group: "formatting",
24624
- targetKinds: ["plain-text", "table-cell"],
24820
+ targetKinds: ["list-item", "plain-text", "table-cell"],
24625
24821
  callback: "onToggleNumberedList"
24626
24822
  }),
24627
24823
  mk({
24628
24824
  id: "paragraph-outdent",
24629
24825
  label: "Decrease indent",
24630
24826
  group: "formatting",
24631
- targetKinds: ["plain-text", "table-cell"],
24827
+ targetKinds: ["list-item", "plain-text", "table-cell"],
24632
24828
  callback: "onOutdent"
24633
24829
  }),
24634
24830
  mk({
24635
24831
  id: "paragraph-indent",
24636
24832
  label: "Increase indent",
24637
24833
  group: "formatting",
24638
- targetKinds: ["plain-text", "table-cell"],
24834
+ targetKinds: ["list-item", "plain-text", "table-cell"],
24639
24835
  callback: "onIndent"
24640
24836
  }),
24641
24837
  mkArg({
@@ -24984,6 +25180,23 @@ var EDITOR_ACTION_REGISTRY = [
24984
25180
  targetKinds: ["hyperlink"],
24985
25181
  callback: "onOpenHyperlink"
24986
25182
  }),
25183
+ // -------- Generated fields --------
25184
+ mk({
25185
+ id: "field-refresh",
25186
+ label: "Refresh field",
25187
+ description: "Refresh generated field results through the runtime field updater.",
25188
+ group: "misc",
25189
+ targetKinds: ["generated-field"],
25190
+ callback: "onUpdateFields"
25191
+ }),
25192
+ mk({
25193
+ id: "toc-refresh",
25194
+ label: "Refresh table of contents",
25195
+ description: "Refresh TOC entries through the runtime table-of-contents updater.",
25196
+ group: "misc",
25197
+ targetKinds: ["toc-field"],
25198
+ callback: "onUpdateTableOfContents"
25199
+ }),
24987
25200
  // -------- Workflow scope --------
24988
25201
  mk({
24989
25202
  id: "scope-open-card",
@@ -25877,13 +26090,40 @@ function hasAncestorAttributeValue(el, attribute, expected, root) {
25877
26090
  }
25878
26091
  return false;
25879
26092
  }
26093
+ function hasAncestorAttributeValueInsensitive(el, attribute, expected, root) {
26094
+ const normalizedExpected = expected.toLowerCase();
26095
+ let cursor = el;
26096
+ while (cursor) {
26097
+ if (cursor.getAttribute?.(attribute)?.toLowerCase() === normalizedExpected) {
26098
+ return true;
26099
+ }
26100
+ if (cursor === root) return false;
26101
+ cursor = cursor.parentElement;
26102
+ }
26103
+ return false;
26104
+ }
25880
26105
  function resolveTargetKind(target, options = {}) {
25881
26106
  const kinds = [];
25882
26107
  const el = toElement(target);
25883
26108
  if (el) {
25884
26109
  const { root } = options;
26110
+ const insideNumberingMarker = hasAncestorAttributeValue(
26111
+ el,
26112
+ "data-numbering-marker",
26113
+ "true",
26114
+ root
26115
+ );
26116
+ const insideListItem = insideNumberingMarker || hasAncestorAttributeValue(el, "data-numbered", "true", root);
26117
+ const insideGeneratedField = hasAncestorAttributeValue(el, "data-generated-field", "true", root) || hasAncestorAttributeValue(el, "data-node-type", "field_ref_atom", root) || hasAncestorAttributeValue(el, "data-node-type", "field_ref", root);
26118
+ if (insideListItem) kinds.push("list-item");
26119
+ if (insideGeneratedField) {
26120
+ kinds.push("generated-field");
26121
+ if (hasAncestorAttributeValueInsensitive(el, "data-field-family", "TOC", root)) {
26122
+ kinds.push("toc-field");
26123
+ }
26124
+ }
25885
26125
  if (hasAncestorTag(el, "a", root)) kinds.push("hyperlink");
25886
- if (hasAncestorTag(el, "img", root)) {
26126
+ if (!insideNumberingMarker && hasAncestorTag(el, "img", root)) {
25887
26127
  kinds.push("image");
25888
26128
  }
25889
26129
  if (hasAncestorTag(el, "td", root) || hasAncestorTag(el, "th", root)) {
@@ -25919,7 +26159,9 @@ function resolveTargetKind(target, options = {}) {
25919
26159
  if (!kinds.includes("template-slot")) kinds.push("template-slot");
25920
26160
  }
25921
26161
  }
25922
- if (!kinds.includes("plain-text")) kinds.push("plain-text");
26162
+ if (!kinds.includes("generated-field") && !kinds.includes("plain-text")) {
26163
+ kinds.push("plain-text");
26164
+ }
25923
26165
  return kinds;
25924
26166
  }
25925
26167
 
@@ -27001,294 +27243,6 @@ function resolveSkeletalPageOverlayRectsFromLayout(facet) {
27001
27243
  }
27002
27244
  return rects;
27003
27245
  }
27004
- function pageOverlayLastBottom(rects) {
27005
- let bottom = 0;
27006
- for (const rect2 of rects) {
27007
- if (rect2.bottomPx > bottom) bottom = rect2.bottomPx;
27008
- }
27009
- return bottom;
27010
- }
27011
- function extendFinalPageOverlayRectToFlowHeight(rects, flowHeightPx) {
27012
- if (rects.length === 0 || !Number.isFinite(flowHeightPx)) return rects;
27013
- const last = rects[rects.length - 1];
27014
- if (flowHeightPx <= last.bottomPx + 1) return rects;
27015
- return [
27016
- ...rects.slice(0, -1),
27017
- {
27018
- ...last,
27019
- bottomPx: flowHeightPx,
27020
- heightPx: Math.max(0, flowHeightPx - last.topPx)
27021
- }
27022
- ];
27023
- }
27024
- function extendPageOverlayRectsAcrossTableBoundaryGaps(rects, tableBoundaryIndices) {
27025
- if (rects.length === 0 || tableBoundaryIndices.length === 0) return rects;
27026
- const tableBoundaries = new Set(tableBoundaryIndices);
27027
- const byPageIndex = /* @__PURE__ */ new Map();
27028
- for (const rect2 of rects) {
27029
- byPageIndex.set(rect2.pageIndex, rect2);
27030
- }
27031
- let changed = false;
27032
- const bridged = rects.map((rect2) => {
27033
- if (!tableBoundaries.has(rect2.pageIndex)) return rect2;
27034
- const next = byPageIndex.get(rect2.pageIndex + 1);
27035
- if (!next || next.topPx <= rect2.bottomPx + 1) return rect2;
27036
- changed = true;
27037
- return {
27038
- ...rect2,
27039
- bottomPx: next.topPx,
27040
- heightPx: Math.max(0, next.topPx - rect2.topPx)
27041
- };
27042
- });
27043
- return changed ? bridged : rects;
27044
- }
27045
- function mergePageOverlayRectsByPageIndex(baseRects, flowRects) {
27046
- if (baseRects.length === 0 || flowRects.length === 0) return baseRects;
27047
- const flowByIndex = /* @__PURE__ */ new Map();
27048
- for (const rect2 of flowRects) {
27049
- flowByIndex.set(rect2.pageIndex, rect2);
27050
- }
27051
- return baseRects.map((rect2) => flowByIndex.get(rect2.pageIndex) ?? rect2);
27052
- }
27053
- function normalizeVisiblePageIndexRange(range, pageCount) {
27054
- if (!range || pageCount <= 0) return null;
27055
- const start = Math.max(0, Math.min(range.start, pageCount));
27056
- const end = Math.max(start, Math.min(range.end, pageCount));
27057
- if (start >= end) return null;
27058
- return { start, end };
27059
- }
27060
- function collectBoundaryIndicesForVisibleRange(range, pageCount) {
27061
- if (pageCount <= 1) return [];
27062
- const startBoundaryIndex = Math.max(0, range.start - 1);
27063
- const endBoundaryIndex = Math.min(pageCount - 2, range.end - 1);
27064
- if (startBoundaryIndex > endBoundaryIndex) return [];
27065
- const indices = [];
27066
- for (let index = startBoundaryIndex; index <= endBoundaryIndex; index += 1) {
27067
- indices.push(index);
27068
- }
27069
- return indices;
27070
- }
27071
- function parsePageBoundaryIndex(prevPageId) {
27072
- const match = /^page-(\d+)$/.exec(prevPageId);
27073
- if (!match) return void 0;
27074
- return Number.parseInt(match[1] ?? "", 10);
27075
- }
27076
- function collectTableEmbeddedBoundaryIndices(queryRoot) {
27077
- if (!queryRoot) return [];
27078
- const indices = [];
27079
- const widgets = Array.from(
27080
- queryRoot.querySelectorAll("[data-page-frame-end]")
27081
- );
27082
- for (const widget of widgets) {
27083
- const prevPageId = widget.getAttribute("data-page-frame-end");
27084
- if (!prevPageId) continue;
27085
- const boundaryIndex = parsePageBoundaryIndex(prevPageId);
27086
- if (boundaryIndex === void 0) continue;
27087
- if (widget.closest("[data-pm-table-root='true'], table")) {
27088
- indices.push(boundaryIndex);
27089
- }
27090
- }
27091
- return indices;
27092
- }
27093
- function containsTableBoundaryRisk(queryRoot) {
27094
- if (!queryRoot) return false;
27095
- if (queryRoot.getElementsByTagName("table").length > 0) return true;
27096
- const descendants = queryRoot.getElementsByTagName("*");
27097
- for (let i = 0; i < descendants.length; i += 1) {
27098
- const element = descendants[i];
27099
- if (element.getAttribute("data-pm-table-root") === "true") {
27100
- return true;
27101
- }
27102
- }
27103
- return false;
27104
- }
27105
- function resolvePageOverlayRects(input, legacyPageCount) {
27106
- let widgets;
27107
- let pageCount;
27108
- let scrollHeight;
27109
- if (Array.isArray(input)) {
27110
- const [scrollRoot, count] = input;
27111
- if (!scrollRoot || count <= 0) return [];
27112
- widgets = measureWidgetsViaOffsetChain(scrollRoot);
27113
- pageCount = count;
27114
- scrollHeight = scrollRoot.clientHeight;
27115
- } else if (input !== null && typeof input === "object" && "widgets" in input) {
27116
- widgets = input.widgets;
27117
- pageCount = input.pageCount;
27118
- scrollHeight = input.scrollHeight;
27119
- } else if (input && legacyPageCount !== void 0) {
27120
- const scrollRoot = input;
27121
- if (legacyPageCount <= 0) return [];
27122
- widgets = measureWidgetsViaOffsetChain(scrollRoot);
27123
- pageCount = legacyPageCount;
27124
- scrollHeight = scrollRoot.clientHeight;
27125
- } else {
27126
- return [];
27127
- }
27128
- if (pageCount <= 0) return [];
27129
- const boundaries = [...widgets].sort((a, b) => a.topPx - b.topPx);
27130
- const normalizedVisiblePageIndexRange = Array.isArray(input) ? null : normalizeVisiblePageIndexRange(input.visiblePageIndexRange, pageCount);
27131
- const boundaryByIndex = /* @__PURE__ */ new Map();
27132
- boundaries.forEach((boundary, index) => {
27133
- const boundaryIndex = boundary.boundaryIndex ?? parsePageBoundaryIndex(boundary.prevPageId) ?? index;
27134
- boundaryByIndex.set(boundaryIndex, boundary);
27135
- });
27136
- const pageStart = normalizedVisiblePageIndexRange?.start ?? 0;
27137
- const pageEnd = normalizedVisiblePageIndexRange?.end ?? pageCount;
27138
- const rects = [];
27139
- for (let pageIndex = pageStart; pageIndex < pageEnd; pageIndex += 1) {
27140
- const boundaryBefore = pageIndex === 0 ? null : boundaryByIndex.get(pageIndex - 1) ?? null;
27141
- const boundaryAfter = pageIndex === pageCount - 1 ? null : boundaryByIndex.get(pageIndex) ?? null;
27142
- let pageId = null;
27143
- if (boundaryBefore) pageId = boundaryBefore.nextPageId;
27144
- else if (boundaryAfter) pageId = boundaryAfter.prevPageId;
27145
- if (!pageId) pageId = `page-${pageIndex}`;
27146
- const topPx = boundaryBefore ? boundaryBefore.bottomPx : 0;
27147
- const bottomPx = boundaryAfter ? boundaryAfter.topPx : scrollHeight;
27148
- if (bottomPx <= topPx) continue;
27149
- rects.push({
27150
- pageId,
27151
- pageIndex,
27152
- topPx,
27153
- bottomPx,
27154
- heightPx: bottomPx - topPx
27155
- });
27156
- }
27157
- return rects;
27158
- }
27159
- function measureWidgetsViaBoundingRect(queryRoot, originElement, options) {
27160
- if (!queryRoot || !originElement) return [];
27161
- const originRect = originElement.getBoundingClientRect();
27162
- const normalizedVisiblePageIndexRange = normalizeVisiblePageIndexRange(
27163
- options?.visiblePageIndexRange,
27164
- options?.pageCount ?? 0
27165
- );
27166
- const queryOne = typeof queryRoot.querySelector === "function" ? queryRoot.querySelector.bind(queryRoot) : null;
27167
- const widgets = normalizedVisiblePageIndexRange && queryOne && options?.pageCount ? collectBoundaryIndicesForVisibleRange(
27168
- normalizedVisiblePageIndexRange,
27169
- options.pageCount
27170
- ).map(
27171
- (boundaryIndex) => queryOne(`[data-page-frame-end="page-${boundaryIndex}"]`)
27172
- ).filter((widget) => widget !== null) : Array.from(
27173
- queryRoot.querySelectorAll("[data-page-frame-end]")
27174
- );
27175
- const out = [];
27176
- for (const widget of widgets) {
27177
- const prevPageId = widget.getAttribute("data-page-frame-end");
27178
- const nextPageId = widget.getAttribute("data-page-frame-start");
27179
- if (!prevPageId || !nextPageId) continue;
27180
- const rect2 = widget.getBoundingClientRect();
27181
- out.push({
27182
- prevPageId,
27183
- nextPageId,
27184
- boundaryIndex: parsePageBoundaryIndex(prevPageId),
27185
- topPx: rect2.top - originRect.top,
27186
- bottomPx: rect2.bottom - originRect.top
27187
- });
27188
- }
27189
- return out;
27190
- }
27191
- function measureWidgetsViaOffsetChain(scrollRoot, options) {
27192
- const normalizedVisiblePageIndexRange = normalizeVisiblePageIndexRange(
27193
- options?.visiblePageIndexRange,
27194
- options?.pageCount ?? 0
27195
- );
27196
- const queryOne = typeof scrollRoot.querySelector === "function" ? scrollRoot.querySelector.bind(scrollRoot) : null;
27197
- const widgets = normalizedVisiblePageIndexRange && queryOne && options?.pageCount ? collectBoundaryIndicesForVisibleRange(
27198
- normalizedVisiblePageIndexRange,
27199
- options.pageCount
27200
- ).map(
27201
- (boundaryIndex) => queryOne(`[data-page-frame-end="page-${boundaryIndex}"]`)
27202
- ).filter((widget) => widget !== null) : Array.from(
27203
- scrollRoot.querySelectorAll("[data-page-frame-end]")
27204
- );
27205
- const out = [];
27206
- for (const widget of widgets) {
27207
- const prevPageId = widget.getAttribute("data-page-frame-end");
27208
- const nextPageId = widget.getAttribute("data-page-frame-start");
27209
- if (!prevPageId || !nextPageId) continue;
27210
- const topPx = resolveOffsetTop(widget, scrollRoot);
27211
- const bottomPx = topPx + resolveOffsetHeight(widget);
27212
- out.push({
27213
- prevPageId,
27214
- nextPageId,
27215
- boundaryIndex: parsePageBoundaryIndex(prevPageId),
27216
- topPx,
27217
- bottomPx
27218
- });
27219
- }
27220
- return out;
27221
- }
27222
- function resolveOffsetTop(widget, scrollRoot) {
27223
- let node = widget;
27224
- let top = 0;
27225
- while (node) {
27226
- top += node.offsetTop ?? 0;
27227
- const parent = node.offsetParent;
27228
- if (parent === scrollRoot || parent === null) break;
27229
- node = parent;
27230
- }
27231
- return top;
27232
- }
27233
- function resolveOffsetHeight(widget) {
27234
- return widget.offsetHeight ?? 0;
27235
- }
27236
- function readElementFlowHeight(element, options = {}) {
27237
- if (!element) return 0;
27238
- let height = 0;
27239
- height = Math.max(height, element.clientHeight || 0);
27240
- if (options.includeScrollHeight !== false) {
27241
- height = Math.max(height, element.scrollHeight || 0);
27242
- }
27243
- if (height <= 0) {
27244
- const rect2 = element.getBoundingClientRect();
27245
- height = Math.max(height, rect2.height || 0);
27246
- }
27247
- return height;
27248
- }
27249
- function readOverlayFlowHeight(origin) {
27250
- if (!origin) return 0;
27251
- const parent = origin.parentElement instanceof HTMLElement ? origin.parentElement : null;
27252
- const parentHeight = readElementFlowHeight(parent);
27253
- if (parentHeight > 0) return parentHeight;
27254
- return readElementFlowHeight(origin, { includeScrollHeight: false });
27255
- }
27256
- function reconcilePageStackRectsWithFlow(input) {
27257
- const { baseRects, pageCount, scrollRoot, originElement } = input;
27258
- if (baseRects.length === 0 || pageCount <= 0) return baseRects;
27259
- const flowHeight = readOverlayFlowHeight(originElement);
27260
- if (flowHeight <= 0) return baseRects;
27261
- const geometryBottom = pageOverlayLastBottom(baseRects);
27262
- const tableBoundaryRisk = containsTableBoundaryRisk(scrollRoot);
27263
- if (!tableBoundaryRisk && flowHeight <= geometryBottom + 1) {
27264
- return extendFinalPageOverlayRectToFlowHeight(baseRects, flowHeight);
27265
- }
27266
- const bridgedBase = extendPageOverlayRectsAcrossTableBoundaryGaps(
27267
- baseRects,
27268
- tableBoundaryRisk ? collectTableEmbeddedBoundaryIndices(scrollRoot) : []
27269
- );
27270
- const extendedBase = extendFinalPageOverlayRectToFlowHeight(
27271
- bridgedBase,
27272
- flowHeight
27273
- );
27274
- if (!originElement || !scrollRoot) return extendedBase;
27275
- if (flowHeight <= pageOverlayLastBottom(bridgedBase) + 1) {
27276
- return extendedBase;
27277
- }
27278
- const widgets = measureWidgetsViaBoundingRect(scrollRoot, originElement, {
27279
- pageCount,
27280
- visiblePageIndexRange: null
27281
- });
27282
- if (widgets.length === 0) return extendedBase;
27283
- const flowRects = resolvePageOverlayRects({
27284
- widgets,
27285
- pageCount,
27286
- scrollHeight: flowHeight,
27287
- visiblePageIndexRange: null
27288
- });
27289
- const merged = mergePageOverlayRectsByPageIndex(extendedBase, flowRects);
27290
- return extendFinalPageOverlayRectToFlowHeight(merged, flowHeight);
27291
- }
27292
27246
  var resolvePageOverlayRectsFromGeometry2 = resolvePageOverlayRectsFromGeometry;
27293
27247
  function resolvePageOverlayRectsFromUiApi(ui, pageCount, visiblePageIndexRange, pageIds) {
27294
27248
  if (pageCount <= 0) return [];
@@ -27346,17 +27300,6 @@ var TwPageStackOverlayLayer = ({
27346
27300
  },
27347
27301
  []
27348
27302
  );
27349
- const reconcilePaperRectsWithFlow = React21.useCallback(
27350
- (baseRects, pageCount) => {
27351
- return reconcilePageStackRectsWithFlow({
27352
- baseRects,
27353
- pageCount,
27354
- scrollRoot,
27355
- originElement: overlayRootRef.current
27356
- });
27357
- },
27358
- [scrollRoot]
27359
- );
27360
27303
  const refreshRectsNow = React21.useCallback(() => {
27361
27304
  const pageCount = facet.getPageCount();
27362
27305
  const skeletalRects = resolveSkeletalPageOverlayRectsFromLayout(facet);
@@ -27397,51 +27340,11 @@ var TwPageStackOverlayLayer = ({
27397
27340
  setRectsIfChanged(skeletalRects);
27398
27341
  return;
27399
27342
  }
27400
- if (!scrollRoot) {
27401
- setRectsIfChanged(skeletalRects);
27402
- return;
27403
- }
27404
- const origin = overlayRootRef.current;
27405
- incrementInvalidationCounter("overlay.page.dom_fallback");
27406
- if (origin) {
27407
- incrementInvalidationCounter("overlay.page.dom.degraded");
27408
- const widgets = measureWidgetsViaBoundingRect(scrollRoot, origin, {
27409
- pageCount,
27410
- visiblePageIndexRange: null
27411
- });
27412
- const originRect = origin.getBoundingClientRect();
27413
- const domRects = resolvePageOverlayRects({
27414
- widgets,
27415
- pageCount,
27416
- scrollHeight: (
27417
- // geometry:allow-dom-fallback
27418
- origin.clientHeight > 0 ? origin.clientHeight : originRect.height
27419
- ),
27420
- visiblePageIndexRange: null
27421
- });
27422
- const reconciled = reconcilePaperRectsWithFlow(domRects, pageCount);
27423
- setRectsIfChanged(reconciled.length > 0 ? reconciled : skeletalRects);
27424
- } else {
27425
- incrementInvalidationCounter("overlay.page.dom.degraded");
27426
- const widgets = measureWidgetsViaOffsetChain(scrollRoot, {
27427
- pageCount,
27428
- visiblePageIndexRange: null
27429
- });
27430
- const domRects = resolvePageOverlayRects({
27431
- widgets,
27432
- pageCount,
27433
- // geometry:allow-dom-fallback
27434
- scrollHeight: scrollRoot.clientHeight,
27435
- visiblePageIndexRange: null
27436
- });
27437
- const reconciled = reconcilePaperRectsWithFlow(domRects, pageCount);
27438
- setRectsIfChanged(reconciled.length > 0 ? reconciled : skeletalRects);
27439
- }
27343
+ incrementInvalidationCounter("overlay.page.skeletal_fallback");
27344
+ setRectsIfChanged(skeletalRects);
27440
27345
  }, [
27441
27346
  facet,
27442
27347
  geometryFacet,
27443
- reconcilePaperRectsWithFlow,
27444
- scrollRoot,
27445
27348
  setRectsIfChanged,
27446
27349
  ui
27447
27350
  ]);
@@ -27472,33 +27375,6 @@ var TwPageStackOverlayLayer = ({
27472
27375
  }
27473
27376
  };
27474
27377
  }, [refreshRects, renderFrameRevision, scrollRoot]);
27475
- React21.useEffect(() => {
27476
- if (geometryFacet) return;
27477
- if (!scrollRoot) return;
27478
- const runtime = scrollRoot.ownerDocument?.defaultView;
27479
- if (!runtime?.ResizeObserver) return;
27480
- const observer = new runtime.ResizeObserver(() => refreshRects());
27481
- observer.observe(scrollRoot);
27482
- return () => observer.disconnect();
27483
- }, [geometryFacet, scrollRoot, refreshRects]);
27484
- React21.useEffect(() => {
27485
- if (geometryFacet) return;
27486
- if (!scrollRoot) return;
27487
- const runtime = scrollRoot.ownerDocument?.defaultView;
27488
- if (!runtime?.MutationObserver) return;
27489
- const observer = new runtime.MutationObserver((records) => {
27490
- const overlay = overlayRootRef.current;
27491
- if (overlay) {
27492
- const allSelf = records.every(
27493
- (r) => r.target instanceof Node && overlay.contains(r.target)
27494
- );
27495
- if (allSelf) return;
27496
- }
27497
- refreshRects();
27498
- });
27499
- observer.observe(scrollRoot, { childList: true, subtree: false });
27500
- return () => observer.disconnect();
27501
- }, [geometryFacet, scrollRoot, refreshRects]);
27502
27378
  if (rects.length === 0) {
27503
27379
  return /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(
27504
27380
  "div",
@@ -28140,6 +28016,18 @@ function emuToPx(emu, pxPerTwip) {
28140
28016
  return emu / EMU_PER_PX * zoomFactor;
28141
28017
  }
28142
28018
 
28019
+ // src/ui-tailwind/editor-surface/media-src-policy.ts
28020
+ var SAFE_DATA_IMAGE_PREFIX_RE = /^data:image\/(?:png|jpe?g|gif|webp|bmp);base64,/iu;
28021
+ var MAX_NUMBERING_PICTURE_BULLET_DATA_URL_LENGTH = 1024 * 1024;
28022
+ function sanitizeNumberingPictureBulletSrc(src) {
28023
+ if (typeof src !== "string") return null;
28024
+ const trimmed = src.trim();
28025
+ if (trimmed.length === 0) return null;
28026
+ if (trimmed.length > MAX_NUMBERING_PICTURE_BULLET_DATA_URL_LENGTH) return null;
28027
+ if (!SAFE_DATA_IMAGE_PREFIX_RE.test(trimmed)) return null;
28028
+ return trimmed;
28029
+ }
28030
+
28143
28031
  // src/ui-tailwind/page-stack/tw-region-block-renderer.tsx
28144
28032
  var import_jsx_runtime49 = require("react/jsx-runtime");
28145
28033
  var EMU_PER_PX2 = 9525;
@@ -28254,6 +28142,10 @@ function renderSegment(seg, mediaPreviews, fallbackDisplay, tabInfoBySegment) {
28254
28142
  "span",
28255
28143
  {
28256
28144
  "data-node-type": "field_ref",
28145
+ "data-generated-field": "true",
28146
+ "data-field-family": seg.fieldFamily,
28147
+ "data-field-target": seg.fieldTarget,
28148
+ "data-field-refresh-status": seg.refreshStatus,
28257
28149
  style: { opacity: 0.6, fontSize: "0.85em" },
28258
28150
  children: seg.displayText ?? seg.label
28259
28151
  },
@@ -28303,6 +28195,9 @@ function RegionParagraph({
28303
28195
  const markerWidth = resolvedNumbering?.geometry?.markerLane?.width;
28304
28196
  const markerStart = resolvedNumbering?.geometry?.markerLane?.start;
28305
28197
  const markerJustification = resolvedNumbering?.geometry?.markerJustification;
28198
+ const pictureBulletSrc = sanitizeNumberingPictureBulletSrc(
28199
+ resolvedNumbering?.picBulletMediaId ? mediaPreviews[resolvedNumbering.picBulletMediaId]?.src : null
28200
+ );
28306
28201
  const prefixSpan = numberingPrefix != null ? /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(
28307
28202
  "span",
28308
28203
  {
@@ -28313,7 +28208,9 @@ function RegionParagraph({
28313
28208
  ...!markerRunProperties ? ["text-tertiary", "font-[family-name:var(--font-legal-sans)]"] : []
28314
28209
  ].join(" "),
28315
28210
  contentEditable: false,
28316
- "data-numbering-prefix": numberingPrefix,
28211
+ "data-numbering-marker": "true",
28212
+ "data-numbering-prefix": pictureBulletSrc ? "" : numberingPrefix,
28213
+ ...pictureBulletSrc ? { "data-numbering-picture-bullet": resolvedNumbering?.pictureBulletPosture?.status ?? "media-rendered" } : {},
28317
28214
  ...typeof resolvedNumbering?.level === "number" ? { "data-numbering-level": String(resolvedNumbering.level) } : {},
28318
28215
  ...numberingSuffix ? { "data-numbering-suffix": numberingSuffix } : {},
28319
28216
  style: buildMarkerStyle(
@@ -28324,7 +28221,20 @@ function RegionParagraph({
28324
28221
  markerStart,
28325
28222
  markerJustification
28326
28223
  ),
28327
- children: numberingPrefix
28224
+ children: pictureBulletSrc ? /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(
28225
+ "img",
28226
+ {
28227
+ src: pictureBulletSrc,
28228
+ alt: "",
28229
+ "aria-hidden": "true",
28230
+ style: {
28231
+ maxWidth: "100%",
28232
+ maxHeight: "100%",
28233
+ objectFit: "contain",
28234
+ display: "block"
28235
+ }
28236
+ }
28237
+ ) : numberingPrefix
28328
28238
  }
28329
28239
  ) : null;
28330
28240
  const attrs = {
@@ -29556,25 +29466,23 @@ var TwPageStackChromeLayerInner = ({
29556
29466
  const pageCount = facet.getPageCount();
29557
29467
  const uiRects = resolveUiPageRects(pageCount);
29558
29468
  if (uiRects !== null) return uiRects;
29559
- if (!geometryFacet) return [];
29560
- const warm = resolvePageOverlayRectsFromGeometry2(
29561
- geometryFacet,
29562
- pageCount,
29563
- visiblePageIndexRange
29469
+ if (geometryFacet) {
29470
+ const warm = resolvePageOverlayRectsFromGeometry2(
29471
+ geometryFacet,
29472
+ pageCount,
29473
+ visiblePageIndexRange
29474
+ );
29475
+ if (warm !== null) return warm;
29476
+ }
29477
+ return resolveSkeletalPageOverlayRectsFromLayout(facet).filter(
29478
+ (rect2) => !visiblePageIndexRange || rect2.pageIndex >= visiblePageIndexRange.start && rect2.pageIndex < visiblePageIndexRange.end
29564
29479
  );
29565
- return warm ?? [];
29566
29480
  });
29567
29481
  const overlayRootRef = import_react29.default.useRef(null);
29568
29482
  const rafHandleRef = import_react29.default.useRef(null);
29569
29483
  const [activeStoryPageIndex, setActiveStoryPageIndex] = import_react29.default.useState(null);
29570
29484
  const refreshRectsNow = import_react29.default.useCallback(() => {
29571
29485
  const pageCount = facet.getPageCount();
29572
- const reconcileDomRects = (baseRects) => reconcilePageStackRectsWithFlow({
29573
- baseRects,
29574
- pageCount,
29575
- scrollRoot,
29576
- originElement: overlayRootRef.current
29577
- });
29578
29486
  const uiRects = resolveUiPageRects(pageCount);
29579
29487
  if (uiRects !== null) {
29580
29488
  setRects(uiRects);
@@ -29593,47 +29501,11 @@ var TwPageStackChromeLayerInner = ({
29593
29501
  setRects([]);
29594
29502
  return;
29595
29503
  }
29596
- if (!scrollRoot) {
29597
- setRects([]);
29598
- return;
29599
- }
29600
- const origin = overlayRootRef.current;
29601
- if (origin) {
29602
- const widgets = measureWidgetsViaBoundingRect(scrollRoot, origin, {
29603
- pageCount,
29604
- visiblePageIndexRange
29605
- });
29606
- const originRect = origin.getBoundingClientRect();
29607
- const scrollHeight = (
29608
- // geometry:allow-dom-fallback
29609
- origin.clientHeight > 0 ? origin.clientHeight : originRect.height > 0 ? originRect.height : scrollRoot.clientHeight
29610
- );
29611
- const domRects = resolvePageOverlayRects({
29612
- widgets,
29613
- pageCount,
29614
- scrollHeight,
29615
- visiblePageIndexRange
29616
- });
29617
- setRects(
29618
- reconcileDomRects(domRects)
29619
- );
29620
- } else {
29621
- const widgets = measureWidgetsViaOffsetChain(scrollRoot, {
29622
- pageCount,
29623
- visiblePageIndexRange
29624
- });
29625
- const domRects = resolvePageOverlayRects({
29626
- widgets,
29627
- pageCount,
29628
- // geometry:allow-dom-fallback
29629
- scrollHeight: scrollRoot.clientHeight,
29630
- visiblePageIndexRange
29631
- });
29632
- setRects(
29633
- reconcileDomRects(domRects)
29634
- );
29635
- }
29636
- }, [facet, geometryFacet, resolveUiPageRects, scrollRoot, visiblePageIndexRange]);
29504
+ const skeletalRects = resolveSkeletalPageOverlayRectsFromLayout(facet).filter(
29505
+ (rect2) => !visiblePageIndexRange || rect2.pageIndex >= visiblePageIndexRange.start && rect2.pageIndex < visiblePageIndexRange.end
29506
+ );
29507
+ setRects(skeletalRects);
29508
+ }, [facet, geometryFacet, resolveUiPageRects, visiblePageIndexRange]);
29637
29509
  const refreshRects = import_react29.default.useCallback(() => {
29638
29510
  if (!scrollRoot) {
29639
29511
  refreshRectsNow();
@@ -29673,33 +29545,6 @@ var TwPageStackChromeLayerInner = ({
29673
29545
  },
29674
29546
  [onOpenStory]
29675
29547
  );
29676
- import_react29.default.useEffect(() => {
29677
- if (geometryFacet) return;
29678
- if (!scrollRoot) return;
29679
- const runtime = scrollRoot.ownerDocument?.defaultView;
29680
- if (!runtime?.ResizeObserver) return;
29681
- const observer = new runtime.ResizeObserver(() => refreshRects());
29682
- observer.observe(scrollRoot);
29683
- return () => observer.disconnect();
29684
- }, [geometryFacet, scrollRoot, refreshRects]);
29685
- import_react29.default.useEffect(() => {
29686
- if (geometryFacet) return;
29687
- if (!scrollRoot) return;
29688
- const runtime = scrollRoot.ownerDocument?.defaultView;
29689
- if (!runtime?.MutationObserver) return;
29690
- const observer = new runtime.MutationObserver((records) => {
29691
- const overlay = overlayRootRef.current;
29692
- if (overlay) {
29693
- const allSelf = records.every(
29694
- (r) => r.target instanceof Node && overlay.contains(r.target)
29695
- );
29696
- if (allSelf) return;
29697
- }
29698
- refreshRects();
29699
- });
29700
- observer.observe(scrollRoot, { childList: true, subtree: false });
29701
- return () => observer.disconnect();
29702
- }, [geometryFacet, scrollRoot, refreshRects]);
29703
29548
  import_react29.default.useLayoutEffect(() => {
29704
29549
  if (!pmSurfaceElement) return;
29705
29550
  const overlay = overlayRootRef.current;
@@ -31184,45 +31029,17 @@ var TwFloatingImageLayer = ({
31184
31029
  const [pageRects, setPageRects] = React37.useState([]);
31185
31030
  const refreshPageRectsNow = React37.useCallback(() => {
31186
31031
  const pageCount = facet.getPageCount();
31187
- if (geometryFacet) {
31188
- const geometryRects = resolvePageOverlayRectsFromGeometry2(
31189
- geometryFacet,
31190
- pageCount,
31191
- visiblePageIndexRange
31192
- );
31193
- if (geometryRects !== null) {
31194
- setPageRects(geometryRects);
31195
- return;
31196
- }
31197
- setPageRects([]);
31198
- return;
31199
- }
31200
- if (!scrollRoot) {
31201
- setPageRects([]);
31202
- return;
31203
- }
31204
- const origin = overlayRootRef.current;
31205
- if (!origin) {
31032
+ if (!geometryFacet) {
31206
31033
  setPageRects([]);
31207
31034
  return;
31208
31035
  }
31209
- const widgets = measureWidgetsViaBoundingRect(scrollRoot, origin, {
31036
+ const geometryRects = resolvePageOverlayRectsFromGeometry2(
31037
+ geometryFacet,
31210
31038
  pageCount,
31211
31039
  visiblePageIndexRange
31212
- });
31213
- const originRect = origin.getBoundingClientRect();
31214
- setPageRects(
31215
- resolvePageOverlayRects({
31216
- widgets,
31217
- pageCount,
31218
- scrollHeight: (
31219
- // geometry:allow-dom-fallback
31220
- origin.clientHeight > 0 ? origin.clientHeight : originRect.height
31221
- ),
31222
- visiblePageIndexRange
31223
- })
31224
31040
  );
31225
- }, [facet, geometryFacet, scrollRoot, visiblePageIndexRange]);
31041
+ setPageRects(geometryRects ?? []);
31042
+ }, [facet, geometryFacet, visiblePageIndexRange]);
31226
31043
  const refreshPageRects = React37.useCallback(() => {
31227
31044
  if (!scrollRoot) {
31228
31045
  refreshPageRectsNow();
@@ -31252,47 +31069,6 @@ var TwFloatingImageLayer = ({
31252
31069
  }
31253
31070
  };
31254
31071
  }, [refreshPageRects, renderFrameRevision, scrollRoot]);
31255
- React37.useEffect(() => {
31256
- if (geometryFacet) {
31257
- return;
31258
- }
31259
- if (!scrollRoot) {
31260
- return;
31261
- }
31262
- const runtime = scrollRoot.ownerDocument?.defaultView;
31263
- if (!runtime?.ResizeObserver) {
31264
- return;
31265
- }
31266
- const observer = new runtime.ResizeObserver(() => refreshPageRects());
31267
- observer.observe(scrollRoot);
31268
- return () => observer.disconnect();
31269
- }, [geometryFacet, refreshPageRects, scrollRoot]);
31270
- React37.useEffect(() => {
31271
- if (geometryFacet) {
31272
- return;
31273
- }
31274
- if (!scrollRoot) {
31275
- return;
31276
- }
31277
- const runtime = scrollRoot.ownerDocument?.defaultView;
31278
- if (!runtime?.MutationObserver) {
31279
- return;
31280
- }
31281
- const observer = new runtime.MutationObserver((records) => {
31282
- const overlay = overlayRootRef.current;
31283
- if (overlay) {
31284
- const allSelf = records.every(
31285
- (record) => record.target instanceof Node && overlay.contains(record.target)
31286
- );
31287
- if (allSelf) {
31288
- return;
31289
- }
31290
- }
31291
- refreshPageRects();
31292
- });
31293
- observer.observe(scrollRoot, { childList: true, subtree: false });
31294
- return () => observer.disconnect();
31295
- }, [geometryFacet, refreshPageRects, scrollRoot]);
31296
31072
  const items = React37.useMemo(() => {
31297
31073
  const viewportScale = geometryFacet?.getViewport().pxPerTwip;
31298
31074
  const pxPerTwip = typeof viewportScale === "number" && viewportScale > 0 ? viewportScale : void 0;
@@ -33694,6 +33470,21 @@ function resolveRoleChromePreset(basePreset, role) {
33694
33470
  }
33695
33471
  return basePreset;
33696
33472
  }
33473
+ function resolveActiveListReadback(rows, activeListContext, selection) {
33474
+ if (!activeListContext) {
33475
+ return null;
33476
+ }
33477
+ const selectionPoint = selection.activeRange.kind === "range" ? selection.head : selection.activeRange.kind === "node" ? selection.activeRange.at : selection.activeRange.lastKnownRange.from;
33478
+ const matchingSelectionRow = rows.find(
33479
+ (row) => row.numberingInstanceId === activeListContext.numberingInstanceId && row.level === activeListContext.level && selectionPoint >= row.authoredTextRange.from && selectionPoint <= row.authoredTextRange.to
33480
+ );
33481
+ if (matchingSelectionRow) {
33482
+ return matchingSelectionRow;
33483
+ }
33484
+ return rows.find(
33485
+ (row) => row.numberingInstanceId === activeListContext.numberingInstanceId && row.level === activeListContext.level
33486
+ ) ?? null;
33487
+ }
33697
33488
  function TwReviewWorkspace(inputProps) {
33698
33489
  const props = {
33699
33490
  ...inputProps,
@@ -33808,6 +33599,14 @@ function TwReviewWorkspace(inputProps) {
33808
33599
  () => uiApi?.scope.list().length,
33809
33600
  [uiApi, renderFrameRevision]
33810
33601
  );
33602
+ const activeListReadback = (0, import_react51.useMemo)(
33603
+ () => resolveActiveListReadback(
33604
+ uiApi?.lists.list() ?? [],
33605
+ props.activeListContext,
33606
+ viewState.selection
33607
+ ),
33608
+ [uiApi, props.activeListContext, viewState.selection, renderFrameRevision]
33609
+ );
33811
33610
  const headings = props.documentNavigation?.headings ?? [];
33812
33611
  const headerVariant = snapshot.pageLayout?.headerVariants[0]?.variant ?? "default";
33813
33612
  const footerVariant = snapshot.pageLayout?.footerVariants[0]?.variant ?? "default";
@@ -34076,6 +33875,7 @@ function TwReviewWorkspace(inputProps) {
34076
33875
  zoomLevel: props.zoomLevel,
34077
33876
  formattingState: props.formattingState,
34078
33877
  activeListContext: props.activeListContext,
33878
+ activeListReadback,
34079
33879
  styleCatalog: props.styleCatalog,
34080
33880
  showTrackedChanges: trackedChangesAuthoringEnabled,
34081
33881
  showSidebarToggle: responsiveChrome.showSidebarToggle,
@@ -34287,6 +34087,7 @@ function TwReviewWorkspace(inputProps) {
34287
34087
  onSetImageFrame: props.onSetImageFrame,
34288
34088
  onRestartNumbering: props.onRestartNumbering,
34289
34089
  onContinueNumbering: props.onContinueNumbering,
34090
+ activeListReadback,
34290
34091
  onToggleRowHeader: props.onToggleRowHeader,
34291
34092
  onToggleRowCantSplit: props.onToggleRowCantSplit,
34292
34093
  onDistributeColumnsEvenly: props.onDistributeColumnsEvenly,