diff --git a/app/components/UI/FormFieldMessage.js b/app/components/UI/FormFieldMessage.js
new file mode 100644
index 00000000..abdc21d0
--- /dev/null
+++ b/app/components/UI/FormFieldMessage.js
@@ -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
+ *
+ */
+class FormFieldMessage extends React.Component {
+ static displayName = 'FormFieldMessage'
+
+ static propTypes = {
+ variant: PropTypes.string,
+ children: PropTypes.node
+ }
+
+ render() {
+ const { children, variant } = this.props
+ return (
+
+
+ {variant === 'success' && }
+ {variant === 'warning' && }
+ {variant === 'error' && }
+
+ {children}
+
+ )
+ }
+}
+
+export default FormFieldMessage
diff --git a/app/components/UI/Input.js b/app/components/UI/Input.js
new file mode 100644
index 00000000..003cbc61
--- /dev/null
+++ b/app/components/UI/Input.js
@@ -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
+ *
+ */
+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 (
+
+ {
+ setValue(e.target.value)
+ if (onChange) {
+ onChange(e)
+ }
+ }}
+ onBlur={e => {
+ setTouched()
+ if (onBlur) {
+ onBlur(e)
+ }
+ }}
+ error={fieldState.error}
+ />
+ {fieldState.error && (
+
+ {fieldState.error}
+
+ )}
+
+ )
+ }
+}
+
+export default asField(withTheme(Input))
diff --git a/app/components/UI/Label.js b/app/components/UI/Label.js
new file mode 100644
index 00000000..33f8c999
--- /dev/null
+++ b/app/components/UI/Label.js
@@ -0,0 +1,20 @@
+import React from 'react'
+import { Label as Base } from 'styled-system-html'
+
+/**
+ * @render react
+ * @name Label
+ * @example
+ *
+ */
+class Label extends React.Component {
+ static displayName = 'Label'
+
+ render() {
+ return (
+
+ )
+ }
+}
+
+export default Label
diff --git a/app/components/UI/Range.js b/app/components/UI/Range.js
new file mode 100644
index 00000000..025a7d7d
--- /dev/null
+++ b/app/components/UI/Range.js
@@ -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 (
+ {
+ setValue(e.target.value)
+ if (onChange) {
+ onChange(e)
+ }
+ }}
+ onBlur={e => {
+ setTouched()
+ if (onBlur) {
+ onBlur(e)
+ }
+ }}
+ />
+ )
+})
+
+export default withTheme(Range)
diff --git a/app/components/UI/Select.js b/app/components/UI/Select.js
new file mode 100644
index 00000000..7dcdeefd
--- /dev/null
+++ b/app/components/UI/Select.js
@@ -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 }) => (
+
+)
+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 (
+ 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
+ }) => (
+
+
+
+ {isOpen
+ ? items.map((item, index) => (
+
+ {item.label || item.value}
+
+ ))
+ : null}
+
+
+ )}
+
+ )
+ }
+}
+
+export default withTheme(asField(Select))
diff --git a/app/components/UI/TextArea.js b/app/components/UI/TextArea.js
new file mode 100644
index 00000000..4b1686d7
--- /dev/null
+++ b/app/components/UI/TextArea.js
@@ -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
+ *
+ */
+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 (
+
+ {
+ setValue(e.target.value)
+ if (onChange) {
+ onChange(e)
+ }
+ }}
+ onBlur={e => {
+ setTouched()
+ if (onBlur) {
+ onBlur(e)
+ }
+ }}
+ error={fieldState.error}
+ />
+ {fieldState.error && (
+
+ {fieldState.error}
+
+ )}
+
+ )
+ }
+}
+
+export default asField(withTheme(TextArea))
diff --git a/app/components/UI/Toggle.js b/app/components/UI/Toggle.js
new file mode 100644
index 00000000..792c1ae5
--- /dev/null
+++ b/app/components/UI/Toggle.js
@@ -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 }) => (
+
+
+
+)
+
+export default asField(Toggle)
diff --git a/app/themes/dark.js b/app/themes/dark.js
index 7da75808..6b2f1bca 100644
--- a/app/themes/dark.js
+++ b/app/themes/dark.js
@@ -45,11 +45,23 @@ const cards = {
color: colors.superRed
}
}
+const messages = {
+ success: {
+ color: colors.superGreen
+ },
+ warning: {
+ color: colors.lightningOrange
+ },
+ error: {
+ color: colors.superRed
+ }
+}
export default {
name: 'dark',
...base,
colors,
buttons,
- cards
+ cards,
+ messages
}
diff --git a/package.json b/package.json
index 09984b31..76f7318f 100644
--- a/package.json
+++ b/package.json
@@ -309,12 +309,14 @@
"country-data-lookup": "^0.0.3",
"debug": "^4.1.0",
"debug-logger": "^0.4.1",
+ "downshift": "^3.1.0",
"electron": "^3.0.4",
"electron-is-dev": "^1.0.1",
"electron-store": "^2.0.0",
"font-awesome": "^4.7.0",
"get-port": "^4.0.0",
"history": "^4.7.2",
+ "informed": "^1.10.7",
"is-electron-renderer": "^2.0.1",
"javascript-state-machine": "^3.1.0",
"jstimezonedetect": "^1.0.6",
@@ -340,6 +342,7 @@
"source-map-support": "^0.5.9",
"split2": "^3.0.0",
"styled-components": "^4.0.0-beta.10",
+ "styled-system-html": "^2.0.2",
"tildify": "^1.2.0",
"untildify": "^3.0.3",
"validator": "^10.8.0"
diff --git a/stories/components/form.stories.js b/stories/components/form.stories.js
new file mode 100644
index 00000000..325299dd
--- /dev/null
+++ b/stories/components/form.stories.js
@@ -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', () => (
+
+ ))
+ .add('Label', () => (
+
+ ))
+ .add('TextArea', () => (
+
+ ))
+ .add('Select', () => (
+
+ ))
+ .add('Toggle', () => (
+
+ ))
+ .add('Range', () => (
+
+ ))
+ .add('Example form', () => (
+
+
+
+
+
+ ))
diff --git a/test/unit/components/UI/Input.spec.js b/test/unit/components/UI/Input.spec.js
new file mode 100644
index 00000000..34eea09e
--- /dev/null
+++ b/test/unit/components/UI/Input.spec.js
@@ -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(
+
+
+
+ )
+ .toJSON()
+ expect(tree).toMatchSnapshot()
+ })
+})
diff --git a/test/unit/components/UI/Range.spec.js b/test/unit/components/UI/Range.spec.js
new file mode 100644
index 00000000..64597330
--- /dev/null
+++ b/test/unit/components/UI/Range.spec.js
@@ -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(
+
+
+
+ )
+ .toJSON()
+ expect(tree).toMatchSnapshot()
+ })
+})
diff --git a/test/unit/components/UI/Select.spec.js b/test/unit/components/UI/Select.spec.js
new file mode 100644
index 00000000..9d0120ab
--- /dev/null
+++ b/test/unit/components/UI/Select.spec.js
@@ -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(
+
+
+
+ )
+ .toJSON()
+ expect(tree).toMatchSnapshot()
+ })
+})
diff --git a/test/unit/components/UI/TextArea.spec.js b/test/unit/components/UI/TextArea.spec.js
new file mode 100644
index 00000000..f21f095d
--- /dev/null
+++ b/test/unit/components/UI/TextArea.spec.js
@@ -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(
+
+
+
+ )
+ .toJSON()
+ expect(tree).toMatchSnapshot()
+ })
+})
diff --git a/test/unit/components/UI/Toggle.spec.js b/test/unit/components/UI/Toggle.spec.js
new file mode 100644
index 00000000..a8e1143c
--- /dev/null
+++ b/test/unit/components/UI/Toggle.spec.js
@@ -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(
+
+
+
+ )
+ .toJSON()
+ expect(tree).toMatchSnapshot()
+ })
+})
diff --git a/test/unit/components/UI/__snapshots__/Input.spec.js.snap b/test/unit/components/UI/__snapshots__/Input.spec.js.snap
new file mode 100644
index 00000000..86784e7a
--- /dev/null
+++ b/test/unit/components/UI/__snapshots__/Input.spec.js.snap
@@ -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;
+}
+
+
+`;
diff --git a/test/unit/components/UI/__snapshots__/Range.spec.js.snap b/test/unit/components/UI/__snapshots__/Range.spec.js.snap
new file mode 100644
index 00000000..4f7b7694
--- /dev/null
+++ b/test/unit/components/UI/__snapshots__/Range.spec.js.snap
@@ -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;
+}
+
+
+`;
diff --git a/test/unit/components/UI/__snapshots__/Select.spec.js.snap b/test/unit/components/UI/__snapshots__/Select.spec.js.snap
new file mode 100644
index 00000000..238fe9bd
--- /dev/null
+++ b/test/unit/components/UI/__snapshots__/Select.spec.js.snap
@@ -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;
+}
+
+
+`;
diff --git a/test/unit/components/UI/__snapshots__/TextArea.spec.js.snap b/test/unit/components/UI/__snapshots__/TextArea.spec.js.snap
new file mode 100644
index 00000000..86784e7a
--- /dev/null
+++ b/test/unit/components/UI/__snapshots__/TextArea.spec.js.snap
@@ -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;
+}
+
+
+`;
diff --git a/test/unit/components/UI/__snapshots__/Toggle.spec.js.snap b/test/unit/components/UI/__snapshots__/Toggle.spec.js.snap
new file mode 100644
index 00000000..218c5fad
--- /dev/null
+++ b/test/unit/components/UI/__snapshots__/Toggle.spec.js.snap
@@ -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);
+}
+
+
+`;
diff --git a/yarn.lock b/yarn.lock
index 7627adfb..6f524535 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -5436,7 +5436,7 @@ css-selector-tokenizer@^0.7.0:
fastparse "^1.1.1"
regexpu-core "^1.0.0"
-css-to-react-native@^2.2.2:
+css-to-react-native@^2.0.3, css-to-react-native@^2.2.2:
version "2.2.2"
resolved "https://registry.yarnpkg.com/css-to-react-native/-/css-to-react-native-2.2.2.tgz#c077d0f7bf3e6c915a539e7325821c9dd01f9965"
integrity sha512-w99Fzop1FO8XKm0VpbQp3y5mnTnaS+rtCvS+ylSEOK76YXO5zoHQx/QMB1N54Cp+Ya9jB9922EHrh14ld4xmmw==
@@ -6107,6 +6107,15 @@ dotenv@^6.0.0:
resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-6.1.0.tgz#9853b6ca98292acb7dec67a95018fa40bccff42c"
integrity sha512-/veDn2ztgRlB7gKmE3i9f6CmDIyXAy6d5nBq+whO9SLX+Zs1sXEgFLPi+aSuWqUuusMfbi84fT8j34fs1HaYUw==
+downshift@^3.1.0:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/downshift/-/downshift-3.1.0.tgz#3a7b4fc26e9d563c745db3a5172437239e0bb8a8"
+ integrity sha512-lk6uBqobNfnumEitDp/GIAAgLK8ad2lHmieKpwZ8bvl7fDIXvJr/26P+CeI/vvQqrjo4YpBrijUNFr8Qqz1dxg==
+ dependencies:
+ "@babel/runtime" "^7.1.2"
+ compute-scroll-into-view "^1.0.9"
+ prop-types "^15.6.0"
+
duplexer2@~0.1.4:
version "0.1.4"
resolved "https://registry.yarnpkg.com/duplexer2/-/duplexer2-0.1.4.tgz#8b12dab878c0d69e3e7891051662a32fc6bddcc1"
@@ -8772,6 +8781,13 @@ inflight@^1.0.4, inflight@~1.0.6:
once "^1.3.0"
wrappy "1"
+informed@^1.10.7:
+ version "1.10.7"
+ resolved "https://registry.yarnpkg.com/informed/-/informed-1.10.7.tgz#78774436444f21c8b1368eb746012d5f9420ee87"
+ integrity sha512-+5tYieUyHSPdX8RJ8Pg9gVMsBUi6GBDKDriUg31be4t332CVBZssS+pNZokwJTwkG1T7rxMYXH4o+HfHN/pqLw==
+ dependencies:
+ "@babel/runtime-corejs2" "^7.0.0-rc.1"
+
inherits@2, inherits@2.0.3, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.0, inherits@~2.0.1, inherits@~2.0.3:
version "2.0.3"
resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de"
@@ -15797,6 +15813,21 @@ style-search@^0.1.0:
resolved "https://registry.yarnpkg.com/style-search/-/style-search-0.1.0.tgz#7958c793e47e32e07d2b5cafe5c0bf8e12e77902"
integrity sha1-eVjHk+R+MuB9K1yv5cC/jhLneQI=
+styled-components@^3.4.5:
+ version "3.4.10"
+ resolved "https://registry.yarnpkg.com/styled-components/-/styled-components-3.4.10.tgz#9a654c50ea2b516c36ade57ddcfa296bf85c96e1"
+ integrity sha512-TA8ip8LoILgmSAFd3r326pKtXytUUGu5YWuqZcOQVwVVwB6XqUMn4MHW2IuYJ/HAD81jLrdQed8YWfLSG1LX4Q==
+ dependencies:
+ buffer "^5.0.3"
+ css-to-react-native "^2.0.3"
+ fbjs "^0.8.16"
+ hoist-non-react-statics "^2.5.0"
+ prop-types "^15.5.4"
+ react-is "^16.3.1"
+ stylis "^3.5.0"
+ stylis-rule-sheet "^0.0.10"
+ supports-color "^3.2.3"
+
styled-components@^4.0.0-beta.10:
version "4.0.0"
resolved "https://registry.yarnpkg.com/styled-components/-/styled-components-4.0.0.tgz#bd37d79408246302051cd63f52a3539f70aa3197"
@@ -15811,6 +15842,15 @@ styled-components@^4.0.0-beta.10:
stylis "^3.5.0"
stylis-rule-sheet "^0.0.10"
+styled-system-html@^2.0.2:
+ version "2.0.2"
+ resolved "https://registry.yarnpkg.com/styled-system-html/-/styled-system-html-2.0.2.tgz#2a95f7720eea44b33d0e29c77289f070fe3dd318"
+ integrity sha512-QtqV+xc16ogG9ni+k/ZLytQ7Q5mpd+jCd1SioUUgm/6YaptSRop5+2qiKLL4acUxIV3liKuZbGyhxGsWeA0Dlg==
+ dependencies:
+ html-tags "^2.0.0"
+ styled-components "^3.4.5"
+ system-components "^3.0.0"
+
styled-system@^3.0.1, styled-system@^3.1.4:
version "3.1.11"
resolved "https://registry.yarnpkg.com/styled-system/-/styled-system-3.1.11.tgz#a91a38cf7a0f0e625b897a04fdd506a359a3629f"