@masterteam/components 0.0.175 → 0.0.176

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 (37) hide show
  1. package/assets/common.css +1 -1
  2. package/assets/i18n/ar.json +19 -1
  3. package/assets/i18n/en.json +19 -1
  4. package/fesm2022/masterteam-components-business-fields.mjs +50 -34
  5. package/fesm2022/masterteam-components-business-fields.mjs.map +1 -1
  6. package/fesm2022/masterteam-components-color-picker-field.mjs +2 -2
  7. package/fesm2022/masterteam-components-color-picker-field.mjs.map +1 -1
  8. package/fesm2022/masterteam-components-field-validation.mjs +21 -1
  9. package/fesm2022/masterteam-components-field-validation.mjs.map +1 -1
  10. package/fesm2022/masterteam-components-formula.mjs +20 -3
  11. package/fesm2022/masterteam-components-formula.mjs.map +1 -1
  12. package/fesm2022/masterteam-components-location-field.mjs +1 -1
  13. package/fesm2022/masterteam-components-location-field.mjs.map +1 -1
  14. package/fesm2022/masterteam-components-property-filter-builder.mjs +1 -1
  15. package/fesm2022/masterteam-components-property-filter-builder.mjs.map +1 -1
  16. package/fesm2022/masterteam-components-table.mjs +112 -24
  17. package/fesm2022/masterteam-components-table.mjs.map +1 -1
  18. package/fesm2022/masterteam-components-text-field.mjs +26 -7
  19. package/fesm2022/masterteam-components-text-field.mjs.map +1 -1
  20. package/fesm2022/masterteam-components-textarea-field.mjs +27 -8
  21. package/fesm2022/masterteam-components-textarea-field.mjs.map +1 -1
  22. package/fesm2022/masterteam-components-treeselect-field.mjs +265 -0
  23. package/fesm2022/masterteam-components-treeselect-field.mjs.map +1 -0
  24. package/fesm2022/masterteam-components-upload-field.mjs +16 -7
  25. package/fesm2022/masterteam-components-upload-field.mjs.map +1 -1
  26. package/fesm2022/masterteam-components.mjs +2 -2
  27. package/fesm2022/masterteam-components.mjs.map +1 -1
  28. package/package.json +5 -1
  29. package/types/masterteam-components-business-fields.d.ts +8 -5
  30. package/types/masterteam-components-field-validation.d.ts +4 -2
  31. package/types/masterteam-components-formula.d.ts +4 -0
  32. package/types/masterteam-components-table.d.ts +13 -3
  33. package/types/masterteam-components-text-field.d.ts +3 -1
  34. package/types/masterteam-components-textarea-field.d.ts +4 -2
  35. package/types/masterteam-components-treeselect-field.d.ts +79 -0
  36. package/types/masterteam-components-upload-field.d.ts +3 -1
  37. package/types/masterteam-components.d.ts +5 -5
@@ -19,6 +19,7 @@ import { DateField } from '@masterteam/components/date-field';
19
19
  import { NumberField } from '@masterteam/components/number-field';
20
20
  import { MultiSelectField } from '@masterteam/components/multi-select-field';
21
21
  import { SelectField } from '@masterteam/components/select-field';
22
+ import { TreeSelectField } from '@masterteam/components/treeselect-field';
22
23
  import { UserSearchField } from '@masterteam/components/user-search-field';
23
24
  import * as XLSX from 'xlsx';
24
25
  import { ToggleField } from '@masterteam/components/toggle-field';
@@ -365,6 +366,17 @@ class TableValueResolver {
365
366
  normalizedItemUser['userName'] === objectFilter.userName ||
366
367
  normalizedItemUser['displayName'] === objectFilter.displayName);
367
368
  }
369
+ if (filterType === 'treeSelect') {
370
+ const filterLabel = TableValueResolver.resolveTreeFilterLabel(filterValue);
371
+ if (!filterLabel) {
372
+ return true;
373
+ }
374
+ const itemLabel = normalizedFilterValue ??
375
+ TableValueResolver.resolveTreeFilterLabel(itemValue);
376
+ return itemLabel === null || itemLabel === undefined
377
+ ? false
378
+ : String(itemLabel).toLowerCase().includes(filterLabel.toLowerCase());
379
+ }
368
380
  }
369
381
  if (typeof filterValue === 'boolean') {
370
382
  return normalizedFilterValue === filterValue;
@@ -414,7 +426,10 @@ class TableValueResolver {
414
426
  filterValue.to != null ||
415
427
  filterValue.value != null ||
416
428
  filterValue.userName != null ||
417
- filterValue.id != null);
429
+ filterValue.id != null ||
430
+ filterValue.key != null ||
431
+ filterValue.label != null ||
432
+ filterValue.data != null);
418
433
  }
419
434
  return true;
420
435
  }
@@ -483,6 +498,8 @@ class TableValueResolver {
483
498
  const right = b;
484
499
  if (left['id'] != null && left['id'] === right['id'])
485
500
  return true;
501
+ if (left['key'] != null && left['key'] === right['key'])
502
+ return true;
486
503
  if (left['userName'] != null && left['userName'] === right['userName']) {
487
504
  return true;
488
505
  }
@@ -614,8 +631,10 @@ class TableValueResolver {
614
631
  const displayCandidate = objectValue['display'] ??
615
632
  objectValue['displayValue'] ??
616
633
  objectValue['displayName'] ??
634
+ objectValue['pathLabel'] ??
617
635
  objectValue['name'] ??
618
636
  objectValue['label'] ??
637
+ objectValue['code'] ??
619
638
  objectValue['value'];
620
639
  return TableValueResolver.resolveDisplayValue(displayCandidate);
621
640
  }
@@ -685,12 +704,35 @@ class TableValueResolver {
685
704
  return (typeof value === 'string' &&
686
705
  TableValueResolver.ALL_ENTITY_VIEW_TYPES.includes(value));
687
706
  }
707
+ static resolveTreeFilterLabel(value) {
708
+ if (!value || typeof value !== 'object') {
709
+ return null;
710
+ }
711
+ const record = value;
712
+ const data = record['data'];
713
+ if (data && typeof data === 'object') {
714
+ const pathLabel = data['pathLabel'];
715
+ if (typeof pathLabel === 'string' && pathLabel.trim().length > 0) {
716
+ return pathLabel.trim();
717
+ }
718
+ }
719
+ const pathLabel = record['pathLabel'];
720
+ if (typeof pathLabel === 'string' && pathLabel.trim().length > 0) {
721
+ return pathLabel.trim();
722
+ }
723
+ const label = record['label'];
724
+ if (typeof label === 'string' && label.trim().length > 0) {
725
+ return label.trim();
726
+ }
727
+ const key = record['key'];
728
+ return typeof key === 'string' && key.trim().length > 0 ? key.trim() : null;
729
+ }
688
730
  }
689
731
 
690
732
  /**
691
733
  * Renders a single filter control for one `ColumnDef`, dispatching on
692
- * `column.filterConfig.type` (`text` | `select` | `date` | `boolean` | `user`
693
- * | `numberRange`).
734
+ * `column.filterConfig.type` (`text` | `select` | `treeSelect` | `date`
735
+ * | `boolean` | `user` | `numberRange`).
694
736
  *
695
737
  * Two-way binds the filter value via `value` / `valueChange`. Shared by both
696
738
  * filter UX modes (popover + per-column) so field rendering lives in one place.
@@ -716,6 +758,7 @@ class TableFilterField {
716
758
  return [current];
717
759
  }, ...(ngDevMode ? [{ debugName: "multiValue" }] : /* istanbul ignore next */ []));
718
760
  filterOptions = computed(() => this.column().filterConfig?.options ?? EMPTY_MULTI_VALUE, ...(ngDevMode ? [{ debugName: "filterOptions" }] : /* istanbul ignore next */ []));
761
+ treeOptions = computed(() => this.column().filterConfig?.treeOptions ?? [], ...(ngDevMode ? [{ debugName: "treeOptions" }] : /* istanbul ignore next */ []));
719
762
  getFilterType() {
720
763
  return this.column().filterConfig?.type ?? 'text';
721
764
  }
