@@ -11,6 +11,14 @@ import { useImperativeHandle } from 'react';
11
11
import { KeyTypes } from '../../helpers' ;
12
12
import { isValidDate } from '../../helpers/datetimeUtils' ;
13
13
14
+ /** Props that customize the requirement of a date */
15
+ export interface DatePickerRequiredObject {
16
+ /** Flag indicating the date is required. */
17
+ isRequired ?: boolean ;
18
+ /** Error message to display when the text input is empty and the isRequired prop is also passed in. */
19
+ emptyDateText ?: string ;
20
+ }
21
+
14
22
/** The main date picker component. */
15
23
16
24
export interface DatePickerProps
@@ -31,15 +39,15 @@ export interface DatePickerProps
31
39
className ?: string ;
32
40
/** How to format the date in the text input. */
33
41
dateFormat ?: ( date : Date ) => string ;
34
- /** How to format the date in the text input. */
42
+ /** How to parse the date in the text input. */
35
43
dateParse ?: ( value : string ) => Date ;
36
44
/** Helper text to display alongside the date picker. */
37
45
helperText ?: React . ReactNode ;
38
46
/** Additional props for the text input. */
39
47
inputProps ?: TextInputProps ;
40
48
/** Flag indicating the date picker is disabled. */
41
49
isDisabled ?: boolean ;
42
- /** Error message to display when the text input cannot be parsed . */
50
+ /** Error message to display when the text input contains a non-empty value in an invalid format . */
43
51
invalidFormatText ?: string ;
44
52
/** Callback called every time the text input loses focus. */
45
53
onBlur ?: ( event : any , value : string , date ?: Date ) => void ;
@@ -49,6 +57,8 @@ export interface DatePickerProps
49
57
placeholder ?: string ;
50
58
/** Props to pass to the popover that contains the calendar month component. */
51
59
popoverProps ?: Partial < Omit < PopoverProps , 'appendTo' > > ;
60
+ /** Options to customize the requirement of a date */
61
+ requiredDateOptions ?: DatePickerRequiredObject ;
52
62
/** Functions that returns an error message if a date is invalid. */
53
63
validators ?: ( ( date : Date ) => string ) [ ] ;
54
64
/** Value of the text input. */
@@ -94,6 +104,7 @@ const DatePickerBase = (
94
104
onChange = ( ) : any => undefined ,
95
105
onBlur = ( ) : any => undefined ,
96
106
invalidFormatText = 'Invalid date' ,
107
+ requiredDateOptions,
97
108
helperText,
98
109
appendTo = 'parent' ,
99
110
popoverProps,
@@ -120,6 +131,7 @@ const DatePickerBase = (
120
131
const style = { '--pf-c-date-picker__input--c-form-control--width-chars' : widthChars , ...styleProps } ;
121
132
const buttonRef = React . useRef < HTMLButtonElement > ( ) ;
122
133
const datePickerWrapperRef = React . useRef < HTMLDivElement > ( ) ;
134
+ const emptyDateText = requiredDateOptions ?. emptyDateText || 'Date cannot be blank' ;
123
135
124
136
React . useEffect ( ( ) => {
125
137
setValue ( valueProp ) ;
@@ -151,17 +163,22 @@ const DatePickerBase = (
151
163
} ;
152
164
153
165
const onInputBlur = ( event : any ) => {
154
- if ( pristine ) {
155
- return ;
156
- }
157
166
const newValueDate = dateParse ( value ) ;
158
- if ( isValidDate ( newValueDate ) ) {
159
- onBlur ( event , value , new Date ( newValueDate ) ) ;
167
+ const dateIsValid = isValidDate ( newValueDate ) ;
168
+ const onBlurDateArg = dateIsValid ? new Date ( newValueDate ) : undefined ;
169
+ onBlur ( event , value , onBlurDateArg ) ;
170
+
171
+ if ( dateIsValid ) {
160
172
setError ( newValueDate ) ;
161
- } else {
162
- onBlur ( event , value ) ;
173
+ }
174
+
175
+ if ( ! dateIsValid && ! pristine ) {
163
176
setErrorText ( invalidFormatText ) ;
164
177
}
178
+
179
+ if ( ! dateIsValid && pristine && requiredDateOptions ?. isRequired ) {
180
+ setErrorText ( emptyDateText ) ;
181
+ }
165
182
} ;
166
183
167
184
const onDateClick = ( newValueDate : Date ) => {
@@ -235,6 +252,10 @@ const DatePickerBase = (
235
252
return false ;
236
253
}
237
254
setPopoverOpen ( false ) ;
255
+ // If datepicker is required and the popover is opened without the text input
256
+ // first receiving focus, we want to validate that the text input is not blank upon
257
+ // closing the popover
258
+ requiredDateOptions ?. isRequired && ! value && setErrorText ( emptyDateText ) ;
238
259
if ( event . key === KeyTypes . Escape && popoverOpen ) {
239
260
event . stopPropagation ( ) ;
240
261
}
@@ -250,6 +271,7 @@ const DatePickerBase = (
250
271
< InputGroup >
251
272
< TextInput
252
273
isDisabled = { isDisabled }
274
+ isRequired = { requiredDateOptions ?. isRequired }
253
275
aria-label = { ariaLabel }
254
276
placeholder = { placeholder }
255
277
validated = { errorText . trim ( ) ? 'error' : 'default' }
0 commit comments