// External dependencies
import React from 'react';
import PropTypes from 'prop-types';
import noop from 'lodash/noop';
import classnames from 'classnames';
// Local dependencies
import { ANIMATION_FOLD, ANIMATION_POPUP, ETCorePopup } from '@core-ui/components/popups/popup';
import { composeRef } from '@core-ui/utils/utils';
import './dropdown.scss';
const CLICK_MODE = 'click';
const HOVER_MODE = 'hover';
const getDefaultDocument = () => window.document;
class ETCoreDropdown extends React.PureComponent {
static propTypes = {
animation: PropTypes.oneOf([ANIMATION_FOLD, ANIMATION_POPUP]),
closeOnClick: PropTypes.bool,
disabled: PropTypes.bool,
getDocument: PropTypes.func,
menu: PropTypes.element,
offsetH: PropTypes.number,
offsetV: PropTypes.number,
onClick: PropTypes.func,
onMouseEnter: PropTypes.func,
onMouseLeave: PropTypes.func,
onVisibleChange: PropTypes.func,
onSelect: PropTypes.func,
open: PropTypes.bool,
trigger: PropTypes.oneOf([CLICK_MODE, HOVER_MODE]),
};
static defaultProps = {
animation: ANIMATION_FOLD,
closeOnClick: false,
disabled: false,
getDocument: getDefaultDocument,
menu: false,
offsetH: 0,
offsetV: 0,
onClick: noop,
onMouseEnter: noop,
onMouseLeave: noop,
onVisibleChange: noop,
trigger: CLICK_MODE,
};
constructor(props) {
super(props);
this.triggerRef = React.createRef();
this.state = {
isVisible: false,
};
}
get visible() {
const { open } = this.props;
return undefined !== open ? open : this.state.isVisible;
}
setVisible(isVisible) {
const { open, onVisibleChange } = this.props;
if (undefined === open) {
this.setState({
isVisible,
});
}
onVisibleChange(isVisible);
}
handleTriggerClick = (e) => {
const {
trigger,
onClick,
open,
closeOnClick,
} = this.props;
if (CLICK_MODE === trigger) {
if (closeOnClick) {
const opened = undefined !== open ? open : this.state.isVisible;
this.setVisible(!opened);
} else {
this.setVisible(true);
}
}
onClick(e);
};
handleMouseEnter = (e) => {
const {
trigger,
onMouseEnter,
} = this.props;
if (HOVER_MODE === trigger) {
this.setVisible(true);
}
onMouseEnter(e);
};
handleMouseLeave = (e) => {
const {
trigger,
onMouseLeave,
} = this.props;
if (HOVER_MODE === trigger) {
this.setVisible(false);
}
onMouseLeave(e);
};
onSelect = (value) => {
const { onSelect } = this.props;
this.setVisible(false);
onSelect(value);
};
close = () => {
this.setVisible(false);
};
renderMenu() {
if (!this.visible) {
return null;
}
const { menu, animation, offsetV, getDocument } = this.props;
const triggerWidth = this.triggerRef.current ? this.triggerRef.current.offsetWidth : 0;
const child = React.Children.only(menu);
const menuCloned = React.cloneElement(child, {
style: {
...child.props.style,
width: child.props.style && child.props.style.width ? child.props.style.width : triggerWidth
},
onSelect: this.onSelect,
});
return (
{menuCloned}
)
}
render() {
const {
children,
disabled,
} = this.props;
const child = React.Children.only(children);
const trigger = React.cloneElement(child, {
className: classnames(child.props.className, 'et-core-control-dropdown'),
onClick: this.handleTriggerClick,
onMouseEnter: this.handleMouseEnter,
onMouseLeave: this.handleMouseLeave,
ref: composeRef(child.ref, this.triggerRef),
disabled,
});
const menu = this.renderMenu();
return (
{trigger}
{menu}
);
}
}
export default ETCoreDropdown;