ngx-dsxlibrary 2.21.67 → 2.21.69

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.
@@ -1,11 +1,11 @@
1
1
  import * as i0 from '@angular/core';
2
- import { input, forwardRef, Component, EventEmitter, effect, Output, viewChild, signal, Input, model, inject, computed, Injectable, isDevMode, InjectionToken, output, HostBinding, ChangeDetectorRef, untracked, Pipe, ViewEncapsulation, HostListener, Directive, NgZone, ElementRef, NgModule, Injector } from '@angular/core';
2
+ import { input, forwardRef, Component, EventEmitter, effect, Output, viewChild, signal, Input, model, inject, computed, Injectable, isDevMode, InjectionToken, output, HostBinding, ChangeDetectorRef, untracked, Pipe, ViewEncapsulation, HostListener, Directive, NgZone, ElementRef, ChangeDetectionStrategy, NgModule, Injector, ViewChild } from '@angular/core';
3
3
  import * as i1 from '@angular/forms';
4
- import { FormsModule, NG_VALUE_ACCESSOR, FormControl, NG_VALIDATORS, FormBuilder, Validators, ReactiveFormsModule, NgControl, FormGroup } from '@angular/forms';
4
+ import { FormsModule, NG_VALUE_ACCESSOR, AbstractControl, FormControl, NG_VALIDATORS, FormBuilder, Validators, ReactiveFormsModule, NgControl, FormGroup } from '@angular/forms';
5
5
  import * as i2 from 'primeng/togglebutton';
6
6
  import { ToggleButtonModule } from 'primeng/togglebutton';
7
7
  import * as i1$1 from '@angular/common';
8
- import { CommonModule, AsyncPipe, DecimalPipe, Location } from '@angular/common';
8
+ import { CommonModule, AsyncPipe, DecimalPipe, Location, JsonPipe } from '@angular/common';
9
9
  import * as i2$1 from 'primeng/tree';
10
10
  import { TreeModule } from 'primeng/tree';
11
11
  import * as i3 from 'primeng/api';
@@ -54,14 +54,14 @@ import { CardModule } from 'primeng/card';
54
54
  import { CheckboxModule } from 'primeng/checkbox';
55
55
  import { ContextMenuModule } from 'primeng/contextmenu';
56
56
  import { DataViewModule } from 'primeng/dataview';
57
- import { DatePickerModule } from 'primeng/datepicker';
57
+ import { DatePickerModule, DatePicker } from 'primeng/datepicker';
58
58
  import { DividerModule } from 'primeng/divider';
59
59
  import { DrawerModule } from 'primeng/drawer';
60
60
  import { FieldsetModule } from 'primeng/fieldset';
61
61
  import { IconFieldModule } from 'primeng/iconfield';
62
62
  import { InputIconModule } from 'primeng/inputicon';
63
63
  import { InputMaskModule } from 'primeng/inputmask';
64
- import { InputNumberModule } from 'primeng/inputnumber';
64
+ import { InputNumberModule, InputNumber } from 'primeng/inputnumber';
65
65
  import { InputTextModule } from 'primeng/inputtext';
66
66
  import { KeyFilterModule } from 'primeng/keyfilter';
67
67
  import { KnobModule } from 'primeng/knob';
@@ -1079,7 +1079,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImpo
1079
1079
  args: [{ selector: 'icon-dsx', imports: [AsyncPipe], template: "<span class=\"dsx-icon\" [innerHTML]=\"svg$ | async\"></span>\r\n", styles: [":host{display:inline-flex;align-items:center;justify-content:center;vertical-align:middle;width:1em;height:1em;font-size:24px;line-height:1;flex-shrink:0}.dsx-icon{display:inline-flex;align-items:center;justify-content:center;width:100%;height:100%}:host ::ng-deep .dsx-icon svg{width:100%;height:100%;fill:currentColor;shape-rendering:geometricPrecision;stroke:currentColor;stroke-width:4px;stroke-linejoin:round;stroke-linecap:round;overflow:visible;transition:fill .2s ease,stroke .2s ease}\n"] }]
1080
1080
  }], ctorParameters: () => [{ type: IconDsxService }], propDecorators: { name: [{ type: i0.Input, args: [{ isSignal: true, alias: "name", required: false }] }], style: [{ type: i0.Input, args: [{ isSignal: true, alias: "style", required: false }] }], debug: [{ type: i0.Input, args: [{ isSignal: true, alias: "debug", required: false }] }] } });
1081
1081
 
