UNPKG

@rehookify/datepicker

Version:

The ultimate tool to create a date, range and time picker in your React applications.

729 lines (697 loc) 28.9 kB
import React, { useMemo, useCallback, useReducer, createContext, useContext } from 'react'; // Year and Month is a minimum required arguments for creating a date // == null is intentional to check also for undefined const newDate = (Y, M, ...rest) => !Y || M == null ? new Date() : new Date(Y, M, ...rest); const getDateParts = (d) => ({ D: d.getDate(), M: d.getMonth(), Y: d.getFullYear(), }); // Days in order sun = 0 ... sat = 6 const getDay = (d) => d.getDay(); /* * We need this function to eliminate time from the comparison. * All date that comes to DP should go through this function. */ const getCleanDate = (d) => newDate(getDateParts(d).Y, getDateParts(d).M, getDateParts(d).D); const daysInMonth = (d) => newDate(getDateParts(d).Y, getDateParts(d).M + 1, 0).getDate(); const addToDate = (d, value, part) => { const { Y, M, D } = getDateParts(d); // Cover case when offsetDate is 31 and next month doesn't have 31 days // More details here https://github.com/rehookify/datepicker/issues/10 const nextDate = part === 'date' ? D + value : part === 'month' && D > daysInMonth(newDate(Y, M + value, 1)) ? daysInMonth(newDate(Y, M + value, 1)) : D; return newDate(Y + (part === 'year' ? value : 0), M + (part === 'month' ? value : 0), nextDate); }; const subtractFromDate = (d, value, part) => addToDate(d, 0 - value, part); const sortDatesAsc = (a, b) => +a - +b; const toLocaleDateString = (d, locale, options) => d.toLocaleDateString(locale, options); const formatMonthName = (d, { locale, monthName }) => toLocaleDateString(d, locale, { month: monthName }); const formatDate = (d, { locale, options }) => toLocaleDateString(d, locale, options); const getTimeDate = (Y, M, D, t) => t && t.h != null && t.m != null ? newDate(Y, M, D, t.h, t.m) : undefined; const formatLocaleTime = (d, { locale, hour, minute, second, hour12 }) => d.toLocaleTimeString(locale, { hour, minute, second, hour12, }); const addLeadingZero = (n) => `${n < 10 ? 0 : ''}${n}`; const convertTo12H = (h, m) => { const median = h >= 12 ? 'pm' : 'am'; return `${addLeadingZero(h % 12 || 12)}:${addLeadingZero(m)} ${median}`; }; const formatTime = (d, { hour12 }) => { const h = d.getHours(); const m = d.getMinutes(); return hour12 ? convertTo12H(h, m) : `${addLeadingZero(h)}:${addLeadingZero(m)}`; }; const addAndSortAsc = (dates, d) => dates.concat(d).sort(sortDatesAsc); const sortMinMax = (min, max, sortFunction) => { let [mN, mX] = [min, max]; if (min && max) { [mN, mX] = [min, max].sort(sortFunction); } return [mN, mX]; }; const isExcludedDay = (d, eDays) => eDays ? eDays.includes(d) : false; const isExcludedDate = (d, dates = []) => { const { M, D } = getDateParts(d); return dates.some((date) => { const { M: md, D: dd } = getDateParts(date); return M === md && D === dd; }); }; const isExcluded = (d, { day, date } = {}) => isExcludedDay(d.getDay(), day) || isExcludedDate(d, date); var NUMBER_OF_STATIC_CALENDAR_DAYS = 42; function getStartOffset(d, startDay) { return (getDay(d) + 7 - startDay) % 7; } function getCalendarMonthParams(month, year, { mode, startDay }) { const firstMonthDay = newDate(year, month, 1); const lastDay = daysInMonth(firstMonthDay); const startOffset = getStartOffset(firstMonthDay, startDay); const length = mode === 'static' ? NUMBER_OF_STATIC_CALENDAR_DAYS : startOffset + lastDay + 6 - getStartOffset(newDate(year, month, lastDay), startDay); return { start: startOffset, length, }; } // Converting Date to Number is equal of calling Date.getTime const isSame = (d1, d2) => +d1 === +d2; const isBefore = (d1, d2) => d1 < d2; const isAfter = (d1, d2) => d1 > d2; const isBetween = (start, d, end) => (isAfter(d, start) && isBefore(d, end)) || (isBefore(d, start) && isAfter(d, end)); const maxDateAndAfter = (maxDate, date) => !!maxDate && isAfter(date, maxDate); const minDateAndBefore = (minDate, date) => !!minDate && isBefore(date, minDate); const includeDate = (dates, d) => dates.some((date) => isSame(getCleanDate(date), getCleanDate(d))); const isBeforeMinMonth = (month, minDate) => !!minDate && month < getDateParts(minDate).M; const isBeforeMinYear = (year, minDate) => !!minDate && year < getDateParts(minDate).Y; const isAfterMaxMonth = (month, maxDate) => !!maxDate && month > getDateParts(maxDate).M; const isAfterMaxYear = (year, maxDate) => !!maxDate && year > getDateParts(maxDate).Y; const isSameOrAfterMaxYear = (year, maxDate) => !!maxDate && year >= getDateParts(maxDate).Y; const isSameOrBeforeMinYear = (year, minDate) => !!minDate && year <= getDateParts(minDate).Y; var DEFAULT_CALENDAR_CONFIG = { mode: 'static', offsets: [0], startDay: 0, }; var DEFAULT_YEARS_CONFIG = { mode: 'decade', /* * The default value for the numberOfYears is 12 * it consists of 10 years + 1 year before + 1 year after */ numberOfYears: 12, step: 10, }; var DEFAULT_DATES_CONFIG = { mode: 'single', toggle: false, selectSameDate: false, }; var DEFAULT_TIME_CONFIG = { interval: 30, useLocales: false, }; var DEFAULT_LOCALE_CONFIG = { locale: 'en-GB', day: '2-digit', year: 'numeric', weekday: 'short', monthName: 'long', hour: '2-digit', minute: '2-digit', hour12: undefined, second: undefined, }; function createConfig({ selectedDates = [], onDatesChange, focusDate, offsetDate, onOffsetChange, calendar = {}, dates = {}, locale, time = {}, exclude = {}, years, }) { const { minDate, maxDate, ...restDates } = dates; const { offsets = [], ...restCalendarParams } = calendar; const { minTime, maxTime, ...restTime } = time; const [minD, maxD] = sortMinMax(minDate, maxDate, sortDatesAsc); const [minT, maxT] = sortMinMax(minTime, maxTime, (a, b) => a.h - b.h); const focus = focusDate && includeDate(selectedDates, focusDate) ? focusDate : undefined; return { selectedDates, onDatesChange, offsetDate, onOffsetChange, focusDate: focus, calendar: { ...DEFAULT_CALENDAR_CONFIG, ...restCalendarParams, offsets: DEFAULT_CALENDAR_CONFIG.offsets.concat(offsets), }, years: { ...DEFAULT_YEARS_CONFIG, ...years }, dates: { ...DEFAULT_DATES_CONFIG, ...restDates, minDate: minD && getCleanDate(minD), maxDate: maxD && getCleanDate(maxD), }, locale: { ...DEFAULT_LOCALE_CONFIG, ...locale, }, time: { ...DEFAULT_TIME_CONFIG, minTime: minT, maxTime: maxT, ...restTime, }, exclude, }; } function isRange(mode) { return mode === 'range'; } const RANGE_START = 'range-start'; const RANGE_END = 'range-end'; const WILL_BE_IN_RANGE_START = 'will-be-range-start'; const WILL_BE_IN_RANGE_END = 'will-be-range-end'; const getDateRangeState = (date, rangeEnd, selectedDates, mode) => { if (!isRange(mode) || selectedDates.length === 0) return ''; const [start, end] = selectedDates; // We have completed range if (start && end) { if (isSame(date, getCleanDate(start))) { return isSame(getCleanDate(start), getCleanDate(end)) ? `${RANGE_START} ${RANGE_END}` : RANGE_START; } if (isSame(date, getCleanDate(end))) return RANGE_END; return isBetween(getCleanDate(start), date, getCleanDate(end)) ? 'in-range' : ''; } // We have 1 date and rangeEnd date if (!end && rangeEnd) { if (isBetween(getCleanDate(start), date, rangeEnd)) return 'will-be-in-range'; // rangeEnd is before start if (isBefore(rangeEnd, getCleanDate(start))) { if (isSame(date, rangeEnd)) return WILL_BE_IN_RANGE_START; return isSame(date, getCleanDate(start)) ? WILL_BE_IN_RANGE_END : ''; } // rangeEnd is after start; if (isSame(date, getCleanDate(start))) return WILL_BE_IN_RANGE_START; return isSame(date, rangeEnd) ? WILL_BE_IN_RANGE_END : ''; } return ''; }; const createCalendar = (offsetDate, calendarStartDate, selectedDates, { rangeEnd }, config) => { const { dates: { mode, minDate, maxDate }, locale, calendar, exclude, } = config; const { locale: localeStr, day, year } = locale; const { M, Y } = getDateParts(calendarStartDate); const { start, length } = getCalendarMonthParams(M, Y, calendar); const days = Array(length) .fill(0) .map((_, i) => { const $date = newDate(Y, M, i + 1 - start); return { $date, active: isSame(offsetDate, $date), day: toLocaleDateString($date, localeStr, { day }), now: isSame(getCleanDate(newDate()), $date), range: getDateRangeState($date, rangeEnd, selectedDates, mode), disabled: minDateAndBefore(minDate, $date) || maxDateAndAfter(maxDate, $date) || isExcluded($date, exclude), selected: includeDate(selectedDates, $date), inCurrentMonth: getDateParts($date).M === M, }; }); return { year: toLocaleDateString(calendarStartDate, localeStr, { year }), month: formatMonthName(calendarStartDate, locale), days, }; }; const createCalendars = ({ selectedDates, state, config, offsetDate, }) => { return config.calendar.offsets.map((offset) => createCalendar(offsetDate, addToDate(offsetDate, offset, 'month'), selectedDates, state, config)); }; var createWeekdays = ({ days }, { locale: { locale, weekday } }) => [0, 1, 2, 3, 4, 5, 6].map((day) => toLocaleDateString(days[day].$date, locale, { weekday })); const useCalendars = (state) => { const calendars = createCalendars(state); return useMemo(() => ({ calendars, weekDays: createWeekdays(calendars[0], state.config), }), [calendars, state.config]); }; const callAll = (...fns) => (...args) => fns.forEach((fn) => fn === null || fn === void 0 ? void 0 : fn(...args)); const skipFirst = (fn) => (_arg1, arg2) => fn(arg2); const skipAll = (fn) => (..._) => { fn(); }; const createPropGetter = (isDisabled, action, props = {}, selected = false) => ({ role: 'button', tabIndex: 0, ...(isDisabled ? { disabled: true, 'aria-disabled': true, } : { onClick(evt) { action(evt); }, }), ...(selected ? { 'aria-selected': true } : {}), ...props, }); var SET_FOCUS_DATE_ACTION = 'SET_FOCUS_DATE'; var SET_OFFSET_DATE_ACTION = 'SET_OFFSET_DATE'; var SET_RANGE_END_ACTION = 'SET_RANGE_END'; var SET_YEAR_ACTION = 'SET_YEAR'; var stateReducer = (state, action) => { switch (action.type) { case SET_FOCUS_DATE_ACTION: return { ...state, focusDate: action.date, }; case SET_OFFSET_DATE_ACTION: return { ...state, offsetDate: action.date, }; case SET_RANGE_END_ACTION: return { ...state, rangeEnd: action.date, }; case SET_YEAR_ACTION: return { ...state, offsetYear: action.year, }; default: return state; } }; var setFocus = (dispatch, date) => { dispatch({ type: SET_FOCUS_DATE_ACTION, date }); }; var setOffset = (dispatch, date) => { dispatch({ type: SET_OFFSET_DATE_ACTION, date }); }; var setRangeEnd = (dispatch, date) => { dispatch({ type: SET_RANGE_END_ACTION, date }); }; var setYear = (dispatch, year) => { dispatch({ type: SET_YEAR_ACTION, year }); }; const setDPOffset = ({ dispatch, config: { onOffsetChange, offsetDate } }) => (d) => { // Prevent to call reducer action if offsetDate is external if (!onOffsetChange && !offsetDate) setOffset(dispatch, d); if (onOffsetChange) onOffsetChange(d); }; const getNextOffsetDate = (d, { days, months, years }) => { let nextDate = d; if (days && days !== 0) { nextDate = addToDate(nextDate, days, 'date'); } if (months && months !== 0) { nextDate = addToDate(nextDate, months, 'month'); } if (years && years !== 0) { nextDate = addToDate(nextDate, years, 'year'); } return nextDate; }; const getEdgedOffsetDate = (offsetDate, { days = 0, months = 0, years = 0 }, dateEdge) => { if (!dateEdge) return offsetDate; if (isSame(offsetDate, dateEdge)) return offsetDate; if (days !== 0) { return calculateNewDateWithOffset(offsetDate, dateEdge, days, 'date'); } if (months !== 0) { return calculateNewDateWithOffset(offsetDate, dateEdge, months, 'month'); } if (years !== 0) { return calculateNewDateWithOffset(offsetDate, dateEdge, years, 'year'); } return offsetDate; }; const calculateNewDateWithOffset = (offsetDate, dateEdge, offsetValue, unit) => { const newDate = addToDate(offsetDate, offsetValue, unit); const isPositiveOffsetValue = offsetValue > 0; if (isPositiveOffsetValue) { const isMaxDateAfterNewDate = maxDateAndAfter(dateEdge, newDate); return isMaxDateAfterNewDate ? subtractFromDate(dateEdge, offsetValue, unit) : offsetDate; } const isMinDateBeforeNewDate = minDateAndBefore(dateEdge, newDate); return isMinDateBeforeNewDate ? subtractFromDate(dateEdge, offsetValue, unit) : offsetDate; }; const useDatePickerOffsetPropGetters = (state) => { const { config: { dates }, } = state; const { minDate, maxDate } = dates; const addOffset = useCallback((offsetValue, { disabled, onClick, ...rest } = {}) => { const offsetDate = getEdgedOffsetDate(state.offsetDate, offsetValue, maxDate); const nextDate = getNextOffsetDate(offsetDate, offsetValue); const isDisabled = !!disabled || maxDateAndAfter(maxDate, nextDate); return createPropGetter(isDisabled, (evt) => callAll(onClick, skipFirst(setDPOffset(state)))(evt, nextDate), rest); }, [maxDate, state]); const subtractOffset = useCallback(({ days = 0, months = 0, years = 0 }, { disabled, onClick, ...rest } = {}) => { const negativeOffsetValue = { days: -days, months: -months, years: -years, }; const offsetDate = getEdgedOffsetDate(state.offsetDate, negativeOffsetValue, minDate); const nextDate = getNextOffsetDate(offsetDate, negativeOffsetValue); const isDisabled = !!disabled || minDateAndBefore(minDate, nextDate); return createPropGetter(isDisabled, (evt) => callAll(onClick, skipFirst(setDPOffset(state)))(evt, nextDate), rest); }, [minDate, state]); const setOffset = useCallback((d, { disabled, onClick, ...rest } = {}) => { const isDisabled = !!disabled || minDateAndBefore(minDate, d) || maxDateAndAfter(maxDate, d); return createPropGetter(isDisabled, (evt) => callAll(onClick, skipFirst(setDPOffset(state)))(evt, d), rest); }, [state, maxDate, minDate]); return { addOffset, setOffset, subtractOffset, }; }; const getCalendarStartDate = (minDate, maxDate, NOW) => { if (maxDateAndAfter(maxDate, NOW)) return maxDate; if (minDateAndBefore(minDate, NOW)) return minDate; return NOW; }; /* * Default behavior years collection * It get start of the decade -1 * It really comfortable to navigate through years * because you have links to the previous and next decade * 2019 2020 2021 * 2022 2023 2024 * 2025 2026 2027 * 2028 2029 2030 */ const getStartDecadePosition = (year) => year - (year % 10) - 1; /* * If number of the year is default = 12 and current year is 2022 * It will show this matrix * 2017 2018 2019 * 2020 2021 2022 👌 * 2023 2024 2025 * 2026 2027 2028 * I think it is nicer to look at the future more ;) */ const getFluidYearPosition = (year, numberOfYears) => year - (numberOfYears / 2 - (numberOfYears % 2 === 0 ? 1 : 0)); /* * It will place offsetYear at the end of the collection * 2015 2016 2017 * 2012 2013 2014 * 2018 2019 2020 * 2021 2022 2023 */ const getStartExactPosition = (year, numberOfYears) => year - numberOfYears + 1; const isExactMode = (mode) => mode === 'exact'; const getCurrentYearPosition = (year, { mode, numberOfYears }) => { if (isExactMode(mode)) return getStartExactPosition(year, numberOfYears); return mode === 'decade' ? getStartDecadePosition(year) : getFluidYearPosition(year, numberOfYears); }; const createInitialState = (config) => { const { selectedDates, offsetDate, focusDate, dates: { minDate, maxDate }, years, } = config; const oDate = offsetDate ? offsetDate : selectedDates.length > 0 ? selectedDates[selectedDates.length - 1] : getCalendarStartDate(minDate, maxDate, getCleanDate(newDate())); return { focusDate, rangeEnd: null, offsetDate: oDate, offsetYear: getCurrentYearPosition(getDateParts(oDate).Y, years), }; }; const useDatePickerState = (config) => { const dpConfig = createConfig(config); const [state, dispatch] = useReducer(stateReducer, createInitialState(dpConfig)); return { dispatch, selectedDates: dpConfig.selectedDates, offsetDate: dpConfig.offsetDate || state.offsetDate, state, config: dpConfig, }; }; const getMultipleDates = (selectedDates, date, { mode, toggle, limit }) => { // If toggle is active and we have already selected this date // Then filter it out in all modes if (toggle && includeDate(selectedDates, date)) return selectedDates.filter((d) => !isSame(getCleanDate(d), date)); if (mode === 'multiple') return !limit || selectedDates.length < limit ? addAndSortAsc(selectedDates, date) : selectedDates; if (isRange(mode)) return selectedDates.length === 2 ? [date] : addAndSortAsc(selectedDates, date); // mode === 'single' return [date]; }; const useDays = ({ selectedDates, config: { locale } }) => useMemo(() => ({ selectedDates, formattedDates: selectedDates.map((d) => formatDate(d, locale)), }), [selectedDates, locale]); const useDaysPropGetters = ({ config, selectedDates, dispatch, }) => { const { onDatesChange, dates: { mode, toggle, selectSameDate }, } = config; const dayButton = useCallback(({ $date, selected, disabled, active }, { onClick, disabled: disabledProps, ...rest } = {}) => createPropGetter(disabled || !!disabledProps, (evt) => { if (selected && !toggle) { selectedDates.forEach((d) => { if (isSame(getCleanDate(d), $date)) setFocus(dispatch, d); }); // Handle case when user could select same date in range mode if (!isRange(mode) || !selectSameDate) return; } if (isRange(mode) && selectedDates.length === 1) { setRangeEnd(dispatch, null); } callAll(onClick, skipFirst((d) => { const nextSelectedDates = getMultipleDates(selectedDates, d, config.dates); setFocus(dispatch, includeDate(nextSelectedDates, d) ? d : undefined); onDatesChange(nextSelectedDates); }))(evt, $date); }, { ...rest, ...(isRange(mode) && selectedDates.length === 1 && { onMouseEnter() { setRangeEnd(dispatch, $date); }, }), tabIndex: active ? 0 : -1, }, selected), [ mode, toggle, config.dates, onDatesChange, selectedDates, dispatch, selectSameDate, ]); return { dayButton }; }; var createMonths = (offsetDate, selectedDates, locale, { minDate, maxDate }) => { const { M, Y, D } = getDateParts(offsetDate); const { Y: nY, M: nM } = getDateParts(newDate()); // 12 is a number of months in the year return Array(12) .fill(0) .map((_, i) => { // Prevent situation when previous month has less days than current March -> February const maxMonthDate = daysInMonth(newDate(Y, i, 1)); const $date = newDate(Y, i, D > maxMonthDate ? maxMonthDate : D); return { $date, month: formatMonthName($date, locale), selected: selectedDates.some((d) => { const { M: dM, Y: dY } = getDateParts(d); return dY === Y && dM === i; }), active: M === i, now: i === nM && Y === nY, disabled: (isBeforeMinMonth(i, minDate) && isSameOrBeforeMinYear(Y, minDate)) || (isAfterMaxMonth(i, maxDate) && isSameOrAfterMaxYear(Y, maxDate)), }; }); }; const useMonths = ({ selectedDates, offsetDate, config: { locale, dates }, }) => useMemo(() => ({ months: createMonths(offsetDate, selectedDates, locale, dates), }), [dates, locale, offsetDate, selectedDates]); const useMonthsPropGetters = (dpState) => { const monthButton = useCallback(({ $date, disabled, selected, active }, { onClick, disabled: disabledProps, ...rest } = {}) => createPropGetter(!!disabledProps || disabled, (evt) => callAll(onClick, skipFirst(setDPOffset(dpState)))(evt, $date), { ...rest, tabIndex: active ? 0 : -1, }, selected), [dpState]); return { monthButton }; }; var createTime = (d, { time, locale }) => { const NOW = newDate(); const { interval, minTime, maxTime, useLocales } = time; const { Y, M, D } = getDateParts(d || NOW); // 1440 is a number of minutes in the day 60 * 24 const segments = 1440 / interval; const minDate = getTimeDate(Y, M, D, minTime); const maxDate = getTimeDate(Y, M, D, maxTime); return Array(segments) .fill(0) .map((_, i) => { const $date = newDate(Y, M, D, 0, i * interval); const disabled = !d || minDateAndBefore(minDate, $date) || maxDateAndAfter(maxDate, $date); return { $date, disabled, now: isSame($date, NOW), selected: d ? isSame(d, $date) : false, time: useLocales ? formatLocaleTime($date, locale) : formatTime($date, locale), }; }); }; const useTime = ({ state: { focusDate }, config }) => useMemo(() => ({ time: createTime(focusDate, config), }), [focusDate, config]); const useTimePropGetter = ({ selectedDates, state: { focusDate }, config: { onDatesChange }, dispatch, }) => { const timeButton = useCallback(({ $date, selected, disabled, now }, { onClick, disabled: disabledProps, ...rest } = {}) => createPropGetter(disabled || !!disabledProps, (evt) => { if (selected) return; callAll(onClick, skipFirst((d) => { const newSelected = selectedDates.map((selected) => { return isSame(focusDate, selected) ? d : selected; }); setFocus(dispatch, d); onDatesChange(newSelected); }))(evt, $date); }, { ...rest, tabIndex: selected || now ? 0 : -1, }, selected), [selectedDates, onDatesChange, dispatch, focusDate]); return { timeButton }; }; const createYears = (currentYear, offsetDate, selectedDates, { numberOfYears }, { minDate, maxDate }) => { const { Y, M, D } = getDateParts(offsetDate); const { Y: nY } = getDateParts(newDate()); return Array(numberOfYears) .fill(0) .map((_, i) => { const year = currentYear + i; const $date = newDate(year, M, D); return { $date, active: Y === year, disabled: isBeforeMinYear(year, minDate) || isAfterMaxYear(year, maxDate), now: year === nY, selected: selectedDates.some((d) => getDateParts(d).Y === year), year, }; }); }; const useYears = ({ selectedDates, offsetDate, state: { offsetYear }, config: { years, dates }, }) => useMemo(() => ({ years: createYears(offsetYear, offsetDate, selectedDates, years, dates), }), [offsetDate, offsetYear, selectedDates, years, dates]); const useYearsPropGetters = (dpState) => { const { offsetDate, state: { offsetYear }, config: { dates, years: yearsConfig }, dispatch, } = dpState; const { minDate, maxDate } = dates; const { step, numberOfYears, mode } = yearsConfig; const { D, M } = getDateParts(offsetDate); const yearButton = useCallback(({ $date, disabled, selected, active }, { onClick, disabled: disabledProps, ...rest } = {}) => createPropGetter(!!disabledProps || disabled, (evt) => callAll(onClick, skipFirst(setDPOffset(dpState)))(evt, $date), { ...rest, tabIndex: active ? 0 : -1, }, selected), [dpState]); const nextYearsButton = useCallback(({ onClick, disabled, ...rest } = {}) => { const endYearDate = newDate(offsetYear + numberOfYears - 1, M, D); const isDisabled = !!disabled || maxDateAndAfter(maxDate, endYearDate) || (isExactMode(mode) && !!maxDate && isSame(maxDate, endYearDate)); return createPropGetter(isDisabled, (evt) => callAll(onClick, skipAll(() => setYear(dispatch, offsetYear + step)))(evt), rest); }, [maxDate, dispatch, offsetYear, step, D, M, numberOfYears, mode]); const previousYearsButton = useCallback(({ onClick, disabled, ...rest } = {}) => { const isDisabled = !!disabled || minDateAndBefore(minDate, newDate(offsetYear, M, D)); return createPropGetter(isDisabled, (evt) => callAll(onClick, skipAll(() => setYear(dispatch, offsetYear - step)))(evt), rest); }, [minDate, dispatch, offsetYear, step, M, D]); return { yearButton, nextYearsButton, previousYearsButton, }; }; const useDatePicker = (config) => { const dpState = useDatePickerState(config); return { data: { ...useCalendars(dpState), ...useDays(dpState), ...useMonths(dpState), ...useTime(dpState), ...useYears(dpState), }, propGetters: { ...useDaysPropGetters(dpState), ...useMonthsPropGetters(dpState), ...useTimePropGetter(dpState), ...useYearsPropGetters(dpState), ...useDatePickerOffsetPropGetters(dpState), }, }; }; var DatePickerContext = createContext({}); var useDatePickerContext = () => useContext(DatePickerContext); var DatePickerProvider = ({ children, config, }) => { return (React.createElement(DatePickerContext.Provider, { value: useDatePicker(config) }, children)); }; var DatePickerStateContext = createContext({}); var useDatePickerStateContext = () => useContext(DatePickerStateContext); var DatePickerStateProvider = ({ children, config, }) => { return (React.createElement(DatePickerStateContext.Provider, { value: useDatePickerState(config) }, children)); }; const useContextCalendars = () => useCalendars(useDatePickerStateContext()); const useContextDays = () => useDays(useDatePickerStateContext()); const useContextDaysPropGetters = () => useDaysPropGetters(useDatePickerStateContext()); const useContextMonths = () => useMonths(useDatePickerStateContext()); const useContextMonthsPropGetters = () => useMonthsPropGetters(useDatePickerStateContext()); const useContextTime = () => useTime(useDatePickerStateContext()); const useContextTimePropGetters = () => useTimePropGetter(useDatePickerStateContext()); const useContextYears = () => useYears(useDatePickerStateContext()); const useContextYearsPropGetters = () => useYearsPropGetters(useDatePickerStateContext()); const useContextDatePickerOffsetPropGetters = () => useDatePickerOffsetPropGetters(useDatePickerStateContext()); export { DatePickerProvider, DatePickerStateProvider, useCalendars, useContextCalendars, useContextDatePickerOffsetPropGetters, useContextDays, useContextDaysPropGetters, useContextMonths, useContextMonthsPropGetters, useContextTime, useContextTimePropGetters, useContextYears, useContextYearsPropGetters, useDatePicker, useDatePickerContext, useDatePickerOffsetPropGetters, useDatePickerState, useDatePickerStateContext, useDays, useDaysPropGetters, useMonths, useMonthsPropGetters, useTime, useTimePropGetter, useYears, useYearsPropGetters }; //# sourceMappingURL=index.esm.mjs.map