@gjsify/adwaita-core 0.47.0 → 0.49.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/esm/adjustment.js +1 -0
- package/lib/esm/avatar.js +1 -1
- package/lib/esm/conformance/adjustment.js +1 -0
- package/lib/esm/conformance/avatar.js +1 -1
- package/lib/esm/conformance/index.js +1 -1
- package/lib/esm/conformance/list.js +1 -0
- package/lib/esm/conformance/menu.js +1 -0
- package/lib/esm/conformance/rows.js +1 -1
- package/lib/esm/conformance/shared-trees.js +1 -0
- package/lib/esm/conformance/split-button.js +1 -1
- package/lib/esm/index.js +1 -1
- package/lib/esm/list.js +1 -0
- package/lib/esm/menu.js +2 -0
- package/lib/esm/rows.js +1 -1
- package/lib/esm/split-button.js +1 -1
- package/lib/esm/tab-view.js +1 -1
- package/lib/types/adjustment.d.ts +198 -0
- package/lib/types/adjustment.spec.d.ts +2 -0
- package/lib/types/avatar.d.ts +15 -0
- package/lib/types/conformance/adjustment.d.ts +33 -0
- package/lib/types/conformance/avatar.d.ts +16 -0
- package/lib/types/conformance/index.d.ts +12 -4
- package/lib/types/conformance/list.d.ts +171 -0
- package/lib/types/conformance/menu.d.ts +118 -0
- package/lib/types/conformance/rows.d.ts +3 -3
- package/lib/types/conformance/shared-trees.d.ts +93 -0
- package/lib/types/conformance/split-button.d.ts +9 -19
- package/lib/types/index.d.ts +12 -6
- package/lib/types/list.d.ts +109 -0
- package/lib/types/list.spec.d.ts +2 -0
- package/lib/types/menu.d.ts +366 -0
- package/lib/types/menu.spec.d.ts +2 -0
- package/lib/types/rows.d.ts +78 -109
- package/lib/types/shared-trees.spec.d.ts +2 -0
- package/lib/types/split-button.d.ts +21 -32
- package/lib/types/tab-view.d.ts +35 -2
- package/package.json +3 -3
|
@@ -0,0 +1,366 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The values `hidden-when` is documented to take.
|
|
3
|
+
*
|
|
4
|
+
* A union rather than `string` because each one has its OWN visibility rule in
|
|
5
|
+
* {@link resolveMenuItemState}; an unrecognised value is ignored by C on purpose ("this
|
|
6
|
+
* code may be running in context of a desktop shell … and should not spew criticals"),
|
|
7
|
+
* which {@link normalizeMenuModel} reproduces by dropping it.
|
|
8
|
+
*/
|
|
9
|
+
export type AdwMenuHiddenWhen = 'action-disabled' | 'action-missing' | 'macos-menubar';
|
|
10
|
+
/** A section's `display-hint`, which asks for a row of buttons instead of a list. */
|
|
11
|
+
export type AdwMenuDisplayHint = 'horizontal-buttons' | 'circular-buttons' | 'inline-buttons';
|
|
12
|
+
/** A section's `text-direction`, read only when {@link AdwMenuDisplayHint} is horizontal. */
|
|
13
|
+
export type AdwMenuTextDirection = 'ltr' | 'rtl' | 'none';
|
|
14
|
+
/**
|
|
15
|
+
* One menu item — the attributes `GtkPopoverMenu` documents, plus `id`.
|
|
16
|
+
*
|
|
17
|
+
* `id` is OURS and has no meaning to GTK. It survives the round trip anyway, because a
|
|
18
|
+
* `GMenuModel`'s attribute space is open (`g_menu_item_set_attribute` takes any name and
|
|
19
|
+
* GTK ignores what it does not know), so carrying it is not a divergence — it is an
|
|
20
|
+
* unread attribute, exactly like an application's own. It exists because the two
|
|
21
|
+
* renderers' activation events already reported one, falling back to the label.
|
|
22
|
+
*/
|
|
23
|
+
export interface AdwMenuItem {
|
|
24
|
+
readonly kind: 'item';
|
|
25
|
+
/** The user-visible string. `''` for an item that has none — never `undefined`. */
|
|
26
|
+
readonly label: string;
|
|
27
|
+
/**
|
|
28
|
+
* The DETAILED action name — `app.save-as`, `app.view::list`, `win.zoom(2)`.
|
|
29
|
+
*
|
|
30
|
+
* One string rather than an action plus a target, because that is what
|
|
31
|
+
* `g_menu_item_set_detailed_action` takes and what `g_action_parse_detailed_name`
|
|
32
|
+
* can read back for every `GVariant` target type. {@link parseDetailedAction} splits
|
|
33
|
+
* it where a surface needs the halves.
|
|
34
|
+
*/
|
|
35
|
+
readonly action?: string;
|
|
36
|
+
/** Symbolic icon name shown beside the label. */
|
|
37
|
+
readonly icon?: string;
|
|
38
|
+
/** Icon for the button form a `display-hint` section draws instead of a row. */
|
|
39
|
+
readonly verbIcon?: string;
|
|
40
|
+
/** Accelerator text, e.g. `<Control>s`. Display only — it binds nothing. */
|
|
41
|
+
readonly accel?: string;
|
|
42
|
+
/** When this item disappears rather than merely dimming. */
|
|
43
|
+
readonly hiddenWhen?: AdwMenuHiddenWhen;
|
|
44
|
+
/** Names an application widget the surface must host in place of a row. */
|
|
45
|
+
readonly custom?: string;
|
|
46
|
+
/** Whether {@link label} is Pango markup. */
|
|
47
|
+
readonly useMarkup?: boolean;
|
|
48
|
+
/** Stable identifier for activation reporting; defaults to {@link label}. */
|
|
49
|
+
readonly id?: string;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* A `section` link: items drawn inline, separated from their neighbours.
|
|
53
|
+
*
|
|
54
|
+
* A section is NOT a container the user opens — it is a visual grouping, which is why a
|
|
55
|
+
* flat surface may inline it ({@link flattenMenu}) without losing an item.
|
|
56
|
+
*/
|
|
57
|
+
export interface AdwMenuSection {
|
|
58
|
+
readonly kind: 'section';
|
|
59
|
+
/** Optional heading above the group. */
|
|
60
|
+
readonly label?: string;
|
|
61
|
+
readonly displayHint?: AdwMenuDisplayHint;
|
|
62
|
+
readonly textDirection?: AdwMenuTextDirection;
|
|
63
|
+
readonly items: readonly AdwMenuNode[];
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* A `submenu` link: a nested menu the user opens.
|
|
67
|
+
*
|
|
68
|
+
* `submenuAction` is documented under ITEMS (`gtkpopovermenu.c:106-107`) rather than
|
|
69
|
+
* under submenus, and it is here anyway: it names the action that tracks whether the
|
|
70
|
+
* submenu is OPEN, so the only item it can sit on is the one carrying the link — which
|
|
71
|
+
* in this model IS this node. `gtkmenutrackeritem.c:822` and `:1049` read it, and both
|
|
72
|
+
* paths are submenu paths.
|
|
73
|
+
*/
|
|
74
|
+
export interface AdwMenuSubmenu {
|
|
75
|
+
readonly kind: 'submenu';
|
|
76
|
+
readonly label: string;
|
|
77
|
+
readonly icon?: string;
|
|
78
|
+
/** Action tracking whether this submenu is shown (`submenu-action`). */
|
|
79
|
+
readonly submenuAction?: string;
|
|
80
|
+
/**
|
|
81
|
+
* `gtk-macos-special` — macOS menu-bar meaning, ignored everywhere else
|
|
82
|
+
* (`gtkpopovermenu.c:130-131`, read at `gtkmenutrackeritem.c:761`).
|
|
83
|
+
*
|
|
84
|
+
* Carried and never acted on here: no renderer in this workspace exports a macOS
|
|
85
|
+
* menu bar. It is in the model so that a menu written for one survives the trip,
|
|
86
|
+
* which is the whole lossless claim.
|
|
87
|
+
*/
|
|
88
|
+
readonly macosSpecial?: string;
|
|
89
|
+
readonly items: readonly AdwMenuNode[];
|
|
90
|
+
}
|
|
91
|
+
/** Any node of a normalised model. */
|
|
92
|
+
export type AdwMenuNode = AdwMenuItem | AdwMenuSection | AdwMenuSubmenu;
|
|
93
|
+
/**
|
|
94
|
+
* A normalised menu: the value a renderer walks and the GTK host converts.
|
|
95
|
+
*
|
|
96
|
+
* `readonly` throughout, because every renderer holds one across a render and a shared
|
|
97
|
+
* mutable tree is how two widgets showing the same menu would diverge.
|
|
98
|
+
*/
|
|
99
|
+
export type AdwMenuModel = readonly AdwMenuNode[];
|
|
100
|
+
/** An item as authored — `kind` is implied by the absence of a link. */
|
|
101
|
+
export interface AdwMenuItemInput {
|
|
102
|
+
label?: unknown;
|
|
103
|
+
action?: unknown;
|
|
104
|
+
icon?: unknown;
|
|
105
|
+
verbIcon?: unknown;
|
|
106
|
+
accel?: unknown;
|
|
107
|
+
hiddenWhen?: unknown;
|
|
108
|
+
custom?: unknown;
|
|
109
|
+
useMarkup?: unknown;
|
|
110
|
+
id?: unknown;
|
|
111
|
+
}
|
|
112
|
+
/** A section as authored — the `section` key IS the link. */
|
|
113
|
+
export interface AdwMenuSectionInput {
|
|
114
|
+
section: readonly AdwMenuEntryInput[];
|
|
115
|
+
label?: unknown;
|
|
116
|
+
displayHint?: unknown;
|
|
117
|
+
textDirection?: unknown;
|
|
118
|
+
}
|
|
119
|
+
/** A submenu as authored — the `submenu` key IS the link. */
|
|
120
|
+
export interface AdwMenuSubmenuInput {
|
|
121
|
+
submenu: readonly AdwMenuEntryInput[];
|
|
122
|
+
label?: unknown;
|
|
123
|
+
icon?: unknown;
|
|
124
|
+
submenuAction?: unknown;
|
|
125
|
+
macosSpecial?: unknown;
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* One authored entry.
|
|
129
|
+
*
|
|
130
|
+
* A BARE STRING is a label-only item, and that form is not a NativeScript leftover: it
|
|
131
|
+
* is the model's own shorthand, the same one {@link normalizeComboOptions} gives an
|
|
132
|
+
* option list, and it is now accepted on every surface rather than on one. What it
|
|
133
|
+
* cannot carry — an action, an icon, a section — is exactly what made
|
|
134
|
+
* `button.menu = ['Save as…']` unable to grow, so the shorthand widens INTO this union
|
|
135
|
+
* instead of standing beside it.
|
|
136
|
+
*/
|
|
137
|
+
export type AdwMenuEntryInput = string | AdwMenuItemInput | AdwMenuSectionInput | AdwMenuSubmenuInput;
|
|
138
|
+
/** A menu as authored, before {@link normalizeMenuModel} has seen it. */
|
|
139
|
+
export type AdwMenuInput = readonly AdwMenuEntryInput[];
|
|
140
|
+
/**
|
|
141
|
+
* Authored entries → the normalised model every renderer walks.
|
|
142
|
+
*
|
|
143
|
+
* TOTAL BY CONSTRUCTION. The input reaches this function from author-written markup (a
|
|
144
|
+
* JSON attribute, an XML attribute, a JSX expression), and a typo must not take the
|
|
145
|
+
* widget down with it — the same rule the `menu` attribute parser it replaces already
|
|
146
|
+
* had. So an unusable entry is DROPPED and an unusable attribute is omitted; nothing
|
|
147
|
+
* here throws. The loud half is {@link assertMenuRenderable}, which runs against a
|
|
148
|
+
* SURFACE and can therefore say something true about what will not be drawn.
|
|
149
|
+
*
|
|
150
|
+
* A link wins over the attributes beside it: `{ label: 'More', submenu: [...] }` is a
|
|
151
|
+
* submenu with a label, never an item that happens to carry a list, because that is how
|
|
152
|
+
* `g_menu_item_get_link` reads the same object.
|
|
153
|
+
*/
|
|
154
|
+
export declare function normalizeMenuModel(input: AdwMenuInput | null | undefined): AdwMenuModel;
|
|
155
|
+
/**
|
|
156
|
+
* A `menu` ATTRIBUTE — a JSON array — as a model.
|
|
157
|
+
*
|
|
158
|
+
* Total for the same reason {@link normalizeMenuModel} is, and it adds the one failure
|
|
159
|
+
* markup can produce that a JS value cannot: `JSON.parse` genuinely throws on a typo,
|
|
160
|
+
* and the widget must degrade to "no menu" rather than fail to upgrade.
|
|
161
|
+
*/
|
|
162
|
+
export declare function parseMenuModel(json: string | null | undefined): AdwMenuModel;
|
|
163
|
+
/**
|
|
164
|
+
* Where a node sits: the index chain from the model's root.
|
|
165
|
+
*
|
|
166
|
+
* A `GMenuModel` addresses its items BY POSITION and a link is a model of its own, so a
|
|
167
|
+
* position inside a submenu is only meaningful together with the positions above it.
|
|
168
|
+
* Resolving a choice by LABEL instead silently dispatches the first of two identically
|
|
169
|
+
* named entries — the defect the split button's activation vectors already pin down, one
|
|
170
|
+
* level deeper now that a menu can nest.
|
|
171
|
+
*/
|
|
172
|
+
export type AdwMenuPath = readonly number[];
|
|
173
|
+
/** The node at a path, or `null` when the path names none. */
|
|
174
|
+
export declare function menuNodeAt(model: AdwMenuModel, path: AdwMenuPath): AdwMenuNode | null;
|
|
175
|
+
/** The item at a path — `null` for a path that names a section, a submenu or nothing. */
|
|
176
|
+
export declare function menuItemAt(model: AdwMenuModel, path: AdwMenuPath): AdwMenuItem | null;
|
|
177
|
+
/** One row of a {@link flattenMenu} walk. */
|
|
178
|
+
export interface AdwMenuFlatRow {
|
|
179
|
+
/** The node this row draws. Sections never appear — they become {@link separated}. */
|
|
180
|
+
readonly node: AdwMenuItem | AdwMenuSubmenu;
|
|
181
|
+
/**
|
|
182
|
+
* Where it lives, for {@link menuItemAt}.
|
|
183
|
+
*
|
|
184
|
+
* It is also the depth: `path.length` counts the links walked to reach the row.
|
|
185
|
+
* There is no separate `depth` field, because nothing would indent by it — GTK
|
|
186
|
+
* draws a section flush with its neighbours — and a field only its own vectors read
|
|
187
|
+
* is a claim nothing holds.
|
|
188
|
+
*/
|
|
189
|
+
readonly path: AdwMenuPath;
|
|
190
|
+
/** Whether a separator belongs above this row — a section boundary. */
|
|
191
|
+
readonly separated: boolean;
|
|
192
|
+
}
|
|
193
|
+
/**
|
|
194
|
+
* ONE LEVEL of a model as the ordered rows a list draws.
|
|
195
|
+
*
|
|
196
|
+
* SECTIONS ARE INLINED, SUBMENUS ARE NOT, and that asymmetry is `GMenuModel`'s own: a
|
|
197
|
+
* section is a visual grouping that `GtkPopoverMenu` itself draws inline with a
|
|
198
|
+
* separator, so inlining it loses a rule and no item; a submenu is a menu the user
|
|
199
|
+
* OPENS, so inlining it would put its items where they were never offered. A submenu
|
|
200
|
+
* row therefore stays a row, and a surface shows its contents by flattening THAT node's
|
|
201
|
+
* `items` when the user asks — a second popover page on the web, a second sheet on
|
|
202
|
+
* NativeScript. {@link AdwMenuFlatRow.path} is what makes the second call addressable.
|
|
203
|
+
*
|
|
204
|
+
* `separated` marks the FIRST row after a boundary and is never set on the first row of
|
|
205
|
+
* all, because a separator above nothing is a line at the top of the menu.
|
|
206
|
+
*/
|
|
207
|
+
export declare function flattenMenu(model: AdwMenuModel, path?: AdwMenuPath): readonly AdwMenuFlatRow[];
|
|
208
|
+
/** What a `GActionGroup` publishes about one action, in portable form. */
|
|
209
|
+
export interface AdwMenuAction {
|
|
210
|
+
/** `g_action_group_get_action_enabled`. Absent counts as enabled. */
|
|
211
|
+
readonly enabled?: boolean;
|
|
212
|
+
/**
|
|
213
|
+
* `g_action_group_get_action_state`, as its CONTENT in text: `true`/`false` for a
|
|
214
|
+
* toggle, `list` for a radio whose targets are strings.
|
|
215
|
+
*
|
|
216
|
+
* NOT the `GVariant` TEXT form, which would quote the string —
|
|
217
|
+
* `GLib.Variant.new_string('list').print(false)` is `'list'`, with the quotes. A
|
|
218
|
+
* consumer bridging a real `GActionGroup` writes `state.get_string()[0]` for a
|
|
219
|
+
* string and `String(state.get_boolean())` for a boolean; reading `print(false)`
|
|
220
|
+
* instead is what makes every radio row render OFF, because the target it is
|
|
221
|
+
* compared against ({@link AdwDetailedAction.target}) is unquoted too.
|
|
222
|
+
*/
|
|
223
|
+
readonly state?: string;
|
|
224
|
+
}
|
|
225
|
+
/**
|
|
226
|
+
* The actions a surface knows about — the portable stand-in for a `GActionGroup`.
|
|
227
|
+
*
|
|
228
|
+
* Keyed by the action's own name, prefix included (`app.save-as`), which is the key a
|
|
229
|
+
* detailed action name yields. An action ABSENT from the map is missing, not disabled,
|
|
230
|
+
* and the two differ: `hidden-when="action-missing"` hides one and shows the other.
|
|
231
|
+
*
|
|
232
|
+
* NO MAP AT ALL IS A THIRD THING, and the distinction is load-bearing rather than
|
|
233
|
+
* pedantic: `{}` is a group that knows no actions, so every item in it is insensitive;
|
|
234
|
+
* `undefined` is a surface with no action group to consult, so nothing is known and
|
|
235
|
+
* nothing is dimmed. MEASURED — collapsing the two made every actioned item in the
|
|
236
|
+
* browser renderer arrive `disabled`, because the common case is a menu whose actions
|
|
237
|
+
* the host dispatches itself and never declares.
|
|
238
|
+
*/
|
|
239
|
+
export type AdwMenuActions = Readonly<Record<string, AdwMenuAction>>;
|
|
240
|
+
/** `GtkMenuTrackerItemRole`. */
|
|
241
|
+
export type AdwMenuItemRole = 'normal' | 'check' | 'radio';
|
|
242
|
+
/** What an item's action makes of it. */
|
|
243
|
+
export interface AdwMenuItemState {
|
|
244
|
+
/** `GTK_STATE_FLAG_INSENSITIVE`'s inverse — the action's `enabled`. */
|
|
245
|
+
readonly sensitive: boolean;
|
|
246
|
+
/** Whether the check/radio decoration is drawn. */
|
|
247
|
+
readonly toggled: boolean;
|
|
248
|
+
readonly role: AdwMenuItemRole;
|
|
249
|
+
/** Whether the item is drawn at all — `hidden-when`, folded. */
|
|
250
|
+
readonly visible: boolean;
|
|
251
|
+
}
|
|
252
|
+
/** An action name and the target text beside it. */
|
|
253
|
+
export interface AdwDetailedAction {
|
|
254
|
+
readonly name: string;
|
|
255
|
+
/**
|
|
256
|
+
* The target's CONTENT — `list` for `app.view::list` AND for `app.view('list')`,
|
|
257
|
+
* `2` for `win.zoom(2)`.
|
|
258
|
+
*
|
|
259
|
+
* Never the `GVariant` TEXT, which would quote a string: the two spellings of the
|
|
260
|
+
* same target must compare equal, or a radio written one way and an action state
|
|
261
|
+
* read the other way disagree. MEASURED: without the unquoting,
|
|
262
|
+
* `parseDetailedAction("app.v('list')")` answered `'list'` WITH quotes and every
|
|
263
|
+
* such radio row rendered OFF against a state of `list`.
|
|
264
|
+
*/
|
|
265
|
+
readonly target?: string;
|
|
266
|
+
}
|
|
267
|
+
/**
|
|
268
|
+
* `app.view::list` → `{ name: 'app.view', target: 'list' }`.
|
|
269
|
+
*
|
|
270
|
+
* The two forms `g_action_parse_detailed_name` accepts, and no third: `::` for a string
|
|
271
|
+
* target and `(…)` for a `GVariant` text one. A quoted `(…)` target is UNQUOTED, so
|
|
272
|
+
* `app.v::list` and `app.v('list')` — the same detailed action to GLib — yield the same
|
|
273
|
+
* target here; without that they did not, and every radio written the second way read
|
|
274
|
+
* OFF.
|
|
275
|
+
*
|
|
276
|
+
* WHAT THIS DELIBERATELY DOES NOT DO is parse the `GVariant`. The target is the text
|
|
277
|
+
* between the delimiters with its quotes removed, so comparing it against an action's
|
|
278
|
+
* `state` is a STRING comparison. That is exact for the string and boolean targets a
|
|
279
|
+
* menu actually uses, and it does not canonicalise WHITESPACE: `win.zoom(2)` and
|
|
280
|
+
* `win.zoom( 2 )` name the same action to GLib and different targets here. A portable
|
|
281
|
+
* model with no `GVariant` implementation cannot close that, and pretending otherwise
|
|
282
|
+
* would be a wrong answer instead of a stated one.
|
|
283
|
+
*
|
|
284
|
+
* IT IS ALSO NOT A VALIDATOR. It never throws and answers something for every string,
|
|
285
|
+
* because it runs on the display side of a menu that has already been accepted. GIO is
|
|
286
|
+
* the authority on whether a detailed action name is legal, and `@gjsify/gtk-host`'s
|
|
287
|
+
* `buildGioMenu` asks it — see {@link AdwMenuItem.action}.
|
|
288
|
+
*/
|
|
289
|
+
export declare function parseDetailedAction(detailed: string | undefined): AdwDetailedAction | null;
|
|
290
|
+
/**
|
|
291
|
+
* `sensitive`, `toggled`, `role` and `visible` for one item — `gtk_menu_tracker_item_*`
|
|
292
|
+
* as a pure fold.
|
|
293
|
+
*
|
|
294
|
+
* This is the whole answer to "where does a menu carry enabled and checked", and the
|
|
295
|
+
* answer is that it does not. C reads all three off the ACTION: `sensitive` is the
|
|
296
|
+
* action's `enabled` flag (c:332), `role` is RADIO when the item has a target and the
|
|
297
|
+
* action has a state (c:336-340), CHECK when the state is a boolean and there is no
|
|
298
|
+
* target (c:342-346), and `toggled` compares the two. An item with no `action` attribute
|
|
299
|
+
* at all is SENSITIVE — C sets it explicitly in the else branch
|
|
300
|
+
* (`gtkmenutrackeritem.c:594`) rather than leaving the field false, because a label with
|
|
301
|
+
* no action is not a disabled command.
|
|
302
|
+
*
|
|
303
|
+
* TWO PLACES THIS IS NOT C, both because a portable action map carries no `GVariantType`:
|
|
304
|
+
*
|
|
305
|
+
* · `can_activate`'s TYPE check. C refuses to activate an item whose target type does
|
|
306
|
+
* not match the action's parameter type, and that refusal feeds
|
|
307
|
+
* `hidden-when="action-missing"`. Here "missing" means only that the action is
|
|
308
|
+
* absent from {@link AdwMenuActions} — a present action with a mistyped target reads
|
|
309
|
+
* as activatable where GTK would hide it.
|
|
310
|
+
* · A boolean state is the TEXT `'true'`/`'false'`, since the state is text. A radio
|
|
311
|
+
* whose targets are literally those two strings would therefore read as a check.
|
|
312
|
+
* GTK tells them apart by `GVariant` type; nothing here can.
|
|
313
|
+
*
|
|
314
|
+
* `macos-menubar` hides an item only in the macOS menubar export (C guards it with
|
|
315
|
+
* `mac_os_mode`, c:534-535), which no renderer here is, so it stays visible.
|
|
316
|
+
*/
|
|
317
|
+
export declare function resolveMenuItemState(item: AdwMenuItem, actions?: AdwMenuActions): AdwMenuItemState;
|
|
318
|
+
/**
|
|
319
|
+
* What a surface can draw.
|
|
320
|
+
*
|
|
321
|
+
* ONE CAPABILITY, because one is what actually differs in a way a reader could not
|
|
322
|
+
* otherwise see. All three surfaces nest (GTK slides a page, the browser swaps the
|
|
323
|
+
* popover's page, NativeScript opens a second sheet) and all three draw every
|
|
324
|
+
* attribute they have a place for, so a field for those would be `true` everywhere and
|
|
325
|
+
* a refusal arm nothing could ever reach — the shape this repository pays most for. A
|
|
326
|
+
* second field lands with the first surface that needs it.
|
|
327
|
+
*/
|
|
328
|
+
export interface AdwMenuSurface {
|
|
329
|
+
/** A name for the diagnostic — `adwaita-web`, `nativescript`. */
|
|
330
|
+
readonly name: string;
|
|
331
|
+
/** Can it host an application widget named by `custom`? Only GTK can. */
|
|
332
|
+
readonly custom: boolean;
|
|
333
|
+
}
|
|
334
|
+
/** The browser popover: it has no `add_child` for a `custom` item to name. */
|
|
335
|
+
export declare const ADW_MENU_SURFACE_WEB: AdwMenuSurface;
|
|
336
|
+
/** The NativeScript action sheet: its rows are STRINGS, so a `custom` widget has no home. */
|
|
337
|
+
export declare const ADW_MENU_SURFACE_NATIVESCRIPT: AdwMenuSurface;
|
|
338
|
+
/** One thing a surface will not draw, with where it is. */
|
|
339
|
+
export interface AdwMenuRefusal {
|
|
340
|
+
readonly path: AdwMenuPath;
|
|
341
|
+
/** The attribute that cannot be honoured. */
|
|
342
|
+
readonly what: 'custom';
|
|
343
|
+
readonly message: string;
|
|
344
|
+
}
|
|
345
|
+
/**
|
|
346
|
+
* Every part of a model the surface cannot render — empty when it can render all of it.
|
|
347
|
+
*
|
|
348
|
+
* IT LISTS WHAT WOULD VANISH, NOT WHAT WOULD LOOK DIFFERENT. An icon a sheet cannot show
|
|
349
|
+
* is a decoration and the row is still there; a `custom` item is a PLACEHOLDER for an
|
|
350
|
+
* application widget, so a surface that ignores it draws a blank row where a control
|
|
351
|
+
* belongs, and the reader has no way to tell. That is the distinction the three-way
|
|
352
|
+
* split in this file's header draws, and it is why refusing everything unsupported
|
|
353
|
+
* would be useless: NativeScript renders no icon and no accelerator on any menu, so a
|
|
354
|
+
* refusal per decoration would fire on every well-formed menu and be switched off.
|
|
355
|
+
*/
|
|
356
|
+
export declare function menuRefusals(model: AdwMenuModel, surface: AdwMenuSurface, path?: AdwMenuPath): AdwMenuRefusal[];
|
|
357
|
+
/**
|
|
358
|
+
* Throw if the surface cannot render the model.
|
|
359
|
+
*
|
|
360
|
+
* Called by a renderer when a menu is SET, so the throw names the assignment rather than
|
|
361
|
+
* arriving as a missing row three interactions later. The message carries every refusal,
|
|
362
|
+
* not the first: a menu written for GTK typically has all of its `custom` items at once,
|
|
363
|
+
* and reporting them one run at a time is how a port becomes a series of identical bug
|
|
364
|
+
* reports.
|
|
365
|
+
*/
|
|
366
|
+
export declare function assertMenuRenderable(model: AdwMenuModel, surface: AdwMenuSurface): void;
|
package/lib/types/rows.d.ts
CHANGED
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
import type { AdwComboOption, AdwListItemsChanged } from './list.js';
|
|
2
|
+
export { ADW_COMBO_NO_SELECTION, normalizeComboOptions } from './list.js';
|
|
3
|
+
export type { AdwComboOption, AdwComboOptionInput } from './list.js';
|
|
4
|
+
export { SpinState } from './adjustment.js';
|
|
5
|
+
export type { SpinStateChange, SpinStateListener, SpinStateRangeListener } from './adjustment.js';
|
|
1
6
|
/** Subscriber for {@link ExpanderState} changes — receives the new expanded flag. */
|
|
2
7
|
export type ExpanderStateListener = (expanded: boolean) => void;
|
|
3
8
|
/**
|
|
@@ -23,44 +28,6 @@ export declare class ExpanderState {
|
|
|
23
28
|
/** Collapse the disclosure. Returns whether it changed. */
|
|
24
29
|
collapse(): boolean;
|
|
25
30
|
}
|
|
26
|
-
/** One selectable option in a {@link ComboState}. */
|
|
27
|
-
export interface AdwComboOption {
|
|
28
|
-
/** Display label shown in the row + chooser. */
|
|
29
|
-
label: string;
|
|
30
|
-
/** Underlying value returned by {@link ComboState.selectedValue}. */
|
|
31
|
-
value: string;
|
|
32
|
-
}
|
|
33
|
-
/**
|
|
34
|
-
* What an author may write for one option before {@link normalizeComboOptions}
|
|
35
|
-
* has seen it: a bare string (value === label, the `Gtk.StringList` case), or a
|
|
36
|
-
* partial descriptor where either half may stand in for the other.
|
|
37
|
-
*/
|
|
38
|
-
export type AdwComboOptionInput = string | {
|
|
39
|
-
value?: unknown;
|
|
40
|
-
label?: unknown;
|
|
41
|
-
};
|
|
42
|
-
/**
|
|
43
|
-
* Raw authored options → the stable `{ value, label }` descriptors every combo surface
|
|
44
|
-
* works with.
|
|
45
|
-
*
|
|
46
|
-
* A bare string is both value and label (`Gtk.StringList`'s model, which is what
|
|
47
|
-
* `Adw.ComboRow` is fed in the common case). In a descriptor either half stands in for the
|
|
48
|
-
* missing other, so `{ label: 'Apple' }` is addressable by the value `'Apple'` rather than
|
|
49
|
-
* by `undefined`. ONE home for the rule, so `<adw-combo-row>` and `<gtk-drop-down>` cannot
|
|
50
|
-
* accept two different option vocabularies.
|
|
51
|
-
*/
|
|
52
|
-
export declare function normalizeComboOptions(raw: ReadonlyArray<AdwComboOptionInput> | null | undefined): AdwComboOption[];
|
|
53
|
-
/**
|
|
54
|
-
* The "no item is selected" index — the TS mirror of `GTK_INVALID_LIST_POSITION`
|
|
55
|
-
* (`AdwComboRow:selected`'s default and empty value).
|
|
56
|
-
*
|
|
57
|
-
* libadwaita spells it `G_MAXUINT` because the property is a `guint`; `-1` is the idiomatic
|
|
58
|
-
* TS sentinel and the spelling {@link ADW_SIDEBAR_NO_SELECTION} uses for the same GTK
|
|
59
|
-
* constant. Without it, an EMPTY model and a model whose first item has an empty label are
|
|
60
|
-
* indistinguishable — both report index 0 with `selectedValue === ''` — so a renderer that
|
|
61
|
-
* wants to draw a placeholder has nothing to test.
|
|
62
|
-
*/
|
|
63
|
-
export declare const ADW_COMBO_NO_SELECTION = -1;
|
|
64
31
|
/** Payload of a {@link ComboState} change. */
|
|
65
32
|
export interface ComboStateChange {
|
|
66
33
|
/** The (new) selected index, or {@link ADW_COMBO_NO_SELECTION}. */
|
|
@@ -72,41 +39,94 @@ export interface ComboStateChange {
|
|
|
72
39
|
/** True for a user pick ({@link ComboState.select}); false for a programmatic set. */
|
|
73
40
|
interactive: boolean;
|
|
74
41
|
}
|
|
75
|
-
/** Subscriber for {@link ComboState} changes. */
|
|
42
|
+
/** Subscriber for {@link ComboState} selection changes. */
|
|
76
43
|
export type ComboStateListener = (change: ComboStateChange) => void;
|
|
44
|
+
/** Subscriber for {@link ComboState} MODEL changes — one `items-changed` per replacement. */
|
|
45
|
+
export type ComboItemsListener = (change: AdwListItemsChanged) => void;
|
|
77
46
|
/**
|
|
78
|
-
* The selection state of a combo row:
|
|
79
|
-
* with a two-way index↔value mapping and empty/out-of-range guards.
|
|
80
|
-
* `Adw.ComboRow`: a programmatic set ({@link setSelectedIndex} /
|
|
81
|
-
* / {@link
|
|
82
|
-
* the inline value but re-emits no `notify::selected`), while
|
|
83
|
-
* user pick that notifies (`interactive: true`).
|
|
47
|
+
* The selection state of a combo row: a portable list model (`AdwListModel`) plus
|
|
48
|
+
* the selected index, with a two-way index↔value mapping and empty/out-of-range guards.
|
|
49
|
+
* Mirrors `Adw.ComboRow`: a programmatic set ({@link setSelectedIndex} /
|
|
50
|
+
* {@link setSelectedValue} / {@link setModel}) updates silently (`interactive: false` —
|
|
51
|
+
* the renderer refreshes the inline value but re-emits no `notify::selected`), while
|
|
52
|
+
* {@link select} is the user pick that notifies (`interactive: true`).
|
|
53
|
+
*
|
|
54
|
+
* TWO SIGNALS, because they answer different questions and a renderer needs both
|
|
55
|
+
* (ADR 0046). {@link subscribe} reports the SELECTION; {@link subscribeItems} reports WHERE
|
|
56
|
+
* the model changed, so a renderer splices its item views instead of rebuilding them.
|
|
57
|
+
* `Adw.ComboRow` gets both from GTK for free — the first is `notify::selected`, the second
|
|
58
|
+
* is `Gio.ListModel::items-changed` on the model it holds — and this class had only the
|
|
59
|
+
* first, which is why both browser selectors dropped every option node on every
|
|
60
|
+
* assignment.
|
|
84
61
|
*/
|
|
85
62
|
export declare class ComboState {
|
|
86
63
|
private _options;
|
|
87
64
|
private _selected;
|
|
88
65
|
private readonly _listeners;
|
|
66
|
+
private readonly _itemListeners;
|
|
89
67
|
/** Subscribe to selection changes. Returns an unsubscribe function. */
|
|
90
68
|
subscribe(listener: ComboStateListener): () => void;
|
|
69
|
+
/**
|
|
70
|
+
* Subscribe to MODEL changes — `Gio.ListModel::items-changed`, one splice per
|
|
71
|
+
* {@link setModel}. Returns an unsubscribe function.
|
|
72
|
+
*
|
|
73
|
+
* Fires BEFORE the selection change {@link setModel} also emits, which is the order
|
|
74
|
+
* that makes it usable: the selection subscriber writes the new index into the item
|
|
75
|
+
* views, so those views have to exist by then. The rebuild path had the inverse
|
|
76
|
+
* ordering hazard written down in `<adw-combo-row>` — "AFTER the rebuild, never during
|
|
77
|
+
* it" — and this is what removes it rather than documenting it again.
|
|
78
|
+
*/
|
|
79
|
+
subscribeItems(listener: ComboItemsListener): () => void;
|
|
91
80
|
private _emit;
|
|
92
81
|
private _setIndex;
|
|
93
|
-
/** The selectable options. */
|
|
94
|
-
get options(): AdwComboOption[];
|
|
95
82
|
/**
|
|
96
|
-
*
|
|
97
|
-
*
|
|
98
|
-
*
|
|
83
|
+
* The list model — `Adw.ComboRow:model` / `Gtk.DropDown:model`, in portable form.
|
|
84
|
+
*
|
|
85
|
+
* A COPY, items included, and that is load-bearing rather than defensive. The splice
|
|
86
|
+
* (ADR 0046) decides what changed by COMPARING the assigned model against the stored
|
|
87
|
+
* one, so anything that leaks a reference into `_options` makes the comparison read the
|
|
88
|
+
* new value on both sides and answer "nothing changed". Handing back `_options` itself
|
|
89
|
+
* did exactly that, and it turned a pattern that WORKED under the old full rebuild into
|
|
90
|
+
* a silent no-op:
|
|
91
|
+
*
|
|
92
|
+
* ```ts
|
|
93
|
+
* const m = row.model; m.push(item); row.model = m; // → no splice, DOM unchanged
|
|
94
|
+
* ```
|
|
95
|
+
*
|
|
96
|
+
* Fresh items and not just a fresh array, because the same failure sits one level down:
|
|
97
|
+
* `m[0].label = 'x'` through a shared descriptor mutates the stored one too, and the
|
|
98
|
+
* comparison is by BOTH halves. A frozen item would have made the mutation loud; a copy
|
|
99
|
+
* makes the round trip CORRECT, which is the difference between documenting the hazard
|
|
100
|
+
* and removing it.
|
|
101
|
+
*
|
|
102
|
+
* Cost, MEASURED rather than assumed (Node 24.19, `{value,label}` records): linear, about
|
|
103
|
+
* four nanoseconds per item — so a read is well under a microsecond at every size a combo
|
|
104
|
+
* row actually holds, and the assignment beside it already costs more. What the shape
|
|
105
|
+
* rules out is a per-item read: the three call sites that had one — `_applyItemsChanged`
|
|
106
|
+
* in each browser selector and `_filter` in `<gtk-drop-down>`, which runs per row per
|
|
107
|
+
* keystroke — hoist it out of their loop, so a read is O(n) once per operation instead of
|
|
108
|
+
* O(n²). Nothing reads it per frame. A model large enough for the linear term to matter is
|
|
109
|
+
* a `Gtk.ListView` and belongs to `ListController`'s virtualisation, which ADR 0046 § 7
|
|
110
|
+
* keeps out of this class on purpose.
|
|
111
|
+
*/
|
|
112
|
+
get model(): AdwComboOption[];
|
|
113
|
+
/**
|
|
114
|
+
* Replace the model: emit the splice that turns the old one into the new
|
|
115
|
+
* ({@link subscribeItems}), then notify the SELECTION (`interactive: false`) so the
|
|
116
|
+
* renderer re-syncs the inline value label — which may change even at an unchanged
|
|
117
|
+
* index, because the label is read out of the model.
|
|
99
118
|
*
|
|
100
|
-
* Replacing the model re-runs autoselect, so an index the
|
|
101
|
-
* back to 0 — including the sentinel, which is how a row
|
|
102
|
-
* model grows. An EMPTY model has no 0 to fall back to
|
|
103
|
-
* {@link ADW_COMBO_NO_SELECTION}.
|
|
119
|
+
* Replacing the model re-runs autoselect ({@link clampListSelection}), so an index the
|
|
120
|
+
* new one does not have falls back to 0 — including the sentinel, which is how a row
|
|
121
|
+
* recovers a selection when its model grows. An EMPTY model has no 0 to fall back to
|
|
122
|
+
* and lands on {@link ADW_COMBO_NO_SELECTION}.
|
|
104
123
|
*
|
|
105
|
-
* The
|
|
106
|
-
*
|
|
107
|
-
*
|
|
124
|
+
* The selection notify is UNCONDITIONAL while the splice is not: an assignment of an
|
|
125
|
+
* equal model emits no `items-changed` (GTK emits none either) but still re-runs the
|
|
126
|
+
* label sync, because that is the behaviour every renderer has depended on since this
|
|
127
|
+
* class existed and nothing measured says it is wrong.
|
|
108
128
|
*/
|
|
109
|
-
|
|
129
|
+
setModel(model: AdwComboOption[]): void;
|
|
110
130
|
/**
|
|
111
131
|
* The selected option index, or {@link ADW_COMBO_NO_SELECTION}. May also sit PAST the
|
|
112
132
|
* options length: {@link setSelectedIndex} is deliberately permissive, mirroring a
|
|
@@ -157,57 +177,6 @@ export declare class ComboState {
|
|
|
157
177
|
/** Number of options. */
|
|
158
178
|
get count(): number;
|
|
159
179
|
}
|
|
160
|
-
/** Payload of a {@link SpinState} change. */
|
|
161
|
-
export interface SpinStateChange {
|
|
162
|
-
/** The new value (already clamped to `[min, max]`). */
|
|
163
|
-
value: number;
|
|
164
|
-
/** True for a stepper press ({@link SpinState.increment}/{@link SpinState.decrement}); false for a programmatic set/re-clamp. */
|
|
165
|
-
interactive: boolean;
|
|
166
|
-
}
|
|
167
|
-
/** Subscriber for {@link SpinState} changes. */
|
|
168
|
-
export type SpinStateListener = (change: SpinStateChange) => void;
|
|
169
|
-
/**
|
|
170
|
-
* The numeric adjustment state of a spin row: `value` bounded by `[min, max]` and
|
|
171
|
-
* stepped by `step`. Every mutation clamps into range. Mirrors `Adw.SpinRow`: a
|
|
172
|
-
* programmatic {@link setValue} (or a re-clamp from a moved {@link setMin}/{@link setMax})
|
|
173
|
-
* notifies `interactive: false` (the renderer refreshes the display but re-emits no
|
|
174
|
-
* `notify::value`), while {@link increment}/{@link decrement} are the stepper presses
|
|
175
|
-
* that notify `interactive: true`.
|
|
176
|
-
*/
|
|
177
|
-
export declare class SpinState {
|
|
178
|
-
private _value;
|
|
179
|
-
private _min;
|
|
180
|
-
private _max;
|
|
181
|
-
private _step;
|
|
182
|
-
private readonly _listeners;
|
|
183
|
-
/** Subscribe to value changes. Returns an unsubscribe function. */
|
|
184
|
-
subscribe(listener: SpinStateListener): () => void;
|
|
185
|
-
private _emit;
|
|
186
|
-
private _clamp;
|
|
187
|
-
private _bump;
|
|
188
|
-
/** Re-clamp the current value after a bound moved; notifies `interactive: false` on change. */
|
|
189
|
-
private _reclamp;
|
|
190
|
-
/** The current numeric value (always within `[min, max]`). */
|
|
191
|
-
get value(): number;
|
|
192
|
-
/** Lower bound. */
|
|
193
|
-
get min(): number;
|
|
194
|
-
/** Upper bound. */
|
|
195
|
-
get max(): number;
|
|
196
|
-
/** Increment/decrement step applied per stepper press. */
|
|
197
|
-
get step(): number;
|
|
198
|
-
/** Programmatic value set — clamp, notify `interactive: false` on change. Returns whether it changed. */
|
|
199
|
-
setValue(value: number): boolean;
|
|
200
|
-
/** Set the lower bound and re-clamp the value into range. Returns whether the value changed. */
|
|
201
|
-
setMin(value: number): boolean;
|
|
202
|
-
/** Set the upper bound and re-clamp the value into range. Returns whether the value changed. */
|
|
203
|
-
setMax(value: number): boolean;
|
|
204
|
-
/** Set the step. A non-positive or non-finite step falls back to `1`. */
|
|
205
|
-
setStep(value: number): void;
|
|
206
|
-
/** Step up by `step`, clamped to `max`. Notifies `interactive: true` on change. Returns whether it changed. */
|
|
207
|
-
increment(): boolean;
|
|
208
|
-
/** Step down by `step`, clamped to `min`. Notifies `interactive: true` on change. Returns whether it changed. */
|
|
209
|
-
decrement(): boolean;
|
|
210
|
-
}
|
|
211
180
|
/** Payload of a {@link ToggleGroupState} change. */
|
|
212
181
|
export interface ToggleGroupStateChange {
|
|
213
182
|
/** The newly-selected segment index. */
|