DateRangePicker: Two independent RangeCalendars with cross-calendar selection #8950
Replies: 2 comments 1 reply
-
Following... I have the same exact problem as you on my current project. I had to modify my design because I couldn't get React Aria hooks to allow me to have non-consecutive months dual calendar picker. For example I couldn't have Jan on the left and Apr on the right. The months had to be back to back according to their multi-month example on the docs. Wondering if there is a way |
Beta Was this translation helpful? Give feedback.
-
I ran into a similar issue when had to implement a multi-month approach with separated month titles. I observed that the implementation of the RangeCalendar on React Spectrum has this feature when applying the visibleMonths prop: https://react-spectrum.adobe.com/react-spectrum/RangeCalendar.html#visible-months. From the line 66 to 95 in: https://github.com/adobe/react-spectrum/blob/main/packages/%40react-spectrum/calendar/src/CalendarBase.tsx you can see how they implemented it. My approach was a bit different (Using RAC), first I created a container component to use: function CalendarNav({
className,
children,
...props
}: React.ComponentProps<'div'>) {
const { direction } = useLocale(); // hook from RAC
return (
<div
className={cn('relative flex w-full items-center gap-8', className)}
{...props}
>
<AriaButton
slot="previous"
className="absolute left-0 z-10"
>
{direction === 'rtl' ? <IconChevronRight /> : <IconChevronLeft />}
</AriaButton>
{children}
<AriaButton
slot="next"
className="absolute right-0 z-10"
>
{direction === 'rtl' ? <IconChevronLeft /> : <IconChevronRight />}
</AriaButton>
</div>
);
} The children in the above component will be this another one: function CalendarHeading({
visibleMonths = 1,
className,
...props
}: React.ComponentProps<typeof AriaHeading> & {
visibleMonths?: number;
}) {
const titles = useMonthTitles(visibleMonths); // Custom hook cited below
return (
<>
{titles.map((title) => {
return (
<AriaHeading
key={title}
className={cn(
'w-full grow text-center',
className,
)}
{...props}
aria-hidden={true}
>
{title}
</AriaHeading>
);
})}
</>
);
} The custom hook const useMonthTitles = (visibleMonths: number) => {
const calendarState = React.useContext(CalendarStateContext);
const rangeCalendarState = React.useContext(RangeCalendarStateContext);
// Works both on Calendar and RangeCalendar, getting the state of one or another
const state = calendarState ?? rangeCalendarState;
if (!state) {
throw new Error(
'useMonthTitles must be used within a Calendar or RangeCalendar',
);
}
const currentMonth = state.visibleRange.start;
// range is a util function to create an array of numbers: range(1, 5) = [1, 2, 3, 4]
return range(visibleMonths).map((monthOffset) => {
const monthDate = currentMonth.add({ months: monthOffset });
return monthDate.toDate(getLocalTimeZone());
});
}; |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
-
Hello,
I'm in the process of re-creating with React Aria an old daterangepicker for my application.
The old daterangepicker is https://github.com/skratchdot/react-bootstrap-daterangepicker
I'm struggling a bit to re-create the "cross-calendar selection" functionality, which is critical for my use case.
I think of it as two strapped togethern, which share the same state, with the exception of the visibleRange, and with independent next/prev buttons.
I've experimented quite a lot with useRangeCalendar and useRangeCalendarState, following the example at https://react-spectrum.adobe.com/react-aria/useRangeCalendar.html
However, I think I'm missing a key insight for decoupling the states I need.
I also tried approaching it in the opposite way, by having two separate states, and manually syncing the necessary states like value, anchorDate, isDragging, etc. but that seems to be even more complicated.
Any heads up would be very, very appreciated!
Thanks!
Beta Was this translation helpful? Give feedback.
All reactions