menu close on click outside

This commit is contained in:
Owen Rees
2023-06-16 12:35:06 +02:00
parent bffb9c1548
commit 7450bc82e3
2 changed files with 43 additions and 5 deletions
+4 -1
View File
@@ -1,13 +1,15 @@
"use client";
import HamburgerMenu from "@/components/HamburgerMenu";
import { useState } from "react";
import { useRef, useState } from "react";
const Hamburger = () => {
const [menuVisible, setMenuVisible] = useState(false);
const hamburgerButtonRef = useRef<HTMLDivElement>(null);
return (
<>
<div
ref={hamburgerButtonRef}
className="space-y-2 relative z-[99999]"
onClick={() => setMenuVisible(!menuVisible)}
>
@@ -31,6 +33,7 @@ const Hamburger = () => {
<HamburgerMenu
menuVisible={menuVisible}
setMenuVisible={setMenuVisible}
hamburgerButtonRef={hamburgerButtonRef}
/>
}
</>
+39 -4
View File
@@ -1,15 +1,49 @@
import Link from "next/link";
import ThemeSwitcher from "@/components/ThemeSwitcher";
import { Dispatch, SetStateAction, useEffect, useRef, useState } from "react";
import {
Dispatch,
RefObject,
SetStateAction,
useEffect,
useRef,
useState,
} from "react";
type menuState = {
type hamburgerMenuState = {
menuVisible: boolean;
setMenuVisible: Dispatch<SetStateAction<boolean>>;
hamburgerButtonRef: RefObject<HTMLDivElement>;
};
const HamburgerMenu = ({ menuVisible, setMenuVisible }: menuState) => {
const HamburgerMenu = ({
menuVisible,
setMenuVisible,
hamburgerButtonRef,
}: hamburgerMenuState) => {
const [mouseOverMenu, setMouseOverMenu] = useState(false);
const timeoutRef = useRef<NodeJS.Timeout | undefined>();
const menuRef = useRef<HTMLDivElement>(null);
useEffect(() => {
const handleMouseDownOutsideMenu = (event: MouseEvent) => {
if (
menuVisible &&
menuRef.current &&
!menuRef.current.contains(event.target as Node) &&
hamburgerButtonRef.current &&
!hamburgerButtonRef.current.contains(event.target as Node)
) {
setMenuVisible(false);
setMouseOverMenu(false);
}
};
document.addEventListener("mousedown", handleMouseDownOutsideMenu);
return () => {
document.removeEventListener("mousedown", handleMouseDownOutsideMenu);
};
}, [menuVisible]);
useEffect(() => {
if (menuVisible && !mouseOverMenu) {
@@ -17,7 +51,7 @@ const HamburgerMenu = ({ menuVisible, setMenuVisible }: menuState) => {
} else {
clearTimeout(timeoutRef.current);
}
}, [mouseOverMenu]);
}, [mouseOverMenu, menuVisible]);
const handleMouseEnterMenu = () => {
setMouseOverMenu(true);
@@ -38,6 +72,7 @@ const HamburgerMenu = ({ menuVisible, setMenuVisible }: menuState) => {
return (
<div
ref={menuRef}
className={`absolute top-0 -right-[173px] ${
menuVisible ? "-translate-x-full" : ""
} z-[9999] bg-teal-600 flex md:hidden dark:bg-gray-600 transition-transform duration-500 ease-linear`}