export interface ShortcutLinks { shortcut_title: string; shortcut_url: string; shortcut_is_external: string; shortcut_aria_label: string; } export interface DesktopLinks { label: string; url: string; description: string; menuLinkId: string; isActive: string; items: Array<DesktopLinks>; shortcuts: Array<ShortcutLinks>; } import {ColorVariant} from '../../../utils/utils'; import {Component, h, Element, Prop, State, Watch} from '@stencil/core'; @Component({ tag: 'hy-desktop-menu-links', styleUrl: 'hy-desktop-menu-links.scss', shadow: true, }) export class HyDesktopMenuLinks { @Element() el: HTMLElement; /* First level menu links to be displayed on Desktop screens. * */ @Prop() dataDesktopLinks: DesktopLinks[] | string; private _dataDesktopLinks: DesktopLinks[]; @State() firstLevelLinksList: Array<object> = []; @State() menuLinkItems: Array<object> = []; @Watch('dataDesktopLinks') dataDesktopLinksWatcher(data: DesktopLinks[] | string) { this._dataDesktopLinks = typeof data === 'string' ? JSON.parse(data) : data; } componentWillLoad() { this.dataDesktopLinksWatcher(this.dataDesktopLinks); } handleDesktopMenuClose() { const menuItems = this.el.shadowRoot.querySelectorAll(`.desktop-menu-link`); const menuPanelItems = this.el.shadowRoot.querySelectorAll('.hy-desktop-menu-panel'); const activeMenuItem = this.el.shadowRoot.querySelector(`.desktop-menu-link[aria-expanded="true"]`); // Return focus to the button of the last desktop panel that was active. if (activeMenuItem !== null) (activeMenuItem as HTMLElement).focus(); // Reset elements by removing the active classes. menuItems.forEach((item) => { item.classList.remove('desktop-menu-link--is-active'); item.setAttribute('aria-expanded', 'false'); }); menuPanelItems.forEach((item) => { item.classList.remove('hy-desktop-menu-panel--is-active'); item.setAttribute('aria-hidden', 'true'); }); } handleDesktopMenuToggle(id) { const menuItems = this.el.shadowRoot.querySelectorAll(`.desktop-menu-link`); const menuPanelItems = this.el.shadowRoot.querySelectorAll('.hy-desktop-menu-panel'); const activeMenuItem = this.el.shadowRoot.querySelector(`.desktop-menu-link[link-id="${id}"]`); const activeMenuItemSibling = activeMenuItem.nextElementSibling; // Reset elements by removing the active classes. menuItems.forEach((item) => { item.classList.remove('desktop-menu-link--is-active'); item.setAttribute('aria-expanded', 'false'); }); menuPanelItems.forEach((item) => { item.classList.remove('hy-desktop-menu-panel--is-active'); item.setAttribute('aria-hidden', 'true'); }); // Add active classes to the currently active item and its sibling element. activeMenuItem.classList.add('desktop-menu-link--is-active'); activeMenuItem.setAttribute('aria-expanded', 'true'); activeMenuItemSibling.classList.add('hy-desktop-menu-panel--is-active'); activeMenuItemSibling.setAttribute('aria-hidden', 'false'); } componentDidLoad() { const links = this._dataDesktopLinks as Array<DesktopLinks>; let menuLinkItems = []; links.map(({menuLinkId: id, shortcuts, items, url, description, label}) => { menuLinkItems.push( <li> <button type="button" class="desktop-menu-link" link-id={id} onMouseOver={() => this.handleDesktopMenuToggle(id)} onFocus={() => this.handleDesktopMenuToggle(id)} aria-expanded="false" > {label} <span class="desktop-menu-link__heading__icon"> <hy-icon icon={'hy-icon-caret-down'} size={16} /> </span> </button> <div class="hy-desktop-menu-panel" onMouseLeave={() => this.handleDesktopMenuClose()} aria-hidden="true"> <div class="hy-desktop-menu-panel__desktop-menu"> <a aria-current={label} href={url} class="" menu-link-id={id}> <span class="heading-icon-first"> <hy-icon icon={'hy-icon-arrow-right'} size={40} /> </span> <span class="hy-menu-item__label">{label}</span> <span class="hy-menu-item__description">{description}</span> </a> <ul class={'desktop-menu first'} menu-link-id={id}> {items.map(({label, url, description}) => ( <li> <a href={url}>{label}</a> <span>{description}</span> </li> ))} </ul> {shortcuts.length > 0 && ( <ul class="shortcuts-panel"> <h2 class="shortcuts-panel__title">{'Shortcuts'}</h2> {shortcuts.map(({shortcut_title, shortcut_url, shortcut_is_external, shortcut_aria_label}, index) => { let target = shortcut_is_external ? '_blank' : '_self'; let shortcutClass = [ 'shortcuts-panel__shortcut-item', index == 0 ? 'shortcuts-panel__shortcut-item__first' : '', ].join(' '); return ( <li class={shortcutClass}> <a aria-current={shortcut_aria_label} href={shortcut_url} class="shortcut-item__link" target={target} aria-label={shortcut_aria_label} > <span class="shortcut-item__label">{shortcut_title}</span> <span class="shortcut-item__icon"> <hy-icon icon={'hy-icon-arrow-right'} size={24} /> </span> </a> </li> ); })} </ul> )} </div> <button onClick={() => this.handleDesktopMenuClose()} class={{ 'hy-desktop-menu-panel__panel-toggle': true, }} aria-label="Close menu" > <span class="hy-desktop-menu-panel__panel-toggle__label"> CLOSE <hy-icon icon={'hy-icon-remove'} size={20} fill={ColorVariant.black} /> </span> </button> </div> </li> ); }); this.menuLinkItems = menuLinkItems; } render() { return ( <nav role={'navigation'} class="hy-site-header__menu-desktop"> <ul class="hy-site-header__menu-desktop-container">{this.menuLinkItems}</ul> </nav> ); } }