@gjsify/adwaita-web 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.
- package/dist/adwaita-web.css +786 -272
- package/dist/adwaita-web.css.map +1 -1
- package/lib/types/adw-about-dialog.spec.d.ts +1 -0
- package/lib/types/adw-action-rows.spec.d.ts +1 -0
- package/lib/types/adw-avatar.spec.d.ts +1 -0
- package/lib/types/adw-banner.spec.d.ts +1 -0
- package/lib/types/adw-button-content.spec.d.ts +1 -0
- package/lib/types/adw-carousel.spec.d.ts +1 -0
- package/lib/types/adw-checks.spec.d.ts +1 -0
- package/lib/types/adw-header-bar.spec.d.ts +1 -0
- package/lib/types/adw-icon.spec.d.ts +1 -0
- package/lib/types/adw-progress-bar.spec.d.ts +1 -0
- package/lib/types/adw-sidebar.spec.d.ts +1 -0
- package/lib/types/adw-switch.spec.d.ts +1 -0
- package/lib/types/adw-wrap-box.spec.d.ts +1 -0
- package/lib/types/bottom-sheet.spec.d.ts +1 -0
- package/lib/types/breakpoints.d.ts +22 -0
- package/lib/types/breakpoints.spec.d.ts +1 -0
- package/lib/types/chrome.spec.d.ts +1 -0
- package/lib/types/elements/adw-about-dialog.d.ts +47 -8
- package/lib/types/elements/adw-action-row.d.ts +35 -0
- package/lib/types/elements/adw-avatar.d.ts +11 -0
- package/lib/types/elements/adw-bottom-sheet.d.ts +33 -4
- package/lib/types/elements/adw-button-content.d.ts +12 -0
- package/lib/types/elements/adw-button-row.d.ts +10 -1
- package/lib/types/elements/adw-carousel.d.ts +111 -8
- package/lib/types/elements/adw-checks.d.ts +57 -0
- package/lib/types/elements/adw-clamp.d.ts +4 -1
- package/lib/types/elements/adw-data-grid.d.ts +11 -31
- package/lib/types/elements/adw-drop-down.d.ts +17 -20
- package/lib/types/elements/adw-entry-row.d.ts +93 -3
- package/lib/types/elements/adw-expander-row.d.ts +7 -1
- package/lib/types/elements/adw-header-bar.d.ts +15 -0
- package/lib/types/elements/adw-icon.d.ts +25 -0
- package/lib/types/elements/adw-inline-view-switcher.d.ts +37 -11
- package/lib/types/elements/adw-menu-button.d.ts +6 -6
- package/lib/types/elements/adw-navigation-split-view.d.ts +6 -0
- package/lib/types/elements/adw-navigation-view.d.ts +63 -20
- package/lib/types/elements/adw-overlay-split-view.d.ts +38 -0
- package/lib/types/elements/adw-password-entry-row.d.ts +19 -10
- package/lib/types/elements/adw-popover.d.ts +58 -0
- package/lib/types/elements/adw-preferences-dialog.d.ts +57 -2
- package/lib/types/elements/adw-preferences-group.d.ts +31 -0
- package/lib/types/elements/adw-progress-bar.d.ts +38 -0
- package/lib/types/elements/adw-sidebar.d.ts +37 -5
- package/lib/types/elements/adw-split-button.d.ts +53 -7
- package/lib/types/elements/adw-switch-row.d.ts +11 -2
- package/lib/types/elements/adw-switch.d.ts +15 -0
- package/lib/types/elements/adw-tab-view.d.ts +129 -12
- package/lib/types/elements/adw-toolbar-view.d.ts +5 -0
- package/lib/types/elements/adw-view-stack.d.ts +27 -19
- package/lib/types/elements/adw-view-switcher-bar.d.ts +23 -7
- package/lib/types/elements/adw-view-switcher.d.ts +22 -11
- package/lib/types/elements/adw-window-title.d.ts +3 -1
- package/lib/types/elements/view-switcher-dom.d.ts +44 -0
- package/lib/types/entry-rows.spec.d.ts +1 -0
- package/lib/types/index.d.ts +7 -0
- package/lib/types/navigation-view.spec.d.ts +1 -0
- package/lib/types/preferences-search.d.ts +20 -0
- package/lib/types/preferences.spec.d.ts +1 -0
- package/lib/types/split-button.spec.d.ts +1 -0
- package/lib/types/split-views.spec.d.ts +1 -0
- package/lib/types/styles.generated.d.ts +1 -1
- package/lib/types/tab-view.spec.d.ts +1 -0
- package/lib/types/view-stack.spec.d.ts +1 -0
- package/lib/types/view-switcher.spec.d.ts +1 -0
- package/package.json +6 -6
- package/scss/_banner.scss +13 -0
- package/scss/_bottom_sheet.scss +5 -6
- package/scss/_button.scss +3 -26
- package/scss/_button_content.scss +28 -0
- package/scss/_checks.scss +228 -0
- package/scss/_clamp.scss +9 -3
- package/scss/_data_grid.scss +15 -7
- package/scss/_drop_down.scss +12 -55
- package/scss/_expander_row.scss +5 -50
- package/scss/_icon.scss +51 -0
- package/scss/_icons.generated.scss +6 -0
- package/scss/_inline_view_switcher.scss +34 -0
- package/scss/_labels.scss +135 -0
- package/scss/_menu_button.scss +10 -70
- package/scss/_popover.scss +186 -0
- package/scss/_preferences.scss +29 -0
- package/scss/_preferences_dialog.scss +17 -0
- package/scss/_progress_bar.scss +161 -0
- package/scss/_reset.scss +18 -7
- package/scss/_spinner.scss +7 -3
- package/scss/_split_button.scss +6 -50
- package/scss/_switch.scss +90 -0
- package/scss/_switch_row.scss +6 -52
- package/scss/_tab_view.scss +64 -0
- package/scss/_theme.scss +10 -0
- package/scss/_toolbar_view.scss +74 -0
- package/scss/_variables.scss +34 -0
- package/scss/_view_switcher.scss +40 -0
- package/scss/_view_switcher_bar.scss +37 -0
- package/scss/_wrap_box.scss +56 -6
- package/scss/adwaita-skin.scss +23 -0
- package/src/adw-about-dialog.spec.ts +350 -0
- package/src/adw-action-rows.spec.ts +342 -0
- package/src/adw-avatar.spec.ts +139 -0
- package/src/adw-banner.spec.ts +152 -0
- package/src/adw-button-content.spec.ts +183 -0
- package/src/adw-button-row.spec.ts +12 -6
- package/src/adw-carousel.spec.ts +389 -0
- package/src/adw-checks.spec.ts +368 -0
- package/src/adw-drop-down.spec.ts +123 -0
- package/src/adw-header-bar.spec.ts +83 -0
- package/src/adw-icon.spec.ts +167 -0
- package/src/adw-progress-bar.spec.ts +173 -0
- package/src/adw-sidebar.spec.ts +332 -0
- package/src/adw-switch.spec.ts +242 -0
- package/src/adw-tab-view.spec.ts +12 -3
- package/src/adw-view-switcher-bar.spec.ts +61 -13
- package/src/adw-wrap-box.spec.ts +194 -0
- package/src/bottom-sheet.spec.ts +325 -0
- package/src/breakpoints.spec.ts +147 -0
- package/src/breakpoints.ts +67 -0
- package/src/chrome.spec.ts +301 -0
- package/src/elements/adw-about-dialog.ts +223 -163
- package/src/elements/adw-action-row.ts +120 -10
- package/src/elements/adw-avatar.ts +48 -54
- package/src/elements/adw-banner.ts +46 -10
- package/src/elements/adw-bottom-sheet.ts +145 -60
- package/src/elements/adw-button-content.ts +107 -33
- package/src/elements/adw-button-row.ts +61 -37
- package/src/elements/adw-button.ts +5 -7
- package/src/elements/adw-carousel.ts +467 -105
- package/src/elements/adw-checks.ts +299 -0
- package/src/elements/adw-clamp.ts +80 -10
- package/src/elements/adw-combo-row.ts +15 -7
- package/src/elements/adw-data-grid.ts +43 -91
- package/src/elements/adw-drop-down.ts +117 -128
- package/src/elements/adw-entry-row.ts +404 -36
- package/src/elements/adw-expander-row.ts +61 -29
- package/src/elements/adw-header-bar.ts +31 -6
- package/src/elements/adw-icon.ts +148 -0
- package/src/elements/adw-inline-view-switcher.ts +240 -129
- package/src/elements/adw-menu-button.ts +93 -70
- package/src/elements/adw-navigation-split-view.ts +48 -7
- package/src/elements/adw-navigation-view.ts +286 -148
- package/src/elements/adw-overlay-split-view.ts +164 -14
- package/src/elements/adw-password-entry-row.ts +111 -89
- package/src/elements/adw-popover.ts +283 -0
- package/src/elements/adw-preferences-dialog.ts +120 -21
- package/src/elements/adw-preferences-group.ts +128 -22
- package/src/elements/adw-progress-bar.ts +189 -0
- package/src/elements/adw-sidebar.ts +301 -142
- package/src/elements/adw-spin-row.ts +11 -5
- package/src/elements/adw-spinner.ts +23 -8
- package/src/elements/adw-split-button.ts +371 -92
- package/src/elements/adw-status-page.ts +9 -9
- package/src/elements/adw-switch-row.ts +100 -30
- package/src/elements/adw-switch.ts +129 -0
- package/src/elements/adw-tab-view.ts +682 -129
- package/src/elements/adw-toggle-group.ts +5 -7
- package/src/elements/adw-toolbar-view.ts +84 -21
- package/src/elements/adw-view-stack.ts +162 -85
- package/src/elements/adw-view-switcher-bar.ts +163 -81
- package/src/elements/adw-view-switcher.ts +231 -112
- package/src/elements/adw-window-title.ts +44 -11
- package/src/elements/adw-wrap-box.ts +131 -35
- package/src/elements/view-switcher-dom.ts +108 -0
- package/src/entry-rows.spec.ts +391 -0
- package/src/index.ts +23 -0
- package/src/navigation-view.spec.ts +435 -0
- package/src/preferences-search.ts +135 -0
- package/src/preferences.spec.ts +250 -0
- package/src/source-view/adw-source-view.ts +2 -5
- package/src/split-button.spec.ts +470 -0
- package/src/split-views.spec.ts +309 -0
- package/src/styles.generated.ts +1 -1
- package/src/tab-view.spec.ts +451 -0
- package/src/test.browser.mts +49 -0
- package/src/view-stack.spec.ts +272 -0
- package/src/view-switcher.spec.ts +446 -0
|
@@ -0,0 +1,272 @@
|
|
|
1
|
+
// DOM-level conformance tests for <adw-view-stack>, driven by the SAME vectors
|
|
2
|
+
// the core suite and the NativeScript renderer assert against
|
|
3
|
+
// (`@gjsify/adwaita-core/conformance`).
|
|
4
|
+
//
|
|
5
|
+
// The two renderers used to carry independent copies of the selection logic —
|
|
6
|
+
// the same four-clause index guard, the same `findIndex` by name, the same
|
|
7
|
+
// `?? ''` fallbacks — and both had drifted away from libadwaita in the same
|
|
8
|
+
// ways: `visibleChildIndex = 1.5` passed the `Number.isFinite` guard and blanked
|
|
9
|
+
// the entire stack, the per-page `visible` flag did not exist so the auto-pick
|
|
10
|
+
// took the first page ADDED instead of the first VISIBLE one, an empty
|
|
11
|
+
// `visible-child-name` was treated as "no name" by the declarative path but as a
|
|
12
|
+
// legal lookup by the property path, and the auto-pick notified nothing so a
|
|
13
|
+
// bound switcher needed a manual `refresh()`. Nothing failed, because nothing
|
|
14
|
+
// compared them. This suite is that comparison.
|
|
15
|
+
import { describe, expect, it } from '@gjsify/unit';
|
|
16
|
+
|
|
17
|
+
import type { ViewStackVectorChange, ViewStackVectorOp, ViewStackVectorPage } from '@gjsify/adwaita-core/conformance';
|
|
18
|
+
import {
|
|
19
|
+
VIEW_STACK_ICON_NAME_VECTORS,
|
|
20
|
+
VIEW_STACK_PAGE_VECTORS,
|
|
21
|
+
VIEW_STACK_VECTORS,
|
|
22
|
+
} from '@gjsify/adwaita-core/conformance';
|
|
23
|
+
|
|
24
|
+
import type { AdwViewStack } from './elements/adw-view-stack.js';
|
|
25
|
+
|
|
26
|
+
/** A stack mounted from markup, with every `notify::visible-child` recorded. */
|
|
27
|
+
interface MountedStack {
|
|
28
|
+
stack: AdwViewStack;
|
|
29
|
+
host: HTMLElement;
|
|
30
|
+
changes: ViewStackVectorChange[];
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Mount a stack whose pages are DECLARED as markup, driving the attribute path.
|
|
35
|
+
*
|
|
36
|
+
* Attributes are set through `setAttribute` rather than an HTML string on
|
|
37
|
+
* purpose: several vectors hinge on an exact name — the empty string, the NFD
|
|
38
|
+
* spelling of `Übersicht` — which an attribute value in parsed markup is not a
|
|
39
|
+
* reliable carrier for. The change listener is attached BEFORE the element is
|
|
40
|
+
* connected so the auto-pick notification is observable, which is the whole
|
|
41
|
+
* point of the fix that made it fire at all.
|
|
42
|
+
*/
|
|
43
|
+
function mountStack(pages: readonly ViewStackVectorPage[], visibleChildName?: string): MountedStack {
|
|
44
|
+
const host = document.createElement('div');
|
|
45
|
+
document.body.appendChild(host);
|
|
46
|
+
|
|
47
|
+
const stack = document.createElement('adw-view-stack') as AdwViewStack;
|
|
48
|
+
if (visibleChildName !== undefined) stack.setAttribute('visible-child-name', visibleChildName);
|
|
49
|
+
|
|
50
|
+
for (const page of pages) {
|
|
51
|
+
const pageEl = document.createElement('adw-view-stack-page');
|
|
52
|
+
pageEl.setAttribute('name', page.name);
|
|
53
|
+
if (page.title !== undefined) pageEl.setAttribute('title', page.title);
|
|
54
|
+
if (page.icon !== undefined) pageEl.setAttribute('icon-name', page.icon);
|
|
55
|
+
if (page.visible === false) pageEl.setAttribute('hidden', '');
|
|
56
|
+
const body = document.createElement('p');
|
|
57
|
+
body.className = 'page-body';
|
|
58
|
+
body.textContent = page.name;
|
|
59
|
+
pageEl.appendChild(body);
|
|
60
|
+
stack.appendChild(pageEl);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const changes: ViewStackVectorChange[] = [];
|
|
64
|
+
stack.addEventListener('notify::visible-child', (event) => {
|
|
65
|
+
changes.push((event as CustomEvent<ViewStackVectorChange>).detail);
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
host.appendChild(stack);
|
|
69
|
+
return { stack, host, changes };
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/** Apply one vector op through the element's own public surface. */
|
|
73
|
+
function applyOp(stack: AdwViewStack, op: ViewStackVectorOp): void {
|
|
74
|
+
switch (op.kind) {
|
|
75
|
+
case 'selectIndex':
|
|
76
|
+
stack.visibleChildIndex = op.index;
|
|
77
|
+
break;
|
|
78
|
+
case 'selectName':
|
|
79
|
+
stack.visibleChildName = op.name;
|
|
80
|
+
break;
|
|
81
|
+
case 'setPageVisible':
|
|
82
|
+
stack.setPageVisible(op.name, op.visible);
|
|
83
|
+
break;
|
|
84
|
+
case 'removePage':
|
|
85
|
+
stack.removePage(op.name);
|
|
86
|
+
break;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/** Which page wrappers are actually SHOWN — what the user sees, not what the model says. */
|
|
91
|
+
function shownPages(stack: AdwViewStack): boolean[] {
|
|
92
|
+
const wrappers = Array.from(stack.querySelectorAll(':scope > .adw-view-stack-child')) as HTMLElement[];
|
|
93
|
+
return wrappers.map((wrapper) => !wrapper.hidden);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
export const AdwViewStackTest = async () => {
|
|
97
|
+
await describe('adw-view-stack selection (libadwaita conformance vectors)', async () => {
|
|
98
|
+
for (const vector of VIEW_STACK_VECTORS) {
|
|
99
|
+
await it(vector.rule, () => {
|
|
100
|
+
const { stack, host, changes } = mountStack(vector.pages);
|
|
101
|
+
|
|
102
|
+
expect(changes).toStrictEqual([...vector.setupChanges]);
|
|
103
|
+
|
|
104
|
+
changes.length = 0;
|
|
105
|
+
for (const op of vector.ops) applyOp(stack, op);
|
|
106
|
+
|
|
107
|
+
expect(changes).toStrictEqual([...vector.changes]);
|
|
108
|
+
expect(stack.visibleChildIndex).toBe(vector.visibleIndex);
|
|
109
|
+
expect(stack.visibleChildName).toBe(vector.visibleName);
|
|
110
|
+
expect(stack.pages.length).toBe(vector.count);
|
|
111
|
+
expect(stack.pages[stack.visibleChildIndex]?.title ?? '').toBe(vector.visibleTitle);
|
|
112
|
+
|
|
113
|
+
// The DOM must agree with the model: exactly the selected page is
|
|
114
|
+
// shown, and nothing at all when the selection is -1. A stack that
|
|
115
|
+
// stored an unreachable index (the 1.5 bug) showed NOTHING while
|
|
116
|
+
// still reporting a selection.
|
|
117
|
+
const expectedShown = vector.pages.map(() => false).slice(0, vector.count);
|
|
118
|
+
if (vector.visibleIndex >= 0) expectedShown[vector.visibleIndex] = true;
|
|
119
|
+
expect(shownPages(stack)).toStrictEqual(expectedShown);
|
|
120
|
+
expect(stack.visibleChild).toBe(
|
|
121
|
+
vector.visibleIndex >= 0 ? (stack.pages[vector.visibleIndex]?.content ?? null) : null,
|
|
122
|
+
);
|
|
123
|
+
|
|
124
|
+
host.remove();
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
await describe('adw-view-stack page descriptors (libadwaita conformance vectors)', async () => {
|
|
130
|
+
for (const vector of VIEW_STACK_PAGE_VECTORS) {
|
|
131
|
+
await it(vector.rule, () => {
|
|
132
|
+
const { stack, host } = mountStack([vector.page]);
|
|
133
|
+
const page = stack.pages[0]!;
|
|
134
|
+
expect(page.name).toBe(vector.page.name);
|
|
135
|
+
expect(page.title).toBe(vector.title);
|
|
136
|
+
expect(page.icon).toBe(vector.icon);
|
|
137
|
+
expect(page.visible).toBe(vector.visible);
|
|
138
|
+
host.remove();
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
for (const { icon, normalized, rule } of VIEW_STACK_ICON_NAME_VECTORS) {
|
|
143
|
+
// `null`/`undefined` have no attribute spelling — an absent icon-name
|
|
144
|
+
// is the same input and is covered by the page-descriptor rows above.
|
|
145
|
+
if (typeof icon !== 'string') continue;
|
|
146
|
+
await it(`icon-name="${icon}" → ${JSON.stringify(normalized)} — ${rule}`, () => {
|
|
147
|
+
const { stack, host } = mountStack([{ name: 'a', icon }]);
|
|
148
|
+
expect(stack.pages[0]!.icon).toBe(normalized);
|
|
149
|
+
host.remove();
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
await it('adopts the declared markup as the page BODY, dropping the wrapper tag', () => {
|
|
154
|
+
const { stack, host } = mountStack([{ name: 'learn' }, { name: 'code' }]);
|
|
155
|
+
expect(stack.querySelectorAll('adw-view-stack-page').length).toBe(0);
|
|
156
|
+
expect(stack.pages[0]!.content!.querySelector('.page-body')!.textContent).toBe('learn');
|
|
157
|
+
host.remove();
|
|
158
|
+
});
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
await describe('adw-view-stack imperative pages (Adw.ViewStack.add)', async () => {
|
|
162
|
+
await it('keeps pages added BEFORE the stack enters the document', () => {
|
|
163
|
+
// The regression: connectedCallback used to overwrite the page list
|
|
164
|
+
// with whatever <adw-view-stack-page> children it found — none, for
|
|
165
|
+
// imperative use — and then replaceChildren() the subtree away, so
|
|
166
|
+
// this exact order silently destroyed the caller's element.
|
|
167
|
+
// libadwaita has no parse-once phase (adw-view-stack.c:2160-2251).
|
|
168
|
+
const stack = document.createElement('adw-view-stack') as AdwViewStack;
|
|
169
|
+
const content = document.createElement('div');
|
|
170
|
+
content.textContent = 'learn body';
|
|
171
|
+
stack.add(content, 'learn', 'Learn');
|
|
172
|
+
|
|
173
|
+
document.body.appendChild(stack);
|
|
174
|
+
|
|
175
|
+
expect(stack.pages.length).toBe(1);
|
|
176
|
+
expect(stack.visibleChildName).toBe('learn');
|
|
177
|
+
expect(content.isConnected).toBe(true);
|
|
178
|
+
expect(content.hidden).toBe(false);
|
|
179
|
+
stack.remove();
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
await it('notifies for the auto-shown first page, so a bound switcher needs no refresh()', () => {
|
|
183
|
+
const stack = document.createElement('adw-view-stack') as AdwViewStack;
|
|
184
|
+
const changes: ViewStackVectorChange[] = [];
|
|
185
|
+
stack.addEventListener('notify::visible-child', (event) => {
|
|
186
|
+
changes.push((event as CustomEvent<ViewStackVectorChange>).detail);
|
|
187
|
+
});
|
|
188
|
+
document.body.appendChild(stack);
|
|
189
|
+
|
|
190
|
+
stack.add(document.createElement('div'), 'learn', 'Learn');
|
|
191
|
+
stack.add(document.createElement('div'), 'code', 'Code');
|
|
192
|
+
|
|
193
|
+
expect(changes).toStrictEqual([{ index: 0, name: 'learn', title: 'Learn', interactive: false }]);
|
|
194
|
+
stack.remove();
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
await it('detaches the content when a page is removed', () => {
|
|
198
|
+
const stack = document.createElement('adw-view-stack') as AdwViewStack;
|
|
199
|
+
document.body.appendChild(stack);
|
|
200
|
+
const first = document.createElement('div');
|
|
201
|
+
const second = document.createElement('div');
|
|
202
|
+
stack.add(first, 'learn');
|
|
203
|
+
stack.add(second, 'code');
|
|
204
|
+
|
|
205
|
+
expect(stack.removePage('learn')).toBe(true);
|
|
206
|
+
expect(first.isConnected).toBe(false);
|
|
207
|
+
expect(second.isConnected).toBe(true);
|
|
208
|
+
// The removed page WAS the visible one, so nothing is shown now.
|
|
209
|
+
expect(stack.visibleChildIndex).toBe(-1);
|
|
210
|
+
expect(second.hidden).toBe(true);
|
|
211
|
+
stack.remove();
|
|
212
|
+
});
|
|
213
|
+
});
|
|
214
|
+
|
|
215
|
+
await describe('adw-view-stack visible-child-name attribute', async () => {
|
|
216
|
+
await it('selects the declared page instead of the auto-pick', () => {
|
|
217
|
+
const { stack, host } = mountStack([{ name: 'learn' }, { name: 'code' }], 'code');
|
|
218
|
+
expect(stack.visibleChildName).toBe('code');
|
|
219
|
+
expect(shownPages(stack)).toStrictEqual([false, true]);
|
|
220
|
+
host.remove();
|
|
221
|
+
});
|
|
222
|
+
|
|
223
|
+
await it('treats an EMPTY declared name as a legal lookup, not as "no name"', () => {
|
|
224
|
+
// The declarative path used `initialName ? … : -1`, so an explicit
|
|
225
|
+
// empty name fell through to page 0 while the PROPERTY path matched
|
|
226
|
+
// the page named '' — one port, two answers for one input.
|
|
227
|
+
// g_strcmp0("", "") is 0 (adw-view-stack.c:901).
|
|
228
|
+
const { stack, host } = mountStack([{ name: 'a' }, { name: '' }], '');
|
|
229
|
+
expect(stack.visibleChildIndex).toBe(1);
|
|
230
|
+
expect(shownPages(stack)).toStrictEqual([false, true]);
|
|
231
|
+
host.remove();
|
|
232
|
+
});
|
|
233
|
+
|
|
234
|
+
await it('reflects the selection back, including an empty name', () => {
|
|
235
|
+
const { stack, host } = mountStack([{ name: 'a' }, { name: '' }]);
|
|
236
|
+
expect(stack.getAttribute('visible-child-name')).toBe('a');
|
|
237
|
+
stack.visibleChildIndex = 1;
|
|
238
|
+
// The old reflection was guarded by `if (current && …)`, so a stack of
|
|
239
|
+
// nameless pages never reflected its selection at all.
|
|
240
|
+
expect(stack.getAttribute('visible-child-name')).toBe('');
|
|
241
|
+
host.remove();
|
|
242
|
+
});
|
|
243
|
+
|
|
244
|
+
await it('drops the attribute when nothing is selected', () => {
|
|
245
|
+
const { stack, host } = mountStack([{ name: 'a' }]);
|
|
246
|
+
expect(stack.getAttribute('visible-child-name')).toBe('a');
|
|
247
|
+
stack.removePage('a');
|
|
248
|
+
expect(stack.hasAttribute('visible-child-name')).toBe(false);
|
|
249
|
+
host.remove();
|
|
250
|
+
});
|
|
251
|
+
|
|
252
|
+
await it('drives the selection when the attribute changes later', () => {
|
|
253
|
+
const { stack, host, changes } = mountStack([{ name: 'learn' }, { name: 'code' }]);
|
|
254
|
+
changes.length = 0;
|
|
255
|
+
stack.setAttribute('visible-child-name', 'code');
|
|
256
|
+
expect(stack.visibleChildIndex).toBe(1);
|
|
257
|
+
expect(changes).toStrictEqual([{ index: 1, name: 'code', title: 'code', interactive: true }]);
|
|
258
|
+
host.remove();
|
|
259
|
+
});
|
|
260
|
+
|
|
261
|
+
await it('does not bounce the selection back when a duplicate name is reflected', () => {
|
|
262
|
+
// Reflection writes the attribute, which re-enters
|
|
263
|
+
// attributeChangedCallback; with duplicate names a naive re-lookup
|
|
264
|
+
// would resolve to the FIRST match and undo the selection.
|
|
265
|
+
const { stack, host } = mountStack([{ name: 'dup' }, { name: 'dup' }]);
|
|
266
|
+
stack.visibleChildIndex = 1;
|
|
267
|
+
expect(stack.visibleChildIndex).toBe(1);
|
|
268
|
+
expect(stack.getAttribute('visible-child-name')).toBe('dup');
|
|
269
|
+
host.remove();
|
|
270
|
+
});
|
|
271
|
+
});
|
|
272
|
+
};
|