@gjsify/adwaita-web 0.54.0 → 0.56.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 (479) hide show
  1. package/README.md +8 -0
  2. package/dist/adwaita-web.css +8146 -3011
  3. package/dist/adwaita-web.css.map +1 -1
  4. package/lib/types/adw-application-window.spec.d.ts +1 -0
  5. package/lib/types/adw-bin.spec.d.ts +1 -0
  6. package/lib/types/adw-breakpoint-bin.spec.d.ts +1 -0
  7. package/lib/types/adw-clamp-scrollable.spec.d.ts +1 -0
  8. package/lib/types/adw-multi-layout-view.spec.d.ts +1 -0
  9. package/lib/types/adw-preferences-row.spec.d.ts +1 -0
  10. package/lib/types/adw-shortcuts.spec.d.ts +1 -0
  11. package/lib/types/adw-status-page.spec.d.ts +1 -0
  12. package/lib/types/adw-tab-bar.spec.d.ts +1 -0
  13. package/lib/types/adw-tab-button.spec.d.ts +1 -0
  14. package/lib/types/adw-tab-overview.spec.d.ts +1 -0
  15. package/lib/types/adw-view-switcher-sidebar.spec.d.ts +1 -0
  16. package/lib/types/adw-window.spec.d.ts +1 -0
  17. package/lib/types/attributes.d.ts +19 -0
  18. package/lib/types/breakpoints.d.ts +14 -3
  19. package/lib/types/construct-vectors.spec.d.ts +1 -0
  20. package/lib/types/elements/adw-action-row.d.ts +4 -0
  21. package/lib/types/elements/adw-application-window.d.ts +27 -0
  22. package/lib/types/elements/adw-bin.d.ts +17 -0
  23. package/lib/types/elements/adw-breakpoint-bin.d.ts +67 -0
  24. package/lib/types/elements/adw-clamp-scrollable.d.ts +38 -0
  25. package/lib/types/elements/adw-combo-row.d.ts +4 -0
  26. package/lib/types/elements/adw-dialog.d.ts +10 -0
  27. package/lib/types/elements/adw-entry-row.d.ts +6 -0
  28. package/lib/types/elements/adw-expander-row.d.ts +2 -0
  29. package/lib/types/elements/adw-header-bar.d.ts +6 -0
  30. package/lib/types/elements/adw-layout-slot.d.ts +19 -0
  31. package/lib/types/elements/adw-multi-layout-view.d.ts +101 -0
  32. package/lib/types/elements/adw-overlay-split-view.d.ts +13 -0
  33. package/lib/types/elements/adw-preferences-row.d.ts +31 -0
  34. package/lib/types/elements/adw-shortcuts-dialog.d.ts +13 -0
  35. package/lib/types/elements/adw-shortcuts-item.d.ts +36 -0
  36. package/lib/types/elements/adw-shortcuts-section.d.ts +14 -0
  37. package/lib/types/elements/adw-sidebar.d.ts +8 -2
  38. package/lib/types/elements/adw-spin-row.d.ts +6 -0
  39. package/lib/types/elements/adw-switch-row.d.ts +7 -0
  40. package/lib/types/elements/adw-tab-bar.d.ts +108 -0
  41. package/lib/types/elements/adw-tab-button.d.ts +32 -0
  42. package/lib/types/elements/adw-tab-overview.d.ts +199 -0
  43. package/lib/types/elements/adw-tab-view.d.ts +19 -23
  44. package/lib/types/elements/adw-toggle-group.d.ts +17 -0
  45. package/lib/types/elements/adw-view-switcher-sidebar.d.ts +84 -0
  46. package/lib/types/elements/adw-window.d.ts +40 -0
  47. package/lib/types/elements/gtk-about-dialog.d.ts +146 -0
  48. package/lib/types/elements/gtk-application-window.d.ts +34 -0
  49. package/lib/types/elements/gtk-aspect-frame.d.ts +27 -0
  50. package/lib/types/elements/gtk-button.d.ts +9 -0
  51. package/lib/types/elements/gtk-calendar.d.ts +159 -0
  52. package/lib/types/elements/gtk-center-box.d.ts +39 -0
  53. package/lib/types/elements/gtk-color-dialog-button.d.ts +69 -0
  54. package/lib/types/elements/gtk-column-view.d.ts +50 -0
  55. package/lib/types/elements/gtk-drag-icon.d.ts +78 -0
  56. package/lib/types/elements/gtk-drawing-area.d.ts +95 -0
  57. package/lib/types/elements/gtk-editable-label.d.ts +33 -0
  58. package/lib/types/elements/gtk-emoji-chooser.d.ts +84 -0
  59. package/lib/types/elements/gtk-entry.d.ts +20 -1
  60. package/lib/types/elements/gtk-expander.d.ts +49 -0
  61. package/lib/types/elements/gtk-fixed.d.ts +13 -0
  62. package/lib/types/elements/gtk-flow-box-child.d.ts +14 -0
  63. package/lib/types/elements/gtk-flow-box.d.ts +87 -0
  64. package/lib/types/elements/gtk-font-dialog-button.d.ts +83 -0
  65. package/lib/types/elements/gtk-frame.d.ts +24 -0
  66. package/lib/types/elements/gtk-gl-area.d.ts +136 -0
  67. package/lib/types/elements/gtk-graphics-offload.d.ts +24 -0
  68. package/lib/types/elements/gtk-grid-view.d.ts +39 -0
  69. package/lib/types/elements/gtk-grid.d.ts +27 -0
  70. package/lib/types/elements/gtk-header-bar.d.ts +60 -0
  71. package/lib/types/elements/gtk-inscription.d.ts +64 -0
  72. package/lib/types/elements/gtk-label.d.ts +3 -0
  73. package/lib/types/elements/gtk-level-bar.d.ts +59 -0
  74. package/lib/types/elements/gtk-link-button.d.ts +29 -0
  75. package/lib/types/elements/gtk-list-box-row.d.ts +54 -0
  76. package/lib/types/elements/gtk-list-box.d.ts +100 -0
  77. package/lib/types/elements/gtk-list-view.d.ts +73 -0
  78. package/lib/types/elements/gtk-media-controls.d.ts +142 -0
  79. package/lib/types/elements/gtk-notebook.d.ts +148 -0
  80. package/lib/types/elements/gtk-overlay.d.ts +22 -0
  81. package/lib/types/elements/gtk-page-setup-unix-dialog.d.ts +87 -0
  82. package/lib/types/elements/gtk-paned.d.ts +121 -0
  83. package/lib/types/elements/gtk-password-entry.d.ts +27 -0
  84. package/lib/types/elements/gtk-picture.d.ts +66 -0
  85. package/lib/types/elements/gtk-popover-bin.d.ts +82 -0
  86. package/lib/types/elements/gtk-popover-menu-bar.d.ts +66 -0
  87. package/lib/types/elements/gtk-popover-menu.d.ts +83 -0
  88. package/lib/types/elements/gtk-popover.d.ts +28 -3
  89. package/lib/types/elements/gtk-print-unix-dialog.d.ts +167 -0
  90. package/lib/types/elements/gtk-revealer.d.ts +55 -0
  91. package/lib/types/elements/gtk-scale-button.d.ts +59 -0
  92. package/lib/types/elements/gtk-scale.d.ts +98 -0
  93. package/lib/types/elements/gtk-scrollbar.d.ts +124 -0
  94. package/lib/types/elements/gtk-scrolled-window.d.ts +129 -0
  95. package/lib/types/elements/gtk-search-bar.d.ts +39 -0
  96. package/lib/types/elements/gtk-search-entry.d.ts +27 -0
  97. package/lib/types/elements/gtk-separator.d.ts +10 -0
  98. package/lib/types/elements/gtk-spin-button.d.ts +94 -0
  99. package/lib/types/elements/gtk-spinner.d.ts +14 -0
  100. package/lib/types/elements/gtk-stack-sidebar.d.ts +43 -0
  101. package/lib/types/elements/gtk-stack-switcher.d.ts +58 -0
  102. package/lib/types/elements/gtk-stack.d.ts +154 -0
  103. package/lib/types/elements/gtk-switch.d.ts +4 -1
  104. package/lib/types/elements/gtk-text-view.d.ts +62 -0
  105. package/lib/types/elements/gtk-text.d.ts +45 -0
  106. package/lib/types/elements/gtk-toggle-button.d.ts +45 -0
  107. package/lib/types/elements/gtk-tree-expander.d.ts +38 -0
  108. package/lib/types/elements/gtk-video.d.ts +97 -0
  109. package/lib/types/elements/gtk-viewport.d.ts +84 -0
  110. package/lib/types/elements/gtk-window-controls.d.ts +80 -0
  111. package/lib/types/elements/gtk-window-handle.d.ts +39 -0
  112. package/lib/types/elements/gtk-window.d.ts +103 -0
  113. package/lib/types/elements/justification.d.ts +2 -0
  114. package/lib/types/elements/popover-menu.d.ts +18 -0
  115. package/lib/types/elements/roving-focus.d.ts +29 -1
  116. package/lib/types/emoji-data.d.ts +38 -0
  117. package/lib/types/font-description.d.ts +96 -0
  118. package/lib/types/gtk-about-dialog.spec.d.ts +1 -0
  119. package/lib/types/gtk-action-bar.spec.d.ts +1 -0
  120. package/lib/types/gtk-application-window.spec.d.ts +1 -0
  121. package/lib/types/gtk-aspect-frame.spec.d.ts +1 -0
  122. package/lib/types/gtk-calendar.spec.d.ts +1 -0
  123. package/lib/types/gtk-center-box.spec.d.ts +1 -0
  124. package/lib/types/gtk-color-dialog-button.spec.d.ts +1 -0
  125. package/lib/types/gtk-column-view.spec.d.ts +1 -0
  126. package/lib/types/gtk-drag-icon.spec.d.ts +1 -0
  127. package/lib/types/gtk-drawing-area.spec.d.ts +1 -0
  128. package/lib/types/gtk-editable-label.spec.d.ts +1 -0
  129. package/lib/types/gtk-emoji-chooser.spec.d.ts +1 -0
  130. package/lib/types/gtk-expander.spec.d.ts +1 -0
  131. package/lib/types/gtk-fixed.spec.d.ts +1 -0
  132. package/lib/types/gtk-flow-box.spec.d.ts +1 -0
  133. package/lib/types/gtk-font-dialog-button.spec.d.ts +1 -0
  134. package/lib/types/gtk-frame.spec.d.ts +1 -0
  135. package/lib/types/gtk-gl-area.spec.d.ts +1 -0
  136. package/lib/types/gtk-graphics-offload.spec.d.ts +1 -0
  137. package/lib/types/gtk-grid-view.spec.d.ts +1 -0
  138. package/lib/types/gtk-grid.spec.d.ts +1 -0
  139. package/lib/types/gtk-header-bar.spec.d.ts +1 -0
  140. package/lib/types/gtk-inscription.spec.d.ts +1 -0
  141. package/lib/types/gtk-level-bar.spec.d.ts +1 -0
  142. package/lib/types/gtk-link-button.spec.d.ts +1 -0
  143. package/lib/types/gtk-list-box.spec.d.ts +1 -0
  144. package/lib/types/gtk-list-view.spec.d.ts +1 -0
  145. package/lib/types/gtk-media-controls.spec.d.ts +1 -0
  146. package/lib/types/gtk-notebook.spec.d.ts +1 -0
  147. package/lib/types/gtk-overlay.spec.d.ts +1 -0
  148. package/lib/types/gtk-paned.spec.d.ts +1 -0
  149. package/lib/types/gtk-password-entry.spec.d.ts +1 -0
  150. package/lib/types/gtk-picture.spec.d.ts +1 -0
  151. package/lib/types/gtk-popover-bin.spec.d.ts +1 -0
  152. package/lib/types/gtk-popover-menu-bar.spec.d.ts +1 -0
  153. package/lib/types/gtk-popover-menu.spec.d.ts +1 -0
  154. package/lib/types/gtk-popover-role.spec.d.ts +1 -0
  155. package/lib/types/gtk-popover.spec.d.ts +1 -0
  156. package/lib/types/gtk-print-dialogs.spec.d.ts +1 -0
  157. package/lib/types/gtk-revealer.spec.d.ts +1 -0
  158. package/lib/types/gtk-scale-button.spec.d.ts +1 -0
  159. package/lib/types/gtk-scale.spec.d.ts +1 -0
  160. package/lib/types/gtk-scrollbar.spec.d.ts +1 -0
  161. package/lib/types/gtk-scrolled-window.spec.d.ts +1 -0
  162. package/lib/types/gtk-search-bar.spec.d.ts +1 -0
  163. package/lib/types/gtk-search-entry.spec.d.ts +1 -0
  164. package/lib/types/gtk-separator.spec.d.ts +1 -0
  165. package/lib/types/gtk-spin-button.spec.d.ts +1 -0
  166. package/lib/types/gtk-spinner.spec.d.ts +1 -0
  167. package/lib/types/gtk-stack-sidebar.spec.d.ts +1 -0
  168. package/lib/types/gtk-stack-switcher.spec.d.ts +1 -0
  169. package/lib/types/gtk-stack.spec.d.ts +1 -0
  170. package/lib/types/gtk-text-view.spec.d.ts +1 -0
  171. package/lib/types/gtk-text.spec.d.ts +1 -0
  172. package/lib/types/gtk-toggle-button.spec.d.ts +1 -0
  173. package/lib/types/gtk-tree-expander.spec.d.ts +1 -0
  174. package/lib/types/gtk-video.spec.d.ts +1 -0
  175. package/lib/types/gtk-viewport.spec.d.ts +1 -0
  176. package/lib/types/gtk-window-controls.spec.d.ts +1 -0
  177. package/lib/types/gtk-window-handle.spec.d.ts +1 -0
  178. package/lib/types/gtk-window.spec.d.ts +1 -0
  179. package/lib/types/index.d.ts +4 -1
  180. package/lib/types/list-view-dom.d.ts +44 -0
  181. package/lib/types/namespace/adw.d.ts +12 -0
  182. package/lib/types/namespace/gtk.d.ts +61 -0
  183. package/lib/types/page-setup.d.ts +100 -0
  184. package/lib/types/row-line-clamp.d.ts +20 -0
  185. package/lib/types/row-tooltip.d.ts +8 -0
  186. package/lib/types/row-tooltip.spec.d.ts +1 -0
  187. package/lib/types/scroll-shading.d.ts +15 -1
  188. package/lib/types/shared-tree-builder.d.ts +75 -17
  189. package/lib/types/shared-tree-mount.spec.d.ts +1 -0
  190. package/lib/types/signals.d.ts +4 -0
  191. package/lib/types/styles.generated.d.ts +1 -1
  192. package/lib/types/tab-chip.d.ts +73 -0
  193. package/lib/types/template-classes.d.ts +11 -0
  194. package/lib/types/widget-size.spec.d.ts +1 -0
  195. package/package.json +12 -8
  196. package/scss/_action_row.scss +41 -17
  197. package/scss/_application_window.scss +26 -0
  198. package/scss/_aspect_frame.scss +25 -0
  199. package/scss/_bin.scss +26 -0
  200. package/scss/_button.scss +45 -0
  201. package/scss/_button_row.scss +5 -0
  202. package/scss/_calendar.scss +176 -0
  203. package/scss/_center_box.scss +25 -0
  204. package/scss/_checks.scss +6 -1
  205. package/scss/_clamp_scrollable.scss +28 -0
  206. package/scss/_color_button.scss +67 -0
  207. package/scss/_column_view.scss +126 -0
  208. package/scss/_drag_icon.scss +55 -0
  209. package/scss/_drawing.scss +85 -0
  210. package/scss/_emoji_chooser.scss +213 -0
  211. package/scss/_entry.scss +13 -5
  212. package/scss/_entry_row.scss +1 -1
  213. package/scss/_expander.scss +113 -0
  214. package/scss/_expander_row.scss +36 -3
  215. package/scss/_fixed.scss +29 -0
  216. package/scss/_flow_box.scss +94 -0
  217. package/scss/_font_button.scss +63 -0
  218. package/scss/_frame.scss +41 -0
  219. package/scss/_grid.scss +19 -0
  220. package/scss/_grid_view.scss +46 -0
  221. package/scss/_gtk_about_dialog.scss +186 -0
  222. package/scss/_headerbar.scss +134 -1
  223. package/scss/_icons.generated.scss +186 -0
  224. package/scss/_inscription.scss +125 -0
  225. package/scss/_level_bar.scss +190 -0
  226. package/scss/_link.scss +82 -0
  227. package/scss/_list_box.scss +88 -0
  228. package/scss/_list_view.scss +96 -0
  229. package/scss/_media_controls.scss +139 -0
  230. package/scss/_overlay.scss +68 -0
  231. package/scss/_paned.scss +130 -0
  232. package/scss/_password_entry.scss +83 -0
  233. package/scss/_picture.scss +80 -0
  234. package/scss/_popover_bin.scss +53 -0
  235. package/scss/_popover_menu_bar.scss +104 -0
  236. package/scss/_preferences_row.scss +60 -0
  237. package/scss/_print_dialogs.scss +328 -0
  238. package/scss/_reset.scss +21 -19
  239. package/scss/_revealer.scss +37 -0
  240. package/scss/_row.scss +36 -5
  241. package/scss/_scale.scss +298 -0
  242. package/scss/_scale_button.scss +167 -0
  243. package/scss/_scrollbar.scss +230 -0
  244. package/scss/_scrolled_window.scss +131 -0
  245. package/scss/_search_bar.scss +118 -0
  246. package/scss/_search_entry.scss +86 -0
  247. package/scss/_separator.scss +44 -0
  248. package/scss/_shortcuts_dialog.scss +100 -0
  249. package/scss/_spin_button.scss +172 -0
  250. package/scss/_spin_row.scss +56 -8
  251. package/scss/_spinner.scss +85 -4
  252. package/scss/_stack.scss +729 -0
  253. package/scss/_status_page.scss +1 -1
  254. package/scss/_switch.scss +13 -5
  255. package/scss/_switch_row.scss +10 -0
  256. package/scss/_tab_bar.scss +317 -0
  257. package/scss/_tab_button.scss +98 -0
  258. package/scss/_tab_overview.scss +483 -0
  259. package/scss/_text.scss +182 -0
  260. package/scss/_theme.scss +1 -1
  261. package/scss/_toggle_group.scss +28 -0
  262. package/scss/_tree_expander.scss +62 -0
  263. package/scss/_variables.scss +1 -1
  264. package/scss/_video.scss +146 -0
  265. package/scss/_view_switcher_sidebar.scss +112 -0
  266. package/scss/_viewport.scss +50 -0
  267. package/scss/_widget.scss +14 -3
  268. package/scss/_window.scss +131 -2
  269. package/scss/_window_handle.scss +20 -0
  270. package/scss/adwaita-skin.scss +109 -0
  271. package/src/adw-action-rows.spec.ts +331 -0
  272. package/src/adw-application-window.spec.ts +118 -0
  273. package/src/adw-bin.spec.ts +75 -0
  274. package/src/adw-breakpoint-bin.spec.ts +324 -0
  275. package/src/adw-clamp-scrollable.spec.ts +189 -0
  276. package/src/adw-header-bar.spec.ts +18 -0
  277. package/src/adw-multi-layout-view.spec.ts +243 -0
  278. package/src/adw-preferences-row.spec.ts +164 -0
  279. package/src/adw-row-state.spec.ts +142 -0
  280. package/src/adw-shortcuts.spec.ts +155 -0
  281. package/src/adw-status-page.spec.ts +124 -0
  282. package/src/adw-tab-bar.spec.ts +287 -0
  283. package/src/adw-tab-button.spec.ts +101 -0
  284. package/src/adw-tab-overview.spec.ts +443 -0
  285. package/src/adw-view-switcher-sidebar.spec.ts +281 -0
  286. package/src/adw-window.spec.ts +129 -0
  287. package/src/attributes.ts +52 -0
  288. package/src/breakpoints.ts +25 -8
  289. package/src/capabilities.d.mts +3 -0
  290. package/src/capabilities.mjs +21 -0
  291. package/src/connect-lifecycle.spec.ts +12 -0
  292. package/src/construct-vectors.spec.ts +175 -0
  293. package/src/elements/adw-action-row.ts +31 -2
  294. package/src/elements/adw-alert-dialog.ts +4 -1
  295. package/src/elements/adw-application-window.ts +154 -0
  296. package/src/elements/adw-bin.ts +101 -0
  297. package/src/elements/adw-breakpoint-bin.ts +287 -0
  298. package/src/elements/adw-button-row.ts +7 -1
  299. package/src/elements/adw-clamp-scrollable.ts +207 -0
  300. package/src/elements/adw-combo-row.ts +26 -1
  301. package/src/elements/adw-dialog.ts +19 -0
  302. package/src/elements/adw-entry-row.ts +22 -12
  303. package/src/elements/adw-expander-row.ts +34 -1
  304. package/src/elements/adw-header-bar.ts +18 -4
  305. package/src/elements/adw-layout-slot.ts +95 -0
  306. package/src/elements/adw-multi-layout-view.ts +326 -0
  307. package/src/elements/adw-overlay-split-view.ts +29 -6
  308. package/src/elements/adw-preferences-row.ts +153 -0
  309. package/src/elements/adw-shortcuts-dialog.ts +52 -0
  310. package/src/elements/adw-shortcuts-item.ts +171 -0
  311. package/src/elements/adw-shortcuts-section.ts +86 -0
  312. package/src/elements/adw-sidebar.ts +74 -7
  313. package/src/elements/adw-spin-row.ts +37 -2
  314. package/src/elements/adw-status-page.ts +10 -2
  315. package/src/elements/adw-switch-row.ts +53 -2
  316. package/src/elements/adw-tab-bar.ts +529 -0
  317. package/src/elements/adw-tab-button.ts +194 -0
  318. package/src/elements/adw-tab-overview.ts +1011 -0
  319. package/src/elements/adw-tab-view.ts +66 -145
  320. package/src/elements/adw-toggle-group.ts +138 -14
  321. package/src/elements/adw-view-stack.ts +18 -0
  322. package/src/elements/adw-view-switcher-sidebar.ts +332 -0
  323. package/src/elements/adw-window.ts +190 -11
  324. package/src/elements/checks.ts +35 -8
  325. package/src/elements/gtk-about-dialog.ts +811 -0
  326. package/src/elements/gtk-application-window.ts +108 -0
  327. package/src/elements/gtk-aspect-frame.ts +160 -0
  328. package/src/elements/gtk-button.ts +12 -0
  329. package/src/elements/gtk-calendar.ts +757 -0
  330. package/src/elements/gtk-center-box.ts +184 -0
  331. package/src/elements/gtk-color-dialog-button.ts +278 -0
  332. package/src/elements/gtk-column-view.ts +320 -0
  333. package/src/elements/gtk-drag-icon.ts +257 -0
  334. package/src/elements/gtk-drawing-area.ts +303 -0
  335. package/src/elements/gtk-editable-label.ts +204 -0
  336. package/src/elements/gtk-emoji-chooser.ts +542 -0
  337. package/src/elements/gtk-entry.ts +39 -5
  338. package/src/elements/gtk-expander.ts +301 -0
  339. package/src/elements/gtk-fixed.ts +99 -0
  340. package/src/elements/gtk-flow-box-child.ts +68 -0
  341. package/src/elements/gtk-flow-box.ts +480 -0
  342. package/src/elements/gtk-font-dialog-button.ts +432 -0
  343. package/src/elements/gtk-frame.ts +174 -0
  344. package/src/elements/gtk-gl-area.ts +476 -0
  345. package/src/elements/gtk-graphics-offload.ts +130 -0
  346. package/src/elements/gtk-grid-view.ts +168 -0
  347. package/src/elements/gtk-grid.ts +127 -0
  348. package/src/elements/gtk-header-bar.ts +273 -0
  349. package/src/elements/gtk-inscription.ts +387 -0
  350. package/src/elements/gtk-label.ts +19 -11
  351. package/src/elements/gtk-level-bar.ts +323 -0
  352. package/src/elements/gtk-link-button.ts +138 -0
  353. package/src/elements/gtk-list-box-row.ts +195 -0
  354. package/src/elements/gtk-list-box.ts +413 -0
  355. package/src/elements/gtk-list-view.ts +370 -0
  356. package/src/elements/gtk-media-controls.ts +509 -0
  357. package/src/elements/gtk-notebook.ts +664 -0
  358. package/src/elements/gtk-overlay.ts +149 -0
  359. package/src/elements/gtk-page-setup-unix-dialog.ts +420 -0
  360. package/src/elements/gtk-paned.ts +597 -0
  361. package/src/elements/gtk-password-entry.ts +170 -0
  362. package/src/elements/gtk-picture.ts +254 -0
  363. package/src/elements/gtk-popover-bin.ts +332 -0
  364. package/src/elements/gtk-popover-menu-bar.ts +355 -0
  365. package/src/elements/gtk-popover-menu.ts +339 -0
  366. package/src/elements/gtk-popover.ts +92 -10
  367. package/src/elements/gtk-print-unix-dialog.ts +989 -0
  368. package/src/elements/gtk-progress-bar.ts +24 -11
  369. package/src/elements/gtk-revealer.ts +406 -0
  370. package/src/elements/gtk-scale-button.ts +358 -0
  371. package/src/elements/gtk-scale.ts +492 -0
  372. package/src/elements/gtk-scrollbar.ts +528 -0
  373. package/src/elements/gtk-scrolled-window.ts +653 -0
  374. package/src/elements/gtk-search-bar.ts +200 -0
  375. package/src/elements/gtk-search-entry.ts +172 -0
  376. package/src/elements/gtk-separator.ts +52 -0
  377. package/src/elements/gtk-spin-button.ts +475 -0
  378. package/src/elements/gtk-spinner.ts +126 -0
  379. package/src/elements/gtk-stack-sidebar.ts +212 -0
  380. package/src/elements/gtk-stack-switcher.ts +279 -0
  381. package/src/elements/gtk-stack.ts +748 -0
  382. package/src/elements/gtk-switch.ts +52 -19
  383. package/src/elements/gtk-text-view.ts +290 -0
  384. package/src/elements/gtk-text.ts +219 -0
  385. package/src/elements/gtk-toggle-button.ts +239 -0
  386. package/src/elements/gtk-tree-expander.ts +243 -0
  387. package/src/elements/gtk-video.ts +423 -0
  388. package/src/elements/gtk-viewport.ts +277 -0
  389. package/src/elements/gtk-window-controls.ts +341 -0
  390. package/src/elements/gtk-window-handle.ts +221 -0
  391. package/src/elements/gtk-window.ts +372 -0
  392. package/src/elements/justification.ts +24 -0
  393. package/src/elements/popover-menu.ts +24 -0
  394. package/src/elements/roving-focus.ts +53 -21
  395. package/src/emoji-data.ts +577 -0
  396. package/src/entry-rows.spec.ts +31 -0
  397. package/src/font-description.ts +238 -0
  398. package/src/gtk-about-dialog.spec.ts +250 -0
  399. package/src/gtk-action-bar.spec.ts +89 -0
  400. package/src/gtk-application-window.spec.ts +107 -0
  401. package/src/gtk-aspect-frame.spec.ts +114 -0
  402. package/src/gtk-calendar.spec.ts +589 -0
  403. package/src/gtk-center-box.spec.ts +125 -0
  404. package/src/gtk-color-dialog-button.spec.ts +141 -0
  405. package/src/gtk-column-view.spec.ts +154 -0
  406. package/src/gtk-drag-icon.spec.ts +190 -0
  407. package/src/gtk-drawing-area.spec.ts +211 -0
  408. package/src/gtk-editable-label.spec.ts +190 -0
  409. package/src/gtk-emoji-chooser.spec.ts +173 -0
  410. package/src/gtk-entry.spec.ts +23 -0
  411. package/src/gtk-expander.spec.ts +170 -0
  412. package/src/gtk-fixed.spec.ts +97 -0
  413. package/src/gtk-flow-box.spec.ts +289 -0
  414. package/src/gtk-font-dialog-button.spec.ts +166 -0
  415. package/src/gtk-frame.spec.ts +119 -0
  416. package/src/gtk-gl-area.spec.ts +361 -0
  417. package/src/gtk-graphics-offload.spec.ts +119 -0
  418. package/src/gtk-grid-view.spec.ts +106 -0
  419. package/src/gtk-grid.spec.ts +122 -0
  420. package/src/gtk-header-bar.spec.ts +202 -0
  421. package/src/gtk-inscription.spec.ts +235 -0
  422. package/src/gtk-level-bar.spec.ts +199 -0
  423. package/src/gtk-link-button.spec.ts +117 -0
  424. package/src/gtk-list-box.spec.ts +422 -0
  425. package/src/gtk-list-view.spec.ts +203 -0
  426. package/src/gtk-media-controls.spec.ts +295 -0
  427. package/src/gtk-notebook.spec.ts +546 -0
  428. package/src/gtk-overlay.spec.ts +141 -0
  429. package/src/gtk-paned.spec.ts +267 -0
  430. package/src/gtk-password-entry.spec.ts +150 -0
  431. package/src/gtk-picture.spec.ts +172 -0
  432. package/src/gtk-popover-bin.spec.ts +229 -0
  433. package/src/gtk-popover-menu-bar.spec.ts +296 -0
  434. package/src/gtk-popover-menu.spec.ts +261 -0
  435. package/src/gtk-popover-role.spec.ts +138 -0
  436. package/src/gtk-popover.spec.ts +264 -0
  437. package/src/gtk-print-dialogs.spec.ts +251 -0
  438. package/src/gtk-revealer.spec.ts +164 -0
  439. package/src/gtk-scale-button.spec.ts +218 -0
  440. package/src/gtk-scale.spec.ts +213 -0
  441. package/src/gtk-scrollbar.spec.ts +244 -0
  442. package/src/gtk-scrolled-window.spec.ts +262 -0
  443. package/src/gtk-search-bar.spec.ts +179 -0
  444. package/src/gtk-search-entry.spec.ts +142 -0
  445. package/src/gtk-separator.spec.ts +74 -0
  446. package/src/gtk-spin-button.spec.ts +186 -0
  447. package/src/gtk-spinner.spec.ts +130 -0
  448. package/src/gtk-stack-sidebar.spec.ts +217 -0
  449. package/src/gtk-stack-switcher.spec.ts +249 -0
  450. package/src/gtk-stack.spec.ts +432 -0
  451. package/src/gtk-text-view.spec.ts +189 -0
  452. package/src/gtk-text.spec.ts +163 -0
  453. package/src/gtk-toggle-button.spec.ts +186 -0
  454. package/src/gtk-tree-expander.spec.ts +201 -0
  455. package/src/gtk-video.spec.ts +240 -0
  456. package/src/gtk-viewport.spec.ts +140 -0
  457. package/src/gtk-window-controls.spec.ts +232 -0
  458. package/src/gtk-window-handle.spec.ts +158 -0
  459. package/src/gtk-window.spec.ts +202 -0
  460. package/src/index.ts +9 -1
  461. package/src/keyboard-operable.spec.ts +77 -9
  462. package/src/list-view-dom.ts +121 -0
  463. package/src/namespace/adw.ts +12 -0
  464. package/src/namespace/gtk.ts +61 -0
  465. package/src/page-setup.ts +222 -0
  466. package/src/row-line-clamp.ts +74 -0
  467. package/src/row-tooltip.spec.ts +313 -0
  468. package/src/row-tooltip.ts +52 -0
  469. package/src/scroll-shading.ts +18 -1
  470. package/src/shared-tree-builder.ts +336 -41
  471. package/src/shared-tree-mount.spec.ts +130 -0
  472. package/src/shared-trees.spec.ts +15 -0
  473. package/src/signals.ts +15 -0
  474. package/src/style-classes.spec.ts +9 -8
  475. package/src/styles.generated.ts +1 -1
  476. package/src/tab-chip.ts +200 -0
  477. package/src/template-classes.ts +45 -0
  478. package/src/test.browser.mts +160 -0
  479. package/src/widget-size.spec.ts +117 -0
