import React from 'react' interface DropdownMenuProps { alwaysPressed?: boolean applyEntity?: any applyPseudoSelection?: any currentColor?: string currentOption?: string defaultOption?: string isApplied?: boolean menuDirection?: string options?: any removeEntity?: any renderStyleButton?: any styleCategory?: string styleType?: string toggleColorStyle?: any } interface DropdownMenuState { isExpanded: boolean, menuStyles?: any textValue?: string } export default class _DropdownMenu extends React.Component { constructor(props) { super(props); this.state = { ...this.defaultState() }; this.handleMouseDown = this.handleMouseDown.bind(this); } // SETUP ----- defaultState() { return { isExpanded: false, }; } // LIFECYCLE componentDidMount() { $(':root').on('mousedown', this.handleMouseDown); } componentWillUnmount() { $(':root').off('mousedown', this.handleMouseDown); } // PUBLIC ----- toggleExpansion() { this.setState({ isExpanded: !this.state.isExpanded }); } handleClickInside() { // When you click ON/IN the BUTTON } handleClickOutside() { // When you click OUTSIDE (but not counting the menu) } // TOGGLE FUNCTIONALITY ----- handleMouseDown(e) { const { button, menu } = this.refs; if (!button) { throw(`Error: Got no 'button' reference in ${this.constructor.name}`) } if (!menu) { throw(`Error: Got no 'menu' reference in ${this.constructor.name}`) } if (this._clickIsInsideButton(e)) { e.stopPropagation(); this.toggleExpansion(); this.handleClickInside(); } else if (this._clickIsInsideMenu(e)) { return; } else { this.setState({ isExpanded: false }); this.handleClickOutside(); } } // PRIVATE HELPERS ----- _clickIsInsideButton(e) { const { button } = this.refs return button && button["contains"](e.target); } _clickIsInsideMenu(e) { const { menu } = this.refs; return menu && menu["contains"](e.target); } }