@shival99/z-ui 1.9.12 → 1.9.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (33) hide show
  1. package/assets/css/base.css +0 -16
  2. package/fesm2022/shival99-z-ui-components-z-calendar.mjs.map +1 -1
  3. package/fesm2022/shival99-z-ui-components-z-drawer.mjs +7 -2
  4. package/fesm2022/shival99-z-ui-components-z-drawer.mjs.map +1 -1
  5. package/fesm2022/shival99-z-ui-components-z-filter.mjs +150 -3
  6. package/fesm2022/shival99-z-ui-components-z-filter.mjs.map +1 -1
  7. package/fesm2022/shival99-z-ui-components-z-kanban.mjs +2 -2
  8. package/fesm2022/shival99-z-ui-components-z-kanban.mjs.map +1 -1
  9. package/fesm2022/shival99-z-ui-components-z-modal.mjs +13 -6
  10. package/fesm2022/shival99-z-ui-components-z-modal.mjs.map +1 -1
  11. package/fesm2022/shival99-z-ui-components-z-table.mjs +219 -0
  12. package/fesm2022/shival99-z-ui-components-z-table.mjs.map +1 -1
  13. package/fesm2022/shival99-z-ui-components-z-timeline.mjs +43 -261
  14. package/fesm2022/shival99-z-ui-components-z-timeline.mjs.map +1 -1
  15. package/fesm2022/shival99-z-ui-components-z-upload.mjs +1 -4
  16. package/fesm2022/shival99-z-ui-components-z-upload.mjs.map +1 -1
  17. package/fesm2022/shival99-z-ui-providers.mjs +6 -2
  18. package/fesm2022/shival99-z-ui-providers.mjs.map +1 -1
  19. package/fesm2022/shival99-z-ui-services.mjs +71 -4
  20. package/fesm2022/shival99-z-ui-services.mjs.map +1 -1
  21. package/package.json +1 -1
  22. package/types/shival99-z-ui-components-z-autocomplete.d.ts +1 -1
  23. package/types/shival99-z-ui-components-z-calendar.d.ts +4 -4
  24. package/types/shival99-z-ui-components-z-drawer.d.ts +2 -0
  25. package/types/shival99-z-ui-components-z-editor.d.ts +1 -1
  26. package/types/shival99-z-ui-components-z-filter.d.ts +17 -0
  27. package/types/shival99-z-ui-components-z-modal.d.ts +5 -2
  28. package/types/shival99-z-ui-components-z-popover.d.ts +1 -1
  29. package/types/shival99-z-ui-components-z-table.d.ts +205 -1
  30. package/types/shival99-z-ui-components-z-timeline.d.ts +20 -62
  31. package/types/shival99-z-ui-components-z-upload.d.ts +3 -3
  32. package/types/shival99-z-ui-providers.d.ts +6 -2
  33. package/types/shival99-z-ui-services.d.ts +26 -1
@@ -1,7 +1,10 @@
1
1
  import { NgTemplateOutlet } from '@angular/common';
2
2
  import * as i0 from '@angular/core';
3
3
  import { Pipe, contentChild, output, input, signal, viewChild, computed, ViewEncapsulation, ChangeDetectionStrategy, Component } from '@angular/core';
4
+ import * as i1 from '@angular/forms';
5
+ import { FormsModule } from '@angular/forms';
4
6
  import { ZButtonComponent } from '@shival99/z-ui/components/z-button';
7
+ import { ZCalendarComponent } from '@shival99/z-ui/components/z-calendar';
5
8
  import { ZIconComponent } from '@shival99/z-ui/components/z-icon';
6
9
  import { ZPopoverDirective } from '@shival99/z-ui/components/z-popover';
7
10
  import { ZSwitchComponent } from '@shival99/z-ui/components/z-switch';
@@ -630,6 +633,46 @@ class ZFilterComponent {
630
633
  }
631
634
  return 'default';
632
635
  }, ...(ngDevMode ? [{ debugName: "buttonSize" }] : []));
636
+ calendarSize = computed(() => {
637
+ const size = this.zSize();
638
+ if (size === 'sm') {
639
+ return 'sm';
640
+ }
641
+ if (size === 'lg') {
642
+ return 'lg';
643
+ }
644
+ return 'default';
645
+ }, ...(ngDevMode ? [{ debugName: "calendarSize" }] : []));
646
+ dateValueMap = computed(() => {
647
+ const map = {};
648
+ for (const filter of this.zFilters()) {
649
+ map[filter.id] = this._parseDateValue(filter.values[0]);
650
+ }
651
+ return map;
652
+ }, ...(ngDevMode ? [{ debugName: "dateValueMap" }] : []));
653
+ dateRangeValueMap = computed(() => {
654
+ const map = {};
655
+ for (const filter of this.zFilters()) {
656
+ const start = this._parseDateValue(filter.values[0]);
657
+ const end = this._parseDateValue(filter.values[1]);
658
+ map[filter.id] = start || end ? { start, end } : null;
659
+ }
660
+ return map;
661
+ }, ...(ngDevMode ? [{ debugName: "dateRangeValueMap" }] : []));
662
+ timeValueMap = computed(() => {
663
+ const map = {};
664
+ for (const filter of this.zFilters()) {
665
+ map[filter.id] = this._parseTimeValue(filter.values[0]);
666
+ }
667
+ return map;
668
+ }, ...(ngDevMode ? [{ debugName: "timeValueMap" }] : []));
669
+ dateTimeValueMap = computed(() => {
670
+ const map = {};
671
+ for (const filter of this.zFilters()) {
672
+ map[filter.id] = this._parseDateTimeValue(filter.values[0]);
673
+ }
674
+ return map;
675
+ }, ...(ngDevMode ? [{ debugName: "dateTimeValueMap" }] : []));
633
676
  hostClasses = computed(() => zMergeClasses(zFilterContainerVariants({ size: this.zSize() }), this.class()), ...(ngDevMode ? [{ debugName: "hostClasses" }] : []));
