@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.
Files changed (37) hide show
  1. package/lib/esm/adjustment.js +1 -0
  2. package/lib/esm/avatar.js +1 -1
  3. package/lib/esm/conformance/adjustment.js +1 -0
  4. package/lib/esm/conformance/avatar.js +1 -1
  5. package/lib/esm/conformance/index.js +1 -1
  6. package/lib/esm/conformance/list.js +1 -0
  7. package/lib/esm/conformance/menu.js +1 -0
  8. package/lib/esm/conformance/rows.js +1 -1
  9. package/lib/esm/conformance/shared-trees.js +1 -0
  10. package/lib/esm/conformance/split-button.js +1 -1
  11. package/lib/esm/index.js +1 -1
  12. package/lib/esm/list.js +1 -0
  13. package/lib/esm/menu.js +2 -0
  14. package/lib/esm/rows.js +1 -1
  15. package/lib/esm/split-button.js +1 -1
  16. package/lib/esm/tab-view.js +1 -1
  17. package/lib/types/adjustment.d.ts +198 -0
  18. package/lib/types/adjustment.spec.d.ts +2 -0
  19. package/lib/types/avatar.d.ts +15 -0
  20. package/lib/types/conformance/adjustment.d.ts +33 -0
  21. package/lib/types/conformance/avatar.d.ts +16 -0
  22. package/lib/types/conformance/index.d.ts +12 -4
  23. package/lib/types/conformance/list.d.ts +171 -0
  24. package/lib/types/conformance/menu.d.ts +118 -0
  25. package/lib/types/conformance/rows.d.ts +3 -3
  26. package/lib/types/conformance/shared-trees.d.ts +93 -0
  27. package/lib/types/conformance/split-button.d.ts +9 -19
  28. package/lib/types/index.d.ts +12 -6
  29. package/lib/types/list.d.ts +109 -0
  30. package/lib/types/list.spec.d.ts +2 -0
  31. package/lib/types/menu.d.ts +366 -0
  32. package/lib/types/menu.spec.d.ts +2 -0
  33. package/lib/types/rows.d.ts +78 -109
  34. package/lib/types/shared-trees.spec.d.ts +2 -0
  35. package/lib/types/split-button.d.ts +21 -32
  36. package/lib/types/tab-view.d.ts +35 -2
  37. package/package.json +3 -3
@@ -1,3 +1,4 @@
1
+ import type { AdwMenuInput, AdwMenuItem, AdwMenuModel, AdwMenuPath } from './menu.js';
1
2
  /**
2
3
  * The four mutually exclusive content slots of the action half. `'empty'` is the
3
4
  * initial state — `label`, `icon-name` and `child` are all `NULL`.
@@ -21,22 +22,6 @@ export type SplitButtonStyleClass = 'image-button' | 'text-button';
21
22
  * single freeze/thaw, and that sequence cannot be reconstructed from the final state alone.
22
23
  */
23
24
  export type SplitButtonProperty = 'label' | 'icon-name' | 'child' | 'use-underline' | 'menu-model' | 'popover' | 'direction' | 'dropdown-tooltip';
24
- /**
25
- * One `GMenuModel` item: a label plus the detailed action it invokes, i.e. what
26
- * `Gio.Menu.append (label, action)` produces. `id` and `icon` are the renderers'
27
- * menu-button extras, so every menu call site can converge on ONE type; the name is
28
- * family-neutral because `Adw.MenuButton` needs exactly this.
29
- */
30
- export interface AdwMenuEntry {
31
- /** Display label. */
32
- label: string;
33
- /** Detailed action name, e.g. `app.save-as`. */
34
- action?: string;
35
- /** Stable identifier, defaulting to {@link label} on activation. */
36
- id?: string;
37
- /** Symbolic icon name for the item. */
38
- icon?: string;
39
- }
40
25
  /** Payload of a {@link SplitButtonState} notification. */