@@ -749,6 +792,37 @@ class TableFilterField {
749
792
  updateScalar(next) {
750
793
  this.value.set(next);
751
794
  }
795
+ getTreePlaceholder() {
796
+ const configured = this.column().filterConfig?.['placeholder'];
797
+ if (typeof configured === 'string' && configured.trim().length > 0) {
798
+ return configured;
799
+ }
800
+ return `${this.transloco.translate('components.table.select')} ${this.column().filterConfig?.label || this.column().label}`;
801
+ }
802
+ getTreeFilterBy() {
803
+ const configured = this.column().filterConfig?.['filterBy'];
804
+ return typeof configured === 'string' && configured.trim().length > 0
805
+ ? configured
806
+ : 'label,data.pathLabel';
807
+ }
808
+ getTreeFilterPlaceholder() {
809
+ const configured = this.column().filterConfig?.['filterPlaceholder'];
810
+ return typeof configured === 'string' && configured.trim().length > 0
811
+ ? configured
812
+ : this.transloco.translate('components.table.search');
813
+ }
814
+ getTreeScrollHeight() {
815
+ const configured = this.column().filterConfig?.['scrollHeight'];
816
+ return typeof configured === 'string' && configured.trim().length > 0
817
+ ? configured
818
+ : '20rem';
819
+ }
820
+ getTreePanelStyleClass() {
821
+ const configured = this.column().filterConfig?.['panelStyleClass'];
822
+ return typeof configured === 'string' && configured.trim().length > 0
823
+ ? configured
824
+ : undefined;
825
+ }
752
826
  updateDate(part, next) {
753
827
  const current = this.value() ?? {};
754
828
  this.value.set({ ...current, [part]: next });
@@ -758,7 +832,7 @@ class TableFilterField {
758
832
  this.value.set({ ...current, [part]: next });
759
833
  }
760
834
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: TableFilterField, deps: [], target: i0.ɵɵFactoryTarget.Component });
761
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.8", type: TableFilterField, isStandalone: true, selector: "mt-table-filter-field", inputs: { column: { classPropertyName: "column", publicName: "column", isSignal: true, isRequired: true, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange" }, ngImport: i0, template: "@switch (getFilterType()) {\r\n @case (\"text\") {\r\n <mt-text-field\r\n [ngModel]=\"getScalarValue()\"\r\n (ngModelChange)=\"updateScalar($event)\"\r\n [placeholder]=\"\r\n ('components.table.select' | transloco) +\r\n ' ' +\r\n (column().filterConfig?.label || column().label)\r\n \"\r\n />\r\n }\r\n @case (\"select\") {\r\n @if (isMultiple()) {\r\n <mt-multi-select-field\r\n [ngModel]=\"multiValue()\"\r\n (ngModelChange)=\"updateScalar($event)\"\r\n [options]=\"filterOptions()\"\r\n [placeholder]=\"\r\n ('components.table.select' | transloco) +\r\n ' ' +\r\n (column().filterConfig?.label || column().label)\r\n \"\r\n [showClear]=\"true\"\r\n [filter]=\"true\"\r\n filterBy=\"label\"\r\n optionLabel=\"label\"\r\n optionValue=\"value\"\r\n />\r\n } @else {\r\n <mt-select-field\r\n [ngModel]=\"getScalarValue()\"\r\n (ngModelChange)=\"updateScalar($event)\"\r\n [options]=\"filterOptions()\"\r\n [placeholder]=\"\r\n ('components.table.select' | transloco) +\r\n ' ' +\r\n (column().filterConfig?.label || column().label)\r\n \"\r\n [hasPlaceholderPrefix]=\"false\"\r\n optionLabel=\"label\"\r\n optionValue=\"value\"\r\n showClear\r\n />\r\n }\r\n }\r\n @case (\"userSelect\") {\r\n @if (isMultiple()) {\r\n <mt-multi-select-field\r\n [ngModel]=\"multiValue()\"\r\n (ngModelChange)=\"updateScalar($event)\"\r\n [options]=\"filterOptions()\"\r\n [placeholder]=\"\r\n ('components.table.select' | transloco) +\r\n ' ' +\r\n (column().filterConfig?.label || column().label)\r\n \"\r\n [showClear]=\"true\"\r\n [filter]=\"true\"\r\n filterBy=\"label\"\r\n optionLabel=\"label\"\r\n optionValue=\"value\"\r\n />\r\n } @else {\r\n <mt-select-field\r\n [ngModel]=\"getScalarValue()\"\r\n (ngModelChange)=\"updateScalar($event)\"\r\n [options]=\"filterOptions()\"\r\n [placeholder]=\"\r\n ('components.table.select' | transloco) +\r\n ' ' +\r\n (column().filterConfig?.label || column().label)\r\n \"\r\n [hasPlaceholderPrefix]=\"false\"\r\n [markCurrentUser]=\"true\"\r\n optionLabel=\"label\"\r\n optionValue=\"value\"\r\n showClear\r\n />\r\n }\r\n }\r\n @case (\"date\") {\r\n <div class=\"space-y-3\">\r\n <div class=\"space-y-1\">\r\n <label\r\n class=\"block text-sm font-medium text-gray-700 dark:text-gray-300\"\r\n >\r\n {{ \"components.table.from\" | transloco }}\r\n </label>\r\n <mt-date-field\r\n [ngModel]=\"getDateRangeValue('from')\"\r\n (ngModelChange)=\"updateDate('from', $event)\"\r\n [placeholder]=\"'components.table.from' | transloco\"\r\n />\r\n </div>\r\n <div class=\"space-y-1\">\r\n <label\r\n class=\"block text-sm font-medium text-gray-700 dark:text-gray-300\"\r\n >\r\n {{ \"components.table.to\" | transloco }}\r\n </label>\r\n <mt-date-field\r\n [ngModel]=\"getDateRangeValue('to')\"\r\n (ngModelChange)=\"updateDate('to', $event)\"\r\n [placeholder]=\"'components.table.to' | transloco\"\r\n />\r\n </div>\r\n </div>\r\n }\r\n @case (\"boolean\") {\r\n <mt-select-field\r\n [ngModel]=\"getScalarValue()\"\r\n (ngModelChange)=\"updateScalar($event)\"\r\n [options]=\"booleanOptions()\"\r\n [placeholder]=\"'components.table.select' | transloco\"\r\n [hasPlaceholderPrefix]=\"false\"\r\n optionLabel=\"label\"\r\n optionValue=\"value\"\r\n showClear\r\n />\r\n }\r\n @case (\"user\") {\r\n <mt-user-search-field\r\n [ngModel]=\"getScalarValue()\"\r\n (ngModelChange)=\"updateScalar($event)\"\r\n [placeholder]=\"column().filterConfig?.label || column().label\"\r\n [apiUrl]=\"column().filterConfig?.apiUrl ?? ''\"\r\n [context]=\"column().filterConfig?.context\"\r\n />\r\n }\r\n @case (\"numberRange\") {\r\n <div class=\"space-y-3\">\r\n <div class=\"space-y-1\">\r\n <label\r\n class=\"block text-sm font-medium text-gray-700 dark:text-gray-300\"\r\n >\r\n {{ \"components.table.from\" | transloco }}\r\n </label>\r\n <mt-number-field\r\n [ngModel]=\"getNumberRangeValue('from')\"\r\n (ngModelChange)=\"updateNumber('from', $event)\"\r\n [placeholder]=\"'components.table.from' | transloco\"\r\n />\r\n </div>\r\n <div class=\"space-y-1\">\r\n <label\r\n class=\"block text-sm font-medium text-gray-700 dark:text-gray-300\"\r\n >\r\n {{ \"components.table.to\" | transloco }}\r\n </label>\r\n <mt-number-field\r\n [ngModel]=\"getNumberRangeValue('to')\"\r\n (ngModelChange)=\"updateNumber('to', $event)\"\r\n [placeholder]=\"'components.table.to' | transloco\"\r\n />\r\n </div>\r\n </div>\r\n }\r\n}\r\n", dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: TextField, selector: "mt-text-field", inputs: ["field", "hint", "label", "placeholder", "class", "type", "readonly", "pInputs", "required", "icon", "iconPosition"] }, { kind: "component", type: NumberField, selector: "mt-number-field", inputs: ["field", "hint", "label", "placeholder", "class", "readonly", "pInputs", "format", "useGrouping", "maxFractionDigits", "min", "max", "required"] }, { kind: "component", type: SelectField, selector: "mt-select-field", inputs: ["field", "hint", "label", "placeholder", "hasPlaceholderPrefix", "class", "readonly", "pInputs", "options", "optionValue", "optionLabel", "filter", "filterBy", "dataKey", "showClear", "clearAfterSelect", "required", "group", "size", "optionGroupLabel", "optionGroupChildren", "loading", "optionIcon", "optionIconColor", "optionIconShape", "optionAvatarShape", "optionGroupIcon", "optionGroupIconColor", "optionGroupIconShape", "optionGroupAvatarShape", "markCurrentUser"], outputs: ["onChange"] }, { kind: "component", type: MultiSelectField, selector: "mt-multi-select-field", inputs: ["field", "label", "placeholder", "class", "readonly", "pInputs", "options", "optionValue", "optionLabel", "filter", "filterBy", "dataKey", "showClear", "display", "required", "maxSelectedLabels", "group", "optionGroupLabel", "optionGroupChildren", "optionIcon", "optionIconColor", "optionIconShape", "optionAvatarShape", "optionGroupIcon", "optionGroupIconColor", "optionGroupIconShape", "optionGroupAvatarShape"], outputs: ["onChange"] }, { kind: "component", type: DateField, selector: "mt-date-field", inputs: ["field", "hint", "label", "placeholder", "class", "readonly", "showIcon", "showClear", "showTime", "pInputs", "required"] }, { kind: "component", type: UserSearchField, selector: "mt-user-search-field", inputs: ["hint", "label", "placeholder", "class", "readonly", "required", "isMultiple", "apiUrl", "dataKey", "paramName", "context", "size"] }, { kind: "ngmodule", type: TranslocoModule }, { kind: "pipe", type: i2.TranslocoPipe, name: "transloco" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
835
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.8", type: TableFilterField, isStandalone: true, selector: "mt-table-filter-field", inputs: { column: { classPropertyName: "column", publicName: "column", isSignal: true, isRequired: true, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange" }, ngImport: i0, template: "@switch (getFilterType()) {\r\n @case (\"text\") {\r\n <mt-text-field\r\n [ngModel]=\"getScalarValue()\"\r\n (ngModelChange)=\"updateScalar($event)\"\r\n [placeholder]=\"\r\n ('components.table.select' | transloco) +\r\n ' ' +\r\n (column().filterConfig?.label || column().label)\r\n \"\r\n />\r\n }\r\n @case (\"select\") {\r\n @if (isMultiple()) {\r\n <mt-multi-select-field\r\n [ngModel]=\"multiValue()\"\r\n (ngModelChange)=\"updateScalar($event)\"\r\n [options]=\"filterOptions()\"\r\n [placeholder]=\"\r\n ('components.table.select' | transloco) +\r\n ' ' +\r\n (column().filterConfig?.label || column().label)\r\n \"\r\n [showClear]=\"true\"\r\n [filter]=\"true\"\r\n filterBy=\"label\"\r\n optionLabel=\"label\"\r\n optionValue=\"value\"\r\n />\r\n } @else {\r\n <mt-select-field\r\n [ngModel]=\"getScalarValue()\"\r\n (ngModelChange)=\"updateScalar($event)\"\r\n [options]=\"filterOptions()\"\r\n [placeholder]=\"\r\n ('components.table.select' | transloco) +\r\n ' ' +\r\n (column().filterConfig?.label || column().label)\r\n \"\r\n [hasPlaceholderPrefix]=\"false\"\r\n optionLabel=\"label\"\r\n optionValue=\"value\"\r\n showClear\r\n />\r\n }\r\n }\r\n @case (\"userSelect\") {\r\n @if (isMultiple()) {\r\n <mt-multi-select-field\r\n [ngModel]=\"multiValue()\"\r\n (ngModelChange)=\"updateScalar($event)\"\r\n [options]=\"filterOptions()\"\r\n [placeholder]=\"\r\n ('components.table.select' | transloco) +\r\n ' ' +\r\n (column().filterConfig?.label || column().label)\r\n \"\r\n [showClear]=\"true\"\r\n [filter]=\"true\"\r\n filterBy=\"label\"\r\n optionLabel=\"label\"\r\n optionValue=\"value\"\r\n />\r\n } @else {\r\n <mt-select-field\r\n [ngModel]=\"getScalarValue()\"\r\n (ngModelChange)=\"updateScalar($event)\"\r\n [options]=\"filterOptions()\"\r\n [placeholder]=\"\r\n ('components.table.select' | transloco) +\r\n ' ' +\r\n (column().filterConfig?.label || column().label)\r\n \"\r\n [hasPlaceholderPrefix]=\"false\"\r\n [markCurrentUser]=\"true\"\r\n optionLabel=\"label\"\r\n optionValue=\"value\"\r\n showClear\r\n />\r\n }\r\n }\r\n @case (\"treeSelect\") {\r\n <mt-treeselect-field\r\n [ngModel]=\"value()\"\r\n (ngModelChange)=\"updateScalar($event)\"\r\n [options]=\"treeOptions()\"\r\n [placeholder]=\"getTreePlaceholder()\"\r\n [selectionMode]=\"$any(column().filterConfig)?.selectionMode || 'single'\"\r\n [scrollHeight]=\"getTreeScrollHeight()\"\r\n [panelStyleClass]=\"getTreePanelStyleClass()\"\r\n [filter]=\"column().filterConfig?.['filter'] !== false\"\r\n [filterBy]=\"getTreeFilterBy()\"\r\n [filterPlaceholder]=\"getTreeFilterPlaceholder()\"\r\n [showClear]=\"column().filterConfig?.['showClear'] !== false\"\r\n [resetFilterOnHide]=\"\r\n column().filterConfig?.['resetFilterOnHide'] !== false\r\n \"\r\n [overlayOptions]=\"$any(column().filterConfig)?.overlayOptions\"\r\n />\r\n }\r\n @case (\"date\") {\r\n <div class=\"space-y-3\">\r\n <div class=\"space-y-1\">\r\n <label\r\n class=\"block text-sm font-medium text-gray-700 dark:text-gray-300\"\r\n >\r\n {{ \"components.table.from\" | transloco }}\r\n </label>\r\n <mt-date-field\r\n [ngModel]=\"getDateRangeValue('from')\"\r\n (ngModelChange)=\"updateDate('from', $event)\"\r\n [placeholder]=\"'components.table.from' | transloco\"\r\n />\r\n </div>\r\n <div class=\"space-y-1\">\r\n <label\r\n class=\"block text-sm font-medium text-gray-700 dark:text-gray-300\"\r\n >\r\n {{ \"components.table.to\" | transloco }}\r\n </label>\r\n <mt-date-field\r\n [ngModel]=\"getDateRangeValue('to')\"\r\n (ngModelChange)=\"updateDate('to', $event)\"\r\n [placeholder]=\"'components.table.to' | transloco\"\r\n />\r\n </div>\r\n </div>\r\n }\r\n @case (\"boolean\") {\r\n <mt-select-field\r\n [ngModel]=\"getScalarValue()\"\r\n (ngModelChange)=\"updateScalar($event)\"\r\n [options]=\"booleanOptions()\"\r\n [placeholder]=\"'components.table.select' | transloco\"\r\n [hasPlaceholderPrefix]=\"false\"\r\n optionLabel=\"label\"\r\n optionValue=\"value\"\r\n showClear\r\n />\r\n }\r\n @case (\"user\") {\r\n <mt-user-search-field\r\n [ngModel]=\"getScalarValue()\"\r\n (ngModelChange)=\"updateScalar($event)\"\r\n [placeholder]=\"column().filterConfig?.label || column().label\"\r\n [apiUrl]=\"column().filterConfig?.apiUrl ?? ''\"\r\n [context]=\"column().filterConfig?.context\"\r\n />\r\n }\r\n @case (\"numberRange\") {\r\n <div class=\"space-y-3\">\r\n <div class=\"space-y-1\">\r\n <label\r\n class=\"block text-sm font-medium text-gray-700 dark:text-gray-300\"\r\n >\r\n {{ \"components.table.from\" | transloco }}\r\n </label>\r\n <mt-number-field\r\n [ngModel]=\"getNumberRangeValue('from')\"\r\n (ngModelChange)=\"updateNumber('from', $event)\"\r\n [placeholder]=\"'components.table.from' | transloco\"\r\n />\r\n </div>\r\n <div class=\"space-y-1\">\r\n <label\r\n class=\"block text-sm font-medium text-gray-700 dark:text-gray-300\"\r\n >\r\n {{ \"components.table.to\" | transloco }}\r\n </label>\r\n <mt-number-field\r\n [ngModel]=\"getNumberRangeValue('to')\"\r\n (ngModelChange)=\"updateNumber('to', $event)\"\r\n [placeholder]=\"'components.table.to' | transloco\"\r\n />\r\n </div>\r\n </div>\r\n }\r\n}\r\n", dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: TextField, selector: "mt-text-field", inputs: ["field", "hint", "label", "placeholder", "class", "type", "readonly", "pInputs", "required", "maxLength", "icon", "iconPosition"] }, { kind: "component", type: NumberField, selector: "mt-number-field", inputs: ["field", "hint", "label", "placeholder", "class", "readonly", "pInputs", "format", "useGrouping", "maxFractionDigits", "min", "max", "required"] }, { kind: "component", type: SelectField, selector: "mt-select-field", inputs: ["field", "hint", "label", "placeholder", "hasPlaceholderPrefix", "class", "readonly", "pInputs", "options", "optionValue", "optionLabel", "filter", "filterBy", "dataKey", "showClear", "clearAfterSelect", "required", "group", "size", "optionGroupLabel", "optionGroupChildren", "loading", "optionIcon", "optionIconColor", "optionIconShape", "optionAvatarShape", "optionGroupIcon", "optionGroupIconColor", "optionGroupIconShape", "optionGroupAvatarShape", "markCurrentUser"], outputs: ["onChange"] }, { kind: "component", type: MultiSelectField, selector: "mt-multi-select-field", inputs: ["field", "label", "placeholder", "class", "readonly", "pInputs", "options", "optionValue", "optionLabel", "filter", "filterBy", "dataKey", "showClear", "display", "required", "maxSelectedLabels", "group", "optionGroupLabel", "optionGroupChildren", "optionIcon", "optionIconColor", "optionIconShape", "optionAvatarShape", "optionGroupIcon", "optionGroupIconColor", "optionGroupIconShape", "optionGroupAvatarShape"], outputs: ["onChange"] }, { kind: "component", type: DateField, selector: "mt-date-field", inputs: ["field", "hint", "label", "placeholder", "class", "readonly", "showIcon", "showClear", "showTime", "pInputs", "required"] }, { kind: "component", type: UserSearchField, selector: "mt-user-search-field", inputs: ["hint", "label", "placeholder", "class", "readonly", "required", "isMultiple", "apiUrl", "dataKey", "paramName", "context", "size"] }, { kind: "component", type: TreeSelectField, selector: "mt-treeselect-field", inputs: ["field", "hint", "label", "placeholder", "class", "readonly", "required", "pInputs", "options", "selectionMode", "display", "scrollHeight", "panelStyleClass", "containerStyleClass", "overlayOptions", "filter", "filterBy", "filterMode", "filterPlaceholder", "filterLocale", "filterInputAutoFocus", "showClear", "resetFilterOnHide", "propagateSelectionDown", "propagateSelectionUp", "virtualScroll", "virtualScrollItemSize", "loading", "loadingMode", "size", "variant", "fluid", "appendTo", "selectedLabelPath"], outputs: ["onChange"] }, { kind: "ngmodule", type: TranslocoModule }, { kind: "pipe", type: i2.TranslocoPipe, name: "transloco" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
762
836
  }
