Newer
Older
url: string;
description: string;
menuLinkId: string;
isExternal: string;
}
export interface SearchLabels {
label?: string;
}
import {Component, Prop, h, Watch, State, Listen, Host, Event, EventEmitter, Element} from '@stencil/core';
Markus Kalijärvi
committed
import {ComponentLabels} from '../site-header';
import {ColorVariant} from '../../../utils/utils';
@Component({
tag: 'hy-site-search',
styleUrl: 'site-search.scss',
shadow: true,
@Prop() color: ColorVariant = ColorVariant.black;
@Prop() isAlternative: boolean = false;
@Prop() searchLabels: string;
@Prop() searchTools: string;
private _searchTools: SearchTools[];
@Prop() showLabel: boolean = false;
@Prop() size: number;
private _searchLabels: SearchLabels[];
private searchTitleLabel: string;
private searchCloseLabel: string;
private searchToolsLabel: string;
private searchDescriptionLabel: string;
@State() isSearchPanelOpen: boolean = false;
@Event() searchPanelToggled: EventEmitter;
private _labels: ComponentLabels[];
@Watch('labels') labelsWatcher(data: ComponentLabels[] | string) {
this._labels = typeof data === 'string' ? JSON.parse(data) : data;
}
// Special search tools.
if (this.searchTools) {
this._searchTools = JSON.parse(this.searchTools);
}
if (this.searchLabels) {
this._searchLabels = JSON.parse(this.searchLabels);
this.searchTitleLabel = this._searchLabels['search_label'];
this.searchCloseLabel = this._searchLabels['search_close_label'];
this.searchToolsLabel = this._searchLabels['search_tools_label'];
this.searchDescriptionLabel = this._searchLabels['search_description'];
componentWillRender() {
this.labelsWatcher(this.labels);
}
// CLose the search panel if user opens the desktop menu panel.
@Listen('menuDesktopToggled', {target: 'document'})
desktopMenuToggled() {
this.isSearchPanelOpen = false;
this.showBackdropShadow();
}
// CLose the search panel if user opens the mobile menu panel.
@Listen('menuMobileToggled', {target: 'document'})
mobileMenuToggled() {
this.isSearchPanelOpen = false;
this.showBackdropShadow();
}
// CLose the search panel if user opens the language menu.
@Listen('menuLanguageToggled', {target: 'document'})
menuLanguageToggled() {
this.isSearchPanelOpen = false;
this.isSearchPanelOpen = !this.isSearchPanelOpen;
if (this.isSearchPanelOpen) {
//const searchPanelSelector = this.el as HTMLElement;
// Close desktop menu panel and lang menu panel if they are open.
this.searchPanelToggled.emit();
let hyHeader = this.el.closest('.hy-site-header') as HTMLElement;
const headerHeight = hyHeader.classList.contains('hy-site-header--sticky-active')
? `${hyHeader.offsetHeight}px`
: `${hyHeader.offsetTop + hyHeader.offsetHeight}px`;
const searchPanel = this.el.shadowRoot.querySelectorAll(`.site-search__panel`)[0] as HTMLElement;
searchPanel.style.top = headerHeight;
// Add shadow backdrop
let rect = searchPanel.getBoundingClientRect();
let shadowTop = hyHeader.classList.contains('hy-site-header--sticky-active')
? hyHeader.offsetHeight + rect.height
: hyHeader.offsetTop + hyHeader.offsetHeight + rect.height;
this.showBackdropShadow('open', shadowTop);
// Without setTimeout it will not focus the input because it hasn't rendered yet.
setTimeout(() => {
const searchInput = this.el.shadowRoot.querySelector('input#search') as HTMLElement;
searchInput.focus();
});
showBackdropShadow(state = 'close', top = 0) {
let hyHeader = this.el.closest('.hy-site-header') as HTMLElement;
let hyBackdropDiv = hyHeader.children[0] as HTMLElement;
if (hyBackdropDiv) {
if (state === 'open') {
let me = window.outerHeight - top;
hyBackdropDiv.style.height = `${me}px`;
hyBackdropDiv.style.top = `${top}px`;
hyBackdropDiv.style.position = 'absolute';
hyBackdropDiv.classList.add('is-active');
} else {
hyBackdropDiv.removeAttribute('style');
hyBackdropDiv.classList.remove('is-active');
}
}
}
handleSearchPanelClose() {
this.isSearchPanelOpen = false;
'site-search': true,
'site-search__is-open': this.isSearchPanelOpen,
aria-expanded={`${this.isSearchPanelOpen}`}
class={{
'button--search': true,
'is-open--menu': this.isAlternative,
'is-open': this.isSearchPanelOpen,
}}
>
{this.showLabel ? <span class={'button--search__label'}>{this._labels['label']}</span> : ''}
<hy-icon icon={'hy-icon-search'} size={this.size} fill={this.color} />
</button>
<div
class={{
'site-search__panel': true,
'site-search__panel__is-open': this.isSearchPanelOpen,
}}
aria-hidden={`${!this.isSearchPanelOpen}`}
<div class="site-search__panel__wrapper">
<div class="site-search__panel__title">
<div class="site-search__panel__title__group">
<h1>{this.searchTitleLabel}</h1>
<div class="description">{this.searchDescriptionLabel}</div>
<div class="site-search__panel__input">
<hy-search-field input-id="search" />
</div>
<div class="site-search__panel__results">
<div class="filters"></div>
<div class="results"></div>
{this._searchTools && this._searchTools.length > 0 && (
<div class="title">{this.searchToolsLabel}</div>
<div class="list">
{this._searchTools.map((i) => {
let searchToolTarget = i.isExternal ? '_blank' : '_self';
return (
<a class="search-special-tool" href={i.url} target={searchToolTarget}>
<hy-icon icon={'hy-icon-arrow-to-right'} size={14} fill={ColorVariant.black} />
<span class="label">{i.label}</span>
<span class="description">{i.description}</span>
</a>
);
})}
</div>
<button
onClick={() => this.handleSearchPanelClose()}
class={{
'site-search__panel__panel-toggle': true,
}}
aria-label={this.searchCloseLabel}
aria-expanded={`${this.isSearchPanelOpen}`}
>
<span class="site-search__panel__panel-toggle__label">
<span class="site-search__panel__panel-toggle__label__title" tabindex="0">
{this.searchCloseLabel}
</span>
<hy-icon icon={'hy-icon-remove'} size={16} fill={ColorVariant.black} />
</span>
</button>