@gjsify/adwaita-web 0.64.2-next.252 → 0.64.2-next.255

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 (293) hide show
  1. package/README.md +10 -80
  2. package/dist/adwaita-web.css +52 -3
  3. package/dist/adwaita-web.css.map +1 -1
  4. package/lib/types/accessible.d.ts +8 -0
  5. package/lib/types/compute-expand.d.ts +5 -0
  6. package/lib/types/compute-expand.spec.d.ts +1 -0
  7. package/lib/types/elements/adw-about-dialog.d.ts +28 -1
  8. package/lib/types/elements/adw-action-row.d.ts +2 -1
  9. package/lib/types/elements/adw-alert-dialog.d.ts +3 -2
  10. package/lib/types/elements/adw-avatar.d.ts +2 -1
  11. package/lib/types/elements/adw-banner.d.ts +2 -1
  12. package/lib/types/elements/adw-bin.d.ts +2 -1
  13. package/lib/types/elements/adw-bottom-sheet.d.ts +5 -4
  14. package/lib/types/elements/adw-breakpoint-bin.d.ts +2 -1
  15. package/lib/types/elements/adw-button-content.d.ts +2 -1
  16. package/lib/types/elements/adw-button-row.d.ts +2 -1
  17. package/lib/types/elements/adw-card.d.ts +2 -1
  18. package/lib/types/elements/adw-carousel.d.ts +20 -3
  19. package/lib/types/elements/adw-clamp-scrollable.d.ts +2 -1
  20. package/lib/types/elements/adw-clamp.d.ts +2 -1
  21. package/lib/types/elements/adw-combo-row.d.ts +6 -1
  22. package/lib/types/elements/adw-data-grid.d.ts +2 -1
  23. package/lib/types/elements/adw-dialog.d.ts +2 -1
  24. package/lib/types/elements/adw-entry-row.d.ts +2 -1
  25. package/lib/types/elements/adw-expander-row.d.ts +2 -1
  26. package/lib/types/elements/adw-header-bar.d.ts +2 -1
  27. package/lib/types/elements/adw-inline-view-switcher.d.ts +3 -2
  28. package/lib/types/elements/adw-layout-slot.d.ts +2 -1
  29. package/lib/types/elements/adw-multi-layout-view.d.ts +2 -1
  30. package/lib/types/elements/adw-navigation-split-view.d.ts +2 -1
  31. package/lib/types/elements/adw-navigation-view.d.ts +3 -2
  32. package/lib/types/elements/adw-overlay-split-view.d.ts +2 -1
  33. package/lib/types/elements/adw-preferences-dialog.d.ts +5 -4
  34. package/lib/types/elements/adw-preferences-group.d.ts +2 -1
  35. package/lib/types/elements/adw-preferences-row.d.ts +2 -1
  36. package/lib/types/elements/adw-shortcut-label.d.ts +2 -1
  37. package/lib/types/elements/adw-shortcuts-item.d.ts +2 -1
  38. package/lib/types/elements/adw-shortcuts-section.d.ts +2 -1
  39. package/lib/types/elements/adw-sidebar.d.ts +4 -3
  40. package/lib/types/elements/adw-spin-row.d.ts +2 -1
  41. package/lib/types/elements/adw-spinner.d.ts +2 -1
  42. package/lib/types/elements/adw-split-button.d.ts +2 -1
  43. package/lib/types/elements/adw-status-page.d.ts +2 -1
  44. package/lib/types/elements/adw-switch-row.d.ts +4 -1
  45. package/lib/types/elements/adw-tab-bar.d.ts +2 -1
  46. package/lib/types/elements/adw-tab-button.d.ts +2 -1
  47. package/lib/types/elements/adw-tab-overview.d.ts +2 -1
  48. package/lib/types/elements/adw-tab-view.d.ts +3 -2
  49. package/lib/types/elements/adw-toast-overlay.d.ts +2 -1
  50. package/lib/types/elements/adw-toggle-group.d.ts +3 -2
  51. package/lib/types/elements/adw-toolbar-view.d.ts +2 -1
  52. package/lib/types/elements/adw-view-stack.d.ts +3 -1
  53. package/lib/types/elements/adw-view-switcher-bar.d.ts +2 -1
  54. package/lib/types/elements/adw-view-switcher-sidebar.d.ts +2 -1
  55. package/lib/types/elements/adw-view-switcher.d.ts +3 -2
  56. package/lib/types/elements/adw-window-title.d.ts +2 -1
  57. package/lib/types/elements/adw-wrap-box.d.ts +2 -1
  58. package/lib/types/elements/checks.d.ts +16 -1
  59. package/lib/types/elements/gtk-action-bar.d.ts +2 -1
  60. package/lib/types/elements/gtk-aspect-frame.d.ts +2 -1
  61. package/lib/types/elements/gtk-box.d.ts +5 -1
  62. package/lib/types/elements/gtk-button.d.ts +5 -7
  63. package/lib/types/elements/gtk-calendar.d.ts +2 -1
  64. package/lib/types/elements/gtk-center-box.d.ts +2 -1
  65. package/lib/types/elements/gtk-color-dialog-button.d.ts +2 -1
  66. package/lib/types/elements/gtk-drag-icon.d.ts +2 -1
  67. package/lib/types/elements/gtk-drawing-area.d.ts +2 -1
  68. package/lib/types/elements/gtk-drop-down.d.ts +2 -1
  69. package/lib/types/elements/gtk-editable-label.d.ts +2 -1
  70. package/lib/types/elements/gtk-entry.d.ts +2 -1
  71. package/lib/types/elements/gtk-expander.d.ts +2 -1
  72. package/lib/types/elements/gtk-fixed.d.ts +2 -1
  73. package/lib/types/elements/gtk-flow-box-child.d.ts +2 -1
  74. package/lib/types/elements/gtk-flow-box.d.ts +2 -1
  75. package/lib/types/elements/gtk-font-dialog-button.d.ts +2 -1
  76. package/lib/types/elements/gtk-frame.d.ts +2 -1
  77. package/lib/types/elements/gtk-gl-area.d.ts +2 -1
  78. package/lib/types/elements/gtk-graphics-offload.d.ts +2 -1
  79. package/lib/types/elements/gtk-grid.d.ts +2 -1
  80. package/lib/types/elements/gtk-header-bar.d.ts +2 -1
  81. package/lib/types/elements/gtk-image.d.ts +5 -6
  82. package/lib/types/elements/gtk-inscription.d.ts +2 -1
  83. package/lib/types/elements/gtk-label.d.ts +10 -3
  84. package/lib/types/elements/gtk-level-bar.d.ts +2 -1
  85. package/lib/types/elements/gtk-list-box-row.d.ts +2 -1
  86. package/lib/types/elements/gtk-list-box.d.ts +2 -1
  87. package/lib/types/elements/gtk-list-view.d.ts +2 -1
  88. package/lib/types/elements/gtk-media-controls.d.ts +2 -1
  89. package/lib/types/elements/gtk-menu-button.d.ts +2 -1
  90. package/lib/types/elements/gtk-notebook.d.ts +2 -1
  91. package/lib/types/elements/gtk-overlay.d.ts +2 -1
  92. package/lib/types/elements/gtk-paned.d.ts +2 -1
  93. package/lib/types/elements/gtk-picture.d.ts +2 -1
  94. package/lib/types/elements/gtk-popover-bin.d.ts +2 -1
  95. package/lib/types/elements/gtk-popover-menu-bar.d.ts +2 -1
  96. package/lib/types/elements/gtk-popover.d.ts +2 -1
  97. package/lib/types/elements/gtk-progress-bar.d.ts +2 -1
  98. package/lib/types/elements/gtk-revealer.d.ts +2 -1
  99. package/lib/types/elements/gtk-scale-button.d.ts +2 -1
  100. package/lib/types/elements/gtk-scale.d.ts +2 -1
  101. package/lib/types/elements/gtk-scrollbar.d.ts +2 -1
  102. package/lib/types/elements/gtk-scrolled-window.d.ts +2 -1
  103. package/lib/types/elements/gtk-search-bar.d.ts +2 -1
  104. package/lib/types/elements/gtk-separator.d.ts +2 -1
  105. package/lib/types/elements/gtk-spin-button.d.ts +2 -1
  106. package/lib/types/elements/gtk-spinner.d.ts +2 -1
  107. package/lib/types/elements/gtk-stack-page.d.ts +2 -1
  108. package/lib/types/elements/gtk-stack-sidebar.d.ts +2 -1
  109. package/lib/types/elements/gtk-stack-switcher.d.ts +2 -1
  110. package/lib/types/elements/gtk-stack.d.ts +2 -1
  111. package/lib/types/elements/gtk-switch.d.ts +2 -1
  112. package/lib/types/elements/gtk-text-view.d.ts +2 -1
  113. package/lib/types/elements/gtk-text.d.ts +2 -1
  114. package/lib/types/elements/gtk-tree-expander.d.ts +2 -1
  115. package/lib/types/elements/gtk-video.d.ts +2 -1
  116. package/lib/types/elements/gtk-viewport.d.ts +2 -1
  117. package/lib/types/elements/gtk-window-controls.d.ts +2 -1
  118. package/lib/types/elements/gtk-window-handle.d.ts +2 -1
  119. package/lib/types/elements/gtk-window.d.ts +2 -1
  120. package/lib/types/gobject-elements.d.ts +7 -1
  121. package/lib/types/gtksource/gtk-source-view.d.ts +2 -1
  122. package/lib/types/{icon-registry.spec.d.ts → icon-masks.spec.d.ts} +1 -1
  123. package/lib/types/icon-theme.d.ts +15 -35
  124. package/lib/types/index.d.ts +1 -2
  125. package/lib/types/namespace/gdk.d.ts +1 -0
  126. package/lib/types/namespace/gio.d.ts +1 -0
  127. package/lib/types/namespace/glib.d.ts +2 -1
  128. package/lib/types/signals.d.ts +5 -1
  129. package/lib/types/source-view/adw-source-view.d.ts +2 -1
  130. package/lib/types/styles.generated.d.ts +1 -1
  131. package/lib/types/widget-element.d.ts +25 -0
  132. package/lib/types/widget-map.spec.d.ts +1 -0
  133. package/lib/types/widget-mapping.d.ts +7 -0
  134. package/package.json +12 -12
  135. package/scss/_about_dialog.scss +46 -1
  136. package/scss/_checks.scss +5 -2
  137. package/scss/_icon.scss +3 -4
  138. package/scss/_labels.scss +2 -2
  139. package/scss/_overlay_split_view.scss +10 -0
  140. package/scss/_scrolled_window.scss +15 -0
  141. package/scss/_widget.scss +5 -1
  142. package/src/accessible.ts +29 -0
  143. package/src/adw-about-dialog.spec.ts +81 -12
  144. package/src/adw-action-rows.spec.ts +2 -2
  145. package/src/adw-button-content.spec.ts +1 -1
  146. package/src/adw-carousel.spec.ts +49 -1
  147. package/src/capabilities.mjs +1 -0
  148. package/src/checks.spec.ts +51 -1
  149. package/src/compute-expand.spec.ts +186 -0
  150. package/src/compute-expand.ts +134 -0
  151. package/src/construct-vectors.spec.ts +46 -1
  152. package/src/elements/adw-about-dialog.ts +152 -9
  153. package/src/elements/adw-action-row.ts +2 -1
  154. package/src/elements/adw-alert-dialog.ts +3 -2
  155. package/src/elements/adw-avatar.ts +2 -1
  156. package/src/elements/adw-banner.ts +2 -1
  157. package/src/elements/adw-bin.ts +2 -1
  158. package/src/elements/adw-bottom-sheet.ts +5 -4
  159. package/src/elements/adw-breakpoint-bin.ts +2 -1
  160. package/src/elements/adw-button-content.ts +2 -1
  161. package/src/elements/adw-button-row.ts +2 -1
  162. package/src/elements/adw-card.ts +2 -1
  163. package/src/elements/adw-carousel.ts +62 -3
  164. package/src/elements/adw-clamp-scrollable.ts +2 -1
  165. package/src/elements/adw-clamp.ts +2 -1
  166. package/src/elements/adw-combo-row.ts +15 -1
  167. package/src/elements/adw-data-grid.ts +2 -1
  168. package/src/elements/adw-dialog.ts +2 -1
  169. package/src/elements/adw-entry-row.ts +2 -1
  170. package/src/elements/adw-expander-row.ts +2 -1
  171. package/src/elements/adw-header-bar.ts +2 -1
  172. package/src/elements/adw-inline-view-switcher.ts +3 -2
  173. package/src/elements/adw-layout-slot.ts +2 -1
  174. package/src/elements/adw-multi-layout-view.ts +2 -1
  175. package/src/elements/adw-navigation-split-view.ts +2 -1
  176. package/src/elements/adw-navigation-view.ts +3 -2
  177. package/src/elements/adw-overlay-split-view.ts +2 -1
  178. package/src/elements/adw-preferences-dialog.ts +6 -4
  179. package/src/elements/adw-preferences-group.ts +2 -1
  180. package/src/elements/adw-preferences-row.ts +2 -1
  181. package/src/elements/adw-shortcut-label.ts +2 -1
  182. package/src/elements/adw-shortcuts-item.ts +2 -1
  183. package/src/elements/adw-shortcuts-section.ts +2 -1
  184. package/src/elements/adw-sidebar.ts +4 -3
  185. package/src/elements/adw-spin-row.ts +2 -1
  186. package/src/elements/adw-spinner.ts +2 -1
  187. package/src/elements/adw-split-button.ts +2 -1
  188. package/src/elements/adw-status-page.ts +2 -1
  189. package/src/elements/adw-switch-row.ts +10 -1
  190. package/src/elements/adw-tab-bar.ts +2 -1
  191. package/src/elements/adw-tab-button.ts +2 -1
  192. package/src/elements/adw-tab-overview.ts +2 -1
  193. package/src/elements/adw-tab-view.ts +3 -2
  194. package/src/elements/adw-toast-overlay.ts +2 -1
  195. package/src/elements/adw-toggle-group.ts +3 -2
  196. package/src/elements/adw-toolbar-view.ts +2 -1
  197. package/src/elements/adw-view-stack.ts +39 -1
  198. package/src/elements/adw-view-switcher-bar.ts +2 -1
  199. package/src/elements/adw-view-switcher-sidebar.ts +2 -1
  200. package/src/elements/adw-view-switcher.ts +3 -2
  201. package/src/elements/adw-window-title.ts +2 -1
  202. package/src/elements/adw-wrap-box.ts +2 -1
  203. package/src/elements/checks.ts +85 -6
  204. package/src/elements/gtk-action-bar.ts +2 -1
  205. package/src/elements/gtk-aspect-frame.ts +2 -1
  206. package/src/elements/gtk-box.ts +56 -1
  207. package/src/elements/gtk-button.ts +10 -22
  208. package/src/elements/gtk-calendar.ts +2 -1
  209. package/src/elements/gtk-center-box.ts +2 -1
  210. package/src/elements/gtk-color-dialog-button.ts +2 -1
  211. package/src/elements/gtk-drag-icon.ts +2 -1
  212. package/src/elements/gtk-drawing-area.ts +2 -1
  213. package/src/elements/gtk-drop-down.ts +2 -1
  214. package/src/elements/gtk-editable-label.ts +2 -1
  215. package/src/elements/gtk-entry.ts +2 -1
  216. package/src/elements/gtk-expander.ts +2 -1
  217. package/src/elements/gtk-fixed.ts +2 -1
  218. package/src/elements/gtk-flow-box-child.ts +2 -1
  219. package/src/elements/gtk-flow-box.ts +2 -1
  220. package/src/elements/gtk-font-dialog-button.ts +2 -1
  221. package/src/elements/gtk-frame.ts +2 -1
  222. package/src/elements/gtk-gl-area.ts +2 -1
  223. package/src/elements/gtk-graphics-offload.ts +2 -1
  224. package/src/elements/gtk-grid.ts +2 -1
  225. package/src/elements/gtk-header-bar.ts +2 -1
  226. package/src/elements/gtk-image.ts +14 -15
  227. package/src/elements/gtk-inscription.ts +2 -1
  228. package/src/elements/gtk-label.ts +12 -5
  229. package/src/elements/gtk-level-bar.ts +2 -1
  230. package/src/elements/gtk-list-box-row.ts +2 -1
  231. package/src/elements/gtk-list-box.ts +2 -1
  232. package/src/elements/gtk-list-view.ts +2 -1
  233. package/src/elements/gtk-media-controls.ts +2 -1
  234. package/src/elements/gtk-menu-button.ts +2 -1
  235. package/src/elements/gtk-notebook.ts +2 -1
  236. package/src/elements/gtk-overlay.ts +2 -1
  237. package/src/elements/gtk-paned.ts +2 -1
  238. package/src/elements/gtk-picture.ts +2 -1
  239. package/src/elements/gtk-popover-bin.ts +2 -1
  240. package/src/elements/gtk-popover-menu-bar.ts +2 -1
  241. package/src/elements/gtk-popover.ts +2 -1
  242. package/src/elements/gtk-progress-bar.ts +2 -1
  243. package/src/elements/gtk-revealer.ts +2 -1
  244. package/src/elements/gtk-scale-button.ts +2 -1
  245. package/src/elements/gtk-scale.ts +2 -1
  246. package/src/elements/gtk-scrollbar.ts +2 -1
  247. package/src/elements/gtk-scrolled-window.ts +8 -5
  248. package/src/elements/gtk-search-bar.ts +2 -1
  249. package/src/elements/gtk-separator.ts +2 -1
  250. package/src/elements/gtk-spin-button.ts +2 -1
  251. package/src/elements/gtk-spinner.ts +2 -1
  252. package/src/elements/gtk-stack-page.ts +2 -1
  253. package/src/elements/gtk-stack-sidebar.ts +2 -1
  254. package/src/elements/gtk-stack-switcher.ts +2 -1
  255. package/src/elements/gtk-stack.ts +2 -1
  256. package/src/elements/gtk-switch.ts +2 -1
  257. package/src/elements/gtk-text-view.ts +2 -1
  258. package/src/elements/gtk-text.ts +2 -1
  259. package/src/elements/gtk-tree-expander.ts +2 -1
  260. package/src/elements/gtk-video.ts +2 -1
  261. package/src/elements/gtk-viewport.ts +2 -1
  262. package/src/elements/gtk-window-controls.ts +2 -1
  263. package/src/elements/gtk-window-handle.ts +2 -1
  264. package/src/elements/gtk-window.ts +2 -1
  265. package/src/gio.spec.ts +13 -3
  266. package/src/glib.spec.ts +9 -0
  267. package/src/gobject-elements.ts +18 -4
  268. package/src/gtk-label.spec.ts +39 -0
  269. package/src/gtk-scrolled-window.spec.ts +6 -6
  270. package/src/gtk-value-doors.spec.ts +19 -0
  271. package/src/gtk-window.spec.ts +2 -2
  272. package/src/gtksource/gtk-source-view.ts +2 -1
  273. package/src/{icon-registry.spec.ts → icon-masks.spec.ts} +4 -100
  274. package/src/icon-theme.spec.ts +69 -124
  275. package/src/icon-theme.ts +29 -119
  276. package/src/index.ts +3 -7
  277. package/src/namespace/gdk.ts +1 -0
  278. package/src/namespace/gio.ts +8 -0
  279. package/src/namespace/glib.ts +4 -0
  280. package/src/shared-tree-builder.ts +26 -3
  281. package/src/signals.ts +11 -2
  282. package/src/source-view/adw-source-view.ts +2 -1
  283. package/src/split-button.spec.ts +1 -1
  284. package/src/style-manager.spec.ts +13 -0
  285. package/src/style-manager.ts +6 -0
  286. package/src/styles.generated.ts +1 -1
  287. package/src/test.browser.mts +6 -2
  288. package/src/widget-element.ts +75 -0
  289. package/src/widget-map.spec.ts +116 -0
  290. package/src/widget-mapping.ts +100 -0
  291. package/src/widget-visible.spec.ts +44 -0
  292. package/lib/types/icon-registry.d.ts +0 -37
  293. package/src/icon-registry.ts +0 -163
