Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(components): add Flex and Text primitives to components library #5637

Merged
merged 1 commit into from
May 11, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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