@gjsify/adwaita-web 0.54.0 → 0.55.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (439) hide show
  1. package/dist/adwaita-web.css +8066 -3033
  2. package/dist/adwaita-web.css.map +1 -1
  3. package/lib/types/adw-application-window.spec.d.ts +1 -0
  4. package/lib/types/adw-bin.spec.d.ts +1 -0
  5. package/lib/types/adw-breakpoint-bin.spec.d.ts +1 -0
  6. package/lib/types/adw-clamp-scrollable.spec.d.ts +1 -0
  7. package/lib/types/adw-multi-layout-view.spec.d.ts +1 -0
  8. package/lib/types/adw-preferences-row.spec.d.ts +1 -0
  9. package/lib/types/adw-shortcuts.spec.d.ts +1 -0
  10. package/lib/types/adw-tab-bar.spec.d.ts +1 -0
  11. package/lib/types/adw-tab-button.spec.d.ts +1 -0
  12. package/lib/types/adw-tab-overview.spec.d.ts +1 -0
  13. package/lib/types/adw-view-switcher-sidebar.spec.d.ts +1 -0
  14. package/lib/types/adw-window.spec.d.ts +1 -0
  15. package/lib/types/breakpoints.d.ts +14 -3
  16. package/lib/types/construct-vectors.spec.d.ts +1 -0
  17. package/lib/types/elements/adw-application-window.d.ts +27 -0
  18. package/lib/types/elements/adw-bin.d.ts +17 -0
  19. package/lib/types/elements/adw-breakpoint-bin.d.ts +67 -0
  20. package/lib/types/elements/adw-clamp-scrollable.d.ts +38 -0
  21. package/lib/types/elements/adw-dialog.d.ts +10 -0
  22. package/lib/types/elements/adw-layout-slot.d.ts +19 -0
  23. package/lib/types/elements/adw-multi-layout-view.d.ts +101 -0
  24. package/lib/types/elements/adw-preferences-row.d.ts +31 -0
  25. package/lib/types/elements/adw-shortcuts-dialog.d.ts +13 -0
  26. package/lib/types/elements/adw-shortcuts-item.d.ts +36 -0
  27. package/lib/types/elements/adw-shortcuts-section.d.ts +14 -0
  28. package/lib/types/elements/adw-sidebar.d.ts +5 -0
  29. package/lib/types/elements/adw-switch-row.d.ts +3 -0
  30. package/lib/types/elements/adw-tab-bar.d.ts +108 -0
  31. package/lib/types/elements/adw-tab-button.d.ts +32 -0
  32. package/lib/types/elements/adw-tab-overview.d.ts +199 -0
  33. package/lib/types/elements/adw-tab-view.d.ts +19 -23
  34. package/lib/types/elements/adw-view-switcher-sidebar.d.ts +84 -0
  35. package/lib/types/elements/adw-window.d.ts +40 -0
  36. package/lib/types/elements/gtk-about-dialog.d.ts +146 -0
  37. package/lib/types/elements/gtk-application-window.d.ts +34 -0
  38. package/lib/types/elements/gtk-aspect-frame.d.ts +27 -0
  39. package/lib/types/elements/gtk-button.d.ts +9 -0
  40. package/lib/types/elements/gtk-calendar.d.ts +159 -0
  41. package/lib/types/elements/gtk-center-box.d.ts +39 -0
  42. package/lib/types/elements/gtk-color-dialog-button.d.ts +69 -0
  43. package/lib/types/elements/gtk-column-view.d.ts +50 -0
  44. package/lib/types/elements/gtk-drag-icon.d.ts +78 -0
  45. package/lib/types/elements/gtk-drawing-area.d.ts +95 -0
  46. package/lib/types/elements/gtk-editable-label.d.ts +33 -0
  47. package/lib/types/elements/gtk-emoji-chooser.d.ts +84 -0
  48. package/lib/types/elements/gtk-entry.d.ts +20 -1
  49. package/lib/types/elements/gtk-expander.d.ts +49 -0
  50. package/lib/types/elements/gtk-fixed.d.ts +13 -0
  51. package/lib/types/elements/gtk-flow-box-child.d.ts +14 -0
  52. package/lib/types/elements/gtk-flow-box.d.ts +87 -0
  53. package/lib/types/elements/gtk-font-dialog-button.d.ts +83 -0
  54. package/lib/types/elements/gtk-frame.d.ts +24 -0
  55. package/lib/types/elements/gtk-gl-area.d.ts +136 -0
  56. package/lib/types/elements/gtk-graphics-offload.d.ts +24 -0
  57. package/lib/types/elements/gtk-grid-view.d.ts +39 -0
  58. package/lib/types/elements/gtk-grid.d.ts +27 -0
  59. package/lib/types/elements/gtk-header-bar.d.ts +60 -0
  60. package/lib/types/elements/gtk-inscription.d.ts +64 -0
  61. package/lib/types/elements/gtk-label.d.ts +3 -0
  62. package/lib/types/elements/gtk-level-bar.d.ts +59 -0
  63. package/lib/types/elements/gtk-link-button.d.ts +29 -0
  64. package/lib/types/elements/gtk-list-box-row.d.ts +54 -0
  65. package/lib/types/elements/gtk-list-box.d.ts +100 -0
  66. package/lib/types/elements/gtk-list-view.d.ts +73 -0
  67. package/lib/types/elements/gtk-media-controls.d.ts +142 -0
  68. package/lib/types/elements/gtk-notebook.d.ts +148 -0
  69. package/lib/types/elements/gtk-overlay.d.ts +22 -0
  70. package/lib/types/elements/gtk-page-setup-unix-dialog.d.ts +87 -0
  71. package/lib/types/elements/gtk-paned.d.ts +121 -0
  72. package/lib/types/elements/gtk-password-entry.d.ts +27 -0
  73. package/lib/types/elements/gtk-picture.d.ts +66 -0
  74. package/lib/types/elements/gtk-popover-bin.d.ts +82 -0
  75. package/lib/types/elements/gtk-popover-menu-bar.d.ts +66 -0
  76. package/lib/types/elements/gtk-popover-menu.d.ts +83 -0
  77. package/lib/types/elements/gtk-popover.d.ts +28 -3
  78. package/lib/types/elements/gtk-print-unix-dialog.d.ts +167 -0
  79. package/lib/types/elements/gtk-revealer.d.ts +55 -0
  80. package/lib/types/elements/gtk-scale-button.d.ts +59 -0
  81. package/lib/types/elements/gtk-scale.d.ts +98 -0
  82. package/lib/types/elements/gtk-scrollbar.d.ts +124 -0
  83. package/lib/types/elements/gtk-scrolled-window.d.ts +121 -0
  84. package/lib/types/elements/gtk-search-bar.d.ts +39 -0
  85. package/lib/types/elements/gtk-search-entry.d.ts +27 -0
  86. package/lib/types/elements/gtk-separator.d.ts +10 -0
  87. package/lib/types/elements/gtk-spin-button.d.ts +94 -0
  88. package/lib/types/elements/gtk-spinner.d.ts +14 -0
  89. package/lib/types/elements/gtk-stack-sidebar.d.ts +43 -0
  90. package/lib/types/elements/gtk-stack-switcher.d.ts +58 -0
  91. package/lib/types/elements/gtk-stack.d.ts +154 -0
  92. package/lib/types/elements/gtk-switch.d.ts +4 -1
  93. package/lib/types/elements/gtk-text-view.d.ts +62 -0
  94. package/lib/types/elements/gtk-text.d.ts +45 -0
  95. package/lib/types/elements/gtk-toggle-button.d.ts +45 -0
  96. package/lib/types/elements/gtk-tree-expander.d.ts +38 -0
  97. package/lib/types/elements/gtk-video.d.ts +97 -0
  98. package/lib/types/elements/gtk-viewport.d.ts +84 -0
  99. package/lib/types/elements/gtk-window-controls.d.ts +80 -0
  100. package/lib/types/elements/gtk-window-handle.d.ts +39 -0
  101. package/lib/types/elements/gtk-window.d.ts +97 -0
  102. package/lib/types/elements/justification.d.ts +2 -0
  103. package/lib/types/elements/popover-menu.d.ts +18 -0
  104. package/lib/types/elements/roving-focus.d.ts +29 -1
  105. package/lib/types/emoji-data.d.ts +38 -0
  106. package/lib/types/font-description.d.ts +96 -0
  107. package/lib/types/gtk-about-dialog.spec.d.ts +1 -0
  108. package/lib/types/gtk-action-bar.spec.d.ts +1 -0
  109. package/lib/types/gtk-application-window.spec.d.ts +1 -0
  110. package/lib/types/gtk-aspect-frame.spec.d.ts +1 -0
  111. package/lib/types/gtk-calendar.spec.d.ts +1 -0
  112. package/lib/types/gtk-center-box.spec.d.ts +1 -0
  113. package/lib/types/gtk-color-dialog-button.spec.d.ts +1 -0
  114. package/lib/types/gtk-column-view.spec.d.ts +1 -0
  115. package/lib/types/gtk-drag-icon.spec.d.ts +1 -0
  116. package/lib/types/gtk-drawing-area.spec.d.ts +1 -0
  117. package/lib/types/gtk-editable-label.spec.d.ts +1 -0
  118. package/lib/types/gtk-emoji-chooser.spec.d.ts +1 -0
  119. package/lib/types/gtk-expander.spec.d.ts +1 -0
  120. package/lib/types/gtk-fixed.spec.d.ts +1 -0
  121. package/lib/types/gtk-flow-box.spec.d.ts +1 -0
  122. package/lib/types/gtk-font-dialog-button.spec.d.ts +1 -0
  123. package/lib/types/gtk-frame.spec.d.ts +1 -0
  124. package/lib/types/gtk-gl-area.spec.d.ts +1 -0
  125. package/lib/types/gtk-graphics-offload.spec.d.ts +1 -0
  126. package/lib/types/gtk-grid-view.spec.d.ts +1 -0
  127. package/lib/types/gtk-grid.spec.d.ts +1 -0
  128. package/lib/types/gtk-header-bar.spec.d.ts +1 -0
  129. package/lib/types/gtk-inscription.spec.d.ts +1 -0
  130. package/lib/types/gtk-level-bar.spec.d.ts +1 -0
  131. package/lib/types/gtk-link-button.spec.d.ts +1 -0
  132. package/lib/types/gtk-list-box.spec.d.ts +1 -0
  133. package/lib/types/gtk-list-view.spec.d.ts +1 -0
  134. package/lib/types/gtk-media-controls.spec.d.ts +1 -0
  135. package/lib/types/gtk-notebook.spec.d.ts +1 -0
  136. package/lib/types/gtk-overlay.spec.d.ts +1 -0
  137. package/lib/types/gtk-paned.spec.d.ts +1 -0
  138. package/lib/types/gtk-password-entry.spec.d.ts +1 -0
  139. package/lib/types/gtk-picture.spec.d.ts +1 -0
  140. package/lib/types/gtk-popover-bin.spec.d.ts +1 -0
  141. package/lib/types/gtk-popover-menu-bar.spec.d.ts +1 -0
  142. package/lib/types/gtk-popover-menu.spec.d.ts +1 -0
  143. package/lib/types/gtk-popover-role.spec.d.ts +1 -0
  144. package/lib/types/gtk-popover.spec.d.ts +1 -0
  145. package/lib/types/gtk-print-dialogs.spec.d.ts +1 -0
  146. package/lib/types/gtk-revealer.spec.d.ts +1 -0
  147. package/lib/types/gtk-scale-button.spec.d.ts +1 -0
  148. package/lib/types/gtk-scale.spec.d.ts +1 -0
  149. package/lib/types/gtk-scrollbar.spec.d.ts +1 -0
  150. package/lib/types/gtk-scrolled-window.spec.d.ts +1 -0
  151. package/lib/types/gtk-search-bar.spec.d.ts +1 -0
  152. package/lib/types/gtk-search-entry.spec.d.ts +1 -0
  153. package/lib/types/gtk-separator.spec.d.ts +1 -0
  154. package/lib/types/gtk-spin-button.spec.d.ts +1 -0
  155. package/lib/types/gtk-spinner.spec.d.ts +1 -0
  156. package/lib/types/gtk-stack-sidebar.spec.d.ts +1 -0
  157. package/lib/types/gtk-stack-switcher.spec.d.ts +1 -0
  158. package/lib/types/gtk-stack.spec.d.ts +1 -0
  159. package/lib/types/gtk-text-view.spec.d.ts +1 -0
  160. package/lib/types/gtk-text.spec.d.ts +1 -0
  161. package/lib/types/gtk-toggle-button.spec.d.ts +1 -0
  162. package/lib/types/gtk-tree-expander.spec.d.ts +1 -0
  163. package/lib/types/gtk-video.spec.d.ts +1 -0
  164. package/lib/types/gtk-viewport.spec.d.ts +1 -0
  165. package/lib/types/gtk-window-controls.spec.d.ts +1 -0
  166. package/lib/types/gtk-window-handle.spec.d.ts +1 -0
  167. package/lib/types/gtk-window.spec.d.ts +1 -0
  168. package/lib/types/index.d.ts +4 -1
  169. package/lib/types/list-view-dom.d.ts +44 -0
  170. package/lib/types/namespace/adw.d.ts +12 -0
  171. package/lib/types/namespace/gtk.d.ts +61 -0
  172. package/lib/types/page-setup.d.ts +100 -0
  173. package/lib/types/scroll-shading.d.ts +15 -1
  174. package/lib/types/shared-tree-builder.d.ts +30 -2
  175. package/lib/types/signals.d.ts +4 -0
  176. package/lib/types/styles.generated.d.ts +1 -1
  177. package/lib/types/tab-chip.d.ts +73 -0
  178. package/lib/types/template-classes.d.ts +11 -0
  179. package/package.json +12 -8
  180. package/scss/_action_row.scss +2 -2
  181. package/scss/_application_window.scss +26 -0
  182. package/scss/_aspect_frame.scss +25 -0
  183. package/scss/_bin.scss +26 -0
  184. package/scss/_button.scss +45 -0
  185. package/scss/_calendar.scss +176 -0
  186. package/scss/_center_box.scss +25 -0
  187. package/scss/_checks.scss +6 -1
  188. package/scss/_clamp_scrollable.scss +28 -0
  189. package/scss/_color_button.scss +67 -0
  190. package/scss/_column_view.scss +126 -0
  191. package/scss/_drag_icon.scss +55 -0
  192. package/scss/_drawing.scss +85 -0
  193. package/scss/_emoji_chooser.scss +213 -0
  194. package/scss/_entry.scss +13 -5
  195. package/scss/_entry_row.scss +1 -1
  196. package/scss/_expander.scss +113 -0
  197. package/scss/_fixed.scss +29 -0
  198. package/scss/_flow_box.scss +94 -0
  199. package/scss/_font_button.scss +63 -0
  200. package/scss/_frame.scss +41 -0
  201. package/scss/_grid.scss +19 -0
  202. package/scss/_grid_view.scss +46 -0
  203. package/scss/_gtk_about_dialog.scss +186 -0
  204. package/scss/_headerbar.scss +132 -0
  205. package/scss/_icons.generated.scss +186 -0
  206. package/scss/_inscription.scss +125 -0
  207. package/scss/_level_bar.scss +190 -0
  208. package/scss/_link.scss +82 -0
  209. package/scss/_list_box.scss +88 -0
  210. package/scss/_list_view.scss +96 -0
  211. package/scss/_media_controls.scss +139 -0
  212. package/scss/_overlay.scss +68 -0
  213. package/scss/_paned.scss +130 -0
  214. package/scss/_password_entry.scss +83 -0
  215. package/scss/_picture.scss +80 -0
  216. package/scss/_popover_bin.scss +53 -0
  217. package/scss/_popover_menu_bar.scss +104 -0
  218. package/scss/_preferences_row.scss +51 -0
  219. package/scss/_print_dialogs.scss +328 -0
  220. package/scss/_reset.scss +21 -19
  221. package/scss/_revealer.scss +37 -0
  222. package/scss/_row.scss +20 -5
  223. package/scss/_scale.scss +298 -0
  224. package/scss/_scale_button.scss +167 -0
  225. package/scss/_scrollbar.scss +230 -0
  226. package/scss/_scrolled_window.scss +131 -0
  227. package/scss/_search_bar.scss +118 -0
  228. package/scss/_search_entry.scss +86 -0
  229. package/scss/_separator.scss +44 -0
  230. package/scss/_shortcuts_dialog.scss +100 -0
  231. package/scss/_spin_button.scss +172 -0
  232. package/scss/_spin_row.scss +56 -8
  233. package/scss/_spinner.scss +85 -4
  234. package/scss/_stack.scss +729 -0
  235. package/scss/_switch.scss +13 -5
  236. package/scss/_switch_row.scss +10 -0
  237. package/scss/_tab_bar.scss +317 -0
  238. package/scss/_tab_button.scss +98 -0
  239. package/scss/_tab_overview.scss +483 -0
  240. package/scss/_text.scss +182 -0
  241. package/scss/_theme.scss +1 -1
  242. package/scss/_tree_expander.scss +62 -0
  243. package/scss/_variables.scss +1 -1
  244. package/scss/_video.scss +146 -0
  245. package/scss/_view_switcher_sidebar.scss +112 -0
  246. package/scss/_viewport.scss +50 -0
  247. package/scss/_window.scss +118 -1
  248. package/scss/_window_handle.scss +20 -0
  249. package/scss/adwaita-skin.scss +109 -0
  250. package/src/adw-action-rows.spec.ts +76 -0
  251. package/src/adw-application-window.spec.ts +118 -0
  252. package/src/adw-bin.spec.ts +75 -0
  253. package/src/adw-breakpoint-bin.spec.ts +324 -0
  254. package/src/adw-clamp-scrollable.spec.ts +189 -0
  255. package/src/adw-multi-layout-view.spec.ts +243 -0
  256. package/src/adw-preferences-row.spec.ts +164 -0
  257. package/src/adw-row-state.spec.ts +142 -0
  258. package/src/adw-shortcuts.spec.ts +155 -0
  259. package/src/adw-tab-bar.spec.ts +287 -0
  260. package/src/adw-tab-button.spec.ts +101 -0
  261. package/src/adw-tab-overview.spec.ts +443 -0
  262. package/src/adw-view-switcher-sidebar.spec.ts +281 -0
  263. package/src/adw-window.spec.ts +129 -0
  264. package/src/breakpoints.ts +25 -8
  265. package/src/capabilities.d.mts +3 -0
  266. package/src/capabilities.mjs +18 -0
  267. package/src/connect-lifecycle.spec.ts +12 -0
  268. package/src/construct-vectors.spec.ts +175 -0
  269. package/src/elements/adw-application-window.ts +154 -0
  270. package/src/elements/adw-bin.ts +101 -0
  271. package/src/elements/adw-breakpoint-bin.ts +287 -0
  272. package/src/elements/adw-clamp-scrollable.ts +207 -0
  273. package/src/elements/adw-dialog.ts +19 -0
  274. package/src/elements/adw-layout-slot.ts +95 -0
  275. package/src/elements/adw-multi-layout-view.ts +326 -0
  276. package/src/elements/adw-preferences-row.ts +150 -0
  277. package/src/elements/adw-shortcuts-dialog.ts +52 -0
  278. package/src/elements/adw-shortcuts-item.ts +171 -0
  279. package/src/elements/adw-shortcuts-section.ts +86 -0
  280. package/src/elements/adw-sidebar.ts +42 -3
  281. package/src/elements/adw-switch-row.ts +28 -1
  282. package/src/elements/adw-tab-bar.ts +529 -0
  283. package/src/elements/adw-tab-button.ts +194 -0
  284. package/src/elements/adw-tab-overview.ts +1011 -0
  285. package/src/elements/adw-tab-view.ts +66 -145
  286. package/src/elements/adw-toggle-group.ts +20 -5
  287. package/src/elements/adw-view-stack.ts +18 -0
  288. package/src/elements/adw-view-switcher-sidebar.ts +332 -0
  289. package/src/elements/adw-window.ts +185 -11
  290. package/src/elements/checks.ts +35 -8
  291. package/src/elements/gtk-about-dialog.ts +811 -0
  292. package/src/elements/gtk-application-window.ts +108 -0
  293. package/src/elements/gtk-aspect-frame.ts +160 -0
  294. package/src/elements/gtk-button.ts +12 -0
  295. package/src/elements/gtk-calendar.ts +757 -0
  296. package/src/elements/gtk-center-box.ts +184 -0
  297. package/src/elements/gtk-color-dialog-button.ts +278 -0
  298. package/src/elements/gtk-column-view.ts +320 -0
  299. package/src/elements/gtk-drag-icon.ts +257 -0
  300. package/src/elements/gtk-drawing-area.ts +303 -0
  301. package/src/elements/gtk-editable-label.ts +204 -0
  302. package/src/elements/gtk-emoji-chooser.ts +542 -0
  303. package/src/elements/gtk-entry.ts +39 -5
  304. package/src/elements/gtk-expander.ts +301 -0
  305. package/src/elements/gtk-fixed.ts +99 -0
  306. package/src/elements/gtk-flow-box-child.ts +68 -0
  307. package/src/elements/gtk-flow-box.ts +480 -0
  308. package/src/elements/gtk-font-dialog-button.ts +432 -0
  309. package/src/elements/gtk-frame.ts +174 -0
  310. package/src/elements/gtk-gl-area.ts +476 -0
  311. package/src/elements/gtk-graphics-offload.ts +130 -0
  312. package/src/elements/gtk-grid-view.ts +168 -0
  313. package/src/elements/gtk-grid.ts +127 -0
  314. package/src/elements/gtk-header-bar.ts +273 -0
  315. package/src/elements/gtk-inscription.ts +387 -0
  316. package/src/elements/gtk-label.ts +19 -11
  317. package/src/elements/gtk-level-bar.ts +323 -0
  318. package/src/elements/gtk-link-button.ts +138 -0
  319. package/src/elements/gtk-list-box-row.ts +195 -0
  320. package/src/elements/gtk-list-box.ts +413 -0
  321. package/src/elements/gtk-list-view.ts +370 -0
  322. package/src/elements/gtk-media-controls.ts +509 -0
  323. package/src/elements/gtk-notebook.ts +664 -0
  324. package/src/elements/gtk-overlay.ts +149 -0
  325. package/src/elements/gtk-page-setup-unix-dialog.ts +420 -0
  326. package/src/elements/gtk-paned.ts +597 -0
  327. package/src/elements/gtk-password-entry.ts +170 -0
  328. package/src/elements/gtk-picture.ts +254 -0
  329. package/src/elements/gtk-popover-bin.ts +332 -0
  330. package/src/elements/gtk-popover-menu-bar.ts +355 -0
  331. package/src/elements/gtk-popover-menu.ts +339 -0
  332. package/src/elements/gtk-popover.ts +92 -10
  333. package/src/elements/gtk-print-unix-dialog.ts +989 -0
  334. package/src/elements/gtk-progress-bar.ts +24 -11
  335. package/src/elements/gtk-revealer.ts +406 -0
  336. package/src/elements/gtk-scale-button.ts +358 -0
  337. package/src/elements/gtk-scale.ts +492 -0
  338. package/src/elements/gtk-scrollbar.ts +528 -0
  339. package/src/elements/gtk-scrolled-window.ts +642 -0
  340. package/src/elements/gtk-search-bar.ts +200 -0
  341. package/src/elements/gtk-search-entry.ts +172 -0
  342. package/src/elements/gtk-separator.ts +52 -0
  343. package/src/elements/gtk-spin-button.ts +475 -0
  344. package/src/elements/gtk-spinner.ts +126 -0
  345. package/src/elements/gtk-stack-sidebar.ts +212 -0
  346. package/src/elements/gtk-stack-switcher.ts +279 -0
  347. package/src/elements/gtk-stack.ts +748 -0
  348. package/src/elements/gtk-switch.ts +52 -19
  349. package/src/elements/gtk-text-view.ts +290 -0
  350. package/src/elements/gtk-text.ts +219 -0
  351. package/src/elements/gtk-toggle-button.ts +239 -0
  352. package/src/elements/gtk-tree-expander.ts +243 -0
  353. package/src/elements/gtk-video.ts +423 -0
  354. package/src/elements/gtk-viewport.ts +277 -0
  355. package/src/elements/gtk-window-controls.ts +341 -0
  356. package/src/elements/gtk-window-handle.ts +221 -0
  357. package/src/elements/gtk-window.ts +366 -0
  358. package/src/elements/justification.ts +24 -0
  359. package/src/elements/popover-menu.ts +24 -0
  360. package/src/elements/roving-focus.ts +53 -21
  361. package/src/emoji-data.ts +577 -0
  362. package/src/entry-rows.spec.ts +31 -0
  363. package/src/font-description.ts +238 -0
  364. package/src/gtk-about-dialog.spec.ts +250 -0
  365. package/src/gtk-action-bar.spec.ts +89 -0
  366. package/src/gtk-application-window.spec.ts +107 -0
  367. package/src/gtk-aspect-frame.spec.ts +114 -0
  368. package/src/gtk-calendar.spec.ts +589 -0
  369. package/src/gtk-center-box.spec.ts +125 -0
  370. package/src/gtk-color-dialog-button.spec.ts +141 -0
  371. package/src/gtk-column-view.spec.ts +154 -0
  372. package/src/gtk-drag-icon.spec.ts +190 -0
  373. package/src/gtk-drawing-area.spec.ts +211 -0
  374. package/src/gtk-editable-label.spec.ts +190 -0
  375. package/src/gtk-emoji-chooser.spec.ts +173 -0
  376. package/src/gtk-entry.spec.ts +23 -0
  377. package/src/gtk-expander.spec.ts +170 -0
  378. package/src/gtk-fixed.spec.ts +97 -0
  379. package/src/gtk-flow-box.spec.ts +289 -0
  380. package/src/gtk-font-dialog-button.spec.ts +166 -0
  381. package/src/gtk-frame.spec.ts +119 -0
  382. package/src/gtk-gl-area.spec.ts +361 -0
  383. package/src/gtk-graphics-offload.spec.ts +119 -0
  384. package/src/gtk-grid-view.spec.ts +106 -0
  385. package/src/gtk-grid.spec.ts +122 -0
  386. package/src/gtk-header-bar.spec.ts +202 -0
  387. package/src/gtk-inscription.spec.ts +235 -0
  388. package/src/gtk-level-bar.spec.ts +199 -0
  389. package/src/gtk-link-button.spec.ts +117 -0
  390. package/src/gtk-list-box.spec.ts +422 -0
  391. package/src/gtk-list-view.spec.ts +203 -0
  392. package/src/gtk-media-controls.spec.ts +295 -0
  393. package/src/gtk-notebook.spec.ts +546 -0
  394. package/src/gtk-overlay.spec.ts +141 -0
  395. package/src/gtk-paned.spec.ts +267 -0
  396. package/src/gtk-password-entry.spec.ts +150 -0
  397. package/src/gtk-picture.spec.ts +172 -0
  398. package/src/gtk-popover-bin.spec.ts +229 -0
  399. package/src/gtk-popover-menu-bar.spec.ts +296 -0
  400. package/src/gtk-popover-menu.spec.ts +261 -0
  401. package/src/gtk-popover-role.spec.ts +138 -0
  402. package/src/gtk-popover.spec.ts +264 -0
  403. package/src/gtk-print-dialogs.spec.ts +251 -0
  404. package/src/gtk-revealer.spec.ts +164 -0
  405. package/src/gtk-scale-button.spec.ts +218 -0
  406. package/src/gtk-scale.spec.ts +213 -0
  407. package/src/gtk-scrollbar.spec.ts +244 -0
  408. package/src/gtk-scrolled-window.spec.ts +262 -0
  409. package/src/gtk-search-bar.spec.ts +179 -0
  410. package/src/gtk-search-entry.spec.ts +142 -0
  411. package/src/gtk-separator.spec.ts +74 -0
  412. package/src/gtk-spin-button.spec.ts +186 -0
  413. package/src/gtk-spinner.spec.ts +130 -0
  414. package/src/gtk-stack-sidebar.spec.ts +217 -0
  415. package/src/gtk-stack-switcher.spec.ts +249 -0
  416. package/src/gtk-stack.spec.ts +432 -0
  417. package/src/gtk-text-view.spec.ts +189 -0
  418. package/src/gtk-text.spec.ts +163 -0
  419. package/src/gtk-toggle-button.spec.ts +186 -0
  420. package/src/gtk-tree-expander.spec.ts +201 -0
  421. package/src/gtk-video.spec.ts +240 -0
  422. package/src/gtk-viewport.spec.ts +140 -0
  423. package/src/gtk-window-controls.spec.ts +232 -0
  424. package/src/gtk-window-handle.spec.ts +158 -0
  425. package/src/gtk-window.spec.ts +190 -0
  426. package/src/index.ts +9 -1
  427. package/src/keyboard-operable.spec.ts +33 -1
  428. package/src/list-view-dom.ts +121 -0
  429. package/src/namespace/adw.ts +12 -0
  430. package/src/namespace/gtk.ts +61 -0
  431. package/src/page-setup.ts +222 -0
  432. package/src/scroll-shading.ts +18 -1
  433. package/src/shared-tree-builder.ts +263 -21
  434. package/src/signals.ts +15 -0
  435. package/src/style-classes.spec.ts +9 -8
  436. package/src/styles.generated.ts +1 -1
  437. package/src/tab-chip.ts +200 -0
  438. package/src/template-classes.ts +45 -0
  439. package/src/test.browser.mts +152 -0
