@salla.sa/twilight-components
Version:
Salla Web Component
316 lines (315 loc) • 14.2 kB
JavaScript
/*!
* Crafted with ❤ by Salla
*/
import { Host, h } from "@stencil/core";
import Helper from "../../Helpers/Helper";
import { FilterOptionTypes } from "../salla-filters/interfaces";
export class SallaFiltersWidget {
constructor() {
this.initHeight = 195;
this.isOpen = true;
this.isShowMore = false;
this.showMoreLabel = "عرض المزيد";
this.showLessLabel = "عرض أقل";
this.page = salla.config.get('page');
}
connectedCallback() {
//lets be smart and don't show 5 and more link for 8 options
this.withLoadMore = this.option.key != 'price' && Array.isArray(this.option.values) && this.option.values.length > 8;
salla.onReady(() => {
this.page = salla.config.get('page');
});
salla.lang.onLoaded(() => {
this.showMoreLabel = salla.lang.getWithDefault('common.titles.more', this.showMoreLabel);
this.showLessLabel = salla.lang.getWithDefault('common.elements.show_less', this.showLessLabel);
});
}
componentDidLoad() {
this.widgetValues.scrollHeight < this.initHeight && (this.withLoadMore = false);
(this.withLoadMore && this.widgetValues) && (this.widgetValues.style.maxHeight = `${this.initHeight}px`);
this.widgetContent.style.height = `${this.widgetContent.scrollHeight}px`;
}
/**
* Asynchronously sets the height of a widget element to its current height, allowing for smooth transitions.
* This function is often used in scenarios where the widget's content changes dynamically, and animating
* the height adjustment is desired for a smoother user experience.
*
* @param {number} [delay=250] - Optional. The delay (in milliseconds) before updating the widget height.
* Defaults to 250 milliseconds.
*
* @returns {Promise<void>} - A Promise that resolves once the widget height is set after the specified delay.
*
* @example
* // Set widget height with the default delay (250 milliseconds)
* await setWidgetHeight();
*
* // Set widget height with a custom delay (e.g., 500 milliseconds)
* await setWidgetHeight(500);
*/
async setWidgetHeight(delay = 250) {
this.widgetContent.removeAttribute('style');
setTimeout(() => {
let currentWidgetHeight = this.widgetContent.scrollHeight;
this.widgetContent.style.height = currentWidgetHeight + 'px';
}, delay);
}
/**
* Reset selected filter options.
*/
async reset() {
if (this.option.type === FilterOptionTypes.RANGE) {
this.priceRange.reset();
}
Array.from(this.host.querySelectorAll('input')).forEach(input => input.checked = false);
}
/**
* Action to show more or less filter options.
*/
async showMore() {
this.isShowMore = !this.isShowMore;
this.widgetContent.style.height = 'auto';
this.widgetValues.style.maxHeight = this.isShowMore ? `${this.widgetValues.scrollHeight}px` : `${this.initHeight}px`;
setTimeout(() => {
this.widgetContent.style.height = `${this.widgetContent.scrollHeight}px`;
}, 400); // get height after time of collapse animtion (duration-300)
}
/**
* Action to toggle widget open or closed (expand/ collapse).
*/
async toggleWidget() {
this.isOpen = !this.isOpen;
Helper.toggleElementClassIf(this.widgetContent, 's-filters-widget-opened', 's-filters-widget-closed', () => this.isOpen);
}
renderFilterOption(option) {
if (![FilterOptionTypes.VALUES, FilterOptionTypes.MINIMUM, FilterOptionTypes.VARIANTS].includes(option.type)) {
return '';
}
//@ts-ignore
return option.values.map((filterOption, index) => {
let value = typeof filterOption == 'number' ? filterOption : (filterOption.key || filterOption.value);
return h("label", { class: "s-filters-label", htmlFor: `${option.key}-option-${value}`, key: `${option.key}-option-${value}` }, h("input", { id: `${option.key}-option-${value}`, name: option.key, type: "radio", checked: this.isSelectedOption(option, value), class: `s-filters-radio`, onChange: event => this.changed.emit({ event, option, value }) }), this.getOptionLabel(option, filterOption));
});
}
isSelectedOption(option, value) {
if (option.type === FilterOptionTypes.MINIMUM) {
return this.filtersData[option.key] == value;
}
if (option.type === FilterOptionTypes.VARIANTS) {
return this.filtersData[option.type] && this.filtersData[option.type][Object.keys(this.filtersData[option.type])[0]] == value;
}
if (option.type === FilterOptionTypes.RANGE) {
return this.filtersData[option.key] && this.filtersData[option.key].min == value.min && this.filtersData[option.key].max == value.max;
}
if (option.type === FilterOptionTypes.VALUES) {
return this.filtersData[option.key] && Number(this.filtersData[option.key]) == Number(value);
}
return false;
}
getOptionLabel(option, filterOption) {
if (option.key == 'rating') {
//in amazon has stars & up, should we add it, to avoid those people who will come to say I selected 4 why I see 5 sars products
return h("salla-rating-stars", { size: "small", value: filterOption });
}
let label = filterOption.value || 'null';
//label+=filterOption.count ? ` (${salla.helpers.number(filterOption.count)})` : '';
return h("span", { class: "s-filters-option-name" }, label);
}
render() {
return (h(Host, { key: 'faa16285c7c2dcd248f00230aa4b1eebc1814fdd', class: "s-filters-widget-container" }, h("h3", { key: '019354d300116c2d567b75e5cc93d0d1dfc4785b', class: "s-filters-widget-title", onClick: () => this.toggleWidget() }, h("span", { key: '8ce2bc6a789a0f5d82308afad47cbae58467439a' }, this.option.label), h("span", { key: 'a5dcaa63ad18d41a324b499f36c82780c0670d4f', class: `s-filters-widget-plusminus ${this.isOpen ? 's-filters-widget-plusminus-active' : ''}` })), h("div", { key: 'bef8427341d94bb6eb6e37d9736f9ca3e9503058', class: "s-filters-widget-content", ref: (el) => this.widgetContent = el }, h("div", { key: '451025fa922e84970107fe6ab2752db780effd86', class: "s-filters-widget-values", ref: (el) => this.widgetValues = el }, h("slot", { key: 'cbea119413f48c302684ae52c81786dcb69c6f29' }), this.option.type !== FilterOptionTypes.RANGE
? this.renderFilterOption(this.option)
: h("salla-price-range", { onChanged: (event) => {
this.changed.emit(event.detail);
}, ref: price => this.priceRange = price, filtersData: this.filtersData, option: this.option })), this.withLoadMore &&
h("a", { key: '6b2e1b91b27509b445ad4af9367b4cc464bd2d4e', class: "s-filters-widget-more", onClick: () => this.showMore() }, !this.isShowMore ? this.showMoreLabel : this.showLessLabel))));
}
static get is() { return "salla-filters-widget"; }
static get originalStyleUrls() {
return {
"$": ["salla-filters-widget.scss"]
};
}
static get styleUrls() {
return {
"$": ["salla-filters-widget.css"]
};
}
static get properties() {
return {
"withLoadMore": {
"type": "boolean",
"attribute": "with-load-more",
"mutable": true,
"complexType": {
"original": "boolean",
"resolved": "boolean",
"references": {}
},
"required": false,
"optional": false,
"docs": {
"tags": [],
"text": "Show more or less filter options."
},
"getter": false,
"setter": false,
"reflect": false
},
"filtersData": {
"type": "unknown",
"attribute": "filters-data",
"mutable": false,
"complexType": {
"original": "object",
"resolved": "object",
"references": {}
},
"required": false,
"optional": false,
"docs": {
"tags": [],
"text": "Selected filter options value."
},
"getter": false,
"setter": false
},
"option": {
"type": "unknown",
"attribute": "option",
"mutable": false,
"complexType": {
"original": "Filter",
"resolved": "Filter",
"references": {
"Filter": {
"location": "import",
"path": "../salla-filters/interfaces",
"id": "src/components/salla-filters/interfaces.ts::Filter"
}
}
},
"required": false,
"optional": false,
"docs": {
"tags": [],
"text": "Filter option along with possible values."
},
"getter": false,
"setter": false
}
};
}
static get states() {
return {
"isOpen": {},
"isShowMore": {},
"showMoreLabel": {},
"showLessLabel": {},
"page": {}
};
}
static get events() {
return [{
"method": "changed",
"name": "changed",
"bubbles": true,
"cancelable": true,
"composed": true,
"docs": {
"tags": [],
"text": "Custom event emitted up on filter option selection changes."
},
"complexType": {
"original": "any",
"resolved": "any",
"references": {}
}
}];
}
static get methods() {
return {
"setWidgetHeight": {
"complexType": {
"signature": "(delay?: number) => Promise<void>",
"parameters": [{
"name": "delay",
"type": "number",
"docs": "- Optional. The delay (in milliseconds) before updating the widget height.\n Defaults to 250 milliseconds."
}],
"references": {
"Promise": {
"location": "global",
"id": "global::Promise"
}
},
"return": "Promise<void>"
},
"docs": {
"text": "Asynchronously sets the height of a widget element to its current height, allowing for smooth transitions.\nThis function is often used in scenarios where the widget's content changes dynamically, and animating\nthe height adjustment is desired for a smoother user experience.",
"tags": [{
"name": "param",
"text": "delay - Optional. The delay (in milliseconds) before updating the widget height.\n Defaults to 250 milliseconds."
}, {
"name": "returns",
"text": "- A Promise that resolves once the widget height is set after the specified delay."
}, {
"name": "example",
"text": "// Set widget height with the default delay (250 milliseconds)\nawait setWidgetHeight();\n\n// Set widget height with a custom delay (e.g., 500 milliseconds)\nawait setWidgetHeight(500);"
}]
}
},
"reset": {
"complexType": {
"signature": "() => Promise<void>",
"parameters": [],
"references": {
"Promise": {
"location": "global",
"id": "global::Promise"
}
},
"return": "Promise<void>"
},
"docs": {
"text": "Reset selected filter options.",
"tags": []
}
},
"showMore": {
"complexType": {
"signature": "() => Promise<void>",
"parameters": [],
"references": {
"Promise": {
"location": "global",
"id": "global::Promise"
}
},
"return": "Promise<void>"
},
"docs": {
"text": "Action to show more or less filter options.",
"tags": []
}
},
"toggleWidget": {
"complexType": {
"signature": "() => Promise<void>",
"parameters": [],
"references": {
"Promise": {
"location": "global",
"id": "global::Promise"
}
},
"return": "Promise<void>"
},
"docs": {
"text": "Action to toggle widget open or closed (expand/ collapse).",
"tags": []
}
}
};
}
static get elementRef() { return "host"; }
}
//# sourceMappingURL=salla-filters-widget.js.map