1082
- // app-message-error.component.ts - Versión corregida
1082
+ // app-message-error.component.ts
1083
1083
  class AppMessageErrorComponent {
1084
1084
  elementRef;
1085
1085
  renderer;
@@ -1107,7 +1107,7 @@ class AppMessageErrorComponent {
1107
1107
  this.lastErrorsCount = nuevoControl.errors
1108
1108
  ? Object.keys(nuevoControl.errors).length
1109
1109
  : 0;
1110
- if (this.debugMode) {
1110
+ if (this.isDevelopmentMode() && this.debugMode) {
1111
1111
  console.log('[ERROR-COMPONENT] Control asignado:', {
1112
1112
  status: nuevoControl.status,
1113
1113
  errors: nuevoControl.errors,
@@ -1128,27 +1128,26 @@ class AppMessageErrorComponent {
1128
1128
  this.renderer = renderer;
1129
1129
  }
1130
1130
  ngAfterViewInit() {
1131
- // Intentar encontrar el floatLabel padre
1132
1131
  this.floatLabelElement = this.elementRef.nativeElement.closest('.p-floatlabel');
1133
1132
  if (this.floatLabelElement) {
1134
1133
  this.previousInlineMarginBottom =
1135
1134
  this.floatLabelElement.style.marginBottom;
1136
- if (this.debugMode) {
1135
+ if (this.isDevelopmentMode() && this.debugMode) {
1137
1136
  console.log('[ERROR-COMPONENT] FloatLabel encontrado, modo absoluto');
1138
1137
  }
1139
1138
  }
1140
1139
  else {
1141
- if (this.debugMode) {
1140
+ if (this.isDevelopmentMode() && this.debugMode) {
1142
1141
  console.log('[ERROR-COMPONENT] No hay FloatLabel, modo estático');
1143
1142
  }
1144
1143
  }
1145
- // Observador de visibilidad
1146
1144
  if (typeof window !== 'undefined' && 'IntersectionObserver' in window) {
1147
1145
  this.observer = new IntersectionObserver((entries) => {
1148
1146
  entries.forEach((entry) => {
1149
1147
  const wasVisible = this.isElementAttachedAndVisible;
1150
1148
  this.isElementAttachedAndVisible = entry.isIntersecting;
1151
- if (this.debugMode &&
1149
+ if (this.isDevelopmentMode() &&
1150
+ this.debugMode &&
1152
1151
  wasVisible !== this.isElementAttachedAndVisible) {
1153
1152
  console.log('[ERROR-COMPONENT] Visibilidad:', this.isElementAttachedAndVisible);
1154
1153
  }
@@ -1173,7 +1172,7 @@ class AppMessageErrorComponent {
1173
1172
  this.control.touched !== this.lastControlTouched ||
1174
1173
  this.control.dirty !== this.lastControlDirty ||
1175
1174
  currentErrorsCount !== this.lastErrorsCount) {
1176
- if (this.debugMode) {
1175
+ if (this.isDevelopmentMode() && this.debugMode) {
1177
1176
  console.log('[ERROR-COMPONENT] Cambio detectado:', {
1178
1177
  invalid: this.control.invalid,
1179
1178
  touched: this.control.touched,
@@ -1191,7 +1190,6 @@ class AppMessageErrorComponent {
1191
1190
  if (this.observer) {
1192
1191
  this.observer.disconnect();
1193
1192
  }
1194
- // Restaurar margen solo si existe floatLabelElement
1195
1193
  if (this.floatLabelElement) {
1196
1194
  if (this.previousInlineMarginBottom) {
1197
1195
  this.renderer.setStyle(this.floatLabelElement, 'margin-bottom', this.previousInlineMarginBottom);
@@ -1202,11 +1200,7 @@ class AppMessageErrorComponent {
1202
1200
  }
1203
1201
  }
1204
1202
  syncFloatLabelSpacing() {
1205
- // Si no hay floatLabel, no hacemos nada (el CSS maneja el espaciado)
1206
- if (!this.floatLabelElement) {
1207
- return;
1208
- }
1209
- if (!this.isElementAttachedAndVisible)
1203
+ if (!this.floatLabelElement || !this.isElementAttachedAndVisible)
1210
1204
  return;
1211
1205
  const isVisible = this.isControlErrorVisible();
1212
1206
  const desiredSpace = this.getFloatLabelErrorSpace();
@@ -1228,11 +1222,9 @@ class AppMessageErrorComponent {
1228
1222
  this.renderer.removeStyle(this.floatLabelElement, 'margin-bottom');
1229
1223
  }
1230
1224
  isControlErrorVisible() {
1231
- // ✅ La condición base es la misma para ambos contextos
1232
1225
  if (!this.control || !this.control.invalid) {
1233
1226
  return false;
1234
1227
  }
1235
- // Solo mostrar si el usuario ha interactuado
1236
1228
  return !!(this.control.touched || this.control.dirty);
1237
1229
  }
1238
1230
  getFloatLabelErrorSpace() {
@@ -1251,18 +1243,140 @@ class AppMessageErrorComponent {
1251
1243
  }
1252
1244
  return this.defaultFloatLabelErrorSpace;
1253
1245
  }
1254
- formatNumber(value) {
1246
+ /**
1247
+ * Obtiene el mensaje de error de un error específico del control
1248
+ * @param errorKey - La clave del error
1249
+ * @returns El mensaje de error o un string vacío
1250
+ */
1251
+ getErrorMessage(errorKey) {
1252
+ if (!this.control || !this.control.errors) {
1253
+ return '';
1254
+ }
1255
+ const error = this.control.errors[errorKey];
1256
+ if (!error) {
1257
+ return '';
1258
+ }
1259
+ if (typeof error === 'object' && error !== null && 'message' in error) {
1260
+ return error.message;
1261
+ }
1262
+ return '';
1263
+ }
1264
+ /**
1265
+ * Obtiene el valor de un error específico del control
1266
+ * @param errorKey - La clave del error
1267
+ * @param propertyKey - La propiedad del error a obtener
1268
+ * @returns El valor de la propiedad o undefined
1269
+ */
1270
+ getErrorValue(errorKey, propertyKey) {
1271
+ if (!this.control || !this.control.errors) {
1272
+ return undefined;
1273
+ }
1274
+ const error = this.control.errors[errorKey];
1275
+ if (!error || typeof error !== 'object') {
1276
+ return undefined;
1277
+ }
1278
+ return error[propertyKey];
1279
+ }
1280
+ /**
1281
+ * Obtiene los detalles de un error de template
1282
+ * @param errorKey - La clave del error (invalidTemplateVariables o invalidTemplateStructure)
1283
+ * @returns El array de detalles o un array vacío
1284
+ */
1285
+ getTemplateErrorDetails(errorKey) {
1286
+ if (!this.control || !this.control.errors) {
1287
+ return [];
1288
+ }
1289
+ const error = this.control.errors[errorKey];
1290
+ if (!error || typeof error !== 'object' || !('details' in error)) {
1291
+ return [];
1292
+ }
1293
+ const details = error.details;
1294
+ return Array.isArray(details) ? details : [];
1295
+ }
1296
+ /**
1297
+ * Obtiene el primer detalle de un error de template
1298
+ * @param errorKey - La clave del error
1299
+ * @returns El primer detalle o string vacío
1300
+ */
1301
+ getFirstTemplateErrorDetail(errorKey) {
1302
+ const details = this.getTemplateErrorDetails(errorKey);
1303
+ return details.length > 0 ? details[0] : '';
1304
+ }
1305
+ /**
1306
+ * Obtiene el mensaje completo para similitud detectada
1307
+ * @returns El mensaje formateado
1308
+ */
1309
+ getSimilitudMessage() {
1310
+ if (!this.control || !this.control.errors) {
1311
+ return '';
1312
+ }
1313
+ const error = this.control.errors['similitudDetectada'];
1314
+ if (!error || typeof error !== 'object' || !('sugerencia' in error)) {
1315
+ return '';
1316
+ }
1317
+ return `Ya existe un registro muy similar en el sistema: "${error.sugerencia}".`;
1318
+ }
1319
+ /**
1320
+ * Obtiene el mensaje de error de un error específico del formulario
1321
+ * @param errorKey - La clave del error
1322
+ * @returns El mensaje de error o un mensaje por defecto
1323
+ */
1324
+ getFormError(errorKey) {
1325
+ if (!this.form) {
1326
+ return '';
1327
+ }
1328
+ const error = this.form.getError(errorKey);
1329
+ if (error && typeof error === 'object' && 'message' in error) {
1330
+ return error.message;
1331
+ }
1332
+ // Mensaje por defecto según el tipo de error
1333
+ switch (errorKey) {
1334
+ case 'atLeastOneRequired':
1335
+ return 'Al menos un campo es requerido';
1336
+ default:
1337
+ return 'Error en el formulario';
1338
+ }
1339
+ }
1340
+ /**
1341
+ * Formatea un número con separadores de miles (coma) y decimales (punto)
1342
+ * @param value - El valor a formatear (puede ser número o string)
1343
+ * @param showDecimals - Si se deben mostrar siempre los decimales
1344
+ * @returns String formateado con separadores de miles
1345
+ */
1346
+ formatNumber(value, showDecimals = false) {
1347
+ // Si es null o undefined, retornar string vacío
1348
+ if (value === null || value === undefined) {
1349
+ return '';
1350
+ }
1351
+ // Convertir a número
1255
1352
  const num = Number(value);
1256
- if (isNaN(num))
1257
- return String(value ?? '');
1258
- return num % 1 === 0 ? String(num) : parseFloat(num.toFixed(2)).toString();
1353
+ // Si no es un número válido, retornar el valor original como string
1354
+ if (isNaN(num)) {
1355
+ return String(value);
1356
+ }
1357
+ // Si es un número entero y no se piden decimales, mostrar solo enteros
1358
+ if (num % 1 === 0 && !showDecimals) {
1359
+ // Formatear con separadores de miles usando coma
1360
+ return num.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',');
1361
+ }
1362
+ // Para números con decimales, usar formato personalizado
1363
+ const parts = num.toFixed(2).split('.');
1364
+ const integerPart = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, ',');
1365
+ const decimalPart = parts[1];
1366
+ return `${integerPart}.${decimalPart}`;
1367
+ }
1368
+ /**
1369
+ * Verifica si estamos en modo desarrollo
1370
+ */
1371
+ isDevelopmentMode() {
1372
+ return typeof window !== 'undefined' && window.ngDevMode !== false;
1259
1373
  }
1260
1374
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: AppMessageErrorComponent, deps: [{ token: i0.ElementRef }, { token: i0.Renderer2 }], target: i0.ɵɵFactoryTarget.Component });
1261
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.17", type: AppMessageErrorComponent, isStandalone: true, selector: "app-message-error", inputs: { control: "control", form: "form", debugMode: "debugMode" }, ngImport: i0, template: "<!-- app-message-error.component.html -->\r\n<div class=\"dsx-error-slot\" [class.is-visible]=\"isControlErrorVisible()\">\r\n <div class=\"dsx-error-message\">\r\n <div class=\"dsx-error-message-content\">\r\n <!-- \uD83C\uDFAF INYECTA ESTA L\u00CDNEA TEMPORAL DE DEPURACI\u00D3N AQU\u00CD -->\r\n <!-- <span\r\n style=\"\r\n color: blue;\r\n font-size: 10px;\r\n display: block;\r\n word-break: break-all;\r\n \"\r\n >\r\n DEBUG ERRORES: {{ control?.errors | json }}\r\n </span> -->\r\n\r\n <icon-dsx name=\"warning\"></icon-dsx>\r\n\r\n @if (control?.errors?.[\"required\"]) {\r\n El campo <strong>es requerido.</strong>\r\n } @else if (control?.errors?.[\"invalidNIT\"]) {\r\n <strong>{{ control?.errors?.[\"invalidNIT\"]?.message }}</strong>\r\n } @else if (control?.errors?.[\"invalidCUI\"]) {\r\n <strong>{{ control?.errors?.[\"invalidCUI\"]?.message }}</strong>\r\n } @else if (control?.errors?.[\"invalidDateRange\"]) {\r\n <strong>{{ control?.errors?.[\"invalidDateRange\"]?.message }}</strong>\r\n } @else if (control?.errors?.[\"dateNotRange\"]) {\r\n <strong>{{ control?.errors?.[\"dateNotRange\"]?.message }}</strong>\r\n } @else if (control?.errors?.[\"invalidDate\"]) {\r\n <strong>{{ control?.errors?.[\"invalidDate\"]?.message }}</strong>\r\n } @else if (control?.errors?.[\"minimumAge\"]) {\r\n <strong>{{ control?.errors?.[\"minimumAge\"]?.message }}</strong>\r\n } @else if (control?.errors?.[\"minlength\"]) {\r\n Debe tener al menos\r\n <strong>{{ control?.errors?.[\"minlength\"]?.requiredLength }}</strong>\r\n caracteres.\r\n } @else if (control?.errors?.[\"maxlength\"]) {\r\n Debe tener como m\u00E1ximo\r\n <strong>{{ control?.errors?.[\"maxlength\"]?.requiredLength }}</strong>\r\n caracteres.\r\n } @else if (control?.errors?.[\"min\"]) {\r\n El valor m\u00EDnimo permitido es\r\n <strong>{{ formatNumber(control?.errors?.[\"min\"]?.min) }}</strong>\r\n } @else if (control?.errors?.[\"max\"]) {\r\n El valor m\u00E1ximo permitido es\r\n <strong>{{ formatNumber(control?.errors?.[\"max\"]?.max) }}</strong>\r\n } @else if (control?.errors?.[\"email\"]) {\r\n Debe ser una direcci\u00F3n de correo v\u00E1lida.\r\n } @else if (control?.errors?.[\"pattern\"]) {\r\n El campo no tiene el formato requerido.\r\n } @else if (control?.errors?.[\"alreadyValueExists\"]) {\r\n <strong>{{ control?.errors?.[\"alreadyValueExists\"]?.message }}</strong>\r\n } @else if (control?.errors?.[\"invalidTemplateVariables\"]) {\r\n <div class=\"dsx-template-error\">\r\n <strong>\r\n {{ control?.errors?.[\"invalidTemplateVariables\"]?.message }}\r\n </strong>\r\n @if (control?.errors?.[\"invalidTemplateVariables\"]?.details?.length) {\r\n <span class=\"dsx-template-error-detail\">\r\n {{ control?.errors?.[\"invalidTemplateVariables\"]?.details?.[0] }}\r\n </span>\r\n }\r\n </div>\r\n } @else if (control?.errors?.[\"invalidTemplateStructure\"]) {\r\n <div class=\"dsx-template-error\">\r\n <strong>\r\n {{ control?.errors?.[\"invalidTemplateStructure\"]?.message }}\r\n </strong>\r\n @if (control?.errors?.[\"invalidTemplateStructure\"]?.details?.length) {\r\n <span class=\"dsx-template-error-detail\">\r\n {{ control?.errors?.[\"invalidTemplateStructure\"]?.details?.[0] }}\r\n </span>\r\n }\r\n </div>\r\n } @else if (control?.errors?.[\"similitudDetectada\"]) {\r\n <!-- \uD83C\uDFAF Estructuraci\u00F3n del mensaje con el nombre aislado en negrita -->\r\n Ya existe un registro muy similar en el sistema:\r\n <strong\r\n >\"{{ control?.errors?.[\"similitudDetectada\"]?.sugerencia }}\"</strong\r\n >.\r\n } @else {\r\n Existe un error a\u00FAn no identificado.\r\n }\r\n </div>\r\n </div>\r\n</div>\r\n\r\n<!-- Mensaje para formulario en general (Cambiado form.touched por form.dirty para evitar falsos positivos al clicar el fondo) -->\r\n@if (form?.invalid && form?.dirty) {\r\n <div class=\"mt-2 mb-2\">\r\n @if (this.form?.errors?.[\"atLeastOneRequired\"]) {\r\n <p-tag severity=\"danger\" [rounded]=\"true\">\r\n {{ form?.getError(\"atLeastOneRequired\")?.message }}\r\n </p-tag>\r\n }\r\n </div>\r\n}\r\n", styles: [".dsx-error-slot{display:block;max-height:0;overflow:hidden;opacity:0;transform:translateY(-2px);transition:opacity .15s ease,transform .15s ease}.dsx-error-slot.is-visible{max-height:80px;opacity:1;transform:translateY(0)}.dsx-error-message{display:block;width:100%}.dsx-error-message-content{display:flex;align-items:center;gap:.5rem;width:100%;box-sizing:border-box;padding:.4rem .7rem;font-size:.85rem;background:var(--dsx-error-bg, #fff2f0)!important;color:var(--dsx-error-color, #b42318)!important;border-left:3px solid var(--dsx-error-color, #b42318)!important;border-radius:.375rem;box-shadow:0 1px 2px #0000000f;line-height:1.4}.dsx-error-icon{flex:0 0 auto;line-height:1;display:inline-flex;align-items:center;justify-content:center}.dsx-error-message-content icon-dsx,.dsx-error-message-content icon-dsx svg,.dsx-error-message-content icon-dsx svg path{color:var(--dsx-error-color, #ff5a4e)!important;fill:var(--dsx-error-color, #e45036)!important}:host-context(.p-floatlabel){position:absolute;top:100%;left:0;width:100%;z-index:10;pointer-events:none}:host-context(.p-floatlabel) .dsx-error-slot{margin-top:.1rem}:host-context(.p-floatlabel) .dsx-error-slot.is-visible{margin-top:.1rem}:host-context(.p-floatlabel) .dsx-error-message-content{padding:.35rem .7rem .35rem .5rem}:host-context(:not(.p-floatlabel)){display:block;width:100%}:host-context(:not(.p-floatlabel)) .dsx-error-slot.is-visible{margin-top:.2rem;margin-bottom:0}:host-context(:not(.p-floatlabel)) .dsx-error-message-content{padding:.35rem .7rem}@media(max-width:640px){.dsx-error-message-content{padding:.3rem .6rem;font-size:.8rem;gap:.4rem}:host-context(.p-floatlabel) .dsx-error-slot.is-visible{margin-top:.05rem}:host-context(:not(.p-floatlabel)) .dsx-error-slot.is-visible{margin-top:.15rem}}@media(prefers-color-scheme:dark){.dsx-error-message-content{background:#2d1a1a;border-left-color:#ef4444;color:#fca5a5}.dsx-error-message-content icon-dsx,.dsx-error-message-content icon-dsx svg,.dsx-error-message-content icon-dsx svg path{color:#ef4444!important;fill:#ef4444!important}}\n"], dependencies: [{ kind: "ngmodule", type: TagModule }, { kind: "component", type: i1$2.Tag, selector: "p-tag", inputs: ["styleClass", "severity", "value", "icon", "rounded"] }, { kind: "component", type: IconDsxComponent, selector: "icon-dsx", inputs: ["name", "style", "debug"] }] });
1375
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.17", type: AppMessageErrorComponent, isStandalone: true, selector: "dsx-message-error", inputs: { control: "control", form: "form", debugMode: "debugMode" }, ngImport: i0, template: "<div class=\"dsx-error-slot\" [class.is-visible]=\"isControlErrorVisible()\">\r\n <div class=\"dsx-error-message\">\r\n <div class=\"dsx-error-message-content\">\r\n <icon-dsx name=\"warning\"></icon-dsx>\r\n\r\n <!-- Usamos control.errors en lugar de control?.errors -->\r\n @if (control && control.errors && control.errors[\"required\"]) {\r\n El campo <strong>es requerido.</strong>\r\n } @else if (control && control.errors && control.errors[\"invalidNIT\"]) {\r\n <strong>{{ getErrorMessage(\"invalidNIT\") }}</strong>\r\n } @else if (control && control.errors && control.errors[\"invalidCUI\"]) {\r\n <strong>{{ getErrorMessage(\"invalidCUI\") }}</strong>\r\n } @else if (\r\n control && control.errors && control.errors[\"invalidDateRange\"]\r\n ) {\r\n <strong>{{ getErrorMessage(\"invalidDateRange\") }}</strong>\r\n } @else if (control && control.errors && control.errors[\"dateNotRange\"]) {\r\n <strong>{{ getErrorMessage(\"dateNotRange\") }}</strong>\r\n } @else if (control && control.errors && control.errors[\"invalidDate\"]) {\r\n <strong>{{ getErrorMessage(\"invalidDate\") }}</strong>\r\n } @else if (control && control.errors && control.errors[\"minimumAge\"]) {\r\n <strong>{{ getErrorMessage(\"minimumAge\") }}</strong>\r\n } @else if (control && control.errors && control.errors[\"minlength\"]) {\r\n Debe tener al menos\r\n <strong>{{\r\n formatNumber(getErrorValue(\"minlength\", \"requiredLength\"), false)\r\n }}</strong>\r\n caracteres.\r\n } @else if (control && control.errors && control.errors[\"maxlength\"]) {\r\n Debe tener como m\u00E1ximo\r\n <strong>{{\r\n formatNumber(getErrorValue(\"maxlength\", \"requiredLength\"), false)\r\n }}</strong>\r\n caracteres.\r\n } @else if (control && control.errors && control.errors[\"min\"]) {\r\n El valor m\u00EDnimo permitido es\r\n <strong>{{ formatNumber(getErrorValue(\"min\", \"min\"), true) }}</strong>\r\n } @else if (control && control.errors && control.errors[\"max\"]) {\r\n El valor m\u00E1ximo permitido es\r\n <strong>{{ formatNumber(getErrorValue(\"max\", \"max\"), true) }}</strong>\r\n } @else if (control && control.errors && control.errors[\"email\"]) {\r\n Debe ser una direcci\u00F3n de correo v\u00E1lida.\r\n } @else if (control && control.errors && control.errors[\"pattern\"]) {\r\n El campo no tiene el formato requerido.\r\n } @else if (\r\n control && control.errors && control.errors[\"alreadyValueExists\"]\r\n ) {\r\n <strong>{{ getErrorMessage(\"alreadyValueExists\") }}</strong>\r\n } @else if (\r\n control && control.errors && control.errors[\"invalidTemplateVariables\"]\r\n ) {\r\n <div class=\"dsx-template-error\">\r\n <strong>{{ getErrorMessage(\"invalidTemplateVariables\") }}</strong>\r\n @if (getTemplateErrorDetails(\"invalidTemplateVariables\").length) {\r\n <span class=\"dsx-template-error-detail\">\r\n {{ getFirstTemplateErrorDetail(\"invalidTemplateVariables\") }}\r\n </span>\r\n }\r\n </div>\r\n } @else if (\r\n control && control.errors && control.errors[\"invalidTemplateStructure\"]\r\n ) {\r\n <div class=\"dsx-template-error\">\r\n <strong>{{ getErrorMessage(\"invalidTemplateStructure\") }}</strong>\r\n @if (getTemplateErrorDetails(\"invalidTemplateStructure\").length) {\r\n <span class=\"dsx-template-error-detail\">\r\n {{ getFirstTemplateErrorDetail(\"invalidTemplateStructure\") }}\r\n </span>\r\n }\r\n </div>\r\n } @else if (\r\n control && control.errors && control.errors[\"similitudDetectada\"]\r\n ) {\r\n <strong>{{ getSimilitudMessage() }}</strong>\r\n } @else {\r\n Existe un error a\u00FAn no identificado.\r\n }\r\n </div>\r\n </div>\r\n</div>\r\n\r\n<!-- Mensaje para formulario en general -->\r\n@if (form && form.invalid && form.dirty) {\r\n <div class=\"mt-2 mb-2\">\r\n @if (form.errors && form.errors[\"atLeastOneRequired\"]) {\r\n <p-tag severity=\"danger\" [rounded]=\"true\">\r\n {{ getFormError(\"atLeastOneRequired\") }}\r\n </p-tag>\r\n }\r\n </div>\r\n}\r\n", styles: [".dsx-error-slot{display:block;max-height:0;overflow:hidden;opacity:0;transform:translateY(-4px) scale(.98);transition:max-height .3s cubic-bezier(.4,0,.2,1),opacity .25s cubic-bezier(.4,0,.2,1),transform .25s cubic-bezier(.4,0,.2,1),margin .25s cubic-bezier(.4,0,.2,1)}.dsx-error-slot.is-visible{max-height:60px;opacity:1;transform:translateY(0) scale(1)}.dsx-error-message{display:block;width:100%}.dsx-error-message-content{display:flex;align-items:center;gap:.4rem;width:100%;box-sizing:border-box;padding:.25rem .6rem;font-size:.82rem;background:var(--dsx-error-bg, #fff2f0)!important;color:var(--dsx-error-color, #b42318)!important;border-left:3px solid var(--dsx-error-color, #b42318)!important;border-radius:.3rem;box-shadow:0 1px 2px #0000000f;line-height:1.3;animation:errorSlideIn .25s cubic-bezier(.4,0,.2,1)}.dsx-error-icon{flex:0 0 auto;line-height:1;display:inline-flex;align-items:center;justify-content:center}.dsx-error-icon icon-dsx{transform:scale(.85);transition:transform .2s ease}.dsx-error-slot.is-visible .dsx-error-icon icon-dsx{transform:scale(1)}.dsx-error-message-content icon-dsx,.dsx-error-message-content icon-dsx svg,.dsx-error-message-content icon-dsx svg path{color:var(--dsx-error-color, #ff5a4e)!important;fill:var(--dsx-error-color, #e45036)!important}@keyframes errorSlideIn{0%{opacity:0;transform:translateY(-6px) scale(.97)}to{opacity:1;transform:translateY(0) scale(1)}}@keyframes errorPulse{0%{box-shadow:0 1px 2px #0000000f}50%{box-shadow:0 2px 8px #b4231826}to{box-shadow:0 1px 2px #0000000f}}.dsx-error-slot.is-visible .dsx-error-message-content{animation:errorSlideIn .25s cubic-bezier(.4,0,.2,1),errorPulse .4s ease .15s}:host-context(.p-floatlabel){position:absolute;top:100%;left:0;width:100%;z-index:10;pointer-events:none}:host-context(.p-floatlabel) .dsx-error-slot.is-visible{margin-top:.08rem}:host-context(.p-floatlabel) .dsx-error-message-content{padding:.2rem .6rem .2rem .4rem}:host-context(:not(.p-floatlabel)){display:block;width:100%}:host-context(:not(.p-floatlabel)) .dsx-error-slot.is-visible{margin-top:.15rem;margin-bottom:0}:host-context(:not(.p-floatlabel)) .dsx-error-message-content{padding:.2rem .6rem}@media(max-width:640px){.dsx-error-message-content{padding:.15rem .5rem;font-size:.75rem;gap:.3rem}.dsx-error-icon icon-dsx{transform:scale(.8)}.dsx-error-slot{transition:max-height .25s cubic-bezier(.4,0,.2,1),opacity .2s cubic-bezier(.4,0,.2,1),transform .2s cubic-bezier(.4,0,.2,1)}@keyframes errorSlideIn{0%{opacity:0;transform:translateY(-4px) scale(.97)}to{opacity:1;transform:translateY(0) scale(1)}}:host-context(.p-floatlabel) .dsx-error-slot.is-visible{margin-top:.05rem}:host-context(:not(.p-floatlabel)) .dsx-error-slot.is-visible{margin-top:.1rem}}@media(prefers-color-scheme:dark){.dsx-error-message-content{background:#2d1a1a;border-left-color:#ef4444;color:#fca5a5}.dsx-error-message-content icon-dsx,.dsx-error-message-content icon-dsx svg,.dsx-error-message-content icon-dsx svg path{color:#ef4444!important;fill:#ef4444!important}@keyframes errorPulse{0%{box-shadow:0 1px 2px #0000004d}50%{box-shadow:0 2px 8px #ef444433}to{box-shadow:0 1px 2px #0000004d}}}\n"], dependencies: [{ kind: "ngmodule", type: TagModule }, { kind: "component", type: i1$2.Tag, selector: "p-tag", inputs: ["styleClass", "severity", "value", "icon", "rounded"] }, { kind: "component", type: IconDsxComponent, selector: "icon-dsx", inputs: ["name", "style", "debug"] }] });
1262
1376
  }
1263
1377
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: AppMessageErrorComponent, decorators: [{
1264
1378
  type: Component,
1265
- args: [{ selector: 'app-message-error', standalone: true, imports: [TagModule, IconDsxComponent], template: "<!-- app-message-error.component.html -->\r\n<div class=\"dsx-error-slot\" [class.is-visible]=\"isControlErrorVisible()\">\r\n <div class=\"dsx-error-message\">\r\n <div class=\"dsx-error-message-content\">\r\n <!-- \uD83C\uDFAF INYECTA ESTA L\u00CDNEA TEMPORAL DE DEPURACI\u00D3N AQU\u00CD -->\r\n <!-- <span\r\n style=\"\r\n color: blue;\r\n font-size: 10px;\r\n display: block;\r\n word-break: break-all;\r\n \"\r\n >\r\n DEBUG ERRORES: {{ control?.errors | json }}\r\n </span> -->\r\n\r\n <icon-dsx name=\"warning\"></icon-dsx>\r\n\r\n @if (control?.errors?.[\"required\"]) {\r\n El campo <strong>es requerido.</strong>\r\n } @else if (control?.errors?.[\"invalidNIT\"]) {\r\n <strong>{{ control?.errors?.[\"invalidNIT\"]?.message }}</strong>\r\n } @else if (control?.errors?.[\"invalidCUI\"]) {\r\n <strong>{{ control?.errors?.[\"invalidCUI\"]?.message }}</strong>\r\n } @else if (control?.errors?.[\"invalidDateRange\"]) {\r\n <strong>{{ control?.errors?.[\"invalidDateRange\"]?.message }}</strong>\r\n } @else if (control?.errors?.[\"dateNotRange\"]) {\r\n <strong>{{ control?.errors?.[\"dateNotRange\"]?.message }}</strong>\r\n } @else if (control?.errors?.[\"invalidDate\"]) {\r\n <strong>{{ control?.errors?.[\"invalidDate\"]?.message }}</strong>\r\n } @else if (control?.errors?.[\"minimumAge\"]) {\r\n <strong>{{ control?.errors?.[\"minimumAge\"]?.message }}</strong>\r\n } @else if (control?.errors?.[\"minlength\"]) {\r\n Debe tener al menos\r\n <strong>{{ control?.errors?.[\"minlength\"]?.requiredLength }}</strong>\r\n caracteres.\r\n } @else if (control?.errors?.[\"maxlength\"]) {\r\n Debe tener como m\u00E1ximo\r\n <strong>{{ control?.errors?.[\"maxlength\"]?.requiredLength }}</strong>\r\n caracteres.\r\n } @else if (control?.errors?.[\"min\"]) {\r\n El valor m\u00EDnimo permitido es\r\n <strong>{{ formatNumber(control?.errors?.[\"min\"]?.min) }}</strong>\r\n } @else if (control?.errors?.[\"max\"]) {\r\n El valor m\u00E1ximo permitido es\r\n <strong>{{ formatNumber(control?.errors?.[\"max\"]?.max) }}</strong>\r\n } @else if (control?.errors?.[\"email\"]) {\r\n Debe ser una direcci\u00F3n de correo v\u00E1lida.\r\n } @else if (control?.errors?.[\"pattern\"]) {\r\n El campo no tiene el formato requerido.\r\n } @else if (control?.errors?.[\"alreadyValueExists\"]) {\r\n <strong>{{ control?.errors?.[\"alreadyValueExists\"]?.message }}</strong>\r\n } @else if (control?.errors?.[\"invalidTemplateVariables\"]) {\r\n <div class=\"dsx-template-error\">\r\n <strong>\r\n {{ control?.errors?.[\"invalidTemplateVariables\"]?.message }}\r\n </strong>\r\n @if (control?.errors?.[\"invalidTemplateVariables\"]?.details?.length) {\r\n <span class=\"dsx-template-error-detail\">\r\n {{ control?.errors?.[\"invalidTemplateVariables\"]?.details?.[0] }}\r\n </span>\r\n }\r\n </div>\r\n } @else if (control?.errors?.[\"invalidTemplateStructure\"]) {\r\n <div class=\"dsx-template-error\">\r\n <strong>\r\n {{ control?.errors?.[\"invalidTemplateStructure\"]?.message }}\r\n </strong>\r\n @if (control?.errors?.[\"invalidTemplateStructure\"]?.details?.length) {\r\n <span class=\"dsx-template-error-detail\">\r\n {{ control?.errors?.[\"invalidTemplateStructure\"]?.details?.[0] }}\r\n </span>\r\n }\r\n </div>\r\n } @else if (control?.errors?.[\"similitudDetectada\"]) {\r\n <!-- \uD83C\uDFAF Estructuraci\u00F3n del mensaje con el nombre aislado en negrita -->\r\n Ya existe un registro muy similar en el sistema:\r\n <strong\r\n >\"{{ control?.errors?.[\"similitudDetectada\"]?.sugerencia }}\"</strong\r\n >.\r\n } @else {\r\n Existe un error a\u00FAn no identificado.\r\n }\r\n </div>\r\n </div>\r\n</div>\r\n\r\n<!-- Mensaje para formulario en general (Cambiado form.touched por form.dirty para evitar falsos positivos al clicar el fondo) -->\r\n@if (form?.invalid && form?.dirty) {\r\n <div class=\"mt-2 mb-2\">\r\n @if (this.form?.errors?.[\"atLeastOneRequired\"]) {\r\n <p-tag severity=\"danger\" [rounded]=\"true\">\r\n {{ form?.getError(\"atLeastOneRequired\")?.message }}\r\n </p-tag>\r\n }\r\n </div>\r\n}\r\n", styles: [".dsx-error-slot{display:block;max-height:0;overflow:hidden;opacity:0;transform:translateY(-2px);transition:opacity .15s ease,transform .15s ease}.dsx-error-slot.is-visible{max-height:80px;opacity:1;transform:translateY(0)}.dsx-error-message{display:block;width:100%}.dsx-error-message-content{display:flex;align-items:center;gap:.5rem;width:100%;box-sizing:border-box;padding:.4rem .7rem;font-size:.85rem;background:var(--dsx-error-bg, #fff2f0)!important;color:var(--dsx-error-color, #b42318)!important;border-left:3px solid var(--dsx-error-color, #b42318)!important;border-radius:.375rem;box-shadow:0 1px 2px #0000000f;line-height:1.4}.dsx-error-icon{flex:0 0 auto;line-height:1;display:inline-flex;align-items:center;justify-content:center}.dsx-error-message-content icon-dsx,.dsx-error-message-content icon-dsx svg,.dsx-error-message-content icon-dsx svg path{color:var(--dsx-error-color, #ff5a4e)!important;fill:var(--dsx-error-color, #e45036)!important}:host-context(.p-floatlabel){position:absolute;top:100%;left:0;width:100%;z-index:10;pointer-events:none}:host-context(.p-floatlabel) .dsx-error-slot{margin-top:.1rem}:host-context(.p-floatlabel) .dsx-error-slot.is-visible{margin-top:.1rem}:host-context(.p-floatlabel) .dsx-error-message-content{padding:.35rem .7rem .35rem .5rem}:host-context(:not(.p-floatlabel)){display:block;width:100%}:host-context(:not(.p-floatlabel)) .dsx-error-slot.is-visible{margin-top:.2rem;margin-bottom:0}:host-context(:not(.p-floatlabel)) .dsx-error-message-content{padding:.35rem .7rem}@media(max-width:640px){.dsx-error-message-content{padding:.3rem .6rem;font-size:.8rem;gap:.4rem}:host-context(.p-floatlabel) .dsx-error-slot.is-visible{margin-top:.05rem}:host-context(:not(.p-floatlabel)) .dsx-error-slot.is-visible{margin-top:.15rem}}@media(prefers-color-scheme:dark){.dsx-error-message-content{background:#2d1a1a;border-left-color:#ef4444;color:#fca5a5}.dsx-error-message-content icon-dsx,.dsx-error-message-content icon-dsx svg,.dsx-error-message-content icon-dsx svg path{color:#ef4444!important;fill:#ef4444!important}}\n"] }]
1379
+ args: [{ selector: 'dsx-message-error', standalone: true, imports: [TagModule, IconDsxComponent], template: "<div class=\"dsx-error-slot\" [class.is-visible]=\"isControlErrorVisible()\">\r\n <div class=\"dsx-error-message\">\r\n <div class=\"dsx-error-message-content\">\r\n <icon-dsx name=\"warning\"></icon-dsx>\r\n\r\n <!-- Usamos control.errors en lugar de control?.errors -->\r\n @if (control && control.errors && control.errors[\"required\"]) {\r\n El campo <strong>es requerido.</strong>\r\n } @else if (control && control.errors && control.errors[\"invalidNIT\"]) {\r\n <strong>{{ getErrorMessage(\"invalidNIT\") }}</strong>\r\n } @else if (control && control.errors && control.errors[\"invalidCUI\"]) {\r\n <strong>{{ getErrorMessage(\"invalidCUI\") }}</strong>\r\n } @else if (\r\n control && control.errors && control.errors[\"invalidDateRange\"]\r\n ) {\r\n <strong>{{ getErrorMessage(\"invalidDateRange\") }}</strong>\r\n } @else if (control && control.errors && control.errors[\"dateNotRange\"]) {\r\n <strong>{{ getErrorMessage(\"dateNotRange\") }}</strong>\r\n } @else if (control && control.errors && control.errors[\"invalidDate\"]) {\r\n <strong>{{ getErrorMessage(\"invalidDate\") }}</strong>\r\n } @else if (control && control.errors && control.errors[\"minimumAge\"]) {\r\n <strong>{{ getErrorMessage(\"minimumAge\") }}</strong>\r\n } @else if (control && control.errors && control.errors[\"minlength\"]) {\r\n Debe tener al menos\r\n <strong>{{\r\n formatNumber(getErrorValue(\"minlength\", \"requiredLength\"), false)\r\n }}</strong>\r\n caracteres.\r\n } @else if (control && control.errors && control.errors[\"maxlength\"]) {\r\n Debe tener como m\u00E1ximo\r\n <strong>{{\r\n formatNumber(getErrorValue(\"maxlength\", \"requiredLength\"), false)\r\n }}</strong>\r\n caracteres.\r\n } @else if (control && control.errors && control.errors[\"min\"]) {\r\n El valor m\u00EDnimo permitido es\r\n <strong>{{ formatNumber(getErrorValue(\"min\", \"min\"), true) }}</strong>\r\n } @else if (control && control.errors && control.errors[\"max\"]) {\r\n El valor m\u00E1ximo permitido es\r\n <strong>{{ formatNumber(getErrorValue(\"max\", \"max\"), true) }}</strong>\r\n } @else if (control && control.errors && control.errors[\"email\"]) {\r\n Debe ser una direcci\u00F3n de correo v\u00E1lida.\r\n } @else if (control && control.errors && control.errors[\"pattern\"]) {\r\n El campo no tiene el formato requerido.\r\n } @else if (\r\n control && control.errors && control.errors[\"alreadyValueExists\"]\r\n ) {\r\n <strong>{{ getErrorMessage(\"alreadyValueExists\") }}</strong>\r\n } @else if (\r\n control && control.errors && control.errors[\"invalidTemplateVariables\"]\r\n ) {\r\n <div class=\"dsx-template-error\">\r\n <strong>{{ getErrorMessage(\"invalidTemplateVariables\") }}</strong>\r\n @if (getTemplateErrorDetails(\"invalidTemplateVariables\").length) {\r\n <span class=\"dsx-template-error-detail\">\r\n {{ getFirstTemplateErrorDetail(\"invalidTemplateVariables\") }}\r\n </span>\r\n }\r\n </div>\r\n } @else if (\r\n control && control.errors && control.errors[\"invalidTemplateStructure\"]\r\n ) {\r\n <div class=\"dsx-template-error\">\r\n <strong>{{ getErrorMessage(\"invalidTemplateStructure\") }}</strong>\r\n @if (getTemplateErrorDetails(\"invalidTemplateStructure\").length) {\r\n <span class=\"dsx-template-error-detail\">\r\n {{ getFirstTemplateErrorDetail(\"invalidTemplateStructure\") }}\r\n </span>\r\n }\r\n </div>\r\n } @else if (\r\n control && control.errors && control.errors[\"similitudDetectada\"]\r\n ) {\r\n <strong>{{ getSimilitudMessage() }}</strong>\r\n } @else {\r\n Existe un error a\u00FAn no identificado.\r\n }\r\n </div>\r\n </div>\r\n</div>\r\n\r\n<!-- Mensaje para formulario en general -->\r\n@if (form && form.invalid && form.dirty) {\r\n <div class=\"mt-2 mb-2\">\r\n @if (form.errors && form.errors[\"atLeastOneRequired\"]) {\r\n <p-tag severity=\"danger\" [rounded]=\"true\">\r\n {{ getFormError(\"atLeastOneRequired\") }}\r\n </p-tag>\r\n }\r\n </div>\r\n}\r\n", styles: [".dsx-error-slot{display:block;max-height:0;overflow:hidden;opacity:0;transform:translateY(-4px) scale(.98);transition:max-height .3s cubic-bezier(.4,0,.2,1),opacity .25s cubic-bezier(.4,0,.2,1),transform .25s cubic-bezier(.4,0,.2,1),margin .25s cubic-bezier(.4,0,.2,1)}.dsx-error-slot.is-visible{max-height:60px;opacity:1;transform:translateY(0) scale(1)}.dsx-error-message{display:block;width:100%}.dsx-error-message-content{display:flex;align-items:center;gap:.4rem;width:100%;box-sizing:border-box;padding:.25rem .6rem;font-size:.82rem;background:var(--dsx-error-bg, #fff2f0)!important;color:var(--dsx-error-color, #b42318)!important;border-left:3px solid var(--dsx-error-color, #b42318)!important;border-radius:.3rem;box-shadow:0 1px 2px #0000000f;line-height:1.3;animation:errorSlideIn .25s cubic-bezier(.4,0,.2,1)}.dsx-error-icon{flex:0 0 auto;line-height:1;display:inline-flex;align-items:center;justify-content:center}.dsx-error-icon icon-dsx{transform:scale(.85);transition:transform .2s ease}.dsx-error-slot.is-visible .dsx-error-icon icon-dsx{transform:scale(1)}.dsx-error-message-content icon-dsx,.dsx-error-message-content icon-dsx svg,.dsx-error-message-content icon-dsx svg path{color:var(--dsx-error-color, #ff5a4e)!important;fill:var(--dsx-error-color, #e45036)!important}@keyframes errorSlideIn{0%{opacity:0;transform:translateY(-6px) scale(.97)}to{opacity:1;transform:translateY(0) scale(1)}}@keyframes errorPulse{0%{box-shadow:0 1px 2px #0000000f}50%{box-shadow:0 2px 8px #b4231826}to{box-shadow:0 1px 2px #0000000f}}.dsx-error-slot.is-visible .dsx-error-message-content{animation:errorSlideIn .25s cubic-bezier(.4,0,.2,1),errorPulse .4s ease .15s}:host-context(.p-floatlabel){position:absolute;top:100%;left:0;width:100%;z-index:10;pointer-events:none}:host-context(.p-floatlabel) .dsx-error-slot.is-visible{margin-top:.08rem}:host-context(.p-floatlabel) .dsx-error-message-content{padding:.2rem .6rem .2rem .4rem}:host-context(:not(.p-floatlabel)){display:block;width:100%}:host-context(:not(.p-floatlabel)) .dsx-error-slot.is-visible{margin-top:.15rem;margin-bottom:0}:host-context(:not(.p-floatlabel)) .dsx-error-message-content{padding:.2rem .6rem}@media(max-width:640px){.dsx-error-message-content{padding:.15rem .5rem;font-size:.75rem;gap:.3rem}.dsx-error-icon icon-dsx{transform:scale(.8)}.dsx-error-slot{transition:max-height .25s cubic-bezier(.4,0,.2,1),opacity .2s cubic-bezier(.4,0,.2,1),transform .2s cubic-bezier(.4,0,.2,1)}@keyframes errorSlideIn{0%{opacity:0;transform:translateY(-4px) scale(.97)}to{opacity:1;transform:translateY(0) scale(1)}}:host-context(.p-floatlabel) .dsx-error-slot.is-visible{margin-top:.05rem}:host-context(:not(.p-floatlabel)) .dsx-error-slot.is-visible{margin-top:.1rem}}@media(prefers-color-scheme:dark){.dsx-error-message-content{background:#2d1a1a;border-left-color:#ef4444;color:#fca5a5}.dsx-error-message-content icon-dsx,.dsx-error-message-content icon-dsx svg,.dsx-error-message-content icon-dsx svg path{color:#ef4444!important;fill:#ef4444!important}@keyframes errorPulse{0%{box-shadow:0 1px 2px #0000004d}50%{box-shadow:0 2px 8px #ef444433}to{box-shadow:0 1px 2px #0000004d}}}\n"] }]
1266
1380
  }], ctorParameters: () => [{ type: i0.ElementRef }, { type: i0.Renderer2 }], propDecorators: { control: [{
1267
1381
  type: Input
1268
1382
  }], form: [{
@@ -2671,11 +2785,18 @@ class UtilityAddService {
2671
2785
  const resolvedOptions = Array.isArray(groupValidatorsOrOptions)
2672
2786
  ? options
2673
2787
  : (groupValidatorsOrOptions ?? options);
2788
+ // IMPORTANTE: Cambiamos el tipado a AbstractControl para permitir meter FormArrays o FormGroups
2674
2789
  const formGroup = {};
2675
- // Crear controles de formulario individuales
2790
+ // Crear controles de formulario individuales o inyectar estructuras abstractas
2676
2791
  for (const key in config) {
2677
2792
  if (Object.prototype.hasOwnProperty.call(config, key)) {
2678
2793
  const fieldConfig = config[key];
2794
+ // ¡EL CAMBIO MÁGICO!: Si ya pasaste un FormArray o FormGroup pre-construido, lo asignamos directo
2795
+ if (fieldConfig instanceof AbstractControl) {
2796
+ formGroup[key] = fieldConfig;
2797
+ continue; // Saltamos a la siguiente iteración
2798
+ }
2799
+ // Tu lógica intacta original para los FormControl estándar
2679
2800
  const { value, validators = [], asyncValidators = [], } = fieldConfig;
2680
2801
  const hasAssignedDisabled = Object.prototype.hasOwnProperty.call(fieldConfig, 'disabled');
2681
2802
  const disabled = hasAssignedDisabled
@@ -4210,6 +4331,8 @@ class DsxButtonComponent {
4210
4331
  renderCount = 0;
4211
4332
  _paramService = inject((ParameterValuesService));
4212
4333
  _router = inject(Router);
4334
+ // Agrega un input para el tamaño
4335
+ size = input(undefined, ...(ngDevMode ? [{ debugName: "size" }] : /* istanbul ignore next */ []));
4213
4336
  _environment = inject(ENVIRONMENT, {
4214
4337
  optional: true,
4215
4338
  });
@@ -4395,8 +4518,18 @@ class DsxButtonComponent {
4395
4518
  get buttonLabel() {
4396
4519
  return this.iconOnly() ? undefined : this.label;
4397
4520
  }
4521
+ // Y modifica el getter buttonSize
4398
4522
  get buttonSize() {
4399
- return this.isCompactIconButton ? 'small' : undefined;
4523
+ // Si el usuario especificó un tamaño, úsalo
4524
+ if (this.size()) {
4525
+ return this.size();
4526
+ }
4527
+ // Si es compacto, siempre small
4528
+ if (this.isCompactIconButton) {
4529
+ return 'small';
4530
+ }
4531
+ // Por defecto, small para todos los botones
4532
+ return 'small';
4400
4533
  }
4401
4534
  get buttonStyleClass() {
4402
4535
  return this.isCompactIconButton ? 'dsx-button-compact' : undefined;
@@ -4638,12 +4771,12 @@ class DsxButtonComponent {
4638
4771
  console.timeEnd(`[dsx-button:${this.type()}] ${label}`);
4639
4772
  }
4640
4773
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: DsxButtonComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
4641
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.17", type: DsxButtonComponent, isStandalone: true, selector: "dsx-button", inputs: { debug: { classPropertyName: "debug", publicName: "debug", isSignal: true, isRequired: false, transformFunction: null }, type: { classPropertyName: "type", publicName: "type", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, routerLink: { classPropertyName: "routerLink", publicName: "routerLink", isSignal: true, isRequired: false, transformFunction: null }, routerPath: { classPropertyName: "routerPath", publicName: "routerPath", isSignal: true, isRequired: false, transformFunction: null }, width: { classPropertyName: "width", publicName: "width", isSignal: true, isRequired: false, transformFunction: null }, iconOnly: { classPropertyName: "iconOnly", publicName: "iconOnly", isSignal: true, isRequired: false, transformFunction: null }, iconOnlyWidth: { classPropertyName: "iconOnlyWidth", publicName: "iconOnlyWidth", isSignal: true, isRequired: false, transformFunction: null }, raised: { classPropertyName: "raised", publicName: "raised", isSignal: true, isRequired: false, transformFunction: null }, rounded: { classPropertyName: "rounded", publicName: "rounded", isSignal: true, isRequired: false, transformFunction: null }, parameterName: { classPropertyName: "parameterName", publicName: "parameterName", isSignal: true, isRequired: false, transformFunction: null }, parameterExpectedValue: { classPropertyName: "parameterExpectedValue", publicName: "parameterExpectedValue", isSignal: true, isRequired: false, transformFunction: null }, parameterIndex: { classPropertyName: "parameterIndex", publicName: "parameterIndex", isSignal: true, isRequired: false, transformFunction: null }, id: { classPropertyName: "id", publicName: "id", isSignal: true, isRequired: false, transformFunction: null }, requireIdInput: { classPropertyName: "requireIdInput", publicName: "requireIdInput", isSignal: true, isRequired: false, transformFunction: null }, requiresIdGreaterThanZero: { classPropertyName: "requiresIdGreaterThanZero", publicName: "requiresIdGreaterThanZero", isSignal: true, isRequired: false, transformFunction: null }, labelOverride: { classPropertyName: "labelOverride", publicName: "labelOverride", isSignal: true, isRequired: false, transformFunction: null }, tooltipOverride: { classPropertyName: "tooltipOverride", publicName: "tooltipOverride", isSignal: true, isRequired: false, transformFunction: null }, iconOverride: { classPropertyName: "iconOverride", publicName: "iconOverride", isSignal: true, isRequired: false, transformFunction: null }, primeIconOverride: { classPropertyName: "primeIconOverride", publicName: "primeIconOverride", isSignal: true, isRequired: false, transformFunction: null }, colorOverride: { classPropertyName: "colorOverride", publicName: "colorOverride", isSignal: true, isRequired: false, transformFunction: null }, outlinedOverride: { classPropertyName: "outlinedOverride", publicName: "outlinedOverride", isSignal: true, isRequired: false, transformFunction: null }, showValidateButtonOverride: { classPropertyName: "showValidateButtonOverride", publicName: "showValidateButtonOverride", isSignal: true, isRequired: false, transformFunction: null }, showRestoreButtonOverride: { classPropertyName: "showRestoreButtonOverride", publicName: "showRestoreButtonOverride", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { action: "action" }, host: { properties: { "class.dsx-button-compact-host": "this.compactHostClass" } }, ngImport: i0, template: "<!--Bot\u00F3n con las configuraciones din\u00E1micas para CRUD -->\r\n@if (visible()) {\r\n<p-button\r\n [label]=\"buttonLabel\"\r\n [style]=\"buttonStyleComputed()\"\r\n [styleClass]=\"buttonStyleClass\"\r\n [pTooltip]=\"tooltip()\"\r\n [tooltipDisabled]=\"disabled()\"\r\n tooltipPosition=\"top\"\r\n [rounded]=\"rounded()\"\r\n [text]=\"isCompactIconButton\"\r\n [size]=\"buttonSize\"\r\n severity=\"secondary\"\r\n [disabled]=\"disabled()\"\r\n [icon]=\"iconOnly() ? primeIcon : undefined\"\r\n (click)=\"onButtonClick()\"\r\n>\r\n @if (!iconOnly()) {\r\n <span class=\"material-symbols-outlined dsx-button-icon-small\"\r\n >{{ materialIcon }}</span\r\n >\r\n }\r\n</p-button>\r\n}\r\n", styles: [".dsx-button-icon-small{font-size:1.25rem;vertical-align:middle}:host{display:inline-flex;margin-bottom:.25rem}:host.dsx-button-compact-host{margin-bottom:0}:host ::ng-deep .p-button .p-button-label{font-family:Montserrat,Roboto,sans-serif;font-weight:500;letter-spacing:.01em}:host ::ng-deep .p-button.dsx-button-compact{min-height:2rem;padding-block:.2rem}:host ::ng-deep .p-button .material-symbols-outlined.p-button-icon{line-height:1;vertical-align:middle}:host ::ng-deep .p-button.dsx-button-compact .p-button-icon{margin:0;font-size:1.2rem;line-height:1}:host ::ng-deep .p-button.dsx-button-compact .material-symbols-outlined.p-button-icon{font-variation-settings:\"FILL\" 1,\"wght\" 500,\"GRAD\" 0,\"opsz\" 24}:host ::ng-deep .p-button:disabled,:host ::ng-deep .p-button.p-disabled{cursor:not-allowed!important;opacity:.45!important;filter:grayscale(.2) saturate(.75)}:host ::ng-deep .p-button:disabled *,:host ::ng-deep .p-button.p-disabled *{cursor:not-allowed!important}.p-button.dsx-button-outlined-neutral,.p-button.dsx-button-outlined-info{background:#f5f7fa!important;border:1.5px solid #0066cc!important;color:#06c!important}.p-button.dsx-button-outlined-neutral:disabled,.p-button.dsx-button-outlined-info:disabled{background:#f5f7fa!important;border:1.5px solid #b0bec5!important;color:#b0bec5!important}\n"], dependencies: [{ kind: "component", type: Button, selector: "p-button", inputs: ["hostName", "type", "badge", "disabled", "raised", "rounded", "text", "plain", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "autofocus", "iconPos", "icon", "label", "loading", "loadingIcon", "severity", "buttonProps", "fluid"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "ngmodule", type: TooltipModule }, { kind: "directive", type: i1$3.Tooltip, selector: "[pTooltip]", inputs: ["tooltipPosition", "tooltipEvent", "positionStyle", "tooltipStyleClass", "tooltipZIndex", "escape", "showDelay", "hideDelay", "life", "positionTop", "positionLeft", "autoHide", "fitContent", "hideOnEscape", "showOnEllipsis", "pTooltip", "tooltipDisabled", "tooltipOptions", "appendTo", "ptTooltip", "pTooltipPT", "pTooltipUnstyled"] }] });
4774
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.17", type: DsxButtonComponent, isStandalone: true, selector: "dsx-button", inputs: { debug: { classPropertyName: "debug", publicName: "debug", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, type: { classPropertyName: "type", publicName: "type", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, routerLink: { classPropertyName: "routerLink", publicName: "routerLink", isSignal: true, isRequired: false, transformFunction: null }, routerPath: { classPropertyName: "routerPath", publicName: "routerPath", isSignal: true, isRequired: false, transformFunction: null }, width: { classPropertyName: "width", publicName: "width", isSignal: true, isRequired: false, transformFunction: null }, iconOnly: { classPropertyName: "iconOnly", publicName: "iconOnly", isSignal: true, isRequired: false, transformFunction: null }, iconOnlyWidth: { classPropertyName: "iconOnlyWidth", publicName: "iconOnlyWidth", isSignal: true, isRequired: false, transformFunction: null }, raised: { classPropertyName: "raised", publicName: "raised", isSignal: true, isRequired: false, transformFunction: null }, rounded: { classPropertyName: "rounded", publicName: "rounded", isSignal: true, isRequired: false, transformFunction: null }, parameterName: { classPropertyName: "parameterName", publicName: "parameterName", isSignal: true, isRequired: false, transformFunction: null }, parameterExpectedValue: { classPropertyName: "parameterExpectedValue", publicName: "parameterExpectedValue", isSignal: true, isRequired: false, transformFunction: null }, parameterIndex: { classPropertyName: "parameterIndex", publicName: "parameterIndex", isSignal: true, isRequired: false, transformFunction: null }, id: { classPropertyName: "id", publicName: "id", isSignal: true, isRequired: false, transformFunction: null }, requireIdInput: { classPropertyName: "requireIdInput", publicName: "requireIdInput", isSignal: true, isRequired: false, transformFunction: null }, requiresIdGreaterThanZero: { classPropertyName: "requiresIdGreaterThanZero", publicName: "requiresIdGreaterThanZero", isSignal: true, isRequired: false, transformFunction: null }, labelOverride: { classPropertyName: "labelOverride", publicName: "labelOverride", isSignal: true, isRequired: false, transformFunction: null }, tooltipOverride: { classPropertyName: "tooltipOverride", publicName: "tooltipOverride", isSignal: true, isRequired: false, transformFunction: null }, iconOverride: { classPropertyName: "iconOverride", publicName: "iconOverride", isSignal: true, isRequired: false, transformFunction: null }, primeIconOverride: { classPropertyName: "primeIconOverride", publicName: "primeIconOverride", isSignal: true, isRequired: false, transformFunction: null }, colorOverride: { classPropertyName: "colorOverride", publicName: "colorOverride", isSignal: true, isRequired: false, transformFunction: null }, outlinedOverride: { classPropertyName: "outlinedOverride", publicName: "outlinedOverride", isSignal: true, isRequired: false, transformFunction: null }, showValidateButtonOverride: { classPropertyName: "showValidateButtonOverride", publicName: "showValidateButtonOverride", isSignal: true, isRequired: false, transformFunction: null }, showRestoreButtonOverride: { classPropertyName: "showRestoreButtonOverride", publicName: "showRestoreButtonOverride", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { action: "action" }, host: { properties: { "class.dsx-button-compact-host": "this.compactHostClass" } }, ngImport: i0, template: "<!--Bot\u00F3n con las configuraciones din\u00E1micas para CRUD -->\r\n@if (visible()) {\r\n<p-button\r\n [label]=\"buttonLabel\"\r\n [style]=\"buttonStyleComputed()\"\r\n [styleClass]=\"buttonStyleClass\"\r\n [pTooltip]=\"tooltip()\"\r\n [tooltipDisabled]=\"disabled()\"\r\n tooltipPosition=\"top\"\r\n [rounded]=\"rounded()\"\r\n [text]=\"isCompactIconButton\"\r\n [size]=\"buttonSize\"\r\n severity=\"secondary\"\r\n [disabled]=\"disabled()\"\r\n [icon]=\"iconOnly() ? primeIcon : undefined\"\r\n (click)=\"onButtonClick()\"\r\n>\r\n @if (!iconOnly()) {\r\n <span class=\"material-symbols-outlined dsx-button-icon-small\"\r\n >{{ materialIcon }}</span\r\n >\r\n }\r\n</p-button>\r\n}\r\n", styles: [".dsx-button-icon-small{font-size:1.25rem;vertical-align:middle}:host{display:inline-flex;margin-bottom:.25rem}:host.dsx-button-compact-host{margin-bottom:0}:host ::ng-deep .p-button.dsx-button-compact{min-height:2rem;padding-block:.2rem}:host ::ng-deep .p-button .material-symbols-outlined.p-button-icon{line-height:1;vertical-align:middle}:host ::ng-deep .p-button.dsx-button-compact .p-button-icon{margin:0;font-size:1.2rem;line-height:1}:host ::ng-deep .p-button.dsx-button-compact .material-symbols-outlined.p-button-icon{font-variation-settings:\"FILL\" 1,\"wght\" 500,\"GRAD\" 0,\"opsz\" 24}:host ::ng-deep .p-button:disabled,:host ::ng-deep .p-button.p-disabled{cursor:not-allowed!important;opacity:.45!important;filter:grayscale(.2) saturate(.75)}:host ::ng-deep .p-button:disabled *,:host ::ng-deep .p-button.p-disabled *{cursor:not-allowed!important}.p-button.dsx-button-outlined-neutral,.p-button.dsx-button-outlined-info{background:#f5f7fa!important;border:1.5px solid #0066cc!important;color:#06c!important}.p-button.dsx-button-outlined-neutral:disabled,.p-button.dsx-button-outlined-info:disabled{background:#f5f7fa!important;border:1.5px solid #b0bec5!important;color:#b0bec5!important}\n"], dependencies: [{ kind: "component", type: Button, selector: "p-button", inputs: ["hostName", "type", "badge", "disabled", "raised", "rounded", "text", "plain", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "autofocus", "iconPos", "icon", "label", "loading", "loadingIcon", "severity", "buttonProps", "fluid"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "ngmodule", type: TooltipModule }, { kind: "directive", type: i1$3.Tooltip, selector: "[pTooltip]", inputs: ["tooltipPosition", "tooltipEvent", "positionStyle", "tooltipStyleClass", "tooltipZIndex", "escape", "showDelay", "hideDelay", "life", "positionTop", "positionLeft", "autoHide", "fitContent", "hideOnEscape", "showOnEllipsis", "pTooltip", "tooltipDisabled", "tooltipOptions", "appendTo", "ptTooltip", "pTooltipPT", "pTooltipUnstyled"] }] });
4642
4775
  }
4643
4776
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: DsxButtonComponent, decorators: [{
4644
4777
  type: Component,
4645
- args: [{ selector: 'dsx-button', imports: [Button, TooltipModule], template: "<!--Bot\u00F3n con las configuraciones din\u00E1micas para CRUD -->\r\n@if (visible()) {\r\n<p-button\r\n [label]=\"buttonLabel\"\r\n [style]=\"buttonStyleComputed()\"\r\n [styleClass]=\"buttonStyleClass\"\r\n [pTooltip]=\"tooltip()\"\r\n [tooltipDisabled]=\"disabled()\"\r\n tooltipPosition=\"top\"\r\n [rounded]=\"rounded()\"\r\n [text]=\"isCompactIconButton\"\r\n [size]=\"buttonSize\"\r\n severity=\"secondary\"\r\n [disabled]=\"disabled()\"\r\n [icon]=\"iconOnly() ? primeIcon : undefined\"\r\n (click)=\"onButtonClick()\"\r\n>\r\n @if (!iconOnly()) {\r\n <span class=\"material-symbols-outlined dsx-button-icon-small\"\r\n >{{ materialIcon }}</span\r\n >\r\n }\r\n</p-button>\r\n}\r\n", styles: [".dsx-button-icon-small{font-size:1.25rem;vertical-align:middle}:host{display:inline-flex;margin-bottom:.25rem}:host.dsx-button-compact-host{margin-bottom:0}:host ::ng-deep .p-button .p-button-label{font-family:Montserrat,Roboto,sans-serif;font-weight:500;letter-spacing:.01em}:host ::ng-deep .p-button.dsx-button-compact{min-height:2rem;padding-block:.2rem}:host ::ng-deep .p-button .material-symbols-outlined.p-button-icon{line-height:1;vertical-align:middle}:host ::ng-deep .p-button.dsx-button-compact .p-button-icon{margin:0;font-size:1.2rem;line-height:1}:host ::ng-deep .p-button.dsx-button-compact .material-symbols-outlined.p-button-icon{font-variation-settings:\"FILL\" 1,\"wght\" 500,\"GRAD\" 0,\"opsz\" 24}:host ::ng-deep .p-button:disabled,:host ::ng-deep .p-button.p-disabled{cursor:not-allowed!important;opacity:.45!important;filter:grayscale(.2) saturate(.75)}:host ::ng-deep .p-button:disabled *,:host ::ng-deep .p-button.p-disabled *{cursor:not-allowed!important}.p-button.dsx-button-outlined-neutral,.p-button.dsx-button-outlined-info{background:#f5f7fa!important;border:1.5px solid #0066cc!important;color:#06c!important}.p-button.dsx-button-outlined-neutral:disabled,.p-button.dsx-button-outlined-info:disabled{background:#f5f7fa!important;border:1.5px solid #b0bec5!important;color:#b0bec5!important}\n"] }]
4646
- }], ctorParameters: () => [], propDecorators: { debug: [{ type: i0.Input, args: [{ isSignal: true, alias: "debug", required: false }] }], compactHostClass: [{
4778
+ args: [{ selector: 'dsx-button', imports: [Button, TooltipModule], template: "<!--Bot\u00F3n con las configuraciones din\u00E1micas para CRUD -->\r\n@if (visible()) {\r\n<p-button\r\n [label]=\"buttonLabel\"\r\n [style]=\"buttonStyleComputed()\"\r\n [styleClass]=\"buttonStyleClass\"\r\n [pTooltip]=\"tooltip()\"\r\n [tooltipDisabled]=\"disabled()\"\r\n tooltipPosition=\"top\"\r\n [rounded]=\"rounded()\"\r\n [text]=\"isCompactIconButton\"\r\n [size]=\"buttonSize\"\r\n severity=\"secondary\"\r\n [disabled]=\"disabled()\"\r\n [icon]=\"iconOnly() ? primeIcon : undefined\"\r\n (click)=\"onButtonClick()\"\r\n>\r\n @if (!iconOnly()) {\r\n <span class=\"material-symbols-outlined dsx-button-icon-small\"\r\n >{{ materialIcon }}</span\r\n >\r\n }\r\n</p-button>\r\n}\r\n", styles: [".dsx-button-icon-small{font-size:1.25rem;vertical-align:middle}:host{display:inline-flex;margin-bottom:.25rem}:host.dsx-button-compact-host{margin-bottom:0}:host ::ng-deep .p-button.dsx-button-compact{min-height:2rem;padding-block:.2rem}:host ::ng-deep .p-button .material-symbols-outlined.p-button-icon{line-height:1;vertical-align:middle}:host ::ng-deep .p-button.dsx-button-compact .p-button-icon{margin:0;font-size:1.2rem;line-height:1}:host ::ng-deep .p-button.dsx-button-compact .material-symbols-outlined.p-button-icon{font-variation-settings:\"FILL\" 1,\"wght\" 500,\"GRAD\" 0,\"opsz\" 24}:host ::ng-deep .p-button:disabled,:host ::ng-deep .p-button.p-disabled{cursor:not-allowed!important;opacity:.45!important;filter:grayscale(.2) saturate(.75)}:host ::ng-deep .p-button:disabled *,:host ::ng-deep .p-button.p-disabled *{cursor:not-allowed!important}.p-button.dsx-button-outlined-neutral,.p-button.dsx-button-outlined-info{background:#f5f7fa!important;border:1.5px solid #0066cc!important;color:#06c!important}.p-button.dsx-button-outlined-neutral:disabled,.p-button.dsx-button-outlined-info:disabled{background:#f5f7fa!important;border:1.5px solid #b0bec5!important;color:#b0bec5!important}\n"] }]
4779
+ }], ctorParameters: () => [], propDecorators: { debug: [{ type: i0.Input, args: [{ isSignal: true, alias: "debug", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], compactHostClass: [{
4647
4780
  type: HostBinding,
4648
4781
  args: ['class.dsx-button-compact-host']
4649
4782
  }], type: [{ type: i0.Input, args: [{ isSignal: true, alias: "type", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], routerLink: [{ type: i0.Input, args: [{ isSignal: true, alias: "routerLink", required: false }] }], routerPath: [{ type: i0.Input, args: [{ isSignal: true, alias: "routerPath", required: false }] }], width: [{ type: i0.Input, args: [{ isSignal: true, alias: "width", required: false }] }], iconOnly: [{ type: i0.Input, args: [{ isSignal: true, alias: "iconOnly", required: false }] }], iconOnlyWidth: [{ type: i0.Input, args: [{ isSignal: true, alias: "iconOnlyWidth", required: false }] }], raised: [{ type: i0.Input, args: [{ isSignal: true, alias: "raised", required: false }] }], rounded: [{ type: i0.Input, args: [{ isSignal: true, alias: "rounded", required: false }] }], parameterName: [{ type: i0.Input, args: [{ isSignal: true, alias: "parameterName", required: false }] }], parameterExpectedValue: [{ type: i0.Input, args: [{ isSignal: true, alias: "parameterExpectedValue", required: false }] }], parameterIndex: [{ type: i0.Input, args: [{ isSignal: true, alias: "parameterIndex", required: false }] }], id: [{ type: i0.Input, args: [{ isSignal: true, alias: "id", required: false }] }], requireIdInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "requireIdInput", required: false }] }], requiresIdGreaterThanZero: [{ type: i0.Input, args: [{ isSignal: true, alias: "requiresIdGreaterThanZero", required: false }] }], labelOverride: [{ type: i0.Input, args: [{ isSignal: true, alias: "labelOverride", required: false }] }], tooltipOverride: [{ type: i0.Input, args: [{ isSignal: true, alias: "tooltipOverride", required: false }] }], iconOverride: [{ type: i0.Input, args: [{ isSignal: true, alias: "iconOverride", required: false }] }], primeIconOverride: [{ type: i0.Input, args: [{ isSignal: true, alias: "primeIconOverride", required: false }] }], colorOverride: [{ type: i0.Input, args: [{ isSignal: true, alias: "colorOverride", required: false }] }], outlinedOverride: [{ type: i0.Input, args: [{ isSignal: true, alias: "outlinedOverride", required: false }] }], showValidateButtonOverride: [{ type: i0.Input, args: [{ isSignal: true, alias: "showValidateButtonOverride", required: false }] }], showRestoreButtonOverride: [{ type: i0.Input, args: [{ isSignal: true, alias: "showRestoreButtonOverride", required: false }] }], action: [{ type: i0.Output, args: ["action"] }] } });
@@ -4726,7 +4859,7 @@ const ACTION_CONFIG = {
4726
4859
  details: {
4727
4860
  label: 'Detalles',
4728
4861
  icon: 'list',
4729
- primeIcon: 'pi pi-list',
4862
+ primeIcon: 'fa-solid fa-list-ol',
4730
4863
  colorToken: 'details',
4731
4864
  tooltip: 'Detalle de registro',
4732
4865
  },
@@ -4771,13 +4904,9 @@ class DsxAutocomplete {
4771
4904
  // Inputs usando Señales
4772
4905
  datasource = input.required(...(ngDevMode ? [{ debugName: "datasource" }] : /* istanbul ignore next */ []));
4773
4906
  optionLabel = input.required(...(ngDevMode ? [{ debugName: "optionLabel" }] : /* istanbul ignore next */ []));
4774
- // Label del input (ej: 'Requisitos')
4775
4907
  label = input('Seleccionar', ...(ngDevMode ? [{ debugName: "label" }] : /* istanbul ignore next */ []));
4776
- //Delay por defecto
4777
4908
  delay = input(100, ...(ngDevMode ? [{ debugName: "delay" }] : /* istanbul ignore next */ []));
4778
- // OBLIGATORIO para la creación automática: nombre de la propiedad ID (ej: 'requisitoId')
4779
4909
  idKey = input.required(...(ngDevMode ? [{ debugName: "idKey" }] : /* istanbul ignore next */ []));
4780
- // Opcional para PrimeNG (por defecto toma el valor de idKey para identificar duplicados)
4781
4910
  dataKey = input('', ...(ngDevMode ? [{ debugName: "dataKey" }] : /* istanbul ignore next */ []));
4782
4911
  permitirCrear = input(false, ...(ngDevMode ? [{ debugName: "permitirCrear" }] : /* istanbul ignore next */ []));
4783
4912
  debug = input(false, ...(ngDevMode ? [{ debugName: "debug" }] : /* istanbul ignore next */ []));
@@ -4788,20 +4917,30 @@ class DsxAutocomplete {
4788
4917
  onChange = () => { };
4789
4918
  onTouched = () => { };
4790
4919
  disabled = false;
4920
+ lastLogTime = 0;
4921
+ timeoutLimpieza = null;
4922
+ logDebug(message, data) {
4923
+ if (!this.debug())
4924
+ return;
4925
+ const now = Date.now();
4926
+ if (now - this.lastLogTime < 50)
4927
+ return;
4928
+ this.lastLogTime = now;
4929
+ console.log(`[DsxAutocomplete] ${message}`, data || '');
4930
+ }
4791
4931
  searchRequisitos(event) {
4792
4932
  const inicio = performance.now();
4793
4933
  const label = this.optionLabel();
4794
- // FLUJO A: El usuario hizo clic en el botón dropdown (Texto vacío)
4934
+ // FLUJO A: Dropdown (sin texto)
4795
4935
  if (!event.query || event.query.trim() === '') {
4796
- // Cargamos TODO el universo de datos para que el usuario pueda navegar libremente
4797
4936
  const todoElUniverso = this.datasource();
4798
4937
  this.dataFiltrada.set(todoElUniverso);
4799
- if (this.debug()) {
4800
- console.log('[DsxAutocomplete] Modo dropdown activo: Mostrando lista completa de registros:', todoElUniverso.length);
4801
- }
4938
+ this.logDebug('Modo dropdown activo', {
4939
+ registros: todoElUniverso.length,
4940
+ });
4802
4941
  return;
4803
4942
  }
4804
- // FLUJO B: El usuario está escribiendo (Búsqueda inteligente con límite de 10)
4943
+ // FLUJO B: Búsqueda
4805
4944
  const palabrasBuscadas = event.query
4806
4945
  .toLowerCase()
4807
4946
  .trim()
@@ -4812,25 +4951,26 @@ class DsxAutocomplete {
4812
4951
  const textoRegistro = String(item[label] || '').toLowerCase();
4813
4952
  return palabrasBuscadas.every((palabra) => textoRegistro.includes(palabra));
4814
4953
  })
4815
- .slice(0, 10); // <-- El límite se aplica estrictamente al escribir
4954
+ .slice(0, 10);
4816
4955
  this.dataFiltrada.set(filtrados);
4817
- if (this.debug()) {
4818
- console.log(`[DsxAutocomplete] Búsqueda inteligente para "${event.query}" tardó ${(performance.now() - inicio).toFixed(2)}ms. Encontrados:`, filtrados.length);
4819
- }
4956
+ this.logDebug(`Búsqueda "${event.query}" (${(performance.now() - inicio).toFixed(2)}ms)`, { encontrados: filtrados.length });
4820
4957
  }
4821
4958
  evaluarYAgregar(event) {
4822
4959
  const valorInput = event.target.value?.trim();
4823
- if (!valorInput)
4960
+ if (!valorInput) {
4961
+ this.dataFiltrada.set([]);
4824
4962
  return;
4963
+ }
4825
4964
  const sugerencias = this.dataFiltrada();
4826
4965
  const actuales = this.value || [];
4827
- const campoId = this.idKey(); // Obtenemos de forma segura el nombre del ID stringificado
4966
+ const campoId = this.idKey();
4828
4967
  if (sugerencias.length > 0) {
4829
4968
  const primeraMatch = sugerencias[0];
4830
- // Comparamos identidades usando el campoId dinámico
4831
4969
  const yaExiste = actuales.some((item) => item[campoId] === primeraMatch[campoId]);
4832
- if (!yaExiste)
4970
+ if (!yaExiste) {
4833
4971
  this.actualizarFormulario([...actuales, primeraMatch]);
4972
+ this.logDebug('✅ Elemento agregado');
4973
+ }
4834
4974
  }
4835
4975
  else if (this.permitirCrear()) {
4836
4976
  let nuevo;
@@ -4838,7 +4978,6 @@ class DsxAutocomplete {
4838
4978
  nuevo = this.factoryNuevoRegistro()(valorInput);
4839
4979
  }
4840
4980
  else {
4841
- // Al estructurar el objeto usando [campoId], garantizamos que viaje con el nombre correcto de tu entidad
4842
4981
  nuevo = {
4843
4982
  [campoId]: 0,
4844
4983
  [this.optionLabel()]: valorInput.toUpperCase(),
@@ -4846,19 +4985,47 @@ class DsxAutocomplete {
4846
4985
  };
4847
4986
  }
4848
4987
  this.actualizarFormulario([...actuales, nuevo]);
4988
+ this.logDebug('🆕 Nuevo elemento creado', valorInput);
4849
4989
  }
4850
4990
  event.target.value = '';
4851
4991
  this.dataFiltrada.set([]);
4852
4992
  }
4993
+ onHide() {
4994
+ this.logDebug('Dropdown ocultado - Limpiando estado');
4995
+ // Limpiar timeout anterior si existe
4996
+ if (this.timeoutLimpieza) {
4997
+ clearTimeout(this.timeoutLimpieza);
4998
+ this.timeoutLimpieza = null;
4999
+ }
5000
+ // Limpiar después de un pequeño delay
5001
+ this.timeoutLimpieza = setTimeout(() => {
5002
+ this.dataFiltrada.set([]);
5003
+ this.timeoutLimpieza = null;
5004
+ }, 100);
5005
+ }
5006
+ onShow() {
5007
+ this.logDebug('Dropdown mostrado');
5008
+ // Limpiar timeout pendiente
5009
+ if (this.timeoutLimpieza) {
5010
+ clearTimeout(this.timeoutLimpieza);
5011
+ this.timeoutLimpieza = null;
5012
+ }
5013
+ }
4853
5014
  actualizarFormulario(nuevaLista) {
4854
5015
  this.value = nuevaLista;
4855
5016
  this.onChange(this.value);
4856
- if (this.debug())
4857
- console.log('[DsxAutocomplete] Estado del Formulario Actualizado con Objetos:', this.value);
5017
+ this.logDebug('Formulario actualizado', {
5018
+ total: nuevaLista.length,
5019
+ });
4858
5020
  }
4859
5021
  // --- ControlValueAccessor ---
4860
5022
  writeValue(value) {
4861
5023
  this.value = value || [];
5024
+ this.dataFiltrada.set([]);
5025
+ if (this.timeoutLimpieza) {
5026
+ clearTimeout(this.timeoutLimpieza);
5027
+ this.timeoutLimpieza = null;
5028
+ }
4862
5029
  }
4863
5030
  registerOnChange(fn) {
4864
5031
  this.onChange = fn;
@@ -4876,7 +5043,7 @@ class DsxAutocomplete {
4876
5043
  useExisting: forwardRef(() => DsxAutocomplete),
4877
5044
  multi: true,
4878
5045
  },
4879
- ], ngImport: i0, template: "<p-floatlabel variant=\"on\">\r\n <p-autoComplete\r\n fluid\r\n multiple\r\n [dropdown]=\"true\"\r\n [suggestions]=\"dataFiltrada()\"\r\n (completeMethod)=\"searchRequisitos($event)\"\r\n [(ngModel)]=\"value\"\r\n (ngModelChange)=\"onChange(value)\"\r\n (onBlur)=\"onTouched()\"\r\n [disabled]=\"disabled\"\r\n [optionLabel]=\"optionLabel()\"\r\n [dataKey]=\"dataKey() || idKey()\"\r\n (keyup.enter)=\"evaluarYAgregar($event)\"\r\n [delay]=\"delay()\"\r\n >\r\n </p-autoComplete>\r\n <label>{{ label() }}</label>\r\n</p-floatlabel>\r\n", styles: [""], dependencies: [{ kind: "component", type: AutoComplete, selector: "p-autoComplete, p-autocomplete, p-auto-complete", inputs: ["minLength", "minQueryLength", "delay", "panelStyle", "styleClass", "panelStyleClass", "inputStyle", "inputId", "inputStyleClass", "placeholder", "readonly", "scrollHeight", "lazy", "virtualScroll", "virtualScrollItemSize", "virtualScrollOptions", "autoHighlight", "forceSelection", "type", "autoZIndex", "baseZIndex", "ariaLabel", "dropdownAriaLabel", "ariaLabelledBy", "dropdownIcon", "unique", "group", "completeOnFocus", "showClear", "dropdown", "showEmptyMessage", "dropdownMode", "multiple", "addOnTab", "tabindex", "dataKey", "emptyMessage", "showTransitionOptions", "hideTransitionOptions", "autofocus", "autocomplete", "optionGroupChildren", "optionGroupLabel", "overlayOptions", "suggestions", "optionLabel", "optionValue", "id", "searchMessage", "emptySelectionMessage", "selectionMessage", "autoOptionFocus", "selectOnFocus", "searchLocale", "optionDisabled", "focusOnHover", "typeahead", "addOnBlur", "separator", "appendTo", "motionOptions"], outputs: ["completeMethod", "onSelect", "onUnselect", "onAdd", "onFocus", "onBlur", "onDropdownClick", "onClear", "onInputKeydown", "onKeyUp", "onShow", "onHide", "onLazyLoad"] }, { kind: "ngmodule", type: FormsModule }, { 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: "component", type: FloatLabel, selector: "p-floatlabel, p-floatLabel, p-float-label", inputs: ["variant"] }] });
5046
+ ], ngImport: i0, template: "<p-floatlabel variant=\"on\">\r\n <p-autoComplete\r\n fluid\r\n multiple\r\n [dropdown]=\"true\"\r\n [suggestions]=\"dataFiltrada()\"\r\n (completeMethod)=\"searchRequisitos($event)\"\r\n [(ngModel)]=\"value\"\r\n (ngModelChange)=\"onChange(value)\"\r\n (onBlur)=\"onTouched()\"\r\n (onShow)=\"onShow()\"\r\n (onHide)=\"onHide()\"\r\n [disabled]=\"disabled\"\r\n [optionLabel]=\"optionLabel()\"\r\n [dataKey]=\"dataKey() || idKey()\"\r\n (keyup.enter)=\"evaluarYAgregar($event)\"\r\n [delay]=\"delay()\"\r\n placeholder=\"Ingresa un texto....\"\r\n >\r\n </p-autoComplete>\r\n <label>{{ label() }}</label>\r\n</p-floatlabel>\r\n", styles: [""], dependencies: [{ kind: "component", type: AutoComplete, selector: "p-autoComplete, p-autocomplete, p-auto-complete", inputs: ["minLength", "minQueryLength", "delay", "panelStyle", "styleClass", "panelStyleClass", "inputStyle", "inputId", "inputStyleClass", "placeholder", "readonly", "scrollHeight", "lazy", "virtualScroll", "virtualScrollItemSize", "virtualScrollOptions", "autoHighlight", "forceSelection", "type", "autoZIndex", "baseZIndex", "ariaLabel", "dropdownAriaLabel", "ariaLabelledBy", "dropdownIcon", "unique", "group", "completeOnFocus", "showClear", "dropdown", "showEmptyMessage", "dropdownMode", "multiple", "addOnTab", "tabindex", "dataKey", "emptyMessage", "showTransitionOptions", "hideTransitionOptions", "autofocus", "autocomplete", "optionGroupChildren", "optionGroupLabel", "overlayOptions", "suggestions", "optionLabel", "optionValue", "id", "searchMessage", "emptySelectionMessage", "selectionMessage", "autoOptionFocus", "selectOnFocus", "searchLocale", "optionDisabled", "focusOnHover", "typeahead", "addOnBlur", "separator", "appendTo", "motionOptions"], outputs: ["completeMethod", "onSelect", "onUnselect", "onAdd", "onFocus", "onBlur", "onDropdownClick", "onClear", "onInputKeydown", "onKeyUp", "onShow", "onHide", "onLazyLoad"] }, { kind: "ngmodule", type: FormsModule }, { 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: "component", type: FloatLabel, selector: "p-floatlabel, p-floatLabel, p-float-label", inputs: ["variant"] }] });
4880
5047
  }
4881
5048
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: DsxAutocomplete, decorators: [{
4882
5049
  type: Component,
@@ -4886,13 +5053,14 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImpo
4886
5053
  useExisting: forwardRef(() => DsxAutocomplete),
4887
5054
  multi: true,
4888
5055
  },
4889
- ], template: "<p-floatlabel variant=\"on\">\r\n <p-autoComplete\r\n fluid\r\n multiple\r\n [dropdown]=\"true\"\r\n [suggestions]=\"dataFiltrada()\"\r\n (completeMethod)=\"searchRequisitos($event)\"\r\n [(ngModel)]=\"value\"\r\n (ngModelChange)=\"onChange(value)\"\r\n (onBlur)=\"onTouched()\"\r\n [disabled]=\"disabled\"\r\n [optionLabel]=\"optionLabel()\"\r\n [dataKey]=\"dataKey() || idKey()\"\r\n (keyup.enter)=\"evaluarYAgregar($event)\"\r\n [delay]=\"delay()\"\r\n >\r\n </p-autoComplete>\r\n <label>{{ label() }}</label>\r\n</p-floatlabel>\r\n" }]
5056
+ ], template: "<p-floatlabel variant=\"on\">\r\n <p-autoComplete\r\n fluid\r\n multiple\r\n [dropdown]=\"true\"\r\n [suggestions]=\"dataFiltrada()\"\r\n (completeMethod)=\"searchRequisitos($event)\"\r\n [(ngModel)]=\"value\"\r\n (ngModelChange)=\"onChange(value)\"\r\n (onBlur)=\"onTouched()\"\r\n (onShow)=\"onShow()\"\r\n (onHide)=\"onHide()\"\r\n [disabled]=\"disabled\"\r\n [optionLabel]=\"optionLabel()\"\r\n [dataKey]=\"dataKey() || idKey()\"\r\n (keyup.enter)=\"evaluarYAgregar($event)\"\r\n [delay]=\"delay()\"\r\n placeholder=\"Ingresa un texto....\"\r\n >\r\n </p-autoComplete>\r\n <label>{{ label() }}</label>\r\n</p-floatlabel>\r\n" }]
4890
5057
  }], propDecorators: { datasource: [{ type: i0.Input, args: [{ isSignal: true, alias: "datasource", required: true }] }], optionLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "optionLabel", required: true }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], delay: [{ type: i0.Input, args: [{ isSignal: true, alias: "delay", required: false }] }], idKey: [{ type: i0.Input, args: [{ isSignal: true, alias: "idKey", required: true }] }], dataKey: [{ type: i0.Input, args: [{ isSignal: true, alias: "dataKey", required: false }] }], permitirCrear: [{ type: i0.Input, args: [{ isSignal: true, alias: "permitirCrear", required: false }] }], debug: [{ type: i0.Input, args: [{ isSignal: true, alias: "debug", required: false }] }], factoryNuevoRegistro: [{ type: i0.Input, args: [{ isSignal: true, alias: "factoryNuevoRegistro", required: false }] }] } });
4891
5058
 
4892
5059
  class FileComponent {
4893
5060
  // Inputs
4894
5061
  existingFile = input(null, ...(ngDevMode ? [{ debugName: "existingFile" }] : /* istanbul ignore next */ []));
4895
5062
  existingFileName = input(null, ...(ngDevMode ? [{ debugName: "existingFileName" }] : /* istanbul ignore next */ []));
5063
+ overrideFileName = input(null, ...(ngDevMode ? [{ debugName: "overrideFileName" }] : /* istanbul ignore next */ []));
4896
5064
  debug = input(false, ...(ngDevMode ? [{ debugName: "debug" }] : /* istanbul ignore next */ []));
4897
5065
  required = input(true, ...(ngDevMode ? [{ debugName: "required" }] : /* istanbul ignore next */ []));
4898
5066
  accept = input('.xls,.xlsx', ...(ngDevMode ? [{ debugName: "accept" }] : /* istanbul ignore next */ []));
@@ -5101,7 +5269,7 @@ class FileComponent {
5101
5269
  console.log(`[FileComponent] ${method}`, data || '');
5102
5270
  }
5103
5271
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: FileComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
5104
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.17", type: FileComponent, isStandalone: true, selector: "dsx-file-upload", inputs: { existingFile: { classPropertyName: "existingFile", publicName: "existingFile", isSignal: true, isRequired: false, transformFunction: null }, existingFileName: { classPropertyName: "existingFileName", publicName: "existingFileName", isSignal: true, isRequired: false, transformFunction: null }, debug: { classPropertyName: "debug", publicName: "debug", isSignal: true, isRequired: false, transformFunction: null }, required: { classPropertyName: "required", publicName: "required", isSignal: true, isRequired: false, transformFunction: null }, accept: { classPropertyName: "accept", publicName: "accept", isSignal: true, isRequired: false, transformFunction: null }, pTooltipOverride: { classPropertyName: "pTooltipOverride", publicName: "pTooltipOverride", isSignal: true, isRequired: false, transformFunction: null }, tooltipPositionOverride: { classPropertyName: "tooltipPositionOverride", publicName: "tooltipPositionOverride", isSignal: true, isRequired: false, transformFunction: null }, maxFileSize: { classPropertyName: "maxFileSize", publicName: "maxFileSize", isSignal: true, isRequired: false, transformFunction: null }, invalidSummary: { classPropertyName: "invalidSummary", publicName: "invalidSummary", isSignal: true, isRequired: false, transformFunction: null }, invalidDetail: { classPropertyName: "invalidDetail", publicName: "invalidDetail", isSignal: true, isRequired: false, transformFunction: null }, invalidSizeSummary: { classPropertyName: "invalidSizeSummary", publicName: "invalidSizeSummary", isSignal: true, isRequired: false, transformFunction: null }, invalidSizeDetail: { classPropertyName: "invalidSizeDetail", publicName: "invalidSizeDetail", isSignal: true, isRequired: false, transformFunction: null } }, providers: [
5272
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.17", type: FileComponent, isStandalone: true, selector: "dsx-file-upload", inputs: { existingFile: { classPropertyName: "existingFile", publicName: "existingFile", isSignal: true, isRequired: false, transformFunction: null }, existingFileName: { classPropertyName: "existingFileName", publicName: "existingFileName", isSignal: true, isRequired: false, transformFunction: null }, overrideFileName: { classPropertyName: "overrideFileName", publicName: "overrideFileName", isSignal: true, isRequired: false, transformFunction: null }, debug: { classPropertyName: "debug", publicName: "debug", isSignal: true, isRequired: false, transformFunction: null }, required: { classPropertyName: "required", publicName: "required", isSignal: true, isRequired: false, transformFunction: null }, accept: { classPropertyName: "accept", publicName: "accept", isSignal: true, isRequired: false, transformFunction: null }, pTooltipOverride: { classPropertyName: "pTooltipOverride", publicName: "pTooltipOverride", isSignal: true, isRequired: false, transformFunction: null }, tooltipPositionOverride: { classPropertyName: "tooltipPositionOverride", publicName: "tooltipPositionOverride", isSignal: true, isRequired: false, transformFunction: null }, maxFileSize: { classPropertyName: "maxFileSize", publicName: "maxFileSize", isSignal: true, isRequired: false, transformFunction: null }, invalidSummary: { classPropertyName: "invalidSummary", publicName: "invalidSummary", isSignal: true, isRequired: false, transformFunction: null }, invalidDetail: { classPropertyName: "invalidDetail", publicName: "invalidDetail", isSignal: true, isRequired: false, transformFunction: null }, invalidSizeSummary: { classPropertyName: "invalidSizeSummary", publicName: "invalidSizeSummary", isSignal: true, isRequired: false, transformFunction: null }, invalidSizeDetail: { classPropertyName: "invalidSizeDetail", publicName: "invalidSizeDetail", isSignal: true, isRequired: false, transformFunction: null } }, providers: [
5105
5273
  {
5106
5274
  provide: NG_VALUE_ACCESSOR,
5107
5275
  useExisting: forwardRef(() => FileComponent),
@@ -5112,7 +5280,7 @@ class FileComponent {
5112
5280
  useExisting: forwardRef(() => FileComponent),
5113
5281
  multi: true,
5114
5282
  },
5115
- ], viewQueries: [{ propertyName: "fileUpload", first: true, predicate: ["fileUpload"], descendants: true, isSignal: true }], ngImport: i0, template: "@if (showExistingFile() && !existingFile()) {\r\n <div class=\"flex items-center gap-2\">\r\n <span class=\"file-name\"> \uD83D\uDCC4 {{ existingFileName() }} </span>\r\n\r\n <p-button\r\n icon=\"pi pi-cloud-upload\"\r\n [rounded]=\"true\"\r\n severity=\"info\"\r\n (click)=\"startReplace()\"\r\n [disabled]=\"isReplaceButtonDisabled()\"\r\n pTooltip=\"Reemplazar archivo\"\r\n tooltipPosition=\"top\"\r\n />\r\n </div>\r\n} @else {\r\n <div class=\"flex items-center gap-2\">\r\n <p-fileUpload\r\n #fileUpload\r\n mode=\"basic\"\r\n [accept]=\"accept()\"\r\n [maxFileSize]=\"maxFileSize() * 1024 * 1024\"\r\n [invalidFileTypeMessageSummary]=\"invalidSummary()\"\r\n [invalidFileTypeMessageDetail]=\"invalidDetail()\"\r\n [invalidFileSizeMessageSummary]=\"invalidSizeSummary()\"\r\n [invalidFileSizeMessageDetail]=\"invalidSizeDetail()\"\r\n (onSelect)=\"onSelect($event)\"\r\n [disabled]=\"!isFileUploadEnabled()\"\r\n [pTooltip]=\"pTooltipOverride()\"\r\n [tooltipPosition]=\"tooltipPositionOverride()\"\r\n />\r\n\r\n @if (isReplacing() || existingFile()) {\r\n <p-button\r\n icon=\"pi pi-times\"\r\n [rounded]=\"true\"\r\n severity=\"secondary\"\r\n (click)=\"cancelReplace()\"\r\n [disabled]=\"disabled()\"\r\n pTooltip=\"Cancelar reemplazo\"\r\n tooltipPosition=\"top\"\r\n />\r\n }\r\n </div>\r\n}\r\n", styles: [".file-name{display:inline-block;font-size:clamp(.85rem,1vw + .5rem,1.4rem);font-weight:500;color:#2c3e50;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:100%}\n"], dependencies: [{ kind: "component", type: FileUpload, selector: "p-fileupload, p-fileUpload", inputs: ["name", "url", "method", "multiple", "accept", "disabled", "auto", "withCredentials", "maxFileSize", "invalidFileSizeMessageSummary", "invalidFileSizeMessageDetail", "invalidFileTypeMessageSummary", "invalidFileTypeMessageDetail", "invalidFileLimitMessageDetail", "invalidFileLimitMessageSummary", "style", "styleClass", "previewWidth", "chooseLabel", "uploadLabel", "cancelLabel", "chooseIcon", "uploadIcon", "cancelIcon", "showUploadButton", "showCancelButton", "mode", "headers", "customUpload", "fileLimit", "uploadStyleClass", "cancelStyleClass", "removeStyleClass", "chooseStyleClass", "chooseButtonProps", "uploadButtonProps", "cancelButtonProps", "files"], outputs: ["onBeforeUpload", "onSend", "onUpload", "onError", "onClear", "onRemove", "onSelect", "onProgress", "uploadHandler", "onImageError", "onRemoveUploadedFile"] }, { kind: "directive", type: Tooltip, selector: "[pTooltip]", inputs: ["tooltipPosition", "tooltipEvent", "positionStyle", "tooltipStyleClass", "tooltipZIndex", "escape", "showDelay", "hideDelay", "life", "positionTop", "positionLeft", "autoHide", "fitContent", "hideOnEscape", "showOnEllipsis", "pTooltip", "tooltipDisabled", "tooltipOptions", "appendTo", "ptTooltip", "pTooltipPT", "pTooltipUnstyled"] }, { kind: "component", type: Button, selector: "p-button", inputs: ["hostName", "type", "badge", "disabled", "raised", "rounded", "text", "plain", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "autofocus", "iconPos", "icon", "label", "loading", "loadingIcon", "severity", "buttonProps", "fluid"], outputs: ["onClick", "onFocus", "onBlur"] }] });
5283
+ ], viewQueries: [{ propertyName: "fileUpload", first: true, predicate: ["fileUpload"], descendants: true, isSignal: true }], ngImport: i0, template: "@if (showExistingFile() && !existingFile()) {\r\n <div class=\"flex items-center gap-2\">\r\n <span class=\"file-name\">\r\n \uD83D\uDCC4 {{ overrideFileName() ?? existingFileName() }}\r\n </span>\r\n\r\n <p-button\r\n icon=\"pi pi-cloud-upload\"\r\n [rounded]=\"true\"\r\n severity=\"info\"\r\n (click)=\"startReplace()\"\r\n [disabled]=\"isReplaceButtonDisabled()\"\r\n pTooltip=\"Reemplazar archivo\"\r\n tooltipPosition=\"top\"\r\n />\r\n </div>\r\n} @else {\r\n <div class=\"flex items-center gap-2\">\r\n <p-fileUpload\r\n #fileUpload\r\n mode=\"basic\"\r\n [accept]=\"accept()\"\r\n [maxFileSize]=\"maxFileSize() * 1024 * 1024\"\r\n [invalidFileTypeMessageSummary]=\"invalidSummary()\"\r\n [invalidFileTypeMessageDetail]=\"invalidDetail()\"\r\n [invalidFileSizeMessageSummary]=\"invalidSizeSummary()\"\r\n [invalidFileSizeMessageDetail]=\"invalidSizeDetail()\"\r\n (onSelect)=\"onSelect($event)\"\r\n [disabled]=\"!isFileUploadEnabled()\"\r\n [pTooltip]=\"pTooltipOverride()\"\r\n [tooltipPosition]=\"tooltipPositionOverride()\"\r\n />\r\n\r\n @if (isReplacing() || existingFile()) {\r\n <p-button\r\n icon=\"pi pi-times\"\r\n [rounded]=\"true\"\r\n severity=\"secondary\"\r\n (click)=\"cancelReplace()\"\r\n [disabled]=\"disabled()\"\r\n pTooltip=\"Cancelar reemplazo\"\r\n tooltipPosition=\"top\"\r\n />\r\n }\r\n </div>\r\n}\r\n", styles: [".file-name{display:inline-block;font-size:clamp(.85rem,1vw + .5rem,1.4rem);font-weight:500;color:#2c3e50;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:100%}\n"], dependencies: [{ kind: "component", type: FileUpload, selector: "p-fileupload, p-fileUpload", inputs: ["name", "url", "method", "multiple", "accept", "disabled", "auto", "withCredentials", "maxFileSize", "invalidFileSizeMessageSummary", "invalidFileSizeMessageDetail", "invalidFileTypeMessageSummary", "invalidFileTypeMessageDetail", "invalidFileLimitMessageDetail", "invalidFileLimitMessageSummary", "style", "styleClass", "previewWidth", "chooseLabel", "uploadLabel", "cancelLabel", "chooseIcon", "uploadIcon", "cancelIcon", "showUploadButton", "showCancelButton", "mode", "headers", "customUpload", "fileLimit", "uploadStyleClass", "cancelStyleClass", "removeStyleClass", "chooseStyleClass", "chooseButtonProps", "uploadButtonProps", "cancelButtonProps", "files"], outputs: ["onBeforeUpload", "onSend", "onUpload", "onError", "onClear", "onRemove", "onSelect", "onProgress", "uploadHandler", "onImageError", "onRemoveUploadedFile"] }, { kind: "directive", type: Tooltip, selector: "[pTooltip]", inputs: ["tooltipPosition", "tooltipEvent", "positionStyle", "tooltipStyleClass", "tooltipZIndex", "escape", "showDelay", "hideDelay", "life", "positionTop", "positionLeft", "autoHide", "fitContent", "hideOnEscape", "showOnEllipsis", "pTooltip", "tooltipDisabled", "tooltipOptions", "appendTo", "ptTooltip", "pTooltipPT", "pTooltipUnstyled"] }, { kind: "component", type: Button, selector: "p-button", inputs: ["hostName", "type", "badge", "disabled", "raised", "rounded", "text", "plain", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "autofocus", "iconPos", "icon", "label", "loading", "loadingIcon", "severity", "buttonProps", "fluid"], outputs: ["onClick", "onFocus", "onBlur"] }] });
5116
5284
  }
5117
5285
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: FileComponent, decorators: [{
5118
5286
  type: Component,
@@ -5127,8 +5295,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImpo
5127
5295
  useExisting: forwardRef(() => FileComponent),
5128
5296
  multi: true,
5129
5297
  },
5130
- ], template: "@if (showExistingFile() && !existingFile()) {\r\n <div class=\"flex items-center gap-2\">\r\n <span class=\"file-name\"> \uD83D\uDCC4 {{ existingFileName() }} </span>\r\n\r\n <p-button\r\n icon=\"pi pi-cloud-upload\"\r\n [rounded]=\"true\"\r\n severity=\"info\"\r\n (click)=\"startReplace()\"\r\n [disabled]=\"isReplaceButtonDisabled()\"\r\n pTooltip=\"Reemplazar archivo\"\r\n tooltipPosition=\"top\"\r\n />\r\n </div>\r\n} @else {\r\n <div class=\"flex items-center gap-2\">\r\n <p-fileUpload\r\n #fileUpload\r\n mode=\"basic\"\r\n [accept]=\"accept()\"\r\n [maxFileSize]=\"maxFileSize() * 1024 * 1024\"\r\n [invalidFileTypeMessageSummary]=\"invalidSummary()\"\r\n [invalidFileTypeMessageDetail]=\"invalidDetail()\"\r\n [invalidFileSizeMessageSummary]=\"invalidSizeSummary()\"\r\n [invalidFileSizeMessageDetail]=\"invalidSizeDetail()\"\r\n (onSelect)=\"onSelect($event)\"\r\n [disabled]=\"!isFileUploadEnabled()\"\r\n [pTooltip]=\"pTooltipOverride()\"\r\n [tooltipPosition]=\"tooltipPositionOverride()\"\r\n />\r\n\r\n @if (isReplacing() || existingFile()) {\r\n <p-button\r\n icon=\"pi pi-times\"\r\n [rounded]=\"true\"\r\n severity=\"secondary\"\r\n (click)=\"cancelReplace()\"\r\n [disabled]=\"disabled()\"\r\n pTooltip=\"Cancelar reemplazo\"\r\n tooltipPosition=\"top\"\r\n />\r\n }\r\n </div>\r\n}\r\n", styles: [".file-name{display:inline-block;font-size:clamp(.85rem,1vw + .5rem,1.4rem);font-weight:500;color:#2c3e50;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:100%}\n"] }]
5131
- }], ctorParameters: () => [], propDecorators: { existingFile: [{ type: i0.Input, args: [{ isSignal: true, alias: "existingFile", required: false }] }], existingFileName: [{ type: i0.Input, args: [{ isSignal: true, alias: "existingFileName", required: false }] }], debug: [{ type: i0.Input, args: [{ isSignal: true, alias: "debug", required: false }] }], required: [{ type: i0.Input, args: [{ isSignal: true, alias: "required", required: false }] }], accept: [{ type: i0.Input, args: [{ isSignal: true, alias: "accept", required: false }] }], pTooltipOverride: [{ type: i0.Input, args: [{ isSignal: true, alias: "pTooltipOverride", required: false }] }], tooltipPositionOverride: [{ type: i0.Input, args: [{ isSignal: true, alias: "tooltipPositionOverride", required: false }] }], maxFileSize: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxFileSize", required: false }] }], invalidSummary: [{ type: i0.Input, args: [{ isSignal: true, alias: "invalidSummary", required: false }] }], invalidDetail: [{ type: i0.Input, args: [{ isSignal: true, alias: "invalidDetail", required: false }] }], invalidSizeSummary: [{ type: i0.Input, args: [{ isSignal: true, alias: "invalidSizeSummary", required: false }] }], invalidSizeDetail: [{ type: i0.Input, args: [{ isSignal: true, alias: "invalidSizeDetail", required: false }] }], fileUpload: [{ type: i0.ViewChild, args: ['fileUpload', { isSignal: true }] }] } });
5298
+ ], template: "@if (showExistingFile() && !existingFile()) {\r\n <div class=\"flex items-center gap-2\">\r\n <span class=\"file-name\">\r\n \uD83D\uDCC4 {{ overrideFileName() ?? existingFileName() }}\r\n </span>\r\n\r\n <p-button\r\n icon=\"pi pi-cloud-upload\"\r\n [rounded]=\"true\"\r\n severity=\"info\"\r\n (click)=\"startReplace()\"\r\n [disabled]=\"isReplaceButtonDisabled()\"\r\n pTooltip=\"Reemplazar archivo\"\r\n tooltipPosition=\"top\"\r\n />\r\n </div>\r\n} @else {\r\n <div class=\"flex items-center gap-2\">\r\n <p-fileUpload\r\n #fileUpload\r\n mode=\"basic\"\r\n [accept]=\"accept()\"\r\n [maxFileSize]=\"maxFileSize() * 1024 * 1024\"\r\n [invalidFileTypeMessageSummary]=\"invalidSummary()\"\r\n [invalidFileTypeMessageDetail]=\"invalidDetail()\"\r\n [invalidFileSizeMessageSummary]=\"invalidSizeSummary()\"\r\n [invalidFileSizeMessageDetail]=\"invalidSizeDetail()\"\r\n (onSelect)=\"onSelect($event)\"\r\n [disabled]=\"!isFileUploadEnabled()\"\r\n [pTooltip]=\"pTooltipOverride()\"\r\n [tooltipPosition]=\"tooltipPositionOverride()\"\r\n />\r\n\r\n @if (isReplacing() || existingFile()) {\r\n <p-button\r\n icon=\"pi pi-times\"\r\n [rounded]=\"true\"\r\n severity=\"secondary\"\r\n (click)=\"cancelReplace()\"\r\n [disabled]=\"disabled()\"\r\n pTooltip=\"Cancelar reemplazo\"\r\n tooltipPosition=\"top\"\r\n />\r\n }\r\n </div>\r\n}\r\n", styles: [".file-name{display:inline-block;font-size:clamp(.85rem,1vw + .5rem,1.4rem);font-weight:500;color:#2c3e50;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:100%}\n"] }]
5299
+ }], ctorParameters: () => [], propDecorators: { existingFile: [{ type: i0.Input, args: [{ isSignal: true, alias: "existingFile", required: false }] }], existingFileName: [{ type: i0.Input, args: [{ isSignal: true, alias: "existingFileName", required: false }] }], overrideFileName: [{ type: i0.Input, args: [{ isSignal: true, alias: "overrideFileName", required: false }] }], debug: [{ type: i0.Input, args: [{ isSignal: true, alias: "debug", required: false }] }], required: [{ type: i0.Input, args: [{ isSignal: true, alias: "required", required: false }] }], accept: [{ type: i0.Input, args: [{ isSignal: true, alias: "accept", required: false }] }], pTooltipOverride: [{ type: i0.Input, args: [{ isSignal: true, alias: "pTooltipOverride", required: false }] }], tooltipPositionOverride: [{ type: i0.Input, args: [{ isSignal: true, alias: "tooltipPositionOverride", required: false }] }], maxFileSize: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxFileSize", required: false }] }], invalidSummary: [{ type: i0.Input, args: [{ isSignal: true, alias: "invalidSummary", required: false }] }], invalidDetail: [{ type: i0.Input, args: [{ isSignal: true, alias: "invalidDetail", required: false }] }], invalidSizeSummary: [{ type: i0.Input, args: [{ isSignal: true, alias: "invalidSizeSummary", required: false }] }], invalidSizeDetail: [{ type: i0.Input, args: [{ isSignal: true, alias: "invalidSizeDetail", required: false }] }], fileUpload: [{ type: i0.ViewChild, args: ['fileUpload', { isSignal: true }] }] } });
5132
5300
 
5133
5301
  class JsonHighlightPipe {
5134
5302
  /**
@@ -5302,11 +5470,11 @@ class JsonValuesDebujComponent {
5302
5470
  }
5303
5471
  }
5304
5472
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JsonValuesDebujComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
5305
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.17", type: JsonValuesDebujComponent, isStandalone: true, selector: "app-json-values-debuj", inputs: { form: { classPropertyName: "form", publicName: "form", isSignal: true, isRequired: false, transformFunction: null }, debug: { classPropertyName: "debug", publicName: "debug", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "@if (form() && shouldShowVisual) {\r\n <div class=\"custom-container\">\r\n <pre class=\"custom-pre\" [innerHTML]=\"debugValue() | jsonHighlight\"></pre>\r\n </div>\r\n}\r\n", styles: [".custom-container{width:100%;overflow:auto;max-height:700px;background:#1e1e1e;border:1px solid #333;border-radius:8px;box-shadow:0 4px 12px #0000004d;padding:1.25rem;margin-bottom:1.25rem}.custom-pre{margin:0;white-space:pre-wrap;word-break:break-word;word-wrap:break-word;font-family:Segoe UI,Fira Code,JetBrains Mono,Consolas,Monaco,Courier New,monospace;font-size:15px;line-height:1.65;color:#d4d4d4;font-weight:400}.json-key{color:#9cdcfe;font-weight:600;font-size:15px}.json-string{color:#ce9178;font-size:15px}.json-number{color:#b5cea8;font-weight:600;font-size:15px}.json-boolean{color:#569cd6;font-weight:700;font-size:15px}.json-null{color:gray;font-style:italic;font-size:15px}.json-bracket{color:gold;font-weight:700;font-size:16px}.json-colon{color:#d4d4d4;font-weight:500}.json-comma{color:gray;font-size:14px}.json-date-part{color:#4fc1ff;font-weight:600;font-size:15px}.json-date-sep{color:gray}.json-date-time{color:#c586c0;font-size:15px}.custom-container::-webkit-scrollbar{width:12px;height:12px}.custom-container::-webkit-scrollbar-track{background:#252526;border-radius:6px}.custom-container::-webkit-scrollbar-thumb{background:#555;border-radius:6px;transition:background .2s ease}.custom-container::-webkit-scrollbar-thumb:hover{background:#777}.custom-container::-webkit-scrollbar-corner{background:#1e1e1e}.custom-container{font-smooth:antialiased;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.custom-pre:hover{background:#252526;transition:background .2s ease;cursor:text}.json-null,.json-undefined{color:#f48771;font-style:italic;opacity:.8}.json-empty{color:gray;font-style:italic}.json-comma+br{margin-bottom:2px}\n"], dependencies: [{ kind: "pipe", type: JsonHighlightPipe, name: "jsonHighlight" }], encapsulation: i0.ViewEncapsulation.None });
5473
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.17", type: JsonValuesDebujComponent, isStandalone: true, selector: "app-json-values-debuj", inputs: { form: { classPropertyName: "form", publicName: "form", isSignal: true, isRequired: false, transformFunction: null }, debug: { classPropertyName: "debug", publicName: "debug", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "@if (form() && shouldShowVisual) {\r\n <div class=\"custom-container\">\r\n <pre class=\"custom-pre\" [innerHTML]=\"debugValue() | jsonHighlight\"></pre>\r\n </div>\r\n}\r\n", styles: [".custom-container{width:100%;overflow:auto;max-height:700px;background:#1e1e1e;border:1px solid #333;border-radius:8px;box-shadow:0 4px 12px #0000004d;padding:1.25rem;margin-bottom:1.25rem}.custom-pre{margin:0;white-space:pre-wrap;word-break:break-word;word-wrap:break-word;font-family:Segoe UI,Fira Code,JetBrains Mono,Consolas,Monaco,Courier New,monospace;font-size:15px;line-height:1.65;color:#d4d4d4;font-weight:400}.json-key{color:#9cdcfe;font-weight:600;font-size:15px}.json-string{color:#ce9178;font-size:15px}.json-number{color:#b5cea8;font-weight:600;font-size:15px}.json-boolean{color:#569cd6;font-weight:700;font-size:15px}.json-null{color:gray;font-style:italic;font-size:15px}.json-bracket{color:gold;font-weight:700;font-size:16px}.json-colon{color:#d4d4d4;font-weight:500}.json-comma{color:gray;font-size:14px}.json-date-part{color:#4fc1ff;font-weight:600;font-size:15px}.json-date-sep{color:gray}.json-date-time{color:#c586c0;font-size:15px}.custom-container::-webkit-scrollbar{width:12px;height:12px}.custom-container::-webkit-scrollbar-track{background:#252526;border-radius:6px}.custom-container::-webkit-scrollbar-thumb{background:#555;border-radius:6px;transition:background .2s ease}.custom-container::-webkit-scrollbar-thumb:hover{background:#777}.custom-container::-webkit-scrollbar-corner{background:#1e1e1e}.custom-container{font-smooth:antialiased;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.json-null,.json-undefined{color:#f48771;font-style:italic;opacity:.8}.json-empty{color:gray;font-style:italic}.json-comma+br{margin-bottom:2px}\n"], dependencies: [{ kind: "pipe", type: JsonHighlightPipe, name: "jsonHighlight" }], encapsulation: i0.ViewEncapsulation.None });
5306
5474
  }
5307
5475
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JsonValuesDebujComponent, decorators: [{
5308
5476
  type: Component,
5309
- args: [{ selector: 'app-json-values-debuj', standalone: true, imports: [JsonHighlightPipe], encapsulation: ViewEncapsulation.None, template: "@if (form() && shouldShowVisual) {\r\n <div class=\"custom-container\">\r\n <pre class=\"custom-pre\" [innerHTML]=\"debugValue() | jsonHighlight\"></pre>\r\n </div>\r\n}\r\n", styles: [".custom-container{width:100%;overflow:auto;max-height:700px;background:#1e1e1e;border:1px solid #333;border-radius:8px;box-shadow:0 4px 12px #0000004d;padding:1.25rem;margin-bottom:1.25rem}.custom-pre{margin:0;white-space:pre-wrap;word-break:break-word;word-wrap:break-word;font-family:Segoe UI,Fira Code,JetBrains Mono,Consolas,Monaco,Courier New,monospace;font-size:15px;line-height:1.65;color:#d4d4d4;font-weight:400}.json-key{color:#9cdcfe;font-weight:600;font-size:15px}.json-string{color:#ce9178;font-size:15px}.json-number{color:#b5cea8;font-weight:600;font-size:15px}.json-boolean{color:#569cd6;font-weight:700;font-size:15px}.json-null{color:gray;font-style:italic;font-size:15px}.json-bracket{color:gold;font-weight:700;font-size:16px}.json-colon{color:#d4d4d4;font-weight:500}.json-comma{color:gray;font-size:14px}.json-date-part{color:#4fc1ff;font-weight:600;font-size:15px}.json-date-sep{color:gray}.json-date-time{color:#c586c0;font-size:15px}.custom-container::-webkit-scrollbar{width:12px;height:12px}.custom-container::-webkit-scrollbar-track{background:#252526;border-radius:6px}.custom-container::-webkit-scrollbar-thumb{background:#555;border-radius:6px;transition:background .2s ease}.custom-container::-webkit-scrollbar-thumb:hover{background:#777}.custom-container::-webkit-scrollbar-corner{background:#1e1e1e}.custom-container{font-smooth:antialiased;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.custom-pre:hover{background:#252526;transition:background .2s ease;cursor:text}.json-null,.json-undefined{color:#f48771;font-style:italic;opacity:.8}.json-empty{color:gray;font-style:italic}.json-comma+br{margin-bottom:2px}\n"] }]
5477
+ args: [{ selector: 'app-json-values-debuj', standalone: true, imports: [JsonHighlightPipe], encapsulation: ViewEncapsulation.None, template: "@if (form() && shouldShowVisual) {\r\n <div class=\"custom-container\">\r\n <pre class=\"custom-pre\" [innerHTML]=\"debugValue() | jsonHighlight\"></pre>\r\n </div>\r\n}\r\n", styles: [".custom-container{width:100%;overflow:auto;max-height:700px;background:#1e1e1e;border:1px solid #333;border-radius:8px;box-shadow:0 4px 12px #0000004d;padding:1.25rem;margin-bottom:1.25rem}.custom-pre{margin:0;white-space:pre-wrap;word-break:break-word;word-wrap:break-word;font-family:Segoe UI,Fira Code,JetBrains Mono,Consolas,Monaco,Courier New,monospace;font-size:15px;line-height:1.65;color:#d4d4d4;font-weight:400}.json-key{color:#9cdcfe;font-weight:600;font-size:15px}.json-string{color:#ce9178;font-size:15px}.json-number{color:#b5cea8;font-weight:600;font-size:15px}.json-boolean{color:#569cd6;font-weight:700;font-size:15px}.json-null{color:gray;font-style:italic;font-size:15px}.json-bracket{color:gold;font-weight:700;font-size:16px}.json-colon{color:#d4d4d4;font-weight:500}.json-comma{color:gray;font-size:14px}.json-date-part{color:#4fc1ff;font-weight:600;font-size:15px}.json-date-sep{color:gray}.json-date-time{color:#c586c0;font-size:15px}.custom-container::-webkit-scrollbar{width:12px;height:12px}.custom-container::-webkit-scrollbar-track{background:#252526;border-radius:6px}.custom-container::-webkit-scrollbar-thumb{background:#555;border-radius:6px;transition:background .2s ease}.custom-container::-webkit-scrollbar-thumb:hover{background:#777}.custom-container::-webkit-scrollbar-corner{background:#1e1e1e}.custom-container{font-smooth:antialiased;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.json-null,.json-undefined{color:#f48771;font-style:italic;opacity:.8}.json-empty{color:gray;font-style:italic}.json-comma+br{margin-bottom:2px}\n"] }]
5310
5478
  }], ctorParameters: () => [], propDecorators: { form: [{ type: i0.Input, args: [{ isSignal: true, alias: "form", required: false }] }], debug: [{ type: i0.Input, args: [{ isSignal: true, alias: "debug", required: false }] }] } });
5311
5479
 
5312
5480
  class IcoLabel {
@@ -7712,54 +7880,197 @@ function createInitialCache(cacheKeys) {
7712
7880
  }
7713
7881
 
7714
7882
  class HeaderDsx {
7883
+ // Inputs
7715
7884
  id = input(null, ...(ngDevMode ? [{ debugName: "id" }] : /* istanbul ignore next */ []));