@@ -0,0 +1,25 @@
1
+ import { type DispatchedSignals } from './signals.js';
2
+ export declare class WidgetElement extends HTMLElement {
3
+ /** `Gtk.Widget::map` / `::unmap`, which every subclass inherits (`dispatchedSignalsOf`). */
4
+ static readonly signals: DispatchedSignals;
5
+ /** `Gtk.Widget:visible`. */
6
+ get visible(): boolean;
7
+ set visible(value: boolean);
8
+ /** `gtk_widget_get_visible`. */
9
+ get_visible(): boolean;
10
+ /** `gtk_widget_set_visible`. */
11
+ set_visible(visible: boolean): void;
12
+ /** `gtk_widget_get_mapped`: on screen, which is in the document and rendered. */
13
+ get_mapped(): boolean;
14
+ }
15
+ export declare class TooltipElement extends WidgetElement {
16
+ /** `Gtk.Widget:tooltip-text`, the `tooltip-text` attribute; `null` while unset. */
17
+ get tooltip_text(): string | null;
18
+ set tooltip_text(value: string | null);
19
+ get tooltipText(): string | null;
20
+ set tooltipText(value: string | null);
21
+ /** `gtk_widget_get_tooltip_text`. */
22
+ get_tooltip_text(): string | null;
23
+ /** `gtk_widget_set_tooltip_text`. */
24
+ set_tooltip_text(text: string | null): void;
25
+ }
@@ -0,0 +1 @@
1
+ export declare const WidgetMapTest: () => Promise<void>;
@@ -0,0 +1,7 @@
1
+ /** `gtk_widget_get_mapped`: in the document, and rendered. */
2
+ export declare function isMapped(el: Element): boolean;
3
+ /**
4
+ * Watches `el` for `map` / `unmap` while the returned function has not been called. Its present
5
+ * state is recorded and not emitted, as connecting a handler in GTK emits nothing.
6
+ */
7
+ export declare function watchMapping(el: HTMLElement): () => void;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gjsify/adwaita-web",
3
- "version": "0.64.2-next.252",
3
+ "version": "0.64.2-next.255",
4
4
  "description": "Adwaita/Libadwaita web components for browser targets",
