Browse Source

feat: add Radio and RadioGroup components

next
Tom Kirkpatrick 6 years ago
parent
commit
055cd9694c
No known key found for this signature in database GPG Key ID: 72203A8EC5967EA8
  1. 88
      app/components/UI/Radio.js
  2. 3
      app/components/UI/RadioGroup.js
  3. 2
      app/components/UI/index.js
  4. 19
      stories/forms/form.stories.js
  5. 24
      test/unit/components/UI/Radio.spec.js
  6. 207
      test/unit/components/UI/__snapshots__/Radio.spec.js.snap

88
app/components/UI/Radio.js

@ -0,0 +1,88 @@
import React from 'react'
import PropTypes from 'prop-types'
import { Radio as InformedRadio } from 'informed'
import styled from 'styled-components'
import { Label, Text } from 'components/UI'
import { Box } from 'rebass'
const Wrapper = styled(Box)`
/* The container */
.container {
display: block;
position: relative;
padding-left: 30px;
cursor: pointer;
user-select: none;
}
/* Hide the browser's default radio button */
.container input {
position: absolute;
opacity: 0;
cursor: pointer;
}
/* Create a custom radio button */
.selection {
position: absolute;
top: 1px;
left: 0;
height: 16px;
width: 16px;
border: 1px solid ${props => props.theme.colors.gray};
border-radius: 50%;
}
/* On mouse-over, add an orange border color */
.container:hover input ~ .selection {
border: 1px solid ${props => props.theme.colors.lightningOrange};
}
/* When the radio button is checked, make the border orange */
.container input:checked ~ .selection {
border: 1px solid ${props => props.theme.colors.lightningOrange};
}
/* Create the indicator (the dot/circle - hidden when not checked) */
.selection:after {
content: '';
position: absolute;
display: none;
}
/* Show the indicator (dot/circle) when checked */
.container input:checked ~ .selection:after {
display: block;
}
/* Style the indicator (dot/circle) */
.container .selection:after {
top: 3px;
left: 3px;
width: 8px;
height: 8px;
border-radius: 50%;
background: ${props => props.theme.colors.lightningOrange};
}
`
const Radio = ({ value, label, description, fontWeight, onChange, onBlur, ...rest }) => (
<Wrapper>
<Label htmlFor={value} className="container" fontWeight="light" mb={3} {...rest}>
<Text>{label}</Text>
<InformedRadio value={value} id={value} onChange={onChange} onBlur={onBlur} />
<span className="selection" />
{description && (
<Text mt={2} color="gray">
{description}
</Text>
)}
</Label>
</Wrapper>
)
Radio.propTypes = {
value: PropTypes.string.isRequired,
label: PropTypes.node,
description: PropTypes.node
}
export default Radio

3
app/components/UI/RadioGroup.js

@ -0,0 +1,3 @@
import { RadioGroup } from 'informed'
export default RadioGroup

2
app/components/UI/index.js

@ -26,6 +26,8 @@ export Notification from './Notification'
export Panel, { PanelHeader, PanelBody, PanelFooter } from './Panel'
export Page from './Page'
export QRCode from './QRCode'
export Radio from './Radio'
export RadioGroup from './RadioGroup'
export Range from './Range'
export Select from './Select'
export Sidebar from './Sidebar'

19
stories/forms/form.stories.js