7716
7885
  etiqueta = input.required(...(ngDevMode ? [{ debugName: "etiqueta" }] : /* istanbul ignore next */ []));
7717
7886
  defaultPNG = input('icon/folder_001.png', ...(ngDevMode ? [{ debugName: "defaultPNG" }] : /* istanbul ignore next */ []));
7718
7887
  defaultGIF = input('gif/file.gif', ...(ngDevMode ? [{ debugName: "defaultGIF" }] : /* istanbul ignore next */ []));
7719
7888
  icoPNG = input(null, ...(ngDevMode ? [{ debugName: "icoPNG" }] : /* istanbul ignore next */ []));
7720
7889
  icoGIF = input(null, ...(ngDevMode ? [{ debugName: "icoGIF" }] : /* istanbul ignore next */ []));
7721
- icono = null;
7722
- textoEncabezado = null;
7723
7890
  subTitulo = input(null, ...(ngDevMode ? [{ debugName: "subTitulo" }] : /* istanbul ignore next */ []));
7891
+ debug = input(false, ...(ngDevMode ? [{ debugName: "debug" }] : /* istanbul ignore next */ []));
7892
+ // Signals
7893
+ icono = signal(null, ...(ngDevMode ? [{ debugName: "icono" }] : /* istanbul ignore next */ []));
7894
+ textoEncabezado = signal(null, ...(ngDevMode ? [{ debugName: "textoEncabezado" }] : /* istanbul ignore next */ []));
7895
+ // Métricas de performance públicas
7896
+ performanceMetrics = {
7897
+ renderCount: 0,
7898
+ lastRenderTime: 0,
7899
+ totalRenderTime: 0,
7900
+ averageRenderTime: 0,
7901
+ lastUpdateTimestamp: 0,
7902
+ };
7903
+ // Computed
7904
+ modo = computed(() => {
7905
+ const id = this.id();
7906
+ if (id === null)
7907
+ return 'Lista';
7908
+ if (id === 0)
7909
+ return 'Registro';
7910
+ if (id > 0)
7911
+ return 'Edición';
7912
+ return 'Desconocido';
7913
+ }, ...(ngDevMode ? [{ debugName: "modo" }] : /* istanbul ignore next */ []));
7914
+ // Control de producción
7915
+ isProduction = !isDevMode();
7916
+ constructor() {
7917
+ effect(() => {
7918
+ if (this.debug() && !this.isProduction) {
7919
+ this.logPerformance('Debug mode activado');
7920
+ }
7921
+ });
7922
+ }
7724
7923
  ngOnInit() {
7924
+ const startTime = performance.now();
7725
7925
  this.definirTexto();
7726
- //throw new Error('Method not implemented.');
7926
+ this.performanceMetrics.lastUpdateTimestamp = Date.now();
7927
+ this.logPerformance('Componente inicializado');
7928
+ const endTime = performance.now();
7929
+ this.logPerformance(`Tiempo de inicialización: ${(endTime - startTime).toFixed(2)}ms`);
7930
+ }
7931
+ ngOnChanges(changes) {
7932
+ const startTime = performance.now();
7933
+ this.performanceMetrics.renderCount++;
7934
+ // Solo procesar si hay cambios relevantes
7935
+ if (this.tieneCambiosRelevantes(changes)) {
7936
+ this.logPerformance('Detectado cambio en inputs', {
7937
+ cambios: Object.keys(changes),
7938
+ idActual: this.id(),
7939
+ idAnterior: changes['id']?.previousValue,
7940
+ idNuevo: changes['id']?.currentValue,
7941
+ });
7942
+ this.definirTexto();
7943
+ }
7944
+ const endTime = performance.now();
7945
+ const renderTime = endTime - startTime;
7946
+ this.performanceMetrics.lastRenderTime = renderTime;
7947
+ this.performanceMetrics.totalRenderTime += renderTime;
7948
+ this.performanceMetrics.averageRenderTime =
7949
+ this.performanceMetrics.totalRenderTime /
7950
+ this.performanceMetrics.renderCount;
7951
+ this.logPerformance('Cambio procesado', {
7952
+ renderTime: renderTime.toFixed(2) + 'ms',
7953
+ renderCount: this.performanceMetrics.renderCount,
7954
+ avgRenderTime: this.performanceMetrics.averageRenderTime.toFixed(2) + 'ms',
7955
+ });
7956
+ }
7957
+ tieneCambiosRelevantes(changes) {
7958
+ const relevantKeys = ['id', 'etiqueta', 'icoPNG', 'icoGIF', 'subTitulo'];
7959
+ for (const key of relevantKeys) {
7960
+ if (changes[key] &&
7961
+ changes[key].currentValue !== changes[key].previousValue) {
7962
+ return true;
7963
+ }
7964
+ }
7965
+ return false;
7727
7966
  }
