import {type CSSResultGroup, html, type PropertyValues, unsafeCSS} from 'lit'; import {FormControlController, validValidityState} from "../../internal/form"; import {property} from 'lit/decorators.js'; import ZincElement, {type ZincFormControl} from '../../internal/zinc-element'; import ZnInput from "../input"; import type ZnDataSelect from "../data-select"; import type ZnQueryBuilder from "../query-builder"; import type ZnSelect from "../select"; import styles from './data-table-search.scss'; type AllowedInputElement = HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement | ZnInput | ZnSelect | ZnDataSelect | ZnQueryBuilder /** * @summary A search component for data tables. * @documentation https://zinc.style/components/data-table-search * @status experimental * @since 1.0 * * @dependency zn-input * * @event zn-search-change - Emitted when the search value changes (debounced). * * @slot - The default slot for additional form inputs. * * @csspart base - The component's base wrapper. * * @property {string} name - The name of the search input field (default: "search"). * @property {string} value - The current search value. * @property {string} placeholder - The placeholder text for the search input (default: "Search..."). * @property {string} helpText - Help text displayed below the search input. * @property {string} searchUri - Optional URI to use for search operations. * @property {number} debounceDelay - The delay in milliseconds before triggering a search (default: 500). */ export default class ZnDataTableSearch extends ZincElement implements ZincFormControl { static styles: CSSResultGroup = unsafeCSS(styles); static dependencies = { 'zn-input': ZnInput, }; private _formController: FormControlController = new FormControlController(this, {}); private _searchTimeout?: number; @property() name: string = "search"; @property() value: string = ""; @property() placeholder: string = "Search..."; @property({attribute: 'help-text'}) helpText: string = ""; @property({attribute: 'search-uri'}) searchUri: string | undefined; @property({type: Number, attribute: 'debounce-delay'}) debounceDelay: number = 350; get validationMessage(): string { return ''; } get validity(): ValidityState { return validValidityState; } checkValidity(): boolean { return true; } getForm(): HTMLFormElement | null { return this._formController.getForm(); } reportValidity(): boolean { return true; } setCustomValidity(): void { this._formController.updateValidity(); } protected firstUpdated(_changedProperties: PropertyValues) { super.firstUpdated(_changedProperties); this._formController.updateValidity(); } /** * Collects form data from slotted input elements */ getFormData(): Record { const params: Record = {}; const slot = this.shadowRoot?.querySelector('slot'); if (!slot) return params; const elements = slot.assignedElements({flatten: true}); const allowedInputs = ['zn-input', 'zn-select', 'zn-query-builder', 'zn-multiselect', 'zn-params-select', 'zn-datepicker', 'input', 'select', 'textarea']; elements.forEach((element) => { if (allowedInputs.includes(element.tagName.toLowerCase())) { const input = element as AllowedInputElement; const value = input.value as string || element.getAttribute('value'); const name = input.name || element.getAttribute('name'); if (name) { params[name] = value; } } }); return params; } handleInput = (e: Event) => { const input = e.target as ZnInput; this.value = input.value as string; this._formController.updateValidity(); if (this._searchTimeout) { window.clearTimeout(this._searchTimeout); } this._searchTimeout = window.setTimeout(() => { this.emitSearchChange(); }, this.debounceDelay); } handleClear = () => { if (this._searchTimeout) { window.clearTimeout(this._searchTimeout); } this.value = ""; const input = this.shadowRoot?.querySelector('zn-input'); if (input) { input.value = ""; } this._formController.updateValidity(); this.emitSearchChange(); } disconnectedCallback() { super.disconnectedCallback(); if (this._searchTimeout) { window.clearTimeout(this._searchTimeout); } } /** * Emit the search change event with form data */ private emitSearchChange() { const formData = this.getFormData(); this.emit('zn-search-change', { detail: { value: this.value, formData: formData, searchUri: this.searchUri } }); } render() { return html` `; } }