@gjsify/adwaita-web 0.64.1 → 0.64.2-next.254

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 (335) hide show
  1. package/README.md +22 -88
  2. package/dist/adwaita-web.css +91 -12
  3. package/dist/adwaita-web.css.map +1 -1
  4. package/lib/types/accessible.d.ts +8 -0
  5. package/lib/types/application.d.ts +1 -1
  6. package/lib/types/child-slot.spec.d.ts +1 -0
  7. package/lib/types/compute-expand.d.ts +5 -0
  8. package/lib/types/compute-expand.spec.d.ts +1 -0
  9. package/lib/types/container-fill.spec.d.ts +1 -0
  10. package/lib/types/elements/adw-about-dialog.d.ts +28 -1
  11. package/lib/types/elements/adw-action-row.d.ts +2 -1
  12. package/lib/types/elements/adw-alert-dialog.d.ts +80 -19
  13. package/lib/types/elements/adw-avatar.d.ts +2 -1
  14. package/lib/types/elements/adw-banner.d.ts +2 -1
  15. package/lib/types/elements/adw-bin.d.ts +2 -1
  16. package/lib/types/elements/adw-bottom-sheet.d.ts +5 -4
  17. package/lib/types/elements/adw-breakpoint-bin.d.ts +2 -1
  18. package/lib/types/elements/adw-button-content.d.ts +2 -1
  19. package/lib/types/elements/adw-button-row.d.ts +2 -1
  20. package/lib/types/elements/adw-card.d.ts +2 -1
  21. package/lib/types/elements/adw-carousel.d.ts +20 -3
  22. package/lib/types/elements/adw-clamp-scrollable.d.ts +2 -1
  23. package/lib/types/elements/adw-clamp.d.ts +2 -1
  24. package/lib/types/elements/adw-combo-row.d.ts +6 -1
  25. package/lib/types/elements/adw-data-grid.d.ts +2 -1
  26. package/lib/types/elements/adw-dialog.d.ts +2 -1
  27. package/lib/types/elements/adw-entry-row.d.ts +2 -1
  28. package/lib/types/elements/adw-expander-row.d.ts +2 -1
  29. package/lib/types/elements/adw-header-bar.d.ts +2 -1
  30. package/lib/types/elements/adw-inline-view-switcher.d.ts +3 -2
  31. package/lib/types/elements/adw-layout-slot.d.ts +2 -1
  32. package/lib/types/elements/adw-multi-layout-view.d.ts +2 -1
  33. package/lib/types/elements/adw-navigation-split-view.d.ts +2 -1
  34. package/lib/types/elements/adw-navigation-view.d.ts +3 -2
  35. package/lib/types/elements/adw-overlay-split-view.d.ts +2 -1
  36. package/lib/types/elements/adw-preferences-dialog.d.ts +5 -4
  37. package/lib/types/elements/adw-preferences-group.d.ts +2 -1
  38. package/lib/types/elements/adw-preferences-row.d.ts +2 -1
  39. package/lib/types/elements/adw-shortcut-label.d.ts +2 -1
  40. package/lib/types/elements/adw-shortcuts-item.d.ts +2 -1
  41. package/lib/types/elements/adw-shortcuts-section.d.ts +2 -1
  42. package/lib/types/elements/adw-sidebar.d.ts +4 -3
  43. package/lib/types/elements/adw-spin-row.d.ts +2 -1
  44. package/lib/types/elements/adw-spinner.d.ts +2 -1
  45. package/lib/types/elements/adw-split-button.d.ts +2 -1
  46. package/lib/types/elements/adw-status-page.d.ts +2 -1
  47. package/lib/types/elements/adw-switch-row.d.ts +4 -1
  48. package/lib/types/elements/adw-tab-bar.d.ts +2 -1
  49. package/lib/types/elements/adw-tab-button.d.ts +2 -1
  50. package/lib/types/elements/adw-tab-overview.d.ts +2 -1
  51. package/lib/types/elements/adw-tab-view.d.ts +3 -2
  52. package/lib/types/elements/adw-toast-overlay.d.ts +10 -30
  53. package/lib/types/elements/adw-toggle-group.d.ts +3 -2
  54. package/lib/types/elements/adw-toolbar-view.d.ts +2 -1
  55. package/lib/types/elements/adw-view-stack.d.ts +3 -1
  56. package/lib/types/elements/adw-view-switcher-bar.d.ts +2 -1
  57. package/lib/types/elements/adw-view-switcher-sidebar.d.ts +2 -1
  58. package/lib/types/elements/adw-view-switcher.d.ts +3 -2
  59. package/lib/types/elements/adw-window-features.d.ts +8 -0
  60. package/lib/types/elements/adw-window-title.d.ts +2 -1
  61. package/lib/types/elements/adw-wrap-box.d.ts +2 -1
  62. package/lib/types/elements/checks.d.ts +16 -1
  63. package/lib/types/elements/gtk-action-bar.d.ts +2 -1
  64. package/lib/types/elements/gtk-application-window.d.ts +1 -4
  65. package/lib/types/elements/gtk-aspect-frame.d.ts +2 -1
  66. package/lib/types/elements/gtk-box.d.ts +5 -1
  67. package/lib/types/elements/gtk-button.d.ts +5 -7
  68. package/lib/types/elements/gtk-calendar.d.ts +2 -1
  69. package/lib/types/elements/gtk-center-box.d.ts +2 -1
  70. package/lib/types/elements/gtk-color-dialog-button.d.ts +2 -1
  71. package/lib/types/elements/gtk-drag-icon.d.ts +2 -1
  72. package/lib/types/elements/gtk-drawing-area.d.ts +2 -1
  73. package/lib/types/elements/gtk-drop-down.d.ts +2 -1
  74. package/lib/types/elements/gtk-editable-label.d.ts +2 -1
  75. package/lib/types/elements/gtk-emoji-chooser.d.ts +2 -0
  76. package/lib/types/elements/gtk-entry.d.ts +2 -1
  77. package/lib/types/elements/gtk-expander.d.ts +2 -1
  78. package/lib/types/elements/gtk-fixed.d.ts +2 -1
  79. package/lib/types/elements/gtk-flow-box-child.d.ts +2 -1
  80. package/lib/types/elements/gtk-flow-box.d.ts +2 -1
  81. package/lib/types/elements/gtk-font-dialog-button.d.ts +2 -1
  82. package/lib/types/elements/gtk-frame.d.ts +2 -1
  83. package/lib/types/elements/gtk-gl-area.d.ts +2 -1
  84. package/lib/types/elements/gtk-graphics-offload.d.ts +2 -1
  85. package/lib/types/elements/gtk-grid.d.ts +2 -1
  86. package/lib/types/elements/gtk-header-bar.d.ts +2 -1
  87. package/lib/types/elements/gtk-image.d.ts +5 -6
  88. package/lib/types/elements/gtk-inscription.d.ts +2 -1
  89. package/lib/types/elements/gtk-label.d.ts +10 -3
  90. package/lib/types/elements/gtk-level-bar.d.ts +2 -1
  91. package/lib/types/elements/gtk-list-box-row.d.ts +2 -1
  92. package/lib/types/elements/gtk-list-box.d.ts +2 -1
  93. package/lib/types/elements/gtk-list-view.d.ts +2 -1
  94. package/lib/types/elements/gtk-media-controls.d.ts +2 -1
  95. package/lib/types/elements/gtk-menu-button.d.ts +2 -1
  96. package/lib/types/elements/gtk-notebook.d.ts +2 -1
  97. package/lib/types/elements/gtk-overlay.d.ts +2 -1
  98. package/lib/types/elements/gtk-paned.d.ts +2 -1
  99. package/lib/types/elements/gtk-picture.d.ts +2 -1
  100. package/lib/types/elements/gtk-popover-bin.d.ts +2 -1
  101. package/lib/types/elements/gtk-popover-menu-bar.d.ts +2 -1
  102. package/lib/types/elements/gtk-popover-menu.d.ts +2 -0
  103. package/lib/types/elements/gtk-popover.d.ts +7 -1
  104. package/lib/types/elements/gtk-progress-bar.d.ts +2 -1
  105. package/lib/types/elements/gtk-revealer.d.ts +2 -1
  106. package/lib/types/elements/gtk-scale-button.d.ts +2 -1
  107. package/lib/types/elements/gtk-scale.d.ts +2 -1
  108. package/lib/types/elements/gtk-scrollbar.d.ts +2 -1
  109. package/lib/types/elements/gtk-scrolled-window.d.ts +2 -1
  110. package/lib/types/elements/gtk-search-bar.d.ts +2 -1
  111. package/lib/types/elements/gtk-separator.d.ts +2 -1
  112. package/lib/types/elements/gtk-spin-button.d.ts +2 -1
  113. package/lib/types/elements/gtk-spinner.d.ts +2 -1
  114. package/lib/types/elements/gtk-stack-page.d.ts +29 -0
  115. package/lib/types/elements/gtk-stack-sidebar.d.ts +2 -1
  116. package/lib/types/elements/gtk-stack-switcher.d.ts +2 -1
  117. package/lib/types/elements/gtk-stack.d.ts +13 -1
  118. package/lib/types/elements/gtk-switch.d.ts +2 -1
  119. package/lib/types/elements/gtk-text-view.d.ts +2 -1
  120. package/lib/types/elements/gtk-text.d.ts +2 -1
  121. package/lib/types/elements/gtk-tree-expander.d.ts +2 -1
  122. package/lib/types/elements/gtk-video.d.ts +2 -1
  123. package/lib/types/elements/gtk-viewport.d.ts +2 -1
  124. package/lib/types/elements/gtk-window-controls.d.ts +2 -1
  125. package/lib/types/elements/gtk-window-handle.d.ts +2 -1
  126. package/lib/types/elements/gtk-window.d.ts +18 -2
  127. package/lib/types/gobject-elements.d.ts +15 -0
  128. package/lib/types/gtksource/gtk-source-view.d.ts +2 -1
  129. package/lib/types/{icon-registry.spec.d.ts → icon-masks.spec.d.ts} +1 -1
  130. package/lib/types/icon-theme.d.ts +15 -35
  131. package/lib/types/index.d.ts +3 -4
  132. package/lib/types/learn6502-window.spec.d.ts +1 -0
  133. package/lib/types/namespace/adw.d.ts +1 -1
  134. package/lib/types/namespace/gdk.d.ts +1 -0
  135. package/lib/types/namespace/gio.d.ts +1 -0
  136. package/lib/types/namespace/glib.d.ts +2 -1
  137. package/lib/types/namespace/gtk.d.ts +2 -0
  138. package/lib/types/shared-tree-builder.d.ts +31 -0
  139. package/lib/types/signals.d.ts +5 -1
  140. package/lib/types/source-view/adw-source-view.d.ts +2 -1
  141. package/lib/types/styles.generated.d.ts +1 -1
  142. package/lib/types/widget-element.d.ts +25 -0
  143. package/lib/types/widget-map.spec.d.ts +1 -0
  144. package/lib/types/widget-mapping.d.ts +7 -0
  145. package/lib/types/widget-visible.spec.d.ts +1 -0
  146. package/lib/types/window-maximize.spec.d.ts +1 -0
  147. package/package.json +13 -12
  148. package/scss/_about_dialog.scss +46 -1
  149. package/scss/_bin.scss +6 -3
  150. package/scss/_checks.scss +5 -2
  151. package/scss/_icon.scss +3 -4
  152. package/scss/_labels.scss +2 -2
  153. package/scss/_overlay.scss +11 -1
  154. package/scss/_overlay_split_view.scss +10 -0
  155. package/scss/_reset.scss +1 -1
  156. package/scss/_scrolled_window.scss +15 -0
  157. package/scss/_stack.scss +8 -2
  158. package/scss/_toast.scss +13 -3
  159. package/scss/_widget.scss +5 -1
  160. package/scss/_window.scss +16 -0
  161. package/src/accessible.ts +29 -0
  162. package/src/adw-about-dialog.spec.ts +81 -12
  163. package/src/adw-action-rows.spec.ts +2 -2
  164. package/src/adw-alert-dialog.spec.ts +71 -5
  165. package/src/adw-bin.spec.ts +4 -3
  166. package/src/adw-button-content.spec.ts +1 -1
  167. package/src/adw-carousel.spec.ts +49 -1
  168. package/src/adw-header-bar.spec.ts +18 -0
  169. package/src/adw-toast-overlay.spec.ts +68 -24
  170. package/src/application.spec.ts +44 -0
  171. package/src/application.ts +13 -18
  172. package/src/capabilities.mjs +2 -3
  173. package/src/checks.spec.ts +51 -1
  174. package/src/child-slot.spec.ts +71 -0
  175. package/src/compute-expand.spec.ts +186 -0
  176. package/src/compute-expand.ts +134 -0
  177. package/src/construct-vectors.spec.ts +97 -7
  178. package/src/container-fill.spec.ts +70 -0
  179. package/src/elements/adw-about-dialog.ts +152 -9
  180. package/src/elements/adw-action-row.ts +2 -1
  181. package/src/elements/adw-alert-dialog.ts +177 -46
  182. package/src/elements/adw-application-window.ts +0 -3
  183. package/src/elements/adw-avatar.ts +2 -1
  184. package/src/elements/adw-banner.ts +2 -1
  185. package/src/elements/adw-bin.ts +2 -1
  186. package/src/elements/adw-bottom-sheet.ts +5 -4
  187. package/src/elements/adw-breakpoint-bin.ts +5 -1
  188. package/src/elements/adw-button-content.ts +2 -1
  189. package/src/elements/adw-button-row.ts +2 -1
  190. package/src/elements/adw-card.ts +2 -1
  191. package/src/elements/adw-carousel.ts +62 -3
  192. package/src/elements/adw-clamp-scrollable.ts +2 -1
  193. package/src/elements/adw-clamp.ts +2 -1
  194. package/src/elements/adw-combo-row.ts +15 -1
  195. package/src/elements/adw-data-grid.ts +2 -1
  196. package/src/elements/adw-dialog.ts +5 -2
  197. package/src/elements/adw-entry-row.ts +2 -1
  198. package/src/elements/adw-expander-row.ts +2 -1
  199. package/src/elements/adw-header-bar.ts +6 -1
  200. package/src/elements/adw-inline-view-switcher.ts +3 -2
  201. package/src/elements/adw-layout-slot.ts +2 -1
  202. package/src/elements/adw-multi-layout-view.ts +2 -1
  203. package/src/elements/adw-navigation-split-view.ts +2 -1
  204. package/src/elements/adw-navigation-view.ts +3 -2
  205. package/src/elements/adw-overlay-split-view.ts +2 -1
  206. package/src/elements/adw-preferences-dialog.ts +6 -4
  207. package/src/elements/adw-preferences-group.ts +2 -1
  208. package/src/elements/adw-preferences-row.ts +2 -1
  209. package/src/elements/adw-shortcut-label.ts +2 -1
  210. package/src/elements/adw-shortcuts-item.ts +2 -1
  211. package/src/elements/adw-shortcuts-section.ts +2 -1
  212. package/src/elements/adw-sidebar.ts +4 -3
  213. package/src/elements/adw-spin-row.ts +2 -1
  214. package/src/elements/adw-spinner.ts +2 -1
  215. package/src/elements/adw-split-button.ts +2 -1
  216. package/src/elements/adw-status-page.ts +2 -1
  217. package/src/elements/adw-switch-row.ts +10 -1
  218. package/src/elements/adw-tab-bar.ts +2 -1
  219. package/src/elements/adw-tab-button.ts +2 -1
  220. package/src/elements/adw-tab-overview.ts +2 -1
  221. package/src/elements/adw-tab-view.ts +3 -2
  222. package/src/elements/adw-toast-overlay.ts +37 -70
  223. package/src/elements/adw-toggle-group.ts +3 -2
  224. package/src/elements/adw-toolbar-view.ts +2 -1
  225. package/src/elements/adw-view-stack.ts +39 -1
  226. package/src/elements/adw-view-switcher-bar.ts +2 -1
  227. package/src/elements/adw-view-switcher-sidebar.ts +2 -1
  228. package/src/elements/adw-view-switcher.ts +3 -2
  229. package/src/elements/adw-window-features.ts +14 -2
  230. package/src/elements/adw-window-title.ts +2 -1
  231. package/src/elements/adw-wrap-box.ts +2 -1
  232. package/src/elements/checks.ts +85 -6
  233. package/src/elements/gtk-action-bar.ts +2 -1
  234. package/src/elements/gtk-application-window.ts +3 -8
  235. package/src/elements/gtk-aspect-frame.ts +2 -1
  236. package/src/elements/gtk-box.ts +56 -1
  237. package/src/elements/gtk-button.ts +10 -22
  238. package/src/elements/gtk-calendar.ts +2 -1
  239. package/src/elements/gtk-center-box.ts +2 -1
  240. package/src/elements/gtk-color-dialog-button.ts +2 -1
  241. package/src/elements/gtk-drag-icon.ts +6 -1
  242. package/src/elements/gtk-drawing-area.ts +2 -1
  243. package/src/elements/gtk-drop-down.ts +2 -1
  244. package/src/elements/gtk-editable-label.ts +2 -1
  245. package/src/elements/gtk-emoji-chooser.ts +5 -0
  246. package/src/elements/gtk-entry.ts +2 -1
  247. package/src/elements/gtk-expander.ts +2 -1
  248. package/src/elements/gtk-fixed.ts +2 -1
  249. package/src/elements/gtk-flow-box-child.ts +5 -2
  250. package/src/elements/gtk-flow-box.ts +2 -1
  251. package/src/elements/gtk-font-dialog-button.ts +2 -1
  252. package/src/elements/gtk-frame.ts +2 -1
  253. package/src/elements/gtk-gl-area.ts +2 -1
  254. package/src/elements/gtk-graphics-offload.ts +5 -2
  255. package/src/elements/gtk-grid.ts +2 -1
  256. package/src/elements/gtk-header-bar.ts +2 -1
  257. package/src/elements/gtk-image.ts +14 -15
  258. package/src/elements/gtk-inscription.ts +2 -1
  259. package/src/elements/gtk-label.ts +12 -5
  260. package/src/elements/gtk-level-bar.ts +2 -1
  261. package/src/elements/gtk-list-box-row.ts +5 -2
  262. package/src/elements/gtk-list-box.ts +2 -1
  263. package/src/elements/gtk-list-view.ts +2 -1
  264. package/src/elements/gtk-media-controls.ts +2 -1
  265. package/src/elements/gtk-menu-button.ts +2 -1
  266. package/src/elements/gtk-notebook.ts +2 -1
  267. package/src/elements/gtk-overlay.ts +7 -5
  268. package/src/elements/gtk-paned.ts +9 -2
  269. package/src/elements/gtk-picture.ts +2 -1
  270. package/src/elements/gtk-popover-bin.ts +5 -1
  271. package/src/elements/gtk-popover-menu-bar.ts +2 -1
  272. package/src/elements/gtk-popover-menu.ts +5 -0
  273. package/src/elements/gtk-popover.ts +14 -1
  274. package/src/elements/gtk-progress-bar.ts +2 -1
  275. package/src/elements/gtk-revealer.ts +2 -1
  276. package/src/elements/gtk-scale-button.ts +2 -1
  277. package/src/elements/gtk-scale.ts +2 -1
  278. package/src/elements/gtk-scrollbar.ts +2 -1
  279. package/src/elements/gtk-scrolled-window.ts +8 -5
  280. package/src/elements/gtk-search-bar.ts +7 -6
  281. package/src/elements/gtk-separator.ts +2 -1
  282. package/src/elements/gtk-spin-button.ts +2 -1
  283. package/src/elements/gtk-spinner.ts +2 -1
  284. package/src/elements/gtk-stack-page.ts +112 -0
  285. package/src/elements/gtk-stack-sidebar.ts +2 -1
  286. package/src/elements/gtk-stack-switcher.ts +2 -1
  287. package/src/elements/gtk-stack.ts +52 -6
  288. package/src/elements/gtk-switch.ts +2 -1
  289. package/src/elements/gtk-text-view.ts +2 -1
  290. package/src/elements/gtk-text.ts +2 -1
  291. package/src/elements/gtk-tree-expander.ts +5 -1
  292. package/src/elements/gtk-video.ts +2 -1
  293. package/src/elements/gtk-viewport.ts +6 -1
  294. package/src/elements/gtk-window-controls.ts +2 -1
  295. package/src/elements/gtk-window-handle.ts +6 -1
  296. package/src/elements/gtk-window.ts +57 -7
  297. package/src/gio.spec.ts +13 -3
  298. package/src/glib.spec.ts +9 -0
  299. package/src/gobject-elements.ts +44 -2
  300. package/src/gtk-label.spec.ts +39 -0
  301. package/src/gtk-scrolled-window.spec.ts +6 -6
  302. package/src/gtk-stack.spec.ts +170 -0
  303. package/src/gtk-value-doors.spec.ts +19 -0
  304. package/src/gtk-window.spec.ts +2 -2
  305. package/src/gtksource/gtk-source-view.ts +2 -1
  306. package/src/{icon-registry.spec.ts → icon-masks.spec.ts} +4 -100
  307. package/src/icon-theme.spec.ts +69 -124
  308. package/src/icon-theme.ts +29 -119
  309. package/src/index.ts +5 -9
  310. package/src/keyboard-operable.spec.ts +3 -3
  311. package/src/learn6502-window.spec.ts +113 -0
  312. package/src/namespace/adw.ts +1 -1
  313. package/src/namespace/gdk.ts +1 -0
  314. package/src/namespace/gio.ts +8 -0
  315. package/src/namespace/glib.ts +4 -0
  316. package/src/namespace/gtk.ts +2 -0
  317. package/src/shared-tree-builder.ts +131 -13
  318. package/src/shared-trees.spec.ts +15 -1
  319. package/src/signals.ts +11 -2
  320. package/src/slotted-children.spec.ts +24 -0
  321. package/src/slotted-children.ts +18 -2
  322. package/src/source-view/adw-source-view.ts +2 -1
  323. package/src/split-button.spec.ts +1 -1
  324. package/src/style-manager.spec.ts +13 -0
  325. package/src/style-manager.ts +6 -0
  326. package/src/styles.generated.ts +1 -1
  327. package/src/test.browser.mts +16 -2
  328. package/src/value-lists.spec.ts +3 -3
  329. package/src/widget-element.ts +75 -0
  330. package/src/widget-map.spec.ts +116 -0
  331. package/src/widget-mapping.ts +100 -0
  332. package/src/widget-visible.spec.ts +148 -0
  333. package/src/window-maximize.spec.ts +93 -0
  334. package/lib/types/icon-registry.d.ts +0 -37
  335. package/src/icon-registry.ts +0 -163
