diff --git a/packages/react-core/src/components/DatePicker/DatePicker.tsx b/packages/react-core/src/components/DatePicker/DatePicker.tsx index 4ab92e187dc..d360673f945 100644 --- a/packages/react-core/src/components/DatePicker/DatePicker.tsx +++ b/packages/react-core/src/components/DatePicker/DatePicker.tsx @@ -128,11 +128,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]); const style = { '--pf-v5-c-date-picker__input--c-form-control--width-chars': widthChars, ...styleProps }; const buttonRef = React.useRef(); const datePickerWrapperRef = React.useRef(); const triggerRef = React.useRef(); + const dateIsRequired = requiredDateOptions?.isRequired || false; const emptyDateText = requiredDateOptions?.emptyDateText || 'Date cannot be blank'; React.useEffect(() => { @@ -146,6 +148,9 @@ const DatePickerBase = ( if (errorText && isValidDate(newValueDate)) { setError(newValueDate); } + if (value === '' && !pristine && !textInputFocused) { + dateIsRequired ? setErrorText(emptyDateText) : setErrorText(''); + } }, [value]); const setError = (date: Date) => { @@ -165,6 +170,7 @@ const DatePickerBase = ( }; const onInputBlur = (event: any) => { + setTextInputFocused(false); const newValueDate = dateParse(value); const dateIsValid = isValidDate(newValueDate); const onBlurDateArg = dateIsValid ? new Date(newValueDate) : undefined; @@ -282,6 +288,7 @@ const DatePickerBase = ( value={value} onChange={onTextInput} onBlur={onInputBlur} + onFocus={() => setTextInputFocused(true)} onKeyPress={onKeyPress} {...inputProps} /> diff --git a/packages/react-core/src/components/DatePicker/examples/DatePicker.md b/packages/react-core/src/components/DatePicker/examples/DatePicker.md index 4d5959b29b0..0456a0bfd14 100644 --- a/packages/react-core/src/components/DatePicker/examples/DatePicker.md +++ b/packages/react-core/src/components/DatePicker/examples/DatePicker.md @@ -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" diff --git a/packages/react-core/src/components/DatePicker/examples/DatePickerControlled.tsx b/packages/react-core/src/components/DatePicker/examples/DatePickerControlled.tsx index a305b70330f..a4297e9265e 100644 --- a/packages/react-core/src/components/DatePicker/examples/DatePickerControlled.tsx +++ b/packages/react-core/src/components/DatePicker/examples/DatePickerControlled.tsx @@ -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'; @@ -9,7 +9,14 @@ export const DatePickerControlled: React.FunctionComponent = () => { setValue(value)} />

- + + + + + + + + ); }; diff --git a/packages/react-core/src/components/DatePicker/examples/DatePickerControlledRequired.tsx b/packages/react-core/src/components/DatePicker/examples/DatePickerControlledRequired.tsx new file mode 100644 index 00000000000..4ba5bf302da --- /dev/null +++ b/packages/react-core/src/components/DatePicker/examples/DatePickerControlledRequired.tsx @@ -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 ( + + setValue(value)} + /> +
+
+ + + + + + + + +
+ ); +}; diff --git a/packages/react-integration/cypress/integration/datepicker.spec.ts b/packages/react-integration/cypress/integration/datepicker.spec.ts index 53cecdfb50b..51e5f959866 100644 --- a/packages/react-integration/cypress/integration/datepicker.spec.ts +++ b/packages/react-integration/cypress/integration/datepicker.spec.ts @@ -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(); diff --git a/packages/react-integration/demo-app-ts/src/components/demos/DatePickerDemo/DatePickerDemo.tsx b/packages/react-integration/demo-app-ts/src/components/demos/DatePickerDemo/DatePickerDemo.tsx index b61f84e7898..c7eaf5a2966 100644 --- a/packages/react-integration/demo-app-ts/src/components/demos/DatePickerDemo/DatePickerDemo.tsx +++ b/packages/react-integration/demo-app-ts/src/components/demos/DatePickerDemo/DatePickerDemo.tsx @@ -14,6 +14,12 @@ export const DatePickerDemo = () => { return ( <> +
+ +
+ +
+
setValue(value)} validators={[rangeValidator]} />