@praxisui/table 1.0.0-beta.10 → 1.0.0-beta.11
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/README.md +11 -1
- package/fesm2022/praxisui-table.mjs +78 -19
- package/fesm2022/praxisui-table.mjs.map +1 -1
- package/index.d.ts +10 -1
- package/package.json +6 -6
package/README.md
CHANGED
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
# @praxisui/table
|
|
2
2
|
|
|
3
|
+
## 🔰 Exemplos / Quickstart
|
|
4
|
+
|
|
5
|
+
Para ver esta biblioteca em funcionamento em uma aplicação completa, utilize o projeto de exemplo (Quickstart):
|
|
6
|
+
|
|
7
|
+
- Repositório: https://github.com/codexrodrigues/praxis-ui-quickstart
|
|
8
|
+
- O Quickstart demonstra a integração das bibliotecas `@praxisui/*` em um app Angular, incluindo instalação, configuração e uso em telas reais.
|
|
9
|
+
|
|
3
10
|
> Componente de tabela empresarial avançado com arquitetura unificada
|
|
4
11
|
|
|
5
12
|
## 🌟 Visão Geral
|
|
@@ -569,8 +576,11 @@ sequenceDiagram
|
|
|
569
576
|
- `notifyIfOutdated: 'inline' | 'snackbar' | 'both' | 'none' = 'both'`
|
|
570
577
|
- `snoozeMs: number = 86400000` (24h)
|
|
571
578
|
- `autoOpenSettingsOnOutdated: boolean = false`
|
|
572
|
-
-
|
|
579
|
+
- Outputs:
|
|
573
580
|
- `schemaStatusChange: { outdated: boolean; serverHash?: string; lastVerifiedAt?: string; resourcePath?: string }`
|
|
581
|
+
- Emitido tanto na verificação leve (304/200) quanto no bootstrap do schema (primeira carga via `loadSchema()`).
|
|
582
|
+
- `metadataChange: { meta: any; reason: 'bootstrap'|'verification'|'applied' }`
|
|
583
|
+
- Emitido quando `config.meta` é atualizado (ex.: após bootstrap ou verificação ETag). Útil para sincronizar sidebars/bridges de metadados.
|
|
574
584
|
|
|
575
585
|
### Fallback Global (opcional)
|
|
576
586
|
|
|
@@ -21622,6 +21622,8 @@ class PraxisTable {
|
|
|
21622
21622
|
rowDoubleClick = new EventEmitter();
|
|
21623
21623
|
/** Emits whenever schema outdated state changes (can be used by host) */
|
|
21624
21624
|
schemaStatusChange = new EventEmitter();
|
|
21625
|
+
/** Emits when metadata (config.meta) changes for hosts interested in schema/config changes */
|
|
21626
|
+
metadataChange = new EventEmitter();
|
|
21625
21627
|
beforeDelete = new EventEmitter();
|
|
21626
21628
|
afterDelete = new EventEmitter();
|
|
21627
21629
|
deleteError = new EventEmitter();
|
|
@@ -21645,6 +21647,36 @@ class PraxisTable {
|
|
|
21645
21647
|
measuredInline = 0;
|
|
21646
21648
|
resizeObserver;
|
|
21647
21649
|
getActionId = getActionId;
|
|
21650
|
+
// Centralized schema status state for internal use/testing; hosts should use outputs
|
|
21651
|
+
schemaStatusSubject = new BehaviorSubject(null);
|
|
21652
|
+
emitSchemaStatus(status, reason) {
|
|
21653
|
+
try {
|
|
21654
|
+
this.schemaStatusSubject.next(status);
|
|
21655
|
+
}
|
|
21656
|
+
catch { }
|
|
21657
|
+
try {
|
|
21658
|
+
this.schemaStatusChange.emit(status);
|
|
21659
|
+
}
|
|
21660
|
+
catch { }
|
|
21661
|
+
if (this.isDebug()) {
|
|
21662
|
+
try {
|
|
21663
|
+
console.debug('[PraxisTable] schema:status', { ...status, reason });
|
|
21664
|
+
}
|
|
21665
|
+
catch { }
|
|
21666
|
+
}
|
|
21667
|
+
}
|
|
21668
|
+
emitMetadataChange(reason) {
|
|
21669
|
+
try {
|
|
21670
|
+
this.metadataChange.emit({ meta: this.config?.meta ?? null, reason });
|
|
21671
|
+
}
|
|
21672
|
+
catch { }
|
|
21673
|
+
if (this.isDebug()) {
|
|
21674
|
+
try {
|
|
21675
|
+
console.debug('[PraxisTable] schema:metadata', { reason, meta: this.config?.meta });
|
|
21676
|
+
}
|
|
21677
|
+
catch { }
|
|
21678
|
+
}
|
|
21679
|
+
}
|
|
21648
21680
|
// Row menu icon helpers (customizable via config.actions.row.menuIcon and optional menuButtonColor)
|
|
21649
21681
|
getRowMenuIcon() {
|
|
21650
21682
|
try {
|
|
@@ -21861,7 +21893,7 @@ class PraxisTable {
|
|
|
21861
21893
|
const hash = this.config?.meta?.serverHash;
|
|
21862
21894
|
this.setOutdatedSnooze(hash, until);
|
|
21863
21895
|
this.schemaOutdated = false;
|
|
21864
|
-
this.
|
|
21896
|
+
this.emitSchemaStatus({ outdated: false, serverHash: hash, lastVerifiedAt: this.config?.meta?.lastVerifiedAt, resourcePath: this.resourcePath }, 'snackbar-dismiss');
|
|
21865
21897
|
this.cdr.markForCheck();
|
|
21866
21898
|
});
|
|
21867
21899
|
this.setOutdatedNotified(serverHash);
|
|
@@ -21870,7 +21902,7 @@ class PraxisTable {
|
|
|
21870
21902
|
}
|
|
21871
21903
|
// Inline banner handlers
|
|
21872
21904
|
onReconcileRequested() {
|
|
21873
|
-
this.
|
|
21905
|
+
this.emitSchemaStatus({ outdated: true, serverHash: this.config?.meta?.serverHash, lastVerifiedAt: this.config?.meta?.lastVerifiedAt, resourcePath: this.resourcePath }, 'reconcile');
|
|
21874
21906
|
// Optional auto open settings first; otherwise just open settings
|
|
21875
21907
|
this.openTableSettings();
|
|
21876
21908
|
}
|
|
@@ -21878,7 +21910,7 @@ class PraxisTable {
|
|
|
21878
21910
|
const hash = this.config?.meta?.serverHash;
|
|
21879
21911
|
this.setOutdatedIgnore(hash, true);
|
|
21880
21912
|
this.schemaOutdated = false;
|
|
21881
|
-
this.
|
|
21913
|
+
this.emitSchemaStatus({ outdated: false, serverHash: hash, lastVerifiedAt: this.config?.meta?.lastVerifiedAt, resourcePath: this.resourcePath }, 'inline-ignore');
|
|
21882
21914
|
this.cdr.markForCheck();
|
|
21883
21915
|
}
|
|
21884
21916
|
onSnoozeOutdated() {
|
|
@@ -21886,7 +21918,7 @@ class PraxisTable {
|
|
|
21886
21918
|
const until = new Date(Date.now() + Math.max(0, this.snoozeMs || 0));
|
|
21887
21919
|
this.setOutdatedSnooze(hash, until);
|
|
21888
21920
|
this.schemaOutdated = false; // hide inline banner for now
|
|
21889
|
-
this.
|
|
21921
|
+
this.emitSchemaStatus({ outdated: false, serverHash: hash, lastVerifiedAt: this.config?.meta?.lastVerifiedAt, resourcePath: this.resourcePath }, 'inline-snooze');
|
|
21890
21922
|
this.cdr.markForCheck();
|
|
21891
21923
|
}
|
|
21892
21924
|
toggleRow(row) {
|
|
@@ -22015,6 +22047,26 @@ class PraxisTable {
|
|
|
22015
22047
|
}
|
|
22016
22048
|
}
|
|
22017
22049
|
subscriptions = [];
|
|
22050
|
+
updateTableMetaFromServerInfo(info, opts) {
|
|
22051
|
+
try {
|
|
22052
|
+
const nowIso = new Date().toISOString();
|
|
22053
|
+
const meta = { ...(this.config?.meta || {}) };
|
|
22054
|
+
if (info?.schemaId)
|
|
22055
|
+
meta.schemaId = info.schemaId;
|
|
22056
|
+
if (info?.schemaHash != null)
|
|
22057
|
+
meta.serverHash = info.schemaHash;
|
|
22058
|
+
if (!meta.version)
|
|
22059
|
+
meta.version = '2.0.0';
|
|
22060
|
+
if (!meta.createdAt)
|
|
22061
|
+
meta.createdAt = nowIso;
|
|
22062
|
+
if (opts?.touchUpdatedAt !== false)
|
|
22063
|
+
meta.updatedAt = nowIso;
|
|
22064
|
+
if (opts?.updateVerifiedAt)
|
|
22065
|
+
meta.lastVerifiedAt = nowIso;
|
|
22066
|
+
this.config.meta = meta;
|
|
22067
|
+
}
|
|
22068
|
+
catch { }
|
|
22069
|
+
}
|
|
22018
22070
|
getIdField() {
|
|
22019
22071
|
// Precedence: @Input → crudContext.idField → config.meta.idField → service.getResourceIdField() → 'id'
|
|
22020
22072
|
const fromInput = this.idField || this.crudContext?.idField;
|
|
@@ -22869,7 +22921,8 @@ class PraxisTable {
|
|
|
22869
22921
|
if (this.schemaOutdated) {
|
|
22870
22922
|
this.schemaOutdated = false;
|
|
22871
22923
|
}
|
|
22872
|
-
this.
|
|
22924
|
+
this.emitMetadataChange('verification');
|
|
22925
|
+
this.emitSchemaStatus({ outdated: false, serverHash: this.config?.meta?.serverHash, lastVerifiedAt: meta.lastVerifiedAt, resourcePath: this.resourcePath }, 'verification-304');
|
|
22873
22926
|
return;
|
|
22874
22927
|
}
|
|
22875
22928
|
// status === 200: server hash changed (or first verification without hash). Do not apply columns here.
|
|
@@ -22880,7 +22933,8 @@ class PraxisTable {
|
|
|
22880
22933
|
this.configStorage.saveConfig(`table-config:${this.tableId}`, this.config);
|
|
22881
22934
|
}
|
|
22882
22935
|
catch { }
|
|
22883
|
-
this.
|
|
22936
|
+
this.emitMetadataChange('verification');
|
|
22937
|
+
this.emitSchemaStatus({ outdated: this.schemaOutdated, serverHash: meta.serverHash, lastVerifiedAt: meta.lastVerifiedAt, resourcePath: this.resourcePath }, 'verification-200');
|
|
22884
22938
|
// Notifications only if edit mode
|
|
22885
22939
|
if (this.schemaOutdated) {
|
|
22886
22940
|
if (this._resolvedPrefs.autoOpenSettingsOnOutdated) {
|
|
@@ -22923,18 +22977,7 @@ class PraxisTable {
|
|
|
22923
22977
|
// Atualizar metadados de schema (schemaId/serverHash) e idField no TableConfig (em memória)
|
|
22924
22978
|
try {
|
|
22925
22979
|
const info = this.crudService.getLastSchemaInfo();
|
|
22926
|
-
|
|
22927
|
-
if (info?.schemaId)
|
|
22928
|
-
meta.schemaId = info.schemaId;
|
|
22929
|
-
if (info?.schemaHash)
|
|
22930
|
-
meta.serverHash = info.schemaHash;
|
|
22931
|
-
if (!meta.version)
|
|
22932
|
-
meta.version = '2.0.0';
|
|
22933
|
-
if (!meta.createdAt)
|
|
22934
|
-
meta.createdAt = new Date().toISOString();
|
|
22935
|
-
meta.updatedAt = new Date().toISOString();
|
|
22936
|
-
meta.lastVerifiedAt = new Date().toISOString();
|
|
22937
|
-
this.config.meta = meta;
|
|
22980
|
+
this.updateTableMetaFromServerInfo({ schemaId: info?.schemaId, schemaHash: info?.schemaHash }, { updateVerifiedAt: true, touchUpdatedAt: true });
|
|
22938
22981
|
}
|
|
22939
22982
|
catch { }
|
|
22940
22983
|
const existing = this.config?.columns ?? [];
|
|
@@ -22944,6 +22987,20 @@ class PraxisTable {
|
|
|
22944
22987
|
.map((f) => this.convertFieldToColumn(f));
|
|
22945
22988
|
}
|
|
22946
22989
|
this.setupColumns();
|
|
22990
|
+
// Notificar hosts sobre atualização de metadados de schema ao concluir o loadSchema
|
|
22991
|
+
try {
|
|
22992
|
+
const meta = this.config?.meta || {};
|
|
22993
|
+
// Ao carregar o schema com sucesso, consideramos que não há desatualização pendente
|
|
22994
|
+
this.schemaOutdated = false;
|
|
22995
|
+
this.emitMetadataChange('bootstrap');
|
|
22996
|
+
this.emitSchemaStatus({
|
|
22997
|
+
outdated: false,
|
|
22998
|
+
serverHash: meta.serverHash,
|
|
22999
|
+
lastVerifiedAt: meta.lastVerifiedAt,
|
|
23000
|
+
resourcePath: this.resourcePath,
|
|
23001
|
+
}, 'bootstrap');
|
|
23002
|
+
}
|
|
23003
|
+
catch { }
|
|
22947
23004
|
this.cdr.detectChanges();
|
|
22948
23005
|
},
|
|
22949
23006
|
error: (err) => {
|
|
@@ -24005,7 +24062,7 @@ class PraxisTable {
|
|
|
24005
24062
|
this.dataSubject.complete();
|
|
24006
24063
|
}
|
|
24007
24064
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.4", ngImport: i0, type: PraxisTable, deps: [{ token: i1$3.GenericCrudService }, { token: i0.ChangeDetectorRef }, { token: i3$2.SettingsPanelService }, { token: DataFormattingService }, { token: CONFIG_STORAGE }, { token: CONNECTION_STORAGE }, { token: TableDefaultsProvider }, { token: i2$1.MatSnackBar }, { token: FilterConfigService }, { token: i7$2.PraxisDialog }, { token: i0.ElementRef }, { token: i1$3.GlobalConfigService }], target: i0.ɵɵFactoryTarget.Component });
|
|
24008
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.1.4", type: PraxisTable, isStandalone: true, selector: "praxis-table", inputs: { config: "config", resourcePath: "resourcePath", filterCriteria: "filterCriteria", notifyIfOutdated: "notifyIfOutdated", snoozeMs: "snoozeMs", autoOpenSettingsOnOutdated: "autoOpenSettingsOnOutdated", showToolbar: "showToolbar", toolbarV2: "toolbarV2", autoDelete: "autoDelete", editModeEnabled: "editModeEnabled", dense: "dense", tableId: "tableId", debugLayout: "debugLayout", horizontalScroll: "horizontalScroll", crudContext: "crudContext", idField: "idField" }, outputs: { rowClick: "rowClick", rowAction: "rowAction", toolbarAction: "toolbarAction", bulkAction: "bulkAction", rowDoubleClick: "rowDoubleClick", schemaStatusChange: "schemaStatusChange", beforeDelete: "beforeDelete", afterDelete: "afterDelete", deleteError: "deleteError", beforeBulkDelete: "beforeBulkDelete", afterBulkDelete: "afterBulkDelete", bulkDeleteError: "bulkDeleteError" }, host: { properties: { "class.debug-layout": "debugLayout", "class.density-compact": "config?.appearance?.density === 'compact'", "class.density-comfortable": "config?.appearance?.density === 'comfortable'", "class.density-spacious": "config?.appearance?.density === 'spacious'", "class.row-borders": "config?.appearance?.borders?.showRowBorders !== false", "class.col-borders": "!!config?.appearance?.borders?.showColumnBorders" } }, queries: [{ propertyName: "projectedFilter", first: true, predicate: PraxisFilter, descendants: true }], viewQueries: [{ propertyName: "paginator", first: true, predicate: MatPaginator, descendants: true }, { propertyName: "sort", first: true, predicate: MatSort, descendants: true }, { propertyName: "actionsHeaderCell", first: true, predicate: ["actionsHeaderCell"], descendants: true }], usesOnChanges: true, ngImport: i0, template: "<praxis-empty-state-card\n *ngIf=\"!resourcePath\"\n icon=\"link\"\n [title]=\"'Conecte a tabela \u00E0 fonte de dados'\"\n [description]=\"'Informe a rota do recurso da API para carregar colunas e dados automaticamente.'\"\n [primaryAction]=\"{ label: 'Conectar \u00E0 fonte de dados', icon: 'bolt', action: openQuickConnect.bind(this) }\"\n></praxis-empty-state-card>\n\n<!-- Error State with Quick Connect CTA -->\n<div class=\"ptable-error\" *ngIf=\"resourcePath && (schemaError || dataError)\" style=\"display:flex; align-items:center; gap:12px; padding:12px; border:1px solid var(--md-sys-color-error, #b00020); border-radius:8px; margin: 8px 0;\">\n <mat-icon color=\"warn\" aria-hidden=\"true\">error</mat-icon>\n <div style=\"flex:1\">\n <div style=\"font-weight:600\">Erro</div>\n <div>{{ errorMessage || 'Ocorreu um erro ao carregar a tabela.' }}</div>\n </div>\n <button mat-flat-button color=\"primary\" (click)=\"openQuickConnect()\">\n <mat-icon>bolt</mat-icon>\n Conectar a recurso\n </button>\n <button mat-stroked-button (click)=\"retryData()\" *ngIf=\"!schemaError\">Tentar novamente</button>\n <button mat-stroked-button (click)=\"reloadSchema()\" *ngIf=\"schemaError\">Recarregar colunas</button>\n </div>\n\n<!-- Inline banner for schema change (only in edit mode) -->\n<div *ngIf=\"shouldShowOutdatedInline()\" class=\"ptable-info-banner\" role=\"status\" aria-live=\"polite\">\n <div class=\"text\">O schema do servidor mudou. Reconciliar agora?</div>\n <div class=\"actions\">\n <button mat-stroked-button color=\"primary\" (click)=\"onReconcileRequested()\">\n <mat-icon>sync</mat-icon>\n Reconciliar\n </button>\n <button mat-button (click)=\"onSnoozeOutdated()\">Lembrar depois</button>\n <button mat-button (click)=\"onIgnoreOutdated()\">Ignorar</button>\n </div>\n </div>\n\n <ng-container *ngIf=\"resourcePath && !schemaError && !dataError && toolbarV2; else legacyHeader\">\n <div class=\"praxis-table-header\" [class.debug-layout]=\"debugLayout\" [class.edit-mode]=\"editModeEnabled\" *ngIf=\"showToolbar || editModeEnabled\">\n <praxis-table-toolbar\n *ngIf=\"showToolbar\"\n [config]=\"config\"\n [debugLayout]=\"debugLayout\"\n (toolbarAction)=\"onToolbarAction($event)\"\n (reset)=\"onResetPreferences()\"\n >\n <praxis-filter\n *ngIf=\"\n resourcePath &&\n config.behavior?.filtering?.advancedFilters?.enabled &&\n !projectedFilter\n \"\n advancedFilter\n [resourcePath]=\"resourcePath\"\n [formId]=\"tableId + '-filter'\"\n [editModeEnabled]=\"editModeEnabled\"\n [quickField]=\"\n config.behavior?.filtering?.advancedFilters?.settings?.quickField\n \"\n [alwaysVisibleFields]=\"\n config.behavior?.filtering?.advancedFilters?.settings\n ?.alwaysVisibleFields\n \"\n [allowSaveTags]=\"\n config.behavior?.filtering?.advancedFilters?.settings\n ?.allowSaveTags\n \"\n [changeDebounceMs]=\"\n config.behavior?.filtering?.advancedFilters?.settings\n ?.changeDebounceMs ?? 300\n \"\n [i18n]=\"getFilterI18n()\"\n [mode]=\"\n config.behavior?.filtering?.advancedFilters?.settings?.mode ??\n 'auto'\n \"\n [debugLayout]=\"debugLayout\"\n [showFilterSettings]=\"!editModeEnabled\"\n (submit)=\"onAdvancedFilterSubmit($event)\"\n (clear)=\"onAdvancedFilterClear()\"\n ></praxis-filter>\n <ng-content select=\"[advancedFilter]\" />\n <ng-content select=\"[toolbar]\" />\n <button end-actions mat-icon-button color=\"primary\" data-role=\"table-settings\" *ngIf=\"editModeEnabled\"\n (click)=\"openTableSettings()\" aria-label=\"Configura\u00E7\u00F5es\"\n [matBadge]=\"schemaOutdated ? '!' : ''\"\n [matBadgeHidden]=\"!schemaOutdated\"\n matBadgeColor=\"warn\" matBadgeSize=\"small\" matBadgePosition=\"above after\"\n [matTooltip]=\"schemaOutdated ? 'Schema do servidor mudou \u2014 Reconciliar' : 'Configura\u00E7\u00F5es'\"\n matTooltipPosition=\"below\">\n <mat-icon>settings</mat-icon>\n </button>\n </praxis-table-toolbar>\n <!-- Render a minimal settings button when toolbar is hidden but edit mode is enabled -->\n <div class=\"ptable-header-actions\" *ngIf=\"!showToolbar && editModeEnabled\">\n <button mat-icon-button color=\"primary\" (click)=\"openTableSettings()\" aria-label=\"Configura\u00E7\u00F5es\"\n [matBadge]=\"schemaOutdated ? '!' : ''\"\n [matBadgeHidden]=\"!schemaOutdated\"\n matBadgeColor=\"warn\" matBadgeSize=\"small\" matBadgePosition=\"above after\"\n [matTooltip]=\"schemaOutdated ? 'Schema do servidor mudou \u2014 Reconciliar' : 'Configura\u00E7\u00F5es'\"\n matTooltipPosition=\"below\">\n <mat-icon>settings</mat-icon>\n </button>\n <button mat-icon-button (click)=\"disconnect()\" aria-label=\"Desconectar\" matTooltip=\"Desconectar da fonte de dados\">\n <mat-icon>link_off</mat-icon>\n </button>\n </div>\n \n </div>\n</ng-container>\n<ng-template #legacyHeader>\n <ng-container *ngIf=\"resourcePath && !schemaError && !dataError\">\n <praxis-table-toolbar\n *ngIf=\"showToolbar\"\n [config]=\"config\"\n [debugLayout]=\"debugLayout\"\n (toolbarAction)=\"onToolbarAction($event)\"\n (reset)=\"onResetPreferences()\"\n >\n <praxis-filter\n *ngIf=\"\n resourcePath &&\n config.behavior?.filtering?.advancedFilters?.enabled &&\n !projectedFilter\n \"\n advancedFilter\n [resourcePath]=\"resourcePath\"\n [formId]=\"tableId + '-filter'\"\n [editModeEnabled]=\"editModeEnabled\"\n [quickField]=\"\n config.behavior?.filtering?.advancedFilters?.settings?.quickField\n \"\n [alwaysVisibleFields]=\"\n config.behavior?.filtering?.advancedFilters?.settings\n ?.alwaysVisibleFields\n \"\n [allowSaveTags]=\"\n config.behavior?.filtering?.advancedFilters?.settings?.allowSaveTags\n \"\n [changeDebounceMs]=\"\n config.behavior?.filtering?.advancedFilters?.settings\n ?.changeDebounceMs ?? 300\n \"\n [i18n]=\"getFilterI18n()\"\n [mode]=\"\n config.behavior?.filtering?.advancedFilters?.settings?.mode ??\n 'auto'\n \"\n [debugLayout]=\"debugLayout\"\n [showFilterSettings]=\"!editModeEnabled\"\n (submit)=\"onAdvancedFilterSubmit($event)\"\n (clear)=\"onAdvancedFilterClear()\"\n ></praxis-filter>\n <ng-content select=\"[advancedFilter]\" />\n <ng-content select=\"[toolbar]\" />\n <button end-actions mat-icon-button color=\"primary\" *ngIf=\"editModeEnabled\"\n (click)=\"openTableSettings()\" aria-label=\"Configura\u00E7\u00F5es\"\n [matBadge]=\"schemaOutdated ? '!' : ''\"\n [matBadgeHidden]=\"!schemaOutdated\"\n matBadgeColor=\"warn\" matBadgeSize=\"small\" matBadgePosition=\"above after\"\n [matTooltip]=\"schemaOutdated ? 'Schema do servidor mudou \u2014 Reconciliar' : 'Configura\u00E7\u00F5es'\"\n matTooltipPosition=\"below\">\n <mat-icon>settings</mat-icon>\n </button>\n </praxis-table-toolbar>\n <!-- Legacy header: settings button when toolbar hidden -->\n <div class=\"ptable-header-actions\" *ngIf=\"!showToolbar && editModeEnabled\">\n <button mat-icon-button color=\"primary\" data-role=\"table-settings\" (click)=\"openTableSettings()\" aria-label=\"Configura\u00E7\u00F5es\"\n [matBadge]=\"schemaOutdated ? '!' : ''\"\n [matBadgeHidden]=\"!schemaOutdated\"\n matBadgeColor=\"warn\" matBadgeSize=\"small\" matBadgePosition=\"above after\"\n [matTooltip]=\"schemaOutdated ? 'Schema do servidor mudou \u2014 Reconciliar' : 'Configura\u00E7\u00F5es'\"\n matTooltipPosition=\"below\">\n <mat-icon>settings</mat-icon>\n </button>\n </div>\n </ng-container>\n \n</ng-template>\n<div class=\"px-scroll-viewport\"\n [class.scroll-auto]=\"horizontalScroll === 'auto'\"\n [class.scroll-wrap]=\"horizontalScroll === 'wrap'\"\n [class.scroll-none]=\"horizontalScroll === 'none'\">\n\n<table\n *ngIf=\"resourcePath && !schemaError && !dataError\"\n mat-table\n [dataSource]=\"dataSource\"\n matSort\n (matSortChange)=\"onSortChange($event)\"\n [matSortDisabled]=\"!getSortingEnabled()\"\n class=\"mat-elevation-z8\"\n>\n <ng-container\n *ngIf=\"config.behavior?.selection?.enabled\"\n matColumnDef=\"_select\"\n >\n <th mat-header-cell *matHeaderCellDef>\n <mat-checkbox\n (change)=\"masterToggle()\"\n [checked]=\"isAllSelected()\"\n [indeterminate]=\"selection.hasValue() && !isAllSelected()\"\n ></mat-checkbox>\n </th>\n <td mat-cell *matCellDef=\"let row\">\n <mat-checkbox\n (click)=\"$event.stopPropagation()\"\n (change)=\"toggleRow(row)\"\n [checked]=\"selection.isSelected(row)\"\n ></mat-checkbox>\n </td>\n </ng-container>\n <ng-container\n *ngFor=\"let column of visibleColumns\"\n [matColumnDef]=\"column.field\"\n [sticky]=\"column.sticky === true || column.sticky === 'start'\"\n [stickyEnd]=\"column.sticky === 'end'\"\n >\n <th\n mat-header-cell\n *matHeaderCellDef\n mat-sort-header\n [disabled]=\"!getSortingEnabled() || column.sortable === false\"\n [style.text-align]=\"column.align\"\n [style.width]=\"column.width\"\n [attr.style]=\"column.headerStyle\"\n >\n {{ column.header }}\n </th>\n <td\n mat-cell\n *matCellDef=\"let element\"\n [style.text-align]=\"column.align\"\n [style.width]=\"column.width\"\n [attr.style]=\"column.style\"\n [ngClass]=\"getCellClasses(element, column)\"\n [ngStyle]=\"getCellNgStyle(element, column)\"\n >\n <ng-container [ngSwitch]=\"getEffectiveRendererType(element, column)\">\n <!-- Icon renderer -->\n <ng-container *ngSwitchCase=\"'icon'\">\n <mat-icon\n [color]=\"getIconColor(element, column) || null\"\n [ngStyle]=\"getIconStyle(element, column)\"\n [attr.aria-label]=\"getIconAriaLabel(element, column) || null\"\n >{{ getIconName(element, column) }}</mat-icon\n >\n </ng-container>\n\n <!-- Image renderer -->\n <ng-container *ngSwitchCase=\"'image'\">\n <img\n class=\"pfx-cell-image\"\n [src]=\"getImageSrc(element, column)\"\n [attr.alt]=\"getImageAlt(element, column) || ''\"\n [attr.loading]=\"getImageLazy(element, column) ? 'lazy' : null\"\n [style.width.px]=\"getImageWidth(element, column)\"\n [style.height.px]=\"getImageHeight(element, column)\"\n [class.shape-rounded]=\"getImageShape(element, column) === 'rounded'\"\n [class.shape-circle]=\"getImageShape(element, column) === 'circle'\"\n [style.object-fit]=\"getImageFit(element, column)\"\n />\n </ng-container>\n\n <!-- Badge renderer -->\n <ng-container *ngSwitchCase=\"'badge'\">\n <span class=\"pfx-badge\" [ngClass]=\"getBadgeClasses(element, column)\">\n <mat-icon *ngIf=\"getBadgeIcon(element, column) as bi\" class=\"pfx-badge-icon\">{{ bi }}</mat-icon>\n <span class=\"pfx-badge-text\">{{ getBadgeText(element, column) }}</span>\n </span>\n </ng-container>\n\n <!-- Link renderer -->\n <ng-container *ngSwitchCase=\"'link'\">\n <a\n class=\"pfx-link\"\n [attr.href]=\"getLinkHref(element, column) || null\"\n [attr.target]=\"getLinkTarget(element, column) || null\"\n [attr.rel]=\"getLinkRel(element, column) || null\"\n (click)=\"$event.stopPropagation()\"\n >{{ getLinkText(element, column) }}</a\n >\n </ng-container>\n\n <!-- Button renderer -->\n <ng-container *ngSwitchCase=\"'button'\">\n <ng-container [ngSwitch]=\"getButtonVariant(element, column)\">\n <button\n *ngSwitchCase=\"'outlined'\"\n mat-stroked-button\n [color]=\"getButtonColor(element, column) || null\"\n [disabled]=\"isButtonDisabled(element, column)\"\n [attr.aria-label]=\"getButtonAriaLabel(element, column) || getButtonLabel(element, column)\"\n (click)=\"onButtonClick(element, column, $event)\"\n >\n <mat-icon *ngIf=\"getButtonIcon(element, column) as bi\">{{ bi }}</mat-icon>\n {{ getButtonLabel(element, column) }}\n </button>\n <button\n *ngSwitchCase=\"'text'\"\n mat-button\n [color]=\"getButtonColor(element, column) || null\"\n [disabled]=\"isButtonDisabled(element, column)\"\n [attr.aria-label]=\"getButtonAriaLabel(element, column) || getButtonLabel(element, column)\"\n (click)=\"onButtonClick(element, column, $event)\"\n >\n <mat-icon *ngIf=\"getButtonIcon(element, column) as bi\">{{ bi }}</mat-icon>\n {{ getButtonLabel(element, column) }}\n </button>\n <button\n *ngSwitchDefault\n mat-flat-button\n [color]=\"getButtonColor(element, column) || null\"\n [disabled]=\"isButtonDisabled(element, column)\"\n [attr.aria-label]=\"getButtonAriaLabel(element, column) || getButtonLabel(element, column)\"\n (click)=\"onButtonClick(element, column, $event)\"\n >\n <mat-icon *ngIf=\"getButtonIcon(element, column) as bi\">{{ bi }}</mat-icon>\n {{ getButtonLabel(element, column) }}\n </button>\n </ng-container>\n </ng-container>\n\n <!-- Chip renderer -->\n <ng-container *ngSwitchCase=\"'chip'\">\n <span class=\"pfx-chip\" [ngClass]=\"getChipClasses(element, column)\">\n <mat-icon *ngIf=\"getChipIcon(element, column) as ci\" class=\"pfx-chip-icon\">{{ ci }}</mat-icon>\n <span class=\"pfx-chip-text\">{{ getChipText(element, column) }}</span>\n </span>\n </ng-container>\n\n <!-- Progress renderer -->\n <ng-container *ngSwitchCase=\"'progress'\">\n <div class=\"pfx-progress\">\n <div class=\"pfx-progress-bar\" [style.width.%]=\"getProgressValue(element, column)\" [style.background]=\"getProgressColor(element, column) || null\"></div>\n <div class=\"pfx-progress-label\" *ngIf=\"getProgressShowLabel(element, column)\">{{ getProgressValue(element, column) }}%</div>\n </div>\n </ng-container>\n\n <!-- Avatar renderer -->\n <ng-container *ngSwitchCase=\"'avatar'\">\n <ng-container *ngIf=\"getAvatarSrc(element, column) as asrc; else initials\">\n <img class=\"pfx-avatar\" [src]=\"asrc\" [attr.alt]=\"getAvatarAlt(element, column) || ''\" [ngStyle]=\"getAvatarStyle(element, column)\" [class.shape-rounded]=\"getAvatarShape(element, column) === 'rounded'\" [class.shape-circle]=\"getAvatarShape(element, column) === 'circle'\" loading=\"lazy\" />\n </ng-container>\n <ng-template #initials>\n <span class=\"pfx-avatar pfx-avatar--initials\" [ngStyle]=\"getAvatarStyle(element, column)\" [class.shape-rounded]=\"getAvatarShape(element, column) === 'rounded'\" [class.shape-circle]=\"getAvatarShape(element, column) === 'circle'\">{{ getAvatarInitials(element, column) }}</span>\n </ng-template>\n </ng-container>\n\n <!-- Toggle renderer -->\n <ng-container *ngSwitchCase=\"'toggle'\">\n <mat-slide-toggle\n [checked]=\"getToggleState(element, column)\"\n [disabled]=\"isToggleDisabled(element, column)\"\n [attr.aria-label]=\"getToggleAriaLabel(element, column) || 'Alternar'\"\n (change)=\"onToggleChange(element, column, $event)\"\n (click)=\"$event.stopPropagation()\"\n ></mat-slide-toggle>\n </ng-container>\n\n <!-- Menu renderer -->\n <ng-container *ngSwitchCase=\"'menu'\">\n <button mat-icon-button [matMenuTriggerFor]=\"menuRef\" (click)=\"$event.stopPropagation()\" [attr.aria-label]=\"getMenuAriaLabel(element, column) || 'Menu'\">\n <mat-icon>more_vert</mat-icon>\n </button>\n <mat-menu #menuRef=\"matMenu\">\n <button mat-menu-item *ngFor=\"let it of getMenuItems(element, column)\" (click)=\"onMenuItemClick(it.id, element, $event)\" [disabled]=\"!it.__visible\" >\n <mat-icon *ngIf=\"it.icon\">{{ it.icon }}</mat-icon>\n <span>{{ it.label }}</span>\n </button>\n </mat-menu>\n </ng-container>\n\n <!-- HTML renderer (sanitizado) -->\n <ng-container *ngSwitchCase=\"'html'\">\n <span [innerHTML]=\"getSafeHtml(element, column)\"></span>\n </ng-container>\n\n <!-- Compose renderer -->\n <ng-container *ngSwitchCase=\"'compose'\">\n <span class=\"pfx-cell-compose\" [ngClass]=\"getComposeClasses(element, column)\" [ngStyle]=\"getComposeGapStyle(element, column)\">\n <ng-container *ngFor=\"let it of getComposeItems(element, column)\">\n <ng-container [ngSwitch]=\"getItemEffectiveType(element, column, it)\">\n <!-- Reuse helpers by projecting item as faux column -->\n <ng-container *ngSwitchCase=\"'icon'\">\n <mat-icon [color]=\"getIconColor(element, asItemColumn(column, it)) || null\" [ngStyle]=\"getIconStyle(element, asItemColumn(column, it))\" [attr.aria-label]=\"getIconAriaLabel(element, asItemColumn(column, it)) || null\">{{ getIconName(element, asItemColumn(column, it)) }}</mat-icon>\n </ng-container>\n <ng-container *ngSwitchCase=\"'image'\">\n <img class=\"pfx-cell-image\" [src]=\"getImageSrc(element, asItemColumn(column, it))\" [attr.alt]=\"getImageAlt(element, asItemColumn(column, it)) || ''\" [attr.loading]=\"getImageLazy(element, asItemColumn(column, it)) ? 'lazy' : null\" [style.width.px]=\"getImageWidth(element, asItemColumn(column, it))\" [style.height.px]=\"getImageHeight(element, asItemColumn(column, it))\" [class.shape-rounded]=\"getImageShape(element, asItemColumn(column, it)) === 'rounded'\" [class.shape-circle]=\"getImageShape(element, asItemColumn(column, it)) === 'circle'\" [style.object-fit]=\"getImageFit(element, asItemColumn(column, it))\" />\n </ng-container>\n <ng-container *ngSwitchCase=\"'badge'\">\n <span class=\"pfx-badge\" [ngClass]=\"getBadgeClasses(element, asItemColumn(column, it))\"><mat-icon *ngIf=\"getBadgeIcon(element, asItemColumn(column, it)) as bi\" class=\"pfx-badge-icon\">{{ bi }}</mat-icon><span class=\"pfx-badge-text\">{{ getBadgeText(element, asItemColumn(column, it)) }}</span></span>\n </ng-container>\n <ng-container *ngSwitchCase=\"'link'\">\n <a class=\"pfx-link\" [attr.href]=\"getLinkHref(element, asItemColumn(column, it)) || null\" [attr.target]=\"getLinkTarget(element, asItemColumn(column, it)) || null\" [attr.rel]=\"getLinkRel(element, asItemColumn(column, it)) || null\" (click)=\"$event.stopPropagation()\">{{ getLinkText(element, asItemColumn(column, it)) }}</a>\n </ng-container>\n <ng-container *ngSwitchCase=\"'button'\">\n <ng-container [ngSwitch]=\"getButtonVariant(element, asItemColumn(column, it))\">\n <button *ngSwitchCase=\"'outlined'\" mat-stroked-button [color]=\"getButtonColor(element, asItemColumn(column, it)) || null\" [disabled]=\"isButtonDisabled(element, asItemColumn(column, it))\" [attr.aria-label]=\"getButtonAriaLabel(element, asItemColumn(column, it)) || getButtonLabel(element, asItemColumn(column, it))\" (click)=\"onButtonClick(element, asItemColumn(column, it), $event)\"><mat-icon *ngIf=\"getButtonIcon(element, asItemColumn(column, it)) as bi\">{{ bi }}</mat-icon>{{ getButtonLabel(element, asItemColumn(column, it)) }}</button>\n <button *ngSwitchCase=\"'text'\" mat-button [color]=\"getButtonColor(element, asItemColumn(column, it)) || null\" [disabled]=\"isButtonDisabled(element, asItemColumn(column, it))\" [attr.aria-label]=\"getButtonAriaLabel(element, asItemColumn(column, it)) || getButtonLabel(element, asItemColumn(column, it))\" (click)=\"onButtonClick(element, asItemColumn(column, it), $event)\"><mat-icon *ngIf=\"getButtonIcon(element, asItemColumn(column, it)) as bi\">{{ bi }}</mat-icon>{{ getButtonLabel(element, asItemColumn(column, it)) }}</button>\n <button *ngSwitchDefault mat-flat-button [color]=\"getButtonColor(element, asItemColumn(column, it)) || null\" [disabled]=\"isButtonDisabled(element, asItemColumn(column, it))\" [attr.aria-label]=\"getButtonAriaLabel(element, asItemColumn(column, it)) || getButtonLabel(element, asItemColumn(column, it))\" (click)=\"onButtonClick(element, asItemColumn(column, it), $event)\"><mat-icon *ngIf=\"getButtonIcon(element, asItemColumn(column, it)) as bi\">{{ bi }}</mat-icon>{{ getButtonLabel(element, asItemColumn(column, it)) }}</button>\n </ng-container>\n </ng-container>\n <ng-container *ngSwitchCase=\"'chip'\">\n <span class=\"pfx-chip\" [ngClass]=\"getChipClasses(element, asItemColumn(column, it))\"><mat-icon *ngIf=\"getChipIcon(element, asItemColumn(column, it)) as ci\" class=\"pfx-chip-icon\">{{ ci }}</mat-icon><span class=\"pfx-chip-text\">{{ getChipText(element, asItemColumn(column, it)) }}</span></span>\n </ng-container>\n <ng-container *ngSwitchCase=\"'progress'\">\n <div class=\"pfx-progress\"><div class=\"pfx-progress-bar\" [style.width.%]=\"getProgressValue(element, asItemColumn(column, it))\" [style.background]=\"getProgressColor(element, asItemColumn(column, it)) || null\"></div><div class=\"pfx-progress-label\" *ngIf=\"getProgressShowLabel(element, asItemColumn(column, it))\">{{ getProgressValue(element, asItemColumn(column, it)) }}%</div></div>\n </ng-container>\n <ng-container *ngSwitchCase=\"'avatar'\">\n <ng-container *ngIf=\"getAvatarSrc(element, asItemColumn(column, it)) as asrc; else initials_comp\">\n <img class=\"pfx-avatar\" [src]=\"asrc\" [attr.alt]=\"getAvatarAlt(element, asItemColumn(column, it)) || ''\" [ngStyle]=\"getAvatarStyle(element, asItemColumn(column, it))\" [class.shape-rounded]=\"getAvatarShape(element, asItemColumn(column, it)) === 'rounded'\" [class.shape-circle]=\"getAvatarShape(element, asItemColumn(column, it)) === 'circle'\" loading=\"lazy\" />\n </ng-container>\n <ng-template #initials_comp>\n <span class=\"pfx-avatar pfx-avatar--initials\" [ngStyle]=\"getAvatarStyle(element, asItemColumn(column, it))\" [class.shape-rounded]=\"getAvatarShape(element, asItemColumn(column, it)) === 'rounded'\" [class.shape-circle]=\"getAvatarShape(element, asItemColumn(column, it)) === 'circle'\">{{ getAvatarInitials(element, asItemColumn(column, it)) }}</span>\n </ng-template>\n </ng-container>\n <ng-container *ngSwitchCase=\"'toggle'\">\n <mat-slide-toggle [checked]=\"getToggleState(element, asItemColumn(column, it))\" [disabled]=\"isToggleDisabled(element, asItemColumn(column, it))\" [attr.aria-label]=\"getToggleAriaLabel(element, asItemColumn(column, it)) || 'Alternar'\" (change)=\"onToggleChange(element, asItemColumn(column, it), $event)\" (click)=\"$event.stopPropagation()\"></mat-slide-toggle>\n </ng-container>\n <ng-container *ngSwitchCase=\"'menu'\">\n <button mat-icon-button [matMenuTriggerFor]=\"menuRef\" (click)=\"$event.stopPropagation()\" [attr.aria-label]=\"getMenuAriaLabel(element, asItemColumn(column, it)) || 'Menu'\"><mat-icon>more_vert</mat-icon></button>\n <mat-menu #menuRef=\"matMenu\">\n <button mat-menu-item *ngFor=\"let mi of getMenuItems(element, asItemColumn(column, it))\" (click)=\"onMenuItemClick(mi.id, element, $event)\" [disabled]=\"!mi.__visible\"><mat-icon *ngIf=\"mi.icon\">{{ mi.icon }}</mat-icon><span>{{ mi.label }}</span></button>\n </mat-menu>\n </ng-container>\n <ng-container *ngSwitchCase=\"'html'\">\n <span [innerHTML]=\"getSafeHtml(element, asItemColumn(column, it))\"></span>\n </ng-container>\n <!-- Value item: render base cell text alongside visuals -->\n <ng-container *ngSwitchCase=\"'value'\">\n <span class=\"pfx-cell-value\">{{ getCellValue(element, column) }}</span>\n </ng-container>\n </ng-container>\n </ng-container>\n </span>\n </ng-container>\n\n <!-- Default text rendering -->\n <ng-container *ngSwitchDefault>\n {{ getCellValue(element, column) }}\n </ng-container>\n </ng-container>\n </td>\n </ng-container>\n <ng-container *ngIf=\"config.actions?.row?.enabled\" matColumnDef=\"_actions\" [sticky]=\"config.actions?.row?.sticky === true || config.actions?.row?.sticky === 'start'\" [stickyEnd]=\"config.actions?.row?.sticky === 'end'\">\n <th mat-header-cell *matHeaderCellDef #actionsHeaderCell [style.width]=\"config.actions?.row?.width\" class=\"praxis-actions-header\" [class.align-start]=\"getActionsHeaderAlign() === 'start'\" [class.align-center]=\"getActionsHeaderAlign() === 'center'\" [class.align-end]=\"getActionsHeaderAlign() === 'end'\">\n <div class=\"praxis-actions-header__content\" [matTooltip]=\"getActionsHeaderTooltip() || ''\" [matTooltipDisabled]=\"!getActionsHeaderTooltip()\">\n <mat-icon *ngIf=\"getActionsHeaderIcon() as hi\" [praxisIcon]=\"hi\"></mat-icon>\n <span class=\"label\" *ngIf=\"getActionsHeaderLabel() as hl\">{{ hl }}</span>\n </div>\n </th>\n <td\n mat-cell\n *matCellDef=\"let row\"\n class=\"praxis-actions-cell\"\n [class.dense]=\"dense\"\n [style.width]=\"config.actions?.row?.width\"\n >\n <div class=\"praxis-actions-cell__content\">\n <!-- A\u00E7\u00F5es inline -->\n <!-- Inline actions: icons mode -->\n <ng-container *ngIf=\"config.actions?.row?.display === 'icons' || !config.actions?.row?.display\">\n <ng-container *ngFor=\"let a of getInlineRowActions(row); trackBy: trackAction\">\n <button\n mat-icon-button\n class=\"praxis-icon-btn\"\n [disabled]=\"isActionDisabled(a, row)\"\n (click)=\"onRowAction(getActionId(a), row, $event)\"\n [matTooltip]=\"a.label || getActionId(a)\"\n matTooltipPosition=\"above\"\n matTooltipClass=\"praxis-tooltip\"\n [attr.aria-label]=\"a.label || getActionId(a)\"\n [color]=\"a.color || null\"\n >\n <mat-icon [praxisIcon]=\"a.icon\"></mat-icon>\n </button>\n </ng-container>\n </ng-container>\n\n <!-- Inline actions: buttons mode (show label + icon) -->\n <ng-container *ngIf=\"config.actions?.row?.display === 'buttons'\">\n <ng-container *ngFor=\"let a of getInlineRowActions(row); trackBy: trackAction\">\n <button\n mat-flat-button\n class=\"praxis-row-btn\"\n [disabled]=\"isActionDisabled(a, row)\"\n (click)=\"onRowAction(getActionId(a), row, $event)\"\n [attr.aria-label]=\"a.label || getActionId(a)\"\n [color]=\"a.color || null\"\n >\n <mat-icon [praxisIcon]=\"a.icon\"></mat-icon>\n <span>{{ a.label || getActionId(a) }}</span>\n </button>\n </ng-container>\n </ng-container>\n\n <!-- Menu de overflow -->\n <button\n mat-icon-button\n class=\"praxis-icon-btn praxis-more-btn\"\n *ngIf=\"hasOverflowRowActions(row)\"\n [matMenuTriggerFor]=\"rowMoreMenu\"\n [color]=\"getRowMenuButtonColor() || null\"\n aria-label=\"Mais a\u00E7\u00F5es\"\n >\n <mat-icon [praxisIcon]=\"getRowMenuIcon()\"></mat-icon>\n </button>\n <mat-menu #rowMoreMenu=\"matMenu\" xPosition=\"before\">\n <ng-container\n *ngFor=\"let a of getOverflowRowActions(row); trackBy: trackAction\"\n >\n <button\n mat-menu-item\n (click)=\"onRowAction(getActionId(a), row, $event)\"\n [disabled]=\"isActionDisabled(a, row)\"\n >\n <mat-icon [color]=\"a.color || null\" [praxisIcon]=\"a.icon\"></mat-icon>\n <span>{{ a.label || getActionId(a) }}</span>\n </button>\n </ng-container>\n </mat-menu>\n </div>\n </td>\n </ng-container>\n\n <tr mat-header-row *matHeaderRowDef=\"displayedColumns\"></tr>\n <ng-container *ngIf=\"!isVirtualized()\">\n <tr\n mat-row\n *matRowDef=\"let row; let i = index; columns: displayedColumns\"\n [ngClass]=\"getRowClasses(row)\"\n [ngStyle]=\"getRowNgStyle(row)\"\n [matTooltip]=\"getRowTooltip(row) || null\"\n [matTooltipDisabled]=\"!getRowTooltip(row)\"\n [matTooltipPosition]=\"getRowTooltipPosition(row)\"\n [matTooltipShowDelay]=\"getRowTooltipShowDelay(row)\"\n (click)=\"onRowClicked(row, i)\"\n (dblclick)=\"onRowDoubleClicked(row, i)\"\n ></tr>\n </ng-container>\n</table>\n\n<!-- Virtual rows path (header preserved above) -->\n<ng-container *ngIf=\"resourcePath && !schemaError && !dataError && isVirtualized()\">\n <cdk-virtual-scroll-viewport\n class=\"ptable-viewport\"\n [itemSize]=\"getVirtItemHeight()\"\n [minBufferPx]=\"getVirtBufferSize() * getVirtItemHeight()\"\n [maxBufferPx]=\"getVirtBufferSize() * getVirtItemHeight() * 2\"\n [style.minHeight]=\"getVirtMinHeightStyle()\"\n >\n <table class=\"mat-mdc-table mat-elevation-z8\" [style.width]=\"horizontalScroll === 'auto' ? 'max-content' : '100%'\">\n <tbody>\n <tr class=\"mat-mdc-row\"\n *cdkVirtualFor=\"let row of dataSource.data; let i = index; trackBy: trackByRow\"\n [ngClass]=\"getRowClasses(row)\"\n [ngStyle]=\"getRowNgStyle(row)\"\n [matTooltip]=\"getRowTooltip(row) || null\"\n [matTooltipDisabled]=\"!getRowTooltip(row)\"\n [matTooltipPosition]=\"getRowTooltipPosition(row)\"\n [matTooltipShowDelay]=\"getRowTooltipShowDelay(row)\"\n (click)=\"onRowClicked(row, i)\"\n (dblclick)=\"onRowDoubleClicked(row, i)\">\n <!-- Selection column -->\n <td class=\"mat-mdc-cell\" *ngIf=\"config.behavior?.selection?.enabled\">\n <mat-checkbox\n (click)=\"$event.stopPropagation()\"\n (change)=\"toggleRow(row)\"\n [checked]=\"selection.isSelected(row)\">\n </mat-checkbox>\n </td>\n <!-- Data columns -->\n <td class=\"mat-mdc-cell\"\n *ngFor=\"let column of visibleColumns\"\n [style.text-align]=\"column.align\"\n [style.width]=\"column.width\"\n [attr.style]=\"column.style\"\n [ngClass]=\"getCellClasses(row, column)\"\n [ngStyle]=\"getCellNgStyle(row, column)\">\n <ng-container [ngSwitch]=\"getEffectiveRendererType(row, column)\">\n <ng-container *ngSwitchCase=\"'icon'\">\n <mat-icon [color]=\"getIconColor(row, column) || null\"\n [ngStyle]=\"getIconStyle(row, column)\"\n [attr.aria-label]=\"getIconAriaLabel(row, column) || null\">\n {{ getIconName(row, column) }}\n </mat-icon>\n </ng-container>\n <ng-container *ngSwitchCase=\"'image'\">\n <img class=\"pfx-cell-image\"\n [src]=\"getImageSrc(row, column)\"\n [attr.alt]=\"getImageAlt(row, column) || ''\"\n [attr.loading]=\"getImageLazy(row, column) ? 'lazy' : null\"\n [style.width.px]=\"getImageWidth(row, column)\"\n [style.height.px]=\"getImageHeight(row, column)\"\n [class.shape-rounded]=\"getImageShape(row, column) === 'rounded'\"\n [class.shape-circle]=\"getImageShape(row, column) === 'circle'\"\n [style.object-fit]=\"getImageFit(row, column)\" />\n </ng-container>\n <ng-container *ngSwitchCase=\"'badge'\">\n <span class=\"pfx-badge\" [ngClass]=\"getBadgeClasses(row, column)\">\n <mat-icon *ngIf=\"getBadgeIcon(row, column) as bi\" class=\"pfx-badge-icon\">{{ bi }}</mat-icon>\n <span class=\"pfx-badge-text\">{{ getBadgeText(row, column) }}</span>\n </span>\n </ng-container>\n <ng-container *ngSwitchDefault>\n {{ getCellValue(row, column) }}\n </ng-container>\n </ng-container>\n </td>\n\n <!-- Actions column -->\n <td class=\"mat-mdc-cell praxis-actions-cell\" *ngIf=\"config.actions?.row?.enabled\" [class.dense]=\"dense\" [style.width]=\"config.actions?.row?.width\">\n <div class=\"praxis-actions-cell__content\">\n <ng-container *ngIf=\"config.actions?.row?.display === 'icons' || !config.actions?.row?.display\">\n <ng-container *ngFor=\"let a of getInlineRowActions(row); trackBy: trackAction\">\n <button mat-icon-button class=\"praxis-icon-btn\"\n [disabled]=\"isActionDisabled(a, row)\"\n (click)=\"onRowAction(getActionId(a), row, $event)\"\n [matTooltip]=\"a.label || getActionId(a)\"\n matTooltipPosition=\"above\"\n matTooltipClass=\"praxis-tooltip\"\n [attr.aria-label]=\"a.label || getActionId(a)\"\n [color]=\"a.color || null\">\n <mat-icon [praxisIcon]=\"a.icon\"></mat-icon>\n </button>\n </ng-container>\n </ng-container>\n <ng-container *ngIf=\"config.actions?.row?.display === 'buttons'\">\n <ng-container *ngFor=\"let a of getInlineRowActions(row); trackBy: trackAction\">\n <button mat-flat-button class=\"praxis-row-btn\"\n [disabled]=\"isActionDisabled(a, row)\"\n (click)=\"onRowAction(getActionId(a), row, $event)\"\n [attr.aria-label]=\"a.label || getActionId(a)\"\n [color]=\"a.color || null\">\n <mat-icon [praxisIcon]=\"a.icon\"></mat-icon>\n <span>{{ a.label || getActionId(a) }}</span>\n </button>\n </ng-container>\n </ng-container>\n <button mat-icon-button class=\"praxis-icon-btn praxis-more-btn\"\n *ngIf=\"hasOverflowRowActions(row)\"\n [matMenuTriggerFor]=\"rowMoreMenuV\"\n [color]=\"getRowMenuButtonColor() || null\"\n aria-label=\"Mais a\u00E7\u00F5es\">\n <mat-icon [praxisIcon]=\"getRowMenuIcon()\"></mat-icon>\n </button>\n <mat-menu #rowMoreMenuV=\"matMenu\" xPosition=\"before\">\n <ng-container *ngFor=\"let a of getOverflowRowActions(row); trackBy: trackAction\">\n <button mat-menu-item (click)=\"onRowAction(getActionId(a), row, $event)\" [disabled]=\"isActionDisabled(a, row)\">\n <mat-icon [color]=\"a.color || null\" [praxisIcon]=\"a.icon\"></mat-icon>\n <span>{{ a.label || getActionId(a) }}</span>\n </button>\n </ng-container>\n </mat-menu>\n </div>\n </td>\n </tr>\n </tbody>\n </table>\n </cdk-virtual-scroll-viewport>\n</ng-container>\n\n</div>\n<!-- Paginadores (top/bottom) -->\n<mat-paginator\n *ngIf=\"resourcePath && !schemaError && !dataError && getPaginationEnabled() && (config.behavior?.pagination?.position === 'top' || config.behavior?.pagination?.position === 'both')\"\n [length]=\"getPaginationLength()\"\n [pageSize]=\"getPaginationPageSize()\"\n [pageSizeOptions]=\"getPaginationPageSizeOptions()\"\n [showFirstLastButtons]=\"getPaginationShowFirstLast()\"\n (page)=\"onPageChange($event)\"\n [class.compact]=\"config.behavior?.pagination?.style === 'compact'\"\n>\n</mat-paginator>\n\n<mat-paginator\n *ngIf=\"resourcePath && !schemaError && !dataError && getPaginationEnabled() && (config.behavior?.pagination?.position === 'bottom' || config.behavior?.pagination?.position === 'both' || !config.behavior?.pagination?.position)\"\n [length]=\"getPaginationLength()\"\n [pageSize]=\"getPaginationPageSize()\"\n [pageSizeOptions]=\"getPaginationPageSizeOptions()\"\n [showFirstLastButtons]=\"getPaginationShowFirstLast()\"\n (page)=\"onPageChange($event)\"\n [class.compact]=\"config.behavior?.pagination?.style === 'compact'\"\n>\n</mat-paginator>\n", styles: ["@charset \"UTF-8\";table{width:100%}.praxis-actions-cell{height:100%;padding-inline:12px;white-space:nowrap}:host.density-compact{--p-header-padding: 8px 12px;--p-actions-btn-size: 32px;--p-actions-icon-size: 18px}:host.density-comfortable{--p-header-padding: 12px 16px;--p-actions-btn-size: 40px;--p-actions-icon-size: 22px}:host.density-spacious{--p-header-padding: 16px 20px;--p-actions-btn-size: 44px;--p-actions-icon-size: 24px}:host.density-compact ::ng-deep .mat-mdc-cell{padding:8px 12px}:host.density-comfortable ::ng-deep .mat-mdc-cell{padding:12px 16px}:host.density-spacious ::ng-deep .mat-mdc-cell{padding:16px 20px}:host.density-compact .praxis-actions-cell{padding-inline:8px}:host.density-spacious .praxis-actions-cell{padding-inline:16px}.praxis-actions-cell__content{display:flex;align-items:center;justify-content:flex-end;gap:8px;width:100%}.praxis-actions-cell.dense .praxis-actions-cell__content{gap:6px}.praxis-icon-btn{width:var(--p-actions-btn-size, 40px);height:var(--p-actions-btn-size, 40px);border:0;background:transparent;padding:0;display:inline-flex;align-items:center;justify-content:center;border-radius:9999px;cursor:pointer;--mat-icon-button-state-layer-size: var(--p-actions-btn-size, 40px)}.praxis-icon-btn:hover{background:var(--md-sys-color-surface-variant, rgba(255, 255, 255, .06))}.praxis-icon-btn:focus-visible{outline:2px solid var(--primary, #48a1ff);outline-offset:2px}.praxis-icon-btn mat-icon,.praxis-icon-btn .mat-icon{font-size:var(--p-actions-icon-size, 22px);width:var(--p-actions-icon-size, 22px);height:var(--p-actions-icon-size, 22px);line-height:var(--p-actions-icon-size, 22px)}.praxis-more-btn{width:var(--p-actions-more-btn-size, var(--p-actions-btn-size, 40px));height:var(--p-actions-more-btn-size, var(--p-actions-btn-size, 40px));--mat-icon-button-state-layer-size: var(--p-actions-more-btn-size, var(--p-actions-btn-size, 40px));background-image:var(--p-actions-more-btn-gradient, none);background-size:100% 100%;background-repeat:no-repeat}.praxis-more-btn mat-icon,.praxis-more-btn .mat-icon{font-size:var(--p-actions-more-icon-size, var(--p-actions-icon-size, 22px));width:var(--p-actions-more-icon-size, var(--p-actions-icon-size, 22px));height:var(--p-actions-more-icon-size, var(--p-actions-icon-size, 22px));line-height:var(--p-actions-more-icon-size, var(--p-actions-icon-size, 22px));color:var(--p-actions-more-icon-color);background-image:var(--p-actions-more-icon-gradient, none);-webkit-background-clip:text;background-clip:text}.praxis-icon-btn.destructive mat-icon{color:#ff6b6b}.mat-mdc-tooltip.praxis-tooltip{margin-top:-8px;margin-bottom:8px}.spacer{flex:1 1 auto}.praxis-table-header{display:flex;flex-wrap:wrap;align-items:flex-start;gap:8px;margin:16px 0 12px;width:100%;clear:both;position:relative}.praxis-table-header.debug-layout,:host.debug-layout .praxis-table-header{outline:2px dashed #ff4d4f;border-radius:8px}:host.debug-layout ::ng-deep .praxis-filter-bar{outline:1px dashed #f59e0b}:host.debug-layout ::ng-deep .quick-shell{outline:1px dashed #3b82f6}:host.debug-layout ::ng-deep .always-fields{outline:1px dashed #22c55e}:host.debug-layout ::ng-deep .praxis-filter-overlay .praxis-filter-advanced{outline:2px solid #a855f7}:host.debug-layout ::ng-deep .mat-mdc-table{outline:1px dashed #94a3b8}.praxis-table-header>praxis-table-toolbar{flex:1 0 100%}:host{--p-table-header-bg: var(--md-sys-color-surface-container-highest, #1d1d1f);--p-table-header-fg: var(--md-sys-color-on-surface, #e8f3f1);--p-table-border-color: var(--md-sys-color-outline-variant, rgba(255, 255, 255, .12));--p-table-row-even-bg: var(--md-sys-color-surface-container, rgba(255, 255, 255, .04));--p-table-row-hover-bg: color-mix(in srgb, var(--md-sys-color-primary, #3f51b5) 10%, transparent);--p-table-row-selected-bg: var(--md-sys-color-primary-container, rgba(63,81,181,.14));--p-table-badge-soft-primary-bg: color-mix(in srgb, var(--mat-sys-primary, var(--md-sys-color-primary)) 16%, transparent);--p-table-badge-soft-primary-fg: var(--mat-sys-primary, var(--md-sys-color-primary));--p-table-badge-soft-accent-bg: color-mix(in srgb, var(--mat-sys-secondary, var(--md-sys-color-secondary, #ff4081)) 14%, transparent);--p-table-badge-soft-accent-fg: var(--mat-sys-secondary, var(--md-sys-color-secondary, #ff4081));--p-table-badge-soft-warn-bg: color-mix(in srgb, var(--mat-sys-error, var(--md-sys-color-error, #f44336)) 14%, transparent);--p-table-badge-soft-warn-fg: var(--mat-sys-error, var(--md-sys-color-error, #f44336));--p-table-state-success-bg: color-mix(in srgb, var(--mat-sys-tertiary, var(--md-sys-color-tertiary, #388E3C)) 16%, transparent);--p-table-state-success-fg: var(--md-sys-color-on-surface, #c8e6c9);--p-table-state-warning-bg: color-mix(in srgb, var(--md-sys-color-secondary, #FFA000) 18%, transparent);--p-table-state-warning-fg: var(--md-sys-color-on-surface, #ffe0b2);--p-table-state-danger-bg: color-mix(in srgb, var(--md-sys-color-error, #e53935) 18%, transparent);--p-table-state-danger-fg: var(--md-sys-color-on-surface, #ffcdd2);--p-table-state-highlight-bg: color-mix(in srgb, var(--md-sys-color-primary, #2196f3) 16%, transparent);--p-table-state-highlight-fg: var(--md-sys-color-on-surface, #bbdefb)}:host ::ng-deep .mat-mdc-table{background:var(--md-sys-color-surface-container-highest, #1d1d1f);border-radius:12px;width:100%}:host [data-role=table-settings].mat-mdc-icon-button{--mdc-icon-button-icon-color: var(--mat-sys-primary, var(--md-sys-color-primary, #3f51b5));color:var(--mat-sys-primary, var(--md-sys-color-primary, #3f51b5))}.pfx-link{color:var(--mat-sys-primary, #3f51b5);text-decoration:underline;cursor:pointer}.pfx-chip{display:inline-flex;align-items:center;gap:4px;padding:2px 8px;border-radius:10px;font-size:12px;line-height:1;border:1px solid transparent}.pfx-chip-icon{font-size:14px;width:14px;height:14px}.pfx-chip--outlined{background:transparent;border-color:var(--mat-sys-outline-variant);color:var(--mat-sys-on-surface)}.pfx-chip--filled-primary{background:var(--mat-sys-primary);color:var(--mat-sys-on-primary)}.pfx-chip--filled-accent{background:var(--mat-sys-secondary, #ff4081);color:#fff}.pfx-chip--filled-warn{background:var(--mat-sys-error, #f44336);color:#fff}.pfx-chip--soft-primary{background:var(--p-table-badge-soft-primary-bg);color:var(--p-table-badge-soft-primary-fg)}.pfx-chip--soft-accent{background:var(--p-table-badge-soft-accent-bg);color:var(--p-table-badge-soft-accent-fg)}.pfx-chip--soft-warn{background:var(--p-table-badge-soft-warn-bg);color:var(--p-table-badge-soft-warn-fg)}.pfx-progress{position:relative;width:100%;max-width:140px;height:8px;background:var(--mat-sys-surface-container-highest, rgba(255, 255, 255, .08));border-radius:4px;overflow:hidden;display:inline-block;vertical-align:middle}.pfx-progress-bar{height:100%;background:var(--mat-sys-primary);transition:width .2s ease}.pfx-progress-label{margin-left:8px;font-size:12px;opacity:.8;display:inline-block;vertical-align:middle}.pfx-avatar{display:inline-flex;align-items:center;justify-content:center;background:var(--mat-sys-surface-container, #2a2a2e);color:var(--mat-sys-on-surface, #eee);border-radius:4px;overflow:hidden;font-weight:600}.pfx-avatar.shape-rounded{border-radius:8px}.pfx-avatar.shape-circle{border-radius:999px}.pfx-avatar--initials{text-transform:uppercase;font-size:12px}.pfx-cell-compose{display:inline-flex;align-items:center;gap:6px}.pfx-cell-compose.dir-col{flex-direction:column;align-items:stretch}.pfx-cell-compose.align-start{justify-content:flex-start}.pfx-cell-compose.align-center{justify-content:center}.pfx-cell-compose.align-end{justify-content:flex-end}.pfx-cell-compose.wrap{flex-wrap:wrap}.pfx-cell-compose.ellipsis{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.px-scroll-viewport{width:100%;overflow-x:auto;-webkit-overflow-scrolling:touch;overscroll-behavior-x:contain;scrollbar-gutter:stable}.px-scroll-viewport.scroll-none{overflow-x:visible}.px-scroll-viewport.scroll-auto ::ng-deep .mat-mdc-table{width:max-content;min-width:100%}.px-scroll-viewport.scroll-wrap ::ng-deep .mat-mdc-header-cell,.px-scroll-viewport.scroll-wrap ::ng-deep .mat-mdc-cell{white-space:normal;text-overflow:initial}.px-scroll-viewport.scroll-wrap ::ng-deep .mat-mdc-table{width:100%}:host ::ng-deep .mat-mdc-header-row{position:sticky;top:0;z-index:1;background:var(--p-table-header-bg);color:var(--p-table-header-fg);box-shadow:var(--p-table-header-shadow, 0 1px 0 var(--p-table-border-color));border-bottom:1px solid var(--p-table-border-color)}:host ::ng-deep .mat-mdc-header-cell,:host ::ng-deep .mat-sort-header-content,:host ::ng-deep .mat-mdc-header-row .mat-icon{color:var(--p-table-header-fg)!important;font-weight:600}:host ::ng-deep .mat-mdc-header-cell.mat-sort-header-sorted .mat-sort-header-arrow,:host ::ng-deep .mat-mdc-header-cell:hover .mat-sort-header-arrow{color:var(--p-table-header-fg)!important}:host ::ng-deep .mat-mdc-header-cell.mat-sort-header-sorted .mat-sort-header-arrow .mat-sort-header-indicator,:host ::ng-deep .mat-mdc-header-cell.mat-sort-header-sorted .mat-sort-header-arrow .mat-sort-header-stem,:host ::ng-deep .mat-mdc-header-cell.mat-sort-header-sorted .mat-sort-header-arrow .mat-sort-header-pointer,:host ::ng-deep .mat-mdc-header-cell.mat-sort-header-sorted .mat-sort-header-arrow .mat-sort-header-pointer-left,:host ::ng-deep .mat-mdc-header-cell.mat-sort-header-sorted .mat-sort-header-arrow .mat-sort-header-pointer-right{border-color:var(--p-table-header-fg)!important;background:var(--p-table-header-fg)!important}:host ::ng-deep .mat-mdc-header-cell{padding:var(--p-header-padding, 12px 16px)!important;font-size:var(--p-header-font-size, inherit);font-weight:var(--p-header-font-weight, 600);letter-spacing:var(--p-header-letter-spacing, normal);text-transform:var(--p-header-text-transform, none);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.praxis-actions-header{text-align:right}.praxis-actions-header.align-start{text-align:left}.praxis-actions-header.align-center{text-align:center}.praxis-actions-header.align-end{text-align:right}.praxis-actions-header .praxis-actions-header__content{display:inline-flex;align-items:center;gap:var(--p-actions-header-gap, 6px);color:var(--p-actions-header-color, inherit)}.praxis-actions-header .praxis-actions-header__content .mat-icon{font-size:18px;width:18px;height:18px;line-height:18px}:host ::ng-deep .mat-mdc-header-cell .mat-sort-header-container{padding-right:20px}:host ::ng-deep .mat-mdc-cell{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}:host ::ng-deep .mat-mdc-row:hover{background:var(--p-table-row-hover-bg)}:host ::ng-deep .mat-mdc-row:nth-child(2n){background:var(--p-table-row-even-bg)}:host.row-borders ::ng-deep .mat-mdc-row .mat-mdc-cell{border-bottom:1px solid var(--p-table-border-color)}:host.row-borders ::ng-deep .mat-mdc-header-row .mat-mdc-header-cell{border-bottom:none}:host.col-borders ::ng-deep .mat-mdc-header-row .mat-mdc-header-cell,:host.col-borders ::ng-deep .mat-mdc-row .mat-mdc-cell{border-right:1px solid var(--p-table-border-color)}:host.col-borders ::ng-deep .mat-mdc-header-row .mat-mdc-header-cell:last-child,:host.col-borders ::ng-deep .mat-mdc-row .mat-mdc-cell:last-child{border-right:none}.ptable-info-banner{display:flex;gap:12px;align-items:center;padding:8px 12px;margin:8px 0;border-radius:8px;border:1px solid var(--mat-sys-primary, var(--md-sys-color-primary, #1a73e8));background:color-mix(in srgb,var(--mat-sys-primary, var(--md-sys-color-primary, #1a73e8)) 10%,transparent)}.ptable-info-banner .text{flex:1;font-weight:600}.ptable-info-banner .actions{display:flex;gap:8px}.pfx-cell-image{display:inline-block;vertical-align:middle;background:var(--md-sys-color-surface-variant, #2a2a2a);border:1px solid var(--md-sys-color-outline-variant, rgba(0, 0, 0, .08))}.pfx-cell-image.shape-rounded{border-radius:8px}.pfx-cell-image.shape-circle{border-radius:9999px}.pfx-badge{display:inline-flex;align-items:center;gap:6px;line-height:1;padding:4px 8px;border-radius:9999px;font-size:12px;font-weight:600;border:1px solid transparent}.pfx-badge .pfx-badge-icon{font-size:16px;width:16px;height:16px}.pfx-badge--filled-primary{background:var(--mat-sys-primary, #3f51b5);color:var(--mat-sys-on-primary, #fff)}.pfx-badge--filled-accent{background:var(--mat-sys-secondary, #ff4081);color:var(--mat-sys-on-secondary, #fff)}.pfx-badge--filled-warn{background:var(--mat-sys-error, #f44336);color:var(--mat-sys-on-error, #fff)}.pfx-badge--outlined{background:transparent;border-color:var(--mat-sys-outline-variant, rgba(255, 255, 255, .24));color:inherit}.pfx-badge--soft-primary{background:var(--p-table-badge-soft-primary-bg);color:var(--p-table-badge-soft-primary-fg)}.pfx-badge--soft-accent{background:var(--p-table-badge-soft-accent-bg);color:var(--p-table-badge-soft-accent-fg)}.pfx-badge--soft-warn{background:var(--p-table-badge-soft-warn-bg);color:var(--p-table-badge-soft-warn-fg)}.row--success,.row--success td,td.row--success{background-color:var(--p-table-state-success-bg)!important;color:var(--p-table-state-success-fg)!important}.row--warning,.row--warning td,td.row--warning{background-color:var(--p-table-state-warning-bg)!important;color:var(--p-table-state-warning-fg)!important}.row--danger,.row--danger td,td.row--danger{background-color:var(--p-table-state-danger-bg)!important;color:var(--p-table-state-danger-fg)!important}.row--highlight,.row--highlight td,td.row--highlight{background-color:var(--p-table-state-highlight-bg)!important;color:var(--p-table-state-highlight-fg)!important;font-weight:600}.row--muted,.row--muted td,td.row--muted{opacity:.7;filter:saturate(.6)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "directive", type: i1.NgSwitch, selector: "[ngSwitch]", inputs: ["ngSwitch"] }, { kind: "directive", type: i1.NgSwitchCase, selector: "[ngSwitchCase]", inputs: ["ngSwitchCase"] }, { kind: "directive", type: i1.NgSwitchDefault, selector: "[ngSwitchDefault]" }, { kind: "ngmodule", type: MatTableModule }, { kind: "component", type: i8.MatTable, selector: "mat-table, table[mat-table]", exportAs: ["matTable"] }, { kind: "directive", type: i8.MatHeaderCellDef, selector: "[matHeaderCellDef]" }, { kind: "directive", type: i8.MatHeaderRowDef, selector: "[matHeaderRowDef]", inputs: ["matHeaderRowDef", "matHeaderRowDefSticky"] }, { kind: "directive", type: i8.MatColumnDef, selector: "[matColumnDef]", inputs: ["matColumnDef"] }, { kind: "directive", type: i8.MatCellDef, selector: "[matCellDef]" }, { kind: "directive", type: i8.MatRowDef, selector: "[matRowDef]", inputs: ["matRowDefColumns", "matRowDefWhen"] }, { kind: "directive", type: i8.MatHeaderCell, selector: "mat-header-cell, th[mat-header-cell]" }, { kind: "directive", type: i8.MatCell, selector: "mat-cell, td[mat-cell]" }, { kind: "component", type: i8.MatHeaderRow, selector: "mat-header-row, tr[mat-header-row]", exportAs: ["matHeaderRow"] }, { kind: "component", type: i8.MatRow, selector: "mat-row, tr[mat-row]", exportAs: ["matRow"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i3.MatButton, selector: " button[matButton], a[matButton], button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button], a[mat-button], a[mat-raised-button], a[mat-flat-button], a[mat-stroked-button] ", inputs: ["matButton"], exportAs: ["matButton", "matAnchor"] }, { kind: "component", type: i3.MatIconButton, selector: "button[mat-icon-button], a[mat-icon-button], button[matIconButton], a[matIconButton]", exportAs: ["matButton", "matAnchor"] }, { kind: "ngmodule", type: MatPaginatorModule }, { kind: "component", type: i11$1.MatPaginator, selector: "mat-paginator", inputs: ["color", "pageIndex", "length", "pageSize", "pageSizeOptions", "hidePageSize", "showFirstLastButtons", "selectConfig", "disabled"], outputs: ["page"], exportAs: ["matPaginator"] }, { kind: "ngmodule", type: MatSortModule }, { kind: "directive", type: i12.MatSort, selector: "[matSort]", inputs: ["matSortActive", "matSortStart", "matSortDirection", "matSortDisableClear", "matSortDisabled"], outputs: ["matSortChange"], exportAs: ["matSort"] }, { kind: "component", type: i12.MatSortHeader, selector: "[mat-sort-header]", inputs: ["mat-sort-header", "arrowPosition", "start", "disabled", "sortActionDescription", "disableClear"], exportAs: ["matSortHeader"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i4.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatMenuModule }, { kind: "component", type: i5.MatMenu, selector: "mat-menu", inputs: ["backdropClass", "aria-label", "aria-labelledby", "aria-describedby", "xPosition", "yPosition", "overlapTrigger", "hasBackdrop", "class", "classList"], outputs: ["closed", "close"], exportAs: ["matMenu"] }, { kind: "component", type: i5.MatMenuItem, selector: "[mat-menu-item]", inputs: ["role", "disabled", "disableRipple"], exportAs: ["matMenuItem"] }, { kind: "directive", type: i5.MatMenuTrigger, selector: "[mat-menu-trigger-for], [matMenuTriggerFor]", inputs: ["mat-menu-trigger-for", "matMenuTriggerFor", "matMenuTriggerData", "matMenuTriggerRestoreFocus"], outputs: ["menuOpened", "onMenuOpen", "menuClosed", "onMenuClose"], exportAs: ["matMenuTrigger"] }, { kind: "ngmodule", type: MatSlideToggleModule }, { kind: "component", type: i6$1.MatSlideToggle, selector: "mat-slide-toggle", inputs: ["name", "id", "labelPosition", "aria-label", "aria-labelledby", "aria-describedby", "required", "color", "disabled", "disableRipple", "tabIndex", "checked", "hideIcon", "disabledInteractive"], outputs: ["change", "toggleChange"], exportAs: ["matSlideToggle"] }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i10.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "ngmodule", type: MatSnackBarModule }, { kind: "ngmodule", type: MatCheckboxModule }, { kind: "component", type: i9.MatCheckbox, selector: "mat-checkbox", inputs: ["aria-label", "aria-labelledby", "aria-describedby", "aria-expanded", "aria-controls", "aria-owns", "id", "required", "labelPosition", "name", "value", "disableRipple", "tabIndex", "color", "disabledInteractive", "checked", "disabled", "indeterminate"], outputs: ["change", "indeterminateChange"], exportAs: ["matCheckbox"] }, { kind: "ngmodule", type: MatBadgeModule }, { kind: "directive", type: i15.MatBadge, selector: "[matBadge]", inputs: ["matBadgeColor", "matBadgeOverlap", "matBadgeDisabled", "matBadgePosition", "matBadge", "matBadgeDescription", "matBadgeSize", "matBadgeHidden"] }, { kind: "ngmodule", type: ScrollingModule }, { kind: "directive", type: i19.ɵɵCdkFixedSizeVirtualScroll, selector: "cdk-virtual-scroll-viewport[itemSize]", inputs: ["itemSize", "minBufferPx", "maxBufferPx"] }, { kind: "directive", type: i19.ɵɵCdkVirtualForOf, selector: "[cdkVirtualFor][cdkVirtualForOf]", inputs: ["cdkVirtualForOf", "cdkVirtualForTrackBy", "cdkVirtualForTemplate", "cdkVirtualForTemplateCacheSize"] }, { kind: "component", type: i19.ɵɵCdkVirtualScrollViewport, selector: "cdk-virtual-scroll-viewport", inputs: ["orientation", "appendOnly"], outputs: ["scrolledIndexChange"] }, { kind: "component", type: PraxisTableToolbar, selector: "praxis-table-toolbar", inputs: ["config", "debugLayout"], outputs: ["toolbarAction", "reset"] }, { kind: "component", type: PraxisFilter, selector: "praxis-filter", inputs: ["resourcePath", "formId", "mode", "notifyIfOutdated", "snoozeMs", "autoOpenSettingsOnOutdated", "editModeEnabled", "value", "quickField", "alwaysVisibleFields", "tags", "allowSaveTags", "persistenceKey", "i18n", "changeDebounceMs", "showFilterSettings", "summary", "summaryTemplate", "summaryMap", "autoSummary", "confirmTagDelete", "debugLayout", "placeBooleansInActions", "showToggleLabels", "alwaysMinWidth", "alwaysColsMd", "alwaysColsLg", "tagColor", "tagVariant", "tagButtonColor", "actionsButtonColor", "actionsVariant", "overlayVariant", "overlayBackdrop", "advancedOpenMode"], outputs: ["submit", "change", "clear", "modeChange", "requestSearch", "tagsChange", "metaChanged", "schemaStatusChange"] }, { kind: "directive", type: PraxisIconDirective, selector: "mat-icon[praxisIcon]", inputs: ["praxisIcon"] }, { kind: "component", type: EmptyStateCardComponent, selector: "praxis-empty-state-card", inputs: ["icon", "title", "description", "primaryAction", "secondaryActions", "inline"] }] });
|
|
24065
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.1.4", type: PraxisTable, isStandalone: true, selector: "praxis-table", inputs: { config: "config", resourcePath: "resourcePath", filterCriteria: "filterCriteria", notifyIfOutdated: "notifyIfOutdated", snoozeMs: "snoozeMs", autoOpenSettingsOnOutdated: "autoOpenSettingsOnOutdated", showToolbar: "showToolbar", toolbarV2: "toolbarV2", autoDelete: "autoDelete", editModeEnabled: "editModeEnabled", dense: "dense", tableId: "tableId", debugLayout: "debugLayout", horizontalScroll: "horizontalScroll", crudContext: "crudContext", idField: "idField" }, outputs: { rowClick: "rowClick", rowAction: "rowAction", toolbarAction: "toolbarAction", bulkAction: "bulkAction", rowDoubleClick: "rowDoubleClick", schemaStatusChange: "schemaStatusChange", metadataChange: "metadataChange", beforeDelete: "beforeDelete", afterDelete: "afterDelete", deleteError: "deleteError", beforeBulkDelete: "beforeBulkDelete", afterBulkDelete: "afterBulkDelete", bulkDeleteError: "bulkDeleteError" }, host: { properties: { "class.debug-layout": "debugLayout", "class.density-compact": "config?.appearance?.density === 'compact'", "class.density-comfortable": "config?.appearance?.density === 'comfortable'", "class.density-spacious": "config?.appearance?.density === 'spacious'", "class.row-borders": "config?.appearance?.borders?.showRowBorders !== false", "class.col-borders": "!!config?.appearance?.borders?.showColumnBorders" } }, queries: [{ propertyName: "projectedFilter", first: true, predicate: PraxisFilter, descendants: true }], viewQueries: [{ propertyName: "paginator", first: true, predicate: MatPaginator, descendants: true }, { propertyName: "sort", first: true, predicate: MatSort, descendants: true }, { propertyName: "actionsHeaderCell", first: true, predicate: ["actionsHeaderCell"], descendants: true }], usesOnChanges: true, ngImport: i0, template: "<praxis-empty-state-card\n *ngIf=\"!resourcePath\"\n icon=\"link\"\n [title]=\"'Conecte a tabela \u00E0 fonte de dados'\"\n [description]=\"'Informe a rota do recurso da API para carregar colunas e dados automaticamente.'\"\n [primaryAction]=\"{ label: 'Conectar \u00E0 fonte de dados', icon: 'bolt', action: openQuickConnect.bind(this) }\"\n></praxis-empty-state-card>\n\n<!-- Error State with Quick Connect CTA -->\n<div class=\"ptable-error\" *ngIf=\"resourcePath && (schemaError || dataError)\" style=\"display:flex; align-items:center; gap:12px; padding:12px; border:1px solid var(--md-sys-color-error, #b00020); border-radius:8px; margin: 8px 0;\">\n <mat-icon color=\"warn\" aria-hidden=\"true\">error</mat-icon>\n <div style=\"flex:1\">\n <div style=\"font-weight:600\">Erro</div>\n <div>{{ errorMessage || 'Ocorreu um erro ao carregar a tabela.' }}</div>\n </div>\n <button mat-flat-button color=\"primary\" (click)=\"openQuickConnect()\">\n <mat-icon>bolt</mat-icon>\n Conectar a recurso\n </button>\n <button mat-stroked-button (click)=\"retryData()\" *ngIf=\"!schemaError\">Tentar novamente</button>\n <button mat-stroked-button (click)=\"reloadSchema()\" *ngIf=\"schemaError\">Recarregar colunas</button>\n </div>\n\n<!-- Inline banner for schema change (only in edit mode) -->\n<div *ngIf=\"shouldShowOutdatedInline()\" class=\"ptable-info-banner\" role=\"status\" aria-live=\"polite\">\n <div class=\"text\">O schema do servidor mudou. Reconciliar agora?</div>\n <div class=\"actions\">\n <button mat-stroked-button color=\"primary\" (click)=\"onReconcileRequested()\">\n <mat-icon>sync</mat-icon>\n Reconciliar\n </button>\n <button mat-button (click)=\"onSnoozeOutdated()\">Lembrar depois</button>\n <button mat-button (click)=\"onIgnoreOutdated()\">Ignorar</button>\n </div>\n </div>\n\n <ng-container *ngIf=\"resourcePath && !schemaError && !dataError && toolbarV2; else legacyHeader\">\n <div class=\"praxis-table-header\" [class.debug-layout]=\"debugLayout\" [class.edit-mode]=\"editModeEnabled\" *ngIf=\"showToolbar || editModeEnabled\">\n <praxis-table-toolbar\n *ngIf=\"showToolbar\"\n [config]=\"config\"\n [debugLayout]=\"debugLayout\"\n (toolbarAction)=\"onToolbarAction($event)\"\n (reset)=\"onResetPreferences()\"\n >\n <praxis-filter\n *ngIf=\"\n resourcePath &&\n config.behavior?.filtering?.advancedFilters?.enabled &&\n !projectedFilter\n \"\n advancedFilter\n [resourcePath]=\"resourcePath\"\n [formId]=\"tableId + '-filter'\"\n [editModeEnabled]=\"editModeEnabled\"\n [quickField]=\"\n config.behavior?.filtering?.advancedFilters?.settings?.quickField\n \"\n [alwaysVisibleFields]=\"\n config.behavior?.filtering?.advancedFilters?.settings\n ?.alwaysVisibleFields\n \"\n [allowSaveTags]=\"\n config.behavior?.filtering?.advancedFilters?.settings\n ?.allowSaveTags\n \"\n [changeDebounceMs]=\"\n config.behavior?.filtering?.advancedFilters?.settings\n ?.changeDebounceMs ?? 300\n \"\n [i18n]=\"getFilterI18n()\"\n [mode]=\"\n config.behavior?.filtering?.advancedFilters?.settings?.mode ??\n 'auto'\n \"\n [debugLayout]=\"debugLayout\"\n [showFilterSettings]=\"!editModeEnabled\"\n (submit)=\"onAdvancedFilterSubmit($event)\"\n (clear)=\"onAdvancedFilterClear()\"\n ></praxis-filter>\n <ng-content select=\"[advancedFilter]\" />\n <ng-content select=\"[toolbar]\" />\n <button end-actions mat-icon-button color=\"primary\" data-role=\"table-settings\" *ngIf=\"editModeEnabled\"\n (click)=\"openTableSettings()\" aria-label=\"Configura\u00E7\u00F5es\"\n [matBadge]=\"schemaOutdated ? '!' : ''\"\n [matBadgeHidden]=\"!schemaOutdated\"\n matBadgeColor=\"warn\" matBadgeSize=\"small\" matBadgePosition=\"above after\"\n [matTooltip]=\"schemaOutdated ? 'Schema do servidor mudou \u2014 Reconciliar' : 'Configura\u00E7\u00F5es'\"\n matTooltipPosition=\"below\">\n <mat-icon>settings</mat-icon>\n </button>\n </praxis-table-toolbar>\n <!-- Render a minimal settings button when toolbar is hidden but edit mode is enabled -->\n <div class=\"ptable-header-actions\" *ngIf=\"!showToolbar && editModeEnabled\">\n <button mat-icon-button color=\"primary\" (click)=\"openTableSettings()\" aria-label=\"Configura\u00E7\u00F5es\"\n [matBadge]=\"schemaOutdated ? '!' : ''\"\n [matBadgeHidden]=\"!schemaOutdated\"\n matBadgeColor=\"warn\" matBadgeSize=\"small\" matBadgePosition=\"above after\"\n [matTooltip]=\"schemaOutdated ? 'Schema do servidor mudou \u2014 Reconciliar' : 'Configura\u00E7\u00F5es'\"\n matTooltipPosition=\"below\">\n <mat-icon>settings</mat-icon>\n </button>\n <button mat-icon-button (click)=\"disconnect()\" aria-label=\"Desconectar\" matTooltip=\"Desconectar da fonte de dados\">\n <mat-icon>link_off</mat-icon>\n </button>\n </div>\n \n </div>\n</ng-container>\n<ng-template #legacyHeader>\n <ng-container *ngIf=\"resourcePath && !schemaError && !dataError\">\n <praxis-table-toolbar\n *ngIf=\"showToolbar\"\n [config]=\"config\"\n [debugLayout]=\"debugLayout\"\n (toolbarAction)=\"onToolbarAction($event)\"\n (reset)=\"onResetPreferences()\"\n >\n <praxis-filter\n *ngIf=\"\n resourcePath &&\n config.behavior?.filtering?.advancedFilters?.enabled &&\n !projectedFilter\n \"\n advancedFilter\n [resourcePath]=\"resourcePath\"\n [formId]=\"tableId + '-filter'\"\n [editModeEnabled]=\"editModeEnabled\"\n [quickField]=\"\n config.behavior?.filtering?.advancedFilters?.settings?.quickField\n \"\n [alwaysVisibleFields]=\"\n config.behavior?.filtering?.advancedFilters?.settings\n ?.alwaysVisibleFields\n \"\n [allowSaveTags]=\"\n config.behavior?.filtering?.advancedFilters?.settings?.allowSaveTags\n \"\n [changeDebounceMs]=\"\n config.behavior?.filtering?.advancedFilters?.settings\n ?.changeDebounceMs ?? 300\n \"\n [i18n]=\"getFilterI18n()\"\n [mode]=\"\n config.behavior?.filtering?.advancedFilters?.settings?.mode ??\n 'auto'\n \"\n [debugLayout]=\"debugLayout\"\n [showFilterSettings]=\"!editModeEnabled\"\n (submit)=\"onAdvancedFilterSubmit($event)\"\n (clear)=\"onAdvancedFilterClear()\"\n ></praxis-filter>\n <ng-content select=\"[advancedFilter]\" />\n <ng-content select=\"[toolbar]\" />\n <button end-actions mat-icon-button color=\"primary\" *ngIf=\"editModeEnabled\"\n (click)=\"openTableSettings()\" aria-label=\"Configura\u00E7\u00F5es\"\n [matBadge]=\"schemaOutdated ? '!' : ''\"\n [matBadgeHidden]=\"!schemaOutdated\"\n matBadgeColor=\"warn\" matBadgeSize=\"small\" matBadgePosition=\"above after\"\n [matTooltip]=\"schemaOutdated ? 'Schema do servidor mudou \u2014 Reconciliar' : 'Configura\u00E7\u00F5es'\"\n matTooltipPosition=\"below\">\n <mat-icon>settings</mat-icon>\n </button>\n </praxis-table-toolbar>\n <!-- Legacy header: settings button when toolbar hidden -->\n <div class=\"ptable-header-actions\" *ngIf=\"!showToolbar && editModeEnabled\">\n <button mat-icon-button color=\"primary\" data-role=\"table-settings\" (click)=\"openTableSettings()\" aria-label=\"Configura\u00E7\u00F5es\"\n [matBadge]=\"schemaOutdated ? '!' : ''\"\n [matBadgeHidden]=\"!schemaOutdated\"\n matBadgeColor=\"warn\" matBadgeSize=\"small\" matBadgePosition=\"above after\"\n [matTooltip]=\"schemaOutdated ? 'Schema do servidor mudou \u2014 Reconciliar' : 'Configura\u00E7\u00F5es'\"\n matTooltipPosition=\"below\">\n <mat-icon>settings</mat-icon>\n </button>\n </div>\n </ng-container>\n \n</ng-template>\n<div class=\"px-scroll-viewport\"\n [class.scroll-auto]=\"horizontalScroll === 'auto'\"\n [class.scroll-wrap]=\"horizontalScroll === 'wrap'\"\n [class.scroll-none]=\"horizontalScroll === 'none'\">\n\n<table\n *ngIf=\"resourcePath && !schemaError && !dataError\"\n mat-table\n [dataSource]=\"dataSource\"\n matSort\n (matSortChange)=\"onSortChange($event)\"\n [matSortDisabled]=\"!getSortingEnabled()\"\n class=\"mat-elevation-z8\"\n>\n <ng-container\n *ngIf=\"config.behavior?.selection?.enabled\"\n matColumnDef=\"_select\"\n >\n <th mat-header-cell *matHeaderCellDef>\n <mat-checkbox\n (change)=\"masterToggle()\"\n [checked]=\"isAllSelected()\"\n [indeterminate]=\"selection.hasValue() && !isAllSelected()\"\n ></mat-checkbox>\n </th>\n <td mat-cell *matCellDef=\"let row\">\n <mat-checkbox\n (click)=\"$event.stopPropagation()\"\n (change)=\"toggleRow(row)\"\n [checked]=\"selection.isSelected(row)\"\n ></mat-checkbox>\n </td>\n </ng-container>\n <ng-container\n *ngFor=\"let column of visibleColumns\"\n [matColumnDef]=\"column.field\"\n [sticky]=\"column.sticky === true || column.sticky === 'start'\"\n [stickyEnd]=\"column.sticky === 'end'\"\n >\n <th\n mat-header-cell\n *matHeaderCellDef\n mat-sort-header\n [disabled]=\"!getSortingEnabled() || column.sortable === false\"\n [style.text-align]=\"column.align\"\n [style.width]=\"column.width\"\n [attr.style]=\"column.headerStyle\"\n >\n {{ column.header }}\n </th>\n <td\n mat-cell\n *matCellDef=\"let element\"\n [style.text-align]=\"column.align\"\n [style.width]=\"column.width\"\n [attr.style]=\"column.style\"\n [ngClass]=\"getCellClasses(element, column)\"\n [ngStyle]=\"getCellNgStyle(element, column)\"\n >\n <ng-container [ngSwitch]=\"getEffectiveRendererType(element, column)\">\n <!-- Icon renderer -->\n <ng-container *ngSwitchCase=\"'icon'\">\n <mat-icon\n [color]=\"getIconColor(element, column) || null\"\n [ngStyle]=\"getIconStyle(element, column)\"\n [attr.aria-label]=\"getIconAriaLabel(element, column) || null\"\n >{{ getIconName(element, column) }}</mat-icon\n >\n </ng-container>\n\n <!-- Image renderer -->\n <ng-container *ngSwitchCase=\"'image'\">\n <img\n class=\"pfx-cell-image\"\n [src]=\"getImageSrc(element, column)\"\n [attr.alt]=\"getImageAlt(element, column) || ''\"\n [attr.loading]=\"getImageLazy(element, column) ? 'lazy' : null\"\n [style.width.px]=\"getImageWidth(element, column)\"\n [style.height.px]=\"getImageHeight(element, column)\"\n [class.shape-rounded]=\"getImageShape(element, column) === 'rounded'\"\n [class.shape-circle]=\"getImageShape(element, column) === 'circle'\"\n [style.object-fit]=\"getImageFit(element, column)\"\n />\n </ng-container>\n\n <!-- Badge renderer -->\n <ng-container *ngSwitchCase=\"'badge'\">\n <span class=\"pfx-badge\" [ngClass]=\"getBadgeClasses(element, column)\">\n <mat-icon *ngIf=\"getBadgeIcon(element, column) as bi\" class=\"pfx-badge-icon\">{{ bi }}</mat-icon>\n <span class=\"pfx-badge-text\">{{ getBadgeText(element, column) }}</span>\n </span>\n </ng-container>\n\n <!-- Link renderer -->\n <ng-container *ngSwitchCase=\"'link'\">\n <a\n class=\"pfx-link\"\n [attr.href]=\"getLinkHref(element, column) || null\"\n [attr.target]=\"getLinkTarget(element, column) || null\"\n [attr.rel]=\"getLinkRel(element, column) || null\"\n (click)=\"$event.stopPropagation()\"\n >{{ getLinkText(element, column) }}</a\n >\n </ng-container>\n\n <!-- Button renderer -->\n <ng-container *ngSwitchCase=\"'button'\">\n <ng-container [ngSwitch]=\"getButtonVariant(element, column)\">\n <button\n *ngSwitchCase=\"'outlined'\"\n mat-stroked-button\n [color]=\"getButtonColor(element, column) || null\"\n [disabled]=\"isButtonDisabled(element, column)\"\n [attr.aria-label]=\"getButtonAriaLabel(element, column) || getButtonLabel(element, column)\"\n (click)=\"onButtonClick(element, column, $event)\"\n >\n <mat-icon *ngIf=\"getButtonIcon(element, column) as bi\">{{ bi }}</mat-icon>\n {{ getButtonLabel(element, column) }}\n </button>\n <button\n *ngSwitchCase=\"'text'\"\n mat-button\n [color]=\"getButtonColor(element, column) || null\"\n [disabled]=\"isButtonDisabled(element, column)\"\n [attr.aria-label]=\"getButtonAriaLabel(element, column) || getButtonLabel(element, column)\"\n (click)=\"onButtonClick(element, column, $event)\"\n >\n <mat-icon *ngIf=\"getButtonIcon(element, column) as bi\">{{ bi }}</mat-icon>\n {{ getButtonLabel(element, column) }}\n </button>\n <button\n *ngSwitchDefault\n mat-flat-button\n [color]=\"getButtonColor(element, column) || null\"\n [disabled]=\"isButtonDisabled(element, column)\"\n [attr.aria-label]=\"getButtonAriaLabel(element, column) || getButtonLabel(element, column)\"\n (click)=\"onButtonClick(element, column, $event)\"\n >\n <mat-icon *ngIf=\"getButtonIcon(element, column) as bi\">{{ bi }}</mat-icon>\n {{ getButtonLabel(element, column) }}\n </button>\n </ng-container>\n </ng-container>\n\n <!-- Chip renderer -->\n <ng-container *ngSwitchCase=\"'chip'\">\n <span class=\"pfx-chip\" [ngClass]=\"getChipClasses(element, column)\">\n <mat-icon *ngIf=\"getChipIcon(element, column) as ci\" class=\"pfx-chip-icon\">{{ ci }}</mat-icon>\n <span class=\"pfx-chip-text\">{{ getChipText(element, column) }}</span>\n </span>\n </ng-container>\n\n <!-- Progress renderer -->\n <ng-container *ngSwitchCase=\"'progress'\">\n <div class=\"pfx-progress\">\n <div class=\"pfx-progress-bar\" [style.width.%]=\"getProgressValue(element, column)\" [style.background]=\"getProgressColor(element, column) || null\"></div>\n <div class=\"pfx-progress-label\" *ngIf=\"getProgressShowLabel(element, column)\">{{ getProgressValue(element, column) }}%</div>\n </div>\n </ng-container>\n\n <!-- Avatar renderer -->\n <ng-container *ngSwitchCase=\"'avatar'\">\n <ng-container *ngIf=\"getAvatarSrc(element, column) as asrc; else initials\">\n <img class=\"pfx-avatar\" [src]=\"asrc\" [attr.alt]=\"getAvatarAlt(element, column) || ''\" [ngStyle]=\"getAvatarStyle(element, column)\" [class.shape-rounded]=\"getAvatarShape(element, column) === 'rounded'\" [class.shape-circle]=\"getAvatarShape(element, column) === 'circle'\" loading=\"lazy\" />\n </ng-container>\n <ng-template #initials>\n <span class=\"pfx-avatar pfx-avatar--initials\" [ngStyle]=\"getAvatarStyle(element, column)\" [class.shape-rounded]=\"getAvatarShape(element, column) === 'rounded'\" [class.shape-circle]=\"getAvatarShape(element, column) === 'circle'\">{{ getAvatarInitials(element, column) }}</span>\n </ng-template>\n </ng-container>\n\n <!-- Toggle renderer -->\n <ng-container *ngSwitchCase=\"'toggle'\">\n <mat-slide-toggle\n [checked]=\"getToggleState(element, column)\"\n [disabled]=\"isToggleDisabled(element, column)\"\n [attr.aria-label]=\"getToggleAriaLabel(element, column) || 'Alternar'\"\n (change)=\"onToggleChange(element, column, $event)\"\n (click)=\"$event.stopPropagation()\"\n ></mat-slide-toggle>\n </ng-container>\n\n <!-- Menu renderer -->\n <ng-container *ngSwitchCase=\"'menu'\">\n <button mat-icon-button [matMenuTriggerFor]=\"menuRef\" (click)=\"$event.stopPropagation()\" [attr.aria-label]=\"getMenuAriaLabel(element, column) || 'Menu'\">\n <mat-icon>more_vert</mat-icon>\n </button>\n <mat-menu #menuRef=\"matMenu\">\n <button mat-menu-item *ngFor=\"let it of getMenuItems(element, column)\" (click)=\"onMenuItemClick(it.id, element, $event)\" [disabled]=\"!it.__visible\" >\n <mat-icon *ngIf=\"it.icon\">{{ it.icon }}</mat-icon>\n <span>{{ it.label }}</span>\n </button>\n </mat-menu>\n </ng-container>\n\n <!-- HTML renderer (sanitizado) -->\n <ng-container *ngSwitchCase=\"'html'\">\n <span [innerHTML]=\"getSafeHtml(element, column)\"></span>\n </ng-container>\n\n <!-- Compose renderer -->\n <ng-container *ngSwitchCase=\"'compose'\">\n <span class=\"pfx-cell-compose\" [ngClass]=\"getComposeClasses(element, column)\" [ngStyle]=\"getComposeGapStyle(element, column)\">\n <ng-container *ngFor=\"let it of getComposeItems(element, column)\">\n <ng-container [ngSwitch]=\"getItemEffectiveType(element, column, it)\">\n <!-- Reuse helpers by projecting item as faux column -->\n <ng-container *ngSwitchCase=\"'icon'\">\n <mat-icon [color]=\"getIconColor(element, asItemColumn(column, it)) || null\" [ngStyle]=\"getIconStyle(element, asItemColumn(column, it))\" [attr.aria-label]=\"getIconAriaLabel(element, asItemColumn(column, it)) || null\">{{ getIconName(element, asItemColumn(column, it)) }}</mat-icon>\n </ng-container>\n <ng-container *ngSwitchCase=\"'image'\">\n <img class=\"pfx-cell-image\" [src]=\"getImageSrc(element, asItemColumn(column, it))\" [attr.alt]=\"getImageAlt(element, asItemColumn(column, it)) || ''\" [attr.loading]=\"getImageLazy(element, asItemColumn(column, it)) ? 'lazy' : null\" [style.width.px]=\"getImageWidth(element, asItemColumn(column, it))\" [style.height.px]=\"getImageHeight(element, asItemColumn(column, it))\" [class.shape-rounded]=\"getImageShape(element, asItemColumn(column, it)) === 'rounded'\" [class.shape-circle]=\"getImageShape(element, asItemColumn(column, it)) === 'circle'\" [style.object-fit]=\"getImageFit(element, asItemColumn(column, it))\" />\n </ng-container>\n <ng-container *ngSwitchCase=\"'badge'\">\n <span class=\"pfx-badge\" [ngClass]=\"getBadgeClasses(element, asItemColumn(column, it))\"><mat-icon *ngIf=\"getBadgeIcon(element, asItemColumn(column, it)) as bi\" class=\"pfx-badge-icon\">{{ bi }}</mat-icon><span class=\"pfx-badge-text\">{{ getBadgeText(element, asItemColumn(column, it)) }}</span></span>\n </ng-container>\n <ng-container *ngSwitchCase=\"'link'\">\n <a class=\"pfx-link\" [attr.href]=\"getLinkHref(element, asItemColumn(column, it)) || null\" [attr.target]=\"getLinkTarget(element, asItemColumn(column, it)) || null\" [attr.rel]=\"getLinkRel(element, asItemColumn(column, it)) || null\" (click)=\"$event.stopPropagation()\">{{ getLinkText(element, asItemColumn(column, it)) }}</a>\n </ng-container>\n <ng-container *ngSwitchCase=\"'button'\">\n <ng-container [ngSwitch]=\"getButtonVariant(element, asItemColumn(column, it))\">\n <button *ngSwitchCase=\"'outlined'\" mat-stroked-button [color]=\"getButtonColor(element, asItemColumn(column, it)) || null\" [disabled]=\"isButtonDisabled(element, asItemColumn(column, it))\" [attr.aria-label]=\"getButtonAriaLabel(element, asItemColumn(column, it)) || getButtonLabel(element, asItemColumn(column, it))\" (click)=\"onButtonClick(element, asItemColumn(column, it), $event)\"><mat-icon *ngIf=\"getButtonIcon(element, asItemColumn(column, it)) as bi\">{{ bi }}</mat-icon>{{ getButtonLabel(element, asItemColumn(column, it)) }}</button>\n <button *ngSwitchCase=\"'text'\" mat-button [color]=\"getButtonColor(element, asItemColumn(column, it)) || null\" [disabled]=\"isButtonDisabled(element, asItemColumn(column, it))\" [attr.aria-label]=\"getButtonAriaLabel(element, asItemColumn(column, it)) || getButtonLabel(element, asItemColumn(column, it))\" (click)=\"onButtonClick(element, asItemColumn(column, it), $event)\"><mat-icon *ngIf=\"getButtonIcon(element, asItemColumn(column, it)) as bi\">{{ bi }}</mat-icon>{{ getButtonLabel(element, asItemColumn(column, it)) }}</button>\n <button *ngSwitchDefault mat-flat-button [color]=\"getButtonColor(element, asItemColumn(column, it)) || null\" [disabled]=\"isButtonDisabled(element, asItemColumn(column, it))\" [attr.aria-label]=\"getButtonAriaLabel(element, asItemColumn(column, it)) || getButtonLabel(element, asItemColumn(column, it))\" (click)=\"onButtonClick(element, asItemColumn(column, it), $event)\"><mat-icon *ngIf=\"getButtonIcon(element, asItemColumn(column, it)) as bi\">{{ bi }}</mat-icon>{{ getButtonLabel(element, asItemColumn(column, it)) }}</button>\n </ng-container>\n </ng-container>\n <ng-container *ngSwitchCase=\"'chip'\">\n <span class=\"pfx-chip\" [ngClass]=\"getChipClasses(element, asItemColumn(column, it))\"><mat-icon *ngIf=\"getChipIcon(element, asItemColumn(column, it)) as ci\" class=\"pfx-chip-icon\">{{ ci }}</mat-icon><span class=\"pfx-chip-text\">{{ getChipText(element, asItemColumn(column, it)) }}</span></span>\n </ng-container>\n <ng-container *ngSwitchCase=\"'progress'\">\n <div class=\"pfx-progress\"><div class=\"pfx-progress-bar\" [style.width.%]=\"getProgressValue(element, asItemColumn(column, it))\" [style.background]=\"getProgressColor(element, asItemColumn(column, it)) || null\"></div><div class=\"pfx-progress-label\" *ngIf=\"getProgressShowLabel(element, asItemColumn(column, it))\">{{ getProgressValue(element, asItemColumn(column, it)) }}%</div></div>\n </ng-container>\n <ng-container *ngSwitchCase=\"'avatar'\">\n <ng-container *ngIf=\"getAvatarSrc(element, asItemColumn(column, it)) as asrc; else initials_comp\">\n <img class=\"pfx-avatar\" [src]=\"asrc\" [attr.alt]=\"getAvatarAlt(element, asItemColumn(column, it)) || ''\" [ngStyle]=\"getAvatarStyle(element, asItemColumn(column, it))\" [class.shape-rounded]=\"getAvatarShape(element, asItemColumn(column, it)) === 'rounded'\" [class.shape-circle]=\"getAvatarShape(element, asItemColumn(column, it)) === 'circle'\" loading=\"lazy\" />\n </ng-container>\n <ng-template #initials_comp>\n <span class=\"pfx-avatar pfx-avatar--initials\" [ngStyle]=\"getAvatarStyle(element, asItemColumn(column, it))\" [class.shape-rounded]=\"getAvatarShape(element, asItemColumn(column, it)) === 'rounded'\" [class.shape-circle]=\"getAvatarShape(element, asItemColumn(column, it)) === 'circle'\">{{ getAvatarInitials(element, asItemColumn(column, it)) }}</span>\n </ng-template>\n </ng-container>\n <ng-container *ngSwitchCase=\"'toggle'\">\n <mat-slide-toggle [checked]=\"getToggleState(element, asItemColumn(column, it))\" [disabled]=\"isToggleDisabled(element, asItemColumn(column, it))\" [attr.aria-label]=\"getToggleAriaLabel(element, asItemColumn(column, it)) || 'Alternar'\" (change)=\"onToggleChange(element, asItemColumn(column, it), $event)\" (click)=\"$event.stopPropagation()\"></mat-slide-toggle>\n </ng-container>\n <ng-container *ngSwitchCase=\"'menu'\">\n <button mat-icon-button [matMenuTriggerFor]=\"menuRef\" (click)=\"$event.stopPropagation()\" [attr.aria-label]=\"getMenuAriaLabel(element, asItemColumn(column, it)) || 'Menu'\"><mat-icon>more_vert</mat-icon></button>\n <mat-menu #menuRef=\"matMenu\">\n <button mat-menu-item *ngFor=\"let mi of getMenuItems(element, asItemColumn(column, it))\" (click)=\"onMenuItemClick(mi.id, element, $event)\" [disabled]=\"!mi.__visible\"><mat-icon *ngIf=\"mi.icon\">{{ mi.icon }}</mat-icon><span>{{ mi.label }}</span></button>\n </mat-menu>\n </ng-container>\n <ng-container *ngSwitchCase=\"'html'\">\n <span [innerHTML]=\"getSafeHtml(element, asItemColumn(column, it))\"></span>\n </ng-container>\n <!-- Value item: render base cell text alongside visuals -->\n <ng-container *ngSwitchCase=\"'value'\">\n <span class=\"pfx-cell-value\">{{ getCellValue(element, column) }}</span>\n </ng-container>\n </ng-container>\n </ng-container>\n </span>\n </ng-container>\n\n <!-- Default text rendering -->\n <ng-container *ngSwitchDefault>\n {{ getCellValue(element, column) }}\n </ng-container>\n </ng-container>\n </td>\n </ng-container>\n <ng-container *ngIf=\"config.actions?.row?.enabled\" matColumnDef=\"_actions\" [sticky]=\"config.actions?.row?.sticky === true || config.actions?.row?.sticky === 'start'\" [stickyEnd]=\"config.actions?.row?.sticky === 'end'\">\n <th mat-header-cell *matHeaderCellDef #actionsHeaderCell [style.width]=\"config.actions?.row?.width\" class=\"praxis-actions-header\" [class.align-start]=\"getActionsHeaderAlign() === 'start'\" [class.align-center]=\"getActionsHeaderAlign() === 'center'\" [class.align-end]=\"getActionsHeaderAlign() === 'end'\">\n <div class=\"praxis-actions-header__content\" [matTooltip]=\"getActionsHeaderTooltip() || ''\" [matTooltipDisabled]=\"!getActionsHeaderTooltip()\">\n <mat-icon *ngIf=\"getActionsHeaderIcon() as hi\" [praxisIcon]=\"hi\"></mat-icon>\n <span class=\"label\" *ngIf=\"getActionsHeaderLabel() as hl\">{{ hl }}</span>\n </div>\n </th>\n <td\n mat-cell\n *matCellDef=\"let row\"\n class=\"praxis-actions-cell\"\n [class.dense]=\"dense\"\n [style.width]=\"config.actions?.row?.width\"\n >\n <div class=\"praxis-actions-cell__content\">\n <!-- A\u00E7\u00F5es inline -->\n <!-- Inline actions: icons mode -->\n <ng-container *ngIf=\"config.actions?.row?.display === 'icons' || !config.actions?.row?.display\">\n <ng-container *ngFor=\"let a of getInlineRowActions(row); trackBy: trackAction\">\n <button\n mat-icon-button\n class=\"praxis-icon-btn\"\n [disabled]=\"isActionDisabled(a, row)\"\n (click)=\"onRowAction(getActionId(a), row, $event)\"\n [matTooltip]=\"a.label || getActionId(a)\"\n matTooltipPosition=\"above\"\n matTooltipClass=\"praxis-tooltip\"\n [attr.aria-label]=\"a.label || getActionId(a)\"\n [color]=\"a.color || null\"\n >\n <mat-icon [praxisIcon]=\"a.icon\"></mat-icon>\n </button>\n </ng-container>\n </ng-container>\n\n <!-- Inline actions: buttons mode (show label + icon) -->\n <ng-container *ngIf=\"config.actions?.row?.display === 'buttons'\">\n <ng-container *ngFor=\"let a of getInlineRowActions(row); trackBy: trackAction\">\n <button\n mat-flat-button\n class=\"praxis-row-btn\"\n [disabled]=\"isActionDisabled(a, row)\"\n (click)=\"onRowAction(getActionId(a), row, $event)\"\n [attr.aria-label]=\"a.label || getActionId(a)\"\n [color]=\"a.color || null\"\n >\n <mat-icon [praxisIcon]=\"a.icon\"></mat-icon>\n <span>{{ a.label || getActionId(a) }}</span>\n </button>\n </ng-container>\n </ng-container>\n\n <!-- Menu de overflow -->\n <button\n mat-icon-button\n class=\"praxis-icon-btn praxis-more-btn\"\n *ngIf=\"hasOverflowRowActions(row)\"\n [matMenuTriggerFor]=\"rowMoreMenu\"\n [color]=\"getRowMenuButtonColor() || null\"\n aria-label=\"Mais a\u00E7\u00F5es\"\n >\n <mat-icon [praxisIcon]=\"getRowMenuIcon()\"></mat-icon>\n </button>\n <mat-menu #rowMoreMenu=\"matMenu\" xPosition=\"before\">\n <ng-container\n *ngFor=\"let a of getOverflowRowActions(row); trackBy: trackAction\"\n >\n <button\n mat-menu-item\n (click)=\"onRowAction(getActionId(a), row, $event)\"\n [disabled]=\"isActionDisabled(a, row)\"\n >\n <mat-icon [color]=\"a.color || null\" [praxisIcon]=\"a.icon\"></mat-icon>\n <span>{{ a.label || getActionId(a) }}</span>\n </button>\n </ng-container>\n </mat-menu>\n </div>\n </td>\n </ng-container>\n\n <tr mat-header-row *matHeaderRowDef=\"displayedColumns\"></tr>\n <ng-container *ngIf=\"!isVirtualized()\">\n <tr\n mat-row\n *matRowDef=\"let row; let i = index; columns: displayedColumns\"\n [ngClass]=\"getRowClasses(row)\"\n [ngStyle]=\"getRowNgStyle(row)\"\n [matTooltip]=\"getRowTooltip(row) || null\"\n [matTooltipDisabled]=\"!getRowTooltip(row)\"\n [matTooltipPosition]=\"getRowTooltipPosition(row)\"\n [matTooltipShowDelay]=\"getRowTooltipShowDelay(row)\"\n (click)=\"onRowClicked(row, i)\"\n (dblclick)=\"onRowDoubleClicked(row, i)\"\n ></tr>\n </ng-container>\n</table>\n\n<!-- Virtual rows path (header preserved above) -->\n<ng-container *ngIf=\"resourcePath && !schemaError && !dataError && isVirtualized()\">\n <cdk-virtual-scroll-viewport\n class=\"ptable-viewport\"\n [itemSize]=\"getVirtItemHeight()\"\n [minBufferPx]=\"getVirtBufferSize() * getVirtItemHeight()\"\n [maxBufferPx]=\"getVirtBufferSize() * getVirtItemHeight() * 2\"\n [style.minHeight]=\"getVirtMinHeightStyle()\"\n >\n <table class=\"mat-mdc-table mat-elevation-z8\" [style.width]=\"horizontalScroll === 'auto' ? 'max-content' : '100%'\">\n <tbody>\n <tr class=\"mat-mdc-row\"\n *cdkVirtualFor=\"let row of dataSource.data; let i = index; trackBy: trackByRow\"\n [ngClass]=\"getRowClasses(row)\"\n [ngStyle]=\"getRowNgStyle(row)\"\n [matTooltip]=\"getRowTooltip(row) || null\"\n [matTooltipDisabled]=\"!getRowTooltip(row)\"\n [matTooltipPosition]=\"getRowTooltipPosition(row)\"\n [matTooltipShowDelay]=\"getRowTooltipShowDelay(row)\"\n (click)=\"onRowClicked(row, i)\"\n (dblclick)=\"onRowDoubleClicked(row, i)\">\n <!-- Selection column -->\n <td class=\"mat-mdc-cell\" *ngIf=\"config.behavior?.selection?.enabled\">\n <mat-checkbox\n (click)=\"$event.stopPropagation()\"\n (change)=\"toggleRow(row)\"\n [checked]=\"selection.isSelected(row)\">\n </mat-checkbox>\n </td>\n <!-- Data columns -->\n <td class=\"mat-mdc-cell\"\n *ngFor=\"let column of visibleColumns\"\n [style.text-align]=\"column.align\"\n [style.width]=\"column.width\"\n [attr.style]=\"column.style\"\n [ngClass]=\"getCellClasses(row, column)\"\n [ngStyle]=\"getCellNgStyle(row, column)\">\n <ng-container [ngSwitch]=\"getEffectiveRendererType(row, column)\">\n <ng-container *ngSwitchCase=\"'icon'\">\n <mat-icon [color]=\"getIconColor(row, column) || null\"\n [ngStyle]=\"getIconStyle(row, column)\"\n [attr.aria-label]=\"getIconAriaLabel(row, column) || null\">\n {{ getIconName(row, column) }}\n </mat-icon>\n </ng-container>\n <ng-container *ngSwitchCase=\"'image'\">\n <img class=\"pfx-cell-image\"\n [src]=\"getImageSrc(row, column)\"\n [attr.alt]=\"getImageAlt(row, column) || ''\"\n [attr.loading]=\"getImageLazy(row, column) ? 'lazy' : null\"\n [style.width.px]=\"getImageWidth(row, column)\"\n [style.height.px]=\"getImageHeight(row, column)\"\n [class.shape-rounded]=\"getImageShape(row, column) === 'rounded'\"\n [class.shape-circle]=\"getImageShape(row, column) === 'circle'\"\n [style.object-fit]=\"getImageFit(row, column)\" />\n </ng-container>\n <ng-container *ngSwitchCase=\"'badge'\">\n <span class=\"pfx-badge\" [ngClass]=\"getBadgeClasses(row, column)\">\n <mat-icon *ngIf=\"getBadgeIcon(row, column) as bi\" class=\"pfx-badge-icon\">{{ bi }}</mat-icon>\n <span class=\"pfx-badge-text\">{{ getBadgeText(row, column) }}</span>\n </span>\n </ng-container>\n <ng-container *ngSwitchDefault>\n {{ getCellValue(row, column) }}\n </ng-container>\n </ng-container>\n </td>\n\n <!-- Actions column -->\n <td class=\"mat-mdc-cell praxis-actions-cell\" *ngIf=\"config.actions?.row?.enabled\" [class.dense]=\"dense\" [style.width]=\"config.actions?.row?.width\">\n <div class=\"praxis-actions-cell__content\">\n <ng-container *ngIf=\"config.actions?.row?.display === 'icons' || !config.actions?.row?.display\">\n <ng-container *ngFor=\"let a of getInlineRowActions(row); trackBy: trackAction\">\n <button mat-icon-button class=\"praxis-icon-btn\"\n [disabled]=\"isActionDisabled(a, row)\"\n (click)=\"onRowAction(getActionId(a), row, $event)\"\n [matTooltip]=\"a.label || getActionId(a)\"\n matTooltipPosition=\"above\"\n matTooltipClass=\"praxis-tooltip\"\n [attr.aria-label]=\"a.label || getActionId(a)\"\n [color]=\"a.color || null\">\n <mat-icon [praxisIcon]=\"a.icon\"></mat-icon>\n </button>\n </ng-container>\n </ng-container>\n <ng-container *ngIf=\"config.actions?.row?.display === 'buttons'\">\n <ng-container *ngFor=\"let a of getInlineRowActions(row); trackBy: trackAction\">\n <button mat-flat-button class=\"praxis-row-btn\"\n [disabled]=\"isActionDisabled(a, row)\"\n (click)=\"onRowAction(getActionId(a), row, $event)\"\n [attr.aria-label]=\"a.label || getActionId(a)\"\n [color]=\"a.color || null\">\n <mat-icon [praxisIcon]=\"a.icon\"></mat-icon>\n <span>{{ a.label || getActionId(a) }}</span>\n </button>\n </ng-container>\n </ng-container>\n <button mat-icon-button class=\"praxis-icon-btn praxis-more-btn\"\n *ngIf=\"hasOverflowRowActions(row)\"\n [matMenuTriggerFor]=\"rowMoreMenuV\"\n [color]=\"getRowMenuButtonColor() || null\"\n aria-label=\"Mais a\u00E7\u00F5es\">\n <mat-icon [praxisIcon]=\"getRowMenuIcon()\"></mat-icon>\n </button>\n <mat-menu #rowMoreMenuV=\"matMenu\" xPosition=\"before\">\n <ng-container *ngFor=\"let a of getOverflowRowActions(row); trackBy: trackAction\">\n <button mat-menu-item (click)=\"onRowAction(getActionId(a), row, $event)\" [disabled]=\"isActionDisabled(a, row)\">\n <mat-icon [color]=\"a.color || null\" [praxisIcon]=\"a.icon\"></mat-icon>\n <span>{{ a.label || getActionId(a) }}</span>\n </button>\n </ng-container>\n </mat-menu>\n </div>\n </td>\n </tr>\n </tbody>\n </table>\n </cdk-virtual-scroll-viewport>\n</ng-container>\n\n</div>\n<!-- Paginadores (top/bottom) -->\n<mat-paginator\n *ngIf=\"resourcePath && !schemaError && !dataError && getPaginationEnabled() && (config.behavior?.pagination?.position === 'top' || config.behavior?.pagination?.position === 'both')\"\n [length]=\"getPaginationLength()\"\n [pageSize]=\"getPaginationPageSize()\"\n [pageSizeOptions]=\"getPaginationPageSizeOptions()\"\n [showFirstLastButtons]=\"getPaginationShowFirstLast()\"\n (page)=\"onPageChange($event)\"\n [class.compact]=\"config.behavior?.pagination?.style === 'compact'\"\n>\n</mat-paginator>\n\n<mat-paginator\n *ngIf=\"resourcePath && !schemaError && !dataError && getPaginationEnabled() && (config.behavior?.pagination?.position === 'bottom' || config.behavior?.pagination?.position === 'both' || !config.behavior?.pagination?.position)\"\n [length]=\"getPaginationLength()\"\n [pageSize]=\"getPaginationPageSize()\"\n [pageSizeOptions]=\"getPaginationPageSizeOptions()\"\n [showFirstLastButtons]=\"getPaginationShowFirstLast()\"\n (page)=\"onPageChange($event)\"\n [class.compact]=\"config.behavior?.pagination?.style === 'compact'\"\n>\n</mat-paginator>\n", styles: ["@charset \"UTF-8\";table{width:100%}.praxis-actions-cell{height:100%;padding-inline:12px;white-space:nowrap}:host.density-compact{--p-header-padding: 8px 12px;--p-actions-btn-size: 32px;--p-actions-icon-size: 18px}:host.density-comfortable{--p-header-padding: 12px 16px;--p-actions-btn-size: 40px;--p-actions-icon-size: 22px}:host.density-spacious{--p-header-padding: 16px 20px;--p-actions-btn-size: 44px;--p-actions-icon-size: 24px}:host.density-compact ::ng-deep .mat-mdc-cell{padding:8px 12px}:host.density-comfortable ::ng-deep .mat-mdc-cell{padding:12px 16px}:host.density-spacious ::ng-deep .mat-mdc-cell{padding:16px 20px}:host.density-compact .praxis-actions-cell{padding-inline:8px}:host.density-spacious .praxis-actions-cell{padding-inline:16px}.praxis-actions-cell__content{display:flex;align-items:center;justify-content:flex-end;gap:8px;width:100%}.praxis-actions-cell.dense .praxis-actions-cell__content{gap:6px}.praxis-icon-btn{width:var(--p-actions-btn-size, 40px);height:var(--p-actions-btn-size, 40px);border:0;background:transparent;padding:0;display:inline-flex;align-items:center;justify-content:center;border-radius:9999px;cursor:pointer;--mat-icon-button-state-layer-size: var(--p-actions-btn-size, 40px)}.praxis-icon-btn:hover{background:var(--md-sys-color-surface-variant, rgba(255, 255, 255, .06))}.praxis-icon-btn:focus-visible{outline:2px solid var(--primary, #48a1ff);outline-offset:2px}.praxis-icon-btn mat-icon,.praxis-icon-btn .mat-icon{font-size:var(--p-actions-icon-size, 22px);width:var(--p-actions-icon-size, 22px);height:var(--p-actions-icon-size, 22px);line-height:var(--p-actions-icon-size, 22px)}.praxis-more-btn{width:var(--p-actions-more-btn-size, var(--p-actions-btn-size, 40px));height:var(--p-actions-more-btn-size, var(--p-actions-btn-size, 40px));--mat-icon-button-state-layer-size: var(--p-actions-more-btn-size, var(--p-actions-btn-size, 40px));background-image:var(--p-actions-more-btn-gradient, none);background-size:100% 100%;background-repeat:no-repeat}.praxis-more-btn mat-icon,.praxis-more-btn .mat-icon{font-size:var(--p-actions-more-icon-size, var(--p-actions-icon-size, 22px));width:var(--p-actions-more-icon-size, var(--p-actions-icon-size, 22px));height:var(--p-actions-more-icon-size, var(--p-actions-icon-size, 22px));line-height:var(--p-actions-more-icon-size, var(--p-actions-icon-size, 22px));color:var(--p-actions-more-icon-color);background-image:var(--p-actions-more-icon-gradient, none);-webkit-background-clip:text;background-clip:text}.praxis-icon-btn.destructive mat-icon{color:#ff6b6b}.mat-mdc-tooltip.praxis-tooltip{margin-top:-8px;margin-bottom:8px}.spacer{flex:1 1 auto}.praxis-table-header{display:flex;flex-wrap:wrap;align-items:flex-start;gap:8px;margin:16px 0 12px;width:100%;clear:both;position:relative}.praxis-table-header.debug-layout,:host.debug-layout .praxis-table-header{outline:2px dashed #ff4d4f;border-radius:8px}:host.debug-layout ::ng-deep .praxis-filter-bar{outline:1px dashed #f59e0b}:host.debug-layout ::ng-deep .quick-shell{outline:1px dashed #3b82f6}:host.debug-layout ::ng-deep .always-fields{outline:1px dashed #22c55e}:host.debug-layout ::ng-deep .praxis-filter-overlay .praxis-filter-advanced{outline:2px solid #a855f7}:host.debug-layout ::ng-deep .mat-mdc-table{outline:1px dashed #94a3b8}.praxis-table-header>praxis-table-toolbar{flex:1 0 100%}:host{--p-table-header-bg: var(--md-sys-color-surface-container-highest, #1d1d1f);--p-table-header-fg: var(--md-sys-color-on-surface, #e8f3f1);--p-table-border-color: var(--md-sys-color-outline-variant, rgba(255, 255, 255, .12));--p-table-row-even-bg: var(--md-sys-color-surface-container, rgba(255, 255, 255, .04));--p-table-row-hover-bg: color-mix(in srgb, var(--md-sys-color-primary, #3f51b5) 10%, transparent);--p-table-row-selected-bg: var(--md-sys-color-primary-container, rgba(63,81,181,.14));--p-table-badge-soft-primary-bg: color-mix(in srgb, var(--mat-sys-primary, var(--md-sys-color-primary)) 16%, transparent);--p-table-badge-soft-primary-fg: var(--mat-sys-primary, var(--md-sys-color-primary));--p-table-badge-soft-accent-bg: color-mix(in srgb, var(--mat-sys-secondary, var(--md-sys-color-secondary, #ff4081)) 14%, transparent);--p-table-badge-soft-accent-fg: var(--mat-sys-secondary, var(--md-sys-color-secondary, #ff4081));--p-table-badge-soft-warn-bg: color-mix(in srgb, var(--mat-sys-error, var(--md-sys-color-error, #f44336)) 14%, transparent);--p-table-badge-soft-warn-fg: var(--mat-sys-error, var(--md-sys-color-error, #f44336));--p-table-state-success-bg: color-mix(in srgb, var(--mat-sys-tertiary, var(--md-sys-color-tertiary, #388E3C)) 16%, transparent);--p-table-state-success-fg: var(--md-sys-color-on-surface, #c8e6c9);--p-table-state-warning-bg: color-mix(in srgb, var(--md-sys-color-secondary, #FFA000) 18%, transparent);--p-table-state-warning-fg: var(--md-sys-color-on-surface, #ffe0b2);--p-table-state-danger-bg: color-mix(in srgb, var(--md-sys-color-error, #e53935) 18%, transparent);--p-table-state-danger-fg: var(--md-sys-color-on-surface, #ffcdd2);--p-table-state-highlight-bg: color-mix(in srgb, var(--md-sys-color-primary, #2196f3) 16%, transparent);--p-table-state-highlight-fg: var(--md-sys-color-on-surface, #bbdefb)}:host ::ng-deep .mat-mdc-table{background:var(--md-sys-color-surface-container-highest, #1d1d1f);border-radius:12px;width:100%}:host [data-role=table-settings].mat-mdc-icon-button{--mdc-icon-button-icon-color: var(--mat-sys-primary, var(--md-sys-color-primary, #3f51b5));color:var(--mat-sys-primary, var(--md-sys-color-primary, #3f51b5))}.pfx-link{color:var(--mat-sys-primary, #3f51b5);text-decoration:underline;cursor:pointer}.pfx-chip{display:inline-flex;align-items:center;gap:4px;padding:2px 8px;border-radius:10px;font-size:12px;line-height:1;border:1px solid transparent}.pfx-chip-icon{font-size:14px;width:14px;height:14px}.pfx-chip--outlined{background:transparent;border-color:var(--mat-sys-outline-variant);color:var(--mat-sys-on-surface)}.pfx-chip--filled-primary{background:var(--mat-sys-primary);color:var(--mat-sys-on-primary)}.pfx-chip--filled-accent{background:var(--mat-sys-secondary, #ff4081);color:#fff}.pfx-chip--filled-warn{background:var(--mat-sys-error, #f44336);color:#fff}.pfx-chip--soft-primary{background:var(--p-table-badge-soft-primary-bg);color:var(--p-table-badge-soft-primary-fg)}.pfx-chip--soft-accent{background:var(--p-table-badge-soft-accent-bg);color:var(--p-table-badge-soft-accent-fg)}.pfx-chip--soft-warn{background:var(--p-table-badge-soft-warn-bg);color:var(--p-table-badge-soft-warn-fg)}.pfx-progress{position:relative;width:100%;max-width:140px;height:8px;background:var(--mat-sys-surface-container-highest, rgba(255, 255, 255, .08));border-radius:4px;overflow:hidden;display:inline-block;vertical-align:middle}.pfx-progress-bar{height:100%;background:var(--mat-sys-primary);transition:width .2s ease}.pfx-progress-label{margin-left:8px;font-size:12px;opacity:.8;display:inline-block;vertical-align:middle}.pfx-avatar{display:inline-flex;align-items:center;justify-content:center;background:var(--mat-sys-surface-container, #2a2a2e);color:var(--mat-sys-on-surface, #eee);border-radius:4px;overflow:hidden;font-weight:600}.pfx-avatar.shape-rounded{border-radius:8px}.pfx-avatar.shape-circle{border-radius:999px}.pfx-avatar--initials{text-transform:uppercase;font-size:12px}.pfx-cell-compose{display:inline-flex;align-items:center;gap:6px}.pfx-cell-compose.dir-col{flex-direction:column;align-items:stretch}.pfx-cell-compose.align-start{justify-content:flex-start}.pfx-cell-compose.align-center{justify-content:center}.pfx-cell-compose.align-end{justify-content:flex-end}.pfx-cell-compose.wrap{flex-wrap:wrap}.pfx-cell-compose.ellipsis{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.px-scroll-viewport{width:100%;overflow-x:auto;-webkit-overflow-scrolling:touch;overscroll-behavior-x:contain;scrollbar-gutter:stable}.px-scroll-viewport.scroll-none{overflow-x:visible}.px-scroll-viewport.scroll-auto ::ng-deep .mat-mdc-table{width:max-content;min-width:100%}.px-scroll-viewport.scroll-wrap ::ng-deep .mat-mdc-header-cell,.px-scroll-viewport.scroll-wrap ::ng-deep .mat-mdc-cell{white-space:normal;text-overflow:initial}.px-scroll-viewport.scroll-wrap ::ng-deep .mat-mdc-table{width:100%}:host ::ng-deep .mat-mdc-header-row{position:sticky;top:0;z-index:1;background:var(--p-table-header-bg);color:var(--p-table-header-fg);box-shadow:var(--p-table-header-shadow, 0 1px 0 var(--p-table-border-color));border-bottom:1px solid var(--p-table-border-color)}:host ::ng-deep .mat-mdc-header-cell,:host ::ng-deep .mat-sort-header-content,:host ::ng-deep .mat-mdc-header-row .mat-icon{color:var(--p-table-header-fg)!important;font-weight:600}:host ::ng-deep .mat-mdc-header-cell.mat-sort-header-sorted .mat-sort-header-arrow,:host ::ng-deep .mat-mdc-header-cell:hover .mat-sort-header-arrow{color:var(--p-table-header-fg)!important}:host ::ng-deep .mat-mdc-header-cell.mat-sort-header-sorted .mat-sort-header-arrow .mat-sort-header-indicator,:host ::ng-deep .mat-mdc-header-cell.mat-sort-header-sorted .mat-sort-header-arrow .mat-sort-header-stem,:host ::ng-deep .mat-mdc-header-cell.mat-sort-header-sorted .mat-sort-header-arrow .mat-sort-header-pointer,:host ::ng-deep .mat-mdc-header-cell.mat-sort-header-sorted .mat-sort-header-arrow .mat-sort-header-pointer-left,:host ::ng-deep .mat-mdc-header-cell.mat-sort-header-sorted .mat-sort-header-arrow .mat-sort-header-pointer-right{border-color:var(--p-table-header-fg)!important;background:var(--p-table-header-fg)!important}:host ::ng-deep .mat-mdc-header-cell{padding:var(--p-header-padding, 12px 16px)!important;font-size:var(--p-header-font-size, inherit);font-weight:var(--p-header-font-weight, 600);letter-spacing:var(--p-header-letter-spacing, normal);text-transform:var(--p-header-text-transform, none);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.praxis-actions-header{text-align:right}.praxis-actions-header.align-start{text-align:left}.praxis-actions-header.align-center{text-align:center}.praxis-actions-header.align-end{text-align:right}.praxis-actions-header .praxis-actions-header__content{display:inline-flex;align-items:center;gap:var(--p-actions-header-gap, 6px);color:var(--p-actions-header-color, inherit)}.praxis-actions-header .praxis-actions-header__content .mat-icon{font-size:18px;width:18px;height:18px;line-height:18px}:host ::ng-deep .mat-mdc-header-cell .mat-sort-header-container{padding-right:20px}:host ::ng-deep .mat-mdc-cell{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}:host ::ng-deep .mat-mdc-row:hover{background:var(--p-table-row-hover-bg)}:host ::ng-deep .mat-mdc-row:nth-child(2n){background:var(--p-table-row-even-bg)}:host.row-borders ::ng-deep .mat-mdc-row .mat-mdc-cell{border-bottom:1px solid var(--p-table-border-color)}:host.row-borders ::ng-deep .mat-mdc-header-row .mat-mdc-header-cell{border-bottom:none}:host.col-borders ::ng-deep .mat-mdc-header-row .mat-mdc-header-cell,:host.col-borders ::ng-deep .mat-mdc-row .mat-mdc-cell{border-right:1px solid var(--p-table-border-color)}:host.col-borders ::ng-deep .mat-mdc-header-row .mat-mdc-header-cell:last-child,:host.col-borders ::ng-deep .mat-mdc-row .mat-mdc-cell:last-child{border-right:none}.ptable-info-banner{display:flex;gap:12px;align-items:center;padding:8px 12px;margin:8px 0;border-radius:8px;border:1px solid var(--mat-sys-primary, var(--md-sys-color-primary, #1a73e8));background:color-mix(in srgb,var(--mat-sys-primary, var(--md-sys-color-primary, #1a73e8)) 10%,transparent)}.ptable-info-banner .text{flex:1;font-weight:600}.ptable-info-banner .actions{display:flex;gap:8px}.pfx-cell-image{display:inline-block;vertical-align:middle;background:var(--md-sys-color-surface-variant, #2a2a2a);border:1px solid var(--md-sys-color-outline-variant, rgba(0, 0, 0, .08))}.pfx-cell-image.shape-rounded{border-radius:8px}.pfx-cell-image.shape-circle{border-radius:9999px}.pfx-badge{display:inline-flex;align-items:center;gap:6px;line-height:1;padding:4px 8px;border-radius:9999px;font-size:12px;font-weight:600;border:1px solid transparent}.pfx-badge .pfx-badge-icon{font-size:16px;width:16px;height:16px}.pfx-badge--filled-primary{background:var(--mat-sys-primary, #3f51b5);color:var(--mat-sys-on-primary, #fff)}.pfx-badge--filled-accent{background:var(--mat-sys-secondary, #ff4081);color:var(--mat-sys-on-secondary, #fff)}.pfx-badge--filled-warn{background:var(--mat-sys-error, #f44336);color:var(--mat-sys-on-error, #fff)}.pfx-badge--outlined{background:transparent;border-color:var(--mat-sys-outline-variant, rgba(255, 255, 255, .24));color:inherit}.pfx-badge--soft-primary{background:var(--p-table-badge-soft-primary-bg);color:var(--p-table-badge-soft-primary-fg)}.pfx-badge--soft-accent{background:var(--p-table-badge-soft-accent-bg);color:var(--p-table-badge-soft-accent-fg)}.pfx-badge--soft-warn{background:var(--p-table-badge-soft-warn-bg);color:var(--p-table-badge-soft-warn-fg)}.row--success,.row--success td,td.row--success{background-color:var(--p-table-state-success-bg)!important;color:var(--p-table-state-success-fg)!important}.row--warning,.row--warning td,td.row--warning{background-color:var(--p-table-state-warning-bg)!important;color:var(--p-table-state-warning-fg)!important}.row--danger,.row--danger td,td.row--danger{background-color:var(--p-table-state-danger-bg)!important;color:var(--p-table-state-danger-fg)!important}.row--highlight,.row--highlight td,td.row--highlight{background-color:var(--p-table-state-highlight-bg)!important;color:var(--p-table-state-highlight-fg)!important;font-weight:600}.row--muted,.row--muted td,td.row--muted{opacity:.7;filter:saturate(.6)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "directive", type: i1.NgSwitch, selector: "[ngSwitch]", inputs: ["ngSwitch"] }, { kind: "directive", type: i1.NgSwitchCase, selector: "[ngSwitchCase]", inputs: ["ngSwitchCase"] }, { kind: "directive", type: i1.NgSwitchDefault, selector: "[ngSwitchDefault]" }, { kind: "ngmodule", type: MatTableModule }, { kind: "component", type: i8.MatTable, selector: "mat-table, table[mat-table]", exportAs: ["matTable"] }, { kind: "directive", type: i8.MatHeaderCellDef, selector: "[matHeaderCellDef]" }, { kind: "directive", type: i8.MatHeaderRowDef, selector: "[matHeaderRowDef]", inputs: ["matHeaderRowDef", "matHeaderRowDefSticky"] }, { kind: "directive", type: i8.MatColumnDef, selector: "[matColumnDef]", inputs: ["matColumnDef"] }, { kind: "directive", type: i8.MatCellDef, selector: "[matCellDef]" }, { kind: "directive", type: i8.MatRowDef, selector: "[matRowDef]", inputs: ["matRowDefColumns", "matRowDefWhen"] }, { kind: "directive", type: i8.MatHeaderCell, selector: "mat-header-cell, th[mat-header-cell]" }, { kind: "directive", type: i8.MatCell, selector: "mat-cell, td[mat-cell]" }, { kind: "component", type: i8.MatHeaderRow, selector: "mat-header-row, tr[mat-header-row]", exportAs: ["matHeaderRow"] }, { kind: "component", type: i8.MatRow, selector: "mat-row, tr[mat-row]", exportAs: ["matRow"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i3.MatButton, selector: " button[matButton], a[matButton], button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button], a[mat-button], a[mat-raised-button], a[mat-flat-button], a[mat-stroked-button] ", inputs: ["matButton"], exportAs: ["matButton", "matAnchor"] }, { kind: "component", type: i3.MatIconButton, selector: "button[mat-icon-button], a[mat-icon-button], button[matIconButton], a[matIconButton]", exportAs: ["matButton", "matAnchor"] }, { kind: "ngmodule", type: MatPaginatorModule }, { kind: "component", type: i11$1.MatPaginator, selector: "mat-paginator", inputs: ["color", "pageIndex", "length", "pageSize", "pageSizeOptions", "hidePageSize", "showFirstLastButtons", "selectConfig", "disabled"], outputs: ["page"], exportAs: ["matPaginator"] }, { kind: "ngmodule", type: MatSortModule }, { kind: "directive", type: i12.MatSort, selector: "[matSort]", inputs: ["matSortActive", "matSortStart", "matSortDirection", "matSortDisableClear", "matSortDisabled"], outputs: ["matSortChange"], exportAs: ["matSort"] }, { kind: "component", type: i12.MatSortHeader, selector: "[mat-sort-header]", inputs: ["mat-sort-header", "arrowPosition", "start", "disabled", "sortActionDescription", "disableClear"], exportAs: ["matSortHeader"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i4.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatMenuModule }, { kind: "component", type: i5.MatMenu, selector: "mat-menu", inputs: ["backdropClass", "aria-label", "aria-labelledby", "aria-describedby", "xPosition", "yPosition", "overlapTrigger", "hasBackdrop", "class", "classList"], outputs: ["closed", "close"], exportAs: ["matMenu"] }, { kind: "component", type: i5.MatMenuItem, selector: "[mat-menu-item]", inputs: ["role", "disabled", "disableRipple"], exportAs: ["matMenuItem"] }, { kind: "directive", type: i5.MatMenuTrigger, selector: "[mat-menu-trigger-for], [matMenuTriggerFor]", inputs: ["mat-menu-trigger-for", "matMenuTriggerFor", "matMenuTriggerData", "matMenuTriggerRestoreFocus"], outputs: ["menuOpened", "onMenuOpen", "menuClosed", "onMenuClose"], exportAs: ["matMenuTrigger"] }, { kind: "ngmodule", type: MatSlideToggleModule }, { kind: "component", type: i6$1.MatSlideToggle, selector: "mat-slide-toggle", inputs: ["name", "id", "labelPosition", "aria-label", "aria-labelledby", "aria-describedby", "required", "color", "disabled", "disableRipple", "tabIndex", "checked", "hideIcon", "disabledInteractive"], outputs: ["change", "toggleChange"], exportAs: ["matSlideToggle"] }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i10.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "ngmodule", type: MatSnackBarModule }, { kind: "ngmodule", type: MatCheckboxModule }, { kind: "component", type: i9.MatCheckbox, selector: "mat-checkbox", inputs: ["aria-label", "aria-labelledby", "aria-describedby", "aria-expanded", "aria-controls", "aria-owns", "id", "required", "labelPosition", "name", "value", "disableRipple", "tabIndex", "color", "disabledInteractive", "checked", "disabled", "indeterminate"], outputs: ["change", "indeterminateChange"], exportAs: ["matCheckbox"] }, { kind: "ngmodule", type: MatBadgeModule }, { kind: "directive", type: i15.MatBadge, selector: "[matBadge]", inputs: ["matBadgeColor", "matBadgeOverlap", "matBadgeDisabled", "matBadgePosition", "matBadge", "matBadgeDescription", "matBadgeSize", "matBadgeHidden"] }, { kind: "ngmodule", type: ScrollingModule }, { kind: "directive", type: i19.ɵɵCdkFixedSizeVirtualScroll, selector: "cdk-virtual-scroll-viewport[itemSize]", inputs: ["itemSize", "minBufferPx", "maxBufferPx"] }, { kind: "directive", type: i19.ɵɵCdkVirtualForOf, selector: "[cdkVirtualFor][cdkVirtualForOf]", inputs: ["cdkVirtualForOf", "cdkVirtualForTrackBy", "cdkVirtualForTemplate", "cdkVirtualForTemplateCacheSize"] }, { kind: "component", type: i19.ɵɵCdkVirtualScrollViewport, selector: "cdk-virtual-scroll-viewport", inputs: ["orientation", "appendOnly"], outputs: ["scrolledIndexChange"] }, { kind: "component", type: PraxisTableToolbar, selector: "praxis-table-toolbar", inputs: ["config", "debugLayout"], outputs: ["toolbarAction", "reset"] }, { kind: "component", type: PraxisFilter, selector: "praxis-filter", inputs: ["resourcePath", "formId", "mode", "notifyIfOutdated", "snoozeMs", "autoOpenSettingsOnOutdated", "editModeEnabled", "value", "quickField", "alwaysVisibleFields", "tags", "allowSaveTags", "persistenceKey", "i18n", "changeDebounceMs", "showFilterSettings", "summary", "summaryTemplate", "summaryMap", "autoSummary", "confirmTagDelete", "debugLayout", "placeBooleansInActions", "showToggleLabels", "alwaysMinWidth", "alwaysColsMd", "alwaysColsLg", "tagColor", "tagVariant", "tagButtonColor", "actionsButtonColor", "actionsVariant", "overlayVariant", "overlayBackdrop", "advancedOpenMode"], outputs: ["submit", "change", "clear", "modeChange", "requestSearch", "tagsChange", "metaChanged", "schemaStatusChange"] }, { kind: "directive", type: PraxisIconDirective, selector: "mat-icon[praxisIcon]", inputs: ["praxisIcon"] }, { kind: "component", type: EmptyStateCardComponent, selector: "praxis-empty-state-card", inputs: ["icon", "title", "description", "primaryAction", "secondaryActions", "inline"] }] });
|
|
24009
24066
|
}
|
|
24010
24067
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.4", ngImport: i0, type: PraxisTable, decorators: [{
|
|
24011
24068
|
type: Component,
|
|
@@ -24087,6 +24144,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.4", ngImpor
|
|
|
24087
24144
|
type: Output
|
|
24088
24145
|
}], schemaStatusChange: [{
|
|
24089
24146
|
type: Output
|
|
24147
|
+
}], metadataChange: [{
|
|
24148
|
+
type: Output
|
|
24090
24149
|
}], beforeDelete: [{
|
|
24091
24150
|
type: Output
|
|
24092
24151
|
}], afterDelete: [{
|