diff --git a/.changeset/proud-lamps-marry.md b/.changeset/proud-lamps-marry.md new file mode 100644 index 00000000000..35a587ef6d7 --- /dev/null +++ b/.changeset/proud-lamps-marry.md @@ -0,0 +1,5 @@ +--- +"@primer/components": patch +--- + +Migrate `Breadcrumb` to TypeScript diff --git a/src/Breadcrumb.js b/src/Breadcrumb.tsx similarity index 61% rename from src/Breadcrumb.js rename to src/Breadcrumb.tsx index 8c6d0263d32..0edbf8a80e2 100644 --- a/src/Breadcrumb.js +++ b/src/Breadcrumb.tsx @@ -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' @@ -30,31 +32,39 @@ const Wrapper = styled.li` } ` -const BreadcrumbBase = ({className, children, theme, ...rest}) => { +const BreadcrumbBase = styled.nav` + display: flex; + justify-content: space-between; + ${COMMON}; + ${FLEX}; + ${sx}; +` + +export type BreadcrumbProps = ComponentProps + +function Breadcrumb({className, children, theme, ...rest}: React.PropsWithChildren) { const classes = classnames(className, 'Breadcrumb') const wrappedChildren = React.Children.map(children, child => {child}) return ( - + ) } -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(props => ({ activeClassName: typeof props.to === 'string' ? 'selected' : '', className: classnames(props.selected && SELECTED_CLASS, props.className), 'aria-current': props.selected ? 'page' : null -}))` +}))` color: ${get('colors.blue.5')}; display: inline-block; font-size: ${get('fontSizes.1')}; @@ -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 +export default Object.assign(Breadcrumb, {Item: BreadcrumbItem}) diff --git a/src/__tests__/Breadcrumb.js b/src/__tests__/Breadcrumb.tsx similarity index 100% rename from src/__tests__/Breadcrumb.js rename to src/__tests__/Breadcrumb.tsx diff --git a/src/__tests__/BreadcrumbItem.js b/src/__tests__/BreadcrumbItem.tsx similarity index 70% rename from src/__tests__/BreadcrumbItem.js rename to src/__tests__/BreadcrumbItem.tsx index 76bbfa62221..0630d5efb70 100644 --- a/src/__tests__/BreadcrumbItem.js +++ b/src/__tests__/BreadcrumbItem.tsx @@ -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', () => { @@ -26,9 +26,7 @@ describe('Breadcrumb.Item', () => { }) it('adds activeClassName={SELECTED_CLASS} when it gets a "to" prop', () => { - const Mock = jest.fn(() =>
) - render() - expect(Mock.mock.calls[0][0].to).toEqual('#') - expect(Mock.mock.calls[0][0].activeClassName).toEqual('selected') + const Link = ({theme, ...props}: any) =>
+ expect(render()).toMatchSnapshot() }) }) diff --git a/src/__tests__/__snapshots__/Breadcrumb.js.snap b/src/__tests__/__snapshots__/Breadcrumb.tsx.snap similarity index 100% rename from src/__tests__/__snapshots__/Breadcrumb.js.snap rename to src/__tests__/__snapshots__/Breadcrumb.tsx.snap diff --git a/src/__tests__/__snapshots__/BreadcrumbItem.js.snap b/src/__tests__/__snapshots__/BreadcrumbItem.tsx.snap similarity index 64% rename from src/__tests__/__snapshots__/BreadcrumbItem.js.snap rename to src/__tests__/__snapshots__/BreadcrumbItem.tsx.snap index c25b60f5693..467b10d0148 100644 --- a/src/__tests__/__snapshots__/BreadcrumbItem.js.snap +++ b/src/__tests__/__snapshots__/BreadcrumbItem.tsx.snap @@ -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; +} + +
+`; + exports[`Breadcrumb.Item renders consistently 1`] = ` .c0 { color: #0366d6;