@masterkeymaterial/ui 0.0.1 → 0.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.
- package/README.md +9 -59
- package/ng-package.json +10 -0
- package/package.json +5 -14
- package/src/elements/ui-button/ui-button.css +229 -0
- package/src/elements/ui-button/ui-button.html +12 -0
- package/src/elements/ui-button/ui-button.ts +133 -0
- package/src/elements/ui-check-box/ui-check-box.css +66 -0
- package/src/elements/ui-check-box/ui-check-box.html +5 -0
- package/src/elements/ui-check-box/ui-check-box.ts +65 -0
- package/src/elements/ui-chip/ui-chip.css +24 -0
- package/src/elements/ui-chip/ui-chip.html +3 -0
- package/src/elements/ui-chip/ui-chip.ts +25 -0
- package/src/elements/ui-drop-zone/ui-drop-zone.css +91 -0
- package/src/elements/ui-drop-zone/ui-drop-zone.html +8 -0
- package/src/elements/ui-drop-zone/ui-drop-zone.ts +153 -0
- package/src/elements/ui-file-list/ui-file-list.css +43 -0
- package/src/elements/ui-file-list/ui-file-list.html +17 -0
- package/src/elements/ui-file-list/ui-file-list.ts +22 -0
- package/src/elements/ui-list-errors/ui-list-errors.css +30 -0
- package/src/elements/ui-list-errors/ui-list-errors.html +10 -0
- package/src/elements/ui-list-errors/ui-list-errors.ts +14 -0
- package/src/elements/ui-loading/ui-loading.css +13 -0
- package/src/elements/ui-loading/ui-loading.html +1 -0
- package/src/elements/ui-loading/ui-loading.ts +10 -0
- package/src/elements/ui-menu/ui-menu.css +69 -0
- package/src/elements/ui-menu/ui-menu.html +20 -0
- package/src/elements/ui-menu/ui-menu.ts +267 -0
- package/src/elements/ui-procurar/ui-procurar.css +48 -0
- package/src/elements/ui-procurar/ui-procurar.html +14 -0
- package/src/elements/ui-procurar/ui-procurar.ts +82 -0
- package/src/elements/ui-progress/ui-progress.css +0 -0
- package/src/elements/ui-progress/ui-progress.html +1 -0
- package/src/elements/ui-progress/ui-progress.ts +15 -0
- package/src/elements/ui-select/ui-select.css +211 -0
- package/src/elements/ui-select/ui-select.html +46 -0
- package/src/elements/ui-select/ui-select.ts +482 -0
- package/src/elements/ui-slide/ui-slide.css +75 -0
- package/src/elements/ui-slide/ui-slide.html +7 -0
- package/src/elements/ui-slide/ui-slide.ts +61 -0
- package/src/fields/Base/BaseFieldsForm/BaseFieldsForm.component.ts +113 -0
- package/src/fields/Base/BaseFieldsValues/BaseFieldsValues.ts +112 -0
- package/src/fields/Formulario/Formulario.ts +1056 -0
- package/src/fields/Formulario/form-action/form-action.css +98 -0
- package/src/fields/Formulario/form-action/form-action.html +75 -0
- package/src/fields/Formulario/form-action/form-action.ts +187 -0
- package/src/fields/Formulario/form-controls/form-controls.css +108 -0
- package/src/fields/Formulario/form-controls/form-controls.html +105 -0
- package/src/fields/Formulario/form-controls/form-controls.ts +122 -0
- package/src/fields/Formulario/form-fase/form-fase.css +84 -0
- package/src/fields/Formulario/form-fase/form-fase.html +24 -0
- package/src/fields/Formulario/form-fase/form-fase.ts +157 -0
- package/src/fields/Formulario/form-filter/form-filter.css +50 -0
- package/src/fields/Formulario/form-filter/form-filter.html +25 -0
- package/src/fields/Formulario/form-filter/form-filter.ts +53 -0
- package/src/fields/Formulario/form-no-action/form-no-action.css +32 -0
- package/src/fields/Formulario/form-no-action/form-no-action.html +12 -0
- package/src/fields/Formulario/form-no-action/form-no-action.ts +21 -0
- package/src/fields/Formulario/formated-values/formated-values.css +104 -0
- package/src/fields/Formulario/formated-values/formated-values.html +15 -0
- package/src/fields/Formulario/formated-values/formated-values.ts +186 -0
- package/src/fields/Formulario/single-values/single-values.css +88 -0
- package/src/fields/Formulario/single-values/single-values.html +11 -0
- package/src/fields/Formulario/single-values/single-values.ts +65 -0
- package/src/fields/autocomplete/autocomplete.css +94 -0
- package/src/fields/autocomplete/autocomplete.html +38 -0
- package/src/fields/autocomplete/autocomplete.ts +294 -0
- package/src/fields/button/button.css +7 -0
- package/src/fields/button/button.html +19 -0
- package/src/fields/button/button.ts +38 -0
- package/src/fields/checkbox/checkbox.css +27 -0
- package/src/fields/checkbox/checkbox.html +20 -0
- package/src/fields/checkbox/checkbox.ts +44 -0
- package/src/fields/color/CirculoColorido/circulocolorido.css +50 -0
- package/src/fields/color/CirculoColorido/circulocolorido.html +8 -0
- package/src/fields/color/CirculoColorido/circulocolorido.ts +24 -0
- package/src/fields/color/color.css +15 -0
- package/src/fields/color/color.html +24 -0
- package/src/fields/color/color.ts +47 -0
- package/src/fields/date/date.html +19 -0
- package/src/fields/date/date.ts +29 -0
- package/src/fields/datetime/datetime.html +19 -0
- package/src/fields/datetime/datetime.ts +29 -0
- package/src/fields/display/display.css +7 -0
- package/src/fields/display/display.html +20 -0
- package/src/fields/display/display.ts +43 -0
- package/src/fields/editor/editor.css +51 -0
- package/src/fields/editor/editor.html +37 -0
- package/src/fields/editor/editor.ts +218 -0
- package/src/fields/email/email.html +19 -0
- package/src/fields/email/email.ts +29 -0
- package/src/fields/fields.css +180 -0
- package/src/fields/generic/generic.html +3 -0
- package/src/fields/generic/generic.ts +91 -0
- package/src/fields/hidden/hidden.html +3 -0
- package/src/fields/hidden/hidden.ts +20 -0
- package/src/fields/icon/icon.css +19 -0
- package/src/fields/icon/icon.html +27 -0
- package/src/fields/icon/icon.ts +31 -0
- package/src/fields/multifactor/multifactor.css +21 -0
- package/src/fields/multifactor/multifactor.html +39 -0
- package/src/fields/multifactor/multifactor.ts +106 -0
- package/src/fields/multikv/multikv.css +43 -0
- package/src/fields/multikv/multikv.html +47 -0
- package/src/fields/multikv/multikv.ts +88 -0
- package/src/fields/multitext/multitext.css +36 -0
- package/src/fields/multitext/multitext.html +38 -0
- package/src/fields/multitext/multitext.ts +75 -0
- package/src/fields/number/number.html +20 -0
- package/src/fields/number/number.ts +35 -0
- package/src/fields/password/password.html +23 -0
- package/src/fields/password/password.ts +37 -0
- package/src/fields/search/search.css +0 -0
- package/src/fields/search/search.html +19 -0
- package/src/fields/search/search.ts +54 -0
- package/src/fields/select/select.css +15 -0
- package/src/fields/select/select.html +18 -0
- package/src/fields/select/select.ts +52 -0
- package/src/fields/slide/slide.css +27 -0
- package/src/fields/slide/slide.html +20 -0
- package/src/fields/slide/slide.ts +45 -0
- package/src/fields/text/text.html +19 -0
- package/src/fields/text/text.ts +30 -0
- package/src/fields/textarea/textarea.css +4 -0
- package/src/fields/textarea/textarea.html +20 -0
- package/src/fields/textarea/textarea.ts +31 -0
- package/src/fields/time/time.html +19 -0
- package/src/fields/time/time.ts +29 -0
- package/src/fields/upload/upload.css +24 -0
- package/src/fields/upload/upload.html +41 -0
- package/src/fields/upload/upload.ts +137 -0
- package/src/interfaces/interfaces.ts +61 -0
- package/src/public-api.ts +38 -0
- package/src/util/ClassOf.pipe.ts +11 -0
- package/src/util/JsonColorido.pipe.ts +11 -0
- package/src/util/util.ts +2151 -0
- package/tsconfig.lib.json +16 -0
- package/tsconfig.lib.prod.json +9 -0
- package/tsconfig.spec.json +13 -0
- package/fesm2022/masterkeymaterial-ui.mjs +0 -6457
- package/fesm2022/masterkeymaterial-ui.mjs.map +0 -1
- package/types/masterkeymaterial-ui.d.ts +0 -928
|
@@ -0,0 +1,1056 @@
|
|
|
1
|
+
import { computed, signal, Type, WritableSignal } from "@angular/core";
|
|
2
|
+
import { IKV, IKV_ext, ITipoBotao, ITiposTema } from '../../interfaces/interfaces';
|
|
3
|
+
import { LibUtil, LOG } from "../../util/util";
|
|
4
|
+
|
|
5
|
+
export class Formulario {
|
|
6
|
+
|
|
7
|
+
campos = signal<IFields<any>>({});
|
|
8
|
+
listaCampos = computed<IFieldComponent<any>[]>(() => Object.values(this.campos()));
|
|
9
|
+
listaErrors = computed<string[]>(() => {
|
|
10
|
+
let errors: string[] = [];
|
|
11
|
+
for (const key of Object.keys(this.campos())) {
|
|
12
|
+
const campoErros = this.campos()?.[key]?.errors;
|
|
13
|
+
if (campoErros && campoErros.length > 0) {
|
|
14
|
+
errors = [...errors, ...campoErros.map(e => `${String(key)}: ${e}`)];
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
return errors;
|
|
18
|
+
});
|
|
19
|
+
values = signal<any>({});
|
|
20
|
+
registredFields = signal<{ [key in keyof IFields<any>]: any }>({});
|
|
21
|
+
|
|
22
|
+
showTouched = signal<boolean>(false);
|
|
23
|
+
isEnviado: boolean = false;
|
|
24
|
+
isEnviando: boolean = false;
|
|
25
|
+
instance: any = null;
|
|
26
|
+
|
|
27
|
+
valido = computed(() => {
|
|
28
|
+
for (const key of Object.keys(this.campos())) {
|
|
29
|
+
const campo = this.campos()[key];
|
|
30
|
+
const errors = campo.errors;
|
|
31
|
+
if (errors && errors.length > 0) {
|
|
32
|
+
return false;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
return true;
|
|
36
|
+
});
|
|
37
|
+
algumTocado = computed(() => {
|
|
38
|
+
return this.listaCampos().some(campo => campo.touched);
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
constructor(campos: IFields<any>, startValues: any = {}, instance: any = null) {
|
|
42
|
+
this.instance = instance;
|
|
43
|
+
let values: any = this._startValues(campos, startValues);
|
|
44
|
+
let camposStarted: IFields<any> = {};
|
|
45
|
+
for (const key of Object.keys(campos)) {
|
|
46
|
+
camposStarted[key] = {
|
|
47
|
+
...campos[key],
|
|
48
|
+
touched: false,
|
|
49
|
+
invalid: false,
|
|
50
|
+
errors: [], // [Valide.msg.naoValidado]
|
|
51
|
+
...LibUtil.formConfigs,
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
this.campos.set(camposStarted);
|
|
55
|
+
this.values.set(values);
|
|
56
|
+
this.obterOpcoes();
|
|
57
|
+
return this;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
updateValues(newValues: any) {
|
|
61
|
+
if (LibUtil.classof(newValues) !== 'object') {
|
|
62
|
+
LOG(1, "❌ Formulario.updateValues deve receber um objeto.");
|
|
63
|
+
}
|
|
64
|
+
this.values.update(v => {
|
|
65
|
+
return { ...v, ...newValues }
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
removeValue(prop: keyof IFields<any>) {
|
|
70
|
+
this.values.update(v => {
|
|
71
|
+
if (v.hasOwnProperty(prop)) {
|
|
72
|
+
delete v[prop];
|
|
73
|
+
} else {
|
|
74
|
+
LOG(1, `❌ Formulario.removeValue: Propriedade '${String(prop)}' não existe nos valores.`);
|
|
75
|
+
}
|
|
76
|
+
return { ...v };
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
updateCampo(prop: keyof IFields<any>, newCampoData: Partial<IFieldComponent<any>>) {
|
|
81
|
+
if (newCampoData.hasOwnProperty('errors')) {
|
|
82
|
+
newCampoData.invalid = (newCampoData.errors && newCampoData.errors.length > 0);
|
|
83
|
+
}
|
|
84
|
+
this.campos.update(c => {
|
|
85
|
+
if (c[prop]) {
|
|
86
|
+
c[prop] = { ...c[prop], ...newCampoData };
|
|
87
|
+
} else {
|
|
88
|
+
LOG(1, `❌ Formulario.updateCampo: Campo '${String(prop)}' não existe.`);
|
|
89
|
+
}
|
|
90
|
+
return { ...c };
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
setAllCamposPartial(newCampoData: Partial<IFieldComponent<any>>) {
|
|
95
|
+
if (newCampoData.hasOwnProperty('errors')) {
|
|
96
|
+
newCampoData.invalid = (newCampoData.errors && newCampoData.errors.length > 0);
|
|
97
|
+
}
|
|
98
|
+
this.campos.update(c => {
|
|
99
|
+
for (const key of Object.keys(c)) {
|
|
100
|
+
c[key] = { ...c[key], ...newCampoData };
|
|
101
|
+
}
|
|
102
|
+
return { ...c };
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
setAllValuesTo(value: any) {
|
|
107
|
+
this.values.update(v => {
|
|
108
|
+
for (const key of Object.keys(v)) {
|
|
109
|
+
v[key] = value;
|
|
110
|
+
}
|
|
111
|
+
return { ...v };
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
resetToStartValues() {
|
|
116
|
+
const campos = this.campos();
|
|
117
|
+
const startValues = this._startValues(campos);
|
|
118
|
+
this.values.set(startValues);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
private _startValues(campos: IFields<any>, startValues: any = {}) {
|
|
122
|
+
let values: any = {};
|
|
123
|
+
for (const key of Object.keys(campos)) {
|
|
124
|
+
values[key] = campos[key].value ?? '';
|
|
125
|
+
}
|
|
126
|
+
values = { ...values, ...startValues };
|
|
127
|
+
return values;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
setDisabledAll(disabled: boolean) {
|
|
131
|
+
this.setAllCamposPartial({ disabled });
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
setTouchedAll(touched: boolean) {
|
|
135
|
+
this.setAllCamposPartial({ touched });
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
async validar(): Promise<any> {
|
|
139
|
+
let camposComErros: string[] = [];
|
|
140
|
+
let camposPendentes: string[] = [];
|
|
141
|
+
|
|
142
|
+
// Executa validações diretamente nos campos registrados
|
|
143
|
+
for (const key of Object.keys(this.registredFields())) {
|
|
144
|
+
const campoComponent = this.registredFields()[key];
|
|
145
|
+
if (campoComponent && typeof campoComponent.executarValidacoes === 'function') {
|
|
146
|
+
try {
|
|
147
|
+
await campoComponent.executarValidacoes();
|
|
148
|
+
} catch (error) {
|
|
149
|
+
LOG(1, `❌ Erro ao validar o campo '${key}':`, error);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// Verifica cada campo para erros e pendências
|
|
155
|
+
for (const key of Object.keys(this.campos())) {
|
|
156
|
+
const campo = this.campos()[key];
|
|
157
|
+
if (campo.errors && campo.errors.length > 0) {
|
|
158
|
+
LOG(1, `❌ Erro de validação no campo '${key}':`, campo.errors);
|
|
159
|
+
camposComErros.push(key);
|
|
160
|
+
}
|
|
161
|
+
if (campo.pending) {
|
|
162
|
+
LOG(1, `⏳ Campo '${key}' ainda está pendente.`);
|
|
163
|
+
camposPendentes.push(key);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// Se houver campos pendentes ou com erros rejeita a validação
|
|
168
|
+
if (camposPendentes.length > 0) {
|
|
169
|
+
return Promise.reject(`${camposPendentes.length} Campos pendentes: ${camposPendentes.join(', ')}`);
|
|
170
|
+
}
|
|
171
|
+
if (camposComErros.length > 0) {
|
|
172
|
+
return Promise.reject(`${camposComErros.length} Campos com erros (inválidos): ${camposComErros.join(', ')}`);
|
|
173
|
+
}
|
|
174
|
+
return this.values();
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
private async obterOpcoes() {
|
|
178
|
+
let campos = this.campos();
|
|
179
|
+
for (const key of Object.keys(campos)) {
|
|
180
|
+
let campo = campos[key];
|
|
181
|
+
// Ignora campos que não são de seleção
|
|
182
|
+
if ([IField.AutoComplete, IField.Select].indexOf(campo.tipo) === -1) continue;
|
|
183
|
+
this.updateCampo(campo.prop, { pending: false });
|
|
184
|
+
|
|
185
|
+
// Inicializa o signal de opções se não existir
|
|
186
|
+
if (campo.options === undefined) campo.options = signal<IKV[]>([]);
|
|
187
|
+
|
|
188
|
+
// Opções atuais
|
|
189
|
+
const opcoesAtuais = campo.options?.();
|
|
190
|
+
|
|
191
|
+
// Se já houver opções E não estiverem vazias, não executa o refill neste momento
|
|
192
|
+
if (opcoesAtuais && opcoesAtuais.length > 0) continue;
|
|
193
|
+
|
|
194
|
+
// Um refill inicial será executado se definido
|
|
195
|
+
if (campo.refill) {
|
|
196
|
+
LOG(4, `🔄 Refill em '${key}'. Opções iniciais:`, opcoesAtuais);
|
|
197
|
+
this.updateCampo(campo.prop, { pending: true });
|
|
198
|
+
let options: IKV[] | null = null;
|
|
199
|
+
try {
|
|
200
|
+
options = await campo.refill(this);
|
|
201
|
+
|
|
202
|
+
// await LibUtil.wait(1000);
|
|
203
|
+
if (campo.mapear) {
|
|
204
|
+
options = await campo.mapear(options);
|
|
205
|
+
}
|
|
206
|
+
// let opcoesKV: IKV[] = this.conveterEntidadesParaKV(options, campo.servico.configService.propsDisplay);
|
|
207
|
+
if (options === null || LibUtil.classof(options) !== 'array') {
|
|
208
|
+
options = [];
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
// Só atualiza as opções se houver conteúdo, pois já está iniciado o signal.
|
|
212
|
+
if (options.length > 0) {
|
|
213
|
+
// campo.options.set(options);
|
|
214
|
+
this.updateCampo(campo.prop, { options: signal(options) });
|
|
215
|
+
LOG(3, `🔄 Refill em '${key}'. recebido:`, options);
|
|
216
|
+
}
|
|
217
|
+
} catch (error) {
|
|
218
|
+
LOG(1, `❌ Erro ao obter opções para o campo '${key}':`, error);
|
|
219
|
+
}
|
|
220
|
+
this.updateCampo(campo.prop, { pending: false });
|
|
221
|
+
|
|
222
|
+
// Se o onMatchOptionOnInit estiver definido, executa o onMatchOption com a opção correspondente ao valor atual do campo.
|
|
223
|
+
if (campo.onMatchOptionOnInit) {
|
|
224
|
+
const optionValue = options?.find(opt => opt.k === this.values()[campo.prop]);
|
|
225
|
+
if (campo.onMatchOption && optionValue) {
|
|
226
|
+
try {
|
|
227
|
+
campo.onMatchOption?.(this, optionValue);
|
|
228
|
+
} catch (err) {
|
|
229
|
+
LOG(1, `❌ Erro ao executar onMatchOption do campo '${key}'`, err);
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
// Ao concluir o refill executa afterRefill, se definido.
|
|
235
|
+
if (campo.afterRefill) {
|
|
236
|
+
await campo.afterRefill(this, options);
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
// Remove os valores que não estão nos campos e os tipos campos que não devem ter valor.
|
|
243
|
+
sanitizar() {
|
|
244
|
+
const campos = this.campos();
|
|
245
|
+
const valoresAtuais = this.values();
|
|
246
|
+
const novosValores: any = {};
|
|
247
|
+
const tiposSemValor = [IField.Display, IField.Button];
|
|
248
|
+
for (const key of Object.keys(campos)) {
|
|
249
|
+
if (key in valoresAtuais && tiposSemValor.indexOf(campos[key].tipo) === -1) {
|
|
250
|
+
novosValores[key] = valoresAtuais[key];
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
this.values.set(novosValores);
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
// Remove os valores que não estão nos campos ou que estão em campos desabilitados.
|
|
257
|
+
onlyAvailable() {
|
|
258
|
+
const novosValores: any = {};
|
|
259
|
+
const valoresAtuais = this.values();
|
|
260
|
+
const campos = this.campos();
|
|
261
|
+
for (const campo of Object.values(campos)) {
|
|
262
|
+
if (campo.prop in valoresAtuais && !campo.disabled) {
|
|
263
|
+
novosValores[campo.prop] = valoresAtuais[campo.prop];
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
this.values.set(novosValores);
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
save() {
|
|
270
|
+
if (this.instance && typeof this.instance.onSave === 'function') {
|
|
271
|
+
this.instance.onSave();
|
|
272
|
+
} else {
|
|
273
|
+
LOG(1, "❌ Formulario.save: instância não encontrada.");
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
|
|
280
|
+
|
|
281
|
+
/************************************************\\
|
|
282
|
+
// Modo de uso \\
|
|
283
|
+
//*************************************************/
|
|
284
|
+
|
|
285
|
+
export interface IFields<T> {
|
|
286
|
+
[key: string]: IFieldComponent<T>;
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
/************************************************\\
|
|
290
|
+
// Tipos de Campos disponíveis para uso \\
|
|
291
|
+
//*************************************************/
|
|
292
|
+
|
|
293
|
+
export enum IField {
|
|
294
|
+
AutoComplete = 'autocomplete',
|
|
295
|
+
Button = 'button',
|
|
296
|
+
Checkbox = 'checkbox',
|
|
297
|
+
Color = 'color',
|
|
298
|
+
Custom = 'custom', // <== Componentes customizados para uma determinada área.
|
|
299
|
+
Date = 'date',
|
|
300
|
+
DateTime = 'datetime',
|
|
301
|
+
Display = 'display', // Representa um campo apenas para exibição
|
|
302
|
+
Editor = 'editor', // Texto multilinha e com Editor
|
|
303
|
+
Email = 'email',
|
|
304
|
+
Hidden = 'hidden',
|
|
305
|
+
Icon = 'icon', // Combo de um texto que permite selecionar um icone instalado no sistema.
|
|
306
|
+
MultiFactor = 'multifactor', // Combo de 6 campos texto para preenchimento individual por caracter.
|
|
307
|
+
MultiKV = 'multikv', // Permite adicionar ou retirar itens em forma KV (Como usado nos seletores e no Importar)
|
|
308
|
+
MultiText = 'multitext', // Lista com: Texto em unica linha.
|
|
309
|
+
Number = 'number',
|
|
310
|
+
Password = 'password',
|
|
311
|
+
Referencia = 'referencia', // Campo que referencia um registro de outra entidade. Utilizado para exibir objetos recebidos de relacionamento.
|
|
312
|
+
Search = 'search',
|
|
313
|
+
Select = 'select',
|
|
314
|
+
Slide = 'slide',
|
|
315
|
+
Text = 'text', // Texto em unica linha.
|
|
316
|
+
Textarea = 'textarea', // Texto multilinha.
|
|
317
|
+
Time = 'time', // Campo de hora (HH:MM)
|
|
318
|
+
Upload = 'upload', // (Padrão 1 Imagem)(Padrao Accept: ".png,.svg,.jpg,.jpeg,.gif")
|
|
319
|
+
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
/************************************************\\
|
|
323
|
+
// Propriedades para Campos \\
|
|
324
|
+
//*************************************************/
|
|
325
|
+
|
|
326
|
+
export interface IFieldComponent<T> {
|
|
327
|
+
tipo: IField, // [OBRIGATORIO] Tipo do campo.
|
|
328
|
+
prop: keyof T & string, // [OBRIGATORIO] nome da propriedade a ser enviada e do controle do formulário.
|
|
329
|
+
value?: any, // Valor do campo.
|
|
330
|
+
titulo?: string, // nome do campo a ser exibido ao usuário (Display)
|
|
331
|
+
area?: string, // Posição gridArea. Doc: https://developer.mozilla.org/en-US/docs/Web/CSS/grid-area
|
|
332
|
+
icone?: string, // Ícone a ser exibido no campo.
|
|
333
|
+
placeholder?: string, // Texto exibido que não representam o valor.
|
|
334
|
+
style?: string, // Estilos CSS a serem aplicados no campo.
|
|
335
|
+
classe?: string, // Classes CSS a serem aplicadas no campo.
|
|
336
|
+
hideLabel?: boolean, // Controla se o campo deve ocultar o label (titulo).
|
|
337
|
+
filter?: boolean, // Padrão true. Indica se o campo será usado em filtros (em grids, por exemplo).
|
|
338
|
+
autofocus?: boolean, // Define se o campo deve receber foco automaticamente ao ser exibido.
|
|
339
|
+
regras?: IRegra[], // Regras de validação do campo.
|
|
340
|
+
maxl?: number, // Tamanho máximo do valor.
|
|
341
|
+
minl?: number, // Tamanho mínimo do valor.
|
|
342
|
+
errors?: (string | undefined)[], // Lista de mensagens de erro para o campo.
|
|
343
|
+
dica?: string, // Texto de ajuda para o campo.
|
|
344
|
+
onInput?: (form: Formulario) => any;// Executada a cada alteração simples no campo.
|
|
345
|
+
onChange?: (form: Formulario) => any;// Executada ao fim de uma alteração no campo.
|
|
346
|
+
|
|
347
|
+
// Indicadores
|
|
348
|
+
readonly?: boolean, // Indisponibiliza a edição.
|
|
349
|
+
need?: boolean, // Valida se o campo está preenchido.
|
|
350
|
+
touched?: boolean, // Indica se o campo foi tocado/editado.
|
|
351
|
+
disabled?: boolean, // Indisponibiliza todos os controles.
|
|
352
|
+
invalid?: boolean, // Indica se o campo está inválido.
|
|
353
|
+
empty?: boolean, // Indica se o campo está vazio.
|
|
354
|
+
pending?: boolean, // Indica que o campo está em estado de espera (loading).
|
|
355
|
+
|
|
356
|
+
// Configurações específicas por tipo de campo
|
|
357
|
+
tema?: ITiposTema, // Tema do botão (para button, etc).
|
|
358
|
+
tituloClicavel?: string, // Título do botão (para button, slide, etc).
|
|
359
|
+
textoAtivo?: string, // Texto quando ativo (para slide).
|
|
360
|
+
textoInativo?: string, // Texto quando inativo (para slide).
|
|
361
|
+
tituloChave?: string, // Titulo para a chave (para multikv).
|
|
362
|
+
tituloValor?: string, // Titulo para o valor (para multikv).
|
|
363
|
+
rows?: number, // Número de linhas (para textarea, select).
|
|
364
|
+
cols?: number, // Número de colunas (para textarea).
|
|
365
|
+
mask?: string | ((valor?: string) => string), // Máscara a ser aplicada ao valor.
|
|
366
|
+
options?: WritableSignal<IKV[]>// Opções para campos que possuem seleção (select, radio, etc).
|
|
367
|
+
multiple?: boolean, // Permitir múltiplas seleções (para select, upload, etc).
|
|
368
|
+
canUnselect?: boolean, // Permitir desselecionar a opção selecionada (para select, radio, etc).
|
|
369
|
+
componente?: Type<any>; // Componente Angular personalizado para renderizar este campo. (para custom)
|
|
370
|
+
tipoBotao?: ITipoBotao; // Tipo do botão (para button).
|
|
371
|
+
onClick?: (form: Formulario) => any;// Função chamada quando o campo é clicado (para button, etc).
|
|
372
|
+
afterRefill?: (form: Formulario, options: IKV[] | null) => any;// Função chamada após o refill do campo (para select, autocomplete, etc).
|
|
373
|
+
onMatchOption?: (form: Formulario, option?: IKV_ext) => any; // Função chamada quando uma opção é selecionada (para autocomplete, select, etc).
|
|
374
|
+
onMatchOptionOnInit?: boolean, // Indica se deve disparar onMatchOption ao iniciar o componente.
|
|
375
|
+
onComplete?: (form: Formulario, value: any) => any // Função chamada quando o campo é completado (para multifactor, etc).
|
|
376
|
+
showHeader?: boolean, // Define se o campo deve exibir o cabeçalho (header) com o título e ícone.
|
|
377
|
+
showToolbar?: boolean, // Define se o campo deve exibir a toolbar de formatação (para editor).
|
|
378
|
+
accept?: string, // Define os tipos de arquivos aceitos (para upload, dropzone, etc). ".png,.svg,.jpg,.jpeg,.gif"
|
|
379
|
+
refill?: (form: Formulario) => Promise<IKV[] | null>; // Função que retorna os dados para popular o campo (para select, autocomplete, etc).
|
|
380
|
+
mapear?: (r: any) => Promise<IKV[] | null>; // Função que mapeia o valor do campo para o formato esperado na submissão do formulário.
|
|
381
|
+
subFields?: IFields<any>; // Define os sub-campos (para multiobject).
|
|
382
|
+
isCollapsed?: () => boolean; // Indica se o campo deve colapsar.
|
|
383
|
+
getDisplay?: (value: any, form?: Formulario) => any; // Função para obter o valor a ser exibido no campo, normalmente no campo Referencia.
|
|
384
|
+
textEmpty?: string; // Texto a ser exibido quando o campo estiver vazio (para select).
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
/************************************************\\
|
|
388
|
+
// FASES \\
|
|
389
|
+
//*************************************************/
|
|
390
|
+
|
|
391
|
+
export interface IFases<T> {
|
|
392
|
+
fases: IFaseCampos<T>[],
|
|
393
|
+
isLinear?: boolean,
|
|
394
|
+
orientation?: 'horizontal' | 'vertical',
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
export interface IFaseCampos<T> {
|
|
398
|
+
nome: string,
|
|
399
|
+
icone?: string | null,
|
|
400
|
+
completed?: boolean,
|
|
401
|
+
optional?: boolean,
|
|
402
|
+
hasErrors?: boolean,
|
|
403
|
+
errorMessage?: string,
|
|
404
|
+
campos: (IFaseCamposAgrupados<T> | keyof T & string)[],
|
|
405
|
+
disabled?: boolean,
|
|
406
|
+
gridMin?: string, // Valor padrão para grid-template-columns mínimo das fases. Ex: "150px"
|
|
407
|
+
gridMax?: string, // Valor padrão para grid-template-columns máximo das fases. Ex: "1fr"
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
export interface IFaseCamposAgrupados<T> {
|
|
411
|
+
campos: (keyof T & string)[],
|
|
412
|
+
titulo?: string,
|
|
413
|
+
area?: string,
|
|
414
|
+
tituloArea?: string,
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
/************************************************\\
|
|
418
|
+
// CAMPOS SIMPLIFICADOS \\
|
|
419
|
+
//*************************************************/
|
|
420
|
+
|
|
421
|
+
export class CampoDe {
|
|
422
|
+
|
|
423
|
+
static AutoComplete<T>(prop: keyof T & string, titulo?: string, config?: Partial<IFieldComponent<T>>): IFieldComponent<T> {
|
|
424
|
+
return {
|
|
425
|
+
tipo: IField.AutoComplete,
|
|
426
|
+
prop,
|
|
427
|
+
titulo,
|
|
428
|
+
...config,
|
|
429
|
+
};
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
static Button<T>(prop: any, tituloClicavel: string, click: (form: Formulario) => void, config?: Partial<IFieldComponent<T>>): IFieldComponent<T> {
|
|
433
|
+
return {
|
|
434
|
+
tipo: IField.Button,
|
|
435
|
+
prop,
|
|
436
|
+
tituloClicavel,
|
|
437
|
+
onClick: click,
|
|
438
|
+
...config,
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
static Checkbox<T>(prop: keyof T & string, titulo?: string, config?: Partial<IFieldComponent<T>>): IFieldComponent<T> {
|
|
443
|
+
return {
|
|
444
|
+
tipo: IField.Checkbox,
|
|
445
|
+
prop,
|
|
446
|
+
titulo,
|
|
447
|
+
...config,
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
static Color<T>(prop: keyof T & string, titulo?: string, config?: Partial<IFieldComponent<T>>): IFieldComponent<T> {
|
|
452
|
+
return {
|
|
453
|
+
tipo: IField.Color,
|
|
454
|
+
prop,
|
|
455
|
+
titulo,
|
|
456
|
+
...config,
|
|
457
|
+
}
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
static Cpf<T>(prop: keyof T & string, titulo?: string, config?: Partial<IFieldComponent<T>>): IFieldComponent<T> {
|
|
461
|
+
return {
|
|
462
|
+
tipo: IField.Text,
|
|
463
|
+
prop,
|
|
464
|
+
titulo,
|
|
465
|
+
mask: LibUtil.formats.cpf.mask,
|
|
466
|
+
placeholder: "000.000.000-00",
|
|
467
|
+
regras: [Regra.CPF()],
|
|
468
|
+
...config,
|
|
469
|
+
}
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
static Cnpj<T>(prop: keyof T & string, titulo?: string, config?: Partial<IFieldComponent<T>>): IFieldComponent<T> {
|
|
473
|
+
return {
|
|
474
|
+
tipo: IField.Text,
|
|
475
|
+
prop,
|
|
476
|
+
titulo,
|
|
477
|
+
mask: LibUtil.formats.cnpj.mask,
|
|
478
|
+
placeholder: "00.000.000/0000-00",
|
|
479
|
+
regras: [Regra.CNPJ()],
|
|
480
|
+
...config,
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
static CpfCnpj<T>(prop: keyof T & string, titulo?: string, config?: Partial<IFieldComponent<T>>): IFieldComponent<T> {
|
|
485
|
+
return {
|
|
486
|
+
tipo: IField.Text,
|
|
487
|
+
prop,
|
|
488
|
+
titulo,
|
|
489
|
+
mask: LibUtil.formats.cpf_cnpj.mask,
|
|
490
|
+
placeholder: "000.000.000-00 ou 00.000.000/0000-00",
|
|
491
|
+
maxl: 18,
|
|
492
|
+
// regras: [Regra.CPF_CNPJ()],
|
|
493
|
+
...config,
|
|
494
|
+
}
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
static Custom<T>(prop: keyof T & string, componente: Type<any>, titulo?: string, config?: Partial<IFieldComponent<T>>): IFieldComponent<T> {
|
|
498
|
+
return {
|
|
499
|
+
tipo: IField.Custom,
|
|
500
|
+
prop,
|
|
501
|
+
titulo,
|
|
502
|
+
componente,
|
|
503
|
+
...config,
|
|
504
|
+
}
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
static Date<T>(prop: keyof T & string, titulo?: string, config?: Partial<IFieldComponent<T>>): IFieldComponent<T> {
|
|
508
|
+
return {
|
|
509
|
+
tipo: IField.Date,
|
|
510
|
+
prop,
|
|
511
|
+
titulo,
|
|
512
|
+
...config,
|
|
513
|
+
}
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
static DateTime<T>(prop: keyof T & string, titulo?: string, config?: Partial<IFieldComponent<T>>): IFieldComponent<T> {
|
|
517
|
+
return {
|
|
518
|
+
tipo: IField.DateTime,
|
|
519
|
+
prop,
|
|
520
|
+
titulo,
|
|
521
|
+
...config,
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
static Display<T>(prop: any, titulo?: string, config?: Partial<IFieldComponent<T>>): IFieldComponent<T> {
|
|
526
|
+
return {
|
|
527
|
+
tipo: IField.Display,
|
|
528
|
+
prop,
|
|
529
|
+
titulo,
|
|
530
|
+
...config,
|
|
531
|
+
}
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
static Editor<T>(prop: keyof T & string, titulo?: string, config?: Partial<IFieldComponent<T>>): IFieldComponent<T> {
|
|
535
|
+
return {
|
|
536
|
+
tipo: IField.Textarea,
|
|
537
|
+
prop,
|
|
538
|
+
titulo,
|
|
539
|
+
area: 'auto / auto / span 2 / auto',
|
|
540
|
+
...config,
|
|
541
|
+
}
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
static Email<T>(prop: keyof T & string, titulo?: string, config?: Partial<IFieldComponent<T>>): IFieldComponent<T> {
|
|
545
|
+
return {
|
|
546
|
+
tipo: IField.Email,
|
|
547
|
+
prop,
|
|
548
|
+
titulo,
|
|
549
|
+
...config,
|
|
550
|
+
}
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
static Hidden<T>(prop: keyof T & string, titulo?: string, config?: Partial<IFieldComponent<T>>): IFieldComponent<T> {
|
|
554
|
+
return {
|
|
555
|
+
tipo: IField.Hidden,
|
|
556
|
+
need: false,
|
|
557
|
+
prop,
|
|
558
|
+
titulo,
|
|
559
|
+
...config,
|
|
560
|
+
}
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
static Icon<T>(prop: keyof T & string, titulo?: string, config?: Partial<IFieldComponent<T>>): IFieldComponent<T> {
|
|
564
|
+
return {
|
|
565
|
+
tipo: IField.Icon,
|
|
566
|
+
prop,
|
|
567
|
+
titulo,
|
|
568
|
+
...config,
|
|
569
|
+
}
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
static MultiFactor<T>(prop: keyof T & string, titulo?: string, config?: Partial<IFieldComponent<T>>): IFieldComponent<T> {
|
|
573
|
+
return {
|
|
574
|
+
tipo: IField.MultiFactor,
|
|
575
|
+
prop,
|
|
576
|
+
titulo,
|
|
577
|
+
...config,
|
|
578
|
+
}
|
|
579
|
+
}
|
|
580
|
+
|
|
581
|
+
static MultiKV<T>(prop: keyof T & string, titulo?: string, config?: Partial<IFieldComponent<T>>): IFieldComponent<T> {
|
|
582
|
+
return {
|
|
583
|
+
tipo: IField.MultiKV,
|
|
584
|
+
prop,
|
|
585
|
+
titulo,
|
|
586
|
+
...config,
|
|
587
|
+
}
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
static MultiText<T>(prop: keyof T & string, titulo?: string, config?: Partial<IFieldComponent<T>>): IFieldComponent<T> {
|
|
591
|
+
return {
|
|
592
|
+
tipo: IField.MultiText,
|
|
593
|
+
prop,
|
|
594
|
+
titulo,
|
|
595
|
+
...config,
|
|
596
|
+
}
|
|
597
|
+
}
|
|
598
|
+
|
|
599
|
+
static Number<T>(prop: keyof T & string, titulo?: string, config?: Partial<IFieldComponent<T>>): IFieldComponent<T> {
|
|
600
|
+
return {
|
|
601
|
+
tipo: IField.Number,
|
|
602
|
+
prop,
|
|
603
|
+
titulo,
|
|
604
|
+
...config,
|
|
605
|
+
}
|
|
606
|
+
}
|
|
607
|
+
|
|
608
|
+
static Password<T>(prop: keyof T & string, titulo?: string, config?: Partial<IFieldComponent<T>>): IFieldComponent<T> {
|
|
609
|
+
return {
|
|
610
|
+
tipo: IField.Password,
|
|
611
|
+
prop,
|
|
612
|
+
titulo,
|
|
613
|
+
...config,
|
|
614
|
+
}
|
|
615
|
+
}
|
|
616
|
+
|
|
617
|
+
static Referencia<T>(prop: keyof T & string, titulo?: string, config?: Partial<IFieldComponent<T>>): IFieldComponent<T> {
|
|
618
|
+
return {
|
|
619
|
+
tipo: IField.Referencia,
|
|
620
|
+
prop,
|
|
621
|
+
titulo,
|
|
622
|
+
...config,
|
|
623
|
+
}
|
|
624
|
+
}
|
|
625
|
+
|
|
626
|
+
static Search<T>(prop: keyof T & string, titulo?: string, config?: Partial<IFieldComponent<T>>): IFieldComponent<T> {
|
|
627
|
+
return {
|
|
628
|
+
tipo: IField.Search,
|
|
629
|
+
prop,
|
|
630
|
+
titulo,
|
|
631
|
+
...config,
|
|
632
|
+
}
|
|
633
|
+
}
|
|
634
|
+
|
|
635
|
+
static Select<T>(prop: keyof T & string, titulo?: string, config?: Partial<IFieldComponent<T>>): IFieldComponent<T> {
|
|
636
|
+
return {
|
|
637
|
+
tipo: IField.Select,
|
|
638
|
+
prop,
|
|
639
|
+
titulo,
|
|
640
|
+
...config,
|
|
641
|
+
};
|
|
642
|
+
}
|
|
643
|
+
|
|
644
|
+
static Slide<T>(prop: keyof T & string, titulo?: string, config?: Partial<IFieldComponent<T>>): IFieldComponent<T> {
|
|
645
|
+
return {
|
|
646
|
+
tipo: IField.Slide,
|
|
647
|
+
prop,
|
|
648
|
+
titulo,
|
|
649
|
+
...config,
|
|
650
|
+
}
|
|
651
|
+
}
|
|
652
|
+
|
|
653
|
+
static Upload<T>(prop: keyof T & string, titulo?: string, config?: Partial<IFieldComponent<T>>): IFieldComponent<T> {
|
|
654
|
+
return {
|
|
655
|
+
tipo: IField.Upload,
|
|
656
|
+
prop,
|
|
657
|
+
titulo,
|
|
658
|
+
...config,
|
|
659
|
+
}
|
|
660
|
+
}
|
|
661
|
+
|
|
662
|
+
static Text<T>(prop: keyof T & string, titulo?: string, config?: Partial<IFieldComponent<T>>): IFieldComponent<T> {
|
|
663
|
+
return {
|
|
664
|
+
tipo: IField.Text,
|
|
665
|
+
prop,
|
|
666
|
+
titulo,
|
|
667
|
+
...config,
|
|
668
|
+
}
|
|
669
|
+
}
|
|
670
|
+
|
|
671
|
+
static Textarea<T>(prop: keyof T & string, titulo?: string, config?: Partial<IFieldComponent<T>>): IFieldComponent<T> {
|
|
672
|
+
return {
|
|
673
|
+
tipo: IField.Textarea,
|
|
674
|
+
prop,
|
|
675
|
+
titulo,
|
|
676
|
+
rows: 15,
|
|
677
|
+
cols: 30,
|
|
678
|
+
...config,
|
|
679
|
+
}
|
|
680
|
+
}
|
|
681
|
+
|
|
682
|
+
static Time<T>(prop: keyof T & string, titulo?: string, config?: Partial<IFieldComponent<T>>): IFieldComponent<T> {
|
|
683
|
+
return {
|
|
684
|
+
tipo: IField.Time,
|
|
685
|
+
prop,
|
|
686
|
+
titulo,
|
|
687
|
+
...config,
|
|
688
|
+
}
|
|
689
|
+
}
|
|
690
|
+
|
|
691
|
+
static UploadImage<T>(prop: keyof T & string, titulo?: string, config?: Partial<IFieldComponent<T>>): IFieldComponent<T> {
|
|
692
|
+
return {
|
|
693
|
+
tipo: IField.Upload,
|
|
694
|
+
prop,
|
|
695
|
+
titulo,
|
|
696
|
+
accept: ".png,.svg,.jpg,.jpeg,.gif",
|
|
697
|
+
...config,
|
|
698
|
+
}
|
|
699
|
+
}
|
|
700
|
+
|
|
701
|
+
}
|
|
702
|
+
|
|
703
|
+
/************************************************\\
|
|
704
|
+
// FILTROS SIMPLIFICADOS \\
|
|
705
|
+
//*************************************************/
|
|
706
|
+
|
|
707
|
+
export class FiltroDe {
|
|
708
|
+
|
|
709
|
+
static Boolean<T>(prop: Extract<keyof T, string>, titulo?: string, config?: Partial<IFieldComponent<T>>): IFieldComponent<any> {
|
|
710
|
+
return {
|
|
711
|
+
...CampoDe.Select<T>((prop as any), titulo, {
|
|
712
|
+
options: signal([{ k: "", v: "Todos" }, { k: "true", v: "Sim" }, { k: "false", v: "Não" }])
|
|
713
|
+
}),
|
|
714
|
+
...config,
|
|
715
|
+
};
|
|
716
|
+
};
|
|
717
|
+
|
|
718
|
+
static Hidden<T>(prop: Extract<keyof T, string>, titulo?: string, config?: Partial<IFieldComponent<T>>): IFieldComponent<any> {
|
|
719
|
+
return CampoDe.Hidden<T>((prop as any), titulo, config);
|
|
720
|
+
};
|
|
721
|
+
|
|
722
|
+
/** Usar este FiltroTexto quando não for Hidden, Select ou Booleano */
|
|
723
|
+
static Text<T>(prop: Extract<keyof T, string>, titulo?: string, config?: Partial<IFieldComponent<T>>): IFieldComponent<any> {
|
|
724
|
+
return CampoDe.Text<T>((prop as any), titulo, config);
|
|
725
|
+
};
|
|
726
|
+
|
|
727
|
+
static Select<T>(prop: Extract<keyof T, string>, titulo?: string, config?: Partial<IFieldComponent<T>>): IFieldComponent<any> {
|
|
728
|
+
return {
|
|
729
|
+
...CampoDe.Select<T>((prop as any), titulo),
|
|
730
|
+
...config,
|
|
731
|
+
};
|
|
732
|
+
};
|
|
733
|
+
|
|
734
|
+
static Date<T>(prop: Extract<keyof T, string>, titulo?: string, config?: Partial<IFieldComponent<T>>): IFieldComponent<any> {
|
|
735
|
+
return {
|
|
736
|
+
...CampoDe.Date<T>((prop as any), titulo),
|
|
737
|
+
...config,
|
|
738
|
+
};
|
|
739
|
+
};
|
|
740
|
+
|
|
741
|
+
}
|
|
742
|
+
|
|
743
|
+
/************************************************\\
|
|
744
|
+
// VALIDAÇÃO de campos \\
|
|
745
|
+
//*************************************************/
|
|
746
|
+
|
|
747
|
+
export enum IRegraTipo {
|
|
748
|
+
ApenasNumeros = "apenasNumeros",
|
|
749
|
+
}
|
|
750
|
+
|
|
751
|
+
export interface IRegra {
|
|
752
|
+
nome: string;
|
|
753
|
+
mensagem: string;
|
|
754
|
+
validar: (value: any) => boolean | Promise<boolean>;
|
|
755
|
+
}
|
|
756
|
+
|
|
757
|
+
export class Regra {
|
|
758
|
+
|
|
759
|
+
static ApenasNumeros(): IRegra {
|
|
760
|
+
return {
|
|
761
|
+
nome: IRegraTipo.ApenasNumeros,
|
|
762
|
+
mensagem: Regra.mensagens.apenasNumeros,
|
|
763
|
+
validar: (value: any): boolean => {
|
|
764
|
+
let s = value.replace(/(?![0-9])./g, "");
|
|
765
|
+
return value.length === s.length;
|
|
766
|
+
}
|
|
767
|
+
}
|
|
768
|
+
}
|
|
769
|
+
|
|
770
|
+
static ApenasLista(): IRegra {
|
|
771
|
+
return {
|
|
772
|
+
nome: "apenasLista",
|
|
773
|
+
mensagem: Regra.mensagens.apenasLista,
|
|
774
|
+
validar: (value: any): boolean => {
|
|
775
|
+
return Array.isArray(value);
|
|
776
|
+
}
|
|
777
|
+
}
|
|
778
|
+
}
|
|
779
|
+
|
|
780
|
+
static ApenasListaDeObjetos(): IRegra {
|
|
781
|
+
return {
|
|
782
|
+
nome: "apenasListaDeObjetos",
|
|
783
|
+
mensagem: Regra.mensagens.apenasListaDeObjetos,
|
|
784
|
+
validar: (value: any): boolean => {
|
|
785
|
+
if (!Array.isArray(value)) return false;
|
|
786
|
+
for (let item of value) {
|
|
787
|
+
if (typeof item !== 'object' || item === null) return false;
|
|
788
|
+
}
|
|
789
|
+
return true;
|
|
790
|
+
}
|
|
791
|
+
}
|
|
792
|
+
}
|
|
793
|
+
|
|
794
|
+
static EntreValores(min: number, max: number): IRegra {
|
|
795
|
+
return {
|
|
796
|
+
nome: "apenasEntre",
|
|
797
|
+
mensagem: Regra.mensagens.apenasEntre(min, max),
|
|
798
|
+
validar: (value: any): boolean => {
|
|
799
|
+
if (typeof value !== 'number') return false;
|
|
800
|
+
return value >= min && value <= max;
|
|
801
|
+
}
|
|
802
|
+
}
|
|
803
|
+
}
|
|
804
|
+
|
|
805
|
+
static TamanhoMinimo(qntCaracteres: number): IRegra {
|
|
806
|
+
return {
|
|
807
|
+
nome: "temSizeMin",
|
|
808
|
+
mensagem: Regra.mensagens.temSizeMin,
|
|
809
|
+
validar: (value: any): boolean => {
|
|
810
|
+
if (!value) return false;
|
|
811
|
+
return value.length >= qntCaracteres;
|
|
812
|
+
}
|
|
813
|
+
}
|
|
814
|
+
}
|
|
815
|
+
|
|
816
|
+
static TamanhoMaximo(qntCaracteres: number): IRegra {
|
|
817
|
+
return {
|
|
818
|
+
nome: "temSizeMax",
|
|
819
|
+
mensagem: Regra.mensagens.temSizeMax,
|
|
820
|
+
validar: (value: any): boolean => {
|
|
821
|
+
if (!value) return true;
|
|
822
|
+
return value.length <= qntCaracteres;
|
|
823
|
+
}
|
|
824
|
+
}
|
|
825
|
+
}
|
|
826
|
+
|
|
827
|
+
static ApenasLetras(): IRegra {
|
|
828
|
+
return {
|
|
829
|
+
nome: "temApenasLetras",
|
|
830
|
+
mensagem: Regra.mensagens.temApenasLetras,
|
|
831
|
+
validar: (value: any): boolean => {
|
|
832
|
+
if (!value) return true;
|
|
833
|
+
let s = value.replace(/(?![A-Za-z])./g, "");
|
|
834
|
+
return value.length === s.length;
|
|
835
|
+
}
|
|
836
|
+
}
|
|
837
|
+
}
|
|
838
|
+
|
|
839
|
+
static ApenasNumerosELetras(): IRegra {
|
|
840
|
+
return {
|
|
841
|
+
nome: "temApenasNumerosELetras",
|
|
842
|
+
mensagem: Regra.mensagens.temApenasNumerosELetras,
|
|
843
|
+
validar: (value: any): boolean => {
|
|
844
|
+
if (!value) return true;
|
|
845
|
+
let s = value.replace(/(?![0-9A-Za-z])./g, "");
|
|
846
|
+
return value.length === s.length;
|
|
847
|
+
}
|
|
848
|
+
}
|
|
849
|
+
}
|
|
850
|
+
|
|
851
|
+
static TemMaiuscula(): IRegra {
|
|
852
|
+
return {
|
|
853
|
+
nome: "temMaiuscula",
|
|
854
|
+
mensagem: Regra.mensagens.temMaiuscula,
|
|
855
|
+
validar: (value: any): boolean => {
|
|
856
|
+
if (!value) return true;
|
|
857
|
+
return /[A-Z]/.test(value);
|
|
858
|
+
}
|
|
859
|
+
}
|
|
860
|
+
}
|
|
861
|
+
|
|
862
|
+
static TemMinuscula(): IRegra {
|
|
863
|
+
return {
|
|
864
|
+
nome: "temMinuscula",
|
|
865
|
+
mensagem: Regra.mensagens.temMinuscula,
|
|
866
|
+
validar: (value: any): boolean => {
|
|
867
|
+
if (!value) return true;
|
|
868
|
+
return /[a-z]/.test(value);
|
|
869
|
+
}
|
|
870
|
+
}
|
|
871
|
+
}
|
|
872
|
+
|
|
873
|
+
static TemNumero(): IRegra {
|
|
874
|
+
return {
|
|
875
|
+
nome: "temNumero",
|
|
876
|
+
mensagem: Regra.mensagens.temNumero,
|
|
877
|
+
validar: (value: any): boolean => {
|
|
878
|
+
if (!value) return true;
|
|
879
|
+
return /[0-9]/.test(value);
|
|
880
|
+
}
|
|
881
|
+
}
|
|
882
|
+
}
|
|
883
|
+
|
|
884
|
+
static TemEspecial(): IRegra {
|
|
885
|
+
return {
|
|
886
|
+
nome: "temEspecial",
|
|
887
|
+
mensagem: Regra.mensagens.temEspecial,
|
|
888
|
+
validar: (value: any): boolean => {
|
|
889
|
+
if (!value) return true;
|
|
890
|
+
return /(?![0-9a-zA-Z])./.test(value);
|
|
891
|
+
}
|
|
892
|
+
}
|
|
893
|
+
}
|
|
894
|
+
|
|
895
|
+
static Email(): IRegra {
|
|
896
|
+
return {
|
|
897
|
+
nome: "isEmail",
|
|
898
|
+
mensagem: Regra.mensagens.isEmail,
|
|
899
|
+
validar: (value: any): boolean => {
|
|
900
|
+
if (!value) return true;
|
|
901
|
+
return LibUtil.formats.email.validate(value);
|
|
902
|
+
}
|
|
903
|
+
}
|
|
904
|
+
}
|
|
905
|
+
|
|
906
|
+
static Same(compareValue: any, mensagem?: string): IRegra {
|
|
907
|
+
return {
|
|
908
|
+
nome: "isSame",
|
|
909
|
+
mensagem: mensagem || Regra.mensagens.isSame,
|
|
910
|
+
validar: (value: any): boolean => {
|
|
911
|
+
return value === compareValue;
|
|
912
|
+
}
|
|
913
|
+
}
|
|
914
|
+
}
|
|
915
|
+
|
|
916
|
+
static SenhaForte(): IRegra {
|
|
917
|
+
return {
|
|
918
|
+
nome: "senhaForte",
|
|
919
|
+
mensagem: Regra.mensagens.senhaForte,
|
|
920
|
+
validar: (value: any): boolean => {
|
|
921
|
+
if (!value) return true;
|
|
922
|
+
const hasNumber = /[0-9]/.test(value);
|
|
923
|
+
const hasMaiuscula = /[A-Z]/.test(value);
|
|
924
|
+
const hasMinuscula = /[a-z]/.test(value);
|
|
925
|
+
const hasEspecial = /(?![0-9a-zA-Z])./.test(value);
|
|
926
|
+
|
|
927
|
+
return hasNumber && hasMaiuscula && hasMinuscula && hasEspecial;
|
|
928
|
+
}
|
|
929
|
+
}
|
|
930
|
+
}
|
|
931
|
+
|
|
932
|
+
static Unique(asyncValidate: (value: any) => Promise<boolean>): IRegra {
|
|
933
|
+
return {
|
|
934
|
+
nome: "isUnique",
|
|
935
|
+
mensagem: Regra.mensagens.isUnique,
|
|
936
|
+
validar: async (value: any): Promise<boolean> => {
|
|
937
|
+
return await asyncValidate(value);
|
|
938
|
+
}
|
|
939
|
+
}
|
|
940
|
+
}
|
|
941
|
+
|
|
942
|
+
static CepBR(): IRegra {
|
|
943
|
+
return {
|
|
944
|
+
nome: "isCepBR",
|
|
945
|
+
mensagem: Regra.mensagens.isCepBR,
|
|
946
|
+
validar: (value: any): boolean => {
|
|
947
|
+
if (!value) return true;
|
|
948
|
+
return /^([0-9]{2}[\.]?[0-9]{3}[-]?[0-9]{3})$/.test(value);
|
|
949
|
+
}
|
|
950
|
+
}
|
|
951
|
+
}
|
|
952
|
+
|
|
953
|
+
static CPF(): IRegra {
|
|
954
|
+
return {
|
|
955
|
+
nome: "isCPF",
|
|
956
|
+
mensagem: Regra.mensagens.isCPF,
|
|
957
|
+
validar: (value: any): boolean => {
|
|
958
|
+
if (!value) return true;
|
|
959
|
+
let c = 0;
|
|
960
|
+
let m1 = [10, 9, 8, 7, 6, 5, 4, 3, 2];
|
|
961
|
+
let m2 = [11, 10, 9, 8, 7, 6, 5, 4, 3, 2];
|
|
962
|
+
let cpf = LibUtil.apenasNumeros(value);
|
|
963
|
+
if (cpf.length != 11) { return false; }
|
|
964
|
+
let temp = cpf.slice(0, 9);
|
|
965
|
+
for (let i = 0; i < 9; i++) { c += Number(temp.charAt(i)) * m1[i]; }
|
|
966
|
+
let r = c % 11;
|
|
967
|
+
(r < 2) ? r = 0 : r = 11 - r;
|
|
968
|
+
temp += r.toString();
|
|
969
|
+
c = 0;
|
|
970
|
+
for (let i = 0; i < 10; i++) { c += Number(temp.charAt(i)) * m2[i]; }
|
|
971
|
+
r = c % 11;
|
|
972
|
+
(r < 2) ? r = 0 : r = 11 - r;
|
|
973
|
+
return cpf.charAt(10) == r.toString();
|
|
974
|
+
}
|
|
975
|
+
}
|
|
976
|
+
}
|
|
977
|
+
|
|
978
|
+
static CNPJ(): IRegra {
|
|
979
|
+
return {
|
|
980
|
+
nome: "isCNPJ",
|
|
981
|
+
mensagem: Regra.mensagens.isCNPJ,
|
|
982
|
+
validar: (value: any): boolean => {
|
|
983
|
+
if (!value) return true;
|
|
984
|
+
let digitCnpj = (cnpj: string) => {
|
|
985
|
+
let m1 = [5, 4, 3, 2, 9, 8, 7, 6, 5, 4, 3, 2];
|
|
986
|
+
let m2 = [6, 5, 4, 3, 2, 9, 8, 7, 6, 5, 4, 3, 2];
|
|
987
|
+
if (!cnpj) { return false; }
|
|
988
|
+
cnpj = LibUtil.apenasNumeros(cnpj);
|
|
989
|
+
if (cnpj.length != 14) { return false; }
|
|
990
|
+
let temp = cnpj.slice(0, 12);
|
|
991
|
+
let c = 0;
|
|
992
|
+
for (let i = 0; i < 12; i++) { c += Number(temp.charAt(i)) * m1[i]; }
|
|
993
|
+
let r = (c % 11);
|
|
994
|
+
(r < 2) ? r = 0 : r = 11 - r;
|
|
995
|
+
temp += r.toString();
|
|
996
|
+
c = 0;
|
|
997
|
+
for (let i = 0; i < 13; i++) { c += Number(temp.charAt(i)) * m2[i]; }
|
|
998
|
+
r = (c % 11);
|
|
999
|
+
(r < 2) ? r = 0 : r = 11 - r;
|
|
1000
|
+
return cnpj.charAt(13) == r.toString();
|
|
1001
|
+
}
|
|
1002
|
+
return digitCnpj(value);
|
|
1003
|
+
}
|
|
1004
|
+
}
|
|
1005
|
+
}
|
|
1006
|
+
|
|
1007
|
+
static ClickRequired(): IRegra {
|
|
1008
|
+
return {
|
|
1009
|
+
nome: "clickRequired",
|
|
1010
|
+
mensagem: Regra.mensagens.clickRequired,
|
|
1011
|
+
validar: (value: any): boolean => {
|
|
1012
|
+
return value === true;
|
|
1013
|
+
}
|
|
1014
|
+
}
|
|
1015
|
+
}
|
|
1016
|
+
|
|
1017
|
+
static Obrigatorio(): IRegra {
|
|
1018
|
+
return {
|
|
1019
|
+
nome: "obrigatorio",
|
|
1020
|
+
mensagem: Regra.mensagens.obrigatorio,
|
|
1021
|
+
validar: (value: any): boolean => {
|
|
1022
|
+
if (value === null || value === undefined) return false;
|
|
1023
|
+
if (typeof value === 'string' && value.trim() === '') return false;
|
|
1024
|
+
if (Array.isArray(value) && value.length === 0) return false;
|
|
1025
|
+
return true;
|
|
1026
|
+
}
|
|
1027
|
+
}
|
|
1028
|
+
}
|
|
1029
|
+
|
|
1030
|
+
static mensagens = {
|
|
1031
|
+
obrigatorio: "Campo Obrigatório.",
|
|
1032
|
+
apenasNumeros: "Apenas Números.",
|
|
1033
|
+
apenasLista: "O valor deve ser uma lista.",
|
|
1034
|
+
apenasListaDeObjetos: "O valor deve ser uma lista de objetos.",
|
|
1035
|
+
apenasEntre: (min: number, max: number) => `O valor deve estar entre ${min} e ${max}.`,
|
|
1036
|
+
temSizeMin: "Tamanho Mínimo.",
|
|
1037
|
+
temSizeMax: "Tamanho Excedido.",
|
|
1038
|
+
temApenasNumeros: "Apenas Números.",
|
|
1039
|
+
temApenasLetras: "Apenas Letras.",
|
|
1040
|
+
temApenasNumerosELetras: "Apenas Números e Letras.",
|
|
1041
|
+
temMaiuscula: "Faltou maiúscula.",
|
|
1042
|
+
temMinuscula: "Faltou minúscula.",
|
|
1043
|
+
temNumero: "Faltou numero.",
|
|
1044
|
+
temEspecial: "Faltou caracter Especial.",
|
|
1045
|
+
isEmail: "Email inválido.",
|
|
1046
|
+
isSame: "Valores diferentes.",
|
|
1047
|
+
senhaForte: "Senha Fraca.",
|
|
1048
|
+
isUnique: "Já está em uso.",
|
|
1049
|
+
isCepBR: "CEP inválido no Brasil.",
|
|
1050
|
+
isCPF: "CPF inválido.",
|
|
1051
|
+
isCNPJ: "CNPJ inválido.",
|
|
1052
|
+
clickRequired: "Clique Necessário.",
|
|
1053
|
+
}
|
|
1054
|
+
|
|
1055
|
+
|
|
1056
|
+
}
|