@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,277 @@
|
|
|
1
|
+
// <gtk-viewport> — a window onto a child too large to show whole: GTK's answer for a
|
|
2
|
+
// widget that does not know how to scroll itself.
|
|
3
|
+
//
|
|
4
|
+
// WHAT IT IS, in GTK's own words: "Implements scrollability for widgets that don't support
|
|
5
|
+
// scrolling on their own" (gtkviewport.c:44-46). It has ONE property of its own
|
|
6
|
+
// (`scroll-to-focus`) and takes its two adjustments from `Gtk.Scrollable`, the interface
|
|
7
|
+
// every scroller in a `GtkScrolledWindow` is addressed through (gtkviewport.c:318-327). This
|
|
8
|
+
// element is therefore the CONTENT HALF of `<gtk-scrolled-window>`, exactly as it is in GTK:
|
|
9
|
+
// setting a non-scrollable child on a scrolled window makes the window "add the child to a
|
|
10
|
+
// Gtk.Viewport and then set the viewport as the child" (gtkscrolledwindow.c:780-793), which
|
|
11
|
+
// is `gtk_scrolled_window_set_child` doing it at gtkscrolledwindow.c:4362-4374.
|
|
12
|
+
//
|
|
13
|
+
// THE ADJUSTMENTS ARE GTK'S ARITHMETIC, VERBATIM. `viewport_set_adjustment_values`
|
|
14
|
+
// (gtkviewport.c:159-189) configures each axis as
|
|
15
|
+
//
|
|
16
|
+
// configure(value, lower: 0, upper: child_size, step: viewport_size * 0.1,
|
|
17
|
+
// page: viewport_size * 0.9, page_size: viewport_size)
|
|
18
|
+
//
|
|
19
|
+
// so a step is a tenth of the window and a page nine tenths of it — which is why a
|
|
20
|
+
// GtkViewport under the mouse wheel moves by the same PROPORTION whatever it wraps. In a
|
|
21
|
+
// browser those six numbers are what the scrollport already knows: `scrollLeft` /
|
|
22
|
+
// `scrollTop` are the value, `scrollWidth` / `scrollHeight` the upper and `clientWidth` /
|
|
23
|
+
// `clientHeight` the page size. The port READS them; it does not recompute a layout GTK
|
|
24
|
+
// negotiated itself. The two are one element HERE for the same reason they are two nodes
|
|
25
|
+
// there: the `viewport` node is the box that clips and the one that is measured, and a
|
|
26
|
+
// browser scrollport is both at once.
|
|
27
|
+
//
|
|
28
|
+
// THE CHILD IS ALLOCATED ITS NATURAL SIZE, never shrunk — `gtk_viewport_size_allocate`
|
|
29
|
+
// measures the child and hands it `MAX (allocated, nat)` (gtkviewport.c:517-545, 550-560),
|
|
30
|
+
// so content wider than the window makes the window scroll sideways instead of being squeezed
|
|
31
|
+
// into it. The CSS spelling of "never shrink it" is `flex: none` on the child of a flex
|
|
32
|
+
// scrollport, which is in `_viewport.scss`; a child that shrinks instead reports its minimum
|
|
33
|
+
// as its size, which is the one thing a viewport exists to avoid.
|
|
34
|
+
//
|
|
35
|
+
// `scroll-to-focus` is the other property, and it is `gtk_viewport_scroll_to` driven by
|
|
36
|
+
// `notify::focus-widget`: when the focus widget changes, the viewport moves its adjustment
|
|
37
|
+
// so the focused widget is inside the window (`focus_change_handler`, gtkviewport.c:620-643).
|
|
38
|
+
// A `focusin` on the host is the same reach — it fires for every focus change inside this
|
|
39
|
+
// subtree and nowhere else, which is also the `FOCUS_WITHIN` test the C applies first
|
|
40
|
+
// (gtkviewport.c:625-626). `scrollIntoView` then replaces `gtk_scroll_info_compute_scroll`
|
|
41
|
+
// and the two animated `set_value` calls (gtkviewport.c:742-758).
|
|
42
|
+
//
|
|
43
|
+
// NO SLOT BINDING, deliberately. The element HAS no internal structure: a child's place is
|
|
44
|
+
// the child list, so there is nothing to route it into, and `bindSlottedChildren` exists for
|
|
45
|
+
// the elements that built a box around their content. `<gtk-scrolled-window>`'s own binding
|
|
46
|
+
// targets THIS element, so the child's placement is one hop from the widget the author wrote
|
|
47
|
+
// it in.
|
|
48
|
+
//
|
|
49
|
+
// A11y: GTK gave the widget the role `GTK_ACCESSIBLE_ROLE_GENERIC` in 4.12
|
|
50
|
+
// (gtkviewport.c:353-354), so the element carries `role="generic"` and nothing else: what is
|
|
51
|
+
// inside the window is what a screen reader announces.
|
|
52
|
+
//
|
|
53
|
+
// NOT PORTED: `hscroll-policy` / `vscroll-policy` (`GtkScrollable`'s enum) choose whether
|
|
54
|
+
// `upper` is the child's MINIMUM size or its NATURAL size — the `GTK_SCROLL_MINIMUM` branch
|
|
55
|
+
// of the same `size_allocate` (gtkviewport.c:532-535, 541-544) — and a browser scrollport has
|
|
56
|
+
// exactly one content size. `hadjustment` / `vadjustment` are read-only properties here for
|
|
57
|
+
// the same reason `GtkViewport` keeps configuring them: it OWNS them
|
|
58
|
+
// (gtkviewport.c:479-500, `viewport_set_adjustment_values` reconfiguring on every allocation).
|
|
59
|
+
//
|
|
60
|
+
// Reference: refs/gtk/gtk/gtkviewport.c (size_allocate, viewport_set_adjustment_values,
|
|
61
|
+
// scroll_to_focus, focus_change_handler, scroll_to)
|
|
62
|
+
// Reference: refs/gtk/gtk/gtkscrolledwindow.c:785-793 (a non-scrollable child is wrapped)
|
|
63
|
+
// Copyright (c) The GTK Team. LGPLv2.1+.
|
|
64
|
+
// Modifications: Implemented as a Web Component for @gjsify/adwaita-web.
|
|
65
|
+
|
|
66
|
+
import { clampAdjustmentValue, normalizeAdjustment, type AdwAdjustment } from '@gjsify/adwaita-core';
|
|
67
|
+
|
|
68
|
+
/** `viewport_set_adjustment_values`'s two fractions of the visible size. */
|
|
69
|
+
const STEP_FRACTION = 0.1;
|
|
70
|
+
const PAGE_FRACTION = 0.9;
|
|
71
|
+
|
|
72
|
+
/** The two axes a scrollport reports numbers for, in the order GTK declares them. */
|
|
73
|
+
const AXES = ['horizontal', 'vertical'] as const;
|
|
74
|
+
type Axis = (typeof AXES)[number];
|
|
75
|
+
|
|
76
|
+
/** The adjustment of a scrollport on one axis — GTK's configure, read off the DOM. */
|
|
77
|
+
function axisAdjustment(clip: HTMLElement, axis: Axis): AdwAdjustment {
|
|
78
|
+
const vertical = axis === 'vertical';
|
|
79
|
+
const viewportSize = vertical ? clip.clientHeight : clip.clientWidth;
|
|
80
|
+
const contentSize = vertical ? clip.scrollHeight : clip.scrollWidth;
|
|
81
|
+
const value = vertical ? clip.scrollTop : clip.scrollLeft;
|
|
82
|
+
return normalizeAdjustment({
|
|
83
|
+
value,
|
|
84
|
+
lower: 0,
|
|
85
|
+
// GTK holds `upper` at the child size and lets `set_value`'s clamp deal with a
|
|
86
|
+
// content smaller than the window; `normalizeAdjustment` wants `upper >= lower`,
|
|
87
|
+
// so the larger of the two is what the range is written with.
|
|
88
|
+
upper: Math.max(contentSize, viewportSize),
|
|
89
|
+
stepIncrement: viewportSize * STEP_FRACTION,
|
|
90
|
+
pageIncrement: viewportSize * PAGE_FRACTION,
|
|
91
|
+
pageSize: viewportSize,
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
export class GtkViewport extends HTMLElement {
|
|
96
|
+
private _observer: ResizeObserver | null = null;
|
|
97
|
+
private _watch: MutationObserver | null = null;
|
|
98
|
+
|
|
99
|
+
static get observedAttributes() {
|
|
100
|
+
return ['scroll-to-focus'];
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* `GtkScrollable:hadjustment` — the horizontal position, as the portable value.
|
|
105
|
+
*
|
|
106
|
+
* Computed on read rather than stored: `viewport_set_adjustment_values` reconfigures both
|
|
107
|
+
* axes on every allocation, so there is no state to cache and nothing an author can write.
|
|
108
|
+
*/
|
|
109
|
+
get hadjustment(): AdwAdjustment {
|
|
110
|
+
return axisAdjustment(this, 'horizontal');
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/** `GtkScrollable:vadjustment` — the vertical position, as the portable value. */
|
|
114
|
+
get vadjustment(): AdwAdjustment {
|
|
115
|
+
return axisAdjustment(this, 'vertical');
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* `GtkViewport:scroll-to-focus` — whether the viewport keeps the focus widget in view.
|
|
120
|
+
* TRUE in the pspec (gtkviewport.c:338-340), and an unknown value is the DEFAULT rather
|
|
121
|
+
* than "off": only the literal `false` turns it off, which is what FALSE in a construct
|
|
122
|
+
* bag means and what a boolean attribute has to spell out to be read at all.
|
|
123
|
+
*/
|
|
124
|
+
get scrollToFocus(): boolean {
|
|
125
|
+
return this.getAttribute('scroll-to-focus') !== 'false';
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
set scrollToFocus(value: boolean) {
|
|
129
|
+
this.setAttribute('scroll-to-focus', value ? 'true' : 'false');
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
connectedCallback() {
|
|
133
|
+
this.setAttribute('role', 'generic');
|
|
134
|
+
// `scroll` does not bubble, so the platform's own is heard here, on the node that
|
|
135
|
+
// raised it, and re-announced as GTK's `GtkAdjustment::value-changed`.
|
|
136
|
+
this.addEventListener('scroll', this._announce, { passive: true });
|
|
137
|
+
this._observe();
|
|
138
|
+
this._bindFocus();
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
disconnectedCallback() {
|
|
142
|
+
this.removeEventListener('scroll', this._announce);
|
|
143
|
+
this.removeEventListener('focusin', this._onFocusIn);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* Announce whenever a number the adjustments are made of has changed.
|
|
148
|
+
*
|
|
149
|
+
* GTK reconfigures both axes on every allocation — `viewport_set_adjustment_values` runs
|
|
150
|
+
* out of `size_allocate`, and `gtk_adjustment_configure` compresses the notifications into
|
|
151
|
+
* one. A browser reports the same event as the scrollport's own box changing (this
|
|
152
|
+
* element) and its CONTENT changing (the children), and neither is the other's: a child
|
|
153
|
+
* that grows leaves the viewport's box exactly where it was, which is why BOTH are watched.
|
|
154
|
+
* The content watcher is what makes a scrolled window's bars appear the moment content
|
|
155
|
+
* lands in it, and it is `gtk_widget_queue_resize` on the child propagating upward.
|
|
156
|
+
*/
|
|
157
|
+
private _observe(): void {
|
|
158
|
+
if (this._observer !== null) return;
|
|
159
|
+
this._observer = new ResizeObserver(() => this._announce());
|
|
160
|
+
this._observer.observe(this);
|
|
161
|
+
for (const child of this.children) this._observer.observe(child);
|
|
162
|
+
// A child added or removed is a size to watch; `observe` is idempotent, so the ones
|
|
163
|
+
// already watched are simply named again.
|
|
164
|
+
this._watch = new MutationObserver(() => {
|
|
165
|
+
for (const child of this.children) this._observer?.observe(child);
|
|
166
|
+
this._announce();
|
|
167
|
+
});
|
|
168
|
+
this._watch.observe(this, { childList: true });
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
attributeChangedCallback(name: string) {
|
|
172
|
+
// The handler's own registration depends on the value, so a change re-binds it — the
|
|
173
|
+
// shape `scripts/check-adwaita-connect-rebind.mjs` accepts. GTK notifies here too
|
|
174
|
+
// (gtkviewport.c:617), and a property notify is the whole of that call.
|
|
175
|
+
this.dispatchEvent(
|
|
176
|
+
new CustomEvent(`notify::${name}`, { bubbles: true, detail: { [name]: this.scrollToFocus } }),
|
|
177
|
+
);
|
|
178
|
+
if (!this.isConnected) return;
|
|
179
|
+
this._bindFocus();
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* `gtk_adjustment_set_value` on one of the viewport's OWN adjustments — the half of a
|
|
184
|
+
* scrolled window's job that moves content rather than deciding whether to.
|
|
185
|
+
*
|
|
186
|
+
* The value is clamped first, which is `set_value`'s documented behaviour ("The value is
|
|
187
|
+
* clamped to lie between lower and upper") and the reason a bar may ask for a position its
|
|
188
|
+
* own range has just outgrown.
|
|
189
|
+
*/
|
|
190
|
+
scrollAxis(axis: Axis, value: number): void {
|
|
191
|
+
const adjustment = axisAdjustment(this, axis);
|
|
192
|
+
const next = clampAdjustmentValue(adjustment, value);
|
|
193
|
+
if (next === adjustment.value) return;
|
|
194
|
+
if (axis === 'vertical') this.scrollTop = next;
|
|
195
|
+
else this.scrollLeft = next;
|
|
196
|
+
this._announce();
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
/**
|
|
200
|
+
* `gtk_viewport_scroll_to` — move the position so `descendant` is inside the window.
|
|
201
|
+
* `null` asks only for the position to be CLAMPED, which is what a content that shrank
|
|
202
|
+
* needs from a value that was legal a moment ago.
|
|
203
|
+
*
|
|
204
|
+
* GTK animates the move (`gtk_adjustment_animate_to_value`, gtkviewport.c:757-758) for
|
|
205
|
+
* `ANIMATION_DURATION` unless the widget should not animate — the browser's spelling of
|
|
206
|
+
* that setting is `prefers-reduced-motion`, and `scrollIntoView`'s own `behavior` is where
|
|
207
|
+
* the choice belongs.
|
|
208
|
+
*
|
|
209
|
+
* `scrollTo` IS a platform method with an options form, so both are here and the KIND of
|
|
210
|
+
* the argument decides: a node is GTK's `scroll_to(descendant)` and anything else is the
|
|
211
|
+
* scrollport's own `scrollTo(options)`, which this element is (one element for the two
|
|
212
|
+
* GTK nodes is the port's own decision, see the header).
|
|
213
|
+
*/
|
|
214
|
+
scrollTo(descendant: Element | null): void;
|
|
215
|
+
scrollTo(options?: ScrollToOptions): void;
|
|
216
|
+
scrollTo(x: number, y: number): void;
|
|
217
|
+
scrollTo(descendantOrOptions?: Element | ScrollToOptions | number | null, y?: number): void {
|
|
218
|
+
if (!(descendantOrOptions instanceof Element) && descendantOrOptions !== null) {
|
|
219
|
+
Element.prototype.scrollTo.call(this, descendantOrOptions as ScrollToOptions | undefined, y);
|
|
220
|
+
return;
|
|
221
|
+
}
|
|
222
|
+
const descendant = descendantOrOptions;
|
|
223
|
+
if (
|
|
224
|
+
descendant !== null &&
|
|
225
|
+
descendant !== this &&
|
|
226
|
+
typeof (descendant as HTMLElement).scrollIntoView === 'function'
|
|
227
|
+
) {
|
|
228
|
+
(descendant as HTMLElement).scrollIntoView({
|
|
229
|
+
block: 'nearest',
|
|
230
|
+
inline: 'nearest',
|
|
231
|
+
behavior: matchMedia('(prefers-reduced-motion: reduce)').matches ? 'auto' : 'smooth',
|
|
232
|
+
});
|
|
233
|
+
this._announce();
|
|
234
|
+
return;
|
|
235
|
+
}
|
|
236
|
+
for (const axis of AXES) {
|
|
237
|
+
const adjustment = axisAdjustment(this, axis);
|
|
238
|
+
const clamped = clampAdjustmentValue(adjustment, adjustment.value);
|
|
239
|
+
if (clamped === adjustment.value) continue;
|
|
240
|
+
if (axis === 'vertical') this.scrollTop = clamped;
|
|
241
|
+
else this.scrollLeft = clamped;
|
|
242
|
+
}
|
|
243
|
+
this._announce();
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
/** The adjustments of both axes, as the detail of the `value-changed` event. */
|
|
247
|
+
get adjustments(): { hadjustment: AdwAdjustment; vadjustment: AdwAdjustment } {
|
|
248
|
+
return { hadjustment: this.hadjustment, vadjustment: this.vadjustment };
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
/**
|
|
252
|
+
* One event for both adjustments: a browser scroll moves them together, and the C's
|
|
253
|
+
* `GtkAdjustment::value-changed` is a signal of the ADJUSTMENT rather than of the viewport
|
|
254
|
+
* that reads it. Bubbling, so `<gtk-scrolled-window>` hears it without holding a reference
|
|
255
|
+
* to anything in here.
|
|
256
|
+
*/
|
|
257
|
+
private _announce = (): void => {
|
|
258
|
+
this.dispatchEvent(new CustomEvent('value-changed', { bubbles: true, detail: this.adjustments }));
|
|
259
|
+
};
|
|
260
|
+
|
|
261
|
+
/** `setup_focus_change_handler` / `clear_focus_change_handler`, on one event instead of a root signal. */
|
|
262
|
+
private _bindFocus(): void {
|
|
263
|
+
this.removeEventListener('focusin', this._onFocusIn);
|
|
264
|
+
if (!this.scrollToFocus) return;
|
|
265
|
+
this.addEventListener('focusin', this._onFocusIn);
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
private _onFocusIn = (event: Event): void => {
|
|
269
|
+
const target = event.target;
|
|
270
|
+
// The event came from inside, which is the C's `FOCUS_WITHIN` test; a target that is
|
|
271
|
+
// the host itself is the viewport taking focus, not a widget to reveal.
|
|
272
|
+
if (!(target instanceof Element) || target === this) return;
|
|
273
|
+
this.scrollTo(target);
|
|
274
|
+
};
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
customElements.define('gtk-viewport', GtkViewport);
|
|
@@ -0,0 +1,341 @@
|
|
|
1
|
+
// <gtk-window-controls> — the window-frame buttons of ONE side: the window icon and the
|
|
2
|
+
// minimize, maximize and close buttons, in the order the decoration layout names them.
|
|
3
|
+
// GTK puts one of these at each end of a header bar and binds the bar's `decoration-layout`
|
|
4
|
+
// to both (gtkheaderbar.c:222-249), which is why `side` exists at all.
|
|
5
|
+
//
|
|
6
|
+
// WHAT IT IS NOT: A TOPLEVEL. `update_window_buttons` opens with the root check and
|
|
7
|
+
// RETURNS on it — no `GtkWindow` above, `set_empty (self, TRUE)` and nothing else
|
|
8
|
+
// (gtkwindowcontrols.c:257-264). A `GtkWindowControls` outside a window therefore draws
|
|
9
|
+
// nothing, and the story on /gjsify/gtk/windows/ puts one inside a `<gtk-window>` for
|
|
10
|
+
// exactly that reason. A browser has no toplevel and no window manager to ask, so the ROOT
|
|
11
|
+
// here is the nearest `<gtk-window>`/`<adw-window>` ancestor: this is the widget's DECISION
|
|
12
|
+
// LOGIC run against an in-page frame, not a window.
|
|
13
|
+
//
|
|
14
|
+
// WHICH BUTTONS, IN WHICH ORDER — `update_window_buttons` (gtkwindowcontrols.c:247-426):
|
|
15
|
+
// · the layout is split on the FIRST ':' into a start half and an end half, and a layout
|
|
16
|
+
// with no ':' is the SAME half on both sides (:141-166). `side` picks which half and
|
|
17
|
+
// defaults to `start` (`GTK_PACK_START`, :68); setting it swaps the `start`/`end` style
|
|
18
|
+
// classes exactly as `gtk_window_controls_set_side` does (:496-522).
|
|
19
|
+
// · the half is split on ',' and each token builds one child, or none:
|
|
20
|
+
// `icon` — a `GtkImage`, SOVEREIGN WINDOWS ONLY: a modal window or one with a
|
|
21
|
+
// `transient-for` has no window icon of its own, and the image is
|
|
22
|
+
// dropped altogether when there is no icon to show (:299-317)
|
|
23
|
+
// `minimize` — `window-minimize-symbolic`, sovereign only (:318-341)
|
|
24
|
+
// `maximize` — `window-maximize-symbolic`, or `window-restore-symbolic` while the
|
|
25
|
+
// window is `maximized`, and only while the window is `resizable`
|
|
26
|
+
// (:342-367)
|
|
27
|
+
// `close` — `window-close-symbolic`, and only while the window is `deletable`
|
|
28
|
+
// (:368-393)
|
|
29
|
+
// A token that names none of them builds nothing, which is what the tail of the loop
|
|
30
|
+
// does with it (:416-419).
|
|
31
|
+
// · `empty` is TRUE when no token produced a button. It is a real GObject property with a
|
|
32
|
+
// notify of its own (`set_empty`, :216-230), so it is read, styled and notified here.
|
|
33
|
+
//
|
|
34
|
+
// WHERE THE LAYOUT COMES FROM, AND WHY THAT IS THE ONE DIVERGENCE. `get_layout` takes this
|
|
35
|
+
// widget's own `decoration-layout`, and failing that the DISPLAY-WIDE
|
|
36
|
+
// `Gtk.Settings:gtk-decoration-layout` (:129-140). A browser page has no settings object,
|
|
37
|
+
// so the port's second stop is the FRAME's own `decoration-layout` — the nearest thing a
|
|
38
|
+
// page has to a display-wide default, and the one value a page author can actually reach.
|
|
39
|
+
// With neither, the default is GNOME's `:minimize,maximize,close`, which is the layout
|
|
40
|
+
// libadwaita's own rules are drawn against (`_header-bar.scss:175-207` styles the three
|
|
41
|
+
// buttons and nothing else).
|
|
42
|
+
//
|
|
43
|
+
// WHAT RE-RENDERS IT. `window_notify_cb` (:428-441) re-runs `update_window_buttons` for six
|
|
44
|
+
// window properties — `deletable`, `icon-name`, `maximized`, `modal`, `resizable`,
|
|
45
|
+
// `transient-for` — and `gtk_window_controls_root` (:443-467) adds `notify::gtk-decoration-layout`
|
|
46
|
+
// from the settings. All seven are observed here, the last one through the frame.
|
|
47
|
+
//
|
|
48
|
+
// KEYS: GTK sets `can_focus = FALSE` on all three buttons (:333, :364, :394) because the
|
|
49
|
+
// window manager owns those actions. NOT PORTED, AND DELIBERATELY: a page has no window
|
|
50
|
+
// manager, and taking the only close/minimize affordance out of the tab order would leave a
|
|
51
|
+
// keyboard user unable to reach them at all. The buttons stay ordinary buttons.
|
|
52
|
+
//
|
|
53
|
+
// A11Y: `role="group"`, GtkWindowControls's own accessible role (:95). Each button carries
|
|
54
|
+
// the LABEL GTK gives it (`Minimize` / `Maximize` / `Close`, :337, :362, :390) and the icon
|
|
55
|
+
// node is `aria-hidden`, as GTK marks those images `presentation`.
|
|
56
|
+
//
|
|
57
|
+
// Events: `notify::<prop>` (CustomEvent, bubbles, detail `{ <prop>: value }`) on every real
|
|
58
|
+
// change, and `window-action` (CustomEvent, bubbles, detail `{ action }`) when a button is
|
|
59
|
+
// pressed — the `GtkActionable` action name of the button that was pressed
|
|
60
|
+
// (`window.minimize`, `window.toggle-maximized`, `window.close`). `<gtk-window>` listens for
|
|
61
|
+
// it and performs the default.
|
|
62
|
+
//
|
|
63
|
+
// Reference: refs/gtk/gtk/gtkwindowcontrols.c
|
|
64
|
+
// Reference: refs/libadwaita/src/stylesheet/widgets/_header-bar.scss (GtkWindowControls)
|
|
65
|
+
// Copyright (c) The GTK Team. LGPLv2.1+.
|
|
66
|
+
// Modifications: Implemented as a Web Component for @gjsify/adwaita-web.
|
|
67
|
+
|
|
68
|
+
import { createGtkImage } from './gtk-image.js';
|
|
69
|
+
|
|
70
|
+
/** `Gtk.PackType`, spelled as the GIR's enum nicks (gtkwindowcontrols.c:68). */
|
|
71
|
+
type PackSide = 'start' | 'end';
|
|
72
|
+
|
|
73
|
+
/** What a press asks for: the `GtkActionable` action name minus its `window.` prefix. */
|
|
74
|
+
export type WindowAction = 'minimize' | 'toggle-maximized' | 'close';
|
|
75
|
+
|
|
76
|
+
/** The button one token builds: its style class, its icon, its accessible name. */
|
|
77
|
+
interface ControlSpec {
|
|
78
|
+
readonly className: string;
|
|
79
|
+
readonly icon: string;
|
|
80
|
+
readonly label: string;
|
|
81
|
+
readonly action: WindowAction;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/** The three button glyphs, named as C names them (:333, :364, :377, :382). */
|
|
85
|
+
const TOKEN_BUTTONS: Record<'minimize' | 'maximize' | 'close', ControlSpec> = {
|
|
86
|
+
minimize: { className: 'minimize', icon: 'window-minimize-symbolic', label: 'Minimize', action: 'minimize' },
|
|
87
|
+
maximize: {
|
|
88
|
+
className: 'maximize',
|
|
89
|
+
icon: 'window-maximize-symbolic',
|
|
90
|
+
label: 'Maximize',
|
|
91
|
+
action: 'toggle-maximized',
|
|
92
|
+
},
|
|
93
|
+
close: { className: 'close', icon: 'window-close-symbolic', label: 'Close', action: 'close' },
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
/** What `maximize` draws while the window is maximized instead (gtkwindowcontrols.c:347-350). */
|
|
97
|
+
const RESTORE_ICON_NAME = 'window-restore-symbolic';
|
|
98
|
+
const RESTORE_LABEL = 'Restore';
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* GNOME's `Gtk.Settings:gtk-decoration-layout`, and the layout libadwaita's rules are drawn
|
|
102
|
+
* against. The port's stand-in for the settings object — see the header.
|
|
103
|
+
*/
|
|
104
|
+
const DEFAULT_DECORATION_LAYOUT = ':minimize,maximize,close';
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* The window properties `window_notify_cb` re-renders on (:430-436), plus `decoration-layout`
|
|
108
|
+
* standing in for the settings notify of :445-447.
|
|
109
|
+
*/
|
|
110
|
+
const WINDOW_ATTRIBUTES = [
|
|
111
|
+
'decoration-layout',
|
|
112
|
+
'deletable',
|
|
113
|
+
'icon-name',
|
|
114
|
+
'maximized',
|
|
115
|
+
'modal',
|
|
116
|
+
'resizable',
|
|
117
|
+
'transient-for',
|
|
118
|
+
];
|
|
119
|
+
|
|
120
|
+
/** `closest` over both window spellings — `Adw.Window` is a `GtkWindow` subclass. */
|
|
121
|
+
const WINDOW_SELECTOR = 'gtk-window, adw-window';
|
|
122
|
+
|
|
123
|
+
export class GtkWindowControls extends HTMLElement {
|
|
124
|
+
private _initialized = false;
|
|
125
|
+
private _empty = true;
|
|
126
|
+
/** The frame this controls answers to, or `null` outside one (`:257-263`). */
|
|
127
|
+
private _window: Element | null = null;
|
|
128
|
+
private _windowObserver: MutationObserver | null = null;
|
|
129
|
+
|
|
130
|
+
static get observedAttributes() {
|
|
131
|
+
return ['decoration-layout', 'side', 'use-native-controls'];
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/** `Gtk.WindowControls:side` — which half of the decoration layout to build. */
|
|
135
|
+
get side(): PackSide {
|
|
136
|
+
return this.getAttribute('side') === 'end' ? 'end' : 'start';
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
set side(value: PackSide) {
|
|
140
|
+
this._write('side', value);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/** `Gtk.WindowControls:use-native-controls` — a macOS-only branch; see KNOWN_GAPS. */
|
|
144
|
+
get useNativeControls(): boolean {
|
|
145
|
+
return this.hasAttribute('use-native-controls');
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* `Gtk.WindowControls:empty` (read-only in GIR). TRUE — the GIR default (:618) — until a
|
|
150
|
+
* render finds a button, which is what happens outside a window.
|
|
151
|
+
*/
|
|
152
|
+
get empty(): boolean {
|
|
153
|
+
return this._empty;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/** `setAttribute` for a write that changes nothing; every GObject setter here returns early. */
|
|
157
|
+
private _write(name: string, value: string): void {
|
|
158
|
+
if (this.getAttribute(name) !== value) this.setAttribute(name, value);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
connectedCallback() {
|
|
162
|
+
if (this._initialized) {
|
|
163
|
+
this._followWindow();
|
|
164
|
+
return;
|
|
165
|
+
}
|
|
166
|
+
this._initialized = true;
|
|
167
|
+
|
|
168
|
+
this.setAttribute('role', 'group');
|
|
169
|
+
this._followWindow();
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
disconnectedCallback() {
|
|
173
|
+
this._windowObserver?.disconnect();
|
|
174
|
+
this._windowObserver = null;
|
|
175
|
+
this._window = null;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
attributeChangedCallback(name: string) {
|
|
179
|
+
if (!this._initialized) return;
|
|
180
|
+
this._render();
|
|
181
|
+
this.dispatchEvent(
|
|
182
|
+
new CustomEvent(`notify::${name}`, { bubbles: true, detail: { [name]: this._property(name) } }),
|
|
183
|
+
);
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
private _property(name: string): boolean | string {
|
|
187
|
+
return name === 'side' ? this.side : this.hasAttribute(name);
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
/**
|
|
191
|
+
* Bind to the frame above, the way `gtk_window_controls_root` binds to the settings and
|
|
192
|
+
* to `notify` on the window (:443-462) — then run the build, which is that handler's
|
|
193
|
+
* first act. Re-established on every connect: a bar moved into another window has a new
|
|
194
|
+
* ancestor, which is why C does it in `root` and drops it in `unroot`.
|
|
195
|
+
*/
|
|
196
|
+
private _followWindow() {
|
|
197
|
+
this._windowObserver?.disconnect();
|
|
198
|
+
this._applyEmptyClass();
|
|
199
|
+
this._window = this.closest(WINDOW_SELECTOR);
|
|
200
|
+
if (this._window !== null) {
|
|
201
|
+
this._windowObserver ??= new MutationObserver(() => this._render());
|
|
202
|
+
this._windowObserver.observe(this._window, { attributes: true, attributeFilter: WINDOW_ATTRIBUTES });
|
|
203
|
+
}
|
|
204
|
+
this._render();
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
/** `is_sovereign_window` (gtkwindowcontrols.c:272-273): neither modal nor transient. */
|
|
208
|
+
private _isSovereign(window: Element): boolean {
|
|
209
|
+
return !window.hasAttribute('modal') && !window.hasAttribute('transient-for');
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* The window property, in ITS polarity. `resizable` and `deletable` default TRUE
|
|
214
|
+
* (gtkwindow.c:893, :1024) and `maximized` defaults FALSE (:1044), so one helper reading
|
|
215
|
+
* them alike would put a maximize button on a window that cannot be maximized — and a
|
|
216
|
+
* restore glyph on every window there is.
|
|
217
|
+
*/
|
|
218
|
+
private _windowFlag(element: Element, name: 'resizable' | 'deletable'): boolean {
|
|
219
|
+
return element.getAttribute(name) !== 'false';
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
/**
|
|
223
|
+
* `get_layout` (gtkwindowcontrols.c:120-176), reduced to what a page can answer: this
|
|
224
|
+
* widget's own value, then the frame's, then GNOME's default. The first ':' splits the
|
|
225
|
+
* layout in two, and a layout with no ':' is the same half on both sides.
|
|
226
|
+
*/
|
|
227
|
+
private _layoutHalf(): string | null {
|
|
228
|
+
const layout =
|
|
229
|
+
this.getAttribute('decoration-layout') ??
|
|
230
|
+
this._window?.getAttribute('decoration-layout') ??
|
|
231
|
+
DEFAULT_DECORATION_LAYOUT;
|
|
232
|
+
if (layout === '') return null;
|
|
233
|
+
const colon = layout.indexOf(':');
|
|
234
|
+
if (colon === -1) return layout;
|
|
235
|
+
return this.side === 'start' ? layout.slice(0, colon) : layout.slice(colon + 1);
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
/** `update_window_buttons` (gtkwindowcontrols.c:247-426), token for token. */
|
|
239
|
+
private _render(): void {
|
|
240
|
+
// `gtk_window_controls_set_side` moves the style class as part of the same rebuild
|
|
241
|
+
// (:496-522), so both halves of that setter live here.
|
|
242
|
+
this.classList.toggle('start', this.side === 'start');
|
|
243
|
+
this.classList.toggle('end', this.side === 'end');
|
|
244
|
+
// `clear_controls` runs before anything is built (:271), so a window that stopped
|
|
245
|
+
// being resizable loses its maximize button rather than keeping a stale one.
|
|
246
|
+
this.replaceChildren();
|
|
247
|
+
this._applyEmptyClass();
|
|
248
|
+
|
|
249
|
+
const window = this._window;
|
|
250
|
+
if (window === null) {
|
|
251
|
+
this._setEmpty(true);
|
|
252
|
+
return;
|
|
253
|
+
}
|
|
254
|
+
const sovereign = this._isSovereign(window);
|
|
255
|
+
const half = this._layoutHalf();
|
|
256
|
+
if (half === null) {
|
|
257
|
+
this._setEmpty(true);
|
|
258
|
+
return;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
let empty = true;
|
|
262
|
+
for (const token of half.split(',')) {
|
|
263
|
+
const button = this._buttonFor(token, window, sovereign);
|
|
264
|
+
if (button === null) continue;
|
|
265
|
+
this.appendChild(button);
|
|
266
|
+
empty = false;
|
|
267
|
+
}
|
|
268
|
+
this._setEmpty(empty);
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
/** Every render writes the class, whether the VALUE moved or not — see {@link _setEmpty}. */
|
|
272
|
+
private _applyEmptyClass(): void {
|
|
273
|
+
this.classList.toggle('empty', this._empty);
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
/** The one child a token builds, or `null` for the tokens that build nothing here. */
|
|
277
|
+
private _buttonFor(token: string, window: Element, sovereign: boolean): HTMLElement | null {
|
|
278
|
+
if (token === 'icon') return sovereign ? this._windowIcon(window) : null;
|
|
279
|
+
if (token === 'minimize') return sovereign ? this._controlButton(TOKEN_BUTTONS.minimize) : null;
|
|
280
|
+
if (token === 'maximize') {
|
|
281
|
+
if (!sovereign || !this._windowFlag(window, 'resizable')) return null;
|
|
282
|
+
// :347-350 — the glyph and the label follow the window's state, not the token.
|
|
283
|
+
const maximized = window.hasAttribute('maximized');
|
|
284
|
+
return this._controlButton(
|
|
285
|
+
maximized
|
|
286
|
+
? { ...TOKEN_BUTTONS.maximize, icon: RESTORE_ICON_NAME, label: RESTORE_LABEL }
|
|
287
|
+
: TOKEN_BUTTONS.maximize,
|
|
288
|
+
);
|
|
289
|
+
}
|
|
290
|
+
if (token === 'close') {
|
|
291
|
+
return this._windowFlag(window, 'deletable') ? this._controlButton(TOKEN_BUTTONS.close) : null;
|
|
292
|
+
}
|
|
293
|
+
return null;
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
/**
|
|
297
|
+
* `update_window_icon` (gtkwindowcontrols.c:187-210): the icon node is `presentation` to
|
|
298
|
+
* an accessibility tree, and it is dropped when the window has no icon — which for a
|
|
299
|
+
* frame means no `icon-name`, the analogue of a window with no `GdkPaintable`.
|
|
300
|
+
*/
|
|
301
|
+
private _windowIcon(window: Element): HTMLElement | null {
|
|
302
|
+
const name = window.getAttribute('icon-name');
|
|
303
|
+
return name === null || name === '' ? null : createGtkImage(name, 'icon');
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
/**
|
|
307
|
+
* One `GtkButton` with its `GtkImage` child. A plain `<button>` rather than
|
|
308
|
+
* `<gtk-button>`: libadwaita's own rules select `windowcontrols > button > image`
|
|
309
|
+
* (refs/libadwaita/src/stylesheet/widgets/_header-bar.scss:178-202), so the button IS
|
|
310
|
+
* the widget node here, and `<gtk-button>` would wrap a second one inside it.
|
|
311
|
+
*/
|
|
312
|
+
private _controlButton(spec: ControlSpec): HTMLElement {
|
|
313
|
+
const button = document.createElement('button');
|
|
314
|
+
button.className = `adw-window-controls-button ${spec.className}`;
|
|
315
|
+
button.setAttribute('aria-label', spec.label);
|
|
316
|
+
button.title = spec.label;
|
|
317
|
+
button.appendChild(createGtkImage(spec.icon));
|
|
318
|
+
button.addEventListener('click', () =>
|
|
319
|
+
this.dispatchEvent(new CustomEvent('window-action', { bubbles: true, detail: { action: spec.action } })),
|
|
320
|
+
);
|
|
321
|
+
return button;
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
/**
|
|
325
|
+
* `set_empty` (gtkwindowcontrols.c:216-230): a style class, and a notify of its own.
|
|
326
|
+
*
|
|
327
|
+
* The early return is about the NOTIFY, and it is the whole of C's `if (empty ==
|
|
328
|
+
* self->empty) return;`. The CLASS is not part of that comparison here: `empty` starts
|
|
329
|
+
* TRUE, so the first render outside a window is a no-op against C and the widget was
|
|
330
|
+
* left wearing nothing at all — a property whose style class only appears once it has
|
|
331
|
+
* been wrong and then right again.
|
|
332
|
+
*/
|
|
333
|
+
private _setEmpty(empty: boolean): void {
|
|
334
|
+
if (empty === this._empty) return;
|
|
335
|
+
this._empty = empty;
|
|
336
|
+
this._applyEmptyClass();
|
|
337
|
+
this.dispatchEvent(new CustomEvent('notify::empty', { bubbles: true, detail: { empty } }));
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
customElements.define('gtk-window-controls', GtkWindowControls);
|