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

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.
@@ -2787,7 +2787,33 @@ class PraxisList {
2787
2787
  value = truthy ? (t ?? 'Sim') : (f ?? 'Não');
2788
2788
  }
2789
2789
  }
2790
- return { type: def.type, value, class: def.class, style: def.style, color: def.color, variant: def.variant };
2790
+ // Optional color mapping from config.templating.chipColorMap
2791
+ let color = def.color;
2792
+ try {
2793
+ const map = this.config?.templating?.chipColorMap;
2794
+ if (map && typeof value === 'string') {
2795
+ const key = String(value).toLowerCase();
2796
+ const found = map[key] ?? map[value];
2797
+ if (found)
2798
+ color = found;
2799
+ }
2800
+ }
2801
+ catch { }
2802
+ // Optional label mapping
2803
+ try {
2804
+ const lmap = this.config?.templating?.chipLabelMap;
2805
+ if (lmap && typeof value === 'string') {
2806
+ const key = String(value).toLowerCase();
2807
+ const lbl = lmap[key] ?? lmap[value];
2808
+ if (lbl)
2809
+ value = lbl;
2810
+ }
2811
+ else if (typeof value === 'string') {
2812
+ value = this.prettyLabel(value);
2813
+ }
2814
+ }
2815
+ catch { }
2816
+ return { type: def.type, value, class: def.class, style: def.style, color, variant: def.variant };
2791
2817
  }
2792
2818
  return evaluateTemplate(def, item);
2793
2819
  }
@@ -2835,6 +2861,21 @@ class PraxisList {
2835
2861
  const s = String(val).trim().toLowerCase();
2836
2862
  return s === 'true' || s === '1' || s === 'yes' || s === 'sim' || s === 'on';
2837
2863
  }
2864
+ // Format labels like 'EM_ANDAMENTO' -> 'Em andamento'; 'PLANEJADA' -> 'Planejada'
2865
+ prettyLabel(v) {
2866
+ try {
2867
+ const t = String(v ?? '')
2868
+ .replace(/[\s_\-]+/g, ' ')
2869
+ .trim()
2870
+ .toLowerCase();
2871
+ if (!t)
2872
+ return '';
2873
+ return t.replace(/\b\w/g, (m) => m.toUpperCase());
2874
+ }
2875
+ catch {
2876
+ return String(v ?? '');
2877
+ }
2878
+ }
2838
2879
  mapDateStyle(style) {
2839
2880
  switch ((style || '').toLowerCase()) {
2840
2881
  case 'short':
@@ -2861,7 +2902,7 @@ class PraxisList {
2861
2902
  trackBySection = (_, s) => s?.key ?? _;
2862
2903
  trackByItem = (i, it) => this.config?.selection?.compareBy ? (it?.[this.config.selection.compareBy] ?? i) : (it?.id ?? i);
2863
2904
  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 });
2905
+ 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 @if ((config.templating?.statusPosition || 'inline') === 'top-right' && tr?.type === 'chip') {\n <div class=\"status-overlay\">\n <mat-chip [color]=\"tr.color || undefined\" [ngClass]=\"((tr.variant || 'filled') === 'outlined') ? 'chip-outlined' : ''\">{{ tr.value }}</mat-chip>\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 @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 @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: "pipe", type: i1.AsyncPipe, name: "async" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
2865
2906
  }
2866
2907
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.4", ngImport: i0, type: PraxisList, decorators: [{
2867
2908
  type: Component,
@@ -2874,7 +2915,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.4", ngImpor
2874
2915
  PraxisIconDirective,
2875
2916
  MatChipsModule,
2876
2917
  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"] }]
2918
+ ], 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 @if ((config.templating?.statusPosition || 'inline') === 'top-right' && tr?.type === 'chip') {\n <div class=\"status-overlay\">\n <mat-chip [color]=\"tr.color || undefined\" [ngClass]=\"((tr.variant || 'filled') === 'outlined') ? 'chip-outlined' : ''\">{{ tr.value }}</mat-chip>\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 @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 @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
2919
  }], propDecorators: { config: [{
2879
2920
  type: Input
2880
2921
  }], form: [{