Home Reference Source

src/components/controls/RadioGroup/RadioGroup.jsx

import React from 'react';
import PropTypes from 'prop-types';
import cx from 'classnames';
import { isEqual } from 'lodash';
import Radio from '../Radio/Radio';
import RadioButton from '../Radio/RadioButton';
import RadioN2O from '../Radio/RadioN2O';

/**
 * Компонент - группа радиобаттонов, содержит {@link Radio} как children
 * @reactProps {string|number|boolean} value - выбранное значение
 * @reactProps {function} onChange - вызывается при изменении значения
 * @reactProps {boolean} disabled - только для чтения
 * @reactProps {boolean} visible - флаг видимости
 * @reactProps {object} style - стили группы
 * @reactProps {string} className - класс группы
 * @reactProps {boolean} inline
 * @reactProps {node} children
 * @example
 * <RadioGroup onChange={(val)=> console.log(val)}>
 *  <Radio value="apple" label='Apple'/>
 *  <Radio value="orange" label='Orange'/>
 *  <Radio value="watermelon" label='Watermelon'/>
 * </RadioGroup>
 */

class RadioGroup extends React.Component {
  constructor(props) {
    super(props);
    this._onChange = this._onChange.bind(this);
  }

  _onChange(e) {
    const { onChange } = this.props;
    const { value } = e.target;
    onChange(value);
  }

  /**
   * Рендер
   */

  render() {
    const { children, value, visible, style, className, inline } = this.props;

    const element = child => {
      return React.cloneElement(child, {
        checked: isEqual(value, child.props.value),
        disabled: this.props.disabled || child.props.disabled,
        onChange: this._onChange,
        inline: this.props.inline,
      });
    };

    const isRadioChild = child => {
      const checkboxTypes = ['Radio', 'RadioN2O', 'RadioButton'];
      return child.type && checkboxTypes.includes(child.type.displayName);
    };

    const isBtn =
      children &&
      React.Children.map(children, child => child.type.displayName).includes(
        'RadioButton'
      );

    return (
      <React.Fragment>
        {visible !== false && (
          <div
            className={cx('n2o-radio-container', className, {
              [`btn-group${inline ? '' : '-vertical'}`]: isBtn,
              'btn-group-toggle': isBtn,
              'n2o-radio-inline': inline,
            })}
            style={style}
          >
            {children &&
              React.Children.map(children, child => {
                if (isRadioChild(child)) {
                  return element(child);
                }
              })}
          </div>
        )}
      </React.Fragment>
    );
  }
}

RadioGroup.propTypes = {
  value: PropTypes.oneOfType([PropTypes.string, PropTypes.object]),
  onChange: PropTypes.func,
  disabled: PropTypes.bool,
  visible: PropTypes.bool,
  children: PropTypes.node.isRequired,
  style: PropTypes.object,
  className: PropTypes.string,
  inline: PropTypes.bool,
};

RadioGroup.defaultProps = {
  isBtnGroup: false,
  visible: true,
  inline: false,
};

RadioGroup.defaultProps = {
  onChange: () => {},
};

export default RadioGroup;