react-day-picker
Version:
Customizable Date Picker for React
133 lines (115 loc) • 3.94 kB
text/typescript
import { DayFlag } from "../UI.js";
import type { CalendarDay, DateLib } from "../classes/index.js";
import type { DayPickerProps, Modifiers } from "../types/index.js";
import { dateMatchModifiers } from "../utils/dateMatchModifiers.js";
/**
* Creates a function to retrieve the modifiers for a given day.
*
* This function calculates both internal and custom modifiers for each day
* based on the provided calendar days and DayPicker props.
*
* @private
* @param days The array of `CalendarDay` objects to process.
* @param props The DayPicker props, including modifiers and configuration
* options.
* @param dateLib The date library to use for date manipulation.
* @returns A function that retrieves the modifiers for a given `CalendarDay`.
*/
export function createGetModifiers(
days: CalendarDay[],
props: DayPickerProps,
navStart: Date | undefined,
navEnd: Date | undefined,
dateLib: DateLib
) {
const {
disabled,
hidden,
modifiers,
showOutsideDays,
broadcastCalendar,
today
} = props;
const {
isSameDay,
isSameMonth,
startOfMonth,
isBefore,
endOfMonth,
isAfter
} = dateLib;
const computedNavStart = navStart && startOfMonth(navStart);
const computedNavEnd = navEnd && endOfMonth(navEnd);
const internalModifiersMap: Record<DayFlag, CalendarDay[]> = {
[DayFlag.focused]: [],
[DayFlag.outside]: [],
[DayFlag.disabled]: [],
[DayFlag.hidden]: [],
[DayFlag.today]: []
};
const customModifiersMap: Record<string, CalendarDay[]> = {};
for (const day of days) {
const { date, displayMonth } = day;
const isOutside = Boolean(displayMonth && !isSameMonth(date, displayMonth));
const isBeforeNavStart = Boolean(
computedNavStart && isBefore(date, computedNavStart)
);
const isAfterNavEnd = Boolean(
computedNavEnd && isAfter(date, computedNavEnd)
);
const isDisabled = Boolean(
disabled && dateMatchModifiers(date, disabled, dateLib)
);
const isHidden =
Boolean(hidden && dateMatchModifiers(date, hidden, dateLib)) ||
isBeforeNavStart ||
isAfterNavEnd ||
// Broadcast calendar will show outside days as default
(!broadcastCalendar && !showOutsideDays && isOutside) ||
(broadcastCalendar && showOutsideDays === false && isOutside);
const isToday = isSameDay(date, today ?? dateLib.today());
if (isOutside) internalModifiersMap.outside.push(day);
if (isDisabled) internalModifiersMap.disabled.push(day);
if (isHidden) internalModifiersMap.hidden.push(day);
if (isToday) internalModifiersMap.today.push(day);
// Add custom modifiers
if (modifiers) {
Object.keys(modifiers).forEach((name) => {
const modifierValue = modifiers?.[name];
const isMatch = modifierValue
? dateMatchModifiers(date, modifierValue, dateLib)
: false;
if (!isMatch) return;
if (customModifiersMap[name]) {
customModifiersMap[name].push(day);
} else {
customModifiersMap[name] = [day];
}
});
}
}
return (day: CalendarDay): Modifiers => {
// Initialize all the modifiers to false
const dayFlags: Record<DayFlag, boolean> = {
[DayFlag.focused]: false,
[DayFlag.disabled]: false,
[DayFlag.hidden]: false,
[DayFlag.outside]: false,
[DayFlag.today]: false
};
const customModifiers: Modifiers = {};
// Find the modifiers for the given day
for (const name in internalModifiersMap) {
const days = internalModifiersMap[name as DayFlag];
dayFlags[name as DayFlag] = days.some((d) => d === day);
}
for (const name in customModifiersMap) {
customModifiers[name] = customModifiersMap[name].some((d) => d === day);
}
return {
...dayFlags,
// custom modifiers should override all the previous ones
...customModifiers
};
};
}