@@ -19,15 +19,35 @@
19
19
  // Children are not moved or wrapped: the element IS the flex container, so a child in the
20
20
  // light DOM is a child of the layout, which is what `gtk_box_append` means.
21
21
  //
22
+ // EXPAND IS THE COMPUTED VALUE, not the attribute: GtkBoxLayout grows a child when
23
+ // `gtk_widget_compute_expand` says so (gtkboxlayout.c:391), and that is true for a bin whose
24
+ // descendant set `hexpand` too. `compute-expand.ts` computes it; the box writes it on each
25
+ // child that authored no value of its own as `data-computed-hexpand` / `-vexpand`, which
26
+ // `_widget.scss` grows like the attribute. A MutationObserver over the box's subtree is the
27
+ // substitute for `gtk_widget_queue_compute_expand`, which walks up from any widget whose
28
+ // expand or visibility changed — so a runtime reparent or a toggled `hexpand` deep inside a
29
+ // child lands one microtask later.
30
+ //
22
31
  // Reference: refs/gtk/gtk/gtkbox.c (the three properties, the `box` CSS name)
23
32
  // Copyright (c) The GTK Team. LGPLv2.1+.
24
33
 
25
34
  import { normalizeBoxOrientation, normalizeBoxSpacing, type BoxOrientation } from '@gjsify/adwaita-core';
