import {type CSSResultGroup, html, unsafeCSS} from 'lit'; import {property} from 'lit/decorators.js'; import ZincElement from '../../internal/zinc-element'; import styles from './filter-container.scss'; /** * @summary Short summary of the component's intended use. * @documentation https://zinc.style/components/filter-container * @status experimental * @since 1.0 * * @dependency zn-example * * @event zn-event-name - Emitted as an example. * * @slot - The default slot. * @slot example - An example slot. * * @csspart base - The component's base wrapper. * * @cssproperty --example - An example CSS custom property. */ export default class ZnFilterContainer extends ZincElement { static styles: CSSResultGroup = unsafeCSS(styles); @property() attr = 'filter'; private _filterFrame = 0; public handleSearchChange(event: Event) { const searchTerm = (event.target as HTMLInputElement).value.trim().toLowerCase(); cancelAnimationFrame(this._filterFrame); this._filterFrame = requestAnimationFrame(() => this.applyFilter(searchTerm)); } disconnectedCallback() { super.disconnectedCallback(); cancelAnimationFrame(this._filterFrame); } private applyFilter(searchTerm: string) { const attr = `data-${this.attr}`; const filterableElements = this.querySelectorAll(`[${attr}]`); const panels = new Map(); const accordions = new Map(); let anyVisibleElements = false; filterableElements.forEach((el) => { const visible = searchTerm === '' || (el.getAttribute(attr)?.toLowerCase() || '').includes(searchTerm); setDisplay(el, visible); if (visible) anyVisibleElements = true; const panel = el.closest('zn-panel'); if (panel) panels.set(panel, (panels.get(panel) ?? false) || visible); const accordion = el.closest('zn-accordion'); if (accordion) accordions.set(accordion, (accordions.get(accordion) ?? false) || visible); }); panels.forEach((visible, panel) => setDisplay(panel, visible)); accordions.forEach((visible, accordion) => { if (visible) setDisplay(accordion, true); }); let noResultsMessage = this.querySelector('.no-results-message'); if (!anyVisibleElements) { if (!noResultsMessage) { noResultsMessage = document.createElement('div'); noResultsMessage.className = 'no-results-message'; noResultsMessage.textContent = 'No results found'; this.appendChild(noResultsMessage); } noResultsMessage.style.display = ''; } else if (noResultsMessage) { noResultsMessage.style.display = 'none'; } } render() { return html` `; } } function setDisplay(el: HTMLElement, visible: boolean) { const display = visible ? '' : 'none'; if (el.style.display !== display) el.style.display = display; }