diff --git a/examples/RangeLong.tsx b/examples/RangeLong.tsx index 9c3d4173d..e15ae46a8 100644 --- a/examples/RangeLong.tsx +++ b/examples/RangeLong.tsx @@ -4,7 +4,7 @@ import { type DateRange, DayPicker } from "react-day-picker"; export function RangeLong() { const [range, setRange] = useState({ - from: new Date("0001-01-01"), + from: new Date(100, 0, 1), to: new Date(2024, 9, 10) }); @@ -15,8 +15,6 @@ export function RangeLong() { defaultMonth={new Date(2024, 9)} selected={range} onSelect={setRange} - excludeDisabled - disabled={new Date("2000-01-01")} /> ); } diff --git a/examples/RangeLongExcludeDisabled.tsx b/examples/RangeLongExcludeDisabled.tsx new file mode 100644 index 000000000..d20d1bff6 --- /dev/null +++ b/examples/RangeLongExcludeDisabled.tsx @@ -0,0 +1,22 @@ +import React, { useState } from "react"; + +import { type DateRange, DayPicker } from "react-day-picker"; + +export function RangeLongExcludeDisabled() { + const [range, setRange] = useState({ + from: new Date(100, 0, 1), + to: new Date(2024, 9, 10) + }); + + return ( + + ); +} diff --git a/examples/index.ts b/examples/index.ts index 702b5d010..aeefef039 100644 --- a/examples/index.ts +++ b/examples/index.ts @@ -47,10 +47,12 @@ export * from "./OutsideDays"; export * from "./PastDatesDisabled"; export * from "./Range"; export * from "./RangeExcludeDisabled"; +export * from "./RangeLong"; export * from "./RangeMinMax"; export * from "./RangeRequired"; export * from "./RangeShiftKey"; export * from "./RangeLong"; +export * from "./RangeLongExcludeDisabled"; export * from "./Rtl"; export * from "./Single"; export * from "./SingleControlled"; diff --git a/performance-tests/flows/range-long.mjs b/performance-tests/flows/range-long.mjs index 02725a7e6..8e3888924 100644 --- a/performance-tests/flows/range-long.mjs +++ b/performance-tests/flows/range-long.mjs @@ -3,9 +3,12 @@ * @param {import("puppeteer").Page} page */ export async function rangeLong(flow, page) { - await flow.navigate("http://localhost:4173/?example=RangeLong", { - name: "Range selection with long range" - }); + await flow.navigate( + "http://localhost:4173/?example=RangeLongExcludeDisabled", + { + name: "Range selection with long range" + } + ); await flow.startTimespan({ name: "Day selection" }); diff --git a/src/selection/useRange.tsx b/src/selection/useRange.tsx index 97acd68bb..15b983248 100644 --- a/src/selection/useRange.tsx +++ b/src/selection/useRange.tsx @@ -8,7 +8,7 @@ import type { PropsRange, Selection } from "../types/index.js"; -import { addToRange, dateMatchModifiers } from "../utils/index.js"; +import { addToRange, rangeContainsModifiers } from "../utils/index.js"; import { rangeIncludesDate } from "../utils/rangeIncludesDate.js"; export function useRange( @@ -43,23 +43,17 @@ export function useRange( ? addToRange(triggerDate, selected, min, max, required, dateLib) : undefined; - if (newRange?.from && newRange.to) { - let newDate = newRange.from; - const totalDays = dateLib.differenceInCalendarDays(newRange.to, newDate); - - for (let i = 0; i < totalDays; i++) { - newDate = dateLib.addDays(newDate, 1); - - if ( - excludeDisabled && - disabled && - dateMatchModifiers(newDate, disabled, dateLib) - ) { - // if a disabled days is found, the range is reset - newRange.from = triggerDate; - newRange.to = undefined; - break; - } + if (excludeDisabled && disabled && newRange?.from && newRange.to) { + if ( + rangeContainsModifiers( + { from: newRange.from, to: newRange.to }, + disabled, + dateLib + ) + ) { + // if a disabled days is found, the range is reset + newRange.from = triggerDate; + newRange.to = undefined; } } diff --git a/src/utils/areRangesOverlapping.test.ts b/src/utils/areRangesOverlapping.test.ts new file mode 100644 index 000000000..74b0d57a8 --- /dev/null +++ b/src/utils/areRangesOverlapping.test.ts @@ -0,0 +1,60 @@ +import { defaultDateLib } from "../classes/DateLib"; + +import { areRangesOverlapping } from "./areRangesOverlapping"; + +const sunday = new Date(2024, 8, 1); +const monday = new Date(2024, 8, 2); +const tuesday = new Date(2024, 8, 3); +const thursday = new Date(2024, 8, 5); +const saturday = new Date(2024, 8, 7); +const nextWeekSunday = new Date(2024, 8, 8); + +const leftRange = { from: monday, to: saturday }; + +test('should return true when matching the "from" date', () => { + const rightRange = { from: sunday, to: monday }; + const result = areRangesOverlapping(leftRange, rightRange, defaultDateLib); + expect(result).toBe(true); +}); + +test('should return true when matching the "to" date', () => { + const rightRange = { from: saturday, to: nextWeekSunday }; + const result = areRangesOverlapping(leftRange, rightRange, defaultDateLib); + expect(result).toBe(true); +}); + +test("should return true when left date range contains right date range", () => { + const rightRange = { from: tuesday, to: thursday }; + const result = areRangesOverlapping(leftRange, rightRange, defaultDateLib); + expect(result).toBe(true); +}); + +test("should return true when right date range contains left date range", () => { + const rightRange = { from: sunday, to: nextWeekSunday }; + const result = areRangesOverlapping(leftRange, rightRange, defaultDateLib); + expect(result).toBe(true); +}); + +test("should return true when a date range is inverted", () => { + const rightRange = { to: sunday, from: nextWeekSunday }; + const result = areRangesOverlapping(leftRange, rightRange, defaultDateLib); + expect(result).toBe(true); +}); + +test('should return false on the edge of the "from" date', () => { + const rightRange = { from: new Date(2000, 1, 1), to: sunday }; + const result = areRangesOverlapping(leftRange, rightRange, defaultDateLib); + expect(result).toBe(false); +}); + +test('should return false on the edge of the "to" date', () => { + const rightRange = { from: nextWeekSunday, to: new Date(2077, 1, 1) }; + const result = areRangesOverlapping(leftRange, rightRange, defaultDateLib); + expect(result).toBe(false); +}); + +test("should return false when a date range is inverted", () => { + const rightRange = { to: nextWeekSunday, from: new Date(2077, 1, 1) }; + const result = areRangesOverlapping(leftRange, rightRange, defaultDateLib); + expect(result).toBe(false); +}); diff --git a/src/utils/areRangesOverlapping.ts b/src/utils/areRangesOverlapping.ts new file mode 100644 index 000000000..963bc9e1a --- /dev/null +++ b/src/utils/areRangesOverlapping.ts @@ -0,0 +1,21 @@ +import { defaultDateLib } from "../classes/index.js"; + +import { rangeIncludesDate } from "./rangeIncludesDate.js"; + +/** + * Determines whether a given range overlaps with another range. + * + * @group Utilities + */ +export function areRangesOverlapping( + rangeLeft: { from: Date; to: Date }, + rangeRight: { from: Date; to: Date }, + dateLib = defaultDateLib +): boolean { + return ( + rangeIncludesDate(rangeLeft, rangeRight.from, false, dateLib) || + rangeIncludesDate(rangeLeft, rangeRight.to, false, dateLib) || + rangeIncludesDate(rangeRight, rangeLeft.from, false, dateLib) || + rangeIncludesDate(rangeRight, rangeLeft.to, false, dateLib) + ); +} diff --git a/src/utils/dateMatchModifiers.ts b/src/utils/dateMatchModifiers.ts index a64dd8c3f..b8f3b3ab7 100644 --- a/src/utils/dateMatchModifiers.ts +++ b/src/utils/dateMatchModifiers.ts @@ -18,14 +18,14 @@ import { * ```tsx * const date = new Date(2022, 5, 19); * const matcher1: DateRange = { - * from: new Date(2021, 12, 21), - * to: new Date(2021, 12, 30) - * } + * from: new Date(2021, 12, 21), + * to: new Date(2021, 12, 30) + * }; * const matcher2: DateRange = { - * from: new Date(2022, 5, 1), - * to: new Date(2022, 5, 23) - * } - * const dateMatchModifiers(date, [matcher1, matcher2]); // true, since day is in the matcher1 range. + * from: new Date(2022, 5, 1), + * to: new Date(2022, 5, 23) + * }; + * dateMatchModifiers(date, [matcher1, matcher2]); // true, since day is in the matcher1 range. * ``` * * @group Utilities diff --git a/src/utils/index.ts b/src/utils/index.ts index 0c563cbe0..a825a825d 100644 --- a/src/utils/index.ts +++ b/src/utils/index.ts @@ -1,4 +1,7 @@ export * from "./addToRange.js"; +export * from "./areRangesOverlapping.js"; export * from "./dateMatchModifiers.js"; +export * from "./rangeContainsDayOfWeek.js"; export * from "./rangeIncludesDate.js"; +export * from "./rangeContainsModifiers.js"; export * from "./typeguards.js"; diff --git a/src/utils/rangeContainsDayOfWeek.test.ts b/src/utils/rangeContainsDayOfWeek.test.ts new file mode 100644 index 000000000..4a987cbec --- /dev/null +++ b/src/utils/rangeContainsDayOfWeek.test.ts @@ -0,0 +1,49 @@ +import { defaultDateLib } from "../classes/DateLib"; +import { DayOfWeek } from "../types"; + +import { rangeContainsDayOfWeek } from "./rangeContainsDayOfWeek"; + +const sunday = new Date(2024, 8, 1); // day of the week 0 +const monday = new Date(2024, 8, 2); // day of the week 1 +const friday = new Date(2024, 8, 6); // day of the week 5 +const saturday = new Date(2024, 8, 7); // day of the week 6 +const nextWeekSunday = new Date(2024, 8, 8); // day of the week 0 + +describe("should return false", () => { + const testCases: Array<[{ from: Date; to: Date }, DayOfWeek]> = [ + [{ from: monday, to: saturday }, { dayOfWeek: 0 }], + [{ from: monday, to: friday }, { dayOfWeek: [0, 6] }], + [{ from: sunday, to: friday }, { dayOfWeek: 6 }] + ]; + + for (const [range, dayOfWeek] of testCases) { + it(`range from ${range.from} to ${range.to} should not contain ${JSON.stringify(dayOfWeek)}`, () => { + expect(rangeContainsDayOfWeek(range, dayOfWeek, defaultDateLib)).toBe( + false + ); + }); + } +}); + +describe("should return true", () => { + const testCases: Array<[{ from: Date; to: Date }, DayOfWeek]> = [ + [{ from: sunday, to: saturday }, { dayOfWeek: 0 }], + [{ from: monday, to: friday }, { dayOfWeek: 1 }], + [{ from: monday, to: friday }, { dayOfWeek: 2 }], + [{ from: monday, to: friday }, { dayOfWeek: 3 }], + [{ from: monday, to: friday }, { dayOfWeek: 4 }], + [{ from: monday, to: friday }, { dayOfWeek: 5 }], + [{ from: monday, to: saturday }, { dayOfWeek: 6 }], + [{ from: monday, to: saturday }, { dayOfWeek: [0, 6] }], + [{ from: monday, to: nextWeekSunday }, { dayOfWeek: 0 }], + [{ from: monday, to: nextWeekSunday }, { dayOfWeek: 6 }] + ]; + + for (const [range, dayOfWeek] of testCases) { + it(`range from ${range.from} to ${range.to} should contain ${JSON.stringify(dayOfWeek)}`, () => { + expect(rangeContainsDayOfWeek(range, dayOfWeek, defaultDateLib)).toBe( + true + ); + }); + } +}); diff --git a/src/utils/rangeContainsDayOfWeek.ts b/src/utils/rangeContainsDayOfWeek.ts new file mode 100644 index 000000000..02f9576af --- /dev/null +++ b/src/utils/rangeContainsDayOfWeek.ts @@ -0,0 +1,37 @@ +import { defaultDateLib, type DateLib } from "../classes/DateLib.js"; +import type { DayOfWeek } from "../types/index.js"; + +/** + * Returns whether a date range matches against a given {@link DayOfWeek}. + * + * ```tsx + * const range: DateRange = { + * from: new Date(2024, 8, 1), // day of the week 0 + * to: new Date(2024, 8, 6) // day of the week 5 + * }; + * rangeContainsDayOfWeek(date, { dayOfWeek: 0 }); // true + * ``` + * + * @group Utilities + */ +export function rangeContainsDayOfWeek( + range: { from: Date; to: Date }, + matcher: DayOfWeek, + dateLib: DateLib = defaultDateLib +) { + const dayOfWeekArr = !Array.isArray(matcher.dayOfWeek) + ? [matcher.dayOfWeek] + : matcher.dayOfWeek; + let date = range.from; + const totalDays = dateLib.differenceInCalendarDays(range.to, range.from); + + // iterate at maximum one week or the total days if the range is shorter than one week + const totalDaysLimit = Math.min(totalDays, 6); + for (let i = 0; i <= totalDaysLimit; i++) { + if (dayOfWeekArr.includes(date.getDay())) { + return true; + } + date = dateLib.addDays(date, 1); + } + return false; +} diff --git a/src/utils/rangeContainsModifiers.test.ts b/src/utils/rangeContainsModifiers.test.ts new file mode 100644 index 000000000..65742a308 --- /dev/null +++ b/src/utils/rangeContainsModifiers.test.ts @@ -0,0 +1,230 @@ +import { defaultDateLib } from "../classes/DateLib"; +import { DayOfWeek } from "../types"; + +import { rangeContainsModifiers } from "./rangeContainsModifiers"; + +const sunday = new Date(2024, 8, 1); // day of the week 0 +const monday = new Date(2024, 8, 2); // day of the week 1 +const tuesday = new Date(2024, 8, 3); // day of the week 1 +const wednesday = new Date(2024, 8, 4); // day of the week 1 +const thursday = new Date(2024, 8, 5); // day of the week 1 +const friday = new Date(2024, 8, 6); // day of the week 5 +const saturday = new Date(2024, 8, 7); // day of the week 6 +const nextWeekSunday = new Date(2024, 8, 8); // day of the week 0 + +const testRange = { from: monday, to: saturday }; + +describe("when the matcher is a boolean", () => { + const matcher = true; + const result = rangeContainsModifiers(testRange, [matcher], defaultDateLib); + test("should return the boolean", () => { + expect(result).toBe(matcher); + }); +}); + +describe("when matching a single date", () => { + test("should return true when matching a date in the range", () => { + const matcher = thursday; + const result = rangeContainsModifiers(testRange, [matcher], defaultDateLib); + expect(result).toBe(true); + }); + test('should return true when matching the "from" date', () => { + const matcher = monday; + const result = rangeContainsModifiers(testRange, [matcher], defaultDateLib); + expect(result).toBe(true); + }); + test('should return true when matching the "to" date', () => { + const matcher = saturday; + const result = rangeContainsModifiers(testRange, [matcher], defaultDateLib); + expect(result).toBe(true); + }); + test('should return false on the edge of the "from" date', () => { + const matcher = sunday; + const result = rangeContainsModifiers(testRange, [matcher], defaultDateLib); + expect(result).toBe(false); + }); + test('should return false on the edge of the "to" date', () => { + const matcher = nextWeekSunday; + const result = rangeContainsModifiers(testRange, [matcher], defaultDateLib); + expect(result).toBe(false); + }); +}); + +describe("when matching an array of dates", () => { + test("should return true", () => { + const matcher = [sunday, wednesday, nextWeekSunday]; + const result = rangeContainsModifiers(testRange, [matcher], defaultDateLib); + expect(result).toBe(true); + }); + test("should return false", () => { + const matcher = [sunday, nextWeekSunday]; + const result = rangeContainsModifiers(testRange, [matcher], defaultDateLib); + expect(result).toBe(false); + }); +}); + +describe("when matching date range", () => { + test('should return true when matching the "from" date', () => { + const matcher = { from: sunday, to: monday }; + const result = rangeContainsModifiers(testRange, [matcher], defaultDateLib); + expect(result).toBe(true); + }); + test('should return true when matching the "to" date', () => { + const matcher = { from: saturday, to: nextWeekSunday }; + const result = rangeContainsModifiers(testRange, [matcher], defaultDateLib); + expect(result).toBe(true); + }); + + test("should return true when date range contains matcher", () => { + const matcher = { from: tuesday, to: thursday }; + const result = rangeContainsModifiers(testRange, [matcher], defaultDateLib); + expect(result).toBe(true); + }); + test("should return true when matcher contains date range", () => { + const matcher = { from: sunday, to: nextWeekSunday }; + const result = rangeContainsModifiers(testRange, [matcher], defaultDateLib); + expect(result).toBe(true); + }); + + test('should return false on the edge of the "from" date', () => { + const matcher = { from: new Date(2000, 1, 1), to: sunday }; + const result = rangeContainsModifiers(testRange, [matcher], defaultDateLib); + expect(result).toBe(false); + }); + test('should return false on the edge of the "to" date', () => { + const matcher = { from: nextWeekSunday, to: new Date(2077, 1, 1) }; + const result = rangeContainsModifiers(testRange, [matcher], defaultDateLib); + expect(result).toBe(false); + }); + test("should return false if matcher is an incomplete date range", () => { + const matcher = { from: monday }; + const result = rangeContainsModifiers(testRange, [matcher], defaultDateLib); + expect(result).toBe(false); + }); +}); + +describe("when matching the day of week", () => { + test("should return true", () => { + const matcher: DayOfWeek = { + dayOfWeek: [monday.getDay()] + }; + const result = rangeContainsModifiers(testRange, [matcher], defaultDateLib); + expect(result).toBe(true); + }); + test("should return false", () => { + const matcher: DayOfWeek = { + dayOfWeek: [sunday.getDay()] + }; + const result = rangeContainsModifiers(testRange, [matcher], defaultDateLib); + expect(result).toBe(false); + }); +}); + +describe("when matching date interval (closed)", () => { + test('should return true when matching the "from" date', () => { + const matcher = { after: sunday, before: tuesday }; + const result = rangeContainsModifiers(testRange, [matcher], defaultDateLib); + expect(result).toBe(true); + }); + test('should return true when matching the "to" date', () => { + const matcher = { after: friday, before: nextWeekSunday }; + const result = rangeContainsModifiers(testRange, [matcher], defaultDateLib); + expect(result).toBe(true); + }); + + test("should return true when date range contains matcher", () => { + const matcher = { after: tuesday, before: thursday }; + const result = rangeContainsModifiers(testRange, [matcher], defaultDateLib); + expect(result).toBe(true); + }); + test("should return true when matcher contains date range", () => { + const matcher = { after: sunday, before: nextWeekSunday }; + const result = rangeContainsModifiers(testRange, [matcher], defaultDateLib); + expect(result).toBe(true); + }); + + test('should return false on the edge of the "from" date', () => { + const matcher = { after: new Date(2000, 1, 1), before: monday }; + const result = rangeContainsModifiers(testRange, [matcher], defaultDateLib); + expect(result).toBe(false); + }); + test('should return false on the edge of the "to" date', () => { + const matcher = { after: saturday, before: new Date(2077, 1, 1) }; + const result = rangeContainsModifiers(testRange, [matcher], defaultDateLib); + expect(result).toBe(false); + }); +}); + +describe("when matching date interval (open)", () => { + test('should return true when matching the "from" date', () => { + const matcher = { before: tuesday, after: saturday }; + const result = rangeContainsModifiers(testRange, [matcher], defaultDateLib); + expect(result).toBe(true); + }); + test('should return true when matching the "to" date', () => { + const matcher = { before: monday, after: friday }; + const result = rangeContainsModifiers(testRange, [matcher], defaultDateLib); + expect(result).toBe(true); + }); + test("should return false when date range is not part of the matcher", () => { + const matcher = { before: monday, after: saturday }; + const result = rangeContainsModifiers(testRange, [matcher], defaultDateLib); + expect(result).toBe(false); + }); +}); + +describe("when matching the date after", () => { + test('should return true when matching the "from" date', () => { + const matcher = { after: sunday }; + const result = rangeContainsModifiers(testRange, [matcher], defaultDateLib); + expect(result).toBe(true); + }); + test('should return true when matching the "to" date', () => { + const matcher = { after: friday }; + const result = rangeContainsModifiers(testRange, [matcher], defaultDateLib); + expect(result).toBe(true); + }); + + test("should return false", () => { + const matcher = { after: saturday }; + const result = rangeContainsModifiers(testRange, [matcher], defaultDateLib); + expect(result).toBe(false); + }); +}); + +describe("when matching the date before", () => { + test('should return true when matching the "from" date', () => { + const matcher = { before: tuesday }; + const result = rangeContainsModifiers(testRange, [matcher], defaultDateLib); + expect(result).toBe(true); + }); + test('should return true when matching the "to" date', () => { + const matcher = { before: nextWeekSunday }; + const result = rangeContainsModifiers(testRange, [matcher], defaultDateLib); + expect(result).toBe(true); + }); + + test("should return false", () => { + const matcher = { before: monday }; + const result = rangeContainsModifiers(testRange, [matcher], defaultDateLib); + expect(result).toBe(false); + }); +}); + +describe("when the matcher is a function", () => { + test('should return true when matching the "from" date', () => { + const matcher = (date: Date) => date.getTime() === monday.getTime(); + const result = rangeContainsModifiers(testRange, [matcher], defaultDateLib); + expect(result).toBe(true); + }); + test('should return true when matching the "to" date', () => { + const matcher = (date: Date) => date.getTime() === saturday.getTime(); + const result = rangeContainsModifiers(testRange, [matcher], defaultDateLib); + expect(result).toBe(true); + }); + test("should return false", () => { + const matcher = (date: Date) => date.getTime() === nextWeekSunday.getTime(); + const result = rangeContainsModifiers(testRange, [matcher], defaultDateLib); + expect(result).toBe(false); + }); +}); diff --git a/src/utils/rangeContainsModifiers.ts b/src/utils/rangeContainsModifiers.ts new file mode 100644 index 000000000..e31217731 --- /dev/null +++ b/src/utils/rangeContainsModifiers.ts @@ -0,0 +1,127 @@ +import { defaultDateLib, type DateLib } from "../classes/DateLib.js"; +import type { Matcher } from "../types/index.js"; + +import { areRangesOverlapping } from "./areRangesOverlapping.js"; +import { dateMatchModifiers } from "./dateMatchModifiers.js"; +import { rangeContainsDayOfWeek } from "./rangeContainsDayOfWeek.js"; +import { rangeIncludesDate } from "./rangeIncludesDate.js"; +import { + isDateAfterType, + isDateBeforeType, + isDateInterval, + isDateRange, + isDatesArray, + isDayOfWeekType +} from "./typeguards.js"; + +/** + * Returns whether a date range matches against at least one of the given + * {@link Matcher}. + * + * ```tsx + * const range: DateRange = { + * from: new Date(2021, 12, 21), + * to: new Date(2021, 12, 30) + * }; + * const matcher1: Date = new Date(2021, 12, 21); + * const matcher2: DateRange = { + * from: new Date(2022, 5, 1), + * to: new Date(2022, 5, 23) + * }; + * rangeContainsModifiers(date, [matcher1, matcher2]); // true, since matcher1 is in the date. + * ``` + * + * @group Utilities + */ +export function rangeContainsModifiers( + range: { from: Date; to: Date }, + matchers: Matcher | Matcher[], + dateLib: DateLib = defaultDateLib +): boolean { + const matchersArr = !Array.isArray(matchers) ? [matchers] : matchers; + + // function matchers needs to verified against every day in the date range, + // because of that it's the least performant one and should be deferred to be the last evaluated + const nonFunctionMatchers = matchersArr.filter( + (matcher) => typeof matcher !== "function" + ); + + const nonFunctionMatchersResult = nonFunctionMatchers.some((matcher) => { + if (typeof matcher === "boolean") { + return matcher; + } + + if (dateLib.isDate(matcher)) { + return rangeIncludesDate(range, matcher, false, dateLib); + } + + if (isDatesArray(matcher, dateLib)) { + return matcher.some((date) => + rangeIncludesDate(range, date, false, dateLib) + ); + } + + if (isDateRange(matcher)) { + if (matcher.from && matcher.to) { + const dateRangeMatcher = { from: matcher.from, to: matcher.to }; + return areRangesOverlapping(range, dateRangeMatcher, dateLib); + } + return false; + } + + if (isDayOfWeekType(matcher)) { + return rangeContainsDayOfWeek(range, matcher, dateLib); + } + + if (isDateInterval(matcher)) { + const isClosedInterval = dateLib.isAfter(matcher.before, matcher.after); + + if (isClosedInterval) { + const dateRangeMatcher = { + from: dateLib.addDays(matcher.after, 1), + to: dateLib.addDays(matcher.before, -1) + }; + return areRangesOverlapping(range, dateRangeMatcher, dateLib); + } + + return ( + dateMatchModifiers(range.from, matcher, dateLib) || + dateMatchModifiers(range.to, matcher, dateLib) + ); + } + if (isDateAfterType(matcher)) { + return ( + dateMatchModifiers(range.from, matcher, dateLib) || + dateMatchModifiers(range.to, matcher, dateLib) + ); + } + if (isDateBeforeType(matcher)) { + return ( + dateMatchModifiers(range.from, matcher, dateLib) || + dateMatchModifiers(range.to, matcher, dateLib) + ); + } + return false; + }); + + if (nonFunctionMatchersResult) { + return true; + } + + const functionMatchers = matchersArr.filter( + (matcher) => typeof matcher === "function" + ); + if (functionMatchers.length) { + let date = range.from; + const totalDays = dateLib.differenceInCalendarDays(range.to, range.from); + + for (let i = 0; i <= totalDays; i++) { + if (functionMatchers.some((matcher) => matcher(date))) { + return true; + } + date = dateLib.addDays(date, 1); + } + } + + return false; +}