-
Notifications
You must be signed in to change notification settings - Fork 5
Expand file tree
/
Copy pathdate-picker.txt
More file actions
157 lines (145 loc) · 4.53 KB
/
Copy pathdate-picker.txt
File metadata and controls
157 lines (145 loc) · 4.53 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
"use client";
import type {
DatePickerProps as AriaDatePickerProps,
DateRangePickerProps as AriaDateRangePickerProps,
} from "react-aria-components";
import {
DatePicker as AriaDatePicker,
DateRangePicker as AriaDateRangePicker,
Button,
DateInput,
DateSegment,
type DateValue,
Dialog,
FieldError,
Group,
Label,
Popover,
Text,
} from "react-aria-components";
import { tv } from "tailwind-variants";
import { ChevronDown } from "lucide-react";
import { Calendar, RangeCalendar } from "../calendar/calendar";
const baseStyles = tv({
slots: {
input:
"appearance-none rounded-lg px-3 py-1.5 outline-none ring-primary transition-all",
popover:
"overflow-auto rounded-2xl data-[entering]:animate-fade data-[exiting]:animate-fadeOut",
},
});
const datePicker = tv({
extend: baseStyles,
slots: {
group:
"relative flex min-h-11 w-auto min-w-48 items-center rounded-lg border border-border bg-surface transition-all data-[focus-within]:border-transparent data-[focus-within]:bg-surface data-[focus-within]:ring-2 data-[focus-within]:ring-primary data-[focus-within]:ring-offset-surface",
dateSegment:
"min-w-16 rounded-md p-1 text-end outline-none focus:bg-primary focus:text-primary-fg data-[placeholder]:text-fg-muted data-[type='literal']:text-fg-muted data-[placeholder]:focus:text-primary-fg",
},
});
const dateRangePicker = tv({
extend: baseStyles,
slots: {
group:
"relative flex min-h-11 w-full flex-wrap items-center rounded-lg border border-border bg-surface transition-all data-[focus-within]:border-transparent data-[focus-within]:bg-surface data-[focus-within]:ring-2 data-[focus-within]:ring-primary data-[focus-within]:ring-offset-surface",
dateSegment:
"rounded-md p-1 text-end outline-none focus:bg-primary focus:text-primary-fg data-[placeholder]:text-fg-muted data-[type='literal']:text-fg-muted data-[placeholder]:focus:text-primary-fg",
separator: "px-2 text-fg-muted",
},
});
const styles = datePicker();
const rangeStyles = dateRangePicker();
interface DatePickerProps<T extends DateValue> extends AriaDatePickerProps<T> {
label?: string;
description?: string;
errorMessage?: string;
}
const DatePicker = <T extends DateValue>({
className,
label,
description,
errorMessage,
children,
...props
}: DatePickerProps<T>) => (
<AriaDatePicker className="flex flex-col gap-1" {...props}>
{label && <Label className="text-sm">{label}</Label>}
<Group className={styles.group()}>
<DateInput className={styles.input()}>
{(segment) => (
<DateSegment className={styles.dateSegment()} segment={segment} />
)}
</DateInput>
<Button className="absolute right-2 w-6 rounded-xs outline-offset-0">
<ChevronDown className="size-4 text-fg-muted" />
</Button>
</Group>
{description && (
<Text className="text-fg-muted text-sm" slot="description">
{description}
</Text>
)}
<FieldError className="text-danger text-sm">{errorMessage}</FieldError>
<Popover className={styles.popover()}>
<Dialog>
<Calendar />
</Dialog>
</Popover>
</AriaDatePicker>
);
interface DateRangePickerProps<T extends DateValue>
extends AriaDateRangePickerProps<T> {
label?: string;
description?: string;
errorMessage?: string;
className?: string;
}
const DateRangePicker = <T extends DateValue>({
className,
label,
description,
errorMessage,
children,
...props
}: DateRangePickerProps<T>) => (
<AriaDateRangePicker className="flex w-full flex-col gap-1" {...props}>
{label && <Label className="text-sm">{label}</Label>}
<Group className={rangeStyles.group({ className })}>
<DateInput slot="start" className={rangeStyles.input()}>
{(segment) => (
<DateSegment
className={rangeStyles.dateSegment()}
segment={segment}
/>
)}
</DateInput>
<span className={rangeStyles.separator()} aria-hidden="true">
–
</span>
<DateInput slot="end" className={rangeStyles.input()}>
{(segment) => (
<DateSegment
className={rangeStyles.dateSegment()}
segment={segment}
/>
)}
</DateInput>
<Button className="absolute right-2 w-6 rounded-xs outline-offset-0">
<ChevronDown className="size-4 text-fg-muted" />
</Button>
</Group>
{description && (
<Text className="text-fg-muted text-sm" slot="description">
{description}
</Text>
)}
<FieldError className="text-danger text-sm">{errorMessage}</FieldError>
<Popover className={rangeStyles.popover()}>
<Dialog>
<RangeCalendar />
</Dialog>
</Popover>
</AriaDateRangePicker>
);
export { DatePicker, DateRangePicker };
export type { DatePickerProps, DateRangePickerProps };