diff --git a/packages/react-aria-components/src/DateField.tsx b/packages/react-aria-components/src/DateField.tsx index df81cb40008..8108cde8cb6 100644 --- a/packages/react-aria-components/src/DateField.tsx +++ b/packages/react-aria-components/src/DateField.tsx @@ -92,7 +92,7 @@ export const DateField = /*#__PURE__*/ (forwardRef as forwardRefType)(function D + data-invalid={state.isInvalid || undefined} + data-disabled={state.isDisabled || undefined} /> ); }); @@ -157,7 +158,7 @@ export const TimeField = /*#__PURE__*/ (forwardRef as forwardRefType)(function T + data-invalid={state.isInvalid || undefined} + data-disabled={state.isDisabled || undefined} /> ); }); @@ -241,7 +243,7 @@ const DateInputStandalone = forwardRef((props: DateInputProps, ref: ForwardedRef values={[ [DateFieldStateContext, state], [InputContext, {...inputProps, ref: inputRef}], - [GroupContext, {...fieldProps, ref: fieldRef, isInvalid: state.isInvalid}] + [GroupContext, {...fieldProps, ref: fieldRef, isInvalid: state.isInvalid, isDisabled: state.isDisabled}] ]}> @@ -261,7 +263,8 @@ const DateInputInner = forwardRef((props: DateInputProps, ref: ForwardedRef + isInvalid={state.isInvalid} + isDisabled={state.isDisabled}> {state.segments.map((segment, i) => cloneElement(children(segment), {key: i}))} diff --git a/packages/react-aria-components/test/DateField.test.js b/packages/react-aria-components/test/DateField.test.js index 6f467435f4b..42605d43d64 100644 --- a/packages/react-aria-components/test/DateField.test.js +++ b/packages/react-aria-components/test/DateField.test.js @@ -179,11 +179,18 @@ describe('DateField', () => { it('should support render props', () => { let {getByRole} = render( - - {({isInvalid}) => ( + + {({isInvalid, isDisabled}) => ( <> - + {segment => } @@ -286,6 +293,81 @@ describe('DateField', () => { expect(group).not.toHaveAttribute('data-invalid'); }); + it('should support both invalid and disabled states simultaneously', () => { + let {getByRole} = render( + + + + `${isInvalid ? 'invalid' : ''} ${isDisabled ? 'disabled' : ''}` + }> + {segment => } + + + ); + let group = getByRole('group'); + expect(group).toHaveAttribute('data-invalid'); + expect(group).toHaveAttribute('data-disabled'); + expect(group).toHaveClass('invalid'); + expect(group).toHaveClass('disabled'); + }); + + it('should use controlled disabled state', async () => { + function ControlledDisabledTest() { + let [isDisabled, setIsDisabled] = React.useState(false); + return ( + <> + + + isDisabled ? 'disabled' : ''}> + {segment => } + + + + + ); + } + let {getByRole} = render(); + let group = getByRole('group'); + expect(group).not.toHaveAttribute('data-disabled'); + expect(group).not.toHaveClass('disabled'); + + let button = getByRole('button'); + await userEvent.click(button); + + expect(group).toHaveAttribute('data-disabled'); + expect(group).toHaveClass('disabled'); + }); + + it('should not validate on submit when disabled', async () => { + let onSubmit = jest.fn(); + let {getByRole} = render( +
{ + e.preventDefault(); + onSubmit(); + }}> + + + + {segment => } + + + + +
+ ); + + let submitButton = getByRole('button'); + await userEvent.click(submitButton); + + let group = getByRole('group'); + expect(group).not.toHaveAttribute('data-invalid'); + expect(group).toHaveAttribute('data-disabled'); + expect(onSubmit).toHaveBeenCalled(); + }); + it('should focus previous segment when backspacing on an empty date segment', async () => { let {getAllByRole} = render(