@@ -0,0 +1,243 @@
1
+ // DOM-level tests for `<adw-multi-layout-view>` and the `<adw-layout-slot>` holes its
2
+ // layouts are built from.
3
+ //
4
+ // The behaviour under test is the pairing the C describes in one paragraph: every child
5
+ // has an ID, every layout has slots with IDs, and switching layouts re-inserts each
6
+ // child into the slot of the SAME id — plus the three rules around it that are easy to
7
+ // miss. `adw_multi_layout_view_add_layout` makes the FIRST layout current rather than
8
+ // waiting for a `layout-name` (:553); a `layout-name` no layout carries is a
9
+ // `g_critical` that leaves the current layout alone (:520); and `visible` is bound ONE
10
+ // way, child to slot, so hiding the child hides the hole (:151).
11
+ import { describe, expect, it } from '@gjsify/unit';
12
+
13
+ import type { AdwLayoutSlot } from './elements/adw-layout-slot.js';
14
+ import type { AdwMultiLayoutView } from './elements/adw-multi-layout-view.js';
15
+
16
+ /** Two frame callbacks — where a `ResizeObserver` delivery and a MutationObserver land. */
17
+ function settle(): Promise<void> {
18
+ return new Promise((resolve) => {
19
+ requestAnimationFrame(() => requestAnimationFrame(() => resolve()));
20
+ });
21
+ }
22
+
23
+ /**
24
+ * Two layouts over the same two children, as the C's own documentation spells it: a
25
+ * secondary pane that is a sidebar in one and the content in the other.
26
+ */
27
+ function markup(): string {
28
+ return (
29
+ '<adw-multi-layout-view layout-name="sidebar">' +
30
+ '<adw-navigation-split-view name="sidebar">' +
31
+ '<adw-layout-slot id="secondary" slot="sidebar"></adw-layout-slot>' +
32
+ '<adw-layout-slot id="primary" slot="content"></adw-layout-slot>' +
33
+ '</adw-navigation-split-view>' +
34
+ '<adw-navigation-split-view name="stacked" collapsed>' +
35
+ '<adw-layout-slot id="secondary" slot="content"></adw-layout-slot>' +
36
+ '<adw-layout-slot id="primary" slot="content"></adw-layout-slot>' +
37
+ '</adw-navigation-split-view>' +
38
+ '<adw-navigation-page slot="primary" tag="inbox" title="Inbox"></adw-navigation-page>' +
39
+ '<adw-navigation-page slot="secondary" tag="about" title="About"></adw-navigation-page>' +
40
+ '</adw-multi-layout-view>'
41
+ );
42
+ }
43
+
44
+ function mount(body: string): { view: AdwMultiLayoutView; host: HTMLElement } {
45
+ const host = document.createElement('div');
46
+ host.style.width = '800px';
47
+ host.style.height = '600px';
48
+ document.body.appendChild(host);
49
+ host.innerHTML = body;
50
+ return { view: host.querySelector('adw-multi-layout-view') as AdwMultiLayoutView, host };
51
+ }
52
+
53
+ /** Where each id's child landed in the mounted layout, `id -> slot id`. */
54
+ function placement(view: AdwMultiLayoutView): string[] {
55
+ const found: string[] = [];
56
+ for (const slot of view.querySelectorAll('adw-layout-slot')) {
57
+ for (const child of slot.children) {
58
+ found.push(`${slot.id}←${child.getAttribute('slot')}`);
59
+ }
60
+ }
61
+ return found.sort();
62
+ }
63
+
64
+ export const AdwMultiLayoutViewTest = async () => {
65
+ await describe('<adw-multi-layout-view> switching layouts', async () => {
66
+ await it('starts on the layout `layout-name` names', () => {
67
+ const { view, host } = mount(markup());
68
+ const report = `layout:${view.layoutName} parent:${view.layout?.getAttribute('name')}`;
69
+ host.remove();
70
+ expect(report).toBe('layout:sidebar parent:sidebar');
71
+ });
72
+
73
+ await it('moves each child into the slot of the SAME id', () => {
74
+ const { view, host } = mount(markup());
75
+ const before = placement(view).join(' ');
76
+ view.layoutName = 'stacked';
77
+ const after = placement(view).join(' ');
78
+ host.remove();
79
+ expect(`sidebar:${before} → stacked:${after}`).toBe(
80
+ 'sidebar:primary←primary secondary←secondary → stacked:primary←primary secondary←secondary',
81
+ );
82
+ });
83
+
84
+ await it('notifies BOTH properties on a switch, as `set_layout` does', () => {
85
+ const { view, host } = mount(markup());
86
+ const log: string[] = [];
87
+ view.addEventListener('notify::layout', () => log.push(`layout:${view.layoutName}`));
88
+ view.addEventListener('notify::layout-name', () => log.push(`name:${view.layoutName}`));
89
+ view.layoutName = 'stacked';
90
+ view.layoutName = 'stacked';
91
+ host.remove();
92
+ // Once for the change and NOT for the repeat: `set_layout` returns early when
93
+ // the layout is unchanged (adw-multi-layout-view.c:255).
94
+ expect(log.join(' | ')).toBe('layout:stacked | name:stacked');
95
+ });
96
+
97
+ await it('leaves the current layout alone for a name no layout carries', () => {
98
+ const { view, host } = mount(markup());
99
+ view.layoutName = 'nowhere';
100
+ const report = `layout:${view.layoutName} mounted:${view.layout?.getAttribute('name')}`;
101
+ host.remove();
102
+ expect(report).toBe('layout:sidebar mounted:sidebar');
103
+ });
104
+
105
+ await it('is driven by a breakpoint through the bin, and keeps the layout when it unwinds', async () => {
106
+ const host = document.createElement('div');
107
+ host.style.width = '900px';
108
+ host.style.height = '600px';
109
+ document.body.appendChild(host);
110
+ host.innerHTML =
111
+ '<adw-breakpoint-bin breakpoints=\'[{"condition":"max-width: 720px","setters":' +
112
+ '[{"target":"#view","property":"layout-name","value":"stacked"}]}]\'>' +
113
+ '<adw-multi-layout-view id="view">' +
114
+ '<adw-navigation-split-view name="sidebar">' +
115
+ '<adw-layout-slot id="primary" slot="content"></adw-layout-slot>' +
116
+ '</adw-navigation-split-view>' +
117
+ '<adw-navigation-split-view name="stacked" collapsed>' +
118
+ '<adw-layout-slot id="primary" slot="content"></adw-layout-slot>' +
119
+ '</adw-navigation-split-view>' +
120
+ '<adw-navigation-page slot="primary" title="Inbox"></adw-navigation-page>' +
121
+ '</adw-multi-layout-view>' +
122
+ '</adw-breakpoint-bin>';
123
+ const view = host.querySelector('adw-multi-layout-view') as AdwMultiLayoutView;
124
+ await settle();
125
+ const wide = view.layoutName;
126
+ host.style.width = '500px';
127
+ await settle();
128
+ const narrow = view.layoutName;
129
+ host.style.width = '900px';
130
+ await settle();
131
+ const wideAgain = view.layoutName;
132
+ host.remove();
133
+ // The restore writes `layout-name` back to what it was — which was NOTHING,
134
+ // because the markup declared no name — and `set_layout_name(NULL)` RETURNS
135
+ // without switching (adw-multi-layout-view.c:514). So the view stays on the
136
+ // layout the breakpoint put it on, exactly as it does on GTK. Restoring the
137
+ // ORIGINAL is right and it is not the same as reverting the switch.
138
+ expect(`900:${wide} → 500:${narrow} → 900:${wideAgain}`).toBe('900:sidebar → 500:stacked → 900:stacked');
139
+ });
140
+ });
141
+
142
+ await describe('<adw-multi-layout-view> children and slots', async () => {
143
+ await it('binds the slot’s visibility to the child’s, one way', async () => {
144
+ const { view, host } = mount(markup());
145
+ const child = view.getChild('primary');
146
+ const slot = view.querySelector('adw-layout-slot#primary') as HTMLElement;
147
+ const before = slot.hidden;
148
+ child?.setAttribute('hidden', '');
149
+ // The binding is a MutationObserver, so it lands a microtask later.
150
+ await settle();
151
+ const hiddenChild = slot.hidden;
152
+ (child as HTMLElement).hidden = false;
153
+ await settle();
154
+ const shownAgain = slot.hidden;
155
+ host.remove();
156
+ expect(`start:${before} child hidden:${hiddenChild} child shown:${shownAgain}`).toBe(
157
+ 'start:false child hidden:true child shown:false',
158
+ );
159
+ });
160
+
161
+ await it('reports a child by id and a layout by name', () => {
162
+ const { view, host } = mount(markup());
163
+ const report = [
164
+ `child:${view.getChild('secondary')?.getAttribute('tag')}`,
165
+ `missing:${view.getChild('nowhere') === null}`,
166
+ `layout:${view.getLayoutByName('stacked')?.getAttribute('name')}`,
167
+ `layoutless:${view.getLayoutByName('nowhere') === null}`,
168
+ ].join(' | ');
169
+ host.remove();
170
+ expect(report).toBe('child:about | missing:true | layout:stacked | layoutless:true');
171
+ });
172
+
173
+ await it('picks a child appended after connect', async () => {
174
+ const { view, host } = mount(
175
+ '<adw-multi-layout-view layout-name="sidebar">' +
176
+ '<adw-navigation-split-view name="sidebar">' +
177
+ '<adw-layout-slot id="late" slot="content"></adw-layout-slot>' +
178
+ '</adw-navigation-split-view>' +
179
+ '</adw-multi-layout-view>',
180
+ );
181
+ const child = document.createElement('adw-navigation-page');
182
+ child.setAttribute('slot', 'late');
183
+ view.appendChild(child);
184
+ await settle();
185
+ const slot = view.querySelector('adw-layout-slot#late') as HTMLElement;
186
+ const landed = slot.contains(child);
187
+ host.remove();
188
+ expect(`late child landed:${landed}`).toBe('late child landed:true');
189
+ });
190
+
191
+ await it('keeps the child in place when the layout has no slot for its id', () => {
192
+ const { view, host } = mount(
193
+ '<adw-multi-layout-view layout-name="sidebar">' +
194
+ '<adw-navigation-split-view name="sidebar">' +
195
+ '<adw-layout-slot id="primary" slot="content"></adw-layout-slot>' +
196
+ '</adw-navigation-split-view>' +
197
+ '<adw-navigation-page slot="orphan" title="Nowhere"></adw-navigation-page>' +
198
+ '</adw-multi-layout-view>',
199
+ );
200
+ // `parent_child` returns on an unmatched id (adw-multi-layout-view.c:143), and
201
+ // `unparent_child` returns on one the layout has no slot for (:175) — so the
202
+ // child is neither inserted nor destroyed upstream: it rides out with the
203
+ // content and is left. Here that is a detached node, still reachable through
204
+ // `getChild`, and C is silent about it, so this port is too.
205
+ const orphan = view.getChild('orphan');
206
+ const parent = orphan?.parentElement?.localName ?? 'none';
207
+ host.remove();
208
+ expect(`orphan parent:${parent} known:${view.getChild('orphan') !== null}`).toBe(
209
+ 'orphan parent:none known:true',
210
+ );
211
+ });
212
+ });
213
+
214
+ await describe('<adw-layout-slot>', async () => {
215
+ await it('has the group role and takes no box of its own', () => {
216
+ const { view, host } = mount(markup());
217
+ const slot = view.querySelector('adw-layout-slot') as AdwLayoutSlot;
218
+ const report = `role:${slot.getAttribute('role')} display:${slot.style.display} id:${slot.slotId}`;
219
+ host.remove();
220
+ expect(report).toBe('role:group display:contents id:secondary');
221
+ });
222
+
223
+ await it('refuses to be built without an id, as `g_error` does', () => {
224
+ const host = document.createElement('div');
225
+ document.body.appendChild(host);
226
+ host.innerHTML = '<adw-multi-layout-view><adw-layout-slot></adw-layout-slot></adw-multi-layout-view>';
227
+ const view = host.querySelector('adw-multi-layout-view') as AdwMultiLayoutView;
228
+ const registered = (view as unknown as { _slots: Map<string, unknown> })._slots.size;
229
+ host.remove();
230
+ expect(`registered:${registered}`).toBe('registered:0');
231
+ });
232
+
233
+ await it('is not a layout slot outside a view, so nothing claims it', () => {
234
+ const host = document.createElement('div');
235
+ document.body.appendChild(host);
236
+ host.innerHTML = '<adw-layout-slot id="orphan"></adw-layout-slot>';
237
+ const slot = host.querySelector('adw-layout-slot') as AdwLayoutSlot;
238
+ const report = `id:${slot.slotId} parent:${slot.parentElement?.localName}`;
239
+ host.remove();
240
+ expect(report).toBe('id:orphan parent:div');
241
+ });
242
+ });
243
+ };
@@ -0,0 +1,164 @@
1
+ // DOM-level tests for <adw-preferences-row>: the four properties that are ALL about
2
+ // the title label (adw-preferences-row.c:118-170) — `title` as Pango markup,
3
+ // `use-markup`, `use-underline`, `title-selectable` — plus the one port decision the
4
+ // element's header records, that this base row presents the title rather than
5
+ // presenting nothing as C does (adw-preferences-row.c:20).
6
+ import { describe, expect, it } from '@gjsify/unit';
7
+
8
+ import type { AdwPreferencesRow } from './elements/adw-preferences-row.js';
9
+
10
+ function mount(
11
+ attributes: Record<string, string | true> = {},
12
+ children: Node[] = [],
13
+ ): {
14
+ el: AdwPreferencesRow;
15
+ host: HTMLElement;
16
+ } {
17
+ const host = document.createElement('div');
18
+ document.body.appendChild(host);
19
+ const el = document.createElement('adw-preferences-row') as AdwPreferencesRow;
20
+ for (const [name, value] of Object.entries(attributes)) {
21
+ if (value === true) el.setAttribute(name, '');
22
+ else el.setAttribute(name, value);
23
+ }
24
+ host.appendChild(el);
25
+ for (const child of children) el.appendChild(child);
26
+ return { el, host };
27
+ }
28
+
29
+ /** The title label the element builds, which is what all four properties drive. */
30
+ function titleEl(el: AdwPreferencesRow): HTMLElement {
31
+ return el.querySelector('.adw-row-title') as HTMLElement;
32
+ }
33
+
34
+ /** Where a `child` property lands, so a caller can put the preference's controls beside it. */
35
+ function contentEl(el: AdwPreferencesRow): HTMLElement {
36
+ return el.querySelector('.adw-preferences-row-content') as HTMLElement;
37
+ }
38
+
39
+ export const AdwPreferencesRowTest = async () => {
40
+ await describe('<adw-preferences-row> the title', async () => {
41
+ await it('presents it, which is the one place this port departs from C', () => {
42
+ const { el, host } = mount({ title: 'Appearance' });
43
+ expect(titleEl(el).textContent).toBe('Appearance');
44
+ expect(titleEl(el).hidden).toBe(false);
45
+ host.remove();
46
+ });
47
+
48
+ await it("is a list item of the group's list, and says so", () => {
49
+ const { el, host } = mount({ title: 'Appearance' });
50
+ expect(el.getAttribute('role')).toBe('listitem');
51
+ host.remove();
52
+ });
53
+
54
+ await it('an absent title is C\'s NULL → "" — no line at all', () => {
55
+ const { el, host } = mount();
56
+ expect(el.title).toBe('');
57
+ expect(titleEl(el).hidden).toBe(true);
58
+ // `row_has_title` keeps such a row out of the preferences search, and the
59
+ // element keeps its title empty so that check agrees.
60
+ expect(el.title).toBe('');
61
+ host.remove();
62
+ });
63
+
64
+ await it('an emptied title drops the attribute rather than leaving "" behind', () => {
65
+ const { el, host } = mount({ title: 'Appearance' });
66
+ el.title = '';
67
+ expect(el.hasAttribute('title')).toBe(false);
68
+ expect(titleEl(el).hidden).toBe(true);
69
+ host.remove();
70
+ });
71
+ });
72
+
73
+ await describe('<adw-preferences-row> use-markup and use-underline', async () => {
74
+ await it("reduces markup when use-markup is set — C's TRUE default, opt-in here", () => {
75
+ const marked = mount({ title: '<b>Dark</b> Style', 'use-markup': true });
76
+ expect(titleEl(marked.el).textContent).toBe('Dark Style');
77
+ // Text in the DOM either way: `use-markup` chooses what the title MEANS, and
78
+ // the string is never parsed as HTML.
79
+ expect(titleEl(marked.el).querySelector('b')).toBeNull();
80
+ marked.host.remove();
81
+
82
+ const plain = mount({ title: '<b>Dark</b> Style' });
83
+ expect(titleEl(plain.el).textContent).toBe('<b>Dark</b> Style');
84
+ plain.host.remove();
85
+ });
86
+
87
+ await it('takes the `_` out when use-underline is set', () => {
88
+ const { el, host } = mount({ title: '_Appearance', 'use-underline': true });
89
+ expect(titleEl(el).textContent).toBe('Appearance');
90
+ host.remove();
91
+ });
92
+
93
+ await it('reduces markup FIRST, so an underscore inside a tag survives', () => {
94
+ const { el, host } = mount({
95
+ title: '<span font_desc="Sans">_Style</span>',
96
+ 'use-markup': true,
97
+ 'use-underline': true,
98
+ });
99
+ expect(titleEl(el).textContent).toBe('Style');
100
+ host.remove();
101
+ });
102
+
103
+ await it('reports both flags as the attributes carry them', () => {
104
+ const { el, host } = mount({ 'use-markup': true });
105
+ expect(el.useMarkup).toBe(true);
106
+ expect(el.useUnderline).toBe(false);
107
+ expect(el.titleSelectable).toBe(false);
108
+ host.remove();
109
+ });
110
+ });
111
+
112
+ await describe('<adw-preferences-row> title-selectable', async () => {
113
+ await it('makes the title copyable, which is `Gtk.Label:selectable` in the DOM', () => {
114
+ const { el, host } = mount({ title: 'Appearance', 'title-selectable': true });
115
+ expect(el.titleSelectable).toBe(true);
116
+ expect(titleEl(el).style.userSelect).toBe('text');
117
+ host.remove();
118
+ });
119
+
120
+ await it('leaves it unselectable by default', () => {
121
+ const { el, host } = mount({ title: 'Appearance' });
122
+ expect(titleEl(el).style.userSelect).toBe('');
123
+ host.remove();
124
+ });
125
+ });
126
+
127
+ await describe('<adw-preferences-row> the child property', async () => {
128
+ await it('routes a `slot="child"` control into the content box, after the title', async () => {
129
+ const switchRow = document.createElement('adw-switch-row');
130
+ switchRow.setAttribute('slot', 'child');
131
+ const { el, host } = mount({ title: 'Night Light' }, [switchRow]);
132
+ await new Promise<void>((resolve) => setTimeout(resolve, 0));
133
+ expect(el.child).toBe(switchRow);
134
+ expect(contentEl(el).contains(switchRow)).toBe(true);
135
+ // The title comes FIRST, the control after it — a row, not a column.
136
+ expect(el.firstElementChild).toBe(titleEl(el));
137
+ host.remove();
138
+ });
139
+
140
+ await it('accepts the child as a property too', () => {
141
+ const { el, host } = mount({ title: 'Night Light' });
142
+ const control = document.createElement('gtk-switch');
143
+ el.child = control;
144
+ expect(el.child).toBe(control);
145
+ expect(contentEl(el).children.length).toBe(1);
146
+ el.child = null;
147
+ expect(el.child).toBeNull();
148
+ host.remove();
149
+ });
150
+ });
151
+
152
+ await describe('<adw-preferences-row> notification', async () => {
153
+ await it('emits one notify:: per observed attribute', async () => {
154
+ const { el, host } = mount({ title: 'Appearance' });
155
+ const seen: string[] = [];
156
+ el.addEventListener('notify::title', (event) => seen.push((event as CustomEvent).detail.title));
157
+ el.title = 'Theme';
158
+ el.title = 'Theme 2';
159
+ expect(seen).toStrictEqual(['Theme', 'Theme 2']);
160
+ expect(titleEl(el).textContent).toBe('Theme 2');
161
+ host.remove();
162
+ });
163
+ });
164
+ };
@@ -490,6 +490,82 @@ export const AdwRowStateTest = async () => {
490
490
  });
