@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,235 @@
1
+ // DOM-level tests for <gtk-inscription>. Two things dominate and both are about DEFAULTS,
2
+ // because GtkInscription's defaults are the opposite of GtkLabel's: `min-chars` is 3 and
3
+ // `xalign` is 0 where a label has none and 0.5, and `wrap-mode` defaults to WORD_CHAR where a
4
+ // label defaults to WORD. A port that reused the label's defaults would be wrong in a way no
5
+ // property assertion would catch, so the first test in each block pins the C's own numbers.
6
+ import { describe, expect, it } from '@gjsify/unit';
7
+
8
+ import type { GtkInscription } from './elements/gtk-inscription.js';
9
+
10
+ function mount(attrs: Record<string, string> = {}): { el: GtkInscription; host: HTMLElement } {
11
+ const host = document.createElement('div');
12
+ document.body.appendChild(host);
13
+ const el = document.createElement('gtk-inscription') as GtkInscription;
14
+ for (const [name, value] of Object.entries(attrs)) el.setAttribute(name, value);
15
+ host.appendChild(el);
16
+ return { el, host };
17
+ }
18
+
19
+ export const GtkInscriptionTest = async () => {
20
+ await describe('<gtk-inscription> defaults', async () => {
21
+ await it('reserves three characters and one line, and nothing more', () => {
22
+ // gtkinscription.c:59-65, :787-790 — min-chars 3, nat-chars 0, min-lines 1,
23
+ // nat-lines 0. So out of the box it holds three characters wide and one line
24
+ // tall, and lets its text be as long as it likes.
25
+ const { el, host } = mount();
26
+ expect(el.minChars).toBe(3);
27
+ expect(el.natChars).toBe(0);
28
+ expect(el.minLines).toBe(1);
29
+ expect(el.natLines).toBe(0);
30
+ host.remove();
31
+ });
32
+
33
+ await it('is start-aligned and centre-tall, the opposite pairing to GtkLabel', () => {
34
+ // gtkinscription.c:67-69, :791-792 — xalign 0.0, yalign 0.5. This is what makes a
35
+ // caption left-aligned under a centred icon with no CSS of its own.
36
+ const { el, host } = mount();
37
+ expect(el.xalign).toBe(0);
38
+ expect(el.yalign).toBe(0.5);
39
+ host.remove();
40
+ });
41
+
42
+ await it('wraps at WORD_CHAR, where GtkLabel wraps at WORD', () => {
43
+ // gtkinscription.c:738-740 — the pspec says so in its own doc comment, and the
44
+ // reason is the widget's purpose: a box of a known character count has to break
45
+ // a word longer than itself or it overflows.
46
+ const { el, host } = mount();
47
+ expect(el.wrapMode).toBe('word-char');
48
+ expect(getComputedStyle(el).overflowWrap).toBe('anywhere');
49
+ host.remove();
50
+ });
51
+
52
+ await it('clips its overflow, where a label only ellipsizes when asked', () => {
53
+ // gtkinscription.c:728-733 — GTK_INSCRIPTION_OVERFLOW_CLIP is the pspec default,
54
+ // so nothing disappears silently without it being written down.
55
+ const { el, host } = mount();
56
+ expect(el.textOverflow).toBe('clip');
57
+ expect(el.classList.contains('clip')).toBe(true);
58
+ expect(el.classList.contains('ellipsized')).toBe(false);
59
+ host.remove();
60
+ });
61
+ });
62
+
63
+ await describe('<gtk-inscription> the four counts ARE the measure', async () => {
64
+ await it('the natural width is MAX(min, nat) — never the smaller of the two', () => {
65
+ // gtkinscription.c:347-348 — `*natural = MAX (min_chars, nat_chars) * char_pixels`.
66
+ // A nat BELOW the min does not shrink the widget below the minimum it reserved.
67
+ const { el, host } = mount({ 'min-chars': '20', 'nat-chars': '5' });
68
+ expect(el.style.getPropertyValue('--gtk-inscription-width')).toBe('20ch');
69
+ expect(el.style.getPropertyValue('--gtk-inscription-min-ch')).toBe('20ch');
70
+ host.remove();
71
+ });
72
+
73
+ await it('a nat ABOVE the min does widen it', () => {
74
+ const { el, host } = mount({ 'min-chars': '5', 'nat-chars': '20' });
75
+ expect(el.style.getPropertyValue('--gtk-inscription-width')).toBe('20ch');
76
+ host.remove();
77
+ });
78
+
79
+ await it('both counts at ZERO means the widget does not size itself at all', () => {
80
+ // gtkinscription.c:344-345 and :378-379 — both measures return NOTHING when the
81
+ // two counts are zero, so the minimum is whatever the widget already had. That is
82
+ // NOT `0ch`, which would be a very much smaller widget.
83
+ const { el, host } = mount({ 'min-chars': '0', 'nat-chars': '0' });
84
+ expect(el.style.getPropertyValue('--gtk-inscription-width')).toBe('auto');
85
+ expect(el.style.getPropertyValue('--gtk-inscription-min-ch')).toBe('auto');
86
+ const { el: el2, host: host2 } = mount({ 'min-lines': '0', 'nat-lines': '0' });
87
+ expect(el2.style.getPropertyValue('--gtk-inscription-height')).toBe('auto');
88
+ host.remove();
89
+ host2.remove();
90
+ });
91
+
92
+ await it('the line counts use lh, which is the line box Pango measures', () => {
93
+ // gtkinscription.c:383-384 — `min_lines * line_pixels`. CSS `lh` resolves to the
94
+ // element's own line box, which is that unit.
95
+ const { el, host } = mount({ 'min-lines': '2', 'nat-lines': '4' });
96
+ expect(el.style.getPropertyValue('--gtk-inscription-min-lh')).toBe('2lh');
97
+ expect(el.style.getPropertyValue('--gtk-inscription-height')).toBe('4lh');
98
+ host.remove();
99
+ });
100
+
101
+ await it('a negative count clamps to zero — there is no -1 "auto" here', () => {
102
+ // gtkinscription.c:638-644 — the pspec is a `guint` with a floor of 0, unlike
103
+ // `GtkLabel:width-chars`, whose floor is -1.
104
+ const { el, host } = mount({ 'min-chars': '-5' });
105
+ expect(el.minChars).toBe(0);
106
+ host.remove();
107
+ });
108
+ });
109
+
110
+ await describe('<gtk-inscription> wrap-mode and text-overflow', async () => {
111
+ await it('the three wrap nicks reach real CSS, none of them a gap', () => {
112
+ // The same two declarations `_labels.scss:112-126` states for `<gtk-label>`:
113
+ // `word-break: break-all` is Pango's CHAR, `overflow-wrap: anywhere` is
114
+ // WORD_CHAR, and `normal` is WORD — which needs a rule only because
115
+ // WORD_CHAR is THIS widget's default.
116
+ const char = mount({ 'wrap-mode': 'char' });
117
+ expect(getComputedStyle(char.el).wordBreak).toBe('break-all');
118
+ char.host.remove();
119
+ const word = mount({ 'wrap-mode': 'word' });
120
+ expect(getComputedStyle(word.el).overflowWrap).toBe('normal');
121
+ word.host.remove();
122
+ const both = mount({ 'wrap-mode': 'word-char' });
123
+ expect(getComputedStyle(both.el).overflowWrap).toBe('anywhere');
124
+ both.host.remove();
125
+ });
126
+
127
+ await it("keeps the GtkInscription nicks, which are not the label's", () => {
128
+ // packages/framework/gtk-host/src/generated/props.ts:331 — `clip`,
129
+ // `ellipsize-start`, `ellipsize-middle`, `ellipsize-end`, where
130
+ // `Gtk.Label:ellipsize` spells the same four `none`/`start`/`middle`/`end`.
131
+ for (const mode of ['clip', 'ellipsize-start', 'ellipsize-middle', 'ellipsize-end'] as const) {
132
+ const { el, host } = mount({ 'text-overflow': mode });
133
+ expect(el.textOverflow).toBe(mode);
134
+ host.remove();
135
+ }
136
+ });
137
+
138
+ await it('draws every truncating member as an END ellipsis, which is the divergence', () => {
139
+ // `labelEllipsizeOverflowValue`'s own doc comment: CSS `text-overflow` has one
140
+ // truncating value, so `start` and `middle` are drawn as an end ellipsis — never
141
+ // as a silent clip, which would drop the same characters with no indication.
142
+ const { el, host } = mount({ 'text-overflow': 'ellipsize-middle' });
143
+ expect(el.classList.contains('ellipsized')).toBe(true);
144
+ expect(el.style.getPropertyValue('--gtk-inscription-text-overflow')).toBe('ellipsis');
145
+ host.remove();
146
+ });
147
+
148
+ await it('clip stays clip', () => {
149
+ const { el, host } = mount({ 'text-overflow': 'clip' });
150
+ expect(el.style.getPropertyValue('--gtk-inscription-text-overflow')).toBe('clip');
151
+ host.remove();
152
+ });
153
+ });
154
+
155
+ await describe('<gtk-inscription> text and markup', async () => {
156
+ await it('text is written as a text node, never as parsed markup', () => {
157
+ // The XSS answer `<gtk-label>` already gives: the string is the display text, not
158
+ // a document. `labelDisplayText` is the same reduction the NativeScript port uses.
159
+ const { el, host } = mount({ text: '<b>bold</b>' });
160
+ expect(el.textContent).toBe('<b>bold</b>');
161
+ expect(el.querySelector('b')).toBe(null);
162
+ host.remove();
163
+ });
164
+
165
+ await it('markup is REDUCED to its plain text, not handed to innerHTML', () => {
166
+ const { el, host } = mount({ markup: '<b>bold</b>' });
167
+ expect(el.textContent).toBe('bold');
168
+ expect(el.querySelector('b')).toBe(null);
169
+ host.remove();
170
+ });
171
+
172
+ await it('text wins when both are written, which is the order the C leaves them in', () => {
173
+ // `gtk_inscription_set_markup` writes the label directly and a later `set_text`
174
+ // overwrites it, so a tree carrying both reads as the plain one.
175
+ const { el, host } = mount({ text: 'plain', markup: '<b>markup</b>' });
176
+ expect(el.textContent).toBe('plain');
177
+ host.remove();
178
+ });
179
+ });
180
+
181
+ await describe('<gtk-inscription> alignment and events', async () => {
182
+ await it('xalign is a ratio on the spacer pair, and 0 puts all free space before', () => {
183
+ // GTK places the text at `xalign * (width − text width)`; splitting the free
184
+ // space between two `flex-grow` spacers in the ratio `xalign : 1 − xalign` IS that
185
+ // formula, and `flex-grow` takes a real number where `align-items` does not.
186
+ const { el, host } = mount({ xalign: '0.25' });
187
+ expect(el.style.getPropertyValue('--gtk-inscription-xalign')).toBe('0.25');
188
+ expect(getComputedStyle(el, '::before').flexGrow).toBe('0.25');
189
+ expect(getComputedStyle(el, '::after').flexGrow).toBe('0.75');
190
+ host.remove();
191
+ });
192
+
193
+ await it('a value outside 0…1 is held to the interval, as the pspec range is', () => {
194
+ // gtkinscription.c:757-760 — `g_param_spec_float (…, 0.0, 1.0, …)`.
195
+ const { el, host } = mount({ xalign: '4' });
196
+ expect(el.xalign).toBe(1);
197
+ const low = mount({ yalign: '-2' });
198
+ expect(low.el.yalign).toBe(0);
199
+ host.remove();
200
+ low.host.remove();
201
+ });
202
+
203
+ await it('notifies once per real change, with the PARSED property in the detail', () => {
204
+ const { el, host } = mount();
205
+ const events: unknown[] = [];
206
+ el.addEventListener('notify::min-chars', (e) => events.push((e as CustomEvent).detail));
207
+ el.minChars = 12;
208
+ el.minChars = 12;
209
+ el.minChars = 4;
210
+ expect(events).toStrictEqual([{ 'min-chars': 12 }, { 'min-chars': 4 }]);
211
+ host.remove();
212
+ });
213
+
214
+ await it('a declaration in the markup is adopted without emitting', () => {
215
+ const host = document.createElement('div');
216
+ document.body.appendChild(host);
217
+ const el = document.createElement('gtk-inscription') as GtkInscription;
218
+ const events: unknown[] = [];
219
+ el.addEventListener('notify::min-chars', (e) => events.push((e as CustomEvent).detail));
220
+ el.setAttribute('min-chars', '7');
221
+ host.appendChild(el);
222
+ expect(el.minChars).toBe(7);
223
+ expect(events.length).toBe(0);
224
+ host.remove();
225
+ });
226
+
227
+ await it('has no ARIA role, because ARIA has no keyword for static text', () => {
228
+ // gtkinscription.c:781 sets GTK_ACCESSIBLE_ROLE_LABEL, the same role GtkLabel
229
+ // sets — and `role="label"` is not in the ARIA role list, so none is written.
230
+ const { el, host } = mount({ text: 'hello' });
231
+ expect(el.hasAttribute('role')).toBe(false);
232
+ host.remove();
233
+ });
234
+ });
235
+ };
@@ -0,0 +1,199 @@
1
+ // DOM-level tests for <gtk-level-bar>. The widget is three separable things and each
2
+ // gets its own describe: the OFFSETS, which are a runtime list and decide both the
3
+ // block's class and nothing else; the BLOCK COUNT, which depends on `mode`; and the
4
+ // INTERVAL, whose endpoints drag `value` with them the way the C's setters do.
5
+ import { describe, expect, it } from '@gjsify/unit';
6
+
7
+ import type { GtkLevelBar } from './elements/gtk-level-bar.js';
8
+
9
+ function mount(attrs: Record<string, string> = {}): { el: GtkLevelBar; host: HTMLElement } {
10
+ const host = document.createElement('div');
11
+ document.body.appendChild(host);
12
+ const el = document.createElement('gtk-level-bar') as GtkLevelBar;
13
+ for (const [name, value] of Object.entries(attrs)) el.setAttribute(name, value);
14
+ host.appendChild(el);
15
+ return { el, host };
16
+ }
17
+
18
+ /** The `block` nodes under the trough, in DOM order, with their class names. */
19
+ function blocks(el: GtkLevelBar): string[] {
20
+ return [...el.querySelectorAll('.adw-level-bar-block')].map((node) =>
21
+ [...node.classList].filter((name) => name !== 'adw-level-bar-block').join(' '),
22
+ );
23
+ }
24
+
25
+ export const GtkLevelBarTest = async () => {
26
+ await describe('<gtk-level-bar> defaults', async () => {
27
+ await it("is a continuous horizontal bar over 0…1, with GTK's three offsets", () => {
28
+ const { el, host } = mount();
29
+ expect(el.value).toBe(0);
30
+ expect(el.minValue).toBe(0);
31
+ expect(el.maxValue).toBe(1);
32
+ expect(el.mode).toBe('continuous');
33
+ expect(el.orientation).toBe('horizontal');
34
+ expect(el.classList.contains('continuous')).toBe(true);
35
+ expect(el.classList.contains('horizontal')).toBe(true);
36
+ // gtklevelbar.c:1058-1060 — installed before any application code runs.
37
+ expect(el.offsetValue('low')).toBe(0.25);
38
+ expect(el.offsetValue('high')).toBe(0.75);
39
+ expect(el.offsetValue('full')).toBe(1);
40
+ expect(el.getAttribute('role')).toBe('meter');
41
+ expect(el.getAttribute('aria-valuemin')).toBe('0');
42
+ expect(el.getAttribute('aria-valuemax')).toBe('1');
43
+ expect(el.getAttribute('aria-valuenow')).toBe('0');
44
+ host.remove();
45
+ });
46
+
47
+ await it('continuous draws an empty level and no filled one at value 0', () => {
48
+ // gtklevelbar.c:429-430 — the filled node is never allocated at 0.
49
+ const { el, host } = mount();
50
+ const filled = el.querySelectorAll('.adw-level-bar-block.filled');
51
+ expect(filled.length).toBe(1);
52
+ expect((filled[0] as HTMLElement).hidden).toBe(true);
53
+ host.remove();
54
+ });
55
+ });
56
+
57
+ await describe('<gtk-level-bar> offsets', async () => {
58
+ await it('names the block by the first offset at or above the value', () => {
59
+ // gtklevelbar.c:604-625 — and the LOWEST offset wins even below its value.
60
+ const { el, host } = mount({ value: '0.3' });
61
+ expect(blocks(el)).toStrictEqual(['empty', 'filled high']);
62
+ el.value = 0.1;
63
+ expect(blocks(el)).toStrictEqual(['empty', 'filled low']);
64
+ el.value = 0.9;
65
+ expect(blocks(el)).toStrictEqual(['empty', 'filled full']);
66
+ el.value = 1;
67
+ expect(blocks(el)).toStrictEqual(['empty', 'filled full']);
68
+ host.remove();
69
+ });
70
+
71
+ await it('above every offset no class is named at all', () => {
72
+ const { el, host } = mount({ value: '1.5' });
73
+ expect(blocks(el)).toStrictEqual(['empty', 'filled']);
74
+ host.remove();
75
+ });
76
+
77
+ await it('adds a custom offset, and refuses one outside the interval', () => {
78
+ // gtklevelbar.c:1403 — `g_return_if_fail (gtk_level_bar_value_in_interval)`.
79
+ const { el, host } = mount({ value: '0.5' });
80
+ const changed: unknown[] = [];
81
+ el.addEventListener('offset-changed', (e) => changed.push((e as CustomEvent).detail));
82
+ el.addOffsetValue('my-offset', 0.6);
83
+ expect(el.offsetValue('my-offset')).toBe(0.6);
84
+ // 0.6 is the first offset at or above 0.5 once it is in the list.
85
+ expect(blocks(el)).toStrictEqual(['empty', 'filled my-offset']);
86
+ expect(changed).toStrictEqual([{ name: 'my-offset' }]);
87
+
88
+ el.addOffsetValue('outside', 2);
89
+ expect(el.offsetValue('outside')).toBe(null);
90
+ // Re-adding the same value is a no-op and says nothing (gtklevelbar.c:259-260).
91
+ el.addOffsetValue('my-offset', 0.6);
92
+ expect(changed.length).toBe(1);
93
+ host.remove();
94
+ });
95
+
96
+ await it('replacing an offset re-sorts the list it is walked in', () => {
97
+ const { el, host } = mount();
98
+ el.addOffsetValue('mid', 0.5);
99
+ expect(el.offsetValue('mid')).toBe(0.5);
100
+ el.addOffsetValue('mid', 0.05);
101
+ // Now the LOWEST offset of all, so it names even a value of 0.
102
+ expect(blocks(el)).toStrictEqual(['empty', 'filled mid']);
103
+ el.value = 0.3;
104
+ expect(blocks(el)).toStrictEqual(['empty', 'filled high']);
105
+ host.remove();
106
+ });
107
+
108
+ await it('removes an offset and the class goes with it', () => {
109
+ const { el, host } = mount({ value: '0.9' });
110
+ el.removeOffsetValue('full');
111
+ // Nothing is above 0.9 any more, so nothing names it.
112
+ expect(blocks(el)).toStrictEqual(['empty', 'filled']);
113
+ host.remove();
114
+ });
115
+ });
116
+
117
+ await describe('<gtk-level-bar> mode', async () => {
118
+ await it('discrete draws one block per unit of the interval, filled from the left', () => {
119
+ // gtklevelbar.c:285-294 and :630-633.
120
+ const { el, host } = mount({ mode: 'discrete', 'max-value': '5', value: '3' });
121
+ expect(el.classList.contains('discrete')).toBe(true);
122
+ expect(blocks(el)).toStrictEqual(['filled', 'filled', 'filled', 'empty', 'empty']);
123
+ host.remove();
124
+ });
125
+
126
+ await it('inverted fills from the far end without reordering the DOM', () => {
127
+ // gtklevelbar.c:637, 648 — the INDEX is reversed, the node order is not.
128
+ const { el, host } = mount({ mode: 'discrete', 'max-value': '4', value: '1', inverted: '' });
129
+ expect(blocks(el)).toStrictEqual(['empty', 'empty', 'empty', 'filled full']);
130
+ host.remove();
131
+ });
132
+
133
+ await it('a one-unit interval is one block, and the value fills none of it', () => {
134
+ // `MAX(1, round(max) − round(min))` blocks, but `MIN(blocks, round(value) −
135
+ // round(min))` of them are filled — and for a zero-width interval that second
136
+ // number is 0 (gtklevelbar.c:291, :633).
137
+ const { el, host } = mount({ mode: 'discrete', 'min-value': '3', 'max-value': '3', value: '3' });
138
+ expect(blocks(el)).toStrictEqual(['empty']);
139
+ host.remove();
140
+ });
141
+
142
+ await it('carries the orientation the stylesheet selects on', () => {
143
+ const { el, host } = mount({ orientation: 'vertical' });
144
+ expect(el.classList.contains('vertical')).toBe(true);
145
+ expect(el.classList.contains('horizontal')).toBe(false);
146
+ host.remove();
147
+ });
148
+ });
149
+
150
+ await describe('<gtk-level-bar> interval', async () => {
151
+ await it('raising the minimum drags the value up with it', () => {
152
+ // gtklevelbar.c:1191-1192 — set_min_value moves `value`, then notifies it.
153
+ const { el, host } = mount({ value: '0.1' });
154
+ const events: string[] = [];
155
+ el.addEventListener('notify::value', () => events.push('value'));
156
+ el.minValue = 0.5;
157
+ expect(el.value).toBe(0.5);
158
+ expect(events).toStrictEqual(['value']);
159
+ host.remove();
160
+ });
161
+
162
+ await it('lowering the maximum drags the value down AND clamps the offsets', () => {
163
+ // gtklevelbar.c:1229-1234 and gtk_level_bar_ensure_offsets_in_range :667-682.
164
+ const { el, host } = mount({ value: '0.9' });
165
+ el.maxValue = 0.4;
166
+ expect(el.value).toBe(0.4);
167
+ expect(el.offsetValue('high')).toBe(0.4);
168
+ expect(el.offsetValue('full')).toBe(0.4);
169
+ expect(el.getAttribute('aria-valuemax')).toBe('0.4');
170
+ host.remove();
171
+ });
172
+
173
+ await it('reports the real interval to assistive technology, not 0…1', () => {
174
+ const { el, host } = mount({ 'min-value': '10', 'max-value': '20', value: '15' });
175
+ expect(el.getAttribute('aria-valuemin')).toBe('10');
176
+ expect(el.getAttribute('aria-valuemax')).toBe('20');
177
+ expect(el.getAttribute('aria-valuenow')).toBe('15');
178
+ expect(
179
+ (el.querySelector('.adw-level-bar-block.filled') as HTMLElement).style.getPropertyValue(
180
+ '--level-fraction',
181
+ ),
182
+ ).toBe('0.5');
183
+ host.remove();
184
+ });
185
+ });
186
+
187
+ await describe('<gtk-level-bar> notification', async () => {
188
+ await it('notifies with the parsed property, and not on a re-render', () => {
189
+ const { el, host } = mount();
190
+ const details: unknown[] = [];
191
+ el.addEventListener('notify::value', (e) => details.push((e as CustomEvent).detail));
192
+ el.value = 0.4;
193
+ el.value = 0.4;
194
+ el.mode = 'discrete';
195
+ expect(details).toStrictEqual([{ value: 0.4 }]);
196
+ host.remove();
197
+ });
198
+ });
199
+ };
@@ -0,0 +1,117 @@
1
+ // DOM-level tests for <gtk-link-button>: the two properties Gtk.LinkButton adds on top of
2
+ // Gtk.Button (`uri`, `visited`), the order GTK writes them in — a new URI un-visits, a click
3
+ // visits — and the boolean-accumulator shape of `::activate-link`.
4
+ import { describe, expect, it } from '@gjsify/unit';
5
+
6
+ import type { GtkLinkButton } from './elements/gtk-link-button.js';
7
+
8
+ function mount(attrs: Record<string, string> = {}): { el: GtkLinkButton; host: HTMLElement; opened: string[] } {
9
+ const host = document.createElement('div');
10
+ document.body.appendChild(host);
11
+ const el = document.createElement('gtk-link-button') as GtkLinkButton;
12
+ for (const [name, value] of Object.entries(attrs)) el.setAttribute(name, value);
13
+ host.appendChild(el);
14
+ // `window.open` is the launcher call; the specs must not open a tab to prove a colour.
15
+ const opened: string[] = [];
16
+ (el as unknown as { launch: (uri: string) => void }).launch = (uri: string) => opened.push(uri);
17
+ return { el, host, opened };
18
+ }
19
+
20
+ /** Collect the `detail` of every `event` dispatched on (or bubbling to) `el`. */
21
+ function record(el: HTMLElement, event: string): unknown[] {
22
+ const details: unknown[] = [];
23
+ el.addEventListener(event, (e) => details.push((e as CustomEvent).detail));
24
+ return details;
25
+ }
26
+
27
+ export const GtkLinkButtonTest = async () => {
28
+ await describe('<gtk-link-button> uri', async () => {
29
+ await it('is a gtk-button with a uri, and the uri is what a new one unsets', async () => {
30
+ const { el, host } = mount({ uri: 'https://example.org/a', visited: '' });
31
+ expect(el.uri).toBe('https://example.org/a');
32
+ expect(el.visited).toBe(true);
33
+ expect(el.button.classList.contains('adw-button')).toBe(true);
34
+ expect(el.button.classList.contains('link')).toBe(true);
35
+ expect(el.button.classList.contains('visited')).toBe(true);
36
+ el.uri = 'https://example.org/b';
37
+ expect(el.getAttribute('uri')).toBe('https://example.org/b');
38
+ expect(el.visited).toBe(false);
39
+ expect(el.button.classList.contains('visited')).toBe(false);
40
+ host.remove();
41
+ });
42
+
43
+ await it('shows the uri as the tooltip only when the label is not the uri already', () => {
44
+ const named = mount({ uri: 'https://example.org/', label: 'Example' });
45
+ expect(named.el.button.title).toBe('https://example.org/');
46
+ const same = mount({ uri: 'https://example.org/', label: 'https://example.org/' });
47
+ expect(same.el.button.title).toBe('');
48
+ const own = mount({ uri: 'https://example.org/', label: 'Example', tooltip: 'Home' });
49
+ expect(own.el.button.title).toBe('Home');
50
+ named.host.remove();
51
+ same.host.remove();
52
+ own.host.remove();
53
+ });
54
+ });
55
+
56
+ await describe('<gtk-link-button> activation', async () => {
57
+ await it('a click launches the uri and then visits the link', () => {
58
+ const { el, host, opened } = mount({ uri: 'https://example.org/a', label: 'Example' });
59
+ const notified = record(el, 'notify::visited');
60
+ el.button.click();
61
+ expect(opened).toStrictEqual(['https://example.org/a']);
62
+ expect(el.visited).toBe(true);
63
+ expect(notified).toStrictEqual([{ visited: true }]);
64
+ host.remove();
65
+ });
66
+
67
+ await it('cancelling activate-link is a handler returning TRUE: no launch, no visit', () => {
68
+ const { el, host, opened } = mount({ uri: 'https://example.org/a', label: 'Example' });
69
+ let handled = false;
70
+ el.addEventListener('activate-link', (event) => {
71
+ event.preventDefault();
72
+ handled = true;
73
+ });
74
+ el.button.click();
75
+ expect(handled).toBe(true);
76
+ expect(opened).toStrictEqual([]);
77
+ expect(el.visited).toBe(false);
78
+ host.remove();
79
+ });
80
+
81
+ await it('a button with no uri launches nothing', () => {
82
+ const { el, host, opened } = mount({ label: 'Nowhere' });
83
+ el.button.click();
84
+ expect(opened).toStrictEqual([]);
85
+ expect(el.visited).toBe(false);
86
+ host.remove();
87
+ });
88
+
89
+ await it('writing the visited state directly notifies, and re-writing it does not', () => {
90
+ const { el, host } = mount({ uri: 'https://example.org/a' });
91
+ const notified = record(el, 'notify::visited');
92
+ el.visited = true;
93
+ el.visited = true;
94
+ expect(notified).toStrictEqual([{ visited: true }]);
95
+ host.remove();
96
+ });
97
+ });
98
+
99
+ await describe('<gtk-link-button> look', async () => {
100
+ await it('a visited link is drawn in a different colour than a fresh one', () => {
101
+ const { el, host } = mount({ uri: 'https://example.org/a', label: 'Example' });
102
+ const fresh = getComputedStyle(el.button).color;
103
+ el.visited = true;
104
+ expect(getComputedStyle(el.button).color === fresh).toBe(false);
105
+ host.remove();
106
+ });
107
+
108
+ await it('keeps the link treatment through a re-render of the label', () => {
109
+ const { el, host } = mount({ uri: 'https://example.org/a', label: 'Example', visited: '' });
110
+ el.setAttribute('label', 'Other');
111
+ expect(el.button.textContent).toBe('Other');
112
+ expect(el.button.classList.contains('link')).toBe(true);
113
+ expect(el.button.classList.contains('visited')).toBe(true);
114
+ host.remove();
115
+ });
116
+ });
117
+ };