5
5
  "type": "module",
6
6
  "main": "./src/index.ts",
@@ -58,14 +58,14 @@
58
58
  "@codemirror/language": "^6.12.4",
59
59
  "@codemirror/state": "^6.7.0",
60
60
  "@codemirror/view": "^6.43.4",
61
- "@gjsify/adwaita-core": "0.64.2-next.252",
62
- "@gjsify/adwaita-fonts": "0.64.2-next.252",
63
- "@gjsify/adwaita-icons": "0.64.2-next.252",
64
- "@gjsify/gtksource-core": "0.64.2-next.252",
61
+ "@gjsify/adwaita-core": "0.64.2-next.255",
62
+ "@gjsify/adwaita-fonts": "0.64.2-next.255",
63
+ "@gjsify/adwaita-icons": "0.64.2-next.255",
64
+ "@gjsify/gtksource-core": "0.64.2-next.255",
65
65
  "@lezer/highlight": "^1.2.3"
66
66
  },
67
67
  "peerDependencies": {
68
- "@gjsify/app-settings": "0.64.2-next.252"
68
+ "@gjsify/app-settings": "0.64.2-next.255"
69
69
  },
70
70
  "peerDependenciesMeta": {
71
71
  "@gjsify/app-settings": {
@@ -73,11 +73,11 @@
73
73
  }
74
74
  },
