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,304 @@
|
|
|
1
|
+
import { createRef } from 'react';
|
|
2
|
+
|
|
3
|
+
import { RenderResult } from '@testing-library/react-hooks';
|
|
4
|
+
import { addDays, addMonths } from 'date-fns';
|
|
5
|
+
import { DayPickerProps } from 'DayPicker';
|
|
6
|
+
|
|
7
|
+
import { customRenderHook, CustomRenderHookContexts } from 'test/render';
|
|
8
|
+
import { freezeBeforeAll } from 'test/utils';
|
|
9
|
+
|
|
10
|
+
import { defaultClassNames } from 'contexts/DayPicker/defaultClassNames';
|
|
11
|
+
import { FocusContextValue } from 'contexts/Focus';
|
|
12
|
+
import { EventName } from 'hooks/useDayEventHandlers';
|
|
13
|
+
|
|
14
|
+
import { DayRender } from './';
|
|
15
|
+
import { useDayRender } from './useDayRender';
|
|
16
|
+
|
|
17
|
+
const today = new Date(2022, 5, 13);
|
|
18
|
+
|
|
19
|
+
freezeBeforeAll(today);
|
|
20
|
+
|
|
21
|
+
let result: RenderResult<DayRender>;
|
|
22
|
+
|
|
23
|
+
const mockedFocusContext: FocusContextValue = {
|
|
24
|
+
focus: jest.fn(),
|
|
25
|
+
focusedDay: undefined,
|
|
26
|
+
focusTarget: undefined,
|
|
27
|
+
blur: jest.fn(),
|
|
28
|
+
focusDayAfter: jest.fn(),
|
|
29
|
+
focusDayBefore: jest.fn(),
|
|
30
|
+
focusWeekBefore: jest.fn(),
|
|
31
|
+
focusWeekAfter: jest.fn(),
|
|
32
|
+
focusMonthBefore: jest.fn(),
|
|
33
|
+
focusMonthAfter: jest.fn(),
|
|
34
|
+
focusYearBefore: jest.fn(),
|
|
35
|
+
focusYearAfter: jest.fn(),
|
|
36
|
+
focusStartOfWeek: jest.fn(),
|
|
37
|
+
focusEndOfWeek: jest.fn()
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
function setup(
|
|
41
|
+
date: Date,
|
|
42
|
+
displayMonth: Date,
|
|
43
|
+
dayPickerProps?: DayPickerProps,
|
|
44
|
+
contexts?: CustomRenderHookContexts
|
|
45
|
+
) {
|
|
46
|
+
const buttonRef = createRef<HTMLButtonElement>();
|
|
47
|
+
const view = customRenderHook(
|
|
48
|
+
() => useDayRender(date, displayMonth, buttonRef),
|
|
49
|
+
dayPickerProps,
|
|
50
|
+
contexts
|
|
51
|
+
);
|
|
52
|
+
result = view.result;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
describe('when rendering the today’s date', () => {
|
|
56
|
+
const date = today;
|
|
57
|
+
const displayMonth = date;
|
|
58
|
+
beforeEach(() => {
|
|
59
|
+
setup(date, displayMonth);
|
|
60
|
+
});
|
|
61
|
+
test('the div should include the default class name', () => {
|
|
62
|
+
expect(result.current.divProps.className?.split(' ')).toContain(
|
|
63
|
+
defaultClassNames.day
|
|
64
|
+
);
|
|
65
|
+
});
|
|
66
|
+
test('the button should include the default class name', () => {
|
|
67
|
+
expect(result.current.buttonProps.className?.split(' ')).toContain(
|
|
68
|
+
defaultClassNames.day
|
|
69
|
+
);
|
|
70
|
+
});
|
|
71
|
+
test('the button should not have "aria-pressed"', () => {
|
|
72
|
+
expect(result.current.buttonProps['aria-pressed']).toBeUndefined();
|
|
73
|
+
});
|
|
74
|
+
test('the button should have 0 as "tabIndex"', () => {
|
|
75
|
+
expect(result.current.buttonProps.tabIndex).toBe(0);
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
const testEvents: EventName[] = [
|
|
79
|
+
'onClick',
|
|
80
|
+
'onFocus',
|
|
81
|
+
'onBlur',
|
|
82
|
+
'onKeyDown',
|
|
83
|
+
'onKeyUp',
|
|
84
|
+
'onMouseEnter',
|
|
85
|
+
'onMouseLeave',
|
|
86
|
+
'onTouchCancel',
|
|
87
|
+
'onTouchEnd',
|
|
88
|
+
'onTouchMove',
|
|
89
|
+
'onTouchStart'
|
|
90
|
+
];
|
|
91
|
+
test.each(testEvents)(
|
|
92
|
+
'the button should have the "%s" event handler',
|
|
93
|
+
(eventName) => {
|
|
94
|
+
expect(result.current.buttonProps[eventName]).toBeDefined();
|
|
95
|
+
}
|
|
96
|
+
);
|
|
97
|
+
test('should return the day active modifiers', () => {
|
|
98
|
+
expect(result.current.activeModifiers).toEqual({ today: true });
|
|
99
|
+
});
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
describe('when not in selection mode', () => {
|
|
103
|
+
const dayPickerProps = { mode: undefined };
|
|
104
|
+
beforeEach(() => {
|
|
105
|
+
setup(today, today, dayPickerProps);
|
|
106
|
+
});
|
|
107
|
+
test('should not be a button', () => {
|
|
108
|
+
expect(result.current.isButton).toBe(false);
|
|
109
|
+
});
|
|
110
|
+
});
|
|
111
|
+
describe('when "onDayClick" is not passed in', () => {
|
|
112
|
+
const dayPickerProps = { onDayClick: undefined };
|
|
113
|
+
beforeEach(() => {
|
|
114
|
+
setup(today, today, dayPickerProps);
|
|
115
|
+
});
|
|
116
|
+
test('should not be a button', () => {
|
|
117
|
+
expect(result.current.isButton).toBe(false);
|
|
118
|
+
});
|
|
119
|
+
});
|
|
120
|
+
describe('when in selection mode', () => {
|
|
121
|
+
const dayPickerProps: DayPickerProps = { mode: 'single' };
|
|
122
|
+
beforeEach(() => {
|
|
123
|
+
setup(today, today, dayPickerProps);
|
|
124
|
+
});
|
|
125
|
+
test('should be a button', () => {
|
|
126
|
+
expect(result.current.isButton).toBe(true);
|
|
127
|
+
});
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
describe('when "onDayClick" is passed in', () => {
|
|
131
|
+
const dayPickerProps: DayPickerProps = { onDayClick: jest.fn() };
|
|
132
|
+
beforeEach(() => {
|
|
133
|
+
setup(today, today, dayPickerProps);
|
|
134
|
+
});
|
|
135
|
+
test('should be a button', () => {
|
|
136
|
+
expect(result.current.isButton).toBe(true);
|
|
137
|
+
});
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
describe('when showing the outside days', () => {
|
|
141
|
+
const dayPickerProps: DayPickerProps = { showOutsideDays: false };
|
|
142
|
+
describe('when the day is outside', () => {
|
|
143
|
+
const day = today;
|
|
144
|
+
const displayMonth = addMonths(today, 1);
|
|
145
|
+
beforeEach(() => {
|
|
146
|
+
setup(day, displayMonth, dayPickerProps);
|
|
147
|
+
});
|
|
148
|
+
test('should be hidden', () => {
|
|
149
|
+
expect(result.current.isHidden).toBe(true);
|
|
150
|
+
});
|
|
151
|
+
});
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
describe('when the day has the "hidden" modifier active', () => {
|
|
155
|
+
const date = today;
|
|
156
|
+
const dayPickerProps: DayPickerProps = {
|
|
157
|
+
modifiers: { hidden: date }
|
|
158
|
+
};
|
|
159
|
+
beforeEach(() => {
|
|
160
|
+
setup(date, date, dayPickerProps);
|
|
161
|
+
});
|
|
162
|
+
test('should have the hidden modifier active', () => {
|
|
163
|
+
expect(result.current.activeModifiers.hidden).toBe(true);
|
|
164
|
+
});
|
|
165
|
+
test('should be hidden', () => {
|
|
166
|
+
expect(result.current.isHidden).toBe(true);
|
|
167
|
+
});
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
describe('when "modifiersStyles" is passed in', () => {
|
|
171
|
+
const date = today;
|
|
172
|
+
const dayPickerProps = {
|
|
173
|
+
modifiers: { foo: date },
|
|
174
|
+
modifiersStyles: { foo: { color: 'red' } }
|
|
175
|
+
};
|
|
176
|
+
beforeEach(() => {
|
|
177
|
+
setup(date, date, dayPickerProps);
|
|
178
|
+
});
|
|
179
|
+
test('the div props should include the modifiers style', () => {
|
|
180
|
+
expect(result.current.divProps.style).toStrictEqual(
|
|
181
|
+
dayPickerProps.modifiersStyles.foo
|
|
182
|
+
);
|
|
183
|
+
});
|
|
184
|
+
test('the button props should include the modifiers style', () => {
|
|
185
|
+
expect(result.current.buttonProps.style).toStrictEqual(
|
|
186
|
+
dayPickerProps.modifiersStyles.foo
|
|
187
|
+
);
|
|
188
|
+
});
|
|
189
|
+
});
|
|
190
|
+
describe('when "styles.day" is passed in', () => {
|
|
191
|
+
const date = today;
|
|
192
|
+
const dayPickerProps = {
|
|
193
|
+
styles: { day: { color: 'red' } }
|
|
194
|
+
};
|
|
195
|
+
beforeEach(() => {
|
|
196
|
+
setup(date, date, dayPickerProps);
|
|
197
|
+
});
|
|
198
|
+
test('the div props should include the style', () => {
|
|
199
|
+
expect(result.current.divProps.style).toStrictEqual(
|
|
200
|
+
dayPickerProps.styles.day
|
|
201
|
+
);
|
|
202
|
+
});
|
|
203
|
+
test('the button props should include the style', () => {
|
|
204
|
+
expect(result.current.buttonProps.style).toStrictEqual(
|
|
205
|
+
dayPickerProps.styles.day
|
|
206
|
+
);
|
|
207
|
+
});
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
describe('when "modifiersClassNames" is passed in', () => {
|
|
211
|
+
const date = today;
|
|
212
|
+
const dayPickerProps = {
|
|
213
|
+
modifiers: { foo: date },
|
|
214
|
+
modifiersClassNames: { foo: 'bar' }
|
|
215
|
+
};
|
|
216
|
+
beforeEach(() => {
|
|
217
|
+
setup(date, date, dayPickerProps);
|
|
218
|
+
});
|
|
219
|
+
test('the div props should include the modifiers classNames', () => {
|
|
220
|
+
expect(result.current.divProps.className).toContain(
|
|
221
|
+
dayPickerProps.modifiersClassNames.foo
|
|
222
|
+
);
|
|
223
|
+
});
|
|
224
|
+
test('the button props should include the modifiers classNames', () => {
|
|
225
|
+
expect(result.current.buttonProps.className).toContain(
|
|
226
|
+
dayPickerProps.modifiersClassNames.foo
|
|
227
|
+
);
|
|
228
|
+
});
|
|
229
|
+
});
|
|
230
|
+
|
|
231
|
+
describe('when "classNames.day" is passed in', () => {
|
|
232
|
+
const date = today;
|
|
233
|
+
const dayPickerProps = {
|
|
234
|
+
classNames: { day: 'foo' }
|
|
235
|
+
};
|
|
236
|
+
beforeEach(() => {
|
|
237
|
+
setup(date, date, dayPickerProps);
|
|
238
|
+
});
|
|
239
|
+
test('the div props should include the class name', () => {
|
|
240
|
+
expect(result.current.divProps.className).toContain(
|
|
241
|
+
dayPickerProps.classNames.day
|
|
242
|
+
);
|
|
243
|
+
});
|
|
244
|
+
test('the button props should include the class name', () => {
|
|
245
|
+
expect(result.current.buttonProps.className).toContain(
|
|
246
|
+
dayPickerProps.classNames.day
|
|
247
|
+
);
|
|
248
|
+
});
|
|
249
|
+
});
|
|
250
|
+
|
|
251
|
+
describe('when the day is not target of focus', () => {
|
|
252
|
+
const yesterday = addDays(today, -1);
|
|
253
|
+
const tomorrow = addDays(today, 1);
|
|
254
|
+
const focusContext: FocusContextValue = {
|
|
255
|
+
...mockedFocusContext,
|
|
256
|
+
focusTarget: yesterday
|
|
257
|
+
};
|
|
258
|
+
beforeEach(() => {
|
|
259
|
+
setup(tomorrow, tomorrow, {}, { focus: focusContext });
|
|
260
|
+
});
|
|
261
|
+
test('the button should have tabIndex -1', () => {
|
|
262
|
+
expect(result.current.buttonProps.tabIndex).toBe(-1);
|
|
263
|
+
});
|
|
264
|
+
});
|
|
265
|
+
|
|
266
|
+
describe('when the day is target of focus', () => {
|
|
267
|
+
const date = today;
|
|
268
|
+
const focusContext: FocusContextValue = {
|
|
269
|
+
...mockedFocusContext,
|
|
270
|
+
focusTarget: date
|
|
271
|
+
};
|
|
272
|
+
beforeEach(() => {
|
|
273
|
+
setup(date, date, {}, { focus: focusContext });
|
|
274
|
+
});
|
|
275
|
+
test('the button should have tabIndex 0', () => {
|
|
276
|
+
expect(result.current.buttonProps.tabIndex).toBe(0);
|
|
277
|
+
});
|
|
278
|
+
});
|
|
279
|
+
|
|
280
|
+
describe('when the day is disabled', () => {
|
|
281
|
+
const date = today;
|
|
282
|
+
const dayPickerProps = {
|
|
283
|
+
disabled: date
|
|
284
|
+
};
|
|
285
|
+
beforeEach(() => {
|
|
286
|
+
setup(date, date, dayPickerProps);
|
|
287
|
+
});
|
|
288
|
+
test('the button should be disabled', () => {
|
|
289
|
+
expect(result.current.buttonProps.disabled).toBe(true);
|
|
290
|
+
});
|
|
291
|
+
});
|
|
292
|
+
|
|
293
|
+
describe('when the day is selected', () => {
|
|
294
|
+
const date = today;
|
|
295
|
+
const dayPickerProps = {
|
|
296
|
+
selected: date
|
|
297
|
+
};
|
|
298
|
+
beforeEach(() => {
|
|
299
|
+
setup(date, date, dayPickerProps);
|
|
300
|
+
});
|
|
301
|
+
test('the button should have "aria-pressed"', () => {
|
|
302
|
+
expect(result.current.buttonProps['aria-pressed']).toBe(true);
|
|
303
|
+
});
|
|
304
|
+
});
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import React, { useEffect } from 'react';
|
|
2
|
+
|
|
3
|
+
import isSameDay from 'date-fns/isSameDay';
|
|
4
|
+
|
|
5
|
+
import { ButtonProps } from 'components/Button';
|
|
6
|
+
import { DayContent } from 'components/DayContent';
|
|
7
|
+
import { useDayPicker } from 'contexts/DayPicker';
|
|
8
|
+
import { useFocusContext } from 'contexts/Focus';
|
|
9
|
+
import { useActiveModifiers } from 'hooks/useActiveModifiers';
|
|
10
|
+
import {
|
|
11
|
+
DayEventHandlers,
|
|
12
|
+
useDayEventHandlers
|
|
13
|
+
} from 'hooks/useDayEventHandlers';
|
|
14
|
+
import { SelectedDays, useSelectedDays } from 'hooks/useSelectedDays';
|
|
15
|
+
import { ActiveModifiers } from 'types/Modifiers';
|
|
16
|
+
import { StyledComponent } from 'types/Styles';
|
|
17
|
+
|
|
18
|
+
import { getDayClassNames } from './utils/getDayClassNames';
|
|
19
|
+
import { getDayStyle } from './utils/getDayStyle';
|
|
20
|
+
|
|
21
|
+
export type DayRender = {
|
|
22
|
+
/** Whether the day should be rendered a `button` instead of a `div` */
|
|
23
|
+
isButton: boolean;
|
|
24
|
+
/** Whether the day should be hidden. */
|
|
25
|
+
isHidden: boolean;
|
|
26
|
+
/** The modifiers active for the given day. */
|
|
27
|
+
activeModifiers: ActiveModifiers;
|
|
28
|
+
/** The props to apply to the button element (when `isButton` is true). */
|
|
29
|
+
buttonProps: StyledComponent &
|
|
30
|
+
Pick<ButtonProps, 'disabled' | 'aria-pressed' | 'tabIndex'> &
|
|
31
|
+
DayEventHandlers;
|
|
32
|
+
/** The props to apply to the div element (when `isButton` is false). */
|
|
33
|
+
divProps: StyledComponent;
|
|
34
|
+
selectedDays: SelectedDays;
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Return props and data used to render the [[Day]] component.
|
|
39
|
+
*
|
|
40
|
+
* Use this hook when creating a component to replace the built-in `Day`
|
|
41
|
+
* component.
|
|
42
|
+
*
|
|
43
|
+
* Each Day in DayPicker should render one of the following, according to the return
|
|
44
|
+
* value:
|
|
45
|
+
*
|
|
46
|
+
* - an empty `React.Fragment`, to render if `isHidden` is true
|
|
47
|
+
* - a `button` element, when the day is interactive, e.g. is selectable
|
|
48
|
+
* - a `div` element, whe the day is not interactive
|
|
49
|
+
*
|
|
50
|
+
* @param day The date to render
|
|
51
|
+
* @param displayMonth The month where the date is displayed (if not the same as
|
|
52
|
+
* `date`, it means it is an "outside" day)
|
|
53
|
+
* @param buttonRef A ref to the button element that will be target of focus
|
|
54
|
+
* when rendered (if required).
|
|
55
|
+
*/
|
|
56
|
+
export function useDayRender(
|
|
57
|
+
day: Date,
|
|
58
|
+
displayMonth: Date,
|
|
59
|
+
buttonRef: React.RefObject<HTMLButtonElement>
|
|
60
|
+
): DayRender {
|
|
61
|
+
const dayPicker = useDayPicker();
|
|
62
|
+
const focusContext = useFocusContext();
|
|
63
|
+
const activeModifiers = useActiveModifiers(day, displayMonth);
|
|
64
|
+
const eventHandlers = useDayEventHandlers(day, activeModifiers);
|
|
65
|
+
const selectedDays = useSelectedDays();
|
|
66
|
+
const isButton = Boolean(
|
|
67
|
+
dayPicker.onDayClick || dayPicker.mode !== 'default'
|
|
68
|
+
);
|
|
69
|
+
|
|
70
|
+
// Focus the button if the day is focused according to the focus context
|
|
71
|
+
useEffect(() => {
|
|
72
|
+
if (!focusContext.focusedDay) return;
|
|
73
|
+
if (!isButton) return;
|
|
74
|
+
if (isSameDay(focusContext.focusedDay, day)) {
|
|
75
|
+
buttonRef.current?.focus();
|
|
76
|
+
}
|
|
77
|
+
}, [focusContext.focusedDay, day, buttonRef, isButton]);
|
|
78
|
+
|
|
79
|
+
const className = getDayClassNames(dayPicker, activeModifiers).join(' ');
|
|
80
|
+
const style = getDayStyle(dayPicker, activeModifiers);
|
|
81
|
+
|
|
82
|
+
const isHidden = Boolean(
|
|
83
|
+
(activeModifiers.outside && !dayPicker.showOutsideDays) ||
|
|
84
|
+
activeModifiers.hidden
|
|
85
|
+
);
|
|
86
|
+
|
|
87
|
+
const DayContentComponent = dayPicker.components?.DayContent ?? DayContent;
|
|
88
|
+
const children = (
|
|
89
|
+
<DayContentComponent
|
|
90
|
+
date={day}
|
|
91
|
+
displayMonth={displayMonth}
|
|
92
|
+
activeModifiers={activeModifiers}
|
|
93
|
+
/>
|
|
94
|
+
);
|
|
95
|
+
|
|
96
|
+
const divProps = {
|
|
97
|
+
style,
|
|
98
|
+
className,
|
|
99
|
+
children
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
const isFocusTarget = Boolean(
|
|
103
|
+
focusContext.focusTarget && isSameDay(focusContext.focusTarget, day)
|
|
104
|
+
);
|
|
105
|
+
const buttonProps = {
|
|
106
|
+
...divProps,
|
|
107
|
+
disabled: activeModifiers.disabled,
|
|
108
|
+
['aria-pressed']: activeModifiers.selected,
|
|
109
|
+
tabIndex: isFocusTarget ? 0 : -1,
|
|
110
|
+
...eventHandlers
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
const dayRender: DayRender = {
|
|
114
|
+
isButton,
|
|
115
|
+
isHidden,
|
|
116
|
+
activeModifiers: activeModifiers,
|
|
117
|
+
selectedDays,
|
|
118
|
+
buttonProps,
|
|
119
|
+
divProps
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
return dayRender;
|
|
123
|
+
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { DayPickerContextValue } from 'contexts/DayPicker';
|
|
2
|
+
import { defaultClassNames } from 'contexts/DayPicker/defaultClassNames';
|
|
3
|
+
import { ActiveModifiers, InternalModifier } from 'types/Modifiers';
|
|
4
|
+
|
|
5
|
+
import { getDayClassNames } from './getDayClassNames';
|
|
6
|
+
|
|
7
|
+
type DayPickerOptions = Pick<
|
|
8
|
+
DayPickerContextValue,
|
|
9
|
+
'modifiersClassNames' | 'classNames'
|
|
10
|
+
>;
|
|
11
|
+
|
|
12
|
+
const internalModifiers = Object.values(InternalModifier);
|
|
13
|
+
|
|
14
|
+
test('should include the day class name', () => {
|
|
15
|
+
const dayPicker: DayPickerOptions = {
|
|
16
|
+
modifiersClassNames: {},
|
|
17
|
+
classNames: defaultClassNames
|
|
18
|
+
};
|
|
19
|
+
const activeModifiers: ActiveModifiers = {};
|
|
20
|
+
expect(getDayClassNames(dayPicker, activeModifiers)).toContain(
|
|
21
|
+
defaultClassNames.day
|
|
22
|
+
);
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
describe('when using "modifiersClassNames" for a custom modifier', () => {
|
|
26
|
+
const modifierClassName = `foo-class`;
|
|
27
|
+
const dayPicker: DayPickerOptions = {
|
|
28
|
+
modifiersClassNames: {
|
|
29
|
+
foo: modifierClassName
|
|
30
|
+
},
|
|
31
|
+
classNames: defaultClassNames
|
|
32
|
+
};
|
|
33
|
+
const activeModifiers: ActiveModifiers = { foo: true };
|
|
34
|
+
test('should return the custom class name for the modifier', () => {
|
|
35
|
+
expect(getDayClassNames(dayPicker, activeModifiers)).toContain(
|
|
36
|
+
modifierClassName
|
|
37
|
+
);
|
|
38
|
+
});
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
describe.each(internalModifiers)(
|
|
42
|
+
'when using "modifiersClassNames" for the %s (internal) modifier',
|
|
43
|
+
(internalModifier) => {
|
|
44
|
+
const modifierClassName = `foo-${internalModifier}`;
|
|
45
|
+
const dayPicker: DayPickerOptions = {
|
|
46
|
+
modifiersClassNames: {
|
|
47
|
+
[internalModifier]: modifierClassName
|
|
48
|
+
},
|
|
49
|
+
classNames: defaultClassNames
|
|
50
|
+
};
|
|
51
|
+
const activeModifiers: ActiveModifiers = { [internalModifier]: true };
|
|
52
|
+
test('should return the custom class name for the modifier', () => {
|
|
53
|
+
expect(getDayClassNames(dayPicker, activeModifiers)).toContain(
|
|
54
|
+
modifierClassName
|
|
55
|
+
);
|
|
56
|
+
});
|
|
57
|
+
test('should not include the default class name for the modifier', () => {
|
|
58
|
+
expect(getDayClassNames(dayPicker, activeModifiers)).not.toContain(
|
|
59
|
+
defaultClassNames.day_selected
|
|
60
|
+
);
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
);
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { DayPickerContextValue } from 'contexts/DayPicker';
|
|
2
|
+
import { ActiveModifiers, InternalModifier } from 'types/Modifiers';
|
|
3
|
+
|
|
4
|
+
function isInternalModifier(modifier: string): modifier is InternalModifier {
|
|
5
|
+
return Object.values(InternalModifier).includes(modifier as InternalModifier);
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Return the class names for the Day element, according to the given active
|
|
10
|
+
* modifiers.
|
|
11
|
+
*
|
|
12
|
+
* Custom class names are set via `modifiersClassNames` or `classNames`,
|
|
13
|
+
* where the first have the precedence.
|
|
14
|
+
*/
|
|
15
|
+
export function getDayClassNames(
|
|
16
|
+
dayPicker: Pick<DayPickerContextValue, 'modifiersClassNames' | 'classNames'>,
|
|
17
|
+
activeModifiers: ActiveModifiers
|
|
18
|
+
) {
|
|
19
|
+
const classNames: string[] = [dayPicker.classNames.day];
|
|
20
|
+
Object.keys(activeModifiers).forEach((modifier) => {
|
|
21
|
+
const customClassName = dayPicker.modifiersClassNames[modifier];
|
|
22
|
+
if (customClassName) {
|
|
23
|
+
classNames.push(customClassName);
|
|
24
|
+
} else if (isInternalModifier(modifier)) {
|
|
25
|
+
const internalClassName = dayPicker.classNames[`day_${modifier}`];
|
|
26
|
+
if (internalClassName) {
|
|
27
|
+
classNames.push(internalClassName);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
});
|
|
31
|
+
return classNames;
|
|
32
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { DayPickerContextValue } from 'contexts/DayPicker';
|
|
2
|
+
import { ActiveModifiers } from 'types/Modifiers';
|
|
3
|
+
|
|
4
|
+
/** Return the style for the Day element, according to the given active modifiers. */
|
|
5
|
+
export function getDayStyle(
|
|
6
|
+
dayPicker: Pick<DayPickerContextValue, 'modifiersStyles' | 'styles'>,
|
|
7
|
+
activeModifiers: ActiveModifiers
|
|
8
|
+
): React.CSSProperties {
|
|
9
|
+
let style: React.CSSProperties = {
|
|
10
|
+
...dayPicker.styles.day
|
|
11
|
+
};
|
|
12
|
+
Object.keys(activeModifiers).forEach((modifier) => {
|
|
13
|
+
style = {
|
|
14
|
+
...style,
|
|
15
|
+
...dayPicker.modifiersStyles?.[modifier]
|
|
16
|
+
};
|
|
17
|
+
});
|
|
18
|
+
return style;
|
|
19
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './useInput';
|