in packages/docusaurus-theme-classic/src/theme/NavbarItem/DropdownNavbarItem.tsx [51:131]
function DropdownNavbarItemDesktop({
items,
position,
className,
...props
}: DesktopOrMobileNavBarItemProps) {
const dropdownRef = useRef<HTMLDivElement>(null);
const [showDropdown, setShowDropdown] = useState(false);
useEffect(() => {
const handleClickOutside = (event: MouseEvent | TouchEvent) => {
if (
!dropdownRef.current ||
dropdownRef.current.contains(event.target as Node)
) {
return;
}
setShowDropdown(false);
};
document.addEventListener('mousedown', handleClickOutside);
document.addEventListener('touchstart', handleClickOutside);
return () => {
document.removeEventListener('mousedown', handleClickOutside);
document.removeEventListener('touchstart', handleClickOutside);
};
}, [dropdownRef]);
return (
<div
ref={dropdownRef}
className={clsx('navbar__item', 'dropdown', 'dropdown--hoverable', {
'dropdown--right': position === 'right',
'dropdown--show': showDropdown,
})}>
<NavbarNavLink
aria-haspopup="true"
aria-expanded={showDropdown}
role="button"
href={props.to ? undefined : '#'}
className={clsx('navbar__link', className)}
{...props}
onClick={props.to ? undefined : (e) => e.preventDefault()}
onKeyDown={(e) => {
if (e.key === 'Enter') {
e.preventDefault();
setShowDropdown(!showDropdown);
}
}}>
{props.children ?? props.label}
</NavbarNavLink>
<ul className="dropdown__menu">
{items.map((childItemProps, i) => (
<NavbarItem
isDropdownItem
onKeyDown={(e) => {
if (i === items.length - 1 && e.key === 'Tab') {
e.preventDefault();
setShowDropdown(false);
const nextNavbarItem = dropdownRef.current!.nextElementSibling;
if (nextNavbarItem) {
const targetItem =
nextNavbarItem instanceof HTMLAnchorElement
? nextNavbarItem
: // Next item is another dropdown; focus on the inner
// anchor element instead so there's outline
nextNavbarItem.querySelector('a');
(targetItem as HTMLElement).focus();
}
}
}}
activeClassName={dropdownLinkActiveClass}
{...childItemProps}
key={i}
/>
))}
</ul>
</div>
);
}