From cdc8913e7cfedac4a99eba8dd3ca3060d1fedcb3 Mon Sep 17 00:00:00 2001 From: literat Date: Thu, 7 Sep 2023 13:57:01 +0200 Subject: [PATCH] Refactor(web-react): Introduce `ModalCloseButton` component --- .../src/components/Modal/ModalCloseButton.tsx | 14 ++++++ .../src/components/Modal/ModalHeader.tsx | 19 ++----- .../Modal/__tests__/ModalCloseButton.test.tsx | 50 +++++++++++++++++++ .../web-react/src/components/Modal/index.ts | 7 +-- packages/web-react/src/types/modal.ts | 13 +++-- 5 files changed, 80 insertions(+), 23 deletions(-) create mode 100644 packages/web-react/src/components/Modal/ModalCloseButton.tsx create mode 100644 packages/web-react/src/components/Modal/__tests__/ModalCloseButton.test.tsx diff --git a/packages/web-react/src/components/Modal/ModalCloseButton.tsx b/packages/web-react/src/components/Modal/ModalCloseButton.tsx new file mode 100644 index 0000000000..ac13400763 --- /dev/null +++ b/packages/web-react/src/components/Modal/ModalCloseButton.tsx @@ -0,0 +1,14 @@ +import React from 'react'; +import { ModalCloseButtonProps } from '../../types'; +import { Icon } from '../Icon'; +import { VisuallyHidden } from '../VisuallyHidden'; +import { Button } from '../Button'; + +const ModalCloseButton = ({ label = 'Close', onClose, id, isOpen, ...restProps }: ModalCloseButtonProps) => ( + +); + +export default ModalCloseButton; diff --git a/packages/web-react/src/components/Modal/ModalHeader.tsx b/packages/web-react/src/components/Modal/ModalHeader.tsx index b994c47593..e8f28e5f7a 100644 --- a/packages/web-react/src/components/Modal/ModalHeader.tsx +++ b/packages/web-react/src/components/Modal/ModalHeader.tsx @@ -1,10 +1,8 @@ import classNames from 'classnames'; import React from 'react'; import { useStyleProps } from '../../hooks'; -import { ClickEvent, ModalHeaderProps } from '../../types'; -import { Button } from '../Button'; -import { Icon } from '../Icon'; -import { VisuallyHidden } from '../VisuallyHidden'; +import { ModalHeaderProps } from '../../types'; +import ModalCloseButton from './ModalCloseButton'; import { useModalContext } from './ModalContext'; import { useModalStyleProps } from './useModalStyleProps'; @@ -22,18 +20,7 @@ const ModalHeader = (props: ModalHeaderProps) => { {children} )} - + ); }; diff --git a/packages/web-react/src/components/Modal/__tests__/ModalCloseButton.test.tsx b/packages/web-react/src/components/Modal/__tests__/ModalCloseButton.test.tsx new file mode 100644 index 0000000000..8181e98549 --- /dev/null +++ b/packages/web-react/src/components/Modal/__tests__/ModalCloseButton.test.tsx @@ -0,0 +1,50 @@ +import '@testing-library/jest-dom'; +import { fireEvent, render } from '@testing-library/react'; +import React from 'react'; +import { classNamePrefixProviderTest } from '../../../../tests/providerTests/classNamePrefixProviderTest'; +import { restPropsTest } from '../../../../tests/providerTests/restPropsTest'; +import { stylePropsTest } from '../../../../tests/providerTests/stylePropsTest'; +import ModalCloseButton from '../ModalCloseButton'; + +describe('ModalCloseButton', () => { + classNamePrefixProviderTest(ModalCloseButton, 'Button'); + + stylePropsTest(ModalCloseButton); + + restPropsTest(ModalCloseButton, 'button'); + + it('should have icon', () => { + const dom = render( {}} />); + + expect(dom.container.querySelector('svg')).toBeDefined(); + }); + + it('should have visually hidden label', () => { + const dom = render( {}} />); + + expect(dom.container.querySelector('button > span')?.textContent).toBe('close'); + expect(dom.container.querySelector('button > span')).toHaveClass('accessibility-hidden'); + }); + + it('should be square', () => { + const dom = render( {}} />); + + expect(dom.container.querySelector('button')).toHaveClass('Button--square'); + }); + + it('should have tertiary color', () => { + const dom = render( {}} />); + + expect(dom.container.querySelector('button')).toHaveClass('Button--tertiary'); + }); + + it('should handle on close click', () => { + const mockedOnClose = jest.fn(); + const dom = render(); + + const button = dom.getByRole('button'); + fireEvent.click(button); + + expect(mockedOnClose).toHaveBeenCalled(); + }); +}); diff --git a/packages/web-react/src/components/Modal/index.ts b/packages/web-react/src/components/Modal/index.ts index 75793a7bab..d074b7372c 100644 --- a/packages/web-react/src/components/Modal/index.ts +++ b/packages/web-react/src/components/Modal/index.ts @@ -1,7 +1,8 @@ export { default as Modal } from './Modal'; -export { default as ModalDialog } from './ModalDialog'; export { default as ModalBody } from './ModalBody'; -export { default as ModalHeader } from './ModalHeader'; -export { default as ModalFooter } from './ModalFooter'; +export { default as ModalCloseButton } from './ModalCloseButton'; export * from './ModalContext'; +export { default as ModalDialog } from './ModalDialog'; +export { default as ModalFooter } from './ModalFooter'; +export { default as ModalHeader } from './ModalHeader'; export * from './useModalStyleProps'; diff --git a/packages/web-react/src/types/modal.ts b/packages/web-react/src/types/modal.ts index d51ae3f9f8..8e55032827 100644 --- a/packages/web-react/src/types/modal.ts +++ b/packages/web-react/src/types/modal.ts @@ -1,13 +1,13 @@ -import { ElementType, ComponentPropsWithRef } from 'react'; +import { ComponentPropsWithRef, ElementType } from 'react'; import { + AlignmentXDictionaryType, ChildrenProps, ClickEvent, OmittedExtendedUnsafeStyleProps, - StyleProps, - SpiritDivElementProps, SpiritDialogElementProps, + SpiritDivElementProps, SpiritElementProps, - AlignmentXDictionaryType, + StyleProps, } from './shared'; export type ModalDialogElementType = 'article' | 'form'; @@ -17,6 +17,11 @@ export type ModalDialogHandlingProps = { onClose: (event: ClickEvent) => void; }; +export interface ModalCloseButtonProps extends ModalDialogHandlingProps { + id: string; + label: string; +} + export type ModalDialogBaseProps = { elementType?: E; isExpandedOnMobile?: boolean;