Skip to content

Commit 981b898

Browse files
marcopiiiveej
authored andcommitted
create DateInput
1 parent 7cb5105 commit 981b898

File tree

2 files changed

+139
-5
lines changed

2 files changed

+139
-5
lines changed

Diff for: packages/bento-design-system/src/DateField/BaseDateInput.tsx

+13-5
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { DatePickerAria, DateRangePickerAria } from "@react-aria/datepicker";
22
import { DatePickerState, DateRangePickerState } from "@react-stately/datepicker";
33
import React from "react";
4+
import { match } from "ts-pattern";
45
import { Input } from "./Input";
56
import { Calendar } from "./Calendar";
67
import { Box } from "../Box/Box";
@@ -9,22 +10,22 @@ import { Button, FieldProps } from "..";
910
import { ShortcutProps } from "./types";
1011

1112
type SingleDateProps = {
12-
type?: "single";
13+
type: "single";
1314
shortcuts?: ShortcutProps<Date | null>[];
1415
datePickerAria: DatePickerAria;
1516
datePickerState: DatePickerState;
16-
} & Pick<FieldProps<Date | null>, "onChange" | "value" | "disabled">;
17+
} & Pick<FieldProps<Date | null>, "onChange" | "value">;
1718

1819
type RangeDateProps = {
1920
type: "range";
2021
shortcuts?: ShortcutProps<[Date, Date] | null>[];
2122
dateRangePickerAria: DateRangePickerAria;
2223
dateRangePickerState: DateRangePickerState;
23-
} & Pick<FieldProps<[Date, Date] | null>, "onChange" | "value" | "disabled">;
24+
} & Pick<FieldProps<[Date, Date] | null>, "onChange" | "value">;
2425

2526
type Props = (SingleDateProps | RangeDateProps) & { inputRef: React.RefObject<HTMLInputElement> };
2627

