ui-core-abv 0.6.81 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -3,7 +3,7 @@ import { CommonModule, CurrencyPipe, DatePipe } from '@angular/common';
3
3
  import * as i0 from '@angular/core';
4
4
  import { Input, Component, EventEmitter, Output, Directive, forwardRef, InjectionToken, Optional, Inject, Injectable, inject, ChangeDetectorRef, Pipe, ViewContainerRef, ElementRef, ViewChild, createComponent, HostListener, ViewChildren, Host, DestroyRef, signal, computed, effect, TemplateRef, ContentChild, Injector, EnvironmentInjector, HostBinding, input, output } from '@angular/core';
5
5
  import * as i1$1 from '@angular/forms';
6
- import { NG_VALUE_ACCESSOR, FormsModule, ReactiveFormsModule, FormBuilder, Validators } from '@angular/forms';
6
+ import { NG_VALUE_ACCESSOR, FormsModule, FormBuilder, Validators, ReactiveFormsModule, FormArray } from '@angular/forms';
7
7
  import { BehaviorSubject, Subject, debounceTime, distinctUntilChanged, tap, switchMap, of, finalize, map, isObservable, from, Subscription } from 'rxjs';
8
8
  import { HttpClient } from '@angular/common/http';
9
9
  import { Overlay, OverlayRef } from '@angular/cdk/overlay';
@@ -488,6 +488,13 @@ const DICTIONARY_EN = {
488
488
  selectSearchEnabled_tip: 'Enables search among options',
489
489
  selectNullable: 'Allow empty option',
490
490
  selectSearchEnabled: 'Enable search',
491
+ repeaterMinItems: 'Minimum items',
492
+ repeaterMinItems_tip: 'Minimum number of required items',
493
+ repeaterMaxItems: 'Maximum items',
494
+ repeaterMaxItems_tip: 'Maximum number of allowed items',
495
+ repeaterAddLabel: 'Add button label',
496
+ repeaterRemoveLabel: 'Remove button label',
497
+ repeaterItemTitle: 'Item title',
491
498
  },
492
499
  options_editor: {
493
500
  title: 'Options',
@@ -513,6 +520,7 @@ const DICTIONARY_EN = {
513
520
  delete: 'Delete',
514
521
  show_advanced: 'Show advanced',
515
522
  hide_advanced: 'Hide advanced',
523
+ subfields: 'Sub-fields',
516
524
  },
517
525
  visibility_operators: {
518
526
  equals: 'Equals',
@@ -527,6 +535,10 @@ const DICTIONARY_EN = {
527
535
  validation: {
528
536
  duplicate_identifier: 'The identifier "{{identifier}}" is used more than once.',
529
537
  duplicate_identifier_title: 'Validation error',
538
+ },
539
+ repeater: {
540
+ no_subfields: 'No sub-fields yet. Add one below.',
541
+ add_subfield: 'Add sub-field',
530
542
  }
531
543
  },
532
544
  validation: {
@@ -803,6 +815,13 @@ const DICTIONARY_ES = {
803
815
  selectSearchEnabled_tip: 'Habilita búsqueda entre opciones',
804
816
  selectNullable: 'Permitir opción vacía',
805
817
  selectSearchEnabled: 'Habilitar búsqueda',
818
+ repeaterMinItems: 'Mínimo de ítems',
819
+ repeaterMinItems_tip: 'Cantidad mínima de ítems requerida',
820
+ repeaterMaxItems: 'Máximo de ítems',
821
+ repeaterMaxItems_tip: 'Cantidad máxima de ítems permitida',
822
+ repeaterAddLabel: 'Etiqueta del botón agregar',
823
+ repeaterRemoveLabel: 'Etiqueta del botón eliminar',
824
+ repeaterItemTitle: 'Título de ítem',
806
825
  },
807
826
  options_editor: {
808
827
  title: 'Opciones',
@@ -828,6 +847,7 @@ const DICTIONARY_ES = {
828
847
  delete: 'Eliminar',
829
848
  show_advanced: 'Mostrar avanzado',
830
849
  hide_advanced: 'Ocultar avanzado',
850
+ subfields: 'Sub-campos',
831
851
  },
832
852
  visibility_operators: {
833
853
  equals: 'Es igual a',
@@ -842,6 +862,10 @@ const DICTIONARY_ES = {
842
862
  validation: {
843
863
  duplicate_identifier: 'El identificador "{{identifier}}" se está usando más de una vez.',
844
864
  duplicate_identifier_title: 'Error de validación',
865
+ },
866
+ repeater: {
867
+ no_subfields: 'Sin sub-campos. Añade uno abajo.',
868
+ add_subfield: 'Agregar sub-campo',
845
869
  }
846
870
  },
847
871
  validation: {
@@ -3872,6 +3896,111 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImpo
3872
3896
  type: Injectable
3873
3897
  }], ctorParameters: () => [] });
3874
3898
 
3899
+ class UicRepeaterComponent {
3900
+ fb = inject(FormBuilder);
3901
+ formArray;
3902
+ field;
3903
+ cols = 2;
3904
+ error;
3905
+ ngOnInit() {
3906
+ if (this.formArray.length === 0) {
3907
+ const min = this.field.repeaterMinItems ?? 0;
3908
+ for (let i = 0; i < min; i++) {
3909
+ this.addGroup();
3910
+ }
3911
+ }
3912
+ }
3913
+ getGroup(index) {
3914
+ return this.formArray.at(index);
3915
+ }
3916
+ addGroup() {
3917
+ if (this.field.repeaterMaxItems && this.formArray.length >= this.field.repeaterMaxItems) {
3918
+ return;
3919
+ }
3920
+ const group = this.fb.group({});
3921
+ (this.field.repeaterFields || []).forEach(subField => {
3922
+ const validators = this.mapValidatorsFromField(subField);
3923
+ const controlState = {
3924
+ value: this.getBlankValue(subField),
3925
+ disabled: !!subField.disabled
3926
+ };
3927
+ group.addControl(subField.name, this.fb.control(controlState, validators));
3928
+ });
3929
+ this.formArray.push(group);
3930
+ }
3931
+ removeGroup(index) {
3932
+ if (this.field.repeaterMinItems && this.formArray.length <= this.field.repeaterMinItems) {
3933
+ return;
3934
+ }
3935
+ this.formArray.removeAt(index);
3936
+ }
3937
+ get canAdd() {
3938
+ if (!this.field.repeaterMaxItems)
3939
+ return true;
3940
+ return this.formArray.length < this.field.repeaterMaxItems;
3941
+ }
3942
+ get canRemove() {
3943
+ if (this.field.repeaterMinItems !== undefined && this.field.repeaterMinItems !== null) {
3944
+ return this.formArray.length > this.field.repeaterMinItems;
3945
+ }
3946
+ return true;
3947
+ }
3948
+ mapValidatorsFromField(field) {
3949
+ const validators = [];
3950
+ if (field.required)
3951
+ validators.push(Validators.required);
3952
+ if (typeof field.min === 'number')
3953
+ validators.push(Validators.min(field.min));
3954
+ if (typeof field.max === 'number')
3955
+ validators.push(Validators.max(field.max));
3956
+ if (typeof field.maxLength === 'number')
3957
+ validators.push(Validators.maxLength(field.maxLength));
3958
+ if (typeof field.minLength === 'number')
3959
+ validators.push(Validators.minLength(field.minLength));
3960
+ if (field.pattern instanceof RegExp)
3961
+ validators.push(Validators.pattern(field.pattern));
3962
+ return validators;
3963
+ }
3964
+ getBlankValue(field) {
3965
+ switch (field.type) {
3966
+ case 'text':
3967
+ case 'textarea':
3968
+ case 'phone':
3969
+ return '';
3970
+ case 'checkbox':
3971
+ case 'switch':
3972
+ return false;
3973
+ case 'multyselect':
3974
+ return [];
3975
+ case 'slider':
3976
+ return field.min ?? 0;
3977
+ default:
3978
+ return null;
3979
+ }
3980
+ }
3981
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: UicRepeaterComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
3982
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.14", type: UicRepeaterComponent, isStandalone: true, selector: "ui-repeater", inputs: { formArray: "formArray", field: "field", cols: "cols", error: "error" }, ngImport: i0, template: "<div class=\"repeater-label\"> {{field.label}} </div>\r\n<div class=\"uic-repeater\" [class.disabled]=\"formArray.disabled\">\r\n @for (group of formArray.controls; track $index) {\r\n <div class=\"uic-repeater-item\">\r\n <div class=\"uic-repeater-item-header\">\r\n <h4 class=\"uic-repeater-item-title\">\r\n {{ field.repeaterItemTitle || field.label || 'Item' }} {{ $index + 1 }}\r\n </h4>\r\n @if (canRemove && !formArray.disabled) {\r\n <ui-button \r\n [icon]=\"'ri-delete-bin-line'\" \r\n [type]=\"'bordered'\" \r\n [color]=\"'red'\" \r\n size=\"s\" \r\n (click)=\"removeGroup($index)\"\r\n [text]=\"field.repeaterRemoveLabel || 'Eliminar'\">\r\n </ui-button>\r\n }\r\n </div>\r\n <div class=\"uic-repeater-item-body\">\r\n <ui-dynamic-form \r\n [form]=\"getGroup($index)\" \r\n [fields]=\"field.repeaterFields || []\" \r\n [disabled]=\"formArray.disabled\"\r\n [cols]=\"cols\"\r\n [isSubForm]=\"true\">\r\n </ui-dynamic-form>\r\n </div>\r\n </div>\r\n }\r\n \r\n @if (canAdd && !formArray.disabled) {\r\n <div class=\"uic-repeater-add-action\">\r\n <ui-button \r\n [icon]=\"'ri-add-line'\" \r\n [type]=\"'bordered'\" \r\n [color]=\"'primary'\" \r\n (click)=\"addGroup()\"\r\n [text]=\"field.repeaterAddLabel || 'A\u00F1adir'\">\r\n </ui-button>\r\n </div>\r\n }\r\n @if (error) {\r\n <p class=\"uic-repeater-error\">{{ error }}</p>\r\n }\r\n</div>\r\n", styles: [".uic-repeater{display:flex;flex-direction:column;gap:16px;width:100%}.uic-repeater.disabled{opacity:.7;pointer-events:none}.uic-repeater .uic-repeater-item{border:1px solid var(--primary-400, #e0e0e0);border-radius:8px;padding:16px;background-color:var(--uic-bg-color, #fff)}.uic-repeater .uic-repeater-item .uic-repeater-item-header{display:flex;justify-content:space-between;align-items:center;margin-bottom:16px;padding-bottom:12px;border-bottom:1px dashed var(--uic-border-color, #e0e0e0)}.uic-repeater .uic-repeater-item .uic-repeater-item-header .uic-repeater-item-title{margin:0;font-size:14px;font-weight:600;color:var(--uic-text-color, #333)}.uic-repeater .uic-repeater-item .uic-repeater-item-body{width:100%}.uic-repeater .uic-repeater-add-action{margin-top:8px}.uic-repeater .uic-repeater-error{margin:4px 0 0;font-size:12px;color:var(--uic-red, #e53935)}.repeater-label{font-size:max(var(--form-ref) + 4px,14px);line-height:1.125rem;min-height:1.125rem;font-weight:400;color:var(--grey-950);margin-bottom:var(--input-label-space)}\n"], dependencies: [{ kind: "ngmodule", type: i0.forwardRef(() => CommonModule) }, { kind: "ngmodule", type: i0.forwardRef(() => ReactiveFormsModule) }, { kind: "component", type: i0.forwardRef(() => UicButtonComponent), selector: "ui-button", inputs: ["text", "icon", "rightIcon", "iconOnly", "disabled", "loading", "size", "type", "color"] }, { kind: "component", type: i0.forwardRef(() => UicDynamicFormComponent), selector: "ui-dynamic-form", inputs: ["fields", "isSubForm", "form", "disabled", "voiceToTextSilenceMs", "cols", "fileUidResolverFn", "selectOptionsResolver"] }] });
3983
+ }
3984
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: UicRepeaterComponent, decorators: [{
3985
+ type: Component,
3986
+ args: [{ selector: 'ui-repeater', standalone: true, imports: [
3987
+ CommonModule,
3988
+ ReactiveFormsModule,
3989
+ UicButtonComponent,
3990
+ forwardRef(() => UicDynamicFormComponent)
3991
+ ], template: "<div class=\"repeater-label\"> {{field.label}} </div>\r\n<div class=\"uic-repeater\" [class.disabled]=\"formArray.disabled\">\r\n @for (group of formArray.controls; track $index) {\r\n <div class=\"uic-repeater-item\">\r\n <div class=\"uic-repeater-item-header\">\r\n <h4 class=\"uic-repeater-item-title\">\r\n {{ field.repeaterItemTitle || field.label || 'Item' }} {{ $index + 1 }}\r\n </h4>\r\n @if (canRemove && !formArray.disabled) {\r\n <ui-button \r\n [icon]=\"'ri-delete-bin-line'\" \r\n [type]=\"'bordered'\" \r\n [color]=\"'red'\" \r\n size=\"s\" \r\n (click)=\"removeGroup($index)\"\r\n [text]=\"field.repeaterRemoveLabel || 'Eliminar'\">\r\n </ui-button>\r\n }\r\n </div>\r\n <div class=\"uic-repeater-item-body\">\r\n <ui-dynamic-form \r\n [form]=\"getGroup($index)\" \r\n [fields]=\"field.repeaterFields || []\" \r\n [disabled]=\"formArray.disabled\"\r\n [cols]=\"cols\"\r\n [isSubForm]=\"true\">\r\n </ui-dynamic-form>\r\n </div>\r\n </div>\r\n }\r\n \r\n @if (canAdd && !formArray.disabled) {\r\n <div class=\"uic-repeater-add-action\">\r\n <ui-button \r\n [icon]=\"'ri-add-line'\" \r\n [type]=\"'bordered'\" \r\n [color]=\"'primary'\" \r\n (click)=\"addGroup()\"\r\n [text]=\"field.repeaterAddLabel || 'A\u00F1adir'\">\r\n </ui-button>\r\n </div>\r\n }\r\n @if (error) {\r\n <p class=\"uic-repeater-error\">{{ error }}</p>\r\n }\r\n</div>\r\n", styles: [".uic-repeater{display:flex;flex-direction:column;gap:16px;width:100%}.uic-repeater.disabled{opacity:.7;pointer-events:none}.uic-repeater .uic-repeater-item{border:1px solid var(--primary-400, #e0e0e0);border-radius:8px;padding:16px;background-color:var(--uic-bg-color, #fff)}.uic-repeater .uic-repeater-item .uic-repeater-item-header{display:flex;justify-content:space-between;align-items:center;margin-bottom:16px;padding-bottom:12px;border-bottom:1px dashed var(--uic-border-color, #e0e0e0)}.uic-repeater .uic-repeater-item .uic-repeater-item-header .uic-repeater-item-title{margin:0;font-size:14px;font-weight:600;color:var(--uic-text-color, #333)}.uic-repeater .uic-repeater-item .uic-repeater-item-body{width:100%}.uic-repeater .uic-repeater-add-action{margin-top:8px}.uic-repeater .uic-repeater-error{margin:4px 0 0;font-size:12px;color:var(--uic-red, #e53935)}.repeater-label{font-size:max(var(--form-ref) + 4px,14px);line-height:1.125rem;min-height:1.125rem;font-weight:400;color:var(--grey-950);margin-bottom:var(--input-label-space)}\n"] }]
3992
+ }], propDecorators: { formArray: [{
3993
+ type: Input,
3994
+ args: [{ required: true }]
3995
+ }], field: [{
3996
+ type: Input,
3997
+ args: [{ required: true }]
3998
+ }], cols: [{
3999
+ type: Input
4000
+ }], error: [{
4001
+ type: Input
4002
+ }] } });
4003
+
3875
4004
  class UicDynamicFormComponent {
3876
4005
  ngZone;
3877
4006
  fieldsSignal = signal([]);
@@ -3893,9 +4022,9 @@ class UicDynamicFormComponent {
3893
4022
  get fields() {
3894
4023
  return this.fieldsSignal();
3895
4024
  }
4025
+ isSubForm = false;
3896
4026
  set form(value) {
3897
4027
  this.formSignal.set(value);
3898
- this.formState.setForm(value);
3899
4028
  }
3900
4029
  get form() {
3901
4030
  return this.formSignal();
@@ -3930,6 +4059,12 @@ class UicDynamicFormComponent {
3930
4059
  return field.visibilityRules.every(rule => this.matchesVisibilityRule(rule));
3931
4060
  });
3932
4061
  });
4062
+ formSyncEffect = effect(() => {
4063
+ const form = this.formSignal();
4064
+ if (form && !this.isSubForm) {
4065
+ this.formState.setForm(form);
4066
+ }
4067
+ });
3933
4068
  fieldStateSyncEffect = effect(() => {
3934
4069
  this.visibleFieldStates();
3935
4070
  this.syncFieldEnabledState();
@@ -3989,7 +4124,14 @@ class UicDynamicFormComponent {
3989
4124
  const isVisible = visibleNames.has(field.name);
3990
4125
  const wasVisible = this.fieldVisibilityState.get(field.name);
3991
4126
  if (!isVisible && wasVisible) {
3992
- control.setValue(this.getClearValue(field.type), { emitEvent: false });
4127
+ if (field.type === 'repeater') {
4128
+ const arr = control;
4129
+ while (arr.length > 0)
4130
+ arr.removeAt(0, { emitEvent: false });
4131
+ }
4132
+ else {
4133
+ control.setValue(this.getClearValue(field.type), { emitEvent: false });
4134
+ }
3993
4135
  control.markAsPristine();
3994
4136
  control.markAsUntouched();
3995
4137
  }
@@ -4012,7 +4154,7 @@ class UicDynamicFormComponent {
4012
4154
  if (fieldType === 'checkbox' || fieldType === 'switch') {
4013
4155
  return false;
4014
4156
  }
4015
- if (fieldType === 'multyselect') {
4157
+ if (fieldType === 'multyselect' || fieldType === 'repeater') {
4016
4158
  return [];
4017
4159
  }
4018
4160
  return null;
@@ -4167,6 +4309,9 @@ class UicDynamicFormComponent {
4167
4309
  });
4168
4310
  });
4169
4311
  }
4312
+ asFormArray(control) {
4313
+ return control;
4314
+ }
4170
4315
  isListening(fieldName) {
4171
4316
  return this.listeningField === fieldName;
4172
4317
  }
@@ -4188,7 +4333,8 @@ class UicDynamicFormComponent {
4188
4333
  field: field.label ?? field.name,
4189
4334
  requiredLength: err.requiredLength,
4190
4335
  }),
4191
- pattern: (_err, field) => this.i18n.translate('validation.pattern', { field: field.label ?? field.name })
4336
+ pattern: (_err, field) => this.i18n.translate('validation.pattern', { field: field.label ?? field.name }),
4337
+ minLengthArray: (_err, field) => this.i18n.translate('validation.required', { field: field.label ?? field.name })
4192
4338
  };
