@gjsify/adwaita-web 0.36.0 → 0.38.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 (151) hide show
  1. package/dist/adwaita-web.css +504 -34
  2. package/dist/adwaita-web.css.map +1 -1
  3. package/lib/types/accent.d.ts +28 -0
  4. package/lib/types/adw-accent.spec.d.ts +2 -0
  5. package/lib/types/adw-shortcut-label.spec.d.ts +2 -0
  6. package/lib/types/breakpoints.d.ts +10 -12
  7. package/lib/types/elements/adw-about-dialog.d.ts +19 -36
  8. package/lib/types/elements/adw-action-row.d.ts +9 -12
  9. package/lib/types/elements/adw-alert-dialog.d.ts +0 -12
  10. package/lib/types/elements/adw-avatar.d.ts +1 -0
  11. package/lib/types/elements/adw-bottom-sheet.d.ts +7 -12
  12. package/lib/types/elements/adw-button-content.d.ts +3 -4
  13. package/lib/types/elements/adw-button-row.d.ts +1 -1
  14. package/lib/types/elements/adw-carousel.d.ts +28 -49
  15. package/lib/types/elements/adw-checks.d.ts +2 -8
  16. package/lib/types/elements/adw-combo-row.d.ts +6 -6
  17. package/lib/types/elements/adw-data-grid.d.ts +5 -10
  18. package/lib/types/elements/adw-drop-down.d.ts +3 -11
  19. package/lib/types/elements/adw-entry-row.d.ts +20 -23
  20. package/lib/types/elements/adw-icon.d.ts +2 -4
  21. package/lib/types/elements/adw-inline-view-switcher.d.ts +18 -31
  22. package/lib/types/elements/adw-navigation-split-view.d.ts +7 -12
  23. package/lib/types/elements/adw-navigation-view.d.ts +2 -10
  24. package/lib/types/elements/adw-overlay-split-view.d.ts +28 -52
  25. package/lib/types/elements/adw-password-entry-row.d.ts +4 -5
  26. package/lib/types/elements/adw-popover.d.ts +2 -7
  27. package/lib/types/elements/adw-preferences-dialog.d.ts +21 -34
  28. package/lib/types/elements/adw-preferences-group.d.ts +12 -14
  29. package/lib/types/elements/adw-progress-bar.d.ts +3 -4
  30. package/lib/types/elements/adw-shortcut-label.d.ts +20 -0
  31. package/lib/types/elements/adw-sidebar.d.ts +5 -10
  32. package/lib/types/elements/adw-spinner.d.ts +3 -5
  33. package/lib/types/elements/adw-split-button.d.ts +6 -16
  34. package/lib/types/elements/adw-switch-row.d.ts +3 -3
  35. package/lib/types/elements/adw-tab-view.d.ts +16 -26
  36. package/lib/types/elements/adw-toast-overlay.d.ts +8 -13
  37. package/lib/types/elements/adw-view-stack.d.ts +7 -17
  38. package/lib/types/elements/adw-view-switcher-bar.d.ts +4 -8
  39. package/lib/types/elements/adw-view-switcher.d.ts +18 -38
  40. package/lib/types/elements/adw-wrap-box.d.ts +7 -17
  41. package/lib/types/elements/view-switcher-dom.d.ts +10 -13
  42. package/lib/types/index.d.ts +3 -0
  43. package/lib/types/source-view/hex.d.ts +7 -13
  44. package/lib/types/style-classes.spec.d.ts +11 -0
  45. package/lib/types/styles.generated.d.ts +1 -1
  46. package/package.json +18 -7
  47. package/scss/_about_dialog.scss +3 -2
  48. package/scss/_action_row.scss +33 -0
  49. package/scss/_avatar.scss +12 -0
  50. package/scss/_button.scss +44 -22
  51. package/scss/_card.scss +11 -8
  52. package/scss/_checks.scss +2 -4
  53. package/scss/_dialog.scss +3 -2
  54. package/scss/_headerbar.scss +23 -0
  55. package/scss/_popover.scss +8 -4
  56. package/scss/_preferences.scss +7 -7
  57. package/scss/_progress_bar.scss +9 -6
  58. package/scss/_reset.scss +1 -1
  59. package/scss/_shortcut_label.scss +80 -0
  60. package/scss/_sidebar.scss +57 -0
  61. package/scss/_status_page.scss +20 -0
  62. package/scss/_style_classes.scss +407 -0
  63. package/scss/_switch.scss +4 -3
  64. package/scss/_theme.scss +20 -2
  65. package/scss/_variables.scss +34 -1
  66. package/scss/adwaita-skin.scss +12 -0
  67. package/src/accent.ts +74 -0
  68. package/src/adw-about-dialog.spec.ts +34 -49
  69. package/src/adw-accent.spec.ts +105 -0
  70. package/src/adw-action-rows.spec.ts +25 -33
  71. package/src/adw-avatar.spec.ts +51 -20
  72. package/src/adw-banner.spec.ts +5 -8
  73. package/src/adw-button-content.spec.ts +9 -12
  74. package/src/adw-button-row.spec.ts +2 -4
  75. package/src/adw-carousel.spec.ts +40 -53
  76. package/src/adw-checks.spec.ts +36 -47
  77. package/src/adw-drop-down.spec.ts +25 -32
  78. package/src/adw-header-bar.spec.ts +5 -7
  79. package/src/adw-icon.spec.ts +23 -32
  80. package/src/adw-progress-bar.spec.ts +10 -12
  81. package/src/adw-row-state.spec.ts +9 -10
  82. package/src/adw-shortcut-label.spec.ts +112 -0
  83. package/src/adw-sidebar.spec.ts +17 -24
  84. package/src/adw-switch.spec.ts +11 -17
  85. package/src/adw-tab-view.spec.ts +7 -10
  86. package/src/adw-toast-overlay.spec.ts +7 -11
  87. package/src/adw-view-switcher-bar.spec.ts +10 -14
  88. package/src/adw-wrap-box.spec.ts +25 -36
  89. package/src/bottom-sheet.spec.ts +30 -36
  90. package/src/breakpoints.ts +15 -18
  91. package/src/chrome.spec.ts +13 -21
  92. package/src/elements/adw-about-dialog.ts +71 -114
  93. package/src/elements/adw-action-row.ts +22 -37
  94. package/src/elements/adw-alert-dialog.ts +25 -50
  95. package/src/elements/adw-avatar.ts +40 -15
  96. package/src/elements/adw-banner.ts +14 -18
  97. package/src/elements/adw-bottom-sheet.ts +31 -52
  98. package/src/elements/adw-button-content.ts +30 -37
  99. package/src/elements/adw-button-row.ts +14 -24
  100. package/src/elements/adw-carousel.ts +87 -148
  101. package/src/elements/adw-checks.ts +43 -56
  102. package/src/elements/adw-clamp.ts +8 -9
  103. package/src/elements/adw-combo-row.ts +17 -25
  104. package/src/elements/adw-data-grid.ts +26 -38
  105. package/src/elements/adw-dialog.ts +25 -56
  106. package/src/elements/adw-drop-down.ts +31 -51
  107. package/src/elements/adw-entry-row.ts +39 -46
  108. package/src/elements/adw-expander-row.ts +30 -53
  109. package/src/elements/adw-icon.ts +30 -53
  110. package/src/elements/adw-inline-view-switcher.ts +38 -67
  111. package/src/elements/adw-menu-button.ts +28 -58
  112. package/src/elements/adw-navigation-split-view.ts +35 -47
  113. package/src/elements/adw-navigation-view.ts +12 -28
  114. package/src/elements/adw-overlay-split-view.ts +100 -175
  115. package/src/elements/adw-password-entry-row.ts +18 -28
  116. package/src/elements/adw-popover.ts +28 -44
  117. package/src/elements/adw-preferences-dialog.ts +41 -66
  118. package/src/elements/adw-preferences-group.ts +33 -46
  119. package/src/elements/adw-progress-bar.ts +27 -47
  120. package/src/elements/adw-shortcut-label.ts +138 -0
  121. package/src/elements/adw-sidebar.ts +31 -39
  122. package/src/elements/adw-spin-row.ts +7 -14
  123. package/src/elements/adw-spinner.ts +31 -43
  124. package/src/elements/adw-split-button.ts +45 -75
  125. package/src/elements/adw-switch-row.ts +29 -46
  126. package/src/elements/adw-switch.ts +28 -47
  127. package/src/elements/adw-tab-view.ts +62 -103
  128. package/src/elements/adw-toast-overlay.ts +28 -35
  129. package/src/elements/adw-toggle-group.ts +9 -16
  130. package/src/elements/adw-view-stack.ts +32 -51
  131. package/src/elements/adw-view-switcher-bar.ts +26 -50
  132. package/src/elements/adw-view-switcher.ts +60 -110
  133. package/src/elements/adw-window-title.ts +4 -4
  134. package/src/elements/adw-wrap-box.ts +33 -59
  135. package/src/elements/view-switcher-dom.ts +15 -22
  136. package/src/entry-rows.spec.ts +18 -24
  137. package/src/index.ts +24 -15
  138. package/src/navigation-view.spec.ts +7 -10
  139. package/src/preferences-search.ts +11 -15
  140. package/src/preferences.spec.ts +13 -15
  141. package/src/source-view/adw-source-view.ts +6 -19
  142. package/src/source-view/hex.ts +7 -13
  143. package/src/split-button.spec.ts +32 -44
  144. package/src/split-views.spec.ts +83 -149
  145. package/src/style-classes.spec.ts +181 -0
  146. package/src/style-isolation.spec.ts +3 -6
  147. package/src/styles.generated.ts +1 -1
  148. package/src/tab-view.spec.ts +26 -35
  149. package/src/test.browser.mts +6 -0
  150. package/src/view-stack.spec.ts +23 -34
  151. package/src/view-switcher.spec.ts +56 -84
