@gjsify/adwaita-web 0.53.0 → 0.55.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/adwaita-web.css +8070 -3037
- package/dist/adwaita-web.css.map +1 -1
- package/lib/types/adw-application-window.spec.d.ts +1 -0
- package/lib/types/adw-bin.spec.d.ts +1 -0
- package/lib/types/adw-breakpoint-bin.spec.d.ts +1 -0
- package/lib/types/adw-clamp-scrollable.spec.d.ts +1 -0
- package/lib/types/adw-multi-layout-view.spec.d.ts +1 -0
- package/lib/types/adw-preferences-row.spec.d.ts +1 -0
- package/lib/types/adw-shortcuts.spec.d.ts +1 -0
- package/lib/types/adw-tab-bar.spec.d.ts +1 -0
- package/lib/types/adw-tab-button.spec.d.ts +1 -0
- package/lib/types/adw-tab-overview.spec.d.ts +1 -0
- package/lib/types/adw-view-switcher-sidebar.spec.d.ts +1 -0
- package/lib/types/adw-window.spec.d.ts +1 -0
- package/lib/types/breakpoints.d.ts +14 -3
- package/lib/types/construct-vectors.spec.d.ts +1 -0
- package/lib/types/elements/adw-application-window.d.ts +27 -0
- package/lib/types/elements/adw-bin.d.ts +17 -0
- package/lib/types/elements/adw-breakpoint-bin.d.ts +67 -0
- package/lib/types/elements/adw-clamp-scrollable.d.ts +38 -0
- package/lib/types/elements/adw-dialog.d.ts +10 -0
- package/lib/types/elements/adw-layout-slot.d.ts +19 -0
- package/lib/types/elements/adw-multi-layout-view.d.ts +101 -0
- package/lib/types/elements/adw-preferences-row.d.ts +31 -0
- package/lib/types/elements/adw-shortcuts-dialog.d.ts +13 -0
- package/lib/types/elements/adw-shortcuts-item.d.ts +36 -0
- package/lib/types/elements/adw-shortcuts-section.d.ts +14 -0
- package/lib/types/elements/adw-sidebar.d.ts +5 -0
- package/lib/types/elements/adw-switch-row.d.ts +3 -0
- package/lib/types/elements/adw-tab-bar.d.ts +108 -0
- package/lib/types/elements/adw-tab-button.d.ts +32 -0
- package/lib/types/elements/adw-tab-overview.d.ts +199 -0
- package/lib/types/elements/adw-tab-view.d.ts +19 -23
- package/lib/types/elements/adw-view-switcher-sidebar.d.ts +84 -0
- package/lib/types/elements/adw-window.d.ts +40 -0
- package/lib/types/elements/gtk-about-dialog.d.ts +146 -0
- package/lib/types/elements/gtk-application-window.d.ts +34 -0
- package/lib/types/elements/gtk-aspect-frame.d.ts +27 -0
- package/lib/types/elements/gtk-button.d.ts +9 -0
- package/lib/types/elements/gtk-calendar.d.ts +159 -0
- package/lib/types/elements/gtk-center-box.d.ts +39 -0
- package/lib/types/elements/gtk-color-dialog-button.d.ts +69 -0
- package/lib/types/elements/gtk-column-view.d.ts +50 -0
- package/lib/types/elements/gtk-drag-icon.d.ts +78 -0
- package/lib/types/elements/gtk-drawing-area.d.ts +95 -0
- package/lib/types/elements/gtk-editable-label.d.ts +33 -0
- package/lib/types/elements/gtk-emoji-chooser.d.ts +84 -0
- package/lib/types/elements/gtk-entry.d.ts +20 -1
- package/lib/types/elements/gtk-expander.d.ts +49 -0
- package/lib/types/elements/gtk-fixed.d.ts +13 -0
- package/lib/types/elements/gtk-flow-box-child.d.ts +14 -0
- package/lib/types/elements/gtk-flow-box.d.ts +87 -0
- package/lib/types/elements/gtk-font-dialog-button.d.ts +83 -0
- package/lib/types/elements/gtk-frame.d.ts +24 -0
- package/lib/types/elements/gtk-gl-area.d.ts +136 -0
- package/lib/types/elements/gtk-graphics-offload.d.ts +24 -0
- package/lib/types/elements/gtk-grid-view.d.ts +39 -0
- package/lib/types/elements/gtk-grid.d.ts +27 -0
- package/lib/types/elements/gtk-header-bar.d.ts +60 -0
- package/lib/types/elements/gtk-inscription.d.ts +64 -0
- package/lib/types/elements/gtk-label.d.ts +3 -0
- package/lib/types/elements/gtk-level-bar.d.ts +59 -0
- package/lib/types/elements/gtk-link-button.d.ts +29 -0
- package/lib/types/elements/gtk-list-box-row.d.ts +54 -0
- package/lib/types/elements/gtk-list-box.d.ts +100 -0
- package/lib/types/elements/gtk-list-view.d.ts +73 -0
- package/lib/types/elements/gtk-media-controls.d.ts +142 -0
- package/lib/types/elements/gtk-notebook.d.ts +148 -0
- package/lib/types/elements/gtk-overlay.d.ts +22 -0
- package/lib/types/elements/gtk-page-setup-unix-dialog.d.ts +87 -0
- package/lib/types/elements/gtk-paned.d.ts +121 -0
- package/lib/types/elements/gtk-password-entry.d.ts +27 -0
- package/lib/types/elements/gtk-picture.d.ts +66 -0
- package/lib/types/elements/gtk-popover-bin.d.ts +82 -0
- package/lib/types/elements/gtk-popover-menu-bar.d.ts +66 -0
- package/lib/types/elements/gtk-popover-menu.d.ts +83 -0
- package/lib/types/elements/gtk-popover.d.ts +28 -3
- package/lib/types/elements/gtk-print-unix-dialog.d.ts +167 -0
- package/lib/types/elements/gtk-revealer.d.ts +55 -0
- package/lib/types/elements/gtk-scale-button.d.ts +59 -0
- package/lib/types/elements/gtk-scale.d.ts +98 -0
- package/lib/types/elements/gtk-scrollbar.d.ts +124 -0
- package/lib/types/elements/gtk-scrolled-window.d.ts +121 -0
- package/lib/types/elements/gtk-search-bar.d.ts +39 -0
- package/lib/types/elements/gtk-search-entry.d.ts +27 -0
- package/lib/types/elements/gtk-separator.d.ts +10 -0
- package/lib/types/elements/gtk-spin-button.d.ts +94 -0
- package/lib/types/elements/gtk-spinner.d.ts +14 -0
- package/lib/types/elements/gtk-stack-sidebar.d.ts +43 -0
- package/lib/types/elements/gtk-stack-switcher.d.ts +58 -0
- package/lib/types/elements/gtk-stack.d.ts +154 -0
- package/lib/types/elements/gtk-switch.d.ts +4 -1
- package/lib/types/elements/gtk-text-view.d.ts +62 -0
- package/lib/types/elements/gtk-text.d.ts +45 -0
- package/lib/types/elements/gtk-toggle-button.d.ts +45 -0
- package/lib/types/elements/gtk-tree-expander.d.ts +38 -0
- package/lib/types/elements/gtk-video.d.ts +97 -0
- package/lib/types/elements/gtk-viewport.d.ts +84 -0
- package/lib/types/elements/gtk-window-controls.d.ts +80 -0
- package/lib/types/elements/gtk-window-handle.d.ts +39 -0
- package/lib/types/elements/gtk-window.d.ts +97 -0
- package/lib/types/elements/justification.d.ts +2 -0
- package/lib/types/elements/popover-menu.d.ts +18 -0
- package/lib/types/elements/roving-focus.d.ts +29 -1
- package/lib/types/emoji-data.d.ts +38 -0
- package/lib/types/font-description.d.ts +96 -0
- package/lib/types/gtk-about-dialog.spec.d.ts +1 -0
- package/lib/types/gtk-action-bar.spec.d.ts +1 -0
- package/lib/types/gtk-application-window.spec.d.ts +1 -0
- package/lib/types/gtk-aspect-frame.spec.d.ts +1 -0
- package/lib/types/gtk-calendar.spec.d.ts +1 -0
- package/lib/types/gtk-center-box.spec.d.ts +1 -0
- package/lib/types/gtk-color-dialog-button.spec.d.ts +1 -0
- package/lib/types/gtk-column-view.spec.d.ts +1 -0
- package/lib/types/gtk-drag-icon.spec.d.ts +1 -0
- package/lib/types/gtk-drawing-area.spec.d.ts +1 -0
- package/lib/types/gtk-editable-label.spec.d.ts +1 -0
- package/lib/types/gtk-emoji-chooser.spec.d.ts +1 -0
- package/lib/types/gtk-expander.spec.d.ts +1 -0
- package/lib/types/gtk-fixed.spec.d.ts +1 -0
- package/lib/types/gtk-flow-box.spec.d.ts +1 -0
- package/lib/types/gtk-font-dialog-button.spec.d.ts +1 -0
- package/lib/types/gtk-frame.spec.d.ts +1 -0
- package/lib/types/gtk-gl-area.spec.d.ts +1 -0
- package/lib/types/gtk-graphics-offload.spec.d.ts +1 -0
- package/lib/types/gtk-grid-view.spec.d.ts +1 -0
- package/lib/types/gtk-grid.spec.d.ts +1 -0
- package/lib/types/gtk-header-bar.spec.d.ts +1 -0
- package/lib/types/gtk-inscription.spec.d.ts +1 -0
- package/lib/types/gtk-level-bar.spec.d.ts +1 -0
- package/lib/types/gtk-link-button.spec.d.ts +1 -0
- package/lib/types/gtk-list-box.spec.d.ts +1 -0
- package/lib/types/gtk-list-view.spec.d.ts +1 -0
- package/lib/types/gtk-media-controls.spec.d.ts +1 -0
- package/lib/types/gtk-notebook.spec.d.ts +1 -0
- package/lib/types/gtk-overlay.spec.d.ts +1 -0
- package/lib/types/gtk-paned.spec.d.ts +1 -0
- package/lib/types/gtk-password-entry.spec.d.ts +1 -0
- package/lib/types/gtk-picture.spec.d.ts +1 -0
- package/lib/types/gtk-popover-bin.spec.d.ts +1 -0
- package/lib/types/gtk-popover-menu-bar.spec.d.ts +1 -0
- package/lib/types/gtk-popover-menu.spec.d.ts +1 -0
- package/lib/types/gtk-popover-role.spec.d.ts +1 -0
- package/lib/types/gtk-popover.spec.d.ts +1 -0
- package/lib/types/gtk-print-dialogs.spec.d.ts +1 -0
- package/lib/types/gtk-revealer.spec.d.ts +1 -0
- package/lib/types/gtk-scale-button.spec.d.ts +1 -0
- package/lib/types/gtk-scale.spec.d.ts +1 -0
- package/lib/types/gtk-scrollbar.spec.d.ts +1 -0
- package/lib/types/gtk-scrolled-window.spec.d.ts +1 -0
- package/lib/types/gtk-search-bar.spec.d.ts +1 -0
- package/lib/types/gtk-search-entry.spec.d.ts +1 -0
- package/lib/types/gtk-separator.spec.d.ts +1 -0
- package/lib/types/gtk-spin-button.spec.d.ts +1 -0
- package/lib/types/gtk-spinner.spec.d.ts +1 -0
- package/lib/types/gtk-stack-sidebar.spec.d.ts +1 -0
- package/lib/types/gtk-stack-switcher.spec.d.ts +1 -0
- package/lib/types/gtk-stack.spec.d.ts +1 -0
- package/lib/types/gtk-text-view.spec.d.ts +1 -0
- package/lib/types/gtk-text.spec.d.ts +1 -0
- package/lib/types/gtk-toggle-button.spec.d.ts +1 -0
- package/lib/types/gtk-tree-expander.spec.d.ts +1 -0
- package/lib/types/gtk-video.spec.d.ts +1 -0
- package/lib/types/gtk-viewport.spec.d.ts +1 -0
- package/lib/types/gtk-window-controls.spec.d.ts +1 -0
- package/lib/types/gtk-window-handle.spec.d.ts +1 -0
- package/lib/types/gtk-window.spec.d.ts +1 -0
- package/lib/types/index.d.ts +4 -1
- package/lib/types/list-view-dom.d.ts +44 -0
- package/lib/types/namespace/adw.d.ts +12 -0
- package/lib/types/namespace/gtk.d.ts +61 -0
- package/lib/types/page-setup.d.ts +100 -0
- package/lib/types/scroll-shading.d.ts +15 -1
- package/lib/types/shared-tree-builder.d.ts +30 -2
- package/lib/types/signals.d.ts +4 -0
- package/lib/types/styles.generated.d.ts +1 -1
- package/lib/types/tab-chip.d.ts +73 -0
- package/lib/types/template-classes.d.ts +11 -0
- package/package.json +12 -8
- package/scss/_action_row.scss +2 -2
- package/scss/_application_window.scss +26 -0
- package/scss/_aspect_frame.scss +25 -0
- package/scss/_bin.scss +26 -0
- package/scss/_button.scss +45 -0
- package/scss/_calendar.scss +176 -0
- package/scss/_center_box.scss +25 -0
- package/scss/_checks.scss +6 -1
- package/scss/_clamp_scrollable.scss +28 -0
- package/scss/_color_button.scss +67 -0
- package/scss/_column_view.scss +126 -0
- package/scss/_drag_icon.scss +55 -0
- package/scss/_drawing.scss +85 -0
- package/scss/_emoji_chooser.scss +213 -0
- package/scss/_entry.scss +13 -5
- package/scss/_entry_row.scss +1 -1
- package/scss/_expander.scss +113 -0
- package/scss/_fixed.scss +29 -0
- package/scss/_flow_box.scss +94 -0
- package/scss/_font_button.scss +63 -0
- package/scss/_frame.scss +41 -0
- package/scss/_grid.scss +19 -0
- package/scss/_grid_view.scss +46 -0
- package/scss/_gtk_about_dialog.scss +186 -0
- package/scss/_headerbar.scss +132 -0
- package/scss/_icons.generated.scss +186 -0
- package/scss/_inscription.scss +125 -0
- package/scss/_level_bar.scss +190 -0
- package/scss/_link.scss +82 -0
- package/scss/_list_box.scss +88 -0
- package/scss/_list_view.scss +96 -0
- package/scss/_media_controls.scss +139 -0
- package/scss/_overlay.scss +68 -0
- package/scss/_paned.scss +130 -0
- package/scss/_password_entry.scss +83 -0
- package/scss/_picture.scss +80 -0
- package/scss/_popover_bin.scss +53 -0
- package/scss/_popover_menu_bar.scss +104 -0
- package/scss/_preferences_row.scss +51 -0
- package/scss/_print_dialogs.scss +328 -0
- package/scss/_reset.scss +21 -19
- package/scss/_revealer.scss +37 -0
- package/scss/_row.scss +20 -5
- package/scss/_scale.scss +298 -0
- package/scss/_scale_button.scss +167 -0
- package/scss/_scrollbar.scss +230 -0
- package/scss/_scrolled_window.scss +131 -0
- package/scss/_search_bar.scss +118 -0
- package/scss/_search_entry.scss +86 -0
- package/scss/_separator.scss +44 -0
- package/scss/_shortcuts_dialog.scss +100 -0
- package/scss/_spin_button.scss +172 -0
- package/scss/_spin_row.scss +56 -8
- package/scss/_spinner.scss +85 -4
- package/scss/_stack.scss +729 -0
- package/scss/_switch.scss +13 -5
- package/scss/_switch_row.scss +10 -0
- package/scss/_tab_bar.scss +317 -0
- package/scss/_tab_button.scss +98 -0
- package/scss/_tab_overview.scss +483 -0
- package/scss/_text.scss +182 -0
- package/scss/_theme.scss +1 -1
- package/scss/_tree_expander.scss +62 -0
- package/scss/_variables.scss +43 -21
- package/scss/_video.scss +146 -0
- package/scss/_view_switcher_sidebar.scss +112 -0
- package/scss/_viewport.scss +50 -0
- package/scss/_window.scss +118 -1
- package/scss/_window_handle.scss +20 -0
- package/scss/adwaita-skin.scss +109 -0
- package/src/adw-action-rows.spec.ts +76 -0
- package/src/adw-application-window.spec.ts +118 -0
- package/src/adw-bin.spec.ts +75 -0
- package/src/adw-breakpoint-bin.spec.ts +324 -0
- package/src/adw-clamp-scrollable.spec.ts +189 -0
- package/src/adw-multi-layout-view.spec.ts +243 -0
- package/src/adw-preferences-row.spec.ts +164 -0
- package/src/adw-row-state.spec.ts +142 -0
- package/src/adw-shortcuts.spec.ts +155 -0
- package/src/adw-tab-bar.spec.ts +287 -0
- package/src/adw-tab-button.spec.ts +101 -0
- package/src/adw-tab-overview.spec.ts +443 -0
- package/src/adw-view-switcher-sidebar.spec.ts +281 -0
- package/src/adw-window.spec.ts +129 -0
- package/src/breakpoints.ts +25 -8
- package/src/capabilities.d.mts +3 -0
- package/src/capabilities.mjs +18 -0
- package/src/connect-lifecycle.spec.ts +12 -0
- package/src/construct-vectors.spec.ts +175 -0
- package/src/elements/adw-application-window.ts +154 -0
- package/src/elements/adw-bin.ts +101 -0
- package/src/elements/adw-breakpoint-bin.ts +287 -0
- package/src/elements/adw-clamp-scrollable.ts +207 -0
- package/src/elements/adw-dialog.ts +19 -0
- package/src/elements/adw-layout-slot.ts +95 -0
- package/src/elements/adw-multi-layout-view.ts +326 -0
- package/src/elements/adw-preferences-row.ts +150 -0
- package/src/elements/adw-shortcuts-dialog.ts +52 -0
- package/src/elements/adw-shortcuts-item.ts +171 -0
- package/src/elements/adw-shortcuts-section.ts +86 -0
- package/src/elements/adw-sidebar.ts +42 -3
- package/src/elements/adw-switch-row.ts +28 -1
- package/src/elements/adw-tab-bar.ts +529 -0
- package/src/elements/adw-tab-button.ts +194 -0
- package/src/elements/adw-tab-overview.ts +1011 -0
- package/src/elements/adw-tab-view.ts +66 -145
- package/src/elements/adw-toggle-group.ts +20 -5
- package/src/elements/adw-view-stack.ts +18 -0
- package/src/elements/adw-view-switcher-sidebar.ts +332 -0
- package/src/elements/adw-window.ts +185 -11
- package/src/elements/checks.ts +35 -8
- package/src/elements/gtk-about-dialog.ts +811 -0
- package/src/elements/gtk-application-window.ts +108 -0
- package/src/elements/gtk-aspect-frame.ts +160 -0
- package/src/elements/gtk-button.ts +12 -0
- package/src/elements/gtk-calendar.ts +757 -0
- package/src/elements/gtk-center-box.ts +184 -0
- package/src/elements/gtk-color-dialog-button.ts +278 -0
- package/src/elements/gtk-column-view.ts +320 -0
- package/src/elements/gtk-drag-icon.ts +257 -0
- package/src/elements/gtk-drawing-area.ts +303 -0
- package/src/elements/gtk-editable-label.ts +204 -0
- package/src/elements/gtk-emoji-chooser.ts +542 -0
- package/src/elements/gtk-entry.ts +39 -5
- package/src/elements/gtk-expander.ts +301 -0
- package/src/elements/gtk-fixed.ts +99 -0
- package/src/elements/gtk-flow-box-child.ts +68 -0
- package/src/elements/gtk-flow-box.ts +480 -0
- package/src/elements/gtk-font-dialog-button.ts +432 -0
- package/src/elements/gtk-frame.ts +174 -0
- package/src/elements/gtk-gl-area.ts +476 -0
- package/src/elements/gtk-graphics-offload.ts +130 -0
- package/src/elements/gtk-grid-view.ts +168 -0
- package/src/elements/gtk-grid.ts +127 -0
- package/src/elements/gtk-header-bar.ts +273 -0
- package/src/elements/gtk-inscription.ts +387 -0
- package/src/elements/gtk-label.ts +19 -11
- package/src/elements/gtk-level-bar.ts +323 -0
- package/src/elements/gtk-link-button.ts +138 -0
- package/src/elements/gtk-list-box-row.ts +195 -0
- package/src/elements/gtk-list-box.ts +413 -0
- package/src/elements/gtk-list-view.ts +370 -0
- package/src/elements/gtk-media-controls.ts +509 -0
- package/src/elements/gtk-notebook.ts +664 -0
- package/src/elements/gtk-overlay.ts +149 -0
- package/src/elements/gtk-page-setup-unix-dialog.ts +420 -0
- package/src/elements/gtk-paned.ts +597 -0
- package/src/elements/gtk-password-entry.ts +170 -0
- package/src/elements/gtk-picture.ts +254 -0
- package/src/elements/gtk-popover-bin.ts +332 -0
- package/src/elements/gtk-popover-menu-bar.ts +355 -0
- package/src/elements/gtk-popover-menu.ts +339 -0
- package/src/elements/gtk-popover.ts +92 -10
- package/src/elements/gtk-print-unix-dialog.ts +989 -0
- package/src/elements/gtk-progress-bar.ts +24 -11
- package/src/elements/gtk-revealer.ts +406 -0
- package/src/elements/gtk-scale-button.ts +358 -0
- package/src/elements/gtk-scale.ts +492 -0
- package/src/elements/gtk-scrollbar.ts +528 -0
- package/src/elements/gtk-scrolled-window.ts +642 -0
- package/src/elements/gtk-search-bar.ts +200 -0
- package/src/elements/gtk-search-entry.ts +172 -0
- package/src/elements/gtk-separator.ts +52 -0
- package/src/elements/gtk-spin-button.ts +475 -0
- package/src/elements/gtk-spinner.ts +126 -0
- package/src/elements/gtk-stack-sidebar.ts +212 -0
- package/src/elements/gtk-stack-switcher.ts +279 -0
- package/src/elements/gtk-stack.ts +748 -0
- package/src/elements/gtk-switch.ts +52 -19
- package/src/elements/gtk-text-view.ts +290 -0
- package/src/elements/gtk-text.ts +219 -0
- package/src/elements/gtk-toggle-button.ts +239 -0
- package/src/elements/gtk-tree-expander.ts +243 -0
- package/src/elements/gtk-video.ts +423 -0
- package/src/elements/gtk-viewport.ts +277 -0
- package/src/elements/gtk-window-controls.ts +341 -0
- package/src/elements/gtk-window-handle.ts +221 -0
- package/src/elements/gtk-window.ts +366 -0
- package/src/elements/justification.ts +24 -0
- package/src/elements/popover-menu.ts +24 -0
- package/src/elements/roving-focus.ts +53 -21
- package/src/emoji-data.ts +577 -0
- package/src/entry-rows.spec.ts +31 -0
- package/src/font-description.ts +238 -0
- package/src/gtk-about-dialog.spec.ts +250 -0
- package/src/gtk-action-bar.spec.ts +89 -0
- package/src/gtk-application-window.spec.ts +107 -0
- package/src/gtk-aspect-frame.spec.ts +114 -0
- package/src/gtk-calendar.spec.ts +589 -0
- package/src/gtk-center-box.spec.ts +125 -0
- package/src/gtk-color-dialog-button.spec.ts +141 -0
- package/src/gtk-column-view.spec.ts +154 -0
- package/src/gtk-drag-icon.spec.ts +190 -0
- package/src/gtk-drawing-area.spec.ts +211 -0
- package/src/gtk-editable-label.spec.ts +190 -0
- package/src/gtk-emoji-chooser.spec.ts +173 -0
- package/src/gtk-entry.spec.ts +23 -0
- package/src/gtk-expander.spec.ts +170 -0
- package/src/gtk-fixed.spec.ts +97 -0
- package/src/gtk-flow-box.spec.ts +289 -0
- package/src/gtk-font-dialog-button.spec.ts +166 -0
- package/src/gtk-frame.spec.ts +119 -0
- package/src/gtk-gl-area.spec.ts +361 -0
- package/src/gtk-graphics-offload.spec.ts +119 -0
- package/src/gtk-grid-view.spec.ts +106 -0
- package/src/gtk-grid.spec.ts +122 -0
- package/src/gtk-header-bar.spec.ts +202 -0
- package/src/gtk-inscription.spec.ts +235 -0
- package/src/gtk-level-bar.spec.ts +199 -0
- package/src/gtk-link-button.spec.ts +117 -0
- package/src/gtk-list-box.spec.ts +422 -0
- package/src/gtk-list-view.spec.ts +203 -0
- package/src/gtk-media-controls.spec.ts +295 -0
- package/src/gtk-notebook.spec.ts +546 -0
- package/src/gtk-overlay.spec.ts +141 -0
- package/src/gtk-paned.spec.ts +267 -0
- package/src/gtk-password-entry.spec.ts +150 -0
- package/src/gtk-picture.spec.ts +172 -0
- package/src/gtk-popover-bin.spec.ts +229 -0
- package/src/gtk-popover-menu-bar.spec.ts +296 -0
- package/src/gtk-popover-menu.spec.ts +261 -0
- package/src/gtk-popover-role.spec.ts +138 -0
- package/src/gtk-popover.spec.ts +264 -0
- package/src/gtk-print-dialogs.spec.ts +251 -0
- package/src/gtk-revealer.spec.ts +164 -0
- package/src/gtk-scale-button.spec.ts +218 -0
- package/src/gtk-scale.spec.ts +213 -0
- package/src/gtk-scrollbar.spec.ts +244 -0
- package/src/gtk-scrolled-window.spec.ts +262 -0
- package/src/gtk-search-bar.spec.ts +179 -0
- package/src/gtk-search-entry.spec.ts +142 -0
- package/src/gtk-separator.spec.ts +74 -0
- package/src/gtk-spin-button.spec.ts +186 -0
- package/src/gtk-spinner.spec.ts +130 -0
- package/src/gtk-stack-sidebar.spec.ts +217 -0
- package/src/gtk-stack-switcher.spec.ts +249 -0
- package/src/gtk-stack.spec.ts +432 -0
- package/src/gtk-text-view.spec.ts +189 -0
- package/src/gtk-text.spec.ts +163 -0
- package/src/gtk-toggle-button.spec.ts +186 -0
- package/src/gtk-tree-expander.spec.ts +201 -0
- package/src/gtk-video.spec.ts +240 -0
- package/src/gtk-viewport.spec.ts +140 -0
- package/src/gtk-window-controls.spec.ts +232 -0
- package/src/gtk-window-handle.spec.ts +158 -0
- package/src/gtk-window.spec.ts +190 -0
- package/src/index.ts +9 -1
- package/src/keyboard-operable.spec.ts +33 -1
- package/src/list-view-dom.ts +121 -0
- package/src/namespace/adw.ts +12 -0
- package/src/namespace/gtk.ts +61 -0
- package/src/page-setup.ts +222 -0
- package/src/scroll-shading.ts +18 -1
- package/src/shared-tree-builder.ts +263 -21
- package/src/signals.ts +15 -0
- package/src/source-view/theme.ts +11 -5
- package/src/style-classes.spec.ts +9 -8
- package/src/styles.generated.ts +1 -1
- package/src/tab-chip.ts +200 -0
- package/src/template-classes.ts +45 -0
- package/src/test.browser.mts +152 -0
|
@@ -0,0 +1,664 @@
|
|
|
1
|
+
// <gtk-notebook> — the older page container, which brings its own tab bar. A stack
|
|
2
|
+
// plus a strip of tabs, in one widget: `tab-pos` says which edge the strip is on,
|
|
3
|
+
// `show-tabs` takes it away entirely, and `page` is the current page by INDEX
|
|
4
|
+
// rather than by name.
|
|
5
|
+
//
|
|
6
|
+
// IT IS A STACK IN C. `GtkNotebook` holds a `stack_widget` (a GtkStack) for the pages
|
|
7
|
+
// and a `header_widget` with the tabs beside it, and `real_switch_page` drives the
|
|
8
|
+
// stack directly (`gtk_stack_set_visible_child`, gtknotebook.c:5476). That is why
|
|
9
|
+
// `page` is an index: the stack speaks names, the notebook speaks positions.
|
|
10
|
+
//
|
|
11
|
+
// THE CHILD IS THE PAGE. `GtkNotebookPage` is a GObject, not a widget
|
|
12
|
+
// (`G_DEFINE_TYPE (…, G_TYPE_OBJECT)`, gtknotebook.c:423), so it has no element of its
|
|
13
|
+
// own: its properties are attributes on the child, and the descriptor
|
|
14
|
+
// {@link NotebookPageInfo} is what `getNthPage()` describes. Of its eleven properties
|
|
15
|
+
// (gtknotebook.c:600-699) this element carries the five that are scalars and draw
|
|
16
|
+
// something — `tab-label` (the tab's text), `menu-label`, `tab-fill`, `tab-expand` and
|
|
17
|
+
// `reorderable` — and the `hidden` attribute is `GtkWidget:visible`.
|
|
18
|
+
//
|
|
19
|
+
// WHICH PAGE IS CURRENT, transcribed from `set_current_page`
|
|
20
|
+
// (gtknotebook.c:6046-6060) and `real_switch_page` (gtknotebook.c:5436-5498):
|
|
21
|
+
// · a NEGATIVE index means the LAST page, not "none" (:6054) — so `page="-1"` on a
|
|
22
|
+
// notebook with three pages selects the third;
|
|
23
|
+
// · `page` OUT OF RANGE does nothing at all, because `g_list_nth` returns NULL and
|
|
24
|
+
// the switch is guarded (:6056-6058);
|
|
25
|
+
// · a page whose child is NOT visible is refused the same way
|
|
26
|
+
// (`!gtk_widget_get_visible (child)`, :5444), which is how a hidden page is kept
|
|
27
|
+
// out of the rotation;
|
|
28
|
+
// · switching to the CURRENT page is not a change (:5444), so no notify;
|
|
29
|
+
// · the old tab loses `:checked` and the new one gains it, and the tab's
|
|
30
|
+
// `GTK_ACCESSIBLE_STATE_SELECTED` follows (:5458-5462, :5472-5474) — which is
|
|
31
|
+
// `aria-selected` here.
|
|
32
|
+
// `page` then notifies (`:5497`), as does every property the setters move.
|
|
33
|
+
//
|
|
34
|
+
// TAB POSITION. `tab-pos` is one of the four `GtkPositionType` nicks and defaults to
|
|
35
|
+
// `top` (gtknotebook.c:1113-1117). `get_effective_tab_pos` swaps left and right under
|
|
36
|
+
// RTL (:1741-1757), which is why the element reflects the SWAPPED position in
|
|
37
|
+
// `data-tab-pos` rather than the raw property.
|
|
38
|
+
//
|
|
39
|
+
// `show-border` is a CSS CLASS in C and not a branch: `gtk_notebook_set_show_border`
|
|
40
|
+
// adds `.frame` and clearing it removes that (gtknotebook.c:6134-6146), and libadwaita
|
|
41
|
+
// styles the class as a plain one-pixel border. Its own docs say the bevel only shows
|
|
42
|
+
// when the tabs are not (:6125-6131), because the header's own border covers it.
|
|
43
|
+
//
|
|
44
|
+
// A11Y: the strip is a `tablist` and each tab a `tab`, which is what the tab widget's
|
|
45
|
+
// own role is here; the pages carry `aria-hidden` as they do in a stack.
|
|
46
|
+
//
|
|
47
|
+
// Events: `notify::<prop>` (CustomEvent, bubbles, detail `{ <prop>: value }`);
|
|
48
|
+
// `switch-page` (detail `{ page: index, child }`) is GtkNotebook's own signal
|
|
49
|
+
// (gtknotebook.c:1180-1197), emitted BEFORE the switch with the page being switched TO
|
|
50
|
+
// — `gtk_notebook_switch_page` emits and the class handler `real_switch_page` performs
|
|
51
|
+
// (:5518-5523) — so a handler that vetoes by not drawing is the documented use;
|
|
52
|
+
// `page-added` (:1380-1391, emitted at :4129) and `page-removed` (:1358-1369) carry
|
|
53
|
+
// `{ position, nPages }`, the two page-list signals the C raises around an insert and a
|
|
54
|
+
// remove.
|
|
55
|
+
//
|
|
56
|
+
// NOT PORTED, and why:
|
|
57
|
+
// · `detachable` (gtknotebook.c:694-702) and the DnD behind it move a page to
|
|
58
|
+
// ANOTHER notebook; the browser's drag is a different protocol, and a notebook
|
|
59
|
+
// with one stack of children has nothing to detach to.
|
|
60
|
+
// · `enable-popup` (:1150-1159) builds a GtkPopoverMenu of the pages when it is set
|
|
61
|
+
// (:6420-6462) and pops it up on right-click (:2684-2692). The flag is read and
|
|
62
|
+
// reflected, and `contextmenu` opens `<div role="listbox">` of the same pages — but
|
|
63
|
+
// it is a DOM listbox, not a GtkPopover.
|
|
64
|
+
// · `scrollable` (:1140-1149) adds GtkScrollbar arrows when the tabs do not fit. The
|
|
65
|
+
// tabs here overflow with `overflow-x: auto`, which scrolls without the two arrow
|
|
66
|
+
// buttons GTK scrolls with.
|
|
67
|
+
// · `group-name` (:1160-1169) groups notebooks for drag and drop, which is the same
|
|
68
|
+
// absent DnD as `detachable`.
|
|
69
|
+
//
|
|
70
|
+
// Reference: refs/gtk/gtk/gtknotebook.c
|
|
71
|
+
// Copyright (c) The GTK Team. LGPLv2.1+.
|
|
72
|
+
// Modifications: Implemented as a Web Component for @gjsify/adwaita-web.
|
|
73
|
+
|
|
74
|
+
/** `GtkPositionType`, spelled as the GIR's enum nicks. `top` is the property default. */
|
|
75
|
+
export type NotebookTabPos = 'top' | 'bottom' | 'left' | 'right';
|
|
76
|
+
|
|
77
|
+
const TAB_POSITIONS: readonly string[] = ['top', 'bottom', 'left', 'right'];
|
|
78
|
+
|
|
79
|
+
/** The page attributes this element reads off a child (gtknotebook.c:600-695). */
|
|
80
|
+
const PAGE_ATTRIBUTES = ['tab-label', 'menu-label', 'tab-fill', 'tab-expand', 'reorderable', 'detachable'];
|
|
81
|
+
|
|
82
|
+
/** The browser's page descriptor — the stand-in for the `GtkNotebookPage` GObject. */
|
|
83
|
+
export interface NotebookPageInfo {
|
|
84
|
+
/** `GtkNotebookPage:tab-label` — the tab's text. `null` when absent. */
|
|
85
|
+
tabLabel: string | null;
|
|
86
|
+
/** `GtkNotebookPage:menu-label` — the text of the menu entry. `null` when absent. */
|
|
87
|
+
menuLabel: string | null;
|
|
88
|
+
/** `GtkNotebookPage:tab-fill` — the tab fills its allocation. Defaults to TRUE. */
|
|
89
|
+
tabFill: boolean;
|
|
90
|
+
/** `GtkNotebookPage:tab-expand` — the tab expands. Defaults to false. */
|
|
91
|
+
tabExpand: boolean;
|
|
92
|
+
/** `GtkNotebookPage:reorderable` — the user may drag the tab. */
|
|
93
|
+
reorderable: boolean;
|
|
94
|
+
/** `GtkNotebookPage:detachable` — read and reflected; the drag itself is not ported. */
|
|
95
|
+
detachable: boolean;
|
|
96
|
+
/** `GtkWidget:visible` on the child, as the DOM's `hidden`. */
|
|
97
|
+
visible: boolean;
|
|
98
|
+
/** `GtkNotebookPage:child`. */
|
|
99
|
+
child: HTMLElement;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
export class GtkNotebook extends HTMLElement {
|
|
103
|
+
private _current: HTMLElement | null = null;
|
|
104
|
+
private _initialized = false;
|
|
105
|
+
private _initializedChildren = new WeakSet<HTMLElement>();
|
|
106
|
+
private _header!: HTMLDivElement;
|
|
107
|
+
private _tabs!: HTMLDivElement;
|
|
108
|
+
private _observer: MutationObserver | null = null;
|
|
109
|
+
private _tabNodes: HTMLButtonElement[] = [];
|
|
110
|
+
private _menu: HTMLElement | null = null;
|
|
111
|
+
|
|
112
|
+
static get observedAttributes() {
|
|
113
|
+
return ['page', 'tab-pos', 'show-tabs', 'show-border', 'scrollable', 'enable-popup', 'group-name'];
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* `Gtk.Notebook:page` — the index of the current page, `-1` when there is none.
|
|
118
|
+
*
|
|
119
|
+
* LIVE rather than the value last written: `get_property` returns
|
|
120
|
+
* `gtk_notebook_get_current_page (notebook)` (gtknotebook.c:1977-1979), so the
|
|
121
|
+
* attribute is an INPUT and this is the answer — a switch reached by clicking a tab
|
|
122
|
+
* is visible through the property without anything having written it. A negative
|
|
123
|
+
* WRITE means the LAST page (gtknotebook.c:6054).
|
|
124
|
+
*/
|
|
125
|
+
get page(): number {
|
|
126
|
+
return this._current ? this._pages().indexOf(this._current) : -1;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
set page(v: number) {
|
|
130
|
+
this.setCurrentPage(v);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/** `Gtk.Notebook:tab-pos` — which edge the tabs are on. Defaults to `top`. */
|
|
134
|
+
get tabPos(): NotebookTabPos {
|
|
135
|
+
const raw = this.getAttribute('tab-pos');
|
|
136
|
+
return raw !== null && TAB_POSITIONS.includes(raw) ? (raw as NotebookTabPos) : 'top';
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
set tabPos(v: NotebookTabPos) {
|
|
140
|
+
this._write('tab-pos', v);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/** `Gtk.Notebook:show-tabs` — the tab strip itself. Defaults to true. */
|
|
144
|
+
get showTabs(): boolean {
|
|
145
|
+
return this._flag('show-tabs', true);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
set showTabs(v: boolean) {
|
|
149
|
+
this._write('show-tabs', v ? '' : 'false');
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/** `Gtk.Notebook:show-border` — the border around the tab strip. Defaults to true. */
|
|
153
|
+
get showBorder(): boolean {
|
|
154
|
+
return this._flag('show-border', true);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
set showBorder(v: boolean) {
|
|
158
|
+
this._write('show-border', v ? '' : 'false');
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/** `Gtk.Notebook:scrollable` — GTK's scroll arrows. Defaults to false. */
|
|
162
|
+
get scrollable(): boolean {
|
|
163
|
+
return this._flag('scrollable', false);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
set scrollable(v: boolean) {
|
|
167
|
+
this._write('scrollable', v ? '' : 'false');
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/** `Gtk.Notebook:enable-popup` — the right-click page menu. Defaults to false. */
|
|
171
|
+
get enablePopup(): boolean {
|
|
172
|
+
return this._flag('enable-popup', false);
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
set enablePopup(v: boolean) {
|
|
176
|
+
this._write('enable-popup', v ? '' : 'false');
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
/** `Gtk.Notebook:group-name` — the drag-and-drop group. Defaults to `null`. */
|
|
180
|
+
get groupName(): string | null {
|
|
181
|
+
return this.getAttribute('group-name');
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
set groupName(v: string | null) {
|
|
185
|
+
this._write('group-name', v);
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
/** The current page's child, or `null` — `gtk_notebook_get_nth_page` at `page`. */
|
|
189
|
+
get currentPage(): HTMLElement | null {
|
|
190
|
+
return this._current;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
/** `gtk_notebook_get_n_pages` as the browser spells it. */
|
|
194
|
+
get nPages(): number {
|
|
195
|
+
return this._pages().length;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
/** `gtk_notebook_get_nth_page` (gtknotebook.c:5956-5977): a child, or null. */
|
|
199
|
+
getNthPage(n: number): HTMLElement | null {
|
|
200
|
+
const pages = this._pages();
|
|
201
|
+
const index = n < 0 ? pages.length - 1 : n;
|
|
202
|
+
return pages[index] ?? null;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
/** `gtk_notebook_page_num` (gtknotebook.c:6006-6020): an index, `-1` when absent. */
|
|
206
|
+
pageNum(child: HTMLElement): number {
|
|
207
|
+
return this._pages().indexOf(child);
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
/** The descriptor of one child, `null` when it is not a page of this notebook. */
|
|
211
|
+
getPage(child: HTMLElement): NotebookPageInfo | null {
|
|
212
|
+
return this._pages().includes(child) ? this._page(child) : null;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
/** `By CHILD rather than by index — `gtk_notebook_page_num` for the index and
|
|
216
|
+
* `gtk_notebook_set_current_page` for the switch (gtknotebook.c:6006, :6046). There is
|
|
217
|
+
* no `gtk_notebook_set_page` to transcribe: GTK 4 dropped it. */
|
|
218
|
+
setPage(child: HTMLElement): boolean {
|
|
219
|
+
const index = this._pages().indexOf(child);
|
|
220
|
+
if (index === -1) return false;
|
|
221
|
+
return this.setCurrentPage(index);
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
/**
|
|
225
|
+
* `gtk_notebook_next_page` (gtknotebook.c:6070-6088) — which searches with
|
|
226
|
+
* `gtk_notebook_search_page (…, STEP_NEXT, TRUE)`, so a HIDDEN page is stepped over
|
|
227
|
+
* rather than ending the walk, and the end of the notebook is simply nothing
|
|
228
|
+
* (:6079-6080).
|
|
229
|
+
*/
|
|
230
|
+
nextPage(): boolean {
|
|
231
|
+
return this._searchPage(1);
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
/** `gtk_notebook_prev_page` (gtknotebook.c:6096-6113), the same search backwards. */
|
|
235
|
+
prevPage(): boolean {
|
|
236
|
+
return this._searchPage(-1);
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
/**
|
|
240
|
+
* `gtk_notebook_set_current_page` (gtknotebook.c:6046-6060) into
|
|
241
|
+
* `real_switch_page` (gtknotebook.c:5436-5498): a negative index is the last page,
|
|
242
|
+
* an out-of-range one does nothing, and a page whose child is hidden is refused.
|
|
243
|
+
*/
|
|
244
|
+
setCurrentPage(index: number): boolean {
|
|
245
|
+
const pages = this._pages();
|
|
246
|
+
const target = index < 0 ? pages.length - 1 : index;
|
|
247
|
+
const child = pages[target];
|
|
248
|
+
if (!child) return false;
|
|
249
|
+
return this._switchTo(child);
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
/** `gtk_notebook_append_page` (gtknotebook.c:5807-5870) — the child is the page. */
|
|
253
|
+
appendPage(child: HTMLElement, tabLabel?: string | null): number {
|
|
254
|
+
return this.insertPage(child, -1, tabLabel);
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
/**
|
|
258
|
+
* `gtk_notebook_insert_page` (gtknotebook.c:5807-5870). A negative `position` means
|
|
259
|
+
* the end, which is what `append_page` passes.
|
|
260
|
+
*/
|
|
261
|
+
insertPage(child: HTMLElement, position: number, tabLabel?: string | null): number {
|
|
262
|
+
const index = position < 0 ? this._pages().length : position;
|
|
263
|
+
if (tabLabel !== undefined && tabLabel !== null) child.setAttribute('tab-label', tabLabel);
|
|
264
|
+
this._initChild(child);
|
|
265
|
+
this.insertBefore(child, this._pages()[index] ?? null);
|
|
266
|
+
this.dispatchEvent(
|
|
267
|
+
new CustomEvent('page-added', { bubbles: true, detail: { position: index, nPages: this._pages().length } }),
|
|
268
|
+
);
|
|
269
|
+
// `if (!gtk_notebook_has_current_page (notebook)) gtk_notebook_switch_page (…)`
|
|
270
|
+
// (gtknotebook.c:4131-4134), so an inserted page only becomes the current one
|
|
271
|
+
// while the notebook has none.
|
|
272
|
+
if (!this._current) this._switchTo(child);
|
|
273
|
+
this._render();
|
|
274
|
+
return index;
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
/** `gtk_notebook_remove_page` (gtknotebook.c:5899-5932). */
|
|
278
|
+
removePage(child: HTMLElement): boolean {
|
|
279
|
+
const index = this._pages().indexOf(child);
|
|
280
|
+
if (index === -1) return false;
|
|
281
|
+
if (child === this._current) this._current = null;
|
|
282
|
+
child.remove();
|
|
283
|
+
this.dispatchEvent(
|
|
284
|
+
new CustomEvent('page-removed', {
|
|
285
|
+
bubbles: true,
|
|
286
|
+
detail: { position: index, nPages: this._pages().length },
|
|
287
|
+
}),
|
|
288
|
+
);
|
|
289
|
+
// The current page went away with it, so a neighbour takes over — C searches
|
|
290
|
+
// `STEP_NEXT` and falls back to `STEP_PREV` at the end, both with `find_visible`
|
|
291
|
+
// TRUE, so it is the page that FOLLOWED rather than the first one, and a hidden
|
|
292
|
+
// page is stepped over rather than refused (gtknotebook.c:4281-4290).
|
|
293
|
+
if (!this._current) this._takeOver(index);
|
|
294
|
+
this._render();
|
|
295
|
+
return true;
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
/** Rebuild the tabs by hand, for a consumer that mutated a page in place. */
|
|
299
|
+
refresh(): void {
|
|
300
|
+
this._render();
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
connectedCallback() {
|
|
304
|
+
if (this._initialized) {
|
|
305
|
+
this._observer = new MutationObserver((records) => this._onMutations(records));
|
|
306
|
+
} else {
|
|
307
|
+
this._initialized = true;
|
|
308
|
+
this._header = document.createElement('div');
|
|
309
|
+
// libadwaita's node tree is `notebook > header > tabs > tab`
|
|
310
|
+
// (refs/libadwaita/src/stylesheet/widgets/_notebook.scss:4-10), so the
|
|
311
|
+
// element builds the same two levels rather than a flat row.
|
|
312
|
+
this._header.className = 'adw-notebook-header';
|
|
313
|
+
this._tabs = document.createElement('div');
|
|
314
|
+
this._tabs.className = 'adw-notebook-tabs';
|
|
315
|
+
this._tabs.setAttribute('role', 'tablist');
|
|
316
|
+
this._header.appendChild(this._tabs);
|
|
317
|
+
for (const child of this._pages()) this._initChild(child);
|
|
318
|
+
}
|
|
319
|
+
if (this._header.parentNode !== this) {
|
|
320
|
+
// The header comes FIRST in the DOM whatever `tab-pos` says — C lays the
|
|
321
|
+
// header out on the edge the tabs are on, which is a rendering decision, not
|
|
322
|
+
// a document-order one (gtknotebook.c:1533-1544: the stack and the tabs are parented to
|
|
323
|
+
// the notebook, and the edge is read at layout time by `get_effective_tab_pos`).
|
|
324
|
+
this.prepend(this._header);
|
|
325
|
+
}
|
|
326
|
+
this._observer?.observe(this, {
|
|
327
|
+
childList: true,
|
|
328
|
+
subtree: true,
|
|
329
|
+
attributes: true,
|
|
330
|
+
attributeFilter: [...PAGE_ATTRIBUTES, 'hidden'],
|
|
331
|
+
});
|
|
332
|
+
if (!this._current) this._switchTo(this._firstVisible());
|
|
333
|
+
this.addEventListener('contextmenu', this._onContextMenu);
|
|
334
|
+
this._render();
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
disconnectedCallback() {
|
|
338
|
+
this._observer?.disconnect();
|
|
339
|
+
this._observer = null;
|
|
340
|
+
this.removeEventListener('contextmenu', this._onContextMenu);
|
|
341
|
+
this._closeMenu();
|
|
342
|
+
// `_initialized` STAYS true: a widget that is removed from the tree keeps the
|
|
343
|
+
// children it had, and a header rebuilt on the way back in would be a second one
|
|
344
|
+
// left behind — which the page list, that filters out the header by identity,
|
|
345
|
+
// would then read as a page.
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
attributeChangedCallback(name: string) {
|
|
349
|
+
if (!this._initialized) return;
|
|
350
|
+
if (name === 'page') {
|
|
351
|
+
// The ATTRIBUTE is the input here — `set_property` is
|
|
352
|
+
// `gtk_notebook_set_current_page (notebook, g_value_get_int (value))`
|
|
353
|
+
// (gtknotebook.c:1940-1942) — and `page` reads the live index, so parsing the
|
|
354
|
+
// raw string is what keeps the two apart.
|
|
355
|
+
const raw = this.getAttribute(name);
|
|
356
|
+
if (raw !== null) this.setCurrentPage(Number.parseInt(raw, 10));
|
|
357
|
+
return;
|
|
358
|
+
}
|
|
359
|
+
this._render();
|
|
360
|
+
this._notify(name);
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
/**
|
|
364
|
+
* `switch-page` is emitted BEFORE the switch (gtknotebook.c:5518-5523) and
|
|
365
|
+
* `real_switch_page` runs after it, so a listener sees the page being switched TO
|
|
366
|
+
* while `page` still reads the old one — the order C's own handlers rely on.
|
|
367
|
+
*/
|
|
368
|
+
private _switchTo(child: HTMLElement): boolean {
|
|
369
|
+
const pages = this._pages();
|
|
370
|
+
const index = pages.indexOf(child);
|
|
371
|
+
if (index === -1) return false;
|
|
372
|
+
// `!gtk_widget_get_visible (child)` (gtknotebook.c:5444) — the page flag AND
|
|
373
|
+
// the widget's own visibility, which is the DOM's `hidden` here.
|
|
374
|
+
if (!this._page(child).visible) return false;
|
|
375
|
+
if (this._current === child) return false;
|
|
376
|
+
const event = new CustomEvent('switch-page', {
|
|
377
|
+
bubbles: true,
|
|
378
|
+
cancelable: true,
|
|
379
|
+
detail: { page: index, child },
|
|
380
|
+
});
|
|
381
|
+
this.dispatchEvent(event);
|
|
382
|
+
// A handler that stops the emission keeps the switch from happening: `switch-page`
|
|
383
|
+
// is `G_SIGNAL_RUN_LAST`, so `real_switch_page` IS the default handler and
|
|
384
|
+
// `g_signal_stop_emission` from a listener is what holds it back. `preventDefault`
|
|
385
|
+
// is that call's spelling here — cancelling the event, not the propagation, so
|
|
386
|
+
// every other listener still runs.
|
|
387
|
+
if (event.defaultPrevented) return false;
|
|
388
|
+
this._current = child;
|
|
389
|
+
this._render();
|
|
390
|
+
// `g_object_notify_by_pspec (…, PROP_PAGE)` (gtknotebook.c:5497).
|
|
391
|
+
this._notify('page');
|
|
392
|
+
return true;
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
private _notify(name: string): void {
|
|
396
|
+
this.dispatchEvent(
|
|
397
|
+
new CustomEvent(`notify::${name}`, { bubbles: true, detail: { [name]: this._property(name) } }),
|
|
398
|
+
);
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
private _property(name: string): string | number | boolean | null {
|
|
402
|
+
switch (name) {
|
|
403
|
+
case 'page':
|
|
404
|
+
return this.page;
|
|
405
|
+
case 'tab-pos':
|
|
406
|
+
return this.tabPos;
|
|
407
|
+
case 'show-tabs':
|
|
408
|
+
return this.showTabs;
|
|
409
|
+
case 'show-border':
|
|
410
|
+
return this.showBorder;
|
|
411
|
+
case 'scrollable':
|
|
412
|
+
return this.scrollable;
|
|
413
|
+
case 'enable-popup':
|
|
414
|
+
return this.enablePopup;
|
|
415
|
+
default:
|
|
416
|
+
return this.groupName;
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
private _write(name: string, value: string | null): void {
|
|
421
|
+
if (value === null) this.removeAttribute(name);
|
|
422
|
+
else if (this.getAttribute(name) !== value) this.setAttribute(name, value);
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
/** A boolean property with a non-false default: absent means the default. */
|
|
426
|
+
private _flag(name: string, fallback: boolean): boolean {
|
|
427
|
+
const raw = this.getAttribute(name);
|
|
428
|
+
if (raw === null) return fallback;
|
|
429
|
+
return raw !== 'false';
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
/** The children, in page order — the header is the widget's own, never a page. */
|
|
433
|
+
private _pages(): HTMLElement[] {
|
|
434
|
+
return Array.from(this.children).filter((child) => child !== this._header) as HTMLElement[];
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
private _page(child: HTMLElement): NotebookPageInfo {
|
|
438
|
+
return {
|
|
439
|
+
tabLabel: child.getAttribute('tab-label'),
|
|
440
|
+
menuLabel: child.getAttribute('menu-label'),
|
|
441
|
+
// `tab-fill` defaults TRUE and `tab-expand` FALSE (gtknotebook.c:663-681).
|
|
442
|
+
tabFill: child.getAttribute('tab-fill') !== 'false',
|
|
443
|
+
tabExpand: child.hasAttribute('tab-expand'),
|
|
444
|
+
reorderable: child.hasAttribute('reorderable'),
|
|
445
|
+
detachable: child.hasAttribute('detachable'),
|
|
446
|
+
visible: !child.hasAttribute('hidden'),
|
|
447
|
+
child,
|
|
448
|
+
};
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
private _initChild(child: HTMLElement): void {
|
|
452
|
+
if (this._initializedChildren.has(child)) return;
|
|
453
|
+
this._initializedChildren.add(child);
|
|
454
|
+
child.classList.add('adw-notebook-page');
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
private _firstVisible(): HTMLElement | null {
|
|
458
|
+
return this._pages().find((child) => this._page(child).visible) ?? null;
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
/**
|
|
462
|
+
* `gtk_notebook_search_page` with `find_visible` TRUE (gtknotebook.c:4412-4470): walk
|
|
463
|
+
* from the current page in `direction`, skipping every page whose child is hidden, and
|
|
464
|
+
* switch to the first one that takes. Off either end there is nothing, which is the
|
|
465
|
+
* FALSE both `next_page` and `prev_page` return.
|
|
466
|
+
*/
|
|
467
|
+
private _searchPage(direction: 1 | -1): boolean {
|
|
468
|
+
const pages = this._pages();
|
|
469
|
+
const start = this._current ? pages.indexOf(this._current) : -1;
|
|
470
|
+
for (let i = start + direction; i >= 0 && i < pages.length; i += direction) {
|
|
471
|
+
if (this._switchTo(pages[i])) return true;
|
|
472
|
+
}
|
|
473
|
+
return false;
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
/**
|
|
477
|
+
* The neighbour a REMOVAL hands the notebook to: the pages that followed the removed
|
|
478
|
+
* one, then the pages that came before it — `search_page (…, STEP_NEXT, TRUE)` and
|
|
479
|
+
* then `search_page (…, STEP_PREV, TRUE)` (gtknotebook.c:4281-4282), which is a wrap
|
|
480
|
+
* rather than a one-way walk. `position` is where the removed page WAS.
|
|
481
|
+
*/
|
|
482
|
+
private _takeOver(position: number): boolean {
|
|
483
|
+
const pages = this._pages();
|
|
484
|
+
for (const page of [...pages.slice(position), ...pages.slice(0, position)]) {
|
|
485
|
+
if (this._switchTo(page)) return true;
|
|
486
|
+
}
|
|
487
|
+
return false;
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
private _onMutations(records: MutationRecord[]): void {
|
|
491
|
+
// THE PAGE AREA ONLY, and the filter is load-bearing rather than tidiness. This
|
|
492
|
+
// observer watches the subtree, and the render pass writes INTO it: `hidden` and
|
|
493
|
+
// `textContent` on the tabs, `replaceChildren` on the strip. `setAttribute` queues a
|
|
494
|
+
// record even when the value is unchanged, and assigning `textContent` always
|
|
495
|
+
// replaces the text node, so a record from the strip went straight back into
|
|
496
|
+
// `_render()` and never stopped — a frozen page rather than a failing test, which is
|
|
497
|
+
// how this presented. `subtree: true` is what makes those records reachable at all;
|
|
498
|
+
// this is what keeps them out. What IS ours is the notebook's own child list — a page
|
|
499
|
+
// in or out — and a page's attributes, which is exactly the two targets below.
|
|
500
|
+
const pages = new Set(this._pages());
|
|
501
|
+
const pageRecords = records.filter(
|
|
502
|
+
(record) => record.target === this || pages.has(record.target as HTMLElement),
|
|
503
|
+
);
|
|
504
|
+
// …and a batch with nothing of ours in it gets NO render pass. That early return is
|
|
505
|
+
// the half that actually stops the feedback: filtering the records only keeps the
|
|
506
|
+
// bookkeeping out, while a `_render()` at the end of EVERY batch rewrote the strip
|
|
507
|
+
// and queued the next one, so the loop kept running on batches already empty.
|
|
508
|
+
if (pageRecords.length === 0) return;
|
|
509
|
+
let added = 0;
|
|
510
|
+
let removed = 0;
|
|
511
|
+
const updated: Element[] = [];
|
|
512
|
+
for (const record of pageRecords) {
|
|
513
|
+
if (record.type === 'childList') {
|
|
514
|
+
for (const node of Array.from(record.removedNodes)) {
|
|
515
|
+
if (node === this._current) this._current = null;
|
|
516
|
+
removed += 1;
|
|
517
|
+
}
|
|
518
|
+
for (const node of Array.from(record.addedNodes)) {
|
|
519
|
+
if (!(node instanceof HTMLElement) || node === this._header) continue;
|
|
520
|
+
this._initChild(node);
|
|
521
|
+
added += 1;
|
|
522
|
+
}
|
|
523
|
+
continue;
|
|
524
|
+
}
|
|
525
|
+
const name = record.attributeName;
|
|
526
|
+
if (name === 'hidden') {
|
|
527
|
+
if (!this._current || !this._page(this._current).visible) this._switchTo(this._firstVisible());
|
|
528
|
+
continue;
|
|
529
|
+
}
|
|
530
|
+
if (name && PAGE_ATTRIBUTES.includes(name)) updated.push(record.target as HTMLElement);
|
|
531
|
+
}
|
|
532
|
+
if (added > 0 || removed > 0) {
|
|
533
|
+
this.dispatchEvent(new CustomEvent('items-changed', { bubbles: true, detail: { added, removed } }));
|
|
534
|
+
}
|
|
535
|
+
for (const child of updated) {
|
|
536
|
+
this.dispatchEvent(new CustomEvent('page-updated', { bubbles: true, detail: { child } }));
|
|
537
|
+
}
|
|
538
|
+
this._render();
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
/** Which edge the tabs are on, with RTL's left/right swap (gtknotebook.c:1741-1757). */
|
|
542
|
+
private _effectiveTabPos(): NotebookTabPos {
|
|
543
|
+
const pos = this.tabPos;
|
|
544
|
+
if (this.getAttribute('dir') !== 'rtl') return pos;
|
|
545
|
+
if (pos === 'left') return 'right';
|
|
546
|
+
if (pos === 'right') return 'left';
|
|
547
|
+
return pos;
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
private _render(): void {
|
|
551
|
+
if (!this._initialized) return;
|
|
552
|
+
const pages = this._pages();
|
|
553
|
+
if (pages.length !== this._tabNodes.length) {
|
|
554
|
+
this._tabs.replaceChildren();
|
|
555
|
+
this._tabNodes = pages.map(() => this._buildTab());
|
|
556
|
+
this._tabs.append(...this._tabNodes);
|
|
557
|
+
}
|
|
558
|
+
const currentIndex = this._current ? pages.indexOf(this._current) : -1;
|
|
559
|
+
// `gtk_notebook_update_labels` numbers the tabs ONE-BASED and only over the
|
|
560
|
+
// VISIBLE ones — `gtk_notebook_search_page (…, STEP_NEXT, FALSE)` steps over a
|
|
561
|
+
// hidden page — and a page with no `tab-label` gets that number AS ITS TEXT rather
|
|
562
|
+
// than no tab at all (gtknotebook.c:4353-4373).
|
|
563
|
+
let pageNumber = 0;
|
|
564
|
+
pages.forEach((page, index) => {
|
|
565
|
+
const tab = this._tabNodes[index];
|
|
566
|
+
if (!tab) return;
|
|
567
|
+
const info = this._page(page);
|
|
568
|
+
const selected = index === currentIndex;
|
|
569
|
+
if (info.visible) pageNumber += 1;
|
|
570
|
+
// The two writes below are GUARDED, and that is not an optimisation: each is a
|
|
571
|
+
// mutation the observer would be handed (`textContent` always replaces the text
|
|
572
|
+
// node, `setAttribute` queues a record even for an unchanged value), so an
|
|
573
|
+
// unguarded write makes a render pass able to trigger the next one. C's own
|
|
574
|
+
// label pass only touches a label whose text differs
|
|
575
|
+
// (`page->default_tab` and `gtk_label_set_text`, gtknotebook.c:4380-4391).
|
|
576
|
+
const text = info.tabLabel ?? `Page ${pageNumber}`;
|
|
577
|
+
if (tab.textContent !== text) tab.textContent = text;
|
|
578
|
+
tab.classList.toggle('active', selected);
|
|
579
|
+
tab.classList.toggle('expand', info.tabExpand);
|
|
580
|
+
tab.classList.toggle('fill', info.tabFill);
|
|
581
|
+
tab.classList.toggle('reorderable', info.reorderable);
|
|
582
|
+
// `gtk_widget_set_visible (page->tab_label, show_tabs &&
|
|
583
|
+
// gtk_widget_get_visible (page->child))` (gtknotebook.c:4117-4118): a hidden
|
|
584
|
+
// page takes its tab with it, which is the other half of why
|
|
585
|
+
// `real_switch_page` refuses a hidden page at all.
|
|
586
|
+
const hidden = !info.visible;
|
|
587
|
+
if (tab.hidden !== hidden) tab.hidden = hidden;
|
|
588
|
+
tab.setAttribute('aria-selected', String(selected));
|
|
589
|
+
page.classList.toggle('visible-page', selected);
|
|
590
|
+
if (selected) page.removeAttribute('aria-hidden');
|
|
591
|
+
else page.setAttribute('aria-hidden', 'true');
|
|
592
|
+
});
|
|
593
|
+
// `gtk_widget_set_visible (header_widget, show_tabs)` (gtknotebook.c:5467).
|
|
594
|
+
const headerHidden = !this.showTabs;
|
|
595
|
+
if (this._header.hidden !== headerHidden) this._header.hidden = headerHidden;
|
|
596
|
+
const tabPos = this._effectiveTabPos();
|
|
597
|
+
if (this.getAttribute('data-tab-pos') !== tabPos) this.setAttribute('data-tab-pos', tabPos);
|
|
598
|
+
// `show-border` IS the `.frame` class in C — `gtk_notebook_set_show_border` adds it
|
|
599
|
+
// and clearing the property removes it (gtknotebook.c:6134-6146) — and this
|
|
600
|
+
// stylesheet already carries libadwaita's rule for the class (`_misc.scss:4-7`,
|
|
601
|
+
// ported whole in `_style_classes.scss`), so this is the same mechanism rather than
|
|
602
|
+
// a private spelling of it.
|
|
603
|
+
this.classList.toggle('frame', this.showBorder);
|
|
604
|
+
}
|
|
605
|
+
|
|
606
|
+
private _buildTab(): HTMLButtonElement {
|
|
607
|
+
const tab = document.createElement('button');
|
|
608
|
+
tab.type = 'button';
|
|
609
|
+
tab.className = 'adw-notebook-tab';
|
|
610
|
+
tab.setAttribute('role', 'tab');
|
|
611
|
+
tab.addEventListener('click', () => {
|
|
612
|
+
const index = this._tabNodes.findIndex((candidate) => candidate === tab);
|
|
613
|
+
if (index === -1) return;
|
|
614
|
+
const page = this._pages()[index];
|
|
615
|
+
if (page) this._switchTo(page);
|
|
616
|
+
});
|
|
617
|
+
return tab;
|
|
618
|
+
}
|
|
619
|
+
|
|
620
|
+
/**
|
|
621
|
+
* `enable-popup`'s right-click menu (`gtk_notebook_popup_enable`,
|
|
622
|
+
* gtknotebook.c:6420-6462 builds it and `gtk_notebook_popup_menu` at :2684-2692 pops
|
|
623
|
+
* it up) as a DOM listbox of
|
|
624
|
+
* the same pages. C builds it with `gtk_menu_model` and a GtkPopover; the page set
|
|
625
|
+
* and the selection are the same, the widget is not.
|
|
626
|
+
*/
|
|
627
|
+
private readonly _onContextMenu = (event: Event): void => {
|
|
628
|
+
if (!this.enablePopup) return;
|
|
629
|
+
event.preventDefault();
|
|
630
|
+
this._closeMenu();
|
|
631
|
+
const menu = document.createElement('div');
|
|
632
|
+
menu.className = 'adw-notebook-menu';
|
|
633
|
+
menu.setAttribute('role', 'listbox');
|
|
634
|
+
let pageNumber = 0;
|
|
635
|
+
for (const page of this._pages()) {
|
|
636
|
+
const info = this._page(page);
|
|
637
|
+
if (info.visible) pageNumber += 1;
|
|
638
|
+
const item = document.createElement('button');
|
|
639
|
+
item.type = 'button';
|
|
640
|
+
item.className = 'adw-notebook-menu-item';
|
|
641
|
+
item.setAttribute('role', 'option');
|
|
642
|
+
// `gtk_notebook_menu_item_create` builds the label from `menu_label`, falls
|
|
643
|
+
// back to the tab label when the tab label IS a GtkLabel, and hides the item
|
|
644
|
+
// for a page whose child is hidden (gtknotebook.c:5624-5649).
|
|
645
|
+
item.textContent = info.menuLabel ?? info.tabLabel ?? `Page ${pageNumber}`;
|
|
646
|
+
item.hidden = !info.visible;
|
|
647
|
+
item.setAttribute('aria-selected', String(page === this._current));
|
|
648
|
+
item.addEventListener('click', () => {
|
|
649
|
+
this._switchTo(page);
|
|
650
|
+
this._closeMenu();
|
|
651
|
+
});
|
|
652
|
+
menu.appendChild(item);
|
|
653
|
+
}
|
|
654
|
+
this.appendChild(menu);
|
|
655
|
+
this._menu = menu;
|
|
656
|
+
};
|
|
657
|
+
|
|
658
|
+
private _closeMenu(): void {
|
|
659
|
+
this._menu?.remove();
|
|
660
|
+
this._menu = null;
|
|
661
|
+
}
|
|
662
|
+
}
|
|
663
|
+
|
|
664
|
+
customElements.define('gtk-notebook', GtkNotebook);
|