@webjsdev/ui 0.3.16 → 0.4.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 +71 -10
- package/THIRD_PARTY_NOTICES.md +349 -0
- package/package.json +4 -2
- package/packages/registry/blocks/_shared/placeholder.svg +1 -0
- package/packages/registry/blocks/charts/chart-area-axes.ts +72 -0
- package/packages/registry/blocks/charts/chart-area-default.ts +64 -0
- package/packages/registry/blocks/charts/chart-area-gradient.ts +82 -0
- package/packages/registry/blocks/charts/chart-area-icons.ts +77 -0
- package/packages/registry/blocks/charts/chart-area-interactive.ts +204 -0
- package/packages/registry/blocks/charts/chart-area-legend.ts +72 -0
- package/packages/registry/blocks/charts/chart-area-linear.ts +64 -0
- package/packages/registry/blocks/charts/chart-area-stacked-expand.ts +77 -0
- package/packages/registry/blocks/charts/chart-area-stacked.ts +71 -0
- package/packages/registry/blocks/charts/chart-area-step.ts +68 -0
- package/packages/registry/blocks/charts/chart-bar-active.ts +93 -0
- package/packages/registry/blocks/charts/chart-bar-default.ts +60 -0
- package/packages/registry/blocks/charts/chart-bar-horizontal.ts +62 -0
- package/packages/registry/blocks/charts/chart-bar-interactive.ts +185 -0
- package/packages/registry/blocks/charts/chart-bar-label-custom.ts +78 -0
- package/packages/registry/blocks/charts/chart-bar-label.ts +66 -0
- package/packages/registry/blocks/charts/chart-bar-mixed.ts +87 -0
- package/packages/registry/blocks/charts/chart-bar-multiple.ts +67 -0
- package/packages/registry/blocks/charts/chart-bar-negative.ts +61 -0
- package/packages/registry/blocks/charts/chart-bar-stacked.ts +68 -0
- package/packages/registry/blocks/charts/chart-line-default.ts +61 -0
- package/packages/registry/blocks/charts/chart-line-dots-colors.ts +86 -0
- package/packages/registry/blocks/charts/chart-line-dots-custom.ts +75 -0
- package/packages/registry/blocks/charts/chart-line-dots.ts +65 -0
- package/packages/registry/blocks/charts/chart-line-interactive.ts +185 -0
- package/packages/registry/blocks/charts/chart-line-label-custom.ts +94 -0
- package/packages/registry/blocks/charts/chart-line-label.ts +73 -0
- package/packages/registry/blocks/charts/chart-line-linear.ts +61 -0
- package/packages/registry/blocks/charts/chart-line-multiple.ts +71 -0
- package/packages/registry/blocks/charts/chart-line-step.ts +61 -0
- package/packages/registry/blocks/charts/chart-pie-donut-active.ts +86 -0
- package/packages/registry/blocks/charts/chart-pie-donut-text.ts +89 -0
- package/packages/registry/blocks/charts/chart-pie-donut.ts +77 -0
- package/packages/registry/blocks/charts/chart-pie-interactive.ts +120 -0
- package/packages/registry/blocks/charts/chart-pie-label-custom.ts +82 -0
- package/packages/registry/blocks/charts/chart-pie-label-list.ts +86 -0
- package/packages/registry/blocks/charts/chart-pie-label.ts +77 -0
- package/packages/registry/blocks/charts/chart-pie-legend.ts +79 -0
- package/packages/registry/blocks/charts/chart-pie-separator-none.ts +77 -0
- package/packages/registry/blocks/charts/chart-pie-simple.ts +77 -0
- package/packages/registry/blocks/charts/chart-pie-stacked.ts +99 -0
- package/packages/registry/blocks/charts/chart-radar-default.ts +61 -0
- package/packages/registry/blocks/charts/chart-radar-dots.ts +61 -0
- package/packages/registry/blocks/charts/chart-radar-grid-circle-fill.ts +61 -0
- package/packages/registry/blocks/charts/chart-radar-grid-circle-no-lines.ts +61 -0
- package/packages/registry/blocks/charts/chart-radar-grid-circle.ts +61 -0
- package/packages/registry/blocks/charts/chart-radar-grid-custom.ts +61 -0
- package/packages/registry/blocks/charts/chart-radar-grid-fill.ts +61 -0
- package/packages/registry/blocks/charts/chart-radar-grid-none.ts +60 -0
- package/packages/registry/blocks/charts/chart-radar-icons.ts +76 -0
- package/packages/registry/blocks/charts/chart-radar-label-custom.ts +77 -0
- package/packages/registry/blocks/charts/chart-radar-legend.ts +70 -0
- package/packages/registry/blocks/charts/chart-radar-lines-only.ts +68 -0
- package/packages/registry/blocks/charts/chart-radar-multiple.ts +68 -0
- package/packages/registry/blocks/charts/chart-radar-radius.ts +68 -0
- package/packages/registry/blocks/charts/chart-radial-grid.ts +80 -0
- package/packages/registry/blocks/charts/chart-radial-label.ts +85 -0
- package/packages/registry/blocks/charts/chart-radial-shape.ts +81 -0
- package/packages/registry/blocks/charts/chart-radial-simple.ts +79 -0
- package/packages/registry/blocks/charts/chart-radial-stacked.ts +69 -0
- package/packages/registry/blocks/charts/chart-radial-text.ts +82 -0
- package/packages/registry/blocks/charts/chart-tooltip-advanced.ts +84 -0
- package/packages/registry/blocks/charts/chart-tooltip-default.ts +62 -0
- package/packages/registry/blocks/charts/chart-tooltip-formatter.ts +75 -0
- package/packages/registry/blocks/charts/chart-tooltip-icons.ts +68 -0
- package/packages/registry/blocks/charts/chart-tooltip-indicator-line.ts +62 -0
- package/packages/registry/blocks/charts/chart-tooltip-indicator-none.ts +62 -0
- package/packages/registry/blocks/charts/chart-tooltip-label-custom.ts +65 -0
- package/packages/registry/blocks/charts/chart-tooltip-label-formatter.ts +66 -0
- package/packages/registry/blocks/charts/chart-tooltip-label-none.ts +62 -0
- package/packages/registry/blocks/dashboard-01/components/app-sidebar.ts +108 -0
- package/packages/registry/blocks/dashboard-01/components/chart-area-interactive.ts +276 -0
- package/packages/registry/blocks/dashboard-01/components/dashboard-data.ts +89 -0
- package/packages/registry/blocks/dashboard-01/components/data-table.ts +637 -0
- package/packages/registry/blocks/dashboard-01/components/nav-documents.ts +65 -0
- package/packages/registry/blocks/dashboard-01/components/nav-main.ts +61 -0
- package/packages/registry/blocks/dashboard-01/components/nav-secondary.ts +40 -0
- package/packages/registry/blocks/dashboard-01/components/nav-user.ts +66 -0
- package/packages/registry/blocks/dashboard-01/components/section-cards.ts +59 -0
- package/packages/registry/blocks/dashboard-01/components/site-header.ts +52 -0
- package/packages/registry/blocks/dashboard-01/page.ts +39 -0
- package/packages/registry/blocks/login-01/components/login-form.ts +70 -0
- package/packages/registry/blocks/login-01/page.ts +19 -0
- package/packages/registry/blocks/login-02/components/login-form.ts +68 -0
- package/packages/registry/blocks/login-02/page.ts +36 -0
- package/packages/registry/blocks/login-03/components/login-form.ts +89 -0
- package/packages/registry/blocks/login-03/page.ts +28 -0
- package/packages/registry/blocks/login-04/components/login-form.ts +91 -0
- package/packages/registry/blocks/login-04/page.ts +20 -0
- package/packages/registry/blocks/login-05/components/login-form.ts +75 -0
- package/packages/registry/blocks/login-05/page.ts +19 -0
- package/packages/registry/blocks/preview/cards/activate-agent-dialog.ts +77 -0
- package/packages/registry/blocks/preview/cards/analytics-card.ts +64 -0
- package/packages/registry/blocks/preview/cards/anomaly-alert.ts +35 -0
- package/packages/registry/blocks/preview/cards/bar-chart-card.ts +91 -0
- package/packages/registry/blocks/preview/cards/book-appointment.ts +51 -0
- package/packages/registry/blocks/preview/cards/codespaces-card.ts +172 -0
- package/packages/registry/blocks/preview/cards/contributions-activity.ts +63 -0
- package/packages/registry/blocks/preview/cards/contributors.ts +51 -0
- package/packages/registry/blocks/preview/cards/environment-variables.ts +47 -0
- package/packages/registry/blocks/preview/cards/feedback-form.ts +61 -0
- package/packages/registry/blocks/preview/cards/file-upload.ts +51 -0
- package/packages/registry/blocks/preview/cards/github-profile.ts +66 -0
- package/packages/registry/blocks/preview/cards/icon-preview-grid.ts +47 -0
- package/packages/registry/blocks/preview/cards/invite-team.ts +78 -0
- package/packages/registry/blocks/preview/cards/invoice.ts +91 -0
- package/packages/registry/blocks/preview/cards/live-waveform.ts +330 -0
- package/packages/registry/blocks/preview/cards/no-team-members.ts +61 -0
- package/packages/registry/blocks/preview/cards/not-found.ts +46 -0
- package/packages/registry/blocks/preview/cards/observability-card.ts +44 -0
- package/packages/registry/blocks/preview/cards/pie-chart-card.ts +84 -0
- package/packages/registry/blocks/preview/cards/report-bug.ts +71 -0
- package/packages/registry/blocks/preview/cards/shipping-address.ts +79 -0
- package/packages/registry/blocks/preview/cards/shortcuts.ts +57 -0
- package/packages/registry/blocks/preview/cards/skeleton-loading.ts +37 -0
- package/packages/registry/blocks/preview/cards/sleep-report.ts +85 -0
- package/packages/registry/blocks/preview/cards/style-overview.ts +64 -0
- package/packages/registry/blocks/preview/cards/typography-specimen.ts +107 -0
- package/packages/registry/blocks/preview/cards/ui-elements.ts +164 -0
- package/packages/registry/blocks/preview/cards/usage-card.ts +63 -0
- package/packages/registry/blocks/preview/cards/visitors.ts +71 -0
- package/packages/registry/blocks/preview/cards/weekly-fitness-summary.ts +54 -0
- package/packages/registry/blocks/preview/page.ts +103 -0
- package/packages/registry/blocks/preview-02/cards/account-access.ts +70 -0
- package/packages/registry/blocks/preview-02/cards/card-overview.ts +75 -0
- package/packages/registry/blocks/preview-02/cards/claimable-balance.ts +54 -0
- package/packages/registry/blocks/preview-02/cards/contribution-history.ts +80 -0
- package/packages/registry/blocks/preview-02/cards/cover-art.ts +41 -0
- package/packages/registry/blocks/preview-02/cards/dividend-income.ts +76 -0
- package/packages/registry/blocks/preview-02/cards/empty-connect-bank.ts +38 -0
- package/packages/registry/blocks/preview-02/cards/empty-distribute-track.ts +38 -0
- package/packages/registry/blocks/preview-02/cards/empty-explore-catalog.ts +39 -0
- package/packages/registry/blocks/preview-02/cards/faq.ts +79 -0
- package/packages/registry/blocks/preview-02/cards/front-door.ts +40 -0
- package/packages/registry/blocks/preview-02/cards/index-investing.ts +31 -0
- package/packages/registry/blocks/preview-02/cards/kitchen-island.ts +90 -0
- package/packages/registry/blocks/preview-02/cards/loading-card.ts +34 -0
- package/packages/registry/blocks/preview-02/cards/new-milestone.ts +53 -0
- package/packages/registry/blocks/preview-02/cards/notification-settings.ts +126 -0
- package/packages/registry/blocks/preview-02/cards/payments.ts +88 -0
- package/packages/registry/blocks/preview-02/cards/payout-threshold.ts +92 -0
- package/packages/registry/blocks/preview-02/cards/power-usage.ts +84 -0
- package/packages/registry/blocks/preview-02/cards/preferences.ts +89 -0
- package/packages/registry/blocks/preview-02/cards/qr-connect.ts +54 -0
- package/packages/registry/blocks/preview-02/cards/receiving-method.ts +89 -0
- package/packages/registry/blocks/preview-02/cards/recent-transactions.ts +101 -0
- package/packages/registry/blocks/preview-02/cards/release-catalog.ts +73 -0
- package/packages/registry/blocks/preview-02/cards/roller-shades.ts +110 -0
- package/packages/registry/blocks/preview-02/cards/savings-progress.ts +68 -0
- package/packages/registry/blocks/preview-02/cards/savings-targets.ts +132 -0
- package/packages/registry/blocks/preview-02/cards/sidebar-nav.ts +88 -0
- package/packages/registry/blocks/preview-02/cards/social-links.ts +57 -0
- package/packages/registry/blocks/preview-02/cards/stock-performance.ts +106 -0
- package/packages/registry/blocks/preview-02/cards/syncing-state.ts +37 -0
- package/packages/registry/blocks/preview-02/cards/transfer-funds.ts +111 -0
- package/packages/registry/blocks/preview-02/cards/upcoming-payments.ts +69 -0
- package/packages/registry/blocks/preview-02/page.ts +111 -0
- package/packages/registry/blocks/preview-03/cards/files-chat.ts +75 -0
- package/packages/registry/blocks/preview-03/cards/group-chat.ts +114 -0
- package/packages/registry/blocks/preview-03/cards/reasoning-chat.ts +88 -0
- package/packages/registry/blocks/preview-03/cards/simple-chat.ts +53 -0
- package/packages/registry/blocks/preview-03/components/chat-card.ts +126 -0
- package/packages/registry/blocks/preview-03/components/chat-player.ts +174 -0
- package/packages/registry/blocks/preview-03/components/part-file.ts +77 -0
- package/packages/registry/blocks/preview-03/components/part-reasoning.ts +25 -0
- package/packages/registry/blocks/preview-03/components/part-source.ts +48 -0
- package/packages/registry/blocks/preview-03/components/part-text.ts +69 -0
- package/packages/registry/blocks/preview-03/components/part-tool.ts +71 -0
- package/packages/registry/blocks/preview-03/components/prompt-input.ts +86 -0
- package/packages/registry/blocks/preview-03/page.ts +39 -0
- package/packages/registry/blocks/sidebar-01/components/app-sidebar.ts +113 -0
- package/packages/registry/blocks/sidebar-01/components/search-form.ts +33 -0
- package/packages/registry/blocks/sidebar-01/components/version-switcher.ts +50 -0
- package/packages/registry/blocks/sidebar-01/page.ts +58 -0
- package/packages/registry/blocks/sidebar-02/components/app-sidebar.ts +131 -0
- package/packages/registry/blocks/sidebar-02/components/search-form.ts +33 -0
- package/packages/registry/blocks/sidebar-02/components/version-switcher.ts +50 -0
- package/packages/registry/blocks/sidebar-02/page.ts +53 -0
- package/packages/registry/blocks/sidebar-03/components/app-sidebar.ts +134 -0
- package/packages/registry/blocks/sidebar-03/page.ts +60 -0
- package/packages/registry/blocks/sidebar-04/components/app-sidebar.ts +136 -0
- package/packages/registry/blocks/sidebar-04/page.ts +58 -0
- package/packages/registry/blocks/sidebar-05/components/app-sidebar.ts +147 -0
- package/packages/registry/blocks/sidebar-05/components/search-form.ts +33 -0
- package/packages/registry/blocks/sidebar-05/page.ts +58 -0
- package/packages/registry/blocks/sidebar-06/components/app-sidebar.ts +105 -0
- package/packages/registry/blocks/sidebar-06/components/nav-main.ts +56 -0
- package/packages/registry/blocks/sidebar-06/components/sidebar-opt-in-form.ts +44 -0
- package/packages/registry/blocks/sidebar-06/page.ts +57 -0
- package/packages/registry/blocks/sidebar-07/components/app-sidebar.ts +108 -0
- package/packages/registry/blocks/sidebar-07/components/nav-main.ts +61 -0
- package/packages/registry/blocks/sidebar-07/components/nav-projects.ts +65 -0
- package/packages/registry/blocks/sidebar-07/components/nav-user.ts +70 -0
- package/packages/registry/blocks/sidebar-07/components/team-switcher.ts +66 -0
- package/packages/registry/blocks/sidebar-07/page.ts +59 -0
- package/packages/registry/blocks/sidebar-08/components/app-sidebar.ts +122 -0
- package/packages/registry/blocks/sidebar-08/components/nav-main.ts +68 -0
- package/packages/registry/blocks/sidebar-08/components/nav-projects.ts +65 -0
- package/packages/registry/blocks/sidebar-08/components/nav-secondary.ts +40 -0
- package/packages/registry/blocks/sidebar-08/components/nav-user.ts +70 -0
- package/packages/registry/blocks/sidebar-08/page.ts +59 -0
- package/packages/registry/blocks/sidebar-09/components/app-sidebar.ts +213 -0
- package/packages/registry/blocks/sidebar-09/components/nav-user.ts +70 -0
- package/packages/registry/blocks/sidebar-09/page.ts +52 -0
- package/packages/registry/blocks/sidebar-10/components/app-sidebar.ts +125 -0
- package/packages/registry/blocks/sidebar-10/components/nav-actions.ts +84 -0
- package/packages/registry/blocks/sidebar-10/components/nav-favorites.ts +66 -0
- package/packages/registry/blocks/sidebar-10/components/nav-main.ts +37 -0
- package/packages/registry/blocks/sidebar-10/components/nav-secondary.ts +43 -0
- package/packages/registry/blocks/sidebar-10/components/nav-workspaces.ts +78 -0
- package/packages/registry/blocks/sidebar-10/components/team-switcher.ts +63 -0
- package/packages/registry/blocks/sidebar-10/page.ts +46 -0
- package/packages/registry/blocks/sidebar-11/components/app-sidebar.ts +114 -0
- package/packages/registry/blocks/sidebar-11/page.ts +63 -0
- package/packages/registry/blocks/sidebar-12/components/app-sidebar.ts +63 -0
- package/packages/registry/blocks/sidebar-12/components/calendars.ts +53 -0
- package/packages/registry/blocks/sidebar-12/components/date-picker.ts +26 -0
- package/packages/registry/blocks/sidebar-12/components/nav-user.ts +70 -0
- package/packages/registry/blocks/sidebar-12/page.ts +43 -0
- package/packages/registry/blocks/sidebar-13/components/settings-dialog.ts +114 -0
- package/packages/registry/blocks/sidebar-13/page.ts +21 -0
- package/packages/registry/blocks/sidebar-14/components/app-sidebar.ts +120 -0
- package/packages/registry/blocks/sidebar-14/page.ts +55 -0
- package/packages/registry/blocks/sidebar-15/components/calendars.ts +53 -0
- package/packages/registry/blocks/sidebar-15/components/date-picker.ts +26 -0
- package/packages/registry/blocks/sidebar-15/components/nav-favorites.ts +66 -0
- package/packages/registry/blocks/sidebar-15/components/nav-main.ts +35 -0
- package/packages/registry/blocks/sidebar-15/components/nav-secondary.ts +43 -0
- package/packages/registry/blocks/sidebar-15/components/nav-user.ts +70 -0
- package/packages/registry/blocks/sidebar-15/components/nav-workspaces.ts +75 -0
- package/packages/registry/blocks/sidebar-15/components/sidebar-left.ts +126 -0
- package/packages/registry/blocks/sidebar-15/components/sidebar-right.ts +62 -0
- package/packages/registry/blocks/sidebar-15/components/team-switcher.ts +63 -0
- package/packages/registry/blocks/sidebar-15/page.ts +47 -0
- package/packages/registry/blocks/sidebar-16/components/app-sidebar.ts +124 -0
- package/packages/registry/blocks/sidebar-16/components/nav-main.ts +67 -0
- package/packages/registry/blocks/sidebar-16/components/nav-projects.ts +65 -0
- package/packages/registry/blocks/sidebar-16/components/nav-secondary.ts +40 -0
- package/packages/registry/blocks/sidebar-16/components/nav-user.ts +70 -0
- package/packages/registry/blocks/sidebar-16/components/search-form.ts +27 -0
- package/packages/registry/blocks/sidebar-16/components/site-header.ts +42 -0
- package/packages/registry/blocks/sidebar-16/page.ts +38 -0
- package/packages/registry/blocks/signup-01/components/signup-form.ts +78 -0
- package/packages/registry/blocks/signup-01/page.ts +19 -0
- package/packages/registry/blocks/signup-02/components/signup-form.ts +78 -0
- package/packages/registry/blocks/signup-02/page.ts +36 -0
- package/packages/registry/blocks/signup-03/components/signup-form.ts +79 -0
- package/packages/registry/blocks/signup-03/page.ts +28 -0
- package/packages/registry/blocks/signup-04/components/signup-form.ts +100 -0
- package/packages/registry/blocks/signup-04/page.ts +20 -0
- package/packages/registry/blocks/signup-05/components/signup-form.ts +75 -0
- package/packages/registry/blocks/signup-05/page.ts +20 -0
- package/packages/registry/components/accordion.ts +20 -7
- package/packages/registry/components/alert-dialog.ts +58 -13
- package/packages/registry/components/alert.ts +11 -6
- package/packages/registry/components/attachment.ts +119 -0
- package/packages/registry/components/avatar.ts +17 -8
- package/packages/registry/components/badge.ts +16 -9
- package/packages/registry/components/breadcrumb.ts +6 -6
- package/packages/registry/components/bubble.ts +95 -0
- package/packages/registry/components/button-group.ts +73 -0
- package/packages/registry/components/button.ts +35 -25
- package/packages/registry/components/calendar.ts +566 -0
- package/packages/registry/components/card.ts +8 -8
- package/packages/registry/components/carousel.ts +352 -0
- package/packages/registry/components/chart-element.ts +547 -0
- package/packages/registry/components/chart-geometry.ts +457 -0
- package/packages/registry/components/chart.ts +932 -0
- package/packages/registry/components/checkbox.ts +22 -84
- package/packages/registry/components/code-block.ts +191 -0
- package/packages/registry/components/collapsible.ts +5 -2
- package/packages/registry/components/combobox.ts +802 -0
- package/packages/registry/components/command.ts +618 -0
- package/packages/registry/components/context-menu.ts +302 -0
- package/packages/registry/components/dialog.ts +156 -45
- package/packages/registry/components/direction.ts +43 -0
- package/packages/registry/components/drawer.ts +226 -0
- package/packages/registry/components/dropdown-menu.ts +262 -83
- package/packages/registry/components/empty.ts +88 -0
- package/packages/registry/components/field.ts +165 -0
- package/packages/registry/components/floating.ts +124 -0
- package/packages/registry/components/hover-card.ts +19 -8
- package/packages/registry/components/input-group.ts +118 -0
- package/packages/registry/components/input-otp.ts +365 -0
- package/packages/registry/components/input.ts +3 -3
- package/packages/registry/components/item.ts +134 -0
- package/packages/registry/components/kbd.ts +2 -2
- package/packages/registry/components/label.ts +1 -1
- package/packages/registry/components/marker.ts +63 -0
- package/packages/registry/components/menubar.ts +388 -0
- package/packages/registry/components/message-scroller.ts +470 -0
- package/packages/registry/components/message.ts +69 -0
- package/packages/registry/components/native-select.ts +5 -5
- package/packages/registry/components/navigation-menu.ts +564 -0
- package/packages/registry/components/pagination.ts +5 -5
- package/packages/registry/components/popover.ts +30 -84
- package/packages/registry/components/progress.ts +7 -3
- package/packages/registry/components/questionnaire.ts +840 -0
- package/packages/registry/components/radio-group.ts +18 -73
- package/packages/registry/components/resizable.ts +330 -0
- package/packages/registry/components/scroll-area.ts +46 -0
- package/packages/registry/components/select.ts +650 -0
- package/packages/registry/components/separator.ts +1 -1
- package/packages/registry/components/sheet.ts +128 -0
- package/packages/registry/components/sidebar.ts +457 -0
- package/packages/registry/components/skeleton.ts +1 -1
- package/packages/registry/components/slider.ts +333 -0
- package/packages/registry/components/sonner.ts +74 -7
- package/packages/registry/components/spinner.ts +66 -0
- package/packages/registry/components/switch.ts +117 -9
- package/packages/registry/components/table.ts +11 -9
- package/packages/registry/components/tabs.ts +76 -25
- package/packages/registry/components/textarea.ts +1 -1
- package/packages/registry/components/toggle-group.ts +30 -11
- package/packages/registry/components/toggle.ts +20 -13
- package/packages/registry/components/tooltip.ts +68 -7
- package/packages/registry/components/trace.ts +75 -0
- package/packages/registry/lib/icons-hugeicons.ts +955 -0
- package/packages/registry/lib/icons-phosphor.ts +955 -0
- package/packages/registry/lib/icons-remixicon.ts +955 -0
- package/packages/registry/lib/icons-tabler.ts +955 -0
- package/packages/registry/lib/icons.ts +768 -0
- package/packages/registry/lib/utils.ts +49 -4
- package/packages/registry/registry.json +4092 -60
- package/packages/registry/styles/shadcn-tailwind.css +654 -0
- package/packages/registry/styles/style-luma.css +1987 -0
- package/packages/registry/styles/style-lyra.css +1965 -0
- package/packages/registry/styles/style-maia.css +1987 -0
- package/packages/registry/styles/style-mira.css +1992 -0
- package/packages/registry/styles/style-new-york.css +1597 -0
- package/packages/registry/styles/style-nova.css +1990 -0
- package/packages/registry/styles/style-rhea.css +1987 -0
- package/packages/registry/styles/style-sera.css +1977 -0
- package/packages/registry/styles/style-vega.css +1990 -0
- package/packages/registry/styles/supplement.json +54 -0
- package/packages/registry/styles/tw-animate.css +6 -0
- package/packages/registry/themes/base-colors.js +8 -2
- package/packages/registry/themes/fonts.js +120 -0
- package/packages/registry/themes/index.css +2 -0
- package/packages/registry/themes/items.js +61 -0
- package/packages/registry/themes/preset.js +302 -0
- package/packages/registry/themes/themes.js +1193 -0
- package/src/commands/add.js +236 -12
- package/src/commands/diff.js +34 -20
- package/src/commands/info.js +7 -0
- package/src/commands/init.js +125 -8
- package/src/commands/list.js +43 -11
- package/src/commands/view.js +33 -5
- package/src/registry/extract.js +192 -2
- package/src/registry/icons.js +31 -0
- package/src/registry/local.js +15 -1
- package/src/registry/schema.js +13 -0
- package/src/registry/style-bake.js +506 -0
- package/src/utils/theme.js +110 -21
|
@@ -31,37 +31,38 @@
|
|
|
31
31
|
*/
|
|
32
32
|
import { cn } from '../lib/utils.ts';
|
|
33
33
|
|
|
34
|
-
//
|
|
35
|
-
//
|
|
36
|
-
//
|
|
37
|
-
//
|
|
38
|
-
//
|
|
39
|
-
//
|
|
40
|
-
//
|
|
41
|
-
//
|
|
34
|
+
// Base form (#1666): the semantic `cn-button*` names carry the look, and
|
|
35
|
+
// the style named in components.json supplies it when the file is installed
|
|
36
|
+
// (styles/style-<name>.css, baked by `add`). What stays inline is the layout
|
|
37
|
+
// shadcn's base form keeps inline in every style.
|
|
38
|
+
//
|
|
39
|
+
// The default new-york style puts cursor-pointer on `cn-button`, so every
|
|
40
|
+
// variant gets the right hover affordance. Native <button> defaults to the OS
|
|
41
|
+
// arrow cursor in Chromium and Firefox, and shadcn's modern Button has
|
|
42
|
+
// gravitated toward an explicit cursor-pointer in the real world (see the open
|
|
43
|
+
// issue shadcn-ui/ui#1791). disabled:pointer-events-none below already
|
|
44
|
+
// suppresses the cursor on a disabled button.
|
|
42
45
|
const BASE =
|
|
43
|
-
|
|
46
|
+
'cn-button group/button inline-flex shrink-0 items-center justify-center whitespace-nowrap transition-all outline-none select-none disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0';
|
|
44
47
|
|
|
45
48
|
const VARIANTS = {
|
|
46
|
-
default: '
|
|
47
|
-
destructive:
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
ghost: 'hover:bg-accent hover:text-accent-foreground dark:hover:bg-accent/50',
|
|
53
|
-
link: 'text-primary underline-offset-4 hover:underline',
|
|
49
|
+
default: 'cn-button-variant-default',
|
|
50
|
+
destructive: 'cn-button-variant-destructive',
|
|
51
|
+
outline: 'cn-button-variant-outline',
|
|
52
|
+
secondary: 'cn-button-variant-secondary',
|
|
53
|
+
ghost: 'cn-button-variant-ghost',
|
|
54
|
+
link: 'cn-button-variant-link',
|
|
54
55
|
} as const;
|
|
55
56
|
|
|
56
57
|
const SIZES = {
|
|
57
|
-
default: '
|
|
58
|
-
xs:
|
|
59
|
-
sm: '
|
|
60
|
-
lg: '
|
|
61
|
-
icon: 'size-
|
|
62
|
-
'icon-xs':
|
|
63
|
-
'icon-sm': 'size-
|
|
64
|
-
'icon-lg': 'size-
|
|
58
|
+
default: 'cn-button-size-default',
|
|
59
|
+
xs: 'cn-button-size-xs',
|
|
60
|
+
sm: 'cn-button-size-sm',
|
|
61
|
+
lg: 'cn-button-size-lg',
|
|
62
|
+
icon: 'cn-button-size-icon',
|
|
63
|
+
'icon-xs': 'cn-button-size-icon-xs',
|
|
64
|
+
'icon-sm': 'cn-button-size-icon-sm',
|
|
65
|
+
'icon-lg': 'cn-button-size-icon-lg',
|
|
65
66
|
} as const;
|
|
66
67
|
|
|
67
68
|
export type ButtonVariant = keyof typeof VARIANTS;
|
|
@@ -78,3 +79,12 @@ export function buttonClass(opts: ButtonClassOptions = {}): string {
|
|
|
78
79
|
const size = opts.size ?? 'default';
|
|
79
80
|
return cn(BASE, VARIANTS[variant], SIZES[size]);
|
|
80
81
|
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* shadcn's name for {@link buttonClass}, so shadcn code ports verbatim
|
|
85
|
+
* (`buttonVariants({ ... })` is shadcn's `cva` export for `Button`). Like cva, it
|
|
86
|
+
* merges a `className` into the result.
|
|
87
|
+
*/
|
|
88
|
+
export function buttonVariants(opts: ButtonClassOptions & { className?: string } = {}): string {
|
|
89
|
+
return cn(buttonClass(opts), opts.className);
|
|
90
|
+
}
|
|
@@ -0,0 +1,566 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Calendar: a month grid for picking a date, several dates, or a range.
|
|
3
|
+
* Tier-2. shadcn's is react-day-picker; this is the same grid hand-rolled on
|
|
4
|
+
* `Intl.DateTimeFormat`, with no dependency. The server renders the month, so
|
|
5
|
+
* the grid is in the first paint; picking needs JavaScript.
|
|
6
|
+
*
|
|
7
|
+
* shadcn parity:
|
|
8
|
+
* Calendar mode="single" | "multiple" | "range"
|
|
9
|
+
* → <ui-calendar mode value>
|
|
10
|
+
* selected → `value`: "2025-06-12"; for multiple a comma list;
|
|
11
|
+
* for range "2025-06-12/2025-06-20"
|
|
12
|
+
* month / defaultMonth → `month`: "2025-06" (the first month shown)
|
|
13
|
+
* numberOfMonths → `number-of-months`
|
|
14
|
+
* showOutsideDays → `show-outside-days="false"` hides them (shown by default)
|
|
15
|
+
* weekStartsOn → `week-starts-on` (0 is Sunday, the default)
|
|
16
|
+
* showWeekNumber → `show-week-number` (a leading column of week numbers)
|
|
17
|
+
* ISOWeek → `iso-week` (ISO 8601 weeks: Monday first, ISO numbers)
|
|
18
|
+
* captionLayout="dropdown" → `caption-layout="dropdown"` (month and year selects)
|
|
19
|
+
* disabled / startMonth / endMonth
|
|
20
|
+
* → `min` / `max` ("2025-01-01"), and `disabled` for the whole grid
|
|
21
|
+
* locale → `locale` (a BCP 47 tag), else the page's `lang`
|
|
22
|
+
* onSelect → `ui-value-change` ({ detail: { value } }): a date string, a
|
|
23
|
+
* string array, or { from, to } for a range
|
|
24
|
+
* onMonthChange → `ui-month-change` ({ detail: { month } })
|
|
25
|
+
*
|
|
26
|
+
* With `name`, the value also rides hidden inputs, so a form submits it: one
|
|
27
|
+
* input for a single date, one per date for multiple, and `name[from]` /
|
|
28
|
+
* `name[to]` for a range.
|
|
29
|
+
*
|
|
30
|
+
* Keyboard (the WAI-ARIA date grid): one day is in the tab order. The arrows
|
|
31
|
+
* move a day or a week (left and right swap under `dir="rtl"`), Home / End go
|
|
32
|
+
* to the week's ends, PageUp / PageDown change the month and with Shift the
|
|
33
|
+
* year, and Enter or Space picks. Moving past the shown months turns the page.
|
|
34
|
+
*
|
|
35
|
+
* A11y (handled by the element): each month is a `role="grid"` labelled by its
|
|
36
|
+
* caption, every day button is named by its full date (and says "Today" and
|
|
37
|
+
* "selected"), days outside `min` / `max` are disabled, and the previous and
|
|
38
|
+
* next buttons are named.
|
|
39
|
+
*
|
|
40
|
+
* @example
|
|
41
|
+
* ```html
|
|
42
|
+
* <ui-calendar mode="single" value="2025-06-12" class="rounded-lg border"></ui-calendar>
|
|
43
|
+
*
|
|
44
|
+
* <ui-calendar mode="range" value="2025-06-12/2025-06-20" number-of-months="2" name="stay"></ui-calendar>
|
|
45
|
+
* ```
|
|
46
|
+
*/
|
|
47
|
+
import { WebComponent, html, prop, signal, nothing } from '@webjsdev/core';
|
|
48
|
+
import { cn } from '../lib/utils.ts';
|
|
49
|
+
import { buttonClass } from './button.ts';
|
|
50
|
+
|
|
51
|
+
// --------------------------------------------------------------------------
|
|
52
|
+
// Date maths, all on UTC calendar dates written as YYYY-MM-DD, so a timezone
|
|
53
|
+
// can never move a day.
|
|
54
|
+
// --------------------------------------------------------------------------
|
|
55
|
+
|
|
56
|
+
/** A date-only value: the calendar's unit. */
|
|
57
|
+
export type CalendarDate = { y: number; m: number; d: number };
|
|
58
|
+
|
|
59
|
+
/** Parse "YYYY-MM-DD" (or "YYYY-MM", day 1); null when it is not a date. */
|
|
60
|
+
export function parseDate(s: string | null | undefined): CalendarDate | null {
|
|
61
|
+
const m = /^(\d{4})-(\d{2})(?:-(\d{2}))?$/.exec((s ?? '').trim());
|
|
62
|
+
if (!m) return null;
|
|
63
|
+
const y = Number(m[1]);
|
|
64
|
+
const mo = Number(m[2]) - 1;
|
|
65
|
+
const d = m[3] ? Number(m[3]) : 1;
|
|
66
|
+
const t = new Date(Date.UTC(y, mo, d));
|
|
67
|
+
if (t.getUTCFullYear() !== y || t.getUTCMonth() !== mo || t.getUTCDate() !== d) return null;
|
|
68
|
+
return { y, m: mo, d };
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/** Format as "YYYY-MM-DD". */
|
|
72
|
+
export function formatDate(c: CalendarDate): string {
|
|
73
|
+
return `${String(c.y).padStart(4, '0')}-${String(c.m + 1).padStart(2, '0')}-${String(c.d).padStart(2, '0')}`;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function toUTC(c: CalendarDate): Date {
|
|
77
|
+
return new Date(Date.UTC(c.y, c.m, c.d));
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function fromUTC(t: Date): CalendarDate {
|
|
81
|
+
return { y: t.getUTCFullYear(), m: t.getUTCMonth(), d: t.getUTCDate() };
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/** `c` moved by `days`. */
|
|
85
|
+
export function addDays(c: CalendarDate, days: number): CalendarDate {
|
|
86
|
+
const t = toUTC(c);
|
|
87
|
+
t.setUTCDate(t.getUTCDate() + days);
|
|
88
|
+
return fromUTC(t);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/** `c` moved by `months`, clamped to the last day of the target month. */
|
|
92
|
+
export function addMonths(c: CalendarDate, months: number): CalendarDate {
|
|
93
|
+
const first = new Date(Date.UTC(c.y, c.m + months, 1));
|
|
94
|
+
const last = new Date(Date.UTC(first.getUTCFullYear(), first.getUTCMonth() + 1, 0)).getUTCDate();
|
|
95
|
+
return { y: first.getUTCFullYear(), m: first.getUTCMonth(), d: Math.min(c.d, last) };
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/** -1, 0 or 1. */
|
|
99
|
+
export function compareDates(a: CalendarDate, b: CalendarDate): number {
|
|
100
|
+
return a.y - b.y || a.m - b.m || a.d - b.d;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/** Whether `a` and `b` are the same day. */
|
|
104
|
+
export function sameDay(a: CalendarDate | null, b: CalendarDate | null): boolean {
|
|
105
|
+
return !!a && !!b && compareDates(a, b) === 0;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* The weeks of a month as rows of seven days, starting on `weekStartsOn`
|
|
110
|
+
* (0 Sunday). Days of the neighbouring months fill the first and last rows;
|
|
111
|
+
* there are only as many rows as the month needs.
|
|
112
|
+
*/
|
|
113
|
+
export function monthWeeks(y: number, m: number, weekStartsOn = 0): CalendarDate[][] {
|
|
114
|
+
const first = { y, m, d: 1 };
|
|
115
|
+
const lead = (toUTC(first).getUTCDay() - weekStartsOn + 7) % 7;
|
|
116
|
+
const daysIn = new Date(Date.UTC(y, m + 1, 0)).getUTCDate();
|
|
117
|
+
const total = Math.ceil((lead + daysIn) / 7) * 7;
|
|
118
|
+
const start = addDays(first, -lead);
|
|
119
|
+
const weeks: CalendarDate[][] = [];
|
|
120
|
+
for (let i = 0; i < total; i += 7) {
|
|
121
|
+
weeks.push(Array.from({ length: 7 }, (_, j) => addDays(start, i + j)));
|
|
122
|
+
}
|
|
123
|
+
return weeks;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* The number of the week `date` falls in, as the calendar labels a row, the
|
|
128
|
+
* way react-day-picker numbers it. By default week 1 is the week holding
|
|
129
|
+
* January 1, with weeks counted from `weekStartsOn` (date-fns getWeek, with
|
|
130
|
+
* the en-US first week). With `iso` the week is ISO 8601's: weeks start on
|
|
131
|
+
* Monday and week 1 holds the year's first Thursday (date-fns getISOWeek),
|
|
132
|
+
* whatever `weekStartsOn` says.
|
|
133
|
+
*/
|
|
134
|
+
export function weekNumber(date: CalendarDate, weekStartsOn = 0, iso = false): number {
|
|
135
|
+
const DAY = 86400000;
|
|
136
|
+
const start = iso ? 1 : weekStartsOn;
|
|
137
|
+
// The day of January that week 1 must contain.
|
|
138
|
+
const anchor = iso ? 4 : 1;
|
|
139
|
+
const startOfWeek = (ms: number): number => ms - ((new Date(ms).getUTCDay() - start + 7) % 7) * DAY;
|
|
140
|
+
const at = Date.UTC(date.y, date.m, date.d);
|
|
141
|
+
const firstOf = (y: number): number => startOfWeek(Date.UTC(y, 0, anchor));
|
|
142
|
+
const year = at >= firstOf(date.y + 1) ? date.y + 1 : at >= firstOf(date.y) ? date.y : date.y - 1;
|
|
143
|
+
return Math.round((startOfWeek(at) - firstOf(year)) / (7 * DAY)) + 1;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/** A range in progress or complete. */
|
|
147
|
+
export type CalendarRange = { from: CalendarDate | null; to: CalendarDate | null };
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* The range after picking `day`: the first pick starts it, the second ends
|
|
151
|
+
* it (swapping if it lies before the start), and a pick on a complete range
|
|
152
|
+
* starts a new one.
|
|
153
|
+
*/
|
|
154
|
+
export function addToRange(range: CalendarRange, day: CalendarDate): CalendarRange {
|
|
155
|
+
const { from, to } = range;
|
|
156
|
+
if (!from || (from && to)) return { from: day, to: null };
|
|
157
|
+
if (compareDates(day, from) < 0) return { from: day, to: from };
|
|
158
|
+
return { from, to: day };
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// --------------------------------------------------------------------------
|
|
162
|
+
// Classes
|
|
163
|
+
// --------------------------------------------------------------------------
|
|
164
|
+
|
|
165
|
+
/** The root's classes (the element applies them). */
|
|
166
|
+
export function calendarClass(): string {
|
|
167
|
+
return 'cn-calendar group/calendar bg-background in-data-[slot=card-content]:bg-transparent in-data-[slot=popover-content]:bg-transparent rtl:**:[.rdp-button-next>svg]:rotate-180 rtl:**:[.rdp-button-previous>svg]:rotate-180';
|
|
168
|
+
}
|
|
169
|
+
/** A month caption's label. */
|
|
170
|
+
export const calendarCaptionClass = (): string => 'cn-calendar-caption text-sm';
|
|
171
|
+
// shadcn names the dropdown caption's box and label `cn-calendar-dropdown-root`
|
|
172
|
+
// and `cn-calendar-caption-label`, but its build bakes only the first name of
|
|
173
|
+
// each component file, so `shadcn add` leaves both unstyled in every style and
|
|
174
|
+
// ui.shadcn.com draws neither a border nor a padded label. The kit gives them
|
|
175
|
+
// names only new-york maps, which keeps new-york's bordered dropdowns and
|
|
176
|
+
// matches shadcn's output in the other styles.
|
|
177
|
+
/** A dropdown caption's visible label. */
|
|
178
|
+
export const calendarCaptionLabelClass = (): string =>
|
|
179
|
+
'cn-calendar-dropdown-label flex items-center gap-1 rounded-(--cell-radius) text-sm [&>svg]:size-3.5 [&>svg]:text-muted-foreground';
|
|
180
|
+
/** A caption dropdown's box. */
|
|
181
|
+
export const calendarDropdownRootClass = (): string => 'cn-calendar-dropdown-box relative rounded-(--cell-radius)';
|
|
182
|
+
/** A day button's classes (the element applies them). */
|
|
183
|
+
export const calendarDayButtonClass = (): string =>
|
|
184
|
+
'cn-calendar-day-button relative isolate z-10 flex aspect-square size-auto w-full min-w-(--cell-size) flex-col gap-1 border-0 leading-none font-normal group-data-[focused=true]/day:relative group-data-[focused=true]/day:z-10 group-data-[focused=true]/day:border-ring group-data-[focused=true]/day:ring-[3px] group-data-[focused=true]/day:ring-ring/50 data-[range-end=true]:rounded-(--cell-radius) data-[range-end=true]:rounded-e-(--cell-radius) data-[range-end=true]:bg-primary data-[range-end=true]:text-primary-foreground data-[range-middle=true]:rounded-none data-[range-middle=true]:bg-muted data-[range-middle=true]:text-foreground data-[range-start=true]:rounded-(--cell-radius) data-[range-start=true]:rounded-s-(--cell-radius) data-[range-start=true]:bg-primary data-[range-start=true]:text-primary-foreground data-[selected-single=true]:bg-primary data-[selected-single=true]:text-primary-foreground dark:hover:text-foreground [&>span]:text-xs [&>span]:opacity-70';
|
|
185
|
+
|
|
186
|
+
const NAV_BUTTON = 'size-(--cell-size) p-0 select-none aria-disabled:opacity-50';
|
|
187
|
+
|
|
188
|
+
// --------------------------------------------------------------------------
|
|
189
|
+
// <ui-calendar>
|
|
190
|
+
// --------------------------------------------------------------------------
|
|
191
|
+
|
|
192
|
+
let uid = 0;
|
|
193
|
+
|
|
194
|
+
export class UiCalendar extends WebComponent({
|
|
195
|
+
mode: prop<'single' | 'multiple' | 'range'>(String),
|
|
196
|
+
value: String,
|
|
197
|
+
name: String,
|
|
198
|
+
month: String,
|
|
199
|
+
numberOfMonths: prop(Number, { attribute: 'number-of-months' }),
|
|
200
|
+
showOutsideDays: prop(String, { attribute: 'show-outside-days' }),
|
|
201
|
+
weekStartsOn: prop(Number, { attribute: 'week-starts-on' }),
|
|
202
|
+
showWeekNumber: prop(Boolean, { attribute: 'show-week-number' }),
|
|
203
|
+
isoWeek: prop(Boolean, { attribute: 'iso-week' }),
|
|
204
|
+
captionLayout: prop<'label' | 'dropdown'>(String, { attribute: 'caption-layout' }),
|
|
205
|
+
min: String,
|
|
206
|
+
max: String,
|
|
207
|
+
disabled: Boolean,
|
|
208
|
+
locale: String,
|
|
209
|
+
}) {
|
|
210
|
+
// The live state: what is chosen, which month is shown, which day has focus.
|
|
211
|
+
readonly #selection = signal<{ days: string[]; from: string; to: string }>({ days: [], from: '', to: '' });
|
|
212
|
+
readonly #shown = signal('');
|
|
213
|
+
readonly #focused = signal('');
|
|
214
|
+
_id = '';
|
|
215
|
+
_parsed = false;
|
|
216
|
+
|
|
217
|
+
constructor() {
|
|
218
|
+
super();
|
|
219
|
+
this.mode = 'single';
|
|
220
|
+
this.value = '';
|
|
221
|
+
this.name = '';
|
|
222
|
+
this.month = '';
|
|
223
|
+
this.numberOfMonths = 1;
|
|
224
|
+
this.showOutsideDays = 'true';
|
|
225
|
+
this.weekStartsOn = 0;
|
|
226
|
+
this.showWeekNumber = false;
|
|
227
|
+
this.isoWeek = false;
|
|
228
|
+
this.captionLayout = 'label';
|
|
229
|
+
this.min = '';
|
|
230
|
+
this.max = '';
|
|
231
|
+
this.disabled = false;
|
|
232
|
+
this.locale = '';
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
connectedCallback(): void {
|
|
236
|
+
super.connectedCallback?.();
|
|
237
|
+
this._id ||= `ui-calendar-${++uid}`;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
// Read the attributes into state once, on the first render (server or client).
|
|
241
|
+
willUpdate(changedProperties: Map<string, unknown>): void {
|
|
242
|
+
super.willUpdate?.(changedProperties);
|
|
243
|
+
if (this._parsed) return;
|
|
244
|
+
this._parsed = true;
|
|
245
|
+
const v = this.value ?? '';
|
|
246
|
+
if (this.mode === 'range') {
|
|
247
|
+
const [a, b] = v.split('/');
|
|
248
|
+
const from = parseDate(a);
|
|
249
|
+
const to = parseDate(b);
|
|
250
|
+
this.#selection.set({ days: [], from: from ? formatDate(from) : '', to: to ? formatDate(to) : '' });
|
|
251
|
+
} else {
|
|
252
|
+
const days = (this.mode === 'multiple' ? v.split(',') : [v]).map(parseDate).filter((d): d is CalendarDate => !!d).map(formatDate);
|
|
253
|
+
this.#selection.set({ days, from: '', to: '' });
|
|
254
|
+
}
|
|
255
|
+
const picked = this.#selection.get();
|
|
256
|
+
const anchor = parseDate(this.month) ?? parseDate(picked.from || picked.days[0]) ?? this._today();
|
|
257
|
+
this.#shown.set(formatDate({ y: anchor.y, m: anchor.m, d: 1 }));
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
_today(): CalendarDate {
|
|
261
|
+
const n = new Date();
|
|
262
|
+
return { y: n.getFullYear(), m: n.getMonth(), d: n.getDate() };
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
_locale(): string {
|
|
266
|
+
if (this.locale) return this.locale;
|
|
267
|
+
const lang = typeof document !== 'undefined' ? document.documentElement?.lang : '';
|
|
268
|
+
return lang || 'en-US';
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
_fmt(opts: Intl.DateTimeFormatOptions): Intl.DateTimeFormat {
|
|
272
|
+
return new Intl.DateTimeFormat(this._locale(), { ...opts, timeZone: 'UTC' });
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
_min(): CalendarDate | null {
|
|
276
|
+
return parseDate(this.min);
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
_max(): CalendarDate | null {
|
|
280
|
+
return parseDate(this.max);
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
_isDisabled(day: CalendarDate): boolean {
|
|
284
|
+
if (this.disabled) return true;
|
|
285
|
+
const lo = this._min();
|
|
286
|
+
const hi = this._max();
|
|
287
|
+
return (!!lo && compareDates(day, lo) < 0) || (!!hi && compareDates(day, hi) > 0);
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
_first(): CalendarDate {
|
|
291
|
+
return parseDate(this.#shown.get()) ?? this._today();
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
/** The value in the shape `ui-value-change` reports. */
|
|
295
|
+
get selected(): string | string[] | { from: string; to: string } {
|
|
296
|
+
const s = this.#selection.get();
|
|
297
|
+
if (this.mode === 'range') return { from: s.from, to: s.to };
|
|
298
|
+
if (this.mode === 'multiple') return [...s.days];
|
|
299
|
+
return s.days[0] ?? '';
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
/** Pick `iso`, as a click or Enter does. */
|
|
303
|
+
pick(iso: string): void {
|
|
304
|
+
const day = parseDate(iso);
|
|
305
|
+
if (!day || this._isDisabled(day)) return;
|
|
306
|
+
const s = this.#selection.get();
|
|
307
|
+
if (this.mode === 'range') {
|
|
308
|
+
const next = addToRange({ from: parseDate(s.from), to: parseDate(s.to) }, day);
|
|
309
|
+
this.#selection.set({ days: [], from: next.from ? formatDate(next.from) : '', to: next.to ? formatDate(next.to) : '' });
|
|
310
|
+
} else if (this.mode === 'multiple') {
|
|
311
|
+
const days = s.days.includes(iso) ? s.days.filter((d) => d !== iso) : [...s.days, iso].sort();
|
|
312
|
+
this.#selection.set({ days, from: '', to: '' });
|
|
313
|
+
} else {
|
|
314
|
+
this.#selection.set({ days: s.days[0] === iso ? [] : [iso], from: '', to: '' });
|
|
315
|
+
}
|
|
316
|
+
this.#focused.set(iso);
|
|
317
|
+
this.dispatchEvent(new CustomEvent('ui-value-change', { bubbles: true, detail: { value: this.selected } }));
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
/** Show the month containing `iso` first. */
|
|
321
|
+
goToMonth(iso: string): void {
|
|
322
|
+
const day = parseDate(iso);
|
|
323
|
+
if (!day) return;
|
|
324
|
+
const next = formatDate({ y: day.y, m: day.m, d: 1 });
|
|
325
|
+
if (next === this.#shown.get()) return;
|
|
326
|
+
this.#shown.set(next);
|
|
327
|
+
this.dispatchEvent(new CustomEvent('ui-month-change', { bubbles: true, detail: { month: next.slice(0, 7) } }));
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
_canGo(by: number): boolean {
|
|
331
|
+
const first = this._first();
|
|
332
|
+
const lo = this._min();
|
|
333
|
+
const hi = this._max();
|
|
334
|
+
if (by < 0 && lo) return compareDates(addMonths(first, -1), { y: lo.y, m: lo.m, d: 1 }) >= 0;
|
|
335
|
+
if (by > 0 && hi) {
|
|
336
|
+
const lastShown = addMonths(first, (this.numberOfMonths || 1) - 1);
|
|
337
|
+
return compareDates(addMonths(lastShown, 1), { y: hi.y, m: hi.m, d: 1 }) <= 0;
|
|
338
|
+
}
|
|
339
|
+
return true;
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
_turn(by: number): void {
|
|
343
|
+
if (!this._canGo(by)) return;
|
|
344
|
+
this.goToMonth(formatDate(addMonths(this._first(), by)));
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
// The state a day is drawn in.
|
|
348
|
+
_dayState(day: CalendarDate): { selected: boolean; single: boolean; start: boolean; end: boolean; middle: boolean } {
|
|
349
|
+
const s = this.#selection.get();
|
|
350
|
+
const iso = formatDate(day);
|
|
351
|
+
if (this.mode === 'range') {
|
|
352
|
+
const from = parseDate(s.from);
|
|
353
|
+
const to = parseDate(s.to);
|
|
354
|
+
const start = sameDay(day, from);
|
|
355
|
+
const end = sameDay(day, to);
|
|
356
|
+
const middle = !!from && !!to && compareDates(day, from) > 0 && compareDates(day, to) < 0;
|
|
357
|
+
// A range of one day (or one not yet ended) draws its start as a single pick.
|
|
358
|
+
const lone = start && (!to || sameDay(from, to));
|
|
359
|
+
return { selected: start || end || middle, single: lone, start: start && !lone, end: end && !lone, middle };
|
|
360
|
+
}
|
|
361
|
+
const on = s.days.includes(iso);
|
|
362
|
+
return { selected: on, single: on, start: false, end: false, middle: false };
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
// The day that owns the tab stop: the focused one, else the first chosen
|
|
366
|
+
// day shown, else today if shown, else the first day of the first month.
|
|
367
|
+
_tabDay(months: CalendarDate[]): string {
|
|
368
|
+
const inShown = (iso: string) => {
|
|
369
|
+
const d = parseDate(iso);
|
|
370
|
+
return !!d && months.some((m) => m.y === d.y && m.m === d.m);
|
|
371
|
+
};
|
|
372
|
+
const focused = this.#focused.get();
|
|
373
|
+
if (focused && inShown(focused)) return focused;
|
|
374
|
+
const s = this.#selection.get();
|
|
375
|
+
const chosen = [s.from, ...s.days].find((d) => d && inShown(d));
|
|
376
|
+
if (chosen) return chosen;
|
|
377
|
+
const today = formatDate(this._today());
|
|
378
|
+
if (inShown(today)) return today;
|
|
379
|
+
return formatDate(months[0]);
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
render() {
|
|
383
|
+
const months = Array.from({ length: Math.max(1, this.numberOfMonths || 1) }, (_, i) => addMonths(this._first(), i));
|
|
384
|
+
const tab = this._tabDay(months);
|
|
385
|
+
const today = formatDate(this._today());
|
|
386
|
+
const outside = this.showOutsideDays !== 'false';
|
|
387
|
+
const weekday = this._fmt({ weekday: 'short' });
|
|
388
|
+
const weekdayLong = this._fmt({ weekday: 'long' });
|
|
389
|
+
const caption = this._fmt({ month: 'long', year: 'numeric' });
|
|
390
|
+
const full = this._fmt({ weekday: 'long', year: 'numeric', month: 'long', day: 'numeric' });
|
|
391
|
+
const en = this._locale().toLowerCase().startsWith('en');
|
|
392
|
+
const headerDays = monthWeeks(2024, 0, this._weekStart())[1];
|
|
393
|
+
const dropdown = this.captionLayout === 'dropdown';
|
|
394
|
+
const weeks = !!this.showWeekNumber;
|
|
395
|
+
const hidden = this.name ? this._hiddenInputs() : '';
|
|
396
|
+
return html`<div
|
|
397
|
+
data-slot="calendar"
|
|
398
|
+
class=${cn('w-fit', calendarClass())}
|
|
399
|
+
@keydown=${this._onKeyDown}
|
|
400
|
+
><div class="relative flex flex-col gap-4 md:flex-row"><nav aria-label="Navigation" class="absolute inset-x-0 top-0 flex w-full items-center justify-between gap-1"><button
|
|
401
|
+
type="button"
|
|
402
|
+
aria-label="Go to the Previous Month"
|
|
403
|
+
aria-disabled=${this._canGo(-1) ? nothing : 'true'}
|
|
404
|
+
class=${cn(buttonClass({ variant: 'ghost' }), NAV_BUTTON, 'rdp-button-previous')}
|
|
405
|
+
@click=${() => this._turn(-1)}
|
|
406
|
+
><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" class="cn-rtl-flip size-4 rtl:rotate-180"><path d="m15 18-6-6 6-6"></path></svg></button><button
|
|
407
|
+
type="button"
|
|
408
|
+
aria-label="Go to the Next Month"
|
|
409
|
+
aria-disabled=${this._canGo(1) ? nothing : 'true'}
|
|
410
|
+
class=${cn(buttonClass({ variant: 'ghost' }), NAV_BUTTON, 'rdp-button-next')}
|
|
411
|
+
@click=${() => this._turn(1)}
|
|
412
|
+
><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" class="cn-rtl-flip size-4 rtl:rotate-180"><path d="m9 18 6-6-6-6"></path></svg></button></nav>${months.map((mo, mi) => {
|
|
413
|
+
// No id before connect (the server never connects an element): a served
|
|
414
|
+
// `-caption-0` would be shared by every calendar on the page.
|
|
415
|
+
const captionId = this._id ? `${this._id}-caption-${mi}` : nothing;
|
|
416
|
+
return html`<div class="flex w-full flex-col gap-4"><div class="flex h-(--cell-size) w-full items-center justify-center px-(--cell-size)">${dropdown && mi === 0
|
|
417
|
+
? this._dropdowns(mo, captionId)
|
|
418
|
+
: html`<span id=${captionId} role="status" aria-live="polite" class=${cn('font-medium select-none', calendarCaptionClass())}>${caption.format(toUTC(mo))}</span>`}</div><table
|
|
419
|
+
role="grid"
|
|
420
|
+
aria-labelledby=${captionId}
|
|
421
|
+
aria-multiselectable=${this.mode === 'single' ? nothing : 'true'}
|
|
422
|
+
class="w-full border-collapse"
|
|
423
|
+
><thead aria-hidden="true"><tr class="flex">${weeks
|
|
424
|
+
? html`<th scope="col" aria-label="Week Number" class="w-(--cell-size) select-none"></th>`
|
|
425
|
+
: ''}${headerDays.map((d) => {
|
|
426
|
+
const short = weekday.format(toUTC(d));
|
|
427
|
+
return html`<th scope="col" aria-label=${weekdayLong.format(toUTC(d))} class="flex-1 rounded-(--cell-radius) text-[0.8rem] font-normal text-muted-foreground select-none">${en ? short.slice(0, 2) : short}</th>`;
|
|
428
|
+
})}</tr></thead><tbody>${monthWeeks(mo.y, mo.m, this._weekStart()).map((week) => html`<tr class="mt-2 flex w-full">${weeks
|
|
429
|
+
? this._weekNumberCell(week)
|
|
430
|
+
: ''}${week.map((day) => {
|
|
431
|
+
const iso = formatDate(day);
|
|
432
|
+
const isOutside = day.m !== mo.m;
|
|
433
|
+
if (isOutside && !outside) {
|
|
434
|
+
return html`<td role="gridcell" class="group/day relative aspect-square h-full w-full p-0 invisible"></td>`;
|
|
435
|
+
}
|
|
436
|
+
const st = this._dayState(day);
|
|
437
|
+
const off = this._isDisabled(day);
|
|
438
|
+
const isToday = iso === today;
|
|
439
|
+
const label = `${isToday ? 'Today, ' : ''}${full.format(toUTC(day))}${st.selected ? ', selected' : ''}`;
|
|
440
|
+
return html`<td
|
|
441
|
+
role="gridcell"
|
|
442
|
+
data-day=${iso}
|
|
443
|
+
aria-selected=${st.selected ? 'true' : nothing}
|
|
444
|
+
data-selected=${st.selected ? 'true' : nothing}
|
|
445
|
+
data-today=${isToday ? 'true' : nothing}
|
|
446
|
+
data-outside=${isOutside ? 'true' : nothing}
|
|
447
|
+
data-disabled=${off ? 'true' : nothing}
|
|
448
|
+
data-focused=${this.#focused.get() === iso ? 'true' : nothing}
|
|
449
|
+
class=${cn(
|
|
450
|
+
'group/day relative aspect-square h-full w-full rounded-(--cell-radius) p-0 text-center select-none [&:last-child[data-selected=true]_button]:rounded-e-(--cell-radius) [&:first-child[data-selected=true]_button]:rounded-s-(--cell-radius)',
|
|
451
|
+
// A week-number column makes the row's first day its second cell,
|
|
452
|
+
// which takes the first day's corner instead.
|
|
453
|
+
weeks ? '[&:nth-child(2)[data-selected=true]_button]:rounded-s-(--cell-radius)' : '',
|
|
454
|
+
st.start ? 'relative isolate z-0 rounded-s-(--cell-radius) bg-muted after:absolute after:inset-y-0 after:end-0 after:w-4 after:bg-muted' : '',
|
|
455
|
+
st.middle ? 'rounded-none' : '',
|
|
456
|
+
st.end ? 'relative isolate z-0 rounded-e-(--cell-radius) bg-muted after:absolute after:inset-y-0 after:start-0 after:w-4 after:bg-muted' : '',
|
|
457
|
+
isToday ? 'rounded-(--cell-radius) bg-muted text-foreground data-[selected=true]:rounded-none' : '',
|
|
458
|
+
isOutside ? 'text-muted-foreground aria-selected:text-muted-foreground' : '',
|
|
459
|
+
off ? 'text-muted-foreground opacity-50' : '',
|
|
460
|
+
)}
|
|
461
|
+
><button
|
|
462
|
+
type="button"
|
|
463
|
+
tabindex=${iso === tab ? '0' : '-1'}
|
|
464
|
+
aria-label=${label}
|
|
465
|
+
?disabled=${off}
|
|
466
|
+
data-day=${iso}
|
|
467
|
+
data-selected-single=${st.single ? 'true' : 'false'}
|
|
468
|
+
data-range-start=${st.start ? 'true' : 'false'}
|
|
469
|
+
data-range-end=${st.end ? 'true' : 'false'}
|
|
470
|
+
data-range-middle=${st.middle ? 'true' : 'false'}
|
|
471
|
+
class=${cn(buttonClass({ variant: 'ghost', size: 'icon' }), calendarDayButtonClass())}
|
|
472
|
+
@click=${() => this.pick(iso)}
|
|
473
|
+
@focus=${() => { this.#focused.set(iso); }}
|
|
474
|
+
>${day.d}</button></td>`;
|
|
475
|
+
})}</tr>`)}</tbody></table></div>`;
|
|
476
|
+
})}</div>${hidden}</div>`;
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
// The first day of a week: Monday for ISO weeks, as react-day-picker's
|
|
480
|
+
// ISOWeek lays them out, else `week-starts-on`.
|
|
481
|
+
_weekStart(): number {
|
|
482
|
+
return this.isoWeek ? 1 : this.weekStartsOn || 0;
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
// A row's week number, a header cell for the row as react-day-picker draws
|
|
486
|
+
// it: named "Week N" and shown two digits wide.
|
|
487
|
+
_weekNumberCell(week: CalendarDate[]): unknown {
|
|
488
|
+
const n = weekNumber(week[0], this._weekStart(), !!this.isoWeek);
|
|
489
|
+
return html`<td role="rowheader" scope="row" aria-label=${`Week ${n}`} class="text-[0.8rem] text-muted-foreground select-none"><div class="flex size-(--cell-size) items-center justify-center text-center">${String(n).padStart(2, '0')}</div></td>`;
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
_hiddenInputs(): unknown {
|
|
493
|
+
const s = this.#selection.get();
|
|
494
|
+
if (this.mode === 'range') {
|
|
495
|
+
return html`<input type="hidden" name=${`${this.name}[from]`} value=${s.from}><input type="hidden" name=${`${this.name}[to]`} value=${s.to}>`;
|
|
496
|
+
}
|
|
497
|
+
return s.days.map((d) => html`<input type="hidden" name=${this.name} value=${d}>`);
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
// Month and year selects over the caption, as react-day-picker draws them.
|
|
501
|
+
_dropdowns(mo: CalendarDate, captionId: string | typeof nothing): unknown {
|
|
502
|
+
const monthName = this._fmt({ month: 'short' });
|
|
503
|
+
const lo = this._min() ?? { y: mo.y - 100, m: 0, d: 1 };
|
|
504
|
+
const hi = this._max() ?? { y: mo.y + 10, m: 11, d: 31 };
|
|
505
|
+
const years: number[] = [];
|
|
506
|
+
for (let y = lo.y; y <= hi.y; y++) years.push(y);
|
|
507
|
+
const months = Array.from({ length: 12 }, (_, i) => i);
|
|
508
|
+
const chevron = html`<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="m6 9 6 6 6-6"></path></svg>`;
|
|
509
|
+
return html`<div id=${captionId} class="flex h-(--cell-size) w-full items-center justify-center gap-1.5 text-sm font-medium"><span class=${calendarDropdownRootClass()}><select
|
|
510
|
+
aria-label="Choose the Month"
|
|
511
|
+
class="absolute inset-0 bg-popover opacity-0"
|
|
512
|
+
@change=${(e: Event) => this.goToMonth(formatDate({ y: mo.y, m: Number((e.target as HTMLSelectElement).value), d: 1 }))}
|
|
513
|
+
>${months.map((m) => html`<option value=${String(m)} ?selected=${m === mo.m}>${monthName.format(toUTC({ y: mo.y, m, d: 1 }))}</option>`)}</select><span
|
|
514
|
+
aria-hidden="true" class=${cn('font-medium select-none', calendarCaptionLabelClass())}>${monthName.format(toUTC(mo))}${chevron}</span></span><span class=${calendarDropdownRootClass()}><select
|
|
515
|
+
aria-label="Choose the Year"
|
|
516
|
+
class="absolute inset-0 bg-popover opacity-0"
|
|
517
|
+
@change=${(e: Event) => this.goToMonth(formatDate({ y: Number((e.target as HTMLSelectElement).value), m: mo.m, d: 1 }))}
|
|
518
|
+
>${years.map((y) => html`<option value=${String(y)} ?selected=${y === mo.y}>${y}</option>`)}</select><span
|
|
519
|
+
aria-hidden="true" class=${cn('font-medium select-none', calendarCaptionLabelClass())}>${mo.y}${chevron}</span></span></div>`;
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
_onKeyDown = (e: KeyboardEvent): void => {
|
|
523
|
+
const target = e.target as HTMLElement;
|
|
524
|
+
const iso = target.getAttribute?.('data-day');
|
|
525
|
+
if (!iso || target.tagName !== 'BUTTON') return;
|
|
526
|
+
const day = parseDate(iso);
|
|
527
|
+
if (!day) return;
|
|
528
|
+
const rtl = typeof getComputedStyle === 'function' && getComputedStyle(this).direction === 'rtl';
|
|
529
|
+
const w = this._weekStart();
|
|
530
|
+
let next: CalendarDate | null = null;
|
|
531
|
+
switch (e.key) {
|
|
532
|
+
case 'ArrowLeft': next = addDays(day, rtl ? 1 : -1); break;
|
|
533
|
+
case 'ArrowRight': next = addDays(day, rtl ? -1 : 1); break;
|
|
534
|
+
case 'ArrowUp': next = addDays(day, -7); break;
|
|
535
|
+
case 'ArrowDown': next = addDays(day, 7); break;
|
|
536
|
+
case 'Home': next = addDays(day, -((toUTC(day).getUTCDay() - w + 7) % 7)); break;
|
|
537
|
+
case 'End': next = addDays(day, 6 - ((toUTC(day).getUTCDay() - w + 7) % 7)); break;
|
|
538
|
+
case 'PageUp': next = e.shiftKey ? addMonths(day, -12) : addMonths(day, -1); break;
|
|
539
|
+
case 'PageDown': next = e.shiftKey ? addMonths(day, 12) : addMonths(day, 1); break;
|
|
540
|
+
case 'Enter':
|
|
541
|
+
case ' ':
|
|
542
|
+
e.preventDefault();
|
|
543
|
+
this.pick(iso);
|
|
544
|
+
return;
|
|
545
|
+
default:
|
|
546
|
+
return;
|
|
547
|
+
}
|
|
548
|
+
e.preventDefault();
|
|
549
|
+
this.focusDay(formatDate(next));
|
|
550
|
+
};
|
|
551
|
+
|
|
552
|
+
/** Move focus to `iso`, turning the page when it is not shown. */
|
|
553
|
+
focusDay(iso: string): void {
|
|
554
|
+
const day = parseDate(iso);
|
|
555
|
+
if (!day) return;
|
|
556
|
+
const first = this._first();
|
|
557
|
+
const last = addMonths(first, (this.numberOfMonths || 1) - 1);
|
|
558
|
+
if (compareDates({ ...day, d: 1 }, { ...first, d: 1 }) < 0) this.goToMonth(iso);
|
|
559
|
+
else if (compareDates({ ...day, d: 1 }, { ...last, d: 1 }) > 0) this.goToMonth(formatDate(addMonths(day, -((this.numberOfMonths || 1) - 1))));
|
|
560
|
+
this.#focused.set(iso);
|
|
561
|
+
this.updateComplete.then(() => {
|
|
562
|
+
this.querySelector<HTMLButtonElement>(`button[data-day="${iso}"]`)?.focus();
|
|
563
|
+
});
|
|
564
|
+
}
|
|
565
|
+
}
|
|
566
|
+
UiCalendar.register('ui-calendar');
|