Skip to content

Commit

Permalink
fix(DatePicker): error not showing on date reset by button (#9267)
Browse files Browse the repository at this point in the history
* fix(DatePicker): clear error on date reset

* feat(DatePicker): add clear date example to controlled DatePicker

* test(DatePicker): add integration test for clear date

* feat(DatePicker): update clear date logic based on #9373

* fix(DatePicker): hide error when date cleared and not required + show error when cleared and required

* refactor(DatePicker)

* fix(DatePicker): prop removal
  • Loading branch information
adamviktora authored Aug 24, 2023
1 parent 3707ffb commit 4fccdaf
Show file tree
Hide file tree
Showing 6 changed files with 63 additions and 2 deletions.
7 changes: 7 additions & 0 deletions packages/react-core/src/components/DatePicker/DatePicker.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -129,11 +129,13 @@ const DatePickerBase = (
const [popoverOpen, setPopoverOpen] = React.useState(false);
const [selectOpen, setSelectOpen] = React.useState(false);
const [pristine, setPristine] = React.useState(true);
const [textInputFocused, setTextInputFocused] = React.useState(false);
const widthChars = React.useMemo(() => Math.max(dateFormat(new Date()).length, placeholder.length), [dateFormat]);

Check warning on line 133 in packages/react-core/src/components/DatePicker/DatePicker.tsx

View workflow job for this annotation

GitHub Actions / lint

React Hook React.useMemo has a missing dependency: 'placeholder.length'. Either include it or remove the dependency array
const style = { '--pf-v5-c-date-picker__input--c-form-control--width-chars': widthChars, ...styleProps };
const buttonRef = React.useRef<HTMLButtonElement>();
const datePickerWrapperRef = React.useRef<HTMLDivElement>();
const triggerRef = React.useRef<HTMLDivElement>();
const dateIsRequired = requiredDateOptions?.isRequired || false;
const emptyDateText = requiredDateOptions?.emptyDateText || 'Date cannot be blank';

React.useEffect(() => {
Expand All @@ -147,6 +149,9 @@ const DatePickerBase = (
if (errorText && isValidDate(newValueDate)) {
setError(newValueDate);
}
if (value === '' && !pristine && !textInputFocused) {
dateIsRequired ? setErrorText(emptyDateText) : setErrorText('');
}
}, [value]);

Check warning on line 155 in packages/react-core/src/components/DatePicker/DatePicker.tsx

View workflow job for this annotation

GitHub Actions / lint

React Hook React.useEffect has missing dependencies: 'dateIsRequired', 'dateParse', 'emptyDateText', 'errorText', 'pristine', 'setError', and 'textInputFocused'. Either include them or remove the dependency array. If 'dateParse' changes too often, find the parent component that defines it and wrap that definition in useCallback

const setError = (date: Date) => {
Expand All @@ -166,6 +171,7 @@ const DatePickerBase = (
};

const onInputBlur = (event: any) => {
setTextInputFocused(false);
const newValueDate = dateParse(value);
const dateIsValid = isValidDate(newValueDate);
const onBlurDateArg = dateIsValid ? new Date(newValueDate) : undefined;
Expand Down Expand Up @@ -288,6 +294,7 @@ const DatePickerBase = (
value={value}
onChange={onTextInput}
onBlur={onInputBlur}
onFocus={() => setTextInputFocused(true)}
onKeyPress={onKeyPress}
{...inputProps}
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,12 @@ The error message can be customized via the `requiredDateOptions.emptyDateText`

```

### Controlled required

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

```

### Controlling the date picker calendar state

```ts file="./DatePickerControlledCalendar.tsx"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React from 'react';
import { Button, DatePicker } from '@patternfly/react-core';
import { Button, DatePicker, Flex, FlexItem } from '@patternfly/react-core';

export const DatePickerControlled: React.FunctionComponent = () => {
const initialValue = '2020-03-17';
Expand All @@ -9,7 +9,14 @@ export const DatePickerControlled: React.FunctionComponent = () => {
<DatePicker value={value} onChange={(_event, value) => setValue(value)} />
<br />
<br />
<Button onClick={() => setValue(initialValue)}>Reset date</Button>
<Flex>
<FlexItem>
<Button onClick={() => setValue(initialValue)}>Reset date</Button>
</FlexItem>
<FlexItem>
<Button onClick={() => setValue('')}>Clear date</Button>
</FlexItem>
</Flex>
</React.Fragment>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import React from 'react';
import { Button, DatePicker, Flex, FlexItem } from '@patternfly/react-core';

export const DatePickerControlled: React.FunctionComponent = () => {
const initialValue = '2020-03-17';
const [value, setValue] = React.useState(initialValue);
return (
<React.Fragment>
<DatePicker
requiredDateOptions={{ isRequired: true, emptyDateText: 'Date is required' }}
value={value}
onChange={(_event, value) => setValue(value)}
/>
<br />
<br />
<Flex>
<FlexItem>
<Button onClick={() => setValue(initialValue)}>Reset date</Button>
</FlexItem>
<FlexItem>
<Button onClick={() => setValue('')}>Clear date</Button>
</FlexItem>
</Flex>
</React.Fragment>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,15 @@ xit('Verify validation error can be cleared from outside', () => {
cy.get('div.pf-m-error').should('not.exist');
});

it('Verify error can be cleared when resetting the date from outside', () => {
cy.get('#date-picker-clear .pf-v5-c-form-control input').click();
cy.focused().clear().type('something invalid');
cy.focused().blur();
cy.get('div.pf-m-error').should('exist');
cy.get('button').contains('Clear date').click();
cy.get('div.pf-m-error').should('not.exist');
});

it('Verify calendar state can be controlled', () => {
cy.get('#date-picker-controlled .pf-v5-c-popover').should('not.exist');
cy.get('button').contains('Toggle').click();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,12 @@ export const DatePickerDemo = () => {

return (
<>
<div id="date-picker-clear">
<DatePicker value={value} />
<div>
<button onClick={() => setValue('')}>Clear date</button>
</div>
</div>
<div id="date-picker-validator">
<DatePicker value={value} onChange={(event, value) => setValue(value)} validators={[rangeValidator]} />
<div>
Expand Down

0 comments on commit 4fccdaf

Please sign in to comment.