4193
4339
  getInputColor(field, value) {
4194
4340
  const scale = field.internalColorScale;
@@ -4449,7 +4595,7 @@ class UicDynamicFormComponent {
4449
4595
  recognition.start();
4450
4596
  }
4451
4597
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: UicDynamicFormComponent, deps: [{ token: i0.NgZone }], target: i0.ɵɵFactoryTarget.Component });
4452
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.14", type: UicDynamicFormComponent, isStandalone: true, selector: "ui-dynamic-form", inputs: { fields: "fields", form: "form", disabled: "disabled", voiceToTextSilenceMs: "voiceToTextSilenceMs", cols: "cols", fileUidResolverFn: "fileUidResolverFn", selectOptionsResolver: "selectOptionsResolver" }, ngImport: i0, template: "<div class=\"form\" [ngStyle]=\"{'--cols': cols, '--min': '180px'}\" [formGroup]=\"form\">\r\n @for (state of visibleFieldStates(); track state.field.name) {\r\n @let field = state.field;\r\n @let control = state.control;\r\n @let currentValue = state.value ?? '';\r\n @let error = getControlErrorMessages(control, field)[0];\r\n\r\n <div [style.grid-column]=\"getGridColumn(field)\">\n @if (['text', 'number'].includes(field.type)) {\r\n @let inputColor = getInputColor(field, currentValue);\r\n <ui-input\r\n [error]=\"error\"\r\n [label]=\"field.label + (field.required ? ' *' : '')\"\r\n [icon]=\"field.icon??''\"\r\n [disabled]=\"!!control?.disabled\"\r\n [internalIconColor]=\"inputColor\"\r\n [internalIcon]=\"field.internalIcon || (currentValue !== '' ? getIconByColor(field, inputColor) : '')\"\r\n [loading]=\"field.loading??false\"\r\n [tip]=\"field.tip??''\">\r\n <input #inp\r\n [id]=\"field.name\"\r\n [formControlName]=\"field.name\"\r\n [type]=\"field.type\"\r\n [step]=\"field.step\"\r\n [min]=\"field.min\"\r\n [max]=\"field.max\"\r\n [minLength]=\"field.minLength||null\"\r\n [maxlength]=\"field.maxLength||null\"\r\n [placeholder]=\"field.placeholder??field.label\"/>\r\n @if (field.maxLength && field.showCounter) {\r\n <span counter>{{inp.value.length}} /{{field.maxLength}}</span>\r\n }\r\n </ui-input>\r\n }\r\n @if (field.type === 'textarea') {\r\n <ui-input\r\n [error]=\"error\"\r\n [label]=\"field.label + (field.required ? ' *' : '')\"\r\n [icon]=\"field.icon??''\"\r\n [disabled]=\"!!control?.disabled\"\r\n [internalIconColor]=\"field.internalIconColor??'grey'\"\r\n [internalIcon]=\"field.internalIcon??''\"\r\n [loading]=\"field.loading??false\"\r\n [tip]=\"field.tip??''\">\r\n <textarea #ta\r\n [id]=\"field.name\"\r\n [formControlName]=\"field.name\"\r\n [minLength]=\"field.minLength||null\"\r\n [maxlength]=\"field.maxLength||null\"\r\n [textareaAutoresize]=\"field.textareaResize\"\r\n [textareaAutoresizeMinRows]=\"field.resizeMinRows??1\"\r\n [textareaAutoresizeMaxRows]=\"field.resizeMaxRows??5\"\r\n [rows]=\"field.resizeMinRows??3\"\r\n [placeholder]=\"field.placeholder??field.label\"\r\n ></textarea>\r\n @if (field.voiceToTextEnabled && !control?.disabled) {\r\n @let listening = isListening(field.name);\r\n <div class=\"speak-icon\" (click)=\"ta.focus()\">\r\n <ui-button\r\n [disabled]=\"listening\"\r\n style=\"margin-bottom: 2px;\"\r\n (click)=\"voiceToText(ta, field.name)\"\r\n [icon]=\"listening?'ri-mic-fill':'ri-mic-line'\"\r\n [type]=\"listening?'filled':'bordered'\"\r\n size=\"s\"\r\n [iconOnly]=\"true\"\r\n ></ui-button>\r\n @if (listening) {\r\n <i class=\"ri-voiceprint-line\"></i>\r\n }\r\n </div>\r\n }\r\n @if (field.showCounter) {\r\n <span counter>\r\n {{ta.value.length}}\r\n @if (field.maxLength) {\r\n /{{field.maxLength}}\r\n }\r\n </span>\r\n }\r\n </ui-input>\r\n }\r\n @if (field.type === 'phone') {\r\n <ui-phone-input\r\n [error]=\"error\"\r\n [label]=\"field.label + (field.required ? ' *' : '')\"\r\n [icon]=\"field.icon??''\"\r\n [internalIcon]=\"field.internalIcon??''\"\r\n [internalIconColor]=\"field.internalIconColor??'grey'\"\r\n [loading]=\"field.loading??false\"\r\n [tip]=\"field.tip??''\"\r\n [id]=\"field.name\"\r\n [formControlName]=\"field.name\"\r\n [placeholder]=\"field.placeholder||field.label||''\"\r\n >\r\n </ui-phone-input>\r\n }\r\n @else if (field.type === 'date') {\r\n <ui-date-picker\r\n [error]=\"error\"\r\n [label]=\"field.label + (field.required ? ' *' : '')\"\r\n [id]=\"field.name\"\r\n [icon]=\"field.icon??''\"\r\n [internalIcon]=\"field.internalIcon??''\"\r\n [internalIconColor]=\"field.internalIconColor??'grey'\"\r\n [tip]=\"field.tip??''\"\r\n [justMonth]=\"!!field.monthMode\"\r\n [min]=\"field.minDate??''\"\r\n [max]=\"field.maxDate??''\"\r\n [monthDay]=\"field.monthDay||'first'\"\r\n [formControlName]=\"field.name\"\r\n ></ui-date-picker>\r\n }\r\n @else if (field.type === 'time') {\r\n <ui-time-picker\r\n [error]=\"error\"\r\n [label]=\"field.label + (field.required ? ' *' : '')\"\r\n [id]=\"field.name\"\r\n [icon]=\"field.icon??''\"\r\n [internalIcon]=\"field.internalIcon??''\"\r\n [internalIconColor]=\"field.internalIconColor??'grey'\"\r\n [tip]=\"field.tip??''\"\r\n [interval]=\"field.timeInterval??5\"\r\n [formControlName]=\"field.name\"\r\n ></ui-time-picker>\r\n }\r\n @else if (field.type === 'select') {\r\n <ui-select\r\n [error]=\"error\"\r\n [label]=\"field.label + (field.required ? ' *' : '')\"\r\n [id]=\"field.name\"\r\n [icon]=\"field.icon??''\"\r\n [internalIcon]=\"field.internalIcon??''\"\r\n [internalIconColor]=\"field.internalIconColor??'grey'\"\r\n [loading]=\"field.loading??false\"\r\n [nullable]=\"field.selectNullable??false\"\r\n [searcherEnabled]=\"field.selectSearchEnabled??false\"\r\n [tip]=\"field.tip??''\"\r\n [formControlName]=\"field.name\"\r\n [options]=\"field.options || []\"\r\n ></ui-select>\r\n }\r\n @else if (field.type === 'multyselect') {\r\n <ui-multy-select\r\n [error]=\"error\"\r\n [label]=\"field.label + (field.required ? ' *' : '')\"\r\n [id]=\"field.name\"\r\n [icon]=\"field.icon??''\"\r\n [loading]=\"field.loading??false\"\r\n [internalIcon]=\"field.internalIcon??''\"\r\n [internalIconColor]=\"field.internalIconColor??'grey'\"\r\n [tip]=\"field.tip??''\"\r\n [formControlName]=\"field.name\"\r\n [options]=\"field.options || []\"\r\n ></ui-multy-select>\r\n }\r\n @else if (field.type === 'searcher') {\r\n <ui-searcher\r\n [id]=\"field.name\"\r\n [formControlName]=\"field.name\"\r\n [label]=\"field.label + (field.required ? ' *' : '')\"\r\n [icon]=\"field.icon??''\"\r\n [loading]=\"field.loading??false\"\r\n [tip]=\"field.tip??''\"\r\n [searchFn]=\"getSearcherFn(field)\"\r\n [itemDisplayFn]=\"getSearcherDisplayFn(field)\"\r\n [itemIsEnabledFn]=\"getSearcherIsEnabledFn(field)\"\r\n [placeholder]=\"field.placeholder??'common.search_ellipsis'\"\r\n [error]=\"error\"\r\n ></ui-searcher>\r\n }\r\n @else if (field.type === 'file') {\r\n <ui-file-input\r\n [error]=\"error\"\r\n [label]=\"field.label + (field.required ? ' *' : '')\"\r\n [id]=\"field.name\"\r\n [icon]=\"field.icon??''\"\r\n [loading]=\"field.loading??false\"\r\n [internalIcon]=\"field.internalIcon??''\"\r\n [internalIconColor]=\"field.internalIconColor??'grey'\"\r\n [multy]=\"field.multyEnabled??false\"\n [tip]=\"field.tip??''\"\n [fileTypes]=\"field.fileTypes??null\"\n [fileUidResolverFn]=\"fileUidResolverFn\"\n [formControlName]=\"field.name\"\n ></ui-file-input>\n }\n @else if (['checkbox', 'switch'].includes(field.type)) {\r\n <ui-checkbox\r\n [label]=\"(field.label??'') + (field.required ? ' *' : '')\"\r\n [id]=\"field.name\"\r\n [formControlName]=\"field.name\"\r\n [icon]=\"field.icon??''\"\r\n [placeholder]=\"field.placeholder??''\"\r\n [tip]=\"field.tip??''\"\r\n [type]=\"field.type === 'checkbox' ? 'checkbox' : 'switch'\"\r\n ></ui-checkbox>\r\n }\r\n @else if (field.type === 'radio') {\r\n <ui-radio\r\n [label]=\"field.label + (field.required ? ' *' : '')\"\r\n [id]=\"field.name\"\r\n [formControlName]=\"field.name\"\r\n [icon]=\"field.icon??''\"\r\n [tip]=\"field.tip??''\"\r\n [loading]=\"field.loading??false\"\r\n [error]=\"error\"\r\n [options]=\"field.options || []\"\r\n ></ui-radio>\r\n }\r\n @else if (field.type === 'slider') {\r\n <ui-slider\r\n [min]=\"field.min??0\"\r\n [max]=\"field.max??100\"\r\n [step]=\"field.sliderInterval??1\"\r\n [markerCount]=\"field.sliderMarks??5\"\r\n [id]=\"field.name\"\r\n [formControlName]=\"field.name\"\r\n [icon]=\"field.icon??''\"\r\n [tip]=\"field.tip??''\"\r\n [error]=\"error\"\r\n [label]=\"field.label + (field.required ? ' *' : '')\"\r\n ></ui-slider>\r\n }\r\n @else if (field.type === 'pool') {\r\n <ui-pool-options\r\n [error]=\"error\"\r\n [label]=\"field.label + (field.required ? ' *' : '')\"\r\n [id]=\"field.name\"\r\n [icon]=\"field.icon??''\"\r\n [loading]=\"field.loading??false\"\r\n [multy]=\"field.multyEnabled??false\"\r\n [tip]=\"field.tip??''\"\r\n [listViewTitle]=\"field.poolTitle??'common.selected'\"\r\n [enabledListView]=\"field.poolEnabledListView||false\"\r\n [formControlName]=\"field.name\"\r\n [options]=\"field.options || []\"\r\n ></ui-pool-options>\r\n }\r\n </div>\r\n }\r\n</div>\r\n", styles: [".form{width:100%;display:grid;align-items:stretch;gap:1rem;padding-bottom:.75rem}@media (max-width: 479px){.form{grid-template-columns:1fr}}@media (min-width: 768px){.form{grid-template-columns:repeat(var(--cols),minmax(0,1fr))}}@media (min-width: 480px) and (max-width: 767px){.form{grid-template-columns:repeat(min(var(--cols),2),minmax(0,1fr))}}.form>*{min-width:0}h2{margin-top:1.5rem}.speak-icon{display:flex;width:100%;align-items:center;gap:10px}.speak-icon i{font-size:20px;color:var(--primary-500)}textarea{resize:none}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "component", type: UicDatePickerComponent, selector: "ui-date-picker", inputs: ["icon", "iconColor", "internalIcon", "internalIconColor", "disabled", "label", "error", "tip", "max", "min", "justMonth", "monthDay"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1$1.MaxLengthValidator, selector: "[maxlength][formControlName],[maxlength][formControl],[maxlength][ngModel]", inputs: ["maxlength"] }, { kind: "directive", type: i1$1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1$1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "component", type: UicSliderComponent, selector: "ui-slider", inputs: ["icon", "iconColor", "label", "error", "tip", "min", "max", "step", "markerCount", "disabled", "loading"] }, { kind: "component", type: UicButtonComponent, selector: "ui-button", inputs: ["text", "icon", "rightIcon", "iconOnly", "disabled", "loading", "size", "type", "color"] }, { kind: "component", type: UicPoolOptionsComponent, selector: "ui-pool-options", inputs: ["icon", "iconColor", "size", "label", "error", "tip", "disabled", "loading", "multy", "enabledListView", "listViewTitle", "options"] }, { kind: "component", type: UicTimePickerComponent, selector: "ui-time-picker", inputs: ["icon", "iconColor", "internalIcon", "internalIconColor", "disabled", "label", "error", "tip", "interval"] }, { kind: "component", type: UicRadioComponent, selector: "ui-radio", inputs: ["icon", "iconColor", "label", "error", "tip", "disabled", "loading", "options", "emptyText", "direction"] }, { kind: "component", type: UicSearcherComponent, selector: "ui-searcher", inputs: ["icon", "iconColor", "internalIcon", "size", "label", "error", "tip", "showSubtitle", "disabled", "loading", "minimumSearchLength", "showSelected", "placeholder", "searchFn", "itemDisplayFn", "itemIsEnabledFn", "manualSearch", "stateless"], outputs: ["pickedItem"] }, { kind: "component", type: UicMultySelectComponent, selector: "ui-multy-select", inputs: ["icon", "iconColor", "internalIcon", "internalIconColor", "size", "label", "error", "tip", "showSubtitle", "disabled", "nonSelectedText", "allSelectedText", "loading", "options"] }, { kind: "component", type: UicFileInputComponent, selector: "ui-file-input", inputs: ["icon", "iconColor", "internalIcon", "internalIconColor", "size", "label", "error", "tip", "disabled", "loading", "multy", "fileTypes", "fileUidResolverFn"] }, { kind: "component", type: UicSelectComponent, selector: "ui-select", inputs: ["icon", "iconColor", "internalIcon", "internalIconColor", "size", "label", "error", "tip", "showSubtitle", "disabled", "nonSelectedText", "noneText", "emptyText", "searcherEnabled", "loading", "nullable", "options"] }, { kind: "directive", type: UicTextareaAutoresizeDirective, selector: "[textareaAutoresize]", inputs: ["minRows", "maxRows", "textareaAutoresize"] }, { kind: "directive", type: UicTextareaAutoresizeMinRowsDirective, selector: "[textareaAutoresizeMinRows]", inputs: ["textareaAutoresizeMinRows"] }, { kind: "directive", type: UicTextareaAutoresizeMaxRowsDirective, selector: "[textareaAutoresizeMaxRows]", inputs: ["textareaAutoresizeMaxRows"] }, { kind: "component", type: UicInputComponent, selector: "ui-input", inputs: ["icon", "iconColor", "internalIcon", "internalIconColor", "size", "label", "error", "tip", "disabled", "loading"], outputs: ["clickButton"] }, { kind: "component", type: UicCheckboxComponent, selector: "ui-checkbox", inputs: ["icon", "iconColor", "label", "tip", "type", "placeholder", "loading", "noPadding", "disabled"] }, { kind: "component", type: UicPhoneInputComponent, selector: "ui-phone-input", inputs: ["icon", "iconColor", "internalIcon", "internalIconColor", "size", "label", "error", "tip", "placeholder", "disabled", "loading", "preferredCountries", "flagPath", "countries"] }, { kind: "ngmodule", type: FormsModule }] });
4598
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.14", type: UicDynamicFormComponent, isStandalone: true, selector: "ui-dynamic-form", inputs: { fields: "fields", isSubForm: "isSubForm", form: "form", disabled: "disabled", voiceToTextSilenceMs: "voiceToTextSilenceMs", cols: "cols", fileUidResolverFn: "fileUidResolverFn", selectOptionsResolver: "selectOptionsResolver" }, ngImport: i0, template: "<div class=\"form\" [ngStyle]=\"{'--cols': cols, '--min': '180px'}\" [formGroup]=\"form\">\r\n @for (state of visibleFieldStates(); track state.field.name) {\r\n @let field = state.field;\r\n @let control = state.control;\r\n @let currentValue = state.value ?? '';\r\n @let error = getControlErrorMessages(control, field)[0];\r\n\r\n <div [style.grid-column]=\"getGridColumn(field)\">\r\n @if (['text', 'number'].includes(field.type)) {\r\n @let inputColor = getInputColor(field, currentValue);\r\n <ui-input\r\n [error]=\"error\"\r\n [label]=\"field.label + (field.required ? ' *' : '')\"\r\n [icon]=\"field.icon??''\"\r\n [disabled]=\"!!control?.disabled\"\r\n [internalIconColor]=\"inputColor\"\r\n [internalIcon]=\"field.internalIcon || (currentValue !== '' ? getIconByColor(field, inputColor) : '')\"\r\n [loading]=\"field.loading??false\"\r\n [tip]=\"field.tip??''\">\r\n <input #inp\r\n [id]=\"field.name\"\r\n [formControlName]=\"field.name\"\r\n [type]=\"field.type\"\r\n [step]=\"field.step\"\r\n [min]=\"field.min\"\r\n [max]=\"field.max\"\r\n [minLength]=\"field.minLength||null\"\r\n [maxlength]=\"field.maxLength||null\"\r\n [placeholder]=\"field.placeholder??field.label\"/>\r\n @if (field.maxLength && field.showCounter) {\r\n <span counter>{{inp.value.length}} /{{field.maxLength}}</span>\r\n }\r\n </ui-input>\r\n }\r\n @if (field.type === 'textarea') {\r\n <ui-input\r\n [error]=\"error\"\r\n [label]=\"field.label + (field.required ? ' *' : '')\"\r\n [icon]=\"field.icon??''\"\r\n [disabled]=\"!!control?.disabled\"\r\n [internalIconColor]=\"field.internalIconColor??'grey'\"\r\n [internalIcon]=\"field.internalIcon??''\"\r\n [loading]=\"field.loading??false\"\r\n [tip]=\"field.tip??''\">\r\n <textarea #ta\r\n [id]=\"field.name\"\r\n [formControlName]=\"field.name\"\r\n [minLength]=\"field.minLength||null\"\r\n [maxlength]=\"field.maxLength||null\"\r\n [textareaAutoresize]=\"field.textareaResize\"\r\n [textareaAutoresizeMinRows]=\"field.resizeMinRows??1\"\r\n [textareaAutoresizeMaxRows]=\"field.resizeMaxRows??5\"\r\n [rows]=\"field.resizeMinRows??3\"\r\n [placeholder]=\"field.placeholder??field.label\"\r\n ></textarea>\r\n @if (field.voiceToTextEnabled && !control?.disabled) {\r\n @let listening = isListening(field.name);\r\n <div class=\"speak-icon\" (click)=\"ta.focus()\">\r\n <ui-button\r\n [disabled]=\"listening\"\r\n style=\"margin-bottom: 2px;\"\r\n (click)=\"voiceToText(ta, field.name)\"\r\n [icon]=\"listening?'ri-mic-fill':'ri-mic-line'\"\r\n [type]=\"listening?'filled':'bordered'\"\r\n size=\"s\"\r\n [iconOnly]=\"true\"\r\n ></ui-button>\r\n @if (listening) {\r\n <i class=\"ri-voiceprint-line\"></i>\r\n }\r\n </div>\r\n }\r\n @if (field.showCounter) {\r\n <span counter>\r\n {{ta.value.length}}\r\n @if (field.maxLength) {\r\n /{{field.maxLength}}\r\n }\r\n </span>\r\n }\r\n </ui-input>\r\n }\r\n @if (field.type === 'phone') {\r\n <ui-phone-input\r\n [error]=\"error\"\r\n [label]=\"field.label + (field.required ? ' *' : '')\"\r\n [icon]=\"field.icon??''\"\r\n [internalIcon]=\"field.internalIcon??''\"\r\n [internalIconColor]=\"field.internalIconColor??'grey'\"\r\n [loading]=\"field.loading??false\"\r\n [tip]=\"field.tip??''\"\r\n [id]=\"field.name\"\r\n [formControlName]=\"field.name\"\r\n [placeholder]=\"field.placeholder||field.label||''\"\r\n >\r\n </ui-phone-input>\r\n }\r\n @else if (field.type === 'date') {\r\n <ui-date-picker\r\n [error]=\"error\"\r\n [label]=\"field.label + (field.required ? ' *' : '')\"\r\n [id]=\"field.name\"\r\n [icon]=\"field.icon??''\"\r\n [internalIcon]=\"field.internalIcon??''\"\r\n [internalIconColor]=\"field.internalIconColor??'grey'\"\r\n [tip]=\"field.tip??''\"\r\n [justMonth]=\"!!field.monthMode\"\r\n [min]=\"field.minDate??''\"\r\n [max]=\"field.maxDate??''\"\r\n [monthDay]=\"field.monthDay||'first'\"\r\n [formControlName]=\"field.name\"\r\n ></ui-date-picker>\r\n }\r\n @else if (field.type === 'time') {\r\n <ui-time-picker\r\n [error]=\"error\"\r\n [label]=\"field.label + (field.required ? ' *' : '')\"\r\n [id]=\"field.name\"\r\n [icon]=\"field.icon??''\"\r\n [internalIcon]=\"field.internalIcon??''\"\r\n [internalIconColor]=\"field.internalIconColor??'grey'\"\r\n [tip]=\"field.tip??''\"\r\n [interval]=\"field.timeInterval??5\"\r\n [formControlName]=\"field.name\"\r\n ></ui-time-picker>\r\n }\r\n @else if (field.type === 'select') {\r\n <ui-select\r\n [error]=\"error\"\r\n [label]=\"field.label + (field.required ? ' *' : '')\"\r\n [id]=\"field.name\"\r\n [icon]=\"field.icon??''\"\r\n [internalIcon]=\"field.internalIcon??''\"\r\n [internalIconColor]=\"field.internalIconColor??'grey'\"\r\n [loading]=\"field.loading??false\"\r\n [nullable]=\"field.selectNullable??false\"\r\n [searcherEnabled]=\"field.selectSearchEnabled??false\"\r\n [tip]=\"field.tip??''\"\r\n [formControlName]=\"field.name\"\r\n [options]=\"field.options || []\"\r\n ></ui-select>\r\n }\r\n @else if (field.type === 'multyselect') {\r\n <ui-multy-select\r\n [error]=\"error\"\r\n [label]=\"field.label + (field.required ? ' *' : '')\"\r\n [id]=\"field.name\"\r\n [icon]=\"field.icon??''\"\r\n [loading]=\"field.loading??false\"\r\n [internalIcon]=\"field.internalIcon??''\"\r\n [internalIconColor]=\"field.internalIconColor??'grey'\"\r\n [tip]=\"field.tip??''\"\r\n [formControlName]=\"field.name\"\r\n [options]=\"field.options || []\"\r\n ></ui-multy-select>\r\n }\r\n @else if (field.type === 'searcher') {\r\n <ui-searcher\r\n [id]=\"field.name\"\r\n [formControlName]=\"field.name\"\r\n [label]=\"field.label + (field.required ? ' *' : '')\"\r\n [icon]=\"field.icon??''\"\r\n [loading]=\"field.loading??false\"\r\n [tip]=\"field.tip??''\"\r\n [searchFn]=\"getSearcherFn(field)\"\r\n [itemDisplayFn]=\"getSearcherDisplayFn(field)\"\r\n [itemIsEnabledFn]=\"getSearcherIsEnabledFn(field)\"\r\n [placeholder]=\"field.placeholder??'common.search_ellipsis'\"\r\n [error]=\"error\"\r\n ></ui-searcher>\r\n }\r\n @else if (field.type === 'file') {\r\n <ui-file-input\r\n [error]=\"error\"\r\n [label]=\"field.label + (field.required ? ' *' : '')\"\r\n [id]=\"field.name\"\r\n [icon]=\"field.icon??''\"\r\n [loading]=\"field.loading??false\"\r\n [internalIcon]=\"field.internalIcon??''\"\r\n [internalIconColor]=\"field.internalIconColor??'grey'\"\r\n [multy]=\"field.multyEnabled??false\"\r\n [tip]=\"field.tip??''\"\r\n [fileTypes]=\"field.fileTypes??null\"\r\n [fileUidResolverFn]=\"fileUidResolverFn\"\r\n [formControlName]=\"field.name\"\r\n ></ui-file-input>\r\n }\r\n @else if (['checkbox', 'switch'].includes(field.type)) {\r\n <ui-checkbox\r\n [label]=\"(field.label??'') + (field.required ? ' *' : '')\"\r\n [id]=\"field.name\"\r\n [formControlName]=\"field.name\"\r\n [icon]=\"field.icon??''\"\r\n [placeholder]=\"field.placeholder??''\"\r\n [tip]=\"field.tip??''\"\r\n [type]=\"field.type === 'checkbox' ? 'checkbox' : 'switch'\"\r\n ></ui-checkbox>\r\n }\r\n @else if (field.type === 'radio') {\r\n <ui-radio\r\n [label]=\"field.label + (field.required ? ' *' : '')\"\r\n [id]=\"field.name\"\r\n [formControlName]=\"field.name\"\r\n [icon]=\"field.icon??''\"\r\n [tip]=\"field.tip??''\"\r\n [loading]=\"field.loading??false\"\r\n [error]=\"error\"\r\n [options]=\"field.options || []\"\r\n ></ui-radio>\r\n }\r\n @else if (field.type === 'slider') {\r\n <ui-slider\r\n [min]=\"field.min??0\"\r\n [max]=\"field.max??100\"\r\n [step]=\"field.sliderInterval??1\"\r\n [markerCount]=\"field.sliderMarks??5\"\r\n [id]=\"field.name\"\r\n [formControlName]=\"field.name\"\r\n [icon]=\"field.icon??''\"\r\n [tip]=\"field.tip??''\"\r\n [error]=\"error\"\r\n [label]=\"field.label + (field.required ? ' *' : '')\"\r\n ></ui-slider>\r\n }\r\n @else if (field.type === 'pool') {\r\n <ui-pool-options\r\n [error]=\"error\"\r\n [label]=\"field.label + (field.required ? ' *' : '')\"\r\n [id]=\"field.name\"\r\n [icon]=\"field.icon??''\"\r\n [loading]=\"field.loading??false\"\r\n [multy]=\"field.multyEnabled??false\"\r\n [tip]=\"field.tip??''\"\r\n [listViewTitle]=\"field.poolTitle??'common.selected'\"\r\n [enabledListView]=\"field.poolEnabledListView||false\"\r\n [formControlName]=\"field.name\"\r\n [options]=\"field.options || []\"\r\n ></ui-pool-options>\r\n }\r\n @else if (field.type === 'repeater') {\r\n <ui-repeater\r\n [formArray]=\"asFormArray(control)\"\r\n [field]=\"field\"\r\n [cols]=\"cols\"\r\n [error]=\"error\"\r\n ></ui-repeater>\r\n }\r\n </div>\r\n }\r\n</div>\r\n", styles: [".form{width:100%;display:grid;align-items:stretch;gap:1rem;padding-bottom:.75rem}@media (max-width: 479px){.form{grid-template-columns:1fr}}@media (min-width: 768px){.form{grid-template-columns:repeat(var(--cols),minmax(0,1fr))}}@media (min-width: 480px) and (max-width: 767px){.form{grid-template-columns:repeat(min(var(--cols),2),minmax(0,1fr))}}.form>*{min-width:0}h2{margin-top:1.5rem}.speak-icon{display:flex;width:100%;align-items:center;gap:10px}.speak-icon i{font-size:20px;color:var(--primary-500)}textarea{resize:none}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "component", type: UicDatePickerComponent, selector: "ui-date-picker", inputs: ["icon", "iconColor", "internalIcon", "internalIconColor", "disabled", "label", "error", "tip", "max", "min", "justMonth", "monthDay"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1$1.MaxLengthValidator, selector: "[maxlength][formControlName],[maxlength][formControl],[maxlength][ngModel]", inputs: ["maxlength"] }, { kind: "directive", type: i1$1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1$1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "component", type: UicSliderComponent, selector: "ui-slider", inputs: ["icon", "iconColor", "label", "error", "tip", "min", "max", "step", "markerCount", "disabled", "loading"] }, { kind: "component", type: UicButtonComponent, selector: "ui-button", inputs: ["text", "icon", "rightIcon", "iconOnly", "disabled", "loading", "size", "type", "color"] }, { kind: "component", type: UicPoolOptionsComponent, selector: "ui-pool-options", inputs: ["icon", "iconColor", "size", "label", "error", "tip", "disabled", "loading", "multy", "enabledListView", "listViewTitle", "options"] }, { kind: "component", type: UicTimePickerComponent, selector: "ui-time-picker", inputs: ["icon", "iconColor", "internalIcon", "internalIconColor", "disabled", "label", "error", "tip", "interval"] }, { kind: "component", type: UicRadioComponent, selector: "ui-radio", inputs: ["icon", "iconColor", "label", "error", "tip", "disabled", "loading", "options", "emptyText", "direction"] }, { kind: "component", type: UicSearcherComponent, selector: "ui-searcher", inputs: ["icon", "iconColor", "internalIcon", "size", "label", "error", "tip", "showSubtitle", "disabled", "loading", "minimumSearchLength", "showSelected", "placeholder", "searchFn", "itemDisplayFn", "itemIsEnabledFn", "manualSearch", "stateless"], outputs: ["pickedItem"] }, { kind: "component", type: UicMultySelectComponent, selector: "ui-multy-select", inputs: ["icon", "iconColor", "internalIcon", "internalIconColor", "size", "label", "error", "tip", "showSubtitle", "disabled", "nonSelectedText", "allSelectedText", "loading", "options"] }, { kind: "component", type: UicFileInputComponent, selector: "ui-file-input", inputs: ["icon", "iconColor", "internalIcon", "internalIconColor", "size", "label", "error", "tip", "disabled", "loading", "multy", "fileTypes", "fileUidResolverFn"] }, { kind: "component", type: UicSelectComponent, selector: "ui-select", inputs: ["icon", "iconColor", "internalIcon", "internalIconColor", "size", "label", "error", "tip", "showSubtitle", "disabled", "nonSelectedText", "noneText", "emptyText", "searcherEnabled", "loading", "nullable", "options"] }, { kind: "directive", type: UicTextareaAutoresizeDirective, selector: "[textareaAutoresize]", inputs: ["minRows", "maxRows", "textareaAutoresize"] }, { kind: "directive", type: UicTextareaAutoresizeMinRowsDirective, selector: "[textareaAutoresizeMinRows]", inputs: ["textareaAutoresizeMinRows"] }, { kind: "directive", type: UicTextareaAutoresizeMaxRowsDirective, selector: "[textareaAutoresizeMaxRows]", inputs: ["textareaAutoresizeMaxRows"] }, { kind: "component", type: UicInputComponent, selector: "ui-input", inputs: ["icon", "iconColor", "internalIcon", "internalIconColor", "size", "label", "error", "tip", "disabled", "loading"], outputs: ["clickButton"] }, { kind: "component", type: UicCheckboxComponent, selector: "ui-checkbox", inputs: ["icon", "iconColor", "label", "tip", "type", "placeholder", "loading", "noPadding", "disabled"] }, { kind: "component", type: UicPhoneInputComponent, selector: "ui-phone-input", inputs: ["icon", "iconColor", "internalIcon", "internalIconColor", "size", "label", "error", "tip", "placeholder", "disabled", "loading", "preferredCountries", "flagPath", "countries"] }, { kind: "ngmodule", type: FormsModule }, { kind: "component", type: UicRepeaterComponent, selector: "ui-repeater", inputs: ["formArray", "field", "cols", "error"] }] });
4453
4599
  }
4454
4600
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: UicDynamicFormComponent, decorators: [{
4455
4601
  type: Component,
@@ -4472,10 +4618,13 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImpo
4472
4618
  UicInputComponent,
4473
4619
  UicCheckboxComponent,
4474
4620
  UicPhoneInputComponent,
4475
- FormsModule
4476
- ], template: "<div class=\"form\" [ngStyle]=\"{'--cols': cols, '--min': '180px'}\" [formGroup]=\"form\">\r\n @for (state of visibleFieldStates(); track state.field.name) {\r\n @let field = state.field;\r\n @let control = state.control;\r\n @let currentValue = state.value ?? '';\r\n @let error = getControlErrorMessages(control, field)[0];\r\n\r\n <div [style.grid-column]=\"getGridColumn(field)\">\n @if (['text', 'number'].includes(field.type)) {\r\n @let inputColor = getInputColor(field, currentValue);\r\n <ui-input\r\n [error]=\"error\"\r\n [label]=\"field.label + (field.required ? ' *' : '')\"\r\n [icon]=\"field.icon??''\"\r\n [disabled]=\"!!control?.disabled\"\r\n [internalIconColor]=\"inputColor\"\r\n [internalIcon]=\"field.internalIcon || (currentValue !== '' ? getIconByColor(field, inputColor) : '')\"\r\n [loading]=\"field.loading??false\"\r\n [tip]=\"field.tip??''\">\r\n <input #inp\r\n [id]=\"field.name\"\r\n [formControlName]=\"field.name\"\r\n [type]=\"field.type\"\r\n [step]=\"field.step\"\r\n [min]=\"field.min\"\r\n [max]=\"field.max\"\r\n [minLength]=\"field.minLength||null\"\r\n [maxlength]=\"field.maxLength||null\"\r\n [placeholder]=\"field.placeholder??field.label\"/>\r\n @if (field.maxLength && field.showCounter) {\r\n <span counter>{{inp.value.length}} /{{field.maxLength}}</span>\r\n }\r\n </ui-input>\r\n }\r\n @if (field.type === 'textarea') {\r\n <ui-input\r\n [error]=\"error\"\r\n [label]=\"field.label + (field.required ? ' *' : '')\"\r\n [icon]=\"field.icon??''\"\r\n [disabled]=\"!!control?.disabled\"\r\n [internalIconColor]=\"field.internalIconColor??'grey'\"\r\n [internalIcon]=\"field.internalIcon??''\"\r\n [loading]=\"field.loading??false\"\r\n [tip]=\"field.tip??''\">\r\n <textarea #ta\r\n [id]=\"field.name\"\r\n [formControlName]=\"field.name\"\r\n [minLength]=\"field.minLength||null\"\r\n [maxlength]=\"field.maxLength||null\"\r\n [textareaAutoresize]=\"field.textareaResize\"\r\n [textareaAutoresizeMinRows]=\"field.resizeMinRows??1\"\r\n [textareaAutoresizeMaxRows]=\"field.resizeMaxRows??5\"\r\n [rows]=\"field.resizeMinRows??3\"\r\n [placeholder]=\"field.placeholder??field.label\"\r\n ></textarea>\r\n @if (field.voiceToTextEnabled && !control?.disabled) {\r\n @let listening = isListening(field.name);\r\n <div class=\"speak-icon\" (click)=\"ta.focus()\">\r\n <ui-button\r\n [disabled]=\"listening\"\r\n style=\"margin-bottom: 2px;\"\r\n (click)=\"voiceToText(ta, field.name)\"\r\n [icon]=\"listening?'ri-mic-fill':'ri-mic-line'\"\r\n [type]=\"listening?'filled':'bordered'\"\r\n size=\"s\"\r\n [iconOnly]=\"true\"\r\n ></ui-button>\r\n @if (listening) {\r\n <i class=\"ri-voiceprint-line\"></i>\r\n }\r\n </div>\r\n }\r\n @if (field.showCounter) {\r\n <span counter>\r\n {{ta.value.length}}\r\n @if (field.maxLength) {\r\n /{{field.maxLength}}\r\n }\r\n </span>\r\n }\r\n </ui-input>\r\n }\r\n @if (field.type === 'phone') {\r\n <ui-phone-input\r\n [error]=\"error\"\r\n [label]=\"field.label + (field.required ? ' *' : '')\"\r\n [icon]=\"field.icon??''\"\r\n [internalIcon]=\"field.internalIcon??''\"\r\n [internalIconColor]=\"field.internalIconColor??'grey'\"\r\n [loading]=\"field.loading??false\"\r\n [tip]=\"field.tip??''\"\r\n [id]=\"field.name\"\r\n [formControlName]=\"field.name\"\r\n [placeholder]=\"field.placeholder||field.label||''\"\r\n >\r\n </ui-phone-input>\r\n }\r\n @else if (field.type === 'date') {\r\n <ui-date-picker\r\n [error]=\"error\"\r\n [label]=\"field.label + (field.required ? ' *' : '')\"\r\n [id]=\"field.name\"\r\n [icon]=\"field.icon??''\"\r\n [internalIcon]=\"field.internalIcon??''\"\r\n [internalIconColor]=\"field.internalIconColor??'grey'\"\r\n [tip]=\"field.tip??''\"\r\n [justMonth]=\"!!field.monthMode\"\r\n [min]=\"field.minDate??''\"\r\n [max]=\"field.maxDate??''\"\r\n [monthDay]=\"field.monthDay||'first'\"\r\n [formControlName]=\"field.name\"\r\n ></ui-date-picker>\r\n }\r\n @else if (field.type === 'time') {\r\n <ui-time-picker\r\n [error]=\"error\"\r\n [label]=\"field.label + (field.required ? ' *' : '')\"\r\n [id]=\"field.name\"\r\n [icon]=\"field.icon??''\"\r\n [internalIcon]=\"field.internalIcon??''\"\r\n [internalIconColor]=\"field.internalIconColor??'grey'\"\r\n [tip]=\"field.tip??''\"\r\n [interval]=\"field.timeInterval??5\"\r\n [formControlName]=\"field.name\"\r\n ></ui-time-picker>\r\n }\r\n @else if (field.type === 'select') {\r\n <ui-select\r\n [error]=\"error\"\r\n [label]=\"field.label + (field.required ? ' *' : '')\"\r\n [id]=\"field.name\"\r\n [icon]=\"field.icon??''\"\r\n [internalIcon]=\"field.internalIcon??''\"\r\n [internalIconColor]=\"field.internalIconColor??'grey'\"\r\n [loading]=\"field.loading??false\"\r\n [nullable]=\"field.selectNullable??false\"\r\n [searcherEnabled]=\"field.selectSearchEnabled??false\"\r\n [tip]=\"field.tip??''\"\r\n [formControlName]=\"field.name\"\r\n [options]=\"field.options || []\"\r\n ></ui-select>\r\n }\r\n @else if (field.type === 'multyselect') {\r\n <ui-multy-select\r\n [error]=\"error\"\r\n [label]=\"field.label + (field.required ? ' *' : '')\"\r\n [id]=\"field.name\"\r\n [icon]=\"field.icon??''\"\r\n [loading]=\"field.loading??false\"\r\n [internalIcon]=\"field.internalIcon??''\"\r\n [internalIconColor]=\"field.internalIconColor??'grey'\"\r\n [tip]=\"field.tip??''\"\r\n [formControlName]=\"field.name\"\r\n [options]=\"field.options || []\"\r\n ></ui-multy-select>\r\n }\r\n @else if (field.type === 'searcher') {\r\n <ui-searcher\r\n [id]=\"field.name\"\r\n [formControlName]=\"field.name\"\r\n [label]=\"field.label + (field.required ? ' *' : '')\"\r\n [icon]=\"field.icon??''\"\r\n [loading]=\"field.loading??false\"\r\n [tip]=\"field.tip??''\"\r\n [searchFn]=\"getSearcherFn(field)\"\r\n [itemDisplayFn]=\"getSearcherDisplayFn(field)\"\r\n [itemIsEnabledFn]=\"getSearcherIsEnabledFn(field)\"\r\n [placeholder]=\"field.placeholder??'common.search_ellipsis'\"\r\n [error]=\"error\"\r\n ></ui-searcher>\r\n }\r\n @else if (field.type === 'file') {\r\n <ui-file-input\r\n [error]=\"error\"\r\n [label]=\"field.label + (field.required ? ' *' : '')\"\r\n [id]=\"field.name\"\r\n [icon]=\"field.icon??''\"\r\n [loading]=\"field.loading??false\"\r\n [internalIcon]=\"field.internalIcon??''\"\r\n [internalIconColor]=\"field.internalIconColor??'grey'\"\r\n [multy]=\"field.multyEnabled??false\"\n [tip]=\"field.tip??''\"\n [fileTypes]=\"field.fileTypes??null\"\n [fileUidResolverFn]=\"fileUidResolverFn\"\n [formControlName]=\"field.name\"\n ></ui-file-input>\n }\n @else if (['checkbox', 'switch'].includes(field.type)) {\r\n <ui-checkbox\r\n [label]=\"(field.label??'') + (field.required ? ' *' : '')\"\r\n [id]=\"field.name\"\r\n [formControlName]=\"field.name\"\r\n [icon]=\"field.icon??''\"\r\n [placeholder]=\"field.placeholder??''\"\r\n [tip]=\"field.tip??''\"\r\n [type]=\"field.type === 'checkbox' ? 'checkbox' : 'switch'\"\r\n ></ui-checkbox>\r\n }\r\n @else if (field.type === 'radio') {\r\n <ui-radio\r\n [label]=\"field.label + (field.required ? ' *' : '')\"\r\n [id]=\"field.name\"\r\n [formControlName]=\"field.name\"\r\n [icon]=\"field.icon??''\"\r\n [tip]=\"field.tip??''\"\r\n [loading]=\"field.loading??false\"\r\n [error]=\"error\"\r\n [options]=\"field.options || []\"\r\n ></ui-radio>\r\n }\r\n @else if (field.type === 'slider') {\r\n <ui-slider\r\n [min]=\"field.min??0\"\r\n [max]=\"field.max??100\"\r\n [step]=\"field.sliderInterval??1\"\r\n [markerCount]=\"field.sliderMarks??5\"\r\n [id]=\"field.name\"\r\n [formControlName]=\"field.name\"\r\n [icon]=\"field.icon??''\"\r\n [tip]=\"field.tip??''\"\r\n [error]=\"error\"\r\n [label]=\"field.label + (field.required ? ' *' : '')\"\r\n ></ui-slider>\r\n }\r\n @else if (field.type === 'pool') {\r\n <ui-pool-options\r\n [error]=\"error\"\r\n [label]=\"field.label + (field.required ? ' *' : '')\"\r\n [id]=\"field.name\"\r\n [icon]=\"field.icon??''\"\r\n [loading]=\"field.loading??false\"\r\n [multy]=\"field.multyEnabled??false\"\r\n [tip]=\"field.tip??''\"\r\n [listViewTitle]=\"field.poolTitle??'common.selected'\"\r\n [enabledListView]=\"field.poolEnabledListView||false\"\r\n [formControlName]=\"field.name\"\r\n [options]=\"field.options || []\"\r\n ></ui-pool-options>\r\n }\r\n </div>\r\n }\r\n</div>\r\n", styles: [".form{width:100%;display:grid;align-items:stretch;gap:1rem;padding-bottom:.75rem}@media (max-width: 479px){.form{grid-template-columns:1fr}}@media (min-width: 768px){.form{grid-template-columns:repeat(var(--cols),minmax(0,1fr))}}@media (min-width: 480px) and (max-width: 767px){.form{grid-template-columns:repeat(min(var(--cols),2),minmax(0,1fr))}}.form>*{min-width:0}h2{margin-top:1.5rem}.speak-icon{display:flex;width:100%;align-items:center;gap:10px}.speak-icon i{font-size:20px;color:var(--primary-500)}textarea{resize:none}\n"] }]
4621
+ FormsModule,
4622
+ UicRepeaterComponent
4623
+ ], template: "<div class=\"form\" [ngStyle]=\"{'--cols': cols, '--min': '180px'}\" [formGroup]=\"form\">\r\n @for (state of visibleFieldStates(); track state.field.name) {\r\n @let field = state.field;\r\n @let control = state.control;\r\n @let currentValue = state.value ?? '';\r\n @let error = getControlErrorMessages(control, field)[0];\r\n\r\n <div [style.grid-column]=\"getGridColumn(field)\">\r\n @if (['text', 'number'].includes(field.type)) {\r\n @let inputColor = getInputColor(field, currentValue);\r\n <ui-input\r\n [error]=\"error\"\r\n [label]=\"field.label + (field.required ? ' *' : '')\"\r\n [icon]=\"field.icon??''\"\r\n [disabled]=\"!!control?.disabled\"\r\n [internalIconColor]=\"inputColor\"\r\n [internalIcon]=\"field.internalIcon || (currentValue !== '' ? getIconByColor(field, inputColor) : '')\"\r\n [loading]=\"field.loading??false\"\r\n [tip]=\"field.tip??''\">\r\n <input #inp\r\n [id]=\"field.name\"\r\n [formControlName]=\"field.name\"\r\n [type]=\"field.type\"\r\n [step]=\"field.step\"\r\n [min]=\"field.min\"\r\n [max]=\"field.max\"\r\n [minLength]=\"field.minLength||null\"\r\n [maxlength]=\"field.maxLength||null\"\r\n [placeholder]=\"field.placeholder??field.label\"/>\r\n @if (field.maxLength && field.showCounter) {\r\n <span counter>{{inp.value.length}} /{{field.maxLength}}</span>\r\n }\r\n </ui-input>\r\n }\r\n @if (field.type === 'textarea') {\r\n <ui-input\r\n [error]=\"error\"\r\n [label]=\"field.label + (field.required ? ' *' : '')\"\r\n [icon]=\"field.icon??''\"\r\n [disabled]=\"!!control?.disabled\"\r\n [internalIconColor]=\"field.internalIconColor??'grey'\"\r\n [internalIcon]=\"field.internalIcon??''\"\r\n [loading]=\"field.loading??false\"\r\n [tip]=\"field.tip??''\">\r\n <textarea #ta\r\n [id]=\"field.name\"\r\n [formControlName]=\"field.name\"\r\n [minLength]=\"field.minLength||null\"\r\n [maxlength]=\"field.maxLength||null\"\r\n [textareaAutoresize]=\"field.textareaResize\"\r\n [textareaAutoresizeMinRows]=\"field.resizeMinRows??1\"\r\n [textareaAutoresizeMaxRows]=\"field.resizeMaxRows??5\"\r\n [rows]=\"field.resizeMinRows??3\"\r\n [placeholder]=\"field.placeholder??field.label\"\r\n ></textarea>\r\n @if (field.voiceToTextEnabled && !control?.disabled) {\r\n @let listening = isListening(field.name);\r\n <div class=\"speak-icon\" (click)=\"ta.focus()\">\r\n <ui-button\r\n [disabled]=\"listening\"\r\n style=\"margin-bottom: 2px;\"\r\n (click)=\"voiceToText(ta, field.name)\"\r\n [icon]=\"listening?'ri-mic-fill':'ri-mic-line'\"\r\n [type]=\"listening?'filled':'bordered'\"\r\n size=\"s\"\r\n [iconOnly]=\"true\"\r\n ></ui-button>\r\n @if (listening) {\r\n <i class=\"ri-voiceprint-line\"></i>\r\n }\r\n </div>\r\n }\r\n @if (field.showCounter) {\r\n <span counter>\r\n {{ta.value.length}}\r\n @if (field.maxLength) {\r\n /{{field.maxLength}}\r\n }\r\n </span>\r\n }\r\n </ui-input>\r\n }\r\n @if (field.type === 'phone') {\r\n <ui-phone-input\r\n [error]=\"error\"\r\n [label]=\"field.label + (field.required ? ' *' : '')\"\r\n [icon]=\"field.icon??''\"\r\n [internalIcon]=\"field.internalIcon??''\"\r\n [internalIconColor]=\"field.internalIconColor??'grey'\"\r\n [loading]=\"field.loading??false\"\r\n [tip]=\"field.tip??''\"\r\n [id]=\"field.name\"\r\n [formControlName]=\"field.name\"\r\n [placeholder]=\"field.placeholder||field.label||''\"\r\n >\r\n </ui-phone-input>\r\n }\r\n @else if (field.type === 'date') {\r\n <ui-date-picker\r\n [error]=\"error\"\r\n [label]=\"field.label + (field.required ? ' *' : '')\"\r\n [id]=\"field.name\"\r\n [icon]=\"field.icon??''\"\r\n [internalIcon]=\"field.internalIcon??''\"\r\n [internalIconColor]=\"field.internalIconColor??'grey'\"\r\n [tip]=\"field.tip??''\"\r\n [justMonth]=\"!!field.monthMode\"\r\n [min]=\"field.minDate??''\"\r\n [max]=\"field.maxDate??''\"\r\n [monthDay]=\"field.monthDay||'first'\"\r\n [formControlName]=\"field.name\"\r\n ></ui-date-picker>\r\n }\r\n @else if (field.type === 'time') {\r\n <ui-time-picker\r\n [error]=\"error\"\r\n [label]=\"field.label + (field.required ? ' *' : '')\"\r\n [id]=\"field.name\"\r\n [icon]=\"field.icon??''\"\r\n [internalIcon]=\"field.internalIcon??''\"\r\n [internalIconColor]=\"field.internalIconColor??'grey'\"\r\n [tip]=\"field.tip??''\"\r\n [interval]=\"field.timeInterval??5\"\r\n [formControlName]=\"field.name\"\r\n ></ui-time-picker>\r\n }\r\n @else if (field.type === 'select') {\r\n <ui-select\r\n [error]=\"error\"\r\n [label]=\"field.label + (field.required ? ' *' : '')\"\r\n [id]=\"field.name\"\r\n [icon]=\"field.icon??''\"\r\n [internalIcon]=\"field.internalIcon??''\"\r\n [internalIconColor]=\"field.internalIconColor??'grey'\"\r\n [loading]=\"field.loading??false\"\r\n [nullable]=\"field.selectNullable??false\"\r\n [searcherEnabled]=\"field.selectSearchEnabled??false\"\r\n [tip]=\"field.tip??''\"\r\n [formControlName]=\"field.name\"\r\n [options]=\"field.options || []\"\r\n ></ui-select>\r\n }\r\n @else if (field.type === 'multyselect') {\r\n <ui-multy-select\r\n [error]=\"error\"\r\n [label]=\"field.label + (field.required ? ' *' : '')\"\r\n [id]=\"field.name\"\r\n [icon]=\"field.icon??''\"\r\n [loading]=\"field.loading??false\"\r\n [internalIcon]=\"field.internalIcon??''\"\r\n [internalIconColor]=\"field.internalIconColor??'grey'\"\r\n [tip]=\"field.tip??''\"\r\n [formControlName]=\"field.name\"\r\n [options]=\"field.options || []\"\r\n ></ui-multy-select>\r\n }\r\n @else if (field.type === 'searcher') {\r\n <ui-searcher\r\n [id]=\"field.name\"\r\n [formControlName]=\"field.name\"\r\n [label]=\"field.label + (field.required ? ' *' : '')\"\r\n [icon]=\"field.icon??''\"\r\n [loading]=\"field.loading??false\"\r\n [tip]=\"field.tip??''\"\r\n [searchFn]=\"getSearcherFn(field)\"\r\n [itemDisplayFn]=\"getSearcherDisplayFn(field)\"\r\n [itemIsEnabledFn]=\"getSearcherIsEnabledFn(field)\"\r\n [placeholder]=\"field.placeholder??'common.search_ellipsis'\"\r\n [error]=\"error\"\r\n ></ui-searcher>\r\n }\r\n @else if (field.type === 'file') {\r\n <ui-file-input\r\n [error]=\"error\"\r\n [label]=\"field.label + (field.required ? ' *' : '')\"\r\n [id]=\"field.name\"\r\n [icon]=\"field.icon??''\"\r\n [loading]=\"field.loading??false\"\r\n [internalIcon]=\"field.internalIcon??''\"\r\n [internalIconColor]=\"field.internalIconColor??'grey'\"\r\n [multy]=\"field.multyEnabled??false\"\r\n [tip]=\"field.tip??''\"\r\n [fileTypes]=\"field.fileTypes??null\"\r\n [fileUidResolverFn]=\"fileUidResolverFn\"\r\n [formControlName]=\"field.name\"\r\n ></ui-file-input>\r\n }\r\n @else if (['checkbox', 'switch'].includes(field.type)) {\r\n <ui-checkbox\r\n [label]=\"(field.label??'') + (field.required ? ' *' : '')\"\r\n [id]=\"field.name\"\r\n [formControlName]=\"field.name\"\r\n [icon]=\"field.icon??''\"\r\n [placeholder]=\"field.placeholder??''\"\r\n [tip]=\"field.tip??''\"\r\n [type]=\"field.type === 'checkbox' ? 'checkbox' : 'switch'\"\r\n ></ui-checkbox>\r\n }\r\n @else if (field.type === 'radio') {\r\n <ui-radio\r\n [label]=\"field.label + (field.required ? ' *' : '')\"\r\n [id]=\"field.name\"\r\n [formControlName]=\"field.name\"\r\n [icon]=\"field.icon??''\"\r\n [tip]=\"field.tip??''\"\r\n [loading]=\"field.loading??false\"\r\n [error]=\"error\"\r\n [options]=\"field.options || []\"\r\n ></ui-radio>\r\n }\r\n @else if (field.type === 'slider') {\r\n <ui-slider\r\n [min]=\"field.min??0\"\r\n [max]=\"field.max??100\"\r\n [step]=\"field.sliderInterval??1\"\r\n [markerCount]=\"field.sliderMarks??5\"\r\n [id]=\"field.name\"\r\n [formControlName]=\"field.name\"\r\n [icon]=\"field.icon??''\"\r\n [tip]=\"field.tip??''\"\r\n [error]=\"error\"\r\n [label]=\"field.label + (field.required ? ' *' : '')\"\r\n ></ui-slider>\r\n }\r\n @else if (field.type === 'pool') {\r\n <ui-pool-options\r\n [error]=\"error\"\r\n [label]=\"field.label + (field.required ? ' *' : '')\"\r\n [id]=\"field.name\"\r\n [icon]=\"field.icon??''\"\r\n [loading]=\"field.loading??false\"\r\n [multy]=\"field.multyEnabled??false\"\r\n [tip]=\"field.tip??''\"\r\n [listViewTitle]=\"field.poolTitle??'common.selected'\"\r\n [enabledListView]=\"field.poolEnabledListView||false\"\r\n [formControlName]=\"field.name\"\r\n [options]=\"field.options || []\"\r\n ></ui-pool-options>\r\n }\r\n @else if (field.type === 'repeater') {\r\n <ui-repeater\r\n [formArray]=\"asFormArray(control)\"\r\n [field]=\"field\"\r\n [cols]=\"cols\"\r\n [error]=\"error\"\r\n ></ui-repeater>\r\n }\r\n </div>\r\n }\r\n</div>\r\n", styles: [".form{width:100%;display:grid;align-items:stretch;gap:1rem;padding-bottom:.75rem}@media (max-width: 479px){.form{grid-template-columns:1fr}}@media (min-width: 768px){.form{grid-template-columns:repeat(var(--cols),minmax(0,1fr))}}@media (min-width: 480px) and (max-width: 767px){.form{grid-template-columns:repeat(min(var(--cols),2),minmax(0,1fr))}}.form>*{min-width:0}h2{margin-top:1.5rem}.speak-icon{display:flex;width:100%;align-items:center;gap:10px}.speak-icon i{font-size:20px;color:var(--primary-500)}textarea{resize:none}\n"] }]
4477
4624
  }], ctorParameters: () => [{ type: i0.NgZone }], propDecorators: { fields: [{
4478
4625
  type: Input
4626
+ }], isSubForm: [{
4627
+ type: Input
4479
4628
  }], form: [{
4480
4629
  type: Input,
4481
4630
  args: [{ required: true }]
@@ -4563,10 +4712,12 @@ class UicFormWrapperComponent {
4563
4712
  buildForm() {
4564
4713
  this.formValueSub?.unsubscribe();
4565
4714
  this.formValueSub = null;
4566
- const fields = this.collectAllFields();
4567
- const numericFields = fields.filter(field => field.type === 'number');
4715
+ const allFields = this.collectAllFields();
4716
+ const regularFields = allFields.filter(field => field.type !== 'repeater');
4717
+ const repeaterFields = allFields.filter(field => field.type === 'repeater');
4718
+ const numericFields = regularFields.filter(field => field.type === 'number');
4568
4719
  const newForm = this.fb.group({});
4569
- fields.forEach(field => {
4720
+ regularFields.forEach(field => {
4570
4721
  const validators = this.mapValidatorsFromField(field);
4571
4722
  const initial = this.normalizeFieldValue(field, this.newFieldInitialValue(field, true));
4572
4723
  const controlState = {
@@ -4575,6 +4726,25 @@ class UicFormWrapperComponent {
4575
4726
  };
4576
4727
  newForm.addControl(field.name, this.fb.control(controlState, validators));
4577
4728
  });
4729
+ repeaterFields.forEach(field => {
4730
+ const arrayValidators = field.required
4731
+ ? [this.repeaterArrayValidator(field.repeaterMinItems ?? 1)]
4732
+ : [];
4733
+ const formArray = new FormArray([], arrayValidators);
4734
+ const initialItems = this.initialValues?.[field.name];
4735
+ if (Array.isArray(initialItems) && initialItems.length > 0) {
4736
+ initialItems.forEach(itemValues => {
4737
+ formArray.push(this.buildRepeaterGroup(field, itemValues), { emitEvent: false });
4738
+ });
4739
+ }
4740
+ else {
4741
+ const min = field.repeaterMinItems ?? 0;
4742
+ for (let i = 0; i < min; i++) {
4743
+ formArray.push(this.buildRepeaterGroup(field, {}), { emitEvent: false });
4744
+ }
4745
+ }
4746
+ newForm.addControl(field.name, formArray);
4747
+ });
4578
4748
  this.formValueSub = newForm.valueChanges.subscribe(() => {
4579
4749
  this.normalizeNumericControls(newForm, numericFields);
4580
4750
  this.handleFormChange();
@@ -4585,6 +4755,21 @@ class UicFormWrapperComponent {
4585
4755
  this.updateDisabledState();
4586
4756
  this.focusConfiguredField();
4587
4757
  }
4758
+ buildRepeaterGroup(field, values = {}) {
4759
+ const group = this.fb.group({});
4760
+ (field.repeaterFields ?? []).forEach(subField => {
4761
+ const validators = this.mapValidatorsFromField(subField);
4762
+ const value = values[subField.name] ?? this.blankValue(subField);
4763
+ group.addControl(subField.name, this.fb.control({ value, disabled: this.disabled || !!subField.disabled }, validators));
4764
+ });
4765
+ return group;
4766
+ }
4767
+ repeaterArrayValidator(min) {
4768
+ return (control) => {
4769
+ const arr = control;
4770
+ return arr.length >= min ? null : { minLengthArray: { required: min, actual: arr.length } };
4771
+ };
4772
+ }
4588
4773
  focusConfiguredField() {
4589
4774
  if (!this.focusFieldName || this.hasFocusedCurrentTrigger)
4590
4775
  return;
@@ -4627,6 +4812,20 @@ class UicFormWrapperComponent {
4627
4812
  }
4628
4813
  for (const block of this.effectiveSchema.blocks) {
4629
4814
  block.fields = this.updateFieldOptions(block);
4815
+ block.fields = block.fields.map(field => {
4816
+ if (field.type !== 'repeater' || !field.repeaterFields?.length)
4817
+ return field;
4818
+ const namespace = this.externalData[field.name];
4819
+ if (!namespace || typeof namespace !== 'object' || Array.isArray(namespace))
4820
+ return field;
4821
+ const updatedRepeaterFields = field.repeaterFields.map(subField => {
4822
+ if (subField.type !== 'select' && subField.type !== 'pool' && subField.type !== 'multyselect')
4823
+ return subField;
4824
+ const subOptions = namespace[subField.name];
4825
+ return Array.isArray(subOptions) ? { ...subField, options: subOptions } : subField;
4826
+ });
4827
+ return { ...field, repeaterFields: updatedRepeaterFields };
4828
+ });
4630
4829
  }
4631
4830
  }
4632
4831
  mapValidatorsFromField(field) {
@@ -4674,6 +4873,16 @@ class UicFormWrapperComponent {
4674
4873
  updateOptionsSources(force = false) {
4675
4874
  const fields = this.collectAllFields().filter(field => this.hasUsableOptionsSource(field));
4676
4875
  const fieldNames = new Set(fields.map(field => field.name));
4876
+ for (const block of this.effectiveSchema?.blocks ?? []) {
4877
+ for (const f of block.fields) {
4878
+ if (f.type === 'repeater' && f.repeaterFields?.length) {
4879
+ f.repeaterFields.forEach(sf => {
4880
+ if (this.hasUsableOptionsSource(sf))
4881
+ fieldNames.add(`${f.name}__${sf.name}`);
4882
+ });
4883
+ }
4884
+ }
4885
+ }
4677
4886
  for (const fieldName of this.optionSourceSubs.keys()) {
4678
4887
  if (!fieldNames.has(fieldName)) {
4679
4888
  this.optionSourceSubs.get(fieldName)?.unsubscribe();
@@ -4682,6 +4891,80 @@ class UicFormWrapperComponent {
4682
4891
  }
4683
4892
  }
4684
4893
  fields.forEach(field => this.resolveOptionsSourceField(field, force));
4894
+ this.updateRepeaterSubFieldOptionsSources(force);
4895
+ }
4896
+ updateRepeaterSubFieldOptionsSources(force = false) {
4897
+ if (!this.effectiveSchema?.blocks?.length)
4898
+ return;
4899
+ for (const block of this.effectiveSchema.blocks) {
4900
+ for (const field of block.fields) {
4901
+ if (field.type !== 'repeater' || !field.repeaterFields?.length)
4902
+ continue;
4903
+ field.repeaterFields.forEach(subField => {
4904
+ if (this.hasUsableOptionsSource(subField)) {
4905
+ this.resolveRepeaterSubFieldOptionsSource(field, subField, force);
4906
+ }
4907
+ });
4908
+ }
4909
+ }
4910
+ }
4911
+ resolveRepeaterSubFieldOptionsSource(parentField, subField, force = false) {
4912
+ const source = subField.optionsSource;
4913
+ const subFieldKey = `${parentField.name}__${subField.name}`;
4914
+ if (!this.selectOptionsResolver) {
4915
+ this.updateRepeaterSubFieldOptionsState(parentField.name, subField.name, {
4916
+ options: subField.options ?? [],
4917
+ loading: false
4918
+ });
4919
+ return;
4920
+ }
4921
+ if (!force && this.optionSourceSubs.has(subFieldKey))
4922
+ return;
4923
+ this.optionSourceSubs.get(subFieldKey)?.unsubscribe();
4924
+ this.updateRepeaterSubFieldOptionsState(parentField.name, subField.name, { loading: true });
4925
+ const values = this.toNestedValues(this.form?.getRawValue?.() ?? {});
4926
+ let optionsResult;
4927
+ try {
4928
+ optionsResult = this.selectOptionsResolver(source, { field: subField, values, dependencyValue: undefined });
4929
+ }
4930
+ catch (error) {
4931
+ this.handleOptionsSourceError(subField, source, error);
4932
+ return;
4933
+ }
4934
+ const sub = this.toObservable(optionsResult).subscribe({
4935
+ next: items => {
4936
+ const options = this.mapOptionsSourceItems(items, source);
4937
+ this.updateRepeaterSubFieldOptionsState(parentField.name, subField.name, { options, loading: false });
4938
+ },
4939
+ error: (error) => this.handleOptionsSourceError(subField, source, error),
4940
+ complete: () => this.updateRepeaterSubFieldOptionsState(parentField.name, subField.name, { loading: false })
4941
+ });
4942
+ this.optionSourceSubs.set(subFieldKey, sub);
4943
+ }
4944
+ updateRepeaterSubFieldOptionsState(repeaterFieldName, subFieldName, values) {
4945
+ if (!this.effectiveSchema?.blocks?.length)
4946
+ return;
4947
+ for (const block of this.effectiveSchema.blocks) {
4948
+ const repeaterIdx = block.fields.findIndex(f => f.name === repeaterFieldName);
4949
+ if (repeaterIdx === -1)
4950
+ continue;
4951
+ const repeaterField = block.fields[repeaterIdx];
4952
+ if (!repeaterField.repeaterFields)
4953
+ continue;
4954
+ const subIdx = repeaterField.repeaterFields.findIndex(sf => sf.name === subFieldName);
4955
+ if (subIdx === -1)
4956
+ continue;
4957
+ const updatedRepeaterFields = [...repeaterField.repeaterFields];
4958
+ updatedRepeaterFields[subIdx] = {
4959
+ ...updatedRepeaterFields[subIdx],
4960
+ ...(values.options !== undefined ? { options: values.options } : {}),
4961
+ ...(values.loading !== undefined ? { loading: values.loading } : {})
4962
+ };
4963
+ block.fields[repeaterIdx] = { ...repeaterField, repeaterFields: updatedRepeaterFields };
4964
+ block.fields = [...block.fields];
4965
+ this.effectiveSchema.blocks = [...this.effectiveSchema.blocks];
4966
+ return;
4967
+ }
4685
4968
  }
4686
4969
  updateDependentOptionsSources() {
4687
4970
  const fields = this.collectAllFields().filter(field => {
@@ -4925,12 +5208,28 @@ class UicFormWrapperComponent {
4925
5208
  return;
4926
5209
  const fields = this.collectAllFields();
4927
5210
  const fieldMap = new Map(fields.map(field => [field.name, field]));
4928
- const resetValues = {};
4929
5211
  Object.keys(this.form.controls).forEach(name => {
4930
5212
  const field = fieldMap.get(name);
4931
- resetValues[name] = this.resolveResetValue(name, field, hardReset);
5213
+ const control = this.form.get([name]);
5214
+ if (!control)
5215
+ return;
5216
+ if (field?.type === 'repeater') {
5217
+ const formArray = control;
5218
+ while (formArray.length > 0) {
5219
+ formArray.removeAt(0, { emitEvent: false });
5220
+ }
5221
+ const min = field.repeaterMinItems ?? 0;
5222
+ for (let i = 0; i < min; i++) {
5223
+ formArray.push(this.buildRepeaterGroup(field, {}), { emitEvent: false });
5224
+ }
5225
+ formArray.markAsPristine();
5226
+ formArray.markAsUntouched();
5227
+ }
5228
+ else {
5229
+ const resetValue = this.resolveResetValue(name, field, hardReset);
5230
+ control.reset(resetValue, { emitEvent: false });
5231
+ }
4932
5232
  });
4933
- this.form.reset(resetValues, { emitEvent: false });
4934
5233
  this.handleFormChange();
4935
5234
  }
4936
5235
  addFieldControl(field, after) {
@@ -5121,7 +5420,7 @@ class UicFormWrapperComponent {
5121
5420
  };
5122
5421
  }
5123
5422
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: UicFormWrapperComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
5124
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.14", type: UicFormWrapperComponent, isStandalone: true, selector: "ui-form-wrapper", inputs: { schema: "schema", fields: "fields", cols: "cols", externalData: "externalData", selectOptionsResolver: "selectOptionsResolver", loading: "loading", disabled: "disabled", showButtons: "showButtons", fillSelects: "fillSelects", initialValues: "initialValues", focusFieldName: "focusFieldName", focusFieldTrigger: "focusFieldTrigger", fileUidResolverFn: "fileUidResolverFn" }, outputs: { formSubmit: "formSubmit", formChange: "formChange", optionsSourceError: "optionsSourceError" }, providers: [UicFormStateService], usesOnChanges: true, ngImport: i0, template: "<form [formGroup]=\"form\" (ngSubmit)=\"handleSubmit()\">\r\n @for (block of effectiveSchema.blocks; track $index) {\r\n \r\n <section class=\"form-block\">\r\n @if (block.title){\r\n <div class=\"block-title\">{{ block.title }}</div>\r\n }\r\n @if (block.subtitle){\r\n <div class=\"block-subtitle\">{{ block.subtitle }}</div>\r\n }\r\n @if (loading) {\r\n <ui-skeleton-loader\r\n [cols]=\"effectiveSchema.cols\"\r\n [inputs]=\"block.fields.length\"\r\n ></ui-skeleton-loader>\r\n } @else {\r\n <ui-dynamic-form\n [cols]=\"effectiveSchema.cols\"\n [disabled]=\"disabled\"\n [fileUidResolverFn]=\"fileUidResolverFn\"\n [fields]=\"block.fields\"\n [form]=\"form\"\n [selectOptionsResolver]=\"selectOptionsResolver\">\n </ui-dynamic-form>\n }\r\n </section>\r\n }\r\n @if ( showButtons ) {\r\n\r\n <div class=\"form-buttons\">\r\n <ui-button color=\"black\" type=\"bordered\" (click)=\"clean()\">{{'common.clear' | uicTranslate}}</ui-button>\r\n <ui-button color=\"black\" (click)=\"submit()\">{{'common.save' | uicTranslate}}</ui-button>\r\n </div>\r\n }\r\n</form>\r\n", styles: [":host{display:block;padding:.25rem 0}.block-title{font-size:1.625rem;font-weight:600;line-height:calc(1.625rem + 4px);margin:1rem 0;color:var(--grey-950)}.block-subtitle{font-size:1.25rem;font-weight:600;line-height:calc(1.25rem + 4px);margin:.75rem 0;color:var(--grey-950)}.form-buttons{display:flex;gap:10px;width:100%}\n"], dependencies: [{ kind: "component", type: UicDynamicFormComponent, selector: "ui-dynamic-form", inputs: ["fields", "form", "disabled", "voiceToTextSilenceMs", "cols", "fileUidResolverFn", "selectOptionsResolver"] }, { kind: "component", type: UicSkeletonLoaderComponent, selector: "ui-skeleton-loader", inputs: ["inputs", "cols"] }, { kind: "component", type: UicButtonComponent, selector: "ui-button", inputs: ["text", "icon", "rightIcon", "iconOnly", "disabled", "loading", "size", "type", "color"] }, { kind: "pipe", type: UicTranslatePipe, name: "uicTranslate" }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1$1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1$1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }] });
5423
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.14", type: UicFormWrapperComponent, isStandalone: true, selector: "ui-form-wrapper", inputs: { schema: "schema", fields: "fields", cols: "cols", externalData: "externalData", selectOptionsResolver: "selectOptionsResolver", loading: "loading", disabled: "disabled", showButtons: "showButtons", fillSelects: "fillSelects", initialValues: "initialValues", focusFieldName: "focusFieldName", focusFieldTrigger: "focusFieldTrigger", fileUidResolverFn: "fileUidResolverFn" }, outputs: { formSubmit: "formSubmit", formChange: "formChange", optionsSourceError: "optionsSourceError" }, providers: [UicFormStateService], usesOnChanges: true, ngImport: i0, template: "<form [formGroup]=\"form\" (ngSubmit)=\"handleSubmit()\">\r\n @for (block of effectiveSchema.blocks; track $index) {\r\n \r\n <section class=\"form-block\">\r\n @if (block.title){\r\n <div class=\"block-title\">{{ block.title }}</div>\r\n }\r\n @if (block.subtitle){\r\n <div class=\"block-subtitle\">{{ block.subtitle }}</div>\r\n }\r\n @if (loading) {\r\n <ui-skeleton-loader\r\n [cols]=\"effectiveSchema.cols\"\r\n [inputs]=\"block.fields.length\"\r\n ></ui-skeleton-loader>\r\n } @else {\r\n <ui-dynamic-form\n [cols]=\"effectiveSchema.cols\"\n [disabled]=\"disabled\"\n [fileUidResolverFn]=\"fileUidResolverFn\"\n [fields]=\"block.fields\"\n [form]=\"form\"\n [selectOptionsResolver]=\"selectOptionsResolver\">\n </ui-dynamic-form>\n }\r\n </section>\r\n }\r\n @if ( showButtons ) {\r\n\r\n <div class=\"form-buttons\">\r\n <ui-button color=\"black\" type=\"bordered\" (click)=\"clean()\">{{'common.clear' | uicTranslate}}</ui-button>\r\n <ui-button color=\"black\" (click)=\"submit()\">{{'common.save' | uicTranslate}}</ui-button>\r\n </div>\r\n }\r\n</form>\r\n", styles: [":host{display:block;padding:.25rem 0}.block-title{font-size:1.625rem;font-weight:600;line-height:calc(1.625rem + 4px);margin:1rem 0;color:var(--grey-950)}.block-subtitle{font-size:1.25rem;font-weight:600;line-height:calc(1.25rem + 4px);margin:.75rem 0;color:var(--grey-950)}.form-buttons{display:flex;gap:10px;width:100%}\n"], dependencies: [{ kind: "component", type: UicDynamicFormComponent, selector: "ui-dynamic-form", inputs: ["fields", "isSubForm", "form", "disabled", "voiceToTextSilenceMs", "cols", "fileUidResolverFn", "selectOptionsResolver"] }, { kind: "component", type: UicSkeletonLoaderComponent, selector: "ui-skeleton-loader", inputs: ["inputs", "cols"] }, { kind: "component", type: UicButtonComponent, selector: "ui-button", inputs: ["text", "icon", "rightIcon", "iconOnly", "disabled", "loading", "size", "type", "color"] }, { kind: "pipe", type: UicTranslatePipe, name: "uicTranslate" }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1$1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1$1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }] });
5125
5424
  }
5126
5425
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: UicFormWrapperComponent, decorators: [{
5127
5426
  type: Component,
@@ -6499,7 +6798,10 @@ function mapEditableBlocksToBlocks(blocks, editable) {
6499
6798
  ...field.fieldData,
6500
6799
  disabled: !editable,
6501
6800
  optionsSource,
6502
- visibilityRules: visibilityRules ?? field.fieldData.visibilityRules
6801
+ visibilityRules: visibilityRules ?? field.fieldData.visibilityRules,
6802
+ ...(field.repeaterSubFields?.length
6803
+ ? { repeaterFields: field.repeaterSubFields.map(sf => ({ ...sf.fieldData, disabled: !editable })) }
6804
+ : {})
6503
6805
  };
6504
6806
  })
6505
6807
  }));
@@ -8588,7 +8890,8 @@ const FIELDS_CONFIG = [
8588
8890
  { value: 'pool', icon: 'ri-bubble-chart-line', detail: 'Seleccion con lista y detalle por item', label: 'Pool de opciones', properties: ['options', 'multyEnabled', 'poolEnabledListView', 'poolTitle'], visibility: { outputType: 'selectedDetailed[]', operators: ['isEmpty', 'isNotEmpty'] } },
8589
8891
  { value: 'file', icon: 'ri-attachment-line', detail: 'Carga de archivos', label: 'Archivo', properties: ['multyEnabled', 'fileTypes', 'iaValidation', 'iaValidationPrompt'], visibility: { outputType: 'UicFileInputValue[]', operators: ['isEmpty', 'isNotEmpty'] } },
8590
8892
  { value: 'searcher', icon: 'ri-seo-line', detail: 'Buscador con fuente de datos externa', label: 'Buscador', properties: ['placeholder', 'optionsSource.key', 'optionsSource.idField', 'optionsSource.textField', 'optionsSource.textTemplate', 'optionsSource.dependsOn', 'optionsSource.paramName'], visibility: { outputType: 'object', operators: ['isEmpty', 'isNotEmpty'] } },
8591
- { value: 'slider', icon: 'ri-equalizer-2-line', detail: 'Control deslizante continuo', label: 'Deslizador', properties: ['min', 'max', 'sliderInterval', 'sliderMarks'], visibility: { outputType: 'number', operators: ['equals', 'notEquals', 'greaterThan', 'lessThan', 'isEmpty', 'isNotEmpty'] } }
8893
+ { value: 'slider', icon: 'ri-equalizer-2-line', detail: 'Control deslizante continuo', label: 'Deslizador', properties: ['min', 'max', 'sliderInterval', 'sliderMarks'], visibility: { outputType: 'number', operators: ['equals', 'notEquals', 'greaterThan', 'lessThan', 'isEmpty', 'isNotEmpty'] } },
8894
+ { value: 'repeater', icon: 'ri-stack-line', detail: 'Grupo de campos repetibles', label: 'Repetidor', properties: ['repeaterMinItems', 'repeaterMaxItems', 'repeaterAddLabel', 'repeaterRemoveLabel', 'repeaterItemTitle'], visibility: { outputType: 'object[]', operators: ['isEmpty', 'isNotEmpty'] } }
8592
8895
  ];
8593
8896
  const BASE_FORM_FIELDS = [
8594
8897
  {
@@ -9028,6 +9331,42 @@ const EXTRA_FORM_FIELDS = [
9028
9331
  internalIcon: 'ri-folder-add-line',
9029
9332
  tip: 'form_builder.extra.multyEnabled_tip',
9030
9333
  type: 'checkbox'
9334
+ },
9335
+ {
9336
+ name: 'repeaterMinItems',
9337
+ label: 'form_builder.extra.repeaterMinItems',
9338
+ internalIcon: 'ri-skip-down-line',
9339
+ tip: 'form_builder.extra.repeaterMinItems_tip',
9340
+ type: 'number',
9341
+ step: 1,
9342
+ min: 0
9343
+ },
9344
+ {
9345
+ name: 'repeaterMaxItems',
9346
+ label: 'form_builder.extra.repeaterMaxItems',
9347
+ internalIcon: 'ri-skip-up-line',
9348
+ tip: 'form_builder.extra.repeaterMaxItems_tip',
9349
+ type: 'number',
9350
+ step: 1,
9351
+ min: 1
9352
+ },
9353
+ {
9354
+ name: 'repeaterAddLabel',
9355
+ label: 'form_builder.extra.repeaterAddLabel',
9356
+ internalIcon: 'ri-add-circle-line',
9357
+ type: 'text'
9358
+ },
9359
+ {
9360
+ name: 'repeaterRemoveLabel',
9361
+ label: 'form_builder.extra.repeaterRemoveLabel',
9362
+ internalIcon: 'ri-delete-bin-line',
9363
+ type: 'text'
9364
+ },
9365
+ {
9366
+ name: 'repeaterItemTitle',
9367
+ label: 'form_builder.extra.repeaterItemTitle',
9368
+ internalIcon: 'ri-price-tag-2-line',
9369
+ type: 'text'
9031
9370
  }
9032
9371
  ];
9033
9372
  const BRANCH_FORM_FIELDS = [
@@ -9136,8 +9475,10 @@ class FieldEditorComponent {
9136
9475
  return !!fieldType && (fieldType.value === 'searcher' || fieldType.properties.includes('options'));
9137
9476
  });
9138
9477
  hasExternalOptionsSource = computed(() => !!this.localField().optionsSource?.key);
9478
+ isRepeater = computed(() => this.fieldType()?.value === 'repeater');
9139
9479
  config = input.required();
9140
9480
  focusRequiredField = input(false);
9481
+ isSubField = input(false);
9141
9482
  options = input({});
9142
9483
  hiddenSections = signal([]);
9143
9484
  fieldChange = output();
@@ -9416,7 +9757,7 @@ class FieldEditorComponent {
9416
9757
  return operator === 'isEmpty' || operator === 'isNotEmpty';
9417
9758
  }
9418
9759
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: FieldEditorComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
9419
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.14", type: FieldEditorComponent, isStandalone: true, selector: "lib-field-editor", inputs: { config: { classPropertyName: "config", publicName: "config", isSignal: true, isRequired: true, transformFunction: null }, focusRequiredField: { classPropertyName: "focusRequiredField", publicName: "focusRequiredField", isSignal: true, isRequired: false, transformFunction: null }, options: { classPropertyName: "options", publicName: "options", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { fieldChange: "fieldChange" }, ngImport: i0, template: "<div class=\"props-title\">{{'form_builder.field_editor.basic' | uicTranslate}} <i (click)=\"toggleSection('basic')\" class=\"{{hiddenSections().includes('basic') ? 'ri-arrow-down-s-line' : 'ri-arrow-up-s-line'}}\"></i> </div>\n<div class=\"props-inputs\" [class.hidden]=\"hiddenSections().includes('basic')\">\n <ui-form-wrapper\n [fields]=\"requiredFields\" \n [initialValues]=\"initialValues()\"\n [focusFieldName]=\"focusRequiredField() ? 'label' : null\"\n [focusFieldTrigger]=\"focusRequiredField() ? config().code : null\"\n [cols]=\"1\" \n (formChange)=\"updateFieldValues($event)\">\n </ui-form-wrapper>\n @if (hasOptionsSourceConfig()) {\n <ui-form-wrapper\n [fields]=\"optionsSourceFields()\"\n [initialValues]=\"initialValues()\"\n [externalData]=\"options()\"\n [cols]=\"1\"\n (formChange)=\"updateFieldValues($event)\">\n </ui-form-wrapper>\n @if (hasOptions() && !hasExternalOptionsSource()) {\n <ui-field-options-editor [options]=\"localField().options ?? []\" (optionsChange)=\"updateOptions($event)\"></ui-field-options-editor>\n }\n }\n</div>\n\n<div class=\"props-title\">{{'form_builder.field_editor.advanced' | uicTranslate}} <i (click)=\"toggleSection('advanced')\" class=\"{{hiddenSections().includes('advanced') ? 'ri-arrow-down-s-line' : 'ri-arrow-up-s-line'}}\"></i> </div>\n<div class=\"props-inputs\" [class.hidden]=\"hiddenSections().includes('advanced')\">\n <ui-form-wrapper\n [fields]=\"advancedFields()\" \n [initialValues]=\"initialValues()\"\n [cols]=\"1\" \n (formChange)=\"updateFieldValues($event)\">\n </ui-form-wrapper>\n</div>\n\n<div class=\"props-title\">{{'form_builder.field_editor.style' | uicTranslate}} <i (click)=\"toggleSection('style')\" class=\"{{hiddenSections().includes('style') ? 'ri-arrow-down-s-line' : 'ri-arrow-up-s-line'}}\"></i> </div>\n<div class=\"props-inputs\" [class.hidden]=\"hiddenSections().includes('style')\">\n <ui-form-wrapper\n [fields]=\"styleFields()\" \n [initialValues]=\"initialValues()\"\n [cols]=\"1\" \n (formChange)=\"updateFieldValues($event)\"> \n </ui-form-wrapper>\n</div>\n\n<div class=\"props-title\">{{'form_builder.field_editor.dependency_title' | uicTranslate}} <i (click)=\"toggleSection('dependency')\" class=\"{{hiddenSections().includes('dependency') ? 'ri-arrow-down-s-line' : 'ri-arrow-up-s-line'}}\"></i> </div>\n<div class=\"props-inputs\" [class.hidden]=\"hiddenSections().includes('dependency')\">\n @if (localField().visibilityRules ) {\n <p>{{'form_builder.field_editor.dependency_description' | uicTranslate}}</p>\n <ui-form-wrapper\n [fields]=\"branchFields()\" \n [initialValues]=\"branchInitialValues()\"\n [externalData]=\"options()\"\n [cols]=\"1\" \n (formChange)=\"updateRuleValue($event)\">\n </ui-form-wrapper>\n <ui-button color=\"black\" size=\"s\" (click)=\"removeRule()\">{{'form_builder.field_editor.remove_relation' | uicTranslate}}</ui-button>\n }@else {\n <ui-button color=\"black\" size=\"s\" (click)=\"addRule()\">{{'form_builder.field_editor.add_relation' | uicTranslate}}</ui-button>\n }\n</div>\n", styles: [".hidden{display:none}.props-title{font-size:14px;font-weight:600;margin-bottom:8px;background:var(--grey-200);padding:5px;border-radius:5px;display:flex;justify-content:space-between}.props-title i{cursor:pointer}.props-inputs{padding-left:20px;margin-bottom:10px}p{font-size:14px;margin:10px 0;color:var(--yellow-800)}\n"], dependencies: [{ kind: "component", type: UicFormWrapperComponent, selector: "ui-form-wrapper", inputs: ["schema", "fields", "cols", "externalData", "selectOptionsResolver", "loading", "disabled", "showButtons", "fillSelects", "initialValues", "focusFieldName", "focusFieldTrigger", "fileUidResolverFn"], outputs: ["formSubmit", "formChange", "optionsSourceError"] }, { kind: "component", type: UicButtonComponent, selector: "ui-button", inputs: ["text", "icon", "rightIcon", "iconOnly", "disabled", "loading", "size", "type", "color"] }, { kind: "pipe", type: UicTranslatePipe, name: "uicTranslate" }, { kind: "component", type: UicFieldOptionsEditorComponent, selector: "ui-field-options-editor", inputs: ["options"], outputs: ["optionsChange"] }] });
9760
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.14", type: FieldEditorComponent, isStandalone: true, selector: "lib-field-editor", inputs: { config: { classPropertyName: "config", publicName: "config", isSignal: true, isRequired: true, transformFunction: null }, focusRequiredField: { classPropertyName: "focusRequiredField", publicName: "focusRequiredField", isSignal: true, isRequired: false, transformFunction: null }, isSubField: { classPropertyName: "isSubField", publicName: "isSubField", isSignal: true, isRequired: false, transformFunction: null }, options: { classPropertyName: "options", publicName: "options", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { fieldChange: "fieldChange" }, ngImport: i0, template: "<div class=\"props-title\">{{'form_builder.field_editor.basic' | uicTranslate}} <i (click)=\"toggleSection('basic')\" class=\"{{hiddenSections().includes('basic') ? 'ri-arrow-down-s-line' : 'ri-arrow-up-s-line'}}\"></i> </div>\r\n<div class=\"props-inputs\" [class.hidden]=\"hiddenSections().includes('basic')\">\r\n <ui-form-wrapper\r\n [fields]=\"requiredFields\" \r\n [initialValues]=\"initialValues()\"\r\n [focusFieldName]=\"focusRequiredField() ? 'label' : null\"\r\n [focusFieldTrigger]=\"focusRequiredField() ? config().code : null\"\r\n [cols]=\"1\" \r\n (formChange)=\"updateFieldValues($event)\">\r\n </ui-form-wrapper>\r\n @if (hasOptionsSourceConfig()) {\r\n <ui-form-wrapper\r\n [fields]=\"optionsSourceFields()\"\r\n [initialValues]=\"initialValues()\"\r\n [externalData]=\"options()\"\r\n [cols]=\"1\"\r\n (formChange)=\"updateFieldValues($event)\">\r\n </ui-form-wrapper>\r\n @if (hasOptions() && !hasExternalOptionsSource()) {\r\n <ui-field-options-editor [options]=\"localField().options ?? []\" (optionsChange)=\"updateOptions($event)\"></ui-field-options-editor>\r\n }\r\n }\r\n</div>\r\n\r\n<div class=\"props-title\">{{'form_builder.field_editor.advanced' | uicTranslate}} <i (click)=\"toggleSection('advanced')\" class=\"{{hiddenSections().includes('advanced') ? 'ri-arrow-down-s-line' : 'ri-arrow-up-s-line'}}\"></i> </div>\r\n<div class=\"props-inputs\" [class.hidden]=\"hiddenSections().includes('advanced')\">\r\n <ui-form-wrapper\r\n [fields]=\"advancedFields()\" \r\n [initialValues]=\"initialValues()\"\r\n [cols]=\"1\" \r\n (formChange)=\"updateFieldValues($event)\">\r\n </ui-form-wrapper>\r\n</div>\r\n\r\n<div class=\"props-title\">{{'form_builder.field_editor.style' | uicTranslate}} <i (click)=\"toggleSection('style')\" class=\"{{hiddenSections().includes('style') ? 'ri-arrow-down-s-line' : 'ri-arrow-up-s-line'}}\"></i> </div>\r\n<div class=\"props-inputs\" [class.hidden]=\"hiddenSections().includes('style')\">\r\n <ui-form-wrapper\r\n [fields]=\"styleFields()\" \r\n [initialValues]=\"initialValues()\"\r\n [cols]=\"1\" \r\n (formChange)=\"updateFieldValues($event)\"> \r\n </ui-form-wrapper>\r\n</div>\r\n\r\n@if (!isSubField()) {\r\n <div class=\"props-title\">{{'form_builder.field_editor.dependency_title' | uicTranslate}} <i (click)=\"toggleSection('dependency')\" class=\"{{hiddenSections().includes('dependency') ? 'ri-arrow-down-s-line' : 'ri-arrow-up-s-line'}}\"></i> </div>\r\n <div class=\"props-inputs\" [class.hidden]=\"hiddenSections().includes('dependency')\">\r\n @if (localField().visibilityRules ) {\r\n <p>{{'form_builder.field_editor.dependency_description' | uicTranslate}}</p>\r\n <ui-form-wrapper\r\n [fields]=\"branchFields()\" \r\n [initialValues]=\"branchInitialValues()\"\r\n [externalData]=\"options()\"\r\n [cols]=\"1\" \r\n (formChange)=\"updateRuleValue($event)\">\r\n </ui-form-wrapper>\r\n <ui-button color=\"black\" size=\"s\" (click)=\"removeRule()\">{{'form_builder.field_editor.remove_relation' | uicTranslate}}</ui-button>\r\n }@else {\r\n <ui-button color=\"black\" size=\"s\" (click)=\"addRule()\">{{'form_builder.field_editor.add_relation' | uicTranslate}}</ui-button>\r\n }\r\n </div>\r\n}\r\n", styles: [".hidden{display:none}.props-title{font-size:14px;font-weight:600;margin-bottom:8px;background:var(--grey-200);padding:5px;border-radius:5px;display:flex;justify-content:space-between}.props-title i{cursor:pointer}.props-inputs{padding-left:20px;margin-bottom:10px}p{font-size:14px;margin:10px 0;color:var(--yellow-800)}\n"], dependencies: [{ kind: "component", type: UicFormWrapperComponent, selector: "ui-form-wrapper", inputs: ["schema", "fields", "cols", "externalData", "selectOptionsResolver", "loading", "disabled", "showButtons", "fillSelects", "initialValues", "focusFieldName", "focusFieldTrigger", "fileUidResolverFn"], outputs: ["formSubmit", "formChange", "optionsSourceError"] }, { kind: "component", type: UicButtonComponent, selector: "ui-button", inputs: ["text", "icon", "rightIcon", "iconOnly", "disabled", "loading", "size", "type", "color"] }, { kind: "pipe", type: UicTranslatePipe, name: "uicTranslate" }, { kind: "component", type: UicFieldOptionsEditorComponent, selector: "ui-field-options-editor", inputs: ["options"], outputs: ["optionsChange"] }] });
9420
9761
  }
9421
9762
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: FieldEditorComponent, decorators: [{
9422
9763
  type: Component,
@@ -9425,21 +9766,22 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImpo
9425
9766
  UicButtonComponent,
9426
9767
  UicTranslatePipe,
9427
9768
  UicFieldOptionsEditorComponent
9428
- ], template: "<div class=\"props-title\">{{'form_builder.field_editor.basic' | uicTranslate}} <i (click)=\"toggleSection('basic')\" class=\"{{hiddenSections().includes('basic') ? 'ri-arrow-down-s-line' : 'ri-arrow-up-s-line'}}\"></i> </div>\n<div class=\"props-inputs\" [class.hidden]=\"hiddenSections().includes('basic')\">\n <ui-form-wrapper\n [fields]=\"requiredFields\" \n [initialValues]=\"initialValues()\"\n [focusFieldName]=\"focusRequiredField() ? 'label' : null\"\n [focusFieldTrigger]=\"focusRequiredField() ? config().code : null\"\n [cols]=\"1\" \n (formChange)=\"updateFieldValues($event)\">\n </ui-form-wrapper>\n @if (hasOptionsSourceConfig()) {\n <ui-form-wrapper\n [fields]=\"optionsSourceFields()\"\n [initialValues]=\"initialValues()\"\n [externalData]=\"options()\"\n [cols]=\"1\"\n (formChange)=\"updateFieldValues($event)\">\n </ui-form-wrapper>\n @if (hasOptions() && !hasExternalOptionsSource()) {\n <ui-field-options-editor [options]=\"localField().options ?? []\" (optionsChange)=\"updateOptions($event)\"></ui-field-options-editor>\n }\n }\n</div>\n\n<div class=\"props-title\">{{'form_builder.field_editor.advanced' | uicTranslate}} <i (click)=\"toggleSection('advanced')\" class=\"{{hiddenSections().includes('advanced') ? 'ri-arrow-down-s-line' : 'ri-arrow-up-s-line'}}\"></i> </div>\n<div class=\"props-inputs\" [class.hidden]=\"hiddenSections().includes('advanced')\">\n <ui-form-wrapper\n [fields]=\"advancedFields()\" \n [initialValues]=\"initialValues()\"\n [cols]=\"1\" \n (formChange)=\"updateFieldValues($event)\">\n </ui-form-wrapper>\n</div>\n\n<div class=\"props-title\">{{'form_builder.field_editor.style' | uicTranslate}} <i (click)=\"toggleSection('style')\" class=\"{{hiddenSections().includes('style') ? 'ri-arrow-down-s-line' : 'ri-arrow-up-s-line'}}\"></i> </div>\n<div class=\"props-inputs\" [class.hidden]=\"hiddenSections().includes('style')\">\n <ui-form-wrapper\n [fields]=\"styleFields()\" \n [initialValues]=\"initialValues()\"\n [cols]=\"1\" \n (formChange)=\"updateFieldValues($event)\"> \n </ui-form-wrapper>\n</div>\n\n<div class=\"props-title\">{{'form_builder.field_editor.dependency_title' | uicTranslate}} <i (click)=\"toggleSection('dependency')\" class=\"{{hiddenSections().includes('dependency') ? 'ri-arrow-down-s-line' : 'ri-arrow-up-s-line'}}\"></i> </div>\n<div class=\"props-inputs\" [class.hidden]=\"hiddenSections().includes('dependency')\">\n @if (localField().visibilityRules ) {\n <p>{{'form_builder.field_editor.dependency_description' | uicTranslate}}</p>\n <ui-form-wrapper\n [fields]=\"branchFields()\" \n [initialValues]=\"branchInitialValues()\"\n [externalData]=\"options()\"\n [cols]=\"1\" \n (formChange)=\"updateRuleValue($event)\">\n </ui-form-wrapper>\n <ui-button color=\"black\" size=\"s\" (click)=\"removeRule()\">{{'form_builder.field_editor.remove_relation' | uicTranslate}}</ui-button>\n }@else {\n <ui-button color=\"black\" size=\"s\" (click)=\"addRule()\">{{'form_builder.field_editor.add_relation' | uicTranslate}}</ui-button>\n }\n</div>\n", styles: [".hidden{display:none}.props-title{font-size:14px;font-weight:600;margin-bottom:8px;background:var(--grey-200);padding:5px;border-radius:5px;display:flex;justify-content:space-between}.props-title i{cursor:pointer}.props-inputs{padding-left:20px;margin-bottom:10px}p{font-size:14px;margin:10px 0;color:var(--yellow-800)}\n"] }]
9769
+ ], template: "<div class=\"props-title\">{{'form_builder.field_editor.basic' | uicTranslate}} <i (click)=\"toggleSection('basic')\" class=\"{{hiddenSections().includes('basic') ? 'ri-arrow-down-s-line' : 'ri-arrow-up-s-line'}}\"></i> </div>\r\n<div class=\"props-inputs\" [class.hidden]=\"hiddenSections().includes('basic')\">\r\n <ui-form-wrapper\r\n [fields]=\"requiredFields\" \r\n [initialValues]=\"initialValues()\"\r\n [focusFieldName]=\"focusRequiredField() ? 'label' : null\"\r\n [focusFieldTrigger]=\"focusRequiredField() ? config().code : null\"\r\n [cols]=\"1\" \r\n (formChange)=\"updateFieldValues($event)\">\r\n </ui-form-wrapper>\r\n @if (hasOptionsSourceConfig()) {\r\n <ui-form-wrapper\r\n [fields]=\"optionsSourceFields()\"\r\n [initialValues]=\"initialValues()\"\r\n [externalData]=\"options()\"\r\n [cols]=\"1\"\r\n (formChange)=\"updateFieldValues($event)\">\r\n </ui-form-wrapper>\r\n @if (hasOptions() && !hasExternalOptionsSource()) {\r\n <ui-field-options-editor [options]=\"localField().options ?? []\" (optionsChange)=\"updateOptions($event)\"></ui-field-options-editor>\r\n }\r\n }\r\n</div>\r\n\r\n<div class=\"props-title\">{{'form_builder.field_editor.advanced' | uicTranslate}} <i (click)=\"toggleSection('advanced')\" class=\"{{hiddenSections().includes('advanced') ? 'ri-arrow-down-s-line' : 'ri-arrow-up-s-line'}}\"></i> </div>\r\n<div class=\"props-inputs\" [class.hidden]=\"hiddenSections().includes('advanced')\">\r\n <ui-form-wrapper\r\n [fields]=\"advancedFields()\" \r\n [initialValues]=\"initialValues()\"\r\n [cols]=\"1\" \r\n (formChange)=\"updateFieldValues($event)\">\r\n </ui-form-wrapper>\r\n</div>\r\n\r\n<div class=\"props-title\">{{'form_builder.field_editor.style' | uicTranslate}} <i (click)=\"toggleSection('style')\" class=\"{{hiddenSections().includes('style') ? 'ri-arrow-down-s-line' : 'ri-arrow-up-s-line'}}\"></i> </div>\r\n<div class=\"props-inputs\" [class.hidden]=\"hiddenSections().includes('style')\">\r\n <ui-form-wrapper\r\n [fields]=\"styleFields()\" \r\n [initialValues]=\"initialValues()\"\r\n [cols]=\"1\" \r\n (formChange)=\"updateFieldValues($event)\"> \r\n </ui-form-wrapper>\r\n</div>\r\n\r\n@if (!isSubField()) {\r\n <div class=\"props-title\">{{'form_builder.field_editor.dependency_title' | uicTranslate}} <i (click)=\"toggleSection('dependency')\" class=\"{{hiddenSections().includes('dependency') ? 'ri-arrow-down-s-line' : 'ri-arrow-up-s-line'}}\"></i> </div>\r\n <div class=\"props-inputs\" [class.hidden]=\"hiddenSections().includes('dependency')\">\r\n @if (localField().visibilityRules ) {\r\n <p>{{'form_builder.field_editor.dependency_description' | uicTranslate}}</p>\r\n <ui-form-wrapper\r\n [fields]=\"branchFields()\" \r\n [initialValues]=\"branchInitialValues()\"\r\n [externalData]=\"options()\"\r\n [cols]=\"1\" \r\n (formChange)=\"updateRuleValue($event)\">\r\n </ui-form-wrapper>\r\n <ui-button color=\"black\" size=\"s\" (click)=\"removeRule()\">{{'form_builder.field_editor.remove_relation' | uicTranslate}}</ui-button>\r\n }@else {\r\n <ui-button color=\"black\" size=\"s\" (click)=\"addRule()\">{{'form_builder.field_editor.add_relation' | uicTranslate}}</ui-button>\r\n }\r\n </div>\r\n}\r\n", styles: [".hidden{display:none}.props-title{font-size:14px;font-weight:600;margin-bottom:8px;background:var(--grey-200);padding:5px;border-radius:5px;display:flex;justify-content:space-between}.props-title i{cursor:pointer}.props-inputs{padding-left:20px;margin-bottom:10px}p{font-size:14px;margin:10px 0;color:var(--yellow-800)}\n"] }]
9429
9770
  }], ctorParameters: () => [] });
