@gjsify/adwaita-web 0.36.0 → 0.37.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 (146) hide show
  1. package/dist/adwaita-web.css +433 -33
  2. package/dist/adwaita-web.css.map +1 -1
  3. package/lib/types/adw-shortcut-label.spec.d.ts +2 -0
  4. package/lib/types/breakpoints.d.ts +10 -12
  5. package/lib/types/elements/adw-about-dialog.d.ts +19 -36
  6. package/lib/types/elements/adw-action-row.d.ts +9 -12
  7. package/lib/types/elements/adw-alert-dialog.d.ts +0 -12
  8. package/lib/types/elements/adw-avatar.d.ts +1 -0
  9. package/lib/types/elements/adw-bottom-sheet.d.ts +7 -12
  10. package/lib/types/elements/adw-button-content.d.ts +3 -4
  11. package/lib/types/elements/adw-button-row.d.ts +1 -1
  12. package/lib/types/elements/adw-carousel.d.ts +28 -49
  13. package/lib/types/elements/adw-checks.d.ts +2 -8
  14. package/lib/types/elements/adw-combo-row.d.ts +6 -6
  15. package/lib/types/elements/adw-data-grid.d.ts +5 -10
  16. package/lib/types/elements/adw-drop-down.d.ts +3 -11
  17. package/lib/types/elements/adw-entry-row.d.ts +20 -23
  18. package/lib/types/elements/adw-icon.d.ts +2 -4
  19. package/lib/types/elements/adw-inline-view-switcher.d.ts +18 -31
  20. package/lib/types/elements/adw-navigation-split-view.d.ts +7 -12
  21. package/lib/types/elements/adw-navigation-view.d.ts +2 -10
  22. package/lib/types/elements/adw-overlay-split-view.d.ts +28 -52
  23. package/lib/types/elements/adw-password-entry-row.d.ts +4 -5
  24. package/lib/types/elements/adw-popover.d.ts +2 -7
  25. package/lib/types/elements/adw-preferences-dialog.d.ts +21 -34
  26. package/lib/types/elements/adw-preferences-group.d.ts +12 -14
  27. package/lib/types/elements/adw-progress-bar.d.ts +3 -4
  28. package/lib/types/elements/adw-shortcut-label.d.ts +20 -0
  29. package/lib/types/elements/adw-sidebar.d.ts +5 -10
  30. package/lib/types/elements/adw-spinner.d.ts +3 -5
  31. package/lib/types/elements/adw-split-button.d.ts +6 -16
  32. package/lib/types/elements/adw-switch-row.d.ts +3 -3
  33. package/lib/types/elements/adw-tab-view.d.ts +16 -26
  34. package/lib/types/elements/adw-toast-overlay.d.ts +8 -13
  35. package/lib/types/elements/adw-view-stack.d.ts +7 -17
  36. package/lib/types/elements/adw-view-switcher-bar.d.ts +4 -8
  37. package/lib/types/elements/adw-view-switcher.d.ts +18 -38
  38. package/lib/types/elements/adw-wrap-box.d.ts +7 -17
  39. package/lib/types/elements/view-switcher-dom.d.ts +10 -13
  40. package/lib/types/index.d.ts +1 -0
  41. package/lib/types/source-view/hex.d.ts +7 -13
  42. package/lib/types/style-classes.spec.d.ts +11 -0
  43. package/lib/types/styles.generated.d.ts +1 -1
  44. package/package.json +6 -6
  45. package/scss/_about_dialog.scss +3 -2
  46. package/scss/_action_row.scss +33 -0
  47. package/scss/_avatar.scss +12 -0
  48. package/scss/_button.scss +44 -22
  49. package/scss/_card.scss +11 -8
  50. package/scss/_checks.scss +2 -4
  51. package/scss/_dialog.scss +3 -2
  52. package/scss/_headerbar.scss +23 -0
  53. package/scss/_popover.scss +8 -4
  54. package/scss/_preferences.scss +7 -7
  55. package/scss/_progress_bar.scss +9 -6
  56. package/scss/_reset.scss +1 -1
  57. package/scss/_shortcut_label.scss +80 -0
  58. package/scss/_sidebar.scss +57 -0
  59. package/scss/_status_page.scss +20 -0
  60. package/scss/_style_classes.scss +407 -0
  61. package/scss/_switch.scss +4 -3
  62. package/scss/_variables.scss +25 -0
  63. package/scss/adwaita-skin.scss +12 -0
  64. package/src/adw-about-dialog.spec.ts +34 -49
  65. package/src/adw-action-rows.spec.ts +25 -33
  66. package/src/adw-avatar.spec.ts +51 -20
  67. package/src/adw-banner.spec.ts +5 -8
  68. package/src/adw-button-content.spec.ts +9 -12
  69. package/src/adw-button-row.spec.ts +2 -4
  70. package/src/adw-carousel.spec.ts +40 -53
  71. package/src/adw-checks.spec.ts +36 -47
  72. package/src/adw-drop-down.spec.ts +25 -32
  73. package/src/adw-header-bar.spec.ts +5 -7
  74. package/src/adw-icon.spec.ts +23 -32
  75. package/src/adw-progress-bar.spec.ts +10 -12
  76. package/src/adw-row-state.spec.ts +9 -10
  77. package/src/adw-shortcut-label.spec.ts +112 -0
  78. package/src/adw-sidebar.spec.ts +17 -24
  79. package/src/adw-switch.spec.ts +11 -17
  80. package/src/adw-tab-view.spec.ts +7 -10
  81. package/src/adw-toast-overlay.spec.ts +7 -11
  82. package/src/adw-view-switcher-bar.spec.ts +10 -14
  83. package/src/adw-wrap-box.spec.ts +25 -36
  84. package/src/bottom-sheet.spec.ts +30 -36
  85. package/src/breakpoints.ts +15 -18
  86. package/src/chrome.spec.ts +13 -21
  87. package/src/elements/adw-about-dialog.ts +71 -114
  88. package/src/elements/adw-action-row.ts +22 -37
  89. package/src/elements/adw-alert-dialog.ts +25 -50
  90. package/src/elements/adw-avatar.ts +40 -15
  91. package/src/elements/adw-banner.ts +14 -18
  92. package/src/elements/adw-bottom-sheet.ts +31 -52
  93. package/src/elements/adw-button-content.ts +30 -37
  94. package/src/elements/adw-button-row.ts +14 -24
  95. package/src/elements/adw-carousel.ts +87 -148
  96. package/src/elements/adw-checks.ts +43 -56
  97. package/src/elements/adw-clamp.ts +8 -9
  98. package/src/elements/adw-combo-row.ts +17 -25
  99. package/src/elements/adw-data-grid.ts +26 -38
  100. package/src/elements/adw-dialog.ts +25 -56
  101. package/src/elements/adw-drop-down.ts +31 -51
  102. package/src/elements/adw-entry-row.ts +39 -46
  103. package/src/elements/adw-expander-row.ts +30 -53
  104. package/src/elements/adw-icon.ts +30 -53
  105. package/src/elements/adw-inline-view-switcher.ts +38 -67
  106. package/src/elements/adw-menu-button.ts +28 -58
  107. package/src/elements/adw-navigation-split-view.ts +35 -47
  108. package/src/elements/adw-navigation-view.ts +12 -28
  109. package/src/elements/adw-overlay-split-view.ts +100 -175
  110. package/src/elements/adw-password-entry-row.ts +18 -28
  111. package/src/elements/adw-popover.ts +28 -44
  112. package/src/elements/adw-preferences-dialog.ts +41 -66
  113. package/src/elements/adw-preferences-group.ts +33 -46
  114. package/src/elements/adw-progress-bar.ts +27 -47
  115. package/src/elements/adw-shortcut-label.ts +138 -0
  116. package/src/elements/adw-sidebar.ts +31 -39
  117. package/src/elements/adw-spin-row.ts +7 -14
  118. package/src/elements/adw-spinner.ts +31 -43
  119. package/src/elements/adw-split-button.ts +45 -75
  120. package/src/elements/adw-switch-row.ts +29 -46
  121. package/src/elements/adw-switch.ts +28 -47
  122. package/src/elements/adw-tab-view.ts +62 -103
  123. package/src/elements/adw-toast-overlay.ts +28 -35
  124. package/src/elements/adw-toggle-group.ts +9 -16
  125. package/src/elements/adw-view-stack.ts +32 -51
  126. package/src/elements/adw-view-switcher-bar.ts +26 -50
  127. package/src/elements/adw-view-switcher.ts +60 -110
  128. package/src/elements/adw-window-title.ts +4 -4
  129. package/src/elements/adw-wrap-box.ts +33 -59
  130. package/src/elements/view-switcher-dom.ts +15 -22
  131. package/src/entry-rows.spec.ts +18 -24
  132. package/src/index.ts +13 -15
  133. package/src/navigation-view.spec.ts +7 -10
  134. package/src/preferences-search.ts +11 -15
  135. package/src/preferences.spec.ts +13 -15
  136. package/src/source-view/adw-source-view.ts +6 -19
  137. package/src/source-view/hex.ts +7 -13
  138. package/src/split-button.spec.ts +32 -44
  139. package/src/split-views.spec.ts +83 -149
  140. package/src/style-classes.spec.ts +181 -0
  141. package/src/style-isolation.spec.ts +3 -6
  142. package/src/styles.generated.ts +1 -1
  143. package/src/tab-view.spec.ts +26 -35
  144. package/src/test.browser.mts +4 -0
  145. package/src/view-stack.spec.ts +23 -34
  146. package/src/view-switcher.spec.ts +56 -84
