UNPKG

@devseed-ui/form

Version:
156 lines (136 loc) 3.69 kB
import React from 'react'; import T from 'prop-types'; import styled, { css } from 'styled-components'; import { shade } from 'polished'; import { visuallyHidden, themeVal, stylizeFunction } from '@devseed-ui/theme-provider'; const _shade = stylizeFunction(shade); /** * Renders a FormSwitch component. * Under the hood this uses a checkbox * * @param {string} name (html prop) name to be used as `name` prop of * the checkbox * @param {string} id (html prop) id to be used as `id` prop of the checkbox * @param {string} title (html prop) Label's title attribute * @param {boolean} checked Whether or not the FormSwitch is checked * @param {func} onChange Change callback for the FormSwitch * @param {string} value Value for the underlying checkbox * @param {node} children Content of the label * @param {boolean} hideText Whether or not to visually hide the FormSwitch text * @param {string} textPlacement Where to position the text. `left` or `right` * of the toggle. */ const FormSwitchElement = (props) => { const { children, id, name, title, checked, onChange, value, className, hideText, textPlacement } = props; return ( <label htmlFor={id} className={className} title={title}> <input type='checkbox' name={name} id={id} value={value} checked={checked} onChange={onChange} /> {textPlacement === 'right' && <FormOptionUi />} <FormOptionText hideText={hideText}>{children}</FormOptionText> {textPlacement === 'left' && <FormOptionUi />} </label> ); }; FormSwitchElement.propTypes = { name: T.string.isRequired, id: T.string.isRequired, textPlacement: T.oneOf(['right', 'left']), hideText: T.bool, className: T.string, title: T.string, checked: T.bool, children: T.node.isRequired, onChange: T.func, value: T.oneOfType([T.number, T.string]) }; FormSwitchElement.defaultProps = { textPlacement: 'left' }; /** * Form option extend. Common code to all form options. */ const formOption = css` display: inline-grid; grid-template-columns: max-content; grid-auto-flow: column; grid-auto-columns: 1fr; grid-gap: 1rem; font-size: 0.875rem; line-height: 1.5; cursor: pointer; input { flex: none; margin-top: 0.3125rem; /* 5px */ } `; const FormOptionText = styled.span` line-height: 1.5; /* Hide Text */ ${({ hideText }) => hideText && visuallyHidden()} `; const FormOptionUi = styled.span` flex: none; position: relative; transition: all 0.16s ease 0s; `; const FormSwitch = styled(FormSwitchElement)` ${formOption} input { ${visuallyHidden()} } ${FormOptionUi} { margin: 0.375rem 0; width: 2.25rem; height: 0.75rem; border-radius: ${themeVal('shape.ellipsoid')}; background: ${themeVal('color.base-300a')}; &::before { background-color: ${themeVal('color.surface')}; box-shadow: ${themeVal('boxShadow.elevationB')}; position: absolute; top: 50%; left: 0; z-index: 2; content: ''; height: 1.25rem; width: 1.25rem; border-radius: ${themeVal('shape.ellipsoid')}; transform: translate(0, -50%); transition: all 0.24s ease 0s; } } &:hover ${/* sc-selector */ FormOptionUi}::before { background-color: ${_shade(0.04, themeVal('color.surface-500'))}; } ${({ checked }) => (checked ? `${FormOptionUi},` : '')} input:checked ~ ${FormOptionUi} { background: ${themeVal('color.link')}; &::before { left: 100%; transform: translate(-100%, -50%); } } `; export default FormSwitch;