@masterteam/components 0.0.172 → 0.0.173

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.
@@ -1,5 +1,5 @@
1
1
  import * as i0 from '@angular/core';
2
- import { input, booleanAttribute, output, viewChild, computed, ChangeDetectionStrategy, Component, model, inject, signal, forwardRef, Injectable, contentChild, effect } from '@angular/core';
2
+ import { input, booleanAttribute, output, viewChild, computed, ChangeDetectionStrategy, Component, model, inject, signal, DestroyRef, forwardRef, Injectable, contentChild, effect } from '@angular/core';
3
3
  import { NgTemplateOutlet } from '@angular/common';
4
4
  import { Card } from '@masterteam/components/card';
5
5
  import * as i1$1 from '@angular/forms';
@@ -774,19 +774,46 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImpor
774
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" }]
775
775
  }], 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
776
 
777
+ const OVERLAY_SELECTOR$1 = '.p-popover, .p-select-overlay, .p-multiselect-overlay, .p-datepicker-panel, .p-autocomplete-panel';
777
778
  class TableFilter {
778
779
  columns = input.required(...(ngDevMode ? [{ debugName: "columns" }] : /* istanbul ignore next */ []));
779
780
  data = input([], ...(ngDevMode ? [{ debugName: "data" }] : /* istanbul ignore next */ []));
780
781
  filterApplied = output();
781
782
  filterReset = output();
783
+ popoverRef = viewChild('popover', ...(ngDevMode ? [{ debugName: "popoverRef" }] : /* istanbul ignore next */ []));
782
784
  pendingFilters = signal({}, ...(ngDevMode ? [{ debugName: "pendingFilters" }] : /* istanbul ignore next */ []));
783
785
  appliedFilters = signal({}, ...(ngDevMode ? [{ debugName: "appliedFilters" }] : /* istanbul ignore next */ []));
784
786
  onChange = () => { };
785
787
  onTouched = () => { };
788
+ constructor() {
789
+ // Body-appended overlays (multi-select, datepicker, etc.) inside the
790
+ // popover don't get a scroll signal when the page's inner scroll
791
+ // container moves under them. Listening on window in capture phase
792
+ // catches scroll on any container; we close the popover when the
793
+ // scroll happens outside the popover or any open dropdown overlay.
794
+ const onScroll = (event) => {
795
+ const popover = this.popoverRef();
796
+ if (!popover?.container)
797
+ return;
798
+ const target = event.target;
799
+ if (target instanceof Element && target.closest(OVERLAY_SELECTOR$1)) {
800
+ return;
801
+ }
802
+ popover.hide();
803
+ };
804
+ window.addEventListener('scroll', onScroll, true);
805
+ inject(DestroyRef).onDestroy(() => {
806
+ window.removeEventListener('scroll', onScroll, true);
807
+ });
808
+ }
786
809
  filterableColumns = computed(() => this.columns()
787
810
  .filter((col) => TableValueResolver.getColumnFilterType(col, this.data()[0]) !== null)
788
811
  .map((col) => TableValueResolver.buildFilterableColumn(col, this.data())), ...(ngDevMode ? [{ debugName: "filterableColumns" }] : /* istanbul ignore next */ []));
789
- activeFilterCount = computed(() => Object.values(this.appliedFilters()).filter((value) => TableValueResolver.hasFilterValue(value)).length, ...(ngDevMode ? [{ debugName: "activeFilterCount" }] : /* istanbul ignore next */ []));
812
+ activeFilterCount = computed(() => Object.entries(this.appliedFilters()).filter(([key, value]) =>
813
+ // `generalSearch` is the table's global search term, not a column
814
+ // filter — it's injected into the filters map for lazy fetches but
815
+ // must not light up the filter button's active badge.
816
+ key !== 'generalSearch' && TableValueResolver.hasFilterValue(value)).length, ...(ngDevMode ? [{ debugName: "activeFilterCount" }] : /* istanbul ignore next */ []));
790
817
  updateFilter(key, value) {
791
818
  this.pendingFilters.update((filters) => ({
792
819
  ...filters,
@@ -825,7 +852,7 @@ class TableFilter {
825
852
  useExisting: forwardRef(() => TableFilter),
826
853
  multi: true,
827
854
  },
828
- ], ngImport: i0, template: "<mt-button\n (click)=\"popover.toggle($event)\"\n [label]=\"'components.table.filter' | transloco\"\n [badge]=\"activeFilterCount()\"\n severity=\"primary\"\n size=\"small\"\n icon=\"general.filter-funnel-01\"\n/>\n\n<p-popover #popover [style]=\"{ width: '320px' }\" appendTo=\"body\">\n <div class=\"flex flex-col max-h-[50vh]\">\n <h4\n class=\"text-lg py-2 font-semibold border-b border-surface-200 dark:border-surface-700 shrink-0\"\n >\n {{ \"components.table.filterOptions\" | transloco }}\n </h4>\n\n <div\n class=\"space-y-3 overflow-y-auto flex-1 py-3\"\n (keydown.enter)=\"apply(); popover.hide()\"\n >\n @for (col of filterableColumns(); track col.key) {\n <div class=\"space-y-1\">\n <label\n class=\"block text-sm font-medium text-gray-700 dark:text-gray-300\"\n >\n {{ col.filterConfig?.label || col.label }}\n </label>\n <mt-table-filter-field\n [column]=\"col\"\n [value]=\"pendingFilters()[col.key]\"\n (valueChange)=\"updateFilter(col.key, $event)\"\n />\n </div>\n }\n </div>\n\n <div\n class=\"flex justify-end gap-2 pt-4 border-t border-surface-200 dark:border-surface-700 shrink-0\"\n >\n <mt-button\n variant=\"outlined\"\n (click)=\"reset(); popover.hide()\"\n [label]=\"'components.table.reset' | transloco\"\n />\n <mt-button\n (click)=\"apply(); popover.hide()\"\n [label]=\"'components.table.apply' | transloco\"\n />\n </div>\n </div>\n</p-popover>\n", dependencies: [{ kind: "ngmodule", type: FormsModule }, { 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: "ngmodule", type: PopoverModule }, { kind: "component", type: i1$2.Popover, selector: "p-popover", inputs: ["ariaLabel", "ariaLabelledBy", "dismissable", "style", "styleClass", "appendTo", "autoZIndex", "ariaCloseLabel", "baseZIndex", "focusOnShow", "showTransitionOptions", "hideTransitionOptions", "motionOptions"], outputs: ["onShow", "onHide"] }, { kind: "ngmodule", type: TranslocoModule }, { kind: "component", type: TableFilterField, selector: "mt-table-filter-field", inputs: ["column", "value"], outputs: ["valueChange"] }, { kind: "pipe", type: i2.TranslocoPipe, name: "transloco" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
855
+ ], viewQueries: [{ propertyName: "popoverRef", first: true, predicate: ["popover"], descendants: true, isSignal: true }], ngImport: i0, template: "<mt-button\n (click)=\"popover.toggle($event)\"\n [label]=\"'components.table.filter' | transloco\"\n [badge]=\"activeFilterCount()\"\n severity=\"primary\"\n size=\"small\"\n icon=\"general.filter-funnel-01\"\n/>\n\n<p-popover #popover [style]=\"{ width: '320px' }\" appendTo=\"body\">\n <div class=\"flex flex-col max-h-[50vh]\">\n <h4\n class=\"text-lg py-2 font-semibold border-b border-surface-200 dark:border-surface-700 shrink-0\"\n >\n {{ \"components.table.filterOptions\" | transloco }}\n </h4>\n\n <div\n class=\"space-y-3 overflow-y-auto flex-1 py-3\"\n (keydown.enter)=\"apply(); popover.hide()\"\n >\n @for (col of filterableColumns(); track col.key) {\n <div class=\"space-y-1\">\n <label\n class=\"block text-sm font-medium text-gray-700 dark:text-gray-300\"\n >\n {{ col.filterConfig?.label || col.label }}\n </label>\n <mt-table-filter-field\n [column]=\"col\"\n [value]=\"pendingFilters()[col.key]\"\n (valueChange)=\"updateFilter(col.key, $event)\"\n />\n </div>\n }\n </div>\n\n <div\n class=\"flex justify-end gap-2 pt-4 border-t border-surface-200 dark:border-surface-700 shrink-0\"\n >\n <mt-button\n variant=\"outlined\"\n (click)=\"reset(); popover.hide()\"\n [label]=\"'components.table.reset' | transloco\"\n />\n <mt-button\n (click)=\"apply(); popover.hide()\"\n [label]=\"'components.table.apply' | transloco\"\n />\n </div>\n </div>\n</p-popover>\n", dependencies: [{ kind: "ngmodule", type: FormsModule }, { 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: "ngmodule", type: PopoverModule }, { kind: "component", type: i1$2.Popover, selector: "p-popover", inputs: ["ariaLabel", "ariaLabelledBy", "dismissable", "style", "styleClass", "appendTo", "autoZIndex", "ariaCloseLabel", "baseZIndex", "focusOnShow", "showTransitionOptions", "hideTransitionOptions", "motionOptions"], outputs: ["onShow", "onHide"] }, { kind: "ngmodule", type: TranslocoModule }, { kind: "component", type: TableFilterField, selector: "mt-table-filter-field", inputs: ["column", "value"], outputs: ["valueChange"] }, { kind: "pipe", type: i2.TranslocoPipe, name: "transloco" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
829
856
  }
830
857
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: TableFilter, decorators: [{
831
858
  type: Component,
@@ -842,7 +869,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImpor
842
869
  multi: true,
843
870
  },
844
871
  ], template: "<mt-button\n (click)=\"popover.toggle($event)\"\n [label]=\"'components.table.filter' | transloco\"\n [badge]=\"activeFilterCount()\"\n severity=\"primary\"\n size=\"small\"\n icon=\"general.filter-funnel-01\"\n/>\n\n<p-popover #popover [style]=\"{ width: '320px' }\" appendTo=\"body\">\n <div class=\"flex flex-col max-h-[50vh]\">\n <h4\n class=\"text-lg py-2 font-semibold border-b border-surface-200 dark:border-surface-700 shrink-0\"\n >\n {{ \"components.table.filterOptions\" | transloco }}\n </h4>\n\n <div\n class=\"space-y-3 overflow-y-auto flex-1 py-3\"\n (keydown.enter)=\"apply(); popover.hide()\"\n >\n @for (col of filterableColumns(); track col.key) {\n <div class=\"space-y-1\">\n <label\n class=\"block text-sm font-medium text-gray-700 dark:text-gray-300\"\n >\n {{ col.filterConfig?.label || col.label }}\n </label>\n <mt-table-filter-field\n [column]=\"col\"\n [value]=\"pendingFilters()[col.key]\"\n (valueChange)=\"updateFilter(col.key, $event)\"\n />\n </div>\n }\n </div>\n\n <div\n class=\"flex justify-end gap-2 pt-4 border-t border-surface-200 dark:border-surface-700 shrink-0\"\n >\n <mt-button\n variant=\"outlined\"\n (click)=\"reset(); popover.hide()\"\n [label]=\"'components.table.reset' | transloco\"\n />\n <mt-button\n (click)=\"apply(); popover.hide()\"\n [label]=\"'components.table.apply' | transloco\"\n />\n </div>\n </div>\n</p-popover>\n" }]
845
- }], propDecorators: { columns: [{ type: i0.Input, args: [{ isSignal: true, alias: "columns", required: true }] }], data: [{ type: i0.Input, args: [{ isSignal: true, alias: "data", required: false }] }], filterApplied: [{ type: i0.Output, args: ["filterApplied"] }], filterReset: [{ type: i0.Output, args: ["filterReset"] }] } });
872
+ }], ctorParameters: () => [], propDecorators: { columns: [{ type: i0.Input, args: [{ isSignal: true, alias: "columns", required: true }] }], data: [{ type: i0.Input, args: [{ isSignal: true, alias: "data", required: false }] }], filterApplied: [{ type: i0.Output, args: ["filterApplied"] }], filterReset: [{ type: i0.Output, args: ["filterReset"] }], popoverRef: [{ type: i0.ViewChild, args: ['popover', { isSignal: true }] }] } });
846
873
 
