Skip to content

Commit

Permalink
fix: disable outside days outside the before and end month range (#2578)
Browse files Browse the repository at this point in the history
  • Loading branch information
rodgobbi authored Nov 17, 2024
1 parent 1f0506b commit b1c746f
Show file tree
Hide file tree
Showing 4 changed files with 178 additions and 54 deletions.
20 changes: 20 additions & 0 deletions examples/StartEndMonthsShowOutsideDays.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import React, { useState } from "react";

import { DayPicker } from "react-day-picker";

export function StartEndMonthsShowOutsideDays() {
const [selected, setSelected] = useState<Date>();

return (
<DayPicker
mode="single"
selected={selected}
onSelect={setSelected}
showOutsideDays={true}
defaultMonth={new Date(2024, 2)}
startMonth={new Date(2024, 2, 30)}
endMonth={new Date(2024, 2, 1)}
disabled={new Date(2024, 2, 10)}
/>
);
}
1 change: 1 addition & 0 deletions examples/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ export * from "./Spanish";
export * from "./SpanishWeekStartsOn";
export * from "./Start";
export * from "./StartEndMonths";
export * from "./StartEndMonthsShowOutsideDays";
export * from "./StylingCss";
export * from "./StylingInline";
export * from "./StylingModifiers";
Expand Down
179 changes: 127 additions & 52 deletions src/useGetModifiers.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,76 +4,151 @@ import { useGetModifiers } from "./useGetModifiers";

const dateLib = defaultDateLib;

const month1 = new Date(2022, 10, 1);
const month2 = new Date(2022, 11, 1);
const displayedMonth = new Date(2022, 10, 1);

const date1 = new Date(2022, 10, 10);
const date2 = new Date(2022, 10, 11);
const date3 = new Date(2022, 10, 12);
const date4 = new Date(2022, 10, 13);
const date5 = new Date(2022, 10, 14);
const date6 = new Date(2022, 10, 30);
const date1 = new Date(2022, 9, 30);
const date2 = new Date(2022, 10, 10);
const date3 = new Date(2022, 10, 11);
const date4 = new Date(2022, 10, 12);
const date5 = new Date(2022, 10, 13);
const date6 = new Date(2022, 10, 14);
const date7 = new Date(2022, 11, 1);

const day1 = new CalendarDay(date1, month1);
const day2 = new CalendarDay(date2, month1);
const day3 = new CalendarDay(date3, month1);
const day4 = new CalendarDay(date4, month1);
const day5 = new CalendarDay(date5, month1);
const day6 = new CalendarDay(date6, month2);
const day1 = new CalendarDay(date1, displayedMonth);
const day2 = new CalendarDay(date2, displayedMonth);
const day3 = new CalendarDay(date3, displayedMonth);
const day4 = new CalendarDay(date4, displayedMonth);
const day5 = new CalendarDay(date5, displayedMonth);
const day6 = new CalendarDay(date6, displayedMonth);
const day7 = new CalendarDay(date7, displayedMonth);

const days: CalendarDay[] = [day1, day2, day3, day4, day5, day6];
const days: CalendarDay[] = [day1, day2, day3, day4, day5, day6, day7];

const props = {
disabled: [date1],
hidden: [date2],
disabled: [date2],
hidden: [date3],
modifiers: {
custom: [date3],
selected: [date5]
custom: [date4],
selected: [date6]
},
selected: date6,
selected: date7,
showOutsideDays: true,
today: date4,
today: date5,
timeZone: "UTC"
};

describe("useGetModifiers", () => {
// eslint-disable-next-line react-hooks/rules-of-hooks
const getModifiers = useGetModifiers(days, props, dateLib);

test("return the modifiers for a given day", () => {
const modifiers = getModifiers(day1);

expect(modifiers[DayFlag.focused]).toBe(false);
expect(modifiers[DayFlag.disabled]).toBe(true);
expect(modifiers[DayFlag.hidden]).toBe(false);
expect(modifiers[DayFlag.outside]).toBe(false);
expect(modifiers[DayFlag.today]).toBe(false);
expect(modifiers.custom).toBe(false);
});
describe("default props", () => {
// eslint-disable-next-line react-hooks/rules-of-hooks
const getModifiers = useGetModifiers(days, props, dateLib);

test("return the custom modifiers for a given day", () => {
const modifiers = getModifiers(day3);
expect(modifiers.custom).toBe(true);
});
test("return the modifiers for a given day", () => {
const modifiers = getModifiers(day2);

test("return the custom `selected` modifier for a given day", () => {
const modifiers = getModifiers(day5);
expect(modifiers.selected).toBe(true);
});
expect(modifiers[DayFlag.focused]).toBe(false);
expect(modifiers[DayFlag.disabled]).toBe(true);
expect(modifiers[DayFlag.hidden]).toBe(false);
expect(modifiers[DayFlag.outside]).toBe(false);
expect(modifiers[DayFlag.today]).toBe(false);
expect(modifiers.custom).toBe(false);
});

test("return the today modifier for a given day", () => {
const modifiers = getModifiers(day4);
expect(modifiers[DayFlag.today]).toBe(true);
});
test("return the custom modifiers for a given day", () => {
const modifiers = getModifiers(day4);
expect(modifiers.custom).toBe(true);
});

test("return the custom `selected` modifier for a given day", () => {
const modifiers = getModifiers(day6);
expect(modifiers.selected).toBe(true);
});

test("return the today modifier for a given day", () => {
const modifiers = getModifiers(day5);

expect(modifiers[DayFlag.today]).toBe(true);
expect(modifiers[DayFlag.focused]).toBe(false);
expect(modifiers[DayFlag.disabled]).toBe(false);
expect(modifiers[DayFlag.outside]).toBe(false);
expect(modifiers[DayFlag.hidden]).toBe(false);
});

test("return the hidden modifier for a given day", () => {
const modifiers = getModifiers(day3);

expect(modifiers[DayFlag.hidden]).toBe(true);
expect(modifiers[DayFlag.focused]).toBe(false);
expect(modifiers[DayFlag.disabled]).toBe(false);
expect(modifiers[DayFlag.outside]).toBe(false);
expect(modifiers[DayFlag.today]).toBe(false);
});

test("return the hidden modifier for a given day", () => {
const modifiers = getModifiers(day2);
expect(modifiers[DayFlag.hidden]).toBe(true);
test("return the modifiers for a given day before the displayed month", () => {
const modifiers = getModifiers(day1);

expect(modifiers[DayFlag.focused]).toBe(false);
expect(modifiers[DayFlag.disabled]).toBe(false);
expect(modifiers[DayFlag.hidden]).toBe(false);
expect(modifiers[DayFlag.outside]).toBe(true);
expect(modifiers[DayFlag.today]).toBe(false);
expect(modifiers.selected).toBe(false);
});

test("return the modifiers for a given day after the displayed month", () => {
const modifiers = getModifiers(day7);

expect(modifiers[DayFlag.focused]).toBe(false);
expect(modifiers[DayFlag.disabled]).toBe(false);
expect(modifiers[DayFlag.hidden]).toBe(false);
expect(modifiers[DayFlag.outside]).toBe(true);
expect(modifiers[DayFlag.today]).toBe(false);
expect(modifiers.selected).toBe(false);
});
});

test("return the outside modifier for a given day", () => {
const modifiers = getModifiers(day6);
describe("with startMonth and endMonth props", () => {
const startMonth = new Date(displayedMonth);
startMonth.setDate(30);
const endMonth = new Date(displayedMonth);
endMonth.setDate(1);

// eslint-disable-next-line react-hooks/rules-of-hooks
const getModifiers = useGetModifiers(
days,
{ ...props, startMonth, endMonth },
dateLib
);
test("return the modifiers for a given day", () => {
const modifiers = getModifiers(day2);

expect(modifiers[DayFlag.focused]).toBe(false);
expect(modifiers[DayFlag.disabled]).toBe(true);
expect(modifiers[DayFlag.hidden]).toBe(false);
expect(modifiers[DayFlag.outside]).toBe(false);
expect(modifiers[DayFlag.today]).toBe(false);
expect(modifiers.custom).toBe(false);
});

test("return the modifiers for a given day before the displayed month", () => {
const modifiers = getModifiers(day1);

expect(modifiers[DayFlag.focused]).toBe(false);
expect(modifiers[DayFlag.disabled]).toBe(false);
expect(modifiers[DayFlag.hidden]).toBe(true);
expect(modifiers[DayFlag.outside]).toBe(true);
expect(modifiers[DayFlag.today]).toBe(false);
expect(modifiers.selected).toBe(false);
});

test("return the modifiers for a given day after the displayed month", () => {
const modifiers = getModifiers(day7);

expect(modifiers[DayFlag.outside]).toBe(true);
expect(modifiers[DayFlag.focused]).toBe(false);
expect(modifiers[DayFlag.disabled]).toBe(false);
expect(modifiers[DayFlag.hidden]).toBe(true);
expect(modifiers[DayFlag.outside]).toBe(true);
expect(modifiers[DayFlag.today]).toBe(false);
expect(modifiers.selected).toBe(false);
});
});
});
32 changes: 30 additions & 2 deletions src/useGetModifiers.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,27 @@ export function useGetModifiers(
props: DayPickerProps,
dateLib: DateLib
) {
const { disabled, hidden, modifiers, showOutsideDays, today } = props;
const {
disabled,
hidden,
modifiers,
showOutsideDays,
today,
startMonth,
endMonth
} = props;

const { isSameDay, isSameMonth } = dateLib;
const {
isSameDay,
isSameMonth,
startOfMonth,
isBefore,
endOfMonth,
isAfter
} = dateLib;

const computedStartMonth = startMonth && startOfMonth(startMonth);
const computedEndMonth = endMonth && endOfMonth(endMonth);

const internalModifiersMap: Record<DayFlag, CalendarDay[]> = {
[DayFlag.focused]: [],
Expand All @@ -36,12 +54,22 @@ export function useGetModifiers(

const isOutside = Boolean(displayMonth && !isSameMonth(date, displayMonth));

const isBeforeStartMonth = Boolean(
computedStartMonth && isBefore(date, computedStartMonth)
);

const isAfterEndMonth = Boolean(
computedEndMonth && isAfter(date, computedEndMonth)
);

const isDisabled = Boolean(
disabled && dateMatchModifiers(date, disabled, dateLib)
);

const isHidden =
Boolean(hidden && dateMatchModifiers(date, hidden, dateLib)) ||
isBeforeStartMonth ||
isAfterEndMonth ||
(!showOutsideDays && isOutside);

const isToday = isSameDay(
Expand Down

0 comments on commit b1c746f

Please sign in to comment.