@solcre-org/core-ui 2.12.11 → 2.12.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -450,10 +450,9 @@ class CheckboxFieldComponent extends BaseFieldComponent {
450
450
  this.formControl().setValue(option.value);
451
451
  }
452
452
  else if (currentValue === option.value) {
453
- if (this.isRequired()) {
454
- return;
453
+ if (!this.isRequired()) {
454
+ this.formControl().setValue(null);
455
455
  }
456
- this.formControl().setValue(null);
457
456
  }
458
457
  }
459
458
  }
@@ -467,17 +466,15 @@ class CheckboxFieldComponent extends BaseFieldComponent {
467
466
  }
468
467
  }
469
468
  cannotDeselect(option) {
469
+ if (!this.allowMultiple()) {
470
+ return false;
471
+ }
470
472
  if (!this.isRequired() || !this.isOptionSelected(option)) {
471
473
  return false;
472
474
  }
473
475
  const currentValue = this.formControl().value;
474
- if (this.allowMultiple()) {
475
- const selectedCount = Array.isArray(currentValue) ? currentValue.length : 0;
476
- return selectedCount <= 1;
477
- }
478
- else {
479
- return true;
480
- }
476
+ const selectedCount = Array.isArray(currentValue) ? currentValue.length : 0;
477
+ return selectedCount <= 1;
481
478
  }
482
479
  onValueChange(newValue) {
483
480
  super.onValueChange(newValue);
@@ -493,11 +490,11 @@ class CheckboxFieldComponent extends BaseFieldComponent {
493
490
  }
494
491
  }
