@docx-editor.dev/core 2.4.0 → 2.5.0

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 (109) hide show
  1. package/dist/automation.cjs +1 -1
  2. package/dist/automation.d.cts +6 -6
  3. package/dist/automation.d.ts +6 -6
  4. package/dist/automation.js +1 -1
  5. package/dist/binding.cjs +1 -1
  6. package/dist/binding.d.cts +12 -12
  7. package/dist/binding.d.ts +12 -12
  8. package/dist/binding.js +1 -1
  9. package/dist/chunk-2GSRLGUI.cjs +10 -0
  10. package/dist/chunk-2QIA75K3.js +2 -0
  11. package/dist/chunk-32NXPFYL.js +5 -0
  12. package/dist/chunk-3C533HSQ.cjs +18 -0
  13. package/dist/{chunk-YMIMLEX4.cjs → chunk-3FRSOOND.cjs} +1 -1
  14. package/dist/chunk-45FL7KH4.js +1 -0
  15. package/dist/chunk-7GYF33B5.cjs +2 -0
  16. package/dist/chunk-H3DZP4LE.cjs +5 -0
  17. package/dist/chunk-IJ4V3LGV.cjs +2 -0
  18. package/dist/chunk-JDHTCMFA.cjs +2 -0
  19. package/dist/chunk-L2GMLEHX.cjs +14 -0
  20. package/dist/chunk-LJIX4ZDF.js +10 -0
  21. package/dist/chunk-QUZM6LWQ.js +14 -0
  22. package/dist/chunk-T252F4US.js +18 -0
  23. package/dist/chunk-UVIUNAQ6.js +2 -0
  24. package/dist/chunk-YTZIGUXT.js +2 -0
  25. package/dist/{content-control-walk-CbTqHq6O.d.cts → content-control-walk-BeAFh6Xi.d.cts} +1 -1
  26. package/dist/{content-control-walk-D06GijR0.d.ts → content-control-walk-CQp8l6eS.d.ts} +1 -1
  27. package/dist/contracts/editor.d.cts +9 -9
  28. package/dist/contracts/editor.d.ts +9 -9
  29. package/dist/contracts/interaction.d.cts +9 -9
  30. package/dist/contracts/interaction.d.ts +9 -9
  31. package/dist/contracts/modules.d.cts +5 -5
  32. package/dist/contracts/modules.d.ts +5 -5
  33. package/dist/{custom-node-writes-BkMgMXxs.d.ts → custom-node-writes-2clI36T9.d.ts} +22 -7
  34. package/dist/{custom-node-writes-C5YRoPcc.d.cts → custom-node-writes-CIC_-wad.d.cts} +22 -7
  35. package/dist/{editor-DYvC9CZs.d.cts → editor-CUul9IuY.d.cts} +22 -5
  36. package/dist/{editor-D1qHfzOt.d.ts → editor-DIwctMcU.d.ts} +22 -5
  37. package/dist/editor.cjs +1 -1
  38. package/dist/editor.css +32 -0
  39. package/dist/editor.d.cts +24 -24
  40. package/dist/editor.d.ts +24 -24
  41. package/dist/editor.js +1 -1
  42. package/dist/{hf-references-CgEOSw3i.d.cts → hf-references-BPET4tlK.d.cts} +2 -2
  43. package/dist/{hf-references-BdjsQNE_.d.ts → hf-references-CAp1xTv6.d.ts} +2 -2
  44. package/dist/{image-resources-DXvPZvXD.d.cts → image-resources-CSlQmPIm.d.cts} +10 -10
  45. package/dist/{image-resources-BG9DLyW7.d.ts → image-resources-e13t-pgy.d.ts} +10 -10
  46. package/dist/{index-Bb-QAg_f.d.cts → index-8t44iXTY.d.cts} +79 -14
  47. package/dist/{index-DpY3WZuP.d.ts → index-BUsYjxF5.d.ts} +79 -14
  48. package/dist/index.cjs +1 -1
  49. package/dist/index.d.cts +18 -18
  50. package/dist/index.d.ts +18 -18
  51. package/dist/index.js +1 -1
  52. package/dist/layout.cjs +1 -1
  53. package/dist/layout.d.cts +114 -50
  54. package/dist/layout.d.ts +114 -50
  55. package/dist/layout.js +1 -1
  56. package/dist/{note-nodes-C6DLxlvj.d.cts → note-nodes-B2wWES2L.d.cts} +1 -1
  57. package/dist/{note-nodes-BPSTVDMr.d.ts → note-nodes-CZQXU6Fg.d.ts} +1 -1
  58. package/dist/{review-reads-CQmU9Lcl.d.ts → note-properties-BS66XmcC.d.ts} +91 -67
  59. package/dist/{review-reads-CxgN62yp.d.cts → note-properties-Dhqkro--.d.cts} +91 -67
  60. package/dist/{ooxml-package-D_CtywTW.d.ts → ooxml-package-BrxTmTsZ.d.ts} +115 -115
  61. package/dist/{ooxml-package-CR5us6ad.d.cts → ooxml-package-Cmbe_M04.d.cts} +115 -115
  62. package/dist/{ooxml-tree-BU0e3DVi.d.cts → ooxml-tree-CG0odFyi.d.cts} +1 -1
  63. package/dist/{ooxml-tree-BU0e3DVi.d.ts → ooxml-tree-CG0odFyi.d.ts} +1 -1
  64. package/dist/output.cjs +1 -1
  65. package/dist/output.d.cts +7 -7
  66. package/dist/output.d.ts +7 -7
  67. package/dist/output.js +1 -1
  68. package/dist/{protocol-CD7slqvl.d.cts → protocol-B5oSt08P.d.cts} +2 -2
  69. package/dist/{protocol-DsbfgBwA.d.ts → protocol-ooK7PAXz.d.ts} +2 -2
  70. package/dist/{review-support-DgXTIYBW.d.ts → review-support-Bl9sN8cv.d.ts} +47 -3
  71. package/dist/{review-support-BJ-YjGmD.d.cts → review-support-CHuJxHmz.d.cts} +47 -3
  72. package/dist/{revision-projection-DHAkcD_L.d.ts → revision-projection-DRZMzoLD.d.cts} +54 -3
  73. package/dist/{revision-projection-72ZApe-g.d.cts → revision-projection-u4nT52xT.d.ts} +54 -3
  74. package/dist/{semantic-cell-selection-DZtyMXkH.d.ts → semantic-cell-selection-CdNQ-a9-.d.cts} +8 -5
  75. package/dist/{semantic-cell-selection--ezfezTe.d.cts → semantic-cell-selection-Dc-_enhm.d.ts} +8 -5
  76. package/dist/{semantic-interaction-DrgbgKg6.d.ts → semantic-interaction-CCVwyw2A.d.ts} +2 -30
  77. package/dist/{semantic-interaction-2yxdv7q0.d.cts → semantic-interaction-DgaWs-5w.d.cts} +2 -30
  78. package/dist/{semantic-paint-BYjE0Xbl.d.cts → semantic-paint-6iIB4fhx.d.cts} +2 -2
  79. package/dist/{semantic-paint-BedBxkyY.d.ts → semantic-paint-CKIbFkQ7.d.ts} +2 -2
  80. package/dist/{semantic-records-CR5hTqMK.d.ts → semantic-records-B-qbrnp2.d.ts} +107 -9
  81. package/dist/{semantic-records-DSD8WENa.d.cts → semantic-records-Dq8SlCY8.d.cts} +107 -9
  82. package/dist/{shaped-measurer-BL8g4AcW.d.ts → shaped-measurer-BT4FqYe9.d.ts} +1 -1
  83. package/dist/{shaped-measurer-CBOTJTV_.d.cts → shaped-measurer-Dx4llNhK.d.cts} +1 -1
  84. package/dist/store.cjs +1 -1
  85. package/dist/store.d.cts +254 -231
  86. package/dist/store.d.ts +254 -231
  87. package/dist/store.js +1 -1
  88. package/dist/{tree-op-types-8a6xyRCN.d.ts → tree-op-types-CZw9QhWX.d.ts} +219 -219
  89. package/dist/{tree-op-types-EZXbR8bW.d.cts → tree-op-types-DOYNkKqD.d.cts} +219 -219
  90. package/dist/{tree-session-SucW0znF.d.ts → tree-session-CF_EOhTW.d.ts} +14 -8
  91. package/dist/{tree-session-DrMm8Cj2.d.cts → tree-session-CtK3KgFU.d.cts} +14 -8
  92. package/dist/{tree-store-BoM6eXaL.d.ts → tree-store-9TaX-L0V.d.ts} +31 -4
  93. package/dist/{tree-store-UYrGKF_Q.d.cts → tree-store-Jg-q7fyf.d.cts} +31 -4
  94. package/package.json +3 -3
  95. package/dist/chunk-33F6TRXO.js +0 -2
  96. package/dist/chunk-4WWEDTTE.js +0 -2
  97. package/dist/chunk-BS554B6D.cjs +0 -2
  98. package/dist/chunk-DQ5HGUWG.cjs +0 -12
  99. package/dist/chunk-EQO762XH.cjs +0 -10
  100. package/dist/chunk-F6WNPYOM.js +0 -2
  101. package/dist/chunk-FL4GWK76.js +0 -12
  102. package/dist/chunk-GWG5IVVX.cjs +0 -5
  103. package/dist/chunk-IZIL6BAW.cjs +0 -12
  104. package/dist/chunk-LIJPSHRA.js +0 -5
  105. package/dist/chunk-MHDO6HLI.cjs +0 -2
  106. package/dist/chunk-SG7OH2EK.js +0 -12
  107. package/dist/chunk-TCX3PVWR.js +0 -10
  108. package/dist/chunk-YTYKNA6X.cjs +0 -2
  109. package/dist/chunk-ZACHY6OS.js +0 -1
