@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
@@ -10,8 +10,8 @@
10
10
  // held to one table (`@gjsify/adwaita-core/conformance`).
11
11
  //
12
12
  // Attributes: title, text, editable, max-length, show-apply-button,
13
- // activates-default. `text-length` is REFLECTED (read-only, mirrors
14
- // `Adw.EntryRow:text-length`).
13
+ // activates-default, tooltip-text (`Gtk.Widget:tooltip-text`). `text-length` is
14
+ // REFLECTED (read-only, mirrors `Adw.EntryRow:text-length`).
15
15
  // Properties: text, editable, maxLength, textLength, showApplyButton,
16
16
  // activatesDefault, editing.
17
17
  // Events:
@@ -37,6 +37,8 @@ import {
37
37
  type EntryRowRenderState,
38
38
  } from '@gjsify/adwaita-core';
39
39
 
40
+ import { booleanAttribute } from '../attributes.js';
41
+ import { applyRowTooltip } from '../row-tooltip.js';
40
42
  import { bindSlottedChildren, type AdwSlottedChildren } from '../slotted-children.js';
41
43
  import { type GtkImage, createGtkImage } from './gtk-image.js';
42
44
 
@@ -51,11 +53,6 @@ function setPartVisible(part: HTMLElement, visible: boolean): void {
51
53
  part.style.display = visible ? '' : 'none';
52
54
  }
53
55
 
