@docx-editor.dev/core 2.0.1 → 2.1.1

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 (107) hide show
  1. package/README.md +32 -33
  2. package/dist/automation.cjs +1 -1
  3. package/dist/automation.d.cts +2 -2
  4. package/dist/automation.d.ts +2 -2
  5. package/dist/automation.js +1 -1
  6. package/dist/binding.cjs +1 -1
  7. package/dist/binding.d.cts +14 -8
  8. package/dist/binding.d.ts +14 -8
  9. package/dist/binding.js +1 -1
  10. package/dist/chunk-2DTQDAN7.js +2 -0
  11. package/dist/chunk-3JKQE4QJ.cjs +2 -0
  12. package/dist/chunk-4WWEDTTE.js +2 -0
  13. package/dist/chunk-6WIIHJFY.js +1 -0
  14. package/dist/chunk-7VQ7YLW3.cjs +1 -0
  15. package/dist/chunk-BS554B6D.cjs +2 -0
  16. package/dist/chunk-BZK64YU3.cjs +10 -0
  17. package/dist/chunk-F2VQQW5R.cjs +12 -0
  18. package/dist/chunk-GQQOL4PV.js +1 -0
  19. package/dist/chunk-JQFDLZXQ.cjs +2 -0
  20. package/dist/chunk-O2WQY7IT.cjs +5 -0
  21. package/dist/chunk-PC76F2HR.cjs +1 -0
  22. package/dist/chunk-QRAUDDVY.js +2 -0
  23. package/dist/chunk-RKNH4ZFT.js +12 -0
  24. package/dist/chunk-STCITBJK.js +12 -0
  25. package/dist/chunk-TBBXCC7D.js +5 -0
  26. package/dist/chunk-TSXT537P.cjs +12 -0
  27. package/dist/chunk-Y7TA7TPF.js +10 -0
  28. package/dist/contracts/editor.d.cts +6 -6
  29. package/dist/contracts/editor.d.ts +6 -6
  30. package/dist/contracts/interaction.d.cts +6 -6
  31. package/dist/contracts/interaction.d.ts +6 -6
  32. package/dist/contracts/modules.cjs +1 -1
  33. package/dist/contracts/modules.d.cts +30 -3
  34. package/dist/contracts/modules.d.ts +30 -3
  35. package/dist/contracts/modules.js +1 -1
  36. package/dist/{tree-package-store-DOKMtCnh.d.cts → custom-node-writes-YqISlSRl.d.cts} +181 -4
  37. package/dist/{tree-package-store-D5S7VKs5.d.ts → custom-node-writes-ttKuYd0M.d.ts} +181 -4
  38. package/dist/{editor-D0UDock4.d.cts → editor-B93PggnR.d.cts} +24 -5
  39. package/dist/{editor-C1QRi1v4.d.ts → editor-CFsSrxGR.d.ts} +24 -5
  40. package/dist/editor.cjs +1 -1
  41. package/dist/editor.css +1368 -279
  42. package/dist/editor.d.cts +19 -19
  43. package/dist/editor.d.ts +19 -19
  44. package/dist/editor.js +1 -1
  45. package/dist/{image-resources-BJnTpG66.d.ts → image-resources-C_YnqPhn.d.ts} +19 -11
  46. package/dist/{image-resources-BpIydXtU.d.cts → image-resources-DwpNnTg3.d.cts} +19 -11
  47. package/dist/{index-CrW-IxXt.d.cts → index-DQhDm4o0.d.cts} +34 -13
  48. package/dist/{index-ZqBEOrTV.d.ts → index-DTbKoFJL.d.ts} +34 -13
  49. package/dist/index.cjs +1 -1
  50. package/dist/index.d.cts +13 -13
  51. package/dist/index.d.ts +13 -13
  52. package/dist/index.js +1 -1
  53. package/dist/layout.cjs +1 -1
  54. package/dist/layout.d.cts +869 -819
  55. package/dist/layout.d.ts +869 -819
  56. package/dist/layout.js +1 -1
  57. package/dist/output.cjs +1 -1
  58. package/dist/output.d.cts +4 -4
  59. package/dist/output.d.ts +4 -4
  60. package/dist/output.js +1 -1
  61. package/dist/{protocol-oxHaWmt4.d.ts → protocol-BWVA3Q1p.d.ts} +56 -2
  62. package/dist/{protocol-CAkOBBGE.d.cts → protocol-FAz_nPm_.d.cts} +56 -2
  63. package/dist/review-reads-CsoXSvUg.d.ts +401 -0
  64. package/dist/review-reads-qW0jvdF1.d.cts +401 -0
  65. package/dist/{review-support-DS8DYX2a.d.cts → review-support-D64Wu236.d.cts} +37 -5
  66. package/dist/{review-support-Fy3vdIea.d.ts → review-support-nsLXC9jf.d.ts} +37 -5
  67. package/dist/{semantic-cell-selection-DsmHmLJ5.d.ts → semantic-cell-selection-D_8RbPII.d.ts} +2 -2
  68. package/dist/{semantic-cell-selection-CZjBSmMv.d.cts → semantic-cell-selection-DwLB71fF.d.cts} +2 -2
  69. package/dist/{semantic-interaction-Dy-dCUFF.d.ts → semantic-interaction-CXH2wFqi.d.ts} +1 -1
  70. package/dist/{semantic-interaction-D-Dszxrn.d.cts → semantic-interaction-DqcEonqD.d.cts} +1 -1
  71. package/dist/{semantic-paint-drawings-BA3z9jl8.d.ts → semantic-paint-drawings-B5Wk2so5.d.ts} +1 -1
  72. package/dist/{semantic-paint-drawings-D7qbB0E2.d.cts → semantic-paint-drawings-x8g44lD_.d.cts} +1 -1
  73. package/dist/{semantic-records-CJR3BvHs.d.cts → semantic-records-COVFW5aS.d.cts} +77 -4
  74. package/dist/{semantic-records-CWodBJsz.d.ts → semantic-records-zTC0_1zi.d.ts} +77 -4
  75. package/dist/{shaped-measurer-CNIT_svZ.d.cts → shaped-measurer-AFnFxoot.d.cts} +1 -1
  76. package/dist/{shaped-measurer-B-TAtcQU.d.ts → shaped-measurer-CZXL-a6v.d.ts} +1 -1
  77. package/dist/store.cjs +1 -1
  78. package/dist/store.d.cts +223 -317
  79. package/dist/store.d.ts +223 -317
  80. package/dist/store.js +1 -1
  81. package/dist/{tree-op-types-CwOeiaQ8.d.ts → tree-op-types-DWLCllG7.d.ts} +80 -25
  82. package/dist/{tree-op-types-DMiW6nIH.d.cts → tree-op-types-UOXlRUqQ.d.cts} +80 -25
  83. package/dist/{tree-session-CiUel5Kz.d.ts → tree-session-BtVFXsF6.d.ts} +45 -7
  84. package/dist/{tree-session-D47_imvR.d.cts → tree-session-DxIOHUOD.d.cts} +45 -7
  85. package/dist/{tree-store-CxifqwIv.d.cts → tree-store-B1lEkdXc.d.cts} +1 -1
  86. package/dist/{tree-store-hLtjeyWE.d.ts → tree-store-BscFPB7x.d.ts} +1 -1
  87. package/package.json +10 -5
  88. package/dist/chunk-5KSCB2OZ.js +0 -2
  89. package/dist/chunk-BSC44TIT.js +0 -5
  90. package/dist/chunk-DLPL5DAG.js +0 -12
  91. package/dist/chunk-DOEIARE2.js +0 -2
  92. package/dist/chunk-G7YCQBZE.cjs +0 -5
  93. package/dist/chunk-HR7K3W6A.js +0 -1
  94. package/dist/chunk-HVAV2JSN.js +0 -11
  95. package/dist/chunk-MYH2HCUJ.cjs +0 -2
  96. package/dist/chunk-NSM75TN6.cjs +0 -1
  97. package/dist/chunk-PHDVKUWZ.js +0 -1
  98. package/dist/chunk-QADYGK5L.cjs +0 -12
  99. package/dist/chunk-RNBHTPW7.js +0 -10
  100. package/dist/chunk-UD2ZXLFI.cjs +0 -2
  101. package/dist/chunk-VYAVK2AH.cjs +0 -1
  102. package/dist/chunk-YUK46A2N.cjs +0 -11
  103. package/dist/chunk-ZMIX42J7.cjs +0 -10
  104. package/dist/chunk-ZT55Q52J.cjs +0 -2
  105. package/dist/chunk-ZUALAR4M.js +0 -2
  106. package/dist/note-properties-CnmCoory.d.cts +0 -68
  107. package/dist/note-properties-m75hmP70.d.ts +0 -68
