@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,475 @@
1
+ // <gtk-spin-button> — a number field with a decrement and an increment arrow either side of it.
2
+ //
3
+ // THE RANGE IS HEADLESS: `SpinState` from `@gjsify/adwaita-core` IS the portable
4
+ // `Gtk.Adjustment` (ADR 0047), the same one `<adw-spin-row>` and `<gtk-scale>` hold, so
5
+ // the `adjustment` attribute takes the same portable value on all three.
6
+ //
7
+ // THE CHILD ORDER IS `Gtk.SpinButton`'s, not the one a spinner usually draws. C builds
8
+ // its children in the order text, down, up (gtkspinbutton.c:1091-1126) and the box layout
9
+ // lays them out in it, so `Gtk.SpinButton` is `text ▼ ▲` horizontally and `▲ text ▼`
10
+ // vertically — `gtk_spin_button_set_orientation` MOVES the up arrow between the two
11
+ // (`insert_after (up, …, down)` for horizontal, `insert_before (up, …, entry)` for
12
+ // vertical, gtkspinbutton.c:1290-1299) and this element re-parents the same way, which is
13
+ // what libadwaita's `:first-child` / `:last-child` corner rules are written against.
14
+ //
15
+ // `snap-to-ticks` and `numeric` are `gtk_spin_button_update` / `gtk_spin_button_insert_text`
16
+ // ported literally, and `wrap` is `gtk_spin_button_real_spin`'s two branches.
17
+ //
18
+ // NOT PORTED: `input` / `output`, the two class-override hooks on the signal. They are C
19
+ // function pointers with no declarative spelling, and `gtk_spin_button_default_input` /
20
+ // `default_output` — the behaviour this element implements — are what they fall back to.
21
+ // `activates-default` is in `KNOWN_GAPS`: activating "the default widget" is a toplevel
22
+ // GTK concept a browser document has no word for.
23
+ //
24
+ // Reference: refs/libadwaita/src/stylesheet/widgets/_spin-button.scss:1-76
25
+ // Reference: refs/gtk/gtk/gtkspinbutton.c (properties, real_spin, update, insert_text,
26
+ // update_buttons_sensitivity, gtk_spin_button_timer, format_for_value)
27
+ // Copyright (c) GNOME contributors (libadwaita, GTK). LGPLv2.1+.
28
+ // Modifications: Implemented as a Web Component for @gjsify/adwaita-web; the range state
29
+ // composed from @gjsify/adwaita-core.
30
+
31
+ import { SpinState, glibClamp, normalizeAdjustment, parseAdjustment, snapAdjustmentValue } from '@gjsify/adwaita-core';
32
+ import type { AdwAdjustment, AdwAdjustmentInput } from '@gjsify/adwaita-core';
33
+
34
+ import { createGtkImage } from './gtk-image.js';
35
+
36
+ import { formatScaleValue } from './gtk-scale.js';
37
+
38
+ /** `EPSILON` in gtkspinbutton.c:64 — the "is the value already at the bound" test. */
39
+ const EPSILON = 1e-10;
40
+
41
+ /** `TIMEOUT_INITIAL` / `TIMEOUT_REPEAT` / `MAX_TIMER_CALLS` (gtkspinbutton.c:63-67). */
42
+ const TIMEOUT_INITIAL = 500;
43
+ const TIMEOUT_REPEAT = 50;
44
+ const MAX_TIMER_CALLS = 5;
45
+
46
+ /** `Gtk.SpinButtonUpdatePolicy` nicks; `always` is the pspec default (gtkspinbutton.c:472-475). */
47
+ const UPDATE_POLICIES = ['always', 'if-valid'] as const;
48
+
49
+ export class GtkSpinButton extends HTMLElement {
50
+ private readonly _range = new SpinState();
51
+ private _input!: HTMLInputElement;
52
+ private _down!: HTMLButtonElement;
53
+ private _up!: HTMLButtonElement;
54
+ private _initialized = false;
55
+ private _edited = false;
56
+ /** The orientation the children are CURRENTLY arranged for — see `_render`. */
57
+ private _vertical: boolean | null = null;
58
+ private _initialTimer: number | null = null;
59
+ private _repeatTimer: number | null = null;
60
+ private _timerCalls = 0;
61
+ private _timerStep = 0;
62
+
63
+ static get observedAttributes() {
64
+ return [
65
+ 'adjustment',
66
+ 'climb-rate',
67
+ 'digits',
68
+ 'disabled',
69
+ 'numeric',
70
+ 'orientation',
71
+ 'snap-to-ticks',
72
+ 'update-policy',
73
+ 'value',
74
+ 'wrap',
75
+ ];
76
+ }
77
+
78
+ /** The numeric range — `Gtk.SpinButton:adjustment`, as the portable value. Writes MERGE. */
79
+ get adjustment(): AdwAdjustment {
80
+ return this._range.adjustment;
81
+ }
82
+
83
+ set adjustment(value: AdwAdjustmentInput | string) {
84
+ this._range.configure(typeof value === 'string' ? parseAdjustment(value) : value);
85
+ this._render();
86
+ }
87
+
88
+ /** `Gtk.SpinButton:value` — always inside `adjustmentRange`. */
89
+ get value(): number {
90
+ return this._range.value;
91
+ }
92
+
93
+ set value(v: number) {
94
+ this._range.setValue(v);
95
+ this._render();
96
+ }
97
+
98
+ /** `Gtk.SpinButton:digits` — `gtk_spin_button_init` starts it at 0. */
99
+ get digits(): number {
100
+ const declared = Number.parseInt(this.getAttribute('digits') ?? '', 10);
101
+ return Number.isFinite(declared) ? Math.max(0, declared) : 0;
102
+ }
103
+
104
+ set digits(value: number) {
105
+ this.setAttribute('digits', String(value));
106
+ }
107
+
108
+ /** `Gtk.SpinButton:numeric` — "whether non-numeric characters should be ignored". */
109
+ get numeric(): boolean {
110
+ return this.hasAttribute('numeric');
111
+ }
112
+
113
+ set numeric(value: boolean) {
114
+ this.toggleAttribute('numeric', !!value);
115
+ }
116
+
117
+ /** `Gtk.SpinButton:snap-to-ticks`. */
118
+ get snapToTicks(): boolean {
119
+ return this.hasAttribute('snap-to-ticks');
120
+ }
121
+
122
+ set snapToTicks(value: boolean) {
123
+ this.toggleAttribute('snap-to-ticks', !!value);
124
+ }
125
+
126
+ /** `Gtk.SpinButton:wrap` — whether the value wraps at either bound. */
127
+ get wrap(): boolean {
128
+ return this.hasAttribute('wrap');
129
+ }
130
+
131
+ set wrap(value: boolean) {
132
+ this.toggleAttribute('wrap', !!value);
133
+ }
134
+
135
+ /** `Gtk.SpinButton:update-policy` — `always` (the default) or `if-valid`. */
136
+ get updatePolicy(): (typeof UPDATE_POLICIES)[number] {
137
+ const declared = this.getAttribute('update-policy');
138
+ return UPDATE_POLICIES.includes(declared as (typeof UPDATE_POLICIES)[number])
139
+ ? (declared as (typeof UPDATE_POLICIES)[number])
140
+ : 'always';
141
+ }
142
+
143
+ set updatePolicy(value: (typeof UPDATE_POLICIES)[number]) {
144
+ this.setAttribute('update-policy', value);
145
+ }
146
+
147
+ /** `Gtk.SpinButton:climb-rate` — the acceleration of a held arrow. */
148
+ get climbRate(): number {
149
+ const declared = Number.parseFloat(this.getAttribute('climb-rate') ?? '');
150
+ return Number.isFinite(declared) && declared > 0 ? declared : 0;
151
+ }
152
+
153
+ set climbRate(value: number) {
154
+ this.setAttribute('climb-rate', String(value));
155
+ }
156
+
157
+ /** The inner text node, for a consumer that needs to place a caret in it. */
158
+ get text(): HTMLInputElement {
159
+ return this._input;
160
+ }
161
+
162
+ connectedCallback() {
163
+ if (this._initialized) return;
164
+ this._initialized = true;
165
+
166
+ // Range and authored value in ONE configure, as `GtkSpinButton`'s constructor takes
167
+ // both: a `value` written through a setter after the range would notify a value the
168
+ // widget never had, and `SpinState.configure` treats an authored value as a
169
+ // placement either way.
170
+ const range = normalizeAdjustment(parseAdjustment(this.getAttribute('adjustment')));
171
+ const authored = this.getAttribute('value');
172
+ const authoredValue = authored === null ? Number.NaN : Number.parseFloat(authored);
173
+ this._range.configure(Number.isFinite(authoredValue) ? { ...range, value: authoredValue } : range);
174
+
175
+ this._input = document.createElement('input');
176
+ this._input.className = 'adw-spin-button-text';
177
+ this._input.type = 'text';
178
+ this._input.inputMode = 'decimal';
179
+ this._input.autocomplete = 'off';
180
+ this._input.spellcheck = false;
181
+
182
+ // `can_focus` is FALSE on both arrows in C (gtkspinbutton.c:1106, 1125) — the field
183
+ // owns the keys and the arrows are pointer targets. They stay real buttons here so a
184
+ // click reaches them, and each carries the label C gives its accessible role NONE.
185
+ this._down = document.createElement('button');
186
+ this._down.type = 'button';
187
+ this._down.className = 'adw-button image-button down';
188
+ this._down.append(createGtkImage('value-decrease-symbolic'));
189
+ this._down.setAttribute('aria-label', 'Decrease');
190
+ this._up = document.createElement('button');
191
+ this._up.type = 'button';
192
+ this._up.className = 'adw-button image-button up';
193
+ this._up.append(createGtkImage('value-increase-symbolic'));
194
+ this._up.setAttribute('aria-label', 'Increase');
195
+
196
+ this._down.addEventListener('click', () => this._spin(-this._range.adjustment.stepIncrement));
197
+ this._up.addEventListener('click', () => this._spin(this._range.adjustment.stepIncrement));
198
+ this._hold(this._down, -1);
199
+ this._hold(this._up, 1);
200
+
201
+ this._input.addEventListener('input', () => {
202
+ this._edited = true;
203
+ if (this.numeric) this._rejectNonNumeric();
204
+ });
205
+ this._input.addEventListener('change', () => this._update());
206
+ this._input.addEventListener('keydown', (event) => this._onKeyDown(event));
207
+
208
+ // `Gtk.AccessibleRole.spin_button` (gtkspinbutton.c:660), with the range's own
209
+ // min/max/now, which C announces through `adjustment_changed_cb` (gtkspinbutton.c:1237-1246).
210
+ this.setAttribute('role', 'spinbutton');
211
+ this.replaceChildren(this._input, this._down, this._up);
212
+
213
+ this._range.subscribe((change) => {
214
+ this._render();
215
+ this.dispatchEvent(new CustomEvent('value-changed', { bubbles: true, detail: { value: change.value } }));
216
+ });
217
+ this._range.subscribeChanged(() => this._render());
218
+
219
+ this._render();
220
+ }
221
+
222
+ attributeChangedCallback(name: string) {
223
+ if (!this._initialized) return;
224
+ if (name === 'adjustment') {
225
+ this._range.configure(parseAdjustment(this.getAttribute('adjustment')));
226
+ return;
227
+ }
228
+ if (name === 'value') {
229
+ this._range.setValue(Number.parseFloat(this.getAttribute('value') ?? '0'));
230
+ return;
231
+ }
232
+ this._render();
233
+ }
234
+
235
+ /**
236
+ * `gtk_spin_button_real_spin` (gtkspinbutton.c:1666-1711), the whole of it: the two wrap
237
+ * branches, the two clamp branches and the `wrapped` signal.
238
+ *
239
+ * The clamp itself is `SpinState`'s; what is here is that `wrap` REPLACES it, which is
240
+ * why this is a method and not `increment()`/`decrement()` on the core state.
241
+ */
242
+ private _spin(increment: number): void {
243
+ const adjustment = this.adjustment;
244
+ let next = adjustment.value + increment;
245
+ let wrapped = false;
246
+ if (increment > 0) {
247
+ if (this.wrap) {
248
+ if (Math.abs(adjustment.value - adjustment.upper) < EPSILON) {
249
+ next = adjustment.lower;
250
+ wrapped = true;
251
+ } else if (next > adjustment.upper) next = adjustment.upper;
252
+ } else {
253
+ next = Math.min(next, adjustment.upper);
254
+ }
255
+ } else if (increment < 0) {
256
+ if (this.wrap) {
257
+ if (Math.abs(adjustment.value - adjustment.lower) < EPSILON) {
258
+ next = adjustment.upper;
259
+ wrapped = true;
260
+ } else if (next < adjustment.lower) next = adjustment.lower;
261
+ } else {
262
+ next = Math.max(next, adjustment.lower);
263
+ }
264
+ }
265
+ if (Math.abs(next - adjustment.value) > EPSILON) this._range.setValueInteractive(next);
266
+ if (wrapped) this.dispatchEvent(new CustomEvent('wrapped', { bubbles: true }));
267
+ }
268
+
269
+ /**
270
+ * `gtk_spin_button_update` (gtkspinbutton.c:1795-1832) over
271
+ * `gtk_spin_button_default_input` (gtkspinbutton.c:1673-1752).
272
+ *
273
+ * `update-policy` is the two branches that decide what a bad entry does: `always`
274
+ * clamps, `if-valid` leaves the field ALONE and re-formats the committed value — which
275
+ * is the `value_changed` call plus the early return C does at :1820-1824.
276
+ */
277
+ private _update(): void {
278
+ const adjustment = this.adjustment;
279
+ const parsed = Number.parseFloat(this._input.value);
280
+ const error = this._input.value.trim() !== '' && Number.isNaN(parsed);
281
+ if (this.updatePolicy === 'always') {
282
+ const target = error || !Number.isFinite(parsed) ? adjustment.value : parsed;
283
+ const bounded = glibClamp(target, adjustment.lower, adjustment.upper - adjustment.pageSize);
284
+ this._commit(this.snapToTicks ? snapAdjustmentValue(adjustment, bounded) : bounded);
285
+ return;
286
+ }
287
+ if (error || !Number.isFinite(parsed) || parsed < adjustment.lower || parsed > adjustment.upper) {
288
+ this._render();
289
+ this.dispatchEvent(
290
+ new CustomEvent('value-changed', { bubbles: true, detail: { value: this._range.value } }),
291
+ );
292
+ return;
293
+ }
294
+ this._commit(this.snapToTicks ? snapAdjustmentValue(adjustment, parsed) : parsed);
295
+ }
296
+
297
+ private _commit(target: number): void {
298
+ this._range.setValue(target);
299
+ this._edited = false;
300
+ this._render();
301
+ }
302
+
303
+ /**
304
+ * `gtk_spin_button_insert_text`'s `numeric` filter (gtkspinbutton.c:1589-1649), applied to
305
+ * the field's whole text rather than to one insertion — a browser input hands over the
306
+ * result, not the keystroke. The three refusals C has are the three here: a sign after
307
+ * the first character, a decimal point when `digits` is 0 or one is already there, and
308
+ * anything that is not a digit.
309
+ */
310
+ private _rejectNonNumeric(): void {
311
+ const digits = this.digits;
312
+ let seenSign = false;
313
+ let seenPoint = false;
314
+ let out = '';
315
+ for (const character of this._input.value) {
316
+ if (character === '-' || character === '+') {
317
+ // Only one sign, and only leading — C returns on any later one.
318
+ if (seenSign || out !== '') return this._resetText();
319
+ seenSign = true;
320
+ out += character;
321
+ continue;
322
+ }
323
+ if (character === '.') {
324
+ if (!digits || seenPoint) return this._resetText();
325
+ seenPoint = true;
326
+ out += character;
327
+ continue;
328
+ }
329
+ if (character < '0' || character > '9') return this._resetText();
330
+ out += character;
331
+ }
332
+ if (out !== this._input.value) this._input.value = out;
333
+ }
334
+
335
+ /** A refused character drops the WHOLE edit and restores the formatted value, as C does. */
336
+ private _resetText(): void {
337
+ this._input.value = this._formatted();
338
+ }
339
+
340
+ /**
341
+ * The held-arrow repeat, `gtk_spin_button_timer` (gtkspinbutton.c:1374-1407) with the
342
+ * two constants that shape it.
343
+ *
344
+ * The ramp is C's exactly: the step grows by `climb-rate` once every `MAX_TIMER_CALLS`
345
+ * ticks, and only while it is still below `page-increment`.
346
+ */
347
+ private _hold(button: HTMLButtonElement, direction: 1 | -1): void {
348
+ const begin = (event: PointerEvent) => {
349
+ if (event.button !== 0 || this.hasAttribute('disabled')) return;
350
+ this._timerStep = this._range.adjustment.stepIncrement;
351
+ this._timerCalls = 0;
352
+ this._spin(direction * this._timerStep);
353
+ this._initialTimer = window.setTimeout(() => {
354
+ this._initialTimer = null;
355
+ this._spin(direction * this._timerStep);
356
+ this._repeatTimer = window.setInterval(() => this._tick(direction), TIMEOUT_REPEAT);
357
+ }, TIMEOUT_INITIAL);
358
+ };
359
+ const end = () => this._stopHold();
360
+ button.addEventListener('pointerdown', begin);
361
+ button.addEventListener('pointerup', end);
362
+ button.addEventListener('pointerleave', end);
363
+ button.addEventListener('pointercancel', end);
364
+ }
365
+
366
+ private _tick(direction: 1 | -1): void {
367
+ this._spin(direction * this._timerStep);
368
+ const adjustment = this._range.adjustment;
369
+ if (this.climbRate > 0 && this._timerStep < adjustment.pageIncrement) {
370
+ if (this._timerCalls < MAX_TIMER_CALLS) this._timerCalls += 1;
371
+ else {
372
+ this._timerCalls = 0;
373
+ this._timerStep += this.climbRate;
374
+ }
375
+ }
376
+ }
377
+
378
+ private _stopHold(): void {
379
+ if (this._initialTimer !== null) {
380
+ clearTimeout(this._initialTimer);
381
+ this._initialTimer = null;
382
+ }
383
+ if (this._repeatTimer !== null) {
384
+ clearInterval(this._repeatTimer);
385
+ this._repeatTimer = null;
386
+ }
387
+ this._timerCalls = 0;
388
+ this._timerStep = 0;
389
+ }
390
+
391
+ /**
392
+ * The keys `GtkSpinButton` takes on the entry (gtkspinbutton.c:1495-1525): the arrows and
393
+ * Page Up/Down move by the step and the page, and the vertical pair is bound on the
394
+ * SCROLL controller rather than the keyboard — which is the same "arrows step whatever way
395
+ * the widget runs" rule `GtkScale` states in its own words.
396
+ */
397
+ private _onKeyDown(event: KeyboardEvent): void {
398
+ const adjustment = this._range.adjustment;
399
+ const step = adjustment.stepIncrement;
400
+ const page = adjustment.pageIncrement;
401
+ let increment: number | null = null;
402
+ switch (event.key) {
403
+ case 'ArrowUp':
404
+ increment = step;
405
+ break;
406
+ case 'ArrowDown':
407
+ increment = -step;
408
+ break;
409
+ case 'PageUp':
410
+ increment = page;
411
+ break;
412
+ case 'PageDown':
413
+ increment = -page;
414
+ break;
415
+ case 'Enter': {
416
+ // `gtk_spin_button_activate` (gtkspinbutton.c:1565-1579) emits `activate` only
417
+ // when the text was NOT edited, and `gtk_spin_button_update` resets the latch.
418
+ const wasEdited = this._edited;
419
+ this._update();
420
+ if (!wasEdited) this.dispatchEvent(new CustomEvent('activate', { bubbles: true }));
421
+ return;
422
+ }
423
+ default:
424
+ return;
425
+ }
426
+ event.preventDefault();
427
+ this._spin(increment);
428
+ }
429
+
430
+ private _formatted(): string {
431
+ return formatScaleValue(this._range.value, this.digits);
432
+ }
433
+
434
+ private _render(): void {
435
+ if (!this._input) return;
436
+ const adjustment = this.adjustment;
437
+ const vertical = this.getAttribute('orientation') === 'vertical';
438
+ this.classList.toggle('vertical', vertical);
439
+ this.classList.toggle('horizontal', !vertical);
440
+
441
+ // `gtk_spin_button_set_orientation`'s two moves, so libadwaita's `:first-child` /
442
+ // `:last-child` corner rules (`_spin-button.scss:41-52`, `:62-74`) select what they
443
+ // select on a desktop: the up arrow hugs the rounded end in both orientations.
444
+ // Only on a CHANGE of orientation — re-parenting a focused node blurs it, and
445
+ // `_render` runs on every value change.
446
+ if (vertical !== this._vertical) {
447
+ this._vertical = vertical;
448
+ if (vertical) this.replaceChildren(this._up, this._input, this._down);
449
+ else this.replaceChildren(this._input, this._down, this._up);
450
+ }
451
+
452
+ this._input.disabled = this.hasAttribute('disabled');
453
+ // `update_width_chars` (gtkspinbutton.c:1329-1360): with no authored `width-chars` the
454
+ // field is as wide as the WIDER bound formatted at `digits`, capped at 10 characters.
455
+ this._input.size = 10;
456
+
457
+ // `gtk_spin_button_default_output` only replaces the text when it DIFFERS, and never
458
+ // while the caret is in the field: a re-render mid-keystroke would move it.
459
+ if (document.activeElement !== this._input && this._input.value !== this._formatted()) {
460
+ this._input.value = this._formatted();
461
+ }
462
+
463
+ // `update_buttons_sensitivity` (gtkspinbutton.c:1214-1226): wrap OR room to move.
464
+ this._up.disabled = !this.wrap && adjustment.upper - adjustment.value <= EPSILON;
465
+ this._down.disabled = !this.wrap && adjustment.value - adjustment.lower <= EPSILON;
466
+
467
+ this.setAttribute('aria-valuemin', String(adjustment.lower));
468
+ this.setAttribute('aria-valuemax', String(adjustment.upper - adjustment.pageSize));
469
+ this.setAttribute('aria-valuenow', String(adjustment.value));
470
+ if (this.hasAttribute('disabled')) this.setAttribute('aria-disabled', 'true');
471
+ else this.removeAttribute('aria-disabled');
472
+ }
473
+ }
474
+
475
+ customElements.define('gtk-spin-button', GtkSpinButton);
@@ -0,0 +1,126 @@
1
+ // <gtk-spinner> — GTK's icon-size busy indicator: a faint ring with a bright QUARTER
2
+ // arc turning around it. It is not `<adw-spinner>`, which breathes a variable-length
3
+ // arc from `@gjsify/adwaita-core`'s `spinnerArc`; this is the older GTK picture and it
4
+ // is the one `Gtk.Spinner` draws.
5
+ //
6
+ // THE PICTURE, FROM THE ICON GTK LOADS. `ensure_paintable` picks
7
+ // `/org/gtk/libgtk/icons/process-working.gpa` and asks the SVG loader to play it
8
+ // (gtkspinner.c:158-171). That file is a full circle stroked at `stroke-opacity 0.2`
9
+ // plus one 90° arc from (1,8) to (8,1) on a radius-7 circle centred at (8,8) — a
10
+ // quarter arc, exactly as the header claims. Both are drawn here with `currentColor`,
11
+ // the track at 20% opacity, which is what the icon's `url(#gpa:foreground)` resolves
12
+ // to inside a widget.
13
+ //
14
+ // `:checked` IS THE SPINNING STATE. GTK puts the `:checked` pseudoclass on the node
15
+ // while `spinning` is set (gtkspinner.c:59-63, `update_state_flags` :99-108), so
16
+ // libadwaita can paint the two apart. In a browser the element is its own node and the
17
+ // `spinning` ATTRIBUTE is the state, so `[spinning]` selects the same rule `:checked`
18
+ // would.
19
+ //
20
+ // UNDER REDUCED MOTION GTK SWAPS THE ICON, and so does this. `ensure_paintable` reads
21
+ // `gtk-interface-reduced-motion` and loads `sand-watch.svg` — a STATIC hourglass —
22
+ // instead of the rotating arc (gtkspinner.c:145-161). The browser has no icon loader,
23
+ // so the equivalent is a rule that holds the arc still. This is deliberately the
24
+ // opposite of `<adw-spinner>`, which keeps turning on purpose
25
+ // (`adw-spinner-paintable.c:537`).
26
+ //
27
+ // `start()` / `stop()` ARE NOT ALIASES FOR THE PROPERTY ALONE. Both also set
28
+ // `GTK_ACCESSIBLE_STATE_BUSY` (gtkspinner.c:373-383, :391-400), so `aria-busy` rides
29
+ // on the same call — the `spinning` property is what the `:checked` class is built on,
30
+ // `aria-busy` is what a screen reader is told.
31
+ //
32
+ // SIZE IS CSS, not a property. `GtkSpinner` has exactly one property, `spinning`; the
33
+ // size comes from the `icon-size` CSS property, measured as minimum AND natural
34
+ // (gtkspinner.c:110-123), so the element carries an icon-size default box and lets a
35
+ // rule size it.
36
+ //
37
+ // A11Y: `role="progressbar"` — GtkSpinner's declared role (gtkspinner.c:345) — with no
38
+ // value range, because there is no fraction to report.
39
+ //
40
+ // Reference: refs/gtk/gtk/gtkspinner.c
41
+ // Reference: refs/gtk/gtk/icons/process-working-symbolic.svg
42
+ // Reference: refs/gtk/gtk/icons/sand-watch.svg
43
+ // Reference: refs/libadwaita/src/stylesheet/widgets/_spinner.scss:1-3 (the disabled rule)
44
+ // Copyright (c) The GTK Team. LGPLv2.1+.
45
+ // Modifications: Implemented as a Web Component for @gjsify/adwaita-web.
46
+
47
+ const SVG_NS = 'http://www.w3.org/2000/svg';
48
+
49
+ /** The radius-7 ring `process-working-symbolic.svg` traces through (1,8)…(15,8). */
50
+ const RADIUS = 7;
51
+
52
+ export class GtkSpinner extends HTMLElement {
53
+ private _initialized = false;
54
+
55
+ static get observedAttributes() {
56
+ return ['spinning', 'disabled'];
57
+ }
58
+
59
+ /** `Gtk.Spinner:spinning` — whether the animation runs. Defaults to FALSE (:338-340). */
60
+ get spinning(): boolean {
61
+ return this.hasAttribute('spinning');
62
+ }
63
+
64
+ set spinning(v: boolean) {
65
+ this.toggleAttribute('spinning', !!v);
66
+ }
67
+
68
+ /** `gtk_spinner_start` (gtkspinner.c:373-383): spin, and announce the busy state. */
69
+ start(): void {
70
+ this.spinning = true;
71
+ this.setAttribute('aria-busy', 'true');
72
+ }
73
+
74
+ /** `gtk_spinner_stop` (gtkspinner.c:391-400). */
75
+ stop(): void {
76
+ this.spinning = false;
77
+ this.setAttribute('aria-busy', 'false');
78
+ }
79
+
80
+ connectedCallback() {
81
+ if (this._initialized) {
82
+ this._render();
83
+ return;
84
+ }
85
+ this._initialized = true;
86
+
87
+ const svg = document.createElementNS(SVG_NS, 'svg');
88
+ svg.setAttribute('viewBox', '0 0 16 16');
89
+ svg.setAttribute('class', 'adw-spinner-ring');
90
+
91
+ const track = document.createElementNS(SVG_NS, 'circle');
92
+ track.setAttribute('cx', '8');
93
+ track.setAttribute('cy', '8');
94
+ track.setAttribute('r', String(RADIUS));
95
+ track.setAttribute('class', 'adw-spinner-track');
96
+
97
+ // The 180°→270° quarter of the same circle, as an arc: from (1,8) up to (8,1).
98
+ const arc = document.createElementNS(SVG_NS, 'path');
99
+ arc.setAttribute('d', `M ${8 - RADIUS} 8 A ${RADIUS} ${RADIUS} 0 0 1 8 ${8 - RADIUS}`);
100
+ arc.setAttribute('class', 'adw-spinner-arc');
101
+
102
+ svg.append(track, arc);
103
+ this.replaceChildren(svg);
104
+
105
+ this.setAttribute('role', 'progressbar');
106
+ this._render();
107
+ }
108
+
109
+ attributeChangedCallback(name: string) {
110
+ if (!this._initialized) return;
111
+ this._render();
112
+ if (name === 'spinning') {
113
+ this.dispatchEvent(
114
+ new CustomEvent('notify::spinning', { bubbles: true, detail: { spinning: this.spinning } }),
115
+ );
116
+ }
117
+ }
118
+
119
+ private _render(): void {
120
+ // `update_state_flags` (gtkspinner.c:99-108) — the `:checked` pseudoclass, which
121
+ // libadwaita and this package's own stylesheet both spell `.checked`.
122
+ this.classList.toggle('checked', this.spinning);
123
+ }
124
+ }
125
+
126
+ customElements.define('gtk-spinner', GtkSpinner);