@masterteam/components 0.0.150 → 0.0.152

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@masterteam/components",
3
- "version": "0.0.150",
3
+ "version": "0.0.152",
4
4
  "publishConfig": {
5
5
  "directory": "../../../dist/masterteam/components",
6
6
  "linkDirectory": true,
@@ -450,16 +450,44 @@ declare class ComparisonEntityList {
450
450
  static ɵcmp: _angular_core.ɵɵComponentDeclaration<ComparisonEntityList, "mt-comparison-entity-list", never, { "data": { "alias": "data"; "required": true; "isSignal": true; }; }, {}, never, never, true, never>;
451
451
  }
452
452
 
453
+ interface EntityClickEvent {
454
+ entity: EntityData;
455
+ key: string;
456
+ source: MouseEvent;
457
+ }
453
458
  declare class EntitiesPreview {
454
459
  /** Array of entity data to display */
455
460
  readonly entities: _angular_core.InputSignal<EntityData[]>;
456
461
  readonly attachmentShape: _angular_core.InputSignal<"compact" | "default">;
462
+ /**
463
+ * Set of entity keys that should appear interactive (cursor pointer,
464
+ * clicks emit). Pass `new Set([...])` from a computed signal in the host
465
+ * for reactive enabling — when the host's set changes, Angular re-renders
466
+ * via its normal change detection, no manual subscriptions required.
467
+ */
468
+ readonly clickableKeys: _angular_core.InputSignal<ReadonlySet<string>>;
469
+ /**
470
+ * Set of entity keys that should render with the "active" treatment
471
+ * (e.g. currently the filter source). Same reactive pattern as
472
+ * `clickableKeys` — host owns a computed signal and passes the value.
473
+ */
474
+ readonly activeKeys: _angular_core.InputSignal<ReadonlySet<string>>;
475
+ /**
476
+ * Emits when an individual entity slot is clicked. Only fires when the
477
+ * entity's key is present in `clickableKeys`.
478
+ */
479
+ readonly entityClick: _angular_core.OutputEmitterRef<EntityClickEvent>;
457
480
  /** Entities expanded and sorted by order */
458
481
  readonly displayEntities: _angular_core.Signal<EntityData[]>;
459
482
  /** Returns the grid-column span for a given entity size (1-24) */
460
483
  getColSpan(entity: EntityData): string;
484
+ /** Stable key resolution shared with the host — must agree on order. */
485
+ private resolveKey;
486
+ protected isClickable(entity: EntityData): boolean;
487
+ protected isActive(entity: EntityData): boolean;
488
+ protected onEntityClick(source: MouseEvent, entity: EntityData): void;
461
489
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<EntitiesPreview, never>;
462
- static ɵcmp: _angular_core.ɵɵComponentDeclaration<EntitiesPreview, "mt-entities-preview", never, { "entities": { "alias": "entities"; "required": true; "isSignal": true; }; "attachmentShape": { "alias": "attachmentShape"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
490
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<EntitiesPreview, "mt-entities-preview", never, { "entities": { "alias": "entities"; "required": true; "isSignal": true; }; "attachmentShape": { "alias": "attachmentShape"; "required": false; "isSignal": true; }; "clickableKeys": { "alias": "clickableKeys"; "required": false; "isSignal": true; }; "activeKeys": { "alias": "activeKeys"; "required": false; "isSignal": true; }; }, { "entityClick": "entityClick"; }, never, never, true, never>;
463
491
  }
464
492
 
465
493
  /**
@@ -531,4 +559,4 @@ declare class EntitiesManage extends EntitiesResizeBase {
531
559
  }
532
560
 
533
561
  export { ComparisonEntityList, ComparisonValue, EntitiesManage, EntitiesPreview, EntitiesResizeBase, EntityAttachment, EntityCheckbox, EntityCurrency, EntityDate, EntityField, EntityLeafDetails, EntityLongText, EntityLookup, EntityPercentage, EntityPreview, EntityPreviewBody, EntityStatus, EntityText, EntityUser, LEAF_DETAILS_KEY_SEPARATOR, buildDisplayEntities, expandLeafDetailsEntity, isLeafDetailsCatalogConfiguration, isLeafDetailsCollectionValue, isLeafDetailsRuntimeValue, isLeafDetailsSyntheticKey, isLeafDetailsValue };
534
- export type { ComparisonValueSide, EntityAttachmentItemValue, EntityAttachmentValue, EntityBaseConfig, EntityComparisonField, EntityComparisonOperation, EntityConfiguration, EntityData, EntityLabelPosition, EntityLeafDetailsConfig, EntityListComparison, EntityListComparisonRow, EntityLookupValue, EntityPercentageConfig, EntityPropertyConfiguration, EntityResizeEvent, EntitySize, EntityStatusValue, EntityUserConfig, EntityUserValue, EntityViewType, LeafDetailsCatalogConfiguration, LeafDetailsCatalogLevelValue, LeafDetailsCatalogStatusValue, LeafDetailsEntityCollectionValue, LeafDetailsEntityValue, LeafDetailsRuntimeChildSchema, LeafDetailsRuntimeStatusCount, LeafDetailsRuntimeStatusDetails, LeafDetailsRuntimeValue, LeafDetailsStatusSummary, LeafLevelSavedConfig, PropertyValueComparison, ValueComparison };
562
+ export type { ComparisonValueSide, EntityAttachmentItemValue, EntityAttachmentValue, EntityBaseConfig, EntityClickEvent, EntityComparisonField, EntityComparisonOperation, EntityConfiguration, EntityData, EntityLabelPosition, EntityLeafDetailsConfig, EntityListComparison, EntityListComparisonRow, EntityLookupValue, EntityPercentageConfig, EntityPropertyConfiguration, EntityResizeEvent, EntitySize, EntityStatusValue, EntityUserConfig, EntityUserValue, EntityViewType, LeafDetailsCatalogConfiguration, LeafDetailsCatalogLevelValue, LeafDetailsCatalogStatusValue, LeafDetailsEntityCollectionValue, LeafDetailsEntityValue, LeafDetailsRuntimeChildSchema, LeafDetailsRuntimeStatusCount, LeafDetailsRuntimeStatusDetails, LeafDetailsRuntimeValue, LeafDetailsStatusSummary, LeafLevelSavedConfig, PropertyValueComparison, ValueComparison };
@@ -1,11 +1,13 @@
1
1
  import * as _angular_core from '@angular/core';
2
- import { TemplateRef } from '@angular/core';
2
+ import { TemplateRef, Signal, WritableSignal } from '@angular/core';
3
3
  import { MTIcon } from '@masterteam/icons';
4
4
  import { ConfirmationConfig, ConfirmationService } from '@masterteam/components/confirmation';
5
5
  import { TablePageEvent } from 'primeng/table';
6
6
  import { EntityData } from '@masterteam/components/entities';
7
- import * as _masterteam_components_table from '@masterteam/components/table';
8
7
  import { ControlValueAccessor } from '@angular/forms';
8
+ import { Popover } from 'primeng/popover';
9
+ import { MenuItem } from 'primeng/api';
10
+ import { TieredMenu } from 'primeng/tieredmenu';
9
11
 
10
12
  /**
11
13
  * Table action confirmation config with optional event
@@ -62,6 +64,30 @@ interface CellChangeEvent {
62
64
  }
63
65
  type ColumnTypeForActionCell = 'boolean';
64
66
  type TableActionShape = 'flat' | 'popover';
67
+ /**
68
+ * Filter UX mode for a table.
69
+ *
70
+ * - `popover`: single top-right funnel button opening a form with every filter.
71
+ * - `column`: per-column funnel icon next to each filterable header.
72
+ *
73
+ * Add new modes here + a matching branch in the table header template.
74
+ */
75
+ type TableFilterMode = 'popover' | 'column';
76
+ /**
77
+ * Injected value resolver for export/print — caller decides how a cell value
78
+ * becomes a scalar for Excel/PDF output. Keeps TableExportService
79
+ * schema-agnostic (open/closed for new column types).
80
+ */
81
+ type TableExportValueResolver = (row: unknown, column: ColumnDef) => string | number | boolean | null;
82
+ interface TableExportConfig {
83
+ rows: any[];
84
+ columns: ColumnDef[];
85
+ filename: string;
86
+ resolveValue: TableExportValueResolver;
87
+ }
88
+ interface TablePrintConfig extends TableExportConfig {
89
+ title?: string;
90
+ }
65
91
  interface ColumnDef {
66
92
  key: string;
67
93
  label: string;
@@ -85,6 +111,51 @@ interface TableAction {
85
111
  confirmation?: TableActionConfirmationConfig;
86
112
  }
87
113
 
114
+ /**
115
+ * Pure controller owning all row-grouping concerns. Table instantiates one and
116
+ * binds its signals — keeps grouping logic out of table.ts.
117
+ *
118
+ * PrimeNG's subheader grouping renders only when `sortField === groupRowsBy`.
119
+ * `setGroup` therefore also pins the sort to the grouped column; clearing the
120
+ * group leaves the user's sort untouched.
121
+ */
122
+ declare class TableGroupingController {
123
+ private readonly columns;
124
+ private readonly rows;
125
+ private readonly groupBy;
126
+ private readonly sortField;
127
+ private readonly sortDirection;
128
+ constructor(columns: Signal<ColumnDef[]>, rows: Signal<unknown[]>, groupBy: WritableSignal<string | null>, sortField: WritableSignal<string | null>, sortDirection: WritableSignal<'asc' | 'desc' | null>);
129
+ readonly groupableColumns: Signal<ColumnDef[]>;
130
+ /**
131
+ * Row counts per group key — consumed by the group header template so each
132
+ * subheader can show "Status: Active (12)".
133
+ */
134
+ readonly groupCounts: Signal<Map<string, number>>;
135
+ getGroupCount(row: unknown): number;
136
+ readonly activeGroupColumn: Signal<ColumnDef | null>;
137
+ readonly groupingActive: Signal<boolean>;
138
+ /**
139
+ * Returns true when the given column is the active group column and
140
+ * therefore cannot have its sort cleared (PrimeNG requirement).
141
+ */
142
+ isGroupLockedSort(columnKey: string): boolean;
143
+ setGroup(key: string | null): void;
144
+ /**
145
+ * Display label for a row's grouped value — used by the `#groupheader`
146
+ * template. Leverages the same resolver pipeline the cells use, so status
147
+ * maps / user display names render consistently.
148
+ */
149
+ getGroupLabel(row: unknown): string;
150
+ /**
151
+ * Accent color for status/entity-Status group headers. Reused from the
152
+ * cell renderer's status-map pipeline so tint is consistent with the cell.
153
+ */
154
+ getGroupAccentColor(row: unknown): string | null;
155
+ /** Stable key used to bucket rows into groups — normalised to string. */
156
+ private getGroupKey;
157
+ }
158
+
88
159
  declare class Table {
89
160
  private static readonly LOADING_COLUMN_COUNT;
90
161
  selectionChange: _angular_core.OutputEmitterRef<any[]>;
@@ -105,6 +176,7 @@ declare class Table {
105
176
  generalSearch: _angular_core.InputSignalWithTransform<boolean, unknown>;
106
177
  lazyLocalSearch: _angular_core.InputSignalWithTransform<boolean, unknown>;
107
178
  showFilters: _angular_core.InputSignalWithTransform<boolean, unknown>;
179
+ filterMode: _angular_core.InputSignal<TableFilterMode>;
108
180
  loading: _angular_core.InputSignalWithTransform<boolean, unknown>;
109
181
  updating: _angular_core.InputSignalWithTransform<boolean, unknown>;
110
182
  lazy: _angular_core.InputSignalWithTransform<boolean, unknown>;
@@ -116,10 +188,15 @@ declare class Table {
116
188
  storageKey: _angular_core.InputSignal<string | null>;
117
189
  storageMode: _angular_core.InputSignal<"local" | "session">;
118
190
  exportable: _angular_core.InputSignalWithTransform<boolean, unknown>;
191
+ printable: _angular_core.InputSignalWithTransform<boolean, unknown>;
192
+ groupable: _angular_core.InputSignalWithTransform<boolean, unknown>;
193
+ cellClickFilter: _angular_core.InputSignalWithTransform<boolean, unknown>;
194
+ printTitle: _angular_core.InputSignal<string>;
119
195
  exportFilename: _angular_core.InputSignal<string>;
120
196
  actionShape: _angular_core.InputSignal<TableActionShape>;
121
197
  tableLayout: _angular_core.InputSignal<"fixed" | "auto">;
122
198
  noCard: _angular_core.InputSignalWithTransform<boolean, unknown>;
199
+ private readonly dateFormat;
123
200
  tabs: _angular_core.InputSignal<any[] | undefined>;
124
201
  tabsOptionLabel: _angular_core.InputSignal<string>;
125
202
  tabsOptionValue: _angular_core.InputSignal<string>;
@@ -136,13 +213,20 @@ declare class Table {
136
213
  currentPage: _angular_core.ModelSignal<number>;
137
214
  first: _angular_core.ModelSignal<number>;
138
215
  filterTerm: _angular_core.ModelSignal<string>;
216
+ groupBy: _angular_core.ModelSignal<string | null>;
139
217
  sortField: _angular_core.WritableSignal<string | null>;
140
218
  sortDirection: _angular_core.WritableSignal<"asc" | "desc" | null>;
141
219
  confirmationService: ConfirmationService;
220
+ private readonly exportService;
221
+ protected readonly grouping: TableGroupingController;
142
222
  protected selectedRowKeys: _angular_core.WritableSignal<Set<string>>;
143
223
  protected transientSelectedRows: _angular_core.WritableSignal<Set<any>>;
144
224
  private readonly hydratedStorageKey;
145
225
  private readonly storageHydrated;
226
+ protected readonly isColumnFilterMode: _angular_core.Signal<boolean>;
227
+ protected filterableColumnMap: _angular_core.Signal<Map<string, ColumnDef>>;
228
+ protected getFilterableColumn(key: string): ColumnDef | undefined;
229
+ onColumnFilterChange(key: string, value: any): void;
146
230
  protected activeFilterCount: _angular_core.Signal<number>;
147
231
  protected filteredData: _angular_core.Signal<any[]>;
148
232
  protected renderedColumns: _angular_core.Signal<ColumnDef[]>;
@@ -150,6 +234,7 @@ declare class Table {
150
234
  protected totalRecords: _angular_core.Signal<number>;
151
235
  protected paginatedData: _angular_core.Signal<any[]>;
152
236
  protected allSelectedOnPage: _angular_core.Signal<boolean>;
237
+ protected totalColumnSpan: _angular_core.Signal<number>;
153
238
  constructor();
154
239
  onFilterApplied(filters: TableFilters): void;
155
240
  onFilterReset(): void;
@@ -159,6 +244,12 @@ declare class Table {
159
244
  getProperty(obj: any, key: string): any;
160
245
  protected getDateProperty(obj: any, key: string): string | number | Date | null;
161
246
  getEntityPreviewData(row: any, col: ColumnDef): EntityData | null;
247
+ /**
248
+ * Entity data resolver that abstracts over the `user` / `status` vs `entity`
249
+ * distinction — used by the shared filterable-cell template so the three
250
+ * cases don't duplicate markup.
251
+ */
252
+ resolveCellEntityData(row: any, col: ColumnDef): EntityData | null;
162
253
  tabChanged(tab: any): void;
163
254
  onTablePage(event: TablePageEvent): void;
164
255
  handleLazyLoad(event: any): void;
@@ -176,6 +267,10 @@ declare class Table {
176
267
  protected updatePagingFromEvent(event: any): void;
177
268
  protected emitLazyLoad(event: any): void;
178
269
  exportExcel(): void;
270
+ printPdf(): void;
271
+ onCellFilterClick(event: Event, row: any, column: ColumnDef): void;
272
+ isCellFilterActive(row: any, column: ColumnDef): boolean;
273
+ isCellClickFilterable(column: ColumnDef, row: unknown): boolean;
179
274
  rowAction(event: Event, action: TableAction, row: any): void;
180
275
  private buildUserEntityData;
181
276
  private buildStatusEntityData;
@@ -200,16 +295,26 @@ declare class Table {
200
295
  private setProperty;
201
296
  private sortData;
202
297
  private getSortValue;
298
+ /**
299
+ * Export/print value resolver — same pipeline as `getColumnResolvedValue`
300
+ * except date / dateTime columns (and their entity counterparts) are
301
+ * formatted via the MT date pipe so Excel and PDF show locale-aware dates
302
+ * instead of raw ISO strings. Sort path keeps the ISO form for ordering.
303
+ */
304
+ private getColumnExportValue;
305
+ /**
306
+ * Detects whether a column should be treated as a date for export purposes:
307
+ * native `date` / `dateTime` types, or entity columns whose viewType is
308
+ * `Date` / `DateTime`.
309
+ */
310
+ private resolveDateColumnType;
203
311
  private getColumnResolvedValue;
204
- private buildExportRows;
205
- private buildExcelRows;
206
312
  protected isRowSelected(row: Record<string, unknown>): boolean;
207
313
  protected getColumnMinWidth(column: ColumnDef): string | null;
208
314
  private emitSelectionChange;
209
315
  private getSelectedRows;
210
316
  private getRowSelectionKey;
211
317
  private getNormalizedStorageKey;
212
- private normalizeExportFilename;
213
318
  private getStorage;
214
319
  private buildPersistedState;
215
320
  private applyPersistedState;
@@ -220,7 +325,69 @@ declare class Table {
220
325
  private normalizePersistedPageSize;
221
326
  private toNonNegativeInteger;
222
327
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<Table, never>;
223
- static ɵcmp: _angular_core.ɵɵComponentDeclaration<Table, "mt-table", never, { "filters": { "alias": "filters"; "required": false; "isSignal": true; }; "data": { "alias": "data"; "required": true; "isSignal": true; }; "columns": { "alias": "columns"; "required": true; "isSignal": true; }; "rowActions": { "alias": "rowActions"; "required": false; "isSignal": true; }; "size": { "alias": "size"; "required": false; "isSignal": true; }; "showGridlines": { "alias": "showGridlines"; "required": false; "isSignal": true; }; "stripedRows": { "alias": "stripedRows"; "required": false; "isSignal": true; }; "selectableRows": { "alias": "selectableRows"; "required": false; "isSignal": true; }; "clickableRows": { "alias": "clickableRows"; "required": false; "isSignal": true; }; "generalSearch": { "alias": "generalSearch"; "required": false; "isSignal": true; }; "lazyLocalSearch": { "alias": "lazyLocalSearch"; "required": false; "isSignal": true; }; "showFilters": { "alias": "showFilters"; "required": false; "isSignal": true; }; "loading": { "alias": "loading"; "required": false; "isSignal": true; }; "updating": { "alias": "updating"; "required": false; "isSignal": true; }; "lazy": { "alias": "lazy"; "required": false; "isSignal": true; }; "lazyLocalSort": { "alias": "lazyLocalSort"; "required": false; "isSignal": true; }; "lazyTotalRecords": { "alias": "lazyTotalRecords"; "required": false; "isSignal": true; }; "reorderableColumns": { "alias": "reorderableColumns"; "required": false; "isSignal": true; }; "reorderableRows": { "alias": "reorderableRows"; "required": false; "isSignal": true; }; "dataKey": { "alias": "dataKey"; "required": false; "isSignal": true; }; "storageKey": { "alias": "storageKey"; "required": false; "isSignal": true; }; "storageMode": { "alias": "storageMode"; "required": false; "isSignal": true; }; "exportable": { "alias": "exportable"; "required": false; "isSignal": true; }; "exportFilename": { "alias": "exportFilename"; "required": false; "isSignal": true; }; "actionShape": { "alias": "actionShape"; "required": false; "isSignal": true; }; "tableLayout": { "alias": "tableLayout"; "required": false; "isSignal": true; }; "noCard": { "alias": "noCard"; "required": false; "isSignal": true; }; "tabs": { "alias": "tabs"; "required": false; "isSignal": true; }; "tabsOptionLabel": { "alias": "tabsOptionLabel"; "required": false; "isSignal": true; }; "tabsOptionValue": { "alias": "tabsOptionValue"; "required": false; "isSignal": true; }; "activeTab": { "alias": "activeTab"; "required": false; "isSignal": true; }; "actions": { "alias": "actions"; "required": false; "isSignal": true; }; "paginatorPosition": { "alias": "paginatorPosition"; "required": false; "isSignal": true; }; "alwaysShowPaginator": { "alias": "alwaysShowPaginator"; "required": false; "isSignal": true; }; "rowsPerPageOptions": { "alias": "rowsPerPageOptions"; "required": false; "isSignal": true; }; "pageSize": { "alias": "pageSize"; "required": false; "isSignal": true; }; "currentPage": { "alias": "currentPage"; "required": false; "isSignal": true; }; "first": { "alias": "first"; "required": false; "isSignal": true; }; "filterTerm": { "alias": "filterTerm"; "required": false; "isSignal": true; }; }, { "selectionChange": "selectionChange"; "cellChange": "cellChange"; "lazyLoad": "lazyLoad"; "columnReorder": "columnReorder"; "rowReorder": "rowReorder"; "rowClick": "rowClick"; "filters": "filtersChange"; "activeTab": "activeTabChange"; "onTabChange": "onTabChange"; "pageSize": "pageSizeChange"; "currentPage": "currentPageChange"; "first": "firstChange"; "filterTerm": "filterTermChange"; }, ["captionStartContent", "captionEndContent", "emptyContent"], never, true, never>;
328
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<Table, "mt-table", never, { "filters": { "alias": "filters"; "required": false; "isSignal": true; }; "data": { "alias": "data"; "required": true; "isSignal": true; }; "columns": { "alias": "columns"; "required": true; "isSignal": true; }; "rowActions": { "alias": "rowActions"; "required": false; "isSignal": true; }; "size": { "alias": "size"; "required": false; "isSignal": true; }; "showGridlines": { "alias": "showGridlines"; "required": false; "isSignal": true; }; "stripedRows": { "alias": "stripedRows"; "required": false; "isSignal": true; }; "selectableRows": { "alias": "selectableRows"; "required": false; "isSignal": true; }; "clickableRows": { "alias": "clickableRows"; "required": false; "isSignal": true; }; "generalSearch": { "alias": "generalSearch"; "required": false; "isSignal": true; }; "lazyLocalSearch": { "alias": "lazyLocalSearch"; "required": false; "isSignal": true; }; "showFilters": { "alias": "showFilters"; "required": false; "isSignal": true; }; "filterMode": { "alias": "filterMode"; "required": false; "isSignal": true; }; "loading": { "alias": "loading"; "required": false; "isSignal": true; }; "updating": { "alias": "updating"; "required": false; "isSignal": true; }; "lazy": { "alias": "lazy"; "required": false; "isSignal": true; }; "lazyLocalSort": { "alias": "lazyLocalSort"; "required": false; "isSignal": true; }; "lazyTotalRecords": { "alias": "lazyTotalRecords"; "required": false; "isSignal": true; }; "reorderableColumns": { "alias": "reorderableColumns"; "required": false; "isSignal": true; }; "reorderableRows": { "alias": "reorderableRows"; "required": false; "isSignal": true; }; "dataKey": { "alias": "dataKey"; "required": false; "isSignal": true; }; "storageKey": { "alias": "storageKey"; "required": false; "isSignal": true; }; "storageMode": { "alias": "storageMode"; "required": false; "isSignal": true; }; "exportable": { "alias": "exportable"; "required": false; "isSignal": true; }; "printable": { "alias": "printable"; "required": false; "isSignal": true; }; "groupable": { "alias": "groupable"; "required": false; "isSignal": true; }; "cellClickFilter": { "alias": "cellClickFilter"; "required": false; "isSignal": true; }; "printTitle": { "alias": "printTitle"; "required": false; "isSignal": true; }; "exportFilename": { "alias": "exportFilename"; "required": false; "isSignal": true; }; "actionShape": { "alias": "actionShape"; "required": false; "isSignal": true; }; "tableLayout": { "alias": "tableLayout"; "required": false; "isSignal": true; }; "noCard": { "alias": "noCard"; "required": false; "isSignal": true; }; "tabs": { "alias": "tabs"; "required": false; "isSignal": true; }; "tabsOptionLabel": { "alias": "tabsOptionLabel"; "required": false; "isSignal": true; }; "tabsOptionValue": { "alias": "tabsOptionValue"; "required": false; "isSignal": true; }; "activeTab": { "alias": "activeTab"; "required": false; "isSignal": true; }; "actions": { "alias": "actions"; "required": false; "isSignal": true; }; "paginatorPosition": { "alias": "paginatorPosition"; "required": false; "isSignal": true; }; "alwaysShowPaginator": { "alias": "alwaysShowPaginator"; "required": false; "isSignal": true; }; "rowsPerPageOptions": { "alias": "rowsPerPageOptions"; "required": false; "isSignal": true; }; "pageSize": { "alias": "pageSize"; "required": false; "isSignal": true; }; "currentPage": { "alias": "currentPage"; "required": false; "isSignal": true; }; "first": { "alias": "first"; "required": false; "isSignal": true; }; "filterTerm": { "alias": "filterTerm"; "required": false; "isSignal": true; }; "groupBy": { "alias": "groupBy"; "required": false; "isSignal": true; }; }, { "selectionChange": "selectionChange"; "cellChange": "cellChange"; "lazyLoad": "lazyLoad"; "columnReorder": "columnReorder"; "rowReorder": "rowReorder"; "rowClick": "rowClick"; "filters": "filtersChange"; "activeTab": "activeTabChange"; "onTabChange": "onTabChange"; "pageSize": "pageSizeChange"; "currentPage": "currentPageChange"; "first": "firstChange"; "filterTerm": "filterTermChange"; "groupBy": "groupByChange"; }, ["captionStartContent", "captionEndContent", "emptyContent"], never, true, never>;
329
+ }
330
+
331
+ type TableEntityUsage = 'sort' | 'export' | 'filter';
332
+ declare class TableValueResolver {
333
+ private static readonly ALL_ENTITY_VIEW_TYPES;
334
+ private static readonly UNSORTABLE_ENTITY_VIEW_TYPES;
335
+ private static readonly EXPORTABLE_ENTITY_VIEW_TYPES;
336
+ private static readonly FILTERABLE_ENTITY_VIEW_TYPES;
337
+ static getProperty(obj: unknown, key: string): unknown;
338
+ static getColumnFilterType(column: ColumnDef, row?: Record<string, unknown>): FilterConfig['type'] | null;
339
+ /**
340
+ * Returns a column with its filterConfig normalized for rendering:
341
+ * - `type` is resolved via `getColumnFilterType`
342
+ * - `options` for `select` filters are auto-generated from `data` when not provided
343
+ *
344
+ * Used by both popover and per-column filter modes so option-building stays in one place.
345
+ */
346
+ static buildFilterableColumn(column: ColumnDef, data: any[]): ColumnDef;
347
+ /**
348
+ * Returns true when `item` passes the filter for `key`. Pure function — callers
349
+ * pass `column` so the resolver can apply type-aware normalisation (entity,
350
+ * status, user, date, boolean). Shared by `mt-table` row-filtering and
351
+ * `client-list-cards-view` card-filtering.
352
+ */
353
+ static matchesFilter(item: unknown, key: string, filterValue: FilterValue | unknown, column: ColumnDef | undefined): boolean;
354
+ /**
355
+ * Applies every entry of `filters` against `item` — used by cards view and
356
+ * anywhere else that consumes the same filter shape as mt-table.
357
+ */
358
+ static matchesAllFilters(item: unknown, filters: Record<string, unknown>, columns: ColumnDef[]): boolean;
359
+ /**
360
+ * True when a filter slot holds a meaningful value (scalar, text, date-range bounds,
361
+ * or user lookup). Shared by popover and per-column modes to compute active counts.
362
+ */
363
+ static hasFilterValue(value: unknown): boolean;
364
+ /**
365
+ * Produces the filter payload a cell-click should apply for `column`.
366
+ * Returns null when the cell type is not click-filterable.
367
+ *
368
+ * Shapes match `Table.matchesFilter` branches:
369
+ * - user / entity(User) → `{ id, userName, displayName }`
370
+ * - status / entity(Status|Lookup) → scalar display string
371
+ * - boolean → boolean
372
+ */
373
+ static buildClickFilterValue(row: unknown, column: ColumnDef): unknown | null;
374
+ /**
375
+ * True when two filter values refer to the same thing. Mirrors the branches
376
+ * in `Table.matchesFilter`: scalar equality, boolean equality, or user-object
377
+ * identity on id / userName / displayName.
378
+ */
379
+ static isFilterValueEqual(a: unknown, b: unknown): boolean;
380
+ private static extractUserFilterValue;
381
+ static getColumnFilterValue(row: Record<string, unknown>, column: ColumnDef): string | number | boolean | null;
382
+ static resolveDateValue(value: unknown): string | number | Date | null;
383
+ static getEntityValueByType(value: unknown, usage: TableEntityUsage): string | number | boolean | null;
384
+ static resolveDisplayValue(value: unknown): string | number | boolean | null;
385
+ static resolveBooleanValue(value: unknown): boolean | null;
386
+ static normalizeTextSortValue(value: unknown): string | null;
387
+ static normalizeNumericSortValue(value: unknown): number | null;
388
+ static normalizeDateSortValue(value: unknown): number | null;
389
+ private static getEntityViewType;
390
+ private static isEntityViewType;
224
391
  }
225
392
 
226
393
  declare class TableFilter implements ControlValueAccessor {
@@ -230,36 +397,13 @@ declare class TableFilter implements ControlValueAccessor {
230
397
  readonly filterReset: _angular_core.OutputEmitterRef<void>;
231
398
  protected pendingFilters: _angular_core.WritableSignal<TableFilters>;
232
399
  protected appliedFilters: _angular_core.WritableSignal<TableFilters>;
233
- protected booleanOptions: {
234
- label: string;
235
- value: boolean;
236
- }[];
237
400
  private onChange;
238
401
  private onTouched;
239
- protected filterableColumns: _angular_core.Signal<{
240
- filterConfig: {
241
- type: "boolean" | "text" | "select" | "date" | "user";
242
- label?: string;
243
- options?: FilterOption[];
244
- };
245
- key: string;
246
- label: string;
247
- type?: _masterteam_components_table.ColumnType;
248
- customCellTpl?: _angular_core.TemplateRef<any>;
249
- statusMap?: Record<string, _masterteam_components_table.TableStatusMapValue>;
250
- sortable?: boolean;
251
- readonly?: boolean;
252
- width?: string;
253
- }[]>;
402
+ protected filterableColumns: _angular_core.Signal<ColumnDef[]>;
254
403
  protected activeFilterCount: _angular_core.Signal<number>;
255
- protected getFilterType(col: ColumnDef): string;
256
- protected getFilterValue(key: string): any;
257
- protected getDateRangeValue(key: string, part: 'from' | 'to'): Date | null;
258
404
  protected updateFilter(key: string, value: any): void;
259
- protected updateDateFilter(key: string, part: 'from' | 'to', value: Date | null): void;
260
405
  protected apply(): void;
261
406
  protected reset(): void;
262
- private hasValue;
263
407
  writeValue(value: TableFilters | null): void;
264
408
  registerOnChange(fn: (value: TableFilters) => void): void;
265
409
  registerOnTouched(fn: () => void): void;
@@ -267,5 +411,161 @@ declare class TableFilter implements ControlValueAccessor {
267
411
  static ɵcmp: _angular_core.ɵɵComponentDeclaration<TableFilter, "mt-table-filter", never, { "columns": { "alias": "columns"; "required": true; "isSignal": true; }; "data": { "alias": "data"; "required": false; "isSignal": true; }; }, { "filterApplied": "filterApplied"; "filterReset": "filterReset"; }, never, never, true, never>;
268
412
  }
269
413
 
270
- export { Table, TableFilter };
271
- export type { CellChangeEvent, ColumnDef, ColumnType, ColumnTypeForActionCell, FilterConfig, FilterOption, FilterValue, TableAction, TableActionConfirmationConfig, TableActionShape, TableFilters, TableStatusMapValue };
414
+ /**
415
+ * Renders a single filter control for one `ColumnDef`, dispatching on
416
+ * `column.filterConfig.type` (`text` | `select` | `date` | `boolean` | `user`).
417
+ *
418
+ * Two-way binds the filter value via `value` / `valueChange`. Shared by both
419
+ * filter UX modes (popover + per-column) so field rendering lives in one place.
420
+ * Add a new filter type by adding a `@case` in the template and extending
421
+ * `FilterConfig['type']`.
422
+ */
423
+ declare class TableFilterField {
424
+ readonly column: _angular_core.InputSignal<ColumnDef>;
425
+ readonly value: _angular_core.ModelSignal<any>;
426
+ protected readonly booleanOptions: {
427
+ label: string;
428
+ value: boolean;
429
+ }[];
430
+ protected getFilterType(): string;
431
+ protected getScalarValue(): any;
432
+ protected getDateRangeValue(part: 'from' | 'to'): Date | null;
433
+ protected updateScalar(next: any): void;
434
+ protected updateDate(part: 'from' | 'to', next: Date | null): void;
435
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<TableFilterField, never>;
436
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<TableFilterField, "mt-table-filter-field", never, { "column": { "alias": "column"; "required": true; "isSignal": true; }; "value": { "alias": "value"; "required": false; "isSignal": true; }; }, { "value": "valueChange"; }, never, never, true, never>;
437
+ }
438
+
439
+ /**
440
+ * Per-column filter affordance: a small funnel icon in the column header that
441
+ * opens a popover with a single `TableFilterField`.
442
+ *
443
+ * Buffers edits in `pendingValue` until the user hits Apply — matches the
444
+ * popover-mode UX so behavior is predictable between modes. Emits `filterChange`
445
+ * with either the new value or `null` to clear.
446
+ */
447
+ declare class TableColumnFilter {
448
+ readonly column: _angular_core.InputSignal<ColumnDef>;
449
+ readonly value: _angular_core.InputSignal<any>;
450
+ readonly filterChange: _angular_core.OutputEmitterRef<any>;
451
+ protected readonly pendingValue: _angular_core.WritableSignal<any>;
452
+ protected readonly hasActiveValue: _angular_core.Signal<boolean>;
453
+ protected open(popover: Popover, event: Event): void;
454
+ protected apply(popover: Popover): void;
455
+ protected clear(popover: Popover): void;
456
+ private cloneValue;
457
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<TableColumnFilter, never>;
458
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<TableColumnFilter, "mt-table-column-filter", never, { "column": { "alias": "column"; "required": true; "isSignal": true; }; "value": { "alias": "value"; "required": false; "isSignal": true; }; }, { "filterChange": "filterChange"; }, never, never, true, never>;
459
+ }
460
+
461
+ /** Visual variants for menu-item icon chips. */
462
+ type ActionMenuTone = 'emerald' | 'sky' | 'indigo' | 'secondary';
463
+ interface TableMenuItem extends MenuItem {
464
+ /** Transloco key resolved in the template so translations stay reactive. */
465
+ labelKey?: string;
466
+ /** Plain, already-translated or dynamic label — used when labelKey isn't set. */
467
+ rawLabel?: string;
468
+ iconKey?: MTIcon;
469
+ iconTone?: ActionMenuTone;
470
+ /** When true, the item renders via `mt-avatar` instead of a flat tinted chip. */
471
+ useAvatar?: boolean;
472
+ /** Small trailing chip (e.g. the group-by item's active column name). */
473
+ badge?: string;
474
+ /** Used to mark the current selection in the group submenu. */
475
+ selected?: boolean;
476
+ }
477
+ /**
478
+ * Top-right `⋯` menu. Uses PrimeNG TieredMenu (popup mode) so submenu
479
+ * cascading, keyboard navigation, and outside-click-to-close come for free.
480
+ * Item rendering is overridden via the `#item` template so each row shows
481
+ * either a flat tone chip (main actions) or an `mt-avatar` (column picker).
482
+ */
483
+ declare class TableActionsMenu {
484
+ readonly exportable: _angular_core.InputSignalWithTransform<boolean, unknown>;
485
+ readonly printable: _angular_core.InputSignalWithTransform<boolean, unknown>;
486
+ readonly groupable: _angular_core.InputSignalWithTransform<boolean, unknown>;
487
+ readonly groupColumns: _angular_core.InputSignal<ColumnDef[]>;
488
+ readonly activeGroup: _angular_core.InputSignal<string | null>;
489
+ readonly exportRequested: _angular_core.OutputEmitterRef<void>;
490
+ readonly printRequested: _angular_core.OutputEmitterRef<void>;
491
+ readonly groupChange: _angular_core.OutputEmitterRef<string | null>;
492
+ protected readonly menu: _angular_core.Signal<TieredMenu | undefined>;
493
+ /** Tailwind classes for flat tone chips, keyed by `iconTone`. */
494
+ protected readonly toneClass: Record<ActionMenuTone, string>;
495
+ protected readonly items: _angular_core.Signal<TableMenuItem[]>;
496
+ protected toggle(event: MouseEvent): void;
497
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<TableActionsMenu, never>;
498
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<TableActionsMenu, "mt-table-actions-menu", never, { "exportable": { "alias": "exportable"; "required": false; "isSignal": true; }; "printable": { "alias": "printable"; "required": false; "isSignal": true; }; "groupable": { "alias": "groupable"; "required": false; "isSignal": true; }; "groupColumns": { "alias": "groupColumns"; "required": false; "isSignal": true; }; "activeGroup": { "alias": "activeGroup"; "required": false; "isSignal": true; }; }, { "exportRequested": "exportRequested"; "printRequested": "printRequested"; "groupChange": "groupChange"; }, never, never, true, never>;
499
+ }
500
+
501
+ /**
502
+ * Stateless, controlled toolbar used by `mt-table` and by list-style consumers
503
+ * (e.g. `client-list-cards-view`) so the two share one caption UI without
504
+ * duplicating the search/filter/actions markup.
505
+ *
506
+ * The caption only renders the popover-mode filter button — per-column filter
507
+ * icons live in the table header itself (cards have no columns).
508
+ */
509
+ declare class TableCaption {
510
+ readonly generalSearch: _angular_core.InputSignalWithTransform<boolean, unknown>;
511
+ readonly showFilters: _angular_core.InputSignalWithTransform<boolean, unknown>;
512
+ readonly filterMode: _angular_core.InputSignal<TableFilterMode>;
513
+ readonly exportable: _angular_core.InputSignalWithTransform<boolean, unknown>;
514
+ readonly printable: _angular_core.InputSignalWithTransform<boolean, unknown>;
515
+ readonly groupable: _angular_core.InputSignalWithTransform<boolean, unknown>;
516
+ readonly columns: _angular_core.InputSignal<ColumnDef[]>;
517
+ readonly data: _angular_core.InputSignal<any[]>;
518
+ readonly groupColumns: _angular_core.InputSignal<ColumnDef[]>;
519
+ readonly tabs: _angular_core.InputSignal<any[] | undefined>;
520
+ readonly tabsOptionLabel: _angular_core.InputSignal<string>;
521
+ readonly tabsOptionValue: _angular_core.InputSignal<string>;
522
+ readonly actions: _angular_core.InputSignal<TableAction[]>;
523
+ readonly captionStart: _angular_core.InputSignal<TemplateRef<unknown> | null>;
524
+ readonly captionEnd: _angular_core.InputSignal<TemplateRef<unknown> | null>;
525
+ readonly activeTab: _angular_core.ModelSignal<any>;
526
+ readonly filters: _angular_core.ModelSignal<TableFilters>;
527
+ readonly filterTerm: _angular_core.ModelSignal<string>;
528
+ readonly groupBy: _angular_core.ModelSignal<string | null>;
529
+ readonly exportRequested: _angular_core.OutputEmitterRef<void>;
530
+ readonly printRequested: _angular_core.OutputEmitterRef<void>;
531
+ readonly onTabChange: _angular_core.OutputEmitterRef<any>;
532
+ readonly searchChange: _angular_core.OutputEmitterRef<string>;
533
+ readonly filterApplied: _angular_core.OutputEmitterRef<TableFilters>;
534
+ readonly filterReset: _angular_core.OutputEmitterRef<void>;
535
+ protected readonly showsAnything: _angular_core.Signal<boolean>;
536
+ protected onSearch(term: string): void;
537
+ protected onFilterApplied(next: TableFilters): void;
538
+ protected onFilterReset(): void;
539
+ protected onGroupChange(key: string | null): void;
540
+ protected tabChanged(tab: any): void;
541
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<TableCaption, never>;
542
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<TableCaption, "mt-table-caption", never, { "generalSearch": { "alias": "generalSearch"; "required": false; "isSignal": true; }; "showFilters": { "alias": "showFilters"; "required": false; "isSignal": true; }; "filterMode": { "alias": "filterMode"; "required": false; "isSignal": true; }; "exportable": { "alias": "exportable"; "required": false; "isSignal": true; }; "printable": { "alias": "printable"; "required": false; "isSignal": true; }; "groupable": { "alias": "groupable"; "required": false; "isSignal": true; }; "columns": { "alias": "columns"; "required": false; "isSignal": true; }; "data": { "alias": "data"; "required": false; "isSignal": true; }; "groupColumns": { "alias": "groupColumns"; "required": false; "isSignal": true; }; "tabs": { "alias": "tabs"; "required": false; "isSignal": true; }; "tabsOptionLabel": { "alias": "tabsOptionLabel"; "required": false; "isSignal": true; }; "tabsOptionValue": { "alias": "tabsOptionValue"; "required": false; "isSignal": true; }; "actions": { "alias": "actions"; "required": false; "isSignal": true; }; "captionStart": { "alias": "captionStart"; "required": false; "isSignal": true; }; "captionEnd": { "alias": "captionEnd"; "required": false; "isSignal": true; }; "activeTab": { "alias": "activeTab"; "required": false; "isSignal": true; }; "filters": { "alias": "filters"; "required": false; "isSignal": true; }; "filterTerm": { "alias": "filterTerm"; "required": false; "isSignal": true; }; "groupBy": { "alias": "groupBy"; "required": false; "isSignal": true; }; }, { "activeTab": "activeTabChange"; "filters": "filtersChange"; "filterTerm": "filterTermChange"; "groupBy": "groupByChange"; "exportRequested": "exportRequested"; "printRequested": "printRequested"; "onTabChange": "onTabChange"; "searchChange": "searchChange"; "filterApplied": "filterApplied"; "filterReset": "filterReset"; }, never, never, true, never>;
543
+ }
544
+
545
+ /**
546
+ * Centralises table export/print so any `mt-table` (and future tables) can
547
+ * drop in the behaviour without reimplementing XLSX serialisation or print
548
+ * DOM cloning. Injected schema-agnostically via `resolveValue` on the config.
549
+ */
550
+ declare class TableExportService {
551
+ private static readonly PRINT_ROOT_CLASS;
552
+ private static readonly PRINT_REGION_CLASS;
553
+ private static readonly PRINT_STYLE_ID;
554
+ private static readonly PRINT_CSS;
555
+ exportToExcel(config: TableExportConfig): void;
556
+ printPdf(config: TablePrintConfig): void;
557
+ private ensurePrintStyles;
558
+ private getExportableColumns;
559
+ /**
560
+ * Produces rows keyed by column label (Excel header row).
561
+ * Entity columns use the dedicated entity resolver for a clean export value.
562
+ */
563
+ private buildLabeledRows;
564
+ private buildPrintRegion;
565
+ private normalizeFilename;
566
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<TableExportService, never>;
567
+ static ɵprov: _angular_core.ɵɵInjectableDeclaration<TableExportService>;
568
+ }
569
+
570
+ export { Table, TableActionsMenu, TableCaption, TableColumnFilter, TableExportService, TableFilter, TableFilterField, TableGroupingController, TableValueResolver };
571
+ export type { CellChangeEvent, ColumnDef, ColumnType, ColumnTypeForActionCell, FilterConfig, FilterOption, FilterValue, TableAction, TableActionConfirmationConfig, TableActionShape, TableEntityUsage, TableExportConfig, TableExportValueResolver, TableFilterMode, TableFilters, TablePrintConfig, TableStatusMapValue };