@@ -0,0 +1,401 @@
1
+ import { e as OoxmlPart, O as OoxmlNode, a as OoxmlElement } from './ooxml-tree-BU0e3DVi.cjs';
2
+ import { O as OoxmlPackage } from './ooxml-package-CR5us6ad.cjs';
3
+ import { R as RevisionAddress } from './tree-op-types-UOXlRUqQ.cjs';
4
+
5
+ /** `w:pos` — where a section's footnotes are laid out. */
6
+ type FootnotePosition = 'pageBottom' | 'beneathText' | 'sectEnd' | 'docEnd';
7
+ /** `w:pos` for endnotes — only the two document-level placements are legal. */
8
+ type EndnotePosition = 'sectEnd' | 'docEnd';
9
+ /** `w:numRestart` — when note numbering starts over. `eachPage` needs the reference's page. */
10
+ type NoteNumRestart = 'continuous' | 'eachSect' | 'eachPage';
11
+ /** Authored subset — only keys present in the file appear. */
12
+ interface AuthoredNoteProperties {
13
+ readonly pos?: string;
14
+ readonly numFmt?: string;
15
+ readonly numStart?: number;
16
+ readonly numRestart?: string;
17
+ }
18
+ /** Fully resolved footnote properties (defaults filled). */
19
+ interface ResolvedFootnoteProperties {
20
+ readonly pos: FootnotePosition;
21
+ readonly numFmt: string;
22
+ readonly numStart: number;
23
+ readonly numRestart: NoteNumRestart;
24
+ }
25
+ /** Fully resolved endnote properties (defaults filled). */
26
+ interface ResolvedEndnoteProperties {
27
+ readonly pos: EndnotePosition;
28
+ readonly numFmt: string;
29
+ readonly numStart: number;
30
+ readonly numRestart: NoteNumRestart;
31
+ }
32
+ /** Word's own footnote defaults, applied where a section declares no `w:footnotePr`. */
33
+ declare const DEFAULT_FOOTNOTE_PROPERTIES: ResolvedFootnoteProperties;
34
+ /**
35
+ * Word-compatible defaults. ECMA-376 says omitted endnote `numFmt` is decimal;
36
+ * MS-OE376 / MS-OI29500 document that Word’s default is `lowerRoman` instead.
37
+ * Resolved (not authored) — unedited packages still invent nothing on save.
38
+ */
39
+ declare const DEFAULT_ENDNOTE_PROPERTIES: ResolvedEndnoteProperties;
40
+ /** Parse authored CT_FtnProps / CT_EdnProps without inventing defaults. */
41
+ declare function parseAuthoredNoteProperties(propsNode: OoxmlNode | null | undefined): AuthoredNoteProperties | undefined;
42
+ /** Authored footnotePr on a sectPr node. */
43
+ declare function authoredFootnotePropertiesFromSectPr(sectPr: OoxmlNode | null | undefined): AuthoredNoteProperties | undefined;
44
+ /** Authored endnotePr on a sectPr node. */
45
+ declare function authoredEndnotePropertiesFromSectPr(sectPr: OoxmlNode | null | undefined): AuthoredNoteProperties | undefined;
46
+ /** Locate settings.xml via the main document relationship when present. */
47
+ declare function settingsPartOf(pkg: OoxmlPackage): OoxmlPart | null;
48
+ /** Authored document-level footnotePr from settings. */
49
+ declare function authoredDocumentFootnoteProperties(settings: OoxmlPart | null | undefined): AuthoredNoteProperties | undefined;
50
+ /** Authored document-level endnotePr from settings. */
51
+ declare function authoredDocumentEndnoteProperties(settings: OoxmlPart | null | undefined): AuthoredNoteProperties | undefined;
52
+ /**
53
+ * Resolve footnote properties: section → document → defaults.
54
+ * Illegal position strings fall through to the next layer / default.
55
+ */
56
+ declare function resolveFootnoteProperties(section?: AuthoredNoteProperties, document?: AuthoredNoteProperties): ResolvedFootnoteProperties;
57
+ /**
58
+ * Resolve endnote properties: section → document → defaults.
59
+ * `pageBottom` is never a legal endnote position — falls back.
60
+ */
61
+ declare function resolveEndnoteProperties(section?: AuthoredNoteProperties, document?: AuthoredNoteProperties): ResolvedEndnoteProperties;
62
+ /** Validate an authored endnote position write — refuse `pageBottom`. */
63
+ declare function isLegalEndnotePosition(pos: string): pos is EndnotePosition;
64
+ /** Validate an authored footnote position write. */
65
+ declare function isLegalFootnotePosition(pos: string): pos is FootnotePosition;
66
+ /** Whether a file-supplied string is a legal `w:numRestart` value. Narrows the type. */
67
+ declare function isLegalNumRestart(value: string): value is NoteNumRestart;
68
+
69
+ /** The `w15` namespace: `commentsExtended.xml` — thread parent and resolved state. */
70
+ declare const W15_NAMESPACE_URI = "http://schemas.microsoft.com/office/word/2012/wordml";
71
+ /** A position in one story: a paragraph node id plus a UTF-16 offset inside it. */
72
+ interface CommentPosition {
73
+ readonly paragraphId: string;
74
+ readonly offset: number;
75
+ }
76
+ /**
77
+ * Where a comment is anchored, as a range.
78
+ *
79
+ * `orphaned` records that the file did not give this comment a usable range — a reference with
80
+ * no range markers, or a start with no end. The comment is still listed, marked orphaned,
81
+ * rather than dropped: a reviewer's remark disappearing silently is worse than one that says
82
+ * it lost its text.
83
+ */
84
+ interface CommentAnchor {
85
+ readonly commentId: string;
86
+ /** Canonical name of the part the range lives in, so a header comment is attributable. */
87
+ readonly partName: string;
88
+ readonly start: CommentPosition;
89
+ readonly end: CommentPosition;
90
+ readonly orphaned: boolean;
91
+ }
92
+ /** One comment as authored in `word/comments.xml`. */
93
+ interface CommentRecord {
94
+ readonly id: string;
95
+ readonly author: string;
96
+ readonly initials?: string;
97
+ readonly date?: string;
98
+ /** Body paragraphs, as tree nodes, so the surface renders measured text rather than a string. */
99
+ readonly blocks: readonly OoxmlElement[];
100
+ /** `w14:paraId` of the first body paragraph — the key thread state is stored under. */
101
+ readonly paraId?: string;
102
+ /** `@w16cid:parentId` — the `w:id` of the comment this replies to, when the file names it. */
103
+ readonly parentCommentId?: string;
104
+ }
105
+ /** Thread state for one comment, read from `commentsExtended.xml`. */
106
+ interface CommentThreadState {
107
+ /** `@w15:paraIdParent` — the comment this one replies to, absent for a top-level comment. */
108
+ readonly parentParaId?: string;
109
+ readonly done: boolean;
110
+ }
111
+ /**
112
+ * Every comment anchor in one story, in document order.
113
+ *
114
+ * Overlapping and nested ranges are supported because each anchor is resolved independently —
115
+ * Word produces both, and a model that assumed ranges nest cleanly would mis-anchor them.
116
+ *
117
+ * A start with no matching end anchors to the end of its own paragraph and is reported orphaned
118
+ * rather than guessed at: extending it to the next end marker would attach a reviewer's remark
119
+ * to text they never saw.
120
+ */
121
+ declare function commentAnchorsOfStory(part: OoxmlPart): CommentAnchor[];
122
+ /**
123
+ * The comments in `word/comments.xml`, in authored order.
124
+ *
125
+ * Every value here comes from a file an attacker fully controls, so nothing is interpreted:
126
+ * author, initials and date are carried verbatim for a surface that will set them as TEXT.
127
+ */
128
+ declare function commentsOfPart(part: OoxmlPart): CommentRecord[];
129
+ /**
130
+ * Thread state by `w14:paraId`, from `commentsExtended.xml`.
131
+ *
132
+ * The part being PRESENT is not evidence of threading. `issue-68-large-comments-suggestions.docx`
133
+ * ships it with 212 entries carrying `@w15:done` and not one `@w15:paraIdParent`, so it records
134
+ * resolved state for a flat list. Absent parent means top-level, and that is a fact about the
135
+ * file rather than a default this code chose.
136
+ */
137
+ declare function threadStateOfPart(part: OoxmlPart): Map<string, CommentThreadState>;
138
+
139
+ /** A position in the model offset space of one story. */
140
+ interface ReviewPosition {
141
+ readonly paragraphId: string;
142
+ readonly offset: number;
143
+ }
144
+ /** Where an item is anchored: a range in one story. */
145
+ interface ReviewRange {
146
+ readonly partName: string;
147
+ readonly start: ReviewPosition;
148
+ readonly end: ReviewPosition;
149
+ }
150
+ /**
151
+ * What kind of decision a revision card represents.
152
+ *
153
+ * Wider than the four content wrappers, because a reviewer has to be shown every pending
154
+ * decision, including the ones that decorate no characters. A card the surface cannot show is
155
+ * a change the reviewer never learns about — and `acceptAllRevisions` refuses if ANY revision
156
+ * in the document is one the engine cannot resolve, so an invisible one makes Accept All fail
157
+ * for a reason nothing on screen explains.
158
+ */
159
+ type ReviewRevisionKind = 'insert' | 'delete'
160
+ /**
161
+ * A deletion and an insertion that are one edit: text typed over a selection.
162
+ *
163
+ * Word shows these as a single `Replaced "x" with "y"` card, and resolving one half
164
+ * without the other is never what the reviewer meant — accepting the deletion alone
165
+ * leaves the replacement text unproposed, rejecting it alone leaves both.
166
+ */
167
+ | 'replace' | 'moveFrom' | 'moveTo'
168
+ /** `w:rPrChange` / `w:pPrChange` — the words are unchanged, their formatting is not. */
169
+ | 'format'
170
+ /** `w:pPr/w:rPr/w:ins|w:del` — a paragraph split or merge. */
171
+ | 'paragraphMark'
172
+ /** A row, cell, section or grid revision. Supported row revisions are resolvable. */
173
+ | 'structural';
174
+ /** One tracked change as the store derives it, keyed per decision rather than per site. */
175
+ interface ReviewRevisionItem {
176
+ readonly kind: 'revision';
177
+ /** Stable across renders and unique per DECISION, not per site. */
178
+ readonly id: string;
179
+ /** The payload `acceptRevision` / `rejectRevision` take. */
180
+ readonly address: RevisionAddress;
181
+ /**
182
+ * EVERY address this decision covers, `address` first.
183
+ *
184
+ * More than one only for a replacement, whose halves a foreign editor may have written
185
+ * as two independent revisions. Accept and reject walk all of them in one transaction:
186
+ * resolving one half and leaving the other is a state no reviewer asked for.
187
+ */
188
+ readonly addresses: readonly RevisionAddress[];
189
+ /** The words a replacement removes. Empty for every other kind. */
190
+ readonly replacedText: string;
191
+ readonly revisionKind: ReviewRevisionKind;
192
+ readonly author: string;
193
+ readonly date?: string;
194
+ /** Text the revision covers, for the card summary. Empty for changes with no characters. */
195
+ readonly text: string;
196
+ /** Every site this decision touches, in document order. */
197
+ readonly ranges: readonly ReviewRange[];
198
+ /**
199
+ * How many leading `ranges` are the STRUCK half of a replacement.
200
+ *
201
+ * A replacement's card is one decision but its ranges are two colours — red over what is
202
+ * going, green over what takes its place. ABSENT when the halves do not split at a single
203
+ * point, which is what a file recording both under one revision id can produce; a surface
204
+ * then has no basis for two colours and should paint one neutral band rather than guess.
205
+ */
206
+ readonly replacedRangeCount?: number;
207
+ /**
208
+ * True when the engine cannot resolve this kind, so accept and reject must not be offered.
209
+ *
210
+ * Derived HERE rather than from a caller-supplied predicate: the refusal list is internal,
211
+ * and a surface asked to compute it would have to guess. A card that offers a button the
212
+ * engine will refuse is worse than one that explains why it cannot.
213
+ */
214
+ readonly readOnly: boolean;
215
+ /** The other half of a move, or the other side of a delete/insert replacement. */
216
+ readonly pairedWith?: string;
217
+ /**
218
+ * Comments answering this change, in document order.
219
+ *
220
+ * A reply to a tracked change IS a comment: `w:ins` and `w:del` carry `(@w:id, @w:author,
221
+ * @w:date)` and no body, so `replyToReviewItem` writes the text as a comment over the
222
+ * revision's own range. Nothing recorded the link, so the reply came back as a separate
223
+ * card — the reader saw their answer detach from the change it answered. The range is the
224
+ * link, and it is the same evidence `commentItemsOf` threads coincident comments on.
225
+ */
226
+ readonly replyIds: readonly string[];
227
+ }
228
+ /** One comment as the store derives it, with its thread links resolved. */
229
+ interface ReviewCommentItem {
230
+ readonly kind: 'comment';
231
+ readonly id: string;
232
+ readonly comment: CommentRecord;
233
+ readonly range: ReviewRange | null;
234
+ readonly resolved: boolean;
235
+ /** The comment this replies to, absent for a top-level comment. */
236
+ readonly parentId?: string;
237
+ /**
238
+ * The REVISION this comment answers, when it covers exactly that change's characters.
239
+ *
240
+ * Separate from {@link parentId} rather than folded into it: the two name different item
241
+ * kinds, and a surface resolving one id against the comment index would find nothing.
242
+ */
243
+ readonly parentRevisionId?: string;
244
+ /** Replies to this comment, in document order. Empty for a reply or a childless comment. */
245
+ readonly replyIds: readonly string[];
246
+ /** True when the file gave this comment no usable range. */
247
+ readonly orphaned: boolean;
248
+ }
249
+ /**
250
+ * One pending decision as the STORE derives it: a tracked change or a comment. Discriminate on
251
+ * `kind`.
252
+ *
253
+ * The layout layer's own `ReviewItem` widens this with the pro custom-node card, which has no
254
+ * store representation.
255
+ */
256
+ type ReviewItem = ReviewRevisionItem | ReviewCommentItem;
257
+ /** The stable key a surface uses for the active item and for a React list. */
258
+ declare function reviewItemKey(item: ReviewItem): string;
259
+ /** Plain text of a comment's body, so a card never re-implements the run walk. */
260
+ declare function commentBodyText(comment: CommentRecord): string;
261
+ /** Author initials for an avatar, from `@w:initials` or the name. */
262
+ declare function commentInitials(comment: CommentRecord): string;
263
+ /**
264
+ * Every revision in one story, one card per DECISION.
265
+ *
266
+ * Sites sharing an `(id, author, date)` triple are ONE revision — a tracked row insertion is
267
+ * `w:trPr/w:ins` plus `w:cellIns` on every cell — so they coalesce into one card listing every
268
+ * range it touches. Keying per site would show the reviewer four decisions where there is one,
269
+ * and accepting any of them would make the other three vanish.
270
+ *
271
+ * Memoized per part root like the indexes it reads, and for the same reason: a heavily
272
+ * tracked document produces tens of thousands of cards, and rebuilding them per read cost
273
+ * more than everything the memos above saved. The paragraph-scoped view the local review
274
+ * patch derives (`revisionItemsOfParagraph`'s synthetic paragraph-root part) is NOT cached:
275
+ * each keystroke would insert a fresh root and churn the bounded ring. The instance is
276
+ * SHARED, so the return type is readonly.
277
+ */
278
+ declare function revisionItemsOf(part: OoxmlPart): readonly ReviewRevisionItem[];
279
+ /**
280
+ * Comment cards, threaded however the file says so and flat when nothing says so.
281
+ *
282
+ * ECMA-376 §17.13.4.2 gives `CT_Comment` no parent pointer, so threading is never something
283
+ * the standard states outright. Three sources, strongest first: `@w15:paraIdParent`, then
284
+ * `@w16cid:parentId` — both in namespaces outside Part 1 — and finally a COINCIDENT anchor, a
285
+ * comment whose `w:commentRangeStart`/`End` cover exactly the characters an earlier comment's
286
+ * cover. The ranges are Part 1's own vocabulary and the only part of a thread that survives a
287
+ * producer dropping the extension parts. Coincidence is the last resort and never overrides a
288
+ * stated link.
289
+ *
290
+ * Deliberately not containment. A remark on one word inside another remark's sentence nests
291
+ * without being a reply, and reading that as a thread would bury an independent comment inside
292
+ * someone else's.
293
+ */
294
+ declare function commentItemsOf(comments: readonly CommentRecord[], anchors: readonly {
295
+ commentId: string;
296
+ partName: string;
297
+ start: ReviewPosition;
298
+ end: ReviewPosition;
299
+ orphaned: boolean;
300
+ }[], threadState: ReadonlyMap<string, CommentThreadState>): ReviewCommentItem[];
301
+ /** What review derivation reads: one story part plus its comment parts. */
302
+ interface ReviewModelInput {
303
+ /** The story the ranges live in — the main document, a header, a note. */
304
+ readonly storyPart: OoxmlPart;
305
+ /**
306
+ * Header/footer story parts, in section order. Their revisions and comment anchors join
307
+ * the queue: a tracked change in a header is a pending decision like any other, and a
308
+ * queue that only walked the body silently hid it from the rail AND from Accept All.
309
+ */
310
+ readonly furnitureParts?: readonly OoxmlPart[] | undefined;
311
+ /** `word/comments.xml`, absent when the package has none. */
312
+ readonly commentsPart?: OoxmlPart | undefined;
313
+ /** `word/commentsExtended.xml`, absent when the package has none. */
314
+ readonly commentsExtendedPart?: OoxmlPart | undefined;
315
+ }
316
+ /**
317
+ * Everything the review surface lists, in document order.
318
+ *
319
+ * Order is by paragraph position within the story, then by offset. A comment and the revision
320
+ * it covers therefore arrive together, which is what lets a surface group them. Furniture
321
+ * stories rank after the body in one merged order — their geometry (the page they first paint
322
+ * on) is a layout question the queue deliberately does not answer.
323
+ */
324
+ declare function collectReviewItems(input: ReviewModelInput): ReviewItem[];
325
+ /**
326
+ * The shape {@link linkRevisionReplies} needs, stated STRUCTURALLY.
327
+ *
328
+ * The store's queue is revisions and comments; the layout lane's adds a third kind for custom
329
+ * nodes, and neither union is assignable to the other. Both lanes have to run this pass — the
330
+ * store on the full derivation, the session on the locally patched list — so the pass is
331
+ * written against the fields it actually reads rather than against either union, and hands
332
+ * back the caller's own item type.
333
+ */
334
+ interface LinkableReviewItem {
335
+ readonly kind: string;
336
+ readonly id: string;
337
+ readonly ranges?: readonly ReviewRange[];
338
+ readonly range?: ReviewRange | null;
339
+ readonly parentId?: string;
340
+ readonly parentRevisionId?: string;
341
+ readonly replyIds?: readonly string[];
342
+ readonly orphaned?: boolean;
343
+ }
344
+ /**
345
+ * Attach each comment that answers a tracked change to the change it answers.
346
+ *
347
+ * The evidence is the RANGE, exactly as it is for a coincident comment thread: replying to a
348
+ * revision writes a comment over that revision's own characters, because OOXML gives `w:ins`
349
+ * and `w:del` nowhere else to put the text. Without this the reply came back as an independent
350
+ * card in the rail, sitting beside the change rather than inside it, and the reader had no way
351
+ * to see which change their answer belonged to.
352
+ *
353
+ * Three things keep it from over-claiming. A ZERO-WIDTH range is evidence of nothing — the same
354
+ * rule the comment threading uses, and a format or paragraph-mark revision decorates no
355
+ * characters at all. A comment already stated to be a REPLY to another comment is not claimed
356
+ * directly, because a stated link always beats an inferred one. And the FIRST revision on a span
357
+ * wins, so a card cannot claim a reply another card already holds.
358
+ *
359
+ * The WHOLE conversation moves, not its head. A change's card renders `replyIds` as a flat list,
360
+ * so linking only the top comment of a thread left every answer to that answer rendered by
361
+ * nobody: reply twice to one change and the second reply existed in `comments.xml` and appeared
362
+ * nowhere on screen. Descendants ride along, in the order they were authored.
363
+ *
364
+ * IDEMPOTENT, and that is load-bearing. The session re-runs this over a list whose comments are
365
+ * ALREADY linked, so a pass that only ever added links left a stale `parentRevisionId` behind
366
+ * when a keystroke shifted the revision's offsets out from under it — the rail filters such a
367
+ * comment out of its roots, and with no revision claiming it any more the card vanished until
368
+ * the next full re-derivation. Every link is rebuilt from the ranges on every pass.
369
+ */
370
+ declare function linkRevisionReplies<T extends LinkableReviewItem>(items: readonly T[]): T[];
371
+ /**
372
+ * Paragraph node id → document position, from the TREE rather than from a layout.
373
+ *
374
+ * Memoized on the immutable root: one full derivation pass asks this question three times
375
+ * (replacement pairing, the queue's merged order, the session's cached order), and each
376
+ * answer was a fresh full-tree walk. The instance is SHARED, so the return type is
377
+ * ReadonlyMap: a caller mutating it would poison every later reader of this root.
378
+ */
379
+ declare function paragraphOrderOfPart(part: OoxmlPart): ReadonlyMap<string, number>;
380
+ /**
381
+ * Like {@link paragraphOrderOfPart}, but descends INTO paragraphs, so paragraphs nested
382
+ * in a run's content — a textbox's `w:txbxContent` — rank right after their host.
383
+ *
384
+ * A separate function on purpose: the shallow order feeds the review queue's card
385
+ * ordering, and re-ranking nested paragraphs there would move cards. This one exists for
386
+ * position containment tests ("is the caret inside this range"), where a paragraph the
387
+ * shallow order cannot see is a position that can never match.
388
+ */
389
+ declare function deepParagraphOrderOfPart(part: OoxmlPart): ReadonlyMap<string, number>;
390
+ /**
391
+ * Every range a decision touches. One card can cover several, in different paragraphs.
392
+ *
393
+ * Exported because the geometry half in the layout lane asks the same question, and a second
394
+ * copy of "which ranges does this item cover" is how a card comes to be painted over one range
395
+ * and activated by another.
396
+ */
397
+ declare function reviewItemRanges(item: ReviewItem): readonly ReviewRange[];
398
+ /** The range an item is anchored at — where its card belongs and how it sorts. */
399
+ declare function firstReviewRange(item: ReviewItem): ReviewRange | null;
400
+
401
+ export { type AuthoredNoteProperties as A, isLegalFootnotePosition as B, type CommentAnchor as C, DEFAULT_ENDNOTE_PROPERTIES as D, type EndnotePosition as E, type FootnotePosition as F, isLegalNumRestart as G, linkRevisionReplies as H, parseAuthoredNoteProperties as I, resolveEndnoteProperties as J, resolveFootnoteProperties as K, type LinkableReviewItem as L, reviewItemKey as M, type NoteNumRestart as N, reviewItemRanges as O, revisionItemsOf as P, settingsPartOf as Q, type ResolvedFootnoteProperties as R, threadStateOfPart as S, W15_NAMESPACE_URI as W, type ResolvedEndnoteProperties as a, type CommentPosition as b, type CommentRecord as c, type CommentThreadState as d, DEFAULT_FOOTNOTE_PROPERTIES as e, type ReviewCommentItem as f, type ReviewItem as g, type ReviewModelInput as h, type ReviewPosition as i, type ReviewRange as j, type ReviewRevisionItem as k, type ReviewRevisionKind as l, authoredDocumentEndnoteProperties as m, authoredDocumentFootnoteProperties as n, authoredEndnotePropertiesFromSectPr as o, paragraphOrderOfPart as p, authoredFootnotePropertiesFromSectPr as q, collectReviewItems as r, commentAnchorsOfStory as s, commentBodyText as t, commentInitials as u, commentItemsOf as v, commentsOfPart as w, deepParagraphOrderOfPart as x, firstReviewRange as y, isLegalEndnotePosition as z };
@@ -1,5 +1,5 @@
1
1
  import { e as OoxmlPart, a as OoxmlElement } from './ooxml-tree-BU0e3DVi.cjs';
