From 24beea49a385c5aae34c0a575bc19438a4052065 Mon Sep 17 00:00:00 2001 From: Eric Olkowski <70952936+thatblindgeye@users.noreply.github.com> Date: Wed, 23 Aug 2023 16:44:04 -0400 Subject: [PATCH] fix(DatePicker): updated v4 onBlur logic (#9491) * fix(DatePicker): updated v4 onBlur logic * Added example --- .../src/components/DatePicker/DatePicker.tsx | 40 ++++++++++++++----- .../DatePicker/examples/DatePicker.md | 13 +++++- .../examples/DatePickerRequired.tsx | 6 +++ 3 files changed, 49 insertions(+), 10 deletions(-) create mode 100644 packages/react-core/src/components/DatePicker/examples/DatePickerRequired.tsx diff --git a/packages/react-core/src/components/DatePicker/DatePicker.tsx b/packages/react-core/src/components/DatePicker/DatePicker.tsx index abbd7a2502a..e0bca30e62b 100644 --- a/packages/react-core/src/components/DatePicker/DatePicker.tsx +++ b/packages/react-core/src/components/DatePicker/DatePicker.tsx @@ -11,6 +11,14 @@ import { useImperativeHandle } from 'react'; import { KeyTypes } from '../../helpers'; import { isValidDate } from '../../helpers/datetimeUtils'; +/** Props that customize the requirement of a date */ +export interface DatePickerRequiredObject { + /** Flag indicating the date is required. */ + isRequired?: boolean; + /** Error message to display when the text input is empty and the isRequired prop is also passed in. */ + emptyDateText?: string; +} + /** The main date picker component. */ export interface DatePickerProps @@ -31,7 +39,7 @@ export interface DatePickerProps className?: string; /** How to format the date in the text input. */ dateFormat?: (date: Date) => string; - /** How to format the date in the text input. */ + /** How to parse the date in the text input. */ dateParse?: (value: string) => Date; /** Helper text to display alongside the date picker. */ helperText?: React.ReactNode; @@ -39,7 +47,7 @@ export interface DatePickerProps inputProps?: TextInputProps; /** Flag indicating the date picker is disabled. */ isDisabled?: boolean; - /** Error message to display when the text input cannot be parsed. */ + /** Error message to display when the text input contains a non-empty value in an invalid format. */ invalidFormatText?: string; /** Callback called every time the text input loses focus. */ onBlur?: (event: any, value: string, date?: Date) => void; @@ -49,6 +57,8 @@ export interface DatePickerProps placeholder?: string; /** Props to pass to the popover that contains the calendar month component. */ popoverProps?: Partial>; + /** Options to customize the requirement of a date */ + requiredDateOptions?: DatePickerRequiredObject; /** Functions that returns an error message if a date is invalid. */ validators?: ((date: Date) => string)[]; /** Value of the text input. */ @@ -94,6 +104,7 @@ const DatePickerBase = ( onChange = (): any => undefined, onBlur = (): any => undefined, invalidFormatText = 'Invalid date', + requiredDateOptions, helperText, appendTo = 'parent', popoverProps, @@ -120,6 +131,7 @@ const DatePickerBase = ( const style = { '--pf-c-date-picker__input--c-form-control--width-chars': widthChars, ...styleProps }; const buttonRef = React.useRef(); const datePickerWrapperRef = React.useRef(); + const emptyDateText = requiredDateOptions?.emptyDateText || 'Date cannot be blank'; React.useEffect(() => { setValue(valueProp); @@ -151,17 +163,22 @@ const DatePickerBase = ( }; const onInputBlur = (event: any) => { - if (pristine) { - return; - } const newValueDate = dateParse(value); - if (isValidDate(newValueDate)) { - onBlur(event, value, new Date(newValueDate)); + const dateIsValid = isValidDate(newValueDate); + const onBlurDateArg = dateIsValid ? new Date(newValueDate) : undefined; + onBlur(event, value, onBlurDateArg); + + if (dateIsValid) { setError(newValueDate); - } else { - onBlur(event, value); + } + + if (!dateIsValid && !pristine) { setErrorText(invalidFormatText); } + + if (!dateIsValid && pristine && requiredDateOptions?.isRequired) { + setErrorText(emptyDateText); + } }; const onDateClick = (newValueDate: Date) => { @@ -235,6 +252,10 @@ const DatePickerBase = ( return false; } setPopoverOpen(false); + // If datepicker is required and the popover is opened without the text input + // first receiving focus, we want to validate that the text input is not blank upon + // closing the popover + requiredDateOptions?.isRequired && !value && setErrorText(emptyDateText); if (event.key === KeyTypes.Escape && popoverOpen) { event.stopPropagation(); } @@ -250,6 +271,7 @@ const DatePickerBase = ( ( + +);