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.
Files changed (85) hide show
  1. package/README.md +3 -3
  2. package/dist/index.d.ts +125 -55
  3. package/dist/index.esm.js +1481 -101
  4. package/dist/index.esm.js.map +1 -1
  5. package/dist/index.js +1505 -142
  6. package/dist/index.js.map +1 -1
  7. package/dist/index.min.js +10 -1
  8. package/dist/index.min.js.map +1 -1
  9. package/dist/style.css +8 -7
  10. package/dist/style.css.map +1 -1
  11. package/dist/style.module.css +8 -7
  12. package/package.json +27 -27
  13. package/src/DayPicker.tsx +0 -2
  14. package/src/components/Button/Button.test.tsx +0 -2
  15. package/src/components/Button/Button.tsx +1 -1
  16. package/src/components/Caption/Caption.test.tsx +0 -2
  17. package/src/components/Caption/Caption.tsx +0 -2
  18. package/src/components/CaptionDropdowns/CaptionDropdowns.test.tsx +0 -2
  19. package/src/components/CaptionDropdowns/CaptionDropdowns.tsx +0 -2
  20. package/src/components/CaptionLabel/CaptionLabel.test.tsx +0 -2
  21. package/src/components/CaptionLabel/CaptionLabel.tsx +0 -2
  22. package/src/components/CaptionNavigation/CaptionNavigation.test.tsx +0 -2
  23. package/src/components/CaptionNavigation/CaptionNavigation.tsx +3 -3
  24. package/src/components/Day/Day.test.tsx +0 -2
  25. package/src/components/Day/Day.tsx +1 -1
  26. package/src/components/DayContent/DayContent.test.tsx +0 -2
  27. package/src/components/DayContent/DayContent.tsx +0 -2
  28. package/src/components/Dropdown/Dropdown.test.tsx +0 -2
  29. package/src/components/Dropdown/Dropdown.tsx +10 -5
  30. package/src/components/Footer/Footer.test.tsx +0 -2
  31. package/src/components/Footer/Footer.tsx +0 -2
  32. package/src/components/Head/Head.test.tsx +0 -2
  33. package/src/components/Head/Head.tsx +0 -2
  34. package/src/components/HeadRow/HeadRow.test.tsx +0 -2
  35. package/src/components/HeadRow/HeadRow.tsx +0 -2
  36. package/src/components/IconDropdown/IconDropdown.test.tsx +0 -2
  37. package/src/components/IconDropdown/IconDropdown.tsx +0 -2
  38. package/src/components/IconLeft/IconLeft.test.tsx +0 -2
  39. package/src/components/IconLeft/IconLeft.tsx +0 -2
  40. package/src/components/IconRight/IconRight.test.tsx +0 -2
  41. package/src/components/IconRight/IconRight.tsx +0 -2
  42. package/src/components/Month/Month.test.tsx +0 -2
  43. package/src/components/Month/Month.tsx +0 -2
  44. package/src/components/Months/Months.test.tsx +27 -0
  45. package/src/components/Months/Months.tsx +19 -0
  46. package/src/components/Months/index.ts +1 -0
  47. package/src/components/MonthsDropdown/MonthsDropdown.test.tsx +0 -2
  48. package/src/components/MonthsDropdown/MonthsDropdown.tsx +2 -2
  49. package/src/components/Navigation/Navigation.test.tsx +0 -2
  50. package/src/components/Navigation/Navigation.tsx +3 -3
  51. package/src/components/Root/Root.test.tsx +58 -15
  52. package/src/components/Root/Root.tsx +9 -6
  53. package/src/components/Row/Row.test.tsx +0 -2
  54. package/src/components/Row/Row.tsx +0 -2
  55. package/src/components/Table/Table.test.tsx +0 -2
  56. package/src/components/Table/Table.tsx +0 -2
  57. package/src/components/WeekNumber/WeekNumber.test.tsx +1 -3
  58. package/src/components/WeekNumber/WeekNumber.tsx +2 -2
  59. package/src/components/YearsDropdown/YearsDropdown.test.tsx +0 -2
  60. package/src/components/YearsDropdown/YearsDropdown.tsx +2 -2
  61. package/src/contexts/DayPicker/DayPickerContext.tsx +1 -1
  62. package/src/contexts/Focus/FocusContext.tsx +4 -2
  63. package/src/contexts/Modifiers/ModifiersContext.tsx +2 -4
  64. package/src/contexts/Navigation/NavigationContext.tsx +1 -1
  65. package/src/contexts/RootProvider.tsx +2 -4
  66. package/src/contexts/SelectMultiple/SelectMultipleContext.test.ts +6 -4
  67. package/src/contexts/SelectMultiple/SelectMultipleContext.tsx +1 -1
  68. package/src/contexts/SelectRange/SelectRangeContext.test.ts +3 -1
  69. package/src/contexts/SelectRange/SelectRangeContext.tsx +3 -5
  70. package/src/contexts/SelectSingle/SelectSingleContext.test.ts +3 -3
  71. package/src/contexts/SelectSingle/SelectSingleContext.tsx +3 -3
  72. package/src/hooks/useControlledValue/useControlledValue.ts +2 -2
  73. package/src/hooks/useDayRender/useDayRender.tsx +2 -2
  74. package/src/hooks/useDayRender/utils/getDayStyle.ts +4 -2
  75. package/src/hooks/useId/useId.ts +5 -7
  76. package/src/hooks/useId/useIsomorphicLayoutEffect.ts +31 -0
  77. package/src/hooks/useInput/useInput.ts +13 -8
  78. package/src/index.ts +1 -0
  79. package/src/style.css +8 -7
  80. package/src/types/DayPickerBase.ts +84 -10
  81. package/src/types/EventHandlers.ts +18 -10
  82. package/src/types/Formatters.ts +3 -3
  83. package/src/types/Modifiers.ts +4 -2
  84. package/src/types/Styles.ts +5 -5
  85. package/tsconfig.json +5 -3
