Skip to content

Commit

Permalink
feat(components): add Flex and Text primitives to components library (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
mcous authored May 11, 2020
1 parent 7b0cf77 commit b1b318e
Show file tree
Hide file tree
Showing 21 changed files with 693 additions and 167 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import * as React from 'react'
import { Form } from 'formik'
import styled, { css } from 'styled-components'

import { FS_BODY_1, BUTTON_TYPE_SUBMIT } from '@opentrons/components'
import { FONT_SIZE_BODY_1, BUTTON_TYPE_SUBMIT } from '@opentrons/components'
import { ScrollableAlertModal } from '../../../modals'
import { TextField } from './TextField'
import { KeyFileField } from './KeyFileField'
Expand All @@ -30,7 +30,7 @@ const StyledForm: StyledComponent<
{||},
typeof Form
> = styled(Form)`
${FS_BODY_1}
font-size: ${FONT_SIZE_BODY_1};
display: table;
width: 80%;
margin-top: 0.5rem;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// presentational components for the wifi connect form
import * as React from 'react'
import styled from 'styled-components'
import { FW_SEMIBOLD } from '@opentrons/components'
import { FONT_WEIGHT_SEMIBOLD } from '@opentrons/components'

import type { StyledComponent } from 'styled-components'

Expand All @@ -20,7 +20,7 @@ const StyledLabel: StyledComponent<{||}, {||}, HTMLLabelElement> = styled.label`
display: table-cell;
padding-right: 1rem;
text-align: right;
${FW_SEMIBOLD}
font-weight: ${FONT_WEIGHT_SEMIBOLD};
`

const StyledInputWrapper: StyledComponent<
Expand Down
4 changes: 3 additions & 1 deletion babel.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@ module.exports = {
},
test: {
plugins: [
'babel-plugin-styled-components',
// NOTE(mc, 2020-05-08): disable ssr, displayName to fix toHaveStyleRule
// https://github.com/styled-components/jest-styled-components/issues/294
['babel-plugin-styled-components', { ssr: false, displayName: false }],
'@babel/plugin-transform-modules-commonjs',
'babel-plugin-dynamic-import-node',
],
Expand Down
4 changes: 2 additions & 2 deletions components/src/controls/ControlSection.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import * as React from 'react'
import styled from 'styled-components'

import { FONT_BODY_1_DARK, FW_SEMIBOLD } from '../styles'
import { FONT_BODY_1_DARK, FONT_WEIGHT_SEMIBOLD } from '../styles'

import type { StyledComponent } from 'styled-components'

Expand All @@ -20,7 +20,7 @@ const SectionWrapper: StyledComponent<{||}, {||}, HTMLDivElement> = styled.div`
`

const SectionTitle: StyledComponent<{||}, {||}, HTMLElement> = styled.p`
${FW_SEMIBOLD}
font-weight: ${FONT_WEIGHT_SEMIBOLD};
margin-bottom: 0.5rem;
`

Expand Down
1 change: 1 addition & 0 deletions components/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ export * from './interaction-enhancers'
export * from './lists'
export * from './modals'
export * from './nav'
export * from './primitives'
export * from './tabbedNav'
export * from './slotmap'
export * from './structure'
Expand Down
60 changes: 60 additions & 0 deletions components/src/primitives/Flex.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
// @flow
import styled from 'styled-components'
import type { StyledComponent } from 'styled-components'

export const ALIGN_NORMAL = 'normal'
export const ALIGN_START = 'start'
export const ALIGN_END = 'end'
export const ALIGN_FLEX_START = 'flex-start'
export const ALIGN_FLEX_END = 'flex-end'
export const ALIGN_CENTER = 'center'
export const ALIGN_BASELINE = 'baseline'
export const ALIGN_STRETCH = 'stretch'

export const JUSTIFY_NORMAL = 'normal'
export const JUSTIFY_START = 'start'
export const JUSTIFY_END = 'end'
export const JUSTIFY_FLEX_START = 'flex-start'
export const JUSTIFY_FLEX_END = 'flex-end'
export const JUSTIFY_CENTER = 'center'
export const JUSTIFY_SPACE_BETWEEN = 'space-between'
export const JUSTIFY_SPACE_AROUND = 'space-around'
export const JUSTIFY_SPACE_EVENLY = 'space-evenly'
export const JUSTIFY_STRETCH = 'stretch'

export const DIRECTION_ROW = 'row'
export const DIRECTION_ROW_REVERSE = 'row-reverse'
export const DIRECTION_COLUMN = 'column'
export const DIRECTION_COLUMN_REVERSE = 'column-reverse'

export const WRAP = 'wrap'
export const NO_WRAP = 'nowrap'
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,
alignItems?: string,
justifyContent?: string,
direction?: string,
wrap?: string,
|}

/**
* Flexbox primitive
*
* @component
*/
export const Flex: StyledComponent<
FlexProps,
{||},
HTMLDivElement
> = styled.div`
display: flex;
${({ color }) => (color ? `color: ${color};` : '')}
${({ alignItems: ai }) => (ai ? `align-items: ${ai};` : '')}
${({ justifyContent: jc }) => (jc ? `justify-content: ${jc};` : '')}
${({ direction: d }) => (d ? `flex-direction: ${d};` : '')}
${({ wrap }) => (wrap ? `flex-wrap: ${wrap};` : '')}
`
22 changes: 22 additions & 0 deletions components/src/primitives/Flex.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
Flexbox primitive. Renders a `div` by default with `display: flex;`

```js
import { Icon, ALIGN_CENTER, JUSTIFY_CENTER } from '@opentrons/components'
;<Flex
alignItems={ALIGN_CENTER}
justifyContent={JUSTIFY_CENTER}
style={{ width: '6rem', height: '6rem' }}
>
<Icon name="ot-logo" width="32" height="32" />
</Flex>
```

`<Flex>` 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
import { DIRECTION_COLUMN } from '@opentrons/components'
;<Flex as="ul" direction={DIRECTION_COLUMN}>
<li>hello</li>
<li>world</li>
</Flex>
```
30 changes: 30 additions & 0 deletions components/src/primitives/Text.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
// @flow
import styled from 'styled-components'
import type { StyledComponent } from 'styled-components'

// props are string type for flexibility, but try to use constants for safety
export type TextProps = {|
color?: string,
fontSize?: string,
fontWeight?: string,
fontStyle?: string,
lineHeight?: string,
|}

// TODO(mc, 2020-05-08): add variants (--font-body-2-dark, etc) as variant prop
// or as components that compose the base Text component

/**
* Text primitive
*
* @component
*/
export const Text: StyledComponent<TextProps, {||}, HTMLElement> = 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};` : '')}
`
24 changes: 24 additions & 0 deletions components/src/primitives/Text.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
Text primitive. Renders a `p` by default with `margin-top: 0; margin-bottom: 0;`