9430
9771
 
9431
9772
  class FieldTypeSelectorComponent {
9432
- types = [...FIELDS_CONFIG];
9773
+ excludeTypes = input([]);
9774
+ types = computed(() => FIELDS_CONFIG.filter(f => !this.excludeTypes().includes(f.value)));
9433
9775
  selectType = output();
9434
9776
  addField(type) {
9435
9777
  this.selectType.emit(type);
9436
9778
  }
9437
9779
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: FieldTypeSelectorComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
9438
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.14", type: FieldTypeSelectorComponent, isStandalone: true, selector: "lib-field-type-selector", outputs: { selectType: "selectType" }, ngImport: i0, template: "@for (type of types; track $index) {\r\n <div [uiTooltip]=\"type.label | uicTranslate\" (click)=\"addField(type)\" class=\"field-type\">\n <i [class]=\"type.icon\"></i>\r\n <!-- <div>\r\n <b>{{type.label}}</b>\r\n <p>{{type.detail}}</p>\r\n </div> -->\r\n </div>\r\n}\n", styles: [":host{display:flex;overflow:auto;gap:5px}.field-type{border:solid 1px var(--grey-300);border-radius:5px;padding:5px;display:flex;align-items:center;background-color:#fff;cursor:pointer;gap:5px}.field-type b{font-weight:400}.field-type p{font-size:12px;color:var(--grey-400)}\n"], dependencies: [{ kind: "directive", type: UicToolTipDirective, selector: "[uiTooltip]", inputs: ["uiTooltip"] }, { kind: "pipe", type: UicTranslatePipe, name: "uicTranslate" }] });
9780
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.14", type: FieldTypeSelectorComponent, isStandalone: true, selector: "lib-field-type-selector", inputs: { excludeTypes: { classPropertyName: "excludeTypes", publicName: "excludeTypes", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { selectType: "selectType" }, ngImport: i0, template: "@for (type of types(); track $index) {\r\n <div [uiTooltip]=\"type.label | uicTranslate\" (click)=\"addField(type)\" class=\"field-type\">\r\n <i [class]=\"type.icon\"></i>\r\n </div>\r\n}\r\n", styles: [":host{display:flex;overflow:auto;gap:5px}.field-type{border:solid 1px var(--grey-300);border-radius:5px;padding:5px;display:flex;align-items:center;background-color:#fff;cursor:pointer;gap:5px}.field-type b{font-weight:400}.field-type p{font-size:12px;color:var(--grey-400)}\n"], dependencies: [{ kind: "directive", type: UicToolTipDirective, selector: "[uiTooltip]", inputs: ["uiTooltip"] }, { kind: "pipe", type: UicTranslatePipe, name: "uicTranslate" }] });
9439
9781
  }
