From dfd3b0df775a5f11fbf785874942b34821c22a1b Mon Sep 17 00:00:00 2001 From: Marco Schumacher Date: Wed, 13 Sep 2023 08:46:22 +0200 Subject: [PATCH] feat: added minDate/maxDate to DatePicker --- .vscode/settings.json | 3 +++ docs/stories/_default.tsx | 2 +- src/components/dateFilter.tsx | 9 ++++++++- src/components/datePicker.tsx | 35 ++++++++++++++++++++++++++++++++++- 4 files changed, 46 insertions(+), 3 deletions(-) create mode 100644 .vscode/settings.json diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..25fa621 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "typescript.tsdk": "node_modules/typescript/lib" +} diff --git a/docs/stories/_default.tsx b/docs/stories/_default.tsx index 7863516..5fc56b2 100644 --- a/docs/stories/_default.tsx +++ b/docs/stories/_default.tsx @@ -30,7 +30,7 @@ const _defaultColumns: TableProps['columns'] = (col) => [ col((x) => x.birthday, { header: 'Birthday', renderCell: (birthday) => dateFormat.format(new Date(birthday)), - filter: , + filter: , }), ]; diff --git a/src/components/dateFilter.tsx b/src/components/dateFilter.tsx index 876bc0e..2e89db7 100644 --- a/src/components/dateFilter.tsx +++ b/src/components/dateFilter.tsx @@ -32,11 +32,16 @@ export function DateFilter({ quickOptions, singleSelect, filterBy = convertDateOrArray, + minDate, + maxDate, ...props }: { /** If enabled, only single days can be selected. Ranges otherwise. */ singleSelect?: boolean; -} & Pick & +} & Pick< + DatePickerProps, + 'locale' | 'firstDayOfWeek' | 'defaultDateInView' | 'quickOptions' | 'minDate' | 'maxDate' +> & CommonFilterProps): JSX.Element { const { value = null, onChange } = useFilter({ ...props, @@ -68,6 +73,8 @@ export function DateFilter({ firstDayOfWeek={firstDayOfWeek} defaultDateInView={defaultDateInView} quickOptions={quickOptions} + minDate={minDate} + maxDate={maxDate} /> ); diff --git a/src/components/datePicker.tsx b/src/components/datePicker.tsx index 38c839a..f9e51e4 100644 --- a/src/components/datePicker.tsx +++ b/src/components/datePicker.tsx @@ -36,6 +36,8 @@ export type DatePickerProps = { defaultDateInView?: Date; /** Show buttons to quickly select suggested dates or date ranges */ quickOptions?: DatePickerQuickOption[]; + minDate?: Date; + maxDate?: Date; }; const weekDays = [0, 1, 2, 3, 4, 5, 6] as const; @@ -138,17 +140,43 @@ export function dateIntersect(a: Date | null | DateRange, b: Date | null | DateR return !(endOfDay(a.max) < startOfDay(b.min) || startOfDay(a.min) > endOfDay(b.max)); } +export function dateClamp(date: Date, min?: Date, max?: Date) { + if (min && date < min) { + return min; + } + + if (max && date > max) { + return max; + } + + return date; +} + export function DatePicker(props: DatePickerProps) { const { value, - onChange, rangeSelect, locale, firstDayOfWeek = 1, defaultDateInView, quickOptions = ['today', 'thisWeek'], + minDate, + maxDate, } = props; + function onChange(value: Date | DateRange | null) { + if (value instanceof Date) { + value = dateClamp(value, minDate, maxDate); + } else if (value) { + value = { + min: dateClamp(value.min, minDate, maxDate), + max: dateClamp(value.max, minDate, maxDate), + }; + } + + props.onChange(value); + } + const Button = useTheme((t) => t.components.Button); const IconButton = useTheme((t) => t.components.IconButton); const ChevronRight = useTheme((t) => t.icons.ChevronRight); @@ -201,6 +229,8 @@ export function DatePicker(props: DatePickerProps) { onOffsetChanged: (offset) => setDateInView(new Date(dateInView.getFullYear(), dateInView.getMonth() + offset)), offset: 0, + minDate, + maxDate, }); const now = useMemo(() => startOfDay(new Date()), []); @@ -333,12 +363,14 @@ export function DatePicker(props: DatePickerProps) { const { prevMonth, nextMonth, date } = dateObject; const today = startOfDay(date).getTime() === now.getTime(); + const disabled = (minDate && date < minDate) || (maxDate && date > maxDate); const selected = date.getTime() === min?.getTime() || (min && max && dateIntersect(date, { min, max })); const preSelected = !selected && + !disabled && (date.getTime() === hovered?.getTime() || (min && !max && @@ -384,6 +416,7 @@ export function DatePicker(props: DatePickerProps) { }} onPointerOver={() => setHovered(date)} onPointerOut={() => setHovered(undefined)} + disabled={disabled} > {date.getDate()}