UNPKG

@bigfishtv/cockpit

Version:

118 lines (106 loc) 2.87 kB
import PropTypes from 'prop-types' import React, { Component } from 'react' import classnames from 'classnames' import { titleCase } from '../../utils/stringUtils' function toString(value) { return value === null ? '' : String(value) } function toValue(string, options) { return string === '' ? null : options.reduce((acc, { value }) => (String(value) === string ? value : acc), string) } export default class SelectInput extends Component { static propTypes = { options: PropTypes.arrayOf( PropTypes.oneOfType([ PropTypes.string, PropTypes.shape({ value: PropTypes.any, text: PropTypes.node, }), ]) ), empty: PropTypes.oneOfType([PropTypes.string, PropTypes.bool]), value: PropTypes.any, defaultValue: PropTypes.any, onChange: PropTypes.func, coerceValueToOptions: PropTypes.bool, className: PropTypes.string, } static defaultProps = { options: [], empty: 'Please select ...', defaultValue: null, onChange: () => {}, coerceValueToOptions: true, } componentDidMount() { if (this.props.coerceValueToOptions) { this.coerceValueToOptions() } } componentDidUpdate() { if (this.props.coerceValueToOptions) { this.coerceValueToOptions() } } coerceValueToOptions() { // coerce value to defaultValue if value not found in options const { value, defaultValue, empty } = this.props const options = this.normalisedOptions() const selectedOption = options.find(option => option.value === value) if (!selectedOption) { if (options.length && empty === false) { // select first item if we have options to choose from // and we have an "empty" option this.props.onChange(options[0].value) } else if (value !== undefined && value !== null && value !== defaultValue) { // set value to defaultValue this.props.onChange(defaultValue) } } } normalisedOptions() { return this.props.options.map(option => typeof option === 'string' ? { value: option, text: titleCase(option) } : option ) } renderOptions() { const empty = this.props.empty !== false && ( <option value={toString(this.props.defaultValue)} key={0}> {this.props.empty} </option> ) const options = this.normalisedOptions().map(({ value, text }, i) => ( <option key={i + 1} value={value}> {text} </option> )) return empty ? [empty, ...options] : options } render() { const { options, defaultValue, empty, coerceValueToOptions, readOnly, onChange, value, className, formValue, invalid, ...rest } = this.props return ( <label className={classnames('select', className)}> <select {...rest} value={toString(value)} disabled={readOnly} onChange={event => this.props.onChange(toValue(event.target.value, this.normalisedOptions()))}> {this.renderOptions()} </select> </label> ) } }