@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
@@ -0,0 +1,811 @@
1
+ // <gtk-about-dialog> — GTK's own "About" window, the browser counterpart of
2
+ // `GtkAboutDialog`, and NOT the libadwaita one `<adw-about-dialog>` ports: this widget
3
+ // is a `GtkWindow` whose headerbar holds a `GtkStackSwitcher` over a four-page
4
+ // `GtkStack` — main, Credits, License, System — and whose main page is a column of
5
+ // centred labels under a dialog-size logo (gtkaboutdialog.ui).
6
+ //
7
+ // The DIALOG CHROME IS `<adw-dialog>`'s, not a copy of it: this element extends
8
+ // `AdwDialog`, so the full-cover scrim, the floating sheet, `present()`/`close()`,
9
+ // `can-close`, Escape, the Tab trap, the initial focus and the return-focus are the ones
10
+ // `adw-dialog.ts` already implements, and the only thing added here is the header hook
11
+ // (`decorateHeader`) that puts the switcher where GTK puts it — in the title position,
12
+ // with NO title text, exactly as the `.ui` declares. That is also why there is no
13
+ // `aria-modal` anywhere below: `elements/modal-surface.ts` owns the declaration.
14
+ //
15
+ // WHAT IS PORTED FROM `gtkaboutdialog.c`, AND WHERE IT SHOWS
16
+ //
17
+ // · `update_name_version` (:1066-1082): the window title is `About <program-name>`
18
+ // and the name label is BOLD; the version label is visible only when a version was
19
+ // set. An UNSET `program-name` falls back to `g_get_application_name()`, which in a
20
+ // document is `document.title` — the same "the application calls itself whatever
21
+ // its own name is" rule, and the reason the element shows something for a dialog
22
+ // that named nothing.
23
+ // · the three page-visibility rules: License exists only for
24
+ // `license-type == custom && license != NULL && license[0] != 0`
25
+ // (`update_license_button_visibility`, :686-696), System only for a non-empty
26
+ // `system-information` (:700-710), and Credits for any of authors / documenters /
27
+ // artists / credit sections / a `translator-credits` that is not an untranslated
28
+ // gettext sentinel (:700-717). The STACK SWITCHER is visible when any of the three
29
+ // is (`update_stack_switcher_visibility`, :657-670), which is why a dialog with
30
+ // none shows an EMPTY headerbar — GTK's own answer.
31
+ // · `set_license_type` (:2259-2313): any type other than `custom` OVERWRITES `license`
32
+ // with the warranty preamble, links it to that licence's URL (falling back to
33
+ // `website` for a licence whose row has no URL, which is what `unknown` does), and
34
+ // forces `wrap-license` TRUE. `gtk_license_info` (:126-146) is the table, held once
35
+ // in `@gjsify/adwaita-core` as `ADW_LICENSES`; the preamble is GTK's own string,
36
+ // which differs from libadwaita's in its first words and in the newline.
37
+ // · `stack_visible_child_notify` (:297-333): the Credits, License and System pages are
38
+ // populated LAZILY, the first time the stack shows them. A credits grid for 300
39
+ // authors is not built by a dialog that is never opened to it.
40
+ // · `populate_credits_page` (:2029-2080) order and headings — "Created by",
41
+ // "Documented by", "Translated by", "Design by", then the app's own sections — with
42
+ // the translator list split on newlines and the untranslated sentinel suppressed
43
+ // (`translatorCreditsPeople`, `creditsSections`).
44
+ // · `add_credits_section` (:1903-2027): a two-column grid, the heading in column 0
45
+ // right-aligned, each name in column 1, and a blank row after every section ("skip
46
+ // one at the end").
47
+ // · `text_buffer_new` (:1903-1990 in `gtkaboutdialog.c`; the License and System text
48
+ // views): `<http://…>` and `<mail@host>` angle-bracket links and bare `http(s)` URLs
49
+ // become clickable spans, everything else stays literal.
50
+ // · `emit_activate_link` (:646-655) + the `activate-link` accumulator: the signal is
51
+ // `BOOLEAN__STRING` with `_gtk_boolean_handled_accumulator`, so a handler returning
52
+ // TRUE suppresses the default navigation — which is what `preventDefault()` on the
53
+ // cancelable CustomEvent spells.
54
+ // · `gtk_widget_class_add_binding_action (…, GDK_KEY_Escape, …, "window.close")`
55
+ // (:725): the base class's Escape handling, through the shared modal surface.
56
+ //
57
+ // KNOWN_GAPS — one property, and it is a TYPE the attribute could have carried:
58
+ // · `logo` (`Gdk.Paintable`) is taken as a URL string and drawn as an `<img>`, because
59
+ // the browser has no paintable object and an attribute can hold a URL. `logo-icon-name`
60
+ // overrides it, as in the C (`gtk_about_dialog_set_logo_icon_name` overwrites the
61
+ // paintable and notifies `logo` back to NULL).
62
+ // · The `<a href="…">` markup form a credit line may carry is NOT recognised as a link
63
+ // (`add_credits_section` leaves it to the label's Pango parser, :2160-2164): this
64
+ // renderer builds DOM nodes, not markup, so such a line shows its markup literally.
65
+ // The link syntax that DOES work is the same one everywhere else — `Ada <ada@x.org>`
66
+ // or `Ada https://example.org`.
67
+ // · The visited-link colour (`update_links_cb`, :720-747) is not tracked: a clicked
68
+ // link does not stay a second colour, which is the one state GTK keeps across a
69
+ // dialog's whole life.
70
+ //
71
+ // Attributes (the GObject property names, hyphenated):
72
+ // program-name, version, copyright, comments, license, license-type,
73
+ // system-information, website, website-label, translator-credits, logo-icon-name,
74
+ // wrap-license — plus `open`/`can-close`/`title`/`content-width`/`content-height`/
75
+ // `presentation-mode`/`show-header` from the `<adw-dialog>` chrome it extends.
76
+ //
77
+ // Properties with no attribute form, exactly as in the C (a `GStrv` is not a string and
78
+ // `authors` is `char **`): `authors`, `documenters`, `artists`, and
79
+ // `addCreditSection(name, people)` for the app's own sections. `logo` takes a URL.
80
+ //
81
+ // Events (bubbling CustomEvents): `notify::open` (`{ open }`), `closed` and
82
+ // `activate-link` (`{ uri }`, CANCELABLE) from the base class, plus `notify::<prop>` for
83
+ // every property this element reflects.
84
+ //
85
+ // A11y: role `dialog` on the sheet, from `AdwModalSurface`. The switcher is a row of
86
+ // toggle buttons naming the three pages, and the sheet's `aria-label` is the window
87
+ // title, since the headerbar carries no text of its own.
88
+ //
89
+ // Reference: refs/gtk/gtk/gtkaboutdialog.c (every derivation cited above by line)
90
+ // Reference: refs/gtk/gtk/ui/gtkaboutdialog.ui (the page tree and the headerbar)
91
+ // Reference: refs/libadwaita/src/stylesheet/widgets/_dialogs.scss:46-56
92
+ // (window.aboutdialog: a FLAT titlebar and `image.large-icons` at 128px)
93
+ // Reference: packages/web/adwaita-web/src/elements/adw-dialog.ts (the chrome reused)
94
+ // Copyright (c) 2008-2024 Red Hat, Inc. / The GTK authors. LGPLv2.1+.
95
+ // Modifications: Implemented as a Web Component for @gjsify/adwaita-web; the icon nodes
96
+ // are <gtk-image>; the licence table and the credit parsing come from
97
+ // @gjsify/adwaita-core (ADR 0004).
98
+
99
+ import { ADW_LICENSES, GTK_LICENSE, parseCreditPerson, translatorCreditsPeople } from '@gjsify/adwaita-core';
100
+
101
+ import { AdwDialog } from './adw-dialog.js';
102
+ import { createGtkImage } from './gtk-image.js';
103
+
104
+ /** The four `GtkStackPage` titles of the `.ui`, mnemonics absent (they carry none). */
105
+ const PAGE_TITLES = {
106
+ main: 'About',
107
+ credits: 'Credits',
108
+ license: 'License',
109
+ system: 'System',
110
+ } as const;
111
+
112
+ /** The three pages behind the switcher, in stack order. */
113
+ const EXTRA_PAGES = ['credits', 'license', 'system'] as const;
114
+ type ExtraPage = (typeof EXTRA_PAGES)[number];
115
+
116
+ /** The `GtkLicense` nicks `packages/framework/gtk-host` generates, in enum order. */
117
+ const LICENSE_NICKS = [
118
+ 'unknown',
119
+ 'custom',
120
+ 'gpl-2-0',
121
+ 'gpl-3-0',
122
+ 'lgpl-2-1',
123
+ 'lgpl-3-0',
124
+ 'bsd',
125
+ 'mit-x11',
126
+ 'artistic',
127
+ 'gpl-2-0-only',
128
+ 'gpl-3-0-only',
129
+ 'lgpl-2-1-only',
130
+ 'lgpl-3-0-only',
131
+ 'agpl-3-0',
132
+ 'agpl-3-0-only',
133
+ 'bsd-3',
134
+ 'apache-2-0',
135
+ 'mpl-2-0',
136
+ '0bsd',
137
+ ] as const;
138
+
139
+ /**
140
+ * GTK's licence preamble (`gtk_about_dialog_set_license_type`, :2301) — NOT
141
+ * libadwaita's `ADW_LICENSE_WARRANTY_TEMPLATE`, which says "This application" and has no
142
+ * newline. Both strings are translatable and they are not translations of each other.
143
+ * The C template is `'This program comes with absolutely no warranty.\nSee the
144
+ * <a href="%s">%s</a> for details.'`; `_licenseMarkup` composes the same three runs —
145
+ * text, link, text — as DOM, because the scan it uses for plain licence text would read
146
+ * the `<a href>` as an email address.
147
+ */
148
+
149
+ export class GtkAboutDialog extends AdwDialog {
150
+ private _built = false;
151
+ private _logo = '';
152
+ private _switcherEl!: HTMLDivElement;
153
+ private _stackEl!: HTMLDivElement;
154
+ private _pages = new Map<string, HTMLElement>();
155
+ private _populated = new Set<string>();
156
+ private _authors: string[] = [];
157
+ private _documenters: string[] = [];
158
+ private _artists: string[] = [];
159
+ private _creditSections: Array<{ name: string; people: string[] }> = [];
160
+
161
+ static get observedAttributes(): string[] {
162
+ return [
163
+ ...AdwDialog.observedAttributes,
164
+ 'program-name',
165
+ 'version',
166
+ 'copyright',
167
+ 'comments',
168
+ 'license',
169
+ 'license-type',
170
+ 'system-information',
171
+ 'website',
172
+ 'website-label',
173
+ 'translator-credits',
174
+ 'logo-icon-name',
175
+ 'wrap-license',
176
+ ];
177
+ }
178
+
179
+ // ------------------------------------------------------------ properties
180
+
181
+ /** The program name; unset falls back to the document's own title (`g_get_application_name`). */
182
+ get programName(): string {
183
+ return this.getAttribute('program-name') ?? '';
184
+ }
185
+
186
+ set programName(value: string) {
187
+ this.setAttribute('program-name', value);
188
+ }
189
+
190
+ get version(): string {
191
+ return this.getAttribute('version') ?? '';
192
+ }
193
+
194
+ set version(value: string) {
195
+ this.setAttribute('version', value);
196
+ }
197
+
198
+ get copyright(): string {
199
+ return this.getAttribute('copyright') ?? '';
200
+ }
201
+
202
+ set copyright(value: string) {
203
+ this.setAttribute('copyright', value);
204
+ }
205
+
206
+ get comments(): string {
207
+ return this.getAttribute('comments') ?? '';
208
+ }
209
+
210
+ set comments(value: string) {
211
+ this.setAttribute('comments', value);
212
+ }
213
+
214
+ get license(): string {
215
+ return this.getAttribute('license') ?? '';
216
+ }
217
+
218
+ set license(value: string) {
219
+ // `set_license` (:1279) stores the text AND forces the type to CUSTOM, in
220
+ // that order — a MIT-typed dialog that is given licence text becomes custom.
221
+ this.setAttribute('license', value);
222
+ this.setAttribute('license-type', 'custom');
223
+ }
224
+
225
+ /** The `GtkLicense` nick — `unknown`, `custom`, `mit-x11`, … */
226
+ get licenseType(): string {
227
+ const value = this.getAttribute('license-type');
228
+ return value !== null && LICENSE_NICKS.includes(value as (typeof LICENSE_NICKS)[number]) ? value : 'unknown';
229
+ }
230
+
231
+ set licenseType(value: string) {
232
+ if (LICENSE_NICKS.includes(value as (typeof LICENSE_NICKS)[number])) this.setAttribute('license-type', value);
233
+ else this.removeAttribute('license-type');
234
+ }
235
+
236
+ get systemInformation(): string {
237
+ return this.getAttribute('system-information') ?? '';
238
+ }
239
+
240
+ set systemInformation(value: string) {
241
+ this.setAttribute('system-information', value);
242
+ }
243
+
244
+ get website(): string {
245
+ return this.getAttribute('website') ?? '';
246
+ }
247
+
248
+ set website(value: string) {
249
+ this.setAttribute('website', value);
250
+ }
251
+
252
+ get websiteLabel(): string {
253
+ return this.getAttribute('website-label') ?? '';
254
+ }
255
+
256
+ set websiteLabel(value: string) {
257
+ this.setAttribute('website-label', value);
258
+ }
259
+
260
+ get translatorCredits(): string {
261
+ return this.getAttribute('translator-credits') ?? '';
262
+ }
263
+
264
+ set translatorCredits(value: string) {
265
+ this.setAttribute('translator-credits', value);
266
+ }
267
+
268
+ /** The named-icon logo; overrides {@link logo}, as in the C. */
269
+ get logoIconName(): string {
270
+ return this.getAttribute('logo-icon-name') ?? '';
271
+ }
272
+
273
+ set logoIconName(value: string) {
274
+ this.setAttribute('logo-icon-name', value);
275
+ }
276
+
277
+ /** Whether the License page's text view WRAPS (`populate_license_page`, :2157). */
278
+ get wrapLicense(): boolean {
279
+ return this.hasAttribute('wrap-license');
280
+ }
281
+
282
+ set wrapLicense(value: boolean) {
283
+ this.toggleAttribute('wrap-license', value);
284
+ }
285
+
286
+ /**
287
+ * A logo URL, drawn as an `<img>`.
288
+ *
289
+ * `GtkAboutDialog:logo` is a `GdkPaintable`, which is the one GObject property here
290
+ * an attribute could have carried and cannot: there is no paintable in a document.
291
+ * A URL is the honest browser stand-in and the override order is the C's.
292
+ */
293
+ get logo(): string {
294
+ return this._logo;
295
+ }
296
+
297
+ set logo(value: string) {
298
+ this._logo = value;
299
+ if (this._built) this._renderLogo();
300
+ }
301
+
302
+ /** The people whose names the Credits page shows — `GtkAboutDialog:authors`. */
303
+ get authors(): string[] {
304
+ return [...this._authors];
305
+ }
306
+
307
+ set authors(value: readonly string[]) {
308
+ this._authors = [...value];
309
+ this._creditsChanged();
310
+ }
311
+
312
+ get documenters(): string[] {
313
+ return [...this._documenters];
314
+ }
315
+
316
+ set documenters(value: readonly string[]) {
317
+ this._documenters = [...value];
318
+ this._creditsChanged();
319
+ }
320
+
321
+ get artists(): string[] {
322
+ return [...this._artists];
323
+ }
324
+
325
+ set artists(value: readonly string[]) {
326
+ this._artists = [...value];
327
+ this._creditsChanged();
328
+ }
329
+
330
+ /** `gtk_about_dialog_add_credit_section` — an extra titled group on the Credits page. */
331
+ addCreditSection(name: string, people: readonly string[]): void {
332
+ this._creditSections.push({ name, people: [...people] });
333
+ this._creditsChanged();
334
+ }
335
+
336
+ private _creditsChanged(): void {
337
+ // The C latches the page visible the moment a credit is set and never clears it;
338
+ // recomputing from the inputs is the same rule without the stale flag, and it is
339
+ // what `creditsSections` exists to be read by.
340
+ this._populated.delete('credits');
341
+ if (this._built) this._renderAbout();
342
+ }
343
+
344
+ // ------------------------------------------------------------ lifecycle
345
+
346
+ connectedCallback(): void {
347
+ if (this._built) {
348
+ // A re-attach (AdwDialog.present on a dialog already in the document) must
349
+ // not rebuild the subtree — the DOM already exists.
350
+ super.connectedCallback();
351
+ return;
352
+ }
353
+ // BEFORE `super.connectedCallback()`, which renders and therefore calls
354
+ // `decorateHeader` — the switcher is what that hook installs.
355
+ this._switcherEl = document.createElement('div');
356
+ this._switcherEl.className = 'adw-gtk-about-dialog-switcher';
357
+ this._switcherEl.setAttribute('role', 'tablist');
358
+ this._switcherEl.setAttribute('aria-label', 'Pages');
359
+
360
+ super.connectedCallback();
361
+ // `_stackEl` before `_build`, which appends the pages to it — and `_built`
362
+ // goes last: `setAttribute('title')` below re-enters through
363
+ // `attributeChangedCallback`, and rendering on an empty `_pages` map throws.
364
+ this._stackEl = document.createElement('div');
365
+ this._stackEl.className = 'adw-gtk-about-dialog-stack';
366
+ this._stackEl.dataset.transitionType = 'crossfade';
367
+
368
+ // GTK's window title is `About <name>` whatever the headerbar shows, and the
369
+ // headerbar shows no text of its own — so the title is what assistive tech reads.
370
+ this.setAttribute('title', `About ${this.programName || document.title}`);
371
+ // The base adopts the author's light-DOM children into `contentArea` on
372
+ // connect; rebuilding around them must keep them, AFTER the dialog's own UI —
373
+ // which is also where children appended later land (`slotted-children.spec.ts`
374
+ // pins the equality, path and index).
375
+ const adopted = [...this.contentArea.childNodes];
376
+ this.contentArea.replaceChildren(this._build());
377
+ for (const node of adopted) this.contentArea.appendChild(node);
378
+ // `_build` hides every page but `main`, which is `gtk_stack_set_visible_child_name
379
+ // (…, "main")`; the three visibility rules then decide which of the others exist.
380
+ this._renderAbout();
381
+ this._built = true;
382
+ }
383
+
384
+ attributeChangedCallback(name: string, oldValue: string | null, newValue: string | null): void {
385
+ super.attributeChangedCallback(name, oldValue, newValue);
386
+ if (!this._built) return;
387
+ if (oldValue === newValue) return;
388
+ if (name === 'license' || name === 'license-type' || name === 'website') {
389
+ // `set_license` sets the type to CUSTOM and `set_license_type` overwrites
390
+ // the text, so either one can invalidate the other's rendering.
391
+ this._populated.delete('license');
392
+ }
393
+ if (name === 'system-information') this._populated.delete('system');
394
+ if (name === 'website' || name === 'website-label' || name === 'license' || name === 'license-type') {
395
+ this._renderMain();
396
+ this._populateLicense();
397
+ }
398
+ if (name === 'wrap-license') this._populateLicense();
399
+ if (name === 'system-information') this._populateSystem();
400
+ this._renderAbout();
401
+ }
402
+
403
+ /**
404
+ * The headerbar carries the stack switcher and nothing else, exactly as
405
+ * `gtkaboutdialog.ui` declares it (`title-widget` → the switcher, no title).
406
+ */
407
+ protected override decorateHeader(header: HTMLElement): void {
408
+ const title = header.querySelector('.adw-dialog-title');
409
+ // The switcher takes the title's place; the title carries no text of its own here.
410
+ if (title !== null) {
411
+ title.replaceWith(this._switcherEl);
412
+ } else {
413
+ header.prepend(this._switcherEl);
414
+ }
415
+ this._renderSwitcher();
416
+ }
417
+
418
+ /** Which stack page is showing — `gtk_stack_get_visible_child_name`. */
419
+ get visiblePage(): string {
420
+ return this._stackEl.dataset.visible ?? 'main';
421
+ }
422
+
423
+ /**
424
+ * Show a page of the stack — `gtk_stack_set_visible_child_name`. The switcher buttons
425
+ * call it, and it is the one way the stack's lazy population (`stack_visible_child_notify`)
426
+ * runs: a page is built the first time it is shown, not before.
427
+ */
428
+ showPage(name: string): void {
429
+ this._populatePage(name);
430
+ for (const [key, page] of this._pages) page.hidden = key !== name;
431
+ this._stackEl.dataset.visible = name;
432
+ this._renderSwitcher();
433
+ }
434
+
435
+ // ------------------------------------------------------------ rendering
436
+
437
+ private _build(): HTMLElement {
438
+ const root = document.createElement('div');
439
+ root.className = 'adw-gtk-about-dialog-box';
440
+
441
+ const head = document.createElement('div');
442
+ head.className = 'adw-gtk-about-dialog-head';
443
+
444
+ const logoSlot = document.createElement('div');
445
+ logoSlot.className = 'adw-gtk-about-dialog-logo-slot';
446
+ head.appendChild(logoSlot);
447
+ this._renderLogo();
448
+
449
+ const name = document.createElement('div');
450
+ name.className = 'adw-gtk-about-dialog-name';
451
+ name.textContent = this.programName || document.title;
452
+ head.appendChild(name);
453
+
454
+ for (const page of ['main', ...EXTRA_PAGES]) {
455
+ const element = document.createElement('div');
456
+ element.className = 'adw-gtk-about-dialog-page';
457
+ element.dataset.page = page;
458
+ element.hidden = page !== 'main';
459
+ this._pages.set(page, element);
460
+ this._stackEl.appendChild(element);
461
+ }
462
+ this._renderMain();
463
+ head.appendChild(this._stackEl);
464
+ root.appendChild(head);
465
+ return root;
466
+ }
467
+
468
+ private _renderAbout(): void {
469
+ this.setAttribute('title', `About ${this.programName || document.title}`);
470
+ for (const page of EXTRA_PAGES) {
471
+ const element = this._pages.get(page);
472
+ if (element === undefined) continue;
473
+ // `gtk_stack_page_set_visible` — and a page that stops being visible is also
474
+ // dropped from the switcher, because the switcher lists the pages the stack
475
+ // holds and no more.
476
+ const visible = this._pageVisible(page);
477
+ if (element.hidden === !visible) continue;
478
+ element.hidden = !visible;
479
+ if (!visible) this._populated.delete(page);
480
+ }
481
+ if (this._pages.get(this._stackEl.dataset.visible ?? 'main')?.hidden !== false) {
482
+ this._stackEl.dataset.visible = 'main';
483
+ this._pages.get('main')!.hidden = false;
484
+ }
485
+ this._renderMain();
486
+ this._renderSwitcher();
487
+ }
488
+
489
+ /** The three visibility rules, one predicate each, as in the C. */
490
+ private _pageVisible(page: ExtraPage): boolean {
491
+ if (page === 'credits') return this._creditsPeople().length > 0;
492
+ if (page === 'license') return this.licenseType === 'custom' && this.license.length > 0;
493
+ return this.systemInformation.length > 0;
494
+ }
495
+
496
+ /** `add_credits_section`'s input, in `populate_credits_page`'s order. */
497
+ private _creditsPeople(): Array<{ title: string; people: readonly string[] }> {
498
+ const sections: Array<{ title: string; people: readonly string[] }> = [];
499
+ if (this._authors.length > 0) sections.push({ title: 'Created by', people: this._authors });
500
+ if (this._documenters.length > 0) sections.push({ title: 'Documented by', people: this._documenters });
501
+ const translators = translatorCreditsPeople(this.translatorCredits);
502
+ if (translators.length > 0) sections.push({ title: 'Translated by', people: translators });
503
+ if (this._artists.length > 0) sections.push({ title: 'Design by', people: this._artists });
504
+ for (const section of this._creditSections) sections.push({ title: section.name, people: section.people });
505
+ return sections;
506
+ }
507
+
508
+ /** Whether the stack switcher has anything to show (`update_stack_switcher_visibility`). */
509
+ private _visiblePages(): ExtraPage[] {
510
+ return EXTRA_PAGES.filter((page) => this._pages.get(page)?.hidden === false);
511
+ }
512
+
513
+ private _renderSwitcher(): void {
514
+ if (this._switcherEl === undefined) return;
515
+ const pages = this._visiblePages();
516
+ // GTK hides the whole switcher (`gtk_widget_set_visible (about->stack_switcher,
517
+ // any_visible)`), which is why an about dialog with no credits, licence or system
518
+ // information shows an EMPTY headerbar.
519
+ this._switcherEl.hidden = pages.length === 0;
520
+ this._switcherEl.replaceChildren(
521
+ ...pages.map((page) => {
522
+ const button = document.createElement('button');
523
+ button.type = 'button';
524
+ button.className = 'adw-gtk-about-dialog-switcher-item';
525
+ button.setAttribute('role', 'tab');
526
+ button.textContent = PAGE_TITLES[page];
527
+ button.classList.toggle('checked', this._stackEl.dataset.visible === page);
528
+ button.setAttribute('aria-selected', String(this._stackEl.dataset.visible === page));
529
+ button.addEventListener('click', () => this.showPage(page));
530
+ return button;
531
+ }),
532
+ );
533
+ }
534
+
535
+ private _renderLogo(): void {
536
+ const slot = this.contentArea.querySelector('.adw-gtk-about-dialog-logo-slot');
537
+ if (slot === null) return;
538
+ // `set_logo_icon_name` overwrites the paintable, and notifies `logo` back to NULL:
539
+ // the icon name wins whenever it is set, which is the only precedence there is.
540
+ if (this.logoIconName.length > 0) {
541
+ slot.replaceChildren(createGtkImage(this.logoIconName, 'adw-gtk-about-dialog-logo'));
542
+ return;
543
+ }
544
+ if (this._logo.length > 0) {
545
+ const image = document.createElement('img');
546
+ image.className = 'adw-gtk-about-dialog-logo';
547
+ image.src = this._logo;
548
+ image.alt = '';
549
+ slot.replaceChildren(image);
550
+ return;
551
+ }
552
+ slot.replaceChildren();
553
+ }
554
+
555
+ /** The main page: version, comments, website, copyright, licence — in `.ui` order. */
556
+ private _renderMain(): void {
557
+ const page = this._pages.get('main');
558
+ if (page === undefined) return;
559
+ const rows: HTMLElement[] = [];
560
+
561
+ const label = (text: string, className: string): HTMLElement => {
562
+ const element = document.createElement('div');
563
+ element.className = className;
564
+ element.textContent = text;
565
+ return element;
566
+ };
567
+
568
+ if (this.version.length > 0) rows.push(label(this.version, 'adw-gtk-about-dialog-version'));
569
+ if (this.comments.length > 0) rows.push(label(this.comments, 'adw-gtk-about-dialog-comments'));
570
+ // `update_website` (:1009-1041): a URL with no label shows the word "Website", a
571
+ // label with no URL shows the label alone and is NOT a link, and neither shows
572
+ // anything when both are unset.
573
+ if (this.website.length > 0) {
574
+ rows.push(
575
+ this.websiteLabel.length > 0
576
+ ? this._link(this.websiteLabel, this.website, 'adw-gtk-about-dialog-website')
577
+ : this._link('Website', this.website, 'adw-gtk-about-dialog-website'),
578
+ );
579
+ } else if (this.websiteLabel.length > 0) {
580
+ rows.push(label(this.websiteLabel, 'adw-gtk-about-dialog-website'));
581
+ }
582
+ if (this.copyright.length > 0) rows.push(label(this.copyright, 'adw-gtk-about-dialog-copyright'));
583
+ const licence = this._licenseMarkup();
584
+ if (licence !== null) rows.push(licence);
585
+
586
+ page.replaceChildren(...rows);
587
+ }
588
+
589
+ /**
590
+ * The licence label: the text `license` holds, with its `<…>` and bare-URL links
591
+ * turned into spans — or, for a known type, the warranty preamble `set_license_type`
592
+ * composes. The preamble keeps its `<a href>` markup and is read with
593
+ * `gtk_label_set_markup` (:2354), a REAL link: it never goes through the
594
+ * `text_buffer_new` scan below, which would read `<a href="…">` as an email
595
+ * address. Same split here.
596
+ */
597
+ private _licenseMarkup(): HTMLElement | null {
598
+ const type = this.licenseType;
599
+ const index = LICENSE_NICKS.indexOf(type as (typeof LICENSE_NICKS)[number]);
600
+ const licenseType =
601
+ index >= 0 ? (index as (typeof GTK_LICENSE)[keyof typeof GTK_LICENSE]) : GTK_LICENSE.UNKNOWN;
602
+ const element = document.createElement('div');
603
+ element.className = 'adw-gtk-about-dialog-license';
604
+ if (licenseType !== GTK_LICENSE.CUSTOM && licenseType !== GTK_LICENSE.UNKNOWN) {
605
+ const info = ADW_LICENSES[licenseType]!;
606
+ // A licence row with no URL of its own links to the WEBSITE, which is what
607
+ // `set_license_type` does for `unknown` and for a row whose `url` is NULL.
608
+ const url = info.url ?? this.website;
609
+ element.append(
610
+ document.createTextNode('This program comes with absolutely no warranty.\nSee the '),
611
+ this._link(info.name ?? '', url, 'adw-gtk-about-dialog-license-link'),
612
+ document.createTextNode(' for details.'),
613
+ );
614
+ return element;
615
+ }
616
+ if (licenseType === GTK_LICENSE.UNKNOWN || this.license.length === 0) return null;
617
+ this._fillWithLinks(element, this.license);
618
+ return element;
619
+ }
620
+
621
+ /** The License page — a text view whose wrap mode is `wrap-license`. */
622
+ private _populateLicense(): void {
623
+ const page = this._pages.get('license');
624
+ if (page === undefined) return;
625
+ const view = document.createElement('div');
626
+ view.className = 'adw-gtk-about-dialog-text-view';
627
+ // `populate_license_page` (:2157-2166): WRAP_WORD when `wrap-license`, else NONE.
628
+ if (this.wrapLicense) view.classList.add('wrap');
629
+ const markup = this._licenseMarkup();
630
+ if (markup !== null) {
631
+ const body = document.createElement('div');
632
+ body.className = 'adw-gtk-about-dialog-text';
633
+ // The main label's runs, cloned — including the preamble's real link.
634
+ body.replaceChildren(...[...markup.childNodes].map((node) => node.cloneNode(true)));
635
+ view.appendChild(body);
636
+ }
637
+ page.replaceChildren(this._frame(view));
638
+ }
639
+
640
+ /** The System page — a text view with no wrap mode of its own. */
641
+ private _populateSystem(): void {
642
+ const page = this._pages.get('system');
643
+ if (page === undefined) return;
644
+ const view = document.createElement('div');
645
+ view.className = 'adw-gtk-about-dialog-text-view';
646
+ const body = document.createElement('div');
647
+ body.className = 'adw-gtk-about-dialog-text';
648
+ this._fillWithLinks(body, this.systemInformation);
649
+ view.appendChild(body);
650
+ page.replaceChildren(this._frame(view));
651
+ }
652
+
653
+ /** The Credits page — the scrolled, framed grid `populate_credits_page` fills. */
654
+ private _populateCredits(): void {
655
+ const page = this._pages.get('credits');
656
+ if (page === undefined) return;
657
+
658
+ const grid = document.createElement('div');
659
+ grid.className = 'adw-gtk-about-dialog-credits-grid';
660
+ grid.setAttribute('role', 'group');
661
+ grid.setAttribute('aria-label', PAGE_TITLES.credits);
662
+
663
+ for (const section of this._creditsPeople()) {
664
+ const heading = document.createElement('div');
665
+ heading.className = 'adw-gtk-about-dialog-credits-heading';
666
+ heading.textContent = section.title;
667
+ grid.appendChild(heading);
668
+ for (const person of section.people) {
669
+ const parsed = parseCreditPerson(person);
670
+ const row = document.createElement('div');
671
+ row.className = 'adw-gtk-about-dialog-credits-person';
672
+ if (parsed.link !== null) {
673
+ row.appendChild(this._link(parsed.name, parsed.uri ?? '', 'adw-gtk-about-dialog-credits-link'));
674
+ } else {
675
+ row.textContent = parsed.name;
676
+ }
677
+ grid.appendChild(row);
678
+ }
679
+ // "skip one at the end" — an empty row so consecutive sections do not touch.
680
+ grid.appendChild(document.createElement('div'));
681
+ }
682
+ page.replaceChildren(this._frame(grid));
683
+ }
684
+
685
+ /**
686
+ * `stack_visible_child_notify` (:297-333): each of the three pages is built the first
687
+ * time the stack SHOWS it, and never rebuilt after. A credits grid for three hundred
688
+ * authors is not work a dialog nobody opened it for.
689
+ */
690
+ private _populatePage(name: string): void {
691
+ if (this._populated.has(name)) return;
692
+ this._populated.add(name);
693
+ if (name === 'credits') this._populateCredits();
694
+ else if (name === 'license') this._populateLicense();
695
+ else if (name === 'system') this._populateSystem();
696
+ }
697
+
698
+ /** The framed scrolled window the three extra pages sit in (`has-frame`). */
699
+ private _frame(content: HTMLElement): HTMLElement {
700
+ const scrolled = document.createElement('div');
701
+ scrolled.className = 'adw-gtk-about-dialog-scrolled';
702
+ const viewport = document.createElement('div');
703
+ viewport.className = 'adw-view';
704
+ viewport.appendChild(content);
705
+ scrolled.appendChild(viewport);
706
+ return scrolled;
707
+ }
708
+
709
+ private _link(text: string, uri: string, className: string): HTMLElement {
710
+ const link = document.createElement('a');
711
+ link.className = className;
712
+ link.href = uri;
713
+ link.rel = 'noopener noreferrer';
714
+ link.textContent = text;
715
+ link.addEventListener('click', (event) => {
716
+ event.preventDefault();
717
+ this._activateLink(uri);
718
+ });
719
+ return link;
720
+ }
721
+
722
+ /**
723
+ * `text_buffer_new` (:1903-2028 of `gtkaboutdialog.c`) for the plain-DOM case: split
724
+ * the string into literal runs and links. A `<…>` run is an email when it carries no
725
+ * scheme and a URL when it does; a bare `http://` or `https://` run ends at the first
726
+ * of space, newline, tab or `>`, which is `strpbrk (r1, " \n\t>")`.
727
+ */
728
+ private _fillWithLinks(target: HTMLElement, text: string): void {
729
+ for (const part of splitLinks(text)) {
730
+ if (part.uri === null) {
731
+ target.appendChild(document.createTextNode(part.text));
732
+ continue;
733
+ }
734
+ const link = document.createElement('a');
735
+ link.href = part.uri;
736
+ link.rel = 'noopener noreferrer';
737
+ link.textContent = part.text;
738
+ link.addEventListener('click', (event) => {
739
+ event.preventDefault();
740
+ this._activateLink(part.uri!);
741
+ });
742
+ target.appendChild(link);
743
+ }
744
+ }
745
+
746
+ /**
747
+ * `emit_activate_link` (:646-655): the `BOOLEAN__STRING` accumulator. A handler that
748
+ * returns TRUE says it took over, which is `preventDefault()` here — and only then
749
+ * does the default `Gtk.UriLauncher` navigation not happen.
750
+ */
751
+ private _activateLink(uri: string): void {
752
+ const event = new CustomEvent('activate-link', {
753
+ bubbles: true,
754
+ cancelable: true,
755
+ detail: { uri },
756
+ });
757
+ if (this.dispatchEvent(event)) window.open(uri, '_blank', 'noopener,noreferrer');
758
+ }
759
+ }
760
+
761
+ /** One run of `text_buffer_new`'s output: literal text, or a link with its URI. */
762
+ interface LinkPart {
763
+ readonly text: string;
764
+ readonly uri: string | null;
765
+ }
766
+
767
+ /** The terminator set a bare URL ends at (`strpbrk (r1, " \n\t>")`). */
768
+ const URL_TERMINATORS = ' \n\t>';
769
+
770
+ /**
771
+ * `text_buffer_new`'s scan, in order: the first `<` and the first `>` after it, the
772
+ * earliest bare `http://` or `https://` and where it ends, and the C's own precedence —
773
+ * a URL that starts AT or just after the `<` wins, which leaves the bracket in the text.
774
+ */
775
+ export function splitLinks(text: string): LinkPart[] {
776
+ const parts: LinkPart[] = [];
777
+ let rest = text;
778
+ while (rest.length > 0) {
779
+ let bracket = rest.indexOf('<');
780
+ let bracketEnd = bracket < 0 ? -1 : rest.indexOf('>', bracket);
781
+ const httpAt = rest.indexOf('http://');
782
+ const httpsAt = rest.indexOf('https://');
783
+ let urlAt = httpAt;
784
+ if (httpAt < 0 || (httpsAt >= 0 && httpsAt < httpAt)) urlAt = httpsAt;
785
+ let urlEnd = -1;
786
+ if (urlAt >= 0) {
787
+ urlEnd = URL_TERMINATORS.split('').reduce((found, character) => {
788
+ if (found >= 0) return found;
789
+ const at = rest.indexOf(character, urlAt);
790
+ return at < 0 ? -1 : at;
791
+ }, -1);
792
+ if (urlEnd < 0) urlEnd = rest.length;
793
+ }
794
+ if (urlAt >= 0 && (bracket < 0 || bracketEnd < 0 || urlAt <= bracket + 1)) {
795
+ bracket = urlAt;
796
+ bracketEnd = urlEnd;
797
+ }
798
+ if (bracket < 0 || bracketEnd < 0) {
799
+ parts.push({ text: rest, uri: null });
800
+ break;
801
+ }
802
+ if (bracket > 0) parts.push({ text: rest.slice(0, bracket), uri: null });
803
+ const isEmail = rest[bracket] === '<';
804
+ const body = isEmail ? rest.slice(bracket + 1, bracketEnd) : rest.slice(bracket, bracketEnd);
805
+ parts.push({ text: body, uri: isEmail ? `mailto:${body}` : body });
806
+ rest = rest.slice(bracketEnd + (isEmail ? 1 : 0));
807
+ }
808
+ return parts;
809
+ }
810
+
811
+ customElements.define('gtk-about-dialog', GtkAboutDialog);