@gjsify/adwaita-web 0.53.0 → 0.55.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 (440) hide show
  1. package/dist/adwaita-web.css +8070 -3037
  2. package/dist/adwaita-web.css.map +1 -1
  3. package/lib/types/adw-application-window.spec.d.ts +1 -0
  4. package/lib/types/adw-bin.spec.d.ts +1 -0
  5. package/lib/types/adw-breakpoint-bin.spec.d.ts +1 -0
  6. package/lib/types/adw-clamp-scrollable.spec.d.ts +1 -0
  7. package/lib/types/adw-multi-layout-view.spec.d.ts +1 -0
  8. package/lib/types/adw-preferences-row.spec.d.ts +1 -0
  9. package/lib/types/adw-shortcuts.spec.d.ts +1 -0
  10. package/lib/types/adw-tab-bar.spec.d.ts +1 -0
  11. package/lib/types/adw-tab-button.spec.d.ts +1 -0
  12. package/lib/types/adw-tab-overview.spec.d.ts +1 -0
  13. package/lib/types/adw-view-switcher-sidebar.spec.d.ts +1 -0
  14. package/lib/types/adw-window.spec.d.ts +1 -0
  15. package/lib/types/breakpoints.d.ts +14 -3
  16. package/lib/types/construct-vectors.spec.d.ts +1 -0
  17. package/lib/types/elements/adw-application-window.d.ts +27 -0
  18. package/lib/types/elements/adw-bin.d.ts +17 -0
  19. package/lib/types/elements/adw-breakpoint-bin.d.ts +67 -0
  20. package/lib/types/elements/adw-clamp-scrollable.d.ts +38 -0
  21. package/lib/types/elements/adw-dialog.d.ts +10 -0
  22. package/lib/types/elements/adw-layout-slot.d.ts +19 -0
  23. package/lib/types/elements/adw-multi-layout-view.d.ts +101 -0
  24. package/lib/types/elements/adw-preferences-row.d.ts +31 -0
  25. package/lib/types/elements/adw-shortcuts-dialog.d.ts +13 -0
  26. package/lib/types/elements/adw-shortcuts-item.d.ts +36 -0
  27. package/lib/types/elements/adw-shortcuts-section.d.ts +14 -0
  28. package/lib/types/elements/adw-sidebar.d.ts +5 -0
  29. package/lib/types/elements/adw-switch-row.d.ts +3 -0
  30. package/lib/types/elements/adw-tab-bar.d.ts +108 -0
  31. package/lib/types/elements/adw-tab-button.d.ts +32 -0
  32. package/lib/types/elements/adw-tab-overview.d.ts +199 -0
  33. package/lib/types/elements/adw-tab-view.d.ts +19 -23
  34. package/lib/types/elements/adw-view-switcher-sidebar.d.ts +84 -0
  35. package/lib/types/elements/adw-window.d.ts +40 -0
  36. package/lib/types/elements/gtk-about-dialog.d.ts +146 -0
  37. package/lib/types/elements/gtk-application-window.d.ts +34 -0
  38. package/lib/types/elements/gtk-aspect-frame.d.ts +27 -0
  39. package/lib/types/elements/gtk-button.d.ts +9 -0
  40. package/lib/types/elements/gtk-calendar.d.ts +159 -0
  41. package/lib/types/elements/gtk-center-box.d.ts +39 -0
  42. package/lib/types/elements/gtk-color-dialog-button.d.ts +69 -0
  43. package/lib/types/elements/gtk-column-view.d.ts +50 -0
  44. package/lib/types/elements/gtk-drag-icon.d.ts +78 -0
  45. package/lib/types/elements/gtk-drawing-area.d.ts +95 -0
  46. package/lib/types/elements/gtk-editable-label.d.ts +33 -0
  47. package/lib/types/elements/gtk-emoji-chooser.d.ts +84 -0
  48. package/lib/types/elements/gtk-entry.d.ts +20 -1
  49. package/lib/types/elements/gtk-expander.d.ts +49 -0
  50. package/lib/types/elements/gtk-fixed.d.ts +13 -0
  51. package/lib/types/elements/gtk-flow-box-child.d.ts +14 -0
  52. package/lib/types/elements/gtk-flow-box.d.ts +87 -0
  53. package/lib/types/elements/gtk-font-dialog-button.d.ts +83 -0
  54. package/lib/types/elements/gtk-frame.d.ts +24 -0
  55. package/lib/types/elements/gtk-gl-area.d.ts +136 -0
  56. package/lib/types/elements/gtk-graphics-offload.d.ts +24 -0
  57. package/lib/types/elements/gtk-grid-view.d.ts +39 -0
  58. package/lib/types/elements/gtk-grid.d.ts +27 -0
  59. package/lib/types/elements/gtk-header-bar.d.ts +60 -0
  60. package/lib/types/elements/gtk-inscription.d.ts +64 -0
  61. package/lib/types/elements/gtk-label.d.ts +3 -0
  62. package/lib/types/elements/gtk-level-bar.d.ts +59 -0
  63. package/lib/types/elements/gtk-link-button.d.ts +29 -0
  64. package/lib/types/elements/gtk-list-box-row.d.ts +54 -0
  65. package/lib/types/elements/gtk-list-box.d.ts +100 -0
  66. package/lib/types/elements/gtk-list-view.d.ts +73 -0
  67. package/lib/types/elements/gtk-media-controls.d.ts +142 -0
  68. package/lib/types/elements/gtk-notebook.d.ts +148 -0
  69. package/lib/types/elements/gtk-overlay.d.ts +22 -0
  70. package/lib/types/elements/gtk-page-setup-unix-dialog.d.ts +87 -0
  71. package/lib/types/elements/gtk-paned.d.ts +121 -0
  72. package/lib/types/elements/gtk-password-entry.d.ts +27 -0
  73. package/lib/types/elements/gtk-picture.d.ts +66 -0
  74. package/lib/types/elements/gtk-popover-bin.d.ts +82 -0
  75. package/lib/types/elements/gtk-popover-menu-bar.d.ts +66 -0
  76. package/lib/types/elements/gtk-popover-menu.d.ts +83 -0
  77. package/lib/types/elements/gtk-popover.d.ts +28 -3
  78. package/lib/types/elements/gtk-print-unix-dialog.d.ts +167 -0
  79. package/lib/types/elements/gtk-revealer.d.ts +55 -0
  80. package/lib/types/elements/gtk-scale-button.d.ts +59 -0
  81. package/lib/types/elements/gtk-scale.d.ts +98 -0
  82. package/lib/types/elements/gtk-scrollbar.d.ts +124 -0
  83. package/lib/types/elements/gtk-scrolled-window.d.ts +121 -0
  84. package/lib/types/elements/gtk-search-bar.d.ts +39 -0
  85. package/lib/types/elements/gtk-search-entry.d.ts +27 -0
  86. package/lib/types/elements/gtk-separator.d.ts +10 -0
  87. package/lib/types/elements/gtk-spin-button.d.ts +94 -0
  88. package/lib/types/elements/gtk-spinner.d.ts +14 -0
  89. package/lib/types/elements/gtk-stack-sidebar.d.ts +43 -0
  90. package/lib/types/elements/gtk-stack-switcher.d.ts +58 -0
  91. package/lib/types/elements/gtk-stack.d.ts +154 -0
  92. package/lib/types/elements/gtk-switch.d.ts +4 -1
  93. package/lib/types/elements/gtk-text-view.d.ts +62 -0
  94. package/lib/types/elements/gtk-text.d.ts +45 -0
  95. package/lib/types/elements/gtk-toggle-button.d.ts +45 -0
  96. package/lib/types/elements/gtk-tree-expander.d.ts +38 -0
  97. package/lib/types/elements/gtk-video.d.ts +97 -0
  98. package/lib/types/elements/gtk-viewport.d.ts +84 -0
  99. package/lib/types/elements/gtk-window-controls.d.ts +80 -0
  100. package/lib/types/elements/gtk-window-handle.d.ts +39 -0
  101. package/lib/types/elements/gtk-window.d.ts +97 -0
  102. package/lib/types/elements/justification.d.ts +2 -0
  103. package/lib/types/elements/popover-menu.d.ts +18 -0
  104. package/lib/types/elements/roving-focus.d.ts +29 -1
  105. package/lib/types/emoji-data.d.ts +38 -0
  106. package/lib/types/font-description.d.ts +96 -0
  107. package/lib/types/gtk-about-dialog.spec.d.ts +1 -0
  108. package/lib/types/gtk-action-bar.spec.d.ts +1 -0
  109. package/lib/types/gtk-application-window.spec.d.ts +1 -0
  110. package/lib/types/gtk-aspect-frame.spec.d.ts +1 -0
  111. package/lib/types/gtk-calendar.spec.d.ts +1 -0
  112. package/lib/types/gtk-center-box.spec.d.ts +1 -0
  113. package/lib/types/gtk-color-dialog-button.spec.d.ts +1 -0
  114. package/lib/types/gtk-column-view.spec.d.ts +1 -0
  115. package/lib/types/gtk-drag-icon.spec.d.ts +1 -0
  116. package/lib/types/gtk-drawing-area.spec.d.ts +1 -0
  117. package/lib/types/gtk-editable-label.spec.d.ts +1 -0
  118. package/lib/types/gtk-emoji-chooser.spec.d.ts +1 -0
  119. package/lib/types/gtk-expander.spec.d.ts +1 -0
  120. package/lib/types/gtk-fixed.spec.d.ts +1 -0
  121. package/lib/types/gtk-flow-box.spec.d.ts +1 -0
  122. package/lib/types/gtk-font-dialog-button.spec.d.ts +1 -0
  123. package/lib/types/gtk-frame.spec.d.ts +1 -0
  124. package/lib/types/gtk-gl-area.spec.d.ts +1 -0
  125. package/lib/types/gtk-graphics-offload.spec.d.ts +1 -0
  126. package/lib/types/gtk-grid-view.spec.d.ts +1 -0
  127. package/lib/types/gtk-grid.spec.d.ts +1 -0
  128. package/lib/types/gtk-header-bar.spec.d.ts +1 -0
  129. package/lib/types/gtk-inscription.spec.d.ts +1 -0
  130. package/lib/types/gtk-level-bar.spec.d.ts +1 -0
  131. package/lib/types/gtk-link-button.spec.d.ts +1 -0
  132. package/lib/types/gtk-list-box.spec.d.ts +1 -0
  133. package/lib/types/gtk-list-view.spec.d.ts +1 -0
  134. package/lib/types/gtk-media-controls.spec.d.ts +1 -0
  135. package/lib/types/gtk-notebook.spec.d.ts +1 -0
  136. package/lib/types/gtk-overlay.spec.d.ts +1 -0
  137. package/lib/types/gtk-paned.spec.d.ts +1 -0
  138. package/lib/types/gtk-password-entry.spec.d.ts +1 -0
  139. package/lib/types/gtk-picture.spec.d.ts +1 -0
  140. package/lib/types/gtk-popover-bin.spec.d.ts +1 -0
  141. package/lib/types/gtk-popover-menu-bar.spec.d.ts +1 -0
  142. package/lib/types/gtk-popover-menu.spec.d.ts +1 -0
  143. package/lib/types/gtk-popover-role.spec.d.ts +1 -0
  144. package/lib/types/gtk-popover.spec.d.ts +1 -0
  145. package/lib/types/gtk-print-dialogs.spec.d.ts +1 -0
  146. package/lib/types/gtk-revealer.spec.d.ts +1 -0
  147. package/lib/types/gtk-scale-button.spec.d.ts +1 -0
  148. package/lib/types/gtk-scale.spec.d.ts +1 -0
  149. package/lib/types/gtk-scrollbar.spec.d.ts +1 -0
  150. package/lib/types/gtk-scrolled-window.spec.d.ts +1 -0
  151. package/lib/types/gtk-search-bar.spec.d.ts +1 -0
  152. package/lib/types/gtk-search-entry.spec.d.ts +1 -0
  153. package/lib/types/gtk-separator.spec.d.ts +1 -0
  154. package/lib/types/gtk-spin-button.spec.d.ts +1 -0
  155. package/lib/types/gtk-spinner.spec.d.ts +1 -0
  156. package/lib/types/gtk-stack-sidebar.spec.d.ts +1 -0
  157. package/lib/types/gtk-stack-switcher.spec.d.ts +1 -0
  158. package/lib/types/gtk-stack.spec.d.ts +1 -0
  159. package/lib/types/gtk-text-view.spec.d.ts +1 -0
  160. package/lib/types/gtk-text.spec.d.ts +1 -0
  161. package/lib/types/gtk-toggle-button.spec.d.ts +1 -0
  162. package/lib/types/gtk-tree-expander.spec.d.ts +1 -0
  163. package/lib/types/gtk-video.spec.d.ts +1 -0
  164. package/lib/types/gtk-viewport.spec.d.ts +1 -0
  165. package/lib/types/gtk-window-controls.spec.d.ts +1 -0
  166. package/lib/types/gtk-window-handle.spec.d.ts +1 -0
  167. package/lib/types/gtk-window.spec.d.ts +1 -0
  168. package/lib/types/index.d.ts +4 -1
  169. package/lib/types/list-view-dom.d.ts +44 -0
  170. package/lib/types/namespace/adw.d.ts +12 -0
  171. package/lib/types/namespace/gtk.d.ts +61 -0
  172. package/lib/types/page-setup.d.ts +100 -0
  173. package/lib/types/scroll-shading.d.ts +15 -1
  174. package/lib/types/shared-tree-builder.d.ts +30 -2
  175. package/lib/types/signals.d.ts +4 -0
  176. package/lib/types/styles.generated.d.ts +1 -1
  177. package/lib/types/tab-chip.d.ts +73 -0
  178. package/lib/types/template-classes.d.ts +11 -0
  179. package/package.json +12 -8
  180. package/scss/_action_row.scss +2 -2
  181. package/scss/_application_window.scss +26 -0
  182. package/scss/_aspect_frame.scss +25 -0
  183. package/scss/_bin.scss +26 -0
  184. package/scss/_button.scss +45 -0
  185. package/scss/_calendar.scss +176 -0
  186. package/scss/_center_box.scss +25 -0
  187. package/scss/_checks.scss +6 -1
  188. package/scss/_clamp_scrollable.scss +28 -0
  189. package/scss/_color_button.scss +67 -0
  190. package/scss/_column_view.scss +126 -0
  191. package/scss/_drag_icon.scss +55 -0
  192. package/scss/_drawing.scss +85 -0
  193. package/scss/_emoji_chooser.scss +213 -0
  194. package/scss/_entry.scss +13 -5
  195. package/scss/_entry_row.scss +1 -1
  196. package/scss/_expander.scss +113 -0
  197. package/scss/_fixed.scss +29 -0
  198. package/scss/_flow_box.scss +94 -0
  199. package/scss/_font_button.scss +63 -0
  200. package/scss/_frame.scss +41 -0
  201. package/scss/_grid.scss +19 -0
  202. package/scss/_grid_view.scss +46 -0
  203. package/scss/_gtk_about_dialog.scss +186 -0
  204. package/scss/_headerbar.scss +132 -0
  205. package/scss/_icons.generated.scss +186 -0
  206. package/scss/_inscription.scss +125 -0
  207. package/scss/_level_bar.scss +190 -0
  208. package/scss/_link.scss +82 -0
  209. package/scss/_list_box.scss +88 -0
  210. package/scss/_list_view.scss +96 -0
  211. package/scss/_media_controls.scss +139 -0
  212. package/scss/_overlay.scss +68 -0
  213. package/scss/_paned.scss +130 -0
  214. package/scss/_password_entry.scss +83 -0
  215. package/scss/_picture.scss +80 -0
  216. package/scss/_popover_bin.scss +53 -0
  217. package/scss/_popover_menu_bar.scss +104 -0
  218. package/scss/_preferences_row.scss +51 -0
  219. package/scss/_print_dialogs.scss +328 -0
  220. package/scss/_reset.scss +21 -19
  221. package/scss/_revealer.scss +37 -0
  222. package/scss/_row.scss +20 -5
  223. package/scss/_scale.scss +298 -0
  224. package/scss/_scale_button.scss +167 -0
  225. package/scss/_scrollbar.scss +230 -0
  226. package/scss/_scrolled_window.scss +131 -0
  227. package/scss/_search_bar.scss +118 -0
  228. package/scss/_search_entry.scss +86 -0
  229. package/scss/_separator.scss +44 -0
  230. package/scss/_shortcuts_dialog.scss +100 -0
  231. package/scss/_spin_button.scss +172 -0
  232. package/scss/_spin_row.scss +56 -8
  233. package/scss/_spinner.scss +85 -4
  234. package/scss/_stack.scss +729 -0
  235. package/scss/_switch.scss +13 -5
  236. package/scss/_switch_row.scss +10 -0
  237. package/scss/_tab_bar.scss +317 -0
  238. package/scss/_tab_button.scss +98 -0
  239. package/scss/_tab_overview.scss +483 -0
  240. package/scss/_text.scss +182 -0
  241. package/scss/_theme.scss +1 -1
  242. package/scss/_tree_expander.scss +62 -0
  243. package/scss/_variables.scss +43 -21
  244. package/scss/_video.scss +146 -0
  245. package/scss/_view_switcher_sidebar.scss +112 -0
  246. package/scss/_viewport.scss +50 -0
  247. package/scss/_window.scss +118 -1
  248. package/scss/_window_handle.scss +20 -0
  249. package/scss/adwaita-skin.scss +109 -0
  250. package/src/adw-action-rows.spec.ts +76 -0
  251. package/src/adw-application-window.spec.ts +118 -0
  252. package/src/adw-bin.spec.ts +75 -0
  253. package/src/adw-breakpoint-bin.spec.ts +324 -0
  254. package/src/adw-clamp-scrollable.spec.ts +189 -0
  255. package/src/adw-multi-layout-view.spec.ts +243 -0
  256. package/src/adw-preferences-row.spec.ts +164 -0
  257. package/src/adw-row-state.spec.ts +142 -0
  258. package/src/adw-shortcuts.spec.ts +155 -0
  259. package/src/adw-tab-bar.spec.ts +287 -0
  260. package/src/adw-tab-button.spec.ts +101 -0
  261. package/src/adw-tab-overview.spec.ts +443 -0
  262. package/src/adw-view-switcher-sidebar.spec.ts +281 -0
  263. package/src/adw-window.spec.ts +129 -0
  264. package/src/breakpoints.ts +25 -8
  265. package/src/capabilities.d.mts +3 -0
  266. package/src/capabilities.mjs +18 -0
  267. package/src/connect-lifecycle.spec.ts +12 -0
  268. package/src/construct-vectors.spec.ts +175 -0
  269. package/src/elements/adw-application-window.ts +154 -0
  270. package/src/elements/adw-bin.ts +101 -0
  271. package/src/elements/adw-breakpoint-bin.ts +287 -0
  272. package/src/elements/adw-clamp-scrollable.ts +207 -0
  273. package/src/elements/adw-dialog.ts +19 -0
  274. package/src/elements/adw-layout-slot.ts +95 -0
  275. package/src/elements/adw-multi-layout-view.ts +326 -0
  276. package/src/elements/adw-preferences-row.ts +150 -0
  277. package/src/elements/adw-shortcuts-dialog.ts +52 -0
  278. package/src/elements/adw-shortcuts-item.ts +171 -0
  279. package/src/elements/adw-shortcuts-section.ts +86 -0
  280. package/src/elements/adw-sidebar.ts +42 -3
  281. package/src/elements/adw-switch-row.ts +28 -1
  282. package/src/elements/adw-tab-bar.ts +529 -0
  283. package/src/elements/adw-tab-button.ts +194 -0
  284. package/src/elements/adw-tab-overview.ts +1011 -0
  285. package/src/elements/adw-tab-view.ts +66 -145
  286. package/src/elements/adw-toggle-group.ts +20 -5
  287. package/src/elements/adw-view-stack.ts +18 -0
  288. package/src/elements/adw-view-switcher-sidebar.ts +332 -0
  289. package/src/elements/adw-window.ts +185 -11
  290. package/src/elements/checks.ts +35 -8
  291. package/src/elements/gtk-about-dialog.ts +811 -0
  292. package/src/elements/gtk-application-window.ts +108 -0
  293. package/src/elements/gtk-aspect-frame.ts +160 -0
  294. package/src/elements/gtk-button.ts +12 -0
  295. package/src/elements/gtk-calendar.ts +757 -0
  296. package/src/elements/gtk-center-box.ts +184 -0
  297. package/src/elements/gtk-color-dialog-button.ts +278 -0
  298. package/src/elements/gtk-column-view.ts +320 -0
  299. package/src/elements/gtk-drag-icon.ts +257 -0
  300. package/src/elements/gtk-drawing-area.ts +303 -0
  301. package/src/elements/gtk-editable-label.ts +204 -0
  302. package/src/elements/gtk-emoji-chooser.ts +542 -0
  303. package/src/elements/gtk-entry.ts +39 -5
  304. package/src/elements/gtk-expander.ts +301 -0
  305. package/src/elements/gtk-fixed.ts +99 -0
  306. package/src/elements/gtk-flow-box-child.ts +68 -0
  307. package/src/elements/gtk-flow-box.ts +480 -0
  308. package/src/elements/gtk-font-dialog-button.ts +432 -0
  309. package/src/elements/gtk-frame.ts +174 -0
  310. package/src/elements/gtk-gl-area.ts +476 -0
  311. package/src/elements/gtk-graphics-offload.ts +130 -0
  312. package/src/elements/gtk-grid-view.ts +168 -0
  313. package/src/elements/gtk-grid.ts +127 -0
  314. package/src/elements/gtk-header-bar.ts +273 -0
  315. package/src/elements/gtk-inscription.ts +387 -0
  316. package/src/elements/gtk-label.ts +19 -11
  317. package/src/elements/gtk-level-bar.ts +323 -0
  318. package/src/elements/gtk-link-button.ts +138 -0
  319. package/src/elements/gtk-list-box-row.ts +195 -0
  320. package/src/elements/gtk-list-box.ts +413 -0
  321. package/src/elements/gtk-list-view.ts +370 -0
  322. package/src/elements/gtk-media-controls.ts +509 -0
  323. package/src/elements/gtk-notebook.ts +664 -0
  324. package/src/elements/gtk-overlay.ts +149 -0
  325. package/src/elements/gtk-page-setup-unix-dialog.ts +420 -0
  326. package/src/elements/gtk-paned.ts +597 -0
  327. package/src/elements/gtk-password-entry.ts +170 -0
  328. package/src/elements/gtk-picture.ts +254 -0
  329. package/src/elements/gtk-popover-bin.ts +332 -0
  330. package/src/elements/gtk-popover-menu-bar.ts +355 -0
  331. package/src/elements/gtk-popover-menu.ts +339 -0
  332. package/src/elements/gtk-popover.ts +92 -10
  333. package/src/elements/gtk-print-unix-dialog.ts +989 -0
  334. package/src/elements/gtk-progress-bar.ts +24 -11
  335. package/src/elements/gtk-revealer.ts +406 -0
  336. package/src/elements/gtk-scale-button.ts +358 -0
  337. package/src/elements/gtk-scale.ts +492 -0
  338. package/src/elements/gtk-scrollbar.ts +528 -0
  339. package/src/elements/gtk-scrolled-window.ts +642 -0
  340. package/src/elements/gtk-search-bar.ts +200 -0
  341. package/src/elements/gtk-search-entry.ts +172 -0
  342. package/src/elements/gtk-separator.ts +52 -0
  343. package/src/elements/gtk-spin-button.ts +475 -0
  344. package/src/elements/gtk-spinner.ts +126 -0
  345. package/src/elements/gtk-stack-sidebar.ts +212 -0
  346. package/src/elements/gtk-stack-switcher.ts +279 -0
  347. package/src/elements/gtk-stack.ts +748 -0
  348. package/src/elements/gtk-switch.ts +52 -19
  349. package/src/elements/gtk-text-view.ts +290 -0
  350. package/src/elements/gtk-text.ts +219 -0
  351. package/src/elements/gtk-toggle-button.ts +239 -0
  352. package/src/elements/gtk-tree-expander.ts +243 -0
  353. package/src/elements/gtk-video.ts +423 -0
  354. package/src/elements/gtk-viewport.ts +277 -0
  355. package/src/elements/gtk-window-controls.ts +341 -0
  356. package/src/elements/gtk-window-handle.ts +221 -0
  357. package/src/elements/gtk-window.ts +366 -0
  358. package/src/elements/justification.ts +24 -0
  359. package/src/elements/popover-menu.ts +24 -0
  360. package/src/elements/roving-focus.ts +53 -21
  361. package/src/emoji-data.ts +577 -0
  362. package/src/entry-rows.spec.ts +31 -0
  363. package/src/font-description.ts +238 -0
  364. package/src/gtk-about-dialog.spec.ts +250 -0
  365. package/src/gtk-action-bar.spec.ts +89 -0
  366. package/src/gtk-application-window.spec.ts +107 -0
  367. package/src/gtk-aspect-frame.spec.ts +114 -0
  368. package/src/gtk-calendar.spec.ts +589 -0
  369. package/src/gtk-center-box.spec.ts +125 -0
  370. package/src/gtk-color-dialog-button.spec.ts +141 -0
  371. package/src/gtk-column-view.spec.ts +154 -0
  372. package/src/gtk-drag-icon.spec.ts +190 -0
  373. package/src/gtk-drawing-area.spec.ts +211 -0
  374. package/src/gtk-editable-label.spec.ts +190 -0
  375. package/src/gtk-emoji-chooser.spec.ts +173 -0
  376. package/src/gtk-entry.spec.ts +23 -0
  377. package/src/gtk-expander.spec.ts +170 -0
  378. package/src/gtk-fixed.spec.ts +97 -0
  379. package/src/gtk-flow-box.spec.ts +289 -0
  380. package/src/gtk-font-dialog-button.spec.ts +166 -0
  381. package/src/gtk-frame.spec.ts +119 -0
  382. package/src/gtk-gl-area.spec.ts +361 -0
  383. package/src/gtk-graphics-offload.spec.ts +119 -0
  384. package/src/gtk-grid-view.spec.ts +106 -0
  385. package/src/gtk-grid.spec.ts +122 -0
  386. package/src/gtk-header-bar.spec.ts +202 -0
  387. package/src/gtk-inscription.spec.ts +235 -0
  388. package/src/gtk-level-bar.spec.ts +199 -0
  389. package/src/gtk-link-button.spec.ts +117 -0
  390. package/src/gtk-list-box.spec.ts +422 -0
  391. package/src/gtk-list-view.spec.ts +203 -0
  392. package/src/gtk-media-controls.spec.ts +295 -0
  393. package/src/gtk-notebook.spec.ts +546 -0
  394. package/src/gtk-overlay.spec.ts +141 -0
  395. package/src/gtk-paned.spec.ts +267 -0
  396. package/src/gtk-password-entry.spec.ts +150 -0
  397. package/src/gtk-picture.spec.ts +172 -0
  398. package/src/gtk-popover-bin.spec.ts +229 -0
  399. package/src/gtk-popover-menu-bar.spec.ts +296 -0
  400. package/src/gtk-popover-menu.spec.ts +261 -0
  401. package/src/gtk-popover-role.spec.ts +138 -0
  402. package/src/gtk-popover.spec.ts +264 -0
  403. package/src/gtk-print-dialogs.spec.ts +251 -0
  404. package/src/gtk-revealer.spec.ts +164 -0
  405. package/src/gtk-scale-button.spec.ts +218 -0
  406. package/src/gtk-scale.spec.ts +213 -0
  407. package/src/gtk-scrollbar.spec.ts +244 -0
  408. package/src/gtk-scrolled-window.spec.ts +262 -0
  409. package/src/gtk-search-bar.spec.ts +179 -0
  410. package/src/gtk-search-entry.spec.ts +142 -0
  411. package/src/gtk-separator.spec.ts +74 -0
  412. package/src/gtk-spin-button.spec.ts +186 -0
  413. package/src/gtk-spinner.spec.ts +130 -0
  414. package/src/gtk-stack-sidebar.spec.ts +217 -0
  415. package/src/gtk-stack-switcher.spec.ts +249 -0
  416. package/src/gtk-stack.spec.ts +432 -0
  417. package/src/gtk-text-view.spec.ts +189 -0
  418. package/src/gtk-text.spec.ts +163 -0
  419. package/src/gtk-toggle-button.spec.ts +186 -0
  420. package/src/gtk-tree-expander.spec.ts +201 -0
  421. package/src/gtk-video.spec.ts +240 -0
  422. package/src/gtk-viewport.spec.ts +140 -0
  423. package/src/gtk-window-controls.spec.ts +232 -0
  424. package/src/gtk-window-handle.spec.ts +158 -0
  425. package/src/gtk-window.spec.ts +190 -0
  426. package/src/index.ts +9 -1
  427. package/src/keyboard-operable.spec.ts +33 -1
  428. package/src/list-view-dom.ts +121 -0
  429. package/src/namespace/adw.ts +12 -0
  430. package/src/namespace/gtk.ts +61 -0
  431. package/src/page-setup.ts +222 -0
  432. package/src/scroll-shading.ts +18 -1
  433. package/src/shared-tree-builder.ts +263 -21
  434. package/src/signals.ts +15 -0
  435. package/src/source-view/theme.ts +11 -5
  436. package/src/style-classes.spec.ts +9 -8
  437. package/src/styles.generated.ts +1 -1
  438. package/src/tab-chip.ts +200 -0
  439. package/src/template-classes.ts +45 -0
  440. package/src/test.browser.mts +152 -0
