superdoc 2.4.0-next.2 → 2.4.0-next.21

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (62) hide show
  1. package/dist/chunks/{FindReplaceSurface-Dx0llWqP.cjs → FindReplaceSurface-0p7EtMZh.cjs} +4 -4
  2. package/dist/chunks/{FindReplaceSurface-BEW-1NhM.es.js → FindReplaceSurface-40AnrqWk.es.js} +5 -4
  3. package/dist/chunks/{PasswordPromptSurface-BUUVC2ee.cjs → PasswordPromptSurface-31lYPcCK.cjs} +4 -3
  4. package/dist/chunks/{PasswordPromptSurface-BA6HHqEa.es.js → PasswordPromptSurface-CwYeO3iQ.es.js} +4 -2
  5. package/dist/chunks/{PdfViewer-CNOtyS-I.es.js → PdfViewer-D8h7LRZy.es.js} +103 -19
  6. package/dist/chunks/{PdfViewer-qpvzwYMz.cjs → PdfViewer-Dug6yDRC.cjs} +105 -20
  7. package/dist/chunks/_plugin-vue_export-helper-BOaGB7Aw.es.js +8 -0
  8. package/dist/chunks/_plugin-vue_export-helper-SDR04tiH.cjs +13 -0
  9. package/dist/chunks/{blank-docx-DP8RUPW-.cjs → blank-docx-BuFAbRjs.cjs} +2 -0
  10. package/dist/chunks/{blank-docx-XRX6Ker2.es.js → blank-docx-DzQccOlW.es.js} +2 -0
  11. package/dist/chunks/constants-B6VBlmKp.es.js +4 -0
  12. package/dist/chunks/constants-DpXuDx_g.cjs +9 -0
  13. package/dist/chunks/{create-super-doc-ui-D4kk9AjM.es.js → create-super-doc-ui-CFsY0uxw.es.js} +2177 -581
  14. package/dist/chunks/{create-super-doc-ui-DXdWuTzm.cjs → create-super-doc-ui-jSJQis_0.cjs} +1987 -619
  15. package/dist/chunks/{eventemitter3-DqY4aSMf.cjs → eventemitter3-C_TAnXOl.cjs} +125 -16
  16. package/dist/chunks/{eventemitter3-Bt2s0X0a.es.js → eventemitter3-DEIiXiH2.es.js} +124 -16
  17. package/dist/chunks/jszip-BzJ3CyxR.es.js +4717 -0
  18. package/dist/chunks/jszip-D8mAFF-r.cjs +4758 -0
  19. package/dist/chunks/{rolldown-runtime-D7PMmH3s.es.js → rolldown-runtime-0pSA04fp.es.js} +12 -3
  20. package/dist/chunks/{rolldown-runtime-1Y-nnZJ3.cjs → rolldown-runtime-74VwNCz7.cjs} +11 -2
  21. package/dist/chunks/{uuid-CFp0WGVU.cjs → uuid-BhG0ngwk.cjs} +10 -6
  22. package/dist/chunks/{uuid-B2Sqk-3p.es.js → uuid-H0Xcmmhy.es.js} +8 -3
  23. package/dist/collaboration-upgrade-engine.cjs +34 -9
  24. package/dist/collaboration-upgrade-engine.es.js +30 -5
  25. package/dist/document-api/src/comments/comments.types.d.ts +7 -0
  26. package/dist/document-api/src/types/track-changes.types.d.ts +1 -3
  27. package/dist/layout-engine/contracts/src/incremental-dependency.d.ts +22 -2
  28. package/dist/layout-engine/contracts/src/index.d.ts +1 -1
  29. package/dist/layout-engine/layout-bridge/src/incrementalLayout.d.ts +2 -1
  30. package/dist/layout-engine/layout-bridge/src/index.d.ts +1 -0
  31. package/dist/public/ui-react.cjs +66 -2
  32. package/dist/public/ui-react.es.js +66 -1
  33. package/dist/public/ui.cjs +1 -1
  34. package/dist/public/ui.es.js +1 -1
  35. package/dist/style.css +104 -69
  36. package/dist/style.layered.css +104 -69
  37. package/dist/superdoc/src/core/SuperDoc.d.ts +4 -0
  38. package/dist/superdoc/src/core/types/index.d.ts +505 -42
  39. package/dist/superdoc/src/helpers/comment-small-screen.d.ts +10 -0
  40. package/dist/superdoc/src/helpers/v2-review-mutation-impact.d.ts +1 -0
  41. package/dist/superdoc/src/helpers/v2-review-mutation-reconciler.d.ts +1 -1
  42. package/dist/superdoc/src/helpers/v2-typing-review-hydration.d.ts +16 -0
  43. package/dist/superdoc/src/internal/toolbar/built-in/ToolbarButton.vue.d.ts +4 -4
  44. package/dist/superdoc/src/internal/toolbar/built-in-toolbar.d.ts +11 -0
  45. package/dist/superdoc/src/internal/toolbar/compatibility-catalog.d.ts +1 -1
  46. package/dist/superdoc/src/public/index.d.cts +22 -0
  47. package/dist/superdoc/src/public/index.d.ts +11 -0
  48. package/dist/superdoc/src/public/ui/types.d.ts +25 -1
  49. package/dist/superdoc/src/stores/comments-store.d.ts +100 -22
  50. package/dist/superdoc/src/stores/superdoc-store.d.ts +300 -66
  51. package/dist/superdoc.cjs +6678 -1391
  52. package/dist/superdoc.es.js +6556 -1268
  53. package/dist-cdn/style.layered.css +1 -1
  54. package/dist-cdn/superdoc.min.css +1 -1
  55. package/dist-cdn/superdoc.min.js +37 -37
  56. package/package.json +14 -14
  57. package/dist/chunks/_plugin-vue_export-helper-BTwbGDKw.cjs +0 -11
  58. package/dist/chunks/_plugin-vue_export-helper-CInC0bKI.es.js +0 -6
  59. package/dist/chunks/constants-CY3R3_kF.es.js +0 -3
  60. package/dist/chunks/constants-sbCZ2O_A.cjs +0 -14
  61. package/dist/chunks/jszip-C8srOKAO.es.js +0 -4650
  62. package/dist/chunks/jszip-Cs9JBLlJ.cjs +0 -4691
