@docx-editor.dev/core 2.0.1 → 2.1.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.
- package/README.md +32 -33
- package/dist/automation.cjs +1 -1
- package/dist/automation.d.cts +2 -2
- package/dist/automation.d.ts +2 -2
- package/dist/automation.js +1 -1
- package/dist/binding.cjs +1 -1
- package/dist/binding.d.cts +14 -8
- package/dist/binding.d.ts +14 -8
- package/dist/binding.js +1 -1
- package/dist/chunk-2DTQDAN7.js +2 -0
- package/dist/chunk-3JKQE4QJ.cjs +2 -0
- package/dist/chunk-4WWEDTTE.js +2 -0
- package/dist/chunk-6WIIHJFY.js +1 -0
- package/dist/chunk-7VQ7YLW3.cjs +1 -0
- package/dist/chunk-BS554B6D.cjs +2 -0
- package/dist/chunk-BZK64YU3.cjs +10 -0
- package/dist/chunk-CZFUMACF.cjs +12 -0
- package/dist/chunk-GQQOL4PV.js +1 -0
- package/dist/chunk-JQFDLZXQ.cjs +2 -0
- package/dist/chunk-O2WQY7IT.cjs +5 -0
- package/dist/chunk-PC76F2HR.cjs +1 -0
- package/dist/chunk-QRAUDDVY.js +2 -0
- package/dist/chunk-STCITBJK.js +12 -0
- package/dist/chunk-TBBXCC7D.js +5 -0
- package/dist/chunk-TSXT537P.cjs +12 -0
- package/dist/chunk-WOGYVM3W.js +12 -0
- package/dist/chunk-Y7TA7TPF.js +10 -0
- package/dist/contracts/editor.d.cts +6 -6
- package/dist/contracts/editor.d.ts +6 -6
- package/dist/contracts/interaction.d.cts +6 -6
- package/dist/contracts/interaction.d.ts +6 -6
- package/dist/contracts/modules.cjs +1 -1
- package/dist/contracts/modules.d.cts +30 -3
- package/dist/contracts/modules.d.ts +30 -3
- package/dist/contracts/modules.js +1 -1
- package/dist/{tree-package-store-DOKMtCnh.d.cts → custom-node-writes-YqISlSRl.d.cts} +181 -4
- package/dist/{tree-package-store-D5S7VKs5.d.ts → custom-node-writes-ttKuYd0M.d.ts} +181 -4
- package/dist/{editor-D0UDock4.d.cts → editor-B93PggnR.d.cts} +24 -5
- package/dist/{editor-C1QRi1v4.d.ts → editor-CFsSrxGR.d.ts} +24 -5
- package/dist/editor.cjs +1 -1
- package/dist/editor.css +1368 -279
- package/dist/editor.d.cts +19 -19
- package/dist/editor.d.ts +19 -19
- package/dist/editor.js +1 -1
- package/dist/{image-resources-BJnTpG66.d.ts → image-resources-C_YnqPhn.d.ts} +19 -11
- package/dist/{image-resources-BpIydXtU.d.cts → image-resources-DwpNnTg3.d.cts} +19 -11
- package/dist/{index-CrW-IxXt.d.cts → index-BjZelfWL.d.cts} +28 -11
- package/dist/{index-ZqBEOrTV.d.ts → index-DP1yJJ3R.d.ts} +28 -11
- package/dist/index.cjs +1 -1
- package/dist/index.d.cts +13 -13
- package/dist/index.d.ts +13 -13
- package/dist/index.js +1 -1
- package/dist/layout.cjs +1 -1
- package/dist/layout.d.cts +869 -819
- package/dist/layout.d.ts +869 -819
- package/dist/layout.js +1 -1
- package/dist/output.cjs +1 -1
- package/dist/output.d.cts +4 -4
- package/dist/output.d.ts +4 -4
- package/dist/output.js +1 -1
- package/dist/{protocol-oxHaWmt4.d.ts → protocol-BWVA3Q1p.d.ts} +56 -2
- package/dist/{protocol-CAkOBBGE.d.cts → protocol-FAz_nPm_.d.cts} +56 -2
- package/dist/review-reads-CsoXSvUg.d.ts +401 -0
- package/dist/review-reads-qW0jvdF1.d.cts +401 -0
- package/dist/{review-support-DS8DYX2a.d.cts → review-support-D64Wu236.d.cts} +37 -5
- package/dist/{review-support-Fy3vdIea.d.ts → review-support-nsLXC9jf.d.ts} +37 -5
- package/dist/{semantic-cell-selection-DsmHmLJ5.d.ts → semantic-cell-selection-D_8RbPII.d.ts} +2 -2
- package/dist/{semantic-cell-selection-CZjBSmMv.d.cts → semantic-cell-selection-DwLB71fF.d.cts} +2 -2
- package/dist/{semantic-interaction-Dy-dCUFF.d.ts → semantic-interaction-CXH2wFqi.d.ts} +1 -1
- package/dist/{semantic-interaction-D-Dszxrn.d.cts → semantic-interaction-DqcEonqD.d.cts} +1 -1
- package/dist/{semantic-paint-drawings-BA3z9jl8.d.ts → semantic-paint-drawings-B5Wk2so5.d.ts} +1 -1
- package/dist/{semantic-paint-drawings-D7qbB0E2.d.cts → semantic-paint-drawings-x8g44lD_.d.cts} +1 -1
- package/dist/{semantic-records-CJR3BvHs.d.cts → semantic-records-COVFW5aS.d.cts} +77 -4
- package/dist/{semantic-records-CWodBJsz.d.ts → semantic-records-zTC0_1zi.d.ts} +77 -4
- package/dist/{shaped-measurer-CNIT_svZ.d.cts → shaped-measurer-AFnFxoot.d.cts} +1 -1
- package/dist/{shaped-measurer-B-TAtcQU.d.ts → shaped-measurer-CZXL-a6v.d.ts} +1 -1
- package/dist/store.cjs +1 -1
- package/dist/store.d.cts +223 -317
- package/dist/store.d.ts +223 -317
- package/dist/store.js +1 -1
- package/dist/{tree-op-types-CwOeiaQ8.d.ts → tree-op-types-DWLCllG7.d.ts} +80 -25
- package/dist/{tree-op-types-DMiW6nIH.d.cts → tree-op-types-UOXlRUqQ.d.cts} +80 -25
- package/dist/{tree-session-CiUel5Kz.d.ts → tree-session-BtVFXsF6.d.ts} +45 -7
- package/dist/{tree-session-D47_imvR.d.cts → tree-session-DxIOHUOD.d.cts} +45 -7
- package/dist/{tree-store-CxifqwIv.d.cts → tree-store-B1lEkdXc.d.cts} +1 -1
- package/dist/{tree-store-hLtjeyWE.d.ts → tree-store-BscFPB7x.d.ts} +1 -1
- package/package.json +10 -5
- package/dist/chunk-5KSCB2OZ.js +0 -2
- package/dist/chunk-BSC44TIT.js +0 -5
- package/dist/chunk-DLPL5DAG.js +0 -12
- package/dist/chunk-DOEIARE2.js +0 -2
- package/dist/chunk-G7YCQBZE.cjs +0 -5
- package/dist/chunk-HR7K3W6A.js +0 -1
- package/dist/chunk-HVAV2JSN.js +0 -11
- package/dist/chunk-MYH2HCUJ.cjs +0 -2
- package/dist/chunk-NSM75TN6.cjs +0 -1
- package/dist/chunk-PHDVKUWZ.js +0 -1
- package/dist/chunk-QADYGK5L.cjs +0 -12
- package/dist/chunk-RNBHTPW7.js +0 -10
- package/dist/chunk-UD2ZXLFI.cjs +0 -2
- package/dist/chunk-VYAVK2AH.cjs +0 -1
- package/dist/chunk-YUK46A2N.cjs +0 -11
- package/dist/chunk-ZMIX42J7.cjs +0 -10
- package/dist/chunk-ZT55Q52J.cjs +0 -2
- package/dist/chunk-ZUALAR4M.js +0 -2
- package/dist/note-properties-CnmCoory.d.cts +0 -68
- 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.js';
|
|
2
|
+
import { O as OoxmlPackage } from './ooxml-package-D_CtywTW.js';
|
|
3
|
+
import { R as RevisionAddress } from './tree-op-types-DWLCllG7.js';
|
|
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 };
|