27-
export function BaseSingleDateInput(props: Extract<Props, { type?: "single" }>) {
28+
function BaseSingleDateInput(props: Extract<Props, { type: "single" }>) {
2829
const shortcuts = props.shortcuts && (
2930
<Inline space={4}>
3031
{props.shortcuts.map((shortcut) => (
@@ -66,7 +67,7 @@ export function BaseSingleDateInput(props: Extract<Props, { type?: "single" }>)
6667
);
6768
}
6869

69-
export function BaseRangeDateInput(props: Extract<Props, { type: "range" }>) {
70+
function BaseRangeDateInput(props: Extract<Props, { type: "range" }>) {
7071
const shortcuts = props.shortcuts && (
7172
<Inline space={4}>
7273
{props.shortcuts.map((shortcut) => (
@@ -110,3 +111,10 @@ export function BaseRangeDateInput(props: Extract<Props, { type: "range" }>) {
110111
</>
111112
);
112113
}
114+
115+
export function BaseDateInput(props: Props) {
116+
return match(props)
117+
.with({ type: "single" }, (props) => <BaseSingleDateInput {...props} />)
118+
.with({ type: "range" }, (props) => <BaseRangeDateInput {...props} />)
119+
.exhaustive();
120+
}
+126
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
import { useDatePicker, useDateRangePicker } from "@react-aria/datepicker";
2+
import { useDatePickerState, useDateRangePickerState } from "@react-stately/datepicker";
3+
import { useRef } from "react";
4+
import { match } from "ts-pattern";
5+
import { FieldProps } from "../Field/FieldProps";
6+
import { CalendarDate, DateValue, getLocalTimeZone } from "@internationalized/date";
7+
import { BaseDateInput } from "./BaseDateInput";
8+
import { RangeValue } from "@react-types/shared";
9+
import { DateProps, ShortcutProps } from "./types";
10+
11+
type StandaloneProps<T> = Pick<
12+
FieldProps<T>,
13+
"autoFocus" | "disabled" | "name" | "onBlur" | "onChange" | "value"
14+
>;
15+
16+
type SingleDateProps = {
17+
type?: "single";
18+
shortcuts?: ShortcutProps<Date | null>[];
19+
};
20+
21+
type RangeDateProps = {
22+
type: "range";
23+
shortcuts?: ShortcutProps<[Date, Date] | null>[];
24+
};
25+
26+
type SingleDateInputProps = SingleDateProps &
27+
StandaloneProps<Date | null> &
28+
DateProps & { validationState: "valid" | "invalid" };
29+
30+
type RangeDateInputProps = RangeDateProps &
31+
StandaloneProps<[Date, Date] | null> &
32+
DateProps & { validationState: "valid" | "invalid" };
33+
34+
function dateToCalendarDate(date: Date): CalendarDate {
35+
return new CalendarDate(date.getFullYear(), date.getMonth() + 1, date.getDate());
36+
}
37+
38+
function SingleDateInput(props: SingleDateInputProps) {
39+
const localTimeZone = getLocalTimeZone();
40+
const ref = useRef(null);
41+
42+
const internalProps = {
43+
...props,
44+
value: props.value ? dateToCalendarDate(props.value) : props.value,
45+
onChange: (date: CalendarDate | null) => {
46+
props.onChange(date?.toDate(localTimeZone) ?? null);
47+
},
48+
isDisabled: props.disabled,
49+
isReadOnly: props.isReadOnly ?? props.readOnly,
50+
validationState: props.validationState,
51+
minValue: props.minDate ? dateToCalendarDate(props.minDate) : undefined,
52+
maxValue: props.maxDate ? dateToCalendarDate(props.maxDate) : undefined,
53+
isDateUnavailable: props.shouldDisableDate
54+
? (date: DateValue) => props.shouldDisableDate!(date.toDate(localTimeZone))
55+
: undefined,
56+
shouldForceLeadingZeros: true,
57+
} as const;
58+
59+
const datePickerState = useDatePickerState(internalProps);
60+
const datePickerAria = useDatePicker(internalProps, datePickerState, ref);
61+
62+
return (
63+
<BaseDateInput
64+
type="single"
65+
value={props.value}
66+
onChange={props.onChange}
67+
shortcuts={props.shortcuts}
68+
datePickerAria={datePickerAria}
69+
datePickerState={datePickerState}
70+
inputRef={ref}
71+
/>
72+
);
73+
}
74+
75+
function RangeDateInput(props: RangeDateInputProps) {
76+
const localTimeZone = getLocalTimeZone();
77+
const ref = useRef(null);
78+
79+
const internalProps = {
80+
...props,
81+
value: props.value
82+
? {
83+
start: dateToCalendarDate(props.value[0]),
84+
end: dateToCalendarDate(props.value[1]),
85+
}
86+
: props.value,
87+
onChange: (range: RangeValue<CalendarDate> | null) => {
88+
if (!range) {
89+
props.onChange(null);
90+
} else {
91+
props.onChange([range.start.toDate(localTimeZone), range.end.toDate(localTimeZone)]);
92+
}
93+
},
94+
isDisabled: props.disabled,
95+
isReadOnly: props.isReadOnly ?? props.readOnly,
96+
validationState: props.validationState,
97+
minValue: props.minDate ? dateToCalendarDate(props.minDate) : undefined,
98+
maxValue: props.maxDate ? dateToCalendarDate(props.maxDate) : undefined,
99+
isDateUnavailable: props.shouldDisableDate
100+
? (date: DateValue) => props.shouldDisableDate!(date.toDate(localTimeZone))
101+
: undefined,
102+
shouldForceLeadingZeros: true,
103+
} as const;
104+
105+
const rangeDatePickerState = useDateRangePickerState(internalProps);
106+
const rangeDatePickerAria = useDateRangePicker(internalProps, rangeDatePickerState, ref);
107+
108+
return (
109+
<BaseDateInput
110+
type="range"
111+
value={props.value}
112+
onChange={props.onChange}
113+
shortcuts={props.shortcuts}
114+
dateRangePickerAria={rangeDatePickerAria}
115+
dateRangePickerState={rangeDatePickerState}
116+
inputRef={ref}
117+
/>
118+
);
119+
}
120+
121+
export function DateInput(props: SingleDateInputProps | RangeDateInputProps) {
122+
return match(props)
123+
.with({ type: "single" }, { type: undefined }, (props) => <SingleDateInput {...props} />)
124+
.with({ type: "range" }, (props) => <RangeDateInput {...props} />)
125+
.exhaustive();
126+
}

0 commit comments

Comments
 (0)