import {Component, Element, Prop, Host, Listen, Event, h, EventEmitter} from '@stencil/core'; import {MenuItemVariants} from '../../utils/utils'; @Component({ tag: 'hy-menu-item', styleUrl: 'menu-item.scss', shadow: true }) export class MenuItem { @Element() el: HTMLElement; @Prop() variant: MenuItemVariants = MenuItemVariants.default; @Prop() inActiveTrail: boolean = false; @Prop() isActive: boolean = false; @Prop() isHeading: boolean = false; @Prop() menuItemAlternative: boolean = false; @Prop() menuLinkId: string = ''; @Prop({mutable: true}) url: string = ''; @Prop({mutable: true}) label: string = ''; @Prop({mutable: true}) ariaExpanded: boolean = false; @Prop({mutable: true, reflect: true}) depth: number = 0; @Prop({mutable: true}) hasChildren: boolean = null; @Prop({mutable: true, reflect: true}) parentExpanded: boolean = false; @Prop({mutable: true}) parentAsHeading: string = ''; @Event() routeClicked: EventEmitter; @Event() menuContainerToggled: EventEmitter; @Event() menuContainerActiveTrail: EventEmitter; @Event() addBreadcrumb: EventEmitter; @Listen('handleClick', {capture: true}) handleClick() { this.menuContainerToggled.emit({triggerItem: this.menuLinkId}); const currentParent = this.el.parentNode; this.addBreadcrumb.emit({ url: this.url, label: currentParent.parentElement.getAttribute('label'), bid: this.menuLinkId }); } componentWillLoad() { // Notify breadcrumbs if item is in active trail. if (this.inActiveTrail && !this.isActive) { const currentParent = this.el.parentNode; this.addBreadcrumb.emit({ url: this.url, label: currentParent.parentElement.getAttribute('label'), bid: this.menuLinkId }); } // Trigger all parent menuLevelContainer elements in the same active-trail // to open the menu. if (this.isActive) { const getParents = (elem) => { let parents = []; while (elem.parentNode && elem.parentNode.nodeName.toLowerCase() != 'hy-menu-mobile') { elem = elem.parentNode; parents.push(elem); } return parents; }; const parents = getParents(this.el); parents.forEach((element) => { if (element.tagName.toLowerCase() === 'hy-menu-item') { this.menuContainerActiveTrail.emit({triggerItem: element.getAttribute('menu-link-id')}); } }); } } componentWillRender() { this.hasChildren = !!this.el.hasChildNodes(); let parentMenu = this.el.closest('hy-menu-item'); let nextParentMenu; this.depth = 0; while (parentMenu) { nextParentMenu = parentMenu.parentElement.closest('hy-menu-item'); if (nextParentMenu === parentMenu) { break; } else { if (nextParentMenu !== null) { this.parentAsHeading = nextParentMenu; } parentMenu = nextParentMenu; this.depth = this.depth + 1; } } } render() { return ( <Host class={{ 'is-active': this.isActive, 'menu-item--alternative': this.menuItemAlternative, 'hy-menu-item': true }} > <a aria-current={this.isHeading.toString()} href={this.url} class={{ 'is-active': this.isActive, 'in-active-trail': this.inActiveTrail, 'is-heading': this.isHeading }} > <span class={'hy-menu-item__label'}>{this.label}</span> </a> {this.hasChildren && ( <button // TODO: Fix aria-label translation. aria-haspopup={'true'} aria-label={`Open submenu for ${this.label}`} onClick={() => this.handleClick()} class={'hy-menu-item__button'} > <hy-icon icon={'hy-icon-caret-right'} size={12} /> </button> )} {this.hasChildren && <slot />} </Host> ); } }