75
75
  "devDependencies": {
76
- "@gjsify/app-settings": "0.64.2-next.252",
77
- "@gjsify/blueprint": "0.64.2-next.252",
78
- "@gjsify/cli": "0.64.2-next.252",
79
- "@gjsify/unit": "0.64.2-next.252",
80
- "@gjsify/vite-plugin-blueprint": "0.64.2-next.252",
76
+ "@gjsify/app-settings": "0.64.2-next.255",
77
+ "@gjsify/blueprint": "0.64.2-next.255",
78
+ "@gjsify/cli": "0.64.2-next.255",
79
+ "@gjsify/unit": "0.64.2-next.255",
80
+ "@gjsify/vite-plugin-blueprint": "0.64.2-next.255",
81
81
  "sass": "^1.101.0",
82
82
  "typescript": "^6.0.3"
83
83
  },
@@ -115,5 +115,5 @@
115
115
  "url": "https://github.com/gjsify/gjsify/issues"
116
116
  },
117
117
  "homepage": "https://github.com/gjsify/gjsify/tree/main/packages/web/adwaita-web#readme",
118
- "gitHead": "3853c65f772d30460e3894ff08a6079a70d7b206"
118
+ "gitHead": "6c88ac780b9742fce781e9b35aa2f45c125d8064"
119
119
  }
@@ -63,7 +63,9 @@ adw-about-dialog {
63
63
  }
64
64
  }
65
65
 
66
- // The navigation view fills the sheet; each page is a column.
66
+ // The toast overlay (template `toast_overlay`) and the navigation view inside it
67
+ // fill the sheet; each page is a column.
68
+ adw-toast-overlay,
67
69
  adw-navigation-view,
68
70
  .adw-navigation-view-pages,
