Skip to content
Snippets Groups Projects
menu-item-sidebar.tsx 6.67 KiB
Newer Older
  • Learn to ignore specific revisions
  • import {Component, Element, Event, EventEmitter, h, Prop, Listen} from '@stencil/core';
    import {MenuType} from '../../../utils/utils';
    
    @Component({
      tag: 'hy-menu-item-sidebar',
      styleUrl: 'menu-item-sidebar.scss',
      shadow: false,
    })
    export class MenuItemSidebar {
      @Element() el: HTMLElement;
      @Event() addBreadcrumb: EventEmitter;
      @Event() menuContainerActiveTrail: EventEmitter;
      @Event() menuContainerToggled: EventEmitter;
      @Event() routeClicked: EventEmitter;
      @Prop() inActiveTrail: boolean = false;
      @Prop() isActive: boolean = false;
      @Prop() isActiveChild?: boolean = false;
      @Prop() isHeading: boolean = false;
      @Prop() isParent: boolean = false;
      @Prop() isDemo: boolean = false;
      @Prop() menuItemAlternative: boolean = false;
      @Prop() menuLinkId: string = '';
      @Prop() menuType: MenuType = MenuType.sidenav;
      @Prop() menuButtonSubmenuExpand?: string = '';
      @Prop() menuIsOpen = false;
      @Prop({mutable: true}) ariaExpanded: boolean = false;
      @Prop({mutable: true, reflect: true}) depth: number = 0;
      @Prop({mutable: true}) hasChildren: boolean = null;
      @Prop({mutable: true}) label: string = '';
      @Prop({mutable: true}) parentAsHeading: string = '';
      @Prop({mutable: true, reflect: true}) parentExpanded: boolean = false;
      @Prop({mutable: true}) url: string = '';
    
      @Listen('sidebarTopLevelToggle') sidebarTopLevelToggle(e) {
        if (this.depth !== 1) {
          return;
        }
    
        const body = document.querySelector('body') as HTMLElement;
        const container = document.querySelector('.hy-menu-sidebar--container') as HTMLElement;
        const menuItem = e.target.closest('.hy-menu-item-sidebar') as HTMLElement;
    
        if (container.classList.contains('sidebar-open') && menuItem.classList.contains('is-active-item')) {
          container.classList.remove('sidebar-open');
          body.classList.remove('hy-menu-sidebar__no-scroll');
        } else {
          container.classList.add('sidebar-open');
          body.classList.add('hy-menu-sidebar__no-scroll');
        }
    
        e.preventDefault();
      }
    
      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;
        }
    
        // If current menu item is active, 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-sidebar') {
              elem = elem.parentNode;
              parents.push(elem);
            }
            return parents;
          };
    
          const parents = getParents(this.el);
          parents.forEach((element) => {
            if (element.tagName.toLowerCase() === 'hy-menu-item-sidebar') {
              this.menuContainerActiveTrail.emit({
                triggerItem: element.getAttribute('menu-link-id'),
              });
            }
          });
    
          // If side navigation menu item has is-active state, prepare the menu items
          // for the last children.
          parents.forEach((element) => {
            if (element.tagName.toLowerCase() === 'hy-menu-item-sidebar') {
              element.classList.add('is-hidden--child');
            }
          });
    
          // If current active menu item have children, set the child
          // menu-level-container open.
          if (this.el.children.length > 0) {
            this.el.children[0].setAttribute('class', 'is-open-on-top');
          }
        }
      }
    
    
      componentDidLoad() {
        if (this.inActiveTrail) {
          const currentParent = this.el.parentNode as any;
          if (this.menuType === MenuType.sidepanel) {
            currentParent.classList.add('is-open');
            const childList = this.el.querySelector('.hy-menu-level-container') as HTMLElement;
            if (childList) {
              childList.classList.add('is-open');
            }
          }
        }
      }
    
    
      componentWillRender() {
        // Assign depth value to current menu item instance; 1st level, 2nd level, etc.
        this.hasChildren = this.el.getElementsByTagName('hy-menu-level-container').length >= 1;
        let parentMenuItem = this.el.closest('hy-menu-item-sidebar');
        let nextParentMenuItem;
        this.depth = 0;
        while (parentMenuItem) {
          nextParentMenuItem = parentMenuItem.parentElement.closest('hy-menu-item-sidebar');
          if (nextParentMenuItem === parentMenuItem) {
            break;
          } else {
            if (nextParentMenuItem !== null) {
              this.parentAsHeading = nextParentMenuItem;
            }
            parentMenuItem = nextParentMenuItem;
            this.depth = this.depth + 1;
          }
        }
      }
    
      render() {
        let classAttributes = [
          'hy-menu-item-sidebar',
          this.menuType ? `hy-menu-item-sidebar--${this.menuType}` : '',
          this.depth != null ? 'hy-menu-item--level-' + this.depth : '',
          this.isDemo ? 'is-demo' : '',
          this.isActive ? 'is-current-page' : '',
          this.isParent ? 'is-parent' : '',
          this.hasChildren ? 'has-children' : '',
          this.inActiveTrail ? 'in-active-trail' : '',
          this.isActive && this.hasChildren ? 'is-active--heading' : '',
        ];
        let anchorClassAttributes = ['hy-menu-item-sidebar__label'];
        classAttributes = [...classAttributes];
    
        if (this.url) {
          return (
            <li
              data-link-id={`menu-link-sidebar-${this.menuLinkId}`}
              class={classAttributes.join(' ')}
              aria-current={this.isActive ? 'true' : 'false'}
              item-level={this.depth}
            >
              {this.isParent && (
                <span class={'hy-menu-item__parent__icon'}>
                  <hy-icon
                    class={'hy-menu-item__parent__icon__svg'}
                    icon={'hy-icon-caret-left'}
                    fill={'currentColor'}
                    size={10}
                  />
                </span>
              )}
              <div class="hy-menu-item-sidebar--label-container">
                {this.isActive ? (
                  <span class={anchorClassAttributes.join(' ')}>{this.label}</span>
                ) : (
                  <a class={anchorClassAttributes.join(' ')} href={this.url}>
                    {this.label}
                  </a>
                )}
                {this.hasChildren && (
                  <button
                    aria-labelledby={this.label}
                    aria-expanded={this.inActiveTrail && !this.isActive ? 'true' : 'false'}
                    type="button"
                    class={'hy-menu-item__label__icon'}
                    onClick={(e) => this.sidebarTopLevelToggle(e)}
                  >
                    <hy-icon
                      class={'hy-menu-item__label__icon__svg'}
                      icon={'hy-icon-caret-right'}
                      fill={'currentColor'}
                      size={18}
                    />
                  </button>
                )}
              </div>
              {this.hasChildren && <slot />}
            </li>
          );
        } else {
          return;
        }
      }
    }