@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 @@
|
|
|
1
|
+
{"version":3,"file":"confirm-morph.js","names":[],"sources":["../../src/confirm-morph/confirm-morph.tsx"],"sourcesContent":["\"use client\";\n\nimport {\n createContext,\n forwardRef,\n useCallback,\n useContext,\n useEffect,\n useId,\n useImperativeHandle,\n useRef,\n useState,\n type CSSProperties,\n type KeyboardEvent as ReactKeyboardEvent,\n type PointerEvent as ReactPointerEvent,\n type ReactNode,\n} from \"react\";\n\nimport { cn } from \"../lib/cn.js\";\nimport {\n prefersReducedMotion,\n useExitBackstop,\n useIsomorphicLayoutEffect,\n useLeavingItems,\n} from \"../lib/motion.js\";\nimport { usePausableTimeout } from \"../lib/pausable-timeout.js\";\n\n/** Where the control is in its life: resting, asking, working, finished, or failed. */\nexport type ConfirmMorphState = \"idle\" | \"confirming\" | \"pending\" | \"done\" | \"error\";\n\n/** How the question is answered: a press, a press held until the fill completes, or a press followed by a short countdown. */\nexport type ConfirmMorphMode = \"press\" | \"hold\" | \"countdown\";\n\n/**\n * A button for destructive or important actions that asks in place. Pressing it\n * morphs the same pill into an inline question with Cancel and Confirm, then into\n * a spinner, then into a result with Undo. The width springs to each face while\n * the faces crossfade at their natural width, so text never squashes and nothing\n * around the control jumps. Escape, an outside press, or the timeout all return\n * it to rest.\n *\n * Use it where a modal dialog would be heavy: deleting a project, revoking\n * access, discarding a draft.\n */\nexport interface ConfirmMorphProps {\n /** The resting label, such as \"Delete project\". */\n label: ReactNode;\n /** A plain icon before the resting label. Mark it `aria-hidden`. */\n icon?: ReactNode;\n /** The question shown while confirming, such as \"Delete 3 files?\". Defaults to the label with a question mark. */\n prompt?: ReactNode;\n confirmLabel?: string;\n cancelLabel?: string;\n /** Shown beside the spinner while `onConfirm` resolves. */\n pendingLabel?: string;\n doneLabel?: string;\n errorLabel?: string;\n retryLabel?: string;\n undoLabel?: string;\n /** Shown beside the spinner while `onUndo` resolves. */\n undoingLabel?: string;\n /**\n * `danger` (default) gives the confirm button the destructive colour, for\n * actions that destroy something. `neutral` gives it the primary colour, for\n * important actions that can be reversed. The resting button is neutral either way.\n */\n tone?: \"danger\" | \"neutral\";\n /** `press` confirms on a press. `hold` asks for a press held for `holdDuration`. `countdown` confirms, then counts down `countdown` seconds that Cancel or Escape can still stop. */\n confirmMode?: ConfirmMorphMode;\n /** Milliseconds the confirm button must be held in `hold` mode. */\n holdDuration?: number;\n /** Seconds counted down before the action runs in `countdown` mode. */\n countdown?: number;\n /** Text before the seconds in `countdown` mode, such as \"Deleting in\". Defaults to the pending label followed by \"in\". */\n countdownLabel?: string;\n /** Runs on confirm. Return a promise to show the pending face; a rejection shows the error face with Retry. */\n onConfirm?: () => void | Promise<unknown>;\n /** Offering it adds Undo to the result. Return a promise to show a pending face while it runs. */\n onUndo?: () => void | Promise<unknown>;\n onCancel?: () => void;\n /** Controlled state. Pair it with `onStateChange`. */\n state?: ConfirmMorphState;\n /** Starting state when uncontrolled. */\n defaultState?: ConfirmMorphState;\n onStateChange?: (state: ConfirmMorphState) => void;\n /** Milliseconds before an unanswered question returns to rest. Resting the pointer on the control pauses it. 0 turns it off. */\n confirmTimeout?: number;\n /** Milliseconds a result stays before returning to rest. Resting the pointer on the control pauses it. 0 turns it off. */\n resultTimeout?: number;\n /** A press outside the control cancels an open question. Defaults to true. */\n cancelOnOutsidePress?: boolean;\n isDisabled?: boolean;\n /** Extra classes for the root. Merged last, so they win conflicts with ours. */\n className?: string;\n}\n\n/** A press this soon after the question appears is the tail of the press that opened it, not an answer. */\nconst ARM_MS = 280;\n\ntype FaceKey = ConfirmMorphState | \"counting\";\n\n/** Whether the parts of the current face arrive with motion: not on first render, only on a change of face. */\nconst PartsAnimate = createContext(false);\n\n/**\n * One piece of a face. The parts of a new face arrive in reading order, 35ms\n * apart after a 50ms beat, each clearing a small blur (--part-delay).\n */\nfunction Part({\n index,\n className,\n children,\n}: {\n index: number;\n className?: string;\n children: ReactNode;\n}) {\n const animate = useContext(PartsAnimate);\n return (\n <span\n style={{ \"--part-delay\": 50 + index * 35 + \"ms\" } as CSSProperties}\n className={cn(\n \"inline-flex h-full items-center \" +\n (animate\n ? \"motion-safe:animate-part-in motion-safe:[animation-delay:var(--part-delay)] \"\n : \"\") +\n (className ?? \"\"),\n )}\n >\n {children}\n </span>\n );\n}\n\n/**\n * Faces never move and never scale: each one sits at its natural width,\n * against the pill's leading edge, so the baseline stays put and the pill's clip\n * reveals it as the width springs. The present face reports its width so the\n * pill can spring to it.\n */\nfunction Face({\n id,\n onSize,\n labelledBy,\n animated,\n children,\n}: {\n id: FaceKey;\n onSize: (width: number) => void;\n labelledBy?: string;\n animated: boolean;\n children: ReactNode;\n}) {\n const ref = useRef<HTMLDivElement>(null);\n useIsomorphicLayoutEffect(() => {\n const node = ref.current;\n if (!node) return;\n // Fractional widths, so the spring lands exactly where the pill's natural width is and the hand back to auto is seamless.\n const report = () => onSize(node.getBoundingClientRect().width);\n report();\n if (typeof ResizeObserver === \"undefined\") return;\n const observer = new ResizeObserver(report);\n observer.observe(node);\n return () => observer.disconnect();\n }, [id, onSize]);\n return (\n <div\n ref={ref}\n data-face={id}\n role={labelledBy ? \"group\" : undefined}\n aria-labelledby={labelledBy}\n className={cn(\n \"flex h-full flex-none items-center gap-0.5 px-1 whitespace-nowrap data-[face=idle]:px-0\" +\n (animated ? \" motion-reduce:animate-face-in-soft\" : \"\"),\n )}\n >\n <PartsAnimate.Provider value={animated}>{children}</PartsAnimate.Provider>\n </div>\n );\n}\n\n/** A leaving face steps out of the flow, exactly where it was, and fades while the pill springs to the next one. */\nfunction LeavingFace({\n id,\n onDone,\n children,\n}: {\n id: number;\n onDone: (id: number) => void;\n children: ReactNode;\n}) {\n const remove = useCallback(() => onDone(id), [onDone, id]);\n useExitBackstop(true, remove);\n return (\n <div\n aria-hidden=\"true\"\n ref={(node) => node?.setAttribute(\"inert\", \"\")}\n onAnimationEnd={(event) => {\n if (event.target === event.currentTarget) remove();\n }}\n className=\"pointer-events-none absolute start-0 top-0 flex h-full flex-none items-center gap-0.5 px-1 whitespace-nowrap motion-safe:animate-face-out motion-reduce:animate-fade-out\"\n >\n <PartsAnimate.Provider value={false}>{children}</PartsAnimate.Provider>\n </div>\n );\n}\n\n/** A success disc that pops in with a tick drawing across it, the moment the action lands. */\nfunction Check() {\n return (\n <svg className=\"size-4.5 flex-none\" viewBox=\"0 0 18 18\" fill=\"none\" aria-hidden=\"true\">\n <circle\n cx=\"9\"\n cy=\"9\"\n r=\"8\"\n className=\"fill-success-strong [transform-box:fill-box] [transform-origin:center] motion-safe:animate-disc-in\"\n />\n <path\n d=\"M5.6 9.3 7.8 11.4 12.4 6.7\"\n pathLength={1}\n strokeWidth=\"1.9\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n className=\"stroke-background [stroke-dasharray:1] motion-safe:animate-tick-draw\"\n />\n </svg>\n );\n}\n\n/** A ring that drains with the countdown. */\nfunction Ring({ seconds, tone }: { seconds: number; tone: \"danger\" | \"neutral\" }) {\n return (\n <svg className=\"size-4 flex-none\" viewBox=\"0 0 16 16\" fill=\"none\" aria-hidden=\"true\">\n <circle cx=\"8\" cy=\"8\" r=\"6.25\" strokeWidth=\"1.75\" className=\"stroke-border\" />\n <circle\n cx=\"8\"\n cy=\"8\"\n r=\"6.25\"\n strokeWidth=\"1.75\"\n strokeLinecap=\"round\"\n pathLength={1}\n style={{ animationDuration: seconds + \"s\" }}\n className={cn(\n \"[stroke-dasharray:1] [transform-box:fill-box] [transform-origin:center] -rotate-90 motion-safe:animate-ring-drain \" +\n (tone === \"neutral\" ? \"stroke-primary\" : \"stroke-destructive\"),\n )}\n />\n </svg>\n );\n}\n\n/** Seconds that swap in place: the old digit fades up and out, the new one rises in, on tabular figures so the width holds. */\nfunction Seconds({ value }: { value: number }) {\n const ref = useRef<HTMLSpanElement>(null);\n const { leaving, changed, remove } = useLeavingItems(String(value), value, () => ref.current);\n return (\n <span className=\"inline-grid min-w-2 text-foreground tabular-nums\">\n {leaving.map((item) => (\n <LeavingDigit key={item.id} id={item.id} onDone={remove}>\n {item.value}\n </LeavingDigit>\n ))}\n <span\n key={value}\n ref={ref}\n className={cn(\n \"col-start-1 row-start-1\" +\n (changed ? \" motion-safe:animate-digit-in motion-reduce:animate-fade-in\" : \"\"),\n )}\n >\n {value}\n </span>\n </span>\n );\n}\n\nfunction LeavingDigit({\n id,\n onDone,\n children,\n}: {\n id: number;\n onDone: (id: number) => void;\n children: ReactNode;\n}) {\n const remove = useCallback(() => onDone(id), [onDone, id]);\n useExitBackstop(true, remove);\n return (\n <span\n aria-hidden=\"true\"\n onAnimationEnd={(event) => {\n if (event.target === event.currentTarget) remove();\n }}\n className=\"col-start-1 row-start-1 motion-safe:animate-digit-out motion-reduce:animate-fade-out\"\n >\n {children}\n </span>\n );\n}\n\nfunction Spinner() {\n return (\n <svg\n className=\"size-4 flex-none motion-safe:animate-spin-fast motion-reduce:[animation:spin_1.6s_linear_infinite]\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth={1.75}\n strokeLinecap=\"round\"\n aria-hidden=\"true\"\n >\n <path d=\"M21 12a9 9 0 1 1-6.219-8.56\" />\n </svg>\n );\n}\n\nfunction AlertIcon() {\n return (\n <svg\n className=\"size-4 flex-none text-destructive-strong\"\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 >\n <circle cx=\"12\" cy=\"12\" r=\"10\" />\n <path d=\"M12 8v4M12 16h.01\" />\n </svg>\n );\n}\n\n/*\n * Class strings are static literals: Tailwind scans source text. Focus reads as\n * a ring on every button here, and as a fill: a tinted fill alone is too faint\n * for WCAG 2.4.7.\n */\nconst focusRing =\n \"outline-none focus-visible:outline-solid focus-visible:outline-(length:--focus-ring-width) focus-visible:outline-offset-(--focus-ring-offset) focus-visible:outline-(--color-ring)\";\n\nconst trigger = cn(\n \"inline-flex h-full cursor-pointer items-center gap-2 rounded-pill border-0 bg-transparent py-0 ps-3.5 pe-4 font-sans font-medium text-foreground \" +\n \"motion-safe:transition-colors motion-safe:duration-(--duration-quick) motion-safe:ease-settle \" +\n \"hover:not-active:not-disabled:bg-foreground/5 active:not-disabled:bg-foreground/10 active:not-disabled:duration-0 focus-visible:bg-foreground/6 \" +\n \"disabled:cursor-not-allowed disabled:text-muted-foreground \" +\n focusRing,\n);\n\nconst secondary =\n \"relative inline-flex confirm-button-h flex-none cursor-pointer touch-manipulation items-center justify-center rounded-pill border-0 bg-transparent px-3 font-sans font-medium text-muted-foreground \" +\n \"motion-safe:transition-colors motion-safe:duration-(--duration-quick) motion-safe:ease-settle \" +\n \"hover:not-active:bg-foreground/7 hover:not-active:text-foreground active:bg-foreground/10 active:text-foreground active:duration-0 focus-visible:bg-foreground/8 focus-visible:text-foreground \" +\n focusRing;\n\nconst confirmDanger =\n \"bg-destructive-subtle text-destructive-subtle-foreground hover:not-active:bg-[color-mix(in_oklab,var(--color-destructive)_18%,transparent)] active:bg-[color-mix(in_oklab,var(--color-destructive)_22%,transparent)] focus-visible:bg-[color-mix(in_oklab,var(--color-destructive)_20%,transparent)]\";\nconst confirmNeutral =\n \"bg-primary text-primary-foreground hover:not-active:bg-primary-hover active:bg-primary-pressed focus-visible:bg-primary-hover\";\n\nconst confirmBase =\n \"relative inline-flex confirm-button-h flex-none cursor-pointer touch-manipulation items-center justify-center overflow-clip rounded-pill border-0 px-3 font-sans font-medium \" +\n \"motion-safe:transition-colors motion-safe:duration-(--duration-quick) motion-safe:ease-settle active:duration-0 \" +\n focusRing;\n\n/**\n * A button for an action that deserves a second thought, without a dialog. It\n * asks in place: the pill morphs into a question with Cancel and Confirm, then\n * a spinner, then a result with Undo, its width springing to each face while the\n * faces crossfade at their natural width.\n *\n * Escape, a press outside, or the timeout answer the question with no. Focus\n * follows the control between faces, but only when it was already inside, so a\n * timeout never steals it. A live region announces each step.\n *\n * @example\n * <ConfirmMorph label=\"Delete project\" onConfirm={() => deleteProject()} onUndo={() => restore()} />\n * <ConfirmMorph label=\"Delete project\" confirmMode=\"hold\" onConfirm={deleteProject} />\n */\nexport const ConfirmMorph = forwardRef<HTMLDivElement, ConfirmMorphProps>(function ConfirmMorph(\n {\n label,\n icon,\n prompt,\n confirmLabel = \"Delete\",\n cancelLabel = \"Cancel\",\n pendingLabel = \"Deleting\",\n doneLabel = \"Deleted\",\n errorLabel = \"Couldn’t finish\",\n retryLabel = \"Retry\",\n undoLabel = \"Undo\",\n undoingLabel = \"Restoring\",\n tone = \"danger\",\n confirmMode = \"press\",\n holdDuration = 1000,\n countdown = 3,\n countdownLabel,\n onConfirm,\n onUndo,\n onCancel,\n state: stateProp,\n defaultState = \"idle\",\n onStateChange,\n confirmTimeout = 6000,\n resultTimeout = 5000,\n cancelOnOutsidePress = true,\n isDisabled = false,\n className,\n },\n ref,\n) {\n const uid = useId();\n const promptId = uid + \"-prompt\";\n const holdHintId = uid + \"-hold\";\n const rootRef = useRef<HTMLDivElement>(null);\n useImperativeHandle(ref, () => rootRef.current as HTMLDivElement, []);\n\n const [inner, setInner] = useState<ConfirmMorphState>(defaultState);\n const state = stateProp ?? inner;\n const [working, setWorking] = useState<\"confirm\" | \"undo\">(\"confirm\");\n const [counting, setCounting] = useState(false);\n const [announcement, setAnnouncement] = useState(\"\");\n const faceKey: FaceKey = state === \"confirming\" && counting ? \"counting\" : state;\n\n const live = useRef({ state, onStateChange, controlled: stateProp !== undefined });\n useIsomorphicLayoutEffect(() => {\n live.current = { state, onStateChange, controlled: stateProp !== undefined };\n });\n const pendingFocus = useRef(false);\n const run = useRef(0);\n const askedAt = useRef(0);\n\n const keepFocus = useCallback(() => {\n const root = rootRef.current;\n // Focus follows the control between faces, but only when it was already inside; a timeout never steals focus from elsewhere.\n pendingFocus.current =\n !!root && (root.contains(document.activeElement) || document.activeElement === document.body);\n }, []);\n\n const go = useCallback(\n (next: ConfirmMorphState) => {\n if (next !== \"confirming\") setCounting(false);\n if (next === live.current.state) return;\n keepFocus();\n if (next === \"confirming\") askedAt.current = performance.now();\n if (!live.current.controlled) setInner(next);\n live.current.state = next;\n live.current.onStateChange?.(next);\n },\n [keepFocus],\n );\n\n // A controlled parent can move the state on its own; the countdown never survives that.\n const [seenState, setSeenState] = useState(state);\n if (seenState !== state) {\n setSeenState(state);\n if (state !== \"confirming\") setCounting(false);\n }\n\n const toIdle = useCallback(() => {\n run.current++;\n go(\"idle\");\n }, [go]);\n\n const perform = useCallback(\n async (kind: \"confirm\" | \"undo\") => {\n const handler = kind === \"confirm\" ? onConfirm : onUndo;\n const token = ++run.current;\n setWorking(kind);\n setCounting(false);\n let result: void | Promise<unknown> | undefined;\n try {\n result = handler?.();\n } catch {\n go(\"error\");\n setAnnouncement(errorLabel);\n return;\n }\n if (result && typeof result.then === \"function\") {\n go(\"pending\");\n setAnnouncement(kind === \"confirm\" ? pendingLabel : undoingLabel);\n try {\n await result;\n } catch {\n if (token !== run.current) return;\n go(\"error\");\n setAnnouncement(errorLabel);\n return;\n }\n if (token !== run.current) return;\n }\n if (kind === \"undo\") {\n go(\"idle\");\n setAnnouncement(\"Undone\");\n return;\n }\n go(\"done\");\n setAnnouncement(onUndo ? doneLabel + \". \" + undoLabel + \" is available.\" : doneLabel);\n },\n [doneLabel, errorLabel, go, onConfirm, onUndo, pendingLabel, undoLabel, undoingLabel],\n );\n\n const cancel = useCallback(() => {\n onCancel?.();\n toIdle();\n setAnnouncement(\"Cancelled\");\n }, [onCancel, toIdle]);\n const expire = useRef(() => {});\n useIsomorphicLayoutEffect(() => {\n expire.current = () => {\n if (live.current.state === \"confirming\") cancel();\n else toIdle();\n };\n });\n\n /* The shape: one pill whose width springs to whichever face is current. At rest it is auto, so it renders right before hydration. */\n const surfaceRef = useRef<HTMLDivElement>(null);\n const target = useRef(0);\n const flight = useRef(0);\n // Only the present face reports (a leaving face stops observing), so every report is the current face's width.\n const onFaceSize = useCallback((width: number) => {\n if (Math.abs(width - target.current) < 0.25) return;\n const from = target.current;\n target.current = width;\n const el = surfaceRef.current;\n if (!el) return;\n if (!from || prefersReducedMotion()) {\n flight.current++;\n el.style.width = \"\";\n el.style.transition = \"\";\n return;\n }\n // Start from where the pill is: the face it was showing, or wherever a spring in flight has got to.\n const start = el.style.width ? el.getBoundingClientRect().width : from;\n const token = ++flight.current;\n const curve = width > start ? \"morph\" : \"smooth\";\n el.style.transition = \"none\";\n el.style.width = start + \"px\";\n void el.offsetWidth;\n // Growing follows new content with a little life; shrinking settles without overshoot.\n el.style.transition =\n \"width var(--duration-\" +\n curve +\n \") var(--ease-\" +\n curve +\n \"), background-color var(--duration-standard) var(--ease-settle), box-shadow var(--duration-standard) var(--ease-settle)\";\n el.style.width = width + \"px\";\n const done = (event: TransitionEvent) => {\n if (event.target !== el || event.propertyName !== \"width\") return;\n el.removeEventListener(\"transitionend\", done);\n if (token !== flight.current) return;\n el.style.width = \"\";\n el.style.transition = \"\";\n };\n el.addEventListener(\"transitionend\", done);\n }, []);\n\n /* The timeout runs as an invisible clock. A pointer resting on the control holds it, and so does a hidden tab. */\n const timeout =\n state === \"confirming\" && !counting\n ? confirmTimeout\n : state === \"done\" || state === \"error\"\n ? resultTimeout\n : 0;\n const setHover = usePausableTimeout(timeout, state, () => expire.current());\n\n /* Countdown: a short grace period after the answer, drawn as a draining ring and ticking seconds. */\n const [seconds, setSeconds] = useState(countdown);\n const performRef = useRef(perform);\n useIsomorphicLayoutEffect(() => {\n performRef.current = perform;\n });\n useEffect(() => {\n if (!counting) return;\n const startedAt = performance.now();\n const timer = setInterval(() => {\n const elapsed = (performance.now() - startedAt) / 1000;\n if (elapsed >= countdown) {\n clearInterval(timer);\n void performRef.current(\"confirm\");\n } else {\n setSeconds(Math.max(1, Math.ceil(countdown - elapsed)));\n }\n }, 100);\n return () => {\n clearInterval(timer);\n setSeconds(countdown);\n };\n }, [counting, countdown]);\n\n /*\n * Hold: the confirm button fills with the destructive colour from the left\n * while pressed, and drains back if let go early. The fill is a clip-path\n * transitioned linearly over the hold, then over a spring on the way back.\n */\n const fillRef = useRef<HTMLSpanElement>(null);\n const holdRef = useRef<{ from: number; at: number; timer: ReturnType<typeof setTimeout> } | null>(\n null,\n );\n const progress = useRef(0);\n const setFill = (value: number, transition: string) => {\n const el = fillRef.current;\n if (!el) return;\n el.style.transition = transition;\n el.style.clipPath = \"inset(0 \" + (1 - value) * 100 + \"% 0 0 round 999px)\";\n };\n const startHold = () => {\n if (holdRef.current) return;\n const from = progress.current;\n const remaining = holdDuration * (1 - from);\n setFill(from, \"none\");\n void fillRef.current?.offsetWidth;\n setFill(1, \"clip-path \" + remaining + \"ms linear\");\n const timer = setTimeout(() => {\n holdRef.current = null;\n progress.current = 1;\n void perform(\"confirm\");\n }, remaining);\n holdRef.current = { from, at: performance.now(), timer };\n };\n const releaseHold = () => {\n const held = holdRef.current;\n if (!held) return;\n holdRef.current = null;\n clearTimeout(held.timer);\n const value = Math.min(1, held.from + (performance.now() - held.at) / holdDuration);\n setFill(value, \"none\");\n void fillRef.current?.offsetWidth;\n progress.current = 0;\n // Drains back on a spring that never overshoots (about 0.3s visual duration).\n setFill(0, prefersReducedMotion() ? \"none\" : \"clip-path 540ms var(--ease-smooth)\");\n setAnnouncement(\"Keep holding to \" + confirmLabel.toLowerCase());\n };\n // An unmounted control must not confirm: the hold's clock stops with it.\n useEffect(\n () => () => {\n if (holdRef.current) clearTimeout(holdRef.current.timer);\n },\n [],\n );\n useEffect(() => {\n if (state !== \"confirming\") {\n if (holdRef.current) clearTimeout(holdRef.current.timer);\n holdRef.current = null;\n progress.current = 0;\n setFill(0, \"none\");\n }\n }, [state]);\n\n const answer = () => {\n if (performance.now() - askedAt.current < ARM_MS) return;\n if (confirmMode === \"countdown\") {\n keepFocus();\n setCounting(true);\n setAnnouncement((countdownLabel ?? pendingLabel + \" in\") + \" \" + countdown + \" seconds\");\n return;\n }\n void perform(\"confirm\");\n };\n\n // An outside press answers the question with no.\n useEffect(() => {\n if (state !== \"confirming\" || !cancelOnOutsidePress) return;\n const down = (event: PointerEvent) => {\n if (!rootRef.current?.contains(event.target as Node)) cancel();\n };\n document.addEventListener(\"pointerdown\", down);\n return () => document.removeEventListener(\"pointerdown\", down);\n }, [cancel, cancelOnOutsidePress, state]);\n\n // Focus moves with the morph: Confirm while asking, the root while counting or working, Undo or Retry on a result, the trigger at rest.\n useIsomorphicLayoutEffect(() => {\n if (!pendingFocus.current) return;\n pendingFocus.current = false;\n const root = rootRef.current;\n if (!root) return;\n const face = root.querySelector<HTMLElement>('[data-face=\"' + faceKey + '\"]');\n const autofocus = face?.querySelector<HTMLElement>(\"[data-autofocus]:not(:disabled)\");\n (autofocus ?? root).focus({ preventScroll: true });\n }, [faceKey]);\n\n const onKeyDown = (event: ReactKeyboardEvent<HTMLDivElement>) => {\n if (event.key === \"Escape\") {\n if (state === \"confirming\") {\n event.preventDefault();\n event.stopPropagation();\n cancel();\n } else if (state === \"done\" || state === \"error\") {\n event.preventDefault();\n event.stopPropagation();\n toIdle();\n }\n return;\n }\n // Enter answers yes from anywhere in the question except a button of its own (Cancel keeps meaning Cancel).\n if (\n event.key === \"Enter\" &&\n state === \"confirming\" &&\n !event.repeat &&\n !(event.target instanceof HTMLButtonElement)\n ) {\n event.preventDefault();\n if (counting) void perform(\"confirm\");\n else if (confirmMode !== \"hold\") answer();\n }\n };\n\n const holdKeys = (event: ReactKeyboardEvent<HTMLButtonElement>, down: boolean) => {\n if (event.key !== \"Enter\" && event.key !== \" \") return;\n event.preventDefault();\n if (down) {\n if (!event.repeat) startHold();\n } else releaseHold();\n };\n const holdPointer = (event: ReactPointerEvent<HTMLButtonElement>) => {\n if (event.button !== 0) return;\n event.currentTarget.setPointerCapture?.(event.pointerId);\n startHold();\n };\n\n const shownPrompt = prompt ?? <>{label}?</>;\n const shownCountdown = countdownLabel ?? pendingLabel + \" in\";\n const confirmClasses = cn(\n confirmBase + \" \" + (tone === \"neutral\" ? confirmNeutral : confirmDanger),\n );\n const confirmButton =\n confirmMode === \"hold\" ? (\n <button\n type=\"button\"\n className={cn(confirmClasses + \" select-none [-webkit-touch-callout:none]\")}\n data-autofocus\n aria-describedby={holdHintId}\n onPointerDown={holdPointer}\n onPointerUp={releaseHold}\n onPointerCancel={releaseHold}\n onLostPointerCapture={releaseHold}\n onKeyDown={(event) => holdKeys(event, true)}\n onKeyUp={(event) => holdKeys(event, false)}\n onBlur={releaseHold}\n onContextMenu={(event) => event.preventDefault()}\n >\n <span>{confirmLabel}</span>\n <span\n ref={fillRef}\n aria-hidden=\"true\"\n style={{ clipPath: \"inset(0 100% 0 0 round 999px)\" }}\n className={cn(\n \"pointer-events-none absolute inset-0 inline-flex items-center justify-center \" +\n (tone === \"neutral\"\n ? \"bg-primary-strong text-primary-foreground\"\n : \"bg-destructive text-destructive-foreground\"),\n )}\n >\n <span>{confirmLabel}</span>\n </span>\n </button>\n ) : (\n <button\n type=\"button\"\n className={confirmClasses}\n data-autofocus\n onClick={answer}\n onKeyDown={(event) => {\n if (event.repeat) event.preventDefault();\n }}\n >\n {confirmLabel}\n </button>\n );\n\n const statusPart = \"gap-2 ps-3 pe-2.5 font-medium text-foreground tabular-nums\";\n const face = (() => {\n switch (faceKey) {\n case \"confirming\":\n return (\n <>\n <Part\n index={0}\n className=\"max-w-64 overflow-hidden ps-3 pe-2 font-medium text-foreground tabular-nums\"\n >\n <span id={promptId} className=\"overflow-hidden text-ellipsis\">\n {shownPrompt}\n </span>\n </Part>\n <Part index={1}>\n <button type=\"button\" className={secondary} onClick={cancel}>\n {cancelLabel}\n </button>\n </Part>\n <Part index={2}>{confirmButton}</Part>\n {confirmMode === \"hold\" ? (\n <span id={holdHintId} className=\"sr-only\">\n Press and hold\n </span>\n ) : null}\n </>\n );\n case \"counting\":\n return (\n <>\n <Part index={0} className={cn(statusPart + \" pe-1.5 text-muted-foreground\")}>\n <Ring seconds={countdown} tone={tone} />\n <span className=\"inline-flex items-baseline gap-1\">\n {shownCountdown} <Seconds value={seconds} />\n </span>\n </Part>\n <Part index={1}>\n <button type=\"button\" className={secondary} onClick={cancel}>\n {cancelLabel}\n </button>\n </Part>\n </>\n );\n case \"pending\":\n return (\n <Part index={0} className={cn(statusPart + \" ps-3 pe-4 text-muted-foreground\")}>\n <Spinner />\n <span className=\"inline-flex items-baseline gap-1\">\n {working === \"undo\" ? undoingLabel : pendingLabel}\n </span>\n </Part>\n );\n case \"done\":\n return (\n <>\n <Part index={0} className={cn(statusPart + (onUndo ? \"\" : \" pe-3.5\"))}>\n <Check />\n <span className=\"inline-flex items-baseline gap-1\">{doneLabel}</span>\n </Part>\n {onUndo ? (\n <Part index={1}>\n <button\n type=\"button\"\n className={cn(secondary + \" text-foreground\")}\n data-autofocus\n onClick={() => void perform(\"undo\")}\n >\n {undoLabel}\n </button>\n </Part>\n ) : null}\n </>\n );\n case \"error\":\n return (\n <>\n <Part index={0} className={statusPart}>\n <AlertIcon />\n <span className=\"inline-flex items-baseline gap-1\">{errorLabel}</span>\n </Part>\n <Part index={1}>\n <button\n type=\"button\"\n className={cn(secondary + \" text-foreground\")}\n data-autofocus\n onClick={() => void perform(working)}\n >\n {retryLabel}\n </button>\n </Part>\n </>\n );\n default:\n return (\n <Part index={0}>\n <button\n type=\"button\"\n className={trigger}\n data-autofocus\n disabled={isDisabled}\n onClick={() => {\n setAnnouncement(typeof shownPrompt === \"string\" ? shownPrompt : \"\");\n go(\"confirming\");\n }}\n >\n {icon ? (\n <span\n className=\"grid size-4 place-items-center text-muted-foreground [&>svg]:size-4\"\n aria-hidden=\"true\"\n >\n {icon}\n </span>\n ) : null}\n <span>{label}</span>\n </button>\n </Part>\n );\n }\n })();\n\n // A leaving face is absolute at the pill’s leading edge, so it needs no position of its own.\n const { leaving, changed, remove } = useLeavingItems<ReactNode>(faceKey, face, () => null);\n\n return (\n <div\n ref={rootRef}\n data-state={state}\n data-face={faceKey}\n data-tone={tone}\n data-mode={confirmMode}\n data-disabled={isDisabled || undefined}\n tabIndex={-1}\n aria-busy={state === \"pending\" || undefined}\n onKeyDown={onKeyDown}\n onPointerEnter={() => setHover(true)}\n onPointerLeave={() => setHover(false)}\n onPointerCancel={() => setHover(false)}\n className={cn(\n \"relative inline-flex max-w-full min-w-0 align-middle font-sans text-sm leading-5 text-foreground outline-none [-webkit-tap-highlight-color:transparent]\",\n className,\n )}\n >\n {/* One neutral pill for every state. Only its width moves; corners, text and border never scale. The border is an overlay so it never changes a measurement. */}\n <div\n ref={surfaceRef}\n className={cn(\n \"relative flex h-(--density-control-h-sm) max-w-full justify-start overflow-clip rounded-pill bg-card shadow-resting \" +\n \"after:pointer-events-none after:absolute after:inset-0 after:rounded-[inherit] after:border-(length:--border-width) after:border-border after:content-[''] \" +\n \"motion-safe:transition-[background-color,box-shadow] motion-safe:duration-(--duration-standard) motion-safe:ease-settle \" +\n (isDisabled && state === \"idle\" ? \"shadow-none\" : \"\"),\n )}\n >\n {leaving.map((item) => (\n <LeavingFace key={item.id} id={item.id} onDone={remove}>\n {item.value}\n </LeavingFace>\n ))}\n <Face\n key={faceKey}\n id={faceKey}\n onSize={onFaceSize}\n labelledBy={faceKey === \"confirming\" ? promptId : undefined}\n animated={changed}\n >\n {face}\n </Face>\n </div>\n <span className=\"sr-only\" role=\"status\" aria-live=\"polite\">\n {announcement}\n </span>\n </div>\n );\n});\n"],"mappings":"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"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
//#region src/copy-button/copy-button.d.ts
|
|
2
|
+
export interface CopyButtonProps {
|
|
3
|
+
/** What goes on the clipboard. */
|
|
4
|
+
value: string;
|
|
5
|
+
/** The label at rest, and the button's accessible name. @default "Copy" */
|
|
6
|
+
children?: string;
|
|
7
|
+
/** Only the icon, a square button. The label is still its accessible name. */
|
|
8
|
+
iconOnly?: boolean;
|
|
9
|
+
/** `plain` has no border until hovered. @default "outline" */
|
|
10
|
+
variant?: "outline" | "plain";
|
|
11
|
+
isDisabled?: boolean;
|
|
12
|
+
/** Called once the text has reached the clipboard. */
|
|
13
|
+
onCopied?: () => void;
|
|
14
|
+
/** Extra classes. Merged last, so they win conflicts with ours. */
|
|
15
|
+
className?: string;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Copies a value and says so, calmly. The icon trades places in one soft breath
|
|
19
|
+
* (copy, then a tick that draws itself, or an alert if the clipboard refused)
|
|
20
|
+
* while the label's changed letters rise in, and the button never changes width:
|
|
21
|
+
* its label cell reserves the widest of the three texts.
|
|
22
|
+
*
|
|
23
|
+
* It goes back to rest by itself after a moment, and a live region announces the
|
|
24
|
+
* result. The accessible name is always the resting label.
|
|
25
|
+
*
|
|
26
|
+
* @example
|
|
27
|
+
* <CopyButton value={token} />
|
|
28
|
+
* <CopyButton value={url} iconOnly variant="plain" />
|
|
29
|
+
*/
|
|
30
|
+
export declare const CopyButton: import("react").ForwardRefExoticComponent<CopyButtonProps & import("react").RefAttributes<HTMLButtonElement>>;
|
|
31
|
+
//#endregion
|
|
32
|
+
//# sourceMappingURL=copy-button.d.ts.map
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { cn } from "../lib/cn.js";
|
|
3
|
+
import { buttonVariants } from "../button/button.js";
|
|
4
|
+
import { MorphText } from "../lib/morph-text.js";
|
|
5
|
+
import { IconSwap } from "../lib/icon-swap.js";
|
|
6
|
+
import { useCopyFeedback } from "../lib/use-copy-feedback.js";
|
|
7
|
+
import { forwardRef } from "react";
|
|
8
|
+
import { Button } from "react-aria-components";
|
|
9
|
+
import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
|
|
10
|
+
//#region src/copy-button/copy-button.tsx
|
|
11
|
+
const ICON = "size-4";
|
|
12
|
+
/** The tick draws itself from its short stroke, the way a hand would write it: quick to start, then easing into place. */
|
|
13
|
+
function DrawnCheck() {
|
|
14
|
+
return /* @__PURE__ */ jsx("svg", {
|
|
15
|
+
className: ICON,
|
|
16
|
+
viewBox: "0 0 24 24",
|
|
17
|
+
fill: "none",
|
|
18
|
+
stroke: "currentColor",
|
|
19
|
+
strokeWidth: 1.75,
|
|
20
|
+
strokeLinecap: "round",
|
|
21
|
+
strokeLinejoin: "round",
|
|
22
|
+
"aria-hidden": "true",
|
|
23
|
+
children: /* @__PURE__ */ jsx("path", {
|
|
24
|
+
d: "M4 12l5 5L20 6",
|
|
25
|
+
pathLength: 1,
|
|
26
|
+
className: "[stroke-dasharray:1] motion-safe:animate-check-draw-calm"
|
|
27
|
+
})
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
function StateIcon({ state }) {
|
|
31
|
+
if (state === "copied") return /* @__PURE__ */ jsx(DrawnCheck, {});
|
|
32
|
+
const common = {
|
|
33
|
+
className: ICON,
|
|
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
|
+
};
|
|
42
|
+
if (state === "error") return /* @__PURE__ */ jsxs("svg", {
|
|
43
|
+
...common,
|
|
44
|
+
children: [/* @__PURE__ */ jsx("circle", {
|
|
45
|
+
cx: "12",
|
|
46
|
+
cy: "12",
|
|
47
|
+
r: "10"
|
|
48
|
+
}), /* @__PURE__ */ jsx("path", { d: "M12 8v4M12 16h.01" })]
|
|
49
|
+
});
|
|
50
|
+
return /* @__PURE__ */ jsxs("svg", {
|
|
51
|
+
...common,
|
|
52
|
+
children: [/* @__PURE__ */ jsx("rect", {
|
|
53
|
+
x: "8",
|
|
54
|
+
y: "8",
|
|
55
|
+
width: "14",
|
|
56
|
+
height: "14",
|
|
57
|
+
rx: "2"
|
|
58
|
+
}), /* @__PURE__ */ jsx("path", { d: "M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2" })]
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Copies a value and says so, calmly. The icon trades places in one soft breath
|
|
63
|
+
* (copy, then a tick that draws itself, or an alert if the clipboard refused)
|
|
64
|
+
* while the label's changed letters rise in, and the button never changes width:
|
|
65
|
+
* its label cell reserves the widest of the three texts.
|
|
66
|
+
*
|
|
67
|
+
* It goes back to rest by itself after a moment, and a live region announces the
|
|
68
|
+
* result. The accessible name is always the resting label.
|
|
69
|
+
*
|
|
70
|
+
* @example
|
|
71
|
+
* <CopyButton value={token} />
|
|
72
|
+
* <CopyButton value={url} iconOnly variant="plain" />
|
|
73
|
+
*/
|
|
74
|
+
const CopyButton = forwardRef(function CopyButton({ value, children: label = "Copy", iconOnly = false, variant = "outline", isDisabled, onCopied, className }, ref) {
|
|
75
|
+
const { state, copy } = useCopyFeedback();
|
|
76
|
+
const text = state === "copied" ? "Copied" : state === "error" ? "Failed" : label;
|
|
77
|
+
const pressStart = (event) => {
|
|
78
|
+
event.target.style.setProperty("--press-scale", iconOnly ? "0.96" : "0.97");
|
|
79
|
+
};
|
|
80
|
+
const classes = cn(buttonVariants({
|
|
81
|
+
variant: variant === "plain" ? "ghost" : "outlineNeutral",
|
|
82
|
+
size: "sm"
|
|
83
|
+
}) + " [--release-duration:var(--duration-gentle)] [--release-ease:var(--ease-gentle)]" + (iconOnly ? " w-(--density-control-h-sm) px-0" : ""), className);
|
|
84
|
+
return /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsxs(Button, {
|
|
85
|
+
ref,
|
|
86
|
+
"data-slot": "button",
|
|
87
|
+
"data-copy-state": state,
|
|
88
|
+
"aria-label": label,
|
|
89
|
+
isDisabled,
|
|
90
|
+
onPressStart: pressStart,
|
|
91
|
+
onPress: () => {
|
|
92
|
+
copy(value).then((ok) => {
|
|
93
|
+
if (ok) onCopied?.();
|
|
94
|
+
});
|
|
95
|
+
},
|
|
96
|
+
className: classes,
|
|
97
|
+
children: [/* @__PURE__ */ jsx(IconSwap, {
|
|
98
|
+
iconKey: state,
|
|
99
|
+
calm: true,
|
|
100
|
+
className: cn(ICON, "relative"),
|
|
101
|
+
children: /* @__PURE__ */ jsx("span", {
|
|
102
|
+
className: state === "copied" ? "text-success-strong" : state === "error" ? "text-destructive-strong" : void 0,
|
|
103
|
+
children: /* @__PURE__ */ jsx(StateIcon, { state })
|
|
104
|
+
})
|
|
105
|
+
}), iconOnly ? null : /* @__PURE__ */ jsxs("span", {
|
|
106
|
+
className: "-mx-1 grid min-w-0 overflow-x-clip px-1 text-start whitespace-nowrap",
|
|
107
|
+
"aria-hidden": "true",
|
|
108
|
+
children: [[
|
|
109
|
+
label,
|
|
110
|
+
"Copied",
|
|
111
|
+
"Failed"
|
|
112
|
+
].map((measure) => /* @__PURE__ */ jsx("span", {
|
|
113
|
+
className: "invisible col-start-1 row-start-1",
|
|
114
|
+
children: measure
|
|
115
|
+
}, measure)), /* @__PURE__ */ jsx("span", {
|
|
116
|
+
className: "col-start-1 row-start-1 justify-self-start",
|
|
117
|
+
children: /* @__PURE__ */ jsx(MorphText, {
|
|
118
|
+
text,
|
|
119
|
+
morphWidth: false,
|
|
120
|
+
calm: true
|
|
121
|
+
})
|
|
122
|
+
})]
|
|
123
|
+
})]
|
|
124
|
+
}), /* @__PURE__ */ jsx("span", {
|
|
125
|
+
className: "sr-only",
|
|
126
|
+
role: "status",
|
|
127
|
+
"aria-live": "polite",
|
|
128
|
+
children: state === "idle" ? "" : state === "error" ? label + ": Could not copy" : label + ": Copied"
|
|
129
|
+
})] });
|
|
130
|
+
});
|
|
131
|
+
//#endregion
|
|
132
|
+
export { CopyButton };
|
|
133
|
+
|
|
134
|
+
//# sourceMappingURL=copy-button.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"copy-button.js","names":["AriaButton"],"sources":["../../src/copy-button/copy-button.tsx"],"sourcesContent":["\"use client\";\n\nimport { forwardRef } 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 { IconSwap } from \"../lib/icon-swap.js\";\nimport { MorphText } from \"../lib/morph-text.js\";\nimport { useCopyFeedback, type CopyFeedbackState } from \"../lib/use-copy-feedback.js\";\n\nexport interface CopyButtonProps {\n /** What goes on the clipboard. */\n value: string;\n /** The label at rest, and the button's accessible name. @default \"Copy\" */\n children?: string;\n /** Only the icon, a square button. The label is still its accessible name. */\n iconOnly?: boolean;\n /** `plain` has no border until hovered. @default \"outline\" */\n variant?: \"outline\" | \"plain\";\n isDisabled?: boolean;\n /** Called once the text has reached the clipboard. */\n onCopied?: () => void;\n /** Extra classes. Merged last, so they win conflicts with ours. */\n className?: string;\n}\n\nconst ICON = \"size-4\";\n\n/** The tick draws itself from its short stroke, the way a hand would write it: quick to start, then easing into place. */\nfunction DrawnCheck() {\n return (\n <svg\n className={ICON}\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 >\n <path\n d=\"M4 12l5 5L20 6\"\n pathLength={1}\n className=\"[stroke-dasharray:1] motion-safe:animate-check-draw-calm\"\n />\n </svg>\n );\n}\n\nfunction StateIcon({ state }: { state: CopyFeedbackState }) {\n if (state === \"copied\") return <DrawnCheck />;\n const common = {\n className: ICON,\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 } as const;\n if (state === \"error\") {\n return (\n <svg {...common}>\n <circle cx=\"12\" cy=\"12\" r=\"10\" />\n <path d=\"M12 8v4M12 16h.01\" />\n </svg>\n );\n }\n return (\n <svg {...common}>\n <rect x=\"8\" y=\"8\" width=\"14\" height=\"14\" rx=\"2\" />\n <path d=\"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2\" />\n </svg>\n );\n}\n\n/**\n * Copies a value and says so, calmly. The icon trades places in one soft breath\n * (copy, then a tick that draws itself, or an alert if the clipboard refused)\n * while the label's changed letters rise in, and the button never changes width:\n * its label cell reserves the widest of the three texts.\n *\n * It goes back to rest by itself after a moment, and a live region announces the\n * result. The accessible name is always the resting label.\n *\n * @example\n * <CopyButton value={token} />\n * <CopyButton value={url} iconOnly variant=\"plain\" />\n */\nexport const CopyButton = forwardRef<HTMLButtonElement, CopyButtonProps>(function CopyButton(\n {\n value,\n children: label = \"Copy\",\n iconOnly = false,\n variant = \"outline\",\n isDisabled,\n onCopied,\n className,\n },\n ref,\n) {\n const { state, copy } = useCopyFeedback();\n const text = state === \"copied\" ? \"Copied\" : state === \"error\" ? \"Failed\" : label;\n\n // Not width-based like Button's press: an icon button presses a little deeper, every other one the same.\n const pressStart = (event: PressEvent) => {\n (event.target as HTMLElement).style.setProperty(\"--press-scale\", iconOnly ? \"0.96\" : \"0.97\");\n };\n\n const classes = cn(\n buttonVariants({ variant: variant === \"plain\" ? \"ghost\" : \"outlineNeutral\", size: \"sm\" }) +\n \" [--release-duration:var(--duration-gentle)] [--release-ease:var(--ease-gentle)]\" +\n (iconOnly ? \" w-(--density-control-h-sm) px-0\" : \"\"),\n className,\n );\n\n return (\n <>\n <AriaButton\n ref={ref}\n data-slot=\"button\"\n data-copy-state={state}\n aria-label={label}\n isDisabled={isDisabled}\n onPressStart={pressStart}\n onPress={() => {\n void copy(value).then((ok) => {\n if (ok) onCopied?.();\n });\n }}\n className={classes}\n >\n <IconSwap iconKey={state} calm className={cn(ICON, \"relative\")}>\n <span\n className={\n state === \"copied\"\n ? \"text-success-strong\"\n : state === \"error\"\n ? \"text-destructive-strong\"\n : undefined\n }\n >\n <StateIcon state={state} />\n </span>\n </IconSwap>\n {iconOnly ? null : (\n // The cell reserves the widest state, so nothing moves but the letters. The inline padding gives blurred\n // edge letters room before the horizontal clip; the negative margin keeps the box the same size.\n <span\n className=\"-mx-1 grid min-w-0 overflow-x-clip px-1 text-start whitespace-nowrap\"\n aria-hidden=\"true\"\n >\n {[label, \"Copied\", \"Failed\"].map((measure) => (\n <span key={measure} className=\"invisible col-start-1 row-start-1\">\n {measure}\n </span>\n ))}\n <span className=\"col-start-1 row-start-1 justify-self-start\">\n <MorphText text={text} morphWidth={false} calm />\n </span>\n </span>\n )}\n </AriaButton>\n <span className=\"sr-only\" role=\"status\" aria-live=\"polite\">\n {state === \"idle\"\n ? \"\"\n : state === \"error\"\n ? label + \": Could not copy\"\n : label + \": Copied\"}\n </span>\n </>\n );\n});\n"],"mappings":";;;;;;;;;;AA2BA,MAAM,OAAO;;AAGb,SAAS,aAAa;CACpB,OACE,oBAAC,OAAD;EACE,WAAW;EACX,SAAQ;EACR,MAAK;EACL,QAAO;EACP,aAAa;EACb,eAAc;EACd,gBAAe;EACf,eAAY;EAEZ,UAAA,oBAAC,QAAD;GACE,GAAE;GACF,YAAY;GACZ,WAAU;EACX,CAAA;CACE,CAAA;AAET;AAEA,SAAS,UAAU,EAAE,SAAuC;CAC1D,IAAI,UAAU,UAAU,OAAO,oBAAC,YAAD,CAAa,CAAA;CAC5C,MAAM,SAAS;EACb,WAAW;EACX,SAAS;EACT,MAAM;EACN,QAAQ;EACR,aAAa;EACb,eAAe;EACf,gBAAgB;EAChB,eAAe;CACjB;CACA,IAAI,UAAU,SACZ,OACE,qBAAC,OAAD;EAAK,GAAI;EAAT,UAAA,CACE,oBAAC,UAAD;GAAQ,IAAG;GAAK,IAAG;GAAK,GAAE;EAAM,CAAA,GAChC,oBAAC,QAAD,EAAM,GAAE,oBAAqB,CAAA,CAC1B;;CAGT,OACE,qBAAC,OAAD;EAAK,GAAI;EAAT,UAAA,CACE,oBAAC,QAAD;GAAM,GAAE;GAAI,GAAE;GAAI,OAAM;GAAK,QAAO;GAAK,IAAG;EAAK,CAAA,GACjD,oBAAC,QAAD,EAAM,GAAE,0DAA2D,CAAA,CAChE;;AAET;;;;;;;;;;;;;;AAeA,MAAa,aAAa,WAA+C,SAAS,WAChF,EACE,OACA,UAAU,QAAQ,QAClB,WAAW,OACX,UAAU,WACV,YACA,UACA,aAEF,KACA;CACA,MAAM,EAAE,OAAO,SAAS,gBAAgB;CACxC,MAAM,OAAO,UAAU,WAAW,WAAW,UAAU,UAAU,WAAW;CAG5E,MAAM,cAAc,UAAsB;EACxC,MAAO,OAAuB,MAAM,YAAY,iBAAiB,WAAW,SAAS,MAAM;CAC7F;CAEA,MAAM,UAAU,GACd,eAAe;EAAE,SAAS,YAAY,UAAU,UAAU;EAAkB,MAAM;CAAK,CAAC,IACtF,sFACC,WAAW,qCAAqC,KACnD,SACF;CAEA,OACE,qBAAA,YAAA,EAAA,UAAA,CACE,qBAACA,QAAD;EACO;EACL,aAAU;EACV,mBAAiB;EACjB,cAAY;EACA;EACZ,cAAc;EACd,eAAe;GACb,KAAU,KAAK,CAAC,CAAC,MAAM,OAAO;IAC5B,IAAI,IAAI,WAAW;GACrB,CAAC;EACH;EACA,WAAW;EAZb,UAAA,CAcE,oBAAC,UAAD;GAAU,SAAS;GAAO,MAAA;GAAK,WAAW,GAAG,MAAM,UAAU;GAC3D,UAAA,oBAAC,QAAD;IACE,WACE,UAAU,WACN,wBACA,UAAU,UACR,4BACA,KAAA;IAGR,UAAA,oBAAC,WAAD,EAAkB,MAAQ,CAAA;GACtB,CAAA;EACE,CAAA,GACT,WAAW,OAGV,qBAAC,QAAD;GACE,WAAU;GACV,eAAY;GAFd,UAAA,CAIG;IAAC;IAAO;IAAU;GAAQ,CAAC,CAAC,KAAK,YAChC,oBAAC,QAAD;IAAoB,WAAU;IAC3B,UAAA;GACG,GAFK,OAEL,CACP,GACD,oBAAC,QAAD;IAAM,WAAU;IACd,UAAA,oBAAC,WAAD;KAAiB;KAAM,YAAY;KAAO,MAAA;IAAM,CAAA;GAC5C,CAAA,CACF;EAEE,CAAA,CAAA;CACZ,CAAA,GAAA,oBAAC,QAAD;EAAM,WAAU;EAAU,MAAK;EAAS,aAAU;EAC/C,UAAA,UAAU,SACP,KACA,UAAU,UACR,QAAQ,qBACR,QAAQ;CACV,CAAA,CACN,EAAA,CAAA;AAEN,CAAC"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { ReactNode } from "react";
|
|
2
|
+
//#region src/countdown/countdown.d.ts
|
|
3
|
+
export type CountdownUnit = "days" | "hours" | "minutes" | "seconds";
|
|
4
|
+
/**
|
|
5
|
+
* Countdown: the time left until a fixed moment people wait for, such as a
|
|
6
|
+
* launch, a live event or a deadline. Each digit is a wheel that takes the short
|
|
7
|
+
* way round, so a tick turns downward and 00 to 59 is a single step; the first
|
|
8
|
+
* reading rolls up from zero, one digit after another. When the moment passes
|
|
9
|
+
* the digits give way to `completeLabel` and the box follows the new size.
|
|
10
|
+
*
|
|
11
|
+
* The clock runs only while the countdown is on screen and the tab is visible,
|
|
12
|
+
* and reads the clock again on return, so it never drifts. Completion is armed
|
|
13
|
+
* separately, so `onComplete` fires on time even while the ticking is paused.
|
|
14
|
+
*
|
|
15
|
+
* The digits are a picture. The timer is read as plain text ("1 day, 2 hours,
|
|
16
|
+
* 5 minutes") that is not announced every second, and finishing is announced
|
|
17
|
+
* once, politely. Reduced motion jumps.
|
|
18
|
+
*/
|
|
19
|
+
export interface CountdownProps {
|
|
20
|
+
/**
|
|
21
|
+
* 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
|
|
22
|
+
* 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
|
|
23
|
+
* no zone is given, so the result never depends on the visitor's own time zone.
|
|
24
|
+
*/
|
|
25
|
+
target: Date | number | string;
|
|
26
|
+
/** IANA zone for a target string without an offset, such as "America/Los_Angeles". Daylight saving is resolved for the target date. */
|
|
27
|
+
timeZone?: string;
|
|
28
|
+
/** 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"] */
|
|
29
|
+
units?: CountdownUnit[];
|
|
30
|
+
/** Large digits with unit names, or one compact line for banners and table cells. @default "large" */
|
|
31
|
+
variant?: "large" | "compact";
|
|
32
|
+
/** Shown once the target passes. The digits swap into it. @default "Live now" */
|
|
33
|
+
completeLabel?: ReactNode;
|
|
34
|
+
/** Fires once, the moment the countdown reaches zero while mounted. It fires on time even when the tab is hidden. */
|
|
35
|
+
onComplete?: () => void;
|
|
36
|
+
/** Accessible name, such as "Keynote starts in". @default "Time remaining" */
|
|
37
|
+
label?: string;
|
|
38
|
+
/** Clock source in epoch milliseconds. Pass a server-synced clock when the visitor's device time cannot be trusted. @default Date.now */
|
|
39
|
+
clock?: () => number;
|
|
40
|
+
/** Extra classes for the countdown. Merged last. */
|
|
41
|
+
className?: string;
|
|
42
|
+
}
|
|
43
|
+
export declare const Countdown: import("react").ForwardRefExoticComponent<CountdownProps & import("react").RefAttributes<HTMLDivElement>>;
|
|
44
|
+
//#endregion
|
|
45
|
+
//# sourceMappingURL=countdown.d.ts.map
|