import type { DateLib } from "../classes/DateLib.js"; import { CalendarDay } from "../classes/index.js"; import type { DayPickerProps, MoveFocusBy, MoveFocusDir } from "../types/index.js"; import { dateMatchModifiers } from "../utils/dateMatchModifiers.js"; import { getFocusableDate } from "./getFocusableDate.js"; /** * Determines the next focusable day in the calendar. * * This function recursively calculates the next focusable day based on the * movement direction and modifiers applied to the days. * * @param moveBy The unit of movement (e.g., "day", "week"). * @param moveDir The direction of movement ("before" or "after"). * @param refDay The currently focused day. * @param calendarStartMonth The earliest month the user can navigate to. * @param calendarEndMonth The latest month the user can navigate to. * @param props The DayPicker props, including modifiers and configuration * options. * @param dateLib The date library to use for date manipulation. * @param attempt The current recursion attempt (used to limit recursion depth). * @returns The next focusable day, or `undefined` if no focusable day is found. */ export function getNextFocus( moveBy: MoveFocusBy, moveDir: MoveFocusDir, refDay: CalendarDay, calendarStartMonth: Date | undefined, calendarEndMonth: Date | undefined, props: Pick< DayPickerProps, "disabled" | "hidden" | "modifiers" | "ISOWeek" | "timeZone" >, dateLib: DateLib, attempt: number = 0 ): CalendarDay | undefined { if (attempt > 365) { // Limit the recursion to 365 attempts return undefined; } const focusableDate = getFocusableDate( moveBy, moveDir, refDay.date, calendarStartMonth, calendarEndMonth, props, dateLib ); const isDisabled = Boolean( props.disabled && dateMatchModifiers(focusableDate, props.disabled, dateLib) ); const isHidden = Boolean( props.hidden && dateMatchModifiers(focusableDate, props.hidden, dateLib) ); const targetMonth = focusableDate; const focusDay = new CalendarDay(focusableDate, targetMonth, dateLib); if (!isDisabled && !isHidden) { return focusDay; } // Recursively attempt to find the next focusable date return getNextFocus( moveBy, moveDir, focusDay, calendarStartMonth, calendarEndMonth, props, dateLib, attempt + 1 ); }