@gjsify/adwaita-core 0.31.0 → 0.32.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 (112) hide show
  1. package/lib/esm/about-dialog.js +3 -0
  2. package/lib/esm/action-row.js +1 -0
  3. package/lib/esm/avatar.js +1 -0
  4. package/lib/esm/banner.js +1 -0
  5. package/lib/esm/button-content.js +1 -0
  6. package/lib/esm/carousel.js +1 -0
  7. package/lib/esm/checks.js +1 -0
  8. package/lib/esm/chrome.js +1 -0
  9. package/lib/esm/conformance/about-dialog.js +6 -0
  10. package/lib/esm/conformance/action-row.js +1 -0
  11. package/lib/esm/conformance/avatar.js +1 -0
  12. package/lib/esm/conformance/banner.js +1 -0
  13. package/lib/esm/conformance/button-content.js +1 -0
  14. package/lib/esm/conformance/carousel.js +1 -0
  15. package/lib/esm/conformance/checks.js +1 -0
  16. package/lib/esm/conformance/chrome.js +1 -0
  17. package/lib/esm/conformance/data-grid.js +1 -0
  18. package/lib/esm/conformance/dialog.js +1 -0
  19. package/lib/esm/conformance/entry-row.js +1 -0
  20. package/lib/esm/conformance/index.js +1 -0
  21. package/lib/esm/conformance/navigation-view.js +1 -0
  22. package/lib/esm/conformance/popover.js +1 -0
  23. package/lib/esm/conformance/preferences.js +1 -0
  24. package/lib/esm/conformance/rows.js +1 -0
  25. package/lib/esm/conformance/sidebar.js +1 -0
  26. package/lib/esm/conformance/split-button.js +1 -0
  27. package/lib/esm/conformance/split-view.js +1 -0
  28. package/lib/esm/conformance/tab-view.js +1 -0
  29. package/lib/esm/conformance/view-stack.js +1 -0
  30. package/lib/esm/conformance/view-switcher.js +1 -0
  31. package/lib/esm/conformance/wrap-box.js +1 -0
  32. package/lib/esm/data-grid.js +1 -0
  33. package/lib/esm/dialog.js +1 -1
  34. package/lib/esm/entry-row.js +1 -0
  35. package/lib/esm/glib.js +1 -0
  36. package/lib/esm/index.js +1 -1
  37. package/lib/esm/navigation-view.js +1 -0
  38. package/lib/esm/popover.js +1 -0
  39. package/lib/esm/preferences.js +1 -0
  40. package/lib/esm/rows.js +1 -1
  41. package/lib/esm/sidebar.js +1 -0
  42. package/lib/esm/split-button.js +1 -0
  43. package/lib/esm/split-view.js +1 -0
  44. package/lib/esm/tab-view.js +1 -0
  45. package/lib/esm/view-stack.js +1 -0
  46. package/lib/esm/view-switcher.js +1 -0
  47. package/lib/types/about-dialog.d.ts +391 -0
  48. package/lib/types/about-dialog.spec.d.ts +2 -0
  49. package/lib/types/action-row.d.ts +270 -0
  50. package/lib/types/action-row.spec.d.ts +2 -0
  51. package/lib/types/avatar.d.ts +112 -0
  52. package/lib/types/avatar.spec.d.ts +2 -0
  53. package/lib/types/banner.d.ts +104 -0
  54. package/lib/types/banner.spec.d.ts +2 -0
  55. package/lib/types/button-content.d.ts +141 -0
  56. package/lib/types/button-content.spec.d.ts +2 -0
  57. package/lib/types/carousel.d.ts +535 -0
  58. package/lib/types/carousel.spec.d.ts +2 -0
  59. package/lib/types/checks.d.ts +63 -0
  60. package/lib/types/checks.spec.d.ts +2 -0
  61. package/lib/types/chrome.d.ts +355 -0
  62. package/lib/types/chrome.spec.d.ts +2 -0
  63. package/lib/types/conformance/about-dialog.d.ts +300 -0
  64. package/lib/types/conformance/action-row.d.ts +186 -0
  65. package/lib/types/conformance/avatar.d.ts +61 -0
  66. package/lib/types/conformance/banner.d.ts +91 -0
  67. package/lib/types/conformance/button-content.d.ts +110 -0
  68. package/lib/types/conformance/carousel.d.ts +284 -0
  69. package/lib/types/conformance/checks.d.ts +29 -0
  70. package/lib/types/conformance/chrome.d.ts +195 -0
  71. package/lib/types/conformance/data-grid.d.ts +134 -0
  72. package/lib/types/conformance/dialog.d.ts +97 -0
  73. package/lib/types/conformance/entry-row.d.ts +185 -0
  74. package/lib/types/conformance/index.d.ts +44 -0
  75. package/lib/types/conformance/navigation-view.d.ts +235 -0
  76. package/lib/types/conformance/popover.d.ts +56 -0
  77. package/lib/types/conformance/preferences.d.ts +170 -0
  78. package/lib/types/conformance/rows.d.ts +51 -0
  79. package/lib/types/conformance/sidebar.d.ts +182 -0
  80. package/lib/types/conformance/split-button.d.ts +189 -0
  81. package/lib/types/conformance/split-view.d.ts +290 -0
  82. package/lib/types/conformance/tab-view.d.ts +441 -0
  83. package/lib/types/conformance/view-stack.d.ts +121 -0
  84. package/lib/types/conformance/view-switcher.d.ts +443 -0
  85. package/lib/types/conformance/wrap-box.d.ts +134 -0
  86. package/lib/types/data-grid.d.ts +140 -0
  87. package/lib/types/data-grid.spec.d.ts +2 -0
  88. package/lib/types/dialog.d.ts +144 -0
  89. package/lib/types/entry-row.d.ts +308 -0
  90. package/lib/types/entry-row.spec.d.ts +2 -0
  91. package/lib/types/glib.d.ts +49 -0
  92. package/lib/types/index.d.ts +43 -4
  93. package/lib/types/navigation-view.d.ts +343 -0
  94. package/lib/types/navigation-view.spec.d.ts +2 -0
  95. package/lib/types/popover.d.ts +155 -0
  96. package/lib/types/popover.spec.d.ts +2 -0
  97. package/lib/types/preferences.d.ts +349 -0
  98. package/lib/types/preferences.spec.d.ts +2 -0
  99. package/lib/types/rows.d.ts +49 -2
  100. package/lib/types/sidebar.d.ts +308 -0
  101. package/lib/types/sidebar.spec.d.ts +2 -0
  102. package/lib/types/split-button.d.ts +316 -0
  103. package/lib/types/split-button.spec.d.ts +2 -0
  104. package/lib/types/split-view.d.ts +714 -0
  105. package/lib/types/split-view.spec.d.ts +2 -0
  106. package/lib/types/tab-view.d.ts +616 -0
  107. package/lib/types/tab-view.spec.d.ts +2 -0
  108. package/lib/types/view-stack.d.ts +266 -0
  109. package/lib/types/view-stack.spec.d.ts +2 -0
  110. package/lib/types/view-switcher.d.ts +521 -0
  111. package/lib/types/view-switcher.spec.d.ts +2 -0
  112. package/package.json +8 -4
