UNPKG

wix-style-react

Version:
171 lines (148 loc) 5.04 kB
import React from 'react'; import PropTypes from 'prop-types'; import uniqueId from 'lodash/uniqueId'; import Radio from '../Radio/Radio'; import { st, classes } from './RadioGroup.st.css'; import { dataHooks } from './constants'; /** * component for easy radio group creation. * * similar to HTML `<input type="radio"/>` except you don't need to handle `name` or click handlers */ class RadioGroup extends React.PureComponent { _getSpacing(index) { const { display: orientation, spacing } = this.props; return orientation === 'vertical' && index > 0 ? { marginTop: spacing } : orientation === 'horizontal' && index > 0 ? { marginInlineStart: spacing } : {}; } render() { const { dataHook, className, name, onChange, disabledRadios, value, vAlign, display: orientation, lineHeight, selectionArea, selectionAreaSkin, selectionAreaPadding, } = this.props; const uniqueName = name || uniqueId('RadioGroup_'); return ( <div role="radiogroup" data-hook={dataHook} className={st( classes.root, { orientation, }, className, )} data-display={orientation} data-lineheight={lineHeight} > {React.Children.map(this.props.children, (radio, index) => { const checked = radio.props.value === value; const radioName = radio.props.name || uniqueName; const disabled = this.props.disabled || disabledRadios.indexOf(radio.props.value) !== -1; const radioDataHook = `${dataHooks.RadioContainer}-${radio.props.value}`; return ( <div className={st(classes.optionContainer, { selectionArea, selectionAreaSkin, checked, disabled, })} data-hook={dataHooks.RadioOptionContainer} style={this._getSpacing(index)} > <div className={classes.radioContainer} data-hook={radioDataHook}> <Radio style={{ minHeight: lineHeight, padding: selectionAreaPadding, }} className={classes.radio} dataHook={radio.props.dataHook} value={radio.props.value} name={radioName} id={uniqueId(`${radioName}_`)} onChange={() => onChange(radio.props.value)} alignItems={vAlign} disabled={disabled} checked={checked} label={radio.props.children} /> </div> {radio.props.content && ( <div className={classes.content} data-hook={dataHooks.RadioContent} > {radio.props.content} </div> )} </div> ); })} </div> ); } } RadioGroup.propTypes = { /** Applies a data-hook HTML attribute that can be used in the tests */ dataHook: PropTypes.string, /** Specifies a CSS class name to be appended to the component’s root element */ className: PropTypes.string, /** Defines a callback function which is called every time user selects a different value */ onChange: PropTypes.func, /** Specifies the selected radio value */ value: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), /** Specify the values of the disabled radio buttons */ disabledRadios: PropTypes.arrayOf( PropTypes.oneOfType([PropTypes.string, PropTypes.number]), ), /** Controls radio alignment to the label on Y axis */ vAlign: PropTypes.oneOf(['center', 'top']), /** Disables the entire group */ disabled: PropTypes.bool, /** Control options direction */ display: PropTypes.oneOf(['vertical', 'horizontal']), /** Controls selection area highlight visibility */ selectionArea: PropTypes.oneOf(['none', 'hover', 'always']), /** Sets the design of the selection area */ selectionAreaSkin: PropTypes.oneOf(['filled', 'outlined']), /** Sets the amount of white space around the radio label in pixels */ selectionAreaPadding: PropTypes.string, /** Lists RadioGroup items. You're recommended to use it with <RadioGroup.Radio/>. */ children: PropTypes.node, /** Controls the distance between options */ spacing: PropTypes.string, /** Sets the min-height of <RadioGroup.Radio/> children */ lineHeight: PropTypes.string, /** Sets a unique name of a radio group */ name: PropTypes.string, }; RadioGroup.defaultProps = { disabledRadios: [], onChange: () => {}, value: '', vAlign: 'center', display: 'vertical', lineHeight: '24px', selectionArea: 'none', selectionAreaSkin: 'filled', }; RadioGroup.Radio = Radio; RadioGroup.displayName = 'RadioGroup'; export default RadioGroup;