diff --git a/src/components/ProcessList/ProcessList/ProcessList.stories.tsx b/src/components/ProcessList/ProcessList/ProcessList.stories.tsx new file mode 100644 index 0000000000..f5b0a5edbe --- /dev/null +++ b/src/components/ProcessList/ProcessList/ProcessList.stories.tsx @@ -0,0 +1,116 @@ +import React from 'react' + +import { ProcessList } from './ProcessList' +import { ProcessListItem } from '../ProcessListItem/ProcessListItem' + +export default { + title: 'Components/ProcessList', + component: ProcessList, + parameters: { + docs: { + description: { + component: ` +### USWDS 2.0 ProcessList component + +Source: https://designsystem.digital.gov/components/process-list +`, + }, + }, + }, +} + +export const processListDefault = (): React.ReactElement => ( + + +

Start a process

+

+ Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Morbi commodo, + ipsum sed pharetra gravida, orci magna rhoncus neque. +

+ +
+ +

Proceed to the second step

+

+ Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Morbi commodo, + ipsum sed pharetra gravida, orci magna rhoncus neque, id pulvinar odio + lorem non turpis. Nullam sit amet enim. Suspendisse id velit vitae + ligula volutpat condimentum. Aliquam erat volutpat. Sed quis velit. + Nulla facilisi. Nulla libero. Vivamus pharetra posuere sapien. +

+
+ +

+ Complete the step-by-step process +

+

+ Nullam sit amet enim. Suspendisse id velit vitae ligula volutpat + condimentum. Aliquam erat volutpat. Sed quis velit. Nulla facilisi. + Nulla libero. Vivamus pharetra posuere sapien. +

+
+
+) + +export const processListNoTextCustomSizing = (): React.ReactElement => ( + + +

+ Start a process. +

+
+ +

+ Proceed to the second step. +

+
+ +

+ Complete the step-by-step process. +

+
+
+) + +export const processListCustomSizing = (): React.ReactElement => ( + + +

+ Start a process. +

+

+ Nullam sit amet enim. Suspendisse id velit vitae ligula volutpat + condimentum. +

+
+ +

+ Proceed to the second step. +

+

+ Suspendisse id velit vitae ligula volutpat condimentum. Aliquam erat + volutpat. +

+
+ +

+ Complete the step-by-step process. +

+

+ Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Morbi commodo, + ipsum sed pharetra gravida, orci magna rhoncus neque. +

+
+
+) diff --git a/src/components/ProcessList/ProcessList/ProcessList.test.tsx b/src/components/ProcessList/ProcessList/ProcessList.test.tsx new file mode 100644 index 0000000000..d67897dece --- /dev/null +++ b/src/components/ProcessList/ProcessList/ProcessList.test.tsx @@ -0,0 +1,56 @@ +/* eslint-disable jsx-a11y/anchor-is-valid */ +import React from 'react' +import { render } from '@testing-library/react' + +import { ProcessList } from '../ProcessList/ProcessList' +import { ProcessListItem } from '../ProcessListItem/ProcessListItem' + +const testListItems = [ +
  • some text
  • , +
  • some more text
  • , +
  • third item
  • , +] + +describe('ProcessList component', () => { + it('renders without errors', () => { + const { getAllByRole, queryByText } = render( + {testListItems} + ) + + expect(queryByText('third item')).toBeInTheDocument() + expect(getAllByRole('listitem')).toHaveLength(3) + }) + + it('accepts a class name', () => { + const { getByRole } = render( + {testListItems} + ) + + expect(getByRole('list')).toHaveClass('usa-process-list custom-class-name') + }) + + it('accepts attributes passed in as props', () => { + const { getByRole } = render( + {testListItems} + ) + + expect(getByRole('list')).toHaveAttribute('aria-label', 'Process list') + }) + + it('renders when passed ProcessListItem', () => { + const { getAllByRole } = render( + + item 1 + item 2 + + item 3 + + + + + + ) + expect(getAllByRole('list')).toHaveLength(2) + expect(getAllByRole('listitem')).toHaveLength(7) + }) +}) diff --git a/src/components/ProcessList/ProcessList/ProcessList.tsx b/src/components/ProcessList/ProcessList/ProcessList.tsx new file mode 100644 index 0000000000..c136f9c252 --- /dev/null +++ b/src/components/ProcessList/ProcessList/ProcessList.tsx @@ -0,0 +1,23 @@ +import React from 'react' +import classnames from 'classnames' +import { ProcessListItemProps } from '../ProcessListItem/ProcessListItem' + +interface ProcessListProps { + className?: string + children: React.ReactElement[] +} + +export const ProcessList = ({ + className, + children, + ...listProps +}: ProcessListProps & JSX.IntrinsicElements['ol']): React.ReactElement => { + const classes = classnames('usa-process-list', className) + return ( +
      + {children} +
    + ) +} + +export default ProcessList diff --git a/src/components/ProcessList/ProcessListItem/ProcessListItem.test.tsx b/src/components/ProcessList/ProcessListItem/ProcessListItem.test.tsx new file mode 100644 index 0000000000..ad18e5c2c9 --- /dev/null +++ b/src/components/ProcessList/ProcessListItem/ProcessListItem.test.tsx @@ -0,0 +1,74 @@ +/* eslint-disable jsx-a11y/anchor-is-valid */ +import React from 'react' +import { render } from '@testing-library/react' + +import { ProcessListItem } from './ProcessListItem' + +const testData = ( + <> +

    Start a process

    +

    + Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Morbi commodo, + ipsum sed pharetra gravida, orci magna rhoncus neque. +

    + +

    Proceed to the second step

    +

    + Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Morbi commodo, + ipsum sed pharetra gravida, orci magna rhoncus neque, id pulvinar odio + lorem non turpis. Nullam sit amet enim. Suspendisse id velit vitae ligula + volutpat condimentum. Aliquam erat volutpat. Sed quis velit. Nulla + facilisi. Nulla libero. Vivamus pharetra posuere sapien. +

    +

    + Complete the step-by-step process +

    +

    + Nullam sit amet enim. Suspendisse id velit vitae ligula volutpat + condimentum. Aliquam erat volutpat. Sed quis velit. Nulla facilisi. Nulla + libero. Vivamus pharetra posuere sapien. +

    + +) + +describe('ProcessListItem component', () => { + it('renders without errors', () => { + const { getByRole } = render(some text) + + const listItem = getByRole('listitem') + expect(listItem).toBeInTheDocument() + expect(listItem).toHaveClass('usa-process-list__item') + }) + + it('renders children passed in', () => { + const { getAllByRole } = render( + {testData} + ) + + expect(getAllByRole('listitem')).toHaveLength(4) + expect(getAllByRole('heading')).toHaveLength(3) + }) + + it('accepts a custom className', () => { + const { getByRole } = render( + + link text + + ) + + expect(getByRole('listitem')).toHaveClass( + 'usa-process-list__item custom-class-name' + ) + }) +}) diff --git a/src/components/ProcessList/ProcessListItem/ProcessListItem.tsx b/src/components/ProcessList/ProcessListItem/ProcessListItem.tsx new file mode 100644 index 0000000000..da49e3c6d9 --- /dev/null +++ b/src/components/ProcessList/ProcessListItem/ProcessListItem.tsx @@ -0,0 +1,22 @@ +import React from 'react' +import classnames from 'classnames' + +export interface ProcessListItemProps { + className?: string + children?: React.ReactNode +} + +export const ProcessListItem = ({ + className, + children, + ...liProps +}: ProcessListItemProps & JSX.IntrinsicElements['li']): React.ReactElement => { + const liClasses = classnames('usa-process-list__item', className) + return ( +
  • + {children} +
  • + ) +} + +export default ProcessListItem diff --git a/src/index.ts b/src/index.ts index 81f5072761..7eee89de33 100644 --- a/src/index.ts +++ b/src/index.ts @@ -90,6 +90,10 @@ export { StepIndicatorStep } from './components/stepindicator/StepIndicatorStep/ export { Search } from './components/Search/Search' +/** ProcessList components */ +export { ProcessList } from './components/ProcessList/ProcessList/ProcessList' +export { ProcessListItem } from './components/ProcessList/ProcessListItem/ProcessListItem' + export { SiteAlert } from './components/SiteAlert/SiteAlert' /** Truss-designed components */ diff --git a/yarn.lock b/yarn.lock index 625e21c42f..304318e108 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2527,14 +2527,14 @@ form-data "^3.0.0" "@types/node@*", "@types/node@>= 8": - version "15.0.0" - resolved "https://registry.yarnpkg.com/@types/node/-/node-15.0.0.tgz#557dd0da4a6dca1407481df3bbacae0cd6f68042" - integrity sha512-YN1d+ae2MCb4U0mMa+Zlb5lWTdpFShbAj5nmte6lel27waMMBfivrm0prC16p/Di3DyTrmerrYUT8/145HXxVw== + version "15.0.1" + resolved "https://registry.yarnpkg.com/@types/node/-/node-15.0.1.tgz#ef34dea0881028d11398be5bf4e856743e3dc35a" + integrity sha512-TMkXt0Ck1y0KKsGr9gJtWGjttxlZnnvDtphxUOSd0bfaR6Q1jle+sPvrzNR1urqYTWMinoKvjKfXUGsumaO1PA== "@types/node@^14.0.10": - version "14.14.42" - resolved "https://registry.yarnpkg.com/@types/node/-/node-14.14.42.tgz#20271ce899f35eb6cd525f500bfa8f4c9e27ecd6" - integrity sha512-88QoObqn9WYIUMRzOx92GmSHmU3JCyukC2ulEv8tFjUG9VeV2FQ/cA7VQ1gi+rB/+gBMVvzVFcTnz8RdMDVIWw== + version "14.14.43" + resolved "https://registry.yarnpkg.com/@types/node/-/node-14.14.43.tgz#26bcbb0595b305400e8ceaf9a127a7f905ae49c8" + integrity sha512-3pwDJjp1PWacPTpH0LcfhgjvurQvrZFBrC6xxjaUEZ7ifUtT32jtjPxEMMblpqd2Mvx+k8haqQJLQxolyGN/cQ== "@types/normalize-package-data@^2.4.0": version "2.4.0" @@ -3052,9 +3052,9 @@ ajv@^6.1.0, ajv@^6.10.0, ajv@^6.10.2, ajv@^6.12.2, ajv@^6.12.3, ajv@^6.12.4, ajv uri-js "^4.2.2" ajv@^8.0.1: - version "8.1.0" - resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.1.0.tgz#45d5d3d36c7cdd808930cc3e603cf6200dbeb736" - integrity sha512-B/Sk2Ix7A36fs/ZkuGLIR86EdjbgR6fsAcbx9lOP/QBSXujDNbVmIS/U4Itz5k8fPFDeVZl/zQ/gJW4Jrq6XjQ== + version "8.2.0" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.2.0.tgz#c89d3380a784ce81b2085f48811c4c101df4c602" + integrity sha512-WSNGFuyWd//XO8n/m/EaOlNLtO0yL8EXT/74LqT4khdhpZjP7lkj/kT5uwRmGitKEVp/Oj7ZUHeGfPtgHhQ5CA== dependencies: fast-deep-equal "^3.1.1" json-schema-traverse "^1.0.0" @@ -4141,9 +4141,9 @@ camelcase@^6.0.0, camelcase@^6.2.0: integrity sha512-c7wVvbw3f37nuobQNtgsgG9POC9qMbNuMQmTCqZv23b6MIz0fcYpBiOlv9gEN/hdLdnZTDQhg6e9Dq5M1vKvfg== caniuse-lite@^1.0.30001109, caniuse-lite@^1.0.30001125, caniuse-lite@^1.0.30001214: - version "1.0.30001216" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001216.tgz#47418a082a4f952d14d8964ae739e25efb2060a9" - integrity sha512-1uU+ww/n5WCJRwUcc9UH/W6925Se5aNnem/G5QaSDga2HzvjYMs8vRbekGUN/PnTZ7ezTHcxxTEb9fgiMYwH6Q== + version "1.0.30001218" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001218.tgz#9b44f6ed16f875db6373e2debd4d14a07359002f" + integrity sha512-0ASydOWSy3bB88FbDpJSTt+PfDwnMqrym3yRZfqG8EXSQ06OZhF+q5wgYP/EN+jJMERItNcDQUqMyNjzZ+r5+Q== capture-exit@^2.0.0: version "2.0.0" @@ -5577,9 +5577,9 @@ ee-first@1.1.1: integrity sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0= electron-to-chromium@^1.3.564, electron-to-chromium@^1.3.719: - version "1.3.721" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.721.tgz#3f64a0f1f58c9470ad8444caca459e996783d5d7" - integrity sha512-7nGs30ff6+KQs1Xhhih0+d6LNq2xz7O+B2aeCiCjYGiYrIIIUntJNaZhPfySw5ydPvZq5IdOdxkEgemYGOSQPw== + version "1.3.722" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.722.tgz#621657f79e7f65402e71aa3403bc941f3a4af0a0" + integrity sha512-aAsc906l0RBsVTsGTK+KirVfey9eNtxyejdkbNzkISGxb7AFna3Kf0qvsp8tMttzBt9Bz3HddtYQ+++/PZtRYA== elem-dataset@^2.0.0: version "2.0.0" @@ -13044,9 +13044,9 @@ table@^5.2.3: string-width "^3.0.0" table@^6.5.1: - version "6.5.1" - resolved "https://registry.yarnpkg.com/table/-/table-6.5.1.tgz#930885a7430f15f8766b35cd1e36de40793db523" - integrity sha512-xGDXWTBJxahkzPQCsn1S9ESHEenU7TbMD5Iv4FeopXv/XwJyWatFjfbor+6ipI10/MNPXBYUamYukOrbPZ9L/w== + version "6.6.0" + resolved "https://registry.yarnpkg.com/table/-/table-6.6.0.tgz#905654b79df98d9e9a973de1dd58682532c40e8e" + integrity sha512-iZMtp5tUvcnAdtHpZTWLPF0M7AgiQsURR2DwmxnJwSy8I3+cY+ozzVvYha3BOLG2TB+L0CqjIz+91htuj6yCXg== dependencies: ajv "^8.0.1" lodash.clonedeep "^4.5.0"