@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,542 @@
1
+ // <gtk-emoji-chooser> — the browser counterpart of `GtkEmojiChooser`, GTK's emoji
2
+ // popover: a search entry over a scrolled list of emoji in ten sections (recent first),
3
+ // with a toolbar of section buttons that both JUMP to a section (`scroll_to_section`) and
4
+ // follow the scroll position (`adj_value_changed`), and an `emoji-picked` signal.
5
+ //
6
+ // The SURFACE is `<gtk-popover>`'s — this element extends `GtkPopover`, so the surface
7
+ // node, the Escape dismissal, the outside-click popdown and the focus return are the ones
8
+ // `gtk-popover.ts` already owns, and the CSS-node contract upstream names (`popover`,
9
+ // `.emoji-searchbar`, `.emoji-toolbar`, `.emoji-section`, `emoji`) is reproduced by the
10
+ // class names below rather than by a second surface.
11
+ //
12
+ // WHAT IS PORTED FROM `gtkemojichooser.c`
13
+ //
14
+ // · the CSS node tree (the `ui/gtkemojichooser.ui` template): a searchbar box holding
15
+ // the entry, a stack of `list` / `empty`, a scrolled `.view` holding one flow box per
16
+ // section with a heading label above each, and a toolbar of `.emoji-section` buttons;
17
+ // · `filter_func` (:896-958) + `match_tokens` (:871-894): the search text is tokenised,
18
+ // case-folded, and an emoji matches when EVERY term is a PREFIX of a token of its name
19
+ // or of one of its keywords. Empty text matches everything
20
+ // (`if (text[0] == 0) goto out`);
21
+ // · `search_changed` (:991) + `update_headings` (:967): a section with no match hides
22
+ // its heading AND its emoji, and a search that empties every section shows the
23
+ // "No Results Found" page instead of the list;
24
+ // · `emoji_activated` (:449-486): picking an emoji emits `emoji-picked` with the text,
25
+ // records it in the recent list unless it came FROM the recent list, and pops the
26
+ // popover down — unless Ctrl is held, which keeps it open to pick several;
27
+ // · `add_recent_item` (:390-447): the recent list is at most `MAX_RECENT` (21) entries,
28
+ // an entry already in it moves to the front, and the section's button becomes
29
+ // sensitive and the section visible (both of which it only does on a NON-empty list);
30
+ // · `gtk_emoji_chooser_scroll_section` (:1198) behind Ctrl+N / Ctrl+P
31
+ // (`gtk_widget_class_add_binding_action`, :1452-1456) and `activate_search` (:1019),
32
+ // which picks the first result of the first non-empty section;
33
+ // · `adj_value_changed` (:814-870): the section whose heading the scroll position has
34
+ // passed is the CHECKED one and every other button is unchecked;
35
+ // · `gtk_emoji_chooser_show` (:1122-1133): showing the popover resets the scroll
36
+ // position to 0 and CLEARS the search text, which is why re-opening starts over;
37
+ // · `has_variations` (:489) / `show_variations` (:508-548): a SECOND click on an emoji
38
+ // that carries a skin-tone slot opens the six variants beside it, and picking one of
39
+ // them picks that variant. GTK opens them with a long press or the third mouse button;
40
+ // a second click is the same affordance where a long press is not available.
41
+ //
42
+ // NOT PORTED, and it is not a browser limit: the emoji table itself. GTK's is a compiled
43
+ // 1.2 MB GVariant per language, so `src/emoji-data.ts` carries a curated table with the
44
+ // same shape; every rule above runs on it unchanged.
45
+ //
46
+ // Attributes: `open`, `position`, `align`, `role`, `menu` from `<gtk-popover>`. This
47
+ // element adds NONE of its own — `GtkEmojiChooser` declares no properties in the GIR.
48
+ //
49
+ // Events: `emoji-picked` (bubbling CustomEvent, detail `{ text }`), plus the popover's
50
+ // `notify::open` and `popover-item-activated`.
51
+ //
52
+ // A11y: the surface is a `listbox` (a grid of choices, not a menu), each emoji is a
53
+ // `button` labelled with the English name — the name the search reads — and the section
54
+ // headings are headings rather than presentational labels.
55
+ //
56
+ // Reference: refs/gtk/gtk/gtkemojichooser.c (every rule above, by line)
57
+ // Reference: refs/gtk/gtk/ui/gtkemojichooser.ui (the node tree, the headings, the tooltips)
58
+ // Reference: refs/libadwaita/src/stylesheet/widgets/_emoji-chooser.scss
59
+ // Copyright (c) 2021-2024 The GTK authors. LGPLv2.1+.
60
+ // Modifications: Implemented as a Web Component for @gjsify/adwaita-web; the surface is
61
+ // <gtk-popover>; the emoji table is packages/web/adwaita-web/src/emoji-data.ts.
62
+
63
+ import {
64
+ EMOJI_CATEGORIES,
65
+ EMOJI_MAX_RECENT,
66
+ EMOJI_SKIN_TONES,
67
+ type EmojiEntry,
68
+ emojiTooltip,
69
+ hasVariations,
70
+ } from '../emoji-data.js';
71
+
72
+ import { createGtkImage } from './gtk-image.js';
73
+ import { GtkPopover } from './gtk-popover.js';
74
+
75
+ /** One section of the list: its heading, its flow box and its toolbar button. */
76
+ interface EmojiSection {
77
+ readonly id: string;
78
+ readonly heading: HTMLElement | null;
79
+ readonly box: HTMLDivElement;
80
+ readonly button: HTMLButtonElement | null;
81
+ /** `GtkFlowBox`'s `empty` latch: set by `invalidate_section`, cleared by any match. */
82
+ empty: boolean;
83
+ }
84
+
85
+ /** `BOX_SPACE` (gtkemojichooser.c:92) — the gap `scroll_to_section` leaves above a heading. */
86
+ const BOX_SPACE = 6;
87
+
88
+ export class GtkEmojiChooser extends GtkPopover {
89
+ private _built = false;
90
+ private _entry!: HTMLInputElement;
91
+ private _listEl!: HTMLDivElement;
92
+ private _emptyEl!: HTMLElement;
93
+ private _sections = new Map<string, EmojiSection>();
94
+ /** The entry a button was built from — `emoji-data` has no reverse lookup. */
95
+ private _entryOf = new WeakMap<HTMLElement, EmojiEntry>();
96
+ /** `recently-used-emoji` — the GSettings key, held in memory here (see the header). */
97
+ private _recent: EmojiEntry[] = [];
98
+ /**
99
+ * The Ctrl state `should_close` reads off the keyboard (:433-448). A DOM event's
100
+ * `ctrlKey` says what the key that caused IT was, and a `click` synthesised from a
101
+ * keyboard activation carries no modifier at all, so the state is tracked from the key
102
+ * events themselves — which is what `gdk_device_get_modifier_state` answers.
103
+ */
104
+ private _ctrl = false;
105
+
106
+ connectedCallback(): void {
107
+ super.connectedCallback();
108
+ if (this._built) return;
109
+ this._built = true;
110
+
111
+ // A grid of choices, not a menu: `role="listbox"` is what the popover's own rows
112
+ // (`popover-item-activated`) and the a11y layer are told to expect.
113
+ if (!this.hasAttribute('role')) this.setAttribute('role', 'listbox');
114
+
115
+ const root = document.createElement('div');
116
+ root.className = 'emoji-picker-root';
117
+ root.appendChild(this._buildSearchbar());
118
+
119
+ this._listEl = document.createElement('div');
120
+ this._listEl.className = 'emoji-list';
121
+ this._emptyEl = this._buildEmptyPage();
122
+ const stack = document.createElement('div');
123
+ stack.className = 'emoji-stack';
124
+ stack.append(this._listEl, this._emptyEl);
125
+ root.appendChild(stack);
126
+
127
+ this.replaceChildren(root);
128
+
129
+ // DOCUMENT ORDER IS SECTION ORDER: `recent.box` first, because the `.ui` puts it
130
+ // above the nine categories and `gtk_flow_box` wraps by DOM order.
131
+ const recentBox = document.createElement('div');
132
+ recentBox.className = 'emoji-flowbox emoji-recent-box';
133
+ recentBox.dataset.section = 'recent';
134
+ this._listEl.appendChild(recentBox);
135
+ this._sections.set('recent', { id: 'recent', heading: null, box: recentBox, button: null, empty: true });
136
+
137
+ this._buildSections();
138
+ this._buildToolbar(root);
139
+ this._renderRecents();
140
+
141
+ // `adj_value_changed` is connected to the scrolled window's adjustment in the C;
142
+ // the scroll event is the DOM's name for the same notification.
143
+ this._listEl.addEventListener('scroll', () => this._markSection(this._currentSection()));
144
+ this.addEventListener('keydown', (event) => (this._ctrl = event.ctrlKey));
145
+ this.addEventListener('keyup', (event) => (this._ctrl = event.ctrlKey));
146
+ // `gtk_emoji_chooser_show` (:1122-1133): the search is CLEARED and the list is back
147
+ // at the top every time the popover appears, which is why re-opening it starts over
148
+ // rather than continuing where the last search left off. The base class's own state
149
+ // change is what says it appeared — `popup()` is not the only way in.
150
+ this.subscribe((open) => {
151
+ if (!open) return;
152
+ this._entry.value = '';
153
+ this._filter();
154
+ this._listEl.scrollTop = 0;
155
+ this._markSection('recent');
156
+ });
157
+ this._markSection('recent');
158
+ }
159
+
160
+ /** The emoji picked most recently, newest first — what `recently-used-emoji` holds. */
161
+ get recentEmoji(): EmojiEntry[] {
162
+ return [...this._recent];
163
+ }
164
+
165
+ /**
166
+ * Pick an entry the flow box's `child-activated` would have delivered — which is what
167
+ * a consumer inserting an emoji from elsewhere needs, and what a test drives the recents
168
+ * with. `fromRecent` is `emoji_activated`'s own half of the recent check: an entry
169
+ * picked out of the recent list is not recorded a second time.
170
+ */
171
+ pick(entry: EmojiEntry, fromRecent = false): void {
172
+ this._activate(entry, null, fromRecent);
173
+ }
174
+
175
+ // ------------------------------------------------------------- building
176
+
177
+ /** The `.emoji-searchbar` box: the magnifying glyph and the search entry. */
178
+ private _buildSearchbar(): HTMLElement {
179
+ const bar = document.createElement('div');
180
+ bar.className = 'emoji-searchbar';
181
+
182
+ const icon = createGtkImage('edit-find', 'emoji-search-icon');
183
+
184
+ this._entry = document.createElement('input');
185
+ this._entry.type = 'search';
186
+ this._entry.className = 'emoji-search-entry';
187
+ this._entry.placeholder = 'Search emoji';
188
+ this._entry.setAttribute('aria-label', 'Search emoji');
189
+ // `search_changed` — every keystroke re-filters, and an empty search restores all.
190
+ this._entry.addEventListener('input', () => this._filter());
191
+ // `stop_search` is Escape and belongs to the popover; `activate_search` is Enter,
192
+ // and picks the first result of the first non-empty section.
193
+ this._entry.addEventListener('keydown', (event) => {
194
+ if (event.key === 'Enter') {
195
+ event.preventDefault();
196
+ this._activateFirstResult();
197
+ return;
198
+ }
199
+ // `gtk_widget_class_add_binding_action (…, GDK_KEY_n / GDK_KEY_p,
200
+ // GDK_CONTROL_MASK, "scroll.section", "i", ±1)` — the only two shortcuts the
201
+ // widget declares besides Enter.
202
+ if (event.ctrlKey && (event.key === 'n' || event.key === 'p')) {
203
+ event.preventDefault();
204
+ this._scrollSection(event.key === 'n' ? 1 : -1);
205
+ }
206
+ });
207
+
208
+ bar.append(icon, this._entry);
209
+ return bar;
210
+ }
211
+
212
+ /** The `empty` stack page: the big glyph and the two lines under it. */
213
+ private _buildEmptyPage(): HTMLElement {
214
+ const empty = document.createElement('div');
215
+ empty.className = 'emoji-empty';
216
+ empty.hidden = true;
217
+ empty.appendChild(createGtkImage('edit-find', 'emoji-empty-icon'));
218
+ const title = document.createElement('div');
219
+ title.className = 'emoji-empty-title';
220
+ title.textContent = 'No Results Found';
221
+ const hint = document.createElement('div');
222
+ hint.className = 'emoji-empty-hint';
223
+ hint.textContent = 'Try a different search';
224
+ empty.append(title, hint);
225
+ return empty;
226
+ }
227
+
228
+ /** One flow box per category, each under its own heading label. */
229
+ private _buildSections(): void {
230
+ for (const category of EMOJI_CATEGORIES) {
231
+ const heading = document.createElement('div');
232
+ heading.className = 'emoji-heading';
233
+ heading.textContent = category.heading;
234
+
235
+ const box = document.createElement('div');
236
+ box.className = 'emoji-flowbox';
237
+ box.dataset.section = category.id;
238
+ for (const entry of category.entries) box.appendChild(this._emojiButton(entry));
239
+
240
+ this._listEl.append(heading, box);
241
+ this._sections.set(category.id, { id: category.id, heading, box, button: null, empty: true });
242
+ }
243
+ }
244
+
245
+ /**
246
+ * The toolbar: one `.emoji-section` button per section, recent FIRST (the struct
247
+ * order), each with its own symbolic and the `.ui`'s tooltip.
248
+ *
249
+ * The icons are written out one call per section rather than looked up from a table:
250
+ * each name is USED there, which is what makes it a name this stylesheet has to be
251
+ * able to draw — `scripts/check-adwaita-icon-masks.mjs` reads exactly that.
252
+ */
253
+ private _buildToolbar(root: HTMLElement): void {
254
+ const toolbar = document.createElement('div');
255
+ toolbar.className = 'emoji-toolbar';
256
+
257
+ const buttons: Array<[string, HTMLButtonElement]> = [
258
+ [
259
+ 'recent',
260
+ this._sectionButton(
261
+ 'recent',
262
+ createGtkImage('emoji-recent', 'emoji-section-icon'),
263
+ emojiTooltip('recent'),
264
+ ),
265
+ ],
266
+ [
267
+ 'people',
268
+ this._sectionButton(
269
+ 'people',
270
+ createGtkImage('emoji-people', 'emoji-section-icon'),
271
+ emojiTooltip('people'),
272
+ ),
273
+ ],
274
+ [
275
+ 'body',
276
+ this._sectionButton('body', createGtkImage('emoji-body', 'emoji-section-icon'), emojiTooltip('body')),
277
+ ],
278
+ [
279
+ 'nature',
280
+ this._sectionButton(
281
+ 'nature',
282
+ createGtkImage('emoji-nature', 'emoji-section-icon'),
283
+ emojiTooltip('nature'),
284
+ ),
285
+ ],
286
+ [
287
+ 'food',
288
+ this._sectionButton('food', createGtkImage('emoji-food', 'emoji-section-icon'), emojiTooltip('food')),
289
+ ],
290
+ [
291
+ 'travel',
292
+ this._sectionButton(
293
+ 'travel',
294
+ createGtkImage('emoji-travel', 'emoji-section-icon'),
295
+ emojiTooltip('travel'),
296
+ ),
297
+ ],
298
+ [
299
+ 'activities',
300
+ this._sectionButton(
301
+ 'activities',
302
+ createGtkImage('emoji-activities', 'emoji-section-icon'),
303
+ emojiTooltip('activities'),
304
+ ),
305
+ ],
306
+ [
307
+ 'objects',
308
+ this._sectionButton(
309
+ 'objects',
310
+ createGtkImage('emoji-objects', 'emoji-section-icon'),
311
+ emojiTooltip('objects'),
312
+ ),
313
+ ],
314
+ [
315
+ 'symbols',
316
+ this._sectionButton(
317
+ 'symbols',
318
+ createGtkImage('emoji-symbols', 'emoji-section-icon'),
319
+ emojiTooltip('symbols'),
320
+ ),
321
+ ],
322
+ [
323
+ 'flags',
324
+ this._sectionButton(
325
+ 'flags',
326
+ createGtkImage('emoji-flags', 'emoji-section-icon'),
327
+ emojiTooltip('flags'),
328
+ ),
329
+ ],
330
+ ];
331
+
332
+ for (const [id, button] of buttons) {
333
+ button.addEventListener('click', () => this._scrollTo(id));
334
+ const section = this._sections.get(id);
335
+ if (section !== undefined) this._sections.set(id, { ...section, button });
336
+ }
337
+
338
+ toolbar.append(...buttons.map(([, button]) => button));
339
+ root.appendChild(toolbar);
340
+ }
341
+
342
+ /** `button.image-button.emoji-section` — flat, circular, 32px, with a tooltip. */
343
+ private _sectionButton(id: string, icon: HTMLElement, tooltip: string): HTMLButtonElement {
344
+ const button = document.createElement('button');
345
+ button.type = 'button';
346
+ button.className = 'emoji-section';
347
+ button.dataset.section = id;
348
+ button.title = tooltip;
349
+ button.setAttribute('aria-label', tooltip);
350
+ button.appendChild(icon);
351
+ return button;
352
+ }
353
+
354
+ /**
355
+ * One emoji: a `<button>` holding the glyph at `PANGO_SCALE_X_LARGE`, labelled with
356
+ * the English name — the name the search reads, so it is the accessible name too.
357
+ */
358
+ private _emojiButton(entry: EmojiEntry): HTMLButtonElement {
359
+ const button = document.createElement('button');
360
+ button.type = 'button';
361
+ button.className = 'emoji';
362
+ button.textContent = entry.text;
363
+ button.title = entry.name;
364
+ button.setAttribute('aria-label', entry.name);
365
+ this._entryOf.set(button, entry);
366
+ // `emoji_activated` (:449) — pick.
367
+ button.addEventListener('click', (event) => {
368
+ this._closeVariations();
369
+ // A second click on an emoji with skin tones opens them, which is what
370
+ // `pressed_cb` (:571) does with the third mouse button.
371
+ if (event.detail > 1 && hasVariations(entry)) {
372
+ this._showVariations(entry, button);
373
+ return;
374
+ }
375
+ this._activate(entry, button);
376
+ });
377
+ return button;
378
+ }
379
+
380
+ // ------------------------------------------------------------- behaviour
381
+
382
+ /** `filter_func` + `match_tokens`: EVERY term must be a PREFIX of a token of the name
383
+ * or of one of the keywords. `g_str_tokenize_and_fold` case-folds, hence lower-casing
384
+ * both sides. */
385
+ private _matches(entry: EmojiEntry, terms: readonly string[]): boolean {
386
+ if (terms.length === 0) return true;
387
+ const tokens = `${entry.name} ${entry.keywords.join(' ')}`.toLowerCase().split(/\s+/);
388
+ return terms.every((term) => tokens.some((token) => token.startsWith(term)));
389
+ }
390
+
391
+ /** `search_changed` — invalidate every section, then `update_headings`. */
392
+ private _filter(): void {
393
+ const terms = this._entry.value
394
+ .toLowerCase()
395
+ .split(/\s+/)
396
+ .filter((term) => term.length > 0);
397
+ for (const section of this._sections.values()) {
398
+ let matched = 0;
399
+ for (const node of section.box.querySelectorAll<HTMLButtonElement>('.emoji')) {
400
+ const entry = this._entryOf.get(node);
401
+ const show = entry !== undefined && this._matches(entry, terms);
402
+ node.hidden = !show;
403
+ if (show) matched += 1;
404
+ }
405
+ // `update_headings` (:967): a section with no match hides BOTH its heading and
406
+ // its emoji, and `empty` is what the section buttons read — an invisible
407
+ // section is not a jumpable one. The recent box is NOT in that function's
408
+ // list: its visibility is `populate_recent_section`'s alone (hidden while
409
+ // the list is empty, shown on the first pick), so filtering never hides it.
410
+ section.empty = matched === 0;
411
+ if (section.heading !== null) section.heading.hidden = section.empty;
412
+ if (section.id !== 'recent') section.box.hidden = section.empty;
413
+ }
414
+ // …and the stack shows `empty` when EVERY section is, `list` otherwise (:984-989).
415
+ const allEmpty = [...this._sections.values()].every((section) => section.empty);
416
+ this._listEl.hidden = allEmpty;
417
+ this._emptyEl.hidden = !allEmpty;
418
+ this._markSection(this._currentSection());
419
+ }
420
+
421
+ /** `emoji_activated` — emit, remember, and pop down unless Ctrl is held. */
422
+ private _activate(entry: EmojiEntry, from: HTMLElement | null, fromRecent = false): void {
423
+ if (!fromRecent && from?.parentElement?.dataset.section !== 'recent') this._remember(entry);
424
+ this.dispatchEvent(new CustomEvent('emoji-picked', { bubbles: true, detail: { text: entry.text } }));
425
+ // `should_close` (:433-448): Ctrl held means "keep picking", which is why the
426
+ // popover stays up — and why the entry keeps what was typed into it.
427
+ if (!this._ctrl) this.popdown();
428
+ }
429
+
430
+ /** `add_recent_item` (:390) — newest first, no duplicates, at most `MAX_RECENT`. */
431
+ private _remember(entry: EmojiEntry): void {
432
+ this._recent = [entry, ...this._recent.filter((candidate) => candidate.text !== entry.text)].slice(
433
+ 0,
434
+ EMOJI_MAX_RECENT,
435
+ );
436
+ this._renderRecents();
437
+ }
438
+
439
+ /** `populate_recent_section` (:366-388): the list, its visibility and its button. */
440
+ private _renderRecents(): void {
441
+ const section = this._sections.get('recent');
442
+ if (section === undefined) return;
443
+ section.box.replaceChildren(...this._recent.map((entry) => this._emojiButton(entry)));
444
+ const empty = this._recent.length === 0;
445
+ section.box.hidden = empty;
446
+ section.empty = empty;
447
+ if (section.button !== null) section.button.disabled = empty;
448
+ }
449
+
450
+ /**
451
+ * `show_variations` (:508-548): the plain form and the five skin tones
452
+ * (`add_emoji (box, FALSE, emoji_data, 0, …)` then `1F3FB`…`1F3FF`), in a popover over
453
+ * the emoji — and only for an emoji that HAS them, which is `has_variations` (:489).
454
+ */
455
+ private _showVariations(entry: EmojiEntry, anchor: HTMLElement): void {
456
+ this._closeVariations();
457
+ const popover = document.createElement('div');
458
+ popover.className = 'emoji-variations';
459
+ const row = document.createElement('div');
460
+ row.className = 'emoji-variations-row';
461
+ const base = [...entry.text].filter((character) => !EMOJI_SKIN_TONES.includes(character)).join('');
462
+ for (const text of [base, ...EMOJI_SKIN_TONES.map((tone) => base + tone)]) {
463
+ const variant = document.createElement('button');
464
+ variant.type = 'button';
465
+ variant.className = 'emoji';
466
+ variant.textContent = text;
467
+ variant.addEventListener('click', (event) => {
468
+ event.stopPropagation();
469
+ this._closeVariations();
470
+ this._activate({ ...entry, text }, variant);
471
+ });
472
+ row.appendChild(variant);
473
+ }
474
+ popover.appendChild(row);
475
+ anchor.insertAdjacentElement('afterend', popover);
476
+ }
477
+
478
+ private _closeVariations(): void {
479
+ for (const popover of this.querySelectorAll('.emoji-variations')) popover.remove();
480
+ }
481
+
482
+ /** `scroll_to_section` (:312-330) — to the heading, minus `BOX_SPACE`. */
483
+ private _scrollTo(id: string): void {
484
+ const section = this._sections.get(id);
485
+ if (section === undefined || section.empty) return;
486
+ const target = section.heading ?? section.box;
487
+ this._listEl.scrollTo({ top: target.offsetTop - BOX_SPACE, behavior: 'smooth' });
488
+ this._markSection(id);
489
+ }
490
+
491
+ /** `gtk_emoji_chooser_scroll_section` (:1198) — Ctrl+N / Ctrl+P over the visible ones. */
492
+ private _scrollSection(direction: 1 | -1): void {
493
+ const order = [...this._sections.values()].filter((section) => !section.empty);
494
+ if (order.length === 0) return;
495
+ const at = order.findIndex((section) => section.id === this._currentSection());
496
+ const next = order[Math.min(Math.max((at < 0 ? 0 : at) + direction, 0), order.length - 1)]!;
497
+ this._scrollTo(next.id);
498
+ }
499
+
500
+ /** `activate_search` (:1019) — the first result of the first non-empty section. */
501
+ private _activateFirstResult(): void {
502
+ for (const section of this._sections.values()) {
503
+ if (section.empty) continue;
504
+ const first = [...section.box.querySelectorAll<HTMLButtonElement>('.emoji')].find((node) => !node.hidden);
505
+ if (first === undefined) continue;
506
+ this._activate(
507
+ this._entryOf.get(first) ?? { text: first.textContent ?? '', name: '', keywords: [] },
508
+ first,
509
+ );
510
+ return;
511
+ }
512
+ }
513
+
514
+ /**
515
+ * `adj_value_changed` (:814-870): the section the scroll position is INSIDE is the
516
+ * checked one, so the toolbar follows the list without any interaction of its own.
517
+ */
518
+ private _sectionAt(offset: number): string {
519
+ let selected = 'recent';
520
+ for (const section of this._sections.values()) {
521
+ if (section.empty || section.box.hidden) continue;
522
+ const target = section.heading ?? section.box;
523
+ if (offset < target.offsetTop - BOX_SPACE) break;
524
+ selected = section.id;
525
+ }
526
+ return selected;
527
+ }
528
+
529
+ private _currentSection(): string {
530
+ return this._sectionAt(this._listEl.scrollTop);
531
+ }
532
+
533
+ private _markSection(id: string): void {
534
+ for (const section of this._sections.values()) {
535
+ // `:checked` is a state a `<button>` cannot raise, so the class stands in for
536
+ // it — the same spelling `<gtk-check-button>` uses for the same reason.
537
+ section.button?.classList.toggle('checked', section.id === id);
538
+ }
539
+ }
540
+ }
541
+
542
+ customElements.define('gtk-emoji-chooser', GtkEmojiChooser);
@@ -1,5 +1,6 @@
1
1
  // <gtk-entry> — Adwaita single-line text entry (e.g. a browser URL bar).