@@ -1,4 +1,4 @@
1
- import { O as OoxmlNode } from './ooxml-tree-BU0e3DVi.cjs';
1
+ import { O as OoxmlNode } from './ooxml-tree-CG0odFyi.js';
2
2
 
3
3
  /**
4
4
  * What a revision wrapper asserts about the content inside it.
@@ -53,16 +53,67 @@ declare const DEFAULT_REVISION_DISPLAY_MODE: RevisionDisplayMode;
53
53
  */
54
54
  declare function revisionsVisible(revisions: readonly RevisionAttribution[], mode: RevisionDisplayMode): boolean;
55
55
  /**
56
- * The revision on a paragraph's own MARK, from `w:pPr/w:rPr/w:ins|w:del`.
56
+ * Every revision on a paragraph's own MARK, from `w:pPr/w:rPr/w:ins|w:del|w:moveFrom|w:moveTo`.
57
+ *
58
+ * All four members of `EG_ParaRPrTrackChanges`. A moved paragraph carries `w:moveFrom` on the
59
+ * mark of the copy it left and `w:moveTo` on the mark of the copy it arrived at, so a move
60
+ * that spans whole paragraphs is recorded here and nowhere else.
57
61
  *
58
62
  * `EG_ParaRPrTrackChanges` records that the pilcrow itself was inserted or deleted, which is how
59
63
  * Word writes a paragraph split or merge. It is not content — there is no text to decorate — so
60
64
  * a surface shows it as a mark of its own beside the paragraph, the way Word draws a struck-
61
65
  * through ¶.
62
66
  *
67
+ * A LIST, because the group is `ins? del? moveFrom? moveTo?` and the first two can both be
68
+ * there: that pair is what Word writes when a second author proposes removing a mark the first
69
+ * proposed adding, and it is what this engine's own writer emits (`tree-op-tracked.ts`).
70
+ * Answering with the first one hid the second author's decision from the PAGE. The review pane
71
+ * walks the tree itself and always listed both, which is the worse shape of the two: a card
72
+ * offering a decision the reader could see no sign of.
73
+ *
74
+ * Ordered as the file orders them, which is the order the group declares.
75
+ *
63
76
  * Property-position `w:ins`/`w:del` stay `generic` in the tree deliberately, so this reads them
64
77
  * by name rather than by kind.
65
78
  */
79
+ declare function paragraphMarkRevisionsOf(paragraph: OoxmlNode): readonly RevisionAttribution[];
80
+ /**
81
+ * The tracked FORMAT change on a paragraph's own mark, from `w:pPr/w:rPr/w:rPrChange`.
82
+ *
83
+ * `CT_ParaRPr` ends with it (§17.13.5.32), and Word writes it when a user changes the mark's
84
+ * own run properties with tracking on. It reaches the fragment rather than a span because it
85
+ * decorates no characters, and it is not in `props`: a fragment's `props` carry the mark's
86
+ * `w:rPr` by NAME only, with none of its children.
87
+ *
88
+ * Note that `w:rPrChange/w:rPr` is `CT_ParaRPrOriginal`, which may carry its own revision
89
+ * marks. Those describe the mark as it WAS and must not be read as live ones, which is why
90
+ * this reads the change element's own attributes and never descends into it.
91
+ */
92
+ declare function paragraphMarkFormatRevisionOf(paragraph: OoxmlNode): RevisionAttribution | null;
93
+ /**
94
+ * The single decision a one-field reader sees.
95
+ *
96
+ * A DELETION wins when a mark carries both, for the reason paint draws it that way: a break
97
+ * proposed and then unproposed ends up removed, so that is the decision a reader who can only
98
+ * see one must see. One function decides it, so the deprecated field, the deprecated function
99
+ * and the painted glyph cannot answer differently.
100
+ */
101
+ declare function shownMarkRevision(revisions: readonly RevisionAttribution[]): RevisionAttribution | undefined;
102
+ /**
103
+ * Does this decision, taken, remove the paragraph mark?
104
+ *
105
+ * A deletion does, and so does a `moveFrom`: the copy the paragraph moved OUT of goes away
106
+ * when the move is accepted. `insert` and `moveTo` are the other half of each pair, and they
107
+ * keep the break. Paint, the change bar and the resolved views all ask this one question, so
108
+ * a `moveFrom` cannot end up struck through in the margin and blue on the glyph.
109
+ */
110
+ declare function markRevisionRemovesMark(revision: RevisionAttribution): boolean;
111
+ /**
112
+ * The one decision on a paragraph's mark that a single-field reader sees.
113
+ *
114
+ * @deprecated Reads one of the revisions a mark can carry. Use {@link paragraphMarkRevisionsOf},
115
+ * which answers with all of them.
116
+ */
66
117
  declare function paragraphMarkRevisionOf(paragraph: OoxmlNode): RevisionAttribution | null;
67
118
  /**
68
119
  * The tracked FORMAT change on a property list, from `w:rPrChange` or `w:pPrChange`.
@@ -81,4 +132,4 @@ declare function formatRevisionOf(properties: readonly {
81
132
  /** True when this stack of revisions marks its content as deleted from the live document. */
82
133
  declare function revisionsAreDeletion(revisions: readonly RevisionAttribution[]): boolean;
83
134
 
84
- export { DEFAULT_REVISION_DISPLAY_MODE as D, type RevisionDisplayMode as R, type RevisionAttribution as a, type RevisionKind as b, revisionsVisible as c, formatRevisionOf as f, paragraphMarkRevisionOf as p, revisionsAreDeletion as r };
135
+ export { DEFAULT_REVISION_DISPLAY_MODE as D, type RevisionDisplayMode as R, type RevisionAttribution as a, type RevisionKind as b, paragraphMarkRevisionOf as c, paragraphMarkRevisionsOf as d, revisionsVisible as e, formatRevisionOf as f, markRevisionRemovesMark as m, paragraphMarkFormatRevisionOf as p, revisionsAreDeletion as r, shownMarkRevision as s };
@@ -1,7 +1,7 @@
1
- import { e as OoxmlPart, a as OoxmlElement, O as OoxmlNode } from './ooxml-tree-BU0e3DVi.js';
2
- import { P as PageGeometry, I as InlineDrawingRecord, A as AnchoredDrawingRecord, T as TextMeasurer, L as LineRecord, S as SemanticLayout, C as ContentControlBoundaryRecord, a as StyleSpanRecord, b as TableRowFragmentRecord, c as TableCellFragmentRecord } from './semantic-records-CR5hTqMK.js';
3
- import { R as RevisionDisplayMode } from './revision-projection-DHAkcD_L.js';
4
- import { S as SemanticPosition, C as CaretGeometry, a as SemanticSelection } from './semantic-interaction-DrgbgKg6.js';
1
+ import { e as OoxmlPart, a as OoxmlElement, O as OoxmlNode } from './ooxml-tree-CG0odFyi.cjs';
2
+ import { P as PageGeometry, I as InlineDrawingRecord, A as AnchoredDrawingRecord, T as TextMeasurer, L as LineRecord, a as StyleSpanRecord, S as SemanticLayout, C as ContentControlBoundaryRecord, b as TableRowFragmentRecord, c as TableCellFragmentRecord } from './semantic-records-Dq8SlCY8.cjs';
3
+ import { R as RevisionDisplayMode } from './revision-projection-DRZMzoLD.cjs';
4
+ import { S as SemanticPosition, C as CaretGeometry, a as SemanticSelection } from './semantic-interaction-DgaWs-5w.cjs';
5
5
 
