banhaten 0.1.2 → 0.2.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/CHANGELOG.md +45 -0
- package/CONTRIBUTING.md +44 -0
- package/README.md +145 -328
- package/SECURITY.md +15 -0
- package/banhaten.config.example.json +1 -3
- package/docs/design-system/README.md +20 -0
- package/docs/design-system/adoption-quality-remediation.md +87 -0
- package/docs/design-system/agent-usage.md +13 -0
- package/docs/design-system/appearance-presets.md +189 -0
- package/docs/design-system/appearances/default.md +94 -0
- package/docs/design-system/appearances/rounded.md +95 -0
- package/docs/design-system/appearances/sharp.md +95 -0
- package/docs/design-system/component-docs-pattern.md +81 -0
- package/docs/design-system/component-showcase-consistency-report.md +217 -0
- package/docs/design-system/component-token-consistency-audit.md +173 -0
- package/docs/design-system/components/README.md +75 -0
- package/docs/design-system/components/accordion.md +67 -0
- package/docs/design-system/components/activity-feed.md +106 -0
- package/docs/design-system/components/alert-dialog.md +87 -0
- package/docs/design-system/components/alert.md +111 -0
- package/docs/design-system/components/aspect-ratio.md +59 -0
- package/docs/design-system/components/attribute.md +103 -0
- package/docs/design-system/components/autocomplete.md +93 -0
- package/docs/design-system/components/avatar.md +70 -0
- package/docs/design-system/components/badge.md +72 -0
- package/docs/design-system/components/banner.md +99 -0
- package/docs/design-system/components/breadcrumbs.md +188 -0
- package/docs/design-system/components/button-group.md +117 -0
- package/docs/design-system/components/button.md +95 -0
- package/docs/design-system/components/card.md +95 -0
- package/docs/design-system/components/carousel.md +61 -0
- package/docs/design-system/components/catalog-components.md +59 -0
- package/docs/design-system/components/chart.md +58 -0
- package/docs/design-system/components/checkbox.md +68 -0
- package/docs/design-system/components/collapsible.md +63 -0
- package/docs/design-system/components/command.md +75 -0
- package/docs/design-system/components/context-menu.md +59 -0
- package/docs/design-system/components/date-picker.md +97 -0
- package/docs/design-system/components/divider.md +117 -0
- package/docs/design-system/components/empty-state.md +72 -0
- package/docs/design-system/components/field.md +86 -0
- package/docs/design-system/components/file-upload.md +199 -0
- package/docs/design-system/components/hover-card.md +61 -0
- package/docs/design-system/components/icons.md +48 -0
- package/docs/design-system/components/input-group.md +73 -0
- package/docs/design-system/components/input-otp.md +73 -0
- package/docs/design-system/components/input.md +84 -0
- package/docs/design-system/components/item.md +72 -0
- package/docs/design-system/components/kbd.md +62 -0
- package/docs/design-system/components/label.md +64 -0
- package/docs/design-system/components/menu.md +76 -0
- package/docs/design-system/components/menubar.md +60 -0
- package/docs/design-system/components/modal.md +119 -0
- package/docs/design-system/components/native-select.md +70 -0
- package/docs/design-system/components/navigation-menu.md +63 -0
- package/docs/design-system/components/onboarding-step-list-item.md +94 -0
- package/docs/design-system/components/page-header.md +98 -0
- package/docs/design-system/components/pagination.md +71 -0
- package/docs/design-system/components/popover.md +77 -0
- package/docs/design-system/components/progress-slider.md +66 -0
- package/docs/design-system/components/progress.md +92 -0
- package/docs/design-system/components/radio-card.md +65 -0
- package/docs/design-system/components/radio-group.md +72 -0
- package/docs/design-system/components/resizable.md +57 -0
- package/docs/design-system/components/scroll-area.md +60 -0
- package/docs/design-system/components/segmented-control.md +71 -0
- package/docs/design-system/components/select.md +87 -0
- package/docs/design-system/components/sheet.md +82 -0
- package/docs/design-system/components/sidebar.md +83 -0
- package/docs/design-system/components/skeleton.md +91 -0
- package/docs/design-system/components/slideout.md +77 -0
- package/docs/design-system/components/slider.md +81 -0
- package/docs/design-system/components/social-button.md +65 -0
- package/docs/design-system/components/spinner.md +77 -0
- package/docs/design-system/components/steps.md +77 -0
- package/docs/design-system/components/table.md +411 -0
- package/docs/design-system/components/tabs.md +69 -0
- package/docs/design-system/components/tag.md +95 -0
- package/docs/design-system/components/textarea.md +64 -0
- package/docs/design-system/components/timeline.md +95 -0
- package/docs/design-system/components/toast.md +73 -0
- package/docs/design-system/components/toggle.md +96 -0
- package/docs/design-system/components/toolbar.md +105 -0
- package/docs/design-system/components/tooltip.md +107 -0
- package/docs/design-system/components/typography.md +18 -0
- package/docs/design-system/density-and-elevation.md +44 -0
- package/docs/design-system/design-system-test-missing-items.md +368 -0
- package/docs/design-system/direction-and-localization.md +23 -0
- package/docs/design-system/form-recipes.md +73 -0
- package/docs/design-system/gap-promotion-policy.md +21 -0
- package/docs/design-system/gap-promotion-report.md +166 -0
- package/docs/design-system/icons.md +69 -0
- package/docs/design-system/installation.md +68 -0
- package/docs/design-system/launch-comparison-shadcn.md +98 -0
- package/docs/design-system/registry-and-cli.md +64 -0
- package/docs/design-system/release-policy.md +30 -0
- package/docs/design-system/roadmap.md +14 -0
- package/docs/design-system/support-matrix.md +23 -0
- package/docs/design-system/tabs.md +53 -0
- package/docs/design-system/token-governance.md +60 -0
- package/package.json +97 -65
- package/registry/component-contract.json +40 -0
- package/registry/components/alert-dialog.tsx +297 -0
- package/registry/components/alert.tsx +86 -65
- package/registry/components/aspect-ratio.tsx +30 -0
- package/registry/components/autocomplete.tsx +23 -9
- package/registry/components/avatar.tsx +7 -7
- package/registry/components/badge.tsx +1 -1
- package/registry/components/button-group.tsx +321 -4
- package/registry/components/button.tsx +38 -17
- package/registry/components/card.tsx +68 -59
- package/registry/components/carousel.tsx +282 -0
- package/registry/components/chart.tsx +203 -0
- package/registry/components/checkbox.tsx +3 -3
- package/registry/components/collapsible.tsx +69 -0
- package/registry/components/command.tsx +174 -0
- package/registry/components/context-menu.tsx +236 -0
- package/registry/components/date-picker.tsx +246 -105
- package/registry/components/expanded/ActivityFeed.tsx +6 -15
- package/registry/components/expanded/Banner.tsx +3 -3
- package/registry/components/expanded/Breadcrumbs.tsx +5 -5
- package/registry/components/expanded/CatalogComponentsShowcase.tsx +13 -13
- package/registry/components/expanded/CatalogDivider.tsx +1 -1
- package/registry/components/expanded/EmptyState.tsx +1 -1
- package/registry/components/expanded/FileUpload.tsx +9 -2
- package/registry/components/expanded/OnboardingStepListItem.tsx +2 -4
- package/registry/components/expanded/PageHeader.tsx +14 -14
- package/registry/components/expanded/Slideout.tsx +15 -415
- package/registry/components/expanded/Steps.tsx +4 -4
- package/registry/components/expanded/Table.tsx +116 -69
- package/registry/components/expanded/Timeline.tsx +3 -3
- package/registry/components/expanded/activityFeed.css +1 -1
- package/registry/components/expanded/breadcrumbs.css +139 -139
- package/registry/components/expanded/catalogComponentsShowcase.css +83 -83
- package/registry/components/expanded/divider.css +1 -1
- package/registry/components/expanded/emptyState.css +1 -1
- package/registry/components/expanded/fileUpload.css +6 -6
- package/registry/components/expanded/slideout.css +9 -685
- package/registry/components/expanded/steps.css +274 -274
- package/registry/components/expanded/table.css +2 -2
- package/registry/components/expanded/timeline.css +264 -264
- package/registry/components/field.tsx +230 -0
- package/registry/components/hover-card.tsx +48 -0
- package/registry/components/input-content.ts +1 -0
- package/registry/components/input-group.tsx +130 -0
- package/registry/components/input-otp.tsx +13 -3
- package/registry/components/input.tsx +70 -45
- package/registry/components/item.tsx +189 -0
- package/registry/components/kbd.tsx +151 -0
- package/registry/components/label.tsx +78 -0
- package/registry/components/menu.tsx +34 -246
- package/registry/components/menubar.tsx +226 -0
- package/registry/components/modal.tsx +216 -143
- package/registry/components/native-select.tsx +205 -0
- package/registry/components/navigation-menu.tsx +171 -0
- package/registry/components/pagination.tsx +80 -58
- package/registry/components/popover.tsx +162 -664
- package/registry/components/radio-card.tsx +116 -87
- package/registry/components/radio-group.tsx +1 -1
- package/registry/components/resizable.tsx +74 -0
- package/registry/components/scroll-area.tsx +67 -0
- package/registry/components/segmented-control.tsx +87 -0
- package/registry/components/select-content.tsx +2 -2
- package/registry/components/select.tsx +54 -20
- package/registry/components/sheet.tsx +305 -0
- package/registry/components/sidebar.tsx +352 -0
- package/registry/components/skeleton.css +0 -3
- package/registry/components/social-button.tsx +116 -30
- package/registry/components/spinner.tsx +18 -55
- package/registry/components/{expanded/tabs.css → tabs.css} +127 -106
- package/registry/components/tabs.tsx +246 -0
- package/registry/components/tag.tsx +2 -2
- package/registry/components/textarea.tsx +4 -4
- package/registry/components/toast.tsx +136 -0
- package/registry/components/toggle.tsx +2 -2
- package/registry/components/toolbar.tsx +89 -17
- package/registry/components/tooltip.tsx +1 -1
- package/registry/examples/alert-demo.tsx +25 -5
- package/registry/examples/alert-dialog-demo.tsx +42 -0
- package/registry/examples/aspect-ratio-demo.tsx +11 -0
- package/registry/examples/attribute-demo.tsx +1 -1
- package/registry/examples/autocomplete-demo.tsx +3 -3
- package/registry/examples/avatar-demo.tsx +7 -7
- package/registry/examples/badge-demo.tsx +1 -1
- package/registry/examples/button-demo.tsx +6 -6
- package/registry/examples/button-group-demo.tsx +23 -2
- package/registry/examples/card-demo.tsx +46 -8
- package/registry/examples/carousel-demo.tsx +43 -0
- package/registry/examples/chart-demo.tsx +33 -0
- package/registry/examples/checkbox-demo.tsx +5 -5
- package/registry/examples/collapsible-demo.tsx +16 -0
- package/registry/examples/collection-filter-bar-demo.tsx +135 -0
- package/registry/examples/command-demo.tsx +42 -0
- package/registry/examples/{expanded/command-bar-demo.tsx → command-palette-demo.tsx} +5 -15
- package/registry/examples/context-menu-demo.tsx +29 -0
- package/registry/examples/control-density-contract-demo.tsx +61 -0
- package/registry/examples/date-picker-demo.tsx +12 -12
- package/registry/examples/divider-demo.tsx +3 -3
- package/registry/examples/expanded/banner-demo.tsx +1 -1
- package/registry/examples/expanded/breadcrumbs-demo.tsx +1 -1
- package/registry/examples/expanded/empty-state-demo.tsx +1 -1
- package/registry/examples/expanded/file-upload-demo.tsx +1 -1
- package/registry/examples/expanded/onboarding-step-demo.tsx +1 -1
- package/registry/examples/expanded/slideout-demo.tsx +2 -2
- package/registry/examples/expanded/steps-demo.tsx +1 -1
- package/registry/examples/expanded/tabs-demo.tsx +2 -2
- package/registry/examples/expanded/timeline-demo.tsx +1 -1
- package/registry/examples/field-demo.tsx +51 -0
- package/registry/examples/hover-card-demo.tsx +23 -0
- package/registry/examples/input-demo.tsx +6 -6
- package/registry/examples/input-group-demo.tsx +16 -0
- package/registry/examples/input-otp-demo.tsx +4 -4
- package/registry/examples/item-demo.tsx +46 -0
- package/registry/examples/kbd-demo.tsx +11 -0
- package/registry/examples/label-demo.tsx +20 -0
- package/registry/examples/menu-demo.tsx +1 -1
- package/registry/examples/menubar-demo.tsx +34 -0
- package/registry/examples/modal-demo.tsx +67 -9
- package/registry/examples/native-select-demo.tsx +16 -0
- package/registry/examples/navigation-menu-demo.tsx +29 -0
- package/registry/examples/pagination-demo.tsx +6 -3
- package/registry/examples/popover-demo.tsx +19 -19
- package/registry/examples/progress-demo.tsx +1 -1
- package/registry/examples/progress-slider-demo.tsx +1 -1
- package/registry/examples/radio-card-demo.tsx +4 -4
- package/registry/examples/radio-group-demo.tsx +2 -2
- package/registry/examples/resizable-demo.tsx +22 -0
- package/registry/examples/results-toolbar-demo.tsx +44 -0
- package/registry/examples/scroll-area-demo.tsx +15 -0
- package/registry/examples/segmented-control-demo.tsx +39 -0
- package/registry/examples/select-demo.tsx +1 -1
- package/registry/examples/sheet-demo.tsx +47 -0
- package/registry/examples/sidebar-demo.tsx +55 -0
- package/registry/examples/slider-demo.tsx +3 -3
- package/registry/examples/social-button-demo.tsx +18 -8
- package/registry/examples/spinner-demo.tsx +13 -13
- package/registry/examples/tabs-demo.tsx +13 -0
- package/registry/examples/tag-demo.tsx +1 -1
- package/registry/examples/textarea-demo.tsx +4 -4
- package/registry/examples/toast-demo.tsx +35 -0
- package/registry/examples/toggle-demo.tsx +6 -6
- package/registry/examples/tooltip-demo.tsx +4 -4
- package/registry/guidance/USAGE.md +27 -0
- package/registry/hooks/use-direction.ts +193 -13
- package/registry/index.json +6010 -432
- package/registry/styles/globals.css +3112 -4690
- package/registry.json +1582 -0
- package/schema/config.schema.json +51 -0
- package/schema/registry.schema.json +190 -0
- package/schema/tokens.schema.json +163 -0
- package/src/cli/command-line.js +194 -0
- package/src/cli/config-editors.js +9 -0
- package/src/cli/doctor.js +399 -0
- package/src/cli/file-transaction.js +295 -0
- package/src/cli/global-css.js +153 -0
- package/src/cli/index.js +639 -1391
- package/src/cli/install-plan.js +592 -0
- package/src/cli/install-receipt.js +171 -0
- package/src/cli/jsonc.js +203 -0
- package/src/cli/package-install-state.js +254 -0
- package/src/cli/package-manager.js +238 -0
- package/src/cli/package-plan.js +185 -0
- package/src/cli/package-version.js +97 -0
- package/src/cli/registry-query.js +207 -0
- package/src/cli/reporting.js +55 -0
- package/src/cli/schema-validation.js +19 -0
- package/src/cli/source-scanner.js +686 -0
- package/src/cli/vite-config.js +478 -0
- package/tokens/banhaten.tokens.json +4313 -310
- package/registry/assets/avatars/avatar-02.jpg +0 -0
- package/registry/assets/avatars/avatar-03.jpg +0 -0
- package/registry/assets/avatars/avatar-04.jpg +0 -0
- package/registry/assets/avatars/avatar-05.jpg +0 -0
- package/registry/assets/avatars/avatar-06.jpg +0 -0
- package/registry/assets/avatars/avatar-07.jpg +0 -0
- package/registry/assets/avatars/avatar-08.jpg +0 -0
- package/registry/assets/avatars/avatar-09.jpg +0 -0
- package/registry/assets/avatars/avatar-10.jpg +0 -0
- package/registry/assets/avatars/avatar-11.jpg +0 -0
- package/registry/assets/avatars/avatar-12.jpg +0 -0
- package/registry/assets/avatars/avatar-13.jpg +0 -0
- package/registry/assets/avatars/avatar-14.jpg +0 -0
- package/registry/assets/avatars/avatar-15.jpg +0 -0
- package/registry/assets/avatars/avatar-16.jpg +0 -0
- package/registry/assets/avatars/avatar-17.jpg +0 -0
- package/registry/assets/avatars/avatar-18.jpg +0 -0
- package/registry/assets/avatars/avatar-19.jpg +0 -0
- package/registry/assets/avatars/avatar-20.jpg +0 -0
- package/registry/assets/avatars/avatar-21.jpg +0 -0
- package/registry/assets/avatars/avatar-22.jpg +0 -0
- package/registry/assets/avatars/avatar-23.jpg +0 -0
- package/registry/assets/avatars/avatar-24.jpg +0 -0
- package/registry/assets/avatars/avatar-25.jpg +0 -0
- package/registry/assets/avatars/avatar-26.jpg +0 -0
- package/registry/assets/avatars/avatar-27.jpg +0 -0
- package/registry/assets/avatars/avatar-28.jpg +0 -0
- package/registry/assets/avatars/avatar-29.jpg +0 -0
- package/registry/assets/avatars/avatar-30.jpg +0 -0
- package/registry/assets/avatars/avatar-31.jpg +0 -0
- package/registry/assets/avatars/avatar-32.jpg +0 -0
- package/registry/assets/avatars/avatar-33.jpg +0 -0
- package/registry/assets/avatars/avatar-34.jpg +0 -0
- package/registry/assets/avatars/avatar-35.jpg +0 -0
- package/registry/assets/image-assets.json +0 -744
- package/registry/assets/images/art-02.jpg +0 -0
- package/registry/assets/images/art-03.jpg +0 -0
- package/registry/assets/images/art-04.jpg +0 -0
- package/registry/assets/images/art-05.jpg +0 -0
- package/registry/assets/images/art-06.jpg +0 -0
- package/registry/assets/images/art-07.jpg +0 -0
- package/registry/assets/images/art-08.jpg +0 -0
- package/registry/assets/images/art-09.jpg +0 -0
- package/registry/assets/images/art-10.jpg +0 -0
- package/registry/assets/images/art-11.jpg +0 -0
- package/registry/assets/images/art-12.jpg +0 -0
- package/registry/assets/images/art-13.jpg +0 -0
- package/registry/assets/images/art-14.jpg +0 -0
- package/registry/assets/images/art-15.jpg +0 -0
- package/registry/assets/images/art-16.jpg +0 -0
- package/registry/assets/images/art-17.jpg +0 -0
- package/registry/assets/images/art-18.jpg +0 -0
- package/registry/assets/images/art-19.jpg +0 -0
- package/registry/assets/images/art-20.jpg +0 -0
- package/registry/assets/images/art-21.jpg +0 -0
- package/registry/assets/images/art-22.jpg +0 -0
- package/registry/assets/images/art-23.jpg +0 -0
- package/registry/assets/images/art-24.jpg +0 -0
- package/registry/assets/images/art-25.jpg +0 -0
- package/registry/assets/images/art-26.jpg +0 -0
- package/registry/assets/images/art-27.jpg +0 -0
- package/registry/assets/images/nature-01.jpg +0 -0
- package/registry/assets/images/nature-02.jpg +0 -0
- package/registry/assets/images/nature-03.jpg +0 -0
- package/registry/assets/images/nature-04.jpg +0 -0
- package/registry/assets/images/nature-05.jpg +0 -0
- package/registry/assets/images/nature-06.jpg +0 -0
- package/registry/assets/images/nature-07.jpg +0 -0
- package/registry/assets/images/nature-08.jpg +0 -0
- package/registry/assets/images/nature-09.jpg +0 -0
- package/registry/assets/images/nature-10.jpg +0 -0
- package/registry/assets/images/nature-11.jpg +0 -0
- package/registry/assets/images/nature-12.jpg +0 -0
- package/registry/assets/images/nature-13.jpg +0 -0
- package/registry/assets/images/nature-14.jpg +0 -0
- package/registry/assets/images/nature-15.jpg +0 -0
- package/registry/assets/images/nature-16.jpg +0 -0
- package/registry/assets/images/nature-17.jpg +0 -0
- package/registry/assets/images/nature-18.jpg +0 -0
- package/registry/assets/images/nature-19.jpg +0 -0
- package/registry/assets/images/nature-20.jpg +0 -0
- package/registry/components/expanded/BannerBoard.tsx +0 -225
- package/registry/components/expanded/CatalogTag.tsx +0 -85
- package/registry/components/expanded/CommandBar.tsx +0 -386
- package/registry/components/expanded/IconExplorer.tsx +0 -612
- package/registry/components/expanded/Tabs.tsx +0 -86
- package/registry/components/expanded/TimelineShowcase.tsx +0 -158
- package/registry/components/expanded/commandBar.css +0 -470
- package/registry/components/expanded/iconExplorer.css +0 -764
- package/registry/components/expanded/iconPacks.ts +0 -866
- package/registry/components/expanded/tag.css +0 -148
- package/registry/examples/expanded/icons-demo.tsx +0 -5
- package/tokens/Color mode.zip +0 -0
- package/tokens/Numbers.zip +0 -0
- package/tokens/Radius.zip +0 -0
- package/tokens/Theme.zip +0 -0
|
@@ -11,6 +11,7 @@ import {
|
|
|
11
11
|
import { cva } from "class-variance-authority"
|
|
12
12
|
|
|
13
13
|
import { cn } from "@/lib/utils"
|
|
14
|
+
import { Popover, PopoverContent, PopoverTrigger } from "./popover"
|
|
14
15
|
import {
|
|
15
16
|
addMonths,
|
|
16
17
|
formatCalendarDate,
|
|
@@ -34,6 +35,8 @@ import type {
|
|
|
34
35
|
RangeCalendarType,
|
|
35
36
|
} from "./date-picker-state"
|
|
36
37
|
|
|
38
|
+
type ControlDensity = "compact" | "default" | "comfortable"
|
|
39
|
+
|
|
37
40
|
type CalendarTimeValue = {
|
|
38
41
|
hours?: string
|
|
39
42
|
minutes?: string
|
|
@@ -45,6 +48,7 @@ type CalendarMonthYearItem = {
|
|
|
45
48
|
id?: string
|
|
46
49
|
month: React.ReactNode
|
|
47
50
|
year: React.ReactNode
|
|
51
|
+
value?: Date
|
|
48
52
|
selected?: boolean
|
|
49
53
|
disabled?: boolean
|
|
50
54
|
}
|
|
@@ -111,6 +115,7 @@ type DatePickerProps = Omit<
|
|
|
111
115
|
>
|
|
112
116
|
defaultOpen?: boolean
|
|
113
117
|
defaultValue?: Date
|
|
118
|
+
density?: ControlDensity
|
|
114
119
|
dir?: DatePickerDirection
|
|
115
120
|
disabled?: boolean
|
|
116
121
|
icon?: React.ReactNode
|
|
@@ -119,6 +124,10 @@ type DatePickerProps = Omit<
|
|
|
119
124
|
open?: boolean
|
|
120
125
|
placeholder?: React.ReactNode
|
|
121
126
|
triggerClassName?: string
|
|
127
|
+
triggerProps?: Omit<
|
|
128
|
+
DatePickerTriggerProps,
|
|
129
|
+
"density" | "icon" | "open" | "placeholder" | "value"
|
|
130
|
+
>
|
|
122
131
|
value?: Date
|
|
123
132
|
}
|
|
124
133
|
|
|
@@ -132,6 +141,7 @@ type DateRangePickerProps = Omit<
|
|
|
132
141
|
>
|
|
133
142
|
defaultOpen?: boolean
|
|
134
143
|
defaultValue?: CalendarRange
|
|
144
|
+
density?: ControlDensity
|
|
135
145
|
dir?: DatePickerDirection
|
|
136
146
|
disabled?: boolean
|
|
137
147
|
icon?: React.ReactNode
|
|
@@ -140,43 +150,16 @@ type DateRangePickerProps = Omit<
|
|
|
140
150
|
open?: boolean
|
|
141
151
|
placeholder?: React.ReactNode
|
|
142
152
|
triggerClassName?: string
|
|
153
|
+
triggerProps?: Omit<
|
|
154
|
+
DatePickerTriggerProps,
|
|
155
|
+
"density" | "icon" | "open" | "placeholder" | "value"
|
|
156
|
+
>
|
|
143
157
|
type?: RangeCalendarType
|
|
144
158
|
value?: CalendarRange
|
|
145
159
|
}
|
|
146
160
|
|
|
147
|
-
const
|
|
148
|
-
const defaultSelectedDate = new Date(2050, 6, 18)
|
|
149
|
-
const defaultRange: CalendarRange = {
|
|
150
|
-
from: new Date(2050, 6, 15),
|
|
151
|
-
to: new Date(2050, 7, 23),
|
|
152
|
-
}
|
|
153
|
-
const defaultTimeValue: Required<CalendarTimeValue> = {
|
|
154
|
-
hours: "05",
|
|
155
|
-
minutes: "21",
|
|
156
|
-
period: "AM",
|
|
157
|
-
zone: "GTM-3",
|
|
158
|
-
}
|
|
161
|
+
const defaultTimeValue = getCurrentTimeValue()
|
|
159
162
|
const defaultDayLabels = ["S", "M", "T", "W", "T", "F", "S"]
|
|
160
|
-
const defaultMonthYearItems: CalendarMonthYearItem[] = [
|
|
161
|
-
{ month: "April", year: "2023" },
|
|
162
|
-
{ month: "May", year: "2022" },
|
|
163
|
-
{ month: "June", year: "2023" },
|
|
164
|
-
{ month: "July", year: "2024", selected: true },
|
|
165
|
-
{ month: "August", year: "2025" },
|
|
166
|
-
{ month: "September", year: "2026" },
|
|
167
|
-
{ month: "October", year: "2027" },
|
|
168
|
-
]
|
|
169
|
-
const defaultPresets: CalendarPreset[] = [
|
|
170
|
-
{ label: "Today" },
|
|
171
|
-
{ label: "Last 7 days" },
|
|
172
|
-
{ label: "Last 14 days" },
|
|
173
|
-
{ label: "Last 30 days" },
|
|
174
|
-
{ label: "Last 3 months" },
|
|
175
|
-
{ label: "Last 12 months" },
|
|
176
|
-
{ label: "Quarter to date" },
|
|
177
|
-
{ label: "Year to date" },
|
|
178
|
-
{ label: "All time" },
|
|
179
|
-
]
|
|
180
163
|
|
|
181
164
|
const calendarSurface = cva(
|
|
182
165
|
[
|
|
@@ -206,21 +189,33 @@ const calendarSurface = cva(
|
|
|
206
189
|
|
|
207
190
|
const pickerTrigger = cva(
|
|
208
191
|
[
|
|
209
|
-
"group/date-trigger relative flex
|
|
210
|
-
"bg-[var(--bh-interactive-input-default)]
|
|
192
|
+
"group/date-trigger relative flex w-[var(--bh-date-trigger-width)] max-w-full items-center gap-[var(--bh-space-md-8)] rounded-[var(--bh-radius-lg-8)]",
|
|
193
|
+
"bg-[var(--bh-interactive-input-default)] text-start outline-none",
|
|
211
194
|
"[--bh-date-trigger-border:var(--bh-border-input)] [--bh-date-trigger-shadow:inset_0px_0px_0px_var(--bh-border-width-default)_var(--bh-date-trigger-border),var(--shadow-component-default)]",
|
|
212
195
|
"text-[length:var(--bh-text-body-md-regular-font-size)] font-[var(--bh-text-body-md-regular-font-weight)] leading-[var(--bh-text-body-md-regular-line-height)] tracking-[var(--bh-text-body-md-regular-letter-spacing)]",
|
|
213
196
|
"text-[var(--bh-content-default)] shadow-[var(--bh-date-trigger-shadow)] transition-[background-color,box-shadow]",
|
|
214
197
|
"hover:bg-[var(--bh-bg-default-hover)] focus-visible:shadow-[var(--shadow-input-focus-ring)]",
|
|
215
198
|
"disabled:pointer-events-none disabled:bg-[var(--bh-interactive-input-disabled)] disabled:text-[var(--bh-content-disabled)] disabled:shadow-[inset_0px_0px_0px_var(--bh-border-width-default)_var(--bh-border-disabled)]",
|
|
216
|
-
]
|
|
199
|
+
],
|
|
200
|
+
{
|
|
201
|
+
variants: {
|
|
202
|
+
density: {
|
|
203
|
+
compact: "h-[var(--bh-button-xs-height)] px-[var(--bh-space-md-8)]",
|
|
204
|
+
default: "h-[var(--bh-button-sm-height)] px-[var(--bh-space-lg-10)]",
|
|
205
|
+
comfortable: "h-[var(--bh-date-trigger-height)] px-[var(--bh-space-xl-12)]",
|
|
206
|
+
},
|
|
207
|
+
},
|
|
208
|
+
defaultVariants: {
|
|
209
|
+
density: "comfortable",
|
|
210
|
+
},
|
|
211
|
+
}
|
|
217
212
|
)
|
|
218
213
|
|
|
219
214
|
const monthButton = cva(
|
|
220
215
|
[
|
|
221
216
|
"flex size-[var(--bh-date-nav-button-size)] shrink-0 items-center justify-center rounded-[var(--bh-control-default)]",
|
|
222
217
|
"bg-[var(--bh-interactive-soft-default)] text-[var(--bh-content-default)] outline-none transition-[background-color,box-shadow,color]",
|
|
223
|
-
"hover:bg-[var(--bh-interactive-soft-hover)] focus-visible:shadow-[var(--shadow-button-focus)] disabled:opacity-0",
|
|
218
|
+
"hover:bg-[var(--bh-interactive-soft-hover)] focus-visible:shadow-[var(--shadow-button-focus)] disabled:opacity-[var(--bh-opacity-0)]",
|
|
224
219
|
"[&_svg]:size-[var(--bh-date-nav-icon-size)]",
|
|
225
220
|
]
|
|
226
221
|
)
|
|
@@ -288,18 +283,18 @@ const dateListItem = cva(
|
|
|
288
283
|
|
|
289
284
|
function Calendar({
|
|
290
285
|
className,
|
|
291
|
-
defaultValue
|
|
286
|
+
defaultValue,
|
|
292
287
|
dir,
|
|
293
288
|
displayMonth,
|
|
294
289
|
events,
|
|
295
|
-
monthYearItems
|
|
290
|
+
monthYearItems,
|
|
296
291
|
nextLabel = "Next month",
|
|
297
292
|
onDisplayMonthChange,
|
|
298
293
|
onSelect,
|
|
299
294
|
onViewChange,
|
|
300
295
|
previousLabel = "Previous month",
|
|
301
296
|
selectedDate,
|
|
302
|
-
showTime =
|
|
297
|
+
showTime = false,
|
|
303
298
|
surfaceSize = "calendar",
|
|
304
299
|
timeLabel = "Time",
|
|
305
300
|
timeValue = defaultTimeValue,
|
|
@@ -310,14 +305,16 @@ function Calendar({
|
|
|
310
305
|
}: CalendarProps) {
|
|
311
306
|
const controlledValue = value ?? selectedDate
|
|
312
307
|
const [internalValue, setInternalValue] = React.useState(defaultValue)
|
|
313
|
-
const [internalDisplayMonth, setInternalDisplayMonth] = React.useState(
|
|
314
|
-
startOfMonth(displayMonth ?? controlledValue ?? defaultValue)
|
|
308
|
+
const [internalDisplayMonth, setInternalDisplayMonth] = React.useState(() =>
|
|
309
|
+
startOfMonth(displayMonth ?? controlledValue ?? defaultValue ?? new Date())
|
|
315
310
|
)
|
|
316
311
|
const [internalView, setInternalView] = React.useState<CalendarView>("days")
|
|
317
312
|
const selected = controlledValue ?? internalValue
|
|
318
313
|
const activeDisplayMonth = startOfMonth(displayMonth ?? internalDisplayMonth)
|
|
319
314
|
const activeView = view ?? internalView
|
|
320
|
-
const eventDates = events ?? [
|
|
315
|
+
const eventDates = events ?? []
|
|
316
|
+
const resolvedMonthYearItems =
|
|
317
|
+
monthYearItems ?? createMonthYearItems(activeDisplayMonth)
|
|
321
318
|
|
|
322
319
|
function updateDisplayMonth(nextMonth: Date) {
|
|
323
320
|
const normalized = startOfMonth(nextMonth)
|
|
@@ -372,7 +369,14 @@ function Calendar({
|
|
|
372
369
|
{activeView === "month-year" ? (
|
|
373
370
|
<>
|
|
374
371
|
<div aria-hidden="true" className="h-[var(--bh-date-month-year-spacer-height)] w-full" />
|
|
375
|
-
<MonthYearList
|
|
372
|
+
<MonthYearList
|
|
373
|
+
items={resolvedMonthYearItems}
|
|
374
|
+
onSelect={(item) => {
|
|
375
|
+
if (!item.value) return
|
|
376
|
+
updateDisplayMonth(item.value)
|
|
377
|
+
updateView("days")
|
|
378
|
+
}}
|
|
379
|
+
/>
|
|
376
380
|
</>
|
|
377
381
|
) : null}
|
|
378
382
|
</div>
|
|
@@ -381,17 +385,17 @@ function Calendar({
|
|
|
381
385
|
|
|
382
386
|
function RangeCalendar({
|
|
383
387
|
className,
|
|
384
|
-
defaultValue =
|
|
388
|
+
defaultValue = {},
|
|
385
389
|
dir,
|
|
386
390
|
displayMonth,
|
|
387
391
|
nextLabel = "Next month",
|
|
388
392
|
onDisplayMonthChange,
|
|
389
393
|
onPresetSelect,
|
|
390
394
|
onSelect,
|
|
391
|
-
presets
|
|
395
|
+
presets,
|
|
392
396
|
previousLabel = "Previous month",
|
|
393
397
|
showPresets,
|
|
394
|
-
showTime =
|
|
398
|
+
showTime = false,
|
|
395
399
|
timeLabel = "Time",
|
|
396
400
|
timeValue = defaultTimeValue,
|
|
397
401
|
type = "double",
|
|
@@ -399,13 +403,15 @@ function RangeCalendar({
|
|
|
399
403
|
...props
|
|
400
404
|
}: RangeCalendarProps) {
|
|
401
405
|
const [internalRange, setInternalRange] = React.useState(defaultValue)
|
|
402
|
-
const [internalDisplayMonth, setInternalDisplayMonth] = React.useState(
|
|
403
|
-
startOfMonth(displayMonth ?? defaultValue.from ??
|
|
406
|
+
const [internalDisplayMonth, setInternalDisplayMonth] = React.useState(() =>
|
|
407
|
+
startOfMonth(displayMonth ?? defaultValue.from ?? new Date())
|
|
404
408
|
)
|
|
409
|
+
const [presetReferenceDate] = React.useState(() => startOfDay(new Date()))
|
|
405
410
|
const selectedRange = normalizeRange(value ?? internalRange)
|
|
406
411
|
const activeDisplayMonth = startOfMonth(displayMonth ?? internalDisplayMonth)
|
|
407
412
|
const monthsToRender = type === "single" ? 1 : 2
|
|
408
413
|
const shouldShowPresets = showPresets ?? type === "double-with-presets"
|
|
414
|
+
const presetItems = presets ?? createDefaultPresets(presetReferenceDate)
|
|
409
415
|
const monthNodes = Array.from({ length: monthsToRender }, (_, index) =>
|
|
410
416
|
addMonths(activeDisplayMonth, index)
|
|
411
417
|
)
|
|
@@ -451,12 +457,17 @@ function RangeCalendar({
|
|
|
451
457
|
data-slot="range-calendar-presets"
|
|
452
458
|
className="grid w-[var(--bh-date-presets-width)] shrink-0 border-e border-[var(--bh-border-subtle)] pe-[var(--bh-space-md-8)]"
|
|
453
459
|
>
|
|
454
|
-
{
|
|
460
|
+
{presetItems.map((preset, index) => {
|
|
461
|
+
const disabled =
|
|
462
|
+
Boolean(preset.disabled) ||
|
|
463
|
+
(!preset.range && onPresetSelect === undefined)
|
|
464
|
+
|
|
465
|
+
return (
|
|
455
466
|
<button
|
|
456
|
-
aria-disabled={
|
|
467
|
+
aria-disabled={disabled || undefined}
|
|
457
468
|
className={dateListItem()}
|
|
458
469
|
data-slot="range-calendar-preset"
|
|
459
|
-
disabled={
|
|
470
|
+
disabled={disabled}
|
|
460
471
|
key={preset.id || index}
|
|
461
472
|
type="button"
|
|
462
473
|
onClick={() => selectPreset(preset)}
|
|
@@ -465,7 +476,8 @@ function RangeCalendar({
|
|
|
465
476
|
{preset.label}
|
|
466
477
|
</span>
|
|
467
478
|
</button>
|
|
468
|
-
|
|
479
|
+
)
|
|
480
|
+
})}
|
|
469
481
|
</div>
|
|
470
482
|
) : null}
|
|
471
483
|
|
|
@@ -501,6 +513,7 @@ function DatePicker({
|
|
|
501
513
|
className,
|
|
502
514
|
defaultOpen = false,
|
|
503
515
|
defaultValue,
|
|
516
|
+
density,
|
|
504
517
|
dir,
|
|
505
518
|
disabled,
|
|
506
519
|
icon,
|
|
@@ -509,13 +522,14 @@ function DatePicker({
|
|
|
509
522
|
open,
|
|
510
523
|
placeholder = "Select date",
|
|
511
524
|
triggerClassName,
|
|
525
|
+
triggerProps,
|
|
512
526
|
value,
|
|
513
527
|
...props
|
|
514
528
|
}: DatePickerProps) {
|
|
515
529
|
const [internalOpen, setInternalOpen] = React.useState(defaultOpen)
|
|
516
530
|
const [internalValue, setInternalValue] = React.useState(defaultValue)
|
|
517
531
|
const [internalDisplayMonth, setInternalDisplayMonth] = React.useState(() =>
|
|
518
|
-
startOfMonth(value ?? defaultValue ??
|
|
532
|
+
startOfMonth(value ?? defaultValue ?? new Date())
|
|
519
533
|
)
|
|
520
534
|
const selected = value ?? internalValue
|
|
521
535
|
const isOpen = open ?? internalOpen
|
|
@@ -550,34 +564,41 @@ function DatePicker({
|
|
|
550
564
|
}
|
|
551
565
|
|
|
552
566
|
return (
|
|
553
|
-
<
|
|
567
|
+
<Popover
|
|
568
|
+
open={isOpen}
|
|
569
|
+
onOpenChange={updateOpen}
|
|
554
570
|
data-open={isOpen ? "true" : "false"}
|
|
555
571
|
data-slot="date-picker"
|
|
556
572
|
dir={dir}
|
|
557
573
|
className={cn("relative w-[var(--bh-date-picker-width)] max-w-full", className)}
|
|
558
574
|
{...props}
|
|
559
575
|
>
|
|
560
|
-
<
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
576
|
+
<PopoverTrigger asChild>
|
|
577
|
+
<DatePickerTrigger
|
|
578
|
+
{...triggerProps}
|
|
579
|
+
disabled={disabled ?? triggerProps?.disabled}
|
|
580
|
+
density={density}
|
|
581
|
+
icon={icon}
|
|
582
|
+
open={isOpen}
|
|
583
|
+
placeholder={placeholder}
|
|
584
|
+
value={selected ? formatCalendarDate(selected, { month: "long" }) : undefined}
|
|
585
|
+
className={cn(triggerClassName, triggerProps?.className)}
|
|
586
|
+
/>
|
|
587
|
+
</PopoverTrigger>
|
|
569
588
|
|
|
570
|
-
|
|
589
|
+
<PopoverContent
|
|
590
|
+
align="center"
|
|
591
|
+
showArrow={false}
|
|
592
|
+
size="auto"
|
|
593
|
+
className="w-auto bg-transparent p-0 shadow-none"
|
|
594
|
+
>
|
|
571
595
|
<Calendar
|
|
572
596
|
{...calendarProps}
|
|
573
|
-
defaultValue={defaultValue
|
|
597
|
+
defaultValue={defaultValue}
|
|
574
598
|
displayMonth={calendarProps?.displayMonth ?? internalDisplayMonth}
|
|
575
599
|
selectedDate={selected}
|
|
576
600
|
surfaceSize="picker"
|
|
577
|
-
className={
|
|
578
|
-
"absolute left-1/2 top-[calc(100%+var(--bh-space-md-8))] z-[var(--bh-z-popover)] -translate-x-1/2",
|
|
579
|
-
calendarProps?.className
|
|
580
|
-
)}
|
|
601
|
+
className={calendarProps?.className}
|
|
581
602
|
dir={calendarProps?.dir ?? dir}
|
|
582
603
|
onDisplayMonthChange={updateDisplayMonth}
|
|
583
604
|
onSelect={(nextDate) => {
|
|
@@ -585,8 +606,8 @@ function DatePicker({
|
|
|
585
606
|
calendarProps?.onSelect?.(nextDate)
|
|
586
607
|
}}
|
|
587
608
|
/>
|
|
588
|
-
|
|
589
|
-
</
|
|
609
|
+
</PopoverContent>
|
|
610
|
+
</Popover>
|
|
590
611
|
)
|
|
591
612
|
}
|
|
592
613
|
|
|
@@ -595,6 +616,7 @@ function DateRangePicker({
|
|
|
595
616
|
className,
|
|
596
617
|
defaultOpen = false,
|
|
597
618
|
defaultValue,
|
|
619
|
+
density,
|
|
598
620
|
dir,
|
|
599
621
|
disabled,
|
|
600
622
|
icon,
|
|
@@ -603,6 +625,7 @@ function DateRangePicker({
|
|
|
603
625
|
open,
|
|
604
626
|
placeholder = "Select date range",
|
|
605
627
|
triggerClassName,
|
|
628
|
+
triggerProps,
|
|
606
629
|
type = "double",
|
|
607
630
|
value,
|
|
608
631
|
...props
|
|
@@ -612,7 +635,7 @@ function DateRangePicker({
|
|
|
612
635
|
const selectedRange = normalizeRange(value ?? internalValue ?? {})
|
|
613
636
|
const isOpen = open ?? internalOpen
|
|
614
637
|
const [internalDisplayMonth, setInternalDisplayMonth] = React.useState(() =>
|
|
615
|
-
startOfMonth(selectedRange.from ?? defaultValue?.from ??
|
|
638
|
+
startOfMonth(selectedRange.from ?? defaultValue?.from ?? new Date())
|
|
616
639
|
)
|
|
617
640
|
const selectedRangeFromTime = selectedRange.from?.getTime()
|
|
618
641
|
|
|
@@ -645,7 +668,9 @@ function DateRangePicker({
|
|
|
645
668
|
}
|
|
646
669
|
|
|
647
670
|
return (
|
|
648
|
-
<
|
|
671
|
+
<Popover
|
|
672
|
+
open={isOpen}
|
|
673
|
+
onOpenChange={updateOpen}
|
|
649
674
|
data-open={isOpen ? "true" : "false"}
|
|
650
675
|
data-slot="date-range-picker"
|
|
651
676
|
data-type={type}
|
|
@@ -653,27 +678,32 @@ function DateRangePicker({
|
|
|
653
678
|
className={cn("relative w-[var(--bh-date-picker-width)] max-w-full", className)}
|
|
654
679
|
{...props}
|
|
655
680
|
>
|
|
656
|
-
<
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
681
|
+
<PopoverTrigger asChild>
|
|
682
|
+
<DatePickerTrigger
|
|
683
|
+
{...triggerProps}
|
|
684
|
+
disabled={disabled ?? triggerProps?.disabled}
|
|
685
|
+
density={density}
|
|
686
|
+
icon={icon}
|
|
687
|
+
open={isOpen}
|
|
688
|
+
placeholder={placeholder}
|
|
689
|
+
value={formatCalendarRange(selectedRange)}
|
|
690
|
+
className={cn(triggerClassName, triggerProps?.className)}
|
|
691
|
+
/>
|
|
692
|
+
</PopoverTrigger>
|
|
665
693
|
|
|
666
|
-
|
|
694
|
+
<PopoverContent
|
|
695
|
+
align="center"
|
|
696
|
+
showArrow={false}
|
|
697
|
+
size="auto"
|
|
698
|
+
className="w-auto bg-transparent p-0 shadow-none"
|
|
699
|
+
>
|
|
667
700
|
<RangeCalendar
|
|
668
701
|
{...calendarProps}
|
|
669
|
-
defaultValue={defaultValue ??
|
|
702
|
+
defaultValue={defaultValue ?? {}}
|
|
670
703
|
displayMonth={calendarProps?.displayMonth ?? internalDisplayMonth}
|
|
671
704
|
type={type}
|
|
672
705
|
value={selectedRange}
|
|
673
|
-
className={
|
|
674
|
-
"absolute left-1/2 top-[calc(100%+var(--bh-space-md-8))] z-[var(--bh-z-popover)] -translate-x-1/2",
|
|
675
|
-
calendarProps?.className
|
|
676
|
-
)}
|
|
706
|
+
className={calendarProps?.className}
|
|
677
707
|
dir={calendarProps?.dir ?? dir}
|
|
678
708
|
onDisplayMonthChange={updateDisplayMonth}
|
|
679
709
|
onSelect={(nextRange) => {
|
|
@@ -681,45 +711,54 @@ function DateRangePicker({
|
|
|
681
711
|
calendarProps?.onSelect?.(nextRange)
|
|
682
712
|
}}
|
|
683
713
|
/>
|
|
684
|
-
|
|
685
|
-
</
|
|
714
|
+
</PopoverContent>
|
|
715
|
+
</Popover>
|
|
686
716
|
)
|
|
687
717
|
}
|
|
688
718
|
|
|
719
|
+
type DatePickerTriggerProps = Omit<
|
|
720
|
+
React.ComponentProps<"button">,
|
|
721
|
+
"children" | "value"
|
|
722
|
+
> & {
|
|
723
|
+
density?: ControlDensity
|
|
724
|
+
icon?: React.ReactNode
|
|
725
|
+
open?: boolean
|
|
726
|
+
placeholder: React.ReactNode
|
|
727
|
+
value?: React.ReactNode
|
|
728
|
+
}
|
|
729
|
+
|
|
689
730
|
function DatePickerTrigger({
|
|
690
731
|
className,
|
|
732
|
+
density,
|
|
691
733
|
disabled,
|
|
692
734
|
icon,
|
|
693
735
|
onClick,
|
|
694
736
|
open,
|
|
695
737
|
placeholder,
|
|
738
|
+
type = "button",
|
|
696
739
|
value,
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
disabled?: boolean
|
|
700
|
-
icon?: React.ReactNode
|
|
701
|
-
onClick?: React.MouseEventHandler<HTMLButtonElement>
|
|
702
|
-
open?: boolean
|
|
703
|
-
placeholder: React.ReactNode
|
|
704
|
-
value?: React.ReactNode
|
|
705
|
-
}) {
|
|
740
|
+
...props
|
|
741
|
+
}: DatePickerTriggerProps) {
|
|
706
742
|
const hasValue = hasRenderableContent(value)
|
|
707
743
|
|
|
708
744
|
return (
|
|
709
745
|
<button
|
|
710
746
|
aria-expanded={open || undefined}
|
|
747
|
+
data-date-picker-trigger=""
|
|
748
|
+
data-density={density ?? "comfortable"}
|
|
711
749
|
data-slot="date-picker-trigger"
|
|
712
750
|
disabled={disabled}
|
|
713
|
-
type=
|
|
714
|
-
className={cn(pickerTrigger(), className)}
|
|
751
|
+
type={type}
|
|
752
|
+
className={cn(pickerTrigger({ density }), className)}
|
|
715
753
|
onClick={onClick}
|
|
754
|
+
{...props}
|
|
716
755
|
>
|
|
717
756
|
<span
|
|
718
757
|
aria-hidden="true"
|
|
719
758
|
data-slot="date-picker-trigger-icon"
|
|
720
759
|
className="flex size-[var(--bh-date-trigger-icon-size)] shrink-0 items-center justify-center text-[var(--bh-content-muted)] group-disabled/date-trigger:text-[var(--bh-content-disabled)] [&_svg:not([class*='size-'])]:size-[var(--bh-date-trigger-icon-size)]"
|
|
721
760
|
>
|
|
722
|
-
{icon ?? <CalendarDaysIcon strokeWidth=
|
|
761
|
+
{icon ?? <CalendarDaysIcon strokeWidth="var(--bh-icon-stroke-180)" />}
|
|
723
762
|
</span>
|
|
724
763
|
<span
|
|
725
764
|
data-slot="date-picker-trigger-value"
|
|
@@ -1003,7 +1042,7 @@ function CalendarTime({
|
|
|
1003
1042
|
{label}
|
|
1004
1043
|
</span>
|
|
1005
1044
|
<span
|
|
1006
|
-
data-slot="calendar-time-
|
|
1045
|
+
data-slot="calendar-time-value"
|
|
1007
1046
|
className="flex min-h-[var(--bh-date-time-input-min-height)] min-w-0 flex-1 items-center gap-[var(--bh-space-xs-4)] rounded-[var(--bh-radius-lg-8)] bg-[var(--bh-interactive-input-default)] px-[var(--bh-space-md-8)] py-[var(--bh-space-sm-6)] shadow-[var(--shadow-date-time-input)]"
|
|
1008
1047
|
>
|
|
1009
1048
|
<CalendarTimeSegment active>{resolved.hours}</CalendarTimeSegment>
|
|
@@ -1039,7 +1078,13 @@ function CalendarTimeSegment({
|
|
|
1039
1078
|
)
|
|
1040
1079
|
}
|
|
1041
1080
|
|
|
1042
|
-
function MonthYearList({
|
|
1081
|
+
function MonthYearList({
|
|
1082
|
+
items,
|
|
1083
|
+
onSelect,
|
|
1084
|
+
}: {
|
|
1085
|
+
items: CalendarMonthYearItem[]
|
|
1086
|
+
onSelect: (item: CalendarMonthYearItem) => void
|
|
1087
|
+
}) {
|
|
1043
1088
|
return (
|
|
1044
1089
|
<div
|
|
1045
1090
|
data-slot="calendar-month-year-list"
|
|
@@ -1055,8 +1100,9 @@ function MonthYearList({ items }: { items: CalendarMonthYearItem[] }) {
|
|
|
1055
1100
|
)}
|
|
1056
1101
|
data-selected={item.selected ? "true" : undefined}
|
|
1057
1102
|
data-slot="calendar-month-year-item"
|
|
1058
|
-
disabled={item.disabled}
|
|
1103
|
+
disabled={item.disabled || !item.value}
|
|
1059
1104
|
key={item.id || index}
|
|
1105
|
+
onClick={() => onSelect(item)}
|
|
1060
1106
|
type="button"
|
|
1061
1107
|
>
|
|
1062
1108
|
<span className="truncate">{item.month}</span>
|
|
@@ -1067,6 +1113,99 @@ function MonthYearList({ items }: { items: CalendarMonthYearItem[] }) {
|
|
|
1067
1113
|
)
|
|
1068
1114
|
}
|
|
1069
1115
|
|
|
1116
|
+
function startOfDay(date: Date) {
|
|
1117
|
+
return new Date(date.getFullYear(), date.getMonth(), date.getDate())
|
|
1118
|
+
}
|
|
1119
|
+
|
|
1120
|
+
function addDays(date: Date, amount: number) {
|
|
1121
|
+
const next = startOfDay(date)
|
|
1122
|
+
next.setDate(next.getDate() + amount)
|
|
1123
|
+
return next
|
|
1124
|
+
}
|
|
1125
|
+
|
|
1126
|
+
function createDefaultPresets(today: Date): CalendarPreset[] {
|
|
1127
|
+
const quarterStartMonth = Math.floor(today.getMonth() / 3) * 3
|
|
1128
|
+
|
|
1129
|
+
return [
|
|
1130
|
+
{ id: "today", label: "Today", range: { from: today, to: today } },
|
|
1131
|
+
{
|
|
1132
|
+
id: "last-7-days",
|
|
1133
|
+
label: "Last 7 days",
|
|
1134
|
+
range: { from: addDays(today, -6), to: today },
|
|
1135
|
+
},
|
|
1136
|
+
{
|
|
1137
|
+
id: "last-14-days",
|
|
1138
|
+
label: "Last 14 days",
|
|
1139
|
+
range: { from: addDays(today, -13), to: today },
|
|
1140
|
+
},
|
|
1141
|
+
{
|
|
1142
|
+
id: "last-30-days",
|
|
1143
|
+
label: "Last 30 days",
|
|
1144
|
+
range: { from: addDays(today, -29), to: today },
|
|
1145
|
+
},
|
|
1146
|
+
{
|
|
1147
|
+
id: "last-3-months",
|
|
1148
|
+
label: "Last 3 months",
|
|
1149
|
+
range: { from: addMonths(today, -3), to: today },
|
|
1150
|
+
},
|
|
1151
|
+
{
|
|
1152
|
+
id: "last-12-months",
|
|
1153
|
+
label: "Last 12 months",
|
|
1154
|
+
range: { from: addMonths(today, -12), to: today },
|
|
1155
|
+
},
|
|
1156
|
+
{
|
|
1157
|
+
id: "quarter-to-date",
|
|
1158
|
+
label: "Quarter to date",
|
|
1159
|
+
range: {
|
|
1160
|
+
from: new Date(today.getFullYear(), quarterStartMonth, 1),
|
|
1161
|
+
to: today,
|
|
1162
|
+
},
|
|
1163
|
+
},
|
|
1164
|
+
{
|
|
1165
|
+
id: "year-to-date",
|
|
1166
|
+
label: "Year to date",
|
|
1167
|
+
range: { from: new Date(today.getFullYear(), 0, 1), to: today },
|
|
1168
|
+
},
|
|
1169
|
+
]
|
|
1170
|
+
}
|
|
1171
|
+
|
|
1172
|
+
function createMonthYearItems(
|
|
1173
|
+
displayMonth: Date
|
|
1174
|
+
): CalendarMonthYearItem[] {
|
|
1175
|
+
return Array.from({ length: 7 }, (_, index) => {
|
|
1176
|
+
const value = addMonths(displayMonth, index - 3)
|
|
1177
|
+
|
|
1178
|
+
return {
|
|
1179
|
+
id: `${value.getFullYear()}-${value.getMonth()}`,
|
|
1180
|
+
month: new Intl.DateTimeFormat(undefined, { month: "long" }).format(value),
|
|
1181
|
+
selected: index === 3,
|
|
1182
|
+
value,
|
|
1183
|
+
year: String(value.getFullYear()),
|
|
1184
|
+
}
|
|
1185
|
+
})
|
|
1186
|
+
}
|
|
1187
|
+
|
|
1188
|
+
function getCurrentTimeValue(): Required<CalendarTimeValue> {
|
|
1189
|
+
const now = new Date()
|
|
1190
|
+
const timeParts = new Intl.DateTimeFormat("en-US", {
|
|
1191
|
+
hour: "2-digit",
|
|
1192
|
+
hour12: true,
|
|
1193
|
+
minute: "2-digit",
|
|
1194
|
+
}).formatToParts(now)
|
|
1195
|
+
const zoneParts = new Intl.DateTimeFormat("en-US", {
|
|
1196
|
+
timeZoneName: "short",
|
|
1197
|
+
}).formatToParts(now)
|
|
1198
|
+
const getPart = (parts: Intl.DateTimeFormatPart[], type: string) =>
|
|
1199
|
+
parts.find((part) => part.type === type)?.value ?? ""
|
|
1200
|
+
|
|
1201
|
+
return {
|
|
1202
|
+
hours: getPart(timeParts, "hour"),
|
|
1203
|
+
minutes: getPart(timeParts, "minute"),
|
|
1204
|
+
period: getPart(timeParts, "dayPeriod"),
|
|
1205
|
+
zone: getPart(zoneParts, "timeZoneName") || "UTC",
|
|
1206
|
+
}
|
|
1207
|
+
}
|
|
1208
|
+
|
|
1070
1209
|
function hasRenderableContent(content: React.ReactNode) {
|
|
1071
1210
|
return (
|
|
1072
1211
|
content !== undefined &&
|
|
@@ -1094,7 +1233,9 @@ export type {
|
|
|
1094
1233
|
CalendarView,
|
|
1095
1234
|
DatePickerDirection,
|
|
1096
1235
|
DatePickerProps,
|
|
1236
|
+
DatePickerTriggerProps,
|
|
1097
1237
|
DateRangePickerProps,
|
|
1238
|
+
ControlDensity,
|
|
1098
1239
|
RangeCalendarProps,
|
|
1099
1240
|
RangeCalendarType,
|
|
1100
1241
|
}
|