491
491
  });
492
492
 
493
+ // `row.spin spinbutton > button.image-button.up/.down`
494
+ // (refs/libadwaita/src/stylesheet/widgets/_lists.scss:250-262) extends `%button_basic`
495
+ // AND `%circular_button` (_buttons.scss:19-27, :312-320): a 30px CIRCLE, filled at rest,
496
+ // with `margin: 10px 2px`. It rendered here as a transparent 32px rounded square. Read
497
+ // from the SHIPPED sheet — `test.browser.mts` imports the package for its side effects,
498
+ // so it is in the document — against a native capture of `Adw.SpinRow` (libadwaita
499
+ // 1.9.3, light): each button allocated 34x50 with min = nat, painted as a 30px circle of
500
+ // flat rgb(235,235,235), the two circles 10px apart, at y=12..41 inside the 54px row.
501
+ await describe('adw-spin-row stepper buttons', async () => {
502
+ /** The two steppers, as the element builds them: `−`, the input, then `+`. */
503
+ function steppers(row: AdwSpinRow): { dec: HTMLElement; inc: HTMLElement; control: HTMLElement } {
504
+ const control = row.querySelector('.adw-spin-control') as HTMLElement;
505
+ return {
506
+ control,
507
+ dec: row.querySelector('.adw-spin-dec') as HTMLElement,
508
+ inc: row.querySelector('.adw-spin-inc') as HTMLElement,
509
+ };
510
+ }
511
+
512
+ await it("is a 30px circle with upstream's margins, not a 32px rounded square", () => {
513
+ const { el: row, host } = parse<AdwSpinRow>(
514
+ `<adw-spin-row title="Amount" value="5" adjustment='{"lower":0,"upper":10}'></adw-spin-row>`,
515
+ 'adw-spin-row',
516
+ );
517
+ const style = getComputedStyle(steppers(row).dec);
518
+ // A floor, as upstream writes it, so a wider glyph grows the circle.
519
+ expect(style.minWidth).toBe('30px');
520
+ expect(style.minHeight).toBe('30px');
521
+ expect(style.margin).toBe('10px 2px');
522
+ expect(style.padding).toBe('0px');
523
+ expect(style.borderRadius).toBe('9999px');
524
+ host.remove();
525
+ });
526
+
527
+ await it('paints the filled rest state rather than a transparent one', async () => {
528
+ const { el: row, host } = parse<AdwSpinRow>(
529
+ `<adw-spin-row title="Amount" value="5" adjustment='{"lower":0,"upper":10}'></adw-spin-row>`,
530
+ 'adw-spin-row',
531
+ );
532
+ const { dec } = steppers(row);
533
+ // `$button_color` (_buttons.scss:1) — the 10% mix that composites to the 235
534
+ // the native pixels show. A transparent rest state resolves to alpha 0.
535
+ expect(getComputedStyle(dec).backgroundColor).not.toBe('rgba(0, 0, 0, 0)');
536
+ host.remove();
537
+ });
538
+
539
+ await it('renders both circles 30px across, spaced as native lays them out', async () => {
540
+ const { el: row, host } = parse<AdwSpinRow>(
541
+ `<adw-spin-row title="Amount" value="5" adjustment='{"lower":0,"upper":10}'></adw-spin-row>`,
542
+ 'adw-spin-row',
543
+ );
544
+ const { dec, inc } = steppers(row);
545
+ const input = row.querySelector('input') as HTMLElement;
546
+ const decBox = dec.getBoundingClientRect();
547
+ const incBox = inc.getBoundingClientRect();
548
+ const inputBox = input.getBoundingClientRect();
549
+ const rowBox = row.getBoundingClientRect();
550
+
551
+ expect(Math.round(decBox.width)).toBe(30);
552
+ expect(Math.round(decBox.height)).toBe(30);
553
+ expect(Math.round(incBox.width)).toBe(30);
554
+ expect(Math.round(incBox.height)).toBe(30);
555
+ // 8px on each side of the entry: `border-spacing: 6px` (:242) plus this button's
556
+ // own 2px margin. Native's two circles stand 10px apart with NO entry between
557
+ // them; this port sandwiches the input between them, so its dec-to-inc distance
558
+ // is not the comparable number.
559
+ expect(Math.round(inputBox.left - decBox.right)).toBe(8);
560
+ expect(Math.round(incBox.left - inputBox.right)).toBe(8);
561
+ // The 10px margins put each circle 12px down the 54px row, which is the native
562
+ // capture's y=12..41.
563
+ expect(Math.round(rowBox.height)).toBe(54);
564
+ expect(Math.round(decBox.top - rowBox.top)).toBe(12);
565
+ host.remove();
566
+ });
567
+ });
568
+
493
569
  await describe('adw-toggle-group (ToggleGroupState)', async () => {
494
570
  await it('tracks the active segment and notifies only on a click', async () => {
495
571
  const { el: group, host } = parse<AdwToggleGroup>(
@@ -550,6 +626,72 @@ export const AdwRowStateTest = async () => {
550
626
  expect(group.active).toBe(1);
551
627
  host.remove();
552
628
  });
629
+
630
+ await it('carries a toggle tooltip onto its button (adw-toggle-group.c:215)', async () => {
631
+ // `update_button` sets the tooltip before it looks at anything else, so it
632
+ // holds for a labelled toggle and an icon-only one alike.
633
+ const { el: group, host } = parse<AdwToggleGroup>(
634
+ `<adw-toggle-group>
635
+ <adw-toggle label="Picture" tooltip="Picture Mode"></adw-toggle>
636
+ <adw-toggle icon-name="camera-photo" tooltip="Take a photo"></adw-toggle>
637
+ </adw-toggle-group>`,
638
+ 'adw-toggle-group',
639
+ );
640
+ const buttons = Array.from(group.querySelectorAll('button.adw-toggle')) as HTMLButtonElement[];
641
+
642
+ expect(buttons.map((btn) => btn.title)).toStrictEqual(['Picture Mode', 'Take a photo']);
643
+ host.remove();
644
+ });
645
+
646
+ await it('names an icon-only toggle by its tooltip, not by its icon name', async () => {
647
+ // The fall-through in `update_button` (:226-282): a label names the toggle,
648
+ // otherwise the TOOLTIP does, and the symbolic icon name is the last resort.
649
+ // Naming it `camera-photo` — which is what this element did before — announces
650
+ // an identifier rather than words.
651
+ const { el: group, host } = parse<AdwToggleGroup>(
652
+ `<adw-toggle-group>
653
+ <adw-toggle icon-name="camera-photo" tooltip="Take a photo"></adw-toggle>
654
+ <adw-toggle icon-name="camera-photo"></adw-toggle>
655
+ </adw-toggle-group>`,
656
+ 'adw-toggle-group',
657
+ );
658
+ const buttons = Array.from(group.querySelectorAll('button.adw-toggle')) as HTMLButtonElement[];
659
+
660
+ expect(buttons[0].getAttribute('aria-label')).toBe('Take a photo');
661
+ // No tooltip, so the icon name still names it rather than leaving it blank.
662
+ expect(buttons[1].getAttribute('aria-label')).toBe('camera-photo');
663
+ host.remove();
664
+ });
665
+
666
+ await it('leaves a labelled toggle named by its label, not by its tooltip', async () => {
667
+ // The label is the visible text and names the button; the tooltip becomes the
668
+ // DESCRIPTION in GTK. Setting `aria-label` here would override the text a
669
+ // reader already sees on the control.
670
+ const { el: group, host } = parse<AdwToggleGroup>(
671
+ `<adw-toggle-group>
672
+ <adw-toggle label="Picture" tooltip="Picture Mode"></adw-toggle>
673
+ </adw-toggle-group>`,
674
+ 'adw-toggle-group',
675
+ );
676
+ const button = group.querySelector('button.adw-toggle') as HTMLButtonElement;
677
+
678
+ expect(button.getAttribute('aria-label')).toBe(null);
679
+ host.remove();
680
+ });
681
+
682
+ await it('leaves an unlabelled, untooltipped toggle unnamed rather than blank-named', async () => {
683
+ const { el: group, host } = parse<AdwToggleGroup>(
684
+ `<adw-toggle-group>
685
+ <adw-toggle></adw-toggle>
686
+ </adw-toggle-group>`,
687
+ 'adw-toggle-group',
688
+ );
689
+ const button = group.querySelector('button.adw-toggle') as HTMLButtonElement;
690
+
691
+ expect(button.getAttribute('aria-label')).toBe(null);
692
+ expect(button.title).toBe('');
693
+ host.remove();
694
+ });
553
695
  });
554
696
 
555
697
  await describe('adw-expander-row (ExpanderState)', async () => {