superdoc 2.4.0-next.12 → 2.4.0-next.13
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/dist/chunks/{create-super-doc-ui-D0mNmAHJ.es.js → create-super-doc-ui-BRBwfV-s.es.js} +43 -55
- package/dist/chunks/{create-super-doc-ui-BWYOinLD.cjs → create-super-doc-ui-CTe12b19.cjs} +43 -55
- package/dist/collaboration-upgrade-engine.cjs +1 -1
- package/dist/collaboration-upgrade-engine.es.js +1 -1
- package/dist/public/ui-react.cjs +1 -1
- package/dist/public/ui-react.es.js +1 -1
- package/dist/public/ui.cjs +1 -1
- package/dist/public/ui.es.js +1 -1
- package/dist/style.css +23 -23
- package/dist/style.layered.css +23 -23
- package/dist/superdoc/src/core/SuperDoc.d.ts +4 -0
- package/dist/superdoc/src/core/types/index.d.ts +380 -37
- package/dist/superdoc/src/helpers/v2-typing-review-hydration.d.ts +16 -0
- package/dist/superdoc/src/internal/toolbar/built-in/ToolbarButton.vue.d.ts +4 -4
- package/dist/superdoc/src/internal/toolbar/built-in-toolbar.d.ts +11 -0
- package/dist/superdoc/src/public/index.d.cts +14 -0
- package/dist/superdoc/src/public/index.d.ts +7 -0
- package/dist/superdoc.cjs +157 -103
- package/dist/superdoc.es.js +157 -103
- package/dist-cdn/style.layered.css +1 -1
- package/dist-cdn/superdoc.min.css +1 -1
- package/dist-cdn/superdoc.min.js +35 -35
- package/package.json +2 -2
package/dist/style.layered.css
CHANGED
|
@@ -1769,11 +1769,11 @@ img[data-v-c95b2073] {
|
|
|
1769
1769
|
pointer-events: auto;
|
|
1770
1770
|
}
|
|
1771
1771
|
|
|
1772
|
-
.superdoc[data-v-
|
|
1772
|
+
.superdoc[data-v-25570fd2] {
|
|
1773
1773
|
display: flex;
|
|
1774
1774
|
position: relative;
|
|
1775
1775
|
}
|
|
1776
|
-
.sd-visually-hidden[data-v-
|
|
1776
|
+
.sd-visually-hidden[data-v-25570fd2] {
|
|
1777
1777
|
position: absolute;
|
|
1778
1778
|
width: 1px;
|
|
1779
1779
|
height: 1px;
|
|
@@ -1784,30 +1784,30 @@ img[data-v-c95b2073] {
|
|
|
1784
1784
|
white-space: nowrap;
|
|
1785
1785
|
border: 0;
|
|
1786
1786
|
}
|
|
1787
|
-
.right-sidebar[data-v-
|
|
1787
|
+
.right-sidebar[data-v-25570fd2] {
|
|
1788
1788
|
min-width: 320px;
|
|
1789
1789
|
height: 100%;
|
|
1790
1790
|
}
|
|
1791
|
-
.floating-comments[data-v-
|
|
1791
|
+
.floating-comments[data-v-25570fd2] {
|
|
1792
1792
|
min-width: 300px;
|
|
1793
1793
|
width: 300px;
|
|
1794
1794
|
height: 100%;
|
|
1795
1795
|
overflow: visible;
|
|
1796
1796
|
}
|
|
1797
|
-
.superdoc__layers[data-v-
|
|
1797
|
+
.superdoc__layers[data-v-25570fd2] {
|
|
1798
1798
|
height: 100%;
|
|
1799
1799
|
position: relative;
|
|
1800
1800
|
box-sizing: border-box;
|
|
1801
1801
|
}
|
|
1802
|
-
.superdoc__document[data-v-
|
|
1802
|
+
.superdoc__document[data-v-25570fd2] {
|
|
1803
1803
|
width: 100%;
|
|
1804
1804
|
position: relative;
|
|
1805
1805
|
}
|
|
1806
|
-
.superdoc__sub-document[data-v-
|
|
1806
|
+
.superdoc__sub-document[data-v-25570fd2] {
|
|
1807
1807
|
width: 100%;
|
|
1808
1808
|
position: relative;
|
|
1809
1809
|
}
|
|
1810
|
-
.superdoc__selection-layer[data-v-
|
|
1810
|
+
.superdoc__selection-layer[data-v-25570fd2] {
|
|
1811
1811
|
position: absolute;
|
|
1812
1812
|
min-width: 100%;
|
|
1813
1813
|
min-height: 100%;
|
|
@@ -1818,13 +1818,13 @@ img[data-v-c95b2073] {
|
|
|
1818
1818
|
/* SD-3497: PDF whiteboard overlay sits above the rendered PDF canvas but below
|
|
1819
1819
|
the PDF comment anchors (z-index 6 in PdfCommentsLayer) so anchors stay
|
|
1820
1820
|
clickable, and below the selection layer (z-index 10). */
|
|
1821
|
-
.superdoc__whiteboard-layer[data-v-
|
|
1821
|
+
.superdoc__whiteboard-layer[data-v-25570fd2] {
|
|
1822
1822
|
z-index: 4;
|
|
1823
1823
|
}
|
|
1824
|
-
.superdoc__temp-selection[data-v-
|
|
1824
|
+
.superdoc__temp-selection[data-v-25570fd2] {
|
|
1825
1825
|
position: absolute;
|
|
1826
1826
|
}
|
|
1827
|
-
.superdoc__right-sidebar[data-v-
|
|
1827
|
+
.superdoc__right-sidebar[data-v-25570fd2] {
|
|
1828
1828
|
width: 320px;
|
|
1829
1829
|
min-width: 320px;
|
|
1830
1830
|
padding: 0 10px;
|
|
@@ -1832,7 +1832,7 @@ img[data-v-c95b2073] {
|
|
|
1832
1832
|
position: relative;
|
|
1833
1833
|
z-index: 2;
|
|
1834
1834
|
}
|
|
1835
|
-
.superdoc__compact-comment-popover[data-v-
|
|
1835
|
+
.superdoc__compact-comment-popover[data-v-25570fd2] {
|
|
1836
1836
|
position: absolute;
|
|
1837
1837
|
top: 12px;
|
|
1838
1838
|
right: 12px;
|
|
@@ -1841,14 +1841,14 @@ img[data-v-c95b2073] {
|
|
|
1841
1841
|
}
|
|
1842
1842
|
|
|
1843
1843
|
/* Tools styles */
|
|
1844
|
-
.tools[data-v-
|
|
1844
|
+
.tools[data-v-25570fd2] {
|
|
1845
1845
|
position: absolute;
|
|
1846
1846
|
z-index: 3;
|
|
1847
1847
|
display: flex;
|
|
1848
1848
|
flex-direction: column;
|
|
1849
1849
|
gap: var(--sd-ui-tools-gap, 6px);
|
|
1850
1850
|
}
|
|
1851
|
-
.tools-item[data-v-
|
|
1851
|
+
.tools-item[data-v-25570fd2] {
|
|
1852
1852
|
display: flex;
|
|
1853
1853
|
align-items: center;
|
|
1854
1854
|
justify-content: center;
|
|
@@ -1859,10 +1859,10 @@ img[data-v-c95b2073] {
|
|
|
1859
1859
|
cursor: pointer;
|
|
1860
1860
|
position: relative;
|
|
1861
1861
|
}
|
|
1862
|
-
.tools-item i[data-v-
|
|
1862
|
+
.tools-item i[data-v-25570fd2] {
|
|
1863
1863
|
cursor: pointer;
|
|
1864
1864
|
}
|
|
1865
|
-
.superdoc__tools-icon[data-v-
|
|
1865
|
+
.superdoc__tools-icon[data-v-25570fd2] {
|
|
1866
1866
|
width: var(--sd-ui-tools-icon-size, 20px);
|
|
1867
1867
|
height: var(--sd-ui-tools-icon-size, 20px);
|
|
1868
1868
|
flex-shrink: 0;
|
|
@@ -1877,22 +1877,22 @@ img[data-v-c95b2073] {
|
|
|
1877
1877
|
|
|
1878
1878
|
/* 834px is iPad screen size in portrait orientation */
|
|
1879
1879
|
@media (max-width: 834px) {
|
|
1880
|
-
.superdoc .superdoc__layers[data-v-
|
|
1880
|
+
.superdoc .superdoc__layers[data-v-25570fd2] {
|
|
1881
1881
|
margin: 0;
|
|
1882
1882
|
border: 0 !important;
|
|
1883
1883
|
box-shadow: none;
|
|
1884
1884
|
}
|
|
1885
|
-
.superdoc__sub-document[data-v-
|
|
1885
|
+
.superdoc__sub-document[data-v-25570fd2] {
|
|
1886
1886
|
max-width: 100%;
|
|
1887
1887
|
}
|
|
1888
|
-
.superdoc__right-sidebar[data-v-
|
|
1888
|
+
.superdoc__right-sidebar[data-v-25570fd2] {
|
|
1889
1889
|
padding: 10px;
|
|
1890
1890
|
position: relative;
|
|
1891
1891
|
}
|
|
1892
1892
|
}
|
|
1893
1893
|
|
|
1894
1894
|
/* AI Writer styles */
|
|
1895
|
-
.ai-writer-container[data-v-
|
|
1895
|
+
.ai-writer-container[data-v-25570fd2] {
|
|
1896
1896
|
position: fixed;
|
|
1897
1897
|
z-index: 1000;
|
|
1898
1898
|
background: white;
|
|
@@ -1908,10 +1908,10 @@ img[data-v-c95b2073] {
|
|
|
1908
1908
|
transform: translateY(-50%);
|
|
1909
1909
|
z-index: 50;
|
|
1910
1910
|
} */
|
|
1911
|
-
.ai-tool > svg[data-v-
|
|
1911
|
+
.ai-tool > svg[data-v-25570fd2] {
|
|
1912
1912
|
fill: transparent;
|
|
1913
1913
|
}
|
|
1914
|
-
.ai-tool[data-v-
|
|
1914
|
+
.ai-tool[data-v-25570fd2]::before {
|
|
1915
1915
|
content: '';
|
|
1916
1916
|
position: absolute;
|
|
1917
1917
|
width: 20px;
|
|
@@ -1932,7 +1932,7 @@ img[data-v-c95b2073] {
|
|
|
1932
1932
|
filter: brightness(1.2);
|
|
1933
1933
|
transition: filter 0.2s ease;
|
|
1934
1934
|
}
|
|
1935
|
-
.ai-tool[data-v-
|
|
1935
|
+
.ai-tool[data-v-25570fd2]:hover::before {
|
|
1936
1936
|
filter: brightness(1.3);
|
|
1937
1937
|
}
|
|
1938
1938
|
|
|
@@ -30,6 +30,9 @@ interface SuperDocFormattingMarksPayload {
|
|
|
30
30
|
interface SuperDocDocumentModeChangePayload {
|
|
31
31
|
documentMode: DocumentMode;
|
|
32
32
|
}
|
|
33
|
+
interface SuperDocCommentsListChangePayload {
|
|
34
|
+
isRendered: boolean;
|
|
35
|
+
}
|
|
33
36
|
interface SuperDocPaginationPayload {
|
|
34
37
|
totalPages: number;
|
|
35
38
|
superdoc: SuperDoc;
|
|
@@ -51,6 +54,7 @@ interface SuperDocEventMap {
|
|
|
51
54
|
editorDestroy: [];
|
|
52
55
|
'pdf:document-ready': [];
|
|
53
56
|
'sidebar-toggle': [boolean];
|
|
57
|
+
'comments-list-change': [SuperDocCommentsListChangePayload];
|
|
54
58
|
/** Requests the shell open its find/replace surface (e.g. the toolbar search button). */
|
|
55
59
|
'search:open': [];
|
|
56
60
|
zoomChange: [SuperDocZoomPayload];
|
|
@@ -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
|
-
/**
|
|
29
|
-
|
|
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
|
-
*
|
|
60
|
-
*
|
|
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).
|
|
67
|
+
* What a custom toolbar entry does when activated.
|
|
64
68
|
*
|
|
65
|
-
*
|
|
66
|
-
*
|
|
67
|
-
*
|
|
68
|
-
*
|
|
69
|
-
*
|
|
70
|
-
*
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
*/
|
|
74
|
-
|
|
75
|
-
/**
|
|
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;
|
|
167
|
+
/**
|
|
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;
|
|
77
178
|
/**
|
|
78
|
-
* What the
|
|
79
|
-
*
|
|
80
|
-
*
|
|
81
|
-
|
|
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.
|
|
195
|
+
*
|
|
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.
|
|
82
198
|
*
|
|
83
|
-
*
|
|
84
|
-
*
|
|
85
|
-
*
|
|
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;
|
|
@@ -2555,18 +2876,36 @@ export interface SuperDocExceptionEditorPayload {
|
|
|
2555
2876
|
code?: string;
|
|
2556
2877
|
documentId?: string | null;
|
|
2557
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
|
+
}
|
|
2558
2896
|
/**
|
|
2559
2897
|
* Union of all `exception` event payloads SuperDoc emits at runtime.
|
|
2560
|
-
* Consumers can narrow with `'stage' in payload` (store init)
|
|
2561
|
-
* `'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).
|
|
2562
2901
|
*
|
|
2563
|
-
* The union exists today because
|
|
2564
|
-
* (`initializeDocuments`, the restore path,
|
|
2565
|
-
* pre-date a shared error contract. Normalizing them to a
|
|
2566
|
-
* 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
|
|
2567
2906
|
* the `in` checks above in the meantime.
|
|
2568
2907
|
*/
|
|
2569
|
-
export type SuperDocExceptionPayload = SuperDocExceptionStorePayload | SuperDocExceptionRestorePayload | SuperDocExceptionEditorPayload;
|
|
2908
|
+
export type SuperDocExceptionPayload = SuperDocExceptionStorePayload | SuperDocExceptionRestorePayload | SuperDocExceptionEditorPayload | SuperDocExceptionToolbarPayload;
|
|
2570
2909
|
/**
|
|
2571
2910
|
* Zoom mode. `manual` holds whatever value was last set; `fit-width`
|
|
2572
2911
|
* continuously recomputes the zoom that fits the page width into the
|
|
@@ -2754,12 +3093,16 @@ export interface UIConfig {
|
|
|
2754
3093
|
*/
|
|
2755
3094
|
fonts?: ToolbarFontOption[];
|
|
2756
3095
|
/**
|
|
2757
|
-
* Custom toolbar
|
|
3096
|
+
* Custom toolbar entries appended to the default item set. See
|
|
3097
|
+
* `ToolbarCustomButton` for which shapes render.
|
|
2758
3098
|
*
|
|
2759
|
-
* `
|
|
2760
|
-
*
|
|
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.
|
|
2761
3104
|
*/
|
|
2762
|
-
customButtons?: ToolbarCustomButton[];
|
|
3105
|
+
customButtons?: readonly ToolbarCustomButton[];
|
|
2763
3106
|
/**
|
|
2764
3107
|
* Show the formatting marks (pilcrow) button in the toolbar. Off by
|
|
2765
3108
|
* default. Distinct from `layoutEngineOptions.showFormattingMarks`, which
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Coalesce automatic review-catalog reconciliation behind a genuine typing
|
|
3
|
+
* quiet period. Every typing signal restarts the trailing timer; there is no
|
|
4
|
+
* maximum-wait escape hatch because that would deliberately run the expensive
|
|
5
|
+
* catalog reads in the middle of a sustained input burst.
|
|
6
|
+
*/
|
|
7
|
+
export function createV2TypingReviewHydrationScheduler({ hydrate, idleMs, setTimer, clearTimer, }: {
|
|
8
|
+
hydrate: any;
|
|
9
|
+
idleMs?: number | undefined;
|
|
10
|
+
setTimer?: ((callback: any, delay: any) => NodeJS.Timeout) | undefined;
|
|
11
|
+
clearTimer?: ((timer: any) => void) | undefined;
|
|
12
|
+
}): {
|
|
13
|
+
schedule: () => void;
|
|
14
|
+
clear: () => void;
|
|
15
|
+
isPending: () => boolean;
|
|
16
|
+
};
|
|
@@ -1,20 +1,20 @@
|
|
|
1
1
|
declare const _default: import('vue').DefineComponent<{}, {
|
|
2
2
|
$emit: (event: "buttonClick" | "textSubmit" | "mainClick", ...args: any[]) => void;
|
|
3
3
|
active: boolean;
|
|
4
|
-
iconColor: string;
|
|
5
4
|
isNarrow: boolean;
|
|
6
5
|
isWide: boolean;
|
|
7
|
-
toolbarItem: Record<string, any>;
|
|
8
6
|
defaultLabel: string;
|
|
7
|
+
iconColor: string;
|
|
8
|
+
toolbarItem: Record<string, any>;
|
|
9
9
|
isOverflowItem: boolean;
|
|
10
10
|
allowEnterPropagation: boolean;
|
|
11
11
|
$props: {
|
|
12
12
|
readonly active?: boolean | undefined;
|
|
13
|
-
readonly iconColor?: string | undefined;
|
|
14
13
|
readonly isNarrow?: boolean | undefined;
|
|
15
14
|
readonly isWide?: boolean | undefined;
|
|
16
|
-
readonly toolbarItem?: Record<string, any> | undefined;
|
|
17
15
|
readonly defaultLabel?: string | undefined;
|
|
16
|
+
readonly iconColor?: string | undefined;
|
|
17
|
+
readonly toolbarItem?: Record<string, any> | undefined;
|
|
18
18
|
readonly isOverflowItem?: boolean | undefined;
|
|
19
19
|
readonly allowEnterPropagation?: boolean | undefined;
|
|
20
20
|
};
|