From b1c746fec2319ee6c5e0d2207e4e4db627ab82e3 Mon Sep 17 00:00:00 2001 From: rodgobbi Date: Mon, 18 Nov 2024 00:28:21 +0100 Subject: [PATCH] fix: disable outside days outside the before and end month range (#2578) --- examples/StartEndMonthsShowOutsideDays.tsx | 20 +++ examples/index.ts | 1 + src/useGetModifiers.test.tsx | 179 +++++++++++++++------ src/useGetModifiers.tsx | 32 +++- 4 files changed, 178 insertions(+), 54 deletions(-) create mode 100644 examples/StartEndMonthsShowOutsideDays.tsx diff --git a/examples/StartEndMonthsShowOutsideDays.tsx b/examples/StartEndMonthsShowOutsideDays.tsx new file mode 100644 index 000000000..0b216ade2 --- /dev/null +++ b/examples/StartEndMonthsShowOutsideDays.tsx @@ -0,0 +1,20 @@ +import React, { useState } from "react"; + +import { DayPicker } from "react-day-picker"; + +export function StartEndMonthsShowOutsideDays() { + const [selected, setSelected] = useState(); + + return ( + + ); +} diff --git a/examples/index.ts b/examples/index.ts index 64e5c6179..6efa1b9fb 100644 --- a/examples/index.ts +++ b/examples/index.ts @@ -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"; diff --git a/src/useGetModifiers.test.tsx b/src/useGetModifiers.test.tsx index 92b7efe1a..357f65e7b 100644 --- a/src/useGetModifiers.test.tsx +++ b/src/useGetModifiers.test.tsx @@ -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); + }); }); }); diff --git a/src/useGetModifiers.tsx b/src/useGetModifiers.tsx index 3d67a705f..747a46ccf 100644 --- a/src/useGetModifiers.tsx +++ b/src/useGetModifiers.tsx @@ -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.focused]: [], @@ -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(