@@ -25,8 +25,16 @@ export type { BrowserDocumentApi } from '../../public/browser-document-api.js';
25
25
  export interface ToolbarDropdownOption {
26
26
  /** Row text, and the default command argument when the row is chosen. */
27
27
  label?: string;
28
- /** Stable row identity, used for selection state. */
29
- key?: string;
28
+ /**
29
+ * Stable row identity, used for selection state and handed to the command.
30
+ *
31
+ * Numbers included, because the built-in zoom dropdown uses them
32
+ * (`key: 0.5`, `key: 1`) and the runtime passes the value through
33
+ * unchanged. This is what a `command` callback reads as `context.option`,
34
+ * so a string-only declaration here made a numeric key unusable at the far
35
+ * end even once the config side accepted it.
36
+ */
37
+ key?: string | number;
30
38
  /** Attributes spread onto the rendered row. */
31
39
  props?: Record<string, unknown>;
32
40
  [key: string]: unknown;
@@ -56,37 +64,350 @@ export interface ToolbarCustomButtonContext extends CustomCommandContext {
56
64
  argument?: unknown;
57
65
  }
58
66
  /**
59
- * A custom entry appended to the built-in toolbar's default item set.
67
+ * What a custom toolbar entry does when activated.
60
68
  *
61
- * Intentionally loose. `name` and `command` are the two members the runtime
62
- * contract already fixes, and the rest stays open because the public
63
- * toolbar-item shape has not been decided yet (#1098).
64
- *
65
- * Tightening it further needs that contract first. `useToolbarItem` accepting
66
- * a `type` only proves construction does not throw, not that the entry renders
67
- * as a top-level toolbar item -- `options` has no render branch at all,
68
- * `dropdown` needs rows and a trigger, and `overflow` draws only when the
69
- * separately-built overflow list is non-empty, which `customButtons` cannot
70
- * populate. Encoding those rules here would publish a contract on the strength
71
- * of constructor behavior, and they need rendered-behavior tests rather than
72
- * direct `useToolbarItem` construction to establish.
73
- */
74
- export interface ToolbarCustomButton {
75
- /** Unique item name. Also derives the registered command id. */
69
+ * A function is registered as a custom command and invoked with
70
+ * {@link ToolbarCustomButtonContext}; a string is read as a canonical V2
71
+ * command id and routed through the shared controller. An unknown id is
72
+ * accepted at compile time and then reported through the toolbar's
73
+ * `exception` event as "Command not handled" -- so the string form stays
74
+ * unnarrowed, but a typo is diagnosed at runtime rather than ignored.
75
+ */
76
+ export type ToolbarCustomButtonCommand = string | ((context: ToolbarCustomButtonContext) => unknown);
77
+ /** Members every custom toolbar entry carries, whatever its type. */
78
+ interface ToolbarCustomEntryBase {
79
+ /**
80
+ * Unique item name, which also derives the registered command id and the
81
+ * rendered `data-item` attribute.
82
+ *
83
+ * Uniqueness is enforced at construction rather than here: a name that
84
+ * repeats, or that matches a built-in item, used to render a second control
85
+ * under the same `data-item` with neither responding.
86
+ */
76
87
  name: string;
88
+ /** Which toolbar group the entry joins. Defaults to `center`. */
89
+ group?: 'left' | 'center' | 'right' | (string & {});
90
+ /** Hover text. */
91
+ tooltip?: string;
92
+ /** Render the entry as unavailable. Honored: a disabled entry does not run. */
93
+ disabled?: boolean;
94
+ /** Extra DOM hooks. Both are read straight onto the rendered control. */
95
+ attributes?: {
96
+ /**
97
+ * Appended to the item's class list. Any value Vue's `class` binding
98
+ * takes: a string, an array, a condition map, or a nesting of those.
99
+ *
100
+ * AIDEV-NOTE: unconstrained for the same reason as `dropdownStyles`, and
101
+ * verified rather than assumed. This lands inside an array binding --
102
+ * `ToolbarButton` renders `:class="['sd-toolbar-item',
103
+ * attributes.className]"` -- so Vue resolves it, and `string` rejected
104
+ * `['compact', { active: isActive }]`, the ordinary way to write a
105
+ * conditional class. There is also nothing to import or mirror:
106
+ * `@vue/shared` types the input as `normalizeClass(value: unknown)`, so
107
+ * Vue does not name this shape either, and any union written here would
108
+ * be narrower than what Vue accepts. A browser test asserts the array and
109
+ * the condition map both resolve, including that a false branch is
110
+ * dropped rather than stringified.
111
+ */
112
+ className?: unknown;
113
+ /** Sets `aria-label`, which is otherwise absent on a custom entry. */
114
+ ariaLabel?: string;
115
+ };
116
+ /** Render the control at reduced width. */
117
+ isNarrow?: boolean;
118
+ /** Render the control at increased width. */
119
+ isWide?: boolean;
120
+ /**
121
+ * `active` and `activeIcon` are rejected by name because both are dead.
122
+ * `useToolbarItem` hard-codes the initial active state to `false` and
123
+ * discards the option, and nothing in the toolbar reads `activeIcon`. Set
124
+ * the state from the command instead, which does work.
125
+ */
126
+ active?: never;
127
+ activeIcon?: never;
128
+ /**
129
+ * Open on purpose. `useToolbarItem` accepts 37 fields and forwards them, and
130
+ * closing this list around the ones I could enumerate rejected seven working
131
+ * configurations in review -- `label`, `hasCaret`, `dropdownValueKey`, row
132
+ * `icon`, `attributes`, `splitButton`, `argument` -- each of which renders or
133
+ * is forwarded by code the enumeration missed.
134
+ *
135
+ * So the guarantees here are structural rather than exhaustive: which `type`
136
+ * values render at all, that a button and a dropdown each have something
137
+ * visible, that a dropdown has rows, and that the two dead fields above are
138
+ * refused. A misspelled rare field still compiles, which is the same
139
+ * trade-off `CommentsConfig` makes for the same reason -- the runtime passes
140
+ * the whole bag through, so a closed type would be wrong more often than a
141
+ * typo is.
142
+ */
143
+ [key: string]: unknown;
144
+ }
145
+ /**
146
+ * A custom button.
147
+ *
148
+ * `icon` is required, which is stricter than the runtime check and deliberately
149
+ * so. Construction accepts `icon` **or** `defaultLabel`, but only the icon
150
+ * reaches the DOM: a button carrying `defaultLabel` alone builds, mounts, and
151
+ * draws nothing, leaving an empty control in the toolbar. Requiring `icon`
152
+ * keeps this type to shapes that produce something a user can see.
153
+ *
154
+ * `label` is not accepted at all. It is the *live* label a built-in item
155
+ * rewrites as state changes, it does not satisfy the affordance check, and a
156
+ * button carrying only `label` is rejected at construction.
157
+ *
158
+ * AIDEV-NOTE: `defaultLabel` renders nothing for a custom button. The check in
159
+ * `use-toolbar-item.js` treats it as an affordance and `ToolbarButton.vue`
160
+ * never draws it. Widening this type to accept `defaultLabel` alone requires
161
+ * fixing that render first, or it re-admits invisible buttons (#1098).
162
+ */
163
+ export interface ToolbarCustomButtonItem extends ToolbarCustomEntryBase {
164
+ type: 'button';
165
+ /** Inline SVG or markup. The only thing a custom button actually renders. */
166
+ icon: string;
77
167
  /**
78
- * What the entry does when activated. A function is registered as a custom
79
- * command and invoked with {@link ToolbarCustomButtonContext}; a string is
80
- * read as a canonical V2 command id and routed through the shared controller
81
- * (`built-in-toolbar.js:948`).
168
+ * Static label kept for the affordance check and for parity with the legacy
169
+ * spelling. It does not render today; pair it with `icon`, never alone.
170
+ */
171
+ defaultLabel?: string;
172
+ /**
173
+ * Visible text drawn beside the icon. Unlike `defaultLabel` this really is
174
+ * rendered, but it does not satisfy the affordance check on its own, so it
175
+ * accompanies `icon` rather than replacing it.
176
+ */
177
+ label?: string;
178
+ /**
179
+ * What the button does. Optional because omitting it renders a control that
180
+ * does nothing rather than failing, which is legal today; an entry meant to
181
+ * be actionable should always carry one.
182
+ */
183
+ command?: ToolbarCustomButtonCommand;
184
+ }
185
+ /**
186
+ * One selectable row in a custom dropdown.
187
+ *
188
+ * Both members are required: `key` is what reaches the command through
189
+ * {@link ToolbarCustomButtonContext.option}, and `label` is the only text the
190
+ * row renders, so a row missing either draws blank or selects as `undefined`.
191
+ */
192
+ interface ToolbarCustomDropdownOptionBase {
193
+ /**
194
+ * Drawn beside the row's label, or a function returning it.
82
195
  *
83
- * Optional because a separator has nothing to do. An actionable entry that
84
- * omits it silently no-ops on click -- a real defect, but one this type
85
- * cannot flag without the variant split that #1098 owns.
196
+ * Not string-only: `OptionIcon` returns whatever this resolves to straight
197
+ * from a render function, so a Vue VNode works as well as markup.
198
+ *
199
+ * `object` rather than `Record<string, unknown>`, which was the first
200
+ * attempt and admitted only inferred object literals -- a value already
201
+ * typed as Vue's `VNode` has no string index signature and so failed to
202
+ * assign. `object` accepts both without importing Vue's types into the
203
+ * public surface.
204
+ */
205
+ icon?: string | object | ((option: ToolbarCustomDropdownOption) => unknown);
206
+ /** Render the row as unavailable. */
207
+ disabled?: boolean;
208
+ /** Added to the row's class list. */
209
+ class?: unknown;
210
+ /**
211
+ * Spread onto the rendered row as attributes, and its `class` is merged
212
+ * with the one above. Declared here as well as on `ToolbarDropdownOption`,
213
+ * which it mirrors.
214
+ */
215
+ props?: Record<string, unknown>;
216
+ /**
217
+ * Open, like the `ToolbarDropdownOption` it mirrors, because
218
+ * `dropdownValueKey` names a member to read dynamically: a row can carry
219
+ * `{ label, key, value }` and send `value` to the command. Closing this
220
+ * would make that shape uncompilable while it still works.
86
221
  */
87
- command?: string | ((context: ToolbarCustomButtonContext) => unknown);
88
222
  [key: string]: unknown;
89
223
  }
224
+ /**
225
+ * One row in a custom dropdown.
226
+ *
227
+ * A selectable row needs both `label` and `key`: `label` is the only text it
228
+ * renders, and `key` is what reaches the command through
229
+ * {@link ToolbarCustomButtonContext.option}.
230
+ *
231
+ * A `type: 'render'` row is the exception and is why this is a union rather
232
+ * than one interface. `ToolbarDropdown` routes those to its `RenderOption`
233
+ * branch and never reads `label` for them, so requiring it would reject rows
234
+ * the runtime supports -- which the first version of this type did.
235
+ */
236
+ export type ToolbarCustomDropdownOption = (ToolbarCustomDropdownOptionBase & {
237
+ /**
238
+ * Application metadata. A row carrying `{ type: 'action', label, key }`
239
+ * stays selectable and reaches the command verbatim, so this member is
240
+ * open.
241
+ *
242
+ * AIDEV-NOTE: that openness means `{ type: 'render', label, key }` with
243
+ * no renderer still matches this branch, so the render branch's
244
+ * required `render` does not catch it (#1098). `Exclude<string,
245
+ * 'render'>` does not help -- subtracting a literal from the wide
246
+ * `string` type leaves `string` -- and neither does a branded
247
+ * intersection, because a plain string literal remains assignable to
248
+ * both. Closing this needs a literal union of the metadata values the
249
+ * product supports, which is a contract decision rather than a
250
+ * transcription. The runtime treats such a row as render-only and draws
251
+ * a blank, inert row.
252
+ */
253
+ type?: string;
254
+ /** Text rendered for the row. */
255
+ label: string;
256
+ /**
257
+ * Value handed to the command when this row is chosen, and the row's
258
+ * Vue key. Numbers are allowed because the built-in zoom dropdown uses
259
+ * them (`key: 0.5`, `key: 1`), and `ButtonGroup` passes the value
260
+ * through to `selectedValue` unchanged.
261
+ */
262
+ key: string | number;
263
+ }) | (ToolbarCustomDropdownOptionBase & {
264
+ /** Rendered through `RenderOption` rather than as a selectable row. */
265
+ type: 'render';
266
+ /**
267
+ * Required, because `RenderOption` returns `null` unless this is
268
+ * callable. A render row is also excluded from selection, so one
269
+ * without a renderer is a permanently blank row that cannot be clicked.
270
+ */
271
+ render: () => unknown;
272
+ label?: string;
273
+ key?: string | number;
274
+ });
275
+ /**
276
+ * A custom dropdown.
277
+ *
278
+ * `options` is required and must be non-empty: a dropdown with no rows, or an
279
+ * empty array, renders no trigger at all, so the entry silently disappears
280
+ * rather than drawing something inert.
281
+ *
282
+ * The trigger rule is looser than a button's -- `label` works here as well as
283
+ * `icon` -- because the dropdown draws its own trigger rather than going
284
+ * through the button affordance check.
285
+ */
286
+ interface ToolbarCustomDropdownBase extends ToolbarCustomEntryBase {
287
+ type: 'dropdown';
288
+ /**
289
+ * Static fallback trigger text. Present for parity with the legacy spelling
290
+ * and does not render, which is why it does not satisfy the trigger
291
+ * requirement below.
292
+ */
293
+ defaultLabel?: string;
294
+ /**
295
+ * The rows the dropdown offers. Empty is accepted, and is not a mistake on
296
+ * its own: `#updateHighlightColors` assigns `nestedOptions` after the item
297
+ * is built, so a dropdown can construct empty and fill in later. An empty
298
+ * one renders no menu rather than breaking -- `ButtonGroup` guards the
299
+ * branch on `nestedOptions.value.length`.
300
+ *
301
+ * AIDEV-NOTE: this was a nonempty tuple until #1188 review. The tuple did
302
+ * reject `options: []`, and it also rejected every array TypeScript cannot
303
+ * see the length of -- `rows.map(...)`, a `Row[]` variable, a function
304
+ * return. Those are how dropdown rows are normally built; `lineHeight` in
305
+ * `default-items.js` builds its own rows with `.map()`. The obvious escape,
306
+ * `readonly T[] & { 0: T }`, rejects all four (measured, not assumed): an
307
+ * array type carries no index-0 property for the intersection to satisfy.
308
+ * So please do not reintroduce a tuple here -- and note there is no runtime
309
+ * check to fall back on either, deliberately, because an empty dropdown is
310
+ * a legitimate intermediate state.
311
+ *
312
+ * `readonly` so an `as const` array is accepted: the runtime only iterates
313
+ * this and copies the elements into `nestedOptions`, never mutating the
314
+ * consumer's array.
315
+ */
316
+ options: readonly ToolbarCustomDropdownOption[];
317
+ /** Draw the dropdown caret beside the trigger. Rendered by `ToolbarButton`. */
318
+ hasCaret?: boolean;
319
+ /**
320
+ * Which member of the selected row becomes the command's `argument`.
321
+ *
322
+ * Defaults to `label`, not `key`: `ButtonGroup.handleSelect` reads
323
+ * `option[dropdownValueKey]` and falls back to `option.label` when this is
324
+ * unset. So a dropdown whose display text differs from its value has to set
325
+ * `'key'` explicitly, or the command receives the text a user sees rather
326
+ * than the value it stands for. Any member name works, not just `key`: a row
327
+ * carrying `{ label, key, value }` can send `value`. `context.option` always
328
+ * carries the whole row either way.
329
+ */
330
+ dropdownValueKey?: string;
331
+ /**
332
+ * Inline styles for the dropdown's own element -- its trigger and wrapper --
333
+ * forwarded unchanged to Vue's `:style` binding.
334
+ *
335
+ * Not the open panel: `ButtonGroup` styles that separately through
336
+ * `menu-props`, which `customButtons` cannot reach. Widths set here size the
337
+ * control in the toolbar, not the menu it opens.
338
+ *
339
+ * AIDEV-NOTE: deliberately unconstrained. Restating Vue's `StyleValue` here
340
+ * was attempted three times and was wrong each time -- string-valued
341
+ * objects rejected `{ padding: 0 }`, object-only rejected
342
+ * `'min-width: 200px'`, and a hand-written union rejected a value already
343
+ * typed as `CSSProperties`, whose index signature a structural restatement
344
+ * does not match. The shape set is Vue's to define and moves with Vue, so
345
+ * mirroring it by hand keeps rejecting working configuration. Importing
346
+ * `StyleValue` would pull a Vue type into the public surface, which this
347
+ * package avoids elsewhere.
348
+ */
349
+ dropdownStyles?: unknown;
350
+ /**
351
+ * `key` of the row to show as selected before the user picks one. Matches
352
+ * the row `key` type, numbers included.
353
+ */
354
+ selectedValue?: string | number;
355
+ /** Invoked with the chosen row on {@link ToolbarCustomButtonContext.option}. */
356
+ command?: ToolbarCustomButtonCommand;
357
+ }
358
+ /**
359
+ * A dropdown needs a trigger a user can see, and it has three ways to draw
360
+ * one. `ToolbarButton` renders `icon` and `label` in its non-split branch and,
361
+ * beside them, `.sd-dropdown-caret` on `v-if="hasCaret"` alone -- so a compact
362
+ * caret-only dropdown is a real control, not an oversight. It renders with a
363
+ * measurable width and opens its rows; only `defaultLabel` draws nothing.
364
+ *
365
+ * Splitting the variant is what makes at-least-one enforceable rather than
366
+ * advisory. Pair a caret-only trigger with `attributes.ariaLabel`, since
367
+ * there is no text for a screen reader to announce.
368
+ */
369
+ export type ToolbarCustomDropdownItem = (ToolbarCustomDropdownBase & {
370
+ icon: string;
371
+ label?: string;
372
+ hasCaret?: boolean;
373
+ }) | (ToolbarCustomDropdownBase & {
374
+ label: string;
375
+ icon?: string;
376
+ hasCaret?: boolean;
377
+ }) | (ToolbarCustomDropdownBase & {
378
+ hasCaret: true;
379
+ icon?: string;
380
+ label?: string;
381
+ });
382
+ /** A visual divider. Renders on its own and has nothing to run. */
383
+ export interface ToolbarCustomSeparatorItem extends ToolbarCustomEntryBase {
384
+ type: 'separator';
385
+ }
386
+ /**
387
+ * A custom entry appended to the built-in toolbar's default item set.
388
+ *
389
+ * What this guarantees is structural, not exhaustive. Each variant fixes the
390
+ * shape of the entry -- which `type` values render at all, that a button and a
391
+ * dropdown each carry something visible, that a dropdown has rows -- while the
392
+ * field list itself stays open, because `useToolbarItem` accepts 37 fields and
393
+ * forwards them. Closing that list rejected eight working configurations
394
+ * during review, and a rejected working config is a worse failure than the
395
+ * autocomplete it buys.
396
+ *
397
+ * Two of the five `useToolbarItem` types are absent because they render
398
+ * nothing: `options` constructs without throwing and `ButtonGroup` has no
399
+ * branch for it, and `overflow` draws only from the separately-built overflow
400
+ * list, which `customButtons` cannot populate.
401
+ *
402
+ * Two fields are refused by name on {@link ToolbarCustomEntryBase} for the
403
+ * same reason: `active` is discarded (`useToolbarItem` hard-codes the initial
404
+ * state to `false`) and `activeIcon` has no toolbar reader at all.
405
+ *
406
+ * Derived from a rendered-behavior survey rather than from the constructor
407
+ * (#1098): construction succeeding proves only that nothing threw, which for
408
+ * this surface was never the same question as whether a control appeared.
409
+ */
410
+ export type ToolbarCustomButton = ToolbarCustomButtonItem | ToolbarCustomDropdownItem | ToolbarCustomSeparatorItem;
90
411
  export type V2AuthoringSelectionCollapse = 'start' | 'end' | null;
91
412
  export type V2AuthoringResult = {
92
413
  ok: true;
@@ -843,6 +1164,111 @@ export type LinkPopoverResolution = {
843
1164
  * default popover.
844
1165
  */
845
1166
  export type LinkPopoverResolver = (ctx: LinkPopoverContext) => LinkPopoverResolution | null | undefined;
1167
+ /**
1168
+ * Canonical presentation settings for the built-in comments UI.
1169
+ *
1170
+ * Presentation only, and deliberately not the whole of `modules.comments`.
1171
+ * That block also carries `readOnly` and `allowResolve`, which resolve through
1172
+ * `interaction.comments`, and `permissionResolver`, which is read off
1173
+ * `modules.comments` or the top-level `Config`. All three are stripped from
1174
+ * this bag: policy outlives the built-in UI, so an application drawing its own
1175
+ * comment surface still has to honor it. See the fields themselves, which are
1176
+ * rejected by name with the spelling that applies to each.
1177
+ *
1178
+ * Open on purpose, for the same reason `modules.comments` is: the runtime
1179
+ * merges this bag over that block and spreads the result through the comments
1180
+ * store, which accepts pass-through keys. Closing it would reject working
1181
+ * configurations, which is a worse failure than the missing autocomplete it
1182
+ * would buy. The named fields are the ones the shell reads.
1183
+ */
1184
+ export type CommentsConfig = {
1185
+ /** How comments present themselves as the surface narrows. */
1186
+ displayMode?: 'auto' | 'sidebar' | 'inline';
1187
+ /** CSS selector for an explicit width measurement target in `auto` mode. */
1188
+ compactMeasurementSelector?: string;
1189
+ /** Fixed compact-mode breakpoint override, in pixels. */
1190
+ compactBreakpointPx?: number;
1191
+ /** Comment highlight colors (internal/external and active overrides). */
1192
+ highlightColors?: {
1193
+ /** Base highlight color for internal comments. */
1194
+ internal?: string;
1195
+ /** Base highlight color for external comments. */
1196
+ external?: string;
1197
+ /** Active highlight color override for internal comments. */
1198
+ activeInternal?: string;
1199
+ /** Active highlight color override for external comments. */
1200
+ activeExternal?: string;
1201
+ };
1202
+ /** Comment highlight opacity, active and inactive. */
1203
+ highlightOpacity?: {
1204
+ /** Opacity for the active comment highlight. */
1205
+ active?: number;
1206
+ /** Opacity for inactive comment highlights. */
1207
+ inactive?: number;
1208
+ };
1209
+ /** Highlight color used while hovering a comment. */
1210
+ highlightHoverColor?: string;
1211
+ /** Tracked-change highlight colors. */
1212
+ trackChangeHighlightColors?: TrackChangeHighlightColors;
1213
+ /** Active tracked-change highlight colors (defaults to the above). */
1214
+ trackChangeActiveHighlightColors?: TrackChangeHighlightColors;
1215
+ /**
1216
+ * Policy, not presentation. `normalizeUiConfig` strips all three from this
1217
+ * bag before anything reads it, so accepting them here would advertise a
1218
+ * setting that is silently discarded.
1219
+ *
1220
+ * `readOnly` and `allowResolve` belong on `interaction.comments`, where they
1221
+ * resolve and keep applying to an application drawing its own comment
1222
+ * surface.
1223
+ *
1224
+ * `permissionResolver` is collaboration wiring rather than policy, and has
1225
+ * no `ui` spelling at all. `pickResolver` takes the first of
1226
+ * `modules.comments.permissionResolver` and the top-level
1227
+ * `Config.permissionResolver`, in that order, so either works and the
1228
+ * comments-scoped one wins.
1229
+ */
1230
+ readOnly?: never;
1231
+ allowResolve?: never;
1232
+ permissionResolver?: never;
1233
+ } & Record<string, unknown>;
1234
+ /** Border and background colors for one tracked-change highlight state. */
1235
+ export interface TrackChangeHighlightColors {
1236
+ /** Border color for inserted text. */
1237
+ insertBorder?: string;
1238
+ /** Background color for inserted text. */
1239
+ insertBackground?: string;
1240
+ /** Border color for deleted text. */
1241
+ deleteBorder?: string;
1242
+ /** Background color for deleted text. */
1243
+ deleteBackground?: string;
1244
+ /** Border color for a format change. */
1245
+ formatBorder?: string;
1246
+ }
1247
+ /**
1248
+ * Canonical configuration for the chrome drawn around content controls.
1249
+ *
1250
+ * `chrome` is the whole option bag this surface has. `'default'` and `'none'`
1251
+ * are the only values the painter and the v2 host accept; anything else is
1252
+ * coerced back to `'default'`.
1253
+ */
1254
+ export interface ContentControlsConfig {
1255
+ /** Whether SuperDoc draws its own chrome around each content control. */
1256
+ chrome?: 'default' | 'none';
1257
+ }
1258
+ /**
1259
+ * Canonical configuration for the built-in link popover.
1260
+ *
1261
+ * `popoverResolver` supersedes `modules.links.popoverResolver`, which stays
1262
+ * supported for all of v2. Setting both keeps the canonical one; the legacy
1263
+ * spelling only applies when the canonical one is absent.
1264
+ */
1265
+ export interface LinkPopoverConfig {
1266
+ /**
1267
+ * Called when a user clicks a link, to decide which popover to show.
1268
+ * Returning `null` or `undefined` falls back to the built-in popover.
1269
+ */
1270
+ popoverResolver?: LinkPopoverResolver;
1271
+ }
846
1272
  /** Context object passed to context menu callbacks (showWhen, render, action, menuProvider). */
847
1273
  export interface ContextMenuContext {
848
1274
  /** The editor instance. */
@@ -1650,6 +2076,17 @@ export interface FindReplaceConfig {
1650
2076
  width?: number | string;
1651
2077
  maxWidth?: number | string;
1652
2078
  maxHeight?: number | string;
2079
+ /**
2080
+ * Focus the find input when the surface opens. Defaults to `true`; set
2081
+ * `false` to leave focus wherever the user had it.
2082
+ *
2083
+ * Honored but undeclared until #1094: `useFindReplace` spreads this whole
2084
+ * bag into the surface request, and `SurfaceManager` applies it last, over
2085
+ * the `modules.surfaces.floating` defaults.
2086
+ */
2087
+ autoFocus?: boolean;
2088
+ /** Close the surface on a pointer press outside it. Defaults to `false`. */
2089
+ closeOnOutsidePointerDown?: boolean;
1653
2090
  };
1654
2091
  }
1655
2092
  /**
@@ -2439,18 +2876,36 @@ export interface SuperDocExceptionEditorPayload {
2439
2876
  code?: string;
2440
2877
  documentId?: string | null;
2441
2878
  }
2879
+ /**
2880
+ * Exception payload raised by the built-in toolbar.
2881
+ *
2882
+ * Emitted for a command that failed and for a custom entry the toolbar could
2883
+ * not build, in which case `itemName` is the entry that was skipped and the
2884
+ * message names the field that would fix it. Reaches the host as well as the
2885
+ * toolbar, because entries are built inside the toolbar constructor and
2886
+ * nothing can have subscribed to the toolbar yet.
2887
+ */
2888
+ export interface SuperDocExceptionToolbarPayload {
2889
+ error: Error;
2890
+ /** The value originally thrown, before it was normalized to an `Error`. */
2891
+ originalError: unknown;
2892
+ /** The toolbar item involved, or `null` when the entry had no usable name. */
2893
+ itemName: string | null;
2894
+ editor?: Editor | null;
2895
+ }
2442
2896
  /**
2443
2897
  * Union of all `exception` event payloads SuperDoc emits at runtime.
2444
- * Consumers can narrow with `'stage' in payload` (store init) or
2445
- * `'code' in payload` (editor lifecycle).
2898
+ * Consumers can narrow with `'stage' in payload` (store init),
2899
+ * `'code' in payload` (editor lifecycle), or `'itemName' in payload`
2900
+ * (built-in toolbar).
2446
2901
  *
2447
- * The union exists today because three independent emit sites
2448
- * (`initializeDocuments`, the restore path, and the editor lifecycle)
2449
- * pre-date a shared error contract. Normalizing them to a single
2450
- * payload shape is a separate follow-up; consumers can narrow with
2902
+ * The union exists today because four independent emit sites
2903
+ * (`initializeDocuments`, the restore path, the editor lifecycle, and the
2904
+ * built-in toolbar) pre-date a shared error contract. Normalizing them to a
2905
+ * single payload shape is a separate follow-up; consumers can narrow with
2451
2906
  * the `in` checks above in the meantime.
2452
2907
  */
2453
- export type SuperDocExceptionPayload = SuperDocExceptionStorePayload | SuperDocExceptionRestorePayload | SuperDocExceptionEditorPayload;
2908
+ export type SuperDocExceptionPayload = SuperDocExceptionStorePayload | SuperDocExceptionRestorePayload | SuperDocExceptionEditorPayload | SuperDocExceptionToolbarPayload;
2454
2909
  /**
2455
2910
  * Zoom mode. `manual` holds whatever value was last set; `fit-width`
2456
2911
  * continuously recomputes the zoom that fits the page width into the
@@ -2638,12 +3093,16 @@ export interface UIConfig {
2638
3093
  */
2639
3094
  fonts?: ToolbarFontOption[];
2640
3095
  /**
2641
- * Custom toolbar buttons appended to the default item set.
3096
+ * Custom toolbar entries appended to the default item set. See
3097
+ * `ToolbarCustomButton` for which shapes render.
2642
3098
  *
2643
- * `name` and the `command` callback are typed; the rest of the
2644
- * `ToolbarItem` shape stays open because it is not yet public (#1098).
3099
+ * `readonly` so an `as const` array is accepted. Without it the array
3100
+ * built in a separate variable had no way through: widening turns each
3101
+ * `type` into `string`, `as const` is the documented answer to that,
3102
+ * and a mutable field then rejected the result. The toolbar only reads
3103
+ * this.
2645
3104
  */
2646
- customButtons?: ToolbarCustomButton[];
3105
+ customButtons?: readonly ToolbarCustomButton[];
2647
3106
  /**
2648
3107
  * Show the formatting marks (pilcrow) button in the toolbar. Off by
2649
3108
  * default. Distinct from `layoutEngineOptions.showFormattingMarks`, which
@@ -2654,7 +3113,7 @@ export interface UIConfig {
2654
3113
  showTableOfContentsButton?: boolean;
2655
3114
  };
2656
3115
  /** Built-in comments UI. Enabled by default. */
2657
- comments?: boolean | Record<string, unknown>;
3116
+ comments?: boolean | CommentsConfig;
2658
3117
  /** Built-in right-click and slash context menu. Enabled by default. */
2659
3118
  contextMenu?: boolean | ContextMenuConfig;
2660
3119
  /**
@@ -2662,16 +3121,20 @@ export interface UIConfig {
2662
3121
  * SuperDoc intercept Cmd+F / Ctrl+F; `editor.ui.search` stays available to
2663
3122
  * custom UI either way.
2664
3123
  */
2665
- search?: boolean | Record<string, unknown>;
2666
- /** Built-in popover shown when a link is selected. Disabled by default. */
2667
- linkPopover?: boolean | Record<string, unknown>;
3124
+ search?: boolean | FindReplaceConfig;
3125
+ /**
3126
+ * Built-in popover shown when a link is clicked. It renders by default;
3127
+ * pass `false` (or `ui: false`) to suppress it. Supplying a
3128
+ * {@link LinkPopoverConfig.popoverResolver} replaces it with your own UI.
3129
+ */
3130
+ linkPopover?: boolean | LinkPopoverConfig;
2668
3131
  /** Built-in ruler. Disabled by default. */
2669
3132
  ruler?: boolean | {
2670
3133
  /** Element or selector to render the ruler into. */
2671
3134
  container?: string | HTMLElement;
2672
3135
  };
2673
3136
  /** Built-in chrome drawn around content controls. Enabled by default. */
2674
- contentControls?: boolean | Record<string, unknown>;
3137
+ contentControls?: boolean | ContentControlsConfig;
2675
3138
  }
2676
3139
  /**
2677
3140
  * What the user is permitted to do, as distinct from what SuperDoc draws.
@@ -1,3 +1,13 @@
1
+ /**
2
+ * Whether a context-menu event landed inside the tracked-change carrier that
3
+ * is already visually active. The review visual owner maintains this marker,
4
+ * so the right-click path can stay synchronous and avoid a catalog lookup or
5
+ * document-wide DOM query.
6
+ *
7
+ * @param {EventTarget | null} target
8
+ * @returns {boolean}
9
+ */
10
+ export function isActiveTrackedChangeContextMenuTarget(target: EventTarget | null): boolean;
1
11
  /**
2
12
  * Normalize adaptive comments UI policy fields.
3
13
  *
@@ -9,6 +9,7 @@
9
9
  * one authoritative catalog after render instead of issuing one read per id.
10
10
  */
11
11
  export function getV2TrackedChangeMutationImpact(event: any): {
12
+ allResolved?: any;
12
13
  upsertIds: Set<any>;
13
14
  removedIds: Set<any>;
14
15
  remappedPairs: {
@@ -12,7 +12,7 @@ export function createV2ReviewMutationReconciler({ getContext, reconcile, hydrat
12
12
  onReconciled: any;
13
13
  }): {
14
14
  enqueue: (impact: any) => void;
15
- enqueueAfterPaint(impact: any, waitForPaint: any): void;
15
+ enqueueAfterPaint(impact: any, waitForPaint: any): Promise<any>;
16
16
  onRender: (supersedesInFlight?: boolean) => void;
17
17
  reset(): void;
18
18
  getPendingIds(): Set<any>;