FEATURE Improving the mobile menu behaviour
This commit is contained in:
parent
2c1dabec6e
commit
d1610f4281
|
|
@ -1,61 +1,140 @@
|
||||||
export default function menuInit() {
|
// Déclaration pour GSAP si disponible
|
||||||
let main_navigation =
|
declare var gsap: any;
|
||||||
document.querySelector('#primary-menu');
|
|
||||||
const header = document.querySelector('#primary-header');
|
|
||||||
const primary_menu =
|
|
||||||
header.querySelector('#primary-menu');
|
|
||||||
const burgerMenuToggle = header.querySelector(
|
|
||||||
'#burger-menu-toggle'
|
|
||||||
);
|
|
||||||
const submenuToggles = primary_menu.querySelectorAll(
|
|
||||||
'.menu-item-submenu-toggle'
|
|
||||||
);
|
|
||||||
|
|
||||||
// #### Open/close burger nav
|
class MobileMenu {
|
||||||
burgerMenuToggle.addEventListener('click', function (e) {
|
private mobileMenu: HTMLElement | null;
|
||||||
|
private mobileMenuToggle: HTMLElement | null;
|
||||||
|
private header: HTMLElement | null;
|
||||||
|
private primaryMenu: HTMLElement | null;
|
||||||
|
private submenuToggles: NodeListOf<Element>;
|
||||||
|
|
||||||
|
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();
|
e.preventDefault();
|
||||||
header.classList.toggle('nav-open');
|
this.toggleMobileMenu();
|
||||||
burgerMenuToggle.toggleAttribute('aria-expanded');
|
}
|
||||||
gsap.from(primary_menu, {
|
|
||||||
opacity: 20,
|
|
||||||
y: '-100vh',
|
|
||||||
duration: 0.5,
|
|
||||||
ease: Power4.easeOut,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
// #### Close nav when reaching the end of the menu with tab
|
/**
|
||||||
document.addEventListener(
|
* Gère la fermeture du menu lors du focus en dehors
|
||||||
'focusin',
|
*/
|
||||||
(e) => {
|
private handleFocusOut(e: Event): void {
|
||||||
const header = document.querySelector(
|
if (!this.header || !this.isMenuOpen()) return;
|
||||||
'#primary-header'
|
|
||||||
);
|
|
||||||
if (
|
|
||||||
header.classList.contains('nav-open') &&
|
|
||||||
!header.contains(document.activeElement)
|
|
||||||
) {
|
|
||||||
header.classList.remove('nav-open');
|
|
||||||
burgerMenuToggle.setAttribute(
|
|
||||||
'aria-expanded',
|
|
||||||
false
|
|
||||||
);
|
|
||||||
|
|
||||||
burgerMenuToggle.focus();
|
const target = e.target as Element;
|
||||||
}
|
if (!this.header.contains(target)) {
|
||||||
},
|
this.closeMobileMenu();
|
||||||
true
|
this.mobileMenuToggle?.focus();
|
||||||
);
|
}
|
||||||
|
}
|
||||||
|
|
||||||
submenuToggles.forEach((button) => {
|
/**
|
||||||
button.addEventListener('click', function (e) {
|
* Gère le toggle des sous-menus
|
||||||
let isExpanded =
|
*/
|
||||||
button.getAttribute('aria-expanded') === 'true';
|
private handleSubmenuToggle(e: Event, button: Element): void {
|
||||||
button.setAttribute('aria-expanded', !isExpanded);
|
e.preventDefault();
|
||||||
|
const isExpanded = button.getAttribute('aria-expanded') === 'true';
|
||||||
|
button.setAttribute('aria-expanded', String(!isExpanded));
|
||||||
|
|
||||||
button.parentElement
|
const submenu = button.parentElement?.querySelector('.sub-menu');
|
||||||
.querySelector('.sub-menu')
|
submenu?.classList.toggle('sub-menu-open');
|
||||||
.classList.toggle('sub-menu-open');
|
}
|
||||||
});
|
}
|
||||||
});
|
|
||||||
|
export default function menuInit(): MobileMenu {
|
||||||
|
return new MobileMenu();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user