9440
9782
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: FieldTypeSelectorComponent, decorators: [{
9441
9783
  type: Component,
9442
- args: [{ selector: 'lib-field-type-selector', imports: [UicToolTipDirective, UicTranslatePipe], template: "@for (type of types; track $index) {\r\n <div [uiTooltip]=\"type.label | uicTranslate\" (click)=\"addField(type)\" class=\"field-type\">\n <i [class]=\"type.icon\"></i>\r\n <!-- <div>\r\n <b>{{type.label}}</b>\r\n <p>{{type.detail}}</p>\r\n </div> -->\r\n </div>\r\n}\n", styles: [":host{display:flex;overflow:auto;gap:5px}.field-type{border:solid 1px var(--grey-300);border-radius:5px;padding:5px;display:flex;align-items:center;background-color:#fff;cursor:pointer;gap:5px}.field-type b{font-weight:400}.field-type p{font-size:12px;color:var(--grey-400)}\n"] }]
9784
+ args: [{ selector: 'lib-field-type-selector', imports: [UicToolTipDirective, UicTranslatePipe], template: "@for (type of types(); track $index) {\r\n <div [uiTooltip]=\"type.label | uicTranslate\" (click)=\"addField(type)\" class=\"field-type\">\r\n <i [class]=\"type.icon\"></i>\r\n </div>\r\n}\r\n", styles: [":host{display:flex;overflow:auto;gap:5px}.field-type{border:solid 1px var(--grey-300);border-radius:5px;padding:5px;display:flex;align-items:center;background-color:#fff;cursor:pointer;gap:5px}.field-type b{font-weight:400}.field-type p{font-size:12px;color:var(--grey-400)}\n"] }]
9443
9785
  }] });
