// Déclaration pour GSAP si disponible declare var gsap: any; class MobileMenu { private mobileMenu: HTMLElement | null; private mobileMenuToggle: HTMLElement | null; private header: HTMLElement | null; private primaryMenu: HTMLElement | null; private submenuToggles: NodeListOf; constructor() { this.mobileMenu = document.querySelector('#menu-mobile-brand'); this.header = document.querySelector('#primary-header'); this.primaryMenu = this.header?.querySelector('#primary-menu-nav') || null; this.mobileMenuToggle = this.mobileMenu?.querySelector('#mobile-menu-toggle') || null; this.submenuToggles = this.primaryMenu?.querySelectorAll('.menu-item-submenu-toggle') || ([] as any); this.init(); } /** * Initialise le menu mobile et ses événements */ private init(): void { if (!this.mobileMenu || !this.header || !this.mobileMenuToggle || !this.primaryMenu) { console.warn('Éléments du menu mobile introuvables'); return; } this.bindEvents(); } /** * Lie tous les événements du menu mobile */ private bindEvents(): void { // Événement pour le toggle du menu mobile this.mobileMenuToggle?.addEventListener('click', (e) => this.handleToggleClick(e)); // Événement pour fermer le menu avec Tab document.addEventListener('focusin', (e) => this.handleFocusOut(e), true); // Événements pour les sous-menus this.submenuToggles.forEach((button) => { button.addEventListener('click', (e) => this.handleSubmenuToggle(e, button)); }); } /** * Ouvre le menu mobile */ public openMobileMenu(): void { if (!this.mobileMenu || !this.mobileMenuToggle || !this.header) return; this.mobileMenu.setAttribute('nav-open', 'true'); this.header.setAttribute('nav-open', 'true'); this.mobileMenuToggle.setAttribute('aria-expanded', 'true'); // // Animation GSAP si disponible // if (typeof gsap !== 'undefined' && this.primaryMenu) { // gsap.from(this.primaryMenu, { // opacity: 0, // y: '-100vh', // duration: 0.5, // ease: 'power4.out', // }); // } } /** * Ferme le menu mobile */ public closeMobileMenu(): void { if (!this.mobileMenu || !this.mobileMenuToggle || !this.header) return; this.mobileMenu.setAttribute('nav-open', 'false'); this.header.setAttribute('nav-open', 'false'); this.mobileMenuToggle.setAttribute('aria-expanded', 'false'); } /** * Toggle l'état du menu mobile */ public toggleMobileMenu(): void { if (!this.mobileMenu) return; if (this.mobileMenu.getAttribute('nav-open') === 'true') { this.closeMobileMenu(); this.mobileMenuToggle.textContent = 'Menu'; } else { this.openMobileMenu(); this.mobileMenuToggle.textContent = 'Fermer'; } } /** * Vérifie si le menu mobile est ouvert */ public isMenuOpen(): boolean { return this.mobileMenu?.getAttribute('nav-open') === 'true' || false; } /** * Gère le clic sur le bouton toggle */ private handleToggleClick(e: Event): void { e.preventDefault(); this.toggleMobileMenu(); } /** * Gère la fermeture du menu lors du focus en dehors */ private handleFocusOut(e: Event): void { if (!this.header || !this.isMenuOpen()) return; const target = e.target as Element; if (!this.header.contains(target)) { this.closeMobileMenu(); this.mobileMenuToggle?.focus(); } } /** * Gère le toggle des sous-menus */ private handleSubmenuToggle(e: Event, button: Element): void { e.preventDefault(); const isExpanded = button.getAttribute('aria-expanded') === 'true'; button.setAttribute('aria-expanded', String(!isExpanded)); const submenu = button.parentElement?.querySelector('.sub-menu'); submenu?.classList.toggle('sub-menu-open'); } } export default function menuInit(): MobileMenu { return new MobileMenu(); }