@@ -1,65 +1,52 @@
1
- // <adw-about-dialog> — The standard Adwaita "About" dialog (the web counterpart
2
- // of Adw.AboutDialog). It is a modal AdwDialog (a full-cover scrim + a centred,
3
- // scrollable floating sheet) hosting a navigation view: the main page shows the
4
- // app icon, name, developer name and a version pill, followed by up to three
5
- // preference groups of rows that link out or push a subpage.
1
+ // <adw-about-dialog> — The standard Adwaita "About" dialog (the web counterpart of
2
+ // Adw.AboutDialog): a modal AdwDialog (full-cover scrim + centred, scrollable
3
+ // floating sheet) hosting a navigation view, whose main page shows the app icon,
4
+ // name, developer name and a version pill, followed by up to three preference
5
+ // groups of rows that link out or push a subpage.
6
6
  //
7
- // Like Adw.AboutDialog the dialog is presented imperatively — `present()` (or
8
- // setting the `open` attribute) reveals it; Escape, a scrim click, the header
9
- // close button, or `close()` dismisses it. The header title fades in once the
10
- // main page is scrolled (mirroring AdwAboutDialog's update_headerbar_cb).
7
+ // Presented imperatively — `present()` (or setting `open`) reveals it; Escape, a
8
+ // scrim click, the header close button or `close()` dismisses it. The header title
9
+ // fades in once the main page is scrolled (`update_headerbar_cb`).
11
10
  //
