@gjsify/adwaita-web 0.54.0 → 0.56.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (479) hide show
  1. package/README.md +8 -0
  2. package/dist/adwaita-web.css +8146 -3011
  3. package/dist/adwaita-web.css.map +1 -1
  4. package/lib/types/adw-application-window.spec.d.ts +1 -0
  5. package/lib/types/adw-bin.spec.d.ts +1 -0
  6. package/lib/types/adw-breakpoint-bin.spec.d.ts +1 -0
  7. package/lib/types/adw-clamp-scrollable.spec.d.ts +1 -0
  8. package/lib/types/adw-multi-layout-view.spec.d.ts +1 -0
  9. package/lib/types/adw-preferences-row.spec.d.ts +1 -0
  10. package/lib/types/adw-shortcuts.spec.d.ts +1 -0
  11. package/lib/types/adw-status-page.spec.d.ts +1 -0
  12. package/lib/types/adw-tab-bar.spec.d.ts +1 -0
  13. package/lib/types/adw-tab-button.spec.d.ts +1 -0
  14. package/lib/types/adw-tab-overview.spec.d.ts +1 -0
  15. package/lib/types/adw-view-switcher-sidebar.spec.d.ts +1 -0
  16. package/lib/types/adw-window.spec.d.ts +1 -0
  17. package/lib/types/attributes.d.ts +19 -0
  18. package/lib/types/breakpoints.d.ts +14 -3
  19. package/lib/types/construct-vectors.spec.d.ts +1 -0
  20. package/lib/types/elements/adw-action-row.d.ts +4 -0
  21. package/lib/types/elements/adw-application-window.d.ts +27 -0
  22. package/lib/types/elements/adw-bin.d.ts +17 -0
  23. package/lib/types/elements/adw-breakpoint-bin.d.ts +67 -0
  24. package/lib/types/elements/adw-clamp-scrollable.d.ts +38 -0
  25. package/lib/types/elements/adw-combo-row.d.ts +4 -0
  26. package/lib/types/elements/adw-dialog.d.ts +10 -0
  27. package/lib/types/elements/adw-entry-row.d.ts +6 -0
  28. package/lib/types/elements/adw-expander-row.d.ts +2 -0
  29. package/lib/types/elements/adw-header-bar.d.ts +6 -0
  30. package/lib/types/elements/adw-layout-slot.d.ts +19 -0
  31. package/lib/types/elements/adw-multi-layout-view.d.ts +101 -0
  32. package/lib/types/elements/adw-overlay-split-view.d.ts +13 -0
  33. package/lib/types/elements/adw-preferences-row.d.ts +31 -0
  34. package/lib/types/elements/adw-shortcuts-dialog.d.ts +13 -0
  35. package/lib/types/elements/adw-shortcuts-item.d.ts +36 -0
  36. package/lib/types/elements/adw-shortcuts-section.d.ts +14 -0
  37. package/lib/types/elements/adw-sidebar.d.ts +8 -2
  38. package/lib/types/elements/adw-spin-row.d.ts +6 -0
  39. package/lib/types/elements/adw-switch-row.d.ts +7 -0
  40. package/lib/types/elements/adw-tab-bar.d.ts +108 -0
  41. package/lib/types/elements/adw-tab-button.d.ts +32 -0
  42. package/lib/types/elements/adw-tab-overview.d.ts +199 -0
  43. package/lib/types/elements/adw-tab-view.d.ts +19 -23
  44. package/lib/types/elements/adw-toggle-group.d.ts +17 -0
  45. package/lib/types/elements/adw-view-switcher-sidebar.d.ts +84 -0
  46. package/lib/types/elements/adw-window.d.ts +40 -0
  47. package/lib/types/elements/gtk-about-dialog.d.ts +146 -0
  48. package/lib/types/elements/gtk-application-window.d.ts +34 -0
  49. package/lib/types/elements/gtk-aspect-frame.d.ts +27 -0
  50. package/lib/types/elements/gtk-button.d.ts +9 -0
  51. package/lib/types/elements/gtk-calendar.d.ts +159 -0
  52. package/lib/types/elements/gtk-center-box.d.ts +39 -0
  53. package/lib/types/elements/gtk-color-dialog-button.d.ts +69 -0
  54. package/lib/types/elements/gtk-column-view.d.ts +50 -0
  55. package/lib/types/elements/gtk-drag-icon.d.ts +78 -0
  56. package/lib/types/elements/gtk-drawing-area.d.ts +95 -0
  57. package/lib/types/elements/gtk-editable-label.d.ts +33 -0
  58. package/lib/types/elements/gtk-emoji-chooser.d.ts +84 -0
  59. package/lib/types/elements/gtk-entry.d.ts +20 -1
  60. package/lib/types/elements/gtk-expander.d.ts +49 -0
  61. package/lib/types/elements/gtk-fixed.d.ts +13 -0
  62. package/lib/types/elements/gtk-flow-box-child.d.ts +14 -0
  63. package/lib/types/elements/gtk-flow-box.d.ts +87 -0
  64. package/lib/types/elements/gtk-font-dialog-button.d.ts +83 -0
  65. package/lib/types/elements/gtk-frame.d.ts +24 -0
  66. package/lib/types/elements/gtk-gl-area.d.ts +136 -0
  67. package/lib/types/elements/gtk-graphics-offload.d.ts +24 -0
  68. package/lib/types/elements/gtk-grid-view.d.ts +39 -0
  69. package/lib/types/elements/gtk-grid.d.ts +27 -0
  70. package/lib/types/elements/gtk-header-bar.d.ts +60 -0
  71. package/lib/types/elements/gtk-inscription.d.ts +64 -0
  72. package/lib/types/elements/gtk-label.d.ts +3 -0
  73. package/lib/types/elements/gtk-level-bar.d.ts +59 -0
  74. package/lib/types/elements/gtk-link-button.d.ts +29 -0
  75. package/lib/types/elements/gtk-list-box-row.d.ts +54 -0
  76. package/lib/types/elements/gtk-list-box.d.ts +100 -0
  77. package/lib/types/elements/gtk-list-view.d.ts +73 -0
  78. package/lib/types/elements/gtk-media-controls.d.ts +142 -0
  79. package/lib/types/elements/gtk-notebook.d.ts +148 -0
  80. package/lib/types/elements/gtk-overlay.d.ts +22 -0
  81. package/lib/types/elements/gtk-page-setup-unix-dialog.d.ts +87 -0
  82. package/lib/types/elements/gtk-paned.d.ts +121 -0
  83. package/lib/types/elements/gtk-password-entry.d.ts +27 -0
  84. package/lib/types/elements/gtk-picture.d.ts +66 -0
  85. package/lib/types/elements/gtk-popover-bin.d.ts +82 -0
  86. package/lib/types/elements/gtk-popover-menu-bar.d.ts +66 -0
  87. package/lib/types/elements/gtk-popover-menu.d.ts +83 -0
  88. package/lib/types/elements/gtk-popover.d.ts +28 -3
  89. package/lib/types/elements/gtk-print-unix-dialog.d.ts +167 -0
  90. package/lib/types/elements/gtk-revealer.d.ts +55 -0
  91. package/lib/types/elements/gtk-scale-button.d.ts +59 -0
  92. package/lib/types/elements/gtk-scale.d.ts +98 -0
  93. package/lib/types/elements/gtk-scrollbar.d.ts +124 -0
  94. package/lib/types/elements/gtk-scrolled-window.d.ts +129 -0
  95. package/lib/types/elements/gtk-search-bar.d.ts +39 -0
  96. package/lib/types/elements/gtk-search-entry.d.ts +27 -0
  97. package/lib/types/elements/gtk-separator.d.ts +10 -0
  98. package/lib/types/elements/gtk-spin-button.d.ts +94 -0
  99. package/lib/types/elements/gtk-spinner.d.ts +14 -0
  100. package/lib/types/elements/gtk-stack-sidebar.d.ts +43 -0
  101. package/lib/types/elements/gtk-stack-switcher.d.ts +58 -0
  102. package/lib/types/elements/gtk-stack.d.ts +154 -0
  103. package/lib/types/elements/gtk-switch.d.ts +4 -1
  104. package/lib/types/elements/gtk-text-view.d.ts +62 -0
  105. package/lib/types/elements/gtk-text.d.ts +45 -0
  106. package/lib/types/elements/gtk-toggle-button.d.ts +45 -0
  107. package/lib/types/elements/gtk-tree-expander.d.ts +38 -0
  108. package/lib/types/elements/gtk-video.d.ts +97 -0
  109. package/lib/types/elements/gtk-viewport.d.ts +84 -0
  110. package/lib/types/elements/gtk-window-controls.d.ts +80 -0
  111. package/lib/types/elements/gtk-window-handle.d.ts +39 -0
  112. package/lib/types/elements/gtk-window.d.ts +103 -0
  113. package/lib/types/elements/justification.d.ts +2 -0
  114. package/lib/types/elements/popover-menu.d.ts +18 -0
  115. package/lib/types/elements/roving-focus.d.ts +29 -1
  116. package/lib/types/emoji-data.d.ts +38 -0
  117. package/lib/types/font-description.d.ts +96 -0
  118. package/lib/types/gtk-about-dialog.spec.d.ts +1 -0
  119. package/lib/types/gtk-action-bar.spec.d.ts +1 -0
  120. package/lib/types/gtk-application-window.spec.d.ts +1 -0
  121. package/lib/types/gtk-aspect-frame.spec.d.ts +1 -0
  122. package/lib/types/gtk-calendar.spec.d.ts +1 -0
  123. package/lib/types/gtk-center-box.spec.d.ts +1 -0
  124. package/lib/types/gtk-color-dialog-button.spec.d.ts +1 -0
  125. package/lib/types/gtk-column-view.spec.d.ts +1 -0
  126. package/lib/types/gtk-drag-icon.spec.d.ts +1 -0
  127. package/lib/types/gtk-drawing-area.spec.d.ts +1 -0
  128. package/lib/types/gtk-editable-label.spec.d.ts +1 -0
  129. package/lib/types/gtk-emoji-chooser.spec.d.ts +1 -0
  130. package/lib/types/gtk-expander.spec.d.ts +1 -0
  131. package/lib/types/gtk-fixed.spec.d.ts +1 -0
  132. package/lib/types/gtk-flow-box.spec.d.ts +1 -0
  133. package/lib/types/gtk-font-dialog-button.spec.d.ts +1 -0
  134. package/lib/types/gtk-frame.spec.d.ts +1 -0
  135. package/lib/types/gtk-gl-area.spec.d.ts +1 -0
  136. package/lib/types/gtk-graphics-offload.spec.d.ts +1 -0
  137. package/lib/types/gtk-grid-view.spec.d.ts +1 -0
  138. package/lib/types/gtk-grid.spec.d.ts +1 -0
  139. package/lib/types/gtk-header-bar.spec.d.ts +1 -0
  140. package/lib/types/gtk-inscription.spec.d.ts +1 -0
  141. package/lib/types/gtk-level-bar.spec.d.ts +1 -0
  142. package/lib/types/gtk-link-button.spec.d.ts +1 -0
  143. package/lib/types/gtk-list-box.spec.d.ts +1 -0
  144. package/lib/types/gtk-list-view.spec.d.ts +1 -0
  145. package/lib/types/gtk-media-controls.spec.d.ts +1 -0
  146. package/lib/types/gtk-notebook.spec.d.ts +1 -0
  147. package/lib/types/gtk-overlay.spec.d.ts +1 -0
  148. package/lib/types/gtk-paned.spec.d.ts +1 -0
  149. package/lib/types/gtk-password-entry.spec.d.ts +1 -0
  150. package/lib/types/gtk-picture.spec.d.ts +1 -0
  151. package/lib/types/gtk-popover-bin.spec.d.ts +1 -0
  152. package/lib/types/gtk-popover-menu-bar.spec.d.ts +1 -0
  153. package/lib/types/gtk-popover-menu.spec.d.ts +1 -0
  154. package/lib/types/gtk-popover-role.spec.d.ts +1 -0
  155. package/lib/types/gtk-popover.spec.d.ts +1 -0
  156. package/lib/types/gtk-print-dialogs.spec.d.ts +1 -0
  157. package/lib/types/gtk-revealer.spec.d.ts +1 -0
  158. package/lib/types/gtk-scale-button.spec.d.ts +1 -0
  159. package/lib/types/gtk-scale.spec.d.ts +1 -0
  160. package/lib/types/gtk-scrollbar.spec.d.ts +1 -0
  161. package/lib/types/gtk-scrolled-window.spec.d.ts +1 -0
  162. package/lib/types/gtk-search-bar.spec.d.ts +1 -0
  163. package/lib/types/gtk-search-entry.spec.d.ts +1 -0
  164. package/lib/types/gtk-separator.spec.d.ts +1 -0
  165. package/lib/types/gtk-spin-button.spec.d.ts +1 -0
  166. package/lib/types/gtk-spinner.spec.d.ts +1 -0
  167. package/lib/types/gtk-stack-sidebar.spec.d.ts +1 -0
  168. package/lib/types/gtk-stack-switcher.spec.d.ts +1 -0
  169. package/lib/types/gtk-stack.spec.d.ts +1 -0
  170. package/lib/types/gtk-text-view.spec.d.ts +1 -0
  171. package/lib/types/gtk-text.spec.d.ts +1 -0
  172. package/lib/types/gtk-toggle-button.spec.d.ts +1 -0
  173. package/lib/types/gtk-tree-expander.spec.d.ts +1 -0
  174. package/lib/types/gtk-video.spec.d.ts +1 -0
  175. package/lib/types/gtk-viewport.spec.d.ts +1 -0
  176. package/lib/types/gtk-window-controls.spec.d.ts +1 -0
  177. package/lib/types/gtk-window-handle.spec.d.ts +1 -0
  178. package/lib/types/gtk-window.spec.d.ts +1 -0
  179. package/lib/types/index.d.ts +4 -1
  180. package/lib/types/list-view-dom.d.ts +44 -0
  181. package/lib/types/namespace/adw.d.ts +12 -0
  182. package/lib/types/namespace/gtk.d.ts +61 -0
  183. package/lib/types/page-setup.d.ts +100 -0
  184. package/lib/types/row-line-clamp.d.ts +20 -0
  185. package/lib/types/row-tooltip.d.ts +8 -0
  186. package/lib/types/row-tooltip.spec.d.ts +1 -0
  187. package/lib/types/scroll-shading.d.ts +15 -1
  188. package/lib/types/shared-tree-builder.d.ts +75 -17
  189. package/lib/types/shared-tree-mount.spec.d.ts +1 -0
  190. package/lib/types/signals.d.ts +4 -0
  191. package/lib/types/styles.generated.d.ts +1 -1
  192. package/lib/types/tab-chip.d.ts +73 -0
  193. package/lib/types/template-classes.d.ts +11 -0
  194. package/lib/types/widget-size.spec.d.ts +1 -0
  195. package/package.json +12 -8
  196. package/scss/_action_row.scss +41 -17
  197. package/scss/_application_window.scss +26 -0
  198. package/scss/_aspect_frame.scss +25 -0
  199. package/scss/_bin.scss +26 -0
  200. package/scss/_button.scss +45 -0
  201. package/scss/_button_row.scss +5 -0
  202. package/scss/_calendar.scss +176 -0
  203. package/scss/_center_box.scss +25 -0
  204. package/scss/_checks.scss +6 -1
  205. package/scss/_clamp_scrollable.scss +28 -0
  206. package/scss/_color_button.scss +67 -0
  207. package/scss/_column_view.scss +126 -0
  208. package/scss/_drag_icon.scss +55 -0
  209. package/scss/_drawing.scss +85 -0
  210. package/scss/_emoji_chooser.scss +213 -0
  211. package/scss/_entry.scss +13 -5
  212. package/scss/_entry_row.scss +1 -1
  213. package/scss/_expander.scss +113 -0
  214. package/scss/_expander_row.scss +36 -3
  215. package/scss/_fixed.scss +29 -0
  216. package/scss/_flow_box.scss +94 -0
  217. package/scss/_font_button.scss +63 -0
  218. package/scss/_frame.scss +41 -0
  219. package/scss/_grid.scss +19 -0
  220. package/scss/_grid_view.scss +46 -0
  221. package/scss/_gtk_about_dialog.scss +186 -0
  222. package/scss/_headerbar.scss +134 -1
  223. package/scss/_icons.generated.scss +186 -0
  224. package/scss/_inscription.scss +125 -0
  225. package/scss/_level_bar.scss +190 -0
  226. package/scss/_link.scss +82 -0
  227. package/scss/_list_box.scss +88 -0
  228. package/scss/_list_view.scss +96 -0
  229. package/scss/_media_controls.scss +139 -0
  230. package/scss/_overlay.scss +68 -0
  231. package/scss/_paned.scss +130 -0
  232. package/scss/_password_entry.scss +83 -0
  233. package/scss/_picture.scss +80 -0
  234. package/scss/_popover_bin.scss +53 -0
  235. package/scss/_popover_menu_bar.scss +104 -0
  236. package/scss/_preferences_row.scss +60 -0
  237. package/scss/_print_dialogs.scss +328 -0
  238. package/scss/_reset.scss +21 -19
  239. package/scss/_revealer.scss +37 -0
  240. package/scss/_row.scss +36 -5
  241. package/scss/_scale.scss +298 -0
  242. package/scss/_scale_button.scss +167 -0
  243. package/scss/_scrollbar.scss +230 -0
  244. package/scss/_scrolled_window.scss +131 -0
  245. package/scss/_search_bar.scss +118 -0
  246. package/scss/_search_entry.scss +86 -0
  247. package/scss/_separator.scss +44 -0
  248. package/scss/_shortcuts_dialog.scss +100 -0
  249. package/scss/_spin_button.scss +172 -0
  250. package/scss/_spin_row.scss +56 -8
  251. package/scss/_spinner.scss +85 -4
  252. package/scss/_stack.scss +729 -0
  253. package/scss/_status_page.scss +1 -1
  254. package/scss/_switch.scss +13 -5
  255. package/scss/_switch_row.scss +10 -0
  256. package/scss/_tab_bar.scss +317 -0
  257. package/scss/_tab_button.scss +98 -0
  258. package/scss/_tab_overview.scss +483 -0
  259. package/scss/_text.scss +182 -0
  260. package/scss/_theme.scss +1 -1
  261. package/scss/_toggle_group.scss +28 -0
  262. package/scss/_tree_expander.scss +62 -0
  263. package/scss/_variables.scss +1 -1
  264. package/scss/_video.scss +146 -0
  265. package/scss/_view_switcher_sidebar.scss +112 -0
  266. package/scss/_viewport.scss +50 -0
  267. package/scss/_widget.scss +14 -3
  268. package/scss/_window.scss +131 -2
  269. package/scss/_window_handle.scss +20 -0
  270. package/scss/adwaita-skin.scss +109 -0
  271. package/src/adw-action-rows.spec.ts +331 -0
  272. package/src/adw-application-window.spec.ts +118 -0
  273. package/src/adw-bin.spec.ts +75 -0
  274. package/src/adw-breakpoint-bin.spec.ts +324 -0
  275. package/src/adw-clamp-scrollable.spec.ts +189 -0
  276. package/src/adw-header-bar.spec.ts +18 -0
  277. package/src/adw-multi-layout-view.spec.ts +243 -0
  278. package/src/adw-preferences-row.spec.ts +164 -0
  279. package/src/adw-row-state.spec.ts +142 -0
  280. package/src/adw-shortcuts.spec.ts +155 -0
  281. package/src/adw-status-page.spec.ts +124 -0
  282. package/src/adw-tab-bar.spec.ts +287 -0
  283. package/src/adw-tab-button.spec.ts +101 -0
  284. package/src/adw-tab-overview.spec.ts +443 -0
  285. package/src/adw-view-switcher-sidebar.spec.ts +281 -0
  286. package/src/adw-window.spec.ts +129 -0
  287. package/src/attributes.ts +52 -0
  288. package/src/breakpoints.ts +25 -8
  289. package/src/capabilities.d.mts +3 -0
  290. package/src/capabilities.mjs +21 -0
  291. package/src/connect-lifecycle.spec.ts +12 -0
  292. package/src/construct-vectors.spec.ts +175 -0
  293. package/src/elements/adw-action-row.ts +31 -2
  294. package/src/elements/adw-alert-dialog.ts +4 -1
  295. package/src/elements/adw-application-window.ts +154 -0
  296. package/src/elements/adw-bin.ts +101 -0
  297. package/src/elements/adw-breakpoint-bin.ts +287 -0
  298. package/src/elements/adw-button-row.ts +7 -1
  299. package/src/elements/adw-clamp-scrollable.ts +207 -0
  300. package/src/elements/adw-combo-row.ts +26 -1
  301. package/src/elements/adw-dialog.ts +19 -0
  302. package/src/elements/adw-entry-row.ts +22 -12
  303. package/src/elements/adw-expander-row.ts +34 -1
  304. package/src/elements/adw-header-bar.ts +18 -4
  305. package/src/elements/adw-layout-slot.ts +95 -0
  306. package/src/elements/adw-multi-layout-view.ts +326 -0
  307. package/src/elements/adw-overlay-split-view.ts +29 -6
  308. package/src/elements/adw-preferences-row.ts +153 -0
  309. package/src/elements/adw-shortcuts-dialog.ts +52 -0
  310. package/src/elements/adw-shortcuts-item.ts +171 -0
  311. package/src/elements/adw-shortcuts-section.ts +86 -0
  312. package/src/elements/adw-sidebar.ts +74 -7
  313. package/src/elements/adw-spin-row.ts +37 -2
  314. package/src/elements/adw-status-page.ts +10 -2
  315. package/src/elements/adw-switch-row.ts +53 -2
  316. package/src/elements/adw-tab-bar.ts +529 -0
  317. package/src/elements/adw-tab-button.ts +194 -0
  318. package/src/elements/adw-tab-overview.ts +1011 -0
  319. package/src/elements/adw-tab-view.ts +66 -145
  320. package/src/elements/adw-toggle-group.ts +138 -14
  321. package/src/elements/adw-view-stack.ts +18 -0
  322. package/src/elements/adw-view-switcher-sidebar.ts +332 -0
  323. package/src/elements/adw-window.ts +190 -11
  324. package/src/elements/checks.ts +35 -8
  325. package/src/elements/gtk-about-dialog.ts +811 -0
  326. package/src/elements/gtk-application-window.ts +108 -0
  327. package/src/elements/gtk-aspect-frame.ts +160 -0
  328. package/src/elements/gtk-button.ts +12 -0
  329. package/src/elements/gtk-calendar.ts +757 -0
  330. package/src/elements/gtk-center-box.ts +184 -0
  331. package/src/elements/gtk-color-dialog-button.ts +278 -0
  332. package/src/elements/gtk-column-view.ts +320 -0
  333. package/src/elements/gtk-drag-icon.ts +257 -0
  334. package/src/elements/gtk-drawing-area.ts +303 -0
  335. package/src/elements/gtk-editable-label.ts +204 -0
  336. package/src/elements/gtk-emoji-chooser.ts +542 -0
  337. package/src/elements/gtk-entry.ts +39 -5
  338. package/src/elements/gtk-expander.ts +301 -0
  339. package/src/elements/gtk-fixed.ts +99 -0
  340. package/src/elements/gtk-flow-box-child.ts +68 -0
  341. package/src/elements/gtk-flow-box.ts +480 -0
  342. package/src/elements/gtk-font-dialog-button.ts +432 -0
  343. package/src/elements/gtk-frame.ts +174 -0
  344. package/src/elements/gtk-gl-area.ts +476 -0
  345. package/src/elements/gtk-graphics-offload.ts +130 -0
  346. package/src/elements/gtk-grid-view.ts +168 -0
  347. package/src/elements/gtk-grid.ts +127 -0
  348. package/src/elements/gtk-header-bar.ts +273 -0
  349. package/src/elements/gtk-inscription.ts +387 -0
  350. package/src/elements/gtk-label.ts +19 -11
  351. package/src/elements/gtk-level-bar.ts +323 -0
  352. package/src/elements/gtk-link-button.ts +138 -0
  353. package/src/elements/gtk-list-box-row.ts +195 -0
  354. package/src/elements/gtk-list-box.ts +413 -0
  355. package/src/elements/gtk-list-view.ts +370 -0
  356. package/src/elements/gtk-media-controls.ts +509 -0
  357. package/src/elements/gtk-notebook.ts +664 -0
  358. package/src/elements/gtk-overlay.ts +149 -0
  359. package/src/elements/gtk-page-setup-unix-dialog.ts +420 -0
  360. package/src/elements/gtk-paned.ts +597 -0
  361. package/src/elements/gtk-password-entry.ts +170 -0
  362. package/src/elements/gtk-picture.ts +254 -0
  363. package/src/elements/gtk-popover-bin.ts +332 -0
  364. package/src/elements/gtk-popover-menu-bar.ts +355 -0
  365. package/src/elements/gtk-popover-menu.ts +339 -0
  366. package/src/elements/gtk-popover.ts +92 -10
  367. package/src/elements/gtk-print-unix-dialog.ts +989 -0
  368. package/src/elements/gtk-progress-bar.ts +24 -11
  369. package/src/elements/gtk-revealer.ts +406 -0
  370. package/src/elements/gtk-scale-button.ts +358 -0
  371. package/src/elements/gtk-scale.ts +492 -0
  372. package/src/elements/gtk-scrollbar.ts +528 -0
  373. package/src/elements/gtk-scrolled-window.ts +653 -0
  374. package/src/elements/gtk-search-bar.ts +200 -0
  375. package/src/elements/gtk-search-entry.ts +172 -0
  376. package/src/elements/gtk-separator.ts +52 -0
  377. package/src/elements/gtk-spin-button.ts +475 -0
  378. package/src/elements/gtk-spinner.ts +126 -0
  379. package/src/elements/gtk-stack-sidebar.ts +212 -0
  380. package/src/elements/gtk-stack-switcher.ts +279 -0
  381. package/src/elements/gtk-stack.ts +748 -0
  382. package/src/elements/gtk-switch.ts +52 -19
  383. package/src/elements/gtk-text-view.ts +290 -0
  384. package/src/elements/gtk-text.ts +219 -0
  385. package/src/elements/gtk-toggle-button.ts +239 -0
  386. package/src/elements/gtk-tree-expander.ts +243 -0
  387. package/src/elements/gtk-video.ts +423 -0
  388. package/src/elements/gtk-viewport.ts +277 -0
  389. package/src/elements/gtk-window-controls.ts +341 -0
  390. package/src/elements/gtk-window-handle.ts +221 -0
  391. package/src/elements/gtk-window.ts +372 -0
  392. package/src/elements/justification.ts +24 -0
  393. package/src/elements/popover-menu.ts +24 -0
  394. package/src/elements/roving-focus.ts +53 -21
  395. package/src/emoji-data.ts +577 -0
  396. package/src/entry-rows.spec.ts +31 -0
  397. package/src/font-description.ts +238 -0
  398. package/src/gtk-about-dialog.spec.ts +250 -0
  399. package/src/gtk-action-bar.spec.ts +89 -0
  400. package/src/gtk-application-window.spec.ts +107 -0
  401. package/src/gtk-aspect-frame.spec.ts +114 -0
  402. package/src/gtk-calendar.spec.ts +589 -0
  403. package/src/gtk-center-box.spec.ts +125 -0
  404. package/src/gtk-color-dialog-button.spec.ts +141 -0
  405. package/src/gtk-column-view.spec.ts +154 -0
  406. package/src/gtk-drag-icon.spec.ts +190 -0
  407. package/src/gtk-drawing-area.spec.ts +211 -0
  408. package/src/gtk-editable-label.spec.ts +190 -0
  409. package/src/gtk-emoji-chooser.spec.ts +173 -0
  410. package/src/gtk-entry.spec.ts +23 -0
  411. package/src/gtk-expander.spec.ts +170 -0
  412. package/src/gtk-fixed.spec.ts +97 -0
  413. package/src/gtk-flow-box.spec.ts +289 -0
  414. package/src/gtk-font-dialog-button.spec.ts +166 -0
  415. package/src/gtk-frame.spec.ts +119 -0
  416. package/src/gtk-gl-area.spec.ts +361 -0
  417. package/src/gtk-graphics-offload.spec.ts +119 -0
  418. package/src/gtk-grid-view.spec.ts +106 -0
  419. package/src/gtk-grid.spec.ts +122 -0
  420. package/src/gtk-header-bar.spec.ts +202 -0
  421. package/src/gtk-inscription.spec.ts +235 -0
  422. package/src/gtk-level-bar.spec.ts +199 -0
  423. package/src/gtk-link-button.spec.ts +117 -0
  424. package/src/gtk-list-box.spec.ts +422 -0
  425. package/src/gtk-list-view.spec.ts +203 -0
  426. package/src/gtk-media-controls.spec.ts +295 -0
  427. package/src/gtk-notebook.spec.ts +546 -0
  428. package/src/gtk-overlay.spec.ts +141 -0
  429. package/src/gtk-paned.spec.ts +267 -0
  430. package/src/gtk-password-entry.spec.ts +150 -0
  431. package/src/gtk-picture.spec.ts +172 -0
  432. package/src/gtk-popover-bin.spec.ts +229 -0
  433. package/src/gtk-popover-menu-bar.spec.ts +296 -0
  434. package/src/gtk-popover-menu.spec.ts +261 -0
  435. package/src/gtk-popover-role.spec.ts +138 -0
  436. package/src/gtk-popover.spec.ts +264 -0
  437. package/src/gtk-print-dialogs.spec.ts +251 -0
  438. package/src/gtk-revealer.spec.ts +164 -0
  439. package/src/gtk-scale-button.spec.ts +218 -0
  440. package/src/gtk-scale.spec.ts +213 -0
  441. package/src/gtk-scrollbar.spec.ts +244 -0
  442. package/src/gtk-scrolled-window.spec.ts +262 -0
  443. package/src/gtk-search-bar.spec.ts +179 -0
  444. package/src/gtk-search-entry.spec.ts +142 -0
  445. package/src/gtk-separator.spec.ts +74 -0
  446. package/src/gtk-spin-button.spec.ts +186 -0
  447. package/src/gtk-spinner.spec.ts +130 -0
  448. package/src/gtk-stack-sidebar.spec.ts +217 -0
  449. package/src/gtk-stack-switcher.spec.ts +249 -0
  450. package/src/gtk-stack.spec.ts +432 -0
  451. package/src/gtk-text-view.spec.ts +189 -0
  452. package/src/gtk-text.spec.ts +163 -0
  453. package/src/gtk-toggle-button.spec.ts +186 -0
  454. package/src/gtk-tree-expander.spec.ts +201 -0
  455. package/src/gtk-video.spec.ts +240 -0
  456. package/src/gtk-viewport.spec.ts +140 -0
  457. package/src/gtk-window-controls.spec.ts +232 -0
  458. package/src/gtk-window-handle.spec.ts +158 -0
  459. package/src/gtk-window.spec.ts +202 -0
  460. package/src/index.ts +9 -1
  461. package/src/keyboard-operable.spec.ts +77 -9
  462. package/src/list-view-dom.ts +121 -0
  463. package/src/namespace/adw.ts +12 -0
  464. package/src/namespace/gtk.ts +61 -0
  465. package/src/page-setup.ts +222 -0
  466. package/src/row-line-clamp.ts +74 -0
  467. package/src/row-tooltip.spec.ts +313 -0
  468. package/src/row-tooltip.ts +52 -0
  469. package/src/scroll-shading.ts +18 -1
  470. package/src/shared-tree-builder.ts +336 -41
  471. package/src/shared-tree-mount.spec.ts +130 -0
  472. package/src/shared-trees.spec.ts +15 -0
  473. package/src/signals.ts +15 -0
  474. package/src/style-classes.spec.ts +9 -8
  475. package/src/styles.generated.ts +1 -1
  476. package/src/tab-chip.ts +200 -0
  477. package/src/template-classes.ts +45 -0
  478. package/src/test.browser.mts +160 -0
  479. package/src/widget-size.spec.ts +117 -0
