Skip to content
Snippets Groups Projects
menu-item.tsx 4.37 KiB
Newer Older
  • Learn to ignore specific revisions
  • 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() inActiveTrail: boolean = false;
      @Prop() isActive: boolean = false;
      @Prop() isHeading: boolean = false;
    
      @Prop() menuItemAlternative: boolean = false;
      @Prop() menuLinkId: string = '';
    
      @Prop() menuType: string = '';
    
      @Prop() menuButtonSubmenuExpand: 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() {
    
        // If is-active class is added by system, add it to menu component as well.
        if (this.el.classList.contains('is-active')) {
          this.isActive = true;
        }
    
    
        // 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') {
    
              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.getElementsByTagName('hy-menu-level-container').length >= 1;
    
        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,
    
              'hy-menu-item': true,
    
              'hy-menu-item--alternative': this.menuItemAlternative,
    
              'hy-menu-item--desktop': this.menuType === 'desktop',
              'is-demo': this.isDemo
    
            }}
          >
            <a
              aria-current={this.isHeading.toString()}
              href={this.url}
              class={{
                'is-active': this.isActive,
                'in-active-trail': this.inActiveTrail,
    
                'is-heading': this.isHeading,
                'hy-menu-item--desktop': this.menuType === 'desktop',
                'hy-menu-item--mobile': this.menuType === 'mobile',
                'is-demo': this.isDemo
    
              }}
            >
              <span class={'hy-menu-item__label'}>{this.label}</span>
            </a>
    
            {this.hasChildren && (
              <button
    
    Markus Kalijärvi's avatar
    Markus Kalijärvi committed
                aria-haspopup={'true'}
    
                aria-label={`${this.menuButtonSubmenuExpand} ${this.label}`}
    
                onClick={() => this.handleClick()}
                class={'hy-menu-item__button'}
              >
                <hy-icon icon={'hy-icon-caret-right'} size={12} />
              </button>
            )}
    
            {this.hasChildren && <slot />}
          </Host>
        );
      }
    }