@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.
- package/dist/adwaita-web.css +8066 -3033
- 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 +1 -1
- 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/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,166 @@
|
|
|
1
|
+
// DOM-level tests for <gtk-font-dialog-button>. The label rules are GTK's and each is
|
|
2
|
+
// separate: at `family` it is one word, at `font` it is family plus size, the size box is
|
|
3
|
+
// gone below `font`, and `use-font` draws the family label in the selected font — with the
|
|
4
|
+
// size only when `use-size` says so.
|
|
5
|
+
import { describe, expect, it } from '@gjsify/unit';
|
|
6
|
+
|
|
7
|
+
import type { GtkFontDialogButton } from './elements/gtk-font-dialog-button.js';
|
|
8
|
+
|
|
9
|
+
function mount(attrs: Record<string, string> = {}): {
|
|
10
|
+
el: GtkFontDialogButton;
|
|
11
|
+
host: HTMLElement;
|
|
12
|
+
label: HTMLElement;
|
|
13
|
+
sizeBox: HTMLElement;
|
|
14
|
+
sizeLabel: HTMLElement;
|
|
15
|
+
button: HTMLButtonElement;
|
|
16
|
+
} {
|
|
17
|
+
const host = document.createElement('div');
|
|
18
|
+
document.body.appendChild(host);
|
|
19
|
+
const el = document.createElement('gtk-font-dialog-button') as GtkFontDialogButton;
|
|
20
|
+
for (const [name, value] of Object.entries(attrs)) el.setAttribute(name, value);
|
|
21
|
+
host.appendChild(el);
|
|
22
|
+
return {
|
|
23
|
+
el,
|
|
24
|
+
host,
|
|
25
|
+
label: el.querySelector('.font-button-label') as HTMLElement,
|
|
26
|
+
sizeBox: el.querySelector('.font-button-size') as HTMLElement,
|
|
27
|
+
sizeLabel: el.querySelector('.font-button-size-label') as HTMLElement,
|
|
28
|
+
button: el.querySelector('button') as HTMLButtonElement,
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export const GtkFontDialogButtonTest = async () => {
|
|
33
|
+
await describe('<gtk-font-dialog-button> defaults', async () => {
|
|
34
|
+
await it('opens on "Sans 12", the description init builds', () => {
|
|
35
|
+
const { el, host, label, sizeLabel } = mount();
|
|
36
|
+
expect(el.fontDesc.family).toBe('Sans');
|
|
37
|
+
expect(el.fontDesc.size).toBe(12);
|
|
38
|
+
expect(label.textContent).toBe('Sans');
|
|
39
|
+
expect(sizeLabel.textContent).toBe('12');
|
|
40
|
+
host.remove();
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
await it('is at level font, so the size box is showing', () => {
|
|
44
|
+
const { el, host, sizeBox } = mount();
|
|
45
|
+
expect(el.level).toBe('font');
|
|
46
|
+
expect(sizeBox.hidden).toBe(false);
|
|
47
|
+
host.remove();
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
await it('is insensitive until a dialog is set', () => {
|
|
51
|
+
const { el, host, button } = mount();
|
|
52
|
+
expect(button.disabled).toBe(true);
|
|
53
|
+
el.dialog = {};
|
|
54
|
+
expect(button.disabled).toBe(false);
|
|
55
|
+
host.remove();
|
|
56
|
+
});
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
await describe('<gtk-font-dialog-button> font-desc', async () => {
|
|
60
|
+
await it('parses Pango’s own string form, styles in any order', () => {
|
|
61
|
+
const { el, host } = mount({ 'font-desc': 'Cantarell Bold Italic 14' });
|
|
62
|
+
expect(el.fontDesc.family).toBe('Cantarell');
|
|
63
|
+
expect(el.fontDesc.weight).toBe(700);
|
|
64
|
+
expect(el.fontDesc.slant).toBe('italic');
|
|
65
|
+
expect(el.fontDesc.size).toBe(14);
|
|
66
|
+
host.remove();
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
await it('remembers a size written in pixels, and prints the unit back', () => {
|
|
70
|
+
const { el, host, sizeLabel } = mount({ 'font-desc': 'Cantarell 18px' });
|
|
71
|
+
expect(el.fontDesc.absolute).toBe(true);
|
|
72
|
+
expect(sizeLabel.textContent).toBe('18px');
|
|
73
|
+
host.remove();
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
await it('a write of the description already held notifies nothing', () => {
|
|
77
|
+
const { el, host } = mount({ 'font-desc': 'Sans 12' });
|
|
78
|
+
const notified: unknown[] = [];
|
|
79
|
+
el.addEventListener('notify::font-desc', (e) => notified.push((e as CustomEvent).detail));
|
|
80
|
+
el.fontDesc = 'Sans 12';
|
|
81
|
+
expect(notified.length).toBe(0);
|
|
82
|
+
el.fontDesc = 'Sans 14';
|
|
83
|
+
expect(notified.length).toBe(1);
|
|
84
|
+
host.remove();
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
await it('a family that was never set reads as the C’s "None"', () => {
|
|
88
|
+
const { el, host, label } = mount();
|
|
89
|
+
el.fontDesc = '12';
|
|
90
|
+
expect(el.fontDesc.family).toBe('');
|
|
91
|
+
expect(label.textContent).toBe('None');
|
|
92
|
+
host.remove();
|
|
93
|
+
});
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
await describe('<gtk-font-dialog-button> level', async () => {
|
|
97
|
+
await it('at family the label is the family alone and the size box is gone', () => {
|
|
98
|
+
const { host, label, sizeBox } = mount({ level: 'family', 'font-desc': 'Cantarell 14' });
|
|
99
|
+
expect(label.textContent).toBe('Cantarell');
|
|
100
|
+
expect(sizeBox.hidden).toBe(true);
|
|
101
|
+
host.remove();
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
await it('at face the size box is gone but the style words are in the label', () => {
|
|
105
|
+
const { el, host, label, sizeBox } = mount();
|
|
106
|
+
el.fontDesc = 'Cantarell Bold 12';
|
|
107
|
+
el.level = 'face';
|
|
108
|
+
expect(sizeBox.hidden).toBe(true);
|
|
109
|
+
expect(label.textContent).toBe('Cantarell Bold');
|
|
110
|
+
host.remove();
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
await it('an unknown level is the default, as an unknown orientation is horizontal', () => {
|
|
114
|
+
const { el, host } = mount();
|
|
115
|
+
el.setAttribute('level', 'glyph');
|
|
116
|
+
expect(el.level).toBe('font');
|
|
117
|
+
host.remove();
|
|
118
|
+
});
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
await describe('<gtk-font-dialog-button> use-font', async () => {
|
|
122
|
+
await it('draws the label in the selected font, without the size unless asked', () => {
|
|
123
|
+
const { el, host, label } = mount({ 'font-desc': 'Cantarell Bold 14' });
|
|
124
|
+
expect(label.style.fontFamily).toBe('');
|
|
125
|
+
el.useFont = true;
|
|
126
|
+
expect(label.style.fontWeight).toBe('700');
|
|
127
|
+
expect(label.style.fontFamily).toBe('"Cantarell"');
|
|
128
|
+
// `use-size` is false, so `PANGO_FONT_MASK_SIZE` was cleared and there is no size.
|
|
129
|
+
expect(label.style.fontSize).toBe('');
|
|
130
|
+
el.useSize = true;
|
|
131
|
+
// `pt`, not a bare `14`: Pango's string carries no unit and a CSS length
|
|
132
|
+
// rejects one that does not, so the projection names the unit Pango means.
|
|
133
|
+
expect(label.style.fontSize).toBe('14pt');
|
|
134
|
+
el.useFont = false;
|
|
135
|
+
expect(label.style.fontFamily).toBe('');
|
|
136
|
+
host.remove();
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
await it('keeps a size written in pixels in pixels', () => {
|
|
140
|
+
const { host, label } = mount({ 'font-desc': 'Cantarell 18px', 'use-font': '', 'use-size': '' });
|
|
141
|
+
expect(label.style.fontSize).toBe('18px');
|
|
142
|
+
host.remove();
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
await it('carries font-features and language into the label with it', () => {
|
|
146
|
+
const { el, host, label } = mount({ 'font-desc': 'Cantarell 12', 'use-font': '', 'use-size': '' });
|
|
147
|
+
el.fontFeatures = 'liga';
|
|
148
|
+
el.language = 'de-de';
|
|
149
|
+
// CSS wants each tag quoted, which is the whole translation Pango's list needs.
|
|
150
|
+
expect(label.style.fontFeatureSettings).toBe('"liga"');
|
|
151
|
+
expect(label.lang).toBe('de-de');
|
|
152
|
+
host.remove();
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
await it('keeps the tags a browser knows and drops the ones it does not', () => {
|
|
156
|
+
const { el, host, label } = mount({ 'font-desc': 'Cantarell 12', 'use-font': '', 'use-size': '' });
|
|
157
|
+
// A `font-feature-settings` value is dropped WHOLE when any tag in it is unknown
|
|
158
|
+
// (measured in Firefox: `"liga", "-kern"` stands for nothing, `"liga"` alone
|
|
159
|
+
// does). So the tags are applied one at a time, and one rejection costs one
|
|
160
|
+
// feature rather than all of them.
|
|
161
|
+
el.fontFeatures = 'liga, -kern';
|
|
162
|
+
expect(label.style.fontFeatureSettings).toBe('"liga"');
|
|
163
|
+
host.remove();
|
|
164
|
+
});
|
|
165
|
+
});
|
|
166
|
+
};
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
// DOM-level tests for <gtk-frame>: the label is a `<gtk-label>` the element builds from
|
|
2
|
+
// the `label` STRING (which is what `gtk_frame_set_label()` does), it is the frame's FIRST
|
|
3
|
+
// child (GTK stacks it above the child), and `label-xalign` is the label's `align-self`.
|
|
4
|
+
import { describe, expect, it } from '@gjsify/unit';
|
|
5
|
+
|
|
6
|
+
import type { GtkFrame } from './elements/gtk-frame.js';
|
|
7
|
+
|
|
8
|
+
function mount(attrs: Record<string, string> = {}, body = ''): { el: GtkFrame; host: HTMLElement } {
|
|
9
|
+
const host = document.createElement('div');
|
|
10
|
+
document.body.appendChild(host);
|
|
11
|
+
const el = document.createElement('gtk-frame') as GtkFrame;
|
|
12
|
+
// Children BEFORE attributes, which is the order the HTML parser sets them in for a
|
|
13
|
+
// custom element: the attribute fires the build while the label is the only child, and
|
|
14
|
+
// the author's own child lands after it.
|
|
15
|
+
if (body !== '') el.innerHTML = body;
|
|
16
|
+
for (const [name, value] of Object.entries(attrs)) el.setAttribute(name, value);
|
|
17
|
+
host.appendChild(el);
|
|
18
|
+
return { el, host };
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/** The label widget the frame is currently showing, or null. */
|
|
22
|
+
const labelWidget = (el: GtkFrame) => (el.labelWidget as HTMLElement | null) ?? null;
|
|
23
|
+
|
|
24
|
+
/** One macrotask, which is after the MutationObserver microtask the element repairs in. */
|
|
25
|
+
const settle = () => new Promise<void>((resolve) => setTimeout(resolve, 0));
|
|
26
|
+
|
|
27
|
+
export const GtkFrameTest = async () => {
|
|
28
|
+
await describe('<gtk-frame> label', async () => {
|
|
29
|
+
await it('builds a gtk-label from the label string and puts it first', () => {
|
|
30
|
+
const { el, host } = mount({ label: 'Details' }, '<gtk-label label="Body"></gtk-label>');
|
|
31
|
+
const label = labelWidget(el);
|
|
32
|
+
expect(label?.tagName.toLowerCase()).toBe('gtk-label');
|
|
33
|
+
expect(label?.getAttribute('label')).toBe('Details');
|
|
34
|
+
expect(el.firstElementChild).toBe(label);
|
|
35
|
+
expect(el.lastElementChild?.getAttribute('label')).toBe('Body');
|
|
36
|
+
host.remove();
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
await it('removes the label when the string goes, and rebuilds it when it returns', () => {
|
|
40
|
+
const { el, host } = mount({ label: 'Details' }, '<gtk-label label="Body"></gtk-label>');
|
|
41
|
+
el.removeAttribute('label');
|
|
42
|
+
expect(labelWidget(el)).toBe(null);
|
|
43
|
+
expect(el.children.length).toBe(1);
|
|
44
|
+
el.setAttribute('label', 'Again');
|
|
45
|
+
expect(el.firstElementChild?.getAttribute('label')).toBe('Again');
|
|
46
|
+
host.remove();
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
await it('an authored label-widget wins over the string, and keeps its place', () => {
|
|
50
|
+
const { el, host } = mount(
|
|
51
|
+
{ label: 'Ignored' },
|
|
52
|
+
'<gtk-label slot="label-widget" label="Authored"></gtk-label><gtk-label label="Body"></gtk-label>',
|
|
53
|
+
);
|
|
54
|
+
const label = labelWidget(el);
|
|
55
|
+
expect(label?.getAttribute('label')).toBe('Authored');
|
|
56
|
+
expect(el.firstElementChild).toBe(label);
|
|
57
|
+
expect(label?.classList.contains('adw-frame-label')).toBe(true);
|
|
58
|
+
host.remove();
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
await it('the label-xalign is a fraction, and reaches the label as align-self', () => {
|
|
62
|
+
const { el, host } = mount({ label: 'Details' }, '<gtk-label label="Body"></gtk-label>');
|
|
63
|
+
expect(el.labelXalign).toBe(0);
|
|
64
|
+
expect(labelWidget(el)?.style.alignSelf).toBe('flex-start');
|
|
65
|
+
el.setAttribute('label-xalign', '0.5');
|
|
66
|
+
expect(el.labelXalign).toBe(0.5);
|
|
67
|
+
expect(labelWidget(el)?.style.alignSelf).toBe('center');
|
|
68
|
+
// Out of range lands on the nearer end, which is what the pspec's 0…1 clamp is.
|
|
69
|
+
el.setAttribute('label-xalign', '4');
|
|
70
|
+
expect(el.labelXalign).toBe(1);
|
|
71
|
+
expect(labelWidget(el)?.style.alignSelf).toBe('flex-end');
|
|
72
|
+
el.setAttribute('label-xalign', 'diagonal');
|
|
73
|
+
expect(el.labelXalign).toBe(0);
|
|
74
|
+
host.remove();
|
|
75
|
+
});
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
await describe('<gtk-frame> surface', async () => {
|
|
79
|
+
await it("is a group, and carries libadwaita's 1px border and card radius", () => {
|
|
80
|
+
const { el, host } = mount();
|
|
81
|
+
expect(el.getAttribute('role')).toBe('group');
|
|
82
|
+
const style = getComputedStyle(el);
|
|
83
|
+
expect(style.borderTopWidth).toBe('1px');
|
|
84
|
+
expect(style.borderTopStyle).toBe('solid');
|
|
85
|
+
expect(style.overflow).toBe('hidden');
|
|
86
|
+
host.remove();
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
await it('notifies on a real change and on none that did not happen', () => {
|
|
90
|
+
const { el, host } = mount({ label: 'One' });
|
|
91
|
+
const notified: unknown[] = [];
|
|
92
|
+
el.addEventListener('notify::label', (event) => notified.push((event as CustomEvent).detail));
|
|
93
|
+
el.label = 'Two';
|
|
94
|
+
el.label = 'Two';
|
|
95
|
+
expect(notified).toStrictEqual([{ label: 'Two' }]);
|
|
96
|
+
host.remove();
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
await it('an author who replaces the children gets the label back', async () => {
|
|
100
|
+
const { el, host } = mount({ label: 'Details' }, '<gtk-label label="Body"></gtk-label>');
|
|
101
|
+
el.innerHTML = '<gtk-label label="New body"></gtk-label>';
|
|
102
|
+
await settle();
|
|
103
|
+
expect(el.firstElementChild?.getAttribute('label')).toBe('Details');
|
|
104
|
+
expect(el.lastElementChild?.getAttribute('label')).toBe('New body');
|
|
105
|
+
host.remove();
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
await it('survives a re-parent without doubling the label', () => {
|
|
109
|
+
const { el, host } = mount({ label: 'Details' }, '<gtk-label label="Body"></gtk-label>');
|
|
110
|
+
const other = document.createElement('div');
|
|
111
|
+
document.body.appendChild(other);
|
|
112
|
+
other.appendChild(el);
|
|
113
|
+
expect(el.querySelectorAll('gtk-label').length).toBe(2);
|
|
114
|
+
expect(el.firstElementChild?.getAttribute('label')).toBe('Details');
|
|
115
|
+
other.remove();
|
|
116
|
+
host.remove();
|
|
117
|
+
});
|
|
118
|
+
});
|
|
119
|
+
};
|
|
@@ -0,0 +1,361 @@
|
|
|
1
|
+
// DOM-level tests for <gtk-gl-area>. What is worth pinning here is the ORDER the C's
|
|
2
|
+
// snapshot runs in and the two flags it clears — a GL application that gets `::render`
|
|
3
|
+
// before the first `::resize` draws into a viewport nobody told it about, and a flag
|
|
4
|
+
// cleared too early loses the frame `queue_render()` asked for from inside `::render`.
|
|
5
|
+
//
|
|
6
|
+
// Every signal the C emits needs a context (`gtkglarea.c:781-782` returns before
|
|
7
|
+
// `::resize` without one), so these tests bring their own through `::create-context`.
|
|
8
|
+
// Whether the BROWSER can hand out WebGL is a property of the machine — headless
|
|
9
|
+
// Firefox says no — and a test that rests on it reports the machine, not the element.
|
|
10
|
+
// See `stubContext`.
|
|
11
|
+
import { describe, expect, it } from '@gjsify/unit';
|
|
12
|
+
|
|
13
|
+
import type { GtkGLArea } from './elements/gtk-gl-area.js';
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* A context that remembers what was switched on, because that is the whole surface the
|
|
17
|
+
* element touches (`attachBuffers` and the snapshot call `enable`/`disable`; `isEnabled`
|
|
18
|
+
* is how a test reads the result back) plus the two capability names it passes them.
|
|
19
|
+
*
|
|
20
|
+
* WHY A STUB AND NOT THE BROWSER'S OWN: `gtk_gl_area_render` returns at
|
|
21
|
+
* `if (priv->context == NULL)` BEFORE it emits `::resize` (gtkglarea.c:781-782), so
|
|
22
|
+
* every signal below depends on a context existing. Chromium hands one out from
|
|
23
|
+
* software GL on a headless runner; Firefox does not, and then every test that waits
|
|
24
|
+
* for a signal waits forever and reports an empty list. That is a fact about the
|
|
25
|
+
* machine, not about the element — so a test may not rest on it. `::create-context`
|
|
26
|
+
* is the documented way in (gtkglarea.c:1086-1109; the element reads `detail.context`
|
|
27
|
+
* and asks the canvas only when nobody supplied one), which is what this uses.
|
|
28
|
+
*/
|
|
29
|
+
function stubContext(): WebGLRenderingContext {
|
|
30
|
+
const enabled = new Set<number>();
|
|
31
|
+
return {
|
|
32
|
+
DEPTH_TEST: 0x0b71,
|
|
33
|
+
STENCIL_TEST: 0x0b90,
|
|
34
|
+
enable: (capability: number) => void enabled.add(capability),
|
|
35
|
+
disable: (capability: number) => void enabled.delete(capability),
|
|
36
|
+
isEnabled: (capability: number) => enabled.has(capability),
|
|
37
|
+
} as unknown as WebGLRenderingContext;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* `context: 'stub'` (the default) gives the element a context of its own, so a test
|
|
42
|
+
* measures the element. `'canvas'` leaves the browser to answer — only the test that is
|
|
43
|
+
* ABOUT the canvas path uses it, and it asks through a recording stub. `'none'` is for
|
|
44
|
+
* the tests that bring their own `create-context` handler.
|
|
45
|
+
*/
|
|
46
|
+
function mount(
|
|
47
|
+
attrs: Record<string, string> = {},
|
|
48
|
+
context: 'stub' | 'canvas' | 'none' = 'stub',
|
|
49
|
+
): { el: GtkGLArea; host: HTMLElement } {
|
|
50
|
+
const host = document.createElement('div');
|
|
51
|
+
document.body.appendChild(host);
|
|
52
|
+
const el = document.createElement('gtk-gl-area') as GtkGLArea;
|
|
53
|
+
el.style.width = '120px';
|
|
54
|
+
el.style.height = '90px';
|
|
55
|
+
for (const [name, value] of Object.entries(attrs)) el.setAttribute(name, value);
|
|
56
|
+
// Before the element is in the tree: the handler is read on the first draw, and the
|
|
57
|
+
// first draw needs an observer record, so it must not be attached after insertion.
|
|
58
|
+
if (context === 'stub') {
|
|
59
|
+
el.addEventListener('create-context', (event) => {
|
|
60
|
+
(event as CustomEvent).detail['context'] = stubContext();
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
host.appendChild(el);
|
|
64
|
+
return { el, host };
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Three frames, and the order is the reason: the element draws in an animation frame
|
|
69
|
+
* that a `ResizeObserver` record schedules, and the platform delivers that record
|
|
70
|
+
* AFTER the animation-frame callbacks of the frame it belongs to — so the draw lands in
|
|
71
|
+
* the frame after the one that observed. Two is what Chromium happens to need, and the
|
|
72
|
+
* count is not a property of the element.
|
|
73
|
+
*/
|
|
74
|
+
function settled(): Promise<void> {
|
|
75
|
+
return new Promise((resolve) => {
|
|
76
|
+
let frames = 0;
|
|
77
|
+
const tick = (): void => {
|
|
78
|
+
frames += 1;
|
|
79
|
+
if (frames >= 3) resolve();
|
|
80
|
+
else requestAnimationFrame(tick);
|
|
81
|
+
};
|
|
82
|
+
requestAnimationFrame(tick);
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
export const GtkGLAreaTest = async () => {
|
|
87
|
+
await describe('<gtk-gl-area> defaults', async () => {
|
|
88
|
+
await it('starts with the GIR defaults and needs_render already set', () => {
|
|
89
|
+
// gtkglarea.c:1101-1105 — auto_render TRUE, needs_render TRUE, allowed APIs
|
|
90
|
+
// `GDK_GL_API_GL | GDK_GL_API_GLES`.
|
|
91
|
+
const { el, host } = mount();
|
|
92
|
+
expect(el.autoRender).toBe(true);
|
|
93
|
+
expect(el.hasDepthBuffer).toBe(false);
|
|
94
|
+
expect(el.hasStencilBuffer).toBe(false);
|
|
95
|
+
expect(el.allowedApis).toStrictEqual(['gl', 'gles']);
|
|
96
|
+
expect(el.context).toBe(null);
|
|
97
|
+
expect(el.error).toBe(null);
|
|
98
|
+
// `get_api` reads 0 — GDK_GL_API_GL — until a context exists.
|
|
99
|
+
expect(el.api).toBe('gl');
|
|
100
|
+
host.remove();
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
await it('reads allowed-apis as a SET of nicks', () => {
|
|
104
|
+
// g_param_spec_flags ("allowed-apis", …) at :983.
|
|
105
|
+
const { el, host } = mount({ 'allowed-apis': 'gles' });
|
|
106
|
+
expect(el.allowedApis).toStrictEqual(['gles']);
|
|
107
|
+
el.allowedApis = ['gl'];
|
|
108
|
+
expect(el.allowedApis).toStrictEqual(['gl']);
|
|
109
|
+
el.allowedApis = ['gl', 'gles'];
|
|
110
|
+
expect(el.allowedApis).toStrictEqual(['gl', 'gles']);
|
|
111
|
+
host.remove();
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
await it('notifies only on a real change', () => {
|
|
115
|
+
const { el, host } = mount();
|
|
116
|
+
const seen: unknown[] = [];
|
|
117
|
+
el.addEventListener('notify::auto-render', (event) =>
|
|
118
|
+
seen.push((event as CustomEvent).detail['auto-render']),
|
|
119
|
+
);
|
|
120
|
+
el.autoRender = true;
|
|
121
|
+
expect(seen).toStrictEqual([]);
|
|
122
|
+
el.autoRender = false;
|
|
123
|
+
expect(seen).toStrictEqual([false]);
|
|
124
|
+
host.remove();
|
|
125
|
+
});
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
await describe('<gtk-gl-area> the snapshot order', async () => {
|
|
129
|
+
await it('emits resize before the first render', async () => {
|
|
130
|
+
// gtkglarea.c:797-807 — the order is the whole point of `needs_resize`.
|
|
131
|
+
const { el, host } = mount();
|
|
132
|
+
const order: string[] = [];
|
|
133
|
+
el.addEventListener('resize', () => order.push('resize'));
|
|
134
|
+
el.addEventListener('render', () => order.push('render'));
|
|
135
|
+
await settled();
|
|
136
|
+
expect(order).toStrictEqual(['resize', 'render']);
|
|
137
|
+
host.remove();
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
await it('hands the resize signal the DEVICE-pixel viewport', async () => {
|
|
141
|
+
// gtkglarea.c:761-763 — `w = gtk_widget_get_width (widget) * scale`.
|
|
142
|
+
const { el, host } = mount();
|
|
143
|
+
const seen: { width: number; height: number }[] = [];
|
|
144
|
+
el.addEventListener('resize', (event) =>
|
|
145
|
+
seen.push((event as unknown as CustomEvent<{ width: number; height: number }>).detail),
|
|
146
|
+
);
|
|
147
|
+
await settled();
|
|
148
|
+
const scale = el.pixelScale;
|
|
149
|
+
expect(seen[0].width).toBe(Math.round(120 * scale));
|
|
150
|
+
expect(seen[0].height).toBe(Math.round(90 * scale));
|
|
151
|
+
expect(el.viewport).toStrictEqual({ width: Math.round(120 * scale), height: Math.round(90 * scale) });
|
|
152
|
+
host.remove();
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
await it('emits resize again only when the allocation changed', async () => {
|
|
156
|
+
const { el, host } = mount();
|
|
157
|
+
let resizes = 0;
|
|
158
|
+
el.addEventListener('resize', () => {
|
|
159
|
+
resizes += 1;
|
|
160
|
+
});
|
|
161
|
+
await settled();
|
|
162
|
+
const first = resizes;
|
|
163
|
+
el.queueRender();
|
|
164
|
+
expect(resizes).toBe(first);
|
|
165
|
+
el.style.width = '160px';
|
|
166
|
+
await settled();
|
|
167
|
+
expect(resizes).toBe(first + 1);
|
|
168
|
+
host.remove();
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
await it('clears needs_render AFTER the signal, so a queue inside it stacks nothing', async () => {
|
|
172
|
+
// gtkglarea.c:800-811 — `priv->needs_render = FALSE` comes AFTER the emit, so
|
|
173
|
+
// a `queue_render()` from a handler has its flag overwritten: the frame is
|
|
174
|
+
// queued, the flag is not. With auto-render off that is ONE render and no
|
|
175
|
+
// runaway — which is also why a GL animation asks per tick rather than from
|
|
176
|
+
// inside `::render`.
|
|
177
|
+
const { el, host } = mount({ 'auto-render': 'false' });
|
|
178
|
+
let renders = 0;
|
|
179
|
+
const onRender = () => {
|
|
180
|
+
renders += 1;
|
|
181
|
+
el.queueRender();
|
|
182
|
+
};
|
|
183
|
+
el.addEventListener('render', onRender);
|
|
184
|
+
await settled();
|
|
185
|
+
expect(renders).toBe(1);
|
|
186
|
+
el.removeEventListener('render', onRender);
|
|
187
|
+
host.remove();
|
|
188
|
+
});
|
|
189
|
+
|
|
190
|
+
await it('emits no render with auto_render off, until something queues one', async () => {
|
|
191
|
+
// gtkglarea.c:800 — `if (priv->needs_render || priv->auto_render)`.
|
|
192
|
+
const { el, host } = mount({ 'auto-render': 'false' });
|
|
193
|
+
let renders = 0;
|
|
194
|
+
el.addEventListener('render', () => {
|
|
195
|
+
renders += 1;
|
|
196
|
+
});
|
|
197
|
+
await settled();
|
|
198
|
+
const first = renders;
|
|
199
|
+
el.queueRender();
|
|
200
|
+
await settled();
|
|
201
|
+
expect(renders).toBe(first + 1);
|
|
202
|
+
host.remove();
|
|
203
|
+
});
|
|
204
|
+
|
|
205
|
+
await it('draws nothing at an empty allocation', async () => {
|
|
206
|
+
// gtkglarea.c:767-768 — `if (w == 0 || h == 0) return;`.
|
|
207
|
+
const { el, host } = mount();
|
|
208
|
+
let renders = 0;
|
|
209
|
+
el.addEventListener('render', () => {
|
|
210
|
+
renders += 1;
|
|
211
|
+
});
|
|
212
|
+
await settled();
|
|
213
|
+
const seen = renders;
|
|
214
|
+
el.style.width = '0px';
|
|
215
|
+
el.queueRender();
|
|
216
|
+
expect(renders).toBe(seen);
|
|
217
|
+
host.remove();
|
|
218
|
+
});
|
|
219
|
+
});
|
|
220
|
+
|
|
221
|
+
await describe('<gtk-gl-area> the context', async () => {
|
|
222
|
+
await it('is created from the canvas, newest API first, and never desktop GL', async () => {
|
|
223
|
+
// The subject is WHERE the context comes from and in what order the element
|
|
224
|
+
// asks for it. It is not whether this browser implements GL: a real
|
|
225
|
+
// `getContext('webgl2')` on the headless Firefox runner returns null, which
|
|
226
|
+
// would say nothing about the element. So the canvas answers through a
|
|
227
|
+
// recording stub, and the two facts the old assertion could not check — the
|
|
228
|
+
// order, and that `gl` is never asked for — come out with it.
|
|
229
|
+
const { el, host } = mount({}, 'canvas');
|
|
230
|
+
const asked: string[] = [];
|
|
231
|
+
const canvas = el.querySelector('canvas') as HTMLCanvasElement;
|
|
232
|
+
// `null` for `webgl2` on purpose: the element stops at the FIRST name the
|
|
233
|
+
// browser answers, so a stub that answered both would record `webgl2` alone
|
|
234
|
+
// and the order would be untested. Refusing the newer name is what puts the
|
|
235
|
+
// fallback — and with it the order — in front of the assertion.
|
|
236
|
+
canvas.getContext = ((name: string) => {
|
|
237
|
+
asked.push(name);
|
|
238
|
+
if (name === 'webgl2') return null;
|
|
239
|
+
return { enable() {}, disable() {} };
|
|
240
|
+
}) as unknown as HTMLCanvasElement['getContext'];
|
|
241
|
+
await settled();
|
|
242
|
+
expect(asked).toStrictEqual(['webgl2', 'webgl']);
|
|
243
|
+
expect(el.api).toBe('gles');
|
|
244
|
+
host.remove();
|
|
245
|
+
});
|
|
246
|
+
|
|
247
|
+
await it('is not created when allowed-apis names neither API', async () => {
|
|
248
|
+
// The no-context branch of the snapshot (:776-777) — nothing is drawn.
|
|
249
|
+
const { el, host } = mount({ 'allowed-apis': '' });
|
|
250
|
+
let renders = 0;
|
|
251
|
+
el.addEventListener('render', () => {
|
|
252
|
+
renders += 1;
|
|
253
|
+
});
|
|
254
|
+
await settled();
|
|
255
|
+
expect(el.context).toBe(null);
|
|
256
|
+
expect(renders).toBe(0);
|
|
257
|
+
host.remove();
|
|
258
|
+
});
|
|
259
|
+
|
|
260
|
+
await it('takes the context a create-context handler supplied', async () => {
|
|
261
|
+
// gtkglarea.c:1086-1109 — a handler RETURNS the context; a browser event has
|
|
262
|
+
// no return channel, so the detail object carries it (see the header).
|
|
263
|
+
const { el, host } = mount({}, 'none');
|
|
264
|
+
const spare = {
|
|
265
|
+
DEPTH_TEST: 1,
|
|
266
|
+
STENCIL_TEST: 2,
|
|
267
|
+
enable() {},
|
|
268
|
+
disable() {},
|
|
269
|
+
} as unknown as WebGLRenderingContext;
|
|
270
|
+
let detail: { context: unknown } | null = null;
|
|
271
|
+
el.addEventListener('create-context', (event) => {
|
|
272
|
+
detail = (event as CustomEvent).detail as { context: unknown };
|
|
273
|
+
detail.context = spare;
|
|
274
|
+
});
|
|
275
|
+
await settled();
|
|
276
|
+
expect(detail).not.toBe(null);
|
|
277
|
+
// A stub is what the handler put there; the element uses it as given, which is
|
|
278
|
+
// what the C does with a handler's context. It carries the two calls every draw
|
|
279
|
+
// makes, because an object without them throws out of the next frame.
|
|
280
|
+
expect(el.context).toBe(spare);
|
|
281
|
+
host.remove();
|
|
282
|
+
});
|
|
283
|
+
|
|
284
|
+
await it('refuses a changed allowed-apis once the area is realized', async () => {
|
|
285
|
+
// gtkglarea.c:1242 — `g_return_if_fail (!gtk_widget_get_realized (…))`. The
|
|
286
|
+
// context is built from the set once, so a later write is undone: the attribute
|
|
287
|
+
// goes back to the set in force and nothing notifies (the C only warns).
|
|
288
|
+
const { el, host } = mount();
|
|
289
|
+
await settled();
|
|
290
|
+
expect(el.context).not.toBe(null);
|
|
291
|
+
const notified: string[] = [];
|
|
292
|
+
el.addEventListener('notify::allowed-apis', () => notified.push('notify'));
|
|
293
|
+
el.allowedApis = ['gl'];
|
|
294
|
+
expect(el.allowedApis).toStrictEqual(['gl', 'gles']);
|
|
295
|
+
expect(el.getAttribute('allowed-apis')).toBe('gl gles');
|
|
296
|
+
expect(notified).toStrictEqual([]);
|
|
297
|
+
host.remove();
|
|
298
|
+
});
|
|
299
|
+
});
|
|
300
|
+
|
|
301
|
+
await describe('<gtk-gl-area> buffers and errors', async () => {
|
|
302
|
+
await it('enables the depth test only when the depth buffer is asked for', async () => {
|
|
303
|
+
// gtkglarea.c:782-785 — `glEnable`/`glDisable (GL_DEPTH_TEST)`, in the SNAPSHOT,
|
|
304
|
+
// not in `attach_buffers`. Neither buffer setter queues a redraw (:1391-1396), so
|
|
305
|
+
// the application asks for the frame that applies it — exactly as it would in GTK.
|
|
306
|
+
const { el, host } = mount();
|
|
307
|
+
await settled();
|
|
308
|
+
const context = el.context;
|
|
309
|
+
expect(context).not.toBe(null);
|
|
310
|
+
expect(context?.isEnabled((context as WebGLRenderingContext).DEPTH_TEST)).toBe(false);
|
|
311
|
+
el.hasDepthBuffer = true;
|
|
312
|
+
el.queueRender();
|
|
313
|
+
await settled();
|
|
314
|
+
expect(context?.isEnabled((context as WebGLRenderingContext).DEPTH_TEST)).toBe(true);
|
|
315
|
+
host.remove();
|
|
316
|
+
});
|
|
317
|
+
|
|
318
|
+
await it('attaches the stencil buffer when asked for, through attach_buffers', async () => {
|
|
319
|
+
// gtkglarea.c:583-618 — the renderbuffer the two setters drop `have_buffers` for.
|
|
320
|
+
const { el, host } = mount();
|
|
321
|
+
await settled();
|
|
322
|
+
const context = el.context as WebGLRenderingContext;
|
|
323
|
+
el.hasStencilBuffer = true;
|
|
324
|
+
el.attachBuffers(context);
|
|
325
|
+
expect(context.isEnabled(context.STENCIL_TEST)).toBe(true);
|
|
326
|
+
el.hasStencilBuffer = false;
|
|
327
|
+
el.attachBuffers(context);
|
|
328
|
+
expect(context.isEnabled(context.STENCIL_TEST)).toBe(false);
|
|
329
|
+
host.remove();
|
|
330
|
+
});
|
|
331
|
+
|
|
332
|
+
await it('shows the error message over the widget and draws nothing', async () => {
|
|
333
|
+
// gtkglarea.c:769-775 and `gtk_gl_area_draw_error_screen` at :701-723.
|
|
334
|
+
const { el, host } = mount();
|
|
335
|
+
let renders = 0;
|
|
336
|
+
el.addEventListener('render', () => {
|
|
337
|
+
renders += 1;
|
|
338
|
+
});
|
|
339
|
+
await settled();
|
|
340
|
+
const seen = renders;
|
|
341
|
+
el.setError('could not create GL context');
|
|
342
|
+
await settled();
|
|
343
|
+
expect(el.error).toBe('could not create GL context');
|
|
344
|
+
expect(el.querySelector('.adw-gl-area-error')?.textContent).toBe('could not create GL context');
|
|
345
|
+
expect(renders).toBe(seen);
|
|
346
|
+
// The canvas is still there: GTK replaces a frame's contents, not the node.
|
|
347
|
+
expect(el.querySelector('canvas')).not.toBe(null);
|
|
348
|
+
host.remove();
|
|
349
|
+
});
|
|
350
|
+
|
|
351
|
+
await it('takes an Error as readily as its message, and clears on null', () => {
|
|
352
|
+
const { el, host } = mount();
|
|
353
|
+
el.setError(new Error('GL error'));
|
|
354
|
+
expect(el.error).toBe('GL error');
|
|
355
|
+
el.setError(null);
|
|
356
|
+
expect(el.error).toBe(null);
|
|
357
|
+
expect(el.querySelector('.adw-gl-area-error')).toBe(null);
|
|
358
|
+
host.remove();
|
|
359
|
+
});
|
|
360
|
+
});
|
|
361
|
+
};
|