35
+ import { WidgetElement } from '../widget-element.js';
36
+
37
+ import { computeExpand, explicitExpand, type ExpandOrientation } from '../compute-expand.js';
26
38
 
27
39
  /** The attributes that carry a property — also the `notify::` roster. */
28
40
  const PROPERTY_ATTRIBUTES = ['orientation', 'spacing', 'homogeneous'] as const;
29
41
 
30
- export class GtkBox extends HTMLElement {
42
+ /** The marker per axis a child carries while its computed expand is true. */
43
+ const COMPUTED_EXPAND: Record<ExpandOrientation, string> = {
44
+ horizontal: 'data-computed-hexpand',
45
+ vertical: 'data-computed-vexpand',
46
+ };
47
+
48
+ export class GtkBox extends WidgetElement {
49
+ private _expandObserver: MutationObserver | null = null;
50
+
31
51
  static get observedAttributes() {
32
52
  return [...PROPERTY_ATTRIBUTES];
33
53
  }
@@ -61,6 +81,22 @@ export class GtkBox extends HTMLElement {
61
81
 
62
82
  connectedCallback() {
63
83
  this._sync();
84
+ this._syncComputedExpand();
85
+ if (this._expandObserver) return;
86
+ this._expandObserver = new MutationObserver((records) => {
87
+ if (records.some(affectsExpand)) this._syncComputedExpand();
88
+ });
89
+ this._expandObserver.observe(this, {
90
+ childList: true,
91
+ subtree: true,
92
+ attributes: true,
93
+ attributeFilter: ['hexpand', 'vexpand', 'hidden'],
94
+ });
95
+ }
96
+
97
+ disconnectedCallback() {
98
+ this._expandObserver?.disconnect();
99
+ this._expandObserver = null;
64
100
  }
65
101
 
66
102
  attributeChangedCallback(name: string, old: string | null, value: string | null) {
@@ -82,6 +118,25 @@ export class GtkBox extends HTMLElement {
82
118
  this.style.flexDirection = this.orientation === 'vertical' ? 'column' : 'row';
83
119
  this.style.gap = `${this.spacing}px`;
84
120
  }
121
+
122
+ private _syncComputedExpand(): void {
123
+ for (const child of this.children) {
124
+ for (const orientation of ['horizontal', 'vertical'] as const) {
125
+ const grows = explicitExpand(child, orientation) === undefined && computeExpand(child, orientation);
126
+ child.toggleAttribute(COMPUTED_EXPAND[orientation], grows);
127
+ }
128
+ }
129
+ }
130
+ }
131
+
132
+ /**
133
+ * Text rewritten inside a label (a hex dump does it every frame) adds and removes only text
134
+ * nodes; no widget came or went, so the computed expand cannot have changed.
135
+ */
136
+ function affectsExpand(record: MutationRecord): boolean {
137
+ if (record.type !== 'childList') return true;
138
+ const isElement = (node: Node): boolean => node.nodeType === Node.ELEMENT_NODE;
139
+ return [...record.addedNodes].some(isElement) || [...record.removedNodes].some(isElement);
85
140
  }
86
141
 
87
142
  customElements.define('gtk-box', GtkBox);
@@ -16,14 +16,16 @@
16
16
 
17
17
  import { buttonStyleClasses } from '@gjsify/adwaita-core';
18
18
 
19
+ import { FORWARDED_ARIA, forwardAccessibleName } from '../accessible.js';
19
20
  import { bindSlottedChildren } from '../slotted-children.js';
20
21
  import type { DispatchedSignals } from '../signals.js';
21
22
  import { createGtkImage } from './gtk-image.js';
23
+ import { TooltipElement } from '../widget-element.js';
22
24
 
23
25
  /** The boolean attributes that select a style class; the mapping lives in the core. */
24
26
  const STYLE_ATTRIBUTES = ['flat', 'suggested', 'destructive', 'circular', 'pill'] as const;
25
27
 
26
- export class GtkButton extends HTMLElement {
28
+ export class GtkButton extends TooltipElement {
27
29
  /** The GTK signals this element dispatches, each with the DOM event it arrives as (ADR 0093). */
28
30
  static readonly signals: DispatchedSignals = { clicked: 'click' };
29
31
 
@@ -47,12 +49,14 @@ export class GtkButton extends HTMLElement {
47
49
  'circular',
48
50
  'pill',
49
51
  'class',
52
+ ...FORWARDED_ARIA,
50
53
  ];
51
54
  }
52
55
 
53
56
  /**
54
- * `Gtk.Button:icon-name` and `Gtk.Widget:tooltip-text`, the GObject spellings: a class that
55
- * holds a button as a template child writes `button.icon_name = …`, which must reach the DOM.
57
+ * `Gtk.Button:icon-name`, the GObject spelling: a class that holds a button as a template
58
+ * child writes `button.icon_name = …`, which must reach the DOM. `Gtk.Widget:tooltip-text`
59
+ * comes from `TooltipElement`.
56
60
  */
57
61
  get icon_name(): string | null {
58
62
  return this.getAttribute('icon-name');
@@ -66,18 +70,6 @@ export class GtkButton extends HTMLElement {
66
70
  set iconName(value: string | null) {
67
71
  this.icon_name = value;
68
72
  }
69
- get tooltip_text(): string | null {
70
- return this.getAttribute('tooltip-text');
71
- }
72
- set tooltip_text(value: string | null) {
73
- this.reflect('tooltip-text', value);
74
- }
75
- get tooltipText(): string | null {
76
- return this.tooltip_text;
77
- }
78
- set tooltipText(value: string | null) {
79
- this.tooltip_text = value;
80
- }
81
73
 
82
74
  private reflect(attribute: string, value: string | null): void {
83
75
  if (value === null || value === undefined) this.removeAttribute(attribute);
@@ -148,13 +140,9 @@ export class GtkButton extends HTMLElement {
148
140
  const tooltip = this.getAttribute('tooltip') ?? this.getAttribute('tooltip-text');
149
141
  btn.title = tooltip ?? '';
150
142
  // An icon-only button has no text content, so screen readers would
151
- // announce it as unlabeled. Give it an accessible name — prefer the
152
- // tooltip, fall back to the symbolic icon name (WCAG 4.1.2).
153
- if (icon && !label) {
154
- btn.setAttribute('aria-label', tooltip ?? icon);
155
- } else {
156
- btn.removeAttribute('aria-label');
157
- }
143
+ // announce it as unlabeled. Give it an accessible name — the one the tree
144
+ // wrote first, then the tooltip, then the symbolic icon name (WCAG 4.1.2).
145
+ if (!forwardAccessibleName(this, btn) && icon && !label) btn.setAttribute('aria-label', tooltip ?? icon);
158
146
  btn.disabled = this.hasAttribute('disabled');
159
147
  this.decorate(btn);
160
148
  }
@@ -68,6 +68,7 @@ import {
68
68
  } from '@gjsify/adwaita-core';
69
69
 
70
70
  import { createGtkImage } from './gtk-image.js';
71
+ import { WidgetElement } from '../widget-element.js';
71
72
 
72
73
  /** The seven abbreviated day names, Sunday first — `default_abbreviated_dayname` (:745-757). */
73
74
  const DAY_NAMES = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];
@@ -99,7 +100,7 @@ const ARROWS: readonly { step: AdwCalendarStep; icon: string; tooltip: string }[
99
100
  /** The arrow a cell's disabled state keys off — `calendar_update_navigation_buttons` (:1055-1084). */
100
101
  type ArrowName = 'previousMonth' | 'nextMonth' | 'previousYear' | 'nextYear';
101
102
 
102
- export class GtkCalendar extends HTMLElement {
103
+ export class GtkCalendar extends WidgetElement {
103
104
  private _headerEl!: HTMLDivElement;
104
105
  private _monthEl!: HTMLSpanElement;
105
106
  private _yearEl!: HTMLSpanElement;
@@ -41,6 +41,7 @@
41
41
  import { labelYalignAlignItems } from '@gjsify/adwaita-core';
42
42
 
43
43
  import { bindSlottedChildren } from '../slotted-children.js';
44
+ import { WidgetElement } from '../widget-element.js';
44
45
 
45
46
  /** `Gtk.BaselinePosition`'s three nicks, in the order GTK measures them (gtkcenterbox.c:267-271). */
46
47
  const BASELINE_POSITIONS = { top: 0, center: 0.5, bottom: 1 } as const;
@@ -51,7 +52,7 @@ export type BaselinePosition = keyof typeof BASELINE_POSITIONS;
51
52
  const SHRINK_FIRST = 100;
52
53
  const SHRINK_LAST = 1;
53
54
 
54
- export class GtkCenterBox extends HTMLElement {
55
+ export class GtkCenterBox extends WidgetElement {
55
56
  static get observedAttributes() {
56
57
  return ['baseline-position', 'shrink-center-last'];
57
58
  }
@@ -37,6 +37,7 @@
37
37
  // Reference: refs/libadwaita/src/stylesheet/widgets/_linked.scss:6 (`colorbutton > button`)
38
38
  // Copyright (c) GNOME contributors (libadwaita). LGPLv2.1+.
39
39
  // Modifications: Implemented as a Web Component for @gjsify/adwaita-web.
40
+ import { WidgetElement } from '../widget-element.js';
40
41
 
41
42
  /** A `GdkRGBA` — the four channels of `GtkColorDialogButton:rgba`, each 0…1. */
42
43
  export interface GdkRgbaValue {
@@ -62,7 +63,7 @@ export interface ColorDialogParameters {
62
63
  /** `gtk_color_dialog_button_init`'s own colour: `{ 0.75, 0.25, 0.25, 1.0 }` (:170). */
63
64
  const INITIAL_RGBA: GdkRgbaValue = { red: 0.75, green: 0.25, blue: 0.25, alpha: 1 };
64
65
 
65
- export class GtkColorDialogButton extends HTMLElement {
66
+ export class GtkColorDialogButton extends WidgetElement {
66
67
  private _buttonEl!: HTMLButtonElement;
67
68
  private _swatchEl!: HTMLSpanElement;
68
69
  private _inputEl!: HTMLInputElement;
@@ -53,6 +53,9 @@
53
53
  // Copyright (c) GNOME contributors (libadwaita). LGPLv2.1+.
54
54
  // Modifications: Implemented as a Web Component for @gjsify/adwaita-web.
55
55
 
56
+ import { bindSlottedChildren } from '../slotted-children.js';
57
+ import { WidgetElement } from '../widget-element.js';
58
+
56
59
  /** The `rgba()` string a `GdkRGBA` value paints, as the colour swatch shows it. */
57
60
  interface Rgba {
58
61
  readonly red: number;
@@ -64,7 +67,7 @@ interface Rgba {
64
67
  /** One icon per drag operation, keyed on the `dataTransfer` a browser gives per drag. */
65
68
  const ICON_BY_DRAG = new WeakMap<DataTransfer, GtkDragIcon>();
66
69
 
67
- export class GtkDragIcon extends HTMLElement {
70
+ export class GtkDragIcon extends WidgetElement {
68
71
  private _pointerX = 0;
69
72
  private _pointerY = 0;
70
73
  private _dragging = false;
@@ -166,6 +169,8 @@ export class GtkDragIcon extends HTMLElement {
166
169
  // `gtk_widget_set_can_target (self, FALSE)` (:386-390), in CSS: the icon is pointed
167
170
  // at, and takes no pointer event of any kind.
168
171
  this.style.pointerEvents = 'none';
172
+ // The NAME only, for the reason `adw-bin.ts` gives: the child already IS the content.
173
+ bindSlottedChildren(this, [{ name: 'child', into: this }]);
169
174
  if (this._dragging) this._observe();
170
175
  }
171
176
 
@@ -53,6 +53,7 @@
53
53
  // Modifications: Implemented as a Web Component for @gjsify/adwaita-web.
54
54
 
55
55
  import { glibClamp } from '@gjsify/adwaita-core';
56
+ import { WidgetElement } from '../widget-element.js';
56
57
 
57
58
  /**
58
59
  * `GtkDrawingAreaDrawFunc` with the `user_data` / `destroy` pair dropped — see the header.
@@ -78,7 +79,7 @@ function intAttribute(element: HTMLElement, name: string): number {
78
79
  return Number.isFinite(raw) ? raw : 0;
79
80
  }
80
81
 
81
- export class GtkDrawingArea extends HTMLElement {
82
+ export class GtkDrawingArea extends WidgetElement {
82
83
  private _canvas!: HTMLCanvasElement;
83
84
  private _context: CanvasRenderingContext2D | null = null;
84
85
  private _initialized = false;
@@ -75,6 +75,7 @@ import type { DispatchedSignals } from '../signals.js';
75
75
  import { stringListSlot } from '../string-list-slot.js';
76
76
 
77
77
  import { createGtkImage } from './gtk-image.js';
78
+ import { WidgetElement } from '../widget-element.js';
78
79
 
79
80
  /**
80
81
  * A dropdown option — `value` is the stable id, `label` the shown text. An alias of
@@ -83,7 +84,7 @@ import { createGtkImage } from './gtk-image.js';
83
84
  */
84
85
  export type GtkDropDownOption = AdwComboOption;
85
86
 
86
- export class GtkDropDown extends HTMLElement {
87
+ export class GtkDropDown extends WidgetElement {
87
88
  /** The GTK signals this element dispatches, each with the DOM event it arrives as (ADR 0093). */
88
89
  static readonly signals: DispatchedSignals = {
89
90
  'notify::selected': 'notify::selected',
@@ -38,11 +38,12 @@
38
38
  // (`label {}`, `editablelabel > stack > text`)
39
39
  // Copyright (c) The GTK Team, GNOME contributors. LGPLv2.1+.
40
40
  // Modifications: Implemented as a Web Component for @gjsify/adwaita-web.
41
+ import { WidgetElement } from '../widget-element.js';
41
42
 
42
43
  /** The C's grace period between a focus leaving the widget and the commit it triggers. */
43
44
  const FOCUS_OUT_GRACE_MS = 100;
44
45
 
45
- export class GtkEditableLabel extends HTMLElement {
46
+ export class GtkEditableLabel extends WidgetElement {
46
47
  private _label!: HTMLSpanElement;
47
48
  private _entry!: HTMLInputElement;
48
49
  private _initialized = false;
@@ -103,6 +103,11 @@ export class GtkEmojiChooser extends GtkPopover {
103
103
  */
104
104
  private _ctrl = false;
105
105
 
106
+ /** The chooser's template is the child (gtkemojichooser.ui). */
107
+ protected override takesChild(): boolean {
108
+ return false;
109
+ }
110
+
106
111
  connectedCallback(): void {
107
112
  super.connectedCallback();
108
113
  if (this._built) return;
@@ -23,8 +23,9 @@
23
23
  import { ENTRY_ROW_MAX_LENGTH_LIMIT, clampEntryText, entryTextLength } from '@gjsify/adwaita-core';
24
24
 
25
25
  import type { DispatchedSignals } from '../signals.js';
26
+ import { WidgetElement } from '../widget-element.js';
26
27
 
27
- export class GtkEntry extends HTMLElement {
28
+ export class GtkEntry extends WidgetElement {
28
29
  /**
29
30
  * `protected`, not `private`: `GtkPasswordEntry` and `GtkSearchEntry` subclass this
30
31
  * element and restyle or wrap the very input it builds (the password field's Caps Lock
@@ -78,6 +78,7 @@ import { attachRowActivation } from './row-activation.js';
78
78
  // elided by TypeScript and take the `customElements.define` with it.
79
79
  import './gtk-label.js';
80
80
  import type { GtkLabel } from './gtk-label.js';
81
+ import { WidgetElement } from '../widget-element.js';
81
82
 
82
83
  /** `expander { -gtk-icon-source: -gtk-icontheme('pan-end-symbolic') }` (_expanders.scss). */
83
84
  const ARROW_ICON = 'pan-end';
@@ -85,7 +86,7 @@ const ARROW_ICON = 'pan-end';
85
86
  /** Stable ids for the `aria-controls` relation, which GTK sets on the child itself. */
86
87
  let labelChildCounter = 0;
87
88
 
88
- export class GtkExpander extends HTMLElement {
89
+ export class GtkExpander extends WidgetElement {
89
90
  private _box!: HTMLDivElement;
90
91
  private _titleEl!: HTMLDivElement;
91
92
  private _arrowEl!: HTMLElement;
@@ -32,8 +32,9 @@
32
32
  // Reference: refs/gtk/gtk/gtkfixedlayout.c:224-300
33
33
  // Copyright (c) The GTK Team. LGPLv2.1+.
34
34
  // Modifications: Implemented as a Web Component for @gjsify/adwaita-web.
35
+ import { WidgetElement } from '../widget-element.js';
35
36
 
36
- export class GtkFixed extends HTMLElement {
37
+ export class GtkFixed extends WidgetElement {
37
38
  private _resize: ResizeObserver | null = null;
38
39
  private _mutations: MutationObserver | null = null;
39
40
 
@@ -26,8 +26,9 @@
26
26
  // Modifications: Implemented as a Web Component for @gjsify/adwaita-web.
27
27
 
28
28
  import { bindSlottedChildren } from '../slotted-children.js';
29
+ import { WidgetElement } from '../widget-element.js';
29
30
 
30
- export class GtkFlowBoxChild extends HTMLElement {
31
+ export class GtkFlowBoxChild extends WidgetElement {
31
32
  private _contentsEl!: HTMLDivElement;
32
33
  private _initialized = false;
33
34
 
@@ -38,7 +39,9 @@ export class GtkFlowBoxChild extends HTMLElement {
38
39
  this._contentsEl = document.createElement('div');
39
40
  this._contentsEl.className = 'adw-flow-box-child-contents';
40
41
 
41
- bindSlottedChildren(this, [{ into: this._contentsEl }]).install(this._contentsEl);
42
+ bindSlottedChildren(this, [{ name: 'child', into: this._contentsEl }, { into: this._contentsEl }]).install(
43
+ this._contentsEl,
44
+ );
42
45
 
43
46
  this.setAttribute('role', 'gridcell');
44
47
  // `gtk_flow_box_child_init` makes the cell focusable (:578-580) — the box's cursor
@@ -66,6 +66,7 @@ import { attachRovingFocus } from './roving-focus.js';
66
66
  // `gtk-list-box.ts` states at its own: a combined import would be elided and take the
67
67
  // registration with it.
68
68
  import './gtk-flow-box-child.js';
69
+ import { WidgetElement } from '../widget-element.js';
69
70
 
70
71
  /** `GtkFlowBox:max-children-per-line`'s default — `DEFAULT_MAX_CHILDREN_PER_LINE` (:728). */
71
72
  export const ADW_FLOW_BOX_MAX_CHILDREN_PER_LINE = 7;
@@ -73,7 +74,7 @@ export const ADW_FLOW_BOX_MAX_CHILDREN_PER_LINE = 7;
73
74
  /** `GtkFlowBox:orientation` — HORIZONTAL by default here, unlike a `GtkListBase` (:3981). */
74
75
  export type AdwFlowBoxOrientation = 'horizontal' | 'vertical';
75
76
 
76
- export class GtkFlowBox extends HTMLElement {
77
+ export class GtkFlowBox extends WidgetElement {
77
78
  private _children: GtkFlowBoxChild[] = [];
78
79
  private _selection: number[] = [];
79
80
  /** `priv->selected_child`, `-1` for the C's NULL. */
@@ -71,6 +71,7 @@ import './gtk-popover.js';
71
71
  import type { GtkPopover } from './gtk-popover.js';
72
72
 
73
73
  import './gtk-separator.js';
74
+ import { WidgetElement } from '../widget-element.js';
74
75
 
75
76
  /** `GtkFontLevel`'s four values, under the nicks a string property carries. */
76
77
  export type FontLevel = 'family' | 'face' | 'font' | 'features';
@@ -103,7 +104,7 @@ const FACE_GRID: readonly { weight: number; slant: PangoFontDescription['slant']
103
104
  { weight: 700, slant: 'italic' },
104
105
  ];
105
106
 
106
- export class GtkFontDialogButton extends HTMLElement {
107
+ export class GtkFontDialogButton extends WidgetElement {
107
108
  private _buttonEl!: HTMLButtonElement;
108
109
  private _labelEl!: HTMLSpanElement;
109
110
  private _sizeBoxEl!: HTMLSpanElement;
@@ -32,6 +32,7 @@
32
32
  import { glibClamp, labelYalignAlignItems } from '@gjsify/adwaita-core';
33
33
 
34
34
  import { bindSlottedChildren } from '../slotted-children.js';
35
+ import { WidgetElement } from '../widget-element.js';
35
36
 
36
37
  /** `Gtk.Frame:label-xalign`'s pspec default (gtkframe.c:180-183, and `:253`). */
37
38
  const LABEL_XALIGN_DEFAULT = 0;
@@ -42,7 +43,7 @@ function normalizeLabelXalign(value: string | null): number {
42
43
  return Number.isFinite(parsed) ? glibClamp(parsed, 0, 1) : LABEL_XALIGN_DEFAULT;
43
44
  }
44
45
 
45
- export class GtkFrame extends HTMLElement {
46
+ export class GtkFrame extends WidgetElement {
46
47
  private _mutations: MutationObserver | null = null;
47
48
 
48
49
  static get observedAttributes() {
@@ -58,6 +58,7 @@
58
58
  // Reference: refs/gtk/gtk/gtkglarea.c
59
59
  // Copyright (c) The GTK Team. LGPLv2.1+.
60
60
  // Modifications: Implemented as a Web Component for @gjsify/adwaita-web.
61
+ import { WidgetElement } from '../widget-element.js';
61
62
 
62
63
  /** `GdkGLAPI`'s nicks, as `GdkGLAPINickSet` spells them. */
63
64
  const APIS = ['gl', 'gles'] as const;
@@ -85,7 +86,7 @@ function booleanAttribute(element: HTMLElement, name: string, fallback: boolean)
85
86
  return raw !== 'false' && raw !== '0';
86
87
  }
87
88
 
88
- export class GtkGLArea extends HTMLElement {
89
+ export class GtkGLArea extends WidgetElement {
89
90
  private _canvas!: HTMLCanvasElement;
90
91
  private _messageEl: HTMLDivElement | null = null;
91
92
  private _initialized = false;
@@ -42,6 +42,7 @@
42
42
  // Modifications: Implemented as a Web Component for @gjsify/adwaita-web.
43
43
 
44
44
  import { bindSlottedChildren } from '../slotted-children.js';
45
+ import { WidgetElement } from '../widget-element.js';
45
46
 
46
47
  /** `GtkGraphicsOffloadEnabled`, spelled as the GIR's enum nicks. */
47
48
  type OffloadEnabled = 'enabled' | 'disabled';
@@ -52,7 +53,7 @@ function booleanAttribute(element: HTMLElement, name: string, fallback: boolean)
52
53
  return raw !== 'false' && raw !== '0';
53
54
  }
54
55
 
55
- export class GtkGraphicsOffload extends HTMLElement {
56
+ export class GtkGraphicsOffload extends WidgetElement {
56
57
  private _childEl!: HTMLDivElement;
57
58
  private _initialized = false;
58
59
 
@@ -98,7 +99,9 @@ export class GtkGraphicsOffload extends HTMLElement {
98
99
  this._childEl.className = 'adw-graphics-offload-child';
99
100
  // `GTK_TYPE_BIN_LAYOUT` gives the child the whole allocation, and `child` is the one
100
101
  // GtkBuildable slot the widget has, so it is the default one here.
101
- bindSlottedChildren(this, [{ into: this._childEl }]).install(this._childEl);
102
+ bindSlottedChildren(this, [{ name: 'child', into: this._childEl }, { into: this._childEl }]).install(
103
+ this._childEl,
104
+ );
102
105
  this.replaceChildren(this._childEl);
103
106
  this._render();
104
107
  }
@@ -38,8 +38,9 @@
38
38
  // Modifications: Implemented as a Web Component for @gjsify/adwaita-web.
39
39
 
40
40
  import { normalizeBoxOrientation, normalizeBoxSpacing, type BoxOrientation } from '@gjsify/adwaita-core';
41
+ import { WidgetElement } from '../widget-element.js';
41
42
 
42
- export class GtkGrid extends HTMLElement {
43
+ export class GtkGrid extends WidgetElement {
43
44
  static get observedAttributes() {
44
45
  return ['column-spacing', 'row-spacing', 'column-homogeneous', 'row-homogeneous', 'orientation'];
45
46
  }
@@ -64,8 +64,9 @@ import { bindSlottedChildren } from '../slotted-children.js';
64
64
  // Registers <gtk-window-controls>: `show-title-buttons` builds two of them, so importing
65
65
  // the bar alone must still define them.
66
66
  import './gtk-window-controls.js';
67
+ import { WidgetElement } from '../widget-element.js';
67
68
 
68
- export class GtkHeaderBar extends HTMLElement {
69
+ export class GtkHeaderBar extends WidgetElement {
69
70
  private _initialized = false;
70
71
  private _handle!: HTMLDivElement;
71
72
  private _box!: HTMLDivElement;
@@ -1,15 +1,15 @@
1
1
  // <gtk-image> — the icon node as an element. A symbolic icon is a CSS-masked box whose
2
2
  // glyph comes from a generated `.adw-icon--<name>` class and whose colour is
3
- // `currentColor`, so it themes with whatever contains it. A full-colour icon registered
4
- // through `registerColorIcon` is the same box with the image as its background and no
3
+ // `currentColor`, so it themes with whatever contains it. A full-colour icon from a
4
+ // `Gtk.IconTheme` resource path is the same box with the image as its background and no
5
5
  // mask. Which of the two a name reaches is decided once, in `../icon-theme.ts`, in the
6
6
  // order GTK's own theme tries them; the symbolic name derivation and its guard live once
7
7
  // in `@gjsify/adwaita-core`'s {@link normalizeIconName}, the markup once here.
8
8
  //
9
9
  // Attributes:
10
10
  // icon-name — icon name, `-symbolic` suffix optional. A name that is neither a
11
- // registered colour icon nor a single CSS token (a space, a quote, an
12
- // unregistered reverse-DNS application id) never reaches a class — it
11
+ // resource file nor a single CSS token (a space, a quote, a reverse-DNS
12
+ // application id no resource ships) never reaches a class — it
13
13
  // draws {@link MISSING_ICON_NAME}, which is what GTK draws for it, rather
14
14
  // than injecting markup.
15
15
  // size — rendered edge length in px. Absent leaves the stylesheet's 16px in
@@ -36,6 +36,7 @@
36
36
  import { normalizeIconName } from '@gjsify/adwaita-core';
37
37
 
38
38
  import { lookupIcon, onIconThemeChanged, type IconRequest } from '../icon-theme.js';
39
+ import { WidgetElement } from '../widget-element.js';
39
40
 
40
41
  /** `url` as one CSS string token, whatever quotes or backslashes it holds. */
41
42
  function cssUrl(url: string): string {
@@ -43,9 +44,7 @@ function cssUrl(url: string): string {
43
44
  }
44
45
 
45
46
  /**
46
- * The generated mask-class prefix — the one place the `--` spelling appears. `icon-registry`
47
- * builds the same class for a runtime registration and imports it from here rather than
48
- * spelling it twice.
47
+ * The generated mask-class prefix — the one place the `--` spelling appears.
49
48
  */
50
49
  export const MASK_CLASS_PREFIX = 'adw-icon--';
51
50
 
@@ -63,7 +62,7 @@ export const MISSING_ICON_NAME = 'image-missing';
63
62
  */
64
63
  export const COLOR_ICON_CLASS = 'adw-icon-color';
65
64
 
66
- export class GtkImage extends HTMLElement {
65
+ export class GtkImage extends WidgetElement {
67
66
  static get observedAttributes() {
68
67
  return ['icon-name', 'size'];
69
68
  }
@@ -80,8 +79,8 @@ export class GtkImage extends HTMLElement {
80
79
 
81
80
  /**
82
81
  * The name the SYMBOLIC lookup works with — `''` when the icon-name is absent, empty,
83
- * or not usable as one CSS token. A registered colour icon can still draw for a name
84
- * that answers `''` here (`org.gnome.Builder`); whether a name draws anything but
82
+ * or not usable as one CSS token. A resource file can still draw for a name that
83
+ * answers `''` here (`org.gnome.Builder`); whether a name draws anything but
85
84
  * `image-missing` is `isIconAvailable`'s question.
86
85
  *
87
86
  * `''` does NOT mean the box draws nothing: an unusable name that was given still
@@ -152,13 +151,13 @@ export class GtkImage extends HTMLElement {
152
151
  const looked = lookupIcon(this.getAttribute('icon-name'), this._request());
153
152
  // A resource file the browser cannot draw (XPM, compressed) is GTK's `image-missing`.
154
153
  const found = looked?.kind === 'resource' && looked.url === null ? ({ kind: 'missing' } as const) : looked;
155
- const asIs = found?.kind === 'color' || (found?.kind === 'resource' && !found.symbolic) ? found.url : null;
154
+ const asIs = found?.kind === 'resource' && !found.symbolic ? found.url : null;
156
155
  const mask = found?.kind === 'resource' && found.symbolic ? found.url : null;
157
156
  this.classList.toggle(COLOR_ICON_CLASS, asIs !== null);
158
157
  if (asIs !== null) {
159
158
  // Drawn as-is: `_icon.scss` drops the mask and the `currentColor` fill for this
160
- // modifier, so only the image paints. `url` is a data-URI, a blob or a resolved href;
161
- // the quote and backslash escapes keep it one CSS string either way.
159
+ // modifier, so only the image paints. `url` is a blob URL; the quote and backslash
160
+ // escapes keep it one CSS string.
162
161
  this.style.backgroundImage = cssUrl(asIs);
163
162
  } else {
164
163
  this.style.removeProperty('background-image');
@@ -177,8 +176,8 @@ export class GtkImage extends HTMLElement {
177
176
  if (found?.kind === 'symbolic') {
178
177
  this.classList.add(`${MASK_CLASS_PREFIX}${found.name}`);
179
178
  } else if (found?.kind === 'missing') {
180
- // A name was GIVEN and nothing answers it — not a colour icon, and not one CSS
181
- // token (a space, a quote, an unregistered reverse-DNS application id). GTK has
179
+ // A name was GIVEN and nothing answers it — no resource file, and not one CSS
180
+ // token (a space, a quote, a reverse-DNS application id no resource ships). GTK has
182
181
  // no such state: `gtk_icon_theme_lookup_icon` never returns NULL, it returns the
183
182
  // always-available `image-missing` (refs/gtk/gtk/gtkicontheme.c —
184
183
  // `gtk_icon_paintable_get_icon_name`'s own docs say so). So the same glyph is
@@ -95,6 +95,7 @@ import {
95
95
  labelYalignAlignItems,
96
96
  type LabelWrapMode,
97
97
  } from '@gjsify/adwaita-core';
98
+ import { WidgetElement } from '../widget-element.js';
98
99
 
99
100
  /** `GtkInscriptionOverflow`, in enum order (gtkinscription.h:44-48). */
100
101
  export const INSCRIPTION_OVERFLOW_MODES = ['clip', 'ellipsize-start', 'ellipsize-middle', 'ellipsize-end'] as const;
@@ -150,7 +151,7 @@ function normalizeCount(value: unknown): number {
150
151
  return Math.max(0, Math.trunc(parsed));
151
152
  }
152
153
 
153
- export class GtkInscription extends HTMLElement {
154
+ export class GtkInscription extends WidgetElement {
154
155
  private _initialized = false;
155
156
 
156
157
  static get observedAttributes() {
@@ -78,6 +78,7 @@ import {
78
78
  } from '@gjsify/adwaita-core';
79
79
 
80
80
  import { JUSTIFY_TEXT_ALIGN } from './justification.js';
81
+ import { WidgetElement } from '../widget-element.js';
81
82
 
82
83
  /** The attributes that carry a property — also the `notify::` roster. */
83
84
  const PROPERTY_ATTRIBUTES = [
@@ -96,7 +97,7 @@ const PROPERTY_ATTRIBUTES = [
96
97
  'selectable',
97
98
  ] as const;
98
99
 
99
- export class GtkLabel extends HTMLElement {
100
+ export class GtkLabel extends WidgetElement {
100
101
  /**
101
102
  * The rendered text's own box — present while {@link wrap} is set (so it can be pinned
102
103
  * to its measured wrap width, see `_remeasure`) OR while {@link ellipsize} is not
@@ -291,9 +292,9 @@ export class GtkLabel extends HTMLElement {
291
292
 
292
293
  private _remeasure(): void {
293
294
  if (!this._wrapSpan || !this.isConnected) return;
294
- this._wrapSpan.style.width = '';
295
+ this._wrapSpan.style.maxWidth = '';
295
296
  const width = measuredWrapWidth(this._wrapSpan);
296
- this._wrapSpan.style.width = width !== null ? `${width}px` : '';
297
+ this._wrapSpan.style.maxWidth = width !== null ? `min(100%, ${width}px)` : '';
297
298
  }
298
299
 
299
300
  attributeChangedCallback(name: string, old: string | null, value: string | null) {
@@ -393,9 +394,15 @@ export class GtkLabel extends HTMLElement {
393
394
  * here, not the narrower width GTK's Pango layout actually wrapped to. So this measures
394
395
  * instead, in two passes: first let {@link _wrapSpan} wrap at the FULL container width
395
396
  * (`width: ''`, the same collapse above, which is exactly the width GTK's own
396
- * allocation wraps against), then pin the span to its widest resulting line via
397
+ * allocation wraps against), then cap the span at its widest resulting line via
397
398
  * `Range.getClientRects()`, which gives the pseudo spacers real free space to split.
398
- * Approximate on purpose, and cheap: one synchronous reflow per render. The pinned
399
+ * A CAP, `max-width`, and never `width`: a pinned `width` is also the span's
400
+ * min-content, so the label could no longer shrink below the width it first wrapped
401
+ * at, and a card holding it in a narrower pane grew past the pane and was clipped.
402
+ * GtkLabel's wrapping minimum is its widest word (`gtk_label_measure`), which a capped
403
+ * flex item keeps as its min-content; the cap itself only resolves against a definite
404
+ * container, so the label's max-content stays its text on one line, GTK's natural.
405
+ * Approximate on purpose, and cheap: one synchronous reflow per render. The measured
399
406
  * width goes stale whenever the available width or the font changes, and a page does
400
407
  * both (a rotated phone, an opened sidebar, a web font arriving late), so
401
408
  * {@link connectedCallback} re-measures on each resize and once the fonts have loaded.