import { useState, useRef } from 'react';
import Link from 'next/link';
import { useRouter } from 'next/router';
import { Transition } from 'react-transition-group';
import { IconChevronDown } from '@/components/icons';
import { useOnClickOutside } from '@/hooks/useClickOutside';
import { useWindowSize } from '@/hooks/useDimension';
/*
* label - dropdown button label
* subMenu - submenu array
* hoverTrigger - whether dropdown should open on hover on click
* className - tailwind classes need to pass to the dropdown
*/
export default function Dropdown({ label, subMenu, hoverTrigger, className, ...props }) {
const router = useRouter();
const { width } = useWindowSize();
const [open, setOpen] = useState(false);
const dropDown = useRef(null);
useOnClickOutside(dropDown, () => setOpen(false));
let classes = '';
if (className) {
classes += ' ' + className;
}
/* Dropdown animation */
const dropDownMenu = useRef(null);
const defaultClasses = `top-full w-[282px] rounded-lg origin-top-left bg-primary-bg transition-all duration-300 absolute left-0 z-20`;
const openClasses = {
entering: `opacity-100 delay-100 scale-100`,
entered: `opacity-100 scale-100`,
exiting: `opacity-0 scale-90`,
exited: `opacity-0 scale-90`
};
const openClassesOverlay = {
entering: `opacity-100 delay-100`,
entered: `opacity-100`,
exiting: `opacity-0`,
exited: `opacity-0`
};
return (
<div className={classes} ref={dropDown} onMouseEnter={() => hoverTrigger && setOpen(true)} onMouseLeave={() => hoverTrigger && setOpen(false)}>
<button onClick={() => !hoverTrigger && setOpen((open) => !open)} className={`flex items-center text-3xs sm:text-sm px-1 sm:px-3 md:px-4 whitespace-nowrap noSelect leading-5 hover:md:text-white active:text-white font-medium transition-colors duration-200 w-full justify-center flex-col lg:flex-row bg-primary-bg relative z-30 ${Component ? `py-4 lg:py-5` : `py-5 lg:py-[22px]`} ${open ? `text-grey-text` : subMenu.map((sm) => sm.url).includes(router.pathname) ? `text-white/80` : `text-secondary-text`}`}>
{label}
{!hoverTrigger && <IconChevronDown />}
</button>
<Transition in={open} mountOnEnter timeout={500} unmountOnExit nodeRef={dropDownMenu}>
{(state) => (
<>
<div ref={dropDownMenu} className={`${defaultClasses} ${openClasses[state]}`}>
<ul className={`border p-3 border-[#191026] rounded-lg`}>
{subMenu.map((menu, index) => {
return (
<li key={index} className="py-0.5">
<Link href={menu.url} onClick={() => setOpen(false)} className={`py-3 px-4 flex text-sm group leading-6 text-white hover:bg-[#191026] rounded transition-colors duration-200 noSelect ${router.pathname == menu.url ? `bg-[#191026]` : ``}`}>
<div className={`${menu.icon ? `pl-4` : ``}`}>
<h6>{menu.label}</h6>
</div>
</Link>
</li>
);
})}
</ul>
</div>
</>
)}
</Transition>
</div>
);
}
Note: useOnClickOutside, useWindowSize hooks code will be in
Some usefull react hooks – window size, click outside, intersection observer
Top comments