@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,179 @@
1
+ // DOM-level tests for `<gtk-search-bar>`: the revealer IS `search-mode-enabled`
2
+ // (gtksearchbar.c:183-205), and the four ways a search starts and the two it stops are all in
3
+ // gtksearchbar.c.
4
+ //
5
+ // The one rule worth a row of its own is that hiding CLEARS the entry (gtksearchbar.c:197-203):
6
+ // a search that is dismissed must leave nothing behind, and that is a rule about the STATE,
7
+ // not about the animation.
8
+
9
+ import { describe, expect, it } from '@gjsify/unit';
10
+
11
+ import type { GtkSearchBar } from './elements/gtk-search-bar.js';
12
+
13
+ function mount(showClose = true): GtkSearchBar {
14
+ const el = document.createElement('gtk-search-bar') as GtkSearchBar;
15
+ const field = document.createElement('input');
16
+ field.className = 'adw-entry';
17
+ el.appendChild(field);
18
+ if (showClose) el.setAttribute('show-close-button', '');
19
+ document.body.appendChild(el);
20
+ return el;
21
+ }
22
+
23
+ function unmountAll(): void {
24
+ for (const el of Array.from(document.querySelectorAll('gtk-search-bar'))) el.remove();
25
+ }
26
+
27
+ /** The box the C builds around the child, named because `inert` is not on `Element`. */
28
+ function boxOf(el: GtkSearchBar): HTMLElement {
29
+ return el.querySelector<HTMLElement>('.adw-search-bar-box') as HTMLElement;
30
+ }
31
+
32
+ const key = (target: HTMLElement, name: string, init: KeyboardEventInit = {}): KeyboardEvent => {
33
+ const event = new KeyboardEvent('keydown', { key: name, bubbles: true, cancelable: true, ...init });
34
+ target.dispatchEvent(event);
35
+ return event;
36
+ };
37
+
38
+ export const GtkSearchBarTest = async () => {
39
+ await describe('<gtk-search-bar> search mode', async () => {
40
+ await it('starts collapsed and inert, as a revealer whose child is not mapped', () => {
41
+ const el = mount();
42
+ expect(el.searchModeEnabled).toBe(false);
43
+ expect(el.classList.contains('revealed')).toBe(false);
44
+ expect(boxOf(el).inert).toBe(true);
45
+ unmountAll();
46
+ });
47
+
48
+ await it('reveals, focuses the entry and leaves the collapsed state', () => {
49
+ const el = mount();
50
+ el.searchModeEnabled = true;
51
+ expect(el.classList.contains('revealed')).toBe(true);
52
+ expect(boxOf(el).inert).toBe(false);
53
+ expect(document.activeElement).toBe(el.entry);
54
+ unmountAll();
55
+ });
56
+
57
+ await it('clears the entry when it is hidden, and only then', () => {
58
+ const el = mount();
59
+ const entry = el.entry as HTMLInputElement;
60
+ el.searchModeEnabled = true;
61
+ entry.value = 'ada';
62
+ expect(entry.value).toBe('ada');
63
+ el.searchModeEnabled = false;
64
+ expect(entry.value).toBe('');
65
+ unmountAll();
66
+ });
67
+
68
+ await it('notifies once per real change', () => {
69
+ const el = mount();
70
+ const seen: unknown[] = [];
71
+ el.addEventListener('notify::search-mode-enabled', (event) => seen.push((event as CustomEvent).detail));
72
+ el.searchModeEnabled = true;
73
+ el.searchModeEnabled = true;
74
+ el.searchModeEnabled = false;
75
+ expect(seen).toStrictEqual([{ searchModeEnabled: true }, { searchModeEnabled: false }]);
76
+ unmountAll();
77
+ });
78
+ });
79
+
80
+ await describe('<gtk-search-bar> the close button', async () => {
81
+ await it('is hidden until `show-close-button` is set', () => {
82
+ const without = mount(false);
83
+ expect(without.showCloseButton).toBe(false);
84
+ expect(without.querySelector<HTMLButtonElement>('.adw-search-bar-close')?.hidden).toBe(true);
85
+ const with_ = mount(true);
86
+ expect(with_.showCloseButton).toBe(true);
87
+ expect(with_.querySelector<HTMLButtonElement>('.adw-search-bar-close')?.hidden).toBe(false);
88
+ unmountAll();
89
+ });
90
+
91
+ await it('turns the search off when pressed', () => {
92
+ const el = mount();
93
+ el.searchModeEnabled = true;
94
+ (el.querySelector('.adw-search-bar-close') as HTMLButtonElement).click();
95
+ expect(el.searchModeEnabled).toBe(false);
96
+ unmountAll();
97
+ });
98
+
99
+ await it('notifies once per real change', () => {
100
+ const el = mount(false);
101
+ const seen: unknown[] = [];
102
+ el.addEventListener('notify::show-close-button', (event) => seen.push((event as CustomEvent).detail));
103
+ el.showCloseButton = true;
104
+ el.showCloseButton = true;
105
+ expect(seen).toStrictEqual([{ showCloseButton: true }]);
106
+ unmountAll();
107
+ });
108
+ });
109
+
110
+ await describe('<gtk-search-bar> what starts a search', async () => {
111
+ await it('Escape inside the bar hides it', () => {
112
+ const el = mount();
113
+ el.searchModeEnabled = true;
114
+ key(el, 'Escape');
115
+ expect(el.searchModeEnabled).toBe(false);
116
+ unmountAll();
117
+ });
118
+
119
+ await it('typing into the connected editable reveals it', () => {
120
+ const el = mount();
121
+ const entry = el.entry as HTMLInputElement;
122
+ entry.value = 'a';
123
+ entry.dispatchEvent(new Event('input', { bubbles: true }));
124
+ expect(el.searchModeEnabled).toBe(true);
125
+ unmountAll();
126
+ });
127
+
128
+ await it('a printable key on the capture widget opens the bar and goes into the entry', () => {
129
+ const el = mount();
130
+ const capture = document.createElement('div');
131
+ document.body.appendChild(capture);
132
+ el.keyCaptureWidget = capture;
133
+ const event = key(capture, 'a');
134
+ expect(event.defaultPrevented).toBe(true);
135
+ expect(el.searchModeEnabled).toBe(true);
136
+ expect(el.entry?.value).toBe('a');
137
+ unmountAll();
138
+ capture.remove();
139
+ });
140
+
141
+ await it('a modified or functional key is left to the widget that owns it', () => {
142
+ const el = mount();
143
+ const capture = document.createElement('div');
144
+ document.body.appendChild(capture);
145
+ el.keyCaptureWidget = capture;
146
+ key(capture, 'a', { ctrlKey: true });
147
+ key(capture, 'ArrowDown');
148
+ expect(el.searchModeEnabled).toBe(false);
149
+ unmountAll();
150
+ capture.remove();
151
+ });
152
+
153
+ await it('stops listening once the capture widget is dropped', () => {
154
+ const el = mount();
155
+ const capture = document.createElement('div');
156
+ document.body.appendChild(capture);
157
+ el.keyCaptureWidget = capture;
158
+ el.keyCaptureWidget = null;
159
+ key(capture, 'a');
160
+ expect(el.searchModeEnabled).toBe(false);
161
+ unmountAll();
162
+ capture.remove();
163
+ });
164
+ });
165
+
166
+ await describe('<gtk-search-bar> a11y', async () => {
167
+ await it('carries the `search` role GTK declares for it', () => {
168
+ const el = mount();
169
+ expect(el.getAttribute('role')).toBe('search');
170
+ unmountAll();
171
+ });
172
+
173
+ await it("keeps the author's child inside the box the C builds around it", () => {
174
+ const el = mount();
175
+ expect(el.querySelector('.adw-search-bar-center input')).not.toBeNull();
176
+ unmountAll();
177
+ });
178
+ });
179
+ };
@@ -0,0 +1,142 @@
1
+ // DOM-level tests for <gtk-search-entry>. Its whole reason to exist is the DELAY: typing
2
+ // queues `search-changed`, emptying the field fires it at once and cancels the queue, and
3
+ // the two keybinding signals are dispatched rather than acted on.
4
+ import { describe, expect, it } from '@gjsify/unit';
5
+
6
+ import type { GtkSearchEntry } from './elements/gtk-search-entry.js';
7
+
8
+ function mount(attrs: Record<string, string> = {}): { el: GtkSearchEntry; host: HTMLElement } {
9
+ const host = document.createElement('div');
10
+ document.body.appendChild(host);
11
+ const el = document.createElement('gtk-search-entry') as GtkSearchEntry;
12
+ for (const [name, value] of Object.entries(attrs)) el.setAttribute(name, value);
13
+ host.appendChild(el);
14
+ return { el, host };
15
+ }
16
+
17
+ function inner(el: GtkSearchEntry): HTMLInputElement {
18
+ return el.querySelector('input') as HTMLInputElement;
19
+ }
20
+
21
+ function clear(el: GtkSearchEntry): HTMLButtonElement {
22
+ return el.querySelector('.adw-search-entry-clear') as HTMLButtonElement;
23
+ }
24
+
25
+ /** Wait past the default 150ms delay, which is what `search-changed` is for. */
26
+ function settle(ms = 220): Promise<void> {
27
+ return new Promise((resolve) => setTimeout(resolve, ms));
28
+ }
29
+
30
+ export const GtkSearchEntryTest = async () => {
31
+ await describe('<gtk-search-entry> the two icons', async () => {
32
+ await it('shows the search glyph always and the clear button only with text', () => {
33
+ const { el, host } = mount();
34
+ expect(el.querySelector('.adw-search-entry-icon')).not.toBeNull();
35
+ expect(clear(el).hidden).toBe(true);
36
+ inner(el).value = 'gjs';
37
+ inner(el).dispatchEvent(new Event('input'));
38
+ expect(clear(el).hidden).toBe(false);
39
+ host.remove();
40
+ });
41
+
42
+ await it('is a search box to assistive technology', () => {
43
+ const { el, host } = mount();
44
+ expect(el.getAttribute('role')).toBe('searchbox');
45
+ expect(el.querySelector('.adw-search-entry-clear')?.getAttribute('aria-label')).toBe('Clear Entry');
46
+ host.remove();
47
+ });
48
+
49
+ await it('the clear button empties the field, as gtk_icon_release does', () => {
50
+ const { el, host } = mount({ value: 'gtk' });
51
+ clear(el).click();
52
+ expect(inner(el).value).toBe('');
53
+ expect(clear(el).hidden).toBe(true);
54
+ host.remove();
55
+ });
56
+ });
57
+
58
+ await describe('<gtk-search-entry> search-delay', async () => {
59
+ await it('defaults to 150ms, which is the pspec default', () => {
60
+ const { el, host } = mount();
61
+ expect(el.searchDelay).toBe(150);
62
+ el.setAttribute('search-delay', '0');
63
+ expect(el.searchDelay).toBe(0);
64
+ host.remove();
65
+ });
66
+
67
+ await it('a keystroke queues search-changed instead of firing it at once', async () => {
68
+ const { el, host } = mount();
69
+ const seen: unknown[] = [];
70
+ el.addEventListener('search-changed', (e) => seen.push((e as CustomEvent).detail));
71
+ inner(el).value = 'g';
72
+ inner(el).dispatchEvent(new Event('input'));
73
+ expect(seen.length).toBe(0);
74
+ await settle();
75
+ expect(seen).toStrictEqual([{ value: 'g' }]);
76
+ host.remove();
77
+ });
78
+
79
+ await it('two keystrokes make ONE signal — the timeout is replaced, not queued', async () => {
80
+ const { el, host } = mount();
81
+ let count = 0;
82
+ el.addEventListener('search-changed', () => (count += 1));
83
+ for (const text of ['g', 'gj', 'gjs']) {
84
+ inner(el).value = text;
85
+ inner(el).dispatchEvent(new Event('input'));
86
+ }
87
+ await settle();
88
+ expect(count).toBe(1);
89
+ host.remove();
90
+ });
91
+
92
+ await it('emptying the field fires at once and cancels what was pending', async () => {
93
+ const { el, host } = mount({ value: 'gjs' });
94
+ const seen: unknown[] = [];
95
+ el.addEventListener('search-changed', (e) => seen.push((e as CustomEvent).detail));
96
+ clear(el).click();
97
+ expect(seen).toStrictEqual([{ value: '' }]);
98
+ await settle();
99
+ expect(seen.length).toBe(1);
100
+ host.remove();
101
+ });
102
+ });
103
+
104
+ await describe('<gtk-search-entry> keys', async () => {
105
+ await it('Enter activates and Escape stops the search', () => {
106
+ const { el, host } = mount();
107
+ const seen: string[] = [];
108
+ for (const name of ['activate', 'stop-search', 'next-match', 'previous-match']) {
109
+ el.addEventListener(name, () => seen.push(name));
110
+ }
111
+ const press = (key: string, init: KeyboardEventInit = {}) =>
112
+ inner(el).dispatchEvent(
113
+ new KeyboardEvent('keydown', { key, bubbles: true, cancelable: true, ...init }),
114
+ );
115
+ press('Enter');
116
+ press('Escape');
117
+ press('g', { ctrlKey: true });
118
+ press('g', { ctrlKey: true, shiftKey: true });
119
+ expect(seen).toStrictEqual(['activate', 'stop-search', 'next-match', 'previous-match']);
120
+ host.remove();
121
+ });
122
+
123
+ await it('a bare g is text, not next-match', () => {
124
+ const { el, host } = mount();
125
+ let count = 0;
126
+ el.addEventListener('next-match', () => (count += 1));
127
+ inner(el).dispatchEvent(new KeyboardEvent('keydown', { key: 'g', bubbles: true, cancelable: true }));
128
+ expect(count).toBe(0);
129
+ host.remove();
130
+ });
131
+ });
132
+
133
+ await describe('<gtk-search-entry> as an entry', async () => {
134
+ await it('keeps the value, placeholder and disabled behaviour it inherits', () => {
135
+ const { el, host } = mount({ value: 'gtk', placeholder: 'Search…', disabled: '' });
136
+ expect(el.value).toBe('gtk');
137
+ expect(inner(el).placeholder).toBe('Search…');
138
+ expect(inner(el).disabled).toBe(true);
139
+ host.remove();
140
+ });
141
+ });
142
+ };
@@ -0,0 +1,74 @@
1
+ // DOM-level tests for <gtk-separator>: the orientation property is GtkOrientable's (shared
2
+ // parser with <gtk-box>), the host carries the orientation as the CSS state the stylesheet
3
+ // selects on, and the RENDERED box is a one-pixel rule, or a 12px gap for `.spacer`.
4
+ import { describe, expect, it } from '@gjsify/unit';
5
+
6
+ import type { GtkSeparator } from './elements/gtk-separator.js';
7
+
8
+ function mount(attrs: Record<string, string> = {}): { el: GtkSeparator; host: HTMLElement } {
9
+ const host = document.createElement('div');
10
+ document.body.appendChild(host);
11
+ const el = document.createElement('gtk-separator') as GtkSeparator;
12
+ for (const [name, value] of Object.entries(attrs)) el.setAttribute(name, value);
13
+ host.appendChild(el);
14
+ return { el, host };
15
+ }
16
+
17
+ export const GtkSeparatorTest = async () => {
18
+ await describe('<gtk-separator> orientation', async () => {
19
+ await it('is horizontal by default and says so to CSS and to assistive technology', () => {
20
+ const { el, host } = mount();
21
+ expect(el.orientation).toBe('horizontal');
22
+ expect(el.classList.contains('horizontal')).toBe(true);
23
+ expect(el.classList.contains('vertical')).toBe(false);
24
+ expect(el.getAttribute('role')).toBe('separator');
25
+ expect(el.getAttribute('aria-orientation')).toBe('horizontal');
26
+ host.remove();
27
+ });
28
+
29
+ await it('follows the attribute and the property, and an unknown value is the default', () => {
30
+ const { el, host } = mount({ orientation: 'vertical' });
31
+ expect(el.orientation).toBe('vertical');
32
+ expect(el.classList.contains('vertical')).toBe(true);
33
+ el.orientation = 'horizontal';
34
+ expect(el.getAttribute('orientation')).toBe('horizontal');
35
+ expect(el.classList.contains('horizontal')).toBe(true);
36
+ expect(el.classList.contains('vertical')).toBe(false);
37
+ el.setAttribute('orientation', 'diagonal');
38
+ expect(el.orientation).toBe('horizontal');
39
+ host.remove();
40
+ });
41
+ });
42
+
43
+ await describe('<gtk-separator> geometry', async () => {
44
+ await it('a horizontal rule is 1px tall and takes the width it is given', () => {
45
+ const { el, host } = mount();
46
+ host.style.width = '200px';
47
+ const box = el.getBoundingClientRect();
48
+ expect(box.height).toBe(1);
49
+ expect(box.width).toBe(200);
50
+ host.remove();
51
+ });
52
+
53
+ await it('a vertical rule is 1px wide', () => {
54
+ const { el, host } = mount({ orientation: 'vertical' });
55
+ expect(el.getBoundingClientRect().width).toBe(1);
56
+ host.remove();
57
+ });
58
+
59
+ await it('.spacer draws nothing and reserves 12px along its axis', () => {
60
+ const { el, host } = mount();
61
+ el.classList.add('spacer');
62
+ host.style.width = '200px';
63
+ expect(getComputedStyle(el).backgroundImage).toBe('none');
64
+ expect(getComputedStyle(el).backgroundColor).toBe('rgba(0, 0, 0, 0)');
65
+ const vertical = mount({ orientation: 'vertical' });
66
+ vertical.el.classList.add('spacer');
67
+ const box = vertical.el.getBoundingClientRect();
68
+ expect(box.height).toBe(12);
69
+ expect(box.width).toBe(1);
70
+ host.remove();
71
+ vertical.host.remove();
72
+ });
73
+ });
74
+ };
@@ -0,0 +1,186 @@
1
+ // DOM-level tests for <gtk-spin-button>. It is an entry with two arrows, so what matters
2
+ // here is `Gtk.SpinButton`'s own half: the child ORDER C parents them in, `real_spin`'s
3
+ // wrap branches, `update`'s two policies, `snap-to-ticks` and the arrows' sensitivity.
4
+ import { describe, expect, it } from '@gjsify/unit';
5
+
6
+ import type { GtkSpinButton } from './elements/gtk-spin-button.js';
7
+
8
+ function mount(attrs: Record<string, string> = {}): { el: GtkSpinButton; host: HTMLElement } {
9
+ const host = document.createElement('div');
10
+ document.body.appendChild(host);
11
+ const el = document.createElement('gtk-spin-button') as GtkSpinButton;
12
+ for (const [name, value] of Object.entries(attrs)) el.setAttribute(name, value);
13
+ host.appendChild(el);
14
+ return { el, host };
15
+ }
16
+
17
+ function record(el: HTMLElement, event: string): unknown[] {
18
+ const details: unknown[] = [];
19
+ el.addEventListener(event, (e) => details.push((e as CustomEvent).detail));
20
+ return details;
21
+ }
22
+
23
+ function arrows(el: GtkSpinButton): { up: HTMLButtonElement; down: HTMLButtonElement } {
24
+ return {
25
+ up: el.querySelector('.image-button.up') as HTMLButtonElement,
26
+ down: el.querySelector('.image-button.down') as HTMLButtonElement,
27
+ };
28
+ }
29
+
30
+ export const GtkSpinButtonTest = async () => {
31
+ await describe('<gtk-spin-button> structure', async () => {
32
+ await it('parents text, down, up horizontally — the order C builds them in', () => {
33
+ const { el, host } = mount();
34
+ const parts = [...el.children];
35
+ expect(parts.map((n) => n.className.split(' ')[0])).toStrictEqual([
36
+ 'adw-spin-button-text',
37
+ 'adw-button',
38
+ 'adw-button',
39
+ ]);
40
+ expect((parts[2] as HTMLElement).classList.contains('up')).toBe(true);
41
+ expect(el.getAttribute('role')).toBe('spinbutton');
42
+ host.remove();
43
+ });
44
+
45
+ await it('a vertical spin button moves the up arrow to the front', () => {
46
+ const { el, host } = mount({ orientation: 'vertical' });
47
+ expect((el.children[0] as HTMLElement).classList.contains('up')).toBe(true);
48
+ expect((el.children[2] as HTMLElement).classList.contains('down')).toBe(true);
49
+ host.remove();
50
+ });
51
+
52
+ await it('the field shows the formatted value and one digit is the default', () => {
53
+ const { el, host } = mount({ adjustment: '{"lower":0,"upper":10,"stepIncrement":0.5}', value: '2.5' });
54
+ // `digits` is 0, so the field shows the value rounded to a whole number — which
55
+ // is exactly what `gtk_spin_button_format_for_value`'s `%0.*f` does.
56
+ expect(el.digits).toBe(0);
57
+ expect(el.text.value).toBe('3');
58
+ el.setAttribute('digits', '1');
59
+ expect(el.text.value).toBe('2.5');
60
+ host.remove();
61
+ });
62
+ });
63
+
64
+ await describe('<gtk-spin-button> stepping', async () => {
65
+ await it('an arrow press steps by the adjustment step and notifies once', () => {
66
+ const { el, host } = mount({ adjustment: '{"lower":0,"upper":10,"stepIncrement":2}' });
67
+ const changed = record(el, 'value-changed');
68
+ arrows(el).up.click();
69
+ expect(el.value).toBe(2);
70
+ arrows(el).down.click();
71
+ expect(el.value).toBe(0);
72
+ expect(changed).toStrictEqual([{ value: 2 }, { value: 0 }]);
73
+ host.remove();
74
+ });
75
+
76
+ await it('without wrap an arrow goes insensitive at the bound, as C computes it', () => {
77
+ const { el, host } = mount({ adjustment: '{"lower":0,"upper":10,"stepIncrement":1}' });
78
+ const { up, down } = arrows(el);
79
+ // At the lower bound the DOWN arrow has nowhere to go and the UP arrow does.
80
+ expect(down.disabled).toBe(true);
81
+ expect(up.disabled).toBe(false);
82
+ el.value = 10;
83
+ expect(up.disabled).toBe(true);
84
+ expect(down.disabled).toBe(false);
85
+ host.remove();
86
+ });
87
+
88
+ await it('with wrap an arrow at the bound jumps to the other end and emits wrapped', () => {
89
+ const { el, host } = mount({ adjustment: '{"lower":0,"upper":10,"stepIncrement":1}', wrap: '' });
90
+ const wrapped = record(el, 'wrapped');
91
+ const { up, down } = arrows(el);
92
+ expect(up.disabled).toBe(false);
93
+ expect(down.disabled).toBe(false);
94
+ up.click();
95
+ expect(el.value).toBe(1);
96
+ expect(wrapped.length).toBe(0);
97
+ el.value = 10;
98
+ up.click();
99
+ // `gtk_spin_button_real_spin`'s wrap branch sets the OTHER BOUND, not "one step
100
+ // away from it": an arrow pressed at 10 in a range of 0…10 lands on 0.
101
+ expect(el.value).toBe(0);
102
+ down.click();
103
+ expect(el.value).toBe(10);
104
+ expect(wrapped.length).toBe(2);
105
+ host.remove();
106
+ });
107
+
108
+ await it('an arrow key steps and Page Up pages', () => {
109
+ const { el, host } = mount({ adjustment: '{"lower":0,"upper":100,"stepIncrement":1,"pageIncrement":10}' });
110
+ const press = (key: string) =>
111
+ el.text.dispatchEvent(new KeyboardEvent('keydown', { key, bubbles: true, cancelable: true }));
112
+ press('ArrowUp');
113
+ expect(el.value).toBe(1);
114
+ press('PageUp');
115
+ expect(el.value).toBe(11);
116
+ press('ArrowDown');
117
+ expect(el.value).toBe(10);
118
+ host.remove();
119
+ });
120
+ });
121
+
122
+ await describe('<gtk-spin-button> committing', async () => {
123
+ await it('always clamps a typed value that is out of range', () => {
124
+ const { el, host } = mount({ adjustment: '{"lower":0,"upper":10,"stepIncrement":1}' });
125
+ el.text.value = '99';
126
+ el.text.dispatchEvent(new Event('change'));
127
+ expect(el.value).toBe(10);
128
+ host.remove();
129
+ });
130
+
131
+ await it('if-valid leaves the committed value alone and re-formats the field', () => {
132
+ const { el, host } = mount({
133
+ adjustment: '{"lower":0,"upper":10,"stepIncrement":1,"value":5}',
134
+ 'update-policy': 'if-valid',
135
+ });
136
+ el.text.value = '99';
137
+ el.text.dispatchEvent(new Event('change'));
138
+ expect(el.value).toBe(5);
139
+ expect(el.text.value).toBe('5');
140
+ host.remove();
141
+ });
142
+
143
+ await it('snap-to-ticks lands a typed value on the step grid', () => {
144
+ const { el, host } = mount({
145
+ adjustment: '{"lower":0,"upper":10,"stepIncrement":4}',
146
+ 'snap-to-ticks': '',
147
+ });
148
+ el.text.value = '7';
149
+ el.text.dispatchEvent(new Event('change'));
150
+ expect(el.value).toBe(8);
151
+ host.remove();
152
+ });
153
+
154
+ await it('numeric refuses letters, a second point and a trailing sign', () => {
155
+ const { el, host } = mount({ numeric: '', digits: '2' });
156
+ // A refused character restores the FORMATTED value, so the field reads `0.00`
157
+ // at the two digits this story sets — not a bare `0`.
158
+ el.text.value = '1a';
159
+ el.text.dispatchEvent(new Event('input'));
160
+ expect(el.text.value).toBe('0.00');
161
+ el.text.value = '1.5';
162
+ el.text.dispatchEvent(new Event('input'));
163
+ expect(el.text.value).toBe('1.5');
164
+ el.text.value = '1.5.';
165
+ el.text.dispatchEvent(new Event('input'));
166
+ expect(el.text.value).toBe('0.00');
167
+ el.text.value = '-3';
168
+ el.text.dispatchEvent(new Event('input'));
169
+ expect(el.text.value).toBe('-3');
170
+ host.remove();
171
+ });
172
+
173
+ await it('Enter activates only when the text was not edited', () => {
174
+ const { el, host } = mount({ adjustment: '{"lower":0,"upper":10,"stepIncrement":1}' });
175
+ const activated = record(el, 'activate');
176
+ el.text.dispatchEvent(new KeyboardEvent('keydown', { key: 'Enter', bubbles: true, cancelable: true }));
177
+ expect(activated.length).toBe(1);
178
+ el.text.value = '3';
179
+ el.text.dispatchEvent(new Event('input'));
180
+ el.text.dispatchEvent(new KeyboardEvent('keydown', { key: 'Enter', bubbles: true, cancelable: true }));
181
+ expect(el.value).toBe(3);
182
+ expect(activated.length).toBe(1);
183
+ host.remove();
184
+ });
185
+ });
186
+ };