easy-forms-core 1.0.11 → 1.1.1

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/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;
@@ -1731,7 +1765,20 @@ var ValidationEngine = class {
1731
1765
  if (!value) {
1732
1766
  return { isValid: true };
1733
1767
  }
1734
- const regex = typeof pattern === "string" ? new RegExp(pattern) : pattern;
1768
+ let regex;
1769
+ if (pattern instanceof RegExp) {
1770
+ regex = pattern;
1771
+ } else if (typeof pattern === "string") {
1772
+ try {
1773
+ regex = new RegExp(pattern);
1774
+ } catch (e) {
1775
+ console.warn("Invalid regex pattern:", pattern);
1776
+ return { isValid: true };
1777
+ }
1778
+ } else {
1779
+ console.warn("Pattern validation expects string or RegExp, got:", typeof pattern, pattern);
1780
+ return { isValid: true };
1781
+ }
1735
1782
  const isValid = regex.test(String(value));
1736
1783
  return {
1737
1784
  isValid,
@@ -2019,6 +2066,26 @@ var StateManager = class {
2019
2066
  }
2020
2067
  return allFields;
2021
2068
  }
2069
+ /**
2070
+ * Encuentra el path completo de un campo dentro de grupos
2071
+ */
2072
+ findFieldPath(fieldName, fields, parentPath = "") {
2073
+ for (const field of fields) {
2074
+ const currentPath = parentPath ? `${parentPath}.${field.name}` : field.name;
2075
+ if (field.name === fieldName) {
2076
+ return currentPath;
2077
+ }
2078
+ if (field.type === "group" && "fields" in field) {
2079
+ const found = this.findFieldPath(fieldName, field.fields, currentPath);
2080
+ if (found) return found;
2081
+ }
2082
+ if (field.type === "row" && "fields" in field) {
2083
+ const found = this.findFieldPath(fieldName, field.fields, currentPath);
2084
+ if (found) return found;
2085
+ }
2086
+ }
2087
+ return null;
2088
+ }
2022
2089
  /**
2023
2090
  * Construye el mapa de dependencias para optimizar re-evaluaciones
2024
2091
  */
@@ -2201,6 +2268,7 @@ var StateManager = class {
2201
2268
  */
2202
2269
  setValueWithoutValidation(fieldName, value) {
2203
2270
  setNestedValue(this.state.values, fieldName, value);
2271
+ this.invalidateDependencyCache(fieldName);
2204
2272
  }
2205
2273
  /**
2206
2274
  * Valida un campo específico
@@ -2233,6 +2301,13 @@ var StateManager = class {
2233
2301
  */
2234
2302
  getActiveValidations(field) {
2235
2303
  let validations = [...field.validations || []];
2304
+ const isRequired = this.getFieldRequired(field.name);
2305
+ const hasRequiredValidation = validations.some((v) => v.type === "required");
2306
+ if (isRequired && !hasRequiredValidation) {
2307
+ validations = [{ type: "required" }, ...validations];
2308
+ } else if (!isRequired && hasRequiredValidation) {
2309
+ validations = validations.filter((v) => v.type !== "required");
2310
+ }
2236
2311
  if (field.conditionalValidations) {
2237
2312
  for (const conditional of field.conditionalValidations) {
2238
2313
  const conditionMet = this.conditionEngine.evaluateConditions(
@@ -2365,13 +2440,41 @@ var StateManager = class {
2365
2440
  if (!this.schema) return true;
2366
2441
  const topLevelFields = this.schema.isWizard ? this.schema.steps.flatMap((step) => step.fields) : this.schema.fields || [];
2367
2442
  const allFields = this.extractAllFields(topLevelFields);
2368
- const field = allFields.find((f) => f.name === fieldName);
2443
+ let field = allFields.find((f) => {
2444
+ const fullPath = this.findFieldPath(f.name, topLevelFields);
2445
+ return fullPath === fieldName || f.name === fieldName;
2446
+ });
2447
+ if (!field) {
2448
+ field = allFields.find((f) => f.name === fieldName);
2449
+ }
2369
2450
  if (!field || !field.dependencies) {
2370
2451
  return !field?.hidden;
2371
2452
  }
2453
+ const fieldFullPath = this.findFieldPath(field.name, topLevelFields) || field.name;
2454
+ const groupPath = fieldFullPath.includes(".") ? fieldFullPath.split(".").slice(0, -1).join(".") : "";
2455
+ let valuesContext = { ...this.state.values };
2456
+ if (groupPath && field.dependencies) {
2457
+ const groupValues = getNestedValue(this.state.values, groupPath);
2458
+ if (groupValues && typeof groupValues === "object") {
2459
+ const createRelativeContext = (obj, prefix = "") => {
2460
+ const result2 = {};
2461
+ for (const [key, value] of Object.entries(obj)) {
2462
+ const relativeKey = prefix ? `${prefix}.${key}` : key;
2463
+ if (value && typeof value === "object" && !Array.isArray(value) && value !== null) {
2464
+ Object.assign(result2, createRelativeContext(value, relativeKey));
2465
+ } else {
2466
+ result2[relativeKey] = value;
2467
+ }
2468
+ }
2469
+ return result2;
2470
+ };
2471
+ const relativeContext = createRelativeContext(groupValues);
2472
+ valuesContext = { ...this.state.values, ...relativeContext };
2473
+ }
2474
+ }
2372
2475
  const result = this.conditionEngine.evaluateDependencies(
2373
2476
  field.dependencies,
2374
- this.state.values
2477
+ valuesContext
2375
2478
  );
2376
2479
  this.dependencyCache.set(fieldName, result);
2377
2480
  return result.visible && !field.hidden;
@@ -2446,7 +2549,15 @@ var BaseInput = class {
2446
2549
  */
2447
2550
  createFieldContainer(input) {
2448
2551
  const container = document.createElement("div");
2449
- container.className = "easy-form-field";
2552
+ const inputClasses = Array.from(input.classList);
2553
+ const componentContainerClasses = inputClasses.filter(
2554
+ (cls) => cls.startsWith("easy-form-") && cls !== "easy-form-field" && (cls.includes("-container") || cls.includes("-wrapper"))
2555
+ );
2556
+ if (componentContainerClasses.length > 0) {
2557
+ container.className = `easy-form-field ${componentContainerClasses.join(" ")}`;
2558
+ } else {
2559
+ container.className = "easy-form-field";
2560
+ }
2450
2561
  if (this.field.label) {
2451
2562
  const label = document.createElement("label");
2452
2563
  label.className = "easy-form-label";
@@ -2693,7 +2804,18 @@ var MaskEngine = class {
2693
2804
  return value;
2694
2805
  }
2695
2806
  const customMask = this.getCustomMask(mask);
2696
- const unformatted = this.removeMask(value, mask);
2807
+ const editableTokens = tokens.filter((t) => t.editable);
2808
+ const acceptedTypes = new Set(editableTokens.map((t) => t.type));
2809
+ let unformatted = "";
2810
+ for (const char of value) {
2811
+ if (acceptedTypes.has("any")) {
2812
+ unformatted += char;
2813
+ } else if (acceptedTypes.has("digit") && /\d/.test(char)) {
2814
+ unformatted += char;
2815
+ } else if (acceptedTypes.has("letter") && /[a-zA-Z]/.test(char)) {
2816
+ unformatted += char;
2817
+ }
2818
+ }
2697
2819
  let formatted = formatValue(unformatted, tokens);
2698
2820
  if (customMask.transform) {
2699
2821
  formatted = customMask.transform(formatted);
@@ -2828,7 +2950,9 @@ var TextInput = class extends BaseInput {
2828
2950
  }
2829
2951
  input.value = displayValue;
2830
2952
  this.applyCommonProps(input);
2831
- if (this.maskEngine && this.field.mask && !this.field.placeholder) {
2953
+ if (this.field.placeholder) {
2954
+ input.placeholder = this.field.placeholder;
2955
+ } else if (this.maskEngine && this.field.mask) {
2832
2956
  const maskPlaceholder = this.maskEngine.getMaskPlaceholder(this.field.mask);
2833
2957
  if (maskPlaceholder) {
2834
2958
  input.placeholder = maskPlaceholder;
@@ -2940,7 +3064,6 @@ var NumberInput = class extends BaseInput {
2940
3064
  input.type = "number";
2941
3065
  input.value = this.value ?? "";
2942
3066
  }
2943
- input.placeholder = this.field.placeholder || "";
2944
3067
  const numberField = this.field;
2945
3068
  if (!this.maskEngine && input.type === "number") {
2946
3069
  if (numberField.min !== void 0) {
@@ -2954,7 +3077,9 @@ var NumberInput = class extends BaseInput {
2954
3077
  }
2955
3078
  }
2956
3079
  this.applyCommonProps(input);
2957
- if (this.maskEngine && this.field.mask && !this.field.placeholder) {
3080
+ if (this.field.placeholder) {
3081
+ input.placeholder = this.field.placeholder;
3082
+ } else if (this.maskEngine && this.field.mask) {
2958
3083
  const maskPlaceholder = this.maskEngine.getMaskPlaceholder(this.field.mask);
2959
3084
  if (maskPlaceholder) {
2960
3085
  input.placeholder = maskPlaceholder;
@@ -4524,26 +4649,45 @@ var EasyForm = class extends BrowserHTMLElement {
4524
4649
  return;
4525
4650
  }
4526
4651
  const preservedValues = this.preserveCurrentValues();
4652
+ const previousWizardState = this.stateManager.getWizardState();
4527
4653
  if (preservedValues && Object.keys(preservedValues).length > 0) {
4528
4654
  for (const [key, value] of Object.entries(preservedValues)) {
4529
4655
  this.stateManager.setValueWithoutValidation(key, value);
4530
4656
  }
4531
4657
  }
4532
4658
  const initialData = this.initialData;
4533
- this.stateManager.initializeSchema(schema, initialData || void 0);
4534
- const wizardState = this.stateManager.getWizardState();
4659
+ const wasWizard = previousWizardState !== null;
4660
+ const isWizard = schema.steps && schema.steps.length > 0;
4661
+ const shouldReinitialize = !previousWizardState || !wasWizard || !isWizard || previousWizardState && schema.steps && previousWizardState.totalSteps !== schema.steps.length;
4662
+ if (shouldReinitialize) {
4663
+ this.stateManager.initializeSchema(schema, initialData || void 0);
4664
+ if (wasWizard && isWizard && previousWizardState) {
4665
+ const wizardState = this.stateManager.getWizardState();
4666
+ if (wizardState && previousWizardState.totalSteps === wizardState.totalSteps) {
4667
+ if (previousWizardState.currentStep >= 0 && previousWizardState.currentStep < wizardState.totalSteps) {
4668
+ this.stateManager.goToStep(previousWizardState.currentStep);
4669
+ }
4670
+ for (const completedStep of previousWizardState.completedSteps) {
4671
+ if (completedStep >= 0 && completedStep < wizardState.totalSteps) {
4672
+ this.stateManager.completeStep(completedStep);
4673
+ }
4674
+ }
4675
+ }
4676
+ }
4677
+ }
4678
+ const finalWizardState = this.stateManager.getWizardState();
4535
4679
  const newFormElement = document.createElement("form");
4536
4680
  newFormElement.addEventListener("submit", (e) => this.handleSubmit(e));
4537
- if (wizardState) {
4538
- this.renderWizard(newFormElement, wizardState);
4681
+ if (finalWizardState) {
4682
+ this.renderWizard(newFormElement);
4539
4683
  } else {
4540
4684
  this.renderFields(newFormElement, schema.fields || []);
4685
+ const submitButton = document.createElement("button");
4686
+ submitButton.type = "submit";
4687
+ submitButton.textContent = "Enviar";
4688
+ submitButton.className = "easy-form-submit";
4689
+ newFormElement.appendChild(submitButton);
4541
4690
  }
4542
- const submitButton = document.createElement("button");
4543
- submitButton.type = "submit";
4544
- submitButton.textContent = "Enviar";
4545
- submitButton.className = "easy-form-submit";
4546
- newFormElement.appendChild(submitButton);
4547
4691
  const oldForm = this.shadow.querySelector("form");
4548
4692
  if (oldForm && oldForm.parentNode === this.shadow && oldForm !== newFormElement) {
4549
4693
  try {
@@ -4832,7 +4976,9 @@ var EasyForm = class extends BrowserHTMLElement {
4832
4976
  /**
4833
4977
  * Renderiza wizard
4834
4978
  */
4835
- renderWizard(container, wizardState) {
4979
+ renderWizard(container) {
4980
+ const wizardState = this.stateManager.getWizardState();
4981
+ if (!wizardState) return;
4836
4982
  const wizardContainer = document.createElement("div");
4837
4983
  wizardContainer.className = "easy-form-wizard";
4838
4984
  const stepsIndicator = document.createElement("div");
@@ -4865,43 +5011,83 @@ var EasyForm = class extends BrowserHTMLElement {
4865
5011
  wizardContainer.appendChild(fieldsContainer);
4866
5012
  const navContainer = document.createElement("div");
4867
5013
  navContainer.className = "easy-form-wizard-nav";
4868
- const prevButton = document.createElement("button");
4869
- prevButton.type = "button";
4870
- prevButton.textContent = "Anterior";
4871
- prevButton.className = "easy-form-wizard-prev";
4872
- prevButton.disabled = wizardState.currentStep === 0;
4873
- prevButton.addEventListener("click", () => {
4874
- if (this.stateManager.previousStep()) {
4875
- this.render();
4876
- this.emitStepChange();
4877
- }
4878
- });
4879
- navContainer.appendChild(prevButton);
4880
- const nextButton = document.createElement("button");
4881
- nextButton.type = "button";
4882
- nextButton.textContent = wizardState.currentStep === wizardState.totalSteps - 1 ? "Enviar" : "Siguiente";
4883
- nextButton.className = "easy-form-wizard-next";
4884
- nextButton.addEventListener("click", async () => {
4885
- if (wizardState.currentStep === wizardState.totalSteps - 1) {
4886
- await this.handleSubmit(new Event("submit"));
4887
- } else {
5014
+ if (wizardState.currentStep > 0) {
5015
+ const prevButton = document.createElement("button");
5016
+ prevButton.type = "button";
5017
+ prevButton.textContent = "Anterior";
5018
+ prevButton.className = "easy-form-wizard-prev";
5019
+ prevButton.addEventListener("click", () => {
5020
+ const currentState = this.stateManager.getWizardState();
5021
+ if (currentState && this.stateManager.previousStep()) {
5022
+ this.render();
5023
+ this.emitStepChange();
5024
+ }
5025
+ });
5026
+ navContainer.appendChild(prevButton);
5027
+ }
5028
+ if (wizardState.currentStep < wizardState.totalSteps - 1) {
5029
+ const nextButton = document.createElement("button");
5030
+ nextButton.type = "button";
5031
+ nextButton.textContent = "Siguiente";
5032
+ nextButton.className = "easy-form-wizard-next";
5033
+ nextButton.addEventListener("click", async () => {
5034
+ const currentState = this.stateManager.getWizardState();
5035
+ if (!currentState) return;
4888
5036
  const currentFields2 = this.stateManager.getCurrentStepFields();
4889
- const errors = await this.stateManager.validateForm();
4890
- const hasErrors = currentFields2.some(
4891
- (f) => errors[f.name] && errors[f.name].length > 0
4892
- );
5037
+ for (const field of currentFields2) {
5038
+ if (this.stateManager.getFieldVisibility(field.name)) {
5039
+ await this.stateManager.validateField(field.name);
5040
+ }
5041
+ }
5042
+ const allErrors = this.stateManager.getAllErrors();
5043
+ const stepErrors = {};
5044
+ for (const field of currentFields2) {
5045
+ if (allErrors[field.name] && allErrors[field.name].length > 0) {
5046
+ stepErrors[field.name] = allErrors[field.name];
5047
+ }
5048
+ }
5049
+ const hasErrors = Object.keys(stepErrors).length > 0;
4893
5050
  if (!hasErrors) {
4894
- this.stateManager.completeStep(wizardState.currentStep);
4895
- if (this.stateManager.nextStep()) {
5051
+ this.stateManager.completeStep(currentState.currentStep);
5052
+ const moved = this.stateManager.nextStep();
5053
+ if (moved) {
4896
5054
  this.render();
4897
5055
  this.emitStepChange();
4898
5056
  }
4899
5057
  } else {
4900
- this.emitError(errors);
5058
+ this.emitError(stepErrors);
4901
5059
  }
4902
- }
4903
- });
4904
- navContainer.appendChild(nextButton);
5060
+ });
5061
+ navContainer.appendChild(nextButton);
5062
+ }
5063
+ if (wizardState.currentStep === wizardState.totalSteps - 1) {
5064
+ const submitButton = document.createElement("button");
5065
+ submitButton.type = "button";
5066
+ submitButton.textContent = "Enviar";
5067
+ submitButton.className = "easy-form-wizard-next";
5068
+ submitButton.addEventListener("click", async () => {
5069
+ const currentFields2 = this.stateManager.getCurrentStepFields();
5070
+ for (const field of currentFields2) {
5071
+ if (this.stateManager.getFieldVisibility(field.name)) {
5072
+ await this.stateManager.validateField(field.name);
5073
+ }
5074
+ }
5075
+ const allErrors = this.stateManager.getAllErrors();
5076
+ const stepErrors = {};
5077
+ for (const field of currentFields2) {
5078
+ if (allErrors[field.name] && allErrors[field.name].length > 0) {
5079
+ stepErrors[field.name] = allErrors[field.name];
5080
+ }
5081
+ }
5082
+ const hasErrors = Object.keys(stepErrors).length > 0;
5083
+ if (!hasErrors) {
5084
+ await this.handleSubmit(new Event("submit"));
5085
+ } else {
5086
+ this.emitError(stepErrors);
5087
+ }
5088
+ });
5089
+ navContainer.appendChild(submitButton);
5090
+ }
4905
5091
  wizardContainer.appendChild(navContainer);
4906
5092
  container.appendChild(wizardContainer);
4907
5093
  }