Skip to content

Commit

Permalink
Merge pull request #1038 from primer/VanAnderson/SubNav-TSX-migration
Browse files Browse the repository at this point in the history
Migrate SubNav component to TSX
  • Loading branch information
colebemis authored Feb 11, 2021
2 parents afd402d + 397d978 commit 97da1af
Show file tree
Hide file tree
Showing 6 changed files with 120 additions and 28 deletions.
5 changes: 5 additions & 0 deletions .changeset/popular-oranges-confess.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@primer/components": patch
---

Migrate `SubNav` to TypeScript
70 changes: 46 additions & 24 deletions src/SubNav.js → src/SubNav.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,25 +2,17 @@ import React from 'react'
import PropTypes from 'prop-types'
import classnames from 'classnames'
import styled from 'styled-components'
import {COMMON, FLEX, get} from './constants'
import {COMMON, FLEX, get, SystemFlexProps, SystemCommonProps, SystemBorderProps} from './constants'
import {ComponentProps} from './utils/types'
import theme from './theme'
import Flex from './Flex'
import sx from './sx'
import Flex, {FlexProps} from './Flex'
import sx, {SxProp} from './sx'
import * as History from 'history'

const ITEM_CLASS = 'SubNav-item'
const SELECTED_CLASS = 'selected'

function SubNavBase({actions, className, children, label, theme, ...rest}) {
const classes = classnames(className, 'SubNav')
return (
<nav className={classes} aria-label={label} {...rest}>
<div className="SubNav-body">{children}</div>
{actions && <div className="SubNav-actions">{actions}</div>}
</nav>
)
}

const SubNav = styled(SubNavBase)`
const SubNavBase = styled.nav<SystemFlexProps & SystemCommonProps & SxProp>`
display: flex;
justify-content: space-between;
Expand All @@ -46,12 +38,40 @@ const SubNav = styled(SubNavBase)`
${sx};
`

SubNav.Links = props => <Flex {...props} />
export type SubNavProps = {
actions?: React.ReactNode
align?: 'right'
full?: boolean
label?: string
} & ComponentProps<typeof SubNavBase>

function SubNav({actions, className, children, label, ...rest}: SubNavProps) {
const classes = classnames(className, 'SubNav')
return (
<SubNavBase className={classes} aria-label={label} {...rest}>
<div className="SubNav-body">{children}</div>
{actions && <div className="SubNav-actions">{actions}</div>}
</SubNavBase>
)
}

export type SubNavLinksProps = FlexProps

SubNav.Link = styled.a.attrs(props => ({
function SubNavLinks(props: SubNavLinksProps) {
return <Flex {...props} />
}

type StyledSubNavLinkProps = {
to?: History.LocationDescriptor
selected?: boolean
} & SystemCommonProps &
SxProp &
SystemBorderProps

const SubNavLink = styled.a.attrs<StyledSubNavLinkProps>(props => ({
activeClassName: typeof props.to === 'string' ? 'selected' : '',
className: classnames(ITEM_CLASS, props.selected && SELECTED_CLASS, props.className)
}))`
}))<StyledSubNavLinkProps>`
padding-left: ${get('space.3')};
padding-right: ${get('space.3')};
font-weight: ${get('fontWeights.semibold')};
Expand Down Expand Up @@ -117,22 +137,24 @@ SubNav.propTypes = {
...sx.propTypes
}

SubNav.Link.defaultProps = {
SubNavLink.defaultProps = {
theme
}

SubNav.Link.propTypes = {
as: PropTypes.oneOfType([PropTypes.string, PropTypes.elementType]),
SubNavLink.propTypes = {
href: PropTypes.string,
selected: PropTypes.bool,
...COMMON.propTypes,
...sx.propTypes
}
SubNav.Link.displayName = 'SubNav.Link'

SubNav.Links.propTypes = {
SubNavLink.displayName = 'SubNav.Link'

SubNavLinks.propTypes = {
...Flex.propTypes
}
SubNav.Links.displayName = 'SubNav.Links'

export default SubNav
SubNavLinks.displayName = 'SubNav.Links'

export type SubNavLinkProps = ComponentProps<typeof SubNavLink>
export default Object.assign(SubNav, {Link: SubNavLink, Links: SubNavLinks})
File renamed without changes.
6 changes: 2 additions & 4 deletions src/__tests__/SubNavLink.js → src/__tests__/SubNavLink.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,7 @@ describe('SubNav.Link', () => {
})

it('adds activeClassName={SELECTED_CLASS} when it gets a "to" prop', () => {
const Mock = jest.fn(() => <div />)
render(<SubNav.Link 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(<SubNav.Link as={Link} to="#" />)).toMatchSnapshot()
})
})
File renamed without changes.
Original file line number Diff line number Diff line change
@@ -1,5 +1,72 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`SubNav.Link adds activeClassName={SELECTED_CLASS} when it gets a "to" prop 1`] = `
.c0 {
padding-left: 16px;
padding-right: 16px;
font-weight: 500;
font-size: 14px;
line-height: 20px;
min-height: 34px;
color: #24292e;
text-align: center;
-webkit-text-decoration: none;
text-decoration: none;
border-top: 1px solid #e1e4e8;
border-bottom: 1px solid #e1e4e8;
border-right: 1px solid #e1e4e8;
display: -webkit-box;
display: -webkit-flex;
display: -ms-flexbox;
display: flex;
-webkit-align-items: center;
-webkit-box-align: center;
-ms-flex-align: center;
align-items: center;
}
.c0:first-of-type {
border-top-left-radius: 6px;
border-bottom-left-radius: 6px;
border-left: 1px solid #e1e4e8;
}
.c0:last-of-type {
border-top-right-radius: 6px;
border-bottom-right-radius: 6px;
}
.c0:hover,
.c0:focus {
-webkit-text-decoration: none;
text-decoration: none;
background-color: #f6f8fa;
-webkit-transition: 0.2s ease;
transition: 0.2s ease;
}
.c0:hover .SubNav-octicon,
.c0:focus .SubNav-octicon {
color: #6a737d;
}
.c0.selected {
color: #fff;
background-color: #0366d6;
border: 0;
}
.c0.selected .SubNav-octicon {
color: #6a737d;
}
<div
activeClassName="selected"
className="c0 SubNav-item"
to="#"
/>
`;

exports[`SubNav.Link renders consistently 1`] = `
.c0 {
padding-left: 16px;
Expand Down

1 comment on commit 97da1af

@vercel
Copy link

@vercel vercel bot commented on 97da1af Feb 11, 2021

Choose a reason for hiding this comment

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

Please # to comment.