Skip to content

Commit aae37c9

Browse files
pgggggggghCopilot
andauthored
[@mantine/dates] TimePicker: Fix clearing in uncontrolled mode not updating to empty value (#8622)
* [@mantine/dates] TimePicker: Fix TimePicker clearing in uncontrolled mode not propagating empty value #8606 * [@mantine/dates] TimePicker: Fix TimePicker clearing in uncontrolled mode not propagating empty value #8606 * Update packages/@mantine/dates/src/components/TimePicker/use-time-picker.ts Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
1 parent a6f627b commit aae37c9

2 files changed

Lines changed: 28 additions & 1 deletion

File tree

packages/@mantine/dates/src/components/TimePicker/TimePicker.test.tsx

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,17 @@ describe('@mantine/dates/TimePicker', () => {
9393
expect(screen.getByLabelText('test-hours')).toHaveValue('08');
9494
});
9595

96+
it('calls onChange when cleared with backspace in uncontrolled mode', async () => {
97+
const spy = jest.fn();
98+
render(<TimePicker {...defaultProps} defaultValue="12:34" onChange={spy} />);
99+
100+
await userEvent.click(screen.getByLabelText('test-hours'));
101+
await userEvent.type(document.activeElement!, '{backspace}');
102+
103+
expect(spy).toHaveBeenCalledTimes(1);
104+
expect(spy).toHaveBeenLastCalledWith('');
105+
});
106+
96107
it('handles left/right arrow keys correctly', async () => {
97108
render(<TimePicker {...defaultProps} withSeconds format="24h" />);
98109

packages/@mantine/dates/src/components/TimePicker/use-time-picker.ts

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,18 @@ export function useTimePicker({
4444
format,
4545
});
4646

47+
const initialTimeString = getTimeString({
48+
hours: parsedTime.hours,
49+
minutes: parsedTime.minutes,
50+
seconds: parsedTime.seconds,
51+
format,
52+
withSeconds,
53+
amPm: parsedTime.amPm,
54+
amPmLabels,
55+
});
56+
4757
const acceptChange = useRef(true);
58+
const wasInvalidBefore = useRef(!initialTimeString.valid);
4859

4960
const [hours, setHours] = useState<number | null>(parsedTime.hours);
5061
const [minutes, setMinutes] = useState<number | null>(parsedTime.minutes);
@@ -87,6 +98,7 @@ export function useTimePicker({
8798

8899
if (timeString.valid) {
89100
acceptChange.current = false;
101+
wasInvalidBefore.current = false;
90102
if (field === 'hours') {
91103
setHours(val);
92104
}
@@ -103,8 +115,9 @@ export function useTimePicker({
103115
onChange?.(timeString.value);
104116
} else {
105117
acceptChange.current = false;
106-
if (typeof value === 'string' && value !== '') {
118+
if (!wasInvalidBefore.current) {
107119
onChange?.('');
120+
wasInvalidBefore.current = true;
108121
}
109122
}
110123
};
@@ -118,6 +131,8 @@ export function useTimePicker({
118131
setSeconds(parsedTime.seconds);
119132
setAmPm(parsedTime.amPm);
120133

134+
const next = getTimeString({ ...parsedTime, format, withSeconds, amPmLabels });
135+
wasInvalidBefore.current = !next.valid;
121136
onChange?.(timeString);
122137
};
123138

@@ -157,6 +172,7 @@ export function useTimePicker({
157172
setSeconds(null);
158173
setAmPm(null);
159174
onChange?.('');
175+
wasInvalidBefore.current = true;
160176
focus('hours');
161177
};
162178

0 commit comments

Comments
 (0)