12
11
  // WHICH PAGE A ROW IS ON IS NOT A LAYOUT CHOICE — it is `update_details` and
13
- // `update_support`, and this element used to get it wrong in three ways: it put
14
- // Support Questions and Report an Issue on the DETAILS page, where the template
15
- // keeps them on the MAIN page (adw-about-dialog.ui:146-186); it treated
16
- // `website` as Details content, which is the one input libadwaita deliberately
17
- // leaves out of that predicate (adw-about-dialog.c:1108), so a dialog whose only
18
- // extra was a website grew a Details subpage holding a single link; and it
19
- // invented fallbacks GTK does not have — "Application" for a missing name, a
20
- // generic executable glyph for a missing icon, and an "About <app>" title on top
21
- // of an "About <app>" label. All four derivations now come from
22
- // `@gjsify/adwaita-core`, which holds them once for both renderers (ADR 0004)
23
- // and is held to `@gjsify/adwaita-core/conformance`.
12
+ // `update_support`. `website` is the one input libadwaita deliberately leaves OUT
13
+ // of the details predicate, so a dialog whose only extra is a website must not grow
14
+ // a Details subpage holding a single link; and there are no fallbacks GTK does not
15
+ // have (no "Application" for a missing name, no generic glyph for a missing icon).
16
+ // All four derivations come from `@gjsify/adwaita-core` (ADR 0004), which holds them
17
+ // once for both renderers and is held to `@gjsify/adwaita-core/conformance`.
24
18
  //
25
19
  // Properties / attributes (all reflected, mirroring the AdwAboutDialog GObject
26
20
  // properties of the same name, hyphenated):
27
21
  // application-name the application's display name (shown as a title-1)
28
- // application-icon a symbolic icon name (with or without -symbolic) — the
29
- // large app icon; absent one, no icon is drawn
22
+ // application-icon a symbolic icon name (with or without -symbolic); absent
23
+ // one, no icon is drawn
30
24
  // developer-name the developer / vendor line below the name
31
25
  // version the version, shown as a clickable pill
32
- // comments a longer description (shown on the Details page)
33
- // website the application's website URL — a Website link row, on
34
- // the MAIN page unless the Details page has other content
26
+ // comments a longer description (Details page)
27
+ // website the website URL — a Website link row, on the MAIN page
28
+ // unless the Details page has other content
35
29
  // support-url a support-forum URL (a main-page Support Questions row)
36
30
  // issue-url an issue-tracker URL (a main-page Report an Issue row)
37
- // copyright the copyright line (shown on the Legal page)
38
- // license the license text/name (shown on the Legal page); when a
39
- // `license-url` is also given the name becomes a link
31
+ // copyright the copyright line (Legal page)
32
+ // license the license text/name (Legal page); with a `license-url`
33
+ // the name becomes a link
40
34
  // license-url a URL the license name links to
41
35
  // open (boolean) whether the dialog is presented
42
36
  //
43
37
  // List-valued credits are set via properties (string arrays), mirroring the
44
- // AdwAboutDialog `developers` / `designers` / `artists` / `documenters`
45
- // properties — entries may be `Name`, `Name <email>` or `Name https://url`,
46
- // parsed by the core's `parseCreditPerson`, which is `parse_person` (:490-534).
38
+ // AdwAboutDialog `developers` / `designers` / `artists` / `documenters` properties
39
+ // — entries may be `Name`, `Name <email>` or `Name https://url`, parsed by the
40
+ // core's `parseCreditPerson` (`parse_person`).
47
41
  //