@@ -0,0 +1,521 @@
1
+ import { stripMnemonic } from './glib.js';
2
+ import type { AdwViewStackPageInfo } from './view-stack.js';
3
+ /**
4
+ * The "nothing is selected" sentinel, standing in for
5
+ * `GTK_INVALID_LIST_POSITION` (adw-inline-view-switcher.c:366, :441).
6
+ *
7
+ * Returned by {@link toggleIndexForPage} / {@link pageIndexForToggle} when the
8
+ * two index spaces have no counterpart for each other — a hidden page has no
9
+ * toggle at all, which is a state `ToggleGroupState`'s always-non-negative
10
+ * `selected` cannot express.
11
+ */
12
+ export declare const VIEW_SWITCHER_NO_SELECTION = -1;
13
+ /**
14
+ * The icon substituted for a NULL or empty icon name
15
+ * (adw-view-switcher-button.c:347, :399-405; adw-inline-view-switcher.c:131-145).
16
+ */
17
+ export declare const VIEW_SWITCHER_FALLBACK_ICON = "image-missing";
18
+ /**
19
+ * `TIMEOUT_EXPAND` — how long a drag has to dwell over a non-active button
20
+ * before it switches to it (adw-view-switcher-button.c:14,
21
+ * adw-inline-view-switcher.c:80). Defined identically in both C files.
22
+ */
23
+ export declare const VIEW_SWITCHER_DRAG_SWITCH_DELAY = 500;
24
+ /** The largest badge `AdwIndicatorBin` prints; anything above collapses to `999+`. */
25
+ export declare const VIEW_SWITCHER_BADGE_LIMIT = 999;
26
+ /** `AdwViewSwitcherPolicy` — which button layout the switcher forces. */
27
+ export type AdwViewSwitcherPolicy = 'narrow' | 'wide';
28
+ /**
29
+ * Every policy, in enum order. Doubles as the style-class list: libadwaita adds
30
+ * the current policy's class and removes the other (adw-view-switcher.c:539-545),
31
+ * so a renderer toggles each entry against the current value rather than
32
+ * hard-coding an add/remove pair.
33
+ */
34
+ export declare const VIEW_SWITCHER_POLICIES: readonly AdwViewSwitcherPolicy[];
35
+ /** `AdwInlineViewSwitcherDisplayMode` — what the inline switcher's toggles show. */
36
+ export type AdwInlineViewSwitcherDisplayMode = 'labels' | 'icons' | 'both';
37
+ /**
38
+ * Every display mode, in enum order — and the toggle-group style classes
39
+ * (adw-inline-view-switcher.c:826-850), same toggle-against-current pattern as
40
+ * {@link VIEW_SWITCHER_POLICIES}.
41
+ */
42
+ export declare const INLINE_VIEW_SWITCHER_DISPLAY_MODES: readonly AdwInlineViewSwitcherDisplayMode[];
43
+ /**
44
+ * Whether `value` is a policy libadwaita would accept.
45
+ *
46
+ * The C setter is guarded by the enum's own type (`g_value_get_enum`), and the
47
+ * browser port instead coerced anything unrecognised to a default — see
48
+ * {@link isInlineViewSwitcherDisplayMode} for why that is not the same thing.
49
+ */
50
+ export declare function isViewSwitcherPolicy(value: unknown): value is AdwViewSwitcherPolicy;
51
+ /**
52
+ * Whether `value` is a display mode libadwaita would accept.
53
+ *
54
+ * `adw_inline_view_switcher_set_display_mode` opens with
55
+ * `g_return_if_fail (mode <= ADW_INLINE_VIEW_SWITCHER_BOTH)`
56
+ * (adw-inline-view-switcher.c:819), which REJECTS the call and leaves the
57
+ * current mode alone. The browser port's `includes(raw) ? raw : 'both'` replaced
58
+ * the current mode with `'both'` instead, so a typo in one attribute silently
59
+ * changed what every toggle displayed.
60
+ */
61
+ export declare function isInlineViewSwitcherDisplayMode(value: unknown): value is AdwInlineViewSwitcherDisplayMode;
62
+ /**
63
+ * The page record every switcher flavour reads — `AdwViewStackPage`'s properties
64
+ * with their C defaults (adw-view-stack.c:373-436).
65
+ *
66
+ * `null` vs `''` is LOAD-BEARING and is why this record exists next to
67
+ * {@link AdwViewStackPageInfo} rather than being replaced by it: the
68
+ * button-visibility rule tests `title != NULL`, and an empty title is not NULL.
69
+ * Wave 1's stack page model resolves an absent title to the page NAME (a
70
+ * deliberate, documented deviation), so a page's "had no title at all" state
71
+ * only survives where the switcher owns its own pages.
72
+ */
73
+ export interface AdwViewSwitcherPage {
74
+ /** Stable id, matching `AdwViewStackPage`'s name. */
75
+ name: string;
76
+ /** `AdwViewStackPage:title` — `null` when the page has none (C default). */
77
+ title: string | null;
78
+ /** `AdwViewStackPage:icon-name` — `null` when the page has none (C default). */
79
+ iconName: string | null;
80
+ /** `AdwViewStackPage:visible` — default `true`. Gates both the button and the toggle. */
81
+ visible: boolean;
82
+ /** `AdwViewStackPage:use-underline` — default `false`. An `_` in the title marks a mnemonic. */
83
+ useUnderline: boolean;
84
+ /** `AdwViewStackPage:badge-number` — default `0`, i.e. no badge. */
85
+ badgeNumber: number;
86
+ /** `AdwViewStackPage:needs-attention` — default `false`, i.e. no dot. */
87
+ needsAttention: boolean;
88
+ }
89
+ /** What a caller has to supply for a page: the name, plus whatever it knows. */
90
+ export interface AdwViewSwitcherPageInit extends Partial<AdwViewSwitcherPage> {
91
+ /** Stable id, matching `AdwViewStackPage`'s name. */
92
+ name: string;
93
+ }
94
+ /**
95
+ * Normalize a partial page into the full record with the C defaults applied, so
96
+ * a renderer that only knows `{ name, title }` gets exactly the same derivations
97
+ * as one that knows badges.
98
+ *
99
+ * `undefined` collapses to the C default; an explicit `null` title or icon name
100
+ * stays `null`. The badge is normalized to a non-negative integer because
101
+ * `badge-number` is a `guint` (adw-view-stack.c:420-423) and every derivation
102
+ * below assumes it.
103
+ */
104
+ export declare function createViewSwitcherPage(init: AdwViewSwitcherPageInit): AdwViewSwitcherPage;
105
+ /**
106
+ * Project a wave-1 stack page descriptor onto a switcher page, for a switcher
107
+ * BOUND to an `Adw.ViewStack` rather than owning its own pages.
108
+ *
109
+ * Two fidelity notes a caller has to know, both consequences of what
110
+ * `AdwViewStackPageInfo` carries: its `title` is already resolved against the
111
+ * page name, so it is never `null` and the button-visibility rule reduces to the
112
+ * `visible` flag; and it carries none of `badge-number`, `needs-attention`,
113
+ * `use-underline`, so a bound switcher derives an empty badge and no
114
+ * description. Only a switcher that owns its pages sees those.
115
+ */
116
+ export declare function viewSwitcherPageFromStackPage(page: AdwViewStackPageInfo): AdwViewSwitcherPage;
117
+ /** {@link viewSwitcherPageFromStackPage} over a whole page list. */
118
+ export declare function viewSwitcherPagesFromStack(pages: readonly AdwViewStackPageInfo[]): AdwViewSwitcherPage[];
119
+ /**
120
+ * `update_button`'s visibility rule (adw-view-switcher.c:178):
121
+ * `visible && (title != NULL || icon_name != NULL)`.
122
+ *
123
+ * The empty string is NOT NULL, so `title: ''` still yields a button — the
124
+ * opposite of what both ports did, which was to keep the button and hide only
125
+ * its label. `undefined` is read as absent, i.e. as C's NULL.
126
+ */
127
+ export declare function isViewSwitcherButtonVisible(page: Pick<AdwViewSwitcherPage, 'visible' | 'title' | 'iconName'>): boolean;
128
+ /**
129
+ * The icon a switcher actually renders: a NULL or EMPTY name becomes
130
+ * `image-missing` (adw-view-switcher-button.c:399-405,
131
+ * adw-inline-view-switcher.c:137-142 — `icon_name && *icon_name` fails on `''`).
132
+ *
133
+ * Never returns `''`, so a renderer has an icon to paint in every mode where the
134
+ * C widget creates a `GtkImage` at all. Both ports instead omitted the icon
135
+ * node, which is why an icon-only toggle for a page without an icon rendered as
136
+ * a blank box.
137
+ */
138
+ export declare function viewSwitcherIconName(iconName: string | null | undefined): string;
139
+ /**
140
+ * The text a switcher paints for a page: `''` for a NULL title, otherwise the
141
+ * title with its mnemonic stripped when `use-underline` is set.
142
+ *
143
+ * `update_button` binds `title` onto the button's label together with
144
+ * `use-underline` (adw-view-switcher.c:170-176), and the template label carries
145
+ * `use-underline` too (adw-view-switcher-button.ui) — so GTK DISPLAYS `_Files`
146
+ * as `Files` with an underlined F. A renderer with no accelerator layer displays
147
+ * the same text; keeping the underscore would render a literal one, which is
148
+ * what the browser port did in the inline switcher's tooltip.
149
+ */
150
+ export declare function viewSwitcherLabel(page: Pick<AdwViewSwitcherPage, 'title' | 'useUnderline'>): string;
151
+ /**
152
+ * `get_badge_label` (adw-indicator-bin.c:58-68): `''` for 0, `999+` above 999,
153
+ * the decimal otherwise. 999 itself prints, because the test is `> 999`.
154
+ */
155
+ export declare function viewSwitcherBadgeLabel(badgeNumber: number): string;
156
+ /**
157
+ * The message catalogue {@link viewSwitcherIndicatorDescription} composes, so the
158
+ * core needs no gettext dependency while the composition ORDER stays pinned.
159
+ *
160
+ * C reads these through `C_("view switcher button badge", …)`; a renderer with a
161
+ * translation layer passes its own catalogue.
162
+ */
163
+ export interface IndicatorDescriptionStrings {
164
+ /** `needs-attention` clause — C's "Attention requested." */
165
+ attentionRequested: string;
166
+ /** Badge clause above the limit — C's "Has a badge: more than 999." */
167
+ badgeOverflow: string;
168
+ /** Badge clause for a printable count — C's "Has a badge: %u." */
169
+ badge: (badgeNumber: number) => string;
170
+ }
171
+ /** The English source strings from adw-indicator-bin.c:77-92. */
172
+ export declare const DEFAULT_INDICATOR_DESCRIPTION_STRINGS: IndicatorDescriptionStrings;
173
+ /**
174
+ * `update_description` (adw-indicator-bin.c:70-113) — the screen-reader
175
+ * description bound onto the switcher button (adw-view-switcher-button.c:98-113)
176
+ * or the inline toggle (adw-inline-view-switcher.c:267).
177
+ *
178
+ * The BADGE clause comes first when both apply: the format string is
179
+ * `"%s %s", badge_description, needs_attention_description` (:96). `''` when
180
+ * neither applies — C stores the empty string there, not NULL, and the button
181
+ * then RESETS the accessible property rather than setting it.
182
+ */
183
+ export declare function viewSwitcherIndicatorDescription(needsAttention: boolean, badgeNumber: number, strings?: IndicatorDescriptionStrings): string;
184
+ /**
185
+ * `update_tooltip` (adw-inline-view-switcher.c:163-192): the empty string in
186
+ * every display mode except `icons`, where it is the title with the mnemonic
187
+ * stripped when `use-underline` is set.
188
+ *
189
+ * Returns PLAIN text — see {@link stripMnemonic} on why the C markup escape does
190
+ * not belong in a port. A NULL title yields `''`: C would hand NULL to
191
+ * `g_markup_escape_text`, which every page libadwaita renders avoids by always
192
+ * having a title.
193
+ */
194
+ export declare function inlineToggleTooltip(page: Pick<AdwViewSwitcherPage, 'title' | 'useUnderline'>, displayMode: AdwInlineViewSwitcherDisplayMode): string;
195
+ /**
196
+ * `update_bar_revealed` (adw-view-switcher-bar.c:104-126): the bar is revealed
197
+ * only when `reveal` is set AND more than one page is VISIBLE.
198
+ *
199
+ * When `reveal` is false the C loop never runs, so the count stays 0 — the two
200
+ * clauses are not independent and a renderer must not reorder them into
201
+ * `visibleCount > 1 || reveal`. Absent from both ports, which is why a bar bound
202
+ * to a one-page stack showed an empty strip libadwaita keeps collapsed.
203
+ *
204
+ * Takes the minimal shape so a caller can pass either
205
+ * {@link AdwViewSwitcherPage}s or wave-1 {@link AdwViewStackPageInfo}s.
206
+ */
207
+ export declare function shouldRevealViewSwitcherBar(reveal: boolean, pages: readonly {
208
+ readonly visible: boolean;
209
+ }[]): boolean;
210
+ /**
211
+ * The button orientation the policy implies — `WIDE` is horizontal, anything
212
+ * else vertical (adw-view-switcher.c:219-220, :534-537). The same ternary is
213
+ * used when a button is created and when the policy changes.
214
+ */
215
+ export declare function viewSwitcherButtonOrientation(policy: AdwViewSwitcherPolicy): 'horizontal' | 'vertical';
216
+ /** The fully-derived per-button view model an `AdwViewSwitcher` renderer paints. */
217
+ export interface ViewSwitcherButtonModel {
218
+ /** Position in the PAGE list — `AdwViewSwitcher` keeps a button per page, so this is also the button index. */
219
+ pageIndex: number;
220
+ /** The page name, for a renderer that addresses pages by name. */
221
+ name: string;
222
+ /** The text to paint — {@link viewSwitcherLabel}, so already mnemonic-stripped. */
223
+ label: string;
224
+ /** The icon to paint — {@link viewSwitcherIconName}, never empty. */
225
+ iconName: string;
226
+ /** Whether the BUTTON is shown at all — {@link isViewSwitcherButtonVisible}. */
227
+ visible: boolean;
228
+ /** Whether this button's page is the selected one. */
229
+ selected: boolean;
230
+ /** Icon/label arrangement — {@link viewSwitcherButtonOrientation}. */
231
+ orientation: 'horizontal' | 'vertical';
232
+ /** Badge text, `''` when there is no badge — {@link viewSwitcherBadgeLabel}. */
233
+ badgeLabel: string;
234
+ /** Whether to paint the needs-attention dot. */
235
+ needsAttention: boolean;
236
+ /** Screen-reader description, `''` when neither badge nor attention applies. */
237
+ description: string;
238
+ }
239
+ /**
240
+ * One model per page for `AdwViewSwitcher`, in PAGE index space.
241
+ *
242
+ * `populate_switcher` adds a button for EVERY page and `update_button` merely
243
+ * hides the ones that fail the visibility rule (adw-view-switcher.c:230-238,
244
+ * :178), so the index space is preserved — unlike the inline switcher, which
245
+ * drops hidden pages entirely. `selected` is the page index; `-1` selects
246
+ * nothing.
247
+ */
248
+ export declare function buildViewSwitcherButtons(pages: readonly AdwViewSwitcherPage[], selected: number, policy: AdwViewSwitcherPolicy, strings?: IndicatorDescriptionStrings): ViewSwitcherButtonModel[];
249
+ /** The fully-derived per-toggle view model an `AdwInlineViewSwitcher` renderer paints. */
250
+ export interface InlineToggleModel {
251
+ /** Position among the TOGGLES — compacted, hidden pages skipped. */
252
+ toggleIndex: number;
253
+ /** Position in the PAGE list — libadwaita's `child-index` (adw-inline-view-switcher.c:346). */
254
+ pageIndex: number;
255
+ /** The page name. */
256
+ name: string;
257
+ /** The text to paint — already mnemonic-stripped. */
258
+ label: string;
259
+ /** The icon to paint, never empty. */
260
+ iconName: string;
261
+ /** Whether this display mode builds an icon at all (`labels` does not). */
262
+ showIcon: boolean;
263
+ /** Whether this display mode builds a label at all (`icons` does not). */
264
+ showLabel: boolean;
265
+ /** Tooltip text, `''` outside `icons` mode — {@link inlineToggleTooltip}. */
266
+ tooltip: string;
267
+ /** Badge text, `''` when there is no badge. */
268
+ badgeLabel: string;
269
+ /** Whether to paint the needs-attention dot. */
270
+ needsAttention: boolean;
271
+ /** Screen-reader description, `''` when neither badge nor attention applies. */
272
+ description: string;
273
+ }
274
+ /**
275
+ * `populate_group`'s filter + order (adw-inline-view-switcher.c:360-392): a page
276
+ * with `visible == FALSE` produces NO toggle.
277
+ *
278
+ * Which is why every model carries BOTH indices — `toggleIndex` is the compacted
279
+ * `0..k-1` position the toggle group knows, `pageIndex` is the position the
280
+ * selection model knows, and libadwaita reconciles them through the
281
+ * `child-index` it stashes on each toggle (:346, :114-129). Neither port
282
+ * filtered, so the two spaces coincided and the reconciliation looked
283
+ * unnecessary.
284
+ *
285
+ * Note this uses the page's `visible` flag ALONE — the title-or-icon rule
286
+ * belongs to `AdwViewSwitcher.update_button` and has no counterpart here, so a
287
+ * page with neither title nor icon still gets an (empty) toggle.
288
+ */
289
+ export declare function buildInlineToggles(pages: readonly AdwViewSwitcherPage[], displayMode: AdwInlineViewSwitcherDisplayMode, strings?: IndicatorDescriptionStrings): InlineToggleModel[];
290
+ /**
291
+ * Page index → toggle index, or {@link VIEW_SWITCHER_NO_SELECTION} when the page
292
+ * is hidden or out of range — `selection_changed_cb`
293
+ * (adw-inline-view-switcher.c:434-453), where `index` stays
294
+ * `GTK_INVALID_LIST_POSITION` unless the visible child's page is itself visible.
295
+ *
296
+ * Non-integers are refused for the same reason `ViewStackState` refuses them:
297
+ * the C position is a `guint`.
298
+ */
299
+ export declare function toggleIndexForPage(pages: readonly AdwViewSwitcherPage[], pageIndex: number): number;
300
+ /**
301
+ * Toggle index → page index, or {@link VIEW_SWITCHER_NO_SELECTION} when there is
302
+ * no such toggle — `notify_active_cb` (adw-inline-view-switcher.c:114-129), which
303
+ * reads the active toggle's `child-index` and selects THAT page position.
304
+ */
305
+ export declare function pageIndexForToggle(pages: readonly AdwViewSwitcherPage[], toggleIndex: number): number;
306
+ /** Opaque handle a {@link ViewSwitcherScheduler} returns for a pending dwell. */
307
+ export type ViewSwitcherTimerHandle = unknown;
308
+ /**
309
+ * The injected timing seam for the drag-hover auto-switch.
310
+ *
311
+ * Deliberately the same SHAPE as `ToastScheduler` in `toast.ts`, so a renderer
312
+ * writes ONE adapter over its platform timer and passes it to both. The core
313
+ * never reaches for a global `setTimeout` — that is what `gjsify.headless: true`
314
+ * machine-checks.
315
+ */
316
+ export interface ViewSwitcherScheduler {
317
+ /** Run `callback` after `ms`; return a handle {@link cancel} understands. */
318
+ schedule(callback: () => void, ms: number): ViewSwitcherTimerHandle;
319
+ /** Cancel a pending {@link schedule}. A stale or unknown handle must be a no-op. */
320
+ cancel(handle: ViewSwitcherTimerHandle): void;
321
+ }
322
+ /** Construction seams for {@link ViewSwitcherDragSwitch}. */
323
+ export interface ViewSwitcherDragSwitchOptions {
324
+ /** The platform timer adapter. */
325
+ scheduler: ViewSwitcherScheduler;
326
+ /** Called with the index that has been dwelt on long enough. */
327
+ onSwitch: (index: number) => void;
328
+ /** Dwell time in ms; defaults to {@link VIEW_SWITCHER_DRAG_SWITCH_DELAY}. */
329
+ delay?: number;
330
+ }
331
+ /**
332
+ * The 500 ms drag-hover auto-switch: hovering a non-active button while dragging
333
+ * switches to it, and leaving before the dwell elapses cancels.
334
+ *
335
+ * Present in BOTH C files and in neither port
336
+ * (adw-view-switcher-button.c:14, :58-63, :79-96; adw-inline-view-switcher.c:80,
337
+ * :194-236). Each button/toggle owns its OWN timer there, so this keeps one
338
+ * pending handle per index rather than a single global one — an enter on a
339
+ * second index does not silently disarm the first.
340
+ */
341
+ export declare class ViewSwitcherDragSwitch {
342
+ private readonly _scheduler;
343
+ private readonly _onSwitch;
344
+ private readonly _delay;
345
+ private readonly _timers;
346
+ constructor(options: ViewSwitcherDragSwitchOptions);
347
+ /**
348
+ * A drag entered the button at `index` while `activeIndex` is selected.
349
+ * Returns whether a dwell was armed.
350
+ *
351
+ * `drag_enter_cb` early-returns when the hovered button is already active
352
+ * (adw-view-switcher-button.c:82-83; the inline twin compares indices at
353
+ * adw-inline-view-switcher.c:219), so hovering the current tab never
354
+ * schedules anything.
355
+ */
356
+ enter(index: number, activeIndex: number): boolean;
357
+ /** The drag left the button at `index` — `drag_leave_cb` removes its source. */
358
+ leave(index: number): void;
359
+ /** Drop every pending dwell — used when the page list is rebuilt under the drag. */
360
+ cancel(): void;
361
+ /** Indices with a dwell still pending, ascending. Lets a test assert on the arming. */
362
+ get pending(): readonly number[];
363
+ }
364
+ /** Payload of a switcher selection change. */
365
+ export interface ViewSwitcherStateChange {
366
+ /** Index of the newly-selected PAGE, `-1` when nothing is selected. */
367
+ selected: number;
368
+ /** Its name, `''` when nothing is selected. */
369
+ name: string;
370
+ /** Its rendered label ({@link viewSwitcherLabel}), `''` when nothing is selected. */
371
+ title: string;
372
+ /**
373
+ * `true` for a user activation or an explicit select, `false` for a model-
374
+ * driven auto-pick (a page list rebuild, a visibility flip). Same tagging
375
+ * convention as `ComboState`/`SpinState`/`ViewStackState`; libadwaita
376
+ * notifies on both paths, so this is for suppressing feedback loops, not for
377
+ * dropping the notification.
378
+ */
379
+ interactive: boolean;
380
+ }
381
+ /** Subscriber for {@link ViewSwitcherState} changes. */
382
+ export type ViewSwitcherStateListener = (change: ViewSwitcherStateChange) => void;
383
+ /** Construction seams for {@link ViewSwitcherState}. */
384
+ export interface ViewSwitcherStateOptions {
385
+ /** Platform timer adapter; without it the drag-hover auto-switch is inert. */
386
+ scheduler?: ViewSwitcherScheduler;
387
+ /** Dwell time in ms; defaults to {@link VIEW_SWITCHER_DRAG_SWITCH_DELAY}. */
388
+ dragSwitchDelay?: number;
389
+ }
390
+ /**
391
+ * The page model + selection of a switcher that OWNS its pages — the browser and
392
+ * NativeScript switchers, which bundle the `AdwViewStack` libadwaita keeps
393
+ * separate.
394
+ *
395
+ * Selection is DELEGATED to {@link ViewStackState}, not re-implemented: the
396
+ * integer/range/already-selected/hidden guards, the by-name lookup, the
397
+ * first-VISIBLE-page auto-pick and the hide-fallback all come from there, which
398
+ * is where their conformance vectors already live. What this class adds is the
399
+ * C-faithful page record (so the button-visibility and badge rules have their
400
+ * inputs) and a name-preserving {@link setPages}, because both renderers rebuild
401
+ * their page list wholesale and libadwaita's selection follows the page OBJECT
402
+ * across such a rebuild (adw-view-stack.c:660-672) rather than the index.
403
+ *
404
+ * Policy and display mode are deliberately NOT here: each is one enum value plus
405
+ * one style class, validated by {@link isViewSwitcherPolicy} /
406
+ * {@link isInlineViewSwitcherDisplayMode} and rendered from
407
+ * {@link VIEW_SWITCHER_POLICIES} / {@link INLINE_VIEW_SWITCHER_DISPLAY_MODES}.
408
+ */
409
+ export declare class ViewSwitcherState {
410
+ private _pages;
411
+ private _pagesView;
412
+ private _stack;
413
+ private readonly _listeners;
414
+ private readonly _drag;
415
+ constructor(options?: ViewSwitcherStateOptions);
416
+ /** Subscribe to selection changes. Returns an unsubscribe function. */
417
+ subscribe(listener: ViewSwitcherStateListener): () => void;
418
+ /** The pages, in declaration order — frozen, so a renderer cannot mutate the model. */
419
+ get pages(): readonly AdwViewSwitcherPage[];
420
+ /**
421
+ * Replace the whole page list, keeping the SELECTED PAGE selected across the
422
+ * rebuild whenever a page of the same name survives.
423
+ *
424
+ * libadwaita's selection is a page pointer compared by identity
425
+ * (`adw_view_stack_pages_is_selected`, adw-view-stack.c:660-672), so an
426
+ * insert before the selected page shifts its index without changing what is
427
+ * shown; a rebuild that dropped the selected page falls through to the
428
+ * first-visible auto-pick. Emits at most ONE change, tagged
429
+ * `interactive: false` — the page set changed, the user did not click.
430
+ */
431
+ setPages(specs: readonly AdwViewSwitcherPageInit[]): void;
432
+ /** Index of the selected page, `-1` when nothing is selected. */
433
+ get selected(): number;
434
+ /** Name of the selected page, `''` when nothing is selected. */
435
+ get selectedName(): string;
436
+ /** The selected page record, or `undefined`. */
437
+ get selectedPage(): AdwViewSwitcherPage | undefined;
438
+ /** Number of pages. */
439
+ get count(): number;
440
+ /**
441
+ * Select by page index. Returns whether the selection changed.
442
+ *
443
+ * Every guard is {@link ViewStackState.setVisibleIndex}'s: a non-integer, a
444
+ * negative, an out-of-range and a hidden page are all silent no-ops — NOT
445
+ * clamped into range, which is what the browser switcher did (`active="-1"`
446
+ * jumped to the first page, `active="99"` to the last) where
447
+ * `adw_view_stack_pages_select_item` simply returns FALSE
448
+ * (adw-view-stack.c:682-684).
449
+ */
450
+ setSelected(index: number, interactive?: boolean): boolean;
451
+ /** Select by page name. Returns whether the selection changed. */
452
+ selectName(name: string | null | undefined, interactive?: boolean): boolean;
453
+ /**
454
+ * Flip a page's `visible` flag. Returns whether the SELECTION moved.
455
+ *
456
+ * Both the switcher's page record and the delegated stack are updated, so the
457
+ * derived buttons and toggles rebuild against the same truth the selection
458
+ * fallback used (`update_child_visible`, adw-view-stack.c:1061-1082).
459
+ */
460
+ setPageVisible(name: string, visible: boolean): boolean;
461
+ /** A drag entered the button/toggle for page `pageIndex`; arms the dwell. */
462
+ dragEnter(pageIndex: number): void;
463
+ /** The drag left page `pageIndex`; cancels its pending dwell. */
464
+ dragLeave(pageIndex: number): void;
465
+ /** Drop every pending dwell (the widget was torn down or the drag ended). */
466
+ cancelDrag(): void;
467
+ /** Page indices with a drag dwell still pending — the observable half of the timer. */
468
+ get pendingDragSwitches(): readonly number[];
469
+ /** Diagnostics the delegated stack recorded (C's `g_warning` texts). */
470
+ get diagnostics(): readonly string[];
471
+ private _subscribeStack;
472
+ private _emit;
473
+ }
474
+ /** Payload of a {@link ViewSwitcherBarState} change. */
475
+ export interface ViewSwitcherBarChange {
476
+ /** The REQUEST — `AdwViewSwitcherBar:reveal`, default `false`. */
477
+ reveal: boolean;
478
+ /** The DERIVED truth — {@link shouldRevealViewSwitcherBar}. */
479
+ revealed: boolean;
480
+ }
481
+ /** Subscriber for {@link ViewSwitcherBarState} changes. */
482
+ export type ViewSwitcherBarListener = (change: ViewSwitcherBarChange) => void;
483
+ /**
484
+ * `AdwViewSwitcherBar`'s reveal state machine: `reveal` is what the layout ASKS
485
+ * for, `revealed` is what the bar actually does.
486
+ *
487
+ * `update_bar_revealed` is re-run from `set_reveal`, from `set_stack` and from
488
+ * the pages' `items-changed` (adw-view-switcher-bar.c:340-343, :383, :277), so
489
+ * the derived value flips both when the flag changes and when the page set does
490
+ * — which is why {@link setPages} exists rather than the count being passed to
491
+ * {@link setReveal}. `reveal` defaults to FALSE (:256-259); the NativeScript bar
492
+ * started life VISIBLE, so a freshly constructed bar covered the screen bottom
493
+ * until someone set `revealed = false`.
494
+ */
495
+ export declare class ViewSwitcherBarState {
496
+ private _reveal;
497
+ private _revealed;
498
+ private _pages;
499
+ private readonly _listeners;
500
+ /** Subscribe to reveal changes. Returns an unsubscribe function. */
501
+ subscribe(listener: ViewSwitcherBarListener): () => void;
502
+ /** Whether the layout asked for the bar — `AdwViewSwitcherBar:reveal`. */
503
+ get reveal(): boolean;
504
+ /** Whether the bar is actually shown — the derived truth. */
505
+ get revealed(): boolean;
506
+ /**
507
+ * Set the request. Returns whether `reveal` itself changed (C returns early
508
+ * before its notify when it did not, adw-view-switcher-bar.c:379-380); the
509
+ * subscriber only fires when the DERIVED value moves.
510
+ */
511
+ setReveal(value: boolean): boolean;
512
+ /**
513
+ * Feed the bound stack's page list. Returns whether `revealed` flipped —
514
+ * the `items-changed` half of the same derivation.
515
+ */
516
+ setPages(pages: readonly {
517
+ readonly visible: boolean;
518
+ }[]): boolean;
519
+ private _refresh;
520
+ }
521
+ export { stripMnemonic };
@@ -0,0 +1,2 @@
1
+ declare const _default: () => Promise<void>;
2
+ export default _default;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@gjsify/adwaita-core",
3
- "version": "0.31.0",
4
- "description": "Headless Adwaita widget behavior (breakpoint condition grammar + apply/unapply state machine, color-scheme observable) shared by the web and NativeScript Adwaita renderers — pure TS, no platform imports",
3
+ "version": "0.32.0",
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",
7
7
  "types": "lib/types/index.d.ts",
@@ -9,6 +9,10 @@
9
9
  ".": {
10
10
  "types": "./lib/types/index.d.ts",
11
11
  "default": "./lib/esm/index.js"
12
+ },
13
+ "./conformance": {
14
+ "types": "./lib/types/conformance/index.d.ts",
15
+ "default": "./lib/esm/conformance/index.js"
12
16
  }
13
17
  },
14
18
  "files": [
@@ -42,8 +46,8 @@
42
46
  "headless"
43
47
  ],
44
48
  "devDependencies": {
45
- "@gjsify/cli": "^0.31.0",
46
- "@gjsify/unit": "^0.31.0",
49
+ "@gjsify/cli": "^0.32.0",
50
+ "@gjsify/unit": "^0.32.0",
47
51
  "@types/node": "^25.9.2",
48
52
  "typescript": "^6.0.3"
49
53
  },