763
837
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: TableFilterField, decorators: [{
764
838
  type: Component,
@@ -770,11 +844,16 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImpor
770
844
  MultiSelectField,
771
845
  DateField,
772
846
  UserSearchField,
847
+ TreeSelectField,
773
848
  TranslocoModule,
774
- ], changeDetection: ChangeDetectionStrategy.OnPush, template: "@switch (getFilterType()) {\r\n @case (\"text\") {\r\n <mt-text-field\r\n [ngModel]=\"getScalarValue()\"\r\n (ngModelChange)=\"updateScalar($event)\"\r\n [placeholder]=\"\r\n ('components.table.select' | transloco) +\r\n ' ' +\r\n (column().filterConfig?.label || column().label)\r\n \"\r\n />\r\n }\r\n @case (\"select\") {\r\n @if (isMultiple()) {\r\n <mt-multi-select-field\r\n [ngModel]=\"multiValue()\"\r\n (ngModelChange)=\"updateScalar($event)\"\r\n [options]=\"filterOptions()\"\r\n [placeholder]=\"\r\n ('components.table.select' | transloco) +\r\n ' ' +\r\n (column().filterConfig?.label || column().label)\r\n \"\r\n [showClear]=\"true\"\r\n [filter]=\"true\"\r\n filterBy=\"label\"\r\n optionLabel=\"label\"\r\n optionValue=\"value\"\r\n />\r\n } @else {\r\n <mt-select-field\r\n [ngModel]=\"getScalarValue()\"\r\n (ngModelChange)=\"updateScalar($event)\"\r\n [options]=\"filterOptions()\"\r\n [placeholder]=\"\r\n ('components.table.select' | transloco) +\r\n ' ' +\r\n (column().filterConfig?.label || column().label)\r\n \"\r\n [hasPlaceholderPrefix]=\"false\"\r\n optionLabel=\"label\"\r\n optionValue=\"value\"\r\n showClear\r\n />\r\n }\r\n }\r\n @case (\"userSelect\") {\r\n @if (isMultiple()) {\r\n <mt-multi-select-field\r\n [ngModel]=\"multiValue()\"\r\n (ngModelChange)=\"updateScalar($event)\"\r\n [options]=\"filterOptions()\"\r\n [placeholder]=\"\r\n ('components.table.select' | transloco) +\r\n ' ' +\r\n (column().filterConfig?.label || column().label)\r\n \"\r\n [showClear]=\"true\"\r\n [filter]=\"true\"\r\n filterBy=\"label\"\r\n optionLabel=\"label\"\r\n optionValue=\"value\"\r\n />\r\n } @else {\r\n <mt-select-field\r\n [ngModel]=\"getScalarValue()\"\r\n (ngModelChange)=\"updateScalar($event)\"\r\n [options]=\"filterOptions()\"\r\n [placeholder]=\"\r\n ('components.table.select' | transloco) +\r\n ' ' +\r\n (column().filterConfig?.label || column().label)\r\n \"\r\n [hasPlaceholderPrefix]=\"false\"\r\n [markCurrentUser]=\"true\"\r\n optionLabel=\"label\"\r\n optionValue=\"value\"\r\n showClear\r\n />\r\n }\r\n }\r\n @case (\"date\") {\r\n <div class=\"space-y-3\">\r\n <div class=\"space-y-1\">\r\n <label\r\n class=\"block text-sm font-medium text-gray-700 dark:text-gray-300\"\r\n >\r\n {{ \"components.table.from\" | transloco }}\r\n </label>\r\n <mt-date-field\r\n [ngModel]=\"getDateRangeValue('from')\"\r\n (ngModelChange)=\"updateDate('from', $event)\"\r\n [placeholder]=\"'components.table.from' | transloco\"\r\n />\r\n </div>\r\n <div class=\"space-y-1\">\r\n <label\r\n class=\"block text-sm font-medium text-gray-700 dark:text-gray-300\"\r\n >\r\n {{ \"components.table.to\" | transloco }}\r\n </label>\r\n <mt-date-field\r\n [ngModel]=\"getDateRangeValue('to')\"\r\n (ngModelChange)=\"updateDate('to', $event)\"\r\n [placeholder]=\"'components.table.to' | transloco\"\r\n />\r\n </div>\r\n </div>\r\n }\r\n @case (\"boolean\") {\r\n <mt-select-field\r\n [ngModel]=\"getScalarValue()\"\r\n (ngModelChange)=\"updateScalar($event)\"\r\n [options]=\"booleanOptions()\"\r\n [placeholder]=\"'components.table.select' | transloco\"\r\n [hasPlaceholderPrefix]=\"false\"\r\n optionLabel=\"label\"\r\n optionValue=\"value\"\r\n showClear\r\n />\r\n }\r\n @case (\"user\") {\r\n <mt-user-search-field\r\n [ngModel]=\"getScalarValue()\"\r\n (ngModelChange)=\"updateScalar($event)\"\r\n [placeholder]=\"column().filterConfig?.label || column().label\"\r\n [apiUrl]=\"column().filterConfig?.apiUrl ?? ''\"\r\n [context]=\"column().filterConfig?.context\"\r\n />\r\n }\r\n @case (\"numberRange\") {\r\n <div class=\"space-y-3\">\r\n <div class=\"space-y-1\">\r\n <label\r\n class=\"block text-sm font-medium text-gray-700 dark:text-gray-300\"\r\n >\r\n {{ \"components.table.from\" | transloco }}\r\n </label>\r\n <mt-number-field\r\n [ngModel]=\"getNumberRangeValue('from')\"\r\n (ngModelChange)=\"updateNumber('from', $event)\"\r\n [placeholder]=\"'components.table.from' | transloco\"\r\n />\r\n </div>\r\n <div class=\"space-y-1\">\r\n <label\r\n class=\"block text-sm font-medium text-gray-700 dark:text-gray-300\"\r\n >\r\n {{ \"components.table.to\" | transloco }}\r\n </label>\r\n <mt-number-field\r\n [ngModel]=\"getNumberRangeValue('to')\"\r\n (ngModelChange)=\"updateNumber('to', $event)\"\r\n [placeholder]=\"'components.table.to' | transloco\"\r\n />\r\n </div>\r\n </div>\r\n }\r\n}\r\n" }]
849
+ ], changeDetection: ChangeDetectionStrategy.OnPush, template: "@switch (getFilterType()) {\r\n @case (\"text\") {\r\n <mt-text-field\r\n [ngModel]=\"getScalarValue()\"\r\n (ngModelChange)=\"updateScalar($event)\"\r\n [placeholder]=\"\r\n ('components.table.select' | transloco) +\r\n ' ' +\r\n (column().filterConfig?.label || column().label)\r\n \"\r\n />\r\n }\r\n @case (\"select\") {\r\n @if (isMultiple()) {\r\n <mt-multi-select-field\r\n [ngModel]=\"multiValue()\"\r\n (ngModelChange)=\"updateScalar($event)\"\r\n [options]=\"filterOptions()\"\r\n [placeholder]=\"\r\n ('components.table.select' | transloco) +\r\n ' ' +\r\n (column().filterConfig?.label || column().label)\r\n \"\r\n [showClear]=\"true\"\r\n [filter]=\"true\"\r\n filterBy=\"label\"\r\n optionLabel=\"label\"\r\n optionValue=\"value\"\r\n />\r\n } @else {\r\n <mt-select-field\r\n [ngModel]=\"getScalarValue()\"\r\n (ngModelChange)=\"updateScalar($event)\"\r\n [options]=\"filterOptions()\"\r\n [placeholder]=\"\r\n ('components.table.select' | transloco) +\r\n ' ' +\r\n (column().filterConfig?.label || column().label)\r\n \"\r\n [hasPlaceholderPrefix]=\"false\"\r\n optionLabel=\"label\"\r\n optionValue=\"value\"\r\n showClear\r\n />\r\n }\r\n }\r\n @case (\"userSelect\") {\r\n @if (isMultiple()) {\r\n <mt-multi-select-field\r\n [ngModel]=\"multiValue()\"\r\n (ngModelChange)=\"updateScalar($event)\"\r\n [options]=\"filterOptions()\"\r\n [placeholder]=\"\r\n ('components.table.select' | transloco) +\r\n ' ' +\r\n (column().filterConfig?.label || column().label)\r\n \"\r\n [showClear]=\"true\"\r\n [filter]=\"true\"\r\n filterBy=\"label\"\r\n optionLabel=\"label\"\r\n optionValue=\"value\"\r\n />\r\n } @else {\r\n <mt-select-field\r\n [ngModel]=\"getScalarValue()\"\r\n (ngModelChange)=\"updateScalar($event)\"\r\n [options]=\"filterOptions()\"\r\n [placeholder]=\"\r\n ('components.table.select' | transloco) +\r\n ' ' +\r\n (column().filterConfig?.label || column().label)\r\n \"\r\n [hasPlaceholderPrefix]=\"false\"\r\n [markCurrentUser]=\"true\"\r\n optionLabel=\"label\"\r\n optionValue=\"value\"\r\n showClear\r\n />\r\n }\r\n }\r\n @case (\"treeSelect\") {\r\n <mt-treeselect-field\r\n [ngModel]=\"value()\"\r\n (ngModelChange)=\"updateScalar($event)\"\r\n [options]=\"treeOptions()\"\r\n [placeholder]=\"getTreePlaceholder()\"\r\n [selectionMode]=\"$any(column().filterConfig)?.selectionMode || 'single'\"\r\n [scrollHeight]=\"getTreeScrollHeight()\"\r\n [panelStyleClass]=\"getTreePanelStyleClass()\"\r\n [filter]=\"column().filterConfig?.['filter'] !== false\"\r\n [filterBy]=\"getTreeFilterBy()\"\r\n [filterPlaceholder]=\"getTreeFilterPlaceholder()\"\r\n [showClear]=\"column().filterConfig?.['showClear'] !== false\"\r\n [resetFilterOnHide]=\"\r\n column().filterConfig?.['resetFilterOnHide'] !== false\r\n \"\r\n [overlayOptions]=\"$any(column().filterConfig)?.overlayOptions\"\r\n />\r\n }\r\n @case (\"date\") {\r\n <div class=\"space-y-3\">\r\n <div class=\"space-y-1\">\r\n <label\r\n class=\"block text-sm font-medium text-gray-700 dark:text-gray-300\"\r\n >\r\n {{ \"components.table.from\" | transloco }}\r\n </label>\r\n <mt-date-field\r\n [ngModel]=\"getDateRangeValue('from')\"\r\n (ngModelChange)=\"updateDate('from', $event)\"\r\n [placeholder]=\"'components.table.from' | transloco\"\r\n />\r\n </div>\r\n <div class=\"space-y-1\">\r\n <label\r\n class=\"block text-sm font-medium text-gray-700 dark:text-gray-300\"\r\n >\r\n {{ \"components.table.to\" | transloco }}\r\n </label>\r\n <mt-date-field\r\n [ngModel]=\"getDateRangeValue('to')\"\r\n (ngModelChange)=\"updateDate('to', $event)\"\r\n [placeholder]=\"'components.table.to' | transloco\"\r\n />\r\n </div>\r\n </div>\r\n }\r\n @case (\"boolean\") {\r\n <mt-select-field\r\n [ngModel]=\"getScalarValue()\"\r\n (ngModelChange)=\"updateScalar($event)\"\r\n [options]=\"booleanOptions()\"\r\n [placeholder]=\"'components.table.select' | transloco\"\r\n [hasPlaceholderPrefix]=\"false\"\r\n optionLabel=\"label\"\r\n optionValue=\"value\"\r\n showClear\r\n />\r\n }\r\n @case (\"user\") {\r\n <mt-user-search-field\r\n [ngModel]=\"getScalarValue()\"\r\n (ngModelChange)=\"updateScalar($event)\"\r\n [placeholder]=\"column().filterConfig?.label || column().label\"\r\n [apiUrl]=\"column().filterConfig?.apiUrl ?? ''\"\r\n [context]=\"column().filterConfig?.context\"\r\n />\r\n }\r\n @case (\"numberRange\") {\r\n <div class=\"space-y-3\">\r\n <div class=\"space-y-1\">\r\n <label\r\n class=\"block text-sm font-medium text-gray-700 dark:text-gray-300\"\r\n >\r\n {{ \"components.table.from\" | transloco }}\r\n </label>\r\n <mt-number-field\r\n [ngModel]=\"getNumberRangeValue('from')\"\r\n (ngModelChange)=\"updateNumber('from', $event)\"\r\n [placeholder]=\"'components.table.from' | transloco\"\r\n />\r\n </div>\r\n <div class=\"space-y-1\">\r\n <label\r\n class=\"block text-sm font-medium text-gray-700 dark:text-gray-300\"\r\n >\r\n {{ \"components.table.to\" | transloco }}\r\n </label>\r\n <mt-number-field\r\n [ngModel]=\"getNumberRangeValue('to')\"\r\n (ngModelChange)=\"updateNumber('to', $event)\"\r\n [placeholder]=\"'components.table.to' | transloco\"\r\n />\r\n </div>\r\n </div>\r\n }\r\n}\r\n" }]
775
850
  }], propDecorators: { column: [{ type: i0.Input, args: [{ isSignal: true, alias: "column", required: true }] }], value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }] } });
