easy-forms-core 1.1.0 → 1.1.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 +169 -2
- package/dist/easy-form.d.ts +20 -0
- package/dist/easy-form.js +307 -55
- package/dist/easy-form.js.map +1 -1
- package/dist/index.d.ts +20 -0
- package/dist/index.js +307 -55
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
#
|
|
1
|
+
# EasyFormsCore
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
EasyFormsCore es una librería agnóstica de framework para construir formularios dinámicos a partir de JSON usando Web Components.
|
|
4
4
|
|
|
5
5
|
Permite crear formularios completos únicamente describiendo un schema JSON.
|
|
6
6
|
|
|
@@ -229,6 +229,173 @@ form.schema = { fields: [...] }
|
|
|
229
229
|
// template ahora es null
|
|
230
230
|
```
|
|
231
231
|
|
|
232
|
+
## Personalización de Estilos
|
|
233
|
+
|
|
234
|
+
EasyFormsCore utiliza variables CSS que puedes sobrescribir para personalizar completamente la apariencia de tus formularios. Todas las variables están definidas en el scope del componente (`:host`), lo que permite un control total sobre los colores y estilos.
|
|
235
|
+
|
|
236
|
+
### Variables CSS Disponibles
|
|
237
|
+
|
|
238
|
+
Puedes sobrescribir estas variables CSS para personalizar los colores de tu formulario:
|
|
239
|
+
|
|
240
|
+
```css
|
|
241
|
+
easy-form {
|
|
242
|
+
--easy-form-primary: #007bff; /* Color principal (botones, focus, etc.) */
|
|
243
|
+
--easy-form-secondary: #6c757d; /* Color secundario */
|
|
244
|
+
--easy-form-error: #dc3545; /* Color de error */
|
|
245
|
+
--easy-form-success: #28a745; /* Color de éxito */
|
|
246
|
+
--easy-form-text: #212529; /* Color del texto */
|
|
247
|
+
--easy-form-label-color: #212529; /* Color de las etiquetas */
|
|
248
|
+
--easy-form-border: #ddd; /* Color de los bordes */
|
|
249
|
+
--easy-form-background: #ffffff; /* Color de fondo */
|
|
250
|
+
}
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
### Ejemplo de Personalización de Colores
|
|
254
|
+
|
|
255
|
+
```html
|
|
256
|
+
<style>
|
|
257
|
+
easy-form {
|
|
258
|
+
--easy-form-primary: #8b5cf6;
|
|
259
|
+
--easy-form-secondary: #64748b;
|
|
260
|
+
--easy-form-error: #ef4444;
|
|
261
|
+
--easy-form-success: #10b981;
|
|
262
|
+
--easy-form-text: #1e293b;
|
|
263
|
+
--easy-form-label-color: #334155;
|
|
264
|
+
--easy-form-border: #e2e8f0;
|
|
265
|
+
--easy-form-background: #ffffff;
|
|
266
|
+
}
|
|
267
|
+
</style>
|
|
268
|
+
|
|
269
|
+
<easy-form id="form"></easy-form>
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
### Sobrescribir Estilos con Clases CSS
|
|
273
|
+
|
|
274
|
+
Puedes sobrescribir cualquier estilo usando las clases CSS del componente. Todas las clases utilizan el prefijo `easy-form-` para evitar conflictos.
|
|
275
|
+
|
|
276
|
+
#### Clases Principales
|
|
277
|
+
|
|
278
|
+
- `.easy-form-field` - Contenedor de cada campo
|
|
279
|
+
- `.easy-form-label` - Etiquetas de los campos
|
|
280
|
+
- `.easy-form-required` - Indicador de campo requerido (asterisco)
|
|
281
|
+
- `.easy-form-input-error` - Input con error
|
|
282
|
+
- `.easy-form-error` - Mensaje de error
|
|
283
|
+
- `.easy-form-description` - Descripción del campo
|
|
284
|
+
- `.easy-form-submit` - Botón de envío
|
|
285
|
+
|
|
286
|
+
#### Clases de Grupos y Filas
|
|
287
|
+
|
|
288
|
+
- `.easy-form-group` - Contenedor de grupo de campos
|
|
289
|
+
- `.easy-form-group-label` - Etiqueta del grupo
|
|
290
|
+
- `.easy-form-row` - Fila horizontal de campos
|
|
291
|
+
- `.easy-form-array` - Contenedor de array dinámico
|
|
292
|
+
- `.easy-form-array-item` - Item individual del array
|
|
293
|
+
- `.easy-form-array-add` - Botón para agregar items
|
|
294
|
+
- `.easy-form-array-remove` - Botón para remover items
|
|
295
|
+
|
|
296
|
+
#### Clases de Wizard/Steps
|
|
297
|
+
|
|
298
|
+
- `.easy-form-wizard` - Contenedor del wizard
|
|
299
|
+
- `.easy-form-wizard-steps` - Contenedor de los pasos
|
|
300
|
+
- `.easy-form-wizard-step` - Paso individual
|
|
301
|
+
- `.easy-form-wizard-step.active` - Paso activo
|
|
302
|
+
- `.easy-form-wizard-step.completed` - Paso completado
|
|
303
|
+
- `.easy-form-wizard-nav` - Navegación del wizard
|
|
304
|
+
- `.easy-form-wizard-prev` - Botón anterior
|
|
305
|
+
- `.easy-form-wizard-next` - Botón siguiente
|
|
306
|
+
- `.easy-form-wizard-fields` - Contenedor de campos del paso actual
|
|
307
|
+
|
|
308
|
+
#### Clases de Inputs Especiales
|
|
309
|
+
|
|
310
|
+
- `.easy-form-radio-group` - Grupo de radio buttons
|
|
311
|
+
- `.easy-form-radio-option` - Opción de radio
|
|
312
|
+
- `.easy-form-radio-label` - Etiqueta de radio
|
|
313
|
+
- `.easy-form-label-checkbox` - Etiqueta de checkbox
|
|
314
|
+
- `.easy-form-label-switch` - Etiqueta de switch
|
|
315
|
+
- `.easy-form-quantity-container` - Contenedor de quantity input
|
|
316
|
+
- `.easy-form-quantity-wrapper` - Wrapper del quantity
|
|
317
|
+
- `.easy-form-quantity-btn` - Botón +/- del quantity
|
|
318
|
+
- `.easy-form-quantity-input` - Input del quantity
|
|
319
|
+
- `.easy-form-accordion-select-container` - Contenedor de accordion select
|
|
320
|
+
- `.easy-form-accordion-item` - Item del accordion
|
|
321
|
+
- `.easy-form-accordion-item.selected` - Item seleccionado
|
|
322
|
+
- `.easy-form-accordion-item.open` - Item abierto
|
|
323
|
+
- `.easy-form-accordion-header` - Header del accordion
|
|
324
|
+
- `.easy-form-accordion-content` - Contenido del accordion
|
|
325
|
+
- `.easy-form-image-grid-container` - Contenedor de image grid
|
|
326
|
+
- `.easy-form-image-grid-item` - Item del grid
|
|
327
|
+
- `.easy-form-image-grid-item.selected` - Item seleccionado
|
|
328
|
+
- `.easy-form-otp-container` - Contenedor de OTP
|
|
329
|
+
- `.easy-form-otp-input` - Input individual de OTP
|
|
330
|
+
|
|
331
|
+
#### Clases de Estado
|
|
332
|
+
|
|
333
|
+
- `.easy-form-field-hidden` - Campo oculto
|
|
334
|
+
- `.easy-form-field-disabled` - Campo deshabilitado
|
|
335
|
+
|
|
336
|
+
### Ejemplo de Sobrescritura de Estilos
|
|
337
|
+
|
|
338
|
+
```html
|
|
339
|
+
<style>
|
|
340
|
+
/* Personalizar colores con variables CSS */
|
|
341
|
+
easy-form {
|
|
342
|
+
--easy-form-primary: #6366f1;
|
|
343
|
+
--easy-form-error: #f43f5e;
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
/* Sobrescribir estilos específicos */
|
|
347
|
+
easy-form .easy-form-label {
|
|
348
|
+
font-weight: 700;
|
|
349
|
+
font-size: 0.875rem;
|
|
350
|
+
text-transform: uppercase;
|
|
351
|
+
letter-spacing: 0.05em;
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
easy-form .easy-form-submit {
|
|
355
|
+
border-radius: 12px;
|
|
356
|
+
padding: 0.875rem 2rem;
|
|
357
|
+
font-weight: 600;
|
|
358
|
+
text-transform: uppercase;
|
|
359
|
+
letter-spacing: 0.1em;
|
|
360
|
+
box-shadow: 0 4px 12px rgba(99, 102, 241, 0.3);
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
easy-form .easy-form-submit:hover {
|
|
364
|
+
transform: translateY(-2px);
|
|
365
|
+
box-shadow: 0 6px 16px rgba(99, 102, 241, 0.4);
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
/* Personalizar inputs */
|
|
369
|
+
easy-form input:not([type="checkbox"]):not([type="radio"]),
|
|
370
|
+
easy-form textarea,
|
|
371
|
+
easy-form select {
|
|
372
|
+
border-radius: 8px;
|
|
373
|
+
border-width: 2px;
|
|
374
|
+
padding: 0.75rem 1rem;
|
|
375
|
+
transition: all 0.2s ease;
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
easy-form input:focus,
|
|
379
|
+
easy-form textarea:focus,
|
|
380
|
+
easy-form select:focus {
|
|
381
|
+
outline: none;
|
|
382
|
+
box-shadow: 0 0 0 4px rgba(99, 102, 241, 0.1);
|
|
383
|
+
}
|
|
384
|
+
</style>
|
|
385
|
+
|
|
386
|
+
<easy-form id="form"></easy-form>
|
|
387
|
+
```
|
|
388
|
+
|
|
389
|
+
### Notas Importantes
|
|
390
|
+
|
|
391
|
+
1. **Especificidad**: Los estilos del componente tienen especificidad media. Si necesitas sobrescribir estilos con `!important`, puedes hacerlo, pero se recomienda usar variables CSS cuando sea posible.
|
|
392
|
+
|
|
393
|
+
2. **Shadow DOM**: El componente utiliza Shadow DOM, por lo que los estilos globales no afectan directamente al contenido interno. Debes usar el selector `easy-form` o las variables CSS.
|
|
394
|
+
|
|
395
|
+
3. **Variables CSS**: Las variables CSS son la forma recomendada de personalizar colores, ya que se propagan correctamente dentro del Shadow DOM.
|
|
396
|
+
|
|
397
|
+
4. **Temas**: Los temas predefinidos (plano, tradicional, material, etc.) también respetan las variables CSS que definas, por lo que puedes cambiar los colores manteniendo el estilo del tema.
|
|
398
|
+
|
|
232
399
|
## Características
|
|
233
400
|
|
|
234
401
|
- Web Component nativo
|
package/dist/easy-form.d.ts
CHANGED
|
@@ -385,6 +385,10 @@ declare class EasyForm extends BrowserHTMLElement {
|
|
|
385
385
|
* Renderiza el formulario
|
|
386
386
|
*/
|
|
387
387
|
private render;
|
|
388
|
+
/**
|
|
389
|
+
* Actualiza el overlay de loading sobre el formulario
|
|
390
|
+
*/
|
|
391
|
+
private updateLoadingOverlay;
|
|
388
392
|
/**
|
|
389
393
|
* Preserva los valores actuales del DOM antes de re-renderizar
|
|
390
394
|
* Retorna un objeto con los valores preservados
|
|
@@ -527,6 +531,22 @@ declare class EasyForm extends BrowserHTMLElement {
|
|
|
527
531
|
* Establece los datos iniciales
|
|
528
532
|
*/
|
|
529
533
|
set initialData(value: Record<string, any> | null);
|
|
534
|
+
/**
|
|
535
|
+
* Obtiene el estado de loading
|
|
536
|
+
*/
|
|
537
|
+
get loading(): boolean;
|
|
538
|
+
/**
|
|
539
|
+
* Establece el estado de loading
|
|
540
|
+
*/
|
|
541
|
+
set loading(value: boolean);
|
|
542
|
+
/**
|
|
543
|
+
* Obtiene el estado de disabled
|
|
544
|
+
*/
|
|
545
|
+
get disabled(): boolean;
|
|
546
|
+
/**
|
|
547
|
+
* Establece el estado de disabled
|
|
548
|
+
*/
|
|
549
|
+
set disabled(value: boolean);
|
|
530
550
|
/**
|
|
531
551
|
* Configura estilos básicos
|
|
532
552
|
*/
|
package/dist/easy-form.js
CHANGED
|
@@ -382,7 +382,41 @@ function getBaseStyles(colors) {
|
|
|
382
382
|
.easy-form-wizard-nav {
|
|
383
383
|
display: flex;
|
|
384
384
|
gap: 1rem;
|
|
385
|
-
margin-top:
|
|
385
|
+
margin-top: 2rem;
|
|
386
|
+
justify-content: flex-end;
|
|
387
|
+
align-items: center;
|
|
388
|
+
}
|
|
389
|
+
.easy-form-wizard-prev,
|
|
390
|
+
.easy-form-wizard-next {
|
|
391
|
+
padding: 0.75rem 1.5rem;
|
|
392
|
+
background: var(--easy-form-primary);
|
|
393
|
+
color: white;
|
|
394
|
+
border: none;
|
|
395
|
+
border-radius: 4px;
|
|
396
|
+
font-size: 1rem;
|
|
397
|
+
font-weight: 600;
|
|
398
|
+
cursor: pointer;
|
|
399
|
+
transition: all 0.2s ease;
|
|
400
|
+
font-family: inherit;
|
|
401
|
+
min-width: 120px;
|
|
402
|
+
}
|
|
403
|
+
.easy-form-wizard-prev:hover:not(:disabled),
|
|
404
|
+
.easy-form-wizard-next:hover:not(:disabled) {
|
|
405
|
+
opacity: 0.9;
|
|
406
|
+
transform: translateY(-1px);
|
|
407
|
+
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
|
408
|
+
}
|
|
409
|
+
.easy-form-wizard-prev:disabled {
|
|
410
|
+
opacity: 0.5;
|
|
411
|
+
cursor: not-allowed;
|
|
412
|
+
}
|
|
413
|
+
.easy-form-wizard-prev {
|
|
414
|
+
background: var(--easy-form-secondary);
|
|
415
|
+
order: 1;
|
|
416
|
+
}
|
|
417
|
+
.easy-form-wizard-next {
|
|
418
|
+
background: var(--easy-form-primary);
|
|
419
|
+
order: 2;
|
|
386
420
|
}
|
|
387
421
|
.easy-form-array-item {
|
|
388
422
|
padding: 1rem;
|
|
@@ -648,6 +682,53 @@ function getBaseStyles(colors) {
|
|
|
648
682
|
.easy-form-otp-input:invalid {
|
|
649
683
|
border-color: var(--easy-form-error);
|
|
650
684
|
}
|
|
685
|
+
/* Loading Overlay (sobre el formulario) */
|
|
686
|
+
.easy-form-loading-overlay {
|
|
687
|
+
position: absolute;
|
|
688
|
+
top: 0;
|
|
689
|
+
left: 0;
|
|
690
|
+
right: 0;
|
|
691
|
+
bottom: 0;
|
|
692
|
+
background: rgba(255, 255, 255, 0.8);
|
|
693
|
+
display: flex;
|
|
694
|
+
align-items: center;
|
|
695
|
+
justify-content: center;
|
|
696
|
+
z-index: 1000;
|
|
697
|
+
backdrop-filter: blur(2px);
|
|
698
|
+
border-radius: inherit;
|
|
699
|
+
}
|
|
700
|
+
.easy-form-loading-spinner {
|
|
701
|
+
width: 40px;
|
|
702
|
+
height: 40px;
|
|
703
|
+
border: 4px solid rgba(0, 0, 0, 0.1);
|
|
704
|
+
border-top-color: var(--easy-form-primary);
|
|
705
|
+
border-radius: 50%;
|
|
706
|
+
animation: easy-form-spin 0.8s linear infinite;
|
|
707
|
+
}
|
|
708
|
+
@keyframes easy-form-spin {
|
|
709
|
+
to {
|
|
710
|
+
transform: rotate(360deg);
|
|
711
|
+
}
|
|
712
|
+
}
|
|
713
|
+
/* Disabled State */
|
|
714
|
+
.easy-form-disabled,
|
|
715
|
+
.easy-form-disabled * {
|
|
716
|
+
pointer-events: none;
|
|
717
|
+
opacity: 0.6;
|
|
718
|
+
}
|
|
719
|
+
.easy-form-disabled input,
|
|
720
|
+
.easy-form-disabled textarea,
|
|
721
|
+
.easy-form-disabled select,
|
|
722
|
+
.easy-form-disabled button {
|
|
723
|
+
cursor: not-allowed;
|
|
724
|
+
}
|
|
725
|
+
.easy-form-input-disabled {
|
|
726
|
+
opacity: 0.6;
|
|
727
|
+
cursor: not-allowed !important;
|
|
728
|
+
}
|
|
729
|
+
form {
|
|
730
|
+
position: relative;
|
|
731
|
+
}
|
|
651
732
|
`;
|
|
652
733
|
}
|
|
653
734
|
function getThemeSpecificStyles(theme, colors) {
|
|
@@ -1731,7 +1812,20 @@ var ValidationEngine = class {
|
|
|
1731
1812
|
if (!value) {
|
|
1732
1813
|
return { isValid: true };
|
|
1733
1814
|
}
|
|
1734
|
-
|
|
1815
|
+
let regex;
|
|
1816
|
+
if (pattern instanceof RegExp) {
|
|
1817
|
+
regex = pattern;
|
|
1818
|
+
} else if (typeof pattern === "string") {
|
|
1819
|
+
try {
|
|
1820
|
+
regex = new RegExp(pattern);
|
|
1821
|
+
} catch (e) {
|
|
1822
|
+
console.warn("Invalid regex pattern:", pattern);
|
|
1823
|
+
return { isValid: true };
|
|
1824
|
+
}
|
|
1825
|
+
} else {
|
|
1826
|
+
console.warn("Pattern validation expects string or RegExp, got:", typeof pattern, pattern);
|
|
1827
|
+
return { isValid: true };
|
|
1828
|
+
}
|
|
1735
1829
|
const isValid = regex.test(String(value));
|
|
1736
1830
|
return {
|
|
1737
1831
|
isValid,
|
|
@@ -4436,7 +4530,7 @@ var EasyForm = class extends BrowserHTMLElement {
|
|
|
4436
4530
|
this.shadow = this.attachShadow({ mode: "open" });
|
|
4437
4531
|
}
|
|
4438
4532
|
static get observedAttributes() {
|
|
4439
|
-
return ["schema", "template", "template-extend", "theme", "colors", "initialData"];
|
|
4533
|
+
return ["schema", "template", "template-extend", "theme", "colors", "initialData", "loading", "disabled"];
|
|
4440
4534
|
}
|
|
4441
4535
|
/**
|
|
4442
4536
|
* Obtiene el schema
|
|
@@ -4545,6 +4639,21 @@ var EasyForm = class extends BrowserHTMLElement {
|
|
|
4545
4639
|
if ((name === "theme" || name === "colors") && newValue !== oldValue) {
|
|
4546
4640
|
this.setupStyles();
|
|
4547
4641
|
}
|
|
4642
|
+
if (name === "loading" && newValue !== oldValue) {
|
|
4643
|
+
const form = this.shadow.querySelector("form");
|
|
4644
|
+
this.updateLoadingOverlay(form || void 0);
|
|
4645
|
+
if (form) {
|
|
4646
|
+
const inputs = form.querySelectorAll("input, textarea, select, button");
|
|
4647
|
+
inputs.forEach((input) => {
|
|
4648
|
+
if (input instanceof HTMLElement && "disabled" in input) {
|
|
4649
|
+
input.disabled = this.loading;
|
|
4650
|
+
}
|
|
4651
|
+
});
|
|
4652
|
+
}
|
|
4653
|
+
}
|
|
4654
|
+
if (name === "disabled" && newValue !== oldValue) {
|
|
4655
|
+
this.render();
|
|
4656
|
+
}
|
|
4548
4657
|
}
|
|
4549
4658
|
/**
|
|
4550
4659
|
* Maneja el cambio de schema
|
|
@@ -4602,26 +4711,51 @@ var EasyForm = class extends BrowserHTMLElement {
|
|
|
4602
4711
|
return;
|
|
4603
4712
|
}
|
|
4604
4713
|
const preservedValues = this.preserveCurrentValues();
|
|
4714
|
+
const previousWizardState = this.stateManager.getWizardState();
|
|
4605
4715
|
if (preservedValues && Object.keys(preservedValues).length > 0) {
|
|
4606
4716
|
for (const [key, value] of Object.entries(preservedValues)) {
|
|
4607
4717
|
this.stateManager.setValueWithoutValidation(key, value);
|
|
4608
4718
|
}
|
|
4609
4719
|
}
|
|
4610
4720
|
const initialData = this.initialData;
|
|
4611
|
-
|
|
4612
|
-
const
|
|
4721
|
+
const wasWizard = previousWizardState !== null;
|
|
4722
|
+
const isWizard = schema.steps && schema.steps.length > 0;
|
|
4723
|
+
const shouldReinitialize = !previousWizardState || !wasWizard || !isWizard || previousWizardState && schema.steps && previousWizardState.totalSteps !== schema.steps.length;
|
|
4724
|
+
if (shouldReinitialize) {
|
|
4725
|
+
this.stateManager.initializeSchema(schema, initialData || void 0);
|
|
4726
|
+
if (wasWizard && isWizard && previousWizardState) {
|
|
4727
|
+
const wizardState = this.stateManager.getWizardState();
|
|
4728
|
+
if (wizardState && previousWizardState.totalSteps === wizardState.totalSteps) {
|
|
4729
|
+
if (previousWizardState.currentStep >= 0 && previousWizardState.currentStep < wizardState.totalSteps) {
|
|
4730
|
+
this.stateManager.goToStep(previousWizardState.currentStep);
|
|
4731
|
+
}
|
|
4732
|
+
for (const completedStep of previousWizardState.completedSteps) {
|
|
4733
|
+
if (completedStep >= 0 && completedStep < wizardState.totalSteps) {
|
|
4734
|
+
this.stateManager.completeStep(completedStep);
|
|
4735
|
+
}
|
|
4736
|
+
}
|
|
4737
|
+
}
|
|
4738
|
+
}
|
|
4739
|
+
}
|
|
4740
|
+
const finalWizardState = this.stateManager.getWizardState();
|
|
4613
4741
|
const newFormElement = document.createElement("form");
|
|
4614
4742
|
newFormElement.addEventListener("submit", (e) => this.handleSubmit(e));
|
|
4615
|
-
if (
|
|
4616
|
-
|
|
4743
|
+
if (this.disabled || this.loading) {
|
|
4744
|
+
newFormElement.classList.add("easy-form-disabled");
|
|
4745
|
+
}
|
|
4746
|
+
if (finalWizardState) {
|
|
4747
|
+
this.renderWizard(newFormElement);
|
|
4617
4748
|
} else {
|
|
4618
4749
|
this.renderFields(newFormElement, schema.fields || []);
|
|
4750
|
+
const submitButton = document.createElement("button");
|
|
4751
|
+
submitButton.type = "submit";
|
|
4752
|
+
submitButton.textContent = "Enviar";
|
|
4753
|
+
submitButton.className = "easy-form-submit";
|
|
4754
|
+
if (this.disabled || this.loading) {
|
|
4755
|
+
submitButton.disabled = true;
|
|
4756
|
+
}
|
|
4757
|
+
newFormElement.appendChild(submitButton);
|
|
4619
4758
|
}
|
|
4620
|
-
const submitButton = document.createElement("button");
|
|
4621
|
-
submitButton.type = "submit";
|
|
4622
|
-
submitButton.textContent = "Enviar";
|
|
4623
|
-
submitButton.className = "easy-form-submit";
|
|
4624
|
-
newFormElement.appendChild(submitButton);
|
|
4625
4759
|
const oldForm = this.shadow.querySelector("form");
|
|
4626
4760
|
if (oldForm && oldForm.parentNode === this.shadow && oldForm !== newFormElement) {
|
|
4627
4761
|
try {
|
|
@@ -4631,10 +4765,33 @@ var EasyForm = class extends BrowserHTMLElement {
|
|
|
4631
4765
|
}
|
|
4632
4766
|
}
|
|
4633
4767
|
this.shadow.appendChild(newFormElement);
|
|
4768
|
+
if (this.loading) {
|
|
4769
|
+
this.updateLoadingOverlay(newFormElement);
|
|
4770
|
+
}
|
|
4634
4771
|
} finally {
|
|
4635
4772
|
this.isRendering = false;
|
|
4636
4773
|
}
|
|
4637
4774
|
}
|
|
4775
|
+
/**
|
|
4776
|
+
* Actualiza el overlay de loading sobre el formulario
|
|
4777
|
+
*/
|
|
4778
|
+
updateLoadingOverlay(formElement) {
|
|
4779
|
+
const existingOverlay = this.shadow.querySelector(".easy-form-loading-overlay");
|
|
4780
|
+
if (existingOverlay) {
|
|
4781
|
+
existingOverlay.remove();
|
|
4782
|
+
}
|
|
4783
|
+
if (this.loading) {
|
|
4784
|
+
const form = formElement || this.shadow.querySelector("form");
|
|
4785
|
+
if (form) {
|
|
4786
|
+
const overlay = document.createElement("div");
|
|
4787
|
+
overlay.className = "easy-form-loading-overlay";
|
|
4788
|
+
const spinner = document.createElement("div");
|
|
4789
|
+
spinner.className = "easy-form-loading-spinner";
|
|
4790
|
+
overlay.appendChild(spinner);
|
|
4791
|
+
form.appendChild(overlay);
|
|
4792
|
+
}
|
|
4793
|
+
}
|
|
4794
|
+
}
|
|
4638
4795
|
/**
|
|
4639
4796
|
* Preserva los valores actuales del DOM antes de re-renderizar
|
|
4640
4797
|
* Retorna un objeto con los valores preservados
|
|
@@ -4743,9 +4900,10 @@ var EasyForm = class extends BrowserHTMLElement {
|
|
|
4743
4900
|
const value = this.stateManager.getValue(field.name);
|
|
4744
4901
|
const errors = this.stateManager.getErrors(field.name);
|
|
4745
4902
|
const error = errors.length > 0 ? errors[0] : void 0;
|
|
4903
|
+
const isFormDisabled = this.disabled || this.loading;
|
|
4746
4904
|
const fieldWithDependencies = {
|
|
4747
4905
|
...field,
|
|
4748
|
-
disabled: !isEnabled || field.disabled
|
|
4906
|
+
disabled: isFormDisabled || !isEnabled || field.disabled
|
|
4749
4907
|
};
|
|
4750
4908
|
const customComponent = getCustomComponent(field.type);
|
|
4751
4909
|
if (customComponent) {
|
|
@@ -4866,11 +5024,15 @@ var EasyForm = class extends BrowserHTMLElement {
|
|
|
4866
5024
|
removeButton.type = "button";
|
|
4867
5025
|
removeButton.textContent = "Eliminar";
|
|
4868
5026
|
removeButton.className = "easy-form-array-remove";
|
|
4869
|
-
|
|
4870
|
-
|
|
4871
|
-
|
|
4872
|
-
|
|
4873
|
-
|
|
5027
|
+
if (this.disabled || this.loading) {
|
|
5028
|
+
removeButton.disabled = true;
|
|
5029
|
+
} else {
|
|
5030
|
+
removeButton.addEventListener("click", () => {
|
|
5031
|
+
const newValues = [...values];
|
|
5032
|
+
newValues.splice(i, 1);
|
|
5033
|
+
this.handleFieldChange(field.name, newValues);
|
|
5034
|
+
});
|
|
5035
|
+
}
|
|
4874
5036
|
itemContainer.appendChild(removeButton);
|
|
4875
5037
|
itemsContainer.appendChild(itemContainer);
|
|
4876
5038
|
}
|
|
@@ -4879,10 +5041,14 @@ var EasyForm = class extends BrowserHTMLElement {
|
|
|
4879
5041
|
addButton.type = "button";
|
|
4880
5042
|
addButton.textContent = "Agregar";
|
|
4881
5043
|
addButton.className = "easy-form-array-add";
|
|
4882
|
-
|
|
4883
|
-
|
|
4884
|
-
|
|
4885
|
-
|
|
5044
|
+
if (this.disabled || this.loading) {
|
|
5045
|
+
addButton.disabled = true;
|
|
5046
|
+
} else {
|
|
5047
|
+
addButton.addEventListener("click", () => {
|
|
5048
|
+
const newValues = [...values, {}];
|
|
5049
|
+
this.handleFieldChange(field.name, newValues);
|
|
5050
|
+
});
|
|
5051
|
+
}
|
|
4886
5052
|
arrayContainer.appendChild(addButton);
|
|
4887
5053
|
return arrayContainer;
|
|
4888
5054
|
}
|
|
@@ -4910,7 +5076,9 @@ var EasyForm = class extends BrowserHTMLElement {
|
|
|
4910
5076
|
/**
|
|
4911
5077
|
* Renderiza wizard
|
|
4912
5078
|
*/
|
|
4913
|
-
renderWizard(container
|
|
5079
|
+
renderWizard(container) {
|
|
5080
|
+
const wizardState = this.stateManager.getWizardState();
|
|
5081
|
+
if (!wizardState) return;
|
|
4914
5082
|
const wizardContainer = document.createElement("div");
|
|
4915
5083
|
wizardContainer.className = "easy-form-wizard";
|
|
4916
5084
|
const stepsIndicator = document.createElement("div");
|
|
@@ -4943,43 +5111,95 @@ var EasyForm = class extends BrowserHTMLElement {
|
|
|
4943
5111
|
wizardContainer.appendChild(fieldsContainer);
|
|
4944
5112
|
const navContainer = document.createElement("div");
|
|
4945
5113
|
navContainer.className = "easy-form-wizard-nav";
|
|
4946
|
-
|
|
4947
|
-
|
|
4948
|
-
|
|
4949
|
-
|
|
4950
|
-
|
|
4951
|
-
|
|
4952
|
-
|
|
4953
|
-
this.render();
|
|
4954
|
-
this.emitStepChange();
|
|
4955
|
-
}
|
|
4956
|
-
});
|
|
4957
|
-
navContainer.appendChild(prevButton);
|
|
4958
|
-
const nextButton = document.createElement("button");
|
|
4959
|
-
nextButton.type = "button";
|
|
4960
|
-
nextButton.textContent = wizardState.currentStep === wizardState.totalSteps - 1 ? "Enviar" : "Siguiente";
|
|
4961
|
-
nextButton.className = "easy-form-wizard-next";
|
|
4962
|
-
nextButton.addEventListener("click", async () => {
|
|
4963
|
-
if (wizardState.currentStep === wizardState.totalSteps - 1) {
|
|
4964
|
-
await this.handleSubmit(new Event("submit"));
|
|
5114
|
+
if (wizardState.currentStep > 0) {
|
|
5115
|
+
const prevButton = document.createElement("button");
|
|
5116
|
+
prevButton.type = "button";
|
|
5117
|
+
prevButton.textContent = "Anterior";
|
|
5118
|
+
prevButton.className = "easy-form-wizard-prev";
|
|
5119
|
+
if (this.disabled || this.loading) {
|
|
5120
|
+
prevButton.disabled = true;
|
|
4965
5121
|
} else {
|
|
4966
|
-
|
|
4967
|
-
|
|
4968
|
-
|
|
4969
|
-
(f) => errors[f.name] && errors[f.name].length > 0
|
|
4970
|
-
);
|
|
4971
|
-
if (!hasErrors) {
|
|
4972
|
-
this.stateManager.completeStep(wizardState.currentStep);
|
|
4973
|
-
if (this.stateManager.nextStep()) {
|
|
5122
|
+
prevButton.addEventListener("click", () => {
|
|
5123
|
+
const currentState = this.stateManager.getWizardState();
|
|
5124
|
+
if (currentState && this.stateManager.previousStep()) {
|
|
4974
5125
|
this.render();
|
|
4975
5126
|
this.emitStepChange();
|
|
4976
5127
|
}
|
|
4977
|
-
}
|
|
4978
|
-
this.emitError(errors);
|
|
4979
|
-
}
|
|
5128
|
+
});
|
|
4980
5129
|
}
|
|
4981
|
-
|
|
4982
|
-
|
|
5130
|
+
navContainer.appendChild(prevButton);
|
|
5131
|
+
}
|
|
5132
|
+
if (wizardState.currentStep < wizardState.totalSteps - 1) {
|
|
5133
|
+
const nextButton = document.createElement("button");
|
|
5134
|
+
nextButton.type = "button";
|
|
5135
|
+
nextButton.textContent = "Siguiente";
|
|
5136
|
+
nextButton.className = "easy-form-wizard-next";
|
|
5137
|
+
if (this.disabled || this.loading) {
|
|
5138
|
+
nextButton.disabled = true;
|
|
5139
|
+
} else {
|
|
5140
|
+
nextButton.addEventListener("click", async () => {
|
|
5141
|
+
const currentState = this.stateManager.getWizardState();
|
|
5142
|
+
if (!currentState) return;
|
|
5143
|
+
const currentFields2 = this.stateManager.getCurrentStepFields();
|
|
5144
|
+
for (const field of currentFields2) {
|
|
5145
|
+
if (this.stateManager.getFieldVisibility(field.name)) {
|
|
5146
|
+
await this.stateManager.validateField(field.name);
|
|
5147
|
+
}
|
|
5148
|
+
}
|
|
5149
|
+
const allErrors = this.stateManager.getAllErrors();
|
|
5150
|
+
const stepErrors = {};
|
|
5151
|
+
for (const field of currentFields2) {
|
|
5152
|
+
if (allErrors[field.name] && allErrors[field.name].length > 0) {
|
|
5153
|
+
stepErrors[field.name] = allErrors[field.name];
|
|
5154
|
+
}
|
|
5155
|
+
}
|
|
5156
|
+
const hasErrors = Object.keys(stepErrors).length > 0;
|
|
5157
|
+
if (!hasErrors) {
|
|
5158
|
+
this.stateManager.completeStep(currentState.currentStep);
|
|
5159
|
+
const moved = this.stateManager.nextStep();
|
|
5160
|
+
if (moved) {
|
|
5161
|
+
this.render();
|
|
5162
|
+
this.emitStepChange();
|
|
5163
|
+
}
|
|
5164
|
+
} else {
|
|
5165
|
+
this.emitError(stepErrors);
|
|
5166
|
+
}
|
|
5167
|
+
});
|
|
5168
|
+
}
|
|
5169
|
+
navContainer.appendChild(nextButton);
|
|
5170
|
+
}
|
|
5171
|
+
if (wizardState.currentStep === wizardState.totalSteps - 1) {
|
|
5172
|
+
const submitButton = document.createElement("button");
|
|
5173
|
+
submitButton.type = "button";
|
|
5174
|
+
submitButton.textContent = "Enviar";
|
|
5175
|
+
submitButton.className = "easy-form-wizard-next";
|
|
5176
|
+
if (this.disabled || this.loading) {
|
|
5177
|
+
submitButton.disabled = true;
|
|
5178
|
+
} else {
|
|
5179
|
+
submitButton.addEventListener("click", async () => {
|
|
5180
|
+
const currentFields2 = this.stateManager.getCurrentStepFields();
|
|
5181
|
+
for (const field of currentFields2) {
|
|
5182
|
+
if (this.stateManager.getFieldVisibility(field.name)) {
|
|
5183
|
+
await this.stateManager.validateField(field.name);
|
|
5184
|
+
}
|
|
5185
|
+
}
|
|
5186
|
+
const allErrors = this.stateManager.getAllErrors();
|
|
5187
|
+
const stepErrors = {};
|
|
5188
|
+
for (const field of currentFields2) {
|
|
5189
|
+
if (allErrors[field.name] && allErrors[field.name].length > 0) {
|
|
5190
|
+
stepErrors[field.name] = allErrors[field.name];
|
|
5191
|
+
}
|
|
5192
|
+
}
|
|
5193
|
+
const hasErrors = Object.keys(stepErrors).length > 0;
|
|
5194
|
+
if (!hasErrors) {
|
|
5195
|
+
await this.handleSubmit(new Event("submit"));
|
|
5196
|
+
} else {
|
|
5197
|
+
this.emitError(stepErrors);
|
|
5198
|
+
}
|
|
5199
|
+
});
|
|
5200
|
+
}
|
|
5201
|
+
navContainer.appendChild(submitButton);
|
|
5202
|
+
}
|
|
4983
5203
|
wizardContainer.appendChild(navContainer);
|
|
4984
5204
|
container.appendChild(wizardContainer);
|
|
4985
5205
|
}
|
|
@@ -5324,6 +5544,38 @@ var EasyForm = class extends BrowserHTMLElement {
|
|
|
5324
5544
|
this.removeAttribute("initialData");
|
|
5325
5545
|
}
|
|
5326
5546
|
}
|
|
5547
|
+
/**
|
|
5548
|
+
* Obtiene el estado de loading
|
|
5549
|
+
*/
|
|
5550
|
+
get loading() {
|
|
5551
|
+
return this.hasAttribute("loading");
|
|
5552
|
+
}
|
|
5553
|
+
/**
|
|
5554
|
+
* Establece el estado de loading
|
|
5555
|
+
*/
|
|
5556
|
+
set loading(value) {
|
|
5557
|
+
if (value) {
|
|
5558
|
+
this.setAttribute("loading", "");
|
|
5559
|
+
} else {
|
|
5560
|
+
this.removeAttribute("loading");
|
|
5561
|
+
}
|
|
5562
|
+
}
|
|
5563
|
+
/**
|
|
5564
|
+
* Obtiene el estado de disabled
|
|
5565
|
+
*/
|
|
5566
|
+
get disabled() {
|
|
5567
|
+
return this.hasAttribute("disabled");
|
|
5568
|
+
}
|
|
5569
|
+
/**
|
|
5570
|
+
* Establece el estado de disabled
|
|
5571
|
+
*/
|
|
5572
|
+
set disabled(value) {
|
|
5573
|
+
if (value) {
|
|
5574
|
+
this.setAttribute("disabled", "");
|
|
5575
|
+
} else {
|
|
5576
|
+
this.removeAttribute("disabled");
|
|
5577
|
+
}
|
|
5578
|
+
}
|
|
5327
5579
|
/**
|
|
5328
5580
|
* Configura estilos básicos
|
|
5329
5581
|
*/
|