import cs from 'classnames' import _ from 'lodash' import React, { Component, ReactNode } from 'react' import { findDOMNode } from 'react-dom' interface Indexable { [key: string]: any } interface Props { className?: string chosen: Indexable others: Indexable[] onSelect: (item: Indexable) => any renderItem: (item: Indexable) => ReactNode keyProperty: string disabled?: boolean document: Document } class Dropdown extends Component { static defaultProps = { className: '', document, } state = { open: false } outsideClickHandler: (e: Event) => void = () => {} componentDidMount () { this.outsideClickHandler = (e: Event) => { if (!findDOMNode(this)?.contains(e.target as Node)) { this.setState({ open: false }) } } this.props.document.body.addEventListener('click', this.outsideClickHandler) } componentWillUnmount () { this.props.document.body.removeEventListener('click', this.outsideClickHandler) } render () { return (
  • {this._button()} {this._items()}
  • ) } _button () { if (this.props.others.length) { return ( ) } return ( {this._buttonContent()} ) } _buttonContent () { return ( <> {this.props.renderItem(this.props.chosen)}{' '} {this._caret()} ) } _caret () { if (!this.props.others.length || this.props.disabled) return null return ( Toggle Dropdown ) } _toggleOpen = () => { this.setState({ open: !this.state.open }) } _items () { if (!this.props.others.length || this.props.disabled) return null return ( ) } _onSelect (item: object) { const retval = this.props.onSelect(item) const open = _.isBoolean(retval) ? retval : false this.setState({ open }) } } export default Dropdown