import {Component, Element, h, Host, Listen, Prop, State} from '@stencil/core'; import {MenuType} from '../../../utils/utils'; @Component({ tag: 'hy-menu-level-container', styleUrl: 'menu-level-container.scss', shadow: false, }) export class MenuLevelContainer { @Element() el: HTMLElement; @Prop() labelFrontPage?: string; @Prop() menuButtonSubmenuExpand?: string; @Prop() menuLevel: number; @Prop() menuType: MenuType = MenuType.mobile; @Prop({reflect: true}) activeTrailTriggered: boolean = false; @Prop({mutable: true, reflect: true}) depth: number = 0; @Prop({mutable: true}) headingItem: any; @Prop({mutable: true, reflect: true}) triggerItem: string; @State() menuIsOpen: boolean = false; // Add/Remove is-hidden class from each upper level menu-items // to make browsing more accessible. assignMenuItemClass(parentMenu: Element, type: string) { const items = Array.from(parentMenu.children); items.forEach((item) => { if (type === 'remove') { item.classList.remove('is-hidden'); } else { item.classList.add('is-hidden'); } }); } // Listener for assigning active-trail for parent menu level container. @Listen('menuContainerActiveTrail', {target: 'document', capture: true}) menuContainerActiveTrail(data) { const currentMenuContainer = this.el.getAttribute('trigger-item'); if (currentMenuContainer === data.detail.triggerItem) { this.activeTrailTriggered = true; this.menuIsOpen = true; this.assignMenuItemClass(this.el.parentElement.closest('hy-menu-level-container'), 'add'); } } // Listener for opening and closing menu level container. @Listen('menuContainerToggled', {target: 'document', capture: true}) menuContainerToggled(data) { // Toggle submenu. if (this.triggerItem == data.detail.triggerItem) { this.activeTrailTriggered = false; this.menuIsOpen = data.detail.triggerType != 'remove'; this.assignMenuItemClass(this.el.parentElement.closest('hy-menu-level-container'), data.detail.triggerType); // Scroll to .hy-menu top. let hyMenu = this.el.parentElement.closest('hy-menu'); hyMenu.shadowRoot.querySelector('.hy-menu').scrollTop = 0; } } componentWillUpdate() { // Pass the menu type and menu-button-submenu-expand attributes to // the child menu item component. if (this.menuType) { const items = Array.from(this.el.children); items.forEach((item) => { item.setAttribute('menu-type', this.menuType); item.setAttribute('menu-button-submenu-expand', this.menuButtonSubmenuExpand); }); } } componentWillRender() { // Assign depth value to current menu level container instance; // 1st level, 2nd level, etc. let parentMenu = this.el.closest('hy-menu-level-container'); let nextParentMenu; this.depth = 0; while (parentMenu) { nextParentMenu = parentMenu.parentElement.closest('hy-menu-level-container'); if (nextParentMenu === parentMenu) { break; } else { parentMenu = nextParentMenu; this.depth = this.depth + 1; } } // Set trigger item for each mobile menu level container and handle only submenus. // Add a heading element foreach level. if (this.menuType === MenuType.mobile) { if (this.menuLevel > 1) { const parentMenuItem = this.el.closest('hy-menu-item'); this.triggerItem = parentMenuItem.getAttribute('menu-link-id'); this.headingItem = { ...this.headingItem, url: parentMenuItem.getAttribute('url'), }; this.headingItem = { ...this.headingItem, label: parentMenuItem.getAttribute('label'), }; this.headingItem = { ...this.headingItem, isActive: window.location.pathname === this.headingItem.url, }; } else { this.triggerItem = 'home'; } } // Set is-active-child and menu-level attributes to all sibling menu-items. if (this.menuType === MenuType.sidenav) { const parentMenuItem = this.el.closest('hy-menu-item'); if (parentMenuItem && parentMenuItem.classList.contains('is-active')) { this.menuIsOpen = true; const items = Array.from(this.el.children); items.forEach((item) => { item.setAttribute('is-active-child', 'true'); item.setAttribute('menu-level', this.menuLevel.toString()); }); } } } render() { let classAttributes = ['hy-menu-level-container', 'hy-menu-level-container--level-' + this.depth]; switch (this.menuType) { case MenuType.desktop: classAttributes = [...classAttributes, 'hy-menu-level-container--desktop']; //menu-type="sidenav" return ( <Host class={classAttributes.join(' ')} menu-type="desktop"> <slot /> </Host> ); case MenuType.mobile: classAttributes = [...classAttributes, 'hy-menu-level-container--mobile']; if (this.depth === 1) { classAttributes = [...classAttributes, 'is-open']; return ( <Host aria-expanded={this.menuIsOpen.toString()} class={classAttributes.join(' ')} tabindex={'-1'}> <slot /> </Host> ); } else { classAttributes = [...classAttributes, this.menuIsOpen ? 'is-open' : null]; return ( <Host aria-expanded={this.menuIsOpen.toString()} class={classAttributes.join(' ')} tabindex={'-1'}> <hy-menu-item label={this.headingItem.label} url={this.headingItem.url} isHeading={true} isActive={this.headingItem.isActive} menu-type={'mobile'} /> <slot /> </Host> ); } case MenuType.sidenav: classAttributes = [...classAttributes, 'hy-menu-level-container--sidenav']; if (this.depth === 1) { classAttributes = [...classAttributes, 'is-open']; return ( <Host aria-expanded={this.menuIsOpen.toString()} class={classAttributes.join(' ')} tabindex={'-1'}> <slot /> </Host> ); } else { classAttributes = [...classAttributes, this.menuIsOpen ? 'is-open' : null]; return ( <Host aria-expanded={this.menuIsOpen.toString()} class={classAttributes.join(' ')} tabindex={'-1'}> <slot /> </Host> ); } } } }