@glyphui/ui 0.4.0 → 0.5.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 +9 -6
- package/dist/chart.d.ts +14 -202
- package/dist/chart.js +14 -465
- package/dist/components/accordion/accordion.d.ts +15 -0
- package/dist/components/accordion/accordion.js +69 -0
- package/dist/components/accordion/accordion.styles.d.ts +65 -0
- package/dist/components/accordion/accordion.styles.js +30 -0
- package/dist/components/accordion/index.d.ts +3 -0
- package/dist/components/alert/alert-icons.js +62 -0
- package/dist/components/alert/alert.d.ts +19 -0
- package/dist/components/alert/alert.js +64 -0
- package/dist/components/alert/alert.styles.d.ts +107 -0
- package/dist/components/alert/alert.styles.js +86 -0
- package/dist/components/alert/index.d.ts +3 -0
- package/dist/components/alert-dialog/alert-dialog.d.ts +29 -0
- package/dist/components/alert-dialog/alert-dialog.js +89 -0
- package/dist/components/alert-dialog/alert-dialog.styles.d.ts +63 -0
- package/dist/components/alert-dialog/alert-dialog.styles.js +19 -0
- package/dist/components/alert-dialog/confirm-dialog.js +22 -0
- package/dist/components/alert-dialog/confirm.d.ts +30 -0
- package/dist/components/alert-dialog/confirm.js +62 -0
- package/dist/components/alert-dialog/index.d.ts +4 -0
- package/dist/components/aspect-ratio/aspect-ratio.d.ts +55 -0
- package/dist/components/aspect-ratio/aspect-ratio.js +28 -0
- package/dist/components/aspect-ratio/index.d.ts +2 -0
- package/dist/components/avatar/avatar.d.ts +13 -0
- package/dist/components/avatar/avatar.js +50 -0
- package/dist/components/avatar/avatar.styles.d.ts +77 -0
- package/dist/components/avatar/avatar.styles.js +32 -0
- package/dist/components/avatar/index.d.ts +3 -0
- package/dist/components/badge/badge.d.ts +10 -0
- package/dist/components/badge/badge.js +28 -0
- package/dist/components/badge/badge.styles.d.ts +62 -0
- package/dist/components/badge/badge.styles.js +72 -0
- package/dist/components/badge/index.d.ts +3 -0
- package/dist/components/banner/banner.d.ts +17 -0
- package/dist/components/banner/banner.js +71 -0
- package/dist/components/banner/banner.styles.d.ts +98 -0
- package/dist/components/banner/banner.styles.js +27 -0
- package/dist/components/banner/index.d.ts +3 -0
- package/dist/components/blockquote/blockquote.d.ts +72 -0
- package/dist/components/blockquote/blockquote.js +47 -0
- package/dist/components/blockquote/index.d.ts +2 -0
- package/dist/components/breadcrumb/breadcrumb.d.ts +28 -0
- package/dist/components/breadcrumb/breadcrumb.js +85 -0
- package/dist/components/breadcrumb/breadcrumb.styles.d.ts +63 -0
- package/dist/components/breadcrumb/breadcrumb.styles.js +18 -0
- package/dist/components/breadcrumb/index.d.ts +3 -0
- package/dist/components/button/button.d.ts +20 -0
- package/dist/components/button/button.js +52 -0
- package/dist/components/button/button.styles.d.ts +146 -0
- package/dist/components/button/button.styles.js +64 -0
- package/dist/components/button/index.d.ts +3 -0
- package/dist/components/calendar/calendar.d.ts +9 -0
- package/dist/components/calendar/calendar.js +75 -0
- package/dist/components/calendar/calendar.styles.d.ts +171 -0
- package/dist/components/calendar/calendar.styles.js +42 -0
- package/dist/components/calendar/index.d.ts +4 -0
- package/dist/components/card/card.d.ts +17 -0
- package/dist/components/card/card.js +79 -0
- package/dist/components/card/card.styles.d.ts +113 -0
- package/dist/components/card/card.styles.js +38 -0
- package/dist/components/card/index.d.ts +3 -0
- package/dist/components/carousel/carousel.d.ts +37 -0
- package/dist/components/carousel/carousel.js +190 -0
- package/dist/components/carousel/carousel.styles.d.ts +74 -0
- package/dist/components/carousel/carousel.styles.js +35 -0
- package/dist/components/carousel/index.d.ts +3 -0
- package/dist/components/checkbox/checkbox.d.ts +37 -0
- package/dist/components/checkbox/checkbox.js +44 -0
- package/dist/components/checkbox/index.d.ts +2 -0
- package/dist/components/code/code.d.ts +18 -0
- package/dist/components/code/code.js +75 -0
- package/dist/components/code/code.styles.d.ts +76 -0
- package/dist/components/code/code.styles.js +18 -0
- package/dist/components/code/index.d.ts +3 -0
- package/dist/components/collapsible/collapsible.d.ts +56 -0
- package/dist/components/collapsible/collapsible.js +43 -0
- package/dist/components/collapsible/index.d.ts +2 -0
- package/dist/components/combobox/combobox.d.ts +50 -0
- package/dist/components/combobox/combobox.js +141 -0
- package/dist/components/combobox/combobox.styles.d.ts +110 -0
- package/dist/components/combobox/combobox.styles.js +42 -0
- package/dist/components/combobox/index.d.ts +3 -0
- package/dist/components/command-menu/command-menu.d.ts +40 -0
- package/dist/components/command-menu/command-menu.js +148 -0
- package/dist/components/command-menu/command-menu.styles.d.ts +105 -0
- package/dist/components/command-menu/command-menu.styles.js +30 -0
- package/dist/components/command-menu/index.d.ts +3 -0
- package/dist/components/container/container.d.ts +34 -0
- package/dist/components/container/container.js +30 -0
- package/dist/components/container/index.d.ts +2 -0
- package/dist/components/context-menu/context-menu.d.ts +34 -0
- package/dist/components/context-menu/context-menu.js +157 -0
- package/dist/components/context-menu/context-menu.styles.d.ts +135 -0
- package/dist/components/context-menu/context-menu.styles.js +14 -0
- package/dist/components/context-menu/index.d.ts +3 -0
- package/dist/components/copy-button/copy-button.d.ts +61 -0
- package/dist/components/copy-button/copy-button.js +79 -0
- package/dist/components/copy-button/index.d.ts +2 -0
- package/dist/components/date-picker/date-picker.d.ts +51 -0
- package/dist/components/date-picker/date-picker.js +235 -0
- package/dist/components/date-picker/date-picker.styles.d.ts +77 -0
- package/dist/components/date-picker/date-picker.styles.js +31 -0
- package/dist/components/date-picker/index.d.ts +3 -0
- package/dist/components/description-list/description-list.d.ts +15 -0
- package/dist/components/description-list/description-list.js +51 -0
- package/dist/components/description-list/description-list.styles.d.ts +74 -0
- package/dist/components/description-list/description-list.styles.js +35 -0
- package/dist/components/description-list/index.d.ts +3 -0
- package/dist/components/dialog/close-icon.js +22 -0
- package/dist/components/dialog/dialog.d.ts +21 -0
- package/dist/components/dialog/dialog.js +79 -0
- package/dist/components/dialog/dialog.styles.d.ts +83 -0
- package/dist/components/dialog/dialog.styles.js +34 -0
- package/dist/components/dialog/index.d.ts +3 -0
- package/dist/components/dropdown-menu/dropdown-menu.d.ts +34 -0
- package/dist/components/dropdown-menu/dropdown-menu.js +160 -0
- package/dist/components/dropdown-menu/dropdown-menu.styles.d.ts +83 -0
- package/dist/components/dropdown-menu/dropdown-menu.styles.js +38 -0
- package/dist/components/dropdown-menu/index.d.ts +3 -0
- package/dist/components/eyebrow/eyebrow.d.ts +9 -0
- package/dist/components/eyebrow/eyebrow.js +20 -0
- package/dist/components/eyebrow/eyebrow.styles.d.ts +38 -0
- package/dist/components/eyebrow/eyebrow.styles.js +13 -0
- package/dist/components/eyebrow/index.d.ts +3 -0
- package/dist/components/field/field-context.d.ts +25 -0
- package/dist/components/field/field-context.js +27 -0
- package/dist/components/field/field.d.ts +28 -0
- package/dist/{field-CVbywksE.js → components/field/field.js} +6 -35
- package/dist/components/field/field.styles.d.ts +53 -0
- package/dist/components/field/field.styles.js +22 -0
- package/dist/components/field/index.d.ts +4 -0
- package/dist/components/file-upload/file-upload.d.ts +52 -0
- package/dist/components/file-upload/file-upload.js +266 -0
- package/dist/components/file-upload/file-upload.styles.d.ts +123 -0
- package/dist/components/file-upload/file-upload.styles.js +32 -0
- package/dist/components/file-upload/index.d.ts +3 -0
- package/dist/components/grid/grid.d.ts +168 -0
- package/dist/components/grid/grid.js +126 -0
- package/dist/components/grid/index.d.ts +2 -0
- package/dist/components/heading/heading.d.ts +12 -0
- package/dist/components/heading/heading.js +28 -0
- package/dist/components/heading/heading.styles.d.ts +65 -0
- package/dist/components/heading/heading.styles.js +15 -0
- package/dist/components/heading/index.d.ts +3 -0
- package/dist/components/hover-card/hover-card.d.ts +43 -0
- package/dist/components/hover-card/hover-card.js +27 -0
- package/dist/components/hover-card/index.d.ts +2 -0
- package/dist/components/input/index.d.ts +3 -0
- package/dist/components/input/input.d.ts +13 -0
- package/dist/components/input/input.js +33 -0
- package/dist/components/input/input.styles.d.ts +55 -0
- package/dist/components/input/input.styles.js +33 -0
- package/dist/components/input-otp/index.d.ts +4 -0
- package/dist/components/input-otp/index.js +5 -0
- package/dist/components/input-otp/input-otp.d.ts +23 -0
- package/dist/components/input-otp/input-otp.js +86 -0
- package/dist/components/input-otp/input-otp.styles.d.ts +71 -0
- package/dist/components/input-otp/input-otp.styles.js +30 -0
- package/dist/components/kbd/index.d.ts +2 -0
- package/dist/components/kbd/kbd.d.ts +30 -0
- package/dist/components/kbd/kbd.js +17 -0
- package/dist/components/label/index.d.ts +2 -0
- package/dist/components/label/label.d.ts +31 -0
- package/dist/components/label/label.js +17 -0
- package/dist/components/link/index.d.ts +3 -0
- package/dist/components/link/link.d.ts +14 -0
- package/dist/components/link/link.js +57 -0
- package/dist/components/link/link.styles.d.ts +89 -0
- package/dist/components/link/link.styles.js +33 -0
- package/dist/components/modal/index.d.ts +3 -0
- package/dist/components/modal/modal.d.ts +33 -0
- package/dist/components/modal/modal.js +56 -0
- package/dist/components/modal/modal.styles.d.ts +61 -0
- package/dist/components/modal/modal.styles.js +14 -0
- package/dist/components/navigation-menu/index.d.ts +3 -0
- package/dist/components/navigation-menu/navigation-menu.d.ts +37 -0
- package/dist/components/navigation-menu/navigation-menu.js +138 -0
- package/dist/components/navigation-menu/navigation-menu.styles.d.ts +111 -0
- package/dist/components/navigation-menu/navigation-menu.styles.js +39 -0
- package/dist/components/number-input/index.d.ts +3 -0
- package/dist/components/number-input/number-input.d.ts +30 -0
- package/dist/components/number-input/number-input.js +151 -0
- package/dist/components/number-input/number-input.styles.d.ts +68 -0
- package/dist/components/number-input/number-input.styles.js +35 -0
- package/dist/components/pagination/index.d.ts +4 -0
- package/dist/components/pagination/pagination-range.d.ts +11 -0
- package/dist/components/pagination/pagination-range.js +42 -0
- package/dist/components/pagination/pagination.d.ts +18 -0
- package/dist/components/pagination/pagination.js +94 -0
- package/dist/components/pagination/pagination.styles.d.ts +65 -0
- package/dist/components/pagination/pagination.styles.js +35 -0
- package/dist/components/password-input/index.d.ts +3 -0
- package/dist/components/password-input/password-input.d.ts +20 -0
- package/dist/components/password-input/password-input.js +106 -0
- package/dist/components/password-input/password-input.styles.d.ts +66 -0
- package/dist/components/password-input/password-input.styles.js +21 -0
- package/dist/components/popover/index.d.ts +2 -0
- package/dist/components/popover/popover.d.ts +52 -0
- package/dist/components/popover/popover.js +35 -0
- package/dist/components/progress/index.d.ts +3 -0
- package/dist/components/progress/progress.d.ts +29 -0
- package/dist/components/progress/progress.js +108 -0
- package/dist/components/progress/progress.styles.d.ts +236 -0
- package/dist/components/progress/progress.styles.js +69 -0
- package/dist/components/prose/index.d.ts +2 -0
- package/dist/components/prose/prose.d.ts +90 -0
- package/dist/components/prose/prose.js +67 -0
- package/dist/components/radio-group/index.d.ts +3 -0
- package/dist/components/radio-group/radio-group.d.ts +26 -0
- package/dist/components/radio-group/radio-group.js +102 -0
- package/dist/components/radio-group/radio-group.styles.d.ts +80 -0
- package/dist/components/radio-group/radio-group.styles.js +56 -0
- package/dist/components/resizable/index.d.ts +3 -0
- package/dist/components/resizable/resizable.d.ts +17 -0
- package/dist/components/resizable/resizable.js +81 -0
- package/dist/components/resizable/resizable.styles.d.ts +53 -0
- package/dist/components/resizable/resizable.styles.js +19 -0
- package/dist/components/scroll-area/index.d.ts +2 -0
- package/dist/components/scroll-area/scroll-area.d.ts +70 -0
- package/dist/components/scroll-area/scroll-area.js +70 -0
- package/dist/components/section/index.d.ts +2 -0
- package/dist/components/section/section.d.ts +52 -0
- package/dist/components/section/section.js +41 -0
- package/dist/components/segmented-control/index.d.ts +2 -0
- package/dist/components/segmented-control/segmented-control.d.ts +92 -0
- package/dist/components/segmented-control/segmented-control.js +86 -0
- package/dist/components/select/index.d.ts +2 -0
- package/dist/components/select/select.d.ts +85 -0
- package/dist/components/select/select.js +81 -0
- package/dist/components/separator/index.d.ts +2 -0
- package/dist/components/separator/separator.d.ts +40 -0
- package/dist/components/separator/separator.js +27 -0
- package/dist/components/sheet/index.d.ts +3 -0
- package/dist/components/sheet/sheet.d.ts +20 -0
- package/dist/components/sheet/sheet.js +83 -0
- package/dist/components/sheet/sheet.styles.d.ts +101 -0
- package/dist/components/sheet/sheet.styles.js +62 -0
- package/dist/components/skeleton/index.d.ts +2 -0
- package/dist/components/skeleton/skeleton.d.ts +30 -0
- package/dist/components/skeleton/skeleton.js +18 -0
- package/dist/components/slider/index.d.ts +3 -0
- package/dist/components/slider/slider.d.ts +38 -0
- package/dist/components/slider/slider.js +68 -0
- package/dist/components/slider/slider.styles.d.ts +56 -0
- package/dist/components/slider/slider.styles.js +23 -0
- package/dist/components/spinner/index.d.ts +3 -0
- package/dist/components/spinner/spinner.d.ts +9 -0
- package/dist/components/spinner/spinner.js +36 -0
- package/dist/components/spinner/spinner.styles.d.ts +53 -0
- package/dist/components/spinner/spinner.styles.js +18 -0
- package/dist/components/stack/index.d.ts +2 -0
- package/dist/components/stack/stack.d.ts +109 -0
- package/dist/components/stack/stack.js +62 -0
- package/dist/components/stat-card/index.d.ts +3 -0
- package/dist/components/stat-card/stat-card.d.ts +22 -0
- package/dist/components/stat-card/stat-card.js +82 -0
- package/dist/components/stat-card/stat-card.styles.d.ts +83 -0
- package/dist/components/stat-card/stat-card.styles.js +16 -0
- package/dist/components/stepper/index.d.ts +3 -0
- package/dist/components/stepper/stepper.d.ts +20 -0
- package/dist/components/stepper/stepper.js +100 -0
- package/dist/components/stepper/stepper.styles.d.ts +170 -0
- package/dist/components/stepper/stepper.styles.js +67 -0
- package/dist/components/switch/index.d.ts +2 -0
- package/dist/components/switch/switch.d.ts +51 -0
- package/dist/components/switch/switch.js +43 -0
- package/dist/components/table/index.d.ts +2 -0
- package/dist/components/table/table.d.ts +78 -0
- package/dist/components/table/table.js +82 -0
- package/dist/components/tabs/index.d.ts +2 -0
- package/dist/components/tabs/tabs.d.ts +73 -0
- package/dist/components/tabs/tabs.js +103 -0
- package/dist/components/tag-input/index.d.ts +3 -0
- package/dist/components/tag-input/tag-input.d.ts +30 -0
- package/dist/components/tag-input/tag-input.js +149 -0
- package/dist/components/tag-input/tag-input.styles.d.ts +71 -0
- package/dist/components/tag-input/tag-input.styles.js +29 -0
- package/dist/components/text/index.d.ts +3 -0
- package/dist/components/text/text.d.ts +9 -0
- package/dist/components/text/text.js +25 -0
- package/dist/components/text/text.styles.d.ts +188 -0
- package/dist/components/text/text.styles.js +36 -0
- package/dist/components/textarea/index.d.ts +2 -0
- package/dist/components/textarea/textarea.d.ts +29 -0
- package/dist/components/textarea/textarea.js +23 -0
- package/dist/components/timeline/index.d.ts +3 -0
- package/dist/components/timeline/timeline.d.ts +28 -0
- package/dist/components/timeline/timeline.js +61 -0
- package/dist/components/timeline/timeline.styles.d.ts +110 -0
- package/dist/components/timeline/timeline.styles.js +30 -0
- package/dist/components/toast/index.d.ts +2 -0
- package/dist/components/toast/toast.d.ts +119 -0
- package/dist/components/toast/toast.js +75 -0
- package/dist/components/toggle/index.d.ts +3 -0
- package/dist/components/toggle/toggle.d.ts +20 -0
- package/dist/components/toggle/toggle.js +58 -0
- package/dist/components/toggle/toggle.styles.d.ts +80 -0
- package/dist/components/toggle/toggle.styles.js +34 -0
- package/dist/components/tooltip/index.d.ts +2 -0
- package/dist/components/tooltip/tooltip.d.ts +39 -0
- package/dist/components/tooltip/tooltip.js +29 -0
- package/dist/components/tree-view/index.d.ts +3 -0
- package/dist/components/tree-view/tree-view.d.ts +31 -0
- package/dist/components/tree-view/tree-view.js +192 -0
- package/dist/components/tree-view/tree-view.styles.d.ts +59 -0
- package/dist/components/tree-view/tree-view.styles.js +32 -0
- package/dist/components/visually-hidden/index.d.ts +2 -0
- package/dist/components/visually-hidden/visually-hidden.d.ts +10 -0
- package/dist/components/visually-hidden/visually-hidden.js +16 -0
- package/dist/data-table.d.ts +3 -110
- package/dist/data-table.js +2 -224
- package/dist/form.d.ts +2 -86
- package/dist/form.js +1 -108
- package/dist/hooks/index.d.ts +5 -0
- package/dist/hooks/use-component-config.d.ts +13 -0
- package/dist/hooks/use-component-config.js +22 -0
- package/dist/hooks/use-controllable-state.d.ts +9 -0
- package/dist/hooks/use-controllable-state.js +18 -0
- package/dist/hooks/use-media-query.d.ts +4 -0
- package/dist/hooks/use-media-query.js +13 -0
- package/dist/hooks/use-scrolled.d.ts +4 -0
- package/dist/hooks/use-scrolled.js +17 -0
- package/dist/index.d.ts +223 -6856
- package/dist/index.js +148 -6791
- package/dist/internal/dev.js +12 -0
- package/dist/internal/icons.js +91 -0
- package/dist/motion/active-indicator.d.ts +12 -0
- package/dist/motion/active-indicator.js +26 -0
- package/dist/motion/animated-number.d.ts +21 -0
- package/dist/motion/animated-number.js +88 -0
- package/dist/motion/features.js +10 -0
- package/dist/motion/index.d.ts +10 -0
- package/dist/motion/index.js +10 -0
- package/dist/motion/motion-root.js +48 -0
- package/dist/motion/page-transition.d.ts +16 -0
- package/dist/motion/page-transition.js +23 -0
- package/dist/motion/presence-list.js +46 -0
- package/dist/motion/presence.d.ts +11 -0
- package/dist/motion/presence.js +17 -0
- package/dist/motion/reveal.d.ts +18 -0
- package/dist/motion/reveal.js +37 -0
- package/dist/motion/stagger.d.ts +29 -0
- package/dist/motion/stagger.js +52 -0
- package/dist/motion/use-motion-settings.d.ts +25 -0
- package/dist/motion/use-motion-settings.js +47 -0
- package/dist/motion/use-reveal.d.ts +11 -0
- package/dist/motion/use-reveal.js +41 -0
- package/dist/patterns/app-shell/app-shell-context.d.ts +14 -0
- package/dist/patterns/app-shell/app-shell-context.js +16 -0
- package/dist/patterns/app-shell/app-shell.d.ts +21 -0
- package/dist/patterns/app-shell/app-shell.js +82 -0
- package/dist/patterns/app-shell/app-shell.styles.d.ts +302 -0
- package/dist/patterns/app-shell/app-shell.styles.js +106 -0
- package/dist/patterns/app-shell/index.d.ts +7 -0
- package/dist/patterns/app-shell/navbar.d.ts +29 -0
- package/dist/patterns/app-shell/navbar.js +116 -0
- package/dist/patterns/app-shell/page-header.d.ts +12 -0
- package/dist/patterns/app-shell/page-header.js +38 -0
- package/dist/patterns/app-shell/sidebar.d.ts +31 -0
- package/dist/patterns/app-shell/sidebar.js +141 -0
- package/dist/patterns/async/async.d.ts +40 -0
- package/dist/patterns/async/async.js +61 -0
- package/dist/patterns/async/index.d.ts +3 -0
- package/dist/patterns/async/states.d.ts +68 -0
- package/dist/patterns/async/states.js +116 -0
- package/dist/patterns/chart/cartesian.d.ts +128 -0
- package/dist/patterns/chart/cartesian.js +552 -0
- package/dist/patterns/chart/chart-card.d.ts +39 -0
- package/dist/patterns/chart/chart-card.js +103 -0
- package/dist/patterns/chart/chart-parts.d.ts +53 -0
- package/dist/patterns/chart/chart-parts.js +282 -0
- package/dist/patterns/chart/chart.styles.d.ts +200 -0
- package/dist/patterns/chart/chart.styles.js +43 -0
- package/dist/patterns/chart/export.d.ts +45 -0
- package/dist/patterns/chart/export.js +293 -0
- package/dist/patterns/chart/funnel.d.ts +23 -0
- package/dist/patterns/chart/funnel.js +129 -0
- package/dist/patterns/chart/heatmap.d.ts +37 -0
- package/dist/patterns/chart/heatmap.js +258 -0
- package/dist/patterns/chart/icons.js +39 -0
- package/dist/patterns/chart/pie.d.ts +36 -0
- package/dist/patterns/chart/pie.js +120 -0
- package/dist/patterns/chart/radial.d.ts +75 -0
- package/dist/patterns/chart/radial.js +282 -0
- package/dist/patterns/chart/sankey.d.ts +29 -0
- package/dist/patterns/chart/sankey.js +136 -0
- package/dist/patterns/chart/scatter.d.ts +42 -0
- package/dist/patterns/chart/scatter.js +203 -0
- package/dist/patterns/chart/sparkline.d.ts +20 -0
- package/dist/patterns/chart/sparkline.js +102 -0
- package/dist/patterns/chart/treemap.d.ts +25 -0
- package/dist/patterns/chart/treemap.js +128 -0
- package/dist/patterns/chart/use-element-width.js +23 -0
- package/dist/patterns/data-table/data-table.d.ts +109 -0
- package/dist/patterns/data-table/data-table.js +233 -0
- package/dist/patterns/form/form.d.ts +89 -0
- package/dist/patterns/form/form.js +111 -0
- package/dist/{color-mode-script-KdwItKN2.d.ts → provider/color-mode-script.d.ts} +4 -5
- package/dist/{color-mode-script-Bf7LYkOj.js → provider/color-mode-script.js} +1 -1
- package/dist/provider/color-mode.d.ts +24 -0
- package/dist/provider/color-mode.js +87 -0
- package/dist/{glyph-context-DxGJrdvr.d.ts → provider/glyph-context.d.ts} +13 -12
- package/dist/provider/glyph-context.js +28 -0
- package/dist/provider/glyph-provider.d.ts +37 -0
- package/dist/provider/glyph-provider.js +48 -0
- package/dist/provider/index.d.ts +6 -0
- package/dist/provider/theme-scope.d.ts +12 -0
- package/dist/provider/theme-scope.js +42 -0
- package/dist/provider/theme-style.js +15 -0
- package/dist/react-router.d.ts +1 -1
- package/dist/register.d.ts +57 -0
- package/dist/themes.d.ts +22 -0
- package/dist/themes.js +49 -0
- package/dist/utils/cn.d.ts +6 -0
- package/dist/utils/cn.js +12 -0
- package/dist/utils/compose-refs.js +11 -0
- package/dist/{registry-BGSJoiLq.d.ts → utils/registry.d.ts} +2 -3
- package/dist/utils/styles.js +20 -0
- package/dist/{tv-DuMh7UH2.d.ts → utils/tv.d.ts} +2 -2
- package/dist/utils/tv.js +8 -0
- package/dist/utils/tw-merge-config.js +13 -0
- package/dist/vite.d.ts +1 -1
- package/dist/vite.js +1 -1
- package/package.json +3 -2
- package/src/components/accordion/accordion.styles.ts +1 -1
- package/src/components/alert/alert.styles.ts +1 -1
- package/src/components/alert-dialog/alert-dialog.styles.ts +5 -4
- package/src/components/alert-dialog/confirm-dialog.tsx +42 -0
- package/src/components/alert-dialog/confirm.tsx +12 -31
- package/src/components/aspect-ratio/aspect-ratio.tsx +1 -1
- package/src/components/avatar/avatar.styles.ts +1 -1
- package/src/components/badge/badge.styles.ts +1 -1
- package/src/components/banner/banner.styles.ts +1 -1
- package/src/components/blockquote/blockquote.tsx +1 -1
- package/src/components/breadcrumb/breadcrumb.styles.ts +1 -1
- package/src/components/button/button.styles.ts +4 -2
- package/src/components/calendar/calendar.styles.ts +1 -1
- package/src/components/card/card.styles.ts +1 -1
- package/src/components/carousel/carousel.styles.ts +1 -1
- package/src/components/checkbox/checkbox.tsx +20 -5
- package/src/components/code/code.styles.ts +2 -2
- package/src/components/collapsible/collapsible.tsx +1 -1
- package/src/components/combobox/combobox.styles.ts +5 -2
- package/src/components/command-menu/command-menu.styles.ts +6 -4
- package/src/components/container/container.tsx +1 -1
- package/src/components/context-menu/context-menu.styles.ts +4 -2
- package/src/components/copy-button/copy-button.tsx +1 -1
- package/src/components/date-picker/date-picker.styles.ts +2 -2
- package/src/components/description-list/description-list.styles.ts +1 -1
- package/src/components/dialog/dialog.styles.ts +11 -4
- package/src/components/dropdown-menu/dropdown-menu.styles.ts +3 -3
- package/src/components/eyebrow/eyebrow.styles.ts +1 -1
- package/src/components/field/field.styles.ts +1 -1
- package/src/components/file-upload/file-upload.styles.ts +1 -1
- package/src/components/file-upload/file-upload.tsx +51 -48
- package/src/components/grid/grid.tsx +1 -1
- package/src/components/heading/heading.styles.ts +1 -1
- package/src/components/hover-card/hover-card.tsx +5 -2
- package/src/components/input/input.styles.ts +1 -1
- package/src/components/input-otp/input-otp.styles.ts +1 -1
- package/src/components/kbd/kbd.tsx +1 -1
- package/src/components/label/label.tsx +1 -1
- package/src/components/link/link.styles.ts +1 -1
- package/src/components/modal/modal.styles.ts +1 -1
- package/src/components/navigation-menu/navigation-menu.styles.ts +2 -2
- package/src/components/number-input/number-input.styles.ts +1 -1
- package/src/components/pagination/pagination.styles.ts +6 -4
- package/src/components/pagination/pagination.tsx +14 -1
- package/src/components/password-input/password-input.styles.ts +1 -1
- package/src/components/popover/popover.tsx +1 -1
- package/src/components/progress/progress.styles.ts +2 -2
- package/src/components/prose/prose.tsx +1 -1
- package/src/components/radio-group/radio-group.styles.ts +1 -1
- package/src/components/resizable/resizable.styles.ts +1 -1
- package/src/components/scroll-area/scroll-area.tsx +1 -1
- package/src/components/section/section.tsx +1 -1
- package/src/components/segmented-control/segmented-control.tsx +24 -8
- package/src/components/select/select.tsx +2 -2
- package/src/components/separator/separator.tsx +1 -1
- package/src/components/sheet/sheet.styles.ts +1 -1
- package/src/components/skeleton/skeleton.tsx +1 -1
- package/src/components/slider/slider.styles.ts +1 -1
- package/src/components/spinner/spinner.styles.ts +1 -1
- package/src/components/stack/stack.tsx +1 -1
- package/src/components/stat-card/stat-card.styles.ts +1 -1
- package/src/components/stepper/stepper.styles.ts +1 -1
- package/src/components/switch/switch.tsx +2 -2
- package/src/components/table/table.tsx +1 -1
- package/src/components/tabs/tabs.tsx +46 -15
- package/src/components/tag-input/tag-input.styles.ts +1 -1
- package/src/components/tag-input/tag-input.tsx +27 -18
- package/src/components/text/text.styles.ts +1 -1
- package/src/components/textarea/textarea.tsx +1 -1
- package/src/components/timeline/timeline.styles.ts +1 -1
- package/src/components/toast/toast.tsx +1 -1
- package/src/components/toggle/toggle.styles.ts +1 -1
- package/src/components/tooltip/tooltip.tsx +6 -3
- package/src/components/tree-view/tree-view.styles.ts +1 -1
- package/src/index.ts +3 -0
- package/src/motion/active-indicator.tsx +26 -0
- package/src/motion/animated-number.tsx +113 -0
- package/src/motion/features.ts +7 -0
- package/src/motion/index.ts +9 -0
- package/src/motion/motion-root.tsx +46 -0
- package/src/motion/page-transition.tsx +30 -0
- package/src/motion/presence-list.tsx +42 -0
- package/src/motion/presence.tsx +13 -0
- package/src/motion/reveal.tsx +50 -0
- package/src/motion/stagger.tsx +81 -0
- package/src/motion/use-motion-settings.ts +52 -0
- package/src/motion/use-reveal.ts +54 -0
- package/src/patterns/app-shell/app-shell.styles.ts +18 -11
- package/src/patterns/app-shell/sidebar.tsx +28 -7
- package/src/patterns/async/states.tsx +1 -1
- package/src/patterns/chart/cartesian.tsx +755 -0
- package/src/patterns/chart/chart-card.tsx +148 -0
- package/src/patterns/chart/chart-parts.tsx +323 -58
- package/src/patterns/chart/chart.styles.ts +29 -3
- package/src/patterns/chart/export.ts +334 -0
- package/src/patterns/chart/funnel.tsx +171 -0
- package/src/patterns/chart/heatmap.tsx +339 -0
- package/src/patterns/chart/icons.tsx +44 -0
- package/src/patterns/chart/index.ts +52 -7
- package/src/patterns/chart/pie.tsx +169 -0
- package/src/patterns/chart/radial.tsx +361 -0
- package/src/patterns/chart/sankey.tsx +197 -0
- package/src/patterns/chart/scatter.tsx +254 -0
- package/src/patterns/chart/sparkline.tsx +111 -0
- package/src/patterns/chart/test-utils.tsx +35 -0
- package/src/patterns/chart/treemap.tsx +198 -0
- package/src/patterns/chart/use-element-width.ts +20 -0
- package/src/patterns/data-table/data-table.tsx +1 -1
- package/src/patterns/form/form.tsx +1 -1
- package/src/provider/glyph-context.ts +3 -1
- package/src/provider/glyph-provider.tsx +31 -12
- package/src/provider/theme-scope.tsx +14 -9
- package/src/themes.ts +3 -3
- package/src/utils/styles.ts +17 -3
- package/styles.css +122 -3
- package/dist/field-context-7I-cWvvS.js +0 -267
- package/dist/index-Bi7rZ6ba.d.ts +0 -244
- package/dist/states-IvhjBgna.js +0 -288
- package/dist/tv-DLbT66dC.js +0 -70
- package/src/patterns/chart/chart.tsx +0 -386
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
import { type ComponentProps, type ReactNode, useRef } from 'react'
|
|
2
|
+
import { IconButton } from '../../components/button'
|
|
3
|
+
import { Card, CardDescription, CardTitle } from '../../components/card'
|
|
4
|
+
import {
|
|
5
|
+
DropdownMenu,
|
|
6
|
+
DropdownMenuContent,
|
|
7
|
+
DropdownMenuItem,
|
|
8
|
+
DropdownMenuTrigger,
|
|
9
|
+
} from '../../components/dropdown-menu'
|
|
10
|
+
import { SegmentedControl, type SegmentedOption } from '../../components/segmented-control'
|
|
11
|
+
import { useComponentConfig } from '../../hooks/use-component-config'
|
|
12
|
+
import { useControllableState } from '../../hooks/use-controllable-state'
|
|
13
|
+
import { chartCardStyles } from './chart.styles'
|
|
14
|
+
import { ChartViewContext } from './chart-parts'
|
|
15
|
+
import { exportChart } from './export'
|
|
16
|
+
import { ChartIcon, DownloadIcon, TableIcon } from './icons'
|
|
17
|
+
|
|
18
|
+
export interface ChartPeriod<P extends string> {
|
|
19
|
+
options: readonly SegmentedOption<P>[]
|
|
20
|
+
value?: P
|
|
21
|
+
defaultValue?: P
|
|
22
|
+
onValueChange?: (value: P) => void
|
|
23
|
+
/** Default "Period". */
|
|
24
|
+
'aria-label'?: string
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export interface ChartCardProps<P extends string = string>
|
|
28
|
+
extends Omit<ComponentProps<'div'>, 'title' | 'children'> {
|
|
29
|
+
title: ReactNode
|
|
30
|
+
description?: ReactNode
|
|
31
|
+
/** A period selector in the header, e.g. 7d / 30d / 90d. */
|
|
32
|
+
period?: ChartPeriod<P>
|
|
33
|
+
/** Extra controls in the header, before the built-in buttons. */
|
|
34
|
+
actions?: ReactNode
|
|
35
|
+
/** Adds a button that shows the chart's data as a table. Default true. */
|
|
36
|
+
tableToggle?: boolean
|
|
37
|
+
view?: 'chart' | 'table'
|
|
38
|
+
defaultView?: 'chart' | 'table'
|
|
39
|
+
onViewChange?: (view: 'chart' | 'table') => void
|
|
40
|
+
/** Adds a download menu (PNG and SVG). Default true. */
|
|
41
|
+
exportable?: boolean | { fileName?: string }
|
|
42
|
+
/** Called when a download fails, e.g. to show a toast. Logs to the console by default. */
|
|
43
|
+
onExportError?: (error: unknown) => void
|
|
44
|
+
/** One chart from `@glyphui/ui/chart`. Its own title becomes the accessible name only. */
|
|
45
|
+
children: ReactNode
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function slug(value: ReactNode): string {
|
|
49
|
+
const text = typeof value === 'string' || typeof value === 'number' ? String(value) : 'chart'
|
|
50
|
+
return (
|
|
51
|
+
text
|
|
52
|
+
.toLowerCase()
|
|
53
|
+
.replace(/[^a-z0-9]+/g, '-')
|
|
54
|
+
.replace(/^-|-$/g, '') || 'chart'
|
|
55
|
+
)
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* A card for one chart: title, period selector, "view as table" toggle and a download menu.
|
|
60
|
+
* The chart inside hides its own caption and switches to a table when asked.
|
|
61
|
+
*/
|
|
62
|
+
export function ChartCard<P extends string = string>(inProps: ChartCardProps<P>) {
|
|
63
|
+
const [props, slots] = useComponentConfig('ChartCard', inProps)
|
|
64
|
+
const {
|
|
65
|
+
title,
|
|
66
|
+
description,
|
|
67
|
+
period,
|
|
68
|
+
actions,
|
|
69
|
+
tableToggle = true,
|
|
70
|
+
view: viewProp,
|
|
71
|
+
defaultView = 'chart',
|
|
72
|
+
onViewChange,
|
|
73
|
+
exportable = true,
|
|
74
|
+
onExportError,
|
|
75
|
+
className,
|
|
76
|
+
children,
|
|
77
|
+
...rest
|
|
78
|
+
} = props
|
|
79
|
+
const s = chartCardStyles()
|
|
80
|
+
const body = useRef<HTMLDivElement>(null)
|
|
81
|
+
const [view, setView] = useControllableState({
|
|
82
|
+
value: viewProp,
|
|
83
|
+
defaultValue: defaultView,
|
|
84
|
+
onChange: onViewChange,
|
|
85
|
+
})
|
|
86
|
+
const fileName = (typeof exportable === 'object' ? exportable.fileName : undefined) ?? slug(title)
|
|
87
|
+
|
|
88
|
+
const download = (format: 'png' | 'svg') => {
|
|
89
|
+
exportChart(body.current, { format, fileName }).catch((error: unknown) => {
|
|
90
|
+
if (onExportError) onExportError(error)
|
|
91
|
+
else console.error(error)
|
|
92
|
+
})
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
return (
|
|
96
|
+
<Card data-slot="chart-card" className={s.root({ class: [slots.root, className] })} {...rest}>
|
|
97
|
+
<div className={s.header({ class: slots.header })}>
|
|
98
|
+
<div className={s.heading({ class: slots.heading })}>
|
|
99
|
+
<CardTitle>{title}</CardTitle>
|
|
100
|
+
{description && <CardDescription>{description}</CardDescription>}
|
|
101
|
+
</div>
|
|
102
|
+
<div className={s.controls({ class: slots.controls })}>
|
|
103
|
+
{period && (
|
|
104
|
+
<SegmentedControl<P>
|
|
105
|
+
size="sm"
|
|
106
|
+
aria-label={period['aria-label'] ?? 'Period'}
|
|
107
|
+
options={period.options}
|
|
108
|
+
{...(period.value !== undefined && { value: period.value })}
|
|
109
|
+
{...(period.defaultValue !== undefined && { defaultValue: period.defaultValue })}
|
|
110
|
+
{...(period.onValueChange && { onValueChange: period.onValueChange })}
|
|
111
|
+
/>
|
|
112
|
+
)}
|
|
113
|
+
{actions}
|
|
114
|
+
{tableToggle && (
|
|
115
|
+
<IconButton
|
|
116
|
+
size="sm"
|
|
117
|
+
variant="ghost"
|
|
118
|
+
aria-label="View as table"
|
|
119
|
+
aria-pressed={view === 'table'}
|
|
120
|
+
icon={view === 'table' ? <ChartIcon /> : <TableIcon />}
|
|
121
|
+
onClick={() => setView(view === 'table' ? 'chart' : 'table')}
|
|
122
|
+
/>
|
|
123
|
+
)}
|
|
124
|
+
{exportable && (
|
|
125
|
+
<DropdownMenu>
|
|
126
|
+
<DropdownMenuTrigger asChild>
|
|
127
|
+
<IconButton
|
|
128
|
+
size="sm"
|
|
129
|
+
variant="ghost"
|
|
130
|
+
aria-label="Download chart"
|
|
131
|
+
icon={<DownloadIcon />}
|
|
132
|
+
disabled={view === 'table'}
|
|
133
|
+
/>
|
|
134
|
+
</DropdownMenuTrigger>
|
|
135
|
+
<DropdownMenuContent align="end">
|
|
136
|
+
<DropdownMenuItem onSelect={() => download('png')}>Download PNG</DropdownMenuItem>
|
|
137
|
+
<DropdownMenuItem onSelect={() => download('svg')}>Download SVG</DropdownMenuItem>
|
|
138
|
+
</DropdownMenuContent>
|
|
139
|
+
</DropdownMenu>
|
|
140
|
+
)}
|
|
141
|
+
</div>
|
|
142
|
+
</div>
|
|
143
|
+
<div ref={body} className={s.body({ class: slots.body })}>
|
|
144
|
+
<ChartViewContext.Provider value={{ view }}>{children}</ChartViewContext.Provider>
|
|
145
|
+
</div>
|
|
146
|
+
</Card>
|
|
147
|
+
)
|
|
148
|
+
}
|
|
@@ -1,5 +1,16 @@
|
|
|
1
|
-
import { type ReactNode, useId } from 'react'
|
|
1
|
+
import { createContext, type ReactNode, useContext, useEffect, useId, useRef } from 'react'
|
|
2
|
+
import { Skeleton } from '../../components/skeleton'
|
|
3
|
+
import {
|
|
4
|
+
Table,
|
|
5
|
+
TableBody,
|
|
6
|
+
TableCell,
|
|
7
|
+
TableHead,
|
|
8
|
+
TableHeader,
|
|
9
|
+
TableRow,
|
|
10
|
+
} from '../../components/table'
|
|
2
11
|
import { useComponentConfig } from '../../hooks/use-component-config'
|
|
12
|
+
import { useMotionSettings } from '../../motion/use-motion-settings'
|
|
13
|
+
import { EmptyState, ErrorState } from '../async/states'
|
|
3
14
|
import { chartStyles } from './chart.styles'
|
|
4
15
|
|
|
5
16
|
/** Theme colors a series can use by name. Any CSS color also works. */
|
|
@@ -17,37 +28,120 @@ export type ChartColor =
|
|
|
17
28
|
| 'foreground'
|
|
18
29
|
| 'muted-foreground'
|
|
19
30
|
|
|
31
|
+
/** A theme color name or any CSS color. */
|
|
32
|
+
export type ChartColorValue = ChartColor | (string & {})
|
|
33
|
+
|
|
34
|
+
export type Key<T> = Extract<keyof T, string>
|
|
35
|
+
|
|
20
36
|
/** Series without a color use the theme's chart palette, in order. */
|
|
21
37
|
const palette: ChartColor[] = ['chart-1', 'chart-2', 'chart-3', 'chart-4', 'chart-5']
|
|
22
38
|
|
|
39
|
+
/**
|
|
40
|
+
* Turns a theme color name into a CSS value. Uses the `--glyph-*` variables the theme always
|
|
41
|
+
* emits: Tailwind only emits `--color-*` variables it finds in your source, and these names
|
|
42
|
+
* are built at runtime.
|
|
43
|
+
*/
|
|
23
44
|
export function resolveColor(color: string | undefined, index: number): string {
|
|
24
45
|
const value = color ?? palette[index % palette.length]!
|
|
25
|
-
return /^[a-z][a-z\d-]*$/.test(value) ? `var(--
|
|
46
|
+
return /^[a-z][a-z\d-]*$/.test(value) ? `var(--glyph-${value})` : value
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* The palette color for the `index`-th category. After the fifth, colors are blended toward
|
|
51
|
+
* the muted surface instead of repeating, so no two categories ever share a color.
|
|
52
|
+
*/
|
|
53
|
+
export function categoryColor(color: string | undefined, index: number): string {
|
|
54
|
+
if (color) return resolveColor(color, index)
|
|
55
|
+
const base = resolveColor(undefined, index)
|
|
56
|
+
const round = Math.floor(index / palette.length)
|
|
57
|
+
if (round === 0) return base
|
|
58
|
+
const mix = Math.max(30, 100 - round * 30)
|
|
59
|
+
return `color-mix(in oklab, ${base} ${mix}%, var(--glyph-muted))`
|
|
26
60
|
}
|
|
27
61
|
|
|
28
62
|
export const defaultFormatter = (value: number) =>
|
|
29
|
-
typeof value === 'number' ? value.toLocaleString() : String(value)
|
|
63
|
+
typeof value === 'number' && Number.isFinite(value) ? value.toLocaleString() : String(value)
|
|
30
64
|
|
|
31
65
|
export function useChartParts() {
|
|
32
66
|
const [, slots] = useComponentConfig('Chart', {})
|
|
33
67
|
return { s: chartStyles(), slots }
|
|
34
68
|
}
|
|
35
69
|
|
|
70
|
+
/**
|
|
71
|
+
* Entry and update animation for recharts series, from the theme's motion settings:
|
|
72
|
+
* off for `none` and reduced motion, a little longer and bouncier for `expressive`.
|
|
73
|
+
*/
|
|
74
|
+
export function useChartAnimation() {
|
|
75
|
+
const { animate, level, duration } = useMotionSettings()
|
|
76
|
+
return {
|
|
77
|
+
isAnimationActive: animate,
|
|
78
|
+
animationDuration: Math.round(duration.slow * 1000 * (level === 'expressive' ? 2.6 : 2)),
|
|
79
|
+
animationEasing: 'ease-out' as const,
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
36
83
|
export interface LegendEntry {
|
|
84
|
+
/** Stable id used for toggling. Defaults to the label. */
|
|
85
|
+
key?: string
|
|
37
86
|
label: ReactNode
|
|
38
87
|
color: string
|
|
88
|
+
hidden?: boolean
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
export interface ChartLegendProps {
|
|
92
|
+
items: LegendEntry[]
|
|
93
|
+
/** Makes entries buttons that show and hide their series. */
|
|
94
|
+
onToggle?: ((key: string) => void) | undefined
|
|
95
|
+
className?: string
|
|
39
96
|
}
|
|
40
97
|
|
|
41
|
-
|
|
98
|
+
/** Legend under a chart. Interactive when `onToggle` is set: click or press Enter to hide a series. */
|
|
99
|
+
export function ChartLegend({ items, onToggle, className }: ChartLegendProps) {
|
|
42
100
|
const { s, slots } = useChartParts()
|
|
101
|
+
if (!onToggle) {
|
|
102
|
+
return (
|
|
103
|
+
<ul
|
|
104
|
+
data-slot="chart-legend"
|
|
105
|
+
className={s.legend({ class: [slots.legend, className] })}
|
|
106
|
+
aria-hidden="true"
|
|
107
|
+
>
|
|
108
|
+
{items.map((item, i) => (
|
|
109
|
+
<li key={item.key ?? i} className={s.legendItem({ class: slots.legendItem })}>
|
|
110
|
+
<span
|
|
111
|
+
className={s.swatch({ class: slots.swatch })}
|
|
112
|
+
style={{ background: item.color }}
|
|
113
|
+
/>
|
|
114
|
+
{item.label}
|
|
115
|
+
</li>
|
|
116
|
+
))}
|
|
117
|
+
</ul>
|
|
118
|
+
)
|
|
119
|
+
}
|
|
43
120
|
return (
|
|
44
|
-
<ul
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
121
|
+
<ul
|
|
122
|
+
data-slot="chart-legend"
|
|
123
|
+
aria-label="Series"
|
|
124
|
+
className={s.legend({ class: [slots.legend, className] })}
|
|
125
|
+
>
|
|
126
|
+
{items.map((item, i) => {
|
|
127
|
+
const key = item.key ?? String(item.label ?? i)
|
|
128
|
+
return (
|
|
129
|
+
<li key={key} className={s.legendItem({ class: slots.legendItem })}>
|
|
130
|
+
<button
|
|
131
|
+
type="button"
|
|
132
|
+
aria-pressed={!item.hidden}
|
|
133
|
+
className={s.legendButton({ class: slots.legendButton })}
|
|
134
|
+
onClick={() => onToggle(key)}
|
|
135
|
+
>
|
|
136
|
+
<span
|
|
137
|
+
className={s.swatch({ class: slots.swatch })}
|
|
138
|
+
style={{ background: item.color }}
|
|
139
|
+
/>
|
|
140
|
+
{item.label}
|
|
141
|
+
</button>
|
|
142
|
+
</li>
|
|
143
|
+
)
|
|
144
|
+
})}
|
|
51
145
|
</ul>
|
|
52
146
|
)
|
|
53
147
|
}
|
|
@@ -60,21 +154,28 @@ interface TooltipPayloadItem {
|
|
|
60
154
|
payload?: Record<string, unknown> & { fill?: string }
|
|
61
155
|
}
|
|
62
156
|
|
|
157
|
+
export interface ChartTooltipCardProps {
|
|
158
|
+
active?: boolean | undefined
|
|
159
|
+
payload?: readonly TooltipPayloadItem[] | undefined
|
|
160
|
+
label?: ReactNode
|
|
161
|
+
formatter: (value: number) => string
|
|
162
|
+
labelFormatter?: ((label: ReactNode) => ReactNode) | undefined
|
|
163
|
+
/** Adds a total row, for stacked charts. */
|
|
164
|
+
total?: boolean | undefined
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/** The themed tooltip every chart uses. Render it from recharts' `<Tooltip content>`. */
|
|
63
168
|
export function ChartTooltipCard({
|
|
64
169
|
active,
|
|
65
170
|
payload,
|
|
66
171
|
label,
|
|
67
172
|
formatter,
|
|
68
173
|
labelFormatter,
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
payload?: readonly TooltipPayloadItem[]
|
|
72
|
-
label?: ReactNode
|
|
73
|
-
formatter: (value: number) => string
|
|
74
|
-
labelFormatter?: ((label: ReactNode) => ReactNode) | undefined
|
|
75
|
-
}) {
|
|
174
|
+
total,
|
|
175
|
+
}: ChartTooltipCardProps) {
|
|
76
176
|
const { s, slots } = useChartParts()
|
|
77
177
|
if (!active || !payload?.length) return null
|
|
178
|
+
const sum = payload.reduce((acc, item) => acc + (Number(item.value) || 0), 0)
|
|
78
179
|
return (
|
|
79
180
|
<div data-slot="chart-tooltip" className={s.tooltip({ class: slots.tooltip })}>
|
|
80
181
|
{label !== undefined && label !== '' && (
|
|
@@ -96,25 +197,125 @@ export function ChartTooltipCard({
|
|
|
96
197
|
</span>
|
|
97
198
|
</div>
|
|
98
199
|
))}
|
|
200
|
+
{total && payload.length > 1 && (
|
|
201
|
+
<div className={s.tooltipTotal({ class: slots.tooltipTotal })}>
|
|
202
|
+
<span className={s.tooltipName({ class: slots.tooltipName })}>Total</span>
|
|
203
|
+
<span className={s.tooltipValue({ class: slots.tooltipValue })}>{formatter(sum)}</span>
|
|
204
|
+
</div>
|
|
205
|
+
)}
|
|
99
206
|
</div>
|
|
100
207
|
)
|
|
101
208
|
}
|
|
102
209
|
|
|
103
|
-
|
|
210
|
+
/** Loading, error and empty handling shared by every chart. */
|
|
211
|
+
export interface ChartStateProps {
|
|
212
|
+
/** Shows a skeleton in place of the plot. */
|
|
213
|
+
loading?: boolean
|
|
214
|
+
/** Shows an error message in place of the plot, with a retry button when `onRetry` is set. */
|
|
215
|
+
error?: unknown
|
|
216
|
+
onRetry?: () => unknown
|
|
217
|
+
/** Shown when there is no data. Defaults to a short "No data" message. */
|
|
218
|
+
empty?: ReactNode
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
/** Set by `ChartCard`: lets a chart render as a visible table instead of a plot. */
|
|
222
|
+
export interface ChartViewContextValue {
|
|
223
|
+
view: 'chart' | 'table'
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
export const ChartViewContext = createContext<ChartViewContextValue | null>(null)
|
|
227
|
+
|
|
228
|
+
export interface ChartTable {
|
|
229
|
+
columns: string[]
|
|
230
|
+
rows: (string | number)[][]
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
export interface ChartFrameProps extends ChartStateProps {
|
|
104
234
|
/** Accessible name of the chart. Shown above it unless `hideTitle` is set. */
|
|
105
235
|
title: string
|
|
106
236
|
description?: ReactNode
|
|
107
|
-
hideTitle?: boolean
|
|
108
|
-
className?: string
|
|
237
|
+
hideTitle?: boolean | undefined
|
|
238
|
+
className?: string | undefined
|
|
109
239
|
legend?: LegendEntry[] | undefined
|
|
240
|
+
/** Makes the legend interactive. */
|
|
241
|
+
onLegendToggle?: ((key: string) => void) | undefined
|
|
110
242
|
/** Columns and rows for the screen-reader table that mirrors the chart. */
|
|
111
|
-
table:
|
|
243
|
+
table: ChartTable
|
|
244
|
+
/** Plot height, so loading, error and empty states keep the layout stable. */
|
|
245
|
+
height?: number | undefined
|
|
246
|
+
/** True when there is nothing to plot. */
|
|
247
|
+
isEmpty?: boolean | undefined
|
|
248
|
+
/**
|
|
249
|
+
* The plot itself is accessible (e.g. Heatmap's keyboard grid), so it is not hidden from
|
|
250
|
+
* screen readers and no duplicate table is rendered.
|
|
251
|
+
*/
|
|
252
|
+
accessiblePlot?: boolean | undefined
|
|
112
253
|
children: ReactNode
|
|
113
254
|
}
|
|
114
255
|
|
|
115
256
|
/**
|
|
116
|
-
*
|
|
117
|
-
*
|
|
257
|
+
* Keeps everything inside a hidden plot out of the tab order. Recharts makes some parts
|
|
258
|
+
* focusable (brush handles, the Sankey surface); inside an `aria-hidden` plot they would be
|
|
259
|
+
* reachable but unnamed. Keyboard and screen-reader users get the data from the table.
|
|
260
|
+
*/
|
|
261
|
+
function useUnfocusable(enabled: boolean) {
|
|
262
|
+
const ref = useRef<HTMLDivElement>(null)
|
|
263
|
+
useEffect(() => {
|
|
264
|
+
const plot = ref.current
|
|
265
|
+
if (!enabled || !plot) return
|
|
266
|
+
const apply = () => {
|
|
267
|
+
for (const node of plot.querySelectorAll<HTMLElement | SVGElement>('[tabindex]')) {
|
|
268
|
+
if (node.getAttribute('tabindex') !== '-1') node.setAttribute('tabindex', '-1')
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
apply()
|
|
272
|
+
const observer = new MutationObserver(apply)
|
|
273
|
+
observer.observe(plot, { subtree: true, childList: true, attributeFilter: ['tabindex'] })
|
|
274
|
+
return () => observer.disconnect()
|
|
275
|
+
}, [enabled])
|
|
276
|
+
return ref
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
function DataTable({ table }: { table: ChartTable }) {
|
|
280
|
+
const { s, slots } = useChartParts()
|
|
281
|
+
return (
|
|
282
|
+
<div className={s.table({ class: slots.table })}>
|
|
283
|
+
<Table>
|
|
284
|
+
<TableHeader>
|
|
285
|
+
<TableRow>
|
|
286
|
+
{table.columns.map((column) => (
|
|
287
|
+
<TableHead key={column} scope="col">
|
|
288
|
+
{column}
|
|
289
|
+
</TableHead>
|
|
290
|
+
))}
|
|
291
|
+
</TableRow>
|
|
292
|
+
</TableHeader>
|
|
293
|
+
<TableBody>
|
|
294
|
+
{table.rows.map((row, i) => (
|
|
295
|
+
<TableRow key={i}>
|
|
296
|
+
{row.map((cell, j) =>
|
|
297
|
+
j === 0 ? (
|
|
298
|
+
<TableHead key={j} scope="row" className="font-normal text-foreground">
|
|
299
|
+
{cell}
|
|
300
|
+
</TableHead>
|
|
301
|
+
) : (
|
|
302
|
+
<TableCell key={j} className="tabular-nums">
|
|
303
|
+
{cell}
|
|
304
|
+
</TableCell>
|
|
305
|
+
),
|
|
306
|
+
)}
|
|
307
|
+
</TableRow>
|
|
308
|
+
))}
|
|
309
|
+
</TableBody>
|
|
310
|
+
</Table>
|
|
311
|
+
</div>
|
|
312
|
+
)
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
/**
|
|
316
|
+
* Wraps every chart in a `<figure>` with a caption and a visually hidden data table, so
|
|
317
|
+
* screen-reader users get the numbers the chart shows. Also renders loading, error and empty
|
|
318
|
+
* states in place of the plot, and the visible table when a `ChartCard` asks for it.
|
|
118
319
|
*/
|
|
119
320
|
export function ChartFrame({
|
|
120
321
|
title,
|
|
@@ -122,18 +323,61 @@ export function ChartFrame({
|
|
|
122
323
|
hideTitle,
|
|
123
324
|
className,
|
|
124
325
|
legend,
|
|
326
|
+
onLegendToggle,
|
|
125
327
|
table,
|
|
328
|
+
height = 240,
|
|
329
|
+
isEmpty,
|
|
330
|
+
loading,
|
|
331
|
+
error,
|
|
332
|
+
onRetry,
|
|
333
|
+
empty,
|
|
334
|
+
accessiblePlot,
|
|
126
335
|
children,
|
|
127
336
|
}: ChartFrameProps) {
|
|
128
337
|
const { s, slots } = useChartParts()
|
|
129
338
|
const titleId = useId()
|
|
339
|
+
const viewContext = useContext(ChartViewContext)
|
|
340
|
+
const plotRef = useUnfocusable(!accessiblePlot)
|
|
341
|
+
const asTable = viewContext?.view === 'table'
|
|
342
|
+
const captionHidden = hideTitle || viewContext !== null
|
|
343
|
+
|
|
344
|
+
let plot: ReactNode
|
|
345
|
+
let state = false
|
|
346
|
+
if (loading) {
|
|
347
|
+
state = true
|
|
348
|
+
plot = (
|
|
349
|
+
<div className={s.state({ class: slots.state })} style={{ height }} role="status">
|
|
350
|
+
<Skeleton className={s.skeleton({ class: slots.skeleton })} />
|
|
351
|
+
<span className={s.srOnly()}>Loading chart…</span>
|
|
352
|
+
</div>
|
|
353
|
+
)
|
|
354
|
+
} else if (error) {
|
|
355
|
+
state = true
|
|
356
|
+
plot = (
|
|
357
|
+
<div className={s.state({ class: slots.state })} style={{ minHeight: height }}>
|
|
358
|
+
<ErrorState error={error} onRetry={onRetry} title="Couldn’t load this chart" />
|
|
359
|
+
</div>
|
|
360
|
+
)
|
|
361
|
+
} else if (isEmpty) {
|
|
362
|
+
state = true
|
|
363
|
+
plot = (
|
|
364
|
+
<div className={s.state({ class: slots.state })} style={{ minHeight: height }}>
|
|
365
|
+
{empty ?? <EmptyState title="No data yet" description="Nothing to show for this period." />}
|
|
366
|
+
</div>
|
|
367
|
+
)
|
|
368
|
+
} else if (asTable) {
|
|
369
|
+
state = true
|
|
370
|
+
plot = <DataTable table={table} />
|
|
371
|
+
}
|
|
372
|
+
|
|
130
373
|
return (
|
|
131
374
|
<figure
|
|
132
375
|
data-slot="chart"
|
|
133
376
|
aria-labelledby={titleId}
|
|
377
|
+
aria-busy={loading || undefined}
|
|
134
378
|
className={s.root({ class: [slots.root, className] })}
|
|
135
379
|
>
|
|
136
|
-
<figcaption className={
|
|
380
|
+
<figcaption className={captionHidden ? s.srOnly() : s.caption({ class: slots.caption })}>
|
|
137
381
|
<span id={titleId} className={s.title({ class: slots.title })}>
|
|
138
382
|
{title}
|
|
139
383
|
</span>
|
|
@@ -141,39 +385,60 @@ export function ChartFrame({
|
|
|
141
385
|
<span className={s.description({ class: slots.description })}>{description}</span>
|
|
142
386
|
)}
|
|
143
387
|
</figcaption>
|
|
144
|
-
{
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
{
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
388
|
+
{state ? (
|
|
389
|
+
plot
|
|
390
|
+
) : (
|
|
391
|
+
<>
|
|
392
|
+
{/* Screen readers get the data table below. Charts pass `accessibilityLayer={false}`
|
|
393
|
+
so recharts adds no focusable nodes inside this hidden plot. */}
|
|
394
|
+
<div
|
|
395
|
+
ref={plotRef}
|
|
396
|
+
data-slot="chart-plot"
|
|
397
|
+
className={s.plot({ class: slots.plot })}
|
|
398
|
+
aria-hidden={accessiblePlot ? undefined : 'true'}
|
|
399
|
+
>
|
|
400
|
+
{children}
|
|
401
|
+
</div>
|
|
402
|
+
{legend && legend.length > 1 && <ChartLegend items={legend} onToggle={onLegendToggle} />}
|
|
403
|
+
{!accessiblePlot && (
|
|
404
|
+
<table className={s.srOnly()}>
|
|
405
|
+
<caption>{title}</caption>
|
|
406
|
+
<thead>
|
|
407
|
+
<tr>
|
|
408
|
+
{table.columns.map((column) => (
|
|
409
|
+
<th key={column} scope="col">
|
|
410
|
+
{column}
|
|
411
|
+
</th>
|
|
412
|
+
))}
|
|
413
|
+
</tr>
|
|
414
|
+
</thead>
|
|
415
|
+
<tbody>
|
|
416
|
+
{table.rows.map((row, i) => (
|
|
417
|
+
<tr key={i}>
|
|
418
|
+
{row.map((cell, j) =>
|
|
419
|
+
j === 0 ? (
|
|
420
|
+
<th key={j} scope="row">
|
|
421
|
+
{cell}
|
|
422
|
+
</th>
|
|
423
|
+
) : (
|
|
424
|
+
<td key={j}>{cell}</td>
|
|
425
|
+
),
|
|
426
|
+
)}
|
|
427
|
+
</tr>
|
|
428
|
+
))}
|
|
429
|
+
</tbody>
|
|
430
|
+
</table>
|
|
431
|
+
)}
|
|
432
|
+
</>
|
|
433
|
+
)}
|
|
177
434
|
</figure>
|
|
178
435
|
)
|
|
179
436
|
}
|
|
437
|
+
|
|
438
|
+
/** Hidden-series state for interactive legends, controlled or not. */
|
|
439
|
+
export function toggleIn<K extends string>(list: readonly K[], key: K, total: number): K[] {
|
|
440
|
+
if (list.includes(key)) return list.filter((k) => k !== key)
|
|
441
|
+
// Never hide the last visible series: an empty plot reads as broken.
|
|
442
|
+
if (list.length + 1 >= total) return [...list]
|
|
443
|
+
return [...list, key]
|
|
444
|
+
}
|
|
@@ -1,16 +1,27 @@
|
|
|
1
1
|
import type { StylesEntry } from '../../utils/registry'
|
|
2
|
-
import { themedBorder } from '../../utils/styles'
|
|
2
|
+
import { focusRing, themedBorder } from '../../utils/styles'
|
|
3
3
|
import { tv, type VariantProps } from '../../utils/tv'
|
|
4
4
|
|
|
5
|
-
export const chartStyles = tv({
|
|
5
|
+
export const chartStyles = /* @__PURE__ */ tv({
|
|
6
6
|
slots: {
|
|
7
7
|
root: 'm-0 grid min-w-0 gap-3',
|
|
8
8
|
caption: 'grid gap-0.5',
|
|
9
9
|
title: 'text-small font-medium text-foreground',
|
|
10
10
|
description: 'text-caption text-muted-foreground',
|
|
11
|
-
plot:
|
|
11
|
+
plot: [
|
|
12
|
+
'relative min-w-0 [&_.recharts-surface]:overflow-visible',
|
|
13
|
+
'[&_.recharts-text]:fill-muted-foreground [&_.recharts-cartesian-axis-tick_text]:tabular-nums',
|
|
14
|
+
'[&_.recharts-layer]:outline-none [&_.recharts-sector]:outline-none [&_.recharts-rectangle]:outline-none',
|
|
15
|
+
],
|
|
16
|
+
state: 'flex items-center justify-center',
|
|
17
|
+
skeleton: 'h-full w-full rounded-md',
|
|
12
18
|
legend: 'flex flex-wrap items-center gap-x-4 gap-y-1 text-caption text-muted-foreground',
|
|
13
19
|
legendItem: 'inline-flex items-center gap-1.5',
|
|
20
|
+
legendButton: [
|
|
21
|
+
'-mx-1 inline-flex cursor-pointer items-center gap-1.5 rounded-xs px-1 py-0.5 transition-opacity hover:text-foreground',
|
|
22
|
+
'aria-[pressed=false]:opacity-45 aria-[pressed=false]:line-through aria-[pressed=false]:decoration-faint-foreground',
|
|
23
|
+
focusRing,
|
|
24
|
+
],
|
|
14
25
|
swatch: 'size-2.5 shrink-0 rounded-[2px]',
|
|
15
26
|
tooltip: [
|
|
16
27
|
'grid min-w-36 gap-1.5 rounded-md border-border bg-raised px-3 py-2 text-caption text-foreground shadow-lg',
|
|
@@ -20,16 +31,31 @@ export const chartStyles = tv({
|
|
|
20
31
|
tooltipRow: 'flex items-center gap-2',
|
|
21
32
|
tooltipName: 'flex-1 text-muted-foreground',
|
|
22
33
|
tooltipValue: 'font-mono font-medium tabular-nums text-foreground',
|
|
34
|
+
tooltipTotal: 'mt-0.5 flex items-center gap-2 border-t border-border pt-1.5',
|
|
23
35
|
center:
|
|
24
36
|
'pointer-events-none absolute inset-0 flex flex-col items-center justify-center text-center',
|
|
37
|
+
table: 'max-h-96 overflow-auto rounded-md border-(length:--glyph-border-width) border-border',
|
|
25
38
|
srOnly: 'sr-only',
|
|
26
39
|
},
|
|
27
40
|
})
|
|
28
41
|
|
|
29
42
|
export type ChartVariants = VariantProps<typeof chartStyles>
|
|
30
43
|
|
|
44
|
+
export const chartCardStyles = /* @__PURE__ */ tv({
|
|
45
|
+
slots: {
|
|
46
|
+
root: 'min-w-0',
|
|
47
|
+
header: 'flex flex-wrap items-start justify-between gap-3',
|
|
48
|
+
heading: 'grid min-w-0 gap-1',
|
|
49
|
+
controls: 'flex flex-wrap items-center gap-2',
|
|
50
|
+
body: 'min-w-0',
|
|
51
|
+
},
|
|
52
|
+
})
|
|
53
|
+
|
|
54
|
+
export type ChartCardVariants = VariantProps<typeof chartCardStyles>
|
|
55
|
+
|
|
31
56
|
declare module '@glyphui/tokens' {
|
|
32
57
|
interface GlyphComponentRegistry {
|
|
33
58
|
Chart: StylesEntry<typeof chartStyles>
|
|
59
|
+
ChartCard: StylesEntry<typeof chartCardStyles>
|
|
34
60
|
}
|
|
35
61
|
}
|