diff --git a/packages/core/src/RangeCalendar/RangeCalendar.test.ts b/packages/core/src/RangeCalendar/RangeCalendar.test.ts index a74c6d031..a4cb0291d 100644 --- a/packages/core/src/RangeCalendar/RangeCalendar.test.ts +++ b/packages/core/src/RangeCalendar/RangeCalendar.test.ts @@ -726,8 +726,8 @@ describe('handles maximumDays', () => { }) const startDay = getByTestId('date-1-15') - const maximumDay = getByTestId('date-1-20') // 5 days ahead - const beyondMaximumDay = getByTestId('date-1-21') // 6 days ahead + const maximumDay = getByTestId('date-1-19') // 5 days ahead + const beyondMaximumDay = getByTestId('date-1-20') // 6 days ahead await user.click(startDay) expect(startDay).toHaveAttribute('data-selection-start') @@ -739,12 +739,12 @@ describe('handles maximumDays', () => { expect(beyondMaximumDay).not.toHaveAttribute('data-selected') // Should be limited to 5 days - expect(getByTestId('date-1-20')).not.toHaveAttribute('data-disabled') + expect(getByTestId('date-1-19')).not.toHaveAttribute('data-disabled') await user.click(maximumDay) // Check that all days within the maximum range are selected - for (let day = 15; day <= 20; day++) { + for (let day = 15; day < 20; day++) { expect(getByTestId(`date-1-${day}`)).toHaveAttribute('data-selected') } }) @@ -771,10 +771,10 @@ describe('handles maximumDays', () => { expect(getByTestId('date-1-14')).toHaveAttribute('aria-disabled', 'true') // Days within the limit should not be disabled - expect(getByTestId('date-1-13')).not.toHaveAttribute('aria-disabled', 'true') + expect(getByTestId('date-1-12')).not.toHaveAttribute('aria-disabled', 'true') // Complete the range selection with a date within the limit - await user.click(getByTestId('date-1-13')) + await user.click(getByTestId('date-1-12')) // Distant dates should no longer be disabled expect(getByTestId('date-1-20')).not.toHaveAttribute('aria-disabled', 'true') @@ -784,7 +784,7 @@ describe('handles maximumDays', () => { expect(getByTestId('date-1-15')).toHaveAttribute('data-selection-start') // Days beyond the maximum limit from the new start date should be disabled - expect(getByTestId('date-1-19')).toHaveAttribute('aria-disabled', 'true') - expect(getByTestId('date-1-18')).not.toHaveAttribute('aria-disabled', 'true') + expect(getByTestId('date-1-18')).toHaveAttribute('aria-disabled', 'true') + expect(getByTestId('date-1-17')).not.toHaveAttribute('aria-disabled', 'true') }) }) diff --git a/packages/core/src/RangeCalendar/useRangeCalendar.ts b/packages/core/src/RangeCalendar/useRangeCalendar.ts index 3bba4c582..c0ae14df6 100644 --- a/packages/core/src/RangeCalendar/useRangeCalendar.ts +++ b/packages/core/src/RangeCalendar/useRangeCalendar.ts @@ -7,7 +7,7 @@ import type { Ref } from 'vue' import type { Matcher } from '@/date' import { isSameDay } from '@internationalized/date' import { computed } from 'vue' -import { areAllDaysBetweenValid, isBefore, isBetween } from '@/date' +import { areAllDaysBetweenValid, getDaysBetween, isBefore, isBetween } from '@/date' export type UseRangeCalendarProps = { start: Ref @@ -76,12 +76,29 @@ export function useRangeCalendarState(props: UseRangeCalendarProps) { if (props.isDateDisabled(date)) return true - if (!props.maximumDays?.value || !props.start.value || props.end.value || isSameDay(props.start.value, date)) - return false - // Check if exceeds maximum days limit - if (Math.abs(date.compare(props.start.value)) > props.maximumDays.value) - return true + if (props.maximumDays?.value) { + if (props.start.value && props.end.value) { + if (props.fixedDate.value) { + const diff = getDaysBetween(props.start.value, props.end.value).length + if (diff <= props.maximumDays.value) { + const daysLeft = props.maximumDays.value - diff - 1 + const startLimit = props.start.value.subtract({ days: daysLeft }) + const endLimit = props.end.value.add({ days: daysLeft }) + return !isBetween(date, startLimit, endLimit) + } + } + return false + } + if (props.start.value) { + const maxDate = props.start.value.add({ days: props.maximumDays.value }) + const minDate = props.start.value.subtract({ days: props.maximumDays.value }) + return !isBetween(date, minDate, maxDate) + } + } + + if (!props.start.value || props.end.value || isSameDay(props.start.value, date)) + return false return false } @@ -111,7 +128,7 @@ export function useRangeCalendarState(props: UseRangeCalendarProps) { // If maximum days is set and the range exceeds it, limit the highlight // We only apply this when we're in the middle of a selection (no end date yet) - if (props.maximumDays?.value && !props.end.value && Math.abs(end.compare(start)) > props.maximumDays.value) { + if (props.maximumDays?.value && !props.end.value) { // Determine the direction of selection and limit to maximum days const cappedEnd = isStartBeforeFocused ? start.add({ days: props.maximumDays.value })