@evinvest/uikit 0.30.0 → 0.32.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +267 -73
- package/dist/{chunk-3IPB4QQJ.js → chunk-35SPIU4U.js} +10 -6
- package/dist/chunk-35SPIU4U.js.map +1 -0
- package/dist/components/{accordion.js → atomic/accordion.js} +3 -3
- package/dist/components/atomic/accordion.js.map +1 -0
- package/dist/components/{alert-dialog.js → atomic/alert-dialog.js} +11 -10
- package/dist/components/atomic/alert-dialog.js.map +1 -0
- package/dist/components/{alert.js → atomic/alert.js} +2 -2
- package/dist/components/atomic/alert.js.map +1 -0
- package/dist/components/atomic/animated-number-columns.js +105 -0
- package/dist/components/atomic/animated-number-columns.js.map +1 -0
- package/dist/components/{avatar.js → atomic/avatar.js} +2 -2
- package/dist/components/atomic/avatar.js.map +1 -0
- package/dist/components/{badge.js → atomic/badge.js} +4 -4
- package/dist/components/atomic/badge.js.map +1 -0
- package/dist/components/{band.js → atomic/band.js} +2 -2
- package/dist/components/atomic/band.js.map +1 -0
- package/dist/components/{breadcrumb.js → atomic/breadcrumb.js} +3 -3
- package/dist/components/atomic/breadcrumb.js.map +1 -0
- package/dist/components/{button-group.js → atomic/button-group.js} +3 -3
- package/dist/components/atomic/button-group.js.map +1 -0
- package/dist/components/{button.js → atomic/button.js} +7 -15
- package/dist/components/atomic/button.js.map +1 -0
- package/dist/components/{calendar.js → atomic/calendar.js} +2 -2
- package/dist/components/atomic/calendar.js.map +1 -0
- package/dist/components/{card.js → atomic/card.js} +2 -2
- package/dist/components/atomic/card.js.map +1 -0
- package/dist/components/{checkbox.js → atomic/checkbox.js} +4 -4
- package/dist/components/atomic/checkbox.js.map +1 -0
- package/dist/components/{collapsible.js → atomic/collapsible.js} +1 -1
- package/dist/components/atomic/collapsible.js.map +1 -0
- package/dist/components/{command.js → atomic/command.js} +9 -7
- package/dist/components/atomic/command.js.map +1 -0
- package/dist/components/{container.js → atomic/container.js} +2 -2
- package/dist/components/atomic/container.js.map +1 -0
- package/dist/components/{context-menu.js → atomic/context-menu.js} +62 -14
- package/dist/components/atomic/context-menu.js.map +1 -0
- package/dist/components/{dialog.js → atomic/dialog.js} +11 -10
- package/dist/components/atomic/dialog.js.map +1 -0
- package/dist/components/{drawer.js → atomic/drawer.js} +10 -8
- package/dist/components/atomic/drawer.js.map +1 -0
- package/dist/components/{dropdown-menu.js → atomic/dropdown-menu.js} +74 -15
- package/dist/components/atomic/dropdown-menu.js.map +1 -0
- package/dist/components/{empty.js → atomic/empty.js} +2 -2
- package/dist/components/atomic/empty.js.map +1 -0
- package/dist/components/atomic/field-context.js.map +1 -0
- package/dist/components/atomic/form-row.js +51 -0
- package/dist/components/atomic/form-row.js.map +1 -0
- package/dist/components/{hover-card.js → atomic/hover-card.js} +8 -8
- package/dist/components/atomic/hover-card.js.map +1 -0
- package/dist/components/{info-tip.js → atomic/info-tip.js} +10 -10
- package/dist/components/atomic/info-tip.js.map +1 -0
- package/dist/components/{input-otp.js → atomic/input-otp.js} +3 -3
- package/dist/components/atomic/input-otp.js.map +1 -0
- package/dist/components/{input.js → atomic/input.js} +3 -3
- package/dist/components/atomic/input.js.map +1 -0
- package/dist/components/{kbd.js → atomic/kbd.js} +2 -2
- package/dist/components/atomic/kbd.js.map +1 -0
- package/dist/components/atomic/key-value.js +68 -0
- package/dist/components/atomic/key-value.js.map +1 -0
- package/dist/components/{label.js → atomic/label.js} +2 -2
- package/dist/components/atomic/label.js.map +1 -0
- package/dist/components/{menubar.js → atomic/menubar.js} +48 -14
- package/dist/components/atomic/menubar.js.map +1 -0
- package/dist/components/{native-select.js → atomic/native-select.js} +6 -7
- package/dist/components/atomic/native-select.js.map +1 -0
- package/dist/components/{navigation-menu.js → atomic/navigation-menu.js} +11 -12
- package/dist/components/atomic/navigation-menu.js.map +1 -0
- package/dist/components/{pagination.js → atomic/pagination.js} +1 -1
- package/dist/components/atomic/pagination.js.map +1 -0
- package/dist/components/{popover.js → atomic/popover.js} +10 -10
- package/dist/components/atomic/popover.js.map +1 -0
- package/dist/components/{progress.js → atomic/progress.js} +2 -2
- package/dist/components/atomic/progress.js.map +1 -0
- package/dist/components/{radio-group.js → atomic/radio-group.js} +4 -4
- package/dist/components/atomic/radio-group.js.map +1 -0
- package/dist/components/{scroll-area.js → atomic/scroll-area.js} +2 -2
- package/dist/components/atomic/scroll-area.js.map +1 -0
- package/dist/components/{section-descriptor.js → atomic/section-descriptor.js} +2 -2
- package/dist/components/atomic/section-descriptor.js.map +1 -0
- package/dist/components/{select-listbox.js → atomic/select-listbox.js} +1 -1
- package/dist/components/atomic/select-listbox.js.map +1 -0
- package/dist/components/{select.js → atomic/select.js} +26 -16
- package/dist/components/atomic/select.js.map +1 -0
- package/dist/components/{separator.js → atomic/separator.js} +2 -2
- package/dist/components/atomic/separator.js.map +1 -0
- package/dist/components/{sheet.js → atomic/sheet.js} +11 -10
- package/dist/components/atomic/sheet.js.map +1 -0
- package/dist/components/{sidebar.js → atomic/sidebar.js} +5 -5
- package/dist/components/atomic/sidebar.js.map +1 -0
- package/dist/components/{skeleton.js → atomic/skeleton.js} +2 -2
- package/dist/components/atomic/skeleton.js.map +1 -0
- package/dist/components/{slider.js → atomic/slider.js} +3 -3
- package/dist/components/atomic/slider.js.map +1 -0
- package/dist/components/{sonner.js → atomic/sonner.js} +2 -2
- package/dist/components/atomic/sonner.js.map +1 -0
- package/dist/components/{spinner.js → atomic/spinner.js} +1 -1
- package/dist/components/atomic/spinner.js.map +1 -0
- package/dist/components/atomic/status-item.js +42 -0
- package/dist/components/atomic/status-item.js.map +1 -0
- package/dist/components/{switch.js → atomic/switch.js} +4 -4
- package/dist/components/atomic/switch.js.map +1 -0
- package/dist/components/{table.js → atomic/table.js} +2 -2
- package/dist/components/atomic/table.js.map +1 -0
- package/dist/components/{tabs.js → atomic/tabs.js} +4 -4
- package/dist/components/atomic/tabs.js.map +1 -0
- package/dist/components/{textarea.js → atomic/textarea.js} +3 -3
- package/dist/components/atomic/textarea.js.map +1 -0
- package/dist/components/{toggle-group.js → atomic/toggle-group.js} +2 -2
- package/dist/components/atomic/toggle-group.js.map +1 -0
- package/dist/components/{toggle.js → atomic/toggle.js} +3 -3
- package/dist/components/atomic/toggle.js.map +1 -0
- package/dist/components/{tooltip.js → atomic/tooltip.js} +8 -8
- package/dist/components/atomic/tooltip.js.map +1 -0
- package/dist/components/atomic/use-count-tween.js +42 -0
- package/dist/components/atomic/use-count-tween.js.map +1 -0
- package/dist/components/derived/animated-number.js +157 -0
- package/dist/components/derived/animated-number.js.map +1 -0
- package/dist/components/{carousel.js → derived/carousel.js} +4 -4
- package/dist/components/derived/carousel.js.map +1 -0
- package/dist/components/derived/command-palette.js +119 -0
- package/dist/components/derived/command-palette.js.map +1 -0
- package/dist/components/derived/confirm-dialog.js +123 -0
- package/dist/components/derived/confirm-dialog.js.map +1 -0
- package/dist/components/{date-time-picker.js → derived/date-time-picker.js} +8 -8
- package/dist/components/derived/date-time-picker.js.map +1 -0
- package/dist/components/{field.js → derived/field.js} +6 -6
- package/dist/components/derived/field.js.map +1 -0
- package/dist/components/{form.js → derived/form.js} +4 -4
- package/dist/components/derived/form.js.map +1 -0
- package/dist/components/derived/icon-button.js +35 -0
- package/dist/components/derived/icon-button.js.map +1 -0
- package/dist/components/{input-group.js → derived/input-group.js} +5 -5
- package/dist/components/derived/input-group.js.map +1 -0
- package/dist/components/{item.js → derived/item.js} +4 -4
- package/dist/components/derived/item.js.map +1 -0
- package/dist/components/derived/popover-form.js +60 -0
- package/dist/components/derived/popover-form.js.map +1 -0
- package/dist/components/derived/settings.js +94 -0
- package/dist/components/derived/settings.js.map +1 -0
- package/dist/components/shell/account-list.js +128 -0
- package/dist/components/shell/account-list.js.map +1 -0
- package/dist/components/shell/account-menu-profile.js +114 -0
- package/dist/components/shell/account-menu-profile.js.map +1 -0
- package/dist/components/shell/account-menu.js +97 -0
- package/dist/components/shell/account-menu.js.map +1 -0
- package/dist/components/shell/account-settings-dialog.js +84 -0
- package/dist/components/shell/account-settings-dialog.js.map +1 -0
- package/dist/components/{app-shell.js → shell/app-shell.js} +10 -1
- package/dist/components/shell/app-shell.js.map +1 -0
- package/dist/components/shell/aside.js +140 -0
- package/dist/components/shell/aside.js.map +1 -0
- package/dist/components/{auth-wall.js → shell/auth-wall.js} +1 -1
- package/dist/components/shell/auth-wall.js.map +1 -0
- package/dist/components/{bottom-tab-bar.js → shell/bottom-tab-bar.js} +1 -1
- package/dist/components/shell/bottom-tab-bar.js.map +1 -0
- package/dist/components/shell/chat-composer.js +141 -0
- package/dist/components/shell/chat-composer.js.map +1 -0
- package/dist/components/shell/chat-message.js +195 -0
- package/dist/components/shell/chat-message.js.map +1 -0
- package/dist/components/shell/chat-panel.js +137 -0
- package/dist/components/shell/chat-panel.js.map +1 -0
- package/dist/components/shell/chat-stream-text.js +69 -0
- package/dist/components/shell/chat-stream-text.js.map +1 -0
- package/dist/components/shell/chat-typing.js +26 -0
- package/dist/components/shell/chat-typing.js.map +1 -0
- package/dist/components/{footer.js → shell/footer.js} +1 -1
- package/dist/components/shell/footer.js.map +1 -0
- package/dist/components/shell/header-controls.js +149 -0
- package/dist/components/shell/header-controls.js.map +1 -0
- package/dist/components/{list-rows.js → shell/list-rows.js} +1 -1
- package/dist/components/shell/list-rows.js.map +1 -0
- package/dist/components/{logo.js → shell/logo.js} +1 -1
- package/dist/components/shell/logo.js.map +1 -0
- package/dist/components/{mobile-app-bar.js → shell/mobile-app-bar.js} +1 -1
- package/dist/components/shell/mobile-app-bar.js.map +1 -0
- package/dist/components/{nav-badge.js → shell/nav-badge.js} +1 -1
- package/dist/components/shell/nav-badge.js.map +1 -0
- package/dist/components/shell/nav-collapse.js +142 -0
- package/dist/components/shell/nav-collapse.js.map +1 -0
- package/dist/components/shell/nav-link.js.map +1 -0
- package/dist/components/shell/nav-model.js.map +1 -0
- package/dist/components/{page-frame.js → shell/page-frame.js} +3 -6
- package/dist/components/shell/page-frame.js.map +1 -0
- package/dist/components/{resource-error.js → shell/resource-error.js} +4 -4
- package/dist/components/shell/resource-error.js.map +1 -0
- package/dist/components/shell/section-nav.js +139 -0
- package/dist/components/shell/section-nav.js.map +1 -0
- package/dist/components/shell/settled.js.map +1 -0
- package/dist/components/shell/shell-icons.js.map +1 -0
- package/dist/components/{shell-nav.js → shell/shell-nav.js} +81 -39
- package/dist/components/shell/shell-nav.js.map +1 -0
- package/dist/components/shell/smart-header.js +53 -0
- package/dist/components/shell/smart-header.js.map +1 -0
- package/dist/components/{status-screen.js → shell/status-screen.js} +3 -3
- package/dist/components/shell/status-screen.js.map +1 -0
- package/dist/components/{system-banner.js → shell/system-banner.js} +23 -13
- package/dist/components/shell/system-banner.js.map +1 -0
- package/dist/components/{top-bar.js → shell/top-bar.js} +5 -4
- package/dist/components/shell/top-bar.js.map +1 -0
- package/dist/components/shell/use-shell-nav.js.map +1 -0
- package/dist/components/shell/workspace-tab.js +140 -0
- package/dist/components/shell/workspace-tab.js.map +1 -0
- package/dist/generated/accent.js +2 -2
- package/dist/generated/accent.js.map +1 -1
- package/dist/generated/account-list.js +35 -0
- package/dist/generated/account-list.js.map +1 -0
- package/dist/generated/account-settings-dialog.js +27 -0
- package/dist/generated/account-settings-dialog.js.map +1 -0
- package/dist/generated/alert-dialog.js +1 -1
- package/dist/generated/alert-dialog.js.map +1 -1
- package/dist/generated/alert.js +2 -2
- package/dist/generated/alert.js.map +1 -1
- package/dist/generated/aside.js +36 -0
- package/dist/generated/aside.js.map +1 -0
- package/dist/generated/badge.js +7 -6
- package/dist/generated/badge.js.map +1 -1
- package/dist/generated/band.js +1 -1
- package/dist/generated/band.js.map +1 -1
- package/dist/generated/breadcrumb.js +2 -2
- package/dist/generated/breadcrumb.js.map +1 -1
- package/dist/generated/button-group.js +2 -2
- package/dist/generated/button-group.js.map +1 -1
- package/dist/generated/button.js +4 -4
- package/dist/generated/button.js.map +1 -1
- package/dist/generated/card.js +6 -6
- package/dist/generated/card.js.map +1 -1
- package/dist/generated/chat-composer.js +21 -0
- package/dist/generated/chat-composer.js.map +1 -0
- package/dist/generated/chat-message.js +86 -0
- package/dist/generated/chat-message.js.map +1 -0
- package/dist/generated/chat-typing.js +9 -0
- package/dist/generated/chat-typing.js.map +1 -0
- package/dist/generated/command-palette.js +17 -0
- package/dist/generated/command-palette.js.map +1 -0
- package/dist/generated/command.js +2 -2
- package/dist/generated/command.js.map +1 -1
- package/dist/generated/confirm-dialog.js +28 -0
- package/dist/generated/confirm-dialog.js.map +1 -0
- package/dist/generated/context-menu.js +1 -1
- package/dist/generated/context-menu.js.map +1 -1
- package/dist/generated/date-time-picker.js +1 -1
- package/dist/generated/date-time-picker.js.map +1 -1
- package/dist/generated/dialog.js +1 -1
- package/dist/generated/dialog.js.map +1 -1
- package/dist/generated/drawer.js +1 -1
- package/dist/generated/drawer.js.map +1 -1
- package/dist/generated/dropdown-menu.js +1 -1
- package/dist/generated/dropdown-menu.js.map +1 -1
- package/dist/generated/form-row.js +17 -0
- package/dist/generated/form-row.js.map +1 -0
- package/dist/generated/header-controls.js +56 -0
- package/dist/generated/header-controls.js.map +1 -0
- package/dist/generated/icon-button.js +13 -0
- package/dist/generated/icon-button.js.map +1 -0
- package/dist/generated/key-value.js +15 -0
- package/dist/generated/key-value.js.map +1 -0
- package/dist/generated/menubar.js +1 -1
- package/dist/generated/menubar.js.map +1 -1
- package/dist/generated/navigation-menu.js +1 -1
- package/dist/generated/navigation-menu.js.map +1 -1
- package/dist/generated/popover-form.js +13 -0
- package/dist/generated/popover-form.js.map +1 -0
- package/dist/generated/section-label.js +10 -0
- package/dist/generated/section-label.js.map +1 -0
- package/dist/generated/select.js +15 -3
- package/dist/generated/select.js.map +1 -1
- package/dist/generated/settings.js +36 -0
- package/dist/generated/settings.js.map +1 -0
- package/dist/generated/sheet.js +1 -1
- package/dist/generated/sheet.js.map +1 -1
- package/dist/generated/slider.js +1 -1
- package/dist/generated/slider.js.map +1 -1
- package/dist/generated/smart-header.js +11 -0
- package/dist/generated/smart-header.js.map +1 -0
- package/dist/generated/sonner.js +4 -4
- package/dist/generated/sonner.js.map +1 -1
- package/dist/generated/status-item.js +17 -0
- package/dist/generated/status-item.js.map +1 -0
- package/dist/generated/system-banner.js +33 -0
- package/dist/generated/system-banner.js.map +1 -0
- package/dist/generated/top-bar.js +9 -0
- package/dist/generated/top-bar.js.map +1 -0
- package/dist/generated/workspace-tab.js +17 -0
- package/dist/generated/workspace-tab.js.map +1 -0
- package/dist/icons/select-chevron.js.map +1 -0
- package/dist/icons/ui-icons.js +77 -0
- package/dist/icons/ui-icons.js.map +1 -0
- package/dist/index.d.ts +852 -156
- package/dist/index.js +96 -76
- package/dist/lib/cn.js +8 -1
- package/dist/lib/cn.js.map +1 -1
- package/dist/lib/number-parts.js +90 -0
- package/dist/lib/number-parts.js.map +1 -0
- package/dist/palette-cli.js +1 -1
- package/dist/palette.d.ts +6 -4
- package/dist/palette.js +3 -1
- package/dist/primitives/dismissable-layer.js +76 -4
- package/dist/primitives/dismissable-layer.js.map +1 -1
- package/dist/primitives/focus-scope.js +20 -5
- package/dist/primitives/focus-scope.js.map +1 -1
- package/dist/primitives/use-floating.js +16 -1
- package/dist/primitives/use-floating.js.map +1 -1
- package/dist/primitives/use-reduced-motion.js +20 -0
- package/dist/primitives/use-reduced-motion.js.map +1 -0
- package/package.json +2 -2
- package/styles/ev.css +281 -49
- package/styles/theme.css +335 -39
- package/styles/tokens.css +643 -103
- package/dist/chunk-3IPB4QQJ.js.map +0 -1
- package/dist/components/accordion.js.map +0 -1
- package/dist/components/account-menu.js +0 -70
- package/dist/components/account-menu.js.map +0 -1
- package/dist/components/alert-dialog.js.map +0 -1
- package/dist/components/alert.js.map +0 -1
- package/dist/components/app-shell.js.map +0 -1
- package/dist/components/auth-wall.js.map +0 -1
- package/dist/components/avatar.js.map +0 -1
- package/dist/components/badge.js.map +0 -1
- package/dist/components/band.js.map +0 -1
- package/dist/components/bottom-tab-bar.js.map +0 -1
- package/dist/components/breadcrumb.js.map +0 -1
- package/dist/components/button-group.js.map +0 -1
- package/dist/components/button.js.map +0 -1
- package/dist/components/calendar.js.map +0 -1
- package/dist/components/card.js.map +0 -1
- package/dist/components/carousel.js.map +0 -1
- package/dist/components/checkbox.js.map +0 -1
- package/dist/components/collapsible.js.map +0 -1
- package/dist/components/command.js.map +0 -1
- package/dist/components/container.js.map +0 -1
- package/dist/components/context-menu.js.map +0 -1
- package/dist/components/date-time-picker.js.map +0 -1
- package/dist/components/dialog.js.map +0 -1
- package/dist/components/drawer.js.map +0 -1
- package/dist/components/dropdown-menu.js.map +0 -1
- package/dist/components/empty.js.map +0 -1
- package/dist/components/field-context.js.map +0 -1
- package/dist/components/field.js.map +0 -1
- package/dist/components/footer.js.map +0 -1
- package/dist/components/form.js.map +0 -1
- package/dist/components/hover-card.js.map +0 -1
- package/dist/components/info-tip.js.map +0 -1
- package/dist/components/input-group.js.map +0 -1
- package/dist/components/input-otp.js.map +0 -1
- package/dist/components/input.js.map +0 -1
- package/dist/components/item.js.map +0 -1
- package/dist/components/kbd.js.map +0 -1
- package/dist/components/label.js.map +0 -1
- package/dist/components/list-rows.js.map +0 -1
- package/dist/components/logo.js.map +0 -1
- package/dist/components/menubar.js.map +0 -1
- package/dist/components/mobile-app-bar.js.map +0 -1
- package/dist/components/native-select.js.map +0 -1
- package/dist/components/nav-badge.js.map +0 -1
- package/dist/components/nav-link.js.map +0 -1
- package/dist/components/nav-model.js.map +0 -1
- package/dist/components/navigation-menu.js.map +0 -1
- package/dist/components/page-frame.js.map +0 -1
- package/dist/components/pagination.js.map +0 -1
- package/dist/components/popover.js.map +0 -1
- package/dist/components/progress.js.map +0 -1
- package/dist/components/radio-group.js.map +0 -1
- package/dist/components/resource-error.js.map +0 -1
- package/dist/components/scroll-area.js.map +0 -1
- package/dist/components/section-descriptor.js.map +0 -1
- package/dist/components/section-nav.js +0 -86
- package/dist/components/section-nav.js.map +0 -1
- package/dist/components/select-chevron.js.map +0 -1
- package/dist/components/select-listbox.js.map +0 -1
- package/dist/components/select.js.map +0 -1
- package/dist/components/separator.js.map +0 -1
- package/dist/components/settled.js.map +0 -1
- package/dist/components/sheet.js.map +0 -1
- package/dist/components/shell-icons.js.map +0 -1
- package/dist/components/shell-nav.js.map +0 -1
- package/dist/components/sidebar.js.map +0 -1
- package/dist/components/skeleton.js.map +0 -1
- package/dist/components/slider.js.map +0 -1
- package/dist/components/sonner.js.map +0 -1
- package/dist/components/spinner.js.map +0 -1
- package/dist/components/status-screen.js.map +0 -1
- package/dist/components/switch.js.map +0 -1
- package/dist/components/system-banner.js.map +0 -1
- package/dist/components/table.js.map +0 -1
- package/dist/components/tabs.js.map +0 -1
- package/dist/components/terminal.js +0 -206
- package/dist/components/terminal.js.map +0 -1
- package/dist/components/textarea.js.map +0 -1
- package/dist/components/toggle-group.js.map +0 -1
- package/dist/components/toggle.js.map +0 -1
- package/dist/components/tooltip.js.map +0 -1
- package/dist/components/top-bar.js.map +0 -1
- package/dist/components/use-shell-nav.js.map +0 -1
- package/dist/generated/terminal.js +0 -70
- package/dist/generated/terminal.js.map +0 -1
- /package/dist/components/{field-context.js → atomic/field-context.js} +0 -0
- /package/dist/components/{nav-link.js → shell/nav-link.js} +0 -0
- /package/dist/components/{nav-model.js → shell/nav-model.js} +0 -0
- /package/dist/components/{settled.js → shell/settled.js} +0 -0
- /package/dist/components/{shell-icons.js → shell/shell-icons.js} +0 -0
- /package/dist/components/{use-shell-nav.js → shell/use-shell-nav.js} +0 -0
- /package/dist/{components → icons}/select-chevron.js +0 -0
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
+
import * as React from "react";
|
|
4
|
+
import { cn } from "../../lib/cn.js";
|
|
5
|
+
import {
|
|
6
|
+
digitGlyphs,
|
|
7
|
+
mergeItems,
|
|
8
|
+
resolveDirection,
|
|
9
|
+
splitNumber
|
|
10
|
+
} from "../../lib/number-parts.js";
|
|
11
|
+
import { useReducedMotion } from "../../primitives/use-reduced-motion.js";
|
|
12
|
+
import { EDGE_MS, SPIN_MS, Slot } from "../atomic/animated-number-columns.js";
|
|
13
|
+
import { useCountTween } from "../atomic/use-count-tween.js";
|
|
14
|
+
function AnimatedNumber({
|
|
15
|
+
value,
|
|
16
|
+
format,
|
|
17
|
+
locales,
|
|
18
|
+
mode = "roll",
|
|
19
|
+
trend,
|
|
20
|
+
duration,
|
|
21
|
+
prefix,
|
|
22
|
+
suffix,
|
|
23
|
+
live = false,
|
|
24
|
+
animateOnMount = false,
|
|
25
|
+
from = 0,
|
|
26
|
+
className,
|
|
27
|
+
style,
|
|
28
|
+
...props
|
|
29
|
+
}) {
|
|
30
|
+
const formatKey = JSON.stringify(format ?? null);
|
|
31
|
+
const localeKey = Array.isArray(locales) ? locales.join(",") : String(locales ?? "");
|
|
32
|
+
const formatter = React.useMemo(
|
|
33
|
+
() => new Intl.NumberFormat(locales, format),
|
|
34
|
+
[localeKey, formatKey]
|
|
35
|
+
);
|
|
36
|
+
const text = formatter.format(value);
|
|
37
|
+
return /* @__PURE__ */ jsxs(
|
|
38
|
+
"span",
|
|
39
|
+
{
|
|
40
|
+
"data-slot": "animated-number",
|
|
41
|
+
"data-mode": mode,
|
|
42
|
+
className: cn("relative inline-flex items-baseline tabular-nums", className),
|
|
43
|
+
style,
|
|
44
|
+
...props,
|
|
45
|
+
children: [
|
|
46
|
+
prefix,
|
|
47
|
+
/* @__PURE__ */ jsx(
|
|
48
|
+
"span",
|
|
49
|
+
{
|
|
50
|
+
"data-slot": "animated-number-text",
|
|
51
|
+
className: "sr-only",
|
|
52
|
+
"aria-live": live ? "polite" : void 0,
|
|
53
|
+
"aria-atomic": live ? true : void 0,
|
|
54
|
+
children: text
|
|
55
|
+
}
|
|
56
|
+
),
|
|
57
|
+
/* @__PURE__ */ jsx("span", { "aria-hidden": true, className: "inline-flex select-none items-baseline", children: mode === "count" ? /* @__PURE__ */ jsx(
|
|
58
|
+
CountView,
|
|
59
|
+
{
|
|
60
|
+
value,
|
|
61
|
+
formatter,
|
|
62
|
+
from,
|
|
63
|
+
animateOnMount,
|
|
64
|
+
...duration === void 0 ? {} : { duration }
|
|
65
|
+
}
|
|
66
|
+
) : /* @__PURE__ */ jsx(
|
|
67
|
+
RollView,
|
|
68
|
+
{
|
|
69
|
+
value,
|
|
70
|
+
formatter,
|
|
71
|
+
from,
|
|
72
|
+
animateOnMount,
|
|
73
|
+
spin: duration ?? SPIN_MS,
|
|
74
|
+
...trend === void 0 ? {} : { trend }
|
|
75
|
+
}
|
|
76
|
+
) }),
|
|
77
|
+
suffix
|
|
78
|
+
]
|
|
79
|
+
}
|
|
80
|
+
);
|
|
81
|
+
}
|
|
82
|
+
function CountView({ value, formatter, from, animateOnMount, duration }) {
|
|
83
|
+
const shown = useCountTween(value, {
|
|
84
|
+
from,
|
|
85
|
+
animateOnMount,
|
|
86
|
+
...duration === void 0 ? {} : { duration }
|
|
87
|
+
});
|
|
88
|
+
return /* @__PURE__ */ jsx("span", { children: formatter.format(shown) });
|
|
89
|
+
}
|
|
90
|
+
function useMountLead(enabled) {
|
|
91
|
+
const [lead, setLead] = React.useState(false);
|
|
92
|
+
const started = React.useRef(false);
|
|
93
|
+
React.useLayoutEffect(() => {
|
|
94
|
+
if (!enabled || started.current) return;
|
|
95
|
+
started.current = true;
|
|
96
|
+
setLead(true);
|
|
97
|
+
let inner = 0;
|
|
98
|
+
const outer = requestAnimationFrame(() => {
|
|
99
|
+
inner = requestAnimationFrame(() => setLead(false));
|
|
100
|
+
});
|
|
101
|
+
return () => {
|
|
102
|
+
cancelAnimationFrame(outer);
|
|
103
|
+
cancelAnimationFrame(inner);
|
|
104
|
+
started.current = false;
|
|
105
|
+
setLead(false);
|
|
106
|
+
};
|
|
107
|
+
}, [enabled]);
|
|
108
|
+
return lead;
|
|
109
|
+
}
|
|
110
|
+
function RollView({ value, formatter, trend, spin, from, animateOnMount }) {
|
|
111
|
+
const motion = !useReducedMotion();
|
|
112
|
+
const lead = useMountLead(animateOnMount && motion);
|
|
113
|
+
const target = lead ? from : value;
|
|
114
|
+
const glyphs = React.useMemo(() => digitGlyphs(formatter), [formatter]);
|
|
115
|
+
const [state, setState] = React.useState(() => ({
|
|
116
|
+
formatter,
|
|
117
|
+
value: target,
|
|
118
|
+
direction: 0,
|
|
119
|
+
items: splitNumber(formatter, target, glyphs).map((part) => ({ part, exiting: false, fresh: false }))
|
|
120
|
+
}));
|
|
121
|
+
let current = state;
|
|
122
|
+
if (state.formatter !== formatter || state.value !== target) {
|
|
123
|
+
const sameFormat = state.formatter === formatter;
|
|
124
|
+
const animate = motion && sameFormat && !lead;
|
|
125
|
+
current = {
|
|
126
|
+
formatter,
|
|
127
|
+
value: target,
|
|
128
|
+
direction: sameFormat ? resolveDirection(trend, state.value, target) : 0,
|
|
129
|
+
items: mergeItems(state.items, splitNumber(formatter, target, glyphs), animate)
|
|
130
|
+
};
|
|
131
|
+
setState(current);
|
|
132
|
+
}
|
|
133
|
+
const leaving = current.items.some((item) => item.exiting);
|
|
134
|
+
React.useEffect(() => {
|
|
135
|
+
if (!leaving) return;
|
|
136
|
+
const id = setTimeout(
|
|
137
|
+
() => setState((s) => ({ ...s, items: s.items.filter((item) => !item.exiting) })),
|
|
138
|
+
EDGE_MS + 50
|
|
139
|
+
);
|
|
140
|
+
return () => clearTimeout(id);
|
|
141
|
+
}, [leaving, current.items]);
|
|
142
|
+
return /* @__PURE__ */ jsx(Fragment, { children: current.items.map((item) => /* @__PURE__ */ jsx(
|
|
143
|
+
Slot,
|
|
144
|
+
{
|
|
145
|
+
item,
|
|
146
|
+
glyphs,
|
|
147
|
+
direction: current.direction,
|
|
148
|
+
motion,
|
|
149
|
+
spin
|
|
150
|
+
},
|
|
151
|
+
item.part.key
|
|
152
|
+
)) });
|
|
153
|
+
}
|
|
154
|
+
export {
|
|
155
|
+
AnimatedNumber
|
|
156
|
+
};
|
|
157
|
+
//# sourceMappingURL=animated-number.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/components/derived/animated-number.tsx"],"sourcesContent":["\"use client\";\n\nimport * as React from \"react\";\nimport { cn } from \"../../lib/cn\";\nimport {\n digitGlyphs,\n mergeItems,\n resolveDirection,\n splitNumber,\n type NumberItem,\n type RollDirection,\n} from \"../../lib/number-parts\";\nimport { useReducedMotion } from \"../../primitives/use-reduced-motion\";\nimport { EDGE_MS, SPIN_MS, Slot } from \"../atomic/animated-number-columns\";\nimport { useCountTween } from \"../atomic/use-count-tween\";\n\nexport interface AnimatedNumberProps\n extends Omit<React.HTMLAttributes<HTMLSpanElement>, \"children\" | \"prefix\"> {\n value: number;\n /** Passed to `Intl.NumberFormat`: currency, percent, compact, `signDisplay`... */\n format?: Intl.NumberFormatOptions;\n locales?: Intl.LocalesArgument;\n /** `roll`: digit columns spin. `count`: the number is tweened and re-formatted each frame. Default `roll`. */\n mode?: \"roll\" | \"count\";\n /**\n * Roll only. `1` every column spins up, `-1` down, `0` each column takes its\n * shorter way. Default: up when the value rose, down when it fell.\n */\n trend?: RollDirection;\n /** Milliseconds one change takes: the spin in `roll` (default 750), the whole tween in `count` (default 800). */\n duration?: number;\n prefix?: React.ReactNode;\n suffix?: React.ReactNode;\n /** Announce each new value politely. Off by default: a ticker would talk over the page. */\n live?: boolean;\n /** Animate the first render from `from`. The server markup still prints `value`. */\n animateOnMount?: boolean;\n /** The first-render start with `animateOnMount`. Default `0`. */\n from?: number;\n}\n\n/**\n * A number that animates when `value` changes. `roll` (default) spins each\n * digit column like an odometer; `count` tweens the number itself. Both format\n * with `Intl.NumberFormat`, inherit font and colour, and swap instantly under\n * `prefers-reduced-motion`. The final formatted value is in the DOM once, as\n * text for assistive tech and for copying; the moving glyphs are `aria-hidden`.\n */\nexport function AnimatedNumber({\n value,\n format,\n locales,\n mode = \"roll\",\n trend,\n duration,\n prefix,\n suffix,\n live = false,\n animateOnMount = false,\n from = 0,\n className,\n style,\n ...props\n}: AnimatedNumberProps) {\n // Callers pass `format` inline; keying on its content keeps one formatter per distinct options.\n const formatKey = JSON.stringify(format ?? null);\n const localeKey = Array.isArray(locales) ? locales.join(\",\") : String(locales ?? \"\");\n const formatter = React.useMemo(\n () => new Intl.NumberFormat(locales, format),\n [localeKey, formatKey],\n );\n const text = formatter.format(value);\n return (\n <span\n data-slot=\"animated-number\"\n data-mode={mode}\n className={cn(\"relative inline-flex items-baseline tabular-nums\", className)}\n style={style}\n {...props}\n >\n {prefix}\n <span\n data-slot=\"animated-number-text\"\n className=\"sr-only\"\n aria-live={live ? \"polite\" : undefined}\n aria-atomic={live ? true : undefined}\n >\n {text}\n </span>\n <span aria-hidden className=\"inline-flex select-none items-baseline\">\n {mode === \"count\" ? (\n <CountView\n value={value}\n formatter={formatter}\n from={from}\n animateOnMount={animateOnMount}\n {...(duration === undefined ? {} : { duration })}\n />\n ) : (\n <RollView\n value={value}\n formatter={formatter}\n from={from}\n animateOnMount={animateOnMount}\n spin={duration ?? SPIN_MS}\n {...(trend === undefined ? {} : { trend })}\n />\n )}\n </span>\n {suffix}\n </span>\n );\n}\n\ninterface CountViewProps {\n value: number;\n formatter: Intl.NumberFormat;\n from: number;\n animateOnMount: boolean;\n duration?: number;\n}\n\nfunction CountView({ value, formatter, from, animateOnMount, duration }: CountViewProps) {\n const shown = useCountTween(value, {\n from,\n animateOnMount,\n ...(duration === undefined ? {} : { duration }),\n });\n return <span>{formatter.format(shown)}</span>;\n}\n\ninterface RollState {\n formatter: Intl.NumberFormat;\n value: number;\n direction: RollDirection;\n items: NumberItem[];\n}\n\ninterface RollViewProps {\n value: number;\n formatter: Intl.NumberFormat;\n trend?: RollDirection;\n spin: number;\n from: number;\n animateOnMount: boolean;\n}\n\n// With `animateOnMount` the first client commit shows `from` and the value\n// arrives two frames later: one frame is not enough for the browser to have\n// painted `from` and so have a start for the transition.\nfunction useMountLead(enabled: boolean): boolean {\n const [lead, setLead] = React.useState(false);\n const started = React.useRef(false);\n React.useLayoutEffect(() => {\n if (!enabled || started.current) return;\n started.current = true;\n setLead(true);\n let inner = 0;\n const outer = requestAnimationFrame(() => {\n inner = requestAnimationFrame(() => setLead(false));\n });\n return () => {\n cancelAnimationFrame(outer);\n cancelAnimationFrame(inner);\n started.current = false;\n setLead(false);\n };\n }, [enabled]);\n return lead;\n}\n\nfunction RollView({ value, formatter, trend, spin, from, animateOnMount }: RollViewProps) {\n const motion = !useReducedMotion();\n const lead = useMountLead(animateOnMount && motion);\n const target = lead ? from : value;\n const glyphs = React.useMemo(() => digitGlyphs(formatter), [formatter]);\n const [state, setState] = React.useState<RollState>(() => ({\n formatter,\n value: target,\n direction: 0,\n items: splitNumber(formatter, target, glyphs).map((part) => ({ part, exiting: false, fresh: false })),\n }));\n\n let current = state;\n if (state.formatter !== formatter || state.value !== target) {\n const sameFormat = state.formatter === formatter;\n // `lead` is a jump to `from`, not a change the reader should watch.\n const animate = motion && sameFormat && !lead;\n current = {\n formatter,\n value: target,\n direction: sameFormat ? resolveDirection(trend, state.value, target) : 0,\n items: mergeItems(state.items, splitNumber(formatter, target, glyphs), animate),\n };\n setState(current);\n }\n\n const leaving = current.items.some((item) => item.exiting);\n React.useEffect(() => {\n if (!leaving) return;\n const id = setTimeout(\n () => setState((s) => ({ ...s, items: s.items.filter((item) => !item.exiting) })),\n EDGE_MS + 50,\n );\n return () => clearTimeout(id);\n }, [leaving, current.items]);\n\n return (\n <>\n {current.items.map((item) => (\n <Slot\n key={item.part.key}\n item={item}\n glyphs={glyphs}\n direction={current.direction}\n motion={motion}\n spin={spin}\n />\n ))}\n </>\n );\n}\n"],"mappings":"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","names":[]}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
3
3
|
import * as React from "react";
|
|
4
|
-
import { cn } from "
|
|
5
|
-
import { Button } from "
|
|
6
|
-
import { useControllableState } from "
|
|
4
|
+
import { cn } from "../../lib/cn.js";
|
|
5
|
+
import { Button } from "../atomic/button.js";
|
|
6
|
+
import { useControllableState } from "../../primitives/use-controllable-state.js";
|
|
7
7
|
import {
|
|
8
8
|
CAROUSEL_CONTENT_TRACK,
|
|
9
9
|
CAROUSEL_CONTENT_TRACK_HORIZONTAL,
|
|
@@ -19,7 +19,7 @@ import {
|
|
|
19
19
|
CAROUSEL_NEXT_VERTICAL,
|
|
20
20
|
CAROUSEL_PREVIOUS_HORIZONTAL,
|
|
21
21
|
CAROUSEL_PREVIOUS_VERTICAL
|
|
22
|
-
} from "
|
|
22
|
+
} from "../../generated/carousel.js";
|
|
23
23
|
const CarouselContext = React.createContext(null);
|
|
24
24
|
function useCarousel() {
|
|
25
25
|
const context = React.useContext(CarouselContext);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/components/derived/carousel.tsx"],"sourcesContent":["\"use client\";\n\nimport * as React from \"react\";\nimport { cn } from \"../../lib/cn\";\nimport { Button, type ButtonProps } from \"../atomic/button\";\nimport { useControllableState } from \"../../primitives/use-controllable-state\";\nimport {\n CAROUSEL_CONTENT_TRACK,\n CAROUSEL_CONTENT_TRACK_HORIZONTAL,\n CAROUSEL_CONTENT_TRACK_VERTICAL,\n CAROUSEL_CONTENT_VIEWPORT,\n CAROUSEL_EDGE_FADE_NEXT,\n CAROUSEL_EDGE_FADE_PREV,\n CAROUSEL_ITEM,\n CAROUSEL_ITEM_HORIZONTAL,\n CAROUSEL_ITEM_VERTICAL,\n CAROUSEL_NAV,\n CAROUSEL_NEXT_HORIZONTAL,\n CAROUSEL_NEXT_VERTICAL,\n CAROUSEL_PREVIOUS_HORIZONTAL,\n CAROUSEL_PREVIOUS_VERTICAL,\n} from \"../../generated/carousel\";\n\ntype CarouselOrientation = \"horizontal\" | \"vertical\";\n\ntype CarouselContextProps = {\n orientation: CarouselOrientation;\n index: number;\n count: number;\n setCount: (count: number) => void;\n scrollPrev: () => void;\n scrollNext: () => void;\n canScrollPrev: boolean;\n canScrollNext: boolean;\n};\n\nconst CarouselContext = React.createContext<CarouselContextProps | null>(null);\n\nfunction useCarousel() {\n const context = React.useContext(CarouselContext);\n if (!context) {\n throw new Error(\"useCarousel must be used within a <Carousel />\");\n }\n return context;\n}\n\nexport interface CarouselProps extends React.ComponentProps<\"div\"> {\n orientation?: CarouselOrientation;\n index?: number;\n defaultIndex?: number;\n onIndexChange?: (index: number) => void;\n}\n\nexport function Carousel({\n orientation = \"horizontal\",\n index: indexProp,\n defaultIndex = 0,\n onIndexChange,\n className,\n children,\n onKeyDown,\n ...props\n}: CarouselProps) {\n const [index, setIndex] = useControllableState<number>({\n value: indexProp,\n defaultValue: defaultIndex,\n onChange: onIndexChange,\n });\n const [count, setCount] = React.useState(0);\n\n const canScrollPrev = index > 0;\n const canScrollNext = index < count - 1;\n\n const scrollPrev = React.useCallback(() => {\n if (index > 0) setIndex(index - 1);\n }, [index, setIndex]);\n\n const scrollNext = React.useCallback(() => {\n if (index < count - 1) setIndex(index + 1);\n }, [index, count, setIndex]);\n\n const handleKeyDown = (event: React.KeyboardEvent<HTMLDivElement>) => {\n if (event.key === \"ArrowLeft\") {\n event.preventDefault();\n scrollPrev();\n } else if (event.key === \"ArrowRight\") {\n event.preventDefault();\n scrollNext();\n }\n onKeyDown?.(event);\n };\n\n return (\n <CarouselContext.Provider\n value={{\n orientation,\n index,\n count,\n setCount,\n scrollPrev,\n scrollNext,\n canScrollPrev,\n canScrollNext,\n }}\n >\n <div\n onKeyDownCapture={handleKeyDown}\n className={cn(\"relative\", className)}\n role=\"region\"\n aria-roledescription=\"carousel\"\n tabIndex={0}\n data-slot=\"carousel\"\n {...props}\n >\n {children}\n </div>\n </CarouselContext.Provider>\n );\n}\n\nexport function CarouselContent({\n className,\n children,\n ...props\n}: React.ComponentProps<\"div\">) {\n const { orientation, index, setCount } = useCarousel();\n const childCount = React.Children.count(children);\n\n React.useEffect(() => {\n setCount(childCount);\n }, [childCount, setCount]);\n\n // drag/momentum: omitted vs embla — see README Limitations\n const transform =\n orientation === \"horizontal\"\n ? `translate3d(-${index * 100}%, 0, 0)`\n : `translate3d(0, -${index * 100}%, 0)`;\n\n return (\n <div className={CAROUSEL_CONTENT_VIEWPORT} data-slot=\"carousel-content\">\n <div\n className={cn(\n CAROUSEL_CONTENT_TRACK,\n orientation === \"horizontal\"\n ? CAROUSEL_CONTENT_TRACK_HORIZONTAL\n : CAROUSEL_CONTENT_TRACK_VERTICAL,\n className,\n )}\n style={{ transform }}\n {...props}\n >\n {children}\n </div>\n </div>\n );\n}\n\nexport function CarouselItem({\n className,\n ...props\n}: React.ComponentProps<\"div\">) {\n const { orientation } = useCarousel();\n\n return (\n <div\n role=\"group\"\n aria-roledescription=\"slide\"\n data-slot=\"carousel-item\"\n className={cn(\n CAROUSEL_ITEM,\n orientation === \"horizontal\" ? CAROUSEL_ITEM_HORIZONTAL : CAROUSEL_ITEM_VERTICAL,\n className,\n )}\n {...props}\n />\n );\n}\n\n/**\n * Netflix-style edge scrims that dissolve the current slide into the surface\n * colour, signalling adjacent slides without revealing them. Each side shows\n * only when there is somewhere to scroll. Drop inside a <Carousel>.\n */\nexport function CarouselEdgeFade({\n className,\n}: {\n className?: string;\n}) {\n const { canScrollPrev, canScrollNext } = useCarousel();\n\n return (\n <>\n <div\n aria-hidden\n className={cn(\n CAROUSEL_EDGE_FADE_PREV,\n canScrollPrev ? \"opacity-100\" : \"opacity-0\",\n className,\n )}\n />\n <div\n aria-hidden\n className={cn(\n CAROUSEL_EDGE_FADE_NEXT,\n canScrollNext ? \"opacity-100\" : \"opacity-0\",\n className,\n )}\n />\n </>\n );\n}\n\nexport function CarouselPrevious({\n className,\n variant = \"outline\",\n size = \"md\",\n icon = true,\n ...props\n}: ButtonProps) {\n const { orientation, scrollPrev, canScrollPrev } = useCarousel();\n\n return (\n <Button\n data-slot=\"carousel-previous\"\n variant={variant}\n size={size}\n icon={icon}\n className={cn(\n CAROUSEL_NAV,\n orientation === \"horizontal\"\n ? CAROUSEL_PREVIOUS_HORIZONTAL\n : CAROUSEL_PREVIOUS_VERTICAL,\n className,\n )}\n disabled={!canScrollPrev}\n onClick={scrollPrev}\n {...props}\n >\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n aria-hidden=\"true\"\n >\n <path d=\"m15 18-6-6 6-6\" />\n </svg>\n <span className=\"sr-only\">Previous slide</span>\n </Button>\n );\n}\n\nexport function CarouselNext({\n className,\n variant = \"outline\",\n size = \"md\",\n icon = true,\n ...props\n}: ButtonProps) {\n const { orientation, scrollNext, canScrollNext } = useCarousel();\n\n return (\n <Button\n data-slot=\"carousel-next\"\n variant={variant}\n size={size}\n icon={icon}\n className={cn(\n CAROUSEL_NAV,\n orientation === \"horizontal\"\n ? CAROUSEL_NEXT_HORIZONTAL\n : CAROUSEL_NEXT_VERTICAL,\n className,\n )}\n disabled={!canScrollNext}\n onClick={scrollNext}\n {...props}\n >\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n aria-hidden=\"true\"\n >\n <path d=\"m9 18 6-6-6-6\" />\n </svg>\n <span className=\"sr-only\">Next slide</span>\n </Button>\n );\n}\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
+
import * as React from "react";
|
|
4
|
+
import {
|
|
5
|
+
COMMAND_PALETTE_COMMAND,
|
|
6
|
+
COMMAND_PALETTE_CONTENT,
|
|
7
|
+
COMMAND_PALETTE_HINT,
|
|
8
|
+
COMMAND_PALETTE_HINTS,
|
|
9
|
+
COMMAND_PALETTE_LABEL,
|
|
10
|
+
COMMAND_PALETTE_LIST,
|
|
11
|
+
COMMAND_PALETTE_TITLE
|
|
12
|
+
} from "../../generated/command-palette.js";
|
|
13
|
+
import { cn } from "../../lib/cn.js";
|
|
14
|
+
import { useControllableState } from "../../primitives/use-controllable-state.js";
|
|
15
|
+
import {
|
|
16
|
+
Command,
|
|
17
|
+
CommandEmpty,
|
|
18
|
+
CommandGroup,
|
|
19
|
+
CommandInput,
|
|
20
|
+
CommandItem,
|
|
21
|
+
CommandList,
|
|
22
|
+
CommandSeparator,
|
|
23
|
+
CommandShortcut
|
|
24
|
+
} from "../atomic/command.js";
|
|
25
|
+
import { Dialog, DialogContent, DialogTitle } from "../atomic/dialog.js";
|
|
26
|
+
import { Kbd } from "../atomic/kbd.js";
|
|
27
|
+
function CommandPalette({
|
|
28
|
+
open,
|
|
29
|
+
defaultOpen = false,
|
|
30
|
+
onOpenChange,
|
|
31
|
+
groups,
|
|
32
|
+
labels = {},
|
|
33
|
+
className
|
|
34
|
+
}) {
|
|
35
|
+
const [isOpen, setOpen] = useControllableState({
|
|
36
|
+
...open !== void 0 ? { value: open } : {},
|
|
37
|
+
defaultValue: defaultOpen,
|
|
38
|
+
...onOpenChange ? { onChange: onOpenChange } : {}
|
|
39
|
+
});
|
|
40
|
+
return /* @__PURE__ */ jsx(Dialog, { open: isOpen, onOpenChange: setOpen, children: /* @__PURE__ */ jsxs(
|
|
41
|
+
DialogContent,
|
|
42
|
+
{
|
|
43
|
+
showCloseButton: false,
|
|
44
|
+
className: cn(COMMAND_PALETTE_CONTENT, className),
|
|
45
|
+
children: [
|
|
46
|
+
/* @__PURE__ */ jsx(DialogTitle, { className: COMMAND_PALETTE_TITLE, children: labels.title ?? "Command palette" }),
|
|
47
|
+
/* @__PURE__ */ jsxs(Command, { className: COMMAND_PALETTE_COMMAND, children: [
|
|
48
|
+
/* @__PURE__ */ jsx(CommandInput, { placeholder: labels.placeholder ?? "Type a command or search\u2026" }),
|
|
49
|
+
/* @__PURE__ */ jsxs(CommandList, { className: COMMAND_PALETTE_LIST, children: [
|
|
50
|
+
/* @__PURE__ */ jsx(CommandEmpty, { children: labels.empty ?? "No results." }),
|
|
51
|
+
groups.map((group, i) => /* @__PURE__ */ jsxs(React.Fragment, { children: [
|
|
52
|
+
i > 0 && /* @__PURE__ */ jsx(CommandSeparator, {}),
|
|
53
|
+
/* @__PURE__ */ jsx(CommandGroup, { ...group.heading !== void 0 ? { heading: group.heading } : {}, children: group.items.map((item) => /* @__PURE__ */ jsxs(
|
|
54
|
+
CommandItem,
|
|
55
|
+
{
|
|
56
|
+
value: [item.label, ...item.keywords ?? []].join(" "),
|
|
57
|
+
disabled: item.disabled ?? false,
|
|
58
|
+
onSelect: () => {
|
|
59
|
+
setOpen(false);
|
|
60
|
+
item.onSelect();
|
|
61
|
+
},
|
|
62
|
+
children: [
|
|
63
|
+
item.icon,
|
|
64
|
+
/* @__PURE__ */ jsx("span", { className: COMMAND_PALETTE_LABEL, children: item.label }),
|
|
65
|
+
item.shortcut !== void 0 && /* @__PURE__ */ jsx(CommandShortcut, { children: item.shortcut })
|
|
66
|
+
]
|
|
67
|
+
},
|
|
68
|
+
item.id
|
|
69
|
+
)) })
|
|
70
|
+
] }, group.id))
|
|
71
|
+
] })
|
|
72
|
+
] }),
|
|
73
|
+
/* @__PURE__ */ jsxs(
|
|
74
|
+
"div",
|
|
75
|
+
{
|
|
76
|
+
"data-slot": "command-palette-hints",
|
|
77
|
+
className: COMMAND_PALETTE_HINTS,
|
|
78
|
+
children: [
|
|
79
|
+
/* @__PURE__ */ jsxs("span", { className: COMMAND_PALETTE_HINT, children: [
|
|
80
|
+
/* @__PURE__ */ jsx(Kbd, { children: "\u2191\u2193" }),
|
|
81
|
+
labels.navigate ?? "navigate"
|
|
82
|
+
] }),
|
|
83
|
+
/* @__PURE__ */ jsxs("span", { className: COMMAND_PALETTE_HINT, children: [
|
|
84
|
+
/* @__PURE__ */ jsx(Kbd, { children: "\u21B5" }),
|
|
85
|
+
labels.select ?? "select"
|
|
86
|
+
] }),
|
|
87
|
+
/* @__PURE__ */ jsxs("span", { className: COMMAND_PALETTE_HINT, children: [
|
|
88
|
+
/* @__PURE__ */ jsx(Kbd, { children: "esc" }),
|
|
89
|
+
labels.close ?? "close"
|
|
90
|
+
] })
|
|
91
|
+
]
|
|
92
|
+
}
|
|
93
|
+
)
|
|
94
|
+
]
|
|
95
|
+
}
|
|
96
|
+
) });
|
|
97
|
+
}
|
|
98
|
+
function useCommandPaletteShortcut(onTrigger, enabled = true) {
|
|
99
|
+
const ref = React.useRef(onTrigger);
|
|
100
|
+
React.useEffect(() => {
|
|
101
|
+
ref.current = onTrigger;
|
|
102
|
+
});
|
|
103
|
+
React.useEffect(() => {
|
|
104
|
+
if (!enabled) return;
|
|
105
|
+
const onKeyDown = (e) => {
|
|
106
|
+
if ((e.metaKey || e.ctrlKey) && !e.altKey && !e.shiftKey && e.code === "KeyK") {
|
|
107
|
+
e.preventDefault();
|
|
108
|
+
if (!e.repeat) ref.current();
|
|
109
|
+
}
|
|
110
|
+
};
|
|
111
|
+
document.addEventListener("keydown", onKeyDown);
|
|
112
|
+
return () => document.removeEventListener("keydown", onKeyDown);
|
|
113
|
+
}, [enabled]);
|
|
114
|
+
}
|
|
115
|
+
export {
|
|
116
|
+
CommandPalette,
|
|
117
|
+
useCommandPaletteShortcut
|
|
118
|
+
};
|
|
119
|
+
//# sourceMappingURL=command-palette.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/components/derived/command-palette.tsx"],"sourcesContent":["\"use client\";\n\nimport * as React from \"react\";\nimport {\n COMMAND_PALETTE_COMMAND,\n COMMAND_PALETTE_CONTENT,\n COMMAND_PALETTE_HINT,\n COMMAND_PALETTE_HINTS,\n COMMAND_PALETTE_LABEL,\n COMMAND_PALETTE_LIST,\n COMMAND_PALETTE_TITLE,\n} from \"../../generated/command-palette\";\nimport { cn } from \"../../lib/cn\";\nimport { useControllableState } from \"../../primitives/use-controllable-state\";\nimport {\n Command,\n CommandEmpty,\n CommandGroup,\n CommandInput,\n CommandItem,\n CommandList,\n CommandSeparator,\n CommandShortcut,\n} from \"../atomic/command\";\nimport { Dialog, DialogContent, DialogTitle } from \"../atomic/dialog\";\nimport { Kbd } from \"../atomic/kbd\";\n\nexport interface CommandPaletteItem {\n id: string;\n label: string;\n icon?: React.ReactNode;\n /** Shown at the row end, e.g. \"⌘N\". */\n shortcut?: string;\n /** Extra words the search matches besides the label. */\n keywords?: readonly string[];\n disabled?: boolean;\n onSelect: () => void;\n}\n\nexport interface CommandPaletteGroup {\n id: string;\n heading?: string;\n items: readonly CommandPaletteItem[];\n}\n\nexport interface CommandPaletteLabels {\n /** Names the dialog for assistive tech. Default `\"Command palette\"`. */\n title?: string;\n placeholder?: string;\n empty?: string;\n navigate?: string;\n select?: string;\n close?: string;\n}\n\nexport interface CommandPaletteProps {\n open?: boolean;\n defaultOpen?: boolean;\n onOpenChange?: (open: boolean) => void;\n groups: readonly CommandPaletteGroup[];\n labels?: CommandPaletteLabels;\n className?: string;\n}\n\n// Built on Dialog + Command rather than the kit's CommandDialog: that one has no accessible\n// name and no footer, and both need Dialog's title and focus wiring.\n/**\n * Search-and-run over a list of actions. Choosing a row runs it and closes the\n * palette. Pair it with `useCommandPaletteShortcut` for ⌘K / Ctrl+K.\n */\nexport function CommandPalette({\n open,\n defaultOpen = false,\n onOpenChange,\n groups,\n labels = {},\n className,\n}: CommandPaletteProps) {\n const [isOpen, setOpen] = useControllableState<boolean>({\n ...(open !== undefined ? { value: open } : {}),\n defaultValue: defaultOpen,\n ...(onOpenChange ? { onChange: onOpenChange } : {}),\n });\n return (\n <Dialog open={isOpen} onOpenChange={setOpen}>\n <DialogContent\n showCloseButton={false}\n className={cn(COMMAND_PALETTE_CONTENT, className)}\n >\n <DialogTitle className={COMMAND_PALETTE_TITLE}>{labels.title ?? \"Command palette\"}</DialogTitle>\n <Command className={COMMAND_PALETTE_COMMAND}>\n <CommandInput placeholder={labels.placeholder ?? \"Type a command or search…\"} />\n <CommandList className={COMMAND_PALETTE_LIST}>\n <CommandEmpty>{labels.empty ?? \"No results.\"}</CommandEmpty>\n {groups.map((group, i) => (\n <React.Fragment key={group.id}>\n {i > 0 && <CommandSeparator />}\n <CommandGroup {...(group.heading !== undefined ? { heading: group.heading } : {})}>\n {group.items.map((item) => (\n <CommandItem\n key={item.id}\n value={[item.label, ...(item.keywords ?? [])].join(\" \")}\n disabled={item.disabled ?? false}\n onSelect={() => {\n setOpen(false);\n item.onSelect();\n }}\n >\n {item.icon}\n <span className={COMMAND_PALETTE_LABEL}>{item.label}</span>\n {item.shortcut !== undefined && <CommandShortcut>{item.shortcut}</CommandShortcut>}\n </CommandItem>\n ))}\n </CommandGroup>\n </React.Fragment>\n ))}\n </CommandList>\n </Command>\n <div\n data-slot=\"command-palette-hints\"\n className={COMMAND_PALETTE_HINTS}\n >\n <span className={COMMAND_PALETTE_HINT}>\n <Kbd>↑↓</Kbd>\n {labels.navigate ?? \"navigate\"}\n </span>\n <span className={COMMAND_PALETTE_HINT}>\n <Kbd>↵</Kbd>\n {labels.select ?? \"select\"}\n </span>\n <span className={COMMAND_PALETTE_HINT}>\n <Kbd>esc</Kbd>\n {labels.close ?? \"close\"}\n </span>\n </div>\n </DialogContent>\n </Dialog>\n );\n}\n\n/**\n * Calls `onTrigger` on ⌘K (Mac) or Ctrl+K, and keeps the browser from taking\n * the key (Chrome focuses the address bar on Ctrl+K in some layouts). Matches the\n * physical key (`code`), so it also works on a Russian or other non-Latin layout.\n */\nexport function useCommandPaletteShortcut(onTrigger: () => void, enabled = true): void {\n // Latest callback without re-binding the listener on every render.\n const ref = React.useRef(onTrigger);\n React.useEffect(() => {\n ref.current = onTrigger;\n });\n React.useEffect(() => {\n if (!enabled) return;\n const onKeyDown = (e: KeyboardEvent) => {\n if ((e.metaKey || e.ctrlKey) && !e.altKey && !e.shiftKey && e.code === \"KeyK\") {\n e.preventDefault();\n // A held key would toggle the palette open and shut.\n if (!e.repeat) ref.current();\n }\n };\n document.addEventListener(\"keydown\", onKeyDown);\n return () => document.removeEventListener(\"keydown\", onKeyDown);\n }, [enabled]);\n}\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
+
import * as React from "react";
|
|
4
|
+
import { cn } from "../../lib/cn.js";
|
|
5
|
+
import {
|
|
6
|
+
CONFIRM_DIALOG_CONTENT,
|
|
7
|
+
CONFIRM_DIALOG_DESCRIPTION,
|
|
8
|
+
CONFIRM_DIALOG_ERROR,
|
|
9
|
+
CONFIRM_DIALOG_FOOTER,
|
|
10
|
+
CONFIRM_DIALOG_HEADER,
|
|
11
|
+
CONFIRM_DIALOG_ICON,
|
|
12
|
+
CONFIRM_DIALOG_PENDING,
|
|
13
|
+
CONFIRM_DIALOG_SPINNER,
|
|
14
|
+
CONFIRM_DIALOG_TEXT,
|
|
15
|
+
CONFIRM_DIALOG_TITLE,
|
|
16
|
+
confirmDialogIconToneClasses
|
|
17
|
+
} from "../../generated/confirm-dialog.js";
|
|
18
|
+
import { useControllableState } from "../../primitives/use-controllable-state.js";
|
|
19
|
+
import {
|
|
20
|
+
AlertDialog,
|
|
21
|
+
AlertDialogContent,
|
|
22
|
+
AlertDialogDescription,
|
|
23
|
+
AlertDialogFooter,
|
|
24
|
+
AlertDialogHeader,
|
|
25
|
+
AlertDialogTitle,
|
|
26
|
+
AlertDialogTrigger
|
|
27
|
+
} from "../atomic/alert-dialog.js";
|
|
28
|
+
import { buttonVariants } from "../atomic/button.js";
|
|
29
|
+
import { Spinner } from "../atomic/spinner.js";
|
|
30
|
+
import { UiIcon } from "../../icons/ui-icons.js";
|
|
31
|
+
function ConfirmDialog({
|
|
32
|
+
open,
|
|
33
|
+
defaultOpen = false,
|
|
34
|
+
onOpenChange,
|
|
35
|
+
trigger,
|
|
36
|
+
title,
|
|
37
|
+
description,
|
|
38
|
+
tone = "default",
|
|
39
|
+
confirmLabel,
|
|
40
|
+
onConfirm,
|
|
41
|
+
icon,
|
|
42
|
+
labels = {},
|
|
43
|
+
className
|
|
44
|
+
}) {
|
|
45
|
+
const [isOpen, setOpen] = useControllableState({
|
|
46
|
+
...open !== void 0 ? { value: open } : {},
|
|
47
|
+
defaultValue: defaultOpen,
|
|
48
|
+
...onOpenChange ? { onChange: onOpenChange } : {}
|
|
49
|
+
});
|
|
50
|
+
const [pending, setPending] = React.useState(false);
|
|
51
|
+
const [error, setError] = React.useState(null);
|
|
52
|
+
const danger = tone === "danger";
|
|
53
|
+
React.useEffect(() => {
|
|
54
|
+
if (isOpen) setError(null);
|
|
55
|
+
}, [isOpen]);
|
|
56
|
+
const change = (next) => {
|
|
57
|
+
if (pending) return;
|
|
58
|
+
if (next) setError(null);
|
|
59
|
+
setOpen(next);
|
|
60
|
+
};
|
|
61
|
+
const confirm = async () => {
|
|
62
|
+
if (pending) return;
|
|
63
|
+
setError(null);
|
|
64
|
+
setPending(true);
|
|
65
|
+
try {
|
|
66
|
+
await onConfirm();
|
|
67
|
+
setPending(false);
|
|
68
|
+
setOpen(false);
|
|
69
|
+
} catch (e) {
|
|
70
|
+
setPending(false);
|
|
71
|
+
setError(e instanceof Error && e.message ? e.message : labels.error ?? "Something went wrong");
|
|
72
|
+
}
|
|
73
|
+
};
|
|
74
|
+
return /* @__PURE__ */ jsxs(AlertDialog, { open: isOpen, onOpenChange: change, children: [
|
|
75
|
+
trigger != null && /* @__PURE__ */ jsx(AlertDialogTrigger, { asChild: true, children: trigger }),
|
|
76
|
+
/* @__PURE__ */ jsxs(AlertDialogContent, { className: cn(CONFIRM_DIALOG_CONTENT, className), children: [
|
|
77
|
+
/* @__PURE__ */ jsxs(AlertDialogHeader, { className: CONFIRM_DIALOG_HEADER, children: [
|
|
78
|
+
/* @__PURE__ */ jsx(
|
|
79
|
+
"span",
|
|
80
|
+
{
|
|
81
|
+
className: cn(CONFIRM_DIALOG_ICON, confirmDialogIconToneClasses[tone]),
|
|
82
|
+
children: icon ?? /* @__PURE__ */ jsx(UiIcon, { name: "alert" })
|
|
83
|
+
}
|
|
84
|
+
),
|
|
85
|
+
/* @__PURE__ */ jsxs("div", { className: CONFIRM_DIALOG_TEXT, children: [
|
|
86
|
+
/* @__PURE__ */ jsx(AlertDialogTitle, { className: CONFIRM_DIALOG_TITLE, children: title }),
|
|
87
|
+
description != null && /* @__PURE__ */ jsx(AlertDialogDescription, { className: CONFIRM_DIALOG_DESCRIPTION, children: description }),
|
|
88
|
+
error !== null && /* @__PURE__ */ jsx("p", { role: "alert", className: CONFIRM_DIALOG_ERROR, children: error })
|
|
89
|
+
] })
|
|
90
|
+
] }),
|
|
91
|
+
/* @__PURE__ */ jsxs(AlertDialogFooter, { className: CONFIRM_DIALOG_FOOTER, children: [
|
|
92
|
+
/* @__PURE__ */ jsx(
|
|
93
|
+
"button",
|
|
94
|
+
{
|
|
95
|
+
type: "button",
|
|
96
|
+
"aria-disabled": pending,
|
|
97
|
+
onClick: () => change(false),
|
|
98
|
+
className: cn(buttonVariants({ variant: "ghost", size: "xs" }), CONFIRM_DIALOG_PENDING),
|
|
99
|
+
children: labels.cancel ?? "Cancel"
|
|
100
|
+
}
|
|
101
|
+
),
|
|
102
|
+
/* @__PURE__ */ jsxs(
|
|
103
|
+
"button",
|
|
104
|
+
{
|
|
105
|
+
type: "button",
|
|
106
|
+
"aria-disabled": pending,
|
|
107
|
+
"aria-busy": pending,
|
|
108
|
+
onClick: confirm,
|
|
109
|
+
className: cn(buttonVariants({ variant: danger ? "destructive" : "primary", size: "xs" }), CONFIRM_DIALOG_PENDING),
|
|
110
|
+
children: [
|
|
111
|
+
pending && /* @__PURE__ */ jsx(Spinner, { className: CONFIRM_DIALOG_SPINNER }),
|
|
112
|
+
confirmLabel
|
|
113
|
+
]
|
|
114
|
+
}
|
|
115
|
+
)
|
|
116
|
+
] })
|
|
117
|
+
] })
|
|
118
|
+
] });
|
|
119
|
+
}
|
|
120
|
+
export {
|
|
121
|
+
ConfirmDialog
|
|
122
|
+
};
|
|
123
|
+
//# sourceMappingURL=confirm-dialog.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/components/derived/confirm-dialog.tsx"],"sourcesContent":["\"use client\";\n\nimport * as React from \"react\";\nimport { cn } from \"../../lib/cn\";\nimport {\n CONFIRM_DIALOG_CONTENT,\n CONFIRM_DIALOG_DESCRIPTION,\n CONFIRM_DIALOG_ERROR,\n CONFIRM_DIALOG_FOOTER,\n CONFIRM_DIALOG_HEADER,\n CONFIRM_DIALOG_ICON,\n CONFIRM_DIALOG_PENDING,\n CONFIRM_DIALOG_SPINNER,\n CONFIRM_DIALOG_TEXT,\n CONFIRM_DIALOG_TITLE,\n confirmDialogIconToneClasses,\n type ConfirmDialogTone,\n} from \"../../generated/confirm-dialog\";\nimport { useControllableState } from \"../../primitives/use-controllable-state\";\nimport {\n AlertDialog,\n AlertDialogContent,\n AlertDialogDescription,\n AlertDialogFooter,\n AlertDialogHeader,\n AlertDialogTitle,\n AlertDialogTrigger,\n} from \"../atomic/alert-dialog\";\nimport { buttonVariants } from \"../atomic/button\";\nimport { Spinner } from \"../atomic/spinner\";\nimport { UiIcon } from \"../../icons/ui-icons\";\n\nexport type { ConfirmDialogTone };\n\nexport interface ConfirmDialogLabels {\n cancel?: string;\n /** Shown when `onConfirm` rejects with something that has no message. */\n error?: string;\n}\n\nexport interface ConfirmDialogProps {\n open?: boolean;\n defaultOpen?: boolean;\n onOpenChange?: (open: boolean) => void;\n /** Opens the dialog; wrapped with `asChild`, so pass one button. */\n trigger?: React.ReactNode;\n title: React.ReactNode;\n description?: React.ReactNode;\n tone?: ConfirmDialogTone;\n confirmLabel: React.ReactNode;\n /**\n * Resolve to close the dialog. While a returned promise is pending both\n * buttons are disabled and Escape and outside clicks do nothing; a rejection\n * keeps the dialog open and shows its message under the text.\n */\n onConfirm: () => void | Promise<void>;\n /** Replaces the tone's glyph. */\n icon?: React.ReactNode;\n labels?: ConfirmDialogLabels;\n className?: string;\n}\n\nexport function ConfirmDialog({\n open,\n defaultOpen = false,\n onOpenChange,\n trigger,\n title,\n description,\n tone = \"default\",\n confirmLabel,\n onConfirm,\n icon,\n labels = {},\n className,\n}: ConfirmDialogProps) {\n const [isOpen, setOpen] = useControllableState<boolean>({\n ...(open !== undefined ? { value: open } : {}),\n defaultValue: defaultOpen,\n ...(onOpenChange ? { onChange: onOpenChange } : {}),\n });\n const [pending, setPending] = React.useState(false);\n const [error, setError] = React.useState<string | null>(null);\n const danger = tone === \"danger\";\n // A controlled parent can reopen the dialog without going through `change`.\n React.useEffect(() => {\n if (isOpen) setError(null);\n }, [isOpen]);\n\n const change = (next: boolean) => {\n if (pending) return;\n if (next) setError(null);\n setOpen(next);\n };\n\n const confirm = async () => {\n if (pending) return;\n setError(null);\n setPending(true);\n try {\n await onConfirm();\n setPending(false);\n setOpen(false);\n } catch (e) {\n setPending(false);\n setError(e instanceof Error && e.message ? e.message : (labels.error ?? \"Something went wrong\"));\n }\n };\n\n return (\n <AlertDialog open={isOpen} onOpenChange={change}>\n {trigger != null && <AlertDialogTrigger asChild>{trigger}</AlertDialogTrigger>}\n <AlertDialogContent className={cn(CONFIRM_DIALOG_CONTENT, className)}>\n <AlertDialogHeader className={CONFIRM_DIALOG_HEADER}>\n <span\n className={cn(CONFIRM_DIALOG_ICON, confirmDialogIconToneClasses[tone])}\n >\n {icon ?? <UiIcon name=\"alert\" />}\n </span>\n <div className={CONFIRM_DIALOG_TEXT}>\n <AlertDialogTitle className={CONFIRM_DIALOG_TITLE}>{title}</AlertDialogTitle>\n {description != null && (\n <AlertDialogDescription className={CONFIRM_DIALOG_DESCRIPTION}>{description}</AlertDialogDescription>\n )}\n {error !== null && (\n <p role=\"alert\" className={CONFIRM_DIALOG_ERROR}>\n {error}\n </p>\n )}\n </div>\n </AlertDialogHeader>\n <AlertDialogFooter className={CONFIRM_DIALOG_FOOTER}>\n {/* aria-disabled, not disabled: a disabled button that holds focus drops it to <body> and Tab leaves the dialog. */}\n <button\n type=\"button\"\n aria-disabled={pending}\n onClick={() => change(false)}\n className={cn(buttonVariants({ variant: \"ghost\", size: \"xs\" }), CONFIRM_DIALOG_PENDING)}\n >\n {labels.cancel ?? \"Cancel\"}\n </button>\n <button\n type=\"button\"\n aria-disabled={pending}\n aria-busy={pending}\n onClick={confirm}\n className={cn(buttonVariants({ variant: danger ? \"destructive\" : \"primary\", size: \"xs\" }), CONFIRM_DIALOG_PENDING)}\n >\n {pending && <Spinner className={CONFIRM_DIALOG_SPINNER} />}\n {confirmLabel}\n </button>\n </AlertDialogFooter>\n </AlertDialogContent>\n </AlertDialog>\n );\n}\n"],"mappings":"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","names":[]}
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
3
|
import * as React from "react";
|
|
4
|
-
import { cn } from "
|
|
5
|
-
import { focusCandidates } from "
|
|
6
|
-
import { useControllableState } from "
|
|
7
|
-
import { buttonVariants } from "
|
|
8
|
-
import { Calendar } from "
|
|
9
|
-
import { Input } from "
|
|
10
|
-
import { Popover, PopoverContent, PopoverTrigger } from "
|
|
4
|
+
import { cn } from "../../lib/cn.js";
|
|
5
|
+
import { focusCandidates } from "../../primitives/focus-scope.js";
|
|
6
|
+
import { useControllableState } from "../../primitives/use-controllable-state.js";
|
|
7
|
+
import { buttonVariants } from "../atomic/button.js";
|
|
8
|
+
import { Calendar } from "../atomic/calendar.js";
|
|
9
|
+
import { Input } from "../atomic/input.js";
|
|
10
|
+
import { Popover, PopoverContent, PopoverTrigger } from "../atomic/popover.js";
|
|
11
11
|
import {
|
|
12
12
|
DATE_TIME_PICKER_CLEAR,
|
|
13
13
|
DATE_TIME_PICKER_CONTENT,
|
|
@@ -15,7 +15,7 @@ import {
|
|
|
15
15
|
DATE_TIME_PICKER_TIME_INPUT,
|
|
16
16
|
DATE_TIME_PICKER_TIME_SEPARATOR,
|
|
17
17
|
DATE_TIME_PICKER_TRIGGER
|
|
18
|
-
} from "
|
|
18
|
+
} from "../../generated/date-time-picker.js";
|
|
19
19
|
const CALENDAR_ICON = [
|
|
20
20
|
"M8 2v4",
|
|
21
21
|
"M16 2v4",
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/components/derived/date-time-picker.tsx"],"sourcesContent":["\"use client\";\n\nimport * as React from \"react\";\nimport { cn } from \"../../lib/cn\";\nimport { focusCandidates } from \"../../primitives/focus-scope\";\nimport { useControllableState } from \"../../primitives/use-controllable-state\";\nimport { buttonVariants } from \"../atomic/button\";\nimport { Calendar } from \"../atomic/calendar\";\nimport { Input } from \"../atomic/input\";\nimport { Popover, PopoverContent, PopoverTrigger } from \"../atomic/popover\";\nimport {\n DATE_TIME_PICKER_CLEAR,\n DATE_TIME_PICKER_CONTENT,\n DATE_TIME_PICKER_TIME,\n DATE_TIME_PICKER_TIME_INPUT,\n DATE_TIME_PICKER_TIME_SEPARATOR,\n DATE_TIME_PICKER_TRIGGER,\n} from \"../../generated/date-time-picker\";\n\n// lucide `calendar`, inlined per the kit's no-icon-dep convention.\nconst CALENDAR_ICON = [\n \"M8 2v4\",\n \"M16 2v4\",\n \"M3 10h18\",\n \"M5 4h14a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2z\",\n] as const;\n\nfunction CalendarIcon() {\n return (\n <svg\n className=\"size-4\"\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"24\"\n height=\"24\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n aria-hidden\n >\n {CALENDAR_ICON.map(d => (\n <path key={d} d={d} />\n ))}\n </svg>\n );\n}\n\n// lucide `x`, inlined like every other icon in the kit.\nfunction XIcon() {\n return (\n <svg\n className=\"size-4\"\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"24\"\n height=\"24\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n aria-hidden\n >\n <path d=\"M18 6 6 18M6 6l12 12\" />\n </svg>\n );\n}\n\nconst pad = (n: number): string => String(n).padStart(2, \"0\");\n\n// The value always carries whole minutes: seconds/ms are dropped on every write.\nfunction atMinute(d: Date): Date {\n return new Date(d.getFullYear(), d.getMonth(), d.getDate(), d.getHours(), d.getMinutes());\n}\n\n/** Inclusive clamp at minute precision. */\nfunction clampMoment(d: Date, min: Date | undefined, max: Date | undefined): Date {\n const lo = min && atMinute(min);\n const hi = max && atMinute(max);\n if (lo && d.getTime() < lo.getTime()) return lo;\n if (hi && d.getTime() > hi.getTime()) return hi;\n return d;\n}\n\n/**\n * Parses the digits an operator typed into an hours/minutes field. `null`\n * (nothing typed, or no digit at all) keeps the last value.\n *\n * The LAST two digits win: the field is controlled, so what the browser hands\n * over is the old value plus the keystroke (\"01\" + \"5\" = \"015\"), and the\n * freshest digits are the ones the operator meant.\n */\nfunction parseField(raw: string, max: number): number | null {\n const digits = raw.replace(/\\D/g, \"\").slice(-2);\n if (digits === \"\") return null;\n return Math.min(Number(digits), max);\n}\n\n// A focused field is replaced, not appended to: with the whole value selected,\n// \"1\" then \"5\" reads as 15.\nconst selectAll = (e: React.FocusEvent<HTMLInputElement>) => e.currentTarget.select();\n\nfunction isoLabel(d: Date): string {\n return `${d.getFullYear().toString().padStart(4, \"0\")}-${pad(d.getMonth() + 1)}-${pad(\n d.getDate(),\n )} ${pad(d.getHours())}:${pad(d.getMinutes())}`;\n}\n\n/** The picker's own strings; every one defaults to English. */\nexport interface DateTimePickerLabels {\n /** `aria-label` of the calendar's previous-month button; \"Previous month\". */\n previousMonth?: string;\n /** `aria-label` of the calendar's next-month button; \"Next month\". */\n nextMonth?: string;\n /** `aria-label` of the hours input; \"Hours\". */\n hours?: string;\n /** `aria-label` of the minutes input; \"Minutes\". */\n minutes?: string;\n /** Text of the clear button; \"Clear\". */\n clear?: string;\n /** `aria-label` of the popover dialog; \"Choose date and time\". */\n dialog?: string;\n /** `aria-label` of the close button; \"Close\". */\n close?: string;\n}\n\nexport interface DateTimePickerProps\n extends React.AriaAttributes,\n Pick<React.ComponentProps<\"button\">, \"onFocus\" | \"onBlur\"> {\n /** Controlled value; `null` = empty. Local-zone `Date` (seconds/ms are zeroed on every change). */\n value?: Date | null;\n /** Uncontrolled seed; default `null`. */\n defaultValue?: Date | null;\n onChange?: (value: Date | null) => void;\n /** Earliest allowed moment (inclusive, minute precision). */\n min?: Date;\n /** Latest allowed moment (inclusive, minute precision). */\n max?: Date;\n /**\n * BCP-47 tag for the trigger label and calendar captions (`Intl`). Absent →\n * `YYYY-MM-DD HH:MM` and English captions, like the Rust port.\n */\n locale?: string;\n /** Overrides the trigger label entirely (e.g. the cabinet's `formatMoment`). */\n format?: (value: Date) => string;\n /** Shown on the trigger while empty; default \"\". */\n placeholder?: string;\n labels?: DateTimePickerLabels;\n disabled?: boolean;\n /** Renders a hidden `<input name>` carrying unix seconds (\"\" when empty) for plain forms. */\n name?: string;\n /**\n * \"Today\" for the calendar highlight and as the day a typed time lands on\n * while empty; default `new Date()`.\n */\n today?: Date;\n open?: boolean;\n defaultOpen?: boolean;\n onOpenChange?: (open: boolean) => void;\n /** `PopoverContent` alignment; default \"start\". */\n align?: \"start\" | \"center\" | \"end\";\n /** Fused onto the trigger. */\n className?: string;\n /** Put on the trigger, so a `FieldLabel`'s `htmlFor` reaches it. */\n id?: string;\n}\n\n/**\n * A date + time field over the kit's own bricks: an outline trigger opening a\n * popover with the `Calendar` and two numeric hours/minutes inputs — no native\n * `datetime-local`, so the browser's locale popup never appears.\n *\n * Every edit reports through `onChange`; the popover stays open after a day\n * click (the operator still sets the time) and closes on clear or on the close\n * button (which keeps the value). Opening moves focus into the hours field;\n * closing hands it back to the trigger unless the operator already focused\n * something else. Any other `aria-*` prop, `onFocus` and `onBlur` land on the\n * trigger.\n */\nexport function DateTimePicker({\n value: valueProp,\n defaultValue = null,\n onChange,\n min,\n max,\n locale,\n format,\n placeholder = \"\",\n labels = {},\n disabled = false,\n name,\n today = new Date(),\n open,\n defaultOpen = false,\n onOpenChange,\n align = \"start\",\n className,\n id,\n ...rest\n}: DateTimePickerProps) {\n const [value, setValue] = useControllableState<Date | null>({\n ...(valueProp !== undefined ? { value: valueProp } : {}),\n defaultValue,\n ...(onChange ? { onChange } : {}),\n });\n const [isOpen, setOpen] = useControllableState<boolean>({\n ...(open !== undefined ? { value: open } : {}),\n defaultValue: defaultOpen,\n ...(onOpenChange ? { onChange: onOpenChange } : {}),\n });\n\n const rootRef = React.useRef<HTMLDivElement | null>(null);\n const hoursRef = React.useRef<HTMLInputElement | null>(null);\n const focusTrigger = () =>\n rootRef.current?.querySelector<HTMLElement>(\"[data-slot=date-time-picker-trigger]\")?.focus();\n // The content lives in a Portal, so the native tab order would skip it.\n React.useEffect(() => {\n if (!isOpen) return;\n hoursRef.current?.focus();\n return () => {\n const active = document.activeElement;\n const content = hoursRef.current?.closest(\"[data-slot=date-time-picker-content]\");\n const lost = !active || active === document.body || !!content?.contains(active);\n if (lost) focusTrigger();\n };\n }, [isOpen]);\n\n const emit = (next: Date) => setValue(clampMoment(atMinute(next), min, max));\n // A fresh copy of the moment a typed time edits: the value, or midnight of\n // `today` while empty — never the consumer's own `Date` instance.\n const base = () =>\n value\n ? new Date(value.getTime())\n : new Date(today.getFullYear(), today.getMonth(), today.getDate());\n\n const onSelect = (day: Date) =>\n emit(\n new Date(\n day.getFullYear(),\n day.getMonth(),\n day.getDate(),\n value?.getHours() ?? 0,\n value?.getMinutes() ?? 0,\n ),\n );\n const onHours = (e: React.ChangeEvent<HTMLInputElement>) => {\n const hour = parseField(e.target.value, 23);\n if (hour === null) return;\n const next = base();\n next.setHours(hour);\n emit(next);\n };\n const onMinutes = (e: React.ChangeEvent<HTMLInputElement>) => {\n const minute = parseField(e.target.value, 59);\n if (minute === null) return;\n const next = base();\n next.setMinutes(minute);\n emit(next);\n };\n const onClear = () => {\n setValue(null);\n setOpen(false);\n };\n // The content is portalled to the end of <body>, so Tab from its last\n // control (and Shift+Tab from its first) has nowhere to go: focus falls out\n // of the document and the dialog stays open over the page. Those two edges\n // close the popover and hand focus back to the trigger — the document's tab\n // order then continues from where the operator started. Middle controls keep\n // the browser's default. Not a trap: the popover is non-modal.\n const onContentKeyDown = (e: React.KeyboardEvent<HTMLDivElement>) => {\n if (e.key !== \"Tab\") return;\n const items = focusCandidates(e.currentTarget);\n const edge = e.shiftKey ? items[0] : items[items.length - 1];\n if (!edge || e.target !== edge) return;\n e.preventDefault();\n setOpen(false);\n focusTrigger();\n };\n // Focus moving elsewhere by pointer or script (the dismissable layer only\n // watches Escape and outside pointerdown). A null `relatedTarget` is the\n // window losing focus (alt-tab), not the operator leaving: keep the popover\n // for their return. Tab-out never reaches here — `onContentKeyDown` closes\n // first.\n const onContentBlur = (e: React.FocusEvent<HTMLDivElement>) => {\n const next = e.relatedTarget;\n if (!(next instanceof Node)) return;\n if (e.currentTarget.contains(next) || rootRef.current?.contains(next)) return;\n setOpen(false);\n };\n\n const label = value\n ? format\n ? format(value)\n : locale\n ? // The fields are 24-hour, so the label is too — even where the locale\n // would default to 12-hour (\"2:05 PM\" over a \"14\" hours field).\n new Intl.DateTimeFormat(locale, {\n dateStyle: \"medium\",\n timeStyle: \"short\",\n hourCycle: \"h23\",\n }).format(value)\n : isoLabel(value)\n : placeholder;\n\n return (\n <div data-slot=\"date-time-picker\" ref={rootRef}>\n <Popover open={isOpen} onOpenChange={setOpen}>\n <PopoverTrigger\n type=\"button\"\n data-slot=\"date-time-picker-trigger\"\n data-placeholder={value ? undefined : \"true\"}\n aria-haspopup=\"dialog\"\n className={cn(\n buttonVariants({ variant: \"outline\", size: \"md\" }),\n DATE_TIME_PICKER_TRIGGER,\n className,\n )}\n disabled={disabled}\n {...(id !== undefined ? { id } : {})}\n {...rest}\n >\n <CalendarIcon />\n <span>{label}</span>\n </PopoverTrigger>\n {name !== undefined && (\n <input\n type=\"hidden\"\n name={name}\n value={value ? String(Math.floor(value.getTime() / 1000)) : \"\"}\n />\n )}\n <PopoverContent\n data-slot=\"date-time-picker-content\"\n role=\"dialog\"\n aria-label={labels.dialog ?? \"Choose date and time\"}\n align={align}\n onBlur={onContentBlur}\n onKeyDown={onContentKeyDown}\n className={DATE_TIME_PICKER_CONTENT}\n >\n <Calendar\n {...(value ? { selected: value } : {})}\n onSelect={onSelect}\n // The content remounts on every open, so this lands on the value's month.\n defaultMonth={value ?? min ?? today}\n today={today}\n disabled={disabled}\n {...(min ? { min } : {})}\n {...(max ? { max } : {})}\n {...(locale !== undefined ? { locale } : {})}\n {...(labels.previousMonth !== undefined\n ? { previousMonthLabel: labels.previousMonth }\n : {})}\n {...(labels.nextMonth !== undefined ? { nextMonthLabel: labels.nextMonth } : {})}\n />\n <div className={DATE_TIME_PICKER_TIME} data-slot=\"date-time-picker-time\">\n <Input\n type=\"text\"\n inputMode=\"numeric\"\n onFocus={selectAll}\n className={DATE_TIME_PICKER_TIME_INPUT}\n ref={hoursRef}\n data-slot=\"date-time-picker-hours\"\n aria-label={labels.hours ?? \"Hours\"}\n value={pad(value?.getHours() ?? 0)}\n disabled={disabled}\n onChange={onHours}\n />\n <span className={DATE_TIME_PICKER_TIME_SEPARATOR} aria-hidden>\n :\n </span>\n <Input\n type=\"text\"\n inputMode=\"numeric\"\n onFocus={selectAll}\n className={DATE_TIME_PICKER_TIME_INPUT}\n data-slot=\"date-time-picker-minutes\"\n aria-label={labels.minutes ?? \"Minutes\"}\n value={pad(value?.getMinutes() ?? 0)}\n disabled={disabled}\n onChange={onMinutes}\n />\n <button\n type=\"button\"\n className={buttonVariants({ variant: \"ghost\", size: \"sm\", className: DATE_TIME_PICKER_CLEAR })}\n data-slot=\"date-time-picker-clear\"\n disabled={disabled}\n onClick={onClear}\n >\n {labels.clear ?? \"Clear\"}\n </button>\n <button\n type=\"button\"\n className={buttonVariants({ variant: \"ghost\", size: \"sm\", icon: true })}\n data-slot=\"date-time-picker-close\"\n aria-label={labels.close ?? \"Close\"}\n disabled={disabled}\n onClick={() => setOpen(false)}\n >\n <XIcon />\n </button>\n </div>\n </PopoverContent>\n </Popover>\n </div>\n );\n}\n"],"mappings":"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","names":[]}
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
3
|
import * as React from "react";
|
|
4
|
-
import { cn } from "
|
|
5
|
-
import { Label } from "
|
|
6
|
-
import { walkElements } from "
|
|
7
|
-
import { isLabelable, markLabelable } from "
|
|
8
|
-
import { FieldControlContext, useFieldClaims } from "
|
|
4
|
+
import { cn } from "../../lib/cn.js";
|
|
5
|
+
import { Label } from "../atomic/label.js";
|
|
6
|
+
import { walkElements } from "../../primitives/walk-elements.js";
|
|
7
|
+
import { isLabelable, markLabelable } from "../../primitives/labelable.js";
|
|
8
|
+
import { FieldControlContext, useFieldClaims } from "../atomic/field-context.js";
|
|
9
9
|
import {
|
|
10
10
|
FIELD_BASE,
|
|
11
11
|
FIELD_SET,
|
|
@@ -20,7 +20,7 @@ import {
|
|
|
20
20
|
FIELD_SEPARATOR_CONTENT,
|
|
21
21
|
FIELD_ERROR,
|
|
22
22
|
fieldOrientation
|
|
23
|
-
} from "
|
|
23
|
+
} from "../../generated/field.js";
|
|
24
24
|
function FieldSet({ className, ...props }) {
|
|
25
25
|
return /* @__PURE__ */ jsx(
|
|
26
26
|
"fieldset",
|