@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
|
@@ -0,0 +1,547 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The chart's browser half (#1666): the `<ui-chart>` element, and the
|
|
3
|
+
* tooltip and legend markup it draws (shadcn's ChartTooltipContent and
|
|
4
|
+
* ChartLegendContent), with the ChartConfig types they share. `chart.ts`
|
|
5
|
+
* draws the charts on the server with the same markup, and imports and
|
|
6
|
+
* re-exports everything here, so an app imports the chart module alone.
|
|
7
|
+
*
|
|
8
|
+
* A11y (handled by the element): once upgraded, a chart with a tooltip is a
|
|
9
|
+
* focusable `role="application"` named by its `title`, the arrow keys and
|
|
10
|
+
* Home / End step through its points, Escape hides the tooltip, and each
|
|
11
|
+
* step is announced through a polite live region.
|
|
12
|
+
*/
|
|
13
|
+
import { WebComponent, html, render } from '@webjsdev/core';
|
|
14
|
+
import { cn } from '../lib/utils.ts';
|
|
15
|
+
import { formatValue, visibleTicks, type Tick } from './chart-geometry.ts';
|
|
16
|
+
|
|
17
|
+
// --------------------------------------------------------------------------
|
|
18
|
+
// Types
|
|
19
|
+
// --------------------------------------------------------------------------
|
|
20
|
+
|
|
21
|
+
/** shadcn's ChartConfig: a label, and a colour or a light and dark pair, per key. */
|
|
22
|
+
export interface ChartConfigItem {
|
|
23
|
+
label?: string;
|
|
24
|
+
/** An icon for the tooltip and legend, a function returning an `html` / `svg` template. */
|
|
25
|
+
icon?: () => unknown;
|
|
26
|
+
color?: string;
|
|
27
|
+
theme?: { light: string; dark: string };
|
|
28
|
+
}
|
|
29
|
+
export type ChartConfig = Record<string, ChartConfigItem>;
|
|
30
|
+
|
|
31
|
+
/** One row of chart data. */
|
|
32
|
+
export type ChartDatum = Record<string, unknown>;
|
|
33
|
+
|
|
34
|
+
export interface Margin { top: number; right: number; bottom: number; left: number }
|
|
35
|
+
|
|
36
|
+
/** One entry of a tooltip or legend payload, Recharts' shape. */
|
|
37
|
+
export interface ChartPayloadItem {
|
|
38
|
+
dataKey: string;
|
|
39
|
+
name: string;
|
|
40
|
+
value: unknown;
|
|
41
|
+
color: string;
|
|
42
|
+
payload: ChartDatum;
|
|
43
|
+
type?: 'none';
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export interface ChartTooltipOptions {
|
|
47
|
+
/** The hover cursor (a muted band behind bars, a line on lines and areas). Default true. */
|
|
48
|
+
cursor?: boolean;
|
|
49
|
+
/** A point shown from the first paint, Recharts' `defaultIndex`. */
|
|
50
|
+
defaultIndex?: number;
|
|
51
|
+
indicator?: 'dot' | 'line' | 'dashed';
|
|
52
|
+
hideLabel?: boolean;
|
|
53
|
+
hideIndicator?: boolean;
|
|
54
|
+
nameKey?: string;
|
|
55
|
+
labelKey?: string;
|
|
56
|
+
labelFormatter?: (label: unknown, payload: ChartPayloadItem[]) => unknown;
|
|
57
|
+
formatter?: (value: unknown, name: string, item: ChartPayloadItem, index: number, datum: ChartDatum) => unknown;
|
|
58
|
+
/** One colour for every indicator, shadcn's `color`. */
|
|
59
|
+
color?: string;
|
|
60
|
+
class?: string;
|
|
61
|
+
labelClass?: string;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export interface ChartLegendOptions {
|
|
65
|
+
verticalAlign?: 'top' | 'bottom';
|
|
66
|
+
nameKey?: string;
|
|
67
|
+
hideIcon?: boolean;
|
|
68
|
+
class?: string;
|
|
69
|
+
/** The height the legend takes from the plot, in viewBox units. Default 28. */
|
|
70
|
+
height?: number;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/** What every chart function takes. */
|
|
74
|
+
export interface ChartBaseOptions {
|
|
75
|
+
config: ChartConfig;
|
|
76
|
+
data: ChartDatum[];
|
|
77
|
+
/** Classes for the container, shadcn's ChartContainer `className`. */
|
|
78
|
+
class?: string;
|
|
79
|
+
id?: string;
|
|
80
|
+
/** The accessible name of the chart. */
|
|
81
|
+
title?: string;
|
|
82
|
+
/** Nominal size: the SVG's viewBox. */
|
|
83
|
+
width?: number;
|
|
84
|
+
height?: number;
|
|
85
|
+
margin?: Partial<Margin>;
|
|
86
|
+
tooltip?: ChartTooltipOptions | false;
|
|
87
|
+
legend?: ChartLegendOptions | false;
|
|
88
|
+
/** Recharts' accessibilityLayer: focus and the arrow keys. Default true. */
|
|
89
|
+
accessibilityLayer?: boolean;
|
|
90
|
+
/** SVG `<defs>` content, for gradients (`svg` template). */
|
|
91
|
+
defs?: unknown;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/** The container's colour variables: `--color-<key>` per configured colour. */
|
|
95
|
+
export function chartStyle(config: ChartConfig): string {
|
|
96
|
+
return Object.entries(config)
|
|
97
|
+
.map(([key, item]) => {
|
|
98
|
+
const color = item.theme ? `light-dark(${item.theme.light}, ${item.theme.dark})` : item.color;
|
|
99
|
+
return color ? `--color-${key}: ${color};` : '';
|
|
100
|
+
})
|
|
101
|
+
.filter(Boolean)
|
|
102
|
+
.join(' ');
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// --------------------------------------------------------------------------
|
|
106
|
+
// Tooltip and legend content (shadcn's ChartTooltipContent / ChartLegendContent)
|
|
107
|
+
// --------------------------------------------------------------------------
|
|
108
|
+
|
|
109
|
+
/** shadcn's getPayloadConfigFromPayload: the config entry a payload item names. */
|
|
110
|
+
export function payloadConfig(config: ChartConfig, item: ChartPayloadItem | undefined, key: string): ChartConfigItem | undefined {
|
|
111
|
+
if (!item) return undefined;
|
|
112
|
+
let k = key;
|
|
113
|
+
const own = (item as unknown as Record<string, unknown>)[key];
|
|
114
|
+
if (typeof own === 'string') k = own;
|
|
115
|
+
else if (typeof item.payload?.[key] === 'string') k = item.payload[key] as string;
|
|
116
|
+
return k in config ? config[k] : config[key];
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* A tooltip resolved for one point: its label and its rows, with every
|
|
121
|
+
* formatter and config lookup already applied. When every part is a string
|
|
122
|
+
* it is plain data, which is how the chart serves a point (see `frame`).
|
|
123
|
+
*/
|
|
124
|
+
export interface ChartTooltipView {
|
|
125
|
+
label: unknown;
|
|
126
|
+
items: Array<{ name: unknown; value: string | null; color: string; icon?: unknown; custom?: unknown }>;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/** The view options the browser needs to draw a served point. */
|
|
130
|
+
export type TooltipLook = Pick<ChartTooltipOptions, 'indicator' | 'hideIndicator' | 'class' | 'labelClass'>;
|
|
131
|
+
|
|
132
|
+
/** Resolve a point's tooltip: shadcn's ChartTooltipContent logic, without the markup. */
|
|
133
|
+
export function chartTooltipView(config: ChartConfig, label: unknown, payload: ChartPayloadItem[], o: ChartTooltipOptions = {}): ChartTooltipView {
|
|
134
|
+
let viewLabel: unknown = '';
|
|
135
|
+
if (!o.hideLabel && payload.length) {
|
|
136
|
+
const first = payload[0];
|
|
137
|
+
const key = `${o.labelKey ?? first.dataKey ?? first.name ?? 'value'}`;
|
|
138
|
+
const itemConfig = payloadConfig(config, first, key);
|
|
139
|
+
const value = !o.labelKey && typeof label === 'string' ? (config[label]?.label ?? label) : itemConfig?.label;
|
|
140
|
+
viewLabel = o.labelFormatter ? o.labelFormatter(value, payload) : (value ?? '');
|
|
141
|
+
}
|
|
142
|
+
const items = payload.filter((item) => item.type !== 'none').map((item, index) => {
|
|
143
|
+
const key = `${o.nameKey ?? item.name ?? item.dataKey ?? 'value'}`;
|
|
144
|
+
const itemConfig = payloadConfig(config, item, key);
|
|
145
|
+
const color = o.color ?? (typeof item.payload?.fill === 'string' ? item.payload.fill : item.color);
|
|
146
|
+
const custom = o.formatter && item.value !== undefined && item.name ? o.formatter(item.value, item.name, item, index, item.payload) : undefined;
|
|
147
|
+
return {
|
|
148
|
+
name: itemConfig?.label ?? item.name,
|
|
149
|
+
value: item.value != null ? formatValue(item.value) : null,
|
|
150
|
+
color,
|
|
151
|
+
...(itemConfig?.icon ? { icon: itemConfig.icon() } : {}),
|
|
152
|
+
...(custom !== undefined ? { custom } : {}),
|
|
153
|
+
};
|
|
154
|
+
});
|
|
155
|
+
return { label: viewLabel, items };
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/** A view that is all strings can be served as data and drawn in the browser. */
|
|
159
|
+
export function isPlainView(v: ChartTooltipView): boolean {
|
|
160
|
+
return typeof v.label === 'string' && v.items.every((i) => i.icon === undefined && i.custom === undefined && typeof i.name === 'string');
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/** Draw a resolved tooltip: shadcn's ChartTooltipContent markup. */
|
|
164
|
+
export function chartTooltipMarkup(view: ChartTooltipView, o: TooltipLook = {}) {
|
|
165
|
+
if (!view.items.length) return '';
|
|
166
|
+
const indicator = o.indicator ?? 'dot';
|
|
167
|
+
const tooltipLabel = view.label === '' || view.label == null ? '' : html`<div class=${cn('font-medium', o.labelClass)}>${view.label}</div>`;
|
|
168
|
+
const nestLabel = view.items.length === 1 && indicator !== 'dot';
|
|
169
|
+
return html`<div class=${cn('cn-chart-tooltip grid min-w-32 items-start', o.class)}>${nestLabel ? '' : tooltipLabel}<div class="grid gap-1.5">${view.items.map((item) => {
|
|
170
|
+
const body = item.custom !== undefined
|
|
171
|
+
? item.custom
|
|
172
|
+
: html`${item.icon !== undefined
|
|
173
|
+
? item.icon
|
|
174
|
+
: o.hideIndicator
|
|
175
|
+
? ''
|
|
176
|
+
: html`<div class=${cn('shrink-0 rounded-[2px] border-(--color-border) bg-(--color-bg)', {
|
|
177
|
+
'h-2.5 w-2.5': indicator === 'dot',
|
|
178
|
+
'w-1': indicator === 'line',
|
|
179
|
+
'w-0 border-[1.5px] border-dashed bg-transparent': indicator === 'dashed',
|
|
180
|
+
'my-0.5': nestLabel && indicator === 'dashed',
|
|
181
|
+
})} style=${`--color-bg: ${item.color}; --color-border: ${item.color}`}></div>`}<div class=${cn('flex flex-1 justify-between leading-none', nestLabel ? 'items-end' : 'items-center')}><div class="grid gap-1.5">${nestLabel ? tooltipLabel : ''}<span class="text-muted-foreground">${item.name}</span></div>${item.value != null ? html`<span class="font-mono font-medium text-foreground tabular-nums">${item.value}</span>` : ''}</div>`;
|
|
182
|
+
return html`<div class=${cn('flex w-full flex-wrap items-stretch gap-2 [&>svg]:h-2.5 [&>svg]:w-2.5 [&>svg]:text-muted-foreground', indicator === 'dot' && 'items-center')}>${body}</div>`;
|
|
183
|
+
})}</div></div>`;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* The tooltip's content for one point: shadcn's ChartTooltipContent.
|
|
188
|
+
* `label` is the point's category (a month, a date), `payload` its series.
|
|
189
|
+
*/
|
|
190
|
+
export function chartTooltipContent(config: ChartConfig, label: unknown, payload: ChartPayloadItem[], o: ChartTooltipOptions = {}) {
|
|
191
|
+
return chartTooltipMarkup(chartTooltipView(config, label, payload, o), o);
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
/** The legend: shadcn's ChartLegendContent markup over a series payload. */
|
|
195
|
+
export function chartLegendContent(config: ChartConfig, payload: ChartPayloadItem[], o: ChartLegendOptions = {}) {
|
|
196
|
+
if (!payload.length) return '';
|
|
197
|
+
return html`<div class=${cn('flex items-center justify-center gap-4', o.verticalAlign === 'top' ? 'pb-3' : 'pt-3', o.class)}>${payload
|
|
198
|
+
.filter((item) => item.type !== 'none')
|
|
199
|
+
.map((item) => {
|
|
200
|
+
const itemConfig = payloadConfig(config, item, `${o.nameKey ?? item.dataKey ?? 'value'}`);
|
|
201
|
+
return html`<div class="flex items-center gap-1.5 [&>svg]:h-3 [&>svg]:w-3 [&>svg]:text-muted-foreground">${itemConfig?.icon && !o.hideIcon
|
|
202
|
+
? itemConfig.icon()
|
|
203
|
+
: html`<div class="h-2 w-2 shrink-0 rounded-[2px]" style=${`background-color: ${item.color}`}></div>`}${itemConfig?.label ?? ''}</div>`;
|
|
204
|
+
})}</div>`;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
// --------------------------------------------------------------------------
|
|
208
|
+
// The element adds the tooltip, cursor and active marks, by pointer and keyboard
|
|
209
|
+
// --------------------------------------------------------------------------
|
|
210
|
+
|
|
211
|
+
export class UiChart extends WebComponent {
|
|
212
|
+
/** The point showing, or -1. */
|
|
213
|
+
activeIndex = -1;
|
|
214
|
+
_resize: ResizeObserver | null = null;
|
|
215
|
+
|
|
216
|
+
connectedCallback(): void {
|
|
217
|
+
super.connectedCallback?.();
|
|
218
|
+
this.addEventListener('pointermove', this._onMove);
|
|
219
|
+
this.addEventListener('pointerleave', this._onLeave);
|
|
220
|
+
this.addEventListener('focusin', this._onFocus);
|
|
221
|
+
this.addEventListener('focusout', this._onBlur);
|
|
222
|
+
this.addEventListener('keydown', this._onKey);
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
firstUpdated(): void {
|
|
226
|
+
// A chart rendered on the client commits its attributes after the
|
|
227
|
+
// element connects, so a first attempt can find the SVG unfinished.
|
|
228
|
+
if (!this._init()) requestAnimationFrame(() => this._init());
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
disconnectedCallback(): void {
|
|
232
|
+
this.removeEventListener('pointermove', this._onMove);
|
|
233
|
+
this.removeEventListener('pointerleave', this._onLeave);
|
|
234
|
+
this.removeEventListener('focusin', this._onFocus);
|
|
235
|
+
this.removeEventListener('focusout', this._onBlur);
|
|
236
|
+
this.removeEventListener('keydown', this._onKey);
|
|
237
|
+
this._resize?.disconnect();
|
|
238
|
+
this._resize = null;
|
|
239
|
+
super.disconnectedCallback?.();
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
render() {
|
|
243
|
+
return html`<slot></slot>`;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
_svg(): SVGSVGElement | null {
|
|
247
|
+
return typeof this.querySelector === 'function' ? this.querySelector<SVGSVGElement>('svg.ui-chart-surface') : null;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
_entries(): HTMLElement[] {
|
|
251
|
+
return Array.from(this.querySelectorAll<HTMLElement>('[data-slot="chart-tooltips"] > [data-index]'));
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
_look(): TooltipLook {
|
|
255
|
+
const raw = this.querySelector<HTMLElement>('[data-slot="chart-tooltips"]')?.dataset.look;
|
|
256
|
+
return raw ? (JSON.parse(raw) as TooltipLook) : {};
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
_init(): boolean {
|
|
260
|
+
const s = this._svg();
|
|
261
|
+
if (!s || !s.getAttribute('viewBox')) return false;
|
|
262
|
+
this._watchSize(s);
|
|
263
|
+
if (!s.dataset.hit) return true;
|
|
264
|
+
if (s.dataset.keyboard === 'true') {
|
|
265
|
+
s.setAttribute('tabindex', '0');
|
|
266
|
+
s.setAttribute('role', 'application');
|
|
267
|
+
s.setAttribute('aria-roledescription', 'chart');
|
|
268
|
+
}
|
|
269
|
+
const d = s.dataset.defaultIndex;
|
|
270
|
+
if (d != null) this.show(Number(d));
|
|
271
|
+
return true;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
/** Lay the chart out again whenever its box changes size. */
|
|
275
|
+
_watchSize(s: SVGSVGElement): void {
|
|
276
|
+
if (this._resize || typeof ResizeObserver !== 'function') return;
|
|
277
|
+
this._resize = new ResizeObserver(() => this._layout(s));
|
|
278
|
+
this._resize.observe(s);
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
/**
|
|
282
|
+
* Fit the served chart to its box, as Recharts lays out at the real size.
|
|
283
|
+
*
|
|
284
|
+
* The server draws at a nominal size, and the SVG scales to its box. Where
|
|
285
|
+
* the box has another shape (a wide chart in a fixed height on a phone), a
|
|
286
|
+
* cartesian chart (`data-fit`) is widened or narrowed to fill it: the
|
|
287
|
+
* viewBox takes the box's aspect, and the plot is stretched along x around
|
|
288
|
+
* its left edge while the margins and the y axis keep their size. That is
|
|
289
|
+
* exact for the marks Recharts would redraw (its scales and the d3 curves
|
|
290
|
+
* are linear in x), so only what has a size of its own is put back: each
|
|
291
|
+
* label and dot is drawn unstretched, and the x axis ticks move to their
|
|
292
|
+
* new places and are thinned again. Without JavaScript the served layout
|
|
293
|
+
* shows, letterboxed in a box of another shape.
|
|
294
|
+
*
|
|
295
|
+
* Then the labels and dots keep their size in pixels. A 12px label in a
|
|
296
|
+
* chart drawn 340px wide on a 450 unit viewBox would read as 9px, so the
|
|
297
|
+
* SVG's font size, in em of its container's, undoes the scale, and each
|
|
298
|
+
* dot is scaled by it around its centre (Recharts' `r` is in pixels).
|
|
299
|
+
*/
|
|
300
|
+
_layout(s: SVGSVGElement): void {
|
|
301
|
+
const shown = s.getBoundingClientRect();
|
|
302
|
+
if (!shown.width || !shown.height) return;
|
|
303
|
+
const [, , w0, h] = (s.dataset.viewBox ??= s.getAttribute('viewBox') ?? '').split(/\s+/).map(Number);
|
|
304
|
+
if (!(w0 > 0 && h > 0)) return;
|
|
305
|
+
const round = (v: number) => Math.round(v * 1e4) / 1e4;
|
|
306
|
+
let w = w0;
|
|
307
|
+
let sx = 1;
|
|
308
|
+
const fit = s.dataset.fit === 'x' && s.dataset.plot != null;
|
|
309
|
+
if (fit) {
|
|
310
|
+
const [px, py, pw, ph] = (s.dataset.plot0 ??= s.dataset.plot ?? '').split(' ').map(Number);
|
|
311
|
+
const wide = (h * shown.width) / shown.height;
|
|
312
|
+
const stretch = (pw + wide - w0) / pw;
|
|
313
|
+
if (pw > 0 && stretch > 0.05) {
|
|
314
|
+
w = wide;
|
|
315
|
+
sx = Math.abs(stretch - 1) < 1e-3 ? 1 : stretch;
|
|
316
|
+
}
|
|
317
|
+
const map = (x: number) => (x <= px ? x : x >= px + pw ? x + (sx - 1) * pw : px + (x - px) * sx);
|
|
318
|
+
s.setAttribute('viewBox', `0 0 ${round(sx === 1 ? w0 : w)} ${h}`);
|
|
319
|
+
s.dataset.plot = [px, py, pw * sx, ph].map(round).join(' ');
|
|
320
|
+
const matrix = sx === 1 ? null : `matrix(${round(sx)} 0 0 1 ${round(px * (1 - sx))} 0)`;
|
|
321
|
+
for (const g of Array.from(s.children)) {
|
|
322
|
+
if (g.tagName.toLowerCase() === 'defs' || g.hasAttribute('data-axis')) continue;
|
|
323
|
+
if (matrix) g.setAttribute('transform', matrix);
|
|
324
|
+
else g.removeAttribute('transform');
|
|
325
|
+
for (const t of Array.from(g.querySelectorAll('text'))) {
|
|
326
|
+
const x = Number(t.getAttribute('x'));
|
|
327
|
+
if (matrix && Number.isFinite(x)) t.setAttribute('transform', `matrix(${round(1 / sx)} 0 0 1 ${round(x * (1 - 1 / sx))} 0)`);
|
|
328
|
+
else t.removeAttribute('transform');
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
const axis = s.querySelector<SVGGElement>('[data-axis="x"]');
|
|
332
|
+
if (axis) {
|
|
333
|
+
axis.dataset.extent = String(round(sx === 1 ? w0 : w));
|
|
334
|
+
for (const line of Array.from(axis.querySelectorAll('.ui-chart-cartesian-axis-line'))) {
|
|
335
|
+
for (const a of ['x1', 'x2']) {
|
|
336
|
+
const key = `data-${a}0`;
|
|
337
|
+
if (!line.hasAttribute(key)) line.setAttribute(key, line.getAttribute(a) ?? '0');
|
|
338
|
+
line.setAttribute(a, String(round(map(Number(line.getAttribute(key))))));
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
for (const t of Array.from(axis.querySelectorAll<SVGGElement>('[data-coord]'))) {
|
|
342
|
+
t.dataset.coord = String(round(map(Number((t.dataset.coord0 ??= t.dataset.coord)))));
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
for (const e of this._entries()) {
|
|
346
|
+
if (e.dataset.x != null) e.dataset.x = String(round(map(Number((e.dataset.x0 ??= e.dataset.x)))));
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
const k = Math.max((sx === 1 ? w0 : w) / shown.width, h / shown.height);
|
|
350
|
+
if (!(Number.isFinite(k) && k > 0)) return;
|
|
351
|
+
s.style.fontSize = `${round(k)}em`;
|
|
352
|
+
for (const c of Array.from(s.querySelectorAll('circle.ui-chart-dot'))) {
|
|
353
|
+
const cx = Number(c.getAttribute('cx'));
|
|
354
|
+
const cy = Number(c.getAttribute('cy'));
|
|
355
|
+
const a = k / (fit ? sx : 1);
|
|
356
|
+
c.setAttribute('transform', `matrix(${round(a)} 0 0 ${round(k)} ${round(cx * (1 - a))} ${round(cy * (1 - k))})`);
|
|
357
|
+
}
|
|
358
|
+
this._fitTicks(s, k);
|
|
359
|
+
const tip = this.querySelector<HTMLElement>('[data-slot="chart-tooltip"]');
|
|
360
|
+
if (this.activeIndex >= 0 && tip && !tip.hidden) this.show(this.activeIndex);
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
/**
|
|
364
|
+
* Thin each axis's labels again with their real widths, the way Recharts'
|
|
365
|
+
* getTicks does at render: the server could only estimate them, and the
|
|
366
|
+
* labels keep their font size while the chart scales.
|
|
367
|
+
*/
|
|
368
|
+
_fitTicks(s: SVGSVGElement, k: number): void {
|
|
369
|
+
for (const axis of Array.from(s.querySelectorAll<SVGGElement>('[data-axis][data-interval]'))) {
|
|
370
|
+
const interval = axis.dataset.interval ?? 'preserveEnd';
|
|
371
|
+
const groups = Array.from(axis.querySelectorAll<SVGGElement>('[data-coord]'));
|
|
372
|
+
const isX = axis.dataset.axis === 'x';
|
|
373
|
+
const ticks: Tick[] = groups.map((g, i) => ({ value: i, label: '', coord: Number(g.dataset.coord) }));
|
|
374
|
+
const size = (t: Tick) => {
|
|
375
|
+
const text = groups[Number(t.value)].querySelector('text');
|
|
376
|
+
if (!text) return 0;
|
|
377
|
+
return isX ? text.getComputedTextLength() : text.getBBox().height;
|
|
378
|
+
};
|
|
379
|
+
// Recharts' edges are the chart's box, with its margins in pixels. Here
|
|
380
|
+
// the margins scale with the chart while the labels do not, so the room
|
|
381
|
+
// between the box and the outer ticks is widened back to its pixels.
|
|
382
|
+
const extent = Number(axis.dataset.extent);
|
|
383
|
+
const coords = ticks.map((t) => t.coord);
|
|
384
|
+
const before = coords.length ? Math.min(...coords) : 0;
|
|
385
|
+
const after = coords.length ? extent - Math.max(...coords) : 0;
|
|
386
|
+
const kept = visibleTicks(ticks, size, -before * (k - 1), extent + after * (k - 1), Number(axis.dataset.gap), /^\d+$/.test(interval) ? Number(interval) : (interval as 'preserveEnd'));
|
|
387
|
+
const at = new Map(kept.map((t) => [Number(t.value), t.at ?? t.coord]));
|
|
388
|
+
groups.forEach((g, i) => {
|
|
389
|
+
const pos = at.get(i);
|
|
390
|
+
if (pos == null) {
|
|
391
|
+
g.setAttribute('visibility', 'hidden');
|
|
392
|
+
return;
|
|
393
|
+
}
|
|
394
|
+
g.removeAttribute('visibility');
|
|
395
|
+
const v = String(Math.round(pos * 1e4) / 1e4);
|
|
396
|
+
for (const el of Array.from(g.querySelectorAll('text, tspan'))) {
|
|
397
|
+
if (isX) el.setAttribute('x', v);
|
|
398
|
+
else if (el.tagName.toLowerCase() === 'text') el.setAttribute('y', v);
|
|
399
|
+
}
|
|
400
|
+
for (const line of Array.from(g.querySelectorAll('line'))) {
|
|
401
|
+
if (isX) { line.setAttribute('x1', v); line.setAttribute('x2', v); } else { line.setAttribute('y1', v); line.setAttribute('y2', v); }
|
|
402
|
+
}
|
|
403
|
+
});
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
/** Where a point's tooltip anchors, in pixels from the chart's wrapper. */
|
|
408
|
+
_anchor(i: number): { x: number; y: number } | null {
|
|
409
|
+
const s = this._svg();
|
|
410
|
+
const e = this._entries()[i];
|
|
411
|
+
const m = s?.getScreenCTM?.();
|
|
412
|
+
const wrap = s?.parentElement;
|
|
413
|
+
if (!s || !e || !m || !wrap) return null;
|
|
414
|
+
const r = wrap.getBoundingClientRect();
|
|
415
|
+
const x = Number(e.dataset.x);
|
|
416
|
+
const y = Number(e.dataset.y);
|
|
417
|
+
return { x: m.a * x + m.c * y + m.e - r.left, y: m.b * x + m.d * y + m.f - r.top };
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
/** Show point `i`, its tooltip at `at` (pixels from the wrapper) or at its anchor. */
|
|
421
|
+
show(i: number, at?: { x: number; y: number }): void {
|
|
422
|
+
const entry = this._entries()[i];
|
|
423
|
+
const wrapper = this.querySelector<HTMLElement>('[data-slot="chart-tooltip"]');
|
|
424
|
+
if (!entry || !wrapper) return;
|
|
425
|
+
for (const g of this.querySelectorAll('[data-slot="chart-cursor"] > [data-index], [data-slot="chart-active"] > [data-index]')) {
|
|
426
|
+
g.setAttribute('visibility', g.getAttribute('data-index') === String(i) ? 'visible' : 'hidden');
|
|
427
|
+
}
|
|
428
|
+
if (i !== this.activeIndex || wrapper.hidden || !wrapper.firstChild) {
|
|
429
|
+
const tip = entry.dataset.tip;
|
|
430
|
+
if (tip) {
|
|
431
|
+
// A served point is data: draw it with the same markup the server uses.
|
|
432
|
+
const box = document.createElement('div');
|
|
433
|
+
render(chartTooltipMarkup(JSON.parse(tip) as ChartTooltipView, this._look()), box);
|
|
434
|
+
wrapper.replaceChildren(...Array.from(box.childNodes));
|
|
435
|
+
} else {
|
|
436
|
+
wrapper.replaceChildren(...Array.from(entry.cloneNode(true).childNodes));
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
this.activeIndex = i;
|
|
440
|
+
wrapper.hidden = false;
|
|
441
|
+
const p = at ?? this._anchor(i);
|
|
442
|
+
if (!p) return;
|
|
443
|
+
// Recharts' getTooltipTranslate: 10px right of and below the point, or
|
|
444
|
+
// above and to its left when that would leave the plot area.
|
|
445
|
+
const area = this._plot();
|
|
446
|
+
const x = p.x + 10 + wrapper.offsetWidth > area.right ? Math.max(p.x - wrapper.offsetWidth - 10, area.left) : Math.max(p.x + 10, area.left);
|
|
447
|
+
const y = p.y + 10 + wrapper.offsetHeight > area.bottom ? Math.max(p.y - wrapper.offsetHeight - 10, area.top) : Math.max(p.y + 10, area.top);
|
|
448
|
+
wrapper.style.transform = `translate(${x}px, ${y}px)`;
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
/** The plot area in pixels from the chart's wrapper. */
|
|
452
|
+
_plot(): { left: number; top: number; right: number; bottom: number } {
|
|
453
|
+
const s = this._svg();
|
|
454
|
+
const wrap = s?.parentElement;
|
|
455
|
+
const m = s?.getScreenCTM?.();
|
|
456
|
+
const [x, y, w, h] = (s?.dataset.plot ?? '').split(' ').map(Number);
|
|
457
|
+
if (!s || !wrap || !m || !Number.isFinite(h)) {
|
|
458
|
+
return { left: 0, top: 0, right: wrap?.clientWidth ?? 0, bottom: wrap?.clientHeight ?? 0 };
|
|
459
|
+
}
|
|
460
|
+
const r = wrap.getBoundingClientRect();
|
|
461
|
+
return {
|
|
462
|
+
left: m.a * x + m.e - r.left,
|
|
463
|
+
top: m.d * y + m.f - r.top,
|
|
464
|
+
right: m.a * (x + w) + m.e - r.left,
|
|
465
|
+
bottom: m.d * (y + h) + m.f - r.top,
|
|
466
|
+
};
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
/** Hide the tooltip and the marks. */
|
|
470
|
+
hide(): void {
|
|
471
|
+
const wrapper = this.querySelector<HTMLElement>('[data-slot="chart-tooltip"]');
|
|
472
|
+
if (wrapper) wrapper.hidden = true;
|
|
473
|
+
for (const g of this.querySelectorAll('[data-slot="chart-cursor"] > [data-index], [data-slot="chart-active"] > [data-index]')) g.setAttribute('visibility', 'hidden');
|
|
474
|
+
this.activeIndex = -1;
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
_announce(i: number): void {
|
|
478
|
+
const live = this.querySelector<HTMLElement>('[data-slot="chart-live"]');
|
|
479
|
+
const entry = this._entries()[i];
|
|
480
|
+
if (!live || !entry) return;
|
|
481
|
+
const tip = entry.dataset.tip ? (JSON.parse(entry.dataset.tip) as ChartTooltipView) : null;
|
|
482
|
+
const text = tip
|
|
483
|
+
? [tip.label, ...tip.items.map((it) => `${it.name} ${it.value ?? ''}`)].join(' ')
|
|
484
|
+
: entry.textContent ?? '';
|
|
485
|
+
live.textContent = text.replace(/\s+/g, ' ').trim();
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
_onMove = (e: PointerEvent): void => {
|
|
489
|
+
const s = this._svg();
|
|
490
|
+
if (!s || !s.dataset.hit || !s.parentElement) return;
|
|
491
|
+
const wrap = s.parentElement.getBoundingClientRect();
|
|
492
|
+
const at = { x: e.clientX - wrap.left, y: e.clientY - wrap.top };
|
|
493
|
+
let index = -1;
|
|
494
|
+
if (s.dataset.hit === 'target') {
|
|
495
|
+
const t = (e.target as Element | null)?.closest?.('[data-index]');
|
|
496
|
+
if (t && s.contains(t)) index = Number(t.getAttribute('data-index'));
|
|
497
|
+
} else {
|
|
498
|
+
const m = s.getScreenCTM?.();
|
|
499
|
+
if (!m) return;
|
|
500
|
+
const inv = m.inverse();
|
|
501
|
+
const v = s.dataset.hit === 'y'
|
|
502
|
+
? inv.b * e.clientX + inv.d * e.clientY + inv.f
|
|
503
|
+
: inv.a * e.clientX + inv.c * e.clientY + inv.e;
|
|
504
|
+
const axis = s.dataset.hit === 'y' ? 'y' : 'x';
|
|
505
|
+
let best = Infinity;
|
|
506
|
+
this._entries().forEach((en, i) => {
|
|
507
|
+
const d = Math.abs(Number(en.dataset[axis]) - v);
|
|
508
|
+
if (d < best) { best = d; index = i; }
|
|
509
|
+
});
|
|
510
|
+
}
|
|
511
|
+
if (index < 0) this.hide();
|
|
512
|
+
else this.show(index, at);
|
|
513
|
+
};
|
|
514
|
+
|
|
515
|
+
_onLeave = (): void => {
|
|
516
|
+
if (!this.contains(document.activeElement)) this.hide();
|
|
517
|
+
};
|
|
518
|
+
|
|
519
|
+
_onFocus = (e: FocusEvent): void => {
|
|
520
|
+
if (e.target !== this._svg()) return;
|
|
521
|
+
const i = this.activeIndex >= 0 ? this.activeIndex : 0;
|
|
522
|
+
this.show(i);
|
|
523
|
+
this._announce(i);
|
|
524
|
+
};
|
|
525
|
+
|
|
526
|
+
_onBlur = (e: FocusEvent): void => {
|
|
527
|
+
if (e.target === this._svg()) this.hide();
|
|
528
|
+
};
|
|
529
|
+
|
|
530
|
+
_onKey = (e: KeyboardEvent): void => {
|
|
531
|
+
if (e.target !== this._svg()) return;
|
|
532
|
+
const n = this._entries().length;
|
|
533
|
+
if (!n) return;
|
|
534
|
+
const cur = this.activeIndex;
|
|
535
|
+
let next = cur;
|
|
536
|
+
if (e.key === 'ArrowRight' || e.key === 'ArrowDown') next = Math.min(n - 1, cur + 1);
|
|
537
|
+
else if (e.key === 'ArrowLeft' || e.key === 'ArrowUp') next = Math.max(0, cur - 1);
|
|
538
|
+
else if (e.key === 'Home') next = 0;
|
|
539
|
+
else if (e.key === 'End') next = n - 1;
|
|
540
|
+
else if (e.key === 'Escape') { this.hide(); return; }
|
|
541
|
+
else return;
|
|
542
|
+
e.preventDefault();
|
|
543
|
+
this.show(next);
|
|
544
|
+
this._announce(next);
|
|
545
|
+
};
|
|
546
|
+
}
|
|
547
|
+
UiChart.register('ui-chart');
|