superlikers-dynamic-forms 0.4.3 → 1.0.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.
@@ -1,94 +1,204 @@
1
1
  import * as i0 from '@angular/core';
2
- import { InjectionToken, inject, Injector, Pipe, Injectable, HostBinding, Input, ChangeDetectionStrategy, Component, ElementRef, ViewContainerRef, Directive } from '@angular/core';
3
- import { of, from, tap, distinctUntilChanged, map, merge, fromEvent, iif, EMPTY, startWith } from 'rxjs';
4
- import * as i2 from '@angular/forms';
5
- import { NgControl, ControlContainer, ReactiveFormsModule, FormControl, Validators, FormArray, FormGroup } from '@angular/forms';
6
- import * as i1 from '@angular/common';
7
- import { KeyValuePipe, CommonModule, AsyncPipe } from '@angular/common';
2
+ import { InjectionToken, Injectable, inject, input, ChangeDetectionStrategy, Component, Injector, signal, Pipe, ViewContainerRef, TemplateRef, computed, effect, Directive, ElementRef } from '@angular/core';
3
+ import * as i1 from '@angular/forms';
4
+ import { Validators, FormGroupDirective, NgControl, ControlContainer, FormBuilder, ReactiveFormsModule, FormControl, NonNullableFormBuilder, FormArray } from '@angular/forms';
5
+ import { of, from, tap, startWith, merge, fromEvent, iif, EMPTY, map as map$1, switchMap as switchMap$1, Observable } from 'rxjs';
6
+ import * as i4 from '@angular/common';
7
+ import { KeyValuePipe, NgComponentOutlet, AsyncPipe } from '@angular/common';
8
+ import { toSignal } from '@angular/core/rxjs-interop';
9
+ import * as i5 from '@angular/cdk/overlay';
10
+ import { OverlayModule } from '@angular/cdk/overlay';
11
+ import { startWith as startWith$1, debounceTime, map, distinctUntilChanged, switchMap } from 'rxjs/operators';
12
+ import { SelectionModel } from '@angular/cdk/collections';
8
13
 
9
- const CONTROL_DATA = new InjectionToken('Control Data');
14
+ /**
15
+ * Type guards for control types
16
+ */
17
+ function isInputControl(control) {
18
+ return control.controlType === 'input';
19
+ }
20
+ function isGroupControl(control) {
21
+ return control.controlType === 'group';
22
+ }
23
+ function isArrayControl(control) {
24
+ return control.controlType === 'array';
25
+ }
26
+ function isMultiSelectControl(control) {
27
+ return control.controlType === 'multi-select-dropdown';
28
+ }
29
+ function isAutocompleteControl(control) {
30
+ return control.controlType === 'autocomplete';
31
+ }
10
32
 
11
- class ControlInjector {
33
+ const CONTROL_DATA = new InjectionToken('CONTROL_DATA');
34
+
35
+ const DEFAULT_SETTINGS = {
36
+ wrapperClasses: 'field-wrapper',
37
+ labelClasses: 'field-label',
38
+ errorClasses: 'field-error',
39
+ helpTextClasses: 'field-help-text',
40
+ inputClasses: 'field-input',
41
+ validationFeedbackClasses: 'validation-feedback',
42
+ selectClasses: 'field-select',
43
+ selectOptionClasses: 'field-select-option',
44
+ checkboxWrapperClasses: 'checkbox-wrapper',
45
+ checkboxInputClasses: 'checkbox-input',
46
+ checkboxLabelTextClasses: 'checkbox-label',
47
+ checkboxGroupContainerClasses: 'checkbox-group-container',
48
+ checkboxGroupItemWrapperClasses: 'checkbox-group-item-wrapper',
49
+ checkboxGroupItemInputClasses: 'checkbox-group-item-input',
50
+ checkboxGroupItemLabelClasses: 'checkbox-group-item-label',
51
+ radioGroupContainerClasses: 'radio-group-container',
52
+ radioItemWrapperClasses: 'radio-item-wrapper',
53
+ radioItemInputClasses: 'radio-item-input',
54
+ radioItemLabelClasses: 'radio-item-label',
55
+ groupContainerClasses: 'group-container',
56
+ groupLegendClasses: 'group-legend',
57
+ legendClasses: 'legend',
58
+ arrayItemContainerClasses: 'array-item-container',
59
+ arrayControlRemoveButtonClasses: 'array-remove-button',
60
+ arrayControlAddButtonClasses: 'array-add-button',
61
+ arrayControlRemoveButtonLabel: 'Remove',
62
+ arrayControlAddButtonLabel: 'Add',
63
+ multiSelectControlRemoveButtonLabel: 'Remove',
64
+ multiSelectEmptyText: 'Select options',
65
+ multiSelectDisplayedOptionsClasses: 'multi-select-displayed-options',
66
+ multiSelectDisplayedOptionClasses: 'multi-select-displayed-option',
67
+ multiselectDropdownClasses: 'multi-select-dropdown',
68
+ multiselectDropdownItemClasses: 'multi-select-dropdown-item',
69
+ chipslistRemoveButtonLabel: 'Remove',
70
+ chipslistAddButtonLabel: 'Add',
71
+ chipslistInputClasses: 'chips-list-input',
72
+ chipslistContainerClasses: 'chips-list-container',
73
+ chipslistChipClasses: 'chips-list-chip',
74
+ chipslistAddWrapperClasses: 'chips-list-add-wrapper',
75
+ autocompleteInputClasses: 'autocomplete-input',
76
+ autocompleteDropdownClasses: 'autocomplete-dropdown',
77
+ autocompleteDropdownItemClasses: 'autocomplete-dropdown-item',
78
+ autocompleteLoadingText: 'Loading...',
79
+ autocompleteLoadingWrapperClasses: 'autocomplete-loading-wrapper'
80
+ };
81
+ const SETTINGS = new InjectionToken('Settings', {
82
+ providedIn: 'root',
83
+ factory: () => DEFAULT_SETTINGS
84
+ });
85
+
86
+ const ERROR_MESSAGES = {
87
+ required: () => `This field is required`,
88
+ requiredTrue: () => `This field is required`,
89
+ pattern: () => `Does not match the pattern`,
90
+ email: () => `Must be a valid email`,
91
+ minlength: args => `Length must be at least ${args?.['requiredLength']} characters`,
92
+ maxlength: args => `Length must not exceed ${args?.['requiredLength']} characters. Currently, it has ${args?.['actualLength']} characters.`,
93
+ min: args => `The value must be at least ${args?.['min']}`,
94
+ max: args => `The value must not exceed ${args?.['max']}`,
95
+ custom: error => String(error)
96
+ };
97
+ const SPANISH_ERROR_MESSAGES = {
98
+ required: () => `Este campo es obligatorio`,
99
+ requiredTrue: () => `Este campo es obligatorio`,
100
+ pattern: () => `No coincide con el patrón`,
101
+ email: () => `Debe ser un correo electrónico válido`,
102
+ minlength: args => `La longitud debe ser al menos ${args?.['requiredLength']} caracteres`,
103
+ maxlength: args => `La longitud no debe exceder los ${args?.['requiredLength']} caracteres. Actualmente tiene ${args?.['actualLength']} caracteres.`,
104
+ min: args => `El valor debe ser al menos ${args?.['min']}`,
105
+ max: args => `El valor no debe exceder ${args?.['max']}`,
106
+ custom: error => String(error)
107
+ };
108
+ const VALIDATION_ERROR_MESSAGES = new InjectionToken('Validation Messages', {
109
+ providedIn: 'root',
110
+ factory: () => ERROR_MESSAGES
111
+ });
112
+
113
+ class ValidatorsService {
12
114
  constructor() {
13
- this.injector = inject(Injector);
115
+ this.validatorStrategies = {
116
+ customValidation: (value) => {
117
+ if (typeof value === 'function') {
118
+ return [value];
119
+ }
120
+ if (Array.isArray(value)) {
121
+ return value.filter((fn) => typeof fn === 'function');
122
+ }
123
+ return [];
124
+ },
125
+ pattern: (value) => {
126
+ if (typeof value === 'string' || value instanceof RegExp) {
127
+ return [Validators.pattern(value)];
128
+ }
129
+ return [];
130
+ },
131
+ max: (value) => {
132
+ return typeof value === 'number' ? [Validators.max(value)] : [];
133
+ },
134
+ min: (value) => {
135
+ return typeof value === 'number' ? [Validators.min(value)] : [];
136
+ },
137
+ maxLength: (value) => {
138
+ return typeof value === 'number' ? [Validators.maxLength(value)] : [];
139
+ },
140
+ minLength: (value) => {
141
+ return typeof value === 'number' ? [Validators.minLength(value)] : [];
142
+ },
143
+ requiredTrue: () => {
144
+ return [Validators.requiredTrue];
145
+ },
146
+ email: () => {
147
+ return [Validators.email];
148
+ },
149
+ required: () => {
150
+ return [Validators.required];
151
+ }
152
+ };
14
153
  }
15
- transform(name, control, formGroup, index) {
16
- return Injector.create({
17
- parent: this.injector,
18
- providers: [
19
- {
20
- provide: CONTROL_DATA,
21
- useValue: { key: name, control, formGroup, index }
154
+ resolveValidators({ validators = {} }) {
155
+ const validatorFns = [];
156
+ for (const key in validators) {
157
+ if (Object.prototype.hasOwnProperty.call(validators, key)) {
158
+ const typedKey = key;
159
+ const strategy = this.validatorStrategies[typedKey];
160
+ if (strategy) {
161
+ const value = validators[typedKey];
162
+ const fns = strategy(value);
163
+ validatorFns.push(...fns);
22
164
  }
23
- ]
24
- });
165
+ }
166
+ }
167
+ return validatorFns.length > 0 ? Validators.compose(validatorFns) : null;
25
168
  }
26
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.1", ngImport: i0, type: ControlInjector, deps: [], target: i0.ɵɵFactoryTarget.Pipe }); }
27
- static { this.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "20.3.1", ngImport: i0, type: ControlInjector, isStandalone: true, name: "controlInjector" }); }
169
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.1", ngImport: i0, type: ValidatorsService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
170
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.1", ngImport: i0, type: ValidatorsService, providedIn: 'root' }); }
28
171
  }
29
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.1", ngImport: i0, type: ControlInjector, decorators: [{
30
- type: Pipe,
172
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.1", ngImport: i0, type: ValidatorsService, decorators: [{
173
+ type: Injectable,
31
174
  args: [{
32
- name: 'controlInjector',
33
- standalone: true
175
+ providedIn: 'root'
34
176
  }]
35
177
  }] });
36
178
 
37
- var ControlTypeValues;
38
- (function (ControlTypeValues) {
39
- ControlTypeValues["INPUT"] = "input";
40
- ControlTypeValues["GROUP"] = "group";
41
- ControlTypeValues["CHECKBOX"] = "checkbox";
42
- ControlTypeValues["CHECKBOX_GROUP"] = "checkbox-group";
43
- ControlTypeValues["RADIO"] = "radio";
44
- ControlTypeValues["SELECT"] = "select";
45
- })(ControlTypeValues || (ControlTypeValues = {}));
46
-
47
179
  class ControlResolver {
48
180
  constructor() {
49
181
  this.lazyControlComponents = {
50
182
  input: () => Promise.resolve().then(function () { return inputField_component; }).then(c => c.InputFieldComponent),
51
- group: () => Promise.resolve().then(function () { return groupField_component; }).then(c => c.GroupFieldComponent),
52
183
  radio: () => Promise.resolve().then(function () { return radioField_component; }).then(c => c.RadioFieldComponent),
53
184
  checkbox: () => Promise.resolve().then(function () { return checkboxField_component; }).then(c => c.CheckboxFieldComponent),
185
+ select: () => Promise.resolve().then(function () { return selectField_component; }).then(c => c.SelectFieldComponent),
186
+ group: () => Promise.resolve().then(function () { return groupField_component; }).then(c => c.GroupFieldComponent),
187
+ array: () => Promise.resolve().then(function () { return arrayField_component; }).then(c => c.ArrayFieldComponent),
188
+ autocomplete: () => Promise.resolve().then(function () { return autocompleteField_component; }).then(c => c.AutocompleteFieldComponent),
54
189
  'checkbox-group': () => Promise.resolve().then(function () { return checkboxGroupField_component; }).then(c => c.CheckboxGroupFieldComponent),
55
- select: () => import('./superlikers-dynamic-forms-select-field.component-D6Qy_SzE.mjs').then(c => c.SelectFieldComponent)
190
+ 'multi-select-dropdown': () => Promise.resolve().then(function () { return multiSelectDropdown_component; }).then(c => c.MultiSelectDropdownComponent),
191
+ 'chips-list': () => Promise.resolve().then(function () { return chipsListField_component; }).then(c => c.ChipsListFieldComponent)
56
192
  };
57
193
  this.loadedControlComponents = new Map();
58
194
  }
59
- resolve(control, form) {
195
+ resolve(control) {
60
196
  const controlType = control.controlType;
61
- const isVisible = this.checkVisible(control, form);
62
- if (!isVisible)
63
- return;
64
197
  const loadedComponent = this.loadedControlComponents.get(controlType);
65
- if (loadedComponent)
198
+ if (loadedComponent) {
66
199
  return of(loadedComponent);
67
- return from(this.lazyControlComponents[controlType]()).pipe(tap(component => {
68
- this.loadedControlComponents.set(controlType, component);
69
- }));
70
- }
71
- checkVisible(control, form) {
72
- if (!control.visible)
73
- return true;
74
- return control.visible(form);
75
- }
76
- toggleControlDisability(controls, form) {
77
- return form.valueChanges.pipe(distinctUntilChanged((prev, current) => {
78
- return JSON.stringify(prev) === JSON.stringify(current);
79
- }), map(() => {
80
- controls.forEach(control => {
81
- if (control.disabled) {
82
- const disabled = control.disabled(form);
83
- if (disabled) {
84
- form.get(control.name)?.disable();
85
- }
86
- else {
87
- form.get(control.name)?.enable();
88
- }
89
- }
90
- });
91
- }));
200
+ }
201
+ return from(this.lazyControlComponents[controlType]()).pipe(tap(component => this.loadedControlComponents.set(controlType, component)));
92
202
  }
93
203
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.1", ngImport: i0, type: ControlResolver, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
94
204
  static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.1", ngImport: i0, type: ControlResolver, providedIn: 'root' }); }
@@ -100,181 +210,163 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.1", ngImpor
100
210
  }]
101
211
  }] });
102
212
 
