Skip to content
Merged
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
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,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We may need to apply this same logic elsewhere where we're applying disabled styling/setting disabled prop. Using the validator from the issue (date > from rather than date >= from), the rangeStart date for the second datepicker doesn't have the expected styling:

image

Copy link
Contributor Author

@adamviktora adamviktora May 28, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is due to the docs building error resolved in #10416, it looks fine locally.
EDIT: I rebased and the example looks good now

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