48
- // NOT implemented here (and therefore left at their empty values when the core
49
- // derivations are asked): `release-notes` + the What's New page, `debug-info` +
50
- // the Troubleshooting page, `add_link`, `add_credit_section`,
51
- // `translator-credits` and the Acknowledgements page. The core covers all of
52
- // them; adopting them is a feature, not a fidelity fix.
42
+ // NOT implemented here, so the core derivations see them empty: `release-notes` +
43
+ // the What's New page, `debug-info` + the Troubleshooting page, `add_link`,
44
+ // `add_credit_section`, `translator-credits` and the Acknowledgements page.
53
45
  //
54
- // Events (CustomEvent, bubbles):
55
- // `notify::open` (detail = { open }) when the presented state changes —
56
- // mirrors the Adw.Dialog `open` notification.
57
- // `closed` when the dialog is dismissed — mirrors Adw.Dialog::closed.
58
- // `activate-link` (detail = { uri }, CANCELABLE) when a link is activated —
59
- // mirrors AdwAboutDialog::activate-link, a boolean signal with the
60
- // `true_handled` accumulator (:2093-2103): a handler that returns TRUE
61
- // suppresses the default navigation (:429-437). `preventDefault()` is the
62
- // web spelling of returning TRUE.
46
+ // Events (CustomEvent, bubbles): `notify::open` (detail `{ open }`), `closed`, and
47
+ // `activate-link` (detail `{ uri }`, CANCELABLE — the signal's `true_handled`
48
+ // accumulator means "a handler returned TRUE suppresses the default navigation",
49
+ // which is what `preventDefault()` spells).
63
50
  //
64
51
  // Reference: refs/libadwaita/src/adw-about-dialog.c (AdwAboutDialog behaviour)
65
52
  // Reference: refs/libadwaita/src/adw-about-dialog.ui (navigation page tree)
@@ -120,8 +107,6 @@ export class AdwAboutDialog extends HTMLElement {
120
107
  ];
121
108
  }
122
109
 
123
- // --- Reflected scalar properties ---
124
-
125
110
  get applicationName(): string {
126
111
  return this.getAttribute('application-name') ?? '';
127
112
  }
@@ -210,7 +195,6 @@ export class AdwAboutDialog extends HTMLElement {
210
195
  this.setAttribute('license-url', value);
211
196
  }
212
197
 
213
- /** Whether the dialog is presented. */
214
198
  get open(): boolean {
215
199
  return this.hasAttribute('open');
216
200
  }
@@ -220,8 +204,6 @@ export class AdwAboutDialog extends HTMLElement {
220
204
  else this.removeAttribute('open');
221
205
  }
222
206
 
223
- // --- List-valued credit properties (no attribute form) ---
224
-
225
207
  get developers(): string[] {
226
208
  return this._developers;
227
209
  }