@ -15,6 +15,8 @@ import {
TextArea,
Button,
Toggle,
Radio,
RadioGroup,
Range
} from 'components/UI'
@ -120,6 +122,15 @@ storiesOf('Forms', module)
<Select field="fieldName" items={selectItems} />
</Form>
))
.add('Radio', () => (
<Form>
<RadioGroup field="radio">
<Radio value="item1" label="Item 1" description="Radio buttons" />
<Radio value="item2" label="Item 2" description="can have an optional title" />
<Radio value="item3" label="Item 3" description="and description" />
</RadioGroup>
</Form>
))
.add('Toggle', () => (
<Form>
<Toggle field="checkbox" />
@ -207,6 +218,14 @@ storiesOf('Forms', module)
</Box>
</Box>
<Box my={4}>
<RadioGroup field="radio">
<Radio value="item1" label="Item 1" description="Radio buttons" />
<Radio value="item2" label="Item 2" description="can have an optional title" />
<Radio value="item3" label="Item 3" description="and description" />
</RadioGroup>
</Box>
<Box my={4}>
<Box>
<Label htmlFor="checkbox1">Example Toggle</Label>

24
test/unit/components/UI/Radio.spec.js

@ -0,0 +1,24 @@
import React from 'react'
import renderer from 'react-test-renderer'
import { dark } from 'themes'
import { ThemeProvider } from 'styled-components'
import { Form, Radio, RadioGroup } from 'components/UI'
describe('component.UI.Radio', () => {
it('should render correctly', () => {
const tree = renderer
.create(
<ThemeProvider theme={dark}>
<Form>
<RadioGroup field="radio">
<Radio value="item1" label="Item 1" description="Radio buttons" />
<Radio value="item2" label="Item 2" description="can have an optional title" />
<Radio value="item3" label="Item 3" description="and description" />
</RadioGroup>
</Form>
</ThemeProvider>
)
.toJSON()
expect(tree).toMatchSnapshot()
})
})

207
test/unit/components/UI/__snapshots__/Radio.spec.js.snap

@ -0,0 +1,207 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`component.UI.Radio should render correctly 1`] = `
.c2 {
font-size: 13px;
color: #ffffff;
line-height: 1.4;
}
.c3 {
margin-top: 8px;
font-size: 13px;
color: #959595;
line-height: 1.4;
}
.c1 {
margin-bottom: 16px;
width: 100%;
font-size: 13px;
color: #ffffff;
color: #ffffff;
font-weight: 300;
display: block;
}
.c0 .container {
display: block;
position: relative;
padding-left: 30px;
cursor: pointer;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
.c0 .container input {
position: absolute;
opacity: 0;
cursor: pointer;
}
.c0 .selection {
position: absolute;
top: 1px;
left: 0;
height: 16px;
width: 16px;
border: 1px solid #959595;
border-radius: 50%;
}
.c0 .container:hover input ~ .selection {
border: 1px solid #fd9800;
}
.c0 .container input:checked ~ .selection {
border: 1px solid #fd9800;
}
.c0 .selection:after {
content: '';
position: absolute;
display: none;
}
.c0 .container input:checked ~ .selection:after {
display: block;
}
.c0 .container .selection:after {
top: 3px;
left: 3px;
width: 8px;
height: 8px;
border-radius: 50%;
background: #fd9800;
}
<form
className=""
onReset={[Function]}
onSubmit={[Function]}
>
<div
className="c0"
>
<label
className="container c1"
color="primaryText"
display="block"
fontSize="m"
fontWeight="light"
htmlFor="item1"
opacity={null}
width={1}
>
<div
className="c2"
color="primaryText"
fontSize="m"
>
Item 1
</div>
<input
checked={false}
id="item1"
onBlur={[Function]}
onChange={[Function]}
type="radio"
value="item1"
/>
<span
className="selection"
/>
<div
className="c3"
color="gray"
fontSize="m"
>
Radio buttons
</div>
</label>
</div>
<div
className="c0"
>
<label
className="container c1"
color="primaryText"
display="block"
fontSize="m"
fontWeight="light"
htmlFor="item2"
opacity={null}
width={1}
>
<div
className="c2"
color="primaryText"
fontSize="m"
>
Item 2
</div>
<input
checked={false}
id="item2"
onBlur={[Function]}
onChange={[Function]}
type="radio"
value="item2"
/>
<span
className="selection"
/>
<div
className="c3"
color="gray"
fontSize="m"
>
can have an optional title
</div>
</label>
</div>
<div
className="c0"
>
<label
className="container c1"
color="primaryText"
display="block"
fontSize="m"
fontWeight="light"
htmlFor="item3"
opacity={null}
width={1}
>
<div
className="c2"
color="primaryText"
fontSize="m"
>
Item 3
</div>
<input
checked={false}
id="item3"
onBlur={[Function]}
onChange={[Function]}
type="radio"
value="item3"
/>
<span
className="selection"
/>
<div
className="c3"
color="gray"
fontSize="m"
>
and description
</div>
</label>
</div>
</form>
`;
Loading…
Cancel
Save