7728
7967
  definirTexto() {
7729
- // Validaciones para el texto del encabezado según el valor de ID
7730
- // Caso 1: No se proporcionó ID (indefinido o nulo) -> Plural
7731
- if (this.id() === null) {
7732
- this.textoEncabezado = this.etiqueta();
7968
+ const startTime = performance.now();
7969
+ const idActual = this.id();
7970
+ if (this.debug() && !this.isProduction) {
7971
+ console.group(`🔍 HeaderDsx - Definiendo texto para ID: ${idActual}`);
7972
+ }
7973
+ let nuevoTexto;
7974
+ let nuevoIcono = null;
7975
+ // Determinar texto
7976
+ if (idActual === null) {
7977
+ nuevoTexto = this.etiqueta();
7978
+ this.logDebug('Caso 1: ID null - Modo lista');
7979
+ }
7980
+ else if (idActual === 0) {
7981
+ nuevoTexto = `Registrar ${this.etiqueta()}`;
7982
+ this.logDebug('Caso 2: ID = 0 - Modo registro');
7983
+ }
7984
+ else if (idActual > 0) {
7985
+ nuevoTexto = `Editar ${this.etiqueta()}`;
7986
+ this.logDebug('Caso 3: ID > 0 - Modo edición', {
7987
+ id: idActual,
7988
+ texto: nuevoTexto,
7989
+ });
7733
7990
  }
7734
- // Caso 2: El ID existe y vale exactamente 0 -> Registrar
7735
- else if (this.id() === 0) {
7736
- this.textoEncabezado = `Registrar ${this.etiqueta()}`;
7991
+ else {
7992
+ nuevoTexto = this.etiqueta();
7993
+ this.logDebug('Caso desconocido', { id: idActual });
7737
7994
  }
7738
- // Caso 3: El ID es mayor que 0 -> Editar
7739
- else if (this.id() > 0) {
7740
- this.textoEncabezado = `Editar ${this.etiqueta()}`;
7995
+ // Determinar icono
7996
+ if (this.icoPNG() !== null) {
7997
+ nuevoIcono = this.icoPNG();
7998
+ this.logDebug('Icono: Usando PNG personalizado', { icono: nuevoIcono });
7741
7999
  }
7742
- // Validaciones para el icono según el valor de ID
7743
- // Caso 1: No se proporcionó ningún icono -> Usar el icono por defecto
7744
- if (this.icoPNG() === null && this.icoGIF() === null) {
7745
- this.icono = this.defaultPNG();
8000
+ else if (this.icoGIF() !== null) {
8001
+ nuevoIcono = this.icoGIF();
8002
+ this.logDebug('Icono: Usando GIF personalizado', { icono: nuevoIcono });
7746
8003
  }
7747
- // Caso 2: Se proporcionó un icono PNG -> Usar el icono PNG
7748
- else if (this.icoPNG() !== null) {
7749
- this.icono = this.icoPNG();
8004
+ else {
8005
+ nuevoIcono = this.defaultPNG();
8006
+ this.logDebug('Icono: Usando default', { icono: nuevoIcono });
7750
8007
  }
7751
- // Caso 3: Se proporcionó un icono GIF -> Usar el icono GIF
7752
- else if (this.icoGIF() !== null) {
7753
- this.icono = this.icoGIF();
8008
+ // Actualizar solo si hay cambios
8009
+ if (this.textoEncabezado() !== nuevoTexto) {
8010
+ this.textoEncabezado.set(nuevoTexto);
8011
+ }
8012
+ if (this.icono() !== nuevoIcono) {
8013
+ this.icono.set(nuevoIcono);
8014
+ }
8015
+ this.logDebug('Estado final actualizado', {
8016
+ texto: nuevoTexto,
8017
+ icono: nuevoIcono,
8018
+ id: idActual,
8019
+ modo: this.modo(),
8020
+ });
8021
+ if (this.debug() && !this.isProduction) {
8022
+ console.groupEnd();
8023
+ }
8024
+ const endTime = performance.now();
8025
+ this.logPerformance(`Tiempo de definición de texto: ${(endTime - startTime).toFixed(2)}ms`);
8026
+ }
8027
+ logDebug(message, data) {
8028
+ if (this.debug() && !this.isProduction) {
8029
+ console.log(`[HeaderDsx Debug] ${message}`, data ? data : '');
8030
+ }
8031
+ }
8032
+ logPerformance(message, data) {
8033
+ if (this.debug() && !this.isProduction) {
8034
+ console.log(`⚡ [HeaderDsx Performance] ${message}`, data ? data : '');
8035
+ }
8036
+ }
8037
+ // Métodos públicos
8038
+ getPerformanceMetrics() {
8039
+ return {
8040
+ ...this.performanceMetrics,
8041
+ currentMode: this.modo(),
8042
+ currentText: this.textoEncabezado(),
8043
+ currentIcon: this.icono(),
8044
+ currentId: this.id(),
8045
+ };
8046
+ }
8047
+ getPerformanceSummary() {
8048
+ const metrics = this.performanceMetrics;
8049
+ return `📊 Renders: ${metrics.renderCount} | Promedio: ${metrics.averageRenderTime.toFixed(2)}ms | Último: ${metrics.lastRenderTime.toFixed(2)}ms`;
8050
+ }
8051
+ debugInfo() {
8052
+ if (this.debug() && !this.isProduction) {
8053
+ console.group('=== HeaderDsx Debug Info ===');
8054
+ console.log('ID:', this.id());
8055
+ console.log('Etiqueta:', this.etiqueta());
8056
+ console.log('Texto Encabezado:', this.textoEncabezado());
8057
+ console.log('Icono:', this.icono());
8058
+ console.log('Subtítulo:', this.subTitulo());
8059
+ console.log('Modo:', this.modo());
8060
+ console.log('Debug Mode:', this.debug());
8061
+ console.log('Performance Metrics:', this.getPerformanceMetrics());
8062
+ console.log('Performance Summary:', this.getPerformanceSummary());
8063
+ console.log('===============================');
8064
+ console.groupEnd();
7754
8065
  }
7755
8066
  }
7756
8067
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: HeaderDsx, deps: [], target: i0.ɵɵFactoryTarget.Component });
7757
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.17", type: HeaderDsx, isStandalone: true, selector: "header-dsx", inputs: { id: { classPropertyName: "id", publicName: "id", isSignal: true, isRequired: false, transformFunction: null }, etiqueta: { classPropertyName: "etiqueta", publicName: "etiqueta", isSignal: true, isRequired: true, transformFunction: null }, defaultPNG: { classPropertyName: "defaultPNG", publicName: "defaultPNG", isSignal: true, isRequired: false, transformFunction: null }, defaultGIF: { classPropertyName: "defaultGIF", publicName: "defaultGIF", isSignal: true, isRequired: false, transformFunction: null }, icoPNG: { classPropertyName: "icoPNG", publicName: "icoPNG", isSignal: true, isRequired: false, transformFunction: null }, icoGIF: { classPropertyName: "icoGIF", publicName: "icoGIF", isSignal: true, isRequired: false, transformFunction: null }, subTitulo: { classPropertyName: "subTitulo", publicName: "subTitulo", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "<div class=\"area-fieldset-header flex items-center gap-2 px-2\">\r\n <p-avatar [image]=\"icono!\"></p-avatar>\r\n <div class=\"flex flex-col\">\r\n <h3>{{ textoEncabezado }}</h3>\r\n @if(subTitulo() !== null ){\r\n <ng-container>\r\n <span class=\"text-xs text-gray-600\">{{ subTitulo() }}</span>\r\n </ng-container>\r\n }\r\n </div>\r\n</div>\r\n", styles: [""], dependencies: [{ kind: "ngmodule", type: AvatarModule }, { kind: "component", type: i2$3.Avatar, selector: "p-avatar", inputs: ["label", "icon", "image", "size", "shape", "styleClass", "ariaLabel", "ariaLabelledBy"], outputs: ["onImageError"] }] });
8068
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.17", type: HeaderDsx, isStandalone: true, selector: "header-dsx", inputs: { id: { classPropertyName: "id", publicName: "id", isSignal: true, isRequired: false, transformFunction: null }, etiqueta: { classPropertyName: "etiqueta", publicName: "etiqueta", isSignal: true, isRequired: true, transformFunction: null }, defaultPNG: { classPropertyName: "defaultPNG", publicName: "defaultPNG", isSignal: true, isRequired: false, transformFunction: null }, defaultGIF: { classPropertyName: "defaultGIF", publicName: "defaultGIF", isSignal: true, isRequired: false, transformFunction: null }, icoPNG: { classPropertyName: "icoPNG", publicName: "icoPNG", isSignal: true, isRequired: false, transformFunction: null }, icoGIF: { classPropertyName: "icoGIF", publicName: "icoGIF", isSignal: true, isRequired: false, transformFunction: null }, subTitulo: { classPropertyName: "subTitulo", publicName: "subTitulo", isSignal: true, isRequired: false, transformFunction: null }, debug: { classPropertyName: "debug", publicName: "debug", isSignal: true, isRequired: false, transformFunction: null } }, usesOnChanges: true, ngImport: i0, template: "<div class=\"area-fieldset-header flex items-center gap-2 px-2\">\r\n <p-avatar [image]=\"icono()!\"></p-avatar>\r\n <div class=\"flex flex-col\">\r\n <h3>{{ textoEncabezado() }}</h3>\r\n @if(subTitulo() !== null ){\r\n <span class=\"text-xs text-gray-600\">{{ subTitulo() }}</span>\r\n }\r\n <!-- Debug info con m\u00E9tricas de performance -->\r\n @if(debug()){\r\n <div\r\n class=\"text-xs mt-1 px-2 py-1 rounded flex flex-wrap items-center gap-1\"\r\n [class]=\"id() === 0 ? 'bg-blue-50 text-blue-700' : \r\n id() !== null && id()! > 0 ? 'bg-green-50 text-green-700' : \r\n 'bg-gray-50 text-gray-700'\"\r\n >\r\n <span>\uD83D\uDD0D</span>\r\n <span>ID: {{ id() }}</span>\r\n <span>|</span>\r\n <span>Modo: <strong>{{ modo() }}</strong></span>\r\n <span>|</span>\r\n <span>Texto: {{ textoEncabezado() }}</span>\r\n @if(id() !== null && id()! > 0){\r\n <span class=\"ml-1 text-xs\">(Editando ID {{ id() }})</span>\r\n }\r\n <!-- M\u00E9tricas de performance -->\r\n <span class=\"ml-1 text-xs text-gray-400\">\r\n | Render: {{ performanceMetrics.renderCount }} | Avg: {{\r\n performanceMetrics.averageRenderTime.toFixed(1) }}ms\r\n </span>\r\n </div>\r\n }\r\n </div>\r\n</div>\r\n", styles: [""], dependencies: [{ kind: "ngmodule", type: AvatarModule }, { kind: "component", type: i2$3.Avatar, selector: "p-avatar", inputs: ["label", "icon", "image", "size", "shape", "styleClass", "ariaLabel", "ariaLabelledBy"], outputs: ["onImageError"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
7758
8069
  }
7759
8070
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: HeaderDsx, decorators: [{
7760
8071
  type: Component,
7761
- args: [{ selector: 'header-dsx', imports: [AvatarModule], template: "<div class=\"area-fieldset-header flex items-center gap-2 px-2\">\r\n <p-avatar [image]=\"icono!\"></p-avatar>\r\n <div class=\"flex flex-col\">\r\n <h3>{{ textoEncabezado }}</h3>\r\n @if(subTitulo() !== null ){\r\n <ng-container>\r\n <span class=\"text-xs text-gray-600\">{{ subTitulo() }}</span>\r\n </ng-container>\r\n }\r\n </div>\r\n</div>\r\n" }]
7762
- }], propDecorators: { id: [{ type: i0.Input, args: [{ isSignal: true, alias: "id", required: false }] }], etiqueta: [{ type: i0.Input, args: [{ isSignal: true, alias: "etiqueta", required: true }] }], defaultPNG: [{ type: i0.Input, args: [{ isSignal: true, alias: "defaultPNG", required: false }] }], defaultGIF: [{ type: i0.Input, args: [{ isSignal: true, alias: "defaultGIF", required: false }] }], icoPNG: [{ type: i0.Input, args: [{ isSignal: true, alias: "icoPNG", required: false }] }], icoGIF: [{ type: i0.Input, args: [{ isSignal: true, alias: "icoGIF", required: false }] }], subTitulo: [{ type: i0.Input, args: [{ isSignal: true, alias: "subTitulo", required: false }] }] } });
8072
+ args: [{ selector: 'header-dsx', imports: [AvatarModule], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"area-fieldset-header flex items-center gap-2 px-2\">\r\n <p-avatar [image]=\"icono()!\"></p-avatar>\r\n <div class=\"flex flex-col\">\r\n <h3>{{ textoEncabezado() }}</h3>\r\n @if(subTitulo() !== null ){\r\n <span class=\"text-xs text-gray-600\">{{ subTitulo() }}</span>\r\n }\r\n <!-- Debug info con m\u00E9tricas de performance -->\r\n @if(debug()){\r\n <div\r\n class=\"text-xs mt-1 px-2 py-1 rounded flex flex-wrap items-center gap-1\"\r\n [class]=\"id() === 0 ? 'bg-blue-50 text-blue-700' : \r\n id() !== null && id()! > 0 ? 'bg-green-50 text-green-700' : \r\n 'bg-gray-50 text-gray-700'\"\r\n >\r\n <span>\uD83D\uDD0D</span>\r\n <span>ID: {{ id() }}</span>\r\n <span>|</span>\r\n <span>Modo: <strong>{{ modo() }}</strong></span>\r\n <span>|</span>\r\n <span>Texto: {{ textoEncabezado() }}</span>\r\n @if(id() !== null && id()! > 0){\r\n <span class=\"ml-1 text-xs\">(Editando ID {{ id() }})</span>\r\n }\r\n <!-- M\u00E9tricas de performance -->\r\n <span class=\"ml-1 text-xs text-gray-400\">\r\n | Render: {{ performanceMetrics.renderCount }} | Avg: {{\r\n performanceMetrics.averageRenderTime.toFixed(1) }}ms\r\n </span>\r\n </div>\r\n }\r\n </div>\r\n</div>\r\n" }]
8073
+ }], ctorParameters: () => [], propDecorators: { id: [{ type: i0.Input, args: [{ isSignal: true, alias: "id", required: false }] }], etiqueta: [{ type: i0.Input, args: [{ isSignal: true, alias: "etiqueta", required: true }] }], defaultPNG: [{ type: i0.Input, args: [{ isSignal: true, alias: "defaultPNG", required: false }] }], defaultGIF: [{ type: i0.Input, args: [{ isSignal: true, alias: "defaultGIF", required: false }] }], icoPNG: [{ type: i0.Input, args: [{ isSignal: true, alias: "icoPNG", required: false }] }], icoGIF: [{ type: i0.Input, args: [{ isSignal: true, alias: "icoGIF", required: false }] }], subTitulo: [{ type: i0.Input, args: [{ isSignal: true, alias: "subTitulo", required: false }] }], debug: [{ type: i0.Input, args: [{ isSignal: true, alias: "debug", required: false }] }] } });
7763
8074
 