41
26
  export interface SplitButtonChange {
42
27
  /** Which content slot is filled. */
@@ -55,7 +40,7 @@ export interface SplitButtonChange {
55
40
  open: boolean;
56
41
  /** The `notify::*` properties C emits for this one mutation, in emission order. */
57
42
  notified: readonly SplitButtonProperty[];
58
- /** True for a user gesture ({@link SplitButtonState.toggleMenu} / {@link SplitButtonState.activateMenuEntry}). */
43
+ /** True for a user gesture ({@link SplitButtonState.toggleMenu} / {@link SplitButtonState.activateMenuItem}). */
59
44
  interactive: boolean;
60
45
  }
61
46
  /** Subscriber for {@link SplitButtonState} changes. */
@@ -127,12 +112,6 @@ export declare function splitButtonRootState(action: SplitButtonHalfState, dropd
127
112
  active: boolean;
128
113
  checked: boolean;
129
114
  };
130
- /**
131
- * Parse a JSON menu attribute into entries. Total by construction — malformed JSON, a
132
- * non-array root and entries without a `label` key all yield `[]` / are dropped — because
133
- * the input is author-written markup and a typo must not take the widget down with it.
134
- */
135
- export declare function parseMenuEntries(json: string | null | undefined): AdwMenuEntry[];
136
115
  /**
137
116
  * The whole `Adw.SplitButton` state machine: content mode, use-underline,
138
117
  * menu-model/popover exclusivity, direction, dropdown tooltip and the popup flag. Every
@@ -194,19 +173,25 @@ export declare class SplitButtonState {
194
173
  * PROPERTY lives here; the `_S` → underlined-S derivation belongs to `GtkLabel`.
195
174
  */
196
175
  setUseUnderline(value: boolean): boolean;
197
- /** The menu entries, or `null` when no menu model is set. */
198
- get menuModel(): readonly AdwMenuEntry[] | null;
176
+ /** The menu model, or `null` when none is set. Always normalised (ADR 0042). */
177
+ get menuModel(): AdwMenuModel | null;
199
178
  /**
200
179
  * Set the menu model, dissociating any popover and replacing it with the model-derived
201
180
  * one.
202
181
  *
182
+ * NORMALISES AT THE DOOR, so every surface stores the same shape whatever it was
183
+ * handed — a JSON attribute, a bare `string[]`, a JSX array of descriptors. It is
184
+ * {@link normalizeMenuModel}'s idempotence that makes `setMenuModel(state.menuModel)`
185
+ * a no-op rather than a quiet flattening.
186
+ *
203
187
  * DELIBERATE NORMALISATION: an EMPTY list is stored as "no menu model". C can hold a
204
188
  * non-`NULL` but empty `GMenu`, which leaves the dropdown live and pops up an empty
205
- * popover — but no renderer can construct that state (one parses a JSON array, another
206
- * takes a label list), so collapsing the two is what makes "no menu ⇒ insensitive
207
- * dropdown" hold from a renderer's point of view.
189
+ * popover; collapsing the two is what makes "no menu ⇒ insensitive dropdown" hold
190
+ * from a renderer's point of view. A model that is non-empty but draws nothing — one
191
+ * empty section — is NOT collapsed: it has a node, so it is a menu, which is the
192
+ * answer GTK gives for the same `GMenu`.
208
193
  */
209
- setMenuModel(entries: readonly AdwMenuEntry[] | null | undefined): boolean;
194
+ setMenuModel(input: AdwMenuInput | null | undefined): boolean;
210
195
  /** The popover: the one the app set, or the model-derived stand-in, or `null`. */
211
196
  get popover(): object | null;
212
197
  /**
@@ -248,13 +233,17 @@ export declare class SplitButtonState {
248
233
  /** The dropdown half was activated by the user; flips the menu open/closed. */
249
234
  toggleMenu(): boolean;
250
235
  /**
251
- * Activate a menu entry BY POSITION and dismiss the menu, returning the entry
252
- * (or `null` for an out-of-range index).
236
+ * Activate a menu item BY POSITION and dismiss the menu, returning the item
237
+ * (or `null` for a path that names no item).
253
238
  *
254
239
  * Position is the addressing a `GMenuModel` actually uses — each item carries its own
255
240
  * detailed action. Resolving a choice by LABEL instead silently dispatches the first of
256
241
  * two identically named entries and cannot tell an entry called `Cancel` from a
257
242
  * dismissed sheet.
243
+ *
244
+ * A PATH rather than a single index (ADR 0042), because a link is a model of its own:
245
+ * `[1, 0]` is the first item of the submenu at position 1, and a flat index cannot
246
+ * name it. A top-level choice is `[2]`.
258
247
  */
259
- activateMenuEntry(index: number): AdwMenuEntry | null;
248
+ activateMenuItem(path: AdwMenuPath): AdwMenuItem | null;
260
249
  }
@@ -1,3 +1,4 @@
1
+ import type { AdwListItemsChanged } from './list.js';
1
2
  /**
2
3
  * Input shape for a tab page.
3
4
  *
@@ -120,6 +121,29 @@ export interface TabViewPagesChange {
120
121
  }
121
122
  /** Subscriber for {@link TabViewState} page-list changes. */
