Skip to content

Commit c244775

Browse files
Add support for onInvalidChange prop
Replaces #398 Co-Authored-By: irunner-toptal <94855173+irunner-toptal@users.noreply.github.com>
1 parent 296f770 commit c244775

4 files changed

Lines changed: 27 additions & 0 deletions

File tree

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,7 @@ Displays an input field complete with custom inputs, native input, and a calenda
111111
| onCalendarOpen | Function called when the calendar opens. | n/a | `() => alert('Calendar opened')` |
112112
| onChange | Function called when the user picks a valid date. If any of the fields were excluded using custom `format`, `new Date(y, 0, 1, 0, 0, 0)`, where `y` is the current year, is going to serve as a "base". | n/a | `(value) => alert('New date is: ', value)` |
113113
| onFocus | Function called when the focuses an input. | n/a | `(event) => alert('Focused input: ', event.target.name)` |
114+
| onInvalidChange | Function called when the user picks an invalid date. | n/a | `() => alert('Invalid date')` |
114115
| openCalendarOnFocus | Whether to open the calendar on input focus. Note: It's recommended to use shouldOpenCalendar function instead. | `true` | `false` |
115116
| portalContainer | Element to render the calendar in using portal. | n/a | `document.getElementById('my-div')` |
116117
| required | Whether date input should be required. | `false` | `true` |

src/DateInput.tsx

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,7 @@ type DateInputProps = {
191191
name?: string;
192192
nativeInputAriaLabel?: string;
193193
onChange?: (value: Value, shouldCloseCalendar: boolean) => void;
194+
onInvalidChange?: () => void;
194195
required?: boolean;
195196
returnValue?: 'start' | 'end' | 'range';
196197
showLeadingZeros?: boolean;
@@ -216,6 +217,7 @@ export default function DateInput({
216217
name = 'date',
217218
nativeInputAriaLabel,
218219
onChange: onChangeProps,
220+
onInvalidChange,
219221
required,
220222
returnValue = 'start',
221223
showLeadingZeros,
@@ -483,6 +485,12 @@ export default function DateInput({
483485
onChangeProps(processedValue, false);
484486
return;
485487
}
488+
489+
if (!onInvalidChange) {
490+
return;
491+
}
492+
493+
onInvalidChange();
486494
}
487495

488496
/**

src/DatePicker.spec.tsx

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -537,6 +537,21 @@ describe('DatePicker', () => {
537537
expect(onChange).toHaveBeenCalledWith(new Date(2023, 0, 1));
538538
});
539539

540+
it('calls onInvalidChange callback when changing value to an invalid one', () => {
541+
const value = new Date(2023, 0, 31);
542+
const onInvalidChange = vi.fn();
543+
544+
const { container } = render(<DatePicker onInvalidChange={onInvalidChange} value={value} />);
545+
546+
const dayInput = container.querySelector('input[name="day"]') as HTMLInputElement;
547+
548+
act(() => {
549+
fireEvent.change(dayInput, { target: { value: '32' } });
550+
});
551+
552+
expect(onInvalidChange).toHaveBeenCalled();
553+
});
554+
540555
it('clears the value when clicking on a button', () => {
541556
const onChange = vi.fn();
542557

src/DatePicker.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ export type DatePickerProps = {
8686
onCalendarOpen?: () => void;
8787
onChange?: (value: Value) => void;
8888
onFocus?: (event: React.FocusEvent<HTMLDivElement>) => void;
89+
onInvalidChange?: () => void;
8990
openCalendarOnFocus?: boolean;
9091
portalContainer?: HTMLElement | null;
9192
required?: boolean;
@@ -128,6 +129,7 @@ export default function DatePicker(props: DatePickerProps) {
128129
onCalendarOpen,
129130
onChange: onChangeProps,
130131
onFocus: onFocusProps,
132+
onInvalidChange,
131133
openCalendarOnFocus = true,
132134
required,
133135
returnValue = 'start',
@@ -314,6 +316,7 @@ export default function DatePicker(props: DatePickerProps) {
314316
minDate={minDate}
315317
name={name}
316318
onChange={onChange}
319+
onInvalidChange={onInvalidChange}
317320
required={required}
318321
returnValue={returnValue}
319322
showLeadingZeros={showLeadingZeros}

0 commit comments

Comments
 (0)