diff --git a/blocks/header/header.css b/blocks/header/header.css index c74e6ab..0fa8918 100644 --- a/blocks/header/header.css +++ b/blocks/header/header.css @@ -296,23 +296,41 @@ header nav .nav-sections .default-content-wrapper > ul > li.nav-drop > p > a { /* chevron: mobile only (p::after); desktop uses li::after below */ @media (width <= 899px) { - header nav .nav-sections .default-content-wrapper > ul > li.nav-drop > p::after { - content: ''; + header nav .nav-sections .default-content-wrapper > ul > li.nav-drop > p { + padding-right: calc(var(--nav-item-padding) + 26px); + } + + header nav .nav-sections .default-content-wrapper > ul > li.nav-drop > p > .nav-submenu-toggle { position: absolute; right: var(--nav-item-padding); top: 50%; - transform: translateY(-50%) rotate(135deg); + width: 24px; + height: 24px; + transform: translateY(-50%); + border: 0; + border-radius: 999px; + background: transparent; + color: inherit; + padding: 0; + cursor: pointer; + } + + header nav .nav-sections .default-content-wrapper > ul > li.nav-drop > p > .nav-submenu-toggle::before { + content: ''; + display: block; width: 6px; height: 6px; + margin: auto; border: 2px solid currentcolor; border-radius: 0 1px 0 0; border-width: 2px 2px 0 0; opacity: 0.6; + transform: rotate(135deg); transition: transform 0.2s ease; } - header nav .nav-sections .default-content-wrapper > ul > li.nav-drop[aria-expanded='true'] > p::after { - transform: translateY(-50%) rotate(-45deg); + header nav .nav-sections .default-content-wrapper > ul > li.nav-drop[aria-expanded='true'] > p > .nav-submenu-toggle::before { + transform: rotate(-45deg); } } @@ -805,6 +823,10 @@ header nav .nav-tools .nav-language-menu a:focus-visible { /* desktop: 900px */ @media (width >= 900px) { + header nav .nav-sections .default-content-wrapper > ul > li.nav-drop > p > .nav-submenu-toggle { + display: none; + } + header nav { display: flex; justify-content: space-between; diff --git a/blocks/header/header.js b/blocks/header/header.js index 641dfcf..69a56b0 100644 --- a/blocks/header/header.js +++ b/blocks/header/header.js @@ -99,12 +99,48 @@ function decorateMega(li) { } function setupDropdown(li) { + const submenu = li.querySelector(':scope > ul'); + const heading = li.querySelector(':scope > p'); + const parentLink = li.querySelector(':scope > p > a'); + let toggleBtn = null; + + const syncToggle = () => { + if (!toggleBtn) return; + const expanded = li.getAttribute('aria-expanded') === 'true'; + toggleBtn.setAttribute('aria-expanded', String(expanded)); + toggleBtn.setAttribute('aria-label', expanded ? 'Collapse submenu' : 'Expand submenu'); + }; + + if (submenu && heading) { + toggleBtn = heading.querySelector('.nav-submenu-toggle'); + if (!toggleBtn) { + toggleBtn = document.createElement('button'); + toggleBtn.type = 'button'; + toggleBtn.className = 'nav-submenu-toggle'; + heading.append(toggleBtn); + } + syncToggle(); + toggleBtn.addEventListener('click', (e) => { + e.preventDefault(); + e.stopPropagation(); + if (DESKTOP.matches) return; + const wasOpen = li.getAttribute('aria-expanded') === 'true'; + collapseAll(li.closest('nav')); + li.setAttribute('aria-expanded', wasOpen ? 'false' : 'true'); + syncToggle(); + }); + } + const open = () => { li.megaSync?.(); collapseAll(li.closest('nav')); li.setAttribute('aria-expanded', 'true'); + syncToggle(); + }; + const close = () => { + li.setAttribute('aria-expanded', 'false'); + syncToggle(); }; - const close = () => li.setAttribute('aria-expanded', 'false'); li.addEventListener('mouseenter', () => { if (DESKTOP.matches) open(); }); li.addEventListener('mouseleave', (e) => { @@ -117,16 +153,22 @@ function setupDropdown(li) { li.addEventListener('click', (e) => { if (!DESKTOP.matches) { - const submenu = li.querySelector(':scope > ul'); const clickedSubmenuLink = submenu?.contains(e.target) && e.target.closest('a'); + const clickedToggle = e.target.closest('.nav-submenu-toggle'); + const clickedParentLink = parentLink && (e.target === parentLink || parentLink.contains(e.target)); + if (clickedToggle) return; if (clickedSubmenuLink) { collapseAll(li.closest('nav')); close(); + } else if (clickedParentLink) { + collapseAll(li.closest('nav')); + close(); } else if (submenu) { e.preventDefault(); const wasOpen = li.getAttribute('aria-expanded') === 'true'; collapseAll(li.closest('nav')); li.setAttribute('aria-expanded', wasOpen ? 'false' : 'true'); + syncToggle(); } } else if (li.querySelector('ul')?.contains(e.target) && e.target.closest('a')) { collapseAll(li.closest('nav'));