Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 13 additions & 5 deletions packages/@react-aria/calendar/src/useRangeCalendar.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@ import {useRef} from 'react';
* A range calendar displays one or more date grids and allows users to select a contiguous range of dates.
*/
export function useRangeCalendar<T extends DateValue>(props: AriaRangeCalendarProps<T>, state: RangeCalendarState, ref: RefObject<FocusableElement | null>): CalendarAria {
let res = useCalendarBase(props, state);
let {pointerUpOutsideAction = 'select', ...otherProps} = props;
let res = useCalendarBase(otherProps, state);

// We need to ignore virtual pointer events from VoiceOver due to these bugs.
// https://bugs.webkit.org/show_bug.cgi?id=222627
Expand All @@ -36,7 +37,13 @@ export function useRangeCalendar<T extends DateValue>(props: AriaRangeCalendarPr
isVirtualClick.current = e.width === 0 && e.height === 0;
});

// Stop range selection when pressing or releasing a pointer outside the calendar body,
const pointerUpOutsideActionMapping = {
clear: () => state.clearSelection(),
reset: () => state.setAnchorDate(null),
select: () => state.selectFocusedDate()
};

// Execute method corresponding to `pointerUpOutsideAction` when pressing or releasing a pointer outside the calendar body,
// except when pressing the next or previous buttons to switch months.
let endDragging = (e: PointerEvent) => {
if (isVirtualClick.current) {
Expand All @@ -55,19 +62,20 @@ export function useRangeCalendar<T extends DateValue>(props: AriaRangeCalendarPr
ref.current.contains(document.activeElement) &&
(!ref.current.contains(target) || !target.closest('button, [role="button"]'))
) {
state.selectFocusedDate();
pointerUpOutsideActionMapping[pointerUpOutsideAction]();
}
};

useEvent(windowRef, 'pointerup', endDragging);

// Also stop range selection on blur, e.g. tabbing away from the calendar.
// Also execute method corresponding to `pointerUpOutsideAction` on blur,
// e.g. tabbing away from the calendar.
res.calendarProps.onBlur = e => {
if (!ref.current) {
return;
}
if ((!e.relatedTarget || !ref.current.contains(e.relatedTarget)) && state.anchorDate) {
state.selectFocusedDate();
pointerUpOutsideActionMapping[pointerUpOutsideAction]();
}
};

Expand Down
4 changes: 3 additions & 1 deletion packages/@react-stately/calendar/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -122,5 +122,7 @@ export interface RangeCalendarState extends CalendarStateBase {
/** Whether the user is currently dragging over the calendar. */
readonly isDragging: boolean,
/** Sets whether the user is dragging over the calendar. */
setDragging(isDragging: boolean): void
setDragging(isDragging: boolean): void,
/** Clears the current selection. */
clearSelection(): void
}
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,11 @@ export function useRangeCalendarState<T extends DateValue = DateValue>(props: Ra
return calendar.isInvalid(date) || isInvalid(date, availableRangeRef.current?.start, availableRangeRef.current?.end);
},
isDragging,
setDragging
setDragging,
clearSelection() {
setAnchorDate(null);
setValue(null);
}
};
}

Expand Down
18 changes: 15 additions & 3 deletions packages/@react-types/calendar/src/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,8 +67,8 @@ export interface CalendarPropsBase {
* The day that starts the week.
*/
firstDayOfWeek?: 'sun' | 'mon' | 'tue' | 'wed' | 'thu' | 'fri' | 'sat',
/**
* Determines the alignment of the visible months on initial render based on the current selection or current date if there is no selection.
/**
* Determines the alignment of the visible months on initial render based on the current selection or current date if there is no selection.
* @default 'center'
*/
selectionAlignment?: 'start' | 'center' | 'end'
Expand All @@ -86,7 +86,19 @@ export interface RangeCalendarProps<T extends DateValue> extends CalendarPropsBa

export interface AriaCalendarProps<T extends DateValue> extends CalendarProps<T>, DOMProps, AriaLabelingProps {}

export interface AriaRangeCalendarProps<T extends DateValue> extends RangeCalendarProps<T>, DOMProps, AriaLabelingProps {}
export interface AriaRangeCalendarProps<T extends DateValue> extends RangeCalendarProps<T>, DOMProps, AriaLabelingProps {
/**
* Controls the behavior when a pointer is released outside the calendar:
*
* - `clear`: clear the currently selected range of dates.
*
* - `reset`: reset the selection to the previously selected range of dates.
*
* - `select`: select the currently hovered range of dates.
* @default 'select'
*/
pointerUpOutsideAction?: 'clear' | 'reset' | 'select'
}

export type PageBehavior = 'single' | 'visible';

Expand Down