Skip to content

Commit

Permalink
fix(DatePicker/CalendarMonth): better range styling when some dates a…
Browse files Browse the repository at this point in the history
…re disabled (patternfly#10398)

* fix(DatePicker/CalendarMonth): range styling when disabled dates

* chore(Datepicker): getElementSelectorToFocus function description
  • Loading branch information
adamviktora authored and tlabaj committed Jun 14, 2024
1 parent 0f901ec commit 467662b
Show file tree
Hide file tree
Showing 2 changed files with 38 additions and 20 deletions.
38 changes: 19 additions & 19 deletions packages/react-core/src/components/CalendarMonth/CalendarMonth.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,7 @@ export const CalendarMonth = ({
const yearFormatted = yearFormat(focusedDate);
const [yearInput, setYearInput] = React.useState(yearFormatted.toString());

const [hoveredDate, setHoveredDate] = React.useState(new Date(focusedDate));
const [hoveredDate, setHoveredDate] = React.useState<Date>(undefined);
const focusRef = React.useRef<HTMLButtonElement>();
const [hiddenMonthId] = React.useState(getUniqueId('hidden-month-span'));
const [shouldFocus, setShouldFocus] = React.useState(false);
Expand All @@ -192,7 +192,6 @@ export const CalendarMonth = ({

const onMonthClick = (ev: React.MouseEvent, newDate: Date) => {
setFocusedDate(newDate);
setHoveredDate(newDate);
setShouldFocus(false);
onMonthChange(ev, newDate);
setYearInput(yearFormat(newDate).toString());
Expand All @@ -212,7 +211,6 @@ export const CalendarMonth = ({
if (newDate.getTime() !== focusedDate.getTime() && isValidated(newDate)) {
ev.preventDefault();
setFocusedDate(newDate);
setHoveredDate(newDate);
setShouldFocus(true);
}
};
Expand All @@ -238,7 +236,6 @@ export const CalendarMonth = ({
if (yearNum >= MIN_YEAR && yearNum <= MAX_YEAR) {
const newDate = changeYear(yearNum);
setFocusedDate(newDate);
setHoveredDate(newDate);
setShouldFocus(false);

// We need to manually focus the year input in FireFox when the scroll buttons are clicked, as FireFox doesn't place focus automatically
Expand Down Expand Up @@ -282,10 +279,9 @@ export const CalendarMonth = ({
.map(({ date }) => date)[0];
if (toFocus) {
setFocusedDate(toFocus);
setHoveredDate(toFocus);
}
}
const isHoveredDateValid = isValidated(hoveredDate);
const isHoveredDateValid = hoveredDate && isValidated(hoveredDate);
const monthFormatted = monthFormat(focusedDate);

const calendarToRender = (
Expand Down Expand Up @@ -331,7 +327,6 @@ export const CalendarMonth = ({
onSelectToggle(false);
const newDate = changeMonth(Number(monthNum as string));
setFocusedDate(newDate);
setHoveredDate(newDate);
setShouldFocus(false);
onMonthChange(ev, newDate);
}, 0);
Expand Down Expand Up @@ -369,7 +364,7 @@ export const CalendarMonth = ({
</Button>
</div>
</div>
<table className={styles.calendarMonthCalendar}>
<table className={styles.calendarMonthCalendar} onMouseLeave={() => setHoveredDate(undefined)}>
<thead className={styles.calendarMonthDays}>
<tr>
{calendar[0].map(({ date }, index) => (
Expand All @@ -392,16 +387,21 @@ export const CalendarMonth = ({
const isRangeStart = isValidDate(rangeStart) && isSameDate(date, rangeStart);
let isInRange = false;
let isRangeEnd = false;
if (isValidDate(rangeStart) && isValidDate(dateProp)) {
isInRange = date > rangeStart && date < dateProp;
isRangeEnd = isSameDate(date, dateProp);
} else if (isValidDate(rangeStart) && isHoveredDateValid) {
if (hoveredDate > rangeStart || isSameDate(hoveredDate, rangeStart)) {
isInRange = date > rangeStart && date < hoveredDate;
isRangeEnd = isSameDate(date, hoveredDate);
if (isValidDate(rangeStart)) {
let rangeEndDate: Date;

if (isValidDate(dateProp)) {
rangeEndDate = dateProp;
}
if (isHoveredDateValid && (!isValidDate(dateProp) || hoveredDate > dateProp)) {
rangeEndDate = hoveredDate;
}

if (rangeEndDate) {
isInRange = date >= rangeStart && date <= rangeEndDate;
isRangeEnd = isSameDate(date, rangeEndDate);
}
// Don't handle focused dates before start dates for now.
// Core would likely need new styles
// Core would likely need new styles for "is selected but disabled"
}

return (
Expand All @@ -412,8 +412,8 @@ export const CalendarMonth = ({
isAdjacentMonth && styles.modifiers.adjacentMonth,
isToday && styles.modifiers.current,
(isSelected || isRangeStart) && styles.modifiers.selected,
!isValid && styles.modifiers.disabled,
(isInRange || isRangeStart || isRangeEnd) && styles.modifiers.inRange,
!isValid && !(isInRange || isRangeStart || isRangeEnd || isSelected) && styles.modifiers.disabled,
isInRange && styles.modifiers.inRange,
isRangeStart && styles.modifiers.startRange,
isRangeEnd && styles.modifiers.endRange
)}
Expand Down
20 changes: 19 additions & 1 deletion packages/react-core/src/components/DatePicker/DatePicker.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -231,12 +231,30 @@ const DatePickerBase = (
const createFocusSelectorString = (modifierClass: string) =>
`.${calendarMonthStyles.calendarMonthDatesCell}.${modifierClass} .${calendarMonthStyles.calendarMonthDate}`;
const focusSelectorForSelectedDate = createFocusSelectorString(calendarMonthStyles.modifiers.selected);
const focusSelectorForSelectedEndRangeDate = createFocusSelectorString(
`${calendarMonthStyles.modifiers.selected}.${calendarMonthStyles.modifiers.endRange}`
);
const focusSelectorForUnselectedDate = createFocusSelectorString(calendarMonthStyles.modifiers.current);

/**
* Returns a CSS selector for a date button element which will receive initial focus after opening calendar popover.
* In case of a range picker it returns the end date, if it is selected, start date otherwise.
* In case of a normal datepicker it returns the selected date, if present, today otherwise.
*/
const getElementSelectorToFocus = () => {
if (isValidDate(valueDate) && isValidDate(rangeStart)) {
return focusSelectorForSelectedEndRangeDate;
}
if (isValidDate(valueDate) || isValidDate(rangeStart)) {
return focusSelectorForSelectedDate;
}
return focusSelectorForUnselectedDate;
};

return (
<div className={css(styles.datePicker, className)} ref={datePickerWrapperRef} style={style} {...props}>
<Popover
elementToFocus={isValidDate(valueDate) ? focusSelectorForSelectedDate : focusSelectorForUnselectedDate}
elementToFocus={getElementSelectorToFocus()}
position="bottom"
bodyContent={
<CalendarMonth
Expand Down

0 comments on commit 467662b

Please sign in to comment.