✨(react) introduce DateRangePicker component
Introduce a flexible and reusable DateRangePicker component to facilitate the selection of date ranges in the design system.
This commit is contained in:
committed by
aleb_the_flash
parent
0775490a60
commit
0d6b98ee1f
5
.changeset/smooth-boxes-bow.md
Normal file
5
.changeset/smooth-boxes-bow.md
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"@openfun/cunningham-react": minor
|
||||
---
|
||||
|
||||
Introduce a DateRangePicker component
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,107 @@
|
||||
import React, { useMemo, useRef, useState } from "react";
|
||||
import { DateValue } from "@internationalized/date";
|
||||
import {
|
||||
DateRangePickerStateOptions,
|
||||
useDateRangePickerState,
|
||||
} from "@react-stately/datepicker";
|
||||
import { useDateRangePicker, DateRange } from "@react-aria/datepicker";
|
||||
import { CalendarRange } from ":/components/Forms/DatePicker/Calendar";
|
||||
import DatePickerAux, {
|
||||
DatePickerAuxSubProps,
|
||||
} from ":/components/Forms/DatePicker/DatePickerAux";
|
||||
import DateFieldBox from ":/components/Forms/DatePicker/DateField";
|
||||
import { StringsOrDateRange } from ":/components/Forms/DatePicker/types";
|
||||
import {
|
||||
getDefaultPickerOptions,
|
||||
parseRangeCalendarDate,
|
||||
} from ":/components/Forms/DatePicker/utils";
|
||||
|
||||
export type DateRangePickerProps = DatePickerAuxSubProps & {
|
||||
startLabel: string;
|
||||
endLabel: string;
|
||||
value?: null | StringsOrDateRange;
|
||||
defaultValue?: StringsOrDateRange;
|
||||
onChange?: (value: [string, string] | null) => void;
|
||||
};
|
||||
|
||||
const DateRangePicker = ({
|
||||
startLabel,
|
||||
endLabel,
|
||||
...props
|
||||
}: DateRangePickerProps) => {
|
||||
if (props.defaultValue && props.value) {
|
||||
throw new Error(
|
||||
"You cannot use both defaultValue and value props on DateRangePicker component"
|
||||
);
|
||||
}
|
||||
const ref = useRef<HTMLDivElement>(null);
|
||||
const [isFocused, setIsFocused] = useState(false);
|
||||
|
||||
const options: DateRangePickerStateOptions<DateValue> = {
|
||||
...getDefaultPickerOptions(props),
|
||||
value: props.value === null ? null : parseRangeCalendarDate(props.value),
|
||||
defaultValue: parseRangeCalendarDate(props.defaultValue),
|
||||
onChange: (value: DateRange) => {
|
||||
props.onChange?.(
|
||||
value?.start && value.end
|
||||
? [value.start.toString(), value.end.toString()]
|
||||
: null
|
||||
);
|
||||
},
|
||||
};
|
||||
const pickerState = useDateRangePickerState(options);
|
||||
const { startFieldProps, endFieldProps, calendarProps, ...pickerProps } =
|
||||
useDateRangePicker(options, pickerState, ref);
|
||||
|
||||
const labelAsPlaceholder = useMemo(
|
||||
() =>
|
||||
!isFocused &&
|
||||
!pickerState.isOpen &&
|
||||
!pickerState.value.start &&
|
||||
!pickerState.value.end,
|
||||
[pickerState.value, pickerState.isOpen, isFocused]
|
||||
);
|
||||
|
||||
const calendar = <CalendarRange {...calendarProps} />;
|
||||
|
||||
return (
|
||||
<DatePickerAux
|
||||
{...{
|
||||
...props,
|
||||
labelAsPlaceholder,
|
||||
isFocused,
|
||||
pickerState,
|
||||
pickerProps,
|
||||
optionalClassName: "c__date-picker__range",
|
||||
onClear: () => {
|
||||
pickerState.setValue({
|
||||
start: null as unknown as DateValue,
|
||||
end: null as unknown as DateValue,
|
||||
});
|
||||
},
|
||||
calendar,
|
||||
}}
|
||||
ref={ref}
|
||||
>
|
||||
<DateFieldBox
|
||||
{...{
|
||||
...startFieldProps,
|
||||
label: startLabel,
|
||||
labelAsPlaceholder,
|
||||
onFocusChange: setIsFocused,
|
||||
}}
|
||||
/>
|
||||
<div className="c__date-picker__range__separator" />
|
||||
<DateFieldBox
|
||||
{...{
|
||||
...endFieldProps,
|
||||
label: endLabel,
|
||||
labelAsPlaceholder,
|
||||
onFocusChange: setIsFocused,
|
||||
}}
|
||||
/>
|
||||
</DatePickerAux>
|
||||
);
|
||||
};
|
||||
|
||||
export default DateRangePicker;
|
||||
Reference in New Issue
Block a user