9444
9786
 
9445
9787
  class BlockEditorComponent {
@@ -9454,10 +9796,81 @@ class BlockEditorComponent {
9454
9796
  addFieldRequest = output();
9455
9797
  deleteBlock = output();
9456
9798
  notifySelectedField = output();
9799
+ notifySelectedSubField = output();
9457
9800
  selectedFieldId = null;
9801
+ selectedSubFieldCode = null;
9458
9802
  visibilityParentFieldCodes = new Set();
9803
+ excludeSubFieldTypes = ['repeater'];
9804
+ expandedRepeaters = signal(new Set());
9805
+ isRepeaterExpanded(code) {
9806
+ return this.expandedRepeaters().has(code);
9807
+ }
9808
+ toggleRepeater(code, event) {
9809
+ event.stopPropagation();
9810
+ const next = new Set(this.expandedRepeaters());
9811
+ next.has(code) ? next.delete(code) : next.add(code);
9812
+ this.expandedRepeaters.set(next);
9813
+ }
9814
+ isRepeaterParentSelected(field) {
9815
+ if (this.selectedFieldId === field.code)
9816
+ return true;
9817
+ if (field.fieldData.type !== 'repeater')
9818
+ return false;
9819
+ return !!(this.selectedSubFieldCode && field.repeaterSubFields?.some(sf => sf.code === this.selectedSubFieldCode));
9820
+ }
9459
9821
  selectField(field) {
9460
9822
  this.notifySelectedField.emit(field);
9823
+ this.notifySelectedSubField.emit(null);
9824
+ }
9825
+ onSelectSubField(parentCode, subField, event) {
9826
+ event.stopPropagation();
9827
+ this.notifySelectedSubField.emit({ parentCode, subField });
9828
+ }
9829
+ addSubField(parentCode, type) {
9830
+ const parentField = this.block().fields.find(f => f.code === parentCode);
9831
+ const existing = parentField?.repeaterSubFields ?? [];
9832
+ const sfCode = this.generateSubFieldCode(existing);
9833
+ const newSf = {
9834
+ code: sfCode,
9835
+ order: existing.length + 1,
9836
+ type: type.value,
9837
+ field: type,
9838
+ fieldData: { name: sfCode, label: 'Nuevo campo', type: type.value }
9839
+ };
9840
+ this.updateSubFields(parentCode, [...existing, newSf]);
9841
+ this.notifySelectedSubField.emit({ parentCode, subField: newSf });
9842
+ }
9843
+ deleteSubField(parentCode, sfCode, event) {
9844
+ event.stopPropagation();
9845
+ const parentField = this.block().fields.find(f => f.code === parentCode);
9846
+ const updated = (parentField?.repeaterSubFields ?? []).filter(sf => sf.code !== sfCode);
9847
+ this.updateSubFields(parentCode, updated);
9848
+ if (this.selectedSubFieldCode === sfCode) {
9849
+ this.notifySelectedSubField.emit(null);
9850
+ }
9851
+ }
9852
+ reorderSubFields(parentCode, event) {
9853
+ if (event.previousIndex === event.currentIndex)
9854
+ return;
9855
+ const parentField = this.block().fields.find(f => f.code === parentCode);
9856
+ const next = [...(parentField?.repeaterSubFields ?? [])];
9857
+ moveItemInArray(next, event.previousIndex, event.currentIndex);
9858
+ this.updateSubFields(parentCode, next);
9859
+ }
9860
+ updateSubFields(parentCode, subFields) {
9861
+ this.blockChange.emit({
9862
+ ...this.block(),
9863
+ fields: this.block().fields.map(f => f.code !== parentCode ? f : { ...f, repeaterSubFields: subFields })
9864
+ });
9865
+ }
9866
+ generateSubFieldCode(existing) {
9867
+ const max = existing.reduce((m, sf) => {
9868
+ if (!sf.code.startsWith('sf_'))
9869
+ return m;
9870
+ const n = parseInt(sf.code.slice(3), 10);
9871
+ return isNaN(n) ? m : Math.max(m, n);
9872
+ }, 0);
9873
+ return `sf_${max + 1}`;
9461
9874
  }
9462
9875
  changeTitle(newTitle) {
9463
9876
  this.blockChange.emit({ ...this.block(), title: newTitle });
@@ -9497,7 +9910,7 @@ class BlockEditorComponent {
9497
9910
  this.blockChange.emit({ ...this.block(), fields: nextFields });
9498
9911
  }
9499
9912
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: BlockEditorComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
9500
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.14", type: BlockEditorComponent, isStandalone: true, selector: "lib-block-editor", inputs: { block: { classPropertyName: "block", publicName: "block", isSignal: true, isRequired: false, transformFunction: null }, selectedFieldId: { classPropertyName: "selectedFieldId", publicName: "selectedFieldId", isSignal: false, isRequired: false, transformFunction: null }, visibilityParentFieldCodes: { classPropertyName: "visibilityParentFieldCodes", publicName: "visibilityParentFieldCodes", isSignal: false, isRequired: false, transformFunction: null } }, outputs: { blockChange: "blockChange", addFieldRequest: "addFieldRequest", deleteBlock: "deleteBlock", notifySelectedField: "notifySelectedField" }, ngImport: i0, template: "<div class=\"form-block-card\">\n <div class=\"form-block-card-header\">\n <div>\n <input [placeholder]=\"'form_builder.block_title' | uicTranslate\" [ngModel]=\"block().title\" (ngModelChange)=\"changeTitle($event)\">\n <input [placeholder]=\"'form_builder.block_subtitle' | uicTranslate\" [ngModel]=\"block().subtitle\" (ngModelChange)=\"changeSubtitle($event)\">\n </div>\n <ui-button\n [uiTooltip]=\"(isBlockVisibilityParent() ? 'form_builder.delete_block_dependency_blocked' : 'form_builder.delete_block') | uicTranslate\"\n [disabled]=\"isBlockVisibilityParent()\"\n (click)=\"requestDeleteBlock($event)\"\n size=\"s\"\n icon=\"ri-delete-bin-line\"\n color=\"red\"\n type=\"ghost\"\n [iconOnly]=\"true\">\n </ui-button>\n </div>\n <div\n class=\"form-block-card-body\"\n cdkDropList\n [cdkDropListData]=\"block().fields\"\n (cdkDropListDropped)=\"reorderFields($event)\">\n \n <!-- FIELDS -->\n @for(edtField of block().fields; track edtField.code; let i = $index) {\n <div\n class=\"xfield-card\"\n cdkDrag\n [class.selected-field]=\"selectedFieldId === edtField.code\"\n (click)=\"selectField(edtField)\">\n <i class=\"ri-draggable field-drag-handle\" cdkDragHandle></i>\n\n <div class=\"xfield-card-icon\">\n <i [class]=\"edtField.field?.icon ?? ''\"></i> \n </div>\n <div class=\"xfield-card-body\">\n <b> {{edtField.fieldData.label}} \n @if(edtField.fieldData.visibilityRules) {\n <i class=\"branched-field ri-git-merge-line\"></i> \n <span class=\"vs-rule\"> {{edtField.fieldData.visibilityRules[0]?.fieldLabel ?? edtField.fieldData.visibilityRules[0]?.fieldName ?? '-'}} </span>\n }\n </b>\n <p> {{edtField.field?.label ?? edtField.type ?? edtField.fieldData.type}} </p>\n </div>\n <div class=\"xfield-card-actions\">\n <ui-button\n [uiTooltip]=\"(isVisibilityParent(edtField.code) ? 'form_builder.delete_field_dependency_blocked' : 'form_builder.field_editor.delete') | uicTranslate\"\n [disabled]=\"isVisibilityParent(edtField.code)\"\n (click)=\"deleteField(edtField.code, $event)\"\n size=\"s\"\n icon=\"ri-delete-bin-line\"\n color=\"red\"\n type=\"ghost\"\n [iconOnly]=\"true\">\n </ui-button>\n </div>\n </div>\n\n }\n\n </div>\n <div class=\"new-field\">\n {{'form_builder.add_new_field' | uicTranslate}}\n <lib-field-type-selector (selectType)=\"addField($event)\"></lib-field-type-selector>\n </div>\n</div>\n", styles: [".form-block-card{border:solid 1px var(--blue-500);border-radius:5px;overflow:hidden}.form-block-card-header{display:flex;gap:5px;align-items:center;background-color:#fff;padding:10px;border-bottom:solid 1px var(--grey-300)}.form-block-card-header>div{flex:1 1;gap:4px;display:flex;flex-direction:column}.form-block-card-header>div input{border:solid 1px var(--grey-100);padding:3px 6px;border-radius:5px}.form-block-card-header>div input:focus{border:solid 1px var(--primary-500);outline:none}.form-block-card-body{padding:15px;display:flex;flex-direction:column;background-color:var(--grey-50);gap:10px}.xfield-card{background-color:#fff;border-radius:5px;padding:10px;gap:10px;display:flex;align-items:center;border:solid 2px var(--grey-200);cursor:pointer;transition:border-color .3s ease}.xfield-card:hover{border-color:var(--grey-300)}.xfield-card-icon{display:flex;justify-content:center;align-items:center;border-radius:5px;width:30px;height:30px;font-size:20px;background-color:var(--grey-300);color:var(--grey-600)}.xfield-card-body{flex:1 1}.xfield-card-body b{display:flex;align-items:center;gap:5px}.xfield-card-body p{color:var(--grey-400);font-size:12px}.field-drag-handle{cursor:grab;color:var(--grey-400);transition:color .2s ease}.field-drag-handle:active{cursor:grabbing}.xfield-card:hover .field-drag-handle{color:var(--grey-600)}.cdk-drag-preview{box-sizing:border-box;border-radius:5px;box-shadow:0 6px 12px #0000002e}.cdk-drag-placeholder{opacity:0}.cdk-drag-animating{transition:transform .25s cubic-bezier(0,0,.2,1)}.form-block-card-body.cdk-drop-list-dragging .xfield-card:not(.cdk-drag-placeholder){transition:transform .25s cubic-bezier(0,0,.2,1)}.branched-field{color:var(--yellow-600)}.selected-field,.selected-field:hover{border-color:var(--primary-500)}.new-field{border-top:solid 1px var(--grey-300);padding:10px;background-color:#fff;display:flex;flex-direction:column;gap:5px;font-size:14px}.vs-rule{font-size:12px;color:var(--grey-600)}\n"], dependencies: [{ kind: "component", type: UicButtonComponent, selector: "ui-button", inputs: ["text", "icon", "rightIcon", "iconOnly", "disabled", "loading", "size", "type", "color"] }, { kind: "directive", type: UicToolTipDirective, selector: "[uiTooltip]", inputs: ["uiTooltip"] }, { kind: "pipe", type: UicTranslatePipe, name: "uicTranslate" }, { kind: "ngmodule", type: DragDropModule }, { kind: "directive", type: i1$3.CdkDropList, selector: "[cdkDropList], cdk-drop-list", inputs: ["cdkDropListConnectedTo", "cdkDropListData", "cdkDropListOrientation", "id", "cdkDropListLockAxis", "cdkDropListDisabled", "cdkDropListSortingDisabled", "cdkDropListEnterPredicate", "cdkDropListSortPredicate", "cdkDropListAutoScrollDisabled", "cdkDropListAutoScrollStep", "cdkDropListElementContainer"], outputs: ["cdkDropListDropped", "cdkDropListEntered", "cdkDropListExited", "cdkDropListSorted"], exportAs: ["cdkDropList"] }, { kind: "directive", type: i1$3.CdkDrag, selector: "[cdkDrag]", inputs: ["cdkDragData", "cdkDragLockAxis", "cdkDragRootElement", "cdkDragBoundary", "cdkDragStartDelay", "cdkDragFreeDragPosition", "cdkDragDisabled", "cdkDragConstrainPosition", "cdkDragPreviewClass", "cdkDragPreviewContainer", "cdkDragScale"], outputs: ["cdkDragStarted", "cdkDragReleased", "cdkDragEnded", "cdkDragEntered", "cdkDragExited", "cdkDragDropped", "cdkDragMoved"], exportAs: ["cdkDrag"] }, { kind: "directive", type: i1$3.CdkDragHandle, selector: "[cdkDragHandle]", inputs: ["cdkDragHandleDisabled"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: FieldTypeSelectorComponent, selector: "lib-field-type-selector", outputs: ["selectType"] }] });
9913
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.14", type: BlockEditorComponent, isStandalone: true, selector: "lib-block-editor", inputs: { block: { classPropertyName: "block", publicName: "block", isSignal: true, isRequired: false, transformFunction: null }, selectedFieldId: { classPropertyName: "selectedFieldId", publicName: "selectedFieldId", isSignal: false, isRequired: false, transformFunction: null }, selectedSubFieldCode: { classPropertyName: "selectedSubFieldCode", publicName: "selectedSubFieldCode", isSignal: false, isRequired: false, transformFunction: null }, visibilityParentFieldCodes: { classPropertyName: "visibilityParentFieldCodes", publicName: "visibilityParentFieldCodes", isSignal: false, isRequired: false, transformFunction: null } }, outputs: { blockChange: "blockChange", addFieldRequest: "addFieldRequest", deleteBlock: "deleteBlock", notifySelectedField: "notifySelectedField", notifySelectedSubField: "notifySelectedSubField" }, ngImport: i0, template: "<div class=\"form-block-card\">\r\n <div class=\"form-block-card-header\">\r\n <div>\r\n <input [placeholder]=\"'form_builder.block_title' | uicTranslate\" [ngModel]=\"block().title\" (ngModelChange)=\"changeTitle($event)\">\r\n <input [placeholder]=\"'form_builder.block_subtitle' | uicTranslate\" [ngModel]=\"block().subtitle\" (ngModelChange)=\"changeSubtitle($event)\">\r\n </div>\r\n <ui-button\r\n [uiTooltip]=\"(isBlockVisibilityParent() ? 'form_builder.delete_block_dependency_blocked' : 'form_builder.delete_block') | uicTranslate\"\r\n [disabled]=\"isBlockVisibilityParent()\"\r\n (click)=\"requestDeleteBlock($event)\"\r\n size=\"s\"\r\n icon=\"ri-delete-bin-line\"\r\n color=\"red\"\r\n type=\"ghost\"\r\n [iconOnly]=\"true\">\r\n </ui-button>\r\n </div>\r\n <div\r\n class=\"form-block-card-body\"\r\n cdkDropList\r\n [cdkDropListData]=\"block().fields\"\r\n (cdkDropListDropped)=\"reorderFields($event)\">\r\n \r\n <!-- FIELDS -->\r\n @for(edtField of block().fields; track edtField.code; let i = $index) {\r\n <div class=\"field-with-subfields\">\r\n <div\r\n class=\"xfield-card\"\r\n cdkDrag\r\n [class.selected-field]=\"isRepeaterParentSelected(edtField)\"\r\n (click)=\"selectField(edtField)\">\r\n <i class=\"ri-draggable field-drag-handle\" cdkDragHandle></i>\r\n\r\n <div class=\"xfield-card-icon\">\r\n <i [class]=\"edtField.field?.icon ?? ''\"></i> \r\n </div>\r\n <div class=\"xfield-card-body\">\r\n <b> {{edtField.fieldData.label}} \r\n @if(edtField.fieldData.visibilityRules) {\r\n <i class=\"branched-field ri-git-merge-line\"></i> \r\n <span class=\"vs-rule\"> {{edtField.fieldData.visibilityRules[0]?.fieldLabel ?? edtField.fieldData.visibilityRules[0]?.fieldName ?? '-'}} </span>\r\n }\r\n </b>\r\n <p> {{edtField.field?.label ?? edtField.type ?? edtField.fieldData.type}} </p>\r\n </div>\r\n <div class=\"xfield-card-actions\">\r\n @if (edtField.fieldData.type === 'repeater') {\r\n <ui-button\r\n [icon]=\"isRepeaterExpanded(edtField.code) ? 'ri-arrow-up-s-line' : 'ri-arrow-down-s-line'\"\r\n size=\"s\" color=\"black\" type=\"ghost\" [iconOnly]=\"true\"\r\n (click)=\"toggleRepeater(edtField.code, $event)\">\r\n </ui-button>\r\n }\r\n <ui-button\r\n [uiTooltip]=\"(isVisibilityParent(edtField.code) ? 'form_builder.delete_field_dependency_blocked' : 'form_builder.field_editor.delete') | uicTranslate\"\r\n [disabled]=\"isVisibilityParent(edtField.code)\"\r\n (click)=\"deleteField(edtField.code, $event)\"\r\n size=\"s\"\r\n icon=\"ri-delete-bin-line\"\r\n color=\"red\"\r\n type=\"ghost\"\r\n [iconOnly]=\"true\">\r\n </ui-button>\r\n </div>\r\n </div>\r\n\r\n @if (edtField.fieldData.type === 'repeater' && isRepeaterExpanded(edtField.code)) {\r\n <div class=\"repeater-inline-panel\">\r\n <div\r\n class=\"repeater-subfields-list\"\r\n cdkDropList\r\n [cdkDropListData]=\"edtField.repeaterSubFields ?? []\"\r\n (cdkDropListDropped)=\"reorderSubFields(edtField.code, $event)\">\r\n @for (sf of edtField.repeaterSubFields ?? []; track sf.code) {\r\n <div\r\n class=\"xfield-card subfield-card\"\r\n cdkDrag\r\n [class.selected-field]=\"selectedSubFieldCode === sf.code\"\r\n (click)=\"onSelectSubField(edtField.code, sf, $event)\">\r\n <i class=\"ri-draggable field-drag-handle\" cdkDragHandle></i>\r\n <div class=\"xfield-card-icon\">\r\n <i [class]=\"sf.field?.icon ?? 'ri-question-line'\"></i>\r\n </div>\r\n <div class=\"xfield-card-body\">\r\n <b>{{ sf.fieldData.label || sf.fieldData.name }}</b>\r\n <p>{{ sf.field?.label ?? sf.type ?? sf.fieldData.type }}</p>\r\n </div>\r\n <div class=\"xfield-card-actions\">\r\n <ui-button\r\n size=\"s\" icon=\"ri-delete-bin-line\" color=\"red\" type=\"ghost\" [iconOnly]=\"true\"\r\n (click)=\"deleteSubField(edtField.code, sf.code, $event)\">\r\n </ui-button>\r\n </div>\r\n </div>\r\n } @empty {\r\n <p class=\"empty-hint\">{{'form_builder.repeater.no_subfields' | uicTranslate}}</p>\r\n }\r\n </div>\r\n <div class=\"new-subfield\">\r\n {{'form_builder.repeater.add_subfield' | uicTranslate}}\r\n <lib-field-type-selector [excludeTypes]=\"excludeSubFieldTypes\" (selectType)=\"addSubField(edtField.code, $event)\"></lib-field-type-selector>\r\n </div>\r\n </div>\r\n }\r\n </div>\r\n\r\n }\r\n\r\n </div>\r\n <div class=\"new-field\">\r\n {{'form_builder.add_new_field' | uicTranslate}}\r\n <lib-field-type-selector (selectType)=\"addField($event)\"></lib-field-type-selector>\r\n </div>\r\n</div>\r\n", styles: [".form-block-card{border:solid 1px var(--blue-500);border-radius:5px;overflow:hidden}.form-block-card-header{display:flex;gap:5px;align-items:center;background-color:#fff;padding:10px;border-bottom:solid 1px var(--grey-300)}.form-block-card-header>div{flex:1 1;gap:4px;display:flex;flex-direction:column}.form-block-card-header>div input{border:solid 1px var(--grey-100);padding:3px 6px;border-radius:5px}.form-block-card-header>div input:focus{border:solid 1px var(--primary-500);outline:none}.form-block-card-body{padding:15px;display:flex;flex-direction:column;background-color:var(--grey-50);gap:10px}.xfield-card{background-color:#fff;border-radius:5px;padding:10px;gap:10px;display:flex;align-items:center;border:solid 2px var(--grey-200);cursor:pointer;transition:border-color .3s ease}.xfield-card:hover{border-color:var(--grey-300)}.xfield-card-icon{display:flex;justify-content:center;align-items:center;border-radius:5px;width:30px;height:30px;font-size:20px;background-color:var(--grey-300);color:var(--grey-600)}.xfield-card-body{flex:1 1}.xfield-card-body b{display:flex;align-items:center;gap:5px}.xfield-card-body p{color:var(--grey-400);font-size:12px}.field-drag-handle{cursor:grab;color:var(--grey-400);transition:color .2s ease}.field-drag-handle:active{cursor:grabbing}.xfield-card:hover .field-drag-handle{color:var(--grey-600)}.cdk-drag-preview{box-sizing:border-box;border-radius:5px;box-shadow:0 6px 12px #0000002e}.cdk-drag-placeholder{opacity:0}.cdk-drag-animating{transition:transform .25s cubic-bezier(0,0,.2,1)}.field-with-subfields{display:flex;flex-direction:column;gap:0}.repeater-inline-panel{background-color:var(--grey-100);border:solid 1px var(--blue-300);border-top:none;border-radius:0 0 5px 5px;padding:10px 10px 8px 28px;display:flex;flex-direction:column;gap:8px}.repeater-subfields-list{display:flex;flex-direction:column;gap:6px;min-height:6px}.subfield-card{font-size:13px;border-radius:4px;padding:7px 8px!important}.subfield-card .xfield-card-icon{width:26px!important;height:26px!important;font-size:16px!important}.subfield-card b{font-size:13px}.subfield-card p{font-size:11px}.new-subfield{display:flex;align-items:center;gap:8px;font-size:12px;color:var(--grey-500);flex-wrap:wrap;padding-top:2px}.empty-hint{font-size:12px;color:var(--grey-400);text-align:center;padding:4px 0;margin:0}.form-block-card-body.cdk-drop-list-dragging .xfield-card:not(.cdk-drag-placeholder){transition:transform .25s cubic-bezier(0,0,.2,1)}.branched-field{color:var(--yellow-600)}.selected-field,.selected-field:hover{border-color:var(--primary-500)}.new-field{border-top:solid 1px var(--grey-300);padding:10px;background-color:#fff;display:flex;flex-direction:column;gap:5px;font-size:14px}.vs-rule{font-size:12px;color:var(--grey-600)}\n"], dependencies: [{ kind: "component", type: UicButtonComponent, selector: "ui-button", inputs: ["text", "icon", "rightIcon", "iconOnly", "disabled", "loading", "size", "type", "color"] }, { kind: "directive", type: UicToolTipDirective, selector: "[uiTooltip]", inputs: ["uiTooltip"] }, { kind: "pipe", type: UicTranslatePipe, name: "uicTranslate" }, { kind: "ngmodule", type: DragDropModule }, { kind: "directive", type: i1$3.CdkDropList, selector: "[cdkDropList], cdk-drop-list", inputs: ["cdkDropListConnectedTo", "cdkDropListData", "cdkDropListOrientation", "id", "cdkDropListLockAxis", "cdkDropListDisabled", "cdkDropListSortingDisabled", "cdkDropListEnterPredicate", "cdkDropListSortPredicate", "cdkDropListAutoScrollDisabled", "cdkDropListAutoScrollStep", "cdkDropListElementContainer"], outputs: ["cdkDropListDropped", "cdkDropListEntered", "cdkDropListExited", "cdkDropListSorted"], exportAs: ["cdkDropList"] }, { kind: "directive", type: i1$3.CdkDrag, selector: "[cdkDrag]", inputs: ["cdkDragData", "cdkDragLockAxis", "cdkDragRootElement", "cdkDragBoundary", "cdkDragStartDelay", "cdkDragFreeDragPosition", "cdkDragDisabled", "cdkDragConstrainPosition", "cdkDragPreviewClass", "cdkDragPreviewContainer", "cdkDragScale"], outputs: ["cdkDragStarted", "cdkDragReleased", "cdkDragEnded", "cdkDragEntered", "cdkDragExited", "cdkDragDropped", "cdkDragMoved"], exportAs: ["cdkDrag"] }, { kind: "directive", type: i1$3.CdkDragHandle, selector: "[cdkDragHandle]", inputs: ["cdkDragHandleDisabled"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: FieldTypeSelectorComponent, selector: "lib-field-type-selector", inputs: ["excludeTypes"], outputs: ["selectType"] }] });
9501
9914
  }
