react-day-picker 8.0.3 → 8.0.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/package.json +13 -11
- package/src/DayPicker.tsx +113 -0
- package/src/components/Button/Button.test.tsx +47 -0
- package/src/components/Button/Button.tsx +36 -0
- package/src/components/Button/index.ts +1 -0
- package/src/components/Caption/Caption.test.tsx +86 -0
- package/src/components/Caption/Caption.tsx +54 -0
- package/src/components/Caption/index.ts +1 -0
- package/src/components/CaptionDropdowns/CaptionDropdowns.test.tsx +123 -0
- package/src/components/CaptionDropdowns/CaptionDropdowns.tsx +43 -0
- package/src/components/CaptionDropdowns/index.ts +1 -0
- package/src/components/CaptionLabel/CaptionLabel.test.tsx +29 -0
- package/src/components/CaptionLabel/CaptionLabel.tsx +32 -0
- package/src/components/CaptionLabel/index.ts +1 -0
- package/src/components/CaptionNavigation/CaptionNavigation.test.tsx +172 -0
- package/src/components/CaptionNavigation/CaptionNavigation.tsx +63 -0
- package/src/components/CaptionNavigation/index.ts +1 -0
- package/src/components/Day/Day.test.tsx +84 -0
- package/src/components/Day/Day.tsx +30 -0
- package/src/components/Day/index.ts +1 -0
- package/src/components/DayContent/DayContent.test.tsx +51 -0
- package/src/components/DayContent/DayContent.tsx +36 -0
- package/src/components/DayContent/index.ts +1 -0
- package/src/components/Dropdown/Dropdown.test.tsx +73 -0
- package/src/components/Dropdown/Dropdown.tsx +56 -0
- package/src/components/Dropdown/index.ts +1 -0
- package/src/components/Footer/Footer.test.tsx +29 -0
- package/src/components/Footer/Footer.tsx +20 -0
- package/src/components/Footer/index.ts +1 -0
- package/src/components/Head/Head.test.tsx +117 -0
- package/src/components/Head/Head.tsx +51 -0
- package/src/components/Head/index.ts +1 -0
- package/src/components/Head/utils/getWeekdays.test.ts +36 -0
- package/src/components/Head/utils/getWeekdays.ts +22 -0
- package/src/components/Head/utils/index.ts +1 -0
- package/src/components/IconDropdown/IconDropdown.test.tsx +20 -0
- package/src/components/IconDropdown/IconDropdown.tsx +24 -0
- package/src/components/IconDropdown/index.ts +1 -0
- package/src/components/IconLeft/IconLeft.test.tsx +20 -0
- package/src/components/IconLeft/IconLeft.tsx +18 -0
- package/src/components/IconLeft/index.ts +1 -0
- package/src/components/IconRight/IconRight.test.tsx +20 -0
- package/src/components/IconRight/IconRight.tsx +17 -0
- package/src/components/IconRight/index.ts +1 -0
- package/src/components/Month/Month.test.tsx +216 -0
- package/src/components/Month/Month.tsx +53 -0
- package/src/components/Month/index.ts +1 -0
- package/src/components/MonthsDropdown/MonthsDropdown.test.tsx +99 -0
- package/src/components/MonthsDropdown/MonthsDropdown.tsx +75 -0
- package/src/components/MonthsDropdown/index.ts +1 -0
- package/src/components/Navigation/Navigation.test.tsx +129 -0
- package/src/components/Navigation/Navigation.tsx +102 -0
- package/src/components/Navigation/index.ts +1 -0
- package/src/components/Root/Root.test.tsx +123 -0
- package/src/components/Root/Root.tsx +58 -0
- package/src/components/Root/index.ts +1 -0
- package/src/components/Row/Row.test.tsx +69 -0
- package/src/components/Row/Row.tsx +51 -0
- package/src/components/Row/index.ts +1 -0
- package/src/components/Table/Table.test.tsx +42 -0
- package/src/components/Table/Table.tsx +60 -0
- package/src/components/Table/__snapshots__/Table.test.tsx.snap +1453 -0
- package/src/components/Table/index.ts +1 -0
- package/src/components/Table/utils/daysToMonthWeeks.ts +47 -0
- package/src/components/Table/utils/getMonthWeeks.test.ts +68 -0
- package/src/components/Table/utils/getMonthWeeks.ts +55 -0
- package/src/components/WeekNumber/WeekNumber.test.tsx +46 -0
- package/src/components/WeekNumber/WeekNumber.tsx +58 -0
- package/src/components/WeekNumber/__snapshots__/WeekNumber.test.tsx.snap +11 -0
- package/src/components/WeekNumber/index.ts +1 -0
- package/src/components/YearsDropdown/YearsDropdown.test.tsx +98 -0
- package/src/components/YearsDropdown/YearsDropdown.tsx +76 -0
- package/src/components/YearsDropdown/index.ts +1 -0
- package/src/contexts/DayPicker/DayPickerContext.tsx +156 -0
- package/src/contexts/DayPicker/defaultClassNames.ts +58 -0
- package/src/contexts/DayPicker/defaultContextValue.ts +37 -0
- package/src/contexts/DayPicker/formatters/formatCaption.test.ts +15 -0
- package/src/contexts/DayPicker/formatters/formatCaption.ts +12 -0
- package/src/contexts/DayPicker/formatters/formatDay.test.ts +7 -0
- package/src/contexts/DayPicker/formatters/formatDay.ts +9 -0
- package/src/contexts/DayPicker/formatters/formatMonthCaption.test.ts +15 -0
- package/src/contexts/DayPicker/formatters/formatMonthCaption.ts +12 -0
- package/src/contexts/DayPicker/formatters/formatWeekNumber.test.ts +5 -0
- package/src/contexts/DayPicker/formatters/formatWeekNumber.ts +6 -0
- package/src/contexts/DayPicker/formatters/formatWeekdayName.test.ts +15 -0
- package/src/contexts/DayPicker/formatters/formatWeekdayName.ts +12 -0
- package/src/contexts/DayPicker/formatters/formatYearCaption.test.ts +7 -0
- package/src/contexts/DayPicker/formatters/formatYearCaption.ts +11 -0
- package/src/contexts/DayPicker/formatters/index.ts +6 -0
- package/src/contexts/DayPicker/index.ts +2 -0
- package/src/contexts/DayPicker/labels/index.ts +7 -0
- package/src/contexts/DayPicker/labels/labelDay.test.ts +7 -0
- package/src/contexts/DayPicker/labels/labelDay.ts +10 -0
- package/src/contexts/DayPicker/labels/labelMonthDropdown.test.ts +5 -0
- package/src/contexts/DayPicker/labels/labelMonthDropdown.ts +6 -0
- package/src/contexts/DayPicker/labels/labelNext.test.ts +5 -0
- package/src/contexts/DayPicker/labels/labelNext.ts +8 -0
- package/src/contexts/DayPicker/labels/labelPrevious.test.ts +5 -0
- package/src/contexts/DayPicker/labels/labelPrevious.ts +8 -0
- package/src/contexts/DayPicker/labels/labelWeekNumber.test.ts +5 -0
- package/src/contexts/DayPicker/labels/labelWeekNumber.ts +8 -0
- package/src/contexts/DayPicker/labels/labelWeekday.test.ts +15 -0
- package/src/contexts/DayPicker/labels/labelWeekday.ts +10 -0
- package/src/contexts/DayPicker/labels/labelYearDropdown.test.ts +5 -0
- package/src/contexts/DayPicker/labels/labelYearDropdown.ts +6 -0
- package/src/contexts/DayPicker/useDayPicker.test.ts +297 -0
- package/src/contexts/DayPicker/useDayPicker.ts +17 -0
- package/src/contexts/DayPicker/utils/index.ts +1 -0
- package/src/contexts/DayPicker/utils/parseFromToProps.test.ts +47 -0
- package/src/contexts/DayPicker/utils/parseFromToProps.ts +32 -0
- package/src/contexts/Focus/FocusContext.tsx +174 -0
- package/src/contexts/Focus/index.ts +2 -0
- package/src/contexts/Focus/useFocusContext.test.ts +183 -0
- package/src/contexts/Focus/useFocusContext.ts +12 -0
- package/src/contexts/Focus/utils/getInitialFocusTarget.test.tsx +12 -0
- package/src/contexts/Focus/utils/getInitialFocusTarget.tsx +44 -0
- package/src/contexts/Modifiers/ModifiersContext.tsx +44 -0
- package/src/contexts/Modifiers/index.ts +2 -0
- package/src/contexts/Modifiers/useModifiers.test.ts +46 -0
- package/src/contexts/Modifiers/useModifiers.ts +17 -0
- package/src/contexts/Modifiers/utils/getActiveModifiers.test.ts +53 -0
- package/src/contexts/Modifiers/utils/getActiveModifiers.ts +33 -0
- package/src/contexts/Modifiers/utils/getCustomModifiers.test.ts +14 -0
- package/src/contexts/Modifiers/utils/getCustomModifiers.ts +14 -0
- package/src/contexts/Modifiers/utils/getInternalModifiers.test.ts +146 -0
- package/src/contexts/Modifiers/utils/getInternalModifiers.ts +58 -0
- package/src/contexts/Modifiers/utils/isDateInRange.test.ts +28 -0
- package/src/contexts/Modifiers/utils/isDateInRange.ts +27 -0
- package/src/contexts/Modifiers/utils/isMatch.test.ts +92 -0
- package/src/contexts/Modifiers/utils/isMatch.ts +76 -0
- package/src/contexts/Modifiers/utils/matcherToArray.test.ts +22 -0
- package/src/contexts/Modifiers/utils/matcherToArray.ts +14 -0
- package/src/contexts/Navigation/NavigationContext.tsx +84 -0
- package/src/contexts/Navigation/index.ts +2 -0
- package/src/contexts/Navigation/useNavigation.test.ts +126 -0
- package/src/contexts/Navigation/useNavigation.ts +12 -0
- package/src/contexts/Navigation/useNavigationState.test.ts +36 -0
- package/src/contexts/Navigation/useNavigationState.ts +25 -0
- package/src/contexts/Navigation/utils/getDisplayMonths.ts +31 -0
- package/src/contexts/Navigation/utils/getInitialMonth.test.ts +56 -0
- package/src/contexts/Navigation/utils/getInitialMonth.ts +24 -0
- package/src/contexts/Navigation/utils/getNextMonth.test.ts +75 -0
- package/src/contexts/Navigation/utils/getNextMonth.ts +45 -0
- package/src/contexts/Navigation/utils/getPreviousMonth.test.ts +55 -0
- package/src/contexts/Navigation/utils/getPreviousMonth.ts +44 -0
- package/src/contexts/RootProvider.tsx +37 -0
- package/src/contexts/SelectMultiple/SelectMultipleContext.tsx +135 -0
- package/src/contexts/SelectMultiple/index.ts +2 -0
- package/src/contexts/SelectMultiple/useSelectMultiple.test.ts +191 -0
- package/src/contexts/SelectMultiple/useSelectMultiple.ts +17 -0
- package/src/contexts/SelectRange/SelectRangeContext.tsx +158 -0
- package/src/contexts/SelectRange/index.ts +2 -0
- package/src/contexts/SelectRange/useSelectRange.test.ts +282 -0
- package/src/contexts/SelectRange/useSelectRange.ts +15 -0
- package/src/contexts/SelectRange/utils/addToRange.test.ts +119 -0
- package/src/contexts/SelectRange/utils/addToRange.ts +43 -0
- package/src/contexts/SelectSingle/SelectSingleContext.tsx +80 -0
- package/src/contexts/SelectSingle/index.ts +2 -0
- package/src/contexts/SelectSingle/useSelectSingle.test.ts +81 -0
- package/src/contexts/SelectSingle/useSelectSingle.ts +17 -0
- package/src/hooks/useActiveModifiers/index.ts +1 -0
- package/src/hooks/useActiveModifiers/useActiveModifiers.test.tsx +36 -0
- package/src/hooks/useActiveModifiers/useActiveModifiers.tsx +18 -0
- package/src/hooks/useControlledValue/index.ts +1 -0
- package/src/hooks/useControlledValue/useControlledValue.test.ts +68 -0
- package/src/hooks/useControlledValue/useControlledValue.ts +24 -0
- package/src/hooks/useDayEventHandlers/index.ts +1 -0
- package/src/hooks/useDayEventHandlers/useDayEventHandlers.test.tsx +213 -0
- package/src/hooks/useDayEventHandlers/useDayEventHandlers.tsx +195 -0
- package/src/hooks/useDayRender/index.ts +1 -0
- package/src/hooks/useDayRender/useDayRender.test.tsx +304 -0
- package/src/hooks/useDayRender/useDayRender.tsx +123 -0
- package/src/hooks/useDayRender/utils/getDayClassNames.test.ts +63 -0
- package/src/hooks/useDayRender/utils/getDayClassNames.ts +32 -0
- package/src/hooks/useDayRender/utils/getDayStyle.ts +19 -0
- package/src/hooks/useInput/index.ts +1 -0
- package/src/hooks/useInput/useInput.ts +175 -0
- package/src/hooks/useInput/utils/isValidDate.tsx +4 -0
- package/src/hooks/useSelectedDays/index.ts +1 -0
- package/src/hooks/useSelectedDays/useSelectedDays.test.ts +72 -0
- package/src/hooks/useSelectedDays/useSelectedDays.ts +32 -0
- package/src/index.ts +43 -0
- package/src/style.css +310 -0
- package/src/style.css.d.ts +38 -0
- package/src/types/DayPickerBase.ts +267 -0
- package/src/types/DayPickerDefault.ts +15 -0
- package/src/types/DayPickerMultiple.ts +26 -0
- package/src/types/DayPickerRange.ts +27 -0
- package/src/types/DayPickerSingle.ts +24 -0
- package/src/types/EventHandlers.ts +87 -0
- package/src/types/Formatters.ts +29 -0
- package/src/types/Labels.ts +36 -0
- package/src/types/Matchers.ts +106 -0
- package/src/types/Modifiers.ts +62 -0
- package/src/types/Styles.ts +108 -0
- package/tsconfig.json +24 -0
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import isSameMonth from 'date-fns/isSameMonth';
|
|
2
|
+
|
|
3
|
+
import { ActiveModifiers, Modifiers } from 'types/Modifiers';
|
|
4
|
+
|
|
5
|
+
import { isMatch } from './isMatch';
|
|
6
|
+
|
|
7
|
+
/** Return the active modifiers for the given day. */
|
|
8
|
+
export function getActiveModifiers(
|
|
9
|
+
day: Date,
|
|
10
|
+
/** The modifiers to match for the given date. */
|
|
11
|
+
modifiers: Modifiers,
|
|
12
|
+
/** The month where the day is displayed, to add the "outside" modifiers. */
|
|
13
|
+
displayMonth?: Date
|
|
14
|
+
): ActiveModifiers {
|
|
15
|
+
const matchedModifiers = Object.keys(modifiers).reduce(
|
|
16
|
+
(result: string[], key: string): string[] => {
|
|
17
|
+
const modifier = modifiers[key];
|
|
18
|
+
if (isMatch(day, modifier)) {
|
|
19
|
+
result.push(key);
|
|
20
|
+
}
|
|
21
|
+
return result;
|
|
22
|
+
},
|
|
23
|
+
[]
|
|
24
|
+
);
|
|
25
|
+
const activeModifiers: ActiveModifiers = {};
|
|
26
|
+
matchedModifiers.forEach((modifier) => (activeModifiers[modifier] = true));
|
|
27
|
+
|
|
28
|
+
if (displayMonth && !isSameMonth(day, displayMonth)) {
|
|
29
|
+
activeModifiers.outside = true;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
return activeModifiers;
|
|
33
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { DayModifiers } from 'index';
|
|
2
|
+
|
|
3
|
+
import { getCustomModifiers } from './getCustomModifiers';
|
|
4
|
+
|
|
5
|
+
describe('when some modifiers are not an array', () => {
|
|
6
|
+
const date = new Date();
|
|
7
|
+
const dayModifiers: DayModifiers = {
|
|
8
|
+
foo: date
|
|
9
|
+
};
|
|
10
|
+
const result = getCustomModifiers(dayModifiers);
|
|
11
|
+
test('should return as array', () => {
|
|
12
|
+
expect(result.foo).toEqual([date]);
|
|
13
|
+
});
|
|
14
|
+
});
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { CustomModifiers, DayModifiers } from 'types/Modifiers';
|
|
2
|
+
|
|
3
|
+
import { matcherToArray } from './matcherToArray';
|
|
4
|
+
|
|
5
|
+
/** Create CustomModifiers from dayModifiers */
|
|
6
|
+
export function getCustomModifiers(
|
|
7
|
+
dayModifiers: DayModifiers
|
|
8
|
+
): CustomModifiers {
|
|
9
|
+
const customModifiers: CustomModifiers = {};
|
|
10
|
+
Object.entries(dayModifiers).forEach(([modifier, matcher]) => {
|
|
11
|
+
customModifiers[modifier] = matcherToArray(matcher);
|
|
12
|
+
});
|
|
13
|
+
return customModifiers;
|
|
14
|
+
}
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
import { addDays } from 'date-fns';
|
|
2
|
+
|
|
3
|
+
import { DayPickerContextValue } from 'contexts/DayPicker';
|
|
4
|
+
import { getDefaultContextValue } from 'contexts/DayPicker/defaultContextValue';
|
|
5
|
+
import { SelectRangeContextValue } from 'contexts/SelectRange';
|
|
6
|
+
import { InternalModifier, InternalModifiers } from 'types/Modifiers';
|
|
7
|
+
|
|
8
|
+
import { getInternalModifiers } from './getInternalModifiers';
|
|
9
|
+
|
|
10
|
+
const defaultDayPickerContext: DayPickerContextValue = getDefaultContextValue();
|
|
11
|
+
const defaultSelectMultipleContext = {
|
|
12
|
+
selected: undefined,
|
|
13
|
+
modifiers: { disabled: [] }
|
|
14
|
+
};
|
|
15
|
+
const defaultSelectRangeContext = {
|
|
16
|
+
selected: undefined,
|
|
17
|
+
modifiers: {
|
|
18
|
+
disabled: [],
|
|
19
|
+
range_start: [],
|
|
20
|
+
range_end: [],
|
|
21
|
+
range_middle: []
|
|
22
|
+
}
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
const { Selected, Disabled, Hidden, Today, RangeEnd, RangeMiddle, RangeStart } =
|
|
26
|
+
InternalModifier;
|
|
27
|
+
|
|
28
|
+
const internalModifiers = [Selected, Disabled, Hidden, Today];
|
|
29
|
+
test.each(internalModifiers)(
|
|
30
|
+
'should transform to array the modifiers from the "%s" prop',
|
|
31
|
+
(propName) => {
|
|
32
|
+
const value = new Date();
|
|
33
|
+
const modifiers = getInternalModifiers(
|
|
34
|
+
{ ...defaultDayPickerContext, [propName]: value },
|
|
35
|
+
defaultSelectMultipleContext,
|
|
36
|
+
defaultSelectRangeContext
|
|
37
|
+
);
|
|
38
|
+
expect(modifiers[propName]).toStrictEqual([value]);
|
|
39
|
+
}
|
|
40
|
+
);
|
|
41
|
+
|
|
42
|
+
describe('when navigation is limited by "fromDate"', () => {
|
|
43
|
+
const fromDate = new Date();
|
|
44
|
+
const dayPickerContext: DayPickerContextValue = {
|
|
45
|
+
...defaultDayPickerContext,
|
|
46
|
+
fromDate
|
|
47
|
+
};
|
|
48
|
+
test('should add a "before" matcher to the "disabled" modifiers', () => {
|
|
49
|
+
const modifiers = getInternalModifiers(
|
|
50
|
+
dayPickerContext,
|
|
51
|
+
defaultSelectMultipleContext,
|
|
52
|
+
defaultSelectRangeContext
|
|
53
|
+
);
|
|
54
|
+
expect(modifiers.disabled).toStrictEqual([{ before: fromDate }]);
|
|
55
|
+
});
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
describe('when navigation is limited by "toDate"', () => {
|
|
59
|
+
const toDate = new Date();
|
|
60
|
+
const dayPickerContext: DayPickerContextValue = {
|
|
61
|
+
...defaultDayPickerContext,
|
|
62
|
+
toDate
|
|
63
|
+
};
|
|
64
|
+
test('should add an "after" matcher to the "disabled" modifiers', () => {
|
|
65
|
+
const modifiers = getInternalModifiers(
|
|
66
|
+
dayPickerContext,
|
|
67
|
+
defaultSelectMultipleContext,
|
|
68
|
+
defaultSelectRangeContext
|
|
69
|
+
);
|
|
70
|
+
expect(modifiers.disabled).toStrictEqual([{ after: toDate }]);
|
|
71
|
+
});
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
describe('when in multiple select mode', () => {
|
|
75
|
+
const disabledDate = new Date();
|
|
76
|
+
const dayPickerContext: DayPickerContextValue = {
|
|
77
|
+
...defaultDayPickerContext,
|
|
78
|
+
mode: 'multiple'
|
|
79
|
+
};
|
|
80
|
+
const selectMultipleContext = {
|
|
81
|
+
...defaultSelectMultipleContext,
|
|
82
|
+
modifiers: {
|
|
83
|
+
[Disabled]: [disabledDate]
|
|
84
|
+
}
|
|
85
|
+
};
|
|
86
|
+
test('should add the disabled modifier from the select multiple context', () => {
|
|
87
|
+
const modifiers = getInternalModifiers(
|
|
88
|
+
dayPickerContext,
|
|
89
|
+
selectMultipleContext,
|
|
90
|
+
defaultSelectRangeContext
|
|
91
|
+
);
|
|
92
|
+
expect(modifiers.disabled).toStrictEqual([disabledDate]);
|
|
93
|
+
});
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
describe('when in range select mode', () => {
|
|
97
|
+
const disabled = [new Date()];
|
|
98
|
+
const rangeStart = new Date();
|
|
99
|
+
const rangeMiddle = [addDays(rangeStart, 1), addDays(rangeStart, 2)];
|
|
100
|
+
const rangeEnd = [addDays(rangeStart, 3)];
|
|
101
|
+
const dayPickerContext: DayPickerContextValue = {
|
|
102
|
+
...defaultDayPickerContext,
|
|
103
|
+
mode: 'range'
|
|
104
|
+
};
|
|
105
|
+
const selectRangeContext: SelectRangeContextValue = {
|
|
106
|
+
...defaultSelectRangeContext,
|
|
107
|
+
modifiers: {
|
|
108
|
+
[Disabled]: [disabled],
|
|
109
|
+
[RangeStart]: [rangeStart],
|
|
110
|
+
[RangeEnd]: rangeEnd,
|
|
111
|
+
[RangeMiddle]: rangeMiddle
|
|
112
|
+
}
|
|
113
|
+
};
|
|
114
|
+
let internalModifiers: InternalModifiers;
|
|
115
|
+
beforeEach(() => {
|
|
116
|
+
internalModifiers = getInternalModifiers(
|
|
117
|
+
dayPickerContext,
|
|
118
|
+
defaultSelectMultipleContext,
|
|
119
|
+
selectRangeContext
|
|
120
|
+
);
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
test('should add the Disabled modifier from the SelectRange context', () => {
|
|
124
|
+
expect(internalModifiers[Disabled]).toStrictEqual(
|
|
125
|
+
selectRangeContext.modifiers[Disabled]
|
|
126
|
+
);
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
test('should add the RangeStart modifier from the SelectRange context', () => {
|
|
130
|
+
expect(internalModifiers[RangeStart]).toStrictEqual(
|
|
131
|
+
selectRangeContext.modifiers[RangeStart]
|
|
132
|
+
);
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
test('should add the RangeEnd modifier from the SelectRange context', () => {
|
|
136
|
+
expect(internalModifiers[RangeEnd]).toStrictEqual(
|
|
137
|
+
selectRangeContext.modifiers[RangeEnd]
|
|
138
|
+
);
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
test('should add the RangeMiddle modifier from the SelectRange context', () => {
|
|
142
|
+
expect(internalModifiers[RangeMiddle]).toStrictEqual(
|
|
143
|
+
selectRangeContext.modifiers[RangeMiddle]
|
|
144
|
+
);
|
|
145
|
+
});
|
|
146
|
+
});
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { DayPickerContextValue } from 'contexts/DayPicker';
|
|
2
|
+
import { SelectMultipleContextValue } from 'contexts/SelectMultiple';
|
|
3
|
+
import { SelectRangeContextValue } from 'contexts/SelectRange';
|
|
4
|
+
import { isDayPickerMultiple } from 'types/DayPickerMultiple';
|
|
5
|
+
import { isDayPickerRange } from 'types/DayPickerRange';
|
|
6
|
+
import { InternalModifier, InternalModifiers } from 'types/Modifiers';
|
|
7
|
+
|
|
8
|
+
import { matcherToArray } from './matcherToArray';
|
|
9
|
+
|
|
10
|
+
const {
|
|
11
|
+
Selected,
|
|
12
|
+
Disabled,
|
|
13
|
+
Hidden,
|
|
14
|
+
Today,
|
|
15
|
+
RangeEnd,
|
|
16
|
+
RangeMiddle,
|
|
17
|
+
RangeStart,
|
|
18
|
+
Outside
|
|
19
|
+
} = InternalModifier;
|
|
20
|
+
|
|
21
|
+
/** Return the [[InternalModifiers]] from the DayPicker and select contexts. */
|
|
22
|
+
export function getInternalModifiers(
|
|
23
|
+
dayPicker: DayPickerContextValue,
|
|
24
|
+
selectMultiple: SelectMultipleContextValue,
|
|
25
|
+
selectRange: SelectRangeContextValue
|
|
26
|
+
) {
|
|
27
|
+
const internalModifiers: InternalModifiers = {
|
|
28
|
+
[Selected]: matcherToArray(dayPicker.selected),
|
|
29
|
+
[Disabled]: matcherToArray(dayPicker.disabled),
|
|
30
|
+
[Hidden]: matcherToArray(dayPicker.hidden),
|
|
31
|
+
[Today]: [dayPicker.today],
|
|
32
|
+
[RangeEnd]: [],
|
|
33
|
+
[RangeMiddle]: [],
|
|
34
|
+
[RangeStart]: [],
|
|
35
|
+
[Outside]: []
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
if (dayPicker.fromDate) {
|
|
39
|
+
internalModifiers[Disabled].push({ before: dayPicker.fromDate });
|
|
40
|
+
}
|
|
41
|
+
if (dayPicker.toDate) {
|
|
42
|
+
internalModifiers[Disabled].push({ after: dayPicker.toDate });
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
if (isDayPickerMultiple(dayPicker)) {
|
|
46
|
+
internalModifiers[Disabled] = internalModifiers[Disabled].concat(
|
|
47
|
+
selectMultiple.modifiers[Disabled]
|
|
48
|
+
);
|
|
49
|
+
} else if (isDayPickerRange(dayPicker)) {
|
|
50
|
+
internalModifiers[Disabled] = internalModifiers[Disabled].concat(
|
|
51
|
+
selectRange.modifiers[Disabled]
|
|
52
|
+
);
|
|
53
|
+
internalModifiers[RangeStart] = selectRange.modifiers[RangeStart];
|
|
54
|
+
internalModifiers[RangeMiddle] = selectRange.modifiers[RangeMiddle];
|
|
55
|
+
internalModifiers[RangeEnd] = selectRange.modifiers[RangeEnd];
|
|
56
|
+
}
|
|
57
|
+
return internalModifiers;
|
|
58
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { DateRange } from 'index';
|
|
2
|
+
|
|
3
|
+
import { isDateInRange } from './isDateInRange';
|
|
4
|
+
|
|
5
|
+
const date = new Date();
|
|
6
|
+
|
|
7
|
+
describe('when range is missing the "from" date', () => {
|
|
8
|
+
const range: DateRange = { from: undefined };
|
|
9
|
+
const result = isDateInRange(date, range);
|
|
10
|
+
test('should return false', () => {
|
|
11
|
+
expect(result).toBe(false);
|
|
12
|
+
});
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
describe('when range is missing the "to" date', () => {
|
|
16
|
+
const to = undefined;
|
|
17
|
+
describe('when the from date is the same as date', () => {
|
|
18
|
+
const range: DateRange = { from: date, to };
|
|
19
|
+
const result = isDateInRange(date, range);
|
|
20
|
+
test('should return true', () => {
|
|
21
|
+
expect(result).toBe(true);
|
|
22
|
+
});
|
|
23
|
+
});
|
|
24
|
+
const result = isDateInRange(date, { from: undefined });
|
|
25
|
+
test('should return false', () => {
|
|
26
|
+
expect(result).toBe(false);
|
|
27
|
+
});
|
|
28
|
+
});
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import differenceInCalendarDays from 'date-fns/differenceInCalendarDays';
|
|
2
|
+
import isSameDay from 'date-fns/isSameDay';
|
|
3
|
+
|
|
4
|
+
import { DateRange } from 'types/Matchers';
|
|
5
|
+
|
|
6
|
+
/** Return `true` whether `date` is inside `range`. */
|
|
7
|
+
export function isDateInRange(date: Date, range: DateRange): boolean {
|
|
8
|
+
let { from, to } = range;
|
|
9
|
+
if (!from) {
|
|
10
|
+
return false;
|
|
11
|
+
}
|
|
12
|
+
if (!to && isSameDay(from, date)) {
|
|
13
|
+
return true;
|
|
14
|
+
}
|
|
15
|
+
if (!to) {
|
|
16
|
+
return false;
|
|
17
|
+
}
|
|
18
|
+
const isToBeforeFrom = differenceInCalendarDays(to, from) < 0;
|
|
19
|
+
if (to && isToBeforeFrom) {
|
|
20
|
+
[from, to] = [to, from];
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
return (
|
|
24
|
+
differenceInCalendarDays(date, from) >= 0 &&
|
|
25
|
+
differenceInCalendarDays(to, date) >= 0
|
|
26
|
+
);
|
|
27
|
+
}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { addDays } from 'date-fns';
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
DateAfter,
|
|
5
|
+
DateBefore,
|
|
6
|
+
DateInterval,
|
|
7
|
+
DateRange,
|
|
8
|
+
DayOfWeek
|
|
9
|
+
} from 'types/Matchers';
|
|
10
|
+
|
|
11
|
+
import { isMatch } from './isMatch';
|
|
12
|
+
|
|
13
|
+
const testDay = new Date();
|
|
14
|
+
|
|
15
|
+
describe('when the matcher is a boolean', () => {
|
|
16
|
+
const matcher = true;
|
|
17
|
+
const result = isMatch(testDay, [matcher]);
|
|
18
|
+
test('should return the boolean', () => {
|
|
19
|
+
expect(result).toBe(matcher);
|
|
20
|
+
});
|
|
21
|
+
});
|
|
22
|
+
describe('when matching the same day', () => {
|
|
23
|
+
const matcher = testDay;
|
|
24
|
+
const result = isMatch(testDay, [matcher]);
|
|
25
|
+
test('should return true', () => {
|
|
26
|
+
expect(result).toBe(true);
|
|
27
|
+
});
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
describe('when matching an array of dates including the day', () => {
|
|
31
|
+
const matcher = [addDays(testDay, -1), testDay, addDays(testDay, 1)];
|
|
32
|
+
const result = isMatch(testDay, [matcher]);
|
|
33
|
+
test('should return true', () => {
|
|
34
|
+
expect(result).toBe(true);
|
|
35
|
+
});
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
describe('when matching date range', () => {
|
|
39
|
+
const matcher: DateRange = {
|
|
40
|
+
from: testDay,
|
|
41
|
+
to: addDays(testDay, 1)
|
|
42
|
+
};
|
|
43
|
+
const result = isMatch(testDay, [matcher]);
|
|
44
|
+
test('should return true', () => {
|
|
45
|
+
expect(result).toBe(true);
|
|
46
|
+
});
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
describe('when matching the day of week', () => {
|
|
50
|
+
const matcher: DayOfWeek = {
|
|
51
|
+
dayOfWeek: [testDay.getDay()]
|
|
52
|
+
};
|
|
53
|
+
const result = isMatch(testDay, [matcher]);
|
|
54
|
+
test('should return true', () => {
|
|
55
|
+
expect(result).toBe(true);
|
|
56
|
+
});
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
describe('when matching date interval', () => {
|
|
60
|
+
const matcher: DateInterval = {
|
|
61
|
+
after: addDays(testDay, -1),
|
|
62
|
+
before: addDays(testDay, 1)
|
|
63
|
+
};
|
|
64
|
+
const result = isMatch(testDay, [matcher]);
|
|
65
|
+
test('should return true', () => {
|
|
66
|
+
expect(result).toBe(true);
|
|
67
|
+
});
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
describe('when matching the date after', () => {
|
|
71
|
+
const matcher: DateAfter = { after: addDays(testDay, -1) };
|
|
72
|
+
const result = isMatch(testDay, [matcher]);
|
|
73
|
+
test('should return true', () => {
|
|
74
|
+
expect(result).toBe(true);
|
|
75
|
+
});
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
describe('when matching the date before', () => {
|
|
79
|
+
const matcher: DateBefore = { before: addDays(testDay, +1) };
|
|
80
|
+
const result = isMatch(testDay, [matcher]);
|
|
81
|
+
test('should return true', () => {
|
|
82
|
+
expect(result).toBe(true);
|
|
83
|
+
});
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
describe('when the matcher is a function', () => {
|
|
87
|
+
const matcher = () => true;
|
|
88
|
+
const result = isMatch(testDay, [matcher]);
|
|
89
|
+
test('should return the result of the function', () => {
|
|
90
|
+
expect(result).toBe(true);
|
|
91
|
+
});
|
|
92
|
+
});
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import differenceInCalendarDays from 'date-fns/differenceInCalendarDays';
|
|
2
|
+
import isDate from 'date-fns/isDate';
|
|
3
|
+
import isSameDay from 'date-fns/isSameDay';
|
|
4
|
+
|
|
5
|
+
import {
|
|
6
|
+
isDateAfterType,
|
|
7
|
+
isDateBeforeType,
|
|
8
|
+
isDateInterval,
|
|
9
|
+
isDateRange,
|
|
10
|
+
isDayOfWeekType,
|
|
11
|
+
Matcher
|
|
12
|
+
} from 'types/Matchers';
|
|
13
|
+
|
|
14
|
+
import { isDateInRange } from './isDateInRange';
|
|
15
|
+
|
|
16
|
+
/** Returns true if `value` is a Date type. */
|
|
17
|
+
function isDateType(value: unknown): value is Date {
|
|
18
|
+
return isDate(value);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/** Returns true if `value` is an array of valid dates. */
|
|
22
|
+
function isArrayOfDates(value: unknown): value is Date[] {
|
|
23
|
+
return Array.isArray(value) && value.every(isDate);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Returns whether a day matches against at least one of the given Matchers.
|
|
28
|
+
*
|
|
29
|
+
* ```
|
|
30
|
+
* const day = new Date(2022, 5, 19);
|
|
31
|
+
* const matcher1: DateRange = {
|
|
32
|
+
* from: new Date(2021, 12, 21),
|
|
33
|
+
* to: new Date(2021, 12, 30)
|
|
34
|
+
* }
|
|
35
|
+
* const matcher2: DateRange = {
|
|
36
|
+
* from: new Date(2022, 5, 1),
|
|
37
|
+
* to: new Date(2022, 5, 23)
|
|
38
|
+
* }
|
|
39
|
+
*
|
|
40
|
+
* const isMatch(day, [matcher1, matcher2]); // true, since day is in the matcher1 range.
|
|
41
|
+
* ```
|
|
42
|
+
* */
|
|
43
|
+
export function isMatch(day: Date, matchers: Matcher[]): boolean {
|
|
44
|
+
return matchers.some((matcher: Matcher) => {
|
|
45
|
+
if (typeof matcher === 'boolean') {
|
|
46
|
+
return matcher;
|
|
47
|
+
}
|
|
48
|
+
if (isDateType(matcher)) {
|
|
49
|
+
return isSameDay(day, matcher);
|
|
50
|
+
}
|
|
51
|
+
if (isArrayOfDates(matcher)) {
|
|
52
|
+
return matcher.includes(day);
|
|
53
|
+
}
|
|
54
|
+
if (isDateRange(matcher)) {
|
|
55
|
+
return isDateInRange(day, matcher);
|
|
56
|
+
}
|
|
57
|
+
if (isDayOfWeekType(matcher)) {
|
|
58
|
+
return matcher.dayOfWeek.includes(day.getDay());
|
|
59
|
+
}
|
|
60
|
+
if (isDateInterval(matcher)) {
|
|
61
|
+
const isBefore = differenceInCalendarDays(matcher.before, day) > 0;
|
|
62
|
+
const isAfter = differenceInCalendarDays(day, matcher.after) > 0;
|
|
63
|
+
return isBefore && isAfter;
|
|
64
|
+
}
|
|
65
|
+
if (isDateAfterType(matcher)) {
|
|
66
|
+
return differenceInCalendarDays(day, matcher.after) > 0;
|
|
67
|
+
}
|
|
68
|
+
if (isDateBeforeType(matcher)) {
|
|
69
|
+
return differenceInCalendarDays(matcher.before, day) > 0;
|
|
70
|
+
}
|
|
71
|
+
if (typeof matcher === 'function') {
|
|
72
|
+
return matcher(day);
|
|
73
|
+
}
|
|
74
|
+
return false;
|
|
75
|
+
});
|
|
76
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { matcherToArray } from 'contexts/Modifiers/utils/matcherToArray';
|
|
2
|
+
import { Matcher } from 'types/Matchers';
|
|
3
|
+
|
|
4
|
+
const matcher: Matcher = jest.fn();
|
|
5
|
+
|
|
6
|
+
describe('when a Matcher is passed in', () => {
|
|
7
|
+
test('should return an array with the Matcher', () => {
|
|
8
|
+
expect(matcherToArray(matcher)).toStrictEqual([matcher]);
|
|
9
|
+
});
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
describe('when an array of Matchers is passed in', () => {
|
|
13
|
+
test('should return the array', () => {
|
|
14
|
+
expect(matcherToArray([matcher])).toStrictEqual([matcher]);
|
|
15
|
+
});
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
describe('when undefined is passed in', () => {
|
|
19
|
+
test('should return an empty array', () => {
|
|
20
|
+
expect(matcherToArray(undefined)).toStrictEqual([]);
|
|
21
|
+
});
|
|
22
|
+
});
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { Matcher } from 'types/Matchers';
|
|
2
|
+
|
|
3
|
+
/** Normalize to array a matcher input. */
|
|
4
|
+
export function matcherToArray(
|
|
5
|
+
matcher: Matcher | Matcher[] | undefined
|
|
6
|
+
): Matcher[] {
|
|
7
|
+
if (Array.isArray(matcher)) {
|
|
8
|
+
return matcher;
|
|
9
|
+
} else if (matcher !== undefined) {
|
|
10
|
+
return [matcher];
|
|
11
|
+
} else {
|
|
12
|
+
return [];
|
|
13
|
+
}
|
|
14
|
+
}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import React, { createContext, ReactNode } from 'react';
|
|
2
|
+
|
|
3
|
+
import addMonths from 'date-fns/addMonths';
|
|
4
|
+
import isBefore from 'date-fns/isBefore';
|
|
5
|
+
import isSameMonth from 'date-fns/isSameMonth';
|
|
6
|
+
|
|
7
|
+
import { useDayPicker } from '../DayPicker';
|
|
8
|
+
import { useNavigationState } from './useNavigationState';
|
|
9
|
+
import { getDisplayMonths } from './utils/getDisplayMonths';
|
|
10
|
+
import { getNextMonth } from './utils/getNextMonth';
|
|
11
|
+
import { getPreviousMonth } from './utils/getPreviousMonth';
|
|
12
|
+
|
|
13
|
+
/** Represents the value of the [[NavigationContext]]. */
|
|
14
|
+
export interface NavigationContextValue {
|
|
15
|
+
/** The month to display in the calendar. Note that when `numberOfMonths > 1` represent the first month in the displayed months. */
|
|
16
|
+
currentMonth: Date;
|
|
17
|
+
/** The months rendered by DayPicker. DayPicker can render one than one month via `numberOfMonths`. */
|
|
18
|
+
displayMonths: Date[];
|
|
19
|
+
/** Navigate to the specified month. */
|
|
20
|
+
goToMonth: (month: Date) => void;
|
|
21
|
+
/** Navigate to the specified date. */
|
|
22
|
+
goToDate: (date: Date, refDate?: Date) => void;
|
|
23
|
+
/** The next month to display. `undefined` if no months left */
|
|
24
|
+
nextMonth?: Date;
|
|
25
|
+
/** The previous month to display. `undefined` if no months left */
|
|
26
|
+
previousMonth?: Date;
|
|
27
|
+
/** Return true if the day is currently included in the months displayed in the calendar. */
|
|
28
|
+
isDateDisplayed: (day: Date) => boolean;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* The Navigation context shares details about the months being navigated in DayPicker.
|
|
33
|
+
*
|
|
34
|
+
* Access this context from the [[useNavigation]] hook.
|
|
35
|
+
*/
|
|
36
|
+
export const NavigationContext = createContext<
|
|
37
|
+
NavigationContextValue | undefined
|
|
38
|
+
>(undefined);
|
|
39
|
+
|
|
40
|
+
/** Provides the values for the [[NavigationContext]]. */
|
|
41
|
+
export function NavigationProvider(props: {
|
|
42
|
+
children?: ReactNode;
|
|
43
|
+
}): JSX.Element {
|
|
44
|
+
const dayPicker = useDayPicker();
|
|
45
|
+
const [currentMonth, goToMonth] = useNavigationState();
|
|
46
|
+
|
|
47
|
+
const displayMonths = getDisplayMonths(currentMonth, dayPicker);
|
|
48
|
+
const nextMonth = getNextMonth(currentMonth, dayPicker);
|
|
49
|
+
const previousMonth = getPreviousMonth(currentMonth, dayPicker);
|
|
50
|
+
|
|
51
|
+
const isDateDisplayed = (date: Date) => {
|
|
52
|
+
return displayMonths.some((displayMonth) =>
|
|
53
|
+
isSameMonth(date, displayMonth)
|
|
54
|
+
);
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
const goToDate = (date: Date, refDate?: Date) => {
|
|
58
|
+
if (isDateDisplayed(date)) {
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
if (refDate && isBefore(date, refDate)) {
|
|
63
|
+
goToMonth(addMonths(date, 1 + dayPicker.numberOfMonths * -1));
|
|
64
|
+
} else {
|
|
65
|
+
goToMonth(date);
|
|
66
|
+
}
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
const value: NavigationContextValue = {
|
|
70
|
+
currentMonth,
|
|
71
|
+
displayMonths,
|
|
72
|
+
goToMonth,
|
|
73
|
+
goToDate,
|
|
74
|
+
previousMonth,
|
|
75
|
+
nextMonth,
|
|
76
|
+
isDateDisplayed
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
return (
|
|
80
|
+
<NavigationContext.Provider value={value}>
|
|
81
|
+
{props.children}
|
|
82
|
+
</NavigationContext.Provider>
|
|
83
|
+
);
|
|
84
|
+
}
|