Skip to content

Commit

Permalink
feat(components): add Box primitive to components library (#5665)
Browse files Browse the repository at this point in the history
  • Loading branch information
mcous authored May 13, 2020
1 parent 4efa400 commit 73614d0
Show file tree
Hide file tree
Showing 17 changed files with 504 additions and 140 deletions.
25 changes: 7 additions & 18 deletions app/src/components/SystemInfoCard/U2EAdapterInfo.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
// @flow
import * as React from 'react'
import { useSelector } from 'react-redux'
import { css } from 'styled-components'

import {
Box,
Text,
FONT_SIZE_BODY_1,
FONT_WEIGHT_SEMIBOLD,
SPACING_2,
SPACING_3,
} from '@opentrons/components'

import * as SystemInfo from '../../system-info'
Expand All @@ -25,30 +27,17 @@ export const U2EAdapterInfo = () => {
})

return (
<div
css={css`
font-size: ${FONT_SIZE_BODY_1};
padding: 1rem;
`}
>
<Box fontSize={FONT_SIZE_BODY_1} padding={SPACING_3}>
<Text
as="h3"
fontSize={FONT_SIZE_BODY_1}
fontWeight={FONT_WEIGHT_SEMIBOLD}
css={css`
margin-bottom: 0.5rem;
`}
marginBottom={SPACING_2}
>
{U2E_ADAPTER_INFORMATION}
</Text>
{driverOutdated && (
<U2EDriverWarning
css={css`
margin-bottom: 1rem;
`}
/>
)}
{driverOutdated && <U2EDriverWarning marginBottom={SPACING_3} />}
<U2EDeviceDetails device={device} />
</div>
</Box>
)
}
36 changes: 18 additions & 18 deletions app/src/components/SystemInfoCard/U2EDeviceDetails.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,16 @@
// @flow
import * as React from 'react'
import { css } from 'styled-components'
import styled from 'styled-components'

import {
Box,
Flex,
Text,
FONT_STYLE_ITALIC,
SPACING_1,
SPACING_2,
} from '@opentrons/components'

import { Flex, Text, FONT_STYLE_ITALIC } from '@opentrons/components'
import type { UsbDevice } from '../../system-info/types'

// TODO(mc, 2020-04-28): i18n
Expand All @@ -15,17 +23,9 @@ export type U2EDeviceDetailsProps = {|
device: UsbDevice | null,
|}

const MARGIN_TOP_0_5 = css`
margin-top: 0.5rem;
`

const MARGIN_BOTTOM_0_25 = css`
margin-bottom: 0.25rem;
`

