import * as React from 'react'; import classnames from 'classnames'; import styles from './Popup.sass'; import IReactComponentProps from '../../../common/structures/IReactComponentProps'; import cloneNodes from '../../../utils/cloneNodes'; /** * Try catch for Local vs. Styleguidist */ declare let __non_webpack_require__: any; let ReactDOM: any; try { ReactDOM = __non_webpack_require__('react-dom'); } catch (e) { ReactDOM = require('react-dom'); } interface IProps extends IReactComponentProps { items?: any[]; offsetX?: string; offsetY?: string; padding?: boolean; position?: 'bottom' | 'right' | 'top'; triggerContent?: React.ReactNode; triggerAble?: boolean; closeOnPopupClick?: boolean; centerTail?: boolean; closeOnTrigger?: boolean; } interface IState { open: boolean; tipItemHover: boolean; } export default class Popup extends React.Component { static defaultProps = { items: [], padding: true, position: 'bottom', triggerAble: true, closeOnPopupClick: true, centerTail: false, closeOnTrigger: true, }; constructor (props: IProps) { super(props); this.state = { open: false, tipItemHover: false, }; this.onClick = this.onClick.bind(this); this.onClickOutside = this.onClickOutside.bind(this); this.maybeClose = this.maybeClose.bind(this); } componentDidMount () { document.addEventListener('click', this.onClickOutside, true); } componentWillUnmount () { document.removeEventListener('click', this.onClickOutside, true); } onClick () { const { open } = this.state; const { triggerAble, closeOnPopupClick } = this.props; if ((!open && !triggerAble) || (open && !closeOnPopupClick)) { return; } this.setState({ open: !this.state.open, }); } onClickOutside (event: any) { try { const domNode = ReactDOM.findDOMNode(this); if (!domNode || !domNode.contains(event.target)) { this.setState({ open: false, }); } } catch (error) {} } maybeClose (event: any) { if (this.props.closeOnTrigger) this.handleClose(); } handleClose = () => this.setState({ open: false }); render () { const transformStyles = [ ...(this.props.offsetX ? [`translateX(${this.props.offsetX})`] : []), ...(this.props.offsetY ? [`translateY(${this.props.offsetY})`] : []), ]; return (
{/** * Clone children and pass a handler function to close the Popup so child nodes can control closing the popup if necessary */} {cloneNodes(this.props.children, { handleClosePopup: this.handleClose })}
{/** * Clone top level triggerContents elements and pass this.state to them * This will allow triggerContents to be state aware to make appropriate styling decisions, etc. */}
{cloneNodes(this.props.triggerContent, { popupState: { ...this.state }})}
); } }