@docx-editor.dev/pro 0.0.1-placeholder → 2.0.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.
- package/LICENSE.md +121 -0
- package/README.md +136 -2
- package/THIRD_PARTY_NOTICES.md +22 -0
- package/dist/chunk-NZOS3H23.js +1 -0
- package/dist/chunk-TNSHSAA4.cjs +1 -0
- package/dist/define-custom-node-CkkDPdB0.d.cts +191 -0
- package/dist/define-custom-node-CkkDPdB0.d.ts +191 -0
- package/dist/index.cjs +1 -0
- package/dist/index.d.cts +175 -0
- package/dist/index.d.ts +175 -0
- package/dist/index.js +1 -0
- package/dist/react/index.cjs +2 -0
- package/dist/react/index.d.cts +592 -0
- package/dist/react/index.d.ts +592 -0
- package/dist/react/index.js +2 -0
- package/package.json +72 -7
|
@@ -0,0 +1,592 @@
|
|
|
1
|
+
import { C as CustomNodeDefinition, A as ActivatedCustomNode } from '../define-custom-node-CkkDPdB0.js';
|
|
2
|
+
export { P as ProLicenseOptions, b as ReviewModuleOptions, e as reviewModule } from '../define-custom-node-CkkDPdB0.js';
|
|
3
|
+
import * as react from 'react';
|
|
4
|
+
import { ReactNode } from 'react';
|
|
5
|
+
import { ToolbarTranslate } from '@docx-editor.dev/react';
|
|
6
|
+
import { ReviewItemPlacement, ReviewItemQuery, Editor } from '@docx-editor.dev/core/contracts/editor';
|
|
7
|
+
import '@docx-editor.dev/core/editor';
|
|
8
|
+
import '@docx-editor.dev/core/store';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* One card's data plus where it belongs on screen.
|
|
12
|
+
*
|
|
13
|
+
* The engine's own placement, unchanged. It is already presentation-ready — author,
|
|
14
|
+
* initials, date, text, thread — because deriving those from the canonical tree is engine
|
|
15
|
+
* work, and an adapter deriving them would be document derivation in a host and would have
|
|
16
|
+
* to be written once per framework.
|
|
17
|
+
*/
|
|
18
|
+
type ReviewItemView = ReviewItemPlacement;
|
|
19
|
+
/**
|
|
20
|
+
* What {@link useReview} returns: the review rail's data and the four things a card can do.
|
|
21
|
+
*
|
|
22
|
+
* @public
|
|
23
|
+
*/
|
|
24
|
+
interface UseReviewReturn {
|
|
25
|
+
/** Every pending decision in the document, in reading order. */
|
|
26
|
+
readonly items: readonly ReviewItemView[];
|
|
27
|
+
/** The item the caret is in, or null. */
|
|
28
|
+
readonly activeKey: string | null;
|
|
29
|
+
/** Card to document: selects the item's range and scrolls to it. */
|
|
30
|
+
readonly setActive: (key: string | null) => void;
|
|
31
|
+
/** Accept a revision. A no-op on an item whose `readOnly` is true. */
|
|
32
|
+
readonly accept: (item: ReviewItemView) => void;
|
|
33
|
+
/** Reject a revision. A no-op on an item whose `readOnly` is true. */
|
|
34
|
+
readonly reject: (item: ReviewItemView) => void;
|
|
35
|
+
/**
|
|
36
|
+
* Discard the item: delete a comment thread, or reject a tracked change.
|
|
37
|
+
*
|
|
38
|
+
* One verb for both, so a card can carry one "remove this" control whatever it holds.
|
|
39
|
+
* Reports whether it landed — a comment the engine refused to delete must not vanish from
|
|
40
|
+
* the caller's own state while the document still holds it.
|
|
41
|
+
*/
|
|
42
|
+
readonly remove: (item: ReviewItemView) => boolean;
|
|
43
|
+
/**
|
|
44
|
+
* Reply to a comment, or to a revision — which OOXML records as a comment on its range.
|
|
45
|
+
*
|
|
46
|
+
* The author is AMBIENT (`DocxEditorConfig.author`); pass one to override it for a single
|
|
47
|
+
* reply. `CT_Comment` makes `@w:author` required, so the engine refuses a reply with
|
|
48
|
+
* neither rather than writing an empty attribute — which is why this REPORTS whether the
|
|
49
|
+
* reply landed. A box that cleared itself on a refusal would throw the text away and show
|
|
50
|
+
* nothing, and the writer would not learn their reply never existed.
|
|
51
|
+
*/
|
|
52
|
+
readonly reply: (item: ReviewItemView, text: string, author?: string) => boolean;
|
|
53
|
+
/**
|
|
54
|
+
* Where a comment on the current selection would sit, or null when nothing is selected.
|
|
55
|
+
*
|
|
56
|
+
* From the engine, not from the DOM — the same rule the card anchors follow.
|
|
57
|
+
*/
|
|
58
|
+
readonly selectionAnchorY: number | null;
|
|
59
|
+
/** Comment on the current selection. Reports whether it landed, like {@link reply}. */
|
|
60
|
+
readonly comment: (text: string, author?: string) => boolean;
|
|
61
|
+
/** Whether the pane shows cards. Engine state: the toolbar's comments button toggles it. */
|
|
62
|
+
readonly paneOpen: boolean;
|
|
63
|
+
/** Open or close the pane — the same toggle the toolbar button runs. */
|
|
64
|
+
readonly setPaneOpen: (open: boolean) => void;
|
|
65
|
+
/** True while the engine has no document, so a surface can render nothing rather than empty. */
|
|
66
|
+
readonly ready: boolean;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Read the review queue and act on it.
|
|
70
|
+
*
|
|
71
|
+
* Subscribes to the editor's own change stream, so the list re-derives when the document does
|
|
72
|
+
* and not on every render.
|
|
73
|
+
*/
|
|
74
|
+
declare function useReview(query?: ReviewItemQuery): UseReviewReturn;
|
|
75
|
+
/** The same hook against an explicit editor, for hosts that hold their own. */
|
|
76
|
+
declare function useReviewOf(editor: Editor | null, query?: ReviewItemQuery): UseReviewReturn;
|
|
77
|
+
/**
|
|
78
|
+
* Non-overlapping Y positions for cards you have measured.
|
|
79
|
+
*
|
|
80
|
+
* Separate from `useReview` because only the CALLER knows how tall its cards are — a host
|
|
81
|
+
* rendering its own markup can be told where each anchor is, but not how much room its card
|
|
82
|
+
* needs. Pass the measured heights back and get positions that do not collide; skip it
|
|
83
|
+
* entirely and cards sit on their raw anchors, which is correct for a rail that does not stack.
|
|
84
|
+
*
|
|
85
|
+
* Takes anything with a key and an anchor, not only cards: a compose box competes for the
|
|
86
|
+
* same column and has to be stacked WITH them or it lands on top of the card whose text was
|
|
87
|
+
* just re-selected. Entries must arrive in document order — the run is a single sweep.
|
|
88
|
+
*
|
|
89
|
+
* UNITS. Anchors are in layout POINTS, because that is what the engine publishes; measured
|
|
90
|
+
* heights are in CSS PIXELS, because that is what the DOM reports. Pass `scale` so the two
|
|
91
|
+
* can be added. Without it a 330px card advanced the run by 330 POINTS — 440px — and two
|
|
92
|
+
* comments on adjacent lines of one paragraph sat a third of a page apart.
|
|
93
|
+
*/
|
|
94
|
+
declare function useStackedReviewPositions(items: readonly {
|
|
95
|
+
readonly key: string;
|
|
96
|
+
readonly anchorY: number | null;
|
|
97
|
+
}[], heights: ReadonlyMap<string, number>, options?: {
|
|
98
|
+
readonly gap?: number;
|
|
99
|
+
readonly scale?: number;
|
|
100
|
+
readonly defaultHeight?: number;
|
|
101
|
+
}): ReadonlyMap<string, number>;
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* The review item the surrounding card (or balloon) renders, or null outside one.
|
|
105
|
+
*
|
|
106
|
+
* The hook a host's own card content is built from: children passed into the rail's cards
|
|
107
|
+
* — extra actions, a custom body — read the CURRENT item here rather than receiving props,
|
|
108
|
+
* exactly the way the packaged parts do.
|
|
109
|
+
*
|
|
110
|
+
* @public
|
|
111
|
+
*/
|
|
112
|
+
declare function useReviewItem(): ReviewItemView | null;
|
|
113
|
+
/** Shared props for every part. @public */
|
|
114
|
+
interface ReviewPartProps {
|
|
115
|
+
className?: string;
|
|
116
|
+
/** Merge this part's wiring onto the single child element instead of the default one. */
|
|
117
|
+
asChild?: boolean;
|
|
118
|
+
/** Render nothing — inside the packaged arrangement this removes the part. */
|
|
119
|
+
hidden?: boolean;
|
|
120
|
+
children?: ReactNode;
|
|
121
|
+
}
|
|
122
|
+
/** Props for the action parts, which also take an icon. @public */
|
|
123
|
+
interface ReviewActionProps extends ReviewPartProps {
|
|
124
|
+
/** Icon override; falls back to `children`, then to the part's default glyph. */
|
|
125
|
+
icon?: ReactNode;
|
|
126
|
+
}
|
|
127
|
+
/** Props for `DocxEditor.Review`. @public */
|
|
128
|
+
interface ReviewProps extends Omit<ReviewPartProps, 'children'> {
|
|
129
|
+
/**
|
|
130
|
+
* Label resolver, as `DocxEditor.Toolbar`, `.Menu` and `.ContextMenu` take one. Unresolved
|
|
131
|
+
* keys fall back to the bundled catalogue rather than to the key.
|
|
132
|
+
*/
|
|
133
|
+
t?: ToolbarTranslate;
|
|
134
|
+
/** Class for each card. The rail's own `className` styles the column; this the boxes in it. */
|
|
135
|
+
card?: {
|
|
136
|
+
className?: string;
|
|
137
|
+
};
|
|
138
|
+
/**
|
|
139
|
+
* The cards, or a render prop that replaces the packaged card entirely while keeping the
|
|
140
|
+
* rail's subscription, anchoring, stacking and virtualization. Nodes are treated as part
|
|
141
|
+
* overrides for the packaged card instead.
|
|
142
|
+
*
|
|
143
|
+
* ```tsx
|
|
144
|
+
* <DocxEditor.Review>{(item) => <MyCard item={item} />}</DocxEditor.Review>
|
|
145
|
+
* ```
|
|
146
|
+
*/
|
|
147
|
+
children?: ReactNode | ((item: ReviewItemView) => ReactNode);
|
|
148
|
+
/**
|
|
149
|
+
* Host content at the top of the rail, above the cards — filters, legends, summaries.
|
|
150
|
+
*
|
|
151
|
+
* Rendered only while the pane is OPEN. A closed rail gives up its width for a 32px strip
|
|
152
|
+
* of markers, and content laid out for the 300px column has nowhere to go in it; unmounting
|
|
153
|
+
* is the rail's own business, not something a host should have to subscribe to `paneOpen`
|
|
154
|
+
* to discover. Furniture that should outlive the toggle belongs outside the rail.
|
|
155
|
+
*/
|
|
156
|
+
furniture?: ReactNode;
|
|
157
|
+
/**
|
|
158
|
+
* Render the packaged arrangement. `false` mounts the rail and its context only, so a host
|
|
159
|
+
* can lay the cards out itself while keeping the subscription and the anchoring.
|
|
160
|
+
*/
|
|
161
|
+
preset?: boolean;
|
|
162
|
+
/**
|
|
163
|
+
* Stack cards so they never overlap, pushing later ones down. `false` leaves every card on
|
|
164
|
+
* its raw anchor, which is right for a rail that draws connectors instead.
|
|
165
|
+
*/
|
|
166
|
+
stack?: boolean;
|
|
167
|
+
/** Gap (px) between stacked cards. The only source of vertical spacing in the rail. */
|
|
168
|
+
gap?: number;
|
|
169
|
+
/** Show only some of the queue — comments in one rail, revisions in another. */
|
|
170
|
+
filter?: (item: ReviewItemView) => boolean;
|
|
171
|
+
/**
|
|
172
|
+
* Show the "changed the document structure" cards. Default `false`: a heavily revised
|
|
173
|
+
* document carries one per structural site and together they crowd out the cards a
|
|
174
|
+
* reviewer can act on. The revisions stay marked in the document, where clicking one
|
|
175
|
+
* opens its balloon — this hides only their rail cards.
|
|
176
|
+
*/
|
|
177
|
+
structural?: boolean;
|
|
178
|
+
/**
|
|
179
|
+
* Show the "changed text formatting" cards. Default `false`, same reasoning as
|
|
180
|
+
* {@link structural}: a restyled document mints one per run, and the decision is
|
|
181
|
+
* reachable by clicking the grey-marked text instead. The rail keeps the decisions a
|
|
182
|
+
* reviewer reads in order — content changes and comments.
|
|
183
|
+
*/
|
|
184
|
+
formatting?: boolean;
|
|
185
|
+
}
|
|
186
|
+
/**
|
|
187
|
+
* The review rail.
|
|
188
|
+
*
|
|
189
|
+
* Positions absolutely inside the nearest positioned ancestor — put it in
|
|
190
|
+
* `DocxEditor.Viewport` beside `DocxEditor.Content`, which is what makes the cards scroll
|
|
191
|
+
* with the pages without a scroll listener.
|
|
192
|
+
*
|
|
193
|
+
* @public
|
|
194
|
+
*/
|
|
195
|
+
declare function ReviewRoot({ className, furniture, asChild, hidden, children, t: hostT, card, preset, stack, gap, filter, structural, formatting, }: ReviewProps): react.JSX.Element | null;
|
|
196
|
+
interface ReviewListProps {
|
|
197
|
+
stack?: boolean;
|
|
198
|
+
positions?: ReadonlyMap<string, number>;
|
|
199
|
+
/** Cards the stacking pass collapsed to a header — pushed too far from their text. */
|
|
200
|
+
collapsed?: ReadonlySet<string>;
|
|
201
|
+
scale?: number;
|
|
202
|
+
offset?: number;
|
|
203
|
+
/** Visible band of the scroller; cards outside it are not mounted. Null renders all. */
|
|
204
|
+
window?: {
|
|
205
|
+
top: number;
|
|
206
|
+
bottom: number;
|
|
207
|
+
} | null;
|
|
208
|
+
/**
|
|
209
|
+
* A render prop takes over the card entirely, keeping the rail's subscription, anchoring
|
|
210
|
+
* and stacking. Nodes are treated as part overrides for the packaged card.
|
|
211
|
+
*/
|
|
212
|
+
children?: ReactNode | ((item: ReviewItemView) => ReactNode);
|
|
213
|
+
className?: string;
|
|
214
|
+
hidden?: boolean;
|
|
215
|
+
}
|
|
216
|
+
/**
|
|
217
|
+
* The cards, each positioned at its anchor.
|
|
218
|
+
*
|
|
219
|
+
* REPLIES are not cards. A threaded reply belongs inside the comment it answers, and giving
|
|
220
|
+
* it a card of its own would put two entries in the rail for one conversation.
|
|
221
|
+
*
|
|
222
|
+
* @public
|
|
223
|
+
*/
|
|
224
|
+
declare function ReviewList({ stack, positions, collapsed, scale, offset, window: visible, children, className, hidden, }: ReviewListProps): react.JSX.Element | null;
|
|
225
|
+
declare namespace ReviewList {
|
|
226
|
+
var docxReviewPart: "List";
|
|
227
|
+
}
|
|
228
|
+
/**
|
|
229
|
+
* The collapsed rail: one marker per item, at its anchor.
|
|
230
|
+
*
|
|
231
|
+
* @public
|
|
232
|
+
*/
|
|
233
|
+
declare function ReviewMarkers({ scale, offset, window: visible, className, hidden, }: {
|
|
234
|
+
scale?: number;
|
|
235
|
+
offset?: number;
|
|
236
|
+
/** Visible band of the scroller; markers outside it are not mounted. */
|
|
237
|
+
window?: {
|
|
238
|
+
top: number;
|
|
239
|
+
bottom: number;
|
|
240
|
+
} | null;
|
|
241
|
+
className?: string;
|
|
242
|
+
hidden?: boolean;
|
|
243
|
+
}): react.JSX.Element | null;
|
|
244
|
+
declare namespace ReviewMarkers {
|
|
245
|
+
var docxReviewPart: "Markers";
|
|
246
|
+
}
|
|
247
|
+
/**
|
|
248
|
+
* The "comment on this" button, beside the selected text.
|
|
249
|
+
*
|
|
250
|
+
* Appears only for a RANGE. A comment on a caret has nothing to point at, and Word writes
|
|
251
|
+
* none, so the affordance is absent rather than present-and-refusing.
|
|
252
|
+
*
|
|
253
|
+
* @public
|
|
254
|
+
*/
|
|
255
|
+
declare function ReviewAddComment({ top, drafting, className, hidden, children, }: ReviewPartProps & {
|
|
256
|
+
top: number | null;
|
|
257
|
+
drafting?: boolean;
|
|
258
|
+
}): react.JSX.Element | null;
|
|
259
|
+
declare namespace ReviewAddComment {
|
|
260
|
+
var docxReviewPart: "AddComment";
|
|
261
|
+
}
|
|
262
|
+
/**
|
|
263
|
+
* The compose box for a new comment.
|
|
264
|
+
*
|
|
265
|
+
* Nothing is written until it is submitted: an empty `w:comment` is a real comment in the
|
|
266
|
+
* file, and committing on open would leave one behind every time somebody changed their mind.
|
|
267
|
+
*
|
|
268
|
+
* @public
|
|
269
|
+
*/
|
|
270
|
+
declare function ReviewDraft({ top, className, hidden }: ReviewPartProps & {
|
|
271
|
+
top: number;
|
|
272
|
+
}): react.JSX.Element | null;
|
|
273
|
+
declare namespace ReviewDraft {
|
|
274
|
+
var docxReviewPart: "Draft";
|
|
275
|
+
}
|
|
276
|
+
/**
|
|
277
|
+
* The decision balloon: CLICKING a format or structural change in the PAGE opens its card
|
|
278
|
+
* beside the text — author, what changed, when, and accept/reject where the engine can
|
|
279
|
+
* resolve it — and the card stays until a press lands somewhere that is neither a tracked
|
|
280
|
+
* change nor the balloon itself. Click-opened on purpose: a hover-opened card vanished
|
|
281
|
+
* under the pointer travelling toward its own buttons.
|
|
282
|
+
*
|
|
283
|
+
* ONLY the kinds whose rail cards are hidden by default. Content changes and comments are
|
|
284
|
+
* the rail's — a balloon over "added" text repeats a card already beside the page — while
|
|
285
|
+
* a format or structural change has nothing but its grey/washed marking, so the click on
|
|
286
|
+
* that marking is where its decision lives.
|
|
287
|
+
*
|
|
288
|
+
* Matches the pressed element against the UNFILTERED queue, attribution first and POSITION
|
|
289
|
+
* last: the `(id, author, date)` triple, then `(id, author)`, then the id, then the span's
|
|
290
|
+
* own paragraph range against the items' ranges — real files drift on attribution, and the
|
|
291
|
+
* range is the one thing the painter and the review model cannot disagree about. An
|
|
292
|
+
* element matching nothing still shows what its DOM carries, just without actions.
|
|
293
|
+
*
|
|
294
|
+
* @public
|
|
295
|
+
*/
|
|
296
|
+
declare function ReviewBalloon({ className, hidden }: ReviewPartProps): react.JSX.Element | null;
|
|
297
|
+
declare namespace ReviewBalloon {
|
|
298
|
+
var docxReviewPart: "Balloon";
|
|
299
|
+
}
|
|
300
|
+
/** Shown when nothing is pending. @public */
|
|
301
|
+
declare function ReviewEmpty({ className, hidden, children }: ReviewPartProps): react.JSX.Element | null;
|
|
302
|
+
declare namespace ReviewEmpty {
|
|
303
|
+
var docxReviewPart: "Empty";
|
|
304
|
+
}
|
|
305
|
+
/**
|
|
306
|
+
* One card.
|
|
307
|
+
*
|
|
308
|
+
* Clicking it makes the item active, which SELECTS ITS RANGE in the document — the card and
|
|
309
|
+
* the text it is about are two views of one thing, and a card that highlighted nothing left
|
|
310
|
+
* the reader hunting for which words a comment meant.
|
|
311
|
+
*
|
|
312
|
+
* @public
|
|
313
|
+
*/
|
|
314
|
+
declare function ReviewCard({ className, asChild, hidden, children }: ReviewPartProps): react.JSX.Element | null;
|
|
315
|
+
declare namespace ReviewCard {
|
|
316
|
+
var docxReviewPart: "Card";
|
|
317
|
+
}
|
|
318
|
+
/** The author's initials, in their colour. @public */
|
|
319
|
+
declare function ReviewAvatar({ className, asChild, hidden, children }: ReviewPartProps): react.JSX.Element | null;
|
|
320
|
+
declare namespace ReviewAvatar {
|
|
321
|
+
var docxReviewPart: "Avatar";
|
|
322
|
+
}
|
|
323
|
+
/** The author's name. @public */
|
|
324
|
+
declare function ReviewAuthor({ className, asChild, hidden, children }: ReviewPartProps): react.JSX.Element | null;
|
|
325
|
+
declare namespace ReviewAuthor {
|
|
326
|
+
var docxReviewPart: "Author";
|
|
327
|
+
}
|
|
328
|
+
/**
|
|
329
|
+
* When the change was made.
|
|
330
|
+
*
|
|
331
|
+
* `@w:date` is optional in `CT_TrackChange` and Word omits it when the author turned off
|
|
332
|
+
* "store randomized IDs"/date stamping, so a missing date renders nothing rather than an
|
|
333
|
+
* "Invalid Date".
|
|
334
|
+
*
|
|
335
|
+
* @public
|
|
336
|
+
*/
|
|
337
|
+
declare function ReviewTime({ className, asChild, hidden, children }: ReviewPartProps): react.JSX.Element | null;
|
|
338
|
+
declare namespace ReviewTime {
|
|
339
|
+
var docxReviewPart: "Time";
|
|
340
|
+
}
|
|
341
|
+
/**
|
|
342
|
+
* What the card is about: the comment's text, or what the revision did.
|
|
343
|
+
*
|
|
344
|
+
* A revision that carries no characters — a formatting change, a paragraph mark, a row
|
|
345
|
+
* insertion — still gets a sentence. Word shows one, and a card reading only "Ada Lovelace"
|
|
346
|
+
* tells the reviewer nothing they can decide on.
|
|
347
|
+
*
|
|
348
|
+
* @public
|
|
349
|
+
*/
|
|
350
|
+
declare function ReviewSummary({ className, asChild, hidden, children }: ReviewPartProps): react.JSX.Element | null;
|
|
351
|
+
declare namespace ReviewSummary {
|
|
352
|
+
var docxReviewPart: "Summary";
|
|
353
|
+
}
|
|
354
|
+
/** Accept the revision behind this card. @public */
|
|
355
|
+
declare function ReviewAccept({ className, asChild, hidden, children, icon: glyph }: ReviewActionProps): react.JSX.Element | null;
|
|
356
|
+
declare namespace ReviewAccept {
|
|
357
|
+
var docxReviewPart: "Accept";
|
|
358
|
+
}
|
|
359
|
+
/** Reject the revision behind this card. @public */
|
|
360
|
+
declare function ReviewReject({ className, asChild, hidden, children, icon: glyph }: ReviewActionProps): react.JSX.Element | null;
|
|
361
|
+
declare namespace ReviewReject {
|
|
362
|
+
var docxReviewPart: "Reject";
|
|
363
|
+
}
|
|
364
|
+
/**
|
|
365
|
+
* Discard what the card holds: delete a comment thread, or reject a tracked change.
|
|
366
|
+
*
|
|
367
|
+
* The rail had accept and reject for a change and NOTHING for a comment, so a remark could be
|
|
368
|
+
* resolved but never removed — a reader who commented by mistake had to go back to the text and
|
|
369
|
+
* delete the words to be rid of it. One control on both kinds, because "remove this" is the same
|
|
370
|
+
* intent whichever the card holds; the engine's `deleteReviewItem` decides what it means.
|
|
371
|
+
*
|
|
372
|
+
* Absent, not disabled, on a card with nothing to discard — a custom node's, or a revision kind
|
|
373
|
+
* the engine cannot resolve.
|
|
374
|
+
*
|
|
375
|
+
* Revealed on HOVER of the one thing it deletes, and on keyboard focus — the stylesheet owns
|
|
376
|
+
* that, not this component. A rail of twenty cards each carrying a standing invitation to
|
|
377
|
+
* delete somebody's remark reads as an invitation to click one by mistake; scoping it to the
|
|
378
|
+
* node under the pointer also means a reply and the comment it answers never offer two
|
|
379
|
+
* identical buttons at once, which is the state that makes a reader delete the wrong one.
|
|
380
|
+
*
|
|
381
|
+
* CSS rather than an `isActive` gate because a reply is never itself the active item, and
|
|
382
|
+
* because requiring the reader to open a card before they can be rid of it is a step with
|
|
383
|
+
* nothing behind it. `visibility`, not `opacity`: hidden must also mean unclickable, and the
|
|
384
|
+
* space stays reserved so the row does not jump as the pointer crosses it.
|
|
385
|
+
*
|
|
386
|
+
* @public
|
|
387
|
+
*/
|
|
388
|
+
declare function ReviewDelete({ className, asChild, hidden, children, icon: glyph }: ReviewActionProps): react.JSX.Element | null;
|
|
389
|
+
declare namespace ReviewDelete {
|
|
390
|
+
var docxReviewPart: "Delete";
|
|
391
|
+
}
|
|
392
|
+
/** The thread under a comment, in document order. @public */
|
|
393
|
+
declare function ReviewReplies({ className, hidden }: ReviewPartProps): react.JSX.Element | null;
|
|
394
|
+
declare namespace ReviewReplies {
|
|
395
|
+
var docxReviewPart: "Replies";
|
|
396
|
+
}
|
|
397
|
+
/**
|
|
398
|
+
* The reply box.
|
|
399
|
+
*
|
|
400
|
+
* Open only on the ACTIVE card: a rail with a text field on every card is mostly text fields,
|
|
401
|
+
* and the caret landing in a tracked change is what says which conversation the reader is in.
|
|
402
|
+
*
|
|
403
|
+
* Replying to a revision writes a comment over that revision's range — `w:ins` and `w:del`
|
|
404
|
+
* have no body and no thread in OOXML, so there is nowhere else for the text to live.
|
|
405
|
+
*
|
|
406
|
+
* @public
|
|
407
|
+
*/
|
|
408
|
+
declare function ReviewReply({ className, hidden, children }: ReviewPartProps): react.JSX.Element | null;
|
|
409
|
+
declare namespace ReviewReply {
|
|
410
|
+
var docxReviewPart: "Reply";
|
|
411
|
+
}
|
|
412
|
+
/**
|
|
413
|
+
* The review rail compound.
|
|
414
|
+
*
|
|
415
|
+
* @public
|
|
416
|
+
*/
|
|
417
|
+
interface DocxEditorReviewNamespace {
|
|
418
|
+
(props: ReviewProps): ReturnType<typeof ReviewRoot>;
|
|
419
|
+
readonly List: typeof ReviewList;
|
|
420
|
+
readonly Empty: typeof ReviewEmpty;
|
|
421
|
+
readonly Card: typeof ReviewCard;
|
|
422
|
+
readonly Avatar: typeof ReviewAvatar;
|
|
423
|
+
readonly Author: typeof ReviewAuthor;
|
|
424
|
+
readonly Time: typeof ReviewTime;
|
|
425
|
+
readonly Summary: typeof ReviewSummary;
|
|
426
|
+
readonly Accept: typeof ReviewAccept;
|
|
427
|
+
readonly Reject: typeof ReviewReject;
|
|
428
|
+
/** Discard the card: delete a comment thread, or reject a tracked change. */
|
|
429
|
+
readonly Delete: typeof ReviewDelete;
|
|
430
|
+
readonly Replies: typeof ReviewReplies;
|
|
431
|
+
readonly Reply: typeof ReviewReply;
|
|
432
|
+
/** The collapsed rail: one marker per item, shown when the pane is closed. */
|
|
433
|
+
readonly Markers: typeof ReviewMarkers;
|
|
434
|
+
/** The "comment on this" button beside a selected range. */
|
|
435
|
+
readonly AddComment: typeof ReviewAddComment;
|
|
436
|
+
/** The compose box a new comment is written in. */
|
|
437
|
+
readonly Draft: typeof ReviewDraft;
|
|
438
|
+
/** The decision balloon opened by clicking a format or structural change in the page. */
|
|
439
|
+
readonly Balloon: typeof ReviewBalloon;
|
|
440
|
+
}
|
|
441
|
+
/**
|
|
442
|
+
* The review rail: comments and tracked changes as a compound component.
|
|
443
|
+
*
|
|
444
|
+
* `DocxEditorReview` is itself the root; every part hangs off it, so a host arranges the pieces
|
|
445
|
+
* it wants rather than accepting one fixed layout. Requires the review module to be registered
|
|
446
|
+
* via `createDocxEditor({ modules: [reviewModule()] })` — without it there is nothing to derive
|
|
447
|
+
* cards from.
|
|
448
|
+
*
|
|
449
|
+
* @example
|
|
450
|
+
* ```tsx
|
|
451
|
+
* <DocxEditorReview>
|
|
452
|
+
* <DocxEditorReview.List>
|
|
453
|
+
* <DocxEditorReview.Card>
|
|
454
|
+
* <DocxEditorReview.Author />
|
|
455
|
+
* <DocxEditorReview.Summary />
|
|
456
|
+
* <DocxEditorReview.Accept />
|
|
457
|
+
* <DocxEditorReview.Reject />
|
|
458
|
+
* </DocxEditorReview.Card>
|
|
459
|
+
* </DocxEditorReview.List>
|
|
460
|
+
* </DocxEditorReview>
|
|
461
|
+
* ```
|
|
462
|
+
*
|
|
463
|
+
* @public
|
|
464
|
+
*/
|
|
465
|
+
declare const DocxEditorReview: DocxEditorReviewNamespace;
|
|
466
|
+
|
|
467
|
+
/**
|
|
468
|
+
* Props for {@link CustomNodeChrome}: which definitions to paint, and where activation goes.
|
|
469
|
+
*
|
|
470
|
+
* The two hooks are the COMPONENT-level twins of a definition's own `onClick`/`onHover`. Host UI
|
|
471
|
+
* state — a popover, a dialog — belongs here rather than on the definition, which is shared by
|
|
472
|
+
* every surface and has no React context to close over.
|
|
473
|
+
*
|
|
474
|
+
* @public
|
|
475
|
+
*/
|
|
476
|
+
interface CustomNodeChromeProps {
|
|
477
|
+
/** Definitions to style and dispatch on. Defaults to the ones registered on the editor. */
|
|
478
|
+
readonly nodes?: readonly CustomNodeDefinition[];
|
|
479
|
+
/** Component-level activation hook — where host UI state (popovers) belongs. */
|
|
480
|
+
readonly onNodeClick?: (node: ActivatedCustomNode) => void;
|
|
481
|
+
readonly onNodeHover?: (node: ActivatedCustomNode) => void;
|
|
482
|
+
}
|
|
483
|
+
/**
|
|
484
|
+
* Paints custom-node chips and dispatches pointer activation on them.
|
|
485
|
+
*
|
|
486
|
+
* Renders nothing itself — it installs the per-definition chip styles and the click/hover
|
|
487
|
+
* listeners, so mount it once anywhere inside the editor provider. Chip colours come from each
|
|
488
|
+
* definition's `chrome`, which is HOST-authored and never file data.
|
|
489
|
+
*
|
|
490
|
+
* @example
|
|
491
|
+
* ```tsx
|
|
492
|
+
* <DocxEditor.Root>
|
|
493
|
+
* <CustomNodeChrome onNodeClick={(node) => setPopover(node)} />
|
|
494
|
+
* <DocxEditor.Viewport><DocxEditor.Content /></DocxEditor.Viewport>
|
|
495
|
+
* </DocxEditor.Root>
|
|
496
|
+
* ```
|
|
497
|
+
*
|
|
498
|
+
* @public
|
|
499
|
+
*/
|
|
500
|
+
declare function CustomNodeChrome(props: CustomNodeChromeProps): null;
|
|
501
|
+
|
|
502
|
+
/**
|
|
503
|
+
* Props for {@link CustomNodeContextMenu}: which definitions get menu sections, and which rows
|
|
504
|
+
* those sections offer.
|
|
505
|
+
*
|
|
506
|
+
* The Edit row renders when either the definition's own `onEdit` or this component's
|
|
507
|
+
* `onEditNode` is present; the Remove row is on by default but only where the node's canonical id
|
|
508
|
+
* can be resolved.
|
|
509
|
+
*
|
|
510
|
+
* @public
|
|
511
|
+
*/
|
|
512
|
+
interface CustomNodeContextMenuProps {
|
|
513
|
+
/** Definitions to offer sections for. Defaults to the ones registered on the editor. */
|
|
514
|
+
readonly nodes?: readonly CustomNodeDefinition[];
|
|
515
|
+
/**
|
|
516
|
+
* Component-level edit hook — where host UI state (an edit dialog) belongs, the twin of
|
|
517
|
+
* `CustomNodeChrome`'s `onNodeClick`. Runs after the definition's own `onEdit`. The row
|
|
518
|
+
* renders when EITHER hook is present.
|
|
519
|
+
*/
|
|
520
|
+
readonly onEditNode?: (node: ActivatedCustomNode, definition: CustomNodeDefinition) => void;
|
|
521
|
+
/**
|
|
522
|
+
* The "Remove {label}" row, on by default: it deletes the node — wrapper and label, one
|
|
523
|
+
* undo step — via `removeCustomNode`. Rendered only when the node's id is resolvable
|
|
524
|
+
* (a registered review module resolves it). `false` removes the row.
|
|
525
|
+
*/
|
|
526
|
+
readonly remove?: boolean;
|
|
527
|
+
}
|
|
528
|
+
/**
|
|
529
|
+
* Renders the pointed-at node's card data plus its "Edit {label}" row, or nothing when the
|
|
530
|
+
* right-click landed elsewhere. Carries `docxRowPlacement: 'start'`, so the context menu
|
|
531
|
+
* mounts it above the packaged rows.
|
|
532
|
+
*
|
|
533
|
+
* @public
|
|
534
|
+
*/
|
|
535
|
+
declare function CustomNodeContextMenu(props: CustomNodeContextMenuProps): react.JSX.Element | null;
|
|
536
|
+
declare namespace CustomNodeContextMenu {
|
|
537
|
+
var docxRowPlacement: "start";
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
/**
|
|
541
|
+
* The definitions a chrome surface should act on: the `nodes` prop when given, else the
|
|
542
|
+
* definitions registered on the editor (`customNodesModule`). Registering once and letting
|
|
543
|
+
* every surface default to it is the intended shape; the prop exists for a host that wants
|
|
544
|
+
* one surface scoped narrower.
|
|
545
|
+
*/
|
|
546
|
+
declare function useCustomNodeDefinitions(nodes: readonly CustomNodeDefinition[] | undefined): readonly CustomNodeDefinition[];
|
|
547
|
+
/**
|
|
548
|
+
* What {@link resolveCustomNodeActivation} found under a pointer target.
|
|
549
|
+
*
|
|
550
|
+
* The RAW decode, before the definition's `fromDocx` has had its say — use
|
|
551
|
+
* `activatedCustomNodeOf` for the enriched form every host hook receives.
|
|
552
|
+
*
|
|
553
|
+
* @public
|
|
554
|
+
*/
|
|
555
|
+
interface ResolvedCustomNodeActivation {
|
|
556
|
+
/** RAW decode: attrs straight from the tag, `fromDocx` not yet applied. */
|
|
557
|
+
readonly node: ActivatedCustomNode;
|
|
558
|
+
readonly definition: CustomNodeDefinition;
|
|
559
|
+
/** The control's canonical node id, from the chrome layer — for review-item lookups. */
|
|
560
|
+
readonly controlId: string | null;
|
|
561
|
+
}
|
|
562
|
+
/**
|
|
563
|
+
* The recognized custom node a pointer target sits on, or null.
|
|
564
|
+
*
|
|
565
|
+
* Every input here is DOM the engine painted from file data — the tag is
|
|
566
|
+
* attacker-controlled and goes through the codec's guards, never into markup.
|
|
567
|
+
*/
|
|
568
|
+
/**
|
|
569
|
+
* The activation every host hook receives: identity, POST-`fromDocx` attrs, and — when the
|
|
570
|
+
* review module derived a card for the node — its literal text and canonical node id.
|
|
571
|
+
*
|
|
572
|
+
* One enrichment step for every surface (click, hover, edit, context-menu card), so a hook
|
|
573
|
+
* written against the review rail's attrs shape sees the SAME shape from the chip. Without
|
|
574
|
+
* a review module the definition's `fromDocx` runs over the raw decode with `text: ''`;
|
|
575
|
+
* its veto (null) drops the activation, exactly as recognition would have.
|
|
576
|
+
*/
|
|
577
|
+
declare function activatedCustomNodeOf(resolved: ResolvedCustomNodeActivation, editor: Editor | null | undefined): ActivatedCustomNode | null;
|
|
578
|
+
/**
|
|
579
|
+
* The recognized custom node a pointer target sits on, or null.
|
|
580
|
+
*
|
|
581
|
+
* Walks up from `target` to the painted control boundary, reads its `data-tag`, and matches the
|
|
582
|
+
* decoded identity against `nodes`. Returns null for anything that is not a recognized chip —
|
|
583
|
+
* ordinary text, an unclaimed SDT, a tag no definition owns.
|
|
584
|
+
*
|
|
585
|
+
* Every input is DOM the engine painted from FILE DATA. The tag is attacker-controlled and goes
|
|
586
|
+
* through the codec's guards; it never reaches markup.
|
|
587
|
+
*
|
|
588
|
+
* @public
|
|
589
|
+
*/
|
|
590
|
+
declare function resolveCustomNodeActivation(target: EventTarget | null, nodes: readonly CustomNodeDefinition[]): ResolvedCustomNodeActivation | null;
|
|
591
|
+
|
|
592
|
+
export { CustomNodeChrome, type CustomNodeChromeProps, CustomNodeContextMenu, type CustomNodeContextMenuProps, DocxEditorReview, type DocxEditorReviewNamespace, type ResolvedCustomNodeActivation, type ReviewActionProps, type ReviewItemView, type ReviewPartProps, type ReviewProps, type UseReviewReturn, activatedCustomNodeOf, resolveCustomNodeActivation, useCustomNodeDefinitions, useReview, useReviewItem, useReviewOf, useStackedReviewPositions };
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import {d,c,j,e}from'../chunk-NZOS3H23.js';export{i as reviewModule}from'../chunk-NZOS3H23.js';import {createContext,useMemo,useCallback,useRef,useContext,useEffect,useState,isValidElement,cloneElement,useId,useSyncExternalStore,Fragment as Fragment$1}from'react';import {useDocxEditor,useTranslation,ReviewRailContext,Slot,useContextMenuTarget,ContextMenuItem}from'@docx-editor.dev/react';import {jsxs,Fragment,jsx}from'react/jsx-runtime';function me(e){let r=useDocxEditor();return nt(r,e)}function nt(e,r){let l=useCallback(p=>{if(!e)return ()=>{};let y=e.on("change",p),P=e.on("selectionChange",p);return ()=>{y(),P();}},[e]),s=useSyncExternalStore(l,()=>e?`${e.getReviewRevision()}`:"none",()=>"none"),t=useMemo(()=>e?e.getReviewItems(r):[],[e,s,r]),o=useMemo(()=>t.find(p=>p.isActive)?.key??null,[t]),i=useCallback(p=>{e?.setActiveReviewItem(p);},[e]),n=useCallback(p=>{p.kind!=="revision"||p.readOnly||e?.acceptReviewItem(p.key);},[e]),d=useCallback(p=>{p.kind!=="revision"||p.readOnly||e?.rejectReviewItem(p.key);},[e]),c=useCallback(p=>!e||p.kind==="custom"||p.kind==="revision"&&p.readOnly?false:e.deleteReviewItem(p.key).ok,[e]),v=useCallback((p,y,P)=>y.trim().length===0||!e?false:e.replyToReviewItem(p.key,y,P).ok,[e]),b=useMemo(()=>e?e.getSelectionPlacement()?.anchorY??null:null,[e,s]),R=useCallback((p,y)=>p.trim().length===0||!e?false:e.addComment(p,y).ok,[e]),w=useMemo(()=>e?e.isReviewPaneOpen():true,[e,s]),f=useCallback(p=>{!e||e.isReviewPaneOpen()===p||e.exec({type:"toggleReviewPane"});},[e]);return useMemo(()=>({items:t,activeKey:o,setActive:i,accept:n,reject:d,remove:c,reply:v,selectionAnchorY:b,comment:R,paneOpen:w,setPaneOpen:f,ready:e!==null}),[t,o,i,n,d,c,v,b,R,w,f,e])}function ht(e,r,l={}){let s=l.gap??8,t=l.scale??1,o=l.defaultHeight??0;return useMemo(()=>{let i=new Map,n=Number.NEGATIVE_INFINITY;for(let d of e){if(d.anchorY===null)continue;let c=Math.max(d.anchorY,n);i.set(d.key,c),n=c+((r.get(d.key)??o)+s)/t;}return i},[e,r,s,t,o])}var Pe=createContext(null),k=createContext(null);function Pt(){return useContext(k)}var It={scale:96/72,top:0,left:null},kt=16,ve="\0compose",ot=600,it=8,At=72,Mt=64,Tt=480,Dt=Object.freeze({placement:false});function Ie(e,r){return e.kind!=="comment"?false:e.parentId!==void 0?r.has(e.parentId):e.parentRevisionId!==void 0?r.has(e.parentRevisionId):false}function ke(e){return new Set(e.map(r=>r.id))}function F(e){let r=e.target?.tagName;r==="INPUT"||r==="SELECT"||r==="TEXTAREA"||e.preventDefault();}function O(){let e=useContext(Pe);return e||St}function Y(){let{t:e}=useContext(Pe)??{},{t:r}=useTranslation();return useCallback(l=>e?.(l)??r(l),[e,r])}var St={t:void 0,cardClassName:void 0,review:{items:[],activeKey:null,setActive:()=>{},accept:()=>{},reject:()=>{},remove:()=>false,reply:()=>false,selectionAnchorY:null,comment:()=>false,paneOpen:true,setPaneOpen:()=>{},ready:false},allItems:[],authorSlots:new Map,byId:new Map,measure:()=>{},beginDraft:()=>{},endDraft:()=>{}},re=e=>jsx("svg",{viewBox:"0 -960 960 960",width:16,height:16,"aria-hidden":"true",focusable:"false",children:jsx("path",{d:e,fill:"currentColor"})}),Lt="M440-400h80v-120h120v-80H520v-120h-80v120H320v80h120v120ZM80-80v-720q0-33 23.5-56.5T160-880h640q33 0 56.5 23.5T880-800v480q0 33-23.5 56.5T800-240H240L80-80Zm126-240h594v-480H160v525l46-45Zm-46 0v-480 480Z",Ot="M240-400h480v-80H240v80Zm0-120h480v-80H240v80Zm0-120h480v-80H240v80ZM880-80 720-240H160q-33 0-56.5-23.5T80-320v-480q0-33 23.5-56.5T160-880h640q33 0 56.5 23.5T880-800v720ZM160-320h594l46 45v-525H160v480Zm0 0v-480 480Z",$t="M382-240 154-468l57-57 171 171 367-367 57 57-424 424Z",Ht="m256-200-56-56 224-224-224-224 56-56 224 224 224-224 56 56-224 224 224 224-56 56-224-224-224 224Z",Vt="M280-120q-33 0-56.5-23.5T200-200v-520h-40v-80h200v-40h240v40h200v80h-40v520q0 33-23.5 56.5T680-120H280Zm400-600H280v520h400v-520ZM360-280h80v-360h-80v360Zm160 0h80v-360h-80v360ZM280-720v520-520Z";function Kt({className:e,furniture:r,asChild:l,hidden:s,children:t,t:o,card:i,preset:n=true,stack:d=true,gap:c=8,filter:v,structural:b=false,formatting:R=false}){let w=useDocxEditor(),f=useMemo(()=>{let m=[];return b||m.push("structural"),R||m.push("format"),m.length>0?m:void 0},[b,R]),p=useMemo(()=>f?{excludeRevisionKinds:f}:void 0,[f]),y=me(Dt),P=me(p),I=P.setPaneOpen,{t:E}=useTranslation(),C=useCallback(m=>o?.(m)??E(m),[o,E]),_=useRef(null),$=useContext(ReviewRailContext);useEffect(()=>$?.register(),[$]);let q=P.paneOpen,M=useMemo(()=>v?P.items.filter(m=>v(m)):P.items,[P.items,v]),ee=useMemo(()=>{let m=new Map;for(let u of M)u.author&&!m.has(u.author)&&m.set(u.author,m.size);return m},[M]),Ke=useMemo(()=>{let m=new Map;for(let u of M)m.set(u.id,u);return m},[M]),[Ye,vt]=useState(()=>new Map),ye=useCallback((m,u)=>{u<=0||vt(x=>{if(x.get(m)===u)return x;let N=new Map(x);return N.set(m,u),N});},[]),be=useRef(new WeakMap),te=useRef(null),Be=useCallback((m,u)=>{!m||typeof ResizeObserver>"u"||(ye(u,m.offsetHeight),te.current??(te.current=new ResizeObserver(x=>{for(let N of x){let g=be.current.get(N.target);g&&ye(g,N.target.offsetHeight);}})),be.current.get(m)!==u&&(be.current.set(m,u),te.current.observe(m)));},[ye]);useEffect(()=>()=>te.current?.disconnect(),[]);let[D,ft]=useState(It);useEffect(()=>{let m=_.current;if(!w||!m)return;let u=m.offsetParent,x=u?.querySelector(".docx-paginated-surface")??null,N=()=>{ft(T=>{let H=x&&u?x.getBoundingClientRect():null,L=H&&u?u.getBoundingClientRect():null,V={scale:w.getRenderScale(),top:H&&L&&u?H.top-L.top-u.clientTop+u.scrollTop:0,left:H&&L&&u?H.right-L.left-u.clientLeft+u.scrollLeft+kt:null};return T.scale===V.scale&&T.top===V.top&&T.left===V.left?T:V});};N();let g=new ResizeObserver(N);return u&&g.observe(u),x&&g.observe(x),()=>g.disconnect()},[w,M]),useEffect(()=>{let m=_.current;if(!w||!m)return;let u=x=>{let N=x.target;if(!(N instanceof Node)||m.contains(N))return;let g=m.offsetParent;!g||!g.contains(N)||g.querySelector(".docx-paginated-surface")?.contains(N)||w.setActiveReviewItem(null);};return document.addEventListener("mousedown",u,true),()=>document.removeEventListener("mousedown",u,true)},[w]);let[xe,pt]=useState(null);useEffect(()=>{let m=_.current,u=m?.offsetParent;if(!u)return;let x=0,N=()=>{x=0,pt(L=>{let V=u.scrollTop-ot,ue=u.scrollTop+u.clientHeight+ot;return L&&L.top===V&&L.bottom===ue?L:{top:V,bottom:ue}});},g=0,T=()=>{x===0&&(x=requestAnimationFrame(N)),m?.setAttribute("data-scrolling",""),window.clearTimeout(g),g=window.setTimeout(()=>m?.removeAttribute("data-scrolling"),150);};N(),u.addEventListener("scroll",T,{passive:true});let H=new ResizeObserver(T);return H.observe(u),()=>{x!==0&&cancelAnimationFrame(x),window.clearTimeout(g),u.removeEventListener("scroll",T),H.disconnect();}},[w]);let[B,he]=useState(null),je=useCallback(()=>{w&&(w.surface?.retainSelection(),I(true),he(w.getSelectionPlacement()?.anchorY??null));},[w,I]),Ze=useCallback(()=>{w?.surface?.releaseSelection(),he(null),w?.focus();},[w]);useEffect(()=>{q||B===null||(w?.surface?.releaseSelection(),he(null));},[q,B,w]);let Fe=B??P.selectionAnchorY,U=useMemo(()=>{let m=ke(M);return M.filter(u=>!Ie(u,m))},[M]),qe=useMemo(()=>{if(B===null)return U;let m=U.findIndex(x=>x.anchorY!==null&&x.anchorY>B),u={key:ve,anchorY:B};return m===-1?[...U,u]:[...U.slice(0,m),u,...U.slice(m)]},[U,B]),Ue=useMemo(()=>{let m=new Map(Ye);for(let u of U){if(m.has(u.key))continue;let x=u.text.length+(u.kind==="revision"?u.replacedText?.length??0:0),N=Math.min(6,Math.max(1,Math.ceil(x/36)));m.set(u.key,64+N*20);}return m},[Ye,U]),{stacked:ge,collapsedKeys:ze}=useMemo(()=>{let m=D.scale,u=new Map,x=new Set,N=Number.NEGATIVE_INFINITY;for(let g of qe){let T=g.anchorY===null?Number.isFinite(N)?N:0:Math.max(g.anchorY,N);u.set(g.key,T);let H=g.anchorY===null?0:(T-g.anchorY)*m,L="isActive"in g&&g.isActive,V=H>Tt&&!L&&g.key!==ve;V&&x.add(g.key);let ue=V?Mt:Ue.get(g.key)??At;N=T+(ue+c)/m;}return {stacked:u,collapsedKeys:x}},[qe,Ue,c,D.scale]),Ne=Fe===null?null:D.top+(ge.get(ve)??Fe)*D.scale,Qe=i?.className,wt=useMemo(()=>({t:o,cardClassName:Qe,review:{...P,items:M},allItems:y.items,authorSlots:ee,byId:Ke,measure:Be,beginDraft:je,endDraft:Ze}),[o,Qe,P,y.items,M,ee,Ke,Be,je,Ze]);if(s)return null;let Ge={ref:_,className:`docx-review${e?` ${e}`:""}`,"data-testid":"review-rail","data-count":M.length,"data-open":q?"":void 0,role:"complementary","aria-label":C("review.ariaLabel"),onMouseDown:F,style:D.left===null?void 0:{left:D.left,right:"auto"}},We=typeof t=="function"?{}:at(t),ne=(m,u)=>m in We?We[m]:u,Xe=n?jsxs(Fragment,{children:[ne("AddComment",jsx(Me,{top:Ne,drafting:B!==null})),!q||B===null||Ne===null?null:ne("Draft",jsx(Te,{top:Ne})),ne("Balloon",jsx(De,{}))]}):null,Rt=n?q?ne("List",jsx(fe,{stack:d,positions:ge,collapsed:ze,scale:D.scale,offset:D.top,window:xe,children:t})):ne("Markers",jsx(Ae,{scale:D.scale,offset:D.top,window:xe})):typeof t=="function"?null:t;return jsx(Pe.Provider,{value:wt,children:l&&isValidElement(t)?jsx(Slot,{...Ge,children:cloneElement(t,void 0,t.props.children,n?jsx(fe,{stack:d,positions:ge,collapsed:ze,scale:D.scale,offset:D.top,window:xe}):null,Xe)}):jsxs("aside",{...Ge,children:[q&&r!==void 0?jsx("div",{className:"docx-review__furniture","data-testid":"review-furniture",children:r}):null,Rt,Xe]})})}function fe({stack:e=true,positions:r,collapsed:l,scale:s=1,offset:t=0,window:o=null,children:i,className:n,hidden:d}){let{review:c,measure:v,cardClassName:b}=O();if(d)return null;let R=ke(c.items),w=c.items.filter(f=>!Ie(f,R));return w.length===0?typeof i=="function"?null:jsx(Se,{}):jsx("div",{className:`docx-review__list${n?` ${n}`:""}`,children:w.map(f=>{let p=e?r?.get(f.key)??f.anchorY:f.anchorY,y=p==null?null:t+p*s;if(y!==null&&o&&(y<o.top||y>o.bottom))return null;let P=y===null?{}:{position:"absolute",top:y};return jsx(k.Provider,{value:f,children:jsx("div",{className:"docx-review__slot",style:P,...l?.has(f.key)?{"data-collapsed":""}:{},ref:I=>{v(I,f.key);},children:typeof i=="function"?i(f):jsx(Le,{...b?{className:b}:{},children:i})})},f.key)})})}fe.docxReviewPart="List";function Ae({scale:e=1,offset:r=0,window:l=null,className:s,hidden:t}){let{review:o}=O(),i=Y();if(t)return null;let n=ke(o.items),d=o.items.filter(c=>!Ie(c,n));return jsx("div",{className:`docx-review__markers${s?` ${s}`:""}`,children:d.map(c=>{if(c.anchorY===null)return null;let v=r+c.anchorY*e;return l&&(v<l.top||v>l.bottom)?null:jsx("button",{type:"button",className:"docx-review__marker","data-testid":"review-marker","data-kind":c.kind==="revision"?c.revisionKind:c.kind,style:{position:"absolute",top:v},title:c.author?`${c.author}: ${c.text}`:c.text,"aria-label":`${i("review.showPane")}: ${c.author?`${c.author}. `:""}${c.text}`,onMouseDown:F,onClick:()=>{o.setPaneOpen(true),o.setActive(c.key);},children:re(Ot)},c.key)})})}Ae.docxReviewPart="Markers";function Me({top:e,drafting:r=false,className:l,hidden:s,children:t}){let{beginDraft:o}=O(),i=Y();if(s||r||e===null)return null;let n={type:"button",className:`docx-review__add${l?` ${l}`:""}`,"data-testid":"review-add-comment",style:{position:"absolute",top:e},"aria-label":i("common.comment"),title:i("common.comment"),onMouseDown:F,onClick:o};return t?jsx(Slot,{...n,children:t}):jsx("button",{...n,children:re(Lt)})}Me.docxReviewPart="AddComment";function Te({top:e,className:r,hidden:l}){let{review:s,endDraft:t,measure:o}=O(),i=Y(),[n,d]=useState(""),[c,v]=useState(false),b=useRef(null),R=useId();useEffect(()=>{b.current?.focus({preventScroll:true});},[]);let w=useCallback(()=>{if(n.trim().length===0)return;let f=s.comment(n.trim());v(!f),f&&(d(""),t());},[n,s,t]);return l?null:jsx("div",{className:`docx-review__slot${r?` ${r}`:""}`,style:{position:"absolute",top:e},ref:f=>{o(f,ve);},children:jsx("div",{className:"docx-review__card","data-testid":"review-draft","data-draft":"",children:jsxs("form",{className:"docx-review__reply-box",onSubmit:f=>{f.preventDefault(),w();},children:[jsx("label",{className:"ep-sr-only",htmlFor:R,children:i("comments.addComment")}),jsx("input",{id:R,ref:b,"data-testid":"review-draft-input",className:"docx-review__input",value:n,placeholder:i("comments.addComment"),...c?{"aria-invalid":true}:{},onChange:f=>{v(false),d(f.target.value);},onKeyDown:f=>{if(f.key==="Escape"){f.preventDefault(),t();return}f.key==="Enter"&&(f.preventDefault(),w());}}),jsxs("div",{className:"docx-review__reply-actions",children:[jsx("button",{type:"button","data-testid":"review-draft-cancel",className:"docx-review__text-button",onMouseDown:F,onClick:t,children:i("common.cancel")}),jsx("button",{type:"submit","data-testid":"review-draft-submit",className:"docx-review__submit",disabled:n.trim().length===0,children:i("common.comment")})]}),c?jsx("span",{className:"docx-review__refused",role:"alert",children:i("review.commentRefused")}):null]})})})}Te.docxReviewPart="Draft";function De({className:e,hidden:r}){let{review:l,allItems:s,authorSlots:t}=O(),o=Y(),i=useRef(null),[n,d]=useState(null),c=useRef(false);c.current=n!==null,useEffect(()=>{let f=i.current,p=f?.closest(".docx-review"),y=p?.closest(".docx-editor__scroll-container")??p?.offsetParent;if(!f||!p||!y)return;let P=(E,C)=>{let _=p.getBoundingClientRect(),$=E.getBoundingClientRect(),q=E.ownerDocument.defaultView?.innerHeight??1/0,M=Number(E.dataset.start),ee=Number(E.dataset.end);d({revisionId:E.dataset.revisionId,author:E.dataset.revisionAuthor??"",...E.dataset.revisionDate!==void 0?{date:E.dataset.revisionDate}:{},...E.dataset.revisionKind!==void 0?{kind:E.dataset.revisionKind}:{},structuralSite:C,...E.dataset.paragraphId!==void 0?{paragraphId:E.dataset.paragraphId}:{},...Number.isFinite(M)?{start:M}:{},...Number.isFinite(ee)?{end:ee}:{},left:$.left-_.left,top:$.top-_.top,bottom:$.bottom-_.top,above:$.bottom+220>q});},I=E=>{let C=E.target;if(!(C instanceof Element)||f.contains(C))return;let _=C.closest("[data-revision-id]");if(_ instanceof HTMLElement&&y.contains(_)){let $=_.classList.contains("docx-table-row--revision");if(_.dataset.revisionKind==="format"||$){P(_,$);return}}c.current&&d(null);};return y.addEventListener("pointerdown",I,true),y.addEventListener("mousedown",I,true),()=>{y.removeEventListener("pointerdown",I,true),y.removeEventListener("mousedown",I,true);}},[]);let v=useMemo(()=>{if(!n)return null;let f=null,p=false,y=null,P=false,I=null,E=false;for(let C of s)if(!(C.kind!=="revision"||C.item.kind!=="revision")){for(let _ of C.item.addresses)if(_.id===n.revisionId){if(_.author===n.author){if(_.date===n.date)return C;f===null?f=C:f!==C&&(p=true);}y===null?y=C:y!==C&&(P=true);}if(n.paragraphId!==void 0&&n.start!==void 0&&n.end!==void 0&&(C.revisionKind==="format"||C.revisionKind==="structural")){for(let _ of C.item.ranges)if(_.start.paragraphId===n.paragraphId&&_.start.offset<n.end&&_.end.offset>n.start){I===null?I=C:I!==C&&(E=true);break}}}return f!==null&&!p?f:y!==null&&!P?y:I!==null&&!E?I:null},[s,n]),b=v&&(v.revisionKind==="format"||v.revisionKind==="structural")?v:null,R=useRef(false);if(useEffect(()=>{if(b){R.current=true;return}R.current&&(R.current=false,d(null));},[b]),r)return null;let w=n?.kind==="format"?"format":"structural";return jsx("div",{ref:i,className:`docx-review__balloon-root${e?` ${e}`:""}`,children:n===null?null:jsx("div",{className:"docx-review__balloon","data-testid":"review-balloon",style:{left:n.left,top:n.above?n.top-6:n.bottom+6,transform:n.above?"translateY(-100%)":void 0},onMouseDown:F,children:b?jsx(k.Provider,{value:b,children:jsxs("div",{className:"docx-review__card","data-testid":"review-balloon-card","data-kind":b.revisionKind??"revision",style:{"--doc-review-author":`var(--doc-review-author-${(t.get(b.author)??0)%it})`},onClick:()=>l.setActive(b.key),children:[jsxs("div",{className:"docx-review__head",children:[jsx(ie,{}),jsxs("div",{className:"docx-review__meta",children:[jsx(ae,{}),jsx(se,{})]}),b.kind==="revision"&&!b.readOnly?jsxs("div",{className:"docx-review__actions",children:[jsx(pe,{}),jsx(we,{})]}):null]}),jsx(le,{})]})}):jsxs("div",{className:"docx-review__card","data-testid":"review-balloon-card","data-kind":w,children:[jsxs("div",{className:"docx-review__head",children:[jsx("span",{className:"docx-review__avatar","aria-hidden":"true",children:Yt(n.author)}),jsxs("div",{className:"docx-review__meta",children:[jsx("span",{className:"docx-review__author",children:n.author||o("comments.unknown")}),n.date?jsx(Bt,{raw:n.date}):null]})]}),jsx("div",{className:"docx-review__summary",children:jsx("span",{className:"docx-review__label","data-kind":w,children:o(lt(w))})})]})})})}De.docxReviewPart="Balloon";function Yt(e){let r=e.trim().split(/\s+/).filter(Boolean);return r.length===0?"?":r.slice(0,2).map(l=>l[0].toUpperCase()).join("")}function Bt({raw:e}){let r=new Date(e);return Number.isNaN(r.getTime())?null:jsx("time",{className:"docx-review__time",dateTime:e,children:st.format(r)})}function Se({className:e,hidden:r,children:l}){let s=Y();return r?null:jsx("div",{className:`docx-review__empty${e?` ${e}`:""}`,"data-testid":"review-empty",children:l??s("review.empty")})}Se.docxReviewPart="Empty";function Le({className:e,asChild:r,hidden:l,children:s}){let{review:t,authorSlots:o}=O(),i=useContext(k),n=useId();if(l||!i)return null;let d=o.get(i.author)??0,c={className:`docx-review__card${e?` ${e}`:""}`,"data-testid":"review-card","aria-labelledby":`${n}-author ${n}-summary`,"data-kind":i.kind==="revision"?i.revisionKind??"revision":i.kind,...i.kind==="custom"&&i.item.kind==="custom"?{"data-node-name":i.item.name}:{},...i.isActive?{"data-active":""}:{},...i.kind==="comment"&&i.resolved?{"data-resolved":""}:{},style:{"--doc-review-author":`var(--doc-review-author-${d%it})`},tabIndex:0,role:"button",id:n,onMouseDown:v=>{v.target?.closest("[data-review-selectable]")||v.currentTarget.focus({preventScroll:true});},onClick:()=>t.setActive(i.key),onKeyDown:v=>{v.target===v.currentTarget&&(v.key!=="Enter"&&v.key!==" "||(v.preventDefault(),t.setActive(i.key)));}};return r?jsx(Slot,{...c,children:s}):jsx("div",{...c,children:jsx(jt,{children:s})})}Le.docxReviewPart="Card";function jt({children:e}){let r=useContext(k),l=useMemo(()=>at(e),[e]),s=(o,i)=>o in l?l[o]:i;if(!r)return null;if(r.kind==="custom"&&r.item.kind==="custom"){let o=r.item;return jsxs(Fragment,{children:[jsxs("div",{className:"docx-review__head",children:[s("Avatar",null),jsx("div",{className:"docx-review__meta",children:s("Author",jsx("span",{className:"docx-review__author","data-testid":"review-custom-title",children:o.title}))})]}),s("Summary",o.detail?jsx("div",{className:"docx-review__summary","data-testid":"review-summary","data-review-selectable":"",children:jsx("span",{className:"docx-review__text",children:o.detail})}):null),l.__extra]})}let t=r.kind==="revision"&&!r.readOnly;return jsxs(Fragment,{children:[jsxs("div",{className:"docx-review__head",children:[s("Avatar",jsx(ie,{})),jsxs("div",{className:"docx-review__meta",children:[s("Author",jsx(ae,{})),s("Time",jsx(se,{}))]}),t||r.kind==="comment"?jsxs("div",{className:"docx-review__actions",children:[s("Accept",jsx(pe,{})),s("Reject",jsx(we,{})),s("Delete",jsx(Re,{}))]}):null]}),s("Summary",jsx(le,{})),s("Replies",jsx(Oe,{})),s("Reply",jsx($e,{})),l.__extra]})}function at(e){let r={},l=[],s=t=>{if(Array.isArray(t)){t.forEach(s);return}if(!t||typeof t!="object"||!("type"in t)){t&&l.push(t);return}if(t.type===Fragment$1){s(t.props.children);return}let o=t.type.docxReviewPart;o?r[o]=t:l.push(t);};return s(e),l.length>0&&(r.__extra=l),r}function ie({className:e,asChild:r,hidden:l,children:s}){let t=useContext(k);if(l||!t||s===void 0&&!t.initials)return null;let o={className:`docx-review__avatar${e?` ${e}`:""}`,"data-testid":"review-avatar","aria-hidden":true};return r?jsx(Slot,{...o,children:s}):jsx("span",{...o,children:s??t.initials})}ie.docxReviewPart="Avatar";function ae({className:e,asChild:r,hidden:l,children:s}){let t=useContext(k),o=Y();if(l||!t)return null;let i=t.author||o("comments.unknown"),n={className:`docx-review__author${e?` ${e}`:""}`,"data-testid":"review-author"};return r?jsx(Slot,{...n,children:s}):jsx("span",{...n,children:s??i})}ae.docxReviewPart="Author";function se({className:e,asChild:r,hidden:l,children:s}){let t=useContext(k);if(l||!t)return null;let o=t.date;if(!o)return null;let i=new Date(o);if(Number.isNaN(i.getTime()))return null;let n={className:`docx-review__time${e?` ${e}`:""}`,"data-testid":"review-time",dateTime:o};return r?jsx(Slot,{...n,children:s}):jsx("time",{...n,children:s??st.format(i)})}se.docxReviewPart="Time";var st=new Intl.DateTimeFormat(void 0,{month:"short",day:"numeric",hour:"numeric",minute:"2-digit"});function le({className:e,asChild:r,hidden:l,children:s}){let t=useContext(k),o=Y();if(l||!t)return null;let i=t.text,n=t.kind!=="revision"?null:o(lt(t.revisionKind)),d=t.kind==="revision"&&t.revisionKind==="replace",c={className:`docx-review__summary${e?` ${e}`:""}`,"data-testid":"review-summary","data-review-selectable":""};return r?jsx(Slot,{...c,children:s}):jsx("div",{...c,children:s??(d?jsxs("span",{className:"docx-review__text",children:[o("review.replaced")," ",jsxs("span",{className:"docx-review__removed",children:['"',t.replacedText,'"']})," ",o("review.replacedWith")," ",jsxs("span",{className:"docx-review__added",children:['"',i,'"']})]}):jsxs(Fragment,{children:[n?jsx("span",{className:"docx-review__label","data-kind":t.kind==="revision"?t.revisionKind:"revision",children:n}):null,i?jsx("span",{className:"docx-review__text",children:i}):null]}))})}le.docxReviewPart="Summary";function lt(e){switch(e){case "insert":return "review.inserted";case "delete":return "review.deleted";case "replace":return "review.replaced";case "moveFrom":return "review.movedFrom";case "moveTo":return "review.movedTo";case "format":return "revisions.runPropertiesChanged";case "paragraphMark":return "revisions.paragraphMarkInserted";default:return "review.structural"}}function pe({className:e,asChild:r,hidden:l,children:s,icon:t}){let{review:o}=O(),i=useContext(k),n=Y();if(l||!i||i.kind!=="revision"||i.readOnly)return null;let d=n("review.accept"),c={type:"button",className:`docx-review__action${e?` ${e}`:""}`,"data-testid":"review-accept","aria-label":d,title:d,onMouseDown:F,onClick:v=>{v.stopPropagation(),o.accept(i);}};return r?jsx(Slot,{...c,children:s}):jsx("button",{...c,children:t??s??re($t)})}pe.docxReviewPart="Accept";function we({className:e,asChild:r,hidden:l,children:s,icon:t}){let{review:o}=O(),i=useContext(k),n=Y();if(l||!i||i.kind!=="revision"||i.readOnly)return null;let d=n("review.reject"),c={type:"button",className:`docx-review__action${e?` ${e}`:""}`,"data-testid":"review-reject","aria-label":d,title:d,onMouseDown:F,onClick:v=>{v.stopPropagation(),o.reject(i);}};return r?jsx(Slot,{...c,children:s}):jsx("button",{...c,children:t??s??re(Ht)})}we.docxReviewPart="Reject";function Re({className:e,asChild:r,hidden:l,children:s,icon:t}){let{review:o}=O(),i=useContext(k),{t:n}=useTranslation();if(l||!i||i.kind==="custom"||i.kind==="revision"&&i.readOnly)return null;let d=i.kind==="comment"?n("review.deleteComment"):n("review.discardChange"),c={type:"button",className:`docx-review__action${e?` ${e}`:""}`,"data-testid":"review-delete","aria-label":d,title:d,onMouseDown:F,onClick:v=>{v.stopPropagation(),o.remove(i);}};return r?jsx(Slot,{...c,children:s}):jsx("button",{...c,children:t??s??re(Vt)})}Re.docxReviewPart="Delete";function Oe({className:e,hidden:r}){let{byId:l}=O(),s=useContext(k);if(r||!s||s.kind==="custom")return null;let t=s.replyIds.map(o=>l.get(o)).filter(o=>o!==void 0);return t.length===0?null:jsx("ol",{className:`docx-review__replies${e?` ${e}`:""}`,children:t.map(o=>jsx(k.Provider,{value:o,children:jsxs("li",{className:"docx-review__reply","data-testid":"review-reply",children:[jsxs("div",{className:"docx-review__head",children:[jsx(ie,{}),jsxs("div",{className:"docx-review__meta",children:[jsx(ae,{}),jsx(se,{})]}),jsx("div",{className:"docx-review__actions",children:jsx(Re,{})})]}),jsx(le,{})]})},o.key))})}Oe.docxReviewPart="Replies";function $e({className:e,hidden:r,children:l}){let{review:s}=O(),t=useContext(k),o=Y(),[i,n]=useState(""),[d,c]=useState(false),v=useId(),b=useCallback(()=>{if(!t||i.trim().length===0)return;let R=s.reply(t,i.trim());c(!R),R&&n("");},[t,i,s]);return r||!t||!t.isActive?null:l?jsx(Fragment,{children:l}):jsxs("form",{className:`docx-review__reply-box${e?` ${e}`:""}`,onSubmit:R=>{R.preventDefault(),b();},children:[jsx("label",{className:"ep-sr-only",htmlFor:v,children:o("comments.replyPlaceholder")}),jsx("input",{id:v,"data-testid":"review-reply-input",className:"docx-review__input",value:i,placeholder:o("comments.replyPlaceholder"),...d?{"aria-invalid":true,"data-refused":""}:{},onChange:R=>{c(false),n(R.target.value);},onClick:R=>R.stopPropagation(),onKeyDown:R=>{R.key==="Enter"&&(R.preventDefault(),b());}}),jsxs("div",{className:"docx-review__reply-actions",children:[jsx("button",{type:"button","data-testid":"review-reply-cancel",className:"docx-review__text-button",onMouseDown:F,onClick:R=>{R.stopPropagation(),n(""),c(false),s.setActive(null);},children:o("common.cancel")}),jsx("button",{type:"submit","data-testid":"review-reply-submit",className:"docx-review__submit",disabled:i.trim().length===0,children:o("review.reply")})]}),d?jsx("span",{className:"docx-review__refused",role:"alert","data-testid":"review-reply-refused",children:o("review.replyRefused")}):null]})}$e.docxReviewPart="Reply";var Zt=Object.assign(Kt,{List:fe,Empty:Se,Card:Le,Avatar:ie,Author:ae,Time:se,Summary:le,Accept:pe,Reject:we,Delete:Re,Replies:Oe,Reply:$e,Markers:Ae,AddComment:Me,Draft:Te,Balloon:De});function ce(e){let r=useDocxEditor();return useMemo(()=>e||(r?.getCustomNodeDefinitions()??[]).filter(d),[e,r])}var Ut=".docx-content-control-boundary";function X(e,r){let{node:l,definition:s,controlId:t}=e,o=t?r?.getReviewItems().find(n=>n.kind==="custom"&&n.item.id===t):void 0;if(o&&o.kind==="custom"){let n=o.item;return {...l,attrs:n.attrs,text:n.text,...t?{nodeId:t}:{}}}let i=s.fromDocx?s.fromDocx({attrs:l.attrs,text:""}):l.attrs;return i===null?null:{...l,attrs:i,...t?{nodeId:t}:{}}}function J(e,r){let l=e?.closest?.(Ut),s=l?.closest(".docx-content-control-chrome"),t=s?.getAttribute("data-tag"),o=t?c(t):null;if(!l||!o||!t)return null;let i=r.find(n=>n.tagPrefix===o.prefix&&n.name===o.name);return i?{node:{name:o.name,attrs:o.attrs,tag:t,rect:l.getBoundingClientRect()},definition:i,controlId:s?.getAttribute("data-docx-content-control")??null}:null}var He=".docx-content-control-boundary",Qt=e$1=>{if(!e.test(e$1.tagPrefix)||!e.test(e$1.name))return [];let r=`${e$1.tagPrefix}:${e$1.name}`;return [`.docx-content-control-chrome[data-tag="${r}"]`,`.docx-content-control-chrome[data-tag^="${r}?"]`]};function Gt(e){let{onNodeClick:r,onNodeHover:l}=e,s=useDocxEditor(),t=ce(e.nodes);return useEffect(()=>{let o=document.createElement("style"),i=[];for(let n of t){let d=Qt(n);if(d.length===0)continue;let c=n.chrome?.color!==void 0&&CSS.supports("color",n.chrome.color)?n.chrome.color:"#2563eb";i.push(`${d.map(v=>`${v} ${He}`).join(", ")} {`," pointer-events: auto !important;"," opacity: 1;"," border: none;",` background: color-mix(in srgb, ${c} 12%, transparent);`," border-radius: 6px;"," cursor: default;","}");}return o.textContent=i.join(`
|
|
2
|
+
`),document.head.append(o),()=>o.remove()},[t]),useEffect(()=>{let o=n=>{let d=J(n.target,t);if(!d)return;let c=X(d,s);c&&(d.definition.onClick?.(c),r?.(c));},i=n=>{let d=J(n.target,t);if(!d||n.relatedTarget?.closest?.(He)===n.target.closest(He))return;let v=X(d,s);v&&(d.definition.onHover?.(v),l?.(v));};return document.addEventListener("click",o),document.addEventListener("mouseover",i),()=>{document.removeEventListener("click",o),document.removeEventListener("mouseover",i);}},[t,s,r,l]),null}function mt(e){let{onEditNode:r,remove:l=true}=e,s=ce(e.nodes),t=useContextMenuTarget(),o=useDocxEditor(),{t:i}=useTranslation(),n=useMemo(()=>t?J(t,s):null,[t,s]),d=useMemo(()=>n?X(n,o):null,[n,o]),c=useMemo(()=>!n?.definition.reviewCard||!d?null:n.definition.reviewCard({attrs:d.attrs,text:d.text??""}),[n,d]);if(!n||!d)return null;let{definition:v}=n,b=v.label??v.name,R=v.onEdit!==void 0||r!==void 0,w=l&&d.nodeId!==void 0&&o!==null;return !c&&!R&&!w?null:jsxs(Fragment,{children:[c?jsxs("div",{className:"docx-contextmenu__custom-info","data-testid":"custom-node-info",children:[jsx("span",{className:"docx-contextmenu__custom-title",children:c.title}),c.detail?jsx("span",{className:"docx-contextmenu__custom-detail",children:c.detail}):null]}):null,R?jsx(ContextMenuItem,{label:i("contextMenu.editCustomNode",{label:b}),className:"docx-contextmenu__custom-edit",onSelect:()=>{v.onEdit?.(d),r?.(d,v);}}):null,w?jsx(ContextMenuItem,{label:i("contextMenu.removeCustomNode",{label:b}),className:"docx-contextmenu__custom-remove",onSelect:()=>{j(o,d.nodeId);}}):null,jsx("div",{role:"separator",className:"docx-toolbar__menu-separator"})]})}mt.docxRowPlacement="start";export{Gt as CustomNodeChrome,mt as CustomNodeContextMenu,Zt as DocxEditorReview,X as activatedCustomNodeOf,J as resolveCustomNodeActivation,ce as useCustomNodeDefinitions,me as useReview,Pt as useReviewItem,nt as useReviewOf,ht as useStackedReviewPositions};
|