9502
9915
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: BlockEditorComponent, decorators: [{
9503
9916
  type: Component,
@@ -9508,9 +9921,11 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImpo
9508
9921
  DragDropModule,
9509
9922
  FormsModule,
9510
9923
  FieldTypeSelectorComponent
9511
- ], template: "<div class=\"form-block-card\">\n <div class=\"form-block-card-header\">\n <div>\n <input [placeholder]=\"'form_builder.block_title' | uicTranslate\" [ngModel]=\"block().title\" (ngModelChange)=\"changeTitle($event)\">\n <input [placeholder]=\"'form_builder.block_subtitle' | uicTranslate\" [ngModel]=\"block().subtitle\" (ngModelChange)=\"changeSubtitle($event)\">\n </div>\n <ui-button\n [uiTooltip]=\"(isBlockVisibilityParent() ? 'form_builder.delete_block_dependency_blocked' : 'form_builder.delete_block') | uicTranslate\"\n [disabled]=\"isBlockVisibilityParent()\"\n (click)=\"requestDeleteBlock($event)\"\n size=\"s\"\n icon=\"ri-delete-bin-line\"\n color=\"red\"\n type=\"ghost\"\n [iconOnly]=\"true\">\n </ui-button>\n </div>\n <div\n class=\"form-block-card-body\"\n cdkDropList\n [cdkDropListData]=\"block().fields\"\n (cdkDropListDropped)=\"reorderFields($event)\">\n \n <!-- FIELDS -->\n @for(edtField of block().fields; track edtField.code; let i = $index) {\n <div\n class=\"xfield-card\"\n cdkDrag\n [class.selected-field]=\"selectedFieldId === edtField.code\"\n (click)=\"selectField(edtField)\">\n <i class=\"ri-draggable field-drag-handle\" cdkDragHandle></i>\n\n <div class=\"xfield-card-icon\">\n <i [class]=\"edtField.field?.icon ?? ''\"></i> \n </div>\n <div class=\"xfield-card-body\">\n <b> {{edtField.fieldData.label}} \n @if(edtField.fieldData.visibilityRules) {\n <i class=\"branched-field ri-git-merge-line\"></i> \n <span class=\"vs-rule\"> {{edtField.fieldData.visibilityRules[0]?.fieldLabel ?? edtField.fieldData.visibilityRules[0]?.fieldName ?? '-'}} </span>\n }\n </b>\n <p> {{edtField.field?.label ?? edtField.type ?? edtField.fieldData.type}} </p>\n </div>\n <div class=\"xfield-card-actions\">\n <ui-button\n [uiTooltip]=\"(isVisibilityParent(edtField.code) ? 'form_builder.delete_field_dependency_blocked' : 'form_builder.field_editor.delete') | uicTranslate\"\n [disabled]=\"isVisibilityParent(edtField.code)\"\n (click)=\"deleteField(edtField.code, $event)\"\n size=\"s\"\n icon=\"ri-delete-bin-line\"\n color=\"red\"\n type=\"ghost\"\n [iconOnly]=\"true\">\n </ui-button>\n </div>\n </div>\n\n }\n\n </div>\n <div class=\"new-field\">\n {{'form_builder.add_new_field' | uicTranslate}}\n <lib-field-type-selector (selectType)=\"addField($event)\"></lib-field-type-selector>\n </div>\n</div>\n", styles: [".form-block-card{border:solid 1px var(--blue-500);border-radius:5px;overflow:hidden}.form-block-card-header{display:flex;gap:5px;align-items:center;background-color:#fff;padding:10px;border-bottom:solid 1px var(--grey-300)}.form-block-card-header>div{flex:1 1;gap:4px;display:flex;flex-direction:column}.form-block-card-header>div input{border:solid 1px var(--grey-100);padding:3px 6px;border-radius:5px}.form-block-card-header>div input:focus{border:solid 1px var(--primary-500);outline:none}.form-block-card-body{padding:15px;display:flex;flex-direction:column;background-color:var(--grey-50);gap:10px}.xfield-card{background-color:#fff;border-radius:5px;padding:10px;gap:10px;display:flex;align-items:center;border:solid 2px var(--grey-200);cursor:pointer;transition:border-color .3s ease}.xfield-card:hover{border-color:var(--grey-300)}.xfield-card-icon{display:flex;justify-content:center;align-items:center;border-radius:5px;width:30px;height:30px;font-size:20px;background-color:var(--grey-300);color:var(--grey-600)}.xfield-card-body{flex:1 1}.xfield-card-body b{display:flex;align-items:center;gap:5px}.xfield-card-body p{color:var(--grey-400);font-size:12px}.field-drag-handle{cursor:grab;color:var(--grey-400);transition:color .2s ease}.field-drag-handle:active{cursor:grabbing}.xfield-card:hover .field-drag-handle{color:var(--grey-600)}.cdk-drag-preview{box-sizing:border-box;border-radius:5px;box-shadow:0 6px 12px #0000002e}.cdk-drag-placeholder{opacity:0}.cdk-drag-animating{transition:transform .25s cubic-bezier(0,0,.2,1)}.form-block-card-body.cdk-drop-list-dragging .xfield-card:not(.cdk-drag-placeholder){transition:transform .25s cubic-bezier(0,0,.2,1)}.branched-field{color:var(--yellow-600)}.selected-field,.selected-field:hover{border-color:var(--primary-500)}.new-field{border-top:solid 1px var(--grey-300);padding:10px;background-color:#fff;display:flex;flex-direction:column;gap:5px;font-size:14px}.vs-rule{font-size:12px;color:var(--grey-600)}\n"] }]
9924
+ ], template: "<div class=\"form-block-card\">\r\n <div class=\"form-block-card-header\">\r\n <div>\r\n <input [placeholder]=\"'form_builder.block_title' | uicTranslate\" [ngModel]=\"block().title\" (ngModelChange)=\"changeTitle($event)\">\r\n <input [placeholder]=\"'form_builder.block_subtitle' | uicTranslate\" [ngModel]=\"block().subtitle\" (ngModelChange)=\"changeSubtitle($event)\">\r\n </div>\r\n <ui-button\r\n [uiTooltip]=\"(isBlockVisibilityParent() ? 'form_builder.delete_block_dependency_blocked' : 'form_builder.delete_block') | uicTranslate\"\r\n [disabled]=\"isBlockVisibilityParent()\"\r\n (click)=\"requestDeleteBlock($event)\"\r\n size=\"s\"\r\n icon=\"ri-delete-bin-line\"\r\n color=\"red\"\r\n type=\"ghost\"\r\n [iconOnly]=\"true\">\r\n </ui-button>\r\n </div>\r\n <div\r\n class=\"form-block-card-body\"\r\n cdkDropList\r\n [cdkDropListData]=\"block().fields\"\r\n (cdkDropListDropped)=\"reorderFields($event)\">\r\n \r\n <!-- FIELDS -->\r\n @for(edtField of block().fields; track edtField.code; let i = $index) {\r\n <div class=\"field-with-subfields\">\r\n <div\r\n class=\"xfield-card\"\r\n cdkDrag\r\n [class.selected-field]=\"isRepeaterParentSelected(edtField)\"\r\n (click)=\"selectField(edtField)\">\r\n <i class=\"ri-draggable field-drag-handle\" cdkDragHandle></i>\r\n\r\n <div class=\"xfield-card-icon\">\r\n <i [class]=\"edtField.field?.icon ?? ''\"></i> \r\n </div>\r\n <div class=\"xfield-card-body\">\r\n <b> {{edtField.fieldData.label}} \r\n @if(edtField.fieldData.visibilityRules) {\r\n <i class=\"branched-field ri-git-merge-line\"></i> \r\n <span class=\"vs-rule\"> {{edtField.fieldData.visibilityRules[0]?.fieldLabel ?? edtField.fieldData.visibilityRules[0]?.fieldName ?? '-'}} </span>\r\n }\r\n </b>\r\n <p> {{edtField.field?.label ?? edtField.type ?? edtField.fieldData.type}} </p>\r\n </div>\r\n <div class=\"xfield-card-actions\">\r\n @if (edtField.fieldData.type === 'repeater') {\r\n <ui-button\r\n [icon]=\"isRepeaterExpanded(edtField.code) ? 'ri-arrow-up-s-line' : 'ri-arrow-down-s-line'\"\r\n size=\"s\" color=\"black\" type=\"ghost\" [iconOnly]=\"true\"\r\n (click)=\"toggleRepeater(edtField.code, $event)\">\r\n </ui-button>\r\n }\r\n <ui-button\r\n [uiTooltip]=\"(isVisibilityParent(edtField.code) ? 'form_builder.delete_field_dependency_blocked' : 'form_builder.field_editor.delete') | uicTranslate\"\r\n [disabled]=\"isVisibilityParent(edtField.code)\"\r\n (click)=\"deleteField(edtField.code, $event)\"\r\n size=\"s\"\r\n icon=\"ri-delete-bin-line\"\r\n color=\"red\"\r\n type=\"ghost\"\r\n [iconOnly]=\"true\">\r\n </ui-button>\r\n </div>\r\n </div>\r\n\r\n @if (edtField.fieldData.type === 'repeater' && isRepeaterExpanded(edtField.code)) {\r\n <div class=\"repeater-inline-panel\">\r\n <div\r\n class=\"repeater-subfields-list\"\r\n cdkDropList\r\n [cdkDropListData]=\"edtField.repeaterSubFields ?? []\"\r\n (cdkDropListDropped)=\"reorderSubFields(edtField.code, $event)\">\r\n @for (sf of edtField.repeaterSubFields ?? []; track sf.code) {\r\n <div\r\n class=\"xfield-card subfield-card\"\r\n cdkDrag\r\n [class.selected-field]=\"selectedSubFieldCode === sf.code\"\r\n (click)=\"onSelectSubField(edtField.code, sf, $event)\">\r\n <i class=\"ri-draggable field-drag-handle\" cdkDragHandle></i>\r\n <div class=\"xfield-card-icon\">\r\n <i [class]=\"sf.field?.icon ?? 'ri-question-line'\"></i>\r\n </div>\r\n <div class=\"xfield-card-body\">\r\n <b>{{ sf.fieldData.label || sf.fieldData.name }}</b>\r\n <p>{{ sf.field?.label ?? sf.type ?? sf.fieldData.type }}</p>\r\n </div>\r\n <div class=\"xfield-card-actions\">\r\n <ui-button\r\n size=\"s\" icon=\"ri-delete-bin-line\" color=\"red\" type=\"ghost\" [iconOnly]=\"true\"\r\n (click)=\"deleteSubField(edtField.code, sf.code, $event)\">\r\n </ui-button>\r\n </div>\r\n </div>\r\n } @empty {\r\n <p class=\"empty-hint\">{{'form_builder.repeater.no_subfields' | uicTranslate}}</p>\r\n }\r\n </div>\r\n <div class=\"new-subfield\">\r\n {{'form_builder.repeater.add_subfield' | uicTranslate}}\r\n <lib-field-type-selector [excludeTypes]=\"excludeSubFieldTypes\" (selectType)=\"addSubField(edtField.code, $event)\"></lib-field-type-selector>\r\n </div>\r\n </div>\r\n }\r\n </div>\r\n\r\n }\r\n\r\n </div>\r\n <div class=\"new-field\">\r\n {{'form_builder.add_new_field' | uicTranslate}}\r\n <lib-field-type-selector (selectType)=\"addField($event)\"></lib-field-type-selector>\r\n </div>\r\n</div>\r\n", styles: [".form-block-card{border:solid 1px var(--blue-500);border-radius:5px;overflow:hidden}.form-block-card-header{display:flex;gap:5px;align-items:center;background-color:#fff;padding:10px;border-bottom:solid 1px var(--grey-300)}.form-block-card-header>div{flex:1 1;gap:4px;display:flex;flex-direction:column}.form-block-card-header>div input{border:solid 1px var(--grey-100);padding:3px 6px;border-radius:5px}.form-block-card-header>div input:focus{border:solid 1px var(--primary-500);outline:none}.form-block-card-body{padding:15px;display:flex;flex-direction:column;background-color:var(--grey-50);gap:10px}.xfield-card{background-color:#fff;border-radius:5px;padding:10px;gap:10px;display:flex;align-items:center;border:solid 2px var(--grey-200);cursor:pointer;transition:border-color .3s ease}.xfield-card:hover{border-color:var(--grey-300)}.xfield-card-icon{display:flex;justify-content:center;align-items:center;border-radius:5px;width:30px;height:30px;font-size:20px;background-color:var(--grey-300);color:var(--grey-600)}.xfield-card-body{flex:1 1}.xfield-card-body b{display:flex;align-items:center;gap:5px}.xfield-card-body p{color:var(--grey-400);font-size:12px}.field-drag-handle{cursor:grab;color:var(--grey-400);transition:color .2s ease}.field-drag-handle:active{cursor:grabbing}.xfield-card:hover .field-drag-handle{color:var(--grey-600)}.cdk-drag-preview{box-sizing:border-box;border-radius:5px;box-shadow:0 6px 12px #0000002e}.cdk-drag-placeholder{opacity:0}.cdk-drag-animating{transition:transform .25s cubic-bezier(0,0,.2,1)}.field-with-subfields{display:flex;flex-direction:column;gap:0}.repeater-inline-panel{background-color:var(--grey-100);border:solid 1px var(--blue-300);border-top:none;border-radius:0 0 5px 5px;padding:10px 10px 8px 28px;display:flex;flex-direction:column;gap:8px}.repeater-subfields-list{display:flex;flex-direction:column;gap:6px;min-height:6px}.subfield-card{font-size:13px;border-radius:4px;padding:7px 8px!important}.subfield-card .xfield-card-icon{width:26px!important;height:26px!important;font-size:16px!important}.subfield-card b{font-size:13px}.subfield-card p{font-size:11px}.new-subfield{display:flex;align-items:center;gap:8px;font-size:12px;color:var(--grey-500);flex-wrap:wrap;padding-top:2px}.empty-hint{font-size:12px;color:var(--grey-400);text-align:center;padding:4px 0;margin:0}.form-block-card-body.cdk-drop-list-dragging .xfield-card:not(.cdk-drag-placeholder){transition:transform .25s cubic-bezier(0,0,.2,1)}.branched-field{color:var(--yellow-600)}.selected-field,.selected-field:hover{border-color:var(--primary-500)}.new-field{border-top:solid 1px var(--grey-300);padding:10px;background-color:#fff;display:flex;flex-direction:column;gap:5px;font-size:14px}.vs-rule{font-size:12px;color:var(--grey-600)}\n"] }]
9512
9925
  }], propDecorators: { selectedFieldId: [{
9513
9926
  type: Input
9927
+ }], selectedSubFieldCode: [{
9928
+ type: Input
9514
9929
  }], visibilityParentFieldCodes: [{
9515
9930
  type: Input
9516
9931
  }] } });
