@telcomdev/ui 0.1.12 → 0.1.13

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.
@@ -6,7 +6,7 @@ import { FORM_FIELD } from '@angular/forms/signals';
6
6
  import * as i2 from '@angular/cdk/scrolling';
7
7
  import { ScrollingModule, CdkVirtualScrollViewport } from '@angular/cdk/scrolling';
8
8
  import { NgTemplateOutlet, NgComponentOutlet, DOCUMENT } from '@angular/common';
9
- import { ScrollStrategyOptions, CdkConnectedOverlay, CdkOverlayOrigin } from '@angular/cdk/overlay';
9
+ import { CdkConnectedOverlay, CdkOverlayOrigin, ScrollStrategyOptions } from '@angular/cdk/overlay';
10
10
  import { DIALOG_DATA, Dialog } from '@angular/cdk/dialog';
11
11
  import { CdkDrag, CdkDragHandle } from '@angular/cdk/drag-drop';
12
12
  import { RouterLink, RouterLinkActive } from '@angular/router';
@@ -1104,12 +1104,118 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.4", ngImpor
1104
1104
  args: ['nativeInput']
1105
1105
  }], id: [{ type: i0.Input, args: [{ isSignal: true, alias: "id", required: false }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], description: [{ type: i0.Input, args: [{ isSignal: true, alias: "description", required: false }] }], hint: [{ type: i0.Input, args: [{ isSignal: true, alias: "hint", required: false }] }], dark: [{ type: i0.Input, args: [{ isSignal: true, alias: "dark", required: false }] }], name: [{ type: i0.Input, args: [{ isSignal: true, alias: "name", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], disabledReasons: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabledReasons", required: false }] }], readonly: [{ type: i0.Input, args: [{ isSignal: true, alias: "readonly", required: false }] }], hidden: [{ type: i0.Input, args: [{ isSignal: true, alias: "hidden", required: false }] }], invalid: [{ type: i0.Input, args: [{ isSignal: true, alias: "invalid", required: false }] }], pending: [{ type: i0.Input, args: [{ isSignal: true, alias: "pending", required: false }] }], dirty: [{ type: i0.Input, args: [{ isSignal: true, alias: "dirty", required: false }] }], required: [{ type: i0.Input, args: [{ isSignal: true, alias: "required", required: false }] }], errors: [{ type: i0.Input, args: [{ isSignal: true, alias: "errors", required: false }] }], touched: [{ type: i0.Input, args: [{ isSignal: true, alias: "touched", required: false }] }, { type: i0.Output, args: ["touchedChange"] }], touch: [{ type: i0.Output, args: ["touch"] }], error: [{ type: i0.Input, args: [{ isSignal: true, alias: "error", required: false }] }], errorDisplay: [{ type: i0.Input, args: [{ isSignal: true, alias: "errorDisplay", required: false }] }], checked: [{ type: i0.Input, args: [{ isSignal: true, alias: "checked", required: false }] }, { type: i0.Output, args: ["checkedChange"] }] } });
1106
1106
 
1107
+ class TdMenu {
1108
+ items = [];
1109
+ etiqueta = '';
1110
+ icono = 'more_vertical';
1111
+ posicion = 'abajo-fin';
1112
+ ancho = '14rem';
1113
+ disabled = false;
1114
+ oscuro = false;
1115
+ ariaLabel = 'Abrir menu';
1116
+ seleccion = new EventEmitter();
1117
+ abiertoChange = new EventEmitter();
1118
+ abierto = false;
1119
+ get itemsVisibles() {
1120
+ return this.items.filter((item) => item.visible ?? true);
1121
+ }
1122
+ alternar() {
1123
+ if (this.disabled)
1124
+ return;
1125
+ this.establecerAbierto(!this.abierto);
1126
+ }
1127
+ cerrar() {
1128
+ this.establecerAbierto(false);
1129
+ }
1130
+ seleccionar(item) {
1131
+ if (item.deshabilitado)
1132
+ return;
1133
+ this.seleccion.emit({ item, id: item.id, data: item.data });
1134
+ this.cerrar();
1135
+ }
1136
+ posiciones() {
1137
+ const offset = 8;
1138
+ const mapa = {
1139
+ 'abajo-inicio': [
1140
+ {
1141
+ originX: 'start',
1142
+ originY: 'bottom',
1143
+ overlayX: 'start',
1144
+ overlayY: 'top',
1145
+ offsetY: offset,
1146
+ },
1147
+ ],
1148
+ 'abajo-fin': [
1149
+ {
1150
+ originX: 'end',
1151
+ originY: 'bottom',
1152
+ overlayX: 'end',
1153
+ overlayY: 'top',
1154
+ offsetY: offset,
1155
+ },
1156
+ ],
1157
+ 'arriba-inicio': [
1158
+ {
1159
+ originX: 'start',
1160
+ originY: 'top',
1161
+ overlayX: 'start',
1162
+ overlayY: 'bottom',
1163
+ offsetY: -offset,
1164
+ },
1165
+ ],
1166
+ 'arriba-fin': [
1167
+ {
1168
+ originX: 'end',
1169
+ originY: 'top',
1170
+ overlayX: 'end',
1171
+ overlayY: 'bottom',
1172
+ offsetY: -offset,
1173
+ },
1174
+ ],
1175
+ };
1176
+ return mapa[this.posicion];
1177
+ }
1178
+ establecerAbierto(valor) {
1179
+ if (this.abierto === valor)
1180
+ return;
1181
+ this.abierto = valor;
1182
+ this.abiertoChange.emit(valor);
1183
+ }
1184
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: TdMenu, deps: [], target: i0.ɵɵFactoryTarget.Component });
1185
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.4", type: TdMenu, isStandalone: true, selector: "td-menu", inputs: { items: "items", etiqueta: "etiqueta", icono: "icono", posicion: "posicion", ancho: "ancho", disabled: "disabled", oscuro: "oscuro", ariaLabel: "ariaLabel" }, outputs: { seleccion: "seleccion", abiertoChange: "abiertoChange" }, ngImport: i0, template: "<button\n #origen=\"cdkOverlayOrigin\"\n cdkOverlayOrigin\n type=\"button\"\n class=\"td-menu__trigger\"\n [class.td-menu__trigger--icon-only]=\"!etiqueta\"\n [disabled]=\"disabled\"\n [attr.aria-label]=\"ariaLabel\"\n [attr.aria-expanded]=\"abierto\"\n aria-haspopup=\"menu\"\n (click)=\"alternar()\"\n>\n @if (icono) {\n <td-icon [nombre]=\"icono\" />\n }\n @if (etiqueta) {\n <span>{{ etiqueta }}</span>\n <td-icon nombre=\"chevron_down\" tamano=\".95rem\" />\n }\n</button>\n\n<ng-template\n cdkConnectedOverlay\n [cdkConnectedOverlayOrigin]=\"origen\"\n [cdkConnectedOverlayOpen]=\"abierto\"\n [cdkConnectedOverlayPositions]=\"posiciones()\"\n [cdkConnectedOverlayHasBackdrop]=\"true\"\n [cdkConnectedOverlayBackdropClass]=\"'td-menu__backdrop'\"\n [cdkConnectedOverlayPanelClass]=\"'td-menu__overlay'\"\n (backdropClick)=\"cerrar()\"\n (detach)=\"cerrar()\"\n>\n <div\n class=\"td-menu\"\n [class.td-menu--oscuro]=\"oscuro\"\n [style.width]=\"ancho\"\n role=\"menu\"\n >\n @for (item of itemsVisibles; track item.id) {\n @if (item.separadorAntes) {\n <span class=\"td-menu__separador\" aria-hidden=\"true\"></span>\n }\n <button\n type=\"button\"\n role=\"menuitem\"\n [class]=\"'td-menu__item td-menu__item--' + (item.tono || 'neutro')\"\n [disabled]=\"item.deshabilitado\"\n (click)=\"seleccionar(item)\"\n >\n @if (item.icono) {\n <span class=\"td-menu__icono\">\n <td-icon [nombre]=\"item.icono\" />\n </span>\n }\n <span class=\"td-menu__texto\">\n <strong>{{ item.etiqueta }}</strong>\n @if (item.descripcion) {\n <small>{{ item.descripcion }}</small>\n }\n </span>\n </button>\n } @empty {\n <div class=\"td-menu__vacio\">\n <td-icon nombre=\"inbox\" />\n <span>Sin opciones disponibles</span>\n </div>\n }\n </div>\n</ng-template>\n", styles: [":host{display:inline-block;font-family:var(--td-font-family, Inter, ui-sans-serif, system-ui, sans-serif)}*{box-sizing:border-box}.td-menu__trigger{display:inline-flex;min-height:2.35rem;align-items:center;justify-content:center;gap:.45rem;border:1px solid var(--td-color-border, #d9e1ee);border-radius:var(--td-radius-md, .85rem);padding:0 .8rem;color:var(--td-color-text, #202b3d);background:var(--td-color-surface, #fff);box-shadow:var(--td-shadow-xs, 0 6px 16px rgba(31, 42, 68, .06));font:inherit;font-size:.78rem;font-weight:800;cursor:pointer;transition:border-color .14s ease,color .14s ease,box-shadow .14s ease,transform .14s ease}.td-menu__trigger:hover:not(:disabled),.td-menu__trigger[aria-expanded=true]{border-color:var(--td-color-primary, #5746d8);color:var(--td-color-primary, #5746d8);box-shadow:var(--td-focus-ring, 0 0 0 3px rgba(87, 70, 216, .14))}.td-menu__trigger:disabled{opacity:.55;cursor:not-allowed}.td-menu__trigger--icon-only{width:2.35rem;padding:0}.td-menu{overflow:hidden;border:1px solid var(--td-color-border, #d9e1ee);border-radius:var(--td-radius-lg, 1rem);padding:.35rem;color:var(--td-color-text, #202b3d);background:var(--td-color-surface, #fff);box-shadow:var(--td-shadow-lg, 0 22px 52px rgba(15, 23, 42, .18));font-family:var(--td-font-family, Inter, ui-sans-serif, system-ui, sans-serif)}.td-menu--oscuro{border-color:var(--td-color-border, #2d3342);color:var(--td-color-text, #f8fafc);background:var(--td-color-surface, #111827)}.td-menu__item{display:grid;width:100%;grid-template-columns:auto minmax(0,1fr);align-items:center;gap:.65rem;border:0;border-radius:var(--td-radius-md, .75rem);padding:.62rem .7rem;color:inherit;background:transparent;font:inherit;text-align:left;cursor:pointer}.td-menu__item:hover:not(:disabled),.td-menu__item:focus-visible{outline:none;background:var(--td-color-primary-soft, #eef2ff)}.td-menu__item:disabled{opacity:.45;cursor:not-allowed}.td-menu__item--primario{color:var(--td-color-primary, #5746d8)}.td-menu__item--exito{color:var(--td-color-success, #07845c)}.td-menu__item--advertencia{color:var(--td-color-warning, #b7791f)}.td-menu__item--peligro{color:var(--td-color-danger, #dc2626)}.td-menu__icono{display:grid;width:2rem;height:2rem;place-items:center;border-radius:var(--td-radius-sm, .6rem);background:color-mix(in srgb,currentColor 10%,transparent)}.td-menu__texto{display:grid;min-width:0;gap:.12rem}.td-menu__texto strong,.td-menu__texto small{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.td-menu__texto strong{font-size:.78rem}.td-menu__texto small{color:var(--td-color-text-muted, #64748b);font-size:.68rem;font-weight:650}.td-menu__separador{display:block;height:1px;margin:.35rem .45rem;background:var(--td-color-border, #d9e1ee)}.td-menu__vacio{display:grid;min-height:5.5rem;place-items:center;align-content:center;gap:.35rem;color:var(--td-color-text-muted, #64748b);font-size:.75rem;font-weight:750}\n"], dependencies: [{ kind: "directive", type: CdkConnectedOverlay, selector: "[cdk-connected-overlay], [connected-overlay], [cdkConnectedOverlay]", inputs: ["cdkConnectedOverlayOrigin", "cdkConnectedOverlayPositions", "cdkConnectedOverlayPositionStrategy", "cdkConnectedOverlayOffsetX", "cdkConnectedOverlayOffsetY", "cdkConnectedOverlayWidth", "cdkConnectedOverlayHeight", "cdkConnectedOverlayMinWidth", "cdkConnectedOverlayMinHeight", "cdkConnectedOverlayBackdropClass", "cdkConnectedOverlayPanelClass", "cdkConnectedOverlayViewportMargin", "cdkConnectedOverlayScrollStrategy", "cdkConnectedOverlayOpen", "cdkConnectedOverlayDisableClose", "cdkConnectedOverlayTransformOriginOn", "cdkConnectedOverlayHasBackdrop", "cdkConnectedOverlayLockPosition", "cdkConnectedOverlayFlexibleDimensions", "cdkConnectedOverlayGrowAfterOpen", "cdkConnectedOverlayPush", "cdkConnectedOverlayDisposeOnNavigation", "cdkConnectedOverlayUsePopover", "cdkConnectedOverlayMatchWidth", "cdkConnectedOverlay"], outputs: ["backdropClick", "positionChange", "attach", "detach", "overlayKeydown", "overlayOutsideClick"], exportAs: ["cdkConnectedOverlay"] }, { kind: "directive", type: CdkOverlayOrigin, selector: "[cdk-overlay-origin], [overlay-origin], [cdkOverlayOrigin]", exportAs: ["cdkOverlayOrigin"] }, { kind: "component", type: TdIcon, selector: "td-icon", inputs: ["nombre", "titulo", "tamano"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1186
+ }
1187
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: TdMenu, decorators: [{
1188
+ type: Component,
1189
+ args: [{ selector: 'td-menu', imports: [CdkConnectedOverlay, CdkOverlayOrigin, TdIcon], changeDetection: ChangeDetectionStrategy.OnPush, template: "<button\n #origen=\"cdkOverlayOrigin\"\n cdkOverlayOrigin\n type=\"button\"\n class=\"td-menu__trigger\"\n [class.td-menu__trigger--icon-only]=\"!etiqueta\"\n [disabled]=\"disabled\"\n [attr.aria-label]=\"ariaLabel\"\n [attr.aria-expanded]=\"abierto\"\n aria-haspopup=\"menu\"\n (click)=\"alternar()\"\n>\n @if (icono) {\n <td-icon [nombre]=\"icono\" />\n }\n @if (etiqueta) {\n <span>{{ etiqueta }}</span>\n <td-icon nombre=\"chevron_down\" tamano=\".95rem\" />\n }\n</button>\n\n<ng-template\n cdkConnectedOverlay\n [cdkConnectedOverlayOrigin]=\"origen\"\n [cdkConnectedOverlayOpen]=\"abierto\"\n [cdkConnectedOverlayPositions]=\"posiciones()\"\n [cdkConnectedOverlayHasBackdrop]=\"true\"\n [cdkConnectedOverlayBackdropClass]=\"'td-menu__backdrop'\"\n [cdkConnectedOverlayPanelClass]=\"'td-menu__overlay'\"\n (backdropClick)=\"cerrar()\"\n (detach)=\"cerrar()\"\n>\n <div\n class=\"td-menu\"\n [class.td-menu--oscuro]=\"oscuro\"\n [style.width]=\"ancho\"\n role=\"menu\"\n >\n @for (item of itemsVisibles; track item.id) {\n @if (item.separadorAntes) {\n <span class=\"td-menu__separador\" aria-hidden=\"true\"></span>\n }\n <button\n type=\"button\"\n role=\"menuitem\"\n [class]=\"'td-menu__item td-menu__item--' + (item.tono || 'neutro')\"\n [disabled]=\"item.deshabilitado\"\n (click)=\"seleccionar(item)\"\n >\n @if (item.icono) {\n <span class=\"td-menu__icono\">\n <td-icon [nombre]=\"item.icono\" />\n </span>\n }\n <span class=\"td-menu__texto\">\n <strong>{{ item.etiqueta }}</strong>\n @if (item.descripcion) {\n <small>{{ item.descripcion }}</small>\n }\n </span>\n </button>\n } @empty {\n <div class=\"td-menu__vacio\">\n <td-icon nombre=\"inbox\" />\n <span>Sin opciones disponibles</span>\n </div>\n }\n </div>\n</ng-template>\n", styles: [":host{display:inline-block;font-family:var(--td-font-family, Inter, ui-sans-serif, system-ui, sans-serif)}*{box-sizing:border-box}.td-menu__trigger{display:inline-flex;min-height:2.35rem;align-items:center;justify-content:center;gap:.45rem;border:1px solid var(--td-color-border, #d9e1ee);border-radius:var(--td-radius-md, .85rem);padding:0 .8rem;color:var(--td-color-text, #202b3d);background:var(--td-color-surface, #fff);box-shadow:var(--td-shadow-xs, 0 6px 16px rgba(31, 42, 68, .06));font:inherit;font-size:.78rem;font-weight:800;cursor:pointer;transition:border-color .14s ease,color .14s ease,box-shadow .14s ease,transform .14s ease}.td-menu__trigger:hover:not(:disabled),.td-menu__trigger[aria-expanded=true]{border-color:var(--td-color-primary, #5746d8);color:var(--td-color-primary, #5746d8);box-shadow:var(--td-focus-ring, 0 0 0 3px rgba(87, 70, 216, .14))}.td-menu__trigger:disabled{opacity:.55;cursor:not-allowed}.td-menu__trigger--icon-only{width:2.35rem;padding:0}.td-menu{overflow:hidden;border:1px solid var(--td-color-border, #d9e1ee);border-radius:var(--td-radius-lg, 1rem);padding:.35rem;color:var(--td-color-text, #202b3d);background:var(--td-color-surface, #fff);box-shadow:var(--td-shadow-lg, 0 22px 52px rgba(15, 23, 42, .18));font-family:var(--td-font-family, Inter, ui-sans-serif, system-ui, sans-serif)}.td-menu--oscuro{border-color:var(--td-color-border, #2d3342);color:var(--td-color-text, #f8fafc);background:var(--td-color-surface, #111827)}.td-menu__item{display:grid;width:100%;grid-template-columns:auto minmax(0,1fr);align-items:center;gap:.65rem;border:0;border-radius:var(--td-radius-md, .75rem);padding:.62rem .7rem;color:inherit;background:transparent;font:inherit;text-align:left;cursor:pointer}.td-menu__item:hover:not(:disabled),.td-menu__item:focus-visible{outline:none;background:var(--td-color-primary-soft, #eef2ff)}.td-menu__item:disabled{opacity:.45;cursor:not-allowed}.td-menu__item--primario{color:var(--td-color-primary, #5746d8)}.td-menu__item--exito{color:var(--td-color-success, #07845c)}.td-menu__item--advertencia{color:var(--td-color-warning, #b7791f)}.td-menu__item--peligro{color:var(--td-color-danger, #dc2626)}.td-menu__icono{display:grid;width:2rem;height:2rem;place-items:center;border-radius:var(--td-radius-sm, .6rem);background:color-mix(in srgb,currentColor 10%,transparent)}.td-menu__texto{display:grid;min-width:0;gap:.12rem}.td-menu__texto strong,.td-menu__texto small{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.td-menu__texto strong{font-size:.78rem}.td-menu__texto small{color:var(--td-color-text-muted, #64748b);font-size:.68rem;font-weight:650}.td-menu__separador{display:block;height:1px;margin:.35rem .45rem;background:var(--td-color-border, #d9e1ee)}.td-menu__vacio{display:grid;min-height:5.5rem;place-items:center;align-content:center;gap:.35rem;color:var(--td-color-text-muted, #64748b);font-size:.75rem;font-weight:750}\n"] }]
1190
+ }], propDecorators: { items: [{
1191
+ type: Input
1192
+ }], etiqueta: [{
1193
+ type: Input
1194
+ }], icono: [{
1195
+ type: Input
1196
+ }], posicion: [{
1197
+ type: Input
1198
+ }], ancho: [{
1199
+ type: Input
1200
+ }], disabled: [{
1201
+ type: Input
1202
+ }], oscuro: [{
1203
+ type: Input
1204
+ }], ariaLabel: [{
1205
+ type: Input
1206
+ }], seleccion: [{
1207
+ type: Output
1208
+ }], abiertoChange: [{
1209
+ type: Output
1210
+ }] } });
1211
+
1107
1212
  class TdDataTable {
1108
1213
  viewport;
1109
1214
  imagenDialog;
1110
1215
  datos = [];
1111
1216
  columnas = [];
1112
1217
  acciones = [];
1218
+ accionesPresentacion = 'inline';
1113
1219
  botones = [];
1114
1220
  total = 0;
1115
1221
  cargando = false;
@@ -1158,8 +1264,9 @@ class TdDataTable {
1158
1264
  }
1159
1265
  columnasGrid() {
1160
1266
  const columnas = this.columnas.map((columna) => columna.ancho ?? 'minmax(10rem, 1fr)');
1161
- if (this.acciones.length)
1162
- columnas.push('minmax(9rem, auto)');
1267
+ if (this.acciones.length) {
1268
+ columnas.push(this.accionesPresentacion === 'menu' ? 'minmax(5rem, auto)' : 'minmax(9rem, auto)');
1269
+ }
1163
1270
  return columnas.join(' ');
1164
1271
  }
1165
1272
  buscar() {
@@ -1234,6 +1341,23 @@ class TdDataTable {
1234
1341
  return accion.tono(fila);
1235
1342
  return accion.tono ?? 'neutro';
1236
1343
  }
1344
+ usarMenuAcciones(fila) {
1345
+ if (this.accionesPresentacion === 'menu')
1346
+ return true;
1347
+ if (this.accionesPresentacion === 'inline')
1348
+ return false;
1349
+ return this.accionesVisibles(fila).length > 3;
1350
+ }
1351
+ accionesMenu(fila) {
1352
+ return this.accionesVisibles(fila).map((accion) => ({
1353
+ id: accion.id,
1354
+ etiqueta: accion.etiqueta,
1355
+ icono: this.iconoAccion(accion, fila),
1356
+ tono: this.tonoAccion(accion, fila),
1357
+ deshabilitado: accion.deshabilitada?.(fila) ?? false,
1358
+ data: accion,
1359
+ }));
1360
+ }
1237
1361
  botonesVisibles() {
1238
1362
  return this.botones.filter((boton) => boton.visible ?? true);
1239
1363
  }
@@ -1245,6 +1369,11 @@ class TdDataTable {
1245
1369
  return;
1246
1370
  this.accion.emit({ accion, fila, indice });
1247
1371
  }
1372
+ ejecutarAccionMenu(evento, fila, indice) {
1373
+ if (!evento.data)
1374
+ return;
1375
+ this.ejecutarAccion(evento.data, fila, indice);
1376
+ }
1248
1377
  abrirImagen(columna, fila, indice) {
1249
1378
  const src = this.imagenSrc(columna, fila, indice);
1250
1379
  if (!src || columna.imagen?.clickeable === false)
@@ -1397,11 +1526,11 @@ class TdDataTable {
1397
1526
  }
1398
1527
  }
1399
1528
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: TdDataTable, deps: [], target: i0.ɵɵFactoryTarget.Component });
1400
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.4", type: TdDataTable, isStandalone: true, selector: "td-data-table", inputs: { datos: "datos", columnas: "columnas", acciones: "acciones", botones: "botones", total: "total", cargando: "cargando", puedeCargarMas: "puedeCargarMas", virtualizar: "virtualizar", virtualizarDesde: "virtualizarDesde", itemSize: "itemSize", filasAntesDeCargar: "filasAntesDeCargar", altura: "altura", campoId: "campoId", oscuro: "oscuro", mostrarBusqueda: "mostrarBusqueda", placeholderBusqueda: "placeholderBusqueda", textoVacio: "textoVacio", descripcionVacio: "descripcionVacio", debounceBusqueda: "debounceBusqueda" }, outputs: { busquedaChange: "busquedaChange", accion: "accion", imagenClick: "imagenClick", botonClick: "botonClick", cargarMas: "cargarMas" }, viewQueries: [{ propertyName: "viewport", first: true, predicate: CdkVirtualScrollViewport, descendants: true }, { propertyName: "imagenDialog", first: true, predicate: ["imagenDialog"], descendants: true }], usesOnChanges: true, ngImport: i0, template: "<section class=\"td-tabla\" [class.td-tabla--oscura]=\"oscuro\">\n <div class=\"td-tabla__toolbar\">\n <div class=\"td-tabla__filtros\">\n @if (mostrarBusqueda) {\n <label class=\"td-tabla__busqueda\">\n <td-icon nombre=\"search\" />\n <input\n type=\"search\"\n [(ngModel)]=\"busqueda\"\n [placeholder]=\"placeholderBusqueda\"\n (input)=\"buscar()\"\n />\n @if (busqueda) {\n <button type=\"button\" title=\"Limpiar b\u00FAsqueda\" (click)=\"limpiarBusqueda()\">\n <td-icon nombre=\"close\" tamano=\"1rem\" />\n </button>\n }\n </label>\n }\n <ng-content select=\"[tdDataTableFilters]\" />\n </div>\n </div>\n\n <div class=\"td-tabla__superficie\">\n <div class=\"td-tabla__resumen\">\n <span><strong>{{ datos.length }}</strong> de {{ total || datos.length }} registros</span>\n <div class=\"td-tabla__resumen-acciones\">\n <ng-content select=\"[tdDataTableActions]\" />\n @for (boton of botonesVisibles(); track boton.id) {\n <button\n type=\"button\"\n [class]=\"'td-tabla__boton td-tabla__boton--' + (boton.tono || 'neutro')\"\n [disabled]=\"boton.deshabilitado\"\n (click)=\"botonClick.emit(boton)\"\n >\n <td-icon [nombre]=\"boton.icono\" />\n <span>{{ boton.etiqueta }}</span>\n </button>\n }\n </div>\n </div>\n\n @if (datos.length) {\n <div class=\"td-tabla__scroll-x\">\n <div class=\"td-tabla__contenido\" [style.--td-tabla-columnas]=\"columnasGrid()\">\n <div class=\"td-tabla__encabezado\" role=\"row\">\n @for (columna of columnas; track columna.clave) {\n <div\n role=\"columnheader\"\n [class]=\"'td-tabla__alinear--' + (columna.alineacion || 'inicio')\"\n >\n {{ columna.encabezado }}\n </div>\n }\n @if (acciones.length) {\n <div role=\"columnheader\" class=\"td-tabla__alinear--centro\">Acciones</div>\n }\n </div>\n\n @if (usaVirtualizacion()) {\n <cdk-virtual-scroll-viewport\n class=\"td-tabla__viewport\"\n [itemSize]=\"itemSize\"\n [style.height]=\"altura\"\n (scroll)=\"alDesplazarViewport()\"\n (wheel)=\"marcarScrollUsuario()\"\n (touchmove)=\"marcarScrollUsuario()\"\n (keydown.arrowdown)=\"marcarScrollUsuario()\"\n (keydown.pagedown)=\"marcarScrollUsuario()\"\n (keydown.end)=\"marcarScrollUsuario()\"\n >\n <ng-container\n *cdkVirtualFor=\"let fila of datos; let indice = index; trackBy: trackFila\"\n >\n <ng-container\n [ngTemplateOutlet]=\"filaTemplate\"\n [ngTemplateOutletContext]=\"{ $implicit: fila, indice: indice }\"\n />\n </ng-container>\n </cdk-virtual-scroll-viewport>\n } @else {\n <div\n class=\"td-tabla__viewport td-tabla__viewport--normal\"\n [style.max-height]=\"altura\"\n (scroll)=\"alDesplazarLista($event)\"\n (wheel)=\"marcarScrollUsuario()\"\n (touchmove)=\"marcarScrollUsuario()\"\n (keydown.arrowdown)=\"marcarScrollUsuario()\"\n (keydown.pagedown)=\"marcarScrollUsuario()\"\n (keydown.end)=\"marcarScrollUsuario()\"\n >\n @for (fila of datos; track trackFila($index, fila); let indice = $index) {\n <ng-container\n [ngTemplateOutlet]=\"filaTemplate\"\n [ngTemplateOutletContext]=\"{ $implicit: fila, indice: indice }\"\n />\n }\n </div>\n }\n </div>\n </div>\n\n <ng-template #filaTemplate let-fila let-indice=\"indice\">\n <div\n class=\"td-tabla__fila\"\n role=\"row\"\n [style.height.px]=\"itemSize\"\n >\n @for (columna of columnas; track columna.clave) {\n <div\n role=\"cell\"\n [class]=\"'td-tabla__celda td-tabla__alinear--' + (columna.alineacion || 'inicio')\"\n >\n @if (columna.tipo === 'imagen') {\n @if (imagenSrc(columna, fila, indice); as src) {\n <button\n type=\"button\"\n [class]=\"'td-tabla__imagen td-tabla__imagen--' + imagenForma(columna)\"\n [title]=\"imagenAlt(columna, fila, indice)\"\n (click)=\"abrirImagen(columna, fila, indice)\"\n >\n <img [src]=\"src\" [alt]=\"imagenAlt(columna, fila, indice)\" loading=\"lazy\" />\n </button>\n } @else {\n <span\n [class]=\"'td-tabla__imagen td-tabla__imagen--placeholder td-tabla__imagen--' + imagenForma(columna)\"\n >\n <td-icon [nombre]=\"columna.imagen?.placeholder || 'image'\" />\n </span>\n }\n } @else if (\n columna.tipo === 'estado' ||\n columna.tipo === 'booleano' ||\n columna.tipo === 'chip'\n ) {\n <span [class]=\"'td-tabla__chip td-tabla__chip--' + tonoCelda(columna, fila)\">\n {{ textoCelda(columna, fila, indice) }}\n </span>\n } @else {\n <span\n [class.td-tabla__numero]=\"\n columna.tipo === 'numero' ||\n columna.tipo === 'decimal' ||\n columna.tipo === 'moneda' ||\n columna.tipo === 'porcentaje'\n \"\n >\n {{ textoCelda(columna, fila, indice) }}\n </span>\n }\n </div>\n }\n\n @if (acciones.length) {\n <div class=\"td-tabla__acciones-fila\" role=\"cell\">\n @for (accionFila of accionesVisibles(fila); track accionFila.id) {\n <button\n type=\"button\"\n [class]=\"'td-tabla__accion td-tabla__accion--' + tonoAccion(accionFila, fila)\"\n [title]=\"accionFila.etiqueta\"\n [disabled]=\"accionFila.deshabilitada?.(fila) ?? false\"\n (click)=\"ejecutarAccion(accionFila, fila, indice)\"\n >\n <td-icon [nombre]=\"iconoAccion(accionFila, fila)\" />\n <span class=\"td-tabla__sr-only\">{{ accionFila.etiqueta }}</span>\n </button>\n }\n </div>\n }\n </div>\n </ng-template>\n\n @if (cargando) {\n <div class=\"td-tabla__cargando\" role=\"status\" aria-live=\"polite\">\n <i aria-hidden=\"true\"></i>\n <span>Cargando m\u00E1s registros...</span>\n </div>\n }\n } @else if (!cargando) {\n <div class=\"td-tabla__vacio\">\n <span><td-icon nombre=\"inbox\" tamano=\"2.4rem\" /></span>\n <h3>{{ textoVacio }}</h3>\n <p>{{ descripcionVacio }}</p>\n </div>\n }\n\n @if (cargando && !datos.length) {\n <div class=\"td-tabla__skeleton\">\n @for (item of [1, 2, 3, 4, 5]; track item) {\n <span></span>\n }\n </div>\n }\n </div>\n</section>\n\n@if (imagenActiva; as imagen) {\n <dialog\n #imagenDialog\n class=\"td-tabla-imagen\"\n [attr.aria-label]=\"imagen.alt\"\n (click)=\"cerrarImagenSiBackdrop($event)\"\n (cancel)=\"cerrarImagen()\"\n (close)=\"imagenActiva = null\"\n >\n <section class=\"td-tabla-imagen__panel\">\n <header>\n <span>{{ imagen.alt }}</span>\n <button type=\"button\" aria-label=\"Cerrar\" (click)=\"cerrarImagen()\">\n <td-icon nombre=\"close\" />\n </button>\n </header>\n <div>\n <img [src]=\"imagen.src\" [alt]=\"imagen.alt\" />\n </div>\n </section>\n </dialog>\n}\n", styles: [":host{display:block}*{box-sizing:border-box}.td-tabla{--fondo: var(--td-color-surface, #fff);--fondo-suave: var(--td-color-surface-soft, #f8fafc);--borde: var(--td-color-border, #e4e8f0);--texto: var(--td-color-text, #263147);--suave: var(--td-color-text-muted, #748096);--hover: var(--td-color-surface-soft, #f7f8fc);--acento: var(--td-color-primary, #5746d8);color:var(--texto);font-family:var(--td-font-family, Inter, ui-sans-serif, system-ui, sans-serif);position:relative;z-index:0;isolation:isolate;contain:layout paint style;overflow-anchor:none}.td-tabla--oscura{--fondo: var(--td-color-surface, #15151b);--fondo-suave: var(--td-color-surface-soft, #1b1b22);--borde: var(--td-color-border, #2d2d36);--texto: var(--td-color-text, #ededf0);--suave: var(--td-color-text-muted, #9393a0);--hover: var(--td-color-surface-muted, #202028);--acento: var(--td-color-primary, #a89cf7)}.td-tabla__toolbar{display:flex;align-items:flex-start;justify-content:space-between;gap:1rem;padding:.55rem 0 .95rem}.td-tabla__filtros{display:flex;min-width:0;flex:1;flex-wrap:wrap;align-items:flex-start;gap:.8rem .65rem}.td-tabla__busqueda{display:flex;width:min(22rem,100%);min-height:3.15rem;align-items:center;gap:.6rem;border:1px solid var(--borde);border-radius:var(--td-radius-md, .78rem);padding:0 .75rem;color:var(--suave);background:var(--fondo);transition:border-color .14s ease,box-shadow .14s ease}.td-tabla__busqueda:focus-within{border-color:var(--acento);box-shadow:var(--td-focus-ring, 0 0 0 3px color-mix(in srgb, var(--acento) 15%, transparent))}.td-tabla__busqueda input{min-width:0;flex:1;border:0;appearance:none;outline:0;color:var(--texto);background:transparent;font:inherit;font-size:.78rem}.td-tabla__busqueda input::-webkit-search-cancel-button,.td-tabla__busqueda input::-webkit-search-decoration{appearance:none;display:none}.td-tabla__busqueda input::-ms-clear,.td-tabla__busqueda input::-ms-reveal{display:none;width:0;height:0}.td-tabla__busqueda button{display:grid;place-items:center;border:0;padding:.2rem;color:var(--suave);background:transparent;cursor:pointer}.td-tabla__vacio button,.td-tabla__boton{display:inline-flex;height:2.55rem;align-items:center;gap:.45rem;border:0;border-radius:var(--td-radius-md, .7rem);padding:0 1rem;color:var(--td-color-on-primary, #fff);background:linear-gradient(135deg,var(--td-color-primary, #5746d8),var(--td-color-info, #7657df));box-shadow:var(--td-shadow-sm, 0 7px 16px rgba(87, 70, 216, .2));font-size:.75rem;font-weight:750;cursor:pointer}.td-tabla__resumen-acciones{display:flex;align-items:center;gap:.45rem}.td-tabla__boton{height:2.15rem;padding:0 .75rem;box-shadow:none;color:var(--td-color-text-muted, #526077);background:var(--td-color-surface-muted, #edf0f5)}.td-tabla__boton--primario{color:var(--td-color-on-primary, #fff);background:linear-gradient(135deg,var(--td-color-primary, #5746d8),var(--td-color-info, #7657df));box-shadow:var(--td-shadow-sm, 0 7px 16px rgba(87, 70, 216, .2))}.td-tabla__boton--exito{color:var(--td-color-on-primary, #fff);background:var(--td-color-success, #168447)}.td-tabla__boton--advertencia{color:var(--td-color-on-primary, #fff);background:var(--td-color-warning, #b66d05)}.td-tabla__boton--peligro{color:var(--td-color-on-primary, #fff);background:var(--td-color-danger, #d33f3f)}.td-tabla__boton:disabled{opacity:.45;cursor:not-allowed}.td-tabla__superficie{position:relative;z-index:0;overflow:hidden;border:1px solid var(--borde);border-radius:var(--td-radius-xl, 1rem);background:var(--fondo);box-shadow:var(--td-shadow-sm, 0 12px 32px rgba(31, 42, 68, .06))}.td-tabla__resumen{display:flex;min-height:3rem;align-items:center;justify-content:space-between;border-bottom:1px solid var(--borde);padding:.7rem 1rem;color:var(--suave);background:var(--fondo-suave);font-size:.7rem}.td-tabla__resumen strong{color:var(--texto)}.td-tabla__cargando{position:absolute;z-index:4;right:0;bottom:0;left:0;display:flex;min-height:2.75rem;align-items:center;justify-content:center;gap:.55rem;border-top:1px solid var(--borde);color:var(--suave);background:color-mix(in srgb,var(--fondo-suave) 94%,transparent);box-shadow:0 -8px 20px color-mix(in srgb,var(--texto) 8%,transparent);-webkit-backdrop-filter:blur(5px);backdrop-filter:blur(5px);font-size:.7rem;font-weight:650;pointer-events:none}.td-tabla__cargando i{width:.85rem;height:.85rem;border:2px solid var(--borde);border-top-color:var(--acento);border-radius:var(--td-radius-pill, 50%);animation:td-tabla-girar .7s linear infinite}.td-tabla__encabezado,.td-tabla__fila{display:grid;align-items:center;grid-template-columns:var(--td-tabla-columnas)}.td-tabla__scroll-x{width:100%;overflow-x:auto;overflow-y:hidden;scrollbar-gutter:stable;scrollbar-width:thin;scrollbar-color:color-mix(in srgb,var(--suave) 42%,transparent) transparent}.td-tabla__contenido{display:grid;grid-template-columns:var(--td-tabla-columnas);min-width:max-content}.td-tabla__encabezado{position:relative;z-index:2;grid-column:1/-1;min-height:2.75rem;border-bottom:1px solid var(--borde);color:var(--suave);background:var(--fondo-suave);font-size:.62rem;font-weight:800;letter-spacing:.075em;text-transform:uppercase}.td-tabla__encabezado>div,.td-tabla__celda{padding:.6rem 1rem}.td-tabla__viewport{grid-column:1/-1;width:100%;min-width:0;min-height:12rem;overflow-x:hidden;overflow-anchor:none;scrollbar-gutter:stable;scrollbar-width:thin;scrollbar-color:color-mix(in srgb,var(--suave) 45%,transparent) transparent}.td-tabla__viewport--normal{overflow-x:hidden;overflow-y:auto}.td-tabla__fila{grid-column:1/-1;border-bottom:1px solid var(--borde);transition:background .12s ease}.td-tabla__fila:hover{background:var(--hover)}.td-tabla__celda{overflow:hidden;color:var(--texto);font-size:.75rem;text-overflow:ellipsis;white-space:nowrap}.td-tabla__numero{font-variant-numeric:tabular-nums}.td-tabla__alinear--inicio{text-align:left}.td-tabla__alinear--centro{text-align:center;justify-content:center}.td-tabla__alinear--fin{text-align:right;justify-content:flex-end}.td-tabla__imagen{display:inline-grid;width:2.35rem;height:2.35rem;place-items:center;overflow:hidden;border:1px solid var(--borde);padding:0;color:var(--suave);background:var(--fondo-suave);vertical-align:middle}button.td-tabla__imagen{cursor:zoom-in}button.td-tabla__imagen:hover{border-color:var(--acento);box-shadow:var(--td-focus-ring, 0 0 0 3px color-mix(in srgb, var(--acento) 14%, transparent))}.td-tabla__imagen img{width:100%;height:100%;object-fit:cover}.td-tabla__imagen--cuadrada{border-radius:var(--td-radius-sm, .55rem)}.td-tabla__imagen--redondeada{border-radius:var(--td-radius-md, .85rem)}.td-tabla__imagen--circular{border-radius:var(--td-radius-pill, 999px)}.td-tabla__imagen--placeholder{border-style:dashed}.td-tabla__chip{display:inline-flex;border-radius:var(--td-radius-pill, 999px);padding:.25rem .55rem;color:var(--td-color-text-muted, #526077);background:var(--td-color-surface-muted, #edf0f5);font-size:.65rem;font-weight:750}.td-tabla__chip--primario{color:var(--td-color-primary, #4f46e5);background:var(--td-color-primary-soft, #eeecff)}.td-tabla__chip--exito{color:var(--td-color-success, #13713a);background:var(--td-color-success-soft, #dff7e8)}.td-tabla__chip--advertencia{color:var(--td-color-warning, #9a5a05);background:var(--td-color-warning-soft, #fff0cf)}.td-tabla__chip--peligro{color:var(--td-color-danger, #b53434);background:var(--td-color-danger-soft, #fee5e5)}.td-tabla__acciones-fila{display:flex;align-items:center;justify-content:center;gap:.25rem;padding:0 .7rem}.td-tabla__accion{display:grid;width:2rem;height:2rem;place-items:center;border:0;border-radius:var(--td-radius-sm, .55rem);color:var(--suave);background:transparent;cursor:pointer}.td-tabla__accion:hover{background:var(--hover);color:var(--acento)}.td-tabla__accion--exito{color:var(--td-color-success, #168447)}.td-tabla__accion--peligro{color:var(--td-color-danger, #dc3e3e)}.td-tabla__accion--advertencia{color:var(--td-color-warning, #b66d05)}.td-tabla__accion:disabled{opacity:.35;cursor:not-allowed}.td-tabla__vacio{display:grid;min-height:21rem;place-items:center;align-content:center;padding:2rem;text-align:center}.td-tabla__vacio>span{display:grid;width:4.5rem;height:4.5rem;place-items:center;border-radius:var(--td-radius-xl, 1.2rem);color:var(--acento);background:color-mix(in srgb,var(--acento) 10%,transparent)}.td-tabla__vacio h3{margin:1rem 0 .3rem;font-size:1rem}.td-tabla__vacio p{margin:0 0 1.25rem;color:var(--suave);font-size:.75rem}.td-tabla__skeleton{padding:.5rem 1rem}.td-tabla__skeleton span{display:block;height:3.5rem;border-bottom:1px solid var(--borde);background:linear-gradient(90deg,transparent,var(--hover),transparent);background-size:200% 100%;animation:td-tabla-cargar 1.2s linear infinite}.td-tabla__sr-only{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap}@keyframes td-tabla-girar{to{transform:rotate(360deg)}}@keyframes td-tabla-cargar{to{background-position:-200% 0}}.td-tabla-imagen{width:min(680px,100vw - 2rem);max-width:none;max-height:min(76dvh,620px);border:0;padding:0;overflow:visible;color:inherit;background:transparent}.td-tabla-imagen::backdrop{background:#0a101e80;-webkit-backdrop-filter:blur(7px);backdrop-filter:blur(7px)}.td-tabla-imagen__panel{display:grid;grid-template-rows:auto minmax(0,1fr);width:100%;max-height:min(76dvh,620px);overflow:hidden;border:1px solid var(--td-color-border, #e4e8f0);border-radius:var(--td-radius-xl, 1.15rem);background:var(--td-color-surface, #fff);box-shadow:var(--td-shadow-xl, 0 24px 72px rgba(15, 23, 42, .28))}.td-tabla-imagen__panel header{display:flex;align-items:center;justify-content:space-between;gap:1rem;border-bottom:1px solid var(--td-color-border, #e4e8f0);padding:.75rem .9rem;background:var(--td-color-surface, #fff)}.td-tabla-imagen__panel span{overflow:hidden;color:var(--td-color-text, #263147);font-size:.78rem;font-weight:800;text-overflow:ellipsis;white-space:nowrap}.td-tabla-imagen__panel button{display:grid;width:2.1rem;height:2.1rem;place-items:center;border:0;border-radius:var(--td-radius-sm, .55rem);color:var(--td-color-text-muted, #748096);background:var(--td-color-surface-soft, #f8fafc);cursor:pointer}.td-tabla-imagen__panel>div{display:grid;min-height:18rem;overflow:hidden;padding:1rem;background:var(--td-color-surface-soft, #f8fafc)}.td-tabla-imagen__panel img{display:block;width:auto;max-width:100%;max-height:min(58dvh,500px);margin:auto;border-radius:var(--td-radius-lg, 1rem);object-fit:contain;box-shadow:var(--td-shadow-md, 0 16px 42px rgba(15, 23, 42, .16))}@media(max-width:640px){.td-tabla__toolbar{align-items:stretch;flex-direction:column}.td-tabla__busqueda{width:100%}.td-tabla__resumen{align-items:flex-start;flex-direction:column}.td-tabla__resumen-acciones{width:100%;flex-wrap:wrap}.td-tabla-imagen{padding:.75rem}.td-tabla-imagen{width:calc(100vw - 1.5rem)}.td-tabla-imagen__panel{width:100%;max-height:calc(100dvh - 1.5rem);height:auto;border-radius:var(--td-radius-xl, 1rem)}.td-tabla-imagen__panel>div{min-height:14rem;padding:.75rem}.td-tabla-imagen__panel img{max-height:calc(100dvh - 7rem)}}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.DefaultValueAccessor, selector: "input:not([type=checkbox]):not([ngNoCva])[formControlName],textarea:not([ngNoCva])[formControlName],input:not([type=checkbox]):not([ngNoCva])[formControl],textarea:not([ngNoCva])[formControl],input:not([type=checkbox]):not([ngNoCva])[ngModel],textarea:not([ngNoCva])[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "ngmodule", type: ScrollingModule }, { kind: "directive", type: i2.CdkFixedSizeVirtualScroll, selector: "cdk-virtual-scroll-viewport[itemSize]", inputs: ["itemSize", "minBufferPx", "maxBufferPx"] }, { kind: "directive", type: i2.CdkVirtualForOf, selector: "[cdkVirtualFor][cdkVirtualForOf]", inputs: ["cdkVirtualForOf", "cdkVirtualForTrackBy", "cdkVirtualForTemplate", "cdkVirtualForTemplateCacheSize"] }, { kind: "component", type: i2.CdkVirtualScrollViewport, selector: "cdk-virtual-scroll-viewport", inputs: ["orientation", "appendOnly"], outputs: ["scrolledIndexChange"] }, { kind: "component", type: TdIcon, selector: "td-icon", inputs: ["nombre", "titulo", "tamano"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1529
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.4", type: TdDataTable, isStandalone: true, selector: "td-data-table", inputs: { datos: "datos", columnas: "columnas", acciones: "acciones", accionesPresentacion: "accionesPresentacion", botones: "botones", total: "total", cargando: "cargando", puedeCargarMas: "puedeCargarMas", virtualizar: "virtualizar", virtualizarDesde: "virtualizarDesde", itemSize: "itemSize", filasAntesDeCargar: "filasAntesDeCargar", altura: "altura", campoId: "campoId", oscuro: "oscuro", mostrarBusqueda: "mostrarBusqueda", placeholderBusqueda: "placeholderBusqueda", textoVacio: "textoVacio", descripcionVacio: "descripcionVacio", debounceBusqueda: "debounceBusqueda" }, outputs: { busquedaChange: "busquedaChange", accion: "accion", imagenClick: "imagenClick", botonClick: "botonClick", cargarMas: "cargarMas" }, viewQueries: [{ propertyName: "viewport", first: true, predicate: CdkVirtualScrollViewport, descendants: true }, { propertyName: "imagenDialog", first: true, predicate: ["imagenDialog"], descendants: true }], usesOnChanges: true, ngImport: i0, template: "<section class=\"td-tabla\" [class.td-tabla--oscura]=\"oscuro\">\n <div class=\"td-tabla__toolbar\">\n <div class=\"td-tabla__filtros\">\n @if (mostrarBusqueda) {\n <label class=\"td-tabla__busqueda\">\n <td-icon nombre=\"search\" />\n <input\n type=\"search\"\n [(ngModel)]=\"busqueda\"\n [placeholder]=\"placeholderBusqueda\"\n (input)=\"buscar()\"\n />\n @if (busqueda) {\n <button type=\"button\" title=\"Limpiar b\u00FAsqueda\" (click)=\"limpiarBusqueda()\">\n <td-icon nombre=\"close\" tamano=\"1rem\" />\n </button>\n }\n </label>\n }\n <ng-content select=\"[tdDataTableFilters]\" />\n </div>\n </div>\n\n <div class=\"td-tabla__superficie\">\n <div class=\"td-tabla__resumen\">\n <span><strong>{{ datos.length }}</strong> de {{ total || datos.length }} registros</span>\n <div class=\"td-tabla__resumen-acciones\">\n <ng-content select=\"[tdDataTableActions]\" />\n @for (boton of botonesVisibles(); track boton.id) {\n <button\n type=\"button\"\n [class]=\"'td-tabla__boton td-tabla__boton--' + (boton.tono || 'neutro')\"\n [disabled]=\"boton.deshabilitado\"\n (click)=\"botonClick.emit(boton)\"\n >\n <td-icon [nombre]=\"boton.icono\" />\n <span>{{ boton.etiqueta }}</span>\n </button>\n }\n </div>\n </div>\n\n @if (datos.length) {\n <div class=\"td-tabla__scroll-x\">\n <div class=\"td-tabla__contenido\" [style.--td-tabla-columnas]=\"columnasGrid()\">\n <div class=\"td-tabla__encabezado\" role=\"row\">\n @for (columna of columnas; track columna.clave) {\n <div\n role=\"columnheader\"\n [class]=\"'td-tabla__alinear--' + (columna.alineacion || 'inicio')\"\n >\n {{ columna.encabezado }}\n </div>\n }\n @if (acciones.length) {\n <div role=\"columnheader\" class=\"td-tabla__alinear--centro\">Acciones</div>\n }\n </div>\n\n @if (usaVirtualizacion()) {\n <cdk-virtual-scroll-viewport\n class=\"td-tabla__viewport\"\n [itemSize]=\"itemSize\"\n [style.height]=\"altura\"\n (scroll)=\"alDesplazarViewport()\"\n (wheel)=\"marcarScrollUsuario()\"\n (touchmove)=\"marcarScrollUsuario()\"\n (keydown.arrowdown)=\"marcarScrollUsuario()\"\n (keydown.pagedown)=\"marcarScrollUsuario()\"\n (keydown.end)=\"marcarScrollUsuario()\"\n >\n <ng-container\n *cdkVirtualFor=\"let fila of datos; let indice = index; trackBy: trackFila\"\n >\n <ng-container\n [ngTemplateOutlet]=\"filaTemplate\"\n [ngTemplateOutletContext]=\"{ $implicit: fila, indice: indice }\"\n />\n </ng-container>\n </cdk-virtual-scroll-viewport>\n } @else {\n <div\n class=\"td-tabla__viewport td-tabla__viewport--normal\"\n [style.max-height]=\"altura\"\n (scroll)=\"alDesplazarLista($event)\"\n (wheel)=\"marcarScrollUsuario()\"\n (touchmove)=\"marcarScrollUsuario()\"\n (keydown.arrowdown)=\"marcarScrollUsuario()\"\n (keydown.pagedown)=\"marcarScrollUsuario()\"\n (keydown.end)=\"marcarScrollUsuario()\"\n >\n @for (fila of datos; track trackFila($index, fila); let indice = $index) {\n <ng-container\n [ngTemplateOutlet]=\"filaTemplate\"\n [ngTemplateOutletContext]=\"{ $implicit: fila, indice: indice }\"\n />\n }\n </div>\n }\n </div>\n </div>\n\n <ng-template #filaTemplate let-fila let-indice=\"indice\">\n <div\n class=\"td-tabla__fila\"\n role=\"row\"\n [style.height.px]=\"itemSize\"\n >\n @for (columna of columnas; track columna.clave) {\n <div\n role=\"cell\"\n [class]=\"'td-tabla__celda td-tabla__alinear--' + (columna.alineacion || 'inicio')\"\n >\n @if (columna.tipo === 'imagen') {\n @if (imagenSrc(columna, fila, indice); as src) {\n <button\n type=\"button\"\n [class]=\"'td-tabla__imagen td-tabla__imagen--' + imagenForma(columna)\"\n [title]=\"imagenAlt(columna, fila, indice)\"\n (click)=\"abrirImagen(columna, fila, indice)\"\n >\n <img [src]=\"src\" [alt]=\"imagenAlt(columna, fila, indice)\" loading=\"lazy\" />\n </button>\n } @else {\n <span\n [class]=\"'td-tabla__imagen td-tabla__imagen--placeholder td-tabla__imagen--' + imagenForma(columna)\"\n >\n <td-icon [nombre]=\"columna.imagen?.placeholder || 'image'\" />\n </span>\n }\n } @else if (\n columna.tipo === 'estado' ||\n columna.tipo === 'booleano' ||\n columna.tipo === 'chip'\n ) {\n <span [class]=\"'td-tabla__chip td-tabla__chip--' + tonoCelda(columna, fila)\">\n {{ textoCelda(columna, fila, indice) }}\n </span>\n } @else {\n <span\n [class.td-tabla__numero]=\"\n columna.tipo === 'numero' ||\n columna.tipo === 'decimal' ||\n columna.tipo === 'moneda' ||\n columna.tipo === 'porcentaje'\n \"\n >\n {{ textoCelda(columna, fila, indice) }}\n </span>\n }\n </div>\n }\n\n @if (acciones.length) {\n <div class=\"td-tabla__acciones-fila\" role=\"cell\">\n @if (usarMenuAcciones(fila)) {\n <td-menu\n ariaLabel=\"Acciones de fila\"\n icono=\"more_vertical\"\n ancho=\"15rem\"\n [oscuro]=\"oscuro\"\n [items]=\"accionesMenu(fila)\"\n (seleccion)=\"ejecutarAccionMenu($event, fila, indice)\"\n />\n } @else {\n @for (accionFila of accionesVisibles(fila); track accionFila.id) {\n <button\n type=\"button\"\n [class]=\"'td-tabla__accion td-tabla__accion--' + tonoAccion(accionFila, fila)\"\n [title]=\"accionFila.etiqueta\"\n [disabled]=\"accionFila.deshabilitada?.(fila) ?? false\"\n (click)=\"ejecutarAccion(accionFila, fila, indice)\"\n >\n <td-icon [nombre]=\"iconoAccion(accionFila, fila)\" />\n <span class=\"td-tabla__sr-only\">{{ accionFila.etiqueta }}</span>\n </button>\n }\n }\n </div>\n }\n </div>\n </ng-template>\n\n @if (cargando) {\n <div class=\"td-tabla__cargando\" role=\"status\" aria-live=\"polite\">\n <i aria-hidden=\"true\"></i>\n <span>Cargando m\u00E1s registros...</span>\n </div>\n }\n } @else if (!cargando) {\n <div class=\"td-tabla__vacio\">\n <span><td-icon nombre=\"inbox\" tamano=\"2.4rem\" /></span>\n <h3>{{ textoVacio }}</h3>\n <p>{{ descripcionVacio }}</p>\n </div>\n }\n\n @if (cargando && !datos.length) {\n <div class=\"td-tabla__skeleton\">\n @for (item of [1, 2, 3, 4, 5]; track item) {\n <span></span>\n }\n </div>\n }\n </div>\n</section>\n\n@if (imagenActiva; as imagen) {\n <dialog\n #imagenDialog\n class=\"td-tabla-imagen\"\n [attr.aria-label]=\"imagen.alt\"\n (click)=\"cerrarImagenSiBackdrop($event)\"\n (cancel)=\"cerrarImagen()\"\n (close)=\"imagenActiva = null\"\n >\n <section class=\"td-tabla-imagen__panel\">\n <header>\n <span>{{ imagen.alt }}</span>\n <button type=\"button\" aria-label=\"Cerrar\" (click)=\"cerrarImagen()\">\n <td-icon nombre=\"close\" />\n </button>\n </header>\n <div>\n <img [src]=\"imagen.src\" [alt]=\"imagen.alt\" />\n </div>\n </section>\n </dialog>\n}\n", styles: [":host{display:block}*{box-sizing:border-box}.td-tabla{--fondo: var(--td-color-surface, #fff);--fondo-suave: var(--td-color-surface-soft, #f8fafc);--borde: var(--td-color-border, #e4e8f0);--texto: var(--td-color-text, #263147);--suave: var(--td-color-text-muted, #748096);--hover: var(--td-color-surface-soft, #f7f8fc);--acento: var(--td-color-primary, #5746d8);color:var(--texto);font-family:var(--td-font-family, Inter, ui-sans-serif, system-ui, sans-serif);position:relative;z-index:0;isolation:isolate;contain:layout paint style;overflow-anchor:none}.td-tabla--oscura{--fondo: var(--td-color-surface, #15151b);--fondo-suave: var(--td-color-surface-soft, #1b1b22);--borde: var(--td-color-border, #2d2d36);--texto: var(--td-color-text, #ededf0);--suave: var(--td-color-text-muted, #9393a0);--hover: var(--td-color-surface-muted, #202028);--acento: var(--td-color-primary, #a89cf7)}.td-tabla__toolbar{display:flex;align-items:flex-start;justify-content:space-between;gap:1rem;padding:.55rem 0 .95rem}.td-tabla__filtros{display:flex;min-width:0;flex:1;flex-wrap:wrap;align-items:flex-start;gap:.8rem .65rem}.td-tabla__busqueda{display:flex;width:min(22rem,100%);min-height:3.15rem;align-items:center;gap:.6rem;border:1px solid var(--borde);border-radius:var(--td-radius-md, .78rem);padding:0 .75rem;color:var(--suave);background:var(--fondo);transition:border-color .14s ease,box-shadow .14s ease}.td-tabla__busqueda:focus-within{border-color:var(--acento);box-shadow:var(--td-focus-ring, 0 0 0 3px color-mix(in srgb, var(--acento) 15%, transparent))}.td-tabla__busqueda input{min-width:0;flex:1;border:0;appearance:none;outline:0;color:var(--texto);background:transparent;font:inherit;font-size:.78rem}.td-tabla__busqueda input::-webkit-search-cancel-button,.td-tabla__busqueda input::-webkit-search-decoration{appearance:none;display:none}.td-tabla__busqueda input::-ms-clear,.td-tabla__busqueda input::-ms-reveal{display:none;width:0;height:0}.td-tabla__busqueda button{display:grid;place-items:center;border:0;padding:.2rem;color:var(--suave);background:transparent;cursor:pointer}.td-tabla__vacio button,.td-tabla__boton{display:inline-flex;height:2.55rem;align-items:center;gap:.45rem;border:0;border-radius:var(--td-radius-md, .7rem);padding:0 1rem;color:var(--td-color-on-primary, #fff);background:linear-gradient(135deg,var(--td-color-primary, #5746d8),var(--td-color-info, #7657df));box-shadow:var(--td-shadow-sm, 0 7px 16px rgba(87, 70, 216, .2));font-size:.75rem;font-weight:750;cursor:pointer}.td-tabla__resumen-acciones{display:flex;align-items:center;gap:.45rem}.td-tabla__boton{height:2.15rem;padding:0 .75rem;box-shadow:none;color:var(--td-color-text-muted, #526077);background:var(--td-color-surface-muted, #edf0f5)}.td-tabla__boton--primario{color:var(--td-color-on-primary, #fff);background:linear-gradient(135deg,var(--td-color-primary, #5746d8),var(--td-color-info, #7657df));box-shadow:var(--td-shadow-sm, 0 7px 16px rgba(87, 70, 216, .2))}.td-tabla__boton--exito{color:var(--td-color-on-primary, #fff);background:var(--td-color-success, #168447)}.td-tabla__boton--advertencia{color:var(--td-color-on-primary, #fff);background:var(--td-color-warning, #b66d05)}.td-tabla__boton--peligro{color:var(--td-color-on-primary, #fff);background:var(--td-color-danger, #d33f3f)}.td-tabla__boton:disabled{opacity:.45;cursor:not-allowed}.td-tabla__superficie{position:relative;z-index:0;overflow:hidden;border:1px solid var(--borde);border-radius:var(--td-radius-xl, 1rem);background:var(--fondo);box-shadow:var(--td-shadow-sm, 0 12px 32px rgba(31, 42, 68, .06))}.td-tabla__resumen{display:flex;min-height:3rem;align-items:center;justify-content:space-between;border-bottom:1px solid var(--borde);padding:.7rem 1rem;color:var(--suave);background:var(--fondo-suave);font-size:.7rem}.td-tabla__resumen strong{color:var(--texto)}.td-tabla__cargando{position:absolute;z-index:4;right:0;bottom:0;left:0;display:flex;min-height:2.75rem;align-items:center;justify-content:center;gap:.55rem;border-top:1px solid var(--borde);color:var(--suave);background:color-mix(in srgb,var(--fondo-suave) 94%,transparent);box-shadow:0 -8px 20px color-mix(in srgb,var(--texto) 8%,transparent);-webkit-backdrop-filter:blur(5px);backdrop-filter:blur(5px);font-size:.7rem;font-weight:650;pointer-events:none}.td-tabla__cargando i{width:.85rem;height:.85rem;border:2px solid var(--borde);border-top-color:var(--acento);border-radius:var(--td-radius-pill, 50%);animation:td-tabla-girar .7s linear infinite}.td-tabla__encabezado,.td-tabla__fila{display:grid;align-items:center;grid-template-columns:var(--td-tabla-columnas)}.td-tabla__scroll-x{width:100%;overflow-x:auto;overflow-y:hidden;scrollbar-gutter:stable;scrollbar-width:thin;scrollbar-color:color-mix(in srgb,var(--suave) 42%,transparent) transparent}.td-tabla__contenido{display:grid;grid-template-columns:var(--td-tabla-columnas);min-width:max-content}.td-tabla__encabezado{position:relative;z-index:2;grid-column:1/-1;min-height:2.75rem;border-bottom:1px solid var(--borde);color:var(--suave);background:var(--fondo-suave);font-size:.62rem;font-weight:800;letter-spacing:.075em;text-transform:uppercase}.td-tabla__encabezado>div,.td-tabla__celda{padding:.6rem 1rem}.td-tabla__viewport{grid-column:1/-1;width:100%;min-width:0;min-height:12rem;overflow-x:hidden;overflow-anchor:none;scrollbar-gutter:stable;scrollbar-width:thin;scrollbar-color:color-mix(in srgb,var(--suave) 45%,transparent) transparent}.td-tabla__viewport--normal{overflow-x:hidden;overflow-y:auto}.td-tabla__fila{grid-column:1/-1;border-bottom:1px solid var(--borde);transition:background .12s ease}.td-tabla__fila:hover{background:var(--hover)}.td-tabla__celda{overflow:hidden;color:var(--texto);font-size:.75rem;text-overflow:ellipsis;white-space:nowrap}.td-tabla__numero{font-variant-numeric:tabular-nums}.td-tabla__alinear--inicio{text-align:left}.td-tabla__alinear--centro{text-align:center;justify-content:center}.td-tabla__alinear--fin{text-align:right;justify-content:flex-end}.td-tabla__imagen{display:inline-grid;width:2.35rem;height:2.35rem;place-items:center;overflow:hidden;border:1px solid var(--borde);padding:0;color:var(--suave);background:var(--fondo-suave);vertical-align:middle}button.td-tabla__imagen{cursor:zoom-in}button.td-tabla__imagen:hover{border-color:var(--acento);box-shadow:var(--td-focus-ring, 0 0 0 3px color-mix(in srgb, var(--acento) 14%, transparent))}.td-tabla__imagen img{width:100%;height:100%;object-fit:cover}.td-tabla__imagen--cuadrada{border-radius:var(--td-radius-sm, .55rem)}.td-tabla__imagen--redondeada{border-radius:var(--td-radius-md, .85rem)}.td-tabla__imagen--circular{border-radius:var(--td-radius-pill, 999px)}.td-tabla__imagen--placeholder{border-style:dashed}.td-tabla__chip{display:inline-flex;border-radius:var(--td-radius-pill, 999px);padding:.25rem .55rem;color:var(--td-color-text-muted, #526077);background:var(--td-color-surface-muted, #edf0f5);font-size:.65rem;font-weight:750}.td-tabla__chip--primario{color:var(--td-color-primary, #4f46e5);background:var(--td-color-primary-soft, #eeecff)}.td-tabla__chip--exito{color:var(--td-color-success, #13713a);background:var(--td-color-success-soft, #dff7e8)}.td-tabla__chip--advertencia{color:var(--td-color-warning, #9a5a05);background:var(--td-color-warning-soft, #fff0cf)}.td-tabla__chip--peligro{color:var(--td-color-danger, #b53434);background:var(--td-color-danger-soft, #fee5e5)}.td-tabla__acciones-fila{display:flex;align-items:center;justify-content:center;gap:.25rem;padding:0 .7rem}.td-tabla__acciones-fila td-menu{line-height:1}.td-tabla__accion{display:grid;width:2rem;height:2rem;place-items:center;border:0;border-radius:var(--td-radius-sm, .55rem);color:var(--suave);background:transparent;cursor:pointer}.td-tabla__accion:hover{background:var(--hover);color:var(--acento)}.td-tabla__accion--exito{color:var(--td-color-success, #168447)}.td-tabla__accion--peligro{color:var(--td-color-danger, #dc3e3e)}.td-tabla__accion--advertencia{color:var(--td-color-warning, #b66d05)}.td-tabla__accion:disabled{opacity:.35;cursor:not-allowed}.td-tabla__vacio{display:grid;min-height:21rem;place-items:center;align-content:center;padding:2rem;text-align:center}.td-tabla__vacio>span{display:grid;width:4.5rem;height:4.5rem;place-items:center;border-radius:var(--td-radius-xl, 1.2rem);color:var(--acento);background:color-mix(in srgb,var(--acento) 10%,transparent)}.td-tabla__vacio h3{margin:1rem 0 .3rem;font-size:1rem}.td-tabla__vacio p{margin:0 0 1.25rem;color:var(--suave);font-size:.75rem}.td-tabla__skeleton{padding:.5rem 1rem}.td-tabla__skeleton span{display:block;height:3.5rem;border-bottom:1px solid var(--borde);background:linear-gradient(90deg,transparent,var(--hover),transparent);background-size:200% 100%;animation:td-tabla-cargar 1.2s linear infinite}.td-tabla__sr-only{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap}@keyframes td-tabla-girar{to{transform:rotate(360deg)}}@keyframes td-tabla-cargar{to{background-position:-200% 0}}.td-tabla-imagen{width:min(680px,100vw - 2rem);max-width:none;max-height:min(76dvh,620px);border:0;padding:0;overflow:visible;color:inherit;background:transparent}.td-tabla-imagen::backdrop{background:#0a101e80;-webkit-backdrop-filter:blur(7px);backdrop-filter:blur(7px)}.td-tabla-imagen__panel{display:grid;grid-template-rows:auto minmax(0,1fr);width:100%;max-height:min(76dvh,620px);overflow:hidden;border:1px solid var(--td-color-border, #e4e8f0);border-radius:var(--td-radius-xl, 1.15rem);background:var(--td-color-surface, #fff);box-shadow:var(--td-shadow-xl, 0 24px 72px rgba(15, 23, 42, .28))}.td-tabla-imagen__panel header{display:flex;align-items:center;justify-content:space-between;gap:1rem;border-bottom:1px solid var(--td-color-border, #e4e8f0);padding:.75rem .9rem;background:var(--td-color-surface, #fff)}.td-tabla-imagen__panel span{overflow:hidden;color:var(--td-color-text, #263147);font-size:.78rem;font-weight:800;text-overflow:ellipsis;white-space:nowrap}.td-tabla-imagen__panel button{display:grid;width:2.1rem;height:2.1rem;place-items:center;border:0;border-radius:var(--td-radius-sm, .55rem);color:var(--td-color-text-muted, #748096);background:var(--td-color-surface-soft, #f8fafc);cursor:pointer}.td-tabla-imagen__panel>div{display:grid;min-height:18rem;overflow:hidden;padding:1rem;background:var(--td-color-surface-soft, #f8fafc)}.td-tabla-imagen__panel img{display:block;width:auto;max-width:100%;max-height:min(58dvh,500px);margin:auto;border-radius:var(--td-radius-lg, 1rem);object-fit:contain;box-shadow:var(--td-shadow-md, 0 16px 42px rgba(15, 23, 42, .16))}@media(max-width:640px){.td-tabla__toolbar{align-items:stretch;flex-direction:column}.td-tabla__busqueda{width:100%}.td-tabla__resumen{align-items:flex-start;flex-direction:column}.td-tabla__resumen-acciones{width:100%;flex-wrap:wrap}.td-tabla-imagen{padding:.75rem}.td-tabla-imagen{width:calc(100vw - 1.5rem)}.td-tabla-imagen__panel{width:100%;max-height:calc(100dvh - 1.5rem);height:auto;border-radius:var(--td-radius-xl, 1rem)}.td-tabla-imagen__panel>div{min-height:14rem;padding:.75rem}.td-tabla-imagen__panel img{max-height:calc(100dvh - 7rem)}}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.DefaultValueAccessor, selector: "input:not([type=checkbox]):not([ngNoCva])[formControlName],textarea:not([ngNoCva])[formControlName],input:not([type=checkbox]):not([ngNoCva])[formControl],textarea:not([ngNoCva])[formControl],input:not([type=checkbox]):not([ngNoCva])[ngModel],textarea:not([ngNoCva])[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "ngmodule", type: ScrollingModule }, { kind: "directive", type: i2.CdkFixedSizeVirtualScroll, selector: "cdk-virtual-scroll-viewport[itemSize]", inputs: ["itemSize", "minBufferPx", "maxBufferPx"] }, { kind: "directive", type: i2.CdkVirtualForOf, selector: "[cdkVirtualFor][cdkVirtualForOf]", inputs: ["cdkVirtualForOf", "cdkVirtualForTrackBy", "cdkVirtualForTemplate", "cdkVirtualForTemplateCacheSize"] }, { kind: "component", type: i2.CdkVirtualScrollViewport, selector: "cdk-virtual-scroll-viewport", inputs: ["orientation", "appendOnly"], outputs: ["scrolledIndexChange"] }, { kind: "component", type: TdIcon, selector: "td-icon", inputs: ["nombre", "titulo", "tamano"] }, { kind: "component", type: TdMenu, selector: "td-menu", inputs: ["items", "etiqueta", "icono", "posicion", "ancho", "disabled", "oscuro", "ariaLabel"], outputs: ["seleccion", "abiertoChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1401
1530
  }
1402
1531
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: TdDataTable, decorators: [{
1403
1532
  type: Component,
1404
- args: [{ selector: 'td-data-table', imports: [FormsModule, NgTemplateOutlet, ScrollingModule, TdIcon], changeDetection: ChangeDetectionStrategy.OnPush, template: "<section class=\"td-tabla\" [class.td-tabla--oscura]=\"oscuro\">\n <div class=\"td-tabla__toolbar\">\n <div class=\"td-tabla__filtros\">\n @if (mostrarBusqueda) {\n <label class=\"td-tabla__busqueda\">\n <td-icon nombre=\"search\" />\n <input\n type=\"search\"\n [(ngModel)]=\"busqueda\"\n [placeholder]=\"placeholderBusqueda\"\n (input)=\"buscar()\"\n />\n @if (busqueda) {\n <button type=\"button\" title=\"Limpiar b\u00FAsqueda\" (click)=\"limpiarBusqueda()\">\n <td-icon nombre=\"close\" tamano=\"1rem\" />\n </button>\n }\n </label>\n }\n <ng-content select=\"[tdDataTableFilters]\" />\n </div>\n </div>\n\n <div class=\"td-tabla__superficie\">\n <div class=\"td-tabla__resumen\">\n <span><strong>{{ datos.length }}</strong> de {{ total || datos.length }} registros</span>\n <div class=\"td-tabla__resumen-acciones\">\n <ng-content select=\"[tdDataTableActions]\" />\n @for (boton of botonesVisibles(); track boton.id) {\n <button\n type=\"button\"\n [class]=\"'td-tabla__boton td-tabla__boton--' + (boton.tono || 'neutro')\"\n [disabled]=\"boton.deshabilitado\"\n (click)=\"botonClick.emit(boton)\"\n >\n <td-icon [nombre]=\"boton.icono\" />\n <span>{{ boton.etiqueta }}</span>\n </button>\n }\n </div>\n </div>\n\n @if (datos.length) {\n <div class=\"td-tabla__scroll-x\">\n <div class=\"td-tabla__contenido\" [style.--td-tabla-columnas]=\"columnasGrid()\">\n <div class=\"td-tabla__encabezado\" role=\"row\">\n @for (columna of columnas; track columna.clave) {\n <div\n role=\"columnheader\"\n [class]=\"'td-tabla__alinear--' + (columna.alineacion || 'inicio')\"\n >\n {{ columna.encabezado }}\n </div>\n }\n @if (acciones.length) {\n <div role=\"columnheader\" class=\"td-tabla__alinear--centro\">Acciones</div>\n }\n </div>\n\n @if (usaVirtualizacion()) {\n <cdk-virtual-scroll-viewport\n class=\"td-tabla__viewport\"\n [itemSize]=\"itemSize\"\n [style.height]=\"altura\"\n (scroll)=\"alDesplazarViewport()\"\n (wheel)=\"marcarScrollUsuario()\"\n (touchmove)=\"marcarScrollUsuario()\"\n (keydown.arrowdown)=\"marcarScrollUsuario()\"\n (keydown.pagedown)=\"marcarScrollUsuario()\"\n (keydown.end)=\"marcarScrollUsuario()\"\n >\n <ng-container\n *cdkVirtualFor=\"let fila of datos; let indice = index; trackBy: trackFila\"\n >\n <ng-container\n [ngTemplateOutlet]=\"filaTemplate\"\n [ngTemplateOutletContext]=\"{ $implicit: fila, indice: indice }\"\n />\n </ng-container>\n </cdk-virtual-scroll-viewport>\n } @else {\n <div\n class=\"td-tabla__viewport td-tabla__viewport--normal\"\n [style.max-height]=\"altura\"\n (scroll)=\"alDesplazarLista($event)\"\n (wheel)=\"marcarScrollUsuario()\"\n (touchmove)=\"marcarScrollUsuario()\"\n (keydown.arrowdown)=\"marcarScrollUsuario()\"\n (keydown.pagedown)=\"marcarScrollUsuario()\"\n (keydown.end)=\"marcarScrollUsuario()\"\n >\n @for (fila of datos; track trackFila($index, fila); let indice = $index) {\n <ng-container\n [ngTemplateOutlet]=\"filaTemplate\"\n [ngTemplateOutletContext]=\"{ $implicit: fila, indice: indice }\"\n />\n }\n </div>\n }\n </div>\n </div>\n\n <ng-template #filaTemplate let-fila let-indice=\"indice\">\n <div\n class=\"td-tabla__fila\"\n role=\"row\"\n [style.height.px]=\"itemSize\"\n >\n @for (columna of columnas; track columna.clave) {\n <div\n role=\"cell\"\n [class]=\"'td-tabla__celda td-tabla__alinear--' + (columna.alineacion || 'inicio')\"\n >\n @if (columna.tipo === 'imagen') {\n @if (imagenSrc(columna, fila, indice); as src) {\n <button\n type=\"button\"\n [class]=\"'td-tabla__imagen td-tabla__imagen--' + imagenForma(columna)\"\n [title]=\"imagenAlt(columna, fila, indice)\"\n (click)=\"abrirImagen(columna, fila, indice)\"\n >\n <img [src]=\"src\" [alt]=\"imagenAlt(columna, fila, indice)\" loading=\"lazy\" />\n </button>\n } @else {\n <span\n [class]=\"'td-tabla__imagen td-tabla__imagen--placeholder td-tabla__imagen--' + imagenForma(columna)\"\n >\n <td-icon [nombre]=\"columna.imagen?.placeholder || 'image'\" />\n </span>\n }\n } @else if (\n columna.tipo === 'estado' ||\n columna.tipo === 'booleano' ||\n columna.tipo === 'chip'\n ) {\n <span [class]=\"'td-tabla__chip td-tabla__chip--' + tonoCelda(columna, fila)\">\n {{ textoCelda(columna, fila, indice) }}\n </span>\n } @else {\n <span\n [class.td-tabla__numero]=\"\n columna.tipo === 'numero' ||\n columna.tipo === 'decimal' ||\n columna.tipo === 'moneda' ||\n columna.tipo === 'porcentaje'\n \"\n >\n {{ textoCelda(columna, fila, indice) }}\n </span>\n }\n </div>\n }\n\n @if (acciones.length) {\n <div class=\"td-tabla__acciones-fila\" role=\"cell\">\n @for (accionFila of accionesVisibles(fila); track accionFila.id) {\n <button\n type=\"button\"\n [class]=\"'td-tabla__accion td-tabla__accion--' + tonoAccion(accionFila, fila)\"\n [title]=\"accionFila.etiqueta\"\n [disabled]=\"accionFila.deshabilitada?.(fila) ?? false\"\n (click)=\"ejecutarAccion(accionFila, fila, indice)\"\n >\n <td-icon [nombre]=\"iconoAccion(accionFila, fila)\" />\n <span class=\"td-tabla__sr-only\">{{ accionFila.etiqueta }}</span>\n </button>\n }\n </div>\n }\n </div>\n </ng-template>\n\n @if (cargando) {\n <div class=\"td-tabla__cargando\" role=\"status\" aria-live=\"polite\">\n <i aria-hidden=\"true\"></i>\n <span>Cargando m\u00E1s registros...</span>\n </div>\n }\n } @else if (!cargando) {\n <div class=\"td-tabla__vacio\">\n <span><td-icon nombre=\"inbox\" tamano=\"2.4rem\" /></span>\n <h3>{{ textoVacio }}</h3>\n <p>{{ descripcionVacio }}</p>\n </div>\n }\n\n @if (cargando && !datos.length) {\n <div class=\"td-tabla__skeleton\">\n @for (item of [1, 2, 3, 4, 5]; track item) {\n <span></span>\n }\n </div>\n }\n </div>\n</section>\n\n@if (imagenActiva; as imagen) {\n <dialog\n #imagenDialog\n class=\"td-tabla-imagen\"\n [attr.aria-label]=\"imagen.alt\"\n (click)=\"cerrarImagenSiBackdrop($event)\"\n (cancel)=\"cerrarImagen()\"\n (close)=\"imagenActiva = null\"\n >\n <section class=\"td-tabla-imagen__panel\">\n <header>\n <span>{{ imagen.alt }}</span>\n <button type=\"button\" aria-label=\"Cerrar\" (click)=\"cerrarImagen()\">\n <td-icon nombre=\"close\" />\n </button>\n </header>\n <div>\n <img [src]=\"imagen.src\" [alt]=\"imagen.alt\" />\n </div>\n </section>\n </dialog>\n}\n", styles: [":host{display:block}*{box-sizing:border-box}.td-tabla{--fondo: var(--td-color-surface, #fff);--fondo-suave: var(--td-color-surface-soft, #f8fafc);--borde: var(--td-color-border, #e4e8f0);--texto: var(--td-color-text, #263147);--suave: var(--td-color-text-muted, #748096);--hover: var(--td-color-surface-soft, #f7f8fc);--acento: var(--td-color-primary, #5746d8);color:var(--texto);font-family:var(--td-font-family, Inter, ui-sans-serif, system-ui, sans-serif);position:relative;z-index:0;isolation:isolate;contain:layout paint style;overflow-anchor:none}.td-tabla--oscura{--fondo: var(--td-color-surface, #15151b);--fondo-suave: var(--td-color-surface-soft, #1b1b22);--borde: var(--td-color-border, #2d2d36);--texto: var(--td-color-text, #ededf0);--suave: var(--td-color-text-muted, #9393a0);--hover: var(--td-color-surface-muted, #202028);--acento: var(--td-color-primary, #a89cf7)}.td-tabla__toolbar{display:flex;align-items:flex-start;justify-content:space-between;gap:1rem;padding:.55rem 0 .95rem}.td-tabla__filtros{display:flex;min-width:0;flex:1;flex-wrap:wrap;align-items:flex-start;gap:.8rem .65rem}.td-tabla__busqueda{display:flex;width:min(22rem,100%);min-height:3.15rem;align-items:center;gap:.6rem;border:1px solid var(--borde);border-radius:var(--td-radius-md, .78rem);padding:0 .75rem;color:var(--suave);background:var(--fondo);transition:border-color .14s ease,box-shadow .14s ease}.td-tabla__busqueda:focus-within{border-color:var(--acento);box-shadow:var(--td-focus-ring, 0 0 0 3px color-mix(in srgb, var(--acento) 15%, transparent))}.td-tabla__busqueda input{min-width:0;flex:1;border:0;appearance:none;outline:0;color:var(--texto);background:transparent;font:inherit;font-size:.78rem}.td-tabla__busqueda input::-webkit-search-cancel-button,.td-tabla__busqueda input::-webkit-search-decoration{appearance:none;display:none}.td-tabla__busqueda input::-ms-clear,.td-tabla__busqueda input::-ms-reveal{display:none;width:0;height:0}.td-tabla__busqueda button{display:grid;place-items:center;border:0;padding:.2rem;color:var(--suave);background:transparent;cursor:pointer}.td-tabla__vacio button,.td-tabla__boton{display:inline-flex;height:2.55rem;align-items:center;gap:.45rem;border:0;border-radius:var(--td-radius-md, .7rem);padding:0 1rem;color:var(--td-color-on-primary, #fff);background:linear-gradient(135deg,var(--td-color-primary, #5746d8),var(--td-color-info, #7657df));box-shadow:var(--td-shadow-sm, 0 7px 16px rgba(87, 70, 216, .2));font-size:.75rem;font-weight:750;cursor:pointer}.td-tabla__resumen-acciones{display:flex;align-items:center;gap:.45rem}.td-tabla__boton{height:2.15rem;padding:0 .75rem;box-shadow:none;color:var(--td-color-text-muted, #526077);background:var(--td-color-surface-muted, #edf0f5)}.td-tabla__boton--primario{color:var(--td-color-on-primary, #fff);background:linear-gradient(135deg,var(--td-color-primary, #5746d8),var(--td-color-info, #7657df));box-shadow:var(--td-shadow-sm, 0 7px 16px rgba(87, 70, 216, .2))}.td-tabla__boton--exito{color:var(--td-color-on-primary, #fff);background:var(--td-color-success, #168447)}.td-tabla__boton--advertencia{color:var(--td-color-on-primary, #fff);background:var(--td-color-warning, #b66d05)}.td-tabla__boton--peligro{color:var(--td-color-on-primary, #fff);background:var(--td-color-danger, #d33f3f)}.td-tabla__boton:disabled{opacity:.45;cursor:not-allowed}.td-tabla__superficie{position:relative;z-index:0;overflow:hidden;border:1px solid var(--borde);border-radius:var(--td-radius-xl, 1rem);background:var(--fondo);box-shadow:var(--td-shadow-sm, 0 12px 32px rgba(31, 42, 68, .06))}.td-tabla__resumen{display:flex;min-height:3rem;align-items:center;justify-content:space-between;border-bottom:1px solid var(--borde);padding:.7rem 1rem;color:var(--suave);background:var(--fondo-suave);font-size:.7rem}.td-tabla__resumen strong{color:var(--texto)}.td-tabla__cargando{position:absolute;z-index:4;right:0;bottom:0;left:0;display:flex;min-height:2.75rem;align-items:center;justify-content:center;gap:.55rem;border-top:1px solid var(--borde);color:var(--suave);background:color-mix(in srgb,var(--fondo-suave) 94%,transparent);box-shadow:0 -8px 20px color-mix(in srgb,var(--texto) 8%,transparent);-webkit-backdrop-filter:blur(5px);backdrop-filter:blur(5px);font-size:.7rem;font-weight:650;pointer-events:none}.td-tabla__cargando i{width:.85rem;height:.85rem;border:2px solid var(--borde);border-top-color:var(--acento);border-radius:var(--td-radius-pill, 50%);animation:td-tabla-girar .7s linear infinite}.td-tabla__encabezado,.td-tabla__fila{display:grid;align-items:center;grid-template-columns:var(--td-tabla-columnas)}.td-tabla__scroll-x{width:100%;overflow-x:auto;overflow-y:hidden;scrollbar-gutter:stable;scrollbar-width:thin;scrollbar-color:color-mix(in srgb,var(--suave) 42%,transparent) transparent}.td-tabla__contenido{display:grid;grid-template-columns:var(--td-tabla-columnas);min-width:max-content}.td-tabla__encabezado{position:relative;z-index:2;grid-column:1/-1;min-height:2.75rem;border-bottom:1px solid var(--borde);color:var(--suave);background:var(--fondo-suave);font-size:.62rem;font-weight:800;letter-spacing:.075em;text-transform:uppercase}.td-tabla__encabezado>div,.td-tabla__celda{padding:.6rem 1rem}.td-tabla__viewport{grid-column:1/-1;width:100%;min-width:0;min-height:12rem;overflow-x:hidden;overflow-anchor:none;scrollbar-gutter:stable;scrollbar-width:thin;scrollbar-color:color-mix(in srgb,var(--suave) 45%,transparent) transparent}.td-tabla__viewport--normal{overflow-x:hidden;overflow-y:auto}.td-tabla__fila{grid-column:1/-1;border-bottom:1px solid var(--borde);transition:background .12s ease}.td-tabla__fila:hover{background:var(--hover)}.td-tabla__celda{overflow:hidden;color:var(--texto);font-size:.75rem;text-overflow:ellipsis;white-space:nowrap}.td-tabla__numero{font-variant-numeric:tabular-nums}.td-tabla__alinear--inicio{text-align:left}.td-tabla__alinear--centro{text-align:center;justify-content:center}.td-tabla__alinear--fin{text-align:right;justify-content:flex-end}.td-tabla__imagen{display:inline-grid;width:2.35rem;height:2.35rem;place-items:center;overflow:hidden;border:1px solid var(--borde);padding:0;color:var(--suave);background:var(--fondo-suave);vertical-align:middle}button.td-tabla__imagen{cursor:zoom-in}button.td-tabla__imagen:hover{border-color:var(--acento);box-shadow:var(--td-focus-ring, 0 0 0 3px color-mix(in srgb, var(--acento) 14%, transparent))}.td-tabla__imagen img{width:100%;height:100%;object-fit:cover}.td-tabla__imagen--cuadrada{border-radius:var(--td-radius-sm, .55rem)}.td-tabla__imagen--redondeada{border-radius:var(--td-radius-md, .85rem)}.td-tabla__imagen--circular{border-radius:var(--td-radius-pill, 999px)}.td-tabla__imagen--placeholder{border-style:dashed}.td-tabla__chip{display:inline-flex;border-radius:var(--td-radius-pill, 999px);padding:.25rem .55rem;color:var(--td-color-text-muted, #526077);background:var(--td-color-surface-muted, #edf0f5);font-size:.65rem;font-weight:750}.td-tabla__chip--primario{color:var(--td-color-primary, #4f46e5);background:var(--td-color-primary-soft, #eeecff)}.td-tabla__chip--exito{color:var(--td-color-success, #13713a);background:var(--td-color-success-soft, #dff7e8)}.td-tabla__chip--advertencia{color:var(--td-color-warning, #9a5a05);background:var(--td-color-warning-soft, #fff0cf)}.td-tabla__chip--peligro{color:var(--td-color-danger, #b53434);background:var(--td-color-danger-soft, #fee5e5)}.td-tabla__acciones-fila{display:flex;align-items:center;justify-content:center;gap:.25rem;padding:0 .7rem}.td-tabla__accion{display:grid;width:2rem;height:2rem;place-items:center;border:0;border-radius:var(--td-radius-sm, .55rem);color:var(--suave);background:transparent;cursor:pointer}.td-tabla__accion:hover{background:var(--hover);color:var(--acento)}.td-tabla__accion--exito{color:var(--td-color-success, #168447)}.td-tabla__accion--peligro{color:var(--td-color-danger, #dc3e3e)}.td-tabla__accion--advertencia{color:var(--td-color-warning, #b66d05)}.td-tabla__accion:disabled{opacity:.35;cursor:not-allowed}.td-tabla__vacio{display:grid;min-height:21rem;place-items:center;align-content:center;padding:2rem;text-align:center}.td-tabla__vacio>span{display:grid;width:4.5rem;height:4.5rem;place-items:center;border-radius:var(--td-radius-xl, 1.2rem);color:var(--acento);background:color-mix(in srgb,var(--acento) 10%,transparent)}.td-tabla__vacio h3{margin:1rem 0 .3rem;font-size:1rem}.td-tabla__vacio p{margin:0 0 1.25rem;color:var(--suave);font-size:.75rem}.td-tabla__skeleton{padding:.5rem 1rem}.td-tabla__skeleton span{display:block;height:3.5rem;border-bottom:1px solid var(--borde);background:linear-gradient(90deg,transparent,var(--hover),transparent);background-size:200% 100%;animation:td-tabla-cargar 1.2s linear infinite}.td-tabla__sr-only{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap}@keyframes td-tabla-girar{to{transform:rotate(360deg)}}@keyframes td-tabla-cargar{to{background-position:-200% 0}}.td-tabla-imagen{width:min(680px,100vw - 2rem);max-width:none;max-height:min(76dvh,620px);border:0;padding:0;overflow:visible;color:inherit;background:transparent}.td-tabla-imagen::backdrop{background:#0a101e80;-webkit-backdrop-filter:blur(7px);backdrop-filter:blur(7px)}.td-tabla-imagen__panel{display:grid;grid-template-rows:auto minmax(0,1fr);width:100%;max-height:min(76dvh,620px);overflow:hidden;border:1px solid var(--td-color-border, #e4e8f0);border-radius:var(--td-radius-xl, 1.15rem);background:var(--td-color-surface, #fff);box-shadow:var(--td-shadow-xl, 0 24px 72px rgba(15, 23, 42, .28))}.td-tabla-imagen__panel header{display:flex;align-items:center;justify-content:space-between;gap:1rem;border-bottom:1px solid var(--td-color-border, #e4e8f0);padding:.75rem .9rem;background:var(--td-color-surface, #fff)}.td-tabla-imagen__panel span{overflow:hidden;color:var(--td-color-text, #263147);font-size:.78rem;font-weight:800;text-overflow:ellipsis;white-space:nowrap}.td-tabla-imagen__panel button{display:grid;width:2.1rem;height:2.1rem;place-items:center;border:0;border-radius:var(--td-radius-sm, .55rem);color:var(--td-color-text-muted, #748096);background:var(--td-color-surface-soft, #f8fafc);cursor:pointer}.td-tabla-imagen__panel>div{display:grid;min-height:18rem;overflow:hidden;padding:1rem;background:var(--td-color-surface-soft, #f8fafc)}.td-tabla-imagen__panel img{display:block;width:auto;max-width:100%;max-height:min(58dvh,500px);margin:auto;border-radius:var(--td-radius-lg, 1rem);object-fit:contain;box-shadow:var(--td-shadow-md, 0 16px 42px rgba(15, 23, 42, .16))}@media(max-width:640px){.td-tabla__toolbar{align-items:stretch;flex-direction:column}.td-tabla__busqueda{width:100%}.td-tabla__resumen{align-items:flex-start;flex-direction:column}.td-tabla__resumen-acciones{width:100%;flex-wrap:wrap}.td-tabla-imagen{padding:.75rem}.td-tabla-imagen{width:calc(100vw - 1.5rem)}.td-tabla-imagen__panel{width:100%;max-height:calc(100dvh - 1.5rem);height:auto;border-radius:var(--td-radius-xl, 1rem)}.td-tabla-imagen__panel>div{min-height:14rem;padding:.75rem}.td-tabla-imagen__panel img{max-height:calc(100dvh - 7rem)}}\n"] }]
1533
+ args: [{ selector: 'td-data-table', imports: [FormsModule, NgTemplateOutlet, ScrollingModule, TdIcon, TdMenu], changeDetection: ChangeDetectionStrategy.OnPush, template: "<section class=\"td-tabla\" [class.td-tabla--oscura]=\"oscuro\">\n <div class=\"td-tabla__toolbar\">\n <div class=\"td-tabla__filtros\">\n @if (mostrarBusqueda) {\n <label class=\"td-tabla__busqueda\">\n <td-icon nombre=\"search\" />\n <input\n type=\"search\"\n [(ngModel)]=\"busqueda\"\n [placeholder]=\"placeholderBusqueda\"\n (input)=\"buscar()\"\n />\n @if (busqueda) {\n <button type=\"button\" title=\"Limpiar b\u00FAsqueda\" (click)=\"limpiarBusqueda()\">\n <td-icon nombre=\"close\" tamano=\"1rem\" />\n </button>\n }\n </label>\n }\n <ng-content select=\"[tdDataTableFilters]\" />\n </div>\n </div>\n\n <div class=\"td-tabla__superficie\">\n <div class=\"td-tabla__resumen\">\n <span><strong>{{ datos.length }}</strong> de {{ total || datos.length }} registros</span>\n <div class=\"td-tabla__resumen-acciones\">\n <ng-content select=\"[tdDataTableActions]\" />\n @for (boton of botonesVisibles(); track boton.id) {\n <button\n type=\"button\"\n [class]=\"'td-tabla__boton td-tabla__boton--' + (boton.tono || 'neutro')\"\n [disabled]=\"boton.deshabilitado\"\n (click)=\"botonClick.emit(boton)\"\n >\n <td-icon [nombre]=\"boton.icono\" />\n <span>{{ boton.etiqueta }}</span>\n </button>\n }\n </div>\n </div>\n\n @if (datos.length) {\n <div class=\"td-tabla__scroll-x\">\n <div class=\"td-tabla__contenido\" [style.--td-tabla-columnas]=\"columnasGrid()\">\n <div class=\"td-tabla__encabezado\" role=\"row\">\n @for (columna of columnas; track columna.clave) {\n <div\n role=\"columnheader\"\n [class]=\"'td-tabla__alinear--' + (columna.alineacion || 'inicio')\"\n >\n {{ columna.encabezado }}\n </div>\n }\n @if (acciones.length) {\n <div role=\"columnheader\" class=\"td-tabla__alinear--centro\">Acciones</div>\n }\n </div>\n\n @if (usaVirtualizacion()) {\n <cdk-virtual-scroll-viewport\n class=\"td-tabla__viewport\"\n [itemSize]=\"itemSize\"\n [style.height]=\"altura\"\n (scroll)=\"alDesplazarViewport()\"\n (wheel)=\"marcarScrollUsuario()\"\n (touchmove)=\"marcarScrollUsuario()\"\n (keydown.arrowdown)=\"marcarScrollUsuario()\"\n (keydown.pagedown)=\"marcarScrollUsuario()\"\n (keydown.end)=\"marcarScrollUsuario()\"\n >\n <ng-container\n *cdkVirtualFor=\"let fila of datos; let indice = index; trackBy: trackFila\"\n >\n <ng-container\n [ngTemplateOutlet]=\"filaTemplate\"\n [ngTemplateOutletContext]=\"{ $implicit: fila, indice: indice }\"\n />\n </ng-container>\n </cdk-virtual-scroll-viewport>\n } @else {\n <div\n class=\"td-tabla__viewport td-tabla__viewport--normal\"\n [style.max-height]=\"altura\"\n (scroll)=\"alDesplazarLista($event)\"\n (wheel)=\"marcarScrollUsuario()\"\n (touchmove)=\"marcarScrollUsuario()\"\n (keydown.arrowdown)=\"marcarScrollUsuario()\"\n (keydown.pagedown)=\"marcarScrollUsuario()\"\n (keydown.end)=\"marcarScrollUsuario()\"\n >\n @for (fila of datos; track trackFila($index, fila); let indice = $index) {\n <ng-container\n [ngTemplateOutlet]=\"filaTemplate\"\n [ngTemplateOutletContext]=\"{ $implicit: fila, indice: indice }\"\n />\n }\n </div>\n }\n </div>\n </div>\n\n <ng-template #filaTemplate let-fila let-indice=\"indice\">\n <div\n class=\"td-tabla__fila\"\n role=\"row\"\n [style.height.px]=\"itemSize\"\n >\n @for (columna of columnas; track columna.clave) {\n <div\n role=\"cell\"\n [class]=\"'td-tabla__celda td-tabla__alinear--' + (columna.alineacion || 'inicio')\"\n >\n @if (columna.tipo === 'imagen') {\n @if (imagenSrc(columna, fila, indice); as src) {\n <button\n type=\"button\"\n [class]=\"'td-tabla__imagen td-tabla__imagen--' + imagenForma(columna)\"\n [title]=\"imagenAlt(columna, fila, indice)\"\n (click)=\"abrirImagen(columna, fila, indice)\"\n >\n <img [src]=\"src\" [alt]=\"imagenAlt(columna, fila, indice)\" loading=\"lazy\" />\n </button>\n } @else {\n <span\n [class]=\"'td-tabla__imagen td-tabla__imagen--placeholder td-tabla__imagen--' + imagenForma(columna)\"\n >\n <td-icon [nombre]=\"columna.imagen?.placeholder || 'image'\" />\n </span>\n }\n } @else if (\n columna.tipo === 'estado' ||\n columna.tipo === 'booleano' ||\n columna.tipo === 'chip'\n ) {\n <span [class]=\"'td-tabla__chip td-tabla__chip--' + tonoCelda(columna, fila)\">\n {{ textoCelda(columna, fila, indice) }}\n </span>\n } @else {\n <span\n [class.td-tabla__numero]=\"\n columna.tipo === 'numero' ||\n columna.tipo === 'decimal' ||\n columna.tipo === 'moneda' ||\n columna.tipo === 'porcentaje'\n \"\n >\n {{ textoCelda(columna, fila, indice) }}\n </span>\n }\n </div>\n }\n\n @if (acciones.length) {\n <div class=\"td-tabla__acciones-fila\" role=\"cell\">\n @if (usarMenuAcciones(fila)) {\n <td-menu\n ariaLabel=\"Acciones de fila\"\n icono=\"more_vertical\"\n ancho=\"15rem\"\n [oscuro]=\"oscuro\"\n [items]=\"accionesMenu(fila)\"\n (seleccion)=\"ejecutarAccionMenu($event, fila, indice)\"\n />\n } @else {\n @for (accionFila of accionesVisibles(fila); track accionFila.id) {\n <button\n type=\"button\"\n [class]=\"'td-tabla__accion td-tabla__accion--' + tonoAccion(accionFila, fila)\"\n [title]=\"accionFila.etiqueta\"\n [disabled]=\"accionFila.deshabilitada?.(fila) ?? false\"\n (click)=\"ejecutarAccion(accionFila, fila, indice)\"\n >\n <td-icon [nombre]=\"iconoAccion(accionFila, fila)\" />\n <span class=\"td-tabla__sr-only\">{{ accionFila.etiqueta }}</span>\n </button>\n }\n }\n </div>\n }\n </div>\n </ng-template>\n\n @if (cargando) {\n <div class=\"td-tabla__cargando\" role=\"status\" aria-live=\"polite\">\n <i aria-hidden=\"true\"></i>\n <span>Cargando m\u00E1s registros...</span>\n </div>\n }\n } @else if (!cargando) {\n <div class=\"td-tabla__vacio\">\n <span><td-icon nombre=\"inbox\" tamano=\"2.4rem\" /></span>\n <h3>{{ textoVacio }}</h3>\n <p>{{ descripcionVacio }}</p>\n </div>\n }\n\n @if (cargando && !datos.length) {\n <div class=\"td-tabla__skeleton\">\n @for (item of [1, 2, 3, 4, 5]; track item) {\n <span></span>\n }\n </div>\n }\n </div>\n</section>\n\n@if (imagenActiva; as imagen) {\n <dialog\n #imagenDialog\n class=\"td-tabla-imagen\"\n [attr.aria-label]=\"imagen.alt\"\n (click)=\"cerrarImagenSiBackdrop($event)\"\n (cancel)=\"cerrarImagen()\"\n (close)=\"imagenActiva = null\"\n >\n <section class=\"td-tabla-imagen__panel\">\n <header>\n <span>{{ imagen.alt }}</span>\n <button type=\"button\" aria-label=\"Cerrar\" (click)=\"cerrarImagen()\">\n <td-icon nombre=\"close\" />\n </button>\n </header>\n <div>\n <img [src]=\"imagen.src\" [alt]=\"imagen.alt\" />\n </div>\n </section>\n </dialog>\n}\n", styles: [":host{display:block}*{box-sizing:border-box}.td-tabla{--fondo: var(--td-color-surface, #fff);--fondo-suave: var(--td-color-surface-soft, #f8fafc);--borde: var(--td-color-border, #e4e8f0);--texto: var(--td-color-text, #263147);--suave: var(--td-color-text-muted, #748096);--hover: var(--td-color-surface-soft, #f7f8fc);--acento: var(--td-color-primary, #5746d8);color:var(--texto);font-family:var(--td-font-family, Inter, ui-sans-serif, system-ui, sans-serif);position:relative;z-index:0;isolation:isolate;contain:layout paint style;overflow-anchor:none}.td-tabla--oscura{--fondo: var(--td-color-surface, #15151b);--fondo-suave: var(--td-color-surface-soft, #1b1b22);--borde: var(--td-color-border, #2d2d36);--texto: var(--td-color-text, #ededf0);--suave: var(--td-color-text-muted, #9393a0);--hover: var(--td-color-surface-muted, #202028);--acento: var(--td-color-primary, #a89cf7)}.td-tabla__toolbar{display:flex;align-items:flex-start;justify-content:space-between;gap:1rem;padding:.55rem 0 .95rem}.td-tabla__filtros{display:flex;min-width:0;flex:1;flex-wrap:wrap;align-items:flex-start;gap:.8rem .65rem}.td-tabla__busqueda{display:flex;width:min(22rem,100%);min-height:3.15rem;align-items:center;gap:.6rem;border:1px solid var(--borde);border-radius:var(--td-radius-md, .78rem);padding:0 .75rem;color:var(--suave);background:var(--fondo);transition:border-color .14s ease,box-shadow .14s ease}.td-tabla__busqueda:focus-within{border-color:var(--acento);box-shadow:var(--td-focus-ring, 0 0 0 3px color-mix(in srgb, var(--acento) 15%, transparent))}.td-tabla__busqueda input{min-width:0;flex:1;border:0;appearance:none;outline:0;color:var(--texto);background:transparent;font:inherit;font-size:.78rem}.td-tabla__busqueda input::-webkit-search-cancel-button,.td-tabla__busqueda input::-webkit-search-decoration{appearance:none;display:none}.td-tabla__busqueda input::-ms-clear,.td-tabla__busqueda input::-ms-reveal{display:none;width:0;height:0}.td-tabla__busqueda button{display:grid;place-items:center;border:0;padding:.2rem;color:var(--suave);background:transparent;cursor:pointer}.td-tabla__vacio button,.td-tabla__boton{display:inline-flex;height:2.55rem;align-items:center;gap:.45rem;border:0;border-radius:var(--td-radius-md, .7rem);padding:0 1rem;color:var(--td-color-on-primary, #fff);background:linear-gradient(135deg,var(--td-color-primary, #5746d8),var(--td-color-info, #7657df));box-shadow:var(--td-shadow-sm, 0 7px 16px rgba(87, 70, 216, .2));font-size:.75rem;font-weight:750;cursor:pointer}.td-tabla__resumen-acciones{display:flex;align-items:center;gap:.45rem}.td-tabla__boton{height:2.15rem;padding:0 .75rem;box-shadow:none;color:var(--td-color-text-muted, #526077);background:var(--td-color-surface-muted, #edf0f5)}.td-tabla__boton--primario{color:var(--td-color-on-primary, #fff);background:linear-gradient(135deg,var(--td-color-primary, #5746d8),var(--td-color-info, #7657df));box-shadow:var(--td-shadow-sm, 0 7px 16px rgba(87, 70, 216, .2))}.td-tabla__boton--exito{color:var(--td-color-on-primary, #fff);background:var(--td-color-success, #168447)}.td-tabla__boton--advertencia{color:var(--td-color-on-primary, #fff);background:var(--td-color-warning, #b66d05)}.td-tabla__boton--peligro{color:var(--td-color-on-primary, #fff);background:var(--td-color-danger, #d33f3f)}.td-tabla__boton:disabled{opacity:.45;cursor:not-allowed}.td-tabla__superficie{position:relative;z-index:0;overflow:hidden;border:1px solid var(--borde);border-radius:var(--td-radius-xl, 1rem);background:var(--fondo);box-shadow:var(--td-shadow-sm, 0 12px 32px rgba(31, 42, 68, .06))}.td-tabla__resumen{display:flex;min-height:3rem;align-items:center;justify-content:space-between;border-bottom:1px solid var(--borde);padding:.7rem 1rem;color:var(--suave);background:var(--fondo-suave);font-size:.7rem}.td-tabla__resumen strong{color:var(--texto)}.td-tabla__cargando{position:absolute;z-index:4;right:0;bottom:0;left:0;display:flex;min-height:2.75rem;align-items:center;justify-content:center;gap:.55rem;border-top:1px solid var(--borde);color:var(--suave);background:color-mix(in srgb,var(--fondo-suave) 94%,transparent);box-shadow:0 -8px 20px color-mix(in srgb,var(--texto) 8%,transparent);-webkit-backdrop-filter:blur(5px);backdrop-filter:blur(5px);font-size:.7rem;font-weight:650;pointer-events:none}.td-tabla__cargando i{width:.85rem;height:.85rem;border:2px solid var(--borde);border-top-color:var(--acento);border-radius:var(--td-radius-pill, 50%);animation:td-tabla-girar .7s linear infinite}.td-tabla__encabezado,.td-tabla__fila{display:grid;align-items:center;grid-template-columns:var(--td-tabla-columnas)}.td-tabla__scroll-x{width:100%;overflow-x:auto;overflow-y:hidden;scrollbar-gutter:stable;scrollbar-width:thin;scrollbar-color:color-mix(in srgb,var(--suave) 42%,transparent) transparent}.td-tabla__contenido{display:grid;grid-template-columns:var(--td-tabla-columnas);min-width:max-content}.td-tabla__encabezado{position:relative;z-index:2;grid-column:1/-1;min-height:2.75rem;border-bottom:1px solid var(--borde);color:var(--suave);background:var(--fondo-suave);font-size:.62rem;font-weight:800;letter-spacing:.075em;text-transform:uppercase}.td-tabla__encabezado>div,.td-tabla__celda{padding:.6rem 1rem}.td-tabla__viewport{grid-column:1/-1;width:100%;min-width:0;min-height:12rem;overflow-x:hidden;overflow-anchor:none;scrollbar-gutter:stable;scrollbar-width:thin;scrollbar-color:color-mix(in srgb,var(--suave) 45%,transparent) transparent}.td-tabla__viewport--normal{overflow-x:hidden;overflow-y:auto}.td-tabla__fila{grid-column:1/-1;border-bottom:1px solid var(--borde);transition:background .12s ease}.td-tabla__fila:hover{background:var(--hover)}.td-tabla__celda{overflow:hidden;color:var(--texto);font-size:.75rem;text-overflow:ellipsis;white-space:nowrap}.td-tabla__numero{font-variant-numeric:tabular-nums}.td-tabla__alinear--inicio{text-align:left}.td-tabla__alinear--centro{text-align:center;justify-content:center}.td-tabla__alinear--fin{text-align:right;justify-content:flex-end}.td-tabla__imagen{display:inline-grid;width:2.35rem;height:2.35rem;place-items:center;overflow:hidden;border:1px solid var(--borde);padding:0;color:var(--suave);background:var(--fondo-suave);vertical-align:middle}button.td-tabla__imagen{cursor:zoom-in}button.td-tabla__imagen:hover{border-color:var(--acento);box-shadow:var(--td-focus-ring, 0 0 0 3px color-mix(in srgb, var(--acento) 14%, transparent))}.td-tabla__imagen img{width:100%;height:100%;object-fit:cover}.td-tabla__imagen--cuadrada{border-radius:var(--td-radius-sm, .55rem)}.td-tabla__imagen--redondeada{border-radius:var(--td-radius-md, .85rem)}.td-tabla__imagen--circular{border-radius:var(--td-radius-pill, 999px)}.td-tabla__imagen--placeholder{border-style:dashed}.td-tabla__chip{display:inline-flex;border-radius:var(--td-radius-pill, 999px);padding:.25rem .55rem;color:var(--td-color-text-muted, #526077);background:var(--td-color-surface-muted, #edf0f5);font-size:.65rem;font-weight:750}.td-tabla__chip--primario{color:var(--td-color-primary, #4f46e5);background:var(--td-color-primary-soft, #eeecff)}.td-tabla__chip--exito{color:var(--td-color-success, #13713a);background:var(--td-color-success-soft, #dff7e8)}.td-tabla__chip--advertencia{color:var(--td-color-warning, #9a5a05);background:var(--td-color-warning-soft, #fff0cf)}.td-tabla__chip--peligro{color:var(--td-color-danger, #b53434);background:var(--td-color-danger-soft, #fee5e5)}.td-tabla__acciones-fila{display:flex;align-items:center;justify-content:center;gap:.25rem;padding:0 .7rem}.td-tabla__acciones-fila td-menu{line-height:1}.td-tabla__accion{display:grid;width:2rem;height:2rem;place-items:center;border:0;border-radius:var(--td-radius-sm, .55rem);color:var(--suave);background:transparent;cursor:pointer}.td-tabla__accion:hover{background:var(--hover);color:var(--acento)}.td-tabla__accion--exito{color:var(--td-color-success, #168447)}.td-tabla__accion--peligro{color:var(--td-color-danger, #dc3e3e)}.td-tabla__accion--advertencia{color:var(--td-color-warning, #b66d05)}.td-tabla__accion:disabled{opacity:.35;cursor:not-allowed}.td-tabla__vacio{display:grid;min-height:21rem;place-items:center;align-content:center;padding:2rem;text-align:center}.td-tabla__vacio>span{display:grid;width:4.5rem;height:4.5rem;place-items:center;border-radius:var(--td-radius-xl, 1.2rem);color:var(--acento);background:color-mix(in srgb,var(--acento) 10%,transparent)}.td-tabla__vacio h3{margin:1rem 0 .3rem;font-size:1rem}.td-tabla__vacio p{margin:0 0 1.25rem;color:var(--suave);font-size:.75rem}.td-tabla__skeleton{padding:.5rem 1rem}.td-tabla__skeleton span{display:block;height:3.5rem;border-bottom:1px solid var(--borde);background:linear-gradient(90deg,transparent,var(--hover),transparent);background-size:200% 100%;animation:td-tabla-cargar 1.2s linear infinite}.td-tabla__sr-only{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap}@keyframes td-tabla-girar{to{transform:rotate(360deg)}}@keyframes td-tabla-cargar{to{background-position:-200% 0}}.td-tabla-imagen{width:min(680px,100vw - 2rem);max-width:none;max-height:min(76dvh,620px);border:0;padding:0;overflow:visible;color:inherit;background:transparent}.td-tabla-imagen::backdrop{background:#0a101e80;-webkit-backdrop-filter:blur(7px);backdrop-filter:blur(7px)}.td-tabla-imagen__panel{display:grid;grid-template-rows:auto minmax(0,1fr);width:100%;max-height:min(76dvh,620px);overflow:hidden;border:1px solid var(--td-color-border, #e4e8f0);border-radius:var(--td-radius-xl, 1.15rem);background:var(--td-color-surface, #fff);box-shadow:var(--td-shadow-xl, 0 24px 72px rgba(15, 23, 42, .28))}.td-tabla-imagen__panel header{display:flex;align-items:center;justify-content:space-between;gap:1rem;border-bottom:1px solid var(--td-color-border, #e4e8f0);padding:.75rem .9rem;background:var(--td-color-surface, #fff)}.td-tabla-imagen__panel span{overflow:hidden;color:var(--td-color-text, #263147);font-size:.78rem;font-weight:800;text-overflow:ellipsis;white-space:nowrap}.td-tabla-imagen__panel button{display:grid;width:2.1rem;height:2.1rem;place-items:center;border:0;border-radius:var(--td-radius-sm, .55rem);color:var(--td-color-text-muted, #748096);background:var(--td-color-surface-soft, #f8fafc);cursor:pointer}.td-tabla-imagen__panel>div{display:grid;min-height:18rem;overflow:hidden;padding:1rem;background:var(--td-color-surface-soft, #f8fafc)}.td-tabla-imagen__panel img{display:block;width:auto;max-width:100%;max-height:min(58dvh,500px);margin:auto;border-radius:var(--td-radius-lg, 1rem);object-fit:contain;box-shadow:var(--td-shadow-md, 0 16px 42px rgba(15, 23, 42, .16))}@media(max-width:640px){.td-tabla__toolbar{align-items:stretch;flex-direction:column}.td-tabla__busqueda{width:100%}.td-tabla__resumen{align-items:flex-start;flex-direction:column}.td-tabla__resumen-acciones{width:100%;flex-wrap:wrap}.td-tabla-imagen{padding:.75rem}.td-tabla-imagen{width:calc(100vw - 1.5rem)}.td-tabla-imagen__panel{width:100%;max-height:calc(100dvh - 1.5rem);height:auto;border-radius:var(--td-radius-xl, 1rem)}.td-tabla-imagen__panel>div{min-height:14rem;padding:.75rem}.td-tabla-imagen__panel img{max-height:calc(100dvh - 7rem)}}\n"] }]
1405
1534
  }], propDecorators: { viewport: [{
1406
1535
  type: ViewChild,
1407
1536
  args: [CdkVirtualScrollViewport]
@@ -1414,6 +1543,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.4", ngImpor
1414
1543
  type: Input
1415
1544
  }], acciones: [{
1416
1545
  type: Input
1546
+ }], accionesPresentacion: [{
1547
+ type: Input
1417
1548
  }], botones: [{
1418
1549
  type: Input
1419
1550
  }], total: [{
@@ -2544,7 +2675,13 @@ class TdFileViewer {
2544
2675
  cdr = inject(ChangeDetectorRef);
2545
2676
  visorDialog;
2546
2677
  pdfCanvas;
2547
- archivos = [];
2678
+ archivosNormalizados = [];
2679
+ set archivos(value) {
2680
+ this.archivosNormalizados = (value ?? []).map((archivo, indice) => this.normalizarArchivo(archivo, indice));
2681
+ }
2682
+ get archivos() {
2683
+ return this.archivosNormalizados;
2684
+ }
2548
2685
  titulo = 'Archivos adjuntos';
2549
2686
  descripcion = 'Visualiza imagenes, PDF y descarga otros formatos.';
2550
2687
  oscuro = false;
@@ -2694,7 +2831,7 @@ class TdFileViewer {
2694
2831
  this.cdr.markForCheck();
2695
2832
  try {
2696
2833
  const pdfjs = await this.obtenerPdfJs();
2697
- const loadingTask = pdfjs.getDocument({ url: archivo.url });
2834
+ const loadingTask = pdfjs.getDocument(this.obtenerFuentePdf(archivo));
2698
2835
  const documento = (await loadingTask.promise);
2699
2836
  if (token !== this.pdfRenderToken) {
2700
2837
  await documento.destroy?.();
@@ -2776,6 +2913,80 @@ class TdFileViewer {
2776
2913
  this.pdfPaginaActual = 1;
2777
2914
  this.pdfTotalPaginas = 0;
2778
2915
  }
2916
+ normalizarArchivo(archivo, indice) {
2917
+ if (this.esAdjuntoNormalizado(archivo)) {
2918
+ return archivo;
2919
+ }
2920
+ const contentType = archivo.type || archivo.contentType || this.inferirContentType(archivo.fileName, archivo.file);
2921
+ const url = this.normalizarFileUrl(archivo.file, contentType);
2922
+ return {
2923
+ id: archivo.id ?? `${archivo.fileName}-${indice}`,
2924
+ nombre: archivo.fileName,
2925
+ url,
2926
+ tipo: contentType,
2927
+ tamano: archivo.size,
2928
+ descripcion: archivo.description,
2929
+ thumbnailUrl: archivo.thumbnailUrl,
2930
+ descargable: archivo.downloadable,
2931
+ };
2932
+ }
2933
+ esAdjuntoNormalizado(archivo) {
2934
+ return 'nombre' in archivo && 'url' in archivo;
2935
+ }
2936
+ normalizarFileUrl(file, contentType) {
2937
+ const value = file.trim();
2938
+ if (!value)
2939
+ return '';
2940
+ if (/^(https?:|blob:|data:)/i.test(value))
2941
+ return value;
2942
+ return `data:${contentType};base64,${value}`;
2943
+ }
2944
+ inferirContentType(fileName, file) {
2945
+ const value = `${fileName} ${file.slice(0, 80)}`.toLowerCase();
2946
+ if (value.includes('data:')) {
2947
+ const match = file.match(/^data:([^;,]+)/i);
2948
+ if (match?.[1])
2949
+ return match[1];
2950
+ }
2951
+ if (/\.(png)$/i.test(fileName))
2952
+ return 'image/png';
2953
+ if (/\.(jpe?g)$/i.test(fileName))
2954
+ return 'image/jpeg';
2955
+ if (/\.(gif)$/i.test(fileName))
2956
+ return 'image/gif';
2957
+ if (/\.(webp)$/i.test(fileName))
2958
+ return 'image/webp';
2959
+ if (/\.(svg)$/i.test(fileName))
2960
+ return 'image/svg+xml';
2961
+ if (/\.(pdf)$/i.test(fileName))
2962
+ return 'application/pdf';
2963
+ if (/\.(xlsx)$/i.test(fileName))
2964
+ return 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet';
2965
+ if (/\.(xls)$/i.test(fileName))
2966
+ return 'application/vnd.ms-excel';
2967
+ if (/\.(csv)$/i.test(fileName))
2968
+ return 'text/csv';
2969
+ if (/\.(xml)$/i.test(fileName))
2970
+ return 'application/xml';
2971
+ if (/\.(zip)$/i.test(fileName))
2972
+ return 'application/zip';
2973
+ return 'application/octet-stream';
2974
+ }
2975
+ obtenerFuentePdf(archivo) {
2976
+ const dataUrl = archivo.url.match(/^data:application\/pdf[^,]*,(.+)$/i);
2977
+ if (!dataUrl?.[1])
2978
+ return { url: archivo.url };
2979
+ return { data: this.base64ABytes(dataUrl[1]) };
2980
+ }
2981
+ base64ABytes(base64) {
2982
+ const limpio = decodeURIComponent(base64).replace(/\s/g, '');
2983
+ const binario = atob(limpio);
2984
+ const bytes = new Uint8Array(binario.length);
2985
+ for (let i = 0; i < binario.length; i += 1) {
2986
+ bytes[i] = binario.charCodeAt(i);
2987
+ }
2988
+ return bytes;
2989
+ }
2779
2990
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: TdFileViewer, deps: [], target: i0.ɵɵFactoryTarget.Component });
2780
2991
  static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.4", type: TdFileViewer, isStandalone: true, selector: "td-file-viewer", inputs: { archivos: "archivos", titulo: "titulo", descripcion: "descripcion", oscuro: "oscuro", compacto: "compacto" }, outputs: { seleccionar: "seleccionar", descargar: "descargar" }, viewQueries: [{ propertyName: "visorDialog", first: true, predicate: ["visorDialog"], descendants: true }, { propertyName: "pdfCanvas", first: true, predicate: ["pdfCanvas"], descendants: true }], ngImport: i0, template: "<section\n class=\"td-file-viewer\"\n [class.td-file-viewer--dark]=\"oscuro\"\n [class.td-file-viewer--compact]=\"compacto\"\n>\n <header class=\"td-file-viewer__header\">\n <div>\n <span>{{ archivos.length }} archivo{{ archivos.length === 1 ? '' : 's' }}</span>\n <h3>{{ titulo }}</h3>\n @if (descripcion) {\n <p>{{ descripcion }}</p>\n }\n </div>\n </header>\n\n @if (archivos.length) {\n <div class=\"td-file-viewer__grid\">\n @for (archivo of archivos; track archivo.id) {\n <button type=\"button\" class=\"td-file-viewer__item\" (click)=\"abrir(archivo)\">\n <span class=\"td-file-viewer__preview\" [class.td-file-viewer__preview--image]=\"tipoArchivo(archivo) === 'imagen'\">\n @if (tipoArchivo(archivo) === 'imagen') {\n <img [src]=\"archivo.thumbnailUrl || archivo.url\" [alt]=\"archivo.nombre\" loading=\"lazy\" />\n } @else {\n <td-icon [nombre]=\"iconoArchivo(archivo)\" tamano=\"1.55rem\" />\n }\n </span>\n\n <span class=\"td-file-viewer__meta\">\n <strong>{{ archivo.nombre }}</strong>\n @if (archivo.descripcion) {\n <small>{{ archivo.descripcion }}</small>\n }\n <em>\n {{ tieneVistaPrevia(archivo) ? 'Vista previa disponible' : 'Descarga / apertura externa' }}\n @if (tamanoLegible(archivo)) {\n - {{ tamanoLegible(archivo) }}\n }\n </em>\n </span>\n\n @if (archivo.descargable !== false) {\n <span\n role=\"button\"\n tabindex=\"-1\"\n class=\"td-file-viewer__download\"\n title=\"Descargar\"\n (click)=\"descargarArchivo(archivo, $event)\"\n >\n <td-icon nombre=\"download\" tamano=\"1rem\" />\n </span>\n }\n </button>\n }\n </div>\n } @else {\n <div class=\"td-file-viewer__empty\">\n <td-icon nombre=\"file\" tamano=\"2rem\" />\n <strong>No hay adjuntos</strong>\n <span>Cuando existan archivos apareceran en esta zona.</span>\n </div>\n }\n</section>\n\n@if (seleccionado; as archivo) {\n <dialog\n #visorDialog\n class=\"td-file-viewer-modal\"\n [class.td-file-viewer-modal--dark]=\"oscuro\"\n [attr.aria-label]=\"archivo.nombre\"\n (click)=\"cerrarSiBackdrop($event)\"\n (cancel)=\"cerrar()\"\n (close)=\"seleccionado = null\"\n >\n <section class=\"td-file-viewer-modal__panel\">\n <header class=\"td-file-viewer-modal__topbar\">\n <div class=\"td-file-viewer-modal__title\">\n <span class=\"td-file-viewer-modal__badge\">\n <td-icon [nombre]=\"iconoArchivo(archivo)\" tamano=\".95rem\" />\n {{ tipoArchivo(archivo) }}\n </span>\n <h3>{{ archivo.nombre }}</h3>\n @if (archivo.descripcion || tamanoLegible(archivo)) {\n <p>\n {{ archivo.descripcion || 'Archivo adjunto' }}\n @if (tamanoLegible(archivo)) {\n - {{ tamanoLegible(archivo) }}\n }\n </p>\n }\n </div>\n\n <nav class=\"td-file-viewer-modal__toolbar\" aria-label=\"Acciones del visor\">\n <button type=\"button\" title=\"Anterior\" [disabled]=\"indiceSeleccionado() <= 0\" (click)=\"seleccionarAnterior()\">\n <td-icon nombre=\"chevron_left\" />\n </button>\n <button type=\"button\" title=\"Siguiente\" [disabled]=\"indiceSeleccionado() >= archivos.length - 1\" (click)=\"seleccionarSiguiente()\">\n <td-icon nombre=\"chevron_right\" />\n </button>\n\n @if (esImagen(archivo) || esPdf(archivo)) {\n <span class=\"td-file-viewer-modal__divider\"></span>\n <button type=\"button\" title=\"Alejar\" (click)=\"cambiarZoom(-0.1)\">\n <span aria-hidden=\"true\">-</span>\n </button>\n <button type=\"button\" class=\"td-file-viewer-modal__zoom\" title=\"Restablecer zoom\" (click)=\"restablecerZoom()\">\n {{ (zoom * 100).toFixed(0) }}%\n </button>\n <button type=\"button\" title=\"Acercar\" (click)=\"cambiarZoom(0.1)\">\n <span aria-hidden=\"true\">+</span>\n </button>\n <button type=\"button\" class=\"td-file-viewer-modal__text-action\" title=\"Ajustar\" (click)=\"restablecerZoom()\">\n Ajustar\n </button>\n @if (esImagen(archivo)) {\n <button type=\"button\" class=\"td-file-viewer-modal__text-action\" title=\"Rotar\" (click)=\"rotar()\">\n Rotar\n </button>\n }\n }\n\n <span class=\"td-file-viewer-modal__divider\"></span>\n <a [href]=\"archivo.url\" target=\"_blank\" rel=\"noopener\" title=\"Abrir en nueva pestana\">\n <td-icon nombre=\"visibility\" />\n </a>\n @if (archivo.descargable !== false) {\n <a [href]=\"archivo.url\" [download]=\"archivo.nombre\" target=\"_blank\" rel=\"noopener\" title=\"Descargar\">\n <td-icon nombre=\"download\" />\n </a>\n }\n <button type=\"button\" title=\"Cerrar\" aria-label=\"Cerrar\" (click)=\"cerrar()\">\n <td-icon nombre=\"close\" />\n </button>\n </nav>\n </header>\n\n <div class=\"td-file-viewer-modal__workspace\">\n <main class=\"td-file-viewer-modal__canvas\">\n @if (esImagen(archivo)) {\n <img\n class=\"td-file-viewer-modal__image\"\n [src]=\"archivo.url\"\n [alt]=\"archivo.nombre\"\n [style.transform]=\"'scale(' + zoom + ') rotate(' + rotacion + 'deg)'\"\n />\n } @else if (esPdf(archivo)) {\n <section class=\"td-file-viewer-modal__pdf-shell\">\n <div class=\"td-file-viewer-modal__pdf-head\">\n <span>\n <td-icon nombre=\"pdf\" />\n Vista PDF\n </span>\n <div class=\"td-file-viewer-modal__pdf-pages\">\n <button type=\"button\" title=\"Pagina anterior\" [disabled]=\"pdfPaginaActual <= 1 || pdfCargando\" (click)=\"paginaPdfAnterior()\">\n <td-icon nombre=\"chevron_left\" />\n </button>\n <small>\n Pagina {{ pdfPaginaActual }} de {{ pdfTotalPaginas || '-' }}\n </small>\n <button type=\"button\" title=\"Pagina siguiente\" [disabled]=\"!pdfTotalPaginas || pdfPaginaActual >= pdfTotalPaginas || pdfCargando\" (click)=\"paginaPdfSiguiente()\">\n <td-icon nombre=\"chevron_right\" />\n </button>\n </div>\n </div>\n <div class=\"td-file-viewer-modal__pdf-canvas-wrap\">\n <canvas #pdfCanvas class=\"td-file-viewer-modal__pdf-canvas\"></canvas>\n\n @if (pdfCargando) {\n <div class=\"td-file-viewer-modal__pdf-state\">\n <span class=\"td-file-viewer-modal__spinner\"></span>\n <strong>Cargando PDF</strong>\n <small>Preparando pagina {{ pdfPaginaActual }}...</small>\n </div>\n }\n\n @if (pdfError) {\n <div class=\"td-file-viewer-modal__pdf-state td-file-viewer-modal__pdf-state--error\">\n <td-icon nombre=\"alert\" tamano=\"2rem\" />\n <strong>{{ pdfError }}</strong>\n <small>Prueba abrirlo en una nueva pesta\u00F1a o descargarlo.</small>\n </div>\n }\n </div>\n </section>\n } @else {\n <div class=\"td-file-viewer-modal__fallback\">\n <span class=\"td-file-viewer-modal__fallback-icon\">\n <td-icon [nombre]=\"iconoArchivo(archivo)\" tamano=\"3rem\" />\n </span>\n <h4>Vista previa no disponible</h4>\n <p>Este tipo de archivo debe abrirse o descargarse con una aplicacion compatible.</p>\n <a [href]=\"archivo.url\" target=\"_blank\" rel=\"noopener\">\n Abrir archivo\n </a>\n </div>\n }\n </main>\n\n @if (archivos.length > 1) {\n <footer class=\"td-file-viewer-modal__strip\">\n @for (item of archivos; track item.id) {\n <button\n type=\"button\"\n [class.td-file-viewer-modal__thumb--active]=\"item.id === archivo.id\"\n [title]=\"item.nombre\"\n (click)=\"abrir(item)\"\n >\n @if (tipoArchivo(item) === 'imagen') {\n <img [src]=\"item.thumbnailUrl || item.url\" [alt]=\"item.nombre\" loading=\"lazy\" />\n } @else {\n <td-icon [nombre]=\"iconoArchivo(item)\" />\n }\n @if (!tieneVistaPrevia(item)) {\n <span class=\"td-file-viewer-modal__no-preview\">Sin preview</span>\n }\n </button>\n }\n </footer>\n }\n </div>\n </section>\n </dialog>\n}\n", styles: [":host{display:block}*{box-sizing:border-box}.td-file-viewer{--fondo: var(--td-color-surface, #fff);--fondo-suave: var(--td-color-surface-soft, #f8fafc);--fondo-mudo: var(--td-color-surface-muted, #eef2f7);--borde: var(--td-color-border, #e4e8f0);--texto: var(--td-color-text, #263147);--suave: var(--td-color-text-muted, #748096);--acento: var(--td-color-primary, #5746d8);display:grid;gap:1rem;color:var(--texto);font-family:var(--td-font-family, Inter, ui-sans-serif, system-ui, sans-serif)}.td-file-viewer--dark{--fondo: var(--td-color-surface, #15151b);--fondo-suave: var(--td-color-surface-soft, #1b1b22);--fondo-mudo: var(--td-color-surface-muted, #202028);--borde: var(--td-color-border, #2d2d36);--texto: var(--td-color-text, #ededf0);--suave: var(--td-color-text-muted, #9393a0);--acento: var(--td-color-primary, #a89cf7)}.td-file-viewer__header{display:flex;align-items:flex-end;justify-content:space-between;gap:1rem}.td-file-viewer__header span,.td-file-viewer-modal__badge,.td-file-viewer-modal__details>span{color:var(--acento);font-size:.66rem;font-weight:850;letter-spacing:.11em;text-transform:uppercase}.td-file-viewer__header h3,.td-file-viewer__header p,.td-file-viewer-modal h3,.td-file-viewer-modal p,.td-file-viewer-modal h4{margin:0}.td-file-viewer__header h3{margin-top:.18rem;font-size:1rem}.td-file-viewer__header p{margin-top:.25rem;color:var(--suave);font-size:.76rem;line-height:1.45}.td-file-viewer__grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(15rem,1fr));gap:.75rem}.td-file-viewer--compact .td-file-viewer__grid{grid-template-columns:1fr}.td-file-viewer__item{display:grid;grid-template-columns:3.25rem minmax(0,1fr) auto;align-items:center;gap:.75rem;border:1px solid var(--borde);border-radius:var(--td-radius-lg, 1rem);padding:.72rem;color:inherit;background:linear-gradient(135deg,var(--fondo),var(--fondo-suave));box-shadow:var(--td-shadow-xs, 0 6px 18px rgba(31, 42, 68, .06));text-align:left;cursor:pointer;transition:border-color .14s ease,box-shadow .14s ease,transform .14s ease}.td-file-viewer__item:hover{border-color:var(--acento);box-shadow:var(--td-shadow-sm, 0 12px 28px rgba(31, 42, 68, .1));transform:translateY(-1px)}.td-file-viewer__preview{display:grid;width:3.25rem;height:3.25rem;place-items:center;overflow:hidden;border-radius:var(--td-radius-md, .85rem);color:var(--acento);background:color-mix(in srgb,var(--acento) 10%,var(--fondo-suave))}.td-file-viewer__preview img{width:100%;height:100%;object-fit:cover}.td-file-viewer__meta{display:grid;min-width:0;gap:.15rem}.td-file-viewer__meta strong,.td-file-viewer__meta small{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.td-file-viewer__meta strong{font-size:.8rem}.td-file-viewer__meta small,.td-file-viewer__meta em{color:var(--suave);font-size:.7rem;font-style:normal}.td-file-viewer__download{display:grid;width:2rem;height:2rem;place-items:center;border-radius:var(--td-radius-sm, .55rem);color:var(--suave)}.td-file-viewer__download:hover{color:var(--acento);background:var(--fondo-suave)}.td-file-viewer__empty{display:grid;min-height:12rem;place-items:center;align-content:center;gap:.35rem;border:1px dashed var(--borde);border-radius:var(--td-radius-lg, 1rem);color:var(--suave);background:var(--fondo-suave);text-align:center}.td-file-viewer__empty strong{color:var(--texto)}.td-file-viewer-modal{width:min(900px,100vw - 2rem);max-width:none;max-height:min(82dvh,720px);border:0;padding:0;overflow:visible;color:var(--td-color-text, #263147);background:transparent;font-family:var(--td-font-family, Inter, ui-sans-serif, system-ui, sans-serif)}.td-file-viewer-modal::backdrop{background:#0a101e80;-webkit-backdrop-filter:blur(7px);backdrop-filter:blur(7px)}.td-file-viewer-modal__panel{display:grid;grid-template-rows:auto minmax(0,1fr);width:100%;max-height:min(82dvh,720px);overflow:hidden;border:1px solid var(--td-color-border, #e4e8f0);border-radius:var(--td-radius-xl, 1.15rem);background:var(--td-color-surface, #fff);box-shadow:var(--td-shadow-xl, 0 24px 72px rgba(15, 23, 42, .28))}.td-file-viewer-modal--dark .td-file-viewer-modal__panel{border-color:var(--td-color-border, #2d2d36);background:var(--td-color-surface, #15151b)}.td-file-viewer-modal__topbar{display:flex;align-items:center;justify-content:space-between;gap:1rem;border-bottom:1px solid var(--td-color-border, #e4e8f0);padding:.75rem .9rem;background:var(--td-color-surface, #fff)}.td-file-viewer-modal__title{display:grid;min-width:0;gap:.12rem}.td-file-viewer-modal__badge{display:inline-flex;width:fit-content;align-items:center;gap:.35rem;color:var(--td-color-primary, #5746d8);font-size:.64rem;font-weight:850;letter-spacing:.1em;text-transform:uppercase}.td-file-viewer-modal h3,.td-file-viewer-modal h4,.td-file-viewer-modal p{margin:0}.td-file-viewer-modal__title h3{overflow:hidden;color:var(--td-color-text, #263147);font-size:.9rem;text-overflow:ellipsis;white-space:nowrap}.td-file-viewer-modal__title p{overflow:hidden;color:var(--td-color-text-muted, #748096);font-size:.7rem;text-overflow:ellipsis;white-space:nowrap}.td-file-viewer-modal__toolbar{display:flex;flex:0 0 auto;align-items:center;gap:.3rem}.td-file-viewer-modal__toolbar button,.td-file-viewer-modal__toolbar a{display:inline-grid;min-width:2rem;height:2rem;place-items:center;border:0;border-radius:var(--td-radius-sm, .55rem);color:var(--td-color-text-muted, #748096);background:var(--td-color-surface-soft, #f8fafc);text-decoration:none;cursor:pointer}.td-file-viewer-modal__toolbar button:hover,.td-file-viewer-modal__toolbar a:hover{color:var(--td-color-primary, #5746d8)}.td-file-viewer-modal__toolbar button:disabled{opacity:.38;cursor:not-allowed}.td-file-viewer-modal__zoom{min-width:3rem!important;padding-inline:.45rem;color:var(--td-color-text, #263147)!important;font-size:.7rem;font-weight:800}.td-file-viewer-modal__text-action{width:auto!important;min-width:3.2rem!important;padding-inline:.55rem;color:var(--td-color-text, #263147)!important;font-size:.7rem;font-weight:800}.td-file-viewer-modal__divider{width:1px;height:1.25rem;margin-inline:.2rem;background:var(--td-color-border, #e4e8f0)}.td-file-viewer-modal__workspace{display:grid;grid-template-rows:minmax(0,1fr) auto;min-height:0;background:var(--td-color-surface-soft, #f8fafc)}.td-file-viewer-modal__canvas{display:grid;min-height:20rem;max-height:calc(82dvh - 8rem);place-items:center;overflow:auto;padding:1rem;background:linear-gradient(180deg,var(--td-color-surface-soft, #f8fafc),var(--td-color-surface, #fff))}.td-file-viewer-modal__image{display:block;width:auto;max-width:100%;max-height:min(58dvh,500px);border-radius:var(--td-radius-lg, 1rem);object-fit:contain;box-shadow:var(--td-shadow-md, 0 16px 42px rgba(15, 23, 42, .16));transition:transform .12s ease}.td-file-viewer-modal__pdf-shell{display:grid;grid-template-rows:auto minmax(0,1fr);width:min(820px,100%);height:min(60dvh,560px);overflow:hidden;border:1px solid var(--td-color-border, #e4e8f0);border-radius:var(--td-radius-lg, 1rem);background:var(--td-color-surface, #fff)}.td-file-viewer-modal__pdf-head{display:flex;align-items:center;justify-content:space-between;gap:1rem;border-bottom:1px solid var(--td-color-border, #e4e8f0);padding:.55rem .65rem .55rem .75rem}.td-file-viewer-modal__pdf-head span{display:inline-flex;align-items:center;gap:.4rem;font-size:.75rem;font-weight:850}.td-file-viewer-modal__pdf-head small{color:var(--td-color-text-muted, #748096);font-size:.65rem}.td-file-viewer-modal__pdf-pages{display:inline-flex;align-items:center;gap:.35rem}.td-file-viewer-modal__pdf-pages button{display:inline-grid;width:1.8rem;height:1.8rem;place-items:center;border:0;border-radius:var(--td-radius-sm, .5rem);color:var(--td-color-text-muted, #748096);background:var(--td-color-surface-soft, #f8fafc);cursor:pointer}.td-file-viewer-modal__pdf-pages button:hover:not(:disabled){color:var(--td-color-primary, #5746d8)}.td-file-viewer-modal__pdf-pages button:disabled{opacity:.38;cursor:not-allowed}.td-file-viewer-modal__pdf-canvas-wrap{position:relative;display:grid;min-height:0;overflow:auto;place-items:start center;padding:1rem;background:radial-gradient(circle at 1px 1px,rgba(100,116,139,.18) 1px,transparent 0) 0 0/18px 18px,var(--td-color-surface-muted, #eef2f7)}.td-file-viewer-modal__pdf-canvas{display:block;max-width:none;border-radius:var(--td-radius-sm, .45rem);background:#fff;box-shadow:var(--td-shadow-md, 0 16px 42px rgba(15, 23, 42, .2))}.td-file-viewer-modal__pdf-state{position:absolute;inset:0;display:grid;place-items:center;align-content:center;gap:.35rem;color:var(--td-color-text-muted, #748096);background:color-mix(in srgb,var(--td-color-surface, #fff) 78%,transparent);text-align:center}.td-file-viewer-modal__pdf-state strong{color:var(--td-color-text, #263147);font-size:.85rem}.td-file-viewer-modal__pdf-state--error{color:var(--td-color-danger, #dc2626);background:color-mix(in srgb,var(--td-color-surface, #fff) 92%,transparent)}.td-file-viewer-modal__spinner{display:block;width:2rem;height:2rem;border:3px solid color-mix(in srgb,var(--td-color-primary, #5746d8) 18%,transparent);border-top-color:var(--td-color-primary, #5746d8);border-radius:999px;animation:td-file-viewer-spin .8s linear infinite}@keyframes td-file-viewer-spin{to{transform:rotate(360deg)}}.td-file-viewer-modal__strip{display:flex;gap:.45rem;overflow-x:auto;border-top:1px solid var(--td-color-border, #e4e8f0);padding:.65rem .75rem;background:var(--td-color-surface, #fff)}.td-file-viewer-modal__strip button{position:relative;display:grid;width:2.4rem;height:2.4rem;flex:0 0 auto;place-items:center;overflow:hidden;border:1px solid var(--td-color-border, #e4e8f0);border-radius:var(--td-radius-sm, .6rem);color:var(--td-color-text-muted, #748096);background:var(--td-color-surface-soft, #f8fafc);cursor:pointer}.td-file-viewer-modal__strip img{width:100%;height:100%;object-fit:cover}.td-file-viewer-modal__thumb--active{border-color:var(--td-color-primary, #5746d8)!important;box-shadow:var(--td-focus-ring, 0 0 0 3px color-mix(in srgb, var(--td-color-primary, #5746d8) 15%, transparent))}.td-file-viewer-modal__no-preview{position:absolute;right:.12rem;bottom:.12rem;border-radius:var(--td-radius-pill, 999px);padding:.05rem .22rem;color:var(--td-color-text-muted, #748096);background:var(--td-color-surface, #fff);font-size:.46rem;font-weight:850;line-height:1.2}.td-file-viewer-modal__fallback{display:grid;place-items:center;align-content:center;gap:.7rem;color:var(--td-color-text-muted, #748096);text-align:center}.td-file-viewer-modal__fallback-icon{display:grid;width:4.5rem;height:4.5rem;place-items:center;border-radius:var(--td-radius-xl, 1.25rem);color:var(--td-color-primary, #5746d8);background:color-mix(in srgb,var(--td-color-primary, #5746d8) 10%,transparent)}.td-file-viewer-modal__fallback h4{color:var(--td-color-text, #263147)}.td-file-viewer-modal__fallback a{display:inline-flex;min-height:2.25rem;align-items:center;border-radius:var(--td-radius-md, .75rem);padding:0 .9rem;color:var(--td-color-on-primary, #fff);background:var(--td-color-primary, #5746d8);font-size:.75rem;font-weight:800;text-decoration:none}@media(max-width:640px){.td-file-viewer-modal{width:calc(100vw - 1.5rem);max-height:calc(100dvh - 1.5rem)}.td-file-viewer-modal__panel{max-height:calc(100dvh - 1.5rem)}.td-file-viewer-modal__topbar{align-items:flex-start;flex-direction:column}.td-file-viewer-modal__toolbar{width:100%;overflow-x:auto}.td-file-viewer-modal__canvas{min-height:16rem;max-height:calc(100dvh - 11rem);padding:.75rem}.td-file-viewer-modal__image,.td-file-viewer-modal__pdf-shell{max-height:calc(100dvh - 13rem)}}\n"], dependencies: [{ kind: "component", type: TdIcon, selector: "td-icon", inputs: ["nombre", "titulo", "tamano"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
2781
2992
  }
@@ -3862,111 +4073,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.4", ngImpor
3862
4073
  type: Input
3863
4074
  }], value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }] } });
3864
4075
 
3865
- class TdMenu {
3866
- items = [];
3867
- etiqueta = '';
3868
- icono = 'more_vertical';
3869
- posicion = 'abajo-fin';
3870
- ancho = '14rem';
3871
- disabled = false;
3872
- oscuro = false;
3873
- ariaLabel = 'Abrir menu';
3874
- seleccion = new EventEmitter();
3875
- abiertoChange = new EventEmitter();
3876
- abierto = false;
3877
- get itemsVisibles() {
3878
- return this.items.filter((item) => item.visible ?? true);
3879
- }
3880
- alternar() {
3881
- if (this.disabled)
3882
- return;
3883
- this.establecerAbierto(!this.abierto);
3884
- }
3885
- cerrar() {
3886
- this.establecerAbierto(false);
3887
- }
3888
- seleccionar(item) {
3889
- if (item.deshabilitado)
3890
- return;
3891
- this.seleccion.emit({ item, id: item.id, data: item.data });
3892
- this.cerrar();
3893
- }
3894
- posiciones() {
3895
- const offset = 8;
3896
- const mapa = {
3897
- 'abajo-inicio': [
3898
- {
3899
- originX: 'start',
3900
- originY: 'bottom',
3901
- overlayX: 'start',
3902
- overlayY: 'top',
3903
- offsetY: offset,
3904
- },
3905
- ],
3906
- 'abajo-fin': [
3907
- {
3908
- originX: 'end',
3909
- originY: 'bottom',
3910
- overlayX: 'end',
3911
- overlayY: 'top',
3912
- offsetY: offset,
3913
- },
3914
- ],
3915
- 'arriba-inicio': [
3916
- {
3917
- originX: 'start',
3918
- originY: 'top',
3919
- overlayX: 'start',
3920
- overlayY: 'bottom',
3921
- offsetY: -offset,
3922
- },
3923
- ],
3924
- 'arriba-fin': [
3925
- {
3926
- originX: 'end',
3927
- originY: 'top',
3928
- overlayX: 'end',
3929
- overlayY: 'bottom',
3930
- offsetY: -offset,
3931
- },
3932
- ],
3933
- };
3934
- return mapa[this.posicion];
3935
- }
3936
- establecerAbierto(valor) {
3937
- if (this.abierto === valor)
3938
- return;
3939
- this.abierto = valor;
3940
- this.abiertoChange.emit(valor);
3941
- }
3942
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: TdMenu, deps: [], target: i0.ɵɵFactoryTarget.Component });
3943
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.4", type: TdMenu, isStandalone: true, selector: "td-menu", inputs: { items: "items", etiqueta: "etiqueta", icono: "icono", posicion: "posicion", ancho: "ancho", disabled: "disabled", oscuro: "oscuro", ariaLabel: "ariaLabel" }, outputs: { seleccion: "seleccion", abiertoChange: "abiertoChange" }, ngImport: i0, template: "<button\n #origen=\"cdkOverlayOrigin\"\n cdkOverlayOrigin\n type=\"button\"\n class=\"td-menu__trigger\"\n [class.td-menu__trigger--icon-only]=\"!etiqueta\"\n [disabled]=\"disabled\"\n [attr.aria-label]=\"ariaLabel\"\n [attr.aria-expanded]=\"abierto\"\n aria-haspopup=\"menu\"\n (click)=\"alternar()\"\n>\n @if (icono) {\n <td-icon [nombre]=\"icono\" />\n }\n @if (etiqueta) {\n <span>{{ etiqueta }}</span>\n <td-icon nombre=\"chevron_down\" tamano=\".95rem\" />\n }\n</button>\n\n<ng-template\n cdkConnectedOverlay\n [cdkConnectedOverlayOrigin]=\"origen\"\n [cdkConnectedOverlayOpen]=\"abierto\"\n [cdkConnectedOverlayPositions]=\"posiciones()\"\n [cdkConnectedOverlayHasBackdrop]=\"true\"\n [cdkConnectedOverlayBackdropClass]=\"'td-menu__backdrop'\"\n [cdkConnectedOverlayPanelClass]=\"'td-menu__overlay'\"\n (backdropClick)=\"cerrar()\"\n (detach)=\"cerrar()\"\n>\n <div\n class=\"td-menu\"\n [class.td-menu--oscuro]=\"oscuro\"\n [style.width]=\"ancho\"\n role=\"menu\"\n >\n @for (item of itemsVisibles; track item.id) {\n @if (item.separadorAntes) {\n <span class=\"td-menu__separador\" aria-hidden=\"true\"></span>\n }\n <button\n type=\"button\"\n role=\"menuitem\"\n [class]=\"'td-menu__item td-menu__item--' + (item.tono || 'neutro')\"\n [disabled]=\"item.deshabilitado\"\n (click)=\"seleccionar(item)\"\n >\n @if (item.icono) {\n <span class=\"td-menu__icono\">\n <td-icon [nombre]=\"item.icono\" />\n </span>\n }\n <span class=\"td-menu__texto\">\n <strong>{{ item.etiqueta }}</strong>\n @if (item.descripcion) {\n <small>{{ item.descripcion }}</small>\n }\n </span>\n </button>\n } @empty {\n <div class=\"td-menu__vacio\">\n <td-icon nombre=\"inbox\" />\n <span>Sin opciones disponibles</span>\n </div>\n }\n </div>\n</ng-template>\n", styles: [":host{display:inline-block;font-family:var(--td-font-family, Inter, ui-sans-serif, system-ui, sans-serif)}*{box-sizing:border-box}.td-menu__trigger{display:inline-flex;min-height:2.35rem;align-items:center;justify-content:center;gap:.45rem;border:1px solid var(--td-color-border, #d9e1ee);border-radius:var(--td-radius-md, .85rem);padding:0 .8rem;color:var(--td-color-text, #202b3d);background:var(--td-color-surface, #fff);box-shadow:var(--td-shadow-xs, 0 6px 16px rgba(31, 42, 68, .06));font:inherit;font-size:.78rem;font-weight:800;cursor:pointer;transition:border-color .14s ease,color .14s ease,box-shadow .14s ease,transform .14s ease}.td-menu__trigger:hover:not(:disabled),.td-menu__trigger[aria-expanded=true]{border-color:var(--td-color-primary, #5746d8);color:var(--td-color-primary, #5746d8);box-shadow:var(--td-focus-ring, 0 0 0 3px rgba(87, 70, 216, .14))}.td-menu__trigger:disabled{opacity:.55;cursor:not-allowed}.td-menu__trigger--icon-only{width:2.35rem;padding:0}.td-menu{overflow:hidden;border:1px solid var(--td-color-border, #d9e1ee);border-radius:var(--td-radius-lg, 1rem);padding:.35rem;color:var(--td-color-text, #202b3d);background:var(--td-color-surface, #fff);box-shadow:var(--td-shadow-lg, 0 22px 52px rgba(15, 23, 42, .18));font-family:var(--td-font-family, Inter, ui-sans-serif, system-ui, sans-serif)}.td-menu--oscuro{border-color:var(--td-color-border, #2d3342);color:var(--td-color-text, #f8fafc);background:var(--td-color-surface, #111827)}.td-menu__item{display:grid;width:100%;grid-template-columns:auto minmax(0,1fr);align-items:center;gap:.65rem;border:0;border-radius:var(--td-radius-md, .75rem);padding:.62rem .7rem;color:inherit;background:transparent;font:inherit;text-align:left;cursor:pointer}.td-menu__item:hover:not(:disabled),.td-menu__item:focus-visible{outline:none;background:var(--td-color-primary-soft, #eef2ff)}.td-menu__item:disabled{opacity:.45;cursor:not-allowed}.td-menu__item--primario{color:var(--td-color-primary, #5746d8)}.td-menu__item--exito{color:var(--td-color-success, #07845c)}.td-menu__item--advertencia{color:var(--td-color-warning, #b7791f)}.td-menu__item--peligro{color:var(--td-color-danger, #dc2626)}.td-menu__icono{display:grid;width:2rem;height:2rem;place-items:center;border-radius:var(--td-radius-sm, .6rem);background:color-mix(in srgb,currentColor 10%,transparent)}.td-menu__texto{display:grid;min-width:0;gap:.12rem}.td-menu__texto strong,.td-menu__texto small{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.td-menu__texto strong{font-size:.78rem}.td-menu__texto small{color:var(--td-color-text-muted, #64748b);font-size:.68rem;font-weight:650}.td-menu__separador{display:block;height:1px;margin:.35rem .45rem;background:var(--td-color-border, #d9e1ee)}.td-menu__vacio{display:grid;min-height:5.5rem;place-items:center;align-content:center;gap:.35rem;color:var(--td-color-text-muted, #64748b);font-size:.75rem;font-weight:750}\n"], dependencies: [{ kind: "directive", type: CdkConnectedOverlay, selector: "[cdk-connected-overlay], [connected-overlay], [cdkConnectedOverlay]", inputs: ["cdkConnectedOverlayOrigin", "cdkConnectedOverlayPositions", "cdkConnectedOverlayPositionStrategy", "cdkConnectedOverlayOffsetX", "cdkConnectedOverlayOffsetY", "cdkConnectedOverlayWidth", "cdkConnectedOverlayHeight", "cdkConnectedOverlayMinWidth", "cdkConnectedOverlayMinHeight", "cdkConnectedOverlayBackdropClass", "cdkConnectedOverlayPanelClass", "cdkConnectedOverlayViewportMargin", "cdkConnectedOverlayScrollStrategy", "cdkConnectedOverlayOpen", "cdkConnectedOverlayDisableClose", "cdkConnectedOverlayTransformOriginOn", "cdkConnectedOverlayHasBackdrop", "cdkConnectedOverlayLockPosition", "cdkConnectedOverlayFlexibleDimensions", "cdkConnectedOverlayGrowAfterOpen", "cdkConnectedOverlayPush", "cdkConnectedOverlayDisposeOnNavigation", "cdkConnectedOverlayUsePopover", "cdkConnectedOverlayMatchWidth", "cdkConnectedOverlay"], outputs: ["backdropClick", "positionChange", "attach", "detach", "overlayKeydown", "overlayOutsideClick"], exportAs: ["cdkConnectedOverlay"] }, { kind: "directive", type: CdkOverlayOrigin, selector: "[cdk-overlay-origin], [overlay-origin], [cdkOverlayOrigin]", exportAs: ["cdkOverlayOrigin"] }, { kind: "component", type: TdIcon, selector: "td-icon", inputs: ["nombre", "titulo", "tamano"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
3944
- }
3945
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: TdMenu, decorators: [{
3946
- type: Component,
3947
- args: [{ selector: 'td-menu', imports: [CdkConnectedOverlay, CdkOverlayOrigin, TdIcon], changeDetection: ChangeDetectionStrategy.OnPush, template: "<button\n #origen=\"cdkOverlayOrigin\"\n cdkOverlayOrigin\n type=\"button\"\n class=\"td-menu__trigger\"\n [class.td-menu__trigger--icon-only]=\"!etiqueta\"\n [disabled]=\"disabled\"\n [attr.aria-label]=\"ariaLabel\"\n [attr.aria-expanded]=\"abierto\"\n aria-haspopup=\"menu\"\n (click)=\"alternar()\"\n>\n @if (icono) {\n <td-icon [nombre]=\"icono\" />\n }\n @if (etiqueta) {\n <span>{{ etiqueta }}</span>\n <td-icon nombre=\"chevron_down\" tamano=\".95rem\" />\n }\n</button>\n\n<ng-template\n cdkConnectedOverlay\n [cdkConnectedOverlayOrigin]=\"origen\"\n [cdkConnectedOverlayOpen]=\"abierto\"\n [cdkConnectedOverlayPositions]=\"posiciones()\"\n [cdkConnectedOverlayHasBackdrop]=\"true\"\n [cdkConnectedOverlayBackdropClass]=\"'td-menu__backdrop'\"\n [cdkConnectedOverlayPanelClass]=\"'td-menu__overlay'\"\n (backdropClick)=\"cerrar()\"\n (detach)=\"cerrar()\"\n>\n <div\n class=\"td-menu\"\n [class.td-menu--oscuro]=\"oscuro\"\n [style.width]=\"ancho\"\n role=\"menu\"\n >\n @for (item of itemsVisibles; track item.id) {\n @if (item.separadorAntes) {\n <span class=\"td-menu__separador\" aria-hidden=\"true\"></span>\n }\n <button\n type=\"button\"\n role=\"menuitem\"\n [class]=\"'td-menu__item td-menu__item--' + (item.tono || 'neutro')\"\n [disabled]=\"item.deshabilitado\"\n (click)=\"seleccionar(item)\"\n >\n @if (item.icono) {\n <span class=\"td-menu__icono\">\n <td-icon [nombre]=\"item.icono\" />\n </span>\n }\n <span class=\"td-menu__texto\">\n <strong>{{ item.etiqueta }}</strong>\n @if (item.descripcion) {\n <small>{{ item.descripcion }}</small>\n }\n </span>\n </button>\n } @empty {\n <div class=\"td-menu__vacio\">\n <td-icon nombre=\"inbox\" />\n <span>Sin opciones disponibles</span>\n </div>\n }\n </div>\n</ng-template>\n", styles: [":host{display:inline-block;font-family:var(--td-font-family, Inter, ui-sans-serif, system-ui, sans-serif)}*{box-sizing:border-box}.td-menu__trigger{display:inline-flex;min-height:2.35rem;align-items:center;justify-content:center;gap:.45rem;border:1px solid var(--td-color-border, #d9e1ee);border-radius:var(--td-radius-md, .85rem);padding:0 .8rem;color:var(--td-color-text, #202b3d);background:var(--td-color-surface, #fff);box-shadow:var(--td-shadow-xs, 0 6px 16px rgba(31, 42, 68, .06));font:inherit;font-size:.78rem;font-weight:800;cursor:pointer;transition:border-color .14s ease,color .14s ease,box-shadow .14s ease,transform .14s ease}.td-menu__trigger:hover:not(:disabled),.td-menu__trigger[aria-expanded=true]{border-color:var(--td-color-primary, #5746d8);color:var(--td-color-primary, #5746d8);box-shadow:var(--td-focus-ring, 0 0 0 3px rgba(87, 70, 216, .14))}.td-menu__trigger:disabled{opacity:.55;cursor:not-allowed}.td-menu__trigger--icon-only{width:2.35rem;padding:0}.td-menu{overflow:hidden;border:1px solid var(--td-color-border, #d9e1ee);border-radius:var(--td-radius-lg, 1rem);padding:.35rem;color:var(--td-color-text, #202b3d);background:var(--td-color-surface, #fff);box-shadow:var(--td-shadow-lg, 0 22px 52px rgba(15, 23, 42, .18));font-family:var(--td-font-family, Inter, ui-sans-serif, system-ui, sans-serif)}.td-menu--oscuro{border-color:var(--td-color-border, #2d3342);color:var(--td-color-text, #f8fafc);background:var(--td-color-surface, #111827)}.td-menu__item{display:grid;width:100%;grid-template-columns:auto minmax(0,1fr);align-items:center;gap:.65rem;border:0;border-radius:var(--td-radius-md, .75rem);padding:.62rem .7rem;color:inherit;background:transparent;font:inherit;text-align:left;cursor:pointer}.td-menu__item:hover:not(:disabled),.td-menu__item:focus-visible{outline:none;background:var(--td-color-primary-soft, #eef2ff)}.td-menu__item:disabled{opacity:.45;cursor:not-allowed}.td-menu__item--primario{color:var(--td-color-primary, #5746d8)}.td-menu__item--exito{color:var(--td-color-success, #07845c)}.td-menu__item--advertencia{color:var(--td-color-warning, #b7791f)}.td-menu__item--peligro{color:var(--td-color-danger, #dc2626)}.td-menu__icono{display:grid;width:2rem;height:2rem;place-items:center;border-radius:var(--td-radius-sm, .6rem);background:color-mix(in srgb,currentColor 10%,transparent)}.td-menu__texto{display:grid;min-width:0;gap:.12rem}.td-menu__texto strong,.td-menu__texto small{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.td-menu__texto strong{font-size:.78rem}.td-menu__texto small{color:var(--td-color-text-muted, #64748b);font-size:.68rem;font-weight:650}.td-menu__separador{display:block;height:1px;margin:.35rem .45rem;background:var(--td-color-border, #d9e1ee)}.td-menu__vacio{display:grid;min-height:5.5rem;place-items:center;align-content:center;gap:.35rem;color:var(--td-color-text-muted, #64748b);font-size:.75rem;font-weight:750}\n"] }]
3948
- }], propDecorators: { items: [{
3949
- type: Input
3950
- }], etiqueta: [{
3951
- type: Input
3952
- }], icono: [{
3953
- type: Input
3954
- }], posicion: [{
3955
- type: Input
3956
- }], ancho: [{
3957
- type: Input
3958
- }], disabled: [{
3959
- type: Input
3960
- }], oscuro: [{
3961
- type: Input
3962
- }], ariaLabel: [{
3963
- type: Input
3964
- }], seleccion: [{
3965
- type: Output
3966
- }], abiertoChange: [{
3967
- type: Output
3968
- }] } });
3969
-
3970
4076
  let autocompleteSequence = 0;
3971
4077
  class TdAutocompleteSelect {
3972
4078
  cdr = inject(ChangeDetectorRef);