import {type CSSResultGroup, html, unsafeCSS} from 'lit'; import {property, state} from "lit/decorators.js"; import {trimControlValue} from '../../internal/form'; import ZincElement from '../../internal/zinc-element'; import type ZnDataSelect from "../data-select"; import type ZnButton from "../button"; import type ZnDataTable from "../data-table"; import type ZnInput from "../input"; import type ZnQueryBuilder from "../query-builder"; import type ZnSelect from "../select"; import styles from './filter-wrapper.scss'; type AllowedInputElement = HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement | ZnInput | ZnSelect | ZnDataSelect | ZnQueryBuilder /** * @summary Short summary of the component's intended use. * @documentation https://zinc.style/components/filter-wrapper * @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 ZnFilterWrapper extends ZincElement { static styles: CSSResultGroup = unsafeCSS(styles); @property() button: string = 'Filter'; /** Submits the filters when Enter is pressed in a text field. */ @property({attribute: 'submit-on-enter', type: Boolean}) submitOnEnter = false; /** Shown on the submit button while results load. */ @property({attribute: 'loading-text'}) loadingText = 'Searching...'; @state() private loading = false; private submitButton: ZnButton | null = null; handleSubmit = (event: Event) => { event.preventDefault(); const dataTable: ZnDataTable | null = this.closest('zn-data-table'); if (dataTable && !this.loading) { const allowedInputs = ['zn-input', 'zn-select', 'zn-query-builder', 'zn-data-select', 'zn-datepicker', 'input', 'select', 'textarea']; const inputs = Array.from(this.querySelectorAll(allowedInputs.join(','))) as AllowedInputElement[]; const params: Record = {}; inputs.forEach(input => { trimControlValue(input); if (!input.value && input.hasAttribute('omit-empty')) { return; } params[input.name] = input.value as string; }); dataTable.requestParams = params; this.setLoading(true); Promise.resolve(dataTable.refresh()).finally(() => this.setLoading(false)); } } private setLoading(loading: boolean) { this.loading = loading; if (this.submitButton) { this.submitButton.processingText = this.loadingText; this.submitButton.processing = loading; } } handleKeyDown = (event: KeyboardEvent) => { if (!this.submitOnEnter || event.key !== 'Enter' || event.defaultPrevented || event.isComposing || event.altKey || event.ctrlKey || event.metaKey || event.shiftKey) { return; } // Only plain text fields: selects, buttons and textareas use Enter themselves if (event.composedPath()[0] instanceof HTMLInputElement) { this.handleSubmit(event); } } connectedCallback() { super.connectedCallback(); this.addEventListener('keydown', this.handleKeyDown); this.submitButton = this.querySelector('zn-button[submit]'); this.submitButton?.addEventListener('click', this.handleSubmit); } disconnectedCallback() { super.disconnectedCallback(); this.removeEventListener('keydown', this.handleKeyDown); } private renderDefaultButton() { return html` ${this.button} `; } render() { return html` ${this.submitButton ? '' : this.renderDefaultButton()} `; } }