import React from 'react';
import PropTypes from 'prop-types';
import cx from 'classnames';
import { Icon } from '@procore/core-react';
import { findDOMNode } from 'react-dom';
import baseStyles from './OverflowMenu.scss';
import composeStyles from '../../shared/stylesheetComposer';
import InlinePortal from './InlinePortal';
import DropdownContent from './DropdownContent';
export default class OverflowMenu extends React.Component {
static propTypes = {
stylesheets: PropTypes.arrayOf(PropTypes.shape()),
placement: PropTypes.oneOf(['left', 'right'])
};
static defaultProps = {
stylesheets: [],
placement: 'right'
};
constructor(props) {
super(props);
this.styles = composeStyles(baseStyles, props.stylesheets);
this.state = { expanded: false };
}
componentDidUpdate(_, prevState) {
if (this.state.expanded && !prevState.expanded) {
window.addEventListener('click', this.closeDropdown, true);
} else if (!this.state.expanded && prevState.expanded) {
window.removeEventListener('click', this.closeDropdown, true);
}
}
closeDropdown = (evt) => {
if (!this.ellipsis.contains(evt.target) && !this.dropdown.contains(evt.target)) {
this.setState({ expanded: false });
}
};
toggleMenu = () => {
this.setState({ expanded: !this.state.expanded });
};
itemClickHandler = handler => (e) => {
this.setState({ expanded: false });
if (handler && typeof handler === 'function') {
handler(e);
}
};
setLeft = (dropdownLeft) => {
this.dropdown.style.left = `${Math.ceil(dropdownLeft)}px`;
};
setTop = (dropdownTop) => {
const top = dropdownTop + window.pageYOffset;
this.dropdown.style.top = `${Math.ceil(top)}px`;
};
position = () => {
const {
left: dropdownLeft,
bottom: dropdownTop,
width: ellipsisWidth
} = this.ellipsis.getBoundingClientRect();
const leftPosition = this.props.placement === 'left' ?
dropdownLeft + (ellipsisWidth - this.dropdown.clientWidth) :
dropdownLeft;
this.setLeft(leftPosition);
this.setTop(dropdownTop);
};
render() {
const styles = this.styles;
const { expanded } = this.state;
return (
[
<div
key='ellipsis'
className={cx(
styles.iconContainer,
{
[styles.expanded]: expanded
}
)}
ref={elem => this.ellipsis = elem}
onClick={this.toggleMenu}
>
<Icon icon={'ellipsis-v'} />
</div>,
<InlinePortal show={expanded} key='portal'>
<DropdownContent
styles={styles}
onItemClick={this.itemClickHandler}
ref={(el) => {
if (el) {
this.dropdown = findDOMNode(el);
this.position();
}
}}
>
{this.props.children}
</DropdownContent>
</InlinePortal>
]
);
}
}
|