@gjsify/adwaita-web 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/README.md +3 -3
- package/dist/adwaita-web.css +62 -0
- package/dist/adwaita-web.css.map +1 -1
- package/lib/types/elements/adw-combo-row.d.ts +56 -0
- package/lib/types/elements/adw-spin-row.d.ts +11 -1
- package/lib/types/elements/adw-split-button.d.ts +43 -3
- package/lib/types/elements/adw-tab-view.d.ts +23 -5
- package/lib/types/elements/adw-view-stack.d.ts +17 -2
- package/lib/types/elements/gtk-drop-down.d.ts +22 -7
- package/lib/types/elements/gtk-menu-button.d.ts +43 -26
- package/lib/types/elements/gtk-popover.d.ts +14 -1
- package/lib/types/elements/popover-menu.d.ts +99 -0
- package/lib/types/index.d.ts +1 -1
- package/lib/types/shared-trees.spec.d.ts +2 -0
- package/lib/types/styles.generated.d.ts +1 -1
- package/package.json +6 -6
- package/scss/_popover.scss +99 -0
- package/src/adw-avatar.spec.ts +17 -0
- package/src/adw-row-state.spec.ts +335 -17
- package/src/adw-tab-view.spec.ts +8 -5
- package/src/elements/adw-avatar.ts +11 -3
- package/src/elements/adw-combo-row.ts +161 -22
- package/src/elements/adw-spin-row.ts +49 -28
- package/src/elements/adw-split-button.ts +117 -39
- package/src/elements/adw-tab-view.ts +42 -22
- package/src/elements/adw-view-stack.ts +20 -4
- package/src/elements/adw-view-switcher-bar.ts +6 -3
- package/src/elements/gtk-drop-down.ts +109 -66
- package/src/elements/gtk-menu-button.ts +112 -88
- package/src/elements/gtk-popover.ts +17 -2
- package/src/elements/popover-menu.ts +366 -0
- package/src/gtk-drop-down.spec.ts +117 -25
- package/src/gtk-image.spec.ts +3 -3
- package/src/gtk-menu-button.spec.ts +165 -11
- package/src/index.ts +14 -1
- package/src/keyboard-operable.spec.ts +170 -1
- package/src/shared-trees.spec.ts +151 -0
- package/src/split-button.spec.ts +36 -22
- package/src/styles.generated.ts +1 -1
- package/src/tab-view.spec.ts +83 -15
- package/src/test.browser.mts +2 -0
- package/src/view-stack.spec.ts +5 -3
package/src/split-button.spec.ts
CHANGED
|
@@ -13,10 +13,11 @@ import {
|
|
|
13
13
|
POPOVER_SURFACE_VECTORS,
|
|
14
14
|
SPLIT_BUTTON_CONTENT_VECTORS,
|
|
15
15
|
SPLIT_BUTTON_DIRECTION_VECTORS,
|
|
16
|
-
|
|
16
|
+
MENU_NORMALIZE_VECTORS,
|
|
17
17
|
SPLIT_BUTTON_STYLE_CLASS_VECTORS,
|
|
18
18
|
SPLIT_BUTTON_TOOLTIP_VECTORS,
|
|
19
19
|
} from '@gjsify/adwaita-core/conformance';
|
|
20
|
+
import { ADW_MENU_SURFACE_WEB, flattenMenu, menuRefusals } from '@gjsify/adwaita-core';
|
|
20
21
|
import type { SplitButtonProperty } from '@gjsify/adwaita-core';
|
|
21
22
|
import type { AdwSplitButton } from './elements/adw-split-button.js';
|
|
22
23
|
import { fallbackMask, maskOf } from './icon-registry.spec.js';
|
|
@@ -234,11 +235,24 @@ export const AdwSplitButtonTest = async () => {
|
|
|
234
235
|
});
|
|
235
236
|
|
|
236
237
|
await describe('adw-split-button menu', async () => {
|
|
237
|
-
for (const {
|
|
238
|
-
await it(`
|
|
239
|
-
const { el, host } = mount(
|
|
240
|
-
|
|
241
|
-
|
|
238
|
+
for (const { input, model, rule } of MENU_NORMALIZE_VECTORS) {
|
|
239
|
+
await it(`normalises an authored menu — ${rule}`, () => {
|
|
240
|
+
const { el, host } = mount({ label: 'Save' });
|
|
241
|
+
// What THIS surface refuses is core's answer, not a list restated here:
|
|
242
|
+
// a `custom` item names an application widget the browser cannot host,
|
|
243
|
+
// and the setter is where that is said out loud.
|
|
244
|
+
if (menuRefusals(model, ADW_MENU_SURFACE_WEB).length > 0) {
|
|
245
|
+
expect(() => {
|
|
246
|
+
el.menuModel = input;
|
|
247
|
+
}).toThrow('adwaita-web');
|
|
248
|
+
host.remove();
|
|
249
|
+
return;
|
|
250
|
+
}
|
|
251
|
+
el.menuModel = input;
|
|
252
|
+
expect([...el.menuModel]).toStrictEqual([...model]);
|
|
253
|
+
// Every node the model draws is a row: a section is inlined, a submenu
|
|
254
|
+
// is one row of its own.
|
|
255
|
+
expect(el.querySelectorAll('.adw-split-button-menu-item').length).toBe(flattenMenu(model).length);
|
|
242
256
|
host.remove();
|
|
243
257
|
});
|
|
244
258
|
}
|
|
@@ -255,7 +269,7 @@ export const AdwSplitButtonTest = async () => {
|
|
|
255
269
|
});
|
|
256
270
|
|
|
257
271
|
await it('opens and closes on the dropdown half once there is a menu', () => {
|
|
258
|
-
const { el, host } = mount({ menu: '[{"label":"Save as…","action":"app.save-as"}]' });
|
|
272
|
+
const { el, host } = mount({ 'menu-model': '[{"label":"Save as…","action":"app.save-as"}]' });
|
|
259
273
|
expect(el.dropdownEnabled).toBe(true);
|
|
260
274
|
expect(dropdownHalf(el).disabled).toBe(false);
|
|
261
275
|
|
|
@@ -275,25 +289,25 @@ export const AdwSplitButtonTest = async () => {
|
|
|
275
289
|
|
|
276
290
|
await it('dispatches a duplicate label BY POSITION, with its own action', () => {
|
|
277
291
|
const { el, host } = mount({
|
|
278
|
-
menu: '[{"label":"Copy","action":"app.copy"},{"label":"Copy","action":"app.copy-special"}]',
|
|
292
|
+
'menu-model': '[{"label":"Copy","action":"app.copy"},{"label":"Copy","action":"app.copy-special"}]',
|
|
279
293
|
});
|
|
280
|
-
const activated: Array<{ label: string; action?: string;
|
|
294
|
+
const activated: Array<{ label: string; action?: string; id: string; path: number[] }> = [];
|
|
281
295
|
el.addEventListener('menu-activated', (event) => activated.push((event as CustomEvent).detail));
|
|
282
296
|
|
|
283
297
|
dropdownHalf(el).click();
|
|
284
298
|
const items = el.querySelectorAll('.adw-split-button-menu-item');
|
|
285
299
|
(items[1] as HTMLButtonElement).click();
|
|
286
300
|
|
|
287
|
-
expect(activated).toStrictEqual([{ label: 'Copy', action: 'app.copy-special',
|
|
301
|
+
expect(activated).toStrictEqual([{ label: 'Copy', action: 'app.copy-special', id: 'Copy', path: [1] }]);
|
|
288
302
|
expect(el.active).toBe(false);
|
|
289
303
|
host.remove();
|
|
290
304
|
});
|
|
291
305
|
|
|
292
306
|
await it('losing its menu closes an open one', () => {
|
|
293
|
-
const { el, host } = mount({ menu: '[{"label":"Print"}]' });
|
|
307
|
+
const { el, host } = mount({ 'menu-model': '[{"label":"Print"}]' });
|
|
294
308
|
dropdownHalf(el).click();
|
|
295
309
|
expect(el.active).toBe(true);
|
|
296
|
-
el.setAttribute('menu', '[]');
|
|
310
|
+
el.setAttribute('menu-model', '[]');
|
|
297
311
|
expect(el.active).toBe(false);
|
|
298
312
|
expect(el.dropdownEnabled).toBe(false);
|
|
299
313
|
host.remove();
|
|
@@ -316,7 +330,7 @@ export const AdwSplitButtonTest = async () => {
|
|
|
316
330
|
});
|
|
317
331
|
|
|
318
332
|
await it('marks the root checked while the menu is open (the update_state fold)', () => {
|
|
319
|
-
const { el, host } = mount({ menu: '[{"label":"Print"}]' });
|
|
333
|
+
const { el, host } = mount({ 'menu-model': '[{"label":"Print"}]' });
|
|
320
334
|
expect(el.classList.contains('checked')).toBe(false);
|
|
321
335
|
dropdownHalf(el).click();
|
|
322
336
|
expect(el.classList.contains('checked')).toBe(true);
|
|
@@ -331,7 +345,7 @@ export const AdwSplitButtonTest = async () => {
|
|
|
331
345
|
// from `<gtk-popover>`, and these cases prove the lift was a lift, not a move.
|
|
332
346
|
await describe('adw-split-button menu keyboard (gained with <gtk-popover>)', async () => {
|
|
333
347
|
await it('Escape dismisses the menu and returns focus to the dropdown half', () => {
|
|
334
|
-
const { el, host } = mount({ menu: '[{"label":"Print"},{"label":"Export"}]' });
|
|
348
|
+
const { el, host } = mount({ 'menu-model': '[{"label":"Print"},{"label":"Export"}]' });
|
|
335
349
|
dropdownHalf(el).click();
|
|
336
350
|
expect(el.active).toBe(true);
|
|
337
351
|
|
|
@@ -346,7 +360,7 @@ export const AdwSplitButtonTest = async () => {
|
|
|
346
360
|
});
|
|
347
361
|
|
|
348
362
|
await it('Escape reaches notify::active, so the dismissal is a real state change', () => {
|
|
349
|
-
const { el, host } = mount({ menu: '[{"label":"Print"}]' });
|
|
363
|
+
const { el, host } = mount({ 'menu-model': '[{"label":"Print"}]' });
|
|
350
364
|
const seen: boolean[] = [];
|
|
351
365
|
el.addEventListener('notify::active', (event) => seen.push((event as CustomEvent).detail.active));
|
|
352
366
|
|
|
@@ -358,7 +372,7 @@ export const AdwSplitButtonTest = async () => {
|
|
|
358
372
|
});
|
|
359
373
|
|
|
360
374
|
await it('the arrow keys walk the menu items and wrap, from the row focused on open', () => {
|
|
361
|
-
const { el, host } = mount({ menu: '[{"label":"Print"},{"label":"Export"},{"label":"Share"}]' });
|
|
375
|
+
const { el, host } = mount({ 'menu-model': '[{"label":"Print"},{"label":"Export"},{"label":"Share"}]' });
|
|
362
376
|
dropdownHalf(el).click();
|
|
363
377
|
|
|
364
378
|
// Queried AFTER opening on purpose: `_renderMenu` runs on every state change
|
|
@@ -391,9 +405,9 @@ export const AdwSplitButtonTest = async () => {
|
|
|
391
405
|
});
|
|
392
406
|
|
|
393
407
|
await it('Enter on a focused row activates it BY POSITION, exactly once', () => {
|
|
394
|
-
const { el, host } = mount({ menu: '[{"label":"Copy"},{"label":"Copy"}]' });
|
|
395
|
-
const seen: number[] = [];
|
|
396
|
-
el.addEventListener('menu-activated', (event) => seen.push((event as CustomEvent).detail.
|
|
408
|
+
const { el, host } = mount({ 'menu-model': '[{"label":"Copy"},{"label":"Copy"}]' });
|
|
409
|
+
const seen: number[][] = [];
|
|
410
|
+
el.addEventListener('menu-activated', (event) => seen.push((event as CustomEvent).detail.path));
|
|
397
411
|
|
|
398
412
|
dropdownHalf(el).click();
|
|
399
413
|
const menu = el.querySelector('gtk-popover') as HTMLElement;
|
|
@@ -403,7 +417,7 @@ export const AdwSplitButtonTest = async () => {
|
|
|
403
417
|
// Two entries share a label, so only position tells them apart; and
|
|
404
418
|
// `preventDefault()` before the synthetic click keeps a focused <button> from
|
|
405
419
|
// ALSO activating natively and firing twice.
|
|
406
|
-
expect(seen).toStrictEqual([1]);
|
|
420
|
+
expect(seen).toStrictEqual([[1]]);
|
|
407
421
|
host.remove();
|
|
408
422
|
});
|
|
409
423
|
});
|
|
@@ -423,7 +437,7 @@ export const AdwSplitButtonTest = async () => {
|
|
|
423
437
|
});
|
|
424
438
|
|
|
425
439
|
await it(`draws a ${menuVector?.borderRadius}px surface with ${menuVector?.padding}px padding and a THREE-layer shadow`, () => {
|
|
426
|
-
const { el, host } = mount({ menu: '[{"label":"Print"}]' });
|
|
440
|
+
const { el, host } = mount({ 'menu-model': '[{"label":"Print"}]' });
|
|
427
441
|
dropdownHalf(el).click();
|
|
428
442
|
const surface = el.querySelector('gtk-popover') as HTMLElement;
|
|
429
443
|
const style = getComputedStyle(surface);
|
|
@@ -445,7 +459,7 @@ export const AdwSplitButtonTest = async () => {
|
|
|
445
459
|
});
|
|
446
460
|
|
|
447
461
|
await it(`draws menu rows at the ${itemVector?.borderRadius}px modelbutton radius`, () => {
|
|
448
|
-
const { el, host } = mount({ menu: '[{"label":"Print"}]' });
|
|
462
|
+
const { el, host } = mount({ 'menu-model': '[{"label":"Print"}]' });
|
|
449
463
|
dropdownHalf(el).click();
|
|
450
464
|
const row = el.querySelector('.adw-split-button-menu-item') as HTMLElement;
|
|
451
465
|
const style = getComputedStyle(row);
|