@@ -0,0 +1,664 @@
1
+ // <gtk-notebook> — the older page container, which brings its own tab bar. A stack
2
+ // plus a strip of tabs, in one widget: `tab-pos` says which edge the strip is on,
3
+ // `show-tabs` takes it away entirely, and `page` is the current page by INDEX
4
+ // rather than by name.
5
+ //
6
+ // IT IS A STACK IN C. `GtkNotebook` holds a `stack_widget` (a GtkStack) for the pages
7
+ // and a `header_widget` with the tabs beside it, and `real_switch_page` drives the
8
+ // stack directly (`gtk_stack_set_visible_child`, gtknotebook.c:5476). That is why
9
+ // `page` is an index: the stack speaks names, the notebook speaks positions.
10
+ //
11
+ // THE CHILD IS THE PAGE. `GtkNotebookPage` is a GObject, not a widget
12
+ // (`G_DEFINE_TYPE (…, G_TYPE_OBJECT)`, gtknotebook.c:423), so it has no element of its
13
+ // own: its properties are attributes on the child, and the descriptor
14
+ // {@link NotebookPageInfo} is what `getNthPage()` describes. Of its eleven properties
15
+ // (gtknotebook.c:600-699) this element carries the five that are scalars and draw
16
+ // something — `tab-label` (the tab's text), `menu-label`, `tab-fill`, `tab-expand` and
17
+ // `reorderable` — and the `hidden` attribute is `GtkWidget:visible`.
18
+ //
19
+ // WHICH PAGE IS CURRENT, transcribed from `set_current_page`
20
+ // (gtknotebook.c:6046-6060) and `real_switch_page` (gtknotebook.c:5436-5498):
21
+ // · a NEGATIVE index means the LAST page, not "none" (:6054) — so `page="-1"` on a
22
+ // notebook with three pages selects the third;
23
+ // · `page` OUT OF RANGE does nothing at all, because `g_list_nth` returns NULL and
24
+ // the switch is guarded (:6056-6058);
25
+ // · a page whose child is NOT visible is refused the same way
26
+ // (`!gtk_widget_get_visible (child)`, :5444), which is how a hidden page is kept
27
+ // out of the rotation;
28
+ // · switching to the CURRENT page is not a change (:5444), so no notify;
29
+ // · the old tab loses `:checked` and the new one gains it, and the tab's
30
+ // `GTK_ACCESSIBLE_STATE_SELECTED` follows (:5458-5462, :5472-5474) — which is
31
+ // `aria-selected` here.
32
+ // `page` then notifies (`:5497`), as does every property the setters move.
33
+ //
34
+ // TAB POSITION. `tab-pos` is one of the four `GtkPositionType` nicks and defaults to
35
+ // `top` (gtknotebook.c:1113-1117). `get_effective_tab_pos` swaps left and right under
36
+ // RTL (:1741-1757), which is why the element reflects the SWAPPED position in
37
+ // `data-tab-pos` rather than the raw property.
38
+ //
39
+ // `show-border` is a CSS CLASS in C and not a branch: `gtk_notebook_set_show_border`
40
+ // adds `.frame` and clearing it removes that (gtknotebook.c:6134-6146), and libadwaita
41
+ // styles the class as a plain one-pixel border. Its own docs say the bevel only shows
42
+ // when the tabs are not (:6125-6131), because the header's own border covers it.
43
+ //
44
+ // A11Y: the strip is a `tablist` and each tab a `tab`, which is what the tab widget's
45
+ // own role is here; the pages carry `aria-hidden` as they do in a stack.
46
+ //
47
+ // Events: `notify::<prop>` (CustomEvent, bubbles, detail `{ <prop>: value }`);
48
+ // `switch-page` (detail `{ page: index, child }`) is GtkNotebook's own signal
49
+ // (gtknotebook.c:1180-1197), emitted BEFORE the switch with the page being switched TO
50
+ // — `gtk_notebook_switch_page` emits and the class handler `real_switch_page` performs
51
+ // (:5518-5523) — so a handler that vetoes by not drawing is the documented use;
52
+ // `page-added` (:1380-1391, emitted at :4129) and `page-removed` (:1358-1369) carry
53
+ // `{ position, nPages }`, the two page-list signals the C raises around an insert and a
54
+ // remove.
55
+ //
56
+ // NOT PORTED, and why:
57
+ // · `detachable` (gtknotebook.c:694-702) and the DnD behind it move a page to
58
+ // ANOTHER notebook; the browser's drag is a different protocol, and a notebook
59
+ // with one stack of children has nothing to detach to.
60
+ // · `enable-popup` (:1150-1159) builds a GtkPopoverMenu of the pages when it is set
61
+ // (:6420-6462) and pops it up on right-click (:2684-2692). The flag is read and
62
+ // reflected, and `contextmenu` opens `<div role="listbox">` of the same pages — but
63
+ // it is a DOM listbox, not a GtkPopover.
64
+ // · `scrollable` (:1140-1149) adds GtkScrollbar arrows when the tabs do not fit. The
65
+ // tabs here overflow with `overflow-x: auto`, which scrolls without the two arrow
66
+ // buttons GTK scrolls with.
67
+ // · `group-name` (:1160-1169) groups notebooks for drag and drop, which is the same
68
+ // absent DnD as `detachable`.
69
+ //
70
+ // Reference: refs/gtk/gtk/gtknotebook.c
71
+ // Copyright (c) The GTK Team. LGPLv2.1+.
72
+ // Modifications: Implemented as a Web Component for @gjsify/adwaita-web.
73
+
74
+ /** `GtkPositionType`, spelled as the GIR's enum nicks. `top` is the property default. */
75
+ export type NotebookTabPos = 'top' | 'bottom' | 'left' | 'right';
76
+
77
+ const TAB_POSITIONS: readonly string[] = ['top', 'bottom', 'left', 'right'];
78
+
79
+ /** The page attributes this element reads off a child (gtknotebook.c:600-695). */
80
+ const PAGE_ATTRIBUTES = ['tab-label', 'menu-label', 'tab-fill', 'tab-expand', 'reorderable', 'detachable'];
81
+
82
+ /** The browser's page descriptor — the stand-in for the `GtkNotebookPage` GObject. */
83
+ export interface NotebookPageInfo {
84
+ /** `GtkNotebookPage:tab-label` — the tab's text. `null` when absent. */
85
+ tabLabel: string | null;
86
+ /** `GtkNotebookPage:menu-label` — the text of the menu entry. `null` when absent. */
87
+ menuLabel: string | null;
88
+ /** `GtkNotebookPage:tab-fill` — the tab fills its allocation. Defaults to TRUE. */
89
+ tabFill: boolean;
90
+ /** `GtkNotebookPage:tab-expand` — the tab expands. Defaults to false. */
91
+ tabExpand: boolean;
92
+ /** `GtkNotebookPage:reorderable` — the user may drag the tab. */
93
+ reorderable: boolean;
94
+ /** `GtkNotebookPage:detachable` — read and reflected; the drag itself is not ported. */
95
+ detachable: boolean;
96
+ /** `GtkWidget:visible` on the child, as the DOM's `hidden`. */
97
+ visible: boolean;
98
+ /** `GtkNotebookPage:child`. */
99
+ child: HTMLElement;
100
+ }
101
+
102
+ export class GtkNotebook extends HTMLElement {
103
+ private _current: HTMLElement | null = null;
104
+ private _initialized = false;
105
+ private _initializedChildren = new WeakSet<HTMLElement>();
106
+ private _header!: HTMLDivElement;
107
+ private _tabs!: HTMLDivElement;
108
+ private _observer: MutationObserver | null = null;
109
+ private _tabNodes: HTMLButtonElement[] = [];
110
+ private _menu: HTMLElement | null = null;
111
+
112
+ static get observedAttributes() {
113
+ return ['page', 'tab-pos', 'show-tabs', 'show-border', 'scrollable', 'enable-popup', 'group-name'];
114
+ }
115
+
116
+ /**
117
+ * `Gtk.Notebook:page` — the index of the current page, `-1` when there is none.
118
+ *
119
+ * LIVE rather than the value last written: `get_property` returns
120
+ * `gtk_notebook_get_current_page (notebook)` (gtknotebook.c:1977-1979), so the
121
+ * attribute is an INPUT and this is the answer — a switch reached by clicking a tab
122
+ * is visible through the property without anything having written it. A negative
123
+ * WRITE means the LAST page (gtknotebook.c:6054).
124
+ */
125
+ get page(): number {
126
+ return this._current ? this._pages().indexOf(this._current) : -1;
127
+ }
128
+
129
+ set page(v: number) {
130
+ this.setCurrentPage(v);
131
+ }
132
+
133
+ /** `Gtk.Notebook:tab-pos` — which edge the tabs are on. Defaults to `top`. */
134
+ get tabPos(): NotebookTabPos {
135
+ const raw = this.getAttribute('tab-pos');
136
+ return raw !== null && TAB_POSITIONS.includes(raw) ? (raw as NotebookTabPos) : 'top';
137
+ }
138
+
139
+ set tabPos(v: NotebookTabPos) {
140
+ this._write('tab-pos', v);
141
+ }
142
+
143
+ /** `Gtk.Notebook:show-tabs` — the tab strip itself. Defaults to true. */
144
+ get showTabs(): boolean {
145
+ return this._flag('show-tabs', true);
146
+ }
147
+
148
+ set showTabs(v: boolean) {
149
+ this._write('show-tabs', v ? '' : 'false');
150
+ }
151
+
152
+ /** `Gtk.Notebook:show-border` — the border around the tab strip. Defaults to true. */
153
+ get showBorder(): boolean {
154
+ return this._flag('show-border', true);
155
+ }
156
+
157
+ set showBorder(v: boolean) {
158
+ this._write('show-border', v ? '' : 'false');
159
+ }
160
+
161
+ /** `Gtk.Notebook:scrollable` — GTK's scroll arrows. Defaults to false. */
162
+ get scrollable(): boolean {
163
+ return this._flag('scrollable', false);
164
+ }
165
+
166
+ set scrollable(v: boolean) {
167
+ this._write('scrollable', v ? '' : 'false');
168
+ }
169
+
170
+ /** `Gtk.Notebook:enable-popup` — the right-click page menu. Defaults to false. */
171
+ get enablePopup(): boolean {
172
+ return this._flag('enable-popup', false);
173
+ }
174
+
175
+ set enablePopup(v: boolean) {
176
+ this._write('enable-popup', v ? '' : 'false');
177
+ }
178
+
179
+ /** `Gtk.Notebook:group-name` — the drag-and-drop group. Defaults to `null`. */
180
+ get groupName(): string | null {
181
+ return this.getAttribute('group-name');
182
+ }
183
+
184
+ set groupName(v: string | null) {
185
+ this._write('group-name', v);
186
+ }
187
+
188
+ /** The current page's child, or `null` — `gtk_notebook_get_nth_page` at `page`. */
189
+ get currentPage(): HTMLElement | null {
190
+ return this._current;
191
+ }
192
+
193
+ /** `gtk_notebook_get_n_pages` as the browser spells it. */
194
+ get nPages(): number {
195
+ return this._pages().length;
196
+ }
197
+
198
+ /** `gtk_notebook_get_nth_page` (gtknotebook.c:5956-5977): a child, or null. */
199
+ getNthPage(n: number): HTMLElement | null {
200
+ const pages = this._pages();
201
+ const index = n < 0 ? pages.length - 1 : n;
202
+ return pages[index] ?? null;
203
+ }
204
+
205
+ /** `gtk_notebook_page_num` (gtknotebook.c:6006-6020): an index, `-1` when absent. */
206
+ pageNum(child: HTMLElement): number {
207
+ return this._pages().indexOf(child);
208
+ }
209
+
210
+ /** The descriptor of one child, `null` when it is not a page of this notebook. */
211
+ getPage(child: HTMLElement): NotebookPageInfo | null {
212
+ return this._pages().includes(child) ? this._page(child) : null;
213
+ }
214
+
215
+ /** `By CHILD rather than by index — `gtk_notebook_page_num` for the index and
216
+ * `gtk_notebook_set_current_page` for the switch (gtknotebook.c:6006, :6046). There is
217
+ * no `gtk_notebook_set_page` to transcribe: GTK 4 dropped it. */
218
+ setPage(child: HTMLElement): boolean {
219
+ const index = this._pages().indexOf(child);
220
+ if (index === -1) return false;
221
+ return this.setCurrentPage(index);
222
+ }
223
+
224
+ /**
225
+ * `gtk_notebook_next_page` (gtknotebook.c:6070-6088) — which searches with
226
+ * `gtk_notebook_search_page (…, STEP_NEXT, TRUE)`, so a HIDDEN page is stepped over
227
+ * rather than ending the walk, and the end of the notebook is simply nothing
228
+ * (:6079-6080).
229
+ */
230
+ nextPage(): boolean {
231
+ return this._searchPage(1);
232
+ }
233
+
234
+ /** `gtk_notebook_prev_page` (gtknotebook.c:6096-6113), the same search backwards. */
235
+ prevPage(): boolean {
236
+ return this._searchPage(-1);
237
+ }
238
+
239
+ /**
240
+ * `gtk_notebook_set_current_page` (gtknotebook.c:6046-6060) into
241
+ * `real_switch_page` (gtknotebook.c:5436-5498): a negative index is the last page,
242
+ * an out-of-range one does nothing, and a page whose child is hidden is refused.
243
+ */
244
+ setCurrentPage(index: number): boolean {
245
+ const pages = this._pages();
246
+ const target = index < 0 ? pages.length - 1 : index;
247
+ const child = pages[target];
248
+ if (!child) return false;
249
+ return this._switchTo(child);
250
+ }
251
+
252
+ /** `gtk_notebook_append_page` (gtknotebook.c:5807-5870) — the child is the page. */
253
+ appendPage(child: HTMLElement, tabLabel?: string | null): number {
254
+ return this.insertPage(child, -1, tabLabel);
255
+ }
256
+
257
+ /**
258
+ * `gtk_notebook_insert_page` (gtknotebook.c:5807-5870). A negative `position` means
259
+ * the end, which is what `append_page` passes.
260
+ */
261
+ insertPage(child: HTMLElement, position: number, tabLabel?: string | null): number {
262
+ const index = position < 0 ? this._pages().length : position;
263
+ if (tabLabel !== undefined && tabLabel !== null) child.setAttribute('tab-label', tabLabel);
264
+ this._initChild(child);
265
+ this.insertBefore(child, this._pages()[index] ?? null);
266
+ this.dispatchEvent(
267
+ new CustomEvent('page-added', { bubbles: true, detail: { position: index, nPages: this._pages().length } }),
268
+ );
269
+ // `if (!gtk_notebook_has_current_page (notebook)) gtk_notebook_switch_page (…)`
270
+ // (gtknotebook.c:4131-4134), so an inserted page only becomes the current one
271
+ // while the notebook has none.
272
+ if (!this._current) this._switchTo(child);
273
+ this._render();
274
+ return index;
275
+ }
276
+
277
+ /** `gtk_notebook_remove_page` (gtknotebook.c:5899-5932). */
278
+ removePage(child: HTMLElement): boolean {
279
+ const index = this._pages().indexOf(child);
280
+ if (index === -1) return false;
281
+ if (child === this._current) this._current = null;
282
+ child.remove();
283
+ this.dispatchEvent(
284
+ new CustomEvent('page-removed', {
285
+ bubbles: true,
286
+ detail: { position: index, nPages: this._pages().length },
287
+ }),
288
+ );
289
+ // The current page went away with it, so a neighbour takes over — C searches
290
+ // `STEP_NEXT` and falls back to `STEP_PREV` at the end, both with `find_visible`
291
+ // TRUE, so it is the page that FOLLOWED rather than the first one, and a hidden
292
+ // page is stepped over rather than refused (gtknotebook.c:4281-4290).
293
+ if (!this._current) this._takeOver(index);
294
+ this._render();
295
+ return true;
296
+ }
297
+
298
+ /** Rebuild the tabs by hand, for a consumer that mutated a page in place. */
299
+ refresh(): void {
300
+ this._render();
301
+ }
302
+
303
+ connectedCallback() {
304
+ if (this._initialized) {
305
+ this._observer = new MutationObserver((records) => this._onMutations(records));
306
+ } else {
307
+ this._initialized = true;
308
+ this._header = document.createElement('div');
309
+ // libadwaita's node tree is `notebook > header > tabs > tab`
310
+ // (refs/libadwaita/src/stylesheet/widgets/_notebook.scss:4-10), so the
311
+ // element builds the same two levels rather than a flat row.
312
+ this._header.className = 'adw-notebook-header';
313
+ this._tabs = document.createElement('div');
314
+ this._tabs.className = 'adw-notebook-tabs';
315
+ this._tabs.setAttribute('role', 'tablist');
316
+ this._header.appendChild(this._tabs);
317
+ for (const child of this._pages()) this._initChild(child);
318
+ }
319
+ if (this._header.parentNode !== this) {
320
+ // The header comes FIRST in the DOM whatever `tab-pos` says — C lays the
321
+ // header out on the edge the tabs are on, which is a rendering decision, not
322
+ // a document-order one (gtknotebook.c:1533-1544: the stack and the tabs are parented to
323
+ // the notebook, and the edge is read at layout time by `get_effective_tab_pos`).
324
+ this.prepend(this._header);
325
+ }
326
+ this._observer?.observe(this, {
327
+ childList: true,
328
+ subtree: true,
329
+ attributes: true,
330
+ attributeFilter: [...PAGE_ATTRIBUTES, 'hidden'],
331
+ });
332
+ if (!this._current) this._switchTo(this._firstVisible());
333
+ this.addEventListener('contextmenu', this._onContextMenu);
334
+ this._render();
335
+ }
336
+
337
+ disconnectedCallback() {
338
+ this._observer?.disconnect();
339
+ this._observer = null;
340
+ this.removeEventListener('contextmenu', this._onContextMenu);
341
+ this._closeMenu();
342
+ // `_initialized` STAYS true: a widget that is removed from the tree keeps the
343
+ // children it had, and a header rebuilt on the way back in would be a second one
344
+ // left behind — which the page list, that filters out the header by identity,
345
+ // would then read as a page.
346
+ }
347
+
348
+ attributeChangedCallback(name: string) {
349
+ if (!this._initialized) return;
350
+ if (name === 'page') {
351
+ // The ATTRIBUTE is the input here — `set_property` is
352
+ // `gtk_notebook_set_current_page (notebook, g_value_get_int (value))`
353
+ // (gtknotebook.c:1940-1942) — and `page` reads the live index, so parsing the
354
+ // raw string is what keeps the two apart.
355
+ const raw = this.getAttribute(name);
356
+ if (raw !== null) this.setCurrentPage(Number.parseInt(raw, 10));
357
+ return;
358
+ }
359
+ this._render();
360
+ this._notify(name);
361
+ }
362
+
363
+ /**
364
+ * `switch-page` is emitted BEFORE the switch (gtknotebook.c:5518-5523) and
365
+ * `real_switch_page` runs after it, so a listener sees the page being switched TO
366
+ * while `page` still reads the old one — the order C's own handlers rely on.
367
+ */
368
+ private _switchTo(child: HTMLElement): boolean {
369
+ const pages = this._pages();
370
+ const index = pages.indexOf(child);
371
+ if (index === -1) return false;
372
+ // `!gtk_widget_get_visible (child)` (gtknotebook.c:5444) — the page flag AND
373
+ // the widget's own visibility, which is the DOM's `hidden` here.
374
+ if (!this._page(child).visible) return false;
375
+ if (this._current === child) return false;
376
+ const event = new CustomEvent('switch-page', {
377
+ bubbles: true,
378
+ cancelable: true,
379
+ detail: { page: index, child },
380
+ });
381
+ this.dispatchEvent(event);
382
+ // A handler that stops the emission keeps the switch from happening: `switch-page`
383
+ // is `G_SIGNAL_RUN_LAST`, so `real_switch_page` IS the default handler and
384
+ // `g_signal_stop_emission` from a listener is what holds it back. `preventDefault`
385
+ // is that call's spelling here — cancelling the event, not the propagation, so
386
+ // every other listener still runs.
387
+ if (event.defaultPrevented) return false;
388
+ this._current = child;
389
+ this._render();
390
+ // `g_object_notify_by_pspec (…, PROP_PAGE)` (gtknotebook.c:5497).
391
+ this._notify('page');
392
+ return true;
393
+ }
394
+
395
+ private _notify(name: string): void {
396
+ this.dispatchEvent(
397
+ new CustomEvent(`notify::${name}`, { bubbles: true, detail: { [name]: this._property(name) } }),
398
+ );
399
+ }
400
+
401
+ private _property(name: string): string | number | boolean | null {
402
+ switch (name) {
403
+ case 'page':
404
+ return this.page;
405
+ case 'tab-pos':
406
+ return this.tabPos;
407
+ case 'show-tabs':
408
+ return this.showTabs;
409
+ case 'show-border':
410
+ return this.showBorder;
411
+ case 'scrollable':
412
+ return this.scrollable;
413
+ case 'enable-popup':
414
+ return this.enablePopup;
415
+ default:
416
+ return this.groupName;
417
+ }
418
+ }
419
+
420
+ private _write(name: string, value: string | null): void {
421
+ if (value === null) this.removeAttribute(name);
422
+ else if (this.getAttribute(name) !== value) this.setAttribute(name, value);
423
+ }
424
+
425
+ /** A boolean property with a non-false default: absent means the default. */
426
+ private _flag(name: string, fallback: boolean): boolean {
427
+ const raw = this.getAttribute(name);
428
+ if (raw === null) return fallback;
429
+ return raw !== 'false';
430
+ }
431
+
432
+ /** The children, in page order — the header is the widget's own, never a page. */
433
+ private _pages(): HTMLElement[] {
434
+ return Array.from(this.children).filter((child) => child !== this._header) as HTMLElement[];
435
+ }
436
+
437
+ private _page(child: HTMLElement): NotebookPageInfo {
438
+ return {
439
+ tabLabel: child.getAttribute('tab-label'),
440
+ menuLabel: child.getAttribute('menu-label'),
441
+ // `tab-fill` defaults TRUE and `tab-expand` FALSE (gtknotebook.c:663-681).
442
+ tabFill: child.getAttribute('tab-fill') !== 'false',
443
+ tabExpand: child.hasAttribute('tab-expand'),
444
+ reorderable: child.hasAttribute('reorderable'),
445
+ detachable: child.hasAttribute('detachable'),
446
+ visible: !child.hasAttribute('hidden'),
447
+ child,
448
+ };
449
+ }
450
+
451
+ private _initChild(child: HTMLElement): void {
452
+ if (this._initializedChildren.has(child)) return;
453
+ this._initializedChildren.add(child);
454
+ child.classList.add('adw-notebook-page');
455
+ }
456
+
457
+ private _firstVisible(): HTMLElement | null {
458
+ return this._pages().find((child) => this._page(child).visible) ?? null;
459
+ }
460
+
461
+ /**
462
+ * `gtk_notebook_search_page` with `find_visible` TRUE (gtknotebook.c:4412-4470): walk
463
+ * from the current page in `direction`, skipping every page whose child is hidden, and
464
+ * switch to the first one that takes. Off either end there is nothing, which is the
465
+ * FALSE both `next_page` and `prev_page` return.
466
+ */
467
+ private _searchPage(direction: 1 | -1): boolean {
468
+ const pages = this._pages();
469
+ const start = this._current ? pages.indexOf(this._current) : -1;
470
+ for (let i = start + direction; i >= 0 && i < pages.length; i += direction) {
471
+ if (this._switchTo(pages[i])) return true;
472
+ }
473
+ return false;
474
+ }
475
+
476
+ /**
477
+ * The neighbour a REMOVAL hands the notebook to: the pages that followed the removed
478
+ * one, then the pages that came before it — `search_page (…, STEP_NEXT, TRUE)` and
479
+ * then `search_page (…, STEP_PREV, TRUE)` (gtknotebook.c:4281-4282), which is a wrap
480
+ * rather than a one-way walk. `position` is where the removed page WAS.
481
+ */
482
+ private _takeOver(position: number): boolean {
483
+ const pages = this._pages();
484
+ for (const page of [...pages.slice(position), ...pages.slice(0, position)]) {
485
+ if (this._switchTo(page)) return true;
486
+ }
487
+ return false;
488
+ }
489
+
490
+ private _onMutations(records: MutationRecord[]): void {
491
+ // THE PAGE AREA ONLY, and the filter is load-bearing rather than tidiness. This
492
+ // observer watches the subtree, and the render pass writes INTO it: `hidden` and
493
+ // `textContent` on the tabs, `replaceChildren` on the strip. `setAttribute` queues a
494
+ // record even when the value is unchanged, and assigning `textContent` always
495
+ // replaces the text node, so a record from the strip went straight back into
496
+ // `_render()` and never stopped — a frozen page rather than a failing test, which is
497
+ // how this presented. `subtree: true` is what makes those records reachable at all;
498
+ // this is what keeps them out. What IS ours is the notebook's own child list — a page
499
+ // in or out — and a page's attributes, which is exactly the two targets below.
500
+ const pages = new Set(this._pages());
501
+ const pageRecords = records.filter(
502
+ (record) => record.target === this || pages.has(record.target as HTMLElement),
503
+ );
504
+ // …and a batch with nothing of ours in it gets NO render pass. That early return is
505
+ // the half that actually stops the feedback: filtering the records only keeps the
506
+ // bookkeeping out, while a `_render()` at the end of EVERY batch rewrote the strip
507
+ // and queued the next one, so the loop kept running on batches already empty.
508
+ if (pageRecords.length === 0) return;
509
+ let added = 0;
510
+ let removed = 0;
511
+ const updated: Element[] = [];
512
+ for (const record of pageRecords) {
513
+ if (record.type === 'childList') {
514
+ for (const node of Array.from(record.removedNodes)) {
515
+ if (node === this._current) this._current = null;
516
+ removed += 1;
517
+ }
518
+ for (const node of Array.from(record.addedNodes)) {
519
+ if (!(node instanceof HTMLElement) || node === this._header) continue;
520
+ this._initChild(node);
521
+ added += 1;
522
+ }
523
+ continue;
524
+ }
525
+ const name = record.attributeName;
526
+ if (name === 'hidden') {
527
+ if (!this._current || !this._page(this._current).visible) this._switchTo(this._firstVisible());
528
+ continue;
529
+ }
530
+ if (name && PAGE_ATTRIBUTES.includes(name)) updated.push(record.target as HTMLElement);
531
+ }
532
+ if (added > 0 || removed > 0) {
533
+ this.dispatchEvent(new CustomEvent('items-changed', { bubbles: true, detail: { added, removed } }));
534
+ }
535
+ for (const child of updated) {
536
+ this.dispatchEvent(new CustomEvent('page-updated', { bubbles: true, detail: { child } }));
537
+ }
538
+ this._render();
539
+ }
540
+
541
+ /** Which edge the tabs are on, with RTL's left/right swap (gtknotebook.c:1741-1757). */
542
+ private _effectiveTabPos(): NotebookTabPos {
543
+ const pos = this.tabPos;
544
+ if (this.getAttribute('dir') !== 'rtl') return pos;
545
+ if (pos === 'left') return 'right';
546
+ if (pos === 'right') return 'left';
547
+ return pos;
548
+ }
549
+
550
+ private _render(): void {
551
+ if (!this._initialized) return;
552
+ const pages = this._pages();
553
+ if (pages.length !== this._tabNodes.length) {
554
+ this._tabs.replaceChildren();
555
+ this._tabNodes = pages.map(() => this._buildTab());
556
+ this._tabs.append(...this._tabNodes);
557
+ }
558
+ const currentIndex = this._current ? pages.indexOf(this._current) : -1;
559
+ // `gtk_notebook_update_labels` numbers the tabs ONE-BASED and only over the
560
+ // VISIBLE ones — `gtk_notebook_search_page (…, STEP_NEXT, FALSE)` steps over a
561
+ // hidden page — and a page with no `tab-label` gets that number AS ITS TEXT rather
562
+ // than no tab at all (gtknotebook.c:4353-4373).
563
+ let pageNumber = 0;
564
+ pages.forEach((page, index) => {
565
+ const tab = this._tabNodes[index];
566
+ if (!tab) return;
567
+ const info = this._page(page);
568
+ const selected = index === currentIndex;
569
+ if (info.visible) pageNumber += 1;
570
+ // The two writes below are GUARDED, and that is not an optimisation: each is a
571
+ // mutation the observer would be handed (`textContent` always replaces the text
572
+ // node, `setAttribute` queues a record even for an unchanged value), so an
573
+ // unguarded write makes a render pass able to trigger the next one. C's own
574
+ // label pass only touches a label whose text differs
575
+ // (`page->default_tab` and `gtk_label_set_text`, gtknotebook.c:4380-4391).
576
+ const text = info.tabLabel ?? `Page ${pageNumber}`;
577
+ if (tab.textContent !== text) tab.textContent = text;
578
+ tab.classList.toggle('active', selected);
579
+ tab.classList.toggle('expand', info.tabExpand);
580
+ tab.classList.toggle('fill', info.tabFill);
581
+ tab.classList.toggle('reorderable', info.reorderable);
582
+ // `gtk_widget_set_visible (page->tab_label, show_tabs &&
583
+ // gtk_widget_get_visible (page->child))` (gtknotebook.c:4117-4118): a hidden
584
+ // page takes its tab with it, which is the other half of why
585
+ // `real_switch_page` refuses a hidden page at all.
586
+ const hidden = !info.visible;
587
+ if (tab.hidden !== hidden) tab.hidden = hidden;
588
+ tab.setAttribute('aria-selected', String(selected));
589
+ page.classList.toggle('visible-page', selected);
590
+ if (selected) page.removeAttribute('aria-hidden');
591
+ else page.setAttribute('aria-hidden', 'true');
592
+ });
593
+ // `gtk_widget_set_visible (header_widget, show_tabs)` (gtknotebook.c:5467).
594
+ const headerHidden = !this.showTabs;
595
+ if (this._header.hidden !== headerHidden) this._header.hidden = headerHidden;
596
+ const tabPos = this._effectiveTabPos();
597
+ if (this.getAttribute('data-tab-pos') !== tabPos) this.setAttribute('data-tab-pos', tabPos);
598
+ // `show-border` IS the `.frame` class in C — `gtk_notebook_set_show_border` adds it
599
+ // and clearing the property removes it (gtknotebook.c:6134-6146) — and this
600
+ // stylesheet already carries libadwaita's rule for the class (`_misc.scss:4-7`,
601
+ // ported whole in `_style_classes.scss`), so this is the same mechanism rather than
602
+ // a private spelling of it.
603
+ this.classList.toggle('frame', this.showBorder);
604
+ }
605
+
606
+ private _buildTab(): HTMLButtonElement {
607
+ const tab = document.createElement('button');
608
+ tab.type = 'button';
609
+ tab.className = 'adw-notebook-tab';
610
+ tab.setAttribute('role', 'tab');
611
+ tab.addEventListener('click', () => {
612
+ const index = this._tabNodes.findIndex((candidate) => candidate === tab);
613
+ if (index === -1) return;
614
+ const page = this._pages()[index];
615
+ if (page) this._switchTo(page);
616
+ });
617
+ return tab;
618
+ }
619
+
620
+ /**
621
+ * `enable-popup`'s right-click menu (`gtk_notebook_popup_enable`,
622
+ * gtknotebook.c:6420-6462 builds it and `gtk_notebook_popup_menu` at :2684-2692 pops
623
+ * it up) as a DOM listbox of
624
+ * the same pages. C builds it with `gtk_menu_model` and a GtkPopover; the page set
625
+ * and the selection are the same, the widget is not.
626
+ */
627
+ private readonly _onContextMenu = (event: Event): void => {
628
+ if (!this.enablePopup) return;
629
+ event.preventDefault();
630
+ this._closeMenu();
631
+ const menu = document.createElement('div');
632
+ menu.className = 'adw-notebook-menu';
633
+ menu.setAttribute('role', 'listbox');
634
+ let pageNumber = 0;
635
+ for (const page of this._pages()) {
636
+ const info = this._page(page);
637
+ if (info.visible) pageNumber += 1;
638
+ const item = document.createElement('button');
639
+ item.type = 'button';
640
+ item.className = 'adw-notebook-menu-item';
641
+ item.setAttribute('role', 'option');
642
+ // `gtk_notebook_menu_item_create` builds the label from `menu_label`, falls
643
+ // back to the tab label when the tab label IS a GtkLabel, and hides the item
644
+ // for a page whose child is hidden (gtknotebook.c:5624-5649).
645
+ item.textContent = info.menuLabel ?? info.tabLabel ?? `Page ${pageNumber}`;
646
+ item.hidden = !info.visible;
647
+ item.setAttribute('aria-selected', String(page === this._current));
648
+ item.addEventListener('click', () => {
649
+ this._switchTo(page);
650
+ this._closeMenu();
651
+ });
652
+ menu.appendChild(item);
653
+ }
654
+ this.appendChild(menu);
655
+ this._menu = menu;
656
+ };
657
+
658
+ private _closeMenu(): void {
659
+ this._menu?.remove();
660
+ this._menu = null;
661
+ }
662
+ }
663
+
664
+ customElements.define('gtk-notebook', GtkNotebook);