@gjsify/adwaita-web 0.54.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 (439) hide show
  1. package/dist/adwaita-web.css +8066 -3033
  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 +1 -1
  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/style-classes.spec.ts +9 -8
  436. package/src/styles.generated.ts +1 -1
  437. package/src/tab-chip.ts +200 -0
  438. package/src/template-classes.ts +45 -0
  439. package/src/test.browser.mts +152 -0
@@ -0,0 +1,642 @@
1
+ // <gtk-scrolled-window> — the widget every scrolling GTK window is built from: one child,
2
+ // two adjustments, and up to two scrollbars that appear only when there is something to
3
+ // scroll.
4
+ //
5
+ // THE PARTS ARE GTK'S PARTS, NOT AN ARRANGEMENT OF THIS ONE'S. The child goes into a
6
+ // `<gtk-viewport>` — `gtk_scrolled_window_set_property(child)` "will add the child to a
7
+ // Gtk.Viewport and then set the viewport as the child" (gtkscrolledwindow.c:780-793), which
8
+ // `gtk_scrolled_window_set_child` does at gtkscrolledwindow.c:4362-4374 — and
9
+ // each scrollbar is a `<gtk-scrollbar>` holding the adjustment of one axis, which is how
10
+ // GTK reaches them too: `gtk_scrollbar_get_adjustment (GTK_SCROLLBAR (priv->hscrollbar))`
11
+ // is the phrase the whole of `gtkscrolledwindow.c` reads a position through. So the
12
+ // adjustments are computed by the VIEWPORT, from its own scroll metrics, in GTK's own
13
+ // fractions (`viewport_set_adjustment_values`, gtkviewport.c:159-189), and this widget owns
14
+ // only what a scrolled window owns: WHICH scrollbars are visible, WHERE they sit, and what
15
+ // the keys do.
16
+ //
17
+ // VISIBILITY IS `update_scrollbar_visibility_flags` AND NOTHING ELSE — an automatic bar is
18
+ // visible when `upper - lower > page_size` (gtkscrolledwindow.c:1553-1579), which is the
19
+ // content being longer than the window, read here as the same comparison of the same six
20
+ // numbers. GTK's guess-and-recheck loop around it (gtkscrolledwindow.c:1608-1750) exists
21
+ // because a GTK widget must be ASKED for its size and the answer moves when a scrollbar
22
+ // takes some of it. A browser reports both numbers at once, so the loop has nothing to
23
+ // converge on and the comparison is taken once per layout.
24
+ //
25
+ // WHERE THE BARS SIT IS `gtk_scrolled_window_allocate_scrollbar` (gtkscrolledwindow.c:3227-3305),
26
+ // including its two complications: `window-placement` moves them to the other edges
27
+ // (`top-left` is the default, and the L/R half is direction-aware upstream — `:dir(rtl)` is
28
+ // that here, from `is_left = ltr != is_start` at :3244-3249), and an
29
+ // OVERLAY bar is laid out INSIDE the content's own allocation, over it
30
+ // (`priv->use_indicators`, gtkscrolledwindow.c:3255-3300) rather than beside it.
31
+ //
32
+ // `overlay-scrolling` is read twice in GTK too: `use_indicators` is the AND of this property
33
+ // with the `gtk-overlay-scrolling` SETTING, which is TRUE by default
34
+ // (gtksettings.c:967-979), and the indicator is the "narrow, auto-hiding" scrollbar
35
+ // `setup_indicator` fades in on every value change and back out `INDICATOR_FADE_OUT_DELAY`
36
+ // after the last one (gtkscrolledwindow.c:191-196, 3807-3847). The settings half is the
37
+ // `(hover: hover)` media query here: whether a pointer that can HOVER exists is what decides
38
+ // between indicators and permanent bars — the sentence GTK's own class documentation puts
39
+ // the other way round ("If no mouse device is present, the scrollbars will overlaid as
40
+ // narrow, auto-hiding indicators over the content", gtkscrolledwindow.c:108-112).
41
+ //
42
+ // THE EDGE INDICATORS ARE NOT REDRAWN HERE. `AdwScrollShading` already owns the undershoot
43
+ // and overshoot bookkeeping for every scroller in this package — the unclamped position a
44
+ // browser scrollport throws away, the `MAX_OVERSHOOT_DISTANCE` clamp, the classes
45
+ // libadwaita's `scrolledwindow.undershoot-top` selector wants — and it is given this widget
46
+ // as its root, exactly as `<adw-toolbar-view>` gives it its own. Its `onOvershoot` hook is
47
+ // what turns a wheel push past an edge into this widget's `edge-overshot`.
48
+ //
49
+ // THE KEYS ARE `gtk_scrolled_window_class_init`'s OWN bindings, which are not the obvious
50
+ // ones: every arrow needs CONTROL, and Page Up/Down and Home/End are bound TWICE — bare for
51
+ // the VERTICAL axis and with CONTROL for the horizontal one
52
+ // (gtkscrolledwindow.c:894-910). `scroll-child` is an ACTION signal, so the adjustment moves
53
+ // FIRST and the signal follows. `may_hscroll` / `may_vscroll` decide whether a key scrolls at
54
+ // all, and an EXTERNAL policy counts — the bar is not drawn, but the widget can still be
55
+ // driven (gtkscrolledwindow.c:916-930).
56
+ //
57
+ // `min-content-width` / `max-content-width` (and the heights) are GTK's SIZE REQUESTS
58
+ // (`gtk_scrolled_window_measure`, gtkscrolledwindow.c:1821-1985): what the window asks its
59
+ // parent for along that axis, which is `min-width` / `max-width` here. -1, the pspec's
60
+ // default, is "not written" and sets nothing.
61
+ //
62
+ // THE TWO `propagate-natural-*` PROPERTIES MOVE THE CHILD'S OWN SIZE REQUEST UP, and they
63
+ // are asked of the CHILD (`gtk_widget_measure (priv->child, …, &min_child_size,
64
+ // &nat_child_size)`, gtkscrolledwindow.c:1881-1883) and added to this window's NATURAL
65
+ // request (`natural_req += nat_child_size`, :1887-1888 and :1905-1906). A scrollport asks
66
+ // its parent for a size with `min-width`, so the natural request is the child asked to be at
67
+ // least its `max-content` size — the CSS name for the natural one — and `hscrollbar-policy:
68
+ // never`, which adds the child's MINIMUM request instead (:1890-1892), is the same line
69
+ // with `min-content`. The larger of the two wins, which is what adding both to two requests
70
+ // and clamping them comes to. Which of the two is asked for AT ALL is `need_child_size`
71
+ // (:1841-1844), so an unwritten request sets nothing on either.
72
+ //
73
+ // A11y: `role="generic"`, which GTK 4.12 gave the widget in place of the `group` it used
74
+ // to report (gtkscrolledwindow.c:137-142, 913). The scrollport inside is the announced part.
75
+ //
76
+ // KNOWN_GAPS, the property behind each: `kinetic-scrolling` — the momentum after a touch
77
+ // release is the platform's own and a page cannot hand a browser a deceleration curve;
78
+ // `edge-overshot` fires for the VERTICAL edges only, because the shading controller
79
+ // accumulates one axis, and its horizontal pair has no unclamped value to read.
80
+ //
81
+ // Reference: refs/gtk/gtk/gtkscrolledwindow.c (class_init's key bindings, measure,
82
+ // size_allocate, allocate_scrollbar, update_scrollbar_visibility_flags, may_hscroll,
83
+ // setup_indicator, scroll_child, move_focus_out, get_overshoot)
84
+ // Reference: refs/libadwaita/src/stylesheet/widgets/_scrolling.scss:129-167 (scrolledwindow)
85
+ // Reference: refs/gtk/gtk/gtksettings.c:967-979 (the setting overlay-scrolling ANDs with)
86
+ // Copyright (c) The GTK Team. LGPLv2.1+.
87
+ // Modifications: Implemented as a Web Component for @gjsify/adwaita-web.
88
+
89
+ import type { AdwAdjustment } from '@gjsify/adwaita-core';
90
+
91
+ import { AdwScrollShading } from '../scroll-shading.js';
92
+ import { bindSlottedChildren } from '../slotted-children.js';
93
+ import type { GtkScrollType } from './gtk-scrollbar.js';
94
+ import { GtkViewport } from './gtk-viewport.js';
95
+
96
+ /**
97
+ * `INDICATOR_FADE_OUT_DELAY` — how long an indicator waits, after the last scroll, before
98
+ * it fades out again (gtkscrolledwindow.c:192).
99
+ */
100
+ const INDICATOR_FADE_OUT_DELAY = 2000;
101
+
102
+ /** `GtkPolicyType`'s four nicks; `automatic` is the pspec's default for both bars. */
103
+ export type GtkPolicyType = 'always' | 'never' | 'automatic' | 'external';
104
+
105
+ /** `GtkCornerType`'s four corners, `top-left` being the pspec's default. */
106
+ export type GtkCornerType = 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right';
107
+
108
+ /** `Gtk.PositionType`'s four edges, as `edge-reached` and `edge-overshot` name them. */
109
+ export type GtkPositionType = 'left' | 'right' | 'top' | 'bottom';
110
+
111
+ /** `Gtk.DirectionType`'s two, as `move-focus-out` names them. */
112
+ export type GtkDirectionType = 'forward' | 'backward';
113
+
114
+ const POLICIES: readonly GtkPolicyType[] = ['always', 'never', 'automatic', 'external'];
115
+ const CORNERS: readonly GtkCornerType[] = ['top-left', 'top-right', 'bottom-left', 'bottom-right'];
116
+
117
+ /** An unknown nick is the pspec's default, which is what GtkBuilder's rejection leaves behind. */
118
+ function normalizePolicy(value: string | null): GtkPolicyType {
119
+ return POLICIES.find((policy) => policy === value) ?? 'automatic';
120
+ }
121
+
122
+ function normalizeCorner(value: string | null): GtkCornerType {
123
+ return CORNERS.find((corner) => corner === value) ?? 'top-left';
124
+ }
125
+
126
+ /** A size request in pixels, or `null` for the pspec's -1, which means "not written". */
127
+ function sizeRequest(value: string | null): number | null {
128
+ if (value === null) return null;
129
+ const size = Number.parseInt(value, 10);
130
+ return Number.isFinite(size) && size >= 0 ? size : null;
131
+ }
132
+
133
+ /**
134
+ * The two axes, in GTK's own order, with everything that differs between them.
135
+ *
136
+ * `end` / `farEnd` are `Gtk.PositionType`'s two names for one axis's edges, and the
137
+ * horizontal pair is inverted under `dir(rtl)` where GTK inverts it
138
+ * (`maybe_emit_edge_reached`, gtkscrolledwindow.c:3656-3658, and the same in
139
+ * `_gtk_scrolled_window_set_adjustment_value` at :3346-3349) — which is
140
+ * a CSS concern and lives in the stylesheet, so only the LTR names are named here.
141
+ */
142
+ const AXES = [
143
+ {
144
+ key: 'hadjustment',
145
+ bar: 'horizontal',
146
+ policy: 'hscrollbar-policy',
147
+ natural: 'propagate-natural-width',
148
+ cssMin: 'minWidth',
149
+ end: 'left',
150
+ farEnd: 'right',
151
+ },
152
+ {
153
+ key: 'vadjustment',
154
+ bar: 'vertical',
155
+ policy: 'vscrollbar-policy',
156
+ natural: 'propagate-natural-height',
157
+ cssMin: 'minHeight',
158
+ end: 'top',
159
+ farEnd: 'bottom',
160
+ },
161
+ ] as const;
162
+
163
+ /**
164
+ * `gtk_scrolled_window_class_init`'s bindings (gtkscrolledwindow.c:894-910), read as a
165
+ * table because the table IS the surprise: CONTROL for every arrow, and Page Up/Down and
166
+ * Home/End on the vertical axis bare and on the horizontal one with CONTROL.
167
+ *
168
+ * `null` is a key this widget does not bind, which is how it reaches a focused child —
169
+ * GTK's action handler returns FALSE and propagation continues.
170
+ */
171
+ function resolveScrollKey(event: KeyboardEvent): { scroll: GtkScrollType; horizontal: boolean } | null {
172
+ switch (event.key) {
173
+ case 'ArrowLeft':
174
+ return event.ctrlKey ? { scroll: 'step-backward', horizontal: true } : null;
175
+ case 'ArrowRight':
176
+ return event.ctrlKey ? { scroll: 'step-forward', horizontal: true } : null;
177
+ case 'ArrowUp':
178
+ return event.ctrlKey ? { scroll: 'step-backward', horizontal: false } : null;
179
+ case 'ArrowDown':
180
+ return event.ctrlKey ? { scroll: 'step-forward', horizontal: false } : null;
181
+ // The pair is VERTICAL bare and HORIZONTAL with CONTROL — the reverse of what the two
182
+ // bindings read like (gtkscrolledwindow.c:899-902).
183
+ case 'PageUp':
184
+ return { scroll: 'page-backward', horizontal: event.ctrlKey };
185
+ case 'PageDown':
186
+ return { scroll: 'page-forward', horizontal: event.ctrlKey };
187
+ // Home and End are bound TWICE, like Page Up/Down (gtkscrolledwindow.c:904-907):
188
+ // CONTROL for the horizontal axis and NOTHING for the vertical one.
189
+ case 'Home':
190
+ return { scroll: 'start', horizontal: event.ctrlKey };
191
+ case 'End':
192
+ return { scroll: 'end', horizontal: event.ctrlKey };
193
+ default:
194
+ return null;
195
+ }
196
+ }
197
+
198
+ export class GtkScrolledWindow extends HTMLElement {
199
+ private _viewport!: GtkViewport;
200
+ private _bars: Record<'horizontal' | 'vertical', HTMLElement> | null = null;
201
+ private _shading: AdwScrollShading | null = null;
202
+ private _observer: ResizeObserver | null = null;
203
+ private _hoverable: MediaQueryList | null = null;
204
+ private _fadeTimer: ReturnType<typeof setTimeout> | null = null;
205
+ private _built = false;
206
+
207
+ static get observedAttributes() {
208
+ return [
209
+ 'hscrollbar-policy',
210
+ 'vscrollbar-policy',
211
+ 'window-placement',
212
+ 'has-frame',
213
+ 'min-content-width',
214
+ 'min-content-height',
215
+ 'max-content-width',
216
+ 'max-content-height',
217
+ 'overlay-scrolling',
218
+ 'propagate-natural-width',
219
+ 'propagate-natural-height',
220
+ ];
221
+ }
222
+
223
+ /** `GtkScrolledWindow:hscrollbar-policy` — `automatic` in the pspec. */
224
+ get hscrollbarPolicy(): GtkPolicyType {
225
+ return normalizePolicy(this.getAttribute('hscrollbar-policy'));
226
+ }
227
+
228
+ set hscrollbarPolicy(value: GtkPolicyType) {
229
+ this.setAttribute('hscrollbar-policy', value);
230
+ }
231
+
232
+ /** `GtkScrolledWindow:vscrollbar-policy` — `automatic` in the pspec. */
233
+ get vscrollbarPolicy(): GtkPolicyType {
234
+ return normalizePolicy(this.getAttribute('vscrollbar-policy'));
235
+ }
236
+
237
+ set vscrollbarPolicy(value: GtkPolicyType) {
238
+ this.setAttribute('vscrollbar-policy', value);
239
+ }
240
+
241
+ /** `GtkScrolledWindow:window-placement` — where the contents sit against the bars. */
242
+ get windowPlacement(): GtkCornerType {
243
+ return normalizeCorner(this.getAttribute('window-placement'));
244
+ }
245
+
246
+ set windowPlacement(value: GtkCornerType) {
247
+ this.setAttribute('window-placement', value);
248
+ }
249
+
250
+ /** `GtkScrolledWindow:has-frame` — the `.frame` style class on the node, and nothing more. */
251
+ get hasFrame(): boolean {
252
+ return this.hasAttribute('has-frame');
253
+ }
254
+
255
+ set hasFrame(value: boolean) {
256
+ this.toggleAttribute('has-frame', !!value);
257
+ }
258
+
259
+ /** `GtkScrolledWindow:overlay-scrolling` — TRUE in the pspec, and unknown is that. */
260
+ get overlayScrolling(): boolean {
261
+ return this.getAttribute('overlay-scrolling') !== 'false';
262
+ }
263
+
264
+ set overlayScrolling(value: boolean) {
265
+ this.toggleAttribute('overlay-scrolling', !!value);
266
+ }
267
+
268
+ /** `GtkScrolledWindow:min-content-width`, in px, or `null` for the pspec's -1. */
269
+ get minContentWidth(): number | null {
270
+ return sizeRequest(this.getAttribute('min-content-width'));
271
+ }
272
+
273
+ set minContentWidth(value: number | null) {
274
+ this._writeSizeRequest('min-content-width', value);
275
+ }
276
+
277
+ /** `GtkScrolledWindow:min-content-height`, in px, or `null` for the pspec's -1. */
278
+ get minContentHeight(): number | null {
279
+ return sizeRequest(this.getAttribute('min-content-height'));
280
+ }
281
+
282
+ set minContentHeight(value: number | null) {
283
+ this._writeSizeRequest('min-content-height', value);
284
+ }
285
+
286
+ /** `GtkScrolledWindow:max-content-width`, in px, or `null` for the pspec's -1. */
287
+ get maxContentWidth(): number | null {
288
+ return sizeRequest(this.getAttribute('max-content-width'));
289
+ }
290
+
291
+ set maxContentWidth(value: number | null) {
292
+ this._writeSizeRequest('max-content-width', value);
293
+ }
294
+
295
+ /** `GtkScrolledWindow:max-content-height`, in px, or `null` for the pspec's -1. */
296
+ get maxContentHeight(): number | null {
297
+ return sizeRequest(this.getAttribute('max-content-height'));
298
+ }
299
+
300
+ set maxContentHeight(value: number | null) {
301
+ this._writeSizeRequest('max-content-height', value);
302
+ }
303
+
304
+ /** `GtkScrolledWindow:propagate-natural-width` — FALSE in the pspec, so absent is that. */
305
+ get propagateNaturalWidth(): boolean {
306
+ return this.hasAttribute('propagate-natural-width');
307
+ }
308
+
309
+ set propagateNaturalWidth(value: boolean) {
310
+ this.toggleAttribute('propagate-natural-width', !!value);
311
+ }
312
+
313
+ /** `GtkScrolledWindow:propagate-natural-height` — FALSE in the pspec, so absent is that. */
314
+ get propagateNaturalHeight(): boolean {
315
+ return this.hasAttribute('propagate-natural-height');
316
+ }
317
+
318
+ set propagateNaturalHeight(value: boolean) {
319
+ this.toggleAttribute('propagate-natural-height', !!value);
320
+ }
321
+
322
+ /**
323
+ * `gtk_scrolled_window_get_hscrollbar` / `get_vscrollbar`, as METHODS and not getters.
324
+ *
325
+ * `connect-lifecycle.spec.ts` reads a get-only accessor returning an element as an
326
+ * invitation to append into it, and a scrollbar that is not visible is not an append
327
+ * point — which is the whole of what a getter here would be asking for.
328
+ */
329
+ hscrollbar(): HTMLElement | null {
330
+ return this._bars?.horizontal ?? null;
331
+ }
332
+
333
+ vscrollbar(): HTMLElement | null {
334
+ return this._bars?.vertical ?? null;
335
+ }
336
+
337
+ /** The `<gtk-viewport>` the child sits in — the one GTK's `set_child` builds for itself. */
338
+ get viewport(): GtkViewport {
339
+ return this._viewport;
340
+ }
341
+
342
+ connectedCallback() {
343
+ if (!this._built) {
344
+ this._built = true;
345
+ this._viewport = document.createElement('gtk-viewport') as GtkViewport;
346
+ const horizontal = document.createElement('gtk-scrollbar');
347
+ const vertical = document.createElement('gtk-scrollbar');
348
+ horizontal.setAttribute('orientation', 'horizontal');
349
+ vertical.setAttribute('orientation', 'vertical');
350
+ this._bars = { horizontal, vertical };
351
+ bindSlottedChildren(this, [{ into: this._viewport }]).install(this._viewport, vertical, horizontal);
352
+ this.setAttribute('role', 'generic');
353
+ // A bar is a VIEW of the viewport's adjustment, so the viewport's
354
+ // `value-changed` is what moves the content and a bar's is what moves the
355
+ // other one — GTK's two directions of one signal.
356
+ this._viewport.addEventListener('value-changed', this._onViewportValue);
357
+ for (const bar of [horizontal, vertical]) {
358
+ bar.addEventListener('value-changed', this._onBarValue);
359
+ // `indicator_set_over`: the pointer over an indicator widens it, which is
360
+ // the `.hovering` class libadwaita paints the trough wash for.
361
+ bar.addEventListener('pointerenter', this._onIndicatorOver);
362
+ bar.addEventListener('pointerleave', this._onIndicatorOut);
363
+ }
364
+ // The adjustments are read from the DOM on demand, so nothing has to be
365
+ // recomputed on resize — but a CONTENT that changed size is a resize of the
366
+ // viewport, and a bar's visibility is a comparison of its numbers.
367
+ this._observer = new ResizeObserver(() => this._sync());
368
+ this._observer.observe(this._viewport);
369
+ this._shading = new AdwScrollShading(this, {
370
+ onOvershoot: (distance) => this._edgeOvershot(distance),
371
+ });
372
+ this._shading.connect();
373
+ }
374
+ // The media query is an OUTSIDE binding: released on the way out and
375
+ // re-established on every way in, which is the shape
376
+ // `scripts/check-adwaita-connect-rebind.mjs` holds every element to.
377
+ this._releaseHoverable();
378
+ this._hoverable = matchMedia('(hover: hover)');
379
+ this._hoverable.addEventListener('change', this._onHoverableChange);
380
+ this.addEventListener('keydown', this._onKeyDown);
381
+ this._sync();
382
+ }
383
+
384
+ disconnectedCallback() {
385
+ this.removeEventListener('keydown', this._onKeyDown);
386
+ this._releaseHoverable();
387
+ }
388
+
389
+ attributeChangedCallback(name: string, _old: string | null, value: string | null) {
390
+ if (!this._built || !this.isConnected) return;
391
+ this.dispatchEvent(
392
+ new CustomEvent(`notify::${name}`, { bubbles: true, detail: { [name]: this._normalized(name, value) } }),
393
+ );
394
+ this._sync();
395
+ }
396
+
397
+ /** The NORMALISED value a notify carries, which is the property and not the raw attribute. */
398
+ private _normalized(name: string, raw: string | null): unknown {
399
+ switch (name) {
400
+ case 'hscrollbar-policy':
401
+ return normalizePolicy(raw);
402
+ case 'vscrollbar-policy':
403
+ return normalizePolicy(raw);
404
+ case 'window-placement':
405
+ return normalizeCorner(raw);
406
+ case 'overlay-scrolling':
407
+ return raw !== 'false';
408
+ case 'has-frame':
409
+ return raw !== null;
410
+ case 'propagate-natural-width':
411
+ case 'propagate-natural-height':
412
+ return raw !== null;
413
+ default:
414
+ return sizeRequest(raw);
415
+ }
416
+ }
417
+
418
+ private _writeSizeRequest(name: string, value: number | null): void {
419
+ if (value === null) this.removeAttribute(name);
420
+ else this.setAttribute(name, String(Math.max(0, Math.trunc(value))));
421
+ }
422
+
423
+ /**
424
+ * `priv->use_indicators` — the AND of the property with the `gtk-overlay-scrolling`
425
+ * setting, whose browser spelling is whether a pointer that can hover exists at all.
426
+ */
427
+ private get _useIndicators(): boolean {
428
+ return this.overlayScrolling && (this._hoverable?.matches ?? true);
429
+ }
430
+
431
+ /** Everything the pspec's own state decides: the classes, the bars, the sizes. */
432
+ private _sync(): void {
433
+ const bars = this._bars;
434
+ // A parent reaches its own children INSIDE `connectedCallback`, where the children's
435
+ // callbacks have not run yet: custom element reactions unwind after the parent's. The
436
+ // bars are not connected, so this pass has no adjustment to read and no geometry to
437
+ // decide — `connectedCallback` ends with a `_sync()` of its own, once they are.
438
+ if (bars === null || !this._viewport.isConnected || !bars.vertical.isConnected) return;
439
+ const placement = this.windowPlacement;
440
+ const indicators = this._useIndicators;
441
+ this.classList.toggle('frame', this.hasFrame);
442
+ // The corner is a class because the bars' PLACEMENT is a layout, and the grid
443
+ // areas that place them are CSS (`_scrolled_window.scss`) the way GTK's allocation
444
+ // is not.
445
+ this.classList.toggle(placement, true);
446
+ for (const corner of CORNERS) if (corner !== placement) this.classList.toggle(corner, false);
447
+ this.classList.toggle('overlay-scrolling', indicators);
448
+ // `gtk_scrolled_window_measure`'s four clamps, as the four CSS size requests they
449
+ // are: an unwritten one (-1) sets nothing at all.
450
+ this.style.minWidth = this._size('min-content-width');
451
+ this.style.minHeight = this._size('min-content-height');
452
+ this.style.maxWidth = this._size('max-content-width');
453
+ this.style.maxHeight = this._size('max-content-height');
454
+ for (const axis of AXES) {
455
+ const bar = bars[axis.bar];
456
+ const policy = normalizePolicy(this.getAttribute(axis.policy));
457
+ const adjustment = this._adjustment(axis.key);
458
+ // `update_scrollbar_visibility_flags`: AUTOMATIC decides from the adjustment,
459
+ // ALWAYS and NEVER do not, and EXTERNAL is a bar this window does not draw.
460
+ const visible =
461
+ policy === 'always'
462
+ ? true
463
+ : policy === 'automatic'
464
+ ? adjustment.upper - adjustment.lower > adjustment.pageSize
465
+ : false;
466
+ bar.hidden = !visible;
467
+ // `setup_indicator`'s own class, which is what makes libadwaita's narrow
468
+ // auto-hiding bar out of a permanent one.
469
+ bar.classList.toggle('overlay-indicator', indicators);
470
+ (bar as HTMLElement & { adjustment: AdwAdjustment }).adjustment = adjustment;
471
+ // `gtk_scrolled_window_measure`'s request for the CHILD'S size, written on the
472
+ // scrollport that has to ask its parent for it: `propagate-natural-*` is the
473
+ // child's NATURAL size (`max-content`), a NEVER policy is its MINIMUM one
474
+ // (`min-content`), and the natural is the larger of the two.
475
+ this._viewport.style[axis.cssMin] = this.hasAttribute(axis.natural)
476
+ ? 'max-content'
477
+ : policy === 'never'
478
+ ? 'min-content'
479
+ : '';
480
+ }
481
+ if (!indicators) this._clearFade();
482
+ }
483
+
484
+ private _size(attribute: string): string {
485
+ const size = sizeRequest(this.getAttribute(attribute));
486
+ return size === null ? '' : `${size}px`;
487
+ }
488
+
489
+ /** The viewport's adjustment for one axis, which is where GTK reads the scrollbar's. */
490
+ private _adjustment(key: 'hadjustment' | 'vadjustment'): AdwAdjustment {
491
+ return this._viewport[key];
492
+ }
493
+
494
+ /**
495
+ * `may_hscroll` / `may_vscroll`: a bar that is DRAWN, or an EXTERNAL policy, which is a
496
+ * scrollbar this window does not show but can still be driven with.
497
+ */
498
+ private _mayScroll(horizontal: boolean): HTMLElement | null {
499
+ const bars = this._bars;
500
+ if (bars === null) return null;
501
+ const bar = horizontal ? bars.horizontal : bars.vertical;
502
+ if (!bar.hidden) return bar;
503
+ const policy = normalizePolicy(this.getAttribute(horizontal ? 'hscrollbar-policy' : 'vscrollbar-policy'));
504
+ return policy === 'external' ? bar : null;
505
+ }
506
+
507
+ /**
508
+ * The viewport moved: hand the position to the bars, ask whether an edge was REACHED
509
+ * (`maybe_emit_edge_reached` fires whenever the adjustment lands exactly on `lower` or
510
+ * `upper - page_size`, gtkscrolledwindow.c:3629-3661) and fade the indicators in.
511
+ */
512
+ private _onViewportValue = (event: Event): void => {
513
+ const bars = this._bars;
514
+ if (bars === null) return;
515
+ const detail = (event as CustomEvent<{ hadjustment: AdwAdjustment; vadjustment: AdwAdjustment }>).detail;
516
+ for (const axis of AXES) {
517
+ const adjustment = detail[axis.key];
518
+ (bars[axis.bar] as HTMLElement & { adjustment: AdwAdjustment }).adjustment = adjustment;
519
+ const max = adjustment.upper - adjustment.pageSize;
520
+ if (adjustment.value <= adjustment.lower) this._edgeReached(axis.end);
521
+ else if (adjustment.value >= max) this._edgeReached(axis.farEnd);
522
+ }
523
+ this._fadeIn();
524
+ };
525
+
526
+ /**
527
+ * A bar moved: move the scrollport. GTK's direction is the other way round — the
528
+ * adjustment belongs to the scrollbar and the scrolled window reads it — which is why
529
+ * the bar is given the adjustment here instead of owning it: the numbers are the same
530
+ * either way, and one writer per side is what keeps them from fighting.
531
+ */
532
+ private _onBarValue = (event: Event): void => {
533
+ const bar = event.currentTarget as HTMLElement;
534
+ const adjustment = (event as CustomEvent<{ adjustment: AdwAdjustment }>).detail.adjustment;
535
+ if (bar.hidden) return;
536
+ // The scrollport's position IS the adjustment's value, so this is one clamped
537
+ // assignment — `gtk_adjustment_set_value`'s own contract.
538
+ this._viewport.scrollAxis(
539
+ bar.getAttribute('orientation') === 'vertical' ? 'vertical' : 'horizontal',
540
+ adjustment.value,
541
+ );
542
+ };
543
+
544
+ private _edgeReached(edge: GtkPositionType): void {
545
+ this.dispatchEvent(new CustomEvent('edge-reached', { bubbles: true, detail: { pos: edge } }));
546
+ }
547
+
548
+ /**
549
+ * `_gtk_scrolled_window_set_adjustment_value`'s `EDGE_OVERSHOT`, from the shading
550
+ * controller's unclamped position: negative is the near edge, positive the far one,
551
+ * and `0` is the settled case the C returns without emitting — it is the value CLAMPED
552
+ * to `lower - MAX_OVERSHOOT_DISTANCE` and `upper - page_size + MAX_OVERSHOOT_DISTANCE`
553
+ * that the signal compares (gtkscrolledwindow.c:3306-3352).
554
+ */
555
+ private _edgeOvershot(distance: number): void {
556
+ if (distance === 0) return;
557
+ this.dispatchEvent(
558
+ new CustomEvent('edge-overshot', { bubbles: true, detail: { pos: distance < 0 ? 'top' : 'bottom' } }),
559
+ );
560
+ }
561
+
562
+ /** The keys of `gtk_scrolled_window_class_init`, and the two signals they emit. */
563
+ private _onKeyDown = (event: KeyboardEvent): void => {
564
+ if (event.key === 'Tab' && event.ctrlKey) {
565
+ // `move_focus_out` re-emits `move-focus` on the ROOT and GTK's focus chain
566
+ // takes it from there (gtkscrolledwindow.c:3055-3076). The browser's own Tab
567
+ // IS that chain, so this is the signal and the event is left to run.
568
+ const directionType: GtkDirectionType = event.shiftKey ? 'backward' : 'forward';
569
+ this.dispatchEvent(new CustomEvent('move-focus-out', { bubbles: true, detail: { directionType } }));
570
+ return;
571
+ }
572
+ const binding = resolveScrollKey(event);
573
+ if (binding === null) return;
574
+ const bar = this._mayScroll(binding.horizontal);
575
+ if (bar === null) return;
576
+ event.preventDefault();
577
+ (bar as HTMLElement & { scrollBy(kind: GtkScrollType): void }).scrollBy(binding.scroll);
578
+ // RUN_LAST: the class handler has already moved the adjustment by the time a
579
+ // listener hears this, which is what an ACTION signal means.
580
+ this.dispatchEvent(
581
+ new CustomEvent('scroll-child', {
582
+ bubbles: true,
583
+ detail: { scroll: binding.scroll, horizontal: binding.horizontal },
584
+ }),
585
+ );
586
+ };
587
+
588
+ /**
589
+ * `indicator_start_fade(indicator, 1.0)` on every value change, and
590
+ * `maybe_hide_indicator`'s check `INDICATOR_FADE_OUT_DELAY` after the last one — a poll
591
+ * upstream, one timer here, and `!indicator->over` is the `.hovering` class (a pointer
592
+ * over the indicator holds it open).
593
+ */
594
+ private _fadeIn(): void {
595
+ const bars = this._bars;
596
+ if (bars === null || !this._useIndicators) return;
597
+ for (const bar of [bars.horizontal, bars.vertical]) bar.style.setProperty('--adw-indicator-opacity', '1');
598
+ if (this._fadeTimer !== null) clearTimeout(this._fadeTimer);
599
+ this._fadeTimer = setTimeout(() => this._fadeOut(), INDICATOR_FADE_OUT_DELAY);
600
+ }
601
+
602
+ private _fadeOut(): void {
603
+ this._fadeTimer = null;
604
+ const bars = this._bars;
605
+ if (bars === null || !this._useIndicators) return;
606
+ for (const bar of [bars.horizontal, bars.vertical]) {
607
+ if (bar.classList.contains('hovering')) continue;
608
+ bar.style.setProperty('--adw-indicator-opacity', '0');
609
+ }
610
+ }
611
+
612
+ private _clearFade(): void {
613
+ if (this._fadeTimer !== null) clearTimeout(this._fadeTimer);
614
+ this._fadeTimer = null;
615
+ const bars = this._bars;
616
+ if (bars === null) return;
617
+ for (const bar of [bars.horizontal, bars.vertical]) bar.style.removeProperty('--adw-indicator-opacity');
618
+ }
619
+
620
+ private _onIndicatorOver = (event: Event): void => {
621
+ const bar = event.currentTarget as HTMLElement;
622
+ bar.classList.add('hovering');
623
+ // An indicator the pointer is ON is never faded out, so a fade already standing is
624
+ // replaced by the visible state and its timer by this one.
625
+ this._fadeIn();
626
+ };
627
+
628
+ private _onIndicatorOut = (event: Event): void => {
629
+ (event.currentTarget as HTMLElement).classList.remove('hovering');
630
+ };
631
+
632
+ private _onHoverableChange = (): void => {
633
+ this._sync();
634
+ };
635
+
636
+ private _releaseHoverable(): void {
637
+ this._hoverable?.removeEventListener('change', this._onHoverableChange);
638
+ this._hoverable = null;
639
+ }
640
+ }
641
+
642
+ customElements.define('gtk-scrolled-window', GtkScrolledWindow);