Welcome to WordPress. This is your first post. Edit or delete it, then start writing!

class MenuToggle {
constructor(config = {}) {
this.config = {
toggleSelector: '[data-menu-toggle]',
overlaySelector: '[data-menu-overlay]',
openText: 'Close',
closedText: 'Menu',
animationDuration: 100,
staggerDelay: 80,
...config
};
this.isOpen = false;
this.initialized = false;
this.init();
}
init() {
if (this.initialized) return;
this.elements = this.getElements();
if (!this.elements.toggle || !this.elements.overlay) {
return;
}
this.injectStyles();
this.forceInitialStateImmediate();
this.createArrow();
this.bindEvents();
this.setAriaAttributes();
this.setupMenuItems();
this.initialized = true;
}
forceInitialStateImmediate() {
this.elements.overlay.style.transform = 'translateY(-100%)';
this.elements.overlay.style.transition = 'none';
this.elements.overlay.classList.add('menu-closed');
this.isOpen = false;
setTimeout(() => {
this.elements.overlay.style.transition = 'transform 0.6s cubic-bezier(0.4, 0.0, 0.2, 1)';
}, 50);
}
getElements() {
return {
toggle: document.querySelector(this.config.toggleSelector),
overlay: document.querySelector(this.config.overlaySelector)
};
}
setupMenuItems() {
this.menuItems = this.elements.overlay.querySelectorAll('*:not(style):not(script)');
this.menuItems = Array.from(this.menuItems).filter(item => {
return item.textContent.trim().length > 0 &&
!item.querySelector('*') &&
item.offsetParent !== null;
});
this.menuItems.forEach((item, index) => {
item.style.opacity = '0';
item.style.transform = 'translateY(30px)';
item.style.transition = `opacity 0.5s ease ${index * this.config.staggerDelay}ms, transform 0.5s ease ${index * this.config.staggerDelay}ms`;
});
}
injectStyles() {
if (document.getElementById('menu-toggle-styles')) return;
const style = document.createElement('style');
style.id = 'menu-toggle-styles';
style.textContent = `
${this.config.overlaySelector} {
position: fixed !important;
top: 0 !important;
left: 0 !important;
width: 100vw !important;
height: 100vh !important;
z-index: 9999 !important;
}
body.menu-open .brx-header {
z-index: 1 !important;
}
.menu-arrow {
display: inline-block;
margin-right: 8px;
transition: transform 0.4s cubic-bezier(0.4, 0.0, 0.2, 1);
width: 8px;
height: 8px;
border-right: 2px solid currentColor;
border-bottom: 2px solid currentColor;
transform: rotate(45deg);
transform-origin: center;
vertical-align: middle;
position: relative;
top: -1px;
}
.menu-arrow.rotated {
transform: rotate(-135deg);
}
body.menu-open {
overflow: hidden !important;
}
`;
document.head.appendChild(style);
}
createArrow() {
this.arrow = document.createElement('span');
this.arrow.className = 'menu-arrow';
this.arrow.setAttribute('aria-hidden', 'true');
this.textNode = document.createTextNode(this.config.closedText);
this.elements.toggle.innerHTML = '';
this.elements.toggle.appendChild(this.arrow);
this.elements.toggle.appendChild(this.textNode);
}
setAriaAttributes() {
this.elements.toggle.setAttribute('aria-expanded', 'false');
this.elements.toggle.setAttribute('aria-controls', this.elements.overlay.id || 'menu-overlay');
this.elements.overlay.setAttribute('aria-hidden', 'true');
}
bindEvents() {
this.boundClickHandler = this.handleClick.bind(this);
this.boundKeyHandler = this.handleKeydown.bind(this);
this.elements.toggle.addEventListener('click', this.boundClickHandler);
this.elements.toggle.addEventListener('keydown', this.boundKeyHandler);
}
handleKeydown(e) {
if (e.key === 'Enter' || e.key === ' ') {
e.preventDefault();
this.toggle();
}
if (e.key === 'Escape' && this.isOpen) {
this.close();
}
}
handleClick(e) {
e.preventDefault();
this.toggle();
}
toggle() {
this.isOpen ? this.close() : this.open();
}
open() {
if (this.isOpen) return;
document.body.classList.add('menu-open');
this.elements.overlay.classList.remove('menu-closed');
this.elements.overlay.style.transform = 'translateY(0)';
this.textNode.textContent = this.config.openText;
this.arrow.classList.add('rotated');
setTimeout(() => {
this.menuItems.forEach((item, index) => {
setTimeout(() => {
item.style.opacity = '1';
item.style.transform = 'translateY(0)';
}, index * this.config.staggerDelay);
});
}, 300);
this.elements.toggle.setAttribute('aria-expanded', 'true');
this.elements.overlay.setAttribute('aria-hidden', 'false');
this.isOpen = true;
}
close() {
if (!this.isOpen) return;
document.body.classList.remove('menu-open');
this.menuItems.forEach((item) => {
item.style.opacity = '0';
item.style.transform = 'translateY(30px)';
});
setTimeout(() => {
this.elements.overlay.style.transform = 'translateY(-100%)';
this.elements.overlay.classList.add('menu-closed');
}, 200);
this.textNode.textContent = this.config.closedText;
this.arrow.classList.remove('rotated');
this.elements.toggle.setAttribute('aria-expanded', 'false');
this.elements.overlay.setAttribute('aria-hidden', 'true');
this.isOpen = false;
}
destroy() {
if (!this.initialized) return;
this.elements.toggle.removeEventListener('click', this.boundClickHandler);
this.elements.toggle.removeEventListener('keydown', this.boundKeyHandler);
document.body.classList.remove('menu-open');
const style = document.getElementById('menu-toggle-styles');
if (style) style.remove();
this.initialized = false;
}
}
document.addEventListener('DOMContentLoaded', () => {
new MenuToggle();
});Welcome to WordPress. This is your first post. Edit or delete it, then start writing!
5 comments
A WordPress Commenter
Hi, this is a comment.
To get started with moderating, editing, and deleting comments, please visit the Comments screen in the dashboard.
Commenter avatars come from Gravatar.
Heri Wisnu
cool
Heri Wisnu
comment 123
Heri Wisnu
coba comment lagi
Heri Wisnu
sip