import { cloneElement, forwardRef, useState, type ElementRef, type ReactNode } from 'react'; import { composeEventHandlers } from '@radix-ui/primitive'; import * as PopperPrimitive from '@radix-ui/react-popper'; import { Portal } from '@radix-ui/react-portal'; import { useControllableState } from '@radix-ui/react-use-controllable-state'; import { useClickOutside } from '../../hooks/useClickOutSide'; import { type ElementProps, type VisibleState } from '../../types'; import { cn } from '../../utils/cn'; const PopperRoot = PopperPrimitive.Root; const PopperAnchor = PopperPrimitive.Anchor; const PopperArrow = PopperPrimitive.Arrow; export interface PopperRootProps extends ElementProps {} export interface PopperArrowProps extends ElementProps {} export interface PopperAnchorProps extends ElementProps {} export interface PopperContentProps extends ElementProps { unstyled?: boolean; fitContent?: boolean; } const PopperContent = forwardRef, PopperContentProps>( ({ className, unstyled, fitContent, ...props }, ref) => { return ( ); } ); export interface PopperProps extends PopperContentProps, VisibleState { trigger?: ReactNode; arrow?: boolean; unstyled?: boolean; fitContent?: boolean; } const Popper = forwardRef, PopperProps>((props, ref) => { const { open: openProp, arrow, defaultOpen, className, onOpenChange, trigger, children, sideOffset = 8, align = 'start', side = 'bottom', unstyled, fitContent, ...etc } = props; const [opened, setOpen] = useControllableState({ prop: openProp, defaultProp: defaultOpen, onChange: onOpenChange, }); const [anchorRef, setAnchorRef] = useState(null); const [contentRef, setContentRef] = useState(null); const close = () => { setOpen(false); }; const open = () => { setOpen(true); }; useClickOutside(close, null, [contentRef, anchorRef] as any); return ( {cloneElement(trigger as any, { onClick: composeEventHandlers(open, (trigger as any)?.props?.onClick), 'aria-expanded': opened, })} {opened && (
{children}
{arrow ? : null}
)}
); }); const PopperFreeSolo = forwardRef, PopperProps>((props, ref) => { const { open: openProp, arrow, defaultOpen, className, onOpenChange, trigger, children, sideOffset = 8, align = 'start', side = 'bottom', unstyled, fitContent, ...etc } = props; const [open, setOpen] = useControllableState({ prop: openProp, defaultProp: defaultOpen, onChange: onOpenChange, }); const [anchorRef, setAnchorRef] = useState(null); const [contentRef, setContentRef] = useState(null); const close = () => { setOpen(false); }; useClickOutside(close, null, [contentRef, anchorRef] as any); return ( {trigger} {open && (
{children}
{arrow ? : null}
)}
); }); export { Popper, PopperAnchor, PopperArrow, PopperContent, PopperFreeSolo, PopperRoot };