easy-forms-core 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +133 -0
- package/dist/easy-form.d.ts +338 -0
- package/dist/easy-form.js +2093 -0
- package/dist/easy-form.js.map +1 -0
- package/dist/index.d.ts +637 -0
- package/dist/index.js +2115 -0
- package/dist/index.js.map +1 -0
- package/package.json +61 -0
package/README.md
ADDED
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
# EasyForms
|
|
2
|
+
|
|
3
|
+
EasyForms es una librería agnóstica de framework para construir formularios dinámicos a partir de JSON usando Web Components.
|
|
4
|
+
|
|
5
|
+
Permite crear formularios completos únicamente describiendo un schema JSON.
|
|
6
|
+
|
|
7
|
+
## Compatibilidad
|
|
8
|
+
|
|
9
|
+
Funciona en:
|
|
10
|
+
- Vue
|
|
11
|
+
- React
|
|
12
|
+
- Svelte
|
|
13
|
+
- Nuxt
|
|
14
|
+
- Next
|
|
15
|
+
- Astro
|
|
16
|
+
- HTML vanilla
|
|
17
|
+
|
|
18
|
+
No depende de ningún framework.
|
|
19
|
+
|
|
20
|
+
## Instalación
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
bun add easy-forms
|
|
24
|
+
# o
|
|
25
|
+
npm install easy-forms
|
|
26
|
+
# o
|
|
27
|
+
pnpm add easy-forms
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## Uso Básico
|
|
31
|
+
|
|
32
|
+
### HTML Vanilla
|
|
33
|
+
|
|
34
|
+
```html
|
|
35
|
+
<easy-form id="form"></easy-form>
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
```javascript
|
|
39
|
+
import 'easy-forms'
|
|
40
|
+
|
|
41
|
+
const form = document.querySelector('#form')
|
|
42
|
+
|
|
43
|
+
form.schema = {
|
|
44
|
+
fields: [
|
|
45
|
+
{
|
|
46
|
+
type: 'text',
|
|
47
|
+
name: 'email',
|
|
48
|
+
label: 'Email',
|
|
49
|
+
validations: [
|
|
50
|
+
{ type: 'required' },
|
|
51
|
+
{ type: 'email' }
|
|
52
|
+
]
|
|
53
|
+
}
|
|
54
|
+
]
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
form.addEventListener('submit', (event) => {
|
|
58
|
+
console.log(event.detail)
|
|
59
|
+
})
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
### React
|
|
63
|
+
|
|
64
|
+
```tsx
|
|
65
|
+
import 'easy-forms'
|
|
66
|
+
|
|
67
|
+
function MyForm() {
|
|
68
|
+
return (
|
|
69
|
+
<easy-form
|
|
70
|
+
schema={{
|
|
71
|
+
fields: [
|
|
72
|
+
{ type: 'text', name: 'name', label: 'Nombre' }
|
|
73
|
+
]
|
|
74
|
+
}}
|
|
75
|
+
/>
|
|
76
|
+
)
|
|
77
|
+
}
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
### Vue
|
|
81
|
+
|
|
82
|
+
```vue
|
|
83
|
+
<script setup>
|
|
84
|
+
import 'easy-forms'
|
|
85
|
+
|
|
86
|
+
const schema = {
|
|
87
|
+
fields: [
|
|
88
|
+
{ type: 'text', name: 'name', label: 'Nombre' }
|
|
89
|
+
]
|
|
90
|
+
}
|
|
91
|
+
</script>
|
|
92
|
+
|
|
93
|
+
<template>
|
|
94
|
+
<easy-form :schema="schema" />
|
|
95
|
+
</template>
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
## Características
|
|
99
|
+
|
|
100
|
+
- Web Component nativo
|
|
101
|
+
- Escrito en TypeScript
|
|
102
|
+
- JSON → Form automático
|
|
103
|
+
- Validaciones integradas
|
|
104
|
+
- Steps / wizard forms
|
|
105
|
+
- Formularios anidados
|
|
106
|
+
- Arrays dinámicos
|
|
107
|
+
- Componentes visuales personalizables
|
|
108
|
+
- Eventos de submit, change y error
|
|
109
|
+
- Testing friendly
|
|
110
|
+
- Listo para producción
|
|
111
|
+
|
|
112
|
+
## Desarrollo
|
|
113
|
+
|
|
114
|
+
```bash
|
|
115
|
+
# Instalar dependencias
|
|
116
|
+
bun install
|
|
117
|
+
|
|
118
|
+
# Desarrollo con watch
|
|
119
|
+
bun run dev
|
|
120
|
+
|
|
121
|
+
# Desarrollo de documentación
|
|
122
|
+
bun run dev:docs
|
|
123
|
+
|
|
124
|
+
# Build
|
|
125
|
+
bun run build
|
|
126
|
+
|
|
127
|
+
# Tests
|
|
128
|
+
bun test
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
## Licencia
|
|
132
|
+
|
|
133
|
+
MIT
|
|
@@ -0,0 +1,338 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tipos de campos soportados
|
|
3
|
+
*/
|
|
4
|
+
type FieldType = 'text' | 'email' | 'number' | 'password' | 'textarea' | 'select' | 'checkbox' | 'radio' | 'switch' | 'date' | 'file' | 'array' | 'group' | 'custom';
|
|
5
|
+
/**
|
|
6
|
+
* Tipos de validaciones soportadas
|
|
7
|
+
*/
|
|
8
|
+
type ValidationType = 'required' | 'email' | 'minLength' | 'maxLength' | 'min' | 'max' | 'pattern' | 'custom';
|
|
9
|
+
/**
|
|
10
|
+
* Validación base
|
|
11
|
+
*/
|
|
12
|
+
interface BaseValidation {
|
|
13
|
+
type: ValidationType;
|
|
14
|
+
message?: string;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Validaciones específicas
|
|
18
|
+
*/
|
|
19
|
+
interface RequiredValidation extends BaseValidation {
|
|
20
|
+
type: 'required';
|
|
21
|
+
}
|
|
22
|
+
interface EmailValidation extends BaseValidation {
|
|
23
|
+
type: 'email';
|
|
24
|
+
}
|
|
25
|
+
interface MinLengthValidation extends BaseValidation {
|
|
26
|
+
type: 'minLength';
|
|
27
|
+
value: number;
|
|
28
|
+
}
|
|
29
|
+
interface MaxLengthValidation extends BaseValidation {
|
|
30
|
+
type: 'maxLength';
|
|
31
|
+
value: number;
|
|
32
|
+
}
|
|
33
|
+
interface MinValidation extends BaseValidation {
|
|
34
|
+
type: 'min';
|
|
35
|
+
value: number;
|
|
36
|
+
}
|
|
37
|
+
interface MaxValidation extends BaseValidation {
|
|
38
|
+
type: 'max';
|
|
39
|
+
value: number;
|
|
40
|
+
}
|
|
41
|
+
interface PatternValidation extends BaseValidation {
|
|
42
|
+
type: 'pattern';
|
|
43
|
+
value: string | RegExp;
|
|
44
|
+
}
|
|
45
|
+
interface CustomValidation extends BaseValidation {
|
|
46
|
+
type: 'custom';
|
|
47
|
+
validator: (value: any) => boolean | Promise<boolean>;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Unión de todas las validaciones
|
|
51
|
+
*/
|
|
52
|
+
type Validation = RequiredValidation | EmailValidation | MinLengthValidation | MaxLengthValidation | MinValidation | MaxValidation | PatternValidation | CustomValidation;
|
|
53
|
+
/**
|
|
54
|
+
* Campo base
|
|
55
|
+
*/
|
|
56
|
+
interface BaseField {
|
|
57
|
+
type: FieldType;
|
|
58
|
+
name: string;
|
|
59
|
+
label?: string;
|
|
60
|
+
placeholder?: string;
|
|
61
|
+
defaultValue?: any;
|
|
62
|
+
validations?: Validation[];
|
|
63
|
+
props?: Record<string, any>;
|
|
64
|
+
disabled?: boolean;
|
|
65
|
+
hidden?: boolean;
|
|
66
|
+
description?: string;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Campo de texto
|
|
70
|
+
*/
|
|
71
|
+
interface TextField extends BaseField {
|
|
72
|
+
type: 'text' | 'email' | 'password';
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Campo numérico
|
|
76
|
+
*/
|
|
77
|
+
interface NumberField extends BaseField {
|
|
78
|
+
type: 'number';
|
|
79
|
+
min?: number;
|
|
80
|
+
max?: number;
|
|
81
|
+
step?: number;
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Campo textarea
|
|
85
|
+
*/
|
|
86
|
+
interface TextareaField extends BaseField {
|
|
87
|
+
type: 'textarea';
|
|
88
|
+
rows?: number;
|
|
89
|
+
cols?: number;
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Campo select
|
|
93
|
+
*/
|
|
94
|
+
interface SelectField extends BaseField {
|
|
95
|
+
type: 'select';
|
|
96
|
+
options: Array<{
|
|
97
|
+
label: string;
|
|
98
|
+
value: any;
|
|
99
|
+
} | string>;
|
|
100
|
+
multiple?: boolean;
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Campo checkbox
|
|
104
|
+
*/
|
|
105
|
+
interface CheckboxField extends BaseField {
|
|
106
|
+
type: 'checkbox';
|
|
107
|
+
checked?: boolean;
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Campo radio
|
|
111
|
+
*/
|
|
112
|
+
interface RadioField extends BaseField {
|
|
113
|
+
type: 'radio';
|
|
114
|
+
options: Array<{
|
|
115
|
+
label: string;
|
|
116
|
+
value: any;
|
|
117
|
+
} | string>;
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Campo switch
|
|
121
|
+
*/
|
|
122
|
+
interface SwitchField extends BaseField {
|
|
123
|
+
type: 'switch';
|
|
124
|
+
checked?: boolean;
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Campo date
|
|
128
|
+
*/
|
|
129
|
+
interface DateField extends BaseField {
|
|
130
|
+
type: 'date';
|
|
131
|
+
min?: string;
|
|
132
|
+
max?: string;
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Campo file
|
|
136
|
+
*/
|
|
137
|
+
interface FileField extends BaseField {
|
|
138
|
+
type: 'file';
|
|
139
|
+
accept?: string;
|
|
140
|
+
multiple?: boolean;
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Campo array
|
|
144
|
+
*/
|
|
145
|
+
interface ArrayField extends BaseField {
|
|
146
|
+
type: 'array';
|
|
147
|
+
itemSchema: FormSchema;
|
|
148
|
+
minItems?: number;
|
|
149
|
+
maxItems?: number;
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* Campo group
|
|
153
|
+
*/
|
|
154
|
+
interface GroupField extends BaseField {
|
|
155
|
+
type: 'group';
|
|
156
|
+
fields: Field[];
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* Campo custom
|
|
160
|
+
*/
|
|
161
|
+
interface CustomField extends BaseField {
|
|
162
|
+
type: 'custom';
|
|
163
|
+
component: string;
|
|
164
|
+
}
|
|
165
|
+
/**
|
|
166
|
+
* Unión de todos los tipos de campos
|
|
167
|
+
*/
|
|
168
|
+
type Field = TextField | NumberField | TextareaField | SelectField | CheckboxField | RadioField | SwitchField | DateField | FileField | ArrayField | GroupField | CustomField;
|
|
169
|
+
/**
|
|
170
|
+
* Step para formularios wizard
|
|
171
|
+
*/
|
|
172
|
+
interface Step {
|
|
173
|
+
title: string;
|
|
174
|
+
description?: string;
|
|
175
|
+
fields: Field[];
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* Tipos de temas disponibles
|
|
179
|
+
*/
|
|
180
|
+
type FormTheme = 'plano' | 'tradicional' | 'material' | 'rounded-shadow' | 'lines';
|
|
181
|
+
/**
|
|
182
|
+
* Colores personalizados del formulario
|
|
183
|
+
*/
|
|
184
|
+
interface FormColors {
|
|
185
|
+
primary?: string;
|
|
186
|
+
secondary?: string;
|
|
187
|
+
error?: string;
|
|
188
|
+
success?: string;
|
|
189
|
+
text?: string;
|
|
190
|
+
border?: string;
|
|
191
|
+
background?: string;
|
|
192
|
+
}
|
|
193
|
+
/**
|
|
194
|
+
* Schema del formulario
|
|
195
|
+
*/
|
|
196
|
+
interface FormSchema {
|
|
197
|
+
fields?: Field[];
|
|
198
|
+
steps?: Step[];
|
|
199
|
+
}
|
|
200
|
+
/**
|
|
201
|
+
* Componente personalizado para inyección
|
|
202
|
+
*/
|
|
203
|
+
type CustomComponent = (props: {
|
|
204
|
+
field: Field;
|
|
205
|
+
value: any;
|
|
206
|
+
error?: string;
|
|
207
|
+
onChange: (value: any) => void;
|
|
208
|
+
onBlur: () => void;
|
|
209
|
+
}) => HTMLElement | null;
|
|
210
|
+
/**
|
|
211
|
+
* Registro de componentes personalizados
|
|
212
|
+
*/
|
|
213
|
+
interface ComponentRegistry {
|
|
214
|
+
[key: string]: CustomComponent;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
declare const BrowserHTMLElement: {
|
|
218
|
+
new (): HTMLElement;
|
|
219
|
+
prototype: HTMLElement;
|
|
220
|
+
};
|
|
221
|
+
/**
|
|
222
|
+
* Web Component principal EasyForm
|
|
223
|
+
*/
|
|
224
|
+
declare class EasyForm extends BrowserHTMLElement {
|
|
225
|
+
private stateManager;
|
|
226
|
+
protected shadow: ShadowRoot;
|
|
227
|
+
private customComponents;
|
|
228
|
+
private isRendering;
|
|
229
|
+
static get observedAttributes(): string[];
|
|
230
|
+
constructor();
|
|
231
|
+
/**
|
|
232
|
+
* Obtiene el schema
|
|
233
|
+
*/
|
|
234
|
+
get schema(): FormSchema | null;
|
|
235
|
+
/**
|
|
236
|
+
* Establece el schema
|
|
237
|
+
*/
|
|
238
|
+
set schema(value: FormSchema | null);
|
|
239
|
+
/**
|
|
240
|
+
* Se llama cuando el componente se conecta al DOM
|
|
241
|
+
*/
|
|
242
|
+
connectedCallback(): void;
|
|
243
|
+
/**
|
|
244
|
+
* Se llama cuando un atributo cambia
|
|
245
|
+
*/
|
|
246
|
+
attributeChangedCallback(name: string, oldValue: string, newValue: string): void;
|
|
247
|
+
/**
|
|
248
|
+
* Maneja el cambio de schema
|
|
249
|
+
*/
|
|
250
|
+
private handleSchemaChange;
|
|
251
|
+
/**
|
|
252
|
+
* Renderiza el formulario
|
|
253
|
+
*/
|
|
254
|
+
private render;
|
|
255
|
+
/**
|
|
256
|
+
* Preserva los valores actuales del DOM antes de re-renderizar
|
|
257
|
+
* Retorna un objeto con los valores preservados
|
|
258
|
+
*/
|
|
259
|
+
private preserveCurrentValues;
|
|
260
|
+
/**
|
|
261
|
+
* Renderiza campos normales
|
|
262
|
+
*/
|
|
263
|
+
private renderFields;
|
|
264
|
+
/**
|
|
265
|
+
* Renderiza un campo
|
|
266
|
+
*/
|
|
267
|
+
private renderField;
|
|
268
|
+
/**
|
|
269
|
+
* Renderiza un grupo de campos
|
|
270
|
+
*/
|
|
271
|
+
private renderGroup;
|
|
272
|
+
/**
|
|
273
|
+
* Renderiza un array dinámico
|
|
274
|
+
*/
|
|
275
|
+
private renderArray;
|
|
276
|
+
/**
|
|
277
|
+
* Renderiza un campo custom
|
|
278
|
+
*/
|
|
279
|
+
private renderCustom;
|
|
280
|
+
/**
|
|
281
|
+
* Renderiza wizard
|
|
282
|
+
*/
|
|
283
|
+
private renderWizard;
|
|
284
|
+
/**
|
|
285
|
+
* Maneja el cambio de un campo
|
|
286
|
+
*/
|
|
287
|
+
private handleFieldChange;
|
|
288
|
+
/**
|
|
289
|
+
* Maneja el blur de un campo
|
|
290
|
+
*/
|
|
291
|
+
private handleFieldBlur;
|
|
292
|
+
/**
|
|
293
|
+
* Actualiza solo un campo específico sin re-renderizar todo el formulario
|
|
294
|
+
*/
|
|
295
|
+
private updateSingleField;
|
|
296
|
+
/**
|
|
297
|
+
* Busca un campo por nombre en el schema
|
|
298
|
+
*/
|
|
299
|
+
private findFieldInSchema;
|
|
300
|
+
/**
|
|
301
|
+
* Maneja el submit del formulario
|
|
302
|
+
*/
|
|
303
|
+
private handleSubmit;
|
|
304
|
+
/**
|
|
305
|
+
* Emite evento de error
|
|
306
|
+
*/
|
|
307
|
+
private emitError;
|
|
308
|
+
/**
|
|
309
|
+
* Emite evento de cambio de step
|
|
310
|
+
*/
|
|
311
|
+
private emitStepChange;
|
|
312
|
+
/**
|
|
313
|
+
* Registra componentes personalizados
|
|
314
|
+
*/
|
|
315
|
+
registerComponents(components: ComponentRegistry): void;
|
|
316
|
+
/**
|
|
317
|
+
* Obtiene el tema del formulario
|
|
318
|
+
*/
|
|
319
|
+
get theme(): FormTheme;
|
|
320
|
+
/**
|
|
321
|
+
* Establece el tema del formulario
|
|
322
|
+
*/
|
|
323
|
+
set theme(value: FormTheme);
|
|
324
|
+
/**
|
|
325
|
+
* Obtiene los colores personalizados
|
|
326
|
+
*/
|
|
327
|
+
get colors(): FormColors | null;
|
|
328
|
+
/**
|
|
329
|
+
* Establece los colores personalizados
|
|
330
|
+
*/
|
|
331
|
+
set colors(value: FormColors | null);
|
|
332
|
+
/**
|
|
333
|
+
* Configura estilos básicos
|
|
334
|
+
*/
|
|
335
|
+
private setupStyles;
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
export { EasyForm };
|