diff --git a/packages/react-core/src/components/CalendarMonth/CalendarMonth.tsx b/packages/react-core/src/components/CalendarMonth/CalendarMonth.tsx index 583824c3a37..b80e69b8d99 100644 --- a/packages/react-core/src/components/CalendarMonth/CalendarMonth.tsx +++ b/packages/react-core/src/components/CalendarMonth/CalendarMonth.tsx @@ -83,9 +83,6 @@ export interface CalendarProps extends CalendarFormat, Omit boolean)[]; } -// Must be numeric given current header design -const yearFormat = (date: Date) => date.getFullYear(); - const buildCalendar = (year: number, month: number, weekStart: number, validators: ((date: Date) => boolean)[]) => { const defaultDate = new Date(year, month); @@ -164,6 +161,13 @@ export const CalendarMonth = ({ }; const initialDate = getInitialDate(); const [focusedDate, setFocusedDate] = React.useState(initialDate); + + // Must be numeric given current header design + const yearFormat = (date: Date) => date.getFullYear(); + // + const yearFormatted = yearFormat(focusedDate); + const [yearInput, setYearInput] = React.useState(yearFormatted.toString()); + const [hoveredDate, setHoveredDate] = React.useState(new Date(focusedDate)); const focusRef = React.useRef(); const [hiddenMonthId] = React.useState(getUniqueId('hidden-month-span')); @@ -191,6 +195,7 @@ export const CalendarMonth = ({ setHoveredDate(newDate); setShouldFocus(false); onMonthChange(ev, newDate); + setYearInput(yearFormat(newDate).toString()); }; const onKeyDown = (ev: React.KeyboardEvent) => { @@ -217,6 +222,34 @@ export const CalendarMonth = ({ const changeMonth = (newMonth: number, newYear?: number) => new Date(newYear ?? focusedDate.getFullYear(), newMonth, 1); + const MIN_YEAR = 1900; + const MAX_YEAR = 2100; + + const handleYearInputChange = (event: React.FormEvent, yearStr: string) => { + if (!/^\d{0,4}$/.test(yearStr)) { + return; + } + + setYearInput(yearStr); + + if (yearStr.length === 4) { + const yearNum = Number(yearStr); + + 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 + (event.target as HTMLElement).focus(); + onMonthChange(event, newDate); + } else { + setYearInput(yearFormatted.toString()); + } + } + }; + const addMonth = (toAdd: -1 | 1) => { let newMonth = focusedDate.getMonth() + toAdd; let newYear = focusedDate.getFullYear(); @@ -254,7 +287,6 @@ export const CalendarMonth = ({ } const isHoveredDateValid = isValidated(hoveredDate); const monthFormatted = monthFormat(focusedDate); - const yearFormatted = yearFormat(focusedDate); const calendarToRender = (
@@ -321,15 +353,8 @@ export const CalendarMonth = ({ , year: string) => { - const newDate = changeYear(Number(year)); - setFocusedDate(newDate); - setHoveredDate(newDate); - setShouldFocus(false); - focusRef.current?.blur(); // will unfocus a date when changing year via up/down arrows - onMonthChange(ev, newDate); - }} + value={yearInput} + onChange={handleYearInputChange} />