Skip to content

Commit

Permalink
feat!: Make Summary Box more flexible (#1929)
Browse files Browse the repository at this point in the history
BREAKING CHANGE: SummaryBox now exposes sub-components (SummaryBoxHeading and SummaryBoxContent) for a more compositional API. Consumers will need to update their implementation to match.
  • Loading branch information
Isaac Garfinkle authored Apr 21, 2022
1 parent 37a3e32 commit a46ed35
Show file tree
Hide file tree
Showing 9 changed files with 234 additions and 89 deletions.
81 changes: 0 additions & 81 deletions src/components/SummaryBox/SummaryBox.test.tsx

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
/* eslint-disable jsx-a11y/anchor-is-valid */
import React from 'react'
import { SummaryBox } from './SummaryBox'
import { SummaryBoxHeading } from '../SummaryBoxHeading/SummaryBoxHeading'
import { SummaryBoxContent } from '../SummaryBoxContent/SummaryBoxContent'

export default {
title: 'Components/Summary box',
Expand Down Expand Up @@ -60,5 +62,8 @@ const summaryBoxContent = (
)

export const summaryBoxDefault = (): React.ReactElement => (
<SummaryBox heading="Key information">{summaryBoxContent}</SummaryBox>
<SummaryBox>
<SummaryBoxHeading headingLevel="h3">Key Information</SummaryBoxHeading>
<SummaryBoxContent>{summaryBoxContent}</SummaryBoxContent>
</SummaryBox>
)
87 changes: 87 additions & 0 deletions src/components/SummaryBox/SummaryBox/SummaryBox.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
/* eslint-disable jsx-a11y/anchor-is-valid */
import React from 'react'
import { render } from '@testing-library/react'
import { SummaryBox } from './SummaryBox'
import { SummaryBoxHeading } from '../SummaryBoxHeading/SummaryBoxHeading'
import { SummaryBoxContent } from '../SummaryBoxContent/SummaryBoxContent'

const testSummaryBoxContent = (
<>
<SummaryBoxHeading headingLevel="h3">My heading</SummaryBoxHeading>
<SummaryBoxContent>
<ul className="usa-list">
<li>
If you are under a winter storm warning,&nbsp;
<a className="usa-summary-box__link" href="#">
find shelter
</a>
&nbsp;right away.
</li>
<li>
Sign up for&nbsp;
<a className="usa-summary-box__link" href="#">
your community’s warning system
</a>
.
</li>
<li>
Learn the signs of, and basic treatments for,&nbsp;
<a className="usa-summary-box__link" href="#">
frostbite
</a>
&nbsp;and&nbsp;
<a className="usa-summary-box__link" href="#">
hypothermia
</a>
.
</li>
<li>
Gather emergency supplies for your&nbsp;
<a className="usa-summary-box__link" href="#">
home
</a>
&nbsp;and your&nbsp;
<a className="usa-summary-box__link" href="#">
car
</a>
.
</li>
</ul>
</SummaryBoxContent>
</>
)

const customProps = {
role: 'complementary',
className: 'custom-class-name',
}

describe('SummaryBox component', () => {
it('renders without errors', () => {
const { getByTestId } = render(
<SummaryBox>{testSummaryBoxContent}</SummaryBox>
)

expect(getByTestId('summary-box')).toBeInTheDocument()
})

it('renders passed in children', () => {
const { getAllByRole, getByRole } = render(
<SummaryBox>{testSummaryBoxContent}</SummaryBox>
)

expect(getByRole('heading')).toBeInTheDocument()
expect(getAllByRole('listitem')).toHaveLength(4)
expect(getAllByRole('link')).toHaveLength(6)
})

it('renders attributes passed in through props', () => {
const { queryByTestId } = render(
<SummaryBox {...customProps}>{testSummaryBoxContent}</SummaryBox>
)

const qByTestId = queryByTestId('summary-box')
expect(qByTestId).toHaveAttribute('role', 'complementary')
expect(qByTestId).toHaveClass('usa-summary-box custom-class-name')
})
})
Original file line number Diff line number Diff line change
Expand Up @@ -3,24 +3,19 @@ import React from 'react'
import classnames from 'classnames'

interface SummaryBoxProps {
heading: string
children?: React.ReactNode
className?: string
}

export const SummaryBox = ({
heading,
children,
className,
...divProps
}: SummaryBoxProps & JSX.IntrinsicElements['div']): React.ReactElement => {
const classes = classnames('usa-summary-box', className)
return (
<div className={classes} data-testid="summary-box" {...divProps}>
<div className="usa-summary-box__body">
<h3 className="usa-summary-box__heading">{heading}</h3>
<div className="usa-summary-box__text">{children}</div>
</div>
<div className="usa-summary-box__body">{children}</div>
</div>
)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import React from 'react'
import { render } from '@testing-library/react'
import { SummaryBoxContent } from './SummaryBoxContent'

describe('SummaryBoxContent component', () => {
it('renders without errors', () => {
const { queryByTestId } = render(
<SummaryBoxContent data-testid="collection-heading" />
)

expect(queryByTestId('collection-heading')).toBeInTheDocument()
})

it('renders children', () => {
const { queryByTestId } = render(
<SummaryBoxContent data-testid="collection-heading">
<div data-testid="test-child" />
</SummaryBoxContent>
)

expect(queryByTestId('test-child')).toBeInTheDocument()
})

it('renders custom class name', () => {
const { getByTestId } = render(
<SummaryBoxContent
data-testid="collection-heading"
className="custom-class"
/>
)

expect(getByTestId('collection-heading')).toHaveClass('custom-class')
})

it('renders custom heading attributes', () => {
const { getByTestId } = render(
<SummaryBoxContent data-testid="collection-heading" aria-label="Hello" />
)

expect(getByTestId('collection-heading')).toHaveAttribute(
'aria-label',
'Hello'
)
})
})
20 changes: 20 additions & 0 deletions src/components/SummaryBox/SummaryBoxContent/SummaryBoxContent.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import React from 'react'
import classnames from 'classnames'

interface SummaryBoxTextProps {
children?: React.ReactNode
className?: string
}

export const SummaryBoxContent = ({
children,
className,
...divProps
}: SummaryBoxTextProps & JSX.IntrinsicElements['div']): React.ReactElement => {
const classes = classnames('usa-summary-box__text', className)
return (
<div className={classes} {...divProps}>
{children}
</div>
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import React from 'react'
import { render } from '@testing-library/react'
import { SummaryBoxHeading } from './SummaryBoxHeading'

describe('SummaryBoxHeading component', () => {
it('renders without errors', () => {
const { queryByText, getByRole } = render(
<SummaryBoxHeading headingLevel="h3">test text</SummaryBoxHeading>
)

expect(getByRole('heading')).toBeInTheDocument()
expect(queryByText('test text')).toBeInTheDocument()
})

it('renders default heading level', () => {
const { getByRole } = render(
<SummaryBoxHeading headingLevel="h3">test text</SummaryBoxHeading>
)

expect(getByRole('heading').tagName).toEqual('H3')
})

it('renders custom level', () => {
const { getByRole } = render(
<SummaryBoxHeading headingLevel="h6">test text </SummaryBoxHeading>
)

expect(getByRole('heading').tagName).toEqual('H6')
})

it('renders custom class name', () => {
const { getByRole } = render(
<SummaryBoxHeading className="custom-class" headingLevel="h3">
test text{' '}
</SummaryBoxHeading>
)

expect(getByRole('heading')).toHaveClass('custom-class')
})

it('renders custom heading attributes', () => {
const { getByRole } = render(
<SummaryBoxHeading aria-label="Hello" headingLevel="h3">
test text{' '}
</SummaryBoxHeading>
)

expect(getByRole('heading')).toHaveAttribute('aria-label', 'Hello')
})
})
24 changes: 24 additions & 0 deletions src/components/SummaryBox/SummaryBoxHeading/SummaryBoxHeading.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import React, { ReactNode } from 'react'
import classnames from 'classnames'

interface SummaryBoxHeadingProps {
children: ReactNode
className?: string
headingLevel: 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6'
}

export const SummaryBoxHeading = ({
children,
className,
headingLevel,
...h3Props
}: SummaryBoxHeadingProps &
JSX.IntrinsicElements['h3']): React.ReactElement => {
const classes = classnames('usa-summary-box__heading', className)
const Heading = headingLevel
return (
<Heading className={classes} {...h3Props}>
{children}
</Heading>
)
}
2 changes: 1 addition & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ export { StepIndicatorStep } from './components/stepindicator/StepIndicatorStep/

export { Search } from './components/Search/Search'

export { SummaryBox } from './components/SummaryBox/SummaryBox'
export { SummaryBox } from './components/SummaryBox/SummaryBox/SummaryBox'

/** ProcessList components */
export { ProcessList } from './components/ProcessList/ProcessList/ProcessList'
Expand Down

0 comments on commit a46ed35

Please sign in to comment.