634
677
  getItemClasses() {
635
678
  return zFilterItemVariants({ size: this.zSize() });
@@ -727,6 +770,27 @@ class ZFilterComponent {
727
770
  this.zFiltersChange.emit(updatedFilters);
728
771
  this.zFilterUpdate.emit({ filter, updates: { values: newValues } });
729
772
  }
773
+ onDateValueChange(filter, value) {
774
+ const formattedValue = this._formatDateValue(value);
775
+ const nextValues = [formattedValue];
776
+ this._updateFilterValues(filter, nextValues);
777
+ }
778
+ onDateRangeValueChange(filter, value) {
779
+ const start = this._formatDateValue(value?.start ?? null);
780
+ const end = this._formatDateValue(value?.end ?? null);
781
+ const nextValues = [start, end];
782
+ this._updateFilterValues(filter, nextValues);
783
+ }
784
+ onTimeValueChange(filter, value) {
785
+ const formattedValue = this._formatTimeValue(value);
786
+ const nextValues = [formattedValue];
787
+ this._updateFilterValues(filter, nextValues);
788
+ }
789
+ onDateTimeValueChange(filter, value) {
790
+ const formattedValue = this._formatDateTimeValue(value);
791
+ const nextValues = [formattedValue];
792
+ this._updateFilterValues(filter, nextValues);
793
+ }
730
794
  removeFilter(filter) {
731
795
  const updatedFilters = this.zFilters().filter(f => f.id !== filter.id);
732
796
  this.zFiltersChange.emit(updatedFilters);
@@ -769,15 +833,98 @@ class ZFilterComponent {
769
833
  trackByFieldKey(index, field) {
770
834
  return field.key || `field-${index}`;
771
835
  }
836
+ _updateFilterValues(filter, values) {
837
+ const updatedFilters = this.zFilters().map(f => {
838
+ if (f.id === filter.id) {
839
+ return { ...f, values };
840
+ }
841
+ return f;
842
+ });
843
+ this.zFiltersChange.emit(updatedFilters);
844
+ this.zFilterUpdate.emit({ filter, updates: { values } });
845
+ }
846
+ _parseDateValue(value) {
847
+ if (typeof value !== 'string' || !value) {
848
+ return null;
849
+ }
850
+ const [year, month, day] = value.split('-').map(Number);
851
+ if (!year || !month || !day) {
852
+ return null;
853
+ }
854
+ const parsedDate = new Date(year, month - 1, day);
855
+ if (Number.isNaN(parsedDate.getTime())) {
856
+ return null;
857
+ }
858
+ return parsedDate;
859
+ }
860
+ _formatDateValue(value) {
861
+ if (!value) {
862
+ return '';
863
+ }
864
+ const year = value.getFullYear();
865
+ const month = String(value.getMonth() + 1).padStart(2, '0');
866
+ const day = String(value.getDate()).padStart(2, '0');
867
+ return `${year}-${month}-${day}`;
868
+ }
869
+ _parseTimeValue(value) {
870
+ if (typeof value !== 'string' || !value) {
871
+ return null;
872
+ }
873
+ const [hours, minutes] = value.split(':').map(Number);
874
+ if (hours == null || minutes == null || Number.isNaN(hours) || Number.isNaN(minutes)) {
875
+ return null;
876
+ }
877
+ const date = new Date();
878
+ date.setHours(hours, minutes, 0, 0);
879
+ return date;
880
+ }
881
+ _parseDateTimeValue(value) {
882
+ if (typeof value !== 'string' || !value) {
883
+ return null;
884
+ }
885
+ const parsed = new Date(value);
886
+ if (Number.isNaN(parsed.getTime())) {
887
+ return null;
888
+ }
889
+ return parsed;
890
+ }
891
+ _formatTimeValue(value) {
892
+ if (!value) {
893
+ return '';
894
+ }
895
+ const hours = String(value.getHours()).padStart(2, '0');
896
+ const minutes = String(value.getMinutes()).padStart(2, '0');
897
+ return `${hours}:${minutes}`;
898
+ }
899
+ _formatDateTimeValue(value) {
900
+ if (!value) {
901
+ return '';
902
+ }
903
+ const year = value.getFullYear();
904
+ const month = String(value.getMonth() + 1).padStart(2, '0');
905
+ const day = String(value.getDate()).padStart(2, '0');
906
+ const hours = String(value.getHours()).padStart(2, '0');
907
+ const minutes = String(value.getMinutes()).padStart(2, '0');
908
+ return `${year}-${month}-${day}T${hours}:${minutes}`;
909
+ }
772
910
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: ZFilterComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
773
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.6", type: ZFilterComponent, isStandalone: true, selector: "z-filter", inputs: { class: { classPropertyName: "class", publicName: "class", isSignal: true, isRequired: false, transformFunction: null }, zFilters: { classPropertyName: "zFilters", publicName: "zFilters", isSignal: true, isRequired: true, transformFunction: null }, zFields: { classPropertyName: "zFields", publicName: "zFields", isSignal: true, isRequired: true, transformFunction: null }, zSize: { classPropertyName: "zSize", publicName: "zSize", isSignal: true, isRequired: false, transformFunction: null }, zI18n: { classPropertyName: "zI18n", publicName: "zI18n", isSignal: true, isRequired: false, transformFunction: null }, zShowAddButton: { classPropertyName: "zShowAddButton", publicName: "zShowAddButton", isSignal: true, isRequired: false, transformFunction: null }, zAllowMultiple: { classPropertyName: "zAllowMultiple", publicName: "zAllowMultiple", isSignal: true, isRequired: false, transformFunction: null }, zAddButtonIcon: { classPropertyName: "zAddButtonIcon", publicName: "zAddButtonIcon", isSignal: true, isRequired: false, transformFunction: null }, zAddButtonText: { classPropertyName: "zAddButtonText", publicName: "zAddButtonText", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { zFiltersChange: "zFiltersChange", zFilterAdd: "zFilterAdd", zFilterRemove: "zFilterRemove", zFilterUpdate: "zFilterUpdate" }, host: { attributes: { "data-slot": "z-filter" }, properties: { "class": "hostClasses()" } }, queries: [{ propertyName: "addButtonTemplate", first: true, predicate: ["addButton"], descendants: true, isSignal: true }], viewQueries: [{ propertyName: "addFilterSearchInput", first: true, predicate: ["addFilterSearchInput"], descendants: true, isSignal: true }], ngImport: i0, template: "<!-- Add Filter Button -->\n@if (zShowAddButton() && selectableFields().length > 0) {\n @if (addButtonTemplate()) {\n <ng-container [ngTemplateOutlet]=\"addButtonTemplate()!\" />\n } @else {\n <button\n z-button\n zType=\"outline\"\n [zSize]=\"buttonSize()\"\n z-popover\n [zPopoverContent]=\"addFilterPopover\"\n zTrigger=\"click\"\n zPosition=\"bottom-left\"\n [zOffset]=\"6\"\n (zShow)=\"addFilterOpen.set(true); focusSearchInput()\"\n (zHide)=\"addFilterOpen.set(false); searchQuery.set('')\">\n <z-icon [zType]=\"zAddButtonIcon()\" zSize=\"14\" />\n {{ zAddButtonText() || i18n().addFilter }}\n </button>\n }\n}\n\n<ng-template #addFilterPopover let-close=\"close\">\n <div class=\"w-[12.5rem]\">\n <div class=\"border-border flex items-center border-b px-3\">\n <z-icon zType=\"lucideSearch\" zSize=\"16\" class=\"text-muted-foreground/50 mr-2 shrink-0\" />\n <input\n #addFilterSearchInput\n type=\"text\"\n [placeholder]=\"i18n().searchFields\"\n [value]=\"searchQuery()\"\n (input)=\"onSearchInput($event)\"\n class=\"placeholder:text-muted-foreground text-foreground flex h-10 w-full bg-transparent py-3 text-sm outline-none\" />\n </div>\n <div class=\"flex max-h-[18.75rem] flex-col gap-0.5 overflow-y-auto p-1\">\n @for (group of groupedFields(); track group.group; let groupIndex = $index) {\n @if (group.group) {\n <div\n class=\"text-muted-foreground px-2 py-1.5 text-xs font-medium\"\n [class.border-border]=\"groupIndex > 0\"\n [class.mt-2]=\"groupIndex > 0\"\n [class.border-t]=\"groupIndex > 0\"\n [class.ml-1]=\"groupIndex > 0\">\n {{ group.group }}\n </div>\n }\n @for (field of group.fields; track trackByFieldKey($index, field)) {\n <button\n type=\"button\"\n class=\"hover:bg-accent flex w-full cursor-pointer items-center gap-2 rounded-sm px-2 py-1.5 text-sm transition-colors\"\n (click)=\"onFieldSelect(field); close()\">\n @if (field.icon) {\n <z-icon [zType]=\"field.icon\" zSize=\"14\" class=\"text-muted-foreground\" />\n }\n <span>{{ field.label }}</span>\n </button>\n }\n } @empty {\n <div class=\"text-muted-foreground py-6 text-center text-sm\">\n {{ i18n().noFieldsFound }}\n </div>\n }\n </div>\n </div>\n</ng-template>\n\n<!-- Filter Items -->\n@for (filter of zFilters(); track trackByFilterId($index, filter)) {\n @if (filter | zFilterField: $any(zFields()); as field) {\n <div [class]=\"getItemClasses()\" data-slot=\"filter-item\">\n <!-- Field Label -->\n <div [class]=\"getLabelClasses()\">\n @if (field.icon) {\n <z-icon [zType]=\"field.icon\" zSize=\"14\" />\n }\n {{ field.label }}\n </div>\n\n <!-- Operator Dropdown -->\n <button\n type=\"button\"\n z-popover\n [zPopoverContent]=\"operatorDropdown\"\n zTrigger=\"click\"\n zPosition=\"bottom-left\"\n [zOffset]=\"4\"\n (zShow)=\"operatorPopoverOpen.set(filter.id)\"\n (zHide)=\"operatorPopoverOpen.set(null)\"\n class=\"text-muted-foreground hover:text-foreground hover:bg-muted flex cursor-pointer items-center px-2.5 text-sm transition-colors\"\n [class.text-foreground]=\"operatorPopoverOpen() === filter.id\"\n [class.bg-muted]=\"operatorPopoverOpen() === filter.id\">\n {{ filter | zFilterOperatorLabel: $any(zFields()) : i18n() }}\n <z-icon zType=\"lucideChevronDown\" zSize=\"12\" class=\"ml-1\" />\n </button>\n\n <ng-template #operatorDropdown let-close=\"close\">\n <div class=\"flex w-fit min-w-32 flex-col gap-0.5 p-1\">\n @for (op of filter | zFilterOperators: $any(zFields()) : i18n(); track op.value) {\n <button\n type=\"button\"\n class=\"hover:bg-accent flex w-full cursor-pointer items-center justify-between gap-4 rounded-sm px-2 py-1.5 text-sm transition-colors outline-none\"\n (click)=\"updateFilterOperator(filter, op.value); close()\">\n <span>{{ op.label }}</span>\n @if (op.value === filter.operator) {\n <z-icon zType=\"lucideCheck\" zSize=\"14\" class=\"text-primary\" />\n }\n </button>\n }\n </div>\n </ng-template>\n\n <!-- Value Selector -->\n @if (!(filter | zFilterIsValueHidden)) {\n <!-- Boolean Field -->\n @if (field.type === 'boolean') {\n <div class=\"flex items-center gap-2 px-2.5\">\n <z-switch [zChecked]=\"filter.values[0] === true\" (zChange)=\"onBooleanChange(filter, $event)\" zSize=\"sm\" />\n @if (field.onLabel && field.offLabel) {\n <span class=\"text-muted-foreground text-xs\">\n {{ filter.values[0] === true ? field.onLabel : field.offLabel }}\n </span>\n }\n </div>\n }\n\n <!-- Text/Email/URL/Tel Input -->\n @else if (field.type === 'text' || field.type === 'email' || field.type === 'url' || field.type === 'tel') {\n <div [class]=\"getInputClasses()\" class=\"w-36\">\n @if (field.prefix) {\n <span class=\"text-muted-foreground mr-1\">{{ field.prefix }}</span>\n }\n <input\n type=\"{{\n field.type === 'email' ? 'email' : field.type === 'url' ? 'url' : field.type === 'tel' ? 'tel' : 'text'\n }}\"\n [value]=\"filter.values[0] || ''\"\n [placeholder]=\"field.placeholder || i18n().placeholders.enterField\"\n [pattern]=\"field | zFilterInputPattern\"\n class=\"w-full bg-transparent outline-none\"\n (blur)=\"onInputChange(filter, $event)\" />\n @if (field.suffix) {\n <span class=\"text-muted-foreground ml-1\">{{ field.suffix }}</span>\n }\n </div>\n }\n\n <!-- Number Input -->\n @else if (field.type === 'number') {\n @if (filter | zFilterIsBetweenOperator) {\n <div class=\"flex items-center\">\n <div [class]=\"getInputClasses()\" class=\"w-20\">\n @if (field.prefix) {\n <span class=\"text-muted-foreground mr-1\">{{ field.prefix }}</span>\n }\n <input\n type=\"number\"\n [value]=\"filter.values[0] || ''\"\n [placeholder]=\"i18n().min\"\n [min]=\"field.min\"\n [max]=\"field.max\"\n [step]=\"field.step\"\n class=\"w-full bg-transparent outline-none\"\n (blur)=\"onInputChange(filter, $event, 0)\" />\n </div>\n <div [class]=\"getBetweenClasses()\">{{ i18n().to }}</div>\n <div [class]=\"getInputClasses()\" class=\"w-20\">\n <input\n type=\"number\"\n [value]=\"filter.values[1] || ''\"\n [placeholder]=\"i18n().max\"\n [min]=\"field.min\"\n [max]=\"field.max\"\n [step]=\"field.step\"\n class=\"w-full bg-transparent outline-none\"\n (blur)=\"onInputChange(filter, $event, 1)\" />\n @if (field.suffix) {\n <span class=\"text-muted-foreground ml-1\">{{ field.suffix }}</span>\n }\n </div>\n </div>\n } @else {\n <div [class]=\"getInputClasses()\" class=\"w-24\">\n @if (field.prefix) {\n <span class=\"text-muted-foreground mr-1\">{{ field.prefix }}</span>\n }\n <input\n type=\"number\"\n [value]=\"filter.values[0] || ''\"\n [placeholder]=\"field.placeholder || i18n().placeholders.enterField\"\n [min]=\"field.min\"\n [max]=\"field.max\"\n [step]=\"field.step\"\n class=\"w-full bg-transparent outline-none\"\n (blur)=\"onInputChange(filter, $event)\" />\n @if (field.suffix) {\n <span class=\"text-muted-foreground ml-1\">{{ field.suffix }}</span>\n }\n </div>\n }\n }\n\n <!-- Date Input -->\n @else if (field.type === 'date') {\n <div [class]=\"getInputClasses()\" class=\"w-36\">\n <input\n type=\"date\"\n [value]=\"filter.values[0] || ''\"\n class=\"w-full bg-transparent outline-none\"\n (change)=\"onInputChange(filter, $event)\" />\n </div>\n }\n\n <!-- Date Range Input -->\n @else if (field.type === 'daterange') {\n <div class=\"flex items-center\">\n <div [class]=\"getInputClasses()\" class=\"w-32\">\n <input\n type=\"date\"\n [value]=\"filter.values[0] || ''\"\n class=\"w-full bg-transparent outline-none\"\n (change)=\"onInputChange(filter, $event, 0)\" />\n </div>\n <div [class]=\"getBetweenClasses()\">{{ i18n().to }}</div>\n <div [class]=\"getInputClasses()\" class=\"w-32\">\n <input\n type=\"date\"\n [value]=\"filter.values[1] || ''\"\n class=\"w-full bg-transparent outline-none\"\n (change)=\"onInputChange(filter, $event, 1)\" />\n </div>\n </div>\n }\n\n <!-- Time Input -->\n @else if (field.type === 'time') {\n @if (filter | zFilterIsBetweenOperator) {\n <div class=\"flex items-center\">\n <div [class]=\"getInputClasses()\" class=\"w-28\">\n <input\n type=\"time\"\n [value]=\"filter.values[0] || ''\"\n class=\"w-full bg-transparent outline-none\"\n (change)=\"onInputChange(filter, $event, 0)\" />\n </div>\n <div [class]=\"getBetweenClasses()\">{{ i18n().to }}</div>\n <div [class]=\"getInputClasses()\" class=\"w-28\">\n <input\n type=\"time\"\n [value]=\"filter.values[1] || ''\"\n class=\"w-full bg-transparent outline-none\"\n (change)=\"onInputChange(filter, $event, 1)\" />\n </div>\n </div>\n } @else {\n <div [class]=\"getInputClasses()\" class=\"w-28\">\n <input\n type=\"time\"\n [value]=\"filter.values[0] || ''\"\n class=\"w-full bg-transparent outline-none\"\n (change)=\"onInputChange(filter, $event)\" />\n </div>\n }\n }\n\n <!-- DateTime Input -->\n @else if (field.type === 'datetime') {\n @if (filter | zFilterIsBetweenOperator) {\n <div class=\"flex items-center\">\n <div [class]=\"getInputClasses()\" class=\"w-44\">\n <input\n type=\"datetime-local\"\n [value]=\"filter.values[0] || ''\"\n class=\"w-full bg-transparent outline-none\"\n (change)=\"onInputChange(filter, $event, 0)\" />\n </div>\n <div [class]=\"getBetweenClasses()\">{{ i18n().to }}</div>\n <div [class]=\"getInputClasses()\" class=\"w-44\">\n <input\n type=\"datetime-local\"\n [value]=\"filter.values[1] || ''\"\n class=\"w-full bg-transparent outline-none\"\n (change)=\"onInputChange(filter, $event, 1)\" />\n </div>\n </div>\n } @else {\n <div [class]=\"getInputClasses()\" class=\"w-44\">\n <input\n type=\"datetime-local\"\n [value]=\"filter.values[0] || ''\"\n class=\"w-full bg-transparent outline-none\"\n (change)=\"onInputChange(filter, $event)\" />\n </div>\n }\n }\n\n <!-- Select/Multiselect -->\n @else if (field.type === 'select' || field.type === 'multiselect' || field.options) {\n <button\n type=\"button\"\n z-popover\n [zPopoverContent]=\"selectPopover\"\n zTrigger=\"click\"\n zPosition=\"bottom-left\"\n [zOffset]=\"4\"\n (zShow)=\"valuePopoverOpen.set(filter.id); focusSelectSearch(filter.id)\"\n (zHide)=\"valuePopoverOpen.set(null)\"\n class=\"hover:bg-muted flex cursor-pointer items-center gap-1.5 px-2.5 text-sm transition-colors\"\n [class.bg-muted]=\"valuePopoverOpen() === filter.id\">\n @if (filter | zFilterSelectedOptions: $any(zFields()); as selectedOpts) {\n @if (selectedOpts.length > 0) {\n <div class=\"flex items-center -space-x-1.5\">\n @for (opt of selectedOpts.slice(0, 3); track $any(opt).value) {\n @if (opt.icon) {\n <z-icon [zType]=\"opt.icon\" zSize=\"14\" />\n }\n }\n </div>\n @if (selectedOpts.length === 1) {\n {{ selectedOpts[0].label }}\n } @else {\n {{ selectedOpts.length }} {{ i18n().selectedCount }}\n }\n } @else {\n <span class=\"text-muted-foreground\">{{ i18n().select }}</span>\n }\n }\n <z-icon zType=\"lucideChevronDown\" zSize=\"12\" class=\"text-muted-foreground ml-1\" />\n </button>\n\n <ng-template #selectPopover let-close=\"close\">\n <div class=\"w-[12.5rem]\">\n @if (field.searchable !== false) {\n <div class=\"border-border flex items-center border-b px-3\">\n <z-icon zType=\"lucideSearch\" zSize=\"16\" class=\"text-muted-foreground/50 mr-2 shrink-0\" />\n <input\n [id]=\"'select-search-' + filter.id\"\n type=\"text\"\n [placeholder]=\"i18n().placeholders.searchField\"\n class=\"placeholder:text-muted-foreground text-foreground flex h-9 w-full bg-transparent py-2 text-sm outline-none\" />\n </div>\n }\n <div class=\"flex max-h-[12.5rem] flex-col gap-0.5 overflow-y-auto p-1\">\n <!-- Selected Options -->\n @for (opt of filter | zFilterSelectedOptions: $any(zFields()); track $any(opt).value) {\n <button\n type=\"button\"\n class=\"hover:bg-accent flex w-full cursor-pointer items-center gap-2 rounded-sm px-2 py-1.5 text-sm transition-colors\"\n (click)=\"onSelectValueChange(filter, $any(opt)); field.type !== 'multiselect' && close()\">\n @if (opt.icon) {\n <z-icon [zType]=\"opt.icon\" zSize=\"14\" />\n }\n <span class=\"truncate\">{{ opt.label }}</span>\n <z-icon zType=\"lucideCheck\" zSize=\"14\" class=\"text-primary ml-auto\" />\n </button>\n }\n\n <!-- Separator -->\n @if (\n (filter | zFilterSelectedOptions: $any(zFields())).length > 0 &&\n (filter | zFilterUnselectedOptions: $any(zFields())).length > 0\n ) {\n <div class=\"bg-border my-1 ml-1 h-px\"></div>\n }\n\n <!-- Unselected Options -->\n @for (opt of filter | zFilterUnselectedOptions: $any(zFields()); track $any(opt).value) {\n <button\n type=\"button\"\n class=\"hover:bg-accent flex w-full cursor-pointer items-center gap-2 rounded-sm px-2 py-1.5 text-sm transition-colors\"\n (click)=\"onSelectValueChange(filter, $any(opt)); field.type !== 'multiselect' && close()\">\n @if (opt.icon) {\n <z-icon [zType]=\"opt.icon\" zSize=\"14\" />\n }\n <span class=\"truncate\">{{ opt.label }}</span>\n </button>\n }\n\n @if (\n (filter | zFilterSelectedOptions: $any(zFields())).length === 0 &&\n (filter | zFilterUnselectedOptions: $any(zFields())).length === 0\n ) {\n <div class=\"text-muted-foreground py-6 text-center text-sm\">\n {{ i18n().noResultsFound }}\n </div>\n }\n </div>\n </div>\n </ng-template>\n }\n }\n\n <!-- Remove Button -->\n <button type=\"button\" [class]=\"getRemoveButtonClasses()\" data-slot=\"filter-remove\" (click)=\"removeFilter(filter)\">\n <z-icon zType=\"lucideX\" zSize=\"14\" />\n </button>\n </div>\n }\n}\n", styles: [":host{display:block}\n"], dependencies: [{ kind: "component", type: ZIconComponent, selector: "z-icon, [z-icon]", inputs: ["class", "zType", "zSize", "zStrokeWidth", "zSvg"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: ZSwitchComponent, selector: "z-switch", inputs: ["class", "zSize", "zMode", "zLabel", "zText", "zCheckedText", "zUncheckedText", "zDisabled", "zLoading", "zTextPosition", "zWave", "zChecked"], outputs: ["zChange", "zOnBlur", "zOnFocus", "zEvent", "zCheckedChange"] }, { kind: "component", type: ZButtonComponent, selector: "z-button, button[z-button], a[z-button]", inputs: ["class", "zType", "zSize", "zShape", "zLabel", "zLoading", "zDisabled", "zTypeIcon", "zSizeIcon", "zStrokeWidthIcon", "zWave"], exportAs: ["zButton"] }, { kind: "directive", type: ZPopoverDirective, selector: "[z-popover]", inputs: ["zPopoverContent", "zPosition", "zTrigger", "zClass", "zShowDelay", "zHideDelay", "zDisabled", "zOffset", "zPopoverWidth", "zManualClose", "zScrollClose", "zShowArrow"], outputs: ["zShow", "zHide", "zHideStart", "zControl", "zPositionChange"], exportAs: ["zPopover"] }, { kind: "pipe", type: ZFilterFieldPipe, name: "zFilterField" }, { kind: "pipe", type: ZFilterOperatorLabelPipe, name: "zFilterOperatorLabel" }, { kind: "pipe", type: ZFilterOperatorsPipe, name: "zFilterOperators" }, { kind: "pipe", type: ZFilterSelectedOptionsPipe, name: "zFilterSelectedOptions" }, { kind: "pipe", type: ZFilterUnselectedOptionsPipe, name: "zFilterUnselectedOptions" }, { kind: "pipe", type: ZFilterInputPatternPipe, name: "zFilterInputPattern" }, { kind: "pipe", type: ZFilterIsValueHiddenPipe, name: "zFilterIsValueHidden" }, { kind: "pipe", type: ZFilterIsBetweenOperatorPipe, name: "zFilterIsBetweenOperator" }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
911
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.6", type: ZFilterComponent, isStandalone: true, selector: "z-filter", inputs: { class: { classPropertyName: "class", publicName: "class", isSignal: true, isRequired: false, transformFunction: null }, zFilters: { classPropertyName: "zFilters", publicName: "zFilters", isSignal: true, isRequired: true, transformFunction: null }, zFields: { classPropertyName: "zFields", publicName: "zFields", isSignal: true, isRequired: true, transformFunction: null }, zSize: { classPropertyName: "zSize", publicName: "zSize", isSignal: true, isRequired: false, transformFunction: null }, zI18n: { classPropertyName: "zI18n", publicName: "zI18n", isSignal: true, isRequired: false, transformFunction: null }, zShowAddButton: { classPropertyName: "zShowAddButton", publicName: "zShowAddButton", isSignal: true, isRequired: false, transformFunction: null }, zAllowMultiple: { classPropertyName: "zAllowMultiple", publicName: "zAllowMultiple", isSignal: true, isRequired: false, transformFunction: null }, zAddButtonIcon: { classPropertyName: "zAddButtonIcon", publicName: "zAddButtonIcon", isSignal: true, isRequired: false, transformFunction: null }, zAddButtonText: { classPropertyName: "zAddButtonText", publicName: "zAddButtonText", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { zFiltersChange: "zFiltersChange", zFilterAdd: "zFilterAdd", zFilterRemove: "zFilterRemove", zFilterUpdate: "zFilterUpdate" }, host: { attributes: { "data-slot": "z-filter" }, properties: { "class": "hostClasses()" } }, queries: [{ propertyName: "addButtonTemplate", first: true, predicate: ["addButton"], descendants: true, isSignal: true }], viewQueries: [{ propertyName: "addFilterSearchInput", first: true, predicate: ["addFilterSearchInput"], descendants: true, isSignal: true }], ngImport: i0, template: "<!-- Add Filter Button -->\n@if (zShowAddButton() && selectableFields().length > 0) {\n @if (addButtonTemplate()) {\n <ng-container [ngTemplateOutlet]=\"addButtonTemplate()!\" />\n } @else {\n <button\n z-button\n zType=\"outline\"\n [zSize]=\"buttonSize()\"\n z-popover\n [zPopoverContent]=\"addFilterPopover\"\n zTrigger=\"click\"\n zPosition=\"bottom-left\"\n [zOffset]=\"6\"\n (zShow)=\"addFilterOpen.set(true); focusSearchInput()\"\n (zHide)=\"addFilterOpen.set(false); searchQuery.set('')\">\n <z-icon [zType]=\"zAddButtonIcon()\" zSize=\"14\" />\n {{ zAddButtonText() || i18n().addFilter }}\n </button>\n }\n}\n\n<ng-template #addFilterPopover let-close=\"close\">\n <div class=\"w-[12.5rem]\">\n <div class=\"border-border flex items-center border-b px-3\">\n <z-icon zType=\"lucideSearch\" zSize=\"16\" class=\"text-muted-foreground/50 mr-2 shrink-0\" />\n <input\n #addFilterSearchInput\n type=\"text\"\n [placeholder]=\"i18n().searchFields\"\n [value]=\"searchQuery()\"\n (input)=\"onSearchInput($event)\"\n class=\"placeholder:text-muted-foreground text-foreground flex h-10 w-full bg-transparent py-3 text-sm outline-none\" />\n </div>\n <div class=\"flex max-h-[18.75rem] flex-col gap-0.5 overflow-y-auto p-1\">\n @for (group of groupedFields(); track group.group; let groupIndex = $index) {\n @if (group.group) {\n <div\n class=\"text-muted-foreground px-2 py-1.5 text-xs font-medium\"\n [class.border-border]=\"groupIndex > 0\"\n [class.mt-2]=\"groupIndex > 0\"\n [class.border-t]=\"groupIndex > 0\"\n [class.ml-1]=\"groupIndex > 0\">\n {{ group.group }}\n </div>\n }\n @for (field of group.fields; track trackByFieldKey($index, field)) {\n <button\n type=\"button\"\n class=\"hover:bg-accent flex w-full cursor-pointer items-center gap-2 rounded-sm px-2 py-1.5 text-sm transition-colors\"\n (click)=\"onFieldSelect(field); close()\">\n @if (field.icon) {\n <z-icon [zType]=\"field.icon\" zSize=\"14\" class=\"text-muted-foreground\" />\n }\n <span>{{ field.label }}</span>\n </button>\n }\n } @empty {\n <div class=\"text-muted-foreground py-6 text-center text-sm\">\n {{ i18n().noFieldsFound }}\n </div>\n }\n </div>\n </div>\n</ng-template>\n\n<!-- Filter Items -->\n@for (filter of zFilters(); track trackByFilterId($index, filter)) {\n @if (filter | zFilterField: $any(zFields()); as field) {\n <div [class]=\"getItemClasses()\" data-slot=\"filter-item\">\n <!-- Field Label -->\n <div [class]=\"getLabelClasses()\">\n @if (field.icon) {\n <z-icon [zType]=\"field.icon\" zSize=\"14\" />\n }\n {{ field.label }}\n </div>\n\n <!-- Operator Dropdown -->\n <button\n type=\"button\"\n z-popover\n [zPopoverContent]=\"operatorDropdown\"\n zTrigger=\"click\"\n zPosition=\"bottom-left\"\n [zOffset]=\"4\"\n (zShow)=\"operatorPopoverOpen.set(filter.id)\"\n (zHide)=\"operatorPopoverOpen.set(null)\"\n class=\"text-muted-foreground hover:text-foreground hover:bg-muted flex cursor-pointer items-center px-2.5 text-sm transition-colors\"\n [class.text-foreground]=\"operatorPopoverOpen() === filter.id\"\n [class.bg-muted]=\"operatorPopoverOpen() === filter.id\">\n {{ filter | zFilterOperatorLabel: $any(zFields()) : i18n() }}\n <z-icon zType=\"lucideChevronDown\" zSize=\"12\" class=\"ml-1\" />\n </button>\n\n <ng-template #operatorDropdown let-close=\"close\">\n <div class=\"flex w-fit min-w-32 flex-col gap-0.5 p-1\">\n @for (op of filter | zFilterOperators: $any(zFields()) : i18n(); track op.value) {\n <button\n type=\"button\"\n class=\"hover:bg-accent flex w-full cursor-pointer items-center justify-between gap-4 rounded-sm px-2 py-1.5 text-sm transition-colors outline-none\"\n (click)=\"updateFilterOperator(filter, op.value); close()\">\n <span>{{ op.label }}</span>\n @if (op.value === filter.operator) {\n <z-icon zType=\"lucideCheck\" zSize=\"14\" class=\"text-primary\" />\n }\n </button>\n }\n </div>\n </ng-template>\n\n <!-- Value Selector -->\n @if (!(filter | zFilterIsValueHidden)) {\n <!-- Boolean Field -->\n @if (field.type === 'boolean') {\n <div class=\"flex items-center gap-2 px-2.5\">\n <z-switch [zChecked]=\"filter.values[0] === true\" (zChange)=\"onBooleanChange(filter, $event)\" zSize=\"sm\" />\n @if (field.onLabel && field.offLabel) {\n <span class=\"text-muted-foreground text-xs\">\n {{ filter.values[0] === true ? field.onLabel : field.offLabel }}\n </span>\n }\n </div>\n }\n\n <!-- Text/Email/URL/Tel Input -->\n @else if (field.type === 'text' || field.type === 'email' || field.type === 'url' || field.type === 'tel') {\n <div [class]=\"getInputClasses()\" class=\"w-36\">\n @if (field.prefix) {\n <span class=\"text-muted-foreground mr-1\">{{ field.prefix }}</span>\n }\n <input\n type=\"{{\n field.type === 'email' ? 'email' : field.type === 'url' ? 'url' : field.type === 'tel' ? 'tel' : 'text'\n }}\"\n [value]=\"filter.values[0] || ''\"\n [placeholder]=\"field.placeholder || i18n().placeholders.enterField\"\n [pattern]=\"field | zFilterInputPattern\"\n class=\"w-full bg-transparent outline-none\"\n (blur)=\"onInputChange(filter, $event)\" />\n @if (field.suffix) {\n <span class=\"text-muted-foreground ml-1\">{{ field.suffix }}</span>\n }\n </div>\n }\n\n <!-- Number Input -->\n @else if (field.type === 'number') {\n @if (filter | zFilterIsBetweenOperator) {\n <div class=\"flex items-center\">\n <div [class]=\"getInputClasses()\" class=\"w-20\">\n @if (field.prefix) {\n <span class=\"text-muted-foreground mr-1\">{{ field.prefix }}</span>\n }\n <input\n type=\"number\"\n [value]=\"filter.values[0] || ''\"\n [placeholder]=\"i18n().min\"\n [min]=\"field.min\"\n [max]=\"field.max\"\n [step]=\"field.step\"\n class=\"w-full bg-transparent outline-none\"\n (blur)=\"onInputChange(filter, $event, 0)\" />\n </div>\n <div [class]=\"getBetweenClasses()\">{{ i18n().to }}</div>\n <div [class]=\"getInputClasses()\" class=\"w-20\">\n <input\n type=\"number\"\n [value]=\"filter.values[1] || ''\"\n [placeholder]=\"i18n().max\"\n [min]=\"field.min\"\n [max]=\"field.max\"\n [step]=\"field.step\"\n class=\"w-full bg-transparent outline-none\"\n (blur)=\"onInputChange(filter, $event, 1)\" />\n @if (field.suffix) {\n <span class=\"text-muted-foreground ml-1\">{{ field.suffix }}</span>\n }\n </div>\n </div>\n } @else {\n <div [class]=\"getInputClasses()\" class=\"w-24\">\n @if (field.prefix) {\n <span class=\"text-muted-foreground mr-1\">{{ field.prefix }}</span>\n }\n <input\n type=\"number\"\n [value]=\"filter.values[0] || ''\"\n [placeholder]=\"field.placeholder || i18n().placeholders.enterField\"\n [min]=\"field.min\"\n [max]=\"field.max\"\n [step]=\"field.step\"\n class=\"w-full bg-transparent outline-none\"\n (blur)=\"onInputChange(filter, $event)\" />\n @if (field.suffix) {\n <span class=\"text-muted-foreground ml-1\">{{ field.suffix }}</span>\n }\n </div>\n }\n }\n\n <!-- Date Input -->\n @else if (field.type === 'date') {\n <div [class]=\"getInputClasses()\" class=\"z-filter-calendar w-40 min-w-0\">\n <z-calendar\n zMode=\"single\"\n zAllowClear\n zValueType=\"date\"\n zFormat=\"YYYY-MM-DD\"\n [zSize]=\"calendarSize()\"\n [zPlaceholder]=\"field.placeholder || i18n().placeholders.enterField\"\n [ngModel]=\"dateValueMap()[filter.id] ?? null\"\n (ngModelChange)=\"onDateValueChange(filter, $event)\"\n class=\"h-full min-w-0 border-0 bg-transparent px-0 shadow-none ring-0 focus-within:border-transparent focus-within:ring-0\" />\n </div>\n }\n\n <!-- Date Range Input -->\n @else if (field.type === 'daterange') {\n <div [class]=\"getInputClasses()\" class=\"z-filter-calendar w-56 min-w-0\">\n <z-calendar\n zMode=\"range\"\n zAllowClear\n zValueType=\"date\"\n zFormat=\"YYYY-MM-DD\"\n [zSize]=\"calendarSize()\"\n [zPlaceholder]=\"field.placeholder || i18n().placeholders.enterField\"\n [ngModel]=\"dateRangeValueMap()[filter.id] ?? null\"\n (ngModelChange)=\"onDateRangeValueChange(filter, $event)\"\n class=\"h-full min-w-0 border-0 bg-transparent px-0 shadow-none ring-0 focus-within:border-transparent focus-within:ring-0\" />\n </div>\n }\n\n <!-- Time Input -->\n @else if (field.type === 'time') {\n <div [class]=\"getInputClasses()\" class=\"z-filter-calendar w-28 min-w-0\">\n <z-calendar\n zMode=\"time\"\n zAllowClear\n zValueType=\"date\"\n zFormat=\"HH:mm\"\n [zSize]=\"calendarSize()\"\n [zShowSecond]=\"false\"\n [zPlaceholder]=\"field.placeholder || i18n().placeholders.enterField\"\n [ngModel]=\"timeValueMap()[filter.id] ?? null\"\n (ngModelChange)=\"onTimeValueChange(filter, $event)\"\n class=\"h-full min-w-0 border-0 bg-transparent px-0 shadow-none ring-0 focus-within:border-transparent focus-within:ring-0\" />\n </div>\n }\n\n <!-- DateTime Input -->\n @else if (field.type === 'datetime') {\n <div [class]=\"getInputClasses()\" class=\"z-filter-calendar w-52 min-w-0\">\n <z-calendar\n zMode=\"single\"\n zShowTime\n zAllowClear\n zValueType=\"date\"\n zFormat=\"YYYY-MM-DD HH:mm\"\n [zSize]=\"calendarSize()\"\n [zShowSecond]=\"false\"\n [zPlaceholder]=\"field.placeholder || i18n().placeholders.enterField\"\n [ngModel]=\"dateTimeValueMap()[filter.id] ?? null\"\n (ngModelChange)=\"onDateTimeValueChange(filter, $event)\"\n class=\"h-full min-w-0 border-0 bg-transparent px-0 shadow-none ring-0 focus-within:border-transparent focus-within:ring-0\" />\n </div>\n }\n\n <!-- Select/Multiselect -->\n @else if (field.type === 'select' || field.type === 'multiselect' || field.options) {\n <button\n type=\"button\"\n z-popover\n [zPopoverContent]=\"selectPopover\"\n zTrigger=\"click\"\n zPosition=\"bottom-left\"\n [zOffset]=\"4\"\n (zShow)=\"valuePopoverOpen.set(filter.id); focusSelectSearch(filter.id)\"\n (zHide)=\"valuePopoverOpen.set(null)\"\n class=\"hover:bg-muted flex cursor-pointer items-center gap-1.5 px-2.5 text-sm transition-colors\"\n [class.bg-muted]=\"valuePopoverOpen() === filter.id\">\n @if (filter | zFilterSelectedOptions: $any(zFields()); as selectedOpts) {\n @if (selectedOpts.length > 0) {\n <div class=\"flex items-center -space-x-1.5\">\n @for (opt of selectedOpts.slice(0, 3); track $any(opt).value) {\n @if (opt.icon) {\n <z-icon [zType]=\"opt.icon\" zSize=\"14\" />\n }\n }\n </div>\n @if (selectedOpts.length === 1) {\n {{ selectedOpts[0].label }}\n } @else {\n {{ selectedOpts.length }} {{ i18n().selectedCount }}\n }\n } @else {\n <span class=\"text-muted-foreground\">{{ i18n().select }}</span>\n }\n }\n <z-icon zType=\"lucideChevronDown\" zSize=\"12\" class=\"text-muted-foreground ml-1\" />\n </button>\n\n <ng-template #selectPopover let-close=\"close\">\n <div class=\"w-[12.5rem]\">\n @if (field.searchable !== false) {\n <div class=\"border-border flex items-center border-b px-3\">\n <z-icon zType=\"lucideSearch\" zSize=\"16\" class=\"text-muted-foreground/50 mr-2 shrink-0\" />\n <input\n [id]=\"'select-search-' + filter.id\"\n type=\"text\"\n [placeholder]=\"i18n().placeholders.searchField\"\n class=\"placeholder:text-muted-foreground text-foreground flex h-9 w-full bg-transparent py-2 text-sm outline-none\" />\n </div>\n }\n <div class=\"flex max-h-[12.5rem] flex-col gap-0.5 overflow-y-auto p-1\">\n <!-- Selected Options -->\n @for (opt of filter | zFilterSelectedOptions: $any(zFields()); track $any(opt).value) {\n <button\n type=\"button\"\n class=\"hover:bg-accent flex w-full cursor-pointer items-center gap-2 rounded-sm px-2 py-1.5 text-sm transition-colors\"\n (click)=\"onSelectValueChange(filter, $any(opt)); field.type !== 'multiselect' && close()\">\n @if (opt.icon) {\n <z-icon [zType]=\"opt.icon\" zSize=\"14\" />\n }\n <span class=\"truncate\">{{ opt.label }}</span>\n <z-icon zType=\"lucideCheck\" zSize=\"14\" class=\"text-primary ml-auto\" />\n </button>\n }\n\n <!-- Separator -->\n @if (\n (filter | zFilterSelectedOptions: $any(zFields())).length > 0 &&\n (filter | zFilterUnselectedOptions: $any(zFields())).length > 0\n ) {\n <div class=\"bg-border my-1 ml-1 h-px\"></div>\n }\n\n <!-- Unselected Options -->\n @for (opt of filter | zFilterUnselectedOptions: $any(zFields()); track $any(opt).value) {\n <button\n type=\"button\"\n class=\"hover:bg-accent flex w-full cursor-pointer items-center gap-2 rounded-sm px-2 py-1.5 text-sm transition-colors\"\n (click)=\"onSelectValueChange(filter, $any(opt)); field.type !== 'multiselect' && close()\">\n @if (opt.icon) {\n <z-icon [zType]=\"opt.icon\" zSize=\"14\" />\n }\n <span class=\"truncate\">{{ opt.label }}</span>\n </button>\n }\n\n @if (\n (filter | zFilterSelectedOptions: $any(zFields())).length === 0 &&\n (filter | zFilterUnselectedOptions: $any(zFields())).length === 0\n ) {\n <div class=\"text-muted-foreground py-6 text-center text-sm\">\n {{ i18n().noResultsFound }}\n </div>\n }\n </div>\n </div>\n </ng-template>\n }\n }\n\n <!-- Remove Button -->\n <button type=\"button\" [class]=\"getRemoveButtonClasses()\" data-slot=\"filter-remove\" (click)=\"removeFilter(filter)\">\n <z-icon zType=\"lucideX\" zSize=\"14\" />\n </button>\n </div>\n }\n}\n", styles: [":host{display:block}.z-filter-calendar z-calendar{display:contents}.z-filter-calendar z-calendar .z-calendar-wrapper{display:contents}.z-filter-calendar z-calendar .z-calendar-wrapper>.relative{display:contents}.z-filter-calendar z-calendar [z-popover]{display:flex!important;align-items:center!important;height:auto!important;min-height:0!important;width:100%!important;border:0!important;box-shadow:none!important;padding:0!important;background:transparent!important;outline:none!important;gap:.375rem!important;cursor:pointer!important}.z-filter-calendar z-calendar [z-popover]:focus-within{border-color:transparent!important;box-shadow:none!important}.z-filter-calendar z-calendar [z-popover]>z-icon{flex-shrink:0}.z-filter-calendar z-calendar [z-popover]>input{flex:1 1 0!important;min-width:0!important;width:0!important}.z-filter-calendar z-calendar [z-popover]>button[tabindex=\"-1\"]{display:none!important}.z-filter-calendar z-calendar .z-calendar-wrapper>p{display:none!important}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: ZIconComponent, selector: "z-icon, [z-icon]", inputs: ["class", "zType", "zSize", "zStrokeWidth", "zSvg"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: ZSwitchComponent, selector: "z-switch", inputs: ["class", "zSize", "zMode", "zLabel", "zText", "zCheckedText", "zUncheckedText", "zDisabled", "zLoading", "zTextPosition", "zWave", "zChecked"], outputs: ["zChange", "zOnBlur", "zOnFocus", "zEvent", "zCheckedChange"] }, { kind: "component", type: ZButtonComponent, selector: "z-button, button[z-button], a[z-button]", inputs: ["class", "zType", "zSize", "zShape", "zLabel", "zLoading", "zDisabled", "zTypeIcon", "zSizeIcon", "zStrokeWidthIcon", "zWave"], exportAs: ["zButton"] }, { kind: "directive", type: ZPopoverDirective, selector: "[z-popover]", inputs: ["zPopoverContent", "zPosition", "zTrigger", "zClass", "zShowDelay", "zHideDelay", "zDisabled", "zOffset", "zPopoverWidth", "zManualClose", "zScrollClose", "zShowArrow"], outputs: ["zShow", "zHide", "zHideStart", "zControl", "zPositionChange"], exportAs: ["zPopover"] }, { kind: "component", type: ZCalendarComponent, selector: "z-calendar", inputs: ["class", "zMode", "zSize", "zLabel", "zLabelClass", "zPlaceholder", "zRequired", "zDisabled", "zReadonly", "zShowTime", "zTimeFormat", "zShowHour", "zShowMinute", "zShowSecond", "zQuickSelect", "zAllowClear", "zFormat", "zMinDate", "zMaxDate", "zValueType", "zValidators", "zShowOk", "zOkText", "zShowCancel", "zCancelText", "zDisabledDate", "zScrollClose", "zDefaultTime", "zRangeDefaultTime"], outputs: ["zControl", "zChange", "zOnBlur", "zOnFocus", "zEvent"], exportAs: ["zCalendar"] }, { kind: "pipe", type: ZFilterFieldPipe, name: "zFilterField" }, { kind: "pipe", type: ZFilterOperatorLabelPipe, name: "zFilterOperatorLabel" }, { kind: "pipe", type: ZFilterOperatorsPipe, name: "zFilterOperators" }, { kind: "pipe", type: ZFilterSelectedOptionsPipe, name: "zFilterSelectedOptions" }, { kind: "pipe", type: ZFilterUnselectedOptionsPipe, name: "zFilterUnselectedOptions" }, { kind: "pipe", type: ZFilterInputPatternPipe, name: "zFilterInputPattern" }, { kind: "pipe", type: ZFilterIsValueHiddenPipe, name: "zFilterIsValueHidden" }, { kind: "pipe", type: ZFilterIsBetweenOperatorPipe, name: "zFilterIsBetweenOperator" }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
774
912
  }
775
913
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: ZFilterComponent, decorators: [{
776
914
  type: Component,
777
- args: [{ selector: 'z-filter', imports: [ZIconComponent, NgTemplateOutlet, ZSwitchComponent, ZButtonComponent, ZPopoverDirective, ...Z_FILTER_PIPES], standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, host: {
915
+ args: [{ selector: 'z-filter', imports: [
916
+ FormsModule,
917
+ ZIconComponent,
918
+ NgTemplateOutlet,
919
+ ZSwitchComponent,
920
+ ZButtonComponent,
921
+ ZPopoverDirective,
922
+ ZCalendarComponent,
923
+ ...Z_FILTER_PIPES,
924
+ ], standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, host: {
778
925
  '[class]': 'hostClasses()',
779
926
  'data-slot': 'z-filter',
780
- }, template: "<!-- Add Filter Button -->\n@if (zShowAddButton() && selectableFields().length > 0) {\n @if (addButtonTemplate()) {\n <ng-container [ngTemplateOutlet]=\"addButtonTemplate()!\" />\n } @else {\n <button\n z-button\n zType=\"outline\"\n [zSize]=\"buttonSize()\"\n z-popover\n [zPopoverContent]=\"addFilterPopover\"\n zTrigger=\"click\"\n zPosition=\"bottom-left\"\n [zOffset]=\"6\"\n (zShow)=\"addFilterOpen.set(true); focusSearchInput()\"\n (zHide)=\"addFilterOpen.set(false); searchQuery.set('')\">\n <z-icon [zType]=\"zAddButtonIcon()\" zSize=\"14\" />\n {{ zAddButtonText() || i18n().addFilter }}\n </button>\n }\n}\n\n<ng-template #addFilterPopover let-close=\"close\">\n <div class=\"w-[12.5rem]\">\n <div class=\"border-border flex items-center border-b px-3\">\n <z-icon zType=\"lucideSearch\" zSize=\"16\" class=\"text-muted-foreground/50 mr-2 shrink-0\" />\n <input\n #addFilterSearchInput\n type=\"text\"\n [placeholder]=\"i18n().searchFields\"\n [value]=\"searchQuery()\"\n (input)=\"onSearchInput($event)\"\n class=\"placeholder:text-muted-foreground text-foreground flex h-10 w-full bg-transparent py-3 text-sm outline-none\" />\n </div>\n <div class=\"flex max-h-[18.75rem] flex-col gap-0.5 overflow-y-auto p-1\">\n @for (group of groupedFields(); track group.group; let groupIndex = $index) {\n @if (group.group) {\n <div\n class=\"text-muted-foreground px-2 py-1.5 text-xs font-medium\"\n [class.border-border]=\"groupIndex > 0\"\n [class.mt-2]=\"groupIndex > 0\"\n [class.border-t]=\"groupIndex > 0\"\n [class.ml-1]=\"groupIndex > 0\">\n {{ group.group }}\n </div>\n }\n @for (field of group.fields; track trackByFieldKey($index, field)) {\n <button\n type=\"button\"\n class=\"hover:bg-accent flex w-full cursor-pointer items-center gap-2 rounded-sm px-2 py-1.5 text-sm transition-colors\"\n (click)=\"onFieldSelect(field); close()\">\n @if (field.icon) {\n <z-icon [zType]=\"field.icon\" zSize=\"14\" class=\"text-muted-foreground\" />\n }\n <span>{{ field.label }}</span>\n </button>\n }\n } @empty {\n <div class=\"text-muted-foreground py-6 text-center text-sm\">\n {{ i18n().noFieldsFound }}\n </div>\n }\n </div>\n </div>\n</ng-template>\n\n<!-- Filter Items -->\n@for (filter of zFilters(); track trackByFilterId($index, filter)) {\n @if (filter | zFilterField: $any(zFields()); as field) {\n <div [class]=\"getItemClasses()\" data-slot=\"filter-item\">\n <!-- Field Label -->\n <div [class]=\"getLabelClasses()\">\n @if (field.icon) {\n <z-icon [zType]=\"field.icon\" zSize=\"14\" />\n }\n {{ field.label }}\n </div>\n\n <!-- Operator Dropdown -->\n <button\n type=\"button\"\n z-popover\n [zPopoverContent]=\"operatorDropdown\"\n zTrigger=\"click\"\n zPosition=\"bottom-left\"\n [zOffset]=\"4\"\n (zShow)=\"operatorPopoverOpen.set(filter.id)\"\n (zHide)=\"operatorPopoverOpen.set(null)\"\n class=\"text-muted-foreground hover:text-foreground hover:bg-muted flex cursor-pointer items-center px-2.5 text-sm transition-colors\"\n [class.text-foreground]=\"operatorPopoverOpen() === filter.id\"\n [class.bg-muted]=\"operatorPopoverOpen() === filter.id\">\n {{ filter | zFilterOperatorLabel: $any(zFields()) : i18n() }}\n <z-icon zType=\"lucideChevronDown\" zSize=\"12\" class=\"ml-1\" />\n </button>\n\n <ng-template #operatorDropdown let-close=\"close\">\n <div class=\"flex w-fit min-w-32 flex-col gap-0.5 p-1\">\n @for (op of filter | zFilterOperators: $any(zFields()) : i18n(); track op.value) {\n <button\n type=\"button\"\n class=\"hover:bg-accent flex w-full cursor-pointer items-center justify-between gap-4 rounded-sm px-2 py-1.5 text-sm transition-colors outline-none\"\n (click)=\"updateFilterOperator(filter, op.value); close()\">\n <span>{{ op.label }}</span>\n @if (op.value === filter.operator) {\n <z-icon zType=\"lucideCheck\" zSize=\"14\" class=\"text-primary\" />\n }\n </button>\n }\n </div>\n </ng-template>\n\n <!-- Value Selector -->\n @if (!(filter | zFilterIsValueHidden)) {\n <!-- Boolean Field -->\n @if (field.type === 'boolean') {\n <div class=\"flex items-center gap-2 px-2.5\">\n <z-switch [zChecked]=\"filter.values[0] === true\" (zChange)=\"onBooleanChange(filter, $event)\" zSize=\"sm\" />\n @if (field.onLabel && field.offLabel) {\n <span class=\"text-muted-foreground text-xs\">\n {{ filter.values[0] === true ? field.onLabel : field.offLabel }}\n </span>\n }\n </div>\n }\n\n <!-- Text/Email/URL/Tel Input -->\n @else if (field.type === 'text' || field.type === 'email' || field.type === 'url' || field.type === 'tel') {\n <div [class]=\"getInputClasses()\" class=\"w-36\">\n @if (field.prefix) {\n <span class=\"text-muted-foreground mr-1\">{{ field.prefix }}</span>\n }\n <input\n type=\"{{\n field.type === 'email' ? 'email' : field.type === 'url' ? 'url' : field.type === 'tel' ? 'tel' : 'text'\n }}\"\n [value]=\"filter.values[0] || ''\"\n [placeholder]=\"field.placeholder || i18n().placeholders.enterField\"\n [pattern]=\"field | zFilterInputPattern\"\n class=\"w-full bg-transparent outline-none\"\n (blur)=\"onInputChange(filter, $event)\" />\n @if (field.suffix) {\n <span class=\"text-muted-foreground ml-1\">{{ field.suffix }}</span>\n }\n </div>\n }\n\n <!-- Number Input -->\n @else if (field.type === 'number') {\n @if (filter | zFilterIsBetweenOperator) {\n <div class=\"flex items-center\">\n <div [class]=\"getInputClasses()\" class=\"w-20\">\n @if (field.prefix) {\n <span class=\"text-muted-foreground mr-1\">{{ field.prefix }}</span>\n }\n <input\n type=\"number\"\n [value]=\"filter.values[0] || ''\"\n [placeholder]=\"i18n().min\"\n [min]=\"field.min\"\n [max]=\"field.max\"\n [step]=\"field.step\"\n class=\"w-full bg-transparent outline-none\"\n (blur)=\"onInputChange(filter, $event, 0)\" />\n </div>\n <div [class]=\"getBetweenClasses()\">{{ i18n().to }}</div>\n <div [class]=\"getInputClasses()\" class=\"w-20\">\n <input\n type=\"number\"\n [value]=\"filter.values[1] || ''\"\n [placeholder]=\"i18n().max\"\n [min]=\"field.min\"\n [max]=\"field.max\"\n [step]=\"field.step\"\n class=\"w-full bg-transparent outline-none\"\n (blur)=\"onInputChange(filter, $event, 1)\" />\n @if (field.suffix) {\n <span class=\"text-muted-foreground ml-1\">{{ field.suffix }}</span>\n }\n </div>\n </div>\n } @else {\n <div [class]=\"getInputClasses()\" class=\"w-24\">\n @if (field.prefix) {\n <span class=\"text-muted-foreground mr-1\">{{ field.prefix }}</span>\n }\n <input\n type=\"number\"\n [value]=\"filter.values[0] || ''\"\n [placeholder]=\"field.placeholder || i18n().placeholders.enterField\"\n [min]=\"field.min\"\n [max]=\"field.max\"\n [step]=\"field.step\"\n class=\"w-full bg-transparent outline-none\"\n (blur)=\"onInputChange(filter, $event)\" />\n @if (field.suffix) {\n <span class=\"text-muted-foreground ml-1\">{{ field.suffix }}</span>\n }\n </div>\n }\n }\n\n <!-- Date Input -->\n @else if (field.type === 'date') {\n <div [class]=\"getInputClasses()\" class=\"w-36\">\n <input\n type=\"date\"\n [value]=\"filter.values[0] || ''\"\n class=\"w-full bg-transparent outline-none\"\n (change)=\"onInputChange(filter, $event)\" />\n </div>\n }\n\n <!-- Date Range Input -->\n @else if (field.type === 'daterange') {\n <div class=\"flex items-center\">\n <div [class]=\"getInputClasses()\" class=\"w-32\">\n <input\n type=\"date\"\n [value]=\"filter.values[0] || ''\"\n class=\"w-full bg-transparent outline-none\"\n (change)=\"onInputChange(filter, $event, 0)\" />\n </div>\n <div [class]=\"getBetweenClasses()\">{{ i18n().to }}</div>\n <div [class]=\"getInputClasses()\" class=\"w-32\">\n <input\n type=\"date\"\n [value]=\"filter.values[1] || ''\"\n class=\"w-full bg-transparent outline-none\"\n (change)=\"onInputChange(filter, $event, 1)\" />\n </div>\n </div>\n }\n\n <!-- Time Input -->\n @else if (field.type === 'time') {\n @if (filter | zFilterIsBetweenOperator) {\n <div class=\"flex items-center\">\n <div [class]=\"getInputClasses()\" class=\"w-28\">\n <input\n type=\"time\"\n [value]=\"filter.values[0] || ''\"\n class=\"w-full bg-transparent outline-none\"\n (change)=\"onInputChange(filter, $event, 0)\" />\n </div>\n <div [class]=\"getBetweenClasses()\">{{ i18n().to }}</div>\n <div [class]=\"getInputClasses()\" class=\"w-28\">\n <input\n type=\"time\"\n [value]=\"filter.values[1] || ''\"\n class=\"w-full bg-transparent outline-none\"\n (change)=\"onInputChange(filter, $event, 1)\" />\n </div>\n </div>\n } @else {\n <div [class]=\"getInputClasses()\" class=\"w-28\">\n <input\n type=\"time\"\n [value]=\"filter.values[0] || ''\"\n class=\"w-full bg-transparent outline-none\"\n (change)=\"onInputChange(filter, $event)\" />\n </div>\n }\n }\n\n <!-- DateTime Input -->\n @else if (field.type === 'datetime') {\n @if (filter | zFilterIsBetweenOperator) {\n <div class=\"flex items-center\">\n <div [class]=\"getInputClasses()\" class=\"w-44\">\n <input\n type=\"datetime-local\"\n [value]=\"filter.values[0] || ''\"\n class=\"w-full bg-transparent outline-none\"\n (change)=\"onInputChange(filter, $event, 0)\" />\n </div>\n <div [class]=\"getBetweenClasses()\">{{ i18n().to }}</div>\n <div [class]=\"getInputClasses()\" class=\"w-44\">\n <input\n type=\"datetime-local\"\n [value]=\"filter.values[1] || ''\"\n class=\"w-full bg-transparent outline-none\"\n (change)=\"onInputChange(filter, $event, 1)\" />\n </div>\n </div>\n } @else {\n <div [class]=\"getInputClasses()\" class=\"w-44\">\n <input\n type=\"datetime-local\"\n [value]=\"filter.values[0] || ''\"\n class=\"w-full bg-transparent outline-none\"\n (change)=\"onInputChange(filter, $event)\" />\n </div>\n }\n }\n\n <!-- Select/Multiselect -->\n @else if (field.type === 'select' || field.type === 'multiselect' || field.options) {\n <button\n type=\"button\"\n z-popover\n [zPopoverContent]=\"selectPopover\"\n zTrigger=\"click\"\n zPosition=\"bottom-left\"\n [zOffset]=\"4\"\n (zShow)=\"valuePopoverOpen.set(filter.id); focusSelectSearch(filter.id)\"\n (zHide)=\"valuePopoverOpen.set(null)\"\n class=\"hover:bg-muted flex cursor-pointer items-center gap-1.5 px-2.5 text-sm transition-colors\"\n [class.bg-muted]=\"valuePopoverOpen() === filter.id\">\n @if (filter | zFilterSelectedOptions: $any(zFields()); as selectedOpts) {\n @if (selectedOpts.length > 0) {\n <div class=\"flex items-center -space-x-1.5\">\n @for (opt of selectedOpts.slice(0, 3); track $any(opt).value) {\n @if (opt.icon) {\n <z-icon [zType]=\"opt.icon\" zSize=\"14\" />\n }\n }\n </div>\n @if (selectedOpts.length === 1) {\n {{ selectedOpts[0].label }}\n } @else {\n {{ selectedOpts.length }} {{ i18n().selectedCount }}\n }\n } @else {\n <span class=\"text-muted-foreground\">{{ i18n().select }}</span>\n }\n }\n <z-icon zType=\"lucideChevronDown\" zSize=\"12\" class=\"text-muted-foreground ml-1\" />\n </button>\n\n <ng-template #selectPopover let-close=\"close\">\n <div class=\"w-[12.5rem]\">\n @if (field.searchable !== false) {\n <div class=\"border-border flex items-center border-b px-3\">\n <z-icon zType=\"lucideSearch\" zSize=\"16\" class=\"text-muted-foreground/50 mr-2 shrink-0\" />\n <input\n [id]=\"'select-search-' + filter.id\"\n type=\"text\"\n [placeholder]=\"i18n().placeholders.searchField\"\n class=\"placeholder:text-muted-foreground text-foreground flex h-9 w-full bg-transparent py-2 text-sm outline-none\" />\n </div>\n }\n <div class=\"flex max-h-[12.5rem] flex-col gap-0.5 overflow-y-auto p-1\">\n <!-- Selected Options -->\n @for (opt of filter | zFilterSelectedOptions: $any(zFields()); track $any(opt).value) {\n <button\n type=\"button\"\n class=\"hover:bg-accent flex w-full cursor-pointer items-center gap-2 rounded-sm px-2 py-1.5 text-sm transition-colors\"\n (click)=\"onSelectValueChange(filter, $any(opt)); field.type !== 'multiselect' && close()\">\n @if (opt.icon) {\n <z-icon [zType]=\"opt.icon\" zSize=\"14\" />\n }\n <span class=\"truncate\">{{ opt.label }}</span>\n <z-icon zType=\"lucideCheck\" zSize=\"14\" class=\"text-primary ml-auto\" />\n </button>\n }\n\n <!-- Separator -->\n @if (\n (filter | zFilterSelectedOptions: $any(zFields())).length > 0 &&\n (filter | zFilterUnselectedOptions: $any(zFields())).length > 0\n ) {\n <div class=\"bg-border my-1 ml-1 h-px\"></div>\n }\n\n <!-- Unselected Options -->\n @for (opt of filter | zFilterUnselectedOptions: $any(zFields()); track $any(opt).value) {\n <button\n type=\"button\"\n class=\"hover:bg-accent flex w-full cursor-pointer items-center gap-2 rounded-sm px-2 py-1.5 text-sm transition-colors\"\n (click)=\"onSelectValueChange(filter, $any(opt)); field.type !== 'multiselect' && close()\">\n @if (opt.icon) {\n <z-icon [zType]=\"opt.icon\" zSize=\"14\" />\n }\n <span class=\"truncate\">{{ opt.label }}</span>\n </button>\n }\n\n @if (\n (filter | zFilterSelectedOptions: $any(zFields())).length === 0 &&\n (filter | zFilterUnselectedOptions: $any(zFields())).length === 0\n ) {\n <div class=\"text-muted-foreground py-6 text-center text-sm\">\n {{ i18n().noResultsFound }}\n </div>\n }\n </div>\n </div>\n </ng-template>\n }\n }\n\n <!-- Remove Button -->\n <button type=\"button\" [class]=\"getRemoveButtonClasses()\" data-slot=\"filter-remove\" (click)=\"removeFilter(filter)\">\n <z-icon zType=\"lucideX\" zSize=\"14\" />\n </button>\n </div>\n }\n}\n", styles: [":host{display:block}\n"] }]
927
+ }, template: "<!-- Add Filter Button -->\n@if (zShowAddButton() && selectableFields().length > 0) {\n @if (addButtonTemplate()) {\n <ng-container [ngTemplateOutlet]=\"addButtonTemplate()!\" />\n } @else {\n <button\n z-button\n zType=\"outline\"\n [zSize]=\"buttonSize()\"\n z-popover\n [zPopoverContent]=\"addFilterPopover\"\n zTrigger=\"click\"\n zPosition=\"bottom-left\"\n [zOffset]=\"6\"\n (zShow)=\"addFilterOpen.set(true); focusSearchInput()\"\n (zHide)=\"addFilterOpen.set(false); searchQuery.set('')\">\n <z-icon [zType]=\"zAddButtonIcon()\" zSize=\"14\" />\n {{ zAddButtonText() || i18n().addFilter }}\n </button>\n }\n}\n\n<ng-template #addFilterPopover let-close=\"close\">\n <div class=\"w-[12.5rem]\">\n <div class=\"border-border flex items-center border-b px-3\">\n <z-icon zType=\"lucideSearch\" zSize=\"16\" class=\"text-muted-foreground/50 mr-2 shrink-0\" />\n <input\n #addFilterSearchInput\n type=\"text\"\n [placeholder]=\"i18n().searchFields\"\n [value]=\"searchQuery()\"\n (input)=\"onSearchInput($event)\"\n class=\"placeholder:text-muted-foreground text-foreground flex h-10 w-full bg-transparent py-3 text-sm outline-none\" />\n </div>\n <div class=\"flex max-h-[18.75rem] flex-col gap-0.5 overflow-y-auto p-1\">\n @for (group of groupedFields(); track group.group; let groupIndex = $index) {\n @if (group.group) {\n <div\n class=\"text-muted-foreground px-2 py-1.5 text-xs font-medium\"\n [class.border-border]=\"groupIndex > 0\"\n [class.mt-2]=\"groupIndex > 0\"\n [class.border-t]=\"groupIndex > 0\"\n [class.ml-1]=\"groupIndex > 0\">\n {{ group.group }}\n </div>\n }\n @for (field of group.fields; track trackByFieldKey($index, field)) {\n <button\n type=\"button\"\n class=\"hover:bg-accent flex w-full cursor-pointer items-center gap-2 rounded-sm px-2 py-1.5 text-sm transition-colors\"\n (click)=\"onFieldSelect(field); close()\">\n @if (field.icon) {\n <z-icon [zType]=\"field.icon\" zSize=\"14\" class=\"text-muted-foreground\" />\n }\n <span>{{ field.label }}</span>\n </button>\n }\n } @empty {\n <div class=\"text-muted-foreground py-6 text-center text-sm\">\n {{ i18n().noFieldsFound }}\n </div>\n }\n </div>\n </div>\n</ng-template>\n\n<!-- Filter Items -->\n@for (filter of zFilters(); track trackByFilterId($index, filter)) {\n @if (filter | zFilterField: $any(zFields()); as field) {\n <div [class]=\"getItemClasses()\" data-slot=\"filter-item\">\n <!-- Field Label -->\n <div [class]=\"getLabelClasses()\">\n @if (field.icon) {\n <z-icon [zType]=\"field.icon\" zSize=\"14\" />\n }\n {{ field.label }}\n </div>\n\n <!-- Operator Dropdown -->\n <button\n type=\"button\"\n z-popover\n [zPopoverContent]=\"operatorDropdown\"\n zTrigger=\"click\"\n zPosition=\"bottom-left\"\n [zOffset]=\"4\"\n (zShow)=\"operatorPopoverOpen.set(filter.id)\"\n (zHide)=\"operatorPopoverOpen.set(null)\"\n class=\"text-muted-foreground hover:text-foreground hover:bg-muted flex cursor-pointer items-center px-2.5 text-sm transition-colors\"\n [class.text-foreground]=\"operatorPopoverOpen() === filter.id\"\n [class.bg-muted]=\"operatorPopoverOpen() === filter.id\">\n {{ filter | zFilterOperatorLabel: $any(zFields()) : i18n() }}\n <z-icon zType=\"lucideChevronDown\" zSize=\"12\" class=\"ml-1\" />\n </button>\n\n <ng-template #operatorDropdown let-close=\"close\">\n <div class=\"flex w-fit min-w-32 flex-col gap-0.5 p-1\">\n @for (op of filter | zFilterOperators: $any(zFields()) : i18n(); track op.value) {\n <button\n type=\"button\"\n class=\"hover:bg-accent flex w-full cursor-pointer items-center justify-between gap-4 rounded-sm px-2 py-1.5 text-sm transition-colors outline-none\"\n (click)=\"updateFilterOperator(filter, op.value); close()\">\n <span>{{ op.label }}</span>\n @if (op.value === filter.operator) {\n <z-icon zType=\"lucideCheck\" zSize=\"14\" class=\"text-primary\" />\n }\n </button>\n }\n </div>\n </ng-template>\n\n <!-- Value Selector -->\n @if (!(filter | zFilterIsValueHidden)) {\n <!-- Boolean Field -->\n @if (field.type === 'boolean') {\n <div class=\"flex items-center gap-2 px-2.5\">\n <z-switch [zChecked]=\"filter.values[0] === true\" (zChange)=\"onBooleanChange(filter, $event)\" zSize=\"sm\" />\n @if (field.onLabel && field.offLabel) {\n <span class=\"text-muted-foreground text-xs\">\n {{ filter.values[0] === true ? field.onLabel : field.offLabel }}\n </span>\n }\n </div>\n }\n\n <!-- Text/Email/URL/Tel Input -->\n @else if (field.type === 'text' || field.type === 'email' || field.type === 'url' || field.type === 'tel') {\n <div [class]=\"getInputClasses()\" class=\"w-36\">\n @if (field.prefix) {\n <span class=\"text-muted-foreground mr-1\">{{ field.prefix }}</span>\n }\n <input\n type=\"{{\n field.type === 'email' ? 'email' : field.type === 'url' ? 'url' : field.type === 'tel' ? 'tel' : 'text'\n }}\"\n [value]=\"filter.values[0] || ''\"\n [placeholder]=\"field.placeholder || i18n().placeholders.enterField\"\n [pattern]=\"field | zFilterInputPattern\"\n class=\"w-full bg-transparent outline-none\"\n (blur)=\"onInputChange(filter, $event)\" />\n @if (field.suffix) {\n <span class=\"text-muted-foreground ml-1\">{{ field.suffix }}</span>\n }\n </div>\n }\n\n <!-- Number Input -->\n @else if (field.type === 'number') {\n @if (filter | zFilterIsBetweenOperator) {\n <div class=\"flex items-center\">\n <div [class]=\"getInputClasses()\" class=\"w-20\">\n @if (field.prefix) {\n <span class=\"text-muted-foreground mr-1\">{{ field.prefix }}</span>\n }\n <input\n type=\"number\"\n [value]=\"filter.values[0] || ''\"\n [placeholder]=\"i18n().min\"\n [min]=\"field.min\"\n [max]=\"field.max\"\n [step]=\"field.step\"\n class=\"w-full bg-transparent outline-none\"\n (blur)=\"onInputChange(filter, $event, 0)\" />\n </div>\n <div [class]=\"getBetweenClasses()\">{{ i18n().to }}</div>\n <div [class]=\"getInputClasses()\" class=\"w-20\">\n <input\n type=\"number\"\n [value]=\"filter.values[1] || ''\"\n [placeholder]=\"i18n().max\"\n [min]=\"field.min\"\n [max]=\"field.max\"\n [step]=\"field.step\"\n class=\"w-full bg-transparent outline-none\"\n (blur)=\"onInputChange(filter, $event, 1)\" />\n @if (field.suffix) {\n <span class=\"text-muted-foreground ml-1\">{{ field.suffix }}</span>\n }\n </div>\n </div>\n } @else {\n <div [class]=\"getInputClasses()\" class=\"w-24\">\n @if (field.prefix) {\n <span class=\"text-muted-foreground mr-1\">{{ field.prefix }}</span>\n }\n <input\n type=\"number\"\n [value]=\"filter.values[0] || ''\"\n [placeholder]=\"field.placeholder || i18n().placeholders.enterField\"\n [min]=\"field.min\"\n [max]=\"field.max\"\n [step]=\"field.step\"\n class=\"w-full bg-transparent outline-none\"\n (blur)=\"onInputChange(filter, $event)\" />\n @if (field.suffix) {\n <span class=\"text-muted-foreground ml-1\">{{ field.suffix }}</span>\n }\n </div>\n }\n }\n\n <!-- Date Input -->\n @else if (field.type === 'date') {\n <div [class]=\"getInputClasses()\" class=\"z-filter-calendar w-40 min-w-0\">\n <z-calendar\n zMode=\"single\"\n zAllowClear\n zValueType=\"date\"\n zFormat=\"YYYY-MM-DD\"\n [zSize]=\"calendarSize()\"\n [zPlaceholder]=\"field.placeholder || i18n().placeholders.enterField\"\n [ngModel]=\"dateValueMap()[filter.id] ?? null\"\n (ngModelChange)=\"onDateValueChange(filter, $event)\"\n class=\"h-full min-w-0 border-0 bg-transparent px-0 shadow-none ring-0 focus-within:border-transparent focus-within:ring-0\" />\n </div>\n }\n\n <!-- Date Range Input -->\n @else if (field.type === 'daterange') {\n <div [class]=\"getInputClasses()\" class=\"z-filter-calendar w-56 min-w-0\">\n <z-calendar\n zMode=\"range\"\n zAllowClear\n zValueType=\"date\"\n zFormat=\"YYYY-MM-DD\"\n [zSize]=\"calendarSize()\"\n [zPlaceholder]=\"field.placeholder || i18n().placeholders.enterField\"\n [ngModel]=\"dateRangeValueMap()[filter.id] ?? null\"\n (ngModelChange)=\"onDateRangeValueChange(filter, $event)\"\n class=\"h-full min-w-0 border-0 bg-transparent px-0 shadow-none ring-0 focus-within:border-transparent focus-within:ring-0\" />\n </div>\n }\n\n <!-- Time Input -->\n @else if (field.type === 'time') {\n <div [class]=\"getInputClasses()\" class=\"z-filter-calendar w-28 min-w-0\">\n <z-calendar\n zMode=\"time\"\n zAllowClear\n zValueType=\"date\"\n zFormat=\"HH:mm\"\n [zSize]=\"calendarSize()\"\n [zShowSecond]=\"false\"\n [zPlaceholder]=\"field.placeholder || i18n().placeholders.enterField\"\n [ngModel]=\"timeValueMap()[filter.id] ?? null\"\n (ngModelChange)=\"onTimeValueChange(filter, $event)\"\n class=\"h-full min-w-0 border-0 bg-transparent px-0 shadow-none ring-0 focus-within:border-transparent focus-within:ring-0\" />\n </div>\n }\n\n <!-- DateTime Input -->\n @else if (field.type === 'datetime') {\n <div [class]=\"getInputClasses()\" class=\"z-filter-calendar w-52 min-w-0\">\n <z-calendar\n zMode=\"single\"\n zShowTime\n zAllowClear\n zValueType=\"date\"\n zFormat=\"YYYY-MM-DD HH:mm\"\n [zSize]=\"calendarSize()\"\n [zShowSecond]=\"false\"\n [zPlaceholder]=\"field.placeholder || i18n().placeholders.enterField\"\n [ngModel]=\"dateTimeValueMap()[filter.id] ?? null\"\n (ngModelChange)=\"onDateTimeValueChange(filter, $event)\"\n class=\"h-full min-w-0 border-0 bg-transparent px-0 shadow-none ring-0 focus-within:border-transparent focus-within:ring-0\" />\n </div>\n }\n\n <!-- Select/Multiselect -->\n @else if (field.type === 'select' || field.type === 'multiselect' || field.options) {\n <button\n type=\"button\"\n z-popover\n [zPopoverContent]=\"selectPopover\"\n zTrigger=\"click\"\n zPosition=\"bottom-left\"\n [zOffset]=\"4\"\n (zShow)=\"valuePopoverOpen.set(filter.id); focusSelectSearch(filter.id)\"\n (zHide)=\"valuePopoverOpen.set(null)\"\n class=\"hover:bg-muted flex cursor-pointer items-center gap-1.5 px-2.5 text-sm transition-colors\"\n [class.bg-muted]=\"valuePopoverOpen() === filter.id\">\n @if (filter | zFilterSelectedOptions: $any(zFields()); as selectedOpts) {\n @if (selectedOpts.length > 0) {\n <div class=\"flex items-center -space-x-1.5\">\n @for (opt of selectedOpts.slice(0, 3); track $any(opt).value) {\n @if (opt.icon) {\n <z-icon [zType]=\"opt.icon\" zSize=\"14\" />\n }\n }\n </div>\n @if (selectedOpts.length === 1) {\n {{ selectedOpts[0].label }}\n } @else {\n {{ selectedOpts.length }} {{ i18n().selectedCount }}\n }\n } @else {\n <span class=\"text-muted-foreground\">{{ i18n().select }}</span>\n }\n }\n <z-icon zType=\"lucideChevronDown\" zSize=\"12\" class=\"text-muted-foreground ml-1\" />\n </button>\n\n <ng-template #selectPopover let-close=\"close\">\n <div class=\"w-[12.5rem]\">\n @if (field.searchable !== false) {\n <div class=\"border-border flex items-center border-b px-3\">\n <z-icon zType=\"lucideSearch\" zSize=\"16\" class=\"text-muted-foreground/50 mr-2 shrink-0\" />\n <input\n [id]=\"'select-search-' + filter.id\"\n type=\"text\"\n [placeholder]=\"i18n().placeholders.searchField\"\n class=\"placeholder:text-muted-foreground text-foreground flex h-9 w-full bg-transparent py-2 text-sm outline-none\" />\n </div>\n }\n <div class=\"flex max-h-[12.5rem] flex-col gap-0.5 overflow-y-auto p-1\">\n <!-- Selected Options -->\n @for (opt of filter | zFilterSelectedOptions: $any(zFields()); track $any(opt).value) {\n <button\n type=\"button\"\n class=\"hover:bg-accent flex w-full cursor-pointer items-center gap-2 rounded-sm px-2 py-1.5 text-sm transition-colors\"\n (click)=\"onSelectValueChange(filter, $any(opt)); field.type !== 'multiselect' && close()\">\n @if (opt.icon) {\n <z-icon [zType]=\"opt.icon\" zSize=\"14\" />\n }\n <span class=\"truncate\">{{ opt.label }}</span>\n <z-icon zType=\"lucideCheck\" zSize=\"14\" class=\"text-primary ml-auto\" />\n </button>\n }\n\n <!-- Separator -->\n @if (\n (filter | zFilterSelectedOptions: $any(zFields())).length > 0 &&\n (filter | zFilterUnselectedOptions: $any(zFields())).length > 0\n ) {\n <div class=\"bg-border my-1 ml-1 h-px\"></div>\n }\n\n <!-- Unselected Options -->\n @for (opt of filter | zFilterUnselectedOptions: $any(zFields()); track $any(opt).value) {\n <button\n type=\"button\"\n class=\"hover:bg-accent flex w-full cursor-pointer items-center gap-2 rounded-sm px-2 py-1.5 text-sm transition-colors\"\n (click)=\"onSelectValueChange(filter, $any(opt)); field.type !== 'multiselect' && close()\">\n @if (opt.icon) {\n <z-icon [zType]=\"opt.icon\" zSize=\"14\" />\n }\n <span class=\"truncate\">{{ opt.label }}</span>\n </button>\n }\n\n @if (\n (filter | zFilterSelectedOptions: $any(zFields())).length === 0 &&\n (filter | zFilterUnselectedOptions: $any(zFields())).length === 0\n ) {\n <div class=\"text-muted-foreground py-6 text-center text-sm\">\n {{ i18n().noResultsFound }}\n </div>\n }\n </div>\n </div>\n </ng-template>\n }\n }\n\n <!-- Remove Button -->\n <button type=\"button\" [class]=\"getRemoveButtonClasses()\" data-slot=\"filter-remove\" (click)=\"removeFilter(filter)\">\n <z-icon zType=\"lucideX\" zSize=\"14\" />\n </button>\n </div>\n }\n}\n", styles: [":host{display:block}.z-filter-calendar z-calendar{display:contents}.z-filter-calendar z-calendar .z-calendar-wrapper{display:contents}.z-filter-calendar z-calendar .z-calendar-wrapper>.relative{display:contents}.z-filter-calendar z-calendar [z-popover]{display:flex!important;align-items:center!important;height:auto!important;min-height:0!important;width:100%!important;border:0!important;box-shadow:none!important;padding:0!important;background:transparent!important;outline:none!important;gap:.375rem!important;cursor:pointer!important}.z-filter-calendar z-calendar [z-popover]:focus-within{border-color:transparent!important;box-shadow:none!important}.z-filter-calendar z-calendar [z-popover]>z-icon{flex-shrink:0}.z-filter-calendar z-calendar [z-popover]>input{flex:1 1 0!important;min-width:0!important;width:0!important}.z-filter-calendar z-calendar [z-popover]>button[tabindex=\"-1\"]{display:none!important}.z-filter-calendar z-calendar .z-calendar-wrapper>p{display:none!important}\n"] }]
781
928
  }], propDecorators: { addButtonTemplate: [{ type: i0.ContentChild, args: ['addButton', { isSignal: true }] }], zFiltersChange: [{ type: i0.Output, args: ["zFiltersChange"] }], zFilterAdd: [{ type: i0.Output, args: ["zFilterAdd"] }], zFilterRemove: [{ type: i0.Output, args: ["zFilterRemove"] }], zFilterUpdate: [{ type: i0.Output, args: ["zFilterUpdate"] }], class: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }], zFilters: [{ type: i0.Input, args: [{ isSignal: true, alias: "zFilters", required: true }] }], zFields: [{ type: i0.Input, args: [{ isSignal: true, alias: "zFields", required: true }] }], zSize: [{ type: i0.Input, args: [{ isSignal: true, alias: "zSize", required: false }] }], zI18n: [{ type: i0.Input, args: [{ isSignal: true, alias: "zI18n", required: false }] }], zShowAddButton: [{ type: i0.Input, args: [{ isSignal: true, alias: "zShowAddButton", required: false }] }], zAllowMultiple: [{ type: i0.Input, args: [{ isSignal: true, alias: "zAllowMultiple", required: false }] }], zAddButtonIcon: [{ type: i0.Input, args: [{ isSignal: true, alias: "zAddButtonIcon", required: false }] }], zAddButtonText: [{ type: i0.Input, args: [{ isSignal: true, alias: "zAddButtonText", required: false }] }], addFilterSearchInput: [{ type: i0.ViewChild, args: ['addFilterSearchInput', { isSignal: true }] }] } });
782
929
 
783
930
  /**