const DETAIL_TEXT_STYLE = css`
const DetailText = styled.span`
min-width: 6rem;
margin-right: 0.25rem;
margin-right: ${SPACING_1};
`

const STATS: Array<{| label: string, property: $Keys<UsbDevice> |}> = [
Expand All @@ -39,20 +39,20 @@ export const U2EDeviceDetails = ({ device }: U2EDeviceDetailsProps) => (
<div>
<Text>{U2E_ADAPTER_DESCRIPTION}</Text>
{device === null ? (
<Text fontStyle={FONT_STYLE_ITALIC} css={MARGIN_TOP_0_5}>
<Text fontStyle={FONT_STYLE_ITALIC} marginTop={SPACING_2}>
{NO_ADAPTER_FOUND}
</Text>
) : (
<ul css={MARGIN_TOP_0_5}>
<Box as="ul" marginTop={SPACING_2}>
{STATS.filter(({ property }) => property in device).map(
({ label, property }) => (
<Flex as="li" key={property} css={MARGIN_BOTTOM_0_25}>
<span css={DETAIL_TEXT_STYLE}>{label}:</span>
<span css={DETAIL_TEXT_STYLE}>{device[property] ?? UNKNOWN}</span>
<Flex as="li" key={property} marginBottom={SPACING_1}>
<DetailText>{label}:</DetailText>
<DetailText>{device[property] ?? UNKNOWN}</DetailText>
</Flex>
)
)}
</ul>
</Box>
)}
</div>
)
23 changes: 23 additions & 0 deletions components/src/primitives/Box.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// @flow
import styled from 'styled-components'

import * as StyleProps from './style-props'

import type { StyledComponent } from 'styled-components'

export type BoxProps = {|
...StyleProps.ColorProps,
...StyleProps.SpacingProps,
...StyleProps.TypographyProps,
|}

/**
* Box primitive
*
* @component
*/
export const Box: StyledComponent<BoxProps, {||}, HTMLDivElement> = styled.div`
${StyleProps.colorStyles}
${StyleProps.spacingStyles}
${StyleProps.typographyStyles}
`
28 changes: 28 additions & 0 deletions components/src/primitives/Box.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
Simple Box primitive. Renders a `div` by default with various styling props for color, spacing, and typography

```js
import {
Icon,
C_DARK_GRAY,
C_WHITE,
SPACING_2,
SPACING_3,
} from '@opentrons/components'
;<Box
color={C_WHITE}
backgroundColor={C_DARK_GRAY}
paddingX={SPACING_3}
paddingY={SPACING_2}
>
hello world
</Box>
```

`<Box>` is a [StyledComponent](https://styled-components.com/docs/basics#getting-started), and accepts an `as` prop to render as any other DOM element or React component.

```js
<Box as="ul" paddingLeft={0}>
<li>hello</li>
<li>world</li>
</Box>
```
11 changes: 9 additions & 2 deletions components/src/primitives/Flex.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
// @flow
import styled from 'styled-components'

import * as StyleProps from './style-props'

import type { StyledComponent } from 'styled-components'

export const ALIGN_NORMAL = 'normal'
Expand Down Expand Up @@ -34,7 +37,9 @@ export const WRAP_REVERSE = 'wrap-reverse'
// style props are string type for flexibility, but try to use the constants
// defined above for safety
export type FlexProps = {|
color?: string,
...StyleProps.ColorProps,
...StyleProps.SpacingProps,
...StyleProps.TypographyProps,
alignItems?: string,
justifyContent?: string,
direction?: string,
Expand All @@ -52,7 +57,9 @@ export const Flex: StyledComponent<
HTMLDivElement
> = styled.div`
display: flex;
${({ color }) => (color ? `color: ${color};` : '')}
${StyleProps.colorStyles}
${StyleProps.spacingStyles}
${StyleProps.typographyStyles}
${({ alignItems: ai }) => (ai ? `align-items: ${ai};` : '')}
${({ justifyContent: jc }) => (jc ? `justify-content: ${jc};` : '')}
${({ direction: d }) => (d ? `flex-direction: ${d};` : '')}
Expand Down
20 changes: 9 additions & 11 deletions components/src/primitives/Link.js
Original file line number Diff line number Diff line change
@@ -1,31 +1,29 @@
// @flow
import * as React from 'react'
import styled from 'styled-components'

import * as StyleProps from './style-props'

import type { StyledComponent } from 'styled-components'

// props are string type for flexibility, but try to use constants for safety
export type LinkProps = {|
...StyleProps.ColorProps,
...StyleProps.TypographyProps,
...StyleProps.SpacingProps,
href: string,
external?: boolean,
color?: string,
fontSize?: string,
fontWeight?: number | string,
fontStyle?: string,
lineHeight?: number | string,
|}

// TODO(mc, 2020-05-11): move common style interpolations into common location
const StyledLink: StyledComponent<
LinkProps,
{||},
HTMLAnchorElement
> = styled.a`
text-decoration: none;
${({ fontSize }) => (fontSize ? `font-size: ${fontSize};` : '')}
${({ fontWeight }) => (fontWeight ? `font-weight: ${fontWeight};` : '')}
${({ fontStyle }) => (fontStyle ? `font-style: ${fontStyle};` : '')}
${({ lineHeight }) => (lineHeight ? `line-height: ${lineHeight};` : '')}
${({ color }) => (color ? `color: ${color};` : '')}
${StyleProps.colorStyles}
${StyleProps.typographyStyles}
${StyleProps.spacingStyles}
`

type StyledLinkProps = React.ElementProps<typeof StyledLink>
Expand Down
20 changes: 8 additions & 12 deletions components/src/primitives/Text.js
Original file line number Diff line number Diff line change
@@ -1,15 +1,13 @@
// @flow
import styled from 'styled-components'
import * as StyleProps from './style-props'

import type { StyledComponent } from 'styled-components'

