@salla.sa/twilight-components
Version:
Salla Web Component
290 lines (289 loc) • 11.9 kB
JavaScript
/*!
* Crafted with ❤ by Salla
*/
import { h } from "@stencil/core";
import Search from "../../assets/svg/search.svg";
import Helper from "../../Helpers/Helper";
/**
* @slot product - Replaces products card in the results, has replaceable props `{name}`, `{price}`, `{regular_price}`, `{image}`.
*/
export class SallaSearch {
constructor() {
var _a;
this.inputValue = '';
this.translationLoaded = false;
this.loading = false;
this.typing = false;
this.debounce = setTimeout(() => '', 1000);
/**
* Set the component display without modal window. Defaults to `false`
*/
this.inline = false;
/**
* Adds a border radius to the input. Half of the height.
*/
this.oval = false;
/**
* Sets the height of the input
*/
this.height = 60;
/**
* Maximum number of words allowed in the input
*/
this.maxWords = 5;
/**
* Show submit action buttons at the end.
*/
this.showAction = false;
this.productSlot = ((_a = this.host.querySelector('[slot="product"]')) === null || _a === void 0 ? void 0 : _a.innerHTML) || this.getDefaultProductSlot();
salla.event.on('search::open', () => this.open());
salla.lang.onLoaded(() => {
this.translationLoaded = true;
});
salla.event.on('modalClosed', () => this.onModalClose());
}
async open() {
if (!this.inline) {
await this.modal.open().then(() => setTimeout(() => this.searchInput.focus(), 300));
}
}
onModalClose() {
this.searchInput.value = '';
this.results = undefined;
this.afterSearching();
this.container.classList.remove('s-search-no-results');
}
handleKeyDown(ev) {
var _a;
if (ev.key === 'Enter' && ((_a = this.search_term) === null || _a === void 0 ? void 0 : _a.length)) {
window.location.href = salla.url.get('search?q=' + encodeURI(this.search_term));
}
}
getDefaultProductSlot() {
return '<div class="s-search-product-image-container">' +
' <img class="s-search-product-image" src="{image}" alt="{name}"/>' +
'</div>' +
'<div class="s-search-product-details">' +
' <div class="s-search-product-title">{name}</div> <div class="s-search-product-price">{price} <span class="s-search-product-regular-price">{regular_price}</span></div>' +
'</div>';
}
debounceSearch(event) {
this.typing = true;
clearTimeout(this.debounce);
this.debounce = setTimeout(() => {
this.typing = false;
this.search_term = event.target.value;
}, 700);
}
limitWordsAndSearch(event) {
let value = event.target.value;
const words = value.trim().split(/\s+/);
if (words.length > this.maxWords) {
const truncatedInput = words.slice(0, this.maxWords).join(' ');
this.searchInput.value = truncatedInput;
}
this.debounceSearch(event);
}
getQueryParam(param) {
const urlParams = new URLSearchParams(window.location.search);
return urlParams.get(param);
}
handleActionClick() {
if (!!this.search_term && this.search_term.length > 2) {
return this.search(this.search_term);
}
}
handleSearch(val) {
this.inputValue = val;
if (val.length > 2) {
this.search(val);
}
else {
this.results = undefined;
this.afterSearching();
}
}
search(val) {
this.noResults.style.display = 'none';
//run loading spinner or stop it
this.loading = true;
salla.product.fetch({ source: "search", source_value: val })
.then(response => {
this.results = response;
salla.event.emit('Products Searched', val);
})
.catch(err => err !== 'Query is same as previous one!' ? this.results = undefined : null)
.finally(() => this.afterSearching(/*isEmpty*/ false));
}
afterSearching(isEmpty = true) {
var _a;
this.noResults.style.display = isEmpty || ((_a = this.results) === null || _a === void 0 ? void 0 : _a.data.length) > 0 ? 'none' : 'block';
Helper.toggleElementClassIf(this.container, 's-search-container-open', 's-search-no-results', () => { var _a; return (_a = this.results) === null || _a === void 0 ? void 0 : _a.data.length; });
this.loading = false;
salla.product.api.previousQuery = ''; //avoid having error 'Query is same as previous one!' after reopen modal;
this.inputValue.length < 3 ? this.container.classList.remove('s-search-no-results') : '';
}
render() {
var _a;
const searchContent = h("div", { key: 'eb0cc353dbbe919fc0489c2c262ee017724c097a', class: { 's-search-container': true, 's-search-inline': this.inline }, ref: container => this.container = container }, h("div", { key: '8fced73d5abd5a7df0a0038e656cd453d4dc07cf', class: "s-search-input-wrapper" }, h("span", { key: '6c9699f37207f2666dacbe1b951d84f183e4d7c3', class: "s-search-icon-wrap" }, h("span", { key: '1d88ca718aac8c4ce66a20ff372d2b78e90a09dc', class: "s-search-icon", innerHTML: this.loading ? '<i class="s-search-spinner-loader"/>' : Search })), h("input", { key: 'c25f01acce8f28b1bfa4a7d02fa72b88836aa6e0', type: "search", enterkeyhint: "search", autocomplete: "off", class: "s-search-input", placeholder: salla.lang.get('blocks.header.search_placeholder'), onInput: (e) => this.limitWordsAndSearch(e), onKeyDown: e => this.handleKeyDown(e), ref: input => this.searchInput = input, style: { height: this.height + 'px', borderRadius: this.oval ? this.height / 2 + 'px' : '' } }), this.showAction ?
h("salla-button", { loading: this.loading, class: { 's-search-action': true, 's-search-action-oval': this.oval }, onClick: () => this.handleActionClick() }, !this.loading && h("span", { innerHTML: Search })) : null), h("div", { key: '8d63e3293e8fe434b45096aeffbeefe3a8fbb5c8', class: "s-search-results" }, (_a = this.results) === null || _a === void 0 ? void 0 :
_a.data.map((product) => h("a", { href: product.url + '?from=search-bar', class: { "s-search-product": true, 's-search-product-not-available': !product.is_available }, innerHTML: this.productSlot
.replace(/\{name\}/g, product.name)
.replace(/\{price\}/g, salla.money(product.price))
.replace(/\{regular_price\}/g, product.is_on_sale ? salla.money(product.regular_price) : '')
.replace(/\{image\}/g, product.image.url) })), h("p", { key: '20dd4c327696b7e3fe385119a369b4fa064e73c2', ref: el => this.noResults = el, class: "s-search-no-results-placeholder" }, salla.lang.get('common.elements.no_options'))));
return (this.inline ?
h("div", { class: "s-search-modal" }, searchContent)
:
h("salla-modal", { position: "top", class: "s-search-modal", ref: modal => this.modal = modal }, searchContent));
}
/**
* Run it one time after load
*/
componentDidLoad() {
this.afterSearching();
this.searchInput.value = this.getQueryParam('q');
}
static get is() { return "salla-search"; }
static get originalStyleUrls() {
return {
"$": ["salla-search.scss"]
};
}
static get styleUrls() {
return {
"$": ["salla-search.css"]
};
}
static get properties() {
return {
"inline": {
"type": "boolean",
"attribute": "inline",
"mutable": false,
"complexType": {
"original": "boolean",
"resolved": "boolean",
"references": {}
},
"required": false,
"optional": false,
"docs": {
"tags": [],
"text": "Set the component display without modal window. Defaults to `false`"
},
"getter": false,
"setter": false,
"reflect": false,
"defaultValue": "false"
},
"oval": {
"type": "boolean",
"attribute": "oval",
"mutable": false,
"complexType": {
"original": "boolean",
"resolved": "boolean",
"references": {}
},
"required": false,
"optional": false,
"docs": {
"tags": [],
"text": "Adds a border radius to the input. Half of the height."
},
"getter": false,
"setter": false,
"reflect": false,
"defaultValue": "false"
},
"height": {
"type": "number",
"attribute": "height",
"mutable": false,
"complexType": {
"original": "number",
"resolved": "number",
"references": {}
},
"required": false,
"optional": false,
"docs": {
"tags": [],
"text": "Sets the height of the input"
},
"getter": false,
"setter": false,
"reflect": false,
"defaultValue": "60"
},
"maxWords": {
"type": "number",
"attribute": "max-words",
"mutable": false,
"complexType": {
"original": "number",
"resolved": "number",
"references": {}
},
"required": false,
"optional": false,
"docs": {
"tags": [],
"text": "Maximum number of words allowed in the input"
},
"getter": false,
"setter": false,
"reflect": false,
"defaultValue": "5"
},
"showAction": {
"type": "boolean",
"attribute": "show-action",
"mutable": false,
"complexType": {
"original": "boolean",
"resolved": "boolean",
"references": {}
},
"required": false,
"optional": false,
"docs": {
"tags": [],
"text": "Show submit action buttons at the end."
},
"getter": false,
"setter": false,
"reflect": false,
"defaultValue": "false"
}
};
}
static get states() {
return {
"translationLoaded": {},
"results": {},
"loading": {},
"typing": {},
"debounce": {},
"search_term": {}
};
}
static get elementRef() { return "host"; }
static get watchers() {
return [{
"propName": "search_term",
"methodName": "handleSearch"
}];
}
static get listeners() {
return [{
"name": "keydown",
"method": "handleKeyDown",
"target": undefined,
"capture": false,
"passive": false
}];
}
}
//# sourceMappingURL=salla-search.js.map