'use client'; import { useRef, useState } from 'react'; import { useFloating, autoUpdate, offset, flip, shift, arrow, useHover, useFocus, useClick, useDismiss, useRole, useInteractions, FloatingPortal, FloatingArrow, } from '@floating-ui/react'; import styles from './InfoPopover.module.css'; export interface InfoPopoverProps { label?: string; plain?: string; detail?: string; ariaLabel?: string; } export function InfoPopover({ label, plain, detail, ariaLabel }: InfoPopoverProps) { const [open, setOpen] = useState(false); const arrowRef = useRef(null); const { refs, floatingStyles, context } = useFloating({ open, onOpenChange: setOpen, placement: 'top', whileElementsMounted: autoUpdate, middleware: [ offset(8), flip({ fallbackAxisSideDirection: 'start' }), shift({ padding: 8 }), arrow({ element: arrowRef, padding: 8 }), ], }); // Hover (desktop) with a short open delay, keyboard focus, tap (touch), // outside-press + Escape to dismiss. Floating UI disables hover on touch, // so tap and hover never double-fire. const hover = useHover(context, { delay: { open: 100, close: 0 } }); const focus = useFocus(context); const click = useClick(context); const dismiss = useDismiss(context); const role = useRole(context, { role: 'tooltip' }); const { getReferenceProps, getFloatingProps } = useInteractions([ hover, focus, click, dismiss, role, ]); if (!plain) return null; return ( <> {open && (
{label && {label}} {plain} {detail && {detail}}
)} ); }