69
71
  .adw-navigation-page {
@@ -213,6 +215,49 @@ adw-about-dialog {
213
215
  white-space: pre-wrap;
214
216
  }
215
217
 
218
+ // --- What's New: the release-notes buffer (a GtkTextView with its text tags) ---
219
+ // Reference: adw-about-dialog.ui (release_notes_buffer tags: heading, em, code, bullet)
220
+ .adw-about-dialog-release-notes {
221
+ margin: var(--spacing-s) 0 0;
222
+ font-size: var(--font-size-base);
223
+ line-height: 1.5;
224
+ white-space: pre-wrap;
225
+
226
+ [data-tag='heading'] {
227
+ font-weight: 800;
228
+ font-size: 1.2em;
229
+ }
230
+
231
+ [data-tag='em'] {
232
+ font-style: italic;
233
+ }
234
+
235
+ [data-tag='code'] {
236
+ font-family: var(--monospace-font-family);
237
+ }
238
+
239
+ [data-tag='bullet'] {
240
+ opacity: var(--dim-opacity);
241
+ }
242
+ }
243
+
244
+ // --- Troubleshooting → Debugging Information ---
245
+ .adw-about-dialog-debug-info {
246
+ margin: var(--spacing-s) 0 0;
247
+ padding: var(--spacing-s);
248
+ font-family: var(--monospace-font-family);
249
+ font-size: var(--font-size-small);
250
+ white-space: pre-wrap;
251
+ overflow-wrap: anywhere;
252
+ border-radius: var(--card-radius);
253
+ background-color: var(--card-bg-color);
254
+ }
255
+
256
+ .adw-about-dialog-copy {
257
+ align-self: center;
258
+ margin-top: var(--spacing-m);
259
+ }
260
+
216
261
  .adw-about-dialog-copyright {
217
262
  margin: var(--spacing-s) 0 0;
218
263
  font-size: var(--font-size-small);
package/scss/_checks.scss CHANGED
@@ -183,7 +183,8 @@ gtk-check-button .adw-check-indicator {
183
183
  }
184
184
 
185
185
  // `radio { border-radius: 100% }` (:73-74)
186
- adw-radio .adw-check-indicator {
186
+ adw-radio .adw-check-indicator,
187
+ gtk-check-button[radio] .adw-check-indicator {
187
188
  border-radius: 100%;
188
189
  }
189
190
 
@@ -194,7 +195,8 @@ gtk-check-button[checked] .adw-check-indicator::after {
194
195
  -webkit-mask-image: $check-glyph;
195
196
  }
196
197
 
197
- adw-radio[checked] .adw-check-indicator::after {
198
+ adw-radio[checked] .adw-check-indicator::after,
199
+ gtk-check-button[radio][checked] .adw-check-indicator::after {
198
200
  background-color: currentColor;
199
201
  mask-image: $bullet-glyph;
200
202
  -webkit-mask-image: $bullet-glyph;
@@ -206,6 +208,7 @@ adw-radio[checked] .adw-check-indicator::after {
206
208
  // specificity, same outcome here — and the same precedence `resolveCheckState`
207
209
  // in `@gjsify/adwaita-core` encodes for the a11y value.
208
210
  gtk-check-button[indeterminate] .adw-check-indicator::after,
211
+ gtk-check-button[radio][indeterminate] .adw-check-indicator::after,
209
212
  adw-radio[indeterminate] .adw-check-indicator::after {
210
213
  background-color: currentColor;
211
214
  mask-image: $dash-glyph;
package/scss/_icon.scss CHANGED
@@ -76,7 +76,7 @@
76
76
  // specificity this rule would come last and override every generated mask class
77
77
  // — every icon in the package would draw the broken glyph. `:where()` scores
78
78
  // 0,0,0, so ANY `.adw-icon--<name>` rule beats it wherever it sits in the
79
- // cascade, including one `registerIcon()` inserts at runtime.
79
+ // cascade.
80
80
  :where(.adw-icon) {
81
81
  mask-image: var(--icon-image-missing);
82
82
  -webkit-mask-image: var(--icon-image-missing);
@@ -97,9 +97,8 @@
97
97
  background-color: transparent;
98
98
  }
99
99
 
100
- // A FULL-COLOUR icon — what `registerColorIcon()` registers and `<gtk-image>` resolves a
101
- // name to before (or, for `-symbolic` names, after) the symbolic glyph, in the order GTK's
102
- // theme tries them. It is drawn as-is, the way GTK draws `hicolor/…/apps/<app-id>.svg`: no
100
+ // A FULL-COLOUR icon — a resource file `<gtk-image>` resolves a name to after the theme's
101
+ // symbolic glyph, in the order GTK's theme tries them. It is drawn as-is, the way GTK draws `hicolor/…/apps/<app-id>.svg`: no
103
102
  // mask and no `currentColor` fill, only the image the element puts in `background-image`.
104
103
  //
105
104
  // The modifier is NOT `adw-icon--…`, so the rule above never sees it as a mask class.
package/scss/_labels.scss CHANGED
@@ -104,8 +104,8 @@ gtk-label {
104
104
  // both cases need the same span and the same measurement pass.
105
105
  .adw-label-text {
106
106
  display: block;
107
- // A pinned width, or a shrink-to-fit one, may never push the label wider than its
108
- // container.
107
+ // A shrink-to-fit width may never push the label wider than its container.
108
+ // `gtk-label.ts`'s measured cap replaces this inline as `min(100%, <width>px)`.
109
109
  max-width: 100%;
110
110
  }
111
111
 
@@ -71,6 +71,16 @@ adw-overlay-split-view {
71
71
  align-self: stretch;
72
72
  }
73
73
 
74
+ // Both panes are AdwBins in the C (`content_bin` / `sidebar_bin`,
75
+ // adw-overlay-split-view.c:1127-1138), allocated the pane's full height (:573-610,
76
+ // :654-690) — so the pane's widget fills it, as `_bin.scss` does for `<adw-bin>`.
77
+ .adw-osv-content,
78
+ .adw-osv-sidebar {
79
+ > :only-child {
80
+ flex: 1 1 auto;
81
+ }
82
+ }
83
+
74
84
  // Docked — the sidebar sits in the flex row and the hidden part is taken off
75
85
  // its own edge by a negative margin the element computes.
76
86
  &:not(.collapsed) .adw-osv-sidebar {
@@ -52,8 +52,23 @@ gtk-scrolled-window {
52
52
  flex: 1 1 0%;
53
53
  overflow: hidden;
54
54
 
55
+ // THE CHILD IS NOT PART OF THE REQUEST on a scrolling axis: `gtk_scrolled_window_measure`
56
+ // reports `min-content-*` (default 0) plus the bars (gtkscrolledwindow.c:1821-1960), and adds
57
+ // the child's minimum only under a NEVER policy and its natural only with
58
+ // `propagate-natural-*` — which `_sync()` writes as an inline `width` / `height`. A zero
59
+ // size with `min-*: 100%` is that request in grid terms: a percentage is cyclic while the
60
+ // tracks are sized, so the item contributes nothing, and at layout it resolves against the
61
+ // cell and fills it. Without it the cell grew to the content's height, a window in a 600px
62
+ // box measured 2229px and had nothing left to scroll. `max-*: 100%` keeps a `max-content`
63
+ // request from overflowing the cell it asked for.
55
64
  > gtk-viewport {
56
65
  grid-area: 1 / 1;
66
+ width: 0;
67
+ height: 0;
68
+ min-width: 100%;
69
+ min-height: 100%;
70
+ max-width: 100%;
71
+ max-height: 100%;
57
72
  }
58
73
 
59
74
  // The vertical bar spans BOTH rows, which is `gtk_widget_size_allocate` giving it the
package/scss/_widget.scss CHANGED
@@ -50,8 +50,12 @@
50
50
  margin-block: auto;
51
51
  }
52
52
 
53
+ // `data-computed-*` is `gtk_widget_compute_expand` for a child that authored no value: a bin
54
+ // whose descendant expands grows too (gtkboxlayout.c:793). `gtk-box.ts` writes it.
53
55
  gtk-box:not([orientation='vertical']) > [hexpand]:not([hexpand='false']),
54
- gtk-box[orientation='vertical'] > [vexpand]:not([vexpand='false']) {
56
+ gtk-box[orientation='vertical'] > [vexpand]:not([vexpand='false']),
57
+ gtk-box:not([orientation='vertical']) > [data-computed-hexpand],
58
+ gtk-box[orientation='vertical'] > [data-computed-vexpand] {
55
59
  flex-grow: 1;
56
60
  }
57
61
 
@@ -0,0 +1,29 @@
1
+ // The accessible name and description of a widget whose ROLE lives on an inner control.
2
+ //
3
+ // A `.blp`'s `accessibility { label: …; description: …; }` reaches this renderer as the host's
4
+ // `aria-label` / `aria-description` (`shared-tree-builder.ts`). Where the host itself carries
5
+ // the role that is the whole door. `<gtk-button>` and `<gtk-check-button>` do not: the role is
6
+ // on the inner `<button>` / `<input>`, and an `aria-label` on a role-less host is one no
7
+ // assistive technology reads. Those elements observe both attributes and copy them onto the
8
+ // control here, so `GTK_ACCESSIBLE_PROPERTY_LABEL` lands where GTK's lands: on the widget that
9
+ // is announced.
10
+ //
11
+ // Reference: refs/gtk/gtk/gtkaccessible.c (gtk_accessible_update_property)
12
+ // Copyright (c) GNOME contributors (GTK). LGPLv2.1+.
13
+
14
+ /** The `accessibility { }` names a host forwards: `label` and `description`, as ARIA spells them. */
15
+ export const FORWARDED_ARIA = ['aria-label', 'aria-description'] as const;
16
+
17
+ /**
18
+ * Copies the host's {@link FORWARDED_ARIA} attributes onto `control`, removing what the host
19
+ * no longer has. Returns whether the host named the control, so a caller with a fallback name
20
+ * of its own (an icon-only button) writes that only where the tree wrote none.
21
+ */
22
+ export function forwardAccessibleName(host: Element, control: Element): boolean {
23
+ for (const name of FORWARDED_ARIA) {
24
+ const value = host.getAttribute(name);
25
+ if (value === null) control.removeAttribute(name);
26
+ else control.setAttribute(name, value);
27
+ }
28
+ return host.hasAttribute('aria-label');
29
+ }
@@ -7,21 +7,27 @@
7
7
  // and `website` is the one input the Details-visibility predicate leaves OUT.
8
8
  import { describe, expect, it } from '@gjsify/unit';
9
9
 
10
- import { ADW_ABOUT_DIALOG_LABELS, stripMnemonic } from '@gjsify/adwaita-core';
10
+ import { ADW_ABOUT_DIALOG_LABELS, type ReleaseNotesSegment, type Toast, stripMnemonic } from '@gjsify/adwaita-core';
11
11
  import {
12
12
  ABOUT_DIALOG_CREDITS_LEGAL_VECTORS,
13
13
  ABOUT_DIALOG_DETAILS_VECTORS,
14
+ ABOUT_DIALOG_DOOR_VECTORS,
14
15
  ABOUT_DIALOG_HEADER_VECTORS,
15
16
  ABOUT_DIALOG_SUPPORT_VECTORS,
17
+ type AboutDialogDoorLike,
16
18
  CREDITS_SECTIONS_VECTORS,
17
19
  CREDIT_PERSON_VECTORS,
20
+ RELEASE_NOTES_VECTORS,
21
+ driveAboutDialogDoorVectors,
22
+ driveReleaseNotesVectors,
18
23
  } from '@gjsify/adwaita-core/conformance';
19
24
 
20
25
  /** The label a renderer without an accelerator layer paints for a row. */
21
26
  const label = (key: keyof typeof ADW_ABOUT_DIALOG_LABELS) => stripMnemonic(ADW_ABOUT_DIALOG_LABELS[key]);
22
27
 
23
28
  interface Mounted {
24
- dialog: HTMLElement & { developers: string[]; designers: string[]; artists: string[]; documenters: string[] };
29
+ dialog: HTMLElement &
30
+ AboutDialogDoorLike & { developers: string[]; designers: string[]; artists: string[]; documenters: string[] };
25
31
  host: HTMLElement;
26
32
  /** Every `window.open` the dialog performed, most recent last. */
27
33
  opened: string[];
@@ -157,22 +163,23 @@ export const AdwAboutDialogTest = async () => {
157
163
  });
158
164
 
159
165
  await describe('adw-about-dialog main page (update_details vectors)', async () => {
160
- // `add_link` has no counterpart on this element, so `has_custom_links`
161
- // is always FALSE here; those rows are asserted by the core suite.
162
- for (const vector of ABOUT_DIALOG_DETAILS_VECTORS.filter((row) => !row.customLinks && !row.releaseNotes)) {
163
- const { website, comments, visible, rule } = vector;
164
- await it(`website=${website} comments=${comments} — ${rule}`, () => {
166
+ for (const vector of ABOUT_DIALOG_DETAILS_VECTORS) {
167
+ const { website, comments, customLinks, releaseNotes, visible, rule } = vector;
168
+ await it(`website=${website} comments=${comments} links=${customLinks} notes=${releaseNotes} — ${rule}`, () => {
165
169
  const mounted = mount({
166
170
  'application-name': 'Builder',
167
171
  ...(website ? { website: 'https://example.org' } : {}),
168
172
  ...(comments ? { comments: 'A description.' } : {}),
173
+ ...(releaseNotes ? { 'release-notes': '<p>Hi</p>' } : {}),
169
174
  });
175
+ if (customLinks) mounted.dialog.add_link('_Docs', 'https://example.org/docs');
170
176
 
171
177
  const main = page(mounted.dialog, 'main');
172
178
  const details = page(mounted.dialog, 'details');
173
179
 
174
180
  expect({
175
181
  detailsGroup: group(mounted.dialog, 'details') !== null,
182
+ whatsNewRow: hasRow(main, label('whatsNewRow')),
176
183
  detailsRow: hasRow(main, label('detailsRow')),
177
184
  websiteRow: hasRow(main, label('websiteRow')),
178
185
  commentsLabel: details?.querySelector('.adw-about-dialog-comments') != null,
@@ -180,6 +187,7 @@ export const AdwAboutDialogTest = async () => {
180
187
  detailsWebsiteRow: hasRow(details, label('websiteRow')),
181
188
  }).toStrictEqual({
182
189
  detailsGroup: visible.detailsGroup,
190
+ whatsNewRow: visible.whatsNewRow,
183
191
  detailsRow: visible.detailsRow,
184
192
  websiteRow: visible.websiteRow,
185
193
  commentsLabel: visible.commentsLabel,
@@ -203,15 +211,14 @@ export const AdwAboutDialogTest = async () => {
203
211
  });
204
212
 
205
213
  await describe('adw-about-dialog main page (update_support vectors)', async () => {
206
- // debug-info has no counterpart here (no Troubleshooting page), so the core
207
- // suite asserts those rows.
208
- for (const vector of ABOUT_DIALOG_SUPPORT_VECTORS.filter((row) => !row.debugInfo)) {
209
- const { supportUrl, issueUrl, visible, rule } = vector;
210
- await it(`support=${supportUrl} issue=${issueUrl} — ${rule}`, () => {
214
+ for (const vector of ABOUT_DIALOG_SUPPORT_VECTORS) {
215
+ const { supportUrl, issueUrl, debugInfo, visible, rule } = vector;
216
+ await it(`support=${supportUrl} issue=${issueUrl} debug=${debugInfo} — ${rule}`, () => {
211
217
  const mounted = mount({
212
218
  'application-name': 'Builder',
213
219
  ...(supportUrl ? { 'support-url': 'https://example.org/help' } : {}),
214
220
  ...(issueUrl ? { 'issue-url': 'https://example.org/issues' } : {}),
221
+ ...(debugInfo ? { 'debug-info': 'GTK 4.20' } : {}),
215
222
  });
216
223
 
217
224
  const main = page(mounted.dialog, 'main');
@@ -219,10 +226,12 @@ export const AdwAboutDialogTest = async () => {
219
226
  supportGroup: group(mounted.dialog, 'support') !== null,
220
227
  supportRow: hasRow(main, label('supportRow')),
221
228
  issueRow: hasRow(main, label('issueRow')),
229
+ troubleshootingRow: hasRow(main, label('troubleshootingRow')),
222
230
  }).toStrictEqual({
223
231
  supportGroup: visible.supportGroup,
224
232
  supportRow: visible.supportRow,
225
233
  issueRow: visible.issueRow,
234
+ troubleshootingRow: visible.troubleshootingRow,
226
235
  });
227
236
 
228
237
  mounted.dispose();
@@ -340,6 +349,66 @@ export const AdwAboutDialogTest = async () => {
340
349
  });
341
350
  });
342
351
 
352
+ // The notes, debug and link doors, on the vectors real `gi://Adw` passes.
353
+ const doorMounts: Mounted[] = [];
354
+ const doorSubject = {
355
+ name: 'adw-about-dialog',
356
+ isOracle: false,
357
+ labels: { ...ADW_ABOUT_DIALOG_LABELS, websiteRow: label('websiteRow') },
358
+ isGLibUntranslated: true,
359
+ makeDialog(): AboutDialogDoorLike {
360
+ const mounted = mount({ 'application-name': 'Builder' });
361
+ doorMounts.push(mounted);
362
+ return mounted.dialog;
363
+ },
364
+ whatsNew(dialog: AboutDialogDoorLike): ReleaseNotesSegment[] {
365
+ const notes =
366
+ page(dialog as Mounted['dialog'], 'whatsnew')?.querySelectorAll(
367
+ '.adw-about-dialog-release-notes > span',
368
+ ) ?? [];
369
+ return [...notes].map((span) => ({
370
+ text: span.textContent ?? '',
371
+ tag: (span.dataset['tag'] ?? null) as ReleaseNotesSegment['tag'],
372
+ }));
373
+ },
374
+ isRowVisible(dialog: AboutDialogDoorLike, row: 'whatsNewRow' | 'detailsRow' | 'troubleshootingRow'): boolean {
375
+ return hasRow(page(dialog as Mounted['dialog'], 'main'), label(row));
376
+ },
377
+ debugInfoText(dialog: AboutDialogDoorLike): string {
378
+ return (dialog as Mounted['dialog']).querySelector('pre.adw-about-dialog-debug-info')?.textContent ?? '';
379
+ },
380
+ linkTitles(dialog: AboutDialogDoorLike): string[] {
381
+ return rowTitles(group(dialog as Mounted['dialog'], 'links'));
382
+ },
383
+ dispose() {
384
+ for (const mounted of doorMounts.splice(0)) mounted.dispose();
385
+ },
386
+ };
387
+ await driveReleaseNotesVectors(doorSubject, { describe, it, expect }, RELEASE_NOTES_VECTORS);
388
+ await driveAboutDialogDoorVectors(doorSubject, { describe, it, expect }, ABOUT_DIALOG_DOOR_VECTORS);
389
+
390
+ await describe('adw-about-dialog new_from_appdata and Copy Text', async () => {
391
+ await it('refuses new_from_appdata by name', () => {
392
+ const ctor = customElements.get('adw-about-dialog') as unknown as {
393
+ new_from_appdata(path: string): unknown;
394
+ };
395
+ expect(() => ctor.new_from_appdata('/org/example/App/metainfo.xml')).toThrow(
396
+ 'Adw.AboutDialog.new_from_appdata',
397
+ );
398
+ });
399
+
400
+ await it('shows the Copied toast when Copy Text copies the debug info', () => {
401
+ const mounted = mount({ 'application-name': 'Builder', 'debug-info': 'GTK 4.20' });
402
+ const copy = page(mounted.dialog, 'debuginfo')!.querySelector('.adw-about-dialog-copy') as HTMLElement;
403
+ copy.click();
404
+ const overlay = mounted.dialog.querySelector('adw-toast-overlay') as unknown as {
405
+ currentToast: Toast | null;
406
+ };
407
+ expect(overlay.currentToast?.title).toBe(ADW_ABOUT_DIALOG_LABELS.copiedToast);
408
+ mounted.dispose();
409
+ });
410
+ });
411
+
343
412
  // An opened dialog has to OCCUPY SPACE, and no other test here can see that: they
344
413
  // all read the built DOM, and all passed while the sheet measured 360×0.
345
414
  //
@@ -28,8 +28,8 @@ import {
28
28
 
29
29
  import { normalizeIconName } from '@gjsify/adwaita-core';
30
30
 
31
- import { isIconAvailable } from './icon-registry.js';
32
- import { fallbackMask, maskOf } from './icon-registry.spec.js';
31
+ import { isIconAvailable } from './icon-theme.js';
32
+ import { fallbackMask, maskOf } from './icon-masks.spec.js';
33
33
 
34
34
  import type { AdwActionRow } from './elements/adw-action-row.js';
35
35
  import type { AdwComboRow } from './elements/adw-combo-row.js';
@@ -20,7 +20,7 @@ import {
20
20
  BUTTON_CONTENT_TEXT_VECTORS,
21
21
  } from '@gjsify/adwaita-core/conformance';
22
22
  import type { AdwButtonContent } from './elements/adw-button-content.js';
23
- import { fallbackMask, maskOf } from './icon-registry.spec.js';
23
+ import { fallbackMask, maskOf } from './icon-masks.spec.js';
24
24
 
25
25
  /** Mount a button content inside a plain Adwaita button, the way the stories do. */
26
26
  function mount(attributes: Record<string, string> = {}): {
@@ -11,11 +11,13 @@ import { describe, expect, it } from '@gjsify/unit';
11
11
 
12
12
  import type { CarouselPageMeasurement } from '@gjsify/adwaita-core';
13
13
  import {
14
+ CAROUSEL_DOOR_VECTORS,
14
15
  CAROUSEL_PAGE_ALLOCATION_VECTORS,
15
16
  CAROUSEL_PAGE_AT_POSITION_VECTORS,
16
17
  CAROUSEL_PAGE_LIST_VECTORS,
18
+ driveCarouselDoorVectors,
17
19
  } from '@gjsify/adwaita-core/conformance';
18
- import type { CarouselPageOp } from '@gjsify/adwaita-core/conformance';
20
+ import type { CarouselDoorLike, CarouselPageOp } from '@gjsify/adwaita-core/conformance';
19
21
 
20
22
  /** The carousel surface this suite drives — the element's own public API. */
21
23
  interface CarouselElement extends HTMLElement {
@@ -513,4 +515,50 @@ export const AdwCarouselTest = async () => {
513
515
  host.remove();
514
516
  });
515
517
  });
518
+
519
+ // The GIR doors, on the vectors real `gi://Adw` passes. `mount` makes the animated
520
+ // scroll instant too, so `settle` waits for the rAF-throttled read-back only.
521
+ const hosts: HTMLElement[] = [];
522
+ await driveCarouselDoorVectors(
523
+ {
524
+ name: 'adw-carousel',
525
+ isOracle: false,
526
+ makeCarousel(count) {
527
+ const { carousel, host } = mount(Array.from({ length: count }, (_unused, i) => `p${i}`));
528
+ hosts.push(host);
529
+ const pages = Array.from(carousel.querySelectorAll('.adw-carousel-page')).map(
530
+ (slot) => slot.firstElementChild as HTMLElement,
531
+ );
532
+ return { carousel: carousel as unknown as CarouselDoorLike, pages };
533
+ },
534
+ makeStranger: () => card('stranger'),
535
+ async settle() {
536
+ await flush();
537
+ await flush();
538
+ },
539
+ dispose() {
540
+ for (const host of hosts.splice(0)) host.remove();
541
+ },
542
+ },
543
+ { describe, it, expect },
544
+ CAROUSEL_DOOR_VECTORS,
545
+ );
546
+
547
+ await describe('adw-carousel scroll_to before the pages are adopted', async () => {
548
+ await it('lands where a declared position would, as upstream defers it to an idle', async () => {
549
+ const carousel = document.createElement('adw-carousel') as CarouselElement & CarouselDoorLike;
550
+ carousel.style.cssText = 'display:block;width:200px;height:80px;';
551
+ const pages = ['a', 'b', 'c'].map((label) => card(label));
552
+ for (const page of pages) carousel.appendChild(page);
553
+ expect(carousel.get_n_pages()).toBe(3);
554
+ expect(carousel.get_nth_page(2)).toBe(pages[2]);
555
+ carousel.scroll_to(pages[2], false);
556
+
557
+ document.body.appendChild(carousel);
558
+ await flush();
559
+ await flush();
560
+ expect(carousel.get_position()).toBe(2);
561
+ carousel.remove();
562
+ });
563
+ });
516
564
  };
@@ -5,6 +5,7 @@
5
5
  /** @type {import('./capabilities.d.mts').capabilities} */
6
6
  export const capabilities = {
7
7
  layout: 'implemented',
8
+ accessibility: 'implemented',
8
9
  strings: 'implemented',
9
10
  responses: 'implemented',
10
11
  page: 'implemented',
@@ -12,9 +12,10 @@
12
12
  // so two scenarios sharing the literal name `colour` would share a selection.
13
13
 
14
14
  import { describe, expect, it } from '@gjsify/unit';
15
- import { RADIO_GROUP_VECTORS } from '@gjsify/adwaita-core/conformance';
15
+ import { RADIO_GROUP_VECTORS, driveCheckGroupVectors, type CheckButtonLike } from '@gjsify/adwaita-core/conformance';
16
16
 
17
17
  import type { GtkCheckButton, AdwRadio } from './elements/checks.js';
18
+ import { buildSharedTree } from './shared-tree-builder.js';
18
19
 
19
20
  function host(): HTMLElement {
20
21
  const el = document.createElement('div');
@@ -354,4 +355,53 @@ export const AdwChecksTest = async () => {
354
355
  parent.remove();
355
356
  });
356
357
  });
358
+
359
+ await describe('<gtk-check-button> group (CHECK_GROUP_VECTORS)', async () => {
360
+ await driveCheckGroupVectors(
361
+ {
362
+ name: 'adwaita-web',
363
+ isOracle: false,
364
+ make: () => mountCheckbox().el as unknown as CheckButtonLike,
365
+ activate: (button) => parts(button as unknown as HTMLElement).indicator.click(),
366
+ countToggled(button) {
367
+ let count = 0;
368
+ (button as unknown as HTMLElement).addEventListener('toggled', () => void (count += 1));
369
+ return () => count;
370
+ },
371
+ },
372
+ { describe, it, expect },
373
+ );
374
+
375
+ await it('a grouped button draws the radio and its input announces role=radio', () => {
376
+ const [a, b] = [mountCheckbox().el, mountCheckbox().el];
377
+ b.set_group(a);
378
+ expect([a.hasAttribute('radio'), parts(b).input.getAttribute('role')].join()).toBe('true,radio');
379
+ b.set_group(null);
380
+ expect([a.hasAttribute('radio'), b.hasAttribute('radio'), parts(b).input.hasAttribute('role')].join()).toBe(
381
+ 'true,false,false',
382
+ );
383
+ });
384
+
385
+ await it('a projected `group: follow` resolves by id once the tree is in the document', () => {
386
+ const tree = buildSharedTree({
387
+ tag: 'GtkBox',
388
+ children: [
389
+ { tag: 'GtkCheckButton', id: 'group-follow', props: { active: true } },
390
+ { tag: 'GtkCheckButton', id: 'group-dark', props: { group: 'group-follow' } },
391
+ ],
392
+ });
393
+ host().appendChild(tree);
394
+ const [follow, dark] = ['group-follow', 'group-dark'].map(
395
+ (id) => document.getElementById(id) as GtkCheckButton,
396
+ );
397
+ dark.set_active(true);
398
+ expect([follow.get_active(), dark.get_active()].join()).toBe('false,true');
399
+ });
400
+
401
+ await it('a group id nothing carries is refused', () => {
402
+ const el = document.createElement('gtk-check-button') as GtkCheckButton;
403
+ el.setAttribute('group', 'group-nowhere');
404
+ expect(() => (el as unknown as { connectedCallback(): void }).connectedCallback()).toThrow();
405
+ });
406
+ });
357
407
  };