@@ -9533,6 +9948,7 @@ class UicUserFormbuilderComponent {
9533
9948
  editingSnapshot = signal(null);
9534
9949
  isReadOnly = signal(true);
9535
9950
  selectedField = signal(null);
9951
+ editingSubField = signal(null);
9536
9952
  focusNewFieldCode = signal(null);
9537
9953
  propertiesWidth = signal(250);
9538
9954
  previewSchema = computed(() => helperShowFormFromBuilder(this.editableBlocks(), this.editableCols()));
@@ -9597,6 +10013,18 @@ class UicUserFormbuilderComponent {
9597
10013
  if (selectedField !== this.selectedField()) {
9598
10014
  this.selectedField.set(selectedField);
9599
10015
  }
10016
+ // Sync editingSubField
10017
+ const subCtx = this.editingSubField();
10018
+ if (subCtx) {
10019
+ const parentField = blocks.flatMap(b => b.fields).find(f => f.code === subCtx.parentCode);
10020
+ const latestSf = parentField?.repeaterSubFields?.find(sf => sf.code === subCtx.subField.code);
10021
+ if (!latestSf) {
10022
+ this.editingSubField.set(null);
10023
+ }
10024
+ else if (latestSf !== subCtx.subField) {
10025
+ this.editingSubField.set({ ...subCtx, subField: latestSf });
10026
+ }
10027
+ }
9600
10028
  });
9601
10029
  }
9602
10030
  addBlock() {
@@ -9639,6 +10067,38 @@ class UicUserFormbuilderComponent {
9639
10067
  selectField(field) {
9640
10068
  this.selectedField.set(field);
9641
10069
  this.focusNewFieldCode.set(null);
10070
+ this.editingSubField.set(null);
10071
+ }
10072
+ onSelectSubField(event) {
10073
+ this.editingSubField.set(event);
10074
+ if (event) {
10075
+ // Highlight the parent repeater field in the block (deselect root selection)
10076
+ const parentField = this.editableBlocks()
10077
+ .flatMap(b => b.fields)
10078
+ .find(f => f.code === event.parentCode);
10079
+ if (parentField)
10080
+ this.selectedField.set(parentField);
10081
+ }
10082
+ }
10083
+ onSubFieldChange(updatedFieldData) {
10084
+ const context = this.editingSubField();
10085
+ if (!context)
10086
+ return;
10087
+ const updatedSubField = {
10088
+ ...context.subField,
10089
+ type: updatedFieldData.type,
10090
+ fieldData: updatedFieldData
10091
+ };
10092
+ this.editingSubField.set({ ...context, subField: updatedSubField });
10093
+ this.editableBlocks.update(blocks => blocks.map(block => ({
10094
+ ...block,
10095
+ fields: block.fields.map(field => {
10096
+ if (field.code !== context.parentCode)
10097
+ return field;
10098
+ const updatedSubFields = (field.repeaterSubFields ?? []).map(sf => sf.code !== context.subField.code ? sf : updatedSubField);
10099
+ return { ...field, repeaterSubFields: updatedSubFields };
10100
+ })
10101
+ })));
9642
10102
  }
9643
10103
  startPropertiesResize(event) {
9644
10104
  event.preventDefault();
@@ -9687,7 +10147,10 @@ class UicUserFormbuilderComponent {
9687
10147
  cols: this.editableCols(),
9688
10148
  blocks: blocksWithOrderedFields.map(block => ({
9689
10149
  ...block,
9690
- fields: block.fields.map(({ field, ...restField }) => restField)
10150
+ fields: block.fields.map(({ field, ...restField }) => ({
10151
+ ...restField,
10152
+ repeaterSubFields: restField.repeaterSubFields?.map(({ field: _sf, ...sfRest }) => sfRest)
10153
+ }))
9691
10154
  }))
9692
10155
  });
9693
10156
  }
@@ -9788,6 +10251,22 @@ class UicUserFormbuilderComponent {
9788
10251
  };
9789
10252
  }
9790
10253
  }
10254
+ // Hydrate sub-fields for repeater
10255
+ if (hydratedField.repeaterSubFields?.length) {
10256
+ const hydratedSubFields = hydratedField.repeaterSubFields.map(sf => {
10257
+ if (sf.field)
10258
+ return sf;
10259
+ const sfConfig = FIELDS_CONFIG.find(c => c.value === sf.type);
10260
+ if (!sfConfig)
10261
+ return sf;
10262
+ changed = true;
10263
+ blockChanged = true;
10264
+ return { ...sf, field: sfConfig };
10265
+ });
10266
+ if (hydratedSubFields !== hydratedField.repeaterSubFields) {
10267
+ hydratedField = { ...hydratedField, repeaterSubFields: hydratedSubFields };
10268
+ }
10269
+ }
9791
10270
  const visibilityRules = hydratedField.fieldData.visibilityRules;
9792
10271
  if (!visibilityRules?.length)
9793
10272
  return hydratedField;
@@ -9861,7 +10340,7 @@ class UicUserFormbuilderComponent {
9861
10340
  return value;
9862
10341
  }
9863
10342
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: UicUserFormbuilderComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
9864
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.14", type: UicUserFormbuilderComponent, isStandalone: true, selector: "ui-user-formbuilder", inputs: { disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: false, isRequired: false, transformFunction: null }, formTitle: { classPropertyName: "formTitle", publicName: "formTitle", isSignal: false, isRequired: false, transformFunction: null }, optionSources: { classPropertyName: "optionSources", publicName: "optionSources", isSignal: false, isRequired: false, transformFunction: null }, selectOptionsResolver: { classPropertyName: "selectOptionsResolver", publicName: "selectOptionsResolver", isSignal: false, isRequired: false, transformFunction: null }, readOnly: { classPropertyName: "readOnly", publicName: "readOnly", isSignal: true, isRequired: false, transformFunction: null }, editableFormInput: { classPropertyName: "editableFormInput", publicName: "editableForm", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { submitFormRequest: "submitFormRequest" }, host: { listeners: { "document:mousemove": "onPropertiesResize($event)", "document:mouseup": "stopPropertiesResize()" } }, ngImport: i0, template: "<div class=\"formeditor\" [class.focused]=\"!isReadOnly()\">\r\n <div class=\"formeditor-header\">\r\n <div style=\"flex: 1 1;\">\r\n {{formTitle}} \r\n \r\n <div class=\"cols-selector\"> \r\n @if (isReadOnly()) {\r\n {{editableCols()}}\r\n }@else {\r\n <ui-select [options]=\"[{id: 1, text: '1'}, {id: 2, text: '2'}, {id: 3, text: '3'}, {id: 4, text: '4'}]\" [ngModel]=\"editableCols()\" (ngModelChange)=\"editableCols.set($event)\"></ui-select> \r\n }\r\n col(s)</div>\r\n </div>\r\n @if (isReadOnly()) {\r\n @if (!disabled) {\r\n <ui-button color=\"black\" icon=\"ri-edit-line\" text=\"Editar\" (click)=\"enableEditMode()\"></ui-button>\r\n }\r\n } @else {\r\n <ui-button color=\"black\" type=\"bordered\" icon=\"ri-eye-line\" [text]=\"'form_builder.preview_form' | uicTranslate\" (click)=\"printForm()\"></ui-button>\r\n <ui-button color=\"black\" type=\"bordered\" icon=\"ri-close-line\" text=\"Descartar cambios\" (click)=\"discardChanges()\"></ui-button>\r\n <ui-button color=\"black\" icon=\"ri-check-line\" [text]=\"'form_builder.submit_form' | uicTranslate\" (click)=\"submitForm()\"></ui-button>\r\n }\r\n </div>\r\n @if (!isReadOnly()) {\r\n <div class=\"formeditor-body\">\r\n \r\n <!-- BLOCKS -->\r\n <div class=\"formeditor-overflow\">\r\n <div class=\"formeditor-workarea\">\r\n @for (block of editableBlocks(); track block.code; let i = $index) {\r\n <lib-block-editor \n [block]=\"block\"\n [selectedFieldId]=\"selectedField()?.code ?? null\"\n [visibilityParentFieldCodes]=\"visibilityParentFieldCodes()\"\n (blockChange)=\"onBlockChange(i, $event)\"\n (addFieldRequest)=\"addField(block.code, $event)\"\n (notifySelectedField)=\"selectField($event)\"\n (deleteBlock)=\"deleteBlock($event)\">\n </lib-block-editor>\n }\r\n <ui-button type=\"bordered\" icon=\"ri-add-line\" color=\"black\" [text]=\"'form_builder.add_block' | uicTranslate\" (click)=\"addBlock()\"></ui-button>\r\n </div>\r\n </div>\r\n <!-- PROPERTIES -->\r\n <div class=\"formeditor-properties\" [style.width.px]=\"propertiesWidth()\">\n <div\n class=\"formeditor-properties-resize\"\n (mousedown)=\"startPropertiesResize($event)\">\n </div>\n <h3>Propiedades</h3>\n <div class=\"formeditor-properties-form\">\n @if (selectedField() ) {\r\n <lib-field-editor \n [config]=\"selectedField()!\"\n [focusRequiredField]=\"focusNewFieldCode() === selectedField()?.code\"\n [options]=\"dependencyOptions()\"\n (fieldChange)=\"onFieldChange($event)\">\n </lib-field-editor>\n }@else{\r\n <div class=\"no-selected-field\">\r\n <i class=\"ri-edit-box-line\"></i>\r\n <p>{{'form_builder.select_field_to_edit' | uicTranslate}}</p>\r\n </div>\r\n }\r\n </div>\r\n </div>\r\n </div>\r\n }@else {\r\n <div class=\"form-preview\">\r\n <ui-form-wrapper \n [schema]=\"previewSchema()\"\n [selectOptionsResolver]=\"selectOptionsResolver\"\n [showButtons]=\"false\">\n </ui-form-wrapper>\n </div>\r\n }\r\n </div>\r\n\r\n", styles: [".formeditor{display:flex;flex-direction:column;overflow:hidden;background-color:var(--grey-100);border:solid 1px var(--grey-300);border-radius:5px;max-height:500px}.formeditor-header{background-color:#fff;padding:5px 10px;align-items:center;display:flex;gap:10px;border-bottom:solid 1px var(--grey-300)}.formeditor-body{display:flex;gap:10px;overflow:hidden;padding:10px;min-height:0}.formeditor-overflow{padding:5px;flex:1 1;overflow:auto;min-width:0}.formeditor-workarea{display:flex;flex-direction:column;gap:15px;height:fit-content}.formeditor-properties{width:250px;flex:0 0 auto;display:flex;flex-direction:column;position:relative;background-color:#fff;border:solid 1px var(--grey-300);border-radius:5px;min-height:0;min-width:250px;max-width:600px}.formeditor-properties-resize{position:absolute;top:0;bottom:0;left:-6px;width:10px;cursor:col-resize;z-index:1}.formeditor-properties>h3{padding:10px;border-bottom:solid 1px var(--grey-300)}.formeditor-properties-form{padding:10px;overflow:auto;flex:1 1 auto;min-height:0}.form-preview{padding:20px;overflow:auto;background-color:#fff}.focused{border:solid 1px var(--primary-400);border-radius:10px;box-shadow:0 0 0 3px var(--secondary-alpha)}.no-selected-field{width:100%;display:flex;flex-direction:column;justify-content:center;align-items:center;padding:20px 0;font-size:13px;gap:15px;text-align:center;color:var(--grey-400)}.no-selected-field i{font-size:24px}.cols-selector{margin-left:8px;padding-left:8px;border-left:solid 1px var(--grey-400);display:inline-flex;align-items:center;gap:5px}\n"], dependencies: [{ kind: "component", type: UicButtonComponent, selector: "ui-button", inputs: ["text", "icon", "rightIcon", "iconOnly", "disabled", "loading", "size", "type", "color"] }, { kind: "component", type: UicFormWrapperComponent, selector: "ui-form-wrapper", inputs: ["schema", "fields", "cols", "externalData", "selectOptionsResolver", "loading", "disabled", "showButtons", "fillSelects", "initialValues", "focusFieldName", "focusFieldTrigger", "fileUidResolverFn"], outputs: ["formSubmit", "formChange", "optionsSourceError"] }, { kind: "pipe", type: UicTranslatePipe, name: "uicTranslate" }, { kind: "component", type: FieldEditorComponent, selector: "lib-field-editor", inputs: ["config", "focusRequiredField", "options"], outputs: ["fieldChange"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: BlockEditorComponent, selector: "lib-block-editor", inputs: ["block", "selectedFieldId", "visibilityParentFieldCodes"], outputs: ["blockChange", "addFieldRequest", "deleteBlock", "notifySelectedField"] }, { kind: "component", type: UicSelectComponent, selector: "ui-select", inputs: ["icon", "iconColor", "internalIcon", "internalIconColor", "size", "label", "error", "tip", "showSubtitle", "disabled", "nonSelectedText", "noneText", "emptyText", "searcherEnabled", "loading", "nullable", "options"] }] });
10343
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.14", type: UicUserFormbuilderComponent, isStandalone: true, selector: "ui-user-formbuilder", inputs: { disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: false, isRequired: false, transformFunction: null }, formTitle: { classPropertyName: "formTitle", publicName: "formTitle", isSignal: false, isRequired: false, transformFunction: null }, optionSources: { classPropertyName: "optionSources", publicName: "optionSources", isSignal: false, isRequired: false, transformFunction: null }, selectOptionsResolver: { classPropertyName: "selectOptionsResolver", publicName: "selectOptionsResolver", isSignal: false, isRequired: false, transformFunction: null }, readOnly: { classPropertyName: "readOnly", publicName: "readOnly", isSignal: true, isRequired: false, transformFunction: null }, editableFormInput: { classPropertyName: "editableFormInput", publicName: "editableForm", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { submitFormRequest: "submitFormRequest" }, host: { listeners: { "document:mousemove": "onPropertiesResize($event)", "document:mouseup": "stopPropertiesResize()" } }, ngImport: i0, template: "<div class=\"formeditor\" [class.focused]=\"!isReadOnly()\">\r\n <div class=\"formeditor-header\">\r\n <div style=\"flex: 1 1;\">\r\n {{formTitle}} \r\n \r\n <div class=\"cols-selector\"> \r\n @if (isReadOnly()) {\r\n {{editableCols()}}\r\n }@else {\r\n <ui-select [options]=\"[{id: 1, text: '1'}, {id: 2, text: '2'}, {id: 3, text: '3'}, {id: 4, text: '4'}]\" [ngModel]=\"editableCols()\" (ngModelChange)=\"editableCols.set($event)\"></ui-select> \r\n }\r\n col(s)</div>\r\n </div>\r\n @if (isReadOnly()) {\r\n @if (!disabled) {\r\n <ui-button color=\"black\" icon=\"ri-edit-line\" text=\"Editar\" (click)=\"enableEditMode()\"></ui-button>\r\n }\r\n } @else {\r\n <ui-button color=\"black\" type=\"bordered\" icon=\"ri-eye-line\" [text]=\"'form_builder.preview_form' | uicTranslate\" (click)=\"printForm()\"></ui-button>\r\n <ui-button color=\"black\" type=\"bordered\" icon=\"ri-close-line\" text=\"Descartar cambios\" (click)=\"discardChanges()\"></ui-button>\r\n <ui-button color=\"black\" icon=\"ri-check-line\" [text]=\"'form_builder.submit_form' | uicTranslate\" (click)=\"submitForm()\"></ui-button>\r\n }\r\n </div>\r\n @if (!isReadOnly()) {\r\n <div class=\"formeditor-body\">\r\n \r\n <!-- BLOCKS -->\r\n <div class=\"formeditor-overflow\">\r\n <div class=\"formeditor-workarea\">\r\n @for (block of editableBlocks(); track block.code; let i = $index) {\r\n <lib-block-editor \r\n [block]=\"block\"\r\n [selectedFieldId]=\"selectedField()?.code ?? null\"\r\n [selectedSubFieldCode]=\"editingSubField()?.subField?.code ?? null\"\r\n [visibilityParentFieldCodes]=\"visibilityParentFieldCodes()\"\r\n (blockChange)=\"onBlockChange(i, $event)\"\r\n (addFieldRequest)=\"addField(block.code, $event)\"\r\n (notifySelectedField)=\"selectField($event)\"\r\n (notifySelectedSubField)=\"onSelectSubField($event)\"\r\n (deleteBlock)=\"deleteBlock($event)\">\r\n </lib-block-editor>\r\n }\r\n <ui-button type=\"bordered\" icon=\"ri-add-line\" color=\"black\" [text]=\"'form_builder.add_block' | uicTranslate\" (click)=\"addBlock()\"></ui-button>\r\n </div>\r\n </div>\r\n <!-- PROPERTIES -->\r\n <div class=\"formeditor-properties\" [style.width.px]=\"propertiesWidth()\">\r\n <div\r\n class=\"formeditor-properties-resize\"\r\n (mousedown)=\"startPropertiesResize($event)\">\r\n </div>\r\n <h3>Propiedades</h3>\r\n <div class=\"formeditor-properties-form\">\r\n @if (editingSubField()) {\r\n <div class=\"subfield-back-header\">\r\n <i class=\"ri-stack-line\"></i>\r\n <span>{{editingSubField()!.subField.fieldData.label || editingSubField()!.subField.fieldData.name}}</span>\r\n </div>\r\n <lib-field-editor\r\n [config]=\"editingSubField()!.subField\"\r\n [isSubField]=\"true\"\r\n [options]=\"{}\"\r\n (fieldChange)=\"onSubFieldChange($event)\">\r\n </lib-field-editor>\r\n } @else if (selectedField()) {\r\n <lib-field-editor \r\n [config]=\"selectedField()!\"\r\n [focusRequiredField]=\"focusNewFieldCode() === selectedField()?.code\"\r\n [options]=\"dependencyOptions()\"\r\n (fieldChange)=\"onFieldChange($event)\">\r\n </lib-field-editor>\r\n }@else{\r\n <div class=\"no-selected-field\">\r\n <i class=\"ri-edit-box-line\"></i>\r\n <p>{{'form_builder.select_field_to_edit' | uicTranslate}}</p>\r\n </div>\r\n }\r\n </div>\r\n </div>\r\n </div>\r\n }@else {\r\n <div class=\"form-preview\">\r\n <ui-form-wrapper \r\n [schema]=\"previewSchema()\"\r\n [selectOptionsResolver]=\"selectOptionsResolver\"\r\n [showButtons]=\"false\">\r\n </ui-form-wrapper>\r\n </div>\r\n }\r\n </div>\r\n\r\n", styles: [".formeditor{display:flex;flex-direction:column;overflow:hidden;background-color:var(--grey-100);border:solid 1px var(--grey-300);border-radius:5px;max-height:500px}.formeditor-header{background-color:#fff;padding:5px 10px;align-items:center;display:flex;gap:10px;border-bottom:solid 1px var(--grey-300)}.formeditor-body{display:flex;gap:10px;overflow:hidden;padding:10px;min-height:0}.formeditor-overflow{padding:5px;flex:1 1;overflow:auto;min-width:0}.formeditor-workarea{display:flex;flex-direction:column;gap:15px;height:fit-content}.formeditor-properties{width:250px;flex:0 0 auto;display:flex;flex-direction:column;position:relative;background-color:#fff;border:solid 1px var(--grey-300);border-radius:5px;min-height:0;min-width:250px;max-width:600px}.formeditor-properties-resize{position:absolute;top:0;bottom:0;left:-6px;width:10px;cursor:col-resize;z-index:1}.formeditor-properties>h3{padding:10px;border-bottom:solid 1px var(--grey-300)}.formeditor-properties-form{padding:10px;overflow:auto;flex:1 1 auto;min-height:0}.form-preview{padding:20px;overflow:auto;background-color:#fff}.focused{border:solid 1px var(--primary-400);border-radius:10px;box-shadow:0 0 0 3px var(--secondary-alpha)}.no-selected-field{width:100%;display:flex;flex-direction:column;justify-content:center;align-items:center;padding:20px 0;font-size:13px;gap:15px;text-align:center;color:var(--grey-400)}.no-selected-field i{font-size:24px}.cols-selector{margin-left:8px;padding-left:8px;border-left:solid 1px var(--grey-400);display:inline-flex;align-items:center;gap:5px}.subfield-back-header{display:flex;align-items:center;gap:6px;padding:0 0 10px;border-bottom:solid 1px var(--grey-200);margin-bottom:10px;color:var(--grey-500);font-size:12px}.subfield-back-header i{font-size:14px;color:var(--primary-500)}.subfield-back-header span{font-weight:600;color:var(--grey-700);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}\n"], dependencies: [{ kind: "component", type: UicButtonComponent, selector: "ui-button", inputs: ["text", "icon", "rightIcon", "iconOnly", "disabled", "loading", "size", "type", "color"] }, { kind: "component", type: UicFormWrapperComponent, selector: "ui-form-wrapper", inputs: ["schema", "fields", "cols", "externalData", "selectOptionsResolver", "loading", "disabled", "showButtons", "fillSelects", "initialValues", "focusFieldName", "focusFieldTrigger", "fileUidResolverFn"], outputs: ["formSubmit", "formChange", "optionsSourceError"] }, { kind: "pipe", type: UicTranslatePipe, name: "uicTranslate" }, { kind: "component", type: FieldEditorComponent, selector: "lib-field-editor", inputs: ["config", "focusRequiredField", "isSubField", "options"], outputs: ["fieldChange"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: BlockEditorComponent, selector: "lib-block-editor", inputs: ["block", "selectedFieldId", "selectedSubFieldCode", "visibilityParentFieldCodes"], outputs: ["blockChange", "addFieldRequest", "deleteBlock", "notifySelectedField", "notifySelectedSubField"] }, { kind: "component", type: UicSelectComponent, selector: "ui-select", inputs: ["icon", "iconColor", "internalIcon", "internalIconColor", "size", "label", "error", "tip", "showSubtitle", "disabled", "nonSelectedText", "noneText", "emptyText", "searcherEnabled", "loading", "nullable", "options"] }] });
9865
10344
  }
