v1.0 with SW PWA enabled
This commit is contained in:
210
frontend/node_modules/react-day-picker/src/contexts/DayPicker/DayPickerContext.test.ts
generated
vendored
Normal file
210
frontend/node_modules/react-day-picker/src/contexts/DayPicker/DayPickerContext.test.ts
generated
vendored
Normal file
@ -0,0 +1,210 @@
|
||||
/* eslint-disable testing-library/render-result-naming-convention */
|
||||
|
||||
import { es } from 'date-fns/locale';
|
||||
import { DayPickerProps } from 'DayPicker';
|
||||
|
||||
import { renderDayPickerHook } from 'test/render';
|
||||
import { freezeBeforeAll } from 'test/utils';
|
||||
|
||||
import { CaptionLayout } from 'components/Caption';
|
||||
import { DayPickerContextValue, useDayPicker } from 'contexts/DayPicker';
|
||||
import {
|
||||
DefaultContextProps,
|
||||
getDefaultContextValues
|
||||
} from 'contexts/DayPicker/defaultContextValues';
|
||||
import { DaySelectionMode } from 'types/DayPickerBase';
|
||||
import { Formatters } from 'types/Formatters';
|
||||
import { Labels } from 'types/Labels';
|
||||
import { DayModifiers, ModifiersClassNames } from 'types/Modifiers';
|
||||
import { ClassNames, Styles } from 'types/Styles';
|
||||
|
||||
const today = new Date(2022, 5, 13);
|
||||
const defaults = getDefaultContextValues();
|
||||
|
||||
freezeBeforeAll(today);
|
||||
|
||||
function renderHook(props?: DayPickerProps) {
|
||||
return renderDayPickerHook<DayPickerContextValue>(useDayPicker, props);
|
||||
}
|
||||
|
||||
describe('when rendered without props', () => {
|
||||
const testPropNames = Object.keys(defaults).filter(
|
||||
(key) => key !== 'today'
|
||||
) as DefaultContextProps[];
|
||||
test.each(testPropNames)('should use the %s default value', (propName) => {
|
||||
const result = renderHook();
|
||||
expect(result.current[propName]).toEqual(defaults[propName]);
|
||||
});
|
||||
});
|
||||
describe('when passing "locale" from props', () => {
|
||||
const locale = es;
|
||||
test('should return the custom locale', () => {
|
||||
const result = renderHook({ locale });
|
||||
expect(result.current.locale).toBe(locale);
|
||||
});
|
||||
});
|
||||
|
||||
describe('when passing "numberOfMonths" from props', () => {
|
||||
const numberOfMonths = 4;
|
||||
test('should return the custom numberOfMonths', () => {
|
||||
const result = renderHook({ numberOfMonths });
|
||||
expect(result.current.numberOfMonths).toBe(4);
|
||||
});
|
||||
});
|
||||
|
||||
describe('when passing "today" from props', () => {
|
||||
const today = new Date(2010, 9, 11);
|
||||
test('should return the custom "today"', () => {
|
||||
const result = renderHook({ today });
|
||||
expect(result.current.today).toBe(today);
|
||||
});
|
||||
});
|
||||
|
||||
describe('when passing "captionLayout" from props', () => {
|
||||
const captionLayout: CaptionLayout = 'dropdown';
|
||||
const fromYear = 2000;
|
||||
const toYear = 2010;
|
||||
const dayPickerProps: DayPickerProps = { captionLayout, fromYear, toYear };
|
||||
test('should return the custom "captionLayout"', () => {
|
||||
const result = renderHook(dayPickerProps);
|
||||
expect(result.current.captionLayout).toBe(captionLayout);
|
||||
});
|
||||
});
|
||||
|
||||
describe('when "fromDate" and "toDate" are undefined', () => {
|
||||
const fromDate = undefined;
|
||||
const toDate = undefined;
|
||||
describe('when using "dropdown" as "captionLayout"', () => {
|
||||
const captionLayout: CaptionLayout = 'dropdown';
|
||||
test('should return "buttons" as "captionLayout"', () => {
|
||||
const result = renderHook({
|
||||
fromDate,
|
||||
toDate,
|
||||
captionLayout
|
||||
});
|
||||
expect(result.current.captionLayout).toBe('buttons');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('when "fromDate" is undefined, but not "toDate"', () => {
|
||||
const fromDate = undefined;
|
||||
const toDate = new Date();
|
||||
|
||||
describe('when using "dropdown" as "captionLayout"', () => {
|
||||
const captionLayout: CaptionLayout = 'dropdown';
|
||||
test('should return "buttons" as "captionLayout"', () => {
|
||||
const result = renderHook({
|
||||
fromDate,
|
||||
toDate,
|
||||
captionLayout
|
||||
});
|
||||
expect(result.current.captionLayout).toBe('buttons');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('when "toDate" is undefined, but not "fromDate"', () => {
|
||||
const fromDate = new Date();
|
||||
const toDate = undefined;
|
||||
|
||||
describe('when using "dropdown" as "captionLayout"', () => {
|
||||
const captionLayout: CaptionLayout = 'dropdown';
|
||||
test('should return "buttons" as "captionLayout"', () => {
|
||||
const result = renderHook({
|
||||
fromDate,
|
||||
toDate,
|
||||
captionLayout
|
||||
});
|
||||
expect(result.current.captionLayout).toBe('buttons');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('when using "dropdown" as "captionLayout"', () => {
|
||||
const captionLayout: CaptionLayout = 'dropdown';
|
||||
const fromYear = 2000;
|
||||
const toYear = 2010;
|
||||
test('should return the custom "captionLayout"', () => {
|
||||
const result = renderHook({ captionLayout, fromYear, toYear });
|
||||
expect(result.current.captionLayout).toBe(captionLayout);
|
||||
});
|
||||
});
|
||||
|
||||
describe('when passing "modifiers" from props', () => {
|
||||
const modifiers: DayModifiers = { foo: new Date() };
|
||||
test('should return the custom "modifiers"', () => {
|
||||
const result = renderHook({ modifiers });
|
||||
expect(result.current.modifiers).toStrictEqual(modifiers);
|
||||
});
|
||||
});
|
||||
|
||||
describe('when passing "modifiersClassNames" from props', () => {
|
||||
const modifiersClassNames: ModifiersClassNames = { foo: 'bar' };
|
||||
test('should return the custom "modifiersClassNames"', () => {
|
||||
const result = renderHook({ modifiersClassNames });
|
||||
expect(result.current.modifiersClassNames).toStrictEqual(
|
||||
modifiersClassNames
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('when passing "styles" from props', () => {
|
||||
const styles: Styles = { caption: { color: 'red ' } };
|
||||
test('should include the custom "styles"', () => {
|
||||
const result = renderHook({ styles });
|
||||
expect(result.current.styles).toStrictEqual({
|
||||
...defaults.styles,
|
||||
...styles
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('when passing "classNames" from props', () => {
|
||||
const classNames: ClassNames = { caption: 'foo' };
|
||||
test('should include the custom "classNames"', () => {
|
||||
const result = renderHook({ classNames });
|
||||
expect(result.current.classNames).toStrictEqual({
|
||||
...defaults.classNames,
|
||||
...classNames
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('when passing "formatters" from props', () => {
|
||||
const formatters: Partial<Formatters> = { formatCaption: jest.fn() };
|
||||
test('should include the custom "formatters"', () => {
|
||||
const result = renderHook({ formatters });
|
||||
expect(result.current.formatters).toStrictEqual({
|
||||
...defaults.formatters,
|
||||
...formatters
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('when passing "labels" from props', () => {
|
||||
const labels: Partial<Labels> = { labelDay: jest.fn() };
|
||||
test('should include the custom "labels"', () => {
|
||||
const result = renderHook({ labels });
|
||||
expect(result.current.labels).toStrictEqual({
|
||||
...defaults.labels,
|
||||
...labels
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('when passing an "id" from props', () => {
|
||||
test('should return the id', () => {
|
||||
const result = renderHook({ id: 'foo' });
|
||||
expect(result.current.id).toBe('foo');
|
||||
});
|
||||
});
|
||||
|
||||
describe('when in selection mode', () => {
|
||||
const mode: DaySelectionMode = 'multiple';
|
||||
const onSelect = jest.fn();
|
||||
test('should return the "onSelect" event handler', () => {
|
||||
const result = renderHook({ mode, onSelect });
|
||||
expect(result.current.onSelect).toBe(onSelect);
|
||||
});
|
||||
});
|
||||
150
frontend/node_modules/react-day-picker/src/contexts/DayPicker/DayPickerContext.tsx
generated
vendored
Normal file
150
frontend/node_modules/react-day-picker/src/contexts/DayPicker/DayPickerContext.tsx
generated
vendored
Normal file
@ -0,0 +1,150 @@
|
||||
import { createContext, ReactNode, useContext } from 'react';
|
||||
|
||||
import { Locale } from 'date-fns';
|
||||
import { DayPickerProps } from 'DayPicker';
|
||||
|
||||
import { CaptionLayout } from 'components/Caption';
|
||||
import { DayPickerBase, DaySelectionMode } from 'types/DayPickerBase';
|
||||
import {
|
||||
DayPickerMultipleProps,
|
||||
isDayPickerMultiple
|
||||
} from 'types/DayPickerMultiple';
|
||||
import { DayPickerRangeProps, isDayPickerRange } from 'types/DayPickerRange';
|
||||
import { DayPickerSingleProps, isDayPickerSingle } from 'types/DayPickerSingle';
|
||||
import { Formatters } from 'types/Formatters';
|
||||
import { Labels } from 'types/Labels';
|
||||
import { Matcher } from 'types/Matchers';
|
||||
import { DayModifiers, ModifiersClassNames } from 'types/Modifiers';
|
||||
import { ClassNames, Styles } from 'types/Styles';
|
||||
|
||||
import { getDefaultContextValues } from './defaultContextValues';
|
||||
import { parseFromToProps } from './utils';
|
||||
|
||||
/**
|
||||
* The value of the {@link DayPickerContext} extends the props from DayPicker
|
||||
* with default and cleaned up values.
|
||||
*/
|
||||
export interface DayPickerContextValue extends DayPickerBase {
|
||||
mode: DaySelectionMode;
|
||||
onSelect?:
|
||||
| DayPickerSingleProps['onSelect']
|
||||
| DayPickerMultipleProps['onSelect']
|
||||
| DayPickerRangeProps['onSelect'];
|
||||
required?: boolean;
|
||||
min?: number;
|
||||
max?: number;
|
||||
selected?: Matcher | Matcher[];
|
||||
|
||||
captionLayout: CaptionLayout;
|
||||
classNames: Required<ClassNames>;
|
||||
formatters: Formatters;
|
||||
labels: Labels;
|
||||
locale: Locale;
|
||||
modifiersClassNames: ModifiersClassNames;
|
||||
modifiers: DayModifiers;
|
||||
numberOfMonths: number;
|
||||
styles: Styles;
|
||||
today: Date;
|
||||
}
|
||||
|
||||
/**
|
||||
* The DayPicker context shares the props passed to DayPicker within internal
|
||||
* and custom components. It is used to set the default values and perform
|
||||
* one-time calculations required to render the days.
|
||||
*
|
||||
* Access to this context from the {@link useDayPicker} hook.
|
||||
*/
|
||||
export const DayPickerContext = createContext<
|
||||
DayPickerContextValue | undefined
|
||||
>(undefined);
|
||||
|
||||
/** The props for the {@link DayPickerProvider}. */
|
||||
export interface DayPickerProviderProps {
|
||||
/** The initial props from the DayPicker component. */
|
||||
initialProps: DayPickerProps;
|
||||
children?: ReactNode;
|
||||
}
|
||||
/**
|
||||
* The provider for the {@link DayPickerContext}, assigning the defaults from the
|
||||
* initial DayPicker props.
|
||||
*/
|
||||
export function DayPickerProvider(props: DayPickerProviderProps): JSX.Element {
|
||||
const { initialProps } = props;
|
||||
|
||||
const defaultContextValues = getDefaultContextValues();
|
||||
|
||||
const { fromDate, toDate } = parseFromToProps(initialProps);
|
||||
|
||||
let captionLayout =
|
||||
initialProps.captionLayout ?? defaultContextValues.captionLayout;
|
||||
if (captionLayout !== 'buttons' && (!fromDate || !toDate)) {
|
||||
// When no from/to dates are set, the caption is always buttons
|
||||
captionLayout = 'buttons';
|
||||
}
|
||||
|
||||
let onSelect;
|
||||
if (
|
||||
isDayPickerSingle(initialProps) ||
|
||||
isDayPickerMultiple(initialProps) ||
|
||||
isDayPickerRange(initialProps)
|
||||
) {
|
||||
onSelect = initialProps.onSelect;
|
||||
}
|
||||
|
||||
const value: DayPickerContextValue = {
|
||||
...defaultContextValues,
|
||||
...initialProps,
|
||||
captionLayout,
|
||||
classNames: {
|
||||
...defaultContextValues.classNames,
|
||||
...initialProps.classNames
|
||||
},
|
||||
components: {
|
||||
...initialProps.components
|
||||
},
|
||||
formatters: {
|
||||
...defaultContextValues.formatters,
|
||||
...initialProps.formatters
|
||||
},
|
||||
fromDate,
|
||||
labels: {
|
||||
...defaultContextValues.labels,
|
||||
...initialProps.labels
|
||||
},
|
||||
mode: initialProps.mode || defaultContextValues.mode,
|
||||
modifiers: {
|
||||
...defaultContextValues.modifiers,
|
||||
...initialProps.modifiers
|
||||
},
|
||||
modifiersClassNames: {
|
||||
...defaultContextValues.modifiersClassNames,
|
||||
...initialProps.modifiersClassNames
|
||||
},
|
||||
onSelect,
|
||||
styles: {
|
||||
...defaultContextValues.styles,
|
||||
...initialProps.styles
|
||||
},
|
||||
toDate
|
||||
};
|
||||
|
||||
return (
|
||||
<DayPickerContext.Provider value={value}>
|
||||
{props.children}
|
||||
</DayPickerContext.Provider>
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Hook to access the {@link DayPickerContextValue}.
|
||||
*
|
||||
* Use the DayPicker context to access to the props passed to DayPicker inside
|
||||
* internal or custom components.
|
||||
*/
|
||||
export function useDayPicker(): DayPickerContextValue {
|
||||
const context = useContext(DayPickerContext);
|
||||
if (!context) {
|
||||
throw new Error(`useDayPicker must be used within a DayPickerProvider.`);
|
||||
}
|
||||
return context;
|
||||
}
|
||||
58
frontend/node_modules/react-day-picker/src/contexts/DayPicker/defaultClassNames.ts
generated
vendored
Normal file
58
frontend/node_modules/react-day-picker/src/contexts/DayPicker/defaultClassNames.ts
generated
vendored
Normal file
@ -0,0 +1,58 @@
|
||||
import { ClassNames } from 'types/Styles';
|
||||
|
||||
/**
|
||||
* The name of the default CSS classes.
|
||||
*/
|
||||
export const defaultClassNames: Required<ClassNames> = {
|
||||
root: 'rdp',
|
||||
multiple_months: 'rdp-multiple_months',
|
||||
with_weeknumber: 'rdp-with_weeknumber',
|
||||
vhidden: 'rdp-vhidden',
|
||||
button_reset: 'rdp-button_reset',
|
||||
button: 'rdp-button',
|
||||
|
||||
caption: 'rdp-caption',
|
||||
|
||||
caption_start: 'rdp-caption_start',
|
||||
caption_end: 'rdp-caption_end',
|
||||
caption_between: 'rdp-caption_between',
|
||||
caption_label: 'rdp-caption_label',
|
||||
|
||||
caption_dropdowns: 'rdp-caption_dropdowns',
|
||||
|
||||
dropdown: 'rdp-dropdown',
|
||||
dropdown_month: 'rdp-dropdown_month',
|
||||
dropdown_year: 'rdp-dropdown_year',
|
||||
dropdown_icon: 'rdp-dropdown_icon',
|
||||
|
||||
months: 'rdp-months',
|
||||
month: 'rdp-month',
|
||||
table: 'rdp-table',
|
||||
tbody: 'rdp-tbody',
|
||||
tfoot: 'rdp-tfoot',
|
||||
|
||||
head: 'rdp-head',
|
||||
head_row: 'rdp-head_row',
|
||||
head_cell: 'rdp-head_cell',
|
||||
|
||||
nav: 'rdp-nav',
|
||||
nav_button: 'rdp-nav_button',
|
||||
nav_button_previous: 'rdp-nav_button_previous',
|
||||
nav_button_next: 'rdp-nav_button_next',
|
||||
|
||||
nav_icon: 'rdp-nav_icon',
|
||||
|
||||
row: 'rdp-row',
|
||||
weeknumber: 'rdp-weeknumber',
|
||||
cell: 'rdp-cell',
|
||||
|
||||
day: 'rdp-day',
|
||||
day_today: 'rdp-day_today',
|
||||
day_outside: 'rdp-day_outside',
|
||||
day_selected: 'rdp-day_selected',
|
||||
day_disabled: 'rdp-day_disabled',
|
||||
day_hidden: 'rdp-day_hidden',
|
||||
day_range_start: 'rdp-day_range_start',
|
||||
day_range_end: 'rdp-day_range_end',
|
||||
day_range_middle: 'rdp-day_range_middle'
|
||||
};
|
||||
54
frontend/node_modules/react-day-picker/src/contexts/DayPicker/defaultContextValues.ts
generated
vendored
Normal file
54
frontend/node_modules/react-day-picker/src/contexts/DayPicker/defaultContextValues.ts
generated
vendored
Normal file
@ -0,0 +1,54 @@
|
||||
import { enUS } from 'date-fns/locale';
|
||||
|
||||
import { CaptionLayout } from 'components/Caption';
|
||||
import { DayPickerContextValue } from 'contexts/DayPicker';
|
||||
|
||||
import { defaultClassNames } from './defaultClassNames';
|
||||
import * as formatters from './formatters';
|
||||
import * as labels from './labels';
|
||||
|
||||
export type DefaultContextProps =
|
||||
| 'captionLayout'
|
||||
| 'classNames'
|
||||
| 'formatters'
|
||||
| 'locale'
|
||||
| 'labels'
|
||||
| 'modifiersClassNames'
|
||||
| 'modifiers'
|
||||
| 'numberOfMonths'
|
||||
| 'styles'
|
||||
| 'today'
|
||||
| 'mode';
|
||||
|
||||
export type DefaultContextValues = Pick<
|
||||
DayPickerContextValue,
|
||||
DefaultContextProps
|
||||
>;
|
||||
/**
|
||||
* Returns the default values to use in the DayPickerContext, in case they are
|
||||
* not passed down with the DayPicker initial props.
|
||||
*/
|
||||
export function getDefaultContextValues(): DefaultContextValues {
|
||||
const captionLayout: CaptionLayout = 'buttons';
|
||||
const classNames = defaultClassNames;
|
||||
const locale = enUS;
|
||||
const modifiersClassNames = {};
|
||||
const modifiers = {};
|
||||
const numberOfMonths = 1;
|
||||
const styles = {};
|
||||
const today = new Date();
|
||||
|
||||
return {
|
||||
captionLayout,
|
||||
classNames,
|
||||
formatters,
|
||||
labels,
|
||||
locale,
|
||||
modifiersClassNames,
|
||||
modifiers,
|
||||
numberOfMonths,
|
||||
styles,
|
||||
today,
|
||||
mode: 'default'
|
||||
};
|
||||
}
|
||||
15
frontend/node_modules/react-day-picker/src/contexts/DayPicker/formatters/formatCaption.test.ts
generated
vendored
Normal file
15
frontend/node_modules/react-day-picker/src/contexts/DayPicker/formatters/formatCaption.test.ts
generated
vendored
Normal file
@ -0,0 +1,15 @@
|
||||
import { es } from 'date-fns/locale';
|
||||
|
||||
import { formatCaption } from './formatCaption';
|
||||
|
||||
const date = new Date(2022, 10, 21);
|
||||
|
||||
test('should return the formatted caption', () => {
|
||||
expect(formatCaption(date)).toEqual('November 2022');
|
||||
});
|
||||
|
||||
describe('when a locale is passed in', () => {
|
||||
test('should format using the locale', () => {
|
||||
expect(formatCaption(date, { locale: es })).toEqual('noviembre 2022');
|
||||
});
|
||||
});
|
||||
11
frontend/node_modules/react-day-picker/src/contexts/DayPicker/formatters/formatCaption.ts
generated
vendored
Normal file
11
frontend/node_modules/react-day-picker/src/contexts/DayPicker/formatters/formatCaption.ts
generated
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
import { format, Locale } from 'date-fns';
|
||||
|
||||
/**
|
||||
* The default formatter for the caption.
|
||||
*/
|
||||
export function formatCaption(
|
||||
month: Date,
|
||||
options?: { locale?: Locale }
|
||||
): string {
|
||||
return format(month, 'LLLL y', options);
|
||||
}
|
||||
7
frontend/node_modules/react-day-picker/src/contexts/DayPicker/formatters/formatDay.test.ts
generated
vendored
Normal file
7
frontend/node_modules/react-day-picker/src/contexts/DayPicker/formatters/formatDay.test.ts
generated
vendored
Normal file
@ -0,0 +1,7 @@
|
||||
import { formatDay } from './formatDay';
|
||||
|
||||
const date = new Date(2022, 10, 21);
|
||||
|
||||
test('should return the formatted day', () => {
|
||||
expect(formatDay(date)).toEqual('21');
|
||||
});
|
||||
8
frontend/node_modules/react-day-picker/src/contexts/DayPicker/formatters/formatDay.ts
generated
vendored
Normal file
8
frontend/node_modules/react-day-picker/src/contexts/DayPicker/formatters/formatDay.ts
generated
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
import { format, Locale } from 'date-fns';
|
||||
|
||||
/**
|
||||
* The default formatter for the Day button.
|
||||
*/
|
||||
export function formatDay(day: Date, options?: { locale?: Locale }): string {
|
||||
return format(day, 'd', options);
|
||||
}
|
||||
15
frontend/node_modules/react-day-picker/src/contexts/DayPicker/formatters/formatMonthCaption.test.ts
generated
vendored
Normal file
15
frontend/node_modules/react-day-picker/src/contexts/DayPicker/formatters/formatMonthCaption.test.ts
generated
vendored
Normal file
@ -0,0 +1,15 @@
|
||||
import { es } from 'date-fns/locale';
|
||||
|
||||
import { formatMonthCaption } from './formatMonthCaption';
|
||||
|
||||
const date = new Date(2022, 10, 21);
|
||||
|
||||
test('should return the formatted month caption', () => {
|
||||
expect(formatMonthCaption(date)).toEqual('November');
|
||||
});
|
||||
|
||||
describe('when a locale is passed in', () => {
|
||||
test('should format using the locale', () => {
|
||||
expect(formatMonthCaption(date, { locale: es })).toEqual('noviembre');
|
||||
});
|
||||
});
|
||||
11
frontend/node_modules/react-day-picker/src/contexts/DayPicker/formatters/formatMonthCaption.ts
generated
vendored
Normal file
11
frontend/node_modules/react-day-picker/src/contexts/DayPicker/formatters/formatMonthCaption.ts
generated
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
import { format, Locale } from 'date-fns';
|
||||
|
||||
/**
|
||||
* The default formatter for the Month caption.
|
||||
*/
|
||||
export function formatMonthCaption(
|
||||
month: Date,
|
||||
options?: { locale?: Locale }
|
||||
): string {
|
||||
return format(month, 'LLLL', options);
|
||||
}
|
||||
5
frontend/node_modules/react-day-picker/src/contexts/DayPicker/formatters/formatWeekNumber.test.ts
generated
vendored
Normal file
5
frontend/node_modules/react-day-picker/src/contexts/DayPicker/formatters/formatWeekNumber.test.ts
generated
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
import { formatWeekNumber } from './formatWeekNumber';
|
||||
|
||||
test('should return the formatted week number', () => {
|
||||
expect(formatWeekNumber(10)).toEqual('10');
|
||||
});
|
||||
6
frontend/node_modules/react-day-picker/src/contexts/DayPicker/formatters/formatWeekNumber.ts
generated
vendored
Normal file
6
frontend/node_modules/react-day-picker/src/contexts/DayPicker/formatters/formatWeekNumber.ts
generated
vendored
Normal file
@ -0,0 +1,6 @@
|
||||
/**
|
||||
* The default formatter for the week number.
|
||||
*/
|
||||
export function formatWeekNumber(weekNumber: number): string {
|
||||
return `${weekNumber}`;
|
||||
}
|
||||
15
frontend/node_modules/react-day-picker/src/contexts/DayPicker/formatters/formatWeekdayName.test.ts
generated
vendored
Normal file
15
frontend/node_modules/react-day-picker/src/contexts/DayPicker/formatters/formatWeekdayName.test.ts
generated
vendored
Normal file
@ -0,0 +1,15 @@
|
||||
import { es } from 'date-fns/locale';
|
||||
|
||||
import { formatWeekdayName } from './formatWeekdayName';
|
||||
|
||||
const date = new Date(2022, 10, 21);
|
||||
|
||||
test('should return the formatted weekday name', () => {
|
||||
expect(formatWeekdayName(date)).toEqual('Mo');
|
||||
});
|
||||
|
||||
describe('when a locale is passed in', () => {
|
||||
test('should format using the locale', () => {
|
||||
expect(formatWeekdayName(date, { locale: es })).toEqual('lu');
|
||||
});
|
||||
});
|
||||
11
frontend/node_modules/react-day-picker/src/contexts/DayPicker/formatters/formatWeekdayName.ts
generated
vendored
Normal file
11
frontend/node_modules/react-day-picker/src/contexts/DayPicker/formatters/formatWeekdayName.ts
generated
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
import { format, Locale } from 'date-fns';
|
||||
|
||||
/**
|
||||
* The default formatter for the name of the weekday.
|
||||
*/
|
||||
export function formatWeekdayName(
|
||||
weekday: Date,
|
||||
options?: { locale?: Locale }
|
||||
): string {
|
||||
return format(weekday, 'cccccc', options);
|
||||
}
|
||||
7
frontend/node_modules/react-day-picker/src/contexts/DayPicker/formatters/formatYearCaption.test.ts
generated
vendored
Normal file
7
frontend/node_modules/react-day-picker/src/contexts/DayPicker/formatters/formatYearCaption.test.ts
generated
vendored
Normal file
@ -0,0 +1,7 @@
|
||||
import { formatYearCaption } from './formatYearCaption';
|
||||
|
||||
const date = new Date(2022, 10, 21);
|
||||
|
||||
test('should return the formatted weekday name', () => {
|
||||
expect(formatYearCaption(date)).toEqual('2022');
|
||||
});
|
||||
13
frontend/node_modules/react-day-picker/src/contexts/DayPicker/formatters/formatYearCaption.ts
generated
vendored
Normal file
13
frontend/node_modules/react-day-picker/src/contexts/DayPicker/formatters/formatYearCaption.ts
generated
vendored
Normal file
@ -0,0 +1,13 @@
|
||||
import { format, Locale } from 'date-fns';
|
||||
|
||||
/**
|
||||
* The default formatter for the Year caption.
|
||||
*/
|
||||
export function formatYearCaption(
|
||||
year: Date,
|
||||
options?: {
|
||||
locale?: Locale;
|
||||
}
|
||||
): string {
|
||||
return format(year, 'yyyy', options);
|
||||
}
|
||||
6
frontend/node_modules/react-day-picker/src/contexts/DayPicker/formatters/index.ts
generated
vendored
Normal file
6
frontend/node_modules/react-day-picker/src/contexts/DayPicker/formatters/index.ts
generated
vendored
Normal file
@ -0,0 +1,6 @@
|
||||
export * from './formatCaption';
|
||||
export * from './formatDay';
|
||||
export * from './formatMonthCaption';
|
||||
export * from './formatWeekNumber';
|
||||
export * from './formatWeekdayName';
|
||||
export * from './formatYearCaption';
|
||||
1
frontend/node_modules/react-day-picker/src/contexts/DayPicker/index.ts
generated
vendored
Normal file
1
frontend/node_modules/react-day-picker/src/contexts/DayPicker/index.ts
generated
vendored
Normal file
@ -0,0 +1 @@
|
||||
export * from './DayPickerContext';
|
||||
7
frontend/node_modules/react-day-picker/src/contexts/DayPicker/labels/index.ts
generated
vendored
Normal file
7
frontend/node_modules/react-day-picker/src/contexts/DayPicker/labels/index.ts
generated
vendored
Normal file
@ -0,0 +1,7 @@
|
||||
export * from './labelDay';
|
||||
export * from './labelMonthDropdown';
|
||||
export * from './labelNext';
|
||||
export * from './labelPrevious';
|
||||
export * from './labelWeekday';
|
||||
export * from './labelWeekNumber';
|
||||
export * from './labelYearDropdown';
|
||||
7
frontend/node_modules/react-day-picker/src/contexts/DayPicker/labels/labelDay.test.ts
generated
vendored
Normal file
7
frontend/node_modules/react-day-picker/src/contexts/DayPicker/labels/labelDay.test.ts
generated
vendored
Normal file
@ -0,0 +1,7 @@
|
||||
import { labelDay } from './labelDay';
|
||||
|
||||
const day = new Date(2022, 10, 21);
|
||||
|
||||
test('should return the day label', () => {
|
||||
expect(labelDay(day, {})).toEqual('21st November (Monday)');
|
||||
});
|
||||
10
frontend/node_modules/react-day-picker/src/contexts/DayPicker/labels/labelDay.ts
generated
vendored
Normal file
10
frontend/node_modules/react-day-picker/src/contexts/DayPicker/labels/labelDay.ts
generated
vendored
Normal file
@ -0,0 +1,10 @@
|
||||
import { format } from 'date-fns';
|
||||
|
||||
import { DayLabel } from 'types/Labels';
|
||||
|
||||
/**
|
||||
* The default ARIA label for the day button.
|
||||
*/
|
||||
export const labelDay: DayLabel = (day, activeModifiers, options): string => {
|
||||
return format(day, 'do MMMM (EEEE)', options);
|
||||
};
|
||||
5
frontend/node_modules/react-day-picker/src/contexts/DayPicker/labels/labelMonthDropdown.test.ts
generated
vendored
Normal file
5
frontend/node_modules/react-day-picker/src/contexts/DayPicker/labels/labelMonthDropdown.test.ts
generated
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
import { labelMonthDropdown } from './labelMonthDropdown';
|
||||
|
||||
test('should return the label', () => {
|
||||
expect(labelMonthDropdown()).toEqual('Month: ');
|
||||
});
|
||||
6
frontend/node_modules/react-day-picker/src/contexts/DayPicker/labels/labelMonthDropdown.ts
generated
vendored
Normal file
6
frontend/node_modules/react-day-picker/src/contexts/DayPicker/labels/labelMonthDropdown.ts
generated
vendored
Normal file
@ -0,0 +1,6 @@
|
||||
/**
|
||||
* The default ARIA label for the WeekNumber element.
|
||||
*/
|
||||
export const labelMonthDropdown = (): string => {
|
||||
return 'Month: ';
|
||||
};
|
||||
5
frontend/node_modules/react-day-picker/src/contexts/DayPicker/labels/labelNext.test.ts
generated
vendored
Normal file
5
frontend/node_modules/react-day-picker/src/contexts/DayPicker/labels/labelNext.test.ts
generated
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
import { labelNext } from './labelNext';
|
||||
|
||||
test('should return the label', () => {
|
||||
expect(labelNext()).toEqual('Go to next month');
|
||||
});
|
||||
8
frontend/node_modules/react-day-picker/src/contexts/DayPicker/labels/labelNext.ts
generated
vendored
Normal file
8
frontend/node_modules/react-day-picker/src/contexts/DayPicker/labels/labelNext.ts
generated
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
import { NavButtonLabel } from 'types/Labels';
|
||||
|
||||
/**
|
||||
* The default ARIA label for next month button in navigation
|
||||
*/
|
||||
export const labelNext: NavButtonLabel = (): string => {
|
||||
return 'Go to next month';
|
||||
};
|
||||
5
frontend/node_modules/react-day-picker/src/contexts/DayPicker/labels/labelPrevious.test.ts
generated
vendored
Normal file
5
frontend/node_modules/react-day-picker/src/contexts/DayPicker/labels/labelPrevious.test.ts
generated
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
import { labelPrevious } from './labelPrevious';
|
||||
|
||||
test('should return the label', () => {
|
||||
expect(labelPrevious()).toEqual('Go to previous month');
|
||||
});
|
||||
8
frontend/node_modules/react-day-picker/src/contexts/DayPicker/labels/labelPrevious.ts
generated
vendored
Normal file
8
frontend/node_modules/react-day-picker/src/contexts/DayPicker/labels/labelPrevious.ts
generated
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
import { NavButtonLabel } from 'types/Labels';
|
||||
|
||||
/**
|
||||
* The default ARIA label for previous month button in navigation
|
||||
*/
|
||||
export const labelPrevious: NavButtonLabel = (): string => {
|
||||
return 'Go to previous month';
|
||||
};
|
||||
5
frontend/node_modules/react-day-picker/src/contexts/DayPicker/labels/labelWeekNumber.test.ts
generated
vendored
Normal file
5
frontend/node_modules/react-day-picker/src/contexts/DayPicker/labels/labelWeekNumber.test.ts
generated
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
import { labelWeekNumber } from './labelWeekNumber';
|
||||
|
||||
test('should return the label', () => {
|
||||
expect(labelWeekNumber(2)).toEqual('Week n. 2');
|
||||
});
|
||||
8
frontend/node_modules/react-day-picker/src/contexts/DayPicker/labels/labelWeekNumber.ts
generated
vendored
Normal file
8
frontend/node_modules/react-day-picker/src/contexts/DayPicker/labels/labelWeekNumber.ts
generated
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
import { WeekNumberLabel } from 'types/Labels';
|
||||
|
||||
/**
|
||||
* The default ARIA label for the WeekNumber element.
|
||||
*/
|
||||
export const labelWeekNumber: WeekNumberLabel = (n): string => {
|
||||
return `Week n. ${n}`;
|
||||
};
|
||||
15
frontend/node_modules/react-day-picker/src/contexts/DayPicker/labels/labelWeekday.test.ts
generated
vendored
Normal file
15
frontend/node_modules/react-day-picker/src/contexts/DayPicker/labels/labelWeekday.test.ts
generated
vendored
Normal file
@ -0,0 +1,15 @@
|
||||
import { es } from 'date-fns/locale';
|
||||
|
||||
import { labelWeekday } from './labelWeekday';
|
||||
|
||||
const weekDay = new Date(2022, 10, 21);
|
||||
|
||||
test('should return the formatted weekday name', () => {
|
||||
expect(labelWeekday(weekDay)).toEqual('Monday');
|
||||
});
|
||||
|
||||
describe('when a locale is passed in', () => {
|
||||
test('should format using the locale', () => {
|
||||
expect(labelWeekday(weekDay, { locale: es })).toEqual('lunes');
|
||||
});
|
||||
});
|
||||
10
frontend/node_modules/react-day-picker/src/contexts/DayPicker/labels/labelWeekday.ts
generated
vendored
Normal file
10
frontend/node_modules/react-day-picker/src/contexts/DayPicker/labels/labelWeekday.ts
generated
vendored
Normal file
@ -0,0 +1,10 @@
|
||||
import { format } from 'date-fns';
|
||||
|
||||
import { WeekdayLabel } from 'types/Labels';
|
||||
|
||||
/**
|
||||
* The default ARIA label for the Weekday element.
|
||||
*/
|
||||
export const labelWeekday: WeekdayLabel = (day, options): string => {
|
||||
return format(day, 'cccc', options);
|
||||
};
|
||||
5
frontend/node_modules/react-day-picker/src/contexts/DayPicker/labels/labelYearDropdown.test.ts
generated
vendored
Normal file
5
frontend/node_modules/react-day-picker/src/contexts/DayPicker/labels/labelYearDropdown.test.ts
generated
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
import { labelYearDropdown } from './labelYearDropdown';
|
||||
|
||||
test('should return the label', () => {
|
||||
expect(labelYearDropdown()).toEqual('Year: ');
|
||||
});
|
||||
6
frontend/node_modules/react-day-picker/src/contexts/DayPicker/labels/labelYearDropdown.ts
generated
vendored
Normal file
6
frontend/node_modules/react-day-picker/src/contexts/DayPicker/labels/labelYearDropdown.ts
generated
vendored
Normal file
@ -0,0 +1,6 @@
|
||||
/**
|
||||
* The default ARIA label for the WeekNumber element.
|
||||
*/
|
||||
export const labelYearDropdown = (): string => {
|
||||
return 'Year: ';
|
||||
};
|
||||
1
frontend/node_modules/react-day-picker/src/contexts/DayPicker/utils/index.ts
generated
vendored
Normal file
1
frontend/node_modules/react-day-picker/src/contexts/DayPicker/utils/index.ts
generated
vendored
Normal file
@ -0,0 +1 @@
|
||||
export * from './parseFromToProps';
|
||||
47
frontend/node_modules/react-day-picker/src/contexts/DayPicker/utils/parseFromToProps.test.ts
generated
vendored
Normal file
47
frontend/node_modules/react-day-picker/src/contexts/DayPicker/utils/parseFromToProps.test.ts
generated
vendored
Normal file
@ -0,0 +1,47 @@
|
||||
import { parseFromToProps } from 'contexts/DayPicker/utils';
|
||||
|
||||
describe('when "fromMonth" is passed in', () => {
|
||||
const fromMonth = new Date(2021, 4, 3);
|
||||
const expectedFromDate = new Date(2021, 4, 1);
|
||||
const { fromDate } = parseFromToProps({ fromMonth });
|
||||
test('"fromDate" should be the start of that month', () => {
|
||||
expect(fromDate).toEqual(expectedFromDate);
|
||||
});
|
||||
describe('when "fromYear" is passed in', () => {
|
||||
test('"fromDate" should be the start of that month', () => {
|
||||
expect(fromDate).toEqual(expectedFromDate);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('when "fromYear" is passed in', () => {
|
||||
const fromYear = 2021;
|
||||
const expectedFromDate = new Date(2021, 0, 1);
|
||||
const { fromDate } = parseFromToProps({ fromYear });
|
||||
test('"fromDate" should be the start of that year', () => {
|
||||
expect(fromDate).toEqual(expectedFromDate);
|
||||
});
|
||||
});
|
||||
|
||||
describe('when "toMonth" is passed in', () => {
|
||||
const toMonth = new Date(2021, 4, 3);
|
||||
const expectedToDate = new Date(2021, 4, 31);
|
||||
const { toDate } = parseFromToProps({ toMonth });
|
||||
test('"toDate" should be the end of that month', () => {
|
||||
expect(toDate).toEqual(expectedToDate);
|
||||
});
|
||||
describe('when "fromYear" is passed in', () => {
|
||||
test('"toDate" should be the end of that month', () => {
|
||||
expect(toDate).toEqual(expectedToDate);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('when "toYear" is passed in', () => {
|
||||
const toYear = 2021;
|
||||
const expectedToDate = new Date(2021, 11, 31);
|
||||
const { toDate } = parseFromToProps({ toYear });
|
||||
test('"toDate" should be the end of that year', () => {
|
||||
expect(toDate).toEqual(expectedToDate);
|
||||
});
|
||||
});
|
||||
30
frontend/node_modules/react-day-picker/src/contexts/DayPicker/utils/parseFromToProps.ts
generated
vendored
Normal file
30
frontend/node_modules/react-day-picker/src/contexts/DayPicker/utils/parseFromToProps.ts
generated
vendored
Normal file
@ -0,0 +1,30 @@
|
||||
import { endOfMonth, startOfDay, startOfMonth } from 'date-fns';
|
||||
|
||||
import { DayPickerBase } from 'types/DayPickerBase';
|
||||
|
||||
/** Return the `fromDate` and `toDate` prop values values parsing the DayPicker props. */
|
||||
export function parseFromToProps(
|
||||
props: Pick<
|
||||
DayPickerBase,
|
||||
'fromYear' | 'toYear' | 'fromDate' | 'toDate' | 'fromMonth' | 'toMonth'
|
||||
>
|
||||
): { fromDate: Date | undefined; toDate: Date | undefined } {
|
||||
const { fromYear, toYear, fromMonth, toMonth } = props;
|
||||
let { fromDate, toDate } = props;
|
||||
|
||||
if (fromMonth) {
|
||||
fromDate = startOfMonth(fromMonth);
|
||||
} else if (fromYear) {
|
||||
fromDate = new Date(fromYear, 0, 1);
|
||||
}
|
||||
if (toMonth) {
|
||||
toDate = endOfMonth(toMonth);
|
||||
} else if (toYear) {
|
||||
toDate = new Date(toYear, 11, 31);
|
||||
}
|
||||
|
||||
return {
|
||||
fromDate: fromDate ? startOfDay(fromDate) : undefined,
|
||||
toDate: toDate ? startOfDay(toDate) : undefined
|
||||
};
|
||||
}
|
||||
156
frontend/node_modules/react-day-picker/src/contexts/Focus/FocusContext.test.ts
generated
vendored
Normal file
156
frontend/node_modules/react-day-picker/src/contexts/Focus/FocusContext.test.ts
generated
vendored
Normal file
@ -0,0 +1,156 @@
|
||||
import { act } from '@testing-library/react';
|
||||
import {
|
||||
addDays,
|
||||
addMonths,
|
||||
addWeeks,
|
||||
addYears,
|
||||
endOfWeek,
|
||||
startOfWeek
|
||||
} from 'date-fns';
|
||||
|
||||
import { renderDayPickerHook, RenderHookResult } from 'test/render';
|
||||
import { freezeBeforeAll } from 'test/utils';
|
||||
|
||||
import { FocusContextValue, useFocusContext } from 'contexts/Focus';
|
||||
|
||||
const today = new Date(2021, 11, 8); // make sure is in the middle of the week for the complete test
|
||||
freezeBeforeAll(today);
|
||||
|
||||
function renderHook() {
|
||||
return renderDayPickerHook<FocusContextValue>(useFocusContext);
|
||||
}
|
||||
|
||||
type HookFunction =
|
||||
| 'focusDayAfter'
|
||||
| 'focusDayBefore'
|
||||
| 'focusWeekAfter'
|
||||
| 'focusWeekBefore'
|
||||
| 'focusMonthBefore'
|
||||
| 'focusMonthAfter'
|
||||
| 'focusYearBefore'
|
||||
| 'focusYearAfter'
|
||||
| 'focusStartOfWeek'
|
||||
| 'focusEndOfWeek';
|
||||
|
||||
test('`focusedDay` should be undefined', () => {
|
||||
const result = renderHook();
|
||||
expect(result.current.focusedDay).toBeUndefined();
|
||||
});
|
||||
|
||||
const tests: Array<HookFunction> = [
|
||||
'focusDayAfter',
|
||||
'focusDayBefore',
|
||||
'focusWeekAfter',
|
||||
'focusWeekBefore',
|
||||
'focusMonthBefore',
|
||||
'focusMonthAfter',
|
||||
'focusYearBefore',
|
||||
'focusYearAfter',
|
||||
'focusStartOfWeek',
|
||||
'focusEndOfWeek'
|
||||
];
|
||||
describe.each(tests)('when calling %s', (fn: HookFunction) => {
|
||||
test('`focusedDay` should be undefined', () => {
|
||||
const result = renderHook();
|
||||
result.current[fn];
|
||||
expect(result.current.focusedDay).toBeUndefined();
|
||||
});
|
||||
});
|
||||
|
||||
describe('when a day is focused', () => {
|
||||
const day = today;
|
||||
let result: RenderHookResult<FocusContextValue>;
|
||||
beforeEach(() => {
|
||||
result = renderHook();
|
||||
act(() => result.current.focus(day));
|
||||
});
|
||||
test('should set the focused day', () => {
|
||||
expect(result.current.focusedDay).toEqual(day);
|
||||
});
|
||||
describe('when "focusDayBefore" is called', () => {
|
||||
const dayBefore = addDays(day, -1);
|
||||
beforeEach(() => act(() => result.current.focusDayBefore()));
|
||||
test('should focus the day before', () => {
|
||||
expect(result.current.focusedDay).toEqual(dayBefore);
|
||||
});
|
||||
test.todo('should call the navigation goToDate');
|
||||
});
|
||||
describe('when "focusDayAfter" is called', () => {
|
||||
beforeEach(() => act(() => result.current.focusDayAfter()));
|
||||
test('should focus the day after', () => {
|
||||
const dayAfter = addDays(day, 1);
|
||||
expect(result.current.focusedDay).toEqual(dayAfter);
|
||||
});
|
||||
test.todo('should call the navigation goToDate');
|
||||
});
|
||||
describe('when "focusWeekBefore" is called', () => {
|
||||
beforeEach(() => act(() => result.current.focusWeekBefore()));
|
||||
test('should focus the day in the previous week', () => {
|
||||
const prevWeek = addWeeks(day, -1);
|
||||
expect(result.current.focusedDay).toEqual(prevWeek);
|
||||
});
|
||||
test.todo('should call the navigation goToDate');
|
||||
});
|
||||
describe('when "focusWeekAfter" is called', () => {
|
||||
beforeEach(() => act(() => result.current.focusWeekAfter()));
|
||||
test('should focus the day in the next week', () => {
|
||||
const nextWeek = addWeeks(day, 1);
|
||||
expect(result.current.focusedDay).toEqual(nextWeek);
|
||||
});
|
||||
test.todo('should call the navigation goToDate');
|
||||
});
|
||||
describe('when "focusStartOfWeek" is called', () => {
|
||||
beforeEach(() => act(() => result.current.focusStartOfWeek()));
|
||||
test('should focus the first day of the week', () => {
|
||||
const firstDayOfWeek = startOfWeek(day);
|
||||
expect(result.current.focusedDay).toEqual(firstDayOfWeek);
|
||||
});
|
||||
test.todo('should call the navigation goToDate');
|
||||
});
|
||||
describe('when "focusEndOfWeek" is called', () => {
|
||||
beforeEach(() => act(() => result.current.focusEndOfWeek()));
|
||||
test('should focus the last day of the week', () => {
|
||||
const lastDayOfWeek = endOfWeek(day);
|
||||
expect(result.current.focusedDay).toEqual(lastDayOfWeek);
|
||||
});
|
||||
test.todo('should call the navigation goToDate');
|
||||
});
|
||||
describe('when "focusMonthBefore" is called', () => {
|
||||
beforeEach(() => act(() => result.current.focusMonthBefore()));
|
||||
test('should focus the day in the month before', () => {
|
||||
const monthBefore = addMonths(day, -1);
|
||||
expect(result.current.focusedDay).toEqual(monthBefore);
|
||||
});
|
||||
test.todo('should call the navigation goToDate');
|
||||
});
|
||||
describe('when "focusMonthAfter" is called', () => {
|
||||
beforeEach(() => act(() => result.current.focusMonthAfter()));
|
||||
test('should focus the day in the month after', () => {
|
||||
const monthAfter = addMonths(day, 1);
|
||||
expect(result.current.focusedDay).toEqual(monthAfter);
|
||||
});
|
||||
test.todo('should call the navigation goToDate');
|
||||
});
|
||||
describe('when "focusYearBefore" is called', () => {
|
||||
beforeEach(() => act(() => result.current.focusYearBefore()));
|
||||
test('should focus the day in the year before', () => {
|
||||
const prevYear = addYears(day, -1);
|
||||
expect(result.current.focusedDay).toEqual(prevYear);
|
||||
});
|
||||
test.todo('should call the navigation goToDate');
|
||||
});
|
||||
describe('when "focusYearAfter" is called', () => {
|
||||
beforeEach(() => act(() => result.current.focusYearAfter()));
|
||||
test('should focus the day in the year after', () => {
|
||||
const nextYear = addYears(day, 1);
|
||||
expect(result.current.focusedDay).toEqual(nextYear);
|
||||
});
|
||||
test.todo('should call the navigation goToDate');
|
||||
});
|
||||
describe('when blur is called', () => {
|
||||
beforeEach(() => act(() => result.current.blur()));
|
||||
test('`focusedDay` should be undefined', () => {
|
||||
expect(result.current.focusedDay).toBeUndefined();
|
||||
});
|
||||
});
|
||||
});
|
||||
137
frontend/node_modules/react-day-picker/src/contexts/Focus/FocusContext.tsx
generated
vendored
Normal file
137
frontend/node_modules/react-day-picker/src/contexts/Focus/FocusContext.tsx
generated
vendored
Normal file
@ -0,0 +1,137 @@
|
||||
import { createContext, ReactNode, useContext, useState } from 'react';
|
||||
|
||||
import { isSameDay } from 'date-fns';
|
||||
|
||||
import { useDayPicker } from 'contexts/DayPicker';
|
||||
|
||||
import { useModifiers } from '../Modifiers';
|
||||
import { useNavigation } from '../Navigation';
|
||||
import { getInitialFocusTarget } from './utils/getInitialFocusTarget';
|
||||
import {
|
||||
getNextFocus,
|
||||
MoveFocusBy,
|
||||
MoveFocusDirection
|
||||
} from './utils/getNextFocus';
|
||||
|
||||
/** Represents the value of the {@link FocusContext}. */
|
||||
export type FocusContextValue = {
|
||||
/** The day currently focused. */
|
||||
focusedDay: Date | undefined;
|
||||
/** Day that will be focused. */
|
||||
focusTarget: Date | undefined;
|
||||
/** Focus a day. */
|
||||
focus: (day: Date) => void;
|
||||
/** Blur the focused day. */
|
||||
blur: () => void;
|
||||
/** Focus the day after the focused day. */
|
||||
focusDayAfter: () => void;
|
||||
/** Focus the day before the focused day. */
|
||||
focusDayBefore: () => void;
|
||||
/** Focus the day in the week before the focused day. */
|
||||
focusWeekBefore: () => void;
|
||||
/** Focus the day in the week after the focused day. */
|
||||
focusWeekAfter: () => void;
|
||||
/* Focus the day in the month before the focused day. */
|
||||
focusMonthBefore: () => void;
|
||||
/* Focus the day in the month after the focused day. */
|
||||
focusMonthAfter: () => void;
|
||||
/* Focus the day in the year before the focused day. */
|
||||
focusYearBefore: () => void;
|
||||
/* Focus the day in the year after the focused day. */
|
||||
focusYearAfter: () => void;
|
||||
/* Focus the day at the start of the week of the focused day. */
|
||||
focusStartOfWeek: () => void;
|
||||
/* Focus the day at the end of the week of focused day. */
|
||||
focusEndOfWeek: () => void;
|
||||
};
|
||||
|
||||
/**
|
||||
* The Focus context shares details about the focused day for the keyboard
|
||||
*
|
||||
* Access this context from the {@link useFocusContext} hook.
|
||||
*/
|
||||
export const FocusContext = createContext<FocusContextValue | undefined>(
|
||||
undefined
|
||||
);
|
||||
|
||||
export type FocusProviderProps = { children: ReactNode };
|
||||
|
||||
/** The provider for the {@link FocusContext}. */
|
||||
export function FocusProvider(props: FocusProviderProps): JSX.Element {
|
||||
const navigation = useNavigation();
|
||||
const modifiers = useModifiers();
|
||||
|
||||
const [focusedDay, setFocusedDay] = useState<Date | undefined>();
|
||||
const [lastFocused, setLastFocused] = useState<Date | undefined>();
|
||||
|
||||
const initialFocusTarget = getInitialFocusTarget(
|
||||
navigation.displayMonths,
|
||||
modifiers
|
||||
);
|
||||
|
||||
// TODO: cleanup and test obscure code below
|
||||
const focusTarget =
|
||||
focusedDay ?? (lastFocused && navigation.isDateDisplayed(lastFocused))
|
||||
? lastFocused
|
||||
: initialFocusTarget;
|
||||
|
||||
const blur = () => {
|
||||
setLastFocused(focusedDay);
|
||||
setFocusedDay(undefined);
|
||||
};
|
||||
const focus = (date: Date) => {
|
||||
setFocusedDay(date);
|
||||
};
|
||||
|
||||
const context = useDayPicker();
|
||||
|
||||
const moveFocus = (moveBy: MoveFocusBy, direction: MoveFocusDirection) => {
|
||||
if (!focusedDay) return;
|
||||
const nextFocused = getNextFocus(focusedDay, {
|
||||
moveBy,
|
||||
direction,
|
||||
context,
|
||||
modifiers
|
||||
});
|
||||
if (isSameDay(focusedDay, nextFocused)) return undefined;
|
||||
navigation.goToDate(nextFocused, focusedDay);
|
||||
focus(nextFocused);
|
||||
};
|
||||
|
||||
const value: FocusContextValue = {
|
||||
focusedDay,
|
||||
focusTarget,
|
||||
blur,
|
||||
focus,
|
||||
focusDayAfter: () => moveFocus('day', 'after'),
|
||||
focusDayBefore: () => moveFocus('day', 'before'),
|
||||
focusWeekAfter: () => moveFocus('week', 'after'),
|
||||
focusWeekBefore: () => moveFocus('week', 'before'),
|
||||
focusMonthBefore: () => moveFocus('month', 'before'),
|
||||
focusMonthAfter: () => moveFocus('month', 'after'),
|
||||
focusYearBefore: () => moveFocus('year', 'before'),
|
||||
focusYearAfter: () => moveFocus('year', 'after'),
|
||||
focusStartOfWeek: () => moveFocus('startOfWeek', 'before'),
|
||||
focusEndOfWeek: () => moveFocus('endOfWeek', 'after')
|
||||
};
|
||||
|
||||
return (
|
||||
<FocusContext.Provider value={value}>
|
||||
{props.children}
|
||||
</FocusContext.Provider>
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Hook to access the {@link FocusContextValue}. Use this hook to handle the
|
||||
* focus state of the elements.
|
||||
*
|
||||
* This hook is meant to be used inside internal or custom components.
|
||||
*/
|
||||
export function useFocusContext(): FocusContextValue {
|
||||
const context = useContext(FocusContext);
|
||||
if (!context) {
|
||||
throw new Error('useFocusContext must be used within a FocusProvider');
|
||||
}
|
||||
return context;
|
||||
}
|
||||
1
frontend/node_modules/react-day-picker/src/contexts/Focus/index.ts
generated
vendored
Normal file
1
frontend/node_modules/react-day-picker/src/contexts/Focus/index.ts
generated
vendored
Normal file
@ -0,0 +1 @@
|
||||
export * from './FocusContext';
|
||||
41
frontend/node_modules/react-day-picker/src/contexts/Focus/utils/getInitialFocusTarget.test.ts
generated
vendored
Normal file
41
frontend/node_modules/react-day-picker/src/contexts/Focus/utils/getInitialFocusTarget.test.ts
generated
vendored
Normal file
@ -0,0 +1,41 @@
|
||||
import { Modifiers } from 'types/Modifiers';
|
||||
|
||||
import { getInitialFocusTarget } from './getInitialFocusTarget';
|
||||
|
||||
describe('when no days are selected is selected', () => {
|
||||
test('should return the first day of month', () => {
|
||||
const displayMonth = new Date(2022, 7);
|
||||
const modifiers: Modifiers = {
|
||||
outside: [],
|
||||
disabled: [],
|
||||
selected: [],
|
||||
hidden: [],
|
||||
today: [],
|
||||
range_start: [],
|
||||
range_end: [],
|
||||
range_middle: []
|
||||
};
|
||||
const initialFocusTarget = getInitialFocusTarget([displayMonth], modifiers);
|
||||
expect(initialFocusTarget).toStrictEqual(displayMonth);
|
||||
});
|
||||
});
|
||||
|
||||
describe('when a day is selected', () => {
|
||||
test('should return the selected day', () => {
|
||||
const displayMonths = [new Date(2022, 7)];
|
||||
const selectedDay1 = new Date(2022, 7, 17);
|
||||
const selectedDay2 = new Date(2022, 7, 19);
|
||||
const modifiers: Modifiers = {
|
||||
outside: [],
|
||||
disabled: [],
|
||||
selected: [selectedDay1, selectedDay2],
|
||||
hidden: [],
|
||||
today: [],
|
||||
range_start: [],
|
||||
range_end: [],
|
||||
range_middle: []
|
||||
};
|
||||
const initialFocusTarget = getInitialFocusTarget(displayMonths, modifiers);
|
||||
expect(initialFocusTarget).toStrictEqual(selectedDay1);
|
||||
});
|
||||
});
|
||||
48
frontend/node_modules/react-day-picker/src/contexts/Focus/utils/getInitialFocusTarget.ts
generated
vendored
Normal file
48
frontend/node_modules/react-day-picker/src/contexts/Focus/utils/getInitialFocusTarget.ts
generated
vendored
Normal file
@ -0,0 +1,48 @@
|
||||
import { addDays, endOfMonth, startOfMonth } from 'date-fns';
|
||||
|
||||
import { getActiveModifiers } from 'contexts/Modifiers';
|
||||
import { Modifiers } from 'types/Modifiers';
|
||||
|
||||
/**
|
||||
* Returns the day that should be the target of the focus when DayPicker is
|
||||
* rendered the first time.
|
||||
*
|
||||
* TODO: this function doesn't consider if the day is outside the month. We
|
||||
* implemented this check in `useDayRender` but it should probably go here. See
|
||||
* https://github.com/gpbl/react-day-picker/pull/1576
|
||||
*/
|
||||
export function getInitialFocusTarget(
|
||||
displayMonths: Date[],
|
||||
modifiers: Modifiers
|
||||
) {
|
||||
const firstDayInMonth = startOfMonth(displayMonths[0]);
|
||||
const lastDayInMonth = endOfMonth(displayMonths[displayMonths.length - 1]);
|
||||
|
||||
// TODO: cleanup code
|
||||
let firstFocusableDay;
|
||||
let today;
|
||||
let date = firstDayInMonth;
|
||||
while (date <= lastDayInMonth) {
|
||||
const activeModifiers = getActiveModifiers(date, modifiers);
|
||||
const isFocusable = !activeModifiers.disabled && !activeModifiers.hidden;
|
||||
if (!isFocusable) {
|
||||
date = addDays(date, 1);
|
||||
continue;
|
||||
}
|
||||
if (activeModifiers.selected) {
|
||||
return date;
|
||||
}
|
||||
if (activeModifiers.today && !today) {
|
||||
today = date;
|
||||
}
|
||||
if (!firstFocusableDay) {
|
||||
firstFocusableDay = date;
|
||||
}
|
||||
date = addDays(date, 1);
|
||||
}
|
||||
if (today) {
|
||||
return today;
|
||||
} else {
|
||||
return firstFocusableDay;
|
||||
}
|
||||
}
|
||||
264
frontend/node_modules/react-day-picker/src/contexts/Focus/utils/getNextFocus.test.ts
generated
vendored
Normal file
264
frontend/node_modules/react-day-picker/src/contexts/Focus/utils/getNextFocus.test.ts
generated
vendored
Normal file
@ -0,0 +1,264 @@
|
||||
/* eslint-disable jest/no-standalone-expect */
|
||||
import { addDays, format, parseISO } from 'date-fns';
|
||||
|
||||
import {
|
||||
InternalModifier,
|
||||
InternalModifiers,
|
||||
Modifiers
|
||||
} from 'types/Modifiers';
|
||||
|
||||
import {
|
||||
FocusDayPickerContext,
|
||||
getNextFocus,
|
||||
MoveFocusBy,
|
||||
MoveFocusDirection
|
||||
} from './getNextFocus';
|
||||
|
||||
type test = {
|
||||
focusedDay: string;
|
||||
moveBy: MoveFocusBy;
|
||||
direction: MoveFocusDirection;
|
||||
context: FocusDayPickerContext;
|
||||
expectedNextFocus: string;
|
||||
};
|
||||
|
||||
const tests: test[] = [
|
||||
{
|
||||
focusedDay: '2022-08-17',
|
||||
moveBy: 'day',
|
||||
direction: 'after',
|
||||
context: {},
|
||||
expectedNextFocus: '2022-08-18'
|
||||
},
|
||||
{
|
||||
focusedDay: '2022-08-17',
|
||||
moveBy: 'day',
|
||||
direction: 'before',
|
||||
context: {},
|
||||
expectedNextFocus: '2022-08-16'
|
||||
},
|
||||
{
|
||||
focusedDay: '2022-08-17',
|
||||
moveBy: 'week',
|
||||
direction: 'after',
|
||||
context: {},
|
||||
expectedNextFocus: '2022-08-24'
|
||||
},
|
||||
{
|
||||
focusedDay: '2022-08-17',
|
||||
moveBy: 'week',
|
||||
direction: 'before',
|
||||
context: {},
|
||||
expectedNextFocus: '2022-08-10'
|
||||
},
|
||||
{
|
||||
focusedDay: '2022-08-17',
|
||||
moveBy: 'month',
|
||||
direction: 'after',
|
||||
context: {},
|
||||
expectedNextFocus: '2022-09-17'
|
||||
},
|
||||
{
|
||||
focusedDay: '2022-08-17',
|
||||
moveBy: 'startOfWeek',
|
||||
direction: 'before',
|
||||
context: {
|
||||
weekStartsOn: 1
|
||||
},
|
||||
expectedNextFocus: '2022-08-15'
|
||||
},
|
||||
{
|
||||
focusedDay: '2022-08-17',
|
||||
moveBy: 'endOfWeek',
|
||||
direction: 'before',
|
||||
context: {
|
||||
weekStartsOn: 1
|
||||
},
|
||||
expectedNextFocus: '2022-08-21'
|
||||
},
|
||||
{
|
||||
focusedDay: '2022-08-17',
|
||||
moveBy: 'month',
|
||||
direction: 'after',
|
||||
context: {},
|
||||
expectedNextFocus: '2022-09-17'
|
||||
},
|
||||
{
|
||||
focusedDay: '2022-08-17',
|
||||
moveBy: 'year',
|
||||
direction: 'before',
|
||||
context: {},
|
||||
expectedNextFocus: '2021-08-17'
|
||||
},
|
||||
{
|
||||
focusedDay: '2022-08-17',
|
||||
moveBy: 'year',
|
||||
direction: 'after',
|
||||
context: {},
|
||||
expectedNextFocus: '2023-08-17'
|
||||
}
|
||||
];
|
||||
|
||||
describe.each(tests)(
|
||||
'when focusing the $moveBy $direction $focusedDay',
|
||||
({ focusedDay, moveBy, direction, context, expectedNextFocus }) => {
|
||||
test(`should return ${expectedNextFocus}`, () => {
|
||||
const nextFocus = getNextFocus(parseISO(focusedDay), {
|
||||
moveBy,
|
||||
direction,
|
||||
context
|
||||
});
|
||||
expect(format(nextFocus, 'yyyy-MM-dd')).toBe(expectedNextFocus);
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
describe('when reaching the "fromDate"', () => {
|
||||
const focusedDay = new Date();
|
||||
const fromDate = addDays(focusedDay, -1);
|
||||
test('next focus should be "fromDate"', () => {
|
||||
const nextFocus = getNextFocus(focusedDay, {
|
||||
moveBy: 'day',
|
||||
direction: 'before',
|
||||
context: { fromDate }
|
||||
});
|
||||
expect(nextFocus).toStrictEqual(fromDate);
|
||||
});
|
||||
});
|
||||
|
||||
describe('when reaching the "toDate"', () => {
|
||||
const focusedDay = new Date();
|
||||
const toDate = addDays(focusedDay, 1);
|
||||
test('next focus should be "toDate"', () => {
|
||||
const nextFocus = getNextFocus(focusedDay, {
|
||||
moveBy: 'day',
|
||||
direction: 'after',
|
||||
context: { toDate }
|
||||
});
|
||||
expect(nextFocus).toStrictEqual(toDate);
|
||||
});
|
||||
});
|
||||
|
||||
const emptyModifiers: Modifiers = {
|
||||
outside: [],
|
||||
disabled: [],
|
||||
selected: [],
|
||||
hidden: [],
|
||||
today: [],
|
||||
range_start: [],
|
||||
range_end: [],
|
||||
range_middle: []
|
||||
};
|
||||
|
||||
type ModifiersTest = {
|
||||
focusedDay: string;
|
||||
skippedDay: string;
|
||||
moveBy: MoveFocusBy;
|
||||
direction: MoveFocusDirection;
|
||||
modifierName: InternalModifier;
|
||||
expectedNextFocus: string;
|
||||
fromDate?: string;
|
||||
toDate?: string;
|
||||
};
|
||||
|
||||
const modifiersTest: ModifiersTest[] = [
|
||||
{
|
||||
focusedDay: '2022-08-17',
|
||||
skippedDay: '2022-08-18',
|
||||
moveBy: 'day',
|
||||
direction: 'after',
|
||||
modifierName: InternalModifier.Hidden,
|
||||
expectedNextFocus: '2022-08-19'
|
||||
},
|
||||
{
|
||||
focusedDay: '2022-08-17',
|
||||
skippedDay: '2022-08-18',
|
||||
moveBy: 'day',
|
||||
direction: 'after',
|
||||
modifierName: InternalModifier.Disabled,
|
||||
expectedNextFocus: '2022-08-19'
|
||||
},
|
||||
{
|
||||
focusedDay: '2022-08-17',
|
||||
skippedDay: '2022-08-16',
|
||||
moveBy: 'day',
|
||||
direction: 'before',
|
||||
modifierName: InternalModifier.Hidden,
|
||||
expectedNextFocus: '2022-08-15'
|
||||
},
|
||||
{
|
||||
focusedDay: '2022-08-17',
|
||||
skippedDay: '2022-08-16',
|
||||
moveBy: 'day',
|
||||
direction: 'before',
|
||||
modifierName: InternalModifier.Disabled,
|
||||
expectedNextFocus: '2022-08-15'
|
||||
},
|
||||
{
|
||||
focusedDay: '2022-08-17',
|
||||
skippedDay: '2022-08-16',
|
||||
fromDate: '2022-08-01',
|
||||
moveBy: 'month',
|
||||
direction: 'before',
|
||||
modifierName: InternalModifier.Disabled,
|
||||
expectedNextFocus: '2022-08-01'
|
||||
},
|
||||
{
|
||||
focusedDay: '2022-08-17',
|
||||
skippedDay: '2022-08-16',
|
||||
toDate: '2022-08-31',
|
||||
moveBy: 'month',
|
||||
direction: 'after',
|
||||
modifierName: InternalModifier.Disabled,
|
||||
expectedNextFocus: '2022-08-31'
|
||||
}
|
||||
];
|
||||
describe.each(modifiersTest)(
|
||||
'when focusing the $moveBy $direction $focusedDay with $modifierName modifier',
|
||||
(modifierTest) => {
|
||||
const modifiers: InternalModifiers = {
|
||||
...emptyModifiers,
|
||||
[modifierTest.modifierName]: [parseISO(modifierTest.skippedDay)]
|
||||
};
|
||||
const context = {
|
||||
fromDate: modifierTest.fromDate
|
||||
? parseISO(modifierTest.fromDate)
|
||||
: undefined,
|
||||
toDate: modifierTest.toDate ? parseISO(modifierTest.toDate) : undefined
|
||||
};
|
||||
test(`should skip the ${modifierTest.modifierName} day`, () => {
|
||||
const nextFocus = getNextFocus(parseISO(modifierTest.focusedDay), {
|
||||
moveBy: modifierTest.moveBy,
|
||||
direction: modifierTest.direction,
|
||||
context,
|
||||
modifiers
|
||||
});
|
||||
expect(format(nextFocus, 'yyyy-MM-dd')).toBe(
|
||||
modifierTest.expectedNextFocus
|
||||
);
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
test('should avoid infinite recursion', () => {
|
||||
const focusedDay = new Date(2022, 7, 17);
|
||||
const modifiers: Modifiers = {
|
||||
outside: [],
|
||||
disabled: [{ after: focusedDay }],
|
||||
selected: [],
|
||||
hidden: [],
|
||||
today: [],
|
||||
range_start: [],
|
||||
range_end: [],
|
||||
range_middle: []
|
||||
};
|
||||
|
||||
const nextFocus = getNextFocus(focusedDay, {
|
||||
moveBy: 'day',
|
||||
direction: 'after',
|
||||
modifiers,
|
||||
context: {}
|
||||
});
|
||||
|
||||
expect(nextFocus).toStrictEqual(focusedDay);
|
||||
});
|
||||
104
frontend/node_modules/react-day-picker/src/contexts/Focus/utils/getNextFocus.ts
generated
vendored
Normal file
104
frontend/node_modules/react-day-picker/src/contexts/Focus/utils/getNextFocus.ts
generated
vendored
Normal file
@ -0,0 +1,104 @@
|
||||
import {
|
||||
addDays,
|
||||
addMonths,
|
||||
addWeeks,
|
||||
addYears,
|
||||
endOfISOWeek,
|
||||
endOfWeek,
|
||||
max,
|
||||
min,
|
||||
startOfISOWeek,
|
||||
startOfWeek
|
||||
} from 'date-fns';
|
||||
|
||||
import { DayPickerContextValue } from 'contexts/DayPicker';
|
||||
import { getActiveModifiers } from 'contexts/Modifiers';
|
||||
import { Modifiers } from 'types/Modifiers';
|
||||
|
||||
export type MoveFocusBy =
|
||||
| 'day'
|
||||
| 'week'
|
||||
| 'startOfWeek'
|
||||
| 'endOfWeek'
|
||||
| 'month'
|
||||
| 'year';
|
||||
|
||||
export type MoveFocusDirection = 'after' | 'before';
|
||||
|
||||
export type FocusDayPickerContext = Partial<
|
||||
Pick<
|
||||
DayPickerContextValue,
|
||||
'ISOWeek' | 'weekStartsOn' | 'fromDate' | 'toDate' | 'locale'
|
||||
>
|
||||
>;
|
||||
|
||||
export type FocusDayOptions = {
|
||||
moveBy: MoveFocusBy;
|
||||
direction: MoveFocusDirection;
|
||||
context: FocusDayPickerContext;
|
||||
modifiers?: Modifiers;
|
||||
retry?: { count: number; lastFocused: Date };
|
||||
};
|
||||
|
||||
const MAX_RETRY = 365;
|
||||
|
||||
/** Return the next date to be focused. */
|
||||
export function getNextFocus(focusedDay: Date, options: FocusDayOptions): Date {
|
||||
const {
|
||||
moveBy,
|
||||
direction,
|
||||
context,
|
||||
modifiers,
|
||||
retry = { count: 0, lastFocused: focusedDay }
|
||||
} = options;
|
||||
const { weekStartsOn, fromDate, toDate, locale } = context;
|
||||
|
||||
const moveFns = {
|
||||
day: addDays,
|
||||
week: addWeeks,
|
||||
month: addMonths,
|
||||
year: addYears,
|
||||
startOfWeek: (date: Date) =>
|
||||
context.ISOWeek
|
||||
? startOfISOWeek(date)
|
||||
: startOfWeek(date, { locale, weekStartsOn }),
|
||||
endOfWeek: (date: Date) =>
|
||||
context.ISOWeek
|
||||
? endOfISOWeek(date)
|
||||
: endOfWeek(date, { locale, weekStartsOn })
|
||||
};
|
||||
|
||||
let newFocusedDay = moveFns[moveBy](
|
||||
focusedDay,
|
||||
direction === 'after' ? 1 : -1
|
||||
);
|
||||
|
||||
if (direction === 'before' && fromDate) {
|
||||
newFocusedDay = max([fromDate, newFocusedDay]);
|
||||
} else if (direction === 'after' && toDate) {
|
||||
newFocusedDay = min([toDate, newFocusedDay]);
|
||||
}
|
||||
let isFocusable = true;
|
||||
|
||||
if (modifiers) {
|
||||
const activeModifiers = getActiveModifiers(newFocusedDay, modifiers);
|
||||
isFocusable = !activeModifiers.disabled && !activeModifiers.hidden;
|
||||
}
|
||||
if (isFocusable) {
|
||||
return newFocusedDay;
|
||||
} else {
|
||||
if (retry.count > MAX_RETRY) {
|
||||
return retry.lastFocused;
|
||||
}
|
||||
return getNextFocus(newFocusedDay, {
|
||||
moveBy,
|
||||
direction,
|
||||
context,
|
||||
modifiers,
|
||||
retry: {
|
||||
...retry,
|
||||
count: retry.count + 1
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
40
frontend/node_modules/react-day-picker/src/contexts/Modifiers/ModifiersContext.test.ts
generated
vendored
Normal file
40
frontend/node_modules/react-day-picker/src/contexts/Modifiers/ModifiersContext.test.ts
generated
vendored
Normal file
@ -0,0 +1,40 @@
|
||||
import { DayPickerProps } from 'DayPicker';
|
||||
|
||||
import { renderDayPickerHook } from 'test/render';
|
||||
|
||||
import { useModifiers } from 'contexts/Modifiers';
|
||||
import { DayModifiers, InternalModifier, Modifiers } from 'types/Modifiers';
|
||||
|
||||
const internalModifiers = Object.values(InternalModifier);
|
||||
|
||||
function renderHook(dayPickerProps: Partial<DayPickerProps> = {}) {
|
||||
return renderDayPickerHook<Modifiers>(useModifiers, dayPickerProps);
|
||||
}
|
||||
|
||||
describe('when rendered with custom modifiers', () => {
|
||||
const modifier = new Date(2018, 11, 12);
|
||||
const dayModifiers: DayModifiers = {
|
||||
foo: modifier,
|
||||
today: modifier,
|
||||
outside: modifier,
|
||||
disabled: modifier,
|
||||
selected: modifier,
|
||||
hidden: modifier,
|
||||
range_start: modifier,
|
||||
range_end: modifier,
|
||||
range_middle: modifier
|
||||
};
|
||||
test('should return the custom modifiers', () => {
|
||||
const result = renderHook({ modifiers: dayModifiers });
|
||||
expect(result.current.foo).toEqual([dayModifiers.foo]);
|
||||
});
|
||||
test.each(internalModifiers)(
|
||||
'should override the %s internal modifier',
|
||||
(internalModifier) => {
|
||||
const result = renderHook({ modifiers: dayModifiers });
|
||||
expect(result.current[internalModifier]).toEqual([
|
||||
dayModifiers[internalModifier]
|
||||
]);
|
||||
}
|
||||
);
|
||||
});
|
||||
57
frontend/node_modules/react-day-picker/src/contexts/Modifiers/ModifiersContext.tsx
generated
vendored
Normal file
57
frontend/node_modules/react-day-picker/src/contexts/Modifiers/ModifiersContext.tsx
generated
vendored
Normal file
@ -0,0 +1,57 @@
|
||||
import { createContext, useContext, ReactNode } from 'react';
|
||||
|
||||
import { useDayPicker } from 'contexts/DayPicker';
|
||||
import { useSelectMultiple } from 'contexts/SelectMultiple';
|
||||
import { useSelectRange } from 'contexts/SelectRange';
|
||||
import { CustomModifiers, InternalModifiers, Modifiers } from 'types/Modifiers';
|
||||
|
||||
import { getCustomModifiers } from './utils/getCustomModifiers';
|
||||
import { getInternalModifiers } from './utils/getInternalModifiers';
|
||||
|
||||
/** The Modifiers context store the modifiers used in DayPicker. To access the value of this context, use {@link useModifiers}. */
|
||||
export const ModifiersContext = createContext<Modifiers | undefined>(undefined);
|
||||
|
||||
export type ModifiersProviderProps = { children: ReactNode };
|
||||
|
||||
/** Provide the value for the {@link ModifiersContext}. */
|
||||
export function ModifiersProvider(props: ModifiersProviderProps): JSX.Element {
|
||||
const dayPicker = useDayPicker();
|
||||
const selectMultiple = useSelectMultiple();
|
||||
const selectRange = useSelectRange();
|
||||
|
||||
const internalModifiers: InternalModifiers = getInternalModifiers(
|
||||
dayPicker,
|
||||
selectMultiple,
|
||||
selectRange
|
||||
);
|
||||
|
||||
const customModifiers: CustomModifiers = getCustomModifiers(
|
||||
dayPicker.modifiers
|
||||
);
|
||||
|
||||
const modifiers: Modifiers = {
|
||||
...internalModifiers,
|
||||
...customModifiers
|
||||
};
|
||||
|
||||
return (
|
||||
<ModifiersContext.Provider value={modifiers}>
|
||||
{props.children}
|
||||
</ModifiersContext.Provider>
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the modifiers used by DayPicker.
|
||||
*
|
||||
* This hook is meant to be used inside internal or custom components.
|
||||
* Requires to be wrapped into {@link ModifiersProvider}.
|
||||
*
|
||||
*/
|
||||
export function useModifiers(): Modifiers {
|
||||
const context = useContext(ModifiersContext);
|
||||
if (!context) {
|
||||
throw new Error('useModifiers must be used within a ModifiersProvider');
|
||||
}
|
||||
return context;
|
||||
}
|
||||
2
frontend/node_modules/react-day-picker/src/contexts/Modifiers/index.ts
generated
vendored
Normal file
2
frontend/node_modules/react-day-picker/src/contexts/Modifiers/index.ts
generated
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
export * from './ModifiersContext';
|
||||
export * from './utils/getActiveModifiers';
|
||||
53
frontend/node_modules/react-day-picker/src/contexts/Modifiers/utils/getActiveModifiers.test.ts
generated
vendored
Normal file
53
frontend/node_modules/react-day-picker/src/contexts/Modifiers/utils/getActiveModifiers.test.ts
generated
vendored
Normal file
@ -0,0 +1,53 @@
|
||||
import { addMonths } from 'date-fns';
|
||||
|
||||
import {
|
||||
InternalModifier,
|
||||
InternalModifiers,
|
||||
Modifiers
|
||||
} from 'types/Modifiers';
|
||||
|
||||
import { getActiveModifiers } from './getActiveModifiers';
|
||||
|
||||
const day = new Date();
|
||||
|
||||
const internalModifiers: InternalModifiers = {
|
||||
[InternalModifier.Outside]: [],
|
||||
[InternalModifier.Disabled]: [],
|
||||
[InternalModifier.Selected]: [],
|
||||
[InternalModifier.Hidden]: [],
|
||||
[InternalModifier.Today]: [],
|
||||
[InternalModifier.RangeStart]: [],
|
||||
[InternalModifier.RangeEnd]: [],
|
||||
[InternalModifier.RangeMiddle]: []
|
||||
};
|
||||
describe('when the day matches a modifier', () => {
|
||||
const modifiers: Modifiers = {
|
||||
...internalModifiers,
|
||||
foo: [day]
|
||||
};
|
||||
const result = getActiveModifiers(day, modifiers);
|
||||
test('should return the modifier as active', () => {
|
||||
expect(result.foo).toBe(true);
|
||||
});
|
||||
});
|
||||
describe('when the day does not match a modifier', () => {
|
||||
const modifiers: Modifiers = {
|
||||
...internalModifiers,
|
||||
foo: []
|
||||
};
|
||||
const result = getActiveModifiers(day, modifiers);
|
||||
test('should not return the modifier as active', () => {
|
||||
expect(result.foo).toBeUndefined();
|
||||
});
|
||||
});
|
||||
|
||||
describe('when the day is not in the same display month', () => {
|
||||
const modifiers: Modifiers = {
|
||||
...internalModifiers
|
||||
};
|
||||
const displayMonth = addMonths(day, 1);
|
||||
const result = getActiveModifiers(day, modifiers, displayMonth);
|
||||
test('should not return the modifier as active', () => {
|
||||
expect(result.outside).toBe(true);
|
||||
});
|
||||
});
|
||||
33
frontend/node_modules/react-day-picker/src/contexts/Modifiers/utils/getActiveModifiers.ts
generated
vendored
Normal file
33
frontend/node_modules/react-day-picker/src/contexts/Modifiers/utils/getActiveModifiers.ts
generated
vendored
Normal file
@ -0,0 +1,33 @@
|
||||
import { isSameMonth } from 'date-fns';
|
||||
|
||||
import { ActiveModifiers, Modifiers } from 'types/Modifiers';
|
||||
|
||||
import { isMatch } from './isMatch';
|
||||
|
||||
/** Return the active modifiers for the given day. */
|
||||
export function getActiveModifiers(
|
||||
day: Date,
|
||||
/** The modifiers to match for the given date. */
|
||||
modifiers: Modifiers,
|
||||
/** The month where the day is displayed, to add the "outside" modifiers. */
|
||||
displayMonth?: Date
|
||||
): ActiveModifiers {
|
||||
const matchedModifiers = Object.keys(modifiers).reduce(
|
||||
(result: string[], key: string): string[] => {
|
||||
const modifier = modifiers[key];
|
||||
if (isMatch(day, modifier)) {
|
||||
result.push(key);
|
||||
}
|
||||
return result;
|
||||
},
|
||||
[]
|
||||
);
|
||||
const activeModifiers: ActiveModifiers = {};
|
||||
matchedModifiers.forEach((modifier) => (activeModifiers[modifier] = true));
|
||||
|
||||
if (displayMonth && !isSameMonth(day, displayMonth)) {
|
||||
activeModifiers.outside = true;
|
||||
}
|
||||
|
||||
return activeModifiers;
|
||||
}
|
||||
14
frontend/node_modules/react-day-picker/src/contexts/Modifiers/utils/getCustomModifiers.test.ts
generated
vendored
Normal file
14
frontend/node_modules/react-day-picker/src/contexts/Modifiers/utils/getCustomModifiers.test.ts
generated
vendored
Normal file
@ -0,0 +1,14 @@
|
||||
import { DayModifiers } from 'index';
|
||||
|
||||
import { getCustomModifiers } from './getCustomModifiers';
|
||||
|
||||
describe('when some modifiers are not an array', () => {
|
||||
const date = new Date();
|
||||
const dayModifiers: DayModifiers = {
|
||||
foo: date
|
||||
};
|
||||
const result = getCustomModifiers(dayModifiers);
|
||||
test('should return as array', () => {
|
||||
expect(result.foo).toEqual([date]);
|
||||
});
|
||||
});
|
||||
14
frontend/node_modules/react-day-picker/src/contexts/Modifiers/utils/getCustomModifiers.ts
generated
vendored
Normal file
14
frontend/node_modules/react-day-picker/src/contexts/Modifiers/utils/getCustomModifiers.ts
generated
vendored
Normal file
@ -0,0 +1,14 @@
|
||||
import { CustomModifiers, DayModifiers } from 'types/Modifiers';
|
||||
|
||||
import { matcherToArray } from './matcherToArray';
|
||||
|
||||
/** Create CustomModifiers from dayModifiers */
|
||||
export function getCustomModifiers(
|
||||
dayModifiers: DayModifiers
|
||||
): CustomModifiers {
|
||||
const customModifiers: CustomModifiers = {};
|
||||
Object.entries(dayModifiers).forEach(([modifier, matcher]) => {
|
||||
customModifiers[modifier] = matcherToArray(matcher);
|
||||
});
|
||||
return customModifiers;
|
||||
}
|
||||
147
frontend/node_modules/react-day-picker/src/contexts/Modifiers/utils/getInternalModifiers.test.ts
generated
vendored
Normal file
147
frontend/node_modules/react-day-picker/src/contexts/Modifiers/utils/getInternalModifiers.test.ts
generated
vendored
Normal file
@ -0,0 +1,147 @@
|
||||
import { addDays } from 'date-fns';
|
||||
|
||||
import { DayPickerContextValue } from 'contexts/DayPicker';
|
||||
import { getDefaultContextValues } from 'contexts/DayPicker/defaultContextValues';
|
||||
import { SelectRangeContextValue } from 'contexts/SelectRange';
|
||||
import { InternalModifier, InternalModifiers } from 'types/Modifiers';
|
||||
|
||||
import { getInternalModifiers } from './getInternalModifiers';
|
||||
|
||||
const defaultDayPickerContext: DayPickerContextValue =
|
||||
getDefaultContextValues();
|
||||
const defaultSelectMultipleContext = {
|
||||
selected: undefined,
|
||||
modifiers: { disabled: [] }
|
||||
};
|
||||
const defaultSelectRangeContext = {
|
||||
selected: undefined,
|
||||
modifiers: {
|
||||
disabled: [],
|
||||
range_start: [],
|
||||
range_end: [],
|
||||
range_middle: []
|
||||
}
|
||||
};
|
||||
|
||||
const { Selected, Disabled, Hidden, Today, RangeEnd, RangeMiddle, RangeStart } =
|
||||
InternalModifier;
|
||||
|
||||
const internalModifiers = [Selected, Disabled, Hidden, Today];
|
||||
test.each(internalModifiers)(
|
||||
'should transform to array the modifiers from the "%s" prop',
|
||||
(propName) => {
|
||||
const value = new Date();
|
||||
const modifiers = getInternalModifiers(
|
||||
{ ...defaultDayPickerContext, [propName]: value },
|
||||
defaultSelectMultipleContext,
|
||||
defaultSelectRangeContext
|
||||
);
|
||||
expect(modifiers[propName]).toStrictEqual([value]);
|
||||
}
|
||||
);
|
||||
|
||||
describe('when navigation is limited by "fromDate"', () => {
|
||||
const fromDate = new Date();
|
||||
const dayPickerContext: DayPickerContextValue = {
|
||||
...defaultDayPickerContext,
|
||||
fromDate
|
||||
};
|
||||
test('should add a "before" matcher to the "disabled" modifiers', () => {
|
||||
const modifiers = getInternalModifiers(
|
||||
dayPickerContext,
|
||||
defaultSelectMultipleContext,
|
||||
defaultSelectRangeContext
|
||||
);
|
||||
expect(modifiers.disabled).toStrictEqual([{ before: fromDate }]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('when navigation is limited by "toDate"', () => {
|
||||
const toDate = new Date();
|
||||
const dayPickerContext: DayPickerContextValue = {
|
||||
...defaultDayPickerContext,
|
||||
toDate
|
||||
};
|
||||
test('should add an "after" matcher to the "disabled" modifiers', () => {
|
||||
const modifiers = getInternalModifiers(
|
||||
dayPickerContext,
|
||||
defaultSelectMultipleContext,
|
||||
defaultSelectRangeContext
|
||||
);
|
||||
expect(modifiers.disabled).toStrictEqual([{ after: toDate }]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('when in multiple select mode', () => {
|
||||
const disabledDate = new Date();
|
||||
const dayPickerContext: DayPickerContextValue = {
|
||||
...defaultDayPickerContext,
|
||||
mode: 'multiple'
|
||||
};
|
||||
const selectMultipleContext = {
|
||||
...defaultSelectMultipleContext,
|
||||
modifiers: {
|
||||
[Disabled]: [disabledDate]
|
||||
}
|
||||
};
|
||||
test('should add the disabled modifier from the select multiple context', () => {
|
||||
const modifiers = getInternalModifiers(
|
||||
dayPickerContext,
|
||||
selectMultipleContext,
|
||||
defaultSelectRangeContext
|
||||
);
|
||||
expect(modifiers.disabled).toStrictEqual([disabledDate]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('when in range select mode', () => {
|
||||
const disabled = [new Date()];
|
||||
const rangeStart = new Date();
|
||||
const rangeMiddle = [addDays(rangeStart, 1), addDays(rangeStart, 2)];
|
||||
const rangeEnd = [addDays(rangeStart, 3)];
|
||||
const dayPickerContext: DayPickerContextValue = {
|
||||
...defaultDayPickerContext,
|
||||
mode: 'range'
|
||||
};
|
||||
const selectRangeContext: SelectRangeContextValue = {
|
||||
...defaultSelectRangeContext,
|
||||
modifiers: {
|
||||
[Disabled]: [disabled],
|
||||
[RangeStart]: [rangeStart],
|
||||
[RangeEnd]: rangeEnd,
|
||||
[RangeMiddle]: rangeMiddle
|
||||
}
|
||||
};
|
||||
let internalModifiers: InternalModifiers;
|
||||
beforeEach(() => {
|
||||
internalModifiers = getInternalModifiers(
|
||||
dayPickerContext,
|
||||
defaultSelectMultipleContext,
|
||||
selectRangeContext
|
||||
);
|
||||
});
|
||||
|
||||
test('should add the Disabled modifier from the SelectRange context', () => {
|
||||
expect(internalModifiers[Disabled]).toStrictEqual(
|
||||
selectRangeContext.modifiers[Disabled]
|
||||
);
|
||||
});
|
||||
|
||||
test('should add the RangeStart modifier from the SelectRange context', () => {
|
||||
expect(internalModifiers[RangeStart]).toStrictEqual(
|
||||
selectRangeContext.modifiers[RangeStart]
|
||||
);
|
||||
});
|
||||
|
||||
test('should add the RangeEnd modifier from the SelectRange context', () => {
|
||||
expect(internalModifiers[RangeEnd]).toStrictEqual(
|
||||
selectRangeContext.modifiers[RangeEnd]
|
||||
);
|
||||
});
|
||||
|
||||
test('should add the RangeMiddle modifier from the SelectRange context', () => {
|
||||
expect(internalModifiers[RangeMiddle]).toStrictEqual(
|
||||
selectRangeContext.modifiers[RangeMiddle]
|
||||
);
|
||||
});
|
||||
});
|
||||
58
frontend/node_modules/react-day-picker/src/contexts/Modifiers/utils/getInternalModifiers.ts
generated
vendored
Normal file
58
frontend/node_modules/react-day-picker/src/contexts/Modifiers/utils/getInternalModifiers.ts
generated
vendored
Normal file
@ -0,0 +1,58 @@
|
||||
import { DayPickerContextValue } from 'contexts/DayPicker';
|
||||
import { SelectMultipleContextValue } from 'contexts/SelectMultiple';
|
||||
import { SelectRangeContextValue } from 'contexts/SelectRange';
|
||||
import { isDayPickerMultiple } from 'types/DayPickerMultiple';
|
||||
import { isDayPickerRange } from 'types/DayPickerRange';
|
||||
import { InternalModifier, InternalModifiers } from 'types/Modifiers';
|
||||
|
||||
import { matcherToArray } from './matcherToArray';
|
||||
|
||||
const {
|
||||
Selected,
|
||||
Disabled,
|
||||
Hidden,
|
||||
Today,
|
||||
RangeEnd,
|
||||
RangeMiddle,
|
||||
RangeStart,
|
||||
Outside
|
||||
} = InternalModifier;
|
||||
|
||||
/** Return the {@link InternalModifiers} from the DayPicker and select contexts. */
|
||||
export function getInternalModifiers(
|
||||
dayPicker: DayPickerContextValue,
|
||||
selectMultiple: SelectMultipleContextValue,
|
||||
selectRange: SelectRangeContextValue
|
||||
) {
|
||||
const internalModifiers: InternalModifiers = {
|
||||
[Selected]: matcherToArray(dayPicker.selected),
|
||||
[Disabled]: matcherToArray(dayPicker.disabled),
|
||||
[Hidden]: matcherToArray(dayPicker.hidden),
|
||||
[Today]: [dayPicker.today],
|
||||
[RangeEnd]: [],
|
||||
[RangeMiddle]: [],
|
||||
[RangeStart]: [],
|
||||
[Outside]: []
|
||||
};
|
||||
|
||||
if (dayPicker.fromDate) {
|
||||
internalModifiers[Disabled].push({ before: dayPicker.fromDate });
|
||||
}
|
||||
if (dayPicker.toDate) {
|
||||
internalModifiers[Disabled].push({ after: dayPicker.toDate });
|
||||
}
|
||||
|
||||
if (isDayPickerMultiple(dayPicker)) {
|
||||
internalModifiers[Disabled] = internalModifiers[Disabled].concat(
|
||||
selectMultiple.modifiers[Disabled]
|
||||
);
|
||||
} else if (isDayPickerRange(dayPicker)) {
|
||||
internalModifiers[Disabled] = internalModifiers[Disabled].concat(
|
||||
selectRange.modifiers[Disabled]
|
||||
);
|
||||
internalModifiers[RangeStart] = selectRange.modifiers[RangeStart];
|
||||
internalModifiers[RangeMiddle] = selectRange.modifiers[RangeMiddle];
|
||||
internalModifiers[RangeEnd] = selectRange.modifiers[RangeEnd];
|
||||
}
|
||||
return internalModifiers;
|
||||
}
|
||||
45
frontend/node_modules/react-day-picker/src/contexts/Modifiers/utils/isDateInRange.test.ts
generated
vendored
Normal file
45
frontend/node_modules/react-day-picker/src/contexts/Modifiers/utils/isDateInRange.test.ts
generated
vendored
Normal file
@ -0,0 +1,45 @@
|
||||
import { addDays } from 'date-fns';
|
||||
import { DateRange } from 'index';
|
||||
|
||||
import { isDateInRange } from './isDateInRange';
|
||||
|
||||
const date = new Date();
|
||||
|
||||
describe('when range is missing the "from" date', () => {
|
||||
const range: DateRange = { from: undefined };
|
||||
const result = isDateInRange(date, range);
|
||||
test('should return false', () => {
|
||||
expect(result).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('when range is missing the "to" date', () => {
|
||||
const result = isDateInRange(date, { from: date, to: undefined });
|
||||
test('should return true', () => {
|
||||
expect(result).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('when the range dates are the same as date', () => {
|
||||
const range: DateRange = { from: date, to: date };
|
||||
const result = isDateInRange(date, range);
|
||||
test('should return true', () => {
|
||||
expect(result).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('when the range dates are the same but not as date', () => {
|
||||
const range: DateRange = { from: date, to: date };
|
||||
const result = isDateInRange(addDays(date, 1), range);
|
||||
test('should return false', () => {
|
||||
expect(result).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('when the range is inverted', () => {
|
||||
const range: DateRange = { from: addDays(date, 1), to: date };
|
||||
const result = isDateInRange(date, range);
|
||||
test('should return true', () => {
|
||||
expect(result).toBe(true);
|
||||
});
|
||||
});
|
||||
25
frontend/node_modules/react-day-picker/src/contexts/Modifiers/utils/isDateInRange.ts
generated
vendored
Normal file
25
frontend/node_modules/react-day-picker/src/contexts/Modifiers/utils/isDateInRange.ts
generated
vendored
Normal file
@ -0,0 +1,25 @@
|
||||
import { differenceInCalendarDays, isSameDay } from 'date-fns';
|
||||
|
||||
import { DateRange } from 'types/Matchers';
|
||||
|
||||
/** Return `true` whether `date` is inside `range`. */
|
||||
export function isDateInRange(date: Date, range: DateRange): boolean {
|
||||
let { from, to } = range;
|
||||
if (from && to) {
|
||||
const isRangeInverted = differenceInCalendarDays(to, from) < 0;
|
||||
if (isRangeInverted) {
|
||||
[from, to] = [to, from];
|
||||
}
|
||||
const isInRange =
|
||||
differenceInCalendarDays(date, from) >= 0 &&
|
||||
differenceInCalendarDays(to, date) >= 0;
|
||||
return isInRange;
|
||||
}
|
||||
if (to) {
|
||||
return isSameDay(to, date);
|
||||
}
|
||||
if (from) {
|
||||
return isSameDay(from, date);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
111
frontend/node_modules/react-day-picker/src/contexts/Modifiers/utils/isMatch.test.ts
generated
vendored
Normal file
111
frontend/node_modules/react-day-picker/src/contexts/Modifiers/utils/isMatch.test.ts
generated
vendored
Normal file
@ -0,0 +1,111 @@
|
||||
import { addDays, subDays } from 'date-fns';
|
||||
|
||||
import {
|
||||
DateAfter,
|
||||
DateBefore,
|
||||
DateInterval,
|
||||
DateRange,
|
||||
DayOfWeek
|
||||
} from 'types/Matchers';
|
||||
|
||||
import { isMatch } from './isMatch';
|
||||
|
||||
const testDay = new Date();
|
||||
|
||||
describe('when the matcher is a boolean', () => {
|
||||
const matcher = true;
|
||||
const result = isMatch(testDay, [matcher]);
|
||||
test('should return the boolean', () => {
|
||||
expect(result).toBe(matcher);
|
||||
});
|
||||
});
|
||||
describe('when matching the same day', () => {
|
||||
const matcher = testDay;
|
||||
const result = isMatch(testDay, [matcher]);
|
||||
test('should return true', () => {
|
||||
expect(result).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('when matching an array of dates including the day', () => {
|
||||
const matcher = [addDays(testDay, -1), testDay, addDays(testDay, 1)];
|
||||
const result = isMatch(testDay, [matcher]);
|
||||
test('should return true', () => {
|
||||
expect(result).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('when matching date range', () => {
|
||||
const matcher: DateRange = {
|
||||
from: testDay,
|
||||
to: addDays(testDay, 1)
|
||||
};
|
||||
const result = isMatch(testDay, [matcher]);
|
||||
test('should return true', () => {
|
||||
expect(result).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('when matching the day of week', () => {
|
||||
const matcher: DayOfWeek = {
|
||||
dayOfWeek: [testDay.getDay()]
|
||||
};
|
||||
const result = isMatch(testDay, [matcher]);
|
||||
test('should return true', () => {
|
||||
expect(result).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('when matching date interval (closed)', () => {
|
||||
const matcher: DateInterval = {
|
||||
before: addDays(testDay, 5),
|
||||
after: subDays(testDay, 3)
|
||||
};
|
||||
const result = isMatch(testDay, [matcher]);
|
||||
test('should return true for the included day', () => {
|
||||
expect(result).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('when matching date interval (open)', () => {
|
||||
const matcher: DateInterval = {
|
||||
before: subDays(testDay, 4),
|
||||
after: addDays(testDay, 5)
|
||||
};
|
||||
test('should return false', () => {
|
||||
const result = isMatch(testDay, [matcher]);
|
||||
expect(result).toBe(false);
|
||||
});
|
||||
test('should return true for the days before', () => {
|
||||
const result = isMatch(subDays(testDay, 8), [matcher]);
|
||||
expect(result).toBe(true);
|
||||
});
|
||||
test('should return true for the days after', () => {
|
||||
const result = isMatch(addDays(testDay, 8), [matcher]);
|
||||
expect(result).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('when matching the date after', () => {
|
||||
const matcher: DateAfter = { after: addDays(testDay, -1) };
|
||||
const result = isMatch(testDay, [matcher]);
|
||||
test('should return true', () => {
|
||||
expect(result).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('when matching the date before', () => {
|
||||
const matcher: DateBefore = { before: addDays(testDay, +1) };
|
||||
const result = isMatch(testDay, [matcher]);
|
||||
test('should return true', () => {
|
||||
expect(result).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('when the matcher is a function', () => {
|
||||
const matcher = () => true;
|
||||
const result = isMatch(testDay, [matcher]);
|
||||
test('should return the result of the function', () => {
|
||||
expect(result).toBe(true);
|
||||
});
|
||||
});
|
||||
81
frontend/node_modules/react-day-picker/src/contexts/Modifiers/utils/isMatch.ts
generated
vendored
Normal file
81
frontend/node_modules/react-day-picker/src/contexts/Modifiers/utils/isMatch.ts
generated
vendored
Normal file
@ -0,0 +1,81 @@
|
||||
import { differenceInCalendarDays, isAfter, isDate, isSameDay } from 'date-fns';
|
||||
|
||||
import {
|
||||
isDateAfterType,
|
||||
isDateBeforeType,
|
||||
isDateInterval,
|
||||
isDateRange,
|
||||
isDayOfWeekType,
|
||||
Matcher
|
||||
} from 'types/Matchers';
|
||||
|
||||
import { isDateInRange } from './isDateInRange';
|
||||
|
||||
/** Returns true if `value` is a Date type. */
|
||||
function isDateType(value: unknown): value is Date {
|
||||
return isDate(value);
|
||||
}
|
||||
|
||||
/** Returns true if `value` is an array of valid dates. */
|
||||
function isArrayOfDates(value: unknown): value is Date[] {
|
||||
return Array.isArray(value) && value.every(isDate);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether a day matches against at least one of the given Matchers.
|
||||
*
|
||||
* ```
|
||||
* const day = new Date(2022, 5, 19);
|
||||
* const matcher1: DateRange = {
|
||||
* from: new Date(2021, 12, 21),
|
||||
* to: new Date(2021, 12, 30)
|
||||
* }
|
||||
* const matcher2: DateRange = {
|
||||
* from: new Date(2022, 5, 1),
|
||||
* to: new Date(2022, 5, 23)
|
||||
* }
|
||||
*
|
||||
* const isMatch(day, [matcher1, matcher2]); // true, since day is in the matcher1 range.
|
||||
* ```
|
||||
* */
|
||||
export function isMatch(day: Date, matchers: Matcher[]): boolean {
|
||||
return matchers.some((matcher: Matcher) => {
|
||||
if (typeof matcher === 'boolean') {
|
||||
return matcher;
|
||||
}
|
||||
if (isDateType(matcher)) {
|
||||
return isSameDay(day, matcher);
|
||||
}
|
||||
if (isArrayOfDates(matcher)) {
|
||||
return matcher.includes(day);
|
||||
}
|
||||
if (isDateRange(matcher)) {
|
||||
return isDateInRange(day, matcher);
|
||||
}
|
||||
if (isDayOfWeekType(matcher)) {
|
||||
return matcher.dayOfWeek.includes(day.getDay());
|
||||
}
|
||||
if (isDateInterval(matcher)) {
|
||||
const diffBefore = differenceInCalendarDays(matcher.before, day);
|
||||
const diffAfter = differenceInCalendarDays(matcher.after, day);
|
||||
const isDayBefore = diffBefore > 0;
|
||||
const isDayAfter = diffAfter < 0;
|
||||
const isClosedInterval = isAfter(matcher.before, matcher.after);
|
||||
if (isClosedInterval) {
|
||||
return isDayAfter && isDayBefore;
|
||||
} else {
|
||||
return isDayBefore || isDayAfter;
|
||||
}
|
||||
}
|
||||
if (isDateAfterType(matcher)) {
|
||||
return differenceInCalendarDays(day, matcher.after) > 0;
|
||||
}
|
||||
if (isDateBeforeType(matcher)) {
|
||||
return differenceInCalendarDays(matcher.before, day) > 0;
|
||||
}
|
||||
if (typeof matcher === 'function') {
|
||||
return matcher(day);
|
||||
}
|
||||
return false;
|
||||
});
|
||||
}
|
||||
25
frontend/node_modules/react-day-picker/src/contexts/Modifiers/utils/matcherToArray.test.ts
generated
vendored
Normal file
25
frontend/node_modules/react-day-picker/src/contexts/Modifiers/utils/matcherToArray.test.ts
generated
vendored
Normal file
@ -0,0 +1,25 @@
|
||||
import { matcherToArray } from 'contexts/Modifiers/utils/matcherToArray';
|
||||
import { Matcher } from 'types/Matchers';
|
||||
|
||||
const matcher: Matcher = jest.fn();
|
||||
|
||||
describe('when a Matcher is passed in', () => {
|
||||
test('should return an array with the Matcher', () => {
|
||||
expect(matcherToArray(matcher)).toStrictEqual([matcher]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('when an array of Matchers is passed in', () => {
|
||||
test('should return a copy of the array', () => {
|
||||
const value = [matcher, matcher];
|
||||
const result = matcherToArray(value);
|
||||
expect(result).toStrictEqual(value);
|
||||
expect(result).not.toBe(value);
|
||||
});
|
||||
});
|
||||
|
||||
describe('when undefined is passed in', () => {
|
||||
test('should return an empty array', () => {
|
||||
expect(matcherToArray(undefined)).toStrictEqual([]);
|
||||
});
|
||||
});
|
||||
14
frontend/node_modules/react-day-picker/src/contexts/Modifiers/utils/matcherToArray.ts
generated
vendored
Normal file
14
frontend/node_modules/react-day-picker/src/contexts/Modifiers/utils/matcherToArray.ts
generated
vendored
Normal file
@ -0,0 +1,14 @@
|
||||
import { Matcher } from 'types/Matchers';
|
||||
|
||||
/** Normalize to array a matcher input. */
|
||||
export function matcherToArray(
|
||||
matcher: Matcher | Matcher[] | undefined
|
||||
): Matcher[] {
|
||||
if (Array.isArray(matcher)) {
|
||||
return [...matcher];
|
||||
} else if (matcher !== undefined) {
|
||||
return [matcher];
|
||||
} else {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
126
frontend/node_modules/react-day-picker/src/contexts/Navigation/NavigationContext.test.ts
generated
vendored
Normal file
126
frontend/node_modules/react-day-picker/src/contexts/Navigation/NavigationContext.test.ts
generated
vendored
Normal file
@ -0,0 +1,126 @@
|
||||
import { act } from '@testing-library/react';
|
||||
import { addMonths, startOfMonth, subMonths } from 'date-fns';
|
||||
import { DayPickerProps } from 'DayPicker';
|
||||
|
||||
import { renderDayPickerHook, RenderHookResult } from 'test/render';
|
||||
import { freezeBeforeAll } from 'test/utils';
|
||||
|
||||
import { NavigationContextValue, useNavigation } from './NavigationContext';
|
||||
|
||||
const today = new Date(2021, 11, 8);
|
||||
const todaysMonth = startOfMonth(today);
|
||||
freezeBeforeAll(today);
|
||||
|
||||
function renderHook(props: Partial<DayPickerProps> = {}) {
|
||||
return renderDayPickerHook<NavigationContextValue>(useNavigation, props);
|
||||
}
|
||||
|
||||
let result: RenderHookResult<NavigationContextValue>;
|
||||
describe('when rendered', () => {
|
||||
beforeEach(() => {
|
||||
result = renderHook();
|
||||
});
|
||||
test('the current month should be the today`s month', () => {
|
||||
expect(result.current.currentMonth).toEqual(todaysMonth);
|
||||
});
|
||||
test('the display months should be the today`s month', () => {
|
||||
expect(result.current.displayMonths).toEqual([todaysMonth]);
|
||||
});
|
||||
test('the previous month should be the month before today`s month', () => {
|
||||
expect(result.current.previousMonth).toEqual(subMonths(todaysMonth, 1));
|
||||
});
|
||||
test('the next month should be the month after today`s month', () => {
|
||||
expect(result.current.nextMonth).toEqual(addMonths(todaysMonth, 1));
|
||||
});
|
||||
describe('when goToMonth is called', () => {
|
||||
const newMonth = addMonths(todaysMonth, 10);
|
||||
beforeEach(() => {
|
||||
result = renderHook();
|
||||
act(() => result.current.goToMonth(newMonth));
|
||||
});
|
||||
test('should go to the specified month', () => {
|
||||
expect(result.current.currentMonth).toEqual(newMonth);
|
||||
});
|
||||
test('the display months should be the today`s month', () => {
|
||||
expect(result.current.displayMonths).toEqual([newMonth]);
|
||||
});
|
||||
test('the previous month should be the month before today`s month', () => {
|
||||
expect(result.current.previousMonth).toEqual(subMonths(newMonth, 1));
|
||||
});
|
||||
test('the next month should be the month after today`s month', () => {
|
||||
expect(result.current.nextMonth).toEqual(addMonths(newMonth, 1));
|
||||
});
|
||||
});
|
||||
describe('when goToDate is called with a date from another month', () => {
|
||||
const newDate = addMonths(today, 10);
|
||||
const onMonthChange = jest.fn();
|
||||
beforeEach(() => {
|
||||
result = renderHook({ onMonthChange });
|
||||
act(() => result.current.goToDate(newDate));
|
||||
});
|
||||
test('should go to the specified month', () => {
|
||||
const date = startOfMonth(newDate);
|
||||
expect(result.current.currentMonth).toEqual(date);
|
||||
expect(onMonthChange).toHaveBeenCalledWith(date);
|
||||
});
|
||||
});
|
||||
describe('when isDateDisplayed is called', () => {
|
||||
describe('with a date in the calendar', () => {
|
||||
test('should return true', () => {
|
||||
expect(result.current.isDateDisplayed(today)).toBe(true);
|
||||
});
|
||||
});
|
||||
describe('with a date not in the calendar', () => {
|
||||
test('should return false', () => {
|
||||
expect(result.current.isDateDisplayed(addMonths(today, 1))).toBe(false);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
const numberOfMonths = 2;
|
||||
describe('when the number of months is ${numberOfMonths}', () => {
|
||||
beforeEach(() => {
|
||||
result = renderHook({ numberOfMonths: 2 });
|
||||
});
|
||||
test('the current month should be the today`s month', () => {
|
||||
expect(result.current.currentMonth).toEqual(todaysMonth);
|
||||
});
|
||||
test('the display months should be the today`s and next month', () => {
|
||||
expect(result.current.displayMonths).toEqual([
|
||||
todaysMonth,
|
||||
addMonths(todaysMonth, 1)
|
||||
]);
|
||||
});
|
||||
test('the previous month should be the month before today`s month', () => {
|
||||
expect(result.current.previousMonth).toEqual(subMonths(todaysMonth, 1));
|
||||
});
|
||||
test('the next month should be the month after today`s month', () => {
|
||||
expect(result.current.nextMonth).toEqual(addMonths(todaysMonth, 1));
|
||||
});
|
||||
});
|
||||
|
||||
describe(`when the number of months is ${numberOfMonths} and the navigation is paged`, () => {
|
||||
beforeEach(() => {
|
||||
result = renderHook({ numberOfMonths, pagedNavigation: true });
|
||||
});
|
||||
test('the current month should be the today`s month', () => {
|
||||
expect(result.current.currentMonth).toEqual(todaysMonth);
|
||||
});
|
||||
test('the display months should be the today`s and next month', () => {
|
||||
expect(result.current.displayMonths).toEqual([
|
||||
todaysMonth,
|
||||
addMonths(todaysMonth, 1)
|
||||
]);
|
||||
});
|
||||
test(`the previous month should be the ${numberOfMonths} months before today's month`, () => {
|
||||
expect(result.current.previousMonth).toEqual(
|
||||
subMonths(todaysMonth, numberOfMonths)
|
||||
);
|
||||
});
|
||||
test(`the next month should be ${numberOfMonths} months after today's month`, () => {
|
||||
expect(result.current.nextMonth).toEqual(
|
||||
addMonths(todaysMonth, numberOfMonths)
|
||||
);
|
||||
});
|
||||
});
|
||||
95
frontend/node_modules/react-day-picker/src/contexts/Navigation/NavigationContext.tsx
generated
vendored
Normal file
95
frontend/node_modules/react-day-picker/src/contexts/Navigation/NavigationContext.tsx
generated
vendored
Normal file
@ -0,0 +1,95 @@
|
||||
import { createContext, ReactNode, useContext } from 'react';
|
||||
|
||||
import { addMonths, isBefore, isSameMonth } from 'date-fns';
|
||||
|
||||
import { useDayPicker } from '../DayPicker';
|
||||
import { useNavigationState } from './useNavigationState';
|
||||
import { getDisplayMonths } from './utils/getDisplayMonths';
|
||||
import { getNextMonth } from './utils/getNextMonth';
|
||||
import { getPreviousMonth } from './utils/getPreviousMonth';
|
||||
|
||||
/** Represents the value of the {@link NavigationContext}. */
|
||||
export interface NavigationContextValue {
|
||||
/** The month to display in the calendar. When `numberOfMonths` is greater than one, is the first of the displayed months. */
|
||||
currentMonth: Date;
|
||||
/** The months rendered by DayPicker. DayPicker can render multiple months via `numberOfMonths`. */
|
||||
displayMonths: Date[];
|
||||
/** Navigate to the specified month. */
|
||||
goToMonth: (month: Date) => void;
|
||||
/** Navigate to the specified date. */
|
||||
goToDate: (date: Date, refDate?: Date) => void;
|
||||
/** The next month to display. */
|
||||
nextMonth?: Date;
|
||||
/** The previous month to display. */
|
||||
previousMonth?: Date;
|
||||
/** Whether the given day is included in the displayed months. */
|
||||
isDateDisplayed: (day: Date) => boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* The Navigation context shares details and methods to navigate the months in DayPicker.
|
||||
* Access this context from the {@link useNavigation} hook.
|
||||
*/
|
||||
export const NavigationContext = createContext<
|
||||
NavigationContextValue | undefined
|
||||
>(undefined);
|
||||
|
||||
/** Provides the values for the {@link NavigationContext}. */
|
||||
export function NavigationProvider(props: {
|
||||
children?: ReactNode;
|
||||
}): JSX.Element {
|
||||
const dayPicker = useDayPicker();
|
||||
const [currentMonth, goToMonth] = useNavigationState();
|
||||
|
||||
const displayMonths = getDisplayMonths(currentMonth, dayPicker);
|
||||
const nextMonth = getNextMonth(currentMonth, dayPicker);
|
||||
const previousMonth = getPreviousMonth(currentMonth, dayPicker);
|
||||
|
||||
const isDateDisplayed = (date: Date) => {
|
||||
return displayMonths.some((displayMonth) =>
|
||||
isSameMonth(date, displayMonth)
|
||||
);
|
||||
};
|
||||
|
||||
const goToDate = (date: Date, refDate?: Date) => {
|
||||
if (isDateDisplayed(date)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (refDate && isBefore(date, refDate)) {
|
||||
goToMonth(addMonths(date, 1 + dayPicker.numberOfMonths * -1));
|
||||
} else {
|
||||
goToMonth(date);
|
||||
}
|
||||
};
|
||||
|
||||
const value: NavigationContextValue = {
|
||||
currentMonth,
|
||||
displayMonths,
|
||||
goToMonth,
|
||||
goToDate,
|
||||
previousMonth,
|
||||
nextMonth,
|
||||
isDateDisplayed
|
||||
};
|
||||
|
||||
return (
|
||||
<NavigationContext.Provider value={value}>
|
||||
{props.children}
|
||||
</NavigationContext.Provider>
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Hook to access the {@link NavigationContextValue}. Use this hook to navigate
|
||||
* between months or years in DayPicker.
|
||||
*
|
||||
* This hook is meant to be used inside internal or custom components.
|
||||
*/
|
||||
export function useNavigation(): NavigationContextValue {
|
||||
const context = useContext(NavigationContext);
|
||||
if (!context) {
|
||||
throw new Error('useNavigation must be used within a NavigationProvider');
|
||||
}
|
||||
return context;
|
||||
}
|
||||
1
frontend/node_modules/react-day-picker/src/contexts/Navigation/index.ts
generated
vendored
Normal file
1
frontend/node_modules/react-day-picker/src/contexts/Navigation/index.ts
generated
vendored
Normal file
@ -0,0 +1 @@
|
||||
export * from './NavigationContext';
|
||||
36
frontend/node_modules/react-day-picker/src/contexts/Navigation/useNavigationState.test.ts
generated
vendored
Normal file
36
frontend/node_modules/react-day-picker/src/contexts/Navigation/useNavigationState.test.ts
generated
vendored
Normal file
@ -0,0 +1,36 @@
|
||||
import { act } from '@testing-library/react';
|
||||
import { addMonths, startOfMonth } from 'date-fns';
|
||||
import { DayPickerProps } from 'DayPicker';
|
||||
|
||||
import { renderDayPickerHook } from 'test/render';
|
||||
import { freezeBeforeAll } from 'test/utils';
|
||||
|
||||
import { NavigationState, useNavigationState } from './useNavigationState';
|
||||
|
||||
const today = new Date(2021, 11, 8);
|
||||
freezeBeforeAll(today);
|
||||
|
||||
function renderHook(props: Partial<DayPickerProps> = {}) {
|
||||
return renderDayPickerHook<NavigationState>(useNavigationState, props);
|
||||
}
|
||||
|
||||
describe('when goToMonth is called', () => {
|
||||
test('should set the month in state', () => {
|
||||
const onMonthChange = jest.fn();
|
||||
const result = renderHook({ onMonthChange });
|
||||
const month = addMonths(today, 2);
|
||||
act(() => result.current[1](month));
|
||||
expect(result.current[0]).toEqual(startOfMonth(month));
|
||||
expect(onMonthChange).toHaveBeenCalledWith(startOfMonth(month));
|
||||
});
|
||||
describe('when navigation is disabled', () => {
|
||||
test('should not set the month in state', () => {
|
||||
const onMonthChange = jest.fn();
|
||||
const result = renderHook({ disableNavigation: true, onMonthChange });
|
||||
const month = addMonths(today, 2);
|
||||
result.current[1](month);
|
||||
expect(result.current[0]).toEqual(startOfMonth(today));
|
||||
expect(onMonthChange).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
});
|
||||
29
frontend/node_modules/react-day-picker/src/contexts/Navigation/useNavigationState.ts
generated
vendored
Normal file
29
frontend/node_modules/react-day-picker/src/contexts/Navigation/useNavigationState.ts
generated
vendored
Normal file
@ -0,0 +1,29 @@
|
||||
import { startOfMonth } from 'date-fns';
|
||||
|
||||
import { useDayPicker } from 'contexts/DayPicker';
|
||||
import { useControlledValue } from 'hooks/useControlledValue';
|
||||
|
||||
import { getInitialMonth } from './utils/getInitialMonth';
|
||||
|
||||
export type NavigationState = [
|
||||
/** The month DayPicker is navigating at */
|
||||
month: Date,
|
||||
/** Go to the specified month. */
|
||||
goToMonth: (month: Date) => void
|
||||
];
|
||||
|
||||
/** Controls the navigation state. */
|
||||
export function useNavigationState(): NavigationState {
|
||||
const context = useDayPicker();
|
||||
const initialMonth = getInitialMonth(context);
|
||||
const [month, setMonth] = useControlledValue(initialMonth, context.month);
|
||||
|
||||
const goToMonth = (date: Date) => {
|
||||
if (context.disableNavigation) return;
|
||||
const month = startOfMonth(date);
|
||||
setMonth(month);
|
||||
context.onMonthChange?.(month);
|
||||
};
|
||||
|
||||
return [month, goToMonth];
|
||||
}
|
||||
29
frontend/node_modules/react-day-picker/src/contexts/Navigation/utils/getDisplayMonths.ts
generated
vendored
Normal file
29
frontend/node_modules/react-day-picker/src/contexts/Navigation/utils/getDisplayMonths.ts
generated
vendored
Normal file
@ -0,0 +1,29 @@
|
||||
import { addMonths, differenceInCalendarMonths, startOfMonth } from 'date-fns';
|
||||
|
||||
/**
|
||||
* Return the months to display in the component according to the number of
|
||||
* months and the from/to date.
|
||||
*/
|
||||
export function getDisplayMonths(
|
||||
month: Date,
|
||||
{
|
||||
reverseMonths,
|
||||
numberOfMonths
|
||||
}: {
|
||||
reverseMonths?: boolean;
|
||||
numberOfMonths: number;
|
||||
}
|
||||
): Date[] {
|
||||
const start = startOfMonth(month);
|
||||
const end = startOfMonth(addMonths(start, numberOfMonths));
|
||||
const monthsDiff = differenceInCalendarMonths(end, start);
|
||||
let months = [];
|
||||
|
||||
for (let i = 0; i < monthsDiff; i++) {
|
||||
const nextMonth = addMonths(start, i);
|
||||
months.push(nextMonth);
|
||||
}
|
||||
|
||||
if (reverseMonths) months = months.reverse();
|
||||
return months;
|
||||
}
|
||||
56
frontend/node_modules/react-day-picker/src/contexts/Navigation/utils/getInitialMonth.test.ts
generated
vendored
Normal file
56
frontend/node_modules/react-day-picker/src/contexts/Navigation/utils/getInitialMonth.test.ts
generated
vendored
Normal file
@ -0,0 +1,56 @@
|
||||
import { addMonths, isSameMonth } from 'date-fns';
|
||||
|
||||
import { getInitialMonth } from './getInitialMonth';
|
||||
|
||||
describe('when no toDate is given', () => {
|
||||
describe('when month is in context', () => {
|
||||
const month = new Date(2010, 11, 12);
|
||||
it('return that month', () => {
|
||||
const initialMonth = getInitialMonth({ month });
|
||||
expect(isSameMonth(initialMonth, month)).toBe(true);
|
||||
});
|
||||
});
|
||||
describe('when defaultMonth is in context', () => {
|
||||
const defaultMonth = new Date(2010, 11, 12);
|
||||
it('return that month', () => {
|
||||
const initialMonth = getInitialMonth({ defaultMonth });
|
||||
expect(isSameMonth(initialMonth, defaultMonth)).toBe(true);
|
||||
});
|
||||
});
|
||||
describe('when no month or defaultMonth are in context', () => {
|
||||
const today = new Date(2010, 11, 12);
|
||||
it('return the today month', () => {
|
||||
const initialMonth = getInitialMonth({ today });
|
||||
expect(isSameMonth(initialMonth, today)).toBe(true);
|
||||
});
|
||||
});
|
||||
});
|
||||
describe('when toDate is given', () => {
|
||||
describe('when toDate is before the default initial date', () => {
|
||||
const month = new Date(2010, 11, 12);
|
||||
const toDate = addMonths(month, -2);
|
||||
describe('when the number of month is 1', () => {
|
||||
const numberOfMonths = 1;
|
||||
it('return the toDate', () => {
|
||||
const initialMonth = getInitialMonth({
|
||||
month,
|
||||
toDate,
|
||||
numberOfMonths
|
||||
});
|
||||
expect(isSameMonth(initialMonth, toDate)).toBe(true);
|
||||
});
|
||||
});
|
||||
describe('when the number of month is 3', () => {
|
||||
const numberOfMonths = 3;
|
||||
it('return the toDate plus the number of months', () => {
|
||||
const initialMonth = getInitialMonth({
|
||||
month,
|
||||
toDate,
|
||||
numberOfMonths
|
||||
});
|
||||
const expectedMonth = addMonths(toDate, -1 * (numberOfMonths - 1));
|
||||
expect(isSameMonth(initialMonth, expectedMonth)).toBe(true);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
22
frontend/node_modules/react-day-picker/src/contexts/Navigation/utils/getInitialMonth.ts
generated
vendored
Normal file
22
frontend/node_modules/react-day-picker/src/contexts/Navigation/utils/getInitialMonth.ts
generated
vendored
Normal file
@ -0,0 +1,22 @@
|
||||
import { addMonths, differenceInCalendarMonths, startOfMonth } from 'date-fns';
|
||||
|
||||
import { DayPickerContextValue } from 'contexts/DayPicker';
|
||||
|
||||
/** Return the initial month according to the given options. */
|
||||
export function getInitialMonth(context: Partial<DayPickerContextValue>): Date {
|
||||
const { month, defaultMonth, today } = context;
|
||||
let initialMonth = month || defaultMonth || today || new Date();
|
||||
|
||||
const { toDate, fromDate, numberOfMonths = 1 } = context;
|
||||
|
||||
// Fix the initialMonth if is after the to-date
|
||||
if (toDate && differenceInCalendarMonths(toDate, initialMonth) < 0) {
|
||||
const offset = -1 * (numberOfMonths - 1);
|
||||
initialMonth = addMonths(toDate, offset);
|
||||
}
|
||||
// Fix the initialMonth if is before the from-date
|
||||
if (fromDate && differenceInCalendarMonths(initialMonth, fromDate) < 0) {
|
||||
initialMonth = fromDate;
|
||||
}
|
||||
return startOfMonth(initialMonth);
|
||||
}
|
||||
75
frontend/node_modules/react-day-picker/src/contexts/Navigation/utils/getNextMonth.test.ts
generated
vendored
Normal file
75
frontend/node_modules/react-day-picker/src/contexts/Navigation/utils/getNextMonth.test.ts
generated
vendored
Normal file
@ -0,0 +1,75 @@
|
||||
import { addMonths, isSameMonth } from 'date-fns';
|
||||
|
||||
import { getNextMonth } from './getNextMonth';
|
||||
|
||||
const startingMonth = new Date(2020, 4, 31);
|
||||
|
||||
describe('when number of months is 1', () => {
|
||||
describe('when the navigation is disabled', () => {
|
||||
const disableNavigation = true;
|
||||
it('the next month is undefined', () => {
|
||||
const result = getNextMonth(startingMonth, { disableNavigation });
|
||||
expect(result).toBe(undefined);
|
||||
});
|
||||
});
|
||||
describe('when in the navigable range', () => {
|
||||
const toDate = addMonths(startingMonth, 3);
|
||||
it('the next month is not undefined', () => {
|
||||
const result = getNextMonth(startingMonth, { toDate });
|
||||
const expectedNextMonth = addMonths(startingMonth, 1);
|
||||
expect(result && isSameMonth(result, expectedNextMonth)).toBeTruthy();
|
||||
});
|
||||
});
|
||||
describe('when not in the navigable range', () => {
|
||||
const toDate = startingMonth;
|
||||
it('the next month is undefined', () => {
|
||||
const result = getNextMonth(startingMonth, { toDate });
|
||||
expect(result).toBe(undefined);
|
||||
});
|
||||
});
|
||||
});
|
||||
describe('when displaying 3 months', () => {
|
||||
const numberOfMonths = 3;
|
||||
describe('when the navigation is paged', () => {
|
||||
const pagedNavigation = true;
|
||||
it('the next month is 3 months ahead', () => {
|
||||
const result = getNextMonth(startingMonth, {
|
||||
numberOfMonths,
|
||||
pagedNavigation
|
||||
});
|
||||
const expectedNextMonth = addMonths(startingMonth, 3);
|
||||
expect(result && isSameMonth(result, expectedNextMonth)).toBeTruthy();
|
||||
});
|
||||
describe('when the to-date is ahead less than 3 months', () => {
|
||||
it('the next month is undefined', () => {
|
||||
const result = getNextMonth(startingMonth, {
|
||||
numberOfMonths,
|
||||
pagedNavigation,
|
||||
toDate: addMonths(startingMonth, 1)
|
||||
});
|
||||
expect(result).toBe(undefined);
|
||||
});
|
||||
});
|
||||
});
|
||||
describe('when the navigation is not paged', () => {
|
||||
const pagedNavigation = false;
|
||||
it('the next month is 1 months ahead', () => {
|
||||
const result = getNextMonth(startingMonth, {
|
||||
numberOfMonths,
|
||||
pagedNavigation
|
||||
});
|
||||
const expectedNextMonth = addMonths(startingMonth, 1);
|
||||
expect(result && isSameMonth(result, expectedNextMonth)).toBeTruthy();
|
||||
});
|
||||
describe('when the to-date is ahead less than 3 months', () => {
|
||||
it('the next month is undefined', () => {
|
||||
const result = getNextMonth(startingMonth, {
|
||||
numberOfMonths,
|
||||
pagedNavigation,
|
||||
toDate: addMonths(startingMonth, 2)
|
||||
});
|
||||
expect(result).toBe(undefined);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
43
frontend/node_modules/react-day-picker/src/contexts/Navigation/utils/getNextMonth.ts
generated
vendored
Normal file
43
frontend/node_modules/react-day-picker/src/contexts/Navigation/utils/getNextMonth.ts
generated
vendored
Normal file
@ -0,0 +1,43 @@
|
||||
import { addMonths, differenceInCalendarMonths, startOfMonth } from 'date-fns';
|
||||
|
||||
/**
|
||||
* Returns the next month the user can navigate to according to the given
|
||||
* options.
|
||||
*
|
||||
* Please note that the next month is not always the next calendar month:
|
||||
*
|
||||
* - if after the `toDate` range, is undefined;
|
||||
* - if the navigation is paged, is the number of months displayed ahead.
|
||||
*
|
||||
*/
|
||||
export function getNextMonth(
|
||||
startingMonth: Date,
|
||||
options: {
|
||||
numberOfMonths?: number;
|
||||
fromDate?: Date;
|
||||
toDate?: Date;
|
||||
pagedNavigation?: boolean;
|
||||
today?: Date;
|
||||
disableNavigation?: boolean;
|
||||
}
|
||||
): Date | undefined {
|
||||
if (options.disableNavigation) {
|
||||
return undefined;
|
||||
}
|
||||
const { toDate, pagedNavigation, numberOfMonths = 1 } = options;
|
||||
const offset = pagedNavigation ? numberOfMonths : 1;
|
||||
const month = startOfMonth(startingMonth);
|
||||
|
||||
if (!toDate) {
|
||||
return addMonths(month, offset);
|
||||
}
|
||||
|
||||
const monthsDiff = differenceInCalendarMonths(toDate, startingMonth);
|
||||
|
||||
if (monthsDiff < numberOfMonths) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
// Jump forward as the number of months when paged navigation
|
||||
return addMonths(month, offset);
|
||||
}
|
||||
55
frontend/node_modules/react-day-picker/src/contexts/Navigation/utils/getPreviousMonth.test.ts
generated
vendored
Normal file
55
frontend/node_modules/react-day-picker/src/contexts/Navigation/utils/getPreviousMonth.test.ts
generated
vendored
Normal file
@ -0,0 +1,55 @@
|
||||
import { addMonths, isSameMonth } from 'date-fns';
|
||||
|
||||
import { getPreviousMonth } from './getPreviousMonth';
|
||||
|
||||
const startingMonth = new Date(2020, 4, 31);
|
||||
|
||||
describe('when number of months is 1', () => {
|
||||
describe('when the navigation is disabled', () => {
|
||||
const disableNavigation = true;
|
||||
it('the previous month is undefined', () => {
|
||||
const result = getPreviousMonth(startingMonth, { disableNavigation });
|
||||
expect(result).toBe(undefined);
|
||||
});
|
||||
});
|
||||
describe('when in the navigable range', () => {
|
||||
const fromDate = addMonths(startingMonth, -3);
|
||||
it('the previous month is not undefined', () => {
|
||||
const result = getPreviousMonth(startingMonth, { fromDate });
|
||||
const expectedPrevMonth = addMonths(startingMonth, -1);
|
||||
expect(result && isSameMonth(result, expectedPrevMonth)).toBeTruthy();
|
||||
});
|
||||
});
|
||||
describe('when not in the navigable range', () => {
|
||||
const fromDate = startingMonth;
|
||||
it('the previous month is undefined', () => {
|
||||
const result = getPreviousMonth(startingMonth, { fromDate });
|
||||
expect(result).toBe(undefined);
|
||||
});
|
||||
});
|
||||
});
|
||||
describe('when displaying 3 months', () => {
|
||||
const numberOfMonths = 3;
|
||||
describe('when the navigation is paged', () => {
|
||||
const pagedNavigation = true;
|
||||
it('the previous month is 3 months back', () => {
|
||||
const result = getPreviousMonth(startingMonth, {
|
||||
numberOfMonths,
|
||||
pagedNavigation
|
||||
});
|
||||
const expectedPrevMonth = addMonths(startingMonth, -numberOfMonths);
|
||||
expect(result && isSameMonth(result, expectedPrevMonth)).toBeTruthy();
|
||||
});
|
||||
});
|
||||
describe('when the navigation is not paged', () => {
|
||||
const pagedNavigation = false;
|
||||
it('the previous month is 1 months back', () => {
|
||||
const result = getPreviousMonth(startingMonth, {
|
||||
numberOfMonths,
|
||||
pagedNavigation
|
||||
});
|
||||
const expectedPrevMonth = addMonths(startingMonth, -1);
|
||||
expect(result && isSameMonth(result, expectedPrevMonth)).toBeTruthy();
|
||||
});
|
||||
});
|
||||
});
|
||||
42
frontend/node_modules/react-day-picker/src/contexts/Navigation/utils/getPreviousMonth.ts
generated
vendored
Normal file
42
frontend/node_modules/react-day-picker/src/contexts/Navigation/utils/getPreviousMonth.ts
generated
vendored
Normal file
@ -0,0 +1,42 @@
|
||||
import { addMonths, differenceInCalendarMonths, startOfMonth } from 'date-fns';
|
||||
|
||||
/**
|
||||
* Returns the next previous the user can navigate to, according to the given
|
||||
* options.
|
||||
*
|
||||
* Please note that the previous month is not always the previous calendar
|
||||
* month:
|
||||
*
|
||||
* - if before the `fromDate` date, is `undefined`;
|
||||
* - if the navigation is paged, is the number of months displayed before.
|
||||
*
|
||||
*/
|
||||
export function getPreviousMonth(
|
||||
startingMonth: Date,
|
||||
options: {
|
||||
numberOfMonths?: number;
|
||||
fromDate?: Date;
|
||||
toDate?: Date;
|
||||
pagedNavigation?: boolean;
|
||||
today?: Date;
|
||||
disableNavigation?: boolean;
|
||||
}
|
||||
): Date | undefined {
|
||||
if (options.disableNavigation) {
|
||||
return undefined;
|
||||
}
|
||||
const { fromDate, pagedNavigation, numberOfMonths = 1 } = options;
|
||||
const offset = pagedNavigation ? numberOfMonths : 1;
|
||||
const month = startOfMonth(startingMonth);
|
||||
if (!fromDate) {
|
||||
return addMonths(month, -offset);
|
||||
}
|
||||
const monthsDiff = differenceInCalendarMonths(month, fromDate);
|
||||
|
||||
if (monthsDiff <= 0) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
// Jump back as the number of months when paged navigation
|
||||
return addMonths(month, -offset);
|
||||
}
|
||||
46
frontend/node_modules/react-day-picker/src/contexts/RootProvider.tsx
generated
vendored
Normal file
46
frontend/node_modules/react-day-picker/src/contexts/RootProvider.tsx
generated
vendored
Normal file
@ -0,0 +1,46 @@
|
||||
import { ReactNode } from 'react';
|
||||
|
||||
import { ModifiersProvider } from 'contexts/Modifiers/ModifiersContext';
|
||||
|
||||
import { DayPickerProvider } from './DayPicker';
|
||||
import { FocusProvider } from './Focus';
|
||||
import { NavigationProvider } from './Navigation';
|
||||
import { SelectMultipleProvider } from './SelectMultiple';
|
||||
import { SelectRangeProvider } from './SelectRange';
|
||||
import { SelectSingleProvider } from './SelectSingle';
|
||||
import { DayPickerDefaultProps } from 'types/DayPickerDefault';
|
||||
import { DayPickerSingleProps } from 'types/DayPickerSingle';
|
||||
import { DayPickerMultipleProps } from 'types/DayPickerMultiple';
|
||||
import { DayPickerRangeProps } from 'types/DayPickerRange';
|
||||
|
||||
type RootContextProps =
|
||||
| Partial<DayPickerDefaultProps>
|
||||
| Partial<DayPickerSingleProps>
|
||||
| Partial<DayPickerMultipleProps>
|
||||
| Partial<DayPickerRangeProps>;
|
||||
|
||||
/** The props of {@link RootProvider}. */
|
||||
export type RootContext = RootContextProps & {
|
||||
children?: ReactNode;
|
||||
};
|
||||
|
||||
/** Provide the value for all the context providers. */
|
||||
export function RootProvider(props: RootContext): JSX.Element {
|
||||
const { children, ...initialProps } = props;
|
||||
|
||||
return (
|
||||
<DayPickerProvider initialProps={initialProps}>
|
||||
<NavigationProvider>
|
||||
<SelectSingleProvider initialProps={initialProps}>
|
||||
<SelectMultipleProvider initialProps={initialProps}>
|
||||
<SelectRangeProvider initialProps={initialProps}>
|
||||
<ModifiersProvider>
|
||||
<FocusProvider>{children}</FocusProvider>
|
||||
</ModifiersProvider>
|
||||
</SelectRangeProvider>
|
||||
</SelectMultipleProvider>
|
||||
</SelectSingleProvider>
|
||||
</NavigationProvider>
|
||||
</DayPickerProvider>
|
||||
);
|
||||
}
|
||||
190
frontend/node_modules/react-day-picker/src/contexts/SelectMultiple/SelectMultipleContext.test.ts
generated
vendored
Normal file
190
frontend/node_modules/react-day-picker/src/contexts/SelectMultiple/SelectMultipleContext.test.ts
generated
vendored
Normal file
@ -0,0 +1,190 @@
|
||||
import { MouseEvent } from 'react';
|
||||
|
||||
import { addDays, addMonths } from 'date-fns';
|
||||
import { DayPickerProps } from 'DayPicker';
|
||||
|
||||
import { renderDayPickerHook } from 'test/render';
|
||||
import { freezeBeforeAll } from 'test/utils';
|
||||
|
||||
import { isMatch } from 'contexts/Modifiers/utils/isMatch';
|
||||
import { DayPickerMultipleProps } from 'types/DayPickerMultiple';
|
||||
import { ActiveModifiers } from 'types/Modifiers';
|
||||
|
||||
import {
|
||||
SelectMultipleContextValue,
|
||||
useSelectMultiple
|
||||
} from './SelectMultipleContext';
|
||||
|
||||
const today = new Date(2021, 11, 8);
|
||||
freezeBeforeAll(today);
|
||||
|
||||
function renderHook(props?: Partial<DayPickerProps>) {
|
||||
return renderDayPickerHook<SelectMultipleContextValue>(
|
||||
useSelectMultiple,
|
||||
props
|
||||
);
|
||||
}
|
||||
|
||||
describe('when is not a multiple select DayPicker', () => {
|
||||
const result = renderHook();
|
||||
test('the selected day should be undefined', () => {
|
||||
expect(result.current.selected).toBeUndefined();
|
||||
});
|
||||
test('the disabled modifiers should be empty', () => {
|
||||
expect(result.current.selected).toBeUndefined();
|
||||
});
|
||||
});
|
||||
|
||||
const initialProps: DayPickerMultipleProps = {
|
||||
mode: 'multiple',
|
||||
onDayClick: jest.fn(),
|
||||
onSelect: jest.fn()
|
||||
};
|
||||
|
||||
const selectedDay1 = today;
|
||||
const selectedDay2 = addDays(today, 1);
|
||||
const selectedDay3 = addDays(today, 4);
|
||||
|
||||
describe('when days are selected', () => {
|
||||
const selected = [selectedDay1, selectedDay2, selectedDay3];
|
||||
const dayPickerProps: DayPickerMultipleProps = {
|
||||
...initialProps,
|
||||
selected
|
||||
};
|
||||
|
||||
test('it should return the days as selected', () => {
|
||||
const result = renderHook(dayPickerProps);
|
||||
expect(result.current.selected).toStrictEqual(selected);
|
||||
});
|
||||
describe('when `onDayClick` is called with a not selected day', () => {
|
||||
const clickedDay = addDays(selectedDay1, -1);
|
||||
const activeModifiers = {};
|
||||
const event = {} as MouseEvent;
|
||||
beforeAll(() => {
|
||||
const result = renderHook(dayPickerProps);
|
||||
result.current.onDayClick?.(clickedDay, activeModifiers, event);
|
||||
});
|
||||
afterAll(() => {
|
||||
jest.resetAllMocks();
|
||||
});
|
||||
|
||||
test('should call the `onDayClick` from the DayPicker props', () => {
|
||||
expect(dayPickerProps.onDayClick).toHaveBeenCalledWith(
|
||||
clickedDay,
|
||||
activeModifiers,
|
||||
event
|
||||
);
|
||||
});
|
||||
test('should call `onSelect` with the clicked day selected', () => {
|
||||
expect(dayPickerProps.onSelect).toHaveBeenCalledWith(
|
||||
[...selected, clickedDay],
|
||||
clickedDay,
|
||||
activeModifiers,
|
||||
event
|
||||
);
|
||||
});
|
||||
});
|
||||
describe('when `onDayClick` is called with a selected day', () => {
|
||||
const clickedDay = selectedDay1;
|
||||
const activeModifiers: ActiveModifiers = { selected: true };
|
||||
beforeAll(() => {
|
||||
const result = renderHook(dayPickerProps);
|
||||
result.current.onDayClick?.(clickedDay, activeModifiers, event);
|
||||
});
|
||||
afterAll(() => {
|
||||
jest.resetAllMocks();
|
||||
});
|
||||
const event = {} as MouseEvent;
|
||||
test('should call the `onDayClick` from the DayPicker props', () => {
|
||||
expect(dayPickerProps.onDayClick).toHaveBeenCalledWith(
|
||||
clickedDay,
|
||||
activeModifiers,
|
||||
event
|
||||
);
|
||||
});
|
||||
test('should call `onSelect` without the clicked day selected', () => {
|
||||
const expectedSelected = selected.filter((day) => day !== clickedDay);
|
||||
expect(dayPickerProps.onSelect).toHaveBeenCalledWith(
|
||||
expectedSelected,
|
||||
clickedDay,
|
||||
activeModifiers,
|
||||
event
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('when the maximum number of days are selected', () => {
|
||||
const selected = [selectedDay1, selectedDay2, selectedDay3];
|
||||
const dayPickerProps: DayPickerMultipleProps = {
|
||||
...initialProps,
|
||||
selected,
|
||||
max: selected.length
|
||||
};
|
||||
test('the selected days should not be disabled', () => {
|
||||
const result = renderHook(dayPickerProps);
|
||||
const { disabled } = result.current.modifiers;
|
||||
expect(isMatch(selectedDay1, disabled)).toBe(false);
|
||||
expect(isMatch(selectedDay2, disabled)).toBe(false);
|
||||
expect(isMatch(selectedDay3, disabled)).toBe(false);
|
||||
});
|
||||
test('the other days should be disabled', () => {
|
||||
const result = renderHook(dayPickerProps);
|
||||
const { disabled } = result.current.modifiers;
|
||||
expect(isMatch(addMonths(selectedDay1, 1), disabled)).toBe(true);
|
||||
expect(isMatch(addMonths(selectedDay2, 1), disabled)).toBe(true);
|
||||
});
|
||||
describe('when `onDayClick` is called', () => {
|
||||
const clickedDay = addMonths(selectedDay1, 1);
|
||||
const activeModifiers: ActiveModifiers = {};
|
||||
beforeAll(() => {
|
||||
const result = renderHook(dayPickerProps);
|
||||
result.current.onDayClick?.(clickedDay, activeModifiers, event);
|
||||
});
|
||||
afterAll(() => {
|
||||
jest.resetAllMocks();
|
||||
});
|
||||
const event = {} as MouseEvent;
|
||||
test('should call the `onDayClick` from the DayPicker props', () => {
|
||||
expect(dayPickerProps.onDayClick).toHaveBeenCalledWith(
|
||||
clickedDay,
|
||||
activeModifiers,
|
||||
event
|
||||
);
|
||||
});
|
||||
test('should not call `onSelect`', () => {
|
||||
expect(dayPickerProps.onSelect).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('when the minimum number of days are selected', () => {
|
||||
const selected = [selectedDay1, selectedDay2, selectedDay3];
|
||||
const dayPickerProps: DayPickerMultipleProps = {
|
||||
...initialProps,
|
||||
selected,
|
||||
min: selected.length
|
||||
};
|
||||
describe('when `onDayClick` is called with one of the selected days', () => {
|
||||
const clickedDay = selected[0];
|
||||
const activeModifiers: ActiveModifiers = { selected: true };
|
||||
beforeAll(() => {
|
||||
const result = renderHook(dayPickerProps);
|
||||
result.current.onDayClick?.(clickedDay, activeModifiers, event);
|
||||
});
|
||||
afterAll(() => {
|
||||
jest.resetAllMocks();
|
||||
});
|
||||
const event = {} as MouseEvent;
|
||||
test('should call the `onDayClick` from the DayPicker props', () => {
|
||||
expect(dayPickerProps.onDayClick).toHaveBeenCalledWith(
|
||||
clickedDay,
|
||||
activeModifiers,
|
||||
event
|
||||
);
|
||||
});
|
||||
test('should not call `onSelect`', () => {
|
||||
expect(dayPickerProps.onSelect).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
});
|
||||
151
frontend/node_modules/react-day-picker/src/contexts/SelectMultiple/SelectMultipleContext.tsx
generated
vendored
Normal file
151
frontend/node_modules/react-day-picker/src/contexts/SelectMultiple/SelectMultipleContext.tsx
generated
vendored
Normal file
@ -0,0 +1,151 @@
|
||||
import { createContext, ReactNode, useContext } from 'react';
|
||||
|
||||
import { isSameDay } from 'date-fns';
|
||||
|
||||
import { DayPickerBase } from 'types/DayPickerBase';
|
||||
import {
|
||||
DayPickerMultipleProps,
|
||||
isDayPickerMultiple
|
||||
} from 'types/DayPickerMultiple';
|
||||
import { DayClickEventHandler } from 'types/EventHandlers';
|
||||
import { InternalModifier, Modifiers } from 'types/Modifiers';
|
||||
|
||||
/** Represent the modifiers that are changed by the multiple selection. */
|
||||
export type SelectMultipleModifiers = Pick<
|
||||
Modifiers,
|
||||
InternalModifier.Disabled
|
||||
>;
|
||||
|
||||
/** Represents the value of a {@link SelectMultipleContext}. */
|
||||
export interface SelectMultipleContextValue {
|
||||
/** The days that have been selected. */
|
||||
selected: Date[] | undefined;
|
||||
/** The modifiers for the corresponding selection. */
|
||||
modifiers: SelectMultipleModifiers;
|
||||
/** Event handler to attach to the day button to enable the multiple select. */
|
||||
onDayClick?: DayClickEventHandler;
|
||||
}
|
||||
|
||||
/**
|
||||
* The SelectMultiple context shares details about the selected days when in
|
||||
* multiple selection mode.
|
||||
*
|
||||
* Access this context from the {@link useSelectMultiple} hook.
|
||||
*/
|
||||
export const SelectMultipleContext = createContext<
|
||||
SelectMultipleContextValue | undefined
|
||||
>(undefined);
|
||||
|
||||
export type SelectMultipleProviderProps = {
|
||||
initialProps: DayPickerBase;
|
||||
children?: ReactNode;
|
||||
};
|
||||
|
||||
/** Provides the values for the {@link SelectMultipleContext}. */
|
||||
export function SelectMultipleProvider(
|
||||
props: SelectMultipleProviderProps
|
||||
): JSX.Element {
|
||||
if (!isDayPickerMultiple(props.initialProps)) {
|
||||
const emptyContextValue: SelectMultipleContextValue = {
|
||||
selected: undefined,
|
||||
modifiers: {
|
||||
disabled: []
|
||||
}
|
||||
};
|
||||
return (
|
||||
<SelectMultipleContext.Provider value={emptyContextValue}>
|
||||
{props.children}
|
||||
</SelectMultipleContext.Provider>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<SelectMultipleProviderInternal
|
||||
initialProps={props.initialProps}
|
||||
children={props.children}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
/** @private */
|
||||
export interface SelectMultipleProviderInternalProps {
|
||||
initialProps: DayPickerMultipleProps;
|
||||
children?: ReactNode;
|
||||
}
|
||||
|
||||
export function SelectMultipleProviderInternal({
|
||||
initialProps,
|
||||
children
|
||||
}: SelectMultipleProviderInternalProps): JSX.Element {
|
||||
const { selected, min, max } = initialProps;
|
||||
|
||||
const onDayClick: DayClickEventHandler = (day, activeModifiers, e) => {
|
||||
initialProps.onDayClick?.(day, activeModifiers, e);
|
||||
|
||||
const isMinSelected = Boolean(
|
||||
activeModifiers.selected && min && selected?.length === min
|
||||
);
|
||||
if (isMinSelected) {
|
||||
return;
|
||||
}
|
||||
|
||||
const isMaxSelected = Boolean(
|
||||
!activeModifiers.selected && max && selected?.length === max
|
||||
);
|
||||
if (isMaxSelected) {
|
||||
return;
|
||||
}
|
||||
|
||||
const selectedDays = selected ? [...selected] : [];
|
||||
|
||||
if (activeModifiers.selected) {
|
||||
const index = selectedDays.findIndex((selectedDay) =>
|
||||
isSameDay(day, selectedDay)
|
||||
);
|
||||
selectedDays.splice(index, 1);
|
||||
} else {
|
||||
selectedDays.push(day);
|
||||
}
|
||||
initialProps.onSelect?.(selectedDays, day, activeModifiers, e);
|
||||
};
|
||||
|
||||
const modifiers: SelectMultipleModifiers = {
|
||||
disabled: []
|
||||
};
|
||||
|
||||
if (selected) {
|
||||
modifiers.disabled.push((day: Date) => {
|
||||
const isMaxSelected = max && selected.length > max - 1;
|
||||
const isSelected = selected.some((selectedDay) =>
|
||||
isSameDay(selectedDay, day)
|
||||
);
|
||||
return Boolean(isMaxSelected && !isSelected);
|
||||
});
|
||||
}
|
||||
|
||||
const contextValue = {
|
||||
selected,
|
||||
onDayClick,
|
||||
modifiers
|
||||
};
|
||||
|
||||
return (
|
||||
<SelectMultipleContext.Provider value={contextValue}>
|
||||
{children}
|
||||
</SelectMultipleContext.Provider>
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Hook to access the {@link SelectMultipleContextValue}.
|
||||
*
|
||||
* This hook is meant to be used inside internal or custom components.
|
||||
*/
|
||||
export function useSelectMultiple(): SelectMultipleContextValue {
|
||||
const context = useContext(SelectMultipleContext);
|
||||
if (!context) {
|
||||
throw new Error(
|
||||
'useSelectMultiple must be used within a SelectMultipleProvider'
|
||||
);
|
||||
}
|
||||
return context;
|
||||
}
|
||||
1
frontend/node_modules/react-day-picker/src/contexts/SelectMultiple/index.ts
generated
vendored
Normal file
1
frontend/node_modules/react-day-picker/src/contexts/SelectMultiple/index.ts
generated
vendored
Normal file
@ -0,0 +1 @@
|
||||
export * from './SelectMultipleContext';
|
||||
302
frontend/node_modules/react-day-picker/src/contexts/SelectRange/SelectRangeContext.test.ts
generated
vendored
Normal file
302
frontend/node_modules/react-day-picker/src/contexts/SelectRange/SelectRangeContext.test.ts
generated
vendored
Normal file
@ -0,0 +1,302 @@
|
||||
import { MouseEvent } from 'react';
|
||||
|
||||
import {
|
||||
addDays,
|
||||
addMonths,
|
||||
differenceInCalendarDays,
|
||||
subDays
|
||||
} from 'date-fns';
|
||||
import { DayPickerProps } from 'DayPicker';
|
||||
|
||||
import { renderDayPickerHook } from 'test/render';
|
||||
import { freezeBeforeAll } from 'test/utils';
|
||||
|
||||
import { isMatch } from 'contexts/Modifiers/utils/isMatch';
|
||||
import { DayPickerRangeProps } from 'types/DayPickerRange';
|
||||
import { ActiveModifiers } from 'types/Modifiers';
|
||||
|
||||
import { SelectRangeContextValue, useSelectRange } from './SelectRangeContext';
|
||||
|
||||
const today = new Date(2021, 11, 8);
|
||||
freezeBeforeAll(today);
|
||||
|
||||
function renderHook(props?: Partial<DayPickerProps>) {
|
||||
return renderDayPickerHook<SelectRangeContextValue>(useSelectRange, props);
|
||||
}
|
||||
describe('when is not a multiple select DayPicker', () => {
|
||||
test('the selected day should be undefined', () => {
|
||||
const result = renderHook();
|
||||
expect(result.current.selected).toBeUndefined();
|
||||
});
|
||||
});
|
||||
|
||||
const initialProps: DayPickerRangeProps = {
|
||||
mode: 'range',
|
||||
onDayClick: jest.fn(),
|
||||
onSelect: jest.fn()
|
||||
};
|
||||
|
||||
const from = today;
|
||||
const to = addDays(today, 6);
|
||||
const stubEvent = {} as MouseEvent;
|
||||
|
||||
describe('when no days are selected', () => {
|
||||
test('the selected days should be undefined', () => {
|
||||
const result = renderHook();
|
||||
expect(result.current.selected).toBeUndefined();
|
||||
});
|
||||
describe('when "onDayClick" is called', () => {
|
||||
const day = from;
|
||||
const activeModifiers = {};
|
||||
beforeAll(() => {
|
||||
const result = renderHook(initialProps);
|
||||
result.current.onDayClick?.(day, activeModifiers, stubEvent);
|
||||
});
|
||||
afterAll(() => {
|
||||
jest.resetAllMocks();
|
||||
});
|
||||
test('should call the "onDayClick" from the DayPicker props', () => {
|
||||
expect(initialProps.onDayClick).toHaveBeenCalledWith(
|
||||
day,
|
||||
activeModifiers,
|
||||
stubEvent
|
||||
);
|
||||
});
|
||||
test('should call "onSelect" with the clicked day as the "from" prop', () => {
|
||||
expect(initialProps.onSelect).toHaveBeenCalledWith(
|
||||
{ from: day, to: undefined },
|
||||
day,
|
||||
activeModifiers,
|
||||
stubEvent
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('when only the "from" day is selected', () => {
|
||||
const selected = { from, to: undefined };
|
||||
const dayPickerProps: DayPickerRangeProps = {
|
||||
...initialProps,
|
||||
selected
|
||||
};
|
||||
test('should return the "range_start" modifiers with the "from" day', () => {
|
||||
const result = renderHook(dayPickerProps);
|
||||
expect(result.current.modifiers.range_start).toEqual([from]);
|
||||
});
|
||||
test('should return the "range_end" modifiers with the "from" day', () => {
|
||||
const result = renderHook(dayPickerProps);
|
||||
expect(result.current.modifiers.range_end).toEqual([from]);
|
||||
});
|
||||
test('should not return any "range_middle" modifiers', () => {
|
||||
const result = renderHook(dayPickerProps);
|
||||
expect(result.current.modifiers.range_middle).toEqual([]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('when only the "to" day is selected', () => {
|
||||
const selected = { from: undefined, to };
|
||||
const dayPickerProps: DayPickerRangeProps = {
|
||||
...initialProps,
|
||||
selected
|
||||
};
|
||||
test('should return the "range_start" modifiers with the "to" day', () => {
|
||||
const result = renderHook(dayPickerProps);
|
||||
expect(result.current.modifiers.range_start).toEqual([to]);
|
||||
});
|
||||
test('should return the "range_end" modifiers with the "to" day', () => {
|
||||
const result = renderHook(dayPickerProps);
|
||||
expect(result.current.modifiers.range_end).toEqual([to]);
|
||||
});
|
||||
test('should not return any "range_middle" modifiers', () => {
|
||||
const result = renderHook(dayPickerProps);
|
||||
expect(result.current.modifiers.range_middle).toEqual([]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('when a complete range of days is selected', () => {
|
||||
const selected = { from, to };
|
||||
const dayPickerProps: DayPickerRangeProps = {
|
||||
...initialProps,
|
||||
selected
|
||||
};
|
||||
test('should return the "range_start" modifiers with the "from" day', () => {
|
||||
const result = renderHook(dayPickerProps);
|
||||
expect(result.current.modifiers.range_start).toEqual([from]);
|
||||
});
|
||||
test('should return the "range_end" modifiers with the "to" day', () => {
|
||||
const result = renderHook(dayPickerProps);
|
||||
expect(result.current.modifiers.range_end).toEqual([to]);
|
||||
});
|
||||
test('should return the "range_middle" range modifiers', () => {
|
||||
const result = renderHook(dayPickerProps);
|
||||
expect(result.current.modifiers.range_middle).toEqual([
|
||||
{ after: from, before: to }
|
||||
]);
|
||||
});
|
||||
describe('when "onDayClick" is called with the day before the from day', () => {
|
||||
const day = addDays(from, -1);
|
||||
const activeModifiers = {};
|
||||
|
||||
beforeAll(() => {
|
||||
const result = renderHook(dayPickerProps);
|
||||
result.current.onDayClick?.(day, activeModifiers, stubEvent);
|
||||
});
|
||||
afterAll(() => {
|
||||
jest.resetAllMocks();
|
||||
});
|
||||
test('should call the "onDayClick" from the DayPicker props', () => {
|
||||
expect(dayPickerProps.onDayClick).toHaveBeenCalledWith(
|
||||
day,
|
||||
activeModifiers,
|
||||
stubEvent
|
||||
);
|
||||
});
|
||||
test('should call "onSelect" with the day selected', () => {
|
||||
expect(dayPickerProps.onSelect).toHaveBeenCalledWith(
|
||||
{ from: day, to },
|
||||
day,
|
||||
activeModifiers,
|
||||
stubEvent
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('when "from" and "to" are the same', () => {
|
||||
const date = new Date();
|
||||
const selected = { from: date, to: date };
|
||||
const dayPickerProps: DayPickerRangeProps = {
|
||||
...initialProps,
|
||||
selected
|
||||
};
|
||||
test('should return the "range_start" modifier with the date', () => {
|
||||
const result = renderHook(dayPickerProps);
|
||||
expect(result.current.modifiers.range_start).toEqual([date]);
|
||||
});
|
||||
test('should return the "range_end" modifier with the date', () => {
|
||||
const result = renderHook(dayPickerProps);
|
||||
expect(result.current.modifiers.range_end).toEqual([date]);
|
||||
});
|
||||
test('should return an empty "range_middle"', () => {
|
||||
const result = renderHook(dayPickerProps);
|
||||
expect(result.current.modifiers.range_middle).toEqual([]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('when the max number of the selected days is reached', () => {
|
||||
const from = today;
|
||||
const to = addDays(today, 6);
|
||||
const selected = { from, to };
|
||||
const dayPickerProps: DayPickerRangeProps = {
|
||||
...initialProps,
|
||||
selected,
|
||||
max: 7
|
||||
};
|
||||
test('the days in the range should not be disabled', () => {
|
||||
const result = renderHook(dayPickerProps);
|
||||
const { disabled } = result.current.modifiers;
|
||||
expect(isMatch(from, disabled)).toBe(false);
|
||||
expect(isMatch(to, disabled)).toBe(false);
|
||||
});
|
||||
test('the other days should be disabled', () => {
|
||||
const result = renderHook(dayPickerProps);
|
||||
const { disabled } = result.current.modifiers;
|
||||
expect(isMatch(addMonths(from, 1), disabled)).toBe(true);
|
||||
});
|
||||
describe('when "onDayClick" is called with a new day', () => {
|
||||
const day = addMonths(from, 1);
|
||||
const activeModifiers: ActiveModifiers = {};
|
||||
|
||||
beforeAll(() => {
|
||||
const result = renderHook(dayPickerProps);
|
||||
result.current.onDayClick?.(day, activeModifiers, stubEvent);
|
||||
});
|
||||
afterAll(() => {
|
||||
jest.resetAllMocks();
|
||||
});
|
||||
test('should call the "onDayClick" from the DayPicker props', () => {
|
||||
expect(dayPickerProps.onDayClick).toHaveBeenCalledWith(
|
||||
day,
|
||||
activeModifiers,
|
||||
stubEvent
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('when the minimum number of days are selected', () => {
|
||||
const selected = { from, to };
|
||||
const dayPickerProps: DayPickerRangeProps = {
|
||||
...initialProps,
|
||||
selected,
|
||||
min: Math.abs(differenceInCalendarDays(to, from))
|
||||
};
|
||||
describe('when "onDayClick" is called with a day before "from"', () => {
|
||||
const day = subDays(from, 1);
|
||||
const activeModifiers: ActiveModifiers = { selected: true };
|
||||
|
||||
beforeAll(() => {
|
||||
const result = renderHook(dayPickerProps);
|
||||
result.current.onDayClick?.(day, activeModifiers, stubEvent);
|
||||
});
|
||||
afterAll(() => {
|
||||
jest.resetAllMocks();
|
||||
});
|
||||
test('should call "onSelect" with the day included in the range', () => {
|
||||
expect(dayPickerProps.onSelect).toHaveBeenCalledWith(
|
||||
{ from: day, to },
|
||||
day,
|
||||
activeModifiers,
|
||||
stubEvent
|
||||
);
|
||||
});
|
||||
});
|
||||
describe('when "onDayClick" is called with the "from" day', () => {
|
||||
const day = from;
|
||||
const activeModifiers: ActiveModifiers = { selected: true };
|
||||
beforeAll(() => {
|
||||
const result = renderHook(dayPickerProps);
|
||||
result.current.onDayClick?.(day, activeModifiers, stubEvent);
|
||||
});
|
||||
afterAll(() => {
|
||||
jest.resetAllMocks();
|
||||
});
|
||||
|
||||
test('should call the "onDayClick" from the DayPicker props', () => {
|
||||
expect(dayPickerProps.onDayClick).toHaveBeenCalledWith(
|
||||
day,
|
||||
activeModifiers,
|
||||
stubEvent
|
||||
);
|
||||
});
|
||||
test('should call "onSelect" with an undefined range', () => {
|
||||
expect(dayPickerProps.onSelect).toHaveBeenCalledWith(
|
||||
undefined,
|
||||
day,
|
||||
activeModifiers,
|
||||
stubEvent
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('when "onDayClick" is called with the "to" day', () => {
|
||||
const day = to;
|
||||
const activeModifiers: ActiveModifiers = { selected: true };
|
||||
beforeAll(() => {
|
||||
const result = renderHook(dayPickerProps);
|
||||
result.current.onDayClick?.(day, activeModifiers, stubEvent);
|
||||
});
|
||||
afterAll(() => {
|
||||
jest.resetAllMocks();
|
||||
});
|
||||
|
||||
test('should call "onSelect" without the "to" in the range', () => {
|
||||
expect(dayPickerProps.onSelect).toHaveBeenCalledWith(
|
||||
{ from: day, to: undefined },
|
||||
day,
|
||||
activeModifiers,
|
||||
stubEvent
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
196
frontend/node_modules/react-day-picker/src/contexts/SelectRange/SelectRangeContext.tsx
generated
vendored
Normal file
196
frontend/node_modules/react-day-picker/src/contexts/SelectRange/SelectRangeContext.tsx
generated
vendored
Normal file
@ -0,0 +1,196 @@
|
||||
import { createContext, ReactNode, useContext } from 'react';
|
||||
|
||||
import {
|
||||
addDays,
|
||||
differenceInCalendarDays,
|
||||
isSameDay,
|
||||
subDays
|
||||
} from 'date-fns';
|
||||
|
||||
import { DayPickerBase } from 'types/DayPickerBase';
|
||||
import { DayPickerRangeProps, isDayPickerRange } from 'types/DayPickerRange';
|
||||
import { DayClickEventHandler } from 'types/EventHandlers';
|
||||
import { DateRange } from 'types/Matchers';
|
||||
import { InternalModifier, Modifiers } from 'types/Modifiers';
|
||||
|
||||
import { addToRange } from './utils/addToRange';
|
||||
|
||||
/** Represent the modifiers that are changed by the range selection. */
|
||||
export type SelectRangeModifiers = Pick<
|
||||
Modifiers,
|
||||
| InternalModifier.Disabled
|
||||
| InternalModifier.RangeEnd
|
||||
| InternalModifier.RangeMiddle
|
||||
| InternalModifier.RangeStart
|
||||
>;
|
||||
|
||||
/** Represents the value of a {@link SelectRangeContext}. */
|
||||
export interface SelectRangeContextValue {
|
||||
/** The range of days that has been selected. */
|
||||
selected: DateRange | undefined;
|
||||
/** The modifiers for the corresponding selection. */
|
||||
modifiers: SelectRangeModifiers;
|
||||
/** Event handler to attach to the day button to enable the range select. */
|
||||
onDayClick?: DayClickEventHandler;
|
||||
}
|
||||
|
||||
/**
|
||||
* The SelectRange context shares details about the selected days when in
|
||||
* range selection mode.
|
||||
*
|
||||
* Access this context from the {@link useSelectRange} hook.
|
||||
*/
|
||||
export const SelectRangeContext = createContext<
|
||||
SelectRangeContextValue | undefined
|
||||
>(undefined);
|
||||
|
||||
export interface SelectRangeProviderProps {
|
||||
initialProps: DayPickerBase;
|
||||
children?: ReactNode;
|
||||
}
|
||||
|
||||
/** Provides the values for the {@link SelectRangeProvider}. */
|
||||
export function SelectRangeProvider(
|
||||
props: SelectRangeProviderProps
|
||||
): JSX.Element {
|
||||
if (!isDayPickerRange(props.initialProps)) {
|
||||
const emptyContextValue: SelectRangeContextValue = {
|
||||
selected: undefined,
|
||||
modifiers: {
|
||||
range_start: [],
|
||||
range_end: [],
|
||||
range_middle: [],
|
||||
disabled: []
|
||||
}
|
||||
};
|
||||
return (
|
||||
<SelectRangeContext.Provider value={emptyContextValue}>
|
||||
{props.children}
|
||||
</SelectRangeContext.Provider>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<SelectRangeProviderInternal
|
||||
initialProps={props.initialProps}
|
||||
children={props.children}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
/** @private */
|
||||
export interface SelectRangeProviderInternalProps {
|
||||
initialProps: DayPickerRangeProps;
|
||||
children?: ReactNode;
|
||||
}
|
||||
|
||||
export function SelectRangeProviderInternal({
|
||||
initialProps,
|
||||
children
|
||||
}: SelectRangeProviderInternalProps): JSX.Element {
|
||||
const { selected } = initialProps;
|
||||
const { from: selectedFrom, to: selectedTo } = selected || {};
|
||||
const min = initialProps.min;
|
||||
const max = initialProps.max;
|
||||
|
||||
const onDayClick: DayClickEventHandler = (day, activeModifiers, e) => {
|
||||
initialProps.onDayClick?.(day, activeModifiers, e);
|
||||
const newRange = addToRange(day, selected);
|
||||
initialProps.onSelect?.(newRange, day, activeModifiers, e);
|
||||
};
|
||||
|
||||
const modifiers: SelectRangeModifiers = {
|
||||
range_start: [],
|
||||
range_end: [],
|
||||
range_middle: [],
|
||||
disabled: []
|
||||
};
|
||||
|
||||
if (selectedFrom) {
|
||||
modifiers.range_start = [selectedFrom];
|
||||
if (!selectedTo) {
|
||||
modifiers.range_end = [selectedFrom];
|
||||
} else {
|
||||
modifiers.range_end = [selectedTo];
|
||||
if (!isSameDay(selectedFrom, selectedTo)) {
|
||||
modifiers.range_middle = [
|
||||
{
|
||||
after: selectedFrom,
|
||||
before: selectedTo
|
||||
}
|
||||
];
|
||||
}
|
||||
}
|
||||
} else if (selectedTo) {
|
||||
modifiers.range_start = [selectedTo];
|
||||
modifiers.range_end = [selectedTo];
|
||||
}
|
||||
|
||||
if (min) {
|
||||
if (selectedFrom && !selectedTo) {
|
||||
modifiers.disabled.push({
|
||||
after: subDays(selectedFrom, min - 1),
|
||||
before: addDays(selectedFrom, min - 1)
|
||||
});
|
||||
}
|
||||
if (selectedFrom && selectedTo) {
|
||||
modifiers.disabled.push({
|
||||
after: selectedFrom,
|
||||
before: addDays(selectedFrom, min - 1)
|
||||
});
|
||||
}
|
||||
if (!selectedFrom && selectedTo) {
|
||||
modifiers.disabled.push({
|
||||
after: subDays(selectedTo, min - 1),
|
||||
before: addDays(selectedTo, min - 1)
|
||||
});
|
||||
}
|
||||
}
|
||||
if (max) {
|
||||
if (selectedFrom && !selectedTo) {
|
||||
modifiers.disabled.push({
|
||||
before: addDays(selectedFrom, -max + 1)
|
||||
});
|
||||
modifiers.disabled.push({
|
||||
after: addDays(selectedFrom, max - 1)
|
||||
});
|
||||
}
|
||||
if (selectedFrom && selectedTo) {
|
||||
const selectedCount =
|
||||
differenceInCalendarDays(selectedTo, selectedFrom) + 1;
|
||||
const offset = max - selectedCount;
|
||||
modifiers.disabled.push({
|
||||
before: subDays(selectedFrom, offset)
|
||||
});
|
||||
modifiers.disabled.push({
|
||||
after: addDays(selectedTo, offset)
|
||||
});
|
||||
}
|
||||
if (!selectedFrom && selectedTo) {
|
||||
modifiers.disabled.push({
|
||||
before: addDays(selectedTo, -max + 1)
|
||||
});
|
||||
modifiers.disabled.push({
|
||||
after: addDays(selectedTo, max - 1)
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<SelectRangeContext.Provider value={{ selected, onDayClick, modifiers }}>
|
||||
{children}
|
||||
</SelectRangeContext.Provider>
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Hook to access the {@link SelectRangeContextValue}.
|
||||
*
|
||||
* This hook is meant to be used inside internal or custom components.
|
||||
*/
|
||||
export function useSelectRange(): SelectRangeContextValue {
|
||||
const context = useContext(SelectRangeContext);
|
||||
if (!context) {
|
||||
throw new Error('useSelectRange must be used within a SelectRangeProvider');
|
||||
}
|
||||
return context;
|
||||
}
|
||||
1
frontend/node_modules/react-day-picker/src/contexts/SelectRange/index.ts
generated
vendored
Normal file
1
frontend/node_modules/react-day-picker/src/contexts/SelectRange/index.ts
generated
vendored
Normal file
@ -0,0 +1 @@
|
||||
export * from './SelectRangeContext';
|
||||
119
frontend/node_modules/react-day-picker/src/contexts/SelectRange/utils/addToRange.test.ts
generated
vendored
Normal file
119
frontend/node_modules/react-day-picker/src/contexts/SelectRange/utils/addToRange.test.ts
generated
vendored
Normal file
@ -0,0 +1,119 @@
|
||||
import { addDays, subDays } from 'date-fns';
|
||||
|
||||
import { DateRange } from 'types/Matchers';
|
||||
|
||||
import { addToRange } from './addToRange';
|
||||
|
||||
describe('when no "from" is the range', () => {
|
||||
const range = { from: undefined };
|
||||
const day = new Date();
|
||||
let result: DateRange | undefined;
|
||||
beforeAll(() => {
|
||||
result = addToRange(day, range);
|
||||
});
|
||||
test('should set "from" as the given day', () => {
|
||||
expect(result).toEqual({ from: day, to: undefined });
|
||||
});
|
||||
});
|
||||
|
||||
describe('when no "to" is the range', () => {
|
||||
const day = new Date();
|
||||
const range = { from: day, to: undefined };
|
||||
describe('and the day is the same as the "from" day', () => {
|
||||
let result: DateRange | undefined;
|
||||
beforeAll(() => {
|
||||
result = addToRange(day, range);
|
||||
});
|
||||
test('should return it in the range', () => {
|
||||
expect(result).toEqual({ from: day, to: day });
|
||||
});
|
||||
});
|
||||
describe('and the day is before "from" day', () => {
|
||||
const day = subDays(range.from, 1);
|
||||
let result: DateRange | undefined;
|
||||
beforeAll(() => {
|
||||
result = addToRange(day, range);
|
||||
});
|
||||
test('should set the day as the "from" range', () => {
|
||||
expect(result).toEqual({ from: day, to: range.from });
|
||||
});
|
||||
});
|
||||
describe('and the day is after the "from" day', () => {
|
||||
const day = addDays(range.from, 1);
|
||||
let result: DateRange | undefined;
|
||||
beforeAll(() => {
|
||||
result = addToRange(day, range);
|
||||
});
|
||||
test('should set the day as the "to" date', () => {
|
||||
expect(result).toEqual({ from: range.from, to: day });
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('when "from", "to" and "day" are the same', () => {
|
||||
const day = new Date();
|
||||
const range = { from: day, to: day };
|
||||
let result: DateRange | undefined;
|
||||
beforeAll(() => {
|
||||
result = addToRange(day, range);
|
||||
});
|
||||
test('should return an undefined range (reset)', () => {
|
||||
expect(result).toBeUndefined();
|
||||
});
|
||||
});
|
||||
|
||||
describe('when "to" and "day" are the same', () => {
|
||||
const from = new Date();
|
||||
const to = addDays(from, 4);
|
||||
const day = to;
|
||||
const range = { from, to };
|
||||
let result: DateRange | undefined;
|
||||
beforeAll(() => {
|
||||
result = addToRange(day, range);
|
||||
});
|
||||
test('should set "to" to undefined', () => {
|
||||
expect(result).toEqual({ from: to, to: undefined });
|
||||
});
|
||||
});
|
||||
|
||||
describe('when "from" and "day" are the same', () => {
|
||||
const from = new Date();
|
||||
const to = addDays(from, 4);
|
||||
const day = from;
|
||||
const range = { from, to };
|
||||
let result: DateRange | undefined;
|
||||
beforeAll(() => {
|
||||
result = addToRange(day, range);
|
||||
});
|
||||
test('should return an undefined range (reset)', () => {
|
||||
expect(result).toBeUndefined();
|
||||
});
|
||||
});
|
||||
|
||||
describe('when "from" is after "day"', () => {
|
||||
const day = new Date();
|
||||
const from = addDays(day, 1);
|
||||
const to = addDays(from, 4);
|
||||
const range = { from, to };
|
||||
let result: DateRange | undefined;
|
||||
beforeAll(() => {
|
||||
result = addToRange(day, range);
|
||||
});
|
||||
test('should set the day as "from"', () => {
|
||||
expect(result).toEqual({ from: day, to: range.to });
|
||||
});
|
||||
});
|
||||
|
||||
describe('when "from" is before "day"', () => {
|
||||
const day = new Date();
|
||||
const from = subDays(day, 1);
|
||||
const to = addDays(from, 4);
|
||||
const range = { from, to };
|
||||
let result: DateRange | undefined;
|
||||
beforeAll(() => {
|
||||
result = addToRange(day, range);
|
||||
});
|
||||
test('should set the day as "to"', () => {
|
||||
expect(result).toEqual({ from: range.from, to: day });
|
||||
});
|
||||
});
|
||||
44
frontend/node_modules/react-day-picker/src/contexts/SelectRange/utils/addToRange.ts
generated
vendored
Normal file
44
frontend/node_modules/react-day-picker/src/contexts/SelectRange/utils/addToRange.ts
generated
vendored
Normal file
@ -0,0 +1,44 @@
|
||||
import { isAfter, isBefore, isSameDay } from 'date-fns';
|
||||
|
||||
import { DateRange } from 'types/Matchers';
|
||||
|
||||
/**
|
||||
* Add a day to an existing range.
|
||||
*
|
||||
* The returned range takes in account the `undefined` values and if the added
|
||||
* day is already present in the range.
|
||||
*/
|
||||
export function addToRange(
|
||||
day: Date,
|
||||
range?: DateRange
|
||||
): DateRange | undefined {
|
||||
const { from, to } = range || {};
|
||||
if (from && to) {
|
||||
if (isSameDay(to, day) && isSameDay(from, day)) {
|
||||
return undefined;
|
||||
}
|
||||
if (isSameDay(to, day)) {
|
||||
return { from: to, to: undefined };
|
||||
}
|
||||
if (isSameDay(from, day)) {
|
||||
return undefined;
|
||||
}
|
||||
if (isAfter(from, day)) {
|
||||
return { from: day, to };
|
||||
}
|
||||
return { from, to: day };
|
||||
}
|
||||
if (to) {
|
||||
if (isAfter(day, to)) {
|
||||
return { from: to, to: day };
|
||||
}
|
||||
return { from: day, to };
|
||||
}
|
||||
if (from) {
|
||||
if (isBefore(day, from)) {
|
||||
return { from: day, to: from };
|
||||
}
|
||||
return { from, to: day };
|
||||
}
|
||||
return { from: day, to: undefined };
|
||||
}
|
||||
84
frontend/node_modules/react-day-picker/src/contexts/SelectSingle/SelectSingleContext.test.ts
generated
vendored
Normal file
84
frontend/node_modules/react-day-picker/src/contexts/SelectSingle/SelectSingleContext.test.ts
generated
vendored
Normal file
@ -0,0 +1,84 @@
|
||||
import { MouseEvent } from 'react';
|
||||
|
||||
import { DayPickerProps } from 'DayPicker';
|
||||
|
||||
import { renderDayPickerHook } from 'test/render';
|
||||
import { freezeBeforeAll } from 'test/utils';
|
||||
|
||||
import { DayPickerSingleProps } from 'types/DayPickerSingle';
|
||||
import { ActiveModifiers } from 'types/Modifiers';
|
||||
|
||||
import {
|
||||
SelectSingleContextValue,
|
||||
useSelectSingle
|
||||
} from './SelectSingleContext';
|
||||
|
||||
const today = new Date(2021, 11, 8);
|
||||
freezeBeforeAll(today);
|
||||
|
||||
function renderHook(props?: Partial<DayPickerProps>) {
|
||||
return renderDayPickerHook<SelectSingleContextValue>(useSelectSingle, props);
|
||||
}
|
||||
describe('when is not a single select DayPicker', () => {
|
||||
test('the selected day should be undefined', () => {
|
||||
const result = renderHook();
|
||||
expect(result.current.selected).toBeUndefined();
|
||||
});
|
||||
});
|
||||
|
||||
describe('when a day is selected from DayPicker props', () => {
|
||||
test('the selected day should be today', () => {
|
||||
const dayPickerProps: DayPickerSingleProps = {
|
||||
mode: 'single',
|
||||
selected: today
|
||||
};
|
||||
const result = renderHook(dayPickerProps);
|
||||
expect(result.current.selected).toBe(today);
|
||||
});
|
||||
});
|
||||
describe('when onDayClick is called', () => {
|
||||
const dayPickerProps: DayPickerSingleProps = {
|
||||
mode: 'single',
|
||||
onSelect: jest.fn(),
|
||||
onDayClick: jest.fn()
|
||||
};
|
||||
const result = renderHook(dayPickerProps);
|
||||
const activeModifiers = {};
|
||||
const event = {} as MouseEvent;
|
||||
test('should call the `onSelect` event handler', () => {
|
||||
result.current.onDayClick?.(today, activeModifiers, event);
|
||||
expect(dayPickerProps.onSelect).toHaveBeenCalledWith(
|
||||
today,
|
||||
today,
|
||||
activeModifiers,
|
||||
event
|
||||
);
|
||||
});
|
||||
test('should call the `onDayClick` event handler', () => {
|
||||
result.current.onDayClick?.(today, activeModifiers, event);
|
||||
expect(dayPickerProps.onDayClick).toHaveBeenCalledWith(
|
||||
today,
|
||||
activeModifiers,
|
||||
event
|
||||
);
|
||||
});
|
||||
});
|
||||
describe('if a selected day is not required', () => {
|
||||
const dayPickerProps: DayPickerSingleProps = {
|
||||
mode: 'single',
|
||||
onSelect: jest.fn(),
|
||||
required: false
|
||||
};
|
||||
test('should call the `onSelect` event handler with an undefined day', () => {
|
||||
const result = renderHook(dayPickerProps);
|
||||
const activeModifiers: ActiveModifiers = { selected: true };
|
||||
const event = {} as MouseEvent;
|
||||
result.current.onDayClick?.(today, activeModifiers, event);
|
||||
expect(dayPickerProps.onSelect).toHaveBeenCalledWith(
|
||||
undefined,
|
||||
today,
|
||||
activeModifiers,
|
||||
event
|
||||
);
|
||||
});
|
||||
});
|
||||
96
frontend/node_modules/react-day-picker/src/contexts/SelectSingle/SelectSingleContext.tsx
generated
vendored
Normal file
96
frontend/node_modules/react-day-picker/src/contexts/SelectSingle/SelectSingleContext.tsx
generated
vendored
Normal file
@ -0,0 +1,96 @@
|
||||
import { createContext, ReactNode, useContext } from 'react';
|
||||
|
||||
import { DayPickerBase } from 'types/DayPickerBase';
|
||||
import { DayPickerSingleProps, isDayPickerSingle } from 'types/DayPickerSingle';
|
||||
import { DayClickEventHandler } from 'types/EventHandlers';
|
||||
|
||||
/** Represents the value of a {@link SelectSingleContext}. */
|
||||
export interface SelectSingleContextValue {
|
||||
/** The day that has been selected. */
|
||||
selected: Date | undefined;
|
||||
/** Event handler to attach to the day button to enable the single select. */
|
||||
onDayClick?: DayClickEventHandler;
|
||||
}
|
||||
|
||||
/**
|
||||
* The SelectSingle context shares details about the selected days when in
|
||||
* single selection mode.
|
||||
*
|
||||
* Access this context from the {@link useSelectSingle} hook.
|
||||
*/
|
||||
export const SelectSingleContext = createContext<
|
||||
SelectSingleContextValue | undefined
|
||||
>(undefined);
|
||||
|
||||
export interface SelectSingleProviderProps {
|
||||
initialProps: DayPickerBase;
|
||||
children?: ReactNode;
|
||||
}
|
||||
|
||||
/** Provides the values for the {@link SelectSingleProvider}. */
|
||||
export function SelectSingleProvider(
|
||||
props: SelectSingleProviderProps
|
||||
): JSX.Element {
|
||||
if (!isDayPickerSingle(props.initialProps)) {
|
||||
const emptyContextValue: SelectSingleContextValue = {
|
||||
selected: undefined
|
||||
};
|
||||
return (
|
||||
<SelectSingleContext.Provider value={emptyContextValue}>
|
||||
{props.children}
|
||||
</SelectSingleContext.Provider>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<SelectSingleProviderInternal
|
||||
initialProps={props.initialProps}
|
||||
children={props.children}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
/** @private */
|
||||
export interface SelectSingleProviderInternal {
|
||||
initialProps: DayPickerSingleProps;
|
||||
children?: ReactNode;
|
||||
}
|
||||
|
||||
export function SelectSingleProviderInternal({
|
||||
initialProps,
|
||||
children
|
||||
}: SelectSingleProviderInternal): JSX.Element {
|
||||
const onDayClick: DayClickEventHandler = (day, activeModifiers, e) => {
|
||||
initialProps.onDayClick?.(day, activeModifiers, e);
|
||||
|
||||
if (activeModifiers.selected && !initialProps.required) {
|
||||
initialProps.onSelect?.(undefined, day, activeModifiers, e);
|
||||
return;
|
||||
}
|
||||
initialProps.onSelect?.(day, day, activeModifiers, e);
|
||||
};
|
||||
|
||||
const contextValue: SelectSingleContextValue = {
|
||||
selected: initialProps.selected,
|
||||
onDayClick
|
||||
};
|
||||
return (
|
||||
<SelectSingleContext.Provider value={contextValue}>
|
||||
{children}
|
||||
</SelectSingleContext.Provider>
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Hook to access the {@link SelectSingleContextValue}.
|
||||
*
|
||||
* This hook is meant to be used inside internal or custom components.
|
||||
*/
|
||||
export function useSelectSingle(): SelectSingleContextValue {
|
||||
const context = useContext(SelectSingleContext);
|
||||
if (!context) {
|
||||
throw new Error(
|
||||
'useSelectSingle must be used within a SelectSingleProvider'
|
||||
);
|
||||
}
|
||||
return context;
|
||||
}
|
||||
1
frontend/node_modules/react-day-picker/src/contexts/SelectSingle/index.ts
generated
vendored
Normal file
1
frontend/node_modules/react-day-picker/src/contexts/SelectSingle/index.ts
generated
vendored
Normal file
@ -0,0 +1 @@
|
||||
export * from './SelectSingleContext';
|
||||
Reference in New Issue
Block a user