@solcre-org/core-ui 2.15.33 → 2.15.35

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.
@@ -371,6 +371,12 @@ class CheckboxFieldComponent extends BaseFieldComponent {
371
371
  const checkboxField = this.field();
372
372
  return checkboxField.checkboxConfig?.required ?? false;
373
373
  });
374
+ hasRequiredIndicator = computed(() => {
375
+ if (this.hasRequiredValidators()) {
376
+ return true;
377
+ }
378
+ return this.isRequired();
379
+ });
374
380
  hasMultipleOptions = computed(() => this.options().length > 0);
375
381
  hasSeparatedOptions = computed(() => this.field().checkboxConfig?.separatedOptions ?? false);
376
382
  constructor() {
@@ -444,8 +450,7 @@ class CheckboxFieldComponent extends BaseFieldComponent {
444
450
  }
445
451
  }
446
452
  initializeFormControl() {
447
- const modeConfig = this.field().modes?.[this.mode()];
448
- const validators = modeConfig?.validators ?? this.field().validators ?? [];
453
+ const validators = this.getCurrentValidators();
449
454
  let initialValue = this.getInitialValue();
450
455
  this.formControl.set(new FormControl(initialValue, validators));
451
456
  this.formControl().valueChanges.subscribe(newValue => {
@@ -561,11 +566,11 @@ class CheckboxFieldComponent extends BaseFieldComponent {
561
566
  }
562
567
  }
563
568
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: CheckboxFieldComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
564
- 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"] }] });
569
+ 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 (hasRequiredIndicator()) {\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 (hasRequiredIndicator()) {\n <span class=\"c-required\">*</span>\n }\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"] }] });
565
570
  }
566
571
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: CheckboxFieldComponent, decorators: [{
567
572
  type: Component,
568
- 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"] }]
573
+ 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 (hasRequiredIndicator()) {\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 (hasRequiredIndicator()) {\n <span class=\"c-required\">*</span>\n }\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"] }]
569
574
  }], ctorParameters: () => [] });
570
575
 
571
576
  class DateFieldComponent extends BaseFieldComponent {
@@ -10860,6 +10865,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.6", ngImpor
10860
10865
  }]
10861
10866
  }] });
10862
10867
 