@@ -1,6 +1,4 @@
1
- import React from 'react';
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 setup(dayPickerProps: DayPickerProps = {}) {
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
- setup(props);
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
- setup(props);
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
- setup({ classNames });
51
+ render({ classNames });
53
52
  });
54
- test('should display the specified number of month grids', () => {
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(() => setup({ id: testId }));
62
- test('should display the specified number of month grids', () => {
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
- setup(props);
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
- setup(props);
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
- setup(props);
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
- setup(baseProps);
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
- setup(props);
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 React, { useEffect, useState } from 'react';
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
- <div
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
- </div>
86
+ </MonthsComponent>
84
87
  </div>
85
88
  );
86
89
  }
@@ -1,5 +1,3 @@
1
- import React from 'react';
2
-
3
1
  import { screen } from '@testing-library/react';
4
2
  import { DayPickerProps } from 'DayPicker';
5
3
 
@@ -1,5 +1,3 @@
1
- import React from 'react';
2
-
3
1
  import { getUnixTime } from 'date-fns';
4
2
 
5
3
  import { Day } from 'components/Day';
@@ -1,5 +1,3 @@
1
- import React from 'react';
2
-
3
1
  import { DayPickerProps } from 'DayPicker';
4
2
 
5
3
  import { customRender } from 'test/render/customRender';
@@ -1,5 +1,3 @@
1
- import React from 'react';
2
-
3
1
  import { Footer } from 'components/Footer';
4
2
  import { Head } from 'components/Head';
5
3
  import { Row } from 'components/Row';
@@ -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 React from 'react';
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: React.MouseEventHandler = function (e) {
44
+ const handleClick: MouseEventHandler = function (e) {
45
45
  onWeekNumberClick(weekNumber, dates, e);
46
46
  };
47
47
 
@@ -1,5 +1,3 @@
1
- import React from 'react';
2
-
3
1
  import { screen } from '@testing-library/react';
4
2
  import { addMonths, differenceInYears } from 'date-fns';
5
3
  import { DayPickerProps } from 'DayPicker';
@@ -1,4 +1,4 @@
1
- import React from 'react';
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: React.ChangeEventHandler<HTMLSelectElement> = (e) => {
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 React, { createContext, ReactNode, useContext } from 'react';
1
+ import { createContext, ReactNode, useContext } from 'react';
2
2
 
3
3
  import { DayPickerProps } from 'DayPicker';
4
4
 
@@ -1,4 +1,4 @@
1
- import React, { createContext, ReactNode, useContext, useState } from 'react';
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: { children: ReactNode }): JSX.Element {
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 React, { createContext, ReactNode, useContext } from 'react';
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 React, { createContext, ReactNode, useContext } from 'react';
1
+ import { createContext, ReactNode, useContext } from 'react';
2
2
 
3
3
  import { addMonths, isBefore, isSameMonth } from 'date-fns';
4
4
 
@@ -1,4 +1,4 @@
1
- import React from 'react';
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 React.MouseEvent;
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 React.MouseEvent;
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 React.MouseEvent;
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 React.MouseEvent;
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,4 +1,4 @@
1
- import React, { createContext, ReactNode, useContext } from 'react';
1
+ import { createContext, ReactNode, useContext } from 'react';
2
2
 
3
3
  import { isSameDay } from 'date-fns';
4
4
 
@@ -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 React.MouseEvent;
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 React, { createContext, ReactNode, useContext } from 'react';
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
- children: ReactNode;
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
- children: ReactNode;
83
- };
81
+ } & PropsWithChildren;
84
82
 
85
83
  export function SelectRangeProviderInternal({
86
84
  initialProps,
@@ -1,4 +1,4 @@
1
- import React from 'react';
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 React.MouseEvent;
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 React.MouseEvent;
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 React, { createContext, useContext } from 'react';
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: React.ReactNode;
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: React.ReactNode;
54
+ children: ReactNode;
55
55
  };
56
56
 
57
57
  export function SelectSingleProviderInternal({
@@ -1,6 +1,6 @@
1
- import React, { useState } from 'react';
1
+ import { Dispatch, SetStateAction, useState } from 'react';
2
2
 
3
- export type DispatchStateAction<T> = React.Dispatch<React.SetStateAction<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 React, { useEffect } from 'react';
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: React.RefObject<HTMLButtonElement>
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
- ): React.CSSProperties {
9
- let style: React.CSSProperties = {
10
+ ): CSSProperties {
11
+ let style: CSSProperties = {
10
12
  ...dayPicker.styles.day
11
13
  };
12
14
  Object.keys(activeModifiers).forEach((modifier) => {
@@ -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 * as React from 'react';
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] = React.useState(initialId);
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
- React.useEffect(() => {
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 React, { useState } from 'react';
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 InputHTMLAttributes = Pick<
18
- React.InputHTMLAttributes<HTMLInputElement>,
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: InputHTMLAttributes;
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: React.ChangeEventHandler<HTMLInputElement> = (e) => {
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: React.FocusEventHandler<HTMLInputElement> = (e) => {
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: React.FocusEventHandler<HTMLInputElement> = (e) => {
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: InputHTMLAttributes = {
174
+ const inputProps: InputProps = {
170
175
  onBlur: handleBlur,
171
176
  onChange: handleChange,
172
177
  onFocus: handleFocus,