react-spectrum
react-spectrum copied to clipboard
UseRangeCalendar - change availability of dates based on anchorDate
๐ Feature Request
Hello! My team is using react-aria rangeCalendar hooks for quite a complex range selection with a lot of different day states. Most of it was fairly easy to implement using the different options these hooks provide but one thing that we haven't found a nice solution (other than hacky workarounds) for is changing date availability in the middle of the range selection. What we want is to show different dates as unavailable/available depending on whether the user didn't make any selection yet, chose the anchorDate or has fully selected a range. In short, we are looking for more flexibility with the isDateUnavailable function.
๐ค Expected Behavior
It is possible to use range calendar state into account when determining the date availability.
๐ฏ Current Behavior
The isDateUnavailable function only has one param (the date in question) and it is part of the input to get the state object (from the useRangeCalendarState hook). Since you only get the anchorDate from that state object, it is quite hacky to use it to determine date availability. Our current workaround includes keeping our own state of anchorDate, which adds unnecessary complexity.
๐ Possible Solution
This can probably be solved in multiple ways, but our suggestion would be to pass additional params to the isDateUnavailable function (e.g. the anchorDate but perhaps the full state object would make even more sense) that would allow us to use that information in determining the date availability.
๐ฆ Context
Some context is already provided in the summary above. The range selection we're looking for is quite dynamic, where different dates can only be start OR end dates, there can be enforced minimum length of ranges or even only full weeks selection can be allowed. Therefore, the date unavailability changes a lot based on user action.
๐ป Examples
N/A
๐งข Your Company/Team
N/A
๐ Tracking Ticket (optional)
N/A
Hey @dj-neza! Did you get some solution to this? Did you end up using some hacky solutions? And if yes, could you provide example?
I've also come up against this issue. Our use cases include limiting the duration of the date range to 7 days and requiring that the user select at least one week. While extra validation can report the requirements to the user after they made a selection, it'd be nice to provide feedback while the user is choosing dates to begin with.
I was about to open a new feature request for minDuration and maxDuration props for RangeCalendar and DateRangePicker, but I'll add the context here because I think I'm only describing one possible solution to the issue or maybe only a subset of it as described above.
Before diving into more details, here's a concrete example of the intended result: https://github.com/adobe/react-spectrum/assets/1218900/5f865daa-c75a-44a3-8146-d5f6e47cdcac
The user is allowed to choose any date, but the final range can only be 7 days in total. Once the user chooses the anchor date, the 6 days before and after the anchor date remain available and all other dates are unavailable.
The example above is implemented with roughly the following workaround:
const AnchorDateWatcher = ({ setAnchorDate }) => {
const { anchorDate } = useContext(RangeCalendarStateContext);
useEffect(() => setAnchorDate(anchorDate), [anchorDate, setAnchorDate]);
return null;
}
const MyDateRangePicker = ({ isDateUnvailable, label, description, errorMessage, ...props }) => {
const [anchorDate, setAnchorDate] = useState<DateValue | null>(null)
const _isDateUnavailable = useCallback((date: DateValue) => {
let result = isDateUnavailable?.(date) ?? false
if (!result && anchorDate) {
result = Math.abs(date.compare(anchorDate)) > 6
}
return result
}, [anchorDate, isDateUnavailable])
return (
<DateRangePicker isDateUnavailable={_isDateUnvailable} {...props}>
<Label>{label}</Label>
<Group>{...}</Group>
{description && <Text slot="description">{description}</Text>}
<FieldError>{errorMessage}</FieldError>
<Popover>
<Dialog>
<RangeCalendar>
<AnchorDateWatcher setAnchorDate={setAnchorDate} />
<header>{...}</header>
<CalendarGrid>
{...}
</CalendarGrid>
</RangeCalendar>
</Dialog>
</Popover>
</DateRangePicker>
)
}
This hack works, but it'd be great to have this functionality builtin. I propose adding two props, minDuration and maxDuration to RangeCalendar and DateRangePicker. These props can be either static durations like { days: 7 } or functions that take the anchorDate and return such a duration. To implement the example above, I would be able to use the following:
<DateRangePicker minValue={today()} maxDuration={{ days: 7 }}>{...}</DateRangePicker>
Allowing the props to be functions would cover more advanced use cases like allowing a rental to be booked for up to only 1 week during the summer, but up to 2 weeks in the off-season. Additionally, minDuration and maxDuration could be combined to handle use cases like selecting at least 1 week, but at most 2 or limiting the selection to exactly 1 week.
The initial suggestion here of adding the anchorDate as a second argument to isDateUnavailable would surely cover all of the use cases I've listed, but I can't think of a use case not covered by minDuration/maxDuration. Additionally, I think the majority of users would benefit from the narrower minDuration and maxDuration props as they could be integrated into the existing validation with localizations and would avoid the need for folks to repeat error-prone, datetime math in all of their isDateUnavailable definitions. I think the minDuration and maxDuration values could also include time information for fine-grained validation when the DateRangePicker includes time fields.
@jsvirtane Perhaps the hack I showed above can help you in your use case.
@adriantrunzo Hello Adrian! I have the same use case and thank you for sharing the example! ~~When I try to use it in my project, I'm faced with a weird problem:~~
~~When you select the anchor date, the popover is not visually updated. The unavailable dates are not crossed out as in your example. However, the _isDateUnavailable function runs and mouse events are correct, as you can't select the unavailable dates, but the visual representation is just not updated.~~
~~I wonder if you faced a similar problem in your workaround.~~
Edit: forgot to add a style for aria-disabled.......
And yeah +1 to support this feature natively.