776
851
 
777
- const OVERLAY_SELECTOR$1 = '.p-popover, .p-select-overlay, .p-multiselect-overlay, .p-datepicker-panel, .p-autocomplete-panel';
852
+ const OVERLAY_SELECTOR$1 = '.p-popover, .p-select-overlay, .p-multiselect-overlay, .p-treeselect-overlay, .p-datepicker-panel, .p-autocomplete-overlay';
853
+ // Field overlays only (no popover). A select/multiselect/autocomplete/datepicker
854
+ // opened inside the popover anchors its own scroll-to-close listener to the
855
+ // popover's inner scroll container, so a page-level scroll never reaches it.
856
+ const FIELD_OVERLAY_SELECTOR = '.p-select-overlay, .p-multiselect-overlay, .p-treeselect-overlay, .p-datepicker-panel, .p-autocomplete-overlay';
778
857
  class TableFilter {
779
858
  columns = input.required(...(ngDevMode ? [{ debugName: "columns" }] : /* istanbul ignore next */ []));
780
859
  data = input([], ...(ngDevMode ? [{ debugName: "data" }] : /* istanbul ignore next */ []));
@@ -799,6 +878,13 @@ class TableFilter {
799
878
  if (target instanceof Element && target.closest(OVERLAY_SELECTOR$1)) {
800
879
  return;
801
880
  }
881
+ // An open field dropdown is body-appended and would be left orphaned when
882
+ // we hide the popover below (its scroll listener is bound to the popover's
883
+ // inner scroll container, not the window). A window resize makes PrimeNG
884
+ // self-close those overlays before the popover goes away.
885
+ if (document.querySelector(FIELD_OVERLAY_SELECTOR)) {
886
+ window.dispatchEvent(new Event('resize'));
887
+ }
802
888
  popover.hide();
803
889
  };
804
890
  window.addEventListener('scroll', onScroll, true);
@@ -948,7 +1034,7 @@ class TableCaption {
948
1034
  this.onTabChange.emit(tab);
949
1035
  }
950
1036
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: TableCaption, deps: [], target: i0.ɵɵFactoryTarget.Component });
951
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.8", type: TableCaption, isStandalone: true, selector: "mt-table-caption", inputs: { generalSearch: { classPropertyName: "generalSearch", publicName: "generalSearch", isSignal: true, isRequired: false, transformFunction: null }, showFilters: { classPropertyName: "showFilters", publicName: "showFilters", isSignal: true, isRequired: false, transformFunction: null }, filterMode: { classPropertyName: "filterMode", publicName: "filterMode", isSignal: true, isRequired: false, transformFunction: null }, exportable: { classPropertyName: "exportable", publicName: "exportable", isSignal: true, isRequired: false, transformFunction: null }, printable: { classPropertyName: "printable", publicName: "printable", isSignal: true, isRequired: false, transformFunction: null }, groupable: { classPropertyName: "groupable", publicName: "groupable", isSignal: true, isRequired: false, transformFunction: null }, columns: { classPropertyName: "columns", publicName: "columns", isSignal: true, isRequired: false, transformFunction: null }, data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: false, transformFunction: null }, groupColumns: { classPropertyName: "groupColumns", publicName: "groupColumns", isSignal: true, isRequired: false, transformFunction: null }, tabs: { classPropertyName: "tabs", publicName: "tabs", isSignal: true, isRequired: false, transformFunction: null }, tabsOptionLabel: { classPropertyName: "tabsOptionLabel", publicName: "tabsOptionLabel", isSignal: true, isRequired: false, transformFunction: null }, tabsOptionValue: { classPropertyName: "tabsOptionValue", publicName: "tabsOptionValue", isSignal: true, isRequired: false, transformFunction: null }, actions: { classPropertyName: "actions", publicName: "actions", isSignal: true, isRequired: false, transformFunction: null }, captionStart: { classPropertyName: "captionStart", publicName: "captionStart", isSignal: true, isRequired: false, transformFunction: null }, captionEnd: { classPropertyName: "captionEnd", publicName: "captionEnd", isSignal: true, isRequired: false, transformFunction: null }, activeTab: { classPropertyName: "activeTab", publicName: "activeTab", isSignal: true, isRequired: false, transformFunction: null }, filters: { classPropertyName: "filters", publicName: "filters", isSignal: true, isRequired: false, transformFunction: null }, filterTerm: { classPropertyName: "filterTerm", publicName: "filterTerm", isSignal: true, isRequired: false, transformFunction: null }, groupBy: { classPropertyName: "groupBy", publicName: "groupBy", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { activeTab: "activeTabChange", filters: "filtersChange", filterTerm: "filterTermChange", groupBy: "groupByChange", exportRequested: "exportRequested", printRequested: "printRequested", onTabChange: "onTabChange", searchChange: "searchChange", filterApplied: "filterApplied", filterReset: "filterReset" }, ngImport: i0, template: "@if (showsAnything()) {\r\n <div class=\"mt-table-caption\">\r\n <div\r\n class=\"flex relative items-center gap-2 pb-4\"\r\n [class]=\"!generalSearch() ? 'justify-end' : 'justify-between'\"\r\n >\r\n <div class=\"flex items-center gap-2\">\r\n @if (captionStart(); as tpl) {\r\n <ng-container *ngTemplateOutlet=\"tpl\"></ng-container>\r\n }\r\n @if (tabs()) {\r\n <mt-tabs\r\n [(active)]=\"activeTab\"\r\n [options]=\"tabs()\"\r\n [optionLabel]=\"tabsOptionLabel()\"\r\n [optionValue]=\"tabsOptionValue()\"\r\n (onChange)=\"tabChanged($event)\"\r\n size=\"large\"\r\n ></mt-tabs>\r\n }\r\n @if (generalSearch()) {\r\n <mt-text-field\r\n [ngModel]=\"filterTerm()\"\r\n (ngModelChange)=\"onSearch($event)\"\r\n icon=\"general.search-lg\"\r\n [placeholder]=\"'components.table.search' | transloco\"\r\n ></mt-text-field>\r\n }\r\n </div>\r\n <div class=\"flex items-center gap-2\">\r\n @if (showFilters() && filterMode() === \"popover\") {\r\n <mt-table-filter\r\n [columns]=\"columns()\"\r\n [data]=\"data()\"\r\n [ngModel]=\"filters()\"\r\n (filterApplied)=\"onFilterApplied($event)\"\r\n (filterReset)=\"onFilterReset()\"\r\n />\r\n }\r\n @if (exportable() || printable() || groupable()) {\r\n <mt-table-actions-menu\r\n [exportable]=\"exportable()\"\r\n [printable]=\"printable()\"\r\n [groupable]=\"groupable()\"\r\n [groupColumns]=\"groupColumns()\"\r\n [activeGroup]=\"groupBy()\"\r\n (exportRequested)=\"exportRequested.emit()\"\r\n (printRequested)=\"printRequested.emit()\"\r\n (groupChange)=\"onGroupChange($event)\"\r\n />\r\n }\r\n @if (actions().length > 0) {\r\n <div class=\"flex items-center space-x-2\">\r\n @for (action of actions(); track action.label) {\r\n <mt-button\r\n [icon]=\"action.icon\"\r\n [severity]=\"action.color\"\r\n [variant]=\"action.variant\"\r\n [size]=\"$any(action).size || 'small'\"\r\n (click)=\"action.action(null)\"\r\n [label]=\"action.label\"\r\n [tooltip]=\"action.tooltip\"\r\n ></mt-button>\r\n }\r\n </div>\r\n }\r\n @if (captionEnd(); as tpl) {\r\n <ng-container *ngTemplateOutlet=\"tpl\"></ng-container>\r\n }\r\n </div>\r\n </div>\r\n </div>\r\n}\r\n", dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: TranslocoModule }, { kind: "component", type: Button, selector: "mt-button", inputs: ["icon", "label", "tooltip", "class", "type", "styleClass", "severity", "badge", "variant", "badgeSeverity", "size", "iconPos", "autofocus", "fluid", "raised", "rounded", "text", "plain", "outlined", "link", "disabled", "loading", "pInputs"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "component", type: Tabs, selector: "mt-tabs", inputs: ["options", "optionLabel", "optionValue", "active", "mode", "moreLabel", "defaultIcon", "size", "fluid", "disabled", "searchThreshold"], outputs: ["activeChange", "onChange"] }, { kind: "component", type: TextField, selector: "mt-text-field", inputs: ["field", "hint", "label", "placeholder", "class", "type", "readonly", "pInputs", "required", "icon", "iconPosition"] }, { kind: "component", type: TableFilter, selector: "mt-table-filter", inputs: ["columns", "data"], outputs: ["filterApplied", "filterReset"] }, { kind: "component", type: TableActionsMenu, selector: "mt-table-actions-menu", inputs: ["exportable", "printable", "groupable", "groupColumns", "activeGroup"], outputs: ["exportRequested", "printRequested", "groupChange"] }, { kind: "pipe", type: i2.TranslocoPipe, name: "transloco" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1037
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.8", type: TableCaption, isStandalone: true, selector: "mt-table-caption", inputs: { generalSearch: { classPropertyName: "generalSearch", publicName: "generalSearch", isSignal: true, isRequired: false, transformFunction: null }, showFilters: { classPropertyName: "showFilters", publicName: "showFilters", isSignal: true, isRequired: false, transformFunction: null }, filterMode: { classPropertyName: "filterMode", publicName: "filterMode", isSignal: true, isRequired: false, transformFunction: null }, exportable: { classPropertyName: "exportable", publicName: "exportable", isSignal: true, isRequired: false, transformFunction: null }, printable: { classPropertyName: "printable", publicName: "printable", isSignal: true, isRequired: false, transformFunction: null }, groupable: { classPropertyName: "groupable", publicName: "groupable", isSignal: true, isRequired: false, transformFunction: null }, columns: { classPropertyName: "columns", publicName: "columns", isSignal: true, isRequired: false, transformFunction: null }, data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: false, transformFunction: null }, groupColumns: { classPropertyName: "groupColumns", publicName: "groupColumns", isSignal: true, isRequired: false, transformFunction: null }, tabs: { classPropertyName: "tabs", publicName: "tabs", isSignal: true, isRequired: false, transformFunction: null }, tabsOptionLabel: { classPropertyName: "tabsOptionLabel", publicName: "tabsOptionLabel", isSignal: true, isRequired: false, transformFunction: null }, tabsOptionValue: { classPropertyName: "tabsOptionValue", publicName: "tabsOptionValue", isSignal: true, isRequired: false, transformFunction: null }, actions: { classPropertyName: "actions", publicName: "actions", isSignal: true, isRequired: false, transformFunction: null }, captionStart: { classPropertyName: "captionStart", publicName: "captionStart", isSignal: true, isRequired: false, transformFunction: null }, captionEnd: { classPropertyName: "captionEnd", publicName: "captionEnd", isSignal: true, isRequired: false, transformFunction: null }, activeTab: { classPropertyName: "activeTab", publicName: "activeTab", isSignal: true, isRequired: false, transformFunction: null }, filters: { classPropertyName: "filters", publicName: "filters", isSignal: true, isRequired: false, transformFunction: null }, filterTerm: { classPropertyName: "filterTerm", publicName: "filterTerm", isSignal: true, isRequired: false, transformFunction: null }, groupBy: { classPropertyName: "groupBy", publicName: "groupBy", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { activeTab: "activeTabChange", filters: "filtersChange", filterTerm: "filterTermChange", groupBy: "groupByChange", exportRequested: "exportRequested", printRequested: "printRequested", onTabChange: "onTabChange", searchChange: "searchChange", filterApplied: "filterApplied", filterReset: "filterReset" }, ngImport: i0, template: "@if (showsAnything()) {\r\n <div class=\"mt-table-caption\">\r\n <div\r\n class=\"flex relative items-center gap-2 pb-4\"\r\n [class]=\"!generalSearch() ? 'justify-end' : 'justify-between'\"\r\n >\r\n <div class=\"flex items-center gap-2\">\r\n @if (captionStart(); as tpl) {\r\n <ng-container *ngTemplateOutlet=\"tpl\"></ng-container>\r\n }\r\n @if (tabs()) {\r\n <mt-tabs\r\n [(active)]=\"activeTab\"\r\n [options]=\"tabs()\"\r\n [optionLabel]=\"tabsOptionLabel()\"\r\n [optionValue]=\"tabsOptionValue()\"\r\n (onChange)=\"tabChanged($event)\"\r\n size=\"large\"\r\n ></mt-tabs>\r\n }\r\n @if (generalSearch()) {\r\n <mt-text-field\r\n [ngModel]=\"filterTerm()\"\r\n (ngModelChange)=\"onSearch($event)\"\r\n icon=\"general.search-lg\"\r\n [placeholder]=\"'components.table.search' | transloco\"\r\n ></mt-text-field>\r\n }\r\n </div>\r\n <div class=\"flex items-center gap-2\">\r\n @if (showFilters() && filterMode() === \"popover\") {\r\n <mt-table-filter\r\n [columns]=\"columns()\"\r\n [data]=\"data()\"\r\n [ngModel]=\"filters()\"\r\n (filterApplied)=\"onFilterApplied($event)\"\r\n (filterReset)=\"onFilterReset()\"\r\n />\r\n }\r\n @if (exportable() || printable() || groupable()) {\r\n <mt-table-actions-menu\r\n [exportable]=\"exportable()\"\r\n [printable]=\"printable()\"\r\n [groupable]=\"groupable()\"\r\n [groupColumns]=\"groupColumns()\"\r\n [activeGroup]=\"groupBy()\"\r\n (exportRequested)=\"exportRequested.emit()\"\r\n (printRequested)=\"printRequested.emit()\"\r\n (groupChange)=\"onGroupChange($event)\"\r\n />\r\n }\r\n @if (actions().length > 0) {\r\n <div class=\"flex items-center space-x-2\">\r\n @for (action of actions(); track action.label) {\r\n <mt-button\r\n [icon]=\"action.icon\"\r\n [severity]=\"action.color\"\r\n [variant]=\"action.variant\"\r\n [size]=\"$any(action).size || 'small'\"\r\n (click)=\"action.action(null)\"\r\n [label]=\"action.label\"\r\n [tooltip]=\"action.tooltip\"\r\n ></mt-button>\r\n }\r\n </div>\r\n }\r\n @if (captionEnd(); as tpl) {\r\n <ng-container *ngTemplateOutlet=\"tpl\"></ng-container>\r\n }\r\n </div>\r\n </div>\r\n </div>\r\n}\r\n", dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: TranslocoModule }, { kind: "component", type: Button, selector: "mt-button", inputs: ["icon", "label", "tooltip", "class", "type", "styleClass", "severity", "badge", "variant", "badgeSeverity", "size", "iconPos", "autofocus", "fluid", "raised", "rounded", "text", "plain", "outlined", "link", "disabled", "loading", "pInputs"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "component", type: Tabs, selector: "mt-tabs", inputs: ["options", "optionLabel", "optionValue", "active", "mode", "moreLabel", "defaultIcon", "size", "fluid", "disabled", "searchThreshold"], outputs: ["activeChange", "onChange"] }, { kind: "component", type: TextField, selector: "mt-text-field", inputs: ["field", "hint", "label", "placeholder", "class", "type", "readonly", "pInputs", "required", "maxLength", "icon", "iconPosition"] }, { kind: "component", type: TableFilter, selector: "mt-table-filter", inputs: ["columns", "data"], outputs: ["filterApplied", "filterReset"] }, { kind: "component", type: TableActionsMenu, selector: "mt-table-actions-menu", inputs: ["exportable", "printable", "groupable", "groupColumns", "activeGroup"], outputs: ["exportRequested", "printRequested", "groupChange"] }, { kind: "pipe", type: i2.TranslocoPipe, name: "transloco" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
952
1038
  }
953
1039
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: TableCaption, decorators: [{
954
1040
  type: Component,
@@ -964,7 +1050,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImpor
964
1050
  ], changeDetection: ChangeDetectionStrategy.OnPush, template: "@if (showsAnything()) {\r\n <div class=\"mt-table-caption\">\r\n <div\r\n class=\"flex relative items-center gap-2 pb-4\"\r\n [class]=\"!generalSearch() ? 'justify-end' : 'justify-between'\"\r\n >\r\n <div class=\"flex items-center gap-2\">\r\n @if (captionStart(); as tpl) {\r\n <ng-container *ngTemplateOutlet=\"tpl\"></ng-container>\r\n }\r\n @if (tabs()) {\r\n <mt-tabs\r\n [(active)]=\"activeTab\"\r\n [options]=\"tabs()\"\r\n [optionLabel]=\"tabsOptionLabel()\"\r\n [optionValue]=\"tabsOptionValue()\"\r\n (onChange)=\"tabChanged($event)\"\r\n size=\"large\"\r\n ></mt-tabs>\r\n }\r\n @if (generalSearch()) {\r\n <mt-text-field\r\n [ngModel]=\"filterTerm()\"\r\n (ngModelChange)=\"onSearch($event)\"\r\n icon=\"general.search-lg\"\r\n [placeholder]=\"'components.table.search' | transloco\"\r\n ></mt-text-field>\r\n }\r\n </div>\r\n <div class=\"flex items-center gap-2\">\r\n @if (showFilters() && filterMode() === \"popover\") {\r\n <mt-table-filter\r\n [columns]=\"columns()\"\r\n [data]=\"data()\"\r\n [ngModel]=\"filters()\"\r\n (filterApplied)=\"onFilterApplied($event)\"\r\n (filterReset)=\"onFilterReset()\"\r\n />\r\n }\r\n @if (exportable() || printable() || groupable()) {\r\n <mt-table-actions-menu\r\n [exportable]=\"exportable()\"\r\n [printable]=\"printable()\"\r\n [groupable]=\"groupable()\"\r\n [groupColumns]=\"groupColumns()\"\r\n [activeGroup]=\"groupBy()\"\r\n (exportRequested)=\"exportRequested.emit()\"\r\n (printRequested)=\"printRequested.emit()\"\r\n (groupChange)=\"onGroupChange($event)\"\r\n />\r\n }\r\n @if (actions().length > 0) {\r\n <div class=\"flex items-center space-x-2\">\r\n @for (action of actions(); track action.label) {\r\n <mt-button\r\n [icon]=\"action.icon\"\r\n [severity]=\"action.color\"\r\n [variant]=\"action.variant\"\r\n [size]=\"$any(action).size || 'small'\"\r\n (click)=\"action.action(null)\"\r\n [label]=\"action.label\"\r\n [tooltip]=\"action.tooltip\"\r\n ></mt-button>\r\n }\r\n </div>\r\n }\r\n @if (captionEnd(); as tpl) {\r\n <ng-container *ngTemplateOutlet=\"tpl\"></ng-container>\r\n }\r\n </div>\r\n </div>\r\n </div>\r\n}\r\n" }]
965
1051
  }], propDecorators: { generalSearch: [{ type: i0.Input, args: [{ isSignal: true, alias: "generalSearch", required: false }] }], showFilters: [{ type: i0.Input, args: [{ isSignal: true, alias: "showFilters", required: false }] }], filterMode: [{ type: i0.Input, args: [{ isSignal: true, alias: "filterMode", required: false }] }], exportable: [{ type: i0.Input, args: [{ isSignal: true, alias: "exportable", required: false }] }], printable: [{ type: i0.Input, args: [{ isSignal: true, alias: "printable", required: false }] }], groupable: [{ type: i0.Input, args: [{ isSignal: true, alias: "groupable", required: false }] }], columns: [{ type: i0.Input, args: [{ isSignal: true, alias: "columns", required: false }] }], data: [{ type: i0.Input, args: [{ isSignal: true, alias: "data", required: false }] }], groupColumns: [{ type: i0.Input, args: [{ isSignal: true, alias: "groupColumns", required: false }] }], tabs: [{ type: i0.Input, args: [{ isSignal: true, alias: "tabs", required: false }] }], tabsOptionLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "tabsOptionLabel", required: false }] }], tabsOptionValue: [{ type: i0.Input, args: [{ isSignal: true, alias: "tabsOptionValue", required: false }] }], actions: [{ type: i0.Input, args: [{ isSignal: true, alias: "actions", required: false }] }], captionStart: [{ type: i0.Input, args: [{ isSignal: true, alias: "captionStart", required: false }] }], captionEnd: [{ type: i0.Input, args: [{ isSignal: true, alias: "captionEnd", required: false }] }], activeTab: [{ type: i0.Input, args: [{ isSignal: true, alias: "activeTab", required: false }] }, { type: i0.Output, args: ["activeTabChange"] }], filters: [{ type: i0.Input, args: [{ isSignal: true, alias: "filters", required: false }] }, { type: i0.Output, args: ["filtersChange"] }], filterTerm: [{ type: i0.Input, args: [{ isSignal: true, alias: "filterTerm", required: false }] }, { type: i0.Output, args: ["filterTermChange"] }], groupBy: [{ type: i0.Input, args: [{ isSignal: true, alias: "groupBy", required: false }] }, { type: i0.Output, args: ["groupByChange"] }], exportRequested: [{ type: i0.Output, args: ["exportRequested"] }], printRequested: [{ type: i0.Output, args: ["printRequested"] }], onTabChange: [{ type: i0.Output, args: ["onTabChange"] }], searchChange: [{ type: i0.Output, args: ["searchChange"] }], filterApplied: [{ type: i0.Output, args: ["filterApplied"] }], filterReset: [{ type: i0.Output, args: ["filterReset"] }] } });