10868
+ const MODEL_REFERENCE_SORT_KEY = '__model_reference__';
10863
10869
  class TableSortService {
10864
10870
  sortConfigsSubject = new BehaviorSubject([]);
10865
10871
  tableSortConfig = { mode: SortMode.MEMORY };
@@ -10911,24 +10917,23 @@ class TableSortService {
10911
10917
  const existingSort = currentSorts.find(sort => sort.key === columnKey);
10912
10918
  let newSorts;
10913
10919
  if (existingSort) {
10914
- if (existingSort.direction === SortDirection.ASC) {
10915
- if (this.tableSortConfig.multiColumn) {
10916
- newSorts = currentSorts.map(sort => sort.key === columnKey
10917
- ? { ...sort, direction: SortDirection.DESC }
10918
- : sort);
10919
- }
10920
- else {
10921
- newSorts = [{ ...existingSort, direction: SortDirection.DESC, priority: 0 }];
10922
- }
10920
+ const currentDirection = existingSort.direction;
10921
+ const newDirection = currentDirection === SortDirection.DESC
10922
+ ? SortDirection.ASC
10923
+ : SortDirection.DESC;
10924
+ if (this.tableSortConfig.multiColumn) {
10925
+ newSorts = currentSorts.map(sort => sort.key === columnKey
10926
+ ? { ...sort, direction: newDirection }
10927
+ : sort);
10923
10928
  }
10924
10929
  else {
10925
- newSorts = currentSorts.filter(sort => sort.key !== columnKey);
10930
+ newSorts = [{ ...existingSort, direction: newDirection, priority: 0 }];
10926
10931
  }
10927
10932
  }
10928
10933
  else {
10929
10934
  const newSort = {
10930
10935
  key: columnKey,
10931
- direction: SortDirection.ASC,
10936
+ direction: SortDirection.DESC,
10932
10937
  priority: 0
10933
10938
  };
10934
10939
  if (this.tableSortConfig.multiColumn) {
@@ -10974,7 +10979,12 @@ class TableSortService {
10974
10979
  for (const sortConfig of sortConfigs.sort((x, y) => (x.priority ?? 0) - (y.priority ?? 0))) {
10975
10980
  const column = columns.find(col => col.key === sortConfig.key || col.sortKey === sortConfig.key);
10976
10981
  let result = 0;
10977
- if (column?.sortFunction) {
10982
+ if (sortConfig.key === MODEL_REFERENCE_SORT_KEY) {
10983
+ const referenceA = this.getModelReferenceValue(a);
10984
+ const referenceB = this.getModelReferenceValue(b);
10985
+ result = this.compareValues(referenceA, referenceB);
10986
+ }
10987
+ else if (column?.sortFunction) {
10978
10988
  result = column.sortFunction(a, b);
10979
10989
  }
10980
10990
  else {
@@ -11001,12 +11011,18 @@ class TableSortService {
11001
11011
  sortConfigs
11002
11012
  .sort((a, b) => (a.priority ?? 0) - (b.priority ?? 0))
11003
11013
  .forEach(sort => {
11014
+ if (sort.key === MODEL_REFERENCE_SORT_KEY) {
11015
+ return;
11016
+ }
11004
11017
  params[`${paramName}[${sort.key}]`] = sort.direction;
11005
11018
  });
11006
11019
  return params;
11007
11020
  }
11008
11021
  else {
11009
11022
  const firstSort = sortConfigs[0];
11023
+ if (firstSort.key === MODEL_REFERENCE_SORT_KEY) {
11024
+ return {};
11025
+ }
11010
11026
  return {
11011
11027
  [`${paramName}[${firstSort.key}]`]: firstSort.direction
11012
11028
  };
@@ -11023,6 +11039,13 @@ class TableSortService {
11023
11039
  return value && value[key] !== undefined ? value[key] : null;
11024
11040
  }, obj);
11025
11041
  }
11042
+ getModelReferenceValue(item) {
11043
+ if (item && typeof item.getReference === 'function') {
11044
+ const reference = item.getReference();
11045
+ return reference !== undefined && reference !== null ? String(reference) : null;
11046
+ }
11047
+ return null;
11048
+ }
11026
11049
  compareValues(a, b) {
11027
11050
  if (a === null || a === undefined)
11028
11051
  return b === null || b === undefined ? 0 : -1;
@@ -12846,6 +12869,10 @@ class GenericTableComponent {
12846
12869
  window.addEventListener('createRequested', this.handleCreateRequested);
12847
12870
  window.addEventListener('globalActionTriggered', this.handleGlobalActionTriggered);
12848
12871
  window.addEventListener('popstate', this.handlePopstate);
12872
+ effect(() => {
12873
+ this.columns();
12874
+ queueMicrotask(() => this.applyDefaultSortIfNeeded());
12875
+ });
12849
12876
  effect(() => {
12850
12877
  this.updateHeaderService();
12851
12878
  });
@@ -12903,6 +12930,10 @@ class GenericTableComponent {
12903
12930
  }
12904
12931
  }
12905
12932
  this.tableSortService.configure(this.sortConfig());
12933
+ this.applyDefaultSortIfNeeded();
12934
+ }
12935
+ else {
12936
+ this.applyDefaultSortIfNeeded();
12906
12937
  }
12907
12938
  this.subscriptions.push(this.tableSortService.sortConfigs$.subscribe(() => {
12908
12939
  this.handleSortChange();
@@ -13048,6 +13079,34 @@ class GenericTableComponent {
13048
13079
  this.processDataInput(this.dataInput());
13049
13080
  }
13050
13081
  }
13082
+ applyDefaultSortIfNeeded() {
13083
+ const currentSorts = this.tableSortService.getCurrentSortConfigs();
13084
+ if (currentSorts.length > 0) {
13085
+ return;
13086
+ }
13087
+ if (!this.tableSortService.isServerMode()) {
13088
+ this.tableSortService.setSortConfigs([
13089
+ {
13090
+ key: MODEL_REFERENCE_SORT_KEY,
13091
+ direction: SortDirection.DESC,
13092
+ priority: 0,
13093
+ },
13094
+ ]);
13095
+ return;
13096
+ }
13097
+ const firstSortableColumn = this.columns().find(column => column.sortable);
13098
+ if (!firstSortableColumn) {
13099
+ return;
13100
+ }
13101
+ const sortKey = firstSortableColumn.sortKey || firstSortableColumn.key;
13102
+ this.tableSortService.setSortConfigs([
13103
+ {
13104
+ key: sortKey,
13105
+ direction: SortDirection.DESC,
13106
+ priority: 0,
13107
+ },
13108
+ ]);
13109
+ }
13051
13110
  updateDisplayedDataFromServer(data) {
13052
13111
  if (!Array.isArray(data)) {
13053
13112
  data = [];
@@ -14169,6 +14228,7 @@ class GenericTableComponent {
14169
14228
  ngOnDestroy() {
14170
14229
  this.subscriptions.forEach(sub => sub.unsubscribe());
14171
14230
  this.inlineEditService.destroy();
14231
+ this.tableSortService.reset();
14172
14232
  this.loaderTimeouts.forEach((timeoutId) => {
14173
14233
  clearTimeout(timeoutId);
14174
14234
  });
@@ -16216,12 +16276,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.6", ngImpor
16216
16276
  // Este archivo es generado automáticamente por scripts/update-version.js
16217
16277
  // No edites manualmente este archivo
16218
16278
  const VERSION = {
16219
- full: '2.15.33',
16279
+ full: '2.15.35',
16220
16280
  major: 2,
16221
16281
  minor: 15,
16222
- patch: 33,
16223
- timestamp: '2025-11-12T13:53:53.157Z',
16224
- buildDate: '12/11/2025'
16282
+ patch: 35,
16283
+ timestamp: '2025-11-14T15:54:22.049Z',
16284
+ buildDate: '14/11/2025'
16225
16285
  };
16226
16286
 
16227
16287
  class MainNavComponent {
@@ -18392,6 +18452,41 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.6", ngImpor
18392
18452
  }]
18393
18453
  }] });
18394
18454
 
18455
+ class RedirectUrlService {
18456
+ REDIRECT_URL_KEY = 'redirect_after_login';
18457
+ setRedirectUrl(url) {
18458
+ if (url && url !== '/app/auth' && url !== '/app' && !url.includes('/auth')) {
18459
+ sessionStorage.setItem(this.REDIRECT_URL_KEY, url);
18460
+ }
18461
+ }
18462
+ getRedirectUrl() {
18463
+ return sessionStorage.getItem(this.REDIRECT_URL_KEY);
18464
+ }
18465
+ getAndClearRedirectUrl() {
18466
+ const url = this.getRedirectUrl();
18467
+ this.clearRedirectUrl();
18468
+ return url;
18469
+ }
18470
+ clearRedirectUrl() {
18471
+ sessionStorage.removeItem(this.REDIRECT_URL_KEY);
18472
+ }
18473
+ hasRedirectUrl() {
18474
+ return !!this.getRedirectUrl();
18475
+ }
18476
+ setFullRedirectUrl() {
18477
+ const fullUrl = window.location.pathname + window.location.search + window.location.hash;
18478
+ this.setRedirectUrl(fullUrl);
18479
+ }
18480
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: RedirectUrlService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
18481
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: RedirectUrlService, providedIn: 'root' });
18482
+ }
18483
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: RedirectUrlService, decorators: [{
18484
+ type: Injectable,
18485
+ args: [{
18486
+ providedIn: 'root'
18487
+ }]
18488
+ }] });
18489
+
18395
18490
  class TranslationMergeService {
18396
18491
  http;
18397
18492
  constructor(http) {
@@ -19949,5 +20044,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.6", ngImpor
19949
20044
  * Generated bundle index. Do not edit.
19950
20045
  */
19951
20046
 
19952
- export { ALL_COUNTRY_CODES, ActiveFiltersComponent, AgeValidationHelper, AlertComponent, AlertContainerComponent, AlertService, AlertType, ApiConfigurationProvider, BaseFieldComponent, ButtonContext, ButtonSize, ButtonType, COMMON_COUNTRIES, CacheBustingInterceptor, CardComponent, CarouselComponent, ChatMessagePosition, ChatMessageType, CheckboxFieldComponent, ConfigurationModel, ConfirmationDialogComponent, ConfirmationDialogService, CoreHostDirective, CoreManualRefreshComponent, CoreUiHttpLoaderFactory, CoreUiTranslateLoader, CoreUiTranslateService, CountryCode, CustomClassService, DEFAULT_COUNTRIES, DataListComponent, DataListItemComponent, DataStoreService, DateFieldComponent, DateUtility, DatetimeFieldComponent, DialogActions, DocumentAction, DocumentDisplayMode, DocumentFieldComponent, DocumentFieldValidators, DocumentPayloadMode, DropdownComponent, DropdownDirection, DropdownService, DynamicFieldDirective, DynamicFieldsHelper, FieldErrorsComponent, FieldType, FileFieldComponent, FileModel, FilePreviewActionType, FileTemplateModel, FileTemplateType, FileType, FileTypeModel, FileUploadService, FilterModalComponent, FilterService, FilterType, FixedActionPosition, FixedActionsMobileModalComponent, FixedActionsMobileModalService, GalleryAnimationType, GalleryLayoutType, GalleryModalComponent, GalleryModalGlobalService, GenericButtonComponent, GenericChatComponent, GenericChatService, GenericDocumentationComponent, GenericFixedActionsComponent, GenericGalleryComponent, GenericModalComponent, GenericPaginationComponent, GenericRatingComponent, GenericSidebarComponent, GenericSkeletonComponent, GenericStepsComponent, GenericSwitchComponent, GenericTableComponent, GenericTabsComponent, GenericTimelineComponent, GlobalApiConfigService, HeaderComponent, HeaderConfigurationService, HeaderElementType, HeaderService, HttpLoaderFactory, ImageModalComponent, ImageModalService, ImagePreviewComponent, LATIN_AMERICA_COUNTRIES, LayoutAuth, LayoutBreakpoint, LayoutComponent, LayoutService, LayoutStateService, LayoutType, LoaderComponent, LoaderService, MainNavComponent, MainNavService, ManualRefreshService, MobileHeaderComponent, MobileResolutionService, ModalMode, ModelApiService, MultiEntryFieldComponent, MultiEntryOutputFormat, NumberFieldComponent, NumberFieldConfigType, NumberFieldType, NumberRange, PERMISSION_ACTIONS_PROVIDER, PERMISSION_PROVIDER, PERMISSION_RESOURCES_PROVIDER, PaginationService, PasswordFieldComponent, PermissionEnumsService, PermissionModel, PermissionService, PermissionWrapperService, PermissionsActions, PermissionsCustomActions, PermissionsInterceptor, PermissionsResources, PhoneFieldComponent, ProgressBarComponent, ProgressBarSize, RatingService, RatingSize, RatingType, ResetPasswordModel, RoleModel, SOUTH_AMERICA_COUNTRIES, SelectFieldComponent, ServerSelectFieldComponent, ServerSelectService, SidebarCustomModalComponent, SidebarCustomModalService, SidebarHeight, SidebarMobileModalService, SidebarMobileType, SidebarPosition, SidebarService, SidebarState, SidebarTemplateRegistryService, SidebarVisibility, SidebarWidth, SkeletonAnimation, SkeletonService, SkeletonSize, SkeletonType, SmartFieldComponent, SortDirection, SortMode, StepSize, StepStatus, StepType, StepsService, SwitchFieldComponent, TableAction, TableActionService, TableDataService, TableFixedActionsService, TableSortService, TextAreaFieldComponent, TextFieldComponent, TimeFieldComponent, TimeInterval, TimelineService, TimelineStatus, TimelineType, TranslationMergeService, UruguayanDocumentValidationHelper, UsersModel, VERSION, ageValidator, calculateAge, equalToValidator, generateRandomUruguayanDocument, getCountryCodeStrings, getLatestBirthDateForAge, getRandomCi, getUruguayanDocumentValidationDigit, getValidationDigit, isSameDate, isValidCountryCode, provideCoreUiTranslateLoader, providePermissionActions, providePermissionEnums, providePermissionResources, providePermissionService, providePermissionServiceFactory, provideTranslateLoader, random, transform, transformUruguayanDocument, uruguayanDocumentValidator, validate, validateAge, validateCi, validateUruguayanDocument, validationDigit };
20047
+ export { ALL_COUNTRY_CODES, ActiveFiltersComponent, AgeValidationHelper, AlertComponent, AlertContainerComponent, AlertService, AlertType, ApiConfigurationProvider, BaseFieldComponent, ButtonContext, ButtonSize, ButtonType, COMMON_COUNTRIES, CacheBustingInterceptor, CardComponent, CarouselComponent, ChatMessagePosition, ChatMessageType, CheckboxFieldComponent, ConfigurationModel, ConfirmationDialogComponent, ConfirmationDialogService, CoreHostDirective, CoreManualRefreshComponent, CoreUiHttpLoaderFactory, CoreUiTranslateLoader, CoreUiTranslateService, CountryCode, CustomClassService, DEFAULT_COUNTRIES, DataListComponent, DataListItemComponent, DataStoreService, DateFieldComponent, DateUtility, DatetimeFieldComponent, DialogActions, DocumentAction, DocumentDisplayMode, DocumentFieldComponent, DocumentFieldValidators, DocumentPayloadMode, DropdownComponent, DropdownDirection, DropdownService, DynamicFieldDirective, DynamicFieldsHelper, FieldErrorsComponent, FieldType, FileFieldComponent, FileModel, FilePreviewActionType, FileTemplateModel, FileTemplateType, FileType, FileTypeModel, FileUploadService, FilterModalComponent, FilterService, FilterType, FixedActionPosition, FixedActionsMobileModalComponent, FixedActionsMobileModalService, GalleryAnimationType, GalleryLayoutType, GalleryModalComponent, GalleryModalGlobalService, GenericButtonComponent, GenericChatComponent, GenericChatService, GenericDocumentationComponent, GenericFixedActionsComponent, GenericGalleryComponent, GenericModalComponent, GenericPaginationComponent, GenericRatingComponent, GenericSidebarComponent, GenericSkeletonComponent, GenericStepsComponent, GenericSwitchComponent, GenericTableComponent, GenericTabsComponent, GenericTimelineComponent, GlobalApiConfigService, HeaderComponent, HeaderConfigurationService, HeaderElementType, HeaderService, HttpLoaderFactory, ImageModalComponent, ImageModalService, ImagePreviewComponent, LATIN_AMERICA_COUNTRIES, LayoutAuth, LayoutBreakpoint, LayoutComponent, LayoutService, LayoutStateService, LayoutType, LoaderComponent, LoaderService, MODEL_REFERENCE_SORT_KEY, MainNavComponent, MainNavService, ManualRefreshService, MobileHeaderComponent, MobileResolutionService, ModalMode, ModelApiService, MultiEntryFieldComponent, MultiEntryOutputFormat, NumberFieldComponent, NumberFieldConfigType, NumberFieldType, NumberRange, PERMISSION_ACTIONS_PROVIDER, PERMISSION_PROVIDER, PERMISSION_RESOURCES_PROVIDER, PaginationService, PasswordFieldComponent, PermissionEnumsService, PermissionModel, PermissionService, PermissionWrapperService, PermissionsActions, PermissionsCustomActions, PermissionsInterceptor, PermissionsResources, PhoneFieldComponent, ProgressBarComponent, ProgressBarSize, RatingService, RatingSize, RatingType, RedirectUrlService, ResetPasswordModel, RoleModel, SOUTH_AMERICA_COUNTRIES, SelectFieldComponent, ServerSelectFieldComponent, ServerSelectService, SidebarCustomModalComponent, SidebarCustomModalService, SidebarHeight, SidebarMobileModalService, SidebarMobileType, SidebarPosition, SidebarService, SidebarState, SidebarTemplateRegistryService, SidebarVisibility, SidebarWidth, SkeletonAnimation, SkeletonService, SkeletonSize, SkeletonType, SmartFieldComponent, SortDirection, SortMode, StepSize, StepStatus, StepType, StepsService, SwitchFieldComponent, TableAction, TableActionService, TableDataService, TableFixedActionsService, TableSortService, TextAreaFieldComponent, TextFieldComponent, TimeFieldComponent, TimeInterval, TimelineService, TimelineStatus, TimelineType, TranslationMergeService, UruguayanDocumentValidationHelper, UsersModel, VERSION, ageValidator, calculateAge, equalToValidator, generateRandomUruguayanDocument, getCountryCodeStrings, getLatestBirthDateForAge, getRandomCi, getUruguayanDocumentValidationDigit, getValidationDigit, isSameDate, isValidCountryCode, provideCoreUiTranslateLoader, providePermissionActions, providePermissionEnums, providePermissionResources, providePermissionService, providePermissionServiceFactory, provideTranslateLoader, random, transform, transformUruguayanDocument, uruguayanDocumentValidator, validate, validateAge, validateCi, validateUruguayanDocument, validationDigit };
19953
20048
  //# sourceMappingURL=solcre-org-core-ui.mjs.map