Skip to content

Commit

Permalink
Merge pull request #1012 from primer/cb/ts-breadcrumb
Browse files Browse the repository at this point in the history
Migrate Breadcrumb to TypeScript
  • Loading branch information
colebemis authored Feb 4, 2021
2 parents f8a30cc + 00c579a commit f78c828
Show file tree
Hide file tree
Showing 6 changed files with 70 additions and 30 deletions.
5 changes: 5 additions & 0 deletions .changeset/proud-lamps-marry.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@primer/components": patch
---

Migrate `Breadcrumb` to TypeScript
54 changes: 32 additions & 22 deletions src/Breadcrumb.js → src/Breadcrumb.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import React from 'react'
import PropTypes from 'prop-types'
import classnames from 'classnames'
import * as History from 'history'
import PropTypes from 'prop-types'
import React from 'react'
import styled from 'styled-components'
import sx from './sx'
import {COMMON, FLEX, get} from './constants'
import theme from './theme'
import Box from './Box'
import {COMMON, FLEX, get, SystemCommonProps, SystemFlexProps} from './constants'
import sx, {SxProp} from './sx'
import theme from './theme'
import {ComponentProps} from './utils/types'

const SELECTED_CLASS = 'selected'

Expand All @@ -30,31 +32,39 @@ const Wrapper = styled.li`
}
`

const BreadcrumbBase = ({className, children, theme, ...rest}) => {
const BreadcrumbBase = styled.nav<SystemFlexProps & SystemCommonProps & SxProp>`
display: flex;
justify-content: space-between;
${COMMON};
${FLEX};
${sx};
`

export type BreadcrumbProps = ComponentProps<typeof BreadcrumbBase>

function Breadcrumb({className, children, theme, ...rest}: React.PropsWithChildren<BreadcrumbProps>) {
const classes = classnames(className, 'Breadcrumb')
const wrappedChildren = React.Children.map(children, child => <Wrapper theme={theme}>{child}</Wrapper>)
return (
<nav className={classes} aria-label="breadcrumb" {...rest}>
<BreadcrumbBase className={classes} aria-label="breadcrumb" theme={theme} {...rest}>
<Box as="ol" my={0} pl={0}>
{wrappedChildren}
</Box>
</nav>
</BreadcrumbBase>
)
}

const Breadcrumb = styled(BreadcrumbBase)`
display: flex;
justify-content: space-between;
${COMMON};
${FLEX};
${sx};
`
type StyledBreadcrumbItemProps = {
to?: History.LocationDescriptor
selected?: boolean
} & SystemCommonProps &
SxProp

Breadcrumb.Item = styled.a.attrs(props => ({
const BreadcrumbItem = styled.a.attrs<StyledBreadcrumbItemProps>(props => ({
activeClassName: typeof props.to === 'string' ? 'selected' : '',
className: classnames(props.selected && SELECTED_CLASS, props.className),
'aria-current': props.selected ? 'page' : null
}))`
}))<StyledBreadcrumbItemProps>`
color: ${get('colors.blue.5')};
display: inline-block;
font-size: ${get('fontSizes.1')};
Expand All @@ -81,18 +91,18 @@ Breadcrumb.propTypes = {

Breadcrumb.displayName = 'Breadcrumb'

Breadcrumb.Item.defaultProps = {
BreadcrumbItem.defaultProps = {
theme
}

Breadcrumb.Item.propTypes = {
as: PropTypes.oneOfType([PropTypes.string, PropTypes.elementType]),
BreadcrumbItem.propTypes = {
href: PropTypes.string,
selected: PropTypes.bool,
...sx.propTypes,
...COMMON.propTypes
}

Breadcrumb.Item.displayName = 'Breadcrumb.Item'
BreadcrumbItem.displayName = 'Breadcrumb.Item'

export default Breadcrumb
export type BreadcrumbItemProps = ComponentProps<typeof BreadcrumbItem>
export default Object.assign(Breadcrumb, {Item: BreadcrumbItem})
File renamed without changes.
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import {cleanup, render as HTMLRender} from '@testing-library/react'
import 'babel-polyfill'
import {axe, toHaveNoViolations} from 'jest-axe'
import React from 'react'
import {Breadcrumb} from '..'
import {render, behavesAsComponent} from '../utils/testing'
import {COMMON} from '../constants'
import {render as HTMLRender, cleanup} from '@testing-library/react'
import {axe, toHaveNoViolations} from 'jest-axe'
import 'babel-polyfill'
import {behavesAsComponent, render} from '../utils/testing'
expect.extend(toHaveNoViolations)

describe('Breadcrumb.Item', () => {
Expand All @@ -26,9 +26,7 @@ describe('Breadcrumb.Item', () => {
})

it('adds activeClassName={SELECTED_CLASS} when it gets a "to" prop', () => {
const Mock = jest.fn(() => <div />)
render(<Breadcrumb.Item as={Mock} to="#" />)
expect(Mock.mock.calls[0][0].to).toEqual('#')
expect(Mock.mock.calls[0][0].activeClassName).toEqual('selected')
const Link = ({theme, ...props}: any) => <div {...props} />
expect(render(<Breadcrumb.Item as={Link} to="#" />)).toMatchSnapshot()
})
})
Original file line number Diff line number Diff line change
@@ -1,5 +1,32 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`Breadcrumb.Item adds activeClassName={SELECTED_CLASS} when it gets a "to" prop 1`] = `
.c0 {
color: #0366d6;
display: inline-block;
font-size: 14px;
-webkit-text-decoration: none;
text-decoration: none;
}
.c0:hover {
-webkit-text-decoration: underline;
text-decoration: underline;
}
.c0.selected {
color: #444d56;
pointer-events: none;
}
<div
activeClassName="selected"
aria-current={null}
className="c0"
to="#"
/>
`;

exports[`Breadcrumb.Item renders consistently 1`] = `
.c0 {
color: #0366d6;
Expand Down

1 comment on commit f78c828

@vercel
Copy link

@vercel vercel bot commented on f78c828 Feb 4, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.