import { useState, useRef, useEffect, cloneElement } from 'react'; import { Button } from 'react-bootstrap'; import { AnimatePresence, motion as _motion } from 'framer-motion'; import '@/css/AnimatedDropdown.css'; const AnimatedDropend = ({ trigger, icon, variant = "secondary", className = "", buttonStyle = "", show, onToggle, onMouseEnter, onMouseLeave, children }) => { const isControlled = show !== undefined; const [open, setOpen] = useState(false); const triggerRef = useRef(null); const dropdownRef = useRef(null); const actualOpen = isControlled ? show : open; const toggle = (forceValue) => { const newState = typeof forceValue === "boolean" ? forceValue : !actualOpen; if (!isControlled) setOpen(newState); onToggle?.(newState); }; useEffect(() => { const handleClickOutside = (e) => { if ( dropdownRef.current && !dropdownRef.current.contains(e.target) && !triggerRef.current?.contains(e.target) ) { if (!isControlled) setOpen(false); onToggle?.(false); } }; document.addEventListener("mousedown", handleClickOutside); return () => document.removeEventListener("mousedown", handleClickOutside); }, [isControlled, onToggle]); const handleMouseEnter = () => { if (!isControlled) setOpen(true); onToggle?.(true); onMouseEnter?.(); }; const handleMouseLeave = () => { if (!isControlled) setOpen(false); onToggle?.(false); onMouseLeave?.(); }; const triggerElement = trigger ? (typeof trigger === "function" ? trigger({ onClick: toggle, ref: triggerRef }) : cloneElement(trigger, { onClick: toggle, ref: triggerRef })) : ( ); const dropdownClasses = `dropdown-menu show shadow rounded-4 px-2 py-2 ${className}`; return (
{triggerElement} {actualOpen && ( <_motion.div ref={dropdownRef} initial={{ opacity: 0, x: -10 }} animate={{ opacity: 1, x: 0 }} exit={{ opacity: 0, x: -10 }} transition={{ duration: 0.15 }} className={dropdownClasses} style={{ position: 'absolute', top: '0', left: '100%', zIndex: 1000, whiteSpace: 'nowrap' }} > {typeof children === "function" ? children({ closeDropdown: () => toggle(false) }) : children} )}
); }; export default AnimatedDropend;