@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,989 @@
1
+ // <adw-print-unix-dialog> — the browser counterpart of `GtkPrintUnixDialog`: the Unix
2
+ // print dialog, a notebook of General / Page Setup / Job / Image Quality / Color /
3
+ // Finishing / Advanced over a printer list, with the conflicts action bar and the
4
+ // Preview / Cancel / Print action area (gtkprintunixdialog.ui).
5
+ //
6
+ // THE REPLICA PRINTS NOTHING. A browser has no print backend, no CUPS over D-Bus and no
7
+ // spooler — `gtk_print_backend_load_modules` (:1274-1310) is what GTK reaches for, and
8
+ // none of it exists here. What this element ports is the DIALOG: its layout, its page
9
+ // set, and every derivation the C runs over a printer's capabilities and options. The
10
+ // buttons behave as GTK's do with no printer: Preview is hidden (no PREVIEW capability),
11
+ // Print is INSENSITIVE (`gtk_dialog_set_response_sensitive (…, GTK_RESPONSE_OK, FALSE)`
12
+ // is what `selected_printer_changed` :1842-1874 sets until a printer that accepts jobs is
13
+ // chosen), and the four option pages are the EMPTY grids the C leaves them in when
14
+ // `_gtk_printer_get_options` has no printer to ask.
15
+ //
16
+ // The DIALOG CHROME IS `<adw-dialog>`'s — this element extends it, so the scrim, the
17
+ // sheet, `present()`/`close()`, `can-close`, Escape, the Tab trap and the return-focus are
18
+ // the ones `adw-dialog.ts` owns, and there is no `aria-modal` below.
19
+ //
20
+ // WHAT IS PORTED FROM `gtkprintunixdialog.c`
21
+ //
22
+ // · `update_dialog_from_capabilities` (:1563-1592): every sensitive control is gated on
23
+ // `manual_capabilities | printer_capabilities`, `collate` additionally needs a copies
24
+ // count above 1 (`atoi (copies) > 1`), and the Preview button is VISIBLE — not merely
25
+ // insensitive — only with the PREVIEW capability;
26
+ // · `set_current_page` (:3059-3073): "Current Page" is sensitive only for a page that is
27
+ // not -1;
28
+ // · `set_support_selection` / `set_has_selection` (:3325-3405): the Selection radio is
29
+ // VISIBLE only when the application supports printing a selection, and sensitive only
30
+ // when it also HAS one;
31
+ // · `update_page_range_entry_sensitivity` (:1962-1972) and
32
+ // `page_range_entry_focus_changed` (:1951-1960): picking "Pages:" focuses the entry,
33
+ // and focusing the entry picks "Pages:";
34
+ // · `update_print_at_entry_sensitivity` (:1974-1989): the same pair for "At:";
35
+ // · `update_collate_icon` (:1920-1949): the four page thumbnails' NUMBERS depend on
36
+ // collate and reverse, and the second COLUMN is visible only when the copies count is
37
+ // above 1 — which is the one piece of the print dialog that explains itself;
38
+ // · `selected_printer_changed` (:1821-1915): choosing a printer that accepts jobs makes
39
+ // Print sensitive, and its capabilities become the second half of every gate above;
40
+ // · `gtk_print_unix_dialog_new` (:2961-2972): a NULL title means "Print";
41
+ // · `draw_page` (:2283-2681) for the Page Setup preview: the sheet scaled to
42
+ // `EXAMPLE_PAGE_AREA_SIZE` (110px), divided by the number-up grid — 1, 2, 4, 6, 9 or 16
43
+ // pages, flipping for 2 and 6 — and each cell numbered in the number-up ORDER. The
44
+ // ruler and its two dimension captions the C draws around it are the part not painted
45
+ // here: they are decoration outside the sheet, and the mm caption is on the label.
46
+ //
47
+ // Attributes (the GObject property names, hyphenated): `current-page`, `embed-page-setup`,
48
+ // `has-selection`, `manual-capabilities`, `support-selection`, plus `title`, `open`,
49
+ // `can-close`, `content-width`, `content-height`, `presentation-mode`, `show-header` from
50
+ // the chrome. `manual-capabilities` takes the nick SET the GIR generates, `|`-separated —
51
+ // `manual-capabilities="page-set|copies|collate|reverse|scale|preview"`.
52
+ //
53
+ // Properties with no attribute form: `pageSetup` and `printSettings` (`GtkPageSetup` /
54
+ // `GtkPrintSettings` OBJECTS, carried as the plain data `src/page-setup.ts` defines),
55
+ // `printerOptions` (the per-printer option widgets GTK fills from the backend — see the
56
+ // header), and `printers` (the list a backend would have discovered; an INPUT here).
57
+ // `selectedPrinter` is read-only, as in the C.
58
+ //
59
+ // Events: the base class's `notify::open` (`{ open }`) and `closed`, plus `response`
60
+ // (detail `{ responseId }`) — GTK_RESPONSE_APPLY (-10, "Pre_view"), GTK_RESPONSE_CANCEL
61
+ // (-6) and GTK_RESPONSE_OK (-5, "_Print"), the three `gtk_dialog_add_buttons` passes.
62
+ //
63
+ // A11y: role `dialog` from `AdwModalSurface`; the notebook is a tab list over `tabpanel`
64
+ // roles, the printer rows are radios, and every control has the label the `.ui` gives it.
65
+ //
66
+ // Reference: refs/gtk/gtk/print/gtkprintunixdialog.c (every rule above, by line)
67
+ // Reference: refs/gtk/gtk/print/ui/gtkprintunixdialog.ui (the notebook, the groups,
68
+ // the group headings, the radio labels, the action area)
69
+ // Reference: refs/libadwaita/src/stylesheet/widgets/_dialogs.scss:9-34
70
+ // (`window.print:not(.ssd-frame)`: the `drawing` node, white `paper` with
71
+ // `background-clip: padding-box` and a 1px `$border_color` border, a FLAT titlebar and
72
+ // a `.view` `.dialog-action-box`)
73
+ // Copyright (c) 2006-2024 Red Hat, Inc. / The GTK authors. LGPLv2.1+.
74
+ // Modifications: Implemented as a Web Component for @gjsify/adwaita-web; the page setup is
75
+ // the plain data of packages/web/adwaita-web/src/page-setup.ts; nothing prints.
76
+
77
+ import {
78
+ type PageOrientation,
79
+ type PageSetup,
80
+ COMMON_PAPER_SIZES,
81
+ defaultMargins,
82
+ defaultPageSetup,
83
+ orientedSize,
84
+ paperSizeOf,
85
+ } from '../page-setup.js';
86
+
87
+ import { AdwDialog } from './adw-dialog.js';
88
+ import { createGtkImage } from './gtk-image.js';
89
+
90
+ /** The three action-area response ids `gtk_dialog_add_buttons` passes. */
91
+ const RESPONSE_APPLY = -10;
92
+ const RESPONSE_CANCEL = -6;
93
+ const RESPONSE_OK = -5;
94
+
95
+ /** The `GtkPrintCapabilities` nicks, in enum order (the GIR's own spelling). */
96
+ const CAPABILITY_NICKS = [
97
+ 'collate',
98
+ 'copies',
99
+ 'generate-pdf',
100
+ 'generate-ps',
101
+ 'number-up',
102
+ 'number-up-layout',
103
+ 'page-set',
104
+ 'preview',
105
+ 'reverse',
106
+ 'scale',
107
+ ] as const;
108
+
109
+ /** One `GtkPrintCapabilities` nick. */
110
+ export type PrintCapability = (typeof CAPABILITY_NICKS)[number];
111
+
112
+ /** The seven notebook tabs, in the `.ui`'s order. */
113
+ const TABS = ['General', 'Page Setup', 'Job', 'Image Quality', 'Color', 'Finishing', 'Advanced'] as const;
114
+ type PrintTab = (typeof TABS)[number];
115
+
116
+ /** `page_set_combo`'s three models, in the `.ui`'s order. */
117
+ const PAGE_SET_ITEMS = ['All sheets', 'Even sheets', 'Odd sheets'];
118
+
119
+ /** `orientation_combo`'s four models, in the `.ui`'s order. */
120
+ const ORIENTATION_ITEMS: PageOrientation[] = ['portrait', 'landscape', 'reverse-portrait', 'reverse-landscape'];
121
+
122
+ /** One row of the printer list — what `GtkPrinter` answers name / location / icon for. */
123
+ export interface PrinterInfo {
124
+ readonly name: string;
125
+ readonly location?: string;
126
+ /** The `.ui`'s icon column, from the printer's own `icon-name`. */
127
+ readonly iconName?: string;
128
+ /** `gtk_printer_is_accepting_jobs` — what gates the Print button. */
129
+ readonly acceptsJobs?: boolean;
130
+ /** `gtk_printer_get_capabilities` — the second half of every sensitivity gate. */
131
+ readonly capabilities?: readonly PrintCapability[];
132
+ /** Whether the row passes `is_printer_active` (:1164-1186). */
133
+ readonly active?: boolean;
134
+ }
135
+
136
+ /** The `Gtk.PrintSettings` this dialog carries, in the keys its own UI sets. */
137
+ export interface PrintSettingsData {
138
+ /** `format-for-printer` — the printer the settings belong to. */
139
+ readonly 'format-for-printer'?: string;
140
+ /** `copies` — a string, because `GtkPrintSettings` values are all strings. */
141
+ readonly copies?: string;
142
+ /** `collate` / `reverse` — `"0"` or `"1"`, as CUPS writes them. */
143
+ readonly collate?: string;
144
+ readonly reverse?: string;
145
+ /** `page-set` — `all` / `even` / `odd`, the index into `PAGE_SET_ITEMS`. */
146
+ readonly 'page-set'?: string;
147
+ /** `scale` — a percentage, as a string. */
148
+ readonly scale?: string;
149
+ /** `orientation` — `portrait` … `reverse-landscape`. */
150
+ readonly orientation?: string;
151
+ /** `print-at` — an ISO timestamp for the "At:" branch. */
152
+ readonly 'print-at'?: string;
153
+ /** `printer-setting-…` — the per-printer option groups of the Job tab. */
154
+ readonly [key: string]: string | undefined;
155
+ }
156
+
157
+ /**
158
+ * `GtkPrintUnixDialog`'s default settings, from `gtk_print_unix_dialog_init` (:875-905) and
159
+ * `update_dialog_from_settings`: copies 1, collate and reverse off, scale 100, all sheets,
160
+ * portrait, and nothing scheduled.
161
+ */
162
+ const DEFAULT_SETTINGS: PrintSettingsData = {
163
+ copies: '1',
164
+ collate: '0',
165
+ reverse: '0',
166
+ 'page-set': '0',
167
+ scale: '100',
168
+ orientation: 'portrait',
169
+ };
170
+
171
+ export class GtkPrintUnixDialog extends AdwDialog {
172
+ private _built = false;
173
+ private _printers: PrinterInfo[] = [];
174
+ private _selected: PrinterInfo | null = null;
175
+ private _settings: PrintSettingsData = { ...DEFAULT_SETTINGS };
176
+ private _pageSetup: PageSetup = defaultPageSetup();
177
+ private _printerListEl!: HTMLElement;
178
+ private _switcherEl!: HTMLDivElement;
179
+ private _panelEl!: HTMLElement;
180
+ private _tabPages = new Map<PrintTab, HTMLElement>();
181
+ private _tab: PrintTab = 'General';
182
+ private _currentPage = -1;
183
+ private _supportSelection = false;
184
+ private _hasSelection = false;
185
+ private _manual: Set<PrintCapability> = new Set();
186
+ private _range: 'all' | 'current' | 'selection' | 'pages' = 'all';
187
+ private _printAt: 'now' | 'at' | 'hold' = 'now';
188
+ private _printButton!: HTMLButtonElement;
189
+ private _previewButton!: HTMLButtonElement;
190
+ private _conflictsEl!: HTMLElement;
191
+ private _capabilityControls = new Map<PrintCapability, HTMLElement>();
192
+ private _collateCheck!: HTMLElement & { checked: boolean };
193
+ private _reverseCheck!: HTMLElement & { checked: boolean };
194
+ private _copiesInput!: HTMLInputElement;
195
+ private _paperDrop!: HTMLElement & { selected: number };
196
+ private _orientationDrop!: HTMLElement & { selected: number };
197
+ private _pageRangeInput!: HTMLInputElement;
198
+ private _selectionRadio!: HTMLElement & { checked: boolean };
199
+ private _currentPageRadio!: HTMLElement & { checked: boolean };
200
+ private _rangeRadios = new Map<string, HTMLElement & { checked: boolean }>();
201
+ private _atInput: HTMLInputElement | null = null;
202
+
203
+ static get observedAttributes(): string[] {
204
+ // The five properties the GIR declares as SCALARS (`:1589` on). `page-setup`,
205
+ // `print-settings` and `selected-printer` are `GtkPageSetup` / `GtkPrintSettings`
206
+ // / `GtkPrinter` objects, which an attribute cannot carry — they are the plain-data
207
+ // properties below, and `check-adwaita-element-properties.mjs` excludes them for
208
+ // exactly that reason.
209
+ return [
210
+ ...AdwDialog.observedAttributes,
211
+ 'current-page',
212
+ 'embed-page-setup',
213
+ 'has-selection',
214
+ 'manual-capabilities',
215
+ 'support-selection',
216
+ ];
217
+ }
218
+
219
+ // ------------------------------------------------------------- properties
220
+
221
+ /** `current-page`, in 0-based document pages; -1 disables "Current Page". */
222
+ get currentPage(): number {
223
+ return this._currentPage;
224
+ }
225
+
226
+ set currentPage(value: number) {
227
+ this._currentPage = value;
228
+ if (this._built) this._renderPrint();
229
+ }
230
+
231
+ /** Whether the page-setup controls are EMBEDDED rather than in their own dialog. */
232
+ get embedPageSetup(): boolean {
233
+ return this.hasAttribute('embed-page-setup');
234
+ }
235
+
236
+ set embedPageSetup(value: boolean) {
237
+ this.toggleAttribute('embed-page-setup', value);
238
+ if (this._built) this._renderPrint();
239
+ }
240
+
241
+ /** Whether the application has a selection to print. */
242
+ get hasSelection(): boolean {
243
+ return this._hasSelection;
244
+ }
245
+
246
+ set hasSelection(value: boolean) {
247
+ this._hasSelection = value;
248
+ if (this._built) this._renderPrint();
249
+ }
250
+
251
+ /** Whether the application supports printing a selection. */
252
+ get supportSelection(): boolean {
253
+ return this.hasAttribute('support-selection');
254
+ }
255
+
256
+ set supportSelection(value: boolean) {
257
+ this.toggleAttribute('support-selection', value);
258
+ if (this._built) this._renderPrint();
259
+ }
260
+
261
+ /** The capabilities the APPLICATION handles, as `GtkPrintCapabilities` nicks. */
262
+ get manualCapabilities(): PrintCapability[] {
263
+ return [...this._manual];
264
+ }
265
+
266
+ set manualCapabilities(value: readonly PrintCapability[]) {
267
+ this._manual = new Set(value.filter((capability) => CAPABILITY_NICKS.includes(capability)));
268
+ if (this._built) this._renderPrint();
269
+ }
270
+
271
+ /** The chosen printer, or `null` — `gtk_print_unix_dialog_get_selected_printer`. */
272
+ get selectedPrinter(): PrinterInfo | null {
273
+ return this._selected === null ? null : { ...this._selected };
274
+ }
275
+
276
+ /** The page setup, as the plain `PageSetup` the value model defines. */
277
+ get pageSetup(): PageSetup {
278
+ return { ...this._pageSetup };
279
+ }
280
+
281
+ set pageSetup(value: PageSetup) {
282
+ this._pageSetup = value;
283
+ if (this._built) this._renderPrint();
284
+ }
285
+
286
+ /** The print settings, in the keys the dialog's own controls write. */
287
+ get printSettings(): PrintSettingsData {
288
+ return { ...this._settings };
289
+ }
290
+
291
+ set printSettings(value: PrintSettingsData) {
292
+ this._settings = { ...DEFAULT_SETTINGS, ...value };
293
+ if (this._built) this._renderPrint();
294
+ }
295
+
296
+ /**
297
+ * Which of the four range buttons is active — the radio group the `.ui` calls the
298
+ * Range frame. GTK has no property for it either: the dialog READS whichever of the four
299
+ * `GtkCheckButton`s is active (`dialog_get_page_range`), and that is what this holds.
300
+ */
301
+ get range(): 'all' | 'current' | 'selection' | 'pages' {
302
+ return this._range;
303
+ }
304
+
305
+ set range(value: 'all' | 'current' | 'selection' | 'pages') {
306
+ this._range = value;
307
+ if (!this._built) return;
308
+ const radio = this._rangeRadios.get(value);
309
+ if (radio !== undefined) radio.checked = true;
310
+ this._renderPrint();
311
+ }
312
+
313
+ /** The printers a print backend would have discovered. An INPUT here — see the header. */
314
+ get printers(): PrinterInfo[] {
315
+ return this._printers.map((printer) => ({ ...printer }));
316
+ }
317
+
318
+ set printers(value: readonly PrinterInfo[]) {
319
+ this._printers = value.map((printer) => ({ ...printer }));
320
+ this._selected = null;
321
+ if (this._built) this._renderPrint();
322
+ }
323
+
324
+ // ------------------------------------------------------------- lifecycle
325
+
326
+ connectedCallback(): void {
327
+ if (this._built) {
328
+ super.connectedCallback();
329
+ return;
330
+ }
331
+ // BEFORE `super.connectedCallback()`, which renders and therefore calls
332
+ // `decorateHeader` — the tab switcher is what that hook installs, as with
333
+ // `<gtk-about-dialog>`.
334
+ this._switcherEl = document.createElement('div');
335
+ this._switcherEl.className = 'adw-print-switcher';
336
+ this._switcherEl.setAttribute('role', 'tablist');
337
+ super.connectedCallback();
338
+
339
+ // `gtk_print_unix_dialog_new`: a NULL title means "Print".
340
+ if (!this.hasAttribute('title')) this.setAttribute('title', 'Print');
341
+ this._readManual();
342
+
343
+ // The base adopts the author's light-DOM children into `contentArea` on
344
+ // connect; rebuilding around them must keep them, AFTER the dialog's own UI —
345
+ // which is also where children appended later land (`slotted-children.spec.ts`
346
+ // pins the equality, path and index).
347
+ const adopted = [...this.contentArea.childNodes];
348
+ this.contentArea.replaceChildren(this._build());
349
+ for (const node of adopted) this.contentArea.appendChild(node);
350
+ this._renderPrint();
351
+ // `_built` goes last: either `setAttribute` above re-enters through
352
+ // `attributeChangedCallback`, and rendering a half-built dialog throws.
353
+ this._built = true;
354
+ }
355
+
356
+ attributeChangedCallback(name: string, oldValue: string | null, newValue: string | null): void {
357
+ super.attributeChangedCallback(name, oldValue, newValue);
358
+ if (!this._built || oldValue === newValue) return;
359
+ if (name === 'title') return;
360
+ if (name === 'manual-capabilities') this._readManual();
361
+ this._renderPrint();
362
+ }
363
+
364
+ /**
365
+ * `manual-capabilities` takes the nick SET the GIR generates, `|`-separated —
366
+ * `manual-capabilities="page-set|copies|collate|reverse|scale|preview"`. Unknown
367
+ * nicks are dropped, which is what the GIR-validated setter does with them.
368
+ */
369
+ private _readManual(): void {
370
+ this._manual = new Set(
371
+ (this.getAttribute('manual-capabilities') ?? '')
372
+ .split('|')
373
+ .map((nick) => nick.trim())
374
+ .filter((nick) => CAPABILITY_NICKS.includes(nick as PrintCapability)) as PrintCapability[],
375
+ );
376
+ }
377
+
378
+ protected override decorateHeader(header: HTMLElement): void {
379
+ const title = header.querySelector('.adw-dialog-title');
380
+ if (title !== null) title.replaceWith(this._switcherEl);
381
+ else header.prepend(this._switcherEl);
382
+ }
383
+
384
+ // ------------------------------------------------------------- building
385
+
386
+ private _build(): HTMLElement {
387
+ const root = document.createElement('div');
388
+ root.className = 'adw-print-root';
389
+
390
+ this._panelEl = document.createElement('div');
391
+ this._panelEl.className = 'adw-print-panel';
392
+ this._panelEl.setAttribute('role', 'tabpanel');
393
+
394
+ root.append(this._panelEl, this._buildConflicts(), this._buildActions());
395
+ this._renderPanel();
396
+ return root;
397
+ }
398
+
399
+ /**
400
+ * Every page of the notebook, built once and hidden but for the visible one —
401
+ * which is what `GtkNotebook` holds: all seven pages exist whether shown or not,
402
+ * so the capability pass can reach every control from the first render.
403
+ */
404
+ private _renderPanel(): void {
405
+ for (const tab of TABS) {
406
+ let page = this._tabPages.get(tab);
407
+ if (page === undefined) {
408
+ page = document.createElement('div');
409
+ page.className = 'adw-print-page';
410
+ page.setAttribute('role', 'tabpanel');
411
+ page.dataset.tab = tab;
412
+ page.appendChild(this._buildTab(tab));
413
+ this._tabPages.set(tab, page);
414
+ this._panelEl.appendChild(page);
415
+ }
416
+ page.hidden = tab !== this._tab;
417
+ }
418
+ }
419
+
420
+ private _buildTab(tab: PrintTab): HTMLElement {
421
+ switch (tab) {
422
+ case 'General':
423
+ return this._buildGeneral();
424
+ case 'Page Setup':
425
+ return this._buildPageSetup();
426
+ case 'Job':
427
+ return this._buildJob();
428
+ // The four option pages: a scrolled grid the backend's `GtkPrinterOptionWidget`s
429
+ // go into. With no backend there are none, so they are the EMPTY grids the C
430
+ // leaves them in — the headings above them are what tells the reader why.
431
+ case 'Image Quality':
432
+ case 'Color':
433
+ case 'Finishing':
434
+ return this._buildOptionsPage(tab);
435
+ case 'Advanced':
436
+ return this._buildOptionsPage(tab);
437
+ }
438
+ }
439
+
440
+ /** General: the printer list, then Range and Copies. */
441
+ private _buildGeneral(): HTMLElement {
442
+ const box = document.createElement('div');
443
+ box.className = 'adw-print-columns';
444
+
445
+ this._printerListEl = document.createElement('div');
446
+ this._printerListEl.className = 'adw-print-printer-list';
447
+ this._printerListEl.setAttribute('role', 'radiogroup');
448
+ this._printerListEl.setAttribute('aria-label', 'Printer');
449
+ box.appendChild(this._frame(this._printerListEl));
450
+
451
+ const right = document.createElement('div');
452
+ right.className = 'adw-print-column';
453
+
454
+ // Range
455
+ const rangeGroup = this._group('Range');
456
+ const range = rangeGroup.body;
457
+ for (const [value, label] of [
458
+ ['all', 'All Pages'],
459
+ ['current', 'Current Page'],
460
+ ['selection', 'Selection'],
461
+ ] as Array<['all' | 'current' | 'selection', string]>) {
462
+ const radio = this._radio(label, `adw-print-range-${value}`);
463
+ radio.addEventListener('notify::checked', () => {
464
+ if (radio.checked) {
465
+ this._range = value;
466
+ if (value === 'current' || value === 'selection') this._renderPrint();
467
+ }
468
+ });
469
+ if (value === 'current') this._currentPageRadio = radio;
470
+ if (value === 'selection') this._selectionRadio = radio;
471
+ this._rangeRadios.set(value, radio);
472
+ range.appendChild(radio);
473
+ }
474
+ const pagesRadio = this._radio('Pages:', 'adw-print-range-pages');
475
+ pagesRadio.addEventListener('notify::checked', () => {
476
+ if (!pagesRadio.checked) return;
477
+ this._range = 'pages';
478
+ // `update_page_range_entry_sensitivity`: picking "Pages:" grabs the entry.
479
+ this._pageRangeInput.focus();
480
+ });
481
+ this._pageRangeInput = document.createElement('input');
482
+ this._pageRangeInput.type = 'text';
483
+ this._pageRangeInput.className = 'adw-print-page-range-entry';
484
+ this._pageRangeInput.title = 'Specify one or more page ranges, e.g. 1–3, 7, 11';
485
+ this._pageRangeInput.setAttribute('aria-label', 'Pages');
486
+ // `page_range_entry_focus_changed`: focusing the entry picks its radio.
487
+ this._pageRangeInput.addEventListener('focus', () => {
488
+ this._range = 'pages';
489
+ pagesRadio.checked = true;
490
+ });
491
+ this._rangeRadios.set('pages', pagesRadio);
492
+ const pagesRow = document.createElement('div');
493
+ pagesRow.className = 'adw-print-grid-row';
494
+ pagesRow.append(pagesRadio, this._pageRangeInput);
495
+ range.appendChild(pagesRow);
496
+ right.appendChild(rangeGroup.group);
497
+
498
+ // Copies
499
+ const copiesGroup = this._group('Copies');
500
+ const copies = copiesGroup.body;
501
+ const copiesRow = document.createElement('div');
502
+ copiesRow.className = 'adw-print-grid-row';
503
+ const copiesLabel = document.createElement('div');
504
+ copiesLabel.className = 'adw-print-label';
505
+ copiesLabel.textContent = 'Copies:';
506
+ this._copiesInput = document.createElement('input');
507
+ this._copiesInput.type = 'number';
508
+ this._copiesInput.min = '1';
509
+ this._copiesInput.className = 'adw-print-copies';
510
+ this._copiesInput.value = this._settings.copies ?? '1';
511
+ this._copiesInput.setAttribute('aria-label', 'Copies');
512
+ // `copies_spin`'s `changed` and `value-changed` both run the capability pass.
513
+ this._copiesInput.addEventListener('input', () => {
514
+ this._settings = { ...this._settings, copies: this._copiesInput.value };
515
+ this._renderPrint();
516
+ });
517
+ copiesRow.append(copiesLabel, this._copiesInput);
518
+ copies.appendChild(copiesRow);
519
+
520
+ this._collateCheck = this._check('Collate', 'adw-print-collate');
521
+ this._reverseCheck = this._check('Reverse', 'adw-print-reverse');
522
+ for (const check of [this._collateCheck, this._reverseCheck]) {
523
+ check.addEventListener('notify::checked', () => this._renderPrint());
524
+ }
525
+ copies.append(this._collateCheck, this._reverseCheck);
526
+
527
+ const preview = this._buildCollatePreview();
528
+ const previewRow = document.createElement('div');
529
+ previewRow.className = 'adw-print-grid-row';
530
+ previewRow.appendChild(preview);
531
+ copies.appendChild(previewRow);
532
+ right.appendChild(copiesGroup.group);
533
+
534
+ box.appendChild(right);
535
+ return box;
536
+ }
537
+
538
+ /** `page_collate_preview`: four thumbnails whose NUMBERS show the ordering. */
539
+ private _buildCollatePreview(): HTMLElement {
540
+ const preview = document.createElement('div');
541
+ preview.className = 'adw-print-collate-preview';
542
+ preview.setAttribute('role', 'img');
543
+ preview.setAttribute(
544
+ 'aria-label',
545
+ 'A visualization of the effect of the collate and reverse options on the page ordering',
546
+ );
547
+ preview.dataset.columnA = '2';
548
+ preview.dataset.columnB = '1';
549
+ return preview;
550
+ }
551
+
552
+ /** Page Setup: Layout and Paper beside the sheet preview. */
553
+ private _buildPageSetup(): HTMLElement {
554
+ const box = document.createElement('div');
555
+ box.className = 'adw-print-columns';
556
+
557
+ const left = document.createElement('div');
558
+ left.className = 'adw-print-column';
559
+
560
+ // Layout
561
+ const layoutGroup = this._group('Layout');
562
+ const layout = layoutGroup.body;
563
+ // `page_set_combo` is the one Layout control `update_dialog_from_capabilities`
564
+ // gates (PAGE_SET); the scale input below is gated by SCALE.
565
+ layout.appendChild(this._labelledRow('Two-sided:', this._dropDown(PAGE_SET_ITEMS, 'Two-sided')));
566
+ const scaleInput = document.createElement('input');
567
+ scaleInput.type = 'number';
568
+ scaleInput.min = '10';
569
+ scaleInput.max = '400';
570
+ scaleInput.className = 'adw-print-scale';
571
+ scaleInput.value = this._settings.scale ?? '100';
572
+ scaleInput.setAttribute('aria-label', 'Scale in percent');
573
+ scaleInput.addEventListener('input', () => {
574
+ this._settings = { ...this._settings, scale: scaleInput.value };
575
+ this._renderPrint();
576
+ });
577
+ this._capabilityControls.set('scale', scaleInput);
578
+ const scaleRow = document.createElement('div');
579
+ scaleRow.className = 'adw-print-grid-row';
580
+ const scaleLabel = document.createElement('div');
581
+ scaleLabel.className = 'adw-print-label';
582
+ scaleLabel.textContent = 'Scale:';
583
+ const percent = document.createElement('span');
584
+ percent.className = 'adw-print-label';
585
+ percent.textContent = '%';
586
+ scaleRow.append(scaleLabel, scaleInput, percent);
587
+ layout.appendChild(scaleRow);
588
+ left.appendChild(layoutGroup.group);
589
+
590
+ // Paper. BOTH drop downs are insensitive until `embed-page-setup` is set —
591
+ // `gtk_print_unix_dialog_set_embed_page_setup` (:3415-3427) is what connects their
592
+ // `notify::selected` handlers AND makes them sensitive, in that order.
593
+ const paperGroup = this._group('Paper');
594
+ const paper = paperGroup.body;
595
+ const paperNames = COMMON_PAPER_SIZES.map((size) => size.displayName);
596
+ this._paperDrop = this._dropDown(paperNames, 'Paper size');
597
+ this._orientationDrop = this._dropDown(
598
+ ORIENTATION_ITEMS.map((orientation) => orientation[0]!.toUpperCase() + orientation.slice(1)),
599
+ 'Orientation',
600
+ );
601
+ paper.appendChild(this._labelledRow('Paper size:', this._paperDrop));
602
+ paper.appendChild(this._labelledRow('Orientation:', this._orientationDrop));
603
+ left.appendChild(paperGroup.group);
604
+
605
+ // The two drop downs react ONLY while the page setup is embedded, which is the
606
+ // other half of `set_embed_page_setup`: connecting a listener and making the
607
+ // control sensitive are one decision there.
608
+ this._paperDrop.addEventListener('notify::selected', () => {
609
+ if (!this.embedPageSetup) return;
610
+ this._paperChanged(this._paperDrop.selected);
611
+ });
612
+ this._orientationDrop.addEventListener('notify::selected', () => {
613
+ if (!this.embedPageSetup) return;
614
+ const orientation = ORIENTATION_ITEMS[this._orientationDrop.selected] ?? 'portrait';
615
+ this._pageSetup = { ...this._pageSetup, orientation };
616
+ this._settings = { ...this._settings, orientation };
617
+ this._renderPrint();
618
+ });
619
+
620
+ box.append(left, this._buildSheetPreview());
621
+ return box;
622
+ }
623
+
624
+ /**
625
+ * `page_layout_preview` (:2683) + `draw_page` (:2283): the sheet at 110px on its long
626
+ * edge, divided by the number-up grid with each cell numbered in the number-up order.
627
+ * The ruler the C draws around it is decoration outside the sheet and is not painted.
628
+ */
629
+ private _buildSheetPreview(): HTMLElement {
630
+ const preview = document.createElement('div');
631
+ preview.className = 'adw-print-sheet-preview';
632
+ preview.setAttribute('role', 'img');
633
+ preview.setAttribute('aria-label', 'Page layout preview');
634
+ const paper = document.createElement('div');
635
+ paper.className = 'adw-print-paper';
636
+ const size = paperSizeOf(this._pageSetup);
637
+ const landscape =
638
+ this._pageSetup.orientation === 'landscape' || this._pageSetup.orientation === 'reverse-landscape';
639
+ paper.style.aspectRatio = landscape ? `${size.height} / ${size.width}` : `${size.width} / ${size.height}`;
640
+ const grid = document.createElement('div');
641
+ grid.className = 'adw-print-number-up';
642
+ grid.dataset.cells = '1';
643
+ paper.appendChild(grid);
644
+ preview.appendChild(paper);
645
+ const caption = document.createElement('div');
646
+ caption.className = 'adw-print-sheet-caption';
647
+ caption.textContent = `${orientedSize(this._pageSetup).width.toFixed(1)} mm × ${orientedSize(this._pageSetup).height.toFixed(1)} mm`;
648
+ preview.appendChild(caption);
649
+ return preview;
650
+ }
651
+
652
+ /** Job: Job Details, Print Document, Add Cover Page. */
653
+ private _buildJob(): HTMLElement {
654
+ const box = document.createElement('div');
655
+ box.className = 'adw-print-column';
656
+
657
+ // Job Details — the two printer option widgets the C puts here (`job_prio`,
658
+ // `billing_info`), which exist only for a printer that offers them.
659
+ const detailsGroup = this._group('Job Details');
660
+ detailsGroup.body.appendChild(this._optionsGrid('Job Details'));
661
+
662
+ const documentGroup = this._group('Print Document');
663
+ const document_ = documentGroup.body;
664
+ for (const [value, label] of [
665
+ ['now', 'Now'],
666
+ ['at', 'At:'],
667
+ ['hold', 'On hold'],
668
+ ] as Array<['now' | 'at' | 'hold', string]>) {
669
+ const radio = this._radio(label, 'adw-print-at');
670
+ radio.addEventListener('notify::checked', () => {
671
+ if (!radio.checked) return;
672
+ this._printAt = value;
673
+ // `update_print_at_entry_sensitivity`: the entry follows its radio, and
674
+ // picking "At:" grabs it.
675
+ if (this._atInput !== null) this._atInput.disabled = value !== 'at';
676
+ if (value === 'at') this._atInput?.focus();
677
+ });
678
+ document_.appendChild(radio);
679
+ if (value === 'at') {
680
+ this._atInput = document.createElement('input');
681
+ this._atInput.type = 'text';
682
+ this._atInput.className = 'adw-print-at-entry';
683
+ this._atInput.setAttribute('aria-label', 'Print at');
684
+ this._atInput.disabled = true;
685
+ this._atInput.addEventListener('input', () => {
686
+ this._settings = { ...this._settings, 'print-at': this._atInput!.value };
687
+ });
688
+ const row = document.createElement('div');
689
+ row.className = 'adw-print-grid-row';
690
+ row.appendChild(this._atInput);
691
+ document_.appendChild(row);
692
+ }
693
+ }
694
+
695
+ const coverGroup = this._group('Add Cover Page');
696
+ coverGroup.body.appendChild(this._optionsGrid('Cover Page'));
697
+
698
+ box.append(detailsGroup.group, documentGroup.group, coverGroup.group);
699
+ return box;
700
+ }
701
+
702
+ /**
703
+ * One of the four option pages: the scrolled viewport + grid the C's
704
+ * `GtkPrinterOptionWidget`s are added to. There are none without a backend, so the grid
705
+ * is empty and says so rather than inventing options.
706
+ */
707
+ private _buildOptionsPage(tab: PrintTab): HTMLElement {
708
+ const box = document.createElement('div');
709
+ box.className = 'adw-print-column';
710
+ const grid = this._optionsGrid(tab);
711
+ if (tab === 'Advanced') {
712
+ // The Advanced page is a plain box (`advanced_vbox`), not a grid.
713
+ const advanced = document.createElement('div');
714
+ advanced.className = 'adw-print-advanced';
715
+ advanced.appendChild(grid);
716
+ box.appendChild(advanced);
717
+ return box;
718
+ }
719
+ box.appendChild(grid);
720
+ return box;
721
+ }
722
+
723
+ /** The option grid, one row per option group the backend would offer. */
724
+ private _optionsGrid(label: string): HTMLElement {
725
+ const grid = document.createElement('div');
726
+ grid.className = 'adw-print-options-grid';
727
+ grid.setAttribute('role', 'group');
728
+ grid.setAttribute('aria-label', label);
729
+ grid.dataset.empty = 'true';
730
+ return grid;
731
+ }
732
+
733
+ /** The conflicts action bar — hidden until `mark_conflicts` finds one (:3050-3060). */
734
+ private _buildConflicts(): HTMLElement {
735
+ this._conflictsEl = document.createElement('div');
736
+ this._conflictsEl.className = 'adw-print-conflicts';
737
+ this._conflictsEl.hidden = true;
738
+ this._conflictsEl.append(
739
+ createGtkImage('dialog-warning', 'adw-print-conflicts-icon'),
740
+ (() => {
741
+ const label = document.createElement('span');
742
+ label.className = 'adw-print-conflicts-label';
743
+ label.textContent = 'Some of the settings in the dialog conflict';
744
+ return label;
745
+ })(),
746
+ );
747
+ return this._conflictsEl;
748
+ }
749
+
750
+ /** Preview / Cancel / Print, in the `.ui`'s order and with its own response ids. */
751
+ private _buildActions(): HTMLElement {
752
+ const actions = document.createElement('div');
753
+ actions.className = 'adw-print-actions';
754
+
755
+ this._previewButton = document.createElement('button');
756
+ this._previewButton.type = 'button';
757
+ this._previewButton.className = 'adw-print-preview';
758
+ this._previewButton.textContent = 'Preview';
759
+ this._previewButton.addEventListener('click', () => this._respond(RESPONSE_APPLY));
760
+
761
+ const cancel = document.createElement('button');
762
+ cancel.type = 'button';
763
+ cancel.className = 'adw-print-cancel';
764
+ cancel.textContent = 'Cancel';
765
+ cancel.addEventListener('click', () => this._respond(RESPONSE_CANCEL));
766
+
767
+ this._printButton = document.createElement('button');
768
+ this._printButton.type = 'button';
769
+ this._printButton.className = 'adw-print-print suggested-action';
770
+ this._printButton.textContent = 'Print';
771
+ this._printButton.addEventListener('click', () => this._respond(RESPONSE_OK));
772
+
773
+ actions.append(this._previewButton, cancel, this._printButton);
774
+ return actions;
775
+ }
776
+
777
+ private _respond(responseId: number): void {
778
+ this.dispatchEvent(new CustomEvent('response', { bubbles: true, detail: { responseId } }));
779
+ if (responseId !== RESPONSE_OK) this.close();
780
+ }
781
+
782
+ // ------------------------------------------------------------- fragments
783
+
784
+ /**
785
+ * One `frame_templateN`: a BOLD heading over a grid, which is the shape every group in
786
+ * the `.ui` has — `box > box > grid` with the heading's `weight=bold`.
787
+ */
788
+ private _group(title: string): { group: HTMLElement; body: HTMLElement } {
789
+ const group = document.createElement('div');
790
+ group.className = 'adw-print-group';
791
+ const heading = document.createElement('div');
792
+ heading.className = 'adw-print-group-title';
793
+ heading.textContent = title;
794
+ const body = document.createElement('div');
795
+ body.className = 'adw-print-group-body';
796
+ group.append(heading, body);
797
+ return { group, body };
798
+ }
799
+
800
+ private _labelledRow(label: string, control: HTMLElement, capability?: PrintCapability): HTMLElement {
801
+ const row = document.createElement('div');
802
+ row.className = 'adw-print-grid-row';
803
+ const text = document.createElement('div');
804
+ text.className = 'adw-print-label';
805
+ text.textContent = label;
806
+ row.append(text, control);
807
+ if (capability !== undefined) this._capabilityControls.set(capability, control);
808
+ return row;
809
+ }
810
+
811
+ private _dropDown(items: readonly string[], label: string): HTMLElement & { selected: number } {
812
+ const dropdown = document.createElement('gtk-drop-down') as HTMLElement & { selected: number };
813
+ dropdown.className = 'adw-print-dropdown';
814
+ dropdown.setAttribute('model', JSON.stringify([...items]));
815
+ dropdown.setAttribute('aria-label', label);
816
+ return dropdown;
817
+ }
818
+
819
+ private _radio(label: string, name: string): HTMLElement & { checked: boolean } {
820
+ const radio = document.createElement('adw-radio') as HTMLElement & { checked: boolean };
821
+ // The name is the class too, so the Range radios answer to
822
+ // `.adw-print-range-selection` and `.adw-print-range-current`.
823
+ radio.className = name;
824
+ radio.setAttribute('label', label);
825
+ radio.setAttribute('name', name);
826
+ radio.setAttribute('value', label);
827
+ return radio;
828
+ }
829
+
830
+ private _check(label: string, name: string): HTMLElement & { checked: boolean } {
831
+ const check = document.createElement('gtk-check-button') as HTMLElement & { checked: boolean };
832
+ // The name is the class too, so Collate and Reverse answer to
833
+ // `.adw-print-collate` and `.adw-print-reverse`.
834
+ check.className = name;
835
+ check.setAttribute('label', label);
836
+ check.setAttribute('name', name);
837
+ return check;
838
+ }
839
+
840
+ private _frame(content: HTMLElement): HTMLElement {
841
+ const frame = document.createElement('div');
842
+ frame.className = 'adw-print-frame';
843
+ frame.appendChild(content);
844
+ return frame;
845
+ }
846
+
847
+ // ------------------------------------------------------------- rendering
848
+
849
+ /** `selected_printer_changed` (:1821-1915) — the list and what selecting does. */
850
+ private _printerChanged(selected: PrinterInfo | null): void {
851
+ this._selected = selected;
852
+ if (selected !== null) {
853
+ // The printer's capabilities replace the previous printer's (:1874), and the
854
+ // settings follow the printer when no explicit page setup was set.
855
+ this._settings = { ...this._settings, 'format-for-printer': selected.name };
856
+ }
857
+ this._renderPrint();
858
+ }
859
+
860
+ private _paperChanged(index: number): void {
861
+ const size = COMMON_PAPER_SIZES[index];
862
+ if (size === undefined) return;
863
+ this._pageSetup = { ...this._pageSetup, paperSize: size.name, margins: defaultMargins(size) };
864
+ this._renderPrint();
865
+ }
866
+
867
+ /** Every capability the dialog currently has: the manual half OR the printer's. */
868
+ private _capabilities(): Set<PrintCapability> {
869
+ const capabilities = new Set(this._manual);
870
+ for (const capability of this._selected?.capabilities ?? []) capabilities.add(capability);
871
+ return capabilities;
872
+ }
873
+
874
+ /** `update_dialog_from_capabilities` (:1563-1592), every line of it. */
875
+ private _renderPrint(): void {
876
+ const capabilities = this._capabilities();
877
+ this._switcherEl.replaceChildren(
878
+ ...TABS.map((tab) => {
879
+ const button = document.createElement('button');
880
+ button.type = 'button';
881
+ button.className = 'adw-print-switcher-item';
882
+ button.setAttribute('role', 'tab');
883
+ button.textContent = tab;
884
+ button.classList.toggle('checked', tab === this._tab);
885
+ button.setAttribute('aria-selected', String(tab === this._tab));
886
+ button.addEventListener('click', () => {
887
+ this._tab = tab;
888
+ this._renderPanel();
889
+ this._renderPrint();
890
+ });
891
+ return button;
892
+ }),
893
+ );
894
+
895
+ this._printerListEl.replaceChildren(
896
+ ...this._printers.map((printer) => {
897
+ const row = document.createElement('button');
898
+ row.type = 'button';
899
+ row.className = 'adw-print-printer-row';
900
+ row.setAttribute('role', 'radio');
901
+ row.setAttribute('aria-checked', String(printer === this._selected));
902
+ row.classList.toggle('checked', printer === this._selected);
903
+ // The `.ui`'s icon column reads each printer's OWN `icon-name`; the
904
+ // default for one that has none is the printer glyph.
905
+ row.appendChild(
906
+ printer.iconName === undefined
907
+ ? createGtkImage('printer', 'adw-print-printer-icon')
908
+ : createGtkImage(printer.iconName, 'adw-print-printer-icon'),
909
+ );
910
+ const text = document.createElement('span');
911
+ text.className = 'adw-print-printer-text';
912
+ const name = document.createElement('span');
913
+ name.className = 'adw-print-printer-name';
914
+ name.textContent = printer.name;
915
+ text.appendChild(name);
916
+ if (printer.location !== undefined) {
917
+ const location = document.createElement('span');
918
+ location.className = 'adw-print-printer-location';
919
+ location.textContent = printer.location;
920
+ text.appendChild(location);
921
+ }
922
+ row.appendChild(text);
923
+ row.addEventListener('click', () => this._printerChanged(printer));
924
+ return row;
925
+ }),
926
+ );
927
+
928
+ // `set_support_selection` (:3325-3343) then `set_has_selection` (:3369-3389): the
929
+ // radio is VISIBLE only with support, and sensitive only with support AND a
930
+ // selection. Both run in that order, so the insensitive case wins.
931
+ this._selectionRadio.hidden = !this.supportSelection;
932
+ this._selectionRadio.classList.toggle('insensitive', !this.supportSelection || !this._hasSelection);
933
+ this._selectionRadio.setAttribute('aria-disabled', String(!this.supportSelection || !this._hasSelection));
934
+
935
+ // `set_current_page` (:3059-3073).
936
+ this._currentPageRadio.classList.toggle('insensitive', this._currentPage === -1);
937
+ this._currentPageRadio.setAttribute('aria-disabled', String(this._currentPage === -1));
938
+
939
+ for (const [capability, control] of this._capabilityControls) {
940
+ control.toggleAttribute('disabled', !capabilities.has(capability));
941
+ }
942
+ // `can_collate` is `*copies != '\0' && atoi (copies) > 1` (:1570-1571).
943
+ const copies = Number.parseInt(this._copiesInput.value, 10);
944
+ const canCollate = this._copiesInput.value !== '' && Number.isFinite(copies) && copies > 1;
945
+ this._collateCheck.toggleAttribute('disabled', !canCollate || !capabilities.has('collate'));
946
+ this._reverseCheck.toggleAttribute('disabled', !capabilities.has('reverse'));
947
+ this._copiesInput.toggleAttribute('disabled', !capabilities.has('copies'));
948
+ // `set_embed_page_setup` (:3425-3426) is the ONLY thing that makes these two
949
+ // sensitive; with it FALSE they keep the `.ui`'s `sensitive=0` and their handlers
950
+ // are not connected, so a selection cannot reach the page setup.
951
+ this._paperDrop.toggleAttribute('disabled', !this.embedPageSetup);
952
+ this._orientationDrop.toggleAttribute('disabled', !this.embedPageSetup);
953
+
954
+ // `update_collate_icon` (:1920-1949): the numbers, and the second column's
955
+ // visibility, which is the copies count and nothing else.
956
+ const collate = this._collateCheck.checked;
957
+ const reverse = this._reverseCheck.checked;
958
+ const preview = this.contentArea.querySelector<HTMLElement>('.adw-print-collate-preview');
959
+ if (preview !== null) {
960
+ preview.dataset.columnA = String(collate ? (reverse ? 1 : 2) : reverse ? 2 : 1);
961
+ preview.dataset.columnB = String(collate ? (reverse ? 2 : 1) : reverse ? 1 : 2);
962
+ preview.dataset.secondColumn = String(canCollate);
963
+ }
964
+
965
+ // Print is sensitive only for a printer that accepts jobs (:1842-1876), and Preview
966
+ // is VISIBLE only with the PREVIEW capability (:1587-1588).
967
+ const prints = this._selected !== null && (this._selected.acceptsJobs ?? true);
968
+ this._printButton.toggleAttribute('disabled', !prints);
969
+ this._previewButton.hidden = !capabilities.has('preview');
970
+
971
+ // The sheet preview follows the page setup and the two-sided pages per sheet.
972
+ const paper = this.contentArea.querySelector<HTMLElement>('.adw-print-paper');
973
+ if (paper !== null) {
974
+ const size = paperSizeOf(this._pageSetup);
975
+ const reverseLandscape = this._pageSetup.orientation === 'reverse-portrait';
976
+ paper.style.aspectRatio = `${
977
+ this._pageSetup.orientation === 'landscape' || reverseLandscape
978
+ ? `${size.height} / ${size.width}`
979
+ : `${size.width} / ${size.height}`
980
+ }`;
981
+ }
982
+ const grid = this.contentArea.querySelector<HTMLElement>('.adw-print-number-up');
983
+ if (grid !== null) grid.dataset.cells = '1';
984
+
985
+ this._conflictsEl.hidden = true;
986
+ }
987
+ }
988
+
989
+ customElements.define('gtk-print-unix-dialog', GtkPrintUnixDialog);