54
- /** Read a boolean attribute the HTML way, with an explicit `="false"` opt-out. */
55
- function boolAttribute(value: string | null): boolean {
56
- return value !== null && value !== 'false';
57
- }
58
-
59
56
  export class AdwEntryRow extends HTMLElement {
60
57
  /** The headless `update_empty` derivation + apply latch (ADR 0004). */
61
58
  protected readonly _state = new EntryRowState();
@@ -81,7 +78,7 @@ export class AdwEntryRow extends HTMLElement {
81
78
  private _lastLength = 0;
82
79
 
83
80
  static get observedAttributes(): string[] {
84
- return ['title', 'text', 'editable', 'max-length', 'show-apply-button', 'activates-default'];
81
+ return ['title', 'text', 'editable', 'max-length', 'show-apply-button', 'activates-default', 'tooltip-text'];
85
82
  }
86
83
 
87
84
  /**
@@ -158,8 +155,8 @@ export class AdwEntryRow extends HTMLElement {
158
155
  // before the element was connected survives.
159
156
  this._state.setMaxLength(Number.parseInt(this.getAttribute('max-length') ?? '', 10));
160
157
  this._state.setEditable(this.getAttribute('editable') !== 'false');
161
- this._state.setShowApplyButton(boolAttribute(this.getAttribute('show-apply-button')));
162
- this._state.setActivatesDefault(boolAttribute(this.getAttribute('activates-default')));
158
+ this._state.setShowApplyButton(booleanAttribute(this.getAttribute('show-apply-button'), false));
159
+ this._state.setActivatesDefault(booleanAttribute(this.getAttribute('activates-default'), false));
163
160
  if (this.hasAttribute('text')) this._state.setText(this.getAttribute('text') ?? '');
164
161
  this._renderTitle();
165
162
 
@@ -181,6 +178,7 @@ export class AdwEntryRow extends HTMLElement {
181
178
  this._lastText = this._state.text;
182
179
  this._lastLength = this._state.textLength;
183
180
  this._render(this._state.state);
181
+ applyRowTooltip(this, this._tooltipParts());
184
182
  this._state.subscribe((state) => this._onStateChanged(state));
185
183
  }
186
184
 
@@ -200,14 +198,26 @@ export class AdwEntryRow extends HTMLElement {
200
198
  this._state.setMaxLength(Number.parseInt(value ?? '', 10));
201
199
  break;
202
200
  case 'show-apply-button':
203
- this._state.setShowApplyButton(boolAttribute(value));
201
+ this._state.setShowApplyButton(booleanAttribute(value, false));
204
202
  break;
205
203
  case 'activates-default':
206
- this._state.setActivatesDefault(boolAttribute(value));
204
+ this._state.setActivatesDefault(booleanAttribute(value, false));
205
+ break;
206
+ case 'tooltip-text':
207
+ applyRowTooltip(this, this._tooltipParts());
207
208
  break;
208
209
  }
209
210
  }
210
211
 
212
+ /**
213
+ * The parts `tooltip-text` lands on: the two slots and the editable area — NOT the
214
+ * apply button or the indicator, which carry tooltips of their own that the consumer
215
+ * reads for what they are.
216
+ */
217
+ private _tooltipParts(): readonly Element[] {
218
+ return [this._prefixes, this._area, this._suffixes];
219
+ }
220
+
211
221
  /**
212
222
  * Add a widget after the editable area — `adw_entry_row_add_suffix`, which APPENDS
213
223
  * into a box, so several suffixes coexist and the password row's own peek toggle
@@ -1,6 +1,12 @@
1
1
  // <adw-expander-row> — a boxed-list row that discloses nested rows when expanded,
2
2
  // with an optional enable switch. Mirrors Adw.ExpanderRow.
3
3
  //
4
+ // ATTRIBUTES: `title`, `subtitle`, `expanded`, `enable-expansion`, `show-enable-switch`,
5
+ // and `title-lines` / `subtitle-lines` — clamp either label to N lines, `0` = unlimited,
6
+ // the AdwActionRow pspec's sentinel (`@girs/adw-1`, min 0, default 0).
7
+ // `tooltip-text` (`Gtk.Widget:tooltip-text`) — on the HEADER row alone, which is the
8
+ // part that is the row libadwaita draws.
9
+ //
4
10
  // Slots: `slot="prefix"` / `slot="suffix"` children sit in the HEADER row beside the
5
11
  // title (before the enable switch and disclosure chevron), like Adw.ExpanderRow's
6
12
  // add_prefix/add_suffix; every other child is moved into the disclosed content
@@ -22,7 +28,9 @@
22
28
  import { ExpanderState, deriveRowLabels } from '@gjsify/adwaita-core';
23
29
 
24
30
  import { bindEmptySections } from '../empty-sections.js';
31
+ import { applyRowTooltip } from '../row-tooltip.js';
25
32
  import { bindSlottedChildren } from '../slotted-children.js';
33
+ import { applyRowLineClamp, parseRowLinesAttribute } from '../row-line-clamp.js';
26
34
 
27
35
  // SIDE-EFFECT import, deliberately separate from the type import below: it guarantees
28
36
  // `gtk-switch` is defined before this module's `customElements.define` can upgrade a
@@ -68,7 +76,16 @@ export class AdwExpanderRow extends HTMLElement {
68
76
  }
69
77
 
70
78
  static get observedAttributes() {
71
- return ['title', 'subtitle', 'expanded', 'enable-expansion', 'show-enable-switch'];
79
+ return [
80
+ 'title',
81
+ 'subtitle',
82
+ 'expanded',
83
+ 'enable-expansion',
84
+ 'show-enable-switch',
85
+ 'tooltip-text',
86
+ 'title-lines',
87
+ 'subtitle-lines',
88
+ ];
72
89
  }
73
90
 
74
91
  get expanded(): boolean {
@@ -224,6 +241,22 @@ export class AdwExpanderRow extends HTMLElement {
224
241
  // step with the flag; `aria-expanded` is the same statement to the same reader.
225
242
  this._headerEl.setAttribute('aria-expanded', String(this.expanded));
226
243
  this._contentEl.classList.toggle('expanded', this.expanded);
244
+ // The HEADER only, not the disclosure: libadwaita's tooltip belongs to the row, and
245
+ // the content box is where the disclosed rows live — a child row's own tooltip is
246
+ // what the browser should offer there.
247
+ applyRowTooltip(this, [this._headerEl]);
248
+ this._applyLineClamping();
249
+ }
250
+
251
+ /** Apply CSS line-clamping based on title-lines/subtitle-lines attributes. */
252
+ private _applyLineClamping(): void {
253
+ applyRowLineClamp({
254
+ titleEl: this._titleEl,
255
+ subtitleEl: this._subtitleEl,
256
+ textContainerEl: this._titleEl.parentElement!,
257
+ getTitleLines: () => parseRowLinesAttribute(this.getAttribute('title-lines')),
258
+ getSubtitleLines: () => parseRowLinesAttribute(this.getAttribute('subtitle-lines')),
259
+ });
227
260
  }
228
261
  }
229
262
 
@@ -53,6 +53,12 @@ export class AdwHeaderBar extends HTMLElement {
53
53
  * bare `Adw.HeaderBar {}` in a `.blp` page shows "Mailboxes" with no title of its own.
54
54
  */
55
55
  private _page: Element | null = null;
56
+ /**
57
+ * The window the bar sits in: `update_title`'s last stop before the application name
58
+ * (`gtk_window_get_title` of the root), so a bar with no title of its own, under no titled
59
+ * page, shows the window's.
60
+ */
61
+ private _window: Element | null = null;
56
62
  private _pageObserver: MutationObserver | null = null;
57
63
 
58
64
  static get observedAttributes() {
@@ -136,6 +142,7 @@ export class AdwHeaderBar extends HTMLElement {
136
142
  this._pageObserver?.disconnect();
137
143
  this._pageObserver = null;
138
144
  this._page = null;
145
+ this._window = null;
139
146
  }
140
147
 
141
148
  /**
@@ -146,9 +153,12 @@ export class AdwHeaderBar extends HTMLElement {
146
153
  */
147
154
  private _followPage() {
148
155
  this._page = this.closest('adw-navigation-page');
149
- if (this._page === null) return;
156
+ this._window = this.closest('adw-window, adw-application-window');
150
157
  this._pageObserver ??= new MutationObserver(() => this._renderTitle());
151
- this._pageObserver.observe(this._page, { attributes: true, attributeFilter: ['title'] });
158
+ for (const ancestor of [this._page, this._window]) {
159
+ if (ancestor !== null)
160
+ this._pageObserver.observe(ancestor, { attributes: true, attributeFilter: ['title'] });
161
+ }
152
162
  }
153
163
 
154
164
  /**
@@ -188,9 +198,13 @@ export class AdwHeaderBar extends HTMLElement {
188
198
  // keeps "unset" distinguishable from "set to empty" on the child.
189
199
  for (const name of ['title', 'subtitle']) {
190
200
  // The bar's own `title` is this port's declarative divergence (see the header) and
191
- // wins; without one, the page's title is the first answer `update_title` has.
201
+ // wins; without one, the page's title is the first answer `update_title` has, then
202
+ // the window's.
192
203
  const value =
193
- this.getAttribute(name) ?? (name === 'title' ? (this._page?.getAttribute('title') ?? null) : null);
204
+ this.getAttribute(name) ??
205
+ (name === 'title'
206
+ ? (this._page?.getAttribute('title') ?? this._window?.getAttribute('title') ?? null)
207
+ : null);
194
208
  if (value === null) this._titleEl.removeAttribute(name);
195
209
  else this._titleEl.setAttribute(name, value);
196
210
  }
@@ -0,0 +1,95 @@
1
+ // <adw-layout-slot> — one named hole inside a layout of an `Adw.MultiLayoutView`.
2
+ //
3
+ // `AdwLayoutSlot` is a bin with an ID and nothing else: it takes a child when the view
4
+ // inserts the child whose ID matches, and its `visible` property is bound to that
5
+ // child's so hiding the child hides the hole (:151). The ID is what pairs the two
6
+ // sides — `adw_multi_layout_view_set_child(id, widget)` finds the layout's slots by
7
+ // `g_hash_table_lookup (self->slots, id)` (:139) — and it is CONSTRUCT-ONLY
8
+ // (adw-layout-slot.c:145), so it is read once and never written.
9
+ //
10
+ // DUPLICATE IDs ACROSS LAYOUTS ARE THE WIDGET'S OWN MODEL, not a mistake here: the
11
+ // canonical example in the C documentation puts an `AdwLayoutSlot` with `id="primary"`
12
+ // in BOTH layouts of one view, because that is how a child follows a layout change. The
13
+ // element never resolves a slot by document lookup, only from the subtree of the layout
14
+ // it is currently mounting, so two of them with one ID are ordinary.
15
+ //
16
+ // Attributes:
17
+ // id (`AdwLayoutSlot:id` — the slot ID. Construct-only upstream, so changing it here
18
+ // after connect re-registers the slot and warns, as `g_error` does for a slot
19
+ // constructed without one (adw-layout-slot.c:68).)
20
+ //
21
+ // A11Y: `role="group"`, the accessible role libadwaita installs on the class
22
+ // (adw-layout-slot.c:131).
23
+ //
24
+ // There is no box of its own (`display: contents`, so the child takes the allocation the
25
+ // container would have given the slot) and libadwaita ships NO rule for this widget —
26
+ // `src/stylesheet/widgets/` has no `layout-slot` partial and no selector names the node,
27
+ // so there is nothing to port and nothing invented to replace it.
28
+ //
29
+ // Reference: refs/libadwaita/src/adw-layout-slot.c
30
+ // Copyright (c) 2023-2024 Purism SPC / GNOME Foundation Inc. (libadwaita). LGPLv2.1+.
31
+ // Modifications: Implemented as a Web Component for @gjsify/adwaita-web.
32
+
33
+ import { AdwMultiLayoutView } from './adw-multi-layout-view.js';
34
+
35
+ export class AdwLayoutSlot extends HTMLElement {
36
+ private _registered = false;
37
+
38
+ static get observedAttributes() {
39
+ return ['id'];
40
+ }
41
+
42
+ /** `adw_layout_slot_get_slot_id()` (:184), read under its property's name. */
43
+ get slotId(): string | null {
44
+ return this.getAttribute('id');
45
+ }
46
+
47
+ connectedCallback() {
48
+ this.setAttribute('role', 'group');
49
+ // `display: contents` inline rather than in a partial: libadwaita styles nothing
50
+ // here, and a host page that wants the slot to box its child sets one rule.
51
+ this.style.display = 'contents';
52
+ this._register();
53
+ }
54
+
55
+ disconnectedCallback() {
56
+ this._registered = false;
57
+ }
58
+
59
+ attributeChangedCallback(name?: string) {
60
+ if (!this.isConnected || name !== 'id') return;
61
+ if (this._registered) {
62
+ // `G_PARAM_CONSTRUCT_ONLY`: upstream cannot change a slot's ID either, and
63
+ // the bin's `slots` table is keyed by it — `register_slot` refuses a second
64
+ // entry under one ID (adw-multi-layout-view.c:693). Saying so beats
65
+ // silently leaving the view holding the old pairing.
66
+ console.warn('<adw-layout-slot>: `id` is construct-only upstream; re-registering the slot.');
67
+ }
68
+ this._register();
69
+ }
70
+
71
+ /**
72
+ * Hand this slot to the nearest `<adw-multi-layout-view>` ancestor.
73
+ *
74
+ * `adw_layout_slot_root` walks up for the view and calls
75
+ * `adw_multi_layout_view_register_slot` (adw-layout-slot.c:55). The view's own
76
+ * mount path is the authority — it registers only while it is building a layout —
77
+ * so a call arriving outside that window is refused there, exactly as
78
+ * `accepting_slots` refuses it upstream.
79
+ */
80
+ private _register(): void {
81
+ const id = this.slotId;
82
+ if (id === null || id === '') {
83
+ console.error('<adw-layout-slot> created without an `id` — libadwaita refuses this with g_error.');
84
+ return;
85
+ }
86
+ // `instanceof` rather than a cast on `closest(…)`: an ancestor that is present
87
+ // but not upgraded yet satisfies a cast and fails at the call, and this is on the
88
+ // connect path of every slot.
89
+ const view = this.closest('adw-multi-layout-view');
90
+ if (view instanceof AdwMultiLayoutView) view.registerSlot(id, this);
91
+ this._registered = true;
92
+ }
93
+ }
94
+
95
+ customElements.define('adw-layout-slot', AdwLayoutSlot);
@@ -0,0 +1,326 @@
1
+ // <adw-multi-layout-view> — one set of children, several arrangements of them.
2
+ //
3
+ // Each child has an ID, each layout has slots, each slot has an ID; switching layouts
4
+ // re-inserts every child into the slot of the SAME ID (adw-multi-layout-view.c:16-26).
5
+ // That is what lets a secondary pane be a sidebar in one layout and a bottom bar in
6
+ // another without the application moving anything: the children are declared once and
7
+ // the view decides where they sit.
8
+ //
9
+ // THE MARKUP FORM, because two of the three objects have no tag. `Adw.Layout` is a
10
+ // GObject (`G_DEFINE_TYPE… G_TYPE_OBJECT`, adw-layout.c:37), so it is not in a table of
11
+ // concrete widgets and has no element of its own; `Adw.Breakpoint`-style GObjects in this
12
+ // package became markup children, and so does this one:
13
+ //
14
+ // * a direct child carrying `name` is a LAYOUT, and that element is its content —
15
+ // `AdwLayout:content` is construct-only (adw-layout.c:144), so the layout IS the
16
+ // tree rather than a wrapper around one;
17
+ // * any other direct child is a CHILD, keyed by its `slot` attribute, which is the
18
+ // GtkBuilder `<child type="ID">` of adw-multi-layout-view.c:88;
19
+ // * an `<adw-layout-slot id="…">` inside a layout is where a child with that ID lands.
20
+ //
21
+ // Attributes:
22
+ // layout-name (`Adw.MultiLayoutView:layout-name` — the name of the layout in use.
23
+ // Setting a name no layout carries logs the C's `g_critical` text
24
+ // (adw-multi-layout-view.c:520) and leaves the current layout alone.)
25
+ //
26
+ // Methods:
27
+ // `getChild(id)` — `adw_multi_layout_view_get_child` (:635).
28
+ // `getLayoutByName(name)` — `adw_multi_layout_view_get_layout_by_name` (:605).
29
+ // `registerSlot(id, slot)` — `adw_multi_layout_view_register_slot` (:682), which every
30
+ // `<adw-layout-slot>` calls on itself once it is rooted.
31
+ //
32
+ // THERE IS NO `addLayout()`, because in this port the MARKUP is `add_layout()`: the
33
+ // declared child carrying `name` is the layout, and the first declared one is made
34
+ // current the way `adw_multi_layout_view_add_layout` makes it (:553). An imperative list
35
+ // beside a declarative one would be two sources for the same table, and the derived one
36
+ // would silently win.
37
+ //
38
+ // Events:
39
+ // `notify::layout` and `notify::layout-name` (CustomEvent, bubbles,
40
+ // `detail = { layout }` / `{ layoutName }`) on every change — `set_layout` notifies
41
+ // BOTH (:263), so switching layouts is two signals even when only the name moved.
42
+ //
43
+ // A11Y: `role="group"`, the accessible role libadwaita installs on the class (:386).
44
+ // `visible` is bound one way, child to slot (`G_BINDING_SYNC_CREATE` alone,
45
+ // adw-multi-layout-view.c:151), so hiding a child hides the hole and nothing more.
46
+ //
47
+ // NOT PORTED: the focus save/restore around a rebuild (`rebuild_current_layout`, :200)
48
+ // and the delayed-focus queue (`delayed_focus`, :159). Both are a GTK frame-clock
49
+ // concern — the whole widget is snapshotted into a render node, hidden, rewritten and
50
+ // shown on the next tick, which is what makes focus observable in between. A browser
51
+ // element moves nodes synchronously, so focus is never lost across a layout change; the
52
+ // consequence is that this port has nothing to restore.
53
+ //
54
+ // Reference: refs/libadwaita/src/adw-multi-layout-view.c
55
+ // Reference: refs/libadwaita/src/adw-layout.c
56
+ // Copyright (c) 2023-2024 Purism SPC / GNOME Foundation Inc. (libadwaita). LGPLv2.1+.
57
+ // Modifications: Implemented as a Web Component for @gjsify/adwaita-web.
58
+
59
+ import type { AdwLayoutSlot } from './adw-layout-slot.js';
60
+
61
+ /** One layout: the element itself, plus the name `AdwLayout:name` carries. */
62
+ interface Layout {
63
+ readonly name: string;
64
+ readonly content: Element;
65
+ }
66
+
67
+ export class AdwMultiLayoutView extends HTMLElement {
68
+ /** The C's own tables: layouts in order, children by id, and the current layout. */
69
+ private _layouts: Layout[] = [];
70
+ private _children = new Map<string, Element>();
71
+ /** `slots` — the current layout's holes, which are cleared on every rebuild. */
72
+ private _slots = new Map<string, AdwLayoutSlot>();
73
+ private _current: Layout | null = null;
74
+ /** `accepting_slots` — only TRUE while a layout is being mounted (:116, :690). */
75
+ private _acceptingSlots = false;
76
+ private _observer: MutationObserver | null = null;
77
+
78
+ static get observedAttributes() {
79
+ return ['layout-name'];
80
+ }
81
+
82
+ /** `adw_multi_layout_view_get_layout_name()` (:485), read under its property's name. */
83
+ get layoutName(): string | null {
84
+ return this._current?.name ?? null;
85
+ }
86
+
87
+ /**
88
+ * `adw_multi_layout_view_set_layout_name()` (:507) — writable, unlike `layout`.
89
+ *
90
+ * The property is written, not the layout: the C looks the name up and refuses a
91
+ * name no layout carries, and the lookup is what makes the ORDER of declaration
92
+ * irrelevant here.
93
+ */
94
+ set layoutName(value: string | null) {
95
+ if (value === null) return;
96
+ this.setAttribute('layout-name', value);
97
+ }
98
+
99
+ /** The element `Adw.MultiLayoutView:layout` points at, or null. */
100
+ get layout(): Element | null {
101
+ return this._current?.content ?? null;
102
+ }
103
+
104
+ connectedCallback() {
105
+ this.setAttribute('role', 'group');
106
+ // A GTK widget is a box and an unknown custom element is `inline`. libadwaita
107
+ // ships no rule for this widget — its CSS node is `multi-layout-view` and no
108
+ // partial names it — so the box model is set here rather than invented.
109
+ this.style.display = 'block';
110
+ this._observer?.disconnect();
111
+ // A layout or child appended after connect has to be picked up: the authored tree
112
+ // is the whole vocabulary of this widget, and a slot is read from the DOM.
113
+ this._observer = new MutationObserver(() => this._rebuild());
114
+ this._observer.observe(this, { childList: true });
115
+ this._rebuild();
116
+ }
117
+
118
+ disconnectedCallback() {
119
+ this._observer?.disconnect();
120
+ this._observer = null;
121
+ }
122
+
123
+ attributeChangedCallback(name?: string) {
124
+ if (!this.isConnected || name !== 'layout-name') return;
125
+ this._setLayoutByName(this.getAttribute('layout-name'));
126
+ }
127
+
128
+ /** `adw_multi_layout_view_get_child(id)` (:635). */
129
+ getChild(id: string): Element | null {
130
+ return this._children.get(id) ?? null;
131
+ }
132
+
133
+ /** `adw_multi_layout_view_get_layout_by_name(name)` (:605). */
134
+ getLayoutByName(name: string): Element | null {
135
+ return this._layouts.find((layout) => layout.name === name)?.content ?? null;
136
+ }
137
+
138
+ /**
139
+ * `adw_multi_layout_view_add_layout()` (:538), over the declared children.
140
+ *
141
+ * The rules it carries are the ones a reader of the markup would otherwise have to
142
+ * infer: the FIRST layout becomes current when the list is built (:553), and a
143
+ * duplicate name is a warning rather than a shadowed entry (:549).
144
+ */
145
+
146
+ /**
147
+ * `adw_multi_layout_view_register_slot()` (:682), called by every `<adw-layout-slot>`
148
+ * that becomes rooted.
149
+ *
150
+ * Refused outside a mount, which is what `accepting_slots` is for: a slot in a layout
151
+ * that is not current has no business in the table.
152
+ *
153
+ * A REPEAT registration by the SAME element is not a duplicate and says nothing. A DOM
154
+ * move fires `connectedCallback` again — and moving a slot is ordinary here, because
155
+ * the container it sits in re-homes its own slotted children when it builds its
156
+ * internals. `g_hash_table_insert` upstream would overwrite with the same pointer, so
157
+ * the C never notices; the warning is for two DIFFERENT slots under one ID, and
158
+ * reporting a re-registration would train a reader to ignore it (adw-multi-layout-view.c:693).
159
+ */
160
+ registerSlot(id: string, slot: AdwLayoutSlot): void {
161
+ if (!this._acceptingSlots) return;
162
+ if (this._slots.get(id) === slot) return;
163
+ if (this._slots.has(id)) {
164
+ console.warn(`Duplicate slot ID in AdwLayout ${this.layoutName}: ${id}`);
165
+ return;
166
+ }
167
+ this._slots.set(id, slot);
168
+ }
169
+
170
+ /**
171
+ * Read the authored tree and mount the layout it names.
172
+ *
173
+ * A direct child with `name` is a layout; anything else is a child, keyed by `slot`.
174
+ * Reading it from the DOM rather than from a list is what makes a child appended
175
+ * after connect work, which is the whole of `bindSlottedChildren`'s contract for the
176
+ * elements that use it.
177
+ */
178
+ private _rebuild(): void {
179
+ if (!this.isConnected) return;
180
+ // THE MOUNT IS A CHILD-LIST CHANGE OF THIS ELEMENT, and re-reading it is a loop:
181
+ // `_rebuild` → `_mount` → `replaceChildren` → a record → `_rebuild` → … The
182
+ // observer is therefore OFF for the duration, which drops those records and any
183
+ // the previous mount already queued, and re-armed below. Without this the widget
184
+ // spins a microtask cycle forever and takes the page with it — measured, and the
185
+ // measurement is why this is a comment rather than a boolean.
186
+ this._observer?.disconnect();
187
+ try {
188
+ this._readAuthoredTree();
189
+ } finally {
190
+ if (this.isConnected) this._observer?.observe(this, { childList: true });
191
+ }
192
+ }
193
+
194
+ /** The C's three tables, read off the declared children. */
195
+ private _readAuthoredTree(): void {
196
+ const layouts: Layout[] = [];
197
+ // ACCUMULATED, not replaced: while a layout is mounted the children this view has
198
+ // taken into its slots are no longer children of the HOST, so a fresh map would
199
+ // drop every one of them and the next mount would parent nothing. `set_child`
200
+ // upserts by id too (adw-multi-layout-view.c:675).
201
+ for (const node of Array.from(this.children)) {
202
+ const name = node.getAttribute('name');
203
+ if (name !== null) {
204
+ layouts.push({ name, content: node });
205
+ continue;
206
+ }
207
+ const id = node.getAttribute('slot');
208
+ // No `slot=` is the DEFAULT child, and GtkBuilder's `<child>` with no type
209
+ // is a deprecation warning upstream (adw-breakpoint-bin.c:679 is the same
210
+ // rule for the bin); this port keeps the node where it is rather than
211
+ // losing it, which is the browser shape of "not our child".
212
+ if (id === null || id === '') continue;
213
+ if (this._children.has(id)) {
214
+ // `set_child` replaces the child of an id rather than adding a second.
215
+ console.warn(`While adding child: duplicate slot ${id} in AdwMultiLayoutView; kept the first`);
216
+ }
217
+ this._children.set(id, node);
218
+ }
219
+ this._layouts = layouts;
220
+ const wanted = this.getAttribute('layout-name');
221
+ // A declared `layout-name` is `set_layout_name`, which REFUSES a name no layout
222
+ // carries rather than falling back; an absent one takes the first, which is what
223
+ // `add_layout` makes current when the list is built (:553).
224
+ if (wanted !== null) this._setLayoutByName(wanted);
225
+ else this._setLayout(layouts[0] ?? null);
226
+ }
227
+
228
+ /** `set_layout()` (:252): the same layout is not a change, and both properties notify. */
229
+ private _setLayout(layout: Layout | null): void {
230
+ if (layout === this._current) {
231
+ // A rebuild still has to re-mount: the content's slots are rebuilt from the
232
+ // DOM every time, so `_current` being unchanged says nothing about the tree.
233
+ if (layout !== null) this._mount(layout);
234
+ return;
235
+ }
236
+ this._current = layout;
237
+ if (layout === null) this._destroy();
238
+ else this._mount(layout);
239
+ this.dispatchEvent(new CustomEvent('notify::layout', { bubbles: true, detail: { layout: this.layoutName } }));
240
+ this.dispatchEvent(
241
+ new CustomEvent('notify::layout-name', { bubbles: true, detail: { layoutName: this.layoutName } }),
242
+ );
243
+ }
244
+
245
+ /**
246
+ * `set_layout_name()` (:507): look the name up, refuse an unknown one, then switch.
247
+ *
248
+ * The refusal is C's, in its own shape — `g_critical` and `return`, with no call to
249
+ * `set_layout` at all (:519), so the current layout is UNCHANGED rather than emptied.
250
+ * That is why the lookup is not folded into `_setLayout`: it answers the question
251
+ * first, and an unknown name is not a switch to nothing.
252
+ */
253
+ private _setLayoutByName(name: string | null): void {
254
+ if (name === null) return;
255
+ const layout = this._layouts.find((candidate) => candidate.name === name);
256
+ if (layout === undefined) {
257
+ console.error(`Layout name '${name}' not found in AdwMultiLayoutView`);
258
+ return;
259
+ }
260
+ this._setLayout(layout);
261
+ }
262
+
263
+ /**
264
+ * `destroy_current_layout()` (:192): forget every slot and unparent the content.
265
+ *
266
+ * The children are simply LEFT, which is what upstream does: a child whose id the
267
+ * OUTGOING layout had no slot for is not unparented by `unparent_child`
268
+ * (adw-multi-layout-view.c:175) and rides out with the content it was in. They stay
269
+ * alive in `_children`, which is where this port remembers the declaration.
270
+ */
271
+ private _destroy(): void {
272
+ this._slots.clear();
273
+ this.replaceChildren();
274
+ }
275
+
276
+ /**
277
+ * `rebuild_current_layout()` (:200), minus the render-node snapshot.
278
+ *
279
+ * The do/while is C's own: parenting a child can root a slot of its own, which grows
280
+ * the table, which may make another child land. `slotCount` is what the loop compares
281
+ * against — the C's `g_hash_table_size`.
282
+ */
283
+ private _mount(layout: Layout): void {
284
+ this._destroy();
285
+ this._acceptingSlots = true;
286
+ // APPENDED, not `replaceChildren`: `_destroy` has already emptied the host, and
287
+ // an unmatched child must not be a reason to drop the layout on the floor.
288
+ this.appendChild(layout.content);
289
+ // Re-register what is already in the mounted layout's own subtree, then let each
290
+ // child's mount register more. The loop is `old_size` again.
291
+ for (;;) {
292
+ const before = this._slots.size;
293
+ for (const slot of layout.content.querySelectorAll('adw-layout-slot')) {
294
+ const id = slot.getAttribute('id');
295
+ if (id !== null && id !== '' && !this._slots.has(id)) this.registerSlot(id, slot as AdwLayoutSlot);
296
+ }
297
+ for (const [id, child] of this._children) this._parent(id, child);
298
+ if (this._slots.size === before) break;
299
+ }
300
+ this._acceptingSlots = false;
301
+ }
302
+
303
+ /** `parent_child()` (:136): bind `visible`, then insert. */
304
+ private _parent(id: string, child: Element): void {
305
+ const slot = this._slots.get(id);
306
+ if (slot === undefined) return;
307
+ if (child.parentElement === slot) return;
308
+ this._mirrorVisible(slot, child);
309
+ slot.appendChild(child);
310
+ }
311
+
312
+ /**
313
+ * The one-way `visible` binding (:151), which CSS cannot express: the SLOT follows
314
+ * the CHILD. `hidden` is observed rather than polled so a child hidden AFTER it
315
+ * landed still hides the hole.
316
+ */
317
+ private _mirrorVisible(slot: Element, child: Element): void {
318
+ const apply = () => {
319
+ slot.toggleAttribute('hidden', (child as HTMLElement).hidden === true);
320
+ };
321
+ apply();
322
+ new MutationObserver(apply).observe(child, { attributes: true, attributeFilter: ['hidden'] });
323
+ }
324
+ }
325
+
326
+ customElements.define('adw-multi-layout-view', AdwMultiLayoutView);