```js
import { FONT_SIZE_BODY_2 } from '@opentrons/components'
;<Text fontSize={FONT_SIZE_BODY_2}>hello world</Text>
```

`<Text>` 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
import {
FONT_SIZE_HEADER,
LINE_HEIGHT_TITLE,
FONT_WEIGHT_REGULAR,
} from '@opentrons/components'
;<Text
as="h3"
lineHeight={LINE_HEIGHT_TITLE}
fontSize={FONT_SIZE_HEADER}
fontWeight={FONT_WEIGHT_REGULAR}
>
hello h3
</Text>
```
149 changes: 149 additions & 0 deletions components/src/primitives/__tests__/Flex.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
// @flow
import * as React from 'react'
import { shallow } from 'enzyme'

import { C_WHITE } from '../../styles'
import {
Flex,
ALIGN_NORMAL,
ALIGN_START,
ALIGN_END,
ALIGN_FLEX_START,
ALIGN_FLEX_END,
ALIGN_CENTER,
ALIGN_BASELINE,
ALIGN_STRETCH,
JUSTIFY_NORMAL,
JUSTIFY_START,
JUSTIFY_END,
JUSTIFY_FLEX_START,
JUSTIFY_FLEX_END,
JUSTIFY_CENTER,
JUSTIFY_SPACE_BETWEEN,
JUSTIFY_SPACE_AROUND,
JUSTIFY_SPACE_EVENLY,
JUSTIFY_STRETCH,
DIRECTION_ROW,
DIRECTION_ROW_REVERSE,
DIRECTION_COLUMN,
DIRECTION_COLUMN_REVERSE,
WRAP,
NO_WRAP,
WRAP_REVERSE,
} from '..'

describe('Flex primitive component', () => {
it('should be a div with display: flex', () => {
const wrapper = shallow(<Flex />)
expect(wrapper.exists('div')).toBe(true)
expect(wrapper).toHaveStyleRule('display', 'flex')
})

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

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

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

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

it('should take an alignItems prop', () => {
const wrapper = shallow(<Flex alignItems={ALIGN_NORMAL} />)
expect(wrapper).toHaveStyleRule('align-items', 'normal')

wrapper.setProps({ alignItems: ALIGN_START })
expect(wrapper).toHaveStyleRule('align-items', 'start')

wrapper.setProps({ alignItems: ALIGN_END })
expect(wrapper).toHaveStyleRule('align-items', 'end')

wrapper.setProps({ alignItems: ALIGN_FLEX_START })
expect(wrapper).toHaveStyleRule('align-items', 'flex-start')

wrapper.setProps({ alignItems: ALIGN_FLEX_END })
expect(wrapper).toHaveStyleRule('align-items', 'flex-end')

wrapper.setProps({ alignItems: ALIGN_CENTER })
expect(wrapper).toHaveStyleRule('align-items', 'center')

wrapper.setProps({ alignItems: ALIGN_BASELINE })
expect(wrapper).toHaveStyleRule('align-items', 'baseline')

wrapper.setProps({ alignItems: ALIGN_STRETCH })
expect(wrapper).toHaveStyleRule('align-items', 'stretch')
})

it('should take a justifyContent prop', () => {
const wrapper = shallow(<Flex justifyContent={JUSTIFY_NORMAL} />)
expect(wrapper).toHaveStyleRule('justify-content', 'normal')

wrapper.setProps({ justifyContent: JUSTIFY_START })
expect(wrapper).toHaveStyleRule('justify-content', 'start')

wrapper.setProps({ justifyContent: JUSTIFY_END })
expect(wrapper).toHaveStyleRule('justify-content', 'end')

wrapper.setProps({ justifyContent: JUSTIFY_FLEX_START })
expect(wrapper).toHaveStyleRule('justify-content', 'flex-start')

wrapper.setProps({ justifyContent: JUSTIFY_FLEX_END })
expect(wrapper).toHaveStyleRule('justify-content', 'flex-end')

wrapper.setProps({ justifyContent: JUSTIFY_CENTER })
expect(wrapper).toHaveStyleRule('justify-content', 'center')

wrapper.setProps({ justifyContent: JUSTIFY_SPACE_BETWEEN })
expect(wrapper).toHaveStyleRule('justify-content', 'space-between')

wrapper.setProps({ justifyContent: JUSTIFY_SPACE_AROUND })
expect(wrapper).toHaveStyleRule('justify-content', 'space-around')

wrapper.setProps({ justifyContent: JUSTIFY_SPACE_EVENLY })
expect(wrapper).toHaveStyleRule('justify-content', 'space-evenly')

wrapper.setProps({ justifyContent: JUSTIFY_STRETCH })
expect(wrapper).toHaveStyleRule('justify-content', 'stretch')
})

it('should take a direction prop', () => {
const wrapper = shallow(<Flex direction={DIRECTION_ROW} />)
expect(wrapper).toHaveStyleRule('flex-direction', 'row')

wrapper.setProps({ direction: DIRECTION_ROW_REVERSE })
expect(wrapper).toHaveStyleRule('flex-direction', 'row-reverse')

wrapper.setProps({ direction: DIRECTION_COLUMN })
expect(wrapper).toHaveStyleRule('flex-direction', 'column')

wrapper.setProps({ direction: DIRECTION_COLUMN_REVERSE })
expect(wrapper).toHaveStyleRule('flex-direction', 'column-reverse')
})

it('should take a wrap prop', () => {
const wrapper = shallow(<Flex wrap={WRAP} />)
expect(wrapper).toHaveStyleRule('flex-wrap', 'wrap')

wrapper.setProps({ wrap: NO_WRAP })
expect(wrapper).toHaveStyleRule('flex-wrap', 'nowrap')

wrapper.setProps({ wrap: WRAP_REVERSE })
expect(wrapper).toHaveStyleRule('flex-wrap', 'wrap-reverse')
})
})
Loading

0 comments on commit b1b318e

Please sign in to comment.