@devseed-ui/form
Version:
devseed UI Kit Form
156 lines (136 loc) • 3.69 kB
JavaScript
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;