@@ -1,15 +1,8 @@
1
- // The two split views against the shared conformance vectors.
1
+ // The two split views against the shared conformance vectors: the attributes reach
2
+ // `OverlaySplitViewState`, and what the state derives reaches the DOM.
2
3
  //
3
- // The element now delegates the property interplay to
4
- // `OverlaySplitViewState`, so this suite asserts the half a DOM renderer owns:
5
- // that the attributes reach the state, and that what the state derives actually
6
- // reaches the DOM.
7
- //
8
- // The rule it pins down first is the one the element got wrong for its whole
9
- // life: `Adw.OverlaySplitView:show-sidebar` defaults to TRUE
10
- // (adw-overlay-split-view.c:974-976), and an HTML boolean attribute is
11
- // presence-only, which can only express a FALSE default. Bare markup showed no
12
- // sidebar where GTK shows one.
4
+ // `Adw.OverlaySplitView:show-sidebar` defaults to TRUE, but an HTML boolean attribute
5
+ // is presence-only and can only express a FALSE default — hence `show-sidebar="false"`.
13
6
  import { describe, expect, it } from '@gjsify/unit';
14
7
 
15
8
  import type { OverlaySplitViewState } from '@gjsify/adwaita-core';
@@ -37,7 +30,6 @@ function settle(): Promise<void> {
37
30
  });
