@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
|
@@ -0,0 +1,298 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { cn } from "../lib/cn.js";
|
|
3
|
+
import { mergeRefs } from "../lib/merge-refs.js";
|
|
4
|
+
import { useMorphWidth } from "../lib/motion.js";
|
|
5
|
+
import { SwapText } from "../lib/swap-text.js";
|
|
6
|
+
import { useHeightFollow } from "../lib/height-follow.js";
|
|
7
|
+
import { forwardRef, useEffect, useLayoutEffect, useMemo, useRef, useState, useSyncExternalStore } from "react";
|
|
8
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
9
|
+
//#region src/countdown/countdown.tsx
|
|
10
|
+
const DEFAULT_UNITS = [
|
|
11
|
+
"days",
|
|
12
|
+
"hours",
|
|
13
|
+
"minutes",
|
|
14
|
+
"seconds"
|
|
15
|
+
];
|
|
16
|
+
const SECONDS = {
|
|
17
|
+
days: 86400,
|
|
18
|
+
hours: 3600,
|
|
19
|
+
minutes: 60,
|
|
20
|
+
seconds: 1
|
|
21
|
+
};
|
|
22
|
+
/** How far each unit counts before carrying into the next, when a larger unit is shown. */
|
|
23
|
+
const LIMIT = {
|
|
24
|
+
days: Infinity,
|
|
25
|
+
hours: 24,
|
|
26
|
+
minutes: 60,
|
|
27
|
+
seconds: 60
|
|
28
|
+
};
|
|
29
|
+
/** The unit's name, its one-letter form, and its singular for speech. */
|
|
30
|
+
const NAMES = {
|
|
31
|
+
days: [
|
|
32
|
+
"Days",
|
|
33
|
+
"d",
|
|
34
|
+
"day"
|
|
35
|
+
],
|
|
36
|
+
hours: [
|
|
37
|
+
"Hours",
|
|
38
|
+
"h",
|
|
39
|
+
"hour"
|
|
40
|
+
],
|
|
41
|
+
minutes: [
|
|
42
|
+
"Minutes",
|
|
43
|
+
"m",
|
|
44
|
+
"minute"
|
|
45
|
+
],
|
|
46
|
+
seconds: [
|
|
47
|
+
"Seconds",
|
|
48
|
+
"s",
|
|
49
|
+
"second"
|
|
50
|
+
]
|
|
51
|
+
};
|
|
52
|
+
/** setTimeout cannot wait longer than this (2^31 - 1 ms, about 24.8 days); a longer wait re-arms itself. */
|
|
53
|
+
const MAX_TIMEOUT = 2147483647;
|
|
54
|
+
/** Wake a few ms after the second turns, so the clock has surely crossed it. */
|
|
55
|
+
const WAKE_MARGIN_MS = 8;
|
|
56
|
+
/** Stagger between digits on the first reading (ms), at most 300 in all. */
|
|
57
|
+
const REVEAL_STAGGER_MS = 35;
|
|
58
|
+
const REVEAL_MAX_DELAY_MS = 300;
|
|
59
|
+
/** How long the first reading takes at most: the longest delay, the smooth spring, and a margin. */
|
|
60
|
+
const REVEAL_SETTLE_MS = 1200;
|
|
61
|
+
const systemClock = () => Date.now();
|
|
62
|
+
/** Offset of a zone from UTC at an instant, in milliseconds. */
|
|
63
|
+
function zoneOffset(epoch, timeZone) {
|
|
64
|
+
const parts = new Intl.DateTimeFormat("en-US", {
|
|
65
|
+
timeZone,
|
|
66
|
+
hourCycle: "h23",
|
|
67
|
+
year: "numeric",
|
|
68
|
+
month: "2-digit",
|
|
69
|
+
day: "2-digit",
|
|
70
|
+
hour: "2-digit",
|
|
71
|
+
minute: "2-digit",
|
|
72
|
+
second: "2-digit"
|
|
73
|
+
}).formatToParts(new Date(epoch));
|
|
74
|
+
const get = (type) => Number(parts.find((part) => part.type === type)?.value ?? 0);
|
|
75
|
+
return Date.UTC(get("year"), get("month") - 1, get("day"), get("hour"), get("minute"), get("second")) - Math.floor(epoch / 1e3) * 1e3;
|
|
76
|
+
}
|
|
77
|
+
/** Resolves a countdown target to epoch milliseconds without ever reading the device's own time zone. */
|
|
78
|
+
function toEpoch(target, timeZone) {
|
|
79
|
+
if (typeof target === "number") return target;
|
|
80
|
+
if (target instanceof Date) return target.getTime();
|
|
81
|
+
const wall = /^(\d{4})-(\d{2})-(\d{2})(?:[T ](\d{2}):(\d{2})(?::(\d{2})(?:\.\d+)?)?)?$/.exec(target.trim());
|
|
82
|
+
if (!wall) return Date.parse(target);
|
|
83
|
+
const utc = Date.UTC(+wall[1], +wall[2] - 1, +wall[3], +(wall[4] ?? 0), +(wall[5] ?? 0), +(wall[6] ?? 0));
|
|
84
|
+
if (!timeZone) return utc;
|
|
85
|
+
return utc - zoneOffset(utc - zoneOffset(utc, timeZone), timeZone);
|
|
86
|
+
}
|
|
87
|
+
/** Whole seconds left, split across the units on show. */
|
|
88
|
+
function partsFor(seconds, units) {
|
|
89
|
+
return units.map((unit, index) => ({
|
|
90
|
+
unit,
|
|
91
|
+
value: index === 0 ? Math.floor(seconds / SECONDS[unit]) : Math.floor(seconds / SECONDS[unit]) % LIMIT[unit]
|
|
92
|
+
}));
|
|
93
|
+
}
|
|
94
|
+
/** Wheel sizes per column: a tens column that only ever shows 0 to 5 turns on a six-face wheel, so 00 to 59 is a single step. */
|
|
95
|
+
function basesFor(unit, largest, length) {
|
|
96
|
+
return Array.from({ length }, (_, index) => {
|
|
97
|
+
return index === length - 2 && length === 2 && !largest ? unit === "hours" ? 3 : 6 : 10;
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
const subscribeVisibility = (notify) => {
|
|
101
|
+
document.addEventListener("visibilitychange", notify);
|
|
102
|
+
return () => document.removeEventListener("visibilitychange", notify);
|
|
103
|
+
};
|
|
104
|
+
const pageIsVisible = () => document.visibilityState === "visible";
|
|
105
|
+
const alwaysVisible = () => true;
|
|
106
|
+
/** Whether the node is on screen (at once where IntersectionObserver is missing). */
|
|
107
|
+
function useOnScreen(node) {
|
|
108
|
+
const [onScreen, setOnScreen] = useState(typeof IntersectionObserver === "undefined");
|
|
109
|
+
useEffect(() => {
|
|
110
|
+
const target = node.current;
|
|
111
|
+
if (!target || typeof IntersectionObserver === "undefined") return;
|
|
112
|
+
const observer = new IntersectionObserver(([entry]) => {
|
|
113
|
+
if (entry) setOnScreen(entry.isIntersecting);
|
|
114
|
+
});
|
|
115
|
+
observer.observe(target);
|
|
116
|
+
return () => observer.disconnect();
|
|
117
|
+
}, [node]);
|
|
118
|
+
return onScreen;
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* One digit wheel. It remembers how far it has turned and takes the short way
|
|
122
|
+
* round to each new digit, so it always keeps going the way the time moved.
|
|
123
|
+
*/
|
|
124
|
+
function Wheel({ digit, base, delay, phase }) {
|
|
125
|
+
const [wheel, setWheel] = useState({
|
|
126
|
+
digit: 0,
|
|
127
|
+
turns: 0
|
|
128
|
+
});
|
|
129
|
+
let { turns } = wheel;
|
|
130
|
+
if (wheel.digit !== digit) {
|
|
131
|
+
const up = (digit - wheel.digit + base) % base;
|
|
132
|
+
const down = base - up;
|
|
133
|
+
turns = wheel.turns + (down <= up ? -down : up);
|
|
134
|
+
setWheel({
|
|
135
|
+
digit,
|
|
136
|
+
turns
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
const style = {
|
|
140
|
+
"--wheel": turns,
|
|
141
|
+
"--base": base
|
|
142
|
+
};
|
|
143
|
+
if (phase === "revealing") {
|
|
144
|
+
style.transitionDelay = `${delay}ms`;
|
|
145
|
+
style.transitionDuration = "var(--duration-smooth)";
|
|
146
|
+
style.transitionTimingFunction = "var(--ease-smooth)";
|
|
147
|
+
}
|
|
148
|
+
return /* @__PURE__ */ jsxs("span", {
|
|
149
|
+
style,
|
|
150
|
+
className: "countdown-wheel",
|
|
151
|
+
children: [/* @__PURE__ */ jsx("span", {
|
|
152
|
+
className: "counter-sizer",
|
|
153
|
+
children: "0"
|
|
154
|
+
}), Array.from({ length: base }, (_, face) => /* @__PURE__ */ jsx("span", {
|
|
155
|
+
style: { "--face": face },
|
|
156
|
+
className: "countdown-glyph",
|
|
157
|
+
children: face
|
|
158
|
+
}, face))]
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
const Countdown = forwardRef(function Countdown({ target, timeZone, units = DEFAULT_UNITS, variant = "large", completeLabel = "Live now", onComplete, label = "Time remaining", clock = systemClock, className }, ref) {
|
|
162
|
+
const root = useRef(null);
|
|
163
|
+
const refs = useMemo(() => mergeRefs(ref, root), [ref]);
|
|
164
|
+
const end = toEpoch(target, timeZone);
|
|
165
|
+
const valid = Number.isFinite(end);
|
|
166
|
+
const shownUnits = units.length ? [...units].sort((a, b) => SECONDS[b] - SECONDS[a]) : DEFAULT_UNITS;
|
|
167
|
+
const pageVisible = useSyncExternalStore(subscribeVisibility, pageIsVisible, alwaysVisible);
|
|
168
|
+
const onScreen = useOnScreen(root);
|
|
169
|
+
const running = pageVisible && onScreen && valid;
|
|
170
|
+
const [now, setNow] = useState(null);
|
|
171
|
+
const clockRef = useRef(clock);
|
|
172
|
+
useLayoutEffect(() => {
|
|
173
|
+
clockRef.current = clock;
|
|
174
|
+
});
|
|
175
|
+
useEffect(() => {
|
|
176
|
+
if (!running) return;
|
|
177
|
+
let timer;
|
|
178
|
+
const tick = () => {
|
|
179
|
+
const time = clockRef.current();
|
|
180
|
+
setNow(time);
|
|
181
|
+
const left = end - time;
|
|
182
|
+
if (left > 0) timer = setTimeout(tick, (left % 1e3 || 1e3) + WAKE_MARGIN_MS);
|
|
183
|
+
};
|
|
184
|
+
timer = setTimeout(tick, 0);
|
|
185
|
+
return () => clearTimeout(timer);
|
|
186
|
+
}, [end, running]);
|
|
187
|
+
useEffect(() => {
|
|
188
|
+
if (!valid) return;
|
|
189
|
+
const left = end - clockRef.current();
|
|
190
|
+
if (left <= 0) return;
|
|
191
|
+
const timer = setTimeout(() => setNow(clockRef.current()), Math.min(MAX_TIMEOUT, left + WAKE_MARGIN_MS));
|
|
192
|
+
return () => clearTimeout(timer);
|
|
193
|
+
}, [end, valid]);
|
|
194
|
+
const left = now === null || !valid ? null : Math.max(0, end - now);
|
|
195
|
+
const complete = left === 0;
|
|
196
|
+
const pending = left === null;
|
|
197
|
+
const onCompleteRef = useRef(onComplete);
|
|
198
|
+
useLayoutEffect(() => {
|
|
199
|
+
onCompleteRef.current = onComplete;
|
|
200
|
+
});
|
|
201
|
+
const wasRunning = useRef(null);
|
|
202
|
+
useEffect(() => {
|
|
203
|
+
if (left === null) return;
|
|
204
|
+
if (left > 0) {
|
|
205
|
+
wasRunning.current = end;
|
|
206
|
+
return;
|
|
207
|
+
}
|
|
208
|
+
if (wasRunning.current === end) {
|
|
209
|
+
wasRunning.current = null;
|
|
210
|
+
onCompleteRef.current?.();
|
|
211
|
+
}
|
|
212
|
+
}, [end, left]);
|
|
213
|
+
const [phase, setPhase] = useState("pending");
|
|
214
|
+
if (phase === "pending" && !pending) setPhase("revealing");
|
|
215
|
+
useEffect(() => {
|
|
216
|
+
if (phase !== "revealing") return;
|
|
217
|
+
const timer = setTimeout(() => setPhase("settled"), REVEAL_SETTLE_MS);
|
|
218
|
+
return () => clearTimeout(timer);
|
|
219
|
+
}, [phase]);
|
|
220
|
+
const seconds = left === null ? 0 : Math.ceil(left / 1e3);
|
|
221
|
+
const parts = partsFor(seconds, shownUnits);
|
|
222
|
+
const compact = variant === "compact";
|
|
223
|
+
const frame = useRef(null);
|
|
224
|
+
const content = useRef(null);
|
|
225
|
+
const shown = complete ? "done" : "running";
|
|
226
|
+
useMorphWidth(content, shown);
|
|
227
|
+
useHeightFollow(frame, content, shown);
|
|
228
|
+
const completeText = typeof completeLabel === "string" ? completeLabel : "Complete";
|
|
229
|
+
const spoken = complete ? completeText : pending ? "" : parts.filter((part, index) => part.value > 0 || index === parts.length - 1).filter((part) => seconds < 60 || part.unit !== "seconds").map((part) => `${part.value} ${NAMES[part.unit][2]}${part.value === 1 ? "" : "s"}`).join(", ");
|
|
230
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
231
|
+
ref: refs,
|
|
232
|
+
"data-slot": "countdown",
|
|
233
|
+
"data-variant": variant,
|
|
234
|
+
"data-complete": complete ? "" : void 0,
|
|
235
|
+
"data-pending": pending ? "" : void 0,
|
|
236
|
+
className: cn("countdown", className),
|
|
237
|
+
children: [/* @__PURE__ */ jsxs("div", {
|
|
238
|
+
ref: frame,
|
|
239
|
+
role: "timer",
|
|
240
|
+
"aria-label": label,
|
|
241
|
+
className: "countdown-frame height-follow",
|
|
242
|
+
children: [/* @__PURE__ */ jsx("div", {
|
|
243
|
+
className: "button-slot",
|
|
244
|
+
children: /* @__PURE__ */ jsx("div", {
|
|
245
|
+
ref: content,
|
|
246
|
+
className: "countdown-content",
|
|
247
|
+
"aria-hidden": "true",
|
|
248
|
+
children: /* @__PURE__ */ jsx(SwapText, {
|
|
249
|
+
swapKey: shown,
|
|
250
|
+
motion: "glyph",
|
|
251
|
+
children: complete ? /* @__PURE__ */ jsxs("span", {
|
|
252
|
+
className: "countdown-done",
|
|
253
|
+
children: [/* @__PURE__ */ jsx("span", { className: "countdown-pulse" }), completeLabel]
|
|
254
|
+
}) : /* @__PURE__ */ jsx("span", {
|
|
255
|
+
className: "countdown-units",
|
|
256
|
+
children: parts.map((part, group) => {
|
|
257
|
+
const text = String(part.value).padStart(2, "0");
|
|
258
|
+
const bases = basesFor(part.unit, group === 0, text.length);
|
|
259
|
+
return /* @__PURE__ */ jsxs("span", {
|
|
260
|
+
className: "countdown-unit",
|
|
261
|
+
children: [!compact && group > 0 ? /* @__PURE__ */ jsx("span", {
|
|
262
|
+
className: "countdown-colon",
|
|
263
|
+
children: ":"
|
|
264
|
+
}) : null, /* @__PURE__ */ jsxs("span", {
|
|
265
|
+
className: "countdown-group",
|
|
266
|
+
children: [/* @__PURE__ */ jsx("span", {
|
|
267
|
+
className: "countdown-number",
|
|
268
|
+
children: [...text].map((char, index) => /* @__PURE__ */ jsx(Wheel, {
|
|
269
|
+
digit: Number(char),
|
|
270
|
+
base: bases[index],
|
|
271
|
+
phase,
|
|
272
|
+
delay: Math.min((group * 2 + index) * REVEAL_STAGGER_MS, REVEAL_MAX_DELAY_MS)
|
|
273
|
+
}, `${part.unit}${text.length - index}`))
|
|
274
|
+
}), /* @__PURE__ */ jsx("span", {
|
|
275
|
+
className: "countdown-name",
|
|
276
|
+
children: NAMES[part.unit][compact ? 1 : 0]
|
|
277
|
+
})]
|
|
278
|
+
})]
|
|
279
|
+
}, part.unit);
|
|
280
|
+
})
|
|
281
|
+
})
|
|
282
|
+
})
|
|
283
|
+
})
|
|
284
|
+
}), /* @__PURE__ */ jsx("span", {
|
|
285
|
+
className: "sr-only",
|
|
286
|
+
children: spoken
|
|
287
|
+
})]
|
|
288
|
+
}), /* @__PURE__ */ jsx("span", {
|
|
289
|
+
className: "sr-only",
|
|
290
|
+
role: "status",
|
|
291
|
+
children: complete ? completeText : ""
|
|
292
|
+
})]
|
|
293
|
+
});
|
|
294
|
+
});
|
|
295
|
+
//#endregion
|
|
296
|
+
export { Countdown };
|
|
297
|
+
|
|
298
|
+
//# sourceMappingURL=countdown.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"countdown.js","names":[],"sources":["../../src/countdown/countdown.tsx"],"sourcesContent":["\"use client\";\n\nimport {\n forwardRef,\n useEffect,\n useLayoutEffect,\n useMemo,\n useRef,\n useState,\n useSyncExternalStore,\n type CSSProperties,\n type ReactNode,\n} from \"react\";\n\nimport { cn } from \"../lib/cn.js\";\nimport { useHeightFollow } from \"../lib/height-follow.js\";\nimport { mergeRefs } from \"../lib/merge-refs.js\";\nimport { useMorphWidth } from \"../lib/motion.js\";\nimport { SwapText } from \"../lib/swap-text.js\";\n\nexport type CountdownUnit = \"days\" | \"hours\" | \"minutes\" | \"seconds\";\n\n/**\n * Countdown: the time left until a fixed moment people wait for, such as a\n * launch, a live event or a deadline. Each digit is a wheel that takes the short\n * way round, so a tick turns downward and 00 to 59 is a single step; the first\n * reading rolls up from zero, one digit after another. When the moment passes\n * the digits give way to `completeLabel` and the box follows the new size.\n *\n * The clock runs only while the countdown is on screen and the tab is visible,\n * and reads the clock again on return, so it never drifts. Completion is armed\n * separately, so `onComplete` fires on time even while the ticking is paused.\n *\n * The digits are a picture. The timer is read as plain text (\"1 day, 2 hours,\n * 5 minutes\") that is not announced every second, and finishing is announced\n * once, politely. Reduced motion jumps.\n */\nexport interface CountdownProps {\n /**\n * The moment to count down to. A number is epoch milliseconds, a Date is used as is, and an ISO string with `Z` or an\n * offset such as `2026-10-06T10:00:00-07:00` is exact. A string without an offset is wall time in `timeZone`, or UTC when\n * no zone is given, so the result never depends on the visitor's own time zone.\n */\n target: Date | number | string;\n /** IANA zone for a target string without an offset, such as \"America/Los_Angeles\". Daylight saving is resolved for the target date. */\n timeZone?: string;\n /** Units to show, largest first. The largest unit absorbs the rest, so hours can pass 24 when days are left out. @default [\"days\", \"hours\", \"minutes\", \"seconds\"] */\n units?: CountdownUnit[];\n /** Large digits with unit names, or one compact line for banners and table cells. @default \"large\" */\n variant?: \"large\" | \"compact\";\n /** Shown once the target passes. The digits swap into it. @default \"Live now\" */\n completeLabel?: ReactNode;\n /** Fires once, the moment the countdown reaches zero while mounted. It fires on time even when the tab is hidden. */\n onComplete?: () => void;\n /** Accessible name, such as \"Keynote starts in\". @default \"Time remaining\" */\n label?: string;\n /** Clock source in epoch milliseconds. Pass a server-synced clock when the visitor's device time cannot be trusted. @default Date.now */\n clock?: () => number;\n /** Extra classes for the countdown. Merged last. */\n className?: string;\n}\n\nconst DEFAULT_UNITS: CountdownUnit[] = [\"days\", \"hours\", \"minutes\", \"seconds\"];\nconst SECONDS: Record<CountdownUnit, number> = {\n days: 86_400,\n hours: 3_600,\n minutes: 60,\n seconds: 1,\n};\n/** How far each unit counts before carrying into the next, when a larger unit is shown. */\nconst LIMIT: Record<CountdownUnit, number> = {\n days: Infinity,\n hours: 24,\n minutes: 60,\n seconds: 60,\n};\n/** The unit's name, its one-letter form, and its singular for speech. */\nconst NAMES: Record<CountdownUnit, [string, string, string]> = {\n days: [\"Days\", \"d\", \"day\"],\n hours: [\"Hours\", \"h\", \"hour\"],\n minutes: [\"Minutes\", \"m\", \"minute\"],\n seconds: [\"Seconds\", \"s\", \"second\"],\n};\n/** setTimeout cannot wait longer than this (2^31 - 1 ms, about 24.8 days); a longer wait re-arms itself. */\nconst MAX_TIMEOUT = 2_147_483_647;\n/** Wake a few ms after the second turns, so the clock has surely crossed it. */\nconst WAKE_MARGIN_MS = 8;\n/** Stagger between digits on the first reading (ms), at most 300 in all. */\nconst REVEAL_STAGGER_MS = 35;\nconst REVEAL_MAX_DELAY_MS = 300;\n/** How long the first reading takes at most: the longest delay, the smooth spring, and a margin. */\nconst REVEAL_SETTLE_MS = 1200;\n\nconst systemClock = () => Date.now();\n\n/** Offset of a zone from UTC at an instant, in milliseconds. */\nfunction zoneOffset(epoch: number, timeZone: string) {\n const parts = new Intl.DateTimeFormat(\"en-US\", {\n timeZone,\n hourCycle: \"h23\",\n year: \"numeric\",\n month: \"2-digit\",\n day: \"2-digit\",\n hour: \"2-digit\",\n minute: \"2-digit\",\n second: \"2-digit\",\n }).formatToParts(new Date(epoch));\n const get = (type: string) => Number(parts.find((part) => part.type === type)?.value ?? 0);\n return (\n Date.UTC(get(\"year\"), get(\"month\") - 1, get(\"day\"), get(\"hour\"), get(\"minute\"), get(\"second\")) -\n Math.floor(epoch / 1000) * 1000\n );\n}\n\n/** Resolves a countdown target to epoch milliseconds without ever reading the device's own time zone. */\nfunction toEpoch(target: Date | number | string, timeZone?: string) {\n if (typeof target === \"number\") return target;\n if (target instanceof Date) return target.getTime();\n const wall = /^(\\d{4})-(\\d{2})-(\\d{2})(?:[T ](\\d{2}):(\\d{2})(?::(\\d{2})(?:\\.\\d+)?)?)?$/.exec(\n target.trim(),\n );\n if (!wall) return Date.parse(target);\n const utc = Date.UTC(\n +wall[1]!,\n +wall[2]! - 1,\n +wall[3]!,\n +(wall[4] ?? 0),\n +(wall[5] ?? 0),\n +(wall[6] ?? 0),\n );\n if (!timeZone) return utc;\n // Two passes settle the offset across a daylight saving change.\n const guess = utc - zoneOffset(utc, timeZone);\n return utc - zoneOffset(guess, timeZone);\n}\n\n/** Whole seconds left, split across the units on show. */\nfunction partsFor(seconds: number, units: CountdownUnit[]) {\n return units.map((unit, index) => ({\n unit,\n value:\n index === 0\n ? Math.floor(seconds / SECONDS[unit])\n : Math.floor(seconds / SECONDS[unit]) % LIMIT[unit],\n }));\n}\n\n/** Wheel sizes per column: a tens column that only ever shows 0 to 5 turns on a six-face wheel, so 00 to 59 is a single step. */\nfunction basesFor(unit: CountdownUnit, largest: boolean, length: number) {\n return Array.from({ length }, (_, index) => {\n const tens = index === length - 2 && length === 2 && !largest;\n return tens ? (unit === \"hours\" ? 3 : 6) : 10;\n });\n}\n\nconst subscribeVisibility = (notify: () => void) => {\n document.addEventListener(\"visibilitychange\", notify);\n return () => document.removeEventListener(\"visibilitychange\", notify);\n};\nconst pageIsVisible = () => document.visibilityState === \"visible\";\nconst alwaysVisible = () => true;\n\n/** Whether the node is on screen (at once where IntersectionObserver is missing). */\nfunction useOnScreen(node: { current: HTMLElement | null }) {\n const [onScreen, setOnScreen] = useState(typeof IntersectionObserver === \"undefined\");\n useEffect(() => {\n const target = node.current;\n if (!target || typeof IntersectionObserver === \"undefined\") return;\n const observer = new IntersectionObserver(([entry]) => {\n if (entry) setOnScreen(entry.isIntersecting);\n });\n observer.observe(target);\n return () => observer.disconnect();\n }, [node]);\n return onScreen;\n}\n\ntype Phase = \"pending\" | \"revealing\" | \"settled\";\n\n/**\n * One digit wheel. It remembers how far it has turned and takes the short way\n * round to each new digit, so it always keeps going the way the time moved.\n */\nfunction Wheel({\n digit,\n base,\n delay,\n phase,\n}: {\n digit: number;\n base: number;\n delay: number;\n phase: Phase;\n}) {\n const [wheel, setWheel] = useState({ digit: 0, turns: 0 });\n let { turns } = wheel;\n if (wheel.digit !== digit) {\n const up = (digit - wheel.digit + base) % base;\n const down = base - up;\n turns = wheel.turns + (down <= up ? -down : up);\n setWheel({ digit, turns });\n }\n const style: CSSProperties & Record<string, string | number> = {\n \"--wheel\": turns,\n \"--base\": base,\n };\n // The first reading rolls on the smooth spring, each digit a beat after the last; every tick after that is snappy.\n if (phase === \"revealing\") {\n style.transitionDelay = `${delay}ms`;\n style.transitionDuration = \"var(--duration-smooth)\";\n style.transitionTimingFunction = \"var(--ease-smooth)\";\n }\n return (\n <span style={style} className=\"countdown-wheel\">\n <span className=\"counter-sizer\">0</span>\n {Array.from({ length: base }, (_, face) => (\n <span key={face} style={{ \"--face\": face } as CSSProperties} className=\"countdown-glyph\">\n {face}\n </span>\n ))}\n </span>\n );\n}\n\nexport const Countdown = forwardRef<HTMLDivElement, CountdownProps>(function Countdown(\n {\n target,\n timeZone,\n units = DEFAULT_UNITS,\n variant = \"large\",\n completeLabel = \"Live now\",\n onComplete,\n label = \"Time remaining\",\n clock = systemClock,\n className,\n },\n ref,\n) {\n const root = useRef<HTMLDivElement | null>(null);\n const refs = useMemo(() => mergeRefs(ref, root), [ref]);\n const end = toEpoch(target, timeZone);\n const valid = Number.isFinite(end);\n const shownUnits = units.length\n ? [...units].sort((a, b) => SECONDS[b] - SECONDS[a])\n : DEFAULT_UNITS;\n\n // The clock only ticks while the countdown is on screen and the tab is visible; coming back reads the clock again, so nothing drifts.\n const pageVisible = useSyncExternalStore(subscribeVisibility, pageIsVisible, alwaysVisible);\n const onScreen = useOnScreen(root);\n const running = pageVisible && onScreen && valid;\n const [now, setNow] = useState<number | null>(null);\n const clockRef = useRef(clock);\n useLayoutEffect(() => {\n clockRef.current = clock;\n });\n useEffect(() => {\n if (!running) return;\n let timer: ReturnType<typeof setTimeout>;\n const tick = () => {\n const time = clockRef.current();\n setNow(time);\n const left = end - time;\n // Wake just after the next whole second, aligned to the target rather than to when the page loaded.\n if (left > 0) timer = setTimeout(tick, (left % 1000 || 1000) + WAKE_MARGIN_MS);\n };\n timer = setTimeout(tick, 0);\n return () => clearTimeout(timer);\n }, [end, running]);\n\n // Completion is armed separately, so it lands on time even while ticking is paused.\n useEffect(() => {\n if (!valid) return;\n const left = end - clockRef.current();\n if (left <= 0) return;\n const timer = setTimeout(\n () => setNow(clockRef.current()),\n Math.min(MAX_TIMEOUT, left + WAKE_MARGIN_MS),\n );\n return () => clearTimeout(timer);\n }, [end, valid]);\n\n const left = now === null || !valid ? null : Math.max(0, end - now);\n const complete = left === 0;\n const pending = left === null;\n const onCompleteRef = useRef(onComplete);\n useLayoutEffect(() => {\n onCompleteRef.current = onComplete;\n });\n const wasRunning = useRef<number | null>(null);\n useEffect(() => {\n if (left === null) return;\n if (left > 0) {\n wasRunning.current = end;\n return;\n }\n if (wasRunning.current === end) {\n wasRunning.current = null;\n onCompleteRef.current?.();\n }\n }, [end, left]);\n\n const [phase, setPhase] = useState<Phase>(\"pending\");\n if (phase === \"pending\" && !pending) setPhase(\"revealing\");\n useEffect(() => {\n if (phase !== \"revealing\") return;\n const timer = setTimeout(() => setPhase(\"settled\"), REVEAL_SETTLE_MS);\n return () => clearTimeout(timer);\n }, [phase]);\n\n const seconds = left === null ? 0 : Math.ceil(left / 1000);\n const parts = partsFor(seconds, shownUnits);\n const compact = variant === \"compact\";\n\n // The box follows the size of whatever it holds, so the digits can swap into the finished label without a jump.\n const frame = useRef<HTMLDivElement>(null);\n const content = useRef<HTMLDivElement>(null);\n const shown = complete ? \"done\" : \"running\";\n useMorphWidth(content, shown);\n useHeightFollow(frame, content, shown);\n\n const completeText = typeof completeLabel === \"string\" ? completeLabel : \"Complete\";\n const spoken = complete\n ? completeText\n : pending\n ? \"\"\n : parts\n .filter((part, index) => part.value > 0 || index === parts.length - 1)\n .filter((part) => seconds < 60 || part.unit !== \"seconds\")\n .map((part) => `${part.value} ${NAMES[part.unit][2]}${part.value === 1 ? \"\" : \"s\"}`)\n .join(\", \");\n\n return (\n <div\n ref={refs}\n data-slot=\"countdown\"\n data-variant={variant}\n data-complete={complete ? \"\" : undefined}\n data-pending={pending ? \"\" : undefined}\n className={cn(\"countdown\", className)}\n >\n <div ref={frame} role=\"timer\" aria-label={label} className=\"countdown-frame height-follow\">\n <div className=\"button-slot\">\n <div ref={content} className=\"countdown-content\" aria-hidden=\"true\">\n <SwapText swapKey={shown} motion=\"glyph\">\n {complete ? (\n <span className=\"countdown-done\">\n <span className=\"countdown-pulse\" />\n {completeLabel}\n </span>\n ) : (\n <span className=\"countdown-units\">\n {parts.map((part, group) => {\n const text = String(part.value).padStart(2, \"0\");\n const bases = basesFor(part.unit, group === 0, text.length);\n return (\n <span key={part.unit} className=\"countdown-unit\">\n {!compact && group > 0 ? <span className=\"countdown-colon\">:</span> : null}\n <span className=\"countdown-group\">\n <span className=\"countdown-number\">\n {[...text].map((char, index) => (\n <Wheel\n key={`${part.unit}${text.length - index}`}\n digit={Number(char)}\n base={bases[index]!}\n phase={phase}\n delay={Math.min(\n (group * 2 + index) * REVEAL_STAGGER_MS,\n REVEAL_MAX_DELAY_MS,\n )}\n />\n ))}\n </span>\n <span className=\"countdown-name\">\n {NAMES[part.unit][compact ? 1 : 0]}\n </span>\n </span>\n </span>\n );\n })}\n </span>\n )}\n </SwapText>\n </div>\n </div>\n <span className=\"sr-only\">{spoken}</span>\n </div>\n {/* Ticking is never announced; finishing is, once. */}\n <span className=\"sr-only\" role=\"status\">\n {complete ? completeText : \"\"}\n </span>\n </div>\n );\n});\n"],"mappings":"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"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { PickerSharedProps, datePickerInputVariants, datePickerLabelVariants, datePickerSegmentVariants, datePickerTriggerVariants, datePickerVariants } from "./picker-parts.js";
|
|
2
|
+
import { DateRangePicker, DateRangePickerMessages, DateRangePickerProps, DateRangePickerValue, DateRangePreset, defaultDateRangePresets } from "./date-range-picker.js";
|
|
3
|
+
import { DateValue } from "@internationalized/date";
|
|
4
|
+
//#region src/date-picker/date-picker.d.ts
|
|
5
|
+
/**
|
|
6
|
+
* DatePicker and DateRangePicker: a field-sized trigger that shows the chosen
|
|
7
|
+
* value as words, opening a Popover with the Calendar in it and a typed date
|
|
8
|
+
* field above the calendar.
|
|
9
|
+
*
|
|
10
|
+
* WHY A TRIGGER AND NOT React Aria's segmented DatePicker. The segmented field
|
|
11
|
+
* shows `dd/mm/yyyy` digits in the field itself, which is exactly what a
|
|
12
|
+
* native `<input type="date">` shows; a product that prints dates as
|
|
13
|
+
* "1 Sep 2026" everywhere else wants the field to say that too. The typed
|
|
14
|
+
* field is still there, inside the popover, because a calendar alone makes a
|
|
15
|
+
* date years away a long walk of "previous month" presses.
|
|
16
|
+
*
|
|
17
|
+
* Values are `DateValue` objects (ADR 0006), the type Calendar already takes,
|
|
18
|
+
* and the import stays `import type`: the default display formats with
|
|
19
|
+
* `Intl.DateTimeFormat` over `value.toDate("UTC")`, an instance method, so the
|
|
20
|
+
* package still contributes zero bytes.
|
|
21
|
+
*
|
|
22
|
+
* Every class string below is a STATIC literal, for the same reason as every
|
|
23
|
+
* other component here: Tailwind scans source text.
|
|
24
|
+
*/
|
|
25
|
+
/** Props for {@link DatePicker}. */
|
|
26
|
+
export interface DatePickerProps extends PickerSharedProps {
|
|
27
|
+
/**
|
|
28
|
+
* The footer's status line when a day is chosen, followed by the day.
|
|
29
|
+
*
|
|
30
|
+
* @default "Selected"
|
|
31
|
+
*/
|
|
32
|
+
selectedStatusLabel?: string;
|
|
33
|
+
/**
|
|
34
|
+
* The footer's status line while no day is chosen.
|
|
35
|
+
*
|
|
36
|
+
* @default "Choose a day"
|
|
37
|
+
*/
|
|
38
|
+
emptyStatusLabel?: string;
|
|
39
|
+
/** The chosen day (controlled). `null` is none. */
|
|
40
|
+
value?: DateValue | null;
|
|
41
|
+
/** The day chosen at first (uncontrolled). */
|
|
42
|
+
defaultValue?: DateValue | null;
|
|
43
|
+
/** Told the new day, or `null` when cleared. */
|
|
44
|
+
onChange?: (value: DateValue | null) => void;
|
|
45
|
+
/** Label of the typed date field inside the popover. @default "Type a date" */
|
|
46
|
+
typedLabel?: string;
|
|
47
|
+
}
|
|
48
|
+
export declare const DatePicker: import("react").ForwardRefExoticComponent<DatePickerProps & import("react").RefAttributes<HTMLButtonElement>>;
|
|
49
|
+
//#endregion
|
|
50
|
+
export { DateRangePicker, type DateRangePickerMessages, type DateRangePickerProps, type DateRangePickerValue, type DateRangePreset, datePickerInputVariants, datePickerLabelVariants, datePickerSegmentVariants, datePickerTriggerVariants, datePickerVariants, defaultDateRangePresets };
|
|
51
|
+
//# sourceMappingURL=date-picker.d.ts.map
|
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { cn } from "../lib/cn.js";
|
|
3
|
+
import { prefersReducedMotion } from "../lib/motion.js";
|
|
4
|
+
import { SwapText } from "../lib/swap-text.js";
|
|
5
|
+
import { useFlip } from "../lib/flip.js";
|
|
6
|
+
import { Calendar as Calendar$1 } from "../calendar/calendar.js";
|
|
7
|
+
import { Popover as Popover$1 } from "../popover/popover.js";
|
|
8
|
+
import { CalendarGlyph, Chevron, TypedDate, datePickerInputVariants, datePickerLabelVariants, datePickerSegmentVariants, datePickerTriggerVariants, datePickerVariants, descriptionClass, errorClass, hintClass, pickerFooterButtonVariants, useDayFormat, useValue } from "./picker-parts.js";
|
|
9
|
+
import { DateRangePicker, defaultDateRangePresets } from "./date-range-picker.js";
|
|
10
|
+
import { forwardRef, useEffect, useId, useMemo, useRef, useState } from "react";
|
|
11
|
+
import { Button, Dialog, DialogTrigger, useLocale } from "react-aria-components";
|
|
12
|
+
import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
|
|
13
|
+
//#region src/date-picker/date-picker.tsx
|
|
14
|
+
/** The shell both pickers share: label, trigger, popover, description and error. */
|
|
15
|
+
function PickerShell({ slot, shown, valueNode, props, triggerRef, children }) {
|
|
16
|
+
const id = useId();
|
|
17
|
+
const labelId = `${id}-label`;
|
|
18
|
+
const valueId = `${id}-value`;
|
|
19
|
+
const descriptionId = `${id}-description`;
|
|
20
|
+
const errorId = `${id}-error`;
|
|
21
|
+
const invalid = props.errorMessage != null;
|
|
22
|
+
const describedBy = [props.description != null && descriptionId, invalid && errorId].filter(Boolean).join(" ");
|
|
23
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
24
|
+
"data-slot": slot,
|
|
25
|
+
"data-invalid": invalid || void 0,
|
|
26
|
+
className: cn(datePickerVariants(), props.className),
|
|
27
|
+
children: [
|
|
28
|
+
/* @__PURE__ */ jsx("span", {
|
|
29
|
+
id: labelId,
|
|
30
|
+
className: cn(datePickerLabelVariants(), props.labelHidden && "sr-only"),
|
|
31
|
+
children: props.label
|
|
32
|
+
}),
|
|
33
|
+
/* @__PURE__ */ jsxs(DialogTrigger, { children: [/* @__PURE__ */ jsxs(Button, {
|
|
34
|
+
ref: triggerRef,
|
|
35
|
+
"data-slot": "date-picker-trigger",
|
|
36
|
+
"aria-labelledby": `${labelId} ${valueId}`,
|
|
37
|
+
"aria-describedby": describedBy || void 0,
|
|
38
|
+
isDisabled: props.isDisabled,
|
|
39
|
+
className: datePickerTriggerVariants({ size: props.size }),
|
|
40
|
+
children: [
|
|
41
|
+
/* @__PURE__ */ jsx(CalendarGlyph, {}),
|
|
42
|
+
valueNode ? /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx("span", {
|
|
43
|
+
id: valueId,
|
|
44
|
+
"data-slot": "date-picker-value",
|
|
45
|
+
className: "sr-only",
|
|
46
|
+
children: shown ?? props.placeholder ?? "Choose a date"
|
|
47
|
+
}), valueNode] }) : /* @__PURE__ */ jsx("span", {
|
|
48
|
+
id: valueId,
|
|
49
|
+
"data-slot": "date-picker-value",
|
|
50
|
+
className: cn("min-w-0 flex-1 truncate", shown === null && "text-muted-foreground"),
|
|
51
|
+
children: shown ?? props.placeholder ?? "Choose a date"
|
|
52
|
+
}),
|
|
53
|
+
/* @__PURE__ */ jsx(Chevron, {})
|
|
54
|
+
]
|
|
55
|
+
}), /* @__PURE__ */ jsx(Popover$1, {
|
|
56
|
+
entrance: "none",
|
|
57
|
+
placement: "bottom start",
|
|
58
|
+
className: "picker-pop w-auto origin-[22px_-4px] overflow-y-auto",
|
|
59
|
+
children: /* @__PURE__ */ jsx(Dialog, {
|
|
60
|
+
"aria-label": props.label,
|
|
61
|
+
"data-slot": "date-picker-dialog",
|
|
62
|
+
className: "flex flex-col gap-3 outline-none",
|
|
63
|
+
children: ({ close }) => children(close)
|
|
64
|
+
})
|
|
65
|
+
})] }),
|
|
66
|
+
props.description == null ? null : /* @__PURE__ */ jsx("span", {
|
|
67
|
+
id: descriptionId,
|
|
68
|
+
"data-slot": "date-picker-description",
|
|
69
|
+
className: cn(descriptionClass, hintClass),
|
|
70
|
+
children: props.description
|
|
71
|
+
}),
|
|
72
|
+
invalid ? /* @__PURE__ */ jsx("span", {
|
|
73
|
+
id: errorId,
|
|
74
|
+
"data-slot": "date-picker-error",
|
|
75
|
+
className: errorClass,
|
|
76
|
+
children: props.errorMessage
|
|
77
|
+
}) : null
|
|
78
|
+
]
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
/** The pieces of a formatted day, so each can roll on its own: a later date rises, an earlier one drops. */
|
|
82
|
+
function useDayParts() {
|
|
83
|
+
const { locale } = useLocale();
|
|
84
|
+
return useMemo(() => {
|
|
85
|
+
const format = new Intl.DateTimeFormat(locale, {
|
|
86
|
+
dateStyle: "medium",
|
|
87
|
+
timeZone: "UTC"
|
|
88
|
+
});
|
|
89
|
+
return (value) => format.formatToParts(value.toDate("UTC"));
|
|
90
|
+
}, [locale]);
|
|
91
|
+
}
|
|
92
|
+
/** Which way a value moved in time, so its text rolls in that direction. */
|
|
93
|
+
function useDirection(value) {
|
|
94
|
+
const key = value ? String(value) : null;
|
|
95
|
+
const [previous, setPrevious] = useState(value);
|
|
96
|
+
const [direction, setDirection] = useState(1);
|
|
97
|
+
if ((previous ? String(previous) : null) !== key) {
|
|
98
|
+
setPrevious(value);
|
|
99
|
+
setDirection(value && previous && value.compare(previous) < 0 ? -1 : 1);
|
|
100
|
+
}
|
|
101
|
+
return direction;
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* The value the eye sees, in a trigger. Each part of a date rolls on its own
|
|
105
|
+
* (a part that did not change holds still), parts after a wider or narrower one
|
|
106
|
+
* slide along instead of jumping, and a value and the placeholder swap as wholes.
|
|
107
|
+
* Nothing animates on first mount. The caller keeps the plain text for screen
|
|
108
|
+
* readers; this copy is `aria-hidden`.
|
|
109
|
+
*/
|
|
110
|
+
function AnimatedValue({ parts, placeholder, direction }) {
|
|
111
|
+
const ref = useRef(null);
|
|
112
|
+
const text = parts ? parts.map((part) => part.value).join("") : "";
|
|
113
|
+
useFlip(ref, text);
|
|
114
|
+
return /* @__PURE__ */ jsx("span", {
|
|
115
|
+
ref,
|
|
116
|
+
"aria-hidden": "true",
|
|
117
|
+
className: "flex min-w-0 flex-1 overflow-hidden",
|
|
118
|
+
children: /* @__PURE__ */ jsx(SwapText, {
|
|
119
|
+
swapKey: parts ? "value" : "placeholder",
|
|
120
|
+
dir: parts ? 1 : -1,
|
|
121
|
+
motion: "roll",
|
|
122
|
+
className: "inline-flex min-w-0 max-w-full",
|
|
123
|
+
children: parts ? /* @__PURE__ */ jsx("span", {
|
|
124
|
+
className: "inline-flex whitespace-pre tabular-nums",
|
|
125
|
+
children: parts.map((part, index) => /* @__PURE__ */ jsx("span", {
|
|
126
|
+
"data-flip": "",
|
|
127
|
+
className: "inline-flex whitespace-pre",
|
|
128
|
+
children: part.type === "literal" ? /* @__PURE__ */ jsx("span", {
|
|
129
|
+
className: "whitespace-pre",
|
|
130
|
+
children: part.value
|
|
131
|
+
}) : /* @__PURE__ */ jsx(SwapText, {
|
|
132
|
+
swapKey: part.value,
|
|
133
|
+
dir: direction,
|
|
134
|
+
motion: "roll",
|
|
135
|
+
className: "inline-block whitespace-pre",
|
|
136
|
+
children: part.value
|
|
137
|
+
})
|
|
138
|
+
}, `${index}-${part.type}`))
|
|
139
|
+
}) : /* @__PURE__ */ jsx("span", {
|
|
140
|
+
"data-slot": "date-picker-placeholder",
|
|
141
|
+
className: "truncate text-muted-foreground",
|
|
142
|
+
children: placeholder
|
|
143
|
+
})
|
|
144
|
+
})
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* The footer of a picker's calendar: Clear on one side and a status line on the
|
|
149
|
+
* other, which confirms a pick (the new line rises in while the old one lifts
|
|
150
|
+
* away).
|
|
151
|
+
*/
|
|
152
|
+
function PickerFooter({ status, statusKey, clearable, clearLabel, canClear, onClear }) {
|
|
153
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
154
|
+
"data-slot": "date-picker-footer",
|
|
155
|
+
className: "flex items-center justify-between gap-2 border-t-(length:--border-width) border-border pt-3 text-xs text-muted-foreground",
|
|
156
|
+
children: [clearable ? /* @__PURE__ */ jsx(Button, {
|
|
157
|
+
slot: null,
|
|
158
|
+
"data-slot": "date-picker-clear",
|
|
159
|
+
isDisabled: !canClear,
|
|
160
|
+
onPress: onClear,
|
|
161
|
+
className: pickerFooterButtonVariants(),
|
|
162
|
+
children: clearLabel
|
|
163
|
+
}) : /* @__PURE__ */ jsx("span", {}), /* @__PURE__ */ jsx("span", {
|
|
164
|
+
"aria-live": "polite",
|
|
165
|
+
className: "grid min-w-0 justify-items-end",
|
|
166
|
+
children: /* @__PURE__ */ jsx(SwapText, {
|
|
167
|
+
swapKey: statusKey,
|
|
168
|
+
className: "block max-w-full truncate",
|
|
169
|
+
children: status
|
|
170
|
+
})
|
|
171
|
+
})]
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
const DatePicker = forwardRef(function DatePicker({ value, defaultValue = null, onChange, typedLabel = "Type a date", selectedStatusLabel = "Selected", emptyStatusLabel = "Choose a day", ...props }, ref) {
|
|
175
|
+
const [current, setCurrent] = useValue(value, defaultValue, onChange);
|
|
176
|
+
const defaultFormat = useDayFormat();
|
|
177
|
+
const dayParts = useDayParts();
|
|
178
|
+
const format = props.formatValue ?? defaultFormat;
|
|
179
|
+
const direction = useDirection(current);
|
|
180
|
+
const closeTimer = useRef(void 0);
|
|
181
|
+
useEffect(() => () => window.clearTimeout(closeTimer.current), []);
|
|
182
|
+
const parts = current ? props.formatValue ? [{
|
|
183
|
+
type: "value",
|
|
184
|
+
value: format(current)
|
|
185
|
+
}] : dayParts(current) : null;
|
|
186
|
+
return /* @__PURE__ */ jsx(PickerShell, {
|
|
187
|
+
slot: "date-picker",
|
|
188
|
+
shown: current ? format(current) : null,
|
|
189
|
+
valueNode: /* @__PURE__ */ jsx(AnimatedValue, {
|
|
190
|
+
parts,
|
|
191
|
+
placeholder: props.placeholder ?? "Choose a date",
|
|
192
|
+
direction
|
|
193
|
+
}),
|
|
194
|
+
props,
|
|
195
|
+
triggerRef: ref,
|
|
196
|
+
children: (close) => {
|
|
197
|
+
/** A picked day lets the disc glide onto it and the footer confirm it, then the calendar returns to the field. */
|
|
198
|
+
const pick = (next) => {
|
|
199
|
+
setCurrent(next);
|
|
200
|
+
window.clearTimeout(closeTimer.current);
|
|
201
|
+
if (!next || prefersReducedMotion()) close();
|
|
202
|
+
else closeTimer.current = window.setTimeout(close, 300);
|
|
203
|
+
};
|
|
204
|
+
return /* @__PURE__ */ jsxs(Fragment$1, { children: [
|
|
205
|
+
/* @__PURE__ */ jsx(TypedDate, {
|
|
206
|
+
label: typedLabel,
|
|
207
|
+
value: current,
|
|
208
|
+
minValue: props.minValue,
|
|
209
|
+
maxValue: props.maxValue,
|
|
210
|
+
onChange: (next) => {
|
|
211
|
+
if (next || props.clearable) setCurrent(next);
|
|
212
|
+
}
|
|
213
|
+
}),
|
|
214
|
+
/* @__PURE__ */ jsx(Calendar$1, {
|
|
215
|
+
label: props.label,
|
|
216
|
+
labelHidden: true,
|
|
217
|
+
autoFocus: true,
|
|
218
|
+
value: current,
|
|
219
|
+
minValue: props.minValue,
|
|
220
|
+
maxValue: props.maxValue,
|
|
221
|
+
onChange: (next) => pick(next)
|
|
222
|
+
}),
|
|
223
|
+
/* @__PURE__ */ jsx(PickerFooter, {
|
|
224
|
+
status: current ? `${selectedStatusLabel} ${format(current)}` : emptyStatusLabel,
|
|
225
|
+
statusKey: current ? String(current) : "none",
|
|
226
|
+
clearable: Boolean(props.clearable),
|
|
227
|
+
clearLabel: props.clearLabel ?? "Clear",
|
|
228
|
+
canClear: current !== null,
|
|
229
|
+
onClear: () => {
|
|
230
|
+
window.clearTimeout(closeTimer.current);
|
|
231
|
+
pick(null);
|
|
232
|
+
}
|
|
233
|
+
})
|
|
234
|
+
] });
|
|
235
|
+
}
|
|
236
|
+
});
|
|
237
|
+
});
|
|
238
|
+
//#endregion
|
|
239
|
+
export { DatePicker, DateRangePicker, datePickerInputVariants, datePickerLabelVariants, datePickerSegmentVariants, datePickerTriggerVariants, datePickerVariants, defaultDateRangePresets };
|
|
240
|
+
|
|
241
|
+
//# sourceMappingURL=date-picker.js.map
|