// props are string type for flexibility, but try to use constants for safety
// TODO(mc, 2020-05-11): move common style interpolations into common location
export type TextProps = {|
color?: string,
fontSize?: string,
fontWeight?: number | string,
fontStyle?: string,
lineHeight?: number | string,
...StyleProps.ColorProps,
...StyleProps.TypographyProps,
...StyleProps.SpacingProps,
|}

// TODO(mc, 2020-05-08): add variants (--font-body-2-dark, etc) as variant prop
Expand All @@ -27,9 +25,7 @@ export const Text: StyledComponent<
> = styled.p`
margin-top: 0;
margin-bottom: 0;
${({ fontSize }) => (fontSize ? `font-size: ${fontSize};` : '')}
${({ fontWeight }) => (fontWeight ? `font-weight: ${fontWeight};` : '')}
${({ fontStyle }) => (fontStyle ? `font-style: ${fontStyle};` : '')}
${({ lineHeight }) => (lineHeight ? `line-height: ${lineHeight};` : '')}
${({ color }) => (color ? `color: ${color};` : '')}
${StyleProps.colorStyles}
${StyleProps.typographyStyles}
${StyleProps.spacingStyles}
`
59 changes: 59 additions & 0 deletions components/src/primitives/__tests__/Box.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
// @flow
import * as React from 'react'
import { shallow } from 'enzyme'

import {
C_WHITE,
SPACING_AUTO,
SPACING_1,
FONT_SIZE_BODY_1,
} from '../../styles'
import { Box } from '..'

describe('Box primitive component', () => {
it('should be a simple div', () => {
const wrapper = shallow(<Box />)
expect(wrapper.exists('div')).toBe(true)
})

it('should accept an `as` prop', () => {
const wrapper = shallow(<Box as="nav" />)
expect(wrapper.exists('nav')).toBe(true)
})

it('should accept an `className` prop', () => {
const wrapper = shallow(<Box className="extra-class" />)
expect(wrapper.hasClass('extra-class')).toBe(true)
})

it('should render children', () => {
const wrapper = shallow(
<Box>
<span data-test="child" />
</Box>
)
expect(wrapper.exists('[data-test="child"]')).toBe(true)
})

it('should take a color prop', () => {
const wrapper = shallow(<Box color={C_WHITE} />)
expect(wrapper).toHaveStyleRule('color', '#ffffff')
})

it('should take a backgroundColor prop', () => {
const wrapper = shallow(<Box backgroundColor={C_WHITE} />)
expect(wrapper).toHaveStyleRule('background-color', '#ffffff')
})

it('should take spacing props', () => {
const wrapper = shallow(<Box marginX={SPACING_AUTO} padding={SPACING_1} />)
expect(wrapper).toHaveStyleRule('margin-left', 'auto')
expect(wrapper).toHaveStyleRule('margin-right', 'auto')
expect(wrapper).toHaveStyleRule('padding', SPACING_1)
})

it('should take typography props', () => {
const wrapper = shallow(<Box fontSize={FONT_SIZE_BODY_1} />)
expect(wrapper).toHaveStyleRule('font-size', FONT_SIZE_BODY_1)
})
})
13 changes: 12 additions & 1 deletion components/src/primitives/__tests__/Flex.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import * as React from 'react'
import { shallow } from 'enzyme'

import { C_WHITE } from '../../styles'
import { C_WHITE, FONT_SIZE_BODY_1 } from '../../styles'
import {
Flex,
ALIGN_NORMAL,
Expand Down Expand Up @@ -146,4 +146,15 @@ describe('Flex primitive component', () => {
wrapper.setProps({ wrap: WRAP_REVERSE })
expect(wrapper).toHaveStyleRule('flex-wrap', 'wrap-reverse')
})

it('should take spacing props', () => {
const wrapper = shallow(<Flex marginBottom={0} paddingLeft={0} />)
expect(wrapper).toHaveStyleRule('margin-bottom', '0')
expect(wrapper).toHaveStyleRule('padding-left', '0')
})

it('should take typography props', () => {
const wrapper = shallow(<Flex fontSize={FONT_SIZE_BODY_1} />)
expect(wrapper).toHaveStyleRule('font-size', FONT_SIZE_BODY_1)
})
})
Loading

0 comments on commit 73614d0

Please sign in to comment.