@gjsify/adwaita-web 0.53.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.
- package/dist/adwaita-web.css +8070 -3037
- package/dist/adwaita-web.css.map +1 -1
- package/lib/types/adw-application-window.spec.d.ts +1 -0
- package/lib/types/adw-bin.spec.d.ts +1 -0
- package/lib/types/adw-breakpoint-bin.spec.d.ts +1 -0
- package/lib/types/adw-clamp-scrollable.spec.d.ts +1 -0
- package/lib/types/adw-multi-layout-view.spec.d.ts +1 -0
- package/lib/types/adw-preferences-row.spec.d.ts +1 -0
- package/lib/types/adw-shortcuts.spec.d.ts +1 -0
- package/lib/types/adw-tab-bar.spec.d.ts +1 -0
- package/lib/types/adw-tab-button.spec.d.ts +1 -0
- package/lib/types/adw-tab-overview.spec.d.ts +1 -0
- package/lib/types/adw-view-switcher-sidebar.spec.d.ts +1 -0
- package/lib/types/adw-window.spec.d.ts +1 -0
- package/lib/types/breakpoints.d.ts +14 -3
- package/lib/types/construct-vectors.spec.d.ts +1 -0
- package/lib/types/elements/adw-application-window.d.ts +27 -0
- package/lib/types/elements/adw-bin.d.ts +17 -0
- package/lib/types/elements/adw-breakpoint-bin.d.ts +67 -0
- package/lib/types/elements/adw-clamp-scrollable.d.ts +38 -0
- package/lib/types/elements/adw-dialog.d.ts +10 -0
- package/lib/types/elements/adw-layout-slot.d.ts +19 -0
- package/lib/types/elements/adw-multi-layout-view.d.ts +101 -0
- package/lib/types/elements/adw-preferences-row.d.ts +31 -0
- package/lib/types/elements/adw-shortcuts-dialog.d.ts +13 -0
- package/lib/types/elements/adw-shortcuts-item.d.ts +36 -0
- package/lib/types/elements/adw-shortcuts-section.d.ts +14 -0
- package/lib/types/elements/adw-sidebar.d.ts +5 -0
- package/lib/types/elements/adw-switch-row.d.ts +3 -0
- package/lib/types/elements/adw-tab-bar.d.ts +108 -0
- package/lib/types/elements/adw-tab-button.d.ts +32 -0
- package/lib/types/elements/adw-tab-overview.d.ts +199 -0
- package/lib/types/elements/adw-tab-view.d.ts +19 -23
- package/lib/types/elements/adw-view-switcher-sidebar.d.ts +84 -0
- package/lib/types/elements/adw-window.d.ts +40 -0
- package/lib/types/elements/gtk-about-dialog.d.ts +146 -0
- package/lib/types/elements/gtk-application-window.d.ts +34 -0
- package/lib/types/elements/gtk-aspect-frame.d.ts +27 -0
- package/lib/types/elements/gtk-button.d.ts +9 -0
- package/lib/types/elements/gtk-calendar.d.ts +159 -0
- package/lib/types/elements/gtk-center-box.d.ts +39 -0
- package/lib/types/elements/gtk-color-dialog-button.d.ts +69 -0
- package/lib/types/elements/gtk-column-view.d.ts +50 -0
- package/lib/types/elements/gtk-drag-icon.d.ts +78 -0
- package/lib/types/elements/gtk-drawing-area.d.ts +95 -0
- package/lib/types/elements/gtk-editable-label.d.ts +33 -0
- package/lib/types/elements/gtk-emoji-chooser.d.ts +84 -0
- package/lib/types/elements/gtk-entry.d.ts +20 -1
- package/lib/types/elements/gtk-expander.d.ts +49 -0
- package/lib/types/elements/gtk-fixed.d.ts +13 -0
- package/lib/types/elements/gtk-flow-box-child.d.ts +14 -0
- package/lib/types/elements/gtk-flow-box.d.ts +87 -0
- package/lib/types/elements/gtk-font-dialog-button.d.ts +83 -0
- package/lib/types/elements/gtk-frame.d.ts +24 -0
- package/lib/types/elements/gtk-gl-area.d.ts +136 -0
- package/lib/types/elements/gtk-graphics-offload.d.ts +24 -0
- package/lib/types/elements/gtk-grid-view.d.ts +39 -0
- package/lib/types/elements/gtk-grid.d.ts +27 -0
- package/lib/types/elements/gtk-header-bar.d.ts +60 -0
- package/lib/types/elements/gtk-inscription.d.ts +64 -0
- package/lib/types/elements/gtk-label.d.ts +3 -0
- package/lib/types/elements/gtk-level-bar.d.ts +59 -0
- package/lib/types/elements/gtk-link-button.d.ts +29 -0
- package/lib/types/elements/gtk-list-box-row.d.ts +54 -0
- package/lib/types/elements/gtk-list-box.d.ts +100 -0
- package/lib/types/elements/gtk-list-view.d.ts +73 -0
- package/lib/types/elements/gtk-media-controls.d.ts +142 -0
- package/lib/types/elements/gtk-notebook.d.ts +148 -0
- package/lib/types/elements/gtk-overlay.d.ts +22 -0
- package/lib/types/elements/gtk-page-setup-unix-dialog.d.ts +87 -0
- package/lib/types/elements/gtk-paned.d.ts +121 -0
- package/lib/types/elements/gtk-password-entry.d.ts +27 -0
- package/lib/types/elements/gtk-picture.d.ts +66 -0
- package/lib/types/elements/gtk-popover-bin.d.ts +82 -0
- package/lib/types/elements/gtk-popover-menu-bar.d.ts +66 -0
- package/lib/types/elements/gtk-popover-menu.d.ts +83 -0
- package/lib/types/elements/gtk-popover.d.ts +28 -3
- package/lib/types/elements/gtk-print-unix-dialog.d.ts +167 -0
- package/lib/types/elements/gtk-revealer.d.ts +55 -0
- package/lib/types/elements/gtk-scale-button.d.ts +59 -0
- package/lib/types/elements/gtk-scale.d.ts +98 -0
- package/lib/types/elements/gtk-scrollbar.d.ts +124 -0
- package/lib/types/elements/gtk-scrolled-window.d.ts +121 -0
- package/lib/types/elements/gtk-search-bar.d.ts +39 -0
- package/lib/types/elements/gtk-search-entry.d.ts +27 -0
- package/lib/types/elements/gtk-separator.d.ts +10 -0
- package/lib/types/elements/gtk-spin-button.d.ts +94 -0
- package/lib/types/elements/gtk-spinner.d.ts +14 -0
- package/lib/types/elements/gtk-stack-sidebar.d.ts +43 -0
- package/lib/types/elements/gtk-stack-switcher.d.ts +58 -0
- package/lib/types/elements/gtk-stack.d.ts +154 -0
- package/lib/types/elements/gtk-switch.d.ts +4 -1
- package/lib/types/elements/gtk-text-view.d.ts +62 -0
- package/lib/types/elements/gtk-text.d.ts +45 -0
- package/lib/types/elements/gtk-toggle-button.d.ts +45 -0
- package/lib/types/elements/gtk-tree-expander.d.ts +38 -0
- package/lib/types/elements/gtk-video.d.ts +97 -0
- package/lib/types/elements/gtk-viewport.d.ts +84 -0
- package/lib/types/elements/gtk-window-controls.d.ts +80 -0
- package/lib/types/elements/gtk-window-handle.d.ts +39 -0
- package/lib/types/elements/gtk-window.d.ts +97 -0
- package/lib/types/elements/justification.d.ts +2 -0
- package/lib/types/elements/popover-menu.d.ts +18 -0
- package/lib/types/elements/roving-focus.d.ts +29 -1
- package/lib/types/emoji-data.d.ts +38 -0
- package/lib/types/font-description.d.ts +96 -0
- package/lib/types/gtk-about-dialog.spec.d.ts +1 -0
- package/lib/types/gtk-action-bar.spec.d.ts +1 -0
- package/lib/types/gtk-application-window.spec.d.ts +1 -0
- package/lib/types/gtk-aspect-frame.spec.d.ts +1 -0
- package/lib/types/gtk-calendar.spec.d.ts +1 -0
- package/lib/types/gtk-center-box.spec.d.ts +1 -0
- package/lib/types/gtk-color-dialog-button.spec.d.ts +1 -0
- package/lib/types/gtk-column-view.spec.d.ts +1 -0
- package/lib/types/gtk-drag-icon.spec.d.ts +1 -0
- package/lib/types/gtk-drawing-area.spec.d.ts +1 -0
- package/lib/types/gtk-editable-label.spec.d.ts +1 -0
- package/lib/types/gtk-emoji-chooser.spec.d.ts +1 -0
- package/lib/types/gtk-expander.spec.d.ts +1 -0
- package/lib/types/gtk-fixed.spec.d.ts +1 -0
- package/lib/types/gtk-flow-box.spec.d.ts +1 -0
- package/lib/types/gtk-font-dialog-button.spec.d.ts +1 -0
- package/lib/types/gtk-frame.spec.d.ts +1 -0
- package/lib/types/gtk-gl-area.spec.d.ts +1 -0
- package/lib/types/gtk-graphics-offload.spec.d.ts +1 -0
- package/lib/types/gtk-grid-view.spec.d.ts +1 -0
- package/lib/types/gtk-grid.spec.d.ts +1 -0
- package/lib/types/gtk-header-bar.spec.d.ts +1 -0
- package/lib/types/gtk-inscription.spec.d.ts +1 -0
- package/lib/types/gtk-level-bar.spec.d.ts +1 -0
- package/lib/types/gtk-link-button.spec.d.ts +1 -0
- package/lib/types/gtk-list-box.spec.d.ts +1 -0
- package/lib/types/gtk-list-view.spec.d.ts +1 -0
- package/lib/types/gtk-media-controls.spec.d.ts +1 -0
- package/lib/types/gtk-notebook.spec.d.ts +1 -0
- package/lib/types/gtk-overlay.spec.d.ts +1 -0
- package/lib/types/gtk-paned.spec.d.ts +1 -0
- package/lib/types/gtk-password-entry.spec.d.ts +1 -0
- package/lib/types/gtk-picture.spec.d.ts +1 -0
- package/lib/types/gtk-popover-bin.spec.d.ts +1 -0
- package/lib/types/gtk-popover-menu-bar.spec.d.ts +1 -0
- package/lib/types/gtk-popover-menu.spec.d.ts +1 -0
- package/lib/types/gtk-popover-role.spec.d.ts +1 -0
- package/lib/types/gtk-popover.spec.d.ts +1 -0
- package/lib/types/gtk-print-dialogs.spec.d.ts +1 -0
- package/lib/types/gtk-revealer.spec.d.ts +1 -0
- package/lib/types/gtk-scale-button.spec.d.ts +1 -0
- package/lib/types/gtk-scale.spec.d.ts +1 -0
- package/lib/types/gtk-scrollbar.spec.d.ts +1 -0
- package/lib/types/gtk-scrolled-window.spec.d.ts +1 -0
- package/lib/types/gtk-search-bar.spec.d.ts +1 -0
- package/lib/types/gtk-search-entry.spec.d.ts +1 -0
- package/lib/types/gtk-separator.spec.d.ts +1 -0
- package/lib/types/gtk-spin-button.spec.d.ts +1 -0
- package/lib/types/gtk-spinner.spec.d.ts +1 -0
- package/lib/types/gtk-stack-sidebar.spec.d.ts +1 -0
- package/lib/types/gtk-stack-switcher.spec.d.ts +1 -0
- package/lib/types/gtk-stack.spec.d.ts +1 -0
- package/lib/types/gtk-text-view.spec.d.ts +1 -0
- package/lib/types/gtk-text.spec.d.ts +1 -0
- package/lib/types/gtk-toggle-button.spec.d.ts +1 -0
- package/lib/types/gtk-tree-expander.spec.d.ts +1 -0
- package/lib/types/gtk-video.spec.d.ts +1 -0
- package/lib/types/gtk-viewport.spec.d.ts +1 -0
- package/lib/types/gtk-window-controls.spec.d.ts +1 -0
- package/lib/types/gtk-window-handle.spec.d.ts +1 -0
- package/lib/types/gtk-window.spec.d.ts +1 -0
- package/lib/types/index.d.ts +4 -1
- package/lib/types/list-view-dom.d.ts +44 -0
- package/lib/types/namespace/adw.d.ts +12 -0
- package/lib/types/namespace/gtk.d.ts +61 -0
- package/lib/types/page-setup.d.ts +100 -0
- package/lib/types/scroll-shading.d.ts +15 -1
- package/lib/types/shared-tree-builder.d.ts +30 -2
- package/lib/types/signals.d.ts +4 -0
- package/lib/types/styles.generated.d.ts +1 -1
- package/lib/types/tab-chip.d.ts +73 -0
- package/lib/types/template-classes.d.ts +11 -0
- package/package.json +12 -8
- package/scss/_action_row.scss +2 -2
- package/scss/_application_window.scss +26 -0
- package/scss/_aspect_frame.scss +25 -0
- package/scss/_bin.scss +26 -0
- package/scss/_button.scss +45 -0
- package/scss/_calendar.scss +176 -0
- package/scss/_center_box.scss +25 -0
- package/scss/_checks.scss +6 -1
- package/scss/_clamp_scrollable.scss +28 -0
- package/scss/_color_button.scss +67 -0
- package/scss/_column_view.scss +126 -0
- package/scss/_drag_icon.scss +55 -0
- package/scss/_drawing.scss +85 -0
- package/scss/_emoji_chooser.scss +213 -0
- package/scss/_entry.scss +13 -5
- package/scss/_entry_row.scss +1 -1
- package/scss/_expander.scss +113 -0
- package/scss/_fixed.scss +29 -0
- package/scss/_flow_box.scss +94 -0
- package/scss/_font_button.scss +63 -0
- package/scss/_frame.scss +41 -0
- package/scss/_grid.scss +19 -0
- package/scss/_grid_view.scss +46 -0
- package/scss/_gtk_about_dialog.scss +186 -0
- package/scss/_headerbar.scss +132 -0
- package/scss/_icons.generated.scss +186 -0
- package/scss/_inscription.scss +125 -0
- package/scss/_level_bar.scss +190 -0
- package/scss/_link.scss +82 -0
- package/scss/_list_box.scss +88 -0
- package/scss/_list_view.scss +96 -0
- package/scss/_media_controls.scss +139 -0
- package/scss/_overlay.scss +68 -0
- package/scss/_paned.scss +130 -0
- package/scss/_password_entry.scss +83 -0
- package/scss/_picture.scss +80 -0
- package/scss/_popover_bin.scss +53 -0
- package/scss/_popover_menu_bar.scss +104 -0
- package/scss/_preferences_row.scss +51 -0
- package/scss/_print_dialogs.scss +328 -0
- package/scss/_reset.scss +21 -19
- package/scss/_revealer.scss +37 -0
- package/scss/_row.scss +20 -5
- package/scss/_scale.scss +298 -0
- package/scss/_scale_button.scss +167 -0
- package/scss/_scrollbar.scss +230 -0
- package/scss/_scrolled_window.scss +131 -0
- package/scss/_search_bar.scss +118 -0
- package/scss/_search_entry.scss +86 -0
- package/scss/_separator.scss +44 -0
- package/scss/_shortcuts_dialog.scss +100 -0
- package/scss/_spin_button.scss +172 -0
- package/scss/_spin_row.scss +56 -8
- package/scss/_spinner.scss +85 -4
- package/scss/_stack.scss +729 -0
- package/scss/_switch.scss +13 -5
- package/scss/_switch_row.scss +10 -0
- package/scss/_tab_bar.scss +317 -0
- package/scss/_tab_button.scss +98 -0
- package/scss/_tab_overview.scss +483 -0
- package/scss/_text.scss +182 -0
- package/scss/_theme.scss +1 -1
- package/scss/_tree_expander.scss +62 -0
- package/scss/_variables.scss +43 -21
- package/scss/_video.scss +146 -0
- package/scss/_view_switcher_sidebar.scss +112 -0
- package/scss/_viewport.scss +50 -0
- package/scss/_window.scss +118 -1
- package/scss/_window_handle.scss +20 -0
- package/scss/adwaita-skin.scss +109 -0
- package/src/adw-action-rows.spec.ts +76 -0
- package/src/adw-application-window.spec.ts +118 -0
- package/src/adw-bin.spec.ts +75 -0
- package/src/adw-breakpoint-bin.spec.ts +324 -0
- package/src/adw-clamp-scrollable.spec.ts +189 -0
- package/src/adw-multi-layout-view.spec.ts +243 -0
- package/src/adw-preferences-row.spec.ts +164 -0
- package/src/adw-row-state.spec.ts +142 -0
- package/src/adw-shortcuts.spec.ts +155 -0
- package/src/adw-tab-bar.spec.ts +287 -0
- package/src/adw-tab-button.spec.ts +101 -0
- package/src/adw-tab-overview.spec.ts +443 -0
- package/src/adw-view-switcher-sidebar.spec.ts +281 -0
- package/src/adw-window.spec.ts +129 -0
- package/src/breakpoints.ts +25 -8
- package/src/capabilities.d.mts +3 -0
- package/src/capabilities.mjs +18 -0
- package/src/connect-lifecycle.spec.ts +12 -0
- package/src/construct-vectors.spec.ts +175 -0
- package/src/elements/adw-application-window.ts +154 -0
- package/src/elements/adw-bin.ts +101 -0
- package/src/elements/adw-breakpoint-bin.ts +287 -0
- package/src/elements/adw-clamp-scrollable.ts +207 -0
- package/src/elements/adw-dialog.ts +19 -0
- package/src/elements/adw-layout-slot.ts +95 -0
- package/src/elements/adw-multi-layout-view.ts +326 -0
- package/src/elements/adw-preferences-row.ts +150 -0
- package/src/elements/adw-shortcuts-dialog.ts +52 -0
- package/src/elements/adw-shortcuts-item.ts +171 -0
- package/src/elements/adw-shortcuts-section.ts +86 -0
- package/src/elements/adw-sidebar.ts +42 -3
- package/src/elements/adw-switch-row.ts +28 -1
- package/src/elements/adw-tab-bar.ts +529 -0
- package/src/elements/adw-tab-button.ts +194 -0
- package/src/elements/adw-tab-overview.ts +1011 -0
- package/src/elements/adw-tab-view.ts +66 -145
- package/src/elements/adw-toggle-group.ts +20 -5
- package/src/elements/adw-view-stack.ts +18 -0
- package/src/elements/adw-view-switcher-sidebar.ts +332 -0
- package/src/elements/adw-window.ts +185 -11
- package/src/elements/checks.ts +35 -8
- package/src/elements/gtk-about-dialog.ts +811 -0
- package/src/elements/gtk-application-window.ts +108 -0
- package/src/elements/gtk-aspect-frame.ts +160 -0
- package/src/elements/gtk-button.ts +12 -0
- package/src/elements/gtk-calendar.ts +757 -0
- package/src/elements/gtk-center-box.ts +184 -0
- package/src/elements/gtk-color-dialog-button.ts +278 -0
- package/src/elements/gtk-column-view.ts +320 -0
- package/src/elements/gtk-drag-icon.ts +257 -0
- package/src/elements/gtk-drawing-area.ts +303 -0
- package/src/elements/gtk-editable-label.ts +204 -0
- package/src/elements/gtk-emoji-chooser.ts +542 -0
- package/src/elements/gtk-entry.ts +39 -5
- package/src/elements/gtk-expander.ts +301 -0
- package/src/elements/gtk-fixed.ts +99 -0
- package/src/elements/gtk-flow-box-child.ts +68 -0
- package/src/elements/gtk-flow-box.ts +480 -0
- package/src/elements/gtk-font-dialog-button.ts +432 -0
- package/src/elements/gtk-frame.ts +174 -0
- package/src/elements/gtk-gl-area.ts +476 -0
- package/src/elements/gtk-graphics-offload.ts +130 -0
- package/src/elements/gtk-grid-view.ts +168 -0
- package/src/elements/gtk-grid.ts +127 -0
- package/src/elements/gtk-header-bar.ts +273 -0
- package/src/elements/gtk-inscription.ts +387 -0
- package/src/elements/gtk-label.ts +19 -11
- package/src/elements/gtk-level-bar.ts +323 -0
- package/src/elements/gtk-link-button.ts +138 -0
- package/src/elements/gtk-list-box-row.ts +195 -0
- package/src/elements/gtk-list-box.ts +413 -0
- package/src/elements/gtk-list-view.ts +370 -0
- package/src/elements/gtk-media-controls.ts +509 -0
- package/src/elements/gtk-notebook.ts +664 -0
- package/src/elements/gtk-overlay.ts +149 -0
- package/src/elements/gtk-page-setup-unix-dialog.ts +420 -0
- package/src/elements/gtk-paned.ts +597 -0
- package/src/elements/gtk-password-entry.ts +170 -0
- package/src/elements/gtk-picture.ts +254 -0
- package/src/elements/gtk-popover-bin.ts +332 -0
- package/src/elements/gtk-popover-menu-bar.ts +355 -0
- package/src/elements/gtk-popover-menu.ts +339 -0
- package/src/elements/gtk-popover.ts +92 -10
- package/src/elements/gtk-print-unix-dialog.ts +989 -0
- package/src/elements/gtk-progress-bar.ts +24 -11
- package/src/elements/gtk-revealer.ts +406 -0
- package/src/elements/gtk-scale-button.ts +358 -0
- package/src/elements/gtk-scale.ts +492 -0
- package/src/elements/gtk-scrollbar.ts +528 -0
- package/src/elements/gtk-scrolled-window.ts +642 -0
- package/src/elements/gtk-search-bar.ts +200 -0
- package/src/elements/gtk-search-entry.ts +172 -0
- package/src/elements/gtk-separator.ts +52 -0
- package/src/elements/gtk-spin-button.ts +475 -0
- package/src/elements/gtk-spinner.ts +126 -0
- package/src/elements/gtk-stack-sidebar.ts +212 -0
- package/src/elements/gtk-stack-switcher.ts +279 -0
- package/src/elements/gtk-stack.ts +748 -0
- package/src/elements/gtk-switch.ts +52 -19
- package/src/elements/gtk-text-view.ts +290 -0
- package/src/elements/gtk-text.ts +219 -0
- package/src/elements/gtk-toggle-button.ts +239 -0
- package/src/elements/gtk-tree-expander.ts +243 -0
- package/src/elements/gtk-video.ts +423 -0
- package/src/elements/gtk-viewport.ts +277 -0
- package/src/elements/gtk-window-controls.ts +341 -0
- package/src/elements/gtk-window-handle.ts +221 -0
- package/src/elements/gtk-window.ts +366 -0
- package/src/elements/justification.ts +24 -0
- package/src/elements/popover-menu.ts +24 -0
- package/src/elements/roving-focus.ts +53 -21
- package/src/emoji-data.ts +577 -0
- package/src/entry-rows.spec.ts +31 -0
- package/src/font-description.ts +238 -0
- package/src/gtk-about-dialog.spec.ts +250 -0
- package/src/gtk-action-bar.spec.ts +89 -0
- package/src/gtk-application-window.spec.ts +107 -0
- package/src/gtk-aspect-frame.spec.ts +114 -0
- package/src/gtk-calendar.spec.ts +589 -0
- package/src/gtk-center-box.spec.ts +125 -0
- package/src/gtk-color-dialog-button.spec.ts +141 -0
- package/src/gtk-column-view.spec.ts +154 -0
- package/src/gtk-drag-icon.spec.ts +190 -0
- package/src/gtk-drawing-area.spec.ts +211 -0
- package/src/gtk-editable-label.spec.ts +190 -0
- package/src/gtk-emoji-chooser.spec.ts +173 -0
- package/src/gtk-entry.spec.ts +23 -0
- package/src/gtk-expander.spec.ts +170 -0
- package/src/gtk-fixed.spec.ts +97 -0
- package/src/gtk-flow-box.spec.ts +289 -0
- package/src/gtk-font-dialog-button.spec.ts +166 -0
- package/src/gtk-frame.spec.ts +119 -0
- package/src/gtk-gl-area.spec.ts +361 -0
- package/src/gtk-graphics-offload.spec.ts +119 -0
- package/src/gtk-grid-view.spec.ts +106 -0
- package/src/gtk-grid.spec.ts +122 -0
- package/src/gtk-header-bar.spec.ts +202 -0
- package/src/gtk-inscription.spec.ts +235 -0
- package/src/gtk-level-bar.spec.ts +199 -0
- package/src/gtk-link-button.spec.ts +117 -0
- package/src/gtk-list-box.spec.ts +422 -0
- package/src/gtk-list-view.spec.ts +203 -0
- package/src/gtk-media-controls.spec.ts +295 -0
- package/src/gtk-notebook.spec.ts +546 -0
- package/src/gtk-overlay.spec.ts +141 -0
- package/src/gtk-paned.spec.ts +267 -0
- package/src/gtk-password-entry.spec.ts +150 -0
- package/src/gtk-picture.spec.ts +172 -0
- package/src/gtk-popover-bin.spec.ts +229 -0
- package/src/gtk-popover-menu-bar.spec.ts +296 -0
- package/src/gtk-popover-menu.spec.ts +261 -0
- package/src/gtk-popover-role.spec.ts +138 -0
- package/src/gtk-popover.spec.ts +264 -0
- package/src/gtk-print-dialogs.spec.ts +251 -0
- package/src/gtk-revealer.spec.ts +164 -0
- package/src/gtk-scale-button.spec.ts +218 -0
- package/src/gtk-scale.spec.ts +213 -0
- package/src/gtk-scrollbar.spec.ts +244 -0
- package/src/gtk-scrolled-window.spec.ts +262 -0
- package/src/gtk-search-bar.spec.ts +179 -0
- package/src/gtk-search-entry.spec.ts +142 -0
- package/src/gtk-separator.spec.ts +74 -0
- package/src/gtk-spin-button.spec.ts +186 -0
- package/src/gtk-spinner.spec.ts +130 -0
- package/src/gtk-stack-sidebar.spec.ts +217 -0
- package/src/gtk-stack-switcher.spec.ts +249 -0
- package/src/gtk-stack.spec.ts +432 -0
- package/src/gtk-text-view.spec.ts +189 -0
- package/src/gtk-text.spec.ts +163 -0
- package/src/gtk-toggle-button.spec.ts +186 -0
- package/src/gtk-tree-expander.spec.ts +201 -0
- package/src/gtk-video.spec.ts +240 -0
- package/src/gtk-viewport.spec.ts +140 -0
- package/src/gtk-window-controls.spec.ts +232 -0
- package/src/gtk-window-handle.spec.ts +158 -0
- package/src/gtk-window.spec.ts +190 -0
- package/src/index.ts +9 -1
- package/src/keyboard-operable.spec.ts +33 -1
- package/src/list-view-dom.ts +121 -0
- package/src/namespace/adw.ts +12 -0
- package/src/namespace/gtk.ts +61 -0
- package/src/page-setup.ts +222 -0
- package/src/scroll-shading.ts +18 -1
- package/src/shared-tree-builder.ts +263 -21
- package/src/signals.ts +15 -0
- package/src/source-view/theme.ts +11 -5
- package/src/style-classes.spec.ts +9 -8
- package/src/styles.generated.ts +1 -1
- package/src/tab-chip.ts +200 -0
- package/src/template-classes.ts +45 -0
- package/src/test.browser.mts +152 -0
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
// The ROLE a `<gtk-popover>` announces, and what that role then obliges it to do.
|
|
2
|
+
//
|
|
3
|
+
// `menu` and `listbox` are list roles: their `.adw-popover-item` rows are what the arrow
|
|
4
|
+
// keys walk. A popover that holds CONTENT instead — an info button's explanatory text,
|
|
5
|
+
// the HIG pattern — was announced as a menu of commands no matter what it contained, and
|
|
6
|
+
// the type had no spelling for the difference, so a consumer set `role="dialog"` as an
|
|
7
|
+
// attribute the element kept but did not know: `popoverRole` answered `menu` about it.
|
|
8
|
+
//
|
|
9
|
+
// Every KEYBOARD assertion reads `document.activeElement`, never a class or a state object:
|
|
10
|
+
// the half under test is where a key put the focus. A synthetic `keydown` is the event a
|
|
11
|
+
// real key produces minus the browser's own default action, and the default action is
|
|
12
|
+
// exactly what must NOT happen — `preventDefault()` on a walk that moves focus is
|
|
13
|
+
// observable, and an arrow that leaves focus where it was is the defect.
|
|
14
|
+
|
|
15
|
+
import { describe, it, expect } from '@gjsify/unit';
|
|
16
|
+
|
|
17
|
+
import type { GtkPopover, GtkPopoverRole } from './elements/gtk-popover.js';
|
|
18
|
+
|
|
19
|
+
function press(target: HTMLElement, key: string): KeyboardEvent {
|
|
20
|
+
const event = new KeyboardEvent('keydown', { key, bubbles: true, cancelable: true });
|
|
21
|
+
target.dispatchEvent(event);
|
|
22
|
+
return event;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/** An open surface holding `count` navigable rows, in the shape the LIST keys walk. */
|
|
26
|
+
function openSurface(
|
|
27
|
+
role: GtkPopoverRole | null,
|
|
28
|
+
count = 2,
|
|
29
|
+
): { popover: GtkPopover; rows: HTMLButtonElement[]; anchor: HTMLButtonElement; host: HTMLElement } {
|
|
30
|
+
const host = document.createElement('div');
|
|
31
|
+
document.body.appendChild(host);
|
|
32
|
+
const anchor = document.createElement('button') as HTMLButtonElement;
|
|
33
|
+
anchor.textContent = 'anchor';
|
|
34
|
+
const popover = document.createElement('gtk-popover') as GtkPopover;
|
|
35
|
+
if (role !== null) popover.setAttribute('role', role);
|
|
36
|
+
host.append(anchor, popover);
|
|
37
|
+
for (let i = 0; i < count; i++) {
|
|
38
|
+
const row = document.createElement('button') as HTMLButtonElement;
|
|
39
|
+
row.className = 'adw-popover-item';
|
|
40
|
+
row.textContent = `row ${i}`;
|
|
41
|
+
popover.appendChild(row);
|
|
42
|
+
}
|
|
43
|
+
popover.popup();
|
|
44
|
+
return { popover, rows: [...popover.querySelectorAll<HTMLButtonElement>('.adw-popover-item')], anchor, host };
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export const GtkPopoverRoleTest = async () => {
|
|
48
|
+
await describe('<gtk-popover> surface role', async () => {
|
|
49
|
+
await it('reads a dialog role off the surface instead of answering menu', async () => {
|
|
50
|
+
const { popover, host } = openSurface('dialog');
|
|
51
|
+
expect(popover.popoverRole).toBe('dialog');
|
|
52
|
+
host.remove();
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
await it('keeps reading the two list roles, and defaults to menu', async () => {
|
|
56
|
+
for (const role of ['menu', 'listbox'] as const) {
|
|
57
|
+
const { popover, host } = openSurface(role);
|
|
58
|
+
expect(popover.popoverRole).toBe(role);
|
|
59
|
+
host.remove();
|
|
60
|
+
}
|
|
61
|
+
const { popover, host } = openSurface(null);
|
|
62
|
+
expect(popover.popoverRole).toBe('menu');
|
|
63
|
+
host.remove();
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
await it('falls back to the default on an unknown role, on a removed one too', async () => {
|
|
67
|
+
const { popover, host } = openSurface('dialog');
|
|
68
|
+
popover.setAttribute('role', 'teapot');
|
|
69
|
+
// Only the GETTER has a default: an author may spell a role outside this union
|
|
70
|
+
// (a `region`, a `tooltip`), and rewriting what they wrote would take the
|
|
71
|
+
// surface's own choice away from them.
|
|
72
|
+
expect(popover.popoverRole).toBe('menu');
|
|
73
|
+
// A REMOVED role is different — there is nothing left to honour, so it
|
|
74
|
+
// re-declares the default rather than leaving the surface unlabelled.
|
|
75
|
+
popover.setAttribute('role', 'dialog');
|
|
76
|
+
popover.removeAttribute('role');
|
|
77
|
+
expect(popover.getAttribute('role')).toBe('menu');
|
|
78
|
+
expect(popover.popoverRole).toBe('menu');
|
|
79
|
+
host.remove();
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
await it('keeps a role authored in markup across connect', async () => {
|
|
83
|
+
const host = document.createElement('div');
|
|
84
|
+
host.innerHTML = '<gtk-popover role="dialog" aria-label="About"><p>a sentence</p></gtk-popover>';
|
|
85
|
+
document.body.appendChild(host);
|
|
86
|
+
const popover = host.querySelector('gtk-popover') as GtkPopover;
|
|
87
|
+
expect(popover.popoverRole).toBe('dialog');
|
|
88
|
+
expect(popover.getAttribute('role')).toBe('dialog');
|
|
89
|
+
host.remove();
|
|
90
|
+
});
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
await describe('<gtk-popover> the LIST keys follow the role', async () => {
|
|
94
|
+
await it('an arrow walks the rows of a menu surface', async () => {
|
|
95
|
+
const { popover, rows, anchor, host } = openSurface('menu');
|
|
96
|
+
anchor.focus();
|
|
97
|
+
press(popover, 'ArrowDown');
|
|
98
|
+
// The control for the case below: focus that lands on a row is what a walk
|
|
99
|
+
// looks like, and focus that stays put is what its absence looks like.
|
|
100
|
+
expect(document.activeElement).toBe(rows[0]);
|
|
101
|
+
host.remove();
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
await it('an arrow leaves a dialog surface to its content', async () => {
|
|
105
|
+
const { popover, anchor, host } = openSurface('dialog');
|
|
106
|
+
anchor.focus();
|
|
107
|
+
const event = press(popover, 'ArrowDown');
|
|
108
|
+
// The keys are the CONTENT's here — the arrows scroll it — and taking them for
|
|
109
|
+
// a row walk would leave an explanatory popover on arrows that move nothing.
|
|
110
|
+
expect(document.activeElement).toBe(anchor);
|
|
111
|
+
expect(event.defaultPrevented).toBe(false);
|
|
112
|
+
host.remove();
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
await it('Enter does not activate a dialog surface as a menu row', async () => {
|
|
116
|
+
const { popover, rows, host } = openSurface('dialog');
|
|
117
|
+
let activated = -1;
|
|
118
|
+
popover.addEventListener('popover-item-activated', (event) => {
|
|
119
|
+
activated = (event as CustomEvent<{ index: number }>).detail.index;
|
|
120
|
+
});
|
|
121
|
+
rows[0].focus();
|
|
122
|
+
press(popover, 'Enter');
|
|
123
|
+
expect(activated).toBe(-1);
|
|
124
|
+
host.remove();
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
await it('Escape still dismisses a dialog surface, and returns focus to the anchor', async () => {
|
|
128
|
+
// Bound at the document in capture, so the list walk's early return above
|
|
129
|
+
// cannot take the escape hatch with it.
|
|
130
|
+
const { popover, anchor, host } = openSurface('dialog');
|
|
131
|
+
anchor.focus();
|
|
132
|
+
press(popover, 'Escape');
|
|
133
|
+
expect(popover.open).toBe(false);
|
|
134
|
+
expect(document.activeElement).toBe(anchor);
|
|
135
|
+
host.remove();
|
|
136
|
+
});
|
|
137
|
+
});
|
|
138
|
+
};
|
|
@@ -0,0 +1,264 @@
|
|
|
1
|
+
// `<gtk-popover>` — the surface every other popover in this package is built on, and the
|
|
2
|
+
// only one that had no spec of its own: `gtk-drop-down.spec.ts`, `gtk-menu-button.spec.ts`,
|
|
3
|
+
// `split-button.spec.ts` and `keyboard-operable.spec.ts` all drive it THROUGH the widget
|
|
4
|
+
// that owns one, so nothing here pins what it does on its own — which is why
|
|
5
|
+
// `autohide` could be unimplemented while every surface around it was tested.
|
|
6
|
+
//
|
|
7
|
+
// The dismissal arithmetic lives in `@gjsify/adwaita-core` (`PopoverState`,
|
|
8
|
+
// `resolvePopoverKey`, ADR 0004) and is ratcheted there; what these are about is the DOM
|
|
9
|
+
// wiring that binds it: the document grab, the attribute reflection, the anchor, and the
|
|
10
|
+
// row walk with its two skips.
|
|
11
|
+
|
|
12
|
+
import { describe, expect, it } from '@gjsify/unit';
|
|
13
|
+
|
|
14
|
+
import { PopoverState, resolvePopoverKey } from '@gjsify/adwaita-core';
|
|
15
|
+
|
|
16
|
+
interface PopoverElement extends HTMLElement {
|
|
17
|
+
open: boolean;
|
|
18
|
+
autohide: boolean;
|
|
19
|
+
anchor: HTMLElement | null;
|
|
20
|
+
items: HTMLElement[];
|
|
21
|
+
popup(): void;
|
|
22
|
+
popdown(): void;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/** A button (the anchor) with a popover holding `labels` rows, mounted in the document. */
|
|
26
|
+
function mount(labels: string[] = []): { anchor: HTMLButtonElement; popover: PopoverElement } {
|
|
27
|
+
const anchor = document.createElement('button');
|
|
28
|
+
anchor.textContent = 'anchor';
|
|
29
|
+
const popover = document.createElement('gtk-popover') as PopoverElement;
|
|
30
|
+
popover.setAttribute('menu', '');
|
|
31
|
+
for (const label of labels) {
|
|
32
|
+
const row = document.createElement('button');
|
|
33
|
+
row.className = 'adw-popover-item';
|
|
34
|
+
row.type = 'button';
|
|
35
|
+
row.textContent = label;
|
|
36
|
+
popover.appendChild(row);
|
|
37
|
+
}
|
|
38
|
+
anchor.appendChild(popover);
|
|
39
|
+
document.body.appendChild(anchor);
|
|
40
|
+
return { anchor, popover };
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function unmountAll(): void {
|
|
44
|
+
for (const el of Array.from(document.querySelectorAll('button'))) {
|
|
45
|
+
if (el.querySelector('gtk-popover') !== null) el.remove();
|
|
46
|
+
}
|
|
47
|
+
for (const el of Array.from(document.querySelectorAll('gtk-popover'))) el.remove();
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/** A keydown on the document, which is where both grab handlers are bound. */
|
|
51
|
+
function press(key: string): void {
|
|
52
|
+
document.dispatchEvent(new KeyboardEvent('keydown', { key, bubbles: true }));
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export const GtkPopoverTest = async () => {
|
|
56
|
+
await describe('<gtk-popover> open state', async () => {
|
|
57
|
+
await it('reflects the state onto `open` and back, idempotently', () => {
|
|
58
|
+
const { popover } = mount();
|
|
59
|
+
expect(popover.open).toBe(false);
|
|
60
|
+
popover.popup();
|
|
61
|
+
expect(popover.hasAttribute('open')).toBe(true);
|
|
62
|
+
expect(popover.hidden).toBe(false);
|
|
63
|
+
// The markup path: `open` is a GObject-shaped attribute, so setting it in markup
|
|
64
|
+
// has to open the popover rather than leave a stale attribute on a closed one.
|
|
65
|
+
popover.removeAttribute('open');
|
|
66
|
+
expect(popover.open).toBe(false);
|
|
67
|
+
popover.setAttribute('open', '');
|
|
68
|
+
expect(popover.open).toBe(true);
|
|
69
|
+
unmountAll();
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
await it('fires notify::open on a real change only', () => {
|
|
73
|
+
const { popover } = mount();
|
|
74
|
+
const seen: boolean[] = [];
|
|
75
|
+
popover.addEventListener('notify::open', (event) => {
|
|
76
|
+
seen.push((event as CustomEvent<{ open: boolean }>).detail.open);
|
|
77
|
+
});
|
|
78
|
+
popover.popup();
|
|
79
|
+
popover.popup(); // idempotent: `PopoverState._setOpen` returns early
|
|
80
|
+
popover.popdown();
|
|
81
|
+
expect(seen).toStrictEqual([true, false]);
|
|
82
|
+
unmountAll();
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
await it('an element rendered WITH `open` comes up already dismissed-on', () => {
|
|
86
|
+
const popover = document.createElement('gtk-popover') as PopoverElement;
|
|
87
|
+
popover.setAttribute('open', '');
|
|
88
|
+
document.body.appendChild(popover);
|
|
89
|
+
expect(popover.open).toBe(true);
|
|
90
|
+
// The document grab must be armed for a popover that was ALREADY open when it
|
|
91
|
+
// connected, or nothing can dismiss it: `connectedCallback` re-binds every time.
|
|
92
|
+
press('Escape');
|
|
93
|
+
expect(popover.open).toBe(false);
|
|
94
|
+
popover.remove();
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
await it('loses its grab when it is disconnected while open', () => {
|
|
98
|
+
const { anchor, popover } = mount();
|
|
99
|
+
popover.popup();
|
|
100
|
+
anchor.remove();
|
|
101
|
+
// `disconnectedCallback` released the listeners, so an Escape now falls through
|
|
102
|
+
// to the page. Reconnecting re-arms them.
|
|
103
|
+
press('Escape');
|
|
104
|
+
expect(popover.open).toBe(true);
|
|
105
|
+
anchor.appendChild(popover);
|
|
106
|
+
document.body.appendChild(anchor);
|
|
107
|
+
press('Escape');
|
|
108
|
+
expect(popover.open).toBe(false);
|
|
109
|
+
unmountAll();
|
|
110
|
+
});
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
await describe('<gtk-popover> autohide is GTK’s grab', async () => {
|
|
114
|
+
await it('defaults to TRUE, and an outside click then dismisses', () => {
|
|
115
|
+
const { popover } = mount();
|
|
116
|
+
// `priv->autohide = TRUE` (gtkpopover.c:1046), which is what `gtk_popover_map`
|
|
117
|
+
// takes the grab on (gtkpopover.c:1245-1247).
|
|
118
|
+
expect(popover.autohide).toBe(true);
|
|
119
|
+
popover.popup();
|
|
120
|
+
document.body.dispatchEvent(new PointerEvent('pointerdown', { bubbles: true }));
|
|
121
|
+
expect(popover.open).toBe(false);
|
|
122
|
+
unmountAll();
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
await it('with it off, neither an outside click nor Escape dismisses', () => {
|
|
126
|
+
const { popover } = mount();
|
|
127
|
+
popover.setAttribute('autohide', 'false');
|
|
128
|
+
popover.popup();
|
|
129
|
+
document.body.dispatchEvent(new PointerEvent('pointerdown', { bubbles: true }));
|
|
130
|
+
expect(popover.open).toBe(true);
|
|
131
|
+
// Same gate, same reason: without the grab GTK never routes the key here.
|
|
132
|
+
press('Escape');
|
|
133
|
+
expect(popover.open).toBe(true);
|
|
134
|
+
unmountAll();
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
await it('a bare `autohide` attribute is the DEFAULT-TRUE spelling, not "off"', () => {
|
|
138
|
+
const { popover } = mount();
|
|
139
|
+
popover.setAttribute('autohide', '');
|
|
140
|
+
// The property is default-TRUE, so only the string can say "off"; a bare
|
|
141
|
+
// attribute must read as the default or every opt-in would read as an opt-out.
|
|
142
|
+
expect(popover.autohide).toBe(true);
|
|
143
|
+
popover.autohide = false;
|
|
144
|
+
expect(popover.getAttribute('autohide')).toBe('false');
|
|
145
|
+
expect(popover.autohide).toBe(false);
|
|
146
|
+
unmountAll();
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
await it('a click on the ANCHOR does not dismiss — it is the anchor’s own toggle', () => {
|
|
150
|
+
const { anchor, popover } = mount();
|
|
151
|
+
popover.popup();
|
|
152
|
+
anchor.dispatchEvent(new PointerEvent('pointerdown', { bubbles: true }));
|
|
153
|
+
expect(popover.open).toBe(true);
|
|
154
|
+
unmountAll();
|
|
155
|
+
});
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
await describe('<gtk-popover> the row walk', async () => {
|
|
159
|
+
await it('skips hidden and disabled rows', () => {
|
|
160
|
+
const { popover } = mount(['New', 'Cut', 'Copy']);
|
|
161
|
+
const rows = [...popover.querySelectorAll<HTMLButtonElement>('.adw-popover-item')];
|
|
162
|
+
(rows[0] as HTMLButtonElement).disabled = true;
|
|
163
|
+
rows[2].hidden = true;
|
|
164
|
+
// A disabled `<button>` cannot take focus at all, so `focus()` on one is a
|
|
165
|
+
// silent no-op and the arrow key reads as dead; `gtk_widget_focus_move` skips
|
|
166
|
+
// insensitive widgets for the same reason.
|
|
167
|
+
expect(popover.items.map((item) => item.textContent)).toStrictEqual(['Cut']);
|
|
168
|
+
unmountAll();
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
await it('ArrowDown walks the rows and wraps, Enter activates the focused one', () => {
|
|
172
|
+
const { popover } = mount(['a', 'b', 'c']);
|
|
173
|
+
popover.popup();
|
|
174
|
+
const rows = [...popover.querySelectorAll<HTMLButtonElement>('.adw-popover-item')];
|
|
175
|
+
rows[0].focus();
|
|
176
|
+
|
|
177
|
+
const send = (key: string) =>
|
|
178
|
+
popover.dispatchEvent(new KeyboardEvent('keydown', { key, bubbles: true, cancelable: true }));
|
|
179
|
+
send('ArrowDown');
|
|
180
|
+
expect(document.activeElement).toBe(rows[1]);
|
|
181
|
+
send('End');
|
|
182
|
+
expect(document.activeElement).toBe(rows[2]);
|
|
183
|
+
// The wrap the naive modulo gets wrong: ArrowUp from no focus is `n - 1`.
|
|
184
|
+
rows[0].blur();
|
|
185
|
+
rows[0].focus();
|
|
186
|
+
send('ArrowUp');
|
|
187
|
+
expect(document.activeElement).toBe(rows[2]);
|
|
188
|
+
|
|
189
|
+
let activated = -1;
|
|
190
|
+
popover.addEventListener('popover-item-activated', (event) => {
|
|
191
|
+
activated = (event as CustomEvent<{ index: number }>).detail.index;
|
|
192
|
+
});
|
|
193
|
+
send('Enter');
|
|
194
|
+
expect(activated).toBe(2);
|
|
195
|
+
unmountAll();
|
|
196
|
+
});
|
|
197
|
+
|
|
198
|
+
await it('Escape dismisses through the grab, and activates nothing', () => {
|
|
199
|
+
const { popover } = mount(['a']);
|
|
200
|
+
popover.popup();
|
|
201
|
+
let activated = -1;
|
|
202
|
+
popover.addEventListener('popover-item-activated', (event) => {
|
|
203
|
+
activated = (event as CustomEvent<{ index: number }>).detail.index;
|
|
204
|
+
});
|
|
205
|
+
const row = popover.querySelector('.adw-popover-item') as HTMLButtonElement;
|
|
206
|
+
row.focus();
|
|
207
|
+
|
|
208
|
+
popover.dispatchEvent(new KeyboardEvent('keydown', { key: 'Escape', bubbles: true }));
|
|
209
|
+
// `resolvePopoverKey` answers 'close' for Escape and the SURFACE's own handler
|
|
210
|
+
// ignores that answer: the document capture listener is what dismisses, and
|
|
211
|
+
// capture runs from `window` down through every ancestor — so the key closes the
|
|
212
|
+
// popover on the way IN, before the surface's own listener ever sees it.
|
|
213
|
+
expect(popover.open).toBe(false);
|
|
214
|
+
// …and `close` is not `activate`. A dismissal chooses nothing, which is the
|
|
215
|
+
// whole difference between it and Enter.
|
|
216
|
+
expect(activated).toBe(-1);
|
|
217
|
+
unmountAll();
|
|
218
|
+
});
|
|
219
|
+
});
|
|
220
|
+
|
|
221
|
+
await describe('<gtk-popover> core’s arithmetic is the one it resolves', async () => {
|
|
222
|
+
await it('answers the same moves the surface applies', () => {
|
|
223
|
+
// The pin that keeps the element from re-deriving the arithmetic: whatever this
|
|
224
|
+
// table says, `_onKeyDown` must do.
|
|
225
|
+
expect(resolvePopoverKey('ArrowDown', { itemCount: 3, currentIndex: -1 })).toStrictEqual({
|
|
226
|
+
action: 'focus',
|
|
227
|
+
index: 0,
|
|
228
|
+
});
|
|
229
|
+
expect(resolvePopoverKey('ArrowUp', { itemCount: 3, currentIndex: -1 })).toStrictEqual({
|
|
230
|
+
action: 'focus',
|
|
231
|
+
index: 2,
|
|
232
|
+
});
|
|
233
|
+
expect(resolvePopoverKey('ArrowDown', { itemCount: 3, currentIndex: 2 })).toStrictEqual({
|
|
234
|
+
action: 'focus',
|
|
235
|
+
index: 0,
|
|
236
|
+
});
|
|
237
|
+
expect(resolvePopoverKey(' ', { itemCount: 3, currentIndex: 1 })).toStrictEqual({
|
|
238
|
+
action: 'activate',
|
|
239
|
+
index: 1,
|
|
240
|
+
});
|
|
241
|
+
expect(resolvePopoverKey('Escape', { itemCount: 0, currentIndex: -1 })).toStrictEqual({
|
|
242
|
+
action: 'close',
|
|
243
|
+
index: -1,
|
|
244
|
+
});
|
|
245
|
+
// A search entry owns the caret keys while it has focus.
|
|
246
|
+
expect(resolvePopoverKey('Home', { itemCount: 3, currentIndex: -1, hasSearch: true })).toStrictEqual({
|
|
247
|
+
action: 'none',
|
|
248
|
+
index: -1,
|
|
249
|
+
});
|
|
250
|
+
});
|
|
251
|
+
|
|
252
|
+
await it('a state whose programmatic and interactive changes are distinguishable', () => {
|
|
253
|
+
// What a renderer re-emits `notify::*` for, and what makes a dismissal read as
|
|
254
|
+
// a gesture rather than a call.
|
|
255
|
+
const state = new PopoverState();
|
|
256
|
+
const seen: boolean[] = [];
|
|
257
|
+
state.subscribe((change) => seen.push(change.interactive));
|
|
258
|
+
state.popup();
|
|
259
|
+
state.toggle(); // the anchor was clicked: interactive
|
|
260
|
+
state.dismiss(); // already closed — IDEMPOTENT, so it notifies nobody
|
|
261
|
+
expect(seen).toStrictEqual([false, true]);
|
|
262
|
+
});
|
|
263
|
+
});
|
|
264
|
+
};
|
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
// DOM-level tests for the two Unix print dialogs. What they hold is the SENSITIVITY
|
|
2
|
+
// derivation — `update_dialog_from_capabilities` and the three small setters around it —
|
|
3
|
+
// because that is the part of a print dialog a reader cannot check by looking at it, and
|
|
4
|
+
// the part that decides whether the dialog is honest about a printer that is not there.
|
|
5
|
+
import { describe, expect, it } from '@gjsify/unit';
|
|
6
|
+
|
|
7
|
+
import type { GtkPrintUnixDialog } from './elements/gtk-print-unix-dialog.js';
|
|
8
|
+
import type { GtkPageSetupUnixDialog } from './elements/gtk-page-setup-unix-dialog.js';
|
|
9
|
+
import { COMMON_PAPER_SIZES, defaultPageSetup } from './page-setup.js';
|
|
10
|
+
|
|
11
|
+
function mountPrint(attrs: Record<string, string> = {}): { el: GtkPrintUnixDialog; host: HTMLElement } {
|
|
12
|
+
const host = document.createElement('div');
|
|
13
|
+
document.body.appendChild(host);
|
|
14
|
+
const el = document.createElement('gtk-print-unix-dialog') as GtkPrintUnixDialog;
|
|
15
|
+
for (const [name, value] of Object.entries(attrs)) el.setAttribute(name, value);
|
|
16
|
+
host.appendChild(el);
|
|
17
|
+
return { el, host };
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function mountSetup(attrs: Record<string, string> = {}): {
|
|
21
|
+
el: GtkPageSetupUnixDialog;
|
|
22
|
+
host: HTMLElement;
|
|
23
|
+
} {
|
|
24
|
+
const host = document.createElement('div');
|
|
25
|
+
document.body.appendChild(host);
|
|
26
|
+
const el = document.createElement('gtk-page-setup-unix-dialog') as GtkPageSetupUnixDialog;
|
|
27
|
+
for (const [name, value] of Object.entries(attrs)) el.setAttribute(name, value);
|
|
28
|
+
host.appendChild(el);
|
|
29
|
+
return { el, host };
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/** The state of a control the way the C asks for it: `gtk_widget_get_sensitive`. */
|
|
33
|
+
function insensitive(el: Element | null): boolean {
|
|
34
|
+
return el?.hasAttribute('disabled') ?? true;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export const GtkPrintDialogsTest = async () => {
|
|
38
|
+
await describe('<gtk-print-unix-dialog> defaults', async () => {
|
|
39
|
+
await it('is titled "Print" and prints nothing', async () => {
|
|
40
|
+
// gtk_print_unix_dialog_new (gtkprintunixdialog.c:2961-2972) — a NULL title means
|
|
41
|
+
// "Print". The replica is a dialog and nothing more: there is no print backend
|
|
42
|
+
// here to hand a job to.
|
|
43
|
+
const { el, host } = mountPrint();
|
|
44
|
+
expect(el.title).toBe('Print');
|
|
45
|
+
expect(el.querySelectorAll('*').length).toBeGreaterThan(0);
|
|
46
|
+
host.remove();
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
await it('starts with no printer, so Print is insensitive and Preview is hidden', async () => {
|
|
50
|
+
// init (:875-905) sets the OK response INSENSITIVE up front, and
|
|
51
|
+
// update_dialog_from_capabilities (:1587-1588) HIDES Preview without PREVIEW.
|
|
52
|
+
const { el, host } = mountPrint();
|
|
53
|
+
expect(el.selectedPrinter).toBe(null);
|
|
54
|
+
expect(insensitive(el.querySelector('.adw-print-print'))).toBe(true);
|
|
55
|
+
expect(el.querySelector('.adw-print-preview')?.hasAttribute('hidden')).toBe(true);
|
|
56
|
+
host.remove();
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
await it('all seven notebook pages are there, General first', () => {
|
|
60
|
+
const { el, host } = mountPrint();
|
|
61
|
+
const tabs = [...el.querySelectorAll('.adw-print-switcher-item')].map((t) => t.textContent);
|
|
62
|
+
expect(tabs).toStrictEqual([
|
|
63
|
+
'General',
|
|
64
|
+
'Page Setup',
|
|
65
|
+
'Job',
|
|
66
|
+
'Image Quality',
|
|
67
|
+
'Color',
|
|
68
|
+
'Finishing',
|
|
69
|
+
'Advanced',
|
|
70
|
+
]);
|
|
71
|
+
host.remove();
|
|
72
|
+
});
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
await describe('<gtk-print-unix-dialog> capabilities', async () => {
|
|
76
|
+
await it('an empty capability set switches every control off', async () => {
|
|
77
|
+
// update_dialog_from_capabilities (:1563-1592) — every line reads the same mask.
|
|
78
|
+
const { el, host } = mountPrint();
|
|
79
|
+
expect(insensitive(el.querySelector('.adw-print-copies'))).toBe(true);
|
|
80
|
+
expect(insensitive(el.querySelector('.adw-print-scale'))).toBe(true);
|
|
81
|
+
expect(insensitive(el.querySelector('.adw-print-collate'))).toBe(true);
|
|
82
|
+
expect(insensitive(el.querySelector('.adw-print-reverse'))).toBe(true);
|
|
83
|
+
host.remove();
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
await it('manual-capabilities is a nick set, and it is half the mask', async () => {
|
|
87
|
+
const { el, host } = mountPrint({ 'manual-capabilities': 'copies|scale' });
|
|
88
|
+
expect(el.manualCapabilities).toStrictEqual(['copies', 'scale']);
|
|
89
|
+
expect(insensitive(el.querySelector('.adw-print-copies'))).toBe(false);
|
|
90
|
+
expect(insensitive(el.querySelector('.adw-print-scale'))).toBe(false);
|
|
91
|
+
// …and the half it does NOT name stays off.
|
|
92
|
+
expect(insensitive(el.querySelector('.adw-print-reverse'))).toBe(true);
|
|
93
|
+
host.remove();
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
await it('Collate needs a copies count above one as well as the capability', async () => {
|
|
97
|
+
// :1570-1571 — `can_collate` is `*copies != '\0' && atoi (copies) > 1`, and it is
|
|
98
|
+
// ANDed with the COLLATE capability, not either alone.
|
|
99
|
+
const { el, host } = mountPrint({ 'manual-capabilities': 'copies|collate' });
|
|
100
|
+
const copies = el.querySelector<HTMLInputElement>('.adw-print-copies')!;
|
|
101
|
+
const collate = el.querySelector('.adw-print-collate')!;
|
|
102
|
+
expect(insensitive(collate)).toBe(true);
|
|
103
|
+
copies.value = '1';
|
|
104
|
+
copies.dispatchEvent(new Event('input', { bubbles: true }));
|
|
105
|
+
expect(insensitive(collate)).toBe(true);
|
|
106
|
+
copies.value = '2';
|
|
107
|
+
copies.dispatchEvent(new Event('input', { bubbles: true }));
|
|
108
|
+
expect(insensitive(collate)).toBe(false);
|
|
109
|
+
host.remove();
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
await it('Preview appears with the PREVIEW capability and Print with a printer', async () => {
|
|
113
|
+
// Preview is VISIBLE, not merely enabled (:1587-1588); Print follows
|
|
114
|
+
// `gtk_printer_is_accepting_jobs` (:1842-1876).
|
|
115
|
+
const { el, host } = mountPrint({ 'manual-capabilities': 'preview' });
|
|
116
|
+
expect(el.querySelector('.adw-print-preview')?.hasAttribute('hidden')).toBe(false);
|
|
117
|
+
el.printers = [
|
|
118
|
+
{ name: 'Office Laser', location: 'Building A', acceptsJobs: true },
|
|
119
|
+
{ name: 'Broken', acceptsJobs: false },
|
|
120
|
+
];
|
|
121
|
+
expect(insensitive(el.querySelector('.adw-print-print'))).toBe(true);
|
|
122
|
+
el.querySelectorAll<HTMLButtonElement>('.adw-print-printer-row')[0]!.click();
|
|
123
|
+
expect(el.selectedPrinter?.name).toBe('Office Laser');
|
|
124
|
+
expect(insensitive(el.querySelector('.adw-print-print'))).toBe(false);
|
|
125
|
+
el.querySelectorAll<HTMLButtonElement>('.adw-print-printer-row')[1]!.click();
|
|
126
|
+
expect(insensitive(el.querySelector('.adw-print-print'))).toBe(true);
|
|
127
|
+
host.remove();
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
await it("a printer's capabilities join the manual ones", async () => {
|
|
131
|
+
// selected_printer_changed (:1874) replaces the previous printer's half with the
|
|
132
|
+
// new one's, and the mask is `manual | printer` (:1581).
|
|
133
|
+
const { el, host } = mountPrint({ 'manual-capabilities': 'copies' });
|
|
134
|
+
el.printers = [{ name: 'Office Laser', capabilities: ['reverse'] }];
|
|
135
|
+
el.querySelector<HTMLButtonElement>('.adw-print-printer-row')!.click();
|
|
136
|
+
expect(insensitive(el.querySelector('.adw-print-copies'))).toBe(false);
|
|
137
|
+
expect(insensitive(el.querySelector('.adw-print-reverse'))).toBe(false);
|
|
138
|
+
host.remove();
|
|
139
|
+
});
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
await describe('<gtk-print-unix-dialog> selection properties', async () => {
|
|
143
|
+
await it('the Selection radio appears with support and works with a selection', async () => {
|
|
144
|
+
// set_support_selection (:3325-3343) then set_has_selection (:3369-3389) — the
|
|
145
|
+
// second runs last, so "support but nothing to select" ends up INSENSITIVE.
|
|
146
|
+
const { el, host } = mountPrint();
|
|
147
|
+
const radio = el.querySelector('.adw-print-range-selection')!;
|
|
148
|
+
expect(radio.hasAttribute('hidden')).toBe(true);
|
|
149
|
+
el.supportSelection = true;
|
|
150
|
+
expect(radio.hasAttribute('hidden')).toBe(false);
|
|
151
|
+
expect(radio.classList.contains('insensitive')).toBe(true);
|
|
152
|
+
el.hasSelection = true;
|
|
153
|
+
expect(radio.classList.contains('insensitive')).toBe(false);
|
|
154
|
+
host.remove();
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
await it('Current Page needs a page that is not -1', async () => {
|
|
158
|
+
// set_current_page (:3059-3073).
|
|
159
|
+
const { el, host } = mountPrint();
|
|
160
|
+
const radio = el.querySelector('.adw-print-range-current')!;
|
|
161
|
+
expect(radio.classList.contains('insensitive')).toBe(true);
|
|
162
|
+
el.currentPage = 4;
|
|
163
|
+
expect(radio.classList.contains('insensitive')).toBe(false);
|
|
164
|
+
host.remove();
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
await it('the page setup controls are insensitive until the setup is embedded', async () => {
|
|
168
|
+
// set_embed_page_setup (:3415-3427) is the only thing that makes the paper size
|
|
169
|
+
// and orientation drop downs sensitive — and it is also what connects their
|
|
170
|
+
// `notify::selected` handlers.
|
|
171
|
+
const { el, host } = mountPrint();
|
|
172
|
+
el.querySelector<HTMLButtonElement>('.adw-print-switcher-item:nth-child(2)')!.click();
|
|
173
|
+
const preview = el.querySelector('.adw-print-sheet-preview')!;
|
|
174
|
+
const paperDrop = el.querySelector('[aria-label="Paper size"]')!;
|
|
175
|
+
const orientationDrop = el.querySelector('[aria-label="Orientation"]')!;
|
|
176
|
+
el.pageSetup = { ...defaultPageSetup(), paperSize: COMMON_PAPER_SIZES[0]!.name };
|
|
177
|
+
// Not embedded: the drop downs are insensitive, so a selection cannot reach them.
|
|
178
|
+
expect(insensitive(paperDrop)).toBe(true);
|
|
179
|
+
expect(insensitive(orientationDrop)).toBe(true);
|
|
180
|
+
expect(preview.getAttribute('aria-label')).toBe('Page layout preview');
|
|
181
|
+
el.embedPageSetup = true;
|
|
182
|
+
expect(insensitive(paperDrop)).toBe(false);
|
|
183
|
+
expect(insensitive(orientationDrop)).toBe(false);
|
|
184
|
+
host.remove();
|
|
185
|
+
});
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
await describe('<gtk-page-setup-unix-dialog> paper and orientation', async () => {
|
|
189
|
+
await it('is titled "Page Setup" and offers the twelve common sizes', () => {
|
|
190
|
+
// gtk_page_setup_unix_dialog_new (gtkpagesetupunixdialog.c:771-786) and
|
|
191
|
+
// common_paper_sizes (:121-134) — the list is NOT sorted upstream.
|
|
192
|
+
const { el, host } = mountSetup();
|
|
193
|
+
expect(el.title).toBe('Page Setup');
|
|
194
|
+
const model = JSON.parse(el.querySelector('.adw-page-setup-paper')!.getAttribute('model')!);
|
|
195
|
+
expect(model).toHaveLength(COMMON_PAPER_SIZES.length + 1);
|
|
196
|
+
expect(model[0]).toBe(COMMON_PAPER_SIZES[0]!.displayName);
|
|
197
|
+
// The last row is the custom-paper manager, which opens the backends' dialog.
|
|
198
|
+
expect(model[model.length - 1]).toBe('Manage Custom Sizes…');
|
|
199
|
+
host.remove();
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
await it('reports the chosen sheet in its user unit', () => {
|
|
203
|
+
// paper_size_changed (gtkpagesetupunixdialog.c:711-728) — the label is
|
|
204
|
+
// `W × H unit` through double_to_string, which prints no decimal point at all
|
|
205
|
+
// on a whole millimetre.
|
|
206
|
+
const { el, host } = mountSetup();
|
|
207
|
+
const label = el.querySelector('.adw-page-setup-size-label')!;
|
|
208
|
+
expect(label.textContent).toBe('210 × 297 mm');
|
|
209
|
+
expect((label as HTMLElement).title).toContain('Margins:');
|
|
210
|
+
expect((label as HTMLElement).title).toContain('Bottom: 14.2 mm');
|
|
211
|
+
host.remove();
|
|
212
|
+
});
|
|
213
|
+
|
|
214
|
+
await it('the orientation radios are one group and drive the setup', () => {
|
|
215
|
+
// get_orientation / set_orientation (:788-838) — four check buttons in one group.
|
|
216
|
+
const { el, host } = mountSetup();
|
|
217
|
+
expect(el.pageSetup.orientation).toBe('portrait');
|
|
218
|
+
const landscape = [...el.querySelectorAll('adw-radio')].find(
|
|
219
|
+
(radio) => radio.getAttribute('value') === 'landscape',
|
|
220
|
+
)!;
|
|
221
|
+
(landscape as HTMLElement & { checked: boolean }).checked = true;
|
|
222
|
+
expect(el.pageSetup.orientation).toBe('landscape');
|
|
223
|
+
host.remove();
|
|
224
|
+
});
|
|
225
|
+
|
|
226
|
+
await it('a setup with margins no row has is APPENDED, as set_paper_size does', () => {
|
|
227
|
+
// set_page_setup (:823-833) — the model is searched with `page_setup_is_equal`
|
|
228
|
+
// and a miss appends the setup, because `add_item` is TRUE here.
|
|
229
|
+
const { el, host } = mountSetup();
|
|
230
|
+
const custom = {
|
|
231
|
+
paperSize: 'iso_a4',
|
|
232
|
+
orientation: 'portrait' as const,
|
|
233
|
+
margins: { top: 1, bottom: 2, left: 3, right: 4 },
|
|
234
|
+
};
|
|
235
|
+
el.pageSetup = custom;
|
|
236
|
+
expect(el.pageSetup).toStrictEqual(custom);
|
|
237
|
+
host.remove();
|
|
238
|
+
});
|
|
239
|
+
|
|
240
|
+
await it('print-settings select the printer they name', () => {
|
|
241
|
+
// set_print_settings (gtkpagesetupunixdialog.c:897-931) — the ONE key it reads
|
|
242
|
+
// is `format-for-printer`, and it selects that printer when the list has it.
|
|
243
|
+
const { el, host } = mountSetup();
|
|
244
|
+
el.printers = [{ name: 'Office Laser', location: 'Building A' }];
|
|
245
|
+
el.printSettings = { 'format-for-printer': 'Office Laser' };
|
|
246
|
+
const dropdown = el.querySelector('.adw-page-setup-printer') as HTMLElement & { selected: number };
|
|
247
|
+
expect(dropdown.selected).toBe(1);
|
|
248
|
+
host.remove();
|
|
249
|
+
});
|
|
250
|
+
});
|
|
251
|
+
};
|