Added Entry and Exit animation for menu

This commit is contained in:
2025-09-29 17:17:32 +02:00
parent bfbe687b63
commit 9f10721104
4 changed files with 53 additions and 12 deletions

View File

@@ -6,7 +6,20 @@ import { useMenu } from '@/contexts/MenuContext';
import styles from './Header.module.css'; import styles from './Header.module.css';
export default function Header() { export default function Header() {
const { isMenuOpen, toggleMenu } = useMenu(); const { isMenuOpen, closeMenu, openMenu, startClosing, resetClosing } =
useMenu();
const handleMenuToggle = () => {
if (isMenuOpen) {
startClosing();
setTimeout(() => {
closeMenu();
resetClosing();
}, 800);
} else {
openMenu();
}
};
return ( return (
<header className={styles.header}> <header className={styles.header}>
<div className={styles.inner}> <div className={styles.inner}>
@@ -21,7 +34,7 @@ export default function Header() {
</div> </div>
<div className={styles.menutoggle}> <div className={styles.menutoggle}>
<button <button
onClick={() => toggleMenu()} onClick={() => handleMenuToggle()}
aria-label={isMenuOpen ? 'Close menu' : 'Open menu'} aria-label={isMenuOpen ? 'Close menu' : 'Open menu'}
aria-expanded={isMenuOpen} aria-expanded={isMenuOpen}
aria-controls="main-menu" aria-controls="main-menu"

View File

@@ -75,11 +75,29 @@
visibility: hidden; visibility: hidden;
opacity: 0; opacity: 0;
background-color: var(--grid-bg); background-color: var(--grid-bg);
clip-path: inset(0 0 100% 0);
transition: clip-path 0.35s steps(8, end);
&.isOpen { &.isOpen {
pointer-events: auto; pointer-events: auto;
transform: translateY(0);
visibility: visible; visibility: visible;
opacity: 1; opacity: 1;
clip-path: inset(0 0 0 0);
}
&.isClosing {
clip-path: inset(0 0 100% 0);
transition: clip-path 0.25s steps(6, end);
&.isOpen {
clip-path: inset(0 0 100% 0);
transition: clip-path 0.25s steps(6, end);
}
} }
@media screen and (--bp-desktop) { @media screen and (--bp-desktop) {

View File

@@ -16,17 +16,16 @@ interface MenuGridProps {
} }
export default function MenuGrid({ navigationData }: MenuGridProps) { export default function MenuGrid({ navigationData }: MenuGridProps) {
const { isMenuOpen, closeMenu } = useMenu(); const { isMenuOpen, closeMenu, isClosing, startClosing, resetClosing } =
useMenu();
const menuRef = React.useRef<HTMLElement>(null); const menuRef = React.useRef<HTMLElement>(null);
const [isClosing, setIsClosing] = React.useState(false);
const handleClose = React.useCallback(() => { const handleClose = React.useCallback(() => {
setIsClosing(true); startClosing();
setTimeout(() => { setTimeout(() => {
closeMenu(); closeMenu();
setIsClosing(false); resetClosing();
}, 800); }, 800);
}, [closeMenu]); }, [closeMenu, startClosing, resetClosing]);
React.useEffect(() => { React.useEffect(() => {
const handleEscape = (e: KeyboardEvent) => { const handleEscape = (e: KeyboardEvent) => {

View File

@@ -4,9 +4,11 @@ import React, { useContext, useEffect } from 'react';
interface MenuContextType { interface MenuContextType {
isMenuOpen: boolean; isMenuOpen: boolean;
toggleMenu: () => void; isClosing: boolean;
closeMenu: () => void; closeMenu: () => void;
openMenu: () => void; openMenu: () => void;
startClosing: () => void;
resetClosing: () => void;
} }
const MenuContext = React.createContext<MenuContextType | undefined>(undefined); const MenuContext = React.createContext<MenuContextType | undefined>(undefined);
@@ -16,11 +18,13 @@ interface MenuProviderProps {
} }
export const MenuProvider = ({ children }: MenuProviderProps) => { export const MenuProvider = ({ children }: MenuProviderProps) => {
const [isMenuOpen, setIsMenuOpen] = React.useState(true); const [isMenuOpen, setIsMenuOpen] = React.useState(false);
const [isClosing, setIsClosing] = React.useState(false);
const toggleMenu = () => setIsMenuOpen(!isMenuOpen);
const closeMenu = () => setIsMenuOpen(false); const closeMenu = () => setIsMenuOpen(false);
const openMenu = () => setIsMenuOpen(true); const openMenu = () => setIsMenuOpen(true);
const startClosing = () => setIsClosing(true);
const resetClosing = () => setIsClosing(false);
useEffect(() => { useEffect(() => {
if (isMenuOpen) { if (isMenuOpen) {
@@ -35,7 +39,14 @@ export const MenuProvider = ({ children }: MenuProviderProps) => {
return ( return (
<MenuContext.Provider <MenuContext.Provider
value={{ isMenuOpen, toggleMenu, openMenu, closeMenu }} value={{
isMenuOpen,
openMenu,
closeMenu,
isClosing,
startClosing,
resetClosing,
}}
> >
{children} {children}
</MenuContext.Provider> </MenuContext.Provider>