7764
8075
  class DsxAddToolsModule {
7765
8076
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: DsxAddToolsModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
@@ -8091,6 +8402,456 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImpo
8091
8402
  }]
8092
8403
  }] });
8093
8404
 
8405
+ // dsxdate-short.ts
8406
+ class DsxdateShort {
8407
+ injector = inject(Injector);
8408
+ // ✅ Exponer isDevMode como propiedad pública
8409
+ isDevMode = isDevMode();
8410
+ // === INPUTS CONFIGURABLES ===
8411
+ label = input.required(...(ngDevMode ? [{ debugName: "label" }] : /* istanbul ignore next */ []));
8412
+ placeholder = input('dd/mm/yyyy', ...(ngDevMode ? [{ debugName: "placeholder" }] : /* istanbul ignore next */ []));
8413
+ dateFormat = input('dd/mm/yy', ...(ngDevMode ? [{ debugName: "dateFormat" }] : /* istanbul ignore next */ []));
8414
+ showIcon = input(true, ...(ngDevMode ? [{ debugName: "showIcon" }] : /* istanbul ignore next */ []));
8415
+ showOnFocus = input(false, ...(ngDevMode ? [{ debugName: "showOnFocus" }] : /* istanbul ignore next */ []));
8416
+ showButtonBar = input(true, ...(ngDevMode ? [{ debugName: "showButtonBar" }] : /* istanbul ignore next */ []));
8417
+ debug = input(false, ...(ngDevMode ? [{ debugName: "debug" }] : /* istanbul ignore next */ []));
8418
+ // === STATE ===
8419
+ debugEnabled = signal(false, ...(ngDevMode ? [{ debugName: "debugEnabled" }] : /* istanbul ignore next */ []));
8420
+ // === OBTENER EL CONTROL PADRE ===
8421
+ ngControl = computed(() => {
8422
+ try {
8423
+ return this.injector.get(NgControl);
8424
+ }
8425
+ catch {
8426
+ return null;
8427
+ }
8428
+ }, ...(ngDevMode ? [{ debugName: "ngControl" }] : /* istanbul ignore next */ []));
8429
+ // === CONTROL PADRE PARA ERRORES ===
8430
+ parentControl = computed(() => {
8431
+ const control = this.ngControl();
8432
+ return control?.control || null;
8433
+ }, ...(ngDevMode ? [{ debugName: "parentControl" }] : /* istanbul ignore next */ []));
8434
+ // === CONTROL INTERNO (para el template) ===
8435
+ fechaControl = new FormControl(null);
8436
+ // === CONTROL VALUE ACCESSOR ===
8437
+ onChange = () => { };
8438
+ onTouched = () => { };
8439
+ constructor() {
8440
+ // Debug effect
8441
+ effect(() => {
8442
+ const isDebug = this.debug() && this.isDevMode;
8443
+ this.debugEnabled.set(isDebug);
8444
+ if (isDebug) {
8445
+ console.log('[dsxdate-short] === DEBUG MODE ACTIVADO ===');
8446
+ console.log('[dsxdate-short] Configuración:', {
8447
+ label: this.label(),
8448
+ placeholder: this.placeholder(),
8449
+ dateFormat: this.dateFormat(),
8450
+ showIcon: this.showIcon(),
8451
+ showOnFocus: this.showOnFocus(),
8452
+ showButtonBar: this.showButtonBar(),
8453
+ });
8454
+ console.log('[dsxdate-short] Control padre:', this.parentControl());
8455
+ }
8456
+ });
8457
+ // ✅ SINCRONIZAR VALIDADORES DEL PADRE AL CONTROL INTERNO
8458
+ effect(() => {
8459
+ const parentCtrl = this.parentControl();
8460
+ if (parentCtrl) {
8461
+ // Copiar validadores del padre al control interno
8462
+ const validators = parentCtrl.validator;
8463
+ const asyncValidators = parentCtrl.asyncValidator;
8464
+ if (this.debugEnabled()) {
8465
+ console.log('[dsxdate-short] 🔄 Sincronizando validadores del padre');
8466
+ console.log('[dsxdate-short] Validadores del padre:', validators);
8467
+ }
8468
+ this.fechaControl.setValidators(validators ? [validators] : []);
8469
+ this.fechaControl.setAsyncValidators(asyncValidators ? [asyncValidators] : []);
8470
+ this.fechaControl.updateValueAndValidity({ emitEvent: false });
8471
+ if (this.debugEnabled()) {
8472
+ console.log('[dsxdate-short] ✅ Validadores sincronizados');
8473
+ console.log('[dsxdate-short] Estado del control interno:', {
8474
+ valid: this.fechaControl.valid,
8475
+ invalid: this.fechaControl.invalid,
8476
+ errors: this.fechaControl.errors,
8477
+ });
8478
+ }
8479
+ }
8480
+ });
8481
+ // Monitorear cambios del control padre
8482
+ effect(() => {
8483
+ if (this.debugEnabled()) {
8484
+ const parentCtrl = this.parentControl();
8485
+ console.log('[dsxdate-short] 📊 Parent Control state:', {
8486
+ value: parentCtrl?.value,
8487
+ status: parentCtrl?.status,
8488
+ errors: parentCtrl?.errors,
8489
+ valid: parentCtrl?.valid,
8490
+ invalid: parentCtrl?.invalid,
8491
+ touched: parentCtrl?.touched,
8492
+ dirty: parentCtrl?.dirty,
8493
+ });
8494
+ }
8495
+ });
8496
+ // Sincronizar cambios del control interno al padre
8497
+ this.fechaControl.valueChanges.subscribe((value) => {
8498
+ if (this.debugEnabled()) {
8499
+ console.log('[dsxdate-short] 🔄 valueChanges - Nuevo valor:', value);
8500
+ }
8501
+ this.onChange(value);
8502
+ });
8503
+ // Sincronizar touched
8504
+ this.fechaControl.statusChanges.subscribe(() => {
8505
+ if (this.debugEnabled()) {
8506
+ console.log('[dsxdate-short] 📊 statusChanges - Estado:', this.fechaControl.status);
8507
+ }
8508
+ this.onTouched();
8509
+ });
8510
+ }
8511
+ // === MÉTODOS DE DEBUG ===
8512
+ log(message, data) {
8513
+ if (this.debugEnabled() && this.isDevMode) {
8514
+ if (data !== undefined) {
8515
+ console.log(`[dsxdate-short] ${message}`, data);
8516
+ }
8517
+ else {
8518
+ console.log(`[dsxdate-short] ${message}`);
8519
+ }
8520
+ }
8521
+ }
8522
+ /**
8523
+ * Convierte cualquier fecha (string ISO, Date, moment) a Date válido
8524
+ */
8525
+ convertirFechaADate(fecha) {
8526
+ if (this.debugEnabled()) {
8527
+ this.log('🔄 convertirFechaADate - entrada:', fecha);
8528
+ }
8529
+ if (!fecha) {
8530
+ this.log('convertirFechaADate - fecha vacía, retornando null');
8531
+ return null;
8532
+ }
8533
+ if (fecha instanceof Date && !isNaN(fecha.getTime())) {
8534
+ this.log('✅ convertirFechaADate - es Date válido:', fecha);
8535
+ return fecha;
8536
+ }
8537
+ if (typeof fecha === 'string') {
8538
+ this.log('📝 convertirFechaADate - procesando string:', fecha);
8539
+ const momentDate = moment(fecha);
8540
+ if (momentDate.isValid()) {
8541
+ const result = momentDate.toDate();
8542
+ this.log('✅ convertirFechaADate - string convertido a Date:', result);
8543
+ return result;
8544
+ }
8545
+ this.log('❌ convertirFechaADate - string inválido para moment');
8546
+ }
8547
+ if (moment.isMoment(fecha)) {
8548
+ this.log('✅ convertirFechaADate - es objeto moment');
8549
+ return fecha.toDate();
8550
+ }
8551
+ const parsed = new Date(fecha);
8552
+ if (!isNaN(parsed.getTime())) {
8553
+ this.log('✅ convertirFechaADate - parseo directo exitoso:', parsed);
8554
+ return parsed;
8555
+ }
8556
+ this.log('❌ convertirFechaADate - no se pudo convertir, retornando null');
8557
+ return null;
8558
+ }
8559
+ // === CONTROL VALUE ACCESSOR IMPLEMENTATION ===
8560
+ writeValue(value) {
8561
+ if (this.debugEnabled()) {
8562
+ this.log('📥 writeValue - Valor recibido:', value);
8563
+ }
8564
+ const fechaConvertida = this.convertirFechaADate(value);
8565
+ if (this.debugEnabled()) {
8566
+ this.log('📥 writeValue - Valor convertido:', fechaConvertida);
8567
+ }
8568
+ this.fechaControl.setValue(fechaConvertida, { emitEvent: false });
8569
+ }
8570
+ registerOnChange(fn) {
8571
+ if (this.debugEnabled()) {
8572
+ this.log('📞 registerOnChange - Callback registrado');
8573
+ }
8574
+ this.onChange = fn;
8575
+ }
8576
+ registerOnTouched(fn) {
8577
+ if (this.debugEnabled()) {
8578
+ this.log('📞 registerOnTouched - Callback registrado');
8579
+ }
8580
+ this.onTouched = fn;
8581
+ }
8582
+ setDisabledState(isDisabled) {
8583
+ if (this.debugEnabled()) {
8584
+ this.log(`🚫 setDisabledState - Deshabilitado: ${isDisabled}`);
8585
+ }
8586
+ if (isDisabled) {
8587
+ this.fechaControl.disable({ emitEvent: false });
8588
+ }
8589
+ else {
8590
+ this.fechaControl.enable({ emitEvent: false });
8591
+ }
8592
+ }
8593
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: DsxdateShort, deps: [], target: i0.ɵɵFactoryTarget.Component });
8594
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.17", type: DsxdateShort, isStandalone: true, selector: "dsxdate-short", inputs: { label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: true, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, dateFormat: { classPropertyName: "dateFormat", publicName: "dateFormat", isSignal: true, isRequired: false, transformFunction: null }, showIcon: { classPropertyName: "showIcon", publicName: "showIcon", isSignal: true, isRequired: false, transformFunction: null }, showOnFocus: { classPropertyName: "showOnFocus", publicName: "showOnFocus", isSignal: true, isRequired: false, transformFunction: null }, showButtonBar: { classPropertyName: "showButtonBar", publicName: "showButtonBar", isSignal: true, isRequired: false, transformFunction: null }, debug: { classPropertyName: "debug", publicName: "debug", isSignal: true, isRequired: false, transformFunction: null } }, providers: [
8595
+ {
8596
+ provide: NG_VALUE_ACCESSOR,
8597
+ useExisting: forwardRef(() => DsxdateShort),
8598
+ multi: true,
8599
+ },
8600
+ ], ngImport: i0, template: "<!-- dsxdate-short.html -->\r\n<p-floatLabel variant=\"on\">\r\n <p-datepicker\r\n [formControl]=\"fechaControl\"\r\n [fluid]=\"true\"\r\n [showIcon]=\"showIcon()\"\r\n [showOnFocus]=\"showOnFocus()\"\r\n [showButtonBar]=\"showButtonBar()\"\r\n [dateFormat]=\"dateFormat()\"\r\n [placeholder]=\"placeholder()\"\r\n pInputMask=\"99/99/9999\"\r\n />\r\n <label>{{ label() }}</label>\r\n</p-floatLabel>\r\n\r\n<!-- \u2705 SIN CONDICI\u00D3N - IGUAL QUE EL ORIGINAL -->\r\n<dsx-message-error [control]=\"fechaControl\" />\r\n\r\n<!-- Debug info -->\r\n@if (debugEnabled() && isDevMode) {\r\n<div\r\n class=\"debug-info\"\r\n style=\"\r\n font-size: 12px;\r\n color: #666;\r\n margin-top: 4px;\r\n border-top: 1px dashed #ccc;\r\n padding-top: 4px;\r\n \"\r\n>\r\n <small>\r\n <strong>Debug:</strong>\r\n Value: {{ fechaControl.value | json }} | Valid: {{ fechaControl.valid }} |\r\n Invalid: {{ fechaControl.invalid }} | Errors: {{ fechaControl.errors | json\r\n }} | Dirty: {{ fechaControl.dirty }} | Touched: {{ fechaControl.touched }} |\r\n Status: {{ fechaControl.status }}\r\n </small>\r\n</div>\r\n}\r\n", styles: [""], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: FloatLabel, selector: "p-floatlabel, p-floatLabel, p-float-label", inputs: ["variant"] }, { kind: "component", type: DatePicker, selector: "p-datePicker, p-datepicker, p-date-picker", inputs: ["iconDisplay", "styleClass", "inputStyle", "inputId", "inputStyleClass", "placeholder", "ariaLabelledBy", "ariaLabel", "iconAriaLabel", "dateFormat", "multipleSeparator", "rangeSeparator", "inline", "showOtherMonths", "selectOtherMonths", "showIcon", "icon", "readonlyInput", "shortYearCutoff", "hourFormat", "timeOnly", "stepHour", "stepMinute", "stepSecond", "showSeconds", "showOnFocus", "showWeek", "startWeekFromFirstDayOfYear", "showClear", "dataType", "selectionMode", "maxDateCount", "showButtonBar", "todayButtonStyleClass", "clearButtonStyleClass", "autofocus", "autoZIndex", "baseZIndex", "panelStyleClass", "panelStyle", "keepInvalid", "hideOnDateTimeSelect", "touchUI", "timeSeparator", "focusTrap", "showTransitionOptions", "hideTransitionOptions", "tabindex", "minDate", "maxDate", "disabledDates", "disabledDays", "showTime", "responsiveOptions", "numberOfMonths", "firstDayOfWeek", "view", "defaultDate", "appendTo", "motionOptions"], outputs: ["onFocus", "onBlur", "onClose", "onSelect", "onClear", "onInput", "onTodayClick", "onClearClick", "onMonthChange", "onYearChange", "onClickOutside", "onShow"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "component", type: AppMessageErrorComponent, selector: "dsx-message-error", inputs: ["control", "form", "debugMode"] }, { kind: "pipe", type: i1$1.JsonPipe, name: "json" }] });
8601
+ }
8602
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: DsxdateShort, decorators: [{
8603
+ type: Component,
8604
+ args: [{ selector: 'dsxdate-short', imports: [
8605
+ CommonModule,
8606
+ FloatLabel,
8607
+ DatePicker,
8608
+ ReactiveFormsModule,
8609
+ AppMessageErrorComponent,
8610
+ JsonPipe,
8611
+ ], providers: [
8612
+ {
8613
+ provide: NG_VALUE_ACCESSOR,
8614
+ useExisting: forwardRef(() => DsxdateShort),
8615
+ multi: true,
8616
+ },
8617
+ ], template: "<!-- dsxdate-short.html -->\r\n<p-floatLabel variant=\"on\">\r\n <p-datepicker\r\n [formControl]=\"fechaControl\"\r\n [fluid]=\"true\"\r\n [showIcon]=\"showIcon()\"\r\n [showOnFocus]=\"showOnFocus()\"\r\n [showButtonBar]=\"showButtonBar()\"\r\n [dateFormat]=\"dateFormat()\"\r\n [placeholder]=\"placeholder()\"\r\n pInputMask=\"99/99/9999\"\r\n />\r\n <label>{{ label() }}</label>\r\n</p-floatLabel>\r\n\r\n<!-- \u2705 SIN CONDICI\u00D3N - IGUAL QUE EL ORIGINAL -->\r\n<dsx-message-error [control]=\"fechaControl\" />\r\n\r\n<!-- Debug info -->\r\n@if (debugEnabled() && isDevMode) {\r\n<div\r\n class=\"debug-info\"\r\n style=\"\r\n font-size: 12px;\r\n color: #666;\r\n margin-top: 4px;\r\n border-top: 1px dashed #ccc;\r\n padding-top: 4px;\r\n \"\r\n>\r\n <small>\r\n <strong>Debug:</strong>\r\n Value: {{ fechaControl.value | json }} | Valid: {{ fechaControl.valid }} |\r\n Invalid: {{ fechaControl.invalid }} | Errors: {{ fechaControl.errors | json\r\n }} | Dirty: {{ fechaControl.dirty }} | Touched: {{ fechaControl.touched }} |\r\n Status: {{ fechaControl.status }}\r\n </small>\r\n</div>\r\n}\r\n" }]
8618
+ }], ctorParameters: () => [], propDecorators: { label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: true }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], dateFormat: [{ type: i0.Input, args: [{ isSignal: true, alias: "dateFormat", required: false }] }], showIcon: [{ type: i0.Input, args: [{ isSignal: true, alias: "showIcon", required: false }] }], showOnFocus: [{ type: i0.Input, args: [{ isSignal: true, alias: "showOnFocus", required: false }] }], showButtonBar: [{ type: i0.Input, args: [{ isSignal: true, alias: "showButtonBar", required: false }] }], debug: [{ type: i0.Input, args: [{ isSignal: true, alias: "debug", required: false }] }] } });
8619
+
8620
+ // dsx-input-currency.ts
8621
+ class DsxInputCurrency {
8622
+ inputNumber;
8623
+ injector = inject(Injector);
8624
+ // === INPUTS CONFIGURABLES ===
8625
+ label = input('Saldo Actual', ...(ngDevMode ? [{ debugName: "label" }] : /* istanbul ignore next */ []));
8626
+ currency = input('GTQ', ...(ngDevMode ? [{ debugName: "currency" }] : /* istanbul ignore next */ []));
8627
+ locale = input('es-GT', ...(ngDevMode ? [{ debugName: "locale" }] : /* istanbul ignore next */ []));
8628
+ minFractionDigits = input(2, ...(ngDevMode ? [{ debugName: "minFractionDigits" }] : /* istanbul ignore next */ []));
8629
+ maxFractionDigits = input(2, ...(ngDevMode ? [{ debugName: "maxFractionDigits" }] : /* istanbul ignore next */ []));
8630
+ placeholder = input('', ...(ngDevMode ? [{ debugName: "placeholder" }] : /* istanbul ignore next */ []));
8631
+ readonly = input(false, ...(ngDevMode ? [{ debugName: "readonly" }] : /* istanbul ignore next */ []));
8632
+ selectAllOnFocus = input(true, ...(ngDevMode ? [{ debugName: "selectAllOnFocus" }] : /* istanbul ignore next */ []));
8633
+ debug = input(false, ...(ngDevMode ? [{ debugName: "debug" }] : /* istanbul ignore next */ []));
8634
+ showError = input(true, ...(ngDevMode ? [{ debugName: "showError" }] : /* istanbul ignore next */ []));
8635
+ // === OUTPUTS ===
8636
+ valueChange = output();
8637
+ focus = output();
8638
+ blur = output();
8639
+ // === STATE ===
8640
+ valueSignal = signal(null, ...(ngDevMode ? [{ debugName: "valueSignal" }] : /* istanbul ignore next */ []));
8641
+ touched = signal(false, ...(ngDevMode ? [{ debugName: "touched" }] : /* istanbul ignore next */ []));
8642
+ debugEnabled = signal(false, ...(ngDevMode ? [{ debugName: "debugEnabled" }] : /* istanbul ignore next */ []));
8643
+ // === COMPUTED ===
8644
+ resolvedLabel = computed(() => this.label(), ...(ngDevMode ? [{ debugName: "resolvedLabel" }] : /* istanbul ignore next */ []));
8645
+ resolvedCurrency = computed(() => this.currency(), ...(ngDevMode ? [{ debugName: "resolvedCurrency" }] : /* istanbul ignore next */ []));
8646
+ resolvedLocale = computed(() => this.locale(), ...(ngDevMode ? [{ debugName: "resolvedLocale" }] : /* istanbul ignore next */ []));
8647
+ // === OBTENER EL CONTROL PADRE ===
8648
+ ngControl = computed(() => {
8649
+ try {
8650
+ return this.injector.get(NgControl);
8651
+ }
8652
+ catch {
8653
+ return null;
8654
+ }
8655
+ }, ...(ngDevMode ? [{ debugName: "ngControl" }] : /* istanbul ignore next */ []));
8656
+ // === CONTROL PADRE PARA ERRORES ===
8657
+ parentControl = computed(() => {
8658
+ const control = this.ngControl();
8659
+ return control?.control || null;
8660
+ }, ...(ngDevMode ? [{ debugName: "parentControl" }] : /* istanbul ignore next */ []));
8661
+ // === CONTROL INTERNO (para el template) ===
8662
+ control = new FormControl();
8663
+ // === CONTROL VALUE ACCESSOR ===
8664
+ onChange = () => { };
8665
+ onTouched = () => { };
8666
+ constructor() {
8667
+ // Debug effect
8668
+ effect(() => {
8669
+ const isDebug = this.debug() && isDevMode();
8670
+ this.debugEnabled.set(isDebug);
8671
+ if (isDebug) {
8672
+ console.log('[dsx-input-currency] === DEBUG MODE ACTIVADO ===');
8673
+ console.log('[dsx-input-currency] Configuración:', {
8674
+ label: this.label(),
8675
+ currency: this.currency(),
8676
+ locale: this.locale(),
8677
+ minFractionDigits: this.minFractionDigits(),
8678
+ maxFractionDigits: this.maxFractionDigits(),
8679
+ placeholder: this.placeholder(),
8680
+ readonly: this.readonly(),
8681
+ selectAllOnFocus: this.selectAllOnFocus(),
8682
+ });
8683
+ console.log('[dsx-input-currency] Control padre:', this.parentControl());
8684
+ }
8685
+ });
8686
+ // Monitorear cambios del control padre
8687
+ effect(() => {
8688
+ if (this.debugEnabled()) {
8689
+ const parentCtrl = this.parentControl();
8690
+ console.log('[dsx-input-currency] 📊 Parent Control state:', {
8691
+ value: parentCtrl?.value,
8692
+ status: parentCtrl?.status,
8693
+ errors: parentCtrl?.errors,
8694
+ valid: parentCtrl?.valid,
8695
+ invalid: parentCtrl?.invalid,
8696
+ touched: parentCtrl?.touched,
8697
+ dirty: parentCtrl?.dirty,
8698
+ });
8699
+ }
8700
+ });
8701
+ }
8702
+ ngAfterViewInit() {
8703
+ if (this.debugEnabled()) {
8704
+ console.log('[dsx-input-currency] ngAfterViewInit - Vista inicializada');
8705
+ }
8706
+ // Sincronizar el control padre con el interno
8707
+ const parentCtrl = this.parentControl();
8708
+ if (parentCtrl) {
8709
+ this.control.setValue(parentCtrl.value, { emitEvent: false });
8710
+ }
8711
+ if (this.inputNumber && this.selectAllOnFocus()) {
8712
+ const inputElement = this.inputNumber.input
8713
+ .nativeElement;
8714
+ if (this.debugEnabled()) {
8715
+ console.log('[dsx-input-currency] Input element encontrado');
8716
+ }
8717
+ const originalFocus = inputElement.focus.bind(inputElement);
8718
+ const enhancedFocus = function () {
8719
+ originalFocus();
8720
+ setTimeout(() => this.select(), 0);
8721
+ };
8722
+ inputElement.focus = enhancedFocus;
8723
+ }
8724
+ }
8725
+ // === MÉTODOS PÚBLICOS ===
8726
+ onValueChange(value) {
8727
+ // ✅ Solo procesar si es un número válido
8728
+ if (value === null || value === undefined || isNaN(value)) {
8729
+ return;
8730
+ }
8731
+ if (this.debugEnabled()) {
8732
+ console.log(`[dsx-input-currency] 📝 onValueChange - Valor: ${value}`);
8733
+ }
8734
+ this.valueSignal.set(value);
8735
+ this.onChange(value);
8736
+ this.valueChange.emit(value);
8737
+ const parentCtrl = this.parentControl();
8738
+ if (parentCtrl) {
8739
+ parentCtrl.setValue(value, { emitEvent: true });
8740
+ }
8741
+ }
8742
+ onFocus() {
8743
+ if (this.debugEnabled()) {
8744
+ console.log(`[dsx-input-currency] 🔍 onFocus - Evento focus emitido`);
8745
+ }
8746
+ if (this.selectAllOnFocus() && this.inputNumber) {
8747
+ const inputElement = this.inputNumber.input
8748
+ .nativeElement;
8749
+ if (inputElement && typeof inputElement.select === 'function') {
8750
+ setTimeout(() => {
8751
+ inputElement.select();
8752
+ if (this.debugEnabled()) {
8753
+ console.log('[dsx-input-currency] ✅ Input seleccionado completamente');
8754
+ }
8755
+ }, 0);
8756
+ }
8757
+ }
8758
+ this.focus.emit();
8759
+ }
8760
+ onBlur() {
8761
+ const wasTouched = this.touched();
8762
+ this.touched.set(true);
8763
+ this.control.markAsTouched();
8764
+ const parentCtrl = this.parentControl();
8765
+ if (parentCtrl) {
8766
+ parentCtrl.markAsTouched();
8767
+ }
8768
+ if (this.debugEnabled()) {
8769
+ console.log(`[dsx-input-currency] 👋 onBlur - touched: ${!wasTouched ? 'Primera vez' : 'Ya estaba touched'}`);
8770
+ }
8771
+ this.blur.emit();
8772
+ }
8773
+ // === MÉTODOS DE DEBUG ===
8774
+ log(message, data) {
8775
+ if (this.debugEnabled() && isDevMode()) {
8776
+ if (data !== undefined) {
8777
+ console.log(`[dsx-input-currency] ${message}`, data);
8778
+ }
8779
+ else {
8780
+ console.log(`[dsx-input-currency] ${message}`);
8781
+ }
8782
+ }
8783
+ }
8784
+ // === CONTROL VALUE ACCESSOR IMPLEMENTATION ===
8785
+ writeValue(value) {
8786
+ if (this.debugEnabled()) {
8787
+ console.log(`[dsx-input-currency] 📥 writeValue - Valor recibido: ${value}`);
8788
+ }
8789
+ this.valueSignal.set(value);
8790
+ this.control.setValue(value, { emitEvent: false });
8791
+ }
8792
+ registerOnChange(fn) {
8793
+ if (this.debugEnabled()) {
8794
+ console.log('[dsx-input-currency] 📞 registerOnChange - Callback registrado');
8795
+ }
8796
+ this.onChange = fn;
8797
+ this.control.valueChanges.subscribe((val) => {
8798
+ if (this.debugEnabled()) {
8799
+ console.log(`[dsx-input-currency] 🔄 valueChanges - Nuevo valor: ${val}`);
8800
+ }
8801
+ this.onChange(val);
8802
+ });
8803
+ }
8804
+ registerOnTouched(fn) {
8805
+ if (this.debugEnabled()) {
8806
+ console.log('[dsx-input-currency] 📞 registerOnTouched - Callback registrado');
8807
+ }
8808
+ this.onTouched = fn;
8809
+ this.control.statusChanges.subscribe(() => {
8810
+ if (this.debugEnabled()) {
8811
+ console.log(`[dsx-input-currency] 📊 statusChanges - Estado: ${this.control.status}`);
8812
+ }
8813
+ this.onTouched();
8814
+ });
8815
+ }
8816
+ setDisabledState(isDisabled) {
8817
+ if (this.debugEnabled()) {
8818
+ console.log(`[dsx-input-currency] 🚫 setDisabledState - Deshabilitado: ${isDisabled}`);
8819
+ }
8820
+ if (isDisabled) {
8821
+ this.control.disable({ emitEvent: false });
8822
+ }
8823
+ else {
8824
+ this.control.enable({ emitEvent: false });
8825
+ }
8826
+ }
8827
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: DsxInputCurrency, deps: [], target: i0.ɵɵFactoryTarget.Component });
8828
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.17", type: DsxInputCurrency, isStandalone: true, selector: "dsx-input-currency", inputs: { label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, currency: { classPropertyName: "currency", publicName: "currency", isSignal: true, isRequired: false, transformFunction: null }, locale: { classPropertyName: "locale", publicName: "locale", isSignal: true, isRequired: false, transformFunction: null }, minFractionDigits: { classPropertyName: "minFractionDigits", publicName: "minFractionDigits", isSignal: true, isRequired: false, transformFunction: null }, maxFractionDigits: { classPropertyName: "maxFractionDigits", publicName: "maxFractionDigits", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, readonly: { classPropertyName: "readonly", publicName: "readonly", isSignal: true, isRequired: false, transformFunction: null }, selectAllOnFocus: { classPropertyName: "selectAllOnFocus", publicName: "selectAllOnFocus", isSignal: true, isRequired: false, transformFunction: null }, debug: { classPropertyName: "debug", publicName: "debug", isSignal: true, isRequired: false, transformFunction: null }, showError: { classPropertyName: "showError", publicName: "showError", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { valueChange: "valueChange", focus: "focus", blur: "blur" }, providers: [
8829
+ {
8830
+ provide: NG_VALUE_ACCESSOR,
8831
+ useExisting: forwardRef(() => DsxInputCurrency),
8832
+ multi: true,
8833
+ },
8834
+ ], viewQueries: [{ propertyName: "inputNumber", first: true, predicate: InputNumber, descendants: true }], ngImport: i0, template: "<!-- dsx-input-currency.html -->\r\n<p-floatLabel [variant]=\"'on'\">\r\n <p-inputNumber\r\n #inputNumber\r\n fluid\r\n [mode]=\"'currency'\"\r\n [currency]=\"resolvedCurrency()\"\r\n [locale]=\"resolvedLocale()\"\r\n [minFractionDigits]=\"minFractionDigits()\"\r\n [maxFractionDigits]=\"maxFractionDigits()\"\r\n [placeholder]=\"placeholder()\"\r\n [autocomplete]=\"'off'\"\r\n [formControl]=\"control\"\r\n [readonly]=\"readonly()\"\r\n (onFocus)=\"onFocus()\"\r\n (onBlur)=\"onBlur()\"\r\n (onInput)=\"onValueChange($event.value)\"\r\n />\r\n <label>{{ resolvedLabel() }}</label>\r\n</p-floatLabel>\r\n\r\n<!-- Mensaje de error usando el control padre -->\r\n@if (showError() && parentControl()) {\r\n<!-- [debugMode]=\"true\" -->\r\n<dsx-message-error [control]=\"parentControl()\" />\r\n}\r\n", styles: [":host ::ng-deep .p-inputnumber-input{text-align:right}\n"], dependencies: [{ kind: "component", type: FloatLabel, selector: "p-floatlabel, p-floatLabel, p-float-label", inputs: ["variant"] }, { kind: "component", type: InputNumber, selector: "p-inputNumber, p-inputnumber, p-input-number", inputs: ["showButtons", "format", "buttonLayout", "inputId", "styleClass", "placeholder", "tabindex", "title", "ariaLabelledBy", "ariaDescribedBy", "ariaLabel", "ariaRequired", "autocomplete", "incrementButtonClass", "decrementButtonClass", "incrementButtonIcon", "decrementButtonIcon", "readonly", "allowEmpty", "locale", "localeMatcher", "mode", "currency", "currencyDisplay", "useGrouping", "minFractionDigits", "maxFractionDigits", "prefix", "suffix", "inputStyle", "inputStyleClass", "showClear", "autofocus"], outputs: ["onInput", "onFocus", "onBlur", "onKeyDown", "onClear"] }, { kind: "component", type: AppMessageErrorComponent, selector: "dsx-message-error", inputs: ["control", "form", "debugMode"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }] });
8835
+ }
8836
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: DsxInputCurrency, decorators: [{
8837
+ type: Component,
8838
+ args: [{ selector: 'dsx-input-currency', imports: [
8839
+ FloatLabel,
8840
+ InputNumber,
8841
+ AppMessageErrorComponent,
8842
+ ReactiveFormsModule,
8843
+ ], providers: [
8844
+ {
8845
+ provide: NG_VALUE_ACCESSOR,
8846
+ useExisting: forwardRef(() => DsxInputCurrency),
8847
+ multi: true,
8848
+ },
8849
+ ], template: "<!-- dsx-input-currency.html -->\r\n<p-floatLabel [variant]=\"'on'\">\r\n <p-inputNumber\r\n #inputNumber\r\n fluid\r\n [mode]=\"'currency'\"\r\n [currency]=\"resolvedCurrency()\"\r\n [locale]=\"resolvedLocale()\"\r\n [minFractionDigits]=\"minFractionDigits()\"\r\n [maxFractionDigits]=\"maxFractionDigits()\"\r\n [placeholder]=\"placeholder()\"\r\n [autocomplete]=\"'off'\"\r\n [formControl]=\"control\"\r\n [readonly]=\"readonly()\"\r\n (onFocus)=\"onFocus()\"\r\n (onBlur)=\"onBlur()\"\r\n (onInput)=\"onValueChange($event.value)\"\r\n />\r\n <label>{{ resolvedLabel() }}</label>\r\n</p-floatLabel>\r\n\r\n<!-- Mensaje de error usando el control padre -->\r\n@if (showError() && parentControl()) {\r\n<!-- [debugMode]=\"true\" -->\r\n<dsx-message-error [control]=\"parentControl()\" />\r\n}\r\n", styles: [":host ::ng-deep .p-inputnumber-input{text-align:right}\n"] }]
8850
+ }], ctorParameters: () => [], propDecorators: { inputNumber: [{
8851
+ type: ViewChild,
8852
+ args: [InputNumber]
8853
+ }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], currency: [{ type: i0.Input, args: [{ isSignal: true, alias: "currency", required: false }] }], locale: [{ type: i0.Input, args: [{ isSignal: true, alias: "locale", required: false }] }], minFractionDigits: [{ type: i0.Input, args: [{ isSignal: true, alias: "minFractionDigits", required: false }] }], maxFractionDigits: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxFractionDigits", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], readonly: [{ type: i0.Input, args: [{ isSignal: true, alias: "readonly", required: false }] }], selectAllOnFocus: [{ type: i0.Input, args: [{ isSignal: true, alias: "selectAllOnFocus", required: false }] }], debug: [{ type: i0.Input, args: [{ isSignal: true, alias: "debug", required: false }] }], showError: [{ type: i0.Input, args: [{ isSignal: true, alias: "showError", required: false }] }], valueChange: [{ type: i0.Output, args: ["valueChange"] }], focus: [{ type: i0.Output, args: ["focus"] }], blur: [{ type: i0.Output, args: ["blur"] }] } });
8854
+
8094
8855
  // dsx-select.component.ts
8095
8856
  class DsxSelect {
8096
8857
  injector = inject(Injector);
@@ -8105,22 +8866,28 @@ class DsxSelect {
8105
8866
  dataList = input.required(...(ngDevMode ? [{ debugName: "dataList" }] : /* istanbul ignore next */ []));
8106
8867
  variant = input('on', ...(ngDevMode ? [{ debugName: "variant" }] : /* istanbul ignore next */ []));
8107
8868
  label = input('', ...(ngDevMode ? [{ debugName: "label" }] : /* istanbul ignore next */ []));
8108
- filterPlaceholder = input('Buscar ...', ...(ngDevMode ? [{ debugName: "filterPlaceholder" }] : /* istanbul ignore next */ []));
8869
+ filterPlaceholder = input('Buscar item...', ...(ngDevMode ? [{ debugName: "filterPlaceholder" }] : /* istanbul ignore next */ []));
8109
8870
  showClear = input(true, ...(ngDevMode ? [{ debugName: "showClear" }] : /* istanbul ignore next */ []));
8110
8871
  // Override opcional (solo cuando la convención no aplica)
8111
8872
  optionLabel = input(undefined, ...(ngDevMode ? [{ debugName: "optionLabel" }] : /* istanbul ignore next */ []));
8112
8873
  optionValue = input(undefined, ...(ngDevMode ? [{ debugName: "optionValue" }] : /* istanbul ignore next */ []));
8874
+ // ✨ NUEVO: Campo secundario opcional (para mostrar información adicional)
8875
+ secondaryField = input(undefined, ...(ngDevMode ? [{ debugName: "secondaryField" }] : /* istanbul ignore next */ []));
8876
+ showSecondaryField = computed(() => !!this.secondaryField(), ...(ngDevMode ? [{ debugName: "showSecondaryField" }] : /* istanbul ignore next */ []));
8877
+ // ✨ NUEVO: Virtual Scroll (por defecto desactivado)
8878
+ virtualScroll = input(false, ...(ngDevMode ? [{ debugName: "virtualScroll" }] : /* istanbul ignore next */ []));
8879
+ virtualScrollItemSize = input(40, ...(ngDevMode ? [{ debugName: "virtualScrollItemSize" }] : /* istanbul ignore next */ []));
8113
8880
  // Iconos
8114
8881
  useIcon = input(true, ...(ngDevMode ? [{ debugName: "useIcon" }] : /* istanbul ignore next */ []));
8115
- itemIcon = input('label', ...(ngDevMode ? [{ debugName: "itemIcon" }] : /* istanbul ignore next */ []));
8882
+ itemIcon = input('keyboard_arrow_right', ...(ngDevMode ? [{ debugName: "itemIcon" }] : /* istanbul ignore next */ []));
8116
8883
  selectedIcon = input('done_outline', ...(ngDevMode ? [{ debugName: "selectedIcon" }] : /* istanbul ignore next */ []));
8117
8884
  // Debug solo consola
8118
8885
  debug = input(false, ...(ngDevMode ? [{ debugName: "debug" }] : /* istanbul ignore next */ []));
8119
- // Mostrar mensajes de error (por defecto true)
8886
+ // Mostrar mensajes de error (por defecto true)
8120
8887
  showError = input(true, ...(ngDevMode ? [{ debugName: "showError" }] : /* istanbul ignore next */ []));
8121
8888
  // Signal model para two-way binding
8122
8889
  selectedValue = model(null, ...(ngDevMode ? [{ debugName: "selectedValue" }] : /* istanbul ignore next */ []));
8123
- // Computed: OptionValue inferido automáticamente (siempre string)
8890
+ // Computed: OptionValue inferido automáticamente
8124
8891
  resolvedOptionValue = computed(() => {
8125
8892
  if (this.optionValue()) {
8126
8893
  return this.optionValue();
@@ -8134,7 +8901,7 @@ class DsxSelect {
8134
8901
  }
8135
8902
  return 'id';
8136
8903
  }, ...(ngDevMode ? [{ debugName: "resolvedOptionValue" }] : /* istanbul ignore next */ []));
8137
- // Computed: OptionLabel inferido automáticamente (siempre string)
8904
+ // Computed: OptionLabel inferido automáticamente
8138
8905
  resolvedOptionLabel = computed(() => {
8139
8906
  if (this.optionLabel()) {
8140
8907
  return this.optionLabel();
@@ -8148,7 +8915,7 @@ class DsxSelect {
8148
8915
  }
8149
8916
  return 'nombre';
8150
8917
  }, ...(ngDevMode ? [{ debugName: "resolvedOptionLabel" }] : /* istanbul ignore next */ []));
8151
- // Computed: Label inferido automáticamente (siempre string)
8918
+ // Computed: Label inferido automáticamente
8152
8919
  resolvedLabel = computed(() => {
8153
8920
  if (this.label()) {
8154
8921
  return this.label();
@@ -8161,7 +8928,7 @@ class DsxSelect {
8161
8928
  }
8162
8929
  return 'Campo';
8163
8930
  }, ...(ngDevMode ? [{ debugName: "resolvedLabel" }] : /* istanbul ignore next */ []));
8164
- // Computed: Obtener el control para errores (solo si showError es true)
8931
+ // Computed: Obtener el control para errores
8165
8932
  errorControl = computed(() => {
8166
8933
  if (!this.showError())
8167
8934
  return null;
@@ -8183,6 +8950,8 @@ class DsxSelect {
8183
8950
  optionLabel: this.resolvedOptionLabel(),
8184
8951
  label: this.resolvedLabel(),
8185
8952
  showError: this.showError(),
8953
+ virtualScroll: this.virtualScroll(),
8954
+ secondaryField: this.secondaryField(),
8186
8955
  });
8187
8956
  }
8188
8957
  });
@@ -8196,14 +8965,22 @@ class DsxSelect {
8196
8965
  console.log(`Control: ${this.getFormControlName()}`);
8197
8966
  console.log(`Items: ${dataList.length}`);
8198
8967
  console.log(`Using: optionValue="${this.resolvedOptionValue()}", optionLabel="${this.resolvedOptionLabel()}"`);
8968
+ if (this.secondaryField()) {
8969
+ console.log(`Secondary field: "${this.secondaryField()}"`);
8970
+ }
8199
8971
  console.log(`Time since last update: ${(currentTime - this.lastChangeTimestamp).toFixed(2)}ms`);
8200
8972
  if (dataList.length > 0 && this.debug()) {
8201
8973
  console.log(`Sample:`, dataList[0]);
8202
8974
  console.log(`Value sample:`, dataList[0][this.resolvedOptionValue()]);
8203
8975
  console.log(`Label sample:`, dataList[0][this.resolvedOptionLabel()]);
8976
+ if (this.secondaryField()) {
8977
+ const secondary = this.secondaryField();
8978
+ console.log(`Secondary sample:`, dataList[0][secondary]);
8979
+ }
8204
8980
  }
8205
8981
  if (dataList.length > 500) {
8206
8982
  console.warn(`⚠️ Large dataset: ${dataList.length} items`);
8983
+ console.log(`💡 Consider enabling virtualScroll="true"`);
8207
8984
  }
8208
8985
  console.groupEnd();
8209
8986
  }
@@ -8270,14 +9047,41 @@ class DsxSelect {
8270
9047
  console.groupEnd();
8271
9048
  }
8272
9049
  }
9050
+ // dsx-select.component.ts - Agregar estos métodos
9051
+ /**
9052
+ * Cuando el select recibe foco
9053
+ */
9054
+ onFocus() {
9055
+ if (this.debug()) {
9056
+ console.log('[DsxSelect] onFocus');
9057
+ }
9058
+ }
9059
+ /**
9060
+ * Cuando el panel de opciones se cierra (el usuario ha interactuado)
9061
+ * Este es el evento clave que marca el control como touched
9062
+ */
9063
+ onHide() {
9064
+ if (this.debug()) {
9065
+ console.log('[DsxSelect] onHide - dropdown closed');
9066
+ }
9067
+ // Marcar como touched cuando el usuario cierra el dropdown
9068
+ // Esto incluye: seleccionar un valor O hacer clic fuera
9069
+ if (this.ngControl?.control && !this.ngControl.control.touched) {
9070
+ this.ngControl.control.markAsTouched();
9071
+ this.onTouched();
9072
+ if (this.debug()) {
9073
+ console.log('[DsxSelect] Control marked as touched (onHide)');
9074
+ }
9075
+ }
9076
+ }
8273
9077
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: DsxSelect, deps: [], target: i0.ɵɵFactoryTarget.Component });
8274
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.17", type: DsxSelect, isStandalone: true, selector: "dsx-select", inputs: { dataList: { classPropertyName: "dataList", publicName: "dataList", isSignal: true, isRequired: true, transformFunction: null }, variant: { classPropertyName: "variant", publicName: "variant", isSignal: true, isRequired: false, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, filterPlaceholder: { classPropertyName: "filterPlaceholder", publicName: "filterPlaceholder", isSignal: true, isRequired: false, transformFunction: null }, showClear: { classPropertyName: "showClear", publicName: "showClear", isSignal: true, isRequired: false, transformFunction: null }, optionLabel: { classPropertyName: "optionLabel", publicName: "optionLabel", isSignal: true, isRequired: false, transformFunction: null }, optionValue: { classPropertyName: "optionValue", publicName: "optionValue", isSignal: true, isRequired: false, transformFunction: null }, useIcon: { classPropertyName: "useIcon", publicName: "useIcon", isSignal: true, isRequired: false, transformFunction: null }, itemIcon: { classPropertyName: "itemIcon", publicName: "itemIcon", isSignal: true, isRequired: false, transformFunction: null }, selectedIcon: { classPropertyName: "selectedIcon", publicName: "selectedIcon", isSignal: true, isRequired: false, transformFunction: null }, debug: { classPropertyName: "debug", publicName: "debug", isSignal: true, isRequired: false, transformFunction: null }, showError: { classPropertyName: "showError", publicName: "showError", isSignal: true, isRequired: false, transformFunction: null }, selectedValue: { classPropertyName: "selectedValue", publicName: "selectedValue", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { selectedValue: "selectedValueChange" }, providers: [
9078
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.17", type: DsxSelect, isStandalone: true, selector: "dsx-select", inputs: { dataList: { classPropertyName: "dataList", publicName: "dataList", isSignal: true, isRequired: true, transformFunction: null }, variant: { classPropertyName: "variant", publicName: "variant", isSignal: true, isRequired: false, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, filterPlaceholder: { classPropertyName: "filterPlaceholder", publicName: "filterPlaceholder", isSignal: true, isRequired: false, transformFunction: null }, showClear: { classPropertyName: "showClear", publicName: "showClear", isSignal: true, isRequired: false, transformFunction: null }, optionLabel: { classPropertyName: "optionLabel", publicName: "optionLabel", isSignal: true, isRequired: false, transformFunction: null }, optionValue: { classPropertyName: "optionValue", publicName: "optionValue", isSignal: true, isRequired: false, transformFunction: null }, secondaryField: { classPropertyName: "secondaryField", publicName: "secondaryField", isSignal: true, isRequired: false, transformFunction: null }, virtualScroll: { classPropertyName: "virtualScroll", publicName: "virtualScroll", isSignal: true, isRequired: false, transformFunction: null }, virtualScrollItemSize: { classPropertyName: "virtualScrollItemSize", publicName: "virtualScrollItemSize", isSignal: true, isRequired: false, transformFunction: null }, useIcon: { classPropertyName: "useIcon", publicName: "useIcon", isSignal: true, isRequired: false, transformFunction: null }, itemIcon: { classPropertyName: "itemIcon", publicName: "itemIcon", isSignal: true, isRequired: false, transformFunction: null }, selectedIcon: { classPropertyName: "selectedIcon", publicName: "selectedIcon", isSignal: true, isRequired: false, transformFunction: null }, debug: { classPropertyName: "debug", publicName: "debug", isSignal: true, isRequired: false, transformFunction: null }, showError: { classPropertyName: "showError", publicName: "showError", isSignal: true, isRequired: false, transformFunction: null }, selectedValue: { classPropertyName: "selectedValue", publicName: "selectedValue", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { selectedValue: "selectedValueChange" }, providers: [
8275
9079
  {
8276
9080
  provide: NG_VALUE_ACCESSOR,
8277
9081
  useExisting: forwardRef(() => DsxSelect),
8278
9082
  multi: true,
8279
9083
  },
8280
- ], ngImport: i0, template: "<!-- dsx-select.html -->\r\n<p-floatLabel [variant]=\"variant()\">\r\n <p-select\r\n fluid\r\n [options]=\"dataList()\"\r\n [filter]=\"true\"\r\n [filterPlaceholder]=\"filterPlaceholder()\"\r\n [showClear]=\"showClear()\"\r\n [disabled]=\"disabled\"\r\n [optionLabel]=\"resolvedOptionLabel()\"\r\n [optionValue]=\"resolvedOptionValue()\"\r\n [(ngModel)]=\"value\"\r\n (ngModelChange)=\"onValueChange($event)\"\r\n >\r\n <ng-template let-item #item>\r\n <div class=\"flex align-items-center\">\r\n @if (useIcon()) {\r\n <icon-dsx [name]=\"itemIcon()\" class=\"text-cyan-500! mr-1\"></icon-dsx>\r\n } {{ item[resolvedOptionLabel()] }}\r\n </div>\r\n </ng-template>\r\n\r\n <ng-template #selectedItem let-selectedOptions>\r\n <div class=\"flex align-items-center\">\r\n @if (useIcon()) {\r\n <icon-dsx\r\n [name]=\"selectedIcon()\"\r\n class=\"text-green-600! mr-1\"\r\n ></icon-dsx>\r\n } {{ selectedOptions?.[resolvedOptionLabel()] }}\r\n </div>\r\n </ng-template>\r\n </p-select>\r\n <label>{{ resolvedLabel() }}</label>\r\n</p-floatLabel>\r\n\r\n<!-- \u2705 Mensaje de error condicional (dentro del floatLabel) -->\r\n@if (showError() && errorControl()) {\r\n<app-message-error [control]=\"errorControl()\" />\r\n}\r\n", styles: ["icon-dsx{font-size:1.5em}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { 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: "component", type: Select, selector: "p-select", inputs: ["id", "scrollHeight", "filter", "panelStyle", "styleClass", "panelStyleClass", "readonly", "editable", "tabindex", "placeholder", "loadingIcon", "filterPlaceholder", "filterLocale", "inputId", "dataKey", "filterBy", "filterFields", "autofocus", "resetFilterOnHide", "checkmark", "dropdownIcon", "loading", "optionLabel", "optionValue", "optionDisabled", "optionGroupLabel", "optionGroupChildren", "group", "showClear", "emptyFilterMessage", "emptyMessage", "lazy", "virtualScroll", "virtualScrollItemSize", "virtualScrollOptions", "overlayOptions", "ariaFilterLabel", "ariaLabel", "ariaLabelledBy", "filterMatchMode", "tooltip", "tooltipPosition", "tooltipPositionStyle", "tooltipStyleClass", "focusOnHover", "selectOnFocus", "autoOptionFocus", "autofocusFilter", "filterValue", "options", "appendTo", "motionOptions"], outputs: ["onChange", "onFilter", "onFocus", "onBlur", "onClick", "onShow", "onHide", "onClear", "onLazyLoad"] }, { kind: "component", type: FloatLabel, selector: "p-floatlabel, p-floatLabel, p-float-label", inputs: ["variant"] }, { kind: "component", type: IconDsxComponent, selector: "icon-dsx", inputs: ["name", "style", "debug"] }, { kind: "component", type: AppMessageErrorComponent, selector: "app-message-error", inputs: ["control", "form", "debugMode"] }] });
9084
+ ], ngImport: i0, template: "<!-- dsx-select.html -->\r\n<p-floatLabel [variant]=\"variant()\">\r\n <p-select\r\n fluid\r\n appendTo=\"body\"\r\n [options]=\"dataList()\"\r\n [filter]=\"true\"\r\n [filterPlaceholder]=\"filterPlaceholder()\"\r\n [showClear]=\"showClear()\"\r\n [disabled]=\"disabled\"\r\n [optionLabel]=\"resolvedOptionLabel()\"\r\n [optionValue]=\"resolvedOptionValue()\"\r\n [virtualScroll]=\"virtualScroll()\"\r\n [virtualScrollItemSize]=\"virtualScrollItemSize()\"\r\n [(ngModel)]=\"value\"\r\n (ngModelChange)=\"onValueChange($event)\"\r\n (onFocus)=\"onFocus()\"\r\n (onHide)=\"onHide()\"\r\n >\r\n <!-- Item template -->\r\n <ng-template let-item #item>\r\n <div class=\"flex align-items-center gap-2\">\r\n @if (useIcon()) {\r\n <icon-dsx [name]=\"itemIcon()\" class=\"text-cyan-500! mr-1\"></icon-dsx>\r\n } @if (showSecondaryField()) {\r\n <div class=\"flex flex-col\">\r\n <span class=\"font-semibold text-sky-800\">\r\n {{ item[resolvedOptionLabel()] }}\r\n </span>\r\n <span class=\"text-xs text-gray-400\">\r\n {{ item[secondaryField()!] }}\r\n </span>\r\n </div>\r\n } @else { {{ item[resolvedOptionLabel()] }} }\r\n </div>\r\n </ng-template>\r\n\r\n <!-- Selected item template -->\r\n <ng-template #selectedItem let-selectedOptions>\r\n <div class=\"flex align-items-center gap-2\">\r\n @if (useIcon()) {\r\n <icon-dsx [name]=\"selectedIcon()\" class=\"text-green-600!\"></icon-dsx>\r\n } @if (showSecondaryField() && selectedOptions) {\r\n <div class=\"flex gap-x-2\">\r\n <span class=\"font-semibold text-sky-700\">\r\n {{ selectedOptions[resolvedOptionLabel()] }}\r\n </span>\r\n <span class=\"text-gray-400\">\r\n {{ selectedOptions[secondaryField()!] }}\r\n </span>\r\n </div>\r\n } @else { {{ selectedOptions?.[resolvedOptionLabel()] }} }\r\n </div>\r\n </ng-template>\r\n </p-select>\r\n <label>{{ resolvedLabel() }}</label>\r\n</p-floatLabel>\r\n\r\n<!-- Mensaje de error condicional -->\r\n@if (showError() && errorControl()) {\r\n<dsx-message-error [control]=\"errorControl()\" />\r\n}\r\n", styles: ["icon-dsx{font-size:1.5em}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { 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: "component", type: Select, selector: "p-select", inputs: ["id", "scrollHeight", "filter", "panelStyle", "styleClass", "panelStyleClass", "readonly", "editable", "tabindex", "placeholder", "loadingIcon", "filterPlaceholder", "filterLocale", "inputId", "dataKey", "filterBy", "filterFields", "autofocus", "resetFilterOnHide", "checkmark", "dropdownIcon", "loading", "optionLabel", "optionValue", "optionDisabled", "optionGroupLabel", "optionGroupChildren", "group", "showClear", "emptyFilterMessage", "emptyMessage", "lazy", "virtualScroll", "virtualScrollItemSize", "virtualScrollOptions", "overlayOptions", "ariaFilterLabel", "ariaLabel", "ariaLabelledBy", "filterMatchMode", "tooltip", "tooltipPosition", "tooltipPositionStyle", "tooltipStyleClass", "focusOnHover", "selectOnFocus", "autoOptionFocus", "autofocusFilter", "filterValue", "options", "appendTo", "motionOptions"], outputs: ["onChange", "onFilter", "onFocus", "onBlur", "onClick", "onShow", "onHide", "onClear", "onLazyLoad"] }, { kind: "component", type: FloatLabel, selector: "p-floatlabel, p-floatLabel, p-float-label", inputs: ["variant"] }, { kind: "component", type: IconDsxComponent, selector: "icon-dsx", inputs: ["name", "style", "debug"] }, { kind: "component", type: AppMessageErrorComponent, selector: "dsx-message-error", inputs: ["control", "form", "debugMode"] }] });
8281
9085
  }
