Skip to content

Commit 24beea4

Browse files
authoredAug 23, 2023
fix(DatePicker): updated v4 onBlur logic (#9491)
* fix(DatePicker): updated v4 onBlur logic * Added example

File tree

3 files changed

+49
-10
lines changed

3 files changed

+49
-10
lines changed
 

‎packages/react-core/src/components/DatePicker/DatePicker.tsx

+31-9
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,14 @@ import { useImperativeHandle } from 'react';
1111
import { KeyTypes } from '../../helpers';
1212
import { isValidDate } from '../../helpers/datetimeUtils';
1313

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+
1422
/** The main date picker component. */
1523

1624
export interface DatePickerProps
@@ -31,15 +39,15 @@ export interface DatePickerProps
3139
className?: string;
3240
/** How to format the date in the text input. */
3341
dateFormat?: (date: Date) => string;
34-
/** How to format the date in the text input. */
42+
/** How to parse the date in the text input. */
3543
dateParse?: (value: string) => Date;
3644
/** Helper text to display alongside the date picker. */
3745
helperText?: React.ReactNode;
3846
/** Additional props for the text input. */
3947
inputProps?: TextInputProps;
4048
/** Flag indicating the date picker is disabled. */
4149
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. */
4351
invalidFormatText?: string;
4452
/** Callback called every time the text input loses focus. */
4553
onBlur?: (event: any, value: string, date?: Date) => void;
@@ -49,6 +57,8 @@ export interface DatePickerProps
4957
placeholder?: string;
5058
/** Props to pass to the popover that contains the calendar month component. */
5159
popoverProps?: Partial<Omit<PopoverProps, 'appendTo'>>;
60+
/** Options to customize the requirement of a date */
61+
requiredDateOptions?: DatePickerRequiredObject;
5262
/** Functions that returns an error message if a date is invalid. */
5363
validators?: ((date: Date) => string)[];
5464
/** Value of the text input. */
@@ -94,6 +104,7 @@ const DatePickerBase = (
94104
onChange = (): any => undefined,
95105
onBlur = (): any => undefined,
96106
invalidFormatText = 'Invalid date',
107+
requiredDateOptions,
97108
helperText,
98109
appendTo = 'parent',
99110
popoverProps,
@@ -120,6 +131,7 @@ const DatePickerBase = (
120131
const style = { '--pf-c-date-picker__input--c-form-control--width-chars': widthChars, ...styleProps };
121132
const buttonRef = React.useRef<HTMLButtonElement>();
122133
const datePickerWrapperRef = React.useRef<HTMLDivElement>();
134+
const emptyDateText = requiredDateOptions?.emptyDateText || 'Date cannot be blank';
123135

124136
React.useEffect(() => {
125137
setValue(valueProp);
@@ -151,17 +163,22 @@ const DatePickerBase = (
151163
};
152164

153165
const onInputBlur = (event: any) => {
154-
if (pristine) {
155-
return;
156-
}
157166
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) {
160172
setError(newValueDate);
161-
} else {
162-
onBlur(event, value);
173+
}
174+
175+
if (!dateIsValid && !pristine) {
163176
setErrorText(invalidFormatText);
164177
}
178+
179+
if (!dateIsValid && pristine && requiredDateOptions?.isRequired) {
180+
setErrorText(emptyDateText);
181+
}
165182
};
166183

167184
const onDateClick = (newValueDate: Date) => {
@@ -235,6 +252,10 @@ const DatePickerBase = (
235252
return false;
236253
}
237254
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);
238259
if (event.key === KeyTypes.Escape && popoverOpen) {
239260
event.stopPropagation();
240261
}
@@ -250,6 +271,7 @@ const DatePickerBase = (
250271
<InputGroup>
251272
<TextInput
252273
isDisabled={isDisabled}
274+
isRequired={requiredDateOptions?.isRequired}
253275
aria-label={ariaLabel}
254276
placeholder={placeholder}
255277
validated={errorText.trim() ? 'error' : 'default'}

‎packages/react-core/src/components/DatePicker/examples/DatePicker.md

+12-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
id: Date picker
33
section: components
44
cssPrefix: pf-c-date-picker
5-
propComponents: ['DatePicker', 'CalendarFormat', 'DatePickerRef']
5+
propComponents: ['DatePicker', 'CalendarFormat', 'DatePickerRef', 'DatePickerRequiredObject']
66
beta: true
77
---
88

@@ -13,6 +13,17 @@ beta: true
1313
```ts file="./DatePickerBasic.tsx"
1414
```
1515

16+
### Required
17+
18+
To require users to select a date before continuing, use the `requiredDateOptions.isRequired` property.
19+
20+
A required date picker will be invalid when the text input is empty and either the text input loses focus or the date picker popover is closed.
21+
22+
The error message can be customized via the `requiredDateOptions.emptyDateText` property.
23+
24+
```ts file="./DatePickerRequired.tsx"
25+
```
26+
1627
### American format
1728

1829
```ts file="./DatePickerAmerican.tsx"
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
import React from 'react';
2+
import { DatePicker } from '@patternfly/react-core';
3+
4+
export const DatePickerRequired: React.FunctionComponent = () => (
5+
<DatePicker requiredDateOptions={{ isRequired: true, emptyDateText: 'Date is required' }} />
6+
);

0 commit comments

Comments
 (0)
Please sign in to comment.