<div class="search">
<div class="search__inner">
<div class="search__textfield-wrapper">
<div class="textfield search__textfield">
<label class="textfield__label h-visually-hidden" for="search1">
Otsing
</label>
<div class="textfield__inner">
<input class="textfield__input" type="text" id="search1" name="search" placeholder="Otsi arvete hulgast...">
</div>
</div>
<button class="search__clear js-search-clear" type="button" aria-label="Tühjenda">
<span class="search__clear-inner">
<svg class="icon search__icon" focusable="false">
<use href="../../inc/svg/global.4609ec92109fc41e7ad4764ef897ea8e.svg#close"></use>
</svg>
</span>
</button>
</div>
<button class="search__button search__button--toggle js-search-toggle" type="button" aria-label="Otsi">
<span class="search__button-inner">
<svg class="icon search__icon" focusable="false">
<use href="../../inc/svg/global.4609ec92109fc41e7ad4764ef897ea8e.svg#search"></use>
</svg>
</span>
</button>
<button class="search__button search__button--submit" type="submit" aria-label="Otsi">
<span class="search__button-inner">
<svg class="icon search__icon" focusable="false">
<use href="../../inc/svg/global.4609ec92109fc41e7ad4764ef897ea8e.svg#search"></use>
</svg>
</span>
</button>
</div>
</div>
{% set BEM -%}
search
{%- if modifier %} {{ modifier }}{% endif %}
{%- if class %} {{ class }}{% endif %}
{% endset %}
<div class="{{ BEM }}">
<div class="search__inner">
<div class="search__textfield-wrapper">
{% include '@textfield' with { class: 'search__textfield', modifier: '', data: data.textfield } %}
<button class="search__clear js-search-clear" type="button" aria-label="{{ data.clearText }}">
<span class="search__clear-inner">
{% include '@icon' with { name: 'close', class: 'search__icon', modifier: '' } %}
</span>
</button>
</div>
<button class="search__button search__button--toggle js-search-toggle" type="button" aria-label="{{ data.searchText }}">
<span class="search__button-inner">
{% include '@icon' with { name: 'search', class: 'search__icon', modifier: '' } %}
</span>
</button>
<button class="search__button search__button--submit" type="submit" aria-label="{{ data.submitText }}">
<span class="search__button-inner">
{% include '@icon' with { name: 'search', class: 'search__icon', modifier: '' } %}
</span>
</button>
</div>
</div>
{
"language": "en-US",
"data": {
"textfield": {
"label": "Otsing",
"id": "search1",
"name": "search",
"placeholder": "Otsi arvete hulgast...",
"isLabelHidden": true
},
"clearText": "Tühjenda",
"searchText": "Otsi",
"submitText": "Otsi"
}
}
.search {
display: none;
@include bp(lg-min) {
display: block;
}
&.is-open {
display: block;
}
}
.search__inner {
display: flex;
align-items: center;
@include bp(lg-min) {
gap: 2px;
}
}
.search__button {
display: inline-block;
padding: 0;
background: transparent;
border: none;
border-radius: $border-radius-base;
color: $brand-primary;
outline: none;
text-align: center;
cursor: pointer;
-webkit-appearance: none;
transition: background $transition-duration-s $transition-easing,
border-radius $transition-duration-s $transition-easing,
color $transition-duration-s $transition-easing;
&:hover {
background: $L-background-none-hover;
}
html[data-whatinput='keyboard'] &:focus {
background: $L-background-none-hover;
outline: 2px solid $L-filter-focus;
outline-offset: 2px;
}
.search.is-open & {
background: $brand-primary;
color: $L-text-inverted;
border-top-left-radius: 0;
border-bottom-left-radius: 0;
}
}
.search__button--toggle {
display: none;
@include bp(lg-min) {
display: inline-block;
}
}
.search__button--submit {
@include bp(lg-min) {
display: none;
}
}
.search__button-inner {
display: flex;
align-items: center;
justify-content: center;
padding: 6px;
.search__button--submit & {
padding: 8px;
}
}
.search__clear {
opacity: 0;
visibility: hidden;
display: inline-block;
position: absolute;
top: 50%;
right: 0;
padding: 0;
background: transparent;
border: none;
color: $L-border-medium;
outline: none;
text-align: center;
cursor: pointer;
-webkit-appearance: none;
transform: translateY(-50%);
transition: opacity $transition-duration-s $transition-easing,
visibility $transition-duration-s $transition-easing;
&:hover {
color: $brand-primary;
}
.search.is-dirty & {
opacity: 1;
visibility: visible;
}
}
.search__clear-inner {
display: flex;
align-items: center;
justify-content: center;
padding: 6px;
}
.search__icon {
flex: 0 0 24px;
font-size: 24px;
}
.search__textfield-wrapper {
display: block;
position: relative;
flex: 1 1 100%;
opacity: 0;
visibility: hidden;
transition: opacity $transition-duration-s $transition-easing,
visibility $transition-duration-s $transition-easing;
.search.is-open & {
opacity: 1;
visibility: visible;
}
}
.textfield__input {
.search__textfield & {
border: 1px solid $L-border-medium;
border-top-right-radius: 0;
border-bottom-right-radius: 0;
min-height: 40px;
}
}
import Component from '../../component/component';
import './search.scss';
export interface ISearchSettings {
buttonSelector?: string;
clearSelector?: string;
dirtyClass?: string;
inputSelector?: string;
openClass?: string;
}
export const searchSettings: ISearchSettings = {
buttonSelector: '.js-search-toggle',
clearSelector: '.js-search-clear',
dirtyClass: 'is-dirty',
inputSelector: '.textfield__input',
openClass: 'is-open',
};
export default class Search extends Component {
static initSelector: string = '.search';
clear: JQuery<HTMLElement>;
input: JQuery<HTMLElement>;
settings: ISearchSettings;
toggle: JQuery<HTMLElement>;
constructor(target: HTMLElement) {
super(target);
this.settings = searchSettings;
this.clear = this.element.find(this.settings.clearSelector);
this.input = $('body').find(this.settings.inputSelector);
this.toggle = this.element.find(this.settings.buttonSelector);
this.toggle.on('click', this.onClick.bind(this));
this.input.on('keyup change', this.handleInputChange.bind(this));
this.clear.on('click', this.handleClear.bind(this));
}
onClick(): void {
if (this.element.hasClass(this.settings.openClass)) {
this.element.removeClass(this.settings.openClass);
} else {
this.element.addClass(this.settings.openClass);
window.setTimeout(() => {
this.input.trigger('focus');
}, 150);
}
}
handleInputChange(): void {
if (this.input.val() !== '') {
this.element.addClass(this.settings.dirtyClass);
} else {
this.element.removeClass(this.settings.dirtyClass);
}
}
handleClear(): void {
this.input.val('');
this.element.removeClass(this.settings.dirtyClass);
}
}
$(() => {
$(document).on('click', (event: Event) => {
const isDirty: boolean = $('.search').hasClass(searchSettings.dirtyClass);
if ($(event.target).closest('.search').length === 0 && $(event.target).closest('.search-toggle').length === 0 && !isDirty) {
$('.search').removeClass(searchSettings.openClass);
$('.search-toggle').removeClass(searchSettings.openClass);
}
});
});