|
1 | | -import { useState } from 'react'; |
2 | | -import { useSpring, animated } from 'react-spring'; |
| 1 | +import { useState, useEffect, useCallback } from 'react'; |
3 | 2 | import Link from 'next/link'; |
4 | 3 |
|
| 4 | +import FadeLeftToRight from 'components/Animations/FadeLeftToRight.component'; |
| 5 | +import FadeLeftToRightItem from 'components/Animations/FadeLeftToRightItem.component'; |
| 6 | + |
5 | 7 | import LINKS from '../../utils/constants/LINKS'; |
6 | 8 |
|
7 | 9 | /** |
8 | | - * Shows the mobile menu. |
| 10 | + * Hamburger component used in mobile menu. Animates to a X when clicked |
| 11 | + * @function Hamburger |
| 12 | + * @param {MouseEventHandler<HTMLButtonElement>} onClick - onClick handler to respond to clicks |
| 13 | + * @param {boolean} isExpanded - Should the hamburger animate to a X? |
| 14 | + * @returns {JSX.Element} - Rendered component |
9 | 15 | */ |
| 16 | + |
10 | 17 | const Hamburger = () => { |
11 | 18 | const [isExpanded, setisExpanded] = useState(false); |
12 | | - const hamburgerSlideDownAnimation = useSpring({ |
13 | | - to: [ |
14 | | - { |
15 | | - opacity: isExpanded ? 1 : 0, |
16 | | - marginTop: isExpanded ? '170px' : '-180px', |
17 | | - }, |
18 | | - ], |
19 | | - from: { |
20 | | - opacity: isExpanded ? 1 : 0, |
21 | | - marginTop: isExpanded ? '170px' : '-180px', |
22 | | - }, |
23 | | - }); |
24 | | - const showHamburgerHideXAnimation = useSpring({ |
25 | | - to: [ |
26 | | - { |
27 | | - opacity: isExpanded ? 0 : 1, |
28 | | - display: isExpanded ? 'none' : 'inline', |
29 | | - }, |
30 | | - ], |
31 | | - from: { |
32 | | - opacity: isExpanded ? 0 : 1, |
33 | | - }, |
34 | | - }); |
35 | | - const showXHideHamburgerAnimation = useSpring({ |
36 | | - to: [ |
37 | | - { |
38 | | - opacity: isExpanded ? 1 : 0, |
39 | | - display: isExpanded ? 'inline' : 'none', |
40 | | - }, |
41 | | - ], |
42 | | - from: { |
43 | | - opacity: isExpanded ? 0 : 1, |
44 | | - display: isExpanded ? 'none' : 'inline', |
45 | | - }, |
46 | | - }); |
| 19 | + const [hidden, setHidden] = useState('invisible'); |
| 20 | + |
| 21 | + useEffect(() => { |
| 22 | + if (isExpanded) { |
| 23 | + //document.addEventListener("mousedown", handleClickOutside); |
| 24 | + setHidden(''); |
| 25 | + } else { |
| 26 | + setTimeout(() => { |
| 27 | + setHidden('invisible'); |
| 28 | + }, 1000); |
| 29 | + |
| 30 | + // document.removeEventListener("mousedown", handleClickOutside); |
| 31 | + } |
| 32 | + /*return () => { |
| 33 | + document.removeEventListener("mousedown", handleClickOutside); |
| 34 | + };*/ |
| 35 | + }, [isExpanded]); |
| 36 | + |
| 37 | + const handleMobileMenuClick = useCallback(() => { |
| 38 | + /** |
| 39 | + * Anti-pattern: setisExpanded(!isExpanded) |
| 40 | + * Even if your state updates are batched and multiple updates to the enabled/disabled state are made together |
| 41 | + * each update will rely on the correct previous state so that you always end up with the result you expect. |
| 42 | + */ |
| 43 | + setisExpanded((prevExpanded) => !prevExpanded); |
| 44 | + }, [setisExpanded]); |
| 45 | + |
| 46 | + const hamburgerLine = |
| 47 | + 'h-1 w-10 my-1 rounded-full bg-white transition ease transform duration-300 not-sr-only'; |
| 48 | + |
| 49 | + const opacityFull = 'opacity-100 group-hover:opacity-100'; |
| 50 | + |
47 | 51 | return ( |
48 | | - <> |
49 | | - <label |
50 | | - htmlFor="menu-toggle" |
51 | | - aria-label="Meny" |
52 | | - className="block cursor-pointer md:hidden" |
| 52 | + <div className="z-50 md:hidden lg:hidden xl:hidden bg-gray-800"> |
| 53 | + <button |
| 54 | + className="flex flex-col w-16 rounded justify-center items-center group" |
| 55 | + data-cy="hamburger" |
| 56 | + data-testid="hamburger" |
| 57 | + onClick={handleMobileMenuClick} |
| 58 | + aria-expanded={isExpanded} |
| 59 | + type="button" |
53 | 60 | > |
54 | | - <animated.svg |
55 | | - id="hamburgersvg" |
56 | | - style={showHamburgerHideXAnimation} |
57 | | - onClick={() => { |
58 | | - setisExpanded((prevExpanded) => !prevExpanded); |
59 | | - }} |
60 | | - className="text-gray-900 fill-current" |
61 | | - xmlns="https://www.w3.org/2000/svg" |
62 | | - width="25" |
63 | | - height="25" |
64 | | - viewBox="0 0 25 25" |
65 | | - > |
66 | | - <path d="M0 3h20v2H0V3zm0 6h20v2H0V9zm0 6h20v2H0v-2z" /> |
67 | | - </animated.svg> |
68 | | - <animated.svg |
69 | | - id="xsvg" |
70 | | - onClick={() => { |
71 | | - setisExpanded((prevExpanded) => !prevExpanded); |
72 | | - }} |
73 | | - style={showXHideHamburgerAnimation} |
74 | | - xmlns="https://www.w3.org/2000/svg" |
75 | | - width="25" |
76 | | - height="25" |
77 | | - viewBox="0 0 25 25" |
78 | | - > |
79 | | - <line x1="18" y1="6" x2="6" y2="18" /> |
80 | | - <line x1="6" y1="6" x2="18" y2="18" /> |
81 | | - </animated.svg> |
82 | | - </label> |
83 | | - {isExpanded && ( |
84 | | - <animated.div |
85 | | - style={hamburgerSlideDownAnimation} |
| 61 | + <span className="sr-only text-white text-2xl">Hamburger</span> |
| 62 | + <span |
| 63 | + data-testid="hamburgerline" |
| 64 | + className={`${hamburgerLine} ${ |
| 65 | + isExpanded |
| 66 | + ? 'rotate-45 translate-y-3 opacity-100 group-hover:opacity-100' |
| 67 | + : opacityFull |
| 68 | + }`} |
| 69 | + /> |
| 70 | + <span |
| 71 | + className={`${hamburgerLine} ${ |
| 72 | + isExpanded ? 'opacity-0' : opacityFull |
| 73 | + }`} |
| 74 | + /> |
| 75 | + <span |
| 76 | + className={`${hamburgerLine} ${ |
| 77 | + isExpanded |
| 78 | + ? '-rotate-45 -translate-y-3 opacity-100 group-hover:opacity-100' |
| 79 | + : opacityFull |
| 80 | + }`} |
| 81 | + /> |
| 82 | + </button> |
| 83 | + <FadeLeftToRight |
| 84 | + delay={0.2} |
| 85 | + staggerDelay={0.2} |
| 86 | + animateNotReverse={isExpanded} |
| 87 | + > |
| 88 | + <div |
86 | 89 | id="mobile-menu" |
87 | | - className="absolute right-0 z-10 w-full text-center text-black bg-white " |
| 90 | + aria-hidden={!isExpanded} |
| 91 | + className={`absolute right-0 z-10 w-full text-center text-black bg-white ${hidden}`} |
88 | 92 | > |
89 | 93 | <ul> |
90 | 94 | {LINKS.map(({ id, title, href }) => ( |
91 | | - <li |
92 | | - key={id} |
93 | | - id="mobile-li" |
94 | | - className="w-full p-4 border-t border-gray-400 border-solid rounded" |
95 | | - > |
96 | | - <Link href={href}> |
97 | | - <a className="inline-block px-4 py-2 no-underline hover:text-black hover:underline"> |
98 | | - {title} |
99 | | - </a> |
100 | | - </Link> |
101 | | - </li> |
| 95 | + <FadeLeftToRightItem key={id} cssClass="block"> |
| 96 | + <li |
| 97 | + id="mobile-li" |
| 98 | + className="w-full p-4 border-t border-gray-400 border-solid rounded" |
| 99 | + > |
| 100 | + <Link href={href}> |
| 101 | + <a className="inline-block px-4 py-2 no-underline hover:text-black hover:underline"> |
| 102 | + {title} |
| 103 | + </a> |
| 104 | + </Link> |
| 105 | + </li> |
| 106 | + </FadeLeftToRightItem> |
102 | 107 | ))} |
103 | 108 | </ul> |
104 | | - </animated.div> |
105 | | - )} |
106 | | - </> |
| 109 | + </div> |
| 110 | + </FadeLeftToRight> |
| 111 | + </div> |
107 | 112 | ); |
108 | 113 | }; |
109 | 114 |
|
|
0 commit comments