react-day-picker 9.6.2 → 9.6.4
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/dist/cjs/DayPicker.js +15 -3
- package/dist/cjs/DayPicker.js.map +1 -1
- package/dist/cjs/classes/DateLib.js +4 -4
- package/dist/cjs/classes/DateLib.js.map +1 -1
- package/dist/cjs/useAnimation.js +74 -42
- package/dist/cjs/useAnimation.js.map +1 -1
- package/dist/esm/DayPicker.js +15 -3
- package/dist/esm/DayPicker.js.map +1 -1
- package/dist/esm/classes/DateLib.js +1 -1
- package/dist/esm/classes/DateLib.js.map +1 -1
- package/dist/esm/useAnimation.js +74 -42
- package/dist/esm/useAnimation.js.map +1 -1
- package/package.json +2 -4
- package/src/.eslintignore +1 -0
- package/src/.eslintrc.cjs +27 -0
- package/src/DayPicker.test.tsx +199 -0
- package/src/DayPicker.tsx +630 -0
- package/src/UI.ts +365 -0
- package/src/classes/CalendarDay.test.ts +17 -0
- package/src/classes/CalendarDay.ts +61 -0
- package/src/classes/CalendarMonth.test.ts +28 -0
- package/src/classes/CalendarMonth.ts +15 -0
- package/src/classes/CalendarWeek.test.ts +21 -0
- package/src/classes/CalendarWeek.ts +13 -0
- package/src/classes/DateLib.ts +615 -0
- package/src/classes/index.ts +4 -0
- package/src/components/Button.tsx +13 -0
- package/src/components/CaptionLabel.tsx +13 -0
- package/src/components/Chevron.tsx +42 -0
- package/src/components/Day.tsx +28 -0
- package/src/components/DayButton.tsx +29 -0
- package/src/components/Dropdown.tsx +71 -0
- package/src/components/DropdownNav.tsx +13 -0
- package/src/components/Footer.tsx +13 -0
- package/src/components/Month.tsx +24 -0
- package/src/components/MonthCaption.tsx +23 -0
- package/src/components/MonthGrid.tsx +13 -0
- package/src/components/Months.tsx +13 -0
- package/src/components/MonthsDropdown.tsx +16 -0
- package/src/components/Nav.tsx +90 -0
- package/src/components/NextMonthButton.tsx +18 -0
- package/src/components/Option.tsx +13 -0
- package/src/components/PreviousMonthButton.tsx +20 -0
- package/src/components/Root.tsx +19 -0
- package/src/components/Select.tsx +13 -0
- package/src/components/Week.tsx +20 -0
- package/src/components/WeekNumber.tsx +21 -0
- package/src/components/WeekNumberHeader.tsx +15 -0
- package/src/components/Weekday.tsx +13 -0
- package/src/components/Weekdays.tsx +17 -0
- package/src/components/Weeks.tsx +13 -0
- package/src/components/YearsDropdown.tsx +16 -0
- package/src/components/custom-components.tsx +26 -0
- package/src/formatters/formatCaption.test.ts +27 -0
- package/src/formatters/formatCaption.ts +23 -0
- package/src/formatters/formatDay.test.ts +7 -0
- package/src/formatters/formatDay.ts +16 -0
- package/src/formatters/formatMonthDropdown.test.ts +19 -0
- package/src/formatters/formatMonthDropdown.ts +15 -0
- package/src/formatters/formatWeekNumber.test.ts +5 -0
- package/src/formatters/formatWeekNumber.ts +13 -0
- package/src/formatters/formatWeekNumberHeader.ts +10 -0
- package/src/formatters/formatWeekdayName.test.ts +15 -0
- package/src/formatters/formatWeekdayName.ts +16 -0
- package/src/formatters/formatYearDropdown.test.ts +7 -0
- package/src/formatters/formatYearDropdown.ts +21 -0
- package/src/formatters/index.ts +7 -0
- package/src/helpers/broadcastCalendar.test.ts +43 -0
- package/src/helpers/calculateFocusTarget.ts +51 -0
- package/src/helpers/endOfBroadcastWeek.test.ts +25 -0
- package/src/helpers/endOfBroadcastWeek.ts +16 -0
- package/src/helpers/getBroadcastWeeksInMonth.test.ts +23 -0
- package/src/helpers/getBroadcastWeeksInMonth.ts +31 -0
- package/src/helpers/getClassNamesForModifiers.ts +26 -0
- package/src/helpers/getComponents.ts +11 -0
- package/src/helpers/getDataAttributes.test.tsx +48 -0
- package/src/helpers/getDataAttributes.tsx +21 -0
- package/src/helpers/getDates.test.ts +190 -0
- package/src/helpers/getDates.ts +64 -0
- package/src/helpers/getDays.test.ts +30 -0
- package/src/helpers/getDays.ts +16 -0
- package/src/helpers/getDefaultClassNames.test.ts +47 -0
- package/src/helpers/getDefaultClassNames.ts +33 -0
- package/src/helpers/getDisplayMonths.test.ts +44 -0
- package/src/helpers/getDisplayMonths.ts +20 -0
- package/src/helpers/getFocusableDate.ts +59 -0
- package/src/helpers/getFormatters.test.ts +48 -0
- package/src/helpers/getFormatters.ts +19 -0
- package/src/helpers/getInitialMonth.test.ts +79 -0
- package/src/helpers/getInitialMonth.ts +41 -0
- package/src/helpers/getLabels.ts +10 -0
- package/src/helpers/getMonthOptions.test.ts +226 -0
- package/src/helpers/getMonthOptions.ts +37 -0
- package/src/helpers/getMonths.test.ts +88 -0
- package/src/helpers/getMonths.ts +90 -0
- package/src/helpers/getNavMonth.test.ts +253 -0
- package/src/helpers/getNavMonth.ts +70 -0
- package/src/helpers/getNextFocus.test.tsx +99 -0
- package/src/helpers/getNextFocus.tsx +67 -0
- package/src/helpers/getNextMonth.test.ts +101 -0
- package/src/helpers/getNextMonth.ts +45 -0
- package/src/helpers/getPossibleFocusDate.test.ts +144 -0
- package/src/helpers/getPreviousMonth.test.ts +77 -0
- package/src/helpers/getPreviousMonth.ts +40 -0
- package/src/helpers/getStyleForModifiers.test.ts +92 -0
- package/src/helpers/getStyleForModifiers.ts +21 -0
- package/src/helpers/getWeekdays.test.ts +44 -0
- package/src/helpers/getWeekdays.ts +29 -0
- package/src/helpers/getWeeks.test.ts +30 -0
- package/src/helpers/getWeeks.ts +9 -0
- package/src/helpers/getYearOptions.test.ts +46 -0
- package/src/helpers/getYearOptions.ts +34 -0
- package/src/helpers/index.ts +2 -0
- package/src/helpers/startOfBroadcastWeek.test.ts +24 -0
- package/src/helpers/startOfBroadcastWeek.ts +19 -0
- package/src/helpers/useControlledValue.test.ts +45 -0
- package/src/helpers/useControlledValue.ts +33 -0
- package/src/index.ts +15 -0
- package/src/jalali.tsx +2 -0
- package/src/labels/index.ts +12 -0
- package/src/labels/labelDayButton.test.ts +41 -0
- package/src/labels/labelDayButton.ts +31 -0
- package/src/labels/labelGrid.test.ts +7 -0
- package/src/labels/labelGrid.ts +23 -0
- package/src/labels/labelGridcell.test.ts +7 -0
- package/src/labels/labelGridcell.ts +22 -0
- package/src/labels/labelMonthDropdown.test.ts +5 -0
- package/src/labels/labelMonthDropdown.ts +12 -0
- package/src/labels/labelNav.test.ts +5 -0
- package/src/labels/labelNav.ts +10 -0
- package/src/labels/labelNext.test.ts +5 -0
- package/src/labels/labelNext.ts +13 -0
- package/src/labels/labelPrevious.test.ts +5 -0
- package/src/labels/labelPrevious.ts +13 -0
- package/src/labels/labelWeekNumber.test.ts +5 -0
- package/src/labels/labelWeekNumber.ts +15 -0
- package/src/labels/labelWeekNumberHeader.test.ts +5 -0
- package/src/labels/labelWeekNumberHeader.ts +12 -0
- package/src/labels/labelWeekday.test.ts +15 -0
- package/src/labels/labelWeekday.ts +16 -0
- package/src/labels/labelYearDropdown.test.ts +5 -0
- package/src/labels/labelYearDropdown.ts +12 -0
- package/src/locale.ts +1 -0
- package/src/persian.tsx +86 -0
- package/src/selection/useMulti.test.tsx +41 -0
- package/src/selection/useMulti.tsx +74 -0
- package/src/selection/useRange.test.tsx +154 -0
- package/src/selection/useRange.tsx +73 -0
- package/src/selection/useSingle.test.tsx +38 -0
- package/src/selection/useSingle.tsx +69 -0
- package/src/types/deprecated.ts +230 -0
- package/src/types/index.ts +4 -0
- package/src/types/props.test.tsx +71 -0
- package/src/types/props.ts +675 -0
- package/src/types/selection.ts +57 -0
- package/src/types/shared.ts +442 -0
- package/src/useAnimation.test.tsx +190 -0
- package/src/useAnimation.ts +236 -0
- package/src/useCalendar.ts +178 -0
- package/src/useDayPicker.test.tsx +142 -0
- package/src/useDayPicker.ts +93 -0
- package/src/useFocus.ts +87 -0
- package/src/useGetModifiers.test.tsx +154 -0
- package/src/useGetModifiers.tsx +122 -0
- package/src/useSelection.ts +26 -0
- package/src/utc.tsx +10 -0
- package/src/utils/addToRange.test.ts +117 -0
- package/src/utils/addToRange.ts +87 -0
- package/src/utils/dateMatchModifiers.test.ts +120 -0
- package/src/utils/dateMatchModifiers.ts +88 -0
- package/src/utils/index.ts +7 -0
- package/src/utils/rangeContainsDayOfWeek.test.ts +48 -0
- package/src/utils/rangeContainsDayOfWeek.ts +35 -0
- package/src/utils/rangeContainsModifiers.test.ts +230 -0
- package/src/utils/rangeContainsModifiers.ts +125 -0
- package/src/utils/rangeIncludesDate.test.ts +46 -0
- package/src/utils/rangeIncludesDate.ts +43 -0
- package/src/utils/rangeOverlaps.test.ts +60 -0
- package/src/utils/rangeOverlaps.ts +22 -0
- package/src/utils/typeguards.test.ts +83 -0
- package/src/utils/typeguards.ts +70 -0
package/src/useFocus.ts
ADDED
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { useState } from "react";
|
|
2
|
+
|
|
3
|
+
import type { CalendarDay, DateLib } from "./classes/index.js";
|
|
4
|
+
import { calculateFocusTarget } from "./helpers/calculateFocusTarget.js";
|
|
5
|
+
import { getNextFocus } from "./helpers/getNextFocus.js";
|
|
6
|
+
import type {
|
|
7
|
+
MoveFocusBy,
|
|
8
|
+
MoveFocusDir,
|
|
9
|
+
DayPickerProps,
|
|
10
|
+
Modifiers
|
|
11
|
+
} from "./types/index.js";
|
|
12
|
+
import { Calendar } from "./useCalendar.js";
|
|
13
|
+
|
|
14
|
+
export type UseFocus = {
|
|
15
|
+
/** The date that is currently focused. */
|
|
16
|
+
focused: CalendarDay | undefined;
|
|
17
|
+
|
|
18
|
+
/** Check if the given day is the focus target when entering the calendar. */
|
|
19
|
+
isFocusTarget: (day: CalendarDay) => boolean;
|
|
20
|
+
|
|
21
|
+
/** Focus the given day. */
|
|
22
|
+
setFocused: (day: CalendarDay | undefined) => void;
|
|
23
|
+
|
|
24
|
+
/** Blur the focused day. */
|
|
25
|
+
blur: () => void;
|
|
26
|
+
|
|
27
|
+
/** Move the current focus to the next day according to the given direction. */
|
|
28
|
+
moveFocus: (moveBy: MoveFocusBy, moveDir: MoveFocusDir) => void;
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
/** @private */
|
|
32
|
+
export function useFocus<T extends DayPickerProps>(
|
|
33
|
+
props: T,
|
|
34
|
+
calendar: Calendar,
|
|
35
|
+
getModifiers: (day: CalendarDay) => Modifiers,
|
|
36
|
+
isSelected: (date: Date) => boolean,
|
|
37
|
+
dateLib: DateLib
|
|
38
|
+
): UseFocus {
|
|
39
|
+
const { autoFocus } = props;
|
|
40
|
+
const [lastFocused, setLastFocused] = useState<CalendarDay | undefined>();
|
|
41
|
+
|
|
42
|
+
const focusTarget = calculateFocusTarget(
|
|
43
|
+
calendar.days,
|
|
44
|
+
getModifiers,
|
|
45
|
+
isSelected || (() => false),
|
|
46
|
+
lastFocused
|
|
47
|
+
);
|
|
48
|
+
const [focusedDay, setFocused] = useState<CalendarDay | undefined>(
|
|
49
|
+
autoFocus ? focusTarget : undefined
|
|
50
|
+
);
|
|
51
|
+
|
|
52
|
+
const blur = () => {
|
|
53
|
+
setLastFocused(focusedDay);
|
|
54
|
+
setFocused(undefined);
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
const moveFocus = (moveBy: MoveFocusBy, moveDir: MoveFocusDir) => {
|
|
58
|
+
if (!focusedDay) return;
|
|
59
|
+
const nextFocus = getNextFocus(
|
|
60
|
+
moveBy,
|
|
61
|
+
moveDir,
|
|
62
|
+
focusedDay,
|
|
63
|
+
calendar.navStart,
|
|
64
|
+
calendar.navEnd,
|
|
65
|
+
props,
|
|
66
|
+
dateLib
|
|
67
|
+
);
|
|
68
|
+
if (!nextFocus) return;
|
|
69
|
+
|
|
70
|
+
calendar.goToDay(nextFocus);
|
|
71
|
+
setFocused(nextFocus);
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
const isFocusTarget = (day: CalendarDay) => {
|
|
75
|
+
return Boolean(focusTarget?.isEqualTo(day));
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
const useFocus: UseFocus = {
|
|
79
|
+
isFocusTarget,
|
|
80
|
+
setFocused,
|
|
81
|
+
focused: focusedDay,
|
|
82
|
+
blur,
|
|
83
|
+
moveFocus
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
return useFocus;
|
|
87
|
+
}
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
import { DayFlag } from "./UI";
|
|
2
|
+
import { CalendarDay, defaultDateLib } from "./classes/index";
|
|
3
|
+
import { useGetModifiers } from "./useGetModifiers";
|
|
4
|
+
|
|
5
|
+
const dateLib = defaultDateLib;
|
|
6
|
+
|
|
7
|
+
const displayedMonth = new Date(2022, 10, 1);
|
|
8
|
+
|
|
9
|
+
const date1 = new Date(2022, 9, 30);
|
|
10
|
+
const date2 = new Date(2022, 10, 10);
|
|
11
|
+
const date3 = new Date(2022, 10, 11);
|
|
12
|
+
const date4 = new Date(2022, 10, 12);
|
|
13
|
+
const date5 = new Date(2022, 10, 13);
|
|
14
|
+
const date6 = new Date(2022, 10, 14);
|
|
15
|
+
const date7 = new Date(2022, 11, 1);
|
|
16
|
+
|
|
17
|
+
const day1 = new CalendarDay(date1, displayedMonth);
|
|
18
|
+
const day2 = new CalendarDay(date2, displayedMonth);
|
|
19
|
+
const day3 = new CalendarDay(date3, displayedMonth);
|
|
20
|
+
const day4 = new CalendarDay(date4, displayedMonth);
|
|
21
|
+
const day5 = new CalendarDay(date5, displayedMonth);
|
|
22
|
+
const day6 = new CalendarDay(date6, displayedMonth);
|
|
23
|
+
const day7 = new CalendarDay(date7, displayedMonth);
|
|
24
|
+
|
|
25
|
+
const days: CalendarDay[] = [day1, day2, day3, day4, day5, day6, day7];
|
|
26
|
+
|
|
27
|
+
const props = {
|
|
28
|
+
disabled: [date2],
|
|
29
|
+
hidden: [date3],
|
|
30
|
+
modifiers: {
|
|
31
|
+
custom: [date4],
|
|
32
|
+
selected: [date6]
|
|
33
|
+
},
|
|
34
|
+
selected: date7,
|
|
35
|
+
showOutsideDays: true,
|
|
36
|
+
today: date5,
|
|
37
|
+
timeZone: "UTC"
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
describe("useGetModifiers", () => {
|
|
41
|
+
describe("default props", () => {
|
|
42
|
+
// eslint-disable-next-line react-hooks/rules-of-hooks
|
|
43
|
+
const getModifiers = useGetModifiers(days, props, dateLib);
|
|
44
|
+
|
|
45
|
+
test("return the modifiers for a given day", () => {
|
|
46
|
+
const modifiers = getModifiers(day2);
|
|
47
|
+
|
|
48
|
+
expect(modifiers[DayFlag.focused]).toBe(false);
|
|
49
|
+
expect(modifiers[DayFlag.disabled]).toBe(true);
|
|
50
|
+
expect(modifiers[DayFlag.hidden]).toBe(false);
|
|
51
|
+
expect(modifiers[DayFlag.outside]).toBe(false);
|
|
52
|
+
expect(modifiers[DayFlag.today]).toBe(false);
|
|
53
|
+
expect(modifiers.custom).toBe(false);
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
test("return the custom modifiers for a given day", () => {
|
|
57
|
+
const modifiers = getModifiers(day4);
|
|
58
|
+
expect(modifiers.custom).toBe(true);
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
test("return the custom `selected` modifier for a given day", () => {
|
|
62
|
+
const modifiers = getModifiers(day6);
|
|
63
|
+
expect(modifiers.selected).toBe(true);
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
test("return the today modifier for a given day", () => {
|
|
67
|
+
const modifiers = getModifiers(day5);
|
|
68
|
+
|
|
69
|
+
expect(modifiers[DayFlag.today]).toBe(true);
|
|
70
|
+
expect(modifiers[DayFlag.focused]).toBe(false);
|
|
71
|
+
expect(modifiers[DayFlag.disabled]).toBe(false);
|
|
72
|
+
expect(modifiers[DayFlag.outside]).toBe(false);
|
|
73
|
+
expect(modifiers[DayFlag.hidden]).toBe(false);
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
test("return the hidden modifier for a given day", () => {
|
|
77
|
+
const modifiers = getModifiers(day3);
|
|
78
|
+
|
|
79
|
+
expect(modifiers[DayFlag.hidden]).toBe(true);
|
|
80
|
+
expect(modifiers[DayFlag.focused]).toBe(false);
|
|
81
|
+
expect(modifiers[DayFlag.disabled]).toBe(false);
|
|
82
|
+
expect(modifiers[DayFlag.outside]).toBe(false);
|
|
83
|
+
expect(modifiers[DayFlag.today]).toBe(false);
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
test("return the modifiers for a given day before the displayed month", () => {
|
|
87
|
+
const modifiers = getModifiers(day1);
|
|
88
|
+
|
|
89
|
+
expect(modifiers[DayFlag.focused]).toBe(false);
|
|
90
|
+
expect(modifiers[DayFlag.disabled]).toBe(false);
|
|
91
|
+
expect(modifiers[DayFlag.hidden]).toBe(false);
|
|
92
|
+
expect(modifiers[DayFlag.outside]).toBe(true);
|
|
93
|
+
expect(modifiers[DayFlag.today]).toBe(false);
|
|
94
|
+
expect(modifiers.selected).toBe(false);
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
test("return the modifiers for a given day after the displayed month", () => {
|
|
98
|
+
const modifiers = getModifiers(day7);
|
|
99
|
+
|
|
100
|
+
expect(modifiers[DayFlag.focused]).toBe(false);
|
|
101
|
+
expect(modifiers[DayFlag.disabled]).toBe(false);
|
|
102
|
+
expect(modifiers[DayFlag.hidden]).toBe(false);
|
|
103
|
+
expect(modifiers[DayFlag.outside]).toBe(true);
|
|
104
|
+
expect(modifiers[DayFlag.today]).toBe(false);
|
|
105
|
+
expect(modifiers.selected).toBe(false);
|
|
106
|
+
});
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
describe("with startMonth and endMonth props", () => {
|
|
110
|
+
const startMonth = new Date(displayedMonth);
|
|
111
|
+
startMonth.setDate(30);
|
|
112
|
+
const endMonth = new Date(displayedMonth);
|
|
113
|
+
endMonth.setDate(1);
|
|
114
|
+
|
|
115
|
+
// eslint-disable-next-line react-hooks/rules-of-hooks
|
|
116
|
+
const getModifiers = useGetModifiers(
|
|
117
|
+
days,
|
|
118
|
+
{ ...props, startMonth, endMonth },
|
|
119
|
+
dateLib
|
|
120
|
+
);
|
|
121
|
+
test("return the modifiers for a given day", () => {
|
|
122
|
+
const modifiers = getModifiers(day2);
|
|
123
|
+
|
|
124
|
+
expect(modifiers[DayFlag.focused]).toBe(false);
|
|
125
|
+
expect(modifiers[DayFlag.disabled]).toBe(true);
|
|
126
|
+
expect(modifiers[DayFlag.hidden]).toBe(false);
|
|
127
|
+
expect(modifiers[DayFlag.outside]).toBe(false);
|
|
128
|
+
expect(modifiers[DayFlag.today]).toBe(false);
|
|
129
|
+
expect(modifiers.custom).toBe(false);
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
test("return the modifiers for a given day before the displayed month", () => {
|
|
133
|
+
const modifiers = getModifiers(day1);
|
|
134
|
+
|
|
135
|
+
expect(modifiers[DayFlag.focused]).toBe(false);
|
|
136
|
+
expect(modifiers[DayFlag.disabled]).toBe(false);
|
|
137
|
+
expect(modifiers[DayFlag.hidden]).toBe(true);
|
|
138
|
+
expect(modifiers[DayFlag.outside]).toBe(true);
|
|
139
|
+
expect(modifiers[DayFlag.today]).toBe(false);
|
|
140
|
+
expect(modifiers.selected).toBe(false);
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
test("return the modifiers for a given day after the displayed month", () => {
|
|
144
|
+
const modifiers = getModifiers(day7);
|
|
145
|
+
|
|
146
|
+
expect(modifiers[DayFlag.focused]).toBe(false);
|
|
147
|
+
expect(modifiers[DayFlag.disabled]).toBe(false);
|
|
148
|
+
expect(modifiers[DayFlag.hidden]).toBe(true);
|
|
149
|
+
expect(modifiers[DayFlag.outside]).toBe(true);
|
|
150
|
+
expect(modifiers[DayFlag.today]).toBe(false);
|
|
151
|
+
expect(modifiers.selected).toBe(false);
|
|
152
|
+
});
|
|
153
|
+
});
|
|
154
|
+
});
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import { DayFlag } from "./UI.js";
|
|
2
|
+
import type { CalendarDay, DateLib } from "./classes/index.js";
|
|
3
|
+
import type { DayPickerProps, Modifiers } from "./types/index.js";
|
|
4
|
+
import { dateMatchModifiers } from "./utils/dateMatchModifiers.js";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Return a function to get the modifiers for a given day.
|
|
8
|
+
*
|
|
9
|
+
* NOTE: this is not an hook, but a factory for `getModifiers`.
|
|
10
|
+
*
|
|
11
|
+
* @private
|
|
12
|
+
*/
|
|
13
|
+
export function useGetModifiers(
|
|
14
|
+
days: CalendarDay[],
|
|
15
|
+
props: DayPickerProps,
|
|
16
|
+
dateLib: DateLib
|
|
17
|
+
) {
|
|
18
|
+
const {
|
|
19
|
+
disabled,
|
|
20
|
+
hidden,
|
|
21
|
+
modifiers,
|
|
22
|
+
showOutsideDays,
|
|
23
|
+
broadcastCalendar,
|
|
24
|
+
today
|
|
25
|
+
} = props;
|
|
26
|
+
|
|
27
|
+
const {
|
|
28
|
+
isSameDay,
|
|
29
|
+
isSameMonth,
|
|
30
|
+
startOfMonth,
|
|
31
|
+
isBefore,
|
|
32
|
+
endOfMonth,
|
|
33
|
+
isAfter
|
|
34
|
+
} = dateLib;
|
|
35
|
+
|
|
36
|
+
const startMonth = props.startMonth && startOfMonth(props.startMonth);
|
|
37
|
+
const endMonth = props.endMonth && endOfMonth(props.endMonth);
|
|
38
|
+
|
|
39
|
+
const internalModifiersMap: Record<DayFlag, CalendarDay[]> = {
|
|
40
|
+
[DayFlag.focused]: [],
|
|
41
|
+
[DayFlag.outside]: [],
|
|
42
|
+
[DayFlag.disabled]: [],
|
|
43
|
+
[DayFlag.hidden]: [],
|
|
44
|
+
[DayFlag.today]: []
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
const customModifiersMap: Record<string, CalendarDay[]> = {};
|
|
48
|
+
|
|
49
|
+
for (const day of days) {
|
|
50
|
+
const { date, displayMonth } = day;
|
|
51
|
+
|
|
52
|
+
const isOutside = Boolean(displayMonth && !isSameMonth(date, displayMonth));
|
|
53
|
+
|
|
54
|
+
const isBeforeStartMonth = Boolean(
|
|
55
|
+
startMonth && isBefore(date, startMonth)
|
|
56
|
+
);
|
|
57
|
+
|
|
58
|
+
const isAfterEndMonth = Boolean(endMonth && isAfter(date, endMonth));
|
|
59
|
+
|
|
60
|
+
const isDisabled = Boolean(
|
|
61
|
+
disabled && dateMatchModifiers(date, disabled, dateLib)
|
|
62
|
+
);
|
|
63
|
+
|
|
64
|
+
const isHidden =
|
|
65
|
+
Boolean(hidden && dateMatchModifiers(date, hidden, dateLib)) ||
|
|
66
|
+
isBeforeStartMonth ||
|
|
67
|
+
isAfterEndMonth ||
|
|
68
|
+
// Broadcast calendar will show outside days as default
|
|
69
|
+
(!broadcastCalendar && !showOutsideDays && isOutside) ||
|
|
70
|
+
(broadcastCalendar && showOutsideDays === false && isOutside);
|
|
71
|
+
|
|
72
|
+
const isToday = isSameDay(date, today ?? dateLib.today());
|
|
73
|
+
|
|
74
|
+
if (isOutside) internalModifiersMap.outside.push(day);
|
|
75
|
+
if (isDisabled) internalModifiersMap.disabled.push(day);
|
|
76
|
+
if (isHidden) internalModifiersMap.hidden.push(day);
|
|
77
|
+
if (isToday) internalModifiersMap.today.push(day);
|
|
78
|
+
|
|
79
|
+
// Add custom modifiers
|
|
80
|
+
if (modifiers) {
|
|
81
|
+
Object.keys(modifiers).forEach((name) => {
|
|
82
|
+
const modifierValue = modifiers?.[name];
|
|
83
|
+
const isMatch = modifierValue
|
|
84
|
+
? dateMatchModifiers(date, modifierValue, dateLib)
|
|
85
|
+
: false;
|
|
86
|
+
if (!isMatch) return;
|
|
87
|
+
if (customModifiersMap[name]) {
|
|
88
|
+
customModifiersMap[name].push(day);
|
|
89
|
+
} else {
|
|
90
|
+
customModifiersMap[name] = [day];
|
|
91
|
+
}
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
return (day: CalendarDay): Modifiers => {
|
|
97
|
+
// Initialize all the modifiers to false
|
|
98
|
+
const dayFlags: Record<DayFlag, boolean> = {
|
|
99
|
+
[DayFlag.focused]: false,
|
|
100
|
+
[DayFlag.disabled]: false,
|
|
101
|
+
[DayFlag.hidden]: false,
|
|
102
|
+
[DayFlag.outside]: false,
|
|
103
|
+
[DayFlag.today]: false
|
|
104
|
+
};
|
|
105
|
+
const customModifiers: Modifiers = {};
|
|
106
|
+
|
|
107
|
+
// Find the modifiers for the given day
|
|
108
|
+
for (const name in internalModifiersMap) {
|
|
109
|
+
const days = internalModifiersMap[name as DayFlag];
|
|
110
|
+
dayFlags[name as DayFlag] = days.some((d) => d === day);
|
|
111
|
+
}
|
|
112
|
+
for (const name in customModifiersMap) {
|
|
113
|
+
customModifiers[name] = customModifiersMap[name].some((d) => d === day);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
return {
|
|
117
|
+
...dayFlags,
|
|
118
|
+
// custom modifiers should override all the previous ones
|
|
119
|
+
...customModifiers
|
|
120
|
+
};
|
|
121
|
+
};
|
|
122
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { type DateLib } from "./classes/DateLib.js";
|
|
2
|
+
import { useMulti } from "./selection/useMulti.js";
|
|
3
|
+
import { useRange } from "./selection/useRange.js";
|
|
4
|
+
import { useSingle } from "./selection/useSingle.js";
|
|
5
|
+
import type { DayPickerProps } from "./types/index.js";
|
|
6
|
+
import { Selection } from "./types/selection.js";
|
|
7
|
+
|
|
8
|
+
export function useSelection<T extends DayPickerProps>(
|
|
9
|
+
props: T,
|
|
10
|
+
dateLib: DateLib
|
|
11
|
+
): Selection<T> | undefined {
|
|
12
|
+
const single = useSingle(props, dateLib);
|
|
13
|
+
const multi = useMulti(props, dateLib);
|
|
14
|
+
const range = useRange(props, dateLib);
|
|
15
|
+
|
|
16
|
+
switch (props.mode) {
|
|
17
|
+
case "single":
|
|
18
|
+
return single;
|
|
19
|
+
case "multiple":
|
|
20
|
+
return multi;
|
|
21
|
+
case "range":
|
|
22
|
+
return range;
|
|
23
|
+
default:
|
|
24
|
+
return undefined;
|
|
25
|
+
}
|
|
26
|
+
}
|
package/src/utc.tsx
ADDED
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import { addToRange } from "./addToRange";
|
|
2
|
+
|
|
3
|
+
describe("addToRange", () => {
|
|
4
|
+
test("add a date to an undefined range", () => {
|
|
5
|
+
const date = new Date(2022, 0, 1);
|
|
6
|
+
const range = addToRange(date, undefined);
|
|
7
|
+
expect(range).toEqual({ from: date, to: date });
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
test("add a date to an empty range", () => {
|
|
11
|
+
const date = new Date(2022, 0, 1);
|
|
12
|
+
const range = addToRange(date, { from: undefined, to: undefined });
|
|
13
|
+
expect(range).toEqual({ from: date, to: date });
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
test("add a date to an incomplete range with same start date", () => {
|
|
17
|
+
const date = new Date(2022, 0, 1);
|
|
18
|
+
const range = addToRange(date, { from: date, to: undefined });
|
|
19
|
+
expect(range).toEqual(undefined);
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
test("add a date to an incomplete range with earlier date", () => {
|
|
23
|
+
const from = new Date(2022, 0, 1);
|
|
24
|
+
const earlierDate = new Date(2021, 11, 31);
|
|
25
|
+
const range = addToRange(earlierDate, { from: from, to: undefined });
|
|
26
|
+
expect(range).toEqual({ from: earlierDate, to: from });
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
test("add a date to an incomplete range with later date", () => {
|
|
30
|
+
const from = new Date(2022, 0, 1);
|
|
31
|
+
const date = new Date(2022, 0, 2);
|
|
32
|
+
const range = addToRange(date, { from: from, to: undefined });
|
|
33
|
+
expect(range).toEqual({ from: from, to: date });
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
test("add a date to a complete range with same start and end date", () => {
|
|
37
|
+
const date = new Date(2022, 0, 1);
|
|
38
|
+
const from = date;
|
|
39
|
+
const to = date;
|
|
40
|
+
const range = addToRange(date, { from, to }, 0, 0, false);
|
|
41
|
+
expect(range).toEqual(undefined);
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
test("add a date to a complete range with same start date", () => {
|
|
45
|
+
const date = new Date(2022, 0, 1);
|
|
46
|
+
const to = new Date(2022, 0, 2);
|
|
47
|
+
const range = addToRange(date, { from: date, to: to });
|
|
48
|
+
expect(range).toEqual({ from: date, to: date });
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
test("add a date to a complete range with same end date", () => {
|
|
52
|
+
const date = new Date(2022, 0, 2);
|
|
53
|
+
const from = new Date(2022, 0, 1);
|
|
54
|
+
const range = addToRange(date, { from: from, to: date });
|
|
55
|
+
expect(range).toEqual({ from: date, to: date });
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
test("add a date when inside the range", () => {
|
|
59
|
+
const date = new Date(2022, 0, 1);
|
|
60
|
+
const from = new Date(2021, 11, 31);
|
|
61
|
+
const to = new Date(2022, 0, 2);
|
|
62
|
+
const range = addToRange(date, { from, to });
|
|
63
|
+
expect(range).toEqual({ from, to: date });
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
test("add an earlier date to a complete range", () => {
|
|
67
|
+
const from = new Date(2022, 0, 1);
|
|
68
|
+
const to = new Date(2022, 0, 2);
|
|
69
|
+
const date = new Date(2021, 11, 31);
|
|
70
|
+
const range = addToRange(date, { from, to });
|
|
71
|
+
expect(range).toEqual({ from: date, to: to });
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
test("add a later date to a complete range", () => {
|
|
75
|
+
const date = new Date(2022, 0, 2);
|
|
76
|
+
const from = new Date(2021, 11, 31);
|
|
77
|
+
const to = new Date(2022, 0, 1);
|
|
78
|
+
const range = addToRange(date, { from, to });
|
|
79
|
+
expect(range).toEqual({ from: from, to: date });
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
test("add a date with min > 0", () => {
|
|
83
|
+
const date = new Date(2022, 0, 1);
|
|
84
|
+
const range = addToRange(date, undefined, 1, 0, false);
|
|
85
|
+
expect(range).toEqual({ from: date, to: undefined });
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
test("add a date with max > 0", () => {
|
|
89
|
+
const date = new Date(2022, 0, 1);
|
|
90
|
+
const range = addToRange(date, undefined, 0, 1, false);
|
|
91
|
+
expect(range).toEqual({ from: date, to: date });
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
test("add a date with required set to true", () => {
|
|
95
|
+
const date = new Date(2022, 0, 1);
|
|
96
|
+
const range = addToRange(date, undefined, 0, 0, true);
|
|
97
|
+
expect(range).toEqual({ from: date, to: date });
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
test("when exceeding max, set the start of the range", () => {
|
|
101
|
+
const from = new Date(2022, 0, 1);
|
|
102
|
+
const to = new Date(2022, 0, 2);
|
|
103
|
+
const date = new Date(2022, 0, 4);
|
|
104
|
+
const max = 2;
|
|
105
|
+
const range = addToRange(date, { from, to }, 0, max, false);
|
|
106
|
+
expect(range).toEqual({ from: date, to: undefined });
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
test("when below min, set the start of the range", () => {
|
|
110
|
+
const from = new Date(2021, 11, 20);
|
|
111
|
+
const to = new Date(2022, 0, 2);
|
|
112
|
+
const date = new Date(2021, 11, 21);
|
|
113
|
+
const min = 5;
|
|
114
|
+
const range = addToRange(date, { from, to }, min, 0, false);
|
|
115
|
+
expect(range).toEqual({ from: date, to: undefined });
|
|
116
|
+
});
|
|
117
|
+
});
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { defaultDateLib, type DateLib } from "../classes/DateLib.js";
|
|
2
|
+
import type { DateRange } from "../types/index.js";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Add a day to an existing range.
|
|
6
|
+
*
|
|
7
|
+
* The returned range takes in account the `undefined` values and if the added
|
|
8
|
+
* day is already present in the range.
|
|
9
|
+
*
|
|
10
|
+
* @group Utilities
|
|
11
|
+
*/
|
|
12
|
+
export function addToRange(
|
|
13
|
+
/** The date to add to the range. */
|
|
14
|
+
date: Date,
|
|
15
|
+
/** The range where to add `date`. */
|
|
16
|
+
initialRange: DateRange | undefined,
|
|
17
|
+
min = 0,
|
|
18
|
+
max = 0,
|
|
19
|
+
required = false,
|
|
20
|
+
/** @ignore */
|
|
21
|
+
dateLib: DateLib = defaultDateLib
|
|
22
|
+
): DateRange | undefined {
|
|
23
|
+
const { from, to } = initialRange || {};
|
|
24
|
+
const { isSameDay, isAfter, isBefore } = dateLib;
|
|
25
|
+
|
|
26
|
+
let range: DateRange | undefined;
|
|
27
|
+
|
|
28
|
+
if (!from && !to) {
|
|
29
|
+
// the range is empty, add the date
|
|
30
|
+
range = { from: date, to: min > 0 ? undefined : date };
|
|
31
|
+
} else if (from && !to) {
|
|
32
|
+
// adding date to an incomplete range
|
|
33
|
+
if (isSameDay(from, date)) {
|
|
34
|
+
// adding a date equal to the start of the range
|
|
35
|
+
if (required) {
|
|
36
|
+
range = { from, to: undefined };
|
|
37
|
+
} else {
|
|
38
|
+
range = undefined;
|
|
39
|
+
}
|
|
40
|
+
} else if (isBefore(date, from)) {
|
|
41
|
+
// adding a date before the start of the range
|
|
42
|
+
range = { from: date, to: from };
|
|
43
|
+
} else {
|
|
44
|
+
// adding a date after the start of the range
|
|
45
|
+
range = { from, to: date };
|
|
46
|
+
}
|
|
47
|
+
} else if (from && to) {
|
|
48
|
+
// adding date to a complete range
|
|
49
|
+
if (isSameDay(from, date) && isSameDay(to, date)) {
|
|
50
|
+
// adding a date that is equal to both start and end of the range
|
|
51
|
+
if (required) {
|
|
52
|
+
range = { from, to };
|
|
53
|
+
} else {
|
|
54
|
+
range = undefined;
|
|
55
|
+
}
|
|
56
|
+
} else if (isSameDay(from, date)) {
|
|
57
|
+
// adding a date equal to the the start of the range
|
|
58
|
+
range = { from, to: min > 0 ? undefined : date };
|
|
59
|
+
} else if (isSameDay(to, date)) {
|
|
60
|
+
// adding a dare equal to the end of the range
|
|
61
|
+
range = { from: date, to: min > 0 ? undefined : date };
|
|
62
|
+
} else if (isBefore(date, from)) {
|
|
63
|
+
// adding a date before the start of the range
|
|
64
|
+
range = { from: date, to: to };
|
|
65
|
+
} else if (isAfter(date, from)) {
|
|
66
|
+
// adding a date after the start of the range
|
|
67
|
+
range = { from, to: date };
|
|
68
|
+
} else if (isAfter(date, to)) {
|
|
69
|
+
// adding a date after the end of the range
|
|
70
|
+
range = { from, to: date };
|
|
71
|
+
} else {
|
|
72
|
+
throw new Error("Invalid range");
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// check for min / max
|
|
77
|
+
if (range?.from && range?.to) {
|
|
78
|
+
const diff = dateLib.differenceInCalendarDays(range.to, range.from);
|
|
79
|
+
if (max > 0 && diff > max) {
|
|
80
|
+
range = { from: date, to: undefined };
|
|
81
|
+
} else if (min > 1 && diff < min) {
|
|
82
|
+
range = { from: date, to: undefined };
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
return range;
|
|
87
|
+
}
|