import type React from 'react'; import { Popover } from '@base-ui/react/popover'; import cs from 'classnames'; import classes from './Popup.module.scss'; type Side = 'top' | 'bottom' | 'left' | 'right'; type Align = 'start' | 'center' | 'end'; type Placement = Side | `${Side}-${Exclude}`; type PortalContainer = React.ComponentPropsWithoutRef['container']; type FocusTarget = React.ComponentPropsWithoutRef['finalFocus']; /** * Details carried by every open-state change. Exposes `reason` (why the state * changed) and `cancel()` (to veto Base UI's default dismiss handling), which * are required to filter out spurious closes such as the dismiss that fires on * the very interaction that opens an anchor-driven (non-trigger) popup. */ export type PopupOpenChangeDetails = Popover.Root.ChangeEventDetails; interface PopupProps { open: boolean; onOpenChange?: (open: boolean, eventDetails: PopupOpenChangeDetails) => void; anchor: Element | null; placement?: Placement; offset?: number; /** Parent element for the Base UI portal. Defaults to document.body. */ container?: PortalContainer; modal?: boolean; /** * Determines the element to focus when the popover is opened. * Passed through to Base UI `Popover.Popup`. Defaults to Base UI behavior. */ initialFocus?: FocusTarget; /** * Determines the element to focus when the popover is closed. * Pass `false` to disable the default return-focus behavior. */ finalFocus?: FocusTarget; className?: string; style?: React.CSSProperties; children: React.ReactNode; } function splitPlacement(placement: Placement): { side: Side; align: Align } { const [side, align] = placement.split('-') as [Side, Align | undefined]; return { side, align: align ?? 'center' }; } function Popup(props: PopupProps) { const { anchor, open = false, onOpenChange, placement = 'top', offset = 10, container, modal = false, initialFocus = false, finalFocus = false, className, style, children, } = props; if (!anchor) { return null; } const { side, align } = splitPlacement(placement); const positioner = ( {children} ); return ( {positioner} ); } export { Popup, };