UNPKG

@devseed-ui/form

Version:
203 lines (180 loc) 4.95 kB
import React from 'react'; import T from 'prop-types'; import styled, { css } from 'styled-components'; import { CollecticonTickSmall, iconDataURI } from '@devseed-ui/collecticons'; import { disabled, rgba, themeVal, visuallyHidden } from '@devseed-ui/theme-provider'; /** * Renders a FormCheckable component. * * @param {string} type Determines the type of input to render. Can be one of * `checkbox` or `radio` * @param {string} name (html prop) name to be used as `name` prop of * the element * @param {string} id (html prop) id to be used as `id` prop of the element * @param {string} title (html prop) Label's title attribute * @param {boolean} checked Whether or not the FormCheckable is checked * @param {func} onChange Change callback for the FormCheckable * @param {string} value Value for the underlying input element * @param {node} children Textual content * @param {string} textPlacement Where to position the text. `left` or `right` * of the control. Default to `right` */ const FormCheckableElement = (props) => { const { children, id, name, title, type, checked, onChange, value, className, textPlacement, hideText, ...rest } = props; return ( <label htmlFor={id} className={className} title={title} {...rest}> <input type={type} name={name} id={id} value={value} checked={checked} onChange={onChange} /> {textPlacement === 'right' && <FormCheckableControl />} <FormCheckableText hideText={hideText}>{children}</FormCheckableText> {textPlacement === 'left' && <FormCheckableControl />} </label> ); }; FormCheckableElement.propTypes = { name: T.string.isRequired, id: T.string.isRequired, textPlacement: T.oneOf(['right', 'left']), hideText: T.bool, className: T.string, title: T.string, type: T.oneOf(['checkbox', 'radio']), checked: T.bool, children: T.node.isRequired, onChange: T.func, value: T.oneOfType([T.number, T.string]) }; FormCheckableElement.defaultProps = { textPlacement: 'right' }; const formCheckableWrapper = css` display: inline-grid; gap: 0.5rem; font-size: 1rem; line-height: 1.5; cursor: pointer; justify-content: start; > * { grid-row: 1; } input { flex: none; } `; const FormCheckableText = styled.span` line-height: 1.5; /* Hide Text */ ${({ hideText }) => hideText && visuallyHidden()} `; const FormCheckableControl = styled.span` position: relative; transition: all 0.16s ease 0s; `; export const FormCheckable = styled(FormCheckableElement)` ${formCheckableWrapper} input { ${visuallyHidden()} } ${FormCheckableControl} { display: flex; align-items: center; justify-content: center; margin: 0.125rem 0; height: 1.25rem; width: 1.25rem; background: ${themeVal('color.surface')}; line-height: 1; border: ${themeVal('layout.border')} solid ${rgba(themeVal('color.base'), 0.16)}; border-radius: ${({ type }) => type === 'checkbox' ? themeVal('shape.rounded') : themeVal('shape.ellipsoid')}; &::before { transition: all 0.24s ease 0s; opacity: 0; content: ''; ${({ type, theme }) => type === 'checkbox' ? css` background-image: url('${iconDataURI(CollecticonTickSmall, { color: theme.color.base })}'); background-size: 1rem 1rem; height: 1rem; width: 1rem; background-repeat: no-repeat; ` : css` height: 0.5rem; width: 0.5rem; background: ${themeVal('color.base')}; border-radius: ${themeVal('shape.ellipsoid')}; `} } } &:hover ${FormCheckableControl} { border-width: ${themeVal('layout.border')}; border-color: ${rgba(themeVal('color.base'), 0.32)}; } ${({ invalid }) => invalid && css` ${FormCheckableControl} { border-width: ${themeVal('layout.border')}; border-color: ${themeVal('color.danger')}; } &:hover ${FormCheckableControl}, &:focus ${FormCheckableControl}, &:active ${FormCheckableControl} { border-color: ${themeVal('color.danger')}; } `} input:focus ~ ${FormCheckableControl}, input:active ~ ${FormCheckableControl} { outline: 0; border-width: ${themeVal('layout.border')}; border-color: ${rgba(themeVal('color.base'), 0.64)}; } ${({ checked }) => (checked ? `${FormCheckableControl},` : '')} input:checked ~ ${FormCheckableControl} { &::before { opacity: 1; } } &[disabled] { ${disabled()} } `; export const FormCheckableGroup = styled.div` display: flex; flex-flow: row wrap; gap: 0.5rem 1rem; `;