495
492
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: CheckboxFieldComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
496
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.0.6", type: CheckboxFieldComponent, isStandalone: true, selector: "core-checkbox-field", usesInheritance: true, hostDirectives: [{ directive: CoreHostDirective }], ngImport: i0, template: "<!-- Clase para layout inline cuando hay m\u00FAltiples opciones -->\n<div class=\"c-entry-toggle-holder\" [class.hasSeparatedOptions]=\"hasSeparatedOptions()\" [class.multiple-inline]=\"hasMultipleOptions()\">\n\n <span class=\"c-entry-text\"\n *ngIf=\"field().label\">\n {{ field().label | translate }}\n @if (hasRequiredValidators()) {\n <span class=\"c-required\">*</span>\n }\n </span>\n \n @if (hasMultipleOptions()) {\n @for (option of options(); track option.value) {\n\n <!-- ! Solcre: Este .c-entry-toggle deber\u00EDa ser un componente en s\u00ED mismo. -->\n <!-- ! Solcre: El cannot-deselect no est\u00E1 over-engineered. Deber\u00EDa ser un Radio. -->\n <label class=\"c-entry-toggle\"\n [class.is-invalid]=\"hasError()\"\n [class.is-disabled]=\"isDisabled()\"\n [class.cannot-deselect]=\"cannotDeselect(option)\">\n\n <!-- onBlurInput() maneja validaciones y marca el campo como touched para mostrar errores -->\n @if (cannotDeselect(option)) {\n <!-- Usar radio cuando no se puede deseleccionar -->\n <input\n type=\"radio\"\n [attr.id]=\"field().key.toString() + '_' + option.value\"\n [attr.name]=\"field().key.toString()\"\n [checked]=\"isOptionSelected(option)\"\n (change)=\"handleOptionChange(option, $event)\"\n (blur)=\"onBlurInput()\"\n />\n } @else {\n <!-- Usar checkbox normal cuando se puede deseleccionar -->\n <input\n type=\"checkbox\"\n [attr.id]=\"field().key.toString() + '_' + option.value\"\n [attr.name]=\"allowMultiple() ? field().key.toString() + '[]' : field().key.toString()\"\n [checked]=\"isOptionSelected(option)\"\n (change)=\"handleOptionChange(option, $event)\"\n (blur)=\"onBlurInput()\"\n />\n }\n <span class=\"c-entry-toggle__toggle\"></span>\n\n <span class=\"c-entry-toggle__text\">\n {{ option.label | translate }}\n @if(option.externalLink) {\n <!-- Link externo funcional implementado -->\n <a class=\"icon-external-link-thin\" [href]=\"option.externalLink\" target=\"_blank\"></a>\n }\n </span>\n @if(option.detail) {\n <!-- Texto de detalle funcional implementado -->\n <span class=\"c-form-checkbox__detail\">{{ option.detail }}</span>\n }\n </label>\n\n }\n } @else {\n <!-- ! Solcre: Este .c-entry-toggle deber\u00EDa ser un componente en s\u00ED mismo. -->\n <!-- ! Solcre: El cannot-deselect no est\u00E1 over-engineered. Deber\u00EDa ser un Radio. -->\n <label class=\"c-entry-toggle\"\n [class.is-invalid]=\"hasError()\"\n [class.is-disabled]=\"isDisabled()\"\n [class.cannot-deselect]=\"isRequired() && !!formControl().value\">\n\n <!-- onBlurInput() maneja validaciones y marca el campo como touched para mostrar errores -->\n @if (isRequired() && !!formControl().value) {\n <!-- Usar radio cuando es requerido y tiene valor (cannot-deselect) -->\n <input\n type=\"radio\"\n [attr.id]=\"field().key.toString()\"\n [attr.name]=\"field().key.toString()\"\n [checked]=\"!!formControl().value\"\n (change)=\"onRadioChange($event)\"\n (blur)=\"onBlurInput()\"\n />\n } @else {\n <!-- Usar checkbox normal cuando se puede deseleccionar -->\n <input\n type=\"checkbox\"\n [attr.id]=\"field().key.toString()\"\n [attr.name]=\"field().key.toString()\"\n [formControl]=\"formControl()\"\n (blur)=\"onBlurInput()\"\n />\n }\n <span class=\"c-entry-toggle__toggle\"></span>\n <span class=\"c-entry-toggle__text\">\n {{ field().label | translate }}\n @if(externalLink()) {\n <!-- Link externo funcional implementado -->\n <a class=\"icon-external-link-thin\" [href]=\"externalLink()\" target=\"_blank\"></a>\n }\n </span>\n @if(detail()) {\n <!-- Texto de detalle funcional implementado -->\n <span class=\"c-form-checkbox__detail\">{{ detail() }}</span>\n }\n </label>\n }\n\n <core-field-errors [errors]=\"errors()\" />\n</div> \n ", styles: [".cannot-deselect{pointer-events:none;cursor:not-allowed}.c-entry-text+.c-entry-toggle-holder.hasSeparatedOptions{margin-top:calc(var(--_entry-group-gap) * .8)}.c-entry-toggle-holder.hasSeparatedOptions{display:grid;grid-template-columns:1fr 1fr;gap:calc(var(--_entry-group-gap) * .8)}.c-entry-toggle-holder.hasSeparatedOptions .c-entry-text{grid-column:span 2;margin-top:1em}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i3$1.CheckboxControlValueAccessor, selector: "input[type=checkbox][formControlName],input[type=checkbox][formControl],input[type=checkbox][ngModel]" }, { kind: "directive", type: i3$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i3$1.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "ngmodule", type: TranslateModule }, { kind: "pipe", type: i3.TranslatePipe, name: "translate" }, { kind: "component", type: FieldErrorsComponent, selector: "core-field-errors", inputs: ["errors"] }] });
493
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.0.6", type: CheckboxFieldComponent, isStandalone: true, selector: "core-checkbox-field", usesInheritance: true, hostDirectives: [{ directive: CoreHostDirective }], ngImport: i0, template: "<!-- Clase para layout inline cuando hay m\u00FAltiples opciones -->\n<div class=\"c-entry-toggle-holder\" [class.hasSeparatedOptions]=\"hasSeparatedOptions()\" [class.multiple-inline]=\"hasMultipleOptions()\">\n\n <span class=\"c-entry-text\"\n *ngIf=\"field().label\">\n {{ field().label | translate }}\n @if (hasRequiredValidators()) {\n <span class=\"c-required\">*</span>\n }\n </span>\n \n @if (hasMultipleOptions()) {\n @for (option of options(); track option.value) {\n\n <!-- ! Solcre: Este .c-entry-toggle deber\u00EDa ser un componente en s\u00ED mismo. -->\n <!-- ! Solcre: El cannot-deselect no est\u00E1 over-engineered. Deber\u00EDa ser un Radio. -->\n <label class=\"c-entry-toggle\"\n [class.is-invalid]=\"hasError()\"\n [class.is-disabled]=\"isDisabled()\"\n [class.cannot-deselect]=\"cannotDeselect(option)\">\n\n <!-- onBlurInput() maneja validaciones y marca el campo como touched para mostrar errores -->\n @if (!allowMultiple() && isRequired()) {\n <!-- Cuando allowMultiple: false y required: true, usar radio buttons para todas las opciones -->\n <input\n type=\"radio\"\n [attr.id]=\"field().key.toString() + '_' + option.value\"\n [attr.name]=\"field().key.toString()\"\n [checked]=\"isOptionSelected(option)\"\n (change)=\"handleOptionChange(option, $event)\"\n (blur)=\"onBlurInput()\"\n />\n } @else if (cannotDeselect(option)) {\n <!-- Usar radio cuando no se puede deseleccionar (modo m\u00FAltiple con una sola opci\u00F3n) -->\n <input\n type=\"radio\"\n [attr.id]=\"field().key.toString() + '_' + option.value\"\n [attr.name]=\"field().key.toString()\"\n [checked]=\"isOptionSelected(option)\"\n (change)=\"handleOptionChange(option, $event)\"\n (blur)=\"onBlurInput()\"\n />\n } @else {\n <!-- Usar checkbox normal cuando se puede deseleccionar -->\n <input\n type=\"checkbox\"\n [attr.id]=\"field().key.toString() + '_' + option.value\"\n [attr.name]=\"allowMultiple() ? field().key.toString() + '[]' : field().key.toString()\"\n [checked]=\"isOptionSelected(option)\"\n (change)=\"handleOptionChange(option, $event)\"\n (blur)=\"onBlurInput()\"\n />\n }\n <span class=\"c-entry-toggle__toggle\"></span>\n\n <span class=\"c-entry-toggle__text\">\n {{ option.label | translate }}\n @if(option.externalLink) {\n <!-- Link externo funcional implementado -->\n <a class=\"icon-external-link-thin\" [href]=\"option.externalLink\" target=\"_blank\"></a>\n }\n </span>\n @if(option.detail) {\n <!-- Texto de detalle funcional implementado -->\n <span class=\"c-form-checkbox__detail\">{{ option.detail }}</span>\n }\n </label>\n\n }\n } @else {\n <!-- ! Solcre: Este .c-entry-toggle deber\u00EDa ser un componente en s\u00ED mismo. -->\n <!-- ! Solcre: El cannot-deselect no est\u00E1 over-engineered. Deber\u00EDa ser un Radio. -->\n <label class=\"c-entry-toggle\"\n [class.is-invalid]=\"hasError()\"\n [class.is-disabled]=\"isDisabled()\"\n [class.cannot-deselect]=\"isRequired() && !!formControl().value\">\n\n <!-- onBlurInput() maneja validaciones y marca el campo como touched para mostrar errores -->\n @if (isRequired() && !!formControl().value) {\n <!-- Usar radio cuando es requerido y tiene valor (cannot-deselect) -->\n <input\n type=\"radio\"\n [attr.id]=\"field().key.toString()\"\n [attr.name]=\"field().key.toString()\"\n [checked]=\"!!formControl().value\"\n (change)=\"onRadioChange($event)\"\n (blur)=\"onBlurInput()\"\n />\n } @else {\n <!-- Usar checkbox normal cuando se puede deseleccionar -->\n <input\n type=\"checkbox\"\n [attr.id]=\"field().key.toString()\"\n [attr.name]=\"field().key.toString()\"\n [formControl]=\"formControl()\"\n (blur)=\"onBlurInput()\"\n />\n }\n <span class=\"c-entry-toggle__toggle\"></span>\n <span class=\"c-entry-toggle__text\">\n {{ field().label | translate }}\n @if(externalLink()) {\n <!-- Link externo funcional implementado -->\n <a class=\"icon-external-link-thin\" [href]=\"externalLink()\" target=\"_blank\"></a>\n }\n </span>\n @if(detail()) {\n <!-- Texto de detalle funcional implementado -->\n <span class=\"c-form-checkbox__detail\">{{ detail() }}</span>\n }\n </label>\n }\n\n <core-field-errors [errors]=\"errors()\" />\n</div> \n ", styles: [".cannot-deselect{pointer-events:none;cursor:not-allowed}.c-entry-text+.c-entry-toggle-holder.hasSeparatedOptions{margin-top:calc(var(--_entry-group-gap) * .8)}.c-entry-toggle-holder.hasSeparatedOptions{display:grid;grid-template-columns:1fr 1fr;gap:calc(var(--_entry-group-gap) * .8)}.c-entry-toggle-holder.hasSeparatedOptions .c-entry-text{grid-column:span 2;margin-top:1em}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i3$1.CheckboxControlValueAccessor, selector: "input[type=checkbox][formControlName],input[type=checkbox][formControl],input[type=checkbox][ngModel]" }, { kind: "directive", type: i3$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i3$1.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "ngmodule", type: TranslateModule }, { kind: "pipe", type: i3.TranslatePipe, name: "translate" }, { kind: "component", type: FieldErrorsComponent, selector: "core-field-errors", inputs: ["errors"] }] });
497
494
  }
498
495
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: CheckboxFieldComponent, decorators: [{
499
496
  type: Component,
500
- args: [{ selector: 'core-checkbox-field', standalone: true, imports: [CommonModule, FormsModule, ReactiveFormsModule, TranslateModule, FieldErrorsComponent], hostDirectives: [CoreHostDirective], template: "<!-- Clase para layout inline cuando hay m\u00FAltiples opciones -->\n<div class=\"c-entry-toggle-holder\" [class.hasSeparatedOptions]=\"hasSeparatedOptions()\" [class.multiple-inline]=\"hasMultipleOptions()\">\n\n <span class=\"c-entry-text\"\n *ngIf=\"field().label\">\n {{ field().label | translate }}\n @if (hasRequiredValidators()) {\n <span class=\"c-required\">*</span>\n }\n </span>\n \n @if (hasMultipleOptions()) {\n @for (option of options(); track option.value) {\n\n <!-- ! Solcre: Este .c-entry-toggle deber\u00EDa ser un componente en s\u00ED mismo. -->\n <!-- ! Solcre: El cannot-deselect no est\u00E1 over-engineered. Deber\u00EDa ser un Radio. -->\n <label class=\"c-entry-toggle\"\n [class.is-invalid]=\"hasError()\"\n [class.is-disabled]=\"isDisabled()\"\n [class.cannot-deselect]=\"cannotDeselect(option)\">\n\n <!-- onBlurInput() maneja validaciones y marca el campo como touched para mostrar errores -->\n @if (cannotDeselect(option)) {\n <!-- Usar radio cuando no se puede deseleccionar -->\n <input\n type=\"radio\"\n [attr.id]=\"field().key.toString() + '_' + option.value\"\n [attr.name]=\"field().key.toString()\"\n [checked]=\"isOptionSelected(option)\"\n (change)=\"handleOptionChange(option, $event)\"\n (blur)=\"onBlurInput()\"\n />\n } @else {\n <!-- Usar checkbox normal cuando se puede deseleccionar -->\n <input\n type=\"checkbox\"\n [attr.id]=\"field().key.toString() + '_' + option.value\"\n [attr.name]=\"allowMultiple() ? field().key.toString() + '[]' : field().key.toString()\"\n [checked]=\"isOptionSelected(option)\"\n (change)=\"handleOptionChange(option, $event)\"\n (blur)=\"onBlurInput()\"\n />\n }\n <span class=\"c-entry-toggle__toggle\"></span>\n\n <span class=\"c-entry-toggle__text\">\n {{ option.label | translate }}\n @if(option.externalLink) {\n <!-- Link externo funcional implementado -->\n <a class=\"icon-external-link-thin\" [href]=\"option.externalLink\" target=\"_blank\"></a>\n }\n </span>\n @if(option.detail) {\n <!-- Texto de detalle funcional implementado -->\n <span class=\"c-form-checkbox__detail\">{{ option.detail }}</span>\n }\n </label>\n\n }\n } @else {\n <!-- ! Solcre: Este .c-entry-toggle deber\u00EDa ser un componente en s\u00ED mismo. -->\n <!-- ! Solcre: El cannot-deselect no est\u00E1 over-engineered. Deber\u00EDa ser un Radio. -->\n <label class=\"c-entry-toggle\"\n [class.is-invalid]=\"hasError()\"\n [class.is-disabled]=\"isDisabled()\"\n [class.cannot-deselect]=\"isRequired() && !!formControl().value\">\n\n <!-- onBlurInput() maneja validaciones y marca el campo como touched para mostrar errores -->\n @if (isRequired() && !!formControl().value) {\n <!-- Usar radio cuando es requerido y tiene valor (cannot-deselect) -->\n <input\n type=\"radio\"\n [attr.id]=\"field().key.toString()\"\n [attr.name]=\"field().key.toString()\"\n [checked]=\"!!formControl().value\"\n (change)=\"onRadioChange($event)\"\n (blur)=\"onBlurInput()\"\n />\n } @else {\n <!-- Usar checkbox normal cuando se puede deseleccionar -->\n <input\n type=\"checkbox\"\n [attr.id]=\"field().key.toString()\"\n [attr.name]=\"field().key.toString()\"\n [formControl]=\"formControl()\"\n (blur)=\"onBlurInput()\"\n />\n }\n <span class=\"c-entry-toggle__toggle\"></span>\n <span class=\"c-entry-toggle__text\">\n {{ field().label | translate }}\n @if(externalLink()) {\n <!-- Link externo funcional implementado -->\n <a class=\"icon-external-link-thin\" [href]=\"externalLink()\" target=\"_blank\"></a>\n }\n </span>\n @if(detail()) {\n <!-- Texto de detalle funcional implementado -->\n <span class=\"c-form-checkbox__detail\">{{ detail() }}</span>\n }\n </label>\n }\n\n <core-field-errors [errors]=\"errors()\" />\n</div> \n ", styles: [".cannot-deselect{pointer-events:none;cursor:not-allowed}.c-entry-text+.c-entry-toggle-holder.hasSeparatedOptions{margin-top:calc(var(--_entry-group-gap) * .8)}.c-entry-toggle-holder.hasSeparatedOptions{display:grid;grid-template-columns:1fr 1fr;gap:calc(var(--_entry-group-gap) * .8)}.c-entry-toggle-holder.hasSeparatedOptions .c-entry-text{grid-column:span 2;margin-top:1em}\n"] }]
497
+ args: [{ selector: 'core-checkbox-field', standalone: true, imports: [CommonModule, FormsModule, ReactiveFormsModule, TranslateModule, FieldErrorsComponent], hostDirectives: [CoreHostDirective], template: "<!-- Clase para layout inline cuando hay m\u00FAltiples opciones -->\n<div class=\"c-entry-toggle-holder\" [class.hasSeparatedOptions]=\"hasSeparatedOptions()\" [class.multiple-inline]=\"hasMultipleOptions()\">\n\n <span class=\"c-entry-text\"\n *ngIf=\"field().label\">\n {{ field().label | translate }}\n @if (hasRequiredValidators()) {\n <span class=\"c-required\">*</span>\n }\n </span>\n \n @if (hasMultipleOptions()) {\n @for (option of options(); track option.value) {\n\n <!-- ! Solcre: Este .c-entry-toggle deber\u00EDa ser un componente en s\u00ED mismo. -->\n <!-- ! Solcre: El cannot-deselect no est\u00E1 over-engineered. Deber\u00EDa ser un Radio. -->\n <label class=\"c-entry-toggle\"\n [class.is-invalid]=\"hasError()\"\n [class.is-disabled]=\"isDisabled()\"\n [class.cannot-deselect]=\"cannotDeselect(option)\">\n\n <!-- onBlurInput() maneja validaciones y marca el campo como touched para mostrar errores -->\n @if (!allowMultiple() && isRequired()) {\n <!-- Cuando allowMultiple: false y required: true, usar radio buttons para todas las opciones -->\n <input\n type=\"radio\"\n [attr.id]=\"field().key.toString() + '_' + option.value\"\n [attr.name]=\"field().key.toString()\"\n [checked]=\"isOptionSelected(option)\"\n (change)=\"handleOptionChange(option, $event)\"\n (blur)=\"onBlurInput()\"\n />\n } @else if (cannotDeselect(option)) {\n <!-- Usar radio cuando no se puede deseleccionar (modo m\u00FAltiple con una sola opci\u00F3n) -->\n <input\n type=\"radio\"\n [attr.id]=\"field().key.toString() + '_' + option.value\"\n [attr.name]=\"field().key.toString()\"\n [checked]=\"isOptionSelected(option)\"\n (change)=\"handleOptionChange(option, $event)\"\n (blur)=\"onBlurInput()\"\n />\n } @else {\n <!-- Usar checkbox normal cuando se puede deseleccionar -->\n <input\n type=\"checkbox\"\n [attr.id]=\"field().key.toString() + '_' + option.value\"\n [attr.name]=\"allowMultiple() ? field().key.toString() + '[]' : field().key.toString()\"\n [checked]=\"isOptionSelected(option)\"\n (change)=\"handleOptionChange(option, $event)\"\n (blur)=\"onBlurInput()\"\n />\n }\n <span class=\"c-entry-toggle__toggle\"></span>\n\n <span class=\"c-entry-toggle__text\">\n {{ option.label | translate }}\n @if(option.externalLink) {\n <!-- Link externo funcional implementado -->\n <a class=\"icon-external-link-thin\" [href]=\"option.externalLink\" target=\"_blank\"></a>\n }\n </span>\n @if(option.detail) {\n <!-- Texto de detalle funcional implementado -->\n <span class=\"c-form-checkbox__detail\">{{ option.detail }}</span>\n }\n </label>\n\n }\n } @else {\n <!-- ! Solcre: Este .c-entry-toggle deber\u00EDa ser un componente en s\u00ED mismo. -->\n <!-- ! Solcre: El cannot-deselect no est\u00E1 over-engineered. Deber\u00EDa ser un Radio. -->\n <label class=\"c-entry-toggle\"\n [class.is-invalid]=\"hasError()\"\n [class.is-disabled]=\"isDisabled()\"\n [class.cannot-deselect]=\"isRequired() && !!formControl().value\">\n\n <!-- onBlurInput() maneja validaciones y marca el campo como touched para mostrar errores -->\n @if (isRequired() && !!formControl().value) {\n <!-- Usar radio cuando es requerido y tiene valor (cannot-deselect) -->\n <input\n type=\"radio\"\n [attr.id]=\"field().key.toString()\"\n [attr.name]=\"field().key.toString()\"\n [checked]=\"!!formControl().value\"\n (change)=\"onRadioChange($event)\"\n (blur)=\"onBlurInput()\"\n />\n } @else {\n <!-- Usar checkbox normal cuando se puede deseleccionar -->\n <input\n type=\"checkbox\"\n [attr.id]=\"field().key.toString()\"\n [attr.name]=\"field().key.toString()\"\n [formControl]=\"formControl()\"\n (blur)=\"onBlurInput()\"\n />\n }\n <span class=\"c-entry-toggle__toggle\"></span>\n <span class=\"c-entry-toggle__text\">\n {{ field().label | translate }}\n @if(externalLink()) {\n <!-- Link externo funcional implementado -->\n <a class=\"icon-external-link-thin\" [href]=\"externalLink()\" target=\"_blank\"></a>\n }\n </span>\n @if(detail()) {\n <!-- Texto de detalle funcional implementado -->\n <span class=\"c-form-checkbox__detail\">{{ detail() }}</span>\n }\n </label>\n }\n\n <core-field-errors [errors]=\"errors()\" />\n</div> \n ", styles: [".cannot-deselect{pointer-events:none;cursor:not-allowed}.c-entry-text+.c-entry-toggle-holder.hasSeparatedOptions{margin-top:calc(var(--_entry-group-gap) * .8)}.c-entry-toggle-holder.hasSeparatedOptions{display:grid;grid-template-columns:1fr 1fr;gap:calc(var(--_entry-group-gap) * .8)}.c-entry-toggle-holder.hasSeparatedOptions .c-entry-text{grid-column:span 2;margin-top:1em}\n"] }]
501
498
  }], ctorParameters: () => [] });
