@vipsolucoes/dynamic-form 1.0.2
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,678 @@
|
|
|
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/yy';
|
|
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
|
+
/>
|
|
94
|
+
<label [for]="field().key">{{ field().label }}</label>
|
|
95
|
+
</p-iftalabel>
|
|
96
|
+
</div>
|
|
97
|
+
`, 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 });
|
|
98
|
+
}
|
|
99
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.7", ngImport: i0, type: DatePickerFieldComponent, decorators: [{
|
|
100
|
+
type: Component,
|
|
101
|
+
args: [{ selector: 'vp-datepicker-field', standalone: true, imports: [ReactiveFormsModule, IftaLabelModule, DatePickerModule], changeDetection: ChangeDetectionStrategy.OnPush, template: `
|
|
102
|
+
<div [formGroup]="form()">
|
|
103
|
+
<p-iftalabel>
|
|
104
|
+
<p-datepicker
|
|
105
|
+
[inputId]="field().key"
|
|
106
|
+
[formControlName]="field().key"
|
|
107
|
+
[showButtonBar]="true"
|
|
108
|
+
[iconDisplay]="'input'"
|
|
109
|
+
[placeholder]="field().placeholder || ''"
|
|
110
|
+
[dateFormat]="dateFormat()"
|
|
111
|
+
[view]="field().dateViewType || 'date'"
|
|
112
|
+
[disabled]="field().disabled ?? false"
|
|
113
|
+
/>
|
|
114
|
+
<label [for]="field().key">{{ field().label }}</label>
|
|
115
|
+
</p-iftalabel>
|
|
116
|
+
</div>
|
|
117
|
+
`, styles: [":host{display:block;width:100%}p-iftalabel{display:block;width:100%}p-datepicker{width:100%}\n"] }]
|
|
118
|
+
}], propDecorators: { form: [{ type: i0.Input, args: [{ isSignal: true, alias: "form", required: true }] }], field: [{ type: i0.Input, args: [{ isSignal: true, alias: "field", required: true }] }] } });
|
|
119
|
+
|
|
120
|
+
class InputTextFieldComponent {
|
|
121
|
+
form = input.required(...(ngDevMode ? [{ debugName: "form" }] : []));
|
|
122
|
+
field = input.required(...(ngDevMode ? [{ debugName: "field" }] : []));
|
|
123
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.7", ngImport: i0, type: InputTextFieldComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
124
|
+
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: `
|
|
125
|
+
<div [formGroup]="form()">
|
|
126
|
+
<p-iftalabel>
|
|
127
|
+
<input pInputText [id]="field().key" [type]="field().controlType" [formControlName]="field().key" [placeholder]="field().placeholder || ''" [disabled]="field().disabled ?? false" />
|
|
128
|
+
<label [for]="field().key">{{ field().label }}</label>
|
|
129
|
+
</p-iftalabel>
|
|
130
|
+
</div>
|
|
131
|
+
`, 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 });
|
|
132
|
+
}
|
|
133
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.7", ngImport: i0, type: InputTextFieldComponent, decorators: [{
|
|
134
|
+
type: Component,
|
|
135
|
+
args: [{ selector: 'vp-input-text-field', standalone: true, imports: [ReactiveFormsModule, IftaLabelModule, InputTextModule], changeDetection: ChangeDetectionStrategy.OnPush, template: `
|
|
136
|
+
<div [formGroup]="form()">
|
|
137
|
+
<p-iftalabel>
|
|
138
|
+
<input pInputText [id]="field().key" [type]="field().controlType" [formControlName]="field().key" [placeholder]="field().placeholder || ''" [disabled]="field().disabled ?? false" />
|
|
139
|
+
<label [for]="field().key">{{ field().label }}</label>
|
|
140
|
+
</p-iftalabel>
|
|
141
|
+
</div>
|
|
142
|
+
`, styles: [":host{display:block;width:100%}p-iftalabel{display:block;width:100%}input{width:100%}\n"] }]
|
|
143
|
+
}], propDecorators: { form: [{ type: i0.Input, args: [{ isSignal: true, alias: "form", required: true }] }], field: [{ type: i0.Input, args: [{ isSignal: true, alias: "field", required: true }] }] } });
|
|
144
|
+
|
|
145
|
+
class NumberInputFieldComponent {
|
|
146
|
+
form = input.required(...(ngDevMode ? [{ debugName: "form" }] : []));
|
|
147
|
+
field = input.required(...(ngDevMode ? [{ debugName: "field" }] : []));
|
|
148
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.7", ngImport: i0, type: NumberInputFieldComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
149
|
+
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: `
|
|
150
|
+
<div [formGroup]="form()">
|
|
151
|
+
<p-iftalabel>
|
|
152
|
+
<p-inputNumber [id]="field().key" [formControlName]="field().key" [placeholder]="field().placeholder || ''" [disabled]="field().disabled ?? false" styleClass="w-full" class="w-full" />
|
|
153
|
+
<label [for]="field().key">{{ field().label }}</label>
|
|
154
|
+
</p-iftalabel>
|
|
155
|
+
</div>
|
|
156
|
+
`, 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 });
|
|
157
|
+
}
|
|
158
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.7", ngImport: i0, type: NumberInputFieldComponent, decorators: [{
|
|
159
|
+
type: Component,
|
|
160
|
+
args: [{ selector: 'vp-number-input-field', standalone: true, imports: [ReactiveFormsModule, IftaLabelModule, InputNumberModule], changeDetection: ChangeDetectionStrategy.OnPush, template: `
|
|
161
|
+
<div [formGroup]="form()">
|
|
162
|
+
<p-iftalabel>
|
|
163
|
+
<p-inputNumber [id]="field().key" [formControlName]="field().key" [placeholder]="field().placeholder || ''" [disabled]="field().disabled ?? false" styleClass="w-full" class="w-full" />
|
|
164
|
+
<label [for]="field().key">{{ field().label }}</label>
|
|
165
|
+
</p-iftalabel>
|
|
166
|
+
</div>
|
|
167
|
+
`, 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"] }]
|
|
168
|
+
}], propDecorators: { form: [{ type: i0.Input, args: [{ isSignal: true, alias: "form", required: true }] }], field: [{ type: i0.Input, args: [{ isSignal: true, alias: "field", required: true }] }] } });
|
|
169
|
+
|
|
170
|
+
class PasswordFieldComponent {
|
|
171
|
+
form = input.required(...(ngDevMode ? [{ debugName: "form" }] : []));
|
|
172
|
+
field = input.required(...(ngDevMode ? [{ debugName: "field" }] : []));
|
|
173
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.7", ngImport: i0, type: PasswordFieldComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
174
|
+
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: `
|
|
175
|
+
<div [formGroup]="form()">
|
|
176
|
+
<p-iftalabel>
|
|
177
|
+
<p-password
|
|
178
|
+
[id]="field().key"
|
|
179
|
+
[formControlName]="field().key"
|
|
180
|
+
[feedback]="false"
|
|
181
|
+
[toggleMask]="true"
|
|
182
|
+
[placeholder]="field().placeholder || ''"
|
|
183
|
+
[disabled]="field().disabled ?? false"
|
|
184
|
+
styleClass="w-full"
|
|
185
|
+
class="w-full" />
|
|
186
|
+
<label [for]="field().key">{{ field().label }}</label>
|
|
187
|
+
</p-iftalabel>
|
|
188
|
+
</div>
|
|
189
|
+
`, 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 });
|
|
190
|
+
}
|
|
191
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.7", ngImport: i0, type: PasswordFieldComponent, decorators: [{
|
|
192
|
+
type: Component,
|
|
193
|
+
args: [{ selector: 'vp-password-field', standalone: true, imports: [ReactiveFormsModule, IftaLabelModule, PasswordModule], changeDetection: ChangeDetectionStrategy.OnPush, template: `
|
|
194
|
+
<div [formGroup]="form()">
|
|
195
|
+
<p-iftalabel>
|
|
196
|
+
<p-password
|
|
197
|
+
[id]="field().key"
|
|
198
|
+
[formControlName]="field().key"
|
|
199
|
+
[feedback]="false"
|
|
200
|
+
[toggleMask]="true"
|
|
201
|
+
[placeholder]="field().placeholder || ''"
|
|
202
|
+
[disabled]="field().disabled ?? false"
|
|
203
|
+
styleClass="w-full"
|
|
204
|
+
class="w-full" />
|
|
205
|
+
<label [for]="field().key">{{ field().label }}</label>
|
|
206
|
+
</p-iftalabel>
|
|
207
|
+
</div>
|
|
208
|
+
`, 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"] }]
|
|
209
|
+
}], propDecorators: { form: [{ type: i0.Input, args: [{ isSignal: true, alias: "form", required: true }] }], field: [{ type: i0.Input, args: [{ isSignal: true, alias: "field", required: true }] }] } });
|
|
210
|
+
|
|
211
|
+
class SelectFieldComponent {
|
|
212
|
+
form = input.required(...(ngDevMode ? [{ debugName: "form" }] : []));
|
|
213
|
+
field = input.required(...(ngDevMode ? [{ debugName: "field" }] : []));
|
|
214
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.7", ngImport: i0, type: SelectFieldComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
215
|
+
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: `
|
|
216
|
+
<div [formGroup]="form()">
|
|
217
|
+
<p-iftalabel>
|
|
218
|
+
<p-select
|
|
219
|
+
[inputId]="field().key"
|
|
220
|
+
[formControlName]="field().key"
|
|
221
|
+
[options]="field().options!"
|
|
222
|
+
[placeholder]="field().placeholder || 'Selecione'"
|
|
223
|
+
[disabled]="field().disabled ?? false"
|
|
224
|
+
optionLabel="label"
|
|
225
|
+
optionValue="value"
|
|
226
|
+
class="w-full" />
|
|
227
|
+
<label [for]="field().key">{{ field().label }}</label>
|
|
228
|
+
</p-iftalabel>
|
|
229
|
+
</div>
|
|
230
|
+
`, 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 });
|
|
231
|
+
}
|
|
232
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.7", ngImport: i0, type: SelectFieldComponent, decorators: [{
|
|
233
|
+
type: Component,
|
|
234
|
+
args: [{ selector: 'vp-select-field', standalone: true, imports: [ReactiveFormsModule, IftaLabelModule, SelectModule], changeDetection: ChangeDetectionStrategy.OnPush, template: `
|
|
235
|
+
<div [formGroup]="form()">
|
|
236
|
+
<p-iftalabel>
|
|
237
|
+
<p-select
|
|
238
|
+
[inputId]="field().key"
|
|
239
|
+
[formControlName]="field().key"
|
|
240
|
+
[options]="field().options!"
|
|
241
|
+
[placeholder]="field().placeholder || 'Selecione'"
|
|
242
|
+
[disabled]="field().disabled ?? false"
|
|
243
|
+
optionLabel="label"
|
|
244
|
+
optionValue="value"
|
|
245
|
+
class="w-full" />
|
|
246
|
+
<label [for]="field().key">{{ field().label }}</label>
|
|
247
|
+
</p-iftalabel>
|
|
248
|
+
</div>
|
|
249
|
+
`, styles: [":host{display:block;width:100%}p-iftalabel{display:block;width:100%}p-select{width:100%}\n"] }]
|
|
250
|
+
}], propDecorators: { form: [{ type: i0.Input, args: [{ isSignal: true, alias: "form", required: true }] }], field: [{ type: i0.Input, args: [{ isSignal: true, alias: "field", required: true }] }] } });
|
|
251
|
+
|
|
252
|
+
class TextareaFieldComponent {
|
|
253
|
+
form = input.required(...(ngDevMode ? [{ debugName: "form" }] : []));
|
|
254
|
+
field = input.required(...(ngDevMode ? [{ debugName: "field" }] : []));
|
|
255
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.7", ngImport: i0, type: TextareaFieldComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
256
|
+
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: `
|
|
257
|
+
<div [formGroup]="form()">
|
|
258
|
+
<p-iftalabel>
|
|
259
|
+
<textarea
|
|
260
|
+
pTextarea
|
|
261
|
+
[id]="field().key"
|
|
262
|
+
[formControlName]="field().key"
|
|
263
|
+
[placeholder]="field().placeholder || ''"
|
|
264
|
+
[rows]="field().textareaRows ?? 1"
|
|
265
|
+
[cols]="field().textareaCols"
|
|
266
|
+
[autoResize]="field().textareaAutoResize ?? false"
|
|
267
|
+
[disabled]="field().disabled ?? false"
|
|
268
|
+
></textarea>
|
|
269
|
+
<label [for]="field().key">{{ field().label }}</label>
|
|
270
|
+
</p-iftalabel>
|
|
271
|
+
</div>
|
|
272
|
+
`, 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 });
|
|
273
|
+
}
|
|
274
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.7", ngImport: i0, type: TextareaFieldComponent, decorators: [{
|
|
275
|
+
type: Component,
|
|
276
|
+
args: [{ selector: 'vp-textarea-field', standalone: true, imports: [ReactiveFormsModule, IftaLabelModule, TextareaModule], changeDetection: ChangeDetectionStrategy.OnPush, template: `
|
|
277
|
+
<div [formGroup]="form()">
|
|
278
|
+
<p-iftalabel>
|
|
279
|
+
<textarea
|
|
280
|
+
pTextarea
|
|
281
|
+
[id]="field().key"
|
|
282
|
+
[formControlName]="field().key"
|
|
283
|
+
[placeholder]="field().placeholder || ''"
|
|
284
|
+
[rows]="field().textareaRows ?? 1"
|
|
285
|
+
[cols]="field().textareaCols"
|
|
286
|
+
[autoResize]="field().textareaAutoResize ?? false"
|
|
287
|
+
[disabled]="field().disabled ?? false"
|
|
288
|
+
></textarea>
|
|
289
|
+
<label [for]="field().key">{{ field().label }}</label>
|
|
290
|
+
</p-iftalabel>
|
|
291
|
+
</div>
|
|
292
|
+
`, styles: [":host{display:block;width:100%}p-iftalabel{display:block;width:100%}textarea{width:100%}\n"] }]
|
|
293
|
+
}], propDecorators: { form: [{ type: i0.Input, args: [{ isSignal: true, alias: "form", required: true }] }], field: [{ type: i0.Input, args: [{ isSignal: true, alias: "field", required: true }] }] } });
|
|
294
|
+
|
|
295
|
+
class ToggleSwitchFieldComponent {
|
|
296
|
+
form = input.required(...(ngDevMode ? [{ debugName: "form" }] : []));
|
|
297
|
+
field = input.required(...(ngDevMode ? [{ debugName: "field" }] : []));
|
|
298
|
+
isInvalid = computed(() => {
|
|
299
|
+
const control = this.form().get(this.field().key);
|
|
300
|
+
return control ? control.invalid && (control.touched || control.dirty) : false;
|
|
301
|
+
}, ...(ngDevMode ? [{ debugName: "isInvalid" }] : []));
|
|
302
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.7", ngImport: i0, type: ToggleSwitchFieldComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
303
|
+
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: `
|
|
304
|
+
<div [formGroup]="form()" class="toggleswitch-field">
|
|
305
|
+
<p-toggleswitch
|
|
306
|
+
[formControlName]="field().key"
|
|
307
|
+
[inputId]="field().key"
|
|
308
|
+
[invalid]="isInvalid()"
|
|
309
|
+
[disabled]="field().disabled ?? false"
|
|
310
|
+
[trueValue]="field().toggleTrueValue ?? true"
|
|
311
|
+
[falseValue]="field().toggleFalseValue ?? false" />
|
|
312
|
+
<label [for]="field().key" class="toggleswitch-label">{{ field().label }}</label>
|
|
313
|
+
</div>
|
|
314
|
+
`, 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 });
|
|
315
|
+
}
|
|
316
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.7", ngImport: i0, type: ToggleSwitchFieldComponent, decorators: [{
|
|
317
|
+
type: Component,
|
|
318
|
+
args: [{ selector: 'vp-toggleswitch-field', standalone: true, imports: [ReactiveFormsModule, ToggleSwitchModule], changeDetection: ChangeDetectionStrategy.OnPush, template: `
|
|
319
|
+
<div [formGroup]="form()" class="toggleswitch-field">
|
|
320
|
+
<p-toggleswitch
|
|
321
|
+
[formControlName]="field().key"
|
|
322
|
+
[inputId]="field().key"
|
|
323
|
+
[invalid]="isInvalid()"
|
|
324
|
+
[disabled]="field().disabled ?? false"
|
|
325
|
+
[trueValue]="field().toggleTrueValue ?? true"
|
|
326
|
+
[falseValue]="field().toggleFalseValue ?? false" />
|
|
327
|
+
<label [for]="field().key" class="toggleswitch-label">{{ field().label }}</label>
|
|
328
|
+
</div>
|
|
329
|
+
`, 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"] }]
|
|
330
|
+
}], propDecorators: { form: [{ type: i0.Input, args: [{ isSignal: true, alias: "form", required: true }] }], field: [{ type: i0.Input, args: [{ isSignal: true, alias: "field", required: true }] }] } });
|
|
331
|
+
|
|
332
|
+
/**
|
|
333
|
+
* Serviço para registro de campos customizados.
|
|
334
|
+
* Permite adicionar novos tipos de campos dinamicamente.
|
|
335
|
+
*/
|
|
336
|
+
class FieldRegistryService {
|
|
337
|
+
registry = signal(new Map(), ...(ngDevMode ? [{ debugName: "registry" }] : []));
|
|
338
|
+
/**
|
|
339
|
+
* Registra um novo tipo de campo.
|
|
340
|
+
* @param type Tipo do campo (ex: 'custom', 'file', etc.)
|
|
341
|
+
* @param component Componente Angular que renderiza o campo
|
|
342
|
+
*/
|
|
343
|
+
registerField(type, component) {
|
|
344
|
+
this.registry.update((map) => new Map(map).set(type, component));
|
|
345
|
+
}
|
|
346
|
+
/**
|
|
347
|
+
* Obtém o componente registrado para um tipo de campo.
|
|
348
|
+
* @param type Tipo do campo
|
|
349
|
+
* @returns Componente Angular ou undefined se não encontrado
|
|
350
|
+
*/
|
|
351
|
+
getField(type) {
|
|
352
|
+
return this.registry().get(type);
|
|
353
|
+
}
|
|
354
|
+
/**
|
|
355
|
+
* Remove um tipo de campo do registro.
|
|
356
|
+
* @param type Tipo do campo a ser removido
|
|
357
|
+
*/
|
|
358
|
+
unregisterField(type) {
|
|
359
|
+
this.registry.update((map) => {
|
|
360
|
+
const newMap = new Map(map);
|
|
361
|
+
newMap.delete(type);
|
|
362
|
+
return newMap;
|
|
363
|
+
});
|
|
364
|
+
}
|
|
365
|
+
/**
|
|
366
|
+
* Limpa todos os campos registrados.
|
|
367
|
+
*/
|
|
368
|
+
clear() {
|
|
369
|
+
this.registry.set(new Map());
|
|
370
|
+
}
|
|
371
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.7", ngImport: i0, type: FieldRegistryService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
372
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.0.7", ngImport: i0, type: FieldRegistryService, providedIn: 'root' });
|
|
373
|
+
}
|
|
374
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.7", ngImport: i0, type: FieldRegistryService, decorators: [{
|
|
375
|
+
type: Injectable,
|
|
376
|
+
args: [{ providedIn: 'root' }]
|
|
377
|
+
}] });
|
|
378
|
+
|
|
379
|
+
class DynamicFormComponent {
|
|
380
|
+
destroyRef = inject(DestroyRef);
|
|
381
|
+
fieldRegistry = inject(FieldRegistryService);
|
|
382
|
+
config = input.required(...(ngDevMode ? [{ debugName: "config" }] : []));
|
|
383
|
+
formReady = output();
|
|
384
|
+
form = new FormGroup({});
|
|
385
|
+
fieldComponents = {
|
|
386
|
+
text: InputTextFieldComponent,
|
|
387
|
+
email: InputTextFieldComponent,
|
|
388
|
+
password: PasswordFieldComponent,
|
|
389
|
+
number: NumberInputFieldComponent,
|
|
390
|
+
select: SelectFieldComponent,
|
|
391
|
+
datepicker: DatePickerFieldComponent,
|
|
392
|
+
textarea: TextareaFieldComponent,
|
|
393
|
+
toggleswitch: ToggleSwitchFieldComponent,
|
|
394
|
+
};
|
|
395
|
+
ngOnInit() {
|
|
396
|
+
const configValue = this.config();
|
|
397
|
+
if (configValue && configValue.length > 0) {
|
|
398
|
+
this.buildForm(configValue);
|
|
399
|
+
this.setupFieldDependencies(configValue);
|
|
400
|
+
this.formReady.emit(this.form);
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
buildForm(config) {
|
|
404
|
+
config.forEach((field) => {
|
|
405
|
+
// Para toggle switch, o valor padrão é false se não especificado
|
|
406
|
+
const defaultValue = field.controlType === 'toggleswitch' ? (field.value ?? false) : (field.value ?? '');
|
|
407
|
+
// Se o campo tem enabledWhen, ele deve começar desabilitado a menos que o toggle já esteja ativo
|
|
408
|
+
const shouldBeDisabled = field.disabled ?? (field.enabledWhen ? !this.getToggleValue(field.enabledWhen, config) : false);
|
|
409
|
+
const control = shouldBeDisabled
|
|
410
|
+
? new FormControl({ value: defaultValue, disabled: true }, {
|
|
411
|
+
validators: field.validators ?? [],
|
|
412
|
+
})
|
|
413
|
+
: new FormControl(defaultValue, {
|
|
414
|
+
validators: field.validators ?? [],
|
|
415
|
+
});
|
|
416
|
+
this.form.addControl(field.key, control);
|
|
417
|
+
});
|
|
418
|
+
}
|
|
419
|
+
setupFieldDependencies(config) {
|
|
420
|
+
config.forEach((field) => {
|
|
421
|
+
if (!field.enabledWhen) {
|
|
422
|
+
return;
|
|
423
|
+
}
|
|
424
|
+
const toggleField = config.find((f) => f.key === field.enabledWhen);
|
|
425
|
+
if (!toggleField) {
|
|
426
|
+
console.warn(`DynamicFormComponent: Campo '${field.key}' referencia '${field.enabledWhen}' em enabledWhen, mas este campo não existe no formulário.`);
|
|
427
|
+
return;
|
|
428
|
+
}
|
|
429
|
+
if (toggleField.controlType !== 'toggleswitch') {
|
|
430
|
+
console.warn(`DynamicFormComponent: Campo '${field.key}' referencia '${field.enabledWhen}' em enabledWhen, mas este campo não é do tipo 'toggleswitch'.`);
|
|
431
|
+
return;
|
|
432
|
+
}
|
|
433
|
+
const toggleControl = this.form.get(field.enabledWhen);
|
|
434
|
+
const dependentControl = this.form.get(field.key);
|
|
435
|
+
if (!toggleControl || !dependentControl) {
|
|
436
|
+
console.warn(`DynamicFormComponent: Não foi possível encontrar os controles para configurar a dependência entre '${field.enabledWhen}' e '${field.key}'.`);
|
|
437
|
+
return;
|
|
438
|
+
}
|
|
439
|
+
// Configura a subscription para reagir às mudanças do toggle
|
|
440
|
+
toggleControl.valueChanges.pipe(takeUntilDestroyed(this.destroyRef)).subscribe((toggleValue) => {
|
|
441
|
+
const isToggleActive = toggleValue === (toggleField.toggleTrueValue ?? true);
|
|
442
|
+
if (isToggleActive) {
|
|
443
|
+
dependentControl.enable();
|
|
444
|
+
}
|
|
445
|
+
else {
|
|
446
|
+
// Limpa o valor do campo antes de desabilitá-lo
|
|
447
|
+
const resetValue = this.getResetValueForFieldType(field.controlType);
|
|
448
|
+
dependentControl.setValue(resetValue, { emitEvent: false });
|
|
449
|
+
dependentControl.disable();
|
|
450
|
+
}
|
|
451
|
+
});
|
|
452
|
+
});
|
|
453
|
+
}
|
|
454
|
+
getToggleValue(toggleKey, config) {
|
|
455
|
+
const toggleField = config.find((f) => f.key === toggleKey);
|
|
456
|
+
if (!toggleField || toggleField.controlType !== 'toggleswitch') {
|
|
457
|
+
return false;
|
|
458
|
+
}
|
|
459
|
+
const toggleTrueValue = toggleField.toggleTrueValue ?? true;
|
|
460
|
+
const toggleValue = toggleField.value ?? false;
|
|
461
|
+
return toggleValue === toggleTrueValue;
|
|
462
|
+
}
|
|
463
|
+
/**
|
|
464
|
+
* Retorna o valor padrão de reset para cada tipo de campo.
|
|
465
|
+
* Usado quando um campo dependente é desabilitado e precisa ser limpo.
|
|
466
|
+
*/
|
|
467
|
+
getResetValueForFieldType(controlType) {
|
|
468
|
+
switch (controlType) {
|
|
469
|
+
case 'text':
|
|
470
|
+
case 'email':
|
|
471
|
+
case 'password':
|
|
472
|
+
case 'textarea':
|
|
473
|
+
return '';
|
|
474
|
+
case 'number':
|
|
475
|
+
return null;
|
|
476
|
+
case 'select':
|
|
477
|
+
return null;
|
|
478
|
+
case 'datepicker':
|
|
479
|
+
return null;
|
|
480
|
+
default:
|
|
481
|
+
return '';
|
|
482
|
+
}
|
|
483
|
+
}
|
|
484
|
+
/**
|
|
485
|
+
* Obtém o componente a ser renderizado para um tipo de campo.
|
|
486
|
+
* Primeiro verifica no registro customizado, depois nos componentes padrão.
|
|
487
|
+
*/
|
|
488
|
+
getFieldComponent(controlType) {
|
|
489
|
+
// Verifica primeiro no registro customizado
|
|
490
|
+
const customComponent = this.fieldRegistry.getField(controlType);
|
|
491
|
+
if (customComponent) {
|
|
492
|
+
return customComponent;
|
|
493
|
+
}
|
|
494
|
+
// Fallback para componentes padrão
|
|
495
|
+
return this.fieldComponents[controlType] || null;
|
|
496
|
+
}
|
|
497
|
+
getControl(key) {
|
|
498
|
+
const control = this.form.get(key);
|
|
499
|
+
if (!control) {
|
|
500
|
+
console.warn(`DynamicFormComponent: Controle não encontrado para a chave: ${key}`);
|
|
501
|
+
}
|
|
502
|
+
return control;
|
|
503
|
+
}
|
|
504
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.7", ngImport: i0, type: DynamicFormComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
505
|
+
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 });
|
|
506
|
+
}
|
|
507
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.7", ngImport: i0, type: DynamicFormComponent, decorators: [{
|
|
508
|
+
type: Component,
|
|
509
|
+
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"] }]
|
|
510
|
+
}], propDecorators: { config: [{ type: i0.Input, args: [{ isSignal: true, alias: "config", required: true }] }], formReady: [{ type: i0.Output, args: ["formReady"] }] } });
|
|
511
|
+
|
|
512
|
+
const PRIMENG_PTBR = {
|
|
513
|
+
// Filtros
|
|
514
|
+
startsWith: 'Começa com',
|
|
515
|
+
contains: 'Contém',
|
|
516
|
+
notContains: 'Não contém',
|
|
517
|
+
endsWith: 'Termina com',
|
|
518
|
+
equals: 'Igual',
|
|
519
|
+
notEquals: 'Diferente',
|
|
520
|
+
noFilter: 'Sem filtro',
|
|
521
|
+
lt: 'Menor que',
|
|
522
|
+
lte: 'Menor ou igual a',
|
|
523
|
+
gt: 'Maior que',
|
|
524
|
+
gte: 'Maior ou igual a',
|
|
525
|
+
is: 'É',
|
|
526
|
+
isNot: 'Não é',
|
|
527
|
+
before: 'Antes',
|
|
528
|
+
after: 'Depois',
|
|
529
|
+
dateIs: 'Data é',
|
|
530
|
+
dateIsNot: 'Data não é',
|
|
531
|
+
dateBefore: 'Data antes',
|
|
532
|
+
dateAfter: 'Data depois',
|
|
533
|
+
// Regras
|
|
534
|
+
clear: 'Limpar',
|
|
535
|
+
apply: 'Aplicar',
|
|
536
|
+
matchAll: 'Corresponder a todos',
|
|
537
|
+
matchAny: 'Corresponder a qualquer',
|
|
538
|
+
addRule: 'Adicionar regra',
|
|
539
|
+
removeRule: 'Remover regra',
|
|
540
|
+
// Ações
|
|
541
|
+
accept: 'Sim',
|
|
542
|
+
reject: 'Não',
|
|
543
|
+
choose: 'Escolher',
|
|
544
|
+
upload: 'Enviar',
|
|
545
|
+
cancel: 'Cancelar',
|
|
546
|
+
completed: 'Concluído',
|
|
547
|
+
pending: 'Pendente',
|
|
548
|
+
// Arquivos
|
|
549
|
+
fileSizeTypes: ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'],
|
|
550
|
+
emptyMessage: 'Nenhum registro encontrado',
|
|
551
|
+
emptyFilterMessage: 'Nenhum resultado encontrado',
|
|
552
|
+
fileChosenMessage: '{0} arquivo(s) selecionado(s)',
|
|
553
|
+
noFileChosenMessage: 'Nenhum arquivo selecionado',
|
|
554
|
+
// Datas
|
|
555
|
+
dayNames: ['Domingo', 'Segunda-feira', 'Terça-feira', 'Quarta-feira', 'Quinta-feira', 'Sexta-feira', 'Sábado'],
|
|
556
|
+
dayNamesShort: ['Dom', 'Seg', 'Ter', 'Qua', 'Qui', 'Sex', 'Sáb'],
|
|
557
|
+
dayNamesMin: ['D', 'S', 'T', 'Q', 'Q', 'S', 'S'],
|
|
558
|
+
monthNames: ['Janeiro', 'Fevereiro', 'Março', 'Abril', 'Maio', 'Junho', 'Julho', 'Agosto', 'Setembro', 'Outubro', 'Novembro', 'Dezembro'],
|
|
559
|
+
monthNamesShort: ['Jan', 'Fev', 'Mar', 'Abr', 'Mai', 'Jun', 'Jul', 'Ago', 'Set', 'Out', 'Nov', 'Dez'],
|
|
560
|
+
dateFormat: 'dd/mm/yy',
|
|
561
|
+
firstDayOfWeek: 0,
|
|
562
|
+
today: 'Hoje',
|
|
563
|
+
weekHeader: 'Sem',
|
|
564
|
+
// Password
|
|
565
|
+
weak: 'Fraca',
|
|
566
|
+
medium: 'Média',
|
|
567
|
+
strong: 'Forte',
|
|
568
|
+
passwordPrompt: 'Digite uma senha',
|
|
569
|
+
// Date navigation
|
|
570
|
+
chooseYear: 'Escolher ano',
|
|
571
|
+
chooseMonth: 'Escolher mês',
|
|
572
|
+
chooseDate: 'Escolher data',
|
|
573
|
+
prevDecade: 'Década anterior',
|
|
574
|
+
nextDecade: 'Próxima década',
|
|
575
|
+
prevYear: 'Ano anterior',
|
|
576
|
+
nextYear: 'Próximo ano',
|
|
577
|
+
prevMonth: 'Mês anterior',
|
|
578
|
+
nextMonth: 'Próximo mês',
|
|
579
|
+
prevHour: 'Hora anterior',
|
|
580
|
+
nextHour: 'Próxima hora',
|
|
581
|
+
prevMinute: 'Minuto anterior',
|
|
582
|
+
nextMinute: 'Próximo minuto',
|
|
583
|
+
prevSecond: 'Segundo anterior',
|
|
584
|
+
nextSecond: 'Próximo segundo',
|
|
585
|
+
am: 'AM',
|
|
586
|
+
pm: 'PM',
|
|
587
|
+
// Busca / seleção
|
|
588
|
+
searchMessage: 'Digite para pesquisar',
|
|
589
|
+
selectionMessage: '{0} item(ns) selecionado(s)',
|
|
590
|
+
emptySelectionMessage: 'Nenhum item selecionado',
|
|
591
|
+
emptySearchMessage: 'Nenhum resultado encontrado',
|
|
592
|
+
// ARIA (acessibilidade)
|
|
593
|
+
aria: {
|
|
594
|
+
trueLabel: 'Verdadeiro',
|
|
595
|
+
falseLabel: 'Falso',
|
|
596
|
+
nullLabel: 'Não selecionado',
|
|
597
|
+
star: '1 estrela',
|
|
598
|
+
stars: '{star} estrelas',
|
|
599
|
+
selectAll: 'Selecionar todos',
|
|
600
|
+
unselectAll: 'Desmarcar todos',
|
|
601
|
+
close: 'Fechar',
|
|
602
|
+
previous: 'Anterior',
|
|
603
|
+
next: 'Próximo',
|
|
604
|
+
navigation: 'Navegação',
|
|
605
|
+
scrollTop: 'Rolar para o topo',
|
|
606
|
+
moveTop: 'Mover para o topo',
|
|
607
|
+
moveUp: 'Mover para cima',
|
|
608
|
+
moveDown: 'Mover para baixo',
|
|
609
|
+
moveBottom: 'Mover para o final',
|
|
610
|
+
moveToTarget: 'Mover para o destino',
|
|
611
|
+
moveToSource: 'Mover para a origem',
|
|
612
|
+
moveAllToTarget: 'Mover todos para o destino',
|
|
613
|
+
moveAllToSource: 'Mover todos para a origem',
|
|
614
|
+
pageLabel: 'Página {page}',
|
|
615
|
+
firstPageLabel: 'Primeira página',
|
|
616
|
+
lastPageLabel: 'Última página',
|
|
617
|
+
nextPageLabel: 'Próxima página',
|
|
618
|
+
prevPageLabel: 'Página anterior',
|
|
619
|
+
rowsPerPageLabel: 'Itens por página',
|
|
620
|
+
previousPageLabel: 'Página anterior',
|
|
621
|
+
jumpToPageDropdownLabel: 'Pular para página',
|
|
622
|
+
jumpToPageInputLabel: 'Ir para página',
|
|
623
|
+
selectRow: 'Selecionar linha',
|
|
624
|
+
unselectRow: 'Desmarcar linha',
|
|
625
|
+
expandRow: 'Expandir linha',
|
|
626
|
+
collapseRow: 'Recolher linha',
|
|
627
|
+
showFilterMenu: 'Mostrar menu de filtro',
|
|
628
|
+
hideFilterMenu: 'Ocultar menu de filtro',
|
|
629
|
+
filterOperator: 'Operador de filtro',
|
|
630
|
+
filterConstraint: 'Restrição de filtro',
|
|
631
|
+
editRow: 'Editar linha',
|
|
632
|
+
saveEdit: 'Salvar edição',
|
|
633
|
+
cancelEdit: 'Cancelar edição',
|
|
634
|
+
listView: 'Visualização em lista',
|
|
635
|
+
gridView: 'Visualização em grade',
|
|
636
|
+
slide: 'Slide',
|
|
637
|
+
slideNumber: 'Slide {slideNumber}',
|
|
638
|
+
zoomImage: 'Ampliar imagem',
|
|
639
|
+
zoomIn: 'Aumentar zoom',
|
|
640
|
+
zoomOut: 'Reduzir zoom',
|
|
641
|
+
rotateRight: 'Girar à direita',
|
|
642
|
+
rotateLeft: 'Girar à esquerda',
|
|
643
|
+
listLabel: 'Lista',
|
|
644
|
+
selectColor: 'Selecionar cor',
|
|
645
|
+
removeLabel: 'Remover',
|
|
646
|
+
browseFiles: 'Procurar arquivos',
|
|
647
|
+
maximizeLabel: 'Maximizar',
|
|
648
|
+
minimizeLabel: 'Minimizar',
|
|
649
|
+
},
|
|
650
|
+
};
|
|
651
|
+
|
|
652
|
+
/**
|
|
653
|
+
* Provider para configurar mensagens de erro customizadas.
|
|
654
|
+
* @param messages Mensagens de erro customizadas
|
|
655
|
+
* @returns Provider configurado
|
|
656
|
+
*/
|
|
657
|
+
function provideDynamicFormConfig(messages) {
|
|
658
|
+
const providers = [];
|
|
659
|
+
if (messages) {
|
|
660
|
+
providers.push({
|
|
661
|
+
provide: DYNAMIC_FORM_ERROR_MESSAGES,
|
|
662
|
+
useValue: messages,
|
|
663
|
+
});
|
|
664
|
+
}
|
|
665
|
+
return providers;
|
|
666
|
+
}
|
|
667
|
+
|
|
668
|
+
/*
|
|
669
|
+
* Public API Surface of @vipsolucoes/dynamic-form
|
|
670
|
+
*/
|
|
671
|
+
// Componentes
|
|
672
|
+
|
|
673
|
+
/**
|
|
674
|
+
* Generated bundle index. Do not edit.
|
|
675
|
+
*/
|
|
676
|
+
|
|
677
|
+
export { DYNAMIC_FORM_ERROR_MESSAGES, DatePickerFieldComponent, DynamicFormComponent, DynamicFormErrorComponent, FieldRegistryService, InputTextFieldComponent, NumberInputFieldComponent, PRIMENG_PTBR, PasswordFieldComponent, SelectFieldComponent, TextareaFieldComponent, ToggleSwitchFieldComponent, provideDynamicFormConfig };
|
|
678
|
+
//# sourceMappingURL=vipsolucoes-dynamic-form.mjs.map
|