Spaces:
Build error
Build error
import { Popover, Transition } from '@headlessui/react' | |
import { Fragment, cloneElement, useRef } from 'react' | |
import s from './style.module.css' | |
import cn from '@/utils/classnames' | |
export type HtmlContentProps = { | |
onClose?: () => void | |
onClick?: () => void | |
} | |
type IPopover = { | |
className?: string | |
htmlContent: React.ReactElement<HtmlContentProps> | |
popupClassName?: string | |
trigger?: 'click' | 'hover' | |
position?: 'bottom' | 'br' | 'bl' | |
btnElement?: string | React.ReactNode | |
btnClassName?: string | ((open: boolean) => string) | |
manualClose?: boolean | |
disabled?: boolean | |
} | |
const timeoutDuration = 100 | |
export default function CustomPopover({ | |
trigger = 'hover', | |
position = 'bottom', | |
htmlContent, | |
popupClassName, | |
btnElement, | |
className, | |
btnClassName, | |
manualClose, | |
disabled = false, | |
}: IPopover) { | |
const buttonRef = useRef<HTMLButtonElement>(null) | |
const timeOutRef = useRef<NodeJS.Timeout | null>(null) | |
const onMouseEnter = (isOpen: boolean) => { | |
timeOutRef.current && clearTimeout(timeOutRef.current) | |
!isOpen && buttonRef.current?.click() | |
} | |
const onMouseLeave = (isOpen: boolean) => { | |
timeOutRef.current = setTimeout(() => { | |
isOpen && buttonRef.current?.click() | |
}, timeoutDuration) | |
} | |
return ( | |
<Popover className="relative"> | |
{({ open }: { open: boolean }) => { | |
return ( | |
<> | |
<div | |
{...(trigger !== 'hover' | |
? {} | |
: { | |
onMouseLeave: () => onMouseLeave(open), | |
onMouseEnter: () => onMouseEnter(open), | |
})} | |
> | |
<Popover.Button | |
ref={buttonRef} | |
disabled={disabled} | |
className={`group ${s.popupBtn} ${open ? '' : 'bg-gray-100'} ${!btnClassName | |
? '' | |
: typeof btnClassName === 'string' | |
? btnClassName | |
: btnClassName?.(open) | |
}`} | |
> | |
{btnElement} | |
</Popover.Button> | |
<Transition as={Fragment}> | |
<Popover.Panel | |
className={cn( | |
s.popupPanel, | |
position === 'bottom' && '-translate-x-1/2 left-1/2', | |
position === 'bl' && 'left-0', | |
position === 'br' && 'right-0', | |
className, | |
)} | |
{...(trigger !== 'hover' | |
? {} | |
: { | |
onMouseLeave: () => onMouseLeave(open), | |
onMouseEnter: () => onMouseEnter(open), | |
}) | |
} | |
> | |
{({ close }) => ( | |
<div | |
className={cn(s.panelContainer, popupClassName)} | |
{...(trigger !== 'hover' | |
? {} | |
: { | |
onMouseLeave: () => onMouseLeave(open), | |
onMouseEnter: () => onMouseEnter(open), | |
}) | |
} | |
> | |
{cloneElement(htmlContent as React.ReactElement<HtmlContentProps>, { | |
onClose: () => onMouseLeave(open), | |
...(manualClose | |
? { | |
onClick: close, | |
} | |
: {}), | |
})} | |
</div> | |
)} | |
</Popover.Panel> | |
</Transition> | |
</div> | |
</> | |
) | |
}} | |
</Popover> | |
) | |
} | |