21 changed files with 1224 additions and 2 deletions
@ -0,0 +1,43 @@ |
|||||
|
import React from 'react' |
||||
|
import PropTypes from 'prop-types' |
||||
|
import { Box, Flex } from 'rebass' |
||||
|
import SystemSuccess from 'components/Icon/SystemSuccess' |
||||
|
import SystemWarning from 'components/Icon/SystemWarning' |
||||
|
import SystemError from 'components/Icon/SystemError' |
||||
|
|
||||
|
import styled from 'styled-components' |
||||
|
import { variant } from 'styled-system' |
||||
|
|
||||
|
const messageStyle = variant({ key: 'messages' }) |
||||
|
const Message = styled(Flex)(messageStyle) |
||||
|
|
||||
|
/** |
||||
|
* @render react |
||||
|
* @name FormFieldMessage |
||||
|
* @example |
||||
|
* <FormFieldMessage message="Error message" /> |
||||
|
*/ |
||||
|
class FormFieldMessage extends React.Component { |
||||
|
static displayName = 'FormFieldMessage' |
||||
|
|
||||
|
static propTypes = { |
||||
|
variant: PropTypes.string, |
||||
|
children: PropTypes.node |
||||
|
} |
||||
|
|
||||
|
render() { |
||||
|
const { children, variant } = this.props |
||||
|
return ( |
||||
|
<Message {...this.props} variant={variant}> |
||||
|
<Box mr={1}> |
||||
|
{variant === 'success' && <SystemSuccess />} |
||||
|
{variant === 'warning' && <SystemWarning />} |
||||
|
{variant === 'error' && <SystemError />} |
||||
|
</Box> |
||||
|
{children} |
||||
|
</Message> |
||||
|
) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
export default FormFieldMessage |
@ -0,0 +1,90 @@ |
|||||
|
import React from 'react' |
||||
|
import { asField } from 'informed' |
||||
|
import { Input as Base } from 'styled-system-html' |
||||
|
import { withTheme } from 'styled-components' |
||||
|
import { Flex } from 'rebass' |
||||
|
import FormFieldMessage from 'components/UI/FormFieldMessage' |
||||
|
|
||||
|
/** |
||||
|
* @render react |
||||
|
* @name Input |
||||
|
* @example |
||||
|
* <Input /> |
||||
|
*/ |
||||
|
class Input extends React.PureComponent { |
||||
|
static displayName = 'Input' |
||||
|
|
||||
|
render() { |
||||
|
const { |
||||
|
onChange, |
||||
|
onBlur, |
||||
|
initialValue, |
||||
|
field, |
||||
|
forwardedRef, |
||||
|
theme, |
||||
|
fieldApi, |
||||
|
fieldState, |
||||
|
justifyContent, |
||||
|
...rest |
||||
|
} = this.props |
||||
|
const { setValue, setTouched } = fieldApi |
||||
|
const { value } = fieldState |
||||
|
|
||||
|
let borderColor |
||||
|
|
||||
|
if (fieldState.touched) { |
||||
|
if (fieldState.error) { |
||||
|
borderColor = theme.colors.superRed |
||||
|
} else if (value && !fieldState.error) { |
||||
|
borderColor = theme.colors.superGreen |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
return ( |
||||
|
<Flex flexDirection="column" justifyContent={justifyContent}> |
||||
|
<Base |
||||
|
outline="none" |
||||
|
borderRadius="5px" |
||||
|
borderColor={borderColor || theme.colors.white} |
||||
|
border="1px solid white" |
||||
|
bg="transparent" |
||||
|
color="white" |
||||
|
p={3} |
||||
|
type="text" |
||||
|
fontSize="m" |
||||
|
width={1} |
||||
|
css={{ |
||||
|
'&:focus': { |
||||
|
outline: 'none', |
||||
|
border: `1px solid ${borderColor || theme.colors.lightningOrange} }` |
||||
|
} |
||||
|
}} |
||||
|
{...rest} |
||||
|
value={!value && value !== 0 ? '' : value} |
||||
|
name={field} |
||||
|
ref={forwardedRef} |
||||
|
onChange={e => { |
||||
|
setValue(e.target.value) |
||||
|
if (onChange) { |
||||
|
onChange(e) |
||||
|
} |
||||
|
}} |
||||
|
onBlur={e => { |
||||
|
setTouched() |
||||
|
if (onBlur) { |
||||
|
onBlur(e) |
||||
|
} |
||||
|
}} |
||||
|
error={fieldState.error} |
||||
|
/> |
||||
|
{fieldState.error && ( |
||||
|
<FormFieldMessage variant="error" justifyContent={justifyContent}> |
||||
|
{fieldState.error} |
||||
|
</FormFieldMessage> |
||||
|
)} |
||||
|
</Flex> |
||||
|
) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
export default asField(withTheme(Input)) |
@ -0,0 +1,20 @@ |
|||||
|
import React from 'react' |
||||
|
import { Label as Base } from 'styled-system-html' |
||||
|
|
||||
|
/** |
||||
|
* @render react |
||||
|
* @name Label |
||||
|
* @example |
||||
|
* <Label /> |
||||
|
*/ |
||||
|
class Label extends React.Component { |
||||
|
static displayName = 'Label' |
||||
|
|
||||
|
render() { |
||||
|
return ( |
||||
|
<Base css={{ display: 'block' }} color="white" fontWeight="bold" mb={1} {...this.props} /> |
||||
|
) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
export default Label |
@ -0,0 +1,57 @@ |
|||||
|
import React from 'react' |
||||
|
import { asField } from 'informed' |
||||
|
import styled, { withTheme } from 'styled-components' |
||||
|
|
||||
|
const Input = styled.input` |
||||
|
overflow: hidden; |
||||
|
width: 100%; |
||||
|
appearance: none; |
||||
|
outline: none; |
||||
|
|
||||
|
::-webkit-slider-runnable-track { |
||||
|
height: 8px; |
||||
|
appearance: none; |
||||
|
background-color: ${props => props.theme.colors.gray}; |
||||
|
margin-top: -1px; |
||||
|
} |
||||
|
|
||||
|
::-webkit-slider-thumb { |
||||
|
width: 8px; |
||||
|
appearance: none; |
||||
|
height: 8px; |
||||
|
cursor: ew-resize; |
||||
|
background: ${props => props.theme.colors.white}; |
||||
|
box-shadow: -1000px 0 0 1000px orange; |
||||
|
} |
||||
|
` |
||||
|
|
||||
|
const Range = asField(({ fieldState, fieldApi, ...props }) => { |
||||
|
const { value } = fieldState |
||||
|
const { setValue, setTouched } = fieldApi |
||||
|
const { onChange, onBlur, initialValue, forwardedRef, ...rest } = props |
||||
|
return ( |
||||
|
<Input |
||||
|
{...rest} |
||||
|
type="range" |
||||
|
min={0} |
||||
|
max={100} |
||||
|
step={1} |
||||
|
ref={forwardedRef} |
||||
|
value={value || initialValue || '0'} |
||||
|
onChange={e => { |
||||
|
setValue(e.target.value) |
||||
|
if (onChange) { |
||||
|
onChange(e) |
||||
|
} |
||||
|
}} |
||||
|
onBlur={e => { |
||||
|
setTouched() |
||||
|
if (onBlur) { |
||||
|
onBlur(e) |
||||
|
} |
||||
|
}} |
||||
|
/> |
||||
|
) |
||||
|
}) |
||||
|
|
||||
|
export default withTheme(Range) |
@ -0,0 +1,156 @@ |
|||||
|
import React from 'react' |
||||
|
import PropTypes from 'prop-types' |
||||
|
import { asField } from 'informed' |
||||
|
import Input from 'components/UI/Input' |
||||
|
import styled, { withTheme } from 'styled-components' |
||||
|
import Downshift from 'downshift' |
||||
|
import { Box } from 'rebass' |
||||
|
import system from '@rebass/components' |
||||
|
|
||||
|
const SelectOptionList = styled.ul` |
||||
|
padding: 0; |
||||
|
margin-top: 0; |
||||
|
position: absolute; |
||||
|
z-index: 2; |
||||
|
width: 100%; |
||||
|
max-height: 20rem; |
||||
|
overflow-y: auto; |
||||
|
overflow-x: hidden; |
||||
|
outline: 0; |
||||
|
transition: opacity 0.1s ease; |
||||
|
border: ${props => (props.isOpen ? null : 'none')}; |
||||
|
background-color: ${props => props.theme.colors.lightestBackground}; |
||||
|
` |
||||
|
|
||||
|
const SelectOptionItem = styled( |
||||
|
system( |
||||
|
{ |
||||
|
extend: Box, |
||||
|
as: 'li', |
||||
|
p: 3, |
||||
|
backgroundColor: 'lightestBackground' |
||||
|
}, |
||||
|
'space', |
||||
|
'color' |
||||
|
) |
||||
|
)` |
||||
|
outline: none; |
||||
|
cursor: pointer; |
||||
|
` |
||||
|
|
||||
|
const ControllerButton = styled('button')({ |
||||
|
backgroundColor: 'transparent', |
||||
|
border: 'none', |
||||
|
position: 'absolute', |
||||
|
right: '5px', |
||||
|
top: 0, |
||||
|
cursor: 'pointer', |
||||
|
width: '47px', |
||||
|
display: 'flex', |
||||
|
flexDirection: 'column', |
||||
|
height: '50px', |
||||
|
justifyContent: 'center', |
||||
|
alignItems: 'center', |
||||
|
outline: 'none' |
||||
|
}) |
||||
|
|
||||
|
const ArrowIcon = ({ isOpen }) => ( |
||||
|
<svg |
||||
|
viewBox="0 0 20 20" |
||||
|
preserveAspectRatio="none" |
||||
|
width={16} |
||||
|
fill="transparent" |
||||
|
stroke="#979797" |
||||
|
strokeWidth="1.1px" |
||||
|
transform={isOpen ? 'rotate(180)' : null} |
||||
|
> |
||||
|
<path d="M1,6 L10,15 L19,6" /> |
||||
|
</svg> |
||||
|
) |
||||
|
ArrowIcon.propTypes = { |
||||
|
isOpen: PropTypes.bool |
||||
|
} |
||||
|
|
||||
|
const itemToString = item => (item ? item.value : '') |
||||
|
|
||||
|
/** |
||||
|
* @render react |
||||
|
* @name Select |
||||
|
*/ |
||||
|
class Select extends React.PureComponent { |
||||
|
static displayName = 'Select' |
||||
|
|
||||
|
static defaultProps = { |
||||
|
items: [] |
||||
|
} |
||||
|
|
||||
|
render() { |
||||
|
const { fieldApi, items, theme, ...rest } = this.props |
||||
|
return ( |
||||
|
<Downshift |
||||
|
itemToString={itemToString} |
||||
|
// When an item is selected, set the item in the Informed form state.
|
||||
|
onSelect={item => fieldApi.setValue(item.value)} |
||||
|
// If an invalid value has been typed into the input, set it back to the currently slected item.
|
||||
|
onInputValueChange={(inputValue, stateAndHelpers) => { |
||||
|
if (inputValue && inputValue !== itemToString(stateAndHelpers.selectedItem)) { |
||||
|
fieldApi.setValue(itemToString(stateAndHelpers.selectedItem)) |
||||
|
} |
||||
|
}} |
||||
|
> |
||||
|
{({ |
||||
|
getInputProps, |
||||
|
getItemProps, |
||||
|
getMenuProps, |
||||
|
getToggleButtonProps, |
||||
|
isOpen, |
||||
|
highlightedIndex, |
||||
|
selectedItem, |
||||
|
openMenu, |
||||
|
closeMenu, |
||||
|
toggleMenu |
||||
|
}) => ( |
||||
|
<div style={{ position: 'relative' }}> |
||||
|
<div style={{ position: 'relative' }}> |
||||
|
<ControllerButton {...getToggleButtonProps()}> |
||||
|
<ArrowIcon isOpen={isOpen} /> |
||||
|
</ControllerButton> |
||||
|
<Input |
||||
|
placeholder="Please select" |
||||
|
{...rest} |
||||
|
{...getInputProps({ |
||||
|
onBlur: closeMenu, |
||||
|
onFocus: openMenu, |
||||
|
onMouseDown: toggleMenu |
||||
|
})} |
||||
|
/> |
||||
|
</div> |
||||
|
<SelectOptionList {...getMenuProps()}> |
||||
|
{isOpen |
||||
|
? items.map((item, index) => ( |
||||
|
<SelectOptionItem |
||||
|
key="" |
||||
|
{...getItemProps({ |
||||
|
key: item.value, |
||||
|
index, |
||||
|
item |
||||
|
})} |
||||
|
style={{ |
||||
|
backgroundColor: |
||||
|
highlightedIndex === index ? theme.colors.lightningOrange : null, |
||||
|
fontWeight: selectedItem === item ? 'bold' : 'normal' |
||||
|
}} |
||||
|
> |
||||
|
{item.label || item.value} |
||||
|
</SelectOptionItem> |
||||
|
)) |
||||
|
: null} |
||||
|
</SelectOptionList> |
||||
|
</div> |
||||
|
)} |
||||
|
</Downshift> |
||||
|
) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
export default withTheme(asField(Select)) |
@ -0,0 +1,86 @@ |
|||||
|
import React from 'react' |
||||
|
import { asField } from 'informed' |
||||
|
import { TextArea as Base } from 'styled-system-html' |
||||
|
import { withTheme } from 'styled-components' |
||||
|
import { Flex } from 'rebass' |
||||
|
import FormFieldMessage from 'components/UI/FormFieldMessage' |
||||
|
|
||||
|
/** |
||||
|
* @render react |
||||
|
* @name TextArea |
||||
|
* @example |
||||
|
* <TextArea /> |
||||
|
*/ |
||||
|
class TextArea extends React.PureComponent { |
||||
|
static displayName = 'TextArea' |
||||
|
|
||||
|
render() { |
||||
|
const { |
||||
|
onChange, |
||||
|
onBlur, |
||||
|
initialValue, |
||||
|
forwardedRef, |
||||
|
theme, |
||||
|
fieldApi, |
||||
|
fieldState, |
||||
|
justifyContent, |
||||
|
...rest |
||||
|
} = this.props |
||||
|
const { setValue, setTouched } = fieldApi |
||||
|
const { value } = fieldState |
||||
|
|
||||
|
let borderColor |
||||
|
if (fieldState.error) { |
||||
|
borderColor = theme.colors.superRed |
||||
|
} else if (value && !fieldState.error) { |
||||
|
borderColor = theme.colors.superGreen |
||||
|
} |
||||
|
|
||||
|
return ( |
||||
|
<Flex flexDirection="column" justifyContent={justifyContent}> |
||||
|
<Base |
||||
|
outline="none" |
||||
|
borderRadius="5px" |
||||
|
borderColor={borderColor || theme.colors.white} |
||||
|
border="1px solid white" |
||||
|
bg="transparent" |
||||
|
color="white" |
||||
|
p={3} |
||||
|
type="text" |
||||
|
fontSize="m" |
||||
|
width={1} |
||||
|
rows="5" |
||||
|
css={{ |
||||
|
'&:focus': { |
||||
|
outline: 'none', |
||||
|
border: `1px solid ${borderColor || theme.colors.lightningOrange} }` |
||||
|
} |
||||
|
}} |
||||
|
{...rest} |
||||
|
ref={forwardedRef} |
||||
|
value={!value && value !== 0 ? '' : value} |
||||
|
onChange={e => { |
||||
|
setValue(e.target.value) |
||||
|
if (onChange) { |
||||
|
onChange(e) |
||||
|
} |
||||
|
}} |
||||
|
onBlur={e => { |
||||
|
setTouched() |
||||
|
if (onBlur) { |
||||
|
onBlur(e) |
||||
|
} |
||||
|
}} |
||||
|
error={fieldState.error} |
||||
|
/> |
||||
|
{fieldState.error && ( |
||||
|
<FormFieldMessage variant="error" justifyContent={justifyContent}> |
||||
|
{fieldState.error} |
||||
|
</FormFieldMessage> |
||||
|
)} |
||||
|
</Flex> |
||||
|
) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
export default asField(withTheme(TextArea)) |
@ -0,0 +1,70 @@ |
|||||
|
import React from 'react' |
||||
|
import styled from 'styled-components' |
||||
|
import { Checkbox, asField } from 'informed' |
||||
|
|
||||
|
const Wrapper = styled.div` |
||||
|
position: relative; |
||||
|
|
||||
|
.switch { |
||||
|
position: relative; |
||||
|
display: inline-block; |
||||
|
width: 35px; |
||||
|
height: 22px; |
||||
|
} |
||||
|
|
||||
|
.switch input { |
||||
|
opacity: 0; |
||||
|
width: 0; |
||||
|
height: 0; |
||||
|
} |
||||
|
|
||||
|
.slider { |
||||
|
position: absolute; |
||||
|
cursor: pointer; |
||||
|
top: 0; |
||||
|
left: 0; |
||||
|
right: 0; |
||||
|
bottom: 0; |
||||
|
background-color: ${props => props.theme.colors.gray}; |
||||
|
transition: 0.4s; |
||||
|
border-radius: 34px; |
||||
|
} |
||||
|
|
||||
|
.slider:before { |
||||
|
position: absolute; |
||||
|
content: ''; |
||||
|
height: 20px; |
||||
|
width: 20px; |
||||
|
left: 1px; |
||||
|
bottom: 1px; |
||||
|
background-color: white; |
||||
|
transition: 0.4s; |
||||
|
border-radius: 50%; |
||||
|
box-shadow: 1px 1px 3px ${props => props.theme.colors.invisibleGray}; |
||||
|
} |
||||
|
|
||||
|
input:checked + .slider { |
||||
|
background-color: ${props => props.theme.colors.superGreen}; |
||||
|
} |
||||
|
|
||||
|
input:focus + .slider { |
||||
|
box-shadow: 0 0 1px #2196f3; |
||||
|
} |
||||
|
|
||||
|
input:checked + .slider:before { |
||||
|
transform: translateX(13px); |
||||
|
} |
||||
|
` |
||||
|
|
||||
|
const Toggle = ({ fieldState, ...props }) => ( |
||||
|
<Wrapper> |
||||
|
<label // eslint-disable-line jsx-a11y/label-has-for,jsx-a11y/label-has-associated-control
|
||||
|
className="switch" |
||||
|
> |
||||
|
<Checkbox type="checkbox" fieldState={fieldState} {...props} /> |
||||
|
<span className="slider round" /> |
||||
|
</label> |
||||
|
</Wrapper> |
||||
|
) |
||||
|
|
||||
|
export default asField(Toggle) |
@ -0,0 +1,140 @@ |
|||||
|
import React from 'react' |
||||
|
import { storiesOf } from '@storybook/react' |
||||
|
import { action } from '@storybook/addon-actions' |
||||
|
import { Box } from 'rebass' |
||||
|
import Page from 'components/UI/Page' |
||||
|
import MainContent from 'components/UI/MainContent' |
||||
|
import Input from 'components/UI/Input' |
||||
|
import Label from 'components/UI/Label' |
||||
|
import Select from 'components/UI/Select' |
||||
|
import TextArea from 'components/UI/TextArea' |
||||
|
import Button from 'components/UI/Button' |
||||
|
import Toggle from 'components/UI/Toggle' |
||||
|
import Range from 'components/UI/Range' |
||||
|
import { Form } from 'informed' |
||||
|
|
||||
|
const validate = value => { |
||||
|
return !value || value.length < 5 ? 'Field must be at least five characters' : null |
||||
|
} |
||||
|
|
||||
|
const selectItems = [ |
||||
|
{ label: '- Please select -', value: '' }, |
||||
|
{ label: 'Apple', value: 'apple' }, |
||||
|
{ value: 'pear' }, |
||||
|
{ value: 'orange' }, |
||||
|
{ value: 'grape' }, |
||||
|
{ value: 'banana' } |
||||
|
] |
||||
|
|
||||
|
storiesOf('Components.Form', module) |
||||
|
.add('Input', () => ( |
||||
|
<Form> |
||||
|
<Input field="fieldName" id="field-name" /> |
||||
|
</Form> |
||||
|
)) |
||||
|
.add('Label', () => ( |
||||
|
<Form> |
||||
|
<Label htmlFor="id">Label</Label> |
||||
|
</Form> |
||||
|
)) |
||||
|
.add('TextArea', () => ( |
||||
|
<Form> |
||||
|
<TextArea field="fieldName" placeholder="Type here" /> |
||||
|
</Form> |
||||
|
)) |
||||
|
.add('Select', () => ( |
||||
|
<Form> |
||||
|
<Select field="fieldName" items={selectItems} /> |
||||
|
</Form> |
||||
|
)) |
||||
|
.add('Toggle', () => ( |
||||
|
<Form> |
||||
|
<Toggle field="checkbox" /> |
||||
|
</Form> |
||||
|
)) |
||||
|
.add('Range', () => ( |
||||
|
<Form> |
||||
|
<Range field="range" /> |
||||
|
</Form> |
||||
|
)) |
||||
|
.add('Example form', () => ( |
||||
|
<Page> |
||||
|
<MainContent> |
||||
|
<Form> |
||||
|
{({ formState }) => ( |
||||
|
<React.Fragment> |
||||
|
<Box mb={3}> |
||||
|
<Box> |
||||
|
<Label htmlFor="input1">Example Field</Label> |
||||
|
</Box> |
||||
|
<Box> |
||||
|
<Input |
||||
|
field="input1" |
||||
|
id="field-name" |
||||
|
placeholder="Type here" |
||||
|
validate={validate} |
||||
|
validateOnBlur |
||||
|
/> |
||||
|
</Box> |
||||
|
</Box> |
||||
|
|
||||
|
<Box mb={3}> |
||||
|
<Box> |
||||
|
<Label htmlFor="textarea1">Example Textarea</Label> |
||||
|
</Box> |
||||
|
<Box> |
||||
|
<TextArea |
||||
|
field="textarea1" |
||||
|
placeholder="Type here" |
||||
|
validate={validate} |
||||
|
validateOnBlur |
||||
|
/> |
||||
|
</Box> |
||||
|
</Box> |
||||
|
|
||||
|
<Box mb={3}> |
||||
|
<Box> |
||||
|
<Label htmlFor="selectfield1">Example Select</Label> |
||||
|
</Box> |
||||
|
<Box> |
||||
|
<Select |
||||
|
field="selectfield1" |
||||
|
items={selectItems} |
||||
|
onChange={action('change')} |
||||
|
validate={validate} |
||||
|
validateOnBlur |
||||
|
/> |
||||
|
</Box> |
||||
|
</Box> |
||||
|
|
||||
|
<Box mb={3}> |
||||
|
<Box> |
||||
|
<Label htmlFor="checkbox1">Example Toggle</Label> |
||||
|
</Box> |
||||
|
<Box> |
||||
|
<Toggle field="checkbox1" onChange={action('change')} /> |
||||
|
</Box> |
||||
|
</Box> |
||||
|
|
||||
|
<Box mb={3}> |
||||
|
<Box> |
||||
|
<Label htmlFor="slider1">Example Range</Label> |
||||
|
</Box> |
||||
|
<Box> |
||||
|
<Range field="slider1" onChange={action('change')} /> |
||||
|
</Box> |
||||
|
</Box> |
||||
|
|
||||
|
<Box mb={3}> |
||||
|
<Button>Submit</Button> |
||||
|
</Box> |
||||
|
|
||||
|
<Box bg="lightestBackground"> |
||||
|
<pre>{JSON.stringify(formState, null, 2)}</pre> |
||||
|
</Box> |
||||
|
</React.Fragment> |
||||
|
)} |
||||
|
</Form> |
||||
|
</MainContent> |
||||
|
</Page> |
||||
|
)) |
@ -0,0 +1,21 @@ |
|||||
|
import React from 'react' |
||||
|
import { Form } from 'informed' |
||||
|
import Input from 'components/UI/Input' |
||||
|
import renderer from 'react-test-renderer' |
||||
|
import { dark } from 'themes' |
||||
|
import { ThemeProvider } from 'styled-components' |
||||
|
|
||||
|
describe('component.UI.Input', () => { |
||||
|
it('should render correctly', () => { |
||||
|
const tree = renderer |
||||
|
.create( |
||||
|
<ThemeProvider theme={dark}> |
||||
|
<Form> |
||||
|
<Input field="name" theme={dark} /> |
||||
|
</Form> |
||||
|
</ThemeProvider> |
||||
|
) |
||||
|
.toJSON() |
||||
|
expect(tree).toMatchSnapshot() |
||||
|
}) |
||||
|
}) |
@ -0,0 +1,21 @@ |
|||||
|
import React from 'react' |
||||
|
import { Form } from 'informed' |
||||
|
import Range from 'components/UI/Range' |
||||
|
import renderer from 'react-test-renderer' |
||||
|
import { dark } from 'themes' |
||||
|
import { ThemeProvider } from 'styled-components' |
||||
|
|
||||
|
describe('component.UI.Range', () => { |
||||
|
it('should render correctly', () => { |
||||
|
const tree = renderer |
||||
|
.create( |
||||
|
<ThemeProvider theme={dark}> |
||||
|
<Form> |
||||
|
<Range field="name" /> |
||||
|
</Form> |
||||
|
</ThemeProvider> |
||||
|
) |
||||
|
.toJSON() |
||||
|
expect(tree).toMatchSnapshot() |
||||
|
}) |
||||
|
}) |
@ -0,0 +1,29 @@ |
|||||
|
import React from 'react' |
||||
|
import { Form } from 'informed' |
||||
|
import Select from 'components/UI/Select' |
||||
|
import renderer from 'react-test-renderer' |
||||
|
import { dark } from 'themes' |
||||
|
import { ThemeProvider } from 'styled-components' |
||||
|
|
||||
|
describe('component.UI.Toggle', () => { |
||||
|
it('should render correctly', () => { |
||||
|
const selectItems = [ |
||||
|
{ label: '- Please select -', value: '' }, |
||||
|
{ label: 'Apple', value: 'apple' }, |
||||
|
{ value: 'pear' }, |
||||
|
{ value: 'orange' }, |
||||
|
{ value: 'grape' }, |
||||
|
{ value: 'banana' } |
||||
|
] |
||||
|
const tree = renderer |
||||
|
.create( |
||||
|
<ThemeProvider theme={dark}> |
||||
|
<Form> |
||||
|
<Select field="name" items={selectItems} /> |
||||
|
</Form> |
||||
|
</ThemeProvider> |
||||
|
) |
||||
|
.toJSON() |
||||
|
expect(tree).toMatchSnapshot() |
||||
|
}) |
||||
|
}) |
@ -0,0 +1,21 @@ |
|||||
|
import React from 'react' |
||||
|
import { Form } from 'informed' |
||||
|
import Input from 'components/UI/Input' |
||||
|
import renderer from 'react-test-renderer' |
||||
|
import { dark } from 'themes' |
||||
|
import { ThemeProvider } from 'styled-components' |
||||
|
|
||||
|
describe('component.UI.Input', () => { |
||||
|
it('should render correctly', () => { |
||||
|
const tree = renderer |
||||
|
.create( |
||||
|
<ThemeProvider theme={dark}> |
||||
|
<Form> |
||||
|
<Input field="name" /> |
||||
|
</Form> |
||||
|
</ThemeProvider> |
||||
|
) |
||||
|
.toJSON() |
||||
|
expect(tree).toMatchSnapshot() |
||||
|
}) |
||||
|
}) |
@ -0,0 +1,21 @@ |
|||||
|
import React from 'react' |
||||
|
import { Form } from 'informed' |
||||
|
import Toggle from 'components/UI/Toggle' |
||||
|
import renderer from 'react-test-renderer' |
||||
|
import { dark } from 'themes' |
||||
|
import { ThemeProvider } from 'styled-components' |
||||
|
|
||||
|
describe('component.UI.Toggle', () => { |
||||
|
it('should render correctly', () => { |
||||
|
const tree = renderer |
||||
|
.create( |
||||
|
<ThemeProvider theme={dark}> |
||||
|
<Form> |
||||
|
<Toggle field="name" /> |
||||
|
</Form> |
||||
|
</ThemeProvider> |
||||
|
) |
||||
|
.toJSON() |
||||
|
expect(tree).toMatchSnapshot() |
||||
|
}) |
||||
|
}) |
@ -0,0 +1,51 @@ |
|||||
|
// Jest Snapshot v1, https://goo.gl/fbAQLP |
||||
|
|
||||
|
exports[`component.UI.Input should render correctly 1`] = ` |
||||
|
.c1 { |
||||
|
padding: 16px; |
||||
|
width: 100%; |
||||
|
font-size: 13px; |
||||
|
color: #ffffff; |
||||
|
background-color: transparent; |
||||
|
color: #ffffff; |
||||
|
background-color: transparent; |
||||
|
border: 1px solid white; |
||||
|
border: 1px solid white; |
||||
|
border-color: #ffffff; |
||||
|
border-radius: 5px; |
||||
|
} |
||||
|
|
||||
|
.c1:focus { |
||||
|
outline: none; |
||||
|
border: 1px solid #fd9800; |
||||
|
} |
||||
|
|
||||
|
.c0 { |
||||
|
display: -webkit-box; |
||||
|
display: -webkit-flex; |
||||
|
display: -ms-flexbox; |
||||
|
display: flex; |
||||
|
-webkit-flex-direction: column; |
||||
|
-ms-flex-direction: column; |
||||
|
flex-direction: column; |
||||
|
} |
||||
|
|
||||
|
<form |
||||
|
onReset={[Function]} |
||||
|
onSubmit={[Function]} |
||||
|
> |
||||
|
<div |
||||
|
className="c0" |
||||
|
> |
||||
|
<input |
||||
|
className="c1" |
||||
|
name="name" |
||||
|
onBlur={[Function]} |
||||
|
onChange={[Function]} |
||||
|
outline="none" |
||||
|
type="text" |
||||
|
value="" |
||||
|
/> |
||||
|
</div> |
||||
|
</form> |
||||
|
`; |
@ -0,0 +1,48 @@ |
|||||
|
// Jest Snapshot v1, https://goo.gl/fbAQLP |
||||
|
|
||||
|
exports[`component.UI.Range should render correctly 1`] = ` |
||||
|
.c0 { |
||||
|
overflow: hidden; |
||||
|
width: 100%; |
||||
|
-webkit-appearance: none; |
||||
|
-moz-appearance: none; |
||||
|
appearance: none; |
||||
|
outline: none; |
||||
|
} |
||||
|
|
||||
|
.c0::-webkit-slider-runnable-track { |
||||
|
height: 8px; |
||||
|
-webkit-appearance: none; |
||||
|
-moz-appearance: none; |
||||
|
appearance: none; |
||||
|
background-color: #959595; |
||||
|
margin-top: -1px; |
||||
|
} |
||||
|
|
||||
|
.c0::-webkit-slider-thumb { |
||||
|
width: 8px; |
||||
|
-webkit-appearance: none; |
||||
|
-moz-appearance: none; |
||||
|
appearance: none; |
||||
|
height: 8px; |
||||
|
cursor: ew-resize; |
||||
|
background: #ffffff; |
||||
|
box-shadow: -1000px 0 0 1000px orange; |
||||
|
} |
||||
|
|
||||
|
<form |
||||
|
onReset={[Function]} |
||||
|
onSubmit={[Function]} |
||||
|
> |
||||
|
<input |
||||
|
className="c0" |
||||
|
max={100} |
||||
|
min={0} |
||||
|
onBlur={[Function]} |
||||
|
onChange={[Function]} |
||||
|
step={1} |
||||
|
type="range" |
||||
|
value="0" |
||||
|
/> |
||||
|
</form> |
||||
|
`; |
@ -0,0 +1,157 @@ |
|||||
|
// Jest Snapshot v1, https://goo.gl/fbAQLP |
||||
|
|
||||
|
exports[`component.UI.Toggle should render correctly 1`] = ` |
||||
|
.c2 { |
||||
|
padding: 16px; |
||||
|
width: 100%; |
||||
|
font-size: 13px; |
||||
|
color: #ffffff; |
||||
|
background-color: transparent; |
||||
|
color: #ffffff; |
||||
|
background-color: transparent; |
||||
|
border: 1px solid white; |
||||
|
border: 1px solid white; |
||||
|
border-color: #ffffff; |
||||
|
border-radius: 5px; |
||||
|
} |
||||
|
|
||||
|
.c2:focus { |
||||
|
outline: none; |
||||
|
border: 1px solid #fd9800; |
||||
|
} |
||||
|
|
||||
|
.c1 { |
||||
|
display: -webkit-box; |
||||
|
display: -webkit-flex; |
||||
|
display: -ms-flexbox; |
||||
|
display: flex; |
||||
|
-webkit-flex-direction: column; |
||||
|
-ms-flex-direction: column; |
||||
|
flex-direction: column; |
||||
|
} |
||||
|
|
||||
|
.c3 { |
||||
|
padding: 0; |
||||
|
margin-top: 0; |
||||
|
position: absolute; |
||||
|
z-index: 2; |
||||
|
width: 100%; |
||||
|
max-height: 20rem; |
||||
|
overflow-y: auto; |
||||
|
overflow-x: hidden; |
||||
|
outline: 0; |
||||
|
-webkit-transition: opacity 0.1s ease; |
||||
|
transition: opacity 0.1s ease; |
||||
|
border: none; |
||||
|
background-color: #373947; |
||||
|
} |
||||
|
|
||||
|
.c0 { |
||||
|
background-color: transparent; |
||||
|
border: none; |
||||
|
position: absolute; |
||||
|
right: 5px; |
||||
|
top: 0; |
||||
|
cursor: pointer; |
||||
|
width: 47px; |
||||
|
display: -webkit-box; |
||||
|
display: -webkit-flex; |
||||
|
display: -ms-flexbox; |
||||
|
display: flex; |
||||
|
-webkit-flex-direction: column; |
||||
|
-ms-flex-direction: column; |
||||
|
flex-direction: column; |
||||
|
height: 50px; |
||||
|
-webkit-box-pack: center; |
||||
|
-webkit-justify-content: center; |
||||
|
-ms-flex-pack: center; |
||||
|
justify-content: center; |
||||
|
-webkit-align-items: center; |
||||
|
-webkit-box-align: center; |
||||
|
-ms-flex-align: center; |
||||
|
align-items: center; |
||||
|
outline: none; |
||||
|
} |
||||
|
|
||||
|
<form |
||||
|
onReset={[Function]} |
||||
|
onSubmit={[Function]} |
||||
|
> |
||||
|
<div |
||||
|
aria-expanded={false} |
||||
|
aria-haspopup="listbox" |
||||
|
aria-labelledby="downshift-0-label" |
||||
|
aria-owns={null} |
||||
|
role="combobox" |
||||
|
style={ |
||||
|
Object { |
||||
|
"position": "relative", |
||||
|
} |
||||
|
} |
||||
|
> |
||||
|
<div |
||||
|
style={ |
||||
|
Object { |
||||
|
"position": "relative", |
||||
|
} |
||||
|
} |
||||
|
> |
||||
|
<button |
||||
|
aria-haspopup={true} |
||||
|
aria-label="open menu" |
||||
|
className="c0" |
||||
|
data-toggle={true} |
||||
|
onBlur={[Function]} |
||||
|
onClick={[Function]} |
||||
|
onKeyDown={[Function]} |
||||
|
onKeyUp={[Function]} |
||||
|
role="button" |
||||
|
type="button" |
||||
|
> |
||||
|
<svg |
||||
|
fill="transparent" |
||||
|
preserveAspectRatio="none" |
||||
|
stroke="#979797" |
||||
|
strokeWidth="1.1px" |
||||
|
transform={null} |
||||
|
viewBox="0 0 20 20" |
||||
|
width={16} |
||||
|
> |
||||
|
<path |
||||
|
d="M1,6 L10,15 L19,6" |
||||
|
/> |
||||
|
</svg> |
||||
|
</button> |
||||
|
<div |
||||
|
className="c1" |
||||
|
> |
||||
|
<input |
||||
|
aria-activedescendant={null} |
||||
|
aria-autocomplete="list" |
||||
|
aria-controls={null} |
||||
|
aria-labelledby="downshift-0-label" |
||||
|
autoComplete="off" |
||||
|
className="c2" |
||||
|
id="downshift-0-input" |
||||
|
name="name" |
||||
|
onBlur={[Function]} |
||||
|
onChange={[Function]} |
||||
|
onFocus={[Function]} |
||||
|
onKeyDown={[Function]} |
||||
|
onMouseDown={[Function]} |
||||
|
outline="none" |
||||
|
placeholder="Please select" |
||||
|
type="text" |
||||
|
value="" |
||||
|
/> |
||||
|
</div> |
||||
|
</div> |
||||
|
<ul |
||||
|
aria-labelledby="downshift-0-label" |
||||
|
className="c3" |
||||
|
id="downshift-0-menu" |
||||
|
role="listbox" |
||||
|
/> |
||||
|
</div> |
||||
|
</form> |
||||
|
`; |
@ -0,0 +1,51 @@ |
|||||
|
// Jest Snapshot v1, https://goo.gl/fbAQLP |
||||
|
|
||||
|
exports[`component.UI.Input should render correctly 1`] = ` |
||||
|
.c1 { |
||||
|
padding: 16px; |
||||
|
width: 100%; |
||||
|
font-size: 13px; |
||||
|
color: #ffffff; |
||||
|
background-color: transparent; |
||||
|
color: #ffffff; |
||||
|
background-color: transparent; |
||||
|
border: 1px solid white; |
||||
|
border: 1px solid white; |
||||
|
border-color: #ffffff; |
||||
|
border-radius: 5px; |
||||
|
} |
||||
|
|
||||
|
.c1:focus { |
||||
|
outline: none; |
||||
|
border: 1px solid #fd9800; |
||||
|
} |
||||
|
|
||||
|
.c0 { |
||||
|
display: -webkit-box; |
||||
|
display: -webkit-flex; |
||||
|
display: -ms-flexbox; |
||||
|
display: flex; |
||||
|
-webkit-flex-direction: column; |
||||
|
-ms-flex-direction: column; |
||||
|
flex-direction: column; |
||||
|
} |
||||
|
|
||||
|
<form |
||||
|
onReset={[Function]} |
||||
|
onSubmit={[Function]} |
||||
|
> |
||||
|
<div |
||||
|
className="c0" |
||||
|
> |
||||
|
<input |
||||
|
className="c1" |
||||
|
name="name" |
||||
|
onBlur={[Function]} |
||||
|
onChange={[Function]} |
||||
|
outline="none" |
||||
|
type="text" |
||||
|
value="" |
||||
|
/> |
||||
|
</div> |
||||
|
</form> |
||||
|
`; |
@ -0,0 +1,85 @@ |
|||||
|
// Jest Snapshot v1, https://goo.gl/fbAQLP |
||||
|
|
||||
|
exports[`component.UI.Toggle should render correctly 1`] = ` |
||||
|
.c0 { |
||||
|
position: relative; |
||||
|
} |
||||
|
|
||||
|
.c0 .switch { |
||||
|
position: relative; |
||||
|
display: inline-block; |
||||
|
width: 35px; |
||||
|
height: 22px; |
||||
|
} |
||||
|
|
||||
|
.c0 .switch input { |
||||
|
opacity: 0; |
||||
|
width: 0; |
||||
|
height: 0; |
||||
|
} |
||||
|
|
||||
|
.c0 .slider { |
||||
|
position: absolute; |
||||
|
cursor: pointer; |
||||
|
top: 0; |
||||
|
left: 0; |
||||
|
right: 0; |
||||
|
bottom: 0; |
||||
|
background-color: #959595; |
||||
|
-webkit-transition: 0.4s; |
||||
|
transition: 0.4s; |
||||
|
border-radius: 34px; |
||||
|
} |
||||
|
|
||||
|
.c0 .slider:before { |
||||
|
position: absolute; |
||||
|
content: ''; |
||||
|
height: 20px; |
||||
|
width: 20px; |
||||
|
left: 1px; |
||||
|
bottom: 1px; |
||||
|
background-color: white; |
||||
|
-webkit-transition: 0.4s; |
||||
|
transition: 0.4s; |
||||
|
border-radius: 50%; |
||||
|
box-shadow: 1px 1px 3px #555; |
||||
|
} |
||||
|
|
||||
|
.c0 input:checked + .slider { |
||||
|
background-color: #39e673; |
||||
|
} |
||||
|
|
||||
|
.c0 input:focus + .slider { |
||||
|
box-shadow: 0 0 1px #2196f3; |
||||
|
} |
||||
|
|
||||
|
.c0 input:checked + .slider:before { |
||||
|
-webkit-transform: translateX(13px); |
||||
|
-ms-transform: translateX(13px); |
||||
|
transform: translateX(13px); |
||||
|
} |
||||
|
|
||||
|
<form |
||||
|
onReset={[Function]} |
||||
|
onSubmit={[Function]} |
||||
|
> |
||||
|
<div |
||||
|
className="c0" |
||||
|
> |
||||
|
<label |
||||
|
className="switch" |
||||
|
> |
||||
|
<input |
||||
|
checked={false} |
||||
|
name="name" |
||||
|
onBlur={[Function]} |
||||
|
onChange={[Function]} |
||||
|
type="checkbox" |
||||
|
/> |
||||
|
<span |
||||
|
className="slider round" |
||||
|
/> |
||||
|
</label> |
||||
|
</div> |
||||
|
</form> |
||||
|
`; |
Loading…
Reference in new issue