react-day-picker 8.0.2 → 8.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/Head/utils/getWeekdays.d.ts +1 -1
- package/dist/components/Table/utils/daysToMonthWeeks.d.ts +1 -1
- package/dist/components/Table/utils/getMonthWeeks.d.ts +1 -1
- package/dist/contexts/DayPicker/formatters/formatCaption.d.ts +1 -1
- package/dist/contexts/DayPicker/formatters/formatDay.d.ts +1 -1
- package/dist/contexts/DayPicker/formatters/formatMonthCaption.d.ts +1 -1
- package/dist/contexts/DayPicker/formatters/formatWeekdayName.d.ts +1 -1
- package/dist/hooks/useDayRender/useDayRender.d.ts +1 -1
- package/dist/index.esm.js +30 -7
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +154 -107
- package/dist/index.js.map +1 -1
- package/dist/react-day-picker.min.js +1 -1
- package/dist/style.css +11 -10
- package/dist/style.module.css +11 -10
- package/dist/types/DayPickerBase.d.ts +1 -1
- package/dist/types/Labels.d.ts +1 -1
- package/package.json +15 -14
- 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 +311 -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,51 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
|
|
3
|
+
import es from 'date-fns/locale/es';
|
|
4
|
+
import { DayPickerProps } from 'DayPicker';
|
|
5
|
+
|
|
6
|
+
import { customRender } from 'test/render';
|
|
7
|
+
import { freezeBeforeAll } from 'test/utils';
|
|
8
|
+
|
|
9
|
+
import { DayContent, DayContentProps } from 'components/DayContent';
|
|
10
|
+
import { defaultClassNames } from 'contexts/DayPicker/defaultClassNames';
|
|
11
|
+
|
|
12
|
+
const today = new Date(2021, 8);
|
|
13
|
+
|
|
14
|
+
freezeBeforeAll(today);
|
|
15
|
+
let container: HTMLElement;
|
|
16
|
+
function setup(props: DayContentProps, dayPickerProps?: DayPickerProps) {
|
|
17
|
+
const view = customRender(<DayContent {...props} />, dayPickerProps);
|
|
18
|
+
container = view.container;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const date = today;
|
|
22
|
+
const displayMonth = today;
|
|
23
|
+
const props: DayContentProps = {
|
|
24
|
+
date: date,
|
|
25
|
+
displayMonth,
|
|
26
|
+
activeModifiers: {}
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
const dayPickerProps: DayPickerProps = {
|
|
30
|
+
locale: es
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
describe('when rendered', () => {
|
|
34
|
+
beforeEach(() => {
|
|
35
|
+
setup(props, dayPickerProps);
|
|
36
|
+
});
|
|
37
|
+
test('the first element is an aria-hidden element with the formatted day', () => {
|
|
38
|
+
expect(container.firstChild).toHaveAttribute('aria-hidden', 'true');
|
|
39
|
+
});
|
|
40
|
+
test('the first element contains the formatted day', () => {
|
|
41
|
+
expect(container.firstChild).toHaveTextContent('1');
|
|
42
|
+
});
|
|
43
|
+
test('the second element is visually hidden', () => {
|
|
44
|
+
expect(container.childNodes[1]).toHaveClass(defaultClassNames.vhidden);
|
|
45
|
+
});
|
|
46
|
+
test('the second element contains the formatted day', () => {
|
|
47
|
+
expect(container.childNodes[1]).toHaveTextContent(
|
|
48
|
+
'1º septiembre (miércoles)'
|
|
49
|
+
);
|
|
50
|
+
});
|
|
51
|
+
});
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
|
|
3
|
+
import { useDayPicker } from 'contexts/DayPicker';
|
|
4
|
+
import { ActiveModifiers } from 'types/Modifiers';
|
|
5
|
+
|
|
6
|
+
/** Represent the props for the [[DayContent]] component. */
|
|
7
|
+
export interface DayContentProps {
|
|
8
|
+
/** The date representing the day. */
|
|
9
|
+
date: Date;
|
|
10
|
+
/** The month where the day is displayed. */
|
|
11
|
+
displayMonth: Date;
|
|
12
|
+
/** The active modifiers for the given date. */
|
|
13
|
+
activeModifiers: ActiveModifiers;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Render the content of the day cell.
|
|
18
|
+
*/
|
|
19
|
+
export function DayContent(props: DayContentProps): JSX.Element {
|
|
20
|
+
const {
|
|
21
|
+
locale,
|
|
22
|
+
classNames,
|
|
23
|
+
styles,
|
|
24
|
+
labels: { labelDay },
|
|
25
|
+
formatters: { formatDay }
|
|
26
|
+
} = useDayPicker();
|
|
27
|
+
|
|
28
|
+
return (
|
|
29
|
+
<>
|
|
30
|
+
<span aria-hidden="true">{formatDay(props.date, { locale })}</span>
|
|
31
|
+
<span className={classNames.vhidden} style={styles.vhidden}>
|
|
32
|
+
{labelDay(props.date, props.activeModifiers, { locale })}
|
|
33
|
+
</span>
|
|
34
|
+
</>
|
|
35
|
+
);
|
|
36
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './DayContent';
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
|
|
3
|
+
import { fireEvent, screen } from '@testing-library/react';
|
|
4
|
+
import { DayPickerProps } from 'DayPicker';
|
|
5
|
+
|
|
6
|
+
import { customRender } from 'test/render';
|
|
7
|
+
import { freezeBeforeAll } from 'test/utils';
|
|
8
|
+
|
|
9
|
+
import { Dropdown, DropdownProps } from 'components/Dropdown';
|
|
10
|
+
import { defaultClassNames } from 'contexts/DayPicker/defaultClassNames';
|
|
11
|
+
import { CustomComponents } from 'types/DayPickerBase';
|
|
12
|
+
|
|
13
|
+
const today = new Date(2021, 8);
|
|
14
|
+
|
|
15
|
+
freezeBeforeAll(today);
|
|
16
|
+
|
|
17
|
+
function setup(props: DropdownProps, dayPickerProps?: DayPickerProps) {
|
|
18
|
+
customRender(<Dropdown {...props} />, dayPickerProps);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const props: Required<DropdownProps> = {
|
|
22
|
+
'aria-label': 'foo',
|
|
23
|
+
onChange: jest.fn(),
|
|
24
|
+
caption: 'Some caption',
|
|
25
|
+
className: 'test',
|
|
26
|
+
value: 'bar',
|
|
27
|
+
children: <option value={'bar'} />,
|
|
28
|
+
style: {}
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
describe('when rendered', () => {
|
|
32
|
+
let combobox: HTMLElement;
|
|
33
|
+
let label: HTMLElement;
|
|
34
|
+
|
|
35
|
+
beforeEach(() => {
|
|
36
|
+
setup(props);
|
|
37
|
+
combobox = screen.getByRole('combobox');
|
|
38
|
+
label = screen.getByText(props['aria-label']);
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
test('should render the vhidden aria label', () => {
|
|
42
|
+
expect(label).toHaveClass(defaultClassNames.vhidden);
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
test('should render the combobox', () => {
|
|
46
|
+
expect(combobox).toBeInTheDocument();
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
describe('when the combobox changes', () => {
|
|
50
|
+
beforeEach(() => {
|
|
51
|
+
fireEvent.change(combobox);
|
|
52
|
+
});
|
|
53
|
+
test('should call the "onChange" eve, nt handler', () => {
|
|
54
|
+
expect(props.onChange).toHaveBeenCalled();
|
|
55
|
+
});
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
test('should render the combobox with the given value', () => {
|
|
59
|
+
expect(combobox).toHaveValue(props.value);
|
|
60
|
+
});
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
describe('when using a custom IconDropdown component', () => {
|
|
64
|
+
const components: CustomComponents = {
|
|
65
|
+
IconDropdown: () => <div>Custom IconDropdown</div>
|
|
66
|
+
};
|
|
67
|
+
beforeEach(() => {
|
|
68
|
+
setup(props, { components });
|
|
69
|
+
});
|
|
70
|
+
test('it should render the custom component instead', () => {
|
|
71
|
+
expect(screen.getByText('Custom IconDropdown')).toBeInTheDocument();
|
|
72
|
+
});
|
|
73
|
+
});
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
|
|
3
|
+
import { IconDropdown } from 'components/IconDropdown';
|
|
4
|
+
import { useDayPicker } from 'contexts/DayPicker';
|
|
5
|
+
|
|
6
|
+
/** The props for the [[Dropdown]] component. */
|
|
7
|
+
export interface DropdownProps {
|
|
8
|
+
caption?: React.ReactNode;
|
|
9
|
+
children?: React.SelectHTMLAttributes<HTMLSelectElement>['children'];
|
|
10
|
+
className?: string;
|
|
11
|
+
['aria-label']?: string;
|
|
12
|
+
style?: React.CSSProperties;
|
|
13
|
+
value?: string | number;
|
|
14
|
+
onChange?: React.ChangeEventHandler<HTMLSelectElement>;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Render a styled select component – displaying a caption and a custom
|
|
19
|
+
* drop-down icon.
|
|
20
|
+
*/
|
|
21
|
+
export function Dropdown(props: DropdownProps): JSX.Element {
|
|
22
|
+
const { onChange, value, children, caption, className, style } = props;
|
|
23
|
+
const dayPicker = useDayPicker();
|
|
24
|
+
|
|
25
|
+
const IconDropdownComponent =
|
|
26
|
+
dayPicker.components?.IconDropdown ?? IconDropdown;
|
|
27
|
+
return (
|
|
28
|
+
<div className={className} style={style}>
|
|
29
|
+
<span className={dayPicker.classNames.vhidden}>
|
|
30
|
+
{props['aria-label']}
|
|
31
|
+
</span>
|
|
32
|
+
<select
|
|
33
|
+
aria-label={props['aria-label']}
|
|
34
|
+
className={dayPicker.classNames.dropdown}
|
|
35
|
+
style={dayPicker.styles.dropdown}
|
|
36
|
+
value={value}
|
|
37
|
+
onChange={onChange}
|
|
38
|
+
>
|
|
39
|
+
{children}
|
|
40
|
+
</select>
|
|
41
|
+
<div
|
|
42
|
+
className={dayPicker.classNames.caption_label}
|
|
43
|
+
style={dayPicker.styles.caption_label}
|
|
44
|
+
aria-hidden="true"
|
|
45
|
+
>
|
|
46
|
+
{caption}
|
|
47
|
+
{
|
|
48
|
+
<IconDropdownComponent
|
|
49
|
+
className={dayPicker.classNames.dropdown_icon}
|
|
50
|
+
style={dayPicker.styles.dropdown_icon}
|
|
51
|
+
/>
|
|
52
|
+
}
|
|
53
|
+
</div>
|
|
54
|
+
</div>
|
|
55
|
+
);
|
|
56
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './Dropdown';
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
|
|
3
|
+
import { getTableFooter, queryTableFooter } from 'test/po';
|
|
4
|
+
import { customRender } from 'test/render';
|
|
5
|
+
|
|
6
|
+
import { Footer } from './Footer';
|
|
7
|
+
|
|
8
|
+
customRender(
|
|
9
|
+
<table role="grid">
|
|
10
|
+
<Footer />
|
|
11
|
+
</table>
|
|
12
|
+
);
|
|
13
|
+
test('should not render anything as default', () => {
|
|
14
|
+
expect(queryTableFooter()).toBeNull();
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
describe('when using the `footer` prop', () => {
|
|
18
|
+
beforeEach(() => {
|
|
19
|
+
customRender(
|
|
20
|
+
<table role="grid">
|
|
21
|
+
<Footer />
|
|
22
|
+
</table>,
|
|
23
|
+
{ footer: 'footer_foo' }
|
|
24
|
+
);
|
|
25
|
+
});
|
|
26
|
+
test('should render the table footer', () => {
|
|
27
|
+
expect(getTableFooter()).toHaveTextContent('footer_foo');
|
|
28
|
+
});
|
|
29
|
+
});
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
|
|
3
|
+
import { useDayPicker } from 'contexts/DayPicker';
|
|
4
|
+
|
|
5
|
+
/** Render the Footer component (empty as default).*/
|
|
6
|
+
export function Footer(): JSX.Element {
|
|
7
|
+
const {
|
|
8
|
+
footer,
|
|
9
|
+
styles,
|
|
10
|
+
classNames: { tfoot }
|
|
11
|
+
} = useDayPicker();
|
|
12
|
+
if (!footer) return <></>;
|
|
13
|
+
return (
|
|
14
|
+
<tfoot className={tfoot} style={styles.tfoot}>
|
|
15
|
+
<tr>
|
|
16
|
+
<td colSpan={8}>{footer}</td>
|
|
17
|
+
</tr>
|
|
18
|
+
</tfoot>
|
|
19
|
+
);
|
|
20
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './Footer';
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
|
|
3
|
+
import { RenderResult, screen } from '@testing-library/react';
|
|
4
|
+
import { DayPickerProps } from 'DayPicker';
|
|
5
|
+
|
|
6
|
+
import { customRender } from 'test/render';
|
|
7
|
+
|
|
8
|
+
import { defaultClassNames } from 'contexts/DayPicker/defaultClassNames';
|
|
9
|
+
import { formatWeekdayName } from 'contexts/DayPicker/formatters';
|
|
10
|
+
import { labelWeekday } from 'contexts/DayPicker/labels';
|
|
11
|
+
|
|
12
|
+
import { Head } from './Head';
|
|
13
|
+
import { getWeekdays } from './utils/getWeekdays';
|
|
14
|
+
|
|
15
|
+
let container: HTMLElement;
|
|
16
|
+
let view: RenderResult;
|
|
17
|
+
|
|
18
|
+
let thElements: HTMLTableCellElement[];
|
|
19
|
+
|
|
20
|
+
function setup(dayPickerProps: DayPickerProps = {}) {
|
|
21
|
+
view = customRender(
|
|
22
|
+
<table>
|
|
23
|
+
<Head />
|
|
24
|
+
</table>,
|
|
25
|
+
dayPickerProps
|
|
26
|
+
);
|
|
27
|
+
container = view.container.firstChild as HTMLTableCellElement;
|
|
28
|
+
thElements = Array.from(container.getElementsByTagName('th'));
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const dayPickerProps = {
|
|
32
|
+
styles: {
|
|
33
|
+
head: { color: 'red' },
|
|
34
|
+
head_row: { color: 'blue' },
|
|
35
|
+
head_cell: { color: 'green' }
|
|
36
|
+
},
|
|
37
|
+
classNames: {
|
|
38
|
+
head: 'foo',
|
|
39
|
+
head_row: 'foo_row',
|
|
40
|
+
head_cell: 'foo_head-cell'
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
describe('when rendered', () => {
|
|
45
|
+
beforeEach(() => {
|
|
46
|
+
setup(dayPickerProps);
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
test('thead should have the `head` style', () => {
|
|
50
|
+
expect(container.firstChild).toHaveStyle(dayPickerProps.styles.head);
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
test('thead should have the `head` class', () => {
|
|
54
|
+
expect(container.firstChild).toHaveClass(dayPickerProps.classNames.head);
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
test('tr element should have the `head_row` style', () => {
|
|
58
|
+
expect(container.firstChild?.firstChild).toHaveStyle(
|
|
59
|
+
dayPickerProps.styles.head_row
|
|
60
|
+
);
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
test('tr element should have the `head_row` class', () => {
|
|
64
|
+
expect(container.firstChild?.firstChild).toHaveClass(
|
|
65
|
+
dayPickerProps.classNames.head_row
|
|
66
|
+
);
|
|
67
|
+
});
|
|
68
|
+
test('should render 7 head elements', () => {
|
|
69
|
+
expect(thElements).toHaveLength(7);
|
|
70
|
+
});
|
|
71
|
+
test('should render the head elements with the "head_cell" class name', () => {
|
|
72
|
+
thElements.forEach((el) => {
|
|
73
|
+
expect(el).toHaveClass(dayPickerProps.classNames.head_cell);
|
|
74
|
+
});
|
|
75
|
+
});
|
|
76
|
+
test('the formatted weekday name should be ARIA-hidden', () => {
|
|
77
|
+
const weekdays = getWeekdays();
|
|
78
|
+
weekdays.forEach((weekday) => {
|
|
79
|
+
const text = formatWeekdayName(weekday);
|
|
80
|
+
expect(screen.getByText(text)).toHaveAttribute('aria-hidden', 'true');
|
|
81
|
+
});
|
|
82
|
+
});
|
|
83
|
+
test('the label should not be visible', () => {
|
|
84
|
+
const weekdays = getWeekdays();
|
|
85
|
+
weekdays.forEach((weekday) => {
|
|
86
|
+
const text = labelWeekday(weekday);
|
|
87
|
+
expect(screen.getByText(text)).toHaveClass(defaultClassNames.vhidden);
|
|
88
|
+
});
|
|
89
|
+
});
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
describe('when showing the week numbers', () => {
|
|
93
|
+
beforeEach(() => {
|
|
94
|
+
setup({ ...dayPickerProps, showWeekNumber: true });
|
|
95
|
+
});
|
|
96
|
+
test('should render 8 head elements', () => {
|
|
97
|
+
expect(thElements).toHaveLength(8);
|
|
98
|
+
});
|
|
99
|
+
test('the first head element should be empty', () => {
|
|
100
|
+
expect(thElements[0]).toHaveTextContent('');
|
|
101
|
+
});
|
|
102
|
+
test('should render the head elements with the "head_cell" class name', () => {
|
|
103
|
+
thElements.forEach((el) => {
|
|
104
|
+
expect(el).toHaveClass(dayPickerProps.classNames.head_cell);
|
|
105
|
+
});
|
|
106
|
+
});
|
|
107
|
+
test('should render the head elements with the "head_cell" style', () => {
|
|
108
|
+
thElements.forEach((el) => {
|
|
109
|
+
expect(el).toHaveStyle(dayPickerProps.styles.head_cell);
|
|
110
|
+
});
|
|
111
|
+
});
|
|
112
|
+
test('should render the head elements with the "col" scope', () => {
|
|
113
|
+
thElements.forEach((el) => {
|
|
114
|
+
expect(el).toHaveAttribute('scope', 'col');
|
|
115
|
+
});
|
|
116
|
+
});
|
|
117
|
+
});
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
|
|
3
|
+
import { useDayPicker } from 'contexts/DayPicker';
|
|
4
|
+
|
|
5
|
+
import { getWeekdays } from './utils';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Render the Head component - i.e. the table head with the weekday names.
|
|
9
|
+
*/
|
|
10
|
+
export function Head(): JSX.Element {
|
|
11
|
+
const {
|
|
12
|
+
classNames,
|
|
13
|
+
styles,
|
|
14
|
+
showWeekNumber,
|
|
15
|
+
locale,
|
|
16
|
+
weekStartsOn,
|
|
17
|
+
formatters: { formatWeekdayName },
|
|
18
|
+
labels: { labelWeekday }
|
|
19
|
+
} = useDayPicker();
|
|
20
|
+
|
|
21
|
+
const weekdays = getWeekdays(locale, weekStartsOn);
|
|
22
|
+
|
|
23
|
+
return (
|
|
24
|
+
<thead style={styles.head} className={classNames.head}>
|
|
25
|
+
<tr style={styles.head_row} className={classNames.head_row}>
|
|
26
|
+
{showWeekNumber && (
|
|
27
|
+
<th
|
|
28
|
+
scope="col"
|
|
29
|
+
style={styles.head_cell}
|
|
30
|
+
className={classNames.head_cell}
|
|
31
|
+
></th>
|
|
32
|
+
)}
|
|
33
|
+
{weekdays.map((weekday, i) => (
|
|
34
|
+
<th
|
|
35
|
+
key={i}
|
|
36
|
+
scope="col"
|
|
37
|
+
className={classNames.head_cell}
|
|
38
|
+
style={styles.head_cell}
|
|
39
|
+
>
|
|
40
|
+
<span aria-hidden={true}>
|
|
41
|
+
{formatWeekdayName(weekday, { locale })}
|
|
42
|
+
</span>
|
|
43
|
+
<span className={classNames.vhidden}>
|
|
44
|
+
{labelWeekday(weekday, { locale })}
|
|
45
|
+
</span>
|
|
46
|
+
</th>
|
|
47
|
+
))}
|
|
48
|
+
</tr>
|
|
49
|
+
</thead>
|
|
50
|
+
);
|
|
51
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './Head';
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import es from 'date-fns/locale/es';
|
|
2
|
+
|
|
3
|
+
import { freezeBeforeAll } from 'test/utils';
|
|
4
|
+
|
|
5
|
+
import { getWeekdays } from './getWeekdays';
|
|
6
|
+
|
|
7
|
+
const today = new Date(2022, 1, 12);
|
|
8
|
+
const prevSunday = new Date(2022, 1, 6);
|
|
9
|
+
|
|
10
|
+
freezeBeforeAll(today);
|
|
11
|
+
|
|
12
|
+
let result: Date[];
|
|
13
|
+
|
|
14
|
+
describe('when rendered without a locale', () => {
|
|
15
|
+
beforeEach(() => {
|
|
16
|
+
result = getWeekdays();
|
|
17
|
+
});
|
|
18
|
+
test('should return 7 days', () => {
|
|
19
|
+
expect(result).toHaveLength(7);
|
|
20
|
+
});
|
|
21
|
+
test('should return Sunday as first day', () => {
|
|
22
|
+
expect(result[0]).toEqual(prevSunday);
|
|
23
|
+
});
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
describe.each<0 | 1 | 2 | 3 | 4 | 5 | 6>([0, 1, 2, 3, 4, 5, 6])(
|
|
27
|
+
'when week start on %s',
|
|
28
|
+
(weekStartsOn) => {
|
|
29
|
+
beforeEach(() => {
|
|
30
|
+
result = getWeekdays(es, weekStartsOn);
|
|
31
|
+
});
|
|
32
|
+
test('the first date should be weekStartsOn', () => {
|
|
33
|
+
expect(result[0].getDay()).toBe(weekStartsOn);
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
);
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import addDays from 'date-fns/addDays';
|
|
2
|
+
import startOfWeek from 'date-fns/startOfWeek';
|
|
3
|
+
|
|
4
|
+
import type { Locale } from 'date-fns';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Generate a series of 7 days, starting from the week, to use for formatting
|
|
8
|
+
* the weekday names (Monday, Tuesday, etc.).
|
|
9
|
+
*/
|
|
10
|
+
export function getWeekdays(
|
|
11
|
+
locale?: Locale,
|
|
12
|
+
/** The index of the first day of the week (0 - Sunday) */
|
|
13
|
+
weekStartsOn?: 0 | 1 | 2 | 3 | 4 | 5 | 6
|
|
14
|
+
): Date[] {
|
|
15
|
+
const start = startOfWeek(new Date(), { locale, weekStartsOn });
|
|
16
|
+
const days = [];
|
|
17
|
+
for (let i = 0; i < 7; i++) {
|
|
18
|
+
const day = addDays(start, i);
|
|
19
|
+
days.push(day);
|
|
20
|
+
}
|
|
21
|
+
return days;
|
|
22
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './getWeekdays';
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
|
|
3
|
+
import { customRender } from 'test/render';
|
|
4
|
+
|
|
5
|
+
import { IconDropdown } from './IconDropdown';
|
|
6
|
+
|
|
7
|
+
let root: HTMLElement;
|
|
8
|
+
|
|
9
|
+
beforeEach(() => {
|
|
10
|
+
const view = customRender(
|
|
11
|
+
<IconDropdown className="foo" style={{ color: 'red' }} />
|
|
12
|
+
);
|
|
13
|
+
root = view.container.firstChild as HTMLElement;
|
|
14
|
+
});
|
|
15
|
+
test('should add the class name', () => {
|
|
16
|
+
expect(root).toHaveClass('foo');
|
|
17
|
+
});
|
|
18
|
+
test('should apply the style', () => {
|
|
19
|
+
expect(root).toHaveStyle({ color: 'red' });
|
|
20
|
+
});
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
|
|
3
|
+
import { StyledComponent } from 'types/Styles';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Render the icon in the styled drop-down.
|
|
7
|
+
*/
|
|
8
|
+
export function IconDropdown(props: StyledComponent): JSX.Element {
|
|
9
|
+
return (
|
|
10
|
+
<svg
|
|
11
|
+
width="8px"
|
|
12
|
+
height="8px"
|
|
13
|
+
viewBox="0 0 120 120"
|
|
14
|
+
data-testid="iconDropdown"
|
|
15
|
+
{...props}
|
|
16
|
+
>
|
|
17
|
+
<path
|
|
18
|
+
d="M4.22182541,48.2218254 C8.44222828,44.0014225 15.2388494,43.9273804 19.5496459,47.9996989 L19.7781746,48.2218254 L60,88.443 L100.221825,48.2218254 C104.442228,44.0014225 111.238849,43.9273804 115.549646,47.9996989 L115.778175,48.2218254 C119.998577,52.4422283 120.07262,59.2388494 116.000301,63.5496459 L115.778175,63.7781746 L67.7781746,111.778175 C63.5577717,115.998577 56.7611506,116.07262 52.4503541,112.000301 L52.2218254,111.778175 L4.22182541,63.7781746 C-0.0739418023,59.4824074 -0.0739418023,52.5175926 4.22182541,48.2218254 Z"
|
|
19
|
+
fill="currentColor"
|
|
20
|
+
fillRule="nonzero"
|
|
21
|
+
></path>
|
|
22
|
+
</svg>
|
|
23
|
+
);
|
|
24
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './IconDropdown';
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
|
|
3
|
+
import { customRender } from 'test/render';
|
|
4
|
+
|
|
5
|
+
import { IconLeft } from './IconLeft';
|
|
6
|
+
|
|
7
|
+
let root: HTMLElement;
|
|
8
|
+
|
|
9
|
+
beforeEach(() => {
|
|
10
|
+
const view = customRender(
|
|
11
|
+
<IconLeft className="foo" style={{ color: 'red' }} />
|
|
12
|
+
);
|
|
13
|
+
root = view.container.firstChild as HTMLElement;
|
|
14
|
+
});
|
|
15
|
+
test('should add the class name', () => {
|
|
16
|
+
expect(root).toHaveClass('foo');
|
|
17
|
+
});
|
|
18
|
+
test('should apply the style', () => {
|
|
19
|
+
expect(root).toHaveStyle({ color: 'red' });
|
|
20
|
+
});
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
|
|
3
|
+
import { StyledComponent } from 'types/Styles';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Render the "previous month" button in the navigation.
|
|
7
|
+
*/
|
|
8
|
+
export function IconLeft(props: StyledComponent): JSX.Element {
|
|
9
|
+
return (
|
|
10
|
+
<svg width="16px" height="16px" viewBox="0 0 120 120" {...props}>
|
|
11
|
+
<path
|
|
12
|
+
d="M69.490332,3.34314575 C72.6145263,0.218951416 77.6798462,0.218951416 80.8040405,3.34314575 C83.8617626,6.40086786 83.9268205,11.3179931 80.9992143,14.4548388 L80.8040405,14.6568542 L35.461,60 L80.8040405,105.343146 C83.8617626,108.400868 83.9268205,113.317993 80.9992143,116.454839 L80.8040405,116.656854 C77.7463184,119.714576 72.8291931,119.779634 69.6923475,116.852028 L69.490332,116.656854 L18.490332,65.6568542 C15.4326099,62.5991321 15.367552,57.6820069 18.2951583,54.5451612 L18.490332,54.3431458 L69.490332,3.34314575 Z"
|
|
13
|
+
fill="currentColor"
|
|
14
|
+
fillRule="nonzero"
|
|
15
|
+
></path>
|
|
16
|
+
</svg>
|
|
17
|
+
);
|
|
18
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './IconLeft';
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
|
|
3
|
+
import { customRender } from 'test/render';
|
|
4
|
+
|
|
5
|
+
import { IconRight } from './IconRight';
|
|
6
|
+
|
|
7
|
+
let root: HTMLElement;
|
|
8
|
+
|
|
9
|
+
beforeEach(() => {
|
|
10
|
+
const view = customRender(
|
|
11
|
+
<IconRight className="foo" style={{ color: 'red' }} />
|
|
12
|
+
);
|
|
13
|
+
root = view.container.firstChild as HTMLElement;
|
|
14
|
+
});
|
|
15
|
+
test('should add the class name', () => {
|
|
16
|
+
expect(root).toHaveClass('foo');
|
|
17
|
+
});
|
|
18
|
+
test('should apply the style', () => {
|
|
19
|
+
expect(root).toHaveStyle({ color: 'red' });
|
|
20
|
+
});
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
|
|
3
|
+
import { StyledComponent } from 'types/Styles';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Render the "next month" button in the navigation.
|
|
7
|
+
*/
|
|
8
|
+
export function IconRight(props: StyledComponent): JSX.Element {
|
|
9
|
+
return (
|
|
10
|
+
<svg width="16px" height="16px" viewBox="0 0 120 120" {...props}>
|
|
11
|
+
<path
|
|
12
|
+
d="M49.8040405,3.34314575 C46.6798462,0.218951416 41.6145263,0.218951416 38.490332,3.34314575 C35.4326099,6.40086786 35.367552,11.3179931 38.2951583,14.4548388 L38.490332,14.6568542 L83.8333725,60 L38.490332,105.343146 C35.4326099,108.400868 35.367552,113.317993 38.2951583,116.454839 L38.490332,116.656854 C41.5480541,119.714576 46.4651794,119.779634 49.602025,116.852028 L49.8040405,116.656854 L100.804041,65.6568542 C103.861763,62.5991321 103.926821,57.6820069 100.999214,54.5451612 L100.804041,54.3431458 L49.8040405,3.34314575 Z"
|
|
13
|
+
fill="currentColor"
|
|
14
|
+
></path>
|
|
15
|
+
</svg>
|
|
16
|
+
);
|
|
17
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './IconRight';
|