103
- /* eslint-disable @typescript-eslint/no-explicit-any */
104
- const ERROR_MESSAGES = {
105
- required: () => `This field is required`,
106
- requiredTrue: () => `This field is required`,
107
- pattern: () => `Does not match the pattern`,
108
- email: () => `Must be a valid email`,
109
- minlength: ({ requiredLength }) => `Length must be at least ${requiredLength} characters`,
110
- customError: error => error
111
- };
112
- const ERROR_MESSAGES_ES = {
113
- required: () => `Este campo es obligatorio`,
114
- requiredTrue: () => `Este campo es obligatorio`,
115
- pattern: () => `No coincide con el patrón`,
116
- email: () => `Debe ser un correo electrónico válido`,
117
- minlength: ({ requiredLength }) => `La longitud debe ser al menos de ${requiredLength} caracteres`,
118
- customError: error => error
119
- };
120
- const VALIDATION_ERROR_MESSAGES = new InjectionToken(`Validation Messages`, {
121
- providedIn: 'root',
122
- factory: () => ERROR_MESSAGES
123
- });
124
-
125
- /* eslint-disable @typescript-eslint/no-explicit-any */
126
- class ErrorsComponent {
213
+ class ErrorMessageComponent {
127
214
  constructor() {
128
- this.errors = null;
129
- this.hostClass = '';
215
+ this.settings = inject(SETTINGS);
130
216
  this.errorsMap = inject(VALIDATION_ERROR_MESSAGES);
217
+ this.errors = input(...(ngDevMode ? [undefined, { debugName: "errors" }] : []));
131
218
  }
132
219
  getError(error) {
133
220
  if (!this.errorsMap[error.key]) {
134
- console.warn(`missing message for ${error.key}`);
135
221
  return;
136
222
  }
137
- return this.errorsMap[error.key](error.value);
223
+ const message = this.errorsMap[error.key](error.value);
224
+ return message;
138
225
  }
139
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.1", ngImport: i0, type: ErrorsComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
140
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.1", type: ErrorsComponent, isStandalone: true, selector: "app-errors", inputs: { errors: "errors" }, host: { properties: { "class": "this.hostClass" } }, ngImport: i0, template: `
141
- @for (error of errors | keyvalue; track error.key) {
142
- <div class="error-text">{{ getError(error) }}</div>
226
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.1", ngImport: i0, type: ErrorMessageComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
227
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.1", type: ErrorMessageComponent, isStandalone: true, selector: "error-message", inputs: { errors: { classPropertyName: "errors", publicName: "errors", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: `
228
+ @for (error of errors() | keyvalue; track error.key) {
229
+ <p [class]="settings.errorClasses">{{ getError(error) }}</p>
143
230
  }
144
231
  `, isInline: true, dependencies: [{ kind: "pipe", type: KeyValuePipe, name: "keyvalue" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
145
232
  }
146
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.1", ngImport: i0, type: ErrorsComponent, decorators: [{
233
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.1", ngImport: i0, type: ErrorMessageComponent, decorators: [{
147
234
  type: Component,
148
235
  args: [{
149
- selector: 'app-errors',
236
+ selector: 'error-message',
150
237
  imports: [KeyValuePipe],
151
- changeDetection: ChangeDetectionStrategy.OnPush,
152
238
  template: `
153
- @for (error of errors | keyvalue; track error.key) {
154
- <div class="error-text">{{ getError(error) }}</div>
239
+ @for (error of errors() | keyvalue; track error.key) {
240
+ <p [class]="settings.errorClasses">{{ getError(error) }}</p>
155
241
  }
156
242
  `,
157
- standalone: true
243
+ changeDetection: ChangeDetectionStrategy.OnPush
158
244
  }]
159
- }], propDecorators: { errors: [{
160
- type: Input
161
- }], hostClass: [{
162
- type: HostBinding,
163
- args: ['class']
164
- }] } });
245
+ }] });
165
246
 
166
- class ValidatorMessageDirective {
247
+ class ControlInjector {
167
248
  constructor() {
168
- this.ngControl = inject(NgControl, { self: true });
169
- this.elementRef = inject(ElementRef);
170
- this.componentRef = null;
171
- this.parentContainer = inject(ControlContainer, { optional: true });
172
- this.vcr = inject(ViewContainerRef);
173
- }
174
- get form() {
175
- return this.parentContainer?.formDirective;
249
+ this.injector = inject(Injector);
176
250
  }
177
- ngOnInit() {
178
- if (!this.ngControl.control)
179
- return;
180
- this.controlSubscription = merge(this.ngControl.control.statusChanges, fromEvent(this.elementRef.nativeElement, 'blur'), iif(() => !!this.form, this.form.ngSubmit, EMPTY))
181
- .pipe(startWith(this.ngControl.control.status))
182
- .subscribe(() => {
183
- if (this.ngControl.errors && this.form?.submitted) {
184
- if (this.componentRef)
185
- return;
186
- this.componentRef = this.vcr.createComponent(ErrorsComponent);
187
- this.componentRef.changeDetectorRef.markForCheck();
188
- this.componentRef.setInput('errors', this.ngControl.errors);
189
- }
190
- else {
191
- this.componentRef?.destroy();
192
- this.componentRef = null;
193
- }
251
+ transform(control, initialValues) {
252
+ const controlPatchValue = initialValues?.[control.name];
253
+ const data = { control, initialValue: controlPatchValue };
254
+ return Injector.create({
255
+ parent: this.injector,
256
+ providers: [
257
+ {
258
+ provide: CONTROL_DATA,
259
+ useValue: signal(data)
260
+ }
261
+ ]
194
262
  });
195
263
  }
196
- ngOnDestroy() {
197
- this.controlSubscription.unsubscribe();
198
- }
199
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.1", ngImport: i0, type: ValidatorMessageDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
200
- static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.3.1", type: ValidatorMessageDirective, isStandalone: true, selector: "[appValidatorMessage]", ngImport: i0 }); }
264
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.1", ngImport: i0, type: ControlInjector, deps: [], target: i0.ɵɵFactoryTarget.Pipe }); }
265
+ static { this.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "20.3.1", ngImport: i0, type: ControlInjector, isStandalone: true, name: "controlInjector" }); }
201
266
  }
202
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.1", ngImport: i0, type: ValidatorMessageDirective, decorators: [{
203
- type: Directive,
267
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.1", ngImport: i0, type: ControlInjector, decorators: [{
268
+ type: Pipe,
204
269
  args: [{
205
- selector: '[appValidatorMessage]',
206
- standalone: true
270
+ name: 'controlInjector'
207
271
  }]
208
272
  }] });
209
273
 
210
- class HelpTextComponent {
274
+ class ActivateControlDirective {
211
275
  constructor() {
212
- this.message = '';
276
+ this.activateControl = input(...(ngDevMode ? [undefined, { debugName: "activateControl" }] : []));
277
+ this.vcr = inject(ViewContainerRef);
278
+ this.templateRef = inject(TemplateRef);
279
+ this.rootFormGroup = inject(FormGroupDirective).form;
280
+ // ✅ Convertir valueChanges a signal
281
+ this.formValue = toSignal(this.rootFormGroup.valueChanges.pipe(startWith(this.rootFormGroup.value)), {
282
+ initialValue: this.rootFormGroup.value
283
+ });
284
+ // ✅ Computed para visibilidad
285
+ this.isVisible = computed(() => {
286
+ // Trigger reactivity cuando cambia el form
287
+ const _ = this.formValue();
288
+ const visible = this.activateControl()?.visible;
289
+ if (visible === undefined) {
290
+ return true;
291
+ }
292
+ if (typeof visible === 'function') {
293
+ return visible(this.rootFormGroup);
294
+ }
295
+ return visible;
296
+ }, ...(ngDevMode ? [{ debugName: "isVisible" }] : []));
297
+ // ✅ Effect para manejar el DOM
298
+ effect(() => {
299
+ const visible = this.isVisible();
300
+ if (visible) {
301
+ if (this.vcr.length === 0) {
302
+ this.vcr.createEmbeddedView(this.templateRef);
303
+ }
304
+ }
305
+ else {
306
+ if (this.vcr.length > 0) {
307
+ this.vcr.clear();
308
+ }
309
+ }
310
+ });
213
311
  }
214
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.1", ngImport: i0, type: HelpTextComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
215
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.1", type: HelpTextComponent, isStandalone: true, selector: "app-help-text", inputs: { message: "message" }, ngImport: i0, template: '<p class="help-text">{{ message }}</p>', isInline: true }); }
312
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.1", ngImport: i0, type: ActivateControlDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
313
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "20.3.1", type: ActivateControlDirective, isStandalone: true, selector: "[activateControl]", inputs: { activateControl: { classPropertyName: "activateControl", publicName: "activateControl", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0 }); }
216
314
  }
217
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.1", ngImport: i0, type: HelpTextComponent, decorators: [{
218
- type: Component,
315
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.1", ngImport: i0, type: ActivateControlDirective, decorators: [{
316
+ type: Directive,
219
317
  args: [{
220
- selector: 'app-help-text',
221
- imports: [],
222
- template: '<p class="help-text">{{ message }}</p>',
223
- standalone: true
318
+ selector: '[activateControl]'
224
319
  }]
225
- }], propDecorators: { message: [{
226
- type: Input
227
- }] } });
320
+ }], ctorParameters: () => [] });
228
321
 
229
322
  class HelpTextDirective {
230
323
  constructor() {
231
- this.message = '';
324
+ this.helpMessage = input(...(ngDevMode ? [undefined, { debugName: "helpMessage" }] : []));
232
325
  this.elementRef = inject(ElementRef);
233
326
  this.vcr = inject(ViewContainerRef);
234
327
  this.componentRef = null;
235
328
  }
236
329
  ngOnInit() {
237
- if (!this.message)
330
+ if (!this.helpMessage()) {
238
331
  return;
332
+ }
239
333
  this.componentRef = this.vcr.createComponent(HelpTextComponent);
240
- this.componentRef.setInput('message', this.message);
334
+ this.componentRef.setInput('message', this.helpMessage());
241
335
  }
242
336
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.1", ngImport: i0, type: HelpTextDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
243
- static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.3.1", type: HelpTextDirective, isStandalone: true, selector: "[appHelpText]", inputs: { message: "message" }, ngImport: i0 }); }
337
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "20.3.1", type: HelpTextDirective, isStandalone: true, selector: "[helpMessage]", inputs: { helpMessage: { classPropertyName: "helpMessage", publicName: "helpMessage", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0 }); }
244
338
  }
245
339
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.1", ngImport: i0, type: HelpTextDirective, decorators: [{
246
340
  type: Directive,
247
341
  args: [{
248
- selector: '[appHelpText]',
249
- standalone: true
342
+ selector: '[helpMessage]'
250
343
  }]
251
- }], propDecorators: { message: [{
252
- type: Input
253
- }] } });
344
+ }] });
254
345
 
255
- class ValidatorArrayMessageDirective {
346
+ class ValidatorMessageDirective {
256
347
  constructor() {
257
- this.parentContainer = inject(ControlContainer);
258
- this.vcr = inject(ViewContainerRef);
348
+ this.ngControl = inject(NgControl, { self: true });
259
349
  this.elementRef = inject(ElementRef);
350
+ this.vcr = inject(ViewContainerRef);
351
+ this.parentContainer = inject(ControlContainer, { optional: true });
260
352
  this.componentRef = null;
261
353
  }
262
354
  get form() {
263
355
  return this.parentContainer?.formDirective;
264
356
  }
265
357
  ngOnInit() {
266
- const formArray = this.parentContainer.control;
267
- if (!formArray)
358
+ const control = this.ngControl.control;
359
+ if (!control) {
268
360
  return;
269
- this.controlSubscription = merge(formArray.statusChanges, fromEvent(this.elementRef.nativeElement, 'blur'), iif(() => !!this.form, this.form.ngSubmit, EMPTY))
270
- .pipe(startWith(formArray.status))
361
+ }
362
+ this.controlSubscription = merge(control.statusChanges, fromEvent(this.elementRef.nativeElement, 'blur'), iif(() => !!this.form, this.form.ngSubmit, EMPTY))
363
+ .pipe(startWith(control.status))
271
364
  .subscribe(() => {
272
- if (formArray.errors && this.form?.submitted) {
273
- if (this.componentRef)
274
- return;
275
- this.componentRef = this.vcr.createComponent(ErrorsComponent);
276
- this.componentRef.changeDetectorRef.markForCheck();
277
- this.componentRef.setInput('errors', formArray.errors);
365
+ if (control.errors && (control.touched || this.form?.submitted)) {
366
+ if (!this.componentRef) {
367
+ this.componentRef = this.vcr.createComponent(ErrorMessageComponent);
368
+ }
369
+ this.componentRef.setInput('errors', control.errors);
278
370
  }
279
371
  else {
280
372
  this.componentRef?.destroy();
@@ -283,103 +375,335 @@ class ValidatorArrayMessageDirective {
283
375
  });
284
376
  }
285
377
  ngOnDestroy() {
286
- this.controlSubscription?.unsubscribe();
378
+ this.controlSubscription.unsubscribe();
287
379
  }
288
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.1", ngImport: i0, type: ValidatorArrayMessageDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
289
- static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.3.1", type: ValidatorArrayMessageDirective, isStandalone: true, selector: "[appValidatorArrayMessage]", ngImport: i0 }); }
380
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.1", ngImport: i0, type: ValidatorMessageDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
381
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.3.1", type: ValidatorMessageDirective, isStandalone: true, selector: "[validatorMessage]", ngImport: i0 }); }
290
382
  }
291
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.1", ngImport: i0, type: ValidatorArrayMessageDirective, decorators: [{
383
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.1", ngImport: i0, type: ValidatorMessageDirective, decorators: [{
292
384
  type: Directive,
293
385
  args: [{
294
- selector: '[appValidatorArrayMessage]',
295
- standalone: true
386
+ selector: '[validatorMessage]'
387
+ }]
388
+ }] });
389
+
390
+ class FieldsComponent {
391
+ constructor() {
392
+ this.controls = input.required(...(ngDevMode ? [{ debugName: "controls" }] : []));
393
+ this.data = input(...(ngDevMode ? [undefined, { debugName: "data" }] : []));
394
+ this.fb = inject(FormBuilder);
395
+ this.controlResolver = inject(ControlResolver);
396
+ this.controlContainer = inject(ControlContainer);
397
+ }
398
+ get form() {
399
+ return this.controlContainer.control;
400
+ }
401
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.1", ngImport: i0, type: FieldsComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
402
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.1", type: FieldsComponent, isStandalone: true, selector: "fields", inputs: { controls: { classPropertyName: "controls", publicName: "controls", isSignal: true, isRequired: true, transformFunction: null }, data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: `
403
+ @for (control of controls(); track control.name) {
404
+ <ng-container
405
+ *activateControl="control"
406
+ [ngComponentOutlet]="controlResolver.resolve(control) | async"
407
+ [ngComponentOutletInjector]="control | controlInjector: data()" />
408
+ }
409
+ `, isInline: true, dependencies: [{ kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: NgComponentOutlet, selector: "[ngComponentOutlet]", inputs: ["ngComponentOutlet", "ngComponentOutletInputs", "ngComponentOutletInjector", "ngComponentOutletEnvironmentInjector", "ngComponentOutletContent", "ngComponentOutletNgModule", "ngComponentOutletNgModuleFactory"], exportAs: ["ngComponentOutlet"] }, { kind: "directive", type: ActivateControlDirective, selector: "[activateControl]", inputs: ["activateControl"] }, { kind: "pipe", type: ControlInjector, name: "controlInjector" }, { kind: "pipe", type: AsyncPipe, name: "async" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
410
+ }
411
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.1", ngImport: i0, type: FieldsComponent, decorators: [{
412
+ type: Component,
413
+ args: [{
414
+ selector: 'fields',
415
+ imports: [ReactiveFormsModule, NgComponentOutlet, ControlInjector, AsyncPipe, ActivateControlDirective],
416
+ template: `
417
+ @for (control of controls(); track control.name) {
418
+ <ng-container
419
+ *activateControl="control"
420
+ [ngComponentOutlet]="controlResolver.resolve(control) | async"
421
+ [ngComponentOutletInjector]="control | controlInjector: data()" />
422
+ }
423
+ `,
424
+ changeDetection: ChangeDetectionStrategy.OnPush
425
+ }]
426
+ }] });
427
+
428
+ class HelpTextComponent {
429
+ constructor() {
430
+ this.settings = inject(SETTINGS);
431
+ this.message = input(...(ngDevMode ? [undefined, { debugName: "message" }] : []));
432
+ }
433
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.1", ngImport: i0, type: HelpTextComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
434
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "20.3.1", type: HelpTextComponent, isStandalone: true, selector: "help-text", inputs: { message: { classPropertyName: "message", publicName: "message", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: `<p [class]="settings.helpTextClasses">{{ message() }}</p>`, isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
435
+ }
436
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.1", ngImport: i0, type: HelpTextComponent, decorators: [{
437
+ type: Component,
438
+ args: [{
439
+ selector: 'help-text',
440
+ template: `<p [class]="settings.helpTextClasses">{{ message() }}</p>`,
441
+ changeDetection: ChangeDetectionStrategy.OnPush
296
442
  }]
297
443
  }] });
298
444
 
299
- const sharedControlDeps = [CommonModule, ReactiveFormsModule, ValidatorMessageDirective, HelpTextDirective, ValidatorArrayMessageDirective, AsyncPipe];
300
445
  const controlProvider = {
301
446
  provide: ControlContainer,
302
447
  useFactory: () => inject(ControlContainer, { skipSelf: true })
303
448
  };
304
- class BaseControlComponent {
449
+ const controlDeps = [ReactiveFormsModule, HelpTextDirective, ValidatorMessageDirective, NgComponentOutlet, ControlInjector, ActivateControlDirective];
450
+ class BaseInputComponent {
305
451
  constructor() {
306
- this.hostClass = '';
307
- this.control = inject(CONTROL_DATA);
308
- this.formControl = new FormControl(this.control.control.value, this.resolveValidators(this.control.control));
309
- this.id = this.control.control.name + this.control.control.id + (this.control.index ?? '');
310
- this.parentGroupDir = inject(ControlContainer);
311
- }
312
- get parentFormGroup() {
313
- return this.parentGroupDir.control;
452
+ this.settings = inject(SETTINGS);
453
+ this.hostClass = signal('', ...(ngDevMode ? [{ debugName: "hostClass" }] : []));
454
+ // Injections
455
+ this.controlData = inject(CONTROL_DATA);
456
+ this.validatorsService = inject(ValidatorsService);
457
+ this.controlContainer = inject(ControlContainer);
458
+ // Computed signals
459
+ this.control = computed(() => this.controlData().control, ...(ngDevMode ? [{ debugName: "control" }] : []));
460
+ this.value = computed(() => this.controlData().initialValue ?? this.control().value, ...(ngDevMode ? [{ debugName: "value" }] : []));
461
+ // Form control
462
+ this.validatorFn = this.validatorsService.resolveValidators(this.control());
463
+ this.formControl = new FormControl(this.value(), this.validatorFn);
464
+ this.parentForm = this.controlContainer.control;
465
+ this.formValue = toSignal(this.parentForm.valueChanges.pipe(startWith(this.parentForm.value)), {
466
+ initialValue: this.parentForm.value
467
+ });
468
+ this.options = computed(() => {
469
+ const _ = this.formValue();
470
+ const optionsFn = this.control().options;
471
+ if (!optionsFn) {
472
+ return [];
473
+ }
474
+ if (Array.isArray(optionsFn)) {
475
+ return optionsFn;
476
+ }
477
+ const result = optionsFn(this.parentForm);
478
+ if (Array.isArray(result)) {
479
+ return result;
480
+ }
481
+ return [];
482
+ }, ...(ngDevMode ? [{ debugName: "options" }] : []));
483
+ this.isDisabled = computed(() => {
484
+ const _ = this.formValue();
485
+ const control = this.control();
486
+ if (control.disabled === undefined) {
487
+ return false;
488
+ }
489
+ if (typeof control.disabled === 'boolean') {
490
+ return control.disabled;
491
+ }
492
+ if (typeof control.disabled === 'function') {
493
+ return control.disabled(this.parentForm);
494
+ }
495
+ return false;
496
+ }, ...(ngDevMode ? [{ debugName: "isDisabled" }] : []));
497
+ effect(() => {
498
+ const disabled = this.isDisabled();
499
+ if (disabled && !this.formControl.disabled) {
500
+ this.formControl.disable({ emitEvent: false });
501
+ }
502
+ else if (!disabled && this.formControl.disabled) {
503
+ this.formControl.enable({ emitEvent: false });
504
+ }
505
+ });
314
506
  }
315
507
  ngOnInit() {
316
508
  this.initialize();
317
509
  }
318
- ngOnDestroy() {
319
- this.destroy();
320
- }
321
510
  initialize() {
322
- if (this.control.formGroup) {
323
- this.control.formGroup.addControl(this.control.control.name, this.formControl);
511
+ const control = this.control();
512
+ const classes = this.settings.wrapperClasses ?? `field wrapper-${control.name}`;
513
+ this.hostClass.set(classes);
514
+ this.parentForm.addControl(control.name, this.formControl);
515
+ }
516
+ destroy() {
517
+ const control = this.control();
518
+ if (this.parentForm.contains(control.name)) {
519
+ this.parentForm.removeControl(control.name);
324
520
  }
325
- else {
326
- this.parentFormGroup.addControl(this.control.control.name, this.formControl);
521
+ }
522
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.1", ngImport: i0, type: BaseInputComponent, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
523
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.3.1", type: BaseInputComponent, isStandalone: true, host: { properties: { "class": "hostClass()" } }, ngImport: i0 }); }
524
+ }
525
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.1", ngImport: i0, type: BaseInputComponent, decorators: [{
526
+ type: Directive,
527
+ args: [{
528
+ host: {
529
+ '[class]': 'hostClass()'
530
+ }
531
+ }]
532
+ }], ctorParameters: () => [] });
533
+
534
+ class ArrayFieldComponent extends BaseInputComponent {
535
+ constructor() {
536
+ super(...arguments);
537
+ this.controlResolver = inject(ControlResolver);
538
+ this.fb = inject(NonNullableFormBuilder);
539
+ this.formControl = new FormArray([], this.validatorFn);
540
+ this.controls = computed(() => {
541
+ const ctrl = this.control();
542
+ return isArrayControl(ctrl) ? ctrl.controls : [];
543
+ }, ...(ngDevMode ? [{ debugName: "controls" }] : []));
544
+ }
545
+ ngOnInit() {
546
+ this.initialize();
547
+ const val = this.value();
548
+ if (Array.isArray(val)) {
549
+ val.forEach(() => {
550
+ const group = this.fb.group({});
551
+ this.formControl.push(group);
552
+ });
327
553
  }
328
- this.hostClass = `field wrapper-${this.control.control.name}`;
329
554
  }
330
- destroy() {
331
- if (this.control.formGroup)
555
+ getControlValue(index) {
556
+ const val = this.value();
557
+ if (Array.isArray(val)) {
558
+ return val[index] ?? null;
559
+ }
560
+ return null;
561
+ }
562
+ removeItem(i) {
563
+ if (this.isDisabled()) {
332
564
  return;
333
- else
334
- this.parentFormGroup.removeControl(this.control.control.name);
565
+ }
566
+ this.formControl.removeAt(i);
335
567
  }
336
- resolveValidators({ validators = {} }) {
337
- const validatorsKeys = Object.keys(validators);
338
- return validatorsKeys.map(key => {
339
- const value = validators[key];
340
- if (key === 'required') {
341
- return Validators.required;
568
+ addItem() {
569
+ if (this.isDisabled()) {
570
+ return;
571
+ }
572
+ const group = this.fb.group({});
573
+ this.formControl.push(group);
574
+ }
575
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.1", ngImport: i0, type: ArrayFieldComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
576
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.1", type: ArrayFieldComponent, isStandalone: true, selector: "array-field", usesInheritance: true, ngImport: i0, template: "<fieldset [formArrayName]=\"control().name\">\n @if (control().label) {\n <legend [class]=\"settings.legendClasses\">{{ control().label }}</legend>\n }\n\n @for (group of formControl.controls; track group; let i = $index) {\n <div\n [formGroupName]=\"i\"\n [class]=\"settings.arrayItemContainerClasses\">\n @for (ctrl of control().controls; track ctrl.name) {\n <ng-container\n *activateControl=\"ctrl\"\n [ngComponentOutlet]=\"controlResolver.resolve(ctrl) | async\"\n [ngComponentOutletInjector]=\"ctrl | controlInjector: getControlValue(i)\" />\n }\n\n <button\n [class]=\"settings.arrayControlRemoveButtonClasses\"\n role=\"button\"\n tabindex=\"0\"\n type=\"button\"\n (click)=\"removeItem(i)\"\n (keydown.enter)=\"removeItem(i)\">\n @if (settings.arrayControlRemoveButtonIcon) {\n <div [class]=\"settings.arrayControlRemoveButtonIconClasses\">\n <ng-container *ngComponentOutlet=\"settings.arrayControlRemoveButtonIcon\" />\n </div>\n }\n @if (settings.arrayControlRemoveButtonLabel) {\n <span>{{ settings.arrayControlRemoveButtonLabel }}</span>\n }\n </button>\n </div>\n }\n\n <button\n [class]=\"settings.arrayControlAddButtonClasses\"\n role=\"button\"\n tabindex=\"0\"\n type=\"button\"\n (click)=\"addItem()\"\n (keydown.enter)=\"addItem()\">\n @if (settings.arrayControlAddButtonIcon) {\n <div [class]=\"settings.arrayControlAddButtonIconClasses\">\n <ng-container *ngComponentOutlet=\"settings.arrayControlAddButtonIcon\" />\n </div>\n }\n @if (settings.arrayControlAddButtonLabel) {\n <span>{{ settings.arrayControlAddButtonLabel }}</span>\n }\n </button>\n</fieldset>\n\n<div [class]=\"settings.validationFeedbackClasses\">\n <ng-container [helpMessage]=\"control().helpText\" />\n</div>\n", dependencies: [{ kind: "ngmodule", type: i1.ReactiveFormsModule }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.FormGroupName, selector: "[formGroupName]", inputs: ["formGroupName"] }, { kind: "directive", type: i1.FormArrayName, selector: "[formArrayName]", inputs: ["formArrayName"] }, { kind: "directive", type: HelpTextDirective, selector: "[helpMessage]", inputs: ["helpMessage"] }, { kind: "directive", type: i4.NgComponentOutlet, selector: "[ngComponentOutlet]", inputs: ["ngComponentOutlet", "ngComponentOutletInputs", "ngComponentOutletInjector", "ngComponentOutletEnvironmentInjector", "ngComponentOutletContent", "ngComponentOutletNgModule", "ngComponentOutletNgModuleFactory"], exportAs: ["ngComponentOutlet"] }, { kind: "directive", type: ActivateControlDirective, selector: "[activateControl]", inputs: ["activateControl"] }, { kind: "pipe", type: ControlInjector, name: "controlInjector" }, { kind: "pipe", type: AsyncPipe, name: "async" }], viewProviders: [controlProvider], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
577
+ }
578
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.1", ngImport: i0, type: ArrayFieldComponent, decorators: [{
579
+ type: Component,
580
+ args: [{ selector: 'array-field', imports: [...controlDeps, AsyncPipe], changeDetection: ChangeDetectionStrategy.OnPush, viewProviders: [controlProvider], template: "<fieldset [formArrayName]=\"control().name\">\n @if (control().label) {\n <legend [class]=\"settings.legendClasses\">{{ control().label }}</legend>\n }\n\n @for (group of formControl.controls; track group; let i = $index) {\n <div\n [formGroupName]=\"i\"\n [class]=\"settings.arrayItemContainerClasses\">\n @for (ctrl of control().controls; track ctrl.name) {\n <ng-container\n *activateControl=\"ctrl\"\n [ngComponentOutlet]=\"controlResolver.resolve(ctrl) | async\"\n [ngComponentOutletInjector]=\"ctrl | controlInjector: getControlValue(i)\" />\n }\n\n <button\n [class]=\"settings.arrayControlRemoveButtonClasses\"\n role=\"button\"\n tabindex=\"0\"\n type=\"button\"\n (click)=\"removeItem(i)\"\n (keydown.enter)=\"removeItem(i)\">\n @if (settings.arrayControlRemoveButtonIcon) {\n <div [class]=\"settings.arrayControlRemoveButtonIconClasses\">\n <ng-container *ngComponentOutlet=\"settings.arrayControlRemoveButtonIcon\" />\n </div>\n }\n @if (settings.arrayControlRemoveButtonLabel) {\n <span>{{ settings.arrayControlRemoveButtonLabel }}</span>\n }\n </button>\n </div>\n }\n\n <button\n [class]=\"settings.arrayControlAddButtonClasses\"\n role=\"button\"\n tabindex=\"0\"\n type=\"button\"\n (click)=\"addItem()\"\n (keydown.enter)=\"addItem()\">\n @if (settings.arrayControlAddButtonIcon) {\n <div [class]=\"settings.arrayControlAddButtonIconClasses\">\n <ng-container *ngComponentOutlet=\"settings.arrayControlAddButtonIcon\" />\n </div>\n }\n @if (settings.arrayControlAddButtonLabel) {\n <span>{{ settings.arrayControlAddButtonLabel }}</span>\n }\n </button>\n</fieldset>\n\n<div [class]=\"settings.validationFeedbackClasses\">\n <ng-container [helpMessage]=\"control().helpText\" />\n</div>\n" }]
581
+ }] });
582
+
583
+ var arrayField_component = /*#__PURE__*/Object.freeze({
584
+ __proto__: null,
585
+ ArrayFieldComponent: ArrayFieldComponent
586
+ });
587
+
588
+ // autocomplete-field.component.ts
589
+ class AutocompleteFieldComponent extends BaseInputComponent {
590
+ constructor() {
591
+ super(...arguments);
592
+ // A separate control for the query input.
593
+ this.queryControl = new FormControl('');
594
+ this.isOpen = signal(false, ...(ngDevMode ? [{ debugName: "isOpen" }] : []));
595
+ this.loading = signal(false, ...(ngDevMode ? [{ debugName: "loading" }] : []));
596
+ this.dependencySubscriptions = [];
597
+ // suggestions$ emits an array of options based on the current query.
598
+ this.suggestions$ = this.queryControl.valueChanges.pipe(startWith$1(this.queryControl.value), debounceTime(300), map(query => query || ''), distinctUntilChanged(), switchMap((query) => {
599
+ const ctrl = this.control();
600
+ if (!ctrl.autocompleteOptions) {
601
+ this.loading.set(false);
602
+ return of([]);
342
603
  }
343
- if (key === 'email') {
344
- return Validators.email;
604
+ // Set loading to true before fetching
605
+ this.loading.set(true);
606
+ const result = ctrl.autocompleteOptions(this.parentForm, query);
607
+ let resultObservable;
608
+ // Handle Promise
609
+ if (result instanceof Promise) {
610
+ resultObservable = from(result);
345
611
  }
346
- if (key === 'requiredTrue') {
347
- return Validators.requiredTrue;
612
+ // Handle Observable
613
+ else if (result && typeof result === 'object' && 'subscribe' in result) {
614
+ resultObservable = result;
348
615
  }
349
- if (key === 'minLength' && typeof value === 'number') {
350
- return Validators.minLength(value);
616
+ // Handle Array
617
+ else if (Array.isArray(result)) {
618
+ resultObservable = of(result);
351
619
  }
352
- if (key === 'pattern' && typeof value === 'string') {
353
- return Validators.pattern(value);
620
+ else {
621
+ resultObservable = of([]);
354
622
  }
355
- return Validators.nullValidator;
356
- });
623
+ // Set loading to false after results arrive
624
+ return resultObservable.pipe(map(results => {
625
+ this.loading.set(false);
626
+ return results;
627
+ }));
628
+ }));
357
629
  }
358
- getOptions() {
359
- if (this.control.control.options) {
360
- return of(this.control.control.options);
630
+ displayWithFn(item) {
631
+ const control = this.control();
632
+ if (control.itemLabel) {
633
+ const label = item[control.itemLabel];
634
+ return label !== null && label !== undefined ? String(label) : '';
361
635
  }
362
- if (!this.control.control.asyncOptions)
363
- return of([]);
364
- return this.control.control.asyncOptions(this.parentFormGroup);
636
+ else {
637
+ return String(item);
638
+ }
639
+ }
640
+ selectOption(option) {
641
+ const ctrl = this.control();
642
+ const valueToStore = ctrl.itemValue ? option[ctrl.itemValue] : option;
643
+ this.formControl.setValue(valueToStore);
644
+ this.queryControl.setValue(this.displayWithFn(option));
645
+ this.close();
646
+ }
647
+ isSelected(option) {
648
+ const ctrl = this.control();
649
+ const value = this.formControl.value;
650
+ const optionValue = ctrl.itemValue ? option[ctrl.itemValue] : option;
651
+ if (Array.isArray(value)) {
652
+ return value.includes(optionValue);
653
+ }
654
+ return value === optionValue;
655
+ }
656
+ open() {
657
+ this.isOpen.set(true);
658
+ }
659
+ close() {
660
+ this.isOpen.set(false);
661
+ }
662
+ trackByFn(index, item) {
663
+ const ctrl = this.control();
664
+ return ctrl.itemValue ? item[ctrl.itemValue] : index;
665
+ }
666
+ ngOnInit() {
667
+ this.initialize();
668
+ // If the control configuration has a 'resetOnChange' array, subscribe to each dependency.
669
+ const ctrl = this.control();
670
+ if (ctrl.resetOnChange && Array.isArray(ctrl.resetOnChange)) {
671
+ ctrl.resetOnChange.forEach((depName) => {
672
+ const depControl = this.parentForm.get(depName);
673
+ if (depControl) {
674
+ const sub = depControl.valueChanges.pipe(distinctUntilChanged()).subscribe(() => {
675
+ this.formControl.reset();
676
+ this.queryControl.reset();
677
+ });
678
+ this.dependencySubscriptions.push(sub);
679
+ }
680
+ });
681
+ }
682
+ }
683
+ ngOnDestroy() {
684
+ this.destroy();
685
+ this.dependencySubscriptions.forEach(sub => sub.unsubscribe());
365
686
  }
366
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.1", ngImport: i0, type: BaseControlComponent, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
367
- static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.3.1", type: BaseControlComponent, isStandalone: true, host: { properties: { "class": "this.hostClass" } }, ngImport: i0 }); }
687
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.1", ngImport: i0, type: AutocompleteFieldComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
688
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.1", type: AutocompleteFieldComponent, isStandalone: true, selector: "autocomplete-field", usesInheritance: true, ngImport: i0, template: "<label\n [class]=\"settings.labelClasses\"\n [attr.for]=\"control().name\">\n {{ control().label }}\n</label>\n\n<div class=\"relative\">\n <input\n #origin\n [id]=\"control().name\"\n [name]=\"control().name\"\n [class]=\"settings.autocompleteInputClasses\"\n [placeholder]=\"control().placeholder ?? ''\"\n [formControl]=\"queryControl\"\n (focus)=\"open()\"\n autocomplete=\"off\"\n [attr.aria-expanded]=\"isOpen() ? 'true' : 'false'\"\n aria-controls=\"autocomplete-list\" />\n\n @if (loading()) {\n <div [class]=\"settings.autocompleteLoadingWrapperClasses\">\n @if (settings.autocompleteLoadingIcon) {\n <div [class]=\"settings.autocompleteLoadingIconClasses\">\n <ng-container [ngComponentOutlet]=\"settings.autocompleteLoadingIcon\" />\n </div>\n } @else {\n <span [class]=\"settings.autocompleteLoadingTextClasses\">{{ settings.autocompleteLoadingText }}</span>\n }\n </div>\n }\n</div>\n\n<!-- CDK Connected Overlay for suggestions dropdown -->\n<ng-template\n cdkConnectedOverlay\n [cdkConnectedOverlayOrigin]=\"origin\"\n [cdkConnectedOverlayOpen]=\"isOpen()\"\n cdkConnectedOverlayHasBackdrop\n cdkConnectedOverlayBackdropClass=\"cdk-overlay-transparent-backdrop\"\n (backdropClick)=\"close()\"\n (detach)=\"close()\">\n <div\n [class]=\"settings.autocompleteDropdownClasses\"\n role=\"listbox\"\n aria-live=\"assertive\"\n id=\"autocomplete-list\">\n @for (option of suggestions$ | async; track trackByFn($index, option)) {\n <div\n [class]=\"[settings.autocompleteDropdownItemClasses, isSelected(option) ? settings.autocompleteDropdownItemSelectedClasses : '']\"\n tabindex=\"0\"\n (click)=\"selectOption(option)\"\n (keyup)=\"selectOption(option)\"\n role=\"option\"\n [attr.aria-selected]=\"isSelected(option)\">\n {{ displayWithFn(option) }}\n </div>\n }\n </div>\n</ng-template>\n\n<div [class]=\"settings.validationFeedbackClasses\">\n <ng-container\n ngDefaultControl\n validatorMessage\n [helpMessage]=\"control().helpText\"\n [formControlName]=\"control().name\" />\n</div>\n", dependencies: [{ kind: "ngmodule", type: i1.ReactiveFormsModule }, { kind: "directive", type: i1.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.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "directive", type: i1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "directive", type: HelpTextDirective, selector: "[helpMessage]", inputs: ["helpMessage"] }, { kind: "directive", type: ValidatorMessageDirective, selector: "[validatorMessage]" }, { kind: "directive", type: i4.NgComponentOutlet, selector: "[ngComponentOutlet]", inputs: ["ngComponentOutlet", "ngComponentOutletInputs", "ngComponentOutletInjector", "ngComponentOutletEnvironmentInjector", "ngComponentOutletContent", "ngComponentOutletNgModule", "ngComponentOutletNgModuleFactory"], exportAs: ["ngComponentOutlet"] }, { kind: "ngmodule", type: OverlayModule }, { kind: "directive", type: i5.CdkConnectedOverlay, selector: "[cdk-connected-overlay], [connected-overlay], [cdkConnectedOverlay]", inputs: ["cdkConnectedOverlayOrigin", "cdkConnectedOverlayPositions", "cdkConnectedOverlayPositionStrategy", "cdkConnectedOverlayOffsetX", "cdkConnectedOverlayOffsetY", "cdkConnectedOverlayWidth", "cdkConnectedOverlayHeight", "cdkConnectedOverlayMinWidth", "cdkConnectedOverlayMinHeight", "cdkConnectedOverlayBackdropClass", "cdkConnectedOverlayPanelClass", "cdkConnectedOverlayViewportMargin", "cdkConnectedOverlayScrollStrategy", "cdkConnectedOverlayOpen", "cdkConnectedOverlayDisableClose", "cdkConnectedOverlayTransformOriginOn", "cdkConnectedOverlayHasBackdrop", "cdkConnectedOverlayLockPosition", "cdkConnectedOverlayFlexibleDimensions", "cdkConnectedOverlayGrowAfterOpen", "cdkConnectedOverlayPush", "cdkConnectedOverlayDisposeOnNavigation"], outputs: ["backdropClick", "positionChange", "attach", "detach", "overlayKeydown", "overlayOutsideClick"], exportAs: ["cdkConnectedOverlay"] }, { kind: "pipe", type: AsyncPipe, name: "async" }], viewProviders: [controlProvider], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
368
689
  }
369
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.1", ngImport: i0, type: BaseControlComponent, decorators: [{
370
- type: Directive
371
- }], propDecorators: { hostClass: [{
372
- type: HostBinding,
373
- args: ['class']
374
- }] } });
375
-
376
- class CheckboxFieldComponent extends BaseControlComponent {
690
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.1", ngImport: i0, type: AutocompleteFieldComponent, decorators: [{
691
+ type: Component,
692
+ args: [{ selector: 'autocomplete-field', imports: [...controlDeps, OverlayModule, AsyncPipe], changeDetection: ChangeDetectionStrategy.OnPush, viewProviders: [controlProvider], template: "<label\n [class]=\"settings.labelClasses\"\n [attr.for]=\"control().name\">\n {{ control().label }}\n</label>\n\n<div class=\"relative\">\n <input\n #origin\n [id]=\"control().name\"\n [name]=\"control().name\"\n [class]=\"settings.autocompleteInputClasses\"\n [placeholder]=\"control().placeholder ?? ''\"\n [formControl]=\"queryControl\"\n (focus)=\"open()\"\n autocomplete=\"off\"\n [attr.aria-expanded]=\"isOpen() ? 'true' : 'false'\"\n aria-controls=\"autocomplete-list\" />\n\n @if (loading()) {\n <div [class]=\"settings.autocompleteLoadingWrapperClasses\">\n @if (settings.autocompleteLoadingIcon) {\n <div [class]=\"settings.autocompleteLoadingIconClasses\">\n <ng-container [ngComponentOutlet]=\"settings.autocompleteLoadingIcon\" />\n </div>\n } @else {\n <span [class]=\"settings.autocompleteLoadingTextClasses\">{{ settings.autocompleteLoadingText }}</span>\n }\n </div>\n }\n</div>\n\n<!-- CDK Connected Overlay for suggestions dropdown -->\n<ng-template\n cdkConnectedOverlay\n [cdkConnectedOverlayOrigin]=\"origin\"\n [cdkConnectedOverlayOpen]=\"isOpen()\"\n cdkConnectedOverlayHasBackdrop\n cdkConnectedOverlayBackdropClass=\"cdk-overlay-transparent-backdrop\"\n (backdropClick)=\"close()\"\n (detach)=\"close()\">\n <div\n [class]=\"settings.autocompleteDropdownClasses\"\n role=\"listbox\"\n aria-live=\"assertive\"\n id=\"autocomplete-list\">\n @for (option of suggestions$ | async; track trackByFn($index, option)) {\n <div\n [class]=\"[settings.autocompleteDropdownItemClasses, isSelected(option) ? settings.autocompleteDropdownItemSelectedClasses : '']\"\n tabindex=\"0\"\n (click)=\"selectOption(option)\"\n (keyup)=\"selectOption(option)\"\n role=\"option\"\n [attr.aria-selected]=\"isSelected(option)\">\n {{ displayWithFn(option) }}\n </div>\n }\n </div>\n</ng-template>\n\n<div [class]=\"settings.validationFeedbackClasses\">\n <ng-container\n ngDefaultControl\n validatorMessage\n [helpMessage]=\"control().helpText\"\n [formControlName]=\"control().name\" />\n</div>\n" }]
693
+ }] });
694
+
695
+ var autocompleteField_component = /*#__PURE__*/Object.freeze({
696
+ __proto__: null,
697
+ AutocompleteFieldComponent: AutocompleteFieldComponent
698
+ });
699
+
700
+ class CheckboxFieldComponent extends BaseInputComponent {
377
701
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.1", ngImport: i0, type: CheckboxFieldComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
378
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.1", type: CheckboxFieldComponent, isStandalone: true, selector: "app-checkbox-field", usesInheritance: true, ngImport: i0, template: "<div>\n <input\n type=\"checkbox\"\n [id]=\"id\"\n [formControlName]=\"control.control.name\" />\n @if (control.control.label) {\n <label\n [for]=\"id\"\n [innerHTML]=\"control.control.label\">\n </label>\n }\n\n <div\n appHelpText\n [message]=\"control.control.helpText ?? ''\"\n appValidatorMessage\n ngDefaultControl\n [formControlName]=\"control.control.name\"></div>\n</div>\n", dependencies: [{ kind: "ngmodule", type: i1.CommonModule }, { kind: "ngmodule", type: i2.ReactiveFormsModule }, { kind: "directive", type: i2.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: i2.CheckboxControlValueAccessor, selector: "input[type=checkbox][formControlName],input[type=checkbox][formControl],input[type=checkbox][ngModel]" }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "directive", type: ValidatorMessageDirective, selector: "[appValidatorMessage]" }, { kind: "directive", type: HelpTextDirective, selector: "[appHelpText]", inputs: ["message"] }], viewProviders: [controlProvider] }); }
702
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.1", type: CheckboxFieldComponent, isStandalone: true, selector: "checkbox-field", usesInheritance: true, ngImport: i0, template: "<label [class]=\"settings.checkboxWrapperClasses\">\n <input\n [id]=\"control().name\"\n [name]=\"control().name\"\n [class]=\"settings.checkboxInputClasses\"\n type=\"checkbox\"\n [attr.aria-checked]=\"formControl.value ? 'true' : 'false'\"\n [formControlName]=\"control().name\" />\n <span\n [class]=\"settings.checkboxLabelTextClasses\"\n [innerHTML]=\"control().label\"></span>\n</label>\n\n<div [class]=\"settings.validationFeedbackClasses\">\n <ng-container\n ngDefaultControl\n validatorMessage\n [helpMessage]=\"control().helpText\"\n [formControlName]=\"control().name\" />\n</div>\n", dependencies: [{ kind: "ngmodule", type: i1.ReactiveFormsModule }, { kind: "directive", type: i1.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.CheckboxControlValueAccessor, selector: "input[type=checkbox][formControlName],input[type=checkbox][formControl],input[type=checkbox][ngModel]" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "directive", type: HelpTextDirective, selector: "[helpMessage]", inputs: ["helpMessage"] }, { kind: "directive", type: ValidatorMessageDirective, selector: "[validatorMessage]" }], viewProviders: [controlProvider], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
379
703
  }
380
704
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.1", ngImport: i0, type: CheckboxFieldComponent, decorators: [{
381
705
  type: Component,
382
- args: [{ selector: 'app-checkbox-field', imports: [...sharedControlDeps], viewProviders: [controlProvider], standalone: true, template: "<div>\n <input\n type=\"checkbox\"\n [id]=\"id\"\n [formControlName]=\"control.control.name\" />\n @if (control.control.label) {\n <label\n [for]=\"id\"\n [innerHTML]=\"control.control.label\">\n </label>\n }\n\n <div\n appHelpText\n [message]=\"control.control.helpText ?? ''\"\n appValidatorMessage\n ngDefaultControl\n [formControlName]=\"control.control.name\"></div>\n</div>\n" }]
706
+ args: [{ selector: 'checkbox-field', imports: [...controlDeps], changeDetection: ChangeDetectionStrategy.OnPush, viewProviders: [controlProvider], template: "<label [class]=\"settings.checkboxWrapperClasses\">\n <input\n [id]=\"control().name\"\n [name]=\"control().name\"\n [class]=\"settings.checkboxInputClasses\"\n type=\"checkbox\"\n [attr.aria-checked]=\"formControl.value ? 'true' : 'false'\"\n [formControlName]=\"control().name\" />\n <span\n [class]=\"settings.checkboxLabelTextClasses\"\n [innerHTML]=\"control().label\"></span>\n</label>\n\n<div [class]=\"settings.validationFeedbackClasses\">\n <ng-container\n ngDefaultControl\n validatorMessage\n [helpMessage]=\"control().helpText\"\n [formControlName]=\"control().name\" />\n</div>\n" }]
383
707
  }] });
384
708
 
385
709
  var checkboxField_component = /*#__PURE__*/Object.freeze({
@@ -387,29 +711,33 @@ var checkboxField_component = /*#__PURE__*/Object.freeze({
387
711
  CheckboxFieldComponent: CheckboxFieldComponent
388
712
  });
389
713
 
390
- class CheckboxGroupFieldComponent extends BaseControlComponent {
714
+ class CheckboxGroupFieldComponent extends BaseInputComponent {
391
715
  constructor() {
392
716
  super(...arguments);
393
- this.formControl = new FormArray([], this.resolveValidators(this.control.control));
394
- }
395
- change(event) {
396
- const element = event.target;
397
- const value = element.value;
398
- const index = this.formControl.value.indexOf(value);
399
- if (index === -1) {
400
- const fc = new FormControl(value);
401
- this.formControl.push(fc);
717
+ this.formControl = new FormControl(Array.isArray(this.value()) ? this.value() : [], this.validatorFn);
718
+ }
719
+ isSelected(value) {
720
+ const selectedValues = this.formControl.value;
721
+ return selectedValues.includes(value);
722
+ }
723
+ onCheckboxChange(event, value) {
724
+ const target = event.target;
725
+ const isChecked = target.checked;
726
+ let selectedValues = this.formControl.value;
727
+ if (isChecked && !this.isSelected(value)) {
728
+ selectedValues.push(value);
402
729
  }
403
730
  else {
404
- this.formControl.removeAt(index);
731
+ selectedValues = selectedValues.filter(item => item !== value);
405
732
  }
733
+ this.formControl.setValue(selectedValues);
406
734
  }
407
735
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.1", ngImport: i0, type: CheckboxGroupFieldComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
408
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.1", type: CheckboxGroupFieldComponent, isStandalone: true, selector: "app-checkbox-group-field", usesInheritance: true, ngImport: i0, template: "@if (control.control.label) {\n <label for=\"\">\n {{ control.control.label }}\n </label>\n}\n\n<div\n [formArrayName]=\"control.control.name\"\n appHelpText\n [message]=\"control.control.helpText ?? ''\"\n appValidatorArrayMessage>\n @for (option of getOptions() | async; track option.value; let index = $index) {\n <div>\n <input\n type=\"checkbox\"\n (change)=\"change($event)\"\n [value]=\"option.value\"\n [id]=\"id + index\" />\n <label [for]=\"id + index\">\n {{ option.label }}\n </label>\n </div>\n }\n</div>\n", dependencies: [{ kind: "ngmodule", type: i1.CommonModule }, { kind: "ngmodule", type: i2.ReactiveFormsModule }, { kind: "directive", type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i2.FormArrayName, selector: "[formArrayName]", inputs: ["formArrayName"] }, { kind: "directive", type: HelpTextDirective, selector: "[appHelpText]", inputs: ["message"] }, { kind: "directive", type: ValidatorArrayMessageDirective, selector: "[appValidatorArrayMessage]" }, { kind: "pipe", type: i1.AsyncPipe, name: "async" }], viewProviders: [controlProvider] }); }
736
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.1", type: CheckboxGroupFieldComponent, isStandalone: true, selector: "checkbox-group-field", usesInheritance: true, ngImport: i0, template: "<label\n [class]=\"settings.labelClasses\"\n [attr.for]=\"control().name\">\n {{ control().label }}\n</label>\n\n<div [class]=\"settings.checkboxGroupContainerClasses\">\n @for (option of options(); track option.value) {\n <label [class]=\"settings.checkboxGroupItemWrapperClasses\">\n <input\n [id]=\"control().name + '-' + option.value\"\n [name]=\"control().name + '-' + option.value\"\n [class]=\"settings.checkboxGroupItemInputClasses\"\n type=\"checkbox\"\n [checked]=\"isSelected(option.value)\"\n [disabled]=\"option.disabled\"\n (change)=\"onCheckboxChange($event, option.value)\" />\n <span [class]=\"settings.checkboxGroupItemLabelClasses\">{{ option.label }}</span>\n </label>\n }\n</div>\n\n<div [class]=\"settings.validationFeedbackClasses\">\n <ng-container\n ngDefaultControl\n validatorMessage\n [helpMessage]=\"control().helpText\"\n [formControlName]=\"control().name\" />\n</div>\n", dependencies: [{ kind: "ngmodule", type: i1.ReactiveFormsModule }, { kind: "directive", type: i1.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.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "directive", type: HelpTextDirective, selector: "[helpMessage]", inputs: ["helpMessage"] }, { kind: "directive", type: ValidatorMessageDirective, selector: "[validatorMessage]" }], viewProviders: [controlProvider], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
409
737
  }
410
738
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.1", ngImport: i0, type: CheckboxGroupFieldComponent, decorators: [{
411
739
  type: Component,
412
- args: [{ selector: 'app-checkbox-group-field', imports: [...sharedControlDeps], viewProviders: [controlProvider], standalone: true, template: "@if (control.control.label) {\n <label for=\"\">\n {{ control.control.label }}\n </label>\n}\n\n<div\n [formArrayName]=\"control.control.name\"\n appHelpText\n [message]=\"control.control.helpText ?? ''\"\n appValidatorArrayMessage>\n @for (option of getOptions() | async; track option.value; let index = $index) {\n <div>\n <input\n type=\"checkbox\"\n (change)=\"change($event)\"\n [value]=\"option.value\"\n [id]=\"id + index\" />\n <label [for]=\"id + index\">\n {{ option.label }}\n </label>\n </div>\n }\n</div>\n" }]
740
+ args: [{ selector: 'checkbox-group-field', imports: [...controlDeps], changeDetection: ChangeDetectionStrategy.OnPush, viewProviders: [controlProvider], template: "<label\n [class]=\"settings.labelClasses\"\n [attr.for]=\"control().name\">\n {{ control().label }}\n</label>\n\n<div [class]=\"settings.checkboxGroupContainerClasses\">\n @for (option of options(); track option.value) {\n <label [class]=\"settings.checkboxGroupItemWrapperClasses\">\n <input\n [id]=\"control().name + '-' + option.value\"\n [name]=\"control().name + '-' + option.value\"\n [class]=\"settings.checkboxGroupItemInputClasses\"\n type=\"checkbox\"\n [checked]=\"isSelected(option.value)\"\n [disabled]=\"option.disabled\"\n (change)=\"onCheckboxChange($event, option.value)\" />\n <span [class]=\"settings.checkboxGroupItemLabelClasses\">{{ option.label }}</span>\n </label>\n }\n</div>\n\n<div [class]=\"settings.validationFeedbackClasses\">\n <ng-container\n ngDefaultControl\n validatorMessage\n [helpMessage]=\"control().helpText\"\n [formControlName]=\"control().name\" />\n</div>\n" }]
413
741
  }] });
414
742
 
415
743
  var checkboxGroupField_component = /*#__PURE__*/Object.freeze({
@@ -417,18 +745,57 @@ var checkboxGroupField_component = /*#__PURE__*/Object.freeze({
417
745
  CheckboxGroupFieldComponent: CheckboxGroupFieldComponent
418
746
  });
419
747
 
420
- class GroupFieldComponent extends BaseControlComponent {
748
+ class ChipsListFieldComponent extends BaseInputComponent {
749
+ constructor() {
750
+ super(...arguments);
751
+ this.formControl = new FormControl(Array.isArray(this.value()) ? this.value() : [], this.validatorFn);
752
+ this.inputValue = signal('', ...(ngDevMode ? [{ debugName: "inputValue" }] : []));
753
+ }
754
+ addChip() {
755
+ const trimmed = this.inputValue().trim();
756
+ if (!trimmed) {
757
+ return;
758
+ }
759
+ const currentChips = this.formControl.value || [];
760
+ this.formControl.setValue([...currentChips, trimmed]);
761
+ this.inputValue.set('');
762
+ }
763
+ removeChip(chipToRemove) {
764
+ const currentChips = this.formControl.value || [];
765
+ const updatedChips = currentChips.filter(chip => chip !== chipToRemove);
766
+ this.formControl.setValue(updatedChips);
767
+ }
768
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.1", ngImport: i0, type: ChipsListFieldComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
769
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.1", type: ChipsListFieldComponent, isStandalone: true, selector: "chips-list-field", usesInheritance: true, ngImport: i0, template: "<label\n [class]=\"settings.labelClasses\"\n [attr.for]=\"control().name\">\n {{ control().label }}\n</label>\n\n<div [class]=\"settings.chipslistContainerClasses\">\n @for (chip of formControl.value; track $index) {\n <div [class]=\"settings.chipslistChipClasses\">\n {{ chip }}\n <button\n type=\"button\"\n [class]=\"settings.chipslistRemoveButtonClasses\"\n (click)=\"removeChip(chip)\">\n @if (settings.chipslistRemoveButtonIcon) {\n <div [class]=\"settings.chipslistRemoveButtonIconClasses\">\n <ng-container [ngComponentOutlet]=\"settings.chipslistRemoveButtonIcon\" />\n </div>\n }\n @if (settings.chipslistRemoveButtonLabel) {\n <span [class]=\"settings.chipslistRemoveButtonLabelClasses\">\n {{ settings.chipslistRemoveButtonLabel }}\n </span>\n }\n </button>\n </div>\n }\n</div>\n\n<div>\n <input\n [id]=\"control().name\"\n [class]=\"settings.chipslistInputClasses\"\n [name]=\"control().name\"\n [placeholder]=\"control().placeholder ?? ''\"\n [value]=\"inputValue()\"\n (input)=\"inputValue.set($any($event.target).value)\"\n (keydown.enter)=\"$event.preventDefault(); addChip()\"\n aria-label=\"Add new chip\" />\n <button\n type=\"button\"\n [class]=\"settings.chipslistAddButtonClasses\"\n aria-label=\"Add chip\"\n (click)=\"addChip()\">\n @if (settings.chipslistAddButtonIcon) {\n <div [class]=\"settings.chipslistAddButtonIconClasses\">\n <ng-container [ngComponentOutlet]=\"settings.chipslistAddButtonIcon\" />\n </div>\n }\n @if (settings.chipslistAddButtonLabel) {\n <span [class]=\"settings.chipslistAddButtonLabelClasses\">\n {{ settings.chipslistAddButtonLabel }}\n </span>\n }\n </button>\n</div>\n\n<div [class]=\"settings.validationFeedbackClasses\">\n <ng-container\n ngDefaultControl\n validatorMessage\n [helpMessage]=\"control().helpText\"\n [formControl]=\"formControl\" />\n</div>\n", dependencies: [{ kind: "ngmodule", type: i1.ReactiveFormsModule }, { kind: "directive", type: i1.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.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "directive", type: HelpTextDirective, selector: "[helpMessage]", inputs: ["helpMessage"] }, { kind: "directive", type: ValidatorMessageDirective, selector: "[validatorMessage]" }, { kind: "directive", type: i4.NgComponentOutlet, selector: "[ngComponentOutlet]", inputs: ["ngComponentOutlet", "ngComponentOutletInputs", "ngComponentOutletInjector", "ngComponentOutletEnvironmentInjector", "ngComponentOutletContent", "ngComponentOutletNgModule", "ngComponentOutletNgModuleFactory"], exportAs: ["ngComponentOutlet"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
770
+ }
771
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.1", ngImport: i0, type: ChipsListFieldComponent, decorators: [{
772
+ type: Component,
773
+ args: [{ selector: 'chips-list-field', imports: [...controlDeps], changeDetection: ChangeDetectionStrategy.OnPush, template: "<label\n [class]=\"settings.labelClasses\"\n [attr.for]=\"control().name\">\n {{ control().label }}\n</label>\n\n<div [class]=\"settings.chipslistContainerClasses\">\n @for (chip of formControl.value; track $index) {\n <div [class]=\"settings.chipslistChipClasses\">\n {{ chip }}\n <button\n type=\"button\"\n [class]=\"settings.chipslistRemoveButtonClasses\"\n (click)=\"removeChip(chip)\">\n @if (settings.chipslistRemoveButtonIcon) {\n <div [class]=\"settings.chipslistRemoveButtonIconClasses\">\n <ng-container [ngComponentOutlet]=\"settings.chipslistRemoveButtonIcon\" />\n </div>\n }\n @if (settings.chipslistRemoveButtonLabel) {\n <span [class]=\"settings.chipslistRemoveButtonLabelClasses\">\n {{ settings.chipslistRemoveButtonLabel }}\n </span>\n }\n </button>\n </div>\n }\n</div>\n\n<div>\n <input\n [id]=\"control().name\"\n [class]=\"settings.chipslistInputClasses\"\n [name]=\"control().name\"\n [placeholder]=\"control().placeholder ?? ''\"\n [value]=\"inputValue()\"\n (input)=\"inputValue.set($any($event.target).value)\"\n (keydown.enter)=\"$event.preventDefault(); addChip()\"\n aria-label=\"Add new chip\" />\n <button\n type=\"button\"\n [class]=\"settings.chipslistAddButtonClasses\"\n aria-label=\"Add chip\"\n (click)=\"addChip()\">\n @if (settings.chipslistAddButtonIcon) {\n <div [class]=\"settings.chipslistAddButtonIconClasses\">\n <ng-container [ngComponentOutlet]=\"settings.chipslistAddButtonIcon\" />\n </div>\n }\n @if (settings.chipslistAddButtonLabel) {\n <span [class]=\"settings.chipslistAddButtonLabelClasses\">\n {{ settings.chipslistAddButtonLabel }}\n </span>\n }\n </button>\n</div>\n\n<div [class]=\"settings.validationFeedbackClasses\">\n <ng-container\n ngDefaultControl\n validatorMessage\n [helpMessage]=\"control().helpText\"\n [formControl]=\"formControl\" />\n</div>\n" }]
774
+ }] });
775
+
776
+ var chipsListField_component = /*#__PURE__*/Object.freeze({
777
+ __proto__: null,
778
+ ChipsListFieldComponent: ChipsListFieldComponent
779
+ });
780
+
781
+ class GroupFieldComponent extends BaseInputComponent {
421
782
  constructor() {
422
783
  super(...arguments);
784
+ this.fb = inject(NonNullableFormBuilder);
423
785
  this.controlResolver = inject(ControlResolver);
424
- this.formControl = new FormGroup({});
786
+ this.formControl = this.fb.group({});
787
+ this.controls = computed(() => {
788
+ const ctrl = this.control();
789
+ return isGroupControl(ctrl) ? ctrl.controls : [];
790
+ }, ...(ngDevMode ? [{ debugName: "controls" }] : []));
791
+ this.groupValue = computed(() => this.value(), ...(ngDevMode ? [{ debugName: "groupValue" }] : []));
425
792
  }
426
793
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.1", ngImport: i0, type: GroupFieldComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
427
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.1", type: GroupFieldComponent, isStandalone: true, selector: "app-group-field", usesInheritance: true, ngImport: i0, template: "<div [formGroupName]=\"control.control.name\">\n @for (control of control.control.controls; track control.name) {\n <ng-container\n [ngComponentOutlet]=\"controlResolver.resolve(control, parentFormGroup) | async\"\n [ngComponentOutletInjector]=\"control.name | controlInjector: control\">\n </ng-container>\n }\n</div>\n", dependencies: [{ kind: "ngmodule", type: i1.CommonModule }, { kind: "directive", type: i1.NgComponentOutlet, selector: "[ngComponentOutlet]", inputs: ["ngComponentOutlet", "ngComponentOutletInputs", "ngComponentOutletInjector", "ngComponentOutletEnvironmentInjector", "ngComponentOutletContent", "ngComponentOutletNgModule", "ngComponentOutletNgModuleFactory"], exportAs: ["ngComponentOutlet"] }, { kind: "ngmodule", type: i2.ReactiveFormsModule }, { kind: "directive", type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i2.FormGroupName, selector: "[formGroupName]", inputs: ["formGroupName"] }, { kind: "pipe", type: i1.AsyncPipe, name: "async" }, { kind: "pipe", type: ControlInjector, name: "controlInjector" }], viewProviders: [controlProvider] }); }
794
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.1", type: GroupFieldComponent, isStandalone: true, selector: "group-field", usesInheritance: true, ngImport: i0, template: "<fieldset\n [class]=\"settings.groupContainerClasses\"\n [formGroupName]=\"control().name\">\n @if (control().label) {\n <legend [class]=\"settings.groupLegendClasses\">{{ control().label }}</legend>\n }\n @for (control of controls(); track control.name) {\n <ng-container\n *activateControl=\"control\"\n [ngComponentOutlet]=\"controlResolver.resolve(control) | async\"\n [ngComponentOutletInjector]=\"control | controlInjector: groupValue()\" />\n }\n</fieldset>\n", dependencies: [{ kind: "ngmodule", type: i1.ReactiveFormsModule }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.FormGroupName, selector: "[formGroupName]", inputs: ["formGroupName"] }, { kind: "directive", type: i4.NgComponentOutlet, selector: "[ngComponentOutlet]", inputs: ["ngComponentOutlet", "ngComponentOutletInputs", "ngComponentOutletInjector", "ngComponentOutletEnvironmentInjector", "ngComponentOutletContent", "ngComponentOutletNgModule", "ngComponentOutletNgModuleFactory"], exportAs: ["ngComponentOutlet"] }, { kind: "directive", type: ActivateControlDirective, selector: "[activateControl]", inputs: ["activateControl"] }, { kind: "pipe", type: ControlInjector, name: "controlInjector" }, { kind: "pipe", type: AsyncPipe, name: "async" }], viewProviders: [controlProvider], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
428
795
  }
429
796
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.1", ngImport: i0, type: GroupFieldComponent, decorators: [{
430
797
  type: Component,
431
- args: [{ selector: 'app-group-field', imports: [...sharedControlDeps, ControlInjector], viewProviders: [controlProvider], standalone: true, template: "<div [formGroupName]=\"control.control.name\">\n @for (control of control.control.controls; track control.name) {\n <ng-container\n [ngComponentOutlet]=\"controlResolver.resolve(control, parentFormGroup) | async\"\n [ngComponentOutletInjector]=\"control.name | controlInjector: control\">\n </ng-container>\n }\n</div>\n" }]
798
+ args: [{ selector: 'group-field', imports: [...controlDeps, AsyncPipe], changeDetection: ChangeDetectionStrategy.OnPush, viewProviders: [controlProvider], template: "<fieldset\n [class]=\"settings.groupContainerClasses\"\n [formGroupName]=\"control().name\">\n @if (control().label) {\n <legend [class]=\"settings.groupLegendClasses\">{{ control().label }}</legend>\n }\n @for (control of controls(); track control.name) {\n <ng-container\n *activateControl=\"control\"\n [ngComponentOutlet]=\"controlResolver.resolve(control) | async\"\n [ngComponentOutletInjector]=\"control | controlInjector: groupValue()\" />\n }\n</fieldset>\n" }]
432
799
  }] });
433
800
 
434
801
  var groupField_component = /*#__PURE__*/Object.freeze({
@@ -436,105 +803,178 @@ var groupField_component = /*#__PURE__*/Object.freeze({
436
803
  GroupFieldComponent: GroupFieldComponent
437
804
  });
438
805
 
439
- class EyeIcon {
440
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.1", ngImport: i0, type: EyeIcon, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
441
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.1", type: EyeIcon, isStandalone: true, selector: "eye-icon", ngImport: i0, template: `<svg
442
- width="100%"
443
- height="100%"
444
- viewBox="0 0 16 10"
445
- fill="none"
446
- xmlns="http://www.w3.org/2000/svg">
447
- <path
448
- d="M15.4569 4.7975C15.435 4.74813 14.9056 3.57375 13.7287 2.39687C12.1606 0.82875 10.18 0 7.99999 0C5.81999 0 3.83937 0.82875 2.27124 2.39687C1.09437 3.57375 0.562494 4.75 0.543119 4.7975C0.51469 4.86144 0.5 4.93064 0.5 5.00062C0.5 5.0706 0.51469 5.1398 0.543119 5.20375C0.564994 5.25312 1.09437 6.42688 2.27124 7.60375C3.83937 9.17125 5.81999 10 7.99999 10C10.18 10 12.1606 9.17125 13.7287 7.60375C14.9056 6.42688 15.435 5.25312 15.4569 5.20375C15.4853 5.1398 15.5 5.0706 15.5 5.00062C15.5 4.93064 15.4853 4.86144 15.4569 4.7975ZM7.99999 7.5C7.50554 7.5 7.02219 7.35338 6.61107 7.07867C6.19995 6.80397 5.87951 6.41352 5.6903 5.95671C5.50108 5.49989 5.45157 4.99723 5.54803 4.51227C5.64449 4.02732 5.8826 3.58186 6.23223 3.23223C6.58186 2.8826 7.02732 2.6445 7.51227 2.54804C7.99722 2.45157 8.49989 2.50108 8.9567 2.6903C9.41352 2.87952 9.80396 3.19995 10.0787 3.61107C10.3534 4.0222 10.5 4.50555 10.5 5C10.5 5.66304 10.2366 6.29893 9.76776 6.76777C9.29892 7.23661 8.66304 7.5 7.99999 7.5Z"
449
- fill="#252623" />
450
- </svg>`, isInline: true }); }
806
+ class InputFieldComponent extends BaseInputComponent {
807
+ constructor() {
808
+ super(...arguments);
809
+ this.isPasswordOpen = signal(false, ...(ngDevMode ? [{ debugName: "isPasswordOpen" }] : []));
810
+ this.eyeComponent = computed(() => (this.isPasswordOpen() ? this.settings.passwordEyeOpenIcon : this.settings.passwordEyeCloseIcon), ...(ngDevMode ? [{ debugName: "eyeComponent" }] : []));
811
+ this.inputType = computed(() => {
812
+ const ctrl = this.control();
813
+ if (!isInputControl(ctrl)) {
814
+ return 'text';
815
+ }
816
+ const type = ctrl.type || 'text';
817
+ if (type === 'password' && this.isPasswordOpen()) {
818
+ return 'text';
819
+ }
820
+ return type;
821
+ }, ...(ngDevMode ? [{ debugName: "inputType" }] : []));
822
+ this.inputPlaceholder = computed(() => {
823
+ const ctrl = this.control();
824
+ return isInputControl(ctrl) ? (ctrl.placeholder ?? '') : '';
825
+ }, ...(ngDevMode ? [{ debugName: "inputPlaceholder" }] : []));
826
+ }
827
+ togglePassword() {
828
+ this.isPasswordOpen.set(!this.isPasswordOpen());
829
+ }
830
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.1", ngImport: i0, type: InputFieldComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
831
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.1", type: InputFieldComponent, isStandalone: true, selector: "input-field", usesInheritance: true, ngImport: i0, template: "<label\n [class]=\"settings.labelClasses\"\n [attr.for]=\"control().name\">\n {{ control().label }}\n</label>\n\n<input\n [class]=\"settings.inputClasses\"\n [id]=\"control().name\"\n [name]=\"control().name\"\n [type]=\"inputType()\"\n [formControlName]=\"control().name\"\n [placeholder]=\"inputPlaceholder()\"\n autocomplete=\"off\" />\n\n@if (control().type === 'password' && eyeComponent()) {\n <button\n type=\"button\"\n [class]=\"settings.passwordIconClasses\"\n (click)=\"togglePassword()\">\n <ng-container [ngComponentOutlet]=\"eyeComponent()!\" />\n </button>\n}\n\n<div [class]=\"settings.validationFeedbackClasses\">\n <ng-container\n ngDefaultControl\n validatorMessage\n [helpMessage]=\"control().helpText\"\n [formControlName]=\"control().name\" />\n</div>\n", dependencies: [{ kind: "ngmodule", type: i1.ReactiveFormsModule }, { kind: "directive", type: i1.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.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "directive", type: HelpTextDirective, selector: "[helpMessage]", inputs: ["helpMessage"] }, { kind: "directive", type: ValidatorMessageDirective, selector: "[validatorMessage]" }, { kind: "directive", type: i4.NgComponentOutlet, selector: "[ngComponentOutlet]", inputs: ["ngComponentOutlet", "ngComponentOutletInputs", "ngComponentOutletInjector", "ngComponentOutletEnvironmentInjector", "ngComponentOutletContent", "ngComponentOutletNgModule", "ngComponentOutletNgModuleFactory"], exportAs: ["ngComponentOutlet"] }], viewProviders: [controlProvider], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
451
832
  }
452
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.1", ngImport: i0, type: EyeIcon, decorators: [{
833
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.1", ngImport: i0, type: InputFieldComponent, decorators: [{
453
834
  type: Component,
454
- args: [{
455
- selector: 'eye-icon',
456
- standalone: true,
457
- template: `<svg
458
- width="100%"
459
- height="100%"
460
- viewBox="0 0 16 10"
461
- fill="none"
462
- xmlns="http://www.w3.org/2000/svg">
463
- <path
464
- d="M15.4569 4.7975C15.435 4.74813 14.9056 3.57375 13.7287 2.39687C12.1606 0.82875 10.18 0 7.99999 0C5.81999 0 3.83937 0.82875 2.27124 2.39687C1.09437 3.57375 0.562494 4.75 0.543119 4.7975C0.51469 4.86144 0.5 4.93064 0.5 5.00062C0.5 5.0706 0.51469 5.1398 0.543119 5.20375C0.564994 5.25312 1.09437 6.42688 2.27124 7.60375C3.83937 9.17125 5.81999 10 7.99999 10C10.18 10 12.1606 9.17125 13.7287 7.60375C14.9056 6.42688 15.435 5.25312 15.4569 5.20375C15.4853 5.1398 15.5 5.0706 15.5 5.00062C15.5 4.93064 15.4853 4.86144 15.4569 4.7975ZM7.99999 7.5C7.50554 7.5 7.02219 7.35338 6.61107 7.07867C6.19995 6.80397 5.87951 6.41352 5.6903 5.95671C5.50108 5.49989 5.45157 4.99723 5.54803 4.51227C5.64449 4.02732 5.8826 3.58186 6.23223 3.23223C6.58186 2.8826 7.02732 2.6445 7.51227 2.54804C7.99722 2.45157 8.49989 2.50108 8.9567 2.6903C9.41352 2.87952 9.80396 3.19995 10.0787 3.61107C10.3534 4.0222 10.5 4.50555 10.5 5C10.5 5.66304 10.2366 6.29893 9.76776 6.76777C9.29892 7.23661 8.66304 7.5 7.99999 7.5Z"
465
- fill="#252623" />
466
- </svg>`
467
- }]
835
+ args: [{ selector: 'input-field', imports: [...controlDeps], changeDetection: ChangeDetectionStrategy.OnPush, viewProviders: [controlProvider], template: "<label\n [class]=\"settings.labelClasses\"\n [attr.for]=\"control().name\">\n {{ control().label }}\n</label>\n\n<input\n [class]=\"settings.inputClasses\"\n [id]=\"control().name\"\n [name]=\"control().name\"\n [type]=\"inputType()\"\n [formControlName]=\"control().name\"\n [placeholder]=\"inputPlaceholder()\"\n autocomplete=\"off\" />\n\n@if (control().type === 'password' && eyeComponent()) {\n <button\n type=\"button\"\n [class]=\"settings.passwordIconClasses\"\n (click)=\"togglePassword()\">\n <ng-container [ngComponentOutlet]=\"eyeComponent()!\" />\n </button>\n}\n\n<div [class]=\"settings.validationFeedbackClasses\">\n <ng-container\n ngDefaultControl\n validatorMessage\n [helpMessage]=\"control().helpText\"\n [formControlName]=\"control().name\" />\n</div>\n" }]
468
836
  }] });
469
837
 
470
- class EyeOffIcon {
471
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.1", ngImport: i0, type: EyeOffIcon, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
472
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.1", type: EyeOffIcon, isStandalone: true, selector: "eye-off-icon", ngImport: i0, template: `<svg
473
- width="100%"
474
- height="100%"
475
- viewBox="0 0 16 12"
476
- fill="none"
477
- xmlns="http://www.w3.org/2000/svg">
478
- <path
479
- d="M6.04249 1.61686C6.01297 1.58451 5.99246 1.54497 5.98301 1.5022C5.97357 1.45944 5.97553 1.41494 5.9887 1.37317C6.00186 1.33139 6.02577 1.29381 6.05803 1.26419C6.09028 1.23456 6.12976 1.21393 6.17249 1.20436C6.77196 1.06729 7.38506 0.998729 7.99999 0.999981C10.18 0.999981 12.1606 1.82873 13.7287 3.39686C14.9056 4.57373 15.435 5.74811 15.4569 5.79748C15.4853 5.86143 15.5 5.93063 15.5 6.00061C15.5 6.07059 15.4853 6.13979 15.4569 6.20373C15.435 6.25311 14.9056 7.42686 13.7287 8.60373C13.5504 8.78123 13.3673 8.94936 13.1794 9.10811C13.1299 9.15008 13.0661 9.1712 13.0014 9.16701C12.9367 9.16281 12.8761 9.13362 12.8325 9.08561L6.04249 1.61686ZM13.37 11.1637C13.4151 11.2122 13.4501 11.2691 13.473 11.3311C13.496 11.3932 13.5064 11.4592 13.5036 11.5253C13.5008 11.5914 13.485 11.6563 13.4569 11.7162C13.4289 11.7762 13.3893 11.8299 13.3403 11.8744C13.2913 11.9189 13.234 11.9533 13.1717 11.9755C13.1094 11.9977 13.0432 12.0072 12.9772 12.0037C12.9111 12.0001 12.8464 11.9835 12.7868 11.9548C12.7272 11.926 12.6739 11.8857 12.63 11.8362L11.25 10.3206C10.2266 10.7733 9.11907 11.0048 7.99999 11C5.81999 11 3.83937 10.1712 2.27124 8.60373C1.09437 7.42686 0.562494 6.25311 0.543119 6.20373C0.51469 6.13979 0.5 6.07059 0.5 6.00061C0.5 5.93063 0.51469 5.86143 0.543119 5.79748C0.562494 5.74998 1.09437 4.57373 2.27124 3.39686C2.74142 2.92451 3.26591 2.50953 3.83374 2.16061L2.62999 0.836231C2.58491 0.787802 2.54989 0.730907 2.52696 0.668843C2.50402 0.606779 2.49364 0.54078 2.4964 0.474672C2.49916 0.408565 2.51502 0.343662 2.54305 0.283728C2.57108 0.223793 2.61072 0.170017 2.65969 0.125518C2.70865 0.0810184 2.76597 0.0466801 2.8283 0.0244932C2.89063 0.00230626 2.95675 -0.00728797 3.02282 -0.00373355C3.08889 -0.000179118 3.1536 0.0164534 3.21319 0.0451998C3.27279 0.0739463 3.32608 0.114235 3.36999 0.163731L13.37 11.1637ZM9.27687 8.14811L5.98374 4.52311C5.64441 4.98804 5.47591 5.55583 5.50668 6.1306C5.53746 6.70538 5.76562 7.25192 6.15266 7.67797C6.5397 8.10401 7.0619 8.38345 7.63109 8.4691C8.20028 8.55476 8.78159 8.44138 9.27687 8.14811Z"
480
- fill="#252623" />
481
- </svg>`, isInline: true }); }
482
- }
483
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.1", ngImport: i0, type: EyeOffIcon, decorators: [{
484
- type: Component,
485
- args: [{
486
- selector: 'eye-off-icon',
487
- standalone: true,
488
- template: `<svg
489
- width="100%"
490
- height="100%"
491
- viewBox="0 0 16 12"
492
- fill="none"
493
- xmlns="http://www.w3.org/2000/svg">
494
- <path
495
- d="M6.04249 1.61686C6.01297 1.58451 5.99246 1.54497 5.98301 1.5022C5.97357 1.45944 5.97553 1.41494 5.9887 1.37317C6.00186 1.33139 6.02577 1.29381 6.05803 1.26419C6.09028 1.23456 6.12976 1.21393 6.17249 1.20436C6.77196 1.06729 7.38506 0.998729 7.99999 0.999981C10.18 0.999981 12.1606 1.82873 13.7287 3.39686C14.9056 4.57373 15.435 5.74811 15.4569 5.79748C15.4853 5.86143 15.5 5.93063 15.5 6.00061C15.5 6.07059 15.4853 6.13979 15.4569 6.20373C15.435 6.25311 14.9056 7.42686 13.7287 8.60373C13.5504 8.78123 13.3673 8.94936 13.1794 9.10811C13.1299 9.15008 13.0661 9.1712 13.0014 9.16701C12.9367 9.16281 12.8761 9.13362 12.8325 9.08561L6.04249 1.61686ZM13.37 11.1637C13.4151 11.2122 13.4501 11.2691 13.473 11.3311C13.496 11.3932 13.5064 11.4592 13.5036 11.5253C13.5008 11.5914 13.485 11.6563 13.4569 11.7162C13.4289 11.7762 13.3893 11.8299 13.3403 11.8744C13.2913 11.9189 13.234 11.9533 13.1717 11.9755C13.1094 11.9977 13.0432 12.0072 12.9772 12.0037C12.9111 12.0001 12.8464 11.9835 12.7868 11.9548C12.7272 11.926 12.6739 11.8857 12.63 11.8362L11.25 10.3206C10.2266 10.7733 9.11907 11.0048 7.99999 11C5.81999 11 3.83937 10.1712 2.27124 8.60373C1.09437 7.42686 0.562494 6.25311 0.543119 6.20373C0.51469 6.13979 0.5 6.07059 0.5 6.00061C0.5 5.93063 0.51469 5.86143 0.543119 5.79748C0.562494 5.74998 1.09437 4.57373 2.27124 3.39686C2.74142 2.92451 3.26591 2.50953 3.83374 2.16061L2.62999 0.836231C2.58491 0.787802 2.54989 0.730907 2.52696 0.668843C2.50402 0.606779 2.49364 0.54078 2.4964 0.474672C2.49916 0.408565 2.51502 0.343662 2.54305 0.283728C2.57108 0.223793 2.61072 0.170017 2.65969 0.125518C2.70865 0.0810184 2.76597 0.0466801 2.8283 0.0244932C2.89063 0.00230626 2.95675 -0.00728797 3.02282 -0.00373355C3.08889 -0.000179118 3.1536 0.0164534 3.21319 0.0451998C3.27279 0.0739463 3.32608 0.114235 3.36999 0.163731L13.37 11.1637ZM9.27687 8.14811L5.98374 4.52311C5.64441 4.98804 5.47591 5.55583 5.50668 6.1306C5.53746 6.70538 5.76562 7.25192 6.15266 7.67797C6.5397 8.10401 7.0619 8.38345 7.63109 8.4691C8.20028 8.55476 8.78159 8.44138 9.27687 8.14811Z"
496
- fill="#252623" />
497
- </svg>`
498
- }]
499
- }] });
838
+ var inputField_component = /*#__PURE__*/Object.freeze({
839
+ __proto__: null,
840
+ InputFieldComponent: InputFieldComponent
841
+ });
500
842
 
501
- class InputFieldComponent extends BaseControlComponent {
843
+ class MultiSelectDropdownComponent extends BaseInputComponent {
502
844
  constructor() {
503
- super(...arguments);
504
- this.showPassword = false;
845
+ super();
846
+ this.formControl = new FormControl(Array.isArray(this.value()) ? this.value() : [], this.validatorFn);
847
+ this.items = toSignal(this.getItems(), { initialValue: [] });
848
+ this.isOpen = signal(false, ...(ngDevMode ? [{ debugName: "isOpen" }] : []));
849
+ this.multipleMode = computed(() => {
850
+ const ctrl = this.control();
851
+ return isMultiSelectControl(ctrl) ? (ctrl.multiple ?? true) : true;
852
+ }, ...(ngDevMode ? [{ debugName: "multipleMode" }] : []));
853
+ this.selectedOptionsModel = new SelectionModel(this.multipleMode());
854
+ this.displayOptions = toSignal(this.selectedOptionsModel.changed.pipe(map$1(() => this.selectedOptionsModel.selected)), { initialValue: [] });
855
+ effect(() => {
856
+ this.setSelectedItems(this.items());
857
+ });
858
+ effect(() => {
859
+ const selected = this.displayOptions();
860
+ this.valueHasChanged(selected);
861
+ });
862
+ }
863
+ setSelectedItems(items) {
864
+ const formControlValue = this.formControl.value;
865
+ this.selectedOptionsModel.clear();
866
+ if (Array.isArray(formControlValue)) {
867
+ items.forEach(item => {
868
+ if (formControlValue.some((val) => this.compareWithFn(item, val))) {
869
+ this.selectedOptionsModel.select(item);
870
+ }
871
+ });
872
+ }
873
+ else {
874
+ items.forEach(item => {
875
+ if (this.compareWithFn(item, String(formControlValue))) {
876
+ this.selectedOptionsModel.select(item);
877
+ }
878
+ });
879
+ }
505
880
  }
506
- togglePasswordVisibility() {
507
- this.showPassword = !this.showPassword;
881
+ getItems() {
882
+ return this.parentForm.valueChanges.pipe(switchMap$1(() => {
883
+ const control = this.control();
884
+ const itemsFn = control.items;
885
+ if (!itemsFn) {
886
+ return of([]);
887
+ }
888
+ if (Array.isArray(itemsFn)) {
889
+ return of(itemsFn);
890
+ }
891
+ const result = itemsFn(this.parentForm);
892
+ if (result instanceof Promise) {
893
+ return from(result);
894
+ }
895
+ if (result instanceof Observable) {
896
+ return result;
897
+ }
898
+ if (Array.isArray(result)) {
899
+ return of(result);
900
+ }
901
+ return of([]);
902
+ }));
508
903
  }
509
- get inputType() {
510
- if (this.control.control.type === 'password' && this.showPassword) {
511
- return 'text';
904
+ displayWithFn(item) {
905
+ const control = this.control();
906
+ if (control.itemLabel) {
907
+ return String(item[control.itemLabel] ?? '');
908
+ }
909
+ else {
910
+ return String(item);
512
911
  }
513
- return this.control.control.type ?? 'text';
514
912
  }
515
- get isPasswordField() {
516
- return this.control.control.type === 'password';
913
+ compareWithFn(item, value) {
914
+ const control = this.control();
915
+ if (control.itemValue) {
916
+ const itemValue = item[control.itemValue];
917
+ return itemValue === value;
918
+ }
919
+ else {
920
+ return item === value;
921
+ }
517
922
  }
518
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.1", ngImport: i0, type: InputFieldComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
519
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.1", type: InputFieldComponent, isStandalone: true, selector: "app-input-field", usesInheritance: true, ngImport: i0, template: "@if (control.control.label) {\n <label [for]=\"id\">\n {{ control.control.label }}\n </label>\n}\n<div class=\"input-container\">\n <div class=\"input-with-icon\">\n <input\n [placeholder]=\"control.control.placeholder ?? ''\"\n [type]=\"inputType\"\n [formControlName]=\"control.control.name\"\n [checked]=\"control.control.value\"\n [id]=\"id\"\n [class.has-toggle]=\"isPasswordField\" />\n @if (isPasswordField) {\n <button\n type=\"button\"\n class=\"toggle-password-btn\"\n (click)=\"togglePasswordVisibility()\"\n [attr.aria-label]=\"showPassword ? 'Ocultar contrase\u00F1a' : 'Mostrar contrase\u00F1a'\">\n @if (showPassword) {\n <eye-off-icon />\n } @else {\n <eye-icon />\n }\n </button>\n }\n </div>\n <div\n appHelpText\n [message]=\"control.control.helpText ?? ''\"\n appValidatorMessage\n [formControlName]=\"control.control.name\"\n ngDefaultControl></div>\n</div>\n", styles: [".input-with-icon{position:relative}.toggle-password-btn{position:absolute;right:12px;top:50%;transform:translateY(-50%);background:none;border:none;cursor:pointer;padding:4px;display:flex;align-items:center;justify-content:center;width:24px;height:24px}.toggle-password-btn:hover{opacity:.7}input.has-toggle{padding-right:40px}\n"], dependencies: [{ kind: "ngmodule", type: i1.CommonModule }, { kind: "ngmodule", type: i2.ReactiveFormsModule }, { kind: "directive", type: i2.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: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "directive", type: ValidatorMessageDirective, selector: "[appValidatorMessage]" }, { kind: "directive", type: HelpTextDirective, selector: "[appHelpText]", inputs: ["message"] }, { kind: "component", type: EyeIcon, selector: "eye-icon" }, { kind: "component", type: EyeOffIcon, selector: "eye-off-icon" }], viewProviders: [controlProvider] }); }
923
+ valueHasChanged(items) {
924
+ const control = this.control();
925
+ const isMultiple = control.multiple !== false;
926
+ const values = items.map(item => {
927
+ if (!control.itemValue) {
928
+ return item;
929
+ }
930
+ return item[control.itemValue];
931
+ });
932
+ if (isMultiple) {
933
+ this.formControl.setValue(values, { emitEvent: false });
934
+ }
935
+ else {
936
+ this.formControl.setValue(values.at(0) ?? null, { emitEvent: false });
937
+ }
938
+ }
939
+ open() {
940
+ this.isOpen.set(true);
941
+ }
942
+ close() {
943
+ this.isOpen.set(false);
944
+ }
945
+ trackByFn(index, item) {
946
+ const ctrl = this.control();
947
+ return ctrl.itemValue ? item[ctrl.itemValue] : index;
948
+ }
949
+ toggleSelection(option) {
950
+ this.selectedOptionsModel.toggle(option);
951
+ }
952
+ deselectOption(event, option) {
953
+ event.stopPropagation();
954
+ this.selectedOptionsModel.deselect(option);
955
+ }
956
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.1", ngImport: i0, type: MultiSelectDropdownComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
957
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.1", type: MultiSelectDropdownComponent, isStandalone: true, selector: "multi-select-dropdown", host: { listeners: { "click": "open()" } }, usesInheritance: true, ngImport: i0, template: "<label\n [class]=\"settings.labelClasses\"\n [attr.for]=\"control().name\">\n {{ control().label }}\n</label>\n\n<div\n cdkOverlayOrigin\n #origin=\"cdkOverlayOrigin\">\n <div>\n @if (displayOptions().length === 0) {\n <span>{{ settings.multiSelectEmptyText }}</span>\n } @else {\n <div [class]=\"settings.multiSelectDisplayedOptionsClasses\">\n @for (option of displayOptions(); track trackByFn($index, option)) {\n <div [class]=\"settings.multiSelectDisplayedOptionClasses\">\n <span>{{ displayWithFn(option) }}</span>\n <button\n type=\"button\"\n [class]=\"settings.multiSelectControlRemoveButtonClasses\"\n (click)=\"deselectOption($event, option)\">\n @if (settings.multiSelectControlRemoveButtonIcon) {\n <div [class]=\"settings.multiSelectControlRemoveButtonIconClasses\">\n <ng-container [ngComponentOutlet]=\"settings.multiSelectControlRemoveButtonIcon\" />\n </div>\n }\n @if (settings.multiSelectControlRemoveButtonLabel) {\n {{ settings.multiSelectControlRemoveButtonLabel }}\n }\n </button>\n </div>\n }\n </div>\n }\n </div>\n</div>\n\n<ng-template\n cdkConnectedOverlay\n [cdkConnectedOverlayOrigin]=\"origin\"\n [cdkConnectedOverlayOpen]=\"isOpen()\"\n cdkConnectedOverlayHasBackdrop\n cdkConnectedOverlayBackdropClass=\"cdk-overlay-transparent-backdrop\"\n (backdropClick)=\"close()\"\n (detach)=\"close()\">\n <div [class]=\"settings.multiselectDropdownClasses\">\n @for (option of items(); track trackByFn($index, option)) {\n <div [class]=\"[settings.multiselectDropdownItemClasses, selectedOptionsModel.isSelected(option) ? settings.multiselectDropdownItemSelectedClasses : '']\">\n <label class=\"flex items-center gap-2 cursor-pointer\">\n <input\n [id]=\"control().name + '-option-' + $index\"\n [name]=\"control().name + '-option-' + $index\"\n type=\"checkbox\"\n class=\"rounded border-gray-300 text-blue-600 focus:ring-blue-500\"\n [checked]=\"selectedOptionsModel.isSelected(option)\"\n (change)=\"toggleSelection(option)\"\n [attr.aria-checked]=\"selectedOptionsModel.isSelected(option) ? 'true' : 'false'\"\n [attr.aria-selected]=\"selectedOptionsModel.isSelected(option) ? 'true' : 'false'\"\n role=\"option\" />\n {{ displayWithFn(option) }}\n </label>\n </div>\n }\n </div>\n</ng-template>\n\n<div [class]=\"settings.validationFeedbackClasses\">\n <ng-container\n ngDefaultControl\n validatorMessage\n [helpMessage]=\"control().helpText\"\n [formControl]=\"formControl\" />\n</div>\n", dependencies: [{ kind: "ngmodule", type: i1.ReactiveFormsModule }, { kind: "directive", type: i1.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.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "directive", type: HelpTextDirective, selector: "[helpMessage]", inputs: ["helpMessage"] }, { kind: "directive", type: ValidatorMessageDirective, selector: "[validatorMessage]" }, { kind: "directive", type: i4.NgComponentOutlet, selector: "[ngComponentOutlet]", inputs: ["ngComponentOutlet", "ngComponentOutletInputs", "ngComponentOutletInjector", "ngComponentOutletEnvironmentInjector", "ngComponentOutletContent", "ngComponentOutletNgModule", "ngComponentOutletNgModuleFactory"], exportAs: ["ngComponentOutlet"] }, { kind: "ngmodule", type: OverlayModule }, { kind: "directive", type: i5.CdkConnectedOverlay, selector: "[cdk-connected-overlay], [connected-overlay], [cdkConnectedOverlay]", inputs: ["cdkConnectedOverlayOrigin", "cdkConnectedOverlayPositions", "cdkConnectedOverlayPositionStrategy", "cdkConnectedOverlayOffsetX", "cdkConnectedOverlayOffsetY", "cdkConnectedOverlayWidth", "cdkConnectedOverlayHeight", "cdkConnectedOverlayMinWidth", "cdkConnectedOverlayMinHeight", "cdkConnectedOverlayBackdropClass", "cdkConnectedOverlayPanelClass", "cdkConnectedOverlayViewportMargin", "cdkConnectedOverlayScrollStrategy", "cdkConnectedOverlayOpen", "cdkConnectedOverlayDisableClose", "cdkConnectedOverlayTransformOriginOn", "cdkConnectedOverlayHasBackdrop", "cdkConnectedOverlayLockPosition", "cdkConnectedOverlayFlexibleDimensions", "cdkConnectedOverlayGrowAfterOpen", "cdkConnectedOverlayPush", "cdkConnectedOverlayDisposeOnNavigation"], outputs: ["backdropClick", "positionChange", "attach", "detach", "overlayKeydown", "overlayOutsideClick"], exportAs: ["cdkConnectedOverlay"] }, { kind: "directive", type: i5.CdkOverlayOrigin, selector: "[cdk-overlay-origin], [overlay-origin], [cdkOverlayOrigin]", exportAs: ["cdkOverlayOrigin"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
520
958
  }
521
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.1", ngImport: i0, type: InputFieldComponent, decorators: [{
959
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.1", ngImport: i0, type: MultiSelectDropdownComponent, decorators: [{
522
960
  type: Component,
523
- args: [{ selector: 'app-input-field', imports: [...sharedControlDeps, EyeIcon, EyeOffIcon], viewProviders: [controlProvider], standalone: true, template: "@if (control.control.label) {\n <label [for]=\"id\">\n {{ control.control.label }}\n </label>\n}\n<div class=\"input-container\">\n <div class=\"input-with-icon\">\n <input\n [placeholder]=\"control.control.placeholder ?? ''\"\n [type]=\"inputType\"\n [formControlName]=\"control.control.name\"\n [checked]=\"control.control.value\"\n [id]=\"id\"\n [class.has-toggle]=\"isPasswordField\" />\n @if (isPasswordField) {\n <button\n type=\"button\"\n class=\"toggle-password-btn\"\n (click)=\"togglePasswordVisibility()\"\n [attr.aria-label]=\"showPassword ? 'Ocultar contrase\u00F1a' : 'Mostrar contrase\u00F1a'\">\n @if (showPassword) {\n <eye-off-icon />\n } @else {\n <eye-icon />\n }\n </button>\n }\n </div>\n <div\n appHelpText\n [message]=\"control.control.helpText ?? ''\"\n appValidatorMessage\n [formControlName]=\"control.control.name\"\n ngDefaultControl></div>\n</div>\n", styles: [".input-with-icon{position:relative}.toggle-password-btn{position:absolute;right:12px;top:50%;transform:translateY(-50%);background:none;border:none;cursor:pointer;padding:4px;display:flex;align-items:center;justify-content:center;width:24px;height:24px}.toggle-password-btn:hover{opacity:.7}input.has-toggle{padding-right:40px}\n"] }]
524
- }] });
961
+ args: [{ selector: 'multi-select-dropdown', imports: [...controlDeps, OverlayModule], changeDetection: ChangeDetectionStrategy.OnPush, host: {
962
+ '(click)': 'open()'
963
+ }, template: "<label\n [class]=\"settings.labelClasses\"\n [attr.for]=\"control().name\">\n {{ control().label }}\n</label>\n\n<div\n cdkOverlayOrigin\n #origin=\"cdkOverlayOrigin\">\n <div>\n @if (displayOptions().length === 0) {\n <span>{{ settings.multiSelectEmptyText }}</span>\n } @else {\n <div [class]=\"settings.multiSelectDisplayedOptionsClasses\">\n @for (option of displayOptions(); track trackByFn($index, option)) {\n <div [class]=\"settings.multiSelectDisplayedOptionClasses\">\n <span>{{ displayWithFn(option) }}</span>\n <button\n type=\"button\"\n [class]=\"settings.multiSelectControlRemoveButtonClasses\"\n (click)=\"deselectOption($event, option)\">\n @if (settings.multiSelectControlRemoveButtonIcon) {\n <div [class]=\"settings.multiSelectControlRemoveButtonIconClasses\">\n <ng-container [ngComponentOutlet]=\"settings.multiSelectControlRemoveButtonIcon\" />\n </div>\n }\n @if (settings.multiSelectControlRemoveButtonLabel) {\n {{ settings.multiSelectControlRemoveButtonLabel }}\n }\n </button>\n </div>\n }\n </div>\n }\n </div>\n</div>\n\n<ng-template\n cdkConnectedOverlay\n [cdkConnectedOverlayOrigin]=\"origin\"\n [cdkConnectedOverlayOpen]=\"isOpen()\"\n cdkConnectedOverlayHasBackdrop\n cdkConnectedOverlayBackdropClass=\"cdk-overlay-transparent-backdrop\"\n (backdropClick)=\"close()\"\n (detach)=\"close()\">\n <div [class]=\"settings.multiselectDropdownClasses\">\n @for (option of items(); track trackByFn($index, option)) {\n <div [class]=\"[settings.multiselectDropdownItemClasses, selectedOptionsModel.isSelected(option) ? settings.multiselectDropdownItemSelectedClasses : '']\">\n <label class=\"flex items-center gap-2 cursor-pointer\">\n <input\n [id]=\"control().name + '-option-' + $index\"\n [name]=\"control().name + '-option-' + $index\"\n type=\"checkbox\"\n class=\"rounded border-gray-300 text-blue-600 focus:ring-blue-500\"\n [checked]=\"selectedOptionsModel.isSelected(option)\"\n (change)=\"toggleSelection(option)\"\n [attr.aria-checked]=\"selectedOptionsModel.isSelected(option) ? 'true' : 'false'\"\n [attr.aria-selected]=\"selectedOptionsModel.isSelected(option) ? 'true' : 'false'\"\n role=\"option\" />\n {{ displayWithFn(option) }}\n </label>\n </div>\n }\n </div>\n</ng-template>\n\n<div [class]=\"settings.validationFeedbackClasses\">\n <ng-container\n ngDefaultControl\n validatorMessage\n [helpMessage]=\"control().helpText\"\n [formControl]=\"formControl\" />\n</div>\n" }]
964
+ }], ctorParameters: () => [] });
525
965
 
526
- var inputField_component = /*#__PURE__*/Object.freeze({
966
+ var multiSelectDropdown_component = /*#__PURE__*/Object.freeze({
527
967
  __proto__: null,
528
- InputFieldComponent: InputFieldComponent
968
+ MultiSelectDropdownComponent: MultiSelectDropdownComponent
529
969
  });
530
970
 
531
- class RadioFieldComponent extends BaseControlComponent {
971
+ class RadioFieldComponent extends BaseInputComponent {
532
972
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.1", ngImport: i0, type: RadioFieldComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
533
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.1", type: RadioFieldComponent, isStandalone: true, selector: "app-radio-field", usesInheritance: true, ngImport: i0, template: "@if (control.control.label) {\n <label for=\"\">\n {{ control.control.label }}\n </label>\n}\n\n<div>\n @for (option of getOptions() | async; track option.value; let i = $index) {\n <div>\n <input\n type=\"radio\"\n [formControlName]=\"control.control.name\"\n [value]=\"option.value\"\n [id]=\"id + i\" />\n <label [for]=\"id + i\">\n {{ option.label }}\n </label>\n </div>\n }\n</div>\n\n<div\n appHelpText\n [message]=\"control.control.helpText ?? ''\"\n appValidatorMessage\n [formControlName]=\"control.control.name\"\n ngDefaultControl></div>\n", dependencies: [{ kind: "ngmodule", type: i1.CommonModule }, { kind: "ngmodule", type: i2.ReactiveFormsModule }, { kind: "directive", type: i2.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: i2.RadioControlValueAccessor, selector: "input[type=radio][formControlName],input[type=radio][formControl],input[type=radio][ngModel]", inputs: ["name", "formControlName", "value"] }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "directive", type: ValidatorMessageDirective, selector: "[appValidatorMessage]" }, { kind: "directive", type: HelpTextDirective, selector: "[appHelpText]", inputs: ["message"] }, { kind: "pipe", type: i1.AsyncPipe, name: "async" }], viewProviders: [controlProvider] }); }
973
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.1", type: RadioFieldComponent, isStandalone: true, selector: "radio-field", usesInheritance: true, ngImport: i0, template: "<label\n [class]=\"settings.labelClasses\"\n [for]=\"control().name\">\n {{ control().label }}\n</label>\n\n<div [class]=\"settings.radioGroupContainerClasses\">\n @for (option of options(); track option.value) {\n <label [class]=\"settings.radioItemWrapperClasses\">\n <input\n [id]=\"control().name + '-' + option.value\"\n [name]=\"control().name\"\n [class]=\"settings.radioItemInputClasses\"\n type=\"radio\"\n [formControlName]=\"control().name\"\n [value]=\"option.value\"\n [attr.aria-checked]=\"formControl.value === option.value ? 'true' : 'false'\" />\n <span [class]=\"settings.radioItemLabelClasses\">{{ option.label }}</span>\n </label>\n }\n</div>\n\n<div [class]=\"settings.validationFeedbackClasses\">\n <ng-container\n ngDefaultControl\n validatorMessage\n [helpMessage]=\"control().helpText\"\n [formControlName]=\"control().name\" />\n</div>\n", dependencies: [{ kind: "ngmodule", type: i1.ReactiveFormsModule }, { kind: "directive", type: i1.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.RadioControlValueAccessor, selector: "input[type=radio][formControlName],input[type=radio][formControl],input[type=radio][ngModel]", inputs: ["name", "formControlName", "value"] }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "directive", type: HelpTextDirective, selector: "[helpMessage]", inputs: ["helpMessage"] }, { kind: "directive", type: ValidatorMessageDirective, selector: "[validatorMessage]" }], viewProviders: [controlProvider], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
534
974
  }
535
975
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.1", ngImport: i0, type: RadioFieldComponent, decorators: [{
536
976
  type: Component,
537
- args: [{ selector: 'app-radio-field', imports: [...sharedControlDeps], viewProviders: [controlProvider], standalone: true, template: "@if (control.control.label) {\n <label for=\"\">\n {{ control.control.label }}\n </label>\n}\n\n<div>\n @for (option of getOptions() | async; track option.value; let i = $index) {\n <div>\n <input\n type=\"radio\"\n [formControlName]=\"control.control.name\"\n [value]=\"option.value\"\n [id]=\"id + i\" />\n <label [for]=\"id + i\">\n {{ option.label }}\n </label>\n </div>\n }\n</div>\n\n<div\n appHelpText\n [message]=\"control.control.helpText ?? ''\"\n appValidatorMessage\n [formControlName]=\"control.control.name\"\n ngDefaultControl></div>\n" }]
977
+ args: [{ selector: 'radio-field', imports: [...controlDeps], changeDetection: ChangeDetectionStrategy.OnPush, viewProviders: [controlProvider], template: "<label\n [class]=\"settings.labelClasses\"\n [for]=\"control().name\">\n {{ control().label }}\n</label>\n\n<div [class]=\"settings.radioGroupContainerClasses\">\n @for (option of options(); track option.value) {\n <label [class]=\"settings.radioItemWrapperClasses\">\n <input\n [id]=\"control().name + '-' + option.value\"\n [name]=\"control().name\"\n [class]=\"settings.radioItemInputClasses\"\n type=\"radio\"\n [formControlName]=\"control().name\"\n [value]=\"option.value\"\n [attr.aria-checked]=\"formControl.value === option.value ? 'true' : 'false'\" />\n <span [class]=\"settings.radioItemLabelClasses\">{{ option.label }}</span>\n </label>\n }\n</div>\n\n<div [class]=\"settings.validationFeedbackClasses\">\n <ng-container\n ngDefaultControl\n validatorMessage\n [helpMessage]=\"control().helpText\"\n [formControlName]=\"control().name\" />\n</div>\n" }]
538
978
  }] });
539
979
 
540
980
  var radioField_component = /*#__PURE__*/Object.freeze({
@@ -542,6 +982,20 @@ var radioField_component = /*#__PURE__*/Object.freeze({
542
982
  RadioFieldComponent: RadioFieldComponent
543
983
  });
544
984
 
985
+ class SelectFieldComponent extends BaseInputComponent {
986
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.1", ngImport: i0, type: SelectFieldComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
987
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.1", type: SelectFieldComponent, isStandalone: true, selector: "select-field", usesInheritance: true, ngImport: i0, template: "<label\n [class]=\"settings.labelClasses\"\n [attr.for]=\"control().name\">\n {{ control().label }}\n</label>\n\n<select\n [class]=\"settings.selectClasses || settings.inputClasses\"\n [id]=\"control().name\"\n [name]=\"control().name\"\n [formControlName]=\"control().name\">\n @for (option of options(); track option.value) {\n <option\n [class]=\"settings.selectOptionClasses\"\n [value]=\"option.value\"\n [selected]=\"option.selected\"\n [disabled]=\"option.disabled\">\n {{ option.label }}\n </option>\n }\n</select>\n\n<div [class]=\"settings.validationFeedbackClasses\">\n <ng-container\n ngDefaultControl\n validatorMessage\n [helpMessage]=\"control().helpText\"\n [formControlName]=\"control().name\" />\n</div>\n", dependencies: [{ kind: "ngmodule", type: i1.ReactiveFormsModule }, { kind: "directive", type: i1.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1.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.SelectControlValueAccessor, selector: "select:not([multiple])[formControlName],select:not([multiple])[formControl],select:not([multiple])[ngModel]", inputs: ["compareWith"] }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "directive", type: HelpTextDirective, selector: "[helpMessage]", inputs: ["helpMessage"] }, { kind: "directive", type: ValidatorMessageDirective, selector: "[validatorMessage]" }], viewProviders: [controlProvider], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
988
+ }
989
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.1", ngImport: i0, type: SelectFieldComponent, decorators: [{
990
+ type: Component,
991
+ args: [{ selector: 'select-field', imports: [...controlDeps], changeDetection: ChangeDetectionStrategy.OnPush, viewProviders: [controlProvider], template: "<label\n [class]=\"settings.labelClasses\"\n [attr.for]=\"control().name\">\n {{ control().label }}\n</label>\n\n<select\n [class]=\"settings.selectClasses || settings.inputClasses\"\n [id]=\"control().name\"\n [name]=\"control().name\"\n [formControlName]=\"control().name\">\n @for (option of options(); track option.value) {\n <option\n [class]=\"settings.selectOptionClasses\"\n [value]=\"option.value\"\n [selected]=\"option.selected\"\n [disabled]=\"option.disabled\">\n {{ option.label }}\n </option>\n }\n</select>\n\n<div [class]=\"settings.validationFeedbackClasses\">\n <ng-container\n ngDefaultControl\n validatorMessage\n [helpMessage]=\"control().helpText\"\n [formControlName]=\"control().name\" />\n</div>\n" }]
992
+ }] });
993
+
994
+ var selectField_component = /*#__PURE__*/Object.freeze({
995
+ __proto__: null,
996
+ SelectFieldComponent: SelectFieldComponent
997
+ });
998
+
545
999
  /*
546
1000
  * Public API Surface of ngx-dynamic-forms
547
1001
  */
@@ -550,5 +1004,5 @@ var radioField_component = /*#__PURE__*/Object.freeze({
550
1004
  * Generated bundle index. Do not edit.
551
1005
  */
552
1006
 
553
- export { BaseControlComponent, CONTROL_DATA, CheckboxFieldComponent, CheckboxGroupFieldComponent, ControlInjector, ControlResolver, ControlTypeValues, ERROR_MESSAGES, ERROR_MESSAGES_ES, ErrorsComponent, GroupFieldComponent, HelpTextComponent, HelpTextDirective, InputFieldComponent, RadioFieldComponent, VALIDATION_ERROR_MESSAGES, ValidatorArrayMessageDirective, ValidatorMessageDirective, controlProvider, sharedControlDeps };
1007
+ export { ActivateControlDirective, ArrayFieldComponent, AutocompleteFieldComponent, BaseInputComponent, CONTROL_DATA, CheckboxFieldComponent, CheckboxGroupFieldComponent, ChipsListFieldComponent, ControlInjector, ControlResolver, DEFAULT_SETTINGS, ERROR_MESSAGES, ErrorMessageComponent, FieldsComponent, GroupFieldComponent, HelpTextComponent, HelpTextDirective, InputFieldComponent, MultiSelectDropdownComponent, RadioFieldComponent, SETTINGS, SPANISH_ERROR_MESSAGES, SelectFieldComponent, VALIDATION_ERROR_MESSAGES, ValidatorMessageDirective, ValidatorsService, controlDeps, controlProvider, isArrayControl, isAutocompleteControl, isGroupControl, isInputControl, isMultiSelectControl };
554
1008
  //# sourceMappingURL=superlikers-dynamic-forms.mjs.map