8282
9086
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: DsxSelect, decorators: [{
8283
9087
  type: Component,
@@ -8293,8 +9097,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImpo
8293
9097
  useExisting: forwardRef(() => DsxSelect),
8294
9098
  multi: true,
8295
9099
  },
8296
- ], template: "<!-- dsx-select.html -->\r\n<p-floatLabel [variant]=\"variant()\">\r\n <p-select\r\n fluid\r\n [options]=\"dataList()\"\r\n [filter]=\"true\"\r\n [filterPlaceholder]=\"filterPlaceholder()\"\r\n [showClear]=\"showClear()\"\r\n [disabled]=\"disabled\"\r\n [optionLabel]=\"resolvedOptionLabel()\"\r\n [optionValue]=\"resolvedOptionValue()\"\r\n [(ngModel)]=\"value\"\r\n (ngModelChange)=\"onValueChange($event)\"\r\n >\r\n <ng-template let-item #item>\r\n <div class=\"flex align-items-center\">\r\n @if (useIcon()) {\r\n <icon-dsx [name]=\"itemIcon()\" class=\"text-cyan-500! mr-1\"></icon-dsx>\r\n } {{ item[resolvedOptionLabel()] }}\r\n </div>\r\n </ng-template>\r\n\r\n <ng-template #selectedItem let-selectedOptions>\r\n <div class=\"flex align-items-center\">\r\n @if (useIcon()) {\r\n <icon-dsx\r\n [name]=\"selectedIcon()\"\r\n class=\"text-green-600! mr-1\"\r\n ></icon-dsx>\r\n } {{ selectedOptions?.[resolvedOptionLabel()] }}\r\n </div>\r\n </ng-template>\r\n </p-select>\r\n <label>{{ resolvedLabel() }}</label>\r\n</p-floatLabel>\r\n\r\n<!-- \u2705 Mensaje de error condicional (dentro del floatLabel) -->\r\n@if (showError() && errorControl()) {\r\n<app-message-error [control]=\"errorControl()\" />\r\n}\r\n", styles: ["icon-dsx{font-size:1.5em}\n"] }]
8297
- }], ctorParameters: () => [], propDecorators: { dataList: [{ type: i0.Input, args: [{ isSignal: true, alias: "dataList", required: true }] }], variant: [{ type: i0.Input, args: [{ isSignal: true, alias: "variant", required: false }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], filterPlaceholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "filterPlaceholder", required: false }] }], showClear: [{ type: i0.Input, args: [{ isSignal: true, alias: "showClear", required: false }] }], optionLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "optionLabel", required: false }] }], optionValue: [{ type: i0.Input, args: [{ isSignal: true, alias: "optionValue", required: false }] }], useIcon: [{ type: i0.Input, args: [{ isSignal: true, alias: "useIcon", required: false }] }], itemIcon: [{ type: i0.Input, args: [{ isSignal: true, alias: "itemIcon", required: false }] }], selectedIcon: [{ type: i0.Input, args: [{ isSignal: true, alias: "selectedIcon", required: false }] }], debug: [{ type: i0.Input, args: [{ isSignal: true, alias: "debug", required: false }] }], showError: [{ type: i0.Input, args: [{ isSignal: true, alias: "showError", required: false }] }], selectedValue: [{ type: i0.Input, args: [{ isSignal: true, alias: "selectedValue", required: false }] }, { type: i0.Output, args: ["selectedValueChange"] }] } });
9100
+ ], template: "<!-- dsx-select.html -->\r\n<p-floatLabel [variant]=\"variant()\">\r\n <p-select\r\n fluid\r\n appendTo=\"body\"\r\n [options]=\"dataList()\"\r\n [filter]=\"true\"\r\n [filterPlaceholder]=\"filterPlaceholder()\"\r\n [showClear]=\"showClear()\"\r\n [disabled]=\"disabled\"\r\n [optionLabel]=\"resolvedOptionLabel()\"\r\n [optionValue]=\"resolvedOptionValue()\"\r\n [virtualScroll]=\"virtualScroll()\"\r\n [virtualScrollItemSize]=\"virtualScrollItemSize()\"\r\n [(ngModel)]=\"value\"\r\n (ngModelChange)=\"onValueChange($event)\"\r\n (onFocus)=\"onFocus()\"\r\n (onHide)=\"onHide()\"\r\n >\r\n <!-- Item template -->\r\n <ng-template let-item #item>\r\n <div class=\"flex align-items-center gap-2\">\r\n @if (useIcon()) {\r\n <icon-dsx [name]=\"itemIcon()\" class=\"text-cyan-500! mr-1\"></icon-dsx>\r\n } @if (showSecondaryField()) {\r\n <div class=\"flex flex-col\">\r\n <span class=\"font-semibold text-sky-800\">\r\n {{ item[resolvedOptionLabel()] }}\r\n </span>\r\n <span class=\"text-xs text-gray-400\">\r\n {{ item[secondaryField()!] }}\r\n </span>\r\n </div>\r\n } @else { {{ item[resolvedOptionLabel()] }} }\r\n </div>\r\n </ng-template>\r\n\r\n <!-- Selected item template -->\r\n <ng-template #selectedItem let-selectedOptions>\r\n <div class=\"flex align-items-center gap-2\">\r\n @if (useIcon()) {\r\n <icon-dsx [name]=\"selectedIcon()\" class=\"text-green-600!\"></icon-dsx>\r\n } @if (showSecondaryField() && selectedOptions) {\r\n <div class=\"flex gap-x-2\">\r\n <span class=\"font-semibold text-sky-700\">\r\n {{ selectedOptions[resolvedOptionLabel()] }}\r\n </span>\r\n <span class=\"text-gray-400\">\r\n {{ selectedOptions[secondaryField()!] }}\r\n </span>\r\n </div>\r\n } @else { {{ selectedOptions?.[resolvedOptionLabel()] }} }\r\n </div>\r\n </ng-template>\r\n </p-select>\r\n <label>{{ resolvedLabel() }}</label>\r\n</p-floatLabel>\r\n\r\n<!-- Mensaje de error condicional -->\r\n@if (showError() && errorControl()) {\r\n<dsx-message-error [control]=\"errorControl()\" />\r\n}\r\n", styles: ["icon-dsx{font-size:1.5em}\n"] }]
9101
+ }], ctorParameters: () => [], propDecorators: { dataList: [{ type: i0.Input, args: [{ isSignal: true, alias: "dataList", required: true }] }], variant: [{ type: i0.Input, args: [{ isSignal: true, alias: "variant", required: false }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], filterPlaceholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "filterPlaceholder", required: false }] }], showClear: [{ type: i0.Input, args: [{ isSignal: true, alias: "showClear", required: false }] }], optionLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "optionLabel", required: false }] }], optionValue: [{ type: i0.Input, args: [{ isSignal: true, alias: "optionValue", required: false }] }], secondaryField: [{ type: i0.Input, args: [{ isSignal: true, alias: "secondaryField", required: false }] }], virtualScroll: [{ type: i0.Input, args: [{ isSignal: true, alias: "virtualScroll", required: false }] }], virtualScrollItemSize: [{ type: i0.Input, args: [{ isSignal: true, alias: "virtualScrollItemSize", required: false }] }], useIcon: [{ type: i0.Input, args: [{ isSignal: true, alias: "useIcon", required: false }] }], itemIcon: [{ type: i0.Input, args: [{ isSignal: true, alias: "itemIcon", required: false }] }], selectedIcon: [{ type: i0.Input, args: [{ isSignal: true, alias: "selectedIcon", required: false }] }], debug: [{ type: i0.Input, args: [{ isSignal: true, alias: "debug", required: false }] }], showError: [{ type: i0.Input, args: [{ isSignal: true, alias: "showError", required: false }] }], selectedValue: [{ type: i0.Input, args: [{ isSignal: true, alias: "selectedValue", required: false }] }, { type: i0.Output, args: ["selectedValueChange"] }] } });
8298
9102
 
