@vipsolucoes/dynamic-form 1.0.1
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.
|
@@ -0,0 +1,536 @@
|
|
|
1
|
+
import * as i1$1 from '@angular/common';
|
|
2
|
+
import { CommonModule, NgComponentOutlet } from '@angular/common';
|
|
3
|
+
import * as i0 from '@angular/core';
|
|
4
|
+
import { InjectionToken, input, inject, Component, computed, ChangeDetectionStrategy, signal, Injectable, DestroyRef, output } from '@angular/core';
|
|
5
|
+
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
|
6
|
+
import * as i1 from '@angular/forms';
|
|
7
|
+
import { ReactiveFormsModule, FormGroup, FormControl } from '@angular/forms';
|
|
8
|
+
import * as i3 from 'primeng/datepicker';
|
|
9
|
+
import { DatePickerModule } from 'primeng/datepicker';
|
|
10
|
+
import * as i2 from 'primeng/iftalabel';
|
|
11
|
+
import { IftaLabelModule } from 'primeng/iftalabel';
|
|
12
|
+
import * as i3$1 from 'primeng/inputtext';
|
|
13
|
+
import { InputTextModule } from 'primeng/inputtext';
|
|
14
|
+
import * as i3$2 from 'primeng/inputnumber';
|
|
15
|
+
import { InputNumberModule } from 'primeng/inputnumber';
|
|
16
|
+
import * as i3$3 from 'primeng/password';
|
|
17
|
+
import { PasswordModule } from 'primeng/password';
|
|
18
|
+
import * as i3$4 from 'primeng/select';
|
|
19
|
+
import { SelectModule } from 'primeng/select';
|
|
20
|
+
import * as i3$5 from 'primeng/textarea';
|
|
21
|
+
import { TextareaModule } from 'primeng/textarea';
|
|
22
|
+
import * as i2$1 from 'primeng/toggleswitch';
|
|
23
|
+
import { ToggleSwitchModule } from 'primeng/toggleswitch';
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* InjectionToken para prover mensagens de erro customizadas.
|
|
27
|
+
*/
|
|
28
|
+
const DYNAMIC_FORM_ERROR_MESSAGES = new InjectionToken('DYNAMIC_FORM_ERROR_MESSAGES');
|
|
29
|
+
|
|
30
|
+
class DynamicFormErrorComponent {
|
|
31
|
+
control = input.required(...(ngDevMode ? [{ debugName: "control" }] : []));
|
|
32
|
+
customMessages = inject(DYNAMIC_FORM_ERROR_MESSAGES, { optional: true });
|
|
33
|
+
// Mapeamento de erros para mensagens
|
|
34
|
+
defaultErrorMessages = {
|
|
35
|
+
required: () => this.customMessages?.required ?? 'Este campo é obrigatório.',
|
|
36
|
+
email: () => this.customMessages?.email ?? 'Por favor, insira um e-mail válido.',
|
|
37
|
+
minlength: (err) => this.customMessages?.minlength?.(err.requiredLength) ?? `Mínimo de ${err.requiredLength} caracteres.`,
|
|
38
|
+
maxlength: (err) => this.customMessages?.maxlength?.(err.requiredLength) ?? `Máximo de ${err.requiredLength} caracteres.`,
|
|
39
|
+
custom: (err) => (this.customMessages?.custom ? this.customMessages.custom(err) : err),
|
|
40
|
+
};
|
|
41
|
+
// Getter simples - Angular detecta mudanças automaticamente
|
|
42
|
+
get errorMessage() {
|
|
43
|
+
const ctrl = this.control();
|
|
44
|
+
if (!ctrl || !ctrl.errors || (!ctrl.touched && !ctrl.dirty)) {
|
|
45
|
+
return null;
|
|
46
|
+
}
|
|
47
|
+
const errorKey = Object.keys(ctrl.errors)[0];
|
|
48
|
+
return this.defaultErrorMessages[errorKey] ? this.defaultErrorMessages[errorKey](ctrl.errors[errorKey]) : 'Campo inválido.';
|
|
49
|
+
}
|
|
50
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.7", ngImport: i0, type: DynamicFormErrorComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
51
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.7", type: DynamicFormErrorComponent, isStandalone: true, selector: "vp-form-field-error", inputs: { control: { classPropertyName: "control", publicName: "control", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0, template: `
|
|
52
|
+
@if (errorMessage) {
|
|
53
|
+
<small class="p-error">{{ errorMessage }}</small>
|
|
54
|
+
}
|
|
55
|
+
`, isInline: true, styles: [":host{display:block;margin-top:.5rem;min-height:1rem}.p-error{color:var(--p-red-500, #ef4444);font-size:.875rem}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }] });
|
|
56
|
+
}
|
|
57
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.7", ngImport: i0, type: DynamicFormErrorComponent, decorators: [{
|
|
58
|
+
type: Component,
|
|
59
|
+
args: [{ selector: 'vp-form-field-error', standalone: true, imports: [CommonModule], template: `
|
|
60
|
+
@if (errorMessage) {
|
|
61
|
+
<small class="p-error">{{ errorMessage }}</small>
|
|
62
|
+
}
|
|
63
|
+
`, styles: [":host{display:block;margin-top:.5rem;min-height:1rem}.p-error{color:var(--p-red-500, #ef4444);font-size:.875rem}\n"] }]
|
|
64
|
+
}], propDecorators: { control: [{ type: i0.Input, args: [{ isSignal: true, alias: "control", required: true }] }] } });
|
|
65
|
+
|
|
66
|
+
class DatePickerFieldComponent {
|
|
67
|
+
form = input.required(...(ngDevMode ? [{ debugName: "form" }] : []));
|
|
68
|
+
field = input.required(...(ngDevMode ? [{ debugName: "field" }] : []));
|
|
69
|
+
dateFormat = computed(() => {
|
|
70
|
+
const viewType = this.field().dateViewType || 'date';
|
|
71
|
+
const customFormat = this.field().dateFormat;
|
|
72
|
+
if (viewType === 'month') {
|
|
73
|
+
return 'mm/yy';
|
|
74
|
+
}
|
|
75
|
+
if (viewType === 'year') {
|
|
76
|
+
return 'yy';
|
|
77
|
+
}
|
|
78
|
+
return customFormat || 'dd/mm/yyyy';
|
|
79
|
+
}, ...(ngDevMode ? [{ debugName: "dateFormat" }] : []));
|
|
80
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.7", ngImport: i0, type: DatePickerFieldComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
81
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.0.7", type: DatePickerFieldComponent, isStandalone: true, selector: "vp-datepicker-field", inputs: { form: { classPropertyName: "form", publicName: "form", isSignal: true, isRequired: true, transformFunction: null }, field: { classPropertyName: "field", publicName: "field", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0, template: `
|
|
82
|
+
<div [formGroup]="form()">
|
|
83
|
+
<p-iftalabel>
|
|
84
|
+
<p-datepicker
|
|
85
|
+
[inputId]="field().key"
|
|
86
|
+
[formControlName]="field().key"
|
|
87
|
+
[showButtonBar]="true"
|
|
88
|
+
[iconDisplay]="'input'"
|
|
89
|
+
[placeholder]="field().placeholder || ''"
|
|
90
|
+
[dateFormat]="dateFormat()"
|
|
91
|
+
[view]="field().dateViewType || 'date'"
|
|
92
|
+
[disabled]="field().disabled ?? false" />
|
|
93
|
+
<label [for]="field().key">{{ field().label }}</label>
|
|
94
|
+
</p-iftalabel>
|
|
95
|
+
</div>
|
|
96
|
+
`, isInline: true, styles: [":host{display:block;width:100%}p-iftalabel{display:block;width:100%}p-datepicker{width:100%}\n"], dependencies: [{ kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "ngmodule", type: IftaLabelModule }, { kind: "component", type: i2.IftaLabel, selector: "p-iftalabel, p-iftaLabel, p-ifta-label" }, { kind: "ngmodule", type: DatePickerModule }, { kind: "component", type: i3.DatePicker, selector: "p-datePicker, p-datepicker, p-date-picker", inputs: ["iconDisplay", "styleClass", "inputStyle", "inputId", "inputStyleClass", "placeholder", "ariaLabelledBy", "ariaLabel", "iconAriaLabel", "dateFormat", "multipleSeparator", "rangeSeparator", "inline", "showOtherMonths", "selectOtherMonths", "showIcon", "icon", "readonlyInput", "shortYearCutoff", "hourFormat", "timeOnly", "stepHour", "stepMinute", "stepSecond", "showSeconds", "showOnFocus", "showWeek", "startWeekFromFirstDayOfYear", "showClear", "dataType", "selectionMode", "maxDateCount", "showButtonBar", "todayButtonStyleClass", "clearButtonStyleClass", "autofocus", "autoZIndex", "baseZIndex", "panelStyleClass", "panelStyle", "keepInvalid", "hideOnDateTimeSelect", "touchUI", "timeSeparator", "focusTrap", "showTransitionOptions", "hideTransitionOptions", "tabindex", "minDate", "maxDate", "disabledDates", "disabledDays", "showTime", "responsiveOptions", "numberOfMonths", "firstDayOfWeek", "view", "defaultDate", "appendTo", "motionOptions"], outputs: ["onFocus", "onBlur", "onClose", "onSelect", "onClear", "onInput", "onTodayClick", "onClearClick", "onMonthChange", "onYearChange", "onClickOutside", "onShow"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
97
|
+
}
|
|
98
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.7", ngImport: i0, type: DatePickerFieldComponent, decorators: [{
|
|
99
|
+
type: Component,
|
|
100
|
+
args: [{ selector: 'vp-datepicker-field', standalone: true, imports: [ReactiveFormsModule, IftaLabelModule, DatePickerModule], changeDetection: ChangeDetectionStrategy.OnPush, template: `
|
|
101
|
+
<div [formGroup]="form()">
|
|
102
|
+
<p-iftalabel>
|
|
103
|
+
<p-datepicker
|
|
104
|
+
[inputId]="field().key"
|
|
105
|
+
[formControlName]="field().key"
|
|
106
|
+
[showButtonBar]="true"
|
|
107
|
+
[iconDisplay]="'input'"
|
|
108
|
+
[placeholder]="field().placeholder || ''"
|
|
109
|
+
[dateFormat]="dateFormat()"
|
|
110
|
+
[view]="field().dateViewType || 'date'"
|
|
111
|
+
[disabled]="field().disabled ?? false" />
|
|
112
|
+
<label [for]="field().key">{{ field().label }}</label>
|
|
113
|
+
</p-iftalabel>
|
|
114
|
+
</div>
|
|
115
|
+
`, styles: [":host{display:block;width:100%}p-iftalabel{display:block;width:100%}p-datepicker{width:100%}\n"] }]
|
|
116
|
+
}], propDecorators: { form: [{ type: i0.Input, args: [{ isSignal: true, alias: "form", required: true }] }], field: [{ type: i0.Input, args: [{ isSignal: true, alias: "field", required: true }] }] } });
|
|
117
|
+
|
|
118
|
+
class InputTextFieldComponent {
|
|
119
|
+
form = input.required(...(ngDevMode ? [{ debugName: "form" }] : []));
|
|
120
|
+
field = input.required(...(ngDevMode ? [{ debugName: "field" }] : []));
|
|
121
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.7", ngImport: i0, type: InputTextFieldComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
122
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.0.7", type: InputTextFieldComponent, isStandalone: true, selector: "vp-input-text-field", inputs: { form: { classPropertyName: "form", publicName: "form", isSignal: true, isRequired: true, transformFunction: null }, field: { classPropertyName: "field", publicName: "field", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0, template: `
|
|
123
|
+
<div [formGroup]="form()">
|
|
124
|
+
<p-iftalabel>
|
|
125
|
+
<input pInputText [id]="field().key" [type]="field().controlType" [formControlName]="field().key" [placeholder]="field().placeholder || ''" [disabled]="field().disabled ?? false" />
|
|
126
|
+
<label [for]="field().key">{{ field().label }}</label>
|
|
127
|
+
</p-iftalabel>
|
|
128
|
+
</div>
|
|
129
|
+
`, isInline: true, styles: [":host{display:block;width:100%}p-iftalabel{display:block;width:100%}input{width:100%}\n"], dependencies: [{ kind: "ngmodule", type: 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.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "ngmodule", type: IftaLabelModule }, { kind: "component", type: i2.IftaLabel, selector: "p-iftalabel, p-iftaLabel, p-ifta-label" }, { kind: "ngmodule", type: InputTextModule }, { kind: "directive", type: i3$1.InputText, selector: "[pInputText]", inputs: ["hostName", "ptInputText", "pInputTextPT", "pInputTextUnstyled", "pSize", "variant", "fluid", "invalid"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
130
|
+
}
|
|
131
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.7", ngImport: i0, type: InputTextFieldComponent, decorators: [{
|
|
132
|
+
type: Component,
|
|
133
|
+
args: [{ selector: 'vp-input-text-field', standalone: true, imports: [ReactiveFormsModule, IftaLabelModule, InputTextModule], changeDetection: ChangeDetectionStrategy.OnPush, template: `
|
|
134
|
+
<div [formGroup]="form()">
|
|
135
|
+
<p-iftalabel>
|
|
136
|
+
<input pInputText [id]="field().key" [type]="field().controlType" [formControlName]="field().key" [placeholder]="field().placeholder || ''" [disabled]="field().disabled ?? false" />
|
|
137
|
+
<label [for]="field().key">{{ field().label }}</label>
|
|
138
|
+
</p-iftalabel>
|
|
139
|
+
</div>
|
|
140
|
+
`, styles: [":host{display:block;width:100%}p-iftalabel{display:block;width:100%}input{width:100%}\n"] }]
|
|
141
|
+
}], propDecorators: { form: [{ type: i0.Input, args: [{ isSignal: true, alias: "form", required: true }] }], field: [{ type: i0.Input, args: [{ isSignal: true, alias: "field", required: true }] }] } });
|
|
142
|
+
|
|
143
|
+
class NumberInputFieldComponent {
|
|
144
|
+
form = input.required(...(ngDevMode ? [{ debugName: "form" }] : []));
|
|
145
|
+
field = input.required(...(ngDevMode ? [{ debugName: "field" }] : []));
|
|
146
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.7", ngImport: i0, type: NumberInputFieldComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
147
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.0.7", type: NumberInputFieldComponent, isStandalone: true, selector: "vp-number-input-field", inputs: { form: { classPropertyName: "form", publicName: "form", isSignal: true, isRequired: true, transformFunction: null }, field: { classPropertyName: "field", publicName: "field", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0, template: `
|
|
148
|
+
<div [formGroup]="form()">
|
|
149
|
+
<p-iftalabel>
|
|
150
|
+
<p-inputNumber [id]="field().key" [formControlName]="field().key" [placeholder]="field().placeholder || ''" [disabled]="field().disabled ?? false" styleClass="w-full" class="w-full" />
|
|
151
|
+
<label [for]="field().key">{{ field().label }}</label>
|
|
152
|
+
</p-iftalabel>
|
|
153
|
+
</div>
|
|
154
|
+
`, isInline: true, styles: [":host{display:block;width:100%}p-iftalabel{display:block;width:100%}:host ::ng-deep p-inputNumber,:host ::ng-deep .p-inputnumber,:host ::ng-deep .p-inputnumber input{width:100%}\n"], dependencies: [{ kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "ngmodule", type: IftaLabelModule }, { kind: "component", type: i2.IftaLabel, selector: "p-iftalabel, p-iftaLabel, p-ifta-label" }, { kind: "ngmodule", type: InputNumberModule }, { kind: "component", type: i3$2.InputNumber, selector: "p-inputNumber, p-inputnumber, p-input-number", inputs: ["showButtons", "format", "buttonLayout", "inputId", "styleClass", "placeholder", "tabindex", "title", "ariaLabelledBy", "ariaDescribedBy", "ariaLabel", "ariaRequired", "autocomplete", "incrementButtonClass", "decrementButtonClass", "incrementButtonIcon", "decrementButtonIcon", "readonly", "allowEmpty", "locale", "localeMatcher", "mode", "currency", "currencyDisplay", "useGrouping", "minFractionDigits", "maxFractionDigits", "prefix", "suffix", "inputStyle", "inputStyleClass", "showClear", "autofocus"], outputs: ["onInput", "onFocus", "onBlur", "onKeyDown", "onClear"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
155
|
+
}
|
|
156
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.7", ngImport: i0, type: NumberInputFieldComponent, decorators: [{
|
|
157
|
+
type: Component,
|
|
158
|
+
args: [{ selector: 'vp-number-input-field', standalone: true, imports: [ReactiveFormsModule, IftaLabelModule, InputNumberModule], changeDetection: ChangeDetectionStrategy.OnPush, template: `
|
|
159
|
+
<div [formGroup]="form()">
|
|
160
|
+
<p-iftalabel>
|
|
161
|
+
<p-inputNumber [id]="field().key" [formControlName]="field().key" [placeholder]="field().placeholder || ''" [disabled]="field().disabled ?? false" styleClass="w-full" class="w-full" />
|
|
162
|
+
<label [for]="field().key">{{ field().label }}</label>
|
|
163
|
+
</p-iftalabel>
|
|
164
|
+
</div>
|
|
165
|
+
`, styles: [":host{display:block;width:100%}p-iftalabel{display:block;width:100%}:host ::ng-deep p-inputNumber,:host ::ng-deep .p-inputnumber,:host ::ng-deep .p-inputnumber input{width:100%}\n"] }]
|
|
166
|
+
}], propDecorators: { form: [{ type: i0.Input, args: [{ isSignal: true, alias: "form", required: true }] }], field: [{ type: i0.Input, args: [{ isSignal: true, alias: "field", required: true }] }] } });
|
|
167
|
+
|
|
168
|
+
class PasswordFieldComponent {
|
|
169
|
+
form = input.required(...(ngDevMode ? [{ debugName: "form" }] : []));
|
|
170
|
+
field = input.required(...(ngDevMode ? [{ debugName: "field" }] : []));
|
|
171
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.7", ngImport: i0, type: PasswordFieldComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
172
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.0.7", type: PasswordFieldComponent, isStandalone: true, selector: "vp-password-field", inputs: { form: { classPropertyName: "form", publicName: "form", isSignal: true, isRequired: true, transformFunction: null }, field: { classPropertyName: "field", publicName: "field", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0, template: `
|
|
173
|
+
<div [formGroup]="form()">
|
|
174
|
+
<p-iftalabel>
|
|
175
|
+
<p-password
|
|
176
|
+
[id]="field().key"
|
|
177
|
+
[formControlName]="field().key"
|
|
178
|
+
[feedback]="false"
|
|
179
|
+
[toggleMask]="true"
|
|
180
|
+
[placeholder]="field().placeholder || ''"
|
|
181
|
+
[disabled]="field().disabled ?? false"
|
|
182
|
+
styleClass="w-full"
|
|
183
|
+
class="w-full" />
|
|
184
|
+
<label [for]="field().key">{{ field().label }}</label>
|
|
185
|
+
</p-iftalabel>
|
|
186
|
+
</div>
|
|
187
|
+
`, isInline: true, styles: [":host{display:block;width:100%}p-iftalabel{display:block;width:100%}:host ::ng-deep .p-password,:host ::ng-deep .p-password input{width:100%}\n"], dependencies: [{ kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "ngmodule", type: IftaLabelModule }, { kind: "component", type: i2.IftaLabel, selector: "p-iftalabel, p-iftaLabel, p-ifta-label" }, { kind: "ngmodule", type: PasswordModule }, { kind: "component", type: i3$3.Password, selector: "p-password", inputs: ["ariaLabel", "ariaLabelledBy", "label", "promptLabel", "mediumRegex", "strongRegex", "weakLabel", "mediumLabel", "maxLength", "strongLabel", "inputId", "feedback", "toggleMask", "inputStyleClass", "styleClass", "inputStyle", "showTransitionOptions", "hideTransitionOptions", "autocomplete", "placeholder", "showClear", "autofocus", "tabindex", "appendTo", "motionOptions", "overlayOptions"], outputs: ["onFocus", "onBlur", "onClear"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
188
|
+
}
|
|
189
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.7", ngImport: i0, type: PasswordFieldComponent, decorators: [{
|
|
190
|
+
type: Component,
|
|
191
|
+
args: [{ selector: 'vp-password-field', standalone: true, imports: [ReactiveFormsModule, IftaLabelModule, PasswordModule], changeDetection: ChangeDetectionStrategy.OnPush, template: `
|
|
192
|
+
<div [formGroup]="form()">
|
|
193
|
+
<p-iftalabel>
|
|
194
|
+
<p-password
|
|
195
|
+
[id]="field().key"
|
|
196
|
+
[formControlName]="field().key"
|
|
197
|
+
[feedback]="false"
|
|
198
|
+
[toggleMask]="true"
|
|
199
|
+
[placeholder]="field().placeholder || ''"
|
|
200
|
+
[disabled]="field().disabled ?? false"
|
|
201
|
+
styleClass="w-full"
|
|
202
|
+
class="w-full" />
|
|
203
|
+
<label [for]="field().key">{{ field().label }}</label>
|
|
204
|
+
</p-iftalabel>
|
|
205
|
+
</div>
|
|
206
|
+
`, styles: [":host{display:block;width:100%}p-iftalabel{display:block;width:100%}:host ::ng-deep .p-password,:host ::ng-deep .p-password input{width:100%}\n"] }]
|
|
207
|
+
}], propDecorators: { form: [{ type: i0.Input, args: [{ isSignal: true, alias: "form", required: true }] }], field: [{ type: i0.Input, args: [{ isSignal: true, alias: "field", required: true }] }] } });
|
|
208
|
+
|
|
209
|
+
class SelectFieldComponent {
|
|
210
|
+
form = input.required(...(ngDevMode ? [{ debugName: "form" }] : []));
|
|
211
|
+
field = input.required(...(ngDevMode ? [{ debugName: "field" }] : []));
|
|
212
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.7", ngImport: i0, type: SelectFieldComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
213
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.0.7", type: SelectFieldComponent, isStandalone: true, selector: "vp-select-field", inputs: { form: { classPropertyName: "form", publicName: "form", isSignal: true, isRequired: true, transformFunction: null }, field: { classPropertyName: "field", publicName: "field", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0, template: `
|
|
214
|
+
<div [formGroup]="form()">
|
|
215
|
+
<p-iftalabel>
|
|
216
|
+
<p-select
|
|
217
|
+
[inputId]="field().key"
|
|
218
|
+
[formControlName]="field().key"
|
|
219
|
+
[options]="field().options!"
|
|
220
|
+
[placeholder]="field().placeholder || 'Selecione'"
|
|
221
|
+
[disabled]="field().disabled ?? false"
|
|
222
|
+
optionLabel="label"
|
|
223
|
+
optionValue="value"
|
|
224
|
+
class="w-full" />
|
|
225
|
+
<label [for]="field().key">{{ field().label }}</label>
|
|
226
|
+
</p-iftalabel>
|
|
227
|
+
</div>
|
|
228
|
+
`, isInline: true, styles: [":host{display:block;width:100%}p-iftalabel{display:block;width:100%}p-select{width:100%}\n"], dependencies: [{ kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "ngmodule", type: IftaLabelModule }, { kind: "component", type: i2.IftaLabel, selector: "p-iftalabel, p-iftaLabel, p-ifta-label" }, { kind: "ngmodule", type: SelectModule }, { kind: "component", type: i3$4.Select, selector: "p-select", inputs: ["id", "scrollHeight", "filter", "panelStyle", "styleClass", "panelStyleClass", "readonly", "editable", "tabindex", "placeholder", "loadingIcon", "filterPlaceholder", "filterLocale", "inputId", "dataKey", "filterBy", "filterFields", "autofocus", "resetFilterOnHide", "checkmark", "dropdownIcon", "loading", "optionLabel", "optionValue", "optionDisabled", "optionGroupLabel", "optionGroupChildren", "group", "showClear", "emptyFilterMessage", "emptyMessage", "lazy", "virtualScroll", "virtualScrollItemSize", "virtualScrollOptions", "overlayOptions", "ariaFilterLabel", "ariaLabel", "ariaLabelledBy", "filterMatchMode", "tooltip", "tooltipPosition", "tooltipPositionStyle", "tooltipStyleClass", "focusOnHover", "selectOnFocus", "autoOptionFocus", "autofocusFilter", "filterValue", "options", "appendTo", "motionOptions"], outputs: ["onChange", "onFilter", "onFocus", "onBlur", "onClick", "onShow", "onHide", "onClear", "onLazyLoad"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
229
|
+
}
|
|
230
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.7", ngImport: i0, type: SelectFieldComponent, decorators: [{
|
|
231
|
+
type: Component,
|
|
232
|
+
args: [{ selector: 'vp-select-field', standalone: true, imports: [ReactiveFormsModule, IftaLabelModule, SelectModule], changeDetection: ChangeDetectionStrategy.OnPush, template: `
|
|
233
|
+
<div [formGroup]="form()">
|
|
234
|
+
<p-iftalabel>
|
|
235
|
+
<p-select
|
|
236
|
+
[inputId]="field().key"
|
|
237
|
+
[formControlName]="field().key"
|
|
238
|
+
[options]="field().options!"
|
|
239
|
+
[placeholder]="field().placeholder || 'Selecione'"
|
|
240
|
+
[disabled]="field().disabled ?? false"
|
|
241
|
+
optionLabel="label"
|
|
242
|
+
optionValue="value"
|
|
243
|
+
class="w-full" />
|
|
244
|
+
<label [for]="field().key">{{ field().label }}</label>
|
|
245
|
+
</p-iftalabel>
|
|
246
|
+
</div>
|
|
247
|
+
`, styles: [":host{display:block;width:100%}p-iftalabel{display:block;width:100%}p-select{width:100%}\n"] }]
|
|
248
|
+
}], propDecorators: { form: [{ type: i0.Input, args: [{ isSignal: true, alias: "form", required: true }] }], field: [{ type: i0.Input, args: [{ isSignal: true, alias: "field", required: true }] }] } });
|
|
249
|
+
|
|
250
|
+
class TextareaFieldComponent {
|
|
251
|
+
form = input.required(...(ngDevMode ? [{ debugName: "form" }] : []));
|
|
252
|
+
field = input.required(...(ngDevMode ? [{ debugName: "field" }] : []));
|
|
253
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.7", ngImport: i0, type: TextareaFieldComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
254
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.0.7", type: TextareaFieldComponent, isStandalone: true, selector: "vp-textarea-field", inputs: { form: { classPropertyName: "form", publicName: "form", isSignal: true, isRequired: true, transformFunction: null }, field: { classPropertyName: "field", publicName: "field", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0, template: `
|
|
255
|
+
<div [formGroup]="form()">
|
|
256
|
+
<p-iftalabel>
|
|
257
|
+
<textarea
|
|
258
|
+
pTextarea
|
|
259
|
+
[id]="field().key"
|
|
260
|
+
[formControlName]="field().key"
|
|
261
|
+
[placeholder]="field().placeholder || ''"
|
|
262
|
+
[rows]="field().textareaRows ?? 1"
|
|
263
|
+
[cols]="field().textareaCols"
|
|
264
|
+
[autoResize]="field().textareaAutoResize ?? false"
|
|
265
|
+
[disabled]="field().disabled ?? false"
|
|
266
|
+
></textarea>
|
|
267
|
+
<label [for]="field().key">{{ field().label }}</label>
|
|
268
|
+
</p-iftalabel>
|
|
269
|
+
</div>
|
|
270
|
+
`, isInline: true, styles: [":host{display:block;width:100%}p-iftalabel{display:block;width:100%}textarea{width:100%}\n"], dependencies: [{ kind: "ngmodule", type: 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.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "ngmodule", type: IftaLabelModule }, { kind: "component", type: i2.IftaLabel, selector: "p-iftalabel, p-iftaLabel, p-ifta-label" }, { kind: "ngmodule", type: TextareaModule }, { kind: "directive", type: i3$5.Textarea, selector: "[pTextarea], [pInputTextarea]", inputs: ["pTextareaPT", "pTextareaUnstyled", "autoResize", "pSize", "variant", "fluid", "invalid"], outputs: ["onResize"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
271
|
+
}
|
|
272
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.7", ngImport: i0, type: TextareaFieldComponent, decorators: [{
|
|
273
|
+
type: Component,
|
|
274
|
+
args: [{ selector: 'vp-textarea-field', standalone: true, imports: [ReactiveFormsModule, IftaLabelModule, TextareaModule], changeDetection: ChangeDetectionStrategy.OnPush, template: `
|
|
275
|
+
<div [formGroup]="form()">
|
|
276
|
+
<p-iftalabel>
|
|
277
|
+
<textarea
|
|
278
|
+
pTextarea
|
|
279
|
+
[id]="field().key"
|
|
280
|
+
[formControlName]="field().key"
|
|
281
|
+
[placeholder]="field().placeholder || ''"
|
|
282
|
+
[rows]="field().textareaRows ?? 1"
|
|
283
|
+
[cols]="field().textareaCols"
|
|
284
|
+
[autoResize]="field().textareaAutoResize ?? false"
|
|
285
|
+
[disabled]="field().disabled ?? false"
|
|
286
|
+
></textarea>
|
|
287
|
+
<label [for]="field().key">{{ field().label }}</label>
|
|
288
|
+
</p-iftalabel>
|
|
289
|
+
</div>
|
|
290
|
+
`, styles: [":host{display:block;width:100%}p-iftalabel{display:block;width:100%}textarea{width:100%}\n"] }]
|
|
291
|
+
}], propDecorators: { form: [{ type: i0.Input, args: [{ isSignal: true, alias: "form", required: true }] }], field: [{ type: i0.Input, args: [{ isSignal: true, alias: "field", required: true }] }] } });
|
|
292
|
+
|
|
293
|
+
class ToggleSwitchFieldComponent {
|
|
294
|
+
form = input.required(...(ngDevMode ? [{ debugName: "form" }] : []));
|
|
295
|
+
field = input.required(...(ngDevMode ? [{ debugName: "field" }] : []));
|
|
296
|
+
isInvalid = computed(() => {
|
|
297
|
+
const control = this.form().get(this.field().key);
|
|
298
|
+
return control ? control.invalid && (control.touched || control.dirty) : false;
|
|
299
|
+
}, ...(ngDevMode ? [{ debugName: "isInvalid" }] : []));
|
|
300
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.7", ngImport: i0, type: ToggleSwitchFieldComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
301
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.0.7", type: ToggleSwitchFieldComponent, isStandalone: true, selector: "vp-toggleswitch-field", inputs: { form: { classPropertyName: "form", publicName: "form", isSignal: true, isRequired: true, transformFunction: null }, field: { classPropertyName: "field", publicName: "field", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0, template: `
|
|
302
|
+
<div [formGroup]="form()" class="toggleswitch-field">
|
|
303
|
+
<p-toggleswitch
|
|
304
|
+
[formControlName]="field().key"
|
|
305
|
+
[inputId]="field().key"
|
|
306
|
+
[invalid]="isInvalid()"
|
|
307
|
+
[disabled]="field().disabled ?? false"
|
|
308
|
+
[trueValue]="field().toggleTrueValue ?? true"
|
|
309
|
+
[falseValue]="field().toggleFalseValue ?? false" />
|
|
310
|
+
<label [for]="field().key" class="toggleswitch-label">{{ field().label }}</label>
|
|
311
|
+
</div>
|
|
312
|
+
`, isInline: true, styles: [":host{display:block;width:100%}.toggleswitch-field{display:flex;align-items:center;gap:.75rem;width:100%}.toggleswitch-label{cursor:pointer;-webkit-user-select:none;user-select:none;font-size:.875rem;color:var(--p-text-color, #333);margin:0}p-toggleswitch{flex-shrink:0}\n"], dependencies: [{ kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "ngmodule", type: ToggleSwitchModule }, { kind: "component", type: i2$1.ToggleSwitch, selector: "p-toggleswitch, p-toggleSwitch, p-toggle-switch", inputs: ["styleClass", "tabindex", "inputId", "readonly", "trueValue", "falseValue", "ariaLabel", "size", "ariaLabelledBy", "autofocus"], outputs: ["onChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
313
|
+
}
|
|
314
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.7", ngImport: i0, type: ToggleSwitchFieldComponent, decorators: [{
|
|
315
|
+
type: Component,
|
|
316
|
+
args: [{ selector: 'vp-toggleswitch-field', standalone: true, imports: [ReactiveFormsModule, ToggleSwitchModule], changeDetection: ChangeDetectionStrategy.OnPush, template: `
|
|
317
|
+
<div [formGroup]="form()" class="toggleswitch-field">
|
|
318
|
+
<p-toggleswitch
|
|
319
|
+
[formControlName]="field().key"
|
|
320
|
+
[inputId]="field().key"
|
|
321
|
+
[invalid]="isInvalid()"
|
|
322
|
+
[disabled]="field().disabled ?? false"
|
|
323
|
+
[trueValue]="field().toggleTrueValue ?? true"
|
|
324
|
+
[falseValue]="field().toggleFalseValue ?? false" />
|
|
325
|
+
<label [for]="field().key" class="toggleswitch-label">{{ field().label }}</label>
|
|
326
|
+
</div>
|
|
327
|
+
`, styles: [":host{display:block;width:100%}.toggleswitch-field{display:flex;align-items:center;gap:.75rem;width:100%}.toggleswitch-label{cursor:pointer;-webkit-user-select:none;user-select:none;font-size:.875rem;color:var(--p-text-color, #333);margin:0}p-toggleswitch{flex-shrink:0}\n"] }]
|
|
328
|
+
}], propDecorators: { form: [{ type: i0.Input, args: [{ isSignal: true, alias: "form", required: true }] }], field: [{ type: i0.Input, args: [{ isSignal: true, alias: "field", required: true }] }] } });
|
|
329
|
+
|
|
330
|
+
/**
|
|
331
|
+
* Serviço para registro de campos customizados.
|
|
332
|
+
* Permite adicionar novos tipos de campos dinamicamente.
|
|
333
|
+
*/
|
|
334
|
+
class FieldRegistryService {
|
|
335
|
+
registry = signal(new Map(), ...(ngDevMode ? [{ debugName: "registry" }] : []));
|
|
336
|
+
/**
|
|
337
|
+
* Registra um novo tipo de campo.
|
|
338
|
+
* @param type Tipo do campo (ex: 'custom', 'file', etc.)
|
|
339
|
+
* @param component Componente Angular que renderiza o campo
|
|
340
|
+
*/
|
|
341
|
+
registerField(type, component) {
|
|
342
|
+
this.registry.update((map) => new Map(map).set(type, component));
|
|
343
|
+
}
|
|
344
|
+
/**
|
|
345
|
+
* Obtém o componente registrado para um tipo de campo.
|
|
346
|
+
* @param type Tipo do campo
|
|
347
|
+
* @returns Componente Angular ou undefined se não encontrado
|
|
348
|
+
*/
|
|
349
|
+
getField(type) {
|
|
350
|
+
return this.registry().get(type);
|
|
351
|
+
}
|
|
352
|
+
/**
|
|
353
|
+
* Remove um tipo de campo do registro.
|
|
354
|
+
* @param type Tipo do campo a ser removido
|
|
355
|
+
*/
|
|
356
|
+
unregisterField(type) {
|
|
357
|
+
this.registry.update((map) => {
|
|
358
|
+
const newMap = new Map(map);
|
|
359
|
+
newMap.delete(type);
|
|
360
|
+
return newMap;
|
|
361
|
+
});
|
|
362
|
+
}
|
|
363
|
+
/**
|
|
364
|
+
* Limpa todos os campos registrados.
|
|
365
|
+
*/
|
|
366
|
+
clear() {
|
|
367
|
+
this.registry.set(new Map());
|
|
368
|
+
}
|
|
369
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.7", ngImport: i0, type: FieldRegistryService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
370
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.0.7", ngImport: i0, type: FieldRegistryService, providedIn: 'root' });
|
|
371
|
+
}
|
|
372
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.7", ngImport: i0, type: FieldRegistryService, decorators: [{
|
|
373
|
+
type: Injectable,
|
|
374
|
+
args: [{ providedIn: 'root' }]
|
|
375
|
+
}] });
|
|
376
|
+
|
|
377
|
+
class DynamicFormComponent {
|
|
378
|
+
destroyRef = inject(DestroyRef);
|
|
379
|
+
fieldRegistry = inject(FieldRegistryService);
|
|
380
|
+
config = input.required(...(ngDevMode ? [{ debugName: "config" }] : []));
|
|
381
|
+
formReady = output();
|
|
382
|
+
form = new FormGroup({});
|
|
383
|
+
fieldComponents = {
|
|
384
|
+
text: InputTextFieldComponent,
|
|
385
|
+
email: InputTextFieldComponent,
|
|
386
|
+
password: PasswordFieldComponent,
|
|
387
|
+
number: NumberInputFieldComponent,
|
|
388
|
+
select: SelectFieldComponent,
|
|
389
|
+
datepicker: DatePickerFieldComponent,
|
|
390
|
+
textarea: TextareaFieldComponent,
|
|
391
|
+
toggleswitch: ToggleSwitchFieldComponent,
|
|
392
|
+
};
|
|
393
|
+
ngOnInit() {
|
|
394
|
+
const configValue = this.config();
|
|
395
|
+
if (configValue && configValue.length > 0) {
|
|
396
|
+
this.buildForm(configValue);
|
|
397
|
+
this.setupFieldDependencies(configValue);
|
|
398
|
+
this.formReady.emit(this.form);
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
buildForm(config) {
|
|
402
|
+
config.forEach((field) => {
|
|
403
|
+
// Para toggle switch, o valor padrão é false se não especificado
|
|
404
|
+
const defaultValue = field.controlType === 'toggleswitch' ? (field.value ?? false) : (field.value ?? '');
|
|
405
|
+
// Se o campo tem enabledWhen, ele deve começar desabilitado a menos que o toggle já esteja ativo
|
|
406
|
+
const shouldBeDisabled = field.disabled ?? (field.enabledWhen ? !this.getToggleValue(field.enabledWhen, config) : false);
|
|
407
|
+
const control = shouldBeDisabled
|
|
408
|
+
? new FormControl({ value: defaultValue, disabled: true }, {
|
|
409
|
+
validators: field.validators ?? [],
|
|
410
|
+
})
|
|
411
|
+
: new FormControl(defaultValue, {
|
|
412
|
+
validators: field.validators ?? [],
|
|
413
|
+
});
|
|
414
|
+
this.form.addControl(field.key, control);
|
|
415
|
+
});
|
|
416
|
+
}
|
|
417
|
+
setupFieldDependencies(config) {
|
|
418
|
+
config.forEach((field) => {
|
|
419
|
+
if (!field.enabledWhen) {
|
|
420
|
+
return;
|
|
421
|
+
}
|
|
422
|
+
const toggleField = config.find((f) => f.key === field.enabledWhen);
|
|
423
|
+
if (!toggleField) {
|
|
424
|
+
console.warn(`DynamicFormComponent: Campo '${field.key}' referencia '${field.enabledWhen}' em enabledWhen, mas este campo não existe no formulário.`);
|
|
425
|
+
return;
|
|
426
|
+
}
|
|
427
|
+
if (toggleField.controlType !== 'toggleswitch') {
|
|
428
|
+
console.warn(`DynamicFormComponent: Campo '${field.key}' referencia '${field.enabledWhen}' em enabledWhen, mas este campo não é do tipo 'toggleswitch'.`);
|
|
429
|
+
return;
|
|
430
|
+
}
|
|
431
|
+
const toggleControl = this.form.get(field.enabledWhen);
|
|
432
|
+
const dependentControl = this.form.get(field.key);
|
|
433
|
+
if (!toggleControl || !dependentControl) {
|
|
434
|
+
console.warn(`DynamicFormComponent: Não foi possível encontrar os controles para configurar a dependência entre '${field.enabledWhen}' e '${field.key}'.`);
|
|
435
|
+
return;
|
|
436
|
+
}
|
|
437
|
+
// Configura a subscription para reagir às mudanças do toggle
|
|
438
|
+
toggleControl.valueChanges.pipe(takeUntilDestroyed(this.destroyRef)).subscribe((toggleValue) => {
|
|
439
|
+
const isToggleActive = toggleValue === (toggleField.toggleTrueValue ?? true);
|
|
440
|
+
if (isToggleActive) {
|
|
441
|
+
dependentControl.enable();
|
|
442
|
+
}
|
|
443
|
+
else {
|
|
444
|
+
// Limpa o valor do campo antes de desabilitá-lo
|
|
445
|
+
const resetValue = this.getResetValueForFieldType(field.controlType);
|
|
446
|
+
dependentControl.setValue(resetValue, { emitEvent: false });
|
|
447
|
+
dependentControl.disable();
|
|
448
|
+
}
|
|
449
|
+
});
|
|
450
|
+
});
|
|
451
|
+
}
|
|
452
|
+
getToggleValue(toggleKey, config) {
|
|
453
|
+
const toggleField = config.find((f) => f.key === toggleKey);
|
|
454
|
+
if (!toggleField || toggleField.controlType !== 'toggleswitch') {
|
|
455
|
+
return false;
|
|
456
|
+
}
|
|
457
|
+
const toggleTrueValue = toggleField.toggleTrueValue ?? true;
|
|
458
|
+
const toggleValue = toggleField.value ?? false;
|
|
459
|
+
return toggleValue === toggleTrueValue;
|
|
460
|
+
}
|
|
461
|
+
/**
|
|
462
|
+
* Retorna o valor padrão de reset para cada tipo de campo.
|
|
463
|
+
* Usado quando um campo dependente é desabilitado e precisa ser limpo.
|
|
464
|
+
*/
|
|
465
|
+
getResetValueForFieldType(controlType) {
|
|
466
|
+
switch (controlType) {
|
|
467
|
+
case 'text':
|
|
468
|
+
case 'email':
|
|
469
|
+
case 'password':
|
|
470
|
+
case 'textarea':
|
|
471
|
+
return '';
|
|
472
|
+
case 'number':
|
|
473
|
+
return null;
|
|
474
|
+
case 'select':
|
|
475
|
+
return null;
|
|
476
|
+
case 'datepicker':
|
|
477
|
+
return null;
|
|
478
|
+
default:
|
|
479
|
+
return '';
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
/**
|
|
483
|
+
* Obtém o componente a ser renderizado para um tipo de campo.
|
|
484
|
+
* Primeiro verifica no registro customizado, depois nos componentes padrão.
|
|
485
|
+
*/
|
|
486
|
+
getFieldComponent(controlType) {
|
|
487
|
+
// Verifica primeiro no registro customizado
|
|
488
|
+
const customComponent = this.fieldRegistry.getField(controlType);
|
|
489
|
+
if (customComponent) {
|
|
490
|
+
return customComponent;
|
|
491
|
+
}
|
|
492
|
+
// Fallback para componentes padrão
|
|
493
|
+
return this.fieldComponents[controlType] || null;
|
|
494
|
+
}
|
|
495
|
+
getControl(key) {
|
|
496
|
+
const control = this.form.get(key);
|
|
497
|
+
if (!control) {
|
|
498
|
+
console.warn(`DynamicFormComponent: Controle não encontrado para a chave: ${key}`);
|
|
499
|
+
}
|
|
500
|
+
return control;
|
|
501
|
+
}
|
|
502
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.7", ngImport: i0, type: DynamicFormComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
503
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.7", type: DynamicFormComponent, isStandalone: true, selector: "vp-dynamic-form", inputs: { config: { classPropertyName: "config", publicName: "config", isSignal: true, isRequired: true, transformFunction: null } }, outputs: { formReady: "formReady" }, ngImport: i0, template: "<form [formGroup]=\"form\" class=\"dynamic-form-container\">\n @for (field of config(); track field.key) {\n @if (getFieldComponent(field.controlType); as fieldComponent) {\n <div [class]=\"'form-field-wrapper ' + (field.styleClass || '')\">\n <!-- Dynamically render the correct field component -->\n <ng-container [ngComponentOutlet]=\"fieldComponent\" [ngComponentOutletInputs]=\"{ form: form, field: field }\" />\n\n @if (field.hint) {\n <small class=\"hint-text\">{{ field.hint }}</small>\n }\n\n <!-- Reusable error display component -->\n <vp-form-field-error [control]=\"getControl(field.key)\" />\n </div>\n } @else {\n <div class=\"form-field-wrapper\">\n <small class=\"p-error\">Tipo de campo '{{ field.controlType }}' n\u00E3o encontrado.</small>\n </div>\n }\n }\n</form>\n", styles: ["@charset \"UTF-8\";:host{display:block;width:100%}.dynamic-form-container{display:flex;flex-direction:column;gap:1.75rem;padding:1rem;border:1px solid var(--p-surface-border);border-radius:var(--p-border-radius);background-color:var(--p-surface-section)}.form-field-wrapper{display:flex;flex-direction:column;position:relative}:is(p-inputNumber,p-password,p-select,p-iftalabel){width:100%}:host ::ng-deep .p-password,:host ::ng-deep .p-password input,:host ::ng-deep .p-inputnumber,:host ::ng-deep .p-inputnumber input,:host ::ng-deep .p-datepicker input,:host ::ng-deep .p-select{width:100%!important}input[pInputText]{width:100%}.hint-text{margin-top:.5rem;color:var(--p-text-muted-color)}.error-messages{margin-top:.5rem;display:flex;flex-direction:column}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$1.NgComponentOutlet, selector: "[ngComponentOutlet]", inputs: ["ngComponentOutlet", "ngComponentOutletInputs", "ngComponentOutletInjector", "ngComponentOutletEnvironmentInjector", "ngComponentOutletContent", "ngComponentOutletNgModule"], exportAs: ["ngComponentOutlet"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "component", type: DynamicFormErrorComponent, selector: "vp-form-field-error", inputs: ["control"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
504
|
+
}
|
|
505
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.7", ngImport: i0, type: DynamicFormComponent, decorators: [{
|
|
506
|
+
type: Component,
|
|
507
|
+
args: [{ selector: 'vp-dynamic-form', standalone: true, imports: [CommonModule, ReactiveFormsModule, NgComponentOutlet, DynamicFormErrorComponent], changeDetection: ChangeDetectionStrategy.OnPush, template: "<form [formGroup]=\"form\" class=\"dynamic-form-container\">\n @for (field of config(); track field.key) {\n @if (getFieldComponent(field.controlType); as fieldComponent) {\n <div [class]=\"'form-field-wrapper ' + (field.styleClass || '')\">\n <!-- Dynamically render the correct field component -->\n <ng-container [ngComponentOutlet]=\"fieldComponent\" [ngComponentOutletInputs]=\"{ form: form, field: field }\" />\n\n @if (field.hint) {\n <small class=\"hint-text\">{{ field.hint }}</small>\n }\n\n <!-- Reusable error display component -->\n <vp-form-field-error [control]=\"getControl(field.key)\" />\n </div>\n } @else {\n <div class=\"form-field-wrapper\">\n <small class=\"p-error\">Tipo de campo '{{ field.controlType }}' n\u00E3o encontrado.</small>\n </div>\n }\n }\n</form>\n", styles: ["@charset \"UTF-8\";:host{display:block;width:100%}.dynamic-form-container{display:flex;flex-direction:column;gap:1.75rem;padding:1rem;border:1px solid var(--p-surface-border);border-radius:var(--p-border-radius);background-color:var(--p-surface-section)}.form-field-wrapper{display:flex;flex-direction:column;position:relative}:is(p-inputNumber,p-password,p-select,p-iftalabel){width:100%}:host ::ng-deep .p-password,:host ::ng-deep .p-password input,:host ::ng-deep .p-inputnumber,:host ::ng-deep .p-inputnumber input,:host ::ng-deep .p-datepicker input,:host ::ng-deep .p-select{width:100%!important}input[pInputText]{width:100%}.hint-text{margin-top:.5rem;color:var(--p-text-muted-color)}.error-messages{margin-top:.5rem;display:flex;flex-direction:column}\n"] }]
|
|
508
|
+
}], propDecorators: { config: [{ type: i0.Input, args: [{ isSignal: true, alias: "config", required: true }] }], formReady: [{ type: i0.Output, args: ["formReady"] }] } });
|
|
509
|
+
|
|
510
|
+
/**
|
|
511
|
+
* Provider para configurar mensagens de erro customizadas.
|
|
512
|
+
* @param messages Mensagens de erro customizadas
|
|
513
|
+
* @returns Provider configurado
|
|
514
|
+
*/
|
|
515
|
+
function provideDynamicFormConfig(messages) {
|
|
516
|
+
const providers = [];
|
|
517
|
+
if (messages) {
|
|
518
|
+
providers.push({
|
|
519
|
+
provide: DYNAMIC_FORM_ERROR_MESSAGES,
|
|
520
|
+
useValue: messages,
|
|
521
|
+
});
|
|
522
|
+
}
|
|
523
|
+
return providers;
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
/*
|
|
527
|
+
* Public API Surface of @vipsolucoes/dynamic-form
|
|
528
|
+
*/
|
|
529
|
+
// Componentes
|
|
530
|
+
|
|
531
|
+
/**
|
|
532
|
+
* Generated bundle index. Do not edit.
|
|
533
|
+
*/
|
|
534
|
+
|
|
535
|
+
export { DYNAMIC_FORM_ERROR_MESSAGES, DatePickerFieldComponent, DynamicFormComponent, DynamicFormErrorComponent, FieldRegistryService, InputTextFieldComponent, NumberInputFieldComponent, PasswordFieldComponent, SelectFieldComponent, TextareaFieldComponent, ToggleSwitchFieldComponent, provideDynamicFormConfig };
|
|
536
|
+
//# sourceMappingURL=vipsolucoes-dynamic-form.mjs.map
|