@@ -0,0 +1,238 @@
1
+ // A `PangoFontDescription` as plain data — the shape `Gtk.FontDialogButton:font-desc`
2
+ // carries (gtkfontdialogbutton.c:340-345), and the only one a browser can hold.
3
+ //
4
+ // WHY A MODULE AND NOT THE ELEMENT. The description is a VALUE with a grammar: Pango's
5
+ // own string form in and out, an equality test, and a projection onto CSS. All three are
6
+ // pure and all three outlive the element — the NativeScript port needs the same parse to
7
+ // give its XML attribute the same meaning, and a copy inside `<gtk-font-dialog-button>`
8
+ // would be the second spelling the second renderer drifts from.
9
+ //
10
+ // THE GRAMMAR IS PANGO'S, and only the part the button uses is here. `from_string` reads
11
+ // a trailing number as the size and every recognised word as a style, in any order, and
12
+ // `to_string` writes them back in ITS order — weight, then slant, then width, then size
13
+ // (`pango_font_description_to_string`). Both are reproduced, including the words
14
+ // themselves, because the string is what `font-desc` carries on the wire and what the
15
+ // C's `pango_font_description_equal` compares.
16
+ //
17
+ // THE FOUR STYLE WORDS A BROWSER HAS. Pango knows twelve weights and three slants; CSS
18
+ // has numbers 1…1000 and two slants, so the projection is total in one direction and
19
+ // lossy in the other: Pango's `ULTRALIGHT` is CSS's `200` and `SEMIBOLD` is `600`, both
20
+ // exactly, because Pango's weights ARE the CSS numbers. Nothing is approximated.
21
+ //
22
+ // Reference: refs/gtk/gtk/gtkfontdialogbutton.c (font_desc, font_description_style_equal,
23
+ // update_font_info's size format, apply_use_font)
24
+ // `pango_font_description_to_string` itself is PANGO's, not GTK's: the pinned refs/gtk has no
25
+ // pango/ tree, so the word order above is transcribed from Pango's own
26
+ // `pango_font_description_to_string` and there is no refs/ coordinate for a reader to open.
27
+ // `refs/gtk/gtk/gtkfontchooserwidget.c:1549` is the GTK-side counterpart — GTK's one call
28
+ // site that puts the round-tripped string back on the wire.
29
+ // Copyright (c) GNOME contributors (Pango). LGPLv2.1+.
30
+ // Modifications: Implemented for @gjsify/adwaita-web as plain data.
31
+
32
+ /** The horizontal slant Pango spells. CSS has `italic` and `oblique`, and so does this. */
33
+ export type FontSlant = 'normal' | 'italic' | 'oblique';
34
+
35
+ /** The four widths Pango distinguishes; CSS `font-stretch` names the same three. */
36
+ export type FontWidth = 'normal' | 'condensed' | 'expanded';
37
+
38
+ /**
39
+ * The fields `GtkFontDialogButton` reads. `variant` and the exact family/face are
40
+ * deliberately absent: the C compares them in `font_description_style_equal`
41
+ * (gtkfontdialogbutton.c:586-592) to pick a face out of a font map, and a browser page
42
+ * has no font map — see `font-button`'s header for what stands in for it.
43
+ */
44
+ export interface PangoFontDescription {
45
+ /** The family name, or `''` for the "unset" a fresh description carries. */
46
+ family: string;
47
+ slant: FontSlant;
48
+ /** Pango's numeric weight, which is also CSS's `font-weight` number. */
49
+ weight: number;
50
+ width: FontWidth;
51
+ /** The size as written. `unit` says what it is counted in. */
52
+ size: number;
53
+ /** `pango_font_description_set_size_is_absolute` — `true` means the size is pixels. */
54
+ absolute: boolean;
55
+ }
56
+
57
+ /** The description `gtk_font_dialog_button_init` builds: `pango_font_description_from_string ("Sans 12")`. */
58
+ export const PANGO_FONT_DESCRIPTION_DEFAULT: PangoFontDescription = {
59
+ family: 'Sans',
60
+ slant: 'normal',
61
+ weight: 400,
62
+ width: 'normal',
63
+ size: 12,
64
+ absolute: false,
65
+ };
66
+
67
+ /**
68
+ * Pango's style words, and what each one sets. `to_string` emits them in THIS order
69
+ * (weight, then slant, then width), so a description round-trips to the same string.
70
+ */
71
+ const STYLE_WORDS: readonly { word: string; set: Partial<Omit<PangoFontDescription, 'family' | 'size'>> }[] = [
72
+ { word: 'Thin', set: { weight: 100 } },
73
+ { word: 'UltraLight', set: { weight: 200 } },
74
+ { word: 'Light', set: { weight: 300 } },
75
+ { word: 'SemiLight', set: { weight: 350 } },
76
+ { word: 'Book', set: { weight: 375 } },
77
+ { word: 'Medium', set: { weight: 500 } },
78
+ { word: 'SemiBold', set: { weight: 600 } },
79
+ { word: 'Bold', set: { weight: 700 } },
80
+ { word: 'UltraBold', set: { weight: 800 } },
81
+ { word: 'Heavy', set: { weight: 900 } },
82
+ { word: 'Black', set: { weight: 1000 } },
83
+ { word: 'Italic', set: { slant: 'italic' } },
84
+ { word: 'Oblique', set: { slant: 'oblique' } },
85
+ { word: 'Condensed', set: { width: 'condensed' } },
86
+ { word: 'Expanded', set: { width: 'expanded' } },
87
+ ];
88
+
89
+ /**
90
+ * `pango_font_description_from_string` — family, style words and a trailing size, in any
91
+ * order.
92
+ *
93
+ * Total, like the C: an unrecognised word is not a style, and a family is whatever is
94
+ * left over once the styles and the size are gone — which is why the tokens are consumed
95
+ * from the END, where Pango reads the size, and a token that matches no style word stays
96
+ * in the family.
97
+ */
98
+ export function parseFontDescription(text: string): PangoFontDescription {
99
+ const description: PangoFontDescription = { ...PANGO_FONT_DESCRIPTION_DEFAULT, family: '' };
100
+ const tokens = text
101
+ .trim()
102
+ .split(/\s+/)
103
+ .filter((token) => token !== '');
104
+ // The size is the LAST token that parses as a number, and Pango remembers whether it
105
+ // was written in pixels.
106
+ for (let end = tokens.length; end > 0; end--) {
107
+ const size = /^(-?\d+(?:\.\d+)?)(px)?$/.exec(tokens[end - 1]);
108
+ if (size === null) continue;
109
+ description.size = Number(size[1]);
110
+ description.absolute = size[2] === 'px';
111
+ tokens.length = end - 1;
112
+ break;
113
+ }
114
+ const family: string[] = [];
115
+ for (const token of tokens) {
116
+ const word = STYLE_WORDS.find((entry) => entry.word.toLowerCase() === token.toLowerCase());
117
+ if (word === undefined) {
118
+ family.push(token);
119
+ continue;
120
+ }
121
+ Object.assign(description, word.set);
122
+ }
123
+ description.family = family.join(' ');
124
+ return description;
125
+ }
126
+
127
+ /** `pango_font_description_to_string` — the same words, in the same order. */
128
+ export function formatFontDescription(description: PangoFontDescription): string {
129
+ const words: string[] = [];
130
+ for (const { word, set } of STYLE_WORDS) {
131
+ const matches = Object.entries(set).every(
132
+ ([key, value]) => description[key as keyof PangoFontDescription] === value,
133
+ );
134
+ if (matches && !words.includes(word)) words.push(word);
135
+ }
136
+ const size = `${description.size}${description.absolute ? 'px' : ''}`;
137
+ return [description.family, ...words, size].filter((part) => part !== '').join(' ');
138
+ }
139
+
140
+ /**
141
+ * `pango_font_description_equal` — every field, as Pango's own comparison is. `font-desc`
142
+ * is `G_PARAM_EXPLICIT_NOTIFY` (:345), so a write of the description already held must be
143
+ * the write that changes nothing (gtkfontdialogbutton.c:869-871).
144
+ */
145
+ export function fontDescriptionEqual(a: PangoFontDescription, b: PangoFontDescription): boolean {
146
+ return (
147
+ a.family === b.family &&
148
+ a.slant === b.slant &&
149
+ a.weight === b.weight &&
150
+ a.width === b.width &&
151
+ a.size === b.size &&
152
+ a.absolute === b.absolute
153
+ );
154
+ }
155
+
156
+ /**
157
+ * `update_font_info`'s size format, `g_strdup_printf ("%2.4g%s", size / PANGO_SCALE, …)`
158
+ * (gtkfontdialogbutton.c:669-673) — four significant digits with the zeros stripped, and
159
+ * `px` when the size is absolute. `%g` is what `Number#toPrecision` computes and
160
+ * `Number#toString` then tidies, which is the whole of the difference between `12` and
161
+ * `12.00`.
162
+ */
163
+ export function formatFontSize(size: number, absolute: boolean): string {
164
+ return `${Number(size.toPrecision(4))}${absolute ? 'px' : ''}`;
165
+ }
166
+
167
+ /**
168
+ * The CSS projection of a description — `apply_use_font`'s attribute list
169
+ * (gtkfontdialogbutton.c:689-720), as the four LONGHANDS Pango's own attribute list sets.
170
+ *
171
+ * `use_size` is the one field `apply_use_font` may unset, and it is a parameter here for
172
+ * that reason: `PANGO_FONT_MASK_SIZE` goes only when the size is not wanted.
173
+ *
174
+ * The longhands rather than the `font` SHORTHAND, because the shorthand is all-or-nothing:
175
+ * one rejected token discards the family with it, and a description is half its fields.
176
+ * `cssFontShorthand` is the same projection for the one caller that needs a string —
177
+ * `FontFaceSet.check()`, which takes nothing else.
178
+ *
179
+ * THE SIZE CARRIES A UNIT, and Pango's own string does not — which is the one place this
180
+ * projection is not a rename. A bare `12` is a size in Pango (points, because
181
+ * `PangoFontDescription`'s size is divided by `PANGO_SCALE` and Pango's renderer reads
182
+ * points) and a length a CSS declaration REJECTS. `pt` is the unit Pango means — one point
183
+ * is 1/72 inch in both — so an absolute size keeps `px` and everything else becomes `pt`.
184
+ */
185
+ export interface CssFontParts {
186
+ fontFamily: string;
187
+ fontWeight: string;
188
+ fontStyle: string;
189
+ fontStretch: string;
190
+ fontSize: string;
191
+ }
192
+
193
+ /** An unset family is "None" as a LABEL, not a font to render in — so the generic is. */
194
+ export function cssFontParts(description: PangoFontDescription, useSize: boolean): CssFontParts {
195
+ return {
196
+ fontFamily: description.family === '' ? 'sans-serif' : `"${description.family}"`,
197
+ fontWeight: String(description.weight),
198
+ fontStyle: description.slant,
199
+ fontStretch: description.width,
200
+ fontSize: useSize ? `${description.size}${description.absolute ? 'px' : 'pt'}` : '',
201
+ };
202
+ }
203
+
204
+ /** {@link cssFontParts} as one `font` shorthand, for the string-shaped caller. */
205
+ export function cssFontShorthand(description: PangoFontDescription, useSize: boolean): string {
206
+ const parts = cssFontParts(description, useSize);
207
+ const shorthand: string[] = [];
208
+ if (parts.fontStyle !== 'normal') shorthand.push(parts.fontStyle);
209
+ if (parts.fontWeight !== '400') shorthand.push(parts.fontWeight);
210
+ if (parts.fontStretch !== 'normal') shorthand.push(parts.fontStretch);
211
+ if (parts.fontSize !== '') shorthand.push(parts.fontSize);
212
+ if (shorthand.length > 0) shorthand.push('');
213
+ return `${shorthand.join(' ')}${parts.fontFamily}`.trim();
214
+ }
215
+
216
+ /**
217
+ * Pango's feature list as the TAGS a CSS `font-feature-settings` value is built from — the
218
+ * one place this module translates rather than renames.
219
+ *
220
+ * `pango_font_features_to_string` writes a comma-separated list of bare tags with `-` for
221
+ * off, which is the same LIST and not the same SYNTAX: CSS wants each tag quoted (`"liga"`).
222
+ *
223
+ * The tags come back as a LIST on purpose. `font-feature-settings` is all-or-nothing, and
224
+ * MEASURED in Firefox: the declaration `"liga", "-kern"` is DROPPED WHOLE — an unknown tag
225
+ * invalidates the value, not just itself — while `"liga"` alone stands. A single joined
226
+ * string would therefore lose every tag the browser does not know, which is a silent
227
+ * difference from Pango's "keep what you recognise". The caller applies the tags one at a
228
+ * time so a rejection costs one feature.
229
+ *
230
+ * `tnum=1` keeps its `=1`, which is Pango's own spelling for "on with a value".
231
+ */
232
+ export function cssFontFeatureTags(features: string): string[] {
233
+ return features
234
+ .split(',')
235
+ .map((feature) => feature.trim())
236
+ .filter((feature) => feature !== '')
237
+ .map((feature) => `"${feature}"`);
238
+ }
@@ -0,0 +1,250 @@
1
+ // DOM-level tests for <gtk-about-dialog>. What is worth asserting is the page
2
+ // VISIBILITY derivation — it is the one thing a reader of the rendered dialog cannot work
3
+ // out by looking, and the three rules in `gtkaboutdialog.c` disagree with each other on
4
+ // purpose: a licence page for a CUSTOM licence only, a system page for any text at all, and
5
+ // a credits page for any credit list or extra section.
6
+ import { describe, expect, it } from '@gjsify/unit';
7
+
8
+ import type { GtkAboutDialog } from './elements/gtk-about-dialog.js';
9
+ import { splitLinks } from './elements/gtk-about-dialog.js';
10
+
11
+ function mount(attrs: Record<string, string> = {}): { el: GtkAboutDialog; host: HTMLElement } {
12
+ const host = document.createElement('div');
13
+ document.body.appendChild(host);
14
+ const el = document.createElement('gtk-about-dialog') as GtkAboutDialog;
15
+ for (const [name, value] of Object.entries(attrs)) el.setAttribute(name, value);
16
+ host.appendChild(el);
17
+ return { el, host };
18
+ }
19
+
20
+ /** The pages the stack switcher currently offers. */
21
+ function pages(el: GtkAboutDialog): string[] {
22
+ return [...el.querySelectorAll('.adw-gtk-about-dialog-switcher-item')].map((item) => item.textContent ?? '');
23
+ }
24
+
25
+ export const GtkAboutDialogTest = async () => {
26
+ await describe('<gtk-about-dialog> chrome', async () => {
27
+ await it('is an AdwDialog sheet, and its title is "About <name>"', () => {
28
+ // update_name_version (gtkaboutdialog.c:1066-1073) — the WINDOW title, which
29
+ // the headerbar does not display: the `.ui` gives the titlebar a stack switcher
30
+ // and no title widget.
31
+ const { el, host } = mount({ 'program-name': 'Calculator' });
32
+ expect(el.classList.contains('adw-dialog')).toBe(true);
33
+ expect(el.title).toBe('About Calculator');
34
+ expect(el.querySelector('.adw-dialog-title')).toBe(null);
35
+ host.remove();
36
+ });
37
+
38
+ await it('an unset program-name falls back to the application name', () => {
39
+ // gtk_about_dialog_set_program_name (gtkaboutdialog.c:1095-1112) —
40
+ // `g_get_application_name ()`, which in a document is its own title.
41
+ const { el, host } = mount();
42
+ expect(el.title).toBe(`About ${document.title}`);
43
+ expect(el.querySelector('.adw-gtk-about-dialog-name')?.textContent).toBe(document.title);
44
+ host.remove();
45
+ });
46
+
47
+ await it('presenting traps focus and closing gives it back', () => {
48
+ const opener = document.createElement('button');
49
+ document.body.appendChild(opener);
50
+ opener.focus();
51
+ const { el, host } = mount({ 'program-name': 'Calculator' });
52
+ el.present();
53
+ expect(el.open).toBe(true);
54
+ // The role and `aria-modal` live on the modal SURFACE, as for every dialog
55
+ // (`surface` in keyboard-operable.spec.ts) — the host carries neither.
56
+ expect(el.querySelector('.adw-dialog-box')?.getAttribute('aria-modal')).toBe('true');
57
+ el.close();
58
+ expect(el.open).toBe(false);
59
+ expect(document.activeElement).toBe(opener);
60
+ opener.remove();
61
+ host.remove();
62
+ });
63
+ });
64
+
65
+ await describe('<gtk-about-dialog> page visibility', async () => {
66
+ await it('shows no switcher for a dialog with nothing extra', () => {
67
+ // update_stack_switcher_visibility (gtkaboutdialog.c:657-670) — the switcher is
68
+ // visible only when one of the three pages is, so a plain about dialog has an
69
+ // EMPTY headerbar, exactly as in GTK.
70
+ const { el, host } = mount({ 'program-name': 'Calculator', version: '1.0' });
71
+ expect(pages(el)).toStrictEqual([]);
72
+ expect(el.querySelector('.adw-gtk-about-dialog-switcher')?.hasAttribute('hidden')).toBe(true);
73
+ host.remove();
74
+ });
75
+
76
+ await it('a licence page needs a CUSTOM licence with text', () => {
77
+ // update_license_button_visibility (gtkaboutdialog.c:686-696) — the type AND a
78
+ // non-empty string, which is why `license-type="mit-x11"` alone shows nothing.
79
+ const { el, host } = mount({ 'program-name': 'Calculator', 'license-type': 'mit-x11' });
80
+ expect(pages(el)).toStrictEqual([]);
81
+ el.license = 'Permission is hereby granted, free of charge, …';
82
+ expect(pages(el)).toStrictEqual(['License']);
83
+ host.remove();
84
+ });
85
+
86
+ await it('a system page needs text, and clearing it takes the page away', () => {
87
+ // update_system_button_visibility (gtkaboutdialog.c:700-710).
88
+ const { el, host } = mount({ 'program-name': 'Calculator' });
89
+ el.setAttribute('system-information', 'GTK 4.24.0\nglibc 2.42');
90
+ expect(pages(el)).toStrictEqual(['System']);
91
+ el.removeAttribute('system-information');
92
+ expect(pages(el)).toStrictEqual([]);
93
+ host.remove();
94
+ });
95
+
96
+ await it('credits come from authors, documenters, artists, translators or a section', () => {
97
+ // populate_credits_page (gtkaboutdialog.c:2029-2080) and its visibility rule
98
+ // (update_credits_button_visibility, :700-717).
99
+ const { el, host } = mount({ 'program-name': 'Calculator' });
100
+ el.authors = ['Ada Lovelace <ada@example.org>', 'Grace Hopper'];
101
+ expect(pages(el)).toStrictEqual(['Credits']);
102
+ el.authors = [];
103
+ expect(pages(el)).toStrictEqual([]);
104
+ el.addCreditSection('Reviewed by', ['Barbara Liskov']);
105
+ expect(pages(el)).toStrictEqual(['Credits']);
106
+ host.remove();
107
+ });
108
+
109
+ await it('an untranslated translator-credits sentinel shows no credits page', () => {
110
+ // :2064-2068 — the string "translator-credits" comes back unchanged from gettext
111
+ // in an untranslated locale, and showing THAT to the user is the bug.
112
+ const { el, host } = mount({ 'program-name': 'Calculator' });
113
+ el.translatorCredits = 'translator-credits';
114
+ expect(pages(el)).toStrictEqual([]);
115
+ el.translatorCredits = 'Ada Lovelace\nGrace Hopper';
116
+ expect(pages(el)).toStrictEqual(['Credits']);
117
+ host.remove();
118
+ });
119
+ });
120
+
121
+ await describe('<gtk-about-dialog> content', async () => {
122
+ await it('the main page shows version, comments, website, copyright and licence', () => {
123
+ const { el, host } = mount({
124
+ 'program-name': 'Calculator',
125
+ version: '48.1',
126
+ comments: 'A four-function calculator.',
127
+ website: 'https://gitlab.gnome.org/World/gnome-calculator',
128
+ 'website-label': 'GNOME Calculator',
129
+ copyright: '© 2026 The GNOME Project',
130
+ });
131
+ const main = el.querySelector('.adw-gtk-about-dialog-page[data-page="main"]')!;
132
+ expect(main.querySelector('.adw-gtk-about-dialog-version')?.textContent).toBe('48.1');
133
+ expect(main.querySelector('.adw-gtk-about-dialog-comments')?.textContent).toBe(
134
+ 'A four-function calculator.',
135
+ );
136
+ // update_website (gtkaboutdialog.c:1009-1041) — the LABEL is the link text when
137
+ // one is set, and the word "Website" when it is not.
138
+ expect(main.querySelector('a.adw-gtk-about-dialog-website')?.textContent).toBe('GNOME Calculator');
139
+ expect(main.querySelector('a.adw-gtk-about-dialog-website')?.getAttribute('href')).toBe(
140
+ 'https://gitlab.gnome.org/World/gnome-calculator',
141
+ );
142
+ expect(main.querySelector('.adw-gtk-about-dialog-copyright')?.textContent).toBe('© 2026 The GNOME Project');
143
+ host.remove();
144
+ });
145
+
146
+ await it('a website with no label links the bare word "Website"', () => {
147
+ const { el, host } = mount({
148
+ 'program-name': 'Calculator',
149
+ website: 'https://gjsify.org',
150
+ });
151
+ expect(el.querySelector('a.adw-gtk-about-dialog-website')?.textContent).toBe('Website');
152
+ host.remove();
153
+ });
154
+
155
+ await it('a known licence type writes the warranty preamble and wraps it', async () => {
156
+ // gtk_about_dialog_set_license_type (gtkaboutdialog.c:2259-2313) — a licence
157
+ // other than CUSTOM OVERWRITES `license` with the disclaimer, links it to that
158
+ // licence's URL and sets wrap-license TRUE. The disclaimer is the MAIN page's
159
+ // label (`gtk_label_set_markup`, :2354), NOT a stack page: the License TAB
160
+ // needs CUSTOM with text (`update_license_button_visibility`, :674-685).
161
+ const { el, host } = mount({ 'program-name': 'Calculator', website: 'https://gjsify.org' });
162
+ el.setAttribute('license-type', 'gpl-3-0');
163
+ const licence = el.querySelector('.adw-gtk-about-dialog-license')!;
164
+ expect(licence.textContent).toContain('absolutely no warranty');
165
+ const link = licence.querySelector('a')!;
166
+ expect(link.getAttribute('href')).toBe('https://www.gnu.org/licenses/gpl-3.0.html');
167
+ expect(link.textContent).toBe('GNU General Public License, version 3 or later');
168
+ expect(el.wrapLicense).toBe(false);
169
+ expect(pages(el)).toStrictEqual([]);
170
+ host.remove();
171
+ });
172
+
173
+ await it('licence and system text turn <…> and bare URLs into links', async () => {
174
+ const { el, host } = mount({
175
+ 'program-name': 'Calculator',
176
+ 'system-information': 'Build host: <build@example.org>\nDocs: https://gjsify.org/gtk end',
177
+ });
178
+ el.setAttribute('system-information', 'Build host: <build@example.org>\nDocs: https://gjsify.org/gtk end');
179
+ await Promise.resolve();
180
+ // Lazy population: the System page is built the first time it is SHOWN
181
+ // (stack_visible_child_notify, gtkaboutdialog.c:297-333), so open it first.
182
+ el.showPage('system');
183
+ const page = el.querySelector('.adw-gtk-about-dialog-page[data-page="system"]')!;
184
+ const mail = page.querySelector('a[href^="mailto:"]');
185
+ const url = page.querySelector('a[href="https://gjsify.org/gtk"]');
186
+ expect(mail?.textContent).toBe('build@example.org');
187
+ expect(url?.textContent).toBe('https://gjsify.org/gtk');
188
+ host.remove();
189
+ });
190
+
191
+ await it("the credits page names every section in the C's order", () => {
192
+ const { el, host } = mount({ 'program-name': 'Calculator' });
193
+ el.authors = ['Ada Lovelace'];
194
+ el.documenters = ['Grace Hopper'];
195
+ el.translatorCredits = 'Barbara Liskov';
196
+ el.artists = ['Margaret Hamilton'];
197
+ el.addCreditSection('Reviewed by', ['Tony Hoare']);
198
+ el.showPage('credits');
199
+ const headings = [...el.querySelectorAll('.adw-gtk-about-dialog-credits-heading')].map(
200
+ (heading) => heading.textContent,
201
+ );
202
+ expect(headings).toStrictEqual([
203
+ 'Created by',
204
+ 'Documented by',
205
+ 'Translated by',
206
+ 'Design by',
207
+ 'Reviewed by',
208
+ ]);
209
+ host.remove();
210
+ });
211
+ });
212
+
213
+ await describe('<gtk-about-dialog> activate-link', async () => {
214
+ await it('a link click raises a cancelable activate-link', () => {
215
+ // emit_activate_link (gtkaboutdialog.c:646-655) — BOOLEAN__STRING with the
216
+ // true-handled accumulator, which is what `preventDefault()` spells.
217
+ const { el, host } = mount({ 'program-name': 'Calculator', website: 'https://gjsify.org' });
218
+ const seen: unknown[] = [];
219
+ el.addEventListener('activate-link', (event) => {
220
+ seen.push((event as CustomEvent).detail);
221
+ event.preventDefault();
222
+ });
223
+ el.querySelector('a.adw-gtk-about-dialog-website')!.dispatchEvent(
224
+ new MouseEvent('click', { bubbles: true, cancelable: true }),
225
+ );
226
+ expect(seen).toStrictEqual([{ uri: 'https://gjsify.org' }]);
227
+ host.remove();
228
+ });
229
+ });
230
+
231
+ await describe('<gtk-about-dialog> link scanning', async () => {
232
+ await it('splits angle-bracket emails, bare URLs and plain text', () => {
233
+ // text_buffer_new (gtkaboutdialog.c:1903-2028) — the three shapes, in order.
234
+ expect(splitLinks('a <b@c.org> d')).toStrictEqual([
235
+ { text: 'a ', uri: null },
236
+ { text: 'b@c.org', uri: 'mailto:b@c.org' },
237
+ { text: ' d', uri: null },
238
+ ]);
239
+ expect(splitLinks('see https://gjsify.org/x now')).toStrictEqual([
240
+ { text: 'see ', uri: null },
241
+ { text: 'https://gjsify.org/x', uri: 'https://gjsify.org/x' },
242
+ { text: ' now', uri: null },
243
+ ]);
244
+ });
245
+
246
+ await it('leaves a name that is only a word alone', () => {
247
+ expect(splitLinks('Ada Lovelace')).toStrictEqual([{ text: 'Ada Lovelace', uri: null }]);
248
+ });
249
+ });
250
+ };
@@ -0,0 +1,89 @@
1
+ // DOM-level tests for <gtk-action-bar>. The bar has ONE property, `revealed`, and everything
2
+ // else about it is WHERE a child lands: `[start]` appends, `[end]` PREpends, `[center]` is the
3
+ // centre widget and a child with no type packs from the start (gtkactionbar.c:220-235,
4
+ // `gtk_action_bar_pack_end` :262-277).
5
+ import { describe, expect, it } from '@gjsify/unit';
6
+
7
+ import type { GtkActionBar } from './elements/gtk-action-bar.js';
8
+
9
+ function mount(attrs: Record<string, string> = {}): { el: GtkActionBar; host: HTMLElement } {
10
+ const host = document.createElement('div');
11
+ document.body.appendChild(host);
12
+ const el = document.createElement('gtk-action-bar') as GtkActionBar;
13
+ for (const [name, value] of Object.entries(attrs)) el.setAttribute(name, value);
14
+ host.appendChild(el);
15
+ return { el, host };
16
+ }
17
+
18
+ function child(slot: string | undefined, text: string): HTMLElement {
19
+ const el = document.createElement('span');
20
+ if (slot !== undefined) el.setAttribute('slot', slot);
21
+ el.textContent = text;
22
+ return el;
23
+ }
24
+
25
+ export const GtkActionBarTest = async () => {
26
+ await describe('<gtk-action-bar> placement', async () => {
27
+ await it('appends a `start` child and PREPENDS an `end` one', async () => {
28
+ // gtk_action_bar_pack_start is an append and pack_end a PREPEND, so the FIRST
29
+ // `[end]` child sits nearest the edge (gtkactionbar.c:255-277).
30
+ const { el, host } = mount();
31
+ el.append(child('start', 'a'), child('end', 'z'), child('start', 'b'), child('end', 'y'));
32
+ // Adoption is the MutationObserver's, so it lands on the next microtask
33
+ // (`src/slotted-children.ts`).
34
+ await Promise.resolve();
35
+ expect([...(el.startSection?.children ?? [])].map((n) => n.textContent)).toStrictEqual(['a', 'b']);
36
+ expect([...(el.endSection?.children ?? [])].map((n) => n.textContent)).toStrictEqual(['y', 'z']);
37
+ host.remove();
38
+ });
39
+
40
+ await it('packs an untyped child from the start', async () => {
41
+ // gtkactionbar.c:233-234 — `type == NULL` is pack_start.
42
+ const { el, host } = mount();
43
+ const loose = child(undefined, 'loose');
44
+ el.appendChild(loose);
45
+ await Promise.resolve();
46
+ expect(loose.parentElement).toBe(el.startSection);
47
+ host.remove();
48
+ });
49
+
50
+ await it('routes `center` to the centre section', async () => {
51
+ // gtk_action_bar_set_center_widget (:306-...) — there is no `center-widget`
52
+ // PROPERTY in GTK, which is why the slot is spelled `center`.
53
+ const { el, host } = mount();
54
+ const centre = child('center', 'mid');
55
+ el.appendChild(centre);
56
+ await Promise.resolve();
57
+ expect(centre.parentElement).toBe(el.centerSection);
58
+ host.remove();
59
+ });
60
+
61
+ await it('a late child reaches the same place a declared one does', async () => {
62
+ const { el, host } = mount();
63
+ const late = child('end', 'late');
64
+ el.appendChild(late);
65
+ await Promise.resolve();
66
+ expect(late.parentElement).toBe(el.endSection);
67
+ host.remove();
68
+ });
69
+ });
70
+
71
+ await describe('<gtk-action-bar> revealed', async () => {
72
+ await it('defaults to TRUE, so only revealed="false" hides the bar', () => {
73
+ // gtkactionbar.c:183 — the property's default is TRUE.
74
+ const { el, host } = mount();
75
+ expect(el.revealed).toBe(true);
76
+ expect(el.hidden).toBe(false);
77
+ host.remove();
78
+ });
79
+
80
+ await it('hides and shows through the property', () => {
81
+ const { el, host } = mount({ revealed: 'false' });
82
+ expect(el.revealed).toBe(false);
83
+ expect(el.hidden).toBe(true);
84
+ el.revealed = true;
85
+ expect(el.hidden).toBe(false);
86
+ host.remove();
87
+ });
88
+ });
89
+ };