diff --git a/components/Accordion/Accordion.js b/components/Accordion/Accordion.tsx similarity index 72% rename from components/Accordion/Accordion.js rename to components/Accordion/Accordion.tsx index 9b6362c7c..506a42853 100644 --- a/components/Accordion/Accordion.js +++ b/components/Accordion/Accordion.tsx @@ -1,5 +1,4 @@ import { useState } from 'react'; -import { arrayOf, bool, node, number, shape, string, oneOfType } from 'prop-types'; import classNames from 'classnames'; import Chevron from 'public/static/images/icons/FontAwesome/angle-right-solid.svg'; import { ACCORDION_CONTENT, ACCORDION_TOGGLE_BUTTON } from 'common/constants/testIDs'; @@ -10,33 +9,47 @@ import styles from './Accordion.module.css'; const ChevronRight = () => ; const ChevronDown = () => ; -Accordion.propTypes = { - /** Accessibility ID to use for joining elements together - * with ARIA attributes */ - accessibilityId: oneOfType([number, string]).isRequired, - /** Name of style class to use */ - className: string, - /** Composition of the Accordion */ - content: shape({ - /** Labels or thumbnails representing sections of content */ - headingChildren: oneOfType([node, arrayOf(node)]).isRequired, - /** Section of content associated with header */ - bodyChildren: oneOfType([node, arrayOf(node)]).isRequired, - }).isRequired, - /** Should Accordion have animation on hover */ - hasAnimationOnHover: bool, +type ContentPropType = { + /** + * Labels or thumbnails representing sections of content. + */ + headingChildren: React.ReactNode | React.ReactNode[]; + /** + * Section of content associated with header. + */ + bodyChildren: React.ReactNode | React.ReactNode[]; }; -Accordion.defaultProps = { - className: undefined, - hasAnimationOnHover: false, +export type AccordionPropsType = { + /** + * Accessibility ID to use for joining elements together with ARIA attributes + */ + accessibilityId: number | string; + /** + * Composition of the Accordion. + */ + content: ContentPropType; + /** + * Name of style class to use. + */ + className?: string; + /** + * Should Accordion have animation on hover. + * @default - false + */ + hasAnimationOnHover?: boolean; }; /** * @description A component whose main content is invisible until revealed by the user * @see http://web-accessibility.carnegiemuseums.org/code/accordions/ */ -function Accordion({ accessibilityId, className, content, hasAnimationOnHover }) { +function Accordion({ + accessibilityId, + className, + content, + hasAnimationOnHover = false, +}: AccordionPropsType) { const [isContentVisible, setContentVisibility] = useState(false); const toggleAccordionContent = () => setContentVisibility(previousState => !previousState); diff --git a/components/Accordion/__stories__/Accordion.stories.js b/components/Accordion/__stories__/Accordion.stories.js deleted file mode 100644 index 0de1a076f..000000000 --- a/components/Accordion/__stories__/Accordion.stories.js +++ /dev/null @@ -1,18 +0,0 @@ -import Accordion from '../Accordion'; - -export default { - component: Accordion, - title: 'Accordion', -}; - -const Template = arguments_ => ; - -// Default Accordion supplied with only required args -export const Default = Template.bind({}); -Default.args = { - accessibilityId: '1', - content: { - headingChildren:
Can be JSX
, - bodyChildren:

Can also be JSX

, - }, -}; diff --git a/components/Accordion/__stories__/Accordion.stories.tsx b/components/Accordion/__stories__/Accordion.stories.tsx new file mode 100644 index 000000000..7d0dab6ac --- /dev/null +++ b/components/Accordion/__stories__/Accordion.stories.tsx @@ -0,0 +1,22 @@ +import { Meta, StoryObj } from '@storybook/react'; +import Accordion from '../Accordion'; + +type AccordionStoryType = StoryObj; + +const meta: Meta = { + title: 'Accordion', + component: Accordion, + args: { + accessibilityId: '1', + content: { + headingChildren:
Can be JSX
, + bodyChildren:

Can also be JSX

, + }, + }, +}; + +export default meta; + +export const Default: AccordionStoryType = { + render: args => , +}; diff --git a/components/Accordion/__tests__/Accordion.test.js b/components/Accordion/__tests__/Accordion.test.tsx similarity index 72% rename from components/Accordion/__tests__/Accordion.test.js rename to components/Accordion/__tests__/Accordion.test.tsx index 531007d28..e5c37cbbe 100644 --- a/components/Accordion/__tests__/Accordion.test.js +++ b/components/Accordion/__tests__/Accordion.test.tsx @@ -1,20 +1,23 @@ import { fireEvent, render } from '@testing-library/react'; - +import { composeStory } from '@storybook/react'; import { ACCORDION_CONTENT, ACCORDION_TOGGLE_BUTTON, SCREEN_READER_ONLY, } from 'common/constants/testIDs'; -import { Default } from '../__stories__/Accordion.stories'; import { toggleMessages } from '../../ScreenReaderOnly/ScreenReaderOnly'; +import meta, { Default } from '../__stories__/Accordion.stories'; + +const AccordionStory = composeStory(Default, meta); describe('Accordion', () => { it('should render invisible text that turns visible on toggle click', async () => { - const component = render(); + const component = render(); const Content = component.queryByTestId(ACCORDION_CONTENT); expect(Content).not.toBeVisible(); + // @ts-expect-error fireEvent.click(component.queryByTestId(ACCORDION_TOGGLE_BUTTON)); expect(Content).toBeVisible(); @@ -23,13 +26,14 @@ describe('Accordion', () => { describe('Accordion Accessibility', () => { it('should display the correct screenReader text for toggle button', async () => { - const component = render(); + const component = render(); const Button = component.queryByTestId(SCREEN_READER_ONLY); + //@ts-expect-error expect(Button.textContent).toBe(toggleMessages.open); - + //@ts-expect-error fireEvent.click(Button); - + //@ts-expect-error expect(Button.textContent).toBe(toggleMessages.close); }); }); diff --git a/components/Alert/Alert.js b/components/Alert/Alert.tsx similarity index 69% rename from components/Alert/Alert.js rename to components/Alert/Alert.tsx index b8fa47321..e058c1195 100644 --- a/components/Alert/Alert.js +++ b/components/Alert/Alert.tsx @@ -1,24 +1,23 @@ -import { func, node, oneOf, string } from 'prop-types'; import classNames from 'classnames'; import { ALERT, ALERT_CLOSE_BUTTON } from 'common/constants/testIDs'; import ScreenReaderOnly from 'components/ScreenReaderOnly/ScreenReaderOnly'; import styles from './Alert.module.css'; -Alert.propTypes = { - children: node.isRequired, - className: string, - 'data-testid': string, - onClose: func, - type: oneOf(['error', 'success', 'warning']).isRequired, +export type AlertPropsType = { + type: 'error' | 'success' | 'warning'; + children: React.ReactNode; + className?: string; + 'data-testid'?: string; + onClose?: () => void; }; -Alert.defaultProps = { - className: undefined, - 'data-testid': ALERT, - onClose: undefined, -}; - -function Alert({ children, className, 'data-testid': testID, onClose, type }) { +function Alert({ + children, + className, + 'data-testid': testID = ALERT, + onClose, + type, +}: AlertPropsType) { return (
; - -export const ErrorAlert = Template.bind({}); -ErrorAlert.args = { - children: 'Error Alert JSX or Text', - type: 'error', -}; - -export const SuccessAlert = Template.bind({}); -SuccessAlert.args = { - children: 'Success Alert JSX or Text', - type: 'success', -}; - -export const WarningAlert = Template.bind({}); -WarningAlert.args = { - children: 'Warning Alert JSX or Text', - type: 'warning', -}; diff --git a/components/Alert/__stories__/Alert.stories.tsx b/components/Alert/__stories__/Alert.stories.tsx new file mode 100644 index 000000000..247f9a79c --- /dev/null +++ b/components/Alert/__stories__/Alert.stories.tsx @@ -0,0 +1,39 @@ +import { Meta, StoryObj } from '@storybook/react'; +import Alert from '../Alert'; + +type AlertStoryType = StoryObj; + +const meta: Meta = { + title: 'Alert', + component: Alert, +}; + +export default meta; + +const AlertStoryTemplate: AlertStoryType = { + render: args => , +}; + +export const ErrorAlert: AlertStoryType = { + ...AlertStoryTemplate, + args: { + children: 'Error Alert JSX or Text', + type: 'error', + }, +}; + +export const SuccessAlert: AlertStoryType = { + ...AlertStoryTemplate, + args: { + children: 'Success Alert JSX or Text', + type: 'success', + }, +}; + +export const WarningAlert: AlertStoryType = { + ...AlertStoryTemplate, + args: { + children: 'Warning Alert JSX or Text', + type: 'warning', + }, +}; diff --git a/components/Alert/__tests__/Alert.test.js b/components/Alert/__tests__/Alert.test.tsx similarity index 56% rename from components/Alert/__tests__/Alert.test.js rename to components/Alert/__tests__/Alert.test.tsx index 8794c3d81..2c17f9f83 100644 --- a/components/Alert/__tests__/Alert.test.js +++ b/components/Alert/__tests__/Alert.test.tsx @@ -1,28 +1,33 @@ import { fireEvent, render } from '@testing-library/react'; +import { composeStory } from '@storybook/react'; import createSnapshotTest from 'test-utils/createSnapshotTest'; import { ALERT_CLOSE_BUTTON } from 'common/constants/testIDs'; +import meta, { ErrorAlert, SuccessAlert, WarningAlert } from '../__stories__/Alert.stories'; -import { ErrorAlert, SuccessAlert, WarningAlert } from '../__stories__/Alert.stories'; +const ErrorAlertStory = composeStory(ErrorAlert, meta); +const SuccessAlertStory = composeStory(SuccessAlert, meta); +const WarningAlertStory = composeStory(WarningAlert, meta); describe('Alert', () => { it('should render error alert with required props', () => { - createSnapshotTest(); + createSnapshotTest(); }); it('should call close handler when close alert button clicked', () => { const onCloseMock = vi.fn(); - const { queryByTestId } = render(); + const { queryByTestId } = render(); expect(onCloseMock).toHaveBeenCalledTimes(0); + // @ts-expect-error fireEvent.click(queryByTestId(ALERT_CLOSE_BUTTON)); expect(onCloseMock).toHaveBeenCalledTimes(1); }); it('should NOT render button if close handler not provided', () => { - const { queryByTestId } = render(); + const { queryByTestId } = render(); expect(queryByTestId(ALERT_CLOSE_BUTTON)).toBeNull(); }); diff --git a/components/Alert/__tests__/__snapshots__/Alert.test.js.snap b/components/Alert/__tests__/__snapshots__/Alert.test.tsx.snap similarity index 100% rename from components/Alert/__tests__/__snapshots__/Alert.test.js.snap rename to components/Alert/__tests__/__snapshots__/Alert.test.tsx.snap diff --git a/components/Buttons/Button/__stories__/Button.stories.tsx b/components/Buttons/Button/__stories__/Button.stories.tsx index ebc127a89..8db7e6da1 100644 --- a/components/Buttons/Button/__stories__/Button.stories.tsx +++ b/components/Buttons/Button/__stories__/Button.stories.tsx @@ -3,13 +3,6 @@ import Button from '../Button'; type ButtonStoryType = StoryObj; -export const Default: ButtonStoryType = { - render: args =>