847
874
  /**
848
875
  * Stateless, controlled toolbar used by `mt-table` and by list-style consumers
@@ -937,6 +964,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImpor
937
964
  ], 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" }]
938
965
  }], 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"] }] } });
939
966
 
967
+ const OVERLAY_SELECTOR = '.p-popover, .p-select-overlay, .p-multiselect-overlay, .p-datepicker-panel, .p-autocomplete-panel';
940
968
  /**
941
969
  * Per-column filter affordance: a small funnel icon in the column header that
942
970
  * opens a popover with a single `TableFilterField`.
@@ -951,6 +979,26 @@ class TableColumnFilter {
951
979
  filterChange = output();
952
980
  pendingValue = signal(null, ...(ngDevMode ? [{ debugName: "pendingValue" }] : /* istanbul ignore next */ []));
953
981
  hasActiveValue = computed(() => TableValueResolver.hasFilterValue(this.value()), ...(ngDevMode ? [{ debugName: "hasActiveValue" }] : /* istanbul ignore next */ []));
982
+ popoverRef = viewChild('popover', ...(ngDevMode ? [{ debugName: "popoverRef" }] : /* istanbul ignore next */ []));
983
+ constructor() {
984
+ // See TableFilter: body-appended child overlays don't dismiss on inner
985
+ // container scroll. Close the popover when the scroll happens outside
986
+ // the popover or any open dropdown overlay.
987
+ const onScroll = (event) => {
988
+ const popover = this.popoverRef();
989
+ if (!popover?.container)
990
+ return;
991
+ const target = event.target;
992
+ if (target instanceof Element && target.closest(OVERLAY_SELECTOR)) {
993
+ return;
994
+ }
995
+ popover.hide();
996
+ };
997
+ window.addEventListener('scroll', onScroll, true);
998
+ inject(DestroyRef).onDestroy(() => {
999
+ window.removeEventListener('scroll', onScroll, true);
1000
+ });
1001
+ }
954
1002
  open(popover, event) {
955
1003
  event.stopPropagation();
956
1004
  this.pendingValue.set(this.cloneValue(this.value()));
@@ -979,7 +1027,7 @@ class TableColumnFilter {
979
1027
  return value;
980
1028
  }
981
1029
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: TableColumnFilter, deps: [], target: i0.ɵɵFactoryTarget.Component });
982
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.8", type: TableColumnFilter, isStandalone: true, selector: "mt-table-column-filter", inputs: { column: { classPropertyName: "column", publicName: "column", isSignal: true, isRequired: true, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { filterChange: "filterChange" }, ngImport: i0, template: "<mt-button\r\n (onClick)=\"open(popover, $event)\"\r\n [icon]=\"\r\n hasActiveValue() ? 'general.filter-funnel-02' : 'general.filter-funnel-01'\r\n \"\r\n [severity]=\"hasActiveValue() ? 'primary' : 'secondary'\"\r\n variant=\"text\"\r\n size=\"small\"\r\n [tooltip]=\"'components.table.filter' | transloco\"\r\n styleClass=\"!p-1 !text-sm\"\r\n/>\r\n\r\n<p-popover #popover [style]=\"{ width: '280px' }\" appendTo=\"body\">\r\n <div class=\"flex flex-col gap-3\" (keydown.enter)=\"apply(popover)\">\r\n <h4\r\n class=\"text-sm font-semibold text-gray-700 dark:text-gray-300 truncate\"\r\n [title]=\"column().filterConfig?.label || column().label\"\r\n >\r\n {{ column().filterConfig?.label || column().label }}\r\n </h4>\r\n\r\n <mt-table-filter-field\r\n [column]=\"column()\"\r\n [value]=\"pendingValue()\"\r\n (valueChange)=\"pendingValue.set($event)\"\r\n />\r\n\r\n <div\r\n class=\"flex justify-end gap-2 pt-2 border-t border-surface-200 dark:border-surface-700\"\r\n >\r\n <mt-button\r\n variant=\"outlined\"\r\n size=\"small\"\r\n (onClick)=\"clear(popover)\"\r\n [label]=\"'components.table.reset' | transloco\"\r\n />\r\n <mt-button\r\n size=\"small\"\r\n (onClick)=\"apply(popover)\"\r\n [label]=\"'components.table.apply' | transloco\"\r\n />\r\n </div>\r\n </div>\r\n</p-popover>\r\n", dependencies: [{ kind: "ngmodule", type: FormsModule }, { 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: "ngmodule", type: PopoverModule }, { kind: "component", type: i1$2.Popover, selector: "p-popover", inputs: ["ariaLabel", "ariaLabelledBy", "dismissable", "style", "styleClass", "appendTo", "autoZIndex", "ariaCloseLabel", "baseZIndex", "focusOnShow", "showTransitionOptions", "hideTransitionOptions", "motionOptions"], outputs: ["onShow", "onHide"] }, { kind: "ngmodule", type: TranslocoModule }, { kind: "component", type: TableFilterField, selector: "mt-table-filter-field", inputs: ["column", "value"], outputs: ["valueChange"] }, { kind: "pipe", type: i2.TranslocoPipe, name: "transloco" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1030
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "21.2.8", type: TableColumnFilter, isStandalone: true, selector: "mt-table-column-filter", inputs: { column: { classPropertyName: "column", publicName: "column", isSignal: true, isRequired: true, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { filterChange: "filterChange" }, viewQueries: [{ propertyName: "popoverRef", first: true, predicate: ["popover"], descendants: true, isSignal: true }], ngImport: i0, template: "<mt-button\r\n (onClick)=\"open(popover, $event)\"\r\n [icon]=\"\r\n hasActiveValue() ? 'general.filter-funnel-02' : 'general.filter-funnel-01'\r\n \"\r\n [severity]=\"hasActiveValue() ? 'primary' : 'secondary'\"\r\n variant=\"text\"\r\n size=\"small\"\r\n [tooltip]=\"'components.table.filter' | transloco\"\r\n styleClass=\"!p-1 !text-sm\"\r\n/>\r\n\r\n<p-popover #popover [style]=\"{ width: '280px' }\" appendTo=\"body\">\r\n <div class=\"flex flex-col gap-3\" (keydown.enter)=\"apply(popover)\">\r\n <h4\r\n class=\"text-sm font-semibold text-gray-700 dark:text-gray-300 truncate\"\r\n [title]=\"column().filterConfig?.label || column().label\"\r\n >\r\n {{ column().filterConfig?.label || column().label }}\r\n </h4>\r\n\r\n <mt-table-filter-field\r\n [column]=\"column()\"\r\n [value]=\"pendingValue()\"\r\n (valueChange)=\"pendingValue.set($event)\"\r\n />\r\n\r\n <div\r\n class=\"flex justify-end gap-2 pt-2 border-t border-surface-200 dark:border-surface-700\"\r\n >\r\n <mt-button\r\n variant=\"outlined\"\r\n size=\"small\"\r\n (onClick)=\"clear(popover)\"\r\n [label]=\"'components.table.reset' | transloco\"\r\n />\r\n <mt-button\r\n size=\"small\"\r\n (onClick)=\"apply(popover)\"\r\n [label]=\"'components.table.apply' | transloco\"\r\n />\r\n </div>\r\n </div>\r\n</p-popover>\r\n", dependencies: [{ kind: "ngmodule", type: FormsModule }, { 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: "ngmodule", type: PopoverModule }, { kind: "component", type: i1$2.Popover, selector: "p-popover", inputs: ["ariaLabel", "ariaLabelledBy", "dismissable", "style", "styleClass", "appendTo", "autoZIndex", "ariaCloseLabel", "baseZIndex", "focusOnShow", "showTransitionOptions", "hideTransitionOptions", "motionOptions"], outputs: ["onShow", "onHide"] }, { kind: "ngmodule", type: TranslocoModule }, { kind: "component", type: TableFilterField, selector: "mt-table-filter-field", inputs: ["column", "value"], outputs: ["valueChange"] }, { kind: "pipe", type: i2.TranslocoPipe, name: "transloco" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
983
1031
  }
984
1032
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: TableColumnFilter, decorators: [{
985
1033
  type: Component,
@@ -990,7 +1038,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImpor
990
1038
  TranslocoModule,
991
1039
  TableFilterField,
992
1040
  ], changeDetection: ChangeDetectionStrategy.OnPush, template: "<mt-button\r\n (onClick)=\"open(popover, $event)\"\r\n [icon]=\"\r\n hasActiveValue() ? 'general.filter-funnel-02' : 'general.filter-funnel-01'\r\n \"\r\n [severity]=\"hasActiveValue() ? 'primary' : 'secondary'\"\r\n variant=\"text\"\r\n size=\"small\"\r\n [tooltip]=\"'components.table.filter' | transloco\"\r\n styleClass=\"!p-1 !text-sm\"\r\n/>\r\n\r\n<p-popover #popover [style]=\"{ width: '280px' }\" appendTo=\"body\">\r\n <div class=\"flex flex-col gap-3\" (keydown.enter)=\"apply(popover)\">\r\n <h4\r\n class=\"text-sm font-semibold text-gray-700 dark:text-gray-300 truncate\"\r\n [title]=\"column().filterConfig?.label || column().label\"\r\n >\r\n {{ column().filterConfig?.label || column().label }}\r\n </h4>\r\n\r\n <mt-table-filter-field\r\n [column]=\"column()\"\r\n [value]=\"pendingValue()\"\r\n (valueChange)=\"pendingValue.set($event)\"\r\n />\r\n\r\n <div\r\n class=\"flex justify-end gap-2 pt-2 border-t border-surface-200 dark:border-surface-700\"\r\n >\r\n <mt-button\r\n variant=\"outlined\"\r\n size=\"small\"\r\n (onClick)=\"clear(popover)\"\r\n [label]=\"'components.table.reset' | transloco\"\r\n />\r\n <mt-button\r\n size=\"small\"\r\n (onClick)=\"apply(popover)\"\r\n [label]=\"'components.table.apply' | transloco\"\r\n />\r\n </div>\r\n </div>\r\n</p-popover>\r\n" }]
993
- }], propDecorators: { column: [{ type: i0.Input, args: [{ isSignal: true, alias: "column", required: true }] }], value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }], filterChange: [{ type: i0.Output, args: ["filterChange"] }] } });
1041
+ }], ctorParameters: () => [], propDecorators: { column: [{ type: i0.Input, args: [{ isSignal: true, alias: "column", required: true }] }], value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }], filterChange: [{ type: i0.Output, args: ["filterChange"] }], popoverRef: [{ type: i0.ViewChild, args: ['popover', { isSignal: true }] }] } });
994
1042
 
995
1043
  /**
996
1044
  * Centralises table export/print so any `mt-table` (and future tables) can