38
31
  }
39
32
 
40
- /** Mount a split view from markup and return it. */
41
33
  function mount(attrs = ''): { view: AdwOverlaySplitView; host: HTMLElement } {
42
34
  const host = document.createElement('div');
43
35
  document.body.appendChild(host);
@@ -58,18 +50,13 @@ interface DomSnapshot {
58
50
  }
59
51
 
60
52
  /**
61
- * Read the whole derived state back OUT of the DOM.
62
- *
63
- * Asserting only `showSidebar`/`collapsed` is what let `pin-sidebar` fall out of
64
- * `observedAttributes` unnoticed: both of those still agreed, because the vectors
65
- * only ever set the attribute in markup, where `connectedCallback` reads it
66
- * directly. Every field the element publishes is checked here instead.
53
+ * Read the whole derived state back OUT of the DOM — EVERY field the element publishes,
54
+ * because `showSidebar`/`collapsed` agreed while `pin-sidebar` had fallen out of
55
+ * `observedAttributes`.
67
56
  *
68
- * `showProgress` is the one snapshot field with no DOM surface — the element
69
- * paints the reveal from the `collapsed`/`show-sidebar` classes rather than a
70
- * numeric progress (a continuous reveal is not implemented). `shieldVisible` is
71
- * derived from it (`collapsed && showProgress > 0`), so a progress bug still
72
- * shows up here.
57
+ * `showProgress` has no DOM surface (the reveal is painted from the
58
+ * `collapsed`/`show-sidebar` classes, not a numeric progress), but `shieldVisible` is
59
+ * derived from it, so a progress bug still shows here.
73
60
  */
74
61
  function domSnapshot(view: AdwOverlaySplitView): DomSnapshot {
75
62
  const backdrop = view.querySelector('.adw-osv-backdrop') as HTMLElement;
@@ -136,8 +123,7 @@ export const AdwSplitViewsTest = async () => {
136
123
  await describe('adw-overlay-split-view collapse (shared conformance vectors)', async () => {
137
124
  for (const vector of OVERLAY_COLLAPSE_VECTORS) {
138
125
  const { initial, before, setCollapsed, after, rule } = vector;
139
- // Only the rows a DOM element can express: `pinSidebar` and the
140
- // starting `collapsed`/`showSidebar` all have attributes.
126
+ // Only the vector fields a DOM element can express as attributes.
141
127
  const attrs = [
142
128
  initial.collapsed ? 'collapsed' : '',
143
129
  initial.showSidebar === false ? 'show-sidebar="false"' : '',
@@ -161,11 +147,9 @@ export const AdwSplitViewsTest = async () => {
161
147
  }
162
148
 
163
149
  await it('honours pin-sidebar set AFTER construction, not only in markup', () => {
164
- // The regression the vector loop above cannot see: it only ever puts
165
- // `pin-sidebar` in the markup, which `connectedCallback` reads directly.
166
- // With the attribute missing from `observedAttributes` the
167
- // `_readAttribute` branch was dead, so pinning a live element silently
168
- // did nothing and the next collapse still hid the sidebar.
150
+ // The vector loop only puts `pin-sidebar` in markup, which
151
+ // `connectedCallback` reads directly: with the attribute missing from
152
+ // `observedAttributes`, pinning a live element was a silent no-op.
169
153
  const { view, host } = mount();
170
154
  view.setAttribute('pin-sidebar', '');
171
155
 
@@ -200,16 +184,14 @@ export const AdwSplitViewsTest = async () => {
200
184
  await it('hides the shield unless collapsed AND revealed', () => {
201
185
  const { view, host } = mount();
202
186
  const backdrop = view.querySelector('.adw-osv-backdrop') as HTMLElement;
203
- // Expanded: no shield, whatever the sidebar is doing.
204
187
  expect(backdrop.hidden).toBe(true);
205
188
  host.remove();
206
189
  });
207
190
 
208
191
  await it('marks the off-screen pane aria-hidden once collapsing hides it', () => {
209
- // Collapsing is a TRANSITION: it auto-hides an unpinned sidebar, so
210
- // content becomes the reachable pane. Constructing collapsed does
211
- // NOT — `<adw-overlay-split-view collapsed>` keeps the sidebar shown,
212
- // the same as building the GTK widget with both properties set.
192
+ // Collapsing is a TRANSITION and auto-hides an unpinned sidebar, so content
193
+ // becomes the reachable pane; constructing collapsed does NOT, matching a GTK
194
+ // widget built with both properties set.
213
195
  const { view, host } = mount();
214
196
  expect((view.querySelector('.adw-osv-sidebar') as HTMLElement).getAttribute('aria-hidden')).toBe('false');
215
197
 
@@ -234,10 +216,9 @@ export const AdwSplitViewsTest = async () => {
234
216
  });
235
217
  await describe('adw-overlay-split-view sidebar width (Adw.OverlaySplitView properties)', async () => {
236
218
  await it('defaults to the WIDGET values, not to an app preference', () => {
237
- // 180 / 280 / 0.25 — adw-overlay-split-view.c:1036-1075. These read
238
- // 280 / 400 / 0.30 before, which are the values the three.js and
239
- // canvas2d showcases set explicitly in their .blp, so the storybook's
240
- // GTK and browser sides showed different sidebars.
219
+ // 180 / 280 / 0.25 per `adw-overlay-split-view.c`. The showcase values
220
+ // (280 / 400 / 0.30, set explicitly in their .blp) had leaked in as the
221
+ // defaults, so storybook's GTK and browser sides diverged.
241
222
  const { view, host } = mount();
242
223
  expect(view.minSidebarWidth).toBe(180);
243
224
  expect(view.maxSidebarWidth).toBe(280);
@@ -248,17 +229,16 @@ export const AdwSplitViewsTest = async () => {
248
229
  await it('writes the normalised bounds, not the raw attributes', () => {
249
230
  const { view, host } = mount('min-sidebar-width="300" max-sidebar-width="200"');
250
231
  const sidebar = view.querySelector('.adw-osv-sidebar') as HTMLElement;
251
- // libadwaita never lets max fall below min, so both land at 300.
252
- // CSS on its own resolves the conflict the other way (min-width wins
253
- // over max-width), which would render a different widget.
232
+ // libadwaita never lets max fall below min, so both land at 300 — CSS alone
233
+ // resolves it the other way (min-width beats max-width).
254
234
  expect(sidebar.style.minWidth).toBe('300px');
255
235
  expect(sidebar.style.maxWidth).toBe('300px');
256
236
  host.remove();
257
237
  });
258
238
 
259
239
  for (const vector of SIDEBAR_BOUNDS_VECTORS) {
260
- // Only the rows expressible in CSS pixels: the element has no dpi or
261
- // length-unit attribute, so `sp`-at-another-dpi rows stay in core.
240
+ // Only rows expressible in CSS pixels: the element has no dpi or length-unit
241
+ // attribute, so `sp`-at-another-dpi rows stay in core.
262
242
  if (vector.spec.sidebarWidthUnit !== undefined || vector.spec.dpi !== undefined) continue;
263
243
  if (vector.sidebarChildMin !== 0 || !vector.ceil) continue;
264
244
 
@@ -293,8 +273,6 @@ export const AdwSplitViewsTest = async () => {
293
273
  };
294
274
 
295
275
  await it('bounds the sidebar even with no attributes', () => {
296
- // An absent attribute used to mean "no bound at all"; the widget
297
- // always has 180 / 280.
298
276
  const { view, host } = mountNav();
299
277
  const sidebar = view.querySelector('.adw-nsv-sidebar') as HTMLElement;
300
278
  expect(sidebar.style.minWidth).toBe('180px');
@@ -351,7 +329,7 @@ export const AdwSplitViewsTest = async () => {
351
329
  offsets.add(sidebar.style.marginLeft || sidebar.style.left || '');
352
330
  }
353
331
  // Two end states would give at most two distinct offsets; the five
354
- // OVERLAY_SWIPE_* tables need every value in between to mean something.
332
+ // OVERLAY_SWIPE_* tables need every value between them to mean something.
355
333
  expect(offsets.size).toBeGreaterThan(2);
356
334
  host.remove();
357
335
  });
@@ -372,10 +350,9 @@ export const AdwSplitViewsTest = async () => {
372
350
  }
373
351
 
374
352
  await it('grabs only where the swipe area is — the ADW_SWIPE_BORDER strip when closed', async () => {
375
- // The row this probes: closed, start edge, LTR — the grabbable strip
376
- // is `ADW_SWIPE_BORDER` wide and nothing outside it starts a gesture.
377
- // What a DOM renderer owns is that second half, which no unit test of
378
- // `resolveSwipeArea` can show.
353
+ // Closed, start edge, LTR: the grabbable strip is `ADW_SWIPE_BORDER` wide and
354
+ // nothing outside it starts a gesture — the second half is the DOM renderer's,
355
+ // which no unit test of `resolveSwipeArea` can show.
379
356
  const closedAtStart = OVERLAY_SWIPE_AREA_VECTORS.find(
380
357
  (vector) =>
381
358
  vector.isDrag &&
@@ -411,12 +388,10 @@ export const AdwSplitViewsTest = async () => {
411
388
  }),
412
389
  );
413
390
 
414
- // Just OUTSIDE the strip, so nothing begins.
415
391
  down(strip + 4);
416
392
  move(strip + 120);
417
393
  expect(state.swipeActive).toBe(false);
418
394
 
419
- // Just inside it: the gesture takes over and the progress follows.
420
395
  down(Math.max(strip - 4, 0));
421
396
  move(strip + 120);
422
397
  expect(state.swipeActive).toBe(true);
@@ -429,7 +404,6 @@ export const AdwSplitViewsTest = async () => {
429
404
  const { view, host } = mountSizedView(800, 'collapsed');
430
405
  const state = stateOf(view);
431
406
  await settle();
432
- // Seed `show-sidebar` without animating, then take the gesture.
433
407
  state.setShowSidebar(vector.showSidebar, { animate: false });
434
408
  state.beginSwipe();
435
409
  const plan = state.endSwipe(vector.to);
@@ -472,15 +446,12 @@ export const AdwSplitViewsTest = async () => {
472
446
  });
473
447
 
474
448
  await it('Escape closes a collapsed revealed sidebar', async () => {
475
- // `escape_shortcut_cb` (adw-overlay-split-view.c:705-716) was absent
476
- // from both ports, which made `OverlaySplitViewState.escape()` dead
477
- // code.
449
+ // `escape_shortcut_cb`.
478
450
  const { view, host } = mountSizedView(800, 'collapsed');
479
451
  await settle();
480
- // Parse-time attributes are CONSTRUCTION options, not sequential
481
- // setters, so `collapsed` in the markup does not fire the auto-hide
482
- // — the element documents that and OVERLAY_COLLAPSE_VECTORS covers
483
- // the setter path. So the sidebar is already revealed here.
452
+ // Parse-time attributes are CONSTRUCTION options, not sequential setters, so
453
+ // markup `collapsed` never fires the auto-hide (the setter path is
454
+ // OVERLAY_COLLAPSE_VECTORS) and the sidebar is revealed here.
484
455
  expect(view.showSidebar).toBe(true);
485
456
 
486
457
  const event = new KeyboardEvent('keydown', { key: 'Escape', bubbles: true, cancelable: true });
@@ -498,20 +469,18 @@ export const AdwSplitViewsTest = async () => {
498
469
 
499
470
  const event = new KeyboardEvent('keydown', { key: 'Escape', bubbles: true, cancelable: true });
500
471
  view.dispatchEvent(event);
501
- // A docked sidebar is not something Escape closes, however revealed
502
- // it is — the gate is `!collapsed`, checked before the progress.
472
+ // Escape never closes a DOCKED sidebar, however revealed: the gate is
473
+ // `!collapsed`, checked before the progress.
503
474
  expect(event.defaultPrevented).toBe(false);
504
475
  expect(view.showSidebar).toBe(true);
505
476
  host.remove();
506
477
  });
507
478
 
508
479
  await it('is gated on the PROGRESS, so it still consumes mid-close', async () => {
509
- // Worth pinning because it looks like a bug: `escape_shortcut_cb`
510
- // tests `show_progress`, not `show_sidebar`, so a second Escape
511
- // during the closing animation is consumed too and the set inside is
512
- // a no-op. Reading the gate as "is the sidebar shown" would make the
513
- // key propagate for ~250ms after the first press and close a dialog
514
- // behind the view.
480
+ // `escape_shortcut_cb` gates on `show_progress`, not `show_sidebar`, so a
481
+ // second Escape mid-close is consumed too. Reading the gate as "is the
482
+ // sidebar shown" would let the key propagate for ~250ms after the first
483
+ // press and close a dialog behind.
515
484
  const { view, host } = mountSizedView(800, 'collapsed');
516
485
  await settle();
517
486
  expect(view.showSidebar).toBe(true);
@@ -529,8 +498,8 @@ export const AdwSplitViewsTest = async () => {
529
498
  });
530
499
 
531
500
  await it('slides off the edge the sidebar is ON, in both positions', async () => {
532
- // `marginRight: -offsetWidth` regardless of `sidebarPosition` is what
533
- // this used to do, so an `end` sidebar slid the wrong way.
501
+ // Regression: `marginRight: -offsetWidth` regardless of
502
+ // `sidebarPosition` slid an `end` sidebar the wrong way.
534
503
  const start = mountSizedView(800, 'show-sidebar="false"');
535
504
  await settle();
536
505
  const startBar = start.view.querySelector('.adw-osv-sidebar') as HTMLElement;
@@ -571,9 +540,8 @@ export const AdwSplitViewsTest = async () => {
571
540
  });
572
541
 
573
542
  await it('keeps the content pane from being squeezed to nothing', async () => {
574
- // `measure_uncollapsed` (:558-563) as CSS spells it: the pane claims
575
- // its own min-content, where `min-width: 0` let the sidebar take
576
- // everything.
543
+ // `measure_uncollapsed` as CSS spells it: the pane claims its own min-content,
544
+ // where `min-width: 0` let the sidebar take everything.
577
545
  const { view, host } = mountSizedView(800);
578
546
  await settle();
579
547
  const content = view.querySelector('.adw-osv-content') as HTMLElement;
@@ -582,11 +550,6 @@ export const AdwSplitViewsTest = async () => {
582
550
  });
583
551
 
584
552
  for (const vector of OVERLAY_SPLIT_VIEW_LAYOUT_VECTORS) {
585
- // Its exact analogue NAVIGATION_SPLIT_VIEW_LAYOUT_VECTORS was driven
586
- // from the NativeScript suite while this one was driven by nobody —
587
- // two sibling tables in the same file, with no reason for the
588
- // difference. The element writes the pane rect from
589
- // `layoutOverlaySplitView` now, so the rects are readable.
590
553
  const label = `${vector.collapsed ? 'collapsed' : 'docked'} ${vector.sidebarPosition}/${vector.direction} @${vector.showProgress}`;
591
554
  await it(`${label} — ${vector.rule}`, async () => {
592
555
  const attrs =
@@ -599,9 +562,8 @@ export const AdwSplitViewsTest = async () => {
599
562
  const state = stateOf(view);
600
563
  state.setShowProgress(vector.showProgress);
601
564
 
602
- // The SHIELD and the paint gate are the element's to publish;
603
- // the pixel rects depend on the measured sidebar width, which a
604
- // real layout decides, so the shared half is what is compared.
565
+ // Shield and paint gate only: the pixel rects depend on the measured
566
+ // sidebar width, which a real layout decides.
605
567
  const backdrop = view.querySelector('.adw-osv-backdrop') as HTMLElement;
606
568
  expect(backdrop.hidden).toBe(!vector.layout.shieldVisible);
607
569
  const sidebar = view.querySelector('.adw-osv-sidebar') as HTMLElement;
@@ -611,16 +573,14 @@ export const AdwSplitViewsTest = async () => {
611
573
  }
612
574
 
613
575
  await it('names the cancel rows the core owns, so this suite is not read as covering them', () => {
614
- // `swipeCancelProgress`'s half-away-from-zero rounding is arithmetic
615
- // with no DOM surface — a pointercancel can only show the rounded
616
- // OUTCOME, not the rule. The core suite drives every row.
576
+ // `swipeCancelProgress`'s half-away-from-zero rounding has no DOM surface: a
577
+ // pointercancel shows the rounded OUTCOME, not the rule.
617
578
  expect(OVERLAY_SWIPE_CANCEL_VECTORS.length).toBeGreaterThan(0);
618
579
  expect(OVERLAY_SWIPE_START_VECTORS.length).toBeGreaterThan(0);
619
580
  });
620
581
  });
621
582
 
622
583
  await describe('<adw-navigation-split-view> stack, tags and navigation.* actions', async () => {
623
- /** Mount a navigation split view with the given panes and attributes. */
624
584
  function mountNav(attrs = '', panes = { sidebar: true, content: true, sidebarTag: '', contentTag: '' }) {
625
585
  const host = document.createElement('div');
626
586
  host.style.width = '800px';
@@ -650,9 +610,8 @@ export const AdwSplitViewsTest = async () => {
650
610
  };
651
611
 
652
612
  for (const vector of NAVIGATION_STACK_VECTORS) {
653
- // Only the STATIC rows: the animated branch reaches the same stack by
654
- // a push or a pop, and a DOM renderer that has no transition cannot
655
- // tell them apart. The core suite drives the direction.
613
+ // Only the STATIC rows: the animated branch reaches the same stack by a push
614
+ // or a pop, which a renderer with no transition cannot tell apart.
656
615
  if (vector.changingPage) continue;
657
616
  const label =
658
617
  `${vector.hasSidebar ? 'sidebar' : '-'}/${vector.hasContent ? 'content' : '-'} ` +
@@ -671,9 +630,8 @@ export const AdwSplitViewsTest = async () => {
671
630
  await settle();
672
631
  const top = vector.plan.stack[vector.plan.stack.length - 1] ?? null;
673
632
  const panes = visiblePane(view);
674
- // A LONE child stays visible whatever `show-content` says — the
675
- // rule two CSS classes could not express, and the reason a
676
- // collapsed sidebar-only view used to render blank.
633
+ // A LONE child stays visible whatever `show-content` says; two CSS classes
634
+ // cannot express that, and a collapsed sidebar-only view renders blank.
677
635
  if (vector.hasSidebar) expect(panes.sidebar).toBe(top === 'sidebar');
678
636
  if (vector.hasContent) expect(panes.content).toBe(top === 'content');
679
637
  host.remove();
@@ -685,10 +643,8 @@ export const AdwSplitViewsTest = async () => {
685
643
  vector.action === 'push'
686
644
  ? `push "${vector.tag}" (sidebar=${vector.sidebarTag ?? 'none'}, content=${vector.contentTag ?? 'none'})`
687
645
  : `pop (sidebar=${vector.hasSidebar}, content=${vector.hasContent})`;
688
- // A row whose two panes carry the SAME tag describes a state the
689
- // duplicate-tag guard makes unreachable through a real widget: the
690
- // second assignment is refused (:1195-1201), so the element can never
691
- // hold both. Asserted below instead of driven here.
646
+ // Two panes with the SAME tag is a state the duplicate-tag guard makes
647
+ // unreachable — the second assignment is refused. Asserted below instead.
692
648
  const collides =
693
649
  vector.action === 'push' && vector.sidebarTag != null && vector.sidebarTag === vector.contentTag;
694
650
  if (collides) continue;
@@ -701,10 +657,8 @@ export const AdwSplitViewsTest = async () => {
701
657
  sidebarTag: vector.sidebarTag ?? '',
702
658
  contentTag: vector.contentTag ?? '',
703
659
  });
704
- // `delegate` is the ROUTING's answer; whether it survives depends
705
- // on the ancestor. An ancestor that claims the tag is the case the
706
- // table describes — the unclaimed one becomes a critical, which
707
- // is the state's own step and has its own test below.
660
+ // `delegate` is the ROUTING's answer; the table describes an ancestor that
661
+ // CLAIMS the tag. The unclaimed case is a critical, tested below.
708
662
  host.addEventListener('navigation-push', (event) => {
709
663
  (event as CustomEvent<{ handled: boolean }>).detail.handled = true;
710
664
  });
@@ -716,8 +670,8 @@ export const AdwSplitViewsTest = async () => {
716
670
  expect(result.kind).toBe(vector.result.kind);
717
671
  if (result.kind === 'set-show-content' && vector.result.kind === 'set-show-content') {
718
672
  expect(view.showContent).toBe(vector.result.showContent);
719
- // The DOM has to agree, or a consumer reading the attribute
720
- // back after a push sees the pre-push answer.
673
+ // The DOM has to agree, or a consumer reading the attribute back after
674
+ // a push sees the pre-push answer.
721
675
  expect(view.hasAttribute('show-content')).toBe(vector.result.showContent);
722
676
  }
723
677
  host.remove();
@@ -728,16 +682,15 @@ export const AdwSplitViewsTest = async () => {
728
682
  const collidingRows = NAVIGATION_ACTION_VECTORS.filter(
729
683
  (v) => v.action === 'push' && v.sidebarTag != null && v.sidebarTag === v.contentTag,
730
684
  );
731
- // Exactly the shared-tag pushes. Their `rule` even says so — the C's
732
- // routing tests the content tag first, which only matters in a
733
- // collision the setters refuse to create.
685
+ // Exactly the shared-tag pushes: the C's routing tests the content tag
686
+ // first, which only matters in a collision the setters refuse to create.
734
687
  expect(collidingRows.length).toBeGreaterThan(0);
735
688
  for (const row of collidingRows) expect(row.contentTag).toBe(row.sidebarTag);
736
689
  });
737
690
 
738
691
  await it('an UNCLAIMED push becomes a critical, not a silent no-op', async () => {
739
- // `navigation_push_cb` :683 — the parent gets first refusal, and only
740
- // then is it an error. A pop walks off the end silently instead.
692
+ // `navigation_push_cb` — the parent gets first refusal, and only then is it
693
+ // an error. A pop walks off the end silently instead.
741
694
  const { view, host } = mountNav('collapsed', {
742
695
  sidebar: true,
743
696
  content: true,
@@ -774,9 +727,8 @@ export const AdwSplitViewsTest = async () => {
774
727
  });
775
728
 
776
729
  await it('REFUSES a pane whose tag the other one already carries', async () => {
777
- // `adw_navigation_split_view_set_content` :1195-1201 — the pane keeps
778
- // what it had; the assignment does not happen. Neither port had a
779
- // duplicate-tag guard at all.
730
+ // `adw_navigation_split_view_set_content` — the pane keeps what it had; the
731
+ // assignment does not happen.
780
732
  const { view, host } = mountNav('', {
781
733
  sidebar: true,
782
734
  content: true,
@@ -803,19 +755,12 @@ export const AdwSplitViewsTest = async () => {
803
755
  });
804
756
  });
805
757
 
806
- // A VIEW THAT WAS NEVER MEASURED, AND A VIEW THAT WAS MOVED.
807
- //
808
- // Both shipped broken in v0.32.0 and were visible on the docs site: its
809
- // slideshow builds each slide inside `display: none` and moves it in, so the
810
- // controls pane had no measurement when it first rendered and no live
811
- // observer afterwards. A hidden sidebar was painted over the content at the
812
- // wrong edge — the state was right the whole time, only the geometry never
813
- // reached the DOM.
814
- //
815
- // These are placement assertions on purpose. Every other test here reads the
816
- // state or a class, and every one of them PASSED while the widget was
817
- // visibly wrong: nothing in the suite looked at where the pane actually
818
- // ended up. That is the gap, not the individual bug.
758
+ // The docs-site slideshow builds each slide inside `display: none` and moves it in,
759
+ // so the pane had no measurement when it first rendered and no live observer
760
+ // afterwards, and a hidden sidebar was painted over the content at the wrong edge.
761
+ // These assert PLACEMENT on purpose: every state-and-class test here PASSED while
762
+ // the widget was visibly wrong, because none of them looked at where the pane
763
+ // ended up.
819
764
  await describe('AdwOverlaySplitView — geometry survives being unmeasured and moved', async () => {
820
765
  /** Does the pane cover the view's own box? */
821
766
  const covers = (view: AdwOverlaySplitView): boolean => {
@@ -837,7 +782,6 @@ export const AdwSplitViewsTest = async () => {
837
782
  const view = slide.querySelector('adw-overlay-split-view') as AdwOverlaySplitView;
838
783
  await settle();
839
784
 
840
- // The slide becomes the visible one.
841
785
  slide.style.display = '';
842
786
  await settle();
843
787
  expect(view.showSidebar).toBe(false);
@@ -880,10 +824,9 @@ export const AdwSplitViewsTest = async () => {
880
824
  const pane = view.querySelector('.adw-osv-sidebar') as HTMLElement;
881
825
  expect(pane.style.left).toBe('900px');
882
826
 
883
- // Unmeasurable again: the inline offset must be CLEARED, because an
884
- // absolutely-positioned box with `left` + `width` ignores `right`,
885
- // so a leftover value would outrank the resting rule it falls back
886
- // to and pin the pane wherever it last happened to be.
827
+ // Unmeasurable again: the inline offset must be CLEARED — an absolutely
828
+ // positioned box with `left` + `width` ignores `right`, so a leftover
829
+ // value outranks the resting rule and pins the pane where it last was.
887
830
  host.style.display = 'none';
888
831
  await settle();
889
832
  expect(pane.style.left).toBe('');
@@ -891,20 +834,12 @@ export const AdwSplitViewsTest = async () => {
891
834
  });
892
835
  });
893
836
 
894
- // The pane STYLE CLASSES, which libadwaita documents as each split view's
895
- // CSS node tree and which an app is meant to be able to select.
896
- //
897
- // They were absent entirely, and both views hard-coded `--sidebar-bg-color`
898
- // onto their own private pane class instead. That is not the same thing
899
- // twice: the class is not constant. It says which STATE a pane is in, and
900
- // the colour follows from that — so a collapsed overlay sidebar, which
901
- // libadwaita puts on the window background, was painted as though it were
902
- // still docked beside the content.
903
- //
904
- // Asserting the class names and not only the colours is deliberate. The
905
- // names are the app-facing contract; a rendering that happened to look right
906
- // through some other selector would still have broken every app stylesheet
907
- // written against the documented one.
837
+ // The pane STYLE CLASSES libadwaita documents as each split view's CSS node tree. A
838
+ // class says which STATE a pane is in and the colour follows: hard-coding
839
+ // `--sidebar-bg-color` onto a private pane class painted a collapsed overlay
840
+ // sidebar as though it were still docked. The class NAMES are asserted, not only
841
+ // the colours, because the names are the app-facing contract — looking right
842
+ // through some other selector still breaks every app stylesheet.
908
843
  await describe('split-view panes carry libadwaita pane style classes', async () => {
909
844
  const bg = (el: Element) => getComputedStyle(el).backgroundColor;
910
845
  const token = (name: string) => {
@@ -941,13 +876,13 @@ export const AdwSplitViewsTest = async () => {
941
876
  await settle();
942
877
  expect(sidebar.classList.contains('overlay-pane')).toBe(true);
943
878
  expect(sidebar.classList.contains('sidebar-pane')).toBe(false);
944
- // Collapsed, libadwaita removes `.content-pane` outright — the
945
- // content is no longer one pane of two, it is the whole view.
879
+ // Collapsed, libadwaita removes `.content-pane` outright — the content
880
+ // is no longer one pane of two, it is the whole view.
946
881
  expect(content.classList.contains('content-pane')).toBe(false);
947
882
  expect(bg(sidebar)).toBe(token('--window-bg-color'));
948
883
 
949
- // And back: the class follows the state in BOTH directions. A
950
- // one-way toggle would leave a re-expanded sidebar window-coloured.
884
+ // BOTH directions: a one-way toggle would leave a re-expanded sidebar
885
+ // window-coloured.
951
886
  view.removeAttribute('collapsed');
952
887
  await settle();
953
888
  expect(sidebar.classList.contains('sidebar-pane')).toBe(true);
@@ -970,9 +905,8 @@ export const AdwSplitViewsTest = async () => {
970
905
  expect(content.classList.contains('content-pane')).toBe(true);
971
906
  expect(bg(sidebar)).toBe(token('--sidebar-bg-color'));
972
907
 
973
- // Collapsed, libadwaita builds no pane bins at all: both pages move
974
- // into one navigation view, so the sidebar is an ordinary full-width
975
- // page and must stop being sidebar-coloured.
908
+ // Collapsed, libadwaita builds no pane bins: both pages move into one
909
+ // navigation view, so the sidebar is an ordinary full-width page.
976
910
  view.setAttribute('collapsed', '');
977
911
  await settle();
978
912
  expect(sidebar.classList.contains('sidebar-pane')).toBe(false);