@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
|
@@ -0,0 +1,757 @@
|
|
|
1
|
+
// <gtk-calendar> — the month grid: a heading with four navigation arrows, the day-name row, an
|
|
2
|
+
// optional week-number column and 42 day cells, the web counterpart of `Gtk.Calendar`.
|
|
3
|
+
//
|
|
4
|
+
// THE GRID IS `calendarDays` AND FRIENDS, in `@gjsify/adwaita-core` (ADR 0004), because every
|
|
5
|
+
// part of it is arithmetic the C does in integers: which days lead the month, which trail it,
|
|
6
|
+
// what ISO week each row is, and what a month step lands on when the source day does not exist
|
|
7
|
+
// in the target. `calendar.ts` carries the derivations and the vectors; this element holds the
|
|
8
|
+
// marks, the focus cell and the date.
|
|
9
|
+
//
|
|
10
|
+
// `date` IS AN ISO `YYYY-MM-DD` STRING, which is what `GDateTime` is written as in every GTK
|
|
11
|
+
// binding and what `Date.parse` reads, so the markup door is the object's own ISO 8601
|
|
12
|
+
// serialisation rather than a port-specific encoding. The three DEPRECATED `year` / `month` /
|
|
13
|
+
// `day` properties are observed as attributes and kept in step with `date` exactly as
|
|
14
|
+
// upstream's setters do — `gtk_calendar_set_year` calls `calendar_select_day_internal` with
|
|
15
|
+
// the same day in the new year (gtkcalendar.c:860-880), so a write to `year` and a write to
|
|
16
|
+
// `date` are the same operation. They are deprecated in 4.20 in favour of `date` and this
|
|
17
|
+
// element says so rather than hiding them.
|
|
18
|
+
//
|
|
19
|
+
// `month` IS 0-11 HERE, because the attribute is the GIR property and GIR's property is
|
|
20
|
+
// 0-indexed — the ONE place this element departs from `GDateTime`'s own 1-12 numbering, and
|
|
21
|
+
// the property's own documentation states the range (:419-429). Core functions take 1-12 and
|
|
22
|
+
// say so; the boundary is exactly the two attribute readers below.
|
|
23
|
+
//
|
|
24
|
+
// SHOW-HEADING AND SHOW-DAY-NAMES DEFAULT TRUE, SHOW-WEEK-NUMBERS FALSE (:440-460), so the
|
|
25
|
+
// two are INVERTED flags read as `="false"`. The week-number column is a real grid COLUMN and
|
|
26
|
+
// not a decoration: upstream the day numbers are attached at column `1 + i` and the week
|
|
27
|
+
// numbers at column 0 (gtkcalendar.c:776-790), which is why turning the numbers on narrows
|
|
28
|
+
// the days rather than overlaying them.
|
|
29
|
+
//
|
|
30
|
+
// THE THREE ARROWS' SENSE. A cell belonging to the PREVIOUS month, activated with Space,
|
|
31
|
+
// pages BACK and selects that day (`calendar_set_month_prev`, gtkcalendar.c:1521-1534), and
|
|
32
|
+
// likewise forwards for the next month. The month and year arrows go through
|
|
33
|
+
// `calendar_select_day_internal` with `emit_day_signal = FALSE` (:868-919), so paging the
|
|
34
|
+
// calendar repaints without telling an application the user picked a day.
|
|
35
|
+
//
|
|
36
|
+
// WHAT IS NOT HERE: `gtk_calendar_select_day` is a deprecated METHOD in favour of the
|
|
37
|
+
// `date` property, so it is `date` here; `GtkDragSource` / `GtkDropTarget` (:543-560, :820-830)
|
|
38
|
+
// have no browser counterpart this element can reach for; and the `focus_row` / `focus_col`
|
|
39
|
+
// cursor is INTERNAL state upstream with no property, so it is the roving focus of the grid
|
|
40
|
+
// here — arrows move it, `Space` acts on the cell it is on, which is the C's `move_focus` +
|
|
41
|
+
// Space branch (gtkcalendar.c:1386-1534).
|
|
42
|
+
//
|
|
43
|
+
// Reference: refs/gtk/gtk/gtkcalendar.c:134-178 (the tables), :372-540 (properties, signals,
|
|
44
|
+
// css name), :564-861 (the widget tree and the defaults), :923-1084 (the grid, the labels, the
|
|
45
|
+
// navigation buttons), :1089-1192 (select_day_internal), :1311-1353 (the click), :1386-1534
|
|
46
|
+
// (move_focus and the key table), :1564-1782 (the public API)
|
|
47
|
+
// Reference: refs/libadwaita/src/stylesheet/widgets/_calendar.scss:1-58
|
|
48
|
+
// Copyright (c) GNOME contributors (GTK/libadwaita). LGPLv2.1+.
|
|
49
|
+
// Modifications: Implemented as a Web Component for @gjsify/adwaita-web; the date arithmetic
|
|
50
|
+
// composed from @gjsify/adwaita-core.
|
|
51
|
+
|
|
52
|
+
import {
|
|
53
|
+
CALENDAR_YEAR_MAX,
|
|
54
|
+
CALENDAR_YEAR_MIN,
|
|
55
|
+
calendarClearMarks,
|
|
56
|
+
calendarDayIsMarked,
|
|
57
|
+
calendarDays,
|
|
58
|
+
calendarMarkDay,
|
|
59
|
+
calendarNavigationButtons,
|
|
60
|
+
calendarSelectDay,
|
|
61
|
+
calendarStep,
|
|
62
|
+
calendarWeekNumber,
|
|
63
|
+
calendarWeekStart,
|
|
64
|
+
type AdwCalendarCell,
|
|
65
|
+
type AdwCalendarSelectResult,
|
|
66
|
+
type AdwCalendarDate,
|
|
67
|
+
type AdwCalendarStep,
|
|
68
|
+
} from '@gjsify/adwaita-core';
|
|
69
|
+
|
|
70
|
+
import { createGtkImage } from './gtk-image.js';
|
|
71
|
+
|
|
72
|
+
/** The seven abbreviated day names, Sunday first — `default_abbreviated_dayname` (:745-757). */
|
|
73
|
+
const DAY_NAMES = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];
|
|
74
|
+
|
|
75
|
+
/** The twelve month names — `default_monthname` (:759-786), which strftime-falls-back to `%B`. */
|
|
76
|
+
const MONTH_NAMES = [
|
|
77
|
+
'January',
|
|
78
|
+
'February',
|
|
79
|
+
'March',
|
|
80
|
+
'April',
|
|
81
|
+
'May',
|
|
82
|
+
'June',
|
|
83
|
+
'July',
|
|
84
|
+
'August',
|
|
85
|
+
'September',
|
|
86
|
+
'October',
|
|
87
|
+
'November',
|
|
88
|
+
'December',
|
|
89
|
+
];
|
|
90
|
+
|
|
91
|
+
/** The four arrows, in the order `gtk_calendar_init` appends them (:600-616). */
|
|
92
|
+
const ARROWS: readonly { step: AdwCalendarStep; icon: string; tooltip: string }[] = [
|
|
93
|
+
{ step: 'previous-month', icon: 'go-previous', tooltip: 'Previous Month' },
|
|
94
|
+
{ step: 'next-month', icon: 'go-next', tooltip: 'Next Month' },
|
|
95
|
+
{ step: 'previous-year', icon: 'go-up', tooltip: 'Previous Year' },
|
|
96
|
+
{ step: 'next-year', icon: 'go-down', tooltip: 'Next Year' },
|
|
97
|
+
];
|
|
98
|
+
|
|
99
|
+
/** The arrow a cell's disabled state keys off — `calendar_update_navigation_buttons` (:1055-1084). */
|
|
100
|
+
type ArrowName = 'previousMonth' | 'nextMonth' | 'previousYear' | 'nextYear';
|
|
101
|
+
|
|
102
|
+
export class GtkCalendar extends HTMLElement {
|
|
103
|
+
private _headerEl!: HTMLDivElement;
|
|
104
|
+
private _monthEl!: HTMLSpanElement;
|
|
105
|
+
private _yearEl!: HTMLSpanElement;
|
|
106
|
+
private _arrowEls: Record<ArrowName, HTMLButtonElement> = {} as Record<ArrowName, HTMLButtonElement>;
|
|
107
|
+
private _gridEl!: HTMLDivElement;
|
|
108
|
+
private _dayNameEls: HTMLSpanElement[] = [];
|
|
109
|
+
private _weekNumberEls: HTMLSpanElement[] = [];
|
|
110
|
+
private _cellEls: HTMLButtonElement[] = [];
|
|
111
|
+
private _marked: boolean[] = calendarClearMarks();
|
|
112
|
+
private _date: AdwCalendarDate;
|
|
113
|
+
/** `focus_row` / `focus_col` collapsed into one index into the 42 cells, -1 for neither. */
|
|
114
|
+
private _focus = -1;
|
|
115
|
+
private _initialized = false;
|
|
116
|
+
|
|
117
|
+
static get observedAttributes() {
|
|
118
|
+
return ['date', 'year', 'month', 'day', 'show-heading', 'show-day-names', 'show-week-numbers', 'week-start'];
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* `GtkCalendar:date` — the selected date as `YYYY-MM-DD`, `GDateTime`'s own ISO form.
|
|
123
|
+
*
|
|
124
|
+
* Unset means TODAY, which is what `gtk_calendar_init` seeds it with
|
|
125
|
+
* (`g_date_time_new_now_local`, gtkcalendar.c:851) — so the getter answers today when no
|
|
126
|
+
* attribute is present, rather than the epoch the C starts from before its first select.
|
|
127
|
+
*/
|
|
128
|
+
get date(): string {
|
|
129
|
+
return toIsoDate(this._date);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
set date(value: string) {
|
|
133
|
+
this.setAttribute('date', value);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/** `GtkCalendar:year` — DEPRECATED in 4.20 in favour of `date` (:396-403). */
|
|
137
|
+
get year(): number {
|
|
138
|
+
return this._date.year;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
set year(value: number) {
|
|
142
|
+
this.setAttribute('year', String(value));
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* `GtkCalendar:month` — DEPRECATED in 4.20, and 0-11, not 1-12 (:405-417). The one place
|
|
147
|
+
* this element is not in `GDateTime`'s own numbering, and it is the attribute that says so.
|
|
148
|
+
*/
|
|
149
|
+
get month(): number {
|
|
150
|
+
return this._date.month - 1;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
set month(value: number) {
|
|
154
|
+
this.setAttribute('month', String(value));
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/** `GtkCalendar:day` — DEPRECATED in 4.20 in favour of `date` (:419-428). */
|
|
158
|
+
get day(): number {
|
|
159
|
+
return this._date.day;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
set day(value: number) {
|
|
163
|
+
this.setAttribute('day', String(value));
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/** Default TRUE (:441-443), so the attribute is the OFF switch. */
|
|
167
|
+
get showHeading(): boolean {
|
|
168
|
+
return this.getAttribute('show-heading') !== 'false';
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
set showHeading(value: boolean) {
|
|
172
|
+
this.setAttribute('show-heading', String(!!value));
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/** Default TRUE (:450-452), read the same way. */
|
|
176
|
+
get showDayNames(): boolean {
|
|
177
|
+
return this.getAttribute('show-day-names') !== 'false';
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
set showDayNames(value: boolean) {
|
|
181
|
+
this.setAttribute('show-day-names', String(!!value));
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/** Default FALSE (:458-460), read the same way. */
|
|
185
|
+
get showWeekNumbers(): boolean {
|
|
186
|
+
return this.hasAttribute('show-week-numbers');
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
set showWeekNumbers(value: boolean) {
|
|
190
|
+
this.toggleAttribute('show-week-numbers', !!value);
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
/**
|
|
194
|
+
* Which day the grid's first column is — `calendar->week_start`, PORT-ONLY.
|
|
195
|
+
*
|
|
196
|
+
* The C reads it out of the locale (`_NL_TIME_FIRST_WEEKDAY` plus `_NL_TIME_WEEK_1STDAY`,
|
|
197
|
+
* gtkcalendar.c:700-718) and has no property for it, and this port does the same by
|
|
198
|
+
* default through `Intl.Locale.getWeekInfo()`. The ATTRIBUTE is the addition, and it is
|
|
199
|
+
* what makes a gallery preview reproducible: a grid whose leading blanks follow the
|
|
200
|
+
* machine's locale is a screenshot that differs per reader, and the C's own
|
|
201
|
+
* `calendar:week_start:0` translatable string (gtkcalendar.c:712-719) is the same
|
|
202
|
+
* override upstream.
|
|
203
|
+
*
|
|
204
|
+
* 0 is Sunday and 6 is Saturday — `GDateTime`'s own numbering, so it is the value
|
|
205
|
+
* `calendarDays` subtracts with and the value every vector table carries.
|
|
206
|
+
*/
|
|
207
|
+
get weekStart(): number {
|
|
208
|
+
const authored = this.getAttribute('week-start');
|
|
209
|
+
if (authored !== null) {
|
|
210
|
+
const parsed = Number.parseInt(authored, 10);
|
|
211
|
+
if (Number.isFinite(parsed) && parsed >= 0 && parsed <= 6) return parsed;
|
|
212
|
+
}
|
|
213
|
+
return localeWeekStart();
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
set weekStart(value: number) {
|
|
217
|
+
this.setAttribute('week-start', String(value));
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
/** The 31-slot table — `gtk_calendar_get_day_is_marked`, so a mark does not change state. */
|
|
221
|
+
get markedDays(): number[] {
|
|
222
|
+
return this._marked.flatMap((mark, index) => (mark ? [index + 1] : []));
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
constructor() {
|
|
226
|
+
super();
|
|
227
|
+
this._date = today();
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
connectedCallback() {
|
|
231
|
+
if (this._initialized) return;
|
|
232
|
+
this._initialized = true;
|
|
233
|
+
|
|
234
|
+
this._buildHeader();
|
|
235
|
+
this._buildGrid();
|
|
236
|
+
// The C parents the header and then the grid onto the widget itself
|
|
237
|
+
// (gtkcalendar.c:620, :816) under a vertical `Gtk.BoxLayout` (:849-850), which is the
|
|
238
|
+
// `flex-direction: column` in `_calendar.scss`.
|
|
239
|
+
this.replaceChildren(this._headerEl, this._gridEl);
|
|
240
|
+
|
|
241
|
+
this.addEventListener('keydown', (event) => this._onKeyDown(event));
|
|
242
|
+
|
|
243
|
+
// Every write goes through `selectDay`, so the early return that makes a no-op write
|
|
244
|
+
// silent (gtkcalendar.c:1103-1104) applies to the ATTRIBUTE door too.
|
|
245
|
+
this._adoptAttributes();
|
|
246
|
+
this._render();
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
attributeChangedCallback(name?: string) {
|
|
250
|
+
if (!this._initialized) return;
|
|
251
|
+
// The RESULT, not just the date: `calendar_select_day_internal` (:1103-1104) returns
|
|
252
|
+
// EARLY when nothing changed, so the notify and the signal are gated on the three
|
|
253
|
+
// booleans it computes — and an element UPGRADED with attributes already on it runs
|
|
254
|
+
// through here for each of them, which is exactly that "nothing changed" case.
|
|
255
|
+
const result = this._adoptAttributes(name);
|
|
256
|
+
this._render();
|
|
257
|
+
if (name === 'date' || name === 'year' || name === 'month' || name === 'day') {
|
|
258
|
+
this._emitDaySelected(result);
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
/** `gtk_calendar_mark_day` (:1650-1666). */
|
|
263
|
+
markDay(day: number): void {
|
|
264
|
+
const next = calendarMarkDay(this._marked, day, true);
|
|
265
|
+
if (next === this._marked) return;
|
|
266
|
+
this._marked = next;
|
|
267
|
+
this._paintStates();
|
|
268
|
+
this.dispatchEvent(
|
|
269
|
+
new CustomEvent('notify::marked-days', { bubbles: true, detail: { markedDays: this.markedDays } }),
|
|
270
|
+
);
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
/** `gtk_calendar_unmark_day` (:1686-1704). */
|
|
274
|
+
unmarkDay(day: number): void {
|
|
275
|
+
const next = calendarMarkDay(this._marked, day, false);
|
|
276
|
+
if (next === this._marked) return;
|
|
277
|
+
this._marked = next;
|
|
278
|
+
this._paintStates();
|
|
279
|
+
this.dispatchEvent(
|
|
280
|
+
new CustomEvent('notify::marked-days', { bubbles: true, detail: { markedDays: this.markedDays } }),
|
|
281
|
+
);
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
/** `gtk_calendar_get_day_is_marked` (:1668-1682). */
|
|
285
|
+
dayIsMarked(day: number): boolean {
|
|
286
|
+
return calendarDayIsMarked(this._marked, day);
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
/** `gtk_calendar_clear_marks` (:1589-1613). */
|
|
290
|
+
clearMarks(): void {
|
|
291
|
+
this._marked = calendarClearMarks();
|
|
292
|
+
this._paintStates();
|
|
293
|
+
this.dispatchEvent(new CustomEvent('notify::marked-days', { bubbles: true, detail: { markedDays: [] } }));
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
/** The six rows of seven, as the C's `day[row][col]` pair. */
|
|
297
|
+
get cells(): readonly AdwCalendarCell[] {
|
|
298
|
+
return calendarDays(this._date.year, this._date.month, this.weekStart);
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
/** The date every write resolves against. */
|
|
302
|
+
get selectedDate(): AdwCalendarDate {
|
|
303
|
+
return { ...this._date };
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
private _buildHeader(): void {
|
|
307
|
+
this._headerEl = document.createElement('div');
|
|
308
|
+
this._headerEl.className = 'adw-calendar-header';
|
|
309
|
+
|
|
310
|
+
const names: Record<ArrowName, { icon: string; tooltip: string }> = {
|
|
311
|
+
previousMonth: { icon: ARROWS[0]!.icon, tooltip: ARROWS[0]!.tooltip },
|
|
312
|
+
nextMonth: { icon: ARROWS[1]!.icon, tooltip: ARROWS[1]!.tooltip },
|
|
313
|
+
previousYear: { icon: ARROWS[2]!.icon, tooltip: ARROWS[2]!.tooltip },
|
|
314
|
+
nextYear: { icon: ARROWS[3]!.icon, tooltip: ARROWS[3]!.tooltip },
|
|
315
|
+
};
|
|
316
|
+
|
|
317
|
+
const button = (name: ArrowName, expand: boolean, align: 'start' | 'center' | 'end') => {
|
|
318
|
+
const el = document.createElement('button');
|
|
319
|
+
el.type = 'button';
|
|
320
|
+
el.className = 'adw-calendar-nav-button flat';
|
|
321
|
+
el.title = names[name].tooltip;
|
|
322
|
+
el.setAttribute('aria-label', names[name].tooltip);
|
|
323
|
+
if (expand) el.classList.add('expand');
|
|
324
|
+
el.style.justifySelf = align;
|
|
325
|
+
el.addEventListener('click', () => this._onArrow(name));
|
|
326
|
+
el.appendChild(createGtkImage(names[name].icon, 'adw-calendar-nav-icon'));
|
|
327
|
+
this._arrowEls[name] = el;
|
|
328
|
+
return el;
|
|
329
|
+
};
|
|
330
|
+
|
|
331
|
+
this._monthEl = document.createElement('span');
|
|
332
|
+
this._monthEl.className = 'adw-calendar-month';
|
|
333
|
+
this._yearEl = document.createElement('span');
|
|
334
|
+
this._yearEl.className = 'adw-calendar-year';
|
|
335
|
+
|
|
336
|
+
// The C's order is prev-month, month-name, next-month, prev-year, year-label,
|
|
337
|
+
// next-year (gtkcalendar.c:618-622), and the middle month name EXPANDS.
|
|
338
|
+
this._headerEl.append(
|
|
339
|
+
button('previousMonth', false, 'start'),
|
|
340
|
+
this._monthEl,
|
|
341
|
+
button('nextMonth', true, 'start'),
|
|
342
|
+
button('previousYear', false, 'center'),
|
|
343
|
+
this._yearEl,
|
|
344
|
+
button('nextYear', false, 'end'),
|
|
345
|
+
);
|
|
346
|
+
// Only the month-name stack hexpands; the year label gets a fixed slot so changing the
|
|
347
|
+
// year does not change the calendar's width (gtkcalendar.c:854-858).
|
|
348
|
+
this._monthEl.style.flex = '1';
|
|
349
|
+
this._yearEl.style.paddingInline = '6px';
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
private _buildGrid(): void {
|
|
353
|
+
this._gridEl = document.createElement('div');
|
|
354
|
+
this._gridEl.className = 'adw-calendar-grid';
|
|
355
|
+
|
|
356
|
+
for (let index = 0; index < 7; index++) {
|
|
357
|
+
const label = document.createElement('span');
|
|
358
|
+
label.className = 'adw-calendar-day-name';
|
|
359
|
+
this._dayNameEls.push(label);
|
|
360
|
+
this._gridEl.appendChild(label);
|
|
361
|
+
}
|
|
362
|
+
// A leading spacer, so the week-number column exists even while the numbers are off:
|
|
363
|
+
// upstream the week numbers are grid column 0 whether or not they are VISIBLE
|
|
364
|
+
// (gtkcalendar.c:786-790), and the day numbers stay at `1 + i`.
|
|
365
|
+
const spacer = document.createElement('span');
|
|
366
|
+
spacer.className = 'adw-calendar-week-spacer';
|
|
367
|
+
spacer.setAttribute('aria-hidden', 'true');
|
|
368
|
+
this._gridEl.appendChild(spacer);
|
|
369
|
+
|
|
370
|
+
for (let index = 0; index < 6; index++) {
|
|
371
|
+
const week = document.createElement('span');
|
|
372
|
+
week.className = 'adw-calendar-week-number';
|
|
373
|
+
this._weekNumberEls.push(week);
|
|
374
|
+
this._gridEl.appendChild(week);
|
|
375
|
+
|
|
376
|
+
for (let column = 0; column < 7; column++) {
|
|
377
|
+
const cell = document.createElement('button');
|
|
378
|
+
cell.type = 'button';
|
|
379
|
+
cell.className = 'adw-calendar-cell day-number';
|
|
380
|
+
cell.addEventListener('click', () => this._onCellClick(Number(cell.dataset.index ?? '0')));
|
|
381
|
+
this._cellEls.push(cell);
|
|
382
|
+
this._gridEl.appendChild(cell);
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
/**
|
|
388
|
+
* Resolve the attributes into the one date they all name.
|
|
389
|
+
*
|
|
390
|
+
* THE ATTRIBUTE THAT CHANGED WINS, which is the C's own rule:
|
|
391
|
+
* `gtk_calendar_set_year` builds a new `GDateTime` from the same day in the new year and
|
|
392
|
+
* hands it to the same `calendar_select_day_internal` (gtkcalendar.c:860-880), so a write
|
|
393
|
+
* to a deprecated half AFTER a `date` write MOVES the date rather than being ignored for
|
|
394
|
+
* one being on the element. Reading `date` unconditionally would pin the element to its
|
|
395
|
+
* first write.
|
|
396
|
+
*
|
|
397
|
+
* At connect no attribute has "changed" and `date` wins, because it is the one the three
|
|
398
|
+
* halves are deprecated IN FAVOUR of. With none of them the answer is today, which is what
|
|
399
|
+
* `gtk_calendar_init` seeds (:849-851).
|
|
400
|
+
*/
|
|
401
|
+
private _adoptAttributes(changed?: string): AdwCalendarSelectResult {
|
|
402
|
+
const iso = this.getAttribute('date');
|
|
403
|
+
const half = changed === 'year' || changed === 'month' || changed === 'day';
|
|
404
|
+
if (iso !== null && !half) {
|
|
405
|
+
const parsed = parseIsoDate(iso);
|
|
406
|
+
if (parsed !== null) {
|
|
407
|
+
const result = calendarSelectDay(this._date, parsed, false);
|
|
408
|
+
this._date = result.date;
|
|
409
|
+
return result;
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
const target = {
|
|
413
|
+
// Each half is read only when present, so `year` alone keeps the current month and
|
|
414
|
+
// day — as `gtk_calendar_set_year` does.
|
|
415
|
+
year: integer(this.getAttribute('year'), this._date.year),
|
|
416
|
+
// The GIR property is 0-11 (gtkcalendar.c:419-429); the core functions are 1-12.
|
|
417
|
+
month: integer(this.getAttribute('month'), this._date.month - 1) + 1,
|
|
418
|
+
day: integer(this.getAttribute('day'), this._date.day),
|
|
419
|
+
};
|
|
420
|
+
const result = calendarSelectDay(this._date, target, false);
|
|
421
|
+
this._date = result.date;
|
|
422
|
+
return result;
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
/**
|
|
426
|
+
* Repaint everything the date decides: the heading, the 42 cells' text and classes, the six
|
|
427
|
+
* week numbers and the four arrows' sensitivity.
|
|
428
|
+
*
|
|
429
|
+
* The cells are NOT rebuilt — the same 42 buttons are reused and re-pointed, so a focus
|
|
430
|
+
* cell and its scroll position survive a month change, which is what `calendar_queue_refresh`
|
|
431
|
+
* gets from the widget layer upstream.
|
|
432
|
+
*/
|
|
433
|
+
private _render(): void {
|
|
434
|
+
this._monthEl.textContent = MONTH_NAMES[this._date.month - 1]!;
|
|
435
|
+
this._yearEl.textContent = String(this._date.year);
|
|
436
|
+
|
|
437
|
+
const cells = calendarDays(this._date.year, this._date.month, this.weekStart);
|
|
438
|
+
cells.forEach((cell, index) => {
|
|
439
|
+
const el = this._cellEls[index]!;
|
|
440
|
+
el.dataset.index = String(index);
|
|
441
|
+
el.textContent = String(cell.date.day);
|
|
442
|
+
el.setAttribute('aria-label', `${MONTH_NAMES[cell.date.month - 1]} ${cell.date.day}, ${cell.date.year}`);
|
|
443
|
+
el.classList.toggle('other-month', cell.month !== 'current');
|
|
444
|
+
});
|
|
445
|
+
|
|
446
|
+
this._paintWeekNumbers(cells);
|
|
447
|
+
this._paintStates();
|
|
448
|
+
this._paintArrows();
|
|
449
|
+
this._paintDayNames();
|
|
450
|
+
this._paintVisibility();
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
/**
|
|
454
|
+
* The six week numbers — `week_of_year` of the LAST cell of each row, which is the C's own
|
|
455
|
+
* rule (gtkcalendar.c:1143-1165): the row's week is the week its Sunday-through-Saturday
|
|
456
|
+
* run belongs to, and the row's last cell is its Saturday.
|
|
457
|
+
*/
|
|
458
|
+
private _paintWeekNumbers(cells: readonly AdwCalendarCell[]): void {
|
|
459
|
+
for (let row = 0; row < 6; row++) {
|
|
460
|
+
const last = cells[row * 7 + 6]!;
|
|
461
|
+
this._weekNumberEls[row]!.textContent = String(calendarWeekNumber(last.date));
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
/** The per-cell state flags `calendar_update_day_labels` raises (:979-1053). */
|
|
466
|
+
private _paintStates(): void {
|
|
467
|
+
const cells = calendarDays(this._date.year, this._date.month, this.weekStart);
|
|
468
|
+
const now = today();
|
|
469
|
+
const todayDay = now.year === this._date.year && now.month === this._date.month ? now.day : -1;
|
|
470
|
+
cells.forEach((cell, index) => {
|
|
471
|
+
const el = this._cellEls[index]!;
|
|
472
|
+
const isSelected = cell.month === 'current' && cell.date.day === this._date.day;
|
|
473
|
+
// `lower_limit_reached` / `upper_limit_reached` (:1002-1003) blank the cells that
|
|
474
|
+
// would leave the supported year range entirely.
|
|
475
|
+
const beyondRange =
|
|
476
|
+
(cell.month === 'previous' && this._date.year === CALENDAR_YEAR_MIN && this._date.month === 1) ||
|
|
477
|
+
(cell.month === 'next' && this._date.year === CALENDAR_YEAR_MAX && this._date.month === 12);
|
|
478
|
+
el.classList.toggle('selected', isSelected);
|
|
479
|
+
el.classList.toggle('marked', cell.month === 'current' && calendarDayIsMarked(this._marked, cell.date.day));
|
|
480
|
+
el.classList.toggle('today', cell.date.day === todayDay && cell.month === 'current');
|
|
481
|
+
el.classList.toggle('focused', index === this._focus);
|
|
482
|
+
el.disabled = beyondRange;
|
|
483
|
+
if (beyondRange) el.textContent = '';
|
|
484
|
+
else el.textContent = String(cell.date.day);
|
|
485
|
+
});
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
/** `calendar_update_navigation_buttons` (:1055-1084). */
|
|
489
|
+
private _paintArrows(): void {
|
|
490
|
+
const live = calendarNavigationButtons(this._date);
|
|
491
|
+
for (const name of ['previousMonth', 'nextMonth', 'previousYear', 'nextYear'] as const) {
|
|
492
|
+
this._arrowEls[name].disabled = !live[name];
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
private _paintDayNames(): void {
|
|
497
|
+
for (let index = 0; index < 7; index++) {
|
|
498
|
+
// `day = (i + calendar->week_start) % 7` (gtkcalendar.c:773).
|
|
499
|
+
this._dayNameEls[index]!.textContent = DAY_NAMES[(index + this.weekStart) % 7]!;
|
|
500
|
+
}
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
/**
|
|
504
|
+
* `show_heading`, `show_day_names` and `show_week_numbers` — the three visibility flags
|
|
505
|
+
* `gtk_calendar_init` and the setters flip (gtkcalendar.c:815-816, :1690-1700,
|
|
506
|
+
* :1756-1762). One of them hides the whole header BOX and the other two a row of labels,
|
|
507
|
+
* which is why they are one method rather than three writes.
|
|
508
|
+
*/
|
|
509
|
+
private _paintVisibility(): void {
|
|
510
|
+
this._headerEl.hidden = !this.showHeading;
|
|
511
|
+
for (const label of this._dayNameEls) label.hidden = !this.showDayNames;
|
|
512
|
+
for (const label of this._weekNumberEls) label.hidden = !this.showWeekNumbers;
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
private _onArrow(name: ArrowName): void {
|
|
516
|
+
const step = ARROWS.find((arrow) => arrowNameOf(arrow.step) === name)?.step;
|
|
517
|
+
if (step === undefined || this._arrowEls[name].disabled) return;
|
|
518
|
+
this._navigate(step);
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
/**
|
|
522
|
+
* `calendar_set_month_prev` and its three siblings: step the date, select it WITHOUT
|
|
523
|
+
* `emit_day_signal`, then emit the arrow's own signal (:868-919).
|
|
524
|
+
*/
|
|
525
|
+
private _navigate(step: AdwCalendarStep): void {
|
|
526
|
+
const before = this._date;
|
|
527
|
+
this._date = calendarSelectDay(before, calendarStep(before, step), false).date;
|
|
528
|
+
if (this._focus >= 0) {
|
|
529
|
+
const cells = this.cells;
|
|
530
|
+
const focus = cells[this._focus];
|
|
531
|
+
// The cursor follows the month when the day it was on is still in the grid, which
|
|
532
|
+
// upstream happens by the focus CELL surviving the repaint (gtkcalendar.c:1017-1020).
|
|
533
|
+
const moved = cells.findIndex((cell) => cell.month === focus?.month && cell.date.day === focus.date.day);
|
|
534
|
+
this._focus = moved >= 0 ? moved : -1;
|
|
535
|
+
}
|
|
536
|
+
this._render();
|
|
537
|
+
this.dispatchEvent(new CustomEvent('notify::date', { bubbles: true, detail: { date: this.date } }));
|
|
538
|
+
const signals: Record<AdwCalendarStep, string> = {
|
|
539
|
+
'previous-month': 'prev-month',
|
|
540
|
+
'next-month': 'next-month',
|
|
541
|
+
'previous-year': 'prev-year',
|
|
542
|
+
'next-year': 'next-year',
|
|
543
|
+
};
|
|
544
|
+
this.dispatchEvent(new CustomEvent(signals[step], { bubbles: true }));
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
/**
|
|
548
|
+
* The C's tail, line for line (:1169-1190): `::day-selected` and the `day` notify INSIDE
|
|
549
|
+
* `if (day_changed)`, the `month` and `year` notifies each inside its own, and `date`
|
|
550
|
+
* unconditionally — because the function that got here changed something.
|
|
551
|
+
*/
|
|
552
|
+
private _emitDaySelected(result: AdwCalendarSelectResult): void {
|
|
553
|
+
const notify = (attribute: string, value: number | string) =>
|
|
554
|
+
this.dispatchEvent(
|
|
555
|
+
new CustomEvent(`notify::${attribute}`, { bubbles: true, detail: { [attribute]: value } }),
|
|
556
|
+
);
|
|
557
|
+
if (result.dayChanged) {
|
|
558
|
+
this.dispatchEvent(new CustomEvent('day-selected', { bubbles: true }));
|
|
559
|
+
notify('day', this._date.day);
|
|
560
|
+
}
|
|
561
|
+
if (result.monthChanged) notify('month', this._date.month - 1);
|
|
562
|
+
if (result.yearChanged) notify('year', this._date.year);
|
|
563
|
+
notify('date', this.date);
|
|
564
|
+
}
|
|
565
|
+
|
|
566
|
+
/**
|
|
567
|
+
* A click on a cell — `calendar_select_and_focus_day` reached from
|
|
568
|
+
* `gtk_calendar_button_press` (:1311-1353).
|
|
569
|
+
*
|
|
570
|
+
* A cell from another month PAGES first: that is the `MONTH_PREV` / `MONTH_NEXT` branch of
|
|
571
|
+
* the Space handler (:1521-1534), and a click lands on the same cell either way.
|
|
572
|
+
*/
|
|
573
|
+
private _onCellClick(index: number): void {
|
|
574
|
+
const cell = this.cells[index];
|
|
575
|
+
if (cell === undefined) return;
|
|
576
|
+
this._focus = index;
|
|
577
|
+
if (cell.month === 'previous') this._navigate('previous-month');
|
|
578
|
+
else if (cell.month === 'next') this._navigate('next-month');
|
|
579
|
+
this._selectDate(cell.date, true);
|
|
580
|
+
}
|
|
581
|
+
|
|
582
|
+
/**
|
|
583
|
+
* `calendar_select_and_focus_day` (:1195-1213) — the date, WITH `::day-selected`, and the
|
|
584
|
+
* cursor on it.
|
|
585
|
+
*/
|
|
586
|
+
private _selectDate(date: AdwCalendarDate, interactive: boolean): void {
|
|
587
|
+
const result = calendarSelectDay(this._date, date, interactive);
|
|
588
|
+
if (!result.dayChanged && !result.monthChanged && !result.yearChanged) {
|
|
589
|
+
this._render();
|
|
590
|
+
return;
|
|
591
|
+
}
|
|
592
|
+
this._date = result.date;
|
|
593
|
+
const cell = this.cells.findIndex(
|
|
594
|
+
(candidate) => candidate.month === 'current' && candidate.date.day === this._date.day,
|
|
595
|
+
);
|
|
596
|
+
if (cell >= 0) this._focus = cell;
|
|
597
|
+
this._render();
|
|
598
|
+
this._emitDaySelected(result);
|
|
599
|
+
}
|
|
600
|
+
|
|
601
|
+
/**
|
|
602
|
+
* The key table: arrows move the cursor (`move_focus`, :1386-1452) and Space selects the
|
|
603
|
+
* cell it is on; `Ctrl` with any arrow is the MONTH and YEAR walk (:1454-1534).
|
|
604
|
+
*/
|
|
605
|
+
private _onKeyDown(event: KeyboardEvent): void {
|
|
606
|
+
const arrow: Record<string, [number, number]> = {
|
|
607
|
+
ArrowLeft: [-1, 0],
|
|
608
|
+
ArrowRight: [1, 0],
|
|
609
|
+
ArrowUp: [0, 1],
|
|
610
|
+
ArrowDown: [0, -1],
|
|
611
|
+
};
|
|
612
|
+
if (event.ctrlKey) {
|
|
613
|
+
const steps: Record<string, AdwCalendarStep> = {
|
|
614
|
+
ArrowLeft: 'previous-month',
|
|
615
|
+
ArrowRight: 'next-month',
|
|
616
|
+
ArrowUp: 'previous-year',
|
|
617
|
+
ArrowDown: 'next-year',
|
|
618
|
+
};
|
|
619
|
+
const step = steps[event.key];
|
|
620
|
+
if (step === undefined) return;
|
|
621
|
+
event.preventDefault();
|
|
622
|
+
// The C refuses the keyboard when the MOUSE would be refused (:1492-1494).
|
|
623
|
+
if (!calendarNavigationButtons(this._date)[arrowNameOf(step)]) return;
|
|
624
|
+
this._navigate(step);
|
|
625
|
+
return;
|
|
626
|
+
}
|
|
627
|
+
if (event.altKey || event.metaKey) return;
|
|
628
|
+
|
|
629
|
+
if (event.key === ' ') {
|
|
630
|
+
if (this._focus < 0) return;
|
|
631
|
+
event.preventDefault();
|
|
632
|
+
const cell = this.cells[this._focus];
|
|
633
|
+
if (cell === undefined) return;
|
|
634
|
+
if (cell.month === 'previous') this._navigate('previous-month');
|
|
635
|
+
else if (cell.month === 'next') this._navigate('next-month');
|
|
636
|
+
this._selectDate(cell.date, true);
|
|
637
|
+
return;
|
|
638
|
+
}
|
|
639
|
+
|
|
640
|
+
const move = arrow[event.key];
|
|
641
|
+
if (move === undefined) return;
|
|
642
|
+
event.preventDefault();
|
|
643
|
+
this._moveFocus(move[0], move[1]);
|
|
644
|
+
}
|
|
645
|
+
|
|
646
|
+
/**
|
|
647
|
+
* `move_focus` (:1386-1452) over the 6x7 grid, wrapping at the edges exactly as the C does
|
|
648
|
+
* (`focus_row < 0 → 5`, `focus_col < 0 → 6`).
|
|
649
|
+
*/
|
|
650
|
+
private _moveFocus(direction: number, updown: number): void {
|
|
651
|
+
const cells = this.cells;
|
|
652
|
+
if (cells.length === 0) return;
|
|
653
|
+
// `focus_row` / `focus_col` start at -1 (gtkcalendar.c:817-818), NOT at 0 — and the
|
|
654
|
+
// difference is the only place the wrap branches are reachable: an ArrowUp from an
|
|
655
|
+
// untouched cursor lands on row 5 column 6, the LAST cell, because of exactly those
|
|
656
|
+
// two `if (focus_row < 0) focus_row = 5` / `focus_col < 0 → 6` lines.
|
|
657
|
+
let row = this._focus < 0 ? -1 : Math.trunc(this._focus / 7);
|
|
658
|
+
let column = this._focus < 0 ? -1 : this._focus % 7;
|
|
659
|
+
|
|
660
|
+
if (updown === 1) {
|
|
661
|
+
if (row > 0) row--;
|
|
662
|
+
if (row < 0) row = 5;
|
|
663
|
+
if (column < 0) column = 6;
|
|
664
|
+
} else if (updown === -1) {
|
|
665
|
+
if (row < 5) row++;
|
|
666
|
+
if (column < 0) column = 0;
|
|
667
|
+
} else if (direction === -1) {
|
|
668
|
+
if (column > 0) column--;
|
|
669
|
+
else if (row > 0) {
|
|
670
|
+
column = 6;
|
|
671
|
+
row--;
|
|
672
|
+
}
|
|
673
|
+
if (column < 0) column = 6;
|
|
674
|
+
if (row < 0) row = 5;
|
|
675
|
+
} else {
|
|
676
|
+
if (column < 6) column++;
|
|
677
|
+
else if (row < 5) {
|
|
678
|
+
column = 0;
|
|
679
|
+
row++;
|
|
680
|
+
}
|
|
681
|
+
if (column < 0) column = 0;
|
|
682
|
+
if (row < 0) row = 0;
|
|
683
|
+
}
|
|
684
|
+
|
|
685
|
+
const next = row * 7 + column;
|
|
686
|
+
// "Not sensitive, not reachable" (:1444-1445) — a cell past the year range is skipped.
|
|
687
|
+
if (this._cellEls[next]?.disabled === true) return;
|
|
688
|
+
this._focus = next;
|
|
689
|
+
this._paintStates();
|
|
690
|
+
this._cellEls[next]?.focus();
|
|
691
|
+
}
|
|
692
|
+
}
|
|
693
|
+
|
|
694
|
+
/** Which of the four arrows a step names — the order `gtk_calendar_init` appends them in (:618-622). */
|
|
695
|
+
function arrowNameOf(step: AdwCalendarStep): ArrowName {
|
|
696
|
+
switch (step) {
|
|
697
|
+
case 'previous-month':
|
|
698
|
+
return 'previousMonth';
|
|
699
|
+
case 'next-month':
|
|
700
|
+
return 'nextMonth';
|
|
701
|
+
case 'previous-year':
|
|
702
|
+
return 'previousYear';
|
|
703
|
+
default:
|
|
704
|
+
return 'nextYear';
|
|
705
|
+
}
|
|
706
|
+
}
|
|
707
|
+
|
|
708
|
+
/**
|
|
709
|
+
* The locale's first day of the week — `calendar->week_start`, from `Intl`.
|
|
710
|
+
*
|
|
711
|
+
* `Intl.Locale.prototype.getWeekInfo()` reports `firstDay` as 1 (Monday) through 7 (Sunday),
|
|
712
|
+
* which is exactly the numbering `_NL_TIME_FIRST_WEEKDAY` uses, so `calendarWeekStart`'s own
|
|
713
|
+
* formula applies to it unchanged — there is no second arithmetic here on purpose. A runtime
|
|
714
|
+
* without `getWeekInfo` answers 0 (Sunday), which is what the C's fallback lands on too
|
|
715
|
+
* (gtkcalendar.c:716-718).
|
|
716
|
+
*/
|
|
717
|
+
function localeWeekStart(): number {
|
|
718
|
+
const language = globalThis.navigator?.language;
|
|
719
|
+
if (typeof language !== 'string') return calendarWeekStart(0, 0);
|
|
720
|
+
const Locale = (Intl as { Locale?: { new (tag: string): { getWeekInfo?: () => { firstDay: number } } } }).Locale;
|
|
721
|
+
if (Locale === undefined) return calendarWeekStart(0, 0);
|
|
722
|
+
const weekInfo = new Locale(language).getWeekInfo?.();
|
|
723
|
+
if (weekInfo === undefined) return calendarWeekStart(0, 0);
|
|
724
|
+
// `firstDay` is 1-7 Monday-to-Sunday; `_NL_TIME_FIRST_WEEKDAY` is 0-6 Sunday-first, and
|
|
725
|
+
// `7 % 7` is the Sunday the two numberings disagree about.
|
|
726
|
+
return calendarWeekStart(weekInfo.firstDay % 7, weekInfo.firstDay === 7 ? 0 : 1);
|
|
727
|
+
}
|
|
728
|
+
|
|
729
|
+
/** Today's date in the local zone — `g_date_time_new_now_local` (:851). */
|
|
730
|
+
function today(): AdwCalendarDate {
|
|
731
|
+
const now = new Date();
|
|
732
|
+
return { year: now.getFullYear(), month: now.getMonth() + 1, day: now.getDate() };
|
|
733
|
+
}
|
|
734
|
+
|
|
735
|
+
function toIsoDate(date: AdwCalendarDate): string {
|
|
736
|
+
return `${String(date.year).padStart(4, '0')}-${String(date.month).padStart(2, '0')}-${String(date.day).padStart(2, '0')}`;
|
|
737
|
+
}
|
|
738
|
+
|
|
739
|
+
/** `YYYY-MM-DD` → a date, or null. A malformed attribute leaves the widget where it was. */
|
|
740
|
+
function parseIsoDate(raw: string): AdwCalendarDate | null {
|
|
741
|
+
const match = /^(-?\d{1,6})-(\d{1,2})-(\d{1,2})$/.exec(raw.trim());
|
|
742
|
+
if (match === null) return null;
|
|
743
|
+
const year = Number(match[1]);
|
|
744
|
+
const month = Number(match[2]);
|
|
745
|
+
const day = Number(match[3]);
|
|
746
|
+
if (month < 1 || month > 12 || day < 1 || day > 31) return null;
|
|
747
|
+
if (year < CALENDAR_YEAR_MIN || year > CALENDAR_YEAR_MAX) return null;
|
|
748
|
+
return { year, month, day };
|
|
749
|
+
}
|
|
750
|
+
|
|
751
|
+
/** A `gint` property read, with the caller's own value standing in for an absent attribute. */
|
|
752
|
+
function integer(raw: string | null, fallback: number): number {
|
|
753
|
+
const parsed = Number.parseInt(raw ?? '', 10);
|
|
754
|
+
return Number.isFinite(parsed) ? parsed : fallback;
|
|
755
|
+
}
|
|
756
|
+
|
|
757
|
+
customElements.define('gtk-calendar', GtkCalendar);
|