122
123
  export type TabViewPagesListener = (change: TabViewPagesChange) => void;
124
+ /**
125
+ * The same change as a portable `items-changed` (ADR 0046) — the mapping that makes "the
126
+ * tab view's page signal IS the positional list signal" a CHECKABLE claim rather than a
127
+ * sentence in an ADR.
128
+ *
129
+ * `TabViewPagesChange` was the only positional collection signal in this package, and it
130
+ * is the evidence the portable one is shaped right; the portable one is GLib's, because
131
+ * `AdwTabView:pages` really is a `GListModel` even though the PAGES are appended by a
132
+ * method. The five kinds fold onto the three numbers exactly:
133
+ *
134
+ * attached (p, 0, 1) an item arrived at p
135
+ * detached (p, 1, 0) an item left p
136
+ * updated (p, 1, 1) the item at p is a different thing to draw — which is how
137
+ * `GListModel` spells a per-item change; it has no other verb
138
+ * reordered \
139
+ * pinned / the span between the two positions, removed and re-added. A move has no
140
+ * verb either, and `g_list_store_move` reports it the same way.
141
+ *
142
+ * NOT a lossy conversion in the direction that matters: {@link AdwListItemsChanged} plus
143
+ * the change's `id` is enough to replay the whole page order, which is what the two
144
+ * renderer tab-view suites assert against the orders their real widgets end on.
145
+ */
146
+ export declare function tabViewItemsChanged(change: TabViewPagesChange): AdwListItemsChanged;
123
147
  /** What a tab draws in its icon and indicator slots — the result of {@link tabIconState}. */
124
148
  export interface TabIconState {
125
149
  /** The icon name to paint, or `null` when there is none to paint. */
@@ -311,15 +335,24 @@ export declare class TabViewState<T = unknown> {
311
335
  /** The selected page, or `null`. */
312
336
  get selectedPage(): AdwTabPageState<T> | null;
313
337
  /**
314
- * Select a page by id. Returns whether the selection changed.
338
+ * Select a page — by the PAGE, or by its id. Returns whether the selection changed.
315
339
  *
316
340
  * An unknown id is refused, and `null` is accepted only while the view is empty —
317
341
  * `adw_tab_view_set_selected_page` asserts `ADW_IS_TAB_PAGE` +
318
342
  * `page_belongs_to_this_view` when `n_pages > 0`, and `selected_page == NULL`
319
343
  * otherwise. `interactive` defaults to `true` because this IS the explicit call;
320
344
  * the model-driven paths (first-page auto-select, close successor) pass `false`.
345
+ *
346
+ * THE PAGE OVERLOAD IS WHAT MAKES `page_belongs_to_this_view` TRUE HERE. An id is
347
+ * unique within ONE view (`_nextId` counts per view), so handing this view another
348
+ * view's page and reading only its id selects the page of the same id HERE — measured
349
+ * on the renderers' `selectedPage` setters, where `viewA.selectedPage = viewB.pages[2]`
350
+ * moved viewA to index 2 rather than refusing. The object is what separates them, so
351
+ * the identity check belongs at the one place that owns the page list, and the refusal
352
+ * carries the same diagnostic C raises rather than being a silent no-op in two
353
+ * renderers.
321
354
  */
322
- setSelectedPage(id: string | null, interactive?: boolean): boolean;
355
+ setSelectedPage(page: AdwTabPageState<T> | string | null, interactive?: boolean): boolean;
323
356
  /**
324
357
  * Select the page at `n` — the Alt+1…Alt+9 / Alt+0 path (`select_nth_page_cb`;
325
358
  * Alt+0 is `n = 9`, since pages count from 0).
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gjsify/adwaita-core",
3
- "version": "0.47.0",
3
+ "version": "0.49.0",
4
4
  "description": "Headless Adwaita widget behavior (breakpoint condition grammar + apply/unapply state machine, color-scheme observable, avatar derivation) shared by the web and NativeScript Adwaita renderers — pure TS, no platform imports",
5
5
  "type": "module",
6
6
  "module": "lib/esm/index.js",
@@ -50,8 +50,8 @@
50
50
  "headless"
51
51
  ],
52
52
  "devDependencies": {
53
- "@gjsify/cli": "^0.47.0",
54
- "@gjsify/unit": "^0.47.0",
53
+ "@gjsify/cli": "^0.49.0",
54
+ "@gjsify/unit": "^0.49.0",
55
55
  "@types/node": "^25.9.2",
56
56
  "typescript": "^6.0.3"
57
57
  },