@@ -45,21 +45,27 @@
45
45
  // Modifications: Implemented as a Web Component for @gjsify/adwaita-web; the
46
46
  // tab icon + indicator nodes are <gtk-image>.
47
47
 
48
- import { TabViewState, tabCloseVisible, tabIconState, tabTooltip, tabsRevealed } from '@gjsify/adwaita-core';
48
+ import { TabViewState, tabsRevealed } from '@gjsify/adwaita-core';
49
49
  import type { AdwTabPageSpec, AdwTabPageState, TabViewPagesChange, TabViewSelectionChange } from '@gjsify/adwaita-core';
50
50
 
51
51
  import { bindSlottedChildren } from '../slotted-children.js';
52
- import { type GtkImage, createGtkImage } from './gtk-image.js';
52
+ import { type TabChip, createTabChip, refreshTabChip, refreshTabChipClose, scrollChipIntoBar } from '../tab-chip.js';
53
53
 
54
54
  export type AdwTabViewPage = AdwTabPageState<HTMLElement>;
55
55
 
56
56
  export type AdwTabViewPageSpec = AdwTabPageSpec<HTMLElement>;
57
57
 
58
58
  /** The live `<adw-tab-page>` properties, each mapped onto a state setter. */
59
- const PAGE_ATTRIBUTES = ['title', 'tooltip', 'icon', 'indicator-icon', 'loading', 'needs-attention', 'pinned'];
60
-
61
- /** `SPACING`: the slack `scroll_to_tab_full` allows before it scrolls (adw-tab-box.c:24). */
62
- const TAB_SPACING = 5;
59
+ const PAGE_ATTRIBUTES = [
60
+ 'title',
61
+ 'tooltip',
62
+ 'icon',
63
+ 'indicator-icon',
64
+ 'keyword',
65
+ 'loading',
66
+ 'needs-attention',
67
+ 'pinned',
68
+ ];
63
69
 