966
1052
 
967
- const OVERLAY_SELECTOR = '.p-popover, .p-select-overlay, .p-multiselect-overlay, .p-datepicker-panel, .p-autocomplete-panel';
1053
+ const OVERLAY_SELECTOR = '.p-popover, .p-select-overlay, .p-multiselect-overlay, .p-treeselect-overlay, .p-datepicker-panel, .p-autocomplete-panel, .p-autocomplete-overlay';
968
1054
  /**
969
1055
  * Per-column filter affordance: a small funnel icon in the column header that
970
1056
  * opens a popover with a single `TableFilterField`.
@@ -1049,20 +1135,20 @@ class TableExportService {
1049
1135
  static PRINT_ROOT_CLASS = 'mt-printing';
1050
1136
  static PRINT_REGION_CLASS = 'mt-print-region';
1051
1137
  static PRINT_STYLE_ID = 'mt-table-print-style';
1052
- static PRINT_CSS = `
1053
- @media print {
1054
- html.mt-printing body > *:not(.mt-print-region) { display: none !important; }
1055
- html.mt-printing, html.mt-printing body { background: #ffffff !important; }
1056
- .mt-print-region { display: block !important; padding: 16px; color: #111827;
1057
- font-family: system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif; }
1058
- .mt-print-region h1 { font-size: 18px; font-weight: 600; margin: 0 0 12px; }
1059
- .mt-print-region table { width: 100%; border-collapse: collapse; font-size: 12px; }
1060
- .mt-print-region th, .mt-print-region td { text-align: start; padding: 6px 8px;
1061
- border: 1px solid #e5e7eb; vertical-align: top; }
1062
- .mt-print-region thead th { background: #f3f4f6; font-weight: 600; }
1063
- .mt-print-region tbody tr { break-inside: avoid; page-break-inside: avoid; }
1064
- }
1065
- .mt-print-region { display: none; }
1138
+ static PRINT_CSS = `
1139
+ @media print {
1140
+ html.mt-printing body > *:not(.mt-print-region) { display: none !important; }
1141
+ html.mt-printing, html.mt-printing body { background: #ffffff !important; }
1142
+ .mt-print-region { display: block !important; padding: 16px; color: #111827;
1143
+ font-family: system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif; }
1144
+ .mt-print-region h1 { font-size: 18px; font-weight: 600; margin: 0 0 12px; }
1145
+ .mt-print-region table { width: 100%; border-collapse: collapse; font-size: 12px; }
1146
+ .mt-print-region th, .mt-print-region td { text-align: start; padding: 6px 8px;
1147
+ border: 1px solid #e5e7eb; vertical-align: top; }
1148
+ .mt-print-region thead th { background: #f3f4f6; font-weight: 600; }
1149
+ .mt-print-region tbody tr { break-inside: avoid; page-break-inside: avoid; }
1150
+ }
1151
+ .mt-print-region { display: none; }
1066
1152
  `;
1067
1153
  exportToExcel(config) {
1068
1154
  const columns = this.getExportableColumns(config.columns);
@@ -1098,7 +1184,7 @@ class TableExportService {
1098
1184
  document.head.appendChild(style);
1099
1185
  }
1100
1186
  getExportableColumns(columns) {
1101
- return columns.filter((column) => column.type !== 'custom');
1187
+ return columns.filter((column) => !column.filterOnly && column.type !== 'custom');
1102
1188
  }
1103
1189
  /**
1104
1190
  * Produces rows keyed by column label (Excel header row).
@@ -1202,6 +1288,8 @@ class TableGroupingController {
1202
1288
  groupableColumns = computed(() => {
1203
1289
  const sampleRow = this.rows()[0];
1204
1290
  return this.columns().filter((col) => {
1291
+ if (col.filterOnly)
1292
+ return false;
1205
1293
  if (col.type === 'custom')
1206
1294
  return false;
1207
1295
  const filterType = TableValueResolver.getColumnFilterType(col, sampleRow);
@@ -1463,7 +1551,7 @@ class Table {
1463
1551
  return applyLocalSort ? this.sortData(result) : result;
1464
1552
  }, ...(ngDevMode ? [{ debugName: "filteredData" }] : /* istanbul ignore next */ []));
1465
1553
  renderedColumns = computed(() => {
1466
- const columns = this.columns();
1554
+ const columns = this.columns().filter((column) => !column.filterOnly);
1467
1555
  if (columns.length > 0 || !this.loading()) {
1468
1556
  return columns;
1469
1557
  }