export interface MainMenu { label: string; url: string; menuLinkId: string; } export interface DonateLink { url: string; label: string; } import {Component, Host, h, Element, Prop, State, Watch, Listen, Event, EventEmitter} from '@stencil/core'; import {ColorVariant, SiteLogoSize} from '../../../utils/utils'; let keys = { enter: 'Enter', }; @Component({ tag: 'hy-menu-main-group', styleUrl: 'hy-menu-main-group.scss', shadow: true, }) export class HyMenuMainGroup { @Element() el: HTMLElement; @Prop() menuLabel: string = 'University main menu'; @Prop() dataMainMenu: MainMenu[] | string; @Prop() isMobile: boolean = false; @Prop() logoUrl?: string; @Prop() logoLabel?: string; @Prop() siteLabel?: string; @Prop() siteUrl?: string; @Prop() donate: DonateLink[]; @State() isMenuOpen: boolean = false; @Event() universityMainMenuToggled: EventEmitter; @Event() mobileMenuTopToggle: EventEmitter; private _dataMainMenu: MainMenu[]; @Watch('dataMainMenu') dataMainMenuWatcher(data: MainMenu[] | string) { this._dataMainMenu = typeof data === 'string' ? JSON.parse(data) : data; } @Listen('click') handleComponentClick(event) { this.mobileMenuTopToggle.emit(); this.isMenuOpen = !this.isMenuOpen; if (this.isMenuOpen) { this.emitEvent(); this.adjustMainMenuPosition(event.target); } event.stopPropagation(); } @Listen('keydown') handleComponentKeyDown(event: KeyboardEvent) { const key = event.code; let target = event.target as HTMLButtonElement; if (target && [keys.enter].includes(key)) { this.isMenuOpen = !this.isMenuOpen; if (this.isMenuOpen) { this.emitEvent(); this.adjustMainMenuPosition(target); event.preventDefault(); } } } emitEvent() { // Close other panels if they are open (lang menu, search, main menu, ..). this.universityMainMenuToggled.emit(); } adjustMainMenuPosition(target) { let hyTopHeader = this.el.closest('.hy-site-header__content-top') as HTMLElement; if (hyTopHeader && !hyTopHeader.hasAttribute('is-mobile')) { let mainMenuToggle = target.shadowRoot.querySelector('.menu--main-group__toggle') as HTMLElement; let mainMenuDropdown = target.shadowRoot.querySelector('.menu--main-group__dropdown') as HTMLElement; let mainMenuList = target.shadowRoot.querySelector('.list') as HTMLElement; if (mainMenuDropdown && mainMenuList && mainMenuToggle) { let rectHeader = hyTopHeader.getBoundingClientRect(); let rectMenuToggle = mainMenuToggle.getBoundingClientRect(); mainMenuDropdown.style.top = `${rectHeader.height}px`; mainMenuList.style.left = `${rectMenuToggle.left}px`; } } } componentWillRender() { this.dataMainMenuWatcher(this.dataMainMenu); } handleMainMenuClose(event) { this.isMenuOpen = false; event.stopPropagation(); } // Close the University main menu if user clicks anywhere outside the component. @Listen('click', {target: 'window'}) handleOutsideMenuClick(event) { this.isMenuOpen = false; event.stopPropagation(); } // CLose the University main menu if user opens the desktop menu panel. @Listen('menuDesktopToggled', {target: 'document'}) desktopMenuToggled() { this.isMenuOpen = false; } // CLose the University main menu if user opens the search panel @Listen('searchPanelToggled', {target: 'document'}) searchPanelToggled() { this.isMenuOpen = false; } // CLose the University main menu if user opens the language menu panel. @Listen('menuLanguageToggled', {target: 'document'}) languageMenuToggled() { this.isMenuOpen = false; } render() { const white = 'var(--grayscale-white)'; const logoSizeGroup = this.isMobile ? SiteLogoSize.small : SiteLogoSize.small; const logoColorGroup = ColorVariant.white; return this.isMobile ? ( <Host class={{ 'menu--main-group--mobile': true, 'menu--main-group--mobile__is-open': this.isMenuOpen, }} > <button class={{ 'menu--main-group__mobile-toggle': true, 'is-open': this.isMenuOpen, }} > <hy-icon icon={'hy-icon-slim-hamburger-menu'} size={20} fill={white} /> </button> <nav role="navigation" aria-hidden={this.isMenuOpen ? 'false' : 'true'} class={{ 'menu--main-group__dropdown--mobile': true, 'is-open': this.isMenuOpen, }} > <div class="menu--main-group__dropdown__top"> <div class={'menu--main-group__logo-container'} id={'menu-logo'}> <hy-site-logo is-group={true} size={logoSizeGroup} color={logoColorGroup} url={this.siteUrl} label={this.siteLabel} /> </div> <button class="menu--main-group__dropdown__close" onClick={() => this.isMenuOpen == false}> <hy-icon icon={'hy-icon-remove'} size={20} fill={white} /> </button> </div> <div class="menu--main-group__dropdown__items"> {this._dataMainMenu.map((item) => { return ( <a href={item.url} class={{'menu-main-link': true}}> <span class={'menu--main-group__label'}>{item.label}</span> </a> ); })} </div> <div class="menu--main-group__dropdown__donate"> {this.donate && this.donate.map((i) => { return ( <a class={'menu--secondary__item hy-link__donate group'} href={i.url}> <hy-icon icon={'hy-icon-heart-support'} size={14} fill={logoColorGroup} /> <span class={'hy-link__donate__label group'}>{i.label}</span> </a> ); })} </div> </nav> </Host> ) : ( <Host class={{ 'menu--main-group': true, 'menu--main-group__is-open': this.isMenuOpen, }} > <button class={{ 'menu--main-group__toggle': true, 'is-open': this.isMenuOpen, }} //aria-label={this.isMenuOpen ? this._labels['close'] : this._labels['open']} > {this.isMenuOpen ? ( <hy-icon class={'toggle__close'} icon={'hy-icon-remove'} size={8} fill={white} /> ) : ( <hy-icon class={'toggle__caret'} icon={'hy-icon-slim-hamburger-menu'} size={8} fill={white} /> )} <span>{this.menuLabel}</span> </button> <div class={{ 'menu--main-group__dropdown': true, 'is-open': this.isMenuOpen, }} > <div class="list"> {this._dataMainMenu.map((item) => { return ( <a href={item.url} class={{'menu-main-link': true}}> <span class="heading-icon"> <hy-icon icon={'hy-icon-caret-right'} size={10} fill={white} /> </span> <span class={'menu--main-group__label'}>{item.label}</span> </a> ); })} </div> <button onClick={(e) => this.handleMainMenuClose(e)} class={{ 'panel-toggle': true, }} aria-label="Close menu" > <span class="panel-toggle__label"> <span class="panel-toggle__label__title">Close</span> <hy-icon icon={'hy-icon-remove'} size={20} fill={ColorVariant.white} /> </span> </button> </div> </Host> ); } }