6
6
  /**
7
7
  * Hard ceiling on sections enumerated from a document (matches write-path
@@ -320,7 +320,10 @@ declare function spanOffsetX(span: StyleSpanRecord, offset: number, measurer: Te
320
320
  * - otherwise the run BEFORE the offset wins — the run a keystroke would continue —
321
321
  * except at the start of the line, where there is nothing before it.
322
322
  */
323
- declare function caretBoxOnLine(line: LineRecord, offset: number, measurer: TextMeasurer | undefined): {
323
+ declare function caretBoxOnLine(line: LineRecord, offset: number, measurer: TextMeasurer | undefined, segment?: {
324
+ readonly spans: readonly StyleSpanRecord[];
325
+ readonly drawings: readonly InlineDrawingRecord[];
326
+ } | null): {
324
327
  x: number;
325
328
  y: number;
326
329
  height: number;
@@ -1,7 +1,7 @@
1
- import { e as OoxmlPart, a as OoxmlElement, O as OoxmlNode } from './ooxml-tree-BU0e3DVi.cjs';
2
- import { P as PageGeometry, I as InlineDrawingRecord, A as AnchoredDrawingRecord, T as TextMeasurer, L as LineRecord, S as SemanticLayout, C as ContentControlBoundaryRecord, a as StyleSpanRecord, b as TableRowFragmentRecord, c as TableCellFragmentRecord } from './semantic-records-DSD8WENa.cjs';
3
- import { R as RevisionDisplayMode } from './revision-projection-72ZApe-g.cjs';
4
- import { S as SemanticPosition, C as CaretGeometry, a as SemanticSelection } from './semantic-interaction-2yxdv7q0.cjs';
1
+ import { e as OoxmlPart, a as OoxmlElement, O as OoxmlNode } from './ooxml-tree-CG0odFyi.js';
2
+ import { P as PageGeometry, I as InlineDrawingRecord, A as AnchoredDrawingRecord, T as TextMeasurer, L as LineRecord, a as StyleSpanRecord, S as SemanticLayout, C as ContentControlBoundaryRecord, b as TableRowFragmentRecord, c as TableCellFragmentRecord } from './semantic-records-B-qbrnp2.js';
3
+ import { R as RevisionDisplayMode } from './revision-projection-u4nT52xT.js';
4
+ import { S as SemanticPosition, C as CaretGeometry, a as SemanticSelection } from './semantic-interaction-CCVwyw2A.js';
5
5
 
6
6
  /**
7
7
  * Hard ceiling on sections enumerated from a document (matches write-path
@@ -320,7 +320,10 @@ declare function spanOffsetX(span: StyleSpanRecord, offset: number, measurer: Te
320
320
  * - otherwise the run BEFORE the offset wins — the run a keystroke would continue —
321
321
  * except at the start of the line, where there is nothing before it.
322
322
  */
323
- declare function caretBoxOnLine(line: LineRecord, offset: number, measurer: TextMeasurer | undefined): {
323
+ declare function caretBoxOnLine(line: LineRecord, offset: number, measurer: TextMeasurer | undefined, segment?: {
324
+ readonly spans: readonly StyleSpanRecord[];
325
+ readonly drawings: readonly InlineDrawingRecord[];
326
+ } | null): {
324
327
  x: number;
325
328
  y: number;
326
329
  height: number;
@@ -1,4 +1,4 @@
1
- import { T as TextMeasurer, S as SemanticLayout, B as BlockFragmentRecord, C as ContentControlBoundaryRecord, a as StyleSpanRecord } from './semantic-records-CR5hTqMK.js';
1
+ import { T as TextMeasurer, S as SemanticLayout, B as BlockFragmentRecord, C as ContentControlBoundaryRecord, a as StyleSpanRecord } from './semantic-records-B-qbrnp2.js';
2
2
 
3
3
  /** A caret position in the model. */
4
4
  interface SemanticPosition {
@@ -87,34 +87,6 @@ declare function contentControlAtSemantic(layout: SemanticLayout, point: {
87
87
  }): ContentControlBoundaryRecord | null;
88
88
  /** Layout-published content-control boundaries in document order. */
89
89
  declare function contentControlsInLayout(layout: SemanticLayout): readonly ContentControlBoundaryRecord[];
90
- /** The rectangles covering a selection, one per line it spans. */
91
- declare function selectionRects(layout: SemanticLayout, selection: SemanticSelection): SelectionRect[];
92
- /** A model range to highlight, and the key the caller knows it by. */
93
- interface KeyedRange {
94
- readonly key: string;
95
- readonly from: SemanticPosition;
96
- readonly to: SemanticPosition;
97
- }
98
- /**
99
- * Rectangles for MANY ranges in ONE pass over the lines.
100
- *
101
- * Not `selectionRects` in a loop. That walks every page, fragment and line per range, and a
102
- * contract with two hundred comments would re-walk the whole document two hundred times on
103
- * every layout — the highlight would cost more than the layout it decorates. One pass tests
104
- * each line against every range instead, which is the same work a single selection does.
105
- */
106
- declare function keyedRangeRects(layout: SemanticLayout, ranges: readonly KeyedRange[],
107
- /**
108
- * Pages to measure, or every page when absent.
109
- *
110
- * A band that is not on screen is not painted, so measuring it is pure cost — and it is
111
- * cost paid per keystroke, because an edit republishes the layout. Bounding this to the
112
- * materialized pages is what keeps typing in a heavily reviewed document as fast as
113
- * typing in a clean one.
114
- */
115
- pages?: ReadonlySet<number>): Map<string, SelectionRect[]>;
116
- /** Paragraph ids in document order, deduplicated across fragments. */
117
- declare function documentOrder(layout: SemanticLayout): string[];
118
90
  /**
119
91
  * One caret movement, in Word's own vocabulary.
120
92
  *
@@ -152,4 +124,4 @@ declare function compositionAnchor(layout: SemanticLayout, position: SemanticPos
152
124
  /** The style spans a selection touches, for reporting active formatting. */
153
125
  declare function spansInSelection(layout: SemanticLayout, selection: SemanticSelection): StyleSpanRecord[];
154
126
 
155
- export { type CaretGeometry as C, type KeyedRange as K, type MoveCaretOptions as M, type NavigationCommand as N, type SemanticPosition as S, type SemanticSelection as a, type CaretAtOptions as b, type SelectionRect as c, caretAt as d, caretStops as e, caretStopsForBlocks as f, compositionAnchor as g, contentControlAtSemantic as h, contentControlsInLayout as i, documentOrder as j, hitTestSemantic as k, keyedRangeRects as l, moveCaret as m, spansInSelection as n, paragraphTextFromLayout as p, selectionRects as s };
127
+ export { type CaretGeometry as C, type MoveCaretOptions as M, type NavigationCommand as N, type SemanticPosition as S, type SemanticSelection as a, type SelectionRect as b, type CaretAtOptions as c, caretAt as d, caretStops as e, caretStopsForBlocks as f, compositionAnchor as g, contentControlAtSemantic as h, contentControlsInLayout as i, hitTestSemantic as j, moveCaret as m, paragraphTextFromLayout as p, spansInSelection as s };
@@ -1,4 +1,4 @@
1
- import { T as TextMeasurer, S as SemanticLayout, B as BlockFragmentRecord, C as ContentControlBoundaryRecord, a as StyleSpanRecord } from './semantic-records-DSD8WENa.cjs';
1
+ import { T as TextMeasurer, S as SemanticLayout, B as BlockFragmentRecord, C as ContentControlBoundaryRecord, a as StyleSpanRecord } from './semantic-records-Dq8SlCY8.cjs';
2
2
 
3
3
  /** A caret position in the model. */
4
4
  interface SemanticPosition {
@@ -87,34 +87,6 @@ declare function contentControlAtSemantic(layout: SemanticLayout, point: {
87
87
  }): ContentControlBoundaryRecord | null;
88
88
  /** Layout-published content-control boundaries in document order. */
89
89
  declare function contentControlsInLayout(layout: SemanticLayout): readonly ContentControlBoundaryRecord[];
90
- /** The rectangles covering a selection, one per line it spans. */
91
- declare function selectionRects(layout: SemanticLayout, selection: SemanticSelection): SelectionRect[];
92
- /** A model range to highlight, and the key the caller knows it by. */
93
- interface KeyedRange {
94
- readonly key: string;
95
- readonly from: SemanticPosition;
96
- readonly to: SemanticPosition;
97
- }
98
- /**
99
- * Rectangles for MANY ranges in ONE pass over the lines.
100
- *
101
- * Not `selectionRects` in a loop. That walks every page, fragment and line per range, and a
102
- * contract with two hundred comments would re-walk the whole document two hundred times on
103
- * every layout — the highlight would cost more than the layout it decorates. One pass tests
104
- * each line against every range instead, which is the same work a single selection does.
105
- */
106
- declare function keyedRangeRects(layout: SemanticLayout, ranges: readonly KeyedRange[],
107
- /**
108
- * Pages to measure, or every page when absent.
109
- *
110
- * A band that is not on screen is not painted, so measuring it is pure cost — and it is
111
- * cost paid per keystroke, because an edit republishes the layout. Bounding this to the
112
- * materialized pages is what keeps typing in a heavily reviewed document as fast as
113
- * typing in a clean one.
114
- */
115
- pages?: ReadonlySet<number>): Map<string, SelectionRect[]>;
116
- /** Paragraph ids in document order, deduplicated across fragments. */
117
- declare function documentOrder(layout: SemanticLayout): string[];
118
90
  /**
119
91
  * One caret movement, in Word's own vocabulary.
120
92
  *
@@ -152,4 +124,4 @@ declare function compositionAnchor(layout: SemanticLayout, position: SemanticPos
152
124
  /** The style spans a selection touches, for reporting active formatting. */
153
125
  declare function spansInSelection(layout: SemanticLayout, selection: SemanticSelection): StyleSpanRecord[];
154
126
 
155
- export { type CaretGeometry as C, type KeyedRange as K, type MoveCaretOptions as M, type NavigationCommand as N, type SemanticPosition as S, type SemanticSelection as a, type CaretAtOptions as b, type SelectionRect as c, caretAt as d, caretStops as e, caretStopsForBlocks as f, compositionAnchor as g, contentControlAtSemantic as h, contentControlsInLayout as i, documentOrder as j, hitTestSemantic as k, keyedRangeRects as l, moveCaret as m, spansInSelection as n, paragraphTextFromLayout as p, selectionRects as s };
127
+ export { type CaretGeometry as C, type MoveCaretOptions as M, type NavigationCommand as N, type SemanticPosition as S, type SemanticSelection as a, type SelectionRect as b, type CaretAtOptions as c, caretAt as d, caretStops as e, caretStopsForBlocks as f, compositionAnchor as g, contentControlAtSemantic as h, contentControlsInLayout as i, hitTestSemantic as j, moveCaret as m, paragraphTextFromLayout as p, spansInSelection as s };
@@ -1,5 +1,5 @@
1
- import { C as ContentControlBoundaryRecord, S as SemanticLayout } from './semantic-records-DSD8WENa.cjs';
2
- import { V as ValidatedImageBytesHandle, R as RenderableImageMime } from './image-resources-DXvPZvXD.cjs';
1
+ import { C as ContentControlBoundaryRecord, S as SemanticLayout } from './semantic-records-Dq8SlCY8.cjs';
2
+ import { V as ValidatedImageBytesHandle, R as RenderableImageMime } from './image-resources-CSlQmPIm.cjs';
3
3
 
4
4
  /** Host port for safe blob URLs — only called for {@link ImageResourceState.kind} `ready`. */
5
5
  interface PaintImageUrlPort {
@@ -1,5 +1,5 @@
1
- import { C as ContentControlBoundaryRecord, S as SemanticLayout } from './semantic-records-CR5hTqMK.js';
2
- import { V as ValidatedImageBytesHandle, R as RenderableImageMime } from './image-resources-BG9DLyW7.js';
1
+ import { C as ContentControlBoundaryRecord, S as SemanticLayout } from './semantic-records-B-qbrnp2.js';
2
+ import { V as ValidatedImageBytesHandle, R as RenderableImageMime } from './image-resources-e13t-pgy.js';
3
3
 
4
4
  /** Host port for safe blob URLs — only called for {@link ImageResourceState.kind} `ready`. */
5
5
  interface PaintImageUrlPort {
@@ -1,7 +1,7 @@
1
- import { O as OoxmlProperty, j as DrawingAccessibility, S as SourceCrop, k as DrawingTransform, V as VectorShapeProjection, f as DrawingHorizontalReferenceFrame, g as DrawingVerticalReferenceFrame, b as ImageWrapTarget, D as DrawingProjection, l as TableBorderStyle } from './tree-op-types-8a6xyRCN.js';
2
- import { O as OoxmlNode, o as OoxmlDrawingNode, a as OoxmlElement } from './ooxml-tree-BU0e3DVi.js';
3
- import { a as RevisionAttribution } from './revision-projection-DHAkcD_L.js';
4
- import { I as ImageResourceState } from './image-resources-BG9DLyW7.js';
1
+ import { O as OoxmlProperty, k as DrawingAccessibility, S as SourceCrop, l as DrawingTransform, V as VectorShapeProjection, f as DrawingHorizontalReferenceFrame, g as DrawingVerticalReferenceFrame, b as ImageWrapTarget, D as DrawingProjection, m as TableBorderStyle } from './tree-op-types-CZw9QhWX.js';
2
+ import { O as OoxmlNode, q as OoxmlDrawingNode, a as OoxmlElement } from './ooxml-tree-CG0odFyi.js';
3
+ import { I as ImageResourceState } from './image-resources-e13t-pgy.js';
4
+ import { a as RevisionAttribution } from './revision-projection-u4nT52xT.js';
5
5
 
6
6
  /** Whether a paragraph must start a new page (`w:pageBreakBefore`). */
7
7
  declare function paragraphBreaksBefore(props: readonly OoxmlProperty[]): boolean;
@@ -429,6 +429,21 @@ declare function runStylesEqual(a: ResolvedRunStyle, b: ResolvedRunStyle): boole
429
429
  */
430
430
  declare function baselineShiftPtOf(style: ResolvedRunStyle): number;
431
431
 
432
+ type AllowlistedPageField = 'PAGE' | 'NUMPAGES' | 'SECTIONPAGES';
433
+ /**
434
+ * Which allowlisted page fields a header/footer story actually contains.
435
+ *
436
+ * Drives layout reuse: no fields → one baseline; NUMPAGES only → one layout per page count;
437
+ * SECTIONPAGES only → one layout per section page count; PAGE (alone or combined) → per
438
+ * distinct evaluated values with a bounded cache. Counts both complex markers and
439
+ * `w:fldSimple` (including an allowlisted page field nested inside a non-page simple field).
440
+ */
441
+ interface StoryPageFieldNeeds {
442
+ readonly hasPage: boolean;
443
+ readonly hasNumPages: boolean;
444
+ readonly hasSectionPages: boolean;
445
+ }
446
+
432
447
  interface DrawingPoint {
433
448
  readonly x: number;
434
449
  readonly y: number;
@@ -561,6 +576,21 @@ interface AnchoredDrawingRecord extends Omit<InlineDrawingRecord, 'kind' | 'base
561
576
  readonly textboxStory?: TextboxStoryLayout;
562
577
  }
563
578
 
579
+ /**
580
+ * One parsed `HYPERLINK` instruction: the raw, unsanitized pieces.
581
+ *
582
+ * `target` and `anchor` are verbatim from the instruction — the projector at the trust
583
+ * boundary decides what, if anything, they become in a DOM sink.
584
+ */
585
+ interface HyperlinkFieldSpec {
586
+ /** The target as authored (first quoted or bare non-switch token), or null. */
587
+ readonly target: string | null;
588
+ /** `\l` — a bookmark name in this document, or null. */
589
+ readonly anchor: string | null;
590
+ /** `\o` — the hover tooltip, or null. */
591
+ readonly tooltip: string | null;
592
+ }
593
+
564
594
  /**
565
595
  * What a piece says about the FIELD result it came from, for Word's shading.
566
596
  *
@@ -576,12 +606,40 @@ interface FieldAtomMarker {
576
606
  * turns it off — because they mark the blanks somebody is meant to fill in.
577
607
  */
578
608
  readonly formField: boolean;
609
+ /**
610
+ * A BODY PAGE / NUMPAGES / SECTIONPAGES atom whose value depends on pagination.
611
+ *
612
+ * The paragraph walk cannot know which page the field lands on — layout runs before the page
613
+ * count — so it paints a placeholder and records the field's kind here. Document finalize
614
+ * (`substituteBodyPageFields`) reads this marker and substitutes the real value per page.
615
+ * Absent in headers/footers, which evaluate live through their own per-page projector.
616
+ */
617
+ readonly pageField?: {
618
+ readonly kind: AllowlistedPageField;
619
+ };
579
620
  }
580
621
  /** A half-open model-offset range, in the paragraph's own UTF-16 offset space. */
581
622
  interface ModelRange {
582
623
  readonly start: number;
583
624
  readonly end: number;
584
625
  }
626
+ /**
627
+ * How layout turns a typed `w:hyperlink` node into the sanitized record spans carry.
628
+ *
629
+ * Injected rather than computed here because resolving `r:id` needs the PACKAGE's
630
+ * relationships and this module only ever sees one part's tree. `null` means the caller
631
+ * declined to project — the runs still measure and paint, they simply carry no link, which is
632
+ * the right degradation: text is never lost for want of a target.
633
+ */
634
+ type HyperlinkProjector = (link: OoxmlNode) => SpanLinkRecord | null;
635
+ /**
636
+ * How layout turns a parsed HYPERLINK field instruction into the sanitized record spans carry.
637
+ *
638
+ * Injected for the same reason as {@link HyperlinkProjector}: the spec's raw target must cross
639
+ * the surface's ONE href trust boundary, and layout owns no sanitization policy. `null` means
640
+ * no link — the cached result still paints as plain text, which is the right degradation.
641
+ */
642
+ type FieldLinkProjector = (spec: HyperlinkFieldSpec) => SpanLinkRecord | null;
585
643
 
586
644
  /** Test-only mutable counters; omitted by production call sites. Not package-public. */
587
645
  interface TableBorderGridResolveWork {
@@ -1073,15 +1131,47 @@ interface ParagraphFragmentRecord {
1073
1131
  */
1074
1132
  readonly shadingBox?: LayoutBox;
1075
1133
  /**
1076
- * The revision on this paragraph's own MARK (`w:pPr/w:rPr/w:ins|w:del`), absent when there
1077
- * is none.
1134
+ * The revisions on this paragraph's own MARK (`w:pPr/w:rPr/w:ins|w:del`), absent when there
1135
+ * are none.
1078
1136
  *
1079
- * Carried on the fragment rather than on a span because it decorates no characters: the
1137
+ * Carried on the fragment rather than on a span because they decorate no characters: the
1080
1138
  * pilcrow was inserted or deleted, which is how a split or a merge is recorded. Only the
1081
- * FINAL fragment carries it — the mark lives at the end of the paragraph, so a paragraph
1139
+ * FINAL fragment carries them — the mark lives at the end of the paragraph, so a paragraph
1082
1140
  * split across pages must not draw two of them.
1141
+ *
1142
+ * A LIST because one mark can hold two decisions at once — an insertion by one author and
1143
+ * a deletion of that insertion by the next. Published only in `all-markup`: the other two
1144
+ * display modes answer what the document WOULD be, and a resolved view draws no
1145
+ * attribution.
1146
+ *
1147
+ * Those two modes are ATTRIBUTION-resolved, not STRUCTURE-resolved. Taking a deleted mark
1148
+ * in `proposed` merges the paragraph into the next one, and taking an inserted mark in
1149
+ * `original` un-splits it, but `revision-visibility.ts` does that only for a paragraph that
1150
+ * renders no text. So a resolved view still shows the break — it just no longer draws a
1151
+ * coloured pilcrow beside it. The merge is the fix for that; suppressing the glyph is not,
1152
+ * and must not be read as it.
1153
+ */
1154
+ readonly markRevisions?: readonly RevisionAttribution[];
1155
+ /**
1156
+ * The one decision a single-field reader sees, absent when there are none.
1157
+ *
1158
+ * Derived from {@link markRevisions} at publish time, never authored beside it, so the two
1159
+ * cannot disagree: a deletion when the mark carries one, because that is where the pair
1160
+ * lands once every decision is taken, and it is the face paint draws for the same reason.
1161
+ *
1162
+ * @deprecated Shows one of the decisions a mark can carry. Read {@link markRevisions}.
1083
1163
  */
1084
1164
  readonly markRevision?: RevisionAttribution;
1165
+ /**
1166
+ * The tracked FORMAT change on this paragraph's mark (`w:pPr/w:rPr/w:rPrChange`), absent
1167
+ * when there is none. Final fragment only, and `all-markup` only, like the decisions above.
1168
+ *
1169
+ * Published without a glyph of its own on purpose. Word draws no pilcrow for a mark whose
1170
+ * only change is its own formatting — the decision belongs to the review pane, which lists
1171
+ * it either way. What was missing was GEOMETRY: with nothing on the fragment, a card had
1172
+ * no place on the page to point at.
1173
+ */
1174
+ readonly markFormatRevision?: RevisionAttribution;
1085
1175
  /**
1086
1176
  * List marker painted in the hanging-indent slot of the FIRST fragment only.
1087
1177
  *
@@ -1400,6 +1490,14 @@ interface PageRecord {
1400
1490
  readonly sectionPageCount: number;
1401
1491
  readonly format?: string;
1402
1492
  };
1493
+ /**
1494
+ * `true` when this page's body flow (or a body table) carries a PAGE/NUMPAGES/SECTIONPAGES
1495
+ * placeholder that document finalize must substitute. Set when the page is assembled, so it
1496
+ * rides the record through incremental reuse. `false` lets `finalizePageFieldProjection` skip
1497
+ * the substitution walk; `undefined` (a page built by a path that does not stamp it) still
1498
+ * walks, which is safe.
1499
+ */
1500
+ readonly hasBodyPageFields?: boolean;
1403
1501
  /**
1404
1502
  * Content-control boundaries whose geometry intersects this page.
1405
1503
  *
@@ -1498,4 +1596,4 @@ declare function unionLayoutBoxes(boxes: readonly LayoutBox[]): LayoutBox | null
1498
1596
  /** Collapse raw + ancestor locks into one `ST_Lock` vocabulary value. */
1499
1597
  declare function effectiveContentControlLock(locks: readonly ContentControlLock[]): ContentControlLock;
1500
1598
 
1501
- export { type ParagraphBorderStrokeRecord as $, type AnchoredDrawingRecord as A, type BlockFragmentRecord as B, type ContentControlBoundaryRecord as C, type DrawingPoint as D, DEFAULT_TAB_INTERVAL_PT as E, DEFAULT_TAB_INTERVAL_TWIPS as F, EMPTY_TAB_STOPS as G, type FieldAtomMarker as H, type InlineDrawingRecord as I, type HeaderFooterStoryRecord as J, type LineSpacingRule as K, type LineRecord as L, type ModelRange as M, type ListMarkerRecord as N, MAX_BORDER_SPACE_PT as O, type PageGeometry as P, MAX_BORDER_WIDTH_PT as Q, type ResolvedRunStyle as R, type SemanticLayout as S, type TextMeasurer as T, MAX_PARAGRAPH_SPACING_PT as U, MAX_TABLE_BORDER_STROKES as V, MAX_TAB_POSITION_TWIPS as W, MAX_TAB_STOPS as X, PARAGRAPH_BORDER_SIDES as Y, type ParagraphAutoSpacingContext as Z, type ParagraphBorderSide as _, type StyleSpanRecord as a, type ParagraphBottomBorderRecord as a0, type ParagraphIndent as a1, type ResolvedCellBorders as a2, type ResolvedTableBorderEdge as a3, type ResolvedTableBorderEdgeSegment as a4, type ResolvedUnderline as a5, SINGLE_LINE_SPACING as a6, type SourceRange as a7, TAB_LEADER_GLYPH as a8, type TabAlignment as a9, paragraphBorderStrokeWidthPt as aA, paragraphBorders as aB, paragraphBordersFingerprint as aC, paragraphBreaksBefore as aD, paragraphContextualSpacing as aE, paragraphFragmentsOf as aF, paragraphFragmentsOfBlocks as aG, paragraphLineSpacing as aH, paragraphSpacing as aI, paragraphTabStops as aJ, readBorderSide as aK, readCellBorders as aL, readTableBorders as aM, resolveBorderConflict as aN, resolveRunStyle as aO, resolveTableCellBorderGrid as aP, runStylesEqual as aQ, tabAdvanceWidth as aR, tabStopsFingerprint as aS, unionLayoutBoxes as aT, withDefaultTabInterval as aU, type TabDestination as aa, type TabLeader as ab, type TabStop as ac, type TableBorderSideName as ad, type TableBorderStrokeRecord as ae, type TableFragmentRecord as af, type VerticalAlign as ag, appliedSpaceBefore as ah, applyLineSpacing as ai, baselineShiftPtOf as aj, borderExtentPt as ak, borderWeight as al, bottomBorderExtentPt as am, cascadedParagraphBorders as an, cascadedTabStops as ao, collapsedSpaceBefore as ap, contentControlsOfLayout as aq, defaultTabIntervalFromSettings as ar, displayText as as, effectiveContentControlLock as at, fragmentsOfParagraph as au, lineAtPosition as av, linesOf as aw, measureDisplayText as ax, nextTabDestination as ay, paragraphBorderExtentPt as az, type TableRowFragmentRecord as b, type TableCellFragmentRecord as c, type SpanLinkRecord as d, type LayoutBox as e, type DrawingInsets as f, type ThemeFonts as g, type ParagraphSpacing as h, type ParagraphLineSpacing as i, type ParagraphBorderEdge as j, type ParagraphBorders as k, type ResolvedTabStops as l, type TableBorderSide as m, type InlineDrawingLayoutContext as n, type PageRecord as o, type ParagraphFragmentRecord as p, type CellBorderBox as q, type TableBorderBox as r, AUTO_PARAGRAPH_SPACING_PT as s, type BorderGridGeometry as t, type ContentControlGeometryFragment as u, type ContentControlLevel as v, type ContentControlLock as w, type ContentControlMappedType as x, DEFAULT_PAGE_GEOMETRY as y, DEFAULT_RUN_STYLE as z };
1599
+ export { PARAGRAPH_BORDER_SIDES as $, type AnchoredDrawingRecord as A, type BlockFragmentRecord as B, type ContentControlBoundaryRecord as C, type DrawingPoint as D, DEFAULT_TAB_INTERVAL_PT as E, type FieldLinkProjector as F, DEFAULT_TAB_INTERVAL_TWIPS as G, type HyperlinkProjector as H, type InlineDrawingRecord as I, EMPTY_TAB_STOPS as J, type FieldAtomMarker as K, type LineRecord as L, type ModelRange as M, type HeaderFooterStoryRecord as N, type HyperlinkFieldSpec as O, type PageGeometry as P, type LineSpacingRule as Q, type ResolvedRunStyle as R, type SemanticLayout as S, type TextMeasurer as T, type ListMarkerRecord as U, MAX_BORDER_SPACE_PT as V, MAX_BORDER_WIDTH_PT as W, MAX_PARAGRAPH_SPACING_PT as X, MAX_TABLE_BORDER_STROKES as Y, MAX_TAB_POSITION_TWIPS as Z, MAX_TAB_STOPS as _, type StyleSpanRecord as a, type ParagraphAutoSpacingContext as a0, type ParagraphBorderSide as a1, type ParagraphBorderStrokeRecord as a2, type ParagraphBottomBorderRecord as a3, type ParagraphIndent as a4, type ResolvedCellBorders as a5, type ResolvedTableBorderEdge as a6, type ResolvedTableBorderEdgeSegment as a7, type ResolvedUnderline as a8, SINGLE_LINE_SPACING as a9, linesOf as aA, measureDisplayText as aB, nextTabDestination as aC, paragraphBorderExtentPt as aD, paragraphBorderStrokeWidthPt as aE, paragraphBorders as aF, paragraphBordersFingerprint as aG, paragraphBreaksBefore as aH, paragraphContextualSpacing as aI, paragraphFragmentsOf as aJ, paragraphFragmentsOfBlocks as aK, paragraphLineSpacing as aL, paragraphSpacing as aM, paragraphTabStops as aN, readBorderSide as aO, readCellBorders as aP, readTableBorders as aQ, resolveBorderConflict as aR, resolveRunStyle as aS, resolveTableCellBorderGrid as aT, runStylesEqual as aU, tabAdvanceWidth as aV, tabStopsFingerprint as aW, unionLayoutBoxes as aX, withDefaultTabInterval as aY, type SourceRange as aa, type SpanLinkRecord as ab, TAB_LEADER_GLYPH as ac, type TabAlignment as ad, type TabDestination as ae, type TabLeader as af, type TabStop as ag, type TableBorderSideName as ah, type TableBorderStrokeRecord as ai, type TableFragmentRecord as aj, type VerticalAlign as ak, appliedSpaceBefore as al, applyLineSpacing as am, baselineShiftPtOf as an, borderExtentPt as ao, borderWeight as ap, bottomBorderExtentPt as aq, cascadedParagraphBorders as ar, cascadedTabStops as as, collapsedSpaceBefore as at, contentControlsOfLayout as au, defaultTabIntervalFromSettings as av, displayText as aw, effectiveContentControlLock as ax, fragmentsOfParagraph as ay, lineAtPosition as az, type TableRowFragmentRecord as b, type TableCellFragmentRecord as c, type LayoutBox as d, type DrawingInsets as e, type ThemeFonts as f, type ParagraphSpacing as g, type ParagraphLineSpacing as h, type ParagraphBorderEdge as i, type ParagraphBorders as j, type ResolvedTabStops as k, type TableBorderSide as l, type InlineDrawingLayoutContext as m, type PageRecord as n, type ParagraphFragmentRecord as o, type StoryPageFieldNeeds as p, type CellBorderBox as q, type TableBorderBox as r, AUTO_PARAGRAPH_SPACING_PT as s, type BorderGridGeometry as t, type ContentControlGeometryFragment as u, type ContentControlLevel as v, type ContentControlLock as w, type ContentControlMappedType as x, DEFAULT_PAGE_GEOMETRY as y, DEFAULT_RUN_STYLE as z };
@@ -1,7 +1,7 @@
1
- import { O as OoxmlProperty, j as DrawingAccessibility, S as SourceCrop, k as DrawingTransform, V as VectorShapeProjection, f as DrawingHorizontalReferenceFrame, g as DrawingVerticalReferenceFrame, b as ImageWrapTarget, D as DrawingProjection, l as TableBorderStyle } from './tree-op-types-EZXbR8bW.cjs';
2
- import { O as OoxmlNode, o as OoxmlDrawingNode, a as OoxmlElement } from './ooxml-tree-BU0e3DVi.cjs';
3
- import { a as RevisionAttribution } from './revision-projection-72ZApe-g.cjs';
4
- import { I as ImageResourceState } from './image-resources-DXvPZvXD.cjs';
1
+ import { O as OoxmlProperty, k as DrawingAccessibility, S as SourceCrop, l as DrawingTransform, V as VectorShapeProjection, f as DrawingHorizontalReferenceFrame, g as DrawingVerticalReferenceFrame, b as ImageWrapTarget, D as DrawingProjection, m as TableBorderStyle } from './tree-op-types-DOYNkKqD.cjs';
2
+ import { O as OoxmlNode, q as OoxmlDrawingNode, a as OoxmlElement } from './ooxml-tree-CG0odFyi.cjs';
3
+ import { I as ImageResourceState } from './image-resources-CSlQmPIm.cjs';
4
+ import { a as RevisionAttribution } from './revision-projection-DRZMzoLD.cjs';
5
5
 
6
6
  /** Whether a paragraph must start a new page (`w:pageBreakBefore`). */
7
7
  declare function paragraphBreaksBefore(props: readonly OoxmlProperty[]): boolean;
@@ -429,6 +429,21 @@ declare function runStylesEqual(a: ResolvedRunStyle, b: ResolvedRunStyle): boole
429
429
  */
430
430
  declare function baselineShiftPtOf(style: ResolvedRunStyle): number;
431
431
 
432
+ type AllowlistedPageField = 'PAGE' | 'NUMPAGES' | 'SECTIONPAGES';
433
+ /**
434
+ * Which allowlisted page fields a header/footer story actually contains.
435
+ *
436
+ * Drives layout reuse: no fields → one baseline; NUMPAGES only → one layout per page count;
437
+ * SECTIONPAGES only → one layout per section page count; PAGE (alone or combined) → per
438
+ * distinct evaluated values with a bounded cache. Counts both complex markers and
439
+ * `w:fldSimple` (including an allowlisted page field nested inside a non-page simple field).
440
+ */
441
+ interface StoryPageFieldNeeds {
442
+ readonly hasPage: boolean;
443
+ readonly hasNumPages: boolean;
444
+ readonly hasSectionPages: boolean;
445
+ }
446
+
432
447
  interface DrawingPoint {
433
448
  readonly x: number;
434
449
  readonly y: number;
@@ -561,6 +576,21 @@ interface AnchoredDrawingRecord extends Omit<InlineDrawingRecord, 'kind' | 'base
561
576
  readonly textboxStory?: TextboxStoryLayout;
562
577
  }
563
578
 
579
+ /**
580
+ * One parsed `HYPERLINK` instruction: the raw, unsanitized pieces.
581
+ *
582
+ * `target` and `anchor` are verbatim from the instruction — the projector at the trust
583
+ * boundary decides what, if anything, they become in a DOM sink.
584
+ */
585
+ interface HyperlinkFieldSpec {
586
+ /** The target as authored (first quoted or bare non-switch token), or null. */
587
+ readonly target: string | null;
588
+ /** `\l` — a bookmark name in this document, or null. */
589
+ readonly anchor: string | null;
590
+ /** `\o` — the hover tooltip, or null. */
591
+ readonly tooltip: string | null;
592
+ }
593
+
564
594
  /**
565
595
  * What a piece says about the FIELD result it came from, for Word's shading.
566
596
  *
@@ -576,12 +606,40 @@ interface FieldAtomMarker {
576
606
  * turns it off — because they mark the blanks somebody is meant to fill in.
577
607
  */
578
608
  readonly formField: boolean;
609
+ /**
610
+ * A BODY PAGE / NUMPAGES / SECTIONPAGES atom whose value depends on pagination.
611
+ *
612
+ * The paragraph walk cannot know which page the field lands on — layout runs before the page
613
+ * count — so it paints a placeholder and records the field's kind here. Document finalize
614
+ * (`substituteBodyPageFields`) reads this marker and substitutes the real value per page.
615
+ * Absent in headers/footers, which evaluate live through their own per-page projector.
616
+ */
617
+ readonly pageField?: {
618
+ readonly kind: AllowlistedPageField;
619
+ };
579
620
  }
580
621
  /** A half-open model-offset range, in the paragraph's own UTF-16 offset space. */
581
622
  interface ModelRange {
582
623
  readonly start: number;
583
624
  readonly end: number;
584
625
  }
626
+ /**
627
+ * How layout turns a typed `w:hyperlink` node into the sanitized record spans carry.
628
+ *
629
+ * Injected rather than computed here because resolving `r:id` needs the PACKAGE's
630
+ * relationships and this module only ever sees one part's tree. `null` means the caller
631
+ * declined to project — the runs still measure and paint, they simply carry no link, which is
632
+ * the right degradation: text is never lost for want of a target.
633
+ */
634
+ type HyperlinkProjector = (link: OoxmlNode) => SpanLinkRecord | null;
635
+ /**
636
+ * How layout turns a parsed HYPERLINK field instruction into the sanitized record spans carry.
637
+ *
638
+ * Injected for the same reason as {@link HyperlinkProjector}: the spec's raw target must cross
639
+ * the surface's ONE href trust boundary, and layout owns no sanitization policy. `null` means
640
+ * no link — the cached result still paints as plain text, which is the right degradation.
641
+ */
642
+ type FieldLinkProjector = (spec: HyperlinkFieldSpec) => SpanLinkRecord | null;
585
643
 
586
644
  /** Test-only mutable counters; omitted by production call sites. Not package-public. */
587
645
  interface TableBorderGridResolveWork {
@@ -1073,15 +1131,47 @@ interface ParagraphFragmentRecord {
1073
1131
  */
1074
1132
  readonly shadingBox?: LayoutBox;
1075
1133
  /**
1076
- * The revision on this paragraph's own MARK (`w:pPr/w:rPr/w:ins|w:del`), absent when there
1077
- * is none.
1134
+ * The revisions on this paragraph's own MARK (`w:pPr/w:rPr/w:ins|w:del`), absent when there
1135
+ * are none.
1078
1136
  *
1079
- * Carried on the fragment rather than on a span because it decorates no characters: the
1137
+ * Carried on the fragment rather than on a span because they decorate no characters: the
1080
1138
  * pilcrow was inserted or deleted, which is how a split or a merge is recorded. Only the
1081
- * FINAL fragment carries it — the mark lives at the end of the paragraph, so a paragraph
1139
+ * FINAL fragment carries them — the mark lives at the end of the paragraph, so a paragraph
1082
1140
  * split across pages must not draw two of them.
1141
+ *
1142
+ * A LIST because one mark can hold two decisions at once — an insertion by one author and
1143
+ * a deletion of that insertion by the next. Published only in `all-markup`: the other two
1144
+ * display modes answer what the document WOULD be, and a resolved view draws no
1145
+ * attribution.
1146
+ *
1147
+ * Those two modes are ATTRIBUTION-resolved, not STRUCTURE-resolved. Taking a deleted mark
1148
+ * in `proposed` merges the paragraph into the next one, and taking an inserted mark in
1149
+ * `original` un-splits it, but `revision-visibility.ts` does that only for a paragraph that
1150
+ * renders no text. So a resolved view still shows the break — it just no longer draws a
1151
+ * coloured pilcrow beside it. The merge is the fix for that; suppressing the glyph is not,
1152
+ * and must not be read as it.
1153
+ */
1154
+ readonly markRevisions?: readonly RevisionAttribution[];
1155
+ /**
1156
+ * The one decision a single-field reader sees, absent when there are none.
1157
+ *
1158
+ * Derived from {@link markRevisions} at publish time, never authored beside it, so the two
1159
+ * cannot disagree: a deletion when the mark carries one, because that is where the pair
1160
+ * lands once every decision is taken, and it is the face paint draws for the same reason.
1161
+ *
1162
+ * @deprecated Shows one of the decisions a mark can carry. Read {@link markRevisions}.
1083
1163
  */
1084
1164
  readonly markRevision?: RevisionAttribution;
1165
+ /**
1166
+ * The tracked FORMAT change on this paragraph's mark (`w:pPr/w:rPr/w:rPrChange`), absent
1167
+ * when there is none. Final fragment only, and `all-markup` only, like the decisions above.
1168
+ *
1169
+ * Published without a glyph of its own on purpose. Word draws no pilcrow for a mark whose
1170
+ * only change is its own formatting — the decision belongs to the review pane, which lists
1171
+ * it either way. What was missing was GEOMETRY: with nothing on the fragment, a card had
1172
+ * no place on the page to point at.
1173
+ */
1174
+ readonly markFormatRevision?: RevisionAttribution;
1085
1175
  /**
1086
1176
  * List marker painted in the hanging-indent slot of the FIRST fragment only.
1087
1177
  *
@@ -1400,6 +1490,14 @@ interface PageRecord {
1400
1490
  readonly sectionPageCount: number;
1401
1491
  readonly format?: string;
1402
1492
  };
1493
+ /**
1494
+ * `true` when this page's body flow (or a body table) carries a PAGE/NUMPAGES/SECTIONPAGES
1495
+ * placeholder that document finalize must substitute. Set when the page is assembled, so it
1496
+ * rides the record through incremental reuse. `false` lets `finalizePageFieldProjection` skip
1497
+ * the substitution walk; `undefined` (a page built by a path that does not stamp it) still
1498
+ * walks, which is safe.
1499
+ */
1500
+ readonly hasBodyPageFields?: boolean;
1403
1501
  /**
1404
1502
  * Content-control boundaries whose geometry intersects this page.
1405
1503
  *
@@ -1498,4 +1596,4 @@ declare function unionLayoutBoxes(boxes: readonly LayoutBox[]): LayoutBox | null
1498
1596
  /** Collapse raw + ancestor locks into one `ST_Lock` vocabulary value. */
1499
1597
  declare function effectiveContentControlLock(locks: readonly ContentControlLock[]): ContentControlLock;
1500
1598
 
1501
- export { type ParagraphBorderStrokeRecord as $, type AnchoredDrawingRecord as A, type BlockFragmentRecord as B, type ContentControlBoundaryRecord as C, type DrawingPoint as D, DEFAULT_TAB_INTERVAL_PT as E, DEFAULT_TAB_INTERVAL_TWIPS as F, EMPTY_TAB_STOPS as G, type FieldAtomMarker as H, type InlineDrawingRecord as I, type HeaderFooterStoryRecord as J, type LineSpacingRule as K, type LineRecord as L, type ModelRange as M, type ListMarkerRecord as N, MAX_BORDER_SPACE_PT as O, type PageGeometry as P, MAX_BORDER_WIDTH_PT as Q, type ResolvedRunStyle as R, type SemanticLayout as S, type TextMeasurer as T, MAX_PARAGRAPH_SPACING_PT as U, MAX_TABLE_BORDER_STROKES as V, MAX_TAB_POSITION_TWIPS as W, MAX_TAB_STOPS as X, PARAGRAPH_BORDER_SIDES as Y, type ParagraphAutoSpacingContext as Z, type ParagraphBorderSide as _, type StyleSpanRecord as a, type ParagraphBottomBorderRecord as a0, type ParagraphIndent as a1, type ResolvedCellBorders as a2, type ResolvedTableBorderEdge as a3, type ResolvedTableBorderEdgeSegment as a4, type ResolvedUnderline as a5, SINGLE_LINE_SPACING as a6, type SourceRange as a7, TAB_LEADER_GLYPH as a8, type TabAlignment as a9, paragraphBorderStrokeWidthPt as aA, paragraphBorders as aB, paragraphBordersFingerprint as aC, paragraphBreaksBefore as aD, paragraphContextualSpacing as aE, paragraphFragmentsOf as aF, paragraphFragmentsOfBlocks as aG, paragraphLineSpacing as aH, paragraphSpacing as aI, paragraphTabStops as aJ, readBorderSide as aK, readCellBorders as aL, readTableBorders as aM, resolveBorderConflict as aN, resolveRunStyle as aO, resolveTableCellBorderGrid as aP, runStylesEqual as aQ, tabAdvanceWidth as aR, tabStopsFingerprint as aS, unionLayoutBoxes as aT, withDefaultTabInterval as aU, type TabDestination as aa, type TabLeader as ab, type TabStop as ac, type TableBorderSideName as ad, type TableBorderStrokeRecord as ae, type TableFragmentRecord as af, type VerticalAlign as ag, appliedSpaceBefore as ah, applyLineSpacing as ai, baselineShiftPtOf as aj, borderExtentPt as ak, borderWeight as al, bottomBorderExtentPt as am, cascadedParagraphBorders as an, cascadedTabStops as ao, collapsedSpaceBefore as ap, contentControlsOfLayout as aq, defaultTabIntervalFromSettings as ar, displayText as as, effectiveContentControlLock as at, fragmentsOfParagraph as au, lineAtPosition as av, linesOf as aw, measureDisplayText as ax, nextTabDestination as ay, paragraphBorderExtentPt as az, type TableRowFragmentRecord as b, type TableCellFragmentRecord as c, type SpanLinkRecord as d, type LayoutBox as e, type DrawingInsets as f, type ThemeFonts as g, type ParagraphSpacing as h, type ParagraphLineSpacing as i, type ParagraphBorderEdge as j, type ParagraphBorders as k, type ResolvedTabStops as l, type TableBorderSide as m, type InlineDrawingLayoutContext as n, type PageRecord as o, type ParagraphFragmentRecord as p, type CellBorderBox as q, type TableBorderBox as r, AUTO_PARAGRAPH_SPACING_PT as s, type BorderGridGeometry as t, type ContentControlGeometryFragment as u, type ContentControlLevel as v, type ContentControlLock as w, type ContentControlMappedType as x, DEFAULT_PAGE_GEOMETRY as y, DEFAULT_RUN_STYLE as z };
1599
+ export { PARAGRAPH_BORDER_SIDES as $, type AnchoredDrawingRecord as A, type BlockFragmentRecord as B, type ContentControlBoundaryRecord as C, type DrawingPoint as D, DEFAULT_TAB_INTERVAL_PT as E, type FieldLinkProjector as F, DEFAULT_TAB_INTERVAL_TWIPS as G, type HyperlinkProjector as H, type InlineDrawingRecord as I, EMPTY_TAB_STOPS as J, type FieldAtomMarker as K, type LineRecord as L, type ModelRange as M, type HeaderFooterStoryRecord as N, type HyperlinkFieldSpec as O, type PageGeometry as P, type LineSpacingRule as Q, type ResolvedRunStyle as R, type SemanticLayout as S, type TextMeasurer as T, type ListMarkerRecord as U, MAX_BORDER_SPACE_PT as V, MAX_BORDER_WIDTH_PT as W, MAX_PARAGRAPH_SPACING_PT as X, MAX_TABLE_BORDER_STROKES as Y, MAX_TAB_POSITION_TWIPS as Z, MAX_TAB_STOPS as _, type StyleSpanRecord as a, type ParagraphAutoSpacingContext as a0, type ParagraphBorderSide as a1, type ParagraphBorderStrokeRecord as a2, type ParagraphBottomBorderRecord as a3, type ParagraphIndent as a4, type ResolvedCellBorders as a5, type ResolvedTableBorderEdge as a6, type ResolvedTableBorderEdgeSegment as a7, type ResolvedUnderline as a8, SINGLE_LINE_SPACING as a9, linesOf as aA, measureDisplayText as aB, nextTabDestination as aC, paragraphBorderExtentPt as aD, paragraphBorderStrokeWidthPt as aE, paragraphBorders as aF, paragraphBordersFingerprint as aG, paragraphBreaksBefore as aH, paragraphContextualSpacing as aI, paragraphFragmentsOf as aJ, paragraphFragmentsOfBlocks as aK, paragraphLineSpacing as aL, paragraphSpacing as aM, paragraphTabStops as aN, readBorderSide as aO, readCellBorders as aP, readTableBorders as aQ, resolveBorderConflict as aR, resolveRunStyle as aS, resolveTableCellBorderGrid as aT, runStylesEqual as aU, tabAdvanceWidth as aV, tabStopsFingerprint as aW, unionLayoutBoxes as aX, withDefaultTabInterval as aY, type SourceRange as aa, type SpanLinkRecord as ab, TAB_LEADER_GLYPH as ac, type TabAlignment as ad, type TabDestination as ae, type TabLeader as af, type TabStop as ag, type TableBorderSideName as ah, type TableBorderStrokeRecord as ai, type TableFragmentRecord as aj, type VerticalAlign as ak, appliedSpaceBefore as al, applyLineSpacing as am, baselineShiftPtOf as an, borderExtentPt as ao, borderWeight as ap, bottomBorderExtentPt as aq, cascadedParagraphBorders as ar, cascadedTabStops as as, collapsedSpaceBefore as at, contentControlsOfLayout as au, defaultTabIntervalFromSettings as av, displayText as aw, effectiveContentControlLock as ax, fragmentsOfParagraph as ay, lineAtPosition as az, type TableRowFragmentRecord as b, type TableCellFragmentRecord as c, type LayoutBox as d, type DrawingInsets as e, type ThemeFonts as f, type ParagraphSpacing as g, type ParagraphLineSpacing as h, type ParagraphBorderEdge as i, type ParagraphBorders as j, type ResolvedTabStops as k, type TableBorderSide as l, type InlineDrawingLayoutContext as m, type PageRecord as n, type ParagraphFragmentRecord as o, type StoryPageFieldNeeds as p, type CellBorderBox as q, type TableBorderBox as r, AUTO_PARAGRAPH_SPACING_PT as s, type BorderGridGeometry as t, type ContentControlGeometryFragment as u, type ContentControlLevel as v, type ContentControlLock as w, type ContentControlMappedType as x, DEFAULT_PAGE_GEOMETRY as y, DEFAULT_RUN_STYLE as z };
@@ -1,4 +1,4 @@
1
- import { R as ResolvedRunStyle, T as TextMeasurer } from './semantic-records-CR5hTqMK.js';
1
+ import { R as ResolvedRunStyle, T as TextMeasurer } from './semantic-records-B-qbrnp2.js';
2
2
 
3
3
  /**
4
4
  * A face, as something asks for it: family plus the two axes this engine admits.
@@ -1,4 +1,4 @@
1
- import { R as ResolvedRunStyle, T as TextMeasurer } from './semantic-records-DSD8WENa.cjs';
1
+ import { R as ResolvedRunStyle, T as TextMeasurer } from './semantic-records-Dq8SlCY8.cjs';
2
2
 
3
3
  /**
4
4
  * A face, as something asks for it: family plus the two axes this engine admits.