Newer
Older
Markus Kalijärvi
committed
import {Component, Element, h, Host, Listen, Prop, State} from '@stencil/core';
import {MenuType} from '../../../utils/utils';
Markus Kalijärvi
committed
@Component({
tag: 'hy-menu-level-container',
styleUrl: 'menu-level-container.scss',
Markus Kalijärvi
committed
})
export class MenuLevelContainer {
@Element() el: HTMLElement;
@Prop() labelFrontPage?: string;
Markus Kalijärvi
committed
@Prop() menuButtonSubmenuExpand?: string;
@Prop() menuLevel: number;
@Prop() menuType: MenuType = MenuType.mobile;
Markus Kalijärvi
committed
@Prop({reflect: true}) activeTrailTriggered: boolean = false;
@Prop({mutable: true, reflect: true}) depth: number = 0;
Markus Kalijärvi
committed
@Prop({mutable: true}) headingItem: any;
@Prop({mutable: true, reflect: true}) triggerItem: string;
@State() menuIsOpen: boolean = false;
Markus Kalijärvi
committed
// 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.
Markus Kalijärvi
committed
@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');
Markus Kalijärvi
committed
}
}
// Listener for opening and closing menu level container.
Markus Kalijärvi
committed
@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;
Markus Kalijärvi
committed
}
}
// 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);
Markus Kalijärvi
committed
item.setAttribute('menu-button-submenu-expand', this.menuButtonSubmenuExpand);
Markus Kalijärvi
committed
componentWillRender() {
// Assign depth value to current menu level container instance;
// 1st level, 2nd level, etc.
Markus Kalijärvi
committed
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.
Markus Kalijärvi
committed
// 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) {
Markus Kalijärvi
committed
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());
});
}
Markus Kalijärvi
committed
}
}
render() {
let classAttributes = ['hy-menu-level-container', 'hy-menu-level-container--level-' + this.depth];
case MenuType.desktop:
classAttributes = [...classAttributes, 'hy-menu-level-container--desktop'];
<Host class={classAttributes.join(' ')} menu-type="desktop">
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];
<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];
<Host aria-expanded={this.menuIsOpen.toString()} class={classAttributes.join(' ')} tabindex={'-1'}>