Skip to content

Commit

Permalink
fix(DatePicker): updated v4 onBlur logic (#9491)
Browse files Browse the repository at this point in the history
* fix(DatePicker): updated v4 onBlur logic

* Added example
  • Loading branch information
thatblindgeye authored Aug 23, 2023
1 parent 63b1d08 commit 24beea4
Show file tree
Hide file tree
Showing 3 changed files with 49 additions and 10 deletions.
40 changes: 31 additions & 9 deletions packages/react-core/src/components/DatePicker/DatePicker.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -31,15 +39,15 @@ 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;
/** Additional props for the text input. */
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;
Expand All @@ -49,6 +57,8 @@ export interface DatePickerProps
placeholder?: string;
/** Props to pass to the popover that contains the calendar month component. */
popoverProps?: Partial<Omit<PopoverProps, 'appendTo'>>;
/** 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. */
Expand Down Expand Up @@ -94,6 +104,7 @@ const DatePickerBase = (
onChange = (): any => undefined,
onBlur = (): any => undefined,
invalidFormatText = 'Invalid date',
requiredDateOptions,
helperText,
appendTo = 'parent',
popoverProps,
Expand All @@ -120,6 +131,7 @@ const DatePickerBase = (
const style = { '--pf-c-date-picker__input--c-form-control--width-chars': widthChars, ...styleProps };
const buttonRef = React.useRef<HTMLButtonElement>();
const datePickerWrapperRef = React.useRef<HTMLDivElement>();
const emptyDateText = requiredDateOptions?.emptyDateText || 'Date cannot be blank';

React.useEffect(() => {
setValue(valueProp);
Expand Down Expand Up @@ -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) => {
Expand Down Expand Up @@ -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();
}
Expand All @@ -250,6 +271,7 @@ const DatePickerBase = (
<InputGroup>
<TextInput
isDisabled={isDisabled}
isRequired={requiredDateOptions?.isRequired}
aria-label={ariaLabel}
placeholder={placeholder}
validated={errorText.trim() ? 'error' : 'default'}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
id: Date picker
section: components
cssPrefix: pf-c-date-picker
propComponents: ['DatePicker', 'CalendarFormat', 'DatePickerRef']
propComponents: ['DatePicker', 'CalendarFormat', 'DatePickerRef', 'DatePickerRequiredObject']
beta: true
---

Expand All @@ -13,6 +13,17 @@ beta: true
```ts file="./DatePickerBasic.tsx"
```

### Required

To require users to select a date before continuing, use the `requiredDateOptions.isRequired` property.

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.

The error message can be customized via the `requiredDateOptions.emptyDateText` property.

```ts file="./DatePickerRequired.tsx"
```

### American format

```ts file="./DatePickerAmerican.tsx"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import React from 'react';
import { DatePicker } from '@patternfly/react-core';

export const DatePickerRequired: React.FunctionComponent = () => (
<DatePicker requiredDateOptions={{ isRequired: true, emptyDateText: 'Date is required' }} />
);

0 comments on commit 24beea4

Please sign in to comment.