wix-style-react
Version:
wix-style-react
101 lines • 4.05 kB
JavaScript
import React, { PureComponent } from 'react';
import PropTypes from 'prop-types';
import Popover from '../../Popover';
import { Mode } from './constants';
const controlledErrorMsg = method => `ClosablePopover.${method}() can not be called when component is Controlled. (opened prop should be undefined)`;
/**
* Closable Popover
* Either a normal Controlled Popover, or a Popover that is initially opened and can be the closed by
* calling a closeAction.
*/
class ClosablePopover extends PureComponent {
constructor() {
super(...arguments);
this.state = {
open: this.props.initiallyOpened,
mode: this.props.initiallyOpened ? Mode.ClickToClose : Mode.Hover,
};
this.open = () => this._doOpen(Mode.ClickToClose);
this._doOpen = nextMode => {
!this.state.open &&
this.setState({
open: true,
mode: nextMode,
}, () => {
this.props.onOpen && this.props.onOpen();
});
};
this.close = () => {
if (this._isControlled()) {
throw new Error(controlledErrorMsg('close'));
}
this.state.open &&
this.setState({
open: false,
mode: Mode.Hover,
}, () => {
this.props.onClose && this.props.onClose();
});
};
this._handleMouseEnter = () => {
if (this.state.mode === Mode.Hover) {
this._doOpen(Mode.Hover);
}
};
this._handleMouseLeave = () => {
if (this.state.mode === Mode.Hover && this.props.closeOnMouseLeave) {
this.close();
}
};
this.actions = {
close: this.close,
};
}
_isControlled() {
return typeof this.props.opened === 'boolean';
}
render() {
const { content, appearance, target, children, onClose, onOpen, initiallyOpened, closeOnMouseLeave, hideDelay, ...rest } = this.props;
const open = this._isControlled() ? this.props.opened : this.state.open;
const popoverProps = {
...rest,
animate: true,
theme: appearance,
shown: open,
onMouseEnter: this._handleMouseEnter,
onMouseLeave: this._handleMouseLeave,
};
return (React.createElement(Popover, { ...popoverProps },
React.createElement(Popover.Element, null, target),
React.createElement(Popover.Content, null, content(this.actions))));
}
}
ClosablePopover.defaultProps = {
hideDelay: 0,
initiallyOpened: true,
closeOnMouseLeave: true,
};
ClosablePopover.propTypes = {
/** Controls whether the popover's content is shown or not.
* When undefined, then the component is Uncontrolled,
* It is initially open, and it can be closed by close-action */
opened: PropTypes.bool,
/** Controls whether the popover's content is initially opened (in Uncontrolled mode only) */
initiallyOpened: PropTypes.bool,
/** The popover's target element*/
target: PropTypes.node.isRequired,
/** Callback to call when the popover content is requested to be opened (Uncontrolled mode only) */
onOpen: PropTypes.func,
/** callback to call when the popover content is requested to be closed (Uncontrolled mode only). NOTE: this callback is called when the close timeout (if exists) starts */
onClose: PropTypes.func,
/** Disable close on mouseLeave */
closeOnMouseLeave: PropTypes.bool,
/** The popover's content, given as a function that receives control-actions and renders the contet.
* In Uncontrolled mode, this function is still called only once.
*/
content: PropTypes.func.isRequired,
/** A css class to be applied to the component's root element */
className: PropTypes.string,
};
export default ClosablePopover;
//# sourceMappingURL=ClosablePopover.js.map