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 CHANGED
@@ -1,6 +1,6 @@
1
- # EasyForms
1
+ # EasyFormsCore
2
2
 
3
- EasyForms es una librería agnóstica de framework para construir formularios dinámicos a partir de JSON usando Web Components.
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
@@ -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: 1rem;
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
- const regex = typeof pattern === "string" ? new RegExp(pattern) : pattern;
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
- this.stateManager.initializeSchema(schema, initialData || void 0);
4612
- const wizardState = this.stateManager.getWizardState();
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 (wizardState) {
4616
- this.renderWizard(newFormElement, wizardState);
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
- removeButton.addEventListener("click", () => {
4870
- const newValues = [...values];
4871
- newValues.splice(i, 1);
4872
- this.handleFieldChange(field.name, newValues);
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
- addButton.addEventListener("click", () => {
4883
- const newValues = [...values, {}];
4884
- this.handleFieldChange(field.name, newValues);
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, wizardState) {
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
- const prevButton = document.createElement("button");
4947
- prevButton.type = "button";
4948
- prevButton.textContent = "Anterior";
4949
- prevButton.className = "easy-form-wizard-prev";
4950
- prevButton.disabled = wizardState.currentStep === 0;
4951
- prevButton.addEventListener("click", () => {
4952
- if (this.stateManager.previousStep()) {
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
- const currentFields2 = this.stateManager.getCurrentStepFields();
4967
- const errors = await this.stateManager.validateForm();
4968
- const hasErrors = currentFields2.some(
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
- } else {
4978
- this.emitError(errors);
4979
- }
5128
+ });
4980
5129
  }
4981
- });
4982
- navContainer.appendChild(nextButton);
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
  */