2
- // Attributes: value, placeholder, type, disabled, maxlength.
2
+ // Attributes: value, placeholder-text (`placeholder` is the older spelling and still read),
3
+ // width-request, type, disabled, maxlength.
3
4
  // Properties: value (get/set, proxies the inner input), maxLength, textLength.
4
5
  // Events: native `input` bubbles from the inner input; `activate` (CustomEvent)
5
6
  // fires on Enter — mirroring Gtk.Entry's `activate` signal.
@@ -22,12 +23,18 @@
22
23
  import { ENTRY_ROW_MAX_LENGTH_LIMIT, clampEntryText, entryTextLength } from '@gjsify/adwaita-core';
23
24
 
24
25
  export class GtkEntry extends HTMLElement {
25
- private _input!: HTMLInputElement;
26
+ /**
27
+ * `protected`, not `private`: `GtkPasswordEntry` and `GtkSearchEntry` subclass this
28
+ * element and restyle or wrap the very input it builds (the password field's Caps Lock
29
+ * and peek listeners, the search field's leading icon and trailing clear button), so the
30
+ * inner node is theirs to reach as well as this class's.
31
+ */
32
+ protected _input!: HTMLInputElement;
26
33
  private _initialized = false;
27
34
  private _maxLength = 0;
28
35
 
29
36
  static get observedAttributes() {
30
- return ['value', 'placeholder', 'type', 'disabled', 'maxlength'];
37
+ return ['value', 'placeholder-text', 'placeholder', 'width-request', 'type', 'disabled', 'maxlength'];
31
38
  }
32
39
 
33
40
  get value(): string {
@@ -57,6 +64,20 @@ export class GtkEntry extends HTMLElement {
57
64
  return entryTextLength(this.value);
58
65
  }
59
66
 
67
+ /**
68
+ * `Gtk.Entry:placeholder-text`, the name a Blueprint file and the gallery trees use.
69
+ * `placeholder` stays for markup written before the GTK spelling was read.
70
+ */
71
+ private placeholderAttribute(): string {
72
+ return this.getAttribute('placeholder-text') ?? this.getAttribute('placeholder') ?? '';
73
+ }
74
+
75
+ /** `Gtk.Widget:width-request` — a minimum width in px; -1 or absent leaves the natural one. */
76
+ private applyWidthRequest(): void {
77
+ const width = Number(this.getAttribute('width-request') ?? -1);
78
+ this.style.minWidth = Number.isFinite(width) && width > 0 ? `${width}px` : '';
79
+ }
80
+
60
81
  /** The inner native input (for focus/selection). */
61
82
  get input(): HTMLInputElement {
62
83
  return this._input;
@@ -72,7 +93,8 @@ export class GtkEntry extends HTMLElement {
72
93
  input.className = 'adw-entry';
73
94
  input.type = this.getAttribute('type') || 'text';
74
95
  input.value = clampEntryText(this.getAttribute('value') ?? '', this._maxLength);
75
- input.placeholder = this.getAttribute('placeholder') ?? '';
96
+ input.placeholder = this.placeholderAttribute();
97
+ this.applyWidthRequest();
76
98
  input.disabled = this.hasAttribute('disabled');
77
99
  // Typing past the limit is clamped here, on the way in — the same place
78
100
  // NativeScript clamps it, so both renderers refuse the same character.
@@ -90,14 +112,26 @@ export class GtkEntry extends HTMLElement {
90
112
  this.replaceChildren(input);
91
113
  }
92
114
 
115
+ /**
116
+ * Declared so a subclass can override it and still reach the base: the custom-element
117
+ * lifecycle hooks a subclass chains (`super.disconnectedCallback()`) have to exist on
118
+ * the class it extends, and `GtkSearchEntry` drops its pending search timeout here.
119
+ */
120
+ disconnectedCallback() {}
121
+
93
122
  attributeChangedCallback(name: string, _old: string | null, value: string | null) {
94
123
  if (name === 'maxlength') {
95
124
  this.maxLength = Number(value ?? 0);
96
125
  return;
97
126
  }
127
+ if (name === 'width-request') {
128
+ this.applyWidthRequest();
129
+ return;
130
+ }
98
131
  if (!this._input) return;
99
132
  if (name === 'value') this._input.value = clampEntryText(value ?? '', this._maxLength);
100
- else if (name === 'placeholder') this._input.placeholder = value ?? '';
133
+ else if (name === 'placeholder-text' || name === 'placeholder')
134
+ this._input.placeholder = this.placeholderAttribute();
101
135
  else if (name === 'type') this._input.type = value || 'text';
102
136
  else if (name === 'disabled') this._input.disabled = value !== null;
103
137
  }