Home Reference Source

src/views/form/radio.field.js

import React from 'react';
import PropTypes from 'prop-types';
import Field from './field.view';
import { FontAwesomeIcon as FA } from '@fortawesome/react-fontawesome';
import { faCircle, faDotCircle } from '@fortawesome/free-solid-svg-icons';

/**
 * Controls input of type radio
 *
 * #### SCSS Import
 * ```
 * @import "~@orloxx/ui-core/scss/form/radio-field";
 * ```
 *
 * @extends {Field}
 *
 * @example
 * <RadioField id='salutation-1' name='salutation' label='Salutation'>
 *   <option value='1' selected>Mr.</option>
 *   <option value='2'>Mrs.</option>
 * </RadioField>
 */
class RadioField extends Field {
  /**
   * @type {Object}
   * @property {Array<HTMLOptionElement>} children - Elements to show in the radiobutton list
   */
  static propTypes = Object.assign({}, Field.propTypes, {
    children: PropTypes.array.isRequired,
  });

  /**
   * @ignore
   */
  static defaultProps = Object.assign({}, Field.defaultProps, {
    children: [],
  });

  /**
   * @ignore
   */
  constructor(props) {
    super(props);

    /**
     * @ignore
     */
    this.state = {
      selectedId: this.getRadioId(props.children.find(child => child.props.selected)),
    };
  }

  /**
   * @ignore
   */
  get isValid() {
    const { required } = this.props;
    if (required) {
      return !!this.state.selectedId;
    }
    return true;
  }

  /**
   * @ignore
   */
  componentDidUpdate(prevProps, prevState) {
    if (prevState.selectedId !== this.state.selectedId) {
      this.validate();
    }
  }

  /**
   * @ignore
   */
  getLabel(children) {
    const { label } = this.props;
    return children.length ? children : label;
  }

  /**
   * @ignore
   */
  getRadioId(child) {
    const { id } = this.props;
    if (child) {
      return `${id}-${child.props.value}`;
    }
    return null;
  }

  /**
   * @ignore
   */
  selectRadio(radio) {
    this.setState({
      selectedId: this.getRadioId(radio),
    });
  }

  /**
   * @ignore
   */
  renderRadioButton(radio) {
    const { selectedId } = this.state;
    if (selectedId === this.getRadioId(radio)) {
      return (<FA icon={faDotCircle} />);
    }
    return (<FA icon={faCircle} />);
  }

  /**
   * @ignore
   */
  renderInputs() {
    const { name, required } = this.props;
    return this.props.children.map(child => (
      <label
        className='radio__label' key={this.getRadioId(child)}
        htmlFor={this.getRadioId(child)}>
        <input
          className='field__input radio__input hideAccessible'
          type='radio' id={this.getRadioId(child)} name={name}
          title={this.getLabel(child.props.children)} required={required}
          onChange={() => this.selectRadio(child)}
          onBlur={() => this.validate()} />
        <div className='radio__wrapper'>
          <div className='radio__icon'>{this.renderRadioButton(child)}</div>
          <div className='radio__text'>{this.getLabel(child.props.children)}</div>
        </div>
      </label>
    ));
  }

  /**
   * @ignore
   */
  render() {
    const { label } = this.props;
    return (
      <div className={`field radio ${this.fieldClasses}`}>
        <label className='field__label'>{label}</label>
        {this.renderInputs()}
        <div className='radio__validation'>
          {this.renderValidationMessages()}
        </div>
      </div>
    );
  }
}

export default RadioField;