From 46a325453778bb2ca399df9449b69ea25c9c05be Mon Sep 17 00:00:00 2001 From: adamviktora Date: Tue, 21 May 2024 11:03:22 +0200 Subject: [PATCH 1/2] fix(DatePicker/CalendarMonth): range styling when disabled dates --- .../CalendarMonth/CalendarMonth.tsx | 38 +++++++++---------- .../src/components/DatePicker/DatePicker.tsx | 15 +++++++- 2 files changed, 33 insertions(+), 20 deletions(-) diff --git a/packages/react-core/src/components/CalendarMonth/CalendarMonth.tsx b/packages/react-core/src/components/CalendarMonth/CalendarMonth.tsx index b80e69b8d99..e57291e8240 100644 --- a/packages/react-core/src/components/CalendarMonth/CalendarMonth.tsx +++ b/packages/react-core/src/components/CalendarMonth/CalendarMonth.tsx @@ -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(undefined); const focusRef = React.useRef(); const [hiddenMonthId] = React.useState(getUniqueId('hidden-month-span')); const [shouldFocus, setShouldFocus] = React.useState(false); @@ -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()); @@ -212,7 +211,6 @@ export const CalendarMonth = ({ if (newDate.getTime() !== focusedDate.getTime() && isValidated(newDate)) { ev.preventDefault(); setFocusedDate(newDate); - setHoveredDate(newDate); setShouldFocus(true); } }; @@ -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 @@ -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 = ( @@ -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); @@ -369,7 +364,7 @@ export const CalendarMonth = ({ - +
setHoveredDate(undefined)}> {calendar[0].map(({ date }, index) => ( @@ -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 ( @@ -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 )} diff --git a/packages/react-core/src/components/DatePicker/DatePicker.tsx b/packages/react-core/src/components/DatePicker/DatePicker.tsx index dbe306ce54a..166f92bbdf2 100644 --- a/packages/react-core/src/components/DatePicker/DatePicker.tsx +++ b/packages/react-core/src/components/DatePicker/DatePicker.tsx @@ -231,12 +231,25 @@ 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); + const getElementToFocus = () => { + if (isValidDate(valueDate) && isValidDate(rangeStart)) { + return focusSelectorForSelectedEndRangeDate; + } + if (isValidDate(valueDate) || isValidDate(rangeStart)) { + return focusSelectorForSelectedDate; + } + return focusSelectorForUnselectedDate; + }; + return (
Date: Tue, 28 May 2024 10:57:33 +0200 Subject: [PATCH 2/2] chore(Datepicker): getElementSelectorToFocus function description --- .../react-core/src/components/DatePicker/DatePicker.tsx | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/packages/react-core/src/components/DatePicker/DatePicker.tsx b/packages/react-core/src/components/DatePicker/DatePicker.tsx index 166f92bbdf2..8e510b2c1f0 100644 --- a/packages/react-core/src/components/DatePicker/DatePicker.tsx +++ b/packages/react-core/src/components/DatePicker/DatePicker.tsx @@ -236,7 +236,12 @@ const DatePickerBase = ( ); const focusSelectorForUnselectedDate = createFocusSelectorString(calendarMonthStyles.modifiers.current); - const getElementToFocus = () => { + /** + * 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; } @@ -249,7 +254,7 @@ const DatePickerBase = ( return (