@praxisui/list 5.0.0-beta.0 → 7.0.0-beta.0

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.
@@ -7,7 +7,7 @@ import * as i3 from '@angular/material/list';
7
7
  import { MatListModule } from '@angular/material/list';
8
8
  import * as i4 from '@angular/material/icon';
9
9
  import { MatIconModule } from '@angular/material/icon';
10
- import { resolveValuePresentation, LoggerService, GenericCrudService, PraxisIconDirective, providePraxisI18n, PraxisI18nService, IconPickerService, GLOBAL_ACTION_CATALOG, PRAXIS_GLOBAL_ACTION_CATALOG, getGlobalActionCatalog, SURFACE_OPEN_I18N_NAMESPACE, getGlobalActionUiSchema, SurfaceOpenActionEditorComponent, providePraxisI18nConfig, SURFACE_OPEN_I18N_CONFIG, deepMerge, ASYNC_CONFIG_STORAGE, ComponentKeyService, PraxisJsonLogicService, GlobalActionService, GLOBAL_DIALOG_SERVICE, ComponentMetadataRegistry, API_URL, LocalStorageAsyncAdapter, LocalStorageConfigService } from '@praxisui/core';
10
+ import { resolveValuePresentation, LoggerService, GenericCrudService, toTitleCase, PraxisIconDirective, providePraxisI18n, PraxisI18nService, IconPickerService, GLOBAL_ACTION_CATALOG, PRAXIS_GLOBAL_ACTION_CATALOG, getGlobalActionCatalog, SURFACE_OPEN_I18N_NAMESPACE, getGlobalActionUiSchema, SurfaceOpenActionEditorComponent, providePraxisI18nConfig, SURFACE_OPEN_I18N_CONFIG, deepMerge, ASYNC_CONFIG_STORAGE, ComponentKeyService, PraxisJsonLogicService, GlobalActionService, GLOBAL_DIALOG_SERVICE, ComponentMetadataRegistry, API_URL, LocalStorageAsyncAdapter, LocalStorageConfigService } from '@praxisui/core';
11
11
  import * as i5 from '@angular/material/chips';
12
12
  import { MatChipsModule } from '@angular/material/chips';
13
13
  import { MatDividerModule } from '@angular/material/divider';
@@ -27,6 +27,7 @@ import * as i2 from '@angular/forms';
27
27
  import { FormsModule, FormControl, ReactiveFormsModule, FormGroup } from '@angular/forms';
28
28
  import { BehaviorSubject, combineLatest, of, Subject, debounceTime, takeUntil, distinctUntilChanged as distinctUntilChanged$1 } from 'rxjs';
29
29
  import { auditTime, switchMap, map, catchError, finalize, shareReplay, debounceTime as debounceTime$1, distinctUntilChanged, tap, take, takeUntil as takeUntil$1 } from 'rxjs/operators';
30
+ import { PraxisRichContent } from '@praxisui/rich-content';
30
31
  import { SETTINGS_PANEL_DATA, SettingsPanelService } from '@praxisui/settings-panel';
31
32
  import * as i3$3 from '@angular/material/tabs';
32
33
  import { MatTabsModule } from '@angular/material/tabs';
@@ -886,8 +887,7 @@ function clamp(value, min, max) {
886
887
  *
887
888
  * @example Basic usage
888
889
  * ```html
889
- * <praxis-executive-badge variant="enterprise">
890
- * Enterprise
890
+ * <praxis-executive-badge variant="enterprise" label="Enterprise">
891
891
  * </praxis-executive-badge>
892
892
  * ```
893
893
  *
@@ -895,8 +895,8 @@ function clamp(value, min, max) {
895
895
  * ```html
896
896
  * <praxis-executive-badge
897
897
  * [variant]="account.segmentType"
898
+ * [label]="account.segmentLabel"
898
899
  * [ariaLabel]="'Account segment: ' + account.segmentLabel">
899
- * {{ account.segmentLabel }}
900
900
  * </praxis-executive-badge>
901
901
  * ```
902
902
  *
@@ -911,6 +911,7 @@ class ExecutiveBadgeComponent {
911
911
  * If not provided, defaults to "Segment badge: {variant}"
912
912
  */
913
913
  ariaLabel;
914
+ label;
914
915
  _variant = 'enterprise';
915
916
  /**
916
917
  * Badge variant type with runtime validation.
@@ -947,32 +948,51 @@ class ExecutiveBadgeComponent {
947
948
  };
948
949
  return labels[this._variant];
949
950
  }
951
+ get contentNodes() {
952
+ return [
953
+ {
954
+ type: 'text',
955
+ text: this.displayLabel,
956
+ },
957
+ ];
958
+ }
959
+ get displayLabel() {
960
+ return String(this.label || '').trim();
961
+ }
950
962
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: ExecutiveBadgeComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
951
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.17", type: ExecutiveBadgeComponent, isStandalone: true, selector: "praxis-executive-badge", inputs: { ariaLabel: "ariaLabel", variant: "variant" }, ngImport: i0, template: `
963
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.17", type: ExecutiveBadgeComponent, isStandalone: true, selector: "praxis-executive-badge", inputs: { ariaLabel: "ariaLabel", label: "label", variant: "variant" }, ngImport: i0, template: `
952
964
  <span
953
965
  class="badge"
954
966
  [class]="variantClass"
955
967
  role="status"
956
968
  [attr.aria-label]="computedAriaLabel"
957
969
  >
958
- <ng-content></ng-content>
970
+ <praxis-rich-content
971
+ rootClassName="badge__content"
972
+ [nodes]="contentNodes"
973
+ ></praxis-rich-content>
959
974
  </span>
960
- `, isInline: true, styles: [".badge{display:inline-flex;align-items:center;padding:0 11px;border-radius:999px;font-size:.69rem;font-weight:700;min-height:21px}.badge-enterprise{background:#eaf4f7;color:#1d769b;border:1px solid #d6e8f0}.badge-corporate{background:#f4efe7;color:#9f8a58;border:1px solid #e7dbc4}.badge-middle{background:#ece8e1;color:#635745;border:1px solid #ddd5ca}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
975
+ `, isInline: true, styles: [".badge{display:inline-flex;align-items:center;padding:0 11px;border-radius:999px;font-size:.69rem;font-weight:700;min-height:21px}.badge__content{display:inline-flex;align-items:center;min-width:0}.badge-enterprise{background:#eaf4f7;color:#1d769b;border:1px solid #d6e8f0}.badge-corporate{background:#f4efe7;color:#9f8a58;border:1px solid #e7dbc4}.badge-middle{background:#ece8e1;color:#635745;border:1px solid #ddd5ca}\n"], dependencies: [{ kind: "component", type: PraxisRichContent, selector: "praxis-rich-content", inputs: ["document", "nodes", "context", "hostCapabilities", "rootClassName"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
961
976
  }
962
977
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: ExecutiveBadgeComponent, decorators: [{
963
978
  type: Component,
964
- args: [{ selector: 'praxis-executive-badge', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, template: `
979
+ args: [{ selector: 'praxis-executive-badge', standalone: true, imports: [PraxisRichContent], changeDetection: ChangeDetectionStrategy.OnPush, template: `
965
980
  <span
966
981
  class="badge"
967
982
  [class]="variantClass"
968
983
  role="status"
969
984
  [attr.aria-label]="computedAriaLabel"
970
985
  >
971
- <ng-content></ng-content>
986
+ <praxis-rich-content
987
+ rootClassName="badge__content"
988
+ [nodes]="contentNodes"
989
+ ></praxis-rich-content>
972
990
  </span>
973
- `, styles: [".badge{display:inline-flex;align-items:center;padding:0 11px;border-radius:999px;font-size:.69rem;font-weight:700;min-height:21px}.badge-enterprise{background:#eaf4f7;color:#1d769b;border:1px solid #d6e8f0}.badge-corporate{background:#f4efe7;color:#9f8a58;border:1px solid #e7dbc4}.badge-middle{background:#ece8e1;color:#635745;border:1px solid #ddd5ca}\n"] }]
991
+ `, styles: [".badge{display:inline-flex;align-items:center;padding:0 11px;border-radius:999px;font-size:.69rem;font-weight:700;min-height:21px}.badge__content{display:inline-flex;align-items:center;min-width:0}.badge-enterprise{background:#eaf4f7;color:#1d769b;border:1px solid #d6e8f0}.badge-corporate{background:#f4efe7;color:#9f8a58;border:1px solid #e7dbc4}.badge-middle{background:#ece8e1;color:#635745;border:1px solid #ddd5ca}\n"] }]
974
992
  }], propDecorators: { ariaLabel: [{
975
993
  type: Input
994
+ }], label: [{
995
+ type: Input
976
996
  }], variant: [{
977
997
  type: Input
978
998
  }] } });
@@ -1079,6 +1099,20 @@ class ExecutiveAlertsComponent {
1079
1099
  : 'requiring attention';
1080
1100
  return `${severity}: ${alert.count} ${plural} ${action}`;
1081
1101
  }
1102
+ alertContentNodes(alert) {
1103
+ return [
1104
+ {
1105
+ type: 'text',
1106
+ text: alert.type === 'warning' ? '△' : '●',
1107
+ className: 'alert-icon',
1108
+ },
1109
+ {
1110
+ type: 'text',
1111
+ text: String(alert.count),
1112
+ className: 'alert-count',
1113
+ },
1114
+ ];
1115
+ }
1082
1116
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: ExecutiveAlertsComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1083
1117
  static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.17", type: ExecutiveAlertsComponent, isStandalone: true, selector: "praxis-executive-alerts", inputs: { alerts: "alerts" }, usesOnChanges: true, ngImport: i0, template: `
1084
1118
  @if (validAlerts.length > 0) {
@@ -1096,22 +1130,22 @@ class ExecutiveAlertsComponent {
1096
1130
  [attr.aria-label]="getAlertAriaLabel(alert)"
1097
1131
  tabindex="0"
1098
1132
  >
1099
- <span class="alert-icon" aria-hidden="true">
1100
- {{ alert.type === 'warning' ? '△' : '●' }}
1101
- </span>
1102
- <span class="alert-count" aria-hidden="true">
1103
- {{ alert.count }}
1133
+ <span class="alert-content" aria-hidden="true">
1134
+ <praxis-rich-content
1135
+ rootClassName="alert-content__nodes"
1136
+ [nodes]="alertContentNodes(alert)"
1137
+ ></praxis-rich-content>
1104
1138
  </span>
1105
1139
  <span class="sr-only">{{ getAlertDescription(alert) }}</span>
1106
1140
  </span>
1107
1141
  }
1108
1142
  </div>
1109
1143
  }
1110
- `, isInline: true, styles: [".alerts-container{display:inline-flex;gap:6px}.alert{display:inline-flex;align-items:center;gap:4px;padding:0 7px;border-radius:999px;font-size:.72rem;font-weight:700;min-width:28px;height:20px;justify-content:center;cursor:help;transition:all .2s ease}.alert:hover,.alert:focus{transform:scale(1.05);box-shadow:0 2px 4px #0000001a;outline:2px solid currentColor;outline-offset:2px}.alert-warning{background:#fff7e8;color:#bf8422;border:1px solid #f3ddaf}.alert-critical{background:#fff1f1;color:#c65857;border:1px solid #f3c9c7}.alert-icon,.alert-count{line-height:1}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1144
+ `, isInline: true, styles: [".alerts-container{display:inline-flex;gap:6px}.alert{display:inline-flex;align-items:center;gap:4px;padding:0 7px;border-radius:999px;font-size:.72rem;font-weight:700;min-width:28px;height:20px;justify-content:center;cursor:help;transition:all .2s ease}.alert:hover,.alert:focus{transform:scale(1.05);box-shadow:0 2px 4px #0000001a;outline:2px solid currentColor;outline-offset:2px}.alert-warning{background:#fff7e8;color:#bf8422;border:1px solid #f3ddaf}.alert-critical{background:#fff1f1;color:#c65857;border:1px solid #f3c9c7}.alert-icon,.alert-count{line-height:1}.alert-content,.alert-content__nodes{display:inline-flex;align-items:center;gap:4px}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: PraxisRichContent, selector: "praxis-rich-content", inputs: ["document", "nodes", "context", "hostCapabilities", "rootClassName"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1111
1145
  }
1112
1146
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: ExecutiveAlertsComponent, decorators: [{
1113
1147
  type: Component,
1114
- args: [{ selector: 'praxis-executive-alerts', standalone: true, imports: [CommonModule], changeDetection: ChangeDetectionStrategy.OnPush, template: `
1148
+ args: [{ selector: 'praxis-executive-alerts', standalone: true, imports: [CommonModule, PraxisRichContent], changeDetection: ChangeDetectionStrategy.OnPush, template: `
1115
1149
  @if (validAlerts.length > 0) {
1116
1150
  <div
1117
1151
  class="alerts-container"
@@ -1127,18 +1161,18 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImpo
1127
1161
  [attr.aria-label]="getAlertAriaLabel(alert)"
1128
1162
  tabindex="0"
1129
1163
  >
1130
- <span class="alert-icon" aria-hidden="true">
1131
- {{ alert.type === 'warning' ? '△' : '●' }}
1132
- </span>
1133
- <span class="alert-count" aria-hidden="true">
1134
- {{ alert.count }}
1164
+ <span class="alert-content" aria-hidden="true">
1165
+ <praxis-rich-content
1166
+ rootClassName="alert-content__nodes"
1167
+ [nodes]="alertContentNodes(alert)"
1168
+ ></praxis-rich-content>
1135
1169
  </span>
1136
1170
  <span class="sr-only">{{ getAlertDescription(alert) }}</span>
1137
1171
  </span>
1138
1172
  }
1139
1173
  </div>
1140
1174
  }
1141
- `, styles: [".alerts-container{display:inline-flex;gap:6px}.alert{display:inline-flex;align-items:center;gap:4px;padding:0 7px;border-radius:999px;font-size:.72rem;font-weight:700;min-width:28px;height:20px;justify-content:center;cursor:help;transition:all .2s ease}.alert:hover,.alert:focus{transform:scale(1.05);box-shadow:0 2px 4px #0000001a;outline:2px solid currentColor;outline-offset:2px}.alert-warning{background:#fff7e8;color:#bf8422;border:1px solid #f3ddaf}.alert-critical{background:#fff1f1;color:#c65857;border:1px solid #f3c9c7}.alert-icon,.alert-count{line-height:1}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}\n"] }]
1175
+ `, styles: [".alerts-container{display:inline-flex;gap:6px}.alert{display:inline-flex;align-items:center;gap:4px;padding:0 7px;border-radius:999px;font-size:.72rem;font-weight:700;min-width:28px;height:20px;justify-content:center;cursor:help;transition:all .2s ease}.alert:hover,.alert:focus{transform:scale(1.05);box-shadow:0 2px 4px #0000001a;outline:2px solid currentColor;outline-offset:2px}.alert-warning{background:#fff7e8;color:#bf8422;border:1px solid #f3ddaf}.alert-critical{background:#fff1f1;color:#c65857;border:1px solid #f3c9c7}.alert-icon,.alert-count{line-height:1}.alert-content,.alert-content__nodes{display:inline-flex;align-items:center;gap:4px}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}\n"] }]
1142
1176
  }], propDecorators: { alerts: [{
1143
1177
  type: Input
1144
1178
  }] } });
@@ -1147,19 +1181,18 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImpo
1147
1181
  * Executive owner component displaying account owner with accessible avatar.
1148
1182
  *
1149
1183
  * This component replaces legacy HTML string-based owner displays with a
1150
- * fully accessible, WCAG 2.1 AA compliant solution featuring an inline SVG avatar.
1184
+ * fully accessible, WCAG 2.1 AA compliant solution backed by shared rich content primitives.
1151
1185
  *
1152
1186
  * @remarks
1153
1187
  * **Accessibility Features:**
1154
- * - WCAG 1.1.1: Non-text content has text alternative (SVG with role and aria-label)
1155
- * - SVG includes <title> element for tooltips
1188
+ * - WCAG 1.1.1: Non-text content has text alternative through avatar labeling
1156
1189
  * - Handles empty/undefined names gracefully
1157
1190
  * - Screen reader announces owner information clearly
1158
1191
  *
1159
1192
  * **Performance:**
1160
1193
  * - OnPush change detection strategy
1161
1194
  * - Input validation for name
1162
- * - Lightweight inline SVG (no external dependencies)
1195
+ * - Shared avatar/text rendering through `PraxisRichContent`
1163
1196
  *
1164
1197
  * @example Basic usage
1165
1198
  * ```html
@@ -1203,64 +1236,40 @@ class ExecutiveOwnerComponent {
1203
1236
  get displayName() {
1204
1237
  return this._name || 'Unassigned';
1205
1238
  }
1206
- /**
1207
- * ARIA label for SVG avatar.
1208
- * Provides context for screen readers.
1209
- */
1210
- get avatarAriaLabel() {
1211
- return this._name
1212
- ? `Avatar for ${this._name}`
1213
- : 'Unassigned user avatar';
1214
- }
1215
- /**
1216
- * SVG title element content for tooltip.
1217
- * Shows on hover in most browsers.
1218
- */
1219
- get avatarTitle() {
1220
- return this._name
1221
- ? `${this._name}'s avatar`
1222
- : 'User avatar';
1239
+ get ownerNodes() {
1240
+ return [
1241
+ {
1242
+ type: 'avatar',
1243
+ name: this.displayName,
1244
+ className: 'owner__avatar',
1245
+ },
1246
+ {
1247
+ type: 'text',
1248
+ text: this.displayName,
1249
+ className: 'owner__name',
1250
+ },
1251
+ ];
1223
1252
  }
1224
1253
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: ExecutiveOwnerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1225
1254
  static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.17", type: ExecutiveOwnerComponent, isStandalone: true, selector: "praxis-executive-owner", inputs: { name: "name" }, ngImport: i0, template: `
1226
1255
  <div class="owner">
1227
- <svg
1228
- class="avatar"
1229
- width="26"
1230
- height="26"
1231
- viewBox="0 0 26 26"
1232
- role="img"
1233
- [attr.aria-label]="avatarAriaLabel"
1234
- >
1235
- <title>{{ avatarTitle }}</title>
1236
- <circle cx="13" cy="13" r="13" fill="#eef2f6" stroke="#dfe6ed" stroke-width="1.5"/>
1237
- <circle cx="13" cy="9" r="3.5" fill="#8a9fb5"/>
1238
- <circle cx="13" cy="20" r="5.5" fill="#8a9fb5"/>
1239
- </svg>
1240
- <span class="name">{{ displayName }}</span>
1256
+ <praxis-rich-content
1257
+ rootClassName="owner__content"
1258
+ [nodes]="ownerNodes"
1259
+ ></praxis-rich-content>
1241
1260
  </div>
1242
- `, isInline: true, styles: [".owner{display:inline-flex;align-items:center;gap:8px;font-size:.82rem;color:#5f7289;font-weight:500}.avatar{flex-shrink:0}.name{white-space:nowrap}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1261
+ `, isInline: true, styles: [".owner{display:inline-flex;align-items:center;font-size:.82rem;color:#5f7289;font-weight:500}.owner__content{display:inline-flex;align-items:center;gap:8px}.owner__avatar{flex-shrink:0}.owner__name{white-space:nowrap}\n"], dependencies: [{ kind: "component", type: PraxisRichContent, selector: "praxis-rich-content", inputs: ["document", "nodes", "context", "hostCapabilities", "rootClassName"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1243
1262
  }
1244
1263
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: ExecutiveOwnerComponent, decorators: [{
1245
1264
  type: Component,
1246
- args: [{ selector: 'praxis-executive-owner', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, template: `
1265
+ args: [{ selector: 'praxis-executive-owner', standalone: true, imports: [PraxisRichContent], changeDetection: ChangeDetectionStrategy.OnPush, template: `
1247
1266
  <div class="owner">
1248
- <svg
1249
- class="avatar"
1250
- width="26"
1251
- height="26"
1252
- viewBox="0 0 26 26"
1253
- role="img"
1254
- [attr.aria-label]="avatarAriaLabel"
1255
- >
1256
- <title>{{ avatarTitle }}</title>
1257
- <circle cx="13" cy="13" r="13" fill="#eef2f6" stroke="#dfe6ed" stroke-width="1.5"/>
1258
- <circle cx="13" cy="9" r="3.5" fill="#8a9fb5"/>
1259
- <circle cx="13" cy="20" r="5.5" fill="#8a9fb5"/>
1260
- </svg>
1261
- <span class="name">{{ displayName }}</span>
1267
+ <praxis-rich-content
1268
+ rootClassName="owner__content"
1269
+ [nodes]="ownerNodes"
1270
+ ></praxis-rich-content>
1262
1271
  </div>
1263
- `, styles: [".owner{display:inline-flex;align-items:center;gap:8px;font-size:.82rem;color:#5f7289;font-weight:500}.avatar{flex-shrink:0}.name{white-space:nowrap}\n"] }]
1272
+ `, styles: [".owner{display:inline-flex;align-items:center;font-size:.82rem;color:#5f7289;font-weight:500}.owner__content{display:inline-flex;align-items:center;gap:8px}.owner__avatar{flex-shrink:0}.owner__name{white-space:nowrap}\n"] }]
1264
1273
  }], propDecorators: { name: [{
1265
1274
  type: Input
1266
1275
  }] } });
@@ -1309,6 +1318,97 @@ class PraxisListSkinPreviewComponent {
1309
1318
  secondary = (item) => this.evalSlot('secondary', item);
1310
1319
  meta = (item) => this.evalSlot('meta', item);
1311
1320
  trailing = (item) => this.evalSlot('trailing', item);
1321
+ previewRichContentNodes(node, options) {
1322
+ if (!node || typeof node !== 'object')
1323
+ return null;
1324
+ const type = String(node.type || 'text').trim();
1325
+ switch (type) {
1326
+ case 'icon':
1327
+ if (!String(node.value || '').trim() || this.isThemeColor(node.color)) {
1328
+ return null;
1329
+ }
1330
+ return [
1331
+ {
1332
+ type: 'icon',
1333
+ icon: String(node.value),
1334
+ className: node.class,
1335
+ style: this.mergeStyleRecords(this.parseInlineStyle(node.style), this.parseInlineStyle(this.iconStyle(node.color))),
1336
+ },
1337
+ ];
1338
+ case 'image':
1339
+ if (!String(node.value || '').trim() || node.badge?.value) {
1340
+ return null;
1341
+ }
1342
+ return [
1343
+ {
1344
+ type: 'image',
1345
+ src: String(node.value),
1346
+ alt: String(node.imageAlt || options?.imageAlt || ''),
1347
+ className: node.class,
1348
+ style: this.parseInlineStyle(node.style),
1349
+ },
1350
+ ];
1351
+ case 'chip':
1352
+ if (this.isThemeColor(node.color))
1353
+ return null;
1354
+ return [
1355
+ {
1356
+ type: 'badge',
1357
+ label: String(node.value ?? ''),
1358
+ className: [node.class, (node.variant || 'filled') === 'outlined' ? 'chip-outlined' : '']
1359
+ .filter(Boolean)
1360
+ .join(' '),
1361
+ style: this.mergeStyleRecords(this.parseInlineStyle(this.chipStyle(node.color, node.variant)), this.parseInlineStyle(node.style)),
1362
+ },
1363
+ ];
1364
+ case 'text':
1365
+ if (options?.slot === 'meta' && this.metaPrefixIcon()) {
1366
+ return null;
1367
+ }
1368
+ return [
1369
+ {
1370
+ type: 'text',
1371
+ text: String(node.value ?? ''),
1372
+ className: node.class,
1373
+ style: this.parseInlineStyle(node.style),
1374
+ },
1375
+ ];
1376
+ default:
1377
+ return null;
1378
+ }
1379
+ }
1380
+ previewFeatureRichContentNodes(item, feature) {
1381
+ if (!feature)
1382
+ return null;
1383
+ const mode = this.featuresMode();
1384
+ const label = this.featureLabel(item, feature.expr).trim();
1385
+ const nodes = [];
1386
+ const icon = String(feature.icon || '').trim();
1387
+ if (icon && mode !== 'labels-only') {
1388
+ nodes.push({
1389
+ type: 'icon',
1390
+ icon,
1391
+ });
1392
+ }
1393
+ if (mode !== 'icons-only' && label) {
1394
+ nodes.push({
1395
+ type: 'text',
1396
+ text: label,
1397
+ className: feature.class,
1398
+ style: this.parseInlineStyle(feature.style),
1399
+ });
1400
+ }
1401
+ if (!nodes.length)
1402
+ return null;
1403
+ if (nodes.length === 1)
1404
+ return [nodes[0]];
1405
+ return [{
1406
+ type: 'compose',
1407
+ direction: 'row',
1408
+ gap: 'sm',
1409
+ items: nodes,
1410
+ }];
1411
+ }
1312
1412
  featureLabel(item, expr) {
1313
1413
  // simple replacement using the same evaluator used internally
1314
1414
  return String(expr || '').replace(/\$\{([^}]+)\}/g, (_, path) => {
@@ -1411,7 +1511,7 @@ class PraxisListSkinPreviewComponent {
1411
1511
  .toLowerCase();
1412
1512
  if (!t)
1413
1513
  return '';
1414
- return t.replace(/\b\w/g, (m) => m.toUpperCase());
1514
+ return toTitleCase(t);
1415
1515
  }
1416
1516
  catch {
1417
1517
  return String(v ?? '');
@@ -1449,6 +1549,31 @@ class PraxisListSkinPreviewComponent {
1449
1549
  return '';
1450
1550
  return `color:${color};`;
1451
1551
  }
1552
+ parseInlineStyle(style) {
1553
+ const cssText = String(style || '').trim();
1554
+ if (!cssText)
1555
+ return undefined;
1556
+ const entries = cssText
1557
+ .split(';')
1558
+ .map((part) => part.trim())
1559
+ .filter(Boolean)
1560
+ .map((part) => {
1561
+ const separatorIndex = part.indexOf(':');
1562
+ if (separatorIndex === -1)
1563
+ return null;
1564
+ const key = part.slice(0, separatorIndex).trim();
1565
+ const value = part.slice(separatorIndex + 1).trim();
1566
+ if (!key || !value)
1567
+ return null;
1568
+ return [key, value];
1569
+ })
1570
+ .filter((entry) => entry != null);
1571
+ return entries.length ? Object.fromEntries(entries) : undefined;
1572
+ }
1573
+ mergeStyleRecords(...records) {
1574
+ const merged = Object.assign({}, ...records.filter(Boolean));
1575
+ return Object.keys(merged).length ? merged : undefined;
1576
+ }
1452
1577
  ratingMax(def) {
1453
1578
  const max = Number(def?.props?.rating?.max ?? 5);
1454
1579
  if (!Number.isFinite(max))
@@ -1477,11 +1602,18 @@ class PraxisListSkinPreviewComponent {
1477
1602
  // trackBy for preview lists
1478
1603
  trackByIndex = (i) => i;
1479
1604
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: PraxisListSkinPreviewComponent, deps: [{ token: ListSkinService }], target: i0.ɵɵFactoryTarget.Component });
1480
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.17", type: PraxisListSkinPreviewComponent, isStandalone: true, selector: "praxis-list-skin-preview", inputs: { config: "config", items: "items", theme: "theme" }, ngImport: i0, template: "<div class=\"preview-root\" [ngClass]=\"skinClasses\" [attr.data-skin-scope]=\"skinScopeId\">\n @if (inlineCss) { <style [attr.nonce]=\"cspNonce || null\" [textContent]=\"inlineCss\"></style> }\n\n @if (isList()) {\n <mat-list>\n @for (item of items; track trackByIndex($index)) {\n <mat-list-item>\n <div class=\"list-item-content\">\n @if (leading(item); as lead) {\n @switch (lead.type) {\n @case ('icon') { <mat-icon [praxisIcon]=\"lead.value\" [ngClass]=\"lead.class\" [color]=\"isThemeColor(lead.color) ? lead.color : undefined\" [style.cssText]=\"(lead.style ? lead.style + ';' : '') + iconStyle(lead.color)\"></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\"\n [color]=\"isThemeColor(lead.badge?.color) ? lead.badge?.color : undefined\"\n [ngClass]=\"(((lead.badge?.variant || 'filled') === 'outlined') ? 'chip-outlined' : '')\"\n [style.cssText]=\"chipStyle(lead.badge?.color, lead.badge?.variant)\">{{ lead.badge?.value }}</mat-chip> }\n </div>\n }\n @case ('text') { <span [ngClass]=\"lead.class\" [style.cssText]=\"lead.style\">{{ lead.value }}</span> }\n @case ('chip') { <mat-chip [color]=\"isThemeColor(lead.color) ? lead.color : undefined\" [ngClass]=\"((lead.variant || 'filled') === 'outlined') ? 'chip-outlined' : ''\" [style.cssText]=\"chipStyle(lead.color, lead.variant)\">{{ lead.value }}</mat-chip> }\n @case ('rating') { @for (_ of ratingRange(lead); track $index; let idx = $index) { <mat-icon [praxisIcon]=\"starIcon(idx, lead.value)\" [color]=\"ratingThemeColor(lead)\" [style.cssText]=\"ratingIconStyle(lead)\"></mat-icon> } }\n @case ('html') { <span [ngClass]=\"lead.class\" [style.cssText]=\"lead.style\" [innerHTML]=\"lead.value\"></span> }\n @default { <span [ngClass]=\"lead.class\" [style.cssText]=\"lead.style\">{{ lead.value }}</span> }\n }\n }\n <div>\n <div class=\"primary\" [ngClass]=\"primary(item)?.class\" [style.cssText]=\"primary(item)?.style\">{{ primary(item)?.value }}</div>\n @if ((config.layout?.lines || 1) > 1) { <div class=\"secondary\" [ngClass]=\"secondary(item)?.class\" [style.cssText]=\"secondary(item)?.style\">{{ secondary(item)?.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 [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 (meta(item); as m) {\n <div class=\"meta\" [ngClass]=\"m.class\" [style.cssText]=\"m.style\">\n @if (metaPrefixIcon(); as mpi) { <mat-icon [praxisIcon]=\"mpi\"></mat-icon> }\n @switch (m.type) {\n @case ('chip') { <mat-chip [color]=\"isThemeColor(m.color) ? m.color : undefined\" [ngClass]=\"((m.variant || 'filled') === 'outlined') ? 'chip-outlined' : ''\" [style.cssText]=\"chipStyle(m.color, m.variant)\">{{ m.value }}</mat-chip> }\n @case ('rating') { @for (_ of ratingRange(m); track $index; let idx = $index) { <mat-icon [praxisIcon]=\"starIcon(idx, m.value)\" [color]=\"ratingThemeColor(m)\" [style.cssText]=\"ratingIconStyle(m)\"></mat-icon> } }\n @case ('icon') { <mat-icon [praxisIcon]=\"m.value\" [color]=\"isThemeColor(m.color) ? m.color : undefined\" [style.cssText]=\"iconStyle(m.color)\"></mat-icon> }\n @case ('image') { <span class=\"inline-image\"><img [src]=\"m.value\" [alt]=\"m.imageAlt || ''\" /></span> }\n @case ('html') { <span [innerHTML]=\"m.value\"></span> }\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 [color]=\"isThemeColor(tr.color) ? tr.color : undefined\" [ngClass]=\"((tr.variant || 'filled') === 'outlined') ? 'chip-outlined' : ''\" [style.cssText]=\"chipStyle(tr.color, tr.variant)\">{{ tr.value }}</mat-chip> }\n @case ('icon') { <mat-icon [praxisIcon]=\"tr.value\" [color]=\"isThemeColor(tr.color) ? tr.color : undefined\" [style.cssText]=\"iconStyle(tr.color)\"></mat-icon> }\n @case ('image') { <span class=\"inline-image\"><img [src]=\"tr.value\" [alt]=\"tr.imageAlt || ''\" /></span> }\n @case ('rating') { @for (_ of ratingRange(tr); track $index; let idx = $index) { <mat-icon [praxisIcon]=\"starIcon(idx, tr.value)\" [color]=\"ratingThemeColor(tr)\" [style.cssText]=\"ratingIconStyle(tr)\"></mat-icon> } }\n @case ('html') { <span [innerHTML]=\"tr.value\"></span> }\n @default { <span>{{ tr.value }}</span> }\n }\n </div>\n }\n </div>\n </mat-list-item>\n }\n </mat-list>\n } @else if (isTiles()) {\n <div class=\"tiles-grid\">\n @for (it of items; track trackByIndex($index)) {\n <div class=\"item-tile\">\n <div class=\"tile-media\">\n @if (leading(it); as lead) {\n @switch (lead.type) {\n @case ('image') {\n <img [src]=\"lead.value\" [alt]=\"config.templating?.leading?.imageAlt || ''\" />\n }\n @case ('icon') { <mat-icon [praxisIcon]=\"lead.value\" [ngClass]=\"lead.class\" [color]=\"isThemeColor(lead.color) ? lead.color : undefined\" [style.cssText]=\"(lead.style ? lead.style + ';' : '') + iconStyle(lead.color)\"></mat-icon> }\n @case ('text') { <span [ngClass]=\"lead.class\" [style.cssText]=\"lead.style\">{{ lead.value }}</span> }\n @case ('chip') { <mat-chip [color]=\"isThemeColor(lead.color) ? lead.color : undefined\" [ngClass]=\"((lead.variant || 'filled') === 'outlined') ? 'chip-outlined' : ''\" [style.cssText]=\"chipStyle(lead.color, lead.variant)\">{{ lead.value }}</mat-chip> }\n @case ('rating') { @for (_ of ratingRange(lead); track $index; let idx = $index) { <mat-icon [praxisIcon]=\"starIcon(idx, lead.value)\" [color]=\"ratingThemeColor(lead)\" [style.cssText]=\"ratingIconStyle(lead)\"></mat-icon> } }\n @case ('html') { <span [ngClass]=\"lead.class\" [style.cssText]=\"lead.style\" [innerHTML]=\"lead.value\"></span> }\n @default { <span [ngClass]=\"lead.class\" [style.cssText]=\"lead.style\">{{ lead.value }}</span> }\n }\n }\n </div>\n @if (trailing(it); as tr) {\n @if (statusPosition() === 'top-right' && (tr?.type === 'chip' || tr?.type === 'icon')) {\n <div class=\"tile-status\">\n @if (tr?.type === 'chip') { <mat-chip [color]=\"isThemeColor(tr.color) ? tr.color : undefined\" [ngClass]=\"((tr.variant || 'filled') === 'outlined') ? 'chip-outlined' : ''\" [style.cssText]=\"chipStyle(tr.color, tr.variant)\">{{ tr.value }}</mat-chip> }\n @if (tr?.type === 'icon') { <mat-icon [praxisIcon]=\"tr.value\" [color]=\"isThemeColor(tr.color) ? tr.color : undefined\" [style.cssText]=\"iconStyle(tr.color)\"></mat-icon> }\n </div>\n }\n }\n <div class=\"tile-body\">\n <div class=\"primary\" [ngClass]=\"primary(it)?.class\" [style.cssText]=\"primary(it)?.style\">{{ primary(it)?.value }}</div>\n @if ((config.layout?.lines || 1) > 1) { <div class=\"secondary\" [ngClass]=\"secondary(it)?.class\" [style.cssText]=\"secondary(it)?.style\">{{ secondary(it)?.value }}</div> }\n @if (meta(it); as m) {\n <div class=\"meta\" [ngClass]=\"m.class\" [style.cssText]=\"m.style\">\n @if (metaPrefixIcon(); as mpi) { <mat-icon [praxisIcon]=\"mpi\"></mat-icon> }\n @switch (m.type) {\n @case ('chip') { <mat-chip [color]=\"isThemeColor(m.color) ? m.color : undefined\" [ngClass]=\"((m.variant || 'filled') === 'outlined') ? 'chip-outlined' : ''\" [style.cssText]=\"chipStyle(m.color, m.variant)\">{{ m.value }}</mat-chip> }\n @case ('rating') { @for (_ of ratingRange(m); track $index; let idx = $index) { <mat-icon [praxisIcon]=\"starIcon(idx, m.value)\" [color]=\"ratingThemeColor(m)\" [style.cssText]=\"ratingIconStyle(m)\"></mat-icon> } }\n @case ('icon') { <mat-icon [praxisIcon]=\"m.value\" [color]=\"isThemeColor(m.color) ? m.color : undefined\" [style.cssText]=\"iconStyle(m.color)\"></mat-icon> }\n @case ('image') { <span class=\"inline-image\"><img [src]=\"m.value\" [alt]=\"m.imageAlt || ''\" /></span> }\n @case ('html') { <span [innerHTML]=\"m.value\"></span> }\n @default { <span>{{ m.value }}</span> }\n }\n </div>\n }\n @if (featuresVisible()) {\n <div class=\"features\">\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(it, f.expr) }}</span> }\n </span>\n }\n </div>\n }\n @if (trailing(it); as tr2) {\n @if (!(statusPosition() === 'top-right' && (tr2?.type === 'chip' || tr2?.type === 'icon'))) {\n <div class=\"meta\" [ngClass]=\"tr2.class\" [style.cssText]=\"tr2.style\">\n @switch (tr2.type) {\n @case ('chip') { <mat-chip [color]=\"isThemeColor(tr2.color) ? tr2.color : undefined\" [ngClass]=\"((tr2.variant || 'filled') === 'outlined') ? 'chip-outlined' : ''\" [style.cssText]=\"chipStyle(tr2.color, tr2.variant)\">{{ tr2.value }}</mat-chip> }\n @case ('rating') { @for (_ of ratingRange(tr2); track $index; let idx = $index) { <mat-icon [praxisIcon]=\"starIcon(idx, tr2.value)\" [color]=\"ratingThemeColor(tr2)\" [style.cssText]=\"ratingIconStyle(tr2)\"></mat-icon> } }\n @case ('image') { <span class=\"inline-image\"><img [src]=\"tr2.value\" [alt]=\"tr2.imageAlt || ''\" /></span> }\n @case ('html') { <span [innerHTML]=\"tr2.value\"></span> }\n @default { <span>{{ tr2.value }}</span> }\n }\n </div>\n }\n }\n </div>\n </div>\n }\n </div>\n } @else {\n <div class=\"cards-grid\">\n @for (it of items; track trackByIndex($index)) {\n <div class=\"item-card\">\n <div class=\"list-item-content\">\n @if (leading(it); as lead) {\n @switch (lead.type) {\n @case ('icon') { <mat-icon [praxisIcon]=\"lead.value\" [ngClass]=\"lead.class\" [color]=\"isThemeColor(lead.color) ? lead.color : undefined\" [style.cssText]=\"(lead.style ? lead.style + ';' : '') + iconStyle(lead.color)\"></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\"\n [color]=\"isThemeColor(lead.badge?.color) ? lead.badge?.color : undefined\"\n [ngClass]=\"(((lead.badge?.variant || 'filled') === 'outlined') ? 'chip-outlined' : '')\"\n [style.cssText]=\"chipStyle(lead.badge?.color, lead.badge?.variant)\">{{ lead.badge?.value }}</mat-chip> }\n </div>\n }\n @case ('text') { <span [ngClass]=\"lead.class\" [style.cssText]=\"lead.style\">{{ lead.value }}</span> }\n @case ('chip') { <mat-chip [color]=\"isThemeColor(lead.color) ? lead.color : undefined\" [ngClass]=\"((lead.variant || 'filled') === 'outlined') ? 'chip-outlined' : ''\" [style.cssText]=\"chipStyle(lead.color, lead.variant)\">{{ lead.value }}</mat-chip> }\n @case ('rating') { @for (_ of ratingRange(lead); track $index; let idx = $index) { <mat-icon [praxisIcon]=\"starIcon(idx, lead.value)\" [color]=\"ratingThemeColor(lead)\" [style.cssText]=\"ratingIconStyle(lead)\"></mat-icon> } }\n @case ('html') { <span [ngClass]=\"lead.class\" [style.cssText]=\"lead.style\" [innerHTML]=\"lead.value\"></span> }\n @default { <span [ngClass]=\"lead.class\" [style.cssText]=\"lead.style\">{{ lead.value }}</span> }\n }\n }\n <div>\n <div class=\"primary\" [ngClass]=\"primary(it)?.class\" [style.cssText]=\"primary(it)?.style\">{{ primary(it)?.value }}</div>\n @if ((config.layout?.lines || 1) > 1) { <div class=\"secondary\" [ngClass]=\"secondary(it)?.class\" [style.cssText]=\"secondary(it)?.style\">{{ secondary(it)?.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 [praxisIcon]=\"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 (meta(it); as m) {\n <div class=\"meta\" [ngClass]=\"m.class\" [style.cssText]=\"m.style\">\n @if (metaPrefixIcon(); as mpi) { <mat-icon [praxisIcon]=\"mpi\"></mat-icon> }\n @switch (m.type) {\n @case ('chip') { <mat-chip [color]=\"isThemeColor(m.color) ? m.color : undefined\" [ngClass]=\"((m.variant || 'filled') === 'outlined') ? 'chip-outlined' : ''\" [style.cssText]=\"chipStyle(m.color, m.variant)\">{{ m.value }}</mat-chip> }\n @case ('rating') { @for (_ of ratingRange(m); track $index; let idx = $index) { <mat-icon [praxisIcon]=\"starIcon(idx, m.value)\" [color]=\"ratingThemeColor(m)\" [style.cssText]=\"ratingIconStyle(m)\"></mat-icon> } }\n @case ('icon') { <mat-icon [praxisIcon]=\"m.value\" [color]=\"isThemeColor(m.color) ? m.color : undefined\" [style.cssText]=\"iconStyle(m.color)\"></mat-icon> }\n @case ('image') { <span class=\"inline-image\"><img [src]=\"m.value\" [alt]=\"m.imageAlt || ''\" /></span> }\n @case ('html') { <span [innerHTML]=\"m.value\"></span> }\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]=\"isThemeColor(tr.color) ? tr.color : undefined\" [ngClass]=\"((tr.variant || 'filled') === 'outlined') ? 'chip-outlined' : ''\" [style.cssText]=\"chipStyle(tr.color, tr.variant)\">{{ tr.value }}</mat-chip> }\n @case ('icon') { <mat-icon [praxisIcon]=\"tr.value\" [color]=\"isThemeColor(tr.color) ? tr.color : undefined\" [style.cssText]=\"iconStyle(tr.color)\"></mat-icon> }\n @case ('image') { <span class=\"inline-image\"><img [src]=\"tr.value\" [alt]=\"tr.imageAlt || ''\" /></span> }\n @case ('rating') { @for (_ of ratingRange(tr); track $index; let idx = $index) { <mat-icon [praxisIcon]=\"starIcon(idx, tr.value)\" [color]=\"ratingThemeColor(tr)\" [style.cssText]=\"ratingIconStyle(tr)\"></mat-icon> } }\n @case ('html') { <span [innerHTML]=\"tr.value\"></span> }\n @default { <span>{{ tr.value }}</span> }\n }\n </div>\n }\n </div>\n </div>\n }\n </div>\n }\n</div>\n", styles: [".preview-root{--p-list-radius: var(--md-sys-shape-corner-medium, 16px);--p-list-shadow: var(--md-sys-elevation-level2);--p-list-border: 1px solid var(--md-sys-color-outline-variant);--p-list-blur: 10px;--p-list-foreground: var(--md-sys-color-on-surface);--p-list-foreground-muted: var(--md-sys-color-on-surface-variant);--p-list-grad-foreground: var(--md-sys-color-on-primary);--p-list-grad-foreground-muted: var(--md-sys-color-on-primary);--p-list-surface: var(--md-sys-color-surface-container);--p-list-accent: var(--md-sys-color-primary);--p-list-item-border: 1px solid var(--md-sys-color-outline-variant);--p-list-grad-from: var(--md-sys-color-primary-container);--p-list-grad-to: var(--md-sys-color-tertiary-container);--p-list-grad-angle: 135deg;--p-list-tile-minW: 240px;--p-list-tile-gap: 16px;--p-list-tile-padding: 16px;--p-list-tile-radius: 16px;--p-list-tile-media-radius: 12px;--p-list-tile-media-ratio: 1 / 1;padding:12px}.preview-light{background:var(--md-sys-color-surface-container-low, var(--md-sys-color-surface))}.preview-dark{background:var(--md-sys-color-surface-container-lowest, var(--md-sys-color-surface))}.preview-grid{background-color:var(--md-sys-color-surface-variant, var(--md-sys-color-surface));background-image:linear-gradient(var(--md-sys-color-outline-variant, var(--md-sys-color-outline)) 1px,transparent 1px),linear-gradient(90deg,var(--md-sys-color-outline-variant, var(--md-sys-color-outline)) 1px,transparent 1px);background-size:16px 16px}.skin-elevated,.skin-outline,.skin-flat,.skin-neumorphism{--p-list-item-surface: var(--mdc-elevated-card-container-color, var(--p-list-surface));--p-list-item-border: var(--p-list-border)}.skin-elevated .item-card,.skin-outline .item-card,.skin-flat .item-card,.skin-neumorphism .item-card{background:var(--mdc-elevated-card-container-color, var(--p-list-surface));border-radius:var(--p-list-radius);box-shadow:var(--p-list-shadow);border:var(--p-list-border)}.skin-elevated .item-tile,.skin-outline .item-tile,.skin-flat .item-tile,.skin-neumorphism .item-tile{background:var(--mdc-elevated-card-container-color, var(--p-list-surface));box-shadow:var(--p-list-shadow);border:var(--p-list-border)}.skin-elevated .mat-mdc-list-item .list-item-content,.skin-outline .mat-mdc-list-item .list-item-content,.skin-flat .mat-mdc-list-item .list-item-content,.skin-neumorphism .mat-mdc-list-item .list-item-content{background:var(--mdc-elevated-card-container-color, var(--p-list-surface));border-radius:calc(var(--p-list-radius) * .75);box-shadow:var(--p-list-shadow);border:var(--p-list-item-border);color:var(--p-list-foreground)}.skin-outline{--p-list-shadow: none;--p-list-border: 1px solid var(--md-sys-color-outline)}.skin-flat{--p-list-shadow: none;--p-list-border: 1px solid var(--md-sys-color-outline-variant)}.skin-neumorphism{--p-list-shadow: var(--md-sys-elevation-level2);--p-list-border: 1px solid var(--md-sys-color-outline-variant);--p-list-radius: 1.25rem}.skin-pill-soft .item-card,.skin-pill-soft .item-tile{background:var(--mdc-elevated-card-container-color, var(--p-list-surface));border-radius:calc(var(--p-list-radius) * 1.3);box-shadow:var(--md-sys-elevation-level1);border:var(--p-list-border)}.skin-pill-soft .mat-mdc-list-item .list-item-content{background:var(--mdc-elevated-card-container-color, var(--p-list-surface));border-radius:calc(var(--p-list-radius) * 1.3);box-shadow:var(--md-sys-elevation-level1);border:var(--p-list-border);color:var(--p-list-foreground)}.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}.features{display:flex;flex-wrap:wrap;gap:12px;margin-top:6px;color:var(--p-list-foreground-muted)}.feature{display:inline-flex;align-items:center;gap:6px}.model-media .lead-image{width:136px;height:96px;border-radius:16px}.model-hotel .lead-image{width:160px;height:110px;border-radius:18px}.skin-gradient-tile{--p-list-foreground: var(--p-list-grad-foreground);--p-list-foreground-muted: var(--p-list-grad-foreground-muted)}.skin-gradient-tile .item-card,.skin-gradient-tile .item-tile,.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:var(--p-list-foreground)}.skin-glass .item-card,.skin-glass .item-tile{background:var(--md-sys-color-surface-container-low);border-radius:var(--p-list-radius);border:1px solid var(--md-sys-color-outline-variant);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:var(--md-sys-color-surface-container-low);border-radius:var(--p-list-radius);border:1px solid var(--md-sys-color-outline-variant);backdrop-filter:blur(var(--p-list-blur));-webkit-backdrop-filter:blur(var(--p-list-blur));color:var(--p-list-foreground)}.list-item-content{display:grid;grid-template-columns:auto minmax(0,1fr) auto auto;align-items:center;gap:12px;padding:12px 16px}.primary{font-weight:500;color:var(--p-list-foreground)}.secondary,.meta{color:var(--p-list-foreground-muted)}.trailing{color:var(--p-list-foreground-muted);text-align:end}.cards-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(var(--p-list-tile-minW),1fr));gap:var(--p-list-tile-gap)}.item-card{padding:12px}.tiles-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(var(--p-list-tile-minW),1fr));gap:var(--p-list-tile-gap)}.item-tile{padding:var(--p-list-tile-padding);border-radius:var(--p-list-tile-radius);border:var(--p-list-border);background:var(--p-list-surface);display:grid;gap:8px}.tile-media{width:100%;aspect-ratio:var(--p-list-tile-media-ratio);border-radius:var(--p-list-tile-media-radius);background:var(--md-sys-color-surface-container-low, var(--p-list-surface));display:grid;place-items:center;overflow:hidden}.tile-media img{width:100%;height:100%;object-fit:cover}.tile-body{display:grid;gap:4px}.chip-outlined.mat-mdc-chip{background:transparent!important;border:1px solid currentColor}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "ngmodule", type: MatListModule }, { kind: "component", type: i3.MatList, selector: "mat-list", exportAs: ["matList"] }, { kind: "component", type: i3.MatListItem, selector: "mat-list-item, a[mat-list-item], button[mat-list-item]", inputs: ["activated"], exportAs: ["matListItem"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i4.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatChipsModule }, { kind: "component", type: i5.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: "directive", type: PraxisIconDirective, selector: "mat-icon[praxisIcon]", inputs: ["praxisIcon"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1605
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.17", type: PraxisListSkinPreviewComponent, isStandalone: true, selector: "praxis-list-skin-preview", inputs: { config: "config", items: "items", theme: "theme" }, ngImport: i0, template: "<div class=\"preview-root\" [ngClass]=\"skinClasses\" [attr.data-skin-scope]=\"skinScopeId\">\n @if (inlineCss) { <style [attr.nonce]=\"cspNonce || null\" [textContent]=\"inlineCss\"></style> }\n\n @if (isList()) {\n <mat-list>\n @for (item of items; track trackByIndex($index)) {\n <mat-list-item>\n <div class=\"list-item-content\">\n @if (leading(item); as lead) {\n @if (previewRichContentNodes(lead, { imageAlt: config.templating?.leading?.imageAlt }); as leadNodes) {\n <praxis-rich-content [nodes]=\"leadNodes\"></praxis-rich-content>\n } @else {\n @switch (lead.type) {\n @case ('icon') { <mat-icon [praxisIcon]=\"lead.value\" [ngClass]=\"lead.class\" [color]=\"isThemeColor(lead.color) ? lead.color : undefined\" [style.cssText]=\"(lead.style ? lead.style + ';' : '') + iconStyle(lead.color)\"></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\"\n [color]=\"isThemeColor(lead.badge?.color) ? lead.badge?.color : undefined\"\n [ngClass]=\"(((lead.badge?.variant || 'filled') === 'outlined') ? 'chip-outlined' : '')\"\n [style.cssText]=\"chipStyle(lead.badge?.color, lead.badge?.variant)\">{{ lead.badge?.value }}</mat-chip> }\n </div>\n }\n @case ('text') { <span [ngClass]=\"lead.class\" [style.cssText]=\"lead.style\">{{ lead.value }}</span> }\n @case ('chip') { <mat-chip [color]=\"isThemeColor(lead.color) ? lead.color : undefined\" [ngClass]=\"((lead.variant || 'filled') === 'outlined') ? 'chip-outlined' : ''\" [style.cssText]=\"chipStyle(lead.color, lead.variant)\">{{ lead.value }}</mat-chip> }\n @case ('rating') { @for (_ of ratingRange(lead); track $index; let idx = $index) { <mat-icon [praxisIcon]=\"starIcon(idx, lead.value)\" [color]=\"ratingThemeColor(lead)\" [style.cssText]=\"ratingIconStyle(lead)\"></mat-icon> } }\n @case ('html') { <span [ngClass]=\"lead.class\" [style.cssText]=\"lead.style\" [innerHTML]=\"lead.value\"></span> }\n @default { <span [ngClass]=\"lead.class\" [style.cssText]=\"lead.style\">{{ lead.value }}</span> }\n }\n }\n }\n <div>\n <div class=\"primary\" [ngClass]=\"primary(item)?.class\" [style.cssText]=\"primary(item)?.style\">\n @if (previewRichContentNodes(primary(item)); as primaryNodes) {\n <praxis-rich-content [nodes]=\"primaryNodes\"></praxis-rich-content>\n } @else {\n {{ primary(item)?.value }}\n }\n </div>\n @if ((config.layout?.lines || 1) > 1) {\n <div class=\"secondary\" [ngClass]=\"secondary(item)?.class\" [style.cssText]=\"secondary(item)?.style\">\n @if (previewRichContentNodes(secondary(item)); as secondaryNodes) {\n <praxis-rich-content [nodes]=\"secondaryNodes\"></praxis-rich-content>\n } @else {\n {{ secondary(item)?.value }}\n }\n </div>\n }\n @if (featuresVisible()) {\n @for (f of (config.templating?.features || []); track $index; let fi = $index) {\n <span class=\"feature\">\n @if (previewFeatureRichContentNodes(item, f); as featureNodes) {\n <praxis-rich-content [nodes]=\"featureNodes\"></praxis-rich-content>\n } @else {\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 }\n </span>\n }\n }\n </div>\n @if (meta(item); as m) {\n <div class=\"meta\" [ngClass]=\"m.class\" [style.cssText]=\"m.style\">\n @if (metaPrefixIcon(); as mpi) { <mat-icon [praxisIcon]=\"mpi\"></mat-icon> }\n @if (previewRichContentNodes(m, { slot: 'meta' }); as metaNodes) {\n <praxis-rich-content [nodes]=\"metaNodes\"></praxis-rich-content>\n } @else {\n @switch (m.type) {\n @case ('chip') { <mat-chip [color]=\"isThemeColor(m.color) ? m.color : undefined\" [ngClass]=\"((m.variant || 'filled') === 'outlined') ? 'chip-outlined' : ''\" [style.cssText]=\"chipStyle(m.color, m.variant)\">{{ m.value }}</mat-chip> }\n @case ('rating') { @for (_ of ratingRange(m); track $index; let idx = $index) { <mat-icon [praxisIcon]=\"starIcon(idx, m.value)\" [color]=\"ratingThemeColor(m)\" [style.cssText]=\"ratingIconStyle(m)\"></mat-icon> } }\n @case ('icon') { <mat-icon [praxisIcon]=\"m.value\" [color]=\"isThemeColor(m.color) ? m.color : undefined\" [style.cssText]=\"iconStyle(m.color)\"></mat-icon> }\n @case ('image') { <span class=\"inline-image\"><img [src]=\"m.value\" [alt]=\"m.imageAlt || ''\" /></span> }\n @case ('html') { <span [innerHTML]=\"m.value\"></span> }\n @default { <span>{{ m.value }}</span> }\n }\n }\n </div>\n }\n @if (trailing(item); as tr) {\n <div class=\"trailing\" [ngClass]=\"tr.class\" [style.cssText]=\"tr.style\">\n @if (previewRichContentNodes(tr); as trailingNodes) {\n <praxis-rich-content [nodes]=\"trailingNodes\"></praxis-rich-content>\n } @else {\n @switch (tr.type) {\n @case ('chip') { <mat-chip [color]=\"isThemeColor(tr.color) ? tr.color : undefined\" [ngClass]=\"((tr.variant || 'filled') === 'outlined') ? 'chip-outlined' : ''\" [style.cssText]=\"chipStyle(tr.color, tr.variant)\">{{ tr.value }}</mat-chip> }\n @case ('icon') { <mat-icon [praxisIcon]=\"tr.value\" [color]=\"isThemeColor(tr.color) ? tr.color : undefined\" [style.cssText]=\"iconStyle(tr.color)\"></mat-icon> }\n @case ('image') { <span class=\"inline-image\"><img [src]=\"tr.value\" [alt]=\"tr.imageAlt || ''\" /></span> }\n @case ('rating') { @for (_ of ratingRange(tr); track $index; let idx = $index) { <mat-icon [praxisIcon]=\"starIcon(idx, tr.value)\" [color]=\"ratingThemeColor(tr)\" [style.cssText]=\"ratingIconStyle(tr)\"></mat-icon> } }\n @case ('html') { <span [innerHTML]=\"tr.value\"></span> }\n @default { <span>{{ tr.value }}</span> }\n }\n }\n </div>\n }\n </div>\n </mat-list-item>\n }\n </mat-list>\n } @else if (isTiles()) {\n <div class=\"tiles-grid\">\n @for (it of items; track trackByIndex($index)) {\n <div class=\"item-tile\">\n <div class=\"tile-media\">\n @if (leading(it); as lead) {\n @if (previewRichContentNodes(lead, { imageAlt: config.templating?.leading?.imageAlt }); as leadNodes) {\n <praxis-rich-content [nodes]=\"leadNodes\"></praxis-rich-content>\n } @else {\n @switch (lead.type) {\n @case ('image') {\n <img [src]=\"lead.value\" [alt]=\"config.templating?.leading?.imageAlt || ''\" />\n }\n @case ('icon') { <mat-icon [praxisIcon]=\"lead.value\" [ngClass]=\"lead.class\" [color]=\"isThemeColor(lead.color) ? lead.color : undefined\" [style.cssText]=\"(lead.style ? lead.style + ';' : '') + iconStyle(lead.color)\"></mat-icon> }\n @case ('text') { <span [ngClass]=\"lead.class\" [style.cssText]=\"lead.style\">{{ lead.value }}</span> }\n @case ('chip') { <mat-chip [color]=\"isThemeColor(lead.color) ? lead.color : undefined\" [ngClass]=\"((lead.variant || 'filled') === 'outlined') ? 'chip-outlined' : ''\" [style.cssText]=\"chipStyle(lead.color, lead.variant)\">{{ lead.value }}</mat-chip> }\n @case ('rating') { @for (_ of ratingRange(lead); track $index; let idx = $index) { <mat-icon [praxisIcon]=\"starIcon(idx, lead.value)\" [color]=\"ratingThemeColor(lead)\" [style.cssText]=\"ratingIconStyle(lead)\"></mat-icon> } }\n @case ('html') { <span [ngClass]=\"lead.class\" [style.cssText]=\"lead.style\" [innerHTML]=\"lead.value\"></span> }\n @default { <span [ngClass]=\"lead.class\" [style.cssText]=\"lead.style\">{{ lead.value }}</span> }\n }\n }\n }\n </div>\n @if (trailing(it); as tr) {\n @if (statusPosition() === 'top-right' && (tr?.type === 'chip' || tr?.type === 'icon')) {\n <div class=\"tile-status\">\n @if (previewRichContentNodes(tr); as trailingNodes) {\n <praxis-rich-content [nodes]=\"trailingNodes\"></praxis-rich-content>\n } @else {\n @if (tr?.type === 'chip') { <mat-chip [color]=\"isThemeColor(tr.color) ? tr.color : undefined\" [ngClass]=\"((tr.variant || 'filled') === 'outlined') ? 'chip-outlined' : ''\" [style.cssText]=\"chipStyle(tr.color, tr.variant)\">{{ tr.value }}</mat-chip> }\n @if (tr?.type === 'icon') { <mat-icon [praxisIcon]=\"tr.value\" [color]=\"isThemeColor(tr.color) ? tr.color : undefined\" [style.cssText]=\"iconStyle(tr.color)\"></mat-icon> }\n }\n </div>\n }\n }\n <div class=\"tile-body\">\n <div class=\"primary\" [ngClass]=\"primary(it)?.class\" [style.cssText]=\"primary(it)?.style\">\n @if (previewRichContentNodes(primary(it)); as primaryNodes) {\n <praxis-rich-content [nodes]=\"primaryNodes\"></praxis-rich-content>\n } @else {\n {{ primary(it)?.value }}\n }\n </div>\n @if ((config.layout?.lines || 1) > 1) {\n <div class=\"secondary\" [ngClass]=\"secondary(it)?.class\" [style.cssText]=\"secondary(it)?.style\">\n @if (previewRichContentNodes(secondary(it)); as secondaryNodes) {\n <praxis-rich-content [nodes]=\"secondaryNodes\"></praxis-rich-content>\n } @else {\n {{ secondary(it)?.value }}\n }\n </div>\n }\n @if (meta(it); as m) {\n <div class=\"meta\" [ngClass]=\"m.class\" [style.cssText]=\"m.style\">\n @if (metaPrefixIcon(); as mpi) { <mat-icon [praxisIcon]=\"mpi\"></mat-icon> }\n @if (previewRichContentNodes(m, { slot: 'meta' }); as metaNodes) {\n <praxis-rich-content [nodes]=\"metaNodes\"></praxis-rich-content>\n } @else {\n @switch (m.type) {\n @case ('chip') { <mat-chip [color]=\"isThemeColor(m.color) ? m.color : undefined\" [ngClass]=\"((m.variant || 'filled') === 'outlined') ? 'chip-outlined' : ''\" [style.cssText]=\"chipStyle(m.color, m.variant)\">{{ m.value }}</mat-chip> }\n @case ('rating') { @for (_ of ratingRange(m); track $index; let idx = $index) { <mat-icon [praxisIcon]=\"starIcon(idx, m.value)\" [color]=\"ratingThemeColor(m)\" [style.cssText]=\"ratingIconStyle(m)\"></mat-icon> } }\n @case ('icon') { <mat-icon [praxisIcon]=\"m.value\" [color]=\"isThemeColor(m.color) ? m.color : undefined\" [style.cssText]=\"iconStyle(m.color)\"></mat-icon> }\n @case ('image') { <span class=\"inline-image\"><img [src]=\"m.value\" [alt]=\"m.imageAlt || ''\" /></span> }\n @case ('html') { <span [innerHTML]=\"m.value\"></span> }\n @default { <span>{{ m.value }}</span> }\n }\n }\n </div>\n }\n @if (featuresVisible()) {\n <div class=\"features\">\n @for (f of (config.templating?.features || []); track $index; let fi = $index) {\n <span class=\"feature\">\n @if (previewFeatureRichContentNodes(it, f); as featureNodes) {\n <praxis-rich-content [nodes]=\"featureNodes\"></praxis-rich-content>\n } @else {\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(it, f.expr) }}</span> }\n }\n </span>\n }\n </div>\n }\n @if (trailing(it); as tr2) {\n @if (!(statusPosition() === 'top-right' && (tr2?.type === 'chip' || tr2?.type === 'icon'))) {\n <div class=\"meta\" [ngClass]=\"tr2.class\" [style.cssText]=\"tr2.style\">\n @if (previewRichContentNodes(tr2); as trailingNodes) {\n <praxis-rich-content [nodes]=\"trailingNodes\"></praxis-rich-content>\n } @else {\n @switch (tr2.type) {\n @case ('chip') { <mat-chip [color]=\"isThemeColor(tr2.color) ? tr2.color : undefined\" [ngClass]=\"((tr2.variant || 'filled') === 'outlined') ? 'chip-outlined' : ''\" [style.cssText]=\"chipStyle(tr2.color, tr2.variant)\">{{ tr2.value }}</mat-chip> }\n @case ('rating') { @for (_ of ratingRange(tr2); track $index; let idx = $index) { <mat-icon [praxisIcon]=\"starIcon(idx, tr2.value)\" [color]=\"ratingThemeColor(tr2)\" [style.cssText]=\"ratingIconStyle(tr2)\"></mat-icon> } }\n @case ('image') { <span class=\"inline-image\"><img [src]=\"tr2.value\" [alt]=\"tr2.imageAlt || ''\" /></span> }\n @case ('html') { <span [innerHTML]=\"tr2.value\"></span> }\n @default { <span>{{ tr2.value }}</span> }\n }\n }\n </div>\n }\n }\n </div>\n </div>\n }\n </div>\n } @else {\n <div class=\"cards-grid\">\n @for (it of items; track trackByIndex($index)) {\n <div class=\"item-card\">\n <div class=\"list-item-content\">\n @if (leading(it); as lead) {\n @if (previewRichContentNodes(lead, { imageAlt: config.templating?.leading?.imageAlt }); as leadNodes) {\n <praxis-rich-content [nodes]=\"leadNodes\"></praxis-rich-content>\n } @else {\n @switch (lead.type) {\n @case ('icon') { <mat-icon [praxisIcon]=\"lead.value\" [ngClass]=\"lead.class\" [color]=\"isThemeColor(lead.color) ? lead.color : undefined\" [style.cssText]=\"(lead.style ? lead.style + ';' : '') + iconStyle(lead.color)\"></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\"\n [color]=\"isThemeColor(lead.badge?.color) ? lead.badge?.color : undefined\"\n [ngClass]=\"(((lead.badge?.variant || 'filled') === 'outlined') ? 'chip-outlined' : '')\"\n [style.cssText]=\"chipStyle(lead.badge?.color, lead.badge?.variant)\">{{ lead.badge?.value }}</mat-chip> }\n </div>\n }\n @case ('text') { <span [ngClass]=\"lead.class\" [style.cssText]=\"lead.style\">{{ lead.value }}</span> }\n @case ('chip') { <mat-chip [color]=\"isThemeColor(lead.color) ? lead.color : undefined\" [ngClass]=\"((lead.variant || 'filled') === 'outlined') ? 'chip-outlined' : ''\" [style.cssText]=\"chipStyle(lead.color, lead.variant)\">{{ lead.value }}</mat-chip> }\n @case ('rating') { @for (_ of ratingRange(lead); track $index; let idx = $index) { <mat-icon [praxisIcon]=\"starIcon(idx, lead.value)\" [color]=\"ratingThemeColor(lead)\" [style.cssText]=\"ratingIconStyle(lead)\"></mat-icon> } }\n @case ('html') { <span [ngClass]=\"lead.class\" [style.cssText]=\"lead.style\" [innerHTML]=\"lead.value\"></span> }\n @default { <span [ngClass]=\"lead.class\" [style.cssText]=\"lead.style\">{{ lead.value }}</span> }\n }\n }\n }\n <div>\n <div class=\"primary\" [ngClass]=\"primary(it)?.class\" [style.cssText]=\"primary(it)?.style\">\n @if (previewRichContentNodes(primary(it)); as primaryNodes) {\n <praxis-rich-content [nodes]=\"primaryNodes\"></praxis-rich-content>\n } @else {\n {{ primary(it)?.value }}\n }\n </div>\n @if ((config.layout?.lines || 1) > 1) {\n <div class=\"secondary\" [ngClass]=\"secondary(it)?.class\" [style.cssText]=\"secondary(it)?.style\">\n @if (previewRichContentNodes(secondary(it)); as secondaryNodes) {\n <praxis-rich-content [nodes]=\"secondaryNodes\"></praxis-rich-content>\n } @else {\n {{ secondary(it)?.value }}\n }\n </div>\n }\n @if (featuresVisible()) {\n @for (f of (config.templating?.features || []); track $index; let fi = $index) {\n <span class=\"feature\">\n @if (previewFeatureRichContentNodes(it, f); as featureNodes) {\n <praxis-rich-content [nodes]=\"featureNodes\"></praxis-rich-content>\n } @else {\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(it, f.expr) }}</span> }\n }\n </span>\n }\n }\n </div>\n @if (meta(it); as m) {\n <div class=\"meta\" [ngClass]=\"m.class\" [style.cssText]=\"m.style\">\n @if (metaPrefixIcon(); as mpi) { <mat-icon [praxisIcon]=\"mpi\"></mat-icon> }\n @if (previewRichContentNodes(m, { slot: 'meta' }); as metaNodes) {\n <praxis-rich-content [nodes]=\"metaNodes\"></praxis-rich-content>\n } @else {\n @switch (m.type) {\n @case ('chip') { <mat-chip [color]=\"isThemeColor(m.color) ? m.color : undefined\" [ngClass]=\"((m.variant || 'filled') === 'outlined') ? 'chip-outlined' : ''\" [style.cssText]=\"chipStyle(m.color, m.variant)\">{{ m.value }}</mat-chip> }\n @case ('rating') { @for (_ of ratingRange(m); track $index; let idx = $index) { <mat-icon [praxisIcon]=\"starIcon(idx, m.value)\" [color]=\"ratingThemeColor(m)\" [style.cssText]=\"ratingIconStyle(m)\"></mat-icon> } }\n @case ('icon') { <mat-icon [praxisIcon]=\"m.value\" [color]=\"isThemeColor(m.color) ? m.color : undefined\" [style.cssText]=\"iconStyle(m.color)\"></mat-icon> }\n @case ('image') { <span class=\"inline-image\"><img [src]=\"m.value\" [alt]=\"m.imageAlt || ''\" /></span> }\n @case ('html') { <span [innerHTML]=\"m.value\"></span> }\n @default { <span>{{ m.value }}</span> }\n }\n }\n </div>\n }\n @if (trailing(it); as tr) {\n <div class=\"trailing\" [ngClass]=\"tr.class\" [style.cssText]=\"tr.style\">\n @if (previewRichContentNodes(tr); as trailingNodes) {\n <praxis-rich-content [nodes]=\"trailingNodes\"></praxis-rich-content>\n } @else {\n @switch (tr.type) {\n @case ('chip') { <mat-chip [color]=\"isThemeColor(tr.color) ? tr.color : undefined\" [ngClass]=\"((tr.variant || 'filled') === 'outlined') ? 'chip-outlined' : ''\" [style.cssText]=\"chipStyle(tr.color, tr.variant)\">{{ tr.value }}</mat-chip> }\n @case ('icon') { <mat-icon [praxisIcon]=\"tr.value\" [color]=\"isThemeColor(tr.color) ? tr.color : undefined\" [style.cssText]=\"iconStyle(tr.color)\"></mat-icon> }\n @case ('image') { <span class=\"inline-image\"><img [src]=\"tr.value\" [alt]=\"tr.imageAlt || ''\" /></span> }\n @case ('rating') { @for (_ of ratingRange(tr); track $index; let idx = $index) { <mat-icon [praxisIcon]=\"starIcon(idx, tr.value)\" [color]=\"ratingThemeColor(tr)\" [style.cssText]=\"ratingIconStyle(tr)\"></mat-icon> } }\n @case ('html') { <span [innerHTML]=\"tr.value\"></span> }\n @default { <span>{{ tr.value }}</span> }\n }\n }\n </div>\n }\n </div>\n </div>\n }\n </div>\n }\n</div>\n", styles: [".preview-root{--p-list-radius: var(--md-sys-shape-corner-medium, 16px);--p-list-shadow: var(--md-sys-elevation-level2);--p-list-border: 1px solid var(--md-sys-color-outline-variant);--p-list-blur: 10px;--p-list-foreground: var(--md-sys-color-on-surface);--p-list-foreground-muted: var(--md-sys-color-on-surface-variant);--p-list-grad-foreground: var(--md-sys-color-on-primary);--p-list-grad-foreground-muted: var(--md-sys-color-on-primary);--p-list-surface: var(--md-sys-color-surface-container);--p-list-accent: var(--md-sys-color-primary);--p-list-item-border: 1px solid var(--md-sys-color-outline-variant);--p-list-grad-from: var(--md-sys-color-primary-container);--p-list-grad-to: var(--md-sys-color-tertiary-container);--p-list-grad-angle: 135deg;--p-list-tile-minW: 240px;--p-list-tile-gap: 16px;--p-list-tile-padding: 16px;--p-list-tile-radius: 16px;--p-list-tile-media-radius: 12px;--p-list-tile-media-ratio: 1 / 1;padding:12px}.preview-light{background:var(--md-sys-color-surface-container-low, var(--md-sys-color-surface))}.preview-dark{background:var(--md-sys-color-surface-container-lowest, var(--md-sys-color-surface))}.preview-grid{background-color:var(--md-sys-color-surface-variant, var(--md-sys-color-surface));background-image:linear-gradient(var(--md-sys-color-outline-variant, var(--md-sys-color-outline)) 1px,transparent 1px),linear-gradient(90deg,var(--md-sys-color-outline-variant, var(--md-sys-color-outline)) 1px,transparent 1px);background-size:16px 16px}.skin-elevated,.skin-outline,.skin-flat,.skin-neumorphism{--p-list-item-surface: var(--mdc-elevated-card-container-color, var(--p-list-surface));--p-list-item-border: var(--p-list-border)}.skin-elevated .item-card,.skin-outline .item-card,.skin-flat .item-card,.skin-neumorphism .item-card{background:var(--mdc-elevated-card-container-color, var(--p-list-surface));border-radius:var(--p-list-radius);box-shadow:var(--p-list-shadow);border:var(--p-list-border)}.skin-elevated .item-tile,.skin-outline .item-tile,.skin-flat .item-tile,.skin-neumorphism .item-tile{background:var(--mdc-elevated-card-container-color, var(--p-list-surface));box-shadow:var(--p-list-shadow);border:var(--p-list-border)}.skin-elevated .mat-mdc-list-item .list-item-content,.skin-outline .mat-mdc-list-item .list-item-content,.skin-flat .mat-mdc-list-item .list-item-content,.skin-neumorphism .mat-mdc-list-item .list-item-content{background:var(--mdc-elevated-card-container-color, var(--p-list-surface));border-radius:calc(var(--p-list-radius) * .75);box-shadow:var(--p-list-shadow);border:var(--p-list-item-border);color:var(--p-list-foreground)}.skin-outline{--p-list-shadow: none;--p-list-border: 1px solid var(--md-sys-color-outline)}.skin-flat{--p-list-shadow: none;--p-list-border: 1px solid var(--md-sys-color-outline-variant)}.skin-neumorphism{--p-list-shadow: var(--md-sys-elevation-level2);--p-list-border: 1px solid var(--md-sys-color-outline-variant);--p-list-radius: 1.25rem}.skin-pill-soft .item-card,.skin-pill-soft .item-tile{background:var(--mdc-elevated-card-container-color, var(--p-list-surface));border-radius:calc(var(--p-list-radius) * 1.3);box-shadow:var(--md-sys-elevation-level1);border:var(--p-list-border)}.skin-pill-soft .mat-mdc-list-item .list-item-content{background:var(--mdc-elevated-card-container-color, var(--p-list-surface));border-radius:calc(var(--p-list-radius) * 1.3);box-shadow:var(--md-sys-elevation-level1);border:var(--p-list-border);color:var(--p-list-foreground)}.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}.features{display:flex;flex-wrap:wrap;gap:12px;margin-top:6px;color:var(--p-list-foreground-muted)}.feature{display:inline-flex;align-items:center;gap:6px}.model-media .lead-image{width:136px;height:96px;border-radius:16px}.model-hotel .lead-image{width:160px;height:110px;border-radius:18px}.skin-gradient-tile{--p-list-foreground: var(--p-list-grad-foreground);--p-list-foreground-muted: var(--p-list-grad-foreground-muted)}.skin-gradient-tile .item-card,.skin-gradient-tile .item-tile,.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:var(--p-list-foreground)}.skin-glass .item-card,.skin-glass .item-tile{background:var(--md-sys-color-surface-container-low);border-radius:var(--p-list-radius);border:1px solid var(--md-sys-color-outline-variant);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:var(--md-sys-color-surface-container-low);border-radius:var(--p-list-radius);border:1px solid var(--md-sys-color-outline-variant);backdrop-filter:blur(var(--p-list-blur));-webkit-backdrop-filter:blur(var(--p-list-blur));color:var(--p-list-foreground)}.list-item-content{display:grid;grid-template-columns:auto minmax(0,1fr) auto auto;align-items:center;gap:12px;padding:12px 16px}.primary{font-weight:500;color:var(--p-list-foreground)}.secondary,.meta{color:var(--p-list-foreground-muted)}.trailing{color:var(--p-list-foreground-muted);text-align:end}.cards-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(var(--p-list-tile-minW),1fr));gap:var(--p-list-tile-gap)}.item-card{padding:12px}.tiles-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(var(--p-list-tile-minW),1fr));gap:var(--p-list-tile-gap)}.item-tile{padding:var(--p-list-tile-padding);border-radius:var(--p-list-tile-radius);border:var(--p-list-border);background:var(--p-list-surface);display:grid;gap:8px}.tile-media{width:100%;aspect-ratio:var(--p-list-tile-media-ratio);border-radius:var(--p-list-tile-media-radius);background:var(--md-sys-color-surface-container-low, var(--p-list-surface));display:grid;place-items:center;overflow:hidden}.tile-media img{width:100%;height:100%;object-fit:cover}.tile-body{display:grid;gap:4px}.chip-outlined.mat-mdc-chip{background:transparent!important;border:1px solid currentColor}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "ngmodule", type: MatListModule }, { kind: "component", type: i3.MatList, selector: "mat-list", exportAs: ["matList"] }, { kind: "component", type: i3.MatListItem, selector: "mat-list-item, a[mat-list-item], button[mat-list-item]", inputs: ["activated"], exportAs: ["matListItem"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i4.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatChipsModule }, { kind: "component", type: i5.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: "directive", type: PraxisIconDirective, selector: "mat-icon[praxisIcon]", inputs: ["praxisIcon"] }, { kind: "component", type: PraxisRichContent, selector: "praxis-rich-content", inputs: ["document", "nodes", "context", "hostCapabilities", "rootClassName"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1481
1606
  }
1482
1607
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: PraxisListSkinPreviewComponent, decorators: [{
1483
1608
  type: Component,
1484
- args: [{ selector: 'praxis-list-skin-preview', standalone: true, imports: [CommonModule, MatListModule, MatIconModule, MatChipsModule, PraxisIconDirective], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"preview-root\" [ngClass]=\"skinClasses\" [attr.data-skin-scope]=\"skinScopeId\">\n @if (inlineCss) { <style [attr.nonce]=\"cspNonce || null\" [textContent]=\"inlineCss\"></style> }\n\n @if (isList()) {\n <mat-list>\n @for (item of items; track trackByIndex($index)) {\n <mat-list-item>\n <div class=\"list-item-content\">\n @if (leading(item); as lead) {\n @switch (lead.type) {\n @case ('icon') { <mat-icon [praxisIcon]=\"lead.value\" [ngClass]=\"lead.class\" [color]=\"isThemeColor(lead.color) ? lead.color : undefined\" [style.cssText]=\"(lead.style ? lead.style + ';' : '') + iconStyle(lead.color)\"></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\"\n [color]=\"isThemeColor(lead.badge?.color) ? lead.badge?.color : undefined\"\n [ngClass]=\"(((lead.badge?.variant || 'filled') === 'outlined') ? 'chip-outlined' : '')\"\n [style.cssText]=\"chipStyle(lead.badge?.color, lead.badge?.variant)\">{{ lead.badge?.value }}</mat-chip> }\n </div>\n }\n @case ('text') { <span [ngClass]=\"lead.class\" [style.cssText]=\"lead.style\">{{ lead.value }}</span> }\n @case ('chip') { <mat-chip [color]=\"isThemeColor(lead.color) ? lead.color : undefined\" [ngClass]=\"((lead.variant || 'filled') === 'outlined') ? 'chip-outlined' : ''\" [style.cssText]=\"chipStyle(lead.color, lead.variant)\">{{ lead.value }}</mat-chip> }\n @case ('rating') { @for (_ of ratingRange(lead); track $index; let idx = $index) { <mat-icon [praxisIcon]=\"starIcon(idx, lead.value)\" [color]=\"ratingThemeColor(lead)\" [style.cssText]=\"ratingIconStyle(lead)\"></mat-icon> } }\n @case ('html') { <span [ngClass]=\"lead.class\" [style.cssText]=\"lead.style\" [innerHTML]=\"lead.value\"></span> }\n @default { <span [ngClass]=\"lead.class\" [style.cssText]=\"lead.style\">{{ lead.value }}</span> }\n }\n }\n <div>\n <div class=\"primary\" [ngClass]=\"primary(item)?.class\" [style.cssText]=\"primary(item)?.style\">{{ primary(item)?.value }}</div>\n @if ((config.layout?.lines || 1) > 1) { <div class=\"secondary\" [ngClass]=\"secondary(item)?.class\" [style.cssText]=\"secondary(item)?.style\">{{ secondary(item)?.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 [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 (meta(item); as m) {\n <div class=\"meta\" [ngClass]=\"m.class\" [style.cssText]=\"m.style\">\n @if (metaPrefixIcon(); as mpi) { <mat-icon [praxisIcon]=\"mpi\"></mat-icon> }\n @switch (m.type) {\n @case ('chip') { <mat-chip [color]=\"isThemeColor(m.color) ? m.color : undefined\" [ngClass]=\"((m.variant || 'filled') === 'outlined') ? 'chip-outlined' : ''\" [style.cssText]=\"chipStyle(m.color, m.variant)\">{{ m.value }}</mat-chip> }\n @case ('rating') { @for (_ of ratingRange(m); track $index; let idx = $index) { <mat-icon [praxisIcon]=\"starIcon(idx, m.value)\" [color]=\"ratingThemeColor(m)\" [style.cssText]=\"ratingIconStyle(m)\"></mat-icon> } }\n @case ('icon') { <mat-icon [praxisIcon]=\"m.value\" [color]=\"isThemeColor(m.color) ? m.color : undefined\" [style.cssText]=\"iconStyle(m.color)\"></mat-icon> }\n @case ('image') { <span class=\"inline-image\"><img [src]=\"m.value\" [alt]=\"m.imageAlt || ''\" /></span> }\n @case ('html') { <span [innerHTML]=\"m.value\"></span> }\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 [color]=\"isThemeColor(tr.color) ? tr.color : undefined\" [ngClass]=\"((tr.variant || 'filled') === 'outlined') ? 'chip-outlined' : ''\" [style.cssText]=\"chipStyle(tr.color, tr.variant)\">{{ tr.value }}</mat-chip> }\n @case ('icon') { <mat-icon [praxisIcon]=\"tr.value\" [color]=\"isThemeColor(tr.color) ? tr.color : undefined\" [style.cssText]=\"iconStyle(tr.color)\"></mat-icon> }\n @case ('image') { <span class=\"inline-image\"><img [src]=\"tr.value\" [alt]=\"tr.imageAlt || ''\" /></span> }\n @case ('rating') { @for (_ of ratingRange(tr); track $index; let idx = $index) { <mat-icon [praxisIcon]=\"starIcon(idx, tr.value)\" [color]=\"ratingThemeColor(tr)\" [style.cssText]=\"ratingIconStyle(tr)\"></mat-icon> } }\n @case ('html') { <span [innerHTML]=\"tr.value\"></span> }\n @default { <span>{{ tr.value }}</span> }\n }\n </div>\n }\n </div>\n </mat-list-item>\n }\n </mat-list>\n } @else if (isTiles()) {\n <div class=\"tiles-grid\">\n @for (it of items; track trackByIndex($index)) {\n <div class=\"item-tile\">\n <div class=\"tile-media\">\n @if (leading(it); as lead) {\n @switch (lead.type) {\n @case ('image') {\n <img [src]=\"lead.value\" [alt]=\"config.templating?.leading?.imageAlt || ''\" />\n }\n @case ('icon') { <mat-icon [praxisIcon]=\"lead.value\" [ngClass]=\"lead.class\" [color]=\"isThemeColor(lead.color) ? lead.color : undefined\" [style.cssText]=\"(lead.style ? lead.style + ';' : '') + iconStyle(lead.color)\"></mat-icon> }\n @case ('text') { <span [ngClass]=\"lead.class\" [style.cssText]=\"lead.style\">{{ lead.value }}</span> }\n @case ('chip') { <mat-chip [color]=\"isThemeColor(lead.color) ? lead.color : undefined\" [ngClass]=\"((lead.variant || 'filled') === 'outlined') ? 'chip-outlined' : ''\" [style.cssText]=\"chipStyle(lead.color, lead.variant)\">{{ lead.value }}</mat-chip> }\n @case ('rating') { @for (_ of ratingRange(lead); track $index; let idx = $index) { <mat-icon [praxisIcon]=\"starIcon(idx, lead.value)\" [color]=\"ratingThemeColor(lead)\" [style.cssText]=\"ratingIconStyle(lead)\"></mat-icon> } }\n @case ('html') { <span [ngClass]=\"lead.class\" [style.cssText]=\"lead.style\" [innerHTML]=\"lead.value\"></span> }\n @default { <span [ngClass]=\"lead.class\" [style.cssText]=\"lead.style\">{{ lead.value }}</span> }\n }\n }\n </div>\n @if (trailing(it); as tr) {\n @if (statusPosition() === 'top-right' && (tr?.type === 'chip' || tr?.type === 'icon')) {\n <div class=\"tile-status\">\n @if (tr?.type === 'chip') { <mat-chip [color]=\"isThemeColor(tr.color) ? tr.color : undefined\" [ngClass]=\"((tr.variant || 'filled') === 'outlined') ? 'chip-outlined' : ''\" [style.cssText]=\"chipStyle(tr.color, tr.variant)\">{{ tr.value }}</mat-chip> }\n @if (tr?.type === 'icon') { <mat-icon [praxisIcon]=\"tr.value\" [color]=\"isThemeColor(tr.color) ? tr.color : undefined\" [style.cssText]=\"iconStyle(tr.color)\"></mat-icon> }\n </div>\n }\n }\n <div class=\"tile-body\">\n <div class=\"primary\" [ngClass]=\"primary(it)?.class\" [style.cssText]=\"primary(it)?.style\">{{ primary(it)?.value }}</div>\n @if ((config.layout?.lines || 1) > 1) { <div class=\"secondary\" [ngClass]=\"secondary(it)?.class\" [style.cssText]=\"secondary(it)?.style\">{{ secondary(it)?.value }}</div> }\n @if (meta(it); as m) {\n <div class=\"meta\" [ngClass]=\"m.class\" [style.cssText]=\"m.style\">\n @if (metaPrefixIcon(); as mpi) { <mat-icon [praxisIcon]=\"mpi\"></mat-icon> }\n @switch (m.type) {\n @case ('chip') { <mat-chip [color]=\"isThemeColor(m.color) ? m.color : undefined\" [ngClass]=\"((m.variant || 'filled') === 'outlined') ? 'chip-outlined' : ''\" [style.cssText]=\"chipStyle(m.color, m.variant)\">{{ m.value }}</mat-chip> }\n @case ('rating') { @for (_ of ratingRange(m); track $index; let idx = $index) { <mat-icon [praxisIcon]=\"starIcon(idx, m.value)\" [color]=\"ratingThemeColor(m)\" [style.cssText]=\"ratingIconStyle(m)\"></mat-icon> } }\n @case ('icon') { <mat-icon [praxisIcon]=\"m.value\" [color]=\"isThemeColor(m.color) ? m.color : undefined\" [style.cssText]=\"iconStyle(m.color)\"></mat-icon> }\n @case ('image') { <span class=\"inline-image\"><img [src]=\"m.value\" [alt]=\"m.imageAlt || ''\" /></span> }\n @case ('html') { <span [innerHTML]=\"m.value\"></span> }\n @default { <span>{{ m.value }}</span> }\n }\n </div>\n }\n @if (featuresVisible()) {\n <div class=\"features\">\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(it, f.expr) }}</span> }\n </span>\n }\n </div>\n }\n @if (trailing(it); as tr2) {\n @if (!(statusPosition() === 'top-right' && (tr2?.type === 'chip' || tr2?.type === 'icon'))) {\n <div class=\"meta\" [ngClass]=\"tr2.class\" [style.cssText]=\"tr2.style\">\n @switch (tr2.type) {\n @case ('chip') { <mat-chip [color]=\"isThemeColor(tr2.color) ? tr2.color : undefined\" [ngClass]=\"((tr2.variant || 'filled') === 'outlined') ? 'chip-outlined' : ''\" [style.cssText]=\"chipStyle(tr2.color, tr2.variant)\">{{ tr2.value }}</mat-chip> }\n @case ('rating') { @for (_ of ratingRange(tr2); track $index; let idx = $index) { <mat-icon [praxisIcon]=\"starIcon(idx, tr2.value)\" [color]=\"ratingThemeColor(tr2)\" [style.cssText]=\"ratingIconStyle(tr2)\"></mat-icon> } }\n @case ('image') { <span class=\"inline-image\"><img [src]=\"tr2.value\" [alt]=\"tr2.imageAlt || ''\" /></span> }\n @case ('html') { <span [innerHTML]=\"tr2.value\"></span> }\n @default { <span>{{ tr2.value }}</span> }\n }\n </div>\n }\n }\n </div>\n </div>\n }\n </div>\n } @else {\n <div class=\"cards-grid\">\n @for (it of items; track trackByIndex($index)) {\n <div class=\"item-card\">\n <div class=\"list-item-content\">\n @if (leading(it); as lead) {\n @switch (lead.type) {\n @case ('icon') { <mat-icon [praxisIcon]=\"lead.value\" [ngClass]=\"lead.class\" [color]=\"isThemeColor(lead.color) ? lead.color : undefined\" [style.cssText]=\"(lead.style ? lead.style + ';' : '') + iconStyle(lead.color)\"></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\"\n [color]=\"isThemeColor(lead.badge?.color) ? lead.badge?.color : undefined\"\n [ngClass]=\"(((lead.badge?.variant || 'filled') === 'outlined') ? 'chip-outlined' : '')\"\n [style.cssText]=\"chipStyle(lead.badge?.color, lead.badge?.variant)\">{{ lead.badge?.value }}</mat-chip> }\n </div>\n }\n @case ('text') { <span [ngClass]=\"lead.class\" [style.cssText]=\"lead.style\">{{ lead.value }}</span> }\n @case ('chip') { <mat-chip [color]=\"isThemeColor(lead.color) ? lead.color : undefined\" [ngClass]=\"((lead.variant || 'filled') === 'outlined') ? 'chip-outlined' : ''\" [style.cssText]=\"chipStyle(lead.color, lead.variant)\">{{ lead.value }}</mat-chip> }\n @case ('rating') { @for (_ of ratingRange(lead); track $index; let idx = $index) { <mat-icon [praxisIcon]=\"starIcon(idx, lead.value)\" [color]=\"ratingThemeColor(lead)\" [style.cssText]=\"ratingIconStyle(lead)\"></mat-icon> } }\n @case ('html') { <span [ngClass]=\"lead.class\" [style.cssText]=\"lead.style\" [innerHTML]=\"lead.value\"></span> }\n @default { <span [ngClass]=\"lead.class\" [style.cssText]=\"lead.style\">{{ lead.value }}</span> }\n }\n }\n <div>\n <div class=\"primary\" [ngClass]=\"primary(it)?.class\" [style.cssText]=\"primary(it)?.style\">{{ primary(it)?.value }}</div>\n @if ((config.layout?.lines || 1) > 1) { <div class=\"secondary\" [ngClass]=\"secondary(it)?.class\" [style.cssText]=\"secondary(it)?.style\">{{ secondary(it)?.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 [praxisIcon]=\"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 (meta(it); as m) {\n <div class=\"meta\" [ngClass]=\"m.class\" [style.cssText]=\"m.style\">\n @if (metaPrefixIcon(); as mpi) { <mat-icon [praxisIcon]=\"mpi\"></mat-icon> }\n @switch (m.type) {\n @case ('chip') { <mat-chip [color]=\"isThemeColor(m.color) ? m.color : undefined\" [ngClass]=\"((m.variant || 'filled') === 'outlined') ? 'chip-outlined' : ''\" [style.cssText]=\"chipStyle(m.color, m.variant)\">{{ m.value }}</mat-chip> }\n @case ('rating') { @for (_ of ratingRange(m); track $index; let idx = $index) { <mat-icon [praxisIcon]=\"starIcon(idx, m.value)\" [color]=\"ratingThemeColor(m)\" [style.cssText]=\"ratingIconStyle(m)\"></mat-icon> } }\n @case ('icon') { <mat-icon [praxisIcon]=\"m.value\" [color]=\"isThemeColor(m.color) ? m.color : undefined\" [style.cssText]=\"iconStyle(m.color)\"></mat-icon> }\n @case ('image') { <span class=\"inline-image\"><img [src]=\"m.value\" [alt]=\"m.imageAlt || ''\" /></span> }\n @case ('html') { <span [innerHTML]=\"m.value\"></span> }\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]=\"isThemeColor(tr.color) ? tr.color : undefined\" [ngClass]=\"((tr.variant || 'filled') === 'outlined') ? 'chip-outlined' : ''\" [style.cssText]=\"chipStyle(tr.color, tr.variant)\">{{ tr.value }}</mat-chip> }\n @case ('icon') { <mat-icon [praxisIcon]=\"tr.value\" [color]=\"isThemeColor(tr.color) ? tr.color : undefined\" [style.cssText]=\"iconStyle(tr.color)\"></mat-icon> }\n @case ('image') { <span class=\"inline-image\"><img [src]=\"tr.value\" [alt]=\"tr.imageAlt || ''\" /></span> }\n @case ('rating') { @for (_ of ratingRange(tr); track $index; let idx = $index) { <mat-icon [praxisIcon]=\"starIcon(idx, tr.value)\" [color]=\"ratingThemeColor(tr)\" [style.cssText]=\"ratingIconStyle(tr)\"></mat-icon> } }\n @case ('html') { <span [innerHTML]=\"tr.value\"></span> }\n @default { <span>{{ tr.value }}</span> }\n }\n </div>\n }\n </div>\n </div>\n }\n </div>\n }\n</div>\n", styles: [".preview-root{--p-list-radius: var(--md-sys-shape-corner-medium, 16px);--p-list-shadow: var(--md-sys-elevation-level2);--p-list-border: 1px solid var(--md-sys-color-outline-variant);--p-list-blur: 10px;--p-list-foreground: var(--md-sys-color-on-surface);--p-list-foreground-muted: var(--md-sys-color-on-surface-variant);--p-list-grad-foreground: var(--md-sys-color-on-primary);--p-list-grad-foreground-muted: var(--md-sys-color-on-primary);--p-list-surface: var(--md-sys-color-surface-container);--p-list-accent: var(--md-sys-color-primary);--p-list-item-border: 1px solid var(--md-sys-color-outline-variant);--p-list-grad-from: var(--md-sys-color-primary-container);--p-list-grad-to: var(--md-sys-color-tertiary-container);--p-list-grad-angle: 135deg;--p-list-tile-minW: 240px;--p-list-tile-gap: 16px;--p-list-tile-padding: 16px;--p-list-tile-radius: 16px;--p-list-tile-media-radius: 12px;--p-list-tile-media-ratio: 1 / 1;padding:12px}.preview-light{background:var(--md-sys-color-surface-container-low, var(--md-sys-color-surface))}.preview-dark{background:var(--md-sys-color-surface-container-lowest, var(--md-sys-color-surface))}.preview-grid{background-color:var(--md-sys-color-surface-variant, var(--md-sys-color-surface));background-image:linear-gradient(var(--md-sys-color-outline-variant, var(--md-sys-color-outline)) 1px,transparent 1px),linear-gradient(90deg,var(--md-sys-color-outline-variant, var(--md-sys-color-outline)) 1px,transparent 1px);background-size:16px 16px}.skin-elevated,.skin-outline,.skin-flat,.skin-neumorphism{--p-list-item-surface: var(--mdc-elevated-card-container-color, var(--p-list-surface));--p-list-item-border: var(--p-list-border)}.skin-elevated .item-card,.skin-outline .item-card,.skin-flat .item-card,.skin-neumorphism .item-card{background:var(--mdc-elevated-card-container-color, var(--p-list-surface));border-radius:var(--p-list-radius);box-shadow:var(--p-list-shadow);border:var(--p-list-border)}.skin-elevated .item-tile,.skin-outline .item-tile,.skin-flat .item-tile,.skin-neumorphism .item-tile{background:var(--mdc-elevated-card-container-color, var(--p-list-surface));box-shadow:var(--p-list-shadow);border:var(--p-list-border)}.skin-elevated .mat-mdc-list-item .list-item-content,.skin-outline .mat-mdc-list-item .list-item-content,.skin-flat .mat-mdc-list-item .list-item-content,.skin-neumorphism .mat-mdc-list-item .list-item-content{background:var(--mdc-elevated-card-container-color, var(--p-list-surface));border-radius:calc(var(--p-list-radius) * .75);box-shadow:var(--p-list-shadow);border:var(--p-list-item-border);color:var(--p-list-foreground)}.skin-outline{--p-list-shadow: none;--p-list-border: 1px solid var(--md-sys-color-outline)}.skin-flat{--p-list-shadow: none;--p-list-border: 1px solid var(--md-sys-color-outline-variant)}.skin-neumorphism{--p-list-shadow: var(--md-sys-elevation-level2);--p-list-border: 1px solid var(--md-sys-color-outline-variant);--p-list-radius: 1.25rem}.skin-pill-soft .item-card,.skin-pill-soft .item-tile{background:var(--mdc-elevated-card-container-color, var(--p-list-surface));border-radius:calc(var(--p-list-radius) * 1.3);box-shadow:var(--md-sys-elevation-level1);border:var(--p-list-border)}.skin-pill-soft .mat-mdc-list-item .list-item-content{background:var(--mdc-elevated-card-container-color, var(--p-list-surface));border-radius:calc(var(--p-list-radius) * 1.3);box-shadow:var(--md-sys-elevation-level1);border:var(--p-list-border);color:var(--p-list-foreground)}.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}.features{display:flex;flex-wrap:wrap;gap:12px;margin-top:6px;color:var(--p-list-foreground-muted)}.feature{display:inline-flex;align-items:center;gap:6px}.model-media .lead-image{width:136px;height:96px;border-radius:16px}.model-hotel .lead-image{width:160px;height:110px;border-radius:18px}.skin-gradient-tile{--p-list-foreground: var(--p-list-grad-foreground);--p-list-foreground-muted: var(--p-list-grad-foreground-muted)}.skin-gradient-tile .item-card,.skin-gradient-tile .item-tile,.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:var(--p-list-foreground)}.skin-glass .item-card,.skin-glass .item-tile{background:var(--md-sys-color-surface-container-low);border-radius:var(--p-list-radius);border:1px solid var(--md-sys-color-outline-variant);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:var(--md-sys-color-surface-container-low);border-radius:var(--p-list-radius);border:1px solid var(--md-sys-color-outline-variant);backdrop-filter:blur(var(--p-list-blur));-webkit-backdrop-filter:blur(var(--p-list-blur));color:var(--p-list-foreground)}.list-item-content{display:grid;grid-template-columns:auto minmax(0,1fr) auto auto;align-items:center;gap:12px;padding:12px 16px}.primary{font-weight:500;color:var(--p-list-foreground)}.secondary,.meta{color:var(--p-list-foreground-muted)}.trailing{color:var(--p-list-foreground-muted);text-align:end}.cards-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(var(--p-list-tile-minW),1fr));gap:var(--p-list-tile-gap)}.item-card{padding:12px}.tiles-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(var(--p-list-tile-minW),1fr));gap:var(--p-list-tile-gap)}.item-tile{padding:var(--p-list-tile-padding);border-radius:var(--p-list-tile-radius);border:var(--p-list-border);background:var(--p-list-surface);display:grid;gap:8px}.tile-media{width:100%;aspect-ratio:var(--p-list-tile-media-ratio);border-radius:var(--p-list-tile-media-radius);background:var(--md-sys-color-surface-container-low, var(--p-list-surface));display:grid;place-items:center;overflow:hidden}.tile-media img{width:100%;height:100%;object-fit:cover}.tile-body{display:grid;gap:4px}.chip-outlined.mat-mdc-chip{background:transparent!important;border:1px solid currentColor}\n"] }]
1609
+ args: [{ selector: 'praxis-list-skin-preview', standalone: true, imports: [
1610
+ CommonModule,
1611
+ MatListModule,
1612
+ MatIconModule,
1613
+ MatChipsModule,
1614
+ PraxisIconDirective,
1615
+ PraxisRichContent,
1616
+ ], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"preview-root\" [ngClass]=\"skinClasses\" [attr.data-skin-scope]=\"skinScopeId\">\n @if (inlineCss) { <style [attr.nonce]=\"cspNonce || null\" [textContent]=\"inlineCss\"></style> }\n\n @if (isList()) {\n <mat-list>\n @for (item of items; track trackByIndex($index)) {\n <mat-list-item>\n <div class=\"list-item-content\">\n @if (leading(item); as lead) {\n @if (previewRichContentNodes(lead, { imageAlt: config.templating?.leading?.imageAlt }); as leadNodes) {\n <praxis-rich-content [nodes]=\"leadNodes\"></praxis-rich-content>\n } @else {\n @switch (lead.type) {\n @case ('icon') { <mat-icon [praxisIcon]=\"lead.value\" [ngClass]=\"lead.class\" [color]=\"isThemeColor(lead.color) ? lead.color : undefined\" [style.cssText]=\"(lead.style ? lead.style + ';' : '') + iconStyle(lead.color)\"></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\"\n [color]=\"isThemeColor(lead.badge?.color) ? lead.badge?.color : undefined\"\n [ngClass]=\"(((lead.badge?.variant || 'filled') === 'outlined') ? 'chip-outlined' : '')\"\n [style.cssText]=\"chipStyle(lead.badge?.color, lead.badge?.variant)\">{{ lead.badge?.value }}</mat-chip> }\n </div>\n }\n @case ('text') { <span [ngClass]=\"lead.class\" [style.cssText]=\"lead.style\">{{ lead.value }}</span> }\n @case ('chip') { <mat-chip [color]=\"isThemeColor(lead.color) ? lead.color : undefined\" [ngClass]=\"((lead.variant || 'filled') === 'outlined') ? 'chip-outlined' : ''\" [style.cssText]=\"chipStyle(lead.color, lead.variant)\">{{ lead.value }}</mat-chip> }\n @case ('rating') { @for (_ of ratingRange(lead); track $index; let idx = $index) { <mat-icon [praxisIcon]=\"starIcon(idx, lead.value)\" [color]=\"ratingThemeColor(lead)\" [style.cssText]=\"ratingIconStyle(lead)\"></mat-icon> } }\n @case ('html') { <span [ngClass]=\"lead.class\" [style.cssText]=\"lead.style\" [innerHTML]=\"lead.value\"></span> }\n @default { <span [ngClass]=\"lead.class\" [style.cssText]=\"lead.style\">{{ lead.value }}</span> }\n }\n }\n }\n <div>\n <div class=\"primary\" [ngClass]=\"primary(item)?.class\" [style.cssText]=\"primary(item)?.style\">\n @if (previewRichContentNodes(primary(item)); as primaryNodes) {\n <praxis-rich-content [nodes]=\"primaryNodes\"></praxis-rich-content>\n } @else {\n {{ primary(item)?.value }}\n }\n </div>\n @if ((config.layout?.lines || 1) > 1) {\n <div class=\"secondary\" [ngClass]=\"secondary(item)?.class\" [style.cssText]=\"secondary(item)?.style\">\n @if (previewRichContentNodes(secondary(item)); as secondaryNodes) {\n <praxis-rich-content [nodes]=\"secondaryNodes\"></praxis-rich-content>\n } @else {\n {{ secondary(item)?.value }}\n }\n </div>\n }\n @if (featuresVisible()) {\n @for (f of (config.templating?.features || []); track $index; let fi = $index) {\n <span class=\"feature\">\n @if (previewFeatureRichContentNodes(item, f); as featureNodes) {\n <praxis-rich-content [nodes]=\"featureNodes\"></praxis-rich-content>\n } @else {\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 }\n </span>\n }\n }\n </div>\n @if (meta(item); as m) {\n <div class=\"meta\" [ngClass]=\"m.class\" [style.cssText]=\"m.style\">\n @if (metaPrefixIcon(); as mpi) { <mat-icon [praxisIcon]=\"mpi\"></mat-icon> }\n @if (previewRichContentNodes(m, { slot: 'meta' }); as metaNodes) {\n <praxis-rich-content [nodes]=\"metaNodes\"></praxis-rich-content>\n } @else {\n @switch (m.type) {\n @case ('chip') { <mat-chip [color]=\"isThemeColor(m.color) ? m.color : undefined\" [ngClass]=\"((m.variant || 'filled') === 'outlined') ? 'chip-outlined' : ''\" [style.cssText]=\"chipStyle(m.color, m.variant)\">{{ m.value }}</mat-chip> }\n @case ('rating') { @for (_ of ratingRange(m); track $index; let idx = $index) { <mat-icon [praxisIcon]=\"starIcon(idx, m.value)\" [color]=\"ratingThemeColor(m)\" [style.cssText]=\"ratingIconStyle(m)\"></mat-icon> } }\n @case ('icon') { <mat-icon [praxisIcon]=\"m.value\" [color]=\"isThemeColor(m.color) ? m.color : undefined\" [style.cssText]=\"iconStyle(m.color)\"></mat-icon> }\n @case ('image') { <span class=\"inline-image\"><img [src]=\"m.value\" [alt]=\"m.imageAlt || ''\" /></span> }\n @case ('html') { <span [innerHTML]=\"m.value\"></span> }\n @default { <span>{{ m.value }}</span> }\n }\n }\n </div>\n }\n @if (trailing(item); as tr) {\n <div class=\"trailing\" [ngClass]=\"tr.class\" [style.cssText]=\"tr.style\">\n @if (previewRichContentNodes(tr); as trailingNodes) {\n <praxis-rich-content [nodes]=\"trailingNodes\"></praxis-rich-content>\n } @else {\n @switch (tr.type) {\n @case ('chip') { <mat-chip [color]=\"isThemeColor(tr.color) ? tr.color : undefined\" [ngClass]=\"((tr.variant || 'filled') === 'outlined') ? 'chip-outlined' : ''\" [style.cssText]=\"chipStyle(tr.color, tr.variant)\">{{ tr.value }}</mat-chip> }\n @case ('icon') { <mat-icon [praxisIcon]=\"tr.value\" [color]=\"isThemeColor(tr.color) ? tr.color : undefined\" [style.cssText]=\"iconStyle(tr.color)\"></mat-icon> }\n @case ('image') { <span class=\"inline-image\"><img [src]=\"tr.value\" [alt]=\"tr.imageAlt || ''\" /></span> }\n @case ('rating') { @for (_ of ratingRange(tr); track $index; let idx = $index) { <mat-icon [praxisIcon]=\"starIcon(idx, tr.value)\" [color]=\"ratingThemeColor(tr)\" [style.cssText]=\"ratingIconStyle(tr)\"></mat-icon> } }\n @case ('html') { <span [innerHTML]=\"tr.value\"></span> }\n @default { <span>{{ tr.value }}</span> }\n }\n }\n </div>\n }\n </div>\n </mat-list-item>\n }\n </mat-list>\n } @else if (isTiles()) {\n <div class=\"tiles-grid\">\n @for (it of items; track trackByIndex($index)) {\n <div class=\"item-tile\">\n <div class=\"tile-media\">\n @if (leading(it); as lead) {\n @if (previewRichContentNodes(lead, { imageAlt: config.templating?.leading?.imageAlt }); as leadNodes) {\n <praxis-rich-content [nodes]=\"leadNodes\"></praxis-rich-content>\n } @else {\n @switch (lead.type) {\n @case ('image') {\n <img [src]=\"lead.value\" [alt]=\"config.templating?.leading?.imageAlt || ''\" />\n }\n @case ('icon') { <mat-icon [praxisIcon]=\"lead.value\" [ngClass]=\"lead.class\" [color]=\"isThemeColor(lead.color) ? lead.color : undefined\" [style.cssText]=\"(lead.style ? lead.style + ';' : '') + iconStyle(lead.color)\"></mat-icon> }\n @case ('text') { <span [ngClass]=\"lead.class\" [style.cssText]=\"lead.style\">{{ lead.value }}</span> }\n @case ('chip') { <mat-chip [color]=\"isThemeColor(lead.color) ? lead.color : undefined\" [ngClass]=\"((lead.variant || 'filled') === 'outlined') ? 'chip-outlined' : ''\" [style.cssText]=\"chipStyle(lead.color, lead.variant)\">{{ lead.value }}</mat-chip> }\n @case ('rating') { @for (_ of ratingRange(lead); track $index; let idx = $index) { <mat-icon [praxisIcon]=\"starIcon(idx, lead.value)\" [color]=\"ratingThemeColor(lead)\" [style.cssText]=\"ratingIconStyle(lead)\"></mat-icon> } }\n @case ('html') { <span [ngClass]=\"lead.class\" [style.cssText]=\"lead.style\" [innerHTML]=\"lead.value\"></span> }\n @default { <span [ngClass]=\"lead.class\" [style.cssText]=\"lead.style\">{{ lead.value }}</span> }\n }\n }\n }\n </div>\n @if (trailing(it); as tr) {\n @if (statusPosition() === 'top-right' && (tr?.type === 'chip' || tr?.type === 'icon')) {\n <div class=\"tile-status\">\n @if (previewRichContentNodes(tr); as trailingNodes) {\n <praxis-rich-content [nodes]=\"trailingNodes\"></praxis-rich-content>\n } @else {\n @if (tr?.type === 'chip') { <mat-chip [color]=\"isThemeColor(tr.color) ? tr.color : undefined\" [ngClass]=\"((tr.variant || 'filled') === 'outlined') ? 'chip-outlined' : ''\" [style.cssText]=\"chipStyle(tr.color, tr.variant)\">{{ tr.value }}</mat-chip> }\n @if (tr?.type === 'icon') { <mat-icon [praxisIcon]=\"tr.value\" [color]=\"isThemeColor(tr.color) ? tr.color : undefined\" [style.cssText]=\"iconStyle(tr.color)\"></mat-icon> }\n }\n </div>\n }\n }\n <div class=\"tile-body\">\n <div class=\"primary\" [ngClass]=\"primary(it)?.class\" [style.cssText]=\"primary(it)?.style\">\n @if (previewRichContentNodes(primary(it)); as primaryNodes) {\n <praxis-rich-content [nodes]=\"primaryNodes\"></praxis-rich-content>\n } @else {\n {{ primary(it)?.value }}\n }\n </div>\n @if ((config.layout?.lines || 1) > 1) {\n <div class=\"secondary\" [ngClass]=\"secondary(it)?.class\" [style.cssText]=\"secondary(it)?.style\">\n @if (previewRichContentNodes(secondary(it)); as secondaryNodes) {\n <praxis-rich-content [nodes]=\"secondaryNodes\"></praxis-rich-content>\n } @else {\n {{ secondary(it)?.value }}\n }\n </div>\n }\n @if (meta(it); as m) {\n <div class=\"meta\" [ngClass]=\"m.class\" [style.cssText]=\"m.style\">\n @if (metaPrefixIcon(); as mpi) { <mat-icon [praxisIcon]=\"mpi\"></mat-icon> }\n @if (previewRichContentNodes(m, { slot: 'meta' }); as metaNodes) {\n <praxis-rich-content [nodes]=\"metaNodes\"></praxis-rich-content>\n } @else {\n @switch (m.type) {\n @case ('chip') { <mat-chip [color]=\"isThemeColor(m.color) ? m.color : undefined\" [ngClass]=\"((m.variant || 'filled') === 'outlined') ? 'chip-outlined' : ''\" [style.cssText]=\"chipStyle(m.color, m.variant)\">{{ m.value }}</mat-chip> }\n @case ('rating') { @for (_ of ratingRange(m); track $index; let idx = $index) { <mat-icon [praxisIcon]=\"starIcon(idx, m.value)\" [color]=\"ratingThemeColor(m)\" [style.cssText]=\"ratingIconStyle(m)\"></mat-icon> } }\n @case ('icon') { <mat-icon [praxisIcon]=\"m.value\" [color]=\"isThemeColor(m.color) ? m.color : undefined\" [style.cssText]=\"iconStyle(m.color)\"></mat-icon> }\n @case ('image') { <span class=\"inline-image\"><img [src]=\"m.value\" [alt]=\"m.imageAlt || ''\" /></span> }\n @case ('html') { <span [innerHTML]=\"m.value\"></span> }\n @default { <span>{{ m.value }}</span> }\n }\n }\n </div>\n }\n @if (featuresVisible()) {\n <div class=\"features\">\n @for (f of (config.templating?.features || []); track $index; let fi = $index) {\n <span class=\"feature\">\n @if (previewFeatureRichContentNodes(it, f); as featureNodes) {\n <praxis-rich-content [nodes]=\"featureNodes\"></praxis-rich-content>\n } @else {\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(it, f.expr) }}</span> }\n }\n </span>\n }\n </div>\n }\n @if (trailing(it); as tr2) {\n @if (!(statusPosition() === 'top-right' && (tr2?.type === 'chip' || tr2?.type === 'icon'))) {\n <div class=\"meta\" [ngClass]=\"tr2.class\" [style.cssText]=\"tr2.style\">\n @if (previewRichContentNodes(tr2); as trailingNodes) {\n <praxis-rich-content [nodes]=\"trailingNodes\"></praxis-rich-content>\n } @else {\n @switch (tr2.type) {\n @case ('chip') { <mat-chip [color]=\"isThemeColor(tr2.color) ? tr2.color : undefined\" [ngClass]=\"((tr2.variant || 'filled') === 'outlined') ? 'chip-outlined' : ''\" [style.cssText]=\"chipStyle(tr2.color, tr2.variant)\">{{ tr2.value }}</mat-chip> }\n @case ('rating') { @for (_ of ratingRange(tr2); track $index; let idx = $index) { <mat-icon [praxisIcon]=\"starIcon(idx, tr2.value)\" [color]=\"ratingThemeColor(tr2)\" [style.cssText]=\"ratingIconStyle(tr2)\"></mat-icon> } }\n @case ('image') { <span class=\"inline-image\"><img [src]=\"tr2.value\" [alt]=\"tr2.imageAlt || ''\" /></span> }\n @case ('html') { <span [innerHTML]=\"tr2.value\"></span> }\n @default { <span>{{ tr2.value }}</span> }\n }\n }\n </div>\n }\n }\n </div>\n </div>\n }\n </div>\n } @else {\n <div class=\"cards-grid\">\n @for (it of items; track trackByIndex($index)) {\n <div class=\"item-card\">\n <div class=\"list-item-content\">\n @if (leading(it); as lead) {\n @if (previewRichContentNodes(lead, { imageAlt: config.templating?.leading?.imageAlt }); as leadNodes) {\n <praxis-rich-content [nodes]=\"leadNodes\"></praxis-rich-content>\n } @else {\n @switch (lead.type) {\n @case ('icon') { <mat-icon [praxisIcon]=\"lead.value\" [ngClass]=\"lead.class\" [color]=\"isThemeColor(lead.color) ? lead.color : undefined\" [style.cssText]=\"(lead.style ? lead.style + ';' : '') + iconStyle(lead.color)\"></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\"\n [color]=\"isThemeColor(lead.badge?.color) ? lead.badge?.color : undefined\"\n [ngClass]=\"(((lead.badge?.variant || 'filled') === 'outlined') ? 'chip-outlined' : '')\"\n [style.cssText]=\"chipStyle(lead.badge?.color, lead.badge?.variant)\">{{ lead.badge?.value }}</mat-chip> }\n </div>\n }\n @case ('text') { <span [ngClass]=\"lead.class\" [style.cssText]=\"lead.style\">{{ lead.value }}</span> }\n @case ('chip') { <mat-chip [color]=\"isThemeColor(lead.color) ? lead.color : undefined\" [ngClass]=\"((lead.variant || 'filled') === 'outlined') ? 'chip-outlined' : ''\" [style.cssText]=\"chipStyle(lead.color, lead.variant)\">{{ lead.value }}</mat-chip> }\n @case ('rating') { @for (_ of ratingRange(lead); track $index; let idx = $index) { <mat-icon [praxisIcon]=\"starIcon(idx, lead.value)\" [color]=\"ratingThemeColor(lead)\" [style.cssText]=\"ratingIconStyle(lead)\"></mat-icon> } }\n @case ('html') { <span [ngClass]=\"lead.class\" [style.cssText]=\"lead.style\" [innerHTML]=\"lead.value\"></span> }\n @default { <span [ngClass]=\"lead.class\" [style.cssText]=\"lead.style\">{{ lead.value }}</span> }\n }\n }\n }\n <div>\n <div class=\"primary\" [ngClass]=\"primary(it)?.class\" [style.cssText]=\"primary(it)?.style\">\n @if (previewRichContentNodes(primary(it)); as primaryNodes) {\n <praxis-rich-content [nodes]=\"primaryNodes\"></praxis-rich-content>\n } @else {\n {{ primary(it)?.value }}\n }\n </div>\n @if ((config.layout?.lines || 1) > 1) {\n <div class=\"secondary\" [ngClass]=\"secondary(it)?.class\" [style.cssText]=\"secondary(it)?.style\">\n @if (previewRichContentNodes(secondary(it)); as secondaryNodes) {\n <praxis-rich-content [nodes]=\"secondaryNodes\"></praxis-rich-content>\n } @else {\n {{ secondary(it)?.value }}\n }\n </div>\n }\n @if (featuresVisible()) {\n @for (f of (config.templating?.features || []); track $index; let fi = $index) {\n <span class=\"feature\">\n @if (previewFeatureRichContentNodes(it, f); as featureNodes) {\n <praxis-rich-content [nodes]=\"featureNodes\"></praxis-rich-content>\n } @else {\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(it, f.expr) }}</span> }\n }\n </span>\n }\n }\n </div>\n @if (meta(it); as m) {\n <div class=\"meta\" [ngClass]=\"m.class\" [style.cssText]=\"m.style\">\n @if (metaPrefixIcon(); as mpi) { <mat-icon [praxisIcon]=\"mpi\"></mat-icon> }\n @if (previewRichContentNodes(m, { slot: 'meta' }); as metaNodes) {\n <praxis-rich-content [nodes]=\"metaNodes\"></praxis-rich-content>\n } @else {\n @switch (m.type) {\n @case ('chip') { <mat-chip [color]=\"isThemeColor(m.color) ? m.color : undefined\" [ngClass]=\"((m.variant || 'filled') === 'outlined') ? 'chip-outlined' : ''\" [style.cssText]=\"chipStyle(m.color, m.variant)\">{{ m.value }}</mat-chip> }\n @case ('rating') { @for (_ of ratingRange(m); track $index; let idx = $index) { <mat-icon [praxisIcon]=\"starIcon(idx, m.value)\" [color]=\"ratingThemeColor(m)\" [style.cssText]=\"ratingIconStyle(m)\"></mat-icon> } }\n @case ('icon') { <mat-icon [praxisIcon]=\"m.value\" [color]=\"isThemeColor(m.color) ? m.color : undefined\" [style.cssText]=\"iconStyle(m.color)\"></mat-icon> }\n @case ('image') { <span class=\"inline-image\"><img [src]=\"m.value\" [alt]=\"m.imageAlt || ''\" /></span> }\n @case ('html') { <span [innerHTML]=\"m.value\"></span> }\n @default { <span>{{ m.value }}</span> }\n }\n }\n </div>\n }\n @if (trailing(it); as tr) {\n <div class=\"trailing\" [ngClass]=\"tr.class\" [style.cssText]=\"tr.style\">\n @if (previewRichContentNodes(tr); as trailingNodes) {\n <praxis-rich-content [nodes]=\"trailingNodes\"></praxis-rich-content>\n } @else {\n @switch (tr.type) {\n @case ('chip') { <mat-chip [color]=\"isThemeColor(tr.color) ? tr.color : undefined\" [ngClass]=\"((tr.variant || 'filled') === 'outlined') ? 'chip-outlined' : ''\" [style.cssText]=\"chipStyle(tr.color, tr.variant)\">{{ tr.value }}</mat-chip> }\n @case ('icon') { <mat-icon [praxisIcon]=\"tr.value\" [color]=\"isThemeColor(tr.color) ? tr.color : undefined\" [style.cssText]=\"iconStyle(tr.color)\"></mat-icon> }\n @case ('image') { <span class=\"inline-image\"><img [src]=\"tr.value\" [alt]=\"tr.imageAlt || ''\" /></span> }\n @case ('rating') { @for (_ of ratingRange(tr); track $index; let idx = $index) { <mat-icon [praxisIcon]=\"starIcon(idx, tr.value)\" [color]=\"ratingThemeColor(tr)\" [style.cssText]=\"ratingIconStyle(tr)\"></mat-icon> } }\n @case ('html') { <span [innerHTML]=\"tr.value\"></span> }\n @default { <span>{{ tr.value }}</span> }\n }\n }\n </div>\n }\n </div>\n </div>\n }\n </div>\n }\n</div>\n", styles: [".preview-root{--p-list-radius: var(--md-sys-shape-corner-medium, 16px);--p-list-shadow: var(--md-sys-elevation-level2);--p-list-border: 1px solid var(--md-sys-color-outline-variant);--p-list-blur: 10px;--p-list-foreground: var(--md-sys-color-on-surface);--p-list-foreground-muted: var(--md-sys-color-on-surface-variant);--p-list-grad-foreground: var(--md-sys-color-on-primary);--p-list-grad-foreground-muted: var(--md-sys-color-on-primary);--p-list-surface: var(--md-sys-color-surface-container);--p-list-accent: var(--md-sys-color-primary);--p-list-item-border: 1px solid var(--md-sys-color-outline-variant);--p-list-grad-from: var(--md-sys-color-primary-container);--p-list-grad-to: var(--md-sys-color-tertiary-container);--p-list-grad-angle: 135deg;--p-list-tile-minW: 240px;--p-list-tile-gap: 16px;--p-list-tile-padding: 16px;--p-list-tile-radius: 16px;--p-list-tile-media-radius: 12px;--p-list-tile-media-ratio: 1 / 1;padding:12px}.preview-light{background:var(--md-sys-color-surface-container-low, var(--md-sys-color-surface))}.preview-dark{background:var(--md-sys-color-surface-container-lowest, var(--md-sys-color-surface))}.preview-grid{background-color:var(--md-sys-color-surface-variant, var(--md-sys-color-surface));background-image:linear-gradient(var(--md-sys-color-outline-variant, var(--md-sys-color-outline)) 1px,transparent 1px),linear-gradient(90deg,var(--md-sys-color-outline-variant, var(--md-sys-color-outline)) 1px,transparent 1px);background-size:16px 16px}.skin-elevated,.skin-outline,.skin-flat,.skin-neumorphism{--p-list-item-surface: var(--mdc-elevated-card-container-color, var(--p-list-surface));--p-list-item-border: var(--p-list-border)}.skin-elevated .item-card,.skin-outline .item-card,.skin-flat .item-card,.skin-neumorphism .item-card{background:var(--mdc-elevated-card-container-color, var(--p-list-surface));border-radius:var(--p-list-radius);box-shadow:var(--p-list-shadow);border:var(--p-list-border)}.skin-elevated .item-tile,.skin-outline .item-tile,.skin-flat .item-tile,.skin-neumorphism .item-tile{background:var(--mdc-elevated-card-container-color, var(--p-list-surface));box-shadow:var(--p-list-shadow);border:var(--p-list-border)}.skin-elevated .mat-mdc-list-item .list-item-content,.skin-outline .mat-mdc-list-item .list-item-content,.skin-flat .mat-mdc-list-item .list-item-content,.skin-neumorphism .mat-mdc-list-item .list-item-content{background:var(--mdc-elevated-card-container-color, var(--p-list-surface));border-radius:calc(var(--p-list-radius) * .75);box-shadow:var(--p-list-shadow);border:var(--p-list-item-border);color:var(--p-list-foreground)}.skin-outline{--p-list-shadow: none;--p-list-border: 1px solid var(--md-sys-color-outline)}.skin-flat{--p-list-shadow: none;--p-list-border: 1px solid var(--md-sys-color-outline-variant)}.skin-neumorphism{--p-list-shadow: var(--md-sys-elevation-level2);--p-list-border: 1px solid var(--md-sys-color-outline-variant);--p-list-radius: 1.25rem}.skin-pill-soft .item-card,.skin-pill-soft .item-tile{background:var(--mdc-elevated-card-container-color, var(--p-list-surface));border-radius:calc(var(--p-list-radius) * 1.3);box-shadow:var(--md-sys-elevation-level1);border:var(--p-list-border)}.skin-pill-soft .mat-mdc-list-item .list-item-content{background:var(--mdc-elevated-card-container-color, var(--p-list-surface));border-radius:calc(var(--p-list-radius) * 1.3);box-shadow:var(--md-sys-elevation-level1);border:var(--p-list-border);color:var(--p-list-foreground)}.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}.features{display:flex;flex-wrap:wrap;gap:12px;margin-top:6px;color:var(--p-list-foreground-muted)}.feature{display:inline-flex;align-items:center;gap:6px}.model-media .lead-image{width:136px;height:96px;border-radius:16px}.model-hotel .lead-image{width:160px;height:110px;border-radius:18px}.skin-gradient-tile{--p-list-foreground: var(--p-list-grad-foreground);--p-list-foreground-muted: var(--p-list-grad-foreground-muted)}.skin-gradient-tile .item-card,.skin-gradient-tile .item-tile,.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:var(--p-list-foreground)}.skin-glass .item-card,.skin-glass .item-tile{background:var(--md-sys-color-surface-container-low);border-radius:var(--p-list-radius);border:1px solid var(--md-sys-color-outline-variant);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:var(--md-sys-color-surface-container-low);border-radius:var(--p-list-radius);border:1px solid var(--md-sys-color-outline-variant);backdrop-filter:blur(var(--p-list-blur));-webkit-backdrop-filter:blur(var(--p-list-blur));color:var(--p-list-foreground)}.list-item-content{display:grid;grid-template-columns:auto minmax(0,1fr) auto auto;align-items:center;gap:12px;padding:12px 16px}.primary{font-weight:500;color:var(--p-list-foreground)}.secondary,.meta{color:var(--p-list-foreground-muted)}.trailing{color:var(--p-list-foreground-muted);text-align:end}.cards-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(var(--p-list-tile-minW),1fr));gap:var(--p-list-tile-gap)}.item-card{padding:12px}.tiles-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(var(--p-list-tile-minW),1fr));gap:var(--p-list-tile-gap)}.item-tile{padding:var(--p-list-tile-padding);border-radius:var(--p-list-tile-radius);border:var(--p-list-border);background:var(--p-list-surface);display:grid;gap:8px}.tile-media{width:100%;aspect-ratio:var(--p-list-tile-media-ratio);border-radius:var(--p-list-tile-media-radius);background:var(--md-sys-color-surface-container-low, var(--p-list-surface));display:grid;place-items:center;overflow:hidden}.tile-media img{width:100%;height:100%;object-fit:cover}.tile-body{display:grid;gap:4px}.chip-outlined.mat-mdc-chip{background:transparent!important;border:1px solid currentColor}\n"] }]
1485
1617
  }], ctorParameters: () => [{ type: ListSkinService }], propDecorators: { config: [{
1486
1618
  type: Input
1487
1619
  }], items: [{
@@ -6717,6 +6849,63 @@ class ListAiAdapter extends BaseAiAdapter {
6717
6849
 
6718
6850
  class PraxisListMetricComponent {
6719
6851
  metric;
6852
+ leftIconNodes() {
6853
+ return this.metric?.icon ? [this.buildIconNode()] : [];
6854
+ }
6855
+ rightIconNodes() {
6856
+ return this.metric?.icon ? [this.buildIconNode()] : [];
6857
+ }
6858
+ valueRowNodes() {
6859
+ const nodes = [
6860
+ {
6861
+ type: 'text',
6862
+ text: String(this.metric?.value ?? ''),
6863
+ className: this.joinClasses('p-list-metric__value', this.metric?.valueClass),
6864
+ style: this.parseInlineStyle(this.metric?.valueStyle),
6865
+ },
6866
+ ];
6867
+ if (this.metric?.layout === 'value+caption' && this.metric?.caption) {
6868
+ nodes.push({
6869
+ type: 'text',
6870
+ text: String(this.metric.caption),
6871
+ className: 'p-list-metric__caption p-list-metric__caption--inline',
6872
+ });
6873
+ }
6874
+ return nodes;
6875
+ }
6876
+ captionNodes() {
6877
+ return this.metric?.caption
6878
+ ? [
6879
+ {
6880
+ type: 'text',
6881
+ text: String(this.metric.caption),
6882
+ className: 'p-list-metric__caption',
6883
+ },
6884
+ ]
6885
+ : [];
6886
+ }
6887
+ belowProgressCaptionNodes() {
6888
+ return this.metric?.caption
6889
+ ? [
6890
+ {
6891
+ type: 'text',
6892
+ text: String(this.metric.caption),
6893
+ className: 'p-list-metric__caption p-list-metric__caption--below-progress',
6894
+ },
6895
+ ]
6896
+ : [];
6897
+ }
6898
+ subcaptionNodes() {
6899
+ return this.metric?.subcaption
6900
+ ? [
6901
+ {
6902
+ type: 'text',
6903
+ text: String(this.metric.subcaption),
6904
+ className: 'p-list-metric__subcaption',
6905
+ },
6906
+ ]
6907
+ : [];
6908
+ }
6720
6909
  metricClasses() {
6721
6910
  const layoutClass = String(this.metric?.layout || 'value-only').replaceAll('+', '-');
6722
6911
  return [
@@ -6739,6 +6928,38 @@ class PraxisListMetricComponent {
6739
6928
  this.metric?.layout !== 'value-only' &&
6740
6929
  this.metric?.layout !== 'value+caption');
6741
6930
  }
6931
+ buildIconNode() {
6932
+ return {
6933
+ type: 'icon',
6934
+ icon: String(this.metric?.icon ?? ''),
6935
+ };
6936
+ }
6937
+ joinClasses(...parts) {
6938
+ const normalized = parts
6939
+ .map((part) => String(part || '').trim())
6940
+ .filter(Boolean);
6941
+ return normalized.length ? normalized.join(' ') : undefined;
6942
+ }
6943
+ parseInlineStyle(inlineStyle) {
6944
+ const source = String(inlineStyle || '').trim();
6945
+ if (!source) {
6946
+ return undefined;
6947
+ }
6948
+ const entries = source
6949
+ .split(';')
6950
+ .map((part) => part.trim())
6951
+ .filter(Boolean)
6952
+ .map((part) => {
6953
+ const separator = part.indexOf(':');
6954
+ if (separator === -1)
6955
+ return null;
6956
+ const key = part.slice(0, separator).trim();
6957
+ const value = part.slice(separator + 1).trim();
6958
+ return key && value ? [key, value] : null;
6959
+ })
6960
+ .filter((entry) => !!entry);
6961
+ return entries.length ? Object.fromEntries(entries) : undefined;
6962
+ }
6742
6963
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: PraxisListMetricComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
6743
6964
  static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.17", type: PraxisListMetricComponent, isStandalone: true, selector: "praxis-list-metric", inputs: { metric: "metric" }, ngImport: i0, template: `
6744
6965
  <div
@@ -6756,25 +6977,13 @@ class PraxisListMetricComponent {
6756
6977
  class="p-list-metric__icon"
6757
6978
  [style.cssText]="metric?.iconStyle || ''"
6758
6979
  >
6759
- <mat-icon [praxisIcon]="metric?.icon"></mat-icon>
6980
+ <praxis-rich-content [nodes]="leftIconNodes()"></praxis-rich-content>
6760
6981
  </span>
6761
6982
  }
6762
6983
 
6763
6984
  <div class="p-list-metric__content">
6764
6985
  <div class="p-list-metric__value-row">
6765
- <span
6766
- class="p-list-metric__value"
6767
- [ngClass]="metric?.valueClass"
6768
- [style.cssText]="metric?.valueStyle || ''"
6769
- >
6770
- {{ metric?.value }}
6771
- </span>
6772
-
6773
- @if (metric?.layout === 'value+caption' && metric?.caption) {
6774
- <span class="p-list-metric__caption p-list-metric__caption--inline">
6775
- {{ metric.caption }}
6776
- </span>
6777
- }
6986
+ <praxis-rich-content [nodes]="valueRowNodes()"></praxis-rich-content>
6778
6987
  </div>
6779
6988
 
6780
6989
  @if (
@@ -6782,11 +6991,11 @@ class PraxisListMetricComponent {
6782
6991
  metric?.caption &&
6783
6992
  metric?.captionPosition !== 'below-progress'
6784
6993
  ) {
6785
- <div class="p-list-metric__caption">{{ metric.caption }}</div>
6994
+ <praxis-rich-content [nodes]="captionNodes()"></praxis-rich-content>
6786
6995
  }
6787
6996
 
6788
6997
  @if (metric?.subcaption) {
6789
- <div class="p-list-metric__subcaption">{{ metric.subcaption }}</div>
6998
+ <praxis-rich-content [nodes]="subcaptionNodes()"></praxis-rich-content>
6790
6999
  }
6791
7000
  </div>
6792
7001
 
@@ -6795,7 +7004,7 @@ class PraxisListMetricComponent {
6795
7004
  class="p-list-metric__icon p-list-metric__icon--right"
6796
7005
  [style.cssText]="metric?.iconStyle || ''"
6797
7006
  >
6798
- <mat-icon [praxisIcon]="metric?.icon"></mat-icon>
7007
+ <praxis-rich-content [nodes]="rightIconNodes()"></praxis-rich-content>
6799
7008
  </span>
6800
7009
  }
6801
7010
  </div>
@@ -6826,16 +7035,14 @@ class PraxisListMetricComponent {
6826
7035
  metric?.caption &&
6827
7036
  metric?.captionPosition === 'below-progress'
6828
7037
  ) {
6829
- <div class="p-list-metric__caption p-list-metric__caption--below-progress">
6830
- {{ metric.caption }}
6831
- </div>
7038
+ <praxis-rich-content [nodes]="belowProgressCaptionNodes()"></praxis-rich-content>
6832
7039
  }
6833
7040
  </div>
6834
- `, isInline: true, styles: [":host{display:block;min-width:0}.p-list-metric{--p-list-metric-tone: currentColor;--p-list-metric-progress-fill: var( --p-list-metric-tone, var(--p-list-accent) );--p-list-metric-progress-track: color-mix( in srgb, var(--p-list-metric-progress-fill) 18%, transparent );display:grid;gap:4px;min-width:0;color:var(--p-list-metric-tone, inherit)}.p-list-metric--align-start{justify-items:start;text-align:start}.p-list-metric--align-center{justify-items:center;text-align:center}.p-list-metric--align-end{justify-items:end;text-align:end}.p-list-metric--tone-positive{--p-list-metric-tone: #2f7d32}.p-list-metric--tone-warning{--p-list-metric-tone: #b26a00}.p-list-metric--tone-negative{--p-list-metric-tone: #b3261e}.p-list-metric--tone-neutral{--p-list-metric-tone: var(--p-list-foreground-muted)}.p-list-metric__label{font-size:.7rem;font-weight:700;letter-spacing:.06em;text-transform:uppercase;color:var(--p-list-foreground-muted)}.p-list-metric__main{display:grid;align-items:center;gap:8px;min-width:0}.p-list-metric--layout-icon-value-caption .p-list-metric__main{grid-template-columns:auto minmax(0,1fr)}.p-list-metric--layout-stacked-center .p-list-metric__main{justify-items:center;text-align:center}.p-list-metric--icon-right .p-list-metric__main{grid-template-columns:minmax(0,1fr) auto}.p-list-metric__icon{display:inline-flex;align-items:center;justify-content:center;color:var(--p-list-metric-tone, inherit)}.p-list-metric__icon--right{order:2}.p-list-metric__icon mat-icon{width:1rem;height:1rem;font-size:1rem}.p-list-metric__content{display:grid;gap:2px;min-width:0}.p-list-metric__value-row{display:flex;align-items:baseline;gap:6px;min-width:0;flex-wrap:wrap}.p-list-metric--layout-stacked-center .p-list-metric__value-row{justify-content:center}.p-list-metric__value{font-size:.95rem;font-weight:700;line-height:1.1;min-width:0}.p-list-metric__caption,.p-list-metric__subcaption{font-size:.72rem;line-height:1.2;color:var(--p-list-foreground-muted)}.p-list-metric__caption--inline{display:inline-flex;align-items:center}.p-list-metric__progress{width:100%;height:4px;border-radius:999px;overflow:hidden;background:var(--p-list-metric-progress-track)}.p-list-metric__progress-value{display:block;height:100%;border-radius:inherit;background:var(--p-list-metric-progress-fill)}.p-list-metric__progress--indeterminate{position:relative}.p-list-metric__progress--indeterminate .p-list-metric__progress-value{width:40%!important;animation:p-list-metric-progress 1.2s ease-in-out infinite}@keyframes p-list-metric-progress{0%{transform:translate(-100%)}to{transform:translate(250%)}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { 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"] }] });
7041
+ `, isInline: true, styles: [":host{display:block;min-width:0}.p-list-metric{--p-list-metric-tone: currentColor;--p-list-metric-progress-fill: var( --p-list-metric-tone, var(--p-list-accent) );--p-list-metric-progress-track: color-mix( in srgb, var(--p-list-metric-progress-fill) 18%, transparent );display:grid;gap:4px;min-width:0;color:var(--p-list-metric-tone, inherit)}.p-list-metric--align-start{justify-items:start;text-align:start}.p-list-metric--align-center{justify-items:center;text-align:center}.p-list-metric--align-end{justify-items:end;text-align:end}.p-list-metric--tone-positive{--p-list-metric-tone: #2f7d32}.p-list-metric--tone-warning{--p-list-metric-tone: #b26a00}.p-list-metric--tone-negative{--p-list-metric-tone: #b3261e}.p-list-metric--tone-neutral{--p-list-metric-tone: var(--p-list-foreground-muted)}.p-list-metric__label{font-size:.7rem;font-weight:700;letter-spacing:.06em;text-transform:uppercase;color:var(--p-list-foreground-muted)}.p-list-metric__main{display:grid;align-items:center;gap:8px;min-width:0}.p-list-metric--layout-icon-value-caption .p-list-metric__main{grid-template-columns:auto minmax(0,1fr)}.p-list-metric--layout-stacked-center .p-list-metric__main{justify-items:center;text-align:center}.p-list-metric--icon-right .p-list-metric__main{grid-template-columns:minmax(0,1fr) auto}.p-list-metric__icon{display:inline-flex;align-items:center;justify-content:center;color:var(--p-list-metric-tone, inherit)}.p-list-metric__icon--right{order:2}.p-list-metric__icon mat-icon{width:1rem;height:1rem;font-size:1rem}.p-list-metric__content{display:grid;gap:2px;min-width:0}.p-list-metric__value-row{display:flex;align-items:baseline;gap:6px;min-width:0;flex-wrap:wrap}.p-list-metric--layout-stacked-center .p-list-metric__value-row{justify-content:center}.p-list-metric__value{font-size:.95rem;font-weight:700;line-height:1.1;min-width:0}.p-list-metric__caption,.p-list-metric__subcaption{font-size:.72rem;line-height:1.2;color:var(--p-list-foreground-muted)}.p-list-metric__caption--inline{display:inline-flex;align-items:center}.p-list-metric__progress{width:100%;height:4px;border-radius:999px;overflow:hidden;background:var(--p-list-metric-progress-track)}.p-list-metric__progress-value{display:block;height:100%;border-radius:inherit;background:var(--p-list-metric-progress-fill)}.p-list-metric__progress--indeterminate{position:relative}.p-list-metric__progress--indeterminate .p-list-metric__progress-value{width:40%!important;animation:p-list-metric-progress 1.2s ease-in-out infinite}@keyframes p-list-metric-progress{0%{transform:translate(-100%)}to{transform:translate(250%)}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "component", type: PraxisRichContent, selector: "praxis-rich-content", inputs: ["document", "nodes", "context", "hostCapabilities", "rootClassName"] }] });
6835
7042
  }
6836
7043
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: PraxisListMetricComponent, decorators: [{
6837
7044
  type: Component,
6838
- args: [{ selector: 'praxis-list-metric', standalone: true, imports: [CommonModule, MatIconModule, PraxisIconDirective], template: `
7045
+ args: [{ selector: 'praxis-list-metric', standalone: true, imports: [CommonModule, PraxisRichContent], template: `
6839
7046
  <div
6840
7047
  class="p-list-metric"
6841
7048
  [ngClass]="metricClasses()"
@@ -6851,25 +7058,13 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImpo
6851
7058
  class="p-list-metric__icon"
6852
7059
  [style.cssText]="metric?.iconStyle || ''"
6853
7060
  >
6854
- <mat-icon [praxisIcon]="metric?.icon"></mat-icon>
7061
+ <praxis-rich-content [nodes]="leftIconNodes()"></praxis-rich-content>
6855
7062
  </span>
6856
7063
  }
6857
7064
 
6858
7065
  <div class="p-list-metric__content">
6859
7066
  <div class="p-list-metric__value-row">
6860
- <span
6861
- class="p-list-metric__value"
6862
- [ngClass]="metric?.valueClass"
6863
- [style.cssText]="metric?.valueStyle || ''"
6864
- >
6865
- {{ metric?.value }}
6866
- </span>
6867
-
6868
- @if (metric?.layout === 'value+caption' && metric?.caption) {
6869
- <span class="p-list-metric__caption p-list-metric__caption--inline">
6870
- {{ metric.caption }}
6871
- </span>
6872
- }
7067
+ <praxis-rich-content [nodes]="valueRowNodes()"></praxis-rich-content>
6873
7068
  </div>
6874
7069
 
6875
7070
  @if (
@@ -6877,11 +7072,11 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImpo
6877
7072
  metric?.caption &&
6878
7073
  metric?.captionPosition !== 'below-progress'
6879
7074
  ) {
6880
- <div class="p-list-metric__caption">{{ metric.caption }}</div>
7075
+ <praxis-rich-content [nodes]="captionNodes()"></praxis-rich-content>
6881
7076
  }
6882
7077
 
6883
7078
  @if (metric?.subcaption) {
6884
- <div class="p-list-metric__subcaption">{{ metric.subcaption }}</div>
7079
+ <praxis-rich-content [nodes]="subcaptionNodes()"></praxis-rich-content>
6885
7080
  }
6886
7081
  </div>
6887
7082
 
@@ -6890,7 +7085,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImpo
6890
7085
  class="p-list-metric__icon p-list-metric__icon--right"
6891
7086
  [style.cssText]="metric?.iconStyle || ''"
6892
7087
  >
6893
- <mat-icon [praxisIcon]="metric?.icon"></mat-icon>
7088
+ <praxis-rich-content [nodes]="rightIconNodes()"></praxis-rich-content>
6894
7089
  </span>
6895
7090
  }
6896
7091
  </div>
@@ -6921,9 +7116,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImpo
6921
7116
  metric?.caption &&
6922
7117
  metric?.captionPosition === 'below-progress'
6923
7118
  ) {
6924
- <div class="p-list-metric__caption p-list-metric__caption--below-progress">
6925
- {{ metric.caption }}
6926
- </div>
7119
+ <praxis-rich-content [nodes]="belowProgressCaptionNodes()"></praxis-rich-content>
6927
7120
  }
6928
7121
  </div>
6929
7122
  `, styles: [":host{display:block;min-width:0}.p-list-metric{--p-list-metric-tone: currentColor;--p-list-metric-progress-fill: var( --p-list-metric-tone, var(--p-list-accent) );--p-list-metric-progress-track: color-mix( in srgb, var(--p-list-metric-progress-fill) 18%, transparent );display:grid;gap:4px;min-width:0;color:var(--p-list-metric-tone, inherit)}.p-list-metric--align-start{justify-items:start;text-align:start}.p-list-metric--align-center{justify-items:center;text-align:center}.p-list-metric--align-end{justify-items:end;text-align:end}.p-list-metric--tone-positive{--p-list-metric-tone: #2f7d32}.p-list-metric--tone-warning{--p-list-metric-tone: #b26a00}.p-list-metric--tone-negative{--p-list-metric-tone: #b3261e}.p-list-metric--tone-neutral{--p-list-metric-tone: var(--p-list-foreground-muted)}.p-list-metric__label{font-size:.7rem;font-weight:700;letter-spacing:.06em;text-transform:uppercase;color:var(--p-list-foreground-muted)}.p-list-metric__main{display:grid;align-items:center;gap:8px;min-width:0}.p-list-metric--layout-icon-value-caption .p-list-metric__main{grid-template-columns:auto minmax(0,1fr)}.p-list-metric--layout-stacked-center .p-list-metric__main{justify-items:center;text-align:center}.p-list-metric--icon-right .p-list-metric__main{grid-template-columns:minmax(0,1fr) auto}.p-list-metric__icon{display:inline-flex;align-items:center;justify-content:center;color:var(--p-list-metric-tone, inherit)}.p-list-metric__icon--right{order:2}.p-list-metric__icon mat-icon{width:1rem;height:1rem;font-size:1rem}.p-list-metric__content{display:grid;gap:2px;min-width:0}.p-list-metric__value-row{display:flex;align-items:baseline;gap:6px;min-width:0;flex-wrap:wrap}.p-list-metric--layout-stacked-center .p-list-metric__value-row{justify-content:center}.p-list-metric__value{font-size:.95rem;font-weight:700;line-height:1.1;min-width:0}.p-list-metric__caption,.p-list-metric__subcaption{font-size:.72rem;line-height:1.2;color:var(--p-list-foreground-muted)}.p-list-metric__caption--inline{display:inline-flex;align-items:center}.p-list-metric__progress{width:100%;height:4px;border-radius:999px;overflow:hidden;background:var(--p-list-metric-progress-track)}.p-list-metric__progress-value{display:block;height:100%;border-radius:inherit;background:var(--p-list-metric-progress-fill)}.p-list-metric__progress--indeterminate{position:relative}.p-list-metric__progress--indeterminate .p-list-metric__progress-value{width:40%!important;animation:p-list-metric-progress 1.2s ease-in-out infinite}@keyframes p-list-metric-progress{0%{transform:translate(-100%)}to{transform:translate(250%)}}\n"] }]
@@ -6966,30 +7159,41 @@ class ExecutiveAccountIdentityComponent {
6966
7159
  ? `Segmento ${this.displaySegmentLabel}`
6967
7160
  : undefined;
6968
7161
  }
7162
+ get titleNodes() {
7163
+ const nodes = [];
7164
+ if (this.displayTitle) {
7165
+ nodes.push({
7166
+ type: 'text',
7167
+ text: this.displayTitle,
7168
+ className: 'account-identity__title',
7169
+ });
7170
+ }
7171
+ if (this.displayMarkerIcon) {
7172
+ nodes.push({
7173
+ type: 'icon',
7174
+ icon: this.displayMarkerIcon,
7175
+ className: 'account-identity__marker',
7176
+ });
7177
+ }
7178
+ return nodes;
7179
+ }
6969
7180
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: ExecutiveAccountIdentityComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
6970
7181
  static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.17", type: ExecutiveAccountIdentityComponent, isStandalone: true, selector: "praxis-executive-account-identity", inputs: { title: "title", markerIcon: "markerIcon", segmentVariant: "segmentVariant", segmentLabel: "segmentLabel", accountType: "accountType", since: "since" }, ngImport: i0, template: `
6971
7182
  <span class="account-identity">
6972
7183
  <span class="account-identity__title-row">
6973
- @if (displayTitle) {
6974
- <span class="account-identity__title">{{ displayTitle }}</span>
6975
- }
6976
- @if (displayMarkerIcon) {
6977
- <mat-icon
6978
- class="account-identity__marker"
6979
- [praxisIcon]="displayMarkerIcon"
6980
- aria-hidden="true"
6981
- ></mat-icon>
6982
- }
7184
+ <praxis-rich-content
7185
+ rootClassName="account-identity__title-content"
7186
+ [nodes]="titleNodes"
7187
+ ></praxis-rich-content>
6983
7188
  </span>
6984
7189
  @if (hasSubtitle) {
6985
7190
  <span class="account-identity__subtitle-row">
6986
7191
  @if (displaySegmentLabel) {
6987
7192
  <praxis-executive-badge
6988
7193
  [variant]="segmentVariant"
7194
+ [label]="displaySegmentLabel"
6989
7195
  [ariaLabel]="segmentAriaLabel"
6990
- >
6991
- {{ displaySegmentLabel }}
6992
- </praxis-executive-badge>
7196
+ ></praxis-executive-badge>
6993
7197
  }
6994
7198
  @if (displayAccountType) {
6995
7199
  <span class="account-identity__meta">{{ displayAccountType }}</span>
@@ -7003,38 +7207,30 @@ class ExecutiveAccountIdentityComponent {
7003
7207
  </span>
7004
7208
  }
7005
7209
  </span>
7006
- `, isInline: true, styles: [":host{display:inline-flex;min-width:0}.account-identity{display:inline-flex;flex-direction:column;gap:4px;min-width:0}.account-identity__title-row{display:inline-flex;align-items:center;gap:8px;min-width:0}.account-identity__title{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:1.05rem;font-weight:800;letter-spacing:-.016em;color:#183046;line-height:1.16}.account-identity__marker{color:#b89536;font-size:15px;width:15px;height:15px;flex-shrink:0;transform:translateY(1px)}.account-identity__subtitle-row{display:inline-flex;align-items:center;flex-wrap:wrap;gap:7px;min-width:0}.account-identity__meta{display:inline-flex;align-items:center;color:#7f90a4;white-space:nowrap;font-size:.76rem;line-height:1.18}.account-identity__separator{color:#a5b0bc;font-size:.74rem;line-height:1}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { 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: "component", type: ExecutiveBadgeComponent, selector: "praxis-executive-badge", inputs: ["ariaLabel", "variant"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
7210
+ `, isInline: true, styles: [":host{display:inline-flex;min-width:0}.account-identity{display:inline-flex;flex-direction:column;gap:4px;min-width:0}.account-identity__title-row{display:inline-flex;align-items:center;min-width:0}.account-identity__title-content{display:inline-flex;align-items:center;gap:8px;min-width:0}.account-identity__title{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:1.05rem;font-weight:800;letter-spacing:-.016em;color:#183046;line-height:1.16}.account-identity__marker{color:#b89536;font-size:15px!important;width:15px!important;height:15px!important;flex-shrink:0;transform:translateY(1px)}.account-identity__subtitle-row{display:inline-flex;align-items:center;flex-wrap:wrap;gap:7px;min-width:0}.account-identity__meta{display:inline-flex;align-items:center;color:#7f90a4;white-space:nowrap;font-size:.76rem;line-height:1.18}.account-identity__separator{color:#a5b0bc;font-size:.74rem;line-height:1}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: PraxisRichContent, selector: "praxis-rich-content", inputs: ["document", "nodes", "context", "hostCapabilities", "rootClassName"] }, { kind: "component", type: ExecutiveBadgeComponent, selector: "praxis-executive-badge", inputs: ["ariaLabel", "label", "variant"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
7007
7211
  }
7008
7212
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: ExecutiveAccountIdentityComponent, decorators: [{
7009
7213
  type: Component,
7010
7214
  args: [{ selector: 'praxis-executive-account-identity', standalone: true, imports: [
7011
7215
  CommonModule,
7012
- MatIconModule,
7013
- PraxisIconDirective,
7216
+ PraxisRichContent,
7014
7217
  ExecutiveBadgeComponent,
7015
7218
  ], changeDetection: ChangeDetectionStrategy.OnPush, template: `
7016
7219
  <span class="account-identity">
7017
7220
  <span class="account-identity__title-row">
7018
- @if (displayTitle) {
7019
- <span class="account-identity__title">{{ displayTitle }}</span>
7020
- }
7021
- @if (displayMarkerIcon) {
7022
- <mat-icon
7023
- class="account-identity__marker"
7024
- [praxisIcon]="displayMarkerIcon"
7025
- aria-hidden="true"
7026
- ></mat-icon>
7027
- }
7221
+ <praxis-rich-content
7222
+ rootClassName="account-identity__title-content"
7223
+ [nodes]="titleNodes"
7224
+ ></praxis-rich-content>
7028
7225
  </span>
7029
7226
  @if (hasSubtitle) {
7030
7227
  <span class="account-identity__subtitle-row">
7031
7228
  @if (displaySegmentLabel) {
7032
7229
  <praxis-executive-badge
7033
7230
  [variant]="segmentVariant"
7231
+ [label]="displaySegmentLabel"
7034
7232
  [ariaLabel]="segmentAriaLabel"
7035
- >
7036
- {{ displaySegmentLabel }}
7037
- </praxis-executive-badge>
7233
+ ></praxis-executive-badge>
7038
7234
  }
7039
7235
  @if (displayAccountType) {
7040
7236
  <span class="account-identity__meta">{{ displayAccountType }}</span>
@@ -7048,7 +7244,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImpo
7048
7244
  </span>
7049
7245
  }
7050
7246
  </span>
7051
- `, styles: [":host{display:inline-flex;min-width:0}.account-identity{display:inline-flex;flex-direction:column;gap:4px;min-width:0}.account-identity__title-row{display:inline-flex;align-items:center;gap:8px;min-width:0}.account-identity__title{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:1.05rem;font-weight:800;letter-spacing:-.016em;color:#183046;line-height:1.16}.account-identity__marker{color:#b89536;font-size:15px;width:15px;height:15px;flex-shrink:0;transform:translateY(1px)}.account-identity__subtitle-row{display:inline-flex;align-items:center;flex-wrap:wrap;gap:7px;min-width:0}.account-identity__meta{display:inline-flex;align-items:center;color:#7f90a4;white-space:nowrap;font-size:.76rem;line-height:1.18}.account-identity__separator{color:#a5b0bc;font-size:.74rem;line-height:1}\n"] }]
7247
+ `, styles: [":host{display:inline-flex;min-width:0}.account-identity{display:inline-flex;flex-direction:column;gap:4px;min-width:0}.account-identity__title-row{display:inline-flex;align-items:center;min-width:0}.account-identity__title-content{display:inline-flex;align-items:center;gap:8px;min-width:0}.account-identity__title{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:1.05rem;font-weight:800;letter-spacing:-.016em;color:#183046;line-height:1.16}.account-identity__marker{color:#b89536;font-size:15px!important;width:15px!important;height:15px!important;flex-shrink:0;transform:translateY(1px)}.account-identity__subtitle-row{display:inline-flex;align-items:center;flex-wrap:wrap;gap:7px;min-width:0}.account-identity__meta{display:inline-flex;align-items:center;color:#7f90a4;white-space:nowrap;font-size:.76rem;line-height:1.18}.account-identity__separator{color:#a5b0bc;font-size:.74rem;line-height:1}\n"] }]
7052
7248
  }], propDecorators: { title: [{
7053
7249
  type: Input
7054
7250
  }], markerIcon: [{
@@ -7099,47 +7295,53 @@ class ExecutiveOwnerSummaryComponent {
7099
7295
  get displayIcon() {
7100
7296
  return String(this.icon || '').trim();
7101
7297
  }
7298
+ get ownerSummaryNodes() {
7299
+ const nodes = [
7300
+ {
7301
+ type: 'icon',
7302
+ icon: this.displayIcon,
7303
+ className: 'owner-summary__icon',
7304
+ },
7305
+ ];
7306
+ if (this.hasName) {
7307
+ nodes.push({
7308
+ type: 'text',
7309
+ text: this.displayName,
7310
+ className: 'owner-summary__name',
7311
+ });
7312
+ }
7313
+ return nodes;
7314
+ }
7102
7315
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: ExecutiveOwnerSummaryComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
7103
7316
  static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.17", type: ExecutiveOwnerSummaryComponent, isStandalone: true, selector: "praxis-executive-owner-summary", inputs: { name: "name", icon: "icon" }, ngImport: i0, template: `
7104
7317
  @if (displayIcon) {
7105
- <span class="owner-summary owner-summary--icon">
7106
- <mat-icon
7107
- class="owner-summary__icon"
7108
- [praxisIcon]="displayIcon"
7109
- aria-hidden="true"
7110
- ></mat-icon>
7111
- @if (hasName) {
7112
- <span class="owner-summary__name">{{ displayName }}</span>
7113
- }
7114
- </span>
7318
+ <praxis-rich-content
7319
+ class="owner-summary owner-summary--icon"
7320
+ rootClassName="owner-summary__content"
7321
+ [nodes]="ownerSummaryNodes"
7322
+ ></praxis-rich-content>
7115
7323
  } @else if (hasName) {
7116
7324
  <praxis-executive-owner [name]="displayName"></praxis-executive-owner>
7117
7325
  }
7118
- `, isInline: true, styles: [":host{display:inline-flex;min-width:0}.owner-summary{display:inline-flex;align-items:center;gap:9px;min-width:0;font-size:.82rem;color:#5b6f84;font-weight:500}.owner-summary__icon{width:20px;height:20px;font-size:20px;color:#8ea2b6;flex-shrink:0}.owner-summary__name{min-width:0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;line-height:1.15}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { 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: "component", type: ExecutiveOwnerComponent, selector: "praxis-executive-owner", inputs: ["name"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
7326
+ `, isInline: true, styles: [":host{display:inline-flex;min-width:0}.owner-summary{display:inline-flex;align-items:center;min-width:0;font-size:.82rem;color:#5b6f84;font-weight:500}.owner-summary__content{display:inline-flex;align-items:center;gap:9px;min-width:0}.owner-summary__icon{width:20px!important;height:20px!important;font-size:20px!important;color:#8ea2b6;flex-shrink:0}.owner-summary__name{min-width:0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;line-height:1.15}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: PraxisRichContent, selector: "praxis-rich-content", inputs: ["document", "nodes", "context", "hostCapabilities", "rootClassName"] }, { kind: "component", type: ExecutiveOwnerComponent, selector: "praxis-executive-owner", inputs: ["name"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
7119
7327
  }
7120
7328
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: ExecutiveOwnerSummaryComponent, decorators: [{
7121
7329
  type: Component,
7122
7330
  args: [{ selector: 'praxis-executive-owner-summary', standalone: true, imports: [
7123
7331
  CommonModule,
7124
- MatIconModule,
7125
- PraxisIconDirective,
7332
+ PraxisRichContent,
7126
7333
  ExecutiveOwnerComponent,
7127
7334
  ], changeDetection: ChangeDetectionStrategy.OnPush, template: `
7128
7335
  @if (displayIcon) {
7129
- <span class="owner-summary owner-summary--icon">
7130
- <mat-icon
7131
- class="owner-summary__icon"
7132
- [praxisIcon]="displayIcon"
7133
- aria-hidden="true"
7134
- ></mat-icon>
7135
- @if (hasName) {
7136
- <span class="owner-summary__name">{{ displayName }}</span>
7137
- }
7138
- </span>
7336
+ <praxis-rich-content
7337
+ class="owner-summary owner-summary--icon"
7338
+ rootClassName="owner-summary__content"
7339
+ [nodes]="ownerSummaryNodes"
7340
+ ></praxis-rich-content>
7139
7341
  } @else if (hasName) {
7140
7342
  <praxis-executive-owner [name]="displayName"></praxis-executive-owner>
7141
7343
  }
7142
- `, styles: [":host{display:inline-flex;min-width:0}.owner-summary{display:inline-flex;align-items:center;gap:9px;min-width:0;font-size:.82rem;color:#5b6f84;font-weight:500}.owner-summary__icon{width:20px;height:20px;font-size:20px;color:#8ea2b6;flex-shrink:0}.owner-summary__name{min-width:0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;line-height:1.15}\n"] }]
7344
+ `, styles: [":host{display:inline-flex;min-width:0}.owner-summary{display:inline-flex;align-items:center;min-width:0;font-size:.82rem;color:#5b6f84;font-weight:500}.owner-summary__content{display:inline-flex;align-items:center;gap:9px;min-width:0}.owner-summary__icon{width:20px!important;height:20px!important;font-size:20px!important;color:#8ea2b6;flex-shrink:0}.owner-summary__name{min-width:0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;line-height:1.15}\n"] }]
7143
7345
  }], propDecorators: { name: [{
7144
7346
  type: Input
7145
7347
  }], icon: [{
@@ -7229,17 +7431,15 @@ class PraxisListRuntimeComponentComponent {
7229
7431
  <praxis-executive-badge
7230
7432
  [variant]="badgeVariant()"
7231
7433
  [ariaLabel]="stringInput('ariaLabel') || undefined"
7232
- >
7233
- {{ badgeLabel() }}
7234
- </praxis-executive-badge>
7434
+ [label]="badgeLabel()"
7435
+ ></praxis-executive-badge>
7235
7436
  }
7236
7437
  @case ("praxis-executive-badge") {
7237
7438
  <praxis-executive-badge
7238
7439
  [variant]="badgeVariant()"
7239
7440
  [ariaLabel]="stringInput('ariaLabel') || undefined"
7240
- >
7241
- {{ badgeLabel() }}
7242
- </praxis-executive-badge>
7441
+ [label]="badgeLabel()"
7442
+ ></praxis-executive-badge>
7243
7443
  }
7244
7444
  @case ("executive-trailing") {
7245
7445
  <span class="exec-trailing-shell">
@@ -7260,7 +7460,7 @@ class PraxisListRuntimeComponentComponent {
7260
7460
  }
7261
7461
  }
7262
7462
  </span>
7263
- `, isInline: true, styles: [":host{display:inline-flex;min-width:0}.p-list-runtime-component{display:inline-flex;min-width:0}.p-list-runtime-component__unsupported{display:inline-flex;align-items:center;justify-content:center;width:.75rem;height:.75rem;min-width:.75rem;border:1px dashed var(--md-sys-color-outline-variant);border-radius:999px;overflow:hidden;color:transparent;font-size:0;line-height:0}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "component", type: ExecutiveAccountIdentityComponent, selector: "praxis-executive-account-identity", inputs: ["title", "markerIcon", "segmentVariant", "segmentLabel", "accountType", "since"] }, { kind: "component", type: ExecutiveAlertSummaryComponent, selector: "praxis-executive-alert-summary", inputs: ["alerts"] }, { kind: "component", type: ExecutiveAlertsComponent, selector: "praxis-executive-alerts", inputs: ["alerts"] }, { kind: "component", type: ExecutiveBadgeComponent, selector: "praxis-executive-badge", inputs: ["ariaLabel", "variant"] }, { kind: "component", type: ExecutiveOwnerComponent, selector: "praxis-executive-owner", inputs: ["name"] }, { kind: "component", type: ExecutiveOwnerSummaryComponent, selector: "praxis-executive-owner-summary", inputs: ["name", "icon"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
7463
+ `, isInline: true, styles: [":host{display:inline-flex;min-width:0}.p-list-runtime-component{display:inline-flex;min-width:0}.p-list-runtime-component__unsupported{display:inline-flex;align-items:center;justify-content:center;width:.75rem;height:.75rem;min-width:.75rem;border:1px dashed var(--md-sys-color-outline-variant);border-radius:999px;overflow:hidden;color:transparent;font-size:0;line-height:0}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "component", type: ExecutiveAccountIdentityComponent, selector: "praxis-executive-account-identity", inputs: ["title", "markerIcon", "segmentVariant", "segmentLabel", "accountType", "since"] }, { kind: "component", type: ExecutiveAlertSummaryComponent, selector: "praxis-executive-alert-summary", inputs: ["alerts"] }, { kind: "component", type: ExecutiveAlertsComponent, selector: "praxis-executive-alerts", inputs: ["alerts"] }, { kind: "component", type: ExecutiveBadgeComponent, selector: "praxis-executive-badge", inputs: ["ariaLabel", "label", "variant"] }, { kind: "component", type: ExecutiveOwnerComponent, selector: "praxis-executive-owner", inputs: ["name"] }, { kind: "component", type: ExecutiveOwnerSummaryComponent, selector: "praxis-executive-owner-summary", inputs: ["name", "icon"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
7264
7464
  }
7265
7465
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: PraxisListRuntimeComponentComponent, decorators: [{
7266
7466
  type: Component,
@@ -7325,17 +7525,15 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImpo
7325
7525
  <praxis-executive-badge
7326
7526
  [variant]="badgeVariant()"
7327
7527
  [ariaLabel]="stringInput('ariaLabel') || undefined"
7328
- >
7329
- {{ badgeLabel() }}
7330
- </praxis-executive-badge>
7528
+ [label]="badgeLabel()"
7529
+ ></praxis-executive-badge>
7331
7530
  }
7332
7531
  @case ("praxis-executive-badge") {
7333
7532
  <praxis-executive-badge
7334
7533
  [variant]="badgeVariant()"
7335
7534
  [ariaLabel]="stringInput('ariaLabel') || undefined"
7336
- >
7337
- {{ badgeLabel() }}
7338
- </praxis-executive-badge>
7535
+ [label]="badgeLabel()"
7536
+ ></praxis-executive-badge>
7339
7537
  }
7340
7538
  @case ("executive-trailing") {
7341
7539
  <span class="exec-trailing-shell">
@@ -7363,6 +7561,36 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImpo
7363
7561
 
7364
7562
  class PraxisListComposeComponent {
7365
7563
  compose;
7564
+ composeRichContentNodes(composeNode) {
7565
+ const items = Array.isArray(composeNode?.items) ? composeNode.items : [];
7566
+ const separator = typeof composeNode?.separator === 'string' && composeNode.separator.trim()
7567
+ ? composeNode.separator
7568
+ : null;
7569
+ const richItems = [];
7570
+ for (let index = 0; index < items.length; index += 1) {
7571
+ const richNode = this.mapRuntimeNodeToRichPresenter(items[index]);
7572
+ if (!richNode) {
7573
+ return null;
7574
+ }
7575
+ richItems.push(richNode);
7576
+ if (separator && index < items.length - 1) {
7577
+ richItems.push({
7578
+ type: 'text',
7579
+ text: separator,
7580
+ className: 'p-list-compose__separator',
7581
+ });
7582
+ }
7583
+ }
7584
+ return [
7585
+ {
7586
+ type: 'compose',
7587
+ direction: composeNode?.direction === 'column' ? 'column' : 'row',
7588
+ gap: this.normalizeGap(composeNode?.gap),
7589
+ wrap: composeNode?.wrap === true,
7590
+ items: richItems,
7591
+ },
7592
+ ];
7593
+ }
7366
7594
  composeClasses(composeNode) {
7367
7595
  const direction = composeNode?.direction === 'column' ? 'column' : 'row';
7368
7596
  return [
@@ -7395,6 +7623,98 @@ class PraxisListComposeComponent {
7395
7623
  ? `background:transparent;border:1px solid ${color};color:${color};`
7396
7624
  : `background:${color};color:#fff;`;
7397
7625
  }
7626
+ mapRuntimeNodeToRichPresenter(node) {
7627
+ switch (node?.type) {
7628
+ case 'text':
7629
+ case undefined:
7630
+ case null:
7631
+ return this.mapTextNode(node);
7632
+ case 'icon':
7633
+ return this.mapIconNode(node);
7634
+ case 'image':
7635
+ return this.mapImageNode(node);
7636
+ case 'chip':
7637
+ return this.mapChipNode(node);
7638
+ default:
7639
+ return null;
7640
+ }
7641
+ }
7642
+ mapTextNode(node) {
7643
+ return {
7644
+ type: 'text',
7645
+ text: String(node?.value ?? ''),
7646
+ className: node?.class,
7647
+ style: this.parseInlineStyle(node?.style),
7648
+ };
7649
+ }
7650
+ mapIconNode(node) {
7651
+ return {
7652
+ type: 'icon',
7653
+ icon: String(node?.value ?? ''),
7654
+ className: node?.class,
7655
+ style: this.parseInlineStyle(node?.style),
7656
+ };
7657
+ }
7658
+ mapImageNode(node) {
7659
+ return {
7660
+ type: 'image',
7661
+ src: String(node?.value ?? ''),
7662
+ alt: node?.imageAlt || '',
7663
+ className: node?.class,
7664
+ style: this.parseInlineStyle(node?.style),
7665
+ };
7666
+ }
7667
+ mapChipNode(node) {
7668
+ return {
7669
+ type: 'badge',
7670
+ label: String(node?.value ?? ''),
7671
+ className: node?.class,
7672
+ style: this.parseInlineStyle(node?.style),
7673
+ };
7674
+ }
7675
+ normalizeGap(gap) {
7676
+ switch (String(gap || '').trim()) {
7677
+ case '4px':
7678
+ case '0.25rem':
7679
+ case 'xs':
7680
+ return 'xs';
7681
+ case '8px':
7682
+ case '0.5rem':
7683
+ case 'sm':
7684
+ return 'sm';
7685
+ case '16px':
7686
+ case '1rem':
7687
+ case 'lg':
7688
+ return 'lg';
7689
+ case '20px':
7690
+ case '1.25rem':
7691
+ case 'xl':
7692
+ return 'xl';
7693
+ default:
7694
+ return gap ? 'md' : undefined;
7695
+ }
7696
+ }
7697
+ parseInlineStyle(inlineStyle) {
7698
+ const source = String(inlineStyle || '').trim();
7699
+ if (!source) {
7700
+ return undefined;
7701
+ }
7702
+ const entries = source
7703
+ .split(';')
7704
+ .map((part) => part.trim())
7705
+ .filter(Boolean)
7706
+ .map((part) => {
7707
+ const separator = part.indexOf(':');
7708
+ if (separator === -1) {
7709
+ return null;
7710
+ }
7711
+ const key = part.slice(0, separator).trim();
7712
+ const value = part.slice(separator + 1).trim();
7713
+ return key && value ? [key, value] : null;
7714
+ })
7715
+ .filter((entry) => !!entry);
7716
+ return entries.length ? Object.fromEntries(entries) : undefined;
7717
+ }
7398
7718
  ratingRange(node) {
7399
7719
  const max = Number(node?.props?.rating?.max ?? 5);
7400
7720
  return Array.from({ length: Number.isFinite(max) && max > 0 ? max : 5 });
@@ -7425,14 +7745,18 @@ class PraxisListComposeComponent {
7425
7745
  [ngClass]="composeClasses(composeNode)"
7426
7746
  [style.cssText]="composeStyle(composeNode)"
7427
7747
  >
7428
- @for (node of composeNode?.items || []; track trackNode($index, node); let isLast = $last) {
7429
- <ng-container
7430
- *ngTemplateOutlet="renderNode; context: { $implicit: node }"
7431
- ></ng-container>
7432
- @if (!isLast && composeNode?.separator) {
7433
- <span class="p-list-compose__separator">{{
7434
- composeNode.separator
7435
- }}</span>
7748
+ @if (composeRichContentNodes(composeNode); as richNodes) {
7749
+ <praxis-rich-content [nodes]="richNodes"></praxis-rich-content>
7750
+ } @else {
7751
+ @for (node of composeNode?.items || []; track trackNode($index, node); let isLast = $last) {
7752
+ <ng-container
7753
+ *ngTemplateOutlet="renderNode; context: { $implicit: node }"
7754
+ ></ng-container>
7755
+ @if (!isLast && composeNode?.separator) {
7756
+ <span class="p-list-compose__separator">{{
7757
+ composeNode.separator
7758
+ }}</span>
7759
+ }
7436
7760
  }
7437
7761
  }
7438
7762
  </div>
@@ -7544,7 +7868,7 @@ class PraxisListComposeComponent {
7544
7868
  }
7545
7869
  }
7546
7870
  </ng-template>
7547
- `, isInline: true, styles: [":host{display:block;min-width:0}.p-list-compose{display:flex;min-width:0}.p-list-compose--direction-row{flex-direction:row}.p-list-compose--direction-column{flex-direction:column}.p-list-compose--align-start{align-items:flex-start}.p-list-compose--align-center{align-items:center}.p-list-compose--align-end{align-items:flex-end}.p-list-compose--wrap{flex-wrap:wrap}.p-list-compose--nowrap{flex-wrap:nowrap}.p-list-compose__separator{color:var(--p-list-foreground-muted);white-space:pre-wrap}.p-list-compose__unsupported{display:inline-flex;align-items:center;justify-content:center;width:.75rem;height:.75rem;min-width:.75rem;border:1px dashed var(--md-sys-color-outline-variant);border-radius:999px;overflow:hidden;color:transparent;font-size:0;line-height:0}\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: MatChipsModule }, { kind: "component", type: i5.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: 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: "component", type: PraxisListMetricComponent, selector: "praxis-list-metric", inputs: ["metric"] }, { kind: "component", type: PraxisListRuntimeComponentComponent, selector: "praxis-list-runtime-component", inputs: ["component"] }] });
7871
+ `, isInline: true, styles: [":host{display:block;min-width:0}.p-list-compose{display:flex;min-width:0}.p-list-compose--direction-row{flex-direction:row}.p-list-compose--direction-column{flex-direction:column}.p-list-compose--align-start{align-items:flex-start}.p-list-compose--align-center{align-items:center}.p-list-compose--align-end{align-items:flex-end}.p-list-compose--wrap{flex-wrap:wrap}.p-list-compose--nowrap{flex-wrap:nowrap}.p-list-compose__separator{color:var(--p-list-foreground-muted);white-space:pre-wrap}.p-list-compose__unsupported{display:inline-flex;align-items:center;justify-content:center;width:.75rem;height:.75rem;min-width:.75rem;border:1px dashed var(--md-sys-color-outline-variant);border-radius:999px;overflow:hidden;color:transparent;font-size:0;line-height:0}\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: MatChipsModule }, { kind: "component", type: i5.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: 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: "component", type: PraxisRichContent, selector: "praxis-rich-content", inputs: ["document", "nodes", "context", "hostCapabilities", "rootClassName"] }, { kind: "component", type: PraxisListMetricComponent, selector: "praxis-list-metric", inputs: ["metric"] }, { kind: "component", type: PraxisListRuntimeComponentComponent, selector: "praxis-list-runtime-component", inputs: ["component"] }] });
7548
7872
  }
7549
7873
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: PraxisListComposeComponent, decorators: [{
7550
7874
  type: Component,
@@ -7553,6 +7877,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImpo
7553
7877
  MatChipsModule,
7554
7878
  MatIconModule,
7555
7879
  PraxisIconDirective,
7880
+ PraxisRichContent,
7556
7881
  PraxisListMetricComponent,
7557
7882
  PraxisListRuntimeComponentComponent,
7558
7883
  ], template: `
@@ -7566,14 +7891,18 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImpo
7566
7891
  [ngClass]="composeClasses(composeNode)"
7567
7892
  [style.cssText]="composeStyle(composeNode)"
7568
7893
  >
7569
- @for (node of composeNode?.items || []; track trackNode($index, node); let isLast = $last) {
7570
- <ng-container
7571
- *ngTemplateOutlet="renderNode; context: { $implicit: node }"
7572
- ></ng-container>
7573
- @if (!isLast && composeNode?.separator) {
7574
- <span class="p-list-compose__separator">{{
7575
- composeNode.separator
7576
- }}</span>
7894
+ @if (composeRichContentNodes(composeNode); as richNodes) {
7895
+ <praxis-rich-content [nodes]="richNodes"></praxis-rich-content>
7896
+ } @else {
7897
+ @for (node of composeNode?.items || []; track trackNode($index, node); let isLast = $last) {
7898
+ <ng-container
7899
+ *ngTemplateOutlet="renderNode; context: { $implicit: node }"
7900
+ ></ng-container>
7901
+ @if (!isLast && composeNode?.separator) {
7902
+ <span class="p-list-compose__separator">{{
7903
+ composeNode.separator
7904
+ }}</span>
7905
+ }
7577
7906
  }
7578
7907
  }
7579
7908
  </div>
@@ -8067,6 +8396,65 @@ class PraxisList {
8067
8396
  const templating = this.config?.templating;
8068
8397
  return String(templating?.[slot]?.imageAlt || '');
8069
8398
  }
8399
+ simpleRichContentNodes(node, options) {
8400
+ if (!node || typeof node !== 'object')
8401
+ return null;
8402
+ const type = String(node.type || 'text').trim();
8403
+ switch (type) {
8404
+ case 'icon':
8405
+ if (!String(node.value || '').trim() || this.isThemeColor(node.color)) {
8406
+ return null;
8407
+ }
8408
+ return [
8409
+ {
8410
+ type: 'icon',
8411
+ icon: String(node.value),
8412
+ className: node.class,
8413
+ style: this.mergeStyleRecords(this.parseInlineStyle(node.style), this.parseInlineStyle(this.iconStyle(node.color))),
8414
+ },
8415
+ ];
8416
+ case 'image':
8417
+ if (!String(node.value || '').trim() || node.badge?.value) {
8418
+ return null;
8419
+ }
8420
+ return [
8421
+ {
8422
+ type: 'image',
8423
+ src: String(node.value),
8424
+ alt: String(node.imageAlt || options?.imageAlt || ''),
8425
+ className: this.joinClasses('inline-image', node.class),
8426
+ style: this.parseInlineStyle(node.style),
8427
+ },
8428
+ ];
8429
+ case 'chip':
8430
+ if (this.isThemeColor(node.color))
8431
+ return null;
8432
+ return [
8433
+ {
8434
+ type: 'badge',
8435
+ label: String(node.value ?? ''),
8436
+ className: this.joinClasses(node.class, (node.variant || 'filled') === 'outlined'
8437
+ ? 'chip-outlined'
8438
+ : undefined),
8439
+ style: this.mergeStyleRecords(this.parseInlineStyle(this.joinStyles(this.chipStyle(node.color, node.variant), node.style ? ';' + node.style : undefined))),
8440
+ },
8441
+ ];
8442
+ case 'text':
8443
+ if (options?.slot === 'meta' && this.config?.templating?.metaPrefixIcon) {
8444
+ return null;
8445
+ }
8446
+ return [
8447
+ {
8448
+ type: 'text',
8449
+ text: String(node.value ?? ''),
8450
+ className: node.class,
8451
+ style: this.parseInlineStyle(node.style),
8452
+ },
8453
+ ];
8454
+ default:
8455
+ return null;
8456
+ }
8457
+ }
8070
8458
  rowLayoutAlignItems() {
8071
8459
  const rowLayout = this.config?.layout?.rowLayout;
8072
8460
  const alias = rowLayout?.itemAlignY;
@@ -8161,6 +8549,48 @@ class PraxisList {
8161
8549
  .map((line) => line.trim())
8162
8550
  .filter((line) => !!line);
8163
8551
  }
8552
+ featureRichContentNodes(item, feature) {
8553
+ if (!feature)
8554
+ return null;
8555
+ if (this.featureProgressPercent(item, feature.expr, feature.class) != null) {
8556
+ return null;
8557
+ }
8558
+ const lines = this.featureLabelLines(item, feature.expr);
8559
+ if (lines.length > 1) {
8560
+ return null;
8561
+ }
8562
+ const mode = this.featuresMode();
8563
+ const nodes = [];
8564
+ const icon = String(feature.icon || '').trim();
8565
+ if (icon && mode !== 'labels-only') {
8566
+ nodes.push({
8567
+ type: 'icon',
8568
+ icon,
8569
+ });
8570
+ }
8571
+ if (mode !== 'icons-only' && lines[0]) {
8572
+ nodes.push({
8573
+ type: 'text',
8574
+ text: lines[0],
8575
+ className: feature.class,
8576
+ style: this.parseInlineStyle(feature.style),
8577
+ });
8578
+ }
8579
+ if (!nodes.length) {
8580
+ return null;
8581
+ }
8582
+ if (nodes.length === 1) {
8583
+ return [nodes[0]];
8584
+ }
8585
+ return [
8586
+ {
8587
+ type: 'compose',
8588
+ direction: 'row',
8589
+ gap: 'sm',
8590
+ items: nodes,
8591
+ },
8592
+ ];
8593
+ }
8164
8594
  featureSemanticClass(item, expr, featureClass) {
8165
8595
  if (!(featureClass || '').includes('exec-metric--risk'))
8166
8596
  return null;
@@ -8399,6 +8829,31 @@ class PraxisList {
8399
8829
  .join(' ');
8400
8830
  return value || undefined;
8401
8831
  }
8832
+ parseInlineStyle(styleText) {
8833
+ const normalized = String(styleText || '').trim();
8834
+ if (!normalized)
8835
+ return undefined;
8836
+ const entries = normalized
8837
+ .split(';')
8838
+ .map((part) => part.trim())
8839
+ .filter(Boolean)
8840
+ .map((part) => {
8841
+ const separatorIndex = part.indexOf(':');
8842
+ if (separatorIndex <= 0)
8843
+ return null;
8844
+ const property = part.slice(0, separatorIndex).trim();
8845
+ const value = part.slice(separatorIndex + 1).trim();
8846
+ return property && value ? [property, value] : null;
8847
+ })
8848
+ .filter((entry) => Array.isArray(entry));
8849
+ if (!entries.length)
8850
+ return undefined;
8851
+ return Object.fromEntries(entries);
8852
+ }
8853
+ mergeStyleRecords(...styles) {
8854
+ const merged = Object.assign({}, ...styles.filter(Boolean));
8855
+ return Object.keys(merged).length ? merged : undefined;
8856
+ }
8402
8857
  featuresVisible() {
8403
8858
  const t = this.config?.templating;
8404
8859
  const has = (t?.features?.length || 0) > 0;
@@ -9154,7 +9609,7 @@ class PraxisList {
9154
9609
  .toLowerCase();
9155
9610
  if (!t)
9156
9611
  return '';
9157
- return t.replace(/\b\w/g, (m) => m.toUpperCase());
9612
+ return toTitleCase(t);
9158
9613
  }
9159
9614
  catch {
9160
9615
  return String(v ?? '');
@@ -9475,7 +9930,7 @@ class PraxisList {
9475
9930
  return [{ key: '', value: String(value) }];
9476
9931
  }
9477
9932
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: PraxisList, deps: [], target: i0.ɵɵFactoryTarget.Component });
9478
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.17", type: PraxisList, isStandalone: true, selector: "praxis-list", inputs: { config: "config", listId: "listId", componentInstanceId: "componentInstanceId", form: "form", enableCustomization: ["enableCustomization", "enableCustomization", booleanAttribute] }, outputs: { itemClick: "itemClick", actionClick: "actionClick", selectionChange: "selectionChange" }, providers: [GenericCrudService, ListDataService, providePraxisListI18n()], usesOnChanges: true, ngImport: i0, template: "<div\n class=\"praxis-list-root\"\n [ngClass]=\"skinClasses\"\n [attr.data-skin-scope]=\"skinScopeId\"\n [attr.aria-label]=\"config.a11y?.ariaLabel || null\"\n [attr.aria-labelledby]=\"config.a11y?.ariaLabelledBy || null\"\n>\n @if (inlineCss) {\n <style [attr.nonce]=\"cspNonce || null\" [textContent]=\"inlineCss\"></style>\n }\n\n @if (enableCustomization) {\n <div class=\"list-assistant\">\n <button\n mat-mini-fab\n type=\"button\"\n color=\"primary\"\n (click)=\"openConfigEditor()\"\n [matTooltip]=\"configEditorLabel()\"\n [attr.aria-label]=\"configEditorLabel()\"\n data-testid=\"praxis-list-open-config-editor\"\n >\n <mat-icon [praxisIcon]=\"'edit'\"></mat-icon>\n </button>\n <praxis-ai-assistant [adapter]=\"aiAdapter\"></praxis-ai-assistant>\n </div>\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=\"list-item-leading\">\n <div class=\"skeleton skeleton-avatar\"></div>\n </div>\n <div class=\"list-item-text\">\n <div class=\"skeleton skeleton-line w-60\"></div>\n @if (layoutLines > 1) {\n <div class=\"skeleton skeleton-line w-40\"></div>\n }\n </div>\n <div class=\"list-item-trailing\">\n <div class=\"skeleton skeleton-chip\"></div>\n </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=\"list-item-leading\">\n <div class=\"skeleton skeleton-avatar\"></div>\n </div>\n <div class=\"list-item-text\">\n <div class=\"skeleton skeleton-line w-60\"></div>\n @if (layoutLines > 1) {\n <div class=\"skeleton skeleton-line w-40\"></div>\n }\n </div>\n <div class=\"list-item-trailing\">\n <div class=\"skeleton skeleton-chip\"></div>\n </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 @if (emptyStateTemplate(); as empty) {\n @switch (empty.type) {\n @case (\"icon\") {\n <mat-icon\n [praxisIcon]=\"empty.value\"\n [ngClass]=\"empty.class\"\n [color]=\"isThemeColor(empty.color) ? empty.color : undefined\"\n [style.cssText]=\"\n (empty.style ? empty.style + ';' : '') +\n iconStyle(empty.color)\n \"\n ></mat-icon>\n }\n @case (\"image\") {\n <span\n class=\"inline-image\"\n [ngClass]=\"empty.class\"\n [style.cssText]=\"empty.style\"\n >\n <img\n [src]=\"empty.value\"\n [alt]=\"config.templating?.emptyState?.imageAlt || ''\"\n />\n @if (empty.badge?.value) {\n <mat-chip\n class=\"inline-badge\"\n [color]=\"\n isThemeColor(empty.badge?.color)\n ? empty.badge?.color\n : undefined\n \"\n [ngClass]=\"\n (empty.badge?.variant || 'filled') === 'outlined'\n ? 'chip-outlined'\n : ''\n \"\n [style.cssText]=\"\n chipStyle(empty.badge?.color, empty.badge?.variant)\n \"\n >{{ empty.badge?.value }}</mat-chip\n >\n }\n </span>\n }\n @case (\"chip\") {\n <mat-chip\n [color]=\"isThemeColor(empty.color) ? empty.color : undefined\"\n [ngClass]=\"[\n empty.class || '',\n (empty.variant || 'filled') === 'outlined'\n ? 'chip-outlined'\n : '',\n ]\"\n [style.cssText]=\"\n chipStyle(empty.color, empty.variant) +\n (empty.style ? ';' + empty.style : '')\n \"\n >{{ empty.value }}</mat-chip\n >\n }\n @case (\"rating\") {\n <span [ngClass]=\"empty.class\" [style.cssText]=\"empty.style\">\n @for (\n _ of ratingRange(empty);\n track $index;\n let idx = $index\n ) {\n <mat-icon\n [praxisIcon]=\"starIcon(idx, empty.value)\"\n [color]=\"ratingThemeColor(empty)\"\n [style.cssText]=\"ratingIconStyle(empty)\"\n ></mat-icon>\n }\n </span>\n }\n @case (\"html\") {\n <span\n [ngClass]=\"empty.class\"\n [style.cssText]=\"empty.style\"\n [innerHTML]=\"empty.value\"\n ></span>\n }\n @case (\"metric\") {\n <praxis-list-metric [metric]=\"empty\"></praxis-list-metric>\n }\n @case (\"compose\") {\n <praxis-list-compose [compose]=\"empty\"></praxis-list-compose>\n }\n @case (\"component\") {\n <praxis-list-runtime-component\n [component]=\"empty\"\n ></praxis-list-runtime-component>\n }\n @default {\n <span [ngClass]=\"empty.class\" [style.cssText]=\"empty.style\">{{\n empty.value\n }}</span>\n }\n }\n }\n </div>\n }\n }\n\n <ng-template\n #rowLayoutNode\n let-node\n let-slot=\"slot\"\n let-imageAlt=\"imageAlt\"\n >\n @switch (node?.type) {\n @case (\"icon\") {\n <mat-icon\n [praxisIcon]=\"node?.value\"\n [ngClass]=\"node?.class\"\n [color]=\"isThemeColor(node?.color) ? node?.color : undefined\"\n [style.cssText]=\"\n ((node?.style || '') ? node.style + ';' : '') +\n iconStyle(node?.color)\n \"\n ></mat-icon>\n }\n @case (\"image\") {\n <span\n class=\"inline-image\"\n [ngClass]=\"node?.class\"\n [style.cssText]=\"node?.style\"\n >\n <img [src]=\"node?.value\" [alt]=\"node?.imageAlt || imageAlt || ''\" />\n @if (node?.badge?.value) {\n <mat-chip\n class=\"inline-badge\"\n [color]=\"\n isThemeColor(node?.badge?.color)\n ? node?.badge?.color\n : undefined\n \"\n [ngClass]=\"\n (node?.badge?.variant || 'filled') === 'outlined'\n ? 'chip-outlined'\n : ''\n \"\n [style.cssText]=\"\n chipStyle(node?.badge?.color, node?.badge?.variant)\n \"\n >\n {{ node?.badge?.value }}\n </mat-chip>\n }\n </span>\n }\n @case (\"chip\") {\n <mat-chip\n [color]=\"isThemeColor(node?.color) ? node?.color : undefined\"\n [ngClass]=\"[\n node?.class || '',\n (node?.variant || 'filled') === 'outlined' ? 'chip-outlined' : '',\n ]\"\n [style.cssText]=\"\n chipStyle(node?.color, node?.variant) +\n (node?.style ? ';' + node.style : '')\n \"\n >\n {{ node?.value }}\n </mat-chip>\n }\n @case (\"rating\") {\n <span [ngClass]=\"node?.class\" [style.cssText]=\"node?.style\">\n @for (_ of ratingRange(node); track $index; let idx = $index) {\n <mat-icon\n [praxisIcon]=\"starIcon(idx, node?.value)\"\n [color]=\"ratingThemeColor(node)\"\n [style.cssText]=\"ratingIconStyle(node)\"\n ></mat-icon>\n }\n </span>\n }\n @case (\"html\") {\n <span\n [ngClass]=\"node?.class\"\n [style.cssText]=\"node?.style\"\n [innerHTML]=\"node?.value\"\n ></span>\n }\n @case (\"metric\") {\n <praxis-list-metric [metric]=\"node\"></praxis-list-metric>\n }\n @case (\"compose\") {\n <praxis-list-compose [compose]=\"node\"></praxis-list-compose>\n }\n @case (\"component\") {\n <praxis-list-runtime-component\n [component]=\"node\"\n ></praxis-list-runtime-component>\n }\n @default {\n <span [ngClass]=\"node?.class\" [style.cssText]=\"node?.style\">\n @if (slot === \"meta\" && config.templating?.metaPrefixIcon; as mpi) {\n <mat-icon [praxisIcon]=\"mpi\"></mat-icon>\n }\n {{ node?.value }}\n </span>\n }\n }\n </ng-template>\n\n <ng-template\n #listRowLayout\n let-item\n let-index=\"index\"\n let-sectionKey=\"sectionKey\"\n let-clickable=\"clickable\"\n >\n <div\n class=\"list-item-content\"\n [ngClass]=\"rowLayoutItemClass(item)\"\n [attr.style]=\"rowLayoutItemStyle(item)\"\n [attr.role]=\"clickable ? 'button' : null\"\n [attr.tabindex]=\"clickable ? '0' : null\"\n [attr.aria-label]=\"clickable ? itemAriaLabel(item) : null\"\n [attr.aria-expanded]=\"\n clickable && expansionOwnedByRow() ? isExpanded(item, index) : null\n \"\n [attr.aria-controls]=\"\n clickable && expansionOwnedByRow()\n ? expandRegionId(item, index)\n : null\n \"\n (click)=\"clickable ? onRowActivate(item, index, sectionKey) : null\"\n (keydown.enter)=\"clickable ? onRowActivate(item, index, sectionKey) : null\"\n (keydown.space)=\"\n onRowSpaceActivate($event, clickable, item, index, sectionKey)\n \"\n >\n @for (column of rowLayoutColumns(); track rowLayoutTrackColumn($index, column)) {\n <div\n [attr.data-row-slot]=\"column.slot\"\n [ngClass]=\"rowLayoutColumnClass(column)\"\n [attr.style]=\"rowLayoutColumnStyle(column)\"\n >\n @if (column.slot === \"leading\") {\n @if (rowLayoutSlot(item, column.slot); as lead) {\n <ng-container\n *ngTemplateOutlet=\"\n rowLayoutNode;\n context: {\n $implicit: lead,\n slot: column.slot,\n imageAlt: rowLayoutImageAlt(column.slot),\n }\n \"\n ></ng-container>\n } @else {\n <span class=\"leading-placeholder\"></span>\n }\n } @else if (column.slot === \"trailing\") {\n @if (rowLayoutSlot(item, column.slot); as trailingNode) {\n <ng-container\n *ngTemplateOutlet=\"\n rowLayoutNode;\n context: {\n $implicit: trailingNode,\n slot: column.slot,\n imageAlt: rowLayoutImageAlt(column.slot),\n }\n \"\n ></ng-container>\n }\n @if (showExpandIcon(\"trailing\")) {\n <button\n mat-icon-button\n type=\"button\"\n class=\"expand-toggle\"\n [attr.aria-label]=\"expandToggleAriaLabel(item, index)\"\n [attr.aria-expanded]=\"\n expansionOwnedByIcon() ? isExpanded(item, index) : null\n \"\n [attr.aria-controls]=\"\n expansionOwnedByIcon()\n ? expandRegionId(item, index)\n : null\n \"\n (click)=\"onExpandToggle($event, item, index)\"\n >\n <mat-icon\n [praxisIcon]=\"\n isExpanded(item, index) ? 'expand_less' : 'expand_more'\n \"\n ></mat-icon>\n </button>\n }\n @if ((visibleActions(item, \"trailing\") || []).length) {\n <div\n class=\"list-item-actions\"\n (click)=\"$event.stopPropagation()\"\n (keydown.enter)=\"onActionKeydown($event)\"\n (keydown.space)=\"onActionKeydown($event)\"\n >\n @for (\n action of visibleActions(item, \"trailing\");\n let aidx = $index;\n track action?.id ?? $index\n ) {\n @if ((action.kind || \"icon\") === \"icon\") {\n <button\n mat-icon-button\n [color]=\"\n isThemeColor(action.color) ? action.color : undefined\n \"\n (click)=\"onActionClick($event, action.id, item, index)\"\n [attr.aria-label]=\"action.label || action.id\"\n [disabled]=\"isActionLoading(action.id, item, index)\"\n [ngClass]=\"{\n 'action-loading': isActionLoading(\n action.id,\n item,\n index\n ),\n }\"\n >\n @if (isActionLoading(action.id, item, index)) {\n <mat-progress-spinner\n class=\"action-spinner\"\n mode=\"indeterminate\"\n diameter=\"16\"\n strokeWidth=\"3\"\n ></mat-progress-spinner>\n } @else {\n <mat-icon\n [praxisIcon]=\"action.icon\"\n [style.cssText]=\"iconStyle(action.color)\"\n ></mat-icon>\n }\n </button>\n } @else {\n @if (action.buttonVariant === \"stroked\") {\n <button\n mat-stroked-button\n [color]=\"\n isThemeColor(action.color) ? action.color : undefined\n \"\n [style.cssText]=\"buttonStyle(action.color, 'stroked')\"\n (click)=\"onActionClick($event, action.id, item, index)\"\n [attr.aria-label]=\"action.label || action.id\"\n [disabled]=\"isActionLoading(action.id, item, index)\"\n [ngClass]=\"{\n 'action-loading': isActionLoading(\n action.id,\n item,\n index\n ),\n }\"\n >\n @if (isActionLoading(action.id, item, index)) {\n <mat-progress-spinner\n class=\"action-spinner\"\n mode=\"indeterminate\"\n diameter=\"16\"\n strokeWidth=\"3\"\n ></mat-progress-spinner>\n } @else {\n {{ action.label || action.id }}\n }\n </button>\n }\n @if (action.buttonVariant === \"raised\") {\n <button\n mat-raised-button\n [color]=\"\n isThemeColor(action.color) ? action.color : undefined\n \"\n [style.cssText]=\"buttonStyle(action.color, 'raised')\"\n (click)=\"onActionClick($event, action.id, item, index)\"\n [attr.aria-label]=\"action.label || action.id\"\n [disabled]=\"isActionLoading(action.id, item, index)\"\n [ngClass]=\"{\n 'action-loading': isActionLoading(\n action.id,\n item,\n index\n ),\n }\"\n >\n @if (isActionLoading(action.id, item, index)) {\n <mat-progress-spinner\n class=\"action-spinner\"\n mode=\"indeterminate\"\n diameter=\"16\"\n strokeWidth=\"3\"\n ></mat-progress-spinner>\n } @else {\n {{ action.label || action.id }}\n }\n </button>\n }\n @if (!action.buttonVariant || action.buttonVariant === \"flat\") {\n <button\n mat-flat-button\n [color]=\"\n isThemeColor(action.color) ? action.color : undefined\n \"\n [style.cssText]=\"buttonStyle(action.color, 'flat')\"\n (click)=\"onActionClick($event, action.id, item, index)\"\n [attr.aria-label]=\"action.label || action.id\"\n [disabled]=\"isActionLoading(action.id, item, index)\"\n [ngClass]=\"{\n 'action-loading': isActionLoading(\n action.id,\n item,\n index\n ),\n }\"\n >\n @if (isActionLoading(action.id, item, index)) {\n <mat-progress-spinner\n class=\"action-spinner\"\n mode=\"indeterminate\"\n diameter=\"16\"\n strokeWidth=\"3\"\n ></mat-progress-spinner>\n } @else {\n {{ action.label || action.id }}\n }\n </button>\n }\n }\n }\n </div>\n }\n } @else if (column.slot === \"actions\") {\n @if ((visibleActions(item, \"actions\") || []).length) {\n <div\n class=\"list-item-actions\"\n (click)=\"$event.stopPropagation()\"\n (keydown.enter)=\"onActionKeydown($event)\"\n (keydown.space)=\"onActionKeydown($event)\"\n >\n @for (\n action of visibleActions(item, \"actions\");\n let aidx = $index;\n track action?.id ?? $index\n ) {\n @if ((action.kind || \"icon\") === \"icon\") {\n <button\n mat-icon-button\n [color]=\"\n isThemeColor(action.color) ? action.color : undefined\n \"\n (click)=\"onActionClick($event, action.id, item, index)\"\n [attr.aria-label]=\"action.label || action.id\"\n [disabled]=\"isActionLoading(action.id, item, index)\"\n [ngClass]=\"{\n 'action-loading': isActionLoading(\n action.id,\n item,\n index\n ),\n }\"\n >\n @if (isActionLoading(action.id, item, index)) {\n <mat-progress-spinner\n class=\"action-spinner\"\n mode=\"indeterminate\"\n diameter=\"16\"\n strokeWidth=\"3\"\n ></mat-progress-spinner>\n } @else {\n <mat-icon\n [praxisIcon]=\"action.icon\"\n [style.cssText]=\"iconStyle(action.color)\"\n ></mat-icon>\n }\n </button>\n } @else {\n @if (action.buttonVariant === \"stroked\") {\n <button\n mat-stroked-button\n [color]=\"\n isThemeColor(action.color) ? action.color : undefined\n \"\n [style.cssText]=\"buttonStyle(action.color, 'stroked')\"\n (click)=\"onActionClick($event, action.id, item, index)\"\n [attr.aria-label]=\"action.label || action.id\"\n [disabled]=\"isActionLoading(action.id, item, index)\"\n [ngClass]=\"{\n 'action-loading': isActionLoading(\n action.id,\n item,\n index\n ),\n }\"\n >\n @if (isActionLoading(action.id, item, index)) {\n <mat-progress-spinner\n class=\"action-spinner\"\n mode=\"indeterminate\"\n diameter=\"16\"\n strokeWidth=\"3\"\n ></mat-progress-spinner>\n } @else {\n {{ action.label || action.id }}\n }\n </button>\n }\n @if (action.buttonVariant === \"raised\") {\n <button\n mat-raised-button\n [color]=\"\n isThemeColor(action.color) ? action.color : undefined\n \"\n [style.cssText]=\"buttonStyle(action.color, 'raised')\"\n (click)=\"onActionClick($event, action.id, item, index)\"\n [attr.aria-label]=\"action.label || action.id\"\n [disabled]=\"isActionLoading(action.id, item, index)\"\n [ngClass]=\"{\n 'action-loading': isActionLoading(\n action.id,\n item,\n index\n ),\n }\"\n >\n @if (isActionLoading(action.id, item, index)) {\n <mat-progress-spinner\n class=\"action-spinner\"\n mode=\"indeterminate\"\n diameter=\"16\"\n strokeWidth=\"3\"\n ></mat-progress-spinner>\n } @else {\n {{ action.label || action.id }}\n }\n </button>\n }\n @if (!action.buttonVariant || action.buttonVariant === \"flat\") {\n <button\n mat-flat-button\n [color]=\"\n isThemeColor(action.color) ? action.color : undefined\n \"\n [style.cssText]=\"buttonStyle(action.color, 'flat')\"\n (click)=\"onActionClick($event, action.id, item, index)\"\n [attr.aria-label]=\"action.label || action.id\"\n [disabled]=\"isActionLoading(action.id, item, index)\"\n [ngClass]=\"{\n 'action-loading': isActionLoading(\n action.id,\n item,\n index\n ),\n }\"\n >\n @if (isActionLoading(action.id, item, index)) {\n <mat-progress-spinner\n class=\"action-spinner\"\n mode=\"indeterminate\"\n diameter=\"16\"\n strokeWidth=\"3\"\n ></mat-progress-spinner>\n } @else {\n {{ action.label || action.id }}\n }\n </button>\n }\n }\n }\n </div>\n }\n } @else if (column.slot === \"expand\") {\n @if (showExpandIcon(\"expand\")) {\n <button\n mat-icon-button\n type=\"button\"\n class=\"expand-toggle\"\n [attr.aria-label]=\"expandToggleAriaLabel(item, index)\"\n [attr.aria-expanded]=\"\n expansionOwnedByIcon() ? isExpanded(item, index) : null\n \"\n [attr.aria-controls]=\"\n expansionOwnedByIcon()\n ? expandRegionId(item, index)\n : null\n \"\n (click)=\"onExpandToggle($event, item, index)\"\n >\n <mat-icon\n [praxisIcon]=\"\n isExpanded(item, index) ? 'expand_less' : 'expand_more'\n \"\n ></mat-icon>\n </button>\n }\n } @else if (rowLayoutSlot(item, column.slot); as slotNode) {\n <ng-container\n *ngTemplateOutlet=\"\n rowLayoutNode;\n context: {\n $implicit: slotNode,\n slot: column.slot,\n imageAlt: rowLayoutImageAlt(column.slot),\n }\n \"\n ></ng-container>\n }\n </div>\n }\n </div>\n </ng-template>\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 (\n section of sections$ | async;\n track trackBySection($index, section)\n ) {\n @if (section.key) {\n <div class=\"section-header mat-subheader\">\n @if (sectionHeaderTemplate(section.key); as sh) {\n @switch (sh.type) {\n @case (\"icon\") {\n <mat-icon\n [praxisIcon]=\"sh.value\"\n [ngClass]=\"sh.class\"\n [color]=\"isThemeColor(sh.color) ? sh.color : undefined\"\n [style.cssText]=\"\n (sh.style ? sh.style + ';' : '') + iconStyle(sh.color)\n \"\n ></mat-icon>\n }\n @case (\"image\") {\n <span\n class=\"inline-image\"\n [ngClass]=\"sh.class\"\n [style.cssText]=\"sh.style\"\n >\n <img\n [src]=\"sh.value\"\n [alt]=\"\n config.templating?.sectionHeader?.imageAlt || ''\n \"\n />\n @if (sh.badge?.value) {\n <mat-chip\n class=\"inline-badge\"\n [color]=\"\n isThemeColor(sh.badge?.color)\n ? sh.badge?.color\n : undefined\n \"\n [ngClass]=\"\n (sh.badge?.variant || 'filled') === 'outlined'\n ? 'chip-outlined'\n : ''\n \"\n [style.cssText]=\"\n chipStyle(sh.badge?.color, sh.badge?.variant)\n \"\n >{{ sh.badge?.value }}</mat-chip\n >\n }\n </span>\n }\n @case (\"chip\") {\n <mat-chip\n [color]=\"isThemeColor(sh.color) ? sh.color : undefined\"\n [ngClass]=\"[\n sh.class || '',\n (sh.variant || 'filled') === 'outlined'\n ? 'chip-outlined'\n : '',\n ]\"\n [style.cssText]=\"\n chipStyle(sh.color, sh.variant) +\n (sh.style ? ';' + sh.style : '')\n \"\n >{{ sh.value }}</mat-chip\n >\n }\n @case (\"rating\") {\n <span [ngClass]=\"sh.class\" [style.cssText]=\"sh.style\">\n @for (\n _ of ratingRange(sh);\n track $index;\n let idx = $index\n ) {\n <mat-icon\n [praxisIcon]=\"starIcon(idx, sh.value)\"\n [color]=\"ratingThemeColor(sh)\"\n [style.cssText]=\"ratingIconStyle(sh)\"\n ></mat-icon>\n }\n </span>\n }\n @case (\"html\") {\n <span\n [ngClass]=\"sh.class\"\n [style.cssText]=\"sh.style\"\n [innerHTML]=\"sh.value\"\n ></span>\n }\n @case (\"metric\") {\n <praxis-list-metric [metric]=\"sh\"></praxis-list-metric>\n }\n @case (\"compose\") {\n <praxis-list-compose [compose]=\"sh\"></praxis-list-compose>\n }\n @case (\"component\") {\n <praxis-list-runtime-component\n [component]=\"sh\"\n ></praxis-list-runtime-component>\n }\n @default {\n <span [ngClass]=\"sh.class\" [style.cssText]=\"sh.style\">{{\n sh.value\n }}</span>\n }\n }\n }\n </div>\n }\n @for (\n item of section.items;\n track trackByItem($index, item);\n let i = $index\n ) {\n <mat-list-option\n [value]=\"item\"\n [attr.aria-label]=\"itemAriaLabel(item)\"\n >\n @if (hasRowLayoutGrid()) {\n <ng-container\n *ngTemplateOutlet=\"\n listRowLayout;\n context: {\n $implicit: item,\n index: i,\n sectionKey: section.key || undefined,\n clickable: false,\n }\n \"\n ></ng-container>\n } @else {\n <div\n class=\"list-item-content\"\n [ngClass]=\"itemRuleClass(item)\"\n [attr.style]=\"itemRuleStyle(item)\"\n >\n <div class=\"list-item-leading\">\n @if (leading(item); as lead) {\n @switch (lead.type) {\n @case (\"icon\") {\n <mat-icon\n [praxisIcon]=\"lead.value\"\n [ngClass]=\"lead.class\"\n [color]=\"\n isThemeColor(lead.color) ? lead.color : undefined\n \"\n [style.cssText]=\"\n (lead.style ? lead.style + ';' : '') +\n iconStyle(lead.color)\n \"\n ></mat-icon>\n }\n @case (\"image\") {\n <div\n class=\"lead-image\"\n [ngClass]=\"lead.class\"\n [style.cssText]=\"lead.style\"\n >\n <img\n [src]=\"lead.value\"\n [alt]=\"config.templating?.leading?.imageAlt || ''\"\n />\n @if (lead.badge?.value) {\n <mat-chip\n class=\"lead-badge\"\n [color]=\"\n isThemeColor(lead.badge?.color)\n ? lead.badge?.color\n : undefined\n \"\n [ngClass]=\"\n (lead.badge?.variant || 'filled') ===\n 'outlined'\n ? 'chip-outlined'\n : ''\n \"\n [style.cssText]=\"\n chipStyle(\n lead.badge?.color,\n lead.badge?.variant\n )\n \"\n >{{ lead.badge?.value }}</mat-chip\n >\n }\n </div>\n }\n @case (\"text\") {\n <span\n [ngClass]=\"lead.class\"\n [style.cssText]=\"lead.style\"\n >{{ lead.value }}</span\n >\n }\n @case (\"chip\") {\n <mat-chip\n [color]=\"\n isThemeColor(lead.color) ? lead.color : undefined\n \"\n [ngClass]=\"\n (lead.variant || 'filled') === 'outlined'\n ? 'chip-outlined'\n : ''\n \"\n [style.cssText]=\"\n chipStyle(lead.color, lead.variant)\n \"\n >{{ lead.value }}</mat-chip\n >\n }\n @case (\"rating\") {\n <span\n [ngClass]=\"lead.class\"\n [style.cssText]=\"lead.style\"\n >\n @for (\n _ of ratingRange(lead);\n track $index;\n let idx = $index\n ) {\n <mat-icon\n [praxisIcon]=\"starIcon(idx, lead.value)\"\n [color]=\"ratingThemeColor(lead)\"\n [style.cssText]=\"ratingIconStyle(lead)\"\n ></mat-icon>\n }\n </span>\n }\n @case (\"html\") {\n <span\n [ngClass]=\"lead.class\"\n [style.cssText]=\"lead.style\"\n [innerHTML]=\"lead.value\"\n ></span>\n }\n @case (\"metric\") {\n <praxis-list-metric [metric]=\"lead\"></praxis-list-metric>\n }\n @case (\"compose\") {\n <praxis-list-compose\n [compose]=\"lead\"\n ></praxis-list-compose>\n }\n @case (\"component\") {\n <praxis-list-runtime-component\n [component]=\"lead\"\n ></praxis-list-runtime-component>\n }\n @default {\n <span\n [ngClass]=\"lead.class\"\n [style.cssText]=\"lead.style\"\n >{{ lead.value }}</span\n >\n }\n }\n } @else {\n <span class=\"leading-placeholder\"></span>\n }\n </div>\n <div class=\"list-item-text\">\n <div\n class=\"primary\"\n [ngClass]=\"primary(item)?.class\"\n [style.cssText]=\"primary(item)?.style\"\n >\n @if (primary(item)?.type === \"metric\") {\n <praxis-list-metric\n [metric]=\"primary(item)\"\n ></praxis-list-metric>\n } @else if (primary(item)?.type === \"compose\") {\n <praxis-list-compose\n [compose]=\"primary(item)\"\n ></praxis-list-compose>\n } @else if (primary(item)?.type === \"component\") {\n <praxis-list-runtime-component\n [component]=\"primary(item)\"\n ></praxis-list-runtime-component>\n } @else {\n {{ primary(item)?.value }}\n }\n </div>\n @if (layoutLines > 1) {\n <div\n class=\"secondary\"\n [ngClass]=\"secondary(item)?.class\"\n [style.cssText]=\"secondary(item)?.style\"\n >\n @if (secondary(item)?.type === \"metric\") {\n <praxis-list-metric\n [metric]=\"secondary(item)\"\n ></praxis-list-metric>\n } @else if (secondary(item)?.type === \"compose\") {\n <praxis-list-compose\n [compose]=\"secondary(item)\"\n ></praxis-list-compose>\n } @else if (secondary(item)?.type === \"component\") {\n <praxis-list-runtime-component\n [component]=\"secondary(item)\"\n ></praxis-list-runtime-component>\n } @else {\n {{ secondary(item)?.value }}\n }\n </div>\n }\n @if (meta(item); as m) {\n @if (\n (config.templating?.metaPlacement === \"line\" &&\n (m?.type === \"text\" ||\n m?.type === \"date\" ||\n m?.type === \"currency\")) ||\n (layoutLines > 2 &&\n (m?.type === \"text\" ||\n m?.type === \"date\" ||\n m?.type === \"currency\"))\n ) {\n <div\n class=\"tertiary\"\n [ngClass]=\"m.class\"\n [style.cssText]=\"m.style\"\n >\n @if (config.templating?.metaPrefixIcon; as mpi) {\n <mat-icon [praxisIcon]=\"mpi\"></mat-icon>\n }\n {{ m.value }}\n </div>\n }\n }\n @if (featuresVisible()) {\n <div class=\"features\">\n @for (\n f of config.templating?.features || [];\n track $index;\n let fi = $index\n ) {\n <span\n class=\"feature\"\n [ngClass]=\"\n featureSemanticClass(item, f.expr, f.class)\n \"\n >\n @if (f.icon && featuresMode() !== \"labels-only\") {\n <mat-icon [praxisIcon]=\"f.icon\"></mat-icon>\n }\n @if (featuresMode() !== \"icons-only\") {\n <span\n [ngClass]=\"f.class\"\n [style.cssText]=\"f.style\"\n >\n @for (\n line of featureLabelLines(item, f.expr);\n track $index\n ) {\n <span class=\"feature-line\">{{ line }}</span>\n }\n </span>\n }\n @if (\n featureProgressPercent(item, f.expr, f.class);\n as progress\n ) {\n <span class=\"feature-progress\" aria-hidden=\"true\">\n <span\n class=\"feature-progress__value\"\n [style.width.%]=\"progress\"\n ></span>\n </span>\n }\n </span>\n }\n </div>\n }\n </div>\n <div class=\"list-item-trailing\">\n @if (meta(item); as m) {\n @if (\n !(\n (config.templating?.metaPlacement === \"line\" ||\n layoutLines > 2) &&\n (m?.type === \"text\" ||\n m?.type === \"date\" ||\n m?.type === \"currency\")\n )\n ) {\n <div\n class=\"meta\"\n [ngClass]=\"m.class\"\n [style.cssText]=\"m.style\"\n >\n @switch (m.type) {\n @case (\"chip\") {\n <mat-chip\n [color]=\"\n isThemeColor(m.color) ? m.color : undefined\n \"\n [ngClass]=\"\n (m.variant || 'filled') === 'outlined'\n ? 'chip-outlined'\n : ''\n \"\n [style.cssText]=\"chipStyle(m.color, m.variant)\"\n >{{ m.value }}</mat-chip\n >\n }\n @case (\"rating\") {\n @for (\n _ of ratingRange(m);\n track $index;\n let idx = $index\n ) {\n <mat-icon\n [praxisIcon]=\"starIcon(idx, m.value)\"\n [color]=\"ratingThemeColor(m)\"\n [style.cssText]=\"ratingIconStyle(m)\"\n ></mat-icon>\n }\n }\n @case (\"icon\") {\n <mat-icon\n [praxisIcon]=\"m.value\"\n [color]=\"\n isThemeColor(m.color) ? m.color : undefined\n \"\n [style.cssText]=\"iconStyle(m.color)\"\n ></mat-icon>\n }\n @case (\"image\") {\n <span class=\"inline-image\"\n ><img [src]=\"m.value\" [alt]=\"m.imageAlt || ''\"\n /></span>\n }\n @case (\"html\") {\n <span [innerHTML]=\"m.value\"></span>\n }\n @case (\"metric\") {\n <praxis-list-metric [metric]=\"m\"></praxis-list-metric>\n }\n @case (\"compose\") {\n <praxis-list-compose\n [compose]=\"m\"\n ></praxis-list-compose>\n }\n @case (\"component\") {\n <praxis-list-runtime-component\n [component]=\"m\"\n ></praxis-list-runtime-component>\n }\n @default {\n <span>\n @if (\n config.templating?.metaPrefixIcon;\n as mpi2\n ) {\n <mat-icon [praxisIcon]=\"mpi2\"></mat-icon>\n }\n {{ m.value }}</span\n >\n }\n }\n </div>\n }\n }\n @if (trailing(item); as tr) {\n <div\n class=\"trailing\"\n [ngClass]=\"tr.class\"\n [style.cssText]=\"tr.style\"\n >\n @switch (tr.type) {\n @case (\"chip\") {\n <mat-chip\n [color]=\"\n isThemeColor(tr.color) ? tr.color : undefined\n \"\n [ngClass]=\"\n (tr.variant || 'filled') === 'outlined'\n ? 'chip-outlined'\n : ''\n \"\n [style.cssText]=\"chipStyle(tr.color, tr.variant)\"\n >{{ tr.value }}</mat-chip\n >\n }\n @case (\"icon\") {\n <mat-icon\n [praxisIcon]=\"tr.value\"\n [color]=\"\n isThemeColor(tr.color) ? tr.color : undefined\n \"\n [style.cssText]=\"iconStyle(tr.color)\"\n ></mat-icon>\n }\n @case (\"image\") {\n <div\n class=\"lead-image\"\n [ngClass]=\"tr.class\"\n [style.cssText]=\"tr.style\"\n >\n <img\n [src]=\"tr.value\"\n [alt]=\"\n config.templating?.trailing?.imageAlt || ''\n \"\n />\n @if (tr.badge?.value) {\n <mat-chip\n class=\"lead-badge\"\n [color]=\"\n isThemeColor(tr.badge?.color)\n ? tr.badge?.color\n : undefined\n \"\n [ngClass]=\"\n (tr.badge?.variant || 'filled') ===\n 'outlined'\n ? 'chip-outlined'\n : ''\n \"\n [style.cssText]=\"\n chipStyle(\n tr.badge?.color,\n tr.badge?.variant\n )\n \"\n >{{ tr.badge?.value }}</mat-chip\n >\n }\n </div>\n }\n @case (\"rating\") {\n @for (\n _ of ratingRange(tr);\n track $index;\n let idx = $index\n ) {\n <mat-icon\n [praxisIcon]=\"starIcon(idx, tr.value)\"\n [color]=\"ratingThemeColor(tr)\"\n [style.cssText]=\"ratingIconStyle(tr)\"\n ></mat-icon>\n }\n }\n @case (\"html\") {\n @if (item.alertsData !== undefined && item.ownerName) {\n <!-- Component-based rendering for executive trailing -->\n <span class=\"exec-trailing-shell\">\n <praxis-executive-alerts [alerts]=\"item.alertsData\"></praxis-executive-alerts>\n <praxis-executive-owner [name]=\"item.ownerName\"></praxis-executive-owner>\n </span>\n } @else {\n <span [innerHTML]=\"tr.value\"></span>\n }\n }\n @case (\"metric\") {\n <praxis-list-metric [metric]=\"tr\"></praxis-list-metric>\n }\n @case (\"compose\") {\n <praxis-list-compose\n [compose]=\"tr\"\n ></praxis-list-compose>\n }\n @case (\"component\") {\n <praxis-list-runtime-component\n [component]=\"tr\"\n ></praxis-list-runtime-component>\n }\n @default {\n <span>{{ tr.value }}</span>\n }\n }\n </div>\n }\n @if (showExpandIcon(\"trailing\")) {\n <button\n mat-icon-button\n type=\"button\"\n class=\"expand-toggle\"\n [attr.aria-label]=\"expandToggleAriaLabel(item, i)\"\n [attr.aria-expanded]=\"\n expansionOwnedByIcon() ? isExpanded(item, i) : null\n \"\n [attr.aria-controls]=\"\n expansionOwnedByIcon()\n ? expandRegionId(item, i)\n : null\n \"\n (click)=\"onExpandToggle($event, item, i)\"\n >\n <mat-icon\n [praxisIcon]=\"\n isExpanded(item, i) ? 'expand_less' : 'expand_more'\n \"\n ></mat-icon>\n </button>\n }\n @if ((visibleActions(item, \"trailing\") || []).length) {\n <div\n class=\"list-item-actions\"\n (click)=\"$event.stopPropagation()\"\n (keydown.enter)=\"onActionKeydown($event)\"\n (keydown.space)=\"onActionKeydown($event)\"\n >\n @for (\n action of visibleActions(item, \"trailing\");\n let aidx = $index;\n track action?.id ?? $index\n ) {\n @if ((action.kind || \"icon\") === \"icon\") {\n <button\n mat-icon-button\n [color]=\"\n isThemeColor(action.color)\n ? action.color\n : undefined\n \"\n (click)=\"\n onActionClick($event, action.id, item, i)\n \"\n [attr.aria-label]=\"action.label || action.id\"\n [disabled]=\"isActionLoading(action.id, item, i)\"\n [ngClass]=\"{\n 'action-loading': isActionLoading(\n action.id,\n item,\n i\n ),\n }\"\n >\n @if (isActionLoading(action.id, item, i)) {\n <mat-progress-spinner\n class=\"action-spinner\"\n mode=\"indeterminate\"\n diameter=\"16\"\n strokeWidth=\"3\"\n ></mat-progress-spinner>\n } @else {\n <mat-icon\n [praxisIcon]=\"action.icon\"\n [style.cssText]=\"iconStyle(action.color)\"\n ></mat-icon>\n }\n </button>\n } @else {\n @if (action.buttonVariant === \"stroked\") {\n <button\n mat-stroked-button\n [color]=\"\n isThemeColor(action.color)\n ? action.color\n : undefined\n \"\n [style.cssText]=\"\n buttonStyle(action.color, 'stroked')\n \"\n (click)=\"\n onActionClick($event, action.id, item, i)\n \"\n [attr.aria-label]=\"action.label || action.id\"\n [disabled]=\"isActionLoading(action.id, item, i)\"\n [ngClass]=\"{\n 'action-loading': isActionLoading(\n action.id,\n item,\n i\n ),\n }\"\n >\n @if (isActionLoading(action.id, item, i)) {\n <mat-progress-spinner\n class=\"action-spinner\"\n mode=\"indeterminate\"\n diameter=\"16\"\n strokeWidth=\"3\"\n ></mat-progress-spinner>\n } @else {\n {{ action.label || action.id }}\n }\n </button>\n }\n @if (action.buttonVariant === \"raised\") {\n <button\n mat-raised-button\n [color]=\"\n isThemeColor(action.color)\n ? action.color\n : undefined\n \"\n [style.cssText]=\"\n buttonStyle(action.color, 'raised')\n \"\n (click)=\"\n onActionClick($event, action.id, item, i)\n \"\n [attr.aria-label]=\"action.label || action.id\"\n [disabled]=\"isActionLoading(action.id, item, i)\"\n [ngClass]=\"{\n 'action-loading': isActionLoading(\n action.id,\n item,\n i\n ),\n }\"\n >\n @if (isActionLoading(action.id, item, i)) {\n <mat-progress-spinner\n class=\"action-spinner\"\n mode=\"indeterminate\"\n diameter=\"16\"\n strokeWidth=\"3\"\n ></mat-progress-spinner>\n } @else {\n {{ action.label || action.id }}\n }\n </button>\n }\n @if (\n !action.buttonVariant ||\n action.buttonVariant === \"flat\"\n ) {\n <button\n mat-flat-button\n [color]=\"\n isThemeColor(action.color)\n ? action.color\n : undefined\n \"\n [style.cssText]=\"\n buttonStyle(action.color, 'flat')\n \"\n (click)=\"\n onActionClick($event, action.id, item, i)\n \"\n [attr.aria-label]=\"action.label || action.id\"\n [disabled]=\"isActionLoading(action.id, item, i)\"\n [ngClass]=\"{\n 'action-loading': isActionLoading(\n action.id,\n item,\n i\n ),\n }\"\n >\n @if (isActionLoading(action.id, item, i)) {\n <mat-progress-spinner\n class=\"action-spinner\"\n mode=\"indeterminate\"\n diameter=\"16\"\n strokeWidth=\"3\"\n ></mat-progress-spinner>\n } @else {\n {{ action.label || action.id }}\n }\n </button>\n }\n }\n }\n </div>\n }\n </div>\n </div>\n }\n @if (isExpandable() && isExpanded(item, i)) {\n <div\n class=\"item-expansion\"\n [id]=\"expandRegionId(item, i)\"\n role=\"region\"\n [attr.aria-label]=\"expansionRegionAriaLabel(item)\"\n >\n <div class=\"item-expansion-grid\">\n @for (\n expansionSection of expansionSections(item);\n track expansionSection.id\n ) {\n <section\n class=\"expansion-section\"\n [attr.data-section-type]=\"expansionSection.type\"\n >\n @if (expansionSection.title) {\n <div class=\"expansion-section-title\">\n {{ expansionSection.title }}\n </div>\n }\n @if (\n expansionSectionHasContent(\n item,\n expansionSection,\n i\n )\n ) {\n @switch (expansionSection.type) {\n @case (\"chip-list\") {\n <div class=\"expansion-chip-list\">\n @for (\n expansionEntry of expansionSectionItems(\n item,\n expansionSection,\n i\n );\n track $index\n ) {\n <mat-chip class=\"expansion-chip\">{{\n expansionItemLabel(expansionEntry)\n }}</mat-chip>\n }\n </div>\n }\n @case (\"timeline\") {\n <div class=\"expansion-timeline\">\n @for (\n expansionEntry of expansionSectionItems(\n item,\n expansionSection,\n i\n );\n track $index\n ) {\n <div class=\"expansion-timeline-item\">\n <div class=\"expansion-timeline-title\">\n {{\n expansionTimelineTitle(expansionEntry)\n }}\n </div>\n @if (\n expansionTimelineMeta(expansionEntry)\n ) {\n <div class=\"expansion-timeline-meta\">\n {{\n expansionTimelineMeta(\n expansionEntry\n )\n }}\n </div>\n }\n @if (\n expansionTimelineDescription(\n expansionEntry\n )\n ) {\n <div\n class=\"expansion-timeline-description\"\n >\n {{\n expansionTimelineDescription(\n expansionEntry\n )\n }}\n </div>\n }\n </div>\n }\n </div>\n }\n @case (\"key-value\") {\n <dl class=\"expansion-key-value\">\n @for (\n expansionEntry of expansionSectionItems(\n item,\n expansionSection,\n i\n );\n track $index\n ) {\n <div class=\"expansion-key-value-row\">\n @if (\n expansionKeyValueKey(expansionEntry)\n ) {\n <dt>\n {{\n expansionKeyValueKey(expansionEntry)\n }}\n </dt>\n }\n <dd>\n {{\n expansionKeyValueValue(expansionEntry)\n }}\n </dd>\n </div>\n }\n </dl>\n }\n @default {\n <div class=\"expansion-info-list\">\n @for (\n expansionEntry of expansionSectionItems(\n item,\n expansionSection,\n i\n );\n track $index\n ) {\n <div class=\"expansion-info-item\">\n <div class=\"expansion-info-title\">\n {{ expansionInfoTitle(expansionEntry) }}\n </div>\n @if (expansionInfoValue(expansionEntry)) {\n <div class=\"expansion-info-value\">\n {{\n expansionInfoValue(expansionEntry)\n }}\n </div>\n }\n </div>\n }\n </div>\n }\n }\n } @else {\n <div class=\"expansion-empty\">\n {{\n expansionSection.emptyLabel ||\n \"Sem dados dispon\u00EDveis\"\n }}\n </div>\n }\n </section>\n }\n </div>\n </div>\n }\n </mat-list-option>\n @if (\n (config.layout?.dividers === \"all\" ||\n config.layout?.dividers === \"between\") &&\n i < section.items.length - 1\n ) {\n <mat-divider></mat-divider>\n }\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 (\n section of sections$ | async;\n track trackBySection($index, section);\n let sidx = $index\n ) {\n @if (section.key) {\n <div class=\"section-header mat-subheader\">\n @if (sectionHeaderTemplate(section.key); as sh) {\n @switch (sh.type) {\n @case (\"icon\") {\n <mat-icon\n [praxisIcon]=\"sh.value\"\n [ngClass]=\"sh.class\"\n [color]=\"isThemeColor(sh.color) ? sh.color : undefined\"\n [style.cssText]=\"\n (sh.style ? sh.style + ';' : '') + iconStyle(sh.color)\n \"\n ></mat-icon>\n }\n @case (\"image\") {\n <span\n class=\"inline-image\"\n [ngClass]=\"sh.class\"\n [style.cssText]=\"sh.style\"\n >\n <img\n [src]=\"sh.value\"\n [alt]=\"\n config.templating?.sectionHeader?.imageAlt || ''\n \"\n />\n @if (sh.badge?.value) {\n <mat-chip\n class=\"inline-badge\"\n [color]=\"\n isThemeColor(sh.badge?.color)\n ? sh.badge?.color\n : undefined\n \"\n [ngClass]=\"\n (sh.badge?.variant || 'filled') === 'outlined'\n ? 'chip-outlined'\n : ''\n \"\n [style.cssText]=\"\n chipStyle(sh.badge?.color, sh.badge?.variant)\n \"\n >{{ sh.badge?.value }}</mat-chip\n >\n }\n </span>\n }\n @case (\"chip\") {\n <mat-chip\n [color]=\"isThemeColor(sh.color) ? sh.color : undefined\"\n [ngClass]=\"[\n sh.class || '',\n (sh.variant || 'filled') === 'outlined'\n ? 'chip-outlined'\n : '',\n ]\"\n [style.cssText]=\"\n chipStyle(sh.color, sh.variant) +\n (sh.style ? ';' + sh.style : '')\n \"\n >{{ sh.value }}</mat-chip\n >\n }\n @case (\"rating\") {\n <span [ngClass]=\"sh.class\" [style.cssText]=\"sh.style\">\n @for (\n _ of ratingRange(sh);\n track $index;\n let idx = $index\n ) {\n <mat-icon\n [praxisIcon]=\"starIcon(idx, sh.value)\"\n [color]=\"ratingThemeColor(sh)\"\n [style.cssText]=\"ratingIconStyle(sh)\"\n ></mat-icon>\n }\n </span>\n }\n @case (\"html\") {\n <span\n [ngClass]=\"sh.class\"\n [style.cssText]=\"sh.style\"\n [innerHTML]=\"sh.value\"\n ></span>\n }\n @case (\"metric\") {\n <praxis-list-metric [metric]=\"sh\"></praxis-list-metric>\n }\n @default {\n <span [ngClass]=\"sh.class\" [style.cssText]=\"sh.style\">{{\n sh.value\n }}</span>\n }\n }\n }\n </div>\n }\n @for (\n item of section.items;\n track trackByItem($index, item);\n let i = $index\n ) {\n <mat-list-item [attr.data-item-status]=\"item?.status || null\">\n @if (hasRowLayoutGrid()) {\n <ng-container\n *ngTemplateOutlet=\"\n listRowLayout;\n context: {\n $implicit: item,\n index: i,\n sectionKey: section.key || undefined,\n clickable: true,\n }\n \"\n ></ng-container>\n } @else {\n <div\n class=\"list-item-content\"\n [ngClass]=\"itemRuleClass(item)\"\n [attr.style]=\"itemRuleStyle(item)\"\n >\n <button\n type=\"button\"\n class=\"list-item-main-action\"\n [attr.aria-label]=\"itemAriaLabel(item)\"\n [attr.aria-expanded]=\"\n expansionOwnedByRow() ? isExpanded(item, i) : null\n \"\n [attr.aria-controls]=\"\n expansionOwnedByRow() ? expandRegionId(item, i) : null\n \"\n (click)=\"onRowActivate(item, i, section.key || undefined)\"\n >\n <div class=\"list-item-leading\">\n @if (leading(item); as lead) {\n @switch (lead.type) {\n @case (\"icon\") {\n <mat-icon\n [praxisIcon]=\"lead.value\"\n [ngClass]=\"lead.class\"\n [color]=\"\n isThemeColor(lead.color)\n ? lead.color\n : undefined\n \"\n [style.cssText]=\"\n (lead.style ? lead.style + ';' : '') +\n iconStyle(lead.color)\n \"\n ></mat-icon>\n }\n @case (\"image\") {\n <div\n class=\"lead-image\"\n [ngClass]=\"lead.class\"\n [style.cssText]=\"lead.style\"\n >\n <img\n [src]=\"lead.value\"\n [alt]=\"\n config.templating?.leading?.imageAlt || ''\n \"\n />\n @if (lead.badge?.value) {\n <mat-chip\n class=\"lead-badge\"\n [color]=\"\n isThemeColor(lead.badge?.color)\n ? lead.badge?.color\n : undefined\n \"\n [ngClass]=\"\n (lead.badge?.variant || 'filled') ===\n 'outlined'\n ? 'chip-outlined'\n : ''\n \"\n [style.cssText]=\"\n chipStyle(\n lead.badge?.color,\n lead.badge?.variant\n )\n \"\n >{{ lead.badge?.value }}</mat-chip\n >\n }\n </div>\n }\n @case (\"text\") {\n <span\n [ngClass]=\"lead.class\"\n [style.cssText]=\"lead.style\"\n >{{ lead.value }}</span\n >\n }\n @case (\"chip\") {\n <mat-chip\n [color]=\"\n isThemeColor(lead.color)\n ? lead.color\n : undefined\n \"\n [ngClass]=\"\n (lead.variant || 'filled') === 'outlined'\n ? 'chip-outlined'\n : ''\n \"\n [style.cssText]=\"\n chipStyle(lead.color, lead.variant)\n \"\n >{{ lead.value }}</mat-chip\n >\n }\n @case (\"rating\") {\n @for (\n _ of ratingRange(lead);\n track $index;\n let idx = $index\n ) {\n <mat-icon\n [praxisIcon]=\"starIcon(idx, lead.value)\"\n [color]=\"ratingThemeColor(lead)\"\n [style.cssText]=\"ratingIconStyle(lead)\"\n ></mat-icon>\n }\n }\n @case (\"html\") {\n <span\n [ngClass]=\"lead.class\"\n [style.cssText]=\"lead.style\"\n [innerHTML]=\"lead.value\"\n ></span>\n }\n @case (\"metric\") {\n <praxis-list-metric [metric]=\"lead\"></praxis-list-metric>\n }\n @default {\n <span\n [ngClass]=\"lead.class\"\n [style.cssText]=\"lead.style\"\n >{{ lead.value }}</span\n >\n }\n }\n } @else {\n <span class=\"leading-placeholder\"></span>\n }\n </div>\n <div class=\"list-item-text\">\n <div\n class=\"primary\"\n [ngClass]=\"primary(item)?.class\"\n [style.cssText]=\"primary(item)?.style\"\n >\n @if (primary(item)?.type === \"metric\") {\n <praxis-list-metric\n [metric]=\"primary(item)\"\n ></praxis-list-metric>\n } @else if (primary(item)?.type === \"html\") {\n <span [innerHTML]=\"primary(item)?.value\"></span>\n } @else {\n {{ primary(item)?.value }}\n }\n </div>\n @if (layoutLines > 1) {\n <div\n class=\"secondary\"\n [ngClass]=\"secondary(item)?.class\"\n [style.cssText]=\"secondary(item)?.style\"\n >\n @if (item.segmentVariant && item.segmentLabel && item.accountType && item.since) {\n <!-- Component-based rendering for executive items -->\n <span class=\"exec-subline\">\n <praxis-executive-badge [variant]=\"item.segmentVariant\">{{ item.segmentLabel }}</praxis-executive-badge>\n <span class=\"exec-subcopy\">{{ item.accountType }}</span>\n <span class=\"exec-subseparator\">\u00B7</span>\n <span class=\"exec-subcopy\">Desde {{ item.since }}</span>\n </span>\n } @else if (secondary(item)?.type === \"html\") {\n <span [innerHTML]=\"secondary(item)?.value\"></span>\n } @else if (secondary(item)?.type === \"metric\") {\n <praxis-list-metric\n [metric]=\"secondary(item)\"\n ></praxis-list-metric>\n } @else {\n {{ secondary(item)?.value }}\n }\n </div>\n }\n @if (meta(item); as m) {\n @if (\n (config.templating?.metaPlacement === \"line\" &&\n (m?.type === \"text\" ||\n m?.type === \"date\" ||\n m?.type === \"currency\")) ||\n (layoutLines > 2 &&\n (m?.type === \"text\" ||\n m?.type === \"date\" ||\n m?.type === \"currency\"))\n ) {\n <div\n class=\"tertiary\"\n [ngClass]=\"m.class\"\n [style.cssText]=\"m.style\"\n >\n @if (config.templating?.metaPrefixIcon; as mpi) {\n <mat-icon [praxisIcon]=\"mpi\"></mat-icon>\n }\n {{ m.value }}\n </div>\n }\n }\n @if (featuresVisible()) {\n <div class=\"features\">\n @for (\n f of config.templating?.features || [];\n track $index;\n let fi = $index\n ) {\n <span\n class=\"feature\"\n [ngClass]=\"\n featureSemanticClass(item, f.expr, f.class)\n \"\n >\n @if (f.icon && featuresMode() !== \"labels-only\") {\n <mat-icon [praxisIcon]=\"f.icon\"></mat-icon>\n }\n @if (featuresMode() !== \"icons-only\") {\n <span\n [ngClass]=\"f.class\"\n [style.cssText]=\"f.style\"\n >\n @for (\n line of featureLabelLines(item, f.expr);\n track $index\n ) {\n <span class=\"feature-line\">{{ line }}</span>\n }\n </span>\n }\n @if (\n featureProgressPercent(item, f.expr, f.class);\n as progress\n ) {\n <span\n class=\"feature-progress\"\n aria-hidden=\"true\"\n >\n <span\n class=\"feature-progress__value\"\n [style.width.%]=\"progress\"\n ></span>\n </span>\n }\n </span>\n }\n </div>\n }\n </div>\n </button>\n <div class=\"list-item-trailing\">\n @if (meta(item); as m) {\n @if (\n !(\n (config.templating?.metaPlacement === \"line\" ||\n layoutLines > 2) &&\n (m?.type === \"text\" ||\n m?.type === \"date\" ||\n m?.type === \"currency\")\n )\n ) {\n <div\n class=\"meta\"\n [ngClass]=\"m.class\"\n [style.cssText]=\"m.style\"\n >\n @switch (m.type) {\n @case (\"chip\") {\n <mat-chip\n [color]=\"\n isThemeColor(m.color) ? m.color : undefined\n \"\n [ngClass]=\"\n (m.variant || 'filled') === 'outlined'\n ? 'chip-outlined'\n : ''\n \"\n [style.cssText]=\"chipStyle(m.color, m.variant)\"\n >{{ m.value }}</mat-chip\n >\n }\n @case (\"rating\") {\n @for (\n _ of ratingRange(m);\n track $index;\n let idx = $index\n ) {\n <mat-icon\n [praxisIcon]=\"starIcon(idx, m.value)\"\n [color]=\"ratingThemeColor(m)\"\n [style.cssText]=\"ratingIconStyle(m)\"\n ></mat-icon>\n }\n }\n @case (\"icon\") {\n <mat-icon\n [praxisIcon]=\"m.value\"\n [color]=\"\n isThemeColor(m.color) ? m.color : undefined\n \"\n [style.cssText]=\"iconStyle(m.color)\"\n ></mat-icon>\n }\n @case (\"image\") {\n <span class=\"inline-image\"\n ><img [src]=\"m.value\" [alt]=\"m.imageAlt || ''\"\n /></span>\n }\n @case (\"html\") {\n <span [innerHTML]=\"m.value\"></span>\n }\n @case (\"metric\") {\n <praxis-list-metric [metric]=\"m\"></praxis-list-metric>\n }\n @default {\n <span>\n @if (\n config.templating?.metaPrefixIcon;\n as mpi2\n ) {\n <mat-icon [praxisIcon]=\"mpi2\"></mat-icon>\n }\n {{ m.value }}</span\n >\n }\n }\n </div>\n }\n }\n @if (trailing(item); as tr) {\n <div\n class=\"trailing\"\n [ngClass]=\"tr.class\"\n [style.cssText]=\"tr.style\"\n >\n @switch (tr.type) {\n @case (\"chip\") {\n <mat-chip\n [color]=\"\n isThemeColor(tr.color) ? tr.color : undefined\n \"\n [ngClass]=\"\n (tr.variant || 'filled') === 'outlined'\n ? 'chip-outlined'\n : ''\n \"\n [style.cssText]=\"chipStyle(tr.color, tr.variant)\"\n >{{ tr.value }}</mat-chip\n >\n }\n @case (\"icon\") {\n <mat-icon\n [praxisIcon]=\"tr.value\"\n [color]=\"\n isThemeColor(tr.color) ? tr.color : undefined\n \"\n [style.cssText]=\"iconStyle(tr.color)\"\n ></mat-icon>\n }\n @case (\"image\") {\n <div\n class=\"lead-image\"\n [ngClass]=\"tr.class\"\n [style.cssText]=\"tr.style\"\n >\n <img\n [src]=\"tr.value\"\n [alt]=\"\n config.templating?.trailing?.imageAlt || ''\n \"\n />\n @if (tr.badge?.value) {\n <mat-chip\n class=\"lead-badge\"\n [color]=\"\n isThemeColor(tr.badge?.color)\n ? tr.badge?.color\n : undefined\n \"\n [ngClass]=\"\n (tr.badge?.variant || 'filled') ===\n 'outlined'\n ? 'chip-outlined'\n : ''\n \"\n [style.cssText]=\"\n chipStyle(\n tr.badge?.color,\n tr.badge?.variant\n )\n \"\n >{{ tr.badge?.value }}</mat-chip\n >\n }\n </div>\n }\n @case (\"rating\") {\n @for (\n _ of ratingRange(tr);\n track $index;\n let idx = $index\n ) {\n <mat-icon\n [praxisIcon]=\"starIcon(idx, tr.value)\"\n [color]=\"ratingThemeColor(tr)\"\n [style.cssText]=\"ratingIconStyle(tr)\"\n ></mat-icon>\n }\n }\n @case (\"html\") {\n @if (item.alertsData !== undefined && item.ownerName) {\n <!-- Component-based rendering for executive trailing -->\n <span class=\"exec-trailing-shell\">\n <praxis-executive-alerts [alerts]=\"item.alertsData\"></praxis-executive-alerts>\n <praxis-executive-owner [name]=\"item.ownerName\"></praxis-executive-owner>\n </span>\n } @else {\n <span [innerHTML]=\"tr.value\"></span>\n }\n }\n @case (\"metric\") {\n <praxis-list-metric [metric]=\"tr\"></praxis-list-metric>\n }\n @default {\n <span>{{ tr.value }}</span>\n }\n }\n </div>\n }\n @if (showExpandIcon(\"trailing\")) {\n <button\n mat-icon-button\n type=\"button\"\n class=\"expand-toggle\"\n [attr.aria-label]=\"expandToggleAriaLabel(item, i)\"\n [attr.aria-expanded]=\"\n expansionOwnedByIcon() ? isExpanded(item, i) : null\n \"\n [attr.aria-controls]=\"\n expansionOwnedByIcon()\n ? expandRegionId(item, i)\n : null\n \"\n (click)=\"onExpandToggle($event, item, i)\"\n >\n <mat-icon\n [praxisIcon]=\"\n isExpanded(item, i) ? 'expand_less' : 'expand_more'\n \"\n ></mat-icon>\n </button>\n }\n @if ((visibleActions(item, \"trailing\") || []).length) {\n <div\n class=\"list-item-actions\"\n (click)=\"$event.stopPropagation()\"\n (keydown.enter)=\"onActionKeydown($event)\"\n (keydown.space)=\"onActionKeydown($event)\"\n >\n @for (\n action of visibleActions(item, \"trailing\");\n let aidx = $index;\n track action?.id ?? $index\n ) {\n @if ((action.kind || \"icon\") === \"icon\") {\n <button\n mat-icon-button\n [color]=\"\n isThemeColor(action.color)\n ? action.color\n : undefined\n \"\n (click)=\"\n onActionClick($event, action.id, item, i)\n \"\n [attr.aria-label]=\"action.label || action.id\"\n [disabled]=\"isActionLoading(action.id, item, i)\"\n [ngClass]=\"{\n 'action-loading': isActionLoading(\n action.id,\n item,\n i\n ),\n }\"\n >\n @if (isActionLoading(action.id, item, i)) {\n <mat-progress-spinner\n class=\"action-spinner\"\n mode=\"indeterminate\"\n diameter=\"16\"\n strokeWidth=\"3\"\n ></mat-progress-spinner>\n } @else {\n <mat-icon\n [praxisIcon]=\"action.icon\"\n [style.cssText]=\"iconStyle(action.color)\"\n ></mat-icon>\n }\n </button>\n } @else {\n @if (action.buttonVariant === \"stroked\") {\n <button\n mat-stroked-button\n [color]=\"\n isThemeColor(action.color)\n ? action.color\n : undefined\n \"\n [style.cssText]=\"\n buttonStyle(action.color, 'stroked')\n \"\n (click)=\"\n onActionClick($event, action.id, item, i)\n \"\n [attr.aria-label]=\"action.label || action.id\"\n [disabled]=\"isActionLoading(action.id, item, i)\"\n [ngClass]=\"{\n 'action-loading': isActionLoading(\n action.id,\n item,\n i\n ),\n }\"\n >\n @if (isActionLoading(action.id, item, i)) {\n <mat-progress-spinner\n class=\"action-spinner\"\n mode=\"indeterminate\"\n diameter=\"16\"\n strokeWidth=\"3\"\n ></mat-progress-spinner>\n } @else {\n {{ action.label || action.id }}\n }\n </button>\n }\n @if (action.buttonVariant === \"raised\") {\n <button\n mat-raised-button\n [color]=\"\n isThemeColor(action.color)\n ? action.color\n : undefined\n \"\n [style.cssText]=\"\n buttonStyle(action.color, 'raised')\n \"\n (click)=\"\n onActionClick($event, action.id, item, i)\n \"\n [attr.aria-label]=\"action.label || action.id\"\n [disabled]=\"isActionLoading(action.id, item, i)\"\n [ngClass]=\"{\n 'action-loading': isActionLoading(\n action.id,\n item,\n i\n ),\n }\"\n >\n @if (isActionLoading(action.id, item, i)) {\n <mat-progress-spinner\n class=\"action-spinner\"\n mode=\"indeterminate\"\n diameter=\"16\"\n strokeWidth=\"3\"\n ></mat-progress-spinner>\n } @else {\n {{ action.label || action.id }}\n }\n </button>\n }\n @if (\n !action.buttonVariant ||\n action.buttonVariant === \"flat\"\n ) {\n <button\n mat-flat-button\n [color]=\"\n isThemeColor(action.color)\n ? action.color\n : undefined\n \"\n [style.cssText]=\"\n buttonStyle(action.color, 'flat')\n \"\n (click)=\"\n onActionClick($event, action.id, item, i)\n \"\n [attr.aria-label]=\"action.label || action.id\"\n [disabled]=\"isActionLoading(action.id, item, i)\"\n [ngClass]=\"{\n 'action-loading': isActionLoading(\n action.id,\n item,\n i\n ),\n }\"\n >\n @if (isActionLoading(action.id, item, i)) {\n <mat-progress-spinner\n class=\"action-spinner\"\n mode=\"indeterminate\"\n diameter=\"16\"\n strokeWidth=\"3\"\n ></mat-progress-spinner>\n } @else {\n {{ action.label || action.id }}\n }\n </button>\n }\n }\n }\n </div>\n }\n </div>\n </div>\n }\n @if (isExpandable() && isExpanded(item, i)) {\n <div\n class=\"item-expansion\"\n [id]=\"expandRegionId(item, i)\"\n role=\"region\"\n [attr.aria-label]=\"expansionRegionAriaLabel(item)\"\n >\n <div class=\"item-expansion-grid\">\n @for (\n expansionSection of expansionSections(item);\n track expansionSection.id\n ) {\n <section\n class=\"expansion-section\"\n [attr.data-section-type]=\"expansionSection.type\"\n >\n @if (expansionSection.title) {\n <div class=\"expansion-section-title\">\n {{ expansionSection.title }}\n </div>\n }\n @if (\n expansionSectionHasContent(\n item,\n expansionSection,\n i\n )\n ) {\n @switch (expansionSection.type) {\n @case (\"chip-list\") {\n <div class=\"expansion-chip-list\">\n @for (\n expansionEntry of expansionSectionItems(\n item,\n expansionSection,\n i\n );\n track $index\n ) {\n <mat-chip class=\"expansion-chip\">{{\n expansionItemLabel(expansionEntry)\n }}</mat-chip>\n }\n </div>\n }\n @case (\"timeline\") {\n <div class=\"expansion-timeline\">\n @for (\n expansionEntry of expansionSectionItems(\n item,\n expansionSection,\n i\n );\n track $index\n ) {\n <div class=\"expansion-timeline-item\">\n <div class=\"expansion-timeline-title\">\n {{\n expansionTimelineTitle(expansionEntry)\n }}\n </div>\n @if (\n expansionTimelineMeta(expansionEntry)\n ) {\n <div class=\"expansion-timeline-meta\">\n {{\n expansionTimelineMeta(\n expansionEntry\n )\n }}\n </div>\n }\n @if (\n expansionTimelineDescription(\n expansionEntry\n )\n ) {\n <div\n class=\"expansion-timeline-description\"\n >\n {{\n expansionTimelineDescription(\n expansionEntry\n )\n }}\n </div>\n }\n </div>\n }\n </div>\n }\n @case (\"key-value\") {\n <dl class=\"expansion-key-value\">\n @for (\n expansionEntry of expansionSectionItems(\n item,\n expansionSection,\n i\n );\n track $index\n ) {\n <div class=\"expansion-key-value-row\">\n @if (\n expansionKeyValueKey(expansionEntry)\n ) {\n <dt>\n {{\n expansionKeyValueKey(expansionEntry)\n }}\n </dt>\n }\n <dd>\n {{\n expansionKeyValueValue(expansionEntry)\n }}\n </dd>\n </div>\n }\n </dl>\n }\n @default {\n <div class=\"expansion-info-list\">\n @for (\n expansionEntry of expansionSectionItems(\n item,\n expansionSection,\n i\n );\n track $index\n ) {\n <div class=\"expansion-info-item\">\n <div class=\"expansion-info-title\">\n {{ expansionInfoTitle(expansionEntry) }}\n </div>\n @if (expansionInfoValue(expansionEntry)) {\n <div class=\"expansion-info-value\">\n {{\n expansionInfoValue(expansionEntry)\n }}\n </div>\n }\n </div>\n }\n </div>\n }\n }\n } @else {\n <div class=\"expansion-empty\">\n {{\n expansionSection.emptyLabel ||\n \"Sem dados dispon\u00EDveis\"\n }}\n </div>\n }\n </section>\n }\n </div>\n </div>\n }\n </mat-list-item>\n @if (\n (config.layout?.dividers === \"all\" ||\n config.layout?.dividers === \"between\") &&\n i < section.items.length - 1\n ) {\n <mat-divider></mat-divider>\n }\n }\n }\n </mat-list>\n </ng-template>\n } @else if (isTilesVariant()) {\n <ng-container *ngTemplateOutlet=\"tilesVariant\"></ng-container>\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\n class=\"item-card\"\n [ngClass]=\"itemRuleClass(it)\"\n [attr.style]=\"itemRuleStyle(it)\"\n role=\"button\"\n tabindex=\"0\"\n [attr.aria-label]=\"itemAriaLabel(it)\"\n (click)=\"onItemClick(it, i)\"\n (keydown.enter)=\"onItemClick(it, i)\"\n (keydown.space)=\"$event.preventDefault(); onItemClick(it, i)\"\n >\n <div class=\"list-item-content\">\n <div class=\"list-item-leading\">\n @if (leading(it); as lead) {\n @switch (lead.type) {\n @case (\"icon\") {\n <mat-icon\n [praxisIcon]=\"lead.value\"\n [ngClass]=\"lead.class\"\n [color]=\"\n isThemeColor(lead.color) ? lead.color : undefined\n \"\n [style.cssText]=\"\n (lead.style ? lead.style + ';' : '') +\n iconStyle(lead.color)\n \"\n ></mat-icon>\n }\n @case (\"image\") {\n <div\n class=\"lead-image\"\n [ngClass]=\"lead.class\"\n [style.cssText]=\"lead.style\"\n >\n <img\n [src]=\"lead.value\"\n [alt]=\"config.templating?.leading?.imageAlt || ''\"\n />\n @if (lead.badge?.value) {\n <mat-chip\n class=\"lead-badge\"\n [color]=\"\n isThemeColor(lead.badge?.color)\n ? lead.badge?.color\n : undefined\n \"\n [ngClass]=\"\n (lead.badge?.variant || 'filled') === 'outlined'\n ? 'chip-outlined'\n : ''\n \"\n [style.cssText]=\"\n chipStyle(lead.badge?.color, lead.badge?.variant)\n \"\n >{{ lead.badge?.value }}</mat-chip\n >\n }\n </div>\n }\n @case (\"text\") {\n <span\n [ngClass]=\"lead.class\"\n [style.cssText]=\"lead.style\"\n >{{ lead.value }}</span\n >\n }\n @case (\"chip\") {\n <mat-chip\n [color]=\"\n isThemeColor(lead.color) ? lead.color : undefined\n \"\n [ngClass]=\"\n (lead.variant || 'filled') === 'outlined'\n ? 'chip-outlined'\n : ''\n \"\n [style.cssText]=\"chipStyle(lead.color, lead.variant)\"\n >{{ lead.value }}</mat-chip\n >\n }\n @case (\"rating\") {\n @for (\n _ of ratingRange(lead);\n track $index;\n let idx = $index\n ) {\n <mat-icon\n [praxisIcon]=\"starIcon(idx, lead.value)\"\n [color]=\"ratingThemeColor(lead)\"\n [style.cssText]=\"ratingIconStyle(lead)\"\n ></mat-icon>\n }\n }\n @case (\"html\") {\n <span\n [ngClass]=\"lead.class\"\n [style.cssText]=\"lead.style\"\n [innerHTML]=\"lead.value\"\n ></span>\n }\n @case (\"metric\") {\n <praxis-list-metric [metric]=\"lead\"></praxis-list-metric>\n }\n @case (\"compose\") {\n <praxis-list-compose\n [compose]=\"lead\"\n ></praxis-list-compose>\n }\n @case (\"component\") {\n <praxis-list-runtime-component\n [component]=\"lead\"\n ></praxis-list-runtime-component>\n }\n @default {\n <span\n [ngClass]=\"lead.class\"\n [style.cssText]=\"lead.style\"\n >{{ lead.value }}</span\n >\n }\n }\n } @else {\n <span class=\"leading-placeholder\"></span>\n }\n </div>\n <div class=\"list-item-text\">\n <div\n class=\"primary\"\n [ngClass]=\"primary(it)?.class\"\n [style.cssText]=\"primary(it)?.style\"\n >\n @if (primary(it)?.type === \"metric\") {\n <praxis-list-metric [metric]=\"primary(it)\"></praxis-list-metric>\n } @else if (primary(it)?.type === \"compose\") {\n <praxis-list-compose\n [compose]=\"primary(it)\"\n ></praxis-list-compose>\n } @else if (primary(it)?.type === \"component\") {\n <praxis-list-runtime-component\n [component]=\"primary(it)\"\n ></praxis-list-runtime-component>\n } @else {\n {{ primary(it)?.value }}\n }\n </div>\n @if (layoutLines > 1) {\n <div\n class=\"secondary\"\n [ngClass]=\"secondary(it)?.class\"\n [style.cssText]=\"secondary(it)?.style\"\n >\n @if (secondary(it)?.type === \"metric\") {\n <praxis-list-metric\n [metric]=\"secondary(it)\"\n ></praxis-list-metric>\n } @else if (secondary(it)?.type === \"compose\") {\n <praxis-list-compose\n [compose]=\"secondary(it)\"\n ></praxis-list-compose>\n } @else if (secondary(it)?.type === \"component\") {\n <praxis-list-runtime-component\n [component]=\"secondary(it)\"\n ></praxis-list-runtime-component>\n } @else {\n {{ secondary(it)?.value }}\n }\n </div>\n }\n @if (meta(it); as m) {\n @if (\n (config.templating?.metaPlacement === \"line\" &&\n (m?.type === \"text\" ||\n m?.type === \"date\" ||\n m?.type === \"currency\")) ||\n (layoutLines > 2 &&\n (m?.type === \"text\" ||\n m?.type === \"date\" ||\n m?.type === \"currency\"))\n ) {\n <div\n class=\"tertiary\"\n [ngClass]=\"m.class\"\n [style.cssText]=\"m.style\"\n >\n @if (config.templating?.metaPrefixIcon; as mpi) {\n <mat-icon [praxisIcon]=\"mpi\"></mat-icon>\n }\n {{ m.value }}\n </div>\n }\n }\n @if (featuresVisible()) {\n <div class=\"features\">\n @for (\n f of config.templating?.features || [];\n track $index;\n let fi = $index\n ) {\n <span\n class=\"feature\"\n [ngClass]=\"featureSemanticClass(it, f.expr, f.class)\"\n >\n @if (f.icon && featuresMode() !== \"labels-only\") {\n <mat-icon [praxisIcon]=\"f.icon\"></mat-icon>\n }\n @if (featuresMode() !== \"icons-only\") {\n <span [ngClass]=\"f.class\" [style.cssText]=\"f.style\">\n @for (\n line of featureLabelLines(it, f.expr);\n track $index\n ) {\n <span class=\"feature-line\">{{ line }}</span>\n }\n </span>\n }\n @if (\n featureProgressPercent(it, f.expr, f.class);\n as progress\n ) {\n <span class=\"feature-progress\" aria-hidden=\"true\">\n <span\n class=\"feature-progress__value\"\n [style.width.%]=\"progress\"\n ></span>\n </span>\n }\n </span>\n }\n </div>\n }\n </div>\n <div class=\"list-item-trailing\">\n @if (meta(it); as m) {\n @if (\n !(\n (config.templating?.metaPlacement === \"line\" ||\n layoutLines > 2) &&\n (m?.type === \"text\" ||\n m?.type === \"date\" ||\n m?.type === \"currency\")\n )\n ) {\n <div\n class=\"meta\"\n [ngClass]=\"m.class\"\n [style.cssText]=\"m.style\"\n >\n @switch (m.type) {\n @case (\"chip\") {\n <mat-chip\n [color]=\"\n isThemeColor(m.color) ? m.color : undefined\n \"\n [ngClass]=\"\n (m.variant || 'filled') === 'outlined'\n ? 'chip-outlined'\n : ''\n \"\n [style.cssText]=\"chipStyle(m.color, m.variant)\"\n >{{ m.value }}</mat-chip\n >\n }\n @case (\"rating\") {\n @for (\n _ of ratingRange(m);\n track $index;\n let idx = $index\n ) {\n <mat-icon\n [praxisIcon]=\"starIcon(idx, m.value)\"\n [color]=\"ratingThemeColor(m)\"\n [style.cssText]=\"ratingIconStyle(m)\"\n ></mat-icon>\n }\n }\n @case (\"icon\") {\n <mat-icon\n [praxisIcon]=\"m.value\"\n [color]=\"\n isThemeColor(m.color) ? m.color : undefined\n \"\n [style.cssText]=\"iconStyle(m.color)\"\n ></mat-icon>\n }\n @case (\"image\") {\n <span class=\"inline-image\"\n ><img [src]=\"m.value\" [alt]=\"m.imageAlt || ''\"\n /></span>\n }\n @case (\"html\") {\n <span [innerHTML]=\"m.value\"></span>\n }\n @case (\"metric\") {\n <praxis-list-metric [metric]=\"m\"></praxis-list-metric>\n }\n @case (\"compose\") {\n <praxis-list-compose\n [compose]=\"m\"\n ></praxis-list-compose>\n }\n @case (\"component\") {\n <praxis-list-runtime-component\n [component]=\"m\"\n ></praxis-list-runtime-component>\n }\n @default {\n <span>\n @if (config.templating?.metaPrefixIcon; as mpi2) {\n <mat-icon [praxisIcon]=\"mpi2\"></mat-icon>\n }\n {{ m.value }}</span\n >\n }\n }\n </div>\n }\n }\n @if (trailing(it); as tr) {\n @if (\n (config.templating?.statusPosition || \"inline\") ===\n \"top-right\" &&\n (tr?.type === \"chip\" || tr?.type === \"icon\")\n ) {\n <div class=\"status-overlay\">\n @if (tr?.type === \"chip\") {\n <mat-chip\n [color]=\"\n isThemeColor(tr.color) ? tr.color : undefined\n \"\n [ngClass]=\"\n (tr.variant || 'filled') === 'outlined'\n ? 'chip-outlined'\n : ''\n \"\n [style.cssText]=\"chipStyle(tr.color, tr.variant)\"\n >{{ tr.value }}</mat-chip\n >\n }\n @if (tr?.type === \"icon\") {\n <mat-icon\n [praxisIcon]=\"tr.value\"\n [color]=\"\n isThemeColor(tr.color) ? tr.color : undefined\n \"\n [style.cssText]=\"iconStyle(tr.color)\"\n ></mat-icon>\n }\n </div>\n } @else {\n <div\n class=\"trailing\"\n [ngClass]=\"tr.class\"\n [style.cssText]=\"tr.style\"\n >\n @switch (tr.type) {\n @case (\"chip\") {\n <mat-chip\n [color]=\"\n isThemeColor(tr.color) ? tr.color : undefined\n \"\n [ngClass]=\"\n (tr.variant || 'filled') === 'outlined'\n ? 'chip-outlined'\n : ''\n \"\n [style.cssText]=\"chipStyle(tr.color, tr.variant)\"\n >{{ tr.value }}</mat-chip\n >\n }\n @case (\"icon\") {\n <mat-icon\n [praxisIcon]=\"tr.value\"\n [color]=\"\n isThemeColor(tr.color) ? tr.color : undefined\n \"\n [style.cssText]=\"iconStyle(tr.color)\"\n ></mat-icon>\n }\n @case (\"image\") {\n <div\n class=\"lead-image\"\n [ngClass]=\"tr.class\"\n [style.cssText]=\"tr.style\"\n >\n <img\n [src]=\"tr.value\"\n [alt]=\"\n config.templating?.trailing?.imageAlt || ''\n \"\n />\n @if (tr.badge?.value) {\n <mat-chip\n class=\"lead-badge\"\n [color]=\"\n isThemeColor(tr.badge?.color)\n ? tr.badge?.color\n : undefined\n \"\n [ngClass]=\"\n (tr.badge?.variant || 'filled') === 'outlined'\n ? 'chip-outlined'\n : ''\n \"\n [style.cssText]=\"\n chipStyle(tr.badge?.color, tr.badge?.variant)\n \"\n >{{ tr.badge?.value }}</mat-chip\n >\n }\n </div>\n }\n @case (\"rating\") {\n @for (\n _ of ratingRange(tr);\n track $index;\n let idx = $index\n ) {\n <mat-icon\n [praxisIcon]=\"starIcon(idx, tr.value)\"\n [color]=\"ratingThemeColor(tr)\"\n [style.cssText]=\"ratingIconStyle(tr)\"\n ></mat-icon>\n }\n }\n @case (\"html\") {\n <span [innerHTML]=\"tr.value\"></span>\n }\n @case (\"metric\") {\n <praxis-list-metric [metric]=\"tr\"></praxis-list-metric>\n }\n @case (\"compose\") {\n <praxis-list-compose\n [compose]=\"tr\"\n ></praxis-list-compose>\n }\n @case (\"component\") {\n <praxis-list-runtime-component\n [component]=\"tr\"\n ></praxis-list-runtime-component>\n }\n @default {\n <span>{{ tr.value }}</span>\n }\n }\n </div>\n }\n }\n </div>\n </div>\n <div\n class=\"card-actions\"\n (click)=\"$event.stopPropagation()\"\n (keydown.enter)=\"onActionKeydown($event)\"\n (keydown.space)=\"onActionKeydown($event)\"\n >\n @for (\n action of visibleActions(it, \"trailing\");\n let aidx = $index;\n track action?.id ?? $index\n ) {\n @if ((action.kind || \"icon\") === \"icon\") {\n <button\n mat-icon-button\n [color]=\"\n isThemeColor(action.color) ? action.color : undefined\n \"\n (click)=\"onActionClick($event, action.id, it, i)\"\n [attr.aria-label]=\"action.label || action.id\"\n [disabled]=\"isActionLoading(action.id, it, i)\"\n [ngClass]=\"{\n 'action-loading': isActionLoading(action.id, it, i),\n }\"\n >\n @if (isActionLoading(action.id, it, i)) {\n <mat-progress-spinner\n class=\"action-spinner\"\n mode=\"indeterminate\"\n diameter=\"16\"\n strokeWidth=\"3\"\n ></mat-progress-spinner>\n } @else {\n <mat-icon\n [praxisIcon]=\"action.icon\"\n [style.cssText]=\"iconStyle(action.color)\"\n ></mat-icon>\n }\n </button>\n } @else {\n @if (action.buttonVariant === \"stroked\") {\n <button\n mat-stroked-button\n [color]=\"\n isThemeColor(action.color) ? action.color : undefined\n \"\n [style.cssText]=\"buttonStyle(action.color, 'stroked')\"\n (click)=\"onActionClick($event, action.id, it, i)\"\n [attr.aria-label]=\"action.label || action.id\"\n [disabled]=\"isActionLoading(action.id, it, i)\"\n [ngClass]=\"{\n 'action-loading': isActionLoading(action.id, it, i),\n }\"\n >\n @if (isActionLoading(action.id, it, i)) {\n <mat-progress-spinner\n class=\"action-spinner\"\n mode=\"indeterminate\"\n diameter=\"16\"\n strokeWidth=\"3\"\n ></mat-progress-spinner>\n } @else {\n {{ action.label || action.id }}\n }\n </button>\n }\n @if (action.buttonVariant === \"raised\") {\n <button\n mat-raised-button\n [color]=\"\n isThemeColor(action.color) ? action.color : undefined\n \"\n [style.cssText]=\"buttonStyle(action.color, 'raised')\"\n (click)=\"onActionClick($event, action.id, it, i)\"\n [attr.aria-label]=\"action.label || action.id\"\n [disabled]=\"isActionLoading(action.id, it, i)\"\n [ngClass]=\"{\n 'action-loading': isActionLoading(action.id, it, i),\n }\"\n >\n @if (isActionLoading(action.id, it, i)) {\n <mat-progress-spinner\n class=\"action-spinner\"\n mode=\"indeterminate\"\n diameter=\"16\"\n strokeWidth=\"3\"\n ></mat-progress-spinner>\n } @else {\n {{ action.label || action.id }}\n }\n </button>\n }\n @if (\n !action.buttonVariant || action.buttonVariant === \"flat\"\n ) {\n <button\n mat-flat-button\n [color]=\"\n isThemeColor(action.color) ? action.color : undefined\n \"\n [style.cssText]=\"buttonStyle(action.color, 'flat')\"\n (click)=\"onActionClick($event, action.id, it, i)\"\n [attr.aria-label]=\"action.label || action.id\"\n [disabled]=\"isActionLoading(action.id, it, i)\"\n [ngClass]=\"{\n 'action-loading': isActionLoading(action.id, it, i),\n }\"\n >\n @if (isActionLoading(action.id, it, i)) {\n <mat-progress-spinner\n class=\"action-spinner\"\n mode=\"indeterminate\"\n diameter=\"16\"\n strokeWidth=\"3\"\n ></mat-progress-spinner>\n } @else {\n {{ action.label || action.id }}\n }\n </button>\n }\n }\n }\n </div>\n </div>\n }\n </div>\n </ng-template>\n\n <!-- Tiles variant -->\n <ng-template #tilesVariant>\n <div class=\"tiles-grid\">\n @for (it of (items$ | async) ?? []; track $index; let i = $index) {\n <div\n class=\"item-tile\"\n [ngClass]=\"itemRuleClass(it)\"\n [attr.style]=\"itemRuleStyle(it)\"\n role=\"button\"\n tabindex=\"0\"\n [attr.aria-label]=\"itemAriaLabel(it)\"\n (click)=\"onItemClick(it, i)\"\n (keydown.enter)=\"onItemClick(it, i)\"\n (keydown.space)=\"$event.preventDefault(); onItemClick(it, i)\"\n >\n <div class=\"tile-media\">\n @if (leading(it); as lead) {\n @switch (lead.type) {\n @case (\"image\") {\n <img\n [src]=\"lead.value\"\n [alt]=\"config.templating?.leading?.imageAlt || ''\"\n />\n }\n @case (\"icon\") {\n <mat-icon\n [praxisIcon]=\"lead.value\"\n [ngClass]=\"lead.class\"\n [color]=\"\n isThemeColor(lead.color) ? lead.color : undefined\n \"\n [style.cssText]=\"\n (lead.style ? lead.style + ';' : '') +\n iconStyle(lead.color)\n \"\n ></mat-icon>\n }\n @case (\"text\") {\n <span [ngClass]=\"lead.class\" [style.cssText]=\"lead.style\">{{\n lead.value\n }}</span>\n }\n @case (\"chip\") {\n <mat-chip\n [color]=\"\n isThemeColor(lead.color) ? lead.color : undefined\n \"\n [ngClass]=\"\n (lead.variant || 'filled') === 'outlined'\n ? 'chip-outlined'\n : ''\n \"\n [style.cssText]=\"chipStyle(lead.color, lead.variant)\"\n >{{ lead.value }}</mat-chip\n >\n }\n @case (\"rating\") {\n <span [ngClass]=\"lead.class\" [style.cssText]=\"lead.style\">\n @for (\n _ of ratingRange(lead);\n track $index;\n let idx = $index\n ) {\n <mat-icon\n [praxisIcon]=\"starIcon(idx, lead.value)\"\n [color]=\"ratingThemeColor(lead)\"\n [style.cssText]=\"ratingIconStyle(lead)\"\n ></mat-icon>\n }\n </span>\n }\n @case (\"html\") {\n <span\n [ngClass]=\"lead.class\"\n [style.cssText]=\"lead.style\"\n [innerHTML]=\"lead.value\"\n ></span>\n }\n @case (\"metric\") {\n <praxis-list-metric [metric]=\"lead\"></praxis-list-metric>\n }\n @case (\"compose\") {\n <praxis-list-compose\n [compose]=\"lead\"\n ></praxis-list-compose>\n }\n @case (\"component\") {\n <praxis-list-runtime-component\n [component]=\"lead\"\n ></praxis-list-runtime-component>\n }\n @default {\n <span [ngClass]=\"lead.class\" [style.cssText]=\"lead.style\">{{\n lead.value\n }}</span>\n }\n }\n }\n </div>\n\n @if (trailing(it); as tr) {\n @if (\n (config.templating?.statusPosition || \"inline\") ===\n \"top-right\" &&\n (tr?.type === \"chip\" || tr?.type === \"icon\")\n ) {\n <div class=\"tile-status\">\n @if (tr?.type === \"chip\") {\n <mat-chip\n [color]=\"isThemeColor(tr.color) ? tr.color : undefined\"\n [ngClass]=\"\n (tr.variant || 'filled') === 'outlined'\n ? 'chip-outlined'\n : ''\n \"\n [style.cssText]=\"chipStyle(tr.color, tr.variant)\"\n >{{ tr.value }}</mat-chip\n >\n }\n @if (tr?.type === \"icon\") {\n <mat-icon\n [praxisIcon]=\"tr.value\"\n [color]=\"isThemeColor(tr.color) ? tr.color : undefined\"\n [style.cssText]=\"iconStyle(tr.color)\"\n ></mat-icon>\n }\n </div>\n }\n }\n\n <div class=\"tile-body\">\n <div\n class=\"primary\"\n [ngClass]=\"primary(it)?.class\"\n [style.cssText]=\"primary(it)?.style\"\n >\n @if (primary(it)?.type === \"metric\") {\n <praxis-list-metric [metric]=\"primary(it)\"></praxis-list-metric>\n } @else if (primary(it)?.type === \"compose\") {\n <praxis-list-compose\n [compose]=\"primary(it)\"\n ></praxis-list-compose>\n } @else if (primary(it)?.type === \"component\") {\n <praxis-list-runtime-component\n [component]=\"primary(it)\"\n ></praxis-list-runtime-component>\n } @else {\n {{ primary(it)?.value }}\n }\n </div>\n @if (layoutLines > 1) {\n <div\n class=\"secondary\"\n [ngClass]=\"secondary(it)?.class\"\n [style.cssText]=\"secondary(it)?.style\"\n >\n @if (secondary(it)?.type === \"metric\") {\n <praxis-list-metric\n [metric]=\"secondary(it)\"\n ></praxis-list-metric>\n } @else if (secondary(it)?.type === \"compose\") {\n <praxis-list-compose\n [compose]=\"secondary(it)\"\n ></praxis-list-compose>\n } @else if (secondary(it)?.type === \"component\") {\n <praxis-list-runtime-component\n [component]=\"secondary(it)\"\n ></praxis-list-runtime-component>\n } @else {\n {{ secondary(it)?.value }}\n }\n </div>\n }\n\n @if (meta(it); as m) {\n <div\n class=\"tile-meta\"\n [ngClass]=\"m.class\"\n [style.cssText]=\"m.style\"\n >\n @if (config.templating?.metaPrefixIcon; as mpi) {\n <mat-icon [praxisIcon]=\"mpi\"></mat-icon>\n }\n @switch (m.type) {\n @case (\"chip\") {\n <mat-chip\n [color]=\"isThemeColor(m.color) ? m.color : undefined\"\n [ngClass]=\"\n (m.variant || 'filled') === 'outlined'\n ? 'chip-outlined'\n : ''\n \"\n [style.cssText]=\"chipStyle(m.color, m.variant)\"\n >{{ m.value }}</mat-chip\n >\n }\n @case (\"rating\") {\n @for (\n _ of ratingRange(m);\n track $index;\n let idx = $index\n ) {\n <mat-icon\n [praxisIcon]=\"starIcon(idx, m.value)\"\n [color]=\"ratingThemeColor(m)\"\n [style.cssText]=\"ratingIconStyle(m)\"\n ></mat-icon>\n }\n }\n @case (\"icon\") {\n <mat-icon\n [praxisIcon]=\"m.value\"\n [color]=\"isThemeColor(m.color) ? m.color : undefined\"\n [style.cssText]=\"iconStyle(m.color)\"\n ></mat-icon>\n }\n @case (\"image\") {\n <span class=\"inline-image\"\n ><img [src]=\"m.value\" [alt]=\"m.imageAlt || ''\"\n /></span>\n }\n @case (\"html\") {\n <span [innerHTML]=\"m.value\"></span>\n }\n @case (\"metric\") {\n <praxis-list-metric [metric]=\"m\"></praxis-list-metric>\n }\n @case (\"compose\") {\n <praxis-list-compose\n [compose]=\"m\"\n ></praxis-list-compose>\n }\n @case (\"component\") {\n <praxis-list-runtime-component\n [component]=\"m\"\n ></praxis-list-runtime-component>\n }\n @default {\n <span>{{ m.value }}</span>\n }\n }\n </div>\n }\n\n @if (featuresVisible()) {\n <div class=\"tiles-features\">\n @for (\n f of config.templating?.features || [];\n track $index;\n let fi = $index\n ) {\n <span\n class=\"feature\"\n [ngClass]=\"featureSemanticClass(it, f.expr, f.class)\"\n >\n @if (f.icon && featuresMode() !== \"labels-only\") {\n <mat-icon [praxisIcon]=\"f.icon\"></mat-icon>\n }\n @if (featuresMode() !== \"icons-only\") {\n <span [ngClass]=\"f.class\" [style.cssText]=\"f.style\">\n @for (\n line of featureLabelLines(it, f.expr);\n track $index\n ) {\n <span class=\"feature-line\">{{ line }}</span>\n }\n </span>\n }\n @if (\n featureProgressPercent(it, f.expr, f.class);\n as progress\n ) {\n <span class=\"feature-progress\" aria-hidden=\"true\">\n <span\n class=\"feature-progress__value\"\n [style.width.%]=\"progress\"\n ></span>\n </span>\n }\n </span>\n }\n </div>\n }\n\n @if (trailing(it); as tr2) {\n @if (\n !(\n (config.templating?.statusPosition || \"inline\") ===\n \"top-right\" &&\n (tr2?.type === \"chip\" || tr2?.type === \"icon\")\n )\n ) {\n <div\n class=\"tile-trailing\"\n [ngClass]=\"tr2.class\"\n [style.cssText]=\"tr2.style\"\n >\n @switch (tr2.type) {\n @case (\"chip\") {\n <mat-chip\n [color]=\"\n isThemeColor(tr2.color) ? tr2.color : undefined\n \"\n [ngClass]=\"\n (tr2.variant || 'filled') === 'outlined'\n ? 'chip-outlined'\n : ''\n \"\n [style.cssText]=\"chipStyle(tr2.color, tr2.variant)\"\n >{{ tr2.value }}</mat-chip\n >\n }\n @case (\"icon\") {\n <mat-icon\n [praxisIcon]=\"tr2.value\"\n [color]=\"\n isThemeColor(tr2.color) ? tr2.color : undefined\n \"\n [style.cssText]=\"iconStyle(tr2.color)\"\n ></mat-icon>\n }\n @case (\"image\") {\n <span class=\"inline-image\"\n ><img [src]=\"tr2.value\" [alt]=\"tr2.imageAlt || ''\"\n /></span>\n }\n @case (\"rating\") {\n @for (\n _ of ratingRange(tr2);\n track $index;\n let idx = $index\n ) {\n <mat-icon\n [praxisIcon]=\"starIcon(idx, tr2.value)\"\n [color]=\"ratingThemeColor(tr2)\"\n [style.cssText]=\"ratingIconStyle(tr2)\"\n ></mat-icon>\n }\n }\n @case (\"html\") {\n <span [innerHTML]=\"tr2.value\"></span>\n }\n @case (\"metric\") {\n <praxis-list-metric [metric]=\"tr2\"></praxis-list-metric>\n }\n @case (\"compose\") {\n <praxis-list-compose\n [compose]=\"tr2\"\n ></praxis-list-compose>\n }\n @case (\"component\") {\n <praxis-list-runtime-component\n [component]=\"tr2\"\n ></praxis-list-runtime-component>\n }\n @default {\n <span>{{ tr2.value }}</span>\n }\n }\n </div>\n }\n }\n </div>\n\n @if ((visibleActions(it, \"trailing\") || []).length) {\n <div\n class=\"tile-actions\"\n (click)=\"$event.stopPropagation()\"\n (keydown.enter)=\"onActionKeydown($event)\"\n (keydown.space)=\"onActionKeydown($event)\"\n >\n @for (\n action of visibleActions(it, \"trailing\");\n let aidx = $index;\n track action?.id ?? $index\n ) {\n @if ((action.kind || \"icon\") === \"icon\") {\n <button\n mat-icon-button\n [color]=\"\n isThemeColor(action.color) ? action.color : undefined\n \"\n (click)=\"onActionClick($event, action.id, it, i)\"\n [attr.aria-label]=\"action.label || action.id\"\n [disabled]=\"isActionLoading(action.id, it, i)\"\n [ngClass]=\"{\n 'action-loading': isActionLoading(action.id, it, i),\n }\"\n >\n @if (isActionLoading(action.id, it, i)) {\n <mat-progress-spinner\n class=\"action-spinner\"\n mode=\"indeterminate\"\n diameter=\"16\"\n strokeWidth=\"3\"\n ></mat-progress-spinner>\n } @else {\n <mat-icon\n [praxisIcon]=\"action.icon\"\n [style.cssText]=\"iconStyle(action.color)\"\n ></mat-icon>\n }\n </button>\n } @else {\n @if (action.buttonVariant === \"stroked\") {\n <button\n mat-stroked-button\n [color]=\"\n isThemeColor(action.color) ? action.color : undefined\n \"\n [style.cssText]=\"buttonStyle(action.color, 'stroked')\"\n (click)=\"onActionClick($event, action.id, it, i)\"\n [attr.aria-label]=\"action.label || action.id\"\n [disabled]=\"isActionLoading(action.id, it, i)\"\n [ngClass]=\"{\n 'action-loading': isActionLoading(action.id, it, i),\n }\"\n >\n @if (isActionLoading(action.id, it, i)) {\n <mat-progress-spinner\n class=\"action-spinner\"\n mode=\"indeterminate\"\n diameter=\"16\"\n strokeWidth=\"3\"\n ></mat-progress-spinner>\n } @else {\n {{ action.label || action.id }}\n }\n </button>\n }\n @if (action.buttonVariant === \"raised\") {\n <button\n mat-raised-button\n [color]=\"\n isThemeColor(action.color) ? action.color : undefined\n \"\n [style.cssText]=\"buttonStyle(action.color, 'raised')\"\n (click)=\"onActionClick($event, action.id, it, i)\"\n [attr.aria-label]=\"action.label || action.id\"\n [disabled]=\"isActionLoading(action.id, it, i)\"\n [ngClass]=\"{\n 'action-loading': isActionLoading(action.id, it, i),\n }\"\n >\n @if (isActionLoading(action.id, it, i)) {\n <mat-progress-spinner\n class=\"action-spinner\"\n mode=\"indeterminate\"\n diameter=\"16\"\n strokeWidth=\"3\"\n ></mat-progress-spinner>\n } @else {\n {{ action.label || action.id }}\n }\n </button>\n }\n @if (\n !action.buttonVariant || action.buttonVariant === \"flat\"\n ) {\n <button\n mat-flat-button\n [color]=\"\n isThemeColor(action.color) ? action.color : undefined\n \"\n [style.cssText]=\"buttonStyle(action.color, 'flat')\"\n (click)=\"onActionClick($event, action.id, it, i)\"\n [attr.aria-label]=\"action.label || action.id\"\n [disabled]=\"isActionLoading(action.id, it, i)\"\n [ngClass]=\"{\n 'action-loading': isActionLoading(action.id, it, i),\n }\"\n >\n @if (isActionLoading(action.id, it, i)) {\n <mat-progress-spinner\n class=\"action-spinner\"\n mode=\"indeterminate\"\n diameter=\"16\"\n strokeWidth=\"3\"\n ></mat-progress-spinner>\n } @else {\n {{ action.label || action.id }}\n }\n </button>\n }\n }\n }\n </div>\n }\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 <div class=\"paginator-controls\">\n <button mat-stroked-button color=\"primary\" (click)=\"prevPage()\">\n Anterior\n </button>\n <button mat-stroked-button color=\"primary\" (click)=\"nextPage()\">\n Pr\u00F3ximo\n </button>\n <mat-form-field class=\"paginator-page-size\" appearance=\"outline\">\n <mat-label>Tam. p\u00E1gina</mat-label>\n <mat-select\n (selectionChange)=\"setPageSize($event.value)\"\n [value]=\"config.layout?.pageSize || 10\"\n >\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 (config.ui?.showSort) {\n <mat-form-field class=\"paginator-sort\" appearance=\"outline\">\n <mat-label>Ordenar</mat-label>\n <mat-select (selectionChange)=\"onSortChange($event.value)\">\n @for (op of config.ui?.sortOptions || []; track $index) {\n <mat-option [value]=\"sortOptionValue(op)\">{{\n sortOptionLabel(op)\n }}</mat-option>\n }\n </mat-select>\n </mat-form-field>\n }\n @if (config.ui?.showSearch && config.ui?.searchField) {\n <mat-form-field class=\"paginator-search\" appearance=\"outline\">\n <mat-label>{{\n config.ui?.searchPlaceholder || \"Buscar\"\n }}</mat-label>\n <input\n matInput\n type=\"search\"\n (input)=\"onSearchInput($any($event.target).value)\"\n />\n </mat-form-field>\n }\n </div>\n <div class=\"paginator-meta\">\n @if (config.ui?.showRange ?? true) {\n @if (page$ | async; as ps) {\n @if (total$ | async; as total) {\n @if (items$ | async; as curr) {\n <span class=\"muted\"\n >{{ (total || 0) > 0 ? rangeStart(ps) : 0 }}\u2013{{\n rangeEnd(curr?.length || 0, ps, total || 0)\n }}\n de {{ total || 0 }}</span\n >\n }\n }\n }\n } @else {\n @if (total$ | async; as total2) {\n <span class=\"muted\">Total: {{ total2 }}</span>\n }\n }\n </div>\n </div>\n }\n </ng-template>\n</div>\n", styles: ["@charset \"UTF-8\";:host{display:block}.praxis-list-root{--p-list-radius: var(--md-sys-shape-corner-medium, 16px);--p-list-shadow: var(--md-sys-elevation-level2);--p-list-border: 1px solid var(--md-sys-color-outline-variant);--p-list-blur: 10px;--p-list-surface: var(--md-sys-color-surface-container);--p-list-surface-low: var(--md-sys-color-surface);--p-list-surface-high: var( --md-sys-color-surface-container-high, var(--md-sys-color-surface-container) );--p-list-foreground: var(--md-sys-color-on-surface);--p-list-foreground-muted: var(--md-sys-color-on-surface-variant);--p-list-accent: var(--md-sys-color-primary);--p-list-accent-weak: var(--md-sys-color-primary-container);--p-list-item-surface: var( --md-sys-color-surface-container-low, var(--md-sys-color-surface) );--p-list-item-border: 1px solid var(--md-sys-color-outline-variant);--p-list-item-hover-surface: var(--md-sys-color-surface-container-low);--p-list-item-active-surface: var(--md-sys-color-surface-container);--p-list-item-selected-surface: var(--md-sys-color-surface-container);--p-list-grad-from: var(--md-sys-color-primary-container);--p-list-grad-to: var(--md-sys-color-tertiary-container);--p-list-grad-angle: 135deg;--p-list-grad-foreground: var(--md-sys-color-on-primary);--p-list-grad-foreground-muted: var(--md-sys-color-on-primary);--p-list-leading-width: 40px;--p-list-trailing-min-width: 140px;--p-list-item-gap: 12px;--p-list-item-padding-x: 16px;--p-list-item-padding-y: 12px;--p-list-item-stack-gap: 0px;--p-list-meta-size: .95rem;--p-list-meta-weight: 500;--p-list-chip-height: 22px;--p-list-chip-font-size: 12px;--p-list-trailing-padding-right: 12px;--p-list-tile-minW: 240px;--p-list-tile-gap: 16px;--p-list-tile-padding: 16px;--p-list-tile-radius: 16px;--p-list-tile-media-radius: 12px;--p-list-tile-media-ratio: 1 / 1;--p-list-tile-hover-overlay: .04;--p-list-tile-press-overlay: .08;--p-list-tile-press-scale: .99}.list-assistant{display:flex;justify-content:flex-end;gap:8px;padding:4px 4px 8px}.action-loading{opacity:.65}.action-spinner{width:16px;height:16px;display:inline-flex;align-items:center;justify-content:center}.action-loading .mat-mdc-button-touch-target,.action-loading .mdc-button__label{opacity:.7}.skin-elevated,.skin-outline,.skin-flat,.skin-neumorphism{--p-list-item-surface: var( --mdc-elevated-card-container-color, var(--p-list-surface) );--p-list-item-border: var(--p-list-border)}.skin-elevated .item-card,.skin-outline .item-card,.skin-flat .item-card,.skin-neumorphism .item-card{background:var(--mdc-elevated-card-container-color, var(--p-list-surface));border-radius:var(--p-list-radius);box-shadow:var(--p-list-shadow);border:var(--p-list-border)}.skin-elevated .item-tile,.skin-outline .item-tile,.skin-flat .item-tile,.skin-neumorphism .item-tile{background:var(--mdc-elevated-card-container-color, var(--p-list-surface));box-shadow:var(--p-list-shadow);border:var(--p-list-border)}.skin-elevated .mat-mdc-list-item .list-item-content,.skin-outline .mat-mdc-list-item .list-item-content,.skin-flat .mat-mdc-list-item .list-item-content,.skin-neumorphism .mat-mdc-list-item .list-item-content{background:var(--mdc-elevated-card-container-color, var(--p-list-surface));border-radius:calc(var(--p-list-radius) * .75);box-shadow:var(--p-list-shadow);border:var(--p-list-item-border);color:var(--p-list-foreground)}.skin-outline{--p-list-shadow: none;--p-list-border: 1px solid var(--md-sys-color-outline)}.skin-flat{--p-list-shadow: none;--p-list-border: 1px solid var(--md-sys-color-outline-variant)}.skin-neumorphism{--p-list-shadow: var(--md-sys-elevation-level2);--p-list-border: 1px solid var(--md-sys-color-outline-variant);--p-list-radius: 1.25rem}.skin-pill-soft .item-card,.skin-pill-soft .item-tile{background:var(--mdc-elevated-card-container-color, var(--p-list-surface));border-radius:calc(var(--p-list-radius) * 1.3);box-shadow:var(--md-sys-elevation-level1);border:var(--p-list-border)}.skin-pill-soft .mat-mdc-list-item .list-item-content{background:var(--mdc-elevated-card-container-color, var(--p-list-surface));border-radius:calc(var(--p-list-radius) * 1.3);box-shadow:var(--md-sys-elevation-level1);border:var(--p-list-border);color:var(--p-list-foreground)}.skin-gradient-tile{--p-list-foreground: var(--p-list-grad-foreground);--p-list-foreground-muted: var(--p-list-grad-foreground-muted);--p-list-item-hover-surface: linear-gradient( var(--p-list-grad-angle), var(--p-list-grad-from), var(--p-list-grad-to) );--p-list-item-active-surface: linear-gradient( var(--p-list-grad-angle), var(--p-list-grad-from), var(--p-list-grad-to) );--p-list-item-selected-surface: linear-gradient( var(--p-list-grad-angle), var(--p-list-grad-from), var(--p-list-grad-to) )}.skin-gradient-tile .item-card,.skin-gradient-tile .item-tile,.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:var(--p-list-foreground)}.skin-glass .item-card,.skin-glass .item-tile{background:var(--md-sys-color-surface-container-low);border-radius:var(--p-list-radius);border:1px solid var(--md-sys-color-outline-variant);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:var(--md-sys-color-surface-container-low);border-radius:var(--p-list-radius);border:1px solid var(--md-sys-color-outline-variant);backdrop-filter:blur(var(--p-list-blur));-webkit-backdrop-filter:blur(var(--p-list-blur));color:var(--p-list-foreground)}.density-compact .mat-mdc-list-item,.density-compact .item-card{--p-list-item-padding-y: 8px;--p-list-item-padding-x: 12px;--p-list-item-gap: 10px}.density-comfortable .mat-mdc-list-item,.density-comfortable .item-card{--p-list-item-padding-y: 10px;--p-list-item-padding-x: 14px;--p-list-item-gap: 12px}.praxis-list-root.lines-3 .mat-mdc-list-item,.praxis-list-root.lines-3 .mat-mdc-list-option{min-height:76px}.density-compact{--p-list-tile-gap: 12px;--p-list-tile-padding: 12px;--p-list-tile-minW: 200px}.density-comfortable{--p-list-tile-gap: 16px;--p-list-tile-padding: 16px}.item-spacing-none{--p-list-item-stack-gap: 0px}.item-spacing-tight{--p-list-item-stack-gap: 6px;--p-list-tile-gap: 12px}.item-spacing-default{--p-list-item-stack-gap: 10px;--p-list-tile-gap: 16px}.item-spacing-relaxed{--p-list-item-stack-gap: 14px;--p-list-tile-gap: 20px}.list-item-content{display:grid;grid-template-columns:var(--p-list-leading-width) minmax(0,1fr) minmax(var(--p-list-trailing-min-width),max-content);align-items:center;gap:var(--p-list-item-gap);padding:var(--p-list-item-padding-y) var(--p-list-item-padding-x);width:100%;min-width:0;border-radius:calc(var(--p-list-radius) * .75);overflow:visible}.list-item-content--row-layout{--p-list-row-template-columns: var(--p-list-leading-width) minmax(0, 1fr) minmax(var(--p-list-trailing-min-width), max-content);--p-list-row-gap: var(--p-list-item-gap);--p-list-row-align-items: center;grid-template-columns:var(--p-list-row-template-columns);gap:var(--p-list-row-gap);align-items:var(--p-list-row-align-items)}.list-item-content--row-layout[role=button]{cursor:pointer}.list-item-content--row-layout[role=button]:focus-visible{outline:2px solid var(--md-sys-color-primary);outline-offset:2px}.list-row-slot{min-width:0;display:flex;align-items:center;gap:8px}.list-row-slot--leading{justify-content:center}.list-row-slot--primary,.list-row-slot--secondary{min-width:0}.list-row-slot--meta{color:var(--p-list-foreground);font-variant-numeric:tabular-nums}.list-row-slot--trailing{flex-wrap:wrap;justify-content:flex-end}.list-row-slot .primary,.list-row-slot .secondary,.list-row-slot .meta,.list-row-slot .trailing{min-width:0}.list-item-main-action{grid-column:1/3;display:grid;grid-template-columns:var(--p-list-leading-width) minmax(0,1fr);align-items:center;gap:var(--p-list-item-gap);min-width:0;padding:0;border:0;background:transparent;color:inherit;text-align:start;font:inherit;cursor:pointer}.list-item-main-action:focus-visible{outline:2px solid var(--md-sys-color-primary);outline-offset:2px;border-radius:12px}.list-item-leading{display:flex;align-items:center;justify-content:center;min-height:100%}.leading-placeholder{width:24px;height:24px;display:inline-block}.list-item-text{min-width:0;display:grid;align-content:center;gap:4px}.list-item-trailing{min-width:0;display:flex;flex-direction:column;align-items:flex-end;justify-content:center;gap:6px;text-align:end;padding-right:var(--p-list-trailing-padding-right)}.list-item-content--row-layout .list-item-actions{justify-content:flex-end}.list-item-actions{display:flex;align-items:center;justify-content:flex-end;gap:4px;flex-wrap:wrap}.expand-toggle{color:var(--p-list-foreground-muted)}.mat-mdc-list-item .list-item-content{background:var(--p-list-item-surface);border:var(--p-list-item-border);transition:background .15s ease,box-shadow .15s ease,transform .15s ease}.mat-mdc-list-item,.mat-mdc-list-option{height:auto;align-items:stretch;overflow:visible}.mat-mdc-list-item.mdc-list-item--with-one-line,.mat-mdc-list-item.mdc-list-item--with-two-lines,.mat-mdc-list-item.mdc-list-item--with-three-lines,.mat-mdc-list-item-single-line,.mat-mdc-list-item-two-line,.mat-mdc-list-item-three-line,.mat-mdc-list-option.mdc-list-item--with-one-line,.mat-mdc-list-option.mdc-list-item--with-two-lines,.mat-mdc-list-option.mdc-list-item--with-three-lines{height:auto!important}.mdc-list-item{overflow:visible}.density-compact .mat-mdc-list-item,.density-compact .mat-mdc-list-option{min-height:44px}.density-comfortable .mat-mdc-list-item,.density-comfortable .mat-mdc-list-option{min-height:52px}.praxis-list-root:not(.density-compact):not(.density-comfortable) .mat-mdc-list-item,.praxis-list-root:not(.density-compact):not(.density-comfortable) .mat-mdc-list-option{min-height:56px}.mat-mdc-list-item .mdc-list-item__content,.mat-mdc-list-option .mdc-list-item__content,.mat-mdc-list-item .mdc-list-item__primary-text,.mat-mdc-list-option .mdc-list-item__primary-text{display:block!important;width:100%!important;height:auto!important;padding:0!important;margin:0!important;overflow:visible!important;box-sizing:border-box}.mat-mdc-list-item,.mat-mdc-list-option{padding:0!important;box-sizing:border-box}.praxis-list-root mat-list>mat-list-item:not(:last-child),.praxis-list-root mat-selection-list>mat-list-option:not(:last-child){margin-bottom:var(--p-list-item-stack-gap)}.mat-mdc-list-item:hover .list-item-content,.mat-mdc-list-option:hover .list-item-content{background:var(--p-list-item-hover-surface)}.mat-mdc-list-item:active .list-item-content,.mat-mdc-list-option:active .list-item-content{background:var(--p-list-item-active-surface)}.mat-mdc-list-option.mdc-list-item--selected .list-item-content{background:var(--p-list-item-selected-surface);border-color:var(--md-sys-color-outline-variant)}.mat-mdc-list-option.cdk-keyboard-focused .list-item-content,.mat-mdc-list-option.cdk-focused .list-item-content{outline:2px solid var(--md-sys-color-primary);outline-offset:2px}.mat-mdc-list-item:focus-visible .list-item-content{outline:2px solid var(--md-sys-color-primary);outline-offset:2px}.executive-inline-skin{--p-list-leading-width: 56px;--p-list-trailing-min-width: 232px;--p-list-item-padding-x: 14px;--p-list-item-padding-y: 8px;--p-list-item-gap: 10px;--p-list-surface: #f8fafb;--p-list-surface-low: #ffffff;--p-list-item-surface: #ffffff;--p-list-item-hover-surface: #f7fafc;--p-list-item-active-surface: #eef4f8;--p-list-item-selected-surface: #eef4f8;--p-list-foreground: #17324d;--p-list-foreground-muted: #72849a}.executive-inline-skin .list-item-content--row-layout.exec-row-layout{min-height:72px;padding:12px 20px;background:linear-gradient(180deg,#fff,#fbfcfd)!important;border:1px solid #dce5ec!important;border-radius:18px;box-shadow:0 1px 2px #0f223a08,0 4px 14px #0f223a08!important;color:#17324d!important}.executive-inline-skin .mat-mdc-list-item:hover .list-item-content--row-layout.exec-row-layout{background:linear-gradient(180deg,#fff,#f7fafc)!important}.executive-inline-skin .list-item-content--row-layout.exec-row-layout+.item-expansion{margin-left:10px;margin-right:10px}.executive-inline-skin .list-item-content--row-layout.exec-row-layout .list-row-slot{min-height:34px}.executive-inline-skin .list-row-slot--leading{justify-content:center}.executive-inline-skin .list-row-slot--identity{align-items:center;padding-right:4px}.executive-inline-skin .list-row-slot--balance,.executive-inline-skin .list-row-slot--limit,.executive-inline-skin .list-row-slot--risk,.executive-inline-skin .list-row-slot--alerts{justify-content:center;padding-inline:2px}.executive-inline-skin .list-row-slot--owner{justify-content:flex-start;padding-left:0}.executive-inline-skin .list-row-slot--actions{justify-content:flex-end;padding-left:0}.executive-inline-skin .list-row-slot--expand{justify-content:center}.executive-inline-skin .docs-expansion-leading{width:44px;height:44px;display:inline-flex;align-items:center;justify-content:center;border-radius:15px;background:linear-gradient(180deg,#edf4f9,#e6eef5);color:#1b5f86;font-size:1rem;font-weight:800;letter-spacing:.02em;box-shadow:0 1px 3px #1b5f861f;border:1px solid #dbe7f0}.executive-inline-skin .exec-balance-metric,.executive-inline-skin .exec-limit-metric,.executive-inline-skin .exec-risk-metric{min-width:0}.executive-inline-skin .exec-balance-metric .p-list-metric,.executive-inline-skin .exec-limit-metric .p-list-metric,.executive-inline-skin .exec-risk-metric .p-list-metric{gap:5px}.executive-inline-skin .exec-balance-metric .p-list-metric__label,.executive-inline-skin .exec-limit-metric .p-list-metric__label,.executive-inline-skin .exec-risk-metric .p-list-metric__label{font-size:.62rem;font-weight:700;letter-spacing:.08em;text-transform:uppercase;color:#8090a1}.executive-inline-skin .exec-balance-metric .p-list-metric__value,.executive-inline-skin .exec-limit-metric .p-list-metric__value{font-size:.96rem;font-weight:800;letter-spacing:-.02em;color:#0d1f34;line-height:1.05}.executive-inline-skin .exec-limit-metric .p-list-metric__caption{font-size:.66rem;font-weight:700;color:#8090a1}.executive-inline-skin .exec-limit-metric .p-list-metric__progress{width:68px;justify-self:center;height:3px}.executive-inline-skin .exec-risk-metric{min-width:84px}.executive-inline-skin .exec-risk-metric .p-list-metric{justify-items:center}.executive-inline-skin .exec-risk-metric .p-list-metric__main{gap:6px}.executive-inline-skin .exec-risk-metric .p-list-metric__value{font-size:1.02rem;font-weight:800;letter-spacing:-.024em;line-height:1}.executive-inline-skin .exec-risk-metric .p-list-metric__progress{width:56px;justify-self:center;height:3px}.executive-inline-skin .exec-risk-metric .p-list-metric__caption{font-size:.7rem;font-weight:700;line-height:1.1}.executive-inline-skin .exec-risk-metric .p-list-metric__caption--below-progress{justify-self:center;margin-top:-1px}.executive-inline-skin .exec-risk-metric .p-list-metric__icon mat-icon{width:15px;height:15px;font-size:15px}.executive-inline-skin .list-item-actions{gap:6px;flex-wrap:nowrap}.executive-inline-skin .list-row-slot--actions .list-item-actions{justify-content:flex-end}.executive-inline-skin .list-item-actions button,.executive-inline-skin .expand-toggle{width:30px;height:30px;min-width:30px;border-radius:12px;color:#6d7f93!important}.executive-inline-skin .list-item-actions button mat-icon,.executive-inline-skin .expand-toggle mat-icon{width:18px;height:18px;font-size:18px}.executive-inline-skin .item-expansion{position:relative;margin-top:-10px;padding:22px 26px;background:linear-gradient(180deg,#fcfdfe,#f5f8fb);border-color:#e4eaf0;border-radius:0 0 22px 22px;box-shadow:inset 0 1px #ffffffdb}.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}.inline-image{position:relative;width:20px;height:20px;border-radius:4px;overflow:hidden;display:inline-block;vertical-align:middle}.inline-image img{width:100%;height:100%;object-fit:cover;display:block}.inline-image .inline-badge{position:absolute;left:2px;bottom:2px}.model-media .lead-image{width:136px;height:96px;border-radius:16px}.model-media .list-item-content{gap:16px}.model-media .item-card{--p-list-leading-width: 136px}.model-hotel .lead-image{width:160px;height:110px;border-radius:18px}.model-hotel .item-card{--p-list-leading-width: 160px}.primary,.secondary{display:-webkit-box;-webkit-box-orient:vertical;overflow:hidden;text-overflow:ellipsis}.primary{-webkit-line-clamp:1;font-weight:600;color:var(--p-list-foreground)}.secondary{-webkit-line-clamp:1;color:var(--p-list-foreground-muted)}.lines-3 .tertiary{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.item-tile .primary{-webkit-line-clamp:2;font-size:.95rem;line-height:1.25rem}.item-tile .secondary{-webkit-line-clamp:2;font-size:.8rem;line-height:1.1rem}.tertiary{color:var(--p-list-foreground-muted)}.features{display:flex;flex-wrap:wrap;gap:12px;margin-top:6px;color:inherit}.feature{display:inline-flex;align-items:center;gap:6px}.feature-line{display:block}.feature-progress{display:block;width:88px;height:4px;margin-top:6px;border-radius:999px;background:#dbe5eb;overflow:hidden}.feature-progress__value{display:block;height:100%;border-radius:inherit;background:#2f9b69}.meta{color:var(--p-list-foreground);font-size:var(--p-list-meta-size);font-weight:var(--p-list-meta-weight);font-variant-numeric:tabular-nums;white-space:nowrap}.trailing{color:var(--p-list-foreground-muted);margin-left:0;white-space:nowrap}.section-header{font-size:.85rem;color:var(--p-list-foreground-muted);padding:8px 12px}.praxis-list-root mat-list,.praxis-list-root mat-selection-list{display:block;padding-bottom:12px}.praxis-list-root .mat-divider{margin-left:var(--p-list-item-padding-x);margin-right:var(--p-list-item-padding-x)}.item-expansion{margin:0 var(--p-list-item-padding-x) var(--p-list-item-stack-gap);padding:14px 16px;background:color-mix(in srgb,var(--p-list-surface) 88%,white 12%);border:1px solid var(--md-sys-color-outline-variant);border-radius:calc(var(--p-list-radius) * .75)}.item-expansion-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(220px,1fr));gap:16px}.expansion-section{min-width:0;display:grid;gap:10px;align-content:start}.expansion-section-title{font-size:.78rem;font-weight:700;letter-spacing:.04em;text-transform:uppercase;color:var(--p-list-foreground-muted)}.expansion-info-list,.expansion-timeline,.expansion-key-value{display:grid;gap:10px}.expansion-info-item,.expansion-timeline-item{display:grid;gap:4px;padding:10px 12px;border-radius:14px;background:var(--p-list-item-surface);border:1px solid color-mix(in srgb,var(--md-sys-color-outline-variant) 72%,transparent 28%)}.expansion-info-title,.expansion-timeline-title{font-size:.92rem;font-weight:600;color:var(--p-list-foreground)}.expansion-info-value,.expansion-timeline-meta,.expansion-timeline-description,.expansion-empty{font-size:.82rem;line-height:1.45;color:var(--p-list-foreground-muted)}.expansion-chip-list{display:flex;flex-wrap:wrap;gap:8px}.expansion-chip{background:var(--p-list-item-surface);border:1px solid var(--md-sys-color-outline-variant)}.expansion-key-value{margin:0}.expansion-key-value-row{display:grid;gap:4px;padding:10px 12px;border-radius:14px;background:var(--p-list-item-surface);border:1px solid color-mix(in srgb,var(--md-sys-color-outline-variant) 72%,transparent 28%)}.expansion-key-value-row dt,.expansion-key-value-row dd{margin:0}.expansion-key-value-row dt{font-size:.78rem;font-weight:600;color:var(--p-list-foreground-muted)}.expansion-key-value-row dd{font-size:.9rem;color:var(--p-list-foreground)}.cards-grid,.tiles-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(var(--p-list-tile-minW),1fr));gap:var(--p-list-tile-gap)}.item-tile{position:relative;display:flex;flex-direction:column;gap:10px;padding:var(--p-list-tile-padding);border-radius:var(--p-list-tile-radius);background:var(--p-list-surface);border:var(--p-list-border);color:var(--p-list-foreground);cursor:pointer;min-height:160px;transition:box-shadow .16s ease-out,border-color .16s ease-out,transform .12s ease-out,background .16s ease-out}.item-tile:hover{box-shadow:var(--md-sys-elevation-level2);border-color:var(--md-sys-color-outline-variant);background:var(--p-list-item-hover-surface)}.item-tile:active{transform:scale(var(--p-list-tile-press-scale));background:var(--p-list-item-active-surface)}.item-tile:focus-visible{outline:2px solid var(--md-sys-color-primary);outline-offset:2px}.tile-media{width:100%;aspect-ratio:var(--p-list-tile-media-ratio);border-radius:var(--p-list-tile-media-radius);background:var(--p-list-item-surface);border:1px solid var(--md-sys-color-outline-variant);display:grid;place-items:center;overflow:hidden}.tile-media img{width:100%;height:100%;object-fit:cover;display:block}.tile-media mat-icon{font-size:28px;height:28px;width:28px;color:var(--p-list-foreground-muted)}.tile-body{display:grid;gap:6px;min-width:0}.tile-meta{display:inline-flex;align-items:center;gap:6px;font-size:.75rem;color:var(--p-list-foreground-muted);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.tile-trailing{font-size:.75rem;color:var(--p-list-foreground-muted);white-space:nowrap}.tiles-features{display:flex;flex-wrap:wrap;gap:8px;color:inherit}.tile-status{position:absolute;top:10px;right:10px}.tile-actions{position:absolute;top:8px;left:8px;display:flex;gap:4px;opacity:0;pointer-events:none;transform:translateY(-2px);transition:opacity .16s ease-out,transform .16s ease-out}.item-tile:hover .tile-actions,.item-tile:focus-visible .tile-actions,.item-tile:focus-within .tile-actions{opacity:1;pointer-events:auto;transform:translateY(0)}@media(hover:none){.tile-actions{opacity:1;pointer-events:auto;transform:none}}@media(max-width:600px){.tiles-grid{grid-template-columns:repeat(auto-fit,minmax(200px,1fr))}}@media(prefers-reduced-motion:reduce){.item-tile,.tile-actions{transition:none}.item-tile:active{transform:none}.item-card{transition:none}.item-card:active{transform:none}}.item-card{padding:var(--p-list-tile-padding);display:flex;flex-direction:column;min-height:160px;position:relative;cursor:pointer;background:var(--p-list-surface);border:var(--p-list-border);border-radius:var(--p-list-tile-radius);box-shadow:var(--p-list-shadow);transition:box-shadow .16s ease-out,border-color .16s ease-out,transform .12s ease-out,background .16s ease-out;--p-list-leading-width: 96px;--p-list-trailing-min-width: 0px}.item-card .list-item-trailing{min-width:var(--p-list-trailing-min-width)}.item-card:hover{box-shadow:var(--md-sys-elevation-level3);border-color:var(--md-sys-color-outline-variant);background:var(--p-list-item-hover-surface)}.item-card:active{transform:scale(var(--p-list-tile-press-scale));background:var(--p-list-item-active-surface)}.item-card:focus-visible{outline:2px solid var(--md-sys-color-primary);outline-offset:2px}.card-actions{display:flex;align-items:center;justify-content:flex-end;gap:4px;padding:6px 8px 4px;border-top:1px solid var(--md-sys-color-outline-variant);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:var(--md-sys-color-primary-container);color:var(--md-sys-color-on-primary-container)}.mat-mdc-chip{--mdc-chip-container-height: var(--p-list-chip-height);font-size:var(--p-list-chip-font-size)}.meta .mat-icon{font-size:18px;height:18px;width:18px}.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:linear-gradient(to right,var(--md-sys-color-surface-container-low) 8%,var(--md-sys-color-surface-container) 18%,var(--md-sys-color-surface-container-low) 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;flex-wrap:wrap;gap:8px;margin-top:14px;padding:14px 4px 8px;border-top:1px solid var(--md-sys-color-outline-variant);position:relative;z-index:1;background:var(--p-list-surface-low);border-radius:calc(var(--p-list-radius) * .75)}.paginator-controls{display:flex;align-items:center;gap:8px;flex-wrap:wrap}.paginator-meta{display:flex;align-items:center;gap:8px;margin-left:auto}.paginator-page-size{width:120px}.paginator-sort{width:180px}.paginator-search{min-width:220px}.muted{color:var(--p-list-foreground-muted)}@media(max-width:720px){.list-item-content{grid-template-columns:var(--p-list-leading-width) minmax(0,1fr)}.list-item-trailing{grid-column:1/-1;padding-right:0;align-items:flex-start;text-align:start}.item-expansion{margin-left:0;margin-right:0}.paginator{align-items:stretch}.paginator-controls{width:100%}.paginator-meta{width:100%;margin-left:0;justify-content:flex-start}.paginator-page-size,.paginator-sort,.paginator-search{width:100%;min-width:0}}\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: i5.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: i6.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: i6.MatMiniFabButton, selector: "button[mat-mini-fab], a[mat-mini-fab], button[matMiniFab], a[matMiniFab]", exportAs: ["matButton", "matAnchor"] }, { kind: "component", type: i6.MatIconButton, selector: "button[mat-icon-button], a[mat-icon-button], button[matIconButton], a[matIconButton]", exportAs: ["matButton", "matAnchor"] }, { kind: "ngmodule", type: MatProgressSpinnerModule }, { kind: "component", type: i7.MatProgressSpinner, selector: "mat-progress-spinner, mat-spinner", inputs: ["color", "mode", "value", "diameter", "strokeWidth"], exportAs: ["matProgressSpinner"] }, { kind: "ngmodule", type: MatFormFieldModule }, { kind: "component", type: i2$1.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i2$1.MatLabel, selector: "mat-label" }, { kind: "ngmodule", type: MatSelectModule }, { kind: "component", type: i4$1.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: i4$1.MatOption, selector: "mat-option", inputs: ["value", "id", "disabled"], outputs: ["onSelectionChange"], exportAs: ["matOption"] }, { kind: "ngmodule", type: MatInputModule }, { kind: "directive", type: i3$1.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly", "disabledInteractive"], exportAs: ["matInput"] }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i12.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "component", type: PraxisAiAssistantComponent, selector: "praxis-ai-assistant", inputs: ["adapter", "riskPolicy", "allowManualPatchEdit"] }, { kind: "component", type: ExecutiveBadgeComponent, selector: "praxis-executive-badge", inputs: ["ariaLabel", "variant"] }, { kind: "component", type: ExecutiveAlertsComponent, selector: "praxis-executive-alerts", inputs: ["alerts"] }, { kind: "component", type: ExecutiveOwnerComponent, selector: "praxis-executive-owner", inputs: ["name"] }, { kind: "component", type: PraxisListMetricComponent, selector: "praxis-list-metric", inputs: ["metric"] }, { kind: "component", type: PraxisListComposeComponent, selector: "praxis-list-compose", inputs: ["compose"] }, { kind: "component", type: PraxisListRuntimeComponentComponent, selector: "praxis-list-runtime-component", inputs: ["component"] }, { kind: "pipe", type: i1.AsyncPipe, name: "async" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
9933
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.17", type: PraxisList, isStandalone: true, selector: "praxis-list", inputs: { config: "config", listId: "listId", componentInstanceId: "componentInstanceId", form: "form", enableCustomization: ["enableCustomization", "enableCustomization", booleanAttribute] }, outputs: { itemClick: "itemClick", actionClick: "actionClick", selectionChange: "selectionChange" }, providers: [GenericCrudService, ListDataService, providePraxisListI18n()], usesOnChanges: true, ngImport: i0, template: "<div\n class=\"praxis-list-root\"\n [ngClass]=\"skinClasses\"\n [attr.data-skin-scope]=\"skinScopeId\"\n [attr.aria-label]=\"config.a11y?.ariaLabel || null\"\n [attr.aria-labelledby]=\"config.a11y?.ariaLabelledBy || null\"\n>\n @if (inlineCss) {\n <style [attr.nonce]=\"cspNonce || null\" [textContent]=\"inlineCss\"></style>\n }\n\n @if (enableCustomization) {\n <div class=\"list-assistant\">\n <button\n mat-mini-fab\n type=\"button\"\n color=\"primary\"\n (click)=\"openConfigEditor()\"\n [matTooltip]=\"configEditorLabel()\"\n [attr.aria-label]=\"configEditorLabel()\"\n data-testid=\"praxis-list-open-config-editor\"\n >\n <mat-icon [praxisIcon]=\"'edit'\"></mat-icon>\n </button>\n <praxis-ai-assistant [adapter]=\"aiAdapter\"></praxis-ai-assistant>\n </div>\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=\"list-item-leading\">\n <div class=\"skeleton skeleton-avatar\"></div>\n </div>\n <div class=\"list-item-text\">\n <div class=\"skeleton skeleton-line w-60\"></div>\n @if (layoutLines > 1) {\n <div class=\"skeleton skeleton-line w-40\"></div>\n }\n </div>\n <div class=\"list-item-trailing\">\n <div class=\"skeleton skeleton-chip\"></div>\n </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=\"list-item-leading\">\n <div class=\"skeleton skeleton-avatar\"></div>\n </div>\n <div class=\"list-item-text\">\n <div class=\"skeleton skeleton-line w-60\"></div>\n @if (layoutLines > 1) {\n <div class=\"skeleton skeleton-line w-40\"></div>\n }\n </div>\n <div class=\"list-item-trailing\">\n <div class=\"skeleton skeleton-chip\"></div>\n </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 @if (emptyStateTemplate(); as empty) {\n @if (\n simpleRichContentNodes(empty, {\n imageAlt: config.templating?.emptyState?.imageAlt || \"\",\n });\n as richNodes\n ) {\n <praxis-rich-content [nodes]=\"richNodes\"></praxis-rich-content>\n } @else {\n @switch (empty.type) {\n @case (\"icon\") {\n <mat-icon\n [praxisIcon]=\"empty.value\"\n [ngClass]=\"empty.class\"\n [color]=\"isThemeColor(empty.color) ? empty.color : undefined\"\n [style.cssText]=\"\n (empty.style ? empty.style + ';' : '') +\n iconStyle(empty.color)\n \"\n ></mat-icon>\n }\n @case (\"image\") {\n <span\n class=\"inline-image\"\n [ngClass]=\"empty.class\"\n [style.cssText]=\"empty.style\"\n >\n <img\n [src]=\"empty.value\"\n [alt]=\"config.templating?.emptyState?.imageAlt || ''\"\n />\n @if (empty.badge?.value) {\n <mat-chip\n class=\"inline-badge\"\n [color]=\"\n isThemeColor(empty.badge?.color)\n ? empty.badge?.color\n : undefined\n \"\n [ngClass]=\"\n (empty.badge?.variant || 'filled') === 'outlined'\n ? 'chip-outlined'\n : ''\n \"\n [style.cssText]=\"\n chipStyle(empty.badge?.color, empty.badge?.variant)\n \"\n >{{ empty.badge?.value }}</mat-chip\n >\n }\n </span>\n }\n @case (\"chip\") {\n <mat-chip\n [color]=\"isThemeColor(empty.color) ? empty.color : undefined\"\n [ngClass]=\"[\n empty.class || '',\n (empty.variant || 'filled') === 'outlined'\n ? 'chip-outlined'\n : '',\n ]\"\n [style.cssText]=\"\n chipStyle(empty.color, empty.variant) +\n (empty.style ? ';' + empty.style : '')\n \"\n >{{ empty.value }}</mat-chip\n >\n }\n @case (\"rating\") {\n <span [ngClass]=\"empty.class\" [style.cssText]=\"empty.style\">\n @for (\n _ of ratingRange(empty);\n track $index;\n let idx = $index\n ) {\n <mat-icon\n [praxisIcon]=\"starIcon(idx, empty.value)\"\n [color]=\"ratingThemeColor(empty)\"\n [style.cssText]=\"ratingIconStyle(empty)\"\n ></mat-icon>\n }\n </span>\n }\n @case (\"html\") {\n <span\n [ngClass]=\"empty.class\"\n [style.cssText]=\"empty.style\"\n [innerHTML]=\"empty.value\"\n ></span>\n }\n @case (\"metric\") {\n <praxis-list-metric [metric]=\"empty\"></praxis-list-metric>\n }\n @case (\"compose\") {\n <praxis-list-compose [compose]=\"empty\"></praxis-list-compose>\n }\n @case (\"component\") {\n <praxis-list-runtime-component\n [component]=\"empty\"\n ></praxis-list-runtime-component>\n }\n @default {\n <span [ngClass]=\"empty.class\" [style.cssText]=\"empty.style\">{{\n empty.value\n }}</span>\n }\n }\n }\n }\n </div>\n }\n }\n\n <ng-template\n #rowLayoutNode\n let-node\n let-slot=\"slot\"\n let-imageAlt=\"imageAlt\"\n >\n @if (simpleRichContentNodes(node, { slot: slot, imageAlt: imageAlt }); as richNodes) {\n <praxis-rich-content [nodes]=\"richNodes\"></praxis-rich-content>\n } @else {\n @switch (node?.type) {\n @case (\"icon\") {\n <mat-icon\n [praxisIcon]=\"node?.value\"\n [ngClass]=\"node?.class\"\n [color]=\"isThemeColor(node?.color) ? node?.color : undefined\"\n [style.cssText]=\"\n ((node?.style || '') ? node.style + ';' : '') +\n iconStyle(node?.color)\n \"\n ></mat-icon>\n }\n @case (\"image\") {\n <span\n class=\"inline-image\"\n [ngClass]=\"node?.class\"\n [style.cssText]=\"node?.style\"\n >\n <img [src]=\"node?.value\" [alt]=\"node?.imageAlt || imageAlt || ''\" />\n @if (node?.badge?.value) {\n <mat-chip\n class=\"inline-badge\"\n [color]=\"\n isThemeColor(node?.badge?.color)\n ? node?.badge?.color\n : undefined\n \"\n [ngClass]=\"\n (node?.badge?.variant || 'filled') === 'outlined'\n ? 'chip-outlined'\n : ''\n \"\n [style.cssText]=\"\n chipStyle(node?.badge?.color, node?.badge?.variant)\n \"\n >\n {{ node?.badge?.value }}\n </mat-chip>\n }\n </span>\n }\n @case (\"chip\") {\n <mat-chip\n [color]=\"isThemeColor(node?.color) ? node?.color : undefined\"\n [ngClass]=\"[\n node?.class || '',\n (node?.variant || 'filled') === 'outlined' ? 'chip-outlined' : '',\n ]\"\n [style.cssText]=\"\n chipStyle(node?.color, node?.variant) +\n (node?.style ? ';' + node.style : '')\n \"\n >\n {{ node?.value }}\n </mat-chip>\n }\n @case (\"rating\") {\n <span [ngClass]=\"node?.class\" [style.cssText]=\"node?.style\">\n @for (_ of ratingRange(node); track $index; let idx = $index) {\n <mat-icon\n [praxisIcon]=\"starIcon(idx, node?.value)\"\n [color]=\"ratingThemeColor(node)\"\n [style.cssText]=\"ratingIconStyle(node)\"\n ></mat-icon>\n }\n </span>\n }\n @case (\"html\") {\n <span\n [ngClass]=\"node?.class\"\n [style.cssText]=\"node?.style\"\n [innerHTML]=\"node?.value\"\n ></span>\n }\n @case (\"metric\") {\n <praxis-list-metric [metric]=\"node\"></praxis-list-metric>\n }\n @case (\"compose\") {\n <praxis-list-compose [compose]=\"node\"></praxis-list-compose>\n }\n @case (\"component\") {\n <praxis-list-runtime-component\n [component]=\"node\"\n ></praxis-list-runtime-component>\n }\n @default {\n <span [ngClass]=\"node?.class\" [style.cssText]=\"node?.style\">\n @if (slot === \"meta\" && config.templating?.metaPrefixIcon; as mpi) {\n <mat-icon [praxisIcon]=\"mpi\"></mat-icon>\n }\n {{ node?.value }}\n </span>\n }\n }\n }\n </ng-template>\n\n <ng-template\n #listRowLayout\n let-item\n let-index=\"index\"\n let-sectionKey=\"sectionKey\"\n let-clickable=\"clickable\"\n >\n <div\n class=\"list-item-content\"\n [ngClass]=\"rowLayoutItemClass(item)\"\n [attr.style]=\"rowLayoutItemStyle(item)\"\n [attr.role]=\"clickable ? 'button' : null\"\n [attr.tabindex]=\"clickable ? '0' : null\"\n [attr.aria-label]=\"clickable ? itemAriaLabel(item) : null\"\n [attr.aria-expanded]=\"\n clickable && expansionOwnedByRow() ? isExpanded(item, index) : null\n \"\n [attr.aria-controls]=\"\n clickable && expansionOwnedByRow()\n ? expandRegionId(item, index)\n : null\n \"\n (click)=\"clickable ? onRowActivate(item, index, sectionKey) : null\"\n (keydown.enter)=\"clickable ? onRowActivate(item, index, sectionKey) : null\"\n (keydown.space)=\"\n onRowSpaceActivate($event, clickable, item, index, sectionKey)\n \"\n >\n @for (column of rowLayoutColumns(); track rowLayoutTrackColumn($index, column)) {\n <div\n [attr.data-row-slot]=\"column.slot\"\n [ngClass]=\"rowLayoutColumnClass(column)\"\n [attr.style]=\"rowLayoutColumnStyle(column)\"\n >\n @if (column.slot === \"leading\") {\n @if (rowLayoutSlot(item, column.slot); as lead) {\n <ng-container\n *ngTemplateOutlet=\"\n rowLayoutNode;\n context: {\n $implicit: lead,\n slot: column.slot,\n imageAlt: rowLayoutImageAlt(column.slot),\n }\n \"\n ></ng-container>\n } @else {\n <span class=\"leading-placeholder\"></span>\n }\n } @else if (column.slot === \"trailing\") {\n @if (rowLayoutSlot(item, column.slot); as trailingNode) {\n <ng-container\n *ngTemplateOutlet=\"\n rowLayoutNode;\n context: {\n $implicit: trailingNode,\n slot: column.slot,\n imageAlt: rowLayoutImageAlt(column.slot),\n }\n \"\n ></ng-container>\n }\n @if (showExpandIcon(\"trailing\")) {\n <button\n mat-icon-button\n type=\"button\"\n class=\"expand-toggle\"\n [attr.aria-label]=\"expandToggleAriaLabel(item, index)\"\n [attr.aria-expanded]=\"\n expansionOwnedByIcon() ? isExpanded(item, index) : null\n \"\n [attr.aria-controls]=\"\n expansionOwnedByIcon()\n ? expandRegionId(item, index)\n : null\n \"\n (click)=\"onExpandToggle($event, item, index)\"\n >\n <mat-icon\n [praxisIcon]=\"\n isExpanded(item, index) ? 'expand_less' : 'expand_more'\n \"\n ></mat-icon>\n </button>\n }\n @if ((visibleActions(item, \"trailing\") || []).length) {\n <div\n class=\"list-item-actions\"\n (click)=\"$event.stopPropagation()\"\n (keydown.enter)=\"onActionKeydown($event)\"\n (keydown.space)=\"onActionKeydown($event)\"\n >\n @for (\n action of visibleActions(item, \"trailing\");\n let aidx = $index;\n track action?.id ?? $index\n ) {\n @if ((action.kind || \"icon\") === \"icon\") {\n <button\n mat-icon-button\n [color]=\"\n isThemeColor(action.color) ? action.color : undefined\n \"\n (click)=\"onActionClick($event, action.id, item, index)\"\n [attr.aria-label]=\"action.label || action.id\"\n [disabled]=\"isActionLoading(action.id, item, index)\"\n [ngClass]=\"{\n 'action-loading': isActionLoading(\n action.id,\n item,\n index\n ),\n }\"\n >\n @if (isActionLoading(action.id, item, index)) {\n <mat-progress-spinner\n class=\"action-spinner\"\n mode=\"indeterminate\"\n diameter=\"16\"\n strokeWidth=\"3\"\n ></mat-progress-spinner>\n } @else {\n <mat-icon\n [praxisIcon]=\"action.icon\"\n [style.cssText]=\"iconStyle(action.color)\"\n ></mat-icon>\n }\n </button>\n } @else {\n @if (action.buttonVariant === \"stroked\") {\n <button\n mat-stroked-button\n [color]=\"\n isThemeColor(action.color) ? action.color : undefined\n \"\n [style.cssText]=\"buttonStyle(action.color, 'stroked')\"\n (click)=\"onActionClick($event, action.id, item, index)\"\n [attr.aria-label]=\"action.label || action.id\"\n [disabled]=\"isActionLoading(action.id, item, index)\"\n [ngClass]=\"{\n 'action-loading': isActionLoading(\n action.id,\n item,\n index\n ),\n }\"\n >\n @if (isActionLoading(action.id, item, index)) {\n <mat-progress-spinner\n class=\"action-spinner\"\n mode=\"indeterminate\"\n diameter=\"16\"\n strokeWidth=\"3\"\n ></mat-progress-spinner>\n } @else {\n {{ action.label || action.id }}\n }\n </button>\n }\n @if (action.buttonVariant === \"raised\") {\n <button\n mat-raised-button\n [color]=\"\n isThemeColor(action.color) ? action.color : undefined\n \"\n [style.cssText]=\"buttonStyle(action.color, 'raised')\"\n (click)=\"onActionClick($event, action.id, item, index)\"\n [attr.aria-label]=\"action.label || action.id\"\n [disabled]=\"isActionLoading(action.id, item, index)\"\n [ngClass]=\"{\n 'action-loading': isActionLoading(\n action.id,\n item,\n index\n ),\n }\"\n >\n @if (isActionLoading(action.id, item, index)) {\n <mat-progress-spinner\n class=\"action-spinner\"\n mode=\"indeterminate\"\n diameter=\"16\"\n strokeWidth=\"3\"\n ></mat-progress-spinner>\n } @else {\n {{ action.label || action.id }}\n }\n </button>\n }\n @if (!action.buttonVariant || action.buttonVariant === \"flat\") {\n <button\n mat-flat-button\n [color]=\"\n isThemeColor(action.color) ? action.color : undefined\n \"\n [style.cssText]=\"buttonStyle(action.color, 'flat')\"\n (click)=\"onActionClick($event, action.id, item, index)\"\n [attr.aria-label]=\"action.label || action.id\"\n [disabled]=\"isActionLoading(action.id, item, index)\"\n [ngClass]=\"{\n 'action-loading': isActionLoading(\n action.id,\n item,\n index\n ),\n }\"\n >\n @if (isActionLoading(action.id, item, index)) {\n <mat-progress-spinner\n class=\"action-spinner\"\n mode=\"indeterminate\"\n diameter=\"16\"\n strokeWidth=\"3\"\n ></mat-progress-spinner>\n } @else {\n {{ action.label || action.id }}\n }\n </button>\n }\n }\n }\n </div>\n }\n } @else if (column.slot === \"actions\") {\n @if ((visibleActions(item, \"actions\") || []).length) {\n <div\n class=\"list-item-actions\"\n (click)=\"$event.stopPropagation()\"\n (keydown.enter)=\"onActionKeydown($event)\"\n (keydown.space)=\"onActionKeydown($event)\"\n >\n @for (\n action of visibleActions(item, \"actions\");\n let aidx = $index;\n track action?.id ?? $index\n ) {\n @if ((action.kind || \"icon\") === \"icon\") {\n <button\n mat-icon-button\n [color]=\"\n isThemeColor(action.color) ? action.color : undefined\n \"\n (click)=\"onActionClick($event, action.id, item, index)\"\n [attr.aria-label]=\"action.label || action.id\"\n [disabled]=\"isActionLoading(action.id, item, index)\"\n [ngClass]=\"{\n 'action-loading': isActionLoading(\n action.id,\n item,\n index\n ),\n }\"\n >\n @if (isActionLoading(action.id, item, index)) {\n <mat-progress-spinner\n class=\"action-spinner\"\n mode=\"indeterminate\"\n diameter=\"16\"\n strokeWidth=\"3\"\n ></mat-progress-spinner>\n } @else {\n <mat-icon\n [praxisIcon]=\"action.icon\"\n [style.cssText]=\"iconStyle(action.color)\"\n ></mat-icon>\n }\n </button>\n } @else {\n @if (action.buttonVariant === \"stroked\") {\n <button\n mat-stroked-button\n [color]=\"\n isThemeColor(action.color) ? action.color : undefined\n \"\n [style.cssText]=\"buttonStyle(action.color, 'stroked')\"\n (click)=\"onActionClick($event, action.id, item, index)\"\n [attr.aria-label]=\"action.label || action.id\"\n [disabled]=\"isActionLoading(action.id, item, index)\"\n [ngClass]=\"{\n 'action-loading': isActionLoading(\n action.id,\n item,\n index\n ),\n }\"\n >\n @if (isActionLoading(action.id, item, index)) {\n <mat-progress-spinner\n class=\"action-spinner\"\n mode=\"indeterminate\"\n diameter=\"16\"\n strokeWidth=\"3\"\n ></mat-progress-spinner>\n } @else {\n {{ action.label || action.id }}\n }\n </button>\n }\n @if (action.buttonVariant === \"raised\") {\n <button\n mat-raised-button\n [color]=\"\n isThemeColor(action.color) ? action.color : undefined\n \"\n [style.cssText]=\"buttonStyle(action.color, 'raised')\"\n (click)=\"onActionClick($event, action.id, item, index)\"\n [attr.aria-label]=\"action.label || action.id\"\n [disabled]=\"isActionLoading(action.id, item, index)\"\n [ngClass]=\"{\n 'action-loading': isActionLoading(\n action.id,\n item,\n index\n ),\n }\"\n >\n @if (isActionLoading(action.id, item, index)) {\n <mat-progress-spinner\n class=\"action-spinner\"\n mode=\"indeterminate\"\n diameter=\"16\"\n strokeWidth=\"3\"\n ></mat-progress-spinner>\n } @else {\n {{ action.label || action.id }}\n }\n </button>\n }\n @if (!action.buttonVariant || action.buttonVariant === \"flat\") {\n <button\n mat-flat-button\n [color]=\"\n isThemeColor(action.color) ? action.color : undefined\n \"\n [style.cssText]=\"buttonStyle(action.color, 'flat')\"\n (click)=\"onActionClick($event, action.id, item, index)\"\n [attr.aria-label]=\"action.label || action.id\"\n [disabled]=\"isActionLoading(action.id, item, index)\"\n [ngClass]=\"{\n 'action-loading': isActionLoading(\n action.id,\n item,\n index\n ),\n }\"\n >\n @if (isActionLoading(action.id, item, index)) {\n <mat-progress-spinner\n class=\"action-spinner\"\n mode=\"indeterminate\"\n diameter=\"16\"\n strokeWidth=\"3\"\n ></mat-progress-spinner>\n } @else {\n {{ action.label || action.id }}\n }\n </button>\n }\n }\n }\n </div>\n }\n } @else if (column.slot === \"expand\") {\n @if (showExpandIcon(\"expand\")) {\n <button\n mat-icon-button\n type=\"button\"\n class=\"expand-toggle\"\n [attr.aria-label]=\"expandToggleAriaLabel(item, index)\"\n [attr.aria-expanded]=\"\n expansionOwnedByIcon() ? isExpanded(item, index) : null\n \"\n [attr.aria-controls]=\"\n expansionOwnedByIcon()\n ? expandRegionId(item, index)\n : null\n \"\n (click)=\"onExpandToggle($event, item, index)\"\n >\n <mat-icon\n [praxisIcon]=\"\n isExpanded(item, index) ? 'expand_less' : 'expand_more'\n \"\n ></mat-icon>\n </button>\n }\n } @else if (rowLayoutSlot(item, column.slot); as slotNode) {\n <ng-container\n *ngTemplateOutlet=\"\n rowLayoutNode;\n context: {\n $implicit: slotNode,\n slot: column.slot,\n imageAlt: rowLayoutImageAlt(column.slot),\n }\n \"\n ></ng-container>\n }\n </div>\n }\n </div>\n </ng-template>\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 (\n section of sections$ | async;\n track trackBySection($index, section)\n ) {\n @if (section.key) {\n <div class=\"section-header mat-subheader\">\n @if (sectionHeaderTemplate(section.key); as sh) {\n @if (\n simpleRichContentNodes(sh, {\n imageAlt: config.templating?.sectionHeader?.imageAlt || \"\",\n });\n as richNodes\n ) {\n <praxis-rich-content [nodes]=\"richNodes\"></praxis-rich-content>\n } @else {\n @switch (sh.type) {\n @case (\"icon\") {\n <mat-icon\n [praxisIcon]=\"sh.value\"\n [ngClass]=\"sh.class\"\n [color]=\"isThemeColor(sh.color) ? sh.color : undefined\"\n [style.cssText]=\"\n (sh.style ? sh.style + ';' : '') + iconStyle(sh.color)\n \"\n ></mat-icon>\n }\n @case (\"image\") {\n <span\n class=\"inline-image\"\n [ngClass]=\"sh.class\"\n [style.cssText]=\"sh.style\"\n >\n <img\n [src]=\"sh.value\"\n [alt]=\"\n config.templating?.sectionHeader?.imageAlt || ''\n \"\n />\n @if (sh.badge?.value) {\n <mat-chip\n class=\"inline-badge\"\n [color]=\"\n isThemeColor(sh.badge?.color)\n ? sh.badge?.color\n : undefined\n \"\n [ngClass]=\"\n (sh.badge?.variant || 'filled') === 'outlined'\n ? 'chip-outlined'\n : ''\n \"\n [style.cssText]=\"\n chipStyle(sh.badge?.color, sh.badge?.variant)\n \"\n >{{ sh.badge?.value }}</mat-chip\n >\n }\n </span>\n }\n @case (\"chip\") {\n <mat-chip\n [color]=\"isThemeColor(sh.color) ? sh.color : undefined\"\n [ngClass]=\"[\n sh.class || '',\n (sh.variant || 'filled') === 'outlined'\n ? 'chip-outlined'\n : '',\n ]\"\n [style.cssText]=\"\n chipStyle(sh.color, sh.variant) +\n (sh.style ? ';' + sh.style : '')\n \"\n >{{ sh.value }}</mat-chip\n >\n }\n @case (\"rating\") {\n <span [ngClass]=\"sh.class\" [style.cssText]=\"sh.style\">\n @for (\n _ of ratingRange(sh);\n track $index;\n let idx = $index\n ) {\n <mat-icon\n [praxisIcon]=\"starIcon(idx, sh.value)\"\n [color]=\"ratingThemeColor(sh)\"\n [style.cssText]=\"ratingIconStyle(sh)\"\n ></mat-icon>\n }\n </span>\n }\n @case (\"html\") {\n <span\n [ngClass]=\"sh.class\"\n [style.cssText]=\"sh.style\"\n [innerHTML]=\"sh.value\"\n ></span>\n }\n @case (\"metric\") {\n <praxis-list-metric [metric]=\"sh\"></praxis-list-metric>\n }\n @case (\"compose\") {\n <praxis-list-compose [compose]=\"sh\"></praxis-list-compose>\n }\n @case (\"component\") {\n <praxis-list-runtime-component\n [component]=\"sh\"\n ></praxis-list-runtime-component>\n }\n @default {\n <span [ngClass]=\"sh.class\" [style.cssText]=\"sh.style\">{{\n sh.value\n }}</span>\n }\n }\n }\n }\n </div>\n }\n @for (\n item of section.items;\n track trackByItem($index, item);\n let i = $index\n ) {\n <mat-list-option\n [value]=\"item\"\n [attr.aria-label]=\"itemAriaLabel(item)\"\n >\n @if (hasRowLayoutGrid()) {\n <ng-container\n *ngTemplateOutlet=\"\n listRowLayout;\n context: {\n $implicit: item,\n index: i,\n sectionKey: section.key || undefined,\n clickable: false,\n }\n \"\n ></ng-container>\n } @else {\n <div\n class=\"list-item-content\"\n [ngClass]=\"itemRuleClass(item)\"\n [attr.style]=\"itemRuleStyle(item)\"\n >\n <div class=\"list-item-leading\">\n @if (leading(item); as lead) {\n @if (\n simpleRichContentNodes(lead, {\n imageAlt: config.templating?.leading?.imageAlt || \"\",\n });\n as richNodes\n ) {\n <praxis-rich-content [nodes]=\"richNodes\"></praxis-rich-content>\n } @else {\n @switch (lead.type) {\n @case (\"icon\") {\n <mat-icon\n [praxisIcon]=\"lead.value\"\n [ngClass]=\"lead.class\"\n [color]=\"\n isThemeColor(lead.color) ? lead.color : undefined\n \"\n [style.cssText]=\"\n (lead.style ? lead.style + ';' : '') +\n iconStyle(lead.color)\n \"\n ></mat-icon>\n }\n @case (\"image\") {\n <div\n class=\"lead-image\"\n [ngClass]=\"lead.class\"\n [style.cssText]=\"lead.style\"\n >\n <img\n [src]=\"lead.value\"\n [alt]=\"config.templating?.leading?.imageAlt || ''\"\n />\n @if (lead.badge?.value) {\n <mat-chip\n class=\"lead-badge\"\n [color]=\"\n isThemeColor(lead.badge?.color)\n ? lead.badge?.color\n : undefined\n \"\n [ngClass]=\"\n (lead.badge?.variant || 'filled') ===\n 'outlined'\n ? 'chip-outlined'\n : ''\n \"\n [style.cssText]=\"\n chipStyle(\n lead.badge?.color,\n lead.badge?.variant\n )\n \"\n >{{ lead.badge?.value }}</mat-chip\n >\n }\n </div>\n }\n @case (\"text\") {\n <span\n [ngClass]=\"lead.class\"\n [style.cssText]=\"lead.style\"\n >{{ lead.value }}</span\n >\n }\n @case (\"chip\") {\n <mat-chip\n [color]=\"\n isThemeColor(lead.color) ? lead.color : undefined\n \"\n [ngClass]=\"\n (lead.variant || 'filled') === 'outlined'\n ? 'chip-outlined'\n : ''\n \"\n [style.cssText]=\"\n chipStyle(lead.color, lead.variant)\n \"\n >{{ lead.value }}</mat-chip\n >\n }\n @case (\"rating\") {\n <span\n [ngClass]=\"lead.class\"\n [style.cssText]=\"lead.style\"\n >\n @for (\n _ of ratingRange(lead);\n track $index;\n let idx = $index\n ) {\n <mat-icon\n [praxisIcon]=\"starIcon(idx, lead.value)\"\n [color]=\"ratingThemeColor(lead)\"\n [style.cssText]=\"ratingIconStyle(lead)\"\n ></mat-icon>\n }\n </span>\n }\n @case (\"html\") {\n <span\n [ngClass]=\"lead.class\"\n [style.cssText]=\"lead.style\"\n [innerHTML]=\"lead.value\"\n ></span>\n }\n @case (\"metric\") {\n <praxis-list-metric [metric]=\"lead\"></praxis-list-metric>\n }\n @case (\"compose\") {\n <praxis-list-compose\n [compose]=\"lead\"\n ></praxis-list-compose>\n }\n @case (\"component\") {\n <praxis-list-runtime-component\n [component]=\"lead\"\n ></praxis-list-runtime-component>\n }\n @default {\n <span\n [ngClass]=\"lead.class\"\n [style.cssText]=\"lead.style\"\n >{{ lead.value }}</span\n >\n }\n }\n }\n } @else {\n <span class=\"leading-placeholder\"></span>\n }\n </div>\n <div class=\"list-item-text\">\n <div\n class=\"primary\"\n [ngClass]=\"primary(item)?.class\"\n [style.cssText]=\"primary(item)?.style\"\n >\n @if (simpleRichContentNodes(primary(item)); as richNodes) {\n <praxis-rich-content [nodes]=\"richNodes\"></praxis-rich-content>\n } @else if (primary(item)?.type === \"metric\") {\n <praxis-list-metric\n [metric]=\"primary(item)\"\n ></praxis-list-metric>\n } @else if (primary(item)?.type === \"compose\") {\n <praxis-list-compose\n [compose]=\"primary(item)\"\n ></praxis-list-compose>\n } @else if (primary(item)?.type === \"component\") {\n <praxis-list-runtime-component\n [component]=\"primary(item)\"\n ></praxis-list-runtime-component>\n } @else {\n {{ primary(item)?.value }}\n }\n </div>\n @if (layoutLines > 1) {\n <div\n class=\"secondary\"\n [ngClass]=\"secondary(item)?.class\"\n [style.cssText]=\"secondary(item)?.style\"\n >\n @if (simpleRichContentNodes(secondary(item)); as richNodes) {\n <praxis-rich-content [nodes]=\"richNodes\"></praxis-rich-content>\n } @else if (secondary(item)?.type === \"metric\") {\n <praxis-list-metric\n [metric]=\"secondary(item)\"\n ></praxis-list-metric>\n } @else if (secondary(item)?.type === \"compose\") {\n <praxis-list-compose\n [compose]=\"secondary(item)\"\n ></praxis-list-compose>\n } @else if (secondary(item)?.type === \"component\") {\n <praxis-list-runtime-component\n [component]=\"secondary(item)\"\n ></praxis-list-runtime-component>\n } @else {\n {{ secondary(item)?.value }}\n }\n </div>\n }\n @if (meta(item); as m) {\n @if (\n (config.templating?.metaPlacement === \"line\" &&\n (m?.type === \"text\" ||\n m?.type === \"date\" ||\n m?.type === \"currency\")) ||\n (layoutLines > 2 &&\n (m?.type === \"text\" ||\n m?.type === \"date\" ||\n m?.type === \"currency\"))\n ) {\n <div\n class=\"tertiary\"\n [ngClass]=\"m.class\"\n [style.cssText]=\"m.style\"\n >\n @if (config.templating?.metaPrefixIcon; as mpi) {\n <mat-icon [praxisIcon]=\"mpi\"></mat-icon>\n }\n {{ m.value }}\n </div>\n }\n }\n @if (featuresVisible()) {\n <div class=\"features\">\n @for (\n f of config.templating?.features || [];\n track $index;\n let fi = $index\n ) {\n <span\n class=\"feature\"\n [ngClass]=\"\n featureSemanticClass(item, f.expr, f.class)\n \"\n >\n @if (featureRichContentNodes(item, f); as featureNodes) {\n <praxis-rich-content [nodes]=\"featureNodes\"></praxis-rich-content>\n } @else {\n @if (f.icon && featuresMode() !== \"labels-only\") {\n <mat-icon [praxisIcon]=\"f.icon\"></mat-icon>\n }\n @if (featuresMode() !== \"icons-only\") {\n <span\n [ngClass]=\"f.class\"\n [style.cssText]=\"f.style\"\n >\n @for (\n line of featureLabelLines(item, f.expr);\n track $index\n ) {\n <span class=\"feature-line\">{{ line }}</span>\n }\n </span>\n }\n }\n @if (\n featureProgressPercent(item, f.expr, f.class);\n as progress\n ) {\n <span class=\"feature-progress\" aria-hidden=\"true\">\n <span\n class=\"feature-progress__value\"\n [style.width.%]=\"progress\"\n ></span>\n </span>\n }\n </span>\n }\n </div>\n }\n </div>\n <div class=\"list-item-trailing\">\n @if (meta(item); as m) {\n @if (\n !(\n (config.templating?.metaPlacement === \"line\" ||\n layoutLines > 2) &&\n (m?.type === \"text\" ||\n m?.type === \"date\" ||\n m?.type === \"currency\")\n )\n ) {\n <div\n class=\"meta\"\n [ngClass]=\"m.class\"\n [style.cssText]=\"m.style\"\n >\n @if (simpleRichContentNodes(m, { slot: 'meta' }); as richNodes) {\n <praxis-rich-content [nodes]=\"richNodes\"></praxis-rich-content>\n } @else {\n @switch (m.type) {\n @case (\"chip\") {\n <mat-chip\n [color]=\"\n isThemeColor(m.color) ? m.color : undefined\n \"\n [ngClass]=\"\n (m.variant || 'filled') === 'outlined'\n ? 'chip-outlined'\n : ''\n \"\n [style.cssText]=\"chipStyle(m.color, m.variant)\"\n >{{ m.value }}</mat-chip\n >\n }\n @case (\"rating\") {\n @for (\n _ of ratingRange(m);\n track $index;\n let idx = $index\n ) {\n <mat-icon\n [praxisIcon]=\"starIcon(idx, m.value)\"\n [color]=\"ratingThemeColor(m)\"\n [style.cssText]=\"ratingIconStyle(m)\"\n ></mat-icon>\n }\n }\n @case (\"icon\") {\n <mat-icon\n [praxisIcon]=\"m.value\"\n [color]=\"\n isThemeColor(m.color) ? m.color : undefined\n \"\n [style.cssText]=\"iconStyle(m.color)\"\n ></mat-icon>\n }\n @case (\"image\") {\n <span class=\"inline-image\"\n ><img [src]=\"m.value\" [alt]=\"m.imageAlt || ''\"\n /></span>\n }\n @case (\"html\") {\n <span [innerHTML]=\"m.value\"></span>\n }\n @case (\"metric\") {\n <praxis-list-metric [metric]=\"m\"></praxis-list-metric>\n }\n @case (\"compose\") {\n <praxis-list-compose\n [compose]=\"m\"\n ></praxis-list-compose>\n }\n @case (\"component\") {\n <praxis-list-runtime-component\n [component]=\"m\"\n ></praxis-list-runtime-component>\n }\n @default {\n <span>\n @if (\n config.templating?.metaPrefixIcon;\n as mpi2\n ) {\n <mat-icon [praxisIcon]=\"mpi2\"></mat-icon>\n }\n {{ m.value }}</span\n >\n }\n }\n }\n </div>\n }\n }\n @if (trailing(item); as tr) {\n <div\n class=\"trailing\"\n [ngClass]=\"tr.class\"\n [style.cssText]=\"tr.style\"\n >\n @if (\n simpleRichContentNodes(tr, {\n imageAlt: config.templating?.trailing?.imageAlt || \"\",\n });\n as richNodes\n ) {\n <praxis-rich-content [nodes]=\"richNodes\"></praxis-rich-content>\n } @else {\n @switch (tr.type) {\n @case (\"chip\") {\n <mat-chip\n [color]=\"\n isThemeColor(tr.color) ? tr.color : undefined\n \"\n [ngClass]=\"\n (tr.variant || 'filled') === 'outlined'\n ? 'chip-outlined'\n : ''\n \"\n [style.cssText]=\"chipStyle(tr.color, tr.variant)\"\n >{{ tr.value }}</mat-chip\n >\n }\n @case (\"icon\") {\n <mat-icon\n [praxisIcon]=\"tr.value\"\n [color]=\"\n isThemeColor(tr.color) ? tr.color : undefined\n \"\n [style.cssText]=\"iconStyle(tr.color)\"\n ></mat-icon>\n }\n @case (\"image\") {\n <div\n class=\"lead-image\"\n [ngClass]=\"tr.class\"\n [style.cssText]=\"tr.style\"\n >\n <img\n [src]=\"tr.value\"\n [alt]=\"\n config.templating?.trailing?.imageAlt || ''\n \"\n />\n @if (tr.badge?.value) {\n <mat-chip\n class=\"lead-badge\"\n [color]=\"\n isThemeColor(tr.badge?.color)\n ? tr.badge?.color\n : undefined\n \"\n [ngClass]=\"\n (tr.badge?.variant || 'filled') ===\n 'outlined'\n ? 'chip-outlined'\n : ''\n \"\n [style.cssText]=\"\n chipStyle(\n tr.badge?.color,\n tr.badge?.variant\n )\n \"\n >{{ tr.badge?.value }}</mat-chip\n >\n }\n </div>\n }\n @case (\"rating\") {\n @for (\n _ of ratingRange(tr);\n track $index;\n let idx = $index\n ) {\n <mat-icon\n [praxisIcon]=\"starIcon(idx, tr.value)\"\n [color]=\"ratingThemeColor(tr)\"\n [style.cssText]=\"ratingIconStyle(tr)\"\n ></mat-icon>\n }\n }\n @case (\"html\") {\n @if (item.alertsData !== undefined && item.ownerName) {\n <!-- Component-based rendering for executive trailing -->\n <span class=\"exec-trailing-shell\">\n <praxis-executive-alerts [alerts]=\"item.alertsData\"></praxis-executive-alerts>\n <praxis-executive-owner [name]=\"item.ownerName\"></praxis-executive-owner>\n </span>\n } @else {\n <span [innerHTML]=\"tr.value\"></span>\n }\n }\n @case (\"metric\") {\n <praxis-list-metric [metric]=\"tr\"></praxis-list-metric>\n }\n @case (\"compose\") {\n <praxis-list-compose\n [compose]=\"tr\"\n ></praxis-list-compose>\n }\n @case (\"component\") {\n <praxis-list-runtime-component\n [component]=\"tr\"\n ></praxis-list-runtime-component>\n }\n @default {\n <span>{{ tr.value }}</span>\n }\n }\n }\n </div>\n }\n @if (showExpandIcon(\"trailing\")) {\n <button\n mat-icon-button\n type=\"button\"\n class=\"expand-toggle\"\n [attr.aria-label]=\"expandToggleAriaLabel(item, i)\"\n [attr.aria-expanded]=\"\n expansionOwnedByIcon() ? isExpanded(item, i) : null\n \"\n [attr.aria-controls]=\"\n expansionOwnedByIcon()\n ? expandRegionId(item, i)\n : null\n \"\n (click)=\"onExpandToggle($event, item, i)\"\n >\n <mat-icon\n [praxisIcon]=\"\n isExpanded(item, i) ? 'expand_less' : 'expand_more'\n \"\n ></mat-icon>\n </button>\n }\n @if ((visibleActions(item, \"trailing\") || []).length) {\n <div\n class=\"list-item-actions\"\n (click)=\"$event.stopPropagation()\"\n (keydown.enter)=\"onActionKeydown($event)\"\n (keydown.space)=\"onActionKeydown($event)\"\n >\n @for (\n action of visibleActions(item, \"trailing\");\n let aidx = $index;\n track action?.id ?? $index\n ) {\n @if ((action.kind || \"icon\") === \"icon\") {\n <button\n mat-icon-button\n [color]=\"\n isThemeColor(action.color)\n ? action.color\n : undefined\n \"\n (click)=\"\n onActionClick($event, action.id, item, i)\n \"\n [attr.aria-label]=\"action.label || action.id\"\n [disabled]=\"isActionLoading(action.id, item, i)\"\n [ngClass]=\"{\n 'action-loading': isActionLoading(\n action.id,\n item,\n i\n ),\n }\"\n >\n @if (isActionLoading(action.id, item, i)) {\n <mat-progress-spinner\n class=\"action-spinner\"\n mode=\"indeterminate\"\n diameter=\"16\"\n strokeWidth=\"3\"\n ></mat-progress-spinner>\n } @else {\n <mat-icon\n [praxisIcon]=\"action.icon\"\n [style.cssText]=\"iconStyle(action.color)\"\n ></mat-icon>\n }\n </button>\n } @else {\n @if (action.buttonVariant === \"stroked\") {\n <button\n mat-stroked-button\n [color]=\"\n isThemeColor(action.color)\n ? action.color\n : undefined\n \"\n [style.cssText]=\"\n buttonStyle(action.color, 'stroked')\n \"\n (click)=\"\n onActionClick($event, action.id, item, i)\n \"\n [attr.aria-label]=\"action.label || action.id\"\n [disabled]=\"isActionLoading(action.id, item, i)\"\n [ngClass]=\"{\n 'action-loading': isActionLoading(\n action.id,\n item,\n i\n ),\n }\"\n >\n @if (isActionLoading(action.id, item, i)) {\n <mat-progress-spinner\n class=\"action-spinner\"\n mode=\"indeterminate\"\n diameter=\"16\"\n strokeWidth=\"3\"\n ></mat-progress-spinner>\n } @else {\n {{ action.label || action.id }}\n }\n </button>\n }\n @if (action.buttonVariant === \"raised\") {\n <button\n mat-raised-button\n [color]=\"\n isThemeColor(action.color)\n ? action.color\n : undefined\n \"\n [style.cssText]=\"\n buttonStyle(action.color, 'raised')\n \"\n (click)=\"\n onActionClick($event, action.id, item, i)\n \"\n [attr.aria-label]=\"action.label || action.id\"\n [disabled]=\"isActionLoading(action.id, item, i)\"\n [ngClass]=\"{\n 'action-loading': isActionLoading(\n action.id,\n item,\n i\n ),\n }\"\n >\n @if (isActionLoading(action.id, item, i)) {\n <mat-progress-spinner\n class=\"action-spinner\"\n mode=\"indeterminate\"\n diameter=\"16\"\n strokeWidth=\"3\"\n ></mat-progress-spinner>\n } @else {\n {{ action.label || action.id }}\n }\n </button>\n }\n @if (\n !action.buttonVariant ||\n action.buttonVariant === \"flat\"\n ) {\n <button\n mat-flat-button\n [color]=\"\n isThemeColor(action.color)\n ? action.color\n : undefined\n \"\n [style.cssText]=\"\n buttonStyle(action.color, 'flat')\n \"\n (click)=\"\n onActionClick($event, action.id, item, i)\n \"\n [attr.aria-label]=\"action.label || action.id\"\n [disabled]=\"isActionLoading(action.id, item, i)\"\n [ngClass]=\"{\n 'action-loading': isActionLoading(\n action.id,\n item,\n i\n ),\n }\"\n >\n @if (isActionLoading(action.id, item, i)) {\n <mat-progress-spinner\n class=\"action-spinner\"\n mode=\"indeterminate\"\n diameter=\"16\"\n strokeWidth=\"3\"\n ></mat-progress-spinner>\n } @else {\n {{ action.label || action.id }}\n }\n </button>\n }\n }\n }\n </div>\n }\n </div>\n </div>\n }\n @if (isExpandable() && isExpanded(item, i)) {\n <div\n class=\"item-expansion\"\n [id]=\"expandRegionId(item, i)\"\n role=\"region\"\n [attr.aria-label]=\"expansionRegionAriaLabel(item)\"\n >\n <div class=\"item-expansion-grid\">\n @for (\n expansionSection of expansionSections(item);\n track expansionSection.id\n ) {\n <section\n class=\"expansion-section\"\n [attr.data-section-type]=\"expansionSection.type\"\n >\n @if (expansionSection.title) {\n <div class=\"expansion-section-title\">\n {{ expansionSection.title }}\n </div>\n }\n @if (\n expansionSectionHasContent(\n item,\n expansionSection,\n i\n )\n ) {\n @switch (expansionSection.type) {\n @case (\"chip-list\") {\n <div class=\"expansion-chip-list\">\n @for (\n expansionEntry of expansionSectionItems(\n item,\n expansionSection,\n i\n );\n track $index\n ) {\n <mat-chip class=\"expansion-chip\">{{\n expansionItemLabel(expansionEntry)\n }}</mat-chip>\n }\n </div>\n }\n @case (\"timeline\") {\n <div class=\"expansion-timeline\">\n @for (\n expansionEntry of expansionSectionItems(\n item,\n expansionSection,\n i\n );\n track $index\n ) {\n <div class=\"expansion-timeline-item\">\n <div class=\"expansion-timeline-title\">\n {{\n expansionTimelineTitle(expansionEntry)\n }}\n </div>\n @if (\n expansionTimelineMeta(expansionEntry)\n ) {\n <div class=\"expansion-timeline-meta\">\n {{\n expansionTimelineMeta(\n expansionEntry\n )\n }}\n </div>\n }\n @if (\n expansionTimelineDescription(\n expansionEntry\n )\n ) {\n <div\n class=\"expansion-timeline-description\"\n >\n {{\n expansionTimelineDescription(\n expansionEntry\n )\n }}\n </div>\n }\n </div>\n }\n </div>\n }\n @case (\"key-value\") {\n <dl class=\"expansion-key-value\">\n @for (\n expansionEntry of expansionSectionItems(\n item,\n expansionSection,\n i\n );\n track $index\n ) {\n <div class=\"expansion-key-value-row\">\n @if (\n expansionKeyValueKey(expansionEntry)\n ) {\n <dt>\n {{\n expansionKeyValueKey(expansionEntry)\n }}\n </dt>\n }\n <dd>\n {{\n expansionKeyValueValue(expansionEntry)\n }}\n </dd>\n </div>\n }\n </dl>\n }\n @default {\n <div class=\"expansion-info-list\">\n @for (\n expansionEntry of expansionSectionItems(\n item,\n expansionSection,\n i\n );\n track $index\n ) {\n <div class=\"expansion-info-item\">\n <div class=\"expansion-info-title\">\n {{ expansionInfoTitle(expansionEntry) }}\n </div>\n @if (expansionInfoValue(expansionEntry)) {\n <div class=\"expansion-info-value\">\n {{\n expansionInfoValue(expansionEntry)\n }}\n </div>\n }\n </div>\n }\n </div>\n }\n }\n } @else {\n <div class=\"expansion-empty\">\n {{\n expansionSection.emptyLabel ||\n \"Sem dados dispon\u00EDveis\"\n }}\n </div>\n }\n </section>\n }\n </div>\n </div>\n }\n </mat-list-option>\n @if (\n (config.layout?.dividers === \"all\" ||\n config.layout?.dividers === \"between\") &&\n i < section.items.length - 1\n ) {\n <mat-divider></mat-divider>\n }\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 (\n section of sections$ | async;\n track trackBySection($index, section);\n let sidx = $index\n ) {\n @if (section.key) {\n <div class=\"section-header mat-subheader\">\n @if (sectionHeaderTemplate(section.key); as sh) {\n @if (\n simpleRichContentNodes(sh, {\n imageAlt: config.templating?.sectionHeader?.imageAlt || \"\",\n });\n as richNodes\n ) {\n <praxis-rich-content [nodes]=\"richNodes\"></praxis-rich-content>\n } @else {\n @switch (sh.type) {\n @case (\"icon\") {\n <mat-icon\n [praxisIcon]=\"sh.value\"\n [ngClass]=\"sh.class\"\n [color]=\"isThemeColor(sh.color) ? sh.color : undefined\"\n [style.cssText]=\"\n (sh.style ? sh.style + ';' : '') + iconStyle(sh.color)\n \"\n ></mat-icon>\n }\n @case (\"image\") {\n <span\n class=\"inline-image\"\n [ngClass]=\"sh.class\"\n [style.cssText]=\"sh.style\"\n >\n <img\n [src]=\"sh.value\"\n [alt]=\"\n config.templating?.sectionHeader?.imageAlt || ''\n \"\n />\n @if (sh.badge?.value) {\n <mat-chip\n class=\"inline-badge\"\n [color]=\"\n isThemeColor(sh.badge?.color)\n ? sh.badge?.color\n : undefined\n \"\n [ngClass]=\"\n (sh.badge?.variant || 'filled') === 'outlined'\n ? 'chip-outlined'\n : ''\n \"\n [style.cssText]=\"\n chipStyle(sh.badge?.color, sh.badge?.variant)\n \"\n >{{ sh.badge?.value }}</mat-chip\n >\n }\n </span>\n }\n @case (\"chip\") {\n <mat-chip\n [color]=\"isThemeColor(sh.color) ? sh.color : undefined\"\n [ngClass]=\"[\n sh.class || '',\n (sh.variant || 'filled') === 'outlined'\n ? 'chip-outlined'\n : '',\n ]\"\n [style.cssText]=\"\n chipStyle(sh.color, sh.variant) +\n (sh.style ? ';' + sh.style : '')\n \"\n >{{ sh.value }}</mat-chip\n >\n }\n @case (\"rating\") {\n <span [ngClass]=\"sh.class\" [style.cssText]=\"sh.style\">\n @for (\n _ of ratingRange(sh);\n track $index;\n let idx = $index\n ) {\n <mat-icon\n [praxisIcon]=\"starIcon(idx, sh.value)\"\n [color]=\"ratingThemeColor(sh)\"\n [style.cssText]=\"ratingIconStyle(sh)\"\n ></mat-icon>\n }\n </span>\n }\n @case (\"html\") {\n <span\n [ngClass]=\"sh.class\"\n [style.cssText]=\"sh.style\"\n [innerHTML]=\"sh.value\"\n ></span>\n }\n @case (\"metric\") {\n <praxis-list-metric [metric]=\"sh\"></praxis-list-metric>\n }\n @default {\n <span [ngClass]=\"sh.class\" [style.cssText]=\"sh.style\">{{\n sh.value\n }}</span>\n }\n }\n }\n }\n </div>\n }\n @for (\n item of section.items;\n track trackByItem($index, item);\n let i = $index\n ) {\n <mat-list-item [attr.data-item-status]=\"item?.status || null\">\n @if (hasRowLayoutGrid()) {\n <ng-container\n *ngTemplateOutlet=\"\n listRowLayout;\n context: {\n $implicit: item,\n index: i,\n sectionKey: section.key || undefined,\n clickable: true,\n }\n \"\n ></ng-container>\n } @else {\n <div\n class=\"list-item-content\"\n [ngClass]=\"itemRuleClass(item)\"\n [attr.style]=\"itemRuleStyle(item)\"\n >\n <button\n type=\"button\"\n class=\"list-item-main-action\"\n [attr.aria-label]=\"itemAriaLabel(item)\"\n [attr.aria-expanded]=\"\n expansionOwnedByRow() ? isExpanded(item, i) : null\n \"\n [attr.aria-controls]=\"\n expansionOwnedByRow() ? expandRegionId(item, i) : null\n \"\n (click)=\"onRowActivate(item, i, section.key || undefined)\"\n >\n <div class=\"list-item-leading\">\n @if (leading(item); as lead) {\n @if (\n simpleRichContentNodes(lead, {\n imageAlt: config.templating?.leading?.imageAlt || \"\",\n });\n as richNodes\n ) {\n <praxis-rich-content [nodes]=\"richNodes\"></praxis-rich-content>\n } @else {\n @switch (lead.type) {\n @case (\"icon\") {\n <mat-icon\n [praxisIcon]=\"lead.value\"\n [ngClass]=\"lead.class\"\n [color]=\"\n isThemeColor(lead.color)\n ? lead.color\n : undefined\n \"\n [style.cssText]=\"\n (lead.style ? lead.style + ';' : '') +\n iconStyle(lead.color)\n \"\n ></mat-icon>\n }\n @case (\"image\") {\n <div\n class=\"lead-image\"\n [ngClass]=\"lead.class\"\n [style.cssText]=\"lead.style\"\n >\n <img\n [src]=\"lead.value\"\n [alt]=\"\n config.templating?.leading?.imageAlt || ''\n \"\n />\n @if (lead.badge?.value) {\n <mat-chip\n class=\"lead-badge\"\n [color]=\"\n isThemeColor(lead.badge?.color)\n ? lead.badge?.color\n : undefined\n \"\n [ngClass]=\"\n (lead.badge?.variant || 'filled') ===\n 'outlined'\n ? 'chip-outlined'\n : ''\n \"\n [style.cssText]=\"\n chipStyle(\n lead.badge?.color,\n lead.badge?.variant\n )\n \"\n >{{ lead.badge?.value }}</mat-chip\n >\n }\n </div>\n }\n @case (\"text\") {\n <span\n [ngClass]=\"lead.class\"\n [style.cssText]=\"lead.style\"\n >{{ lead.value }}</span\n >\n }\n @case (\"chip\") {\n <mat-chip\n [color]=\"\n isThemeColor(lead.color)\n ? lead.color\n : undefined\n \"\n [ngClass]=\"\n (lead.variant || 'filled') === 'outlined'\n ? 'chip-outlined'\n : ''\n \"\n [style.cssText]=\"\n chipStyle(lead.color, lead.variant)\n \"\n >{{ lead.value }}</mat-chip\n >\n }\n @case (\"rating\") {\n @for (\n _ of ratingRange(lead);\n track $index;\n let idx = $index\n ) {\n <mat-icon\n [praxisIcon]=\"starIcon(idx, lead.value)\"\n [color]=\"ratingThemeColor(lead)\"\n [style.cssText]=\"ratingIconStyle(lead)\"\n ></mat-icon>\n }\n }\n @case (\"html\") {\n <span\n [ngClass]=\"lead.class\"\n [style.cssText]=\"lead.style\"\n [innerHTML]=\"lead.value\"\n ></span>\n }\n @case (\"metric\") {\n <praxis-list-metric [metric]=\"lead\"></praxis-list-metric>\n }\n @default {\n <span\n [ngClass]=\"lead.class\"\n [style.cssText]=\"lead.style\"\n >{{ lead.value }}</span\n >\n }\n }\n }\n } @else {\n <span class=\"leading-placeholder\"></span>\n }\n </div>\n <div class=\"list-item-text\">\n <div\n class=\"primary\"\n [ngClass]=\"primary(item)?.class\"\n [style.cssText]=\"primary(item)?.style\"\n >\n @if (simpleRichContentNodes(primary(item)); as richNodes) {\n <praxis-rich-content [nodes]=\"richNodes\"></praxis-rich-content>\n } @else if (primary(item)?.type === \"metric\") {\n <praxis-list-metric\n [metric]=\"primary(item)\"\n ></praxis-list-metric>\n } @else if (primary(item)?.type === \"html\") {\n <span [innerHTML]=\"primary(item)?.value\"></span>\n } @else {\n {{ primary(item)?.value }}\n }\n </div>\n @if (layoutLines > 1) {\n <div\n class=\"secondary\"\n [ngClass]=\"secondary(item)?.class\"\n [style.cssText]=\"secondary(item)?.style\"\n >\n @if (simpleRichContentNodes(secondary(item)); as richNodes) {\n <praxis-rich-content [nodes]=\"richNodes\"></praxis-rich-content>\n } @else if (item.segmentVariant && item.segmentLabel && item.accountType && item.since) {\n <!-- Component-based rendering for executive items -->\n <span class=\"exec-subline\">\n <praxis-executive-badge\n [variant]=\"item.segmentVariant\"\n [label]=\"item.segmentLabel\"\n ></praxis-executive-badge>\n <span class=\"exec-subcopy\">{{ item.accountType }}</span>\n <span class=\"exec-subseparator\">\u00B7</span>\n <span class=\"exec-subcopy\">Desde {{ item.since }}</span>\n </span>\n } @else if (secondary(item)?.type === \"html\") {\n <span [innerHTML]=\"secondary(item)?.value\"></span>\n } @else if (secondary(item)?.type === \"metric\") {\n <praxis-list-metric\n [metric]=\"secondary(item)\"\n ></praxis-list-metric>\n } @else {\n {{ secondary(item)?.value }}\n }\n </div>\n }\n @if (meta(item); as m) {\n @if (\n (config.templating?.metaPlacement === \"line\" &&\n (m?.type === \"text\" ||\n m?.type === \"date\" ||\n m?.type === \"currency\")) ||\n (layoutLines > 2 &&\n (m?.type === \"text\" ||\n m?.type === \"date\" ||\n m?.type === \"currency\"))\n ) {\n <div\n class=\"tertiary\"\n [ngClass]=\"m.class\"\n [style.cssText]=\"m.style\"\n >\n @if (config.templating?.metaPrefixIcon; as mpi) {\n <mat-icon [praxisIcon]=\"mpi\"></mat-icon>\n }\n {{ m.value }}\n </div>\n }\n }\n @if (featuresVisible()) {\n <div class=\"features\">\n @for (\n f of config.templating?.features || [];\n track $index;\n let fi = $index\n ) {\n <span\n class=\"feature\"\n [ngClass]=\"\n featureSemanticClass(item, f.expr, f.class)\n \"\n >\n @if (featureRichContentNodes(item, f); as featureNodes) {\n <praxis-rich-content [nodes]=\"featureNodes\"></praxis-rich-content>\n } @else {\n @if (f.icon && featuresMode() !== \"labels-only\") {\n <mat-icon [praxisIcon]=\"f.icon\"></mat-icon>\n }\n @if (featuresMode() !== \"icons-only\") {\n <span\n [ngClass]=\"f.class\"\n [style.cssText]=\"f.style\"\n >\n @for (\n line of featureLabelLines(item, f.expr);\n track $index\n ) {\n <span class=\"feature-line\">{{ line }}</span>\n }\n </span>\n }\n }\n @if (\n featureProgressPercent(item, f.expr, f.class);\n as progress\n ) {\n <span\n class=\"feature-progress\"\n aria-hidden=\"true\"\n >\n <span\n class=\"feature-progress__value\"\n [style.width.%]=\"progress\"\n ></span>\n </span>\n }\n </span>\n }\n </div>\n }\n </div>\n </button>\n <div class=\"list-item-trailing\">\n @if (meta(item); as m) {\n @if (\n !(\n (config.templating?.metaPlacement === \"line\" ||\n layoutLines > 2) &&\n (m?.type === \"text\" ||\n m?.type === \"date\" ||\n m?.type === \"currency\")\n )\n ) {\n <div\n class=\"meta\"\n [ngClass]=\"m.class\"\n [style.cssText]=\"m.style\"\n >\n @if (simpleRichContentNodes(m, { slot: 'meta' }); as richNodes) {\n <praxis-rich-content [nodes]=\"richNodes\"></praxis-rich-content>\n } @else {\n @switch (m.type) {\n @case (\"chip\") {\n <mat-chip\n [color]=\"\n isThemeColor(m.color) ? m.color : undefined\n \"\n [ngClass]=\"\n (m.variant || 'filled') === 'outlined'\n ? 'chip-outlined'\n : ''\n \"\n [style.cssText]=\"chipStyle(m.color, m.variant)\"\n >{{ m.value }}</mat-chip\n >\n }\n @case (\"rating\") {\n @for (\n _ of ratingRange(m);\n track $index;\n let idx = $index\n ) {\n <mat-icon\n [praxisIcon]=\"starIcon(idx, m.value)\"\n [color]=\"ratingThemeColor(m)\"\n [style.cssText]=\"ratingIconStyle(m)\"\n ></mat-icon>\n }\n }\n @case (\"icon\") {\n <mat-icon\n [praxisIcon]=\"m.value\"\n [color]=\"\n isThemeColor(m.color) ? m.color : undefined\n \"\n [style.cssText]=\"iconStyle(m.color)\"\n ></mat-icon>\n }\n @case (\"image\") {\n <span class=\"inline-image\"\n ><img [src]=\"m.value\" [alt]=\"m.imageAlt || ''\"\n /></span>\n }\n @case (\"html\") {\n <span [innerHTML]=\"m.value\"></span>\n }\n @case (\"metric\") {\n <praxis-list-metric [metric]=\"m\"></praxis-list-metric>\n }\n @default {\n <span>\n @if (\n config.templating?.metaPrefixIcon;\n as mpi2\n ) {\n <mat-icon [praxisIcon]=\"mpi2\"></mat-icon>\n }\n {{ m.value }}</span\n >\n }\n }\n }\n </div>\n }\n }\n @if (trailing(item); as tr) {\n <div\n class=\"trailing\"\n [ngClass]=\"tr.class\"\n [style.cssText]=\"tr.style\"\n >\n @if (\n simpleRichContentNodes(tr, {\n imageAlt: config.templating?.trailing?.imageAlt || \"\",\n });\n as richNodes\n ) {\n <praxis-rich-content [nodes]=\"richNodes\"></praxis-rich-content>\n } @else {\n @switch (tr.type) {\n @case (\"chip\") {\n <mat-chip\n [color]=\"\n isThemeColor(tr.color) ? tr.color : undefined\n \"\n [ngClass]=\"\n (tr.variant || 'filled') === 'outlined'\n ? 'chip-outlined'\n : ''\n \"\n [style.cssText]=\"chipStyle(tr.color, tr.variant)\"\n >{{ tr.value }}</mat-chip\n >\n }\n @case (\"icon\") {\n <mat-icon\n [praxisIcon]=\"tr.value\"\n [color]=\"\n isThemeColor(tr.color) ? tr.color : undefined\n \"\n [style.cssText]=\"iconStyle(tr.color)\"\n ></mat-icon>\n }\n @case (\"image\") {\n <div\n class=\"lead-image\"\n [ngClass]=\"tr.class\"\n [style.cssText]=\"tr.style\"\n >\n <img\n [src]=\"tr.value\"\n [alt]=\"\n config.templating?.trailing?.imageAlt || ''\n \"\n />\n @if (tr.badge?.value) {\n <mat-chip\n class=\"lead-badge\"\n [color]=\"\n isThemeColor(tr.badge?.color)\n ? tr.badge?.color\n : undefined\n \"\n [ngClass]=\"\n (tr.badge?.variant || 'filled') ===\n 'outlined'\n ? 'chip-outlined'\n : ''\n \"\n [style.cssText]=\"\n chipStyle(\n tr.badge?.color,\n tr.badge?.variant\n )\n \"\n >{{ tr.badge?.value }}</mat-chip\n >\n }\n </div>\n }\n @case (\"rating\") {\n @for (\n _ of ratingRange(tr);\n track $index;\n let idx = $index\n ) {\n <mat-icon\n [praxisIcon]=\"starIcon(idx, tr.value)\"\n [color]=\"ratingThemeColor(tr)\"\n [style.cssText]=\"ratingIconStyle(tr)\"\n ></mat-icon>\n }\n }\n @case (\"html\") {\n @if (item.alertsData !== undefined && item.ownerName) {\n <!-- Component-based rendering for executive trailing -->\n <span class=\"exec-trailing-shell\">\n <praxis-executive-alerts [alerts]=\"item.alertsData\"></praxis-executive-alerts>\n <praxis-executive-owner [name]=\"item.ownerName\"></praxis-executive-owner>\n </span>\n } @else {\n <span [innerHTML]=\"tr.value\"></span>\n }\n }\n @case (\"metric\") {\n <praxis-list-metric [metric]=\"tr\"></praxis-list-metric>\n }\n @default {\n <span>{{ tr.value }}</span>\n }\n }\n }\n </div>\n }\n @if (showExpandIcon(\"trailing\")) {\n <button\n mat-icon-button\n type=\"button\"\n class=\"expand-toggle\"\n [attr.aria-label]=\"expandToggleAriaLabel(item, i)\"\n [attr.aria-expanded]=\"\n expansionOwnedByIcon() ? isExpanded(item, i) : null\n \"\n [attr.aria-controls]=\"\n expansionOwnedByIcon()\n ? expandRegionId(item, i)\n : null\n \"\n (click)=\"onExpandToggle($event, item, i)\"\n >\n <mat-icon\n [praxisIcon]=\"\n isExpanded(item, i) ? 'expand_less' : 'expand_more'\n \"\n ></mat-icon>\n </button>\n }\n @if ((visibleActions(item, \"trailing\") || []).length) {\n <div\n class=\"list-item-actions\"\n (click)=\"$event.stopPropagation()\"\n (keydown.enter)=\"onActionKeydown($event)\"\n (keydown.space)=\"onActionKeydown($event)\"\n >\n @for (\n action of visibleActions(item, \"trailing\");\n let aidx = $index;\n track action?.id ?? $index\n ) {\n @if ((action.kind || \"icon\") === \"icon\") {\n <button\n mat-icon-button\n [color]=\"\n isThemeColor(action.color)\n ? action.color\n : undefined\n \"\n (click)=\"\n onActionClick($event, action.id, item, i)\n \"\n [attr.aria-label]=\"action.label || action.id\"\n [disabled]=\"isActionLoading(action.id, item, i)\"\n [ngClass]=\"{\n 'action-loading': isActionLoading(\n action.id,\n item,\n i\n ),\n }\"\n >\n @if (isActionLoading(action.id, item, i)) {\n <mat-progress-spinner\n class=\"action-spinner\"\n mode=\"indeterminate\"\n diameter=\"16\"\n strokeWidth=\"3\"\n ></mat-progress-spinner>\n } @else {\n <mat-icon\n [praxisIcon]=\"action.icon\"\n [style.cssText]=\"iconStyle(action.color)\"\n ></mat-icon>\n }\n </button>\n } @else {\n @if (action.buttonVariant === \"stroked\") {\n <button\n mat-stroked-button\n [color]=\"\n isThemeColor(action.color)\n ? action.color\n : undefined\n \"\n [style.cssText]=\"\n buttonStyle(action.color, 'stroked')\n \"\n (click)=\"\n onActionClick($event, action.id, item, i)\n \"\n [attr.aria-label]=\"action.label || action.id\"\n [disabled]=\"isActionLoading(action.id, item, i)\"\n [ngClass]=\"{\n 'action-loading': isActionLoading(\n action.id,\n item,\n i\n ),\n }\"\n >\n @if (isActionLoading(action.id, item, i)) {\n <mat-progress-spinner\n class=\"action-spinner\"\n mode=\"indeterminate\"\n diameter=\"16\"\n strokeWidth=\"3\"\n ></mat-progress-spinner>\n } @else {\n {{ action.label || action.id }}\n }\n </button>\n }\n @if (action.buttonVariant === \"raised\") {\n <button\n mat-raised-button\n [color]=\"\n isThemeColor(action.color)\n ? action.color\n : undefined\n \"\n [style.cssText]=\"\n buttonStyle(action.color, 'raised')\n \"\n (click)=\"\n onActionClick($event, action.id, item, i)\n \"\n [attr.aria-label]=\"action.label || action.id\"\n [disabled]=\"isActionLoading(action.id, item, i)\"\n [ngClass]=\"{\n 'action-loading': isActionLoading(\n action.id,\n item,\n i\n ),\n }\"\n >\n @if (isActionLoading(action.id, item, i)) {\n <mat-progress-spinner\n class=\"action-spinner\"\n mode=\"indeterminate\"\n diameter=\"16\"\n strokeWidth=\"3\"\n ></mat-progress-spinner>\n } @else {\n {{ action.label || action.id }}\n }\n </button>\n }\n @if (\n !action.buttonVariant ||\n action.buttonVariant === \"flat\"\n ) {\n <button\n mat-flat-button\n [color]=\"\n isThemeColor(action.color)\n ? action.color\n : undefined\n \"\n [style.cssText]=\"\n buttonStyle(action.color, 'flat')\n \"\n (click)=\"\n onActionClick($event, action.id, item, i)\n \"\n [attr.aria-label]=\"action.label || action.id\"\n [disabled]=\"isActionLoading(action.id, item, i)\"\n [ngClass]=\"{\n 'action-loading': isActionLoading(\n action.id,\n item,\n i\n ),\n }\"\n >\n @if (isActionLoading(action.id, item, i)) {\n <mat-progress-spinner\n class=\"action-spinner\"\n mode=\"indeterminate\"\n diameter=\"16\"\n strokeWidth=\"3\"\n ></mat-progress-spinner>\n } @else {\n {{ action.label || action.id }}\n }\n </button>\n }\n }\n }\n </div>\n }\n </div>\n </div>\n }\n @if (isExpandable() && isExpanded(item, i)) {\n <div\n class=\"item-expansion\"\n [id]=\"expandRegionId(item, i)\"\n role=\"region\"\n [attr.aria-label]=\"expansionRegionAriaLabel(item)\"\n >\n <div class=\"item-expansion-grid\">\n @for (\n expansionSection of expansionSections(item);\n track expansionSection.id\n ) {\n <section\n class=\"expansion-section\"\n [attr.data-section-type]=\"expansionSection.type\"\n >\n @if (expansionSection.title) {\n <div class=\"expansion-section-title\">\n {{ expansionSection.title }}\n </div>\n }\n @if (\n expansionSectionHasContent(\n item,\n expansionSection,\n i\n )\n ) {\n @switch (expansionSection.type) {\n @case (\"chip-list\") {\n <div class=\"expansion-chip-list\">\n @for (\n expansionEntry of expansionSectionItems(\n item,\n expansionSection,\n i\n );\n track $index\n ) {\n <mat-chip class=\"expansion-chip\">{{\n expansionItemLabel(expansionEntry)\n }}</mat-chip>\n }\n </div>\n }\n @case (\"timeline\") {\n <div class=\"expansion-timeline\">\n @for (\n expansionEntry of expansionSectionItems(\n item,\n expansionSection,\n i\n );\n track $index\n ) {\n <div class=\"expansion-timeline-item\">\n <div class=\"expansion-timeline-title\">\n {{\n expansionTimelineTitle(expansionEntry)\n }}\n </div>\n @if (\n expansionTimelineMeta(expansionEntry)\n ) {\n <div class=\"expansion-timeline-meta\">\n {{\n expansionTimelineMeta(\n expansionEntry\n )\n }}\n </div>\n }\n @if (\n expansionTimelineDescription(\n expansionEntry\n )\n ) {\n <div\n class=\"expansion-timeline-description\"\n >\n {{\n expansionTimelineDescription(\n expansionEntry\n )\n }}\n </div>\n }\n </div>\n }\n </div>\n }\n @case (\"key-value\") {\n <dl class=\"expansion-key-value\">\n @for (\n expansionEntry of expansionSectionItems(\n item,\n expansionSection,\n i\n );\n track $index\n ) {\n <div class=\"expansion-key-value-row\">\n @if (\n expansionKeyValueKey(expansionEntry)\n ) {\n <dt>\n {{\n expansionKeyValueKey(expansionEntry)\n }}\n </dt>\n }\n <dd>\n {{\n expansionKeyValueValue(expansionEntry)\n }}\n </dd>\n </div>\n }\n </dl>\n }\n @default {\n <div class=\"expansion-info-list\">\n @for (\n expansionEntry of expansionSectionItems(\n item,\n expansionSection,\n i\n );\n track $index\n ) {\n <div class=\"expansion-info-item\">\n <div class=\"expansion-info-title\">\n {{ expansionInfoTitle(expansionEntry) }}\n </div>\n @if (expansionInfoValue(expansionEntry)) {\n <div class=\"expansion-info-value\">\n {{\n expansionInfoValue(expansionEntry)\n }}\n </div>\n }\n </div>\n }\n </div>\n }\n }\n } @else {\n <div class=\"expansion-empty\">\n {{\n expansionSection.emptyLabel ||\n \"Sem dados dispon\u00EDveis\"\n }}\n </div>\n }\n </section>\n }\n </div>\n </div>\n }\n </mat-list-item>\n @if (\n (config.layout?.dividers === \"all\" ||\n config.layout?.dividers === \"between\") &&\n i < section.items.length - 1\n ) {\n <mat-divider></mat-divider>\n }\n }\n }\n </mat-list>\n </ng-template>\n } @else if (isTilesVariant()) {\n <ng-container *ngTemplateOutlet=\"tilesVariant\"></ng-container>\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\n class=\"item-card\"\n [ngClass]=\"itemRuleClass(it)\"\n [attr.style]=\"itemRuleStyle(it)\"\n role=\"button\"\n tabindex=\"0\"\n [attr.aria-label]=\"itemAriaLabel(it)\"\n (click)=\"onItemClick(it, i)\"\n (keydown.enter)=\"onItemClick(it, i)\"\n (keydown.space)=\"$event.preventDefault(); onItemClick(it, i)\"\n >\n <div class=\"list-item-content\">\n <div class=\"list-item-leading\">\n @if (leading(it); as lead) {\n @if (\n simpleRichContentNodes(lead, {\n imageAlt: config.templating?.leading?.imageAlt || \"\",\n });\n as richNodes\n ) {\n <praxis-rich-content [nodes]=\"richNodes\"></praxis-rich-content>\n } @else {\n @switch (lead.type) {\n @case (\"icon\") {\n <mat-icon\n [praxisIcon]=\"lead.value\"\n [ngClass]=\"lead.class\"\n [color]=\"\n isThemeColor(lead.color) ? lead.color : undefined\n \"\n [style.cssText]=\"\n (lead.style ? lead.style + ';' : '') +\n iconStyle(lead.color)\n \"\n ></mat-icon>\n }\n @case (\"image\") {\n <div\n class=\"lead-image\"\n [ngClass]=\"lead.class\"\n [style.cssText]=\"lead.style\"\n >\n <img\n [src]=\"lead.value\"\n [alt]=\"config.templating?.leading?.imageAlt || ''\"\n />\n @if (lead.badge?.value) {\n <mat-chip\n class=\"lead-badge\"\n [color]=\"\n isThemeColor(lead.badge?.color)\n ? lead.badge?.color\n : undefined\n \"\n [ngClass]=\"\n (lead.badge?.variant || 'filled') === 'outlined'\n ? 'chip-outlined'\n : ''\n \"\n [style.cssText]=\"\n chipStyle(\n lead.badge?.color,\n lead.badge?.variant\n )\n \"\n >{{ lead.badge?.value }}</mat-chip\n >\n }\n </div>\n }\n @case (\"text\") {\n <span\n [ngClass]=\"lead.class\"\n [style.cssText]=\"lead.style\"\n >{{ lead.value }}</span\n >\n }\n @case (\"chip\") {\n <mat-chip\n [color]=\"\n isThemeColor(lead.color) ? lead.color : undefined\n \"\n [ngClass]=\"\n (lead.variant || 'filled') === 'outlined'\n ? 'chip-outlined'\n : ''\n \"\n [style.cssText]=\"chipStyle(lead.color, lead.variant)\"\n >{{ lead.value }}</mat-chip\n >\n }\n @case (\"rating\") {\n @for (\n _ of ratingRange(lead);\n track $index;\n let idx = $index\n ) {\n <mat-icon\n [praxisIcon]=\"starIcon(idx, lead.value)\"\n [color]=\"ratingThemeColor(lead)\"\n [style.cssText]=\"ratingIconStyle(lead)\"\n ></mat-icon>\n }\n }\n @case (\"html\") {\n <span\n [ngClass]=\"lead.class\"\n [style.cssText]=\"lead.style\"\n [innerHTML]=\"lead.value\"\n ></span>\n }\n @case (\"metric\") {\n <praxis-list-metric\n [metric]=\"lead\"\n ></praxis-list-metric>\n }\n @case (\"compose\") {\n <praxis-list-compose\n [compose]=\"lead\"\n ></praxis-list-compose>\n }\n @case (\"component\") {\n <praxis-list-runtime-component\n [component]=\"lead\"\n ></praxis-list-runtime-component>\n }\n @default {\n <span\n [ngClass]=\"lead.class\"\n [style.cssText]=\"lead.style\"\n >{{ lead.value }}</span\n >\n }\n }\n }\n } @else {\n <span class=\"leading-placeholder\"></span>\n }\n </div>\n <div class=\"list-item-text\">\n <div\n class=\"primary\"\n [ngClass]=\"primary(it)?.class\"\n [style.cssText]=\"primary(it)?.style\"\n >\n @if (simpleRichContentNodes(primary(it)); as richNodes) {\n <praxis-rich-content [nodes]=\"richNodes\"></praxis-rich-content>\n } @else if (primary(it)?.type === \"metric\") {\n <praxis-list-metric [metric]=\"primary(it)\"></praxis-list-metric>\n } @else if (primary(it)?.type === \"compose\") {\n <praxis-list-compose\n [compose]=\"primary(it)\"\n ></praxis-list-compose>\n } @else if (primary(it)?.type === \"component\") {\n <praxis-list-runtime-component\n [component]=\"primary(it)\"\n ></praxis-list-runtime-component>\n } @else {\n {{ primary(it)?.value }}\n }\n </div>\n @if (layoutLines > 1) {\n <div\n class=\"secondary\"\n [ngClass]=\"secondary(it)?.class\"\n [style.cssText]=\"secondary(it)?.style\"\n >\n @if (simpleRichContentNodes(secondary(it)); as richNodes) {\n <praxis-rich-content [nodes]=\"richNodes\"></praxis-rich-content>\n } @else if (secondary(it)?.type === \"metric\") {\n <praxis-list-metric\n [metric]=\"secondary(it)\"\n ></praxis-list-metric>\n } @else if (secondary(it)?.type === \"compose\") {\n <praxis-list-compose\n [compose]=\"secondary(it)\"\n ></praxis-list-compose>\n } @else if (secondary(it)?.type === \"component\") {\n <praxis-list-runtime-component\n [component]=\"secondary(it)\"\n ></praxis-list-runtime-component>\n } @else {\n {{ secondary(it)?.value }}\n }\n </div>\n }\n @if (meta(it); as m) {\n @if (\n (config.templating?.metaPlacement === \"line\" &&\n (m?.type === \"text\" ||\n m?.type === \"date\" ||\n m?.type === \"currency\")) ||\n (layoutLines > 2 &&\n (m?.type === \"text\" ||\n m?.type === \"date\" ||\n m?.type === \"currency\"))\n ) {\n <div\n class=\"tertiary\"\n [ngClass]=\"m.class\"\n [style.cssText]=\"m.style\"\n >\n @if (config.templating?.metaPrefixIcon; as mpi) {\n <mat-icon [praxisIcon]=\"mpi\"></mat-icon>\n }\n {{ m.value }}\n </div>\n }\n }\n @if (featuresVisible()) {\n <div class=\"features\">\n @for (\n f of config.templating?.features || [];\n track $index;\n let fi = $index\n ) {\n <span\n class=\"feature\"\n [ngClass]=\"featureSemanticClass(it, f.expr, f.class)\"\n >\n @if (featureRichContentNodes(it, f); as featureNodes) {\n <praxis-rich-content [nodes]=\"featureNodes\"></praxis-rich-content>\n } @else {\n @if (f.icon && featuresMode() !== \"labels-only\") {\n <mat-icon [praxisIcon]=\"f.icon\"></mat-icon>\n }\n @if (featuresMode() !== \"icons-only\") {\n <span [ngClass]=\"f.class\" [style.cssText]=\"f.style\">\n @for (\n line of featureLabelLines(it, f.expr);\n track $index\n ) {\n <span class=\"feature-line\">{{ line }}</span>\n }\n </span>\n }\n }\n @if (\n featureProgressPercent(it, f.expr, f.class);\n as progress\n ) {\n <span class=\"feature-progress\" aria-hidden=\"true\">\n <span\n class=\"feature-progress__value\"\n [style.width.%]=\"progress\"\n ></span>\n </span>\n }\n </span>\n }\n </div>\n }\n </div>\n <div class=\"list-item-trailing\">\n @if (meta(it); as m) {\n @if (\n !(\n (config.templating?.metaPlacement === \"line\" ||\n layoutLines > 2) &&\n (m?.type === \"text\" ||\n m?.type === \"date\" ||\n m?.type === \"currency\")\n )\n ) {\n <div\n class=\"meta\"\n [ngClass]=\"m.class\"\n [style.cssText]=\"m.style\"\n >\n @if (\n simpleRichContentNodes(m, {\n slot: \"meta\",\n imageAlt: m.imageAlt || \"\",\n });\n as richNodes\n ) {\n <praxis-rich-content [nodes]=\"richNodes\"></praxis-rich-content>\n } @else {\n @switch (m.type) {\n @case (\"chip\") {\n <mat-chip\n [color]=\"\n isThemeColor(m.color) ? m.color : undefined\n \"\n [ngClass]=\"\n (m.variant || 'filled') === 'outlined'\n ? 'chip-outlined'\n : ''\n \"\n [style.cssText]=\"chipStyle(m.color, m.variant)\"\n >{{ m.value }}</mat-chip\n >\n }\n @case (\"rating\") {\n @for (\n _ of ratingRange(m);\n track $index;\n let idx = $index\n ) {\n <mat-icon\n [praxisIcon]=\"starIcon(idx, m.value)\"\n [color]=\"ratingThemeColor(m)\"\n [style.cssText]=\"ratingIconStyle(m)\"\n ></mat-icon>\n }\n }\n @case (\"icon\") {\n <mat-icon\n [praxisIcon]=\"m.value\"\n [color]=\"\n isThemeColor(m.color) ? m.color : undefined\n \"\n [style.cssText]=\"iconStyle(m.color)\"\n ></mat-icon>\n }\n @case (\"image\") {\n <span class=\"inline-image\"\n ><img [src]=\"m.value\" [alt]=\"m.imageAlt || ''\"\n /></span>\n }\n @case (\"html\") {\n <span [innerHTML]=\"m.value\"></span>\n }\n @case (\"metric\") {\n <praxis-list-metric\n [metric]=\"m\"\n ></praxis-list-metric>\n }\n @case (\"compose\") {\n <praxis-list-compose\n [compose]=\"m\"\n ></praxis-list-compose>\n }\n @case (\"component\") {\n <praxis-list-runtime-component\n [component]=\"m\"\n ></praxis-list-runtime-component>\n }\n @default {\n <span>\n @if (config.templating?.metaPrefixIcon; as mpi2) {\n <mat-icon [praxisIcon]=\"mpi2\"></mat-icon>\n }\n {{ m.value }}</span\n >\n }\n }\n }\n </div>\n }\n }\n @if (trailing(it); as tr) {\n @if (\n (config.templating?.statusPosition || \"inline\") ===\n \"top-right\" &&\n (tr?.type === \"chip\" || tr?.type === \"icon\")\n ) {\n <div class=\"status-overlay\">\n @if (simpleRichContentNodes(tr); as richNodes) {\n <praxis-rich-content [nodes]=\"richNodes\"></praxis-rich-content>\n } @else {\n @if (tr?.type === \"chip\") {\n <mat-chip\n [color]=\"\n isThemeColor(tr.color) ? tr.color : undefined\n \"\n [ngClass]=\"\n (tr.variant || 'filled') === 'outlined'\n ? 'chip-outlined'\n : ''\n \"\n [style.cssText]=\"chipStyle(tr.color, tr.variant)\"\n >{{ tr.value }}</mat-chip\n >\n }\n @if (tr?.type === \"icon\") {\n <mat-icon\n [praxisIcon]=\"tr.value\"\n [color]=\"\n isThemeColor(tr.color) ? tr.color : undefined\n \"\n [style.cssText]=\"iconStyle(tr.color)\"\n ></mat-icon>\n }\n }\n </div>\n } @else {\n <div\n class=\"trailing\"\n [ngClass]=\"tr.class\"\n [style.cssText]=\"tr.style\"\n >\n @if (\n simpleRichContentNodes(tr, {\n imageAlt: config.templating?.trailing?.imageAlt || \"\",\n });\n as richNodes\n ) {\n <praxis-rich-content [nodes]=\"richNodes\"></praxis-rich-content>\n } @else {\n @switch (tr.type) {\n @case (\"chip\") {\n <mat-chip\n [color]=\"\n isThemeColor(tr.color) ? tr.color : undefined\n \"\n [ngClass]=\"\n (tr.variant || 'filled') === 'outlined'\n ? 'chip-outlined'\n : ''\n \"\n [style.cssText]=\"chipStyle(tr.color, tr.variant)\"\n >{{ tr.value }}</mat-chip\n >\n }\n @case (\"icon\") {\n <mat-icon\n [praxisIcon]=\"tr.value\"\n [color]=\"\n isThemeColor(tr.color) ? tr.color : undefined\n \"\n [style.cssText]=\"iconStyle(tr.color)\"\n ></mat-icon>\n }\n @case (\"image\") {\n <div\n class=\"lead-image\"\n [ngClass]=\"tr.class\"\n [style.cssText]=\"tr.style\"\n >\n <img\n [src]=\"tr.value\"\n [alt]=\"\n config.templating?.trailing?.imageAlt || ''\n \"\n />\n @if (tr.badge?.value) {\n <mat-chip\n class=\"lead-badge\"\n [color]=\"\n isThemeColor(tr.badge?.color)\n ? tr.badge?.color\n : undefined\n \"\n [ngClass]=\"\n (tr.badge?.variant || 'filled') ===\n 'outlined'\n ? 'chip-outlined'\n : ''\n \"\n [style.cssText]=\"\n chipStyle(\n tr.badge?.color,\n tr.badge?.variant\n )\n \"\n >{{ tr.badge?.value }}</mat-chip\n >\n }\n </div>\n }\n @case (\"rating\") {\n @for (\n _ of ratingRange(tr);\n track $index;\n let idx = $index\n ) {\n <mat-icon\n [praxisIcon]=\"starIcon(idx, tr.value)\"\n [color]=\"ratingThemeColor(tr)\"\n [style.cssText]=\"ratingIconStyle(tr)\"\n ></mat-icon>\n }\n }\n @case (\"html\") {\n <span [innerHTML]=\"tr.value\"></span>\n }\n @case (\"metric\") {\n <praxis-list-metric\n [metric]=\"tr\"\n ></praxis-list-metric>\n }\n @case (\"compose\") {\n <praxis-list-compose\n [compose]=\"tr\"\n ></praxis-list-compose>\n }\n @case (\"component\") {\n <praxis-list-runtime-component\n [component]=\"tr\"\n ></praxis-list-runtime-component>\n }\n @default {\n <span>{{ tr.value }}</span>\n }\n }\n }\n </div>\n }\n }\n </div>\n </div>\n <div\n class=\"card-actions\"\n (click)=\"$event.stopPropagation()\"\n (keydown.enter)=\"onActionKeydown($event)\"\n (keydown.space)=\"onActionKeydown($event)\"\n >\n @for (\n action of visibleActions(it, \"trailing\");\n let aidx = $index;\n track action?.id ?? $index\n ) {\n @if ((action.kind || \"icon\") === \"icon\") {\n <button\n mat-icon-button\n [color]=\"\n isThemeColor(action.color) ? action.color : undefined\n \"\n (click)=\"onActionClick($event, action.id, it, i)\"\n [attr.aria-label]=\"action.label || action.id\"\n [disabled]=\"isActionLoading(action.id, it, i)\"\n [ngClass]=\"{\n 'action-loading': isActionLoading(action.id, it, i),\n }\"\n >\n @if (isActionLoading(action.id, it, i)) {\n <mat-progress-spinner\n class=\"action-spinner\"\n mode=\"indeterminate\"\n diameter=\"16\"\n strokeWidth=\"3\"\n ></mat-progress-spinner>\n } @else {\n <mat-icon\n [praxisIcon]=\"action.icon\"\n [style.cssText]=\"iconStyle(action.color)\"\n ></mat-icon>\n }\n </button>\n } @else {\n @if (action.buttonVariant === \"stroked\") {\n <button\n mat-stroked-button\n [color]=\"\n isThemeColor(action.color) ? action.color : undefined\n \"\n [style.cssText]=\"buttonStyle(action.color, 'stroked')\"\n (click)=\"onActionClick($event, action.id, it, i)\"\n [attr.aria-label]=\"action.label || action.id\"\n [disabled]=\"isActionLoading(action.id, it, i)\"\n [ngClass]=\"{\n 'action-loading': isActionLoading(action.id, it, i),\n }\"\n >\n @if (isActionLoading(action.id, it, i)) {\n <mat-progress-spinner\n class=\"action-spinner\"\n mode=\"indeterminate\"\n diameter=\"16\"\n strokeWidth=\"3\"\n ></mat-progress-spinner>\n } @else {\n {{ action.label || action.id }}\n }\n </button>\n }\n @if (action.buttonVariant === \"raised\") {\n <button\n mat-raised-button\n [color]=\"\n isThemeColor(action.color) ? action.color : undefined\n \"\n [style.cssText]=\"buttonStyle(action.color, 'raised')\"\n (click)=\"onActionClick($event, action.id, it, i)\"\n [attr.aria-label]=\"action.label || action.id\"\n [disabled]=\"isActionLoading(action.id, it, i)\"\n [ngClass]=\"{\n 'action-loading': isActionLoading(action.id, it, i),\n }\"\n >\n @if (isActionLoading(action.id, it, i)) {\n <mat-progress-spinner\n class=\"action-spinner\"\n mode=\"indeterminate\"\n diameter=\"16\"\n strokeWidth=\"3\"\n ></mat-progress-spinner>\n } @else {\n {{ action.label || action.id }}\n }\n </button>\n }\n @if (\n !action.buttonVariant || action.buttonVariant === \"flat\"\n ) {\n <button\n mat-flat-button\n [color]=\"\n isThemeColor(action.color) ? action.color : undefined\n \"\n [style.cssText]=\"buttonStyle(action.color, 'flat')\"\n (click)=\"onActionClick($event, action.id, it, i)\"\n [attr.aria-label]=\"action.label || action.id\"\n [disabled]=\"isActionLoading(action.id, it, i)\"\n [ngClass]=\"{\n 'action-loading': isActionLoading(action.id, it, i),\n }\"\n >\n @if (isActionLoading(action.id, it, i)) {\n <mat-progress-spinner\n class=\"action-spinner\"\n mode=\"indeterminate\"\n diameter=\"16\"\n strokeWidth=\"3\"\n ></mat-progress-spinner>\n } @else {\n {{ action.label || action.id }}\n }\n </button>\n }\n }\n }\n </div>\n </div>\n }\n </div>\n </ng-template>\n\n <!-- Tiles variant -->\n <ng-template #tilesVariant>\n <div class=\"tiles-grid\">\n @for (it of (items$ | async) ?? []; track $index; let i = $index) {\n <div\n class=\"item-tile\"\n [ngClass]=\"itemRuleClass(it)\"\n [attr.style]=\"itemRuleStyle(it)\"\n role=\"button\"\n tabindex=\"0\"\n [attr.aria-label]=\"itemAriaLabel(it)\"\n (click)=\"onItemClick(it, i)\"\n (keydown.enter)=\"onItemClick(it, i)\"\n (keydown.space)=\"$event.preventDefault(); onItemClick(it, i)\"\n >\n <div class=\"tile-media\">\n @if (leading(it); as lead) {\n @if (\n simpleRichContentNodes(lead, {\n imageAlt: config.templating?.leading?.imageAlt || \"\",\n });\n as richNodes\n ) {\n <praxis-rich-content [nodes]=\"richNodes\"></praxis-rich-content>\n } @else {\n @switch (lead.type) {\n @case (\"image\") {\n <img\n [src]=\"lead.value\"\n [alt]=\"config.templating?.leading?.imageAlt || ''\"\n />\n }\n @case (\"icon\") {\n <mat-icon\n [praxisIcon]=\"lead.value\"\n [ngClass]=\"lead.class\"\n [color]=\"\n isThemeColor(lead.color) ? lead.color : undefined\n \"\n [style.cssText]=\"\n (lead.style ? lead.style + ';' : '') +\n iconStyle(lead.color)\n \"\n ></mat-icon>\n }\n @case (\"text\") {\n <span [ngClass]=\"lead.class\" [style.cssText]=\"lead.style\">{{\n lead.value\n }}</span>\n }\n @case (\"chip\") {\n <mat-chip\n [color]=\"\n isThemeColor(lead.color) ? lead.color : undefined\n \"\n [ngClass]=\"\n (lead.variant || 'filled') === 'outlined'\n ? 'chip-outlined'\n : ''\n \"\n [style.cssText]=\"chipStyle(lead.color, lead.variant)\"\n >{{ lead.value }}</mat-chip\n >\n }\n @case (\"rating\") {\n <span [ngClass]=\"lead.class\" [style.cssText]=\"lead.style\">\n @for (\n _ of ratingRange(lead);\n track $index;\n let idx = $index\n ) {\n <mat-icon\n [praxisIcon]=\"starIcon(idx, lead.value)\"\n [color]=\"ratingThemeColor(lead)\"\n [style.cssText]=\"ratingIconStyle(lead)\"\n ></mat-icon>\n }\n </span>\n }\n @case (\"html\") {\n <span\n [ngClass]=\"lead.class\"\n [style.cssText]=\"lead.style\"\n [innerHTML]=\"lead.value\"\n ></span>\n }\n @case (\"metric\") {\n <praxis-list-metric [metric]=\"lead\"></praxis-list-metric>\n }\n @case (\"compose\") {\n <praxis-list-compose\n [compose]=\"lead\"\n ></praxis-list-compose>\n }\n @case (\"component\") {\n <praxis-list-runtime-component\n [component]=\"lead\"\n ></praxis-list-runtime-component>\n }\n @default {\n <span [ngClass]=\"lead.class\" [style.cssText]=\"lead.style\">{{\n lead.value\n }}</span>\n }\n }\n }\n }\n </div>\n\n @if (trailing(it); as tr) {\n @if (\n (config.templating?.statusPosition || \"inline\") ===\n \"top-right\" &&\n (tr?.type === \"chip\" || tr?.type === \"icon\")\n ) {\n <div class=\"tile-status\">\n @if (simpleRichContentNodes(tr); as richNodes) {\n <praxis-rich-content [nodes]=\"richNodes\"></praxis-rich-content>\n } @else {\n @if (tr?.type === \"chip\") {\n <mat-chip\n [color]=\"isThemeColor(tr.color) ? tr.color : undefined\"\n [ngClass]=\"\n (tr.variant || 'filled') === 'outlined'\n ? 'chip-outlined'\n : ''\n \"\n [style.cssText]=\"chipStyle(tr.color, tr.variant)\"\n >{{ tr.value }}</mat-chip\n >\n }\n @if (tr?.type === \"icon\") {\n <mat-icon\n [praxisIcon]=\"tr.value\"\n [color]=\"isThemeColor(tr.color) ? tr.color : undefined\"\n [style.cssText]=\"iconStyle(tr.color)\"\n ></mat-icon>\n }\n }\n </div>\n }\n }\n\n <div class=\"tile-body\">\n <div\n class=\"primary\"\n [ngClass]=\"primary(it)?.class\"\n [style.cssText]=\"primary(it)?.style\"\n >\n @if (simpleRichContentNodes(primary(it)); as richNodes) {\n <praxis-rich-content [nodes]=\"richNodes\"></praxis-rich-content>\n } @else if (primary(it)?.type === \"metric\") {\n <praxis-list-metric [metric]=\"primary(it)\"></praxis-list-metric>\n } @else if (primary(it)?.type === \"compose\") {\n <praxis-list-compose\n [compose]=\"primary(it)\"\n ></praxis-list-compose>\n } @else if (primary(it)?.type === \"component\") {\n <praxis-list-runtime-component\n [component]=\"primary(it)\"\n ></praxis-list-runtime-component>\n } @else {\n {{ primary(it)?.value }}\n }\n </div>\n @if (layoutLines > 1) {\n <div\n class=\"secondary\"\n [ngClass]=\"secondary(it)?.class\"\n [style.cssText]=\"secondary(it)?.style\"\n >\n @if (simpleRichContentNodes(secondary(it)); as richNodes) {\n <praxis-rich-content [nodes]=\"richNodes\"></praxis-rich-content>\n } @else if (secondary(it)?.type === \"metric\") {\n <praxis-list-metric\n [metric]=\"secondary(it)\"\n ></praxis-list-metric>\n } @else if (secondary(it)?.type === \"compose\") {\n <praxis-list-compose\n [compose]=\"secondary(it)\"\n ></praxis-list-compose>\n } @else if (secondary(it)?.type === \"component\") {\n <praxis-list-runtime-component\n [component]=\"secondary(it)\"\n ></praxis-list-runtime-component>\n } @else {\n {{ secondary(it)?.value }}\n }\n </div>\n }\n\n @if (meta(it); as m) {\n <div\n class=\"tile-meta\"\n [ngClass]=\"m.class\"\n [style.cssText]=\"m.style\"\n >\n @if (config.templating?.metaPrefixIcon; as mpi) {\n <mat-icon [praxisIcon]=\"mpi\"></mat-icon>\n }\n @if (\n simpleRichContentNodes(m, {\n slot: \"meta\",\n imageAlt: m.imageAlt || \"\",\n });\n as richNodes\n ) {\n <praxis-rich-content [nodes]=\"richNodes\"></praxis-rich-content>\n } @else {\n @switch (m.type) {\n @case (\"chip\") {\n <mat-chip\n [color]=\"isThemeColor(m.color) ? m.color : undefined\"\n [ngClass]=\"\n (m.variant || 'filled') === 'outlined'\n ? 'chip-outlined'\n : ''\n \"\n [style.cssText]=\"chipStyle(m.color, m.variant)\"\n >{{ m.value }}</mat-chip\n >\n }\n @case (\"rating\") {\n @for (\n _ of ratingRange(m);\n track $index;\n let idx = $index\n ) {\n <mat-icon\n [praxisIcon]=\"starIcon(idx, m.value)\"\n [color]=\"ratingThemeColor(m)\"\n [style.cssText]=\"ratingIconStyle(m)\"\n ></mat-icon>\n }\n }\n @case (\"icon\") {\n <mat-icon\n [praxisIcon]=\"m.value\"\n [color]=\"isThemeColor(m.color) ? m.color : undefined\"\n [style.cssText]=\"iconStyle(m.color)\"\n ></mat-icon>\n }\n @case (\"image\") {\n <span class=\"inline-image\"\n ><img [src]=\"m.value\" [alt]=\"m.imageAlt || ''\"\n /></span>\n }\n @case (\"html\") {\n <span [innerHTML]=\"m.value\"></span>\n }\n @case (\"metric\") {\n <praxis-list-metric [metric]=\"m\"></praxis-list-metric>\n }\n @case (\"compose\") {\n <praxis-list-compose\n [compose]=\"m\"\n ></praxis-list-compose>\n }\n @case (\"component\") {\n <praxis-list-runtime-component\n [component]=\"m\"\n ></praxis-list-runtime-component>\n }\n @default {\n <span>{{ m.value }}</span>\n }\n }\n }\n </div>\n }\n\n @if (featuresVisible()) {\n <div class=\"tiles-features\">\n @for (\n f of config.templating?.features || [];\n track $index;\n let fi = $index\n ) {\n <span\n class=\"feature\"\n [ngClass]=\"featureSemanticClass(it, f.expr, f.class)\"\n >\n @if (featureRichContentNodes(it, f); as featureNodes) {\n <praxis-rich-content [nodes]=\"featureNodes\"></praxis-rich-content>\n } @else {\n @if (f.icon && featuresMode() !== \"labels-only\") {\n <mat-icon [praxisIcon]=\"f.icon\"></mat-icon>\n }\n @if (featuresMode() !== \"icons-only\") {\n <span [ngClass]=\"f.class\" [style.cssText]=\"f.style\">\n @for (\n line of featureLabelLines(it, f.expr);\n track $index\n ) {\n <span class=\"feature-line\">{{ line }}</span>\n }\n </span>\n }\n }\n @if (\n featureProgressPercent(it, f.expr, f.class);\n as progress\n ) {\n <span class=\"feature-progress\" aria-hidden=\"true\">\n <span\n class=\"feature-progress__value\"\n [style.width.%]=\"progress\"\n ></span>\n </span>\n }\n </span>\n }\n </div>\n }\n\n @if (trailing(it); as tr2) {\n @if (\n !(\n (config.templating?.statusPosition || \"inline\") ===\n \"top-right\" &&\n (tr2?.type === \"chip\" || tr2?.type === \"icon\")\n )\n ) {\n <div\n class=\"tile-trailing\"\n [ngClass]=\"tr2.class\"\n [style.cssText]=\"tr2.style\"\n >\n @if (\n simpleRichContentNodes(tr2, {\n imageAlt: tr2.imageAlt || \"\",\n });\n as richNodes\n ) {\n <praxis-rich-content [nodes]=\"richNodes\"></praxis-rich-content>\n } @else {\n @switch (tr2.type) {\n @case (\"chip\") {\n <mat-chip\n [color]=\"\n isThemeColor(tr2.color) ? tr2.color : undefined\n \"\n [ngClass]=\"\n (tr2.variant || 'filled') === 'outlined'\n ? 'chip-outlined'\n : ''\n \"\n [style.cssText]=\"chipStyle(tr2.color, tr2.variant)\"\n >{{ tr2.value }}</mat-chip\n >\n }\n @case (\"icon\") {\n <mat-icon\n [praxisIcon]=\"tr2.value\"\n [color]=\"\n isThemeColor(tr2.color) ? tr2.color : undefined\n \"\n [style.cssText]=\"iconStyle(tr2.color)\"\n ></mat-icon>\n }\n @case (\"image\") {\n <span class=\"inline-image\"\n ><img [src]=\"tr2.value\" [alt]=\"tr2.imageAlt || ''\"\n /></span>\n }\n @case (\"rating\") {\n @for (\n _ of ratingRange(tr2);\n track $index;\n let idx = $index\n ) {\n <mat-icon\n [praxisIcon]=\"starIcon(idx, tr2.value)\"\n [color]=\"ratingThemeColor(tr2)\"\n [style.cssText]=\"ratingIconStyle(tr2)\"\n ></mat-icon>\n }\n }\n @case (\"html\") {\n <span [innerHTML]=\"tr2.value\"></span>\n }\n @case (\"metric\") {\n <praxis-list-metric\n [metric]=\"tr2\"\n ></praxis-list-metric>\n }\n @case (\"compose\") {\n <praxis-list-compose\n [compose]=\"tr2\"\n ></praxis-list-compose>\n }\n @case (\"component\") {\n <praxis-list-runtime-component\n [component]=\"tr2\"\n ></praxis-list-runtime-component>\n }\n @default {\n <span>{{ tr2.value }}</span>\n }\n }\n }\n </div>\n }\n }\n </div>\n\n @if ((visibleActions(it, \"trailing\") || []).length) {\n <div\n class=\"tile-actions\"\n (click)=\"$event.stopPropagation()\"\n (keydown.enter)=\"onActionKeydown($event)\"\n (keydown.space)=\"onActionKeydown($event)\"\n >\n @for (\n action of visibleActions(it, \"trailing\");\n let aidx = $index;\n track action?.id ?? $index\n ) {\n @if ((action.kind || \"icon\") === \"icon\") {\n <button\n mat-icon-button\n [color]=\"\n isThemeColor(action.color) ? action.color : undefined\n \"\n (click)=\"onActionClick($event, action.id, it, i)\"\n [attr.aria-label]=\"action.label || action.id\"\n [disabled]=\"isActionLoading(action.id, it, i)\"\n [ngClass]=\"{\n 'action-loading': isActionLoading(action.id, it, i),\n }\"\n >\n @if (isActionLoading(action.id, it, i)) {\n <mat-progress-spinner\n class=\"action-spinner\"\n mode=\"indeterminate\"\n diameter=\"16\"\n strokeWidth=\"3\"\n ></mat-progress-spinner>\n } @else {\n <mat-icon\n [praxisIcon]=\"action.icon\"\n [style.cssText]=\"iconStyle(action.color)\"\n ></mat-icon>\n }\n </button>\n } @else {\n @if (action.buttonVariant === \"stroked\") {\n <button\n mat-stroked-button\n [color]=\"\n isThemeColor(action.color) ? action.color : undefined\n \"\n [style.cssText]=\"buttonStyle(action.color, 'stroked')\"\n (click)=\"onActionClick($event, action.id, it, i)\"\n [attr.aria-label]=\"action.label || action.id\"\n [disabled]=\"isActionLoading(action.id, it, i)\"\n [ngClass]=\"{\n 'action-loading': isActionLoading(action.id, it, i),\n }\"\n >\n @if (isActionLoading(action.id, it, i)) {\n <mat-progress-spinner\n class=\"action-spinner\"\n mode=\"indeterminate\"\n diameter=\"16\"\n strokeWidth=\"3\"\n ></mat-progress-spinner>\n } @else {\n {{ action.label || action.id }}\n }\n </button>\n }\n @if (action.buttonVariant === \"raised\") {\n <button\n mat-raised-button\n [color]=\"\n isThemeColor(action.color) ? action.color : undefined\n \"\n [style.cssText]=\"buttonStyle(action.color, 'raised')\"\n (click)=\"onActionClick($event, action.id, it, i)\"\n [attr.aria-label]=\"action.label || action.id\"\n [disabled]=\"isActionLoading(action.id, it, i)\"\n [ngClass]=\"{\n 'action-loading': isActionLoading(action.id, it, i),\n }\"\n >\n @if (isActionLoading(action.id, it, i)) {\n <mat-progress-spinner\n class=\"action-spinner\"\n mode=\"indeterminate\"\n diameter=\"16\"\n strokeWidth=\"3\"\n ></mat-progress-spinner>\n } @else {\n {{ action.label || action.id }}\n }\n </button>\n }\n @if (\n !action.buttonVariant || action.buttonVariant === \"flat\"\n ) {\n <button\n mat-flat-button\n [color]=\"\n isThemeColor(action.color) ? action.color : undefined\n \"\n [style.cssText]=\"buttonStyle(action.color, 'flat')\"\n (click)=\"onActionClick($event, action.id, it, i)\"\n [attr.aria-label]=\"action.label || action.id\"\n [disabled]=\"isActionLoading(action.id, it, i)\"\n [ngClass]=\"{\n 'action-loading': isActionLoading(action.id, it, i),\n }\"\n >\n @if (isActionLoading(action.id, it, i)) {\n <mat-progress-spinner\n class=\"action-spinner\"\n mode=\"indeterminate\"\n diameter=\"16\"\n strokeWidth=\"3\"\n ></mat-progress-spinner>\n } @else {\n {{ action.label || action.id }}\n }\n </button>\n }\n }\n }\n </div>\n }\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 <div class=\"paginator-controls\">\n <button mat-stroked-button color=\"primary\" (click)=\"prevPage()\">\n Anterior\n </button>\n <button mat-stroked-button color=\"primary\" (click)=\"nextPage()\">\n Pr\u00F3ximo\n </button>\n <mat-form-field class=\"paginator-page-size\" appearance=\"outline\">\n <mat-label>Tam. p\u00E1gina</mat-label>\n <mat-select\n (selectionChange)=\"setPageSize($event.value)\"\n [value]=\"config.layout?.pageSize || 10\"\n >\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 (config.ui?.showSort) {\n <mat-form-field class=\"paginator-sort\" appearance=\"outline\">\n <mat-label>Ordenar</mat-label>\n <mat-select (selectionChange)=\"onSortChange($event.value)\">\n @for (op of config.ui?.sortOptions || []; track $index) {\n <mat-option [value]=\"sortOptionValue(op)\">{{\n sortOptionLabel(op)\n }}</mat-option>\n }\n </mat-select>\n </mat-form-field>\n }\n @if (config.ui?.showSearch && config.ui?.searchField) {\n <mat-form-field class=\"paginator-search\" appearance=\"outline\">\n <mat-label>{{\n config.ui?.searchPlaceholder || \"Buscar\"\n }}</mat-label>\n <input\n matInput\n type=\"search\"\n (input)=\"onSearchInput($any($event.target).value)\"\n />\n </mat-form-field>\n }\n </div>\n <div class=\"paginator-meta\">\n @if (config.ui?.showRange ?? true) {\n @if (page$ | async; as ps) {\n @if (total$ | async; as total) {\n @if (items$ | async; as curr) {\n <span class=\"muted\"\n >{{ (total || 0) > 0 ? rangeStart(ps) : 0 }}\u2013{{\n rangeEnd(curr?.length || 0, ps, total || 0)\n }}\n de {{ total || 0 }}</span\n >\n }\n }\n }\n } @else {\n @if (total$ | async; as total2) {\n <span class=\"muted\">Total: {{ total2 }}</span>\n }\n }\n </div>\n </div>\n }\n </ng-template>\n</div>\n", styles: ["@charset \"UTF-8\";:host{display:block}.praxis-list-root{--p-list-radius: var(--md-sys-shape-corner-medium, 16px);--p-list-shadow: var(--md-sys-elevation-level2);--p-list-border: 1px solid var(--md-sys-color-outline-variant);--p-list-blur: 10px;--p-list-surface: var(--md-sys-color-surface-container);--p-list-surface-low: var(--md-sys-color-surface);--p-list-surface-high: var( --md-sys-color-surface-container-high, var(--md-sys-color-surface-container) );--p-list-foreground: var(--md-sys-color-on-surface);--p-list-foreground-muted: var(--md-sys-color-on-surface-variant);--p-list-accent: var(--md-sys-color-primary);--p-list-accent-weak: var(--md-sys-color-primary-container);--p-list-item-surface: var( --md-sys-color-surface-container-low, var(--md-sys-color-surface) );--p-list-item-border: 1px solid var(--md-sys-color-outline-variant);--p-list-item-hover-surface: var(--md-sys-color-surface-container-low);--p-list-item-active-surface: var(--md-sys-color-surface-container);--p-list-item-selected-surface: var(--md-sys-color-surface-container);--p-list-grad-from: var(--md-sys-color-primary-container);--p-list-grad-to: var(--md-sys-color-tertiary-container);--p-list-grad-angle: 135deg;--p-list-grad-foreground: var(--md-sys-color-on-primary);--p-list-grad-foreground-muted: var(--md-sys-color-on-primary);--p-list-leading-width: 36px;--p-list-trailing-min-width: 140px;--p-list-item-gap: 10px;--p-list-item-padding-x: 14px;--p-list-item-padding-y: 10px;--p-list-item-stack-gap: 0px;--p-list-meta-size: .875rem;--p-list-meta-weight: 500;--p-list-chip-height: 22px;--p-list-chip-font-size: 12px;--p-list-trailing-padding-right: 8px;--p-list-tile-minW: 240px;--p-list-tile-gap: 12px;--p-list-tile-padding: 12px;--p-list-tile-radius: 12px;--p-list-tile-media-radius: 12px;--p-list-tile-media-ratio: 1 / 1;--p-list-tile-hover-overlay: .04;--p-list-tile-press-overlay: .08;--p-list-tile-press-scale: .99}.list-assistant{display:flex;justify-content:flex-end;gap:8px;padding:4px 4px 8px}.action-loading{opacity:.65}.action-spinner{width:16px;height:16px;display:inline-flex;align-items:center;justify-content:center}.action-loading .mat-mdc-button-touch-target,.action-loading .mdc-button__label{opacity:.7}.skin-elevated,.skin-outline,.skin-flat,.skin-neumorphism{--p-list-item-surface: var( --mdc-elevated-card-container-color, var(--p-list-surface) );--p-list-item-border: var(--p-list-border)}.skin-elevated .item-card,.skin-outline .item-card,.skin-flat .item-card,.skin-neumorphism .item-card{background:var(--mdc-elevated-card-container-color, var(--p-list-surface));border-radius:var(--p-list-radius);box-shadow:var(--p-list-shadow);border:var(--p-list-border)}.skin-elevated .item-tile,.skin-outline .item-tile,.skin-flat .item-tile,.skin-neumorphism .item-tile{background:var(--mdc-elevated-card-container-color, var(--p-list-surface));box-shadow:var(--p-list-shadow);border:var(--p-list-border)}.skin-elevated .mat-mdc-list-item .list-item-content,.skin-outline .mat-mdc-list-item .list-item-content,.skin-flat .mat-mdc-list-item .list-item-content,.skin-neumorphism .mat-mdc-list-item .list-item-content{background:var(--mdc-elevated-card-container-color, var(--p-list-surface));border-radius:calc(var(--p-list-radius) * .75);box-shadow:var(--p-list-shadow);border:var(--p-list-item-border);color:var(--p-list-foreground)}.skin-outline{--p-list-shadow: none;--p-list-border: 1px solid var(--md-sys-color-outline)}.skin-flat{--p-list-shadow: none;--p-list-border: 1px solid var(--md-sys-color-outline-variant)}.skin-neumorphism{--p-list-shadow: var(--md-sys-elevation-level2);--p-list-border: 1px solid var(--md-sys-color-outline-variant);--p-list-radius: 1.25rem}.skin-pill-soft .item-card,.skin-pill-soft .item-tile{background:var(--mdc-elevated-card-container-color, var(--p-list-surface));border-radius:calc(var(--p-list-radius) * 1.3);box-shadow:var(--md-sys-elevation-level1);border:var(--p-list-border)}.skin-pill-soft .mat-mdc-list-item .list-item-content{background:var(--mdc-elevated-card-container-color, var(--p-list-surface));border-radius:calc(var(--p-list-radius) * 1.3);box-shadow:var(--md-sys-elevation-level1);border:var(--p-list-border);color:var(--p-list-foreground)}.skin-gradient-tile{--p-list-foreground: var(--p-list-grad-foreground);--p-list-foreground-muted: var(--p-list-grad-foreground-muted);--p-list-item-hover-surface: linear-gradient( var(--p-list-grad-angle), var(--p-list-grad-from), var(--p-list-grad-to) );--p-list-item-active-surface: linear-gradient( var(--p-list-grad-angle), var(--p-list-grad-from), var(--p-list-grad-to) );--p-list-item-selected-surface: linear-gradient( var(--p-list-grad-angle), var(--p-list-grad-from), var(--p-list-grad-to) )}.skin-gradient-tile .item-card,.skin-gradient-tile .item-tile,.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:var(--p-list-foreground)}.skin-glass .item-card,.skin-glass .item-tile{background:var(--md-sys-color-surface-container-low);border-radius:var(--p-list-radius);border:1px solid var(--md-sys-color-outline-variant);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:var(--md-sys-color-surface-container-low);border-radius:var(--p-list-radius);border:1px solid var(--md-sys-color-outline-variant);backdrop-filter:blur(var(--p-list-blur));-webkit-backdrop-filter:blur(var(--p-list-blur));color:var(--p-list-foreground)}.density-compact .mat-mdc-list-item,.density-compact .item-card{--p-list-item-padding-y: 6px;--p-list-item-padding-x: 10px;--p-list-item-gap: 8px}.density-comfortable .mat-mdc-list-item,.density-comfortable .item-card{--p-list-item-padding-y: 8px;--p-list-item-padding-x: 12px;--p-list-item-gap: 10px}.praxis-list-root.lines-3 .mat-mdc-list-item,.praxis-list-root.lines-3 .mat-mdc-list-option{min-height:68px}.density-compact{--p-list-tile-gap: 10px;--p-list-tile-padding: 10px;--p-list-tile-minW: 188px}.density-comfortable{--p-list-tile-gap: 12px;--p-list-tile-padding: 12px}.item-spacing-none{--p-list-item-stack-gap: 0px}.item-spacing-tight{--p-list-item-stack-gap: 4px;--p-list-tile-gap: 10px}.item-spacing-default{--p-list-item-stack-gap: 6px;--p-list-tile-gap: 12px}.item-spacing-relaxed{--p-list-item-stack-gap: 14px;--p-list-tile-gap: 20px}.list-item-content{display:grid;grid-template-columns:var(--p-list-leading-width) minmax(0,1fr) minmax(var(--p-list-trailing-min-width),max-content);align-items:center;gap:var(--p-list-item-gap);padding:var(--p-list-item-padding-y) var(--p-list-item-padding-x);width:100%;min-width:0;border-radius:calc(var(--p-list-radius) * .75);overflow:visible}.list-item-content--row-layout{--p-list-row-template-columns: var(--p-list-leading-width) minmax(0, 1fr) minmax(var(--p-list-trailing-min-width), max-content);--p-list-row-gap: var(--p-list-item-gap);--p-list-row-align-items: center;grid-template-columns:var(--p-list-row-template-columns);gap:var(--p-list-row-gap);align-items:var(--p-list-row-align-items)}.list-item-content--row-layout[role=button]{cursor:pointer}.list-item-content--row-layout[role=button]:focus-visible{outline:2px solid var(--md-sys-color-primary);outline-offset:2px}.list-row-slot{min-width:0;display:flex;align-items:center;gap:8px}.list-row-slot--leading{justify-content:center}.list-row-slot--primary,.list-row-slot--secondary{min-width:0}.list-row-slot--meta{color:var(--p-list-foreground);font-variant-numeric:tabular-nums}.list-row-slot--trailing{flex-wrap:wrap;justify-content:flex-end}.list-row-slot .primary,.list-row-slot .secondary,.list-row-slot .meta,.list-row-slot .trailing{min-width:0}.list-item-main-action{grid-column:1/3;display:grid;grid-template-columns:var(--p-list-leading-width) minmax(0,1fr);align-items:center;gap:var(--p-list-item-gap);min-width:0;padding:0;border:0;background:transparent;color:inherit;text-align:start;font:inherit;cursor:pointer}.list-item-main-action:focus-visible{outline:2px solid var(--md-sys-color-primary);outline-offset:2px;border-radius:12px}.list-item-leading{display:flex;align-items:center;justify-content:center;min-height:100%}.leading-placeholder{width:24px;height:24px;display:inline-block}.list-item-text{min-width:0;display:grid;align-content:center;gap:2px}.list-item-trailing{min-width:0;display:flex;flex-direction:column;align-items:flex-end;justify-content:center;gap:4px;text-align:end;padding-right:var(--p-list-trailing-padding-right)}.list-item-content--row-layout .list-item-actions{justify-content:flex-end}.list-item-actions{display:flex;align-items:center;justify-content:flex-end;gap:4px;flex-wrap:wrap}.expand-toggle{color:var(--p-list-foreground-muted)}.mat-mdc-list-item .list-item-content{background:var(--p-list-item-surface);border:var(--p-list-item-border);transition:background .15s ease,box-shadow .15s ease,transform .15s ease}.mat-mdc-list-item,.mat-mdc-list-option{height:auto;align-items:stretch;overflow:visible}.mat-mdc-list-item.mdc-list-item--with-one-line,.mat-mdc-list-item.mdc-list-item--with-two-lines,.mat-mdc-list-item.mdc-list-item--with-three-lines,.mat-mdc-list-item-single-line,.mat-mdc-list-item-two-line,.mat-mdc-list-item-three-line,.mat-mdc-list-option.mdc-list-item--with-one-line,.mat-mdc-list-option.mdc-list-item--with-two-lines,.mat-mdc-list-option.mdc-list-item--with-three-lines{height:auto!important}.mdc-list-item{overflow:visible}.density-compact .mat-mdc-list-item,.density-compact .mat-mdc-list-option{min-height:40px}.density-comfortable .mat-mdc-list-item,.density-comfortable .mat-mdc-list-option{min-height:46px}.praxis-list-root:not(.density-compact):not(.density-comfortable) .mat-mdc-list-item,.praxis-list-root:not(.density-compact):not(.density-comfortable) .mat-mdc-list-option{min-height:48px}.mat-mdc-list-item .mdc-list-item__content,.mat-mdc-list-option .mdc-list-item__content,.mat-mdc-list-item .mdc-list-item__primary-text,.mat-mdc-list-option .mdc-list-item__primary-text{display:block!important;width:100%!important;height:auto!important;padding:0!important;margin:0!important;overflow:visible!important;box-sizing:border-box}.mat-mdc-list-item,.mat-mdc-list-option{padding:0!important;box-sizing:border-box}.praxis-list-root mat-list>mat-list-item:not(:last-child),.praxis-list-root mat-selection-list>mat-list-option:not(:last-child){margin-bottom:var(--p-list-item-stack-gap)}.mat-mdc-list-item:hover .list-item-content,.mat-mdc-list-option:hover .list-item-content{background:var(--p-list-item-hover-surface)}.mat-mdc-list-item:active .list-item-content,.mat-mdc-list-option:active .list-item-content{background:var(--p-list-item-active-surface)}.mat-mdc-list-option.mdc-list-item--selected .list-item-content{background:var(--p-list-item-selected-surface);border-color:var(--md-sys-color-outline-variant)}.mat-mdc-list-option.cdk-keyboard-focused .list-item-content,.mat-mdc-list-option.cdk-focused .list-item-content{outline:2px solid var(--md-sys-color-primary);outline-offset:2px}.mat-mdc-list-item:focus-visible .list-item-content{outline:2px solid var(--md-sys-color-primary);outline-offset:2px}.executive-inline-skin{--p-list-leading-width: 56px;--p-list-trailing-min-width: 232px;--p-list-item-padding-x: 14px;--p-list-item-padding-y: 8px;--p-list-item-gap: 10px;--p-list-surface: #f8fafb;--p-list-surface-low: #ffffff;--p-list-item-surface: #ffffff;--p-list-item-hover-surface: #f7fafc;--p-list-item-active-surface: #eef4f8;--p-list-item-selected-surface: #eef4f8;--p-list-foreground: #17324d;--p-list-foreground-muted: #72849a}.executive-inline-skin .list-item-content--row-layout.exec-row-layout{min-height:72px;padding:12px 20px;background:linear-gradient(180deg,#fff,#fbfcfd)!important;border:1px solid #dce5ec!important;border-radius:18px;box-shadow:0 1px 2px #0f223a08,0 4px 14px #0f223a08!important;color:#17324d!important}.executive-inline-skin .mat-mdc-list-item:hover .list-item-content--row-layout.exec-row-layout{background:linear-gradient(180deg,#fff,#f7fafc)!important}.executive-inline-skin .list-item-content--row-layout.exec-row-layout+.item-expansion{margin-left:10px;margin-right:10px}.executive-inline-skin .list-item-content--row-layout.exec-row-layout .list-row-slot{min-height:34px}.executive-inline-skin .list-row-slot--leading{justify-content:center}.executive-inline-skin .list-row-slot--identity{align-items:center;padding-right:4px}.executive-inline-skin .list-row-slot--balance,.executive-inline-skin .list-row-slot--limit,.executive-inline-skin .list-row-slot--risk,.executive-inline-skin .list-row-slot--alerts{justify-content:center;padding-inline:2px}.executive-inline-skin .list-row-slot--owner{justify-content:flex-start;padding-left:0}.executive-inline-skin .list-row-slot--actions{justify-content:flex-end;padding-left:0}.executive-inline-skin .list-row-slot--expand{justify-content:center}.executive-inline-skin .docs-expansion-leading{width:44px;height:44px;display:inline-flex;align-items:center;justify-content:center;border-radius:15px;background:linear-gradient(180deg,#edf4f9,#e6eef5);color:#1b5f86;font-size:1rem;font-weight:800;letter-spacing:.02em;box-shadow:0 1px 3px #1b5f861f;border:1px solid #dbe7f0}.executive-inline-skin .exec-balance-metric,.executive-inline-skin .exec-limit-metric,.executive-inline-skin .exec-risk-metric{min-width:0}.executive-inline-skin .exec-balance-metric .p-list-metric,.executive-inline-skin .exec-limit-metric .p-list-metric,.executive-inline-skin .exec-risk-metric .p-list-metric{gap:5px}.executive-inline-skin .exec-balance-metric .p-list-metric__label,.executive-inline-skin .exec-limit-metric .p-list-metric__label,.executive-inline-skin .exec-risk-metric .p-list-metric__label{font-size:.62rem;font-weight:700;letter-spacing:.08em;text-transform:uppercase;color:#8090a1}.executive-inline-skin .exec-balance-metric .p-list-metric__value,.executive-inline-skin .exec-limit-metric .p-list-metric__value{font-size:.96rem;font-weight:800;letter-spacing:-.02em;color:#0d1f34;line-height:1.05}.executive-inline-skin .exec-limit-metric .p-list-metric__caption{font-size:.66rem;font-weight:700;color:#8090a1}.executive-inline-skin .exec-limit-metric .p-list-metric__progress{width:68px;justify-self:center;height:3px}.executive-inline-skin .exec-risk-metric{min-width:84px}.executive-inline-skin .exec-risk-metric .p-list-metric{justify-items:center}.executive-inline-skin .exec-risk-metric .p-list-metric__main{gap:6px}.executive-inline-skin .exec-risk-metric .p-list-metric__value{font-size:1.02rem;font-weight:800;letter-spacing:-.024em;line-height:1}.executive-inline-skin .exec-risk-metric .p-list-metric__progress{width:56px;justify-self:center;height:3px}.executive-inline-skin .exec-risk-metric .p-list-metric__caption{font-size:.7rem;font-weight:700;line-height:1.1}.executive-inline-skin .exec-risk-metric .p-list-metric__caption--below-progress{justify-self:center;margin-top:-1px}.executive-inline-skin .exec-risk-metric .p-list-metric__icon mat-icon{width:15px;height:15px;font-size:15px}.executive-inline-skin .list-item-actions{gap:6px;flex-wrap:nowrap}.executive-inline-skin .list-row-slot--actions .list-item-actions{justify-content:flex-end}.executive-inline-skin .list-item-actions button,.executive-inline-skin .expand-toggle{width:30px;height:30px;min-width:30px;border-radius:12px;color:#6d7f93!important}.executive-inline-skin .list-item-actions button mat-icon,.executive-inline-skin .expand-toggle mat-icon{width:18px;height:18px;font-size:18px}.executive-inline-skin .item-expansion{position:relative;margin-top:-10px;padding:22px 26px;background:linear-gradient(180deg,#fcfdfe,#f5f8fb);border-color:#e4eaf0;border-radius:0 0 22px 22px;box-shadow:inset 0 1px #ffffffdb}.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}.inline-image{position:relative;width:20px;height:20px;border-radius:4px;overflow:hidden;display:inline-block;vertical-align:middle}.inline-image img{width:100%;height:100%;object-fit:cover;display:block}.inline-image .inline-badge{position:absolute;left:2px;bottom:2px}.model-media .lead-image{width:136px;height:96px;border-radius:16px}.model-media .list-item-content{gap:16px}.model-media .item-card{--p-list-leading-width: 136px}.model-hotel .lead-image{width:160px;height:110px;border-radius:18px}.model-hotel .item-card{--p-list-leading-width: 160px}.primary,.secondary{display:-webkit-box;-webkit-box-orient:vertical;overflow:hidden;text-overflow:ellipsis}.primary{-webkit-line-clamp:1;font-weight:600;color:var(--p-list-foreground)}.secondary{-webkit-line-clamp:1;color:var(--p-list-foreground-muted)}.lines-3 .tertiary{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.item-tile .primary{-webkit-line-clamp:2;font-size:.95rem;line-height:1.25rem}.item-tile .secondary{-webkit-line-clamp:2;font-size:.8rem;line-height:1.1rem}.tertiary{color:var(--p-list-foreground-muted)}.features{display:flex;flex-wrap:wrap;gap:12px;margin-top:6px;color:inherit}.feature{display:inline-flex;align-items:center;gap:6px}.feature-line{display:block}.feature-progress{display:block;width:88px;height:4px;margin-top:6px;border-radius:999px;background:#dbe5eb;overflow:hidden}.feature-progress__value{display:block;height:100%;border-radius:inherit;background:#2f9b69}.meta{color:var(--p-list-foreground);font-size:var(--p-list-meta-size);font-weight:var(--p-list-meta-weight);font-variant-numeric:tabular-nums;white-space:nowrap}.trailing{color:var(--p-list-foreground-muted);margin-left:0;white-space:nowrap}.section-header{font-size:.85rem;color:var(--p-list-foreground-muted);padding:8px 12px}.praxis-list-root mat-list,.praxis-list-root mat-selection-list{display:block;padding-bottom:12px}.praxis-list-root .mat-divider{margin-left:var(--p-list-item-padding-x);margin-right:var(--p-list-item-padding-x)}.item-expansion{margin:0 var(--p-list-item-padding-x) var(--p-list-item-stack-gap);padding:14px 16px;background:color-mix(in srgb,var(--p-list-surface) 88%,white 12%);border:1px solid var(--md-sys-color-outline-variant);border-radius:calc(var(--p-list-radius) * .75)}.item-expansion-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(220px,1fr));gap:16px}.expansion-section{min-width:0;display:grid;gap:10px;align-content:start}.expansion-section-title{font-size:.78rem;font-weight:700;letter-spacing:.04em;text-transform:uppercase;color:var(--p-list-foreground-muted)}.expansion-info-list,.expansion-timeline,.expansion-key-value{display:grid;gap:10px}.expansion-info-item,.expansion-timeline-item{display:grid;gap:4px;padding:10px 12px;border-radius:14px;background:var(--p-list-item-surface);border:1px solid color-mix(in srgb,var(--md-sys-color-outline-variant) 72%,transparent 28%)}.expansion-info-title,.expansion-timeline-title{font-size:.92rem;font-weight:600;color:var(--p-list-foreground)}.expansion-info-value,.expansion-timeline-meta,.expansion-timeline-description,.expansion-empty{font-size:.82rem;line-height:1.45;color:var(--p-list-foreground-muted)}.expansion-chip-list{display:flex;flex-wrap:wrap;gap:8px}.expansion-chip{background:var(--p-list-item-surface);border:1px solid var(--md-sys-color-outline-variant)}.expansion-key-value{margin:0}.expansion-key-value-row{display:grid;gap:4px;padding:10px 12px;border-radius:14px;background:var(--p-list-item-surface);border:1px solid color-mix(in srgb,var(--md-sys-color-outline-variant) 72%,transparent 28%)}.expansion-key-value-row dt,.expansion-key-value-row dd{margin:0}.expansion-key-value-row dt{font-size:.78rem;font-weight:600;color:var(--p-list-foreground-muted)}.expansion-key-value-row dd{font-size:.9rem;color:var(--p-list-foreground)}.cards-grid,.tiles-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(var(--p-list-tile-minW),1fr));gap:var(--p-list-tile-gap)}.item-tile{position:relative;display:flex;flex-direction:column;gap:10px;padding:var(--p-list-tile-padding);border-radius:var(--p-list-tile-radius);background:var(--p-list-surface);border:var(--p-list-border);color:var(--p-list-foreground);cursor:pointer;min-height:160px;transition:box-shadow .16s ease-out,border-color .16s ease-out,transform .12s ease-out,background .16s ease-out}.item-tile:hover{box-shadow:var(--md-sys-elevation-level2);border-color:var(--md-sys-color-outline-variant);background:var(--p-list-item-hover-surface)}.item-tile:active{transform:scale(var(--p-list-tile-press-scale));background:var(--p-list-item-active-surface)}.item-tile:focus-visible{outline:2px solid var(--md-sys-color-primary);outline-offset:2px}.tile-media{width:100%;aspect-ratio:var(--p-list-tile-media-ratio);border-radius:var(--p-list-tile-media-radius);background:var(--p-list-item-surface);border:1px solid var(--md-sys-color-outline-variant);display:grid;place-items:center;overflow:hidden}.tile-media img{width:100%;height:100%;object-fit:cover;display:block}.tile-media mat-icon{font-size:28px;height:28px;width:28px;color:var(--p-list-foreground-muted)}.tile-body{display:grid;gap:6px;min-width:0}.tile-meta{display:inline-flex;align-items:center;gap:6px;font-size:.75rem;color:var(--p-list-foreground-muted);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.tile-trailing{font-size:.75rem;color:var(--p-list-foreground-muted);white-space:nowrap}.tiles-features{display:flex;flex-wrap:wrap;gap:8px;color:inherit}.tile-status{position:absolute;top:10px;right:10px}.tile-actions{position:absolute;top:8px;left:8px;display:flex;gap:4px;opacity:0;pointer-events:none;transform:translateY(-2px);transition:opacity .16s ease-out,transform .16s ease-out}.item-tile:hover .tile-actions,.item-tile:focus-visible .tile-actions,.item-tile:focus-within .tile-actions{opacity:1;pointer-events:auto;transform:translateY(0)}@media(hover:none){.tile-actions{opacity:1;pointer-events:auto;transform:none}}@media(max-width:600px){.tiles-grid{grid-template-columns:repeat(auto-fit,minmax(200px,1fr))}}@media(prefers-reduced-motion:reduce){.item-tile,.tile-actions{transition:none}.item-tile:active{transform:none}.item-card{transition:none}.item-card:active{transform:none}}.item-card{padding:var(--p-list-tile-padding);display:flex;flex-direction:column;min-height:160px;position:relative;cursor:pointer;background:var(--p-list-surface);border:var(--p-list-border);border-radius:var(--p-list-tile-radius);box-shadow:var(--p-list-shadow);transition:box-shadow .16s ease-out,border-color .16s ease-out,transform .12s ease-out,background .16s ease-out;--p-list-leading-width: 96px;--p-list-trailing-min-width: 0px}.item-card .list-item-trailing{min-width:var(--p-list-trailing-min-width)}.item-card:hover{box-shadow:var(--md-sys-elevation-level3);border-color:var(--md-sys-color-outline-variant);background:var(--p-list-item-hover-surface)}.item-card:active{transform:scale(var(--p-list-tile-press-scale));background:var(--p-list-item-active-surface)}.item-card:focus-visible{outline:2px solid var(--md-sys-color-primary);outline-offset:2px}.card-actions{display:flex;align-items:center;justify-content:flex-end;gap:4px;padding:6px 8px 4px;border-top:1px solid var(--md-sys-color-outline-variant);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:var(--md-sys-color-primary-container);color:var(--md-sys-color-on-primary-container)}.mat-mdc-chip{--mdc-chip-container-height: var(--p-list-chip-height);font-size:var(--p-list-chip-font-size)}.meta .mat-icon{font-size:18px;height:18px;width:18px}.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:linear-gradient(to right,var(--md-sys-color-surface-container-low) 8%,var(--md-sys-color-surface-container) 18%,var(--md-sys-color-surface-container-low) 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;flex-wrap:wrap;gap:8px;margin-top:14px;padding:14px 4px 8px;border-top:1px solid var(--md-sys-color-outline-variant);position:relative;z-index:1;background:var(--p-list-surface-low);border-radius:calc(var(--p-list-radius) * .75)}.paginator-controls{display:flex;align-items:center;gap:8px;flex-wrap:wrap}.paginator-meta{display:flex;align-items:center;gap:8px;margin-left:auto}.paginator-page-size{width:120px}.paginator-sort{width:180px}.paginator-search{min-width:220px}.muted{color:var(--p-list-foreground-muted)}@media(max-width:720px){.list-item-content{grid-template-columns:var(--p-list-leading-width) minmax(0,1fr)}.list-item-trailing{grid-column:1/-1;padding-right:0;align-items:flex-start;text-align:start}.item-expansion{margin-left:0;margin-right:0}.paginator{align-items:stretch}.paginator-controls{width:100%}.paginator-meta{width:100%;margin-left:0;justify-content:flex-start}.paginator-page-size,.paginator-sort,.paginator-search{width:100%;min-width:0}}\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: i5.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: i6.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: i6.MatMiniFabButton, selector: "button[mat-mini-fab], a[mat-mini-fab], button[matMiniFab], a[matMiniFab]", exportAs: ["matButton", "matAnchor"] }, { kind: "component", type: i6.MatIconButton, selector: "button[mat-icon-button], a[mat-icon-button], button[matIconButton], a[matIconButton]", exportAs: ["matButton", "matAnchor"] }, { kind: "ngmodule", type: MatProgressSpinnerModule }, { kind: "component", type: i7.MatProgressSpinner, selector: "mat-progress-spinner, mat-spinner", inputs: ["color", "mode", "value", "diameter", "strokeWidth"], exportAs: ["matProgressSpinner"] }, { kind: "ngmodule", type: MatFormFieldModule }, { kind: "component", type: i2$1.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i2$1.MatLabel, selector: "mat-label" }, { kind: "ngmodule", type: MatSelectModule }, { kind: "component", type: i4$1.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: i4$1.MatOption, selector: "mat-option", inputs: ["value", "id", "disabled"], outputs: ["onSelectionChange"], exportAs: ["matOption"] }, { kind: "ngmodule", type: MatInputModule }, { kind: "directive", type: i3$1.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly", "disabledInteractive"], exportAs: ["matInput"] }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i12.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "component", type: PraxisAiAssistantComponent, selector: "praxis-ai-assistant", inputs: ["adapter", "riskPolicy", "allowManualPatchEdit"] }, { kind: "component", type: ExecutiveBadgeComponent, selector: "praxis-executive-badge", inputs: ["ariaLabel", "label", "variant"] }, { kind: "component", type: ExecutiveAlertsComponent, selector: "praxis-executive-alerts", inputs: ["alerts"] }, { kind: "component", type: ExecutiveOwnerComponent, selector: "praxis-executive-owner", inputs: ["name"] }, { kind: "component", type: PraxisRichContent, selector: "praxis-rich-content", inputs: ["document", "nodes", "context", "hostCapabilities", "rootClassName"] }, { kind: "component", type: PraxisListMetricComponent, selector: "praxis-list-metric", inputs: ["metric"] }, { kind: "component", type: PraxisListComposeComponent, selector: "praxis-list-compose", inputs: ["compose"] }, { kind: "component", type: PraxisListRuntimeComponentComponent, selector: "praxis-list-runtime-component", inputs: ["component"] }, { kind: "pipe", type: i1.AsyncPipe, name: "async" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
9479
9934
  }
9480
9935
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: PraxisList, decorators: [{
9481
9936
  type: Component,
@@ -9497,10 +9952,11 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImpo
9497
9952
  ExecutiveBadgeComponent,
9498
9953
  ExecutiveAlertsComponent,
9499
9954
  ExecutiveOwnerComponent,
9955
+ PraxisRichContent,
9500
9956
  PraxisListMetricComponent,
9501
9957
  PraxisListComposeComponent,
9502
9958
  PraxisListRuntimeComponentComponent,
9503
- ], changeDetection: ChangeDetectionStrategy.OnPush, providers: [GenericCrudService, ListDataService, providePraxisListI18n()], template: "<div\n class=\"praxis-list-root\"\n [ngClass]=\"skinClasses\"\n [attr.data-skin-scope]=\"skinScopeId\"\n [attr.aria-label]=\"config.a11y?.ariaLabel || null\"\n [attr.aria-labelledby]=\"config.a11y?.ariaLabelledBy || null\"\n>\n @if (inlineCss) {\n <style [attr.nonce]=\"cspNonce || null\" [textContent]=\"inlineCss\"></style>\n }\n\n @if (enableCustomization) {\n <div class=\"list-assistant\">\n <button\n mat-mini-fab\n type=\"button\"\n color=\"primary\"\n (click)=\"openConfigEditor()\"\n [matTooltip]=\"configEditorLabel()\"\n [attr.aria-label]=\"configEditorLabel()\"\n data-testid=\"praxis-list-open-config-editor\"\n >\n <mat-icon [praxisIcon]=\"'edit'\"></mat-icon>\n </button>\n <praxis-ai-assistant [adapter]=\"aiAdapter\"></praxis-ai-assistant>\n </div>\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=\"list-item-leading\">\n <div class=\"skeleton skeleton-avatar\"></div>\n </div>\n <div class=\"list-item-text\">\n <div class=\"skeleton skeleton-line w-60\"></div>\n @if (layoutLines > 1) {\n <div class=\"skeleton skeleton-line w-40\"></div>\n }\n </div>\n <div class=\"list-item-trailing\">\n <div class=\"skeleton skeleton-chip\"></div>\n </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=\"list-item-leading\">\n <div class=\"skeleton skeleton-avatar\"></div>\n </div>\n <div class=\"list-item-text\">\n <div class=\"skeleton skeleton-line w-60\"></div>\n @if (layoutLines > 1) {\n <div class=\"skeleton skeleton-line w-40\"></div>\n }\n </div>\n <div class=\"list-item-trailing\">\n <div class=\"skeleton skeleton-chip\"></div>\n </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 @if (emptyStateTemplate(); as empty) {\n @switch (empty.type) {\n @case (\"icon\") {\n <mat-icon\n [praxisIcon]=\"empty.value\"\n [ngClass]=\"empty.class\"\n [color]=\"isThemeColor(empty.color) ? empty.color : undefined\"\n [style.cssText]=\"\n (empty.style ? empty.style + ';' : '') +\n iconStyle(empty.color)\n \"\n ></mat-icon>\n }\n @case (\"image\") {\n <span\n class=\"inline-image\"\n [ngClass]=\"empty.class\"\n [style.cssText]=\"empty.style\"\n >\n <img\n [src]=\"empty.value\"\n [alt]=\"config.templating?.emptyState?.imageAlt || ''\"\n />\n @if (empty.badge?.value) {\n <mat-chip\n class=\"inline-badge\"\n [color]=\"\n isThemeColor(empty.badge?.color)\n ? empty.badge?.color\n : undefined\n \"\n [ngClass]=\"\n (empty.badge?.variant || 'filled') === 'outlined'\n ? 'chip-outlined'\n : ''\n \"\n [style.cssText]=\"\n chipStyle(empty.badge?.color, empty.badge?.variant)\n \"\n >{{ empty.badge?.value }}</mat-chip\n >\n }\n </span>\n }\n @case (\"chip\") {\n <mat-chip\n [color]=\"isThemeColor(empty.color) ? empty.color : undefined\"\n [ngClass]=\"[\n empty.class || '',\n (empty.variant || 'filled') === 'outlined'\n ? 'chip-outlined'\n : '',\n ]\"\n [style.cssText]=\"\n chipStyle(empty.color, empty.variant) +\n (empty.style ? ';' + empty.style : '')\n \"\n >{{ empty.value }}</mat-chip\n >\n }\n @case (\"rating\") {\n <span [ngClass]=\"empty.class\" [style.cssText]=\"empty.style\">\n @for (\n _ of ratingRange(empty);\n track $index;\n let idx = $index\n ) {\n <mat-icon\n [praxisIcon]=\"starIcon(idx, empty.value)\"\n [color]=\"ratingThemeColor(empty)\"\n [style.cssText]=\"ratingIconStyle(empty)\"\n ></mat-icon>\n }\n </span>\n }\n @case (\"html\") {\n <span\n [ngClass]=\"empty.class\"\n [style.cssText]=\"empty.style\"\n [innerHTML]=\"empty.value\"\n ></span>\n }\n @case (\"metric\") {\n <praxis-list-metric [metric]=\"empty\"></praxis-list-metric>\n }\n @case (\"compose\") {\n <praxis-list-compose [compose]=\"empty\"></praxis-list-compose>\n }\n @case (\"component\") {\n <praxis-list-runtime-component\n [component]=\"empty\"\n ></praxis-list-runtime-component>\n }\n @default {\n <span [ngClass]=\"empty.class\" [style.cssText]=\"empty.style\">{{\n empty.value\n }}</span>\n }\n }\n }\n </div>\n }\n }\n\n <ng-template\n #rowLayoutNode\n let-node\n let-slot=\"slot\"\n let-imageAlt=\"imageAlt\"\n >\n @switch (node?.type) {\n @case (\"icon\") {\n <mat-icon\n [praxisIcon]=\"node?.value\"\n [ngClass]=\"node?.class\"\n [color]=\"isThemeColor(node?.color) ? node?.color : undefined\"\n [style.cssText]=\"\n ((node?.style || '') ? node.style + ';' : '') +\n iconStyle(node?.color)\n \"\n ></mat-icon>\n }\n @case (\"image\") {\n <span\n class=\"inline-image\"\n [ngClass]=\"node?.class\"\n [style.cssText]=\"node?.style\"\n >\n <img [src]=\"node?.value\" [alt]=\"node?.imageAlt || imageAlt || ''\" />\n @if (node?.badge?.value) {\n <mat-chip\n class=\"inline-badge\"\n [color]=\"\n isThemeColor(node?.badge?.color)\n ? node?.badge?.color\n : undefined\n \"\n [ngClass]=\"\n (node?.badge?.variant || 'filled') === 'outlined'\n ? 'chip-outlined'\n : ''\n \"\n [style.cssText]=\"\n chipStyle(node?.badge?.color, node?.badge?.variant)\n \"\n >\n {{ node?.badge?.value }}\n </mat-chip>\n }\n </span>\n }\n @case (\"chip\") {\n <mat-chip\n [color]=\"isThemeColor(node?.color) ? node?.color : undefined\"\n [ngClass]=\"[\n node?.class || '',\n (node?.variant || 'filled') === 'outlined' ? 'chip-outlined' : '',\n ]\"\n [style.cssText]=\"\n chipStyle(node?.color, node?.variant) +\n (node?.style ? ';' + node.style : '')\n \"\n >\n {{ node?.value }}\n </mat-chip>\n }\n @case (\"rating\") {\n <span [ngClass]=\"node?.class\" [style.cssText]=\"node?.style\">\n @for (_ of ratingRange(node); track $index; let idx = $index) {\n <mat-icon\n [praxisIcon]=\"starIcon(idx, node?.value)\"\n [color]=\"ratingThemeColor(node)\"\n [style.cssText]=\"ratingIconStyle(node)\"\n ></mat-icon>\n }\n </span>\n }\n @case (\"html\") {\n <span\n [ngClass]=\"node?.class\"\n [style.cssText]=\"node?.style\"\n [innerHTML]=\"node?.value\"\n ></span>\n }\n @case (\"metric\") {\n <praxis-list-metric [metric]=\"node\"></praxis-list-metric>\n }\n @case (\"compose\") {\n <praxis-list-compose [compose]=\"node\"></praxis-list-compose>\n }\n @case (\"component\") {\n <praxis-list-runtime-component\n [component]=\"node\"\n ></praxis-list-runtime-component>\n }\n @default {\n <span [ngClass]=\"node?.class\" [style.cssText]=\"node?.style\">\n @if (slot === \"meta\" && config.templating?.metaPrefixIcon; as mpi) {\n <mat-icon [praxisIcon]=\"mpi\"></mat-icon>\n }\n {{ node?.value }}\n </span>\n }\n }\n </ng-template>\n\n <ng-template\n #listRowLayout\n let-item\n let-index=\"index\"\n let-sectionKey=\"sectionKey\"\n let-clickable=\"clickable\"\n >\n <div\n class=\"list-item-content\"\n [ngClass]=\"rowLayoutItemClass(item)\"\n [attr.style]=\"rowLayoutItemStyle(item)\"\n [attr.role]=\"clickable ? 'button' : null\"\n [attr.tabindex]=\"clickable ? '0' : null\"\n [attr.aria-label]=\"clickable ? itemAriaLabel(item) : null\"\n [attr.aria-expanded]=\"\n clickable && expansionOwnedByRow() ? isExpanded(item, index) : null\n \"\n [attr.aria-controls]=\"\n clickable && expansionOwnedByRow()\n ? expandRegionId(item, index)\n : null\n \"\n (click)=\"clickable ? onRowActivate(item, index, sectionKey) : null\"\n (keydown.enter)=\"clickable ? onRowActivate(item, index, sectionKey) : null\"\n (keydown.space)=\"\n onRowSpaceActivate($event, clickable, item, index, sectionKey)\n \"\n >\n @for (column of rowLayoutColumns(); track rowLayoutTrackColumn($index, column)) {\n <div\n [attr.data-row-slot]=\"column.slot\"\n [ngClass]=\"rowLayoutColumnClass(column)\"\n [attr.style]=\"rowLayoutColumnStyle(column)\"\n >\n @if (column.slot === \"leading\") {\n @if (rowLayoutSlot(item, column.slot); as lead) {\n <ng-container\n *ngTemplateOutlet=\"\n rowLayoutNode;\n context: {\n $implicit: lead,\n slot: column.slot,\n imageAlt: rowLayoutImageAlt(column.slot),\n }\n \"\n ></ng-container>\n } @else {\n <span class=\"leading-placeholder\"></span>\n }\n } @else if (column.slot === \"trailing\") {\n @if (rowLayoutSlot(item, column.slot); as trailingNode) {\n <ng-container\n *ngTemplateOutlet=\"\n rowLayoutNode;\n context: {\n $implicit: trailingNode,\n slot: column.slot,\n imageAlt: rowLayoutImageAlt(column.slot),\n }\n \"\n ></ng-container>\n }\n @if (showExpandIcon(\"trailing\")) {\n <button\n mat-icon-button\n type=\"button\"\n class=\"expand-toggle\"\n [attr.aria-label]=\"expandToggleAriaLabel(item, index)\"\n [attr.aria-expanded]=\"\n expansionOwnedByIcon() ? isExpanded(item, index) : null\n \"\n [attr.aria-controls]=\"\n expansionOwnedByIcon()\n ? expandRegionId(item, index)\n : null\n \"\n (click)=\"onExpandToggle($event, item, index)\"\n >\n <mat-icon\n [praxisIcon]=\"\n isExpanded(item, index) ? 'expand_less' : 'expand_more'\n \"\n ></mat-icon>\n </button>\n }\n @if ((visibleActions(item, \"trailing\") || []).length) {\n <div\n class=\"list-item-actions\"\n (click)=\"$event.stopPropagation()\"\n (keydown.enter)=\"onActionKeydown($event)\"\n (keydown.space)=\"onActionKeydown($event)\"\n >\n @for (\n action of visibleActions(item, \"trailing\");\n let aidx = $index;\n track action?.id ?? $index\n ) {\n @if ((action.kind || \"icon\") === \"icon\") {\n <button\n mat-icon-button\n [color]=\"\n isThemeColor(action.color) ? action.color : undefined\n \"\n (click)=\"onActionClick($event, action.id, item, index)\"\n [attr.aria-label]=\"action.label || action.id\"\n [disabled]=\"isActionLoading(action.id, item, index)\"\n [ngClass]=\"{\n 'action-loading': isActionLoading(\n action.id,\n item,\n index\n ),\n }\"\n >\n @if (isActionLoading(action.id, item, index)) {\n <mat-progress-spinner\n class=\"action-spinner\"\n mode=\"indeterminate\"\n diameter=\"16\"\n strokeWidth=\"3\"\n ></mat-progress-spinner>\n } @else {\n <mat-icon\n [praxisIcon]=\"action.icon\"\n [style.cssText]=\"iconStyle(action.color)\"\n ></mat-icon>\n }\n </button>\n } @else {\n @if (action.buttonVariant === \"stroked\") {\n <button\n mat-stroked-button\n [color]=\"\n isThemeColor(action.color) ? action.color : undefined\n \"\n [style.cssText]=\"buttonStyle(action.color, 'stroked')\"\n (click)=\"onActionClick($event, action.id, item, index)\"\n [attr.aria-label]=\"action.label || action.id\"\n [disabled]=\"isActionLoading(action.id, item, index)\"\n [ngClass]=\"{\n 'action-loading': isActionLoading(\n action.id,\n item,\n index\n ),\n }\"\n >\n @if (isActionLoading(action.id, item, index)) {\n <mat-progress-spinner\n class=\"action-spinner\"\n mode=\"indeterminate\"\n diameter=\"16\"\n strokeWidth=\"3\"\n ></mat-progress-spinner>\n } @else {\n {{ action.label || action.id }}\n }\n </button>\n }\n @if (action.buttonVariant === \"raised\") {\n <button\n mat-raised-button\n [color]=\"\n isThemeColor(action.color) ? action.color : undefined\n \"\n [style.cssText]=\"buttonStyle(action.color, 'raised')\"\n (click)=\"onActionClick($event, action.id, item, index)\"\n [attr.aria-label]=\"action.label || action.id\"\n [disabled]=\"isActionLoading(action.id, item, index)\"\n [ngClass]=\"{\n 'action-loading': isActionLoading(\n action.id,\n item,\n index\n ),\n }\"\n >\n @if (isActionLoading(action.id, item, index)) {\n <mat-progress-spinner\n class=\"action-spinner\"\n mode=\"indeterminate\"\n diameter=\"16\"\n strokeWidth=\"3\"\n ></mat-progress-spinner>\n } @else {\n {{ action.label || action.id }}\n }\n </button>\n }\n @if (!action.buttonVariant || action.buttonVariant === \"flat\") {\n <button\n mat-flat-button\n [color]=\"\n isThemeColor(action.color) ? action.color : undefined\n \"\n [style.cssText]=\"buttonStyle(action.color, 'flat')\"\n (click)=\"onActionClick($event, action.id, item, index)\"\n [attr.aria-label]=\"action.label || action.id\"\n [disabled]=\"isActionLoading(action.id, item, index)\"\n [ngClass]=\"{\n 'action-loading': isActionLoading(\n action.id,\n item,\n index\n ),\n }\"\n >\n @if (isActionLoading(action.id, item, index)) {\n <mat-progress-spinner\n class=\"action-spinner\"\n mode=\"indeterminate\"\n diameter=\"16\"\n strokeWidth=\"3\"\n ></mat-progress-spinner>\n } @else {\n {{ action.label || action.id }}\n }\n </button>\n }\n }\n }\n </div>\n }\n } @else if (column.slot === \"actions\") {\n @if ((visibleActions(item, \"actions\") || []).length) {\n <div\n class=\"list-item-actions\"\n (click)=\"$event.stopPropagation()\"\n (keydown.enter)=\"onActionKeydown($event)\"\n (keydown.space)=\"onActionKeydown($event)\"\n >\n @for (\n action of visibleActions(item, \"actions\");\n let aidx = $index;\n track action?.id ?? $index\n ) {\n @if ((action.kind || \"icon\") === \"icon\") {\n <button\n mat-icon-button\n [color]=\"\n isThemeColor(action.color) ? action.color : undefined\n \"\n (click)=\"onActionClick($event, action.id, item, index)\"\n [attr.aria-label]=\"action.label || action.id\"\n [disabled]=\"isActionLoading(action.id, item, index)\"\n [ngClass]=\"{\n 'action-loading': isActionLoading(\n action.id,\n item,\n index\n ),\n }\"\n >\n @if (isActionLoading(action.id, item, index)) {\n <mat-progress-spinner\n class=\"action-spinner\"\n mode=\"indeterminate\"\n diameter=\"16\"\n strokeWidth=\"3\"\n ></mat-progress-spinner>\n } @else {\n <mat-icon\n [praxisIcon]=\"action.icon\"\n [style.cssText]=\"iconStyle(action.color)\"\n ></mat-icon>\n }\n </button>\n } @else {\n @if (action.buttonVariant === \"stroked\") {\n <button\n mat-stroked-button\n [color]=\"\n isThemeColor(action.color) ? action.color : undefined\n \"\n [style.cssText]=\"buttonStyle(action.color, 'stroked')\"\n (click)=\"onActionClick($event, action.id, item, index)\"\n [attr.aria-label]=\"action.label || action.id\"\n [disabled]=\"isActionLoading(action.id, item, index)\"\n [ngClass]=\"{\n 'action-loading': isActionLoading(\n action.id,\n item,\n index\n ),\n }\"\n >\n @if (isActionLoading(action.id, item, index)) {\n <mat-progress-spinner\n class=\"action-spinner\"\n mode=\"indeterminate\"\n diameter=\"16\"\n strokeWidth=\"3\"\n ></mat-progress-spinner>\n } @else {\n {{ action.label || action.id }}\n }\n </button>\n }\n @if (action.buttonVariant === \"raised\") {\n <button\n mat-raised-button\n [color]=\"\n isThemeColor(action.color) ? action.color : undefined\n \"\n [style.cssText]=\"buttonStyle(action.color, 'raised')\"\n (click)=\"onActionClick($event, action.id, item, index)\"\n [attr.aria-label]=\"action.label || action.id\"\n [disabled]=\"isActionLoading(action.id, item, index)\"\n [ngClass]=\"{\n 'action-loading': isActionLoading(\n action.id,\n item,\n index\n ),\n }\"\n >\n @if (isActionLoading(action.id, item, index)) {\n <mat-progress-spinner\n class=\"action-spinner\"\n mode=\"indeterminate\"\n diameter=\"16\"\n strokeWidth=\"3\"\n ></mat-progress-spinner>\n } @else {\n {{ action.label || action.id }}\n }\n </button>\n }\n @if (!action.buttonVariant || action.buttonVariant === \"flat\") {\n <button\n mat-flat-button\n [color]=\"\n isThemeColor(action.color) ? action.color : undefined\n \"\n [style.cssText]=\"buttonStyle(action.color, 'flat')\"\n (click)=\"onActionClick($event, action.id, item, index)\"\n [attr.aria-label]=\"action.label || action.id\"\n [disabled]=\"isActionLoading(action.id, item, index)\"\n [ngClass]=\"{\n 'action-loading': isActionLoading(\n action.id,\n item,\n index\n ),\n }\"\n >\n @if (isActionLoading(action.id, item, index)) {\n <mat-progress-spinner\n class=\"action-spinner\"\n mode=\"indeterminate\"\n diameter=\"16\"\n strokeWidth=\"3\"\n ></mat-progress-spinner>\n } @else {\n {{ action.label || action.id }}\n }\n </button>\n }\n }\n }\n </div>\n }\n } @else if (column.slot === \"expand\") {\n @if (showExpandIcon(\"expand\")) {\n <button\n mat-icon-button\n type=\"button\"\n class=\"expand-toggle\"\n [attr.aria-label]=\"expandToggleAriaLabel(item, index)\"\n [attr.aria-expanded]=\"\n expansionOwnedByIcon() ? isExpanded(item, index) : null\n \"\n [attr.aria-controls]=\"\n expansionOwnedByIcon()\n ? expandRegionId(item, index)\n : null\n \"\n (click)=\"onExpandToggle($event, item, index)\"\n >\n <mat-icon\n [praxisIcon]=\"\n isExpanded(item, index) ? 'expand_less' : 'expand_more'\n \"\n ></mat-icon>\n </button>\n }\n } @else if (rowLayoutSlot(item, column.slot); as slotNode) {\n <ng-container\n *ngTemplateOutlet=\"\n rowLayoutNode;\n context: {\n $implicit: slotNode,\n slot: column.slot,\n imageAlt: rowLayoutImageAlt(column.slot),\n }\n \"\n ></ng-container>\n }\n </div>\n }\n </div>\n </ng-template>\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 (\n section of sections$ | async;\n track trackBySection($index, section)\n ) {\n @if (section.key) {\n <div class=\"section-header mat-subheader\">\n @if (sectionHeaderTemplate(section.key); as sh) {\n @switch (sh.type) {\n @case (\"icon\") {\n <mat-icon\n [praxisIcon]=\"sh.value\"\n [ngClass]=\"sh.class\"\n [color]=\"isThemeColor(sh.color) ? sh.color : undefined\"\n [style.cssText]=\"\n (sh.style ? sh.style + ';' : '') + iconStyle(sh.color)\n \"\n ></mat-icon>\n }\n @case (\"image\") {\n <span\n class=\"inline-image\"\n [ngClass]=\"sh.class\"\n [style.cssText]=\"sh.style\"\n >\n <img\n [src]=\"sh.value\"\n [alt]=\"\n config.templating?.sectionHeader?.imageAlt || ''\n \"\n />\n @if (sh.badge?.value) {\n <mat-chip\n class=\"inline-badge\"\n [color]=\"\n isThemeColor(sh.badge?.color)\n ? sh.badge?.color\n : undefined\n \"\n [ngClass]=\"\n (sh.badge?.variant || 'filled') === 'outlined'\n ? 'chip-outlined'\n : ''\n \"\n [style.cssText]=\"\n chipStyle(sh.badge?.color, sh.badge?.variant)\n \"\n >{{ sh.badge?.value }}</mat-chip\n >\n }\n </span>\n }\n @case (\"chip\") {\n <mat-chip\n [color]=\"isThemeColor(sh.color) ? sh.color : undefined\"\n [ngClass]=\"[\n sh.class || '',\n (sh.variant || 'filled') === 'outlined'\n ? 'chip-outlined'\n : '',\n ]\"\n [style.cssText]=\"\n chipStyle(sh.color, sh.variant) +\n (sh.style ? ';' + sh.style : '')\n \"\n >{{ sh.value }}</mat-chip\n >\n }\n @case (\"rating\") {\n <span [ngClass]=\"sh.class\" [style.cssText]=\"sh.style\">\n @for (\n _ of ratingRange(sh);\n track $index;\n let idx = $index\n ) {\n <mat-icon\n [praxisIcon]=\"starIcon(idx, sh.value)\"\n [color]=\"ratingThemeColor(sh)\"\n [style.cssText]=\"ratingIconStyle(sh)\"\n ></mat-icon>\n }\n </span>\n }\n @case (\"html\") {\n <span\n [ngClass]=\"sh.class\"\n [style.cssText]=\"sh.style\"\n [innerHTML]=\"sh.value\"\n ></span>\n }\n @case (\"metric\") {\n <praxis-list-metric [metric]=\"sh\"></praxis-list-metric>\n }\n @case (\"compose\") {\n <praxis-list-compose [compose]=\"sh\"></praxis-list-compose>\n }\n @case (\"component\") {\n <praxis-list-runtime-component\n [component]=\"sh\"\n ></praxis-list-runtime-component>\n }\n @default {\n <span [ngClass]=\"sh.class\" [style.cssText]=\"sh.style\">{{\n sh.value\n }}</span>\n }\n }\n }\n </div>\n }\n @for (\n item of section.items;\n track trackByItem($index, item);\n let i = $index\n ) {\n <mat-list-option\n [value]=\"item\"\n [attr.aria-label]=\"itemAriaLabel(item)\"\n >\n @if (hasRowLayoutGrid()) {\n <ng-container\n *ngTemplateOutlet=\"\n listRowLayout;\n context: {\n $implicit: item,\n index: i,\n sectionKey: section.key || undefined,\n clickable: false,\n }\n \"\n ></ng-container>\n } @else {\n <div\n class=\"list-item-content\"\n [ngClass]=\"itemRuleClass(item)\"\n [attr.style]=\"itemRuleStyle(item)\"\n >\n <div class=\"list-item-leading\">\n @if (leading(item); as lead) {\n @switch (lead.type) {\n @case (\"icon\") {\n <mat-icon\n [praxisIcon]=\"lead.value\"\n [ngClass]=\"lead.class\"\n [color]=\"\n isThemeColor(lead.color) ? lead.color : undefined\n \"\n [style.cssText]=\"\n (lead.style ? lead.style + ';' : '') +\n iconStyle(lead.color)\n \"\n ></mat-icon>\n }\n @case (\"image\") {\n <div\n class=\"lead-image\"\n [ngClass]=\"lead.class\"\n [style.cssText]=\"lead.style\"\n >\n <img\n [src]=\"lead.value\"\n [alt]=\"config.templating?.leading?.imageAlt || ''\"\n />\n @if (lead.badge?.value) {\n <mat-chip\n class=\"lead-badge\"\n [color]=\"\n isThemeColor(lead.badge?.color)\n ? lead.badge?.color\n : undefined\n \"\n [ngClass]=\"\n (lead.badge?.variant || 'filled') ===\n 'outlined'\n ? 'chip-outlined'\n : ''\n \"\n [style.cssText]=\"\n chipStyle(\n lead.badge?.color,\n lead.badge?.variant\n )\n \"\n >{{ lead.badge?.value }}</mat-chip\n >\n }\n </div>\n }\n @case (\"text\") {\n <span\n [ngClass]=\"lead.class\"\n [style.cssText]=\"lead.style\"\n >{{ lead.value }}</span\n >\n }\n @case (\"chip\") {\n <mat-chip\n [color]=\"\n isThemeColor(lead.color) ? lead.color : undefined\n \"\n [ngClass]=\"\n (lead.variant || 'filled') === 'outlined'\n ? 'chip-outlined'\n : ''\n \"\n [style.cssText]=\"\n chipStyle(lead.color, lead.variant)\n \"\n >{{ lead.value }}</mat-chip\n >\n }\n @case (\"rating\") {\n <span\n [ngClass]=\"lead.class\"\n [style.cssText]=\"lead.style\"\n >\n @for (\n _ of ratingRange(lead);\n track $index;\n let idx = $index\n ) {\n <mat-icon\n [praxisIcon]=\"starIcon(idx, lead.value)\"\n [color]=\"ratingThemeColor(lead)\"\n [style.cssText]=\"ratingIconStyle(lead)\"\n ></mat-icon>\n }\n </span>\n }\n @case (\"html\") {\n <span\n [ngClass]=\"lead.class\"\n [style.cssText]=\"lead.style\"\n [innerHTML]=\"lead.value\"\n ></span>\n }\n @case (\"metric\") {\n <praxis-list-metric [metric]=\"lead\"></praxis-list-metric>\n }\n @case (\"compose\") {\n <praxis-list-compose\n [compose]=\"lead\"\n ></praxis-list-compose>\n }\n @case (\"component\") {\n <praxis-list-runtime-component\n [component]=\"lead\"\n ></praxis-list-runtime-component>\n }\n @default {\n <span\n [ngClass]=\"lead.class\"\n [style.cssText]=\"lead.style\"\n >{{ lead.value }}</span\n >\n }\n }\n } @else {\n <span class=\"leading-placeholder\"></span>\n }\n </div>\n <div class=\"list-item-text\">\n <div\n class=\"primary\"\n [ngClass]=\"primary(item)?.class\"\n [style.cssText]=\"primary(item)?.style\"\n >\n @if (primary(item)?.type === \"metric\") {\n <praxis-list-metric\n [metric]=\"primary(item)\"\n ></praxis-list-metric>\n } @else if (primary(item)?.type === \"compose\") {\n <praxis-list-compose\n [compose]=\"primary(item)\"\n ></praxis-list-compose>\n } @else if (primary(item)?.type === \"component\") {\n <praxis-list-runtime-component\n [component]=\"primary(item)\"\n ></praxis-list-runtime-component>\n } @else {\n {{ primary(item)?.value }}\n }\n </div>\n @if (layoutLines > 1) {\n <div\n class=\"secondary\"\n [ngClass]=\"secondary(item)?.class\"\n [style.cssText]=\"secondary(item)?.style\"\n >\n @if (secondary(item)?.type === \"metric\") {\n <praxis-list-metric\n [metric]=\"secondary(item)\"\n ></praxis-list-metric>\n } @else if (secondary(item)?.type === \"compose\") {\n <praxis-list-compose\n [compose]=\"secondary(item)\"\n ></praxis-list-compose>\n } @else if (secondary(item)?.type === \"component\") {\n <praxis-list-runtime-component\n [component]=\"secondary(item)\"\n ></praxis-list-runtime-component>\n } @else {\n {{ secondary(item)?.value }}\n }\n </div>\n }\n @if (meta(item); as m) {\n @if (\n (config.templating?.metaPlacement === \"line\" &&\n (m?.type === \"text\" ||\n m?.type === \"date\" ||\n m?.type === \"currency\")) ||\n (layoutLines > 2 &&\n (m?.type === \"text\" ||\n m?.type === \"date\" ||\n m?.type === \"currency\"))\n ) {\n <div\n class=\"tertiary\"\n [ngClass]=\"m.class\"\n [style.cssText]=\"m.style\"\n >\n @if (config.templating?.metaPrefixIcon; as mpi) {\n <mat-icon [praxisIcon]=\"mpi\"></mat-icon>\n }\n {{ m.value }}\n </div>\n }\n }\n @if (featuresVisible()) {\n <div class=\"features\">\n @for (\n f of config.templating?.features || [];\n track $index;\n let fi = $index\n ) {\n <span\n class=\"feature\"\n [ngClass]=\"\n featureSemanticClass(item, f.expr, f.class)\n \"\n >\n @if (f.icon && featuresMode() !== \"labels-only\") {\n <mat-icon [praxisIcon]=\"f.icon\"></mat-icon>\n }\n @if (featuresMode() !== \"icons-only\") {\n <span\n [ngClass]=\"f.class\"\n [style.cssText]=\"f.style\"\n >\n @for (\n line of featureLabelLines(item, f.expr);\n track $index\n ) {\n <span class=\"feature-line\">{{ line }}</span>\n }\n </span>\n }\n @if (\n featureProgressPercent(item, f.expr, f.class);\n as progress\n ) {\n <span class=\"feature-progress\" aria-hidden=\"true\">\n <span\n class=\"feature-progress__value\"\n [style.width.%]=\"progress\"\n ></span>\n </span>\n }\n </span>\n }\n </div>\n }\n </div>\n <div class=\"list-item-trailing\">\n @if (meta(item); as m) {\n @if (\n !(\n (config.templating?.metaPlacement === \"line\" ||\n layoutLines > 2) &&\n (m?.type === \"text\" ||\n m?.type === \"date\" ||\n m?.type === \"currency\")\n )\n ) {\n <div\n class=\"meta\"\n [ngClass]=\"m.class\"\n [style.cssText]=\"m.style\"\n >\n @switch (m.type) {\n @case (\"chip\") {\n <mat-chip\n [color]=\"\n isThemeColor(m.color) ? m.color : undefined\n \"\n [ngClass]=\"\n (m.variant || 'filled') === 'outlined'\n ? 'chip-outlined'\n : ''\n \"\n [style.cssText]=\"chipStyle(m.color, m.variant)\"\n >{{ m.value }}</mat-chip\n >\n }\n @case (\"rating\") {\n @for (\n _ of ratingRange(m);\n track $index;\n let idx = $index\n ) {\n <mat-icon\n [praxisIcon]=\"starIcon(idx, m.value)\"\n [color]=\"ratingThemeColor(m)\"\n [style.cssText]=\"ratingIconStyle(m)\"\n ></mat-icon>\n }\n }\n @case (\"icon\") {\n <mat-icon\n [praxisIcon]=\"m.value\"\n [color]=\"\n isThemeColor(m.color) ? m.color : undefined\n \"\n [style.cssText]=\"iconStyle(m.color)\"\n ></mat-icon>\n }\n @case (\"image\") {\n <span class=\"inline-image\"\n ><img [src]=\"m.value\" [alt]=\"m.imageAlt || ''\"\n /></span>\n }\n @case (\"html\") {\n <span [innerHTML]=\"m.value\"></span>\n }\n @case (\"metric\") {\n <praxis-list-metric [metric]=\"m\"></praxis-list-metric>\n }\n @case (\"compose\") {\n <praxis-list-compose\n [compose]=\"m\"\n ></praxis-list-compose>\n }\n @case (\"component\") {\n <praxis-list-runtime-component\n [component]=\"m\"\n ></praxis-list-runtime-component>\n }\n @default {\n <span>\n @if (\n config.templating?.metaPrefixIcon;\n as mpi2\n ) {\n <mat-icon [praxisIcon]=\"mpi2\"></mat-icon>\n }\n {{ m.value }}</span\n >\n }\n }\n </div>\n }\n }\n @if (trailing(item); as tr) {\n <div\n class=\"trailing\"\n [ngClass]=\"tr.class\"\n [style.cssText]=\"tr.style\"\n >\n @switch (tr.type) {\n @case (\"chip\") {\n <mat-chip\n [color]=\"\n isThemeColor(tr.color) ? tr.color : undefined\n \"\n [ngClass]=\"\n (tr.variant || 'filled') === 'outlined'\n ? 'chip-outlined'\n : ''\n \"\n [style.cssText]=\"chipStyle(tr.color, tr.variant)\"\n >{{ tr.value }}</mat-chip\n >\n }\n @case (\"icon\") {\n <mat-icon\n [praxisIcon]=\"tr.value\"\n [color]=\"\n isThemeColor(tr.color) ? tr.color : undefined\n \"\n [style.cssText]=\"iconStyle(tr.color)\"\n ></mat-icon>\n }\n @case (\"image\") {\n <div\n class=\"lead-image\"\n [ngClass]=\"tr.class\"\n [style.cssText]=\"tr.style\"\n >\n <img\n [src]=\"tr.value\"\n [alt]=\"\n config.templating?.trailing?.imageAlt || ''\n \"\n />\n @if (tr.badge?.value) {\n <mat-chip\n class=\"lead-badge\"\n [color]=\"\n isThemeColor(tr.badge?.color)\n ? tr.badge?.color\n : undefined\n \"\n [ngClass]=\"\n (tr.badge?.variant || 'filled') ===\n 'outlined'\n ? 'chip-outlined'\n : ''\n \"\n [style.cssText]=\"\n chipStyle(\n tr.badge?.color,\n tr.badge?.variant\n )\n \"\n >{{ tr.badge?.value }}</mat-chip\n >\n }\n </div>\n }\n @case (\"rating\") {\n @for (\n _ of ratingRange(tr);\n track $index;\n let idx = $index\n ) {\n <mat-icon\n [praxisIcon]=\"starIcon(idx, tr.value)\"\n [color]=\"ratingThemeColor(tr)\"\n [style.cssText]=\"ratingIconStyle(tr)\"\n ></mat-icon>\n }\n }\n @case (\"html\") {\n @if (item.alertsData !== undefined && item.ownerName) {\n <!-- Component-based rendering for executive trailing -->\n <span class=\"exec-trailing-shell\">\n <praxis-executive-alerts [alerts]=\"item.alertsData\"></praxis-executive-alerts>\n <praxis-executive-owner [name]=\"item.ownerName\"></praxis-executive-owner>\n </span>\n } @else {\n <span [innerHTML]=\"tr.value\"></span>\n }\n }\n @case (\"metric\") {\n <praxis-list-metric [metric]=\"tr\"></praxis-list-metric>\n }\n @case (\"compose\") {\n <praxis-list-compose\n [compose]=\"tr\"\n ></praxis-list-compose>\n }\n @case (\"component\") {\n <praxis-list-runtime-component\n [component]=\"tr\"\n ></praxis-list-runtime-component>\n }\n @default {\n <span>{{ tr.value }}</span>\n }\n }\n </div>\n }\n @if (showExpandIcon(\"trailing\")) {\n <button\n mat-icon-button\n type=\"button\"\n class=\"expand-toggle\"\n [attr.aria-label]=\"expandToggleAriaLabel(item, i)\"\n [attr.aria-expanded]=\"\n expansionOwnedByIcon() ? isExpanded(item, i) : null\n \"\n [attr.aria-controls]=\"\n expansionOwnedByIcon()\n ? expandRegionId(item, i)\n : null\n \"\n (click)=\"onExpandToggle($event, item, i)\"\n >\n <mat-icon\n [praxisIcon]=\"\n isExpanded(item, i) ? 'expand_less' : 'expand_more'\n \"\n ></mat-icon>\n </button>\n }\n @if ((visibleActions(item, \"trailing\") || []).length) {\n <div\n class=\"list-item-actions\"\n (click)=\"$event.stopPropagation()\"\n (keydown.enter)=\"onActionKeydown($event)\"\n (keydown.space)=\"onActionKeydown($event)\"\n >\n @for (\n action of visibleActions(item, \"trailing\");\n let aidx = $index;\n track action?.id ?? $index\n ) {\n @if ((action.kind || \"icon\") === \"icon\") {\n <button\n mat-icon-button\n [color]=\"\n isThemeColor(action.color)\n ? action.color\n : undefined\n \"\n (click)=\"\n onActionClick($event, action.id, item, i)\n \"\n [attr.aria-label]=\"action.label || action.id\"\n [disabled]=\"isActionLoading(action.id, item, i)\"\n [ngClass]=\"{\n 'action-loading': isActionLoading(\n action.id,\n item,\n i\n ),\n }\"\n >\n @if (isActionLoading(action.id, item, i)) {\n <mat-progress-spinner\n class=\"action-spinner\"\n mode=\"indeterminate\"\n diameter=\"16\"\n strokeWidth=\"3\"\n ></mat-progress-spinner>\n } @else {\n <mat-icon\n [praxisIcon]=\"action.icon\"\n [style.cssText]=\"iconStyle(action.color)\"\n ></mat-icon>\n }\n </button>\n } @else {\n @if (action.buttonVariant === \"stroked\") {\n <button\n mat-stroked-button\n [color]=\"\n isThemeColor(action.color)\n ? action.color\n : undefined\n \"\n [style.cssText]=\"\n buttonStyle(action.color, 'stroked')\n \"\n (click)=\"\n onActionClick($event, action.id, item, i)\n \"\n [attr.aria-label]=\"action.label || action.id\"\n [disabled]=\"isActionLoading(action.id, item, i)\"\n [ngClass]=\"{\n 'action-loading': isActionLoading(\n action.id,\n item,\n i\n ),\n }\"\n >\n @if (isActionLoading(action.id, item, i)) {\n <mat-progress-spinner\n class=\"action-spinner\"\n mode=\"indeterminate\"\n diameter=\"16\"\n strokeWidth=\"3\"\n ></mat-progress-spinner>\n } @else {\n {{ action.label || action.id }}\n }\n </button>\n }\n @if (action.buttonVariant === \"raised\") {\n <button\n mat-raised-button\n [color]=\"\n isThemeColor(action.color)\n ? action.color\n : undefined\n \"\n [style.cssText]=\"\n buttonStyle(action.color, 'raised')\n \"\n (click)=\"\n onActionClick($event, action.id, item, i)\n \"\n [attr.aria-label]=\"action.label || action.id\"\n [disabled]=\"isActionLoading(action.id, item, i)\"\n [ngClass]=\"{\n 'action-loading': isActionLoading(\n action.id,\n item,\n i\n ),\n }\"\n >\n @if (isActionLoading(action.id, item, i)) {\n <mat-progress-spinner\n class=\"action-spinner\"\n mode=\"indeterminate\"\n diameter=\"16\"\n strokeWidth=\"3\"\n ></mat-progress-spinner>\n } @else {\n {{ action.label || action.id }}\n }\n </button>\n }\n @if (\n !action.buttonVariant ||\n action.buttonVariant === \"flat\"\n ) {\n <button\n mat-flat-button\n [color]=\"\n isThemeColor(action.color)\n ? action.color\n : undefined\n \"\n [style.cssText]=\"\n buttonStyle(action.color, 'flat')\n \"\n (click)=\"\n onActionClick($event, action.id, item, i)\n \"\n [attr.aria-label]=\"action.label || action.id\"\n [disabled]=\"isActionLoading(action.id, item, i)\"\n [ngClass]=\"{\n 'action-loading': isActionLoading(\n action.id,\n item,\n i\n ),\n }\"\n >\n @if (isActionLoading(action.id, item, i)) {\n <mat-progress-spinner\n class=\"action-spinner\"\n mode=\"indeterminate\"\n diameter=\"16\"\n strokeWidth=\"3\"\n ></mat-progress-spinner>\n } @else {\n {{ action.label || action.id }}\n }\n </button>\n }\n }\n }\n </div>\n }\n </div>\n </div>\n }\n @if (isExpandable() && isExpanded(item, i)) {\n <div\n class=\"item-expansion\"\n [id]=\"expandRegionId(item, i)\"\n role=\"region\"\n [attr.aria-label]=\"expansionRegionAriaLabel(item)\"\n >\n <div class=\"item-expansion-grid\">\n @for (\n expansionSection of expansionSections(item);\n track expansionSection.id\n ) {\n <section\n class=\"expansion-section\"\n [attr.data-section-type]=\"expansionSection.type\"\n >\n @if (expansionSection.title) {\n <div class=\"expansion-section-title\">\n {{ expansionSection.title }}\n </div>\n }\n @if (\n expansionSectionHasContent(\n item,\n expansionSection,\n i\n )\n ) {\n @switch (expansionSection.type) {\n @case (\"chip-list\") {\n <div class=\"expansion-chip-list\">\n @for (\n expansionEntry of expansionSectionItems(\n item,\n expansionSection,\n i\n );\n track $index\n ) {\n <mat-chip class=\"expansion-chip\">{{\n expansionItemLabel(expansionEntry)\n }}</mat-chip>\n }\n </div>\n }\n @case (\"timeline\") {\n <div class=\"expansion-timeline\">\n @for (\n expansionEntry of expansionSectionItems(\n item,\n expansionSection,\n i\n );\n track $index\n ) {\n <div class=\"expansion-timeline-item\">\n <div class=\"expansion-timeline-title\">\n {{\n expansionTimelineTitle(expansionEntry)\n }}\n </div>\n @if (\n expansionTimelineMeta(expansionEntry)\n ) {\n <div class=\"expansion-timeline-meta\">\n {{\n expansionTimelineMeta(\n expansionEntry\n )\n }}\n </div>\n }\n @if (\n expansionTimelineDescription(\n expansionEntry\n )\n ) {\n <div\n class=\"expansion-timeline-description\"\n >\n {{\n expansionTimelineDescription(\n expansionEntry\n )\n }}\n </div>\n }\n </div>\n }\n </div>\n }\n @case (\"key-value\") {\n <dl class=\"expansion-key-value\">\n @for (\n expansionEntry of expansionSectionItems(\n item,\n expansionSection,\n i\n );\n track $index\n ) {\n <div class=\"expansion-key-value-row\">\n @if (\n expansionKeyValueKey(expansionEntry)\n ) {\n <dt>\n {{\n expansionKeyValueKey(expansionEntry)\n }}\n </dt>\n }\n <dd>\n {{\n expansionKeyValueValue(expansionEntry)\n }}\n </dd>\n </div>\n }\n </dl>\n }\n @default {\n <div class=\"expansion-info-list\">\n @for (\n expansionEntry of expansionSectionItems(\n item,\n expansionSection,\n i\n );\n track $index\n ) {\n <div class=\"expansion-info-item\">\n <div class=\"expansion-info-title\">\n {{ expansionInfoTitle(expansionEntry) }}\n </div>\n @if (expansionInfoValue(expansionEntry)) {\n <div class=\"expansion-info-value\">\n {{\n expansionInfoValue(expansionEntry)\n }}\n </div>\n }\n </div>\n }\n </div>\n }\n }\n } @else {\n <div class=\"expansion-empty\">\n {{\n expansionSection.emptyLabel ||\n \"Sem dados dispon\u00EDveis\"\n }}\n </div>\n }\n </section>\n }\n </div>\n </div>\n }\n </mat-list-option>\n @if (\n (config.layout?.dividers === \"all\" ||\n config.layout?.dividers === \"between\") &&\n i < section.items.length - 1\n ) {\n <mat-divider></mat-divider>\n }\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 (\n section of sections$ | async;\n track trackBySection($index, section);\n let sidx = $index\n ) {\n @if (section.key) {\n <div class=\"section-header mat-subheader\">\n @if (sectionHeaderTemplate(section.key); as sh) {\n @switch (sh.type) {\n @case (\"icon\") {\n <mat-icon\n [praxisIcon]=\"sh.value\"\n [ngClass]=\"sh.class\"\n [color]=\"isThemeColor(sh.color) ? sh.color : undefined\"\n [style.cssText]=\"\n (sh.style ? sh.style + ';' : '') + iconStyle(sh.color)\n \"\n ></mat-icon>\n }\n @case (\"image\") {\n <span\n class=\"inline-image\"\n [ngClass]=\"sh.class\"\n [style.cssText]=\"sh.style\"\n >\n <img\n [src]=\"sh.value\"\n [alt]=\"\n config.templating?.sectionHeader?.imageAlt || ''\n \"\n />\n @if (sh.badge?.value) {\n <mat-chip\n class=\"inline-badge\"\n [color]=\"\n isThemeColor(sh.badge?.color)\n ? sh.badge?.color\n : undefined\n \"\n [ngClass]=\"\n (sh.badge?.variant || 'filled') === 'outlined'\n ? 'chip-outlined'\n : ''\n \"\n [style.cssText]=\"\n chipStyle(sh.badge?.color, sh.badge?.variant)\n \"\n >{{ sh.badge?.value }}</mat-chip\n >\n }\n </span>\n }\n @case (\"chip\") {\n <mat-chip\n [color]=\"isThemeColor(sh.color) ? sh.color : undefined\"\n [ngClass]=\"[\n sh.class || '',\n (sh.variant || 'filled') === 'outlined'\n ? 'chip-outlined'\n : '',\n ]\"\n [style.cssText]=\"\n chipStyle(sh.color, sh.variant) +\n (sh.style ? ';' + sh.style : '')\n \"\n >{{ sh.value }}</mat-chip\n >\n }\n @case (\"rating\") {\n <span [ngClass]=\"sh.class\" [style.cssText]=\"sh.style\">\n @for (\n _ of ratingRange(sh);\n track $index;\n let idx = $index\n ) {\n <mat-icon\n [praxisIcon]=\"starIcon(idx, sh.value)\"\n [color]=\"ratingThemeColor(sh)\"\n [style.cssText]=\"ratingIconStyle(sh)\"\n ></mat-icon>\n }\n </span>\n }\n @case (\"html\") {\n <span\n [ngClass]=\"sh.class\"\n [style.cssText]=\"sh.style\"\n [innerHTML]=\"sh.value\"\n ></span>\n }\n @case (\"metric\") {\n <praxis-list-metric [metric]=\"sh\"></praxis-list-metric>\n }\n @default {\n <span [ngClass]=\"sh.class\" [style.cssText]=\"sh.style\">{{\n sh.value\n }}</span>\n }\n }\n }\n </div>\n }\n @for (\n item of section.items;\n track trackByItem($index, item);\n let i = $index\n ) {\n <mat-list-item [attr.data-item-status]=\"item?.status || null\">\n @if (hasRowLayoutGrid()) {\n <ng-container\n *ngTemplateOutlet=\"\n listRowLayout;\n context: {\n $implicit: item,\n index: i,\n sectionKey: section.key || undefined,\n clickable: true,\n }\n \"\n ></ng-container>\n } @else {\n <div\n class=\"list-item-content\"\n [ngClass]=\"itemRuleClass(item)\"\n [attr.style]=\"itemRuleStyle(item)\"\n >\n <button\n type=\"button\"\n class=\"list-item-main-action\"\n [attr.aria-label]=\"itemAriaLabel(item)\"\n [attr.aria-expanded]=\"\n expansionOwnedByRow() ? isExpanded(item, i) : null\n \"\n [attr.aria-controls]=\"\n expansionOwnedByRow() ? expandRegionId(item, i) : null\n \"\n (click)=\"onRowActivate(item, i, section.key || undefined)\"\n >\n <div class=\"list-item-leading\">\n @if (leading(item); as lead) {\n @switch (lead.type) {\n @case (\"icon\") {\n <mat-icon\n [praxisIcon]=\"lead.value\"\n [ngClass]=\"lead.class\"\n [color]=\"\n isThemeColor(lead.color)\n ? lead.color\n : undefined\n \"\n [style.cssText]=\"\n (lead.style ? lead.style + ';' : '') +\n iconStyle(lead.color)\n \"\n ></mat-icon>\n }\n @case (\"image\") {\n <div\n class=\"lead-image\"\n [ngClass]=\"lead.class\"\n [style.cssText]=\"lead.style\"\n >\n <img\n [src]=\"lead.value\"\n [alt]=\"\n config.templating?.leading?.imageAlt || ''\n \"\n />\n @if (lead.badge?.value) {\n <mat-chip\n class=\"lead-badge\"\n [color]=\"\n isThemeColor(lead.badge?.color)\n ? lead.badge?.color\n : undefined\n \"\n [ngClass]=\"\n (lead.badge?.variant || 'filled') ===\n 'outlined'\n ? 'chip-outlined'\n : ''\n \"\n [style.cssText]=\"\n chipStyle(\n lead.badge?.color,\n lead.badge?.variant\n )\n \"\n >{{ lead.badge?.value }}</mat-chip\n >\n }\n </div>\n }\n @case (\"text\") {\n <span\n [ngClass]=\"lead.class\"\n [style.cssText]=\"lead.style\"\n >{{ lead.value }}</span\n >\n }\n @case (\"chip\") {\n <mat-chip\n [color]=\"\n isThemeColor(lead.color)\n ? lead.color\n : undefined\n \"\n [ngClass]=\"\n (lead.variant || 'filled') === 'outlined'\n ? 'chip-outlined'\n : ''\n \"\n [style.cssText]=\"\n chipStyle(lead.color, lead.variant)\n \"\n >{{ lead.value }}</mat-chip\n >\n }\n @case (\"rating\") {\n @for (\n _ of ratingRange(lead);\n track $index;\n let idx = $index\n ) {\n <mat-icon\n [praxisIcon]=\"starIcon(idx, lead.value)\"\n [color]=\"ratingThemeColor(lead)\"\n [style.cssText]=\"ratingIconStyle(lead)\"\n ></mat-icon>\n }\n }\n @case (\"html\") {\n <span\n [ngClass]=\"lead.class\"\n [style.cssText]=\"lead.style\"\n [innerHTML]=\"lead.value\"\n ></span>\n }\n @case (\"metric\") {\n <praxis-list-metric [metric]=\"lead\"></praxis-list-metric>\n }\n @default {\n <span\n [ngClass]=\"lead.class\"\n [style.cssText]=\"lead.style\"\n >{{ lead.value }}</span\n >\n }\n }\n } @else {\n <span class=\"leading-placeholder\"></span>\n }\n </div>\n <div class=\"list-item-text\">\n <div\n class=\"primary\"\n [ngClass]=\"primary(item)?.class\"\n [style.cssText]=\"primary(item)?.style\"\n >\n @if (primary(item)?.type === \"metric\") {\n <praxis-list-metric\n [metric]=\"primary(item)\"\n ></praxis-list-metric>\n } @else if (primary(item)?.type === \"html\") {\n <span [innerHTML]=\"primary(item)?.value\"></span>\n } @else {\n {{ primary(item)?.value }}\n }\n </div>\n @if (layoutLines > 1) {\n <div\n class=\"secondary\"\n [ngClass]=\"secondary(item)?.class\"\n [style.cssText]=\"secondary(item)?.style\"\n >\n @if (item.segmentVariant && item.segmentLabel && item.accountType && item.since) {\n <!-- Component-based rendering for executive items -->\n <span class=\"exec-subline\">\n <praxis-executive-badge [variant]=\"item.segmentVariant\">{{ item.segmentLabel }}</praxis-executive-badge>\n <span class=\"exec-subcopy\">{{ item.accountType }}</span>\n <span class=\"exec-subseparator\">\u00B7</span>\n <span class=\"exec-subcopy\">Desde {{ item.since }}</span>\n </span>\n } @else if (secondary(item)?.type === \"html\") {\n <span [innerHTML]=\"secondary(item)?.value\"></span>\n } @else if (secondary(item)?.type === \"metric\") {\n <praxis-list-metric\n [metric]=\"secondary(item)\"\n ></praxis-list-metric>\n } @else {\n {{ secondary(item)?.value }}\n }\n </div>\n }\n @if (meta(item); as m) {\n @if (\n (config.templating?.metaPlacement === \"line\" &&\n (m?.type === \"text\" ||\n m?.type === \"date\" ||\n m?.type === \"currency\")) ||\n (layoutLines > 2 &&\n (m?.type === \"text\" ||\n m?.type === \"date\" ||\n m?.type === \"currency\"))\n ) {\n <div\n class=\"tertiary\"\n [ngClass]=\"m.class\"\n [style.cssText]=\"m.style\"\n >\n @if (config.templating?.metaPrefixIcon; as mpi) {\n <mat-icon [praxisIcon]=\"mpi\"></mat-icon>\n }\n {{ m.value }}\n </div>\n }\n }\n @if (featuresVisible()) {\n <div class=\"features\">\n @for (\n f of config.templating?.features || [];\n track $index;\n let fi = $index\n ) {\n <span\n class=\"feature\"\n [ngClass]=\"\n featureSemanticClass(item, f.expr, f.class)\n \"\n >\n @if (f.icon && featuresMode() !== \"labels-only\") {\n <mat-icon [praxisIcon]=\"f.icon\"></mat-icon>\n }\n @if (featuresMode() !== \"icons-only\") {\n <span\n [ngClass]=\"f.class\"\n [style.cssText]=\"f.style\"\n >\n @for (\n line of featureLabelLines(item, f.expr);\n track $index\n ) {\n <span class=\"feature-line\">{{ line }}</span>\n }\n </span>\n }\n @if (\n featureProgressPercent(item, f.expr, f.class);\n as progress\n ) {\n <span\n class=\"feature-progress\"\n aria-hidden=\"true\"\n >\n <span\n class=\"feature-progress__value\"\n [style.width.%]=\"progress\"\n ></span>\n </span>\n }\n </span>\n }\n </div>\n }\n </div>\n </button>\n <div class=\"list-item-trailing\">\n @if (meta(item); as m) {\n @if (\n !(\n (config.templating?.metaPlacement === \"line\" ||\n layoutLines > 2) &&\n (m?.type === \"text\" ||\n m?.type === \"date\" ||\n m?.type === \"currency\")\n )\n ) {\n <div\n class=\"meta\"\n [ngClass]=\"m.class\"\n [style.cssText]=\"m.style\"\n >\n @switch (m.type) {\n @case (\"chip\") {\n <mat-chip\n [color]=\"\n isThemeColor(m.color) ? m.color : undefined\n \"\n [ngClass]=\"\n (m.variant || 'filled') === 'outlined'\n ? 'chip-outlined'\n : ''\n \"\n [style.cssText]=\"chipStyle(m.color, m.variant)\"\n >{{ m.value }}</mat-chip\n >\n }\n @case (\"rating\") {\n @for (\n _ of ratingRange(m);\n track $index;\n let idx = $index\n ) {\n <mat-icon\n [praxisIcon]=\"starIcon(idx, m.value)\"\n [color]=\"ratingThemeColor(m)\"\n [style.cssText]=\"ratingIconStyle(m)\"\n ></mat-icon>\n }\n }\n @case (\"icon\") {\n <mat-icon\n [praxisIcon]=\"m.value\"\n [color]=\"\n isThemeColor(m.color) ? m.color : undefined\n \"\n [style.cssText]=\"iconStyle(m.color)\"\n ></mat-icon>\n }\n @case (\"image\") {\n <span class=\"inline-image\"\n ><img [src]=\"m.value\" [alt]=\"m.imageAlt || ''\"\n /></span>\n }\n @case (\"html\") {\n <span [innerHTML]=\"m.value\"></span>\n }\n @case (\"metric\") {\n <praxis-list-metric [metric]=\"m\"></praxis-list-metric>\n }\n @default {\n <span>\n @if (\n config.templating?.metaPrefixIcon;\n as mpi2\n ) {\n <mat-icon [praxisIcon]=\"mpi2\"></mat-icon>\n }\n {{ m.value }}</span\n >\n }\n }\n </div>\n }\n }\n @if (trailing(item); as tr) {\n <div\n class=\"trailing\"\n [ngClass]=\"tr.class\"\n [style.cssText]=\"tr.style\"\n >\n @switch (tr.type) {\n @case (\"chip\") {\n <mat-chip\n [color]=\"\n isThemeColor(tr.color) ? tr.color : undefined\n \"\n [ngClass]=\"\n (tr.variant || 'filled') === 'outlined'\n ? 'chip-outlined'\n : ''\n \"\n [style.cssText]=\"chipStyle(tr.color, tr.variant)\"\n >{{ tr.value }}</mat-chip\n >\n }\n @case (\"icon\") {\n <mat-icon\n [praxisIcon]=\"tr.value\"\n [color]=\"\n isThemeColor(tr.color) ? tr.color : undefined\n \"\n [style.cssText]=\"iconStyle(tr.color)\"\n ></mat-icon>\n }\n @case (\"image\") {\n <div\n class=\"lead-image\"\n [ngClass]=\"tr.class\"\n [style.cssText]=\"tr.style\"\n >\n <img\n [src]=\"tr.value\"\n [alt]=\"\n config.templating?.trailing?.imageAlt || ''\n \"\n />\n @if (tr.badge?.value) {\n <mat-chip\n class=\"lead-badge\"\n [color]=\"\n isThemeColor(tr.badge?.color)\n ? tr.badge?.color\n : undefined\n \"\n [ngClass]=\"\n (tr.badge?.variant || 'filled') ===\n 'outlined'\n ? 'chip-outlined'\n : ''\n \"\n [style.cssText]=\"\n chipStyle(\n tr.badge?.color,\n tr.badge?.variant\n )\n \"\n >{{ tr.badge?.value }}</mat-chip\n >\n }\n </div>\n }\n @case (\"rating\") {\n @for (\n _ of ratingRange(tr);\n track $index;\n let idx = $index\n ) {\n <mat-icon\n [praxisIcon]=\"starIcon(idx, tr.value)\"\n [color]=\"ratingThemeColor(tr)\"\n [style.cssText]=\"ratingIconStyle(tr)\"\n ></mat-icon>\n }\n }\n @case (\"html\") {\n @if (item.alertsData !== undefined && item.ownerName) {\n <!-- Component-based rendering for executive trailing -->\n <span class=\"exec-trailing-shell\">\n <praxis-executive-alerts [alerts]=\"item.alertsData\"></praxis-executive-alerts>\n <praxis-executive-owner [name]=\"item.ownerName\"></praxis-executive-owner>\n </span>\n } @else {\n <span [innerHTML]=\"tr.value\"></span>\n }\n }\n @case (\"metric\") {\n <praxis-list-metric [metric]=\"tr\"></praxis-list-metric>\n }\n @default {\n <span>{{ tr.value }}</span>\n }\n }\n </div>\n }\n @if (showExpandIcon(\"trailing\")) {\n <button\n mat-icon-button\n type=\"button\"\n class=\"expand-toggle\"\n [attr.aria-label]=\"expandToggleAriaLabel(item, i)\"\n [attr.aria-expanded]=\"\n expansionOwnedByIcon() ? isExpanded(item, i) : null\n \"\n [attr.aria-controls]=\"\n expansionOwnedByIcon()\n ? expandRegionId(item, i)\n : null\n \"\n (click)=\"onExpandToggle($event, item, i)\"\n >\n <mat-icon\n [praxisIcon]=\"\n isExpanded(item, i) ? 'expand_less' : 'expand_more'\n \"\n ></mat-icon>\n </button>\n }\n @if ((visibleActions(item, \"trailing\") || []).length) {\n <div\n class=\"list-item-actions\"\n (click)=\"$event.stopPropagation()\"\n (keydown.enter)=\"onActionKeydown($event)\"\n (keydown.space)=\"onActionKeydown($event)\"\n >\n @for (\n action of visibleActions(item, \"trailing\");\n let aidx = $index;\n track action?.id ?? $index\n ) {\n @if ((action.kind || \"icon\") === \"icon\") {\n <button\n mat-icon-button\n [color]=\"\n isThemeColor(action.color)\n ? action.color\n : undefined\n \"\n (click)=\"\n onActionClick($event, action.id, item, i)\n \"\n [attr.aria-label]=\"action.label || action.id\"\n [disabled]=\"isActionLoading(action.id, item, i)\"\n [ngClass]=\"{\n 'action-loading': isActionLoading(\n action.id,\n item,\n i\n ),\n }\"\n >\n @if (isActionLoading(action.id, item, i)) {\n <mat-progress-spinner\n class=\"action-spinner\"\n mode=\"indeterminate\"\n diameter=\"16\"\n strokeWidth=\"3\"\n ></mat-progress-spinner>\n } @else {\n <mat-icon\n [praxisIcon]=\"action.icon\"\n [style.cssText]=\"iconStyle(action.color)\"\n ></mat-icon>\n }\n </button>\n } @else {\n @if (action.buttonVariant === \"stroked\") {\n <button\n mat-stroked-button\n [color]=\"\n isThemeColor(action.color)\n ? action.color\n : undefined\n \"\n [style.cssText]=\"\n buttonStyle(action.color, 'stroked')\n \"\n (click)=\"\n onActionClick($event, action.id, item, i)\n \"\n [attr.aria-label]=\"action.label || action.id\"\n [disabled]=\"isActionLoading(action.id, item, i)\"\n [ngClass]=\"{\n 'action-loading': isActionLoading(\n action.id,\n item,\n i\n ),\n }\"\n >\n @if (isActionLoading(action.id, item, i)) {\n <mat-progress-spinner\n class=\"action-spinner\"\n mode=\"indeterminate\"\n diameter=\"16\"\n strokeWidth=\"3\"\n ></mat-progress-spinner>\n } @else {\n {{ action.label || action.id }}\n }\n </button>\n }\n @if (action.buttonVariant === \"raised\") {\n <button\n mat-raised-button\n [color]=\"\n isThemeColor(action.color)\n ? action.color\n : undefined\n \"\n [style.cssText]=\"\n buttonStyle(action.color, 'raised')\n \"\n (click)=\"\n onActionClick($event, action.id, item, i)\n \"\n [attr.aria-label]=\"action.label || action.id\"\n [disabled]=\"isActionLoading(action.id, item, i)\"\n [ngClass]=\"{\n 'action-loading': isActionLoading(\n action.id,\n item,\n i\n ),\n }\"\n >\n @if (isActionLoading(action.id, item, i)) {\n <mat-progress-spinner\n class=\"action-spinner\"\n mode=\"indeterminate\"\n diameter=\"16\"\n strokeWidth=\"3\"\n ></mat-progress-spinner>\n } @else {\n {{ action.label || action.id }}\n }\n </button>\n }\n @if (\n !action.buttonVariant ||\n action.buttonVariant === \"flat\"\n ) {\n <button\n mat-flat-button\n [color]=\"\n isThemeColor(action.color)\n ? action.color\n : undefined\n \"\n [style.cssText]=\"\n buttonStyle(action.color, 'flat')\n \"\n (click)=\"\n onActionClick($event, action.id, item, i)\n \"\n [attr.aria-label]=\"action.label || action.id\"\n [disabled]=\"isActionLoading(action.id, item, i)\"\n [ngClass]=\"{\n 'action-loading': isActionLoading(\n action.id,\n item,\n i\n ),\n }\"\n >\n @if (isActionLoading(action.id, item, i)) {\n <mat-progress-spinner\n class=\"action-spinner\"\n mode=\"indeterminate\"\n diameter=\"16\"\n strokeWidth=\"3\"\n ></mat-progress-spinner>\n } @else {\n {{ action.label || action.id }}\n }\n </button>\n }\n }\n }\n </div>\n }\n </div>\n </div>\n }\n @if (isExpandable() && isExpanded(item, i)) {\n <div\n class=\"item-expansion\"\n [id]=\"expandRegionId(item, i)\"\n role=\"region\"\n [attr.aria-label]=\"expansionRegionAriaLabel(item)\"\n >\n <div class=\"item-expansion-grid\">\n @for (\n expansionSection of expansionSections(item);\n track expansionSection.id\n ) {\n <section\n class=\"expansion-section\"\n [attr.data-section-type]=\"expansionSection.type\"\n >\n @if (expansionSection.title) {\n <div class=\"expansion-section-title\">\n {{ expansionSection.title }}\n </div>\n }\n @if (\n expansionSectionHasContent(\n item,\n expansionSection,\n i\n )\n ) {\n @switch (expansionSection.type) {\n @case (\"chip-list\") {\n <div class=\"expansion-chip-list\">\n @for (\n expansionEntry of expansionSectionItems(\n item,\n expansionSection,\n i\n );\n track $index\n ) {\n <mat-chip class=\"expansion-chip\">{{\n expansionItemLabel(expansionEntry)\n }}</mat-chip>\n }\n </div>\n }\n @case (\"timeline\") {\n <div class=\"expansion-timeline\">\n @for (\n expansionEntry of expansionSectionItems(\n item,\n expansionSection,\n i\n );\n track $index\n ) {\n <div class=\"expansion-timeline-item\">\n <div class=\"expansion-timeline-title\">\n {{\n expansionTimelineTitle(expansionEntry)\n }}\n </div>\n @if (\n expansionTimelineMeta(expansionEntry)\n ) {\n <div class=\"expansion-timeline-meta\">\n {{\n expansionTimelineMeta(\n expansionEntry\n )\n }}\n </div>\n }\n @if (\n expansionTimelineDescription(\n expansionEntry\n )\n ) {\n <div\n class=\"expansion-timeline-description\"\n >\n {{\n expansionTimelineDescription(\n expansionEntry\n )\n }}\n </div>\n }\n </div>\n }\n </div>\n }\n @case (\"key-value\") {\n <dl class=\"expansion-key-value\">\n @for (\n expansionEntry of expansionSectionItems(\n item,\n expansionSection,\n i\n );\n track $index\n ) {\n <div class=\"expansion-key-value-row\">\n @if (\n expansionKeyValueKey(expansionEntry)\n ) {\n <dt>\n {{\n expansionKeyValueKey(expansionEntry)\n }}\n </dt>\n }\n <dd>\n {{\n expansionKeyValueValue(expansionEntry)\n }}\n </dd>\n </div>\n }\n </dl>\n }\n @default {\n <div class=\"expansion-info-list\">\n @for (\n expansionEntry of expansionSectionItems(\n item,\n expansionSection,\n i\n );\n track $index\n ) {\n <div class=\"expansion-info-item\">\n <div class=\"expansion-info-title\">\n {{ expansionInfoTitle(expansionEntry) }}\n </div>\n @if (expansionInfoValue(expansionEntry)) {\n <div class=\"expansion-info-value\">\n {{\n expansionInfoValue(expansionEntry)\n }}\n </div>\n }\n </div>\n }\n </div>\n }\n }\n } @else {\n <div class=\"expansion-empty\">\n {{\n expansionSection.emptyLabel ||\n \"Sem dados dispon\u00EDveis\"\n }}\n </div>\n }\n </section>\n }\n </div>\n </div>\n }\n </mat-list-item>\n @if (\n (config.layout?.dividers === \"all\" ||\n config.layout?.dividers === \"between\") &&\n i < section.items.length - 1\n ) {\n <mat-divider></mat-divider>\n }\n }\n }\n </mat-list>\n </ng-template>\n } @else if (isTilesVariant()) {\n <ng-container *ngTemplateOutlet=\"tilesVariant\"></ng-container>\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\n class=\"item-card\"\n [ngClass]=\"itemRuleClass(it)\"\n [attr.style]=\"itemRuleStyle(it)\"\n role=\"button\"\n tabindex=\"0\"\n [attr.aria-label]=\"itemAriaLabel(it)\"\n (click)=\"onItemClick(it, i)\"\n (keydown.enter)=\"onItemClick(it, i)\"\n (keydown.space)=\"$event.preventDefault(); onItemClick(it, i)\"\n >\n <div class=\"list-item-content\">\n <div class=\"list-item-leading\">\n @if (leading(it); as lead) {\n @switch (lead.type) {\n @case (\"icon\") {\n <mat-icon\n [praxisIcon]=\"lead.value\"\n [ngClass]=\"lead.class\"\n [color]=\"\n isThemeColor(lead.color) ? lead.color : undefined\n \"\n [style.cssText]=\"\n (lead.style ? lead.style + ';' : '') +\n iconStyle(lead.color)\n \"\n ></mat-icon>\n }\n @case (\"image\") {\n <div\n class=\"lead-image\"\n [ngClass]=\"lead.class\"\n [style.cssText]=\"lead.style\"\n >\n <img\n [src]=\"lead.value\"\n [alt]=\"config.templating?.leading?.imageAlt || ''\"\n />\n @if (lead.badge?.value) {\n <mat-chip\n class=\"lead-badge\"\n [color]=\"\n isThemeColor(lead.badge?.color)\n ? lead.badge?.color\n : undefined\n \"\n [ngClass]=\"\n (lead.badge?.variant || 'filled') === 'outlined'\n ? 'chip-outlined'\n : ''\n \"\n [style.cssText]=\"\n chipStyle(lead.badge?.color, lead.badge?.variant)\n \"\n >{{ lead.badge?.value }}</mat-chip\n >\n }\n </div>\n }\n @case (\"text\") {\n <span\n [ngClass]=\"lead.class\"\n [style.cssText]=\"lead.style\"\n >{{ lead.value }}</span\n >\n }\n @case (\"chip\") {\n <mat-chip\n [color]=\"\n isThemeColor(lead.color) ? lead.color : undefined\n \"\n [ngClass]=\"\n (lead.variant || 'filled') === 'outlined'\n ? 'chip-outlined'\n : ''\n \"\n [style.cssText]=\"chipStyle(lead.color, lead.variant)\"\n >{{ lead.value }}</mat-chip\n >\n }\n @case (\"rating\") {\n @for (\n _ of ratingRange(lead);\n track $index;\n let idx = $index\n ) {\n <mat-icon\n [praxisIcon]=\"starIcon(idx, lead.value)\"\n [color]=\"ratingThemeColor(lead)\"\n [style.cssText]=\"ratingIconStyle(lead)\"\n ></mat-icon>\n }\n }\n @case (\"html\") {\n <span\n [ngClass]=\"lead.class\"\n [style.cssText]=\"lead.style\"\n [innerHTML]=\"lead.value\"\n ></span>\n }\n @case (\"metric\") {\n <praxis-list-metric [metric]=\"lead\"></praxis-list-metric>\n }\n @case (\"compose\") {\n <praxis-list-compose\n [compose]=\"lead\"\n ></praxis-list-compose>\n }\n @case (\"component\") {\n <praxis-list-runtime-component\n [component]=\"lead\"\n ></praxis-list-runtime-component>\n }\n @default {\n <span\n [ngClass]=\"lead.class\"\n [style.cssText]=\"lead.style\"\n >{{ lead.value }}</span\n >\n }\n }\n } @else {\n <span class=\"leading-placeholder\"></span>\n }\n </div>\n <div class=\"list-item-text\">\n <div\n class=\"primary\"\n [ngClass]=\"primary(it)?.class\"\n [style.cssText]=\"primary(it)?.style\"\n >\n @if (primary(it)?.type === \"metric\") {\n <praxis-list-metric [metric]=\"primary(it)\"></praxis-list-metric>\n } @else if (primary(it)?.type === \"compose\") {\n <praxis-list-compose\n [compose]=\"primary(it)\"\n ></praxis-list-compose>\n } @else if (primary(it)?.type === \"component\") {\n <praxis-list-runtime-component\n [component]=\"primary(it)\"\n ></praxis-list-runtime-component>\n } @else {\n {{ primary(it)?.value }}\n }\n </div>\n @if (layoutLines > 1) {\n <div\n class=\"secondary\"\n [ngClass]=\"secondary(it)?.class\"\n [style.cssText]=\"secondary(it)?.style\"\n >\n @if (secondary(it)?.type === \"metric\") {\n <praxis-list-metric\n [metric]=\"secondary(it)\"\n ></praxis-list-metric>\n } @else if (secondary(it)?.type === \"compose\") {\n <praxis-list-compose\n [compose]=\"secondary(it)\"\n ></praxis-list-compose>\n } @else if (secondary(it)?.type === \"component\") {\n <praxis-list-runtime-component\n [component]=\"secondary(it)\"\n ></praxis-list-runtime-component>\n } @else {\n {{ secondary(it)?.value }}\n }\n </div>\n }\n @if (meta(it); as m) {\n @if (\n (config.templating?.metaPlacement === \"line\" &&\n (m?.type === \"text\" ||\n m?.type === \"date\" ||\n m?.type === \"currency\")) ||\n (layoutLines > 2 &&\n (m?.type === \"text\" ||\n m?.type === \"date\" ||\n m?.type === \"currency\"))\n ) {\n <div\n class=\"tertiary\"\n [ngClass]=\"m.class\"\n [style.cssText]=\"m.style\"\n >\n @if (config.templating?.metaPrefixIcon; as mpi) {\n <mat-icon [praxisIcon]=\"mpi\"></mat-icon>\n }\n {{ m.value }}\n </div>\n }\n }\n @if (featuresVisible()) {\n <div class=\"features\">\n @for (\n f of config.templating?.features || [];\n track $index;\n let fi = $index\n ) {\n <span\n class=\"feature\"\n [ngClass]=\"featureSemanticClass(it, f.expr, f.class)\"\n >\n @if (f.icon && featuresMode() !== \"labels-only\") {\n <mat-icon [praxisIcon]=\"f.icon\"></mat-icon>\n }\n @if (featuresMode() !== \"icons-only\") {\n <span [ngClass]=\"f.class\" [style.cssText]=\"f.style\">\n @for (\n line of featureLabelLines(it, f.expr);\n track $index\n ) {\n <span class=\"feature-line\">{{ line }}</span>\n }\n </span>\n }\n @if (\n featureProgressPercent(it, f.expr, f.class);\n as progress\n ) {\n <span class=\"feature-progress\" aria-hidden=\"true\">\n <span\n class=\"feature-progress__value\"\n [style.width.%]=\"progress\"\n ></span>\n </span>\n }\n </span>\n }\n </div>\n }\n </div>\n <div class=\"list-item-trailing\">\n @if (meta(it); as m) {\n @if (\n !(\n (config.templating?.metaPlacement === \"line\" ||\n layoutLines > 2) &&\n (m?.type === \"text\" ||\n m?.type === \"date\" ||\n m?.type === \"currency\")\n )\n ) {\n <div\n class=\"meta\"\n [ngClass]=\"m.class\"\n [style.cssText]=\"m.style\"\n >\n @switch (m.type) {\n @case (\"chip\") {\n <mat-chip\n [color]=\"\n isThemeColor(m.color) ? m.color : undefined\n \"\n [ngClass]=\"\n (m.variant || 'filled') === 'outlined'\n ? 'chip-outlined'\n : ''\n \"\n [style.cssText]=\"chipStyle(m.color, m.variant)\"\n >{{ m.value }}</mat-chip\n >\n }\n @case (\"rating\") {\n @for (\n _ of ratingRange(m);\n track $index;\n let idx = $index\n ) {\n <mat-icon\n [praxisIcon]=\"starIcon(idx, m.value)\"\n [color]=\"ratingThemeColor(m)\"\n [style.cssText]=\"ratingIconStyle(m)\"\n ></mat-icon>\n }\n }\n @case (\"icon\") {\n <mat-icon\n [praxisIcon]=\"m.value\"\n [color]=\"\n isThemeColor(m.color) ? m.color : undefined\n \"\n [style.cssText]=\"iconStyle(m.color)\"\n ></mat-icon>\n }\n @case (\"image\") {\n <span class=\"inline-image\"\n ><img [src]=\"m.value\" [alt]=\"m.imageAlt || ''\"\n /></span>\n }\n @case (\"html\") {\n <span [innerHTML]=\"m.value\"></span>\n }\n @case (\"metric\") {\n <praxis-list-metric [metric]=\"m\"></praxis-list-metric>\n }\n @case (\"compose\") {\n <praxis-list-compose\n [compose]=\"m\"\n ></praxis-list-compose>\n }\n @case (\"component\") {\n <praxis-list-runtime-component\n [component]=\"m\"\n ></praxis-list-runtime-component>\n }\n @default {\n <span>\n @if (config.templating?.metaPrefixIcon; as mpi2) {\n <mat-icon [praxisIcon]=\"mpi2\"></mat-icon>\n }\n {{ m.value }}</span\n >\n }\n }\n </div>\n }\n }\n @if (trailing(it); as tr) {\n @if (\n (config.templating?.statusPosition || \"inline\") ===\n \"top-right\" &&\n (tr?.type === \"chip\" || tr?.type === \"icon\")\n ) {\n <div class=\"status-overlay\">\n @if (tr?.type === \"chip\") {\n <mat-chip\n [color]=\"\n isThemeColor(tr.color) ? tr.color : undefined\n \"\n [ngClass]=\"\n (tr.variant || 'filled') === 'outlined'\n ? 'chip-outlined'\n : ''\n \"\n [style.cssText]=\"chipStyle(tr.color, tr.variant)\"\n >{{ tr.value }}</mat-chip\n >\n }\n @if (tr?.type === \"icon\") {\n <mat-icon\n [praxisIcon]=\"tr.value\"\n [color]=\"\n isThemeColor(tr.color) ? tr.color : undefined\n \"\n [style.cssText]=\"iconStyle(tr.color)\"\n ></mat-icon>\n }\n </div>\n } @else {\n <div\n class=\"trailing\"\n [ngClass]=\"tr.class\"\n [style.cssText]=\"tr.style\"\n >\n @switch (tr.type) {\n @case (\"chip\") {\n <mat-chip\n [color]=\"\n isThemeColor(tr.color) ? tr.color : undefined\n \"\n [ngClass]=\"\n (tr.variant || 'filled') === 'outlined'\n ? 'chip-outlined'\n : ''\n \"\n [style.cssText]=\"chipStyle(tr.color, tr.variant)\"\n >{{ tr.value }}</mat-chip\n >\n }\n @case (\"icon\") {\n <mat-icon\n [praxisIcon]=\"tr.value\"\n [color]=\"\n isThemeColor(tr.color) ? tr.color : undefined\n \"\n [style.cssText]=\"iconStyle(tr.color)\"\n ></mat-icon>\n }\n @case (\"image\") {\n <div\n class=\"lead-image\"\n [ngClass]=\"tr.class\"\n [style.cssText]=\"tr.style\"\n >\n <img\n [src]=\"tr.value\"\n [alt]=\"\n config.templating?.trailing?.imageAlt || ''\n \"\n />\n @if (tr.badge?.value) {\n <mat-chip\n class=\"lead-badge\"\n [color]=\"\n isThemeColor(tr.badge?.color)\n ? tr.badge?.color\n : undefined\n \"\n [ngClass]=\"\n (tr.badge?.variant || 'filled') === 'outlined'\n ? 'chip-outlined'\n : ''\n \"\n [style.cssText]=\"\n chipStyle(tr.badge?.color, tr.badge?.variant)\n \"\n >{{ tr.badge?.value }}</mat-chip\n >\n }\n </div>\n }\n @case (\"rating\") {\n @for (\n _ of ratingRange(tr);\n track $index;\n let idx = $index\n ) {\n <mat-icon\n [praxisIcon]=\"starIcon(idx, tr.value)\"\n [color]=\"ratingThemeColor(tr)\"\n [style.cssText]=\"ratingIconStyle(tr)\"\n ></mat-icon>\n }\n }\n @case (\"html\") {\n <span [innerHTML]=\"tr.value\"></span>\n }\n @case (\"metric\") {\n <praxis-list-metric [metric]=\"tr\"></praxis-list-metric>\n }\n @case (\"compose\") {\n <praxis-list-compose\n [compose]=\"tr\"\n ></praxis-list-compose>\n }\n @case (\"component\") {\n <praxis-list-runtime-component\n [component]=\"tr\"\n ></praxis-list-runtime-component>\n }\n @default {\n <span>{{ tr.value }}</span>\n }\n }\n </div>\n }\n }\n </div>\n </div>\n <div\n class=\"card-actions\"\n (click)=\"$event.stopPropagation()\"\n (keydown.enter)=\"onActionKeydown($event)\"\n (keydown.space)=\"onActionKeydown($event)\"\n >\n @for (\n action of visibleActions(it, \"trailing\");\n let aidx = $index;\n track action?.id ?? $index\n ) {\n @if ((action.kind || \"icon\") === \"icon\") {\n <button\n mat-icon-button\n [color]=\"\n isThemeColor(action.color) ? action.color : undefined\n \"\n (click)=\"onActionClick($event, action.id, it, i)\"\n [attr.aria-label]=\"action.label || action.id\"\n [disabled]=\"isActionLoading(action.id, it, i)\"\n [ngClass]=\"{\n 'action-loading': isActionLoading(action.id, it, i),\n }\"\n >\n @if (isActionLoading(action.id, it, i)) {\n <mat-progress-spinner\n class=\"action-spinner\"\n mode=\"indeterminate\"\n diameter=\"16\"\n strokeWidth=\"3\"\n ></mat-progress-spinner>\n } @else {\n <mat-icon\n [praxisIcon]=\"action.icon\"\n [style.cssText]=\"iconStyle(action.color)\"\n ></mat-icon>\n }\n </button>\n } @else {\n @if (action.buttonVariant === \"stroked\") {\n <button\n mat-stroked-button\n [color]=\"\n isThemeColor(action.color) ? action.color : undefined\n \"\n [style.cssText]=\"buttonStyle(action.color, 'stroked')\"\n (click)=\"onActionClick($event, action.id, it, i)\"\n [attr.aria-label]=\"action.label || action.id\"\n [disabled]=\"isActionLoading(action.id, it, i)\"\n [ngClass]=\"{\n 'action-loading': isActionLoading(action.id, it, i),\n }\"\n >\n @if (isActionLoading(action.id, it, i)) {\n <mat-progress-spinner\n class=\"action-spinner\"\n mode=\"indeterminate\"\n diameter=\"16\"\n strokeWidth=\"3\"\n ></mat-progress-spinner>\n } @else {\n {{ action.label || action.id }}\n }\n </button>\n }\n @if (action.buttonVariant === \"raised\") {\n <button\n mat-raised-button\n [color]=\"\n isThemeColor(action.color) ? action.color : undefined\n \"\n [style.cssText]=\"buttonStyle(action.color, 'raised')\"\n (click)=\"onActionClick($event, action.id, it, i)\"\n [attr.aria-label]=\"action.label || action.id\"\n [disabled]=\"isActionLoading(action.id, it, i)\"\n [ngClass]=\"{\n 'action-loading': isActionLoading(action.id, it, i),\n }\"\n >\n @if (isActionLoading(action.id, it, i)) {\n <mat-progress-spinner\n class=\"action-spinner\"\n mode=\"indeterminate\"\n diameter=\"16\"\n strokeWidth=\"3\"\n ></mat-progress-spinner>\n } @else {\n {{ action.label || action.id }}\n }\n </button>\n }\n @if (\n !action.buttonVariant || action.buttonVariant === \"flat\"\n ) {\n <button\n mat-flat-button\n [color]=\"\n isThemeColor(action.color) ? action.color : undefined\n \"\n [style.cssText]=\"buttonStyle(action.color, 'flat')\"\n (click)=\"onActionClick($event, action.id, it, i)\"\n [attr.aria-label]=\"action.label || action.id\"\n [disabled]=\"isActionLoading(action.id, it, i)\"\n [ngClass]=\"{\n 'action-loading': isActionLoading(action.id, it, i),\n }\"\n >\n @if (isActionLoading(action.id, it, i)) {\n <mat-progress-spinner\n class=\"action-spinner\"\n mode=\"indeterminate\"\n diameter=\"16\"\n strokeWidth=\"3\"\n ></mat-progress-spinner>\n } @else {\n {{ action.label || action.id }}\n }\n </button>\n }\n }\n }\n </div>\n </div>\n }\n </div>\n </ng-template>\n\n <!-- Tiles variant -->\n <ng-template #tilesVariant>\n <div class=\"tiles-grid\">\n @for (it of (items$ | async) ?? []; track $index; let i = $index) {\n <div\n class=\"item-tile\"\n [ngClass]=\"itemRuleClass(it)\"\n [attr.style]=\"itemRuleStyle(it)\"\n role=\"button\"\n tabindex=\"0\"\n [attr.aria-label]=\"itemAriaLabel(it)\"\n (click)=\"onItemClick(it, i)\"\n (keydown.enter)=\"onItemClick(it, i)\"\n (keydown.space)=\"$event.preventDefault(); onItemClick(it, i)\"\n >\n <div class=\"tile-media\">\n @if (leading(it); as lead) {\n @switch (lead.type) {\n @case (\"image\") {\n <img\n [src]=\"lead.value\"\n [alt]=\"config.templating?.leading?.imageAlt || ''\"\n />\n }\n @case (\"icon\") {\n <mat-icon\n [praxisIcon]=\"lead.value\"\n [ngClass]=\"lead.class\"\n [color]=\"\n isThemeColor(lead.color) ? lead.color : undefined\n \"\n [style.cssText]=\"\n (lead.style ? lead.style + ';' : '') +\n iconStyle(lead.color)\n \"\n ></mat-icon>\n }\n @case (\"text\") {\n <span [ngClass]=\"lead.class\" [style.cssText]=\"lead.style\">{{\n lead.value\n }}</span>\n }\n @case (\"chip\") {\n <mat-chip\n [color]=\"\n isThemeColor(lead.color) ? lead.color : undefined\n \"\n [ngClass]=\"\n (lead.variant || 'filled') === 'outlined'\n ? 'chip-outlined'\n : ''\n \"\n [style.cssText]=\"chipStyle(lead.color, lead.variant)\"\n >{{ lead.value }}</mat-chip\n >\n }\n @case (\"rating\") {\n <span [ngClass]=\"lead.class\" [style.cssText]=\"lead.style\">\n @for (\n _ of ratingRange(lead);\n track $index;\n let idx = $index\n ) {\n <mat-icon\n [praxisIcon]=\"starIcon(idx, lead.value)\"\n [color]=\"ratingThemeColor(lead)\"\n [style.cssText]=\"ratingIconStyle(lead)\"\n ></mat-icon>\n }\n </span>\n }\n @case (\"html\") {\n <span\n [ngClass]=\"lead.class\"\n [style.cssText]=\"lead.style\"\n [innerHTML]=\"lead.value\"\n ></span>\n }\n @case (\"metric\") {\n <praxis-list-metric [metric]=\"lead\"></praxis-list-metric>\n }\n @case (\"compose\") {\n <praxis-list-compose\n [compose]=\"lead\"\n ></praxis-list-compose>\n }\n @case (\"component\") {\n <praxis-list-runtime-component\n [component]=\"lead\"\n ></praxis-list-runtime-component>\n }\n @default {\n <span [ngClass]=\"lead.class\" [style.cssText]=\"lead.style\">{{\n lead.value\n }}</span>\n }\n }\n }\n </div>\n\n @if (trailing(it); as tr) {\n @if (\n (config.templating?.statusPosition || \"inline\") ===\n \"top-right\" &&\n (tr?.type === \"chip\" || tr?.type === \"icon\")\n ) {\n <div class=\"tile-status\">\n @if (tr?.type === \"chip\") {\n <mat-chip\n [color]=\"isThemeColor(tr.color) ? tr.color : undefined\"\n [ngClass]=\"\n (tr.variant || 'filled') === 'outlined'\n ? 'chip-outlined'\n : ''\n \"\n [style.cssText]=\"chipStyle(tr.color, tr.variant)\"\n >{{ tr.value }}</mat-chip\n >\n }\n @if (tr?.type === \"icon\") {\n <mat-icon\n [praxisIcon]=\"tr.value\"\n [color]=\"isThemeColor(tr.color) ? tr.color : undefined\"\n [style.cssText]=\"iconStyle(tr.color)\"\n ></mat-icon>\n }\n </div>\n }\n }\n\n <div class=\"tile-body\">\n <div\n class=\"primary\"\n [ngClass]=\"primary(it)?.class\"\n [style.cssText]=\"primary(it)?.style\"\n >\n @if (primary(it)?.type === \"metric\") {\n <praxis-list-metric [metric]=\"primary(it)\"></praxis-list-metric>\n } @else if (primary(it)?.type === \"compose\") {\n <praxis-list-compose\n [compose]=\"primary(it)\"\n ></praxis-list-compose>\n } @else if (primary(it)?.type === \"component\") {\n <praxis-list-runtime-component\n [component]=\"primary(it)\"\n ></praxis-list-runtime-component>\n } @else {\n {{ primary(it)?.value }}\n }\n </div>\n @if (layoutLines > 1) {\n <div\n class=\"secondary\"\n [ngClass]=\"secondary(it)?.class\"\n [style.cssText]=\"secondary(it)?.style\"\n >\n @if (secondary(it)?.type === \"metric\") {\n <praxis-list-metric\n [metric]=\"secondary(it)\"\n ></praxis-list-metric>\n } @else if (secondary(it)?.type === \"compose\") {\n <praxis-list-compose\n [compose]=\"secondary(it)\"\n ></praxis-list-compose>\n } @else if (secondary(it)?.type === \"component\") {\n <praxis-list-runtime-component\n [component]=\"secondary(it)\"\n ></praxis-list-runtime-component>\n } @else {\n {{ secondary(it)?.value }}\n }\n </div>\n }\n\n @if (meta(it); as m) {\n <div\n class=\"tile-meta\"\n [ngClass]=\"m.class\"\n [style.cssText]=\"m.style\"\n >\n @if (config.templating?.metaPrefixIcon; as mpi) {\n <mat-icon [praxisIcon]=\"mpi\"></mat-icon>\n }\n @switch (m.type) {\n @case (\"chip\") {\n <mat-chip\n [color]=\"isThemeColor(m.color) ? m.color : undefined\"\n [ngClass]=\"\n (m.variant || 'filled') === 'outlined'\n ? 'chip-outlined'\n : ''\n \"\n [style.cssText]=\"chipStyle(m.color, m.variant)\"\n >{{ m.value }}</mat-chip\n >\n }\n @case (\"rating\") {\n @for (\n _ of ratingRange(m);\n track $index;\n let idx = $index\n ) {\n <mat-icon\n [praxisIcon]=\"starIcon(idx, m.value)\"\n [color]=\"ratingThemeColor(m)\"\n [style.cssText]=\"ratingIconStyle(m)\"\n ></mat-icon>\n }\n }\n @case (\"icon\") {\n <mat-icon\n [praxisIcon]=\"m.value\"\n [color]=\"isThemeColor(m.color) ? m.color : undefined\"\n [style.cssText]=\"iconStyle(m.color)\"\n ></mat-icon>\n }\n @case (\"image\") {\n <span class=\"inline-image\"\n ><img [src]=\"m.value\" [alt]=\"m.imageAlt || ''\"\n /></span>\n }\n @case (\"html\") {\n <span [innerHTML]=\"m.value\"></span>\n }\n @case (\"metric\") {\n <praxis-list-metric [metric]=\"m\"></praxis-list-metric>\n }\n @case (\"compose\") {\n <praxis-list-compose\n [compose]=\"m\"\n ></praxis-list-compose>\n }\n @case (\"component\") {\n <praxis-list-runtime-component\n [component]=\"m\"\n ></praxis-list-runtime-component>\n }\n @default {\n <span>{{ m.value }}</span>\n }\n }\n </div>\n }\n\n @if (featuresVisible()) {\n <div class=\"tiles-features\">\n @for (\n f of config.templating?.features || [];\n track $index;\n let fi = $index\n ) {\n <span\n class=\"feature\"\n [ngClass]=\"featureSemanticClass(it, f.expr, f.class)\"\n >\n @if (f.icon && featuresMode() !== \"labels-only\") {\n <mat-icon [praxisIcon]=\"f.icon\"></mat-icon>\n }\n @if (featuresMode() !== \"icons-only\") {\n <span [ngClass]=\"f.class\" [style.cssText]=\"f.style\">\n @for (\n line of featureLabelLines(it, f.expr);\n track $index\n ) {\n <span class=\"feature-line\">{{ line }}</span>\n }\n </span>\n }\n @if (\n featureProgressPercent(it, f.expr, f.class);\n as progress\n ) {\n <span class=\"feature-progress\" aria-hidden=\"true\">\n <span\n class=\"feature-progress__value\"\n [style.width.%]=\"progress\"\n ></span>\n </span>\n }\n </span>\n }\n </div>\n }\n\n @if (trailing(it); as tr2) {\n @if (\n !(\n (config.templating?.statusPosition || \"inline\") ===\n \"top-right\" &&\n (tr2?.type === \"chip\" || tr2?.type === \"icon\")\n )\n ) {\n <div\n class=\"tile-trailing\"\n [ngClass]=\"tr2.class\"\n [style.cssText]=\"tr2.style\"\n >\n @switch (tr2.type) {\n @case (\"chip\") {\n <mat-chip\n [color]=\"\n isThemeColor(tr2.color) ? tr2.color : undefined\n \"\n [ngClass]=\"\n (tr2.variant || 'filled') === 'outlined'\n ? 'chip-outlined'\n : ''\n \"\n [style.cssText]=\"chipStyle(tr2.color, tr2.variant)\"\n >{{ tr2.value }}</mat-chip\n >\n }\n @case (\"icon\") {\n <mat-icon\n [praxisIcon]=\"tr2.value\"\n [color]=\"\n isThemeColor(tr2.color) ? tr2.color : undefined\n \"\n [style.cssText]=\"iconStyle(tr2.color)\"\n ></mat-icon>\n }\n @case (\"image\") {\n <span class=\"inline-image\"\n ><img [src]=\"tr2.value\" [alt]=\"tr2.imageAlt || ''\"\n /></span>\n }\n @case (\"rating\") {\n @for (\n _ of ratingRange(tr2);\n track $index;\n let idx = $index\n ) {\n <mat-icon\n [praxisIcon]=\"starIcon(idx, tr2.value)\"\n [color]=\"ratingThemeColor(tr2)\"\n [style.cssText]=\"ratingIconStyle(tr2)\"\n ></mat-icon>\n }\n }\n @case (\"html\") {\n <span [innerHTML]=\"tr2.value\"></span>\n }\n @case (\"metric\") {\n <praxis-list-metric [metric]=\"tr2\"></praxis-list-metric>\n }\n @case (\"compose\") {\n <praxis-list-compose\n [compose]=\"tr2\"\n ></praxis-list-compose>\n }\n @case (\"component\") {\n <praxis-list-runtime-component\n [component]=\"tr2\"\n ></praxis-list-runtime-component>\n }\n @default {\n <span>{{ tr2.value }}</span>\n }\n }\n </div>\n }\n }\n </div>\n\n @if ((visibleActions(it, \"trailing\") || []).length) {\n <div\n class=\"tile-actions\"\n (click)=\"$event.stopPropagation()\"\n (keydown.enter)=\"onActionKeydown($event)\"\n (keydown.space)=\"onActionKeydown($event)\"\n >\n @for (\n action of visibleActions(it, \"trailing\");\n let aidx = $index;\n track action?.id ?? $index\n ) {\n @if ((action.kind || \"icon\") === \"icon\") {\n <button\n mat-icon-button\n [color]=\"\n isThemeColor(action.color) ? action.color : undefined\n \"\n (click)=\"onActionClick($event, action.id, it, i)\"\n [attr.aria-label]=\"action.label || action.id\"\n [disabled]=\"isActionLoading(action.id, it, i)\"\n [ngClass]=\"{\n 'action-loading': isActionLoading(action.id, it, i),\n }\"\n >\n @if (isActionLoading(action.id, it, i)) {\n <mat-progress-spinner\n class=\"action-spinner\"\n mode=\"indeterminate\"\n diameter=\"16\"\n strokeWidth=\"3\"\n ></mat-progress-spinner>\n } @else {\n <mat-icon\n [praxisIcon]=\"action.icon\"\n [style.cssText]=\"iconStyle(action.color)\"\n ></mat-icon>\n }\n </button>\n } @else {\n @if (action.buttonVariant === \"stroked\") {\n <button\n mat-stroked-button\n [color]=\"\n isThemeColor(action.color) ? action.color : undefined\n \"\n [style.cssText]=\"buttonStyle(action.color, 'stroked')\"\n (click)=\"onActionClick($event, action.id, it, i)\"\n [attr.aria-label]=\"action.label || action.id\"\n [disabled]=\"isActionLoading(action.id, it, i)\"\n [ngClass]=\"{\n 'action-loading': isActionLoading(action.id, it, i),\n }\"\n >\n @if (isActionLoading(action.id, it, i)) {\n <mat-progress-spinner\n class=\"action-spinner\"\n mode=\"indeterminate\"\n diameter=\"16\"\n strokeWidth=\"3\"\n ></mat-progress-spinner>\n } @else {\n {{ action.label || action.id }}\n }\n </button>\n }\n @if (action.buttonVariant === \"raised\") {\n <button\n mat-raised-button\n [color]=\"\n isThemeColor(action.color) ? action.color : undefined\n \"\n [style.cssText]=\"buttonStyle(action.color, 'raised')\"\n (click)=\"onActionClick($event, action.id, it, i)\"\n [attr.aria-label]=\"action.label || action.id\"\n [disabled]=\"isActionLoading(action.id, it, i)\"\n [ngClass]=\"{\n 'action-loading': isActionLoading(action.id, it, i),\n }\"\n >\n @if (isActionLoading(action.id, it, i)) {\n <mat-progress-spinner\n class=\"action-spinner\"\n mode=\"indeterminate\"\n diameter=\"16\"\n strokeWidth=\"3\"\n ></mat-progress-spinner>\n } @else {\n {{ action.label || action.id }}\n }\n </button>\n }\n @if (\n !action.buttonVariant || action.buttonVariant === \"flat\"\n ) {\n <button\n mat-flat-button\n [color]=\"\n isThemeColor(action.color) ? action.color : undefined\n \"\n [style.cssText]=\"buttonStyle(action.color, 'flat')\"\n (click)=\"onActionClick($event, action.id, it, i)\"\n [attr.aria-label]=\"action.label || action.id\"\n [disabled]=\"isActionLoading(action.id, it, i)\"\n [ngClass]=\"{\n 'action-loading': isActionLoading(action.id, it, i),\n }\"\n >\n @if (isActionLoading(action.id, it, i)) {\n <mat-progress-spinner\n class=\"action-spinner\"\n mode=\"indeterminate\"\n diameter=\"16\"\n strokeWidth=\"3\"\n ></mat-progress-spinner>\n } @else {\n {{ action.label || action.id }}\n }\n </button>\n }\n }\n }\n </div>\n }\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 <div class=\"paginator-controls\">\n <button mat-stroked-button color=\"primary\" (click)=\"prevPage()\">\n Anterior\n </button>\n <button mat-stroked-button color=\"primary\" (click)=\"nextPage()\">\n Pr\u00F3ximo\n </button>\n <mat-form-field class=\"paginator-page-size\" appearance=\"outline\">\n <mat-label>Tam. p\u00E1gina</mat-label>\n <mat-select\n (selectionChange)=\"setPageSize($event.value)\"\n [value]=\"config.layout?.pageSize || 10\"\n >\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 (config.ui?.showSort) {\n <mat-form-field class=\"paginator-sort\" appearance=\"outline\">\n <mat-label>Ordenar</mat-label>\n <mat-select (selectionChange)=\"onSortChange($event.value)\">\n @for (op of config.ui?.sortOptions || []; track $index) {\n <mat-option [value]=\"sortOptionValue(op)\">{{\n sortOptionLabel(op)\n }}</mat-option>\n }\n </mat-select>\n </mat-form-field>\n }\n @if (config.ui?.showSearch && config.ui?.searchField) {\n <mat-form-field class=\"paginator-search\" appearance=\"outline\">\n <mat-label>{{\n config.ui?.searchPlaceholder || \"Buscar\"\n }}</mat-label>\n <input\n matInput\n type=\"search\"\n (input)=\"onSearchInput($any($event.target).value)\"\n />\n </mat-form-field>\n }\n </div>\n <div class=\"paginator-meta\">\n @if (config.ui?.showRange ?? true) {\n @if (page$ | async; as ps) {\n @if (total$ | async; as total) {\n @if (items$ | async; as curr) {\n <span class=\"muted\"\n >{{ (total || 0) > 0 ? rangeStart(ps) : 0 }}\u2013{{\n rangeEnd(curr?.length || 0, ps, total || 0)\n }}\n de {{ total || 0 }}</span\n >\n }\n }\n }\n } @else {\n @if (total$ | async; as total2) {\n <span class=\"muted\">Total: {{ total2 }}</span>\n }\n }\n </div>\n </div>\n }\n </ng-template>\n</div>\n", styles: ["@charset \"UTF-8\";:host{display:block}.praxis-list-root{--p-list-radius: var(--md-sys-shape-corner-medium, 16px);--p-list-shadow: var(--md-sys-elevation-level2);--p-list-border: 1px solid var(--md-sys-color-outline-variant);--p-list-blur: 10px;--p-list-surface: var(--md-sys-color-surface-container);--p-list-surface-low: var(--md-sys-color-surface);--p-list-surface-high: var( --md-sys-color-surface-container-high, var(--md-sys-color-surface-container) );--p-list-foreground: var(--md-sys-color-on-surface);--p-list-foreground-muted: var(--md-sys-color-on-surface-variant);--p-list-accent: var(--md-sys-color-primary);--p-list-accent-weak: var(--md-sys-color-primary-container);--p-list-item-surface: var( --md-sys-color-surface-container-low, var(--md-sys-color-surface) );--p-list-item-border: 1px solid var(--md-sys-color-outline-variant);--p-list-item-hover-surface: var(--md-sys-color-surface-container-low);--p-list-item-active-surface: var(--md-sys-color-surface-container);--p-list-item-selected-surface: var(--md-sys-color-surface-container);--p-list-grad-from: var(--md-sys-color-primary-container);--p-list-grad-to: var(--md-sys-color-tertiary-container);--p-list-grad-angle: 135deg;--p-list-grad-foreground: var(--md-sys-color-on-primary);--p-list-grad-foreground-muted: var(--md-sys-color-on-primary);--p-list-leading-width: 40px;--p-list-trailing-min-width: 140px;--p-list-item-gap: 12px;--p-list-item-padding-x: 16px;--p-list-item-padding-y: 12px;--p-list-item-stack-gap: 0px;--p-list-meta-size: .95rem;--p-list-meta-weight: 500;--p-list-chip-height: 22px;--p-list-chip-font-size: 12px;--p-list-trailing-padding-right: 12px;--p-list-tile-minW: 240px;--p-list-tile-gap: 16px;--p-list-tile-padding: 16px;--p-list-tile-radius: 16px;--p-list-tile-media-radius: 12px;--p-list-tile-media-ratio: 1 / 1;--p-list-tile-hover-overlay: .04;--p-list-tile-press-overlay: .08;--p-list-tile-press-scale: .99}.list-assistant{display:flex;justify-content:flex-end;gap:8px;padding:4px 4px 8px}.action-loading{opacity:.65}.action-spinner{width:16px;height:16px;display:inline-flex;align-items:center;justify-content:center}.action-loading .mat-mdc-button-touch-target,.action-loading .mdc-button__label{opacity:.7}.skin-elevated,.skin-outline,.skin-flat,.skin-neumorphism{--p-list-item-surface: var( --mdc-elevated-card-container-color, var(--p-list-surface) );--p-list-item-border: var(--p-list-border)}.skin-elevated .item-card,.skin-outline .item-card,.skin-flat .item-card,.skin-neumorphism .item-card{background:var(--mdc-elevated-card-container-color, var(--p-list-surface));border-radius:var(--p-list-radius);box-shadow:var(--p-list-shadow);border:var(--p-list-border)}.skin-elevated .item-tile,.skin-outline .item-tile,.skin-flat .item-tile,.skin-neumorphism .item-tile{background:var(--mdc-elevated-card-container-color, var(--p-list-surface));box-shadow:var(--p-list-shadow);border:var(--p-list-border)}.skin-elevated .mat-mdc-list-item .list-item-content,.skin-outline .mat-mdc-list-item .list-item-content,.skin-flat .mat-mdc-list-item .list-item-content,.skin-neumorphism .mat-mdc-list-item .list-item-content{background:var(--mdc-elevated-card-container-color, var(--p-list-surface));border-radius:calc(var(--p-list-radius) * .75);box-shadow:var(--p-list-shadow);border:var(--p-list-item-border);color:var(--p-list-foreground)}.skin-outline{--p-list-shadow: none;--p-list-border: 1px solid var(--md-sys-color-outline)}.skin-flat{--p-list-shadow: none;--p-list-border: 1px solid var(--md-sys-color-outline-variant)}.skin-neumorphism{--p-list-shadow: var(--md-sys-elevation-level2);--p-list-border: 1px solid var(--md-sys-color-outline-variant);--p-list-radius: 1.25rem}.skin-pill-soft .item-card,.skin-pill-soft .item-tile{background:var(--mdc-elevated-card-container-color, var(--p-list-surface));border-radius:calc(var(--p-list-radius) * 1.3);box-shadow:var(--md-sys-elevation-level1);border:var(--p-list-border)}.skin-pill-soft .mat-mdc-list-item .list-item-content{background:var(--mdc-elevated-card-container-color, var(--p-list-surface));border-radius:calc(var(--p-list-radius) * 1.3);box-shadow:var(--md-sys-elevation-level1);border:var(--p-list-border);color:var(--p-list-foreground)}.skin-gradient-tile{--p-list-foreground: var(--p-list-grad-foreground);--p-list-foreground-muted: var(--p-list-grad-foreground-muted);--p-list-item-hover-surface: linear-gradient( var(--p-list-grad-angle), var(--p-list-grad-from), var(--p-list-grad-to) );--p-list-item-active-surface: linear-gradient( var(--p-list-grad-angle), var(--p-list-grad-from), var(--p-list-grad-to) );--p-list-item-selected-surface: linear-gradient( var(--p-list-grad-angle), var(--p-list-grad-from), var(--p-list-grad-to) )}.skin-gradient-tile .item-card,.skin-gradient-tile .item-tile,.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:var(--p-list-foreground)}.skin-glass .item-card,.skin-glass .item-tile{background:var(--md-sys-color-surface-container-low);border-radius:var(--p-list-radius);border:1px solid var(--md-sys-color-outline-variant);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:var(--md-sys-color-surface-container-low);border-radius:var(--p-list-radius);border:1px solid var(--md-sys-color-outline-variant);backdrop-filter:blur(var(--p-list-blur));-webkit-backdrop-filter:blur(var(--p-list-blur));color:var(--p-list-foreground)}.density-compact .mat-mdc-list-item,.density-compact .item-card{--p-list-item-padding-y: 8px;--p-list-item-padding-x: 12px;--p-list-item-gap: 10px}.density-comfortable .mat-mdc-list-item,.density-comfortable .item-card{--p-list-item-padding-y: 10px;--p-list-item-padding-x: 14px;--p-list-item-gap: 12px}.praxis-list-root.lines-3 .mat-mdc-list-item,.praxis-list-root.lines-3 .mat-mdc-list-option{min-height:76px}.density-compact{--p-list-tile-gap: 12px;--p-list-tile-padding: 12px;--p-list-tile-minW: 200px}.density-comfortable{--p-list-tile-gap: 16px;--p-list-tile-padding: 16px}.item-spacing-none{--p-list-item-stack-gap: 0px}.item-spacing-tight{--p-list-item-stack-gap: 6px;--p-list-tile-gap: 12px}.item-spacing-default{--p-list-item-stack-gap: 10px;--p-list-tile-gap: 16px}.item-spacing-relaxed{--p-list-item-stack-gap: 14px;--p-list-tile-gap: 20px}.list-item-content{display:grid;grid-template-columns:var(--p-list-leading-width) minmax(0,1fr) minmax(var(--p-list-trailing-min-width),max-content);align-items:center;gap:var(--p-list-item-gap);padding:var(--p-list-item-padding-y) var(--p-list-item-padding-x);width:100%;min-width:0;border-radius:calc(var(--p-list-radius) * .75);overflow:visible}.list-item-content--row-layout{--p-list-row-template-columns: var(--p-list-leading-width) minmax(0, 1fr) minmax(var(--p-list-trailing-min-width), max-content);--p-list-row-gap: var(--p-list-item-gap);--p-list-row-align-items: center;grid-template-columns:var(--p-list-row-template-columns);gap:var(--p-list-row-gap);align-items:var(--p-list-row-align-items)}.list-item-content--row-layout[role=button]{cursor:pointer}.list-item-content--row-layout[role=button]:focus-visible{outline:2px solid var(--md-sys-color-primary);outline-offset:2px}.list-row-slot{min-width:0;display:flex;align-items:center;gap:8px}.list-row-slot--leading{justify-content:center}.list-row-slot--primary,.list-row-slot--secondary{min-width:0}.list-row-slot--meta{color:var(--p-list-foreground);font-variant-numeric:tabular-nums}.list-row-slot--trailing{flex-wrap:wrap;justify-content:flex-end}.list-row-slot .primary,.list-row-slot .secondary,.list-row-slot .meta,.list-row-slot .trailing{min-width:0}.list-item-main-action{grid-column:1/3;display:grid;grid-template-columns:var(--p-list-leading-width) minmax(0,1fr);align-items:center;gap:var(--p-list-item-gap);min-width:0;padding:0;border:0;background:transparent;color:inherit;text-align:start;font:inherit;cursor:pointer}.list-item-main-action:focus-visible{outline:2px solid var(--md-sys-color-primary);outline-offset:2px;border-radius:12px}.list-item-leading{display:flex;align-items:center;justify-content:center;min-height:100%}.leading-placeholder{width:24px;height:24px;display:inline-block}.list-item-text{min-width:0;display:grid;align-content:center;gap:4px}.list-item-trailing{min-width:0;display:flex;flex-direction:column;align-items:flex-end;justify-content:center;gap:6px;text-align:end;padding-right:var(--p-list-trailing-padding-right)}.list-item-content--row-layout .list-item-actions{justify-content:flex-end}.list-item-actions{display:flex;align-items:center;justify-content:flex-end;gap:4px;flex-wrap:wrap}.expand-toggle{color:var(--p-list-foreground-muted)}.mat-mdc-list-item .list-item-content{background:var(--p-list-item-surface);border:var(--p-list-item-border);transition:background .15s ease,box-shadow .15s ease,transform .15s ease}.mat-mdc-list-item,.mat-mdc-list-option{height:auto;align-items:stretch;overflow:visible}.mat-mdc-list-item.mdc-list-item--with-one-line,.mat-mdc-list-item.mdc-list-item--with-two-lines,.mat-mdc-list-item.mdc-list-item--with-three-lines,.mat-mdc-list-item-single-line,.mat-mdc-list-item-two-line,.mat-mdc-list-item-three-line,.mat-mdc-list-option.mdc-list-item--with-one-line,.mat-mdc-list-option.mdc-list-item--with-two-lines,.mat-mdc-list-option.mdc-list-item--with-three-lines{height:auto!important}.mdc-list-item{overflow:visible}.density-compact .mat-mdc-list-item,.density-compact .mat-mdc-list-option{min-height:44px}.density-comfortable .mat-mdc-list-item,.density-comfortable .mat-mdc-list-option{min-height:52px}.praxis-list-root:not(.density-compact):not(.density-comfortable) .mat-mdc-list-item,.praxis-list-root:not(.density-compact):not(.density-comfortable) .mat-mdc-list-option{min-height:56px}.mat-mdc-list-item .mdc-list-item__content,.mat-mdc-list-option .mdc-list-item__content,.mat-mdc-list-item .mdc-list-item__primary-text,.mat-mdc-list-option .mdc-list-item__primary-text{display:block!important;width:100%!important;height:auto!important;padding:0!important;margin:0!important;overflow:visible!important;box-sizing:border-box}.mat-mdc-list-item,.mat-mdc-list-option{padding:0!important;box-sizing:border-box}.praxis-list-root mat-list>mat-list-item:not(:last-child),.praxis-list-root mat-selection-list>mat-list-option:not(:last-child){margin-bottom:var(--p-list-item-stack-gap)}.mat-mdc-list-item:hover .list-item-content,.mat-mdc-list-option:hover .list-item-content{background:var(--p-list-item-hover-surface)}.mat-mdc-list-item:active .list-item-content,.mat-mdc-list-option:active .list-item-content{background:var(--p-list-item-active-surface)}.mat-mdc-list-option.mdc-list-item--selected .list-item-content{background:var(--p-list-item-selected-surface);border-color:var(--md-sys-color-outline-variant)}.mat-mdc-list-option.cdk-keyboard-focused .list-item-content,.mat-mdc-list-option.cdk-focused .list-item-content{outline:2px solid var(--md-sys-color-primary);outline-offset:2px}.mat-mdc-list-item:focus-visible .list-item-content{outline:2px solid var(--md-sys-color-primary);outline-offset:2px}.executive-inline-skin{--p-list-leading-width: 56px;--p-list-trailing-min-width: 232px;--p-list-item-padding-x: 14px;--p-list-item-padding-y: 8px;--p-list-item-gap: 10px;--p-list-surface: #f8fafb;--p-list-surface-low: #ffffff;--p-list-item-surface: #ffffff;--p-list-item-hover-surface: #f7fafc;--p-list-item-active-surface: #eef4f8;--p-list-item-selected-surface: #eef4f8;--p-list-foreground: #17324d;--p-list-foreground-muted: #72849a}.executive-inline-skin .list-item-content--row-layout.exec-row-layout{min-height:72px;padding:12px 20px;background:linear-gradient(180deg,#fff,#fbfcfd)!important;border:1px solid #dce5ec!important;border-radius:18px;box-shadow:0 1px 2px #0f223a08,0 4px 14px #0f223a08!important;color:#17324d!important}.executive-inline-skin .mat-mdc-list-item:hover .list-item-content--row-layout.exec-row-layout{background:linear-gradient(180deg,#fff,#f7fafc)!important}.executive-inline-skin .list-item-content--row-layout.exec-row-layout+.item-expansion{margin-left:10px;margin-right:10px}.executive-inline-skin .list-item-content--row-layout.exec-row-layout .list-row-slot{min-height:34px}.executive-inline-skin .list-row-slot--leading{justify-content:center}.executive-inline-skin .list-row-slot--identity{align-items:center;padding-right:4px}.executive-inline-skin .list-row-slot--balance,.executive-inline-skin .list-row-slot--limit,.executive-inline-skin .list-row-slot--risk,.executive-inline-skin .list-row-slot--alerts{justify-content:center;padding-inline:2px}.executive-inline-skin .list-row-slot--owner{justify-content:flex-start;padding-left:0}.executive-inline-skin .list-row-slot--actions{justify-content:flex-end;padding-left:0}.executive-inline-skin .list-row-slot--expand{justify-content:center}.executive-inline-skin .docs-expansion-leading{width:44px;height:44px;display:inline-flex;align-items:center;justify-content:center;border-radius:15px;background:linear-gradient(180deg,#edf4f9,#e6eef5);color:#1b5f86;font-size:1rem;font-weight:800;letter-spacing:.02em;box-shadow:0 1px 3px #1b5f861f;border:1px solid #dbe7f0}.executive-inline-skin .exec-balance-metric,.executive-inline-skin .exec-limit-metric,.executive-inline-skin .exec-risk-metric{min-width:0}.executive-inline-skin .exec-balance-metric .p-list-metric,.executive-inline-skin .exec-limit-metric .p-list-metric,.executive-inline-skin .exec-risk-metric .p-list-metric{gap:5px}.executive-inline-skin .exec-balance-metric .p-list-metric__label,.executive-inline-skin .exec-limit-metric .p-list-metric__label,.executive-inline-skin .exec-risk-metric .p-list-metric__label{font-size:.62rem;font-weight:700;letter-spacing:.08em;text-transform:uppercase;color:#8090a1}.executive-inline-skin .exec-balance-metric .p-list-metric__value,.executive-inline-skin .exec-limit-metric .p-list-metric__value{font-size:.96rem;font-weight:800;letter-spacing:-.02em;color:#0d1f34;line-height:1.05}.executive-inline-skin .exec-limit-metric .p-list-metric__caption{font-size:.66rem;font-weight:700;color:#8090a1}.executive-inline-skin .exec-limit-metric .p-list-metric__progress{width:68px;justify-self:center;height:3px}.executive-inline-skin .exec-risk-metric{min-width:84px}.executive-inline-skin .exec-risk-metric .p-list-metric{justify-items:center}.executive-inline-skin .exec-risk-metric .p-list-metric__main{gap:6px}.executive-inline-skin .exec-risk-metric .p-list-metric__value{font-size:1.02rem;font-weight:800;letter-spacing:-.024em;line-height:1}.executive-inline-skin .exec-risk-metric .p-list-metric__progress{width:56px;justify-self:center;height:3px}.executive-inline-skin .exec-risk-metric .p-list-metric__caption{font-size:.7rem;font-weight:700;line-height:1.1}.executive-inline-skin .exec-risk-metric .p-list-metric__caption--below-progress{justify-self:center;margin-top:-1px}.executive-inline-skin .exec-risk-metric .p-list-metric__icon mat-icon{width:15px;height:15px;font-size:15px}.executive-inline-skin .list-item-actions{gap:6px;flex-wrap:nowrap}.executive-inline-skin .list-row-slot--actions .list-item-actions{justify-content:flex-end}.executive-inline-skin .list-item-actions button,.executive-inline-skin .expand-toggle{width:30px;height:30px;min-width:30px;border-radius:12px;color:#6d7f93!important}.executive-inline-skin .list-item-actions button mat-icon,.executive-inline-skin .expand-toggle mat-icon{width:18px;height:18px;font-size:18px}.executive-inline-skin .item-expansion{position:relative;margin-top:-10px;padding:22px 26px;background:linear-gradient(180deg,#fcfdfe,#f5f8fb);border-color:#e4eaf0;border-radius:0 0 22px 22px;box-shadow:inset 0 1px #ffffffdb}.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}.inline-image{position:relative;width:20px;height:20px;border-radius:4px;overflow:hidden;display:inline-block;vertical-align:middle}.inline-image img{width:100%;height:100%;object-fit:cover;display:block}.inline-image .inline-badge{position:absolute;left:2px;bottom:2px}.model-media .lead-image{width:136px;height:96px;border-radius:16px}.model-media .list-item-content{gap:16px}.model-media .item-card{--p-list-leading-width: 136px}.model-hotel .lead-image{width:160px;height:110px;border-radius:18px}.model-hotel .item-card{--p-list-leading-width: 160px}.primary,.secondary{display:-webkit-box;-webkit-box-orient:vertical;overflow:hidden;text-overflow:ellipsis}.primary{-webkit-line-clamp:1;font-weight:600;color:var(--p-list-foreground)}.secondary{-webkit-line-clamp:1;color:var(--p-list-foreground-muted)}.lines-3 .tertiary{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.item-tile .primary{-webkit-line-clamp:2;font-size:.95rem;line-height:1.25rem}.item-tile .secondary{-webkit-line-clamp:2;font-size:.8rem;line-height:1.1rem}.tertiary{color:var(--p-list-foreground-muted)}.features{display:flex;flex-wrap:wrap;gap:12px;margin-top:6px;color:inherit}.feature{display:inline-flex;align-items:center;gap:6px}.feature-line{display:block}.feature-progress{display:block;width:88px;height:4px;margin-top:6px;border-radius:999px;background:#dbe5eb;overflow:hidden}.feature-progress__value{display:block;height:100%;border-radius:inherit;background:#2f9b69}.meta{color:var(--p-list-foreground);font-size:var(--p-list-meta-size);font-weight:var(--p-list-meta-weight);font-variant-numeric:tabular-nums;white-space:nowrap}.trailing{color:var(--p-list-foreground-muted);margin-left:0;white-space:nowrap}.section-header{font-size:.85rem;color:var(--p-list-foreground-muted);padding:8px 12px}.praxis-list-root mat-list,.praxis-list-root mat-selection-list{display:block;padding-bottom:12px}.praxis-list-root .mat-divider{margin-left:var(--p-list-item-padding-x);margin-right:var(--p-list-item-padding-x)}.item-expansion{margin:0 var(--p-list-item-padding-x) var(--p-list-item-stack-gap);padding:14px 16px;background:color-mix(in srgb,var(--p-list-surface) 88%,white 12%);border:1px solid var(--md-sys-color-outline-variant);border-radius:calc(var(--p-list-radius) * .75)}.item-expansion-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(220px,1fr));gap:16px}.expansion-section{min-width:0;display:grid;gap:10px;align-content:start}.expansion-section-title{font-size:.78rem;font-weight:700;letter-spacing:.04em;text-transform:uppercase;color:var(--p-list-foreground-muted)}.expansion-info-list,.expansion-timeline,.expansion-key-value{display:grid;gap:10px}.expansion-info-item,.expansion-timeline-item{display:grid;gap:4px;padding:10px 12px;border-radius:14px;background:var(--p-list-item-surface);border:1px solid color-mix(in srgb,var(--md-sys-color-outline-variant) 72%,transparent 28%)}.expansion-info-title,.expansion-timeline-title{font-size:.92rem;font-weight:600;color:var(--p-list-foreground)}.expansion-info-value,.expansion-timeline-meta,.expansion-timeline-description,.expansion-empty{font-size:.82rem;line-height:1.45;color:var(--p-list-foreground-muted)}.expansion-chip-list{display:flex;flex-wrap:wrap;gap:8px}.expansion-chip{background:var(--p-list-item-surface);border:1px solid var(--md-sys-color-outline-variant)}.expansion-key-value{margin:0}.expansion-key-value-row{display:grid;gap:4px;padding:10px 12px;border-radius:14px;background:var(--p-list-item-surface);border:1px solid color-mix(in srgb,var(--md-sys-color-outline-variant) 72%,transparent 28%)}.expansion-key-value-row dt,.expansion-key-value-row dd{margin:0}.expansion-key-value-row dt{font-size:.78rem;font-weight:600;color:var(--p-list-foreground-muted)}.expansion-key-value-row dd{font-size:.9rem;color:var(--p-list-foreground)}.cards-grid,.tiles-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(var(--p-list-tile-minW),1fr));gap:var(--p-list-tile-gap)}.item-tile{position:relative;display:flex;flex-direction:column;gap:10px;padding:var(--p-list-tile-padding);border-radius:var(--p-list-tile-radius);background:var(--p-list-surface);border:var(--p-list-border);color:var(--p-list-foreground);cursor:pointer;min-height:160px;transition:box-shadow .16s ease-out,border-color .16s ease-out,transform .12s ease-out,background .16s ease-out}.item-tile:hover{box-shadow:var(--md-sys-elevation-level2);border-color:var(--md-sys-color-outline-variant);background:var(--p-list-item-hover-surface)}.item-tile:active{transform:scale(var(--p-list-tile-press-scale));background:var(--p-list-item-active-surface)}.item-tile:focus-visible{outline:2px solid var(--md-sys-color-primary);outline-offset:2px}.tile-media{width:100%;aspect-ratio:var(--p-list-tile-media-ratio);border-radius:var(--p-list-tile-media-radius);background:var(--p-list-item-surface);border:1px solid var(--md-sys-color-outline-variant);display:grid;place-items:center;overflow:hidden}.tile-media img{width:100%;height:100%;object-fit:cover;display:block}.tile-media mat-icon{font-size:28px;height:28px;width:28px;color:var(--p-list-foreground-muted)}.tile-body{display:grid;gap:6px;min-width:0}.tile-meta{display:inline-flex;align-items:center;gap:6px;font-size:.75rem;color:var(--p-list-foreground-muted);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.tile-trailing{font-size:.75rem;color:var(--p-list-foreground-muted);white-space:nowrap}.tiles-features{display:flex;flex-wrap:wrap;gap:8px;color:inherit}.tile-status{position:absolute;top:10px;right:10px}.tile-actions{position:absolute;top:8px;left:8px;display:flex;gap:4px;opacity:0;pointer-events:none;transform:translateY(-2px);transition:opacity .16s ease-out,transform .16s ease-out}.item-tile:hover .tile-actions,.item-tile:focus-visible .tile-actions,.item-tile:focus-within .tile-actions{opacity:1;pointer-events:auto;transform:translateY(0)}@media(hover:none){.tile-actions{opacity:1;pointer-events:auto;transform:none}}@media(max-width:600px){.tiles-grid{grid-template-columns:repeat(auto-fit,minmax(200px,1fr))}}@media(prefers-reduced-motion:reduce){.item-tile,.tile-actions{transition:none}.item-tile:active{transform:none}.item-card{transition:none}.item-card:active{transform:none}}.item-card{padding:var(--p-list-tile-padding);display:flex;flex-direction:column;min-height:160px;position:relative;cursor:pointer;background:var(--p-list-surface);border:var(--p-list-border);border-radius:var(--p-list-tile-radius);box-shadow:var(--p-list-shadow);transition:box-shadow .16s ease-out,border-color .16s ease-out,transform .12s ease-out,background .16s ease-out;--p-list-leading-width: 96px;--p-list-trailing-min-width: 0px}.item-card .list-item-trailing{min-width:var(--p-list-trailing-min-width)}.item-card:hover{box-shadow:var(--md-sys-elevation-level3);border-color:var(--md-sys-color-outline-variant);background:var(--p-list-item-hover-surface)}.item-card:active{transform:scale(var(--p-list-tile-press-scale));background:var(--p-list-item-active-surface)}.item-card:focus-visible{outline:2px solid var(--md-sys-color-primary);outline-offset:2px}.card-actions{display:flex;align-items:center;justify-content:flex-end;gap:4px;padding:6px 8px 4px;border-top:1px solid var(--md-sys-color-outline-variant);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:var(--md-sys-color-primary-container);color:var(--md-sys-color-on-primary-container)}.mat-mdc-chip{--mdc-chip-container-height: var(--p-list-chip-height);font-size:var(--p-list-chip-font-size)}.meta .mat-icon{font-size:18px;height:18px;width:18px}.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:linear-gradient(to right,var(--md-sys-color-surface-container-low) 8%,var(--md-sys-color-surface-container) 18%,var(--md-sys-color-surface-container-low) 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;flex-wrap:wrap;gap:8px;margin-top:14px;padding:14px 4px 8px;border-top:1px solid var(--md-sys-color-outline-variant);position:relative;z-index:1;background:var(--p-list-surface-low);border-radius:calc(var(--p-list-radius) * .75)}.paginator-controls{display:flex;align-items:center;gap:8px;flex-wrap:wrap}.paginator-meta{display:flex;align-items:center;gap:8px;margin-left:auto}.paginator-page-size{width:120px}.paginator-sort{width:180px}.paginator-search{min-width:220px}.muted{color:var(--p-list-foreground-muted)}@media(max-width:720px){.list-item-content{grid-template-columns:var(--p-list-leading-width) minmax(0,1fr)}.list-item-trailing{grid-column:1/-1;padding-right:0;align-items:flex-start;text-align:start}.item-expansion{margin-left:0;margin-right:0}.paginator{align-items:stretch}.paginator-controls{width:100%}.paginator-meta{width:100%;margin-left:0;justify-content:flex-start}.paginator-page-size,.paginator-sort,.paginator-search{width:100%;min-width:0}}\n"] }]
9959
+ ], changeDetection: ChangeDetectionStrategy.OnPush, providers: [GenericCrudService, ListDataService, providePraxisListI18n()], template: "<div\n class=\"praxis-list-root\"\n [ngClass]=\"skinClasses\"\n [attr.data-skin-scope]=\"skinScopeId\"\n [attr.aria-label]=\"config.a11y?.ariaLabel || null\"\n [attr.aria-labelledby]=\"config.a11y?.ariaLabelledBy || null\"\n>\n @if (inlineCss) {\n <style [attr.nonce]=\"cspNonce || null\" [textContent]=\"inlineCss\"></style>\n }\n\n @if (enableCustomization) {\n <div class=\"list-assistant\">\n <button\n mat-mini-fab\n type=\"button\"\n color=\"primary\"\n (click)=\"openConfigEditor()\"\n [matTooltip]=\"configEditorLabel()\"\n [attr.aria-label]=\"configEditorLabel()\"\n data-testid=\"praxis-list-open-config-editor\"\n >\n <mat-icon [praxisIcon]=\"'edit'\"></mat-icon>\n </button>\n <praxis-ai-assistant [adapter]=\"aiAdapter\"></praxis-ai-assistant>\n </div>\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=\"list-item-leading\">\n <div class=\"skeleton skeleton-avatar\"></div>\n </div>\n <div class=\"list-item-text\">\n <div class=\"skeleton skeleton-line w-60\"></div>\n @if (layoutLines > 1) {\n <div class=\"skeleton skeleton-line w-40\"></div>\n }\n </div>\n <div class=\"list-item-trailing\">\n <div class=\"skeleton skeleton-chip\"></div>\n </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=\"list-item-leading\">\n <div class=\"skeleton skeleton-avatar\"></div>\n </div>\n <div class=\"list-item-text\">\n <div class=\"skeleton skeleton-line w-60\"></div>\n @if (layoutLines > 1) {\n <div class=\"skeleton skeleton-line w-40\"></div>\n }\n </div>\n <div class=\"list-item-trailing\">\n <div class=\"skeleton skeleton-chip\"></div>\n </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 @if (emptyStateTemplate(); as empty) {\n @if (\n simpleRichContentNodes(empty, {\n imageAlt: config.templating?.emptyState?.imageAlt || \"\",\n });\n as richNodes\n ) {\n <praxis-rich-content [nodes]=\"richNodes\"></praxis-rich-content>\n } @else {\n @switch (empty.type) {\n @case (\"icon\") {\n <mat-icon\n [praxisIcon]=\"empty.value\"\n [ngClass]=\"empty.class\"\n [color]=\"isThemeColor(empty.color) ? empty.color : undefined\"\n [style.cssText]=\"\n (empty.style ? empty.style + ';' : '') +\n iconStyle(empty.color)\n \"\n ></mat-icon>\n }\n @case (\"image\") {\n <span\n class=\"inline-image\"\n [ngClass]=\"empty.class\"\n [style.cssText]=\"empty.style\"\n >\n <img\n [src]=\"empty.value\"\n [alt]=\"config.templating?.emptyState?.imageAlt || ''\"\n />\n @if (empty.badge?.value) {\n <mat-chip\n class=\"inline-badge\"\n [color]=\"\n isThemeColor(empty.badge?.color)\n ? empty.badge?.color\n : undefined\n \"\n [ngClass]=\"\n (empty.badge?.variant || 'filled') === 'outlined'\n ? 'chip-outlined'\n : ''\n \"\n [style.cssText]=\"\n chipStyle(empty.badge?.color, empty.badge?.variant)\n \"\n >{{ empty.badge?.value }}</mat-chip\n >\n }\n </span>\n }\n @case (\"chip\") {\n <mat-chip\n [color]=\"isThemeColor(empty.color) ? empty.color : undefined\"\n [ngClass]=\"[\n empty.class || '',\n (empty.variant || 'filled') === 'outlined'\n ? 'chip-outlined'\n : '',\n ]\"\n [style.cssText]=\"\n chipStyle(empty.color, empty.variant) +\n (empty.style ? ';' + empty.style : '')\n \"\n >{{ empty.value }}</mat-chip\n >\n }\n @case (\"rating\") {\n <span [ngClass]=\"empty.class\" [style.cssText]=\"empty.style\">\n @for (\n _ of ratingRange(empty);\n track $index;\n let idx = $index\n ) {\n <mat-icon\n [praxisIcon]=\"starIcon(idx, empty.value)\"\n [color]=\"ratingThemeColor(empty)\"\n [style.cssText]=\"ratingIconStyle(empty)\"\n ></mat-icon>\n }\n </span>\n }\n @case (\"html\") {\n <span\n [ngClass]=\"empty.class\"\n [style.cssText]=\"empty.style\"\n [innerHTML]=\"empty.value\"\n ></span>\n }\n @case (\"metric\") {\n <praxis-list-metric [metric]=\"empty\"></praxis-list-metric>\n }\n @case (\"compose\") {\n <praxis-list-compose [compose]=\"empty\"></praxis-list-compose>\n }\n @case (\"component\") {\n <praxis-list-runtime-component\n [component]=\"empty\"\n ></praxis-list-runtime-component>\n }\n @default {\n <span [ngClass]=\"empty.class\" [style.cssText]=\"empty.style\">{{\n empty.value\n }}</span>\n }\n }\n }\n }\n </div>\n }\n }\n\n <ng-template\n #rowLayoutNode\n let-node\n let-slot=\"slot\"\n let-imageAlt=\"imageAlt\"\n >\n @if (simpleRichContentNodes(node, { slot: slot, imageAlt: imageAlt }); as richNodes) {\n <praxis-rich-content [nodes]=\"richNodes\"></praxis-rich-content>\n } @else {\n @switch (node?.type) {\n @case (\"icon\") {\n <mat-icon\n [praxisIcon]=\"node?.value\"\n [ngClass]=\"node?.class\"\n [color]=\"isThemeColor(node?.color) ? node?.color : undefined\"\n [style.cssText]=\"\n ((node?.style || '') ? node.style + ';' : '') +\n iconStyle(node?.color)\n \"\n ></mat-icon>\n }\n @case (\"image\") {\n <span\n class=\"inline-image\"\n [ngClass]=\"node?.class\"\n [style.cssText]=\"node?.style\"\n >\n <img [src]=\"node?.value\" [alt]=\"node?.imageAlt || imageAlt || ''\" />\n @if (node?.badge?.value) {\n <mat-chip\n class=\"inline-badge\"\n [color]=\"\n isThemeColor(node?.badge?.color)\n ? node?.badge?.color\n : undefined\n \"\n [ngClass]=\"\n (node?.badge?.variant || 'filled') === 'outlined'\n ? 'chip-outlined'\n : ''\n \"\n [style.cssText]=\"\n chipStyle(node?.badge?.color, node?.badge?.variant)\n \"\n >\n {{ node?.badge?.value }}\n </mat-chip>\n }\n </span>\n }\n @case (\"chip\") {\n <mat-chip\n [color]=\"isThemeColor(node?.color) ? node?.color : undefined\"\n [ngClass]=\"[\n node?.class || '',\n (node?.variant || 'filled') === 'outlined' ? 'chip-outlined' : '',\n ]\"\n [style.cssText]=\"\n chipStyle(node?.color, node?.variant) +\n (node?.style ? ';' + node.style : '')\n \"\n >\n {{ node?.value }}\n </mat-chip>\n }\n @case (\"rating\") {\n <span [ngClass]=\"node?.class\" [style.cssText]=\"node?.style\">\n @for (_ of ratingRange(node); track $index; let idx = $index) {\n <mat-icon\n [praxisIcon]=\"starIcon(idx, node?.value)\"\n [color]=\"ratingThemeColor(node)\"\n [style.cssText]=\"ratingIconStyle(node)\"\n ></mat-icon>\n }\n </span>\n }\n @case (\"html\") {\n <span\n [ngClass]=\"node?.class\"\n [style.cssText]=\"node?.style\"\n [innerHTML]=\"node?.value\"\n ></span>\n }\n @case (\"metric\") {\n <praxis-list-metric [metric]=\"node\"></praxis-list-metric>\n }\n @case (\"compose\") {\n <praxis-list-compose [compose]=\"node\"></praxis-list-compose>\n }\n @case (\"component\") {\n <praxis-list-runtime-component\n [component]=\"node\"\n ></praxis-list-runtime-component>\n }\n @default {\n <span [ngClass]=\"node?.class\" [style.cssText]=\"node?.style\">\n @if (slot === \"meta\" && config.templating?.metaPrefixIcon; as mpi) {\n <mat-icon [praxisIcon]=\"mpi\"></mat-icon>\n }\n {{ node?.value }}\n </span>\n }\n }\n }\n </ng-template>\n\n <ng-template\n #listRowLayout\n let-item\n let-index=\"index\"\n let-sectionKey=\"sectionKey\"\n let-clickable=\"clickable\"\n >\n <div\n class=\"list-item-content\"\n [ngClass]=\"rowLayoutItemClass(item)\"\n [attr.style]=\"rowLayoutItemStyle(item)\"\n [attr.role]=\"clickable ? 'button' : null\"\n [attr.tabindex]=\"clickable ? '0' : null\"\n [attr.aria-label]=\"clickable ? itemAriaLabel(item) : null\"\n [attr.aria-expanded]=\"\n clickable && expansionOwnedByRow() ? isExpanded(item, index) : null\n \"\n [attr.aria-controls]=\"\n clickable && expansionOwnedByRow()\n ? expandRegionId(item, index)\n : null\n \"\n (click)=\"clickable ? onRowActivate(item, index, sectionKey) : null\"\n (keydown.enter)=\"clickable ? onRowActivate(item, index, sectionKey) : null\"\n (keydown.space)=\"\n onRowSpaceActivate($event, clickable, item, index, sectionKey)\n \"\n >\n @for (column of rowLayoutColumns(); track rowLayoutTrackColumn($index, column)) {\n <div\n [attr.data-row-slot]=\"column.slot\"\n [ngClass]=\"rowLayoutColumnClass(column)\"\n [attr.style]=\"rowLayoutColumnStyle(column)\"\n >\n @if (column.slot === \"leading\") {\n @if (rowLayoutSlot(item, column.slot); as lead) {\n <ng-container\n *ngTemplateOutlet=\"\n rowLayoutNode;\n context: {\n $implicit: lead,\n slot: column.slot,\n imageAlt: rowLayoutImageAlt(column.slot),\n }\n \"\n ></ng-container>\n } @else {\n <span class=\"leading-placeholder\"></span>\n }\n } @else if (column.slot === \"trailing\") {\n @if (rowLayoutSlot(item, column.slot); as trailingNode) {\n <ng-container\n *ngTemplateOutlet=\"\n rowLayoutNode;\n context: {\n $implicit: trailingNode,\n slot: column.slot,\n imageAlt: rowLayoutImageAlt(column.slot),\n }\n \"\n ></ng-container>\n }\n @if (showExpandIcon(\"trailing\")) {\n <button\n mat-icon-button\n type=\"button\"\n class=\"expand-toggle\"\n [attr.aria-label]=\"expandToggleAriaLabel(item, index)\"\n [attr.aria-expanded]=\"\n expansionOwnedByIcon() ? isExpanded(item, index) : null\n \"\n [attr.aria-controls]=\"\n expansionOwnedByIcon()\n ? expandRegionId(item, index)\n : null\n \"\n (click)=\"onExpandToggle($event, item, index)\"\n >\n <mat-icon\n [praxisIcon]=\"\n isExpanded(item, index) ? 'expand_less' : 'expand_more'\n \"\n ></mat-icon>\n </button>\n }\n @if ((visibleActions(item, \"trailing\") || []).length) {\n <div\n class=\"list-item-actions\"\n (click)=\"$event.stopPropagation()\"\n (keydown.enter)=\"onActionKeydown($event)\"\n (keydown.space)=\"onActionKeydown($event)\"\n >\n @for (\n action of visibleActions(item, \"trailing\");\n let aidx = $index;\n track action?.id ?? $index\n ) {\n @if ((action.kind || \"icon\") === \"icon\") {\n <button\n mat-icon-button\n [color]=\"\n isThemeColor(action.color) ? action.color : undefined\n \"\n (click)=\"onActionClick($event, action.id, item, index)\"\n [attr.aria-label]=\"action.label || action.id\"\n [disabled]=\"isActionLoading(action.id, item, index)\"\n [ngClass]=\"{\n 'action-loading': isActionLoading(\n action.id,\n item,\n index\n ),\n }\"\n >\n @if (isActionLoading(action.id, item, index)) {\n <mat-progress-spinner\n class=\"action-spinner\"\n mode=\"indeterminate\"\n diameter=\"16\"\n strokeWidth=\"3\"\n ></mat-progress-spinner>\n } @else {\n <mat-icon\n [praxisIcon]=\"action.icon\"\n [style.cssText]=\"iconStyle(action.color)\"\n ></mat-icon>\n }\n </button>\n } @else {\n @if (action.buttonVariant === \"stroked\") {\n <button\n mat-stroked-button\n [color]=\"\n isThemeColor(action.color) ? action.color : undefined\n \"\n [style.cssText]=\"buttonStyle(action.color, 'stroked')\"\n (click)=\"onActionClick($event, action.id, item, index)\"\n [attr.aria-label]=\"action.label || action.id\"\n [disabled]=\"isActionLoading(action.id, item, index)\"\n [ngClass]=\"{\n 'action-loading': isActionLoading(\n action.id,\n item,\n index\n ),\n }\"\n >\n @if (isActionLoading(action.id, item, index)) {\n <mat-progress-spinner\n class=\"action-spinner\"\n mode=\"indeterminate\"\n diameter=\"16\"\n strokeWidth=\"3\"\n ></mat-progress-spinner>\n } @else {\n {{ action.label || action.id }}\n }\n </button>\n }\n @if (action.buttonVariant === \"raised\") {\n <button\n mat-raised-button\n [color]=\"\n isThemeColor(action.color) ? action.color : undefined\n \"\n [style.cssText]=\"buttonStyle(action.color, 'raised')\"\n (click)=\"onActionClick($event, action.id, item, index)\"\n [attr.aria-label]=\"action.label || action.id\"\n [disabled]=\"isActionLoading(action.id, item, index)\"\n [ngClass]=\"{\n 'action-loading': isActionLoading(\n action.id,\n item,\n index\n ),\n }\"\n >\n @if (isActionLoading(action.id, item, index)) {\n <mat-progress-spinner\n class=\"action-spinner\"\n mode=\"indeterminate\"\n diameter=\"16\"\n strokeWidth=\"3\"\n ></mat-progress-spinner>\n } @else {\n {{ action.label || action.id }}\n }\n </button>\n }\n @if (!action.buttonVariant || action.buttonVariant === \"flat\") {\n <button\n mat-flat-button\n [color]=\"\n isThemeColor(action.color) ? action.color : undefined\n \"\n [style.cssText]=\"buttonStyle(action.color, 'flat')\"\n (click)=\"onActionClick($event, action.id, item, index)\"\n [attr.aria-label]=\"action.label || action.id\"\n [disabled]=\"isActionLoading(action.id, item, index)\"\n [ngClass]=\"{\n 'action-loading': isActionLoading(\n action.id,\n item,\n index\n ),\n }\"\n >\n @if (isActionLoading(action.id, item, index)) {\n <mat-progress-spinner\n class=\"action-spinner\"\n mode=\"indeterminate\"\n diameter=\"16\"\n strokeWidth=\"3\"\n ></mat-progress-spinner>\n } @else {\n {{ action.label || action.id }}\n }\n </button>\n }\n }\n }\n </div>\n }\n } @else if (column.slot === \"actions\") {\n @if ((visibleActions(item, \"actions\") || []).length) {\n <div\n class=\"list-item-actions\"\n (click)=\"$event.stopPropagation()\"\n (keydown.enter)=\"onActionKeydown($event)\"\n (keydown.space)=\"onActionKeydown($event)\"\n >\n @for (\n action of visibleActions(item, \"actions\");\n let aidx = $index;\n track action?.id ?? $index\n ) {\n @if ((action.kind || \"icon\") === \"icon\") {\n <button\n mat-icon-button\n [color]=\"\n isThemeColor(action.color) ? action.color : undefined\n \"\n (click)=\"onActionClick($event, action.id, item, index)\"\n [attr.aria-label]=\"action.label || action.id\"\n [disabled]=\"isActionLoading(action.id, item, index)\"\n [ngClass]=\"{\n 'action-loading': isActionLoading(\n action.id,\n item,\n index\n ),\n }\"\n >\n @if (isActionLoading(action.id, item, index)) {\n <mat-progress-spinner\n class=\"action-spinner\"\n mode=\"indeterminate\"\n diameter=\"16\"\n strokeWidth=\"3\"\n ></mat-progress-spinner>\n } @else {\n <mat-icon\n [praxisIcon]=\"action.icon\"\n [style.cssText]=\"iconStyle(action.color)\"\n ></mat-icon>\n }\n </button>\n } @else {\n @if (action.buttonVariant === \"stroked\") {\n <button\n mat-stroked-button\n [color]=\"\n isThemeColor(action.color) ? action.color : undefined\n \"\n [style.cssText]=\"buttonStyle(action.color, 'stroked')\"\n (click)=\"onActionClick($event, action.id, item, index)\"\n [attr.aria-label]=\"action.label || action.id\"\n [disabled]=\"isActionLoading(action.id, item, index)\"\n [ngClass]=\"{\n 'action-loading': isActionLoading(\n action.id,\n item,\n index\n ),\n }\"\n >\n @if (isActionLoading(action.id, item, index)) {\n <mat-progress-spinner\n class=\"action-spinner\"\n mode=\"indeterminate\"\n diameter=\"16\"\n strokeWidth=\"3\"\n ></mat-progress-spinner>\n } @else {\n {{ action.label || action.id }}\n }\n </button>\n }\n @if (action.buttonVariant === \"raised\") {\n <button\n mat-raised-button\n [color]=\"\n isThemeColor(action.color) ? action.color : undefined\n \"\n [style.cssText]=\"buttonStyle(action.color, 'raised')\"\n (click)=\"onActionClick($event, action.id, item, index)\"\n [attr.aria-label]=\"action.label || action.id\"\n [disabled]=\"isActionLoading(action.id, item, index)\"\n [ngClass]=\"{\n 'action-loading': isActionLoading(\n action.id,\n item,\n index\n ),\n }\"\n >\n @if (isActionLoading(action.id, item, index)) {\n <mat-progress-spinner\n class=\"action-spinner\"\n mode=\"indeterminate\"\n diameter=\"16\"\n strokeWidth=\"3\"\n ></mat-progress-spinner>\n } @else {\n {{ action.label || action.id }}\n }\n </button>\n }\n @if (!action.buttonVariant || action.buttonVariant === \"flat\") {\n <button\n mat-flat-button\n [color]=\"\n isThemeColor(action.color) ? action.color : undefined\n \"\n [style.cssText]=\"buttonStyle(action.color, 'flat')\"\n (click)=\"onActionClick($event, action.id, item, index)\"\n [attr.aria-label]=\"action.label || action.id\"\n [disabled]=\"isActionLoading(action.id, item, index)\"\n [ngClass]=\"{\n 'action-loading': isActionLoading(\n action.id,\n item,\n index\n ),\n }\"\n >\n @if (isActionLoading(action.id, item, index)) {\n <mat-progress-spinner\n class=\"action-spinner\"\n mode=\"indeterminate\"\n diameter=\"16\"\n strokeWidth=\"3\"\n ></mat-progress-spinner>\n } @else {\n {{ action.label || action.id }}\n }\n </button>\n }\n }\n }\n </div>\n }\n } @else if (column.slot === \"expand\") {\n @if (showExpandIcon(\"expand\")) {\n <button\n mat-icon-button\n type=\"button\"\n class=\"expand-toggle\"\n [attr.aria-label]=\"expandToggleAriaLabel(item, index)\"\n [attr.aria-expanded]=\"\n expansionOwnedByIcon() ? isExpanded(item, index) : null\n \"\n [attr.aria-controls]=\"\n expansionOwnedByIcon()\n ? expandRegionId(item, index)\n : null\n \"\n (click)=\"onExpandToggle($event, item, index)\"\n >\n <mat-icon\n [praxisIcon]=\"\n isExpanded(item, index) ? 'expand_less' : 'expand_more'\n \"\n ></mat-icon>\n </button>\n }\n } @else if (rowLayoutSlot(item, column.slot); as slotNode) {\n <ng-container\n *ngTemplateOutlet=\"\n rowLayoutNode;\n context: {\n $implicit: slotNode,\n slot: column.slot,\n imageAlt: rowLayoutImageAlt(column.slot),\n }\n \"\n ></ng-container>\n }\n </div>\n }\n </div>\n </ng-template>\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 (\n section of sections$ | async;\n track trackBySection($index, section)\n ) {\n @if (section.key) {\n <div class=\"section-header mat-subheader\">\n @if (sectionHeaderTemplate(section.key); as sh) {\n @if (\n simpleRichContentNodes(sh, {\n imageAlt: config.templating?.sectionHeader?.imageAlt || \"\",\n });\n as richNodes\n ) {\n <praxis-rich-content [nodes]=\"richNodes\"></praxis-rich-content>\n } @else {\n @switch (sh.type) {\n @case (\"icon\") {\n <mat-icon\n [praxisIcon]=\"sh.value\"\n [ngClass]=\"sh.class\"\n [color]=\"isThemeColor(sh.color) ? sh.color : undefined\"\n [style.cssText]=\"\n (sh.style ? sh.style + ';' : '') + iconStyle(sh.color)\n \"\n ></mat-icon>\n }\n @case (\"image\") {\n <span\n class=\"inline-image\"\n [ngClass]=\"sh.class\"\n [style.cssText]=\"sh.style\"\n >\n <img\n [src]=\"sh.value\"\n [alt]=\"\n config.templating?.sectionHeader?.imageAlt || ''\n \"\n />\n @if (sh.badge?.value) {\n <mat-chip\n class=\"inline-badge\"\n [color]=\"\n isThemeColor(sh.badge?.color)\n ? sh.badge?.color\n : undefined\n \"\n [ngClass]=\"\n (sh.badge?.variant || 'filled') === 'outlined'\n ? 'chip-outlined'\n : ''\n \"\n [style.cssText]=\"\n chipStyle(sh.badge?.color, sh.badge?.variant)\n \"\n >{{ sh.badge?.value }}</mat-chip\n >\n }\n </span>\n }\n @case (\"chip\") {\n <mat-chip\n [color]=\"isThemeColor(sh.color) ? sh.color : undefined\"\n [ngClass]=\"[\n sh.class || '',\n (sh.variant || 'filled') === 'outlined'\n ? 'chip-outlined'\n : '',\n ]\"\n [style.cssText]=\"\n chipStyle(sh.color, sh.variant) +\n (sh.style ? ';' + sh.style : '')\n \"\n >{{ sh.value }}</mat-chip\n >\n }\n @case (\"rating\") {\n <span [ngClass]=\"sh.class\" [style.cssText]=\"sh.style\">\n @for (\n _ of ratingRange(sh);\n track $index;\n let idx = $index\n ) {\n <mat-icon\n [praxisIcon]=\"starIcon(idx, sh.value)\"\n [color]=\"ratingThemeColor(sh)\"\n [style.cssText]=\"ratingIconStyle(sh)\"\n ></mat-icon>\n }\n </span>\n }\n @case (\"html\") {\n <span\n [ngClass]=\"sh.class\"\n [style.cssText]=\"sh.style\"\n [innerHTML]=\"sh.value\"\n ></span>\n }\n @case (\"metric\") {\n <praxis-list-metric [metric]=\"sh\"></praxis-list-metric>\n }\n @case (\"compose\") {\n <praxis-list-compose [compose]=\"sh\"></praxis-list-compose>\n }\n @case (\"component\") {\n <praxis-list-runtime-component\n [component]=\"sh\"\n ></praxis-list-runtime-component>\n }\n @default {\n <span [ngClass]=\"sh.class\" [style.cssText]=\"sh.style\">{{\n sh.value\n }}</span>\n }\n }\n }\n }\n </div>\n }\n @for (\n item of section.items;\n track trackByItem($index, item);\n let i = $index\n ) {\n <mat-list-option\n [value]=\"item\"\n [attr.aria-label]=\"itemAriaLabel(item)\"\n >\n @if (hasRowLayoutGrid()) {\n <ng-container\n *ngTemplateOutlet=\"\n listRowLayout;\n context: {\n $implicit: item,\n index: i,\n sectionKey: section.key || undefined,\n clickable: false,\n }\n \"\n ></ng-container>\n } @else {\n <div\n class=\"list-item-content\"\n [ngClass]=\"itemRuleClass(item)\"\n [attr.style]=\"itemRuleStyle(item)\"\n >\n <div class=\"list-item-leading\">\n @if (leading(item); as lead) {\n @if (\n simpleRichContentNodes(lead, {\n imageAlt: config.templating?.leading?.imageAlt || \"\",\n });\n as richNodes\n ) {\n <praxis-rich-content [nodes]=\"richNodes\"></praxis-rich-content>\n } @else {\n @switch (lead.type) {\n @case (\"icon\") {\n <mat-icon\n [praxisIcon]=\"lead.value\"\n [ngClass]=\"lead.class\"\n [color]=\"\n isThemeColor(lead.color) ? lead.color : undefined\n \"\n [style.cssText]=\"\n (lead.style ? lead.style + ';' : '') +\n iconStyle(lead.color)\n \"\n ></mat-icon>\n }\n @case (\"image\") {\n <div\n class=\"lead-image\"\n [ngClass]=\"lead.class\"\n [style.cssText]=\"lead.style\"\n >\n <img\n [src]=\"lead.value\"\n [alt]=\"config.templating?.leading?.imageAlt || ''\"\n />\n @if (lead.badge?.value) {\n <mat-chip\n class=\"lead-badge\"\n [color]=\"\n isThemeColor(lead.badge?.color)\n ? lead.badge?.color\n : undefined\n \"\n [ngClass]=\"\n (lead.badge?.variant || 'filled') ===\n 'outlined'\n ? 'chip-outlined'\n : ''\n \"\n [style.cssText]=\"\n chipStyle(\n lead.badge?.color,\n lead.badge?.variant\n )\n \"\n >{{ lead.badge?.value }}</mat-chip\n >\n }\n </div>\n }\n @case (\"text\") {\n <span\n [ngClass]=\"lead.class\"\n [style.cssText]=\"lead.style\"\n >{{ lead.value }}</span\n >\n }\n @case (\"chip\") {\n <mat-chip\n [color]=\"\n isThemeColor(lead.color) ? lead.color : undefined\n \"\n [ngClass]=\"\n (lead.variant || 'filled') === 'outlined'\n ? 'chip-outlined'\n : ''\n \"\n [style.cssText]=\"\n chipStyle(lead.color, lead.variant)\n \"\n >{{ lead.value }}</mat-chip\n >\n }\n @case (\"rating\") {\n <span\n [ngClass]=\"lead.class\"\n [style.cssText]=\"lead.style\"\n >\n @for (\n _ of ratingRange(lead);\n track $index;\n let idx = $index\n ) {\n <mat-icon\n [praxisIcon]=\"starIcon(idx, lead.value)\"\n [color]=\"ratingThemeColor(lead)\"\n [style.cssText]=\"ratingIconStyle(lead)\"\n ></mat-icon>\n }\n </span>\n }\n @case (\"html\") {\n <span\n [ngClass]=\"lead.class\"\n [style.cssText]=\"lead.style\"\n [innerHTML]=\"lead.value\"\n ></span>\n }\n @case (\"metric\") {\n <praxis-list-metric [metric]=\"lead\"></praxis-list-metric>\n }\n @case (\"compose\") {\n <praxis-list-compose\n [compose]=\"lead\"\n ></praxis-list-compose>\n }\n @case (\"component\") {\n <praxis-list-runtime-component\n [component]=\"lead\"\n ></praxis-list-runtime-component>\n }\n @default {\n <span\n [ngClass]=\"lead.class\"\n [style.cssText]=\"lead.style\"\n >{{ lead.value }}</span\n >\n }\n }\n }\n } @else {\n <span class=\"leading-placeholder\"></span>\n }\n </div>\n <div class=\"list-item-text\">\n <div\n class=\"primary\"\n [ngClass]=\"primary(item)?.class\"\n [style.cssText]=\"primary(item)?.style\"\n >\n @if (simpleRichContentNodes(primary(item)); as richNodes) {\n <praxis-rich-content [nodes]=\"richNodes\"></praxis-rich-content>\n } @else if (primary(item)?.type === \"metric\") {\n <praxis-list-metric\n [metric]=\"primary(item)\"\n ></praxis-list-metric>\n } @else if (primary(item)?.type === \"compose\") {\n <praxis-list-compose\n [compose]=\"primary(item)\"\n ></praxis-list-compose>\n } @else if (primary(item)?.type === \"component\") {\n <praxis-list-runtime-component\n [component]=\"primary(item)\"\n ></praxis-list-runtime-component>\n } @else {\n {{ primary(item)?.value }}\n }\n </div>\n @if (layoutLines > 1) {\n <div\n class=\"secondary\"\n [ngClass]=\"secondary(item)?.class\"\n [style.cssText]=\"secondary(item)?.style\"\n >\n @if (simpleRichContentNodes(secondary(item)); as richNodes) {\n <praxis-rich-content [nodes]=\"richNodes\"></praxis-rich-content>\n } @else if (secondary(item)?.type === \"metric\") {\n <praxis-list-metric\n [metric]=\"secondary(item)\"\n ></praxis-list-metric>\n } @else if (secondary(item)?.type === \"compose\") {\n <praxis-list-compose\n [compose]=\"secondary(item)\"\n ></praxis-list-compose>\n } @else if (secondary(item)?.type === \"component\") {\n <praxis-list-runtime-component\n [component]=\"secondary(item)\"\n ></praxis-list-runtime-component>\n } @else {\n {{ secondary(item)?.value }}\n }\n </div>\n }\n @if (meta(item); as m) {\n @if (\n (config.templating?.metaPlacement === \"line\" &&\n (m?.type === \"text\" ||\n m?.type === \"date\" ||\n m?.type === \"currency\")) ||\n (layoutLines > 2 &&\n (m?.type === \"text\" ||\n m?.type === \"date\" ||\n m?.type === \"currency\"))\n ) {\n <div\n class=\"tertiary\"\n [ngClass]=\"m.class\"\n [style.cssText]=\"m.style\"\n >\n @if (config.templating?.metaPrefixIcon; as mpi) {\n <mat-icon [praxisIcon]=\"mpi\"></mat-icon>\n }\n {{ m.value }}\n </div>\n }\n }\n @if (featuresVisible()) {\n <div class=\"features\">\n @for (\n f of config.templating?.features || [];\n track $index;\n let fi = $index\n ) {\n <span\n class=\"feature\"\n [ngClass]=\"\n featureSemanticClass(item, f.expr, f.class)\n \"\n >\n @if (featureRichContentNodes(item, f); as featureNodes) {\n <praxis-rich-content [nodes]=\"featureNodes\"></praxis-rich-content>\n } @else {\n @if (f.icon && featuresMode() !== \"labels-only\") {\n <mat-icon [praxisIcon]=\"f.icon\"></mat-icon>\n }\n @if (featuresMode() !== \"icons-only\") {\n <span\n [ngClass]=\"f.class\"\n [style.cssText]=\"f.style\"\n >\n @for (\n line of featureLabelLines(item, f.expr);\n track $index\n ) {\n <span class=\"feature-line\">{{ line }}</span>\n }\n </span>\n }\n }\n @if (\n featureProgressPercent(item, f.expr, f.class);\n as progress\n ) {\n <span class=\"feature-progress\" aria-hidden=\"true\">\n <span\n class=\"feature-progress__value\"\n [style.width.%]=\"progress\"\n ></span>\n </span>\n }\n </span>\n }\n </div>\n }\n </div>\n <div class=\"list-item-trailing\">\n @if (meta(item); as m) {\n @if (\n !(\n (config.templating?.metaPlacement === \"line\" ||\n layoutLines > 2) &&\n (m?.type === \"text\" ||\n m?.type === \"date\" ||\n m?.type === \"currency\")\n )\n ) {\n <div\n class=\"meta\"\n [ngClass]=\"m.class\"\n [style.cssText]=\"m.style\"\n >\n @if (simpleRichContentNodes(m, { slot: 'meta' }); as richNodes) {\n <praxis-rich-content [nodes]=\"richNodes\"></praxis-rich-content>\n } @else {\n @switch (m.type) {\n @case (\"chip\") {\n <mat-chip\n [color]=\"\n isThemeColor(m.color) ? m.color : undefined\n \"\n [ngClass]=\"\n (m.variant || 'filled') === 'outlined'\n ? 'chip-outlined'\n : ''\n \"\n [style.cssText]=\"chipStyle(m.color, m.variant)\"\n >{{ m.value }}</mat-chip\n >\n }\n @case (\"rating\") {\n @for (\n _ of ratingRange(m);\n track $index;\n let idx = $index\n ) {\n <mat-icon\n [praxisIcon]=\"starIcon(idx, m.value)\"\n [color]=\"ratingThemeColor(m)\"\n [style.cssText]=\"ratingIconStyle(m)\"\n ></mat-icon>\n }\n }\n @case (\"icon\") {\n <mat-icon\n [praxisIcon]=\"m.value\"\n [color]=\"\n isThemeColor(m.color) ? m.color : undefined\n \"\n [style.cssText]=\"iconStyle(m.color)\"\n ></mat-icon>\n }\n @case (\"image\") {\n <span class=\"inline-image\"\n ><img [src]=\"m.value\" [alt]=\"m.imageAlt || ''\"\n /></span>\n }\n @case (\"html\") {\n <span [innerHTML]=\"m.value\"></span>\n }\n @case (\"metric\") {\n <praxis-list-metric [metric]=\"m\"></praxis-list-metric>\n }\n @case (\"compose\") {\n <praxis-list-compose\n [compose]=\"m\"\n ></praxis-list-compose>\n }\n @case (\"component\") {\n <praxis-list-runtime-component\n [component]=\"m\"\n ></praxis-list-runtime-component>\n }\n @default {\n <span>\n @if (\n config.templating?.metaPrefixIcon;\n as mpi2\n ) {\n <mat-icon [praxisIcon]=\"mpi2\"></mat-icon>\n }\n {{ m.value }}</span\n >\n }\n }\n }\n </div>\n }\n }\n @if (trailing(item); as tr) {\n <div\n class=\"trailing\"\n [ngClass]=\"tr.class\"\n [style.cssText]=\"tr.style\"\n >\n @if (\n simpleRichContentNodes(tr, {\n imageAlt: config.templating?.trailing?.imageAlt || \"\",\n });\n as richNodes\n ) {\n <praxis-rich-content [nodes]=\"richNodes\"></praxis-rich-content>\n } @else {\n @switch (tr.type) {\n @case (\"chip\") {\n <mat-chip\n [color]=\"\n isThemeColor(tr.color) ? tr.color : undefined\n \"\n [ngClass]=\"\n (tr.variant || 'filled') === 'outlined'\n ? 'chip-outlined'\n : ''\n \"\n [style.cssText]=\"chipStyle(tr.color, tr.variant)\"\n >{{ tr.value }}</mat-chip\n >\n }\n @case (\"icon\") {\n <mat-icon\n [praxisIcon]=\"tr.value\"\n [color]=\"\n isThemeColor(tr.color) ? tr.color : undefined\n \"\n [style.cssText]=\"iconStyle(tr.color)\"\n ></mat-icon>\n }\n @case (\"image\") {\n <div\n class=\"lead-image\"\n [ngClass]=\"tr.class\"\n [style.cssText]=\"tr.style\"\n >\n <img\n [src]=\"tr.value\"\n [alt]=\"\n config.templating?.trailing?.imageAlt || ''\n \"\n />\n @if (tr.badge?.value) {\n <mat-chip\n class=\"lead-badge\"\n [color]=\"\n isThemeColor(tr.badge?.color)\n ? tr.badge?.color\n : undefined\n \"\n [ngClass]=\"\n (tr.badge?.variant || 'filled') ===\n 'outlined'\n ? 'chip-outlined'\n : ''\n \"\n [style.cssText]=\"\n chipStyle(\n tr.badge?.color,\n tr.badge?.variant\n )\n \"\n >{{ tr.badge?.value }}</mat-chip\n >\n }\n </div>\n }\n @case (\"rating\") {\n @for (\n _ of ratingRange(tr);\n track $index;\n let idx = $index\n ) {\n <mat-icon\n [praxisIcon]=\"starIcon(idx, tr.value)\"\n [color]=\"ratingThemeColor(tr)\"\n [style.cssText]=\"ratingIconStyle(tr)\"\n ></mat-icon>\n }\n }\n @case (\"html\") {\n @if (item.alertsData !== undefined && item.ownerName) {\n <!-- Component-based rendering for executive trailing -->\n <span class=\"exec-trailing-shell\">\n <praxis-executive-alerts [alerts]=\"item.alertsData\"></praxis-executive-alerts>\n <praxis-executive-owner [name]=\"item.ownerName\"></praxis-executive-owner>\n </span>\n } @else {\n <span [innerHTML]=\"tr.value\"></span>\n }\n }\n @case (\"metric\") {\n <praxis-list-metric [metric]=\"tr\"></praxis-list-metric>\n }\n @case (\"compose\") {\n <praxis-list-compose\n [compose]=\"tr\"\n ></praxis-list-compose>\n }\n @case (\"component\") {\n <praxis-list-runtime-component\n [component]=\"tr\"\n ></praxis-list-runtime-component>\n }\n @default {\n <span>{{ tr.value }}</span>\n }\n }\n }\n </div>\n }\n @if (showExpandIcon(\"trailing\")) {\n <button\n mat-icon-button\n type=\"button\"\n class=\"expand-toggle\"\n [attr.aria-label]=\"expandToggleAriaLabel(item, i)\"\n [attr.aria-expanded]=\"\n expansionOwnedByIcon() ? isExpanded(item, i) : null\n \"\n [attr.aria-controls]=\"\n expansionOwnedByIcon()\n ? expandRegionId(item, i)\n : null\n \"\n (click)=\"onExpandToggle($event, item, i)\"\n >\n <mat-icon\n [praxisIcon]=\"\n isExpanded(item, i) ? 'expand_less' : 'expand_more'\n \"\n ></mat-icon>\n </button>\n }\n @if ((visibleActions(item, \"trailing\") || []).length) {\n <div\n class=\"list-item-actions\"\n (click)=\"$event.stopPropagation()\"\n (keydown.enter)=\"onActionKeydown($event)\"\n (keydown.space)=\"onActionKeydown($event)\"\n >\n @for (\n action of visibleActions(item, \"trailing\");\n let aidx = $index;\n track action?.id ?? $index\n ) {\n @if ((action.kind || \"icon\") === \"icon\") {\n <button\n mat-icon-button\n [color]=\"\n isThemeColor(action.color)\n ? action.color\n : undefined\n \"\n (click)=\"\n onActionClick($event, action.id, item, i)\n \"\n [attr.aria-label]=\"action.label || action.id\"\n [disabled]=\"isActionLoading(action.id, item, i)\"\n [ngClass]=\"{\n 'action-loading': isActionLoading(\n action.id,\n item,\n i\n ),\n }\"\n >\n @if (isActionLoading(action.id, item, i)) {\n <mat-progress-spinner\n class=\"action-spinner\"\n mode=\"indeterminate\"\n diameter=\"16\"\n strokeWidth=\"3\"\n ></mat-progress-spinner>\n } @else {\n <mat-icon\n [praxisIcon]=\"action.icon\"\n [style.cssText]=\"iconStyle(action.color)\"\n ></mat-icon>\n }\n </button>\n } @else {\n @if (action.buttonVariant === \"stroked\") {\n <button\n mat-stroked-button\n [color]=\"\n isThemeColor(action.color)\n ? action.color\n : undefined\n \"\n [style.cssText]=\"\n buttonStyle(action.color, 'stroked')\n \"\n (click)=\"\n onActionClick($event, action.id, item, i)\n \"\n [attr.aria-label]=\"action.label || action.id\"\n [disabled]=\"isActionLoading(action.id, item, i)\"\n [ngClass]=\"{\n 'action-loading': isActionLoading(\n action.id,\n item,\n i\n ),\n }\"\n >\n @if (isActionLoading(action.id, item, i)) {\n <mat-progress-spinner\n class=\"action-spinner\"\n mode=\"indeterminate\"\n diameter=\"16\"\n strokeWidth=\"3\"\n ></mat-progress-spinner>\n } @else {\n {{ action.label || action.id }}\n }\n </button>\n }\n @if (action.buttonVariant === \"raised\") {\n <button\n mat-raised-button\n [color]=\"\n isThemeColor(action.color)\n ? action.color\n : undefined\n \"\n [style.cssText]=\"\n buttonStyle(action.color, 'raised')\n \"\n (click)=\"\n onActionClick($event, action.id, item, i)\n \"\n [attr.aria-label]=\"action.label || action.id\"\n [disabled]=\"isActionLoading(action.id, item, i)\"\n [ngClass]=\"{\n 'action-loading': isActionLoading(\n action.id,\n item,\n i\n ),\n }\"\n >\n @if (isActionLoading(action.id, item, i)) {\n <mat-progress-spinner\n class=\"action-spinner\"\n mode=\"indeterminate\"\n diameter=\"16\"\n strokeWidth=\"3\"\n ></mat-progress-spinner>\n } @else {\n {{ action.label || action.id }}\n }\n </button>\n }\n @if (\n !action.buttonVariant ||\n action.buttonVariant === \"flat\"\n ) {\n <button\n mat-flat-button\n [color]=\"\n isThemeColor(action.color)\n ? action.color\n : undefined\n \"\n [style.cssText]=\"\n buttonStyle(action.color, 'flat')\n \"\n (click)=\"\n onActionClick($event, action.id, item, i)\n \"\n [attr.aria-label]=\"action.label || action.id\"\n [disabled]=\"isActionLoading(action.id, item, i)\"\n [ngClass]=\"{\n 'action-loading': isActionLoading(\n action.id,\n item,\n i\n ),\n }\"\n >\n @if (isActionLoading(action.id, item, i)) {\n <mat-progress-spinner\n class=\"action-spinner\"\n mode=\"indeterminate\"\n diameter=\"16\"\n strokeWidth=\"3\"\n ></mat-progress-spinner>\n } @else {\n {{ action.label || action.id }}\n }\n </button>\n }\n }\n }\n </div>\n }\n </div>\n </div>\n }\n @if (isExpandable() && isExpanded(item, i)) {\n <div\n class=\"item-expansion\"\n [id]=\"expandRegionId(item, i)\"\n role=\"region\"\n [attr.aria-label]=\"expansionRegionAriaLabel(item)\"\n >\n <div class=\"item-expansion-grid\">\n @for (\n expansionSection of expansionSections(item);\n track expansionSection.id\n ) {\n <section\n class=\"expansion-section\"\n [attr.data-section-type]=\"expansionSection.type\"\n >\n @if (expansionSection.title) {\n <div class=\"expansion-section-title\">\n {{ expansionSection.title }}\n </div>\n }\n @if (\n expansionSectionHasContent(\n item,\n expansionSection,\n i\n )\n ) {\n @switch (expansionSection.type) {\n @case (\"chip-list\") {\n <div class=\"expansion-chip-list\">\n @for (\n expansionEntry of expansionSectionItems(\n item,\n expansionSection,\n i\n );\n track $index\n ) {\n <mat-chip class=\"expansion-chip\">{{\n expansionItemLabel(expansionEntry)\n }}</mat-chip>\n }\n </div>\n }\n @case (\"timeline\") {\n <div class=\"expansion-timeline\">\n @for (\n expansionEntry of expansionSectionItems(\n item,\n expansionSection,\n i\n );\n track $index\n ) {\n <div class=\"expansion-timeline-item\">\n <div class=\"expansion-timeline-title\">\n {{\n expansionTimelineTitle(expansionEntry)\n }}\n </div>\n @if (\n expansionTimelineMeta(expansionEntry)\n ) {\n <div class=\"expansion-timeline-meta\">\n {{\n expansionTimelineMeta(\n expansionEntry\n )\n }}\n </div>\n }\n @if (\n expansionTimelineDescription(\n expansionEntry\n )\n ) {\n <div\n class=\"expansion-timeline-description\"\n >\n {{\n expansionTimelineDescription(\n expansionEntry\n )\n }}\n </div>\n }\n </div>\n }\n </div>\n }\n @case (\"key-value\") {\n <dl class=\"expansion-key-value\">\n @for (\n expansionEntry of expansionSectionItems(\n item,\n expansionSection,\n i\n );\n track $index\n ) {\n <div class=\"expansion-key-value-row\">\n @if (\n expansionKeyValueKey(expansionEntry)\n ) {\n <dt>\n {{\n expansionKeyValueKey(expansionEntry)\n }}\n </dt>\n }\n <dd>\n {{\n expansionKeyValueValue(expansionEntry)\n }}\n </dd>\n </div>\n }\n </dl>\n }\n @default {\n <div class=\"expansion-info-list\">\n @for (\n expansionEntry of expansionSectionItems(\n item,\n expansionSection,\n i\n );\n track $index\n ) {\n <div class=\"expansion-info-item\">\n <div class=\"expansion-info-title\">\n {{ expansionInfoTitle(expansionEntry) }}\n </div>\n @if (expansionInfoValue(expansionEntry)) {\n <div class=\"expansion-info-value\">\n {{\n expansionInfoValue(expansionEntry)\n }}\n </div>\n }\n </div>\n }\n </div>\n }\n }\n } @else {\n <div class=\"expansion-empty\">\n {{\n expansionSection.emptyLabel ||\n \"Sem dados dispon\u00EDveis\"\n }}\n </div>\n }\n </section>\n }\n </div>\n </div>\n }\n </mat-list-option>\n @if (\n (config.layout?.dividers === \"all\" ||\n config.layout?.dividers === \"between\") &&\n i < section.items.length - 1\n ) {\n <mat-divider></mat-divider>\n }\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 (\n section of sections$ | async;\n track trackBySection($index, section);\n let sidx = $index\n ) {\n @if (section.key) {\n <div class=\"section-header mat-subheader\">\n @if (sectionHeaderTemplate(section.key); as sh) {\n @if (\n simpleRichContentNodes(sh, {\n imageAlt: config.templating?.sectionHeader?.imageAlt || \"\",\n });\n as richNodes\n ) {\n <praxis-rich-content [nodes]=\"richNodes\"></praxis-rich-content>\n } @else {\n @switch (sh.type) {\n @case (\"icon\") {\n <mat-icon\n [praxisIcon]=\"sh.value\"\n [ngClass]=\"sh.class\"\n [color]=\"isThemeColor(sh.color) ? sh.color : undefined\"\n [style.cssText]=\"\n (sh.style ? sh.style + ';' : '') + iconStyle(sh.color)\n \"\n ></mat-icon>\n }\n @case (\"image\") {\n <span\n class=\"inline-image\"\n [ngClass]=\"sh.class\"\n [style.cssText]=\"sh.style\"\n >\n <img\n [src]=\"sh.value\"\n [alt]=\"\n config.templating?.sectionHeader?.imageAlt || ''\n \"\n />\n @if (sh.badge?.value) {\n <mat-chip\n class=\"inline-badge\"\n [color]=\"\n isThemeColor(sh.badge?.color)\n ? sh.badge?.color\n : undefined\n \"\n [ngClass]=\"\n (sh.badge?.variant || 'filled') === 'outlined'\n ? 'chip-outlined'\n : ''\n \"\n [style.cssText]=\"\n chipStyle(sh.badge?.color, sh.badge?.variant)\n \"\n >{{ sh.badge?.value }}</mat-chip\n >\n }\n </span>\n }\n @case (\"chip\") {\n <mat-chip\n [color]=\"isThemeColor(sh.color) ? sh.color : undefined\"\n [ngClass]=\"[\n sh.class || '',\n (sh.variant || 'filled') === 'outlined'\n ? 'chip-outlined'\n : '',\n ]\"\n [style.cssText]=\"\n chipStyle(sh.color, sh.variant) +\n (sh.style ? ';' + sh.style : '')\n \"\n >{{ sh.value }}</mat-chip\n >\n }\n @case (\"rating\") {\n <span [ngClass]=\"sh.class\" [style.cssText]=\"sh.style\">\n @for (\n _ of ratingRange(sh);\n track $index;\n let idx = $index\n ) {\n <mat-icon\n [praxisIcon]=\"starIcon(idx, sh.value)\"\n [color]=\"ratingThemeColor(sh)\"\n [style.cssText]=\"ratingIconStyle(sh)\"\n ></mat-icon>\n }\n </span>\n }\n @case (\"html\") {\n <span\n [ngClass]=\"sh.class\"\n [style.cssText]=\"sh.style\"\n [innerHTML]=\"sh.value\"\n ></span>\n }\n @case (\"metric\") {\n <praxis-list-metric [metric]=\"sh\"></praxis-list-metric>\n }\n @default {\n <span [ngClass]=\"sh.class\" [style.cssText]=\"sh.style\">{{\n sh.value\n }}</span>\n }\n }\n }\n }\n </div>\n }\n @for (\n item of section.items;\n track trackByItem($index, item);\n let i = $index\n ) {\n <mat-list-item [attr.data-item-status]=\"item?.status || null\">\n @if (hasRowLayoutGrid()) {\n <ng-container\n *ngTemplateOutlet=\"\n listRowLayout;\n context: {\n $implicit: item,\n index: i,\n sectionKey: section.key || undefined,\n clickable: true,\n }\n \"\n ></ng-container>\n } @else {\n <div\n class=\"list-item-content\"\n [ngClass]=\"itemRuleClass(item)\"\n [attr.style]=\"itemRuleStyle(item)\"\n >\n <button\n type=\"button\"\n class=\"list-item-main-action\"\n [attr.aria-label]=\"itemAriaLabel(item)\"\n [attr.aria-expanded]=\"\n expansionOwnedByRow() ? isExpanded(item, i) : null\n \"\n [attr.aria-controls]=\"\n expansionOwnedByRow() ? expandRegionId(item, i) : null\n \"\n (click)=\"onRowActivate(item, i, section.key || undefined)\"\n >\n <div class=\"list-item-leading\">\n @if (leading(item); as lead) {\n @if (\n simpleRichContentNodes(lead, {\n imageAlt: config.templating?.leading?.imageAlt || \"\",\n });\n as richNodes\n ) {\n <praxis-rich-content [nodes]=\"richNodes\"></praxis-rich-content>\n } @else {\n @switch (lead.type) {\n @case (\"icon\") {\n <mat-icon\n [praxisIcon]=\"lead.value\"\n [ngClass]=\"lead.class\"\n [color]=\"\n isThemeColor(lead.color)\n ? lead.color\n : undefined\n \"\n [style.cssText]=\"\n (lead.style ? lead.style + ';' : '') +\n iconStyle(lead.color)\n \"\n ></mat-icon>\n }\n @case (\"image\") {\n <div\n class=\"lead-image\"\n [ngClass]=\"lead.class\"\n [style.cssText]=\"lead.style\"\n >\n <img\n [src]=\"lead.value\"\n [alt]=\"\n config.templating?.leading?.imageAlt || ''\n \"\n />\n @if (lead.badge?.value) {\n <mat-chip\n class=\"lead-badge\"\n [color]=\"\n isThemeColor(lead.badge?.color)\n ? lead.badge?.color\n : undefined\n \"\n [ngClass]=\"\n (lead.badge?.variant || 'filled') ===\n 'outlined'\n ? 'chip-outlined'\n : ''\n \"\n [style.cssText]=\"\n chipStyle(\n lead.badge?.color,\n lead.badge?.variant\n )\n \"\n >{{ lead.badge?.value }}</mat-chip\n >\n }\n </div>\n }\n @case (\"text\") {\n <span\n [ngClass]=\"lead.class\"\n [style.cssText]=\"lead.style\"\n >{{ lead.value }}</span\n >\n }\n @case (\"chip\") {\n <mat-chip\n [color]=\"\n isThemeColor(lead.color)\n ? lead.color\n : undefined\n \"\n [ngClass]=\"\n (lead.variant || 'filled') === 'outlined'\n ? 'chip-outlined'\n : ''\n \"\n [style.cssText]=\"\n chipStyle(lead.color, lead.variant)\n \"\n >{{ lead.value }}</mat-chip\n >\n }\n @case (\"rating\") {\n @for (\n _ of ratingRange(lead);\n track $index;\n let idx = $index\n ) {\n <mat-icon\n [praxisIcon]=\"starIcon(idx, lead.value)\"\n [color]=\"ratingThemeColor(lead)\"\n [style.cssText]=\"ratingIconStyle(lead)\"\n ></mat-icon>\n }\n }\n @case (\"html\") {\n <span\n [ngClass]=\"lead.class\"\n [style.cssText]=\"lead.style\"\n [innerHTML]=\"lead.value\"\n ></span>\n }\n @case (\"metric\") {\n <praxis-list-metric [metric]=\"lead\"></praxis-list-metric>\n }\n @default {\n <span\n [ngClass]=\"lead.class\"\n [style.cssText]=\"lead.style\"\n >{{ lead.value }}</span\n >\n }\n }\n }\n } @else {\n <span class=\"leading-placeholder\"></span>\n }\n </div>\n <div class=\"list-item-text\">\n <div\n class=\"primary\"\n [ngClass]=\"primary(item)?.class\"\n [style.cssText]=\"primary(item)?.style\"\n >\n @if (simpleRichContentNodes(primary(item)); as richNodes) {\n <praxis-rich-content [nodes]=\"richNodes\"></praxis-rich-content>\n } @else if (primary(item)?.type === \"metric\") {\n <praxis-list-metric\n [metric]=\"primary(item)\"\n ></praxis-list-metric>\n } @else if (primary(item)?.type === \"html\") {\n <span [innerHTML]=\"primary(item)?.value\"></span>\n } @else {\n {{ primary(item)?.value }}\n }\n </div>\n @if (layoutLines > 1) {\n <div\n class=\"secondary\"\n [ngClass]=\"secondary(item)?.class\"\n [style.cssText]=\"secondary(item)?.style\"\n >\n @if (simpleRichContentNodes(secondary(item)); as richNodes) {\n <praxis-rich-content [nodes]=\"richNodes\"></praxis-rich-content>\n } @else if (item.segmentVariant && item.segmentLabel && item.accountType && item.since) {\n <!-- Component-based rendering for executive items -->\n <span class=\"exec-subline\">\n <praxis-executive-badge\n [variant]=\"item.segmentVariant\"\n [label]=\"item.segmentLabel\"\n ></praxis-executive-badge>\n <span class=\"exec-subcopy\">{{ item.accountType }}</span>\n <span class=\"exec-subseparator\">\u00B7</span>\n <span class=\"exec-subcopy\">Desde {{ item.since }}</span>\n </span>\n } @else if (secondary(item)?.type === \"html\") {\n <span [innerHTML]=\"secondary(item)?.value\"></span>\n } @else if (secondary(item)?.type === \"metric\") {\n <praxis-list-metric\n [metric]=\"secondary(item)\"\n ></praxis-list-metric>\n } @else {\n {{ secondary(item)?.value }}\n }\n </div>\n }\n @if (meta(item); as m) {\n @if (\n (config.templating?.metaPlacement === \"line\" &&\n (m?.type === \"text\" ||\n m?.type === \"date\" ||\n m?.type === \"currency\")) ||\n (layoutLines > 2 &&\n (m?.type === \"text\" ||\n m?.type === \"date\" ||\n m?.type === \"currency\"))\n ) {\n <div\n class=\"tertiary\"\n [ngClass]=\"m.class\"\n [style.cssText]=\"m.style\"\n >\n @if (config.templating?.metaPrefixIcon; as mpi) {\n <mat-icon [praxisIcon]=\"mpi\"></mat-icon>\n }\n {{ m.value }}\n </div>\n }\n }\n @if (featuresVisible()) {\n <div class=\"features\">\n @for (\n f of config.templating?.features || [];\n track $index;\n let fi = $index\n ) {\n <span\n class=\"feature\"\n [ngClass]=\"\n featureSemanticClass(item, f.expr, f.class)\n \"\n >\n @if (featureRichContentNodes(item, f); as featureNodes) {\n <praxis-rich-content [nodes]=\"featureNodes\"></praxis-rich-content>\n } @else {\n @if (f.icon && featuresMode() !== \"labels-only\") {\n <mat-icon [praxisIcon]=\"f.icon\"></mat-icon>\n }\n @if (featuresMode() !== \"icons-only\") {\n <span\n [ngClass]=\"f.class\"\n [style.cssText]=\"f.style\"\n >\n @for (\n line of featureLabelLines(item, f.expr);\n track $index\n ) {\n <span class=\"feature-line\">{{ line }}</span>\n }\n </span>\n }\n }\n @if (\n featureProgressPercent(item, f.expr, f.class);\n as progress\n ) {\n <span\n class=\"feature-progress\"\n aria-hidden=\"true\"\n >\n <span\n class=\"feature-progress__value\"\n [style.width.%]=\"progress\"\n ></span>\n </span>\n }\n </span>\n }\n </div>\n }\n </div>\n </button>\n <div class=\"list-item-trailing\">\n @if (meta(item); as m) {\n @if (\n !(\n (config.templating?.metaPlacement === \"line\" ||\n layoutLines > 2) &&\n (m?.type === \"text\" ||\n m?.type === \"date\" ||\n m?.type === \"currency\")\n )\n ) {\n <div\n class=\"meta\"\n [ngClass]=\"m.class\"\n [style.cssText]=\"m.style\"\n >\n @if (simpleRichContentNodes(m, { slot: 'meta' }); as richNodes) {\n <praxis-rich-content [nodes]=\"richNodes\"></praxis-rich-content>\n } @else {\n @switch (m.type) {\n @case (\"chip\") {\n <mat-chip\n [color]=\"\n isThemeColor(m.color) ? m.color : undefined\n \"\n [ngClass]=\"\n (m.variant || 'filled') === 'outlined'\n ? 'chip-outlined'\n : ''\n \"\n [style.cssText]=\"chipStyle(m.color, m.variant)\"\n >{{ m.value }}</mat-chip\n >\n }\n @case (\"rating\") {\n @for (\n _ of ratingRange(m);\n track $index;\n let idx = $index\n ) {\n <mat-icon\n [praxisIcon]=\"starIcon(idx, m.value)\"\n [color]=\"ratingThemeColor(m)\"\n [style.cssText]=\"ratingIconStyle(m)\"\n ></mat-icon>\n }\n }\n @case (\"icon\") {\n <mat-icon\n [praxisIcon]=\"m.value\"\n [color]=\"\n isThemeColor(m.color) ? m.color : undefined\n \"\n [style.cssText]=\"iconStyle(m.color)\"\n ></mat-icon>\n }\n @case (\"image\") {\n <span class=\"inline-image\"\n ><img [src]=\"m.value\" [alt]=\"m.imageAlt || ''\"\n /></span>\n }\n @case (\"html\") {\n <span [innerHTML]=\"m.value\"></span>\n }\n @case (\"metric\") {\n <praxis-list-metric [metric]=\"m\"></praxis-list-metric>\n }\n @default {\n <span>\n @if (\n config.templating?.metaPrefixIcon;\n as mpi2\n ) {\n <mat-icon [praxisIcon]=\"mpi2\"></mat-icon>\n }\n {{ m.value }}</span\n >\n }\n }\n }\n </div>\n }\n }\n @if (trailing(item); as tr) {\n <div\n class=\"trailing\"\n [ngClass]=\"tr.class\"\n [style.cssText]=\"tr.style\"\n >\n @if (\n simpleRichContentNodes(tr, {\n imageAlt: config.templating?.trailing?.imageAlt || \"\",\n });\n as richNodes\n ) {\n <praxis-rich-content [nodes]=\"richNodes\"></praxis-rich-content>\n } @else {\n @switch (tr.type) {\n @case (\"chip\") {\n <mat-chip\n [color]=\"\n isThemeColor(tr.color) ? tr.color : undefined\n \"\n [ngClass]=\"\n (tr.variant || 'filled') === 'outlined'\n ? 'chip-outlined'\n : ''\n \"\n [style.cssText]=\"chipStyle(tr.color, tr.variant)\"\n >{{ tr.value }}</mat-chip\n >\n }\n @case (\"icon\") {\n <mat-icon\n [praxisIcon]=\"tr.value\"\n [color]=\"\n isThemeColor(tr.color) ? tr.color : undefined\n \"\n [style.cssText]=\"iconStyle(tr.color)\"\n ></mat-icon>\n }\n @case (\"image\") {\n <div\n class=\"lead-image\"\n [ngClass]=\"tr.class\"\n [style.cssText]=\"tr.style\"\n >\n <img\n [src]=\"tr.value\"\n [alt]=\"\n config.templating?.trailing?.imageAlt || ''\n \"\n />\n @if (tr.badge?.value) {\n <mat-chip\n class=\"lead-badge\"\n [color]=\"\n isThemeColor(tr.badge?.color)\n ? tr.badge?.color\n : undefined\n \"\n [ngClass]=\"\n (tr.badge?.variant || 'filled') ===\n 'outlined'\n ? 'chip-outlined'\n : ''\n \"\n [style.cssText]=\"\n chipStyle(\n tr.badge?.color,\n tr.badge?.variant\n )\n \"\n >{{ tr.badge?.value }}</mat-chip\n >\n }\n </div>\n }\n @case (\"rating\") {\n @for (\n _ of ratingRange(tr);\n track $index;\n let idx = $index\n ) {\n <mat-icon\n [praxisIcon]=\"starIcon(idx, tr.value)\"\n [color]=\"ratingThemeColor(tr)\"\n [style.cssText]=\"ratingIconStyle(tr)\"\n ></mat-icon>\n }\n }\n @case (\"html\") {\n @if (item.alertsData !== undefined && item.ownerName) {\n <!-- Component-based rendering for executive trailing -->\n <span class=\"exec-trailing-shell\">\n <praxis-executive-alerts [alerts]=\"item.alertsData\"></praxis-executive-alerts>\n <praxis-executive-owner [name]=\"item.ownerName\"></praxis-executive-owner>\n </span>\n } @else {\n <span [innerHTML]=\"tr.value\"></span>\n }\n }\n @case (\"metric\") {\n <praxis-list-metric [metric]=\"tr\"></praxis-list-metric>\n }\n @default {\n <span>{{ tr.value }}</span>\n }\n }\n }\n </div>\n }\n @if (showExpandIcon(\"trailing\")) {\n <button\n mat-icon-button\n type=\"button\"\n class=\"expand-toggle\"\n [attr.aria-label]=\"expandToggleAriaLabel(item, i)\"\n [attr.aria-expanded]=\"\n expansionOwnedByIcon() ? isExpanded(item, i) : null\n \"\n [attr.aria-controls]=\"\n expansionOwnedByIcon()\n ? expandRegionId(item, i)\n : null\n \"\n (click)=\"onExpandToggle($event, item, i)\"\n >\n <mat-icon\n [praxisIcon]=\"\n isExpanded(item, i) ? 'expand_less' : 'expand_more'\n \"\n ></mat-icon>\n </button>\n }\n @if ((visibleActions(item, \"trailing\") || []).length) {\n <div\n class=\"list-item-actions\"\n (click)=\"$event.stopPropagation()\"\n (keydown.enter)=\"onActionKeydown($event)\"\n (keydown.space)=\"onActionKeydown($event)\"\n >\n @for (\n action of visibleActions(item, \"trailing\");\n let aidx = $index;\n track action?.id ?? $index\n ) {\n @if ((action.kind || \"icon\") === \"icon\") {\n <button\n mat-icon-button\n [color]=\"\n isThemeColor(action.color)\n ? action.color\n : undefined\n \"\n (click)=\"\n onActionClick($event, action.id, item, i)\n \"\n [attr.aria-label]=\"action.label || action.id\"\n [disabled]=\"isActionLoading(action.id, item, i)\"\n [ngClass]=\"{\n 'action-loading': isActionLoading(\n action.id,\n item,\n i\n ),\n }\"\n >\n @if (isActionLoading(action.id, item, i)) {\n <mat-progress-spinner\n class=\"action-spinner\"\n mode=\"indeterminate\"\n diameter=\"16\"\n strokeWidth=\"3\"\n ></mat-progress-spinner>\n } @else {\n <mat-icon\n [praxisIcon]=\"action.icon\"\n [style.cssText]=\"iconStyle(action.color)\"\n ></mat-icon>\n }\n </button>\n } @else {\n @if (action.buttonVariant === \"stroked\") {\n <button\n mat-stroked-button\n [color]=\"\n isThemeColor(action.color)\n ? action.color\n : undefined\n \"\n [style.cssText]=\"\n buttonStyle(action.color, 'stroked')\n \"\n (click)=\"\n onActionClick($event, action.id, item, i)\n \"\n [attr.aria-label]=\"action.label || action.id\"\n [disabled]=\"isActionLoading(action.id, item, i)\"\n [ngClass]=\"{\n 'action-loading': isActionLoading(\n action.id,\n item,\n i\n ),\n }\"\n >\n @if (isActionLoading(action.id, item, i)) {\n <mat-progress-spinner\n class=\"action-spinner\"\n mode=\"indeterminate\"\n diameter=\"16\"\n strokeWidth=\"3\"\n ></mat-progress-spinner>\n } @else {\n {{ action.label || action.id }}\n }\n </button>\n }\n @if (action.buttonVariant === \"raised\") {\n <button\n mat-raised-button\n [color]=\"\n isThemeColor(action.color)\n ? action.color\n : undefined\n \"\n [style.cssText]=\"\n buttonStyle(action.color, 'raised')\n \"\n (click)=\"\n onActionClick($event, action.id, item, i)\n \"\n [attr.aria-label]=\"action.label || action.id\"\n [disabled]=\"isActionLoading(action.id, item, i)\"\n [ngClass]=\"{\n 'action-loading': isActionLoading(\n action.id,\n item,\n i\n ),\n }\"\n >\n @if (isActionLoading(action.id, item, i)) {\n <mat-progress-spinner\n class=\"action-spinner\"\n mode=\"indeterminate\"\n diameter=\"16\"\n strokeWidth=\"3\"\n ></mat-progress-spinner>\n } @else {\n {{ action.label || action.id }}\n }\n </button>\n }\n @if (\n !action.buttonVariant ||\n action.buttonVariant === \"flat\"\n ) {\n <button\n mat-flat-button\n [color]=\"\n isThemeColor(action.color)\n ? action.color\n : undefined\n \"\n [style.cssText]=\"\n buttonStyle(action.color, 'flat')\n \"\n (click)=\"\n onActionClick($event, action.id, item, i)\n \"\n [attr.aria-label]=\"action.label || action.id\"\n [disabled]=\"isActionLoading(action.id, item, i)\"\n [ngClass]=\"{\n 'action-loading': isActionLoading(\n action.id,\n item,\n i\n ),\n }\"\n >\n @if (isActionLoading(action.id, item, i)) {\n <mat-progress-spinner\n class=\"action-spinner\"\n mode=\"indeterminate\"\n diameter=\"16\"\n strokeWidth=\"3\"\n ></mat-progress-spinner>\n } @else {\n {{ action.label || action.id }}\n }\n </button>\n }\n }\n }\n </div>\n }\n </div>\n </div>\n }\n @if (isExpandable() && isExpanded(item, i)) {\n <div\n class=\"item-expansion\"\n [id]=\"expandRegionId(item, i)\"\n role=\"region\"\n [attr.aria-label]=\"expansionRegionAriaLabel(item)\"\n >\n <div class=\"item-expansion-grid\">\n @for (\n expansionSection of expansionSections(item);\n track expansionSection.id\n ) {\n <section\n class=\"expansion-section\"\n [attr.data-section-type]=\"expansionSection.type\"\n >\n @if (expansionSection.title) {\n <div class=\"expansion-section-title\">\n {{ expansionSection.title }}\n </div>\n }\n @if (\n expansionSectionHasContent(\n item,\n expansionSection,\n i\n )\n ) {\n @switch (expansionSection.type) {\n @case (\"chip-list\") {\n <div class=\"expansion-chip-list\">\n @for (\n expansionEntry of expansionSectionItems(\n item,\n expansionSection,\n i\n );\n track $index\n ) {\n <mat-chip class=\"expansion-chip\">{{\n expansionItemLabel(expansionEntry)\n }}</mat-chip>\n }\n </div>\n }\n @case (\"timeline\") {\n <div class=\"expansion-timeline\">\n @for (\n expansionEntry of expansionSectionItems(\n item,\n expansionSection,\n i\n );\n track $index\n ) {\n <div class=\"expansion-timeline-item\">\n <div class=\"expansion-timeline-title\">\n {{\n expansionTimelineTitle(expansionEntry)\n }}\n </div>\n @if (\n expansionTimelineMeta(expansionEntry)\n ) {\n <div class=\"expansion-timeline-meta\">\n {{\n expansionTimelineMeta(\n expansionEntry\n )\n }}\n </div>\n }\n @if (\n expansionTimelineDescription(\n expansionEntry\n )\n ) {\n <div\n class=\"expansion-timeline-description\"\n >\n {{\n expansionTimelineDescription(\n expansionEntry\n )\n }}\n </div>\n }\n </div>\n }\n </div>\n }\n @case (\"key-value\") {\n <dl class=\"expansion-key-value\">\n @for (\n expansionEntry of expansionSectionItems(\n item,\n expansionSection,\n i\n );\n track $index\n ) {\n <div class=\"expansion-key-value-row\">\n @if (\n expansionKeyValueKey(expansionEntry)\n ) {\n <dt>\n {{\n expansionKeyValueKey(expansionEntry)\n }}\n </dt>\n }\n <dd>\n {{\n expansionKeyValueValue(expansionEntry)\n }}\n </dd>\n </div>\n }\n </dl>\n }\n @default {\n <div class=\"expansion-info-list\">\n @for (\n expansionEntry of expansionSectionItems(\n item,\n expansionSection,\n i\n );\n track $index\n ) {\n <div class=\"expansion-info-item\">\n <div class=\"expansion-info-title\">\n {{ expansionInfoTitle(expansionEntry) }}\n </div>\n @if (expansionInfoValue(expansionEntry)) {\n <div class=\"expansion-info-value\">\n {{\n expansionInfoValue(expansionEntry)\n }}\n </div>\n }\n </div>\n }\n </div>\n }\n }\n } @else {\n <div class=\"expansion-empty\">\n {{\n expansionSection.emptyLabel ||\n \"Sem dados dispon\u00EDveis\"\n }}\n </div>\n }\n </section>\n }\n </div>\n </div>\n }\n </mat-list-item>\n @if (\n (config.layout?.dividers === \"all\" ||\n config.layout?.dividers === \"between\") &&\n i < section.items.length - 1\n ) {\n <mat-divider></mat-divider>\n }\n }\n }\n </mat-list>\n </ng-template>\n } @else if (isTilesVariant()) {\n <ng-container *ngTemplateOutlet=\"tilesVariant\"></ng-container>\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\n class=\"item-card\"\n [ngClass]=\"itemRuleClass(it)\"\n [attr.style]=\"itemRuleStyle(it)\"\n role=\"button\"\n tabindex=\"0\"\n [attr.aria-label]=\"itemAriaLabel(it)\"\n (click)=\"onItemClick(it, i)\"\n (keydown.enter)=\"onItemClick(it, i)\"\n (keydown.space)=\"$event.preventDefault(); onItemClick(it, i)\"\n >\n <div class=\"list-item-content\">\n <div class=\"list-item-leading\">\n @if (leading(it); as lead) {\n @if (\n simpleRichContentNodes(lead, {\n imageAlt: config.templating?.leading?.imageAlt || \"\",\n });\n as richNodes\n ) {\n <praxis-rich-content [nodes]=\"richNodes\"></praxis-rich-content>\n } @else {\n @switch (lead.type) {\n @case (\"icon\") {\n <mat-icon\n [praxisIcon]=\"lead.value\"\n [ngClass]=\"lead.class\"\n [color]=\"\n isThemeColor(lead.color) ? lead.color : undefined\n \"\n [style.cssText]=\"\n (lead.style ? lead.style + ';' : '') +\n iconStyle(lead.color)\n \"\n ></mat-icon>\n }\n @case (\"image\") {\n <div\n class=\"lead-image\"\n [ngClass]=\"lead.class\"\n [style.cssText]=\"lead.style\"\n >\n <img\n [src]=\"lead.value\"\n [alt]=\"config.templating?.leading?.imageAlt || ''\"\n />\n @if (lead.badge?.value) {\n <mat-chip\n class=\"lead-badge\"\n [color]=\"\n isThemeColor(lead.badge?.color)\n ? lead.badge?.color\n : undefined\n \"\n [ngClass]=\"\n (lead.badge?.variant || 'filled') === 'outlined'\n ? 'chip-outlined'\n : ''\n \"\n [style.cssText]=\"\n chipStyle(\n lead.badge?.color,\n lead.badge?.variant\n )\n \"\n >{{ lead.badge?.value }}</mat-chip\n >\n }\n </div>\n }\n @case (\"text\") {\n <span\n [ngClass]=\"lead.class\"\n [style.cssText]=\"lead.style\"\n >{{ lead.value }}</span\n >\n }\n @case (\"chip\") {\n <mat-chip\n [color]=\"\n isThemeColor(lead.color) ? lead.color : undefined\n \"\n [ngClass]=\"\n (lead.variant || 'filled') === 'outlined'\n ? 'chip-outlined'\n : ''\n \"\n [style.cssText]=\"chipStyle(lead.color, lead.variant)\"\n >{{ lead.value }}</mat-chip\n >\n }\n @case (\"rating\") {\n @for (\n _ of ratingRange(lead);\n track $index;\n let idx = $index\n ) {\n <mat-icon\n [praxisIcon]=\"starIcon(idx, lead.value)\"\n [color]=\"ratingThemeColor(lead)\"\n [style.cssText]=\"ratingIconStyle(lead)\"\n ></mat-icon>\n }\n }\n @case (\"html\") {\n <span\n [ngClass]=\"lead.class\"\n [style.cssText]=\"lead.style\"\n [innerHTML]=\"lead.value\"\n ></span>\n }\n @case (\"metric\") {\n <praxis-list-metric\n [metric]=\"lead\"\n ></praxis-list-metric>\n }\n @case (\"compose\") {\n <praxis-list-compose\n [compose]=\"lead\"\n ></praxis-list-compose>\n }\n @case (\"component\") {\n <praxis-list-runtime-component\n [component]=\"lead\"\n ></praxis-list-runtime-component>\n }\n @default {\n <span\n [ngClass]=\"lead.class\"\n [style.cssText]=\"lead.style\"\n >{{ lead.value }}</span\n >\n }\n }\n }\n } @else {\n <span class=\"leading-placeholder\"></span>\n }\n </div>\n <div class=\"list-item-text\">\n <div\n class=\"primary\"\n [ngClass]=\"primary(it)?.class\"\n [style.cssText]=\"primary(it)?.style\"\n >\n @if (simpleRichContentNodes(primary(it)); as richNodes) {\n <praxis-rich-content [nodes]=\"richNodes\"></praxis-rich-content>\n } @else if (primary(it)?.type === \"metric\") {\n <praxis-list-metric [metric]=\"primary(it)\"></praxis-list-metric>\n } @else if (primary(it)?.type === \"compose\") {\n <praxis-list-compose\n [compose]=\"primary(it)\"\n ></praxis-list-compose>\n } @else if (primary(it)?.type === \"component\") {\n <praxis-list-runtime-component\n [component]=\"primary(it)\"\n ></praxis-list-runtime-component>\n } @else {\n {{ primary(it)?.value }}\n }\n </div>\n @if (layoutLines > 1) {\n <div\n class=\"secondary\"\n [ngClass]=\"secondary(it)?.class\"\n [style.cssText]=\"secondary(it)?.style\"\n >\n @if (simpleRichContentNodes(secondary(it)); as richNodes) {\n <praxis-rich-content [nodes]=\"richNodes\"></praxis-rich-content>\n } @else if (secondary(it)?.type === \"metric\") {\n <praxis-list-metric\n [metric]=\"secondary(it)\"\n ></praxis-list-metric>\n } @else if (secondary(it)?.type === \"compose\") {\n <praxis-list-compose\n [compose]=\"secondary(it)\"\n ></praxis-list-compose>\n } @else if (secondary(it)?.type === \"component\") {\n <praxis-list-runtime-component\n [component]=\"secondary(it)\"\n ></praxis-list-runtime-component>\n } @else {\n {{ secondary(it)?.value }}\n }\n </div>\n }\n @if (meta(it); as m) {\n @if (\n (config.templating?.metaPlacement === \"line\" &&\n (m?.type === \"text\" ||\n m?.type === \"date\" ||\n m?.type === \"currency\")) ||\n (layoutLines > 2 &&\n (m?.type === \"text\" ||\n m?.type === \"date\" ||\n m?.type === \"currency\"))\n ) {\n <div\n class=\"tertiary\"\n [ngClass]=\"m.class\"\n [style.cssText]=\"m.style\"\n >\n @if (config.templating?.metaPrefixIcon; as mpi) {\n <mat-icon [praxisIcon]=\"mpi\"></mat-icon>\n }\n {{ m.value }}\n </div>\n }\n }\n @if (featuresVisible()) {\n <div class=\"features\">\n @for (\n f of config.templating?.features || [];\n track $index;\n let fi = $index\n ) {\n <span\n class=\"feature\"\n [ngClass]=\"featureSemanticClass(it, f.expr, f.class)\"\n >\n @if (featureRichContentNodes(it, f); as featureNodes) {\n <praxis-rich-content [nodes]=\"featureNodes\"></praxis-rich-content>\n } @else {\n @if (f.icon && featuresMode() !== \"labels-only\") {\n <mat-icon [praxisIcon]=\"f.icon\"></mat-icon>\n }\n @if (featuresMode() !== \"icons-only\") {\n <span [ngClass]=\"f.class\" [style.cssText]=\"f.style\">\n @for (\n line of featureLabelLines(it, f.expr);\n track $index\n ) {\n <span class=\"feature-line\">{{ line }}</span>\n }\n </span>\n }\n }\n @if (\n featureProgressPercent(it, f.expr, f.class);\n as progress\n ) {\n <span class=\"feature-progress\" aria-hidden=\"true\">\n <span\n class=\"feature-progress__value\"\n [style.width.%]=\"progress\"\n ></span>\n </span>\n }\n </span>\n }\n </div>\n }\n </div>\n <div class=\"list-item-trailing\">\n @if (meta(it); as m) {\n @if (\n !(\n (config.templating?.metaPlacement === \"line\" ||\n layoutLines > 2) &&\n (m?.type === \"text\" ||\n m?.type === \"date\" ||\n m?.type === \"currency\")\n )\n ) {\n <div\n class=\"meta\"\n [ngClass]=\"m.class\"\n [style.cssText]=\"m.style\"\n >\n @if (\n simpleRichContentNodes(m, {\n slot: \"meta\",\n imageAlt: m.imageAlt || \"\",\n });\n as richNodes\n ) {\n <praxis-rich-content [nodes]=\"richNodes\"></praxis-rich-content>\n } @else {\n @switch (m.type) {\n @case (\"chip\") {\n <mat-chip\n [color]=\"\n isThemeColor(m.color) ? m.color : undefined\n \"\n [ngClass]=\"\n (m.variant || 'filled') === 'outlined'\n ? 'chip-outlined'\n : ''\n \"\n [style.cssText]=\"chipStyle(m.color, m.variant)\"\n >{{ m.value }}</mat-chip\n >\n }\n @case (\"rating\") {\n @for (\n _ of ratingRange(m);\n track $index;\n let idx = $index\n ) {\n <mat-icon\n [praxisIcon]=\"starIcon(idx, m.value)\"\n [color]=\"ratingThemeColor(m)\"\n [style.cssText]=\"ratingIconStyle(m)\"\n ></mat-icon>\n }\n }\n @case (\"icon\") {\n <mat-icon\n [praxisIcon]=\"m.value\"\n [color]=\"\n isThemeColor(m.color) ? m.color : undefined\n \"\n [style.cssText]=\"iconStyle(m.color)\"\n ></mat-icon>\n }\n @case (\"image\") {\n <span class=\"inline-image\"\n ><img [src]=\"m.value\" [alt]=\"m.imageAlt || ''\"\n /></span>\n }\n @case (\"html\") {\n <span [innerHTML]=\"m.value\"></span>\n }\n @case (\"metric\") {\n <praxis-list-metric\n [metric]=\"m\"\n ></praxis-list-metric>\n }\n @case (\"compose\") {\n <praxis-list-compose\n [compose]=\"m\"\n ></praxis-list-compose>\n }\n @case (\"component\") {\n <praxis-list-runtime-component\n [component]=\"m\"\n ></praxis-list-runtime-component>\n }\n @default {\n <span>\n @if (config.templating?.metaPrefixIcon; as mpi2) {\n <mat-icon [praxisIcon]=\"mpi2\"></mat-icon>\n }\n {{ m.value }}</span\n >\n }\n }\n }\n </div>\n }\n }\n @if (trailing(it); as tr) {\n @if (\n (config.templating?.statusPosition || \"inline\") ===\n \"top-right\" &&\n (tr?.type === \"chip\" || tr?.type === \"icon\")\n ) {\n <div class=\"status-overlay\">\n @if (simpleRichContentNodes(tr); as richNodes) {\n <praxis-rich-content [nodes]=\"richNodes\"></praxis-rich-content>\n } @else {\n @if (tr?.type === \"chip\") {\n <mat-chip\n [color]=\"\n isThemeColor(tr.color) ? tr.color : undefined\n \"\n [ngClass]=\"\n (tr.variant || 'filled') === 'outlined'\n ? 'chip-outlined'\n : ''\n \"\n [style.cssText]=\"chipStyle(tr.color, tr.variant)\"\n >{{ tr.value }}</mat-chip\n >\n }\n @if (tr?.type === \"icon\") {\n <mat-icon\n [praxisIcon]=\"tr.value\"\n [color]=\"\n isThemeColor(tr.color) ? tr.color : undefined\n \"\n [style.cssText]=\"iconStyle(tr.color)\"\n ></mat-icon>\n }\n }\n </div>\n } @else {\n <div\n class=\"trailing\"\n [ngClass]=\"tr.class\"\n [style.cssText]=\"tr.style\"\n >\n @if (\n simpleRichContentNodes(tr, {\n imageAlt: config.templating?.trailing?.imageAlt || \"\",\n });\n as richNodes\n ) {\n <praxis-rich-content [nodes]=\"richNodes\"></praxis-rich-content>\n } @else {\n @switch (tr.type) {\n @case (\"chip\") {\n <mat-chip\n [color]=\"\n isThemeColor(tr.color) ? tr.color : undefined\n \"\n [ngClass]=\"\n (tr.variant || 'filled') === 'outlined'\n ? 'chip-outlined'\n : ''\n \"\n [style.cssText]=\"chipStyle(tr.color, tr.variant)\"\n >{{ tr.value }}</mat-chip\n >\n }\n @case (\"icon\") {\n <mat-icon\n [praxisIcon]=\"tr.value\"\n [color]=\"\n isThemeColor(tr.color) ? tr.color : undefined\n \"\n [style.cssText]=\"iconStyle(tr.color)\"\n ></mat-icon>\n }\n @case (\"image\") {\n <div\n class=\"lead-image\"\n [ngClass]=\"tr.class\"\n [style.cssText]=\"tr.style\"\n >\n <img\n [src]=\"tr.value\"\n [alt]=\"\n config.templating?.trailing?.imageAlt || ''\n \"\n />\n @if (tr.badge?.value) {\n <mat-chip\n class=\"lead-badge\"\n [color]=\"\n isThemeColor(tr.badge?.color)\n ? tr.badge?.color\n : undefined\n \"\n [ngClass]=\"\n (tr.badge?.variant || 'filled') ===\n 'outlined'\n ? 'chip-outlined'\n : ''\n \"\n [style.cssText]=\"\n chipStyle(\n tr.badge?.color,\n tr.badge?.variant\n )\n \"\n >{{ tr.badge?.value }}</mat-chip\n >\n }\n </div>\n }\n @case (\"rating\") {\n @for (\n _ of ratingRange(tr);\n track $index;\n let idx = $index\n ) {\n <mat-icon\n [praxisIcon]=\"starIcon(idx, tr.value)\"\n [color]=\"ratingThemeColor(tr)\"\n [style.cssText]=\"ratingIconStyle(tr)\"\n ></mat-icon>\n }\n }\n @case (\"html\") {\n <span [innerHTML]=\"tr.value\"></span>\n }\n @case (\"metric\") {\n <praxis-list-metric\n [metric]=\"tr\"\n ></praxis-list-metric>\n }\n @case (\"compose\") {\n <praxis-list-compose\n [compose]=\"tr\"\n ></praxis-list-compose>\n }\n @case (\"component\") {\n <praxis-list-runtime-component\n [component]=\"tr\"\n ></praxis-list-runtime-component>\n }\n @default {\n <span>{{ tr.value }}</span>\n }\n }\n }\n </div>\n }\n }\n </div>\n </div>\n <div\n class=\"card-actions\"\n (click)=\"$event.stopPropagation()\"\n (keydown.enter)=\"onActionKeydown($event)\"\n (keydown.space)=\"onActionKeydown($event)\"\n >\n @for (\n action of visibleActions(it, \"trailing\");\n let aidx = $index;\n track action?.id ?? $index\n ) {\n @if ((action.kind || \"icon\") === \"icon\") {\n <button\n mat-icon-button\n [color]=\"\n isThemeColor(action.color) ? action.color : undefined\n \"\n (click)=\"onActionClick($event, action.id, it, i)\"\n [attr.aria-label]=\"action.label || action.id\"\n [disabled]=\"isActionLoading(action.id, it, i)\"\n [ngClass]=\"{\n 'action-loading': isActionLoading(action.id, it, i),\n }\"\n >\n @if (isActionLoading(action.id, it, i)) {\n <mat-progress-spinner\n class=\"action-spinner\"\n mode=\"indeterminate\"\n diameter=\"16\"\n strokeWidth=\"3\"\n ></mat-progress-spinner>\n } @else {\n <mat-icon\n [praxisIcon]=\"action.icon\"\n [style.cssText]=\"iconStyle(action.color)\"\n ></mat-icon>\n }\n </button>\n } @else {\n @if (action.buttonVariant === \"stroked\") {\n <button\n mat-stroked-button\n [color]=\"\n isThemeColor(action.color) ? action.color : undefined\n \"\n [style.cssText]=\"buttonStyle(action.color, 'stroked')\"\n (click)=\"onActionClick($event, action.id, it, i)\"\n [attr.aria-label]=\"action.label || action.id\"\n [disabled]=\"isActionLoading(action.id, it, i)\"\n [ngClass]=\"{\n 'action-loading': isActionLoading(action.id, it, i),\n }\"\n >\n @if (isActionLoading(action.id, it, i)) {\n <mat-progress-spinner\n class=\"action-spinner\"\n mode=\"indeterminate\"\n diameter=\"16\"\n strokeWidth=\"3\"\n ></mat-progress-spinner>\n } @else {\n {{ action.label || action.id }}\n }\n </button>\n }\n @if (action.buttonVariant === \"raised\") {\n <button\n mat-raised-button\n [color]=\"\n isThemeColor(action.color) ? action.color : undefined\n \"\n [style.cssText]=\"buttonStyle(action.color, 'raised')\"\n (click)=\"onActionClick($event, action.id, it, i)\"\n [attr.aria-label]=\"action.label || action.id\"\n [disabled]=\"isActionLoading(action.id, it, i)\"\n [ngClass]=\"{\n 'action-loading': isActionLoading(action.id, it, i),\n }\"\n >\n @if (isActionLoading(action.id, it, i)) {\n <mat-progress-spinner\n class=\"action-spinner\"\n mode=\"indeterminate\"\n diameter=\"16\"\n strokeWidth=\"3\"\n ></mat-progress-spinner>\n } @else {\n {{ action.label || action.id }}\n }\n </button>\n }\n @if (\n !action.buttonVariant || action.buttonVariant === \"flat\"\n ) {\n <button\n mat-flat-button\n [color]=\"\n isThemeColor(action.color) ? action.color : undefined\n \"\n [style.cssText]=\"buttonStyle(action.color, 'flat')\"\n (click)=\"onActionClick($event, action.id, it, i)\"\n [attr.aria-label]=\"action.label || action.id\"\n [disabled]=\"isActionLoading(action.id, it, i)\"\n [ngClass]=\"{\n 'action-loading': isActionLoading(action.id, it, i),\n }\"\n >\n @if (isActionLoading(action.id, it, i)) {\n <mat-progress-spinner\n class=\"action-spinner\"\n mode=\"indeterminate\"\n diameter=\"16\"\n strokeWidth=\"3\"\n ></mat-progress-spinner>\n } @else {\n {{ action.label || action.id }}\n }\n </button>\n }\n }\n }\n </div>\n </div>\n }\n </div>\n </ng-template>\n\n <!-- Tiles variant -->\n <ng-template #tilesVariant>\n <div class=\"tiles-grid\">\n @for (it of (items$ | async) ?? []; track $index; let i = $index) {\n <div\n class=\"item-tile\"\n [ngClass]=\"itemRuleClass(it)\"\n [attr.style]=\"itemRuleStyle(it)\"\n role=\"button\"\n tabindex=\"0\"\n [attr.aria-label]=\"itemAriaLabel(it)\"\n (click)=\"onItemClick(it, i)\"\n (keydown.enter)=\"onItemClick(it, i)\"\n (keydown.space)=\"$event.preventDefault(); onItemClick(it, i)\"\n >\n <div class=\"tile-media\">\n @if (leading(it); as lead) {\n @if (\n simpleRichContentNodes(lead, {\n imageAlt: config.templating?.leading?.imageAlt || \"\",\n });\n as richNodes\n ) {\n <praxis-rich-content [nodes]=\"richNodes\"></praxis-rich-content>\n } @else {\n @switch (lead.type) {\n @case (\"image\") {\n <img\n [src]=\"lead.value\"\n [alt]=\"config.templating?.leading?.imageAlt || ''\"\n />\n }\n @case (\"icon\") {\n <mat-icon\n [praxisIcon]=\"lead.value\"\n [ngClass]=\"lead.class\"\n [color]=\"\n isThemeColor(lead.color) ? lead.color : undefined\n \"\n [style.cssText]=\"\n (lead.style ? lead.style + ';' : '') +\n iconStyle(lead.color)\n \"\n ></mat-icon>\n }\n @case (\"text\") {\n <span [ngClass]=\"lead.class\" [style.cssText]=\"lead.style\">{{\n lead.value\n }}</span>\n }\n @case (\"chip\") {\n <mat-chip\n [color]=\"\n isThemeColor(lead.color) ? lead.color : undefined\n \"\n [ngClass]=\"\n (lead.variant || 'filled') === 'outlined'\n ? 'chip-outlined'\n : ''\n \"\n [style.cssText]=\"chipStyle(lead.color, lead.variant)\"\n >{{ lead.value }}</mat-chip\n >\n }\n @case (\"rating\") {\n <span [ngClass]=\"lead.class\" [style.cssText]=\"lead.style\">\n @for (\n _ of ratingRange(lead);\n track $index;\n let idx = $index\n ) {\n <mat-icon\n [praxisIcon]=\"starIcon(idx, lead.value)\"\n [color]=\"ratingThemeColor(lead)\"\n [style.cssText]=\"ratingIconStyle(lead)\"\n ></mat-icon>\n }\n </span>\n }\n @case (\"html\") {\n <span\n [ngClass]=\"lead.class\"\n [style.cssText]=\"lead.style\"\n [innerHTML]=\"lead.value\"\n ></span>\n }\n @case (\"metric\") {\n <praxis-list-metric [metric]=\"lead\"></praxis-list-metric>\n }\n @case (\"compose\") {\n <praxis-list-compose\n [compose]=\"lead\"\n ></praxis-list-compose>\n }\n @case (\"component\") {\n <praxis-list-runtime-component\n [component]=\"lead\"\n ></praxis-list-runtime-component>\n }\n @default {\n <span [ngClass]=\"lead.class\" [style.cssText]=\"lead.style\">{{\n lead.value\n }}</span>\n }\n }\n }\n }\n </div>\n\n @if (trailing(it); as tr) {\n @if (\n (config.templating?.statusPosition || \"inline\") ===\n \"top-right\" &&\n (tr?.type === \"chip\" || tr?.type === \"icon\")\n ) {\n <div class=\"tile-status\">\n @if (simpleRichContentNodes(tr); as richNodes) {\n <praxis-rich-content [nodes]=\"richNodes\"></praxis-rich-content>\n } @else {\n @if (tr?.type === \"chip\") {\n <mat-chip\n [color]=\"isThemeColor(tr.color) ? tr.color : undefined\"\n [ngClass]=\"\n (tr.variant || 'filled') === 'outlined'\n ? 'chip-outlined'\n : ''\n \"\n [style.cssText]=\"chipStyle(tr.color, tr.variant)\"\n >{{ tr.value }}</mat-chip\n >\n }\n @if (tr?.type === \"icon\") {\n <mat-icon\n [praxisIcon]=\"tr.value\"\n [color]=\"isThemeColor(tr.color) ? tr.color : undefined\"\n [style.cssText]=\"iconStyle(tr.color)\"\n ></mat-icon>\n }\n }\n </div>\n }\n }\n\n <div class=\"tile-body\">\n <div\n class=\"primary\"\n [ngClass]=\"primary(it)?.class\"\n [style.cssText]=\"primary(it)?.style\"\n >\n @if (simpleRichContentNodes(primary(it)); as richNodes) {\n <praxis-rich-content [nodes]=\"richNodes\"></praxis-rich-content>\n } @else if (primary(it)?.type === \"metric\") {\n <praxis-list-metric [metric]=\"primary(it)\"></praxis-list-metric>\n } @else if (primary(it)?.type === \"compose\") {\n <praxis-list-compose\n [compose]=\"primary(it)\"\n ></praxis-list-compose>\n } @else if (primary(it)?.type === \"component\") {\n <praxis-list-runtime-component\n [component]=\"primary(it)\"\n ></praxis-list-runtime-component>\n } @else {\n {{ primary(it)?.value }}\n }\n </div>\n @if (layoutLines > 1) {\n <div\n class=\"secondary\"\n [ngClass]=\"secondary(it)?.class\"\n [style.cssText]=\"secondary(it)?.style\"\n >\n @if (simpleRichContentNodes(secondary(it)); as richNodes) {\n <praxis-rich-content [nodes]=\"richNodes\"></praxis-rich-content>\n } @else if (secondary(it)?.type === \"metric\") {\n <praxis-list-metric\n [metric]=\"secondary(it)\"\n ></praxis-list-metric>\n } @else if (secondary(it)?.type === \"compose\") {\n <praxis-list-compose\n [compose]=\"secondary(it)\"\n ></praxis-list-compose>\n } @else if (secondary(it)?.type === \"component\") {\n <praxis-list-runtime-component\n [component]=\"secondary(it)\"\n ></praxis-list-runtime-component>\n } @else {\n {{ secondary(it)?.value }}\n }\n </div>\n }\n\n @if (meta(it); as m) {\n <div\n class=\"tile-meta\"\n [ngClass]=\"m.class\"\n [style.cssText]=\"m.style\"\n >\n @if (config.templating?.metaPrefixIcon; as mpi) {\n <mat-icon [praxisIcon]=\"mpi\"></mat-icon>\n }\n @if (\n simpleRichContentNodes(m, {\n slot: \"meta\",\n imageAlt: m.imageAlt || \"\",\n });\n as richNodes\n ) {\n <praxis-rich-content [nodes]=\"richNodes\"></praxis-rich-content>\n } @else {\n @switch (m.type) {\n @case (\"chip\") {\n <mat-chip\n [color]=\"isThemeColor(m.color) ? m.color : undefined\"\n [ngClass]=\"\n (m.variant || 'filled') === 'outlined'\n ? 'chip-outlined'\n : ''\n \"\n [style.cssText]=\"chipStyle(m.color, m.variant)\"\n >{{ m.value }}</mat-chip\n >\n }\n @case (\"rating\") {\n @for (\n _ of ratingRange(m);\n track $index;\n let idx = $index\n ) {\n <mat-icon\n [praxisIcon]=\"starIcon(idx, m.value)\"\n [color]=\"ratingThemeColor(m)\"\n [style.cssText]=\"ratingIconStyle(m)\"\n ></mat-icon>\n }\n }\n @case (\"icon\") {\n <mat-icon\n [praxisIcon]=\"m.value\"\n [color]=\"isThemeColor(m.color) ? m.color : undefined\"\n [style.cssText]=\"iconStyle(m.color)\"\n ></mat-icon>\n }\n @case (\"image\") {\n <span class=\"inline-image\"\n ><img [src]=\"m.value\" [alt]=\"m.imageAlt || ''\"\n /></span>\n }\n @case (\"html\") {\n <span [innerHTML]=\"m.value\"></span>\n }\n @case (\"metric\") {\n <praxis-list-metric [metric]=\"m\"></praxis-list-metric>\n }\n @case (\"compose\") {\n <praxis-list-compose\n [compose]=\"m\"\n ></praxis-list-compose>\n }\n @case (\"component\") {\n <praxis-list-runtime-component\n [component]=\"m\"\n ></praxis-list-runtime-component>\n }\n @default {\n <span>{{ m.value }}</span>\n }\n }\n }\n </div>\n }\n\n @if (featuresVisible()) {\n <div class=\"tiles-features\">\n @for (\n f of config.templating?.features || [];\n track $index;\n let fi = $index\n ) {\n <span\n class=\"feature\"\n [ngClass]=\"featureSemanticClass(it, f.expr, f.class)\"\n >\n @if (featureRichContentNodes(it, f); as featureNodes) {\n <praxis-rich-content [nodes]=\"featureNodes\"></praxis-rich-content>\n } @else {\n @if (f.icon && featuresMode() !== \"labels-only\") {\n <mat-icon [praxisIcon]=\"f.icon\"></mat-icon>\n }\n @if (featuresMode() !== \"icons-only\") {\n <span [ngClass]=\"f.class\" [style.cssText]=\"f.style\">\n @for (\n line of featureLabelLines(it, f.expr);\n track $index\n ) {\n <span class=\"feature-line\">{{ line }}</span>\n }\n </span>\n }\n }\n @if (\n featureProgressPercent(it, f.expr, f.class);\n as progress\n ) {\n <span class=\"feature-progress\" aria-hidden=\"true\">\n <span\n class=\"feature-progress__value\"\n [style.width.%]=\"progress\"\n ></span>\n </span>\n }\n </span>\n }\n </div>\n }\n\n @if (trailing(it); as tr2) {\n @if (\n !(\n (config.templating?.statusPosition || \"inline\") ===\n \"top-right\" &&\n (tr2?.type === \"chip\" || tr2?.type === \"icon\")\n )\n ) {\n <div\n class=\"tile-trailing\"\n [ngClass]=\"tr2.class\"\n [style.cssText]=\"tr2.style\"\n >\n @if (\n simpleRichContentNodes(tr2, {\n imageAlt: tr2.imageAlt || \"\",\n });\n as richNodes\n ) {\n <praxis-rich-content [nodes]=\"richNodes\"></praxis-rich-content>\n } @else {\n @switch (tr2.type) {\n @case (\"chip\") {\n <mat-chip\n [color]=\"\n isThemeColor(tr2.color) ? tr2.color : undefined\n \"\n [ngClass]=\"\n (tr2.variant || 'filled') === 'outlined'\n ? 'chip-outlined'\n : ''\n \"\n [style.cssText]=\"chipStyle(tr2.color, tr2.variant)\"\n >{{ tr2.value }}</mat-chip\n >\n }\n @case (\"icon\") {\n <mat-icon\n [praxisIcon]=\"tr2.value\"\n [color]=\"\n isThemeColor(tr2.color) ? tr2.color : undefined\n \"\n [style.cssText]=\"iconStyle(tr2.color)\"\n ></mat-icon>\n }\n @case (\"image\") {\n <span class=\"inline-image\"\n ><img [src]=\"tr2.value\" [alt]=\"tr2.imageAlt || ''\"\n /></span>\n }\n @case (\"rating\") {\n @for (\n _ of ratingRange(tr2);\n track $index;\n let idx = $index\n ) {\n <mat-icon\n [praxisIcon]=\"starIcon(idx, tr2.value)\"\n [color]=\"ratingThemeColor(tr2)\"\n [style.cssText]=\"ratingIconStyle(tr2)\"\n ></mat-icon>\n }\n }\n @case (\"html\") {\n <span [innerHTML]=\"tr2.value\"></span>\n }\n @case (\"metric\") {\n <praxis-list-metric\n [metric]=\"tr2\"\n ></praxis-list-metric>\n }\n @case (\"compose\") {\n <praxis-list-compose\n [compose]=\"tr2\"\n ></praxis-list-compose>\n }\n @case (\"component\") {\n <praxis-list-runtime-component\n [component]=\"tr2\"\n ></praxis-list-runtime-component>\n }\n @default {\n <span>{{ tr2.value }}</span>\n }\n }\n }\n </div>\n }\n }\n </div>\n\n @if ((visibleActions(it, \"trailing\") || []).length) {\n <div\n class=\"tile-actions\"\n (click)=\"$event.stopPropagation()\"\n (keydown.enter)=\"onActionKeydown($event)\"\n (keydown.space)=\"onActionKeydown($event)\"\n >\n @for (\n action of visibleActions(it, \"trailing\");\n let aidx = $index;\n track action?.id ?? $index\n ) {\n @if ((action.kind || \"icon\") === \"icon\") {\n <button\n mat-icon-button\n [color]=\"\n isThemeColor(action.color) ? action.color : undefined\n \"\n (click)=\"onActionClick($event, action.id, it, i)\"\n [attr.aria-label]=\"action.label || action.id\"\n [disabled]=\"isActionLoading(action.id, it, i)\"\n [ngClass]=\"{\n 'action-loading': isActionLoading(action.id, it, i),\n }\"\n >\n @if (isActionLoading(action.id, it, i)) {\n <mat-progress-spinner\n class=\"action-spinner\"\n mode=\"indeterminate\"\n diameter=\"16\"\n strokeWidth=\"3\"\n ></mat-progress-spinner>\n } @else {\n <mat-icon\n [praxisIcon]=\"action.icon\"\n [style.cssText]=\"iconStyle(action.color)\"\n ></mat-icon>\n }\n </button>\n } @else {\n @if (action.buttonVariant === \"stroked\") {\n <button\n mat-stroked-button\n [color]=\"\n isThemeColor(action.color) ? action.color : undefined\n \"\n [style.cssText]=\"buttonStyle(action.color, 'stroked')\"\n (click)=\"onActionClick($event, action.id, it, i)\"\n [attr.aria-label]=\"action.label || action.id\"\n [disabled]=\"isActionLoading(action.id, it, i)\"\n [ngClass]=\"{\n 'action-loading': isActionLoading(action.id, it, i),\n }\"\n >\n @if (isActionLoading(action.id, it, i)) {\n <mat-progress-spinner\n class=\"action-spinner\"\n mode=\"indeterminate\"\n diameter=\"16\"\n strokeWidth=\"3\"\n ></mat-progress-spinner>\n } @else {\n {{ action.label || action.id }}\n }\n </button>\n }\n @if (action.buttonVariant === \"raised\") {\n <button\n mat-raised-button\n [color]=\"\n isThemeColor(action.color) ? action.color : undefined\n \"\n [style.cssText]=\"buttonStyle(action.color, 'raised')\"\n (click)=\"onActionClick($event, action.id, it, i)\"\n [attr.aria-label]=\"action.label || action.id\"\n [disabled]=\"isActionLoading(action.id, it, i)\"\n [ngClass]=\"{\n 'action-loading': isActionLoading(action.id, it, i),\n }\"\n >\n @if (isActionLoading(action.id, it, i)) {\n <mat-progress-spinner\n class=\"action-spinner\"\n mode=\"indeterminate\"\n diameter=\"16\"\n strokeWidth=\"3\"\n ></mat-progress-spinner>\n } @else {\n {{ action.label || action.id }}\n }\n </button>\n }\n @if (\n !action.buttonVariant || action.buttonVariant === \"flat\"\n ) {\n <button\n mat-flat-button\n [color]=\"\n isThemeColor(action.color) ? action.color : undefined\n \"\n [style.cssText]=\"buttonStyle(action.color, 'flat')\"\n (click)=\"onActionClick($event, action.id, it, i)\"\n [attr.aria-label]=\"action.label || action.id\"\n [disabled]=\"isActionLoading(action.id, it, i)\"\n [ngClass]=\"{\n 'action-loading': isActionLoading(action.id, it, i),\n }\"\n >\n @if (isActionLoading(action.id, it, i)) {\n <mat-progress-spinner\n class=\"action-spinner\"\n mode=\"indeterminate\"\n diameter=\"16\"\n strokeWidth=\"3\"\n ></mat-progress-spinner>\n } @else {\n {{ action.label || action.id }}\n }\n </button>\n }\n }\n }\n </div>\n }\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 <div class=\"paginator-controls\">\n <button mat-stroked-button color=\"primary\" (click)=\"prevPage()\">\n Anterior\n </button>\n <button mat-stroked-button color=\"primary\" (click)=\"nextPage()\">\n Pr\u00F3ximo\n </button>\n <mat-form-field class=\"paginator-page-size\" appearance=\"outline\">\n <mat-label>Tam. p\u00E1gina</mat-label>\n <mat-select\n (selectionChange)=\"setPageSize($event.value)\"\n [value]=\"config.layout?.pageSize || 10\"\n >\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 (config.ui?.showSort) {\n <mat-form-field class=\"paginator-sort\" appearance=\"outline\">\n <mat-label>Ordenar</mat-label>\n <mat-select (selectionChange)=\"onSortChange($event.value)\">\n @for (op of config.ui?.sortOptions || []; track $index) {\n <mat-option [value]=\"sortOptionValue(op)\">{{\n sortOptionLabel(op)\n }}</mat-option>\n }\n </mat-select>\n </mat-form-field>\n }\n @if (config.ui?.showSearch && config.ui?.searchField) {\n <mat-form-field class=\"paginator-search\" appearance=\"outline\">\n <mat-label>{{\n config.ui?.searchPlaceholder || \"Buscar\"\n }}</mat-label>\n <input\n matInput\n type=\"search\"\n (input)=\"onSearchInput($any($event.target).value)\"\n />\n </mat-form-field>\n }\n </div>\n <div class=\"paginator-meta\">\n @if (config.ui?.showRange ?? true) {\n @if (page$ | async; as ps) {\n @if (total$ | async; as total) {\n @if (items$ | async; as curr) {\n <span class=\"muted\"\n >{{ (total || 0) > 0 ? rangeStart(ps) : 0 }}\u2013{{\n rangeEnd(curr?.length || 0, ps, total || 0)\n }}\n de {{ total || 0 }}</span\n >\n }\n }\n }\n } @else {\n @if (total$ | async; as total2) {\n <span class=\"muted\">Total: {{ total2 }}</span>\n }\n }\n </div>\n </div>\n }\n </ng-template>\n</div>\n", styles: ["@charset \"UTF-8\";:host{display:block}.praxis-list-root{--p-list-radius: var(--md-sys-shape-corner-medium, 16px);--p-list-shadow: var(--md-sys-elevation-level2);--p-list-border: 1px solid var(--md-sys-color-outline-variant);--p-list-blur: 10px;--p-list-surface: var(--md-sys-color-surface-container);--p-list-surface-low: var(--md-sys-color-surface);--p-list-surface-high: var( --md-sys-color-surface-container-high, var(--md-sys-color-surface-container) );--p-list-foreground: var(--md-sys-color-on-surface);--p-list-foreground-muted: var(--md-sys-color-on-surface-variant);--p-list-accent: var(--md-sys-color-primary);--p-list-accent-weak: var(--md-sys-color-primary-container);--p-list-item-surface: var( --md-sys-color-surface-container-low, var(--md-sys-color-surface) );--p-list-item-border: 1px solid var(--md-sys-color-outline-variant);--p-list-item-hover-surface: var(--md-sys-color-surface-container-low);--p-list-item-active-surface: var(--md-sys-color-surface-container);--p-list-item-selected-surface: var(--md-sys-color-surface-container);--p-list-grad-from: var(--md-sys-color-primary-container);--p-list-grad-to: var(--md-sys-color-tertiary-container);--p-list-grad-angle: 135deg;--p-list-grad-foreground: var(--md-sys-color-on-primary);--p-list-grad-foreground-muted: var(--md-sys-color-on-primary);--p-list-leading-width: 36px;--p-list-trailing-min-width: 140px;--p-list-item-gap: 10px;--p-list-item-padding-x: 14px;--p-list-item-padding-y: 10px;--p-list-item-stack-gap: 0px;--p-list-meta-size: .875rem;--p-list-meta-weight: 500;--p-list-chip-height: 22px;--p-list-chip-font-size: 12px;--p-list-trailing-padding-right: 8px;--p-list-tile-minW: 240px;--p-list-tile-gap: 12px;--p-list-tile-padding: 12px;--p-list-tile-radius: 12px;--p-list-tile-media-radius: 12px;--p-list-tile-media-ratio: 1 / 1;--p-list-tile-hover-overlay: .04;--p-list-tile-press-overlay: .08;--p-list-tile-press-scale: .99}.list-assistant{display:flex;justify-content:flex-end;gap:8px;padding:4px 4px 8px}.action-loading{opacity:.65}.action-spinner{width:16px;height:16px;display:inline-flex;align-items:center;justify-content:center}.action-loading .mat-mdc-button-touch-target,.action-loading .mdc-button__label{opacity:.7}.skin-elevated,.skin-outline,.skin-flat,.skin-neumorphism{--p-list-item-surface: var( --mdc-elevated-card-container-color, var(--p-list-surface) );--p-list-item-border: var(--p-list-border)}.skin-elevated .item-card,.skin-outline .item-card,.skin-flat .item-card,.skin-neumorphism .item-card{background:var(--mdc-elevated-card-container-color, var(--p-list-surface));border-radius:var(--p-list-radius);box-shadow:var(--p-list-shadow);border:var(--p-list-border)}.skin-elevated .item-tile,.skin-outline .item-tile,.skin-flat .item-tile,.skin-neumorphism .item-tile{background:var(--mdc-elevated-card-container-color, var(--p-list-surface));box-shadow:var(--p-list-shadow);border:var(--p-list-border)}.skin-elevated .mat-mdc-list-item .list-item-content,.skin-outline .mat-mdc-list-item .list-item-content,.skin-flat .mat-mdc-list-item .list-item-content,.skin-neumorphism .mat-mdc-list-item .list-item-content{background:var(--mdc-elevated-card-container-color, var(--p-list-surface));border-radius:calc(var(--p-list-radius) * .75);box-shadow:var(--p-list-shadow);border:var(--p-list-item-border);color:var(--p-list-foreground)}.skin-outline{--p-list-shadow: none;--p-list-border: 1px solid var(--md-sys-color-outline)}.skin-flat{--p-list-shadow: none;--p-list-border: 1px solid var(--md-sys-color-outline-variant)}.skin-neumorphism{--p-list-shadow: var(--md-sys-elevation-level2);--p-list-border: 1px solid var(--md-sys-color-outline-variant);--p-list-radius: 1.25rem}.skin-pill-soft .item-card,.skin-pill-soft .item-tile{background:var(--mdc-elevated-card-container-color, var(--p-list-surface));border-radius:calc(var(--p-list-radius) * 1.3);box-shadow:var(--md-sys-elevation-level1);border:var(--p-list-border)}.skin-pill-soft .mat-mdc-list-item .list-item-content{background:var(--mdc-elevated-card-container-color, var(--p-list-surface));border-radius:calc(var(--p-list-radius) * 1.3);box-shadow:var(--md-sys-elevation-level1);border:var(--p-list-border);color:var(--p-list-foreground)}.skin-gradient-tile{--p-list-foreground: var(--p-list-grad-foreground);--p-list-foreground-muted: var(--p-list-grad-foreground-muted);--p-list-item-hover-surface: linear-gradient( var(--p-list-grad-angle), var(--p-list-grad-from), var(--p-list-grad-to) );--p-list-item-active-surface: linear-gradient( var(--p-list-grad-angle), var(--p-list-grad-from), var(--p-list-grad-to) );--p-list-item-selected-surface: linear-gradient( var(--p-list-grad-angle), var(--p-list-grad-from), var(--p-list-grad-to) )}.skin-gradient-tile .item-card,.skin-gradient-tile .item-tile,.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:var(--p-list-foreground)}.skin-glass .item-card,.skin-glass .item-tile{background:var(--md-sys-color-surface-container-low);border-radius:var(--p-list-radius);border:1px solid var(--md-sys-color-outline-variant);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:var(--md-sys-color-surface-container-low);border-radius:var(--p-list-radius);border:1px solid var(--md-sys-color-outline-variant);backdrop-filter:blur(var(--p-list-blur));-webkit-backdrop-filter:blur(var(--p-list-blur));color:var(--p-list-foreground)}.density-compact .mat-mdc-list-item,.density-compact .item-card{--p-list-item-padding-y: 6px;--p-list-item-padding-x: 10px;--p-list-item-gap: 8px}.density-comfortable .mat-mdc-list-item,.density-comfortable .item-card{--p-list-item-padding-y: 8px;--p-list-item-padding-x: 12px;--p-list-item-gap: 10px}.praxis-list-root.lines-3 .mat-mdc-list-item,.praxis-list-root.lines-3 .mat-mdc-list-option{min-height:68px}.density-compact{--p-list-tile-gap: 10px;--p-list-tile-padding: 10px;--p-list-tile-minW: 188px}.density-comfortable{--p-list-tile-gap: 12px;--p-list-tile-padding: 12px}.item-spacing-none{--p-list-item-stack-gap: 0px}.item-spacing-tight{--p-list-item-stack-gap: 4px;--p-list-tile-gap: 10px}.item-spacing-default{--p-list-item-stack-gap: 6px;--p-list-tile-gap: 12px}.item-spacing-relaxed{--p-list-item-stack-gap: 14px;--p-list-tile-gap: 20px}.list-item-content{display:grid;grid-template-columns:var(--p-list-leading-width) minmax(0,1fr) minmax(var(--p-list-trailing-min-width),max-content);align-items:center;gap:var(--p-list-item-gap);padding:var(--p-list-item-padding-y) var(--p-list-item-padding-x);width:100%;min-width:0;border-radius:calc(var(--p-list-radius) * .75);overflow:visible}.list-item-content--row-layout{--p-list-row-template-columns: var(--p-list-leading-width) minmax(0, 1fr) minmax(var(--p-list-trailing-min-width), max-content);--p-list-row-gap: var(--p-list-item-gap);--p-list-row-align-items: center;grid-template-columns:var(--p-list-row-template-columns);gap:var(--p-list-row-gap);align-items:var(--p-list-row-align-items)}.list-item-content--row-layout[role=button]{cursor:pointer}.list-item-content--row-layout[role=button]:focus-visible{outline:2px solid var(--md-sys-color-primary);outline-offset:2px}.list-row-slot{min-width:0;display:flex;align-items:center;gap:8px}.list-row-slot--leading{justify-content:center}.list-row-slot--primary,.list-row-slot--secondary{min-width:0}.list-row-slot--meta{color:var(--p-list-foreground);font-variant-numeric:tabular-nums}.list-row-slot--trailing{flex-wrap:wrap;justify-content:flex-end}.list-row-slot .primary,.list-row-slot .secondary,.list-row-slot .meta,.list-row-slot .trailing{min-width:0}.list-item-main-action{grid-column:1/3;display:grid;grid-template-columns:var(--p-list-leading-width) minmax(0,1fr);align-items:center;gap:var(--p-list-item-gap);min-width:0;padding:0;border:0;background:transparent;color:inherit;text-align:start;font:inherit;cursor:pointer}.list-item-main-action:focus-visible{outline:2px solid var(--md-sys-color-primary);outline-offset:2px;border-radius:12px}.list-item-leading{display:flex;align-items:center;justify-content:center;min-height:100%}.leading-placeholder{width:24px;height:24px;display:inline-block}.list-item-text{min-width:0;display:grid;align-content:center;gap:2px}.list-item-trailing{min-width:0;display:flex;flex-direction:column;align-items:flex-end;justify-content:center;gap:4px;text-align:end;padding-right:var(--p-list-trailing-padding-right)}.list-item-content--row-layout .list-item-actions{justify-content:flex-end}.list-item-actions{display:flex;align-items:center;justify-content:flex-end;gap:4px;flex-wrap:wrap}.expand-toggle{color:var(--p-list-foreground-muted)}.mat-mdc-list-item .list-item-content{background:var(--p-list-item-surface);border:var(--p-list-item-border);transition:background .15s ease,box-shadow .15s ease,transform .15s ease}.mat-mdc-list-item,.mat-mdc-list-option{height:auto;align-items:stretch;overflow:visible}.mat-mdc-list-item.mdc-list-item--with-one-line,.mat-mdc-list-item.mdc-list-item--with-two-lines,.mat-mdc-list-item.mdc-list-item--with-three-lines,.mat-mdc-list-item-single-line,.mat-mdc-list-item-two-line,.mat-mdc-list-item-three-line,.mat-mdc-list-option.mdc-list-item--with-one-line,.mat-mdc-list-option.mdc-list-item--with-two-lines,.mat-mdc-list-option.mdc-list-item--with-three-lines{height:auto!important}.mdc-list-item{overflow:visible}.density-compact .mat-mdc-list-item,.density-compact .mat-mdc-list-option{min-height:40px}.density-comfortable .mat-mdc-list-item,.density-comfortable .mat-mdc-list-option{min-height:46px}.praxis-list-root:not(.density-compact):not(.density-comfortable) .mat-mdc-list-item,.praxis-list-root:not(.density-compact):not(.density-comfortable) .mat-mdc-list-option{min-height:48px}.mat-mdc-list-item .mdc-list-item__content,.mat-mdc-list-option .mdc-list-item__content,.mat-mdc-list-item .mdc-list-item__primary-text,.mat-mdc-list-option .mdc-list-item__primary-text{display:block!important;width:100%!important;height:auto!important;padding:0!important;margin:0!important;overflow:visible!important;box-sizing:border-box}.mat-mdc-list-item,.mat-mdc-list-option{padding:0!important;box-sizing:border-box}.praxis-list-root mat-list>mat-list-item:not(:last-child),.praxis-list-root mat-selection-list>mat-list-option:not(:last-child){margin-bottom:var(--p-list-item-stack-gap)}.mat-mdc-list-item:hover .list-item-content,.mat-mdc-list-option:hover .list-item-content{background:var(--p-list-item-hover-surface)}.mat-mdc-list-item:active .list-item-content,.mat-mdc-list-option:active .list-item-content{background:var(--p-list-item-active-surface)}.mat-mdc-list-option.mdc-list-item--selected .list-item-content{background:var(--p-list-item-selected-surface);border-color:var(--md-sys-color-outline-variant)}.mat-mdc-list-option.cdk-keyboard-focused .list-item-content,.mat-mdc-list-option.cdk-focused .list-item-content{outline:2px solid var(--md-sys-color-primary);outline-offset:2px}.mat-mdc-list-item:focus-visible .list-item-content{outline:2px solid var(--md-sys-color-primary);outline-offset:2px}.executive-inline-skin{--p-list-leading-width: 56px;--p-list-trailing-min-width: 232px;--p-list-item-padding-x: 14px;--p-list-item-padding-y: 8px;--p-list-item-gap: 10px;--p-list-surface: #f8fafb;--p-list-surface-low: #ffffff;--p-list-item-surface: #ffffff;--p-list-item-hover-surface: #f7fafc;--p-list-item-active-surface: #eef4f8;--p-list-item-selected-surface: #eef4f8;--p-list-foreground: #17324d;--p-list-foreground-muted: #72849a}.executive-inline-skin .list-item-content--row-layout.exec-row-layout{min-height:72px;padding:12px 20px;background:linear-gradient(180deg,#fff,#fbfcfd)!important;border:1px solid #dce5ec!important;border-radius:18px;box-shadow:0 1px 2px #0f223a08,0 4px 14px #0f223a08!important;color:#17324d!important}.executive-inline-skin .mat-mdc-list-item:hover .list-item-content--row-layout.exec-row-layout{background:linear-gradient(180deg,#fff,#f7fafc)!important}.executive-inline-skin .list-item-content--row-layout.exec-row-layout+.item-expansion{margin-left:10px;margin-right:10px}.executive-inline-skin .list-item-content--row-layout.exec-row-layout .list-row-slot{min-height:34px}.executive-inline-skin .list-row-slot--leading{justify-content:center}.executive-inline-skin .list-row-slot--identity{align-items:center;padding-right:4px}.executive-inline-skin .list-row-slot--balance,.executive-inline-skin .list-row-slot--limit,.executive-inline-skin .list-row-slot--risk,.executive-inline-skin .list-row-slot--alerts{justify-content:center;padding-inline:2px}.executive-inline-skin .list-row-slot--owner{justify-content:flex-start;padding-left:0}.executive-inline-skin .list-row-slot--actions{justify-content:flex-end;padding-left:0}.executive-inline-skin .list-row-slot--expand{justify-content:center}.executive-inline-skin .docs-expansion-leading{width:44px;height:44px;display:inline-flex;align-items:center;justify-content:center;border-radius:15px;background:linear-gradient(180deg,#edf4f9,#e6eef5);color:#1b5f86;font-size:1rem;font-weight:800;letter-spacing:.02em;box-shadow:0 1px 3px #1b5f861f;border:1px solid #dbe7f0}.executive-inline-skin .exec-balance-metric,.executive-inline-skin .exec-limit-metric,.executive-inline-skin .exec-risk-metric{min-width:0}.executive-inline-skin .exec-balance-metric .p-list-metric,.executive-inline-skin .exec-limit-metric .p-list-metric,.executive-inline-skin .exec-risk-metric .p-list-metric{gap:5px}.executive-inline-skin .exec-balance-metric .p-list-metric__label,.executive-inline-skin .exec-limit-metric .p-list-metric__label,.executive-inline-skin .exec-risk-metric .p-list-metric__label{font-size:.62rem;font-weight:700;letter-spacing:.08em;text-transform:uppercase;color:#8090a1}.executive-inline-skin .exec-balance-metric .p-list-metric__value,.executive-inline-skin .exec-limit-metric .p-list-metric__value{font-size:.96rem;font-weight:800;letter-spacing:-.02em;color:#0d1f34;line-height:1.05}.executive-inline-skin .exec-limit-metric .p-list-metric__caption{font-size:.66rem;font-weight:700;color:#8090a1}.executive-inline-skin .exec-limit-metric .p-list-metric__progress{width:68px;justify-self:center;height:3px}.executive-inline-skin .exec-risk-metric{min-width:84px}.executive-inline-skin .exec-risk-metric .p-list-metric{justify-items:center}.executive-inline-skin .exec-risk-metric .p-list-metric__main{gap:6px}.executive-inline-skin .exec-risk-metric .p-list-metric__value{font-size:1.02rem;font-weight:800;letter-spacing:-.024em;line-height:1}.executive-inline-skin .exec-risk-metric .p-list-metric__progress{width:56px;justify-self:center;height:3px}.executive-inline-skin .exec-risk-metric .p-list-metric__caption{font-size:.7rem;font-weight:700;line-height:1.1}.executive-inline-skin .exec-risk-metric .p-list-metric__caption--below-progress{justify-self:center;margin-top:-1px}.executive-inline-skin .exec-risk-metric .p-list-metric__icon mat-icon{width:15px;height:15px;font-size:15px}.executive-inline-skin .list-item-actions{gap:6px;flex-wrap:nowrap}.executive-inline-skin .list-row-slot--actions .list-item-actions{justify-content:flex-end}.executive-inline-skin .list-item-actions button,.executive-inline-skin .expand-toggle{width:30px;height:30px;min-width:30px;border-radius:12px;color:#6d7f93!important}.executive-inline-skin .list-item-actions button mat-icon,.executive-inline-skin .expand-toggle mat-icon{width:18px;height:18px;font-size:18px}.executive-inline-skin .item-expansion{position:relative;margin-top:-10px;padding:22px 26px;background:linear-gradient(180deg,#fcfdfe,#f5f8fb);border-color:#e4eaf0;border-radius:0 0 22px 22px;box-shadow:inset 0 1px #ffffffdb}.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}.inline-image{position:relative;width:20px;height:20px;border-radius:4px;overflow:hidden;display:inline-block;vertical-align:middle}.inline-image img{width:100%;height:100%;object-fit:cover;display:block}.inline-image .inline-badge{position:absolute;left:2px;bottom:2px}.model-media .lead-image{width:136px;height:96px;border-radius:16px}.model-media .list-item-content{gap:16px}.model-media .item-card{--p-list-leading-width: 136px}.model-hotel .lead-image{width:160px;height:110px;border-radius:18px}.model-hotel .item-card{--p-list-leading-width: 160px}.primary,.secondary{display:-webkit-box;-webkit-box-orient:vertical;overflow:hidden;text-overflow:ellipsis}.primary{-webkit-line-clamp:1;font-weight:600;color:var(--p-list-foreground)}.secondary{-webkit-line-clamp:1;color:var(--p-list-foreground-muted)}.lines-3 .tertiary{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.item-tile .primary{-webkit-line-clamp:2;font-size:.95rem;line-height:1.25rem}.item-tile .secondary{-webkit-line-clamp:2;font-size:.8rem;line-height:1.1rem}.tertiary{color:var(--p-list-foreground-muted)}.features{display:flex;flex-wrap:wrap;gap:12px;margin-top:6px;color:inherit}.feature{display:inline-flex;align-items:center;gap:6px}.feature-line{display:block}.feature-progress{display:block;width:88px;height:4px;margin-top:6px;border-radius:999px;background:#dbe5eb;overflow:hidden}.feature-progress__value{display:block;height:100%;border-radius:inherit;background:#2f9b69}.meta{color:var(--p-list-foreground);font-size:var(--p-list-meta-size);font-weight:var(--p-list-meta-weight);font-variant-numeric:tabular-nums;white-space:nowrap}.trailing{color:var(--p-list-foreground-muted);margin-left:0;white-space:nowrap}.section-header{font-size:.85rem;color:var(--p-list-foreground-muted);padding:8px 12px}.praxis-list-root mat-list,.praxis-list-root mat-selection-list{display:block;padding-bottom:12px}.praxis-list-root .mat-divider{margin-left:var(--p-list-item-padding-x);margin-right:var(--p-list-item-padding-x)}.item-expansion{margin:0 var(--p-list-item-padding-x) var(--p-list-item-stack-gap);padding:14px 16px;background:color-mix(in srgb,var(--p-list-surface) 88%,white 12%);border:1px solid var(--md-sys-color-outline-variant);border-radius:calc(var(--p-list-radius) * .75)}.item-expansion-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(220px,1fr));gap:16px}.expansion-section{min-width:0;display:grid;gap:10px;align-content:start}.expansion-section-title{font-size:.78rem;font-weight:700;letter-spacing:.04em;text-transform:uppercase;color:var(--p-list-foreground-muted)}.expansion-info-list,.expansion-timeline,.expansion-key-value{display:grid;gap:10px}.expansion-info-item,.expansion-timeline-item{display:grid;gap:4px;padding:10px 12px;border-radius:14px;background:var(--p-list-item-surface);border:1px solid color-mix(in srgb,var(--md-sys-color-outline-variant) 72%,transparent 28%)}.expansion-info-title,.expansion-timeline-title{font-size:.92rem;font-weight:600;color:var(--p-list-foreground)}.expansion-info-value,.expansion-timeline-meta,.expansion-timeline-description,.expansion-empty{font-size:.82rem;line-height:1.45;color:var(--p-list-foreground-muted)}.expansion-chip-list{display:flex;flex-wrap:wrap;gap:8px}.expansion-chip{background:var(--p-list-item-surface);border:1px solid var(--md-sys-color-outline-variant)}.expansion-key-value{margin:0}.expansion-key-value-row{display:grid;gap:4px;padding:10px 12px;border-radius:14px;background:var(--p-list-item-surface);border:1px solid color-mix(in srgb,var(--md-sys-color-outline-variant) 72%,transparent 28%)}.expansion-key-value-row dt,.expansion-key-value-row dd{margin:0}.expansion-key-value-row dt{font-size:.78rem;font-weight:600;color:var(--p-list-foreground-muted)}.expansion-key-value-row dd{font-size:.9rem;color:var(--p-list-foreground)}.cards-grid,.tiles-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(var(--p-list-tile-minW),1fr));gap:var(--p-list-tile-gap)}.item-tile{position:relative;display:flex;flex-direction:column;gap:10px;padding:var(--p-list-tile-padding);border-radius:var(--p-list-tile-radius);background:var(--p-list-surface);border:var(--p-list-border);color:var(--p-list-foreground);cursor:pointer;min-height:160px;transition:box-shadow .16s ease-out,border-color .16s ease-out,transform .12s ease-out,background .16s ease-out}.item-tile:hover{box-shadow:var(--md-sys-elevation-level2);border-color:var(--md-sys-color-outline-variant);background:var(--p-list-item-hover-surface)}.item-tile:active{transform:scale(var(--p-list-tile-press-scale));background:var(--p-list-item-active-surface)}.item-tile:focus-visible{outline:2px solid var(--md-sys-color-primary);outline-offset:2px}.tile-media{width:100%;aspect-ratio:var(--p-list-tile-media-ratio);border-radius:var(--p-list-tile-media-radius);background:var(--p-list-item-surface);border:1px solid var(--md-sys-color-outline-variant);display:grid;place-items:center;overflow:hidden}.tile-media img{width:100%;height:100%;object-fit:cover;display:block}.tile-media mat-icon{font-size:28px;height:28px;width:28px;color:var(--p-list-foreground-muted)}.tile-body{display:grid;gap:6px;min-width:0}.tile-meta{display:inline-flex;align-items:center;gap:6px;font-size:.75rem;color:var(--p-list-foreground-muted);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.tile-trailing{font-size:.75rem;color:var(--p-list-foreground-muted);white-space:nowrap}.tiles-features{display:flex;flex-wrap:wrap;gap:8px;color:inherit}.tile-status{position:absolute;top:10px;right:10px}.tile-actions{position:absolute;top:8px;left:8px;display:flex;gap:4px;opacity:0;pointer-events:none;transform:translateY(-2px);transition:opacity .16s ease-out,transform .16s ease-out}.item-tile:hover .tile-actions,.item-tile:focus-visible .tile-actions,.item-tile:focus-within .tile-actions{opacity:1;pointer-events:auto;transform:translateY(0)}@media(hover:none){.tile-actions{opacity:1;pointer-events:auto;transform:none}}@media(max-width:600px){.tiles-grid{grid-template-columns:repeat(auto-fit,minmax(200px,1fr))}}@media(prefers-reduced-motion:reduce){.item-tile,.tile-actions{transition:none}.item-tile:active{transform:none}.item-card{transition:none}.item-card:active{transform:none}}.item-card{padding:var(--p-list-tile-padding);display:flex;flex-direction:column;min-height:160px;position:relative;cursor:pointer;background:var(--p-list-surface);border:var(--p-list-border);border-radius:var(--p-list-tile-radius);box-shadow:var(--p-list-shadow);transition:box-shadow .16s ease-out,border-color .16s ease-out,transform .12s ease-out,background .16s ease-out;--p-list-leading-width: 96px;--p-list-trailing-min-width: 0px}.item-card .list-item-trailing{min-width:var(--p-list-trailing-min-width)}.item-card:hover{box-shadow:var(--md-sys-elevation-level3);border-color:var(--md-sys-color-outline-variant);background:var(--p-list-item-hover-surface)}.item-card:active{transform:scale(var(--p-list-tile-press-scale));background:var(--p-list-item-active-surface)}.item-card:focus-visible{outline:2px solid var(--md-sys-color-primary);outline-offset:2px}.card-actions{display:flex;align-items:center;justify-content:flex-end;gap:4px;padding:6px 8px 4px;border-top:1px solid var(--md-sys-color-outline-variant);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:var(--md-sys-color-primary-container);color:var(--md-sys-color-on-primary-container)}.mat-mdc-chip{--mdc-chip-container-height: var(--p-list-chip-height);font-size:var(--p-list-chip-font-size)}.meta .mat-icon{font-size:18px;height:18px;width:18px}.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:linear-gradient(to right,var(--md-sys-color-surface-container-low) 8%,var(--md-sys-color-surface-container) 18%,var(--md-sys-color-surface-container-low) 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;flex-wrap:wrap;gap:8px;margin-top:14px;padding:14px 4px 8px;border-top:1px solid var(--md-sys-color-outline-variant);position:relative;z-index:1;background:var(--p-list-surface-low);border-radius:calc(var(--p-list-radius) * .75)}.paginator-controls{display:flex;align-items:center;gap:8px;flex-wrap:wrap}.paginator-meta{display:flex;align-items:center;gap:8px;margin-left:auto}.paginator-page-size{width:120px}.paginator-sort{width:180px}.paginator-search{min-width:220px}.muted{color:var(--p-list-foreground-muted)}@media(max-width:720px){.list-item-content{grid-template-columns:var(--p-list-leading-width) minmax(0,1fr)}.list-item-trailing{grid-column:1/-1;padding-right:0;align-items:flex-start;text-align:start}.item-expansion{margin-left:0;margin-right:0}.paginator{align-items:stretch}.paginator-controls{width:100%}.paginator-meta{width:100%;margin-left:0;justify-content:flex-start}.paginator-page-size,.paginator-sort,.paginator-search{width:100%;min-width:0}}\n"] }]
9504
9960
  }], propDecorators: { config: [{
9505
9961
  type: Input
9506
9962
  }], listId: [{
@@ -9521,6 +9977,149 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImpo
9521
9977
  type: Output
9522
9978
  }] } });
9523
9979
 
9980
+ function isListTemplateSupportedByRichContentP0(template) {
9981
+ if (!template) {
9982
+ return false;
9983
+ }
9984
+ switch (template.type) {
9985
+ case 'text':
9986
+ case 'icon':
9987
+ case 'image':
9988
+ case 'chip':
9989
+ case 'metric':
9990
+ case 'compose':
9991
+ return true;
9992
+ default:
9993
+ return false;
9994
+ }
9995
+ }
9996
+ function mapListTemplateToRichContentP0(template) {
9997
+ if (!template) {
9998
+ return null;
9999
+ }
10000
+ switch (template.type) {
10001
+ case 'text':
10002
+ return mapTextTemplate(template);
10003
+ case 'icon':
10004
+ return {
10005
+ type: 'icon',
10006
+ icon: template.expr || '',
10007
+ className: template.class,
10008
+ style: parseInlineStyle(template.style),
10009
+ };
10010
+ case 'image':
10011
+ return mapImageTemplate(template);
10012
+ case 'chip':
10013
+ return mapChipTemplate(template);
10014
+ case 'metric':
10015
+ return mapMetricTemplate(template);
10016
+ case 'compose':
10017
+ return mapComposeTemplate(template);
10018
+ default:
10019
+ return null;
10020
+ }
10021
+ }
10022
+ function mapTextTemplate(template) {
10023
+ return {
10024
+ type: 'text',
10025
+ textExpr: template.expr,
10026
+ className: template.class,
10027
+ style: parseInlineStyle(template.style),
10028
+ };
10029
+ }
10030
+ function mapImageTemplate(template) {
10031
+ return {
10032
+ type: 'image',
10033
+ srcExpr: template.expr,
10034
+ alt: template.imageAlt,
10035
+ className: template.class,
10036
+ style: parseInlineStyle(template.style),
10037
+ };
10038
+ }
10039
+ function mapChipTemplate(template) {
10040
+ return {
10041
+ type: 'badge',
10042
+ labelExpr: template.expr,
10043
+ className: template.class,
10044
+ style: parseInlineStyle(template.style),
10045
+ };
10046
+ }
10047
+ function mapMetricTemplate(template) {
10048
+ const metric = template.props?.metric;
10049
+ return {
10050
+ type: 'metric',
10051
+ label: metric?.label || '',
10052
+ valueExpr: metric?.valueExpr || template.expr || '',
10053
+ captionExpr: metric?.caption,
10054
+ icon: metric?.icon,
10055
+ className: template.class,
10056
+ style: parseInlineStyle(template.style),
10057
+ };
10058
+ }
10059
+ function mapComposeTemplate(template) {
10060
+ const compose = template.props?.compose;
10061
+ const childTemplates = compose?.items ?? compose?.nodes ?? [];
10062
+ return {
10063
+ type: 'compose',
10064
+ direction: compose?.direction === 'column' || compose?.orientation === 'vertical'
10065
+ ? 'column'
10066
+ : 'row',
10067
+ gap: normalizeGap(compose?.gap),
10068
+ wrap: compose?.wrap,
10069
+ className: template.class || compose?.class,
10070
+ style: parseInlineStyle(template.style || compose?.style),
10071
+ items: childTemplates
10072
+ .map(child => mapListTemplateToRichContentP0(child))
10073
+ .filter(isRichPresenterNode),
10074
+ };
10075
+ }
10076
+ function normalizeGap(gap) {
10077
+ switch ((gap || '').trim()) {
10078
+ case '4px':
10079
+ case '0.25rem':
10080
+ case 'xs':
10081
+ return 'xs';
10082
+ case '8px':
10083
+ case '0.5rem':
10084
+ case 'sm':
10085
+ return 'sm';
10086
+ case '16px':
10087
+ case '1rem':
10088
+ case 'lg':
10089
+ return 'lg';
10090
+ case '20px':
10091
+ case '1.25rem':
10092
+ case 'xl':
10093
+ return 'xl';
10094
+ default:
10095
+ return gap ? 'md' : undefined;
10096
+ }
10097
+ }
10098
+ function isRichPresenterNode(node) {
10099
+ return !!node && node.type !== 'compose';
10100
+ }
10101
+ function parseInlineStyle(inlineStyle) {
10102
+ const source = (inlineStyle || '').trim();
10103
+ if (!source) {
10104
+ return undefined;
10105
+ }
10106
+ const entries = source
10107
+ .split(';')
10108
+ .map(part => part.trim())
10109
+ .filter(Boolean)
10110
+ .map(part => {
10111
+ const separator = part.indexOf(':');
10112
+ if (separator === -1) {
10113
+ return null;
10114
+ }
10115
+ const key = part.slice(0, separator).trim();
10116
+ const value = part.slice(separator + 1).trim();
10117
+ return key && value ? [key, value] : null;
10118
+ })
10119
+ .filter((entry) => !!entry);
10120
+ return entries.length ? Object.fromEntries(entries) : undefined;
10121
+ }
10122
+
9524
10123
  const PRAXIS_LIST_COMPONENT_METADATA = {
9525
10124
  id: 'praxis-list',
9526
10125
  selector: 'praxis-list',
@@ -10887,4 +11486,4 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImpo
10887
11486
  * Generated bundle index. Do not edit.
10888
11487
  */
10889
11488
 
10890
- export { ExecutiveAlertsComponent, ExecutiveBadgeComponent, ExecutiveOwnerComponent, LIST_AI_CAPABILITIES, ListDataService, ListSkinService, PRAXIS_LIST_COMPONENT_METADATA, PRAXIS_LIST_EN_US, PRAXIS_LIST_I18N_NAMESPACE, PRAXIS_LIST_PT_BR, PraxisList, PraxisListConfigEditor, PraxisListDocPageComponent, PraxisListJsonConfigEditorComponent, adaptSelection, buildListApplyPlan, createListAuthoringDocument, evalExpr, evaluateTemplate, inferListAuthoringDocument, inferTemplatingFromSchema, normalizeListActionPayloads, normalizeListAuthoringDocument, normalizeListConfig, parseLegacyOrListDocument, projectListAuthoringDocument, providePraxisListI18n, providePraxisListMetadata, serializeListAuthoringDocument, toCanonicalListConfig, validateListAuthoringDocument };
11489
+ export { ExecutiveAlertsComponent, ExecutiveBadgeComponent, ExecutiveOwnerComponent, LIST_AI_CAPABILITIES, ListDataService, ListSkinService, PRAXIS_LIST_COMPONENT_METADATA, PRAXIS_LIST_EN_US, PRAXIS_LIST_I18N_NAMESPACE, PRAXIS_LIST_PT_BR, PraxisList, PraxisListConfigEditor, PraxisListDocPageComponent, PraxisListJsonConfigEditorComponent, adaptSelection, buildListApplyPlan, createListAuthoringDocument, evalExpr, evaluateTemplate, inferListAuthoringDocument, inferTemplatingFromSchema, isListTemplateSupportedByRichContentP0, mapListTemplateToRichContentP0, normalizeListActionPayloads, normalizeListAuthoringDocument, normalizeListConfig, parseLegacyOrListDocument, projectListAuthoringDocument, providePraxisListI18n, providePraxisListMetadata, serializeListAuthoringDocument, toCanonicalListConfig, validateListAuthoringDocument };