react-day-picker 8.8.2 → 8.9.0
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/README.md +3 -3
- package/dist/index.d.ts +125 -55
- package/dist/index.esm.js +1481 -101
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +1505 -142
- package/dist/index.js.map +1 -1
- package/dist/index.min.js +10 -1
- package/dist/index.min.js.map +1 -1
- package/dist/style.css +8 -7
- package/dist/style.css.map +1 -1
- package/dist/style.module.css +8 -7
- package/package.json +27 -27
- package/src/DayPicker.tsx +0 -2
- package/src/components/Button/Button.test.tsx +0 -2
- package/src/components/Button/Button.tsx +1 -1
- package/src/components/Caption/Caption.test.tsx +0 -2
- package/src/components/Caption/Caption.tsx +0 -2
- package/src/components/CaptionDropdowns/CaptionDropdowns.test.tsx +0 -2
- package/src/components/CaptionDropdowns/CaptionDropdowns.tsx +0 -2
- package/src/components/CaptionLabel/CaptionLabel.test.tsx +0 -2
- package/src/components/CaptionLabel/CaptionLabel.tsx +0 -2
- package/src/components/CaptionNavigation/CaptionNavigation.test.tsx +0 -2
- package/src/components/CaptionNavigation/CaptionNavigation.tsx +3 -3
- package/src/components/Day/Day.test.tsx +0 -2
- package/src/components/Day/Day.tsx +1 -1
- package/src/components/DayContent/DayContent.test.tsx +0 -2
- package/src/components/DayContent/DayContent.tsx +0 -2
- package/src/components/Dropdown/Dropdown.test.tsx +0 -2
- package/src/components/Dropdown/Dropdown.tsx +10 -5
- package/src/components/Footer/Footer.test.tsx +0 -2
- package/src/components/Footer/Footer.tsx +0 -2
- package/src/components/Head/Head.test.tsx +0 -2
- package/src/components/Head/Head.tsx +0 -2
- package/src/components/HeadRow/HeadRow.test.tsx +0 -2
- package/src/components/HeadRow/HeadRow.tsx +0 -2
- package/src/components/IconDropdown/IconDropdown.test.tsx +0 -2
- package/src/components/IconDropdown/IconDropdown.tsx +0 -2
- package/src/components/IconLeft/IconLeft.test.tsx +0 -2
- package/src/components/IconLeft/IconLeft.tsx +0 -2
- package/src/components/IconRight/IconRight.test.tsx +0 -2
- package/src/components/IconRight/IconRight.tsx +0 -2
- package/src/components/Month/Month.test.tsx +0 -2
- package/src/components/Month/Month.tsx +0 -2
- package/src/components/Months/Months.test.tsx +27 -0
- package/src/components/Months/Months.tsx +19 -0
- package/src/components/Months/index.ts +1 -0
- package/src/components/MonthsDropdown/MonthsDropdown.test.tsx +0 -2
- package/src/components/MonthsDropdown/MonthsDropdown.tsx +2 -2
- package/src/components/Navigation/Navigation.test.tsx +0 -2
- package/src/components/Navigation/Navigation.tsx +3 -3
- package/src/components/Root/Root.test.tsx +58 -15
- package/src/components/Root/Root.tsx +9 -6
- package/src/components/Row/Row.test.tsx +0 -2
- package/src/components/Row/Row.tsx +0 -2
- package/src/components/Table/Table.test.tsx +0 -2
- package/src/components/Table/Table.tsx +0 -2
- package/src/components/WeekNumber/WeekNumber.test.tsx +1 -3
- package/src/components/WeekNumber/WeekNumber.tsx +2 -2
- package/src/components/YearsDropdown/YearsDropdown.test.tsx +0 -2
- package/src/components/YearsDropdown/YearsDropdown.tsx +2 -2
- package/src/contexts/DayPicker/DayPickerContext.tsx +1 -1
- package/src/contexts/Focus/FocusContext.tsx +4 -2
- package/src/contexts/Modifiers/ModifiersContext.tsx +2 -4
- package/src/contexts/Navigation/NavigationContext.tsx +1 -1
- package/src/contexts/RootProvider.tsx +2 -4
- package/src/contexts/SelectMultiple/SelectMultipleContext.test.ts +6 -4
- package/src/contexts/SelectMultiple/SelectMultipleContext.tsx +1 -1
- package/src/contexts/SelectRange/SelectRangeContext.test.ts +3 -1
- package/src/contexts/SelectRange/SelectRangeContext.tsx +3 -5
- package/src/contexts/SelectSingle/SelectSingleContext.test.ts +3 -3
- package/src/contexts/SelectSingle/SelectSingleContext.tsx +3 -3
- package/src/hooks/useControlledValue/useControlledValue.ts +2 -2
- package/src/hooks/useDayRender/useDayRender.tsx +2 -2
- package/src/hooks/useDayRender/utils/getDayStyle.ts +4 -2
- package/src/hooks/useId/useId.ts +5 -7
- package/src/hooks/useId/useIsomorphicLayoutEffect.ts +31 -0
- package/src/hooks/useInput/useInput.ts +13 -8
- package/src/index.ts +1 -0
- package/src/style.css +8 -7
- package/src/types/DayPickerBase.ts +84 -10
- package/src/types/EventHandlers.ts +18 -10
- package/src/types/Formatters.ts +3 -3
- package/src/types/Modifiers.ts +4 -2
- package/src/types/Styles.ts +5 -5
- package/tsconfig.json +5 -3
|
@@ -1,6 +1,4 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
3
|
-
import { RenderResult } from '@testing-library/react';
|
|
1
|
+
import { RenderResult, screen } from '@testing-library/react';
|
|
4
2
|
import { addDays } from 'date-fns';
|
|
5
3
|
import { DayPickerProps } from 'DayPicker';
|
|
6
4
|
|
|
@@ -8,6 +6,7 @@ import { customRender } from 'test/render';
|
|
|
8
6
|
import { getDayButton, queryMonthGrids } from 'test/selectors';
|
|
9
7
|
import { freezeBeforeAll } from 'test/utils';
|
|
10
8
|
|
|
9
|
+
import { MonthsProps } from 'components/Months';
|
|
11
10
|
import { defaultClassNames } from 'contexts/DayPicker/defaultClassNames';
|
|
12
11
|
import { ClassNames } from 'types/Styles';
|
|
13
12
|
|
|
@@ -19,7 +18,7 @@ freezeBeforeAll(today);
|
|
|
19
18
|
let container: HTMLElement;
|
|
20
19
|
let view: RenderResult;
|
|
21
20
|
|
|
22
|
-
function
|
|
21
|
+
function render(dayPickerProps: DayPickerProps = {}) {
|
|
23
22
|
view = customRender(<Root initialProps={dayPickerProps} />, dayPickerProps);
|
|
24
23
|
container = view.container;
|
|
25
24
|
}
|
|
@@ -27,7 +26,7 @@ function setup(dayPickerProps: DayPickerProps = {}) {
|
|
|
27
26
|
describe('when the number of months is 1', () => {
|
|
28
27
|
const props: DayPickerProps = { numberOfMonths: 1 };
|
|
29
28
|
beforeEach(() => {
|
|
30
|
-
|
|
29
|
+
render(props);
|
|
31
30
|
});
|
|
32
31
|
test('should display one month grid', () => {
|
|
33
32
|
expect(queryMonthGrids()).toHaveLength(1);
|
|
@@ -37,7 +36,7 @@ describe('when the number of months is 1', () => {
|
|
|
37
36
|
describe('when the number of months is greater than 1', () => {
|
|
38
37
|
const props: DayPickerProps = { numberOfMonths: 3 };
|
|
39
38
|
beforeEach(() => {
|
|
40
|
-
|
|
39
|
+
render(props);
|
|
41
40
|
});
|
|
42
41
|
test('should display the specified number of month grids', () => {
|
|
43
42
|
expect(queryMonthGrids()).toHaveLength(3);
|
|
@@ -49,25 +48,69 @@ describe('when using the "classNames" prop', () => {
|
|
|
49
48
|
root: 'foo'
|
|
50
49
|
};
|
|
51
50
|
beforeEach(() => {
|
|
52
|
-
|
|
51
|
+
render({ classNames });
|
|
53
52
|
});
|
|
54
|
-
test('should
|
|
53
|
+
test('should add the class to the container', () => {
|
|
55
54
|
expect(container.firstChild).toHaveClass('foo');
|
|
56
55
|
});
|
|
57
56
|
});
|
|
58
57
|
|
|
58
|
+
describe('when using a custom "Months" component', () => {
|
|
59
|
+
function CustomMonths(props: MonthsProps) {
|
|
60
|
+
return (
|
|
61
|
+
<div>
|
|
62
|
+
<div data-testid="foo" />
|
|
63
|
+
{props.children}
|
|
64
|
+
</div>
|
|
65
|
+
);
|
|
66
|
+
}
|
|
67
|
+
beforeEach(() => {
|
|
68
|
+
render({ numberOfMonths: 3, components: { Months: CustomMonths } });
|
|
69
|
+
});
|
|
70
|
+
test('should render the custom component', () => {
|
|
71
|
+
expect(screen.getByTestId('foo')).toBeInTheDocument();
|
|
72
|
+
});
|
|
73
|
+
test('should still display the specified number of months', () => {
|
|
74
|
+
expect(queryMonthGrids()).toHaveLength(3);
|
|
75
|
+
});
|
|
76
|
+
});
|
|
77
|
+
|
|
59
78
|
describe('when using the "id" prop', () => {
|
|
60
79
|
const testId = 'foo';
|
|
61
|
-
beforeEach(() =>
|
|
62
|
-
test('should
|
|
80
|
+
beforeEach(() => render({ id: testId }));
|
|
81
|
+
test('should add the "id" attribute', () => {
|
|
63
82
|
expect(container.firstChild).toHaveAttribute('id', testId);
|
|
64
83
|
});
|
|
65
84
|
});
|
|
66
85
|
|
|
86
|
+
describe('when using the "nonce" prop', () => {
|
|
87
|
+
const nonce = 'foo';
|
|
88
|
+
beforeEach(() => render({ nonce }));
|
|
89
|
+
test('should add the "nonce" attribute', () => {
|
|
90
|
+
expect(container.firstChild).toHaveAttribute('nonce', nonce);
|
|
91
|
+
});
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
describe('when using the "title" prop', () => {
|
|
95
|
+
const title = 'foo';
|
|
96
|
+
beforeEach(() => render({ title }));
|
|
97
|
+
test('should add the "title" attribute', () => {
|
|
98
|
+
expect(container.firstChild).toHaveAttribute('title', title);
|
|
99
|
+
});
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
describe('when using the "lang" prop', () => {
|
|
103
|
+
const lang = 'en-US';
|
|
104
|
+
beforeEach(() => render({ lang }));
|
|
105
|
+
test('should add the "lang" attribute', () => {
|
|
106
|
+
expect(container.firstChild).toHaveAttribute('lang', lang);
|
|
107
|
+
});
|
|
108
|
+
});
|
|
109
|
+
|
|
67
110
|
describe('when using the "className" prop', () => {
|
|
68
111
|
const props: DayPickerProps = { className: 'foo' };
|
|
69
112
|
beforeEach(() => {
|
|
70
|
-
|
|
113
|
+
render(props);
|
|
71
114
|
});
|
|
72
115
|
test('should append the class name to the root element', () => {
|
|
73
116
|
expect(container.firstChild).toHaveClass('rdp foo');
|
|
@@ -78,7 +121,7 @@ describe('when the "numberOfMonths" is greater than 1', () => {
|
|
|
78
121
|
const props: DayPickerProps = { numberOfMonths: 3 };
|
|
79
122
|
const expectedClassName = defaultClassNames.multiple_months;
|
|
80
123
|
beforeEach(() => {
|
|
81
|
-
|
|
124
|
+
render(props);
|
|
82
125
|
});
|
|
83
126
|
test(`should have the ${expectedClassName} class name`, () => {
|
|
84
127
|
expect(container.firstChild).toHaveClass(expectedClassName);
|
|
@@ -89,7 +132,7 @@ describe('when showing the week numbers', () => {
|
|
|
89
132
|
const props: DayPickerProps = { showWeekNumber: true };
|
|
90
133
|
const expectedClassName = defaultClassNames.with_weeknumber;
|
|
91
134
|
beforeEach(() => {
|
|
92
|
-
|
|
135
|
+
render(props);
|
|
93
136
|
});
|
|
94
137
|
test(`should have the ${expectedClassName} class name`, () => {
|
|
95
138
|
expect(container.firstChild).toHaveClass(expectedClassName);
|
|
@@ -103,7 +146,7 @@ describe('when "initialFocus" is set', () => {
|
|
|
103
146
|
};
|
|
104
147
|
describe('when a day is not selected', () => {
|
|
105
148
|
beforeEach(() => {
|
|
106
|
-
|
|
149
|
+
render(baseProps);
|
|
107
150
|
});
|
|
108
151
|
test('should focus today', () => {
|
|
109
152
|
expect(getDayButton(today)).toHaveFocus();
|
|
@@ -121,7 +164,7 @@ describe('when "initialFocus" is set', () => {
|
|
|
121
164
|
const selected = addDays(today, 1);
|
|
122
165
|
const props: DayPickerProps = { ...baseProps, selected };
|
|
123
166
|
beforeEach(() => {
|
|
124
|
-
|
|
167
|
+
render(props);
|
|
125
168
|
});
|
|
126
169
|
test('should focus the selected day', () => {
|
|
127
170
|
expect(getDayButton(selected)).toHaveFocus();
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { useEffect, useState } from 'react';
|
|
2
2
|
|
|
3
3
|
import { DayPickerProps } from 'DayPicker';
|
|
4
4
|
|
|
5
5
|
import { Month } from 'components/Month';
|
|
6
|
+
import { Months } from 'components/Months';
|
|
6
7
|
import { useDayPicker } from 'contexts/DayPicker';
|
|
7
8
|
import { useFocusContext } from 'contexts/Focus';
|
|
8
9
|
import { useNavigation } from 'contexts/Navigation';
|
|
@@ -65,22 +66,24 @@ export function Root({ initialProps }: RootProps): JSX.Element {
|
|
|
65
66
|
};
|
|
66
67
|
}, {});
|
|
67
68
|
|
|
69
|
+
const MonthsComponent = initialProps.components?.Months ?? Months;
|
|
70
|
+
|
|
68
71
|
return (
|
|
69
72
|
<div
|
|
70
73
|
className={classNames.join(' ')}
|
|
71
74
|
style={style}
|
|
72
75
|
dir={dayPicker.dir}
|
|
73
76
|
id={dayPicker.id}
|
|
77
|
+
nonce={initialProps.nonce}
|
|
78
|
+
title={initialProps.title}
|
|
79
|
+
lang={initialProps.lang}
|
|
74
80
|
{...dataAttributes}
|
|
75
81
|
>
|
|
76
|
-
<
|
|
77
|
-
className={dayPicker.classNames.months}
|
|
78
|
-
style={dayPicker.styles.months}
|
|
79
|
-
>
|
|
82
|
+
<MonthsComponent>
|
|
80
83
|
{navigation.displayMonths.map((month, i) => (
|
|
81
84
|
<Month key={i} displayIndex={i} displayMonth={month} />
|
|
82
85
|
))}
|
|
83
|
-
</
|
|
86
|
+
</MonthsComponent>
|
|
84
87
|
</div>
|
|
85
88
|
);
|
|
86
89
|
}
|
|
@@ -1,7 +1,5 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
|
|
3
1
|
import { screen } from '@testing-library/react';
|
|
4
|
-
import userEvent from '@testing-library/user-event';
|
|
2
|
+
import { userEvent } from '@testing-library/user-event';
|
|
5
3
|
import { DayPickerProps } from 'DayPicker';
|
|
6
4
|
|
|
7
5
|
import { customRender } from 'test/render/customRender';
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { MouseEventHandler } from 'react';
|
|
2
2
|
|
|
3
3
|
import { useDayPicker } from 'contexts/DayPicker';
|
|
4
4
|
|
|
@@ -41,7 +41,7 @@ export function WeekNumber(props: WeekNumberProps): JSX.Element {
|
|
|
41
41
|
|
|
42
42
|
const label = labelWeekNumber(Number(weekNumber), { locale });
|
|
43
43
|
|
|
44
|
-
const handleClick:
|
|
44
|
+
const handleClick: MouseEventHandler = function (e) {
|
|
45
45
|
onWeekNumberClick(weekNumber, dates, e);
|
|
46
46
|
};
|
|
47
47
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { ChangeEventHandler } from 'react';
|
|
2
2
|
|
|
3
3
|
import { setYear, startOfMonth, startOfYear } from 'date-fns';
|
|
4
4
|
|
|
@@ -45,7 +45,7 @@ export function YearsDropdown(props: YearsDropdownProps): JSX.Element {
|
|
|
45
45
|
years.push(setYear(startOfYear(new Date()), year));
|
|
46
46
|
}
|
|
47
47
|
|
|
48
|
-
const handleChange:
|
|
48
|
+
const handleChange: ChangeEventHandler<HTMLSelectElement> = (e) => {
|
|
49
49
|
const newMonth = setYear(
|
|
50
50
|
startOfMonth(displayMonth),
|
|
51
51
|
Number(e.target.value)
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { createContext, PropsWithChildren, useContext, useState } from 'react';
|
|
2
2
|
|
|
3
3
|
import { isSameDay } from 'date-fns';
|
|
4
4
|
|
|
@@ -54,8 +54,10 @@ export const FocusContext = createContext<FocusContextValue | undefined>(
|
|
|
54
54
|
undefined
|
|
55
55
|
);
|
|
56
56
|
|
|
57
|
+
export type FocusProviderProps = PropsWithChildren;
|
|
58
|
+
|
|
57
59
|
/** The provider for the {@link FocusContext}. */
|
|
58
|
-
export function FocusProvider(props:
|
|
60
|
+
export function FocusProvider(props: FocusProviderProps): JSX.Element {
|
|
59
61
|
const navigation = useNavigation();
|
|
60
62
|
const modifiers = useModifiers();
|
|
61
63
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { createContext, PropsWithChildren, useContext } from 'react';
|
|
2
2
|
|
|
3
3
|
import { useDayPicker } from 'contexts/DayPicker';
|
|
4
4
|
import { useSelectMultiple } from 'contexts/SelectMultiple';
|
|
@@ -11,9 +11,7 @@ import { getInternalModifiers } from './utils/getInternalModifiers';
|
|
|
11
11
|
/** The Modifiers context store the modifiers used in DayPicker. To access the value of this context, use {@link useModifiers}. */
|
|
12
12
|
export const ModifiersContext = createContext<Modifiers | undefined>(undefined);
|
|
13
13
|
|
|
14
|
-
export type ModifiersProviderProps =
|
|
15
|
-
children: ReactNode;
|
|
16
|
-
};
|
|
14
|
+
export type ModifiersProviderProps = PropsWithChildren;
|
|
17
15
|
|
|
18
16
|
/** Provide the value for the {@link ModifiersContext}. */
|
|
19
17
|
export function ModifiersProvider(props: ModifiersProviderProps): JSX.Element {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { PropsWithChildren } from 'react';
|
|
2
2
|
|
|
3
3
|
import { ModifiersProvider } from 'contexts/Modifiers/ModifiersContext';
|
|
4
4
|
import { DayPickerBase } from 'types/DayPickerBase';
|
|
@@ -11,9 +11,7 @@ import { SelectRangeProvider } from './SelectRange';
|
|
|
11
11
|
import { SelectSingleProvider } from './SelectSingle';
|
|
12
12
|
|
|
13
13
|
/** The props of {@link RootProvider}. */
|
|
14
|
-
export type RootContext = DayPickerBase
|
|
15
|
-
children: React.ReactNode;
|
|
16
|
-
};
|
|
14
|
+
export type RootContext = PropsWithChildren<DayPickerBase>;
|
|
17
15
|
|
|
18
16
|
/** Provide the value for all the context providers. */
|
|
19
17
|
export function RootProvider(props: RootContext): JSX.Element {
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { MouseEvent } from 'react';
|
|
2
|
+
|
|
1
3
|
import { addDays, addMonths } from 'date-fns';
|
|
2
4
|
import { DayPickerProps } from 'DayPicker';
|
|
3
5
|
|
|
@@ -57,7 +59,7 @@ describe('when days are selected', () => {
|
|
|
57
59
|
describe('when `onDayClick` is called with a not selected day', () => {
|
|
58
60
|
const clickedDay = addDays(selectedDay1, -1);
|
|
59
61
|
const activeModifiers = {};
|
|
60
|
-
const event = {} as
|
|
62
|
+
const event = {} as MouseEvent;
|
|
61
63
|
beforeAll(() => {
|
|
62
64
|
const result = renderHook(dayPickerProps);
|
|
63
65
|
result.current.onDayClick?.(clickedDay, activeModifiers, event);
|
|
@@ -92,7 +94,7 @@ describe('when days are selected', () => {
|
|
|
92
94
|
afterAll(() => {
|
|
93
95
|
jest.resetAllMocks();
|
|
94
96
|
});
|
|
95
|
-
const event = {} as
|
|
97
|
+
const event = {} as MouseEvent;
|
|
96
98
|
test('should call the `onDayClick` from the DayPicker props', () => {
|
|
97
99
|
expect(dayPickerProps.onDayClick).toHaveBeenCalledWith(
|
|
98
100
|
clickedDay,
|
|
@@ -142,7 +144,7 @@ describe('when the maximum number of days are selected', () => {
|
|
|
142
144
|
afterAll(() => {
|
|
143
145
|
jest.resetAllMocks();
|
|
144
146
|
});
|
|
145
|
-
const event = {} as
|
|
147
|
+
const event = {} as MouseEvent;
|
|
146
148
|
test('should call the `onDayClick` from the DayPicker props', () => {
|
|
147
149
|
expect(dayPickerProps.onDayClick).toHaveBeenCalledWith(
|
|
148
150
|
clickedDay,
|
|
@@ -173,7 +175,7 @@ describe('when the minimum number of days are selected', () => {
|
|
|
173
175
|
afterAll(() => {
|
|
174
176
|
jest.resetAllMocks();
|
|
175
177
|
});
|
|
176
|
-
const event = {} as
|
|
178
|
+
const event = {} as MouseEvent;
|
|
177
179
|
test('should call the `onDayClick` from the DayPicker props', () => {
|
|
178
180
|
expect(dayPickerProps.onDayClick).toHaveBeenCalledWith(
|
|
179
181
|
clickedDay,
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { MouseEvent } from 'react';
|
|
2
|
+
|
|
1
3
|
import {
|
|
2
4
|
addDays,
|
|
3
5
|
addMonths,
|
|
@@ -36,7 +38,7 @@ const initialProps: DayPickerRangeProps = {
|
|
|
36
38
|
|
|
37
39
|
const from = today;
|
|
38
40
|
const to = addDays(today, 6);
|
|
39
|
-
const stubEvent = {} as
|
|
41
|
+
const stubEvent = {} as MouseEvent;
|
|
40
42
|
|
|
41
43
|
describe('when no days are selected', () => {
|
|
42
44
|
test('the selected days should be undefined', () => {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { createContext, PropsWithChildren, useContext } from 'react';
|
|
2
2
|
|
|
3
3
|
import {
|
|
4
4
|
addDays,
|
|
@@ -46,8 +46,7 @@ export const SelectRangeContext = createContext<
|
|
|
46
46
|
|
|
47
47
|
type SelectRangeProviderProps = {
|
|
48
48
|
initialProps: DayPickerBase;
|
|
49
|
-
|
|
50
|
-
};
|
|
49
|
+
} & PropsWithChildren;
|
|
51
50
|
|
|
52
51
|
/** Provides the values for the {@link SelectRangeProvider}. */
|
|
53
52
|
export function SelectRangeProvider(
|
|
@@ -79,8 +78,7 @@ export function SelectRangeProvider(
|
|
|
79
78
|
|
|
80
79
|
type SelectRangeProviderInternalProps = {
|
|
81
80
|
initialProps: DayPickerRangeProps;
|
|
82
|
-
|
|
83
|
-
};
|
|
81
|
+
} & PropsWithChildren;
|
|
84
82
|
|
|
85
83
|
export function SelectRangeProviderInternal({
|
|
86
84
|
initialProps,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { MouseEvent } from 'react';
|
|
2
2
|
|
|
3
3
|
import { DayPickerProps } from 'DayPicker';
|
|
4
4
|
|
|
@@ -44,7 +44,7 @@ describe('when onDayClick is called', () => {
|
|
|
44
44
|
};
|
|
45
45
|
const result = renderHook(dayPickerProps);
|
|
46
46
|
const activeModifiers = {};
|
|
47
|
-
const event = {} as
|
|
47
|
+
const event = {} as MouseEvent;
|
|
48
48
|
test('should call the `onSelect` event handler', () => {
|
|
49
49
|
result.current.onDayClick?.(today, activeModifiers, event);
|
|
50
50
|
expect(dayPickerProps.onSelect).toHaveBeenCalledWith(
|
|
@@ -72,7 +72,7 @@ describe('if a selected day is not required', () => {
|
|
|
72
72
|
test('should call the `onSelect` event handler with an undefined day', () => {
|
|
73
73
|
const result = renderHook(dayPickerProps);
|
|
74
74
|
const activeModifiers: ActiveModifiers = { selected: true };
|
|
75
|
-
const event = {} as
|
|
75
|
+
const event = {} as MouseEvent;
|
|
76
76
|
result.current.onDayClick?.(today, activeModifiers, event);
|
|
77
77
|
expect(dayPickerProps.onSelect).toHaveBeenCalledWith(
|
|
78
78
|
undefined,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { createContext, ReactNode, useContext } from 'react';
|
|
2
2
|
|
|
3
3
|
import { DayPickerBase } from 'types/DayPickerBase';
|
|
4
4
|
import { DayPickerSingleProps, isDayPickerSingle } from 'types/DayPickerSingle';
|
|
@@ -24,7 +24,7 @@ export const SelectSingleContext = createContext<
|
|
|
24
24
|
|
|
25
25
|
type SelectSingleProviderProps = {
|
|
26
26
|
initialProps: DayPickerBase;
|
|
27
|
-
children:
|
|
27
|
+
children: ReactNode;
|
|
28
28
|
};
|
|
29
29
|
|
|
30
30
|
/** Provides the values for the {@link SelectSingleProvider}. */
|
|
@@ -51,7 +51,7 @@ export function SelectSingleProvider(
|
|
|
51
51
|
|
|
52
52
|
type SelectSingleProviderInternal = {
|
|
53
53
|
initialProps: DayPickerSingleProps;
|
|
54
|
-
children:
|
|
54
|
+
children: ReactNode;
|
|
55
55
|
};
|
|
56
56
|
|
|
57
57
|
export function SelectSingleProviderInternal({
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { Dispatch, SetStateAction, useState } from 'react';
|
|
2
2
|
|
|
3
|
-
export type DispatchStateAction<T> =
|
|
3
|
+
export type DispatchStateAction<T> = Dispatch<SetStateAction<T>>;
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* Helper hook for using controlled/uncontrolled values from a component props.
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { RefObject, useEffect } from 'react';
|
|
2
2
|
|
|
3
3
|
import { isSameDay } from 'date-fns';
|
|
4
4
|
|
|
@@ -46,7 +46,7 @@ export function useDayRender(
|
|
|
46
46
|
/** The month where the date is displayed (if not the same as `date`, it means it is an "outside" day). */
|
|
47
47
|
displayMonth: Date,
|
|
48
48
|
/** A ref to the button element that will be target of focus when rendered (if required). */
|
|
49
|
-
buttonRef:
|
|
49
|
+
buttonRef: RefObject<HTMLButtonElement>
|
|
50
50
|
): DayRender {
|
|
51
51
|
const dayPicker = useDayPicker();
|
|
52
52
|
const focusContext = useFocusContext();
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { CSSProperties } from 'react';
|
|
2
|
+
|
|
1
3
|
import { DayPickerContextValue } from 'contexts/DayPicker';
|
|
2
4
|
import { ActiveModifiers } from 'types/Modifiers';
|
|
3
5
|
|
|
@@ -5,8 +7,8 @@ import { ActiveModifiers } from 'types/Modifiers';
|
|
|
5
7
|
export function getDayStyle(
|
|
6
8
|
dayPicker: Pick<DayPickerContextValue, 'modifiersStyles' | 'styles'>,
|
|
7
9
|
activeModifiers: ActiveModifiers
|
|
8
|
-
):
|
|
9
|
-
let style:
|
|
10
|
+
): CSSProperties {
|
|
11
|
+
let style: CSSProperties = {
|
|
10
12
|
...dayPicker.styles.day
|
|
11
13
|
};
|
|
12
14
|
Object.keys(activeModifiers).forEach((modifier) => {
|
package/src/hooks/useId/useId.ts
CHANGED
|
@@ -67,7 +67,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
|
|
|
67
67
|
* server hydration and never again, SO BACK OFF ALRIGHT?
|
|
68
68
|
*/
|
|
69
69
|
|
|
70
|
-
import
|
|
70
|
+
import { useEffect, useLayoutEffect, useState } from 'react';
|
|
71
71
|
|
|
72
72
|
function canUseDOM() {
|
|
73
73
|
return !!(
|
|
@@ -100,9 +100,7 @@ function canUseDOM() {
|
|
|
100
100
|
* @param effect
|
|
101
101
|
* @param deps
|
|
102
102
|
*/
|
|
103
|
-
const useIsomorphicLayoutEffect = canUseDOM()
|
|
104
|
-
? React.useLayoutEffect
|
|
105
|
-
: React.useEffect;
|
|
103
|
+
const useIsomorphicLayoutEffect = canUseDOM() ? useLayoutEffect : useEffect;
|
|
106
104
|
|
|
107
105
|
let serverHandoffComplete = false;
|
|
108
106
|
let id = 0;
|
|
@@ -140,7 +138,7 @@ function useId(providedId?: number | string | undefined | null) {
|
|
|
140
138
|
// If this instance isn't part of the initial render, we don't have to do the
|
|
141
139
|
// double render/patch-up dance. We can just generate the ID and return it.
|
|
142
140
|
let initialId = providedId ?? (serverHandoffComplete ? genId() : null);
|
|
143
|
-
let [id, setId] =
|
|
141
|
+
let [id, setId] = useState(initialId);
|
|
144
142
|
|
|
145
143
|
useIsomorphicLayoutEffect(() => {
|
|
146
144
|
if (id === null) {
|
|
@@ -153,7 +151,7 @@ function useId(providedId?: number | string | undefined | null) {
|
|
|
153
151
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
154
152
|
}, []);
|
|
155
153
|
|
|
156
|
-
|
|
154
|
+
useEffect(() => {
|
|
157
155
|
if (serverHandoffComplete === false) {
|
|
158
156
|
// Flag all future uses of `useId` to skip the update dance. This is in
|
|
159
157
|
// `useEffect` because it goes after `useLayoutEffect`, ensuring we don't
|
|
@@ -165,4 +163,4 @@ function useId(providedId?: number | string | undefined | null) {
|
|
|
165
163
|
return providedId ?? id ?? undefined;
|
|
166
164
|
}
|
|
167
165
|
|
|
168
|
-
export { useId };
|
|
166
|
+
export { useId, canUseDOM };
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { useEffect, useLayoutEffect } from 'react';
|
|
2
|
+
|
|
3
|
+
import { canUseDOM } from './useId';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* React currently throws a warning when using useLayoutEffect on the server. To
|
|
7
|
+
* get around it, we can conditionally useEffect on the server (no-op) and
|
|
8
|
+
* useLayoutEffect in the browser. We occasionally need useLayoutEffect to
|
|
9
|
+
* ensure we don't get a render flash for certain operations, but we may also
|
|
10
|
+
* need affected components to render on the server. One example is when setting
|
|
11
|
+
* a component's descendants to retrieve their index values.
|
|
12
|
+
*
|
|
13
|
+
* Important to note that using this hook as an escape hatch will break the
|
|
14
|
+
* eslint dependency warnings unless you rename the import to `useLayoutEffect`.
|
|
15
|
+
* Use sparingly only when the effect won't effect the rendered HTML to avoid
|
|
16
|
+
* any server/client mismatch.
|
|
17
|
+
*
|
|
18
|
+
* If a useLayoutEffect is needed and the result would create a mismatch, it's
|
|
19
|
+
* likely that the component in question shouldn't be rendered on the server at
|
|
20
|
+
* all, so a better approach would be to lazily render those in a parent
|
|
21
|
+
* component after client-side hydration.
|
|
22
|
+
*
|
|
23
|
+
* https://gist.github.com/gaearon/e7d97cdf38a2907924ea12e4ebdf3c85
|
|
24
|
+
* https://github.com/reduxjs/react-redux/blob/master/src/utils/useIsomorphicLayoutEffect.js
|
|
25
|
+
*
|
|
26
|
+
* @param effect
|
|
27
|
+
* @param deps
|
|
28
|
+
*/
|
|
29
|
+
export const useIsomorphicLayoutEffect = canUseDOM()
|
|
30
|
+
? useLayoutEffect
|
|
31
|
+
: useEffect;
|
|
@@ -1,4 +1,9 @@
|
|
|
1
|
-
import
|
|
1
|
+
import {
|
|
2
|
+
ChangeEventHandler,
|
|
3
|
+
FocusEventHandler,
|
|
4
|
+
InputHTMLAttributes,
|
|
5
|
+
useState
|
|
6
|
+
} from 'react';
|
|
2
7
|
|
|
3
8
|
import { differenceInCalendarDays, format as _format, parse } from 'date-fns';
|
|
4
9
|
import { enUS } from 'date-fns/locale';
|
|
@@ -14,8 +19,8 @@ import {
|
|
|
14
19
|
import { isValidDate } from './utils/isValidDate';
|
|
15
20
|
|
|
16
21
|
/** The props to attach to the input field when using {@link useInput}. */
|
|
17
|
-
export type
|
|
18
|
-
|
|
22
|
+
export type InputProps = Pick<
|
|
23
|
+
InputHTMLAttributes<HTMLInputElement>,
|
|
19
24
|
'onBlur' | 'onChange' | 'onFocus' | 'value' | 'placeholder'
|
|
20
25
|
>;
|
|
21
26
|
|
|
@@ -62,7 +67,7 @@ export interface UseInputValue {
|
|
|
62
67
|
/** The props to pass to a DayPicker component. */
|
|
63
68
|
dayPickerProps: InputDayPickerProps;
|
|
64
69
|
/** The props to pass to an input field. */
|
|
65
|
-
inputProps:
|
|
70
|
+
inputProps: InputProps;
|
|
66
71
|
/** A function to reset to the initial state. */
|
|
67
72
|
reset: () => void;
|
|
68
73
|
/** A function to set the selected day. */
|
|
@@ -120,7 +125,7 @@ export function useInput(options: UseInputOptions = {}): UseInputValue {
|
|
|
120
125
|
// When changing the input field, save its value in state and check if the
|
|
121
126
|
// string is a valid date. If it is a valid day, set it as selected and update
|
|
122
127
|
// the calendar’s month.
|
|
123
|
-
const handleChange:
|
|
128
|
+
const handleChange: ChangeEventHandler<HTMLInputElement> = (e) => {
|
|
124
129
|
setInputValue(e.target.value);
|
|
125
130
|
const day = parseValue(e.target.value);
|
|
126
131
|
const isBefore = fromDate && differenceInCalendarDays(fromDate, day) > 0;
|
|
@@ -135,7 +140,7 @@ export function useInput(options: UseInputOptions = {}): UseInputValue {
|
|
|
135
140
|
|
|
136
141
|
// Special case for _required_ fields: on blur, if the value of the input is not
|
|
137
142
|
// a valid date, reset the calendar and the input value.
|
|
138
|
-
const handleBlur:
|
|
143
|
+
const handleBlur: FocusEventHandler<HTMLInputElement> = (e) => {
|
|
139
144
|
const day = parseValue(e.target.value);
|
|
140
145
|
if (!isValidDate(day)) {
|
|
141
146
|
reset();
|
|
@@ -144,7 +149,7 @@ export function useInput(options: UseInputOptions = {}): UseInputValue {
|
|
|
144
149
|
|
|
145
150
|
// When focusing, make sure DayPicker visualizes the month of the date in the
|
|
146
151
|
// input field.
|
|
147
|
-
const handleFocus:
|
|
152
|
+
const handleFocus: FocusEventHandler<HTMLInputElement> = (e) => {
|
|
148
153
|
if (!e.target.value) {
|
|
149
154
|
reset();
|
|
150
155
|
return;
|
|
@@ -166,7 +171,7 @@ export function useInput(options: UseInputOptions = {}): UseInputValue {
|
|
|
166
171
|
today
|
|
167
172
|
};
|
|
168
173
|
|
|
169
|
-
const inputProps:
|
|
174
|
+
const inputProps: InputProps = {
|
|
170
175
|
onBlur: handleBlur,
|
|
171
176
|
onChange: handleChange,
|
|
172
177
|
onFocus: handleFocus,
|