8299
9103
  /**
8300
9104
  * Servicio genérico para consumir endpoints REST de la API.
@@ -9551,44 +10355,98 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImpo
9551
10355
 
9552
10356
  // form-preview.service.ts
9553
10357
  class FormPreviewService {
10358
+ environment;
10359
+ constructor() {
10360
+ // Inyectar el token en el constructor
10361
+ this.environment = inject(ENVIRONMENT);
10362
+ }
9554
10363
  /**
9555
- * Genera resumen HTML desde un objeto plano
9556
- * @param data - Objeto con los datos (ej: form.value)
9557
- * @param fields - Array de campos a mostrar
9558
- * @param options - Opciones adicionales
10364
+ * Construye el HTML para el preview de un objeto
10365
+ * @param data - Objeto con los datos a mostrar
10366
+ * @param fields - Configuración de los campos a mostrar
10367
+ * @param options - Opciones de configuración
10368
+ * @returns String con el HTML generado
10369
+ *
10370
+ * @example
10371
+ * ```typescript
10372
+ * const data = {
10373
+ * usuario: {
10374
+ * nombre: 'Juan Pérez',
10375
+ * email: 'juan@email.com'
10376
+ * },
10377
+ * estado: 1
10378
+ * };
10379
+ *
10380
+ * const fields = [
10381
+ * { key: 'usuario.nombre', label: 'Nombre' },
10382
+ * { key: 'usuario.email', label: 'Email' },
10383
+ * {
10384
+ * key: 'estado',
10385
+ * label: 'Estado',
10386
+ * referenceMap: new Map([[1, 'Activo'], [2, 'Inactivo']])
10387
+ * }
10388
+ * ];
10389
+ *
10390
+ * const html = this.formPreviewService.buildObjectSummaryHtml(data, fields, {
10391
+ * title: 'Datos del Usuario',
10392
+ * showEmpty: false,
10393
+ * compact: true,
10394
+ * debug: false
10395
+ * });
10396
+ * ```
9559
10397
  */
