@seekalfred/primitives 0.5.1 → 0.7.1
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 +682 -19
- package/dist/accordion/accordion.js +10 -4
- package/dist/accordion/accordion.js.map +1 -1
- package/dist/action-button/action-button.d.ts +50 -0
- package/dist/action-button/action-button.js +159 -0
- package/dist/action-button/action-button.js.map +1 -0
- package/dist/action-button/index.d.ts +2 -0
- package/dist/action-button/index.js +2 -0
- package/dist/activity-heatmap/activity-heatmap.d.ts +92 -0
- package/dist/activity-heatmap/activity-heatmap.js +699 -0
- package/dist/activity-heatmap/activity-heatmap.js.map +1 -0
- package/dist/activity-heatmap/index.d.ts +2 -0
- package/dist/activity-heatmap/index.js +2 -0
- package/dist/alert/alert.d.ts +19 -1
- package/dist/alert/alert.js +180 -23
- package/dist/alert/alert.js.map +1 -1
- package/dist/alert-dialog/alert-dialog.d.ts +45 -18
- package/dist/alert-dialog/alert-dialog.js +128 -9
- package/dist/alert-dialog/alert-dialog.js.map +1 -1
- package/dist/alert-dialog/index.d.ts +2 -2
- package/dist/alert-dialog/index.js +2 -2
- package/dist/animated-counter/animated-counter.d.ts +38 -0
- package/dist/animated-counter/animated-counter.js +230 -0
- package/dist/animated-counter/animated-counter.js.map +1 -0
- package/dist/animated-counter/index.d.ts +2 -0
- package/dist/animated-counter/index.js +2 -0
- package/dist/announcement-bar/announcement-bar.d.ts +67 -0
- package/dist/announcement-bar/announcement-bar.js +364 -0
- package/dist/announcement-bar/announcement-bar.js.map +1 -0
- package/dist/announcement-bar/index.d.ts +2 -0
- package/dist/announcement-bar/index.js +2 -0
- package/dist/avatar/avatar.d.ts +6 -0
- package/dist/avatar/avatar.js +47 -16
- package/dist/avatar/avatar.js.map +1 -1
- package/dist/badge/badge.d.ts +10 -3
- package/dist/badge/badge.js +35 -5
- package/dist/badge/badge.js.map +1 -1
- package/dist/bar-chart/bar-chart.d.ts +51 -0
- package/dist/bar-chart/bar-chart.js +565 -0
- package/dist/bar-chart/bar-chart.js.map +1 -0
- package/dist/bar-chart/index.d.ts +2 -0
- package/dist/bar-chart/index.js +2 -0
- package/dist/breadcrumb/breadcrumb.d.ts +2 -29
- package/dist/breadcrumb/breadcrumb.js +32 -9
- package/dist/breadcrumb/breadcrumb.js.map +1 -1
- package/dist/brush-chart/brush-chart.d.ts +64 -0
- package/dist/brush-chart/brush-chart.js +1056 -0
- package/dist/brush-chart/brush-chart.js.map +1 -0
- package/dist/brush-chart/index.d.ts +2 -0
- package/dist/brush-chart/index.js +2 -0
- package/dist/button/button.d.ts +36 -23
- package/dist/button/button.js +198 -45
- package/dist/button/button.js.map +1 -1
- package/dist/button-group/button-group.d.ts +76 -0
- package/dist/button-group/button-group.js +402 -0
- package/dist/button-group/button-group.js.map +1 -0
- package/dist/button-group/index.d.ts +2 -0
- package/dist/button-group/index.js +2 -0
- package/dist/calendar/calendar.d.ts +1 -1
- package/dist/calendar/calendar.js +257 -30
- package/dist/calendar/calendar.js.map +1 -1
- package/dist/card/card.d.ts +9 -2
- package/dist/card/card.js +16 -5
- package/dist/card/card.js.map +1 -1
- package/dist/card-stack/card-stack.d.ts +54 -0
- package/dist/card-stack/card-stack.js +492 -0
- package/dist/card-stack/card-stack.js.map +1 -0
- package/dist/card-stack/index.d.ts +2 -0
- package/dist/card-stack/index.js +2 -0
- package/dist/carousel/carousel.d.ts +56 -0
- package/dist/carousel/carousel.js +389 -0
- package/dist/carousel/carousel.js.map +1 -0
- package/dist/carousel/index.d.ts +2 -0
- package/dist/carousel/index.js +2 -0
- package/dist/checkbox/checkbox.d.ts +0 -7
- package/dist/checkbox/checkbox.js +26 -29
- package/dist/checkbox/checkbox.js.map +1 -1
- package/dist/chip-group/chip-group.d.ts +37 -0
- package/dist/chip-group/chip-group.js +148 -0
- package/dist/chip-group/chip-group.js.map +1 -0
- package/dist/chip-group/index.d.ts +2 -0
- package/dist/chip-group/index.js +2 -0
- package/dist/confirm-morph/confirm-morph.d.ts +85 -0
- package/dist/confirm-morph/confirm-morph.js +652 -0
- package/dist/confirm-morph/confirm-morph.js.map +1 -0
- package/dist/confirm-morph/index.d.ts +2 -0
- package/dist/confirm-morph/index.js +2 -0
- package/dist/copy-button/copy-button.d.ts +32 -0
- package/dist/copy-button/copy-button.js +134 -0
- package/dist/copy-button/copy-button.js.map +1 -0
- package/dist/copy-button/index.d.ts +2 -0
- package/dist/copy-button/index.js +2 -0
- package/dist/countdown/countdown.d.ts +45 -0
- package/dist/countdown/countdown.js +298 -0
- package/dist/countdown/countdown.js.map +1 -0
- package/dist/countdown/index.d.ts +2 -0
- package/dist/countdown/index.js +2 -0
- package/dist/date-picker/date-picker.d.ts +51 -0
- package/dist/date-picker/date-picker.js +241 -0
- package/dist/date-picker/date-picker.js.map +1 -0
- package/dist/date-picker/date-range-picker.d.ts +78 -0
- package/dist/date-picker/date-range-picker.js +1015 -0
- package/dist/date-picker/date-range-picker.js.map +1 -0
- package/dist/date-picker/index.d.ts +4 -0
- package/dist/date-picker/index.js +4 -0
- package/dist/date-picker/picker-parts.d.ts +46 -0
- package/dist/date-picker/picker-parts.js +135 -0
- package/dist/date-picker/picker-parts.js.map +1 -0
- package/dist/dialog/dialog.d.ts +10 -14
- package/dist/dialog/dialog.js +40 -12
- package/dist/dialog/dialog.js.map +1 -1
- package/dist/donut-chart/donut-chart.d.ts +64 -0
- package/dist/donut-chart/donut-chart.js +576 -0
- package/dist/donut-chart/donut-chart.js.map +1 -0
- package/dist/donut-chart/index.d.ts +2 -0
- package/dist/donut-chart/index.js +2 -0
- package/dist/empty-state/empty-state.d.ts +55 -0
- package/dist/empty-state/empty-state.js +89 -0
- package/dist/empty-state/empty-state.js.map +1 -0
- package/dist/empty-state/index.d.ts +2 -0
- package/dist/empty-state/index.js +2 -0
- package/dist/expanding-button-group/expanding-button-group.d.ts +54 -0
- package/dist/expanding-button-group/expanding-button-group.js +350 -0
- package/dist/expanding-button-group/expanding-button-group.js.map +1 -0
- package/dist/expanding-button-group/index.d.ts +2 -0
- package/dist/expanding-button-group/index.js +2 -0
- package/dist/file-drop-zone/file-drop-zone.d.ts +71 -0
- package/dist/file-drop-zone/file-drop-zone.js +116 -0
- package/dist/file-drop-zone/file-drop-zone.js.map +1 -0
- package/dist/file-drop-zone/index.d.ts +2 -0
- package/dist/file-drop-zone/index.js +2 -0
- package/dist/filter-bar/filter-bar.d.ts +142 -0
- package/dist/filter-bar/filter-bar.js +416 -0
- package/dist/filter-bar/filter-bar.js.map +1 -0
- package/dist/filter-bar/index.d.ts +2 -0
- package/dist/filter-bar/index.js +2 -0
- package/dist/floating-button-group/floating-button-group.d.ts +61 -0
- package/dist/floating-button-group/floating-button-group.js +340 -0
- package/dist/floating-button-group/floating-button-group.js.map +1 -0
- package/dist/floating-button-group/index.d.ts +2 -0
- package/dist/floating-button-group/index.js +2 -0
- package/dist/gauge/gauge.d.ts +45 -0
- package/dist/gauge/gauge.js +219 -0
- package/dist/gauge/gauge.js.map +1 -0
- package/dist/gauge/index.d.ts +2 -0
- package/dist/gauge/index.js +2 -0
- package/dist/icon-morph/icon-morph.d.ts +55 -0
- package/dist/icon-morph/icon-morph.js +331 -0
- package/dist/icon-morph/icon-morph.js.map +1 -0
- package/dist/icon-morph/index.d.ts +2 -0
- package/dist/icon-morph/index.js +2 -0
- package/dist/in-view-title/in-view-title.d.ts +33 -0
- package/dist/in-view-title/in-view-title.js +119 -0
- package/dist/in-view-title/in-view-title.js.map +1 -0
- package/dist/in-view-title/index.d.ts +2 -0
- package/dist/in-view-title/index.js +2 -0
- package/dist/index.d.ts +71 -6
- package/dist/index.js +73 -11
- package/dist/input/input.d.ts +22 -0
- package/dist/input/input.js +36 -12
- package/dist/input/input.js.map +1 -1
- package/dist/lib/cn.js +11 -1
- package/dist/lib/cn.js.map +1 -1
- package/dist/lib/count-to.js +113 -0
- package/dist/lib/count-to.js.map +1 -0
- package/dist/lib/eye-morph.js +62 -0
- package/dist/lib/eye-morph.js.map +1 -0
- package/dist/lib/field-message.js +354 -0
- package/dist/lib/field-message.js.map +1 -0
- package/dist/lib/field-shell.js +81 -0
- package/dist/lib/field-shell.js.map +1 -0
- package/dist/lib/field-surface.js +11 -8
- package/dist/lib/field-surface.js.map +1 -1
- package/dist/lib/flag-emoji.js +50 -0
- package/dist/lib/flag-emoji.js.map +1 -0
- package/dist/lib/flip.js +88 -0
- package/dist/lib/flip.js.map +1 -0
- package/dist/lib/height-follow.js +59 -0
- package/dist/lib/height-follow.js.map +1 -0
- package/dist/lib/icon-swap.js +47 -0
- package/dist/lib/icon-swap.js.map +1 -0
- package/dist/lib/leaving-list.js +57 -0
- package/dist/lib/leaving-list.js.map +1 -0
- package/dist/lib/menu-highlight.js +64 -0
- package/dist/lib/menu-highlight.js.map +1 -0
- package/dist/lib/merge-refs.js +3 -3
- package/dist/lib/merge-refs.js.map +1 -1
- package/dist/lib/morph-text.js +128 -0
- package/dist/lib/morph-text.js.map +1 -0
- package/dist/lib/motion.js +169 -0
- package/dist/lib/motion.js.map +1 -0
- package/dist/lib/pausable-timeout.js +67 -0
- package/dist/lib/pausable-timeout.js.map +1 -0
- package/dist/lib/rolling-value.js +31 -0
- package/dist/lib/rolling-value.js.map +1 -0
- package/dist/lib/spring-progress.js +114 -0
- package/dist/lib/spring-progress.js.map +1 -0
- package/dist/lib/spring-tween.js +500 -0
- package/dist/lib/spring-tween.js.map +1 -0
- package/dist/lib/svg-id.js +10 -0
- package/dist/lib/svg-id.js.map +1 -0
- package/dist/lib/swap-text.js +79 -0
- package/dist/lib/swap-text.js.map +1 -0
- package/dist/lib/use-copy-feedback.js +36 -0
- package/dist/lib/use-copy-feedback.js.map +1 -0
- package/dist/line-chart/index.d.ts +2 -0
- package/dist/line-chart/index.js +2 -0
- package/dist/line-chart/line-chart.d.ts +76 -0
- package/dist/line-chart/line-chart.js +611 -0
- package/dist/line-chart/line-chart.js.map +1 -0
- package/dist/mention-input/index.d.ts +2 -0
- package/dist/mention-input/index.js +2 -0
- package/dist/mention-input/mention-input.d.ts +98 -0
- package/dist/mention-input/mention-input.js +576 -0
- package/dist/mention-input/mention-input.js.map +1 -0
- package/dist/menu/menu.d.ts +2 -0
- package/dist/menu/menu.js +23 -12
- package/dist/menu/menu.js.map +1 -1
- package/dist/money-input/index.d.ts +2 -0
- package/dist/money-input/index.js +2 -0
- package/dist/money-input/money-input.d.ts +65 -0
- package/dist/money-input/money-input.js +607 -0
- package/dist/money-input/money-input.js.map +1 -0
- package/dist/morph-select/index.d.ts +2 -0
- package/dist/morph-select/index.js +2 -0
- package/dist/morph-select/morph-select.d.ts +71 -0
- package/dist/morph-select/morph-select.js +693 -0
- package/dist/morph-select/morph-select.js.map +1 -0
- package/dist/multi-select/index.d.ts +2 -0
- package/dist/multi-select/index.js +2 -0
- package/dist/multi-select/multi-select.d.ts +36 -0
- package/dist/multi-select/multi-select.js +152 -0
- package/dist/multi-select/multi-select.js.map +1 -0
- package/dist/number-field/index.d.ts +2 -0
- package/dist/number-field/index.js +2 -0
- package/dist/number-field/number-field.d.ts +42 -0
- package/dist/number-field/number-field.js +199 -0
- package/dist/number-field/number-field.js.map +1 -0
- package/dist/onboarding-checklist/index.d.ts +2 -0
- package/dist/onboarding-checklist/index.js +2 -0
- package/dist/onboarding-checklist/onboarding-checklist.d.ts +55 -0
- package/dist/onboarding-checklist/onboarding-checklist.js +577 -0
- package/dist/onboarding-checklist/onboarding-checklist.js.map +1 -0
- package/dist/page-header/index.d.ts +2 -0
- package/dist/page-header/index.js +2 -0
- package/dist/page-header/page-header.d.ts +75 -0
- package/dist/page-header/page-header.js +83 -0
- package/dist/page-header/page-header.js.map +1 -0
- package/dist/password-field/index.d.ts +2 -0
- package/dist/password-field/index.js +2 -0
- package/dist/password-field/password-field.d.ts +37 -0
- package/dist/password-field/password-field.js +101 -0
- package/dist/password-field/password-field.js.map +1 -0
- package/dist/password-strength/index.d.ts +2 -0
- package/dist/password-strength/index.js +2 -0
- package/dist/password-strength/password-strength.d.ts +127 -0
- package/dist/password-strength/password-strength.js +455 -0
- package/dist/password-strength/password-strength.js.map +1 -0
- package/dist/phone-input/index.d.ts +3 -0
- package/dist/phone-input/index.js +3 -0
- package/dist/phone-input/phone-countries.d.ts +29 -0
- package/dist/phone-input/phone-countries.js +170 -0
- package/dist/phone-input/phone-countries.js.map +1 -0
- package/dist/phone-input/phone-input.d.ts +66 -0
- package/dist/phone-input/phone-input.js +440 -0
- package/dist/phone-input/phone-input.js.map +1 -0
- package/dist/popover/popover.d.ts +20 -0
- package/dist/popover/popover.js +33 -9
- package/dist/popover/popover.js.map +1 -1
- package/dist/progress/progress.js +46 -5
- package/dist/progress/progress.js.map +1 -1
- package/dist/radio-group/radio-group.js +8 -7
- package/dist/radio-group/radio-group.js.map +1 -1
- package/dist/reactions/index.d.ts +2 -0
- package/dist/reactions/index.js +2 -0
- package/dist/reactions/reactions.d.ts +50 -0
- package/dist/reactions/reactions.js +315 -0
- package/dist/reactions/reactions.js.map +1 -0
- package/dist/rich-text-editor/index.d.ts +3 -0
- package/dist/rich-text-editor/index.js +2 -0
- package/dist/rich-text-editor/rich-text-editor.d.ts +70 -0
- package/dist/rich-text-editor/rich-text-editor.js +909 -0
- package/dist/rich-text-editor/rich-text-editor.js.map +1 -0
- package/dist/rich-text-editor/rich-text-engine.d.ts +16 -0
- package/dist/rich-text-editor/rich-text-engine.js +366 -0
- package/dist/rich-text-editor/rich-text-engine.js.map +1 -0
- package/dist/rich-text-editor/rich-text-html.js +174 -0
- package/dist/rich-text-editor/rich-text-html.js.map +1 -0
- package/dist/rich-text-editor/rich-text-icons.js +43 -0
- package/dist/rich-text-editor/rich-text-icons.js.map +1 -0
- package/dist/ridgeline/index.d.ts +2 -0
- package/dist/ridgeline/index.js +2 -0
- package/dist/ridgeline/ridgeline.d.ts +55 -0
- package/dist/ridgeline/ridgeline.js +701 -0
- package/dist/ridgeline/ridgeline.js.map +1 -0
- package/dist/scroll-area/index.d.ts +2 -2
- package/dist/scroll-area/index.js +2 -2
- package/dist/scroll-area/scroll-area.d.ts +75 -28
- package/dist/scroll-area/scroll-area.js +212 -41
- package/dist/scroll-area/scroll-area.js.map +1 -1
- package/dist/scrub-input/evaluate.d.ts +14 -0
- package/dist/scrub-input/evaluate.js +72 -0
- package/dist/scrub-input/evaluate.js.map +1 -0
- package/dist/scrub-input/index.d.ts +3 -0
- package/dist/scrub-input/index.js +3 -0
- package/dist/scrub-input/scrub-input.d.ts +74 -0
- package/dist/scrub-input/scrub-input.js +486 -0
- package/dist/scrub-input/scrub-input.js.map +1 -0
- package/dist/search-field/index.d.ts +2 -0
- package/dist/search-field/index.js +2 -0
- package/dist/search-field/search-field.d.ts +27 -0
- package/dist/search-field/search-field.js +155 -0
- package/dist/search-field/search-field.js.map +1 -0
- package/dist/select/select.d.ts +3 -1
- package/dist/select/select.js +95 -25
- package/dist/select/select.js.map +1 -1
- package/dist/separator/separator.d.ts +1 -1
- package/dist/sheet/sheet.js +4 -2
- package/dist/sheet/sheet.js.map +1 -1
- package/dist/shortcut-recorder/index.d.ts +3 -0
- package/dist/shortcut-recorder/index.js +3 -0
- package/dist/shortcut-recorder/shortcut-model.d.ts +27 -0
- package/dist/shortcut-recorder/shortcut-model.js +206 -0
- package/dist/shortcut-recorder/shortcut-model.js.map +1 -0
- package/dist/shortcut-recorder/shortcut-recorder.d.ts +93 -0
- package/dist/shortcut-recorder/shortcut-recorder.js +489 -0
- package/dist/shortcut-recorder/shortcut-recorder.js.map +1 -0
- package/dist/side-nav/index.d.ts +2 -0
- package/dist/side-nav/index.js +2 -0
- package/dist/side-nav/side-nav.d.ts +72 -0
- package/dist/side-nav/side-nav.js +142 -0
- package/dist/side-nav/side-nav.js.map +1 -0
- package/dist/skeleton/skeleton.d.ts +8 -2
- package/dist/skeleton/skeleton.js +6 -2
- package/dist/skeleton/skeleton.js.map +1 -1
- package/dist/slider/index.d.ts +2 -2
- package/dist/slider/slider.d.ts +46 -14
- package/dist/slider/slider.js +188 -50
- package/dist/slider/slider.js.map +1 -1
- package/dist/slope-chart/index.d.ts +2 -0
- package/dist/slope-chart/index.js +2 -0
- package/dist/slope-chart/slope-chart.d.ts +54 -0
- package/dist/slope-chart/slope-chart.js +568 -0
- package/dist/slope-chart/slope-chart.js.map +1 -0
- package/dist/sparkline/index.d.ts +2 -0
- package/dist/sparkline/index.js +2 -0
- package/dist/sparkline/sparkline.d.ts +46 -0
- package/dist/sparkline/sparkline.js +390 -0
- package/dist/sparkline/sparkline.js.map +1 -0
- package/dist/split-bar/index.d.ts +2 -0
- package/dist/split-bar/index.js +2 -0
- package/dist/split-bar/split-bar.d.ts +62 -0
- package/dist/split-bar/split-bar.js +513 -0
- package/dist/split-bar/split-bar.js.map +1 -0
- package/dist/split-button/index.d.ts +2 -0
- package/dist/split-button/index.js +2 -0
- package/dist/split-button/split-button.d.ts +46 -0
- package/dist/split-button/split-button.js +123 -0
- package/dist/split-button/split-button.js.map +1 -0
- package/dist/stat-card/index.d.ts +2 -0
- package/dist/stat-card/index.js +2 -0
- package/dist/stat-card/stat-card.d.ts +101 -0
- package/dist/stat-card/stat-card.js +249 -0
- package/dist/stat-card/stat-card.js.map +1 -0
- package/dist/stepper/index.d.ts +2 -0
- package/dist/stepper/index.js +2 -0
- package/dist/stepper/stepper.d.ts +51 -0
- package/dist/stepper/stepper.js +215 -0
- package/dist/stepper/stepper.js.map +1 -0
- package/dist/streamgraph/index.d.ts +2 -0
- package/dist/streamgraph/index.js +2 -0
- package/dist/streamgraph/streamgraph.d.ts +70 -0
- package/dist/streamgraph/streamgraph.js +613 -0
- package/dist/streamgraph/streamgraph.js.map +1 -0
- package/dist/styles.css +1 -1
- package/dist/swipe-actions/index.d.ts +2 -0
- package/dist/swipe-actions/index.js +2 -0
- package/dist/swipe-actions/swipe-actions.d.ts +67 -0
- package/dist/swipe-actions/swipe-actions.js +552 -0
- package/dist/swipe-actions/swipe-actions.js.map +1 -0
- package/dist/switch/switch.js +10 -9
- package/dist/switch/switch.js.map +1 -1
- package/dist/table/index.d.ts +2 -2
- package/dist/table/index.js +2 -2
- package/dist/table/table.d.ts +87 -4
- package/dist/table/table.js +441 -165
- package/dist/table/table.js.map +1 -1
- package/dist/tabs/tabs.js +143 -7
- package/dist/tabs/tabs.js.map +1 -1
- package/dist/tag-input/index.d.ts +2 -0
- package/dist/tag-input/index.js +2 -0
- package/dist/tag-input/tag-input.d.ts +40 -0
- package/dist/tag-input/tag-input.js +269 -0
- package/dist/tag-input/tag-input.js.map +1 -0
- package/dist/text-morph/index.d.ts +2 -0
- package/dist/text-morph/index.js +2 -0
- package/dist/text-morph/text-morph.d.ts +23 -0
- package/dist/text-morph/text-morph.js +21 -0
- package/dist/text-morph/text-morph.js.map +1 -0
- package/dist/text-reveal/index.d.ts +2 -0
- package/dist/text-reveal/index.js +2 -0
- package/dist/text-reveal/text-reveal.d.ts +27 -0
- package/dist/text-reveal/text-reveal.js +51 -0
- package/dist/text-reveal/text-reveal.js.map +1 -0
- package/dist/text-shimmer/index.d.ts +2 -0
- package/dist/text-shimmer/index.js +2 -0
- package/dist/text-shimmer/text-shimmer.d.ts +29 -0
- package/dist/text-shimmer/text-shimmer.js +29 -0
- package/dist/text-shimmer/text-shimmer.js.map +1 -0
- package/dist/textarea/textarea.d.ts +23 -0
- package/dist/textarea/textarea.js +24 -2
- package/dist/textarea/textarea.js.map +1 -1
- package/dist/theme-switch/index.d.ts +2 -0
- package/dist/theme-switch/index.js +2 -0
- package/dist/theme-switch/theme-switch.d.ts +37 -0
- package/dist/theme-switch/theme-switch.js +123 -0
- package/dist/theme-switch/theme-switch.js.map +1 -0
- package/dist/time-picker/index.d.ts +2 -0
- package/dist/time-picker/index.js +2 -0
- package/dist/time-picker/time-picker.d.ts +54 -0
- package/dist/time-picker/time-picker.js +201 -0
- package/dist/time-picker/time-picker.js.map +1 -0
- package/dist/toast/index.d.ts +2 -2
- package/dist/toast/index.js +2 -2
- package/dist/toast/toast.d.ts +6 -0
- package/dist/toast/toast.js +98 -36
- package/dist/toast/toast.js.map +1 -1
- package/dist/tooltip/tooltip.d.ts +10 -3
- package/dist/tooltip/tooltip.js +67 -18
- package/dist/tooltip/tooltip.js.map +1 -1
- package/dist/treemap/index.d.ts +2 -0
- package/dist/treemap/index.js +2 -0
- package/dist/treemap/treemap.d.ts +53 -0
- package/dist/treemap/treemap.js +699 -0
- package/dist/treemap/treemap.js.map +1 -0
- package/dist/usage-meter/index.d.ts +2 -0
- package/dist/usage-meter/index.js +2 -0
- package/dist/usage-meter/usage-meter.d.ts +50 -0
- package/dist/usage-meter/usage-meter.js +440 -0
- package/dist/usage-meter/usage-meter.js.map +1 -0
- package/dist/waffle-chart/index.d.ts +2 -0
- package/dist/waffle-chart/index.js +2 -0
- package/dist/waffle-chart/waffle-chart.d.ts +57 -0
- package/dist/waffle-chart/waffle-chart.js +426 -0
- package/dist/waffle-chart/waffle-chart.js.map +1 -0
- package/package.json +245 -3
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"textarea.js","names":["AriaTextArea"],"sources":["../../src/textarea/textarea.tsx"],"sourcesContent":["\"use client\";\n\nimport { cva } from \"class-variance-authority\";\nimport { forwardRef } from \"react\";\nimport {\n TextArea as AriaTextArea,\n type TextAreaProps as AriaTextAreaProps,\n} from \"react-aria-components\";\n\nimport { cn } from \"../lib/cn.js\";\nimport { fieldSurfaceVariants } from \"../lib/field-surface.js\";\n\n/**\n * Textarea, ported from the legacy component onto React Aria's TextArea.\n *\n * Census: 3 files, 3 uses -- `value`, `onChange`, `placeholder`, `id`,\n * `ref`. All native props, all still native here.\n *\n * The surface comes from `fieldSurfaceVariants`, shared with Input. The two\n * legacy files styled it separately and had already drifted -- different\n * background, different focus ring, invalid styling on one and not the\n * other -- and none of those differences was a decision anyone made.\n */\nexport const textareaVariants = cva([\n fieldSurfaceVariants(),\n\n // min-h-20 is 80px, the legacy min-h-[80px] -- but as a spacing-scale step\n // rather than a bracket value, which check:hardcoding rejects.\n \"min-h-20\",\n \"px-(--density-control-pad-md) py-(--density-control-pad-sm)\",\n \"text-base\",\n\n // A textarea is resizable by the user agent, and horizontal resize breaks\n // any layout it sits in. Vertical only.\n \"resize-y\",\n // Height is content, not a control slot, so the line-height has to be set\n // explicitly -- unset it computes to `normal`, which varies with the\n // font's own metrics.\n \"leading-(--leading-normal)\",\n]);\n\n/**\n * A multi-line text field.\n *\n * @example\n * <Textarea placeholder=\"Tell us more\" value={v} onChange={e => set(e.target.value)} />\n */\nexport interface TextareaProps extends Omit<AriaTextAreaProps, \"className\" | \"style\"> {\n /** Extra classes. Merged last, so they win conflicts with ours. */\n className?: string;\n}\n\nexport const Textarea = forwardRef<HTMLTextAreaElement, TextareaProps>(function Textarea(\n
|
|
1
|
+
{"version":3,"file":"textarea.js","names":["AriaTextArea"],"sources":["../../src/textarea/textarea.tsx"],"sourcesContent":["\"use client\";\n\nimport { cva } from \"class-variance-authority\";\nimport { forwardRef, type ReactNode } from \"react\";\nimport {\n TextArea as AriaTextArea,\n type TextAreaProps as AriaTextAreaProps,\n} from \"react-aria-components\";\n\nimport { cn } from \"../lib/cn.js\";\nimport { FieldShell, hasFieldProps, useFieldWiring } from \"../lib/field-shell.js\";\nimport { fieldSurfaceVariants } from \"../lib/field-surface.js\";\n\n/**\n * Textarea, ported from the legacy component onto React Aria's TextArea.\n *\n * Census: 3 files, 3 uses -- `value`, `onChange`, `placeholder`, `id`,\n * `ref`. All native props, all still native here.\n *\n * The surface comes from `fieldSurfaceVariants`, shared with Input. The two\n * legacy files styled it separately and had already drifted -- different\n * background, different focus ring, invalid styling on one and not the\n * other -- and none of those differences was a decision anyone made.\n */\nexport const textareaVariants = cva([\n fieldSurfaceVariants(),\n\n // min-h-20 is 80px, the legacy min-h-[80px] -- but as a spacing-scale step\n // rather than a bracket value, which check:hardcoding rejects.\n \"min-h-20\",\n \"px-(--density-control-pad-md) py-(--density-control-pad-sm)\",\n \"text-base\",\n\n // A textarea is resizable by the user agent, and horizontal resize breaks\n // any layout it sits in. Vertical only.\n \"resize-y\",\n // Height is content, not a control slot, so the line-height has to be set\n // explicitly -- unset it computes to `normal`, which varies with the\n // font's own metrics.\n \"leading-(--leading-normal)\",\n]);\n\n/**\n * A multi-line text field.\n *\n * @example\n * <Textarea placeholder=\"Tell us more\" value={v} onChange={e => set(e.target.value)} />\n */\nexport interface TextareaProps extends Omit<AriaTextAreaProps, \"className\" | \"style\"> {\n /** Extra classes. Merged last, so they win conflicts with ours. */\n className?: string;\n /**\n * A visible label above the field, tied to it with `htmlFor`. Passing any of\n * `label`, `description` or `error` (even as `undefined`) wraps the field;\n * with none of them the DOM is exactly the bare textarea. Do not also pass\n * `aria-label`: it wins over the label (WCAG 2.5.3). Ignored inside a React\n * Aria `TextField`, which supplies its own label and messages.\n */\n label?: ReactNode;\n /**\n * Helper text under the field, named by `aria-describedby`. A count in it,\n * such as \"12/200 characters\", rolls digit by digit as it changes. Opens on a\n * spring when it appears after mount; nothing animates on first render, and\n * reduced motion swaps it instantly. A string, because the copy is animated\n * word by word.\n */\n description?: string;\n /**\n * Error text under the field. Sets `aria-invalid`, so the field takes its\n * invalid border, and is announced as an alert when it appears. An empty or\n * `undefined` value closes the row.\n */\n error?: string;\n}\n\nexport const Textarea = forwardRef<HTMLTextAreaElement, TextareaProps>(\n function Textarea(allProps, ref) {\n const { className, label, description, error, ...props } = allProps;\n const field = useFieldWiring({\n enabled: hasFieldProps(allProps),\n id: props.id,\n describedBy: props[\"aria-describedby\"],\n invalid: props[\"aria-invalid\"],\n description,\n error,\n });\n const textarea = (\n <AriaTextArea\n ref={ref}\n {...props}\n {...field.controlProps}\n data-slot=\"textarea\"\n className={cn(textareaVariants(), className)}\n />\n );\n if (!field.active) return textarea;\n return (\n <FieldShell\n label={label}\n controlId={field.controlId}\n description={description}\n hintId={field.hintId}\n error={error}\n errorId={field.errorId}\n wordExit=\"quick\"\n >\n {textarea}\n </FieldShell>\n );\n },\n);\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAwBA,MAAa,mBAAmB,IAAI;CAClC,qBAAqB;CAIrB;CACA;CACA;CAIA;CAIA;AACF,CAAC;AAmCD,MAAa,WAAW,WACtB,SAAS,SAAS,UAAU,KAAK;CAC/B,MAAM,EAAE,WAAW,OAAO,aAAa,OAAO,GAAG,UAAU;CAC3D,MAAM,QAAQ,eAAe;EAC3B,SAAS,cAAc,QAAQ;EAC/B,IAAI,MAAM;EACV,aAAa,MAAM;EACnB,SAAS,MAAM;EACf;EACA;CACF,CAAC;CACD,MAAM,WACJ,oBAACA,UAAD;EACO;EACL,GAAI;EACJ,GAAI,MAAM;EACV,aAAU;EACV,WAAW,GAAG,iBAAiB,GAAG,SAAS;CAC5C,CAAA;CAEH,IAAI,CAAC,MAAM,QAAQ,OAAO;CAC1B,OACE,oBAAC,YAAD;EACS;EACP,WAAW,MAAM;EACJ;EACb,QAAQ,MAAM;EACP;EACP,SAAS,MAAM;EACf,UAAS;EAER,UAAA;CACS,CAAA;AAEhB,CACF"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
//#region src/theme-switch/theme-switch.d.ts
|
|
2
|
+
export type Theme = "light" | "dark";
|
|
3
|
+
/** Which way the page transition travels. The switch nudges its icon the same way; the transition itself is the caller's. */
|
|
4
|
+
export type ThemeSwitchVariant = "reveal" | "eclipse" | "split" | "rise";
|
|
5
|
+
export interface ThemeSwitchProps {
|
|
6
|
+
/** The current theme. The switch shows the icon for it and offers the other. */
|
|
7
|
+
theme: Theme;
|
|
8
|
+
/** @default "reveal" */
|
|
9
|
+
variant?: ThemeSwitchVariant;
|
|
10
|
+
/**
|
|
11
|
+
* Called when the switch is pressed, with the theme to move to, the variant,
|
|
12
|
+
* and the button (the origin a page transition can grow from). The component
|
|
13
|
+
* does not change the theme itself: it is controlled.
|
|
14
|
+
*/
|
|
15
|
+
onThemeChange: (next: Theme, variant: ThemeSwitchVariant, trigger: HTMLElement) => void;
|
|
16
|
+
/** The accessible name. @default "Switch to light mode" / "Switch to dark mode" */
|
|
17
|
+
label?: string;
|
|
18
|
+
/** Only the icon, a square button. @default false */
|
|
19
|
+
iconOnly?: boolean;
|
|
20
|
+
/** Extra classes. Merged last, so they win conflicts with ours. */
|
|
21
|
+
className?: string;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* A light/dark switch. The sun and the moon turn the same way, clockwise into
|
|
25
|
+
* dark and back out of it, so the swap reads as one rotation; the icon is
|
|
26
|
+
* nudged the way the page transition travels (`variant`) and eases back when
|
|
27
|
+
* the theme returns.
|
|
28
|
+
*
|
|
29
|
+
* Controlled: it shows `theme` and calls `onThemeChange`; it never changes
|
|
30
|
+
* the theme itself, so the page transition can run in the caller.
|
|
31
|
+
*
|
|
32
|
+
* @example
|
|
33
|
+
* <ThemeSwitch theme={theme} onThemeChange={(next) => setTheme(next)} />
|
|
34
|
+
*/
|
|
35
|
+
export declare const ThemeSwitch: import("react").ForwardRefExoticComponent<ThemeSwitchProps & import("react").RefAttributes<HTMLButtonElement>>;
|
|
36
|
+
//#endregion
|
|
37
|
+
//# sourceMappingURL=theme-switch.d.ts.map
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { cn } from "../lib/cn.js";
|
|
3
|
+
import { pressScaleFor, useExitBackstop, useLeavingItems } from "../lib/motion.js";
|
|
4
|
+
import { buttonVariants } from "../button/button.js";
|
|
5
|
+
import { forwardRef, useCallback, useEffect, useRef, useState } from "react";
|
|
6
|
+
import { Button } from "react-aria-components";
|
|
7
|
+
import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
|
|
8
|
+
//#region src/theme-switch/theme-switch.tsx
|
|
9
|
+
/**
|
|
10
|
+
* A stored preference usually reaches the theme prop just after hydration. That
|
|
11
|
+
* correction swaps the icon in place; only changes after the first painted
|
|
12
|
+
* frames animate, so a page that loads in dark mode never spins its switches.
|
|
13
|
+
*/
|
|
14
|
+
function useSettled() {
|
|
15
|
+
const [settled, setSettled] = useState(false);
|
|
16
|
+
useEffect(() => {
|
|
17
|
+
let second = 0;
|
|
18
|
+
const first = requestAnimationFrame(() => {
|
|
19
|
+
second = requestAnimationFrame(() => setSettled(true));
|
|
20
|
+
});
|
|
21
|
+
return () => {
|
|
22
|
+
cancelAnimationFrame(first);
|
|
23
|
+
cancelAnimationFrame(second);
|
|
24
|
+
};
|
|
25
|
+
}, []);
|
|
26
|
+
return settled;
|
|
27
|
+
}
|
|
28
|
+
const ANGLE = {
|
|
29
|
+
light: "30deg",
|
|
30
|
+
dark: "-30deg"
|
|
31
|
+
};
|
|
32
|
+
function Icon({ theme }) {
|
|
33
|
+
return /* @__PURE__ */ jsx("svg", {
|
|
34
|
+
viewBox: "0 0 24 24",
|
|
35
|
+
fill: "none",
|
|
36
|
+
stroke: "currentColor",
|
|
37
|
+
strokeWidth: 1.75,
|
|
38
|
+
strokeLinecap: "round",
|
|
39
|
+
strokeLinejoin: "round",
|
|
40
|
+
"aria-hidden": "true",
|
|
41
|
+
className: "size-4",
|
|
42
|
+
children: theme === "light" ? /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx("circle", {
|
|
43
|
+
cx: "12",
|
|
44
|
+
cy: "12",
|
|
45
|
+
r: "4"
|
|
46
|
+
}), /* @__PURE__ */ jsx("path", { d: "M12 2v2M12 20v2m-7.07-17.07 1.41 1.41m11.32 11.32 1.41 1.41M2 12h2m16 0h2M6.34 17.66l-1.41 1.41M19.07 4.93l-1.41 1.41" })] }) : /* @__PURE__ */ jsx("path", { d: "M12 3a6 6 0 0 0 9 9 9 9 0 1 1-9-9Z" })
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
function LeavingIcon({ id, theme, settled, onDone }) {
|
|
50
|
+
const remove = useCallback(() => onDone(id), [onDone, id]);
|
|
51
|
+
useExitBackstop(true, remove);
|
|
52
|
+
useEffect(() => {
|
|
53
|
+
if (!settled) remove();
|
|
54
|
+
}, [settled, remove]);
|
|
55
|
+
if (!settled) return null;
|
|
56
|
+
return /* @__PURE__ */ jsx("span", {
|
|
57
|
+
"aria-hidden": "true",
|
|
58
|
+
onAnimationEnd: (event) => {
|
|
59
|
+
if (event.target === event.currentTarget) remove();
|
|
60
|
+
},
|
|
61
|
+
style: { "--theme-angle": ANGLE[theme] },
|
|
62
|
+
className: "absolute grid size-4 place-items-center motion-safe:animate-theme-icon-out motion-reduce:animate-fade-out",
|
|
63
|
+
children: /* @__PURE__ */ jsx(Icon, { theme })
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* A light/dark switch. The sun and the moon turn the same way, clockwise into
|
|
68
|
+
* dark and back out of it, so the swap reads as one rotation; the icon is
|
|
69
|
+
* nudged the way the page transition travels (`variant`) and eases back when
|
|
70
|
+
* the theme returns.
|
|
71
|
+
*
|
|
72
|
+
* Controlled: it shows `theme` and calls `onThemeChange`; it never changes
|
|
73
|
+
* the theme itself, so the page transition can run in the caller.
|
|
74
|
+
*
|
|
75
|
+
* @example
|
|
76
|
+
* <ThemeSwitch theme={theme} onThemeChange={(next) => setTheme(next)} />
|
|
77
|
+
*/
|
|
78
|
+
const ThemeSwitch = forwardRef(function ThemeSwitch({ theme, variant = "reveal", onThemeChange, label, iconOnly = false, className }, ref) {
|
|
79
|
+
const settled = useSettled();
|
|
80
|
+
const next = theme === "light" ? "dark" : "light";
|
|
81
|
+
const phaseRef = useRef(null);
|
|
82
|
+
const { leaving, changed, remove } = useLeavingItems(theme, theme, () => phaseRef.current);
|
|
83
|
+
const pressStart = (event) => {
|
|
84
|
+
const target = event.target;
|
|
85
|
+
target.style.setProperty("--press-scale", pressScaleFor(target.offsetWidth));
|
|
86
|
+
};
|
|
87
|
+
return /* @__PURE__ */ jsxs(Button, {
|
|
88
|
+
ref,
|
|
89
|
+
"data-slot": "button",
|
|
90
|
+
"data-mode": theme,
|
|
91
|
+
"data-variant": variant,
|
|
92
|
+
"aria-label": label ?? "Switch to " + next + " mode",
|
|
93
|
+
"aria-pressed": theme === "dark",
|
|
94
|
+
onPressStart: pressStart,
|
|
95
|
+
onPress: (event) => onThemeChange(next, variant, event.target),
|
|
96
|
+
className: cn(buttonVariants({
|
|
97
|
+
variant: "outlineNeutral",
|
|
98
|
+
size: "sm"
|
|
99
|
+
}) + (iconOnly ? " w-(--density-control-h-sm) px-0" : ""), className),
|
|
100
|
+
children: [/* @__PURE__ */ jsxs("span", {
|
|
101
|
+
"data-settled": settled || void 0,
|
|
102
|
+
className: "theme-nudge relative inline-grid size-5 shrink-0 place-items-center",
|
|
103
|
+
children: [leaving.map((item) => /* @__PURE__ */ jsx(LeavingIcon, {
|
|
104
|
+
id: item.id,
|
|
105
|
+
theme: item.value,
|
|
106
|
+
settled,
|
|
107
|
+
onDone: remove
|
|
108
|
+
}, item.id)), /* @__PURE__ */ jsx("span", {
|
|
109
|
+
ref: phaseRef,
|
|
110
|
+
style: { "--theme-angle": ANGLE[theme] },
|
|
111
|
+
className: cn("absolute grid size-4 place-items-center", changed && settled && "motion-safe:animate-theme-icon-in motion-reduce:animate-fade-in"),
|
|
112
|
+
children: /* @__PURE__ */ jsx(Icon, { theme })
|
|
113
|
+
}, theme)]
|
|
114
|
+
}), iconOnly ? null : /* @__PURE__ */ jsx("span", {
|
|
115
|
+
className: "whitespace-nowrap",
|
|
116
|
+
children: "Switch theme"
|
|
117
|
+
})]
|
|
118
|
+
});
|
|
119
|
+
});
|
|
120
|
+
//#endregion
|
|
121
|
+
export { ThemeSwitch };
|
|
122
|
+
|
|
123
|
+
//# sourceMappingURL=theme-switch.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"theme-switch.js","names":["AriaButton"],"sources":["../../src/theme-switch/theme-switch.tsx"],"sourcesContent":["\"use client\";\n\nimport { forwardRef, useCallback, useEffect, useRef, useState } from \"react\";\nimport { Button as AriaButton, type PressEvent } from \"react-aria-components\";\n\nimport { buttonVariants } from \"../button/button.js\";\nimport { cn } from \"../lib/cn.js\";\nimport { pressScaleFor, useExitBackstop, useLeavingItems } from \"../lib/motion.js\";\n\nexport type Theme = \"light\" | \"dark\";\n/** Which way the page transition travels. The switch nudges its icon the same way; the transition itself is the caller's. */\nexport type ThemeSwitchVariant = \"reveal\" | \"eclipse\" | \"split\" | \"rise\";\n\nexport interface ThemeSwitchProps {\n /** The current theme. The switch shows the icon for it and offers the other. */\n theme: Theme;\n /** @default \"reveal\" */\n variant?: ThemeSwitchVariant;\n /**\n * Called when the switch is pressed, with the theme to move to, the variant,\n * and the button (the origin a page transition can grow from). The component\n * does not change the theme itself: it is controlled.\n */\n onThemeChange: (next: Theme, variant: ThemeSwitchVariant, trigger: HTMLElement) => void;\n /** The accessible name. @default \"Switch to light mode\" / \"Switch to dark mode\" */\n label?: string;\n /** Only the icon, a square button. @default false */\n iconOnly?: boolean;\n /** Extra classes. Merged last, so they win conflicts with ours. */\n className?: string;\n}\n\n/**\n * A stored preference usually reaches the theme prop just after hydration. That\n * correction swaps the icon in place; only changes after the first painted\n * frames animate, so a page that loads in dark mode never spins its switches.\n */\nfunction useSettled() {\n const [settled, setSettled] = useState(false);\n useEffect(() => {\n let second = 0;\n const first = requestAnimationFrame(() => {\n second = requestAnimationFrame(() => setSettled(true));\n });\n return () => {\n cancelAnimationFrame(first);\n cancelAnimationFrame(second);\n };\n }, []);\n return settled;\n}\n\nconst ANGLE = { light: \"30deg\", dark: \"-30deg\" } as const;\n\nfunction Icon({ theme }: { theme: Theme }) {\n return (\n <svg\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth={1.75}\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n aria-hidden=\"true\"\n className=\"size-4\"\n >\n {theme === \"light\" ? (\n <>\n <circle cx=\"12\" cy=\"12\" r=\"4\" />\n <path d=\"M12 2v2M12 20v2m-7.07-17.07 1.41 1.41m11.32 11.32 1.41 1.41M2 12h2m16 0h2M6.34 17.66l-1.41 1.41M19.07 4.93l-1.41 1.41\" />\n </>\n ) : (\n <path d=\"M12 3a6 6 0 0 0 9 9 9 9 0 1 1-9-9Z\" />\n )}\n </svg>\n );\n}\n\nfunction LeavingIcon({\n id,\n theme,\n settled,\n onDone,\n}: {\n id: number;\n theme: Theme;\n settled: boolean;\n onDone: (id: number) => void;\n}) {\n const remove = useCallback(() => onDone(id), [onDone, id]);\n useExitBackstop(true, remove);\n // Before the switch has settled there is nothing to animate: the old icon is simply gone.\n useEffect(() => {\n if (!settled) remove();\n }, [settled, remove]);\n if (!settled) return null;\n return (\n <span\n aria-hidden=\"true\"\n onAnimationEnd={(event) => {\n if (event.target === event.currentTarget) remove();\n }}\n style={{ \"--theme-angle\": ANGLE[theme] } as React.CSSProperties}\n className=\"absolute grid size-4 place-items-center motion-safe:animate-theme-icon-out motion-reduce:animate-fade-out\"\n >\n <Icon theme={theme} />\n </span>\n );\n}\n\n/**\n * A light/dark switch. The sun and the moon turn the same way, clockwise into\n * dark and back out of it, so the swap reads as one rotation; the icon is\n * nudged the way the page transition travels (`variant`) and eases back when\n * the theme returns.\n *\n * Controlled: it shows `theme` and calls `onThemeChange`; it never changes\n * the theme itself, so the page transition can run in the caller.\n *\n * @example\n * <ThemeSwitch theme={theme} onThemeChange={(next) => setTheme(next)} />\n */\nexport const ThemeSwitch = forwardRef<HTMLButtonElement, ThemeSwitchProps>(function ThemeSwitch(\n { theme, variant = \"reveal\", onThemeChange, label, iconOnly = false, className },\n ref,\n) {\n const settled = useSettled();\n const next: Theme = theme === \"light\" ? \"dark\" : \"light\";\n const phaseRef = useRef<HTMLSpanElement>(null);\n const { leaving, changed, remove } = useLeavingItems<Theme>(theme, theme, () => phaseRef.current);\n\n const pressStart = (event: PressEvent) => {\n const target = event.target as HTMLElement;\n target.style.setProperty(\"--press-scale\", pressScaleFor(target.offsetWidth));\n };\n\n return (\n <AriaButton\n ref={ref}\n data-slot=\"button\"\n data-mode={theme}\n data-variant={variant}\n aria-label={label ?? \"Switch to \" + next + \" mode\"}\n aria-pressed={theme === \"dark\"}\n onPressStart={pressStart}\n onPress={(event) => onThemeChange(next, variant, event.target as HTMLElement)}\n className={cn(\n buttonVariants({ variant: \"outlineNeutral\", size: \"sm\" }) +\n (iconOnly ? \" w-(--density-control-h-sm) px-0\" : \"\"),\n className,\n )}\n >\n <span\n data-settled={settled || undefined}\n className=\"theme-nudge relative inline-grid size-5 shrink-0 place-items-center\"\n >\n {leaving.map((item) => (\n <LeavingIcon\n key={item.id}\n id={item.id}\n theme={item.value}\n settled={settled}\n onDone={remove}\n />\n ))}\n <span\n key={theme}\n ref={phaseRef}\n style={{ \"--theme-angle\": ANGLE[theme] } as React.CSSProperties}\n className={cn(\n \"absolute grid size-4 place-items-center\",\n changed && settled && \"motion-safe:animate-theme-icon-in motion-reduce:animate-fade-in\",\n )}\n >\n <Icon theme={theme} />\n </span>\n </span>\n {iconOnly ? null : <span className=\"whitespace-nowrap\">Switch theme</span>}\n </AriaButton>\n );\n});\n"],"mappings":";;;;;;;;;;;;;AAqCA,SAAS,aAAa;CACpB,MAAM,CAAC,SAAS,cAAc,SAAS,KAAK;CAC5C,gBAAgB;EACd,IAAI,SAAS;EACb,MAAM,QAAQ,4BAA4B;GACxC,SAAS,4BAA4B,WAAW,IAAI,CAAC;EACvD,CAAC;EACD,aAAa;GACX,qBAAqB,KAAK;GAC1B,qBAAqB,MAAM;EAC7B;CACF,GAAG,CAAC,CAAC;CACL,OAAO;AACT;AAEA,MAAM,QAAQ;CAAE,OAAO;CAAS,MAAM;AAAS;AAE/C,SAAS,KAAK,EAAE,SAA2B;CACzC,OACE,oBAAC,OAAD;EACE,SAAQ;EACR,MAAK;EACL,QAAO;EACP,aAAa;EACb,eAAc;EACd,gBAAe;EACf,eAAY;EACZ,WAAU;EAET,UAAA,UAAU,UACT,qBAAA,YAAA,EAAA,UAAA,CACE,oBAAC,UAAD;GAAQ,IAAG;GAAK,IAAG;GAAK,GAAE;EAAK,CAAA,GAC/B,oBAAC,QAAD,EAAM,GAAE,wHAAyH,CAAA,CACjI,EAAA,CAAA,IAEF,oBAAC,QAAD,EAAM,GAAE,qCAAsC,CAAA;CAE7C,CAAA;AAET;AAEA,SAAS,YAAY,EACnB,IACA,OACA,SACA,UAMC;CACD,MAAM,SAAS,kBAAkB,OAAO,EAAE,GAAG,CAAC,QAAQ,EAAE,CAAC;CACzD,gBAAgB,MAAM,MAAM;CAE5B,gBAAgB;EACd,IAAI,CAAC,SAAS,OAAO;CACvB,GAAG,CAAC,SAAS,MAAM,CAAC;CACpB,IAAI,CAAC,SAAS,OAAO;CACrB,OACE,oBAAC,QAAD;EACE,eAAY;EACZ,iBAAiB,UAAU;GACzB,IAAI,MAAM,WAAW,MAAM,eAAe,OAAO;EACnD;EACA,OAAO,EAAE,iBAAiB,MAAM,OAAO;EACvC,WAAU;EAEV,UAAA,oBAAC,MAAD,EAAa,MAAQ,CAAA;CACjB,CAAA;AAEV;;;;;;;;;;;;;AAcA,MAAa,cAAc,WAAgD,SAAS,YAClF,EAAE,OAAO,UAAU,UAAU,eAAe,OAAO,WAAW,OAAO,aACrE,KACA;CACA,MAAM,UAAU,WAAW;CAC3B,MAAM,OAAc,UAAU,UAAU,SAAS;CACjD,MAAM,WAAW,OAAwB,IAAI;CAC7C,MAAM,EAAE,SAAS,SAAS,WAAW,gBAAuB,OAAO,aAAa,SAAS,OAAO;CAEhG,MAAM,cAAc,UAAsB;EACxC,MAAM,SAAS,MAAM;EACrB,OAAO,MAAM,YAAY,iBAAiB,cAAc,OAAO,WAAW,CAAC;CAC7E;CAEA,OACE,qBAACA,QAAD;EACO;EACL,aAAU;EACV,aAAW;EACX,gBAAc;EACd,cAAY,SAAS,eAAe,OAAO;EAC3C,gBAAc,UAAU;EACxB,cAAc;EACd,UAAU,UAAU,cAAc,MAAM,SAAS,MAAM,MAAqB;EAC5E,WAAW,GACT,eAAe;GAAE,SAAS;GAAkB,MAAM;EAAK,CAAC,KACrD,WAAW,qCAAqC,KACnD,SACF;EAbF,UAAA,CAeE,qBAAC,QAAD;GACE,gBAAc,WAAW,KAAA;GACzB,WAAU;GAFZ,UAAA,CAIG,QAAQ,KAAK,SACZ,oBAAC,aAAD;IAEE,IAAI,KAAK;IACT,OAAO,KAAK;IACH;IACT,QAAQ;GACT,GALM,KAAK,EAKX,CACF,GACD,oBAAC,QAAD;IAEE,KAAK;IACL,OAAO,EAAE,iBAAiB,MAAM,OAAO;IACvC,WAAW,GACT,2CACA,WAAW,WAAW,iEACxB;IAEA,UAAA,oBAAC,MAAD,EAAa,MAAQ,CAAA;GACjB,GATC,KASD,CACF;EACL,CAAA,GAAA,WAAW,OAAO,oBAAC,QAAD;GAAM,WAAU;GAAoB,UAAA;EAAkB,CAAA,CAC/D;;AAEhB,CAAC"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { TimeValue } from "react-aria-components";
|
|
2
|
+
//#region src/time-picker/time-picker.d.ts
|
|
3
|
+
/**
|
|
4
|
+
* TimePicker, a field that shows a time and opens a list of times to pick from.
|
|
5
|
+
*
|
|
6
|
+
* Values are `TimeValue` objects from `@internationalized/date`, as Calendar and
|
|
7
|
+
* DatePicker use `DateValue` (ADR 0006), not "HH:MM" strings: a time of day has
|
|
8
|
+
* no time zone or format of its own. Unlike those two, this one builds a `Time`
|
|
9
|
+
* at runtime to hand back, so the package is a real (peer) dependency here and
|
|
10
|
+
* not only a type.
|
|
11
|
+
*
|
|
12
|
+
* The control is a React Aria `Select`, so the list is a listbox with typeahead,
|
|
13
|
+
* arrow keys and a roving highlight; the motion (the value rolling like a clock
|
|
14
|
+
* face, the chevron, the list growing from the field) sits on top of it.
|
|
15
|
+
*/
|
|
16
|
+
/** The list: it grows from the field, and the highlight follows the pointer and the arrows. */
|
|
17
|
+
export declare const timePickerListVariants: (props?: import("class-variance-authority/types").ClassProp | undefined) => string;
|
|
18
|
+
/** A time. The highlight changes almost at once (the arrows move it often); a dot marks the chosen one. */
|
|
19
|
+
export declare const timePickerItemVariants: (props?: import("class-variance-authority/types").ClassProp | undefined) => string;
|
|
20
|
+
export interface TimePickerProps {
|
|
21
|
+
/** What is being chosen, and the control's accessible name. Required, as on Select. */
|
|
22
|
+
label: string;
|
|
23
|
+
/** Render the label for screen readers only. */
|
|
24
|
+
labelHidden?: boolean;
|
|
25
|
+
/** Help text under the control, named in `aria-describedby`. */
|
|
26
|
+
description?: string;
|
|
27
|
+
/** Shown while no time is chosen. @default "Select a time" */
|
|
28
|
+
placeholder?: string;
|
|
29
|
+
/** The chosen time. Controlled: pass `null` for none. */
|
|
30
|
+
value?: TimeValue | null;
|
|
31
|
+
/** The starting time when uncontrolled. @default null */
|
|
32
|
+
defaultValue?: TimeValue | null;
|
|
33
|
+
/** Called with the chosen time, as a `Time`. */
|
|
34
|
+
onChange?: (value: TimeValue) => void;
|
|
35
|
+
/** Minutes between the times in the list. @default 15 */
|
|
36
|
+
minuteStep?: 1 | 5 | 10 | 15 | 30;
|
|
37
|
+
/** 12-hour (9:00 AM) or 24-hour (09:00) times. @default 12 */
|
|
38
|
+
hourCycle?: 12 | 24;
|
|
39
|
+
/** Control scale of the trigger. @default "md" */
|
|
40
|
+
size?: "sm" | "md" | "lg";
|
|
41
|
+
/** Disable the control. */
|
|
42
|
+
isDisabled?: boolean;
|
|
43
|
+
/** Extra classes for the wrapper. Merged last. */
|
|
44
|
+
className?: string;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* A time picker.
|
|
48
|
+
*
|
|
49
|
+
* @example
|
|
50
|
+
* <TimePicker label="Start time" value={time} onChange={setTime} minuteStep={30} />
|
|
51
|
+
*/
|
|
52
|
+
export declare const TimePicker: import("react").ForwardRefExoticComponent<TimePickerProps & import("react").RefAttributes<HTMLButtonElement>>;
|
|
53
|
+
//#endregion
|
|
54
|
+
//# sourceMappingURL=time-picker.d.ts.map
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { cn, cnAll } from "../lib/cn.js";
|
|
3
|
+
import { useIsomorphicLayoutEffect } from "../lib/motion.js";
|
|
4
|
+
import { labelVariants } from "../label/label.js";
|
|
5
|
+
import { RollingValue } from "../lib/rolling-value.js";
|
|
6
|
+
import { selectTriggerVariants, selectVariants } from "../select/select.js";
|
|
7
|
+
import { cva } from "class-variance-authority";
|
|
8
|
+
import { forwardRef, useMemo, useRef, useState } from "react";
|
|
9
|
+
import { Button, Label, ListBox, ListBoxItem, Popover, Select, SelectValue, Text, useLocale } from "react-aria-components";
|
|
10
|
+
import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
|
|
11
|
+
import { Time } from "@internationalized/date";
|
|
12
|
+
//#region src/time-picker/time-picker.tsx
|
|
13
|
+
/**
|
|
14
|
+
* TimePicker, a field that shows a time and opens a list of times to pick from.
|
|
15
|
+
*
|
|
16
|
+
* Values are `TimeValue` objects from `@internationalized/date`, as Calendar and
|
|
17
|
+
* DatePicker use `DateValue` (ADR 0006), not "HH:MM" strings: a time of day has
|
|
18
|
+
* no time zone or format of its own. Unlike those two, this one builds a `Time`
|
|
19
|
+
* at runtime to hand back, so the package is a real (peer) dependency here and
|
|
20
|
+
* not only a type.
|
|
21
|
+
*
|
|
22
|
+
* The control is a React Aria `Select`, so the list is a listbox with typeahead,
|
|
23
|
+
* arrow keys and a roving highlight; the motion (the value rolling like a clock
|
|
24
|
+
* face, the chevron, the list growing from the field) sits on top of it.
|
|
25
|
+
*/
|
|
26
|
+
/** The list: it grows from the field, and the highlight follows the pointer and the arrows. */
|
|
27
|
+
const timePickerListVariants = cva([
|
|
28
|
+
"picker-pop w-(--trigger-width) origin-top overflow-hidden",
|
|
29
|
+
"[--pop-in-y:-6px] [--pop-in-scale:0.97] [--pop-out-y:-4px] [--pop-out-scale:0.98] [--pop-out-duration:120ms]",
|
|
30
|
+
"rounded-panel border-(length:--border-width) border-border p-1",
|
|
31
|
+
"bg-card text-card-foreground shadow-floating",
|
|
32
|
+
"box-border font-sans text-sm leading-(--leading-normal)"
|
|
33
|
+
]);
|
|
34
|
+
/** A time. The highlight changes almost at once (the arrows move it often); a dot marks the chosen one. */
|
|
35
|
+
const timePickerItemVariants = cva([
|
|
36
|
+
"relative flex min-h-9 cursor-pointer select-none items-center justify-between gap-2",
|
|
37
|
+
"rounded-control px-3 py-1.5 tabular-nums outline-none",
|
|
38
|
+
"text-sm leading-(--leading-normal) text-card-foreground",
|
|
39
|
+
"data-[focused]:bg-muted",
|
|
40
|
+
"motion-safe:transition-colors motion-safe:duration-80 motion-safe:ease-settle",
|
|
41
|
+
"data-[focus-visible]:outline-solid data-[focus-visible]:outline-(length:--focus-ring-width)",
|
|
42
|
+
"data-[focus-visible]:outline-offset-(--focus-ring-offset) data-[focus-visible]:outline-(--color-ring)",
|
|
43
|
+
"data-[disabled]:cursor-not-allowed data-[disabled]:opacity-(--opacity-disabled)"
|
|
44
|
+
]);
|
|
45
|
+
const descriptionClass = "text-sm leading-(--leading-normal) text-muted-foreground";
|
|
46
|
+
const pad = (value) => String(value).padStart(2, "0");
|
|
47
|
+
const keyOf = (minutes) => `${pad(Math.floor(minutes / 60))}:${pad(minutes % 60)}`;
|
|
48
|
+
const minutesOf = (value) => value.hour * 60 + value.minute;
|
|
49
|
+
function ClockGlyph() {
|
|
50
|
+
return /* @__PURE__ */ jsxs("svg", {
|
|
51
|
+
"aria-hidden": "true",
|
|
52
|
+
viewBox: "0 0 16 16",
|
|
53
|
+
fill: "none",
|
|
54
|
+
stroke: "currentColor",
|
|
55
|
+
strokeWidth: "1.5",
|
|
56
|
+
strokeLinecap: "round",
|
|
57
|
+
strokeLinejoin: "round",
|
|
58
|
+
className: "text-muted-foreground",
|
|
59
|
+
children: [/* @__PURE__ */ jsx("circle", {
|
|
60
|
+
cx: "8",
|
|
61
|
+
cy: "8",
|
|
62
|
+
r: "5.5"
|
|
63
|
+
}), /* @__PURE__ */ jsx("path", { d: "M8 5v3l2 1.5" })]
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
/** The chevron turns half a turn while the list is open, on the gentle spring. */
|
|
67
|
+
function Chevron() {
|
|
68
|
+
return /* @__PURE__ */ jsx("svg", {
|
|
69
|
+
"aria-hidden": "true",
|
|
70
|
+
viewBox: "0 0 16 16",
|
|
71
|
+
fill: "none",
|
|
72
|
+
stroke: "currentColor",
|
|
73
|
+
strokeWidth: "1.75",
|
|
74
|
+
strokeLinecap: "round",
|
|
75
|
+
strokeLinejoin: "round",
|
|
76
|
+
className: "text-muted-foreground motion-safe:transition-[rotate] motion-safe:duration-(--duration-gentle) motion-safe:ease-gentle group-aria-expanded/trigger:rotate-180",
|
|
77
|
+
children: /* @__PURE__ */ jsx("path", { d: "m4 6 4 4 4-4" })
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* The list of times. It opens centred on the chosen time (or at the top with
|
|
82
|
+
* none), before the first frame, so there is no scroll to watch; the arrow keys
|
|
83
|
+
* then keep the highlight in view, which React Aria does.
|
|
84
|
+
*/
|
|
85
|
+
function CenteredListBox({ children }) {
|
|
86
|
+
const ref = useRef(null);
|
|
87
|
+
useIsomorphicLayoutEffect(() => {
|
|
88
|
+
const list = ref.current;
|
|
89
|
+
const chosen = list?.querySelector("[role=\"option\"][aria-selected=\"true\"]");
|
|
90
|
+
if (!list || !chosen) return;
|
|
91
|
+
list.scrollTop = chosen.offsetTop - (list.clientHeight - chosen.offsetHeight) / 2;
|
|
92
|
+
}, []);
|
|
93
|
+
return /* @__PURE__ */ jsx(ListBox, {
|
|
94
|
+
ref,
|
|
95
|
+
"data-slot": "time-picker-list",
|
|
96
|
+
className: "relative max-h-62.5 overflow-y-auto overscroll-contain outline-none",
|
|
97
|
+
children
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* A time picker.
|
|
102
|
+
*
|
|
103
|
+
* @example
|
|
104
|
+
* <TimePicker label="Start time" value={time} onChange={setTime} minuteStep={30} />
|
|
105
|
+
*/
|
|
106
|
+
const TimePicker = forwardRef(function TimePicker({ label, labelHidden, description, placeholder = "Select a time", value, defaultValue = null, onChange, minuteStep = 15, hourCycle = 12, size = "md", isDisabled, className }, ref) {
|
|
107
|
+
const { locale } = useLocale();
|
|
108
|
+
const [inner, setInner] = useState(defaultValue);
|
|
109
|
+
const current = value === void 0 ? inner : value;
|
|
110
|
+
const minutes = current ? minutesOf(current) : null;
|
|
111
|
+
const key = minutes === null ? null : keyOf(minutes);
|
|
112
|
+
const display = useMemo(() => {
|
|
113
|
+
const format = new Intl.DateTimeFormat(locale, {
|
|
114
|
+
hour: "numeric",
|
|
115
|
+
minute: "2-digit",
|
|
116
|
+
hourCycle: hourCycle === 24 ? "h23" : "h12",
|
|
117
|
+
timeZone: "UTC"
|
|
118
|
+
});
|
|
119
|
+
return (total) => format.format(new Date(Date.UTC(2e3, 0, 1, Math.floor(total / 60), total % 60))).replace(/\u202f/g, " ");
|
|
120
|
+
}, [locale, hourCycle]);
|
|
121
|
+
const options = useMemo(() => {
|
|
122
|
+
const all = Array.from({ length: Math.ceil(1440 / minuteStep) }, (_, i) => i * minuteStep);
|
|
123
|
+
if (minutes !== null && !all.includes(minutes)) all.push(minutes);
|
|
124
|
+
return all.sort((a, b) => a - b);
|
|
125
|
+
}, [minuteStep, minutes]);
|
|
126
|
+
const [previous, setPrevious] = useState(minutes);
|
|
127
|
+
const [dir, setDir] = useState(1);
|
|
128
|
+
if (previous !== minutes) {
|
|
129
|
+
setPrevious(minutes);
|
|
130
|
+
setDir(minutes !== null && previous !== null && minutes < previous ? -1 : 1);
|
|
131
|
+
}
|
|
132
|
+
return /* @__PURE__ */ jsxs(Select, {
|
|
133
|
+
"data-slot": "time-picker",
|
|
134
|
+
selectedKey: key,
|
|
135
|
+
onSelectionChange: (next) => {
|
|
136
|
+
if (next == null) return;
|
|
137
|
+
const [hour = 0, minute = 0] = String(next).split(":").map(Number);
|
|
138
|
+
const time = new Time(hour, minute);
|
|
139
|
+
if (value === void 0) setInner(time);
|
|
140
|
+
onChange?.(time);
|
|
141
|
+
},
|
|
142
|
+
isDisabled,
|
|
143
|
+
placeholder,
|
|
144
|
+
className: cn(selectVariants(), className),
|
|
145
|
+
children: [
|
|
146
|
+
/* @__PURE__ */ jsx(Label, {
|
|
147
|
+
"data-slot": "time-picker-label",
|
|
148
|
+
className: cnAll(labelVariants(), labelHidden && "sr-only"),
|
|
149
|
+
children: label
|
|
150
|
+
}),
|
|
151
|
+
/* @__PURE__ */ jsxs(Button, {
|
|
152
|
+
ref,
|
|
153
|
+
"data-slot": "time-picker-trigger",
|
|
154
|
+
className: selectTriggerVariants({ size }),
|
|
155
|
+
children: [
|
|
156
|
+
/* @__PURE__ */ jsx(ClockGlyph, {}),
|
|
157
|
+
/* @__PURE__ */ jsx(RollingValue, {
|
|
158
|
+
srValue: /* @__PURE__ */ jsx(SelectValue, {
|
|
159
|
+
"data-slot": "time-picker-value",
|
|
160
|
+
className: "sr-only",
|
|
161
|
+
children: ({ isPlaceholder, selectedText }) => isPlaceholder ? placeholder : selectedText
|
|
162
|
+
}),
|
|
163
|
+
swapKey: key ?? "placeholder",
|
|
164
|
+
dir: key === null ? -1 : dir,
|
|
165
|
+
children: minutes === null ? /* @__PURE__ */ jsx("span", {
|
|
166
|
+
"data-slot": "time-picker-placeholder",
|
|
167
|
+
className: "text-muted-foreground",
|
|
168
|
+
children: placeholder
|
|
169
|
+
}) : display(minutes)
|
|
170
|
+
}),
|
|
171
|
+
/* @__PURE__ */ jsx(Chevron, {})
|
|
172
|
+
]
|
|
173
|
+
}),
|
|
174
|
+
description ? /* @__PURE__ */ jsx(Text, {
|
|
175
|
+
slot: "description",
|
|
176
|
+
"data-slot": "time-picker-description",
|
|
177
|
+
className: descriptionClass,
|
|
178
|
+
children: description
|
|
179
|
+
}) : null,
|
|
180
|
+
/* @__PURE__ */ jsx(Popover, {
|
|
181
|
+
"data-slot": "time-picker-popover",
|
|
182
|
+
className: timePickerListVariants(),
|
|
183
|
+
children: /* @__PURE__ */ jsx(CenteredListBox, { children: options.map((total) => /* @__PURE__ */ jsx(ListBoxItem, {
|
|
184
|
+
id: keyOf(total),
|
|
185
|
+
textValue: display(total),
|
|
186
|
+
"data-slot": "time-picker-item",
|
|
187
|
+
className: timePickerItemVariants(),
|
|
188
|
+
children: ({ isSelected }) => /* @__PURE__ */ jsxs(Fragment$1, { children: [display(total), isSelected ? /* @__PURE__ */ jsx("span", {
|
|
189
|
+
"aria-hidden": "true",
|
|
190
|
+
"data-slot": "time-picker-dot",
|
|
191
|
+
className: "size-1.5 rounded-full bg-foreground"
|
|
192
|
+
}) : null] })
|
|
193
|
+
}, keyOf(total))) })
|
|
194
|
+
})
|
|
195
|
+
]
|
|
196
|
+
});
|
|
197
|
+
});
|
|
198
|
+
//#endregion
|
|
199
|
+
export { TimePicker, timePickerItemVariants, timePickerListVariants };
|
|
200
|
+
|
|
201
|
+
//# sourceMappingURL=time-picker.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"time-picker.js","names":["AriaListBox","AriaSelect","AriaLabel","AriaButton","AriaSelectValue","AriaText","AriaPopover","AriaListBoxItem"],"sources":["../../src/time-picker/time-picker.tsx"],"sourcesContent":["\"use client\";\n\nimport { Time } from \"@internationalized/date\";\nimport { cva } from \"class-variance-authority\";\nimport { forwardRef, useMemo, useRef, useState } from \"react\";\nimport {\n Button as AriaButton,\n Label as AriaLabel,\n ListBox as AriaListBox,\n ListBoxItem as AriaListBoxItem,\n Popover as AriaPopover,\n Select as AriaSelect,\n SelectValue as AriaSelectValue,\n Text as AriaText,\n useLocale,\n type TimeValue,\n} from \"react-aria-components\";\n\nimport { labelVariants } from \"../label/label.js\";\nimport { cn, cnAll } from \"../lib/cn.js\";\nimport { useIsomorphicLayoutEffect } from \"../lib/motion.js\";\nimport { RollingValue } from \"../lib/rolling-value.js\";\nimport { selectTriggerVariants, selectVariants } from \"../select/select.js\";\n\n/**\n * TimePicker, a field that shows a time and opens a list of times to pick from.\n *\n * Values are `TimeValue` objects from `@internationalized/date`, as Calendar and\n * DatePicker use `DateValue` (ADR 0006), not \"HH:MM\" strings: a time of day has\n * no time zone or format of its own. Unlike those two, this one builds a `Time`\n * at runtime to hand back, so the package is a real (peer) dependency here and\n * not only a type.\n *\n * The control is a React Aria `Select`, so the list is a listbox with typeahead,\n * arrow keys and a roving highlight; the motion (the value rolling like a clock\n * face, the chevron, the list growing from the field) sits on top of it.\n */\n\n/** The list: it grows from the field, and the highlight follows the pointer and the arrows. */\nexport const timePickerListVariants = cva([\n \"picker-pop w-(--trigger-width) origin-top overflow-hidden\",\n // A little less offset than a date picker: this list sits close under its field.\n \"[--pop-in-y:-6px] [--pop-in-scale:0.97] [--pop-out-y:-4px] [--pop-out-scale:0.98] [--pop-out-duration:120ms]\",\n \"rounded-panel border-(length:--border-width) border-border p-1\",\n \"bg-card text-card-foreground shadow-floating\",\n \"box-border font-sans text-sm leading-(--leading-normal)\",\n]);\n\n/** A time. The highlight changes almost at once (the arrows move it often); a dot marks the chosen one. */\nexport const timePickerItemVariants = cva([\n \"relative flex min-h-9 cursor-pointer select-none items-center justify-between gap-2\",\n \"rounded-control px-3 py-1.5 tabular-nums outline-none\",\n \"text-sm leading-(--leading-normal) text-card-foreground\",\n \"data-[focused]:bg-muted\",\n \"motion-safe:transition-colors motion-safe:duration-80 motion-safe:ease-settle\",\n \"data-[focus-visible]:outline-solid data-[focus-visible]:outline-(length:--focus-ring-width)\",\n \"data-[focus-visible]:outline-offset-(--focus-ring-offset) data-[focus-visible]:outline-(--color-ring)\",\n \"data-[disabled]:cursor-not-allowed data-[disabled]:opacity-(--opacity-disabled)\",\n]);\n\nconst descriptionClass = \"text-sm leading-(--leading-normal) text-muted-foreground\";\n\nconst pad = (value: number) => String(value).padStart(2, \"0\");\nconst keyOf = (minutes: number) => `${pad(Math.floor(minutes / 60))}:${pad(minutes % 60)}`;\nconst minutesOf = (value: TimeValue) => value.hour * 60 + value.minute;\n\nfunction ClockGlyph() {\n return (\n <svg\n aria-hidden=\"true\"\n viewBox=\"0 0 16 16\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n className=\"text-muted-foreground\"\n >\n <circle cx=\"8\" cy=\"8\" r=\"5.5\" />\n <path d=\"M8 5v3l2 1.5\" />\n </svg>\n );\n}\n\n/** The chevron turns half a turn while the list is open, on the gentle spring. */\nfunction Chevron() {\n return (\n <svg\n aria-hidden=\"true\"\n viewBox=\"0 0 16 16\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"1.75\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n className=\"text-muted-foreground motion-safe:transition-[rotate] motion-safe:duration-(--duration-gentle) motion-safe:ease-gentle group-aria-expanded/trigger:rotate-180\"\n >\n <path d=\"m4 6 4 4 4-4\" />\n </svg>\n );\n}\n\n/**\n * The list of times. It opens centred on the chosen time (or at the top with\n * none), before the first frame, so there is no scroll to watch; the arrow keys\n * then keep the highlight in view, which React Aria does.\n */\nfunction CenteredListBox({ children }: { children: React.ReactNode }) {\n const ref = useRef<HTMLDivElement>(null);\n useIsomorphicLayoutEffect(() => {\n const list = ref.current;\n const chosen = list?.querySelector<HTMLElement>('[role=\"option\"][aria-selected=\"true\"]');\n if (!list || !chosen) return;\n list.scrollTop = chosen.offsetTop - (list.clientHeight - chosen.offsetHeight) / 2;\n }, []);\n return (\n <AriaListBox\n ref={ref}\n data-slot=\"time-picker-list\"\n className=\"relative max-h-62.5 overflow-y-auto overscroll-contain outline-none\"\n >\n {children}\n </AriaListBox>\n );\n}\n\nexport interface TimePickerProps {\n /** What is being chosen, and the control's accessible name. Required, as on Select. */\n label: string;\n /** Render the label for screen readers only. */\n labelHidden?: boolean;\n /** Help text under the control, named in `aria-describedby`. */\n description?: string;\n /** Shown while no time is chosen. @default \"Select a time\" */\n placeholder?: string;\n /** The chosen time. Controlled: pass `null` for none. */\n value?: TimeValue | null;\n /** The starting time when uncontrolled. @default null */\n defaultValue?: TimeValue | null;\n /** Called with the chosen time, as a `Time`. */\n onChange?: (value: TimeValue) => void;\n /** Minutes between the times in the list. @default 15 */\n minuteStep?: 1 | 5 | 10 | 15 | 30;\n /** 12-hour (9:00 AM) or 24-hour (09:00) times. @default 12 */\n hourCycle?: 12 | 24;\n /** Control scale of the trigger. @default \"md\" */\n size?: \"sm\" | \"md\" | \"lg\";\n /** Disable the control. */\n isDisabled?: boolean;\n /** Extra classes for the wrapper. Merged last. */\n className?: string;\n}\n\n/**\n * A time picker.\n *\n * @example\n * <TimePicker label=\"Start time\" value={time} onChange={setTime} minuteStep={30} />\n */\nexport const TimePicker = forwardRef<HTMLButtonElement, TimePickerProps>(function TimePicker(\n {\n label,\n labelHidden,\n description,\n placeholder = \"Select a time\",\n value,\n defaultValue = null,\n onChange,\n minuteStep = 15,\n hourCycle = 12,\n size = \"md\",\n isDisabled,\n className,\n },\n ref,\n) {\n const { locale } = useLocale();\n const [inner, setInner] = useState<TimeValue | null>(defaultValue);\n const current = value === undefined ? inner : value;\n const minutes = current ? minutesOf(current) : null;\n const key = minutes === null ? null : keyOf(minutes);\n\n const display = useMemo(() => {\n const format = new Intl.DateTimeFormat(locale, {\n hour: \"numeric\",\n minute: \"2-digit\",\n hourCycle: hourCycle === 24 ? \"h23\" : \"h12\",\n timeZone: \"UTC\",\n });\n return (total: number) =>\n format\n .format(new Date(Date.UTC(2000, 0, 1, Math.floor(total / 60), total % 60)))\n .replace(/\\u202f/g, \" \");\n }, [locale, hourCycle]);\n\n // The list: every step of the day, plus the current time if it falls between steps.\n const options = useMemo(() => {\n const all = Array.from({ length: Math.ceil(1440 / minuteStep) }, (_, i) => i * minuteStep);\n if (minutes !== null && !all.includes(minutes)) all.push(minutes);\n return all.sort((a, b) => a - b);\n }, [minuteStep, minutes]);\n\n // Which way the time moved, so the shown value rolls like a clock face.\n const [previous, setPrevious] = useState(minutes);\n const [dir, setDir] = useState(1);\n if (previous !== minutes) {\n setPrevious(minutes);\n setDir(minutes !== null && previous !== null && minutes < previous ? -1 : 1);\n }\n\n return (\n <AriaSelect\n data-slot=\"time-picker\"\n selectedKey={key}\n onSelectionChange={(next) => {\n if (next == null) return;\n const [hour = 0, minute = 0] = String(next).split(\":\").map(Number);\n const time = new Time(hour, minute);\n if (value === undefined) setInner(time);\n onChange?.(time);\n }}\n isDisabled={isDisabled}\n placeholder={placeholder}\n className={cn(selectVariants(), className)}\n >\n <AriaLabel\n data-slot=\"time-picker-label\"\n className={cnAll(labelVariants(), labelHidden && \"sr-only\")}\n >\n {label}\n </AriaLabel>\n <AriaButton ref={ref} data-slot=\"time-picker-trigger\" className={selectTriggerVariants({ size })}>\n <ClockGlyph />\n <RollingValue\n srValue={\n <AriaSelectValue data-slot=\"time-picker-value\" className=\"sr-only\">\n {({ isPlaceholder, selectedText }) => (isPlaceholder ? placeholder : selectedText)}\n </AriaSelectValue>\n }\n swapKey={key ?? \"placeholder\"}\n dir={key === null ? -1 : dir}\n >\n {minutes === null ? (\n <span data-slot=\"time-picker-placeholder\" className=\"text-muted-foreground\">\n {placeholder}\n </span>\n ) : (\n display(minutes)\n )}\n </RollingValue>\n <Chevron />\n </AriaButton>\n {description ? (\n <AriaText slot=\"description\" data-slot=\"time-picker-description\" className={descriptionClass}>\n {description}\n </AriaText>\n ) : null}\n <AriaPopover data-slot=\"time-picker-popover\" className={timePickerListVariants()}>\n <CenteredListBox>\n {options.map((total) => (\n <AriaListBoxItem\n key={keyOf(total)}\n id={keyOf(total)}\n textValue={display(total)}\n data-slot=\"time-picker-item\"\n className={timePickerItemVariants()}\n >\n {({ isSelected }) => (\n <>\n {display(total)}\n {isSelected ? (\n <span\n aria-hidden=\"true\"\n data-slot=\"time-picker-dot\"\n className=\"size-1.5 rounded-full bg-foreground\"\n />\n ) : null}\n </>\n )}\n </AriaListBoxItem>\n ))}\n </CenteredListBox>\n </AriaPopover>\n </AriaSelect>\n );\n});\n"],"mappings":"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"}
|
package/dist/toast/index.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { ToastContent, ToastRegion, ToastRegionProps, toast, toastCloseVariants, toastQueue, toastRegionVariants, toastVariants } from "./toast.js";
|
|
2
|
-
export { type ToastContent, ToastRegion, type ToastRegionProps, toast, toastCloseVariants, toastQueue, toastRegionVariants, toastVariants };
|
|
1
|
+
import { ToastContent, ToastRegion, ToastRegionProps, toast, toastCloseVariants, toastIconVariants, toastQueue, toastRegionVariants, toastVariants } from "./toast.js";
|
|
2
|
+
export { type ToastContent, ToastRegion, type ToastRegionProps, toast, toastCloseVariants, toastIconVariants, toastQueue, toastRegionVariants, toastVariants };
|
package/dist/toast/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { ToastRegion, toast, toastCloseVariants, toastQueue, toastRegionVariants, toastVariants } from "./toast.js";
|
|
2
|
-
export { ToastRegion, toast, toastCloseVariants, toastQueue, toastRegionVariants, toastVariants };
|
|
1
|
+
import { ToastRegion, toast, toastCloseVariants, toastIconVariants, toastQueue, toastRegionVariants, toastVariants } from "./toast.js";
|
|
2
|
+
export { ToastRegion, toast, toastCloseVariants, toastIconVariants, toastQueue, toastRegionVariants, toastVariants };
|
package/dist/toast/toast.d.ts
CHANGED
|
@@ -36,6 +36,10 @@ export declare const toastRegionVariants: (props?: import("class-variance-author
|
|
|
36
36
|
export declare const toastVariants: (props?: ({
|
|
37
37
|
tone?: "neutral" | "success" | "warning" | "danger" | "info" | null | undefined;
|
|
38
38
|
} & import("class-variance-authority/types").ClassProp) | undefined) => string;
|
|
39
|
+
/** The status icon's circle: the tone's light fill with its AA text colour. */
|
|
40
|
+
export declare const toastIconVariants: (props?: ({
|
|
41
|
+
tone?: "neutral" | "success" | "warning" | "danger" | "info" | null | undefined;
|
|
42
|
+
} & import("class-variance-authority/types").ClassProp) | undefined) => string;
|
|
39
43
|
export declare const toastCloseVariants: (props?: import("class-variance-authority/types").ClassProp | undefined) => string;
|
|
40
44
|
/** What a toast carries. `title` is required: an unnamed toast announces nothing. */
|
|
41
45
|
export interface ToastContent extends VariantProps<typeof toastVariants> {
|
|
@@ -43,6 +47,8 @@ export interface ToastContent extends VariantProps<typeof toastVariants> {
|
|
|
43
47
|
title: ReactNode;
|
|
44
48
|
/** Secondary detail, beneath the title. */
|
|
45
49
|
description?: ReactNode;
|
|
50
|
+
/** Replaces the tone's status icon. Pass a 16px glyph; it is hidden from assistive tech. */
|
|
51
|
+
icon?: ReactNode;
|
|
46
52
|
}
|
|
47
53
|
/**
|
|
48
54
|
* The queue every `toast()` call feeds.
|