UNPKG

@spaced-out/ui-design-system

Version:
114 lines (104 loc) 2.99 kB
// @flow strict import * as React from 'react'; import classify from '../../utils/classify'; import css from './Toggle.module.css'; /** * Note: * Do not wrap Toggle in a label. For simplicity's sake, Toggle uses an * internal label tag to handle click delegation to the hidden input, and * nesting labels is a bad idea. */ type ClassNames = $ReadOnly<{wrapper?: string, label?: string}>; export type ToggleProps = { name?: string, classNames?: ClassNames, children?: React.Node, checked?: boolean, onChange?: ({value: string, checked: boolean}) => mixed, disabled?: boolean, focused?: boolean, value?: string, ariaLabel?: string, labelPosition?: 'left' | 'right', }; export const Toggle: React$AbstractComponent<ToggleProps, HTMLInputElement> = React.forwardRef<ToggleProps, HTMLInputElement>( ( { name = 'toggle', value = '', classNames, children, disabled, checked, focused, onChange, ariaLabel, labelPosition = 'right', ...props }: ToggleProps, forwardRef, ): React.Node => { const toggleInput = React.createRef<HTMLInputElement>(); React.useImperativeHandle(forwardRef, () => toggleInput.current); const handleOnChange = () => { if (!disabled) { onChange && onChange({ value, checked: !checked, }); } }; const onWrapClickHandler = (e) => { e.nativeEvent.stopImmediatePropagation(); toggleInput.current?.click(); }; React.useEffect(() => { if (toggleInput.current && focused) { toggleInput.current.focus(); } }, [focused]); return ( <div className={classify( css.container, { [css.disabled]: disabled, }, classNames?.wrapper, )} onClick={onWrapClickHandler} > {labelPosition === 'left' && React.Children.count(children) > 0 && ( <div className={classify(css.toggleLabel, classNames?.label)}> {children} </div> )} <span className={css.toggleWrap}> <input type="checkbox" name={name} value={value} checked={checked} onChange={handleOnChange} ref={toggleInput} disabled={disabled} aria-label={ariaLabel || children} {...props} /> <span className={classify(css.toggle, { [css.disabledButton]: disabled, })} /> </span> {labelPosition === 'right' && React.Children.count(children) > 0 && ( <div className={classify(css.toggleLabel, classNames?.label)}> {children} </div> )} </div> ); }, );