502
499
 
503
500
  class DateFieldComponent extends BaseFieldComponent {
@@ -5229,6 +5226,317 @@ const isSameDate = (date1, date2) => {
5229
5226
  date1.getDate() === date2.getDate());
5230
5227
  };
5231
5228
 
5229
+ class DynamicFieldsHelper {
5230
+ formBuilder = new FormBuilder();
5231
+ config;
5232
+ mode;
5233
+ _editedData = signal(null);
5234
+ _fieldErrors = signal({});
5235
+ _originalData = signal(null);
5236
+ _form = signal(this.formBuilder.group({}));
5237
+ state;
5238
+ constructor(config, mode = ModalMode.CREATE) {
5239
+ this.config = config;
5240
+ this.mode = mode;
5241
+ this.state = {
5242
+ editedData: this._editedData.asReadonly(),
5243
+ fieldErrors: this._fieldErrors.asReadonly(),
5244
+ hasUnsavedChanges: computed(() => this.detectChanges()),
5245
+ isValid: computed(() => this.isFormValid())
5246
+ };
5247
+ this.initializeData();
5248
+ }
5249
+ initializeData() {
5250
+ const initialData = this.config.initialData;
5251
+ let newInstance;
5252
+ if (initialData && Object.keys(initialData).length > 0) {
5253
+ if (this.config.modelFactory) {
5254
+ newInstance = this.config.modelFactory(initialData);
5255
+ }
5256
+ else {
5257
+ newInstance = Object.create(Object.getPrototypeOf(initialData));
5258
+ Object.assign(newInstance, initialData);
5259
+ }
5260
+ }
5261
+ else if (this.mode === ModalMode.CREATE) {
5262
+ if (this.config.modelFactory) {
5263
+ newInstance = this.config.modelFactory({});
5264
+ }
5265
+ else {
5266
+ newInstance = {
5267
+ getId: () => 0,
5268
+ };
5269
+ }
5270
+ }
5271
+ else {
5272
+ this._editedData.set(null);
5273
+ return;
5274
+ }
5275
+ const formGroup = {};
5276
+ this.config.fields.forEach(field => {
5277
+ const fieldKey = field.key;
5278
+ const payloadKey = (field.keyToPayload ?? field.key);
5279
+ const modeConfig = field.modes?.[this.mode];
5280
+ const defaultValue = modeConfig?.defaultValue ?? field.defaultValue;
5281
+ if (this.mode === ModalMode.CREATE) {
5282
+ if (defaultValue !== undefined && newInstance[fieldKey] === undefined) {
5283
+ if (typeof defaultValue === 'function') {
5284
+ const computedValue = defaultValue(newInstance);
5285
+ newInstance[payloadKey] = computedValue;
5286
+ }
5287
+ else {
5288
+ newInstance[payloadKey] = defaultValue;
5289
+ }
5290
+ }
5291
+ }
5292
+ else if (this.mode === ModalMode.EDIT) {
5293
+ if (typeof defaultValue === 'function') {
5294
+ const computedValue = defaultValue(newInstance);
5295
+ newInstance[payloadKey] = computedValue;
5296
+ }
5297
+ }
5298
+ const validators = modeConfig?.validators ?? field.validators ?? [];
5299
+ formGroup[fieldKey] = [newInstance[fieldKey], validators];
5300
+ });
5301
+ this._form.set(this.formBuilder.group(formGroup));
5302
+ this.config.fields.forEach(field => {
5303
+ const fieldKey = field.key;
5304
+ const payloadKey = (field.keyToPayload ?? field.key);
5305
+ if ('dynamicValue' in field && typeof field.dynamicValue === 'function') {
5306
+ const dynamicVal = field.dynamicValue(newInstance);
5307
+ if (dynamicVal !== undefined) {
5308
+ newInstance[payloadKey] = dynamicVal;
5309
+ const control = this._form().get(fieldKey);
5310
+ if (control) {
5311
+ control.setValue(dynamicVal, { emitEvent: false });
5312
+ }
5313
+ }
5314
+ }
5315
+ });
5316
+ this._editedData.set(newInstance);
5317
+ if (this.mode !== ModalMode.VIEW) {
5318
+ const originalCopy = this.config.modelFactory
5319
+ ? this.config.modelFactory(newInstance)
5320
+ : Object.create(Object.getPrototypeOf(newInstance));
5321
+ Object.assign(originalCopy, newInstance);
5322
+ this._originalData.set(originalCopy);
5323
+ }
5324
+ setTimeout(() => {
5325
+ Object.values(this._form().controls).forEach(control => {
5326
+ control.markAsUntouched();
5327
+ });
5328
+ this._fieldErrors.set({});
5329
+ }, 0);
5330
+ if (this.config.onDataChange) {
5331
+ setTimeout(() => {
5332
+ this.config.onDataChange(newInstance);
5333
+ }, 1);
5334
+ }
5335
+ }
5336
+ getFieldValue(fieldKey) {
5337
+ const data = this._editedData();
5338
+ return data ? data[fieldKey] : null;
5339
+ }
5340
+ onFieldValueChange(fieldKey, value) {
5341
+ this.updateField(fieldKey, value);
5342
+ const control = this._form().get(fieldKey);
5343
+ if (control) {
5344
+ control.markAsTouched();
5345
+ this.validateField(fieldKey);
5346
+ if (this.config.onDataChange && this._editedData()) {
5347
+ this.config.onDataChange(this._editedData());
5348
+ }
5349
+ }
5350
+ }
5351
+ onFieldBlur(fieldKey) {
5352
+ const control = this._form().get(fieldKey);
5353
+ if (control) {
5354
+ control.markAsTouched();
5355
+ this.validateField(fieldKey);
5356
+ }
5357
+ }
5358
+ getFieldErrors(fieldKey) {
5359
+ return this._fieldErrors()[fieldKey] || [];
5360
+ }
5361
+ validateField(fieldKey) {
5362
+ const field = this.config.fields.find(f => f.key === fieldKey);
5363
+ const control = this._form().get(fieldKey);
5364
+ const errors = [];
5365
+ if (!field || !control)
5366
+ return;
5367
+ if (control.touched && control.errors) {
5368
+ const modeConfig = field.modes?.[this.mode];
5369
+ const errorMessages = modeConfig?.errorMessages ?? field.errorMessages ?? {};
5370
+ Object.keys(control.errors).forEach(errorKey => {
5371
+ const message = errorMessages[errorKey] || errorKey;
5372
+ errors.push(message);
5373
+ });
5374
+ }
5375
+ if (control.touched && this.config.customValidators && this._editedData()) {
5376
+ const customErrors = this.config.customValidators
5377
+ .flatMap(validator => validator(this._editedData()));
5378
+ errors.push(...customErrors);
5379
+ }
5380
+ this._fieldErrors.update(current => {
5381
+ const updated = { ...current };
5382
+ if (errors.length > 0) {
5383
+ updated[fieldKey] = errors;
5384
+ }
5385
+ else {
5386
+ delete updated[fieldKey];
5387
+ }
5388
+ return updated;
5389
+ });
5390
+ if (this.config.onValidationChange) {
5391
+ this.config.onValidationChange(this._fieldErrors());
5392
+ }
5393
+ }
5394
+ validateAllFields() {
5395
+ const allErrors = {};
5396
+ let isValid = true;
5397
+ this.config.fields.forEach(field => {
5398
+ const modeConfig = field.modes?.[this.mode];
5399
+ if (modeConfig?.visible === false)
5400
+ return;
5401
+ const control = this._form().get(field.key);
5402
+ if (control) {
5403
+ control.markAsTouched();
5404
+ if (control.errors) {
5405
+ isValid = false;
5406
+ const errorMessages = modeConfig?.errorMessages ?? field.errorMessages ?? {};
5407
+ const fieldErrors = Object.keys(control.errors).map(errorKey => errorMessages[errorKey] || errorKey);
5408
+ allErrors[field.key] = fieldErrors;
5409
+ }
5410
+ }
5411
+ });
5412
+ if (this.config.customValidators && this._editedData()) {
5413
+ const customErrors = this.config.customValidators
5414
+ .flatMap(validator => validator(this._editedData()));
5415
+ if (customErrors.length > 0) {
5416
+ isValid = false;
5417
+ allErrors['_custom'] = customErrors;
5418
+ }
5419
+ }
5420
+ this._fieldErrors.set(allErrors);
5421
+ if (this.config.onValidationChange) {
5422
+ this.config.onValidationChange(allErrors);
5423
+ }
5424
+ return isValid;
5425
+ }
5426
+ reset() {
5427
+ this._editedData.set(null);
5428
+ this._fieldErrors.set({});
5429
+ this._originalData.set(null);
5430
+ this._form.set(this.formBuilder.group({}));
5431
+ this.initializeData();
5432
+ }
5433
+ setData(data) {
5434
+ this.config.initialData = data;
5435
+ this.initializeData();
5436
+ }
5437
+ getPayloadData() {
5438
+ const data = this._editedData();
5439
+ if (!data)
5440
+ return null;
5441
+ let clonedData;
5442
+ if (this.config.modelFactory) {
5443
+ clonedData = this.config.modelFactory(data);
5444
+ }
5445
+ else {
5446
+ clonedData = Object.create(Object.getPrototypeOf(data));
5447
+ Object.assign(clonedData, data);
5448
+ }
5449
+ this.config.fields.forEach(field => {
5450
+ const fieldConfig = this.getFieldConfig(field);
5451
+ const shouldInclude = fieldConfig.includeInPayload !== false;
5452
+ if (!shouldInclude) {
5453
+ const targetKey = (fieldConfig.keyToPayload ?? field.key);
5454
+ delete clonedData[targetKey];
5455
+ }
5456
+ else if (field.keyToPayload && field.keyToPayload !== field.key) {
5457
+ delete clonedData[field.key];
5458
+ }
5459
+ });
5460
+ this.convertEmptyStringsToNull(clonedData);
5461
+ return clonedData;
5462
+ }
5463
+ updateField(fieldKey, value) {
5464
+ if (!this._editedData())
5465
+ return;
5466
+ const field = this.config.fields.find(f => f.key === fieldKey);
5467
+ if (!field)
5468
+ return;
5469
+ const payloadKey = (field.keyToPayload ?? field.key);
5470
+ this._editedData.update(data => {
5471
+ if (data) {
5472
+ data[payloadKey] = value;
5473
+ }
5474
+ return data;
5475
+ });
5476
+ const control = this._form().get(fieldKey);
5477
+ if (control) {
5478
+ control.setValue(value, { emitEvent: false });
5479
+ }
5480
+ }
5481
+ getFieldConfig(field) {
5482
+ const modeConfig = field.modes?.[this.mode];
5483
+ if (!modeConfig)
5484
+ return field;
5485
+ return {
5486
+ ...field,
5487
+ defaultValue: modeConfig.defaultValue ?? field.defaultValue,
5488
+ readonly: modeConfig.readonly ?? field.readonly,
5489
+ options: modeConfig.options ?? field.options,
5490
+ validators: modeConfig.validators ?? field.validators,
5491
+ errorMessages: modeConfig.errorMessages ?? field.errorMessages,
5492
+ multiple: modeConfig.multiple ?? field.multiple,
5493
+ visible: modeConfig.visible ?? field.visible,
5494
+ includeInPayload: modeConfig.includeInPayload ?? field.includeInPayload
5495
+ };
5496
+ }
5497
+ detectChanges() {
5498
+ const editedData = this._editedData();
5499
+ const originalData = this._originalData();
5500
+ if (!editedData || !originalData || this.mode === ModalMode.VIEW) {
5501
+ return false;
5502
+ }
5503
+ const relevantFields = this.config.fields.filter(field => {
5504
+ const modeConfig = field.modes?.[this.mode];
5505
+ return modeConfig?.visible !== false;
5506
+ });
5507
+ return relevantFields.some(field => {
5508
+ const fieldKey = field.key;
5509
+ const editedValue = editedData[fieldKey];
5510
+ const originalValue = originalData[fieldKey];
5511
+ if (Array.isArray(editedValue) && Array.isArray(originalValue)) {
5512
+ return JSON.stringify(editedValue) !== JSON.stringify(originalValue);
5513
+ }
5514
+ if (editedValue instanceof Date && originalValue instanceof Date) {
5515
+ return editedValue.getTime() !== originalValue.getTime();
5516
+ }
5517
+ return editedValue !== originalValue;
5518
+ });
5519
+ }
5520
+ isFormValid() {
5521
+ const fieldErrors = this._fieldErrors();
5522
+ return Object.keys(fieldErrors).length === 0;
5523
+ }
5524
+ convertEmptyStringsToNull(data) {
5525
+ Object.keys(data).forEach(key => {
5526
+ const value = data[key];
5527
+ if (typeof value === 'string' && value.trim() === '') {
5528
+ data[key] = null;
5529
+ }
5530
+ else if (Array.isArray(value)) {
5531
+ data[key] = value.map(item => typeof item === 'string' && item.trim() === '' ? null : item);
5532
+ }
5533
+ else if (value && typeof value === 'object' && value.constructor === Object) {
5534
+ this.convertEmptyStringsToNull(value);
5535
+ }
5536
+ });
5537
+ }
5538
+ }
5539
+
5232
5540
  class FileModel {
5233
5541
  id;
5234
5542
  filename;
@@ -11311,12 +11619,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.6", ngImpor
11311
11619
  // Este archivo es generado automáticamente por scripts/update-version.js
11312
11620
  // No edites manualmente este archivo
11313
11621
  const VERSION = {
11314
- full: '2.12.11',
11622
+ full: '2.12.13',
11315
11623
  major: 2,
11316
11624
  minor: 12,
11317
- patch: 11,
11318
- timestamp: '2025-09-05T14:00:47.757Z',
11319
- buildDate: '5/9/2025'
11625
+ patch: 13,
11626
+ timestamp: '2025-09-08T15:36:53.831Z',
11627
+ buildDate: '8/9/2025'
11320
11628
  };
11321
11629
 
11322
11630
  class MainNavComponent {
@@ -13233,5 +13541,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.6", ngImpor
13233
13541
  * Generated bundle index. Do not edit.
13234
13542
  */
13235
13543
 
13236
- export { ActiveFiltersComponent, AlertComponent, AlertContainerComponent, AlertService, AlertType, ApiConfigurationProvider, BaseFieldComponent, ButtonContext, ButtonSize, ButtonType, CacheBustingInterceptor, CardComponent, CarouselComponent, CheckboxFieldComponent, ConfigurationModel, ConfirmationDialogComponent, ConfirmationDialogService, CoreHostDirective, CoreUiHttpLoaderFactory, CoreUiTranslateLoader, CoreUiTranslateService, DataListComponent, DataListItemComponent, DateFieldComponent, DateUtility, DatetimeFieldComponent, DialogActions, DocumentAction, DocumentDisplayMode, DropdownComponent, DropdownDirection, DropdownService, DynamicFieldDirective, FieldErrorsComponent, FieldType, FileFieldComponent, FileModel, FileTemplateModel, FileTemplateType, FileType, FileTypeModel, FileUploadService, FilterModalComponent, FilterService, FilterType, GenericButtonComponent, GenericDocumentationComponent, GenericModalComponent, GenericPaginationComponent, GenericRatingComponent, GenericSidebarComponent, GenericStepsComponent, GenericTableComponent, GenericTabsComponent, GenericTimelineComponent, GlobalApiConfigService, HeaderComponent, HeaderConfigurationService, HeaderElementType, HeaderService, HttpLoaderFactory, ImageModalComponent, ImageModalService, ImagePreviewComponent, LayoutAuth, LayoutBreakpoint, LayoutComponent, LayoutService, LayoutStateService, LayoutType, LoaderComponent, LoaderService, MainNavComponent, MainNavService, ModalMode, ModelApiService, MultiEntryFieldComponent, MultiEntryOutputFormat, NumberFieldComponent, NumberFieldConfigType, NumberFieldType, NumberRange, PERMISSION_ACTIONS_PROVIDER, PERMISSION_PROVIDER, PERMISSION_RESOURCES_PROVIDER, PaginationService, PasswordFieldComponent, PermissionEnumsService, PermissionModel, PermissionService, PermissionWrapperService, PermissionsActions, PermissionsInterceptor, PermissionsResources, ProgressBarComponent, ProgressBarSize, RatingService, RatingSize, RatingType, ResetPasswordModel, RoleModel, SelectFieldComponent, ServerSelectFieldComponent, ServerSelectService, SidebarCustomModalComponent, SidebarCustomModalService, SidebarHeight, SidebarMobileModalService, SidebarMobileType, SidebarPosition, SidebarService, SidebarState, SidebarTemplateRegistryService, SidebarVisibility, SidebarWidth, SmartFieldComponent, SortDirection, SortMode, StepSize, StepStatus, StepType, StepsService, SwitchFieldComponent, TableAction, TableActionService, TableDataService, TableSortService, TextAreaFieldComponent, TextFieldComponent, TimeFieldComponent, TimeInterval, TimelineService, TimelineStatus, TimelineType, TranslationMergeService, UsersModel, VERSION, equalToValidator, isSameDate, provideCoreUiTranslateLoader, providePermissionActions, providePermissionEnums, providePermissionResources, providePermissionService, providePermissionServiceFactory, provideTranslateLoader };
13544
+ export { ActiveFiltersComponent, AlertComponent, AlertContainerComponent, AlertService, AlertType, ApiConfigurationProvider, BaseFieldComponent, ButtonContext, ButtonSize, ButtonType, CacheBustingInterceptor, CardComponent, CarouselComponent, CheckboxFieldComponent, ConfigurationModel, ConfirmationDialogComponent, ConfirmationDialogService, CoreHostDirective, CoreUiHttpLoaderFactory, CoreUiTranslateLoader, CoreUiTranslateService, DataListComponent, DataListItemComponent, DateFieldComponent, DateUtility, DatetimeFieldComponent, DialogActions, DocumentAction, DocumentDisplayMode, DropdownComponent, DropdownDirection, DropdownService, DynamicFieldDirective, DynamicFieldsHelper, FieldErrorsComponent, FieldType, FileFieldComponent, FileModel, FileTemplateModel, FileTemplateType, FileType, FileTypeModel, FileUploadService, FilterModalComponent, FilterService, FilterType, GenericButtonComponent, GenericDocumentationComponent, GenericModalComponent, GenericPaginationComponent, GenericRatingComponent, GenericSidebarComponent, GenericStepsComponent, GenericTableComponent, GenericTabsComponent, GenericTimelineComponent, GlobalApiConfigService, HeaderComponent, HeaderConfigurationService, HeaderElementType, HeaderService, HttpLoaderFactory, ImageModalComponent, ImageModalService, ImagePreviewComponent, LayoutAuth, LayoutBreakpoint, LayoutComponent, LayoutService, LayoutStateService, LayoutType, LoaderComponent, LoaderService, MainNavComponent, MainNavService, ModalMode, ModelApiService, MultiEntryFieldComponent, MultiEntryOutputFormat, NumberFieldComponent, NumberFieldConfigType, NumberFieldType, NumberRange, PERMISSION_ACTIONS_PROVIDER, PERMISSION_PROVIDER, PERMISSION_RESOURCES_PROVIDER, PaginationService, PasswordFieldComponent, PermissionEnumsService, PermissionModel, PermissionService, PermissionWrapperService, PermissionsActions, PermissionsInterceptor, PermissionsResources, ProgressBarComponent, ProgressBarSize, RatingService, RatingSize, RatingType, ResetPasswordModel, RoleModel, SelectFieldComponent, ServerSelectFieldComponent, ServerSelectService, SidebarCustomModalComponent, SidebarCustomModalService, SidebarHeight, SidebarMobileModalService, SidebarMobileType, SidebarPosition, SidebarService, SidebarState, SidebarTemplateRegistryService, SidebarVisibility, SidebarWidth, SmartFieldComponent, SortDirection, SortMode, StepSize, StepStatus, StepType, StepsService, SwitchFieldComponent, TableAction, TableActionService, TableDataService, TableSortService, TextAreaFieldComponent, TextFieldComponent, TimeFieldComponent, TimeInterval, TimelineService, TimelineStatus, TimelineType, TranslationMergeService, UsersModel, VERSION, equalToValidator, isSameDate, provideCoreUiTranslateLoader, providePermissionActions, providePermissionEnums, providePermissionResources, providePermissionService, providePermissionServiceFactory, provideTranslateLoader };
13237
13545
  //# sourceMappingURL=solcre-org-core-ui.mjs.map