64
70
  /**
65
71
  * A single page. Declared as a child of <adw-tab-view>; the element itself becomes the
@@ -109,6 +115,8 @@ export class AdwTabView extends HTMLElement {
109
115
  private readonly _pagesEl: HTMLDivElement;
110
116
  /** Tab chips keyed by page id — the bar is edited in place, never rebuilt. */
111
117
  private readonly _tabs = new Map<string, HTMLButtonElement>();
118
+ /** The same chips as {@link _tabs}, held as the shared builder's parts for a refresh. */
119
+ private readonly _chips = new Map<string, TabChip>();
112
120
  /** Page panels keyed by page id; kept so a DETACHED page's node is still reachable. */
113
121
  private readonly _panels = new Map<string, HTMLElement>();
114
122
  private readonly _hovered = new Set<string>();
@@ -258,6 +266,9 @@ export class AdwTabView extends HTMLElement {
258
266
  case 'indicator-icon':
259
267
  this._state.setPageIndicatorIcon(id, value);
260
268
  return;
269
+ case 'keyword':
270
+ this._state.setPageKeyword(id, value);
271
+ return;
261
272
  case 'loading':
262
273
  this._state.setPageLoading(id, value !== null);
263
274
  return;
@@ -428,10 +439,25 @@ export class AdwTabView extends HTMLElement {
428
439
  return this._state.setPageTooltip(id, tooltip);
429
440
  }
430
441
 
442
+ /**
443
+ * Set a page's search keyword (`AdwTabPage:keyword`) — the string the tab overview's
444
+ * search matches on beside the title and the tooltip ("Use keywords to search in
445
+ * e.g. page URLs in a web browser", adw-tab-overview.c:1646-1648).
446
+ */
447
+ setPageKeyword(id: string, keyword: string | null): boolean {
448
+ return this._state.setPageKeyword(id, keyword);
449
+ }
450
+
451
+ /** Set a page's icon name (`adw_tab_page_set_icon`). */
431
452
  setPageIcon(id: string, icon: string | null): boolean {
432
453
  return this._state.setPageIcon(id, icon);
433
454
  }
434
455
 
456
+ /** Set a page's indicator icon (`adw_tab_page_set_indicator_icon`). */
457
+ setPageIndicatorIcon(id: string, indicatorIcon: string | null): boolean {
458
+ return this._state.setPageIndicatorIcon(id, indicatorIcon);
459
+ }
460
+
435
461
  setPageLoading(id: string, loading: boolean): boolean {
436
462
  return this._state.setPageLoading(id, loading);
437
463
  }
@@ -488,6 +514,7 @@ export class AdwTabView extends HTMLElement {
488
514
  case 'detached': {
489
515
  this._tabs.get(change.id)?.remove();
490
516
  this._tabs.delete(change.id);
517
+ this._chips.delete(change.id);
491
518
  this._hovered.delete(change.id);
492
519
  // The page is already out of the model, so its node has to come
493
520
  // from here rather than from `getPage(id)?.content`.
@@ -516,64 +543,28 @@ export class AdwTabView extends HTMLElement {
516
543
  }
517
544
 
518
545
  private _insertTab(page: AdwTabViewPage, position: number): void {
519
- const tab = document.createElement('button');
520
- tab.type = 'button';
521
- tab.className = 'adw-tab';
522
- tab.setAttribute('role', 'tab');
523
- tab.dataset.pageId = page.id;
524
-
525
- // Decorative mask-image nodes — <gtk-image> carries the convention, including the
526
- // `-symbolic` strip, which is ours and not C's: there the name reaches
527
- // `GtkImage` untouched.
528
- const icon = createGtkImage(null, 'adw-tab-icon');
529
- tab.appendChild(icon);
530
-
531
- // `AdwTabPage:loading` swaps the icon image for an `AdwSpinnerPaintable` — the
532
- // SAME paintable `Adw.Spinner` uses (`update_icons`). So this is a real
533
- // `<adw-spinner>` in the icon's slot, not a ring drawn again in CSS: a CSS copy
534
- // inherits every spinner defect independently.
535
- const spinner = document.createElement('adw-spinner');
536
- spinner.className = 'adw-tab-spinner';
537
- spinner.setAttribute('size', '16');
538
- spinner.hidden = true;
539
- tab.appendChild(spinner);
540
-
541
- const label = document.createElement('span');
542
- label.className = 'adw-tab-title';
543
- tab.appendChild(label);
544
-
545
- tab.appendChild(createGtkImage(null, 'adw-tab-indicator'));
546
-
547
- // Close affordance — a small flat button drawn with a CSS "×" glyph. NOT because
548
- // the glyph is unavailable: `window-close` is in the ICONS map and has a mask class
549
- // (the comment that used to stand here said otherwise, and was read by two more
550
- // widgets). It is a SIZING difference — upstream's close button is 24px around a
551
- // 16px symbolic (adw-tab.ui:77), this strip's chip budgets 18px, and a 16px-grid
552
- // symbolic scaled into it is a design change, not a rename.
553
- // `can-focus=False` in C, so it stays out of the tab order here too.
554
- const close = document.createElement('button');
555
- close.type = 'button';
556
- close.className = 'adw-tab-close';
557
- close.tabIndex = -1;
558
- close.setAttribute('aria-label', 'Close tab');
559
- close.addEventListener('click', (event) => {
560
- event.stopPropagation();
561
- this._state.closePage(page.id);
562
- });
563
- tab.appendChild(close);
564
-
565
- tab.addEventListener('click', () => this._state.setSelectedPage(page.id));
566
- tab.addEventListener('pointerenter', () => {
567
- this._hovered.add(page.id);
568
- this._refreshCloseVisibility(page.id);
569
- });
570
- tab.addEventListener('pointerleave', () => {
571
- this._hovered.delete(page.id);
572
- this._refreshCloseVisibility(page.id);
546
+ // The chip itself is the shared one (`../tab-chip.js`), which `<adw-tab-bar>` builds
547
+ // too — the five nodes, their classes and every derivation off the page live there,
548
+ // and what is left here is this widget's own business: where the chip goes in the
549
+ // strip, which page it answers to, and the close affordance's focus policy.
550
+ const chip = createTabChip({
551
+ onSelect: () => this._state.setSelectedPage(page.id),
552
+ onClose: () => this._state.closePage(page.id),
553
+ onHover: (hovering) => {
554
+ if (hovering) this._hovered.add(page.id);
555
+ else this._hovered.delete(page.id);
556
+ this._refreshCloseVisibility(page.id);
557
+ },
573
558
  });
559
+ chip.el.dataset.pageId = page.id;
560
+ // `can-focus=False` in C (adw-tab.ui:77), and it lives in the WIDGET rather than in
561
+ // the shared builder because the roving obligation belongs to the file that
562
+ // registers the arrow keys — see scripts/check-adwaita-keyboard-contract.mjs.
563
+ chip.close.tabIndex = -1;
574
564
 
575
- this._tabBoxEl.insertBefore(tab, this._tabBoxEl.children[position] ?? null);
576
- this._tabs.set(page.id, tab);
565
+ this._tabBoxEl.insertBefore(chip.el, this._tabBoxEl.children[position] ?? null);
566
+ this._tabs.set(page.id, chip.el);
567
+ this._chips.set(page.id, chip);
577
568
 
578
569
  const panel = page.content;
579
570
  if (panel) {
@@ -600,79 +591,25 @@ export class AdwTabView extends HTMLElement {
600
591
  const page = this._state.getPage(id);
601
592
  const tab = this._tabs.get(id);
602
593
  if (!page || !tab) return;
603
-
604
- const label = tab.querySelector('.adw-tab-title') as HTMLElement | null;
605
- if (label) label.textContent = page.title;
606
- // The tooltip is Pango MARKUP when the page sets one of its own. The DOM `title`
607
- // attribute is a TEXT sink, so the markup is shown verbatim rather than pushed
608
- // through an HTML sink — interpreting it would execute page-supplied markup.
609
- tab.title = tabTooltip(page);
610
- tab.classList.toggle('pinned', page.pinned);
611
- tab.classList.toggle('needs-attention', page.needsAttention);
612
- tab.classList.toggle('closing', page.closing);
613
-
614
- const icons = tabIconState(page, this.getAttribute('default-icon'));
615
- const icon = tab.querySelector('.adw-tab-icon') as GtkImage | null;
616
- if (icon) {
617
- icon.iconName = icons.icon;
618
- // The two occupy the same slot and are never both visible: C
619
- // REPLACES the image's contents rather than stacking a second node.
620
- icon.hidden = !icons.iconVisible || icons.spinner;
621
- }
622
- const spinner = tab.querySelector('.adw-tab-spinner') as HTMLElement | null;
623
- // The spinner is mounted only while it spins, so an idle tab holds no
624
- // element in the shared rAF ticker.
625
- if (spinner) spinner.hidden = !(icons.spinner && icons.iconVisible);
626
- const indicator = tab.querySelector('.adw-tab-indicator') as GtkImage | null;
627
- if (indicator) {
628
- indicator.iconName = page.indicatorIcon;
629
- indicator.hidden = !icons.indicatorVisible;
630
- }
594
+ refreshTabChip(this._chips.get(id) as TabChip, page, this.getAttribute('default-icon'));
631
595
  this._refreshCloseVisibility(id);
632
596
  }
633
597
 
634
598
  /**
635
- * `get_tab_position` in the BAR's scroll space: how far the chip sits from the
636
- * strip's scroll origin, the one coordinate both `scroll_to_tab_full` and
637
- * `update_visible` compare against the adjustment.
638
- *
639
- * Never `offsetLeft`. Nothing in this widget is positioned, so a chip's offsetParent
640
- * is whichever positioned ancestor the HOST page happens to have; a tab view that
641
- * merely sits indented then measured every chip against the wrong origin and
642
- * reported all of them clipped.
643
- */
644
- private _tabPosition(tab: HTMLElement): number {
645
- return tab.getBoundingClientRect().left - this._barEl.getBoundingClientRect().left + this._barEl.scrollLeft;
646
- }
647
-
648
- /**
649
- * `tabCloseVisible`, with its pinned gate. `dragging` is constantly false — tab
650
- * drag-and-drop is compositor work and is not modelled — and `fullyVisible` is
651
- * measured against the bar's scroll window, which is what the C term means for a
652
- * horizontally scrolled bar.
599
+ * The close affordance's visibility, and both halves of it now live in `../tab-chip.js`
600
+ * — `tabCloseVisible` and the geometry it is measured with, in the BAR's own scroll
601
+ * space. The incident that moved them there is recorded beside `chipPosition`: the
602
+ * measurement once used `offsetLeft`, which is relative to whichever positioned ancestor
603
+ * the HOST page happens to have, so a tab view that merely sat indented reported every
604
+ * chip clipped and swallowed the close button on hover.
653
605
  */
654
606
  private _refreshCloseVisibility(id: string): void {
655
607
  const page = this._state.getPage(id);
656
- const tab = this._tabs.get(id);
657
- if (!page || !tab) return;
658
- const close = tab.querySelector('.adw-tab-close') as HTMLElement | null;
659
- if (!close) return;
660
-
661
- const barLeft = this._barEl.scrollLeft;
662
- const pos = this._tabPosition(tab);
663
- // `update_visible` (adw-tab-box.c:769-797). C also demands SPACING of slack on
664
- // both sides; that term is deliberately NOT transplanted, because it is not
665
- // slack there either: the allocation loop starts the first tab at `pos = SPACING`
666
- // and puts SPACING between tabs (:3270-3286), so `pos - SPACING >= value` is
667
- // exactly "flush against the leading edge". This strip has no such gaps, so the
668
- // same term would report the first chip clipped and hide its close button.
669
- const fullyVisible = pos >= barLeft && pos + tab.offsetWidth <= barLeft + this._barEl.clientWidth;
670
- close.hidden = !tabCloseVisible({
608
+ const chip = this._chips.get(id);
609
+ if (!page || !chip) return;
610
+ refreshTabChipClose(this._barEl, chip, page, {
671
611
  hovering: this._hovered.has(id),
672
- fullyVisible,
673
612
  selected: this._state.selectedId === id,
674
- dragging: false,
675
- pinned: page.pinned,
676
613
  });
677
614
  }
678
615
 
@@ -714,30 +651,14 @@ export class AdwTabView extends HTMLElement {
714
651
 
715
652
  /**
716
653
  * `scroll_to_tab_full` (adw-tab-box.c:928-961), called on every selection the way
717
- * `select_page` calls it (:1728): bring the selected chip inside the BAR's own
718
- * scroll window, padded by half of whichever is smaller, the chip or the leftover.
719
- *
720
- * The bar is the only thing C ever scrolls for a tab: `scroll_to_tab_full` writes
721
- * `self->adjustment`, the strip's own adjustment, and nothing else. The DOM has no
722
- * such narrow API: `focus()` and `scrollIntoView()` both walk EVERY scrollable
723
- * ancestor up to the window. So this moves `scrollLeft` by hand, and the focus call
724
- * below passes `preventScroll`.
654
+ * `select_page` calls it (:1728) — `scrollChipIntoBar` in `../tab-chip.js`, with the
655
+ * reasoning and the SPACING slack that is deliberately not transplanted.
725
656
  */
726
657
  private _scrollSelectedTabIntoBar(): void {
727
658
  const id = this._state.selectedId;
728
659
  const tab = id === null ? undefined : this._tabs.get(id);
729
660
  if (!tab) return;
730
- const pageSize = this._barEl.clientWidth;
731
- const width = tab.offsetWidth;
732
- // Unmeasured (detached, or still inside connectedCallback): nothing to scroll to.
733
- if (pageSize <= 0 || width <= 0) return;
734
-
735
- const value = this._barEl.scrollLeft;
736
- const pos = this._tabPosition(tab);
737
- const padding = Math.min(width, pageSize - width) / 2;
738
- if (pos - TAB_SPACING < value) this._barEl.scrollLeft = pos - padding;
739
- else if (pos + width + TAB_SPACING > value + pageSize)
740
- this._barEl.scrollLeft = pos + width + padding - pageSize;
661
+ scrollChipIntoBar(this._barEl, tab);
741
662
  }
742
663
 
743
664
  private _applyBarVisibility(): void {
@@ -1,7 +1,8 @@
1
1
  // <adw-toggle-group> — the web counterpart of Adw.ToggleGroup: a linked set of toggle
2
2
  // buttons where exactly one is active. Toggles are `<adw-toggle>` children carrying
3
- // `label` and/or `icon-name` and an optional `name`, which the group's `active-name`
4
- // selects by (read at connect, like the rest). The `flat` / `round` attributes mirror the upstream
3
+ // `label` and/or `icon-name`, an optional `tooltip`, and an optional `name`, which the
4
+ // group's `active-name` selects by (read at connect, like the rest). The `flat` / `round`
5
+ // attributes mirror the upstream
5
6
  // `.flat` / `.round` style classes. `notify::active` (CustomEvent, bubbles, detail
6
7
  // `{ active }`) mirrors the `active` GObject property.
7
8
  //
@@ -47,6 +48,28 @@
47
48
  // C does for the only layout this element has, it matches the three sibling tab lists,
48
49
  // and it leaves ArrowUp/ArrowDown to the page instead of swallowing a scroll.
49
50
  //
51
+ // SENSITIVITY HAS TWO DOORS, and both are the GTK ones. `GtkWidget:sensitive` on the GROUP
52
+ // is the `sensitive` attribute, read by VALUE rather than by presence because the property
53
+ // is TRUE by default and `<adw-toggle-group>` must not read as insensitive (`src/attributes.ts`).
54
+ // `AdwToggle:enabled` is per toggle.
55
+ //
56
+ // PER-TOGGLE `enabled` IS REACHABLE, and the issue's warning does not close it. `add_toggle`
57
+ // spends it at add time — `gtk_widget_set_sensitive (toggle->button, toggle->enabled)`
58
+ // (adw-toggle-group.c:871) — and `adw_toggle_set_enabled` applies it to that same button
59
+ // afterwards (:1663), so nothing about the order is load-bearing. What makes the door awkward
60
+ // is not the order but the TYPE: `AdwToggle` is not a widget and has no `set_sensitive`, so
61
+ // `add_toggle` is the only public way in and it wants an `AdwToggle` this element never
62
+ // builds. Here the door is the rendered `<button>` — which is exactly what `add_toggle` spends
63
+ // the flag on — so the element reads `enabled` where `add_toggle` would have read it and lands
64
+ // in the same state. One consequence is ported with it: an insensitive toggle cannot be the
65
+ // active one (`set_active_toggle`, :720), which is also what makes a disabled `<button>`
66
+ // agree with the selection rather than sitting checked and unreachable.
67
+ //
68
+ // The roving walk is FILTERED, which `roving-focus.ts` requires of every caller: a disabled
69
+ // `<button>` cannot take focus, and leaving one in strands the user on a `focus()` the browser
70
+ // refuses. `status/open-todos/adwaita-web.md` made adding that filter the price of the
71
+ // attribute; this is that change.
72
+ //
50
73
  // Reference: refs/libadwaita/src/adw-toggle-group.c (AdwToggleGroup behaviour)
51
74
  // Reference: refs/libadwaita/src/stylesheet/widgets/_toggle-group.scss
52
75
  // Reference: refs/adwaita-web/adwaita-web/scss/_toggle_group.scss
@@ -57,13 +80,34 @@
57
80
 
58
81
  import { ToggleGroupState, keptToggles, toggleIndexOfName } from '@gjsify/adwaita-core';
59
82
 
83
+ import { booleanAttribute } from '../attributes.js';
60
84
  import { createGtkImage } from './gtk-image.js';
61
85
  import { attachRovingFocus } from './roving-focus.js';
62
86
 
63
87
  /** A single toggle. Children of <adw-toggle-group>; consumed at connect time. */
64
88
  export class AdwToggle extends HTMLElement {
89
+ // `tooltip` joins because `AdwToggle:tooltip` exists upstream (:467) and an
90
+ // icon-only toggle has no other text — `tooltip` is what NAMES it, so it is not a
91
+ // decoration. It produces no disabled or hidden button, which is the invariant
92
+ // `keyboard-operable.spec.ts` pins this list for.
93
+ //
94
+ // `enabled` is the one that DOES change the invariant, and the pinned list is what
95
+ // forced the roving filter to land in the same change.
65
96
  static get observedAttributes() {
66
- return ['label', 'icon-name'];
97
+ return ['label', 'icon-name', 'tooltip', 'enabled'];
98
+ }
99
+
100
+ attributeChangedCallback(name: string, oldValue: string | null, newValue: string | null): void {
101
+ if (name === 'enabled' && oldValue !== newValue) {
102
+ // Notify the parent group that this toggle's enabled state changed.
103
+ this.dispatchEvent(
104
+ new CustomEvent('toggle-enabled-changed', {
105
+ bubbles: true,
106
+ composed: true,
107
+ detail: { enabled: newValue !== 'false' },
108
+ }),
109
+ );
110
+ }
67
111
  }
68
112
  }
69
113
 
@@ -77,9 +121,32 @@ export class AdwToggleGroup extends HTMLElement {
77
121
  private _stateAttr: 'aria-checked' | 'aria-selected' = 'aria-checked';
78
122
  /** Each toggle's `name`, in order — what `active-name` resolves against. */
79
123
  private _names: (string | null)[] = [];
124
+ /** `AdwToggle:enabled` per rendered button, in order — `add_toggle` spends this at add time. */
125
+ private _enabled: boolean[] = [];
126
+ /** The authored <adw-toggle> elements, kept to observe live `enabled` changes. */
127
+ private _toggles: AdwToggle[] = [];
80
128
 
81
129
  static get observedAttributes() {
82
- return ['active', 'active-name', 'flat', 'round'];
130
+ return ['active', 'active-name', 'flat', 'round', 'sensitive'];
131
+ }
132
+
133
+ /**
134
+ * `GtkWidget:sensitive` — whether the whole group is insensitive.
135
+ *
136
+ * TRUE unless the attribute says `false`, because the property defaults to TRUE and a
137
+ * boolean attribute read by PRESENCE would leave every group on a page insensitive.
138
+ */
139
+ get sensitive(): boolean {
140
+ return booleanAttribute(this.getAttribute('sensitive'), true);
141
+ }
142
+
143
+ set sensitive(value: boolean) {
144
+ this.setAttribute('sensitive', value ? 'true' : 'false');
145
+ }
146
+
147
+ /** Whether the toggle at `index` is enabled (`AdwToggle:enabled`) — false once disabled. */
148
+ isToggleEnabled(index: number): boolean {
149
+ return this._enabled[index] ?? false;
83
150
  }
84
151
 
85
152
  /** Zero-based index of the active toggle. */
@@ -154,19 +221,33 @@ export class AdwToggleGroup extends HTMLElement {
154
221
  // in the C.
155
222
  this._innerEl.setAttribute('role', 'none');
156
223
 
224
+ this._toggles = toggles;
157
225
  this._buttons = toggles.map((toggle, index) => {
158
226
  const btn = document.createElement('button');
159
227
  btn.type = 'button';
160
228
  btn.className = 'adw-toggle';
161
229
  btn.setAttribute('role', toggleRole);
230
+ // `add_toggle` reads `enabled` while building the button (:871), and a toggle
231
+ // with no `enabled` attribute is the TRUE default (:513).
232
+ this._enabled[index] = booleanAttribute(toggle.getAttribute('enabled'), true);
162
233
 
163
234
  const label = toggle.getAttribute('label') ?? '';
164
235
  const icon = toggle.getAttribute('icon-name') ?? '';
236
+ const tooltip = toggle.getAttribute('tooltip') ?? '';
165
237
  if (icon) btn.appendChild(createGtkImage(icon));
166
238
  if (label) btn.appendChild(document.createTextNode(label));
167
239
 
168
- // An icon-only toggle has no text — give it an accessible name.
169
- if (icon && !label) btn.setAttribute('aria-label', icon);
240
+ // `update_button` (adw-toggle-group.c:215) sets the tooltip FIRST and
241
+ // unconditionally, so it is a property of the button whatever else it holds.
242
+ btn.title = tooltip;
243
+
244
+ // The accessible NAME falls through in upstream's order (:226-282): a label
245
+ // names the toggle and the tooltip is then GTK's automatic DESCRIPTION; with
246
+ // no label, the TOOLTIP becomes the name. The icon name is the last resort —
247
+ // it is a symbolic identifier, not words, which is exactly why an icon-only
248
+ // toggle was undiscoverable without this.
249
+ if (!label && tooltip) btn.setAttribute('aria-label', tooltip);
250
+ else if (icon && !label) btn.setAttribute('aria-label', icon);
170
251
 
171
252
  btn.addEventListener('click', () => this._selectIndex(index));
172
253
  return btn;
@@ -175,6 +256,21 @@ export class AdwToggleGroup extends HTMLElement {
175
256
  this._innerEl.append(...this._buttons);
176
257
  this.replaceChildren(this._innerEl);
177
258
 
259
+ // Observe live `enabled` changes on the authored <adw-toggle> elements.
260
+ // Upstream's `adw_toggle_set_enabled` is a live setter (:1663); the port
261
+ // snapshots at connect, so a later `toggle.setAttribute('enabled', 'false')`
262
+ // had no effect. The `AdwToggle` element fires `toggle-enabled-changed`
263
+ // from its attributeChangedCallback; we update `_enabled` and re-render.
264
+ for (let i = 0; i < this._toggles.length; i++) {
265
+ this._toggles[i].addEventListener('toggle-enabled-changed', (event: Event) => {
266
+ const { enabled } = (event as CustomEvent<{ enabled: boolean }>).detail;
267
+ if (this._enabled[i] !== enabled) {
268
+ this._enabled[i] = enabled;
269
+ this._render();
270
+ }
271
+ });
272
+ }
273
+
178
274
  // Hand the segments to the headless state machine (it needs the count to
179
275
  // bound the selection), then seed the active index from the attribute.
180
276
  this._state.setLabels(
@@ -188,16 +284,13 @@ export class AdwToggleGroup extends HTMLElement {
188
284
  this._applyActiveName();
189
285
  this._render();
190
286
 
191
- // No `disabled`/`hidden` filter, because no `<adw-toggle>` attribute can produce
192
- // either — upstream's per-toggle `enabled` (adw-toggle-group.c:871) has no web
193
- // counterpart yet, and a filter for a state this element cannot reach would be
194
- // untestable. `AdwToggle.observedAttributes` is pinned in
195
- // `keyboard-operable.spec.ts` so the day it grows, this decision has to be
196
- // revisited instead of silently becoming a focus trap.
287
+ // No `hidden` filter, because no `<adw-toggle>` attribute can produce one — and now
288
+ // there IS a `disabled` one, so the filter `roving-focus.ts` asks of every caller is
289
+ // here. `status/open-todos/adwaita-web.md` made that the price of `enabled`.
197
290
  attachRovingFocus({
198
291
  host: this,
199
292
  orientation: 'horizontal',
200
- items: () => this._buttons,
293
+ items: () => this._buttons.filter((btn) => !btn.disabled),
201
294
  // Same path a click takes, so an arrow key cannot drift from a press.
202
295
  select: (item) => this._selectIndex(this._buttons.findIndex((btn) => btn === item)),
203
296
  });
@@ -214,7 +307,7 @@ export class AdwToggleGroup extends HTMLElement {
214
307
  this._applyActiveName();
215
308
  return;
216
309
  }
217
- // flat / round are styling-only.
310
+ // `sensitive`, flat and round: styling and per-button state, both `_render`.
218
311
  this._render();
219
312
  }
220
313
 
@@ -238,6 +331,10 @@ export class AdwToggleGroup extends HTMLElement {
238
331
  }
239
332
 
240
333
  private _selectIndex(index: number): void {
334
+ // `set_active_toggle` refuses a toggle that is not enabled (:720), so an insensitive
335
+ // one can never become the active one — the check is the core state machine's guard
336
+ // plus this one, in C's order.
337
+ if (!this._enabled[index]) return;
241
338
  // The core state machine guards the no-op/out-of-range cases and notifies
242
339
  // the subscriber (which re-renders) only on a real change.
243
340
  if (!this._state.setSelected(index)) return;
@@ -251,14 +348,41 @@ export class AdwToggleGroup extends HTMLElement {
251
348
  this.classList.toggle('flat', this.hasAttribute('flat'));
252
349
  this.classList.toggle('round', this.hasAttribute('round'));
253
350
  const active = this._state.selected;
351
+ const sensitive = this.sensitive;
352
+ // The group node's own `:disabled` rule (_toggle-group.scss:16) needs the UA's
353
+ // `:disabled`, which a custom element never is — `_expander.scss` records why, and
354
+ // writes the rule against the attribute for the same reason.
355
+ this.toggleAttribute('disabled', !sensitive);
254
356
  this._buttons.forEach((btn, index) => {
255
357
  const isActive = index === active;
256
358
  btn.classList.toggle('active', isActive);
257
359
  btn.setAttribute(this._stateAttr, String(isActive));
360
+ // `GtkWidget:sensitive` on the GROUP reaches every child in GTK, because
361
+ // `gtk_widget_is_sensitive` ANDs the parent chain; a `<button disabled>` is the
362
+ // browser's half of that, and it is also what takes the toggle out of the tab
363
+ // order and out of the roving walk.
364
+ btn.disabled = !sensitive || !this._enabled[index];
258
365
  // The roving tabindex: Tab enters on the ACTIVE toggle, the way
259
366
  // `adw_toggle_group_grab_focus` grabs it, and leaves the group from there.
260
367
  btn.tabIndex = isActive ? 0 : -1;
261
368
  });
369
+ // An insensitive toggle can never BE the active one, so an active-but-disabled toggle
370
+ // — `active="1"` authored next to `<adw-toggle enabled="false">` — would be a
371
+ // checked radio nothing can reach. Upstream cannot express the pair at all
372
+ // (`set_active_toggle` clears the selection instead, :720), so the selection moves
373
+ // to the first enabled toggle, which is the one Tab then enters on.
374
+ if (!this._enabled[active]) this._activateFirstEnabled();
375
+ }
376
+
377
+ /** Select the first enabled toggle, if there is one — the C's "no active" repair. */
378
+ private _activateFirstEnabled(): void {
379
+ const first = this._enabled.findIndex((enabled) => enabled);
380
+ if (first === -1) return;
381
+ this._state.setSelected(first);
382
+ this.setAttribute('active', String(first));
383
+ // The state change came from _render, not user interaction, but the active
384
+ // index changed — emit notify::active so consumers stay in sync.
385
+ this.dispatchEvent(new CustomEvent('notify::active', { bubbles: true, detail: { active: first } }));
262
386
  }
263
387
  }
264
388
 
@@ -140,6 +140,17 @@ export class AdwViewStack extends HTMLElement {
140
140
  // `hidden` is the DOM spelling of AdwViewStackPage:visible, which
141
141
  // gates the auto-pick and refuses selection.
142
142
  visible: !pageEl.hasAttribute('hidden'),
143
+ // The five a bound switcher reads. Each was reachable only from the
144
+ // imperative API before, which left `AdwViewSwitcherSidebar`'s grouping
145
+ // (`starts-section`, `section-title`) and its badge dots unreachable
146
+ // from markup at all — the stack page is where they live.
147
+ badgeNumber: pageEl.hasAttribute('badge-number')
148
+ ? Number.parseInt(pageEl.getAttribute('badge-number') ?? '0', 10)
149
+ : 0,
150
+ needsAttention: pageEl.hasAttribute('needs-attention'),
151
+ useUnderline: pageEl.hasAttribute('use-underline'),
152
+ startsSection: pageEl.hasAttribute('starts-section'),
153
+ sectionTitle: pageEl.getAttribute('section-title'),
143
154
  });
144
155
  this.replaceChild(element, pageEl);
145
156
  }
@@ -150,6 +161,13 @@ export class AdwViewStack extends HTMLElement {
150
161
  if (initialName !== null) this._state.setVisibleName(initialName, false);
151
162
  this._applyVisibility();
152
163
  this._reflectName();
164
+ // Adopting the declared pages IS an items-changed, and a bound switcher needs to
165
+ // hear it: it connects while this element is still un-upgraded (custom elements
166
+ // upgrade in document order, and a `<adw-view-switcher-sidebar>` beside a stack
167
+ // connects FIRST), so it read an empty page list. The `notify::visible-child`
168
+ // the auto-pick emits covers the first page alone — a stack of two left every
169
+ // bound switcher showing one row.
170
+ this._emitItemsChanged();
153
171
  }
154
172
 
155
173
  attributeChangedCallback(name: string, _old: string | null, value: string | null) {