@praxisui/list 1.0.0-beta.26 → 1.0.0-beta.29

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.
@@ -12,6 +12,10 @@ import { MatChipsModule } from '@angular/material/chips';
12
12
  import { MatDividerModule } from '@angular/material/divider';
13
13
  import * as i7 from '@angular/material/button';
14
14
  import { MatButtonModule } from '@angular/material/button';
15
+ import * as i4$1 from '@angular/material/form-field';
16
+ import { MatFormFieldModule } from '@angular/material/form-field';
17
+ import * as i6 from '@angular/material/select';
18
+ import { MatSelectModule } from '@angular/material/select';
15
19
  import * as i2 from '@angular/forms';
16
20
  import { FormsModule, FormControl, ReactiveFormsModule } from '@angular/forms';
17
21
  import { BehaviorSubject, combineLatest, of, Subject } from 'rxjs';
@@ -19,12 +23,8 @@ import { auditTime, switchMap, map, catchError, finalize, shareReplay, debounceT
19
23
  import { SETTINGS_PANEL_DATA, SettingsPanelService } from '@praxisui/settings-panel';
20
24
  import * as i3$1 from '@angular/material/tabs';
21
25
  import { MatTabsModule } from '@angular/material/tabs';
22
- import * as i4$1 from '@angular/material/form-field';
23
- import { MatFormFieldModule } from '@angular/material/form-field';
24
26
  import * as i5 from '@angular/material/input';
25
27
  import { MatInputModule } from '@angular/material/input';
26
- import * as i6 from '@angular/material/select';
27
- import { MatSelectModule } from '@angular/material/select';
28
28
  import * as i8 from '@angular/material/slide-toggle';
29
29
  import { MatSlideToggleModule } from '@angular/material/slide-toggle';
30
30
  import * as i11 from '@angular/material/button-toggle';
@@ -43,13 +43,49 @@ import { produce } from 'immer';
43
43
  function evalExpr(expr, ctx) {
44
44
  if (!expr)
45
45
  return '';
46
- // Replace ${...} with values from context (item)
47
- return expr.replace(/\$\{([^}]+)\}/g, (_, path) => {
46
+ // Replace ${...} with values from context (item), supporting simple pipes inside placeholders
47
+ return expr.replace(/\$\{([^}]+)\}/g, (_, raw) => {
48
48
  try {
49
- const value = path
49
+ const { baseExpr, pipe } = splitFirstPipe(raw);
50
+ const value = baseExpr
50
51
  .split('.')
51
52
  .reduce((acc, k) => (acc == null ? undefined : acc[k]), ctx);
52
- return value == null ? '' : String(value);
53
+ let out = value == null ? '' : String(value);
54
+ if (pipe) {
55
+ const { name, args } = parsePipe(pipe);
56
+ if (name === 'bool') {
57
+ const [trueLabel, falseLabel] = parseTwoArgs(args);
58
+ const truthy = toBoolean(value);
59
+ out = truthy ? (trueLabel ?? 'Sim') : (falseLabel ?? 'Não');
60
+ }
61
+ if (name === 'date') {
62
+ const [localeArg, styleArg] = parseTwoArgs(args);
63
+ const dt = value ? new Date(value) : null;
64
+ if (dt && !isNaN(dt.getTime())) {
65
+ const fmt = new Intl.DateTimeFormat(localeArg || undefined, mapDateStyle(styleArg)).format(dt);
66
+ out = fmt;
67
+ }
68
+ else {
69
+ out = '';
70
+ }
71
+ }
72
+ if (name === 'map') {
73
+ const map = parseMap(args);
74
+ const key = String(value ?? '').trim();
75
+ out = map[key] ?? map[key.toLowerCase?.()] ?? map[key.toUpperCase?.()] ?? out;
76
+ }
77
+ if (name === 'number') {
78
+ const [localeArg, styleArg] = parseTwoArgs(args);
79
+ const num = Number(value);
80
+ if (isFinite(num)) {
81
+ const opt = {};
82
+ if ((styleArg || '').toLowerCase() === 'compact')
83
+ opt.notation = 'compact';
84
+ out = new Intl.NumberFormat(localeArg || undefined, opt).format(num);
85
+ }
86
+ }
87
+ }
88
+ return out;
53
89
  }
54
90
  catch {
55
91
  return '';
@@ -64,10 +100,6 @@ function evalExpr(expr, ctx) {
64
100
  function evaluateTemplate(def, item) {
65
101
  if (!def)
66
102
  return null;
67
- // Icons ignore pipes (usually a literal name)
68
- if (def.type === 'icon') {
69
- return { type: def.type, value: def.expr, class: def.class, style: def.style };
70
- }
71
103
  const { baseExpr, pipe } = splitFirstPipe(def.expr);
72
104
  let value = evalExpr(baseExpr, { item });
73
105
  if (pipe) {
@@ -124,6 +156,35 @@ function toBoolean(val) {
124
156
  const s = String(val).trim().toLowerCase();
125
157
  return s === 'true' || s === '1' || s === 'yes' || s === 'sim' || s === 'on';
126
158
  }
159
+ function mapDateStyle(style) {
160
+ switch ((style || '').toLowerCase()) {
161
+ case 'short':
162
+ return { dateStyle: 'short' };
163
+ case 'long':
164
+ return { dateStyle: 'long' };
165
+ case 'full':
166
+ return { dateStyle: 'full' };
167
+ case 'medium':
168
+ default:
169
+ return { dateStyle: 'medium' };
170
+ }
171
+ }
172
+ function parseMap(spec) {
173
+ const out = {};
174
+ if (!spec)
175
+ return out;
176
+ const entries = spec.split(/[,;|]/g).map(s => s.trim()).filter(Boolean);
177
+ for (const e of entries) {
178
+ const idx = e.indexOf('=');
179
+ if (idx === -1)
180
+ continue;
181
+ const k = e.slice(0, idx).trim();
182
+ const v = e.slice(idx + 1).trim();
183
+ if (k)
184
+ out[k] = v;
185
+ }
186
+ return out;
187
+ }
127
188
 
128
189
  function adaptSelection(config, items) {
129
190
  const mode = (config?.selection?.mode ?? 'none');
@@ -2689,6 +2750,11 @@ class PraxisList {
2689
2750
  prevPage() {
2690
2751
  this.data.prevPage();
2691
2752
  }
2753
+ setPageSize(ps) {
2754
+ const size = Number(ps);
2755
+ if (isFinite(size) && size > 0)
2756
+ this.data.setPageSize(size);
2757
+ }
2692
2758
  onEditorApplied(newCfg) {
2693
2759
  this.config = newCfg;
2694
2760
  // Optionally infer templates from backend schema if not defined
@@ -2787,7 +2853,59 @@ class PraxisList {
2787
2853
  value = truthy ? (t ?? 'Sim') : (f ?? 'Não');
2788
2854
  }
2789
2855
  }
2790
- return { type: def.type, value, class: def.class, style: def.style, color: def.color, variant: def.variant };
2856
+ // Optional color mapping from config.templating.chipColorMap
2857
+ let color = def.color;
2858
+ try {
2859
+ const map = this.config?.templating?.chipColorMap;
2860
+ if (map && typeof value === 'string') {
2861
+ const key = String(value).toLowerCase();
2862
+ const found = map[key] ?? map[value];
2863
+ if (found)
2864
+ color = found;
2865
+ }
2866
+ }
2867
+ catch { }
2868
+ // Optional label mapping
2869
+ try {
2870
+ const lmap = this.config?.templating?.chipLabelMap;
2871
+ if (lmap && typeof value === 'string') {
2872
+ const key = String(value).toLowerCase();
2873
+ const lbl = lmap[key] ?? lmap[value];
2874
+ if (lbl)
2875
+ value = lbl;
2876
+ }
2877
+ else if (typeof value === 'string') {
2878
+ value = this.prettyLabel(value);
2879
+ }
2880
+ }
2881
+ catch { }
2882
+ return { type: def.type, value, class: def.class, style: def.style, color, variant: def.variant };
2883
+ }
2884
+ if (def.type === 'icon') {
2885
+ const out = evaluateTemplate(def, item);
2886
+ // Optional color mapping from config.templating.iconColorMap
2887
+ try {
2888
+ const map = this.config?.templating?.iconColorMap;
2889
+ if (map) {
2890
+ const status = String(item?.status ?? '').trim();
2891
+ const icon = String(out?.value ?? '').trim();
2892
+ const tryKeys = [
2893
+ status,
2894
+ status.toLowerCase?.(),
2895
+ icon,
2896
+ icon.toLowerCase?.(),
2897
+ ].filter(Boolean);
2898
+ for (const k of tryKeys) {
2899
+ const found = map[k];
2900
+ if (found) {
2901
+ out.color = found;
2902
+ break;
2903
+ }
2904
+ }
2905
+ }
2906
+ }
2907
+ catch { }
2908
+ return out;
2791
2909
  }
2792
2910
  return evaluateTemplate(def, item);
2793
2911
  }
@@ -2835,6 +2953,21 @@ class PraxisList {
2835
2953
  const s = String(val).trim().toLowerCase();
2836
2954
  return s === 'true' || s === '1' || s === 'yes' || s === 'sim' || s === 'on';
2837
2955
  }
2956
+ // Format labels like 'EM_ANDAMENTO' -> 'Em andamento'; 'PLANEJADA' -> 'Planejada'
2957
+ prettyLabel(v) {
2958
+ try {
2959
+ const t = String(v ?? '')
2960
+ .replace(/[\s_\-]+/g, ' ')
2961
+ .trim()
2962
+ .toLowerCase();
2963
+ if (!t)
2964
+ return '';
2965
+ return t.replace(/\b\w/g, (m) => m.toUpperCase());
2966
+ }
2967
+ catch {
2968
+ return String(v ?? '');
2969
+ }
2970
+ }
2838
2971
  mapDateStyle(style) {
2839
2972
  switch ((style || '').toLowerCase()) {
2840
2973
  case 'short':
@@ -2861,7 +2994,7 @@ class PraxisList {
2861
2994
  trackBySection = (_, s) => s?.key ?? _;
2862
2995
  trackByItem = (i, it) => this.config?.selection?.compareBy ? (it?.[this.config.selection.compareBy] ?? i) : (it?.id ?? i);
2863
2996
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.4", ngImport: i0, type: PraxisList, deps: [], target: i0.ɵɵFactoryTarget.Component });
2864
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.1.4", type: PraxisList, isStandalone: true, selector: "praxis-list", inputs: { config: "config", form: "form" }, outputs: { itemClick: "itemClick", actionClick: "actionClick", selectionChange: "selectionChange" }, providers: [GenericCrudService, ListDataService], usesOnChanges: true, ngImport: i0, template: "<div\n class=\"praxis-list-root\"\n [ngClass]=\"skinClasses\"\n [attr.aria-label]=\"config.a11y?.ariaLabel || null\"\n [attr.aria-labelledby]=\"config.a11y?.ariaLabelledBy || null\"\n>\n @if (inlineCss) {\n <style [innerHTML]=\"inlineCss\"></style>\n }\n\n <!-- Skeleton while loading -->\n @if ((loading$ | async) && hasSkeleton()) {\n @if (isListVariant()) {\n <mat-list>\n @for (_ of skeletonItems(); track $index; let i = $index) {\n <mat-list-item>\n <div class=\"list-item-content\">\n <div class=\"skeleton skeleton-avatar\"></div>\n <div style=\"width:100%\">\n <div class=\"skeleton skeleton-line w-60\"></div>\n @if (layoutLines > 1) { <div class=\"skeleton skeleton-line w-40\"></div> }\n </div>\n <div class=\"skeleton skeleton-chip\"></div>\n </div>\n </mat-list-item>\n }\n </mat-list>\n } @else {\n <div class=\"cards-grid\">\n @for (_ of skeletonItems(); track $index; let i = $index) {\n <div class=\"item-card\">\n <div class=\"list-item-content\">\n <div class=\"skeleton skeleton-avatar\"></div>\n <div style=\"width:100%\">\n <div class=\"skeleton skeleton-line w-60\"></div>\n @if (layoutLines > 1) { <div class=\"skeleton skeleton-line w-40\"></div> }\n </div>\n <div class=\"skeleton skeleton-chip\"></div>\n </div>\n </div>\n }\n </div>\n }\n } @else {\n <ng-container *ngTemplateOutlet=\"notLoading\"></ng-container>\n }\n\n <ng-template #notLoading>\n <!-- Empty state -->\n @if (items$ | async; as all) {\n @if (all.length === 0) {\n <div class=\"section-header\">\n {{ (config.templating?.emptyState?.expr || 'Nenhum item dispon\u00EDvel') }}\n </div>\n }\n }\n\n <!-- List variant -->\n @if (isListVariant()) {\n <!-- Selection list -->\n @if (isSelectionEnabled()) {\n <mat-selection-list\n [multiple]=\"config.selection?.mode === 'multiple'\"\n [formControl]=\"boundControl\"\n (selectionChange)=\"onSelectionChange($event)\"\n >\n @for (section of sections$ | async; track trackBySection($index, section)) {\n @if (section.key) {\n <div class=\"section-header mat-subheader\">\n {{ sectionHeader(section.key) }}\n </div>\n }\n @for (item of section.items; track trackByItem($index, item); let i = $index) {\n <mat-list-option\n [value]=\"item\"\n (click)=\"onItemClick(item, i, section.key || undefined)\"\n >\n <div class=\"list-item-content\">\n @if (leading(item); as lead) {\n @switch (lead.type) {\n @case ('icon') {\n <mat-icon [ngClass]=\"lead.class\" [style.cssText]=\"lead.style\">{{ lead.value }}</mat-icon>\n }\n @case ('image') {\n <div class=\"lead-image\" [ngClass]=\"lead.class\" [style.cssText]=\"lead.style\">\n <img [src]=\"lead.value\" [alt]=\"config.templating?.leading?.imageAlt || ''\" />\n @if (lead.badge?.value) {\n <mat-chip class=\"lead-badge\" [color]=\"lead.badge?.color || undefined\" [ngClass]=\"(((lead.badge?.variant || 'filled') === 'outlined') ? 'chip-outlined' : '')\">{{ lead.badge?.value }}</mat-chip>\n }\n </div>\n }\n }\n }\n @if (meta(item); as m) {\n <div>\n <div class=\"primary\" [ngClass]=\"primary(item)?.class\" [style.cssText]=\"primary(item)?.style\">{{ primary(item)?.value }}</div>\n @if (layoutLines > 1) { <div class=\"secondary\" [ngClass]=\"secondary(item)?.class\" [style.cssText]=\"secondary(item)?.style\">{{ secondary(item)?.value }}</div> }\n @if ((config.templating?.metaPlacement === 'line' && m?.type === 'text') || (layoutLines > 2 && m?.type === 'text')) {\n <div class=\"tertiary\" [ngClass]=\"m.class\" [style.cssText]=\"m.style\">\n @if (config.templating?.metaPrefixIcon; as mpi) { <mat-icon [praxisIcon]=\"mpi\"></mat-icon> }\n {{ m.value }}\n </div>\n }\n @if (featuresVisible()) {\n @for (f of (config.templating?.features || []); track $index; let fi = $index) {\n <span class=\"feature\">\n @if (f.icon && featuresMode() !== 'labels-only') { <mat-icon [praxisIcon]=\"f.icon\"></mat-icon> }\n @if (featuresMode() !== 'icons-only') { <span [ngClass]=\"f.class\" [style.cssText]=\"f.style\">{{ featureLabel(item, f.expr) }}</span> }\n </span>\n }\n }\n </div>\n @if (!(((config.templating?.metaPlacement === 'line') || (layoutLines > 2)) && m?.type === 'text')) {\n <div class=\"meta\" [ngClass]=\"m.class\" [style.cssText]=\"m.style\">\n @switch (m.type) {\n @case ('chip') { <mat-chip [color]=\"m.color || undefined\" [ngClass]=\"((m.variant || 'filled') === 'outlined') ? 'chip-outlined' : ''\">{{ m.value }}</mat-chip> }\n @case ('rating') { @for (_ of [0,1,2,3,4]; track $index; let idx = $index) { <mat-icon [praxisIcon]=\"starIcon(idx, m.value)\"></mat-icon> } }\n @default { <span>@if (config.templating?.metaPrefixIcon; as mpi2) { <mat-icon>{{ mpi2 }}</mat-icon> }{{ m.value }}</span> }\n }\n </div>\n }\n @if (trailing(item); as tr) {\n <div class=\"trailing\" [ngClass]=\"tr.class\" [style.cssText]=\"tr.style\">\n @switch (tr.type) {\n @case ('chip') { <mat-chip [color]=\"tr.color || undefined\" [ngClass]=\"((tr.variant || 'filled') === 'outlined') ? 'chip-outlined' : ''\">{{ tr.value }}</mat-chip> }\n @default { <span>{{ tr.value }}</span> }\n }\n </div>\n }\n }\n @for (action of visibleActions(item); let aidx = $index; track action?.id ?? $index) {\n @if ((action.kind || 'icon') === 'icon') {\n <button mat-icon-button [color]=\"action.color || undefined\" (click)=\"onActionClick($event, action.id, item, i)\" [attr.aria-label]=\"action.label || action.id\">\n <mat-icon [praxisIcon]=\"action.icon\"></mat-icon>\n </button>\n } @else {\n @if (action.buttonVariant === 'stroked') { <button mat-stroked-button [color]=\"action.color || undefined\" (click)=\"onActionClick($event, action.id, item, i)\" [attr.aria-label]=\"action.label || action.id\">{{ action.label || action.id }}</button> }\n @if (action.buttonVariant === 'raised') { <button mat-raised-button [color]=\"action.color || undefined\" (click)=\"onActionClick($event, action.id, item, i)\" [attr.aria-label]=\"action.label || action.id\">{{ action.label || action.id }}</button> }\n @if (!action.buttonVariant || action.buttonVariant === 'flat') { <button mat-flat-button [color]=\"action.color || undefined\" (click)=\"onActionClick($event, action.id, item, i)\" [attr.aria-label]=\"action.label || action.id\">{{ action.label || action.id }}</button> }\n }\n }\n </div>\n </mat-list-option>\n }\n }\n </mat-selection-list>\n } @else {\n <ng-container *ngTemplateOutlet=\"readList\"></ng-container>\n }\n\n <!-- Read-only list -->\n <ng-template #readList>\n <mat-list>\n @for (section of sections$ | async; track trackBySection($index, section); let sidx = $index) {\n @if (section.key) {\n <div class=\"section-header mat-subheader\">\n {{ sectionHeader(section.key) }}\n </div>\n }\n @for (item of section.items; track trackByItem($index, item); let i = $index) {\n <mat-list-item (click)=\"onItemClick(item, i, section.key || undefined)\">\n <div class=\"list-item-content\">\n @if (leading(item); as lead) { <mat-icon [ngClass]=\"lead.class\" [style.cssText]=\"lead.style\">{{ lead.value }}</mat-icon> }\n @if (meta(item); as m) {\n <div>\n <div class=\"primary\" [ngClass]=\"primary(item)?.class\" [style.cssText]=\"primary(item)?.style\">{{ primary(item)?.value }}</div>\n @if (layoutLines > 1) { <div class=\"secondary\" [ngClass]=\"secondary(item)?.class\" [style.cssText]=\"secondary(item)?.style\">{{ secondary(item)?.value }}</div> }\n @if ((config.templating?.metaPlacement === 'line' && m?.type === 'text') || (layoutLines > 2 && m?.type === 'text')) { <div class=\"tertiary\" [ngClass]=\"m.class\" [style.cssText]=\"m.style\">{{ m.value }}</div> }\n </div>\n @if (!(((config.templating?.metaPlacement === 'line') || (layoutLines > 2)) && m?.type === 'text')) {\n <div class=\"meta\" [ngClass]=\"m.class\" [style.cssText]=\"m.style\">\n @switch (m.type) {\n @case ('chip') { <mat-chip>{{ m.value }}</mat-chip> }\n @case ('rating') { @for (_ of [0,1,2,3,4]; track $index; let idx = $index) { <mat-icon>{{ starIcon(idx, m.value) }}</mat-icon> } }\n @default { <span>{{ m.value }}</span> }\n }\n </div>\n }\n @if (trailing(item); as tr) {\n <div class=\"trailing\" [ngClass]=\"tr.class\" [style.cssText]=\"tr.style\">\n @switch (tr.type) {\n @case ('chip') { <mat-chip>{{ tr.value }}</mat-chip> }\n @default { <span>{{ tr.value }}</span> }\n }\n </div>\n }\n }\n @for (action of visibleActions(item); let aidx = $index; track action?.id ?? $index) {\n <button mat-icon-button [color]=\"action.color || undefined\" (click)=\"onActionClick($event, action.id, item, i)\" [attr.aria-label]=\"action.label || action.id\">\n <mat-icon>{{ action.icon }}</mat-icon>\n </button>\n }\n </div>\n </mat-list-item>\n }\n @if (config.layout?.dividers === 'between') { <mat-divider></mat-divider> }\n }\n </mat-list>\n </ng-template>\n } @else {\n <ng-container *ngTemplateOutlet=\"cardsVariant\"></ng-container>\n }\n\n <!-- Cards variant -->\n <ng-template #cardsVariant>\n <div class=\"cards-grid\">\n @for (it of (items$ | async) ?? []; track $index; let i = $index) {\n <div class=\"item-card\" (click)=\"onItemClick(it, i)\">\n <div class=\"list-item-content\">\n @if (leading(it); as lead) {\n @switch (lead.type) {\n @case ('icon') { <mat-icon [ngClass]=\"lead.class\" [style.cssText]=\"lead.style\">{{ lead.value }}</mat-icon> }\n @case ('image') {\n <div class=\"lead-image\" [ngClass]=\"lead.class\" [style.cssText]=\"lead.style\">\n <img [src]=\"lead.value\" [alt]=\"config.templating?.leading?.imageAlt || ''\" />\n @if (lead.badge?.value) { <mat-chip class=\"lead-badge\" [color]=\"lead.badge?.color || undefined\" [ngClass]=\"(((lead.badge?.variant || 'filled') === 'outlined') ? 'chip-outlined' : '')\">{{ lead.badge?.value }}</mat-chip> }\n </div>\n }\n }\n }\n @if (meta(it); as m) {\n <div>\n <div class=\"primary\" [ngClass]=\"primary(it)?.class\" [style.cssText]=\"primary(it)?.style\">{{ primary(it)?.value }}</div>\n @if (layoutLines > 1) { <div class=\"secondary\" [ngClass]=\"secondary(it)?.class\" [style.cssText]=\"secondary(it)?.style\">{{ secondary(it)?.value }}</div> }\n @if ((config.templating?.metaPlacement === 'line' && m?.type === 'text') || (layoutLines > 2 && m?.type === 'text')) { <div class=\"tertiary\" [ngClass]=\"m.class\" [style.cssText]=\"m.style\">{{ m.value }}</div> }\n @if (featuresVisible()) {\n @for (f of (config.templating?.features || []); track $index; let fi = $index) {\n <span class=\"feature\">\n @if (f.icon && featuresMode() !== 'labels-only') { <mat-icon>{{ f.icon }}</mat-icon> }\n @if (featuresMode() !== 'icons-only') { <span [ngClass]=\"f.class\" [style.cssText]=\"f.style\">{{ featureLabel(it, f.expr) }}</span> }\n </span>\n }\n }\n </div>\n @if (!(((config.templating?.metaPlacement === 'line') || (layoutLines > 2)) && m?.type === 'text')) {\n <div class=\"meta\" [ngClass]=\"m.class\" [style.cssText]=\"m.style\">\n @switch (m.type) {\n @case ('chip') { <mat-chip [color]=\"m.color || undefined\" [ngClass]=\"((m.variant || 'filled') === 'outlined') ? 'chip-outlined' : ''\">{{ m.value }}</mat-chip> }\n @case ('rating') { @for (_ of [0,1,2,3,4]; track $index; let idx = $index) { <mat-icon>{{ starIcon(idx, m.value) }}</mat-icon> } }\n @default { <span>{{ m.value }}</span> }\n }\n </div>\n }\n @if (trailing(it); as tr) {\n <div class=\"trailing\" [ngClass]=\"tr.class\" [style.cssText]=\"tr.style\">\n @switch (tr.type) {\n @case ('chip') { <mat-chip [color]=\"tr.color || undefined\" [ngClass]=\"((tr.variant || 'filled') === 'outlined') ? 'chip-outlined' : ''\">{{ tr.value }}</mat-chip> }\n @default { <span>{{ tr.value }}</span> }\n }\n </div>\n }\n }\n </div>\n <div class=\"card-actions\" (click)=\"$event.stopPropagation()\">\n @for (action of visibleActions(it); let aidx = $index; track action?.id ?? $index) {\n @if ((action.kind || 'icon') === 'icon') {\n <button mat-icon-button [color]=\"action.color || undefined\" (click)=\"onActionClick($event, action.id, it, i)\" [attr.aria-label]=\"action.label || action.id\">\n <mat-icon>{{ action.icon }}</mat-icon>\n </button>\n } @else {\n @if (action.buttonVariant === 'stroked') { <button mat-stroked-button [color]=\"action.color || undefined\" (click)=\"onActionClick($event, action.id, it, i)\" [attr.aria-label]=\"action.label || action.id\">{{ action.label || action.id }}</button> }\n @if (action.buttonVariant === 'raised') { <button mat-raised-button [color]=\"action.color || undefined\" (click)=\"onActionClick($event, action.id, it, i)\" [attr.aria-label]=\"action.label || action.id\">{{ action.label || action.id }}</button> }\n @if (!action.buttonVariant || action.buttonVariant === 'flat') { <button mat-flat-button [color]=\"action.color || undefined\" (click)=\"onActionClick($event, action.id, it, i)\" [attr.aria-label]=\"action.label || action.id\">{{ action.label || action.id }}</button> }\n }\n }\n </div>\n </div>\n }\n </div>\n </ng-template>\n \n <!-- Simple pagination controls for remote data -->\n @if (config.dataSource?.resourcePath) {\n <div class=\"paginator\">\n <button mat-stroked-button color=\"primary\" (click)=\"prevPage()\">Anterior</button>\n <button mat-stroked-button color=\"primary\" (click)=\"nextPage()\">Pr\u00F3ximo</button>\n @if (total$ | async; as total) { <span class=\"muted\">Total: {{ total }}</span> }\n </div>\n }\n </ng-template>\n</div>\n", styles: ["@charset \"UTF-8\";:host{display:block}.praxis-list-root{--p-list-radius: 1rem;--p-list-shadow: 0 6px 20px rgba(0, 0, 0, .08);--p-list-border: 1px solid rgba(0, 0, 0, .08);--p-list-blur: 8px;--p-list-grad-from: #8e72ff;--p-list-grad-to: #ffaa70;--p-list-grad-angle: 135deg}.skin-elevated .item-card{background:var(--mdc-elevated-card-container-color, var(--md-sys-color-surface));border-radius:var(--p-list-radius);box-shadow:var(--p-list-shadow);border:var(--p-list-border)}.skin-pill-soft .item-card{background:var(--mdc-elevated-card-container-color, var(--md-sys-color-surface));border-radius:calc(var(--p-list-radius) * 1.3);box-shadow:0 4px 16px #00000014;border:var(--p-list-border)}.skin-pill-soft .mat-mdc-list-item .list-item-content{background:var(--mdc-elevated-card-container-color, var(--md-sys-color-surface));border-radius:calc(var(--p-list-radius) * 1.3);box-shadow:0 4px 16px #00000014;border:var(--p-list-border);color:var(--p-list-foreground, #1f2937)}.skin-gradient-tile .item-card,.skin-gradient-tile .mat-mdc-list-item .list-item-content{background:linear-gradient(var(--p-list-grad-angle),var(--p-list-grad-from),var(--p-list-grad-to));border-radius:var(--p-list-radius);color:#fff}.skin-glass .item-card{background:#ffffff2e;border-radius:var(--p-list-radius);border:1px solid rgba(255,255,255,.3);backdrop-filter:blur(var(--p-list-blur));-webkit-backdrop-filter:blur(var(--p-list-blur))}.skin-glass .mat-mdc-list-item .list-item-content{background:#ffffff2e;border-radius:var(--p-list-radius);border:1px solid rgba(255,255,255,.3);backdrop-filter:blur(var(--p-list-blur));-webkit-backdrop-filter:blur(var(--p-list-blur));color:var(--p-list-foreground, #111)}.density-compact .mat-mdc-list-item,.density-compact .item-card{--_item-padding: 4px 8px}.density-comfortable .mat-mdc-list-item,.density-comfortable .item-card{--_item-padding: 8px 12px}.list-item-content{display:grid;grid-template-columns:auto 1fr auto;align-items:center;gap:12px;padding:var(--_item-padding, 12px 16px)}.lead-image{position:relative;width:96px;height:72px;border-radius:12px;overflow:hidden}.lead-image img{width:100%;height:100%;object-fit:cover;display:block}.lead-image .lead-badge{position:absolute;left:8px;bottom:8px}.model-media .lead-image{width:136px;height:96px;border-radius:16px}.model-media .list-item-content{gap:16px}.model-hotel .lead-image{width:160px;height:110px;border-radius:18px}.primary{font-weight:600;color:var(--sicoob-tertiary-default, #001E24)}.secondary{opacity:.8}.tertiary{opacity:.68}.features{display:flex;flex-wrap:wrap;gap:12px;margin-top:6px;color:#000000a8}.feature{display:inline-flex;align-items:center;gap:6px}.meta{opacity:.9}.trailing{opacity:.9;margin-left:8px}.section-header{font-size:.85rem;opacity:.7;padding:8px 12px}.cards-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(280px,1fr));gap:12px}.item-card{padding:12px;display:flex;flex-direction:column;min-height:160px}.item-card:hover{box-shadow:0 10px 24px var(--sicoob-shadow-medium, rgba(0, 0, 0, .12));transform:translateY(-1px);transition:box-shadow .15s ease,transform .15s ease}.card-actions{display:flex;align-items:center;justify-content:flex-end;gap:4px;padding:6px 8px 4px;border-top:1px solid var(--sicoob-stroke-medium, rgba(0, 0, 0, .08));margin-top:auto}.leading-icon.mat-icon{width:36px;height:36px;line-height:36px;font-size:20px;display:inline-flex;align-items:center;justify-content:center;border-radius:999px;background:color-mix(in srgb,var(--sicoob-info-lightest, #f0f9ff),transparent 30%);color:var(--sicoob-info-default, #0090e0)}.mat-mdc-chip{--mdc-chip-container-height: 22px;font-size:12px}.meta .mat-icon{font-size:18px;height:18px;width:18px}.primary,.secondary{display:-webkit-box;-webkit-box-orient:vertical;overflow:hidden;text-overflow:ellipsis}.primary,.secondary{-webkit-line-clamp:1}.features{overflow:hidden}@keyframes shimmer{0%{background-position:-468px 0}to{background-position:468px 0}}.skeleton{animation-duration:1.2s;animation-fill-mode:forwards;animation-iteration-count:infinite;animation-name:shimmer;animation-timing-function:linear;background:#f6f7f8;background:linear-gradient(to right,#eee 8%,#ddd 18%,#eee 33%);background-size:800px 104px;position:relative}.skeleton-avatar{width:32px;height:32px;border-radius:50%}.skeleton-line{height:10px;margin:6px 0;border-radius:6px}.skeleton-chip{width:48px;height:18px;border-radius:999px}.chip-outlined.mat-mdc-chip{background:transparent!important;border:1px solid currentColor}.w-60{width:60%}.w-40{width:40%}.paginator{display:flex;align-items:center;gap:8px;padding:8px 4px}.muted{opacity:.7}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "ngmodule", type: MatListModule }, { kind: "component", type: i3.MatList, selector: "mat-list", exportAs: ["matList"] }, { kind: "component", type: i3.MatSelectionList, selector: "mat-selection-list", inputs: ["color", "compareWith", "multiple", "hideSingleSelectionIndicator", "disabled"], outputs: ["selectionChange"], exportAs: ["matSelectionList"] }, { kind: "component", type: i3.MatListItem, selector: "mat-list-item, a[mat-list-item], button[mat-list-item]", inputs: ["activated"], exportAs: ["matListItem"] }, { kind: "component", type: i3.MatListOption, selector: "mat-list-option", inputs: ["togglePosition", "checkboxPosition", "color", "value", "selected"], outputs: ["selectedChange"], exportAs: ["matListOption"] }, { kind: "component", type: i3.MatDivider, selector: "mat-divider", inputs: ["vertical", "inset"] }, { kind: "ngmodule", type: MatDividerModule }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i4.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "directive", type: PraxisIconDirective, selector: "mat-icon[praxisIcon]", inputs: ["praxisIcon"] }, { kind: "ngmodule", type: MatChipsModule }, { kind: "component", type: i14.MatChip, selector: "mat-basic-chip, [mat-basic-chip], mat-chip, [mat-chip]", inputs: ["role", "id", "aria-label", "aria-description", "value", "color", "removable", "highlighted", "disableRipple", "disabled"], outputs: ["removed", "destroyed"], exportAs: ["matChip"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i7.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: i7.MatIconButton, selector: "button[mat-icon-button], a[mat-icon-button], button[matIconButton], a[matIconButton]", exportAs: ["matButton", "matAnchor"] }, { kind: "pipe", type: i1.AsyncPipe, name: "async" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
2997
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.1.4", type: PraxisList, isStandalone: true, selector: "praxis-list", inputs: { config: "config", form: "form" }, outputs: { itemClick: "itemClick", actionClick: "actionClick", selectionChange: "selectionChange" }, providers: [GenericCrudService, ListDataService], usesOnChanges: true, ngImport: i0, template: "<div\n class=\"praxis-list-root\"\n [ngClass]=\"skinClasses\"\n [attr.aria-label]=\"config.a11y?.ariaLabel || null\"\n [attr.aria-labelledby]=\"config.a11y?.ariaLabelledBy || null\"\n>\n @if (inlineCss) {\n <style [innerHTML]=\"inlineCss\"></style>\n }\n\n <!-- Skeleton while loading -->\n @if ((loading$ | async) && hasSkeleton()) {\n @if (isListVariant()) {\n <mat-list>\n @for (_ of skeletonItems(); track $index; let i = $index) {\n <mat-list-item>\n <div class=\"list-item-content\">\n <div class=\"skeleton skeleton-avatar\"></div>\n <div style=\"width:100%\">\n <div class=\"skeleton skeleton-line w-60\"></div>\n @if (layoutLines > 1) { <div class=\"skeleton skeleton-line w-40\"></div> }\n </div>\n <div class=\"skeleton skeleton-chip\"></div>\n </div>\n </mat-list-item>\n }\n </mat-list>\n } @else {\n <div class=\"cards-grid\">\n @for (_ of skeletonItems(); track $index; let i = $index) {\n <div class=\"item-card\">\n <div class=\"list-item-content\">\n <div class=\"skeleton skeleton-avatar\"></div>\n <div style=\"width:100%\">\n <div class=\"skeleton skeleton-line w-60\"></div>\n @if (layoutLines > 1) { <div class=\"skeleton skeleton-line w-40\"></div> }\n </div>\n <div class=\"skeleton skeleton-chip\"></div>\n </div>\n </div>\n }\n </div>\n }\n } @else {\n <ng-container *ngTemplateOutlet=\"notLoading\"></ng-container>\n }\n\n <ng-template #notLoading>\n <!-- Empty state -->\n @if (items$ | async; as all) {\n @if (all.length === 0) {\n <div class=\"section-header\">\n {{ (config.templating?.emptyState?.expr || 'Nenhum item dispon\u00EDvel') }}\n </div>\n }\n }\n\n <!-- List variant -->\n @if (isListVariant()) {\n <!-- Selection list -->\n @if (isSelectionEnabled()) {\n <mat-selection-list\n [multiple]=\"config.selection?.mode === 'multiple'\"\n [formControl]=\"boundControl\"\n (selectionChange)=\"onSelectionChange($event)\"\n >\n @for (section of sections$ | async; track trackBySection($index, section)) {\n @if (section.key) {\n <div class=\"section-header mat-subheader\">\n {{ sectionHeader(section.key) }}\n </div>\n }\n @for (item of section.items; track trackByItem($index, item); let i = $index) {\n <mat-list-option\n [value]=\"item\"\n (click)=\"onItemClick(item, i, section.key || undefined)\"\n >\n <div class=\"list-item-content\">\n @if (leading(item); as lead) {\n @switch (lead.type) {\n @case ('icon') {\n <mat-icon [ngClass]=\"lead.class\" [style.cssText]=\"lead.style\">{{ lead.value }}</mat-icon>\n }\n @case ('image') {\n <div class=\"lead-image\" [ngClass]=\"lead.class\" [style.cssText]=\"lead.style\">\n <img [src]=\"lead.value\" [alt]=\"config.templating?.leading?.imageAlt || ''\" />\n @if (lead.badge?.value) {\n <mat-chip class=\"lead-badge\" [color]=\"lead.badge?.color || undefined\" [ngClass]=\"(((lead.badge?.variant || 'filled') === 'outlined') ? 'chip-outlined' : '')\">{{ lead.badge?.value }}</mat-chip>\n }\n </div>\n }\n }\n }\n @if (meta(item); as m) {\n <div>\n <div class=\"primary\" [ngClass]=\"primary(item)?.class\" [style.cssText]=\"primary(item)?.style\">{{ primary(item)?.value }}</div>\n @if (layoutLines > 1) { <div class=\"secondary\" [ngClass]=\"secondary(item)?.class\" [style.cssText]=\"secondary(item)?.style\">{{ secondary(item)?.value }}</div> }\n @if ((config.templating?.metaPlacement === 'line' && (m?.type === 'text' || m?.type === 'date')) || (layoutLines > 2 && (m?.type === 'text' || m?.type === 'date'))) {\n <div class=\"tertiary\" [ngClass]=\"m.class\" [style.cssText]=\"m.style\">\n @if (config.templating?.metaPrefixIcon; as mpi) { <mat-icon [praxisIcon]=\"mpi\"></mat-icon> }\n {{ m.value }}\n </div>\n }\n @if (featuresVisible()) {\n @for (f of (config.templating?.features || []); track $index; let fi = $index) {\n <span class=\"feature\">\n @if (f.icon && featuresMode() !== 'labels-only') { <mat-icon [praxisIcon]=\"f.icon\"></mat-icon> }\n @if (featuresMode() !== 'icons-only') { <span [ngClass]=\"f.class\" [style.cssText]=\"f.style\">{{ featureLabel(item, f.expr) }}</span> }\n </span>\n }\n }\n </div>\n @if (!(((config.templating?.metaPlacement === 'line') || (layoutLines > 2)) && (m?.type === 'text' || m?.type === 'date'))) {\n <div class=\"meta\" [ngClass]=\"m.class\" [style.cssText]=\"m.style\">\n @switch (m.type) {\n @case ('chip') { <mat-chip [color]=\"m.color || undefined\" [ngClass]=\"((m.variant || 'filled') === 'outlined') ? 'chip-outlined' : ''\">{{ m.value }}</mat-chip> }\n @case ('rating') { @for (_ of [0,1,2,3,4]; track $index; let idx = $index) { <mat-icon [praxisIcon]=\"starIcon(idx, m.value)\"></mat-icon> } }\n @default { <span>@if (config.templating?.metaPrefixIcon; as mpi2) { <mat-icon>{{ mpi2 }}</mat-icon> }{{ m.value }}</span> }\n }\n </div>\n }\n @if (trailing(item); as tr) {\n <div class=\"trailing\" [ngClass]=\"tr.class\" [style.cssText]=\"tr.style\">\n @switch (tr.type) {\n @case ('chip') { <mat-chip [color]=\"tr.color || undefined\" [ngClass]=\"((tr.variant || 'filled') === 'outlined') ? 'chip-outlined' : ''\">{{ tr.value }}</mat-chip> }\n @case ('icon') { <mat-icon [praxisIcon]=\"tr.value\" [color]=\"tr.color || undefined\"></mat-icon> }\n @default { <span>{{ tr.value }}</span> }\n }\n </div>\n }\n }\n @for (action of visibleActions(item); let aidx = $index; track action?.id ?? $index) {\n @if ((action.kind || 'icon') === 'icon') {\n <button mat-icon-button [color]=\"action.color || undefined\" (click)=\"onActionClick($event, action.id, item, i)\" [attr.aria-label]=\"action.label || action.id\">\n <mat-icon [praxisIcon]=\"action.icon\"></mat-icon>\n </button>\n } @else {\n @if (action.buttonVariant === 'stroked') { <button mat-stroked-button [color]=\"action.color || undefined\" (click)=\"onActionClick($event, action.id, item, i)\" [attr.aria-label]=\"action.label || action.id\">{{ action.label || action.id }}</button> }\n @if (action.buttonVariant === 'raised') { <button mat-raised-button [color]=\"action.color || undefined\" (click)=\"onActionClick($event, action.id, item, i)\" [attr.aria-label]=\"action.label || action.id\">{{ action.label || action.id }}</button> }\n @if (!action.buttonVariant || action.buttonVariant === 'flat') { <button mat-flat-button [color]=\"action.color || undefined\" (click)=\"onActionClick($event, action.id, item, i)\" [attr.aria-label]=\"action.label || action.id\">{{ action.label || action.id }}</button> }\n }\n }\n </div>\n </mat-list-option>\n }\n }\n </mat-selection-list>\n } @else {\n <ng-container *ngTemplateOutlet=\"readList\"></ng-container>\n }\n\n <!-- Read-only list -->\n <ng-template #readList>\n <mat-list>\n @for (section of sections$ | async; track trackBySection($index, section); let sidx = $index) {\n @if (section.key) {\n <div class=\"section-header mat-subheader\">\n {{ sectionHeader(section.key) }}\n </div>\n }\n @for (item of section.items; track trackByItem($index, item); let i = $index) {\n <mat-list-item (click)=\"onItemClick(item, i, section.key || undefined)\">\n <div class=\"list-item-content\">\n @if (leading(item); as lead) { <mat-icon [ngClass]=\"lead.class\" [style.cssText]=\"lead.style\">{{ lead.value }}</mat-icon> }\n @if (meta(item); as m) {\n <div>\n <div class=\"primary\" [ngClass]=\"primary(item)?.class\" [style.cssText]=\"primary(item)?.style\">{{ primary(item)?.value }}</div>\n @if (layoutLines > 1) { <div class=\"secondary\" [ngClass]=\"secondary(item)?.class\" [style.cssText]=\"secondary(item)?.style\">{{ secondary(item)?.value }}</div> }\n @if ((config.templating?.metaPlacement === 'line' && (m?.type === 'text' || m?.type === 'date')) || (layoutLines > 2 && (m?.type === 'text' || m?.type === 'date'))) { <div class=\"tertiary\" [ngClass]=\"m.class\" [style.cssText]=\"m.style\">{{ m.value }}</div> }\n </div>\n @if (!(((config.templating?.metaPlacement === 'line') || (layoutLines > 2)) && (m?.type === 'text' || m?.type === 'date'))) {\n <div class=\"meta\" [ngClass]=\"m.class\" [style.cssText]=\"m.style\">\n @switch (m.type) {\n @case ('chip') { <mat-chip>{{ m.value }}</mat-chip> }\n @case ('rating') { @for (_ of [0,1,2,3,4]; track $index; let idx = $index) { <mat-icon>{{ starIcon(idx, m.value) }}</mat-icon> } }\n @default { <span>{{ m.value }}</span> }\n }\n </div>\n }\n @if (trailing(item); as tr) {\n <div class=\"trailing\" [ngClass]=\"tr.class\" [style.cssText]=\"tr.style\">\n @switch (tr.type) {\n @case ('chip') { <mat-chip>{{ tr.value }}</mat-chip> }\n @case ('icon') { <mat-icon [praxisIcon]=\"tr.value\" [color]=\"tr.color || undefined\"></mat-icon> }\n @default { <span>{{ tr.value }}</span> }\n }\n </div>\n }\n }\n @for (action of visibleActions(item); let aidx = $index; track action?.id ?? $index) {\n <button mat-icon-button [color]=\"action.color || undefined\" (click)=\"onActionClick($event, action.id, item, i)\" [attr.aria-label]=\"action.label || action.id\">\n <mat-icon>{{ action.icon }}</mat-icon>\n </button>\n }\n </div>\n </mat-list-item>\n }\n @if (config.layout?.dividers === 'between') { <mat-divider></mat-divider> }\n }\n </mat-list>\n </ng-template>\n } @else {\n <ng-container *ngTemplateOutlet=\"cardsVariant\"></ng-container>\n }\n\n <!-- Cards variant -->\n <ng-template #cardsVariant>\n <div class=\"cards-grid\">\n @for (it of (items$ | async) ?? []; track $index; let i = $index) {\n <div class=\"item-card\" (click)=\"onItemClick(it, i)\">\n <div class=\"list-item-content\">\n @if (leading(it); as lead) {\n @switch (lead.type) {\n @case ('icon') { <mat-icon [ngClass]=\"lead.class\" [style.cssText]=\"lead.style\">{{ lead.value }}</mat-icon> }\n @case ('image') {\n <div class=\"lead-image\" [ngClass]=\"lead.class\" [style.cssText]=\"lead.style\">\n <img [src]=\"lead.value\" [alt]=\"config.templating?.leading?.imageAlt || ''\" />\n @if (lead.badge?.value) { <mat-chip class=\"lead-badge\" [color]=\"lead.badge?.color || undefined\" [ngClass]=\"(((lead.badge?.variant || 'filled') === 'outlined') ? 'chip-outlined' : '')\">{{ lead.badge?.value }}</mat-chip> }\n </div>\n }\n }\n }\n @if (meta(it); as m) {\n <div>\n <div class=\"primary\" [ngClass]=\"primary(it)?.class\" [style.cssText]=\"primary(it)?.style\">{{ primary(it)?.value }}</div>\n @if (layoutLines > 1) { <div class=\"secondary\" [ngClass]=\"secondary(it)?.class\" [style.cssText]=\"secondary(it)?.style\">{{ secondary(it)?.value }}</div> }\n @if ((config.templating?.metaPlacement === 'line' && (m?.type === 'text' || m?.type === 'date')) || (layoutLines > 2 && (m?.type === 'text' || m?.type === 'date'))) { <div class=\"tertiary\" [ngClass]=\"m.class\" [style.cssText]=\"m.style\">{{ m.value }}</div> }\n @if (featuresVisible()) {\n @for (f of (config.templating?.features || []); track $index; let fi = $index) {\n <span class=\"feature\">\n @if (f.icon && featuresMode() !== 'labels-only') { <mat-icon>{{ f.icon }}</mat-icon> }\n @if (featuresMode() !== 'icons-only') { <span [ngClass]=\"f.class\" [style.cssText]=\"f.style\">{{ featureLabel(it, f.expr) }}</span> }\n </span>\n }\n }\n </div>\n @if (!(((config.templating?.metaPlacement === 'line') || (layoutLines > 2)) && (m?.type === 'text' || m?.type === 'date'))) {\n <div class=\"meta\" [ngClass]=\"m.class\" [style.cssText]=\"m.style\">\n @switch (m.type) {\n @case ('chip') { <mat-chip [color]=\"m.color || undefined\" [ngClass]=\"((m.variant || 'filled') === 'outlined') ? 'chip-outlined' : ''\">{{ m.value }}</mat-chip> }\n @case ('rating') { @for (_ of [0,1,2,3,4]; track $index; let idx = $index) { <mat-icon>{{ starIcon(idx, m.value) }}</mat-icon> } }\n @default { <span>{{ m.value }}</span> }\n }\n </div>\n }\n @if (trailing(it); as tr) {\n @if ((config.templating?.statusPosition || 'inline') === 'top-right' && (tr?.type === 'chip' || tr?.type === 'icon')) {\n <div class=\"status-overlay\">\n @if (tr?.type === 'chip') { <mat-chip [color]=\"tr.color || undefined\" [ngClass]=\"((tr.variant || 'filled') === 'outlined') ? 'chip-outlined' : ''\">{{ tr.value }}</mat-chip> }\n @if (tr?.type === 'icon') { <mat-icon [praxisIcon]=\"tr.value\" [color]=\"tr.color || undefined\"></mat-icon> }\n </div>\n } @else {\n <div class=\"trailing\" [ngClass]=\"tr.class\" [style.cssText]=\"tr.style\">\n @switch (tr.type) {\n @case ('chip') { <mat-chip [color]=\"tr.color || undefined\" [ngClass]=\"((tr.variant || 'filled') === 'outlined') ? 'chip-outlined' : ''\">{{ tr.value }}</mat-chip> }\n @case ('icon') { <mat-icon [praxisIcon]=\"tr.value\" [color]=\"tr.color || undefined\"></mat-icon> }\n @default { <span>{{ tr.value }}</span> }\n }\n </div>\n }\n }\n }\n </div>\n <div class=\"card-actions\" (click)=\"$event.stopPropagation()\">\n @for (action of visibleActions(it); let aidx = $index; track action?.id ?? $index) {\n @if ((action.kind || 'icon') === 'icon') {\n <button mat-icon-button [color]=\"action.color || undefined\" (click)=\"onActionClick($event, action.id, it, i)\" [attr.aria-label]=\"action.label || action.id\">\n <mat-icon>{{ action.icon }}</mat-icon>\n </button>\n } @else {\n @if (action.buttonVariant === 'stroked') { <button mat-stroked-button [color]=\"action.color || undefined\" (click)=\"onActionClick($event, action.id, it, i)\" [attr.aria-label]=\"action.label || action.id\">{{ action.label || action.id }}</button> }\n @if (action.buttonVariant === 'raised') { <button mat-raised-button [color]=\"action.color || undefined\" (click)=\"onActionClick($event, action.id, it, i)\" [attr.aria-label]=\"action.label || action.id\">{{ action.label || action.id }}</button> }\n @if (!action.buttonVariant || action.buttonVariant === 'flat') { <button mat-flat-button [color]=\"action.color || undefined\" (click)=\"onActionClick($event, action.id, it, i)\" [attr.aria-label]=\"action.label || action.id\">{{ action.label || action.id }}</button> }\n }\n }\n </div>\n </div>\n }\n </div>\n </ng-template>\n \n <!-- Simple pagination controls for remote data -->\n @if (config.dataSource?.resourcePath) {\n <div class=\"paginator\">\n <button mat-stroked-button color=\"primary\" (click)=\"prevPage()\">Anterior</button>\n <button mat-stroked-button color=\"primary\" (click)=\"nextPage()\">Pr\u00F3ximo</button>\n <mat-form-field style=\"width: 120px; margin-left: 8px;\" appearance=\"outline\">\n <mat-label>Tam. p\u00E1gina</mat-label>\n <mat-select (selectionChange)=\"setPageSize($event.value)\" [value]=\"config.layout?.pageSize || 10\">\n <mat-option [value]=\"6\">6</mat-option>\n <mat-option [value]=\"8\">8</mat-option>\n <mat-option [value]=\"12\">12</mat-option>\n <mat-option [value]=\"24\">24</mat-option>\n </mat-select>\n </mat-form-field>\n @if (total$ | async; as total) { <span class=\"muted\">Total: {{ total }}</span> }\n </div>\n }\n </ng-template>\n</div>\n", styles: ["@charset \"UTF-8\";:host{display:block}.praxis-list-root{--p-list-radius: 1rem;--p-list-shadow: 0 6px 20px rgba(0, 0, 0, .08);--p-list-border: 1px solid rgba(0, 0, 0, .08);--p-list-blur: 8px;--p-list-grad-from: #8e72ff;--p-list-grad-to: #ffaa70;--p-list-grad-angle: 135deg}.skin-elevated .item-card{background:var(--mdc-elevated-card-container-color, var(--md-sys-color-surface));border-radius:var(--p-list-radius);box-shadow:var(--p-list-shadow);border:var(--p-list-border)}.skin-pill-soft .item-card{background:var(--mdc-elevated-card-container-color, var(--md-sys-color-surface));border-radius:calc(var(--p-list-radius) * 1.3);box-shadow:0 4px 16px #00000014;border:var(--p-list-border)}.skin-pill-soft .mat-mdc-list-item .list-item-content{background:var(--mdc-elevated-card-container-color, var(--md-sys-color-surface));border-radius:calc(var(--p-list-radius) * 1.3);box-shadow:0 4px 16px #00000014;border:var(--p-list-border);color:var(--p-list-foreground, #1f2937)}.skin-gradient-tile .item-card,.skin-gradient-tile .mat-mdc-list-item .list-item-content{background:linear-gradient(var(--p-list-grad-angle),var(--p-list-grad-from),var(--p-list-grad-to));border-radius:var(--p-list-radius);color:#fff}.skin-glass .item-card{background:#ffffff2e;border-radius:var(--p-list-radius);border:1px solid rgba(255,255,255,.3);backdrop-filter:blur(var(--p-list-blur));-webkit-backdrop-filter:blur(var(--p-list-blur))}.skin-glass .mat-mdc-list-item .list-item-content{background:#ffffff2e;border-radius:var(--p-list-radius);border:1px solid rgba(255,255,255,.3);backdrop-filter:blur(var(--p-list-blur));-webkit-backdrop-filter:blur(var(--p-list-blur));color:var(--p-list-foreground, #111)}.density-compact .mat-mdc-list-item,.density-compact .item-card{--_item-padding: 4px 8px}.density-comfortable .mat-mdc-list-item,.density-comfortable .item-card{--_item-padding: 8px 12px}.list-item-content{display:grid;grid-template-columns:auto 1fr auto;align-items:center;gap:12px;padding:var(--_item-padding, 12px 16px)}.lead-image{position:relative;width:96px;height:72px;border-radius:12px;overflow:hidden}.lead-image img{width:100%;height:100%;object-fit:cover;display:block}.lead-image .lead-badge{position:absolute;left:8px;bottom:8px}.model-media .lead-image{width:136px;height:96px;border-radius:16px}.model-media .list-item-content{gap:16px}.model-hotel .lead-image{width:160px;height:110px;border-radius:18px}.primary{font-weight:600;color:var(--sicoob-tertiary-default, #001E24)}.secondary{opacity:.8}.tertiary{opacity:.68}.features{display:flex;flex-wrap:wrap;gap:12px;margin-top:6px;color:inherit}.feature{display:inline-flex;align-items:center;gap:6px}.meta{opacity:.9}.trailing{opacity:.9;margin-left:8px}.section-header{font-size:.85rem;opacity:.7;padding:8px 12px}.cards-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(280px,1fr));gap:12px}.item-card{padding:12px;display:flex;flex-direction:column;min-height:160px;position:relative;cursor:pointer}.item-card:hover{box-shadow:0 10px 24px var(--sicoob-shadow-medium, rgba(0, 0, 0, .12));transform:translateY(-1px);transition:box-shadow .15s ease,transform .15s ease}.card-actions{display:flex;align-items:center;justify-content:flex-end;gap:4px;padding:6px 8px 4px;border-top:1px solid var(--sicoob-stroke-medium, rgba(0, 0, 0, .08));margin-top:auto}.status-overlay{position:absolute;top:10px;right:10px;pointer-events:none}.status-overlay .mat-mdc-chip{pointer-events:auto}.leading-icon.mat-icon{width:36px;height:36px;line-height:36px;font-size:20px;display:inline-flex;align-items:center;justify-content:center;border-radius:999px;background:color-mix(in srgb,var(--sicoob-info-lightest, #f0f9ff),transparent 30%);color:var(--sicoob-info-default, #0090e0)}.mat-mdc-chip{--mdc-chip-container-height: 22px;font-size:12px}.meta .mat-icon{font-size:18px;height:18px;width:18px}.primary,.secondary{display:-webkit-box;-webkit-box-orient:vertical;overflow:hidden;text-overflow:ellipsis}.primary,.secondary{-webkit-line-clamp:1}.features{overflow:hidden}@keyframes shimmer{0%{background-position:-468px 0}to{background-position:468px 0}}.skeleton{animation-duration:1.2s;animation-fill-mode:forwards;animation-iteration-count:infinite;animation-name:shimmer;animation-timing-function:linear;background:#f6f7f8;background:linear-gradient(to right,#eee 8%,#ddd 18%,#eee 33%);background-size:800px 104px;position:relative}.skeleton-avatar{width:32px;height:32px;border-radius:50%}.skeleton-line{height:10px;margin:6px 0;border-radius:6px}.skeleton-chip{width:48px;height:18px;border-radius:999px}.chip-outlined.mat-mdc-chip{background:transparent!important;border:1px solid currentColor}.w-60{width:60%}.w-40{width:40%}.paginator{display:flex;align-items:center;gap:8px;padding:8px 4px}.muted{opacity:.7}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "ngmodule", type: MatListModule }, { kind: "component", type: i3.MatList, selector: "mat-list", exportAs: ["matList"] }, { kind: "component", type: i3.MatSelectionList, selector: "mat-selection-list", inputs: ["color", "compareWith", "multiple", "hideSingleSelectionIndicator", "disabled"], outputs: ["selectionChange"], exportAs: ["matSelectionList"] }, { kind: "component", type: i3.MatListItem, selector: "mat-list-item, a[mat-list-item], button[mat-list-item]", inputs: ["activated"], exportAs: ["matListItem"] }, { kind: "component", type: i3.MatListOption, selector: "mat-list-option", inputs: ["togglePosition", "checkboxPosition", "color", "value", "selected"], outputs: ["selectedChange"], exportAs: ["matListOption"] }, { kind: "component", type: i3.MatDivider, selector: "mat-divider", inputs: ["vertical", "inset"] }, { kind: "ngmodule", type: MatDividerModule }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i4.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "directive", type: PraxisIconDirective, selector: "mat-icon[praxisIcon]", inputs: ["praxisIcon"] }, { kind: "ngmodule", type: MatChipsModule }, { kind: "component", type: i14.MatChip, selector: "mat-basic-chip, [mat-basic-chip], mat-chip, [mat-chip]", inputs: ["role", "id", "aria-label", "aria-description", "value", "color", "removable", "highlighted", "disableRipple", "disabled"], outputs: ["removed", "destroyed"], exportAs: ["matChip"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i7.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: i7.MatIconButton, selector: "button[mat-icon-button], a[mat-icon-button], button[matIconButton], a[matIconButton]", exportAs: ["matButton", "matAnchor"] }, { kind: "ngmodule", type: MatFormFieldModule }, { kind: "component", type: i4$1.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i4$1.MatLabel, selector: "mat-label" }, { kind: "ngmodule", type: MatSelectModule }, { kind: "component", type: i6.MatSelect, selector: "mat-select", inputs: ["aria-describedby", "panelClass", "disabled", "disableRipple", "tabIndex", "hideSingleSelectionIndicator", "placeholder", "required", "multiple", "disableOptionCentering", "compareWith", "value", "aria-label", "aria-labelledby", "errorStateMatcher", "typeaheadDebounceInterval", "sortComparator", "id", "panelWidth", "canSelectNullableOptions"], outputs: ["openedChange", "opened", "closed", "selectionChange", "valueChange"], exportAs: ["matSelect"] }, { kind: "component", type: i6.MatOption, selector: "mat-option", inputs: ["value", "id", "disabled"], outputs: ["onSelectionChange"], exportAs: ["matOption"] }, { kind: "pipe", type: i1.AsyncPipe, name: "async" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
2865
2998
  }
2866
2999
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.4", ngImport: i0, type: PraxisList, decorators: [{
2867
3000
  type: Component,
@@ -2874,7 +3007,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.4", ngImpor
2874
3007
  PraxisIconDirective,
2875
3008
  MatChipsModule,
2876
3009
  MatButtonModule,
2877
- ], changeDetection: ChangeDetectionStrategy.OnPush, providers: [GenericCrudService, ListDataService], template: "<div\n class=\"praxis-list-root\"\n [ngClass]=\"skinClasses\"\n [attr.aria-label]=\"config.a11y?.ariaLabel || null\"\n [attr.aria-labelledby]=\"config.a11y?.ariaLabelledBy || null\"\n>\n @if (inlineCss) {\n <style [innerHTML]=\"inlineCss\"></style>\n }\n\n <!-- Skeleton while loading -->\n @if ((loading$ | async) && hasSkeleton()) {\n @if (isListVariant()) {\n <mat-list>\n @for (_ of skeletonItems(); track $index; let i = $index) {\n <mat-list-item>\n <div class=\"list-item-content\">\n <div class=\"skeleton skeleton-avatar\"></div>\n <div style=\"width:100%\">\n <div class=\"skeleton skeleton-line w-60\"></div>\n @if (layoutLines > 1) { <div class=\"skeleton skeleton-line w-40\"></div> }\n </div>\n <div class=\"skeleton skeleton-chip\"></div>\n </div>\n </mat-list-item>\n }\n </mat-list>\n } @else {\n <div class=\"cards-grid\">\n @for (_ of skeletonItems(); track $index; let i = $index) {\n <div class=\"item-card\">\n <div class=\"list-item-content\">\n <div class=\"skeleton skeleton-avatar\"></div>\n <div style=\"width:100%\">\n <div class=\"skeleton skeleton-line w-60\"></div>\n @if (layoutLines > 1) { <div class=\"skeleton skeleton-line w-40\"></div> }\n </div>\n <div class=\"skeleton skeleton-chip\"></div>\n </div>\n </div>\n }\n </div>\n }\n } @else {\n <ng-container *ngTemplateOutlet=\"notLoading\"></ng-container>\n }\n\n <ng-template #notLoading>\n <!-- Empty state -->\n @if (items$ | async; as all) {\n @if (all.length === 0) {\n <div class=\"section-header\">\n {{ (config.templating?.emptyState?.expr || 'Nenhum item dispon\u00EDvel') }}\n </div>\n }\n }\n\n <!-- List variant -->\n @if (isListVariant()) {\n <!-- Selection list -->\n @if (isSelectionEnabled()) {\n <mat-selection-list\n [multiple]=\"config.selection?.mode === 'multiple'\"\n [formControl]=\"boundControl\"\n (selectionChange)=\"onSelectionChange($event)\"\n >\n @for (section of sections$ | async; track trackBySection($index, section)) {\n @if (section.key) {\n <div class=\"section-header mat-subheader\">\n {{ sectionHeader(section.key) }}\n </div>\n }\n @for (item of section.items; track trackByItem($index, item); let i = $index) {\n <mat-list-option\n [value]=\"item\"\n (click)=\"onItemClick(item, i, section.key || undefined)\"\n >\n <div class=\"list-item-content\">\n @if (leading(item); as lead) {\n @switch (lead.type) {\n @case ('icon') {\n <mat-icon [ngClass]=\"lead.class\" [style.cssText]=\"lead.style\">{{ lead.value }}</mat-icon>\n }\n @case ('image') {\n <div class=\"lead-image\" [ngClass]=\"lead.class\" [style.cssText]=\"lead.style\">\n <img [src]=\"lead.value\" [alt]=\"config.templating?.leading?.imageAlt || ''\" />\n @if (lead.badge?.value) {\n <mat-chip class=\"lead-badge\" [color]=\"lead.badge?.color || undefined\" [ngClass]=\"(((lead.badge?.variant || 'filled') === 'outlined') ? 'chip-outlined' : '')\">{{ lead.badge?.value }}</mat-chip>\n }\n </div>\n }\n }\n }\n @if (meta(item); as m) {\n <div>\n <div class=\"primary\" [ngClass]=\"primary(item)?.class\" [style.cssText]=\"primary(item)?.style\">{{ primary(item)?.value }}</div>\n @if (layoutLines > 1) { <div class=\"secondary\" [ngClass]=\"secondary(item)?.class\" [style.cssText]=\"secondary(item)?.style\">{{ secondary(item)?.value }}</div> }\n @if ((config.templating?.metaPlacement === 'line' && m?.type === 'text') || (layoutLines > 2 && m?.type === 'text')) {\n <div class=\"tertiary\" [ngClass]=\"m.class\" [style.cssText]=\"m.style\">\n @if (config.templating?.metaPrefixIcon; as mpi) { <mat-icon [praxisIcon]=\"mpi\"></mat-icon> }\n {{ m.value }}\n </div>\n }\n @if (featuresVisible()) {\n @for (f of (config.templating?.features || []); track $index; let fi = $index) {\n <span class=\"feature\">\n @if (f.icon && featuresMode() !== 'labels-only') { <mat-icon [praxisIcon]=\"f.icon\"></mat-icon> }\n @if (featuresMode() !== 'icons-only') { <span [ngClass]=\"f.class\" [style.cssText]=\"f.style\">{{ featureLabel(item, f.expr) }}</span> }\n </span>\n }\n }\n </div>\n @if (!(((config.templating?.metaPlacement === 'line') || (layoutLines > 2)) && m?.type === 'text')) {\n <div class=\"meta\" [ngClass]=\"m.class\" [style.cssText]=\"m.style\">\n @switch (m.type) {\n @case ('chip') { <mat-chip [color]=\"m.color || undefined\" [ngClass]=\"((m.variant || 'filled') === 'outlined') ? 'chip-outlined' : ''\">{{ m.value }}</mat-chip> }\n @case ('rating') { @for (_ of [0,1,2,3,4]; track $index; let idx = $index) { <mat-icon [praxisIcon]=\"starIcon(idx, m.value)\"></mat-icon> } }\n @default { <span>@if (config.templating?.metaPrefixIcon; as mpi2) { <mat-icon>{{ mpi2 }}</mat-icon> }{{ m.value }}</span> }\n }\n </div>\n }\n @if (trailing(item); as tr) {\n <div class=\"trailing\" [ngClass]=\"tr.class\" [style.cssText]=\"tr.style\">\n @switch (tr.type) {\n @case ('chip') { <mat-chip [color]=\"tr.color || undefined\" [ngClass]=\"((tr.variant || 'filled') === 'outlined') ? 'chip-outlined' : ''\">{{ tr.value }}</mat-chip> }\n @default { <span>{{ tr.value }}</span> }\n }\n </div>\n }\n }\n @for (action of visibleActions(item); let aidx = $index; track action?.id ?? $index) {\n @if ((action.kind || 'icon') === 'icon') {\n <button mat-icon-button [color]=\"action.color || undefined\" (click)=\"onActionClick($event, action.id, item, i)\" [attr.aria-label]=\"action.label || action.id\">\n <mat-icon [praxisIcon]=\"action.icon\"></mat-icon>\n </button>\n } @else {\n @if (action.buttonVariant === 'stroked') { <button mat-stroked-button [color]=\"action.color || undefined\" (click)=\"onActionClick($event, action.id, item, i)\" [attr.aria-label]=\"action.label || action.id\">{{ action.label || action.id }}</button> }\n @if (action.buttonVariant === 'raised') { <button mat-raised-button [color]=\"action.color || undefined\" (click)=\"onActionClick($event, action.id, item, i)\" [attr.aria-label]=\"action.label || action.id\">{{ action.label || action.id }}</button> }\n @if (!action.buttonVariant || action.buttonVariant === 'flat') { <button mat-flat-button [color]=\"action.color || undefined\" (click)=\"onActionClick($event, action.id, item, i)\" [attr.aria-label]=\"action.label || action.id\">{{ action.label || action.id }}</button> }\n }\n }\n </div>\n </mat-list-option>\n }\n }\n </mat-selection-list>\n } @else {\n <ng-container *ngTemplateOutlet=\"readList\"></ng-container>\n }\n\n <!-- Read-only list -->\n <ng-template #readList>\n <mat-list>\n @for (section of sections$ | async; track trackBySection($index, section); let sidx = $index) {\n @if (section.key) {\n <div class=\"section-header mat-subheader\">\n {{ sectionHeader(section.key) }}\n </div>\n }\n @for (item of section.items; track trackByItem($index, item); let i = $index) {\n <mat-list-item (click)=\"onItemClick(item, i, section.key || undefined)\">\n <div class=\"list-item-content\">\n @if (leading(item); as lead) { <mat-icon [ngClass]=\"lead.class\" [style.cssText]=\"lead.style\">{{ lead.value }}</mat-icon> }\n @if (meta(item); as m) {\n <div>\n <div class=\"primary\" [ngClass]=\"primary(item)?.class\" [style.cssText]=\"primary(item)?.style\">{{ primary(item)?.value }}</div>\n @if (layoutLines > 1) { <div class=\"secondary\" [ngClass]=\"secondary(item)?.class\" [style.cssText]=\"secondary(item)?.style\">{{ secondary(item)?.value }}</div> }\n @if ((config.templating?.metaPlacement === 'line' && m?.type === 'text') || (layoutLines > 2 && m?.type === 'text')) { <div class=\"tertiary\" [ngClass]=\"m.class\" [style.cssText]=\"m.style\">{{ m.value }}</div> }\n </div>\n @if (!(((config.templating?.metaPlacement === 'line') || (layoutLines > 2)) && m?.type === 'text')) {\n <div class=\"meta\" [ngClass]=\"m.class\" [style.cssText]=\"m.style\">\n @switch (m.type) {\n @case ('chip') { <mat-chip>{{ m.value }}</mat-chip> }\n @case ('rating') { @for (_ of [0,1,2,3,4]; track $index; let idx = $index) { <mat-icon>{{ starIcon(idx, m.value) }}</mat-icon> } }\n @default { <span>{{ m.value }}</span> }\n }\n </div>\n }\n @if (trailing(item); as tr) {\n <div class=\"trailing\" [ngClass]=\"tr.class\" [style.cssText]=\"tr.style\">\n @switch (tr.type) {\n @case ('chip') { <mat-chip>{{ tr.value }}</mat-chip> }\n @default { <span>{{ tr.value }}</span> }\n }\n </div>\n }\n }\n @for (action of visibleActions(item); let aidx = $index; track action?.id ?? $index) {\n <button mat-icon-button [color]=\"action.color || undefined\" (click)=\"onActionClick($event, action.id, item, i)\" [attr.aria-label]=\"action.label || action.id\">\n <mat-icon>{{ action.icon }}</mat-icon>\n </button>\n }\n </div>\n </mat-list-item>\n }\n @if (config.layout?.dividers === 'between') { <mat-divider></mat-divider> }\n }\n </mat-list>\n </ng-template>\n } @else {\n <ng-container *ngTemplateOutlet=\"cardsVariant\"></ng-container>\n }\n\n <!-- Cards variant -->\n <ng-template #cardsVariant>\n <div class=\"cards-grid\">\n @for (it of (items$ | async) ?? []; track $index; let i = $index) {\n <div class=\"item-card\" (click)=\"onItemClick(it, i)\">\n <div class=\"list-item-content\">\n @if (leading(it); as lead) {\n @switch (lead.type) {\n @case ('icon') { <mat-icon [ngClass]=\"lead.class\" [style.cssText]=\"lead.style\">{{ lead.value }}</mat-icon> }\n @case ('image') {\n <div class=\"lead-image\" [ngClass]=\"lead.class\" [style.cssText]=\"lead.style\">\n <img [src]=\"lead.value\" [alt]=\"config.templating?.leading?.imageAlt || ''\" />\n @if (lead.badge?.value) { <mat-chip class=\"lead-badge\" [color]=\"lead.badge?.color || undefined\" [ngClass]=\"(((lead.badge?.variant || 'filled') === 'outlined') ? 'chip-outlined' : '')\">{{ lead.badge?.value }}</mat-chip> }\n </div>\n }\n }\n }\n @if (meta(it); as m) {\n <div>\n <div class=\"primary\" [ngClass]=\"primary(it)?.class\" [style.cssText]=\"primary(it)?.style\">{{ primary(it)?.value }}</div>\n @if (layoutLines > 1) { <div class=\"secondary\" [ngClass]=\"secondary(it)?.class\" [style.cssText]=\"secondary(it)?.style\">{{ secondary(it)?.value }}</div> }\n @if ((config.templating?.metaPlacement === 'line' && m?.type === 'text') || (layoutLines > 2 && m?.type === 'text')) { <div class=\"tertiary\" [ngClass]=\"m.class\" [style.cssText]=\"m.style\">{{ m.value }}</div> }\n @if (featuresVisible()) {\n @for (f of (config.templating?.features || []); track $index; let fi = $index) {\n <span class=\"feature\">\n @if (f.icon && featuresMode() !== 'labels-only') { <mat-icon>{{ f.icon }}</mat-icon> }\n @if (featuresMode() !== 'icons-only') { <span [ngClass]=\"f.class\" [style.cssText]=\"f.style\">{{ featureLabel(it, f.expr) }}</span> }\n </span>\n }\n }\n </div>\n @if (!(((config.templating?.metaPlacement === 'line') || (layoutLines > 2)) && m?.type === 'text')) {\n <div class=\"meta\" [ngClass]=\"m.class\" [style.cssText]=\"m.style\">\n @switch (m.type) {\n @case ('chip') { <mat-chip [color]=\"m.color || undefined\" [ngClass]=\"((m.variant || 'filled') === 'outlined') ? 'chip-outlined' : ''\">{{ m.value }}</mat-chip> }\n @case ('rating') { @for (_ of [0,1,2,3,4]; track $index; let idx = $index) { <mat-icon>{{ starIcon(idx, m.value) }}</mat-icon> } }\n @default { <span>{{ m.value }}</span> }\n }\n </div>\n }\n @if (trailing(it); as tr) {\n <div class=\"trailing\" [ngClass]=\"tr.class\" [style.cssText]=\"tr.style\">\n @switch (tr.type) {\n @case ('chip') { <mat-chip [color]=\"tr.color || undefined\" [ngClass]=\"((tr.variant || 'filled') === 'outlined') ? 'chip-outlined' : ''\">{{ tr.value }}</mat-chip> }\n @default { <span>{{ tr.value }}</span> }\n }\n </div>\n }\n }\n </div>\n <div class=\"card-actions\" (click)=\"$event.stopPropagation()\">\n @for (action of visibleActions(it); let aidx = $index; track action?.id ?? $index) {\n @if ((action.kind || 'icon') === 'icon') {\n <button mat-icon-button [color]=\"action.color || undefined\" (click)=\"onActionClick($event, action.id, it, i)\" [attr.aria-label]=\"action.label || action.id\">\n <mat-icon>{{ action.icon }}</mat-icon>\n </button>\n } @else {\n @if (action.buttonVariant === 'stroked') { <button mat-stroked-button [color]=\"action.color || undefined\" (click)=\"onActionClick($event, action.id, it, i)\" [attr.aria-label]=\"action.label || action.id\">{{ action.label || action.id }}</button> }\n @if (action.buttonVariant === 'raised') { <button mat-raised-button [color]=\"action.color || undefined\" (click)=\"onActionClick($event, action.id, it, i)\" [attr.aria-label]=\"action.label || action.id\">{{ action.label || action.id }}</button> }\n @if (!action.buttonVariant || action.buttonVariant === 'flat') { <button mat-flat-button [color]=\"action.color || undefined\" (click)=\"onActionClick($event, action.id, it, i)\" [attr.aria-label]=\"action.label || action.id\">{{ action.label || action.id }}</button> }\n }\n }\n </div>\n </div>\n }\n </div>\n </ng-template>\n \n <!-- Simple pagination controls for remote data -->\n @if (config.dataSource?.resourcePath) {\n <div class=\"paginator\">\n <button mat-stroked-button color=\"primary\" (click)=\"prevPage()\">Anterior</button>\n <button mat-stroked-button color=\"primary\" (click)=\"nextPage()\">Pr\u00F3ximo</button>\n @if (total$ | async; as total) { <span class=\"muted\">Total: {{ total }}</span> }\n </div>\n }\n </ng-template>\n</div>\n", styles: ["@charset \"UTF-8\";:host{display:block}.praxis-list-root{--p-list-radius: 1rem;--p-list-shadow: 0 6px 20px rgba(0, 0, 0, .08);--p-list-border: 1px solid rgba(0, 0, 0, .08);--p-list-blur: 8px;--p-list-grad-from: #8e72ff;--p-list-grad-to: #ffaa70;--p-list-grad-angle: 135deg}.skin-elevated .item-card{background:var(--mdc-elevated-card-container-color, var(--md-sys-color-surface));border-radius:var(--p-list-radius);box-shadow:var(--p-list-shadow);border:var(--p-list-border)}.skin-pill-soft .item-card{background:var(--mdc-elevated-card-container-color, var(--md-sys-color-surface));border-radius:calc(var(--p-list-radius) * 1.3);box-shadow:0 4px 16px #00000014;border:var(--p-list-border)}.skin-pill-soft .mat-mdc-list-item .list-item-content{background:var(--mdc-elevated-card-container-color, var(--md-sys-color-surface));border-radius:calc(var(--p-list-radius) * 1.3);box-shadow:0 4px 16px #00000014;border:var(--p-list-border);color:var(--p-list-foreground, #1f2937)}.skin-gradient-tile .item-card,.skin-gradient-tile .mat-mdc-list-item .list-item-content{background:linear-gradient(var(--p-list-grad-angle),var(--p-list-grad-from),var(--p-list-grad-to));border-radius:var(--p-list-radius);color:#fff}.skin-glass .item-card{background:#ffffff2e;border-radius:var(--p-list-radius);border:1px solid rgba(255,255,255,.3);backdrop-filter:blur(var(--p-list-blur));-webkit-backdrop-filter:blur(var(--p-list-blur))}.skin-glass .mat-mdc-list-item .list-item-content{background:#ffffff2e;border-radius:var(--p-list-radius);border:1px solid rgba(255,255,255,.3);backdrop-filter:blur(var(--p-list-blur));-webkit-backdrop-filter:blur(var(--p-list-blur));color:var(--p-list-foreground, #111)}.density-compact .mat-mdc-list-item,.density-compact .item-card{--_item-padding: 4px 8px}.density-comfortable .mat-mdc-list-item,.density-comfortable .item-card{--_item-padding: 8px 12px}.list-item-content{display:grid;grid-template-columns:auto 1fr auto;align-items:center;gap:12px;padding:var(--_item-padding, 12px 16px)}.lead-image{position:relative;width:96px;height:72px;border-radius:12px;overflow:hidden}.lead-image img{width:100%;height:100%;object-fit:cover;display:block}.lead-image .lead-badge{position:absolute;left:8px;bottom:8px}.model-media .lead-image{width:136px;height:96px;border-radius:16px}.model-media .list-item-content{gap:16px}.model-hotel .lead-image{width:160px;height:110px;border-radius:18px}.primary{font-weight:600;color:var(--sicoob-tertiary-default, #001E24)}.secondary{opacity:.8}.tertiary{opacity:.68}.features{display:flex;flex-wrap:wrap;gap:12px;margin-top:6px;color:#000000a8}.feature{display:inline-flex;align-items:center;gap:6px}.meta{opacity:.9}.trailing{opacity:.9;margin-left:8px}.section-header{font-size:.85rem;opacity:.7;padding:8px 12px}.cards-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(280px,1fr));gap:12px}.item-card{padding:12px;display:flex;flex-direction:column;min-height:160px}.item-card:hover{box-shadow:0 10px 24px var(--sicoob-shadow-medium, rgba(0, 0, 0, .12));transform:translateY(-1px);transition:box-shadow .15s ease,transform .15s ease}.card-actions{display:flex;align-items:center;justify-content:flex-end;gap:4px;padding:6px 8px 4px;border-top:1px solid var(--sicoob-stroke-medium, rgba(0, 0, 0, .08));margin-top:auto}.leading-icon.mat-icon{width:36px;height:36px;line-height:36px;font-size:20px;display:inline-flex;align-items:center;justify-content:center;border-radius:999px;background:color-mix(in srgb,var(--sicoob-info-lightest, #f0f9ff),transparent 30%);color:var(--sicoob-info-default, #0090e0)}.mat-mdc-chip{--mdc-chip-container-height: 22px;font-size:12px}.meta .mat-icon{font-size:18px;height:18px;width:18px}.primary,.secondary{display:-webkit-box;-webkit-box-orient:vertical;overflow:hidden;text-overflow:ellipsis}.primary,.secondary{-webkit-line-clamp:1}.features{overflow:hidden}@keyframes shimmer{0%{background-position:-468px 0}to{background-position:468px 0}}.skeleton{animation-duration:1.2s;animation-fill-mode:forwards;animation-iteration-count:infinite;animation-name:shimmer;animation-timing-function:linear;background:#f6f7f8;background:linear-gradient(to right,#eee 8%,#ddd 18%,#eee 33%);background-size:800px 104px;position:relative}.skeleton-avatar{width:32px;height:32px;border-radius:50%}.skeleton-line{height:10px;margin:6px 0;border-radius:6px}.skeleton-chip{width:48px;height:18px;border-radius:999px}.chip-outlined.mat-mdc-chip{background:transparent!important;border:1px solid currentColor}.w-60{width:60%}.w-40{width:40%}.paginator{display:flex;align-items:center;gap:8px;padding:8px 4px}.muted{opacity:.7}\n"] }]
3010
+ MatFormFieldModule,
3011
+ MatSelectModule,
3012
+ ], changeDetection: ChangeDetectionStrategy.OnPush, providers: [GenericCrudService, ListDataService], template: "<div\n class=\"praxis-list-root\"\n [ngClass]=\"skinClasses\"\n [attr.aria-label]=\"config.a11y?.ariaLabel || null\"\n [attr.aria-labelledby]=\"config.a11y?.ariaLabelledBy || null\"\n>\n @if (inlineCss) {\n <style [innerHTML]=\"inlineCss\"></style>\n }\n\n <!-- Skeleton while loading -->\n @if ((loading$ | async) && hasSkeleton()) {\n @if (isListVariant()) {\n <mat-list>\n @for (_ of skeletonItems(); track $index; let i = $index) {\n <mat-list-item>\n <div class=\"list-item-content\">\n <div class=\"skeleton skeleton-avatar\"></div>\n <div style=\"width:100%\">\n <div class=\"skeleton skeleton-line w-60\"></div>\n @if (layoutLines > 1) { <div class=\"skeleton skeleton-line w-40\"></div> }\n </div>\n <div class=\"skeleton skeleton-chip\"></div>\n </div>\n </mat-list-item>\n }\n </mat-list>\n } @else {\n <div class=\"cards-grid\">\n @for (_ of skeletonItems(); track $index; let i = $index) {\n <div class=\"item-card\">\n <div class=\"list-item-content\">\n <div class=\"skeleton skeleton-avatar\"></div>\n <div style=\"width:100%\">\n <div class=\"skeleton skeleton-line w-60\"></div>\n @if (layoutLines > 1) { <div class=\"skeleton skeleton-line w-40\"></div> }\n </div>\n <div class=\"skeleton skeleton-chip\"></div>\n </div>\n </div>\n }\n </div>\n }\n } @else {\n <ng-container *ngTemplateOutlet=\"notLoading\"></ng-container>\n }\n\n <ng-template #notLoading>\n <!-- Empty state -->\n @if (items$ | async; as all) {\n @if (all.length === 0) {\n <div class=\"section-header\">\n {{ (config.templating?.emptyState?.expr || 'Nenhum item dispon\u00EDvel') }}\n </div>\n }\n }\n\n <!-- List variant -->\n @if (isListVariant()) {\n <!-- Selection list -->\n @if (isSelectionEnabled()) {\n <mat-selection-list\n [multiple]=\"config.selection?.mode === 'multiple'\"\n [formControl]=\"boundControl\"\n (selectionChange)=\"onSelectionChange($event)\"\n >\n @for (section of sections$ | async; track trackBySection($index, section)) {\n @if (section.key) {\n <div class=\"section-header mat-subheader\">\n {{ sectionHeader(section.key) }}\n </div>\n }\n @for (item of section.items; track trackByItem($index, item); let i = $index) {\n <mat-list-option\n [value]=\"item\"\n (click)=\"onItemClick(item, i, section.key || undefined)\"\n >\n <div class=\"list-item-content\">\n @if (leading(item); as lead) {\n @switch (lead.type) {\n @case ('icon') {\n <mat-icon [ngClass]=\"lead.class\" [style.cssText]=\"lead.style\">{{ lead.value }}</mat-icon>\n }\n @case ('image') {\n <div class=\"lead-image\" [ngClass]=\"lead.class\" [style.cssText]=\"lead.style\">\n <img [src]=\"lead.value\" [alt]=\"config.templating?.leading?.imageAlt || ''\" />\n @if (lead.badge?.value) {\n <mat-chip class=\"lead-badge\" [color]=\"lead.badge?.color || undefined\" [ngClass]=\"(((lead.badge?.variant || 'filled') === 'outlined') ? 'chip-outlined' : '')\">{{ lead.badge?.value }}</mat-chip>\n }\n </div>\n }\n }\n }\n @if (meta(item); as m) {\n <div>\n <div class=\"primary\" [ngClass]=\"primary(item)?.class\" [style.cssText]=\"primary(item)?.style\">{{ primary(item)?.value }}</div>\n @if (layoutLines > 1) { <div class=\"secondary\" [ngClass]=\"secondary(item)?.class\" [style.cssText]=\"secondary(item)?.style\">{{ secondary(item)?.value }}</div> }\n @if ((config.templating?.metaPlacement === 'line' && (m?.type === 'text' || m?.type === 'date')) || (layoutLines > 2 && (m?.type === 'text' || m?.type === 'date'))) {\n <div class=\"tertiary\" [ngClass]=\"m.class\" [style.cssText]=\"m.style\">\n @if (config.templating?.metaPrefixIcon; as mpi) { <mat-icon [praxisIcon]=\"mpi\"></mat-icon> }\n {{ m.value }}\n </div>\n }\n @if (featuresVisible()) {\n @for (f of (config.templating?.features || []); track $index; let fi = $index) {\n <span class=\"feature\">\n @if (f.icon && featuresMode() !== 'labels-only') { <mat-icon [praxisIcon]=\"f.icon\"></mat-icon> }\n @if (featuresMode() !== 'icons-only') { <span [ngClass]=\"f.class\" [style.cssText]=\"f.style\">{{ featureLabel(item, f.expr) }}</span> }\n </span>\n }\n }\n </div>\n @if (!(((config.templating?.metaPlacement === 'line') || (layoutLines > 2)) && (m?.type === 'text' || m?.type === 'date'))) {\n <div class=\"meta\" [ngClass]=\"m.class\" [style.cssText]=\"m.style\">\n @switch (m.type) {\n @case ('chip') { <mat-chip [color]=\"m.color || undefined\" [ngClass]=\"((m.variant || 'filled') === 'outlined') ? 'chip-outlined' : ''\">{{ m.value }}</mat-chip> }\n @case ('rating') { @for (_ of [0,1,2,3,4]; track $index; let idx = $index) { <mat-icon [praxisIcon]=\"starIcon(idx, m.value)\"></mat-icon> } }\n @default { <span>@if (config.templating?.metaPrefixIcon; as mpi2) { <mat-icon>{{ mpi2 }}</mat-icon> }{{ m.value }}</span> }\n }\n </div>\n }\n @if (trailing(item); as tr) {\n <div class=\"trailing\" [ngClass]=\"tr.class\" [style.cssText]=\"tr.style\">\n @switch (tr.type) {\n @case ('chip') { <mat-chip [color]=\"tr.color || undefined\" [ngClass]=\"((tr.variant || 'filled') === 'outlined') ? 'chip-outlined' : ''\">{{ tr.value }}</mat-chip> }\n @case ('icon') { <mat-icon [praxisIcon]=\"tr.value\" [color]=\"tr.color || undefined\"></mat-icon> }\n @default { <span>{{ tr.value }}</span> }\n }\n </div>\n }\n }\n @for (action of visibleActions(item); let aidx = $index; track action?.id ?? $index) {\n @if ((action.kind || 'icon') === 'icon') {\n <button mat-icon-button [color]=\"action.color || undefined\" (click)=\"onActionClick($event, action.id, item, i)\" [attr.aria-label]=\"action.label || action.id\">\n <mat-icon [praxisIcon]=\"action.icon\"></mat-icon>\n </button>\n } @else {\n @if (action.buttonVariant === 'stroked') { <button mat-stroked-button [color]=\"action.color || undefined\" (click)=\"onActionClick($event, action.id, item, i)\" [attr.aria-label]=\"action.label || action.id\">{{ action.label || action.id }}</button> }\n @if (action.buttonVariant === 'raised') { <button mat-raised-button [color]=\"action.color || undefined\" (click)=\"onActionClick($event, action.id, item, i)\" [attr.aria-label]=\"action.label || action.id\">{{ action.label || action.id }}</button> }\n @if (!action.buttonVariant || action.buttonVariant === 'flat') { <button mat-flat-button [color]=\"action.color || undefined\" (click)=\"onActionClick($event, action.id, item, i)\" [attr.aria-label]=\"action.label || action.id\">{{ action.label || action.id }}</button> }\n }\n }\n </div>\n </mat-list-option>\n }\n }\n </mat-selection-list>\n } @else {\n <ng-container *ngTemplateOutlet=\"readList\"></ng-container>\n }\n\n <!-- Read-only list -->\n <ng-template #readList>\n <mat-list>\n @for (section of sections$ | async; track trackBySection($index, section); let sidx = $index) {\n @if (section.key) {\n <div class=\"section-header mat-subheader\">\n {{ sectionHeader(section.key) }}\n </div>\n }\n @for (item of section.items; track trackByItem($index, item); let i = $index) {\n <mat-list-item (click)=\"onItemClick(item, i, section.key || undefined)\">\n <div class=\"list-item-content\">\n @if (leading(item); as lead) { <mat-icon [ngClass]=\"lead.class\" [style.cssText]=\"lead.style\">{{ lead.value }}</mat-icon> }\n @if (meta(item); as m) {\n <div>\n <div class=\"primary\" [ngClass]=\"primary(item)?.class\" [style.cssText]=\"primary(item)?.style\">{{ primary(item)?.value }}</div>\n @if (layoutLines > 1) { <div class=\"secondary\" [ngClass]=\"secondary(item)?.class\" [style.cssText]=\"secondary(item)?.style\">{{ secondary(item)?.value }}</div> }\n @if ((config.templating?.metaPlacement === 'line' && (m?.type === 'text' || m?.type === 'date')) || (layoutLines > 2 && (m?.type === 'text' || m?.type === 'date'))) { <div class=\"tertiary\" [ngClass]=\"m.class\" [style.cssText]=\"m.style\">{{ m.value }}</div> }\n </div>\n @if (!(((config.templating?.metaPlacement === 'line') || (layoutLines > 2)) && (m?.type === 'text' || m?.type === 'date'))) {\n <div class=\"meta\" [ngClass]=\"m.class\" [style.cssText]=\"m.style\">\n @switch (m.type) {\n @case ('chip') { <mat-chip>{{ m.value }}</mat-chip> }\n @case ('rating') { @for (_ of [0,1,2,3,4]; track $index; let idx = $index) { <mat-icon>{{ starIcon(idx, m.value) }}</mat-icon> } }\n @default { <span>{{ m.value }}</span> }\n }\n </div>\n }\n @if (trailing(item); as tr) {\n <div class=\"trailing\" [ngClass]=\"tr.class\" [style.cssText]=\"tr.style\">\n @switch (tr.type) {\n @case ('chip') { <mat-chip>{{ tr.value }}</mat-chip> }\n @case ('icon') { <mat-icon [praxisIcon]=\"tr.value\" [color]=\"tr.color || undefined\"></mat-icon> }\n @default { <span>{{ tr.value }}</span> }\n }\n </div>\n }\n }\n @for (action of visibleActions(item); let aidx = $index; track action?.id ?? $index) {\n <button mat-icon-button [color]=\"action.color || undefined\" (click)=\"onActionClick($event, action.id, item, i)\" [attr.aria-label]=\"action.label || action.id\">\n <mat-icon>{{ action.icon }}</mat-icon>\n </button>\n }\n </div>\n </mat-list-item>\n }\n @if (config.layout?.dividers === 'between') { <mat-divider></mat-divider> }\n }\n </mat-list>\n </ng-template>\n } @else {\n <ng-container *ngTemplateOutlet=\"cardsVariant\"></ng-container>\n }\n\n <!-- Cards variant -->\n <ng-template #cardsVariant>\n <div class=\"cards-grid\">\n @for (it of (items$ | async) ?? []; track $index; let i = $index) {\n <div class=\"item-card\" (click)=\"onItemClick(it, i)\">\n <div class=\"list-item-content\">\n @if (leading(it); as lead) {\n @switch (lead.type) {\n @case ('icon') { <mat-icon [ngClass]=\"lead.class\" [style.cssText]=\"lead.style\">{{ lead.value }}</mat-icon> }\n @case ('image') {\n <div class=\"lead-image\" [ngClass]=\"lead.class\" [style.cssText]=\"lead.style\">\n <img [src]=\"lead.value\" [alt]=\"config.templating?.leading?.imageAlt || ''\" />\n @if (lead.badge?.value) { <mat-chip class=\"lead-badge\" [color]=\"lead.badge?.color || undefined\" [ngClass]=\"(((lead.badge?.variant || 'filled') === 'outlined') ? 'chip-outlined' : '')\">{{ lead.badge?.value }}</mat-chip> }\n </div>\n }\n }\n }\n @if (meta(it); as m) {\n <div>\n <div class=\"primary\" [ngClass]=\"primary(it)?.class\" [style.cssText]=\"primary(it)?.style\">{{ primary(it)?.value }}</div>\n @if (layoutLines > 1) { <div class=\"secondary\" [ngClass]=\"secondary(it)?.class\" [style.cssText]=\"secondary(it)?.style\">{{ secondary(it)?.value }}</div> }\n @if ((config.templating?.metaPlacement === 'line' && (m?.type === 'text' || m?.type === 'date')) || (layoutLines > 2 && (m?.type === 'text' || m?.type === 'date'))) { <div class=\"tertiary\" [ngClass]=\"m.class\" [style.cssText]=\"m.style\">{{ m.value }}</div> }\n @if (featuresVisible()) {\n @for (f of (config.templating?.features || []); track $index; let fi = $index) {\n <span class=\"feature\">\n @if (f.icon && featuresMode() !== 'labels-only') { <mat-icon>{{ f.icon }}</mat-icon> }\n @if (featuresMode() !== 'icons-only') { <span [ngClass]=\"f.class\" [style.cssText]=\"f.style\">{{ featureLabel(it, f.expr) }}</span> }\n </span>\n }\n }\n </div>\n @if (!(((config.templating?.metaPlacement === 'line') || (layoutLines > 2)) && (m?.type === 'text' || m?.type === 'date'))) {\n <div class=\"meta\" [ngClass]=\"m.class\" [style.cssText]=\"m.style\">\n @switch (m.type) {\n @case ('chip') { <mat-chip [color]=\"m.color || undefined\" [ngClass]=\"((m.variant || 'filled') === 'outlined') ? 'chip-outlined' : ''\">{{ m.value }}</mat-chip> }\n @case ('rating') { @for (_ of [0,1,2,3,4]; track $index; let idx = $index) { <mat-icon>{{ starIcon(idx, m.value) }}</mat-icon> } }\n @default { <span>{{ m.value }}</span> }\n }\n </div>\n }\n @if (trailing(it); as tr) {\n @if ((config.templating?.statusPosition || 'inline') === 'top-right' && (tr?.type === 'chip' || tr?.type === 'icon')) {\n <div class=\"status-overlay\">\n @if (tr?.type === 'chip') { <mat-chip [color]=\"tr.color || undefined\" [ngClass]=\"((tr.variant || 'filled') === 'outlined') ? 'chip-outlined' : ''\">{{ tr.value }}</mat-chip> }\n @if (tr?.type === 'icon') { <mat-icon [praxisIcon]=\"tr.value\" [color]=\"tr.color || undefined\"></mat-icon> }\n </div>\n } @else {\n <div class=\"trailing\" [ngClass]=\"tr.class\" [style.cssText]=\"tr.style\">\n @switch (tr.type) {\n @case ('chip') { <mat-chip [color]=\"tr.color || undefined\" [ngClass]=\"((tr.variant || 'filled') === 'outlined') ? 'chip-outlined' : ''\">{{ tr.value }}</mat-chip> }\n @case ('icon') { <mat-icon [praxisIcon]=\"tr.value\" [color]=\"tr.color || undefined\"></mat-icon> }\n @default { <span>{{ tr.value }}</span> }\n }\n </div>\n }\n }\n }\n </div>\n <div class=\"card-actions\" (click)=\"$event.stopPropagation()\">\n @for (action of visibleActions(it); let aidx = $index; track action?.id ?? $index) {\n @if ((action.kind || 'icon') === 'icon') {\n <button mat-icon-button [color]=\"action.color || undefined\" (click)=\"onActionClick($event, action.id, it, i)\" [attr.aria-label]=\"action.label || action.id\">\n <mat-icon>{{ action.icon }}</mat-icon>\n </button>\n } @else {\n @if (action.buttonVariant === 'stroked') { <button mat-stroked-button [color]=\"action.color || undefined\" (click)=\"onActionClick($event, action.id, it, i)\" [attr.aria-label]=\"action.label || action.id\">{{ action.label || action.id }}</button> }\n @if (action.buttonVariant === 'raised') { <button mat-raised-button [color]=\"action.color || undefined\" (click)=\"onActionClick($event, action.id, it, i)\" [attr.aria-label]=\"action.label || action.id\">{{ action.label || action.id }}</button> }\n @if (!action.buttonVariant || action.buttonVariant === 'flat') { <button mat-flat-button [color]=\"action.color || undefined\" (click)=\"onActionClick($event, action.id, it, i)\" [attr.aria-label]=\"action.label || action.id\">{{ action.label || action.id }}</button> }\n }\n }\n </div>\n </div>\n }\n </div>\n </ng-template>\n \n <!-- Simple pagination controls for remote data -->\n @if (config.dataSource?.resourcePath) {\n <div class=\"paginator\">\n <button mat-stroked-button color=\"primary\" (click)=\"prevPage()\">Anterior</button>\n <button mat-stroked-button color=\"primary\" (click)=\"nextPage()\">Pr\u00F3ximo</button>\n <mat-form-field style=\"width: 120px; margin-left: 8px;\" appearance=\"outline\">\n <mat-label>Tam. p\u00E1gina</mat-label>\n <mat-select (selectionChange)=\"setPageSize($event.value)\" [value]=\"config.layout?.pageSize || 10\">\n <mat-option [value]=\"6\">6</mat-option>\n <mat-option [value]=\"8\">8</mat-option>\n <mat-option [value]=\"12\">12</mat-option>\n <mat-option [value]=\"24\">24</mat-option>\n </mat-select>\n </mat-form-field>\n @if (total$ | async; as total) { <span class=\"muted\">Total: {{ total }}</span> }\n </div>\n }\n </ng-template>\n</div>\n", styles: ["@charset \"UTF-8\";:host{display:block}.praxis-list-root{--p-list-radius: 1rem;--p-list-shadow: 0 6px 20px rgba(0, 0, 0, .08);--p-list-border: 1px solid rgba(0, 0, 0, .08);--p-list-blur: 8px;--p-list-grad-from: #8e72ff;--p-list-grad-to: #ffaa70;--p-list-grad-angle: 135deg}.skin-elevated .item-card{background:var(--mdc-elevated-card-container-color, var(--md-sys-color-surface));border-radius:var(--p-list-radius);box-shadow:var(--p-list-shadow);border:var(--p-list-border)}.skin-pill-soft .item-card{background:var(--mdc-elevated-card-container-color, var(--md-sys-color-surface));border-radius:calc(var(--p-list-radius) * 1.3);box-shadow:0 4px 16px #00000014;border:var(--p-list-border)}.skin-pill-soft .mat-mdc-list-item .list-item-content{background:var(--mdc-elevated-card-container-color, var(--md-sys-color-surface));border-radius:calc(var(--p-list-radius) * 1.3);box-shadow:0 4px 16px #00000014;border:var(--p-list-border);color:var(--p-list-foreground, #1f2937)}.skin-gradient-tile .item-card,.skin-gradient-tile .mat-mdc-list-item .list-item-content{background:linear-gradient(var(--p-list-grad-angle),var(--p-list-grad-from),var(--p-list-grad-to));border-radius:var(--p-list-radius);color:#fff}.skin-glass .item-card{background:#ffffff2e;border-radius:var(--p-list-radius);border:1px solid rgba(255,255,255,.3);backdrop-filter:blur(var(--p-list-blur));-webkit-backdrop-filter:blur(var(--p-list-blur))}.skin-glass .mat-mdc-list-item .list-item-content{background:#ffffff2e;border-radius:var(--p-list-radius);border:1px solid rgba(255,255,255,.3);backdrop-filter:blur(var(--p-list-blur));-webkit-backdrop-filter:blur(var(--p-list-blur));color:var(--p-list-foreground, #111)}.density-compact .mat-mdc-list-item,.density-compact .item-card{--_item-padding: 4px 8px}.density-comfortable .mat-mdc-list-item,.density-comfortable .item-card{--_item-padding: 8px 12px}.list-item-content{display:grid;grid-template-columns:auto 1fr auto;align-items:center;gap:12px;padding:var(--_item-padding, 12px 16px)}.lead-image{position:relative;width:96px;height:72px;border-radius:12px;overflow:hidden}.lead-image img{width:100%;height:100%;object-fit:cover;display:block}.lead-image .lead-badge{position:absolute;left:8px;bottom:8px}.model-media .lead-image{width:136px;height:96px;border-radius:16px}.model-media .list-item-content{gap:16px}.model-hotel .lead-image{width:160px;height:110px;border-radius:18px}.primary{font-weight:600;color:var(--sicoob-tertiary-default, #001E24)}.secondary{opacity:.8}.tertiary{opacity:.68}.features{display:flex;flex-wrap:wrap;gap:12px;margin-top:6px;color:inherit}.feature{display:inline-flex;align-items:center;gap:6px}.meta{opacity:.9}.trailing{opacity:.9;margin-left:8px}.section-header{font-size:.85rem;opacity:.7;padding:8px 12px}.cards-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(280px,1fr));gap:12px}.item-card{padding:12px;display:flex;flex-direction:column;min-height:160px;position:relative;cursor:pointer}.item-card:hover{box-shadow:0 10px 24px var(--sicoob-shadow-medium, rgba(0, 0, 0, .12));transform:translateY(-1px);transition:box-shadow .15s ease,transform .15s ease}.card-actions{display:flex;align-items:center;justify-content:flex-end;gap:4px;padding:6px 8px 4px;border-top:1px solid var(--sicoob-stroke-medium, rgba(0, 0, 0, .08));margin-top:auto}.status-overlay{position:absolute;top:10px;right:10px;pointer-events:none}.status-overlay .mat-mdc-chip{pointer-events:auto}.leading-icon.mat-icon{width:36px;height:36px;line-height:36px;font-size:20px;display:inline-flex;align-items:center;justify-content:center;border-radius:999px;background:color-mix(in srgb,var(--sicoob-info-lightest, #f0f9ff),transparent 30%);color:var(--sicoob-info-default, #0090e0)}.mat-mdc-chip{--mdc-chip-container-height: 22px;font-size:12px}.meta .mat-icon{font-size:18px;height:18px;width:18px}.primary,.secondary{display:-webkit-box;-webkit-box-orient:vertical;overflow:hidden;text-overflow:ellipsis}.primary,.secondary{-webkit-line-clamp:1}.features{overflow:hidden}@keyframes shimmer{0%{background-position:-468px 0}to{background-position:468px 0}}.skeleton{animation-duration:1.2s;animation-fill-mode:forwards;animation-iteration-count:infinite;animation-name:shimmer;animation-timing-function:linear;background:#f6f7f8;background:linear-gradient(to right,#eee 8%,#ddd 18%,#eee 33%);background-size:800px 104px;position:relative}.skeleton-avatar{width:32px;height:32px;border-radius:50%}.skeleton-line{height:10px;margin:6px 0;border-radius:6px}.skeleton-chip{width:48px;height:18px;border-radius:999px}.chip-outlined.mat-mdc-chip{background:transparent!important;border:1px solid currentColor}.w-60{width:60%}.w-40{width:40%}.paginator{display:flex;align-items:center;gap:8px;padding:8px 4px}.muted{opacity:.7}\n"] }]
2878
3013
  }], propDecorators: { config: [{
2879
3014
  type: Input
2880
3015
  }], form: [{