9560
10398
  buildObjectSummaryHtml(data, fields, options) {
9561
10399
  const debug = options?.debug ?? false;
9562
- // Modo desarrollo: mostrar información de depuración
9563
- if (debug) {
10400
+ const isDev = !this.environment.production;
10401
+ // Solo ejecutar logs si estamos en desarrollo y debug está activado
10402
+ if (debug && isDev) {
9564
10403
  this.debugInputData(data, fields, options);
9565
10404
  }
10405
+ // Logs de error siempre se muestran en desarrollo si debug está activado
9566
10406
  if (!data) {
9567
- if (debug)
10407
+ if (debug && isDev) {
9568
10408
  console.error('❌ FormPreview: data es null o undefined');
10409
+ }
9569
10410
  return '';
9570
10411
  }
9571
10412
  if (!fields || fields.length === 0) {
9572
- if (debug)
10413
+ if (debug && isDev) {
9573
10414
  console.error('❌ FormPreview: fields está vacío');
10415
+ }
9574
10416
  return '';
9575
10417
  }
9576
10418
  const showEmpty = options?.showEmpty ?? false;
9577
10419
  const compact = options?.compact ?? true;
9578
- const title = options?.title || 'Datos del formulario';
10420
+ const title = options?.title || '📋 Datos a guardar';
9579
10421
  const cells = [];
9580
10422
  const propiedadesNoEncontradas = [];
9581
10423
  for (const field of fields) {
9582
- // Obtener valor
9583
- const value = this.getNestedValue(data, field.key);
10424
+ let value = this.getNestedValue(data, field.key);
10425
+ // Resolver referencia si existe
10426
+ if (field.referenceMap && value !== undefined && value !== null) {
10427
+ const originalValue = value;
10428
+ value = this.resolveReferenceValue(value, field);
10429
+ // Logs de depuración solo en desarrollo
10430
+ if (debug && isDev) {
10431
+ console.log(`🔍 Resolviendo referencia para "${field.key}":`, {
10432
+ original: originalValue,
10433
+ resuelto: value,
10434
+ tipoMapa: Array.isArray(field.referenceMap)
10435
+ ? 'Array'
10436
+ : field.referenceMap instanceof Map
10437
+ ? 'Map'
10438
+ : typeof field.referenceMap === 'function'
10439
+ ? 'Función'
10440
+ : 'Objeto',
10441
+ });
10442
+ }
10443
+ }
9584
10444
  const valueText = field.format
9585
10445
  ? field.format(value)
9586
10446
  : this.formatValue(value);
9587
- // Registrar si no se encontró la propiedad
9588
10447
  if (value === undefined) {
9589
10448
  propiedadesNoEncontradas.push(field.key);
9590
10449
  }
9591
- // Filtrar vacíos
9592
10450
  if (!showEmpty && !valueText)
9593
10451
  continue;
9594
10452
  cells.push({
@@ -9596,8 +10454,8 @@ class FormPreviewService {
9596
10454
  value: valueText || '—',
9597
10455
  });
9598
10456
  }
9599
- // Modo desarrollo: mostrar advertencias
9600
- if (debug) {
10457
+ // Logs de depuración solo en desarrollo
10458
+ if (debug && isDev) {
9601
10459
  if (propiedadesNoEncontradas.length > 0) {
9602
10460
  console.warn('⚠️ FormPreview: Propiedades no encontradas:', propiedadesNoEncontradas);
9603
10461
  console.warn('📋 Propiedades disponibles en data:', Object.keys(data));
@@ -9616,15 +10474,55 @@ class FormPreviewService {
9616
10474
  return '';
9617
10475
  return this.generateHtml(title, cells, compact);
9618
10476
  }
10477
+ resolveReferenceValue(value, field) {
10478
+ if (Array.isArray(value)) {
10479
+ return value.map((item) => this.resolveSingleReference(item, field));
10480
+ }
10481
+ return this.resolveSingleReference(value, field);
10482
+ }
10483
+ resolveSingleReference(value, field) {
10484
+ if (!value)
10485
+ return value;
10486
+ if (typeof value === 'object' && value !== null)
10487
+ return value;
10488
+ const map = field.referenceMap;
10489
+ if (!map)
10490
+ return value;
10491
+ let referencedItem = null;
10492
+ if (typeof map === 'function') {
10493
+ referencedItem = map(value);
10494
+ }
10495
+ else if (map instanceof Map) {
10496
+ referencedItem = map.get(value);
10497
+ }
10498
+ else if (Array.isArray(map)) {
10499
+ const idKey = field.referenceId || 'id';
10500
+ referencedItem = map.find((item) => item[idKey] === value);
10501
+ }
10502
+ else if (typeof map === 'object') {
10503
+ referencedItem = map[String(value)];
10504
+ }
10505
+ if (referencedItem) {
10506
+ const labelProp = field.referenceLabel || 'nombre';
10507
+ if (typeof referencedItem === 'object' && referencedItem !== null) {
10508
+ if (referencedItem[labelProp] !== undefined &&
10509
+ referencedItem[labelProp] !== null) {
10510
+ return referencedItem[labelProp];
10511
+ }
10512
+ return referencedItem;
10513
+ }
10514
+ return referencedItem;
10515
+ }
10516
+ return value;
10517
+ }
9619
10518
  getNestedValue(obj, path) {
9620
10519
  if (!obj || !path)
9621
10520
  return undefined;
9622
10521
  const parts = path.split('.');
9623
10522
  let result = obj;
9624
10523
  for (const part of parts) {
9625
- if (result === null || result === undefined) {
10524
+ if (result === null || result === undefined)
9626
10525
  return undefined;
9627
- }
9628
10526
  result = result[part];
9629
10527
  }
9630
10528
  return result;
@@ -9635,24 +10533,47 @@ class FormPreviewService {
9635
10533
  if (value instanceof Date)
9636
10534
  return value.toLocaleDateString();
9637
10535
  if (typeof value === 'object') {
9638
- // Para selects, mostrar propiedades comunes
9639
- if (value.label)
9640
- return String(value.label);
9641
- if (value.nombre)
9642
- return String(value.nombre);
9643
- if (value.name)
9644
- return String(value.name);
9645
- if (value.value)
9646
- return String(value.value);
9647
- try {
9648
- return JSON.stringify(value);
9649
- }
9650
- catch {
9651
- return String(value);
10536
+ if (Array.isArray(value)) {
10537
+ return value
10538
+ .map((item) => this.formatSingleValue(item))
10539
+ .filter((v) => v)
10540
+ .join(', ');
9652
10541
  }
10542
+ return this.formatSingleValue(value);
9653
10543
  }
9654
10544
  return String(value);
9655
10545
  }
10546
+ formatSingleValue(value) {
10547
+ if (!value || typeof value !== 'object')
10548
+ return String(value);
10549
+ const props = [
10550
+ 'label',
10551
+ 'nombre',
10552
+ 'name',
10553
+ 'empresaNombre',
10554
+ 'descripcion',
10555
+ 'description',
10556
+ 'text',
10557
+ 'value',
10558
+ ];
10559
+ for (const prop of props) {
10560
+ if (value[prop] !== undefined &&
10561
+ value[prop] !== null &&
10562
+ value[prop] !== '') {
10563
+ return String(value[prop]);
10564
+ }
10565
+ }
10566
+ if (value.id !== undefined && value.id !== null) {
10567
+ return `ID: ${value.id}`;
10568
+ }
10569
+ try {
10570
+ const json = JSON.stringify(value);
10571
+ return json.length > 50 ? json.substring(0, 50) + '...' : json;
10572
+ }
10573
+ catch {
10574
+ return '[Objeto]';
10575
+ }
10576
+ }
9656
10577
  generateHtml(title, cells, compact) {
9657
10578
  if (compact) {
9658
10579
  return `
@@ -9679,7 +10600,6 @@ class FormPreviewService {
9679
10600
  </div>
9680
10601
  `;
9681
10602
  }
9682
- // Versión no compacta (con más padding)
9683
10603
  return `
9684
10604
  <div style="margin: 12px 0; border: 1px solid #dee2e6; border-radius: 8px; overflow: hidden; background: #ffffff;">
9685
10605
  <div style="padding: 12px; background: #f8f9fa; border-bottom: 1px solid #dee2e6; font-weight: 600; color: #495057;">
@@ -9705,19 +10625,20 @@ class FormPreviewService {
9705
10625
  `;
9706
10626
  }
9707
10627
  debugInputData(data, fields, options) {
10628
+ const isDev = !this.environment.production;
10629
+ if (!isDev)
10630
+ return;
9708
10631
  console.group('🔍 FormPreview Debug');
9709
10632
  console.log('📊 Data:', data);
9710
10633
  console.log('📋 Propiedades disponibles:', data ? Object.keys(data) : 'data es null');
9711
10634
  console.log('🎯 Fields solicitados:', fields);
9712
10635
  console.log('⚙️ Options:', options);
9713
- // Verificar cada campo
9714
10636
  if (data) {
9715
10637
  for (const field of fields) {
9716
10638
  const value = this.getNestedValue(data, field.key);
9717
10639
  const existe = value !== undefined;
9718
10640
  if (!existe) {
9719
10641
  console.warn(`❌ Campo "${field.key}" NO existe en data`);
9720
- // Sugerir propiedades similares
9721
10642
  const similares = this.findSimilarProperties(field.key, Object.keys(data));
9722
10643
  if (similares.length > 0) {
9723
10644
  console.warn(`💡 Quizás quisiste decir: ${similares.join(', ')}`);
@@ -9757,13 +10678,17 @@ class FormPreviewService {
9757
10678
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: FormPreviewService, decorators: [{
9758
10679
  type: Injectable,
9759
10680
  args: [{ providedIn: 'root' }]
9760
- }] });
10681
+ }], ctorParameters: () => [] });
9761
10682
 
9762
10683
  // table-preview.service.ts
9763
10684
  class TablePreviewService {
10685
+ environment = inject(ENVIRONMENT);
10686
+ isProduction = this.environment?.production ?? false;
9764
10687
  buildSingleRowSummaryHtml(row, columns, options) {
9765
- const debug = options?.debug ?? false; // Por defecto false
9766
- // Solo mostrar logs si debug está activado
10688
+ const debug = !this.isProduction && (options?.debug ?? false);
10689
+ const showRowId = options?.showRowId ?? false;
10690
+ const title = options?.title || '🗑️ Datos a eliminar';
10691
+ const icon = options?.icon || '';
9767
10692
  if (debug) {
9768
10693
  this.debugInputData(row, columns, options);
9769
10694
  }
@@ -9783,33 +10708,50 @@ class TablePreviewService {
9783
10708
  const rowId = options?.rowId?.trim() || '1';
9784
10709
  const cells = [];
9785
10710
  const propiedadesNoEncontradas = [];
10711
+ // Si showRowId está activo, agregamos una fila con el ID
10712
+ if (showRowId) {
10713
+ cells.push({ label: 'ID', value: rowId });
10714
+ }
9786
10715
  for (const col of columns) {
9787
- // Obtener key
9788
10716
  const key = typeof col === 'string' ? col : col.key;
9789
- // Obtener valor con validación
10717
+ const formatFn = typeof col === 'object' ? col.format : undefined;
9790
10718
  const value = this.getNestedValue(row, key);
9791
- const valueText = this.formatValue(value);
9792
- // Registrar si no se encontró la propiedad
10719
+ let valueText;
10720
+ if (formatFn && typeof formatFn === 'function') {
10721
+ try {
10722
+ valueText = formatFn(value, row) ?? '';
10723
+ }
10724
+ catch (error) {
10725
+ if (debug) {
10726
+ console.error(`❌ Error al formatear "${key}":`, error);
10727
+ }
10728
+ valueText = this.formatValue(value);
10729
+ }
10730
+ }
10731
+ else {
10732
+ valueText = this.formatValue(value);
10733
+ }
9793
10734
  if (value === undefined) {
9794
10735
  propiedadesNoEncontradas.push(key);
9795
10736
  }
9796
- // Filtrar vacíos
9797
- if (!includeEmpty && !valueText)
10737
+ const isEmpty = value === null ||
10738
+ value === undefined ||
10739
+ value === '' ||
10740
+ (Array.isArray(value) && value.length === 0);
10741
+ if (!includeEmpty && isEmpty)
9798
10742
  continue;
9799
- // Obtener label
9800
10743
  let label = headerMap[key];
9801
10744
  if (!label && typeof col === 'object' && col.label)
9802
10745
  label = col.label;
9803
10746
  if (!label)
9804
10747
  label = this.humanizeKey(key);
9805
- cells.push({ label, value: valueText || '—' });
10748
+ const displayValue = isEmpty ? '—' : valueText;
10749
+ cells.push({ label, value: displayValue });
9806
10750
  }
9807
- // Solo mostrar logs si debug está activado
9808
10751
  if (debug) {
9809
10752
  if (propiedadesNoEncontradas.length > 0) {
9810
10753
  console.warn('⚠️ TablePreview: Propiedades no encontradas:', propiedadesNoEncontradas);
9811
10754
  console.warn('📋 Propiedades disponibles en rowData:', Object.keys(row));
9812
- console.warn('💡 Sugerencia: Verifica que los nombres coincidan exactamente');
9813
10755
  }
9814
10756
  if (cells.length === 0) {
9815
10757
  console.error('❌ TablePreview: No se generaron celdas. Verifica tus columnas y datos.');
@@ -9822,7 +10764,7 @@ class TablePreviewService {
9822
10764
  }
9823
10765
  if (!cells.length)
9824
10766
  return '';
9825
- return this.generateCompactHtml(rowId, cells, showLabel);
10767
+ return this.generateCompactHtml(cells, showLabel, title, icon);
9826
10768
  }
9827
10769
  getNestedValue(obj, path) {
9828
10770
  if (!obj || !path)
@@ -9840,6 +10782,8 @@ class TablePreviewService {
9840
10782
  formatValue(value) {
9841
10783
  if (value === null || value === undefined)
9842
10784
  return '';
10785
+ if (typeof value === 'number')
10786
+ return String(value);
9843
10787
  if (value instanceof Date)
9844
10788
  return value.toLocaleDateString();
9845
10789
  if (typeof value === 'object') {
@@ -9861,30 +10805,29 @@ class TablePreviewService {
9861
10805
  .map((w) => w.charAt(0).toUpperCase() + w.slice(1).toLowerCase())
9862
10806
  .join(' ');
9863
10807
  }
9864
- generateCompactHtml(rowId, cells, showLabel) {
9865
- const rowIdWidth = Math.min(Math.max(rowId.length, 1), 3);
10808
+ generateCompactHtml(cells, showLabel, title, icon) {
9866
10809
  return `
9867
10810
  <div style="margin: 8px 0; border: 1px solid #e9ecef; border-radius: 6px; overflow: hidden; background: #ffffff; font-size: 13px;">
10811
+ <!-- Encabezado con título e ícono -->
10812
+ <div style="padding: 10px 12px; background: #f8f9fa; border-bottom: 1px solid #e9ecef; font-weight: 600; color: #212529; text-align: center; font-size: 14px;">
10813
+ ${icon ? `<span style="margin-right: 8px; font-size: 18px;">${icon}</span>` : ''}
10814
+ ${this.escapeHtml(title)}
10815
+ </div>
10816
+
10817
+ <!-- Tabla de datos -->
9868
10818
  <table style="width: 100%; border-collapse: collapse; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;">
9869
10819
  <tbody>
9870
10820
  ${cells
9871
10821
  .map((cell, i) => `
9872
10822
  <tr style="border-bottom: ${i < cells.length - 1 ? '0.5px solid #f1f3f5' : 'none'}">
9873
- ${i === 0
9874
- ? `
9875
- <td style="padding: 6px 8px; background: #f8f9fa; font-weight: 600; color: #6c757d; border-right: 0.5px solid #f1f3f5; vertical-align: top;">
9876
- ${this.escapeHtml(rowId)}
9877
- </td>
9878
- `
9879
- : ''}
9880
10823
  ${showLabel
9881
10824
  ? `
9882
- <td style="padding: 6px 8px; background: #f8f9fa; text-transform: uppercase; width: auto; color: #6c757d; border-right: 0.5px solid #f1f3f5;">
10825
+ <td style="padding: 8px 12px; background: #f8f9fa; text-transform: uppercase; width: 40%; color: #6c757d; border-right: 0.5px solid #f1f3f5; font-weight: 600; font-size: 11px; letter-spacing: 0.3px;">
9883
10826
  ${this.escapeHtml(cell.label)}
9884
10827
  </td>
9885
10828
  `
9886
10829
  : ''}
9887
- <td style="padding: 6px 8px; color: #212529; font-weight: 500;">
10830
+ <td style="padding: 8px 12px; color: #212529; font-weight: 500;">
9888
10831
  ${this.escapeHtml(cell.value)}
9889
10832
  </td>
9890
10833
  </tr>
@@ -9901,7 +10844,6 @@ class TablePreviewService {
9901
10844
  console.log('📋 Propiedades disponibles:', row ? Object.keys(row) : 'row es null');
9902
10845
  console.log('🎯 Columns solicitadas:', columns);
9903
10846
  console.log('⚙️ Options:', options);
9904
- // Verificar cada columna
9905
10847
  if (row) {
9906
10848
  for (const col of columns) {
9907
10849
  const key = typeof col === 'string' ? col : col.key;
@@ -9909,7 +10851,6 @@ class TablePreviewService {
9909
10851
  const existe = value !== undefined;
9910
10852
  if (!existe) {
9911
10853
  console.warn(`❌ Propiedad "${key}" NO existe en rowData`);
9912
- // Sugerir propiedades similares
9913
10854
  const similares = this.findSimilarProperties(key, Object.keys(row));
9914
10855
  if (similares.length > 0) {
9915
10856
  console.warn(`💡 Quizás quisiste decir: ${similares.join(', ')}`);
@@ -9927,16 +10868,14 @@ class TablePreviewService {
9927
10868
  const searchLower = search.toLowerCase();
9928
10869
  for (const prop of properties) {
9929
10870
  const propLower = prop.toLowerCase();
9930
- // Buscar similitudes (contiene o es similar)
9931
10871
  if (propLower.includes(searchLower) || searchLower.includes(propLower)) {
9932
10872
  similares.push(prop);
9933
10873
  }
9934
- // Distancia de Levenshtein simple (máximo 3 caracteres de diferencia)
9935
10874
  else if (this.levenshteinDistance(searchLower, propLower) <= 3) {
9936
10875
  similares.push(prop);
9937
10876
  }
9938
10877
  }
9939
- return similares.slice(0, 3); // Máximo 3 sugerencias
10878
+ return similares.slice(0, 3);
9940
10879
  }
9941
10880
  levenshteinDistance(a, b) {
9942
10881
  if (a.length === 0)
@@ -10376,7 +11315,7 @@ function buildAlreadyExistsMessage(control, options) {
10376
11315
  * Validador asíncrono que verifica si un valor ya existe mediante una llamada a un servicio.
10377
11316
  * Útil para validar unicidad de campos como nombres de usuario, correos electrónicos, etc.
10378
11317
  *
10379
- * Aplica `debounceTime(400)` y `distinctUntilChanged()` para evitar llamadas innecesarias
11318
+ * Aplica `debounceTime(800)` y `distinctUntilChanged()` para evitar llamadas innecesarias
10380
11319
  * al servicio mientras el usuario escribe.
10381
11320
  *
10382
11321
  * @template T Tipo del valor del control a validar.
@@ -10384,39 +11323,93 @@ function buildAlreadyExistsMessage(control, options) {
10384
11323
  * el identificador del registro actual. Debe retornar un `Observable<boolean>`
10385
11324
  * emitiendo `true` si el valor ya existe (en otro registro), `false` en caso contrario.
10386
11325
  * @param options Opciones del validador:
10387
- * - `currentId`: Id opcional del registro en edición para excluirlo en backend.
11326
+ * - `currentId`: Id fijo del registro en edición para excluirlo en backend.
11327
+ * ⚠️ Útil cuando el ID no cambia durante la vida del validador.
11328
+ * - `getCurrentId`: Función que obtiene el ID en tiempo real.
11329
+ * ✅ **RECOMENDADO** cuando el ID puede cambiar (ej: signals, componentes reactivos).
11330
+ * Si se proporciona, tiene prioridad sobre `currentId`.
10388
11331
  * - `fieldName`: Nombre del campo para construir el mensaje dinámico
10389
11332
  * (si se omite, se intenta inferir del control).
10390
11333
  * - `errorMessage`: Mensaje personalizado (si se omite y se resuelve nombre
10391
11334
  * de campo, se usa `El valor {campo} ya existe`).
11335
+ * - `debug`: Si es `true`, muestra logs en consola para depuración.
10392
11336
  * @returns Un `AsyncValidatorFn` que emite `null` si el valor no existe o el control está vacío,
10393
11337
  * o un objeto `ValidationErrors` con la clave fija `alreadyValueExists` si el valor ya existe.
10394
11338
  *
10395
11339
  * @example
10396
11340
  * ```ts
10397
- * // Creación
11341
+ * // EJEMPLO 1: Creación (ID fijo o sin ID)
10398
11342
  * email: ['', [], asyncExistsValidator(
10399
11343
  * (value, id) => this.userService.emailExists({ value, id: Number(id) })
10400
11344
  * )]
10401
11345
  *
10402
- * // Edición (excluyendo el registro actual por id)
11346
+ * // EJEMPLO 2: Edición con ID fijo (cuando el ID no cambia)
11347
+ * email: ['', [], asyncExistsValidator(
11348
+ * (value, id) => this.userService.emailExists(value, id),
11349
+ * { currentId: this.userId, fieldName: 'email' }
11350
+ * )]
11351
+ *
11352
+ * // EJEMPLO 3: Edición con ID dinámico (RECOMENDADO con signals)
10403
11353
  * email: ['', [], asyncExistsValidator(
10404
11354
  * (value, id) => this.userService.emailExists(value, id),
10405
- * { currentId: this.id, fieldName: 'email' }
11355
+ * {
11356
+ * getCurrentId: () => this.id(), // ✅ Obtiene el ID en tiempo real
11357
+ * fieldName: 'email',
11358
+ * debug: true // Para depuración
11359
+ * }
11360
+ * )]
11361
+ *
11362
+ * // EJEMPLO 4: Con mensaje personalizado
11363
+ * codigo: ['', [], asyncExistsValidator(
11364
+ * (value, id) => this.productService.codigoExists(value, id),
11365
+ * {
11366
+ * getCurrentId: () => this.productId(),
11367
+ * errorMessage: 'El código de producto ya está registrado',
11368
+ * fieldName: 'código de producto'
11369
+ * }
10406
11370
  * )]
10407
11371
  * ```
10408
11372
  */
10409
11373
  function asyncExistsValidator(serviceMethod, options = {}) {
10410
- const { currentId = null, fieldName, errorMessage } = options;
11374
+ const { currentId = null, fieldName, errorMessage, debug = false, getCurrentId, } = options;
10411
11375
  const errorKey = 'alreadyValueExists';
10412
11376
  return (control) => {
10413
- if (!control.value)
11377
+ if (!control.value) {
11378
+ if (debug)
11379
+ console.log('[AsyncExistsValidator] Control value is empty, returning null');
10414
11380
  return of(null);
11381
+ }
11382
+ // Obtener el ID: prioridad a getCurrentId, luego currentId, luego 0
11383
+ const resolvedId = getCurrentId ? getCurrentId() : currentId;
11384
+ const finalId = resolvedId ?? 0;
11385
+ if (debug) {
11386
+ console.log('[AsyncExistsValidator] Starting validation for:', {
11387
+ value: control.value,
11388
+ currentId: finalId,
11389
+ fieldName,
11390
+ errorMessage,
11391
+ debug,
11392
+ usingGetCurrentId: !!getCurrentId,
11393
+ });
11394
+ }
10415
11395
  return of(control.value).pipe(debounceTime$1(800), distinctUntilChanged$1(), switchMap$1((value) => {
10416
- const resolvedId = currentId ?? 0;
10417
- return serviceMethod(value, resolvedId);
11396
+ if (debug) {
11397
+ console.log('[AsyncExistsValidator] Calling service method with:', {
11398
+ value: value,
11399
+ resolvedId: finalId,
11400
+ });
11401
+ }
11402
+ return serviceMethod(value, finalId);
10418
11403
  }), map((exists) => {
11404
+ if (debug) {
11405
+ console.log('[AsyncExistsValidator] Service response:', {
11406
+ exists,
11407
+ value: control.value,
11408
+ });
11409
+ }
10419
11410
  if (exists) {
11411
+ if (debug)
11412
+ console.log('[AsyncExistsValidator] Validation failed - value already exists');
10420
11413
  return {
10421
11414
  [errorKey]: {
10422
11415
  message: buildAlreadyExistsMessage(control, {
@@ -10427,8 +11420,15 @@ function asyncExistsValidator(serviceMethod, options = {}) {
10427
11420
  },
10428
11421
  };
10429
11422
  }
11423
+ if (debug)
11424
+ console.log('[AsyncExistsValidator] Validation passed - value is available');
10430
11425
  return null;
10431
- }), catchError(() => of(null)));
11426
+ }), catchError((error) => {
11427
+ if (debug) {
11428
+ console.error('[AsyncExistsValidator] Error occurred:', error);
11429
+ }
11430
+ return of(null);
11431
+ }));
10432
11432
  };
10433
11433
  }
10434
11434
  function templateVariablesValidator(allowedKeys) {
@@ -10599,5 +11599,5 @@ function sorensenDiceValidator(dataSource, key, umbral = 0.7) {
10599
11599
  * Generated bundle index. Do not edit.
10600
11600
  */
10601
11601
 
10602
- export { ACTION_TYPES, AlertaService, AppMessageErrorComponent, AppMessageHelpComponent, ArrowNavigationDirective, AuthorizeService, AutoScrollHeightDirective, BaseCRUDService, CACHE_KEYS, CacheService, CssV2Component, DSX_PALETTE, DateIndicator, DocxPreviewComponent, DsxAddToolsModule, DsxAutocomplete, DsxButtonComponent, DsxEnableDisable, DsxMessagesService, DsxSelect, DsxStatusToggle, DteService, ENVIRONMENT, EndpointService, ErrorHandlerService, FileComponent, FormPreviewService, GTQFormatter, HeaderDsx, HelpersService, HttpHelpersService, INITIAL_PARAMETERS, IcoLabel, IconDsxComponent, JoinByPipe, JsonHighlightPipe, JsonValuesDebujComponent, JsonViewerComponent, KpicardComponent, LoadingComponent, LoadingLottieComponent, LogoDsxComponent, MasterDetailChangeService, NavbarDsxComponent, NetworkStatusComponent, OnlyRangoPatternDirective, ParameterValuesService, PdfPreviewComponent, PrimeNgModule, QrGenerator, ResultFileService, SWEET_ALERT_THEMES, ScreenInspector, SecurityService, SelectAllOnFocusDirective, SpinnerLoadingService, SweetAlert2DialogService, TablePreviewService, TemplateHighlight, TokenPurposeLogin, TruncatePipe, UtilityAddService, asyncExistsValidator, atLeastOneFieldRequiredValidator, chainControlGroups, createCurrencyFormatter, createInitialCache, createTypedCacheProvider, cuiValidator, dateMinMaxValidator, dateRangeValidator, dateRangeValidatorFromTo, developmentEnvironment, getActionMessageConfig, getZeroBasedRolIndex, guardTokenPurposeGuard, httpAuthorizeInterceptor, minimumAgeValidator, nitValidator, productionEnvironment, provideEnvironment, sorensenDiceValidator, templateStructureValidator, templateVariablesValidator, validateEnvironmentConfig };
11602
+ export { ACTION_TYPES, AlertaService, AppMessageErrorComponent, AppMessageHelpComponent, ArrowNavigationDirective, AuthorizeService, AutoScrollHeightDirective, BaseCRUDService, CACHE_KEYS, CacheService, CssV2Component, DSX_PALETTE, DateIndicator, DocxPreviewComponent, DsxAddToolsModule, DsxAutocomplete, DsxButtonComponent, DsxEnableDisable, DsxInputCurrency, DsxMessagesService, DsxSelect, DsxStatusToggle, DsxdateShort, DteService, ENVIRONMENT, EndpointService, ErrorHandlerService, FileComponent, FormPreviewService, GTQFormatter, HeaderDsx, HelpersService, HttpHelpersService, INITIAL_PARAMETERS, IcoLabel, IconDsxComponent, JoinByPipe, JsonHighlightPipe, JsonValuesDebujComponent, JsonViewerComponent, KpicardComponent, LoadingComponent, LoadingLottieComponent, LogoDsxComponent, MasterDetailChangeService, NavbarDsxComponent, NetworkStatusComponent, OnlyRangoPatternDirective, ParameterValuesService, PdfPreviewComponent, PrimeNgModule, QrGenerator, ResultFileService, SWEET_ALERT_THEMES, ScreenInspector, SecurityService, SelectAllOnFocusDirective, SpinnerLoadingService, SweetAlert2DialogService, TablePreviewService, TemplateHighlight, TokenPurposeLogin, TruncatePipe, UtilityAddService, asyncExistsValidator, atLeastOneFieldRequiredValidator, chainControlGroups, createCurrencyFormatter, createInitialCache, createTypedCacheProvider, cuiValidator, dateMinMaxValidator, dateRangeValidator, dateRangeValidatorFromTo, developmentEnvironment, getActionMessageConfig, getZeroBasedRolIndex, guardTokenPurposeGuard, httpAuthorizeInterceptor, minimumAgeValidator, nitValidator, productionEnvironment, provideEnvironment, sorensenDiceValidator, templateStructureValidator, templateVariablesValidator, validateEnvironmentConfig };
10603
11603
  //# sourceMappingURL=ngx-dsxlibrary.mjs.map