phoenix-components-library
Version:
Component library for Phoenix Frontend Projects.
139 lines (115 loc) • 3.16 kB
JSX
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 };