import React, { useState, useEffect, useRef } from 'react'; import { usePopper } from 'react-popper'; export interface IPopover { children: React.ReactNode; className?: string; placement?: 'top' | 'top-start' | 'top-end' | 'right' | 'bottom' | 'bottom-start' | 'bottom-end' | 'left'; show?: boolean; target?: React.RefObject; onHide?(): void; onClick?(): void; [x: string]: any; } export const Popover: React.FC = (props) => { const { children, className, placement = 'top', show, target, onHide, onClick, ...otherProps } = props; const refSelfTarget = useRef(null); const [referenceElement, setReferenceElement] = useState(null); const [popperElement, setPopperElement] = useState(null); const [arrowElement, setArrowElement] = useState(null); const { styles, attributes } = usePopper(referenceElement, popperElement, { placement: placement, modifiers: [ { name: 'arrow', options: { element: arrowElement } }, { name: 'offset', options: { offset: [0, 10], }, }, ], }); const getClassNames = (): string => { let classList = `b-popover`; if (className) classList += ` ${className}`; return classList; }; const handleClickOutside = (e: Event) => { if (popperElement.contains(e.target)) { return; } else { onHide && onHide(); } }; useEffect(() => { if (target && target.current) { setReferenceElement(target.current); } else { setReferenceElement(refSelfTarget.current); } }, []); useEffect(() => { if (show) { document.addEventListener('click', handleClickOutside); setTimeout(() => { popperElement && popperElement.classList.add('is-visible'); }, 0); } else { document.removeEventListener('click', handleClickOutside); setTimeout(() => { popperElement && popperElement.classList.remove('is-visible'); }, 0); } return () => { document.removeEventListener('click', handleClickOutside); }; }, [show, popperElement]); if (show === false) { return null; } if (target) { return (
{children}
); } else { return (
{children}
); } };