2
- import { R as RevisionAddress } from './tree-op-types-DMiW6nIH.cjs';
2
+ import { R as RevisionAddress } from './tree-op-types-UOXlRUqQ.cjs';
3
3
 
4
4
  /** The `w15` namespace: `commentsExtended.xml` — thread parent and resolved state. */
5
5
  declare const W15_NAMESPACE_URI = "http://schemas.microsoft.com/office/word/2012/wordml";
@@ -174,7 +174,22 @@ interface ReviewCustomItem {
174
174
  readonly attrs: Readonly<Record<string, string>>;
175
175
  /** The SDT's literal content text. Untrusted input. */
176
176
  readonly text: string;
177
- /** Card title, from the definition's `reviewCard` hook. */
177
+ /**
178
+ * The payload the node's control binds to, after the definition validated it.
179
+ *
180
+ * Undefined when the node carries none or the payload did not match — see the pro package's
181
+ * `RecognizedCustomNode.data`, which this is carried from.
182
+ */
183
+ readonly data?: unknown;
184
+ /**
185
+ * Whether this node asked for a sidebar card.
186
+ *
187
+ * False for a definition with no `reviewCard`: the item exists so the chip's own surfaces can
188
+ * read `attrs`, `text` and `data` off it, and the rail leaves it out. A surface listing cards
189
+ * filters on this rather than on an empty `title`.
190
+ */
191
+ readonly carded: boolean;
192
+ /** Card title, from the definition's `reviewCard` hook. Empty when `carded` is false. */
178
193
  readonly title: string;
179
194
  /** Card body, from the definition's `reviewCard` hook. */
180
195
  readonly detail?: string;
@@ -207,6 +222,24 @@ interface ReviewModelInput {
207
222
  * `kind: 'custom'` cards for definitions that opted in.
208
223
  */
209
224
  readonly customNodes?: readonly unknown[] | undefined;
225
+ /**
226
+ * The payload each of the story's controls binds to, keyed by the control's node id.
227
+ *
228
+ * Resolved by the ENGINE and handed over, because a payload lives in a customXml data part
229
+ * and a derivation that only receives story parts has no way to reach one. Untrusted file
230
+ * input on both members; a capability package validates it against whatever shape it
231
+ * declared before handing it to a host.
232
+ */
233
+ /**
234
+ * Where a capability package reports a node it could not read. Supplied per editor, so a page
235
+ * with two of them keeps their diagnostics apart.
236
+ */
237
+ readonly reportCustomNodeDiagnostic?: ((diagnostic: unknown) => void) | undefined;
238
+ readonly customNodePayloads?: ReadonlyMap<string, {
239
+ readonly nodeId: string;
240
+ readonly label: string;
241
+ readonly data: string;
242
+ }> | undefined;
210
243
  }
211
244
  /** The stable key a surface uses for the active item and for a React list. */
212
245
  declare function reviewItemKey(item: ReviewItem): string;
@@ -214,8 +247,7 @@ declare function reviewItemKey(item: ReviewItem): string;
214
247
  declare function commentBodyText(comment: CommentRecord): string;
215
248
  /** Author initials for an avatar, from `@w:initials` or the name. */
216
249
  declare function commentInitials(comment: CommentRecord): string;
217
- /** Paragraph node id → document position, from the TREE rather than from a layout. */
218
- declare function paragraphOrderOfPart(part: OoxmlPart): Map<string, number>;
250
+
219
251
  /** Every range a decision touches. One card can cover several, in different paragraphs. */
220
252
  declare function reviewItemRanges(item: ReviewItem): readonly ReviewRange[];
221
253
  /** The first range of an item, in authored order, or null when it has none. */
@@ -323,4 +355,4 @@ declare function reviewItemGeometry(item: ReviewItem, index: ReadonlyMap<string,
323
355
  readonly y: number;
324
356
  } | null;
325
357
 
326
- export { type CommentRecord as C, type ReviewModelInput as R, W15_NAMESPACE_URI as W, type ReviewItem as a, type ReviewRevisionItem as b, type ReviewCommentItem as c, type ReviewCustomItem as d, type ReviewPosition as e, type ReviewRange as f, type ReviewRevisionKind as g, type CommentAnchor as h, type CommentPosition as i, type CommentThreadState as j, type ReviewParagraphAnchor as k, activeReviewItem as l, commentBodyText as m, commentInitials as n, firstReviewRange as o, paragraphOrderOfPart as p, reviewItemGeometry as q, reviewAnchorIndex as r, reviewItemKey as s, reviewItemPositionRank as t, reviewItemRanges as u, reviewItemsAt as v, reviewThreadRootOf as w };
358
+ export { type CommentRecord as C, type ReviewModelInput as R, W15_NAMESPACE_URI as W, type ReviewItem as a, type ReviewRevisionItem as b, type ReviewCommentItem as c, type ReviewCustomItem as d, type ReviewPosition as e, type ReviewRange as f, type ReviewRevisionKind as g, type CommentAnchor as h, type CommentPosition as i, type CommentThreadState as j, type ReviewParagraphAnchor as k, activeReviewItem as l, commentBodyText as m, commentInitials as n, firstReviewRange as o, reviewItemGeometry as p, reviewItemKey as q, reviewAnchorIndex as r, reviewItemPositionRank as s, reviewItemRanges as t, reviewItemsAt as u, reviewThreadRootOf as v };
@@ -1,5 +1,5 @@
1
1
  import { e as OoxmlPart, a as OoxmlElement } from './ooxml-tree-BU0e3DVi.js';
2
- import { R as RevisionAddress } from './tree-op-types-CwOeiaQ8.js';
2
+ import { R as RevisionAddress } from './tree-op-types-DWLCllG7.js';
3
3
 
4
4
  /** The `w15` namespace: `commentsExtended.xml` — thread parent and resolved state. */
5
5
  declare const W15_NAMESPACE_URI = "http://schemas.microsoft.com/office/word/2012/wordml";
@@ -174,7 +174,22 @@ interface ReviewCustomItem {
174
174
  readonly attrs: Readonly<Record<string, string>>;
175
175
  /** The SDT's literal content text. Untrusted input. */
176
176
  readonly text: string;
177
- /** Card title, from the definition's `reviewCard` hook. */
177
+ /**
178
+ * The payload the node's control binds to, after the definition validated it.
179
+ *
180
+ * Undefined when the node carries none or the payload did not match — see the pro package's
181
+ * `RecognizedCustomNode.data`, which this is carried from.
182
+ */
183
+ readonly data?: unknown;
184
+ /**
185
+ * Whether this node asked for a sidebar card.
186
+ *
187
+ * False for a definition with no `reviewCard`: the item exists so the chip's own surfaces can
188
+ * read `attrs`, `text` and `data` off it, and the rail leaves it out. A surface listing cards
189
+ * filters on this rather than on an empty `title`.
190
+ */
191
+ readonly carded: boolean;
192
+ /** Card title, from the definition's `reviewCard` hook. Empty when `carded` is false. */
178
193
  readonly title: string;
179
194
  /** Card body, from the definition's `reviewCard` hook. */
180
195
  readonly detail?: string;
@@ -207,6 +222,24 @@ interface ReviewModelInput {
207
222
  * `kind: 'custom'` cards for definitions that opted in.
208
223
  */
209
224
  readonly customNodes?: readonly unknown[] | undefined;
225
+ /**
226
+ * The payload each of the story's controls binds to, keyed by the control's node id.
227
+ *
228
+ * Resolved by the ENGINE and handed over, because a payload lives in a customXml data part
229
+ * and a derivation that only receives story parts has no way to reach one. Untrusted file
230
+ * input on both members; a capability package validates it against whatever shape it
231
+ * declared before handing it to a host.
232
+ */
233
+ /**
234
+ * Where a capability package reports a node it could not read. Supplied per editor, so a page
235
+ * with two of them keeps their diagnostics apart.
236
+ */
237
+ readonly reportCustomNodeDiagnostic?: ((diagnostic: unknown) => void) | undefined;
238
+ readonly customNodePayloads?: ReadonlyMap<string, {
239
+ readonly nodeId: string;
240
+ readonly label: string;
241
+ readonly data: string;
242
+ }> | undefined;
210
243
  }
211
244
  /** The stable key a surface uses for the active item and for a React list. */
212
245
  declare function reviewItemKey(item: ReviewItem): string;
@@ -214,8 +247,7 @@ declare function reviewItemKey(item: ReviewItem): string;
214
247
  declare function commentBodyText(comment: CommentRecord): string;
215
248
  /** Author initials for an avatar, from `@w:initials` or the name. */
216
249
  declare function commentInitials(comment: CommentRecord): string;
217
- /** Paragraph node id → document position, from the TREE rather than from a layout. */
218
- declare function paragraphOrderOfPart(part: OoxmlPart): Map<string, number>;
250
+
219
251
  /** Every range a decision touches. One card can cover several, in different paragraphs. */
220
252
  declare function reviewItemRanges(item: ReviewItem): readonly ReviewRange[];
221
253
  /** The first range of an item, in authored order, or null when it has none. */
@@ -323,4 +355,4 @@ declare function reviewItemGeometry(item: ReviewItem, index: ReadonlyMap<string,
323
355
  readonly y: number;
324
356
  } | null;
325
357
 
326
- export { type CommentRecord as C, type ReviewModelInput as R, W15_NAMESPACE_URI as W, type ReviewItem as a, type ReviewRevisionItem as b, type ReviewCommentItem as c, type ReviewCustomItem as d, type ReviewPosition as e, type ReviewRange as f, type ReviewRevisionKind as g, type CommentAnchor as h, type CommentPosition as i, type CommentThreadState as j, type ReviewParagraphAnchor as k, activeReviewItem as l, commentBodyText as m, commentInitials as n, firstReviewRange as o, paragraphOrderOfPart as p, reviewItemGeometry as q, reviewAnchorIndex as r, reviewItemKey as s, reviewItemPositionRank as t, reviewItemRanges as u, reviewItemsAt as v, reviewThreadRootOf as w };
358
+ export { type CommentRecord as C, type ReviewModelInput as R, W15_NAMESPACE_URI as W, type ReviewItem as a, type ReviewRevisionItem as b, type ReviewCommentItem as c, type ReviewCustomItem as d, type ReviewPosition as e, type ReviewRange as f, type ReviewRevisionKind as g, type CommentAnchor as h, type CommentPosition as i, type CommentThreadState as j, type ReviewParagraphAnchor as k, activeReviewItem as l, commentBodyText as m, commentInitials as n, firstReviewRange as o, reviewItemGeometry as p, reviewItemKey as q, reviewAnchorIndex as r, reviewItemPositionRank as s, reviewItemRanges as t, reviewItemsAt as u, reviewThreadRootOf as v };
@@ -1,7 +1,7 @@
1
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-CWodBJsz.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-zTC0_1zi.js';
3
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-Dy-dCUFF.js';
4
+ import { S as SemanticPosition, C as CaretGeometry, a as SemanticSelection } from './semantic-interaction-CXH2wFqi.js';
5
5
 
6
6
  /**
7
7
  * Hard ceiling on sections enumerated from a document (matches write-path
@@ -1,7 +1,7 @@
1
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-CJR3BvHs.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-COVFW5aS.cjs';
3
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-D-Dszxrn.cjs';
4
+ import { S as SemanticPosition, C as CaretGeometry, a as SemanticSelection } from './semantic-interaction-DqcEonqD.cjs';
5
5
 
6
6
  /**
7
7
  * Hard ceiling on sections enumerated from a document (matches write-path
@@ -1,4 +1,4 @@
1
- import { T as TextMeasurer, S as SemanticLayout, B as BlockFragmentRecord, C as ContentControlBoundaryRecord, a as StyleSpanRecord } from './semantic-records-CWodBJsz.js';
1
+ import { T as TextMeasurer, S as SemanticLayout, B as BlockFragmentRecord, C as ContentControlBoundaryRecord, a as StyleSpanRecord } from './semantic-records-zTC0_1zi.js';
2
2
 
3
3
  /** A caret position in the model. */
4
4
  interface SemanticPosition {
@@ -1,4 +1,4 @@
1
- import { T as TextMeasurer, S as SemanticLayout, B as BlockFragmentRecord, C as ContentControlBoundaryRecord, a as StyleSpanRecord } from './semantic-records-CJR3BvHs.cjs';
1
+ import { T as TextMeasurer, S as SemanticLayout, B as BlockFragmentRecord, C as ContentControlBoundaryRecord, a as StyleSpanRecord } from './semantic-records-COVFW5aS.cjs';
2
2
 
3
3
  /** A caret position in the model. */
4
4
  interface SemanticPosition {
@@ -1,4 +1,4 @@
1
- import { V as ValidatedImageBytesHandle, R as RenderableImageMime } from './image-resources-BJnTpG66.js';
1
+ import { V as ValidatedImageBytesHandle, R as RenderableImageMime } from './image-resources-C_YnqPhn.js';
2
2
 
3
3
  /** Host port for safe blob URLs — only called for {@link ImageResourceState.kind} `ready`. */
4
4
  interface PaintImageUrlPort {
@@ -1,4 +1,4 @@
1
- import { V as ValidatedImageBytesHandle, R as RenderableImageMime } from './image-resources-BpIydXtU.cjs';
1
+ import { V as ValidatedImageBytesHandle, R as RenderableImageMime } from './image-resources-DwpNnTg3.cjs';
2
2
 
3
3
  /** Host port for safe blob URLs — only called for {@link ImageResourceState.kind} `ready`. */
4
4
  interface PaintImageUrlPort {