UNPKG

phoenix-components-library

Version:

Component library for Phoenix Frontend Projects.

139 lines (115 loc) 3.16 kB
import React, { Component } from "react"; import PropTypes from "prop-types"; import { Input } from "../Input/Input.jsx"; import { Option } from "./Option.jsx"; import "./Select.css"; const ESC_KEY_CODE = 27; const OptionShape = PropTypes.shape({ name: PropTypes.string, value: PropTypes.string }); class Select extends Component { selectDomElement = null; static propTypes = { placeholder: PropTypes.string, default: OptionShape, options: PropTypes.arrayOf(OptionShape), selectHandler: PropTypes.func, includeNone: PropTypes.bool }; static defaultProps = { placeholder: "Select", default: {}, options: [], selectHandler: () => {}, includeNone: false }; state = { open: false, selected: {} }; static getDerivedStateFromProps = (nextProps, prevState) => { if (prevState.selected.value) { return null; } return { selected: nextProps.default }; }; openDropdown = () => this.setState({ open: true }); closeOnEsc = ({ keyCode }) => ESC_KEY_CODE === keyCode && this.setState({ open: false }); closeOnClick = ({ target }) => this.setState({ open: this.selectDomElement.contains(target) }); componentDidMount() { window.addEventListener("click", this.closeOnClick); window.addEventListener("keyup", this.closeOnEsc); } componentWillUnmount() { window.removeEventListener("click", this.closeOnClick); window.removeEventListener("keyup", this.closeOnEsc); } onOptionClick = value => { const { options, selectHandler } = this.props; if (value === "none") { return this.selectNone(); } const selected = options.reduce( (selectedOption, option) => option.value === value ? option : selectedOption, {} ); this.setState({ selected }); return selectHandler(selected); }; selectNone = () => { const { selectHandler } = this.props; this.setState({ selected: { name: "None", value: "none" } }); return selectHandler({ name: "None", value: null }); }; render() { const { options, placeholder, includeNone } = this.props; return ( <div className="es-selector"> <div className="es-selector-input" ref={elem => (this.selectDomElement = elem)} onClick={this.openDropdown} > <Input type="text" name={placeholder} className="es-select-icon" value={this.state.selected.name} disabled /> </div> {this.state.open && ( <div className="es-selector-options"> {includeNone && ( <Option onClickHandler={this.selectNone} value="none" name="None" /> )} {options.map(({ name, value }) => ( <Option onClickHandler={this.onOptionClick} name={name} key={value} value={value} /> ))} </div> )} </div> ); } } export { Select };