9866
10345
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: UicUserFormbuilderComponent, decorators: [{
9867
10346
  type: Component,
@@ -9873,7 +10352,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImpo
9873
10352
  FormsModule,
9874
10353
  BlockEditorComponent,
9875
10354
  UicSelectComponent
9876
- ], template: "<div class=\"formeditor\" [class.focused]=\"!isReadOnly()\">\r\n <div class=\"formeditor-header\">\r\n <div style=\"flex: 1 1;\">\r\n {{formTitle}} \r\n \r\n <div class=\"cols-selector\"> \r\n @if (isReadOnly()) {\r\n {{editableCols()}}\r\n }@else {\r\n <ui-select [options]=\"[{id: 1, text: '1'}, {id: 2, text: '2'}, {id: 3, text: '3'}, {id: 4, text: '4'}]\" [ngModel]=\"editableCols()\" (ngModelChange)=\"editableCols.set($event)\"></ui-select> \r\n }\r\n col(s)</div>\r\n </div>\r\n @if (isReadOnly()) {\r\n @if (!disabled) {\r\n <ui-button color=\"black\" icon=\"ri-edit-line\" text=\"Editar\" (click)=\"enableEditMode()\"></ui-button>\r\n }\r\n } @else {\r\n <ui-button color=\"black\" type=\"bordered\" icon=\"ri-eye-line\" [text]=\"'form_builder.preview_form' | uicTranslate\" (click)=\"printForm()\"></ui-button>\r\n <ui-button color=\"black\" type=\"bordered\" icon=\"ri-close-line\" text=\"Descartar cambios\" (click)=\"discardChanges()\"></ui-button>\r\n <ui-button color=\"black\" icon=\"ri-check-line\" [text]=\"'form_builder.submit_form' | uicTranslate\" (click)=\"submitForm()\"></ui-button>\r\n }\r\n </div>\r\n @if (!isReadOnly()) {\r\n <div class=\"formeditor-body\">\r\n \r\n <!-- BLOCKS -->\r\n <div class=\"formeditor-overflow\">\r\n <div class=\"formeditor-workarea\">\r\n @for (block of editableBlocks(); track block.code; let i = $index) {\r\n <lib-block-editor \n [block]=\"block\"\n [selectedFieldId]=\"selectedField()?.code ?? null\"\n [visibilityParentFieldCodes]=\"visibilityParentFieldCodes()\"\n (blockChange)=\"onBlockChange(i, $event)\"\n (addFieldRequest)=\"addField(block.code, $event)\"\n (notifySelectedField)=\"selectField($event)\"\n (deleteBlock)=\"deleteBlock($event)\">\n </lib-block-editor>\n }\r\n <ui-button type=\"bordered\" icon=\"ri-add-line\" color=\"black\" [text]=\"'form_builder.add_block' | uicTranslate\" (click)=\"addBlock()\"></ui-button>\r\n </div>\r\n </div>\r\n <!-- PROPERTIES -->\r\n <div class=\"formeditor-properties\" [style.width.px]=\"propertiesWidth()\">\n <div\n class=\"formeditor-properties-resize\"\n (mousedown)=\"startPropertiesResize($event)\">\n </div>\n <h3>Propiedades</h3>\n <div class=\"formeditor-properties-form\">\n @if (selectedField() ) {\r\n <lib-field-editor \n [config]=\"selectedField()!\"\n [focusRequiredField]=\"focusNewFieldCode() === selectedField()?.code\"\n [options]=\"dependencyOptions()\"\n (fieldChange)=\"onFieldChange($event)\">\n </lib-field-editor>\n }@else{\r\n <div class=\"no-selected-field\">\r\n <i class=\"ri-edit-box-line\"></i>\r\n <p>{{'form_builder.select_field_to_edit' | uicTranslate}}</p>\r\n </div>\r\n }\r\n </div>\r\n </div>\r\n </div>\r\n }@else {\r\n <div class=\"form-preview\">\r\n <ui-form-wrapper \n [schema]=\"previewSchema()\"\n [selectOptionsResolver]=\"selectOptionsResolver\"\n [showButtons]=\"false\">\n </ui-form-wrapper>\n </div>\r\n }\r\n </div>\r\n\r\n", styles: [".formeditor{display:flex;flex-direction:column;overflow:hidden;background-color:var(--grey-100);border:solid 1px var(--grey-300);border-radius:5px;max-height:500px}.formeditor-header{background-color:#fff;padding:5px 10px;align-items:center;display:flex;gap:10px;border-bottom:solid 1px var(--grey-300)}.formeditor-body{display:flex;gap:10px;overflow:hidden;padding:10px;min-height:0}.formeditor-overflow{padding:5px;flex:1 1;overflow:auto;min-width:0}.formeditor-workarea{display:flex;flex-direction:column;gap:15px;height:fit-content}.formeditor-properties{width:250px;flex:0 0 auto;display:flex;flex-direction:column;position:relative;background-color:#fff;border:solid 1px var(--grey-300);border-radius:5px;min-height:0;min-width:250px;max-width:600px}.formeditor-properties-resize{position:absolute;top:0;bottom:0;left:-6px;width:10px;cursor:col-resize;z-index:1}.formeditor-properties>h3{padding:10px;border-bottom:solid 1px var(--grey-300)}.formeditor-properties-form{padding:10px;overflow:auto;flex:1 1 auto;min-height:0}.form-preview{padding:20px;overflow:auto;background-color:#fff}.focused{border:solid 1px var(--primary-400);border-radius:10px;box-shadow:0 0 0 3px var(--secondary-alpha)}.no-selected-field{width:100%;display:flex;flex-direction:column;justify-content:center;align-items:center;padding:20px 0;font-size:13px;gap:15px;text-align:center;color:var(--grey-400)}.no-selected-field i{font-size:24px}.cols-selector{margin-left:8px;padding-left:8px;border-left:solid 1px var(--grey-400);display:inline-flex;align-items:center;gap:5px}\n"] }]
10355
+ ], template: "<div class=\"formeditor\" [class.focused]=\"!isReadOnly()\">\r\n <div class=\"formeditor-header\">\r\n <div style=\"flex: 1 1;\">\r\n {{formTitle}} \r\n \r\n <div class=\"cols-selector\"> \r\n @if (isReadOnly()) {\r\n {{editableCols()}}\r\n }@else {\r\n <ui-select [options]=\"[{id: 1, text: '1'}, {id: 2, text: '2'}, {id: 3, text: '3'}, {id: 4, text: '4'}]\" [ngModel]=\"editableCols()\" (ngModelChange)=\"editableCols.set($event)\"></ui-select> \r\n }\r\n col(s)</div>\r\n </div>\r\n @if (isReadOnly()) {\r\n @if (!disabled) {\r\n <ui-button color=\"black\" icon=\"ri-edit-line\" text=\"Editar\" (click)=\"enableEditMode()\"></ui-button>\r\n }\r\n } @else {\r\n <ui-button color=\"black\" type=\"bordered\" icon=\"ri-eye-line\" [text]=\"'form_builder.preview_form' | uicTranslate\" (click)=\"printForm()\"></ui-button>\r\n <ui-button color=\"black\" type=\"bordered\" icon=\"ri-close-line\" text=\"Descartar cambios\" (click)=\"discardChanges()\"></ui-button>\r\n <ui-button color=\"black\" icon=\"ri-check-line\" [text]=\"'form_builder.submit_form' | uicTranslate\" (click)=\"submitForm()\"></ui-button>\r\n }\r\n </div>\r\n @if (!isReadOnly()) {\r\n <div class=\"formeditor-body\">\r\n \r\n <!-- BLOCKS -->\r\n <div class=\"formeditor-overflow\">\r\n <div class=\"formeditor-workarea\">\r\n @for (block of editableBlocks(); track block.code; let i = $index) {\r\n <lib-block-editor \r\n [block]=\"block\"\r\n [selectedFieldId]=\"selectedField()?.code ?? null\"\r\n [selectedSubFieldCode]=\"editingSubField()?.subField?.code ?? null\"\r\n [visibilityParentFieldCodes]=\"visibilityParentFieldCodes()\"\r\n (blockChange)=\"onBlockChange(i, $event)\"\r\n (addFieldRequest)=\"addField(block.code, $event)\"\r\n (notifySelectedField)=\"selectField($event)\"\r\n (notifySelectedSubField)=\"onSelectSubField($event)\"\r\n (deleteBlock)=\"deleteBlock($event)\">\r\n </lib-block-editor>\r\n }\r\n <ui-button type=\"bordered\" icon=\"ri-add-line\" color=\"black\" [text]=\"'form_builder.add_block' | uicTranslate\" (click)=\"addBlock()\"></ui-button>\r\n </div>\r\n </div>\r\n <!-- PROPERTIES -->\r\n <div class=\"formeditor-properties\" [style.width.px]=\"propertiesWidth()\">\r\n <div\r\n class=\"formeditor-properties-resize\"\r\n (mousedown)=\"startPropertiesResize($event)\">\r\n </div>\r\n <h3>Propiedades</h3>\r\n <div class=\"formeditor-properties-form\">\r\n @if (editingSubField()) {\r\n <div class=\"subfield-back-header\">\r\n <i class=\"ri-stack-line\"></i>\r\n <span>{{editingSubField()!.subField.fieldData.label || editingSubField()!.subField.fieldData.name}}</span>\r\n </div>\r\n <lib-field-editor\r\n [config]=\"editingSubField()!.subField\"\r\n [isSubField]=\"true\"\r\n [options]=\"{}\"\r\n (fieldChange)=\"onSubFieldChange($event)\">\r\n </lib-field-editor>\r\n } @else if (selectedField()) {\r\n <lib-field-editor \r\n [config]=\"selectedField()!\"\r\n [focusRequiredField]=\"focusNewFieldCode() === selectedField()?.code\"\r\n [options]=\"dependencyOptions()\"\r\n (fieldChange)=\"onFieldChange($event)\">\r\n </lib-field-editor>\r\n }@else{\r\n <div class=\"no-selected-field\">\r\n <i class=\"ri-edit-box-line\"></i>\r\n <p>{{'form_builder.select_field_to_edit' | uicTranslate}}</p>\r\n </div>\r\n }\r\n </div>\r\n </div>\r\n </div>\r\n }@else {\r\n <div class=\"form-preview\">\r\n <ui-form-wrapper \r\n [schema]=\"previewSchema()\"\r\n [selectOptionsResolver]=\"selectOptionsResolver\"\r\n [showButtons]=\"false\">\r\n </ui-form-wrapper>\r\n </div>\r\n }\r\n </div>\r\n\r\n", styles: [".formeditor{display:flex;flex-direction:column;overflow:hidden;background-color:var(--grey-100);border:solid 1px var(--grey-300);border-radius:5px;max-height:500px}.formeditor-header{background-color:#fff;padding:5px 10px;align-items:center;display:flex;gap:10px;border-bottom:solid 1px var(--grey-300)}.formeditor-body{display:flex;gap:10px;overflow:hidden;padding:10px;min-height:0}.formeditor-overflow{padding:5px;flex:1 1;overflow:auto;min-width:0}.formeditor-workarea{display:flex;flex-direction:column;gap:15px;height:fit-content}.formeditor-properties{width:250px;flex:0 0 auto;display:flex;flex-direction:column;position:relative;background-color:#fff;border:solid 1px var(--grey-300);border-radius:5px;min-height:0;min-width:250px;max-width:600px}.formeditor-properties-resize{position:absolute;top:0;bottom:0;left:-6px;width:10px;cursor:col-resize;z-index:1}.formeditor-properties>h3{padding:10px;border-bottom:solid 1px var(--grey-300)}.formeditor-properties-form{padding:10px;overflow:auto;flex:1 1 auto;min-height:0}.form-preview{padding:20px;overflow:auto;background-color:#fff}.focused{border:solid 1px var(--primary-400);border-radius:10px;box-shadow:0 0 0 3px var(--secondary-alpha)}.no-selected-field{width:100%;display:flex;flex-direction:column;justify-content:center;align-items:center;padding:20px 0;font-size:13px;gap:15px;text-align:center;color:var(--grey-400)}.no-selected-field i{font-size:24px}.cols-selector{margin-left:8px;padding-left:8px;border-left:solid 1px var(--grey-400);display:inline-flex;align-items:center;gap:5px}.subfield-back-header{display:flex;align-items:center;gap:6px;padding:0 0 10px;border-bottom:solid 1px var(--grey-200);margin-bottom:10px;color:var(--grey-500);font-size:12px}.subfield-back-header i{font-size:14px;color:var(--primary-500)}.subfield-back-header span{font-weight:600;color:var(--grey-700);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}\n"] }]
9877
10356
  }], ctorParameters: () => [], propDecorators: { disabled: [{
9878
10357
  type: Input
9879
10358
  }], formTitle: [{
@@ -10691,5 +11170,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImpo
10691
11170
  * Generated bundle index. Do not edit.
10692
11171
  */
10693
11172
 
10694
- export { BASE_FORM_FIELDS, BRANCH_FORM_FIELDS, DROPDOWN_OVERLAY_CONTROLS, EXTRA_FORM_FIELDS, FIELDS_CONFIG, FirstCapitalPipe, LAYOUT_FORM_FIELDS, MODAL_CLOSE_EVENT, MODAL_CLOSE_REQUEST, MODAL_COMPONENT, MODAL_CONFIG, MODAL_DATA, UIC_TRANSLATE_CONFIG, UiDropdownCloseDirective, UiModalRef, UicAccordionComponent, UicActionButtonComponent, UicAlertContainerComponent, UicButtonComponent, UicCheckboxComponent, UicDatePickerComponent, UicDropdownContainerComponent, UicEditableTableComponent, UicExcelTableComponent, UicFileInputComponent, UicFormWrapperComponent, UicInputComponent, UicKpiCardComponent, UicModalService, UicMultySearcherComponent, UicMultySelectComponent, UicNameInitsPipe, UicOverlayCardComponent, UicPhoneInputComponent, UicPoolOptionsComponent, UicPortletCardComponent, UicProgressBarComponent, UicPushAlertService, UicRadioComponent, UicRuleBuilderComponent, UicSearcherComponent, UicSelectComponent, UicShortTableComponent, UicSignaturePadComponent, UicSkeletonCardsComponent, UicSkeletonLoaderComponent, UicSliderComponent, UicStepTabsComponent, UicStepsFormComponent, UicSwichComponent, UicTableComponent, UicTabsButtonComponent, UicTagSelectorComponent, UicTextareaAutoresizeDirective, UicTextareaAutoresizeMaxRowsDirective, UicTextareaAutoresizeMinRowsDirective, UicTimePickerComponent, UicTinyAlertService, UicToolTipDirective, UicTranslatePipe, UicTranslateService, UicTreeAdminComponent, UicUserFormbuilderComponent, UicWorkPanelComponent, VISIBILITY_OPERATOR_OPTIONS, animatedRow, fadeAndRise, fadeBackdrop, helperFormMapFormdataToObject, helperShowFormFromBuilder, helperTableMapDatoToColums, highlightRow, isMobile, provideUicTranslateConfig, pushTop, sideModal, simpleFade };
11173
+ export { BASE_FORM_FIELDS, BRANCH_FORM_FIELDS, DROPDOWN_OVERLAY_CONTROLS, EXTRA_FORM_FIELDS, FIELDS_CONFIG, FirstCapitalPipe, LAYOUT_FORM_FIELDS, MODAL_CLOSE_EVENT, MODAL_CLOSE_REQUEST, MODAL_COMPONENT, MODAL_CONFIG, MODAL_DATA, UIC_TRANSLATE_CONFIG, UiDropdownCloseDirective, UiModalRef, UicAccordionComponent, UicActionButtonComponent, UicAlertContainerComponent, UicButtonComponent, UicCheckboxComponent, UicDatePickerComponent, UicDropdownContainerComponent, UicEditableTableComponent, UicExcelTableComponent, UicFileInputComponent, UicFormWrapperComponent, UicInputComponent, UicKpiCardComponent, UicModalService, UicMultySearcherComponent, UicMultySelectComponent, UicNameInitsPipe, UicOverlayCardComponent, UicPhoneInputComponent, UicPoolOptionsComponent, UicPortletCardComponent, UicProgressBarComponent, UicPushAlertService, UicRadioComponent, UicRepeaterComponent, UicRuleBuilderComponent, UicSearcherComponent, UicSelectComponent, UicShortTableComponent, UicSignaturePadComponent, UicSkeletonCardsComponent, UicSkeletonLoaderComponent, UicSliderComponent, UicStepTabsComponent, UicStepsFormComponent, UicSwichComponent, UicTableComponent, UicTabsButtonComponent, UicTagSelectorComponent, UicTextareaAutoresizeDirective, UicTextareaAutoresizeMaxRowsDirective, UicTextareaAutoresizeMinRowsDirective, UicTimePickerComponent, UicTinyAlertService, UicToolTipDirective, UicTranslatePipe, UicTranslateService, UicTreeAdminComponent, UicUserFormbuilderComponent, UicWorkPanelComponent, VISIBILITY_OPERATOR_OPTIONS, animatedRow, fadeAndRise, fadeBackdrop, helperFormMapFormdataToObject, helperShowFormFromBuilder, helperTableMapDatoToColums, highlightRow, isMobile, provideUicTranslateConfig, pushTop, sideModal, simpleFade };
10695
11174
  //# sourceMappingURL=ui-core-abv.mjs.map