buster/web/src/components/ui/tooltip/PopoverBase.tsx

76 lines
2.4 KiB
TypeScript
Raw Normal View History

2025-02-27 01:24:46 +08:00
'use client';
import * as React from 'react';
import * as PopoverPrimitive from '@radix-ui/react-popover';
import { cn } from '@/lib/utils';
2025-03-04 11:37:34 +08:00
import { useMemoizedFn } from 'ahooks';
export type PopoverTriggerType = 'click' | 'hover';
2025-02-27 01:24:46 +08:00
const Popover = PopoverPrimitive.Root;
2025-03-04 11:37:34 +08:00
interface PopoverProps extends React.ComponentPropsWithoutRef<typeof Popover> {
triggerType?: PopoverTriggerType;
}
const PopoverRoot: React.FC<PopoverProps> = ({ children, triggerType = 'click', ...props }) => {
const [isOpen, setIsOpen] = React.useState(false);
const handleMouseEnter = useMemoizedFn(() => {
if (triggerType === 'hover') {
setIsOpen(true);
}
});
const handleMouseLeave = useMemoizedFn(() => {
if (triggerType === 'hover') {
setIsOpen(false);
}
});
const content =
triggerType === 'hover' ? (
<div className="relative" onMouseEnter={handleMouseEnter} onMouseLeave={handleMouseLeave}>
<div className="absolute -inset-[4px]" />
<div className="relative z-10">{children}</div>
</div>
) : (
children
);
return (
<Popover {...props} open={triggerType === 'hover' ? isOpen : undefined}>
{content}
</Popover>
);
};
2025-02-27 01:24:46 +08:00
const PopoverTrigger = PopoverPrimitive.Trigger;
const PopoverContent = React.forwardRef<
React.ElementRef<typeof PopoverPrimitive.Content>,
React.ComponentPropsWithoutRef<typeof PopoverPrimitive.Content> & {
headerContent?: React.ReactNode;
}
>(({ className, align = 'center', children, sideOffset = 4, headerContent, ...props }, ref) => (
<PopoverPrimitive.Portal>
<PopoverPrimitive.Content
ref={ref}
align={align}
sideOffset={sideOffset}
className={cn(
'bg-popover text-popover-foreground',
'w-fit rounded border shadow outline-none',
2025-02-27 06:30:46 +08:00
'data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50'
2025-02-27 01:24:46 +08:00
)}
{...props}>
{headerContent && <>{headerContent}</>}
2025-02-27 06:30:46 +08:00
<div className={cn('p-2.5', className)}>{children}</div>
2025-02-27 01:24:46 +08:00
</PopoverPrimitive.Content>
</PopoverPrimitive.Portal>
));
PopoverContent.displayName = PopoverPrimitive.Content.displayName;
2025-03-04 11:37:34 +08:00
export { PopoverRoot, PopoverTrigger, PopoverContent };