import { arrow, autoPlacement, FloatingArrow, offset, useClick, useDismiss, useFloating, useHover, useInteractions, useTransitionStyles, } from '@floating-ui/react'; import clsx from 'clsx'; import React, { useRef, useState } from 'react'; import Portal from '../portal/portal'; interface IPopover { children: React.ReactElement> /** The content of the popover */ content: React.ReactNode /** Should we remove padding on the Popover */ isFlush?: boolean /** Should the popover trigger via click or hover */ interaction?: 'click' | 'hover' /** Add a class to the reference (trigger) element */ referenceElementClassName?: string } /** * Popover * * Similar to tooltip, but requires a click and is used for larger blocks * of information. */ const Popover: React.FC = (props) => { const { children, content, referenceElementClassName, interaction = 'hover', isFlush = false } = props; const [isOpen, setIsOpen] = useState(false); const arrowRef = useRef(null); const { x, y, strategy, refs, context } = useFloating({ open: isOpen, onOpenChange: setIsOpen, placement: 'top', middleware: [ autoPlacement({ allowedPlacements: ['top', 'bottom'], }), offset(10), arrow({ element: arrowRef, }), ], }); const { isMounted, styles } = useTransitionStyles(context, { initial: { opacity: 0, transform: 'scale(0.8)', }, duration: { open: 200, close: 200, }, }); const click = useClick(context, { enabled: interaction === 'click' }); const hover = useHover(context, { enabled: interaction === 'hover' }); const dismiss = useDismiss(context); const { getReferenceProps, getFloatingProps } = useInteractions([ click, hover, dismiss, ]); return ( <> {React.cloneElement(children, { ref: refs.setReference, ...getReferenceProps(), className: clsx(children.props.className, referenceElementClassName), })} {(isMounted) && (
{content}
)} ); }; export default Popover;