Skip to content

Commit d7f1121

Browse files
ibolton336tlabaj
authored andcommitted
🐛 Address datepicker crashing when manually entering year (patternfly#10134)
1 parent 193cb22 commit d7f1121

File tree

1 file changed

+38
-13
lines changed

1 file changed

+38
-13
lines changed

packages/react-core/src/components/CalendarMonth/CalendarMonth.tsx

Lines changed: 38 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -83,9 +83,6 @@ export interface CalendarProps extends CalendarFormat, Omit<React.HTMLProps<HTML
8383
validators?: ((date: Date) => boolean)[];
8484
}
8585

86-
// Must be numeric given current header design
87-
const yearFormat = (date: Date) => date.getFullYear();
88-
8986
const buildCalendar = (year: number, month: number, weekStart: number, validators: ((date: Date) => boolean)[]) => {
9087
const defaultDate = new Date(year, month);
9188

@@ -164,6 +161,13 @@ export const CalendarMonth = ({
164161
};
165162
const initialDate = getInitialDate();
166163
const [focusedDate, setFocusedDate] = React.useState(initialDate);
164+
165+
// Must be numeric given current header design
166+
const yearFormat = (date: Date) => date.getFullYear();
167+
//
168+
const yearFormatted = yearFormat(focusedDate);
169+
const [yearInput, setYearInput] = React.useState(yearFormatted.toString());
170+
167171
const [hoveredDate, setHoveredDate] = React.useState(new Date(focusedDate));
168172
const focusRef = React.useRef<HTMLButtonElement>();
169173
const [hiddenMonthId] = React.useState(getUniqueId('hidden-month-span'));
@@ -191,6 +195,7 @@ export const CalendarMonth = ({
191195
setHoveredDate(newDate);
192196
setShouldFocus(false);
193197
onMonthChange(ev, newDate);
198+
setYearInput(yearFormat(newDate).toString());
194199
};
195200

196201
const onKeyDown = (ev: React.KeyboardEvent<HTMLTableSectionElement>) => {
@@ -217,6 +222,34 @@ export const CalendarMonth = ({
217222
const changeMonth = (newMonth: number, newYear?: number) =>
218223
new Date(newYear ?? focusedDate.getFullYear(), newMonth, 1);
219224

225+
const MIN_YEAR = 1900;
226+
const MAX_YEAR = 2100;
227+
228+
const handleYearInputChange = (event: React.FormEvent<HTMLInputElement>, yearStr: string) => {
229+
if (!/^\d{0,4}$/.test(yearStr)) {
230+
return;
231+
}
232+
233+
setYearInput(yearStr);
234+
235+
if (yearStr.length === 4) {
236+
const yearNum = Number(yearStr);
237+
238+
if (yearNum >= MIN_YEAR && yearNum <= MAX_YEAR) {
239+
const newDate = changeYear(yearNum);
240+
setFocusedDate(newDate);
241+
setHoveredDate(newDate);
242+
setShouldFocus(false);
243+
244+
// We need to manually focus the year input in FireFox when the scroll buttons are clicked, as FireFox doesn't place focus automatically
245+
(event.target as HTMLElement).focus();
246+
onMonthChange(event, newDate);
247+
} else {
248+
setYearInput(yearFormatted.toString());
249+
}
250+
}
251+
};
252+
220253
const addMonth = (toAdd: -1 | 1) => {
221254
let newMonth = focusedDate.getMonth() + toAdd;
222255
let newYear = focusedDate.getFullYear();
@@ -254,7 +287,6 @@ export const CalendarMonth = ({
254287
}
255288
const isHoveredDateValid = isValidated(hoveredDate);
256289
const monthFormatted = monthFormat(focusedDate);
257-
const yearFormatted = yearFormat(focusedDate);
258290

259291
const calendarToRender = (
260292
<div className={css(styles.calendarMonth, className)} {...props}>
@@ -321,15 +353,8 @@ export const CalendarMonth = ({
321353
<TextInput
322354
aria-label={yearInputAriaLabel}
323355
type="number"
324-
value={yearFormatted}
325-
onChange={(ev: React.FormEvent<HTMLInputElement>, year: string) => {
326-
const newDate = changeYear(Number(year));
327-
setFocusedDate(newDate);
328-
setHoveredDate(newDate);
329-
setShouldFocus(false);
330-
focusRef.current?.blur(); // will unfocus a date when changing year via up/down arrows
331-
onMonthChange(ev, newDate);
332-
}}
356+
value={yearInput}
357+
onChange={handleYearInputChange}
333358
/>
334359
</div>
335360
</InputGroupItem>

0 commit comments

Comments
 (0)