@@ -272,19 +254,17 @@ export class AdwAboutDialog extends HTMLElement {
272
254
  if (this._initialized) return;
273
255
  this._initialized = true;
274
256
 
275
- // The full-cover modal scrim — clicking it dismisses the dialog.
276
257
  this._scrimEl = document.createElement('div');
277
258
  this._scrimEl.className = 'adw-about-dialog-scrim';
278
259
  this._scrimEl.addEventListener('click', () => this.close());
279
260
 
280
- // The centred floating sheet.
281
261
  this._sheetEl = document.createElement('div');
282
262
  this._sheetEl.className = 'adw-about-dialog-sheet';
283
263
  this._sheetEl.setAttribute('role', 'dialog');
284
264
  this._sheetEl.setAttribute('aria-modal', 'true');
285
- // AdwDialog:title, whose template default is the bare word (.ui:6). The
286
- // application name is announced by the title-1 label inside, exactly as
287
- // the header revealer shows it separately in GTK (.ui:29-31).
265
+ // AdwDialog:title, whose template default is the bare word. The application
266
+ // name is announced by the title-1 label inside, exactly as the header
267
+ // revealer shows it separately in GTK.
288
268
  this._sheetEl.setAttribute('aria-label', ADW_ABOUT_DIALOG_LABELS.dialogTitle);
289
269
 
290
270
  this.replaceChildren(this._scrimEl, this._sheetEl);
@@ -337,23 +317,18 @@ export class AdwAboutDialog extends HTMLElement {
337
317
  }
338
318
 
339
319
  /**
340
- * Whether the Legal page has anything on it.
341
- *
342
- * This element's licence model is the simplified one — a name plus an
343
- * optional URL — so it maps onto `GtkLicense` as "custom text when a licence
344
- * is set, unknown otherwise", which is what `adw_about_dialog_set_license`
345
- * does to the type anyway (:3472).
320
+ * Whether the Legal page has anything on it. This element's licence model is the
321
+ * simplified one — a name plus an optional URL — so it maps onto `GtkLicense` as
322
+ * "custom text when a licence is set, unknown otherwise", which is what
323
+ * `adw_about_dialog_set_license` does to the type anyway.
346
324
  */
347
325
  private _hasLegal(): boolean {
348
326
  const licenseType = this.license.length > 0 ? GTK_LICENSE.CUSTOM : GTK_LICENSE.UNKNOWN;
349
327
  return legalSectionVisible(this.copyright, licenseType, this.license);
350
328
  }
351
329
 
352
- /** Rebuild the sheet contents from the current attributes / credit lists. */
353
330
  private _render(): void {
354
331
  const sections = this._creditsSections();
355
- // The four inputs this element has no API for stay empty: `debug-info`,
356
- // `release-notes`, `add_link` and the acknowledgements page.
357
332
  const visibility = aboutDialogVisibility({
358
333
  applicationIcon: this.applicationIcon,
359
334
  applicationName: this.applicationName,
@@ -367,12 +342,11 @@ export class AdwAboutDialog extends HTMLElement {
367
342
  hasLegal: this._hasLegal(),
368
343
  });
369
344
 
370
- // The navigation view (main page + subpages) lives inside the sheet.
371
345
  this._navView = document.createElement('adw-navigation-view');
372
346
  this._navView.append(this._buildMainPage(visibility));
373
347
 
374
348
  // The Details page exists exactly when its row does — `details_row` is
375
- // `has_comments || show_links` (:1115), i.e. "the page has content".
349
+ // `has_comments || show_links`, i.e. "the page has content".
376
350
  if (visibility.detailsRow) this._navView.append(this._buildDetailsPage(visibility));
377
351
  if (visibility.creditsRow) this._navView.append(this._buildCreditsPage(sections));
378
352
  if (visibility.legalRow) this._navView.append(this._buildLegalPage());
@@ -385,10 +359,8 @@ export class AdwAboutDialog extends HTMLElement {
385
359
 
386
360
  /**
387
361
  * A navigation page wrapping a header bar (with the close button) + content.
388
- *
389
- * `headerTitle` defaults to the page title; the main page overrides it,
390
- * because its page title is the dialog's ("About", .ui:19) while its header
391
- * shows the application name (.ui:30).
362
+ * `headerTitle` defaults to the page title; the main page overrides it, because its
363
+ * page title is the dialog's ("About") while its header shows the application name.
392
364
  */
393
365
  private _buildPage(
394
366
  tag: string,
@@ -410,9 +382,10 @@ export class AdwAboutDialog extends HTMLElement {
410
382
  header.setAttribute('title', headerTitle);
411
383
 
412
384
  if (showClose) {
413
- // The close button — drawn with a CSS "×" glyph (no window-close
414
- // symbolic icon ships in @gjsify/adwaita-icons, the same approach as
415
- // adw-tab-view's close affordance).
385
+ // The close button — drawn with a CSS "×" glyph, the same approach as
386
+ // adw-tab-view's close affordance: `window-close` has no mask class,
387
+ // because it is not in the ICONS map in `scripts/build-scss.mjs` that
388
+ // generates them (`@gjsify/adwaita-icons` does export the SVG).
416
389
  const close = document.createElement('button');
417
390
  close.type = 'button';
418
391
  close.className = 'adw-button flat circular adw-about-dialog-close';
@@ -422,8 +395,8 @@ export class AdwAboutDialog extends HTMLElement {
422
395
  const end = (header as { endSection?: HTMLElement | null }).endSection ?? null;
423
396
  if (end) end.appendChild(close);
424
397
  };
425
- // The header bar builds its sections in its own connectedCallback;
426
- // append the close button once that has run.
398
+ // The header bar builds its sections in its own connectedCallback, so the
399
+ // close button can only be appended after that has run.
427
400
  queueMicrotask(endApply);
428
401
  }
429
402
 
@@ -445,7 +418,6 @@ export class AdwAboutDialog extends HTMLElement {
445
418
  if (tag === 'main') {
446
419
  this._scrollEl = scroll;
447
420
  this._mainToolbarEl = toolbar;
448
- // The main page's header title fades in once the content scrolls.
449
421
  toolbar.classList.add('main-page');
450
422
  scroll.addEventListener('scroll', () => this._updateHeaderTitle());
451
423
  }
@@ -453,21 +425,19 @@ export class AdwAboutDialog extends HTMLElement {
453
425
  return { page, body, header };
454
426
  }
455
427
 
456
- /** The main page: icon, name, developer, version pill, then the three groups. */
457
428
  private _buildMainPage(visibility: ReturnType<typeof aboutDialogVisibility>): HTMLElement {
458
429
  const { page, body } = this._buildPage('main', ADW_ABOUT_DIALOG_LABELS.dialogTitle, true, this.applicationName);
459
430
 
460
- // App icon — a large symbolic glyph, and only when one was given. GTK
461
- // hides the image outright for an empty icon name (:2313-2314); picking
462
- // a generic glyph here would show an icon for an application that asked
463
- // for none. A reverse-DNS application id (`org.gnome.Builder`) is not one
464
- // CSS token and resolves to no glyph rather than to three stray classes —
465
- // see `normalizeIconName`.
431
+ // Only when one was given: GTK hides the image outright for an empty icon
432
+ // name, and a generic glyph would show an icon for an application that asked
433
+ // for none. A reverse-DNS application id (`org.gnome.Builder`) is not one CSS
434
+ // token and resolves to no glyph rather than to three stray classes — see
435
+ // `normalizeIconName`.
466
436
  if (visibility.appIcon) {
467
437
  body.appendChild(createAdwIcon(this.applicationIcon, 'adw-about-dialog-icon'));
468
438
  }
469
439
 
470
- // App name — title-1. No fallback: an unset name means no label (:2376-2377).
440
+ // No fallback: an unset name means no label.
471
441
  if (visibility.appName) {
472
442
  const nameEl = document.createElement('span');
473
443
  nameEl.className = 'adw-about-dialog-name';
@@ -475,7 +445,6 @@ export class AdwAboutDialog extends HTMLElement {
475
445
  body.appendChild(nameEl);
476
446
  }
477
447
 
478
- // Developer / vendor.
479
448
  if (visibility.developerName) {
480
449
  const devEl = document.createElement('span');
481
450
  devEl.className = 'adw-about-dialog-developer';
@@ -483,7 +452,6 @@ export class AdwAboutDialog extends HTMLElement {
483
452
  body.appendChild(devEl);
484
453
  }
485
454
 
486
- // Version pill.
487
455
  if (visibility.version) {
488
456
  const versionEl = document.createElement('span');
489
457
  versionEl.className = 'adw-about-dialog-version';
@@ -491,10 +459,9 @@ export class AdwAboutDialog extends HTMLElement {
491
459
  body.appendChild(versionEl);
492
460
  }
493
461
 
494
- // Three separate preference groups, as in the template: details_group
495
- // (.ui:96), support_group (.ui:146) and credits_legal_group (.ui:188).
496
- // They are groups, not one list, and the stylesheet already spaces
497
- // consecutive `.adw-about-dialog-rows` apart for exactly this.
462
+ // Three separate preference groups, as in the template (details_group,
463
+ // support_group, credits_legal_group) — groups, not one list, and the
464
+ // stylesheet already spaces consecutive `.adw-about-dialog-rows` apart.
498
465
  const detailsGroupRows: HTMLElement[] = [];
499
466
  if (visibility.detailsRow) {
500
467
  detailsGroupRows.push(this._buildNavRow(rowLabel('detailsRow'), 'details'));
@@ -523,12 +490,10 @@ export class AdwAboutDialog extends HTMLElement {
523
490
  }
524
491
 
525
492
  /**
526
- * One `AdwPreferencesGroup` in its spacing wrapper.
527
- *
528
- * `data-group` carries the template's widget id so a test — and a reader —
529
- * can tell the four named groups apart; nothing styles off it. The credits
530
- * sections pass `null`, because the template has no id for them: they are
531
- * built one per section at runtime (:548-549).
493
+ * One `AdwPreferencesGroup` in its spacing wrapper. `data-group` carries the
494
+ * template's widget id so a test — and a reader — can tell the named groups apart;
495
+ * nothing styles off it. The credits sections pass `null`, because the template has
496
+ * no id for them: they are built one per section at runtime.
532
497
  */
533
498
  private _buildGroup(id: string | null, rows: HTMLElement[], title?: string): HTMLElement {
534
499
  const group = document.createElement('adw-preferences-group');
@@ -542,7 +507,6 @@ export class AdwAboutDialog extends HTMLElement {
542
507
  return wrap;
543
508
  }
544
509
 
545
- /** An activatable row that pushes a subpage, with a trailing go-next chevron. */
546
510
  private _buildNavRow(title: string, tag: string): HTMLElement {
547
511
  const row = document.createElement('adw-action-row');
548
512
  row.setAttribute('title', title);
@@ -561,20 +525,17 @@ export class AdwAboutDialog extends HTMLElement {
561
525
  }
562
526
 
563
527
  /**
564
- * Emit `activate-link` and navigate unless a handler took over.
565
- *
566
- * The GObject signal is `BOOLEAN__STRING` with `g_signal_accumulator_true_handled`
567
- * (:2093-2103) and its default handler returns `GDK_EVENT_PROPAGATE`
568
- * (:455-460), i.e. "not handled, do the default". A handler returning TRUE
569
- * suppresses it — which is what `preventDefault()` on a cancelable event
570
- * means, and why `dispatchEvent`'s return value is the gate here.
528
+ * Emit `activate-link` and navigate unless a handler took over. The GObject signal
529
+ * is `BOOLEAN__STRING` with `g_signal_accumulator_true_handled` and its default
530
+ * handler returns `GDK_EVENT_PROPAGATE` ("not handled, do the default"); a handler
531
+ * returning TRUE suppresses it, which is what `preventDefault()` on a cancelable
532
+ * event means — hence the gate on `dispatchEvent`'s return value.
571
533
  */
572
534
  private _activateLink(uri: string): void {
573
535
  const event = new CustomEvent('activate-link', { bubbles: true, cancelable: true, detail: { uri } });
574
536
  if (this.dispatchEvent(event)) window.open(uri, '_blank', 'noopener,noreferrer');
575
537
  }
576
538
 
577
- /** The Details page: comments + the links group (website + future custom links). */
578
539
  private _buildDetailsPage(visibility: ReturnType<typeof aboutDialogVisibility>): HTMLElement {
579
540
  const { page, body } = this._buildPage('details', ADW_ABOUT_DIALOG_LABELS.detailsPage, false);
580
541
 
@@ -596,7 +557,6 @@ export class AdwAboutDialog extends HTMLElement {
596
557
  return page;
597
558
  }
598
559
 
599
- /** A link row that opens a URL in a new tab and emits `activate-link`. */
600
560
  private _buildLinkRow(title: string, uri: string): HTMLElement {
601
561
  const row = document.createElement('adw-action-row');
602
562
  row.setAttribute('title', title);
@@ -612,7 +572,6 @@ export class AdwAboutDialog extends HTMLElement {
612
572
  return row;
613
573
  }
614
574
 
615
- /** The Credits page: one group per section the core assembled. */
616
575
  private _buildCreditsPage(sections: ReturnType<typeof creditsSections>): HTMLElement {
617
576
  const { page, body } = this._buildPage('credits', ADW_ABOUT_DIALOG_LABELS.creditsPage, false);
618
577
 
@@ -625,11 +584,10 @@ export class AdwAboutDialog extends HTMLElement {
625
584
  }
626
585
 
627
586
  /**
628
- * A credit row — a plain title, or a link row when the entry carries a URI.
629
- *
630
- * The gate is `link !== null`, not the URI's truthiness: `"Ada <>"` parses to
631
- * an EMPTY link, which is still a link in the C (`if (link)` tests the
632
- * pointer, :562) and still produces an `AdwLinkRow`, to `mailto:`.
587
+ * A credit row — a plain title, or a link row when the entry carries a URI. The gate
588
+ * is `link !== null`, not the URI's truthiness: `"Ada <>"` parses to an EMPTY link,
589
+ * which is still a link in the C (`if (link)` tests the pointer) and still produces
590
+ * an `AdwLinkRow`, to `mailto:`.
633
591
  */
634
592
  private _buildCreditRow(person: AdwCreditPerson): HTMLElement {
635
593
  const row = document.createElement('adw-action-row');
@@ -648,7 +606,6 @@ export class AdwAboutDialog extends HTMLElement {
648
606
  return row;
649
607
  }
650
608
 
651
- /** The Legal page: copyright + license text. */
652
609
  private _buildLegalPage(): HTMLElement {
653
610
  const { page, body } = this._buildPage('legal', ADW_ABOUT_DIALOG_LABELS.legalPage, false);
654
611
 
@@ -664,7 +621,7 @@ export class AdwAboutDialog extends HTMLElement {
664
621
  license.className = 'adw-about-dialog-license';
665
622
  if (this.licenseUrl) {
666
623
  // GTK connects the legal label's `activate-link` to the same
667
- // handler as the rows (:695), so this link is cancelable too.
624
+ // handler as the rows, so this link is cancelable too.
668
625
  const link = document.createElement('a');
669
626
  link.href = this.licenseUrl;
670
627
  link.rel = 'noopener noreferrer';
@@ -1,18 +1,11 @@
1
- // <adw-action-row> — A boxed-list row with a title, optional subtitle, and
2
- // prefix / suffix widget slots. The most fundamental Adwaita row type.
3
- // Attributes: title, subtitle, activatable.
4
- // Properties: activatableWidget (get/set) — the Adw.ActionRow:activatable-widget
5
- // the row forwards its activation to, and whose sensitivity drives whether the
6
- // row is activatable at all.
7
- // Slots: slot="prefix" (icons/widgets before the text), slot="suffix" (controls
8
- // after the text — switches, buttons, value labels).
9
- // Events: `activated` (CustomEvent) when an `activatable` row is clicked.
1
+ // <adw-action-row> — a boxed-list row with a title, optional subtitle and prefix /
2
+ // suffix widget slots; the most fundamental Adwaita row type. `slot="prefix"` holds
3
+ // icons/widgets before the text, `slot="suffix"` the controls after it, and an
4
+ // `activatable` row emits `activated` on click.
10
5
  //
11
- // The LABEL VISIBILITY rule and the activatable-widget coupling are HEADLESS and
12
- // live in `@gjsify/adwaita-core` (ADR 0004) as {@link ActionRowState}; this
13
- // element composes it and keeps only the DOM render half.
14
- // `@gjsify/adwaita-nativescript` composes the same state, so both ports share one
15
- // behaviour.
6
+ // The LABEL VISIBILITY rule and the activatable-widget coupling are HEADLESS and live
7
+ // in `@gjsify/adwaita-core` (ADR 0004) as {@link ActionRowState}; this element keeps
8
+ // only the DOM render half.
16
9
  //
17
10
  // Reference: refs/adwaita-web/adwaita-web/docs/widgets/actionrow.md
18
11
  // Reference: refs/libadwaita/src/adw-action-row.c, adw-action-row.ui
@@ -67,10 +60,9 @@ export class AdwActionRow extends HTMLElement {
67
60
  }
68
61
 
69
62
  /**
70
- * Set the activatable widget. Its sensitivity is copied into `activatable`
71
- * right away and then tracked, exactly as libadwaita's `sensitive` →
72
- * `activatable` binding does (adw-action-row.c:729-732) — including the part
73
- * that surprises: clearing the widget LEAVES the row activatable (C:709).
63
+ * Set the activatable widget. Its sensitivity is copied into `activatable` right
64
+ * away and then tracked, as libadwaita's `sensitive` → `activatable` binding does —
65
+ * including the surprising part: clearing the widget LEAVES the row activatable.
74
66
  */
75
67
  set activatableWidget(widget: HTMLElement | null) {
76
68
  if (!this._state.setActivatableWidget(widget, widget ? isSensitive(widget) : true)) return;
@@ -85,13 +77,9 @@ export class AdwActionRow extends HTMLElement {
85
77
 
86
78
  connectedCallback() {
87
79
  if (this._initialized) {
88
- // Re-entering a document. `disconnectedCallback` drops the
89
- // sensitivity observer, and returning here without rebuilding it
90
- // left a MOVED row permanently blind to its activatable widget
91
- // becoming insensitive — the same shape that broke the overlay
92
- // split view's ResizeObserver and both view switchers' page
93
- // observers. Anything torn down on the way out has to be rebuilt
94
- // on the way back in.
80
+ // Re-entering a document: `disconnectedCallback` dropped the sensitivity
81
+ // observer, so it has to be rebuilt here or a MOVED row is permanently blind
82
+ // to its activatable widget becoming insensitive.
95
83
  this._observeSensitivity(this._state.activatableWidget);
96
84
  return;
97
85
  }
@@ -117,8 +105,8 @@ export class AdwActionRow extends HTMLElement {
117
105
  for (const child of suffixChildren) this._suffixEl.appendChild(child);
118
106
 
119
107
  this.replaceChildren(this._prefixEl, textEl, this._suffixEl);
120
- // Adopt the declared attributes; `attributeChangedCallback` was guarded
121
- // until now, so a parsed row would otherwise start with a stale state.
108
+ // `attributeChangedCallback` was guarded until now, so a parsed row would
109
+ // otherwise start with a stale state.
122
110
  this._adoptAttributes();
123
111
  this._render();
124
112
 
@@ -144,15 +132,13 @@ export class AdwActionRow extends HTMLElement {
144
132
  }
145
133
 
146
134
  /**
147
- * `adw_action_row_activate_real` (adw-action-row.c:297-307): forward the
148
- * activation to the activatable widget, then emit `activated`.
135
+ * `adw_action_row_activate_real`: forward the activation to the activatable widget,
136
+ * then emit `activated`.
149
137
  *
150
- * A click that ORIGINATED inside the activatable widget does not activate the
151
- * row at all — no forwarding, no `activated`. That is GTK's answer too: the
152
- * widget claims the gesture, so `GtkListBox` never emits `row-activated`, and
153
- * `pressed_cb` denies anything picked below the row / header / prefixes /
154
- * suffixes (C:120-137). It is also what keeps the forwarding from looping —
155
- * the synthetic click dispatched below bubbles straight back into this same
138
+ * A click that ORIGINATED inside the activatable widget does not activate the row at
139
+ * all — no forwarding, no `activated`. That is GTK's answer too: the widget claims
140
+ * the gesture, so `GtkListBox` never emits `row-activated`. It is also what keeps the
141
+ * forwarding from looping — the synthetic click below bubbles back into this same
156
142
  * listener, and without the guard one activation emitted `activated` twice.
157
143
  */
158
144
  private _onClick(event: Event) {
@@ -188,8 +174,7 @@ export class AdwActionRow extends HTMLElement {
188
174
  private _render() {
189
175
  const { title, titleVisible, subtitle, subtitleVisible } = this._state.state;
190
176
  this._titleEl.textContent = title;
191
- // `string_is_not_empty` applies to the TITLE as much as to the subtitle
192
- // (adw-action-row.ui:49-53) — an empty title used to keep its line here.
177
+ // `string_is_not_empty` applies to the TITLE as much as to the subtitle.
193
178
  this._titleEl.hidden = !titleVisible;
194
179
  this._subtitleEl.textContent = subtitle;
195
180
  this._subtitleEl.hidden = !subtitleVisible;