@gjsify/adwaita-web 0.54.0 → 0.56.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/README.md +8 -0
- package/dist/adwaita-web.css +8146 -3011
- 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-status-page.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/attributes.d.ts +19 -0
- package/lib/types/breakpoints.d.ts +14 -3
- package/lib/types/construct-vectors.spec.d.ts +1 -0
- package/lib/types/elements/adw-action-row.d.ts +4 -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-combo-row.d.ts +4 -0
- package/lib/types/elements/adw-dialog.d.ts +10 -0
- package/lib/types/elements/adw-entry-row.d.ts +6 -0
- package/lib/types/elements/adw-expander-row.d.ts +2 -0
- package/lib/types/elements/adw-header-bar.d.ts +6 -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-overlay-split-view.d.ts +13 -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 +8 -2
- package/lib/types/elements/adw-spin-row.d.ts +6 -0
- package/lib/types/elements/adw-switch-row.d.ts +7 -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-toggle-group.d.ts +17 -0
- 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 +129 -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 +103 -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/row-line-clamp.d.ts +20 -0
- package/lib/types/row-tooltip.d.ts +8 -0
- package/lib/types/row-tooltip.spec.d.ts +1 -0
- package/lib/types/scroll-shading.d.ts +15 -1
- package/lib/types/shared-tree-builder.d.ts +75 -17
- package/lib/types/shared-tree-mount.spec.d.ts +1 -0
- 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/lib/types/widget-size.spec.d.ts +1 -0
- package/package.json +12 -8
- package/scss/_action_row.scss +41 -17
- 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/_button_row.scss +5 -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/_expander_row.scss +36 -3
- 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 +134 -1
- 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 +60 -0
- package/scss/_print_dialogs.scss +328 -0
- package/scss/_reset.scss +21 -19
- package/scss/_revealer.scss +37 -0
- package/scss/_row.scss +36 -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/_status_page.scss +1 -1
- 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/_toggle_group.scss +28 -0
- 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/_widget.scss +14 -3
- package/scss/_window.scss +131 -2
- package/scss/_window_handle.scss +20 -0
- package/scss/adwaita-skin.scss +109 -0
- package/src/adw-action-rows.spec.ts +331 -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-header-bar.spec.ts +18 -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-status-page.spec.ts +124 -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/attributes.ts +52 -0
- package/src/breakpoints.ts +25 -8
- package/src/capabilities.d.mts +3 -0
- package/src/capabilities.mjs +21 -0
- package/src/connect-lifecycle.spec.ts +12 -0
- package/src/construct-vectors.spec.ts +175 -0
- package/src/elements/adw-action-row.ts +31 -2
- package/src/elements/adw-alert-dialog.ts +4 -1
- 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-button-row.ts +7 -1
- package/src/elements/adw-clamp-scrollable.ts +207 -0
- package/src/elements/adw-combo-row.ts +26 -1
- package/src/elements/adw-dialog.ts +19 -0
- package/src/elements/adw-entry-row.ts +22 -12
- package/src/elements/adw-expander-row.ts +34 -1
- package/src/elements/adw-header-bar.ts +18 -4
- package/src/elements/adw-layout-slot.ts +95 -0
- package/src/elements/adw-multi-layout-view.ts +326 -0
- package/src/elements/adw-overlay-split-view.ts +29 -6
- package/src/elements/adw-preferences-row.ts +153 -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 +74 -7
- package/src/elements/adw-spin-row.ts +37 -2
- package/src/elements/adw-status-page.ts +10 -2
- package/src/elements/adw-switch-row.ts +53 -2
- 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 +138 -14
- 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 +190 -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 +653 -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 +372 -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 +202 -0
- package/src/index.ts +9 -1
- package/src/keyboard-operable.spec.ts +77 -9
- 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/row-line-clamp.ts +74 -0
- package/src/row-tooltip.spec.ts +313 -0
- package/src/row-tooltip.ts +52 -0
- package/src/scroll-shading.ts +18 -1
- package/src/shared-tree-builder.ts +336 -41
- package/src/shared-tree-mount.spec.ts +130 -0
- package/src/shared-trees.spec.ts +15 -0
- 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 +160 -0
- package/src/widget-size.spec.ts +117 -0
|
@@ -34,10 +34,23 @@
|
|
|
34
34
|
// package's `exports` map ships only `.`, and a new subpath would buy nothing for a module
|
|
35
35
|
// this small, most of which (the `SharedTreeNode` type) is erased at build anyway.
|
|
36
36
|
|
|
37
|
-
import type
|
|
38
|
-
import {
|
|
37
|
+
import { createBreakpointDriver, parseBreakpointCondition, type BreakpointSize } from '@gjsify/adwaita-core';
|
|
38
|
+
import { assertTreeConstructs, type SharedTreeNode } from '@gjsify/adwaita-core/conformance';
|
|
39
|
+
import {
|
|
40
|
+
GTK_WIDGET_EXPAND,
|
|
41
|
+
attributeOf,
|
|
42
|
+
hostTagOf,
|
|
43
|
+
isValueBasedBooleanAttr,
|
|
44
|
+
propertyOf,
|
|
45
|
+
widgetLengthStyle,
|
|
46
|
+
} from '@gjsify/adwaita-core/tags';
|
|
39
47
|
|
|
48
|
+
import { observeAdaptiveSize } from './breakpoints.js';
|
|
49
|
+
import { capabilities } from './capabilities.mjs';
|
|
50
|
+
import { dispatchedSignalsOf } from './signals.js';
|
|
40
51
|
import { slottedChildrenOf } from './slotted-children.js';
|
|
52
|
+
import { templateTagFor } from './template-classes.js';
|
|
53
|
+
import { writeBooleanAttribute } from './attributes.js';
|
|
41
54
|
|
|
42
55
|
/** One authored placement, kept so {@link mountSharedTree} can hold the renderer to it. */
|
|
43
56
|
interface PlacedChild {
|
|
@@ -56,6 +69,29 @@ interface ExtendedNode {
|
|
|
56
69
|
interface BuildRecord {
|
|
57
70
|
placed: PlacedChild[];
|
|
58
71
|
extended: ExtendedNode[];
|
|
72
|
+
/** Every authored id and the element it built, which a `bind` source is looked up in. */
|
|
73
|
+
ids: Map<string, HTMLElement>;
|
|
74
|
+
/** The `bindings` of every node, resolved once every id exists (a source may be built after its target). */
|
|
75
|
+
binds: PendingBind[];
|
|
76
|
+
/** The nodes that carry `breakpoints`, wired once every id exists (a setter may name a later sibling). */
|
|
77
|
+
breakpointHosts: { el: HTMLElement; node: SharedTreeNode }[];
|
|
78
|
+
/** Undoes what the build wired to the outside (the size observers); {@link mountSharedTree}'s `unmount` runs it. */
|
|
79
|
+
disposers: (() => void)[];
|
|
80
|
+
/** The size source a `breakpoints` node is driven from; a `ResizeObserver` unless the caller supplies one. */
|
|
81
|
+
observeSize?: SizeSource;
|
|
82
|
+
/** The object a signal handler's NAME is resolved against (ADR 0093 § 3), as `Gtk.BuilderScope` does. */
|
|
83
|
+
scope?: Readonly<Record<string, unknown>>;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/** Calls `onSize` with the host's measured size, now and on every change; returns its disposer. */
|
|
87
|
+
export type SizeSource = (element: Element, onSize: (size: BreakpointSize) => void) => () => void;
|
|
88
|
+
|
|
89
|
+
interface PendingBind {
|
|
90
|
+
el: HTMLElement;
|
|
91
|
+
property: string;
|
|
92
|
+
source: string;
|
|
93
|
+
sourceProperty: string;
|
|
94
|
+
flags: readonly string[];
|
|
59
95
|
}
|
|
60
96
|
|
|
61
97
|
/**
|
|
@@ -76,21 +112,22 @@ function isWritable(el: object, member: string): boolean {
|
|
|
76
112
|
* A `SharedTreeNode`, realised as a DETACHED element tree: a tag, its authored properties as
|
|
77
113
|
* attributes, its style classes as classes, its extensions (ADR 0072) as the markup the element
|
|
78
114
|
* reads, its placement as `slot=`, its children, in that order — recursive and total,
|
|
79
|
-
* no tag list, no per-block case.
|
|
80
|
-
*
|
|
81
|
-
* (
|
|
82
|
-
*
|
|
115
|
+
* no tag list, no per-block case.
|
|
116
|
+
*
|
|
117
|
+
* BOOLEAN ATTRIBUTES are written per (widget, property), not per attribute name. The same
|
|
118
|
+
* attribute name (e.g. `revealed`) can be VALUE-BASED for one widget (`gtk-action-bar`,
|
|
119
|
+
* default TRUE) and PRESENCE-BASED for another (`adw-banner`, default FALSE). The
|
|
120
|
+
* per-widget map in `@gjsify/adwaita-core/tags` ({@link isValueBasedBooleanAttr}) records this.
|
|
83
121
|
*
|
|
84
|
-
*
|
|
85
|
-
*
|
|
86
|
-
*
|
|
87
|
-
*
|
|
88
|
-
*
|
|
89
|
-
*
|
|
90
|
-
*
|
|
91
|
-
*
|
|
92
|
-
*
|
|
93
|
-
* out of the assignment, so such a property falls back to the presence rule too.
|
|
122
|
+
* - VALUE-BASED: `attr="false"` means false, absent means true (the GTK default).
|
|
123
|
+
* The builder writes `attr="true"|"false"` directly via {@link writeBooleanAttribute}.
|
|
124
|
+
* - PRESENCE-BASED (style classes like `flat`, `round`, `compact`): `toggleAttribute`
|
|
125
|
+
* writes the bare attribute for `true`, removes it for `false`.
|
|
126
|
+
*
|
|
127
|
+
* EXCEPT an authored `false` on a NON-value-based, WRITABLE property: the property is set
|
|
128
|
+
* directly (bypassing the attribute) because the element's setter will reflect it correctly.
|
|
129
|
+
* A getter-only property of the same name (e.g. `AdwSplitButton.active`) falls back to the
|
|
130
|
+
* presence rule since assignment would throw.
|
|
94
131
|
*
|
|
95
132
|
* THE SLOT IS WRITTEN AS THE ATTRIBUTE THIS RENDERER ALREADY ROUTES ON, not translated:
|
|
96
133
|
* `src/slotted-children.ts` reads `slot=` off every light-DOM child and keeps the routing
|
|
@@ -103,29 +140,206 @@ function isWritable(el: object, member: string): boolean {
|
|
|
103
140
|
* container. A DETACHED build therefore cannot check a slot either: an element that has not
|
|
104
141
|
* upgraded has declared no slots yet, so the refusal below belongs to the mount.
|
|
105
142
|
*/
|
|
106
|
-
export function buildSharedTree(node: SharedTreeNode, record: BuildRecord =
|
|
107
|
-
|
|
143
|
+
export function buildSharedTree(node: SharedTreeNode, record: BuildRecord = newRecord()): HTMLElement {
|
|
144
|
+
// ADR 0093 § 2: the whole tree is checked against the capability table before an element is
|
|
145
|
+
// created. A refused `layout` is named with its node and the reason the table gives.
|
|
146
|
+
assertTreeConstructs('adwaita-web', capabilities, node);
|
|
147
|
+
const root = buildNode(node, record);
|
|
148
|
+
for (const bind of record.binds) bindProperty(bind, record);
|
|
149
|
+
for (const host of record.breakpointHosts) bindBreakpoints(host.el, host.node, record);
|
|
150
|
+
return root;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/** A fresh record, with the scope when the caller has one. */
|
|
154
|
+
function newRecord(scope?: Readonly<Record<string, unknown>>, observeSize?: SizeSource): BuildRecord {
|
|
155
|
+
return {
|
|
156
|
+
placed: [],
|
|
157
|
+
extended: [],
|
|
158
|
+
ids: new Map(),
|
|
159
|
+
binds: [],
|
|
160
|
+
breakpointHosts: [],
|
|
161
|
+
disposers: [],
|
|
162
|
+
...(scope === undefined ? {} : { scope }),
|
|
163
|
+
...(observeSize === undefined ? {} : { observeSize }),
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/** What a setter's target held before any breakpoint wrote it: the member's value or the attribute's. */
|
|
168
|
+
type Original = { member: unknown } | { attribute: string | null };
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* ADR 0093's `breakpoints`: each setter's `object` resolves to the element built for that id and
|
|
172
|
+
* the write is the one an authored prop takes. The parent's own box is the size source (a
|
|
173
|
+
* `ResizeObserver`; an Adwaita condition is written against the window, which a page rarely is),
|
|
174
|
+
* and `adwaita-core` picks the breakpoint and the restores.
|
|
175
|
+
*
|
|
176
|
+
* Refused by name, never dropped: a setter whose object is not an id of this tree (`template`
|
|
177
|
+
* included) and a condition the grammar cannot read, which libadwaita would drop silently.
|
|
178
|
+
*/
|
|
179
|
+
function bindBreakpoints(el: HTMLElement, node: SharedTreeNode, record: BuildRecord): void {
|
|
180
|
+
const definitions = (node.breakpoints ?? []).map((breakpoint) => {
|
|
181
|
+
if (parseBreakpointCondition(breakpoint.condition) === null) {
|
|
182
|
+
throw new Error(
|
|
183
|
+
`<${el.localName}> \`condition ("${breakpoint.condition}")\` is not an Adwaita breakpoint condition.`,
|
|
184
|
+
);
|
|
185
|
+
}
|
|
186
|
+
return {
|
|
187
|
+
condition: breakpoint.condition,
|
|
188
|
+
setters: breakpoint.setters.map((setter) => {
|
|
189
|
+
const object = record.ids.get(setter.object);
|
|
190
|
+
if (object === undefined) {
|
|
191
|
+
throw new Error(
|
|
192
|
+
`<${el.localName}> breakpoint setter \`${setter.object}.${setter.property}\` names no object: ` +
|
|
193
|
+
`nothing in this tree has the id '${setter.object}'.`,
|
|
194
|
+
);
|
|
195
|
+
}
|
|
196
|
+
return { object, property: setter.property, value: setter.value };
|
|
197
|
+
}),
|
|
198
|
+
};
|
|
199
|
+
});
|
|
200
|
+
const driver = createBreakpointDriver<HTMLElement>(definitions, {
|
|
201
|
+
read(target, property) {
|
|
202
|
+
const member = propertyOf(property);
|
|
203
|
+
const current = (target as unknown as Record<string, unknown>)[member];
|
|
204
|
+
if (typeof current === 'boolean' && isWritable(target, member))
|
|
205
|
+
return { member: current } satisfies Original;
|
|
206
|
+
return { attribute: target.getAttribute(attributeOf(property)) } satisfies Original;
|
|
207
|
+
},
|
|
208
|
+
write(target, property, value) {
|
|
209
|
+
const member = propertyOf(property);
|
|
210
|
+
if (typeof value === 'object' && value !== null && 'member' in value) {
|
|
211
|
+
(target as unknown as Record<string, unknown>)[member] = (value as { member: unknown }).member;
|
|
212
|
+
} else if (typeof value === 'object' && value !== null && 'attribute' in value) {
|
|
213
|
+
const attribute = (value as { attribute: string | null }).attribute;
|
|
214
|
+
if (attribute === null) target.removeAttribute(attributeOf(property));
|
|
215
|
+
else target.setAttribute(attributeOf(property), attribute);
|
|
216
|
+
} else if (typeof value === 'boolean' && isWritable(target, member)) {
|
|
217
|
+
(target as unknown as Record<string, unknown>)[member] = value;
|
|
218
|
+
} else writeProp(target, property, value as string | number | boolean);
|
|
219
|
+
},
|
|
220
|
+
});
|
|
221
|
+
record.disposers.push((record.observeSize ?? observeAdaptiveSize)(el, (size) => driver.evaluate(size)));
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
/**
|
|
225
|
+
* ADR 0093's `bindings`, the simple form: the target property takes the source's value now and
|
|
226
|
+
* again on every `notify::<property>` the source dispatches (`G_BINDING_SYNC_CREATE`, which is
|
|
227
|
+
* what GtkBuilder's `bind-flags` default means).
|
|
228
|
+
*
|
|
229
|
+
* Refused by name, never dropped: a source that is not an id of this tree (`template` included),
|
|
230
|
+
* a source element that does not dispatch `notify::<property>`, a target without a writable
|
|
231
|
+
* property, and any flag, which this first slice has not verified. An element dispatches
|
|
232
|
+
* `notify::…` only while connected, so a tree built but never attached follows once, at build.
|
|
233
|
+
*/
|
|
234
|
+
function bindProperty(bind: PendingBind, record: BuildRecord): void {
|
|
235
|
+
const { el, property, source, sourceProperty, flags } = bind;
|
|
236
|
+
const where = `<${el.localName}> \`${property}: bind ${source}.${sourceProperty}\``;
|
|
237
|
+
const from = record.ids.get(source);
|
|
238
|
+
if (from === undefined) {
|
|
239
|
+
throw new Error(`${where} names no object: nothing in this tree has the id '${source}'.`);
|
|
240
|
+
}
|
|
241
|
+
if (flags.length > 0) {
|
|
242
|
+
throw new Error(
|
|
243
|
+
`${where} carries ${flags.join(', ')}: adwaita-web binds the plain form only until each flag is ` +
|
|
244
|
+
'verified against GObject.',
|
|
245
|
+
);
|
|
246
|
+
}
|
|
247
|
+
const notification = `notify::${sourceProperty}`;
|
|
248
|
+
const declared = dispatchedSignalsOf(from);
|
|
249
|
+
const event = declared[notification];
|
|
250
|
+
if (event === undefined) {
|
|
251
|
+
throw new Error(
|
|
252
|
+
`${where}: <${from.localName}> dispatches no '${notification}', so the target would follow the source ` +
|
|
253
|
+
`once and never again. It dispatches: ${Object.keys(declared).join(', ') || 'none'}.`,
|
|
254
|
+
);
|
|
255
|
+
}
|
|
256
|
+
const targetMember = propertyOf(property);
|
|
257
|
+
const sourceMember = propertyOf(sourceProperty);
|
|
258
|
+
if (!isWritable(el, targetMember)) {
|
|
259
|
+
throw new Error(`${where}: <${el.localName}> has no writable property '${targetMember}'.`);
|
|
260
|
+
}
|
|
261
|
+
const follow = () => {
|
|
262
|
+
(el as unknown as Record<string, unknown>)[targetMember] = (from as unknown as Record<string, unknown>)[
|
|
263
|
+
sourceMember
|
|
264
|
+
];
|
|
265
|
+
};
|
|
266
|
+
follow();
|
|
267
|
+
from.addEventListener(event, follow);
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
/**
|
|
271
|
+
* One authored property, written as the element reads it; a breakpoint setter takes the same door.
|
|
272
|
+
*
|
|
273
|
+
* BOOLEAN ATTRIBUTES are written per (widget, property), not per attribute name. The same
|
|
274
|
+
* attribute name (e.g. `revealed`) can be VALUE-BASED for one widget (`gtk-action-bar`,
|
|
275
|
+
* default TRUE) and PRESENCE-BASED for another (`adw-banner`, default FALSE). The
|
|
276
|
+
* per-widget map in `@gjsify/adwaita-core/tags` ({@link isValueBasedBooleanAttr}) records this.
|
|
277
|
+
*
|
|
278
|
+
* - VALUE-BASED: `attr="false"` means false, absent means true (the GTK default).
|
|
279
|
+
* The builder writes `attr="true"|"false"` directly via {@link writeBooleanAttribute}.
|
|
280
|
+
* - PRESENCE-BASED (style classes like `flat`, `round`, `compact`): `toggleAttribute`
|
|
281
|
+
* writes the bare attribute for `true`, removes it for `false`.
|
|
282
|
+
*
|
|
283
|
+
* EXCEPT an authored `false` on a NON-value-based, WRITABLE property: the property is set
|
|
284
|
+
* directly (bypassing the attribute) because the element's setter will reflect it correctly.
|
|
285
|
+
* A getter-only property of the same name (e.g. `AdwSplitButton.active`) falls back to the
|
|
286
|
+
* presence rule since assignment would throw. `hexpand` / `vexpand` keep an authored `false`
|
|
287
|
+
* as the attribute `"false"` and a later `true` rewrites it — `GTK_WIDGET_EXPAND` says why.
|
|
288
|
+
*/
|
|
289
|
+
export function writeProp(el: HTMLElement, prop: string, value: string | number | boolean): void {
|
|
290
|
+
const attr = attributeOf(prop);
|
|
291
|
+
const member = propertyOf(prop);
|
|
292
|
+
const expand = GTK_WIDGET_EXPAND.find((name) => name === attr);
|
|
293
|
+
if (expand !== undefined && typeof value === 'boolean') el.setAttribute(expand, value ? '' : 'false');
|
|
294
|
+
else if (typeof value === 'boolean' && isValueBasedBooleanAttr(el.localName, attr)) {
|
|
295
|
+
writeBooleanAttribute(el, attr, value);
|
|
296
|
+
} else if (value === false && isWritable(el, member)) {
|
|
297
|
+
// Non-value-based, writable property: set the property directly (bypasses attribute).
|
|
298
|
+
(el as unknown as Record<string, unknown>)[member] = false;
|
|
299
|
+
} else if (typeof value === 'boolean') {
|
|
300
|
+
// Presence-based (style classes) or true for non-value-based: use toggleAttribute.
|
|
301
|
+
el.toggleAttribute(attr, value);
|
|
302
|
+
} else {
|
|
303
|
+
el.setAttribute(attr, String(value));
|
|
304
|
+
}
|
|
305
|
+
// A margin or a size request is also inline style (`GTK_WIDGET_MARGIN_CSS` says why); the
|
|
306
|
+
// attribute stays, since it is what the tree authored and what a reader of the DOM looks for.
|
|
307
|
+
const length = widgetLengthStyle(attr, value);
|
|
308
|
+
if (length === undefined) return;
|
|
309
|
+
if (length[1] === null) el.style.removeProperty(length[0]);
|
|
310
|
+
else el.style.setProperty(length[0], length[1]);
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
function buildNode(node: SharedTreeNode, record: BuildRecord): HTMLElement {
|
|
314
|
+
// An `extern` node is built by the class the application registered under its name (ADR 0093).
|
|
315
|
+
const el = document.createElement(node.extern === true ? templateTagFor(node.tag) : hostTagOf(node.tag));
|
|
108
316
|
// The id is how the TypeScript beside a `.blp` reaches this element
|
|
109
317
|
// (`root.querySelector('#…')`), the counterpart of `InternalChildren` on GTK.
|
|
110
|
-
if (node.id !== undefined)
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
318
|
+
if (node.id !== undefined) {
|
|
319
|
+
el.id = node.id;
|
|
320
|
+
record.ids.set(node.id, el);
|
|
321
|
+
}
|
|
322
|
+
for (const [property, binding] of Object.entries(node.bindings ?? {})) {
|
|
323
|
+
record.binds.push({
|
|
324
|
+
el,
|
|
325
|
+
property,
|
|
326
|
+
source: binding.source,
|
|
327
|
+
sourceProperty: binding.property,
|
|
328
|
+
flags: binding.flags ?? [],
|
|
329
|
+
});
|
|
120
330
|
}
|
|
331
|
+
for (const [prop, value] of Object.entries(node.props ?? {})) writeProp(el, prop, value);
|
|
332
|
+
if (node.breakpoints !== undefined) record.breakpointHosts.push({ el, node });
|
|
121
333
|
// `styleClasses` is `GtkWidget:css-classes`, and this renderer's door for it is the
|
|
122
334
|
// `class` attribute — what `.title-1`, `.dimmed` and `.card` select on. Unread, a
|
|
123
335
|
// `.blp`'s `styles ["title-1"]` reached the tree and never the page.
|
|
124
336
|
if (node.styleClasses !== undefined && node.styleClasses.length > 0) el.classList.add(...node.styleClasses);
|
|
125
337
|
writeExtensions(el, node);
|
|
338
|
+
bindSignals(el, node, record);
|
|
126
339
|
if (node.extensions !== undefined) record.extended.push({ el, node });
|
|
127
340
|
for (const child of node.children ?? []) {
|
|
128
|
-
const childEl =
|
|
341
|
+
const childEl = buildNode(child, record);
|
|
342
|
+
if (child.page !== undefined) writePage(el, childEl, child);
|
|
129
343
|
if (child.slot !== undefined) {
|
|
130
344
|
childEl.setAttribute('slot', child.slot);
|
|
131
345
|
record.placed.push({ parent: el, child: childEl, slot: child.slot });
|
|
@@ -135,6 +349,43 @@ export function buildSharedTree(node: SharedTreeNode, record: BuildRecord = { pl
|
|
|
135
349
|
return el;
|
|
136
350
|
}
|
|
137
351
|
|
|
352
|
+
/**
|
|
353
|
+
* ADR 0093's `signals`: each handler NAME is looked up on the scope the builder was handed and
|
|
354
|
+
* listened for as the DOM event the element declares for that GTK signal.
|
|
355
|
+
*
|
|
356
|
+
* Refused by name, never dropped: a missing scope or handler (as `Gtk.Builder` refuses one), a
|
|
357
|
+
* signal the element does not declare, and the `swapped`, `after` and `object` forms, which this
|
|
358
|
+
* first slice has not verified against GTK's argument order and emission phase.
|
|
359
|
+
*/
|
|
360
|
+
function bindSignals(el: HTMLElement, node: SharedTreeNode, record: BuildRecord): void {
|
|
361
|
+
const declared = dispatchedSignalsOf(el);
|
|
362
|
+
for (const signal of node.signals ?? []) {
|
|
363
|
+
const name = signal.detail === undefined ? signal.name : `${signal.name}::${signal.detail}`;
|
|
364
|
+
const event = declared[name];
|
|
365
|
+
if (event === undefined) {
|
|
366
|
+
throw new Error(
|
|
367
|
+
`<${el.localName}> declares no signal '${name}', so the handler '${signal.handler}' would never ` +
|
|
368
|
+
`run. It dispatches: ${Object.keys(declared).join(', ') || 'none'}.`,
|
|
369
|
+
);
|
|
370
|
+
}
|
|
371
|
+
if (signal.object !== undefined || (signal.flags?.length ?? 0) > 0) {
|
|
372
|
+
throw new Error(
|
|
373
|
+
`the handler '${signal.handler}' for '${name}' uses ${signal.object === undefined ? '' : 'an object '}` +
|
|
374
|
+
`${(signal.flags ?? []).join(', ')}: adwaita-web binds plain handlers only until each of those ` +
|
|
375
|
+
'is verified against GTK.',
|
|
376
|
+
);
|
|
377
|
+
}
|
|
378
|
+
const handler = record.scope?.[signal.handler];
|
|
379
|
+
if (typeof handler !== 'function') {
|
|
380
|
+
throw new Error(
|
|
381
|
+
`the tree binds the handler '${signal.handler}' for '${name}', and the scope ` +
|
|
382
|
+
`${record.scope === undefined ? 'was not given (pass `scope`)' : 'has no such function'}.`,
|
|
383
|
+
);
|
|
384
|
+
}
|
|
385
|
+
el.addEventListener(event, (domEvent) => handler.call(record.scope, domEvent));
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
|
|
138
389
|
/**
|
|
139
390
|
* ADR 0072's `extensions`, written in the markup this package already reads for each.
|
|
140
391
|
*
|
|
@@ -217,10 +468,12 @@ function refuseUnheldExtensions(extended: readonly ExtendedNode[]): void {
|
|
|
217
468
|
* purpose. An undefined element has exactly ONE destination — itself — so a placement
|
|
218
469
|
* cannot land anywhere but where the tree authored it; what such a tree is really missing
|
|
219
470
|
* is the WIDGET, which is a wider gap than a slot and not this refusal's claim to make.
|
|
220
|
-
* (`AdwApplicationWindow
|
|
221
|
-
* no element for it.
|
|
222
|
-
*
|
|
223
|
-
*
|
|
471
|
+
* (It was `AdwApplicationWindow`, which `showcases/gtk/effect-adw-services/src/window.blp`
|
|
472
|
+
* roots at while this package had no element for it. That element now exists, so the live
|
|
473
|
+
* case is the opposite one: `<adw-window>` and `<adw-application-window>` both declare
|
|
474
|
+
* `content`, which is what that file's `content:` becomes.) A DEFINED element that routes
|
|
475
|
+
* no named slot is refused like any other: it built a structure and chose not to route
|
|
476
|
+
* into it, so a name it does not have would leave the child beside that structure.
|
|
224
477
|
*/
|
|
225
478
|
function refuseUnknownSlots(placed: readonly PlacedChild[]): void {
|
|
226
479
|
for (const { parent, child, slot } of placed) {
|
|
@@ -239,21 +492,37 @@ function refuseUnknownSlots(placed: readonly PlacedChild[]): void {
|
|
|
239
492
|
export interface MountedSharedTree {
|
|
240
493
|
/** The authored root — connected, so every custom element under it has upgraded and run. */
|
|
241
494
|
root: HTMLElement;
|
|
242
|
-
/** Disconnects and discards the mount point. */
|
|
495
|
+
/** Disconnects the tree, and discards the mount point when this call made one. */
|
|
243
496
|
unmount: () => void;
|
|
244
497
|
}
|
|
245
498
|
|
|
499
|
+
/** What {@link mountSharedTree} takes beside the tree. */
|
|
500
|
+
export interface MountOptions {
|
|
501
|
+
/** The object a handler NAME is looked up on (ADR 0093 § 3). */
|
|
502
|
+
scope?: Readonly<Record<string, unknown>>;
|
|
503
|
+
/** The size source a `breakpoints` node is driven from. */
|
|
504
|
+
observeSize?: SizeSource;
|
|
505
|
+
/**
|
|
506
|
+
* Where the root is appended — a showcase's own container, which then lays the window out.
|
|
507
|
+
* Without it the tree gets a fresh host `<div>` in `document.body`, discarded on `unmount`.
|
|
508
|
+
*/
|
|
509
|
+
into?: HTMLElement;
|
|
510
|
+
}
|
|
511
|
+
|
|
246
512
|
/**
|
|
247
513
|
* {@link buildSharedTree}, attached under a fresh host `<div>` in `document.body` so the tree
|
|
248
514
|
* — and every custom element in it — is REAL rather than merely constructed. This is the
|
|
249
515
|
* instantiation half a caller reading the corpus's elements normally wants; a bare
|
|
250
516
|
* `buildSharedTree` is for a caller that already has somewhere of its own to attach it.
|
|
251
517
|
*/
|
|
252
|
-
export function mountSharedTree(node: SharedTreeNode): MountedSharedTree {
|
|
253
|
-
const
|
|
254
|
-
const
|
|
255
|
-
|
|
256
|
-
|
|
518
|
+
export function mountSharedTree(node: SharedTreeNode, options: MountOptions = {}): MountedSharedTree {
|
|
519
|
+
const { into } = options;
|
|
520
|
+
const host = into ?? document.createElement('div');
|
|
521
|
+
const record = newRecord(options.scope, options.observeSize);
|
|
522
|
+
const root = buildSharedTree(node, record);
|
|
523
|
+
host.append(root);
|
|
524
|
+
if (into === undefined) document.body.append(host);
|
|
525
|
+
const discard = () => (into === undefined ? host : root).remove();
|
|
257
526
|
// After the append, because that is what upgrades the elements and runs the binds the
|
|
258
527
|
// refusal reads; before the return, because a caller handed a tree back has no way left
|
|
259
528
|
// to tell a placement that was honoured from one that was dropped.
|
|
@@ -261,8 +530,34 @@ export function mountSharedTree(node: SharedTreeNode): MountedSharedTree {
|
|
|
261
530
|
refuseUnknownSlots(record.placed);
|
|
262
531
|
refuseUnheldExtensions(record.extended);
|
|
263
532
|
} catch (error) {
|
|
264
|
-
|
|
533
|
+
for (const dispose of record.disposers) dispose();
|
|
534
|
+
discard();
|
|
265
535
|
throw error;
|
|
266
536
|
}
|
|
267
|
-
return {
|
|
537
|
+
return {
|
|
538
|
+
root,
|
|
539
|
+
unmount: () => {
|
|
540
|
+
for (const dispose of record.disposers) dispose();
|
|
541
|
+
discard();
|
|
542
|
+
},
|
|
543
|
+
};
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
/**
|
|
547
|
+
* A `page` as the attributes `<gtk-notebook>` (`tab-label`) and `<gtk-stack>` (`name`, `title`)
|
|
548
|
+
* read off their children. Any other parent is refused by name: the attributes would be written
|
|
549
|
+
* and read by nobody.
|
|
550
|
+
*/
|
|
551
|
+
function writePage(parent: HTMLElement, child: HTMLElement, node: SharedTreeNode): void {
|
|
552
|
+
const { page } = node;
|
|
553
|
+
if (parent.localName === 'gtk-notebook') {
|
|
554
|
+
if (page?.label !== undefined) child.setAttribute('tab-label', page.label);
|
|
555
|
+
} else if (parent.localName === 'gtk-stack') {
|
|
556
|
+
if (page?.name !== undefined) child.setAttribute('name', page.name);
|
|
557
|
+
if (page?.label !== undefined) child.setAttribute('title', page.label);
|
|
558
|
+
} else {
|
|
559
|
+
throw new Error(
|
|
560
|
+
`adwaita-web's shared-tree builder: <${node.tag}> has a page, and <${parent.localName}> has no pages.`,
|
|
561
|
+
);
|
|
562
|
+
}
|
|
268
563
|
}
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
// A showcase window mounted from its tree (ADR 0093): the shape every showcase `.blp` writes — a
|
|
2
|
+
// toggle button and a split view that bind to each other, two breakpoints that collapse the split
|
|
3
|
+
// view, and a window sized by `default-width`. What is held here is the exact cycle the showcases
|
|
4
|
+
// rely on, and `into`, the container a showcase mounts its window in.
|
|
5
|
+
import { describe, expect, it } from '@gjsify/unit';
|
|
6
|
+
import type { SharedTreeNode } from '@gjsify/adwaita-core/conformance';
|
|
7
|
+
|
|
8
|
+
import { mountSharedTree } from './shared-tree-builder.js';
|
|
9
|
+
|
|
10
|
+
/** Wait for a ResizeObserver delivery (it runs after layout, before paint). */
|
|
11
|
+
function settle(): Promise<void> {
|
|
12
|
+
return new Promise((resolve) => {
|
|
13
|
+
requestAnimationFrame(() => requestAnimationFrame(() => resolve()));
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/** The showcase window, sized by `default-width` and adapting at 800sp. */
|
|
18
|
+
const tree = (width: number): SharedTreeNode => ({
|
|
19
|
+
tag: 'AdwApplicationWindow',
|
|
20
|
+
props: { 'default-width': width, 'default-height': 400 },
|
|
21
|
+
breakpoints: [
|
|
22
|
+
{
|
|
23
|
+
condition: 'max-width: 799sp',
|
|
24
|
+
setters: [
|
|
25
|
+
{ object: 'splitView', property: 'collapsed', value: true },
|
|
26
|
+
{ object: 'splitView', property: 'show-sidebar', value: false },
|
|
27
|
+
],
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
condition: 'min-width: 800sp',
|
|
31
|
+
setters: [
|
|
32
|
+
{ object: 'splitView', property: 'collapsed', value: false },
|
|
33
|
+
{ object: 'splitView', property: 'show-sidebar', value: true },
|
|
34
|
+
],
|
|
35
|
+
},
|
|
36
|
+
],
|
|
37
|
+
children: [
|
|
38
|
+
{
|
|
39
|
+
tag: 'GtkBox',
|
|
40
|
+
slot: 'content',
|
|
41
|
+
children: [
|
|
42
|
+
{
|
|
43
|
+
tag: 'GtkToggleButton',
|
|
44
|
+
id: 'sidebarToggleButton',
|
|
45
|
+
bindings: { active: { source: 'splitView', property: 'show-sidebar' } },
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
tag: 'AdwOverlaySplitView',
|
|
49
|
+
id: 'splitView',
|
|
50
|
+
bindings: { 'show-sidebar': { source: 'sidebarToggleButton', property: 'active' } },
|
|
51
|
+
children: [
|
|
52
|
+
{ tag: 'GtkBox', slot: 'sidebar' },
|
|
53
|
+
{ tag: 'GtkBox', slot: 'content' },
|
|
54
|
+
],
|
|
55
|
+
},
|
|
56
|
+
],
|
|
57
|
+
},
|
|
58
|
+
],
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
type SplitView = HTMLElement & { showSidebar: boolean; collapsed: boolean };
|
|
62
|
+
type Toggle = HTMLElement & { active: boolean };
|
|
63
|
+
|
|
64
|
+
export const AdwSharedTreeMountTest = async () => {
|
|
65
|
+
await describe('adwaita-web: a showcase window mounted from its tree', async () => {
|
|
66
|
+
await it('<adw-overlay-split-view> raises notify::show-sidebar once per real change', () => {
|
|
67
|
+
const view = document.createElement('adw-overlay-split-view') as SplitView;
|
|
68
|
+
document.body.append(view);
|
|
69
|
+
const seen: boolean[] = [];
|
|
70
|
+
view.addEventListener('notify::show-sidebar', (event) => {
|
|
71
|
+
seen.push((event as CustomEvent<{ showSidebar: boolean }>).detail.showSidebar);
|
|
72
|
+
});
|
|
73
|
+
view.showSidebar = true;
|
|
74
|
+
view.showSidebar = false;
|
|
75
|
+
view.showSidebar = false;
|
|
76
|
+
view.showSidebar = true;
|
|
77
|
+
view.remove();
|
|
78
|
+
expect(seen).toStrictEqual([false, true]);
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
await it('a wide window keeps the sidebar and the toggle follows the split view', async () => {
|
|
82
|
+
const { root, unmount } = mountSharedTree(tree(1100));
|
|
83
|
+
await settle();
|
|
84
|
+
const split = root.querySelector('#splitView') as SplitView;
|
|
85
|
+
expect(root.getBoundingClientRect().width).toBe(1100);
|
|
86
|
+
expect(split.collapsed).toBe(false);
|
|
87
|
+
expect(split.showSidebar).toBe(true);
|
|
88
|
+
expect((root.querySelector('#sidebarToggleButton') as Toggle).active).toBe(true);
|
|
89
|
+
unmount();
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
await it('a narrow window collapses the split view and the toggle follows it', async () => {
|
|
93
|
+
const { root, unmount } = mountSharedTree(tree(500));
|
|
94
|
+
await settle();
|
|
95
|
+
const split = root.querySelector('#splitView') as SplitView;
|
|
96
|
+
expect(split.collapsed).toBe(true);
|
|
97
|
+
expect(split.showSidebar).toBe(false);
|
|
98
|
+
expect((root.querySelector('#sidebarToggleButton') as Toggle).active).toBe(false);
|
|
99
|
+
unmount();
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
await it('the toggle drives the split view back, and the cycle settles', async () => {
|
|
103
|
+
const { root, unmount } = mountSharedTree(tree(1100));
|
|
104
|
+
await settle();
|
|
105
|
+
const toggle = root.querySelector('#sidebarToggleButton') as Toggle;
|
|
106
|
+
const split = root.querySelector('#splitView') as SplitView;
|
|
107
|
+
toggle.active = false;
|
|
108
|
+
expect(split.showSidebar).toBe(false);
|
|
109
|
+
split.showSidebar = true;
|
|
110
|
+
expect(toggle.active).toBe(true);
|
|
111
|
+
toggle.active = false;
|
|
112
|
+
toggle.active = true;
|
|
113
|
+
expect(split.showSidebar).toBe(true);
|
|
114
|
+
expect(split.getAttribute('show-sidebar')).toBe('');
|
|
115
|
+
unmount();
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
await it('a tree mounted into a container lives in it, and unmount takes only the tree', () => {
|
|
119
|
+
const container = document.createElement('div');
|
|
120
|
+
document.body.append(container);
|
|
121
|
+
const { root, unmount } = mountSharedTree(tree(1100), { into: container });
|
|
122
|
+
expect(root.parentElement).toBe(container);
|
|
123
|
+
expect(container.querySelector('adw-application-window')).toBe(root);
|
|
124
|
+
unmount();
|
|
125
|
+
expect(container.childElementCount).toBe(0);
|
|
126
|
+
expect(container.isConnected).toBe(true);
|
|
127
|
+
container.remove();
|
|
128
|
+
});
|
|
129
|
+
});
|
|
130
|
+
};
|
package/src/shared-trees.spec.ts
CHANGED
|
@@ -295,6 +295,21 @@ export const AdwSharedTreesTest = async () => {
|
|
|
295
295
|
});
|
|
296
296
|
});
|
|
297
297
|
|
|
298
|
+
await it('Adw.Banner with revealed: false stays closed — attribute must be absent, not "false"', () => {
|
|
299
|
+
const tree = blueprintTree(`Adw.Banner {
|
|
300
|
+
title: "Test";
|
|
301
|
+
revealed: false;
|
|
302
|
+
}`);
|
|
303
|
+
mounted(tree, (root) => {
|
|
304
|
+
const banner = root as HTMLElement;
|
|
305
|
+
// The banner reads 'revealed' by PRESENCE (hasAttribute), so the attribute must be absent.
|
|
306
|
+
// Currently the builder writes revealed="false", which makes hasAttribute return true.
|
|
307
|
+
expect(banner.hasAttribute('revealed')).toBe(false);
|
|
308
|
+
expect(banner.classList.contains('revealed')).toBe(false);
|
|
309
|
+
expect(getComputedStyle(banner).display).toBe('none');
|
|
310
|
+
});
|
|
311
|
+
});
|
|
312
|
+
|
|
298
313
|
await it('an authored false on a getter-only property keeps the presence rule instead of throwing', () => {
|
|
299
314
|
// `<adw-split-button>` exposes `active` as a read-only getter; assigning through it
|
|
300
315
|
// threw a bare TypeError out of the builder before the writability check.
|
package/src/signals.ts
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
// The GTK signals an element dispatches, and the DOM event each one arrives as (ADR 0093 § 3).
|
|
2
|
+
//
|
|
3
|
+
// A GTK signal name is not a DOM event name — `clicked` is a native `click` here, `notify::active`
|
|
4
|
+
// is a `CustomEvent` of that very name — so a `.blp`'s `clicked => $onClicked()` cannot be wired by
|
|
5
|
+
// the name alone, and an element that dispatches nothing under it must not be wired silently. Each
|
|
6
|
+
// element declares its signals in a `static signals` the way it declares its `slots`, and the
|
|
7
|
+
// builder refuses a signal the element does not declare.
|
|
8
|
+
|
|
9
|
+
/** GTK signal name → the DOM event type the element dispatches it as. */
|
|
10
|
+
export type DispatchedSignals = Readonly<Record<string, string>>;
|
|
11
|
+
|
|
12
|
+
/** The signals `el`'s class declares, or none. */
|
|
13
|
+
export function dispatchedSignalsOf(el: Element): DispatchedSignals {
|
|
14
|
+
return (el.constructor as { signals?: DispatchedSignals }).signals ?? {};
|
|
15
|
+
}
|
|
@@ -45,8 +45,10 @@ const SHIPPED = { shipped: true } as const;
|
|
|
45
45
|
const deprecated = (replacement: string) =>
|
|
46
46
|
({ shipped: false, reason: `deprecated upstream — use ${replacement}` }) as const;
|
|
47
47
|
|
|
48
|
-
|
|
49
|
-
|
|
48
|
+
// There is no "no counterpart in this renderer YET" form any more: every class this ledger
|
|
49
|
+
// documents either ships a rule or is deprecated upstream, the last of the unported ones
|
|
50
|
+
// (`.inline`) becoming a rule with `<gtk-text-view>` and `<gtk-search-bar>`. An entry that
|
|
51
|
+
// does need one gets its own form back, with the reason it has no rule.
|
|
50
52
|
|
|
51
53
|
/**
|
|
52
54
|
* Every class `style-classes.md` documents, and what this package does about it.
|
|
@@ -117,12 +119,11 @@ export const DOCUMENTED_STYLE_CLASSES: Record<string, { shipped: boolean; reason
|
|
|
117
119
|
// Development window
|
|
118
120
|
devel: SHIPPED,
|
|
119
121
|
// Inline
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
),
|
|
122
|
+
// SHIPPED since `<gtk-text-view>` and `<gtk-search-bar>` arrived: upstream applies
|
|
123
|
+
// `.inline` to GtkTextView (`_views.scss:31-36`) and to GtkSearchBar
|
|
124
|
+
// (`_toolbars.scss:156-158`), and both elements carry the rule in `scss/_text.scss` and
|
|
125
|
+
// `scss/_search_bar.scss`. AdwTabBar and GtkSourceView still have no counterpart here.
|
|
126
|
+
inline: SHIPPED,
|
|
126
127
|
// Undershoot indicators
|
|
127
128
|
'undershoot-top': SHIPPED,
|
|
128
129
|
'undershoot-bottom': SHIPPED,
|