UNPKG

react-day-picker

Version:

Customizable Date Picker for React

111 lines (110 loc) 4.4 kB
import { useEffect, useMemo } from "react"; import { getDates } from "./helpers/getDates.js"; import { getDays } from "./helpers/getDays.js"; import { getDisplayMonths } from "./helpers/getDisplayMonths.js"; import { getInitialMonth } from "./helpers/getInitialMonth.js"; import { getMonths } from "./helpers/getMonths.js"; import { getNavMonths } from "./helpers/getNavMonth.js"; import { getNextMonth } from "./helpers/getNextMonth.js"; import { getPreviousMonth } from "./helpers/getPreviousMonth.js"; import { getWeeks } from "./helpers/getWeeks.js"; import { useControlledValue } from "./helpers/useControlledValue.js"; /** * Provides the calendar object to work with the calendar in custom components. * * @private * @param props - The DayPicker props related to calendar configuration. * @param dateLib - The date utility library instance. * @returns The calendar object containing displayed days, weeks, months, and * navigation methods. */ export function useCalendar(props, dateLib) { const [navStart, navEnd] = getNavMonths(props, dateLib); const { startOfMonth, endOfMonth } = dateLib; const initialMonth = getInitialMonth(props, navStart, navEnd, dateLib); const [firstMonth, setFirstMonth] = useControlledValue(initialMonth, // initialMonth is always computed from props.month if provided props.month ? initialMonth : undefined); // biome-ignore lint/correctness/useExhaustiveDependencies: change the initial month when the time zone changes. useEffect(() => { const newInitialMonth = getInitialMonth(props, navStart, navEnd, dateLib); setFirstMonth(newInitialMonth); }, [props.timeZone]); /** The months displayed in the calendar. */ // biome-ignore lint/correctness/useExhaustiveDependencies: We want to recompute only when specific props change. const { months, weeks, days, previousMonth, nextMonth } = useMemo(() => { const displayMonths = getDisplayMonths(firstMonth, navEnd, { numberOfMonths: props.numberOfMonths }, dateLib); const dates = getDates(displayMonths, props.endMonth ? endOfMonth(props.endMonth) : undefined, { ISOWeek: props.ISOWeek, fixedWeeks: props.fixedWeeks, broadcastCalendar: props.broadcastCalendar, }, dateLib); const months = getMonths(displayMonths, dates, { broadcastCalendar: props.broadcastCalendar, fixedWeeks: props.fixedWeeks, ISOWeek: props.ISOWeek, reverseMonths: props.reverseMonths, }, dateLib); const weeks = getWeeks(months); const days = getDays(months); const previousMonth = getPreviousMonth(firstMonth, navStart, props, dateLib); const nextMonth = getNextMonth(firstMonth, navEnd, props, dateLib); return { months, weeks, days, previousMonth, nextMonth, }; }, [ dateLib, firstMonth.getTime(), navEnd?.getTime(), navStart?.getTime(), props.disableNavigation, props.broadcastCalendar, props.endMonth?.getTime(), props.fixedWeeks, props.ISOWeek, props.numberOfMonths, props.pagedNavigation, props.reverseMonths, ]); const { disableNavigation, onMonthChange } = props; const isDayInCalendar = (day) => weeks.some((week) => week.days.some((d) => d.isEqualTo(day))); const goToMonth = (date) => { if (disableNavigation) { return; } let newMonth = startOfMonth(date); // if month is before start, use the first month instead if (navStart && newMonth < startOfMonth(navStart)) { newMonth = startOfMonth(navStart); } // if month is after endMonth, use the last month instead if (navEnd && newMonth > startOfMonth(navEnd)) { newMonth = startOfMonth(navEnd); } setFirstMonth(newMonth); onMonthChange?.(newMonth); }; const goToDay = (day) => { // is this check necessary? if (isDayInCalendar(day)) { return; } goToMonth(day.date); }; const calendar = { months, weeks, days, navStart, navEnd, previousMonth, nextMonth, goToMonth, goToDay, }; return calendar; }