92 lines
2.8 KiB
JavaScript
92 lines
2.8 KiB
JavaScript
customElements.define('i-navigation-menu', class extends HTMLElement {
|
|
|
|
constructor () {
|
|
super();
|
|
this.menu = this.querySelector('.ipsNavBar');
|
|
this.moreLi = this.menu.querySelector("[data-el='nav-more']");
|
|
this.moreMenu = this.moreLi.querySelector(".ipsNav__dropdown");
|
|
}
|
|
|
|
emptyMoreMenu() {
|
|
// Move all children back into main
|
|
this.moreLi.before(...this.moreMenu.children);
|
|
// Then hide the More menu
|
|
this.moreLi.hidden = true;
|
|
}
|
|
|
|
fillMoreMenu(clientWidth){
|
|
|
|
let scrollWidth = this.menu.scrollWidth;
|
|
|
|
// If there's no overflow, return early
|
|
if(scrollWidth <= clientWidth) return;
|
|
// Show More menu
|
|
this.moreLi.hidden = false;
|
|
// While the navigation list overflows, move items into the More menu
|
|
while(scrollWidth > clientWidth){
|
|
// If the More menu is the first element, end the while loop
|
|
if(!this.moreLi.previousElementSibling){ break; }
|
|
// Move last link into More menu
|
|
this.moreMenu.prepend(this.moreLi.previousElementSibling);
|
|
|
|
scrollWidth = this.menu.scrollWidth;
|
|
}
|
|
}
|
|
|
|
updateAttributes(){
|
|
|
|
// Reapply the light-dismiss functionality to items which have been moved from the More menu back to the main menu
|
|
this.menu.querySelectorAll('[data-ips-hidden-light-dismiss-disabled]').forEach(el => {
|
|
el.removeAttribute('data-ips-hidden-light-dismiss-disabled');
|
|
el.setAttribute('data-ips-hidden-light-dismiss', '');
|
|
});
|
|
|
|
// Then loop through menus inside More menu and remove their light-dismiss feature, and add a -disabled variant so we can reapply the correct attribute later
|
|
this.moreMenu.querySelectorAll('[data-ips-hidden-light-dismiss]').forEach(el => {
|
|
el.removeAttribute('data-ips-hidden-light-dismiss');
|
|
el.setAttribute('data-ips-hidden-light-dismiss-disabled', '');
|
|
});
|
|
|
|
// If the active link is inside the More menu...
|
|
if(this.moreMenu.querySelector("[aria-current]")){
|
|
// ..add [data-active] to "More"
|
|
this.moreLi.setAttribute("data-active", "");
|
|
// ..and expand the active dropdown
|
|
this.moreMenu.querySelectorAll(':scope > [data-active]').forEach(el => {
|
|
const button = el.querySelector(":scope > [aria-expanded]");
|
|
if(button){
|
|
button.setAttribute("aria-expanded", "true");
|
|
}
|
|
const menu = el.querySelector(":scope > .ipsNav__dropdown");
|
|
if(menu){
|
|
menu.hidden = false;
|
|
}
|
|
});
|
|
} else {
|
|
// Otherwise remove [data-active] from the More menu
|
|
this.moreLi.removeAttribute("data-active");
|
|
}
|
|
}
|
|
|
|
connectedCallback(){
|
|
|
|
// Empty More menu and refill it on resize
|
|
this.ro = new ResizeObserver(entries => {
|
|
for (let entry of entries) {
|
|
|
|
let entryWidth = Math.ceil(entry.contentRect.width);
|
|
|
|
if(this.lastWidth && entryWidth > this.lastWidth){
|
|
this.emptyMoreMenu();
|
|
}
|
|
|
|
this.fillMoreMenu(entryWidth);
|
|
this.updateAttributes();
|
|
|
|
this.lastWidth = entryWidth;
|
|
}
|
|
});
|
|
|
|
this.ro.observe(this.menu);
|
|
}
|
|
}); |