Skip to content

Commit 21f8468

Browse files
committed
fix(date-picker): instant update when using arrows on year field
1 parent 3b5b7f1 commit 21f8468

File tree

1 file changed

+48
-27
lines changed

1 file changed

+48
-27
lines changed

packages/lumx-react/src/components/date-picker/DatePickerControlled.tsx

Lines changed: 48 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import React, { KeyboardEventHandler, forwardRef } from 'react';
22
import classNames from 'classnames';
3-
import { DatePickerProps, Emphasis, FlexBox, IconButton, Text, TextField, Toolbar } from '@lumx/react';
3+
import { DatePickerProps, Emphasis, FlexBox, IconButton, Text, TextField, TextFieldProps, Toolbar } from '@lumx/react';
44
import { mdiChevronLeft, mdiChevronRight } from '@lumx/icons';
55
import { Comp } from '@lumx/react/utils/type';
66
import { getMonthCalendar } from '@lumx/react/utils/date/getMonthCalendar';
@@ -62,35 +62,56 @@ export const DatePickerControlled: Comp<DatePickerControlledProps, HTMLDivElemen
6262
}, [locale, minDate, maxDate, selectedMonth]);
6363

6464
const selectedYear = selectedMonth.toLocaleDateString(locale, { year: 'numeric' }).slice(0, 4);
65-
const [textFieldYearValue, setTextFieldYearValue] = React.useState(selectedYear);
66-
const isYearValid = Number(textFieldYearValue) > 0 && Number(textFieldYearValue) <= 9999;
65+
const [currentYear, setCurrentYear] = React.useState(selectedYear);
6766

6867
// Updates month offset when validating year. Adds or removes 12 months per year when updating year value.
69-
const updateMonthOffset = React.useCallback(() => {
70-
if (isYearValid) {
71-
const yearNumber = selectedMonth.getFullYear();
72-
const offset = (Number(textFieldYearValue) - yearNumber) * 12;
73-
if (onMonthChange) {
74-
onMonthChange(addMonthResetDay(selectedMonth, offset));
68+
const updateMonthOffset = React.useCallback(
69+
(newYearValue: string) => {
70+
const yearNumber = Number(newYearValue);
71+
if (yearNumber < 0 && yearNumber >= 9999) {
72+
return;
7573
}
76-
}
77-
}, [isYearValid, selectedMonth, textFieldYearValue, onMonthChange]);
7874

79-
const monthYear = selectedMonth.toLocaleDateString(locale, { year: 'numeric', month: 'long' });
75+
const previousYearNumber = selectedMonth.getFullYear();
76+
const offset = (yearNumber - previousYearNumber) * 12;
77+
onMonthChange?.(addMonthResetDay(selectedMonth, offset));
78+
},
79+
[selectedMonth, onMonthChange],
80+
);
81+
82+
const onYearChange = React.useCallback<TextFieldProps['onChange']>(
83+
(newYearValue, _, event) => {
84+
setCurrentYear(newYearValue);
8085

81-
// Year can only be validated by pressing Enter key or on Blur. The below handles the press Enter key case
82-
const handleKeyPress: KeyboardEventHandler = React.useMemo(
83-
() => onEnterPressed(updateMonthOffset),
86+
// Detect if change is coming from the spin up/down arrows
87+
const inputType = (event?.nativeEvent as any)?.inputType;
88+
if (
89+
// Chrome/Safari
90+
!inputType ||
91+
// Firefox
92+
inputType === 'insertReplacementText'
93+
) {
94+
updateMonthOffset(newYearValue);
95+
}
96+
},
8497
[updateMonthOffset],
8598
);
8699

87-
// Required to update year in the TextField when the user changes year by using prev next month arrows
100+
const updateYear = React.useCallback(() => {
101+
updateMonthOffset(currentYear);
102+
}, [updateMonthOffset, currentYear]);
103+
104+
const updateYearOnEnterPressed: KeyboardEventHandler = React.useMemo(
105+
() => onEnterPressed(updateYear),
106+
[updateYear],
107+
);
108+
109+
const monthYear = selectedMonth.toLocaleDateString(locale, { year: 'numeric', month: 'long' });
110+
111+
// Update current year when selected year changes
88112
React.useEffect(() => {
89-
if (Number(textFieldYearValue) !== selectedMonth.getFullYear()) {
90-
setTextFieldYearValue(selectedMonth.getFullYear().toString());
91-
}
92-
// eslint-disable-next-line react-hooks/exhaustive-deps
93-
}, [selectedMonth]);
113+
setCurrentYear(selectedYear);
114+
}, [selectedYear]);
94115

95116
const prevSelectedMonth = usePreviousValue(selectedMonth);
96117
const monthHasChanged = prevSelectedMonth && !isSameDay(selectedMonth, prevSelectedMonth);
@@ -101,7 +122,7 @@ export const DatePickerControlled: Comp<DatePickerControlledProps, HTMLDivElemen
101122
if (monthHasChanged) setLabelAriaLive('polite');
102123
}, [monthHasChanged]);
103124

104-
const label = getYearDisplayName(locale);
125+
const yearLabel = getYearDisplayName(locale);
105126

106127
return (
107128
<div ref={ref} className={`${CLASSNAME}`}>
@@ -144,14 +165,14 @@ export const DatePickerControlled: Comp<DatePickerControlledProps, HTMLDivElemen
144165
.map((part) =>
145166
part === selectedYear ? (
146167
<TextField
147-
value={textFieldYearValue}
148-
aria-label={label}
149-
onChange={setTextFieldYearValue}
168+
value={currentYear}
169+
aria-label={yearLabel}
170+
onChange={onYearChange}
150171
type="number"
151172
max={9999}
152173
min={0}
153-
onBlur={updateMonthOffset}
154-
onKeyPress={handleKeyPress}
174+
onBlur={updateYear}
175+
onKeyPress={updateYearOnEnterPressed}
155176
key="year"
156177
className={`${CLASSNAME}__year`}
157178
/>

0 commit comments

Comments
 (0)