import React, { useState } from 'react'; import { useFloating, offset, shift, flip, arrow, Placement, Middleware } from '@floating-ui/react'; export type PopoverProps = { title?: React.ReactNode; content: React.ReactNode; placement?: Placement; children: React.ReactElement; className?: string; }; /** * Popover using floating-ui. Controlled by hover/focus. */ export function Popover({ title, content, placement = 'top', children, className = '' }: PopoverProps) { const [open, setOpen] = useState(false); const [arrowEl, setArrowEl] = useState(null); const middleware: Middleware[] = [offset(8), flip(), shift()]; if (arrowEl) middleware.push(arrow({ element: arrowEl })); const { x, y, refs, strategy, middlewareData, placement: finalPlacement } = useFloating({ open, onOpenChange: setOpen, placement, middleware }); const staticSide = { top: 'bottom', right: 'left', bottom: 'top', left: 'right' }[finalPlacement.split('-')[0]] as string; return ( <> {React.cloneElement(children, { ref: refs.setReference, onMouseEnter: () => setOpen(true), onMouseLeave: () => setOpen(false), onFocus: () => setOpen(true), onBlur: () => setOpen(false) })} {open ? (
{title ? (
{title}
) : null}
{content}
) : null} ); }