UNPKG

@unicef-polymer/etools-unicef

Version:
471 lines (466 loc) 16.7 kB
import { __decorate } from "tslib"; import { LitElement, html, css } from 'lit'; import { customElement, property } from 'lit/decorators.js'; import { etoolsFiltersStyles } from './etools-filters-styles'; import '../etools-icons/etools-icon'; import '@shoelace-style/shoelace/dist/components/switch/switch.js'; import '../etools-button/etools-button'; import '@shoelace-style/shoelace/dist/components/dropdown/dropdown.js'; import '../etools-dropdown/etools-dropdown-multi'; import '../etools-dropdown/etools-dropdown'; import '../etools-input/etools-input'; import '../etools-date-time/datepicker-lite.js'; import '../etools-loading/etools-loading'; import debounce from 'lodash-es/debounce'; import { getTranslation } from './utils/translate'; export var EtoolsFilterTypes; (function (EtoolsFilterTypes) { EtoolsFilterTypes[EtoolsFilterTypes["Search"] = 0] = "Search"; EtoolsFilterTypes[EtoolsFilterTypes["Dropdown"] = 1] = "Dropdown"; EtoolsFilterTypes[EtoolsFilterTypes["DropdownMulti"] = 2] = "DropdownMulti"; EtoolsFilterTypes[EtoolsFilterTypes["Toggle"] = 3] = "Toggle"; EtoolsFilterTypes[EtoolsFilterTypes["Date"] = 4] = "Date"; })(EtoolsFilterTypes || (EtoolsFilterTypes = {})); let EtoolsFilters = class EtoolsFilters extends LitElement { constructor() { super(); this.filters = []; /** Set this to true if the Loading... overlay should be displayed over the page, * not just over the etools-filter component */ this.filterLoadingAbsolute = false; this.lastSelectedValues = null; if (!this.language) { // @ts-ignore this.language = window.EtoolsLanguage || 'en'; } this.handleLanguageChange = this.handleLanguageChange.bind(this); } handleLanguageChange(e) { this.language = e.detail.language; } static get styles() { return [ etoolsFiltersStyles, css ` /* Set datepicker prefix icon color using mixin (cannot be used in etools-filter-styles) */ datepicker-lite { --etools-input-prefix: { color: var(--secondary-text-color, rgba(0, 0, 0, 0.54)); }; } *[hidden] { display: none !important; } .date { margin-inline-end: 16px; } etools-button[variant='text'] { --sl-color-primary-600: var(--primary-color, rgb(2, 132, 199)); } ` ]; } getSearchTmpl(f) { // language=HTML return html ` <etools-input class="filter search" part="filter-search" ?hidden="${!f.selected}" type="search" clearable autocomplete="off" always-float-label .value="${f.selectedValue}" placeholder="${f.filterName}" data-filter-key="${f.filterKey}" @value-changed="${this.textInputChange}" > <etools-icon name="search" slot="prefix"></etools-icon> </etools-input> `; } getDropdownTmpl(f) { // language=HTML return html ` <etools-dropdown ?hidden="${!f.selected}" class="filter" part="filter-dropdown" label="${f.filterName}" placeholder="&#8212;" ?disabled="${f.disabled}" .options="${f.selectionOptions}" .optionValue="${f.optionValue ? f.optionValue : 'value'}" .optionLabel="${f.optionLabel ? f.optionLabel : 'label'}" .selected="${f.selectedValue}" trigger-value-change-event @etools-selected-item-changed="${this.filterSelectionChange}" data-filter-key="${f.filterKey}" ?hide-search="${f.hideSearch}" .minWidth="${f.minWidth}" horizontal-align="left" no-dynamic-align enable-none-option > </etools-dropdown> `; } getDropdownMultiTmpl(f) { // language=HTML return html ` <etools-dropdown-multi id="${f.filterKey}" ?hidden="${!f.selected}" class="filter" part="filter-dropdownmulti" label="${f.filterName}" placeholder="${getTranslation(this.language, 'SELECT')}" ?disabled="${f.disabled}" .options="${f.selectionOptions}" .optionValue="${f.optionValue ? f.optionValue : 'value'}" .optionLabel="${f.optionLabel ? f.optionLabel : 'label'}" .selectedValues="${[...f.selectedValue]}" trigger-value-change-event @etools-selected-items-changed="${this.filterMultiSelectionChange}" data-filter-key="${f.filterKey}" ?hide-search="${f.hideSearch}" .minWidth="${f.minWidth}" horizontal-align="left" no-dynamic-align > </etools-dropdown-multi> `; } getDateTmpl(f) { // language=HTML return html ` <datepicker-lite class="filter date" part="filter-datepicker" ?hidden="${!f.selected}" .label="${f.filterName}" .value="${f.selectedValue}" fire-date-has-changed @date-has-changed="${this.filterDateChange}" data-filter-key="${f.filterKey}" selected-date-display-format="D MMM YYYY" > </datepicker-lite> `; } getToggleTmpl(f) { // language=HTML return html ` <div class="filter toggle" ?hidden="${!f.selected}" style="padding: 8px 0; box-sizing: border-box;"> ${f.filterName} <sl-switch title="${f.filterName}" id="toggleFilter" part="filter-toggle" ?checked="${f.selectedValue}" data-filter-key="${f.filterKey}" @sl-change="${this.filterToggleChange}" > </sl-switch> </div> `; } selectedFiltersTmpl(filters) { if (!filters) { return html `<etools-loading source="filters-loading" ?absolute=${this.filterLoadingAbsolute} loading-text="${getTranslation(this.language, 'LOADING')}" active ></etools-loading>`; } const tmpl = []; filters.forEach((f) => { let filterHtml; switch (f.type) { case EtoolsFilterTypes.Search: filterHtml = this.getSearchTmpl(f); break; case EtoolsFilterTypes.Dropdown: filterHtml = this.getDropdownTmpl(f); break; case EtoolsFilterTypes.DropdownMulti: filterHtml = this.getDropdownMultiTmpl(f); break; case EtoolsFilterTypes.Date: filterHtml = this.getDateTmpl(f); break; case EtoolsFilterTypes.Toggle: filterHtml = this.getToggleTmpl(f); break; } if (filterHtml) { tmpl.push(filterHtml); } }); return tmpl; } filterMenuOptions(filters) { if (!this.filters) { return []; } const menuOptions = []; filters.forEach((f) => { // language=HTML menuOptions.push(html ` <sl-menu-item type="checkbox" ?disabled="${f.disabled}" ?checked="${f.selected}" data-filter-key="${f.filterKey}" value="${f.filterKey}" > ${f.filterName} </sl-menu-item> `); }); return menuOptions; } connectedCallback() { this.afterFilterChange = debounce(this.afterFilterChange.bind(this), 1000); super.connectedCallback(); document.addEventListener('language-changed', this.handleLanguageChange); } disconnectedCallback() { super.disconnectedCallback(); document.removeEventListener('language-changed', this.handleLanguageChange); } render() { this.setDefaultLastSelectedValues(); // language=HTML return html ` <style> etools-dropdown[disabled] { opacity: 60%; } etools-dropdown-multi[disabled] { opacity: 60%; } </style> <div id="filters" part="filters">${this.selectedFiltersTmpl(this.filters)}</div> <div id="filters-selector" part="filters-selector"> <sl-dropdown id="filterMenu" stay-open-on-select> <etools-button variant="text" class="trigger-button" slot="trigger"> <etools-icon name="filter-list" slot="prefix"></etools-icon> ${this.textFilters || getTranslation(this.language, 'FILTERS')} </etools-button> <sl-menu @sl-select="${this.selectFilter}"> <sl-menu-item class="clear-all-filters" @click="${this.clearAllFilters}"> <etools-button variant="text" tabindex="-1" >${this.textClearAll || getTranslation(this.language, 'CLEAR_ALL')}</etools-button > </sl-menu-item> ${this.filterMenuOptions(this.filters)} </sl-menu> </sl-dropdown> </div> `; } setDefaultLastSelectedValues() { if (!this.lastSelectedValues && this.filters) { this.lastSelectedValues = this.getAllFiltersAndTheirValues(); } } clearAllFilters() { if (this.filters.length === 0) { return; } // Clear selected value in filters this.filters.forEach((f) => { if (f.disabled) { return; } f.selectedValue = this.getFilterEmptyValue(f.type); }); // clear selecter filters this.filters.forEach((f) => { if (f.disabled) { return; } if (f.filterKey === 'search') { // TODO - using FilterKeys.search here breaks the app return; } f.selected = false; }); // repaint this.requestUpdate(); this.updateComplete.then(() => this.fireFiltersChangeEvent()); } selectFilter(e) { const menuOption = e.detail.item; if (!menuOption.value) { return; } const filterOption = this.getFilterOption(menuOption); const wasSelected = menuOption.hasAttribute('checked'); // toggle selected state filterOption.selected = !wasSelected; // reset selected value if filter was unselected and had a value if (wasSelected) { filterOption.selectedValue = this.getFilterEmptyValue(filterOption.type); } // repaint&fire change event this.requestUpdate(); this.updateComplete.then(() => this.fireFiltersChangeEvent()); } // get filter empty value by type getFilterEmptyValue(filterType) { switch (filterType) { case EtoolsFilterTypes.Search: return ''; case EtoolsFilterTypes.Toggle: return false; case EtoolsFilterTypes.Date: case EtoolsFilterTypes.Dropdown: return null; case EtoolsFilterTypes.DropdownMulti: return []; } } getFilterOption(filterElement) { const filterKey = filterElement.getAttribute('data-filter-key'); if (!filterKey) { throw new Error('[EtoolsFilters.getFilterOption] No data-filter-key attr found on clicked option'); } const filterOption = this.filters.find((f) => f.filterKey === filterKey); if (!filterOption) { // something went wrong... filter option not found throw new Error(`[EtoolsFilters.getFilterOption] Filter option not found by filterKey: "${filterKey}"`); } return filterOption; } textInputChange(e) { if (!e.detail) { return; } const filterEl = e.currentTarget; const filterOption = this.getFilterOption(filterEl); if (filterOption.selectedValue === e.detail.value) { return; } filterOption.selectedValue = e.detail.value; this.requestUpdate(); this.updateComplete.then(() => this.fireFiltersChangeEvent()); } filterSelectionChange(e) { const filterEl = e.currentTarget; const filterOption = this.getFilterOption(filterEl); filterOption.selectedValue = e.detail.selectedItem ? e.detail.selectedItem[filterEl.optionValue] : null; this.requestUpdate(); this.updateComplete.then(() => this.fireFiltersChangeEvent()); } filterMultiSelectionChange(e) { const filterEl = e.currentTarget; const filterOption = this.getFilterOption(filterEl); const currentSelectedVal = e.detail.selectedItems.length > 0 ? e.detail.selectedItems.map((optionObj) => optionObj[filterEl.optionValue]) : []; if (JSON.stringify(currentSelectedVal) === JSON.stringify(filterOption.selectedValue)) { return; } filterOption.selectedValue = currentSelectedVal; this.afterFilterChange(); } afterFilterChange() { this.requestUpdate(); this.updateComplete.then(() => this.fireFiltersChangeEvent()); } filterDateChange(e) { const filterEl = e.currentTarget; const filterOption = this.getFilterOption(filterEl); filterOption.selectedValue = filterEl.value; // get datepicker value this.requestUpdate(); this.updateComplete.then(() => this.fireFiltersChangeEvent()); } filterToggleChange(e) { if (!e.detail) { return; } const filterEl = e.currentTarget; const filterOption = this.getFilterOption(filterEl); if (filterOption.selectedValue === filterEl.checked) { return; } filterOption.selectedValue = filterEl.checked; // get toggle btn value this.requestUpdate(); this.updateComplete.then(() => this.fireFiltersChangeEvent()); } // update filter values from parent element (! one way data flow) updateFilters(filterValues) { if (!filterValues || Object.keys(filterValues).length === 0) { return; } const keys = Object.keys(filterValues); this.filters.forEach((f) => { if (keys.indexOf(f.filterKey) > -1) { // filter found by key if (!f.selected) { // select filter is not already selected f.selected = true; } // update value f.selectedValue = filterValues[f.filterKey]; } }); this.requestUpdate(); this.lastSelectedValues = { ...this.getAllFiltersAndTheirValues(), ...filterValues }; } // fire change custom event to notify parent that filters were updated fireFiltersChangeEvent() { const selectedValues = this.getAllFiltersAndTheirValues(); if (JSON.stringify(this.lastSelectedValues) === JSON.stringify(selectedValues)) { return; } this.lastSelectedValues = { ...selectedValues }; this.dispatchEvent(new CustomEvent('filter-change', { detail: this.getSelectedFiltersAndTheirValues(), bubbles: true, composed: true })); } // build and return and object based on filterKey and selectedValue getAllFiltersAndTheirValues() { const allFilters = {}; if (this.filters) { this.filters.forEach((f) => { allFilters[f.filterKey] = f.selectedValue; }); } return allFilters; } getSelectedFiltersAndTheirValues() { const selectedFilters = {}; this.filters.forEach((f) => { if (f.selected) { selectedFilters[f.filterKey] = f.selectedValue; } }); return selectedFilters; } }; __decorate([ property({ type: Array }) ], EtoolsFilters.prototype, "filters", void 0); __decorate([ property({ type: Boolean }) ], EtoolsFilters.prototype, "filterLoadingAbsolute", void 0); __decorate([ property({ type: String }) ], EtoolsFilters.prototype, "textClearAll", void 0); __decorate([ property({ type: String }) ], EtoolsFilters.prototype, "textFilters", void 0); __decorate([ property({ type: String }) ], EtoolsFilters.prototype, "language", void 0); EtoolsFilters = __decorate([ customElement('etools-filters') ], EtoolsFilters); export { EtoolsFilters };