form-builder-pro 1.2.7 → 1.2.9

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/index.mjs CHANGED
@@ -4119,7 +4119,8 @@ var FIELD_TYPES = [
4119
4119
  { type: "checkbox", label: "Checkbox", icon: "CheckSquare" },
4120
4120
  { type: "radio", label: "Radio Group", icon: "CircleDot" },
4121
4121
  { type: "toggle", label: "Toggle", icon: "ToggleSwitch" },
4122
- { type: "file", label: "File Upload", icon: "Upload" }
4122
+ { type: "file", label: "File Upload", icon: "Upload" },
4123
+ { type: "image", label: "Image", icon: "Image" }
4123
4124
  ];
4124
4125
  var DEFAULT_FIELD_CONFIG = {
4125
4126
  text: { label: "Text Input", placeholder: "Enter text...", width: "100%", enabled: true, visible: true },
@@ -4145,7 +4146,39 @@ var DEFAULT_FIELD_CONFIG = {
4145
4146
  checkbox: { label: "Checkbox", options: [], width: "100%", enabled: true, visible: true },
4146
4147
  radio: { label: "Radio Group", options: [], width: "100%", enabled: true, visible: true },
4147
4148
  toggle: { label: "Toggle", width: "50%", enabled: true, visible: true },
4148
- file: { label: "File Upload", width: "100%", enabled: true, visible: true }
4149
+ file: { label: "File Upload", width: "100%", enabled: true, visible: true },
4150
+ image: { label: "Image", width: "50%", enabled: true, visible: true }
4151
+ };
4152
+ var VALIDATION_TYPE_PRESETS = {
4153
+ postalCode: {
4154
+ pattern: "^[0-9]{6}$",
4155
+ minLength: 6,
4156
+ maxLength: 6,
4157
+ validationType: "postalCode",
4158
+ customErrorMessages: { pattern: "Please enter a valid 6-digit postal code" }
4159
+ },
4160
+ phoneNumber: {
4161
+ pattern: "^[6-9][0-9]{9}$",
4162
+ minLength: 10,
4163
+ maxLength: 10,
4164
+ validationType: "phoneNumber",
4165
+ customErrorMessages: { pattern: "Please enter a valid 10-digit mobile number starting with 6-9" }
4166
+ },
4167
+ otp: {
4168
+ pattern: "^[0-9]{4,6}$",
4169
+ minLength: 4,
4170
+ maxLength: 6,
4171
+ validationType: "otp",
4172
+ customErrorMessages: { pattern: "Please enter a valid OTP (4-6 digits)" }
4173
+ },
4174
+ amount: {
4175
+ min: 0,
4176
+ allowDecimal: true,
4177
+ decimalPlaces: 2,
4178
+ allowNegative: false,
4179
+ validationType: "amount",
4180
+ customErrorMessages: { min: "Amount must be at least 0" }
4181
+ }
4149
4182
  };
4150
4183
  var REGEX_PRESETS = [
4151
4184
  {
@@ -4271,11 +4304,72 @@ var cloneField = (field) => {
4271
4304
  id: generateId(),
4272
4305
  // Ensure options are also cloned if present
4273
4306
  options: field.options ? field.options.map((opt) => ({ ...opt })) : void 0,
4274
- validation: field.validation ? field.validation.map((v) => ({ ...v })) : void 0
4307
+ validation: field.validation ? field.validation.map((v) => ({ ...v })) : void 0,
4308
+ // Preserve formula config for number fields (dependencies stay as-is - they reference other field ids/names)
4309
+ valueSource: field.valueSource,
4310
+ formula: field.formula,
4311
+ dependencies: field.dependencies ? [...field.dependencies] : void 0
4275
4312
  };
4276
4313
  };
4277
4314
 
4278
4315
  // src/utils/mapper.ts
4316
+ function validationsToValidationObject(v) {
4317
+ if (!v)
4318
+ return void 0;
4319
+ const obj = {};
4320
+ if (v.required !== void 0)
4321
+ obj.required = v.required;
4322
+ if (v.pattern)
4323
+ obj.regex = v.pattern;
4324
+ if (v.minLength !== void 0)
4325
+ obj.minLength = v.minLength;
4326
+ if (v.maxLength !== void 0)
4327
+ obj.maxLength = v.maxLength;
4328
+ if (v.min !== void 0)
4329
+ obj.min = v.min;
4330
+ if (v.max !== void 0)
4331
+ obj.max = v.max;
4332
+ if (v.customErrorMessages?.pattern)
4333
+ obj.regexMessage = v.customErrorMessages.pattern;
4334
+ if (v.minSelected !== void 0)
4335
+ obj.minSelected = v.minSelected;
4336
+ if (v.maxSelected !== void 0)
4337
+ obj.maxSelected = v.maxSelected;
4338
+ if (v.minDate)
4339
+ obj.minDate = v.minDate;
4340
+ if (v.maxDate)
4341
+ obj.maxDate = v.maxDate;
4342
+ return Object.keys(obj).length > 0 ? obj : void 0;
4343
+ }
4344
+ function validationObjectToValidations(v) {
4345
+ if (!v)
4346
+ return void 0;
4347
+ const validations = {};
4348
+ if (v.required !== void 0)
4349
+ validations.required = v.required;
4350
+ if (v.regex)
4351
+ validations.pattern = v.regex;
4352
+ if (v.minLength !== void 0)
4353
+ validations.minLength = v.minLength;
4354
+ if (v.maxLength !== void 0)
4355
+ validations.maxLength = v.maxLength;
4356
+ if (v.min !== void 0)
4357
+ validations.min = v.min;
4358
+ if (v.max !== void 0)
4359
+ validations.max = v.max;
4360
+ if (v.regexMessage) {
4361
+ validations.customErrorMessages = { pattern: v.regexMessage };
4362
+ }
4363
+ if (v.minSelected !== void 0)
4364
+ validations.minSelected = v.minSelected;
4365
+ if (v.maxSelected !== void 0)
4366
+ validations.maxSelected = v.maxSelected;
4367
+ if (v.minDate)
4368
+ validations.minDate = v.minDate;
4369
+ if (v.maxDate)
4370
+ validations.maxDate = v.maxDate;
4371
+ return Object.keys(validations).length > 0 ? validations : void 0;
4372
+ }
4279
4373
  function convertValidationObjectToArray(validationObj) {
4280
4374
  if (!validationObj)
4281
4375
  return [];
@@ -4284,7 +4378,7 @@ function convertValidationObjectToArray(validationObj) {
4284
4378
  }
4285
4379
  const rules = [];
4286
4380
  const obj = validationObj;
4287
- const hasValidationProperties = !!(obj.regex || obj.regexMessage || obj.minLength !== void 0 || obj.maxLength !== void 0 || obj.minSelected !== void 0 || obj.maxSelected !== void 0);
4381
+ const hasValidationProperties = !!(obj.regex || obj.regexMessage || obj.minLength !== void 0 || obj.maxLength !== void 0 || obj.min !== void 0 || obj.max !== void 0 || obj.minSelected !== void 0 || obj.maxSelected !== void 0);
4288
4382
  const isRequired = obj.required === true || hasValidationProperties && obj.required !== false;
4289
4383
  if (isRequired) {
4290
4384
  rules.push({ type: "required", value: true });
@@ -4302,6 +4396,12 @@ function convertValidationObjectToArray(validationObj) {
4302
4396
  if (obj.maxLength !== void 0) {
4303
4397
  rules.push({ type: "maxLength", value: obj.maxLength });
4304
4398
  }
4399
+ if (obj.min !== void 0) {
4400
+ rules.push({ type: "min", value: obj.min });
4401
+ }
4402
+ if (obj.max !== void 0) {
4403
+ rules.push({ type: "max", value: obj.max });
4404
+ }
4305
4405
  if (obj.minSelected !== void 0) {
4306
4406
  rules.push({ type: "minSelected", value: obj.minSelected });
4307
4407
  }
@@ -4319,10 +4419,12 @@ function convertSpanToWidth(span, totalColumns = 12) {
4319
4419
  function normalizeFieldType(type) {
4320
4420
  if (!type)
4321
4421
  return "text";
4322
- const normalized = String(type).toLowerCase();
4422
+ const normalized = String(type).toLowerCase().replace(/_/g, "");
4323
4423
  if (normalized === "decimal")
4324
4424
  return "number";
4325
- return normalized;
4425
+ if (["phonenumber", "telephone", "mobile"].includes(normalized))
4426
+ return "phone";
4427
+ return String(type).toLowerCase();
4326
4428
  }
4327
4429
  function transformField(field) {
4328
4430
  const fieldId = field.id || field.fieldId;
@@ -4373,7 +4475,15 @@ function transformField(field) {
4373
4475
  if (transformed.order === void 0) {
4374
4476
  transformed.order = field.order !== void 0 ? field.order : 0;
4375
4477
  }
4376
- if (field.validation) {
4478
+ if (field.validations) {
4479
+ let validations = field.validations;
4480
+ if (validations.validationType === "age") {
4481
+ validations = { ...validations, validationType: "custom" };
4482
+ }
4483
+ transformed.validations = validations;
4484
+ transformed.required = validations.required ?? false;
4485
+ transformed.validation = validationsToValidationObject(validations);
4486
+ } else if (field.validation) {
4377
4487
  if (Array.isArray(field.validation)) {
4378
4488
  const validationObj = {};
4379
4489
  field.validation.forEach((rule) => {
@@ -4386,6 +4496,10 @@ function transformField(field) {
4386
4496
  validationObj.minLength = rule.value;
4387
4497
  } else if (rule.type === "maxLength" && typeof rule.value === "number") {
4388
4498
  validationObj.maxLength = rule.value;
4499
+ } else if (rule.type === "min" && typeof rule.value === "number") {
4500
+ validationObj.min = rule.value;
4501
+ } else if (rule.type === "max" && typeof rule.value === "number") {
4502
+ validationObj.max = rule.value;
4389
4503
  } else if (rule.type === "minSelected" && typeof rule.value === "number") {
4390
4504
  validationObj.minSelected = rule.value;
4391
4505
  } else if (rule.type === "maxSelected" && typeof rule.value === "number") {
@@ -4398,13 +4512,20 @@ function transformField(field) {
4398
4512
  });
4399
4513
  transformed.validation = validationObj;
4400
4514
  transformed.required = validationObj.required || false;
4515
+ transformed.validations = validationObjectToValidations(validationObj);
4401
4516
  } else {
4402
4517
  transformed.validation = field.validation;
4403
4518
  transformed.required = field.validation.required || false;
4519
+ let validations = validationObjectToValidations(field.validation);
4520
+ if (validations?.validationType === "age") {
4521
+ validations = { ...validations, validationType: "custom" };
4522
+ }
4523
+ transformed.validations = validations;
4404
4524
  }
4405
4525
  } else if (field.required !== void 0) {
4406
4526
  transformed.required = field.required;
4407
4527
  transformed.validation = { required: field.required };
4528
+ transformed.validations = { required: field.required };
4408
4529
  }
4409
4530
  if (normalizedType === "select") {
4410
4531
  if (field.multiSelect !== void 0) {
@@ -4453,6 +4574,10 @@ function transformField(field) {
4453
4574
  transformed.lookupValueField = lookupValueField;
4454
4575
  if (lookupLabelField !== void 0)
4455
4576
  transformed.lookupLabelField = lookupLabelField;
4577
+ if (field.fieldName !== void 0)
4578
+ transformed.fieldName = field.fieldName;
4579
+ else if (field.name !== void 0)
4580
+ transformed.fieldName = field.name;
4456
4581
  if (field.placeholder !== void 0)
4457
4582
  transformed.placeholder = field.placeholder;
4458
4583
  if (field.description !== void 0)
@@ -4467,6 +4592,16 @@ function transformField(field) {
4467
4592
  transformed.enabled = field.enabled;
4468
4593
  if (field.visible !== void 0)
4469
4594
  transformed.visible = field.visible;
4595
+ if (field.isd !== void 0)
4596
+ transformed.isd = field.isd;
4597
+ if (field.imageUrl !== void 0)
4598
+ transformed.imageUrl = field.imageUrl;
4599
+ if (field.valueSource !== void 0)
4600
+ transformed.valueSource = field.valueSource;
4601
+ if (field.formula !== void 0)
4602
+ transformed.formula = field.formula;
4603
+ if (field.dependencies !== void 0 && Array.isArray(field.dependencies))
4604
+ transformed.dependencies = field.dependencies;
4470
4605
  if (field.css !== void 0)
4471
4606
  transformed.css = field.css;
4472
4607
  if (field.optionsSource !== void 0)
@@ -4477,8 +4612,18 @@ function transformField(field) {
4477
4612
  transformed.groupName = field.groupName;
4478
4613
  if (field.masterTypeName !== void 0)
4479
4614
  transformed.masterTypeName = field.masterTypeName;
4480
- if ((normalizedType === "select" || normalizedType === "radio" || normalizedType === "checkbox") && field.options) {
4481
- transformed.options = field.options;
4615
+ if ((normalizedType === "select" || normalizedType === "radio" || normalizedType === "checkbox") && field.options && Array.isArray(field.options)) {
4616
+ transformed.options = field.options.map((opt, idx) => {
4617
+ if (opt && typeof opt === "object" && "label" in opt && "value" in opt) {
4618
+ return { label: String(opt.label), value: String(opt.value) };
4619
+ }
4620
+ const label = opt?.label ?? opt?.name ?? opt?.displayName ?? opt?.text ?? `Option ${idx + 1}`;
4621
+ const value = opt?.value ?? opt?.id ?? opt?.name ?? String(idx);
4622
+ return { label: String(label), value: String(value) };
4623
+ });
4624
+ if (normalizedType === "select" && transformed.options.length > 0 && (transformed.optionSource === "STATIC" || !transformed.optionSource) && transformed.customOptionsEnabled === void 0) {
4625
+ transformed.customOptionsEnabled = true;
4626
+ }
4482
4627
  }
4483
4628
  return transformed;
4484
4629
  }
@@ -4548,6 +4693,10 @@ function convertValidationArrayToObject(validation) {
4548
4693
  obj.minLength = rule.value;
4549
4694
  } else if (rule.type === "maxLength" && typeof rule.value === "number") {
4550
4695
  obj.maxLength = rule.value;
4696
+ } else if (rule.type === "min" && typeof rule.value === "number") {
4697
+ obj.min = rule.value;
4698
+ } else if (rule.type === "max" && typeof rule.value === "number") {
4699
+ obj.max = rule.value;
4551
4700
  } else if (rule.type === "minSelected" && typeof rule.value === "number") {
4552
4701
  obj.minSelected = rule.value;
4553
4702
  } else if (rule.type === "maxSelected" && typeof rule.value === "number") {
@@ -4571,6 +4720,8 @@ function fieldToPayload(field) {
4571
4720
  id: field.id,
4572
4721
  type: field.type,
4573
4722
  label: field.label,
4723
+ name: field.fieldName || field.id,
4724
+ // Model key for binding (API / host app)
4574
4725
  order: field.order !== void 0 ? field.order : 0
4575
4726
  };
4576
4727
  if (field.layout?.span !== void 0) {
@@ -4592,8 +4743,18 @@ function fieldToPayload(field) {
4592
4743
  span: 12
4593
4744
  };
4594
4745
  }
4595
- payload.validation = convertValidationArrayToObject(field.validation);
4596
- if (payload.validation?.required) {
4746
+ if (field.validations) {
4747
+ let validations = { ...field.validations };
4748
+ if (validations.validationType === "age") {
4749
+ validations = { ...validations, validationType: "custom" };
4750
+ }
4751
+ payload.validations = validations;
4752
+ if (field.validations.required) {
4753
+ payload.required = true;
4754
+ }
4755
+ }
4756
+ payload.validation = field.validations ? validationsToValidationObject(field.validations) : convertValidationArrayToObject(field.validation);
4757
+ if (payload.validation?.required || payload.validations?.required) {
4597
4758
  payload.required = true;
4598
4759
  }
4599
4760
  if (field.type === "select") {
@@ -4629,6 +4790,14 @@ function fieldToPayload(field) {
4629
4790
  payload.lookupLabelField = field.lookupLabelField;
4630
4791
  if (field.isd !== void 0)
4631
4792
  payload.isd = field.isd;
4793
+ if (field.imageUrl !== void 0)
4794
+ payload.imageUrl = field.imageUrl;
4795
+ if (field.valueSource !== void 0)
4796
+ payload.valueSource = field.valueSource;
4797
+ if (field.formula !== void 0)
4798
+ payload.formula = field.formula;
4799
+ if (field.dependencies !== void 0 && Array.isArray(field.dependencies))
4800
+ payload.dependencies = field.dependencies;
4632
4801
  if ((field.type === "select" || field.type === "radio" || field.type === "checkbox") && field.options && Array.isArray(field.options)) {
4633
4802
  payload.options = field.options.map((opt) => ({ label: opt.label, value: opt.value }));
4634
4803
  }
@@ -4653,6 +4822,20 @@ var builderToPlatform = (builderSchema) => {
4653
4822
  var platformToBuilder = (platformSchema) => {
4654
4823
  return cleanFormSchema(platformSchema);
4655
4824
  };
4825
+ function getValidationConfigForAngular(validations) {
4826
+ if (!validations) {
4827
+ return { required: false, customErrorMessages: {} };
4828
+ }
4829
+ return {
4830
+ required: validations.required ?? false,
4831
+ minLength: validations.minLength,
4832
+ maxLength: validations.maxLength,
4833
+ min: validations.min,
4834
+ max: validations.max,
4835
+ pattern: validations.pattern,
4836
+ customErrorMessages: validations.customErrorMessages || {}
4837
+ };
4838
+ }
4656
4839
 
4657
4840
  // src/core/useFormStore.ts
4658
4841
  var INITIAL_SCHEMA = {
@@ -4957,9 +5140,10 @@ var formStore = createStore((set, get) => ({
4957
5140
  const { existingForms, history, historyIndex } = get();
4958
5141
  const found = existingForms.find((f) => f.id === formId);
4959
5142
  if (found) {
5143
+ const cleanedSchema = cleanFormSchema(found);
4960
5144
  set({
4961
- schema: found,
4962
- history: [...history.slice(0, historyIndex + 1), found],
5145
+ schema: cleanedSchema,
5146
+ history: [...history.slice(0, historyIndex + 1), cleanedSchema],
4963
5147
  historyIndex: historyIndex + 1
4964
5148
  });
4965
5149
  }
@@ -4969,9 +5153,10 @@ var formStore = createStore((set, get) => ({
4969
5153
  const found = existingForms.find((f) => f.id === formId);
4970
5154
  if (found) {
4971
5155
  const cloned = cloneForm(found);
5156
+ const cleanedSchema = cleanFormSchema(cloned);
4972
5157
  set({
4973
- schema: cloned,
4974
- history: [...history.slice(0, historyIndex + 1), cloned],
5158
+ schema: cleanedSchema,
5159
+ history: [...history.slice(0, historyIndex + 1), cleanedSchema],
4975
5160
  historyIndex: historyIndex + 1
4976
5161
  });
4977
5162
  }
@@ -5354,6 +5539,7 @@ var ICONS = {
5354
5539
  "ToggleSwitch": '<rect x="2" y="6" width="20" height="12" rx="6" ry="6" stroke-linecap="round" stroke-linejoin="round" /><circle cx="8" cy="12" r="4" stroke-linecap="round" stroke-linejoin="round" />',
5355
5540
  // Custom SVG for toggle
5356
5541
  "Upload": '<path stroke-linecap="round" stroke-linejoin="round" d="M3 16.5v2.25A2.25 2.25 0 005.25 21h13.5A2.25 2.25 0 0021 18.75V16.5m-13.5-9L12 3m0 0l4.5 4.5M12 3v13.5" />',
5542
+ "Image": '<path stroke-linecap="round" stroke-linejoin="round" d="M2.25 15.75l5.159-5.159a2.25 2.25 0 013.182 0l5.159 5.159m-1.5-1.5l1.409-1.409a2.25 2.25 0 013.182 0l2.909 2.909m-18 3.75h16.5a1.5 1.5 0 001.5-1.5V6a1.5 1.5 0 00-1.5-1.5H3.75A1.5 1.5 0 002.25 6v12a1.5 1.5 0 001.5 1.5zm10.5-11.25h.008v.008h-.008V8.25zm.375 0a.375.375 0 11-.75 0 .375.375 0 01.75 0z" />',
5357
5543
  // UI Icons
5358
5544
  "GripVertical": '<path stroke-linecap="round" stroke-linejoin="round" d="M8.25 15L12 18.75 15.75 15m-7.5-6L12 5.25 15.75 9" />',
5359
5545
  "GripDots": '<path stroke-linecap="round" stroke-linejoin="round" d="M12 6.75a.75.75 0 110-1.5.75.75 0 010 1.5zM12 12.75a.75.75 0 110-1.5.75.75 0 010 1.5zM12 18.75a.75.75 0 110-1.5.75.75 0 010 1.5z" />',
@@ -5386,6 +5572,224 @@ function getIcon(name, size = 20) {
5386
5572
  return svg;
5387
5573
  }
5388
5574
 
5575
+ // src/utils/formula.ts
5576
+ var FORMULA_OPERATOR_REGEX = /[\+\-\*\/\(\)]/g;
5577
+ function parseFormulaDependencies(formula) {
5578
+ if (!formula || typeof formula !== "string")
5579
+ return [];
5580
+ const tokens = formula.replace(FORMULA_OPERATOR_REGEX, " ").split(/\s+/).filter(Boolean);
5581
+ const seen = /* @__PURE__ */ new Set();
5582
+ const deps = [];
5583
+ for (const t of tokens) {
5584
+ const trimmed = t.trim();
5585
+ if (trimmed && !seen.has(trimmed)) {
5586
+ seen.add(trimmed);
5587
+ deps.push(trimmed);
5588
+ }
5589
+ }
5590
+ return deps;
5591
+ }
5592
+ function validateFormula(formula, availableFieldIds, availableFieldNames, _currentFieldId) {
5593
+ if (!formula || typeof formula !== "string") {
5594
+ return { valid: false, error: "Formula cannot be empty" };
5595
+ }
5596
+ const trimmed = formula.trim();
5597
+ if (!trimmed) {
5598
+ return { valid: false, error: "Formula cannot be empty" };
5599
+ }
5600
+ const deps = parseFormulaDependencies(trimmed);
5601
+ const validRefs = /* @__PURE__ */ new Set([...availableFieldIds, ...availableFieldNames]);
5602
+ for (const dep of deps) {
5603
+ if (!validRefs.has(dep)) {
5604
+ return { valid: false, error: `Unknown field reference: "${dep}"` };
5605
+ }
5606
+ }
5607
+ let open = 0;
5608
+ for (const c of trimmed) {
5609
+ if (c === "(")
5610
+ open++;
5611
+ else if (c === ")") {
5612
+ open--;
5613
+ if (open < 0)
5614
+ return { valid: false, error: "Unbalanced parentheses" };
5615
+ }
5616
+ }
5617
+ if (open !== 0)
5618
+ return { valid: false, error: "Unbalanced parentheses" };
5619
+ return { valid: true };
5620
+ }
5621
+ function detectCircularDependency(schema, formulaFieldId, _formula, dependencies) {
5622
+ const visited = /* @__PURE__ */ new Set();
5623
+ const resolveFieldByRef = (ref) => {
5624
+ for (const s of schema.sections) {
5625
+ for (const f of s.fields) {
5626
+ if (f.id === ref || f.fieldName === ref)
5627
+ return f;
5628
+ }
5629
+ }
5630
+ return void 0;
5631
+ };
5632
+ const hasCycle = (fieldId) => {
5633
+ if (visited.has(fieldId))
5634
+ return true;
5635
+ visited.add(fieldId);
5636
+ const field = resolveFieldByRef(fieldId);
5637
+ if (!field || field.type !== "number" || field.valueSource !== "formula" || !field.formula) {
5638
+ visited.delete(fieldId);
5639
+ return false;
5640
+ }
5641
+ const deps = field.dependencies ?? parseFormulaDependencies(field.formula);
5642
+ for (const dep of deps) {
5643
+ const depField = resolveFieldByRef(dep);
5644
+ if (!depField)
5645
+ continue;
5646
+ const depId = depField.id;
5647
+ if (depId === formulaFieldId) {
5648
+ visited.delete(fieldId);
5649
+ return true;
5650
+ }
5651
+ if (hasCycle(depId)) {
5652
+ visited.delete(fieldId);
5653
+ return true;
5654
+ }
5655
+ }
5656
+ visited.delete(fieldId);
5657
+ return false;
5658
+ };
5659
+ for (const dep of dependencies) {
5660
+ const depField = resolveFieldByRef(dep);
5661
+ if (!depField)
5662
+ continue;
5663
+ if (depField.id === formulaFieldId)
5664
+ return true;
5665
+ if (hasCycle(depField.id))
5666
+ return true;
5667
+ }
5668
+ return false;
5669
+ }
5670
+ function evaluateFormula(formula, values) {
5671
+ if (!formula || typeof formula !== "string")
5672
+ return NaN;
5673
+ const trimmed = formula.trim();
5674
+ if (!trimmed)
5675
+ return NaN;
5676
+ const getValue = (ref) => {
5677
+ const v = values[ref];
5678
+ if (v === void 0 || v === null || v === "")
5679
+ return 0;
5680
+ const n = typeof v === "number" ? v : parseFloat(String(v));
5681
+ return isNaN(n) ? 0 : n;
5682
+ };
5683
+ const tokens = [];
5684
+ let i = 0;
5685
+ while (i < trimmed.length) {
5686
+ const c = trimmed[i];
5687
+ if (/\s/.test(c)) {
5688
+ i++;
5689
+ continue;
5690
+ }
5691
+ if (/[\+\-\*\/\(\)]/.test(c)) {
5692
+ tokens.push(c);
5693
+ i++;
5694
+ continue;
5695
+ }
5696
+ if (/[a-zA-Z_0-9]/.test(c)) {
5697
+ let ident = "";
5698
+ while (i < trimmed.length && /[a-zA-Z0-9_]/.test(trimmed[i])) {
5699
+ ident += trimmed[i++];
5700
+ }
5701
+ tokens.push(ident);
5702
+ continue;
5703
+ }
5704
+ i++;
5705
+ }
5706
+ let pos = 0;
5707
+ const parseExpr = () => {
5708
+ let left = parseTerm();
5709
+ while (pos < tokens.length) {
5710
+ const op = tokens[pos];
5711
+ if (op === "+") {
5712
+ pos++;
5713
+ left += parseTerm();
5714
+ } else if (op === "-") {
5715
+ pos++;
5716
+ left -= parseTerm();
5717
+ } else
5718
+ break;
5719
+ }
5720
+ return left;
5721
+ };
5722
+ const parseTerm = () => {
5723
+ let left = parseFactor();
5724
+ while (pos < tokens.length) {
5725
+ const op = tokens[pos];
5726
+ if (op === "*") {
5727
+ pos++;
5728
+ left *= parseFactor();
5729
+ } else if (op === "/") {
5730
+ pos++;
5731
+ const right = parseFactor();
5732
+ if (right === 0)
5733
+ return NaN;
5734
+ left /= right;
5735
+ } else
5736
+ break;
5737
+ }
5738
+ return left;
5739
+ };
5740
+ const parseFactor = () => {
5741
+ if (pos >= tokens.length)
5742
+ return NaN;
5743
+ const t = tokens[pos];
5744
+ if (t === "(") {
5745
+ pos++;
5746
+ const v = parseExpr();
5747
+ if (pos < tokens.length && tokens[pos] === ")")
5748
+ pos++;
5749
+ return v;
5750
+ }
5751
+ if (t === "-") {
5752
+ pos++;
5753
+ return -parseFactor();
5754
+ }
5755
+ if (t === "+") {
5756
+ pos++;
5757
+ return parseFactor();
5758
+ }
5759
+ const n = parseFloat(t);
5760
+ if (!isNaN(n)) {
5761
+ pos++;
5762
+ return n;
5763
+ }
5764
+ pos++;
5765
+ return getValue(t);
5766
+ };
5767
+ try {
5768
+ const result = parseExpr();
5769
+ return isNaN(result) ? NaN : result;
5770
+ } catch {
5771
+ return NaN;
5772
+ }
5773
+ }
5774
+ function getNumericFieldsForFormula(schema, excludeFieldId) {
5775
+ const result = [];
5776
+ for (const section of schema.sections) {
5777
+ for (const field of section.fields) {
5778
+ if (field.type !== "number")
5779
+ continue;
5780
+ if (excludeFieldId && field.id === excludeFieldId)
5781
+ continue;
5782
+ const fieldName = field.fieldName ?? field.id;
5783
+ result.push({
5784
+ id: field.id,
5785
+ fieldName,
5786
+ label: field.label || fieldName
5787
+ });
5788
+ }
5789
+ }
5790
+ return result;
5791
+ }
5792
+
5389
5793
  // src/core/countryData.ts
5390
5794
  var COUNTRY_DATA = [
5391
5795
  { code: "US", name: "United States", dialCode: "+1", flag: "\u{1F1FA}\u{1F1F8}" },
@@ -5441,6 +5845,64 @@ function getDefaultCountry() {
5441
5845
  }
5442
5846
 
5443
5847
  // src/renderer/FieldRenderer.ts
5848
+ function getValidationRules(field) {
5849
+ const v = field.validations;
5850
+ if (v) {
5851
+ return {
5852
+ required: v.required,
5853
+ pattern: v.pattern,
5854
+ patternMessage: v.customErrorMessages?.pattern,
5855
+ minLength: v.minLength,
5856
+ maxLength: v.maxLength,
5857
+ min: v.min,
5858
+ max: v.max,
5859
+ minDate: v.minDate,
5860
+ maxDate: v.maxDate
5861
+ };
5862
+ }
5863
+ const val = field.validation;
5864
+ if (!val)
5865
+ return {};
5866
+ if (Array.isArray(val)) {
5867
+ const rules = {};
5868
+ val.forEach((r) => {
5869
+ if (r.type === "required")
5870
+ rules.required = true;
5871
+ else if (r.type === "pattern") {
5872
+ rules.pattern = r.regex;
5873
+ rules.patternMessage = r.message;
5874
+ } else if (r.type === "minLength")
5875
+ rules.minLength = r.value;
5876
+ else if (r.type === "maxLength")
5877
+ rules.maxLength = r.value;
5878
+ else if (r.type === "min")
5879
+ rules.min = r.value;
5880
+ else if (r.type === "max")
5881
+ rules.max = r.value;
5882
+ else if (r.type === "minDate")
5883
+ rules.minDate = r.value;
5884
+ else if (r.type === "maxDate")
5885
+ rules.maxDate = r.value;
5886
+ });
5887
+ return rules;
5888
+ }
5889
+ const o = val;
5890
+ return {
5891
+ required: o.required,
5892
+ pattern: o.regex,
5893
+ patternMessage: o.regexMessage,
5894
+ minLength: o.minLength,
5895
+ maxLength: o.maxLength,
5896
+ min: o.min,
5897
+ max: o.max,
5898
+ minDate: o.minDate,
5899
+ maxDate: o.maxDate
5900
+ };
5901
+ }
5902
+ function isNumericTextField(field) {
5903
+ const v = field.validations;
5904
+ return !!(v?.validationType && ["postalCode", "phoneNumber", "otp"].includes(v.validationType));
5905
+ }
5444
5906
  var FieldRenderer = class {
5445
5907
  static render(field, value, onChange, readOnly = false) {
5446
5908
  const wrapper = createElement("div", { className: "w-full form-row" });
@@ -5475,89 +5937,71 @@ var FieldRenderer = class {
5475
5937
  }
5476
5938
  let input;
5477
5939
  let validationMsg = null;
5478
- const validationArray = Array.isArray(field.validation) ? field.validation : field.validation ? (() => {
5479
- const obj = field.validation;
5480
- const rules = [];
5481
- if (obj.required)
5482
- rules.push({ type: "required", value: true });
5483
- if (obj.regex)
5484
- rules.push({ type: "pattern", regex: obj.regex, message: obj.regexMessage });
5485
- if (obj.minLength !== void 0)
5486
- rules.push({ type: "minLength", value: obj.minLength });
5487
- if (obj.maxLength !== void 0)
5488
- rules.push({ type: "maxLength", value: obj.maxLength });
5489
- if (obj.minSelected !== void 0)
5490
- rules.push({ type: "minSelected", value: obj.minSelected });
5491
- if (obj.maxSelected !== void 0)
5492
- rules.push({ type: "maxSelected", value: obj.maxSelected });
5493
- if (obj.minDate)
5494
- rules.push({ type: "minDate", value: obj.minDate });
5495
- if (obj.maxDate)
5496
- rules.push({ type: "maxDate", value: obj.maxDate });
5497
- return rules;
5498
- })() : [];
5499
- const hasPatternValidation = validationArray.some((v) => v.type === "pattern");
5500
- if (field.type === "date" || field.type === "email" || field.type === "text" && hasPatternValidation) {
5940
+ const validationRules = getValidationRules(field);
5941
+ const hasPatternValidation = !!validationRules.pattern;
5942
+ const hasNumericTextValidation = isNumericTextField(field);
5943
+ if (field.type === "date" || field.type === "email" || field.type === "number" || field.type === "text" && (hasPatternValidation || hasNumericTextValidation || validationRules.minLength !== void 0 || validationRules.maxLength !== void 0)) {
5501
5944
  validationMsg = createElement("div", { className: "text-xs text-red-600 dark:text-red-400 mt-1 hidden", id: `validation-${field.id}` });
5502
5945
  }
5503
- const validateField = (field2, value2, inputElement, validationMsg2) => {
5946
+ const validateField = (f, value2, inputElement, msgEl) => {
5947
+ const rules = getValidationRules(f);
5948
+ const custom2 = f.validations?.customErrorMessages;
5504
5949
  let errorMessage = "";
5505
- const validationArray2 = Array.isArray(field2.validation) ? field2.validation : field2.validation ? (() => {
5506
- const obj = field2.validation;
5507
- const rules = [];
5508
- if (obj.required)
5509
- rules.push({ type: "required", value: true });
5510
- if (obj.regex)
5511
- rules.push({ type: "pattern", regex: obj.regex, message: obj.regexMessage });
5512
- if (obj.minLength !== void 0)
5513
- rules.push({ type: "minLength", value: obj.minLength });
5514
- if (obj.maxLength !== void 0)
5515
- rules.push({ type: "maxLength", value: obj.maxLength });
5516
- if (obj.minSelected !== void 0)
5517
- rules.push({ type: "minSelected", value: obj.minSelected });
5518
- if (obj.maxSelected !== void 0)
5519
- rules.push({ type: "maxSelected", value: obj.maxSelected });
5520
- if (obj.minDate)
5521
- rules.push({ type: "minDate", value: obj.minDate });
5522
- if (obj.maxDate)
5523
- rules.push({ type: "maxDate", value: obj.maxDate });
5524
- return rules;
5525
- })() : [];
5526
- if (field2.type === "date" && value2) {
5527
- const minDateRule = validationArray2.find((v) => v.type === "minDate");
5528
- const maxDateRule = validationArray2.find((v) => v.type === "maxDate");
5950
+ if (rules.required && (!value2 || String(value2).trim() === "")) {
5951
+ errorMessage = custom2?.required || "This field is required";
5952
+ }
5953
+ if (!errorMessage && f.type === "date" && value2) {
5529
5954
  const inputDate = new Date(value2);
5530
- if (minDateRule?.value) {
5531
- const minDate = new Date(minDateRule.value);
5955
+ if (rules.minDate) {
5956
+ const minDate = new Date(rules.minDate);
5532
5957
  if (inputDate < minDate) {
5533
- errorMessage = minDateRule.message || "Date must be after the minimum date";
5958
+ errorMessage = "Date must be after the minimum date";
5534
5959
  }
5535
5960
  }
5536
- if (maxDateRule?.value && !errorMessage) {
5537
- const maxDate = new Date(maxDateRule.value);
5961
+ if (!errorMessage && rules.maxDate) {
5962
+ const maxDate = new Date(rules.maxDate);
5538
5963
  if (inputDate > maxDate) {
5539
- errorMessage = maxDateRule.message || "Date must be before the maximum date";
5964
+ errorMessage = "Date must be before the maximum date";
5540
5965
  }
5541
5966
  }
5542
5967
  }
5543
- if ((field2.type === "email" || field2.type === "text") && value2) {
5544
- const patternRule = validationArray2.find((v) => v.type === "pattern");
5545
- if (patternRule?.regex) {
5546
- try {
5547
- const regex = new RegExp(patternRule.regex);
5548
- if (!regex.test(value2)) {
5549
- errorMessage = patternRule.message || "Invalid format";
5550
- }
5551
- } catch (e) {
5968
+ if (!errorMessage && (f.type === "email" || f.type === "text" || f.type === "phone") && value2 && rules.pattern) {
5969
+ try {
5970
+ if (!new RegExp(rules.pattern).test(value2)) {
5971
+ errorMessage = rules.patternMessage || custom2?.pattern || "Invalid format";
5972
+ }
5973
+ } catch (_e) {
5974
+ }
5975
+ }
5976
+ if (!errorMessage && value2 && (f.type === "text" || f.type === "phone")) {
5977
+ const len = String(value2).length;
5978
+ if (rules.minLength !== void 0 && len < rules.minLength) {
5979
+ errorMessage = custom2?.minLength || `Minimum length is ${rules.minLength}`;
5980
+ }
5981
+ if (!errorMessage && rules.maxLength !== void 0 && len > rules.maxLength) {
5982
+ errorMessage = custom2?.maxLength || `Maximum length is ${rules.maxLength}`;
5983
+ }
5984
+ }
5985
+ if (!errorMessage && f.type === "number" && value2 !== "" && value2 !== void 0) {
5986
+ const num = parseFloat(String(value2));
5987
+ if (!isNaN(num)) {
5988
+ if (f.validations?.allowNegative === false && num < 0) {
5989
+ errorMessage = custom2?.min || "Negative values are not allowed";
5990
+ }
5991
+ if (!errorMessage && rules.min !== void 0 && num < rules.min) {
5992
+ errorMessage = custom2?.min || `Value must be at least ${rules.min}`;
5993
+ }
5994
+ if (!errorMessage && rules.max !== void 0 && num > rules.max) {
5995
+ errorMessage = custom2?.max || `Value must be at most ${rules.max}`;
5552
5996
  }
5553
5997
  }
5554
5998
  }
5555
5999
  if (errorMessage) {
5556
- validationMsg2.textContent = errorMessage;
5557
- validationMsg2.classList.remove("hidden");
6000
+ msgEl.textContent = errorMessage;
6001
+ msgEl.classList.remove("hidden");
5558
6002
  inputElement.classList.add("border-red-500");
5559
6003
  } else {
5560
- validationMsg2.classList.add("hidden");
6004
+ msgEl.classList.add("hidden");
5561
6005
  inputElement.classList.remove("border-red-500");
5562
6006
  }
5563
6007
  };
@@ -5691,59 +6135,40 @@ var FieldRenderer = class {
5691
6135
  case "phone":
5692
6136
  input = this.renderPhoneField(field, value, onChange, isEnabled);
5693
6137
  break;
6138
+ case "image":
6139
+ input = this.renderImageField(field, value ?? field.imageUrl ?? field.defaultValue, onChange, isEnabled);
6140
+ break;
5694
6141
  default:
5695
- const fieldValidationArray = Array.isArray(field.validation) ? field.validation : field.validation ? (() => {
5696
- const obj = field.validation;
5697
- const rules = [];
5698
- if (obj.required)
5699
- rules.push({ type: "required", value: true });
5700
- if (obj.regex)
5701
- rules.push({ type: "pattern", regex: obj.regex, message: obj.regexMessage });
5702
- if (obj.minLength !== void 0)
5703
- rules.push({ type: "minLength", value: obj.minLength });
5704
- if (obj.maxLength !== void 0)
5705
- rules.push({ type: "maxLength", value: obj.maxLength });
5706
- if (obj.minSelected !== void 0)
5707
- rules.push({ type: "minSelected", value: obj.minSelected });
5708
- if (obj.maxSelected !== void 0)
5709
- rules.push({ type: "maxSelected", value: obj.maxSelected });
5710
- if (obj.minDate)
5711
- rules.push({ type: "minDate", value: obj.minDate });
5712
- if (obj.maxDate)
5713
- rules.push({ type: "maxDate", value: obj.maxDate });
5714
- return rules;
5715
- })() : [];
5716
- const patternRule = fieldValidationArray.find((v) => v.type === "pattern");
5717
- const patternRegex = patternRule?.regex;
6142
+ const rules = getValidationRules(field);
6143
+ const useNumericTextInput = field.type === "text" && isNumericTextField(field);
6144
+ const inputType = useNumericTextInput ? "text" : field.type === "number" ? "number" : field.type;
6145
+ const runValidation = () => {
6146
+ if (validationMsg && (field.type === "date" || field.type === "email" || field.type === "text" || field.type === "number")) {
6147
+ validateField(field, input.value, input, validationMsg);
6148
+ }
6149
+ };
5718
6150
  input = createElement("input", {
5719
- type: field.type,
6151
+ type: inputType,
6152
+ ...useNumericTextInput && { inputmode: "numeric" },
5720
6153
  className: "flex min-h-touch w-full rounded-md border border-input bg-background px-3 py-2 text-sm sm:text-base ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",
5721
- // type: field.type === 'phone' ? 'tel' : field.type,
5722
- // className: 'flex min-h-touch w-full rounded-md border border-gray-300 bg-background px-3 py-2 text-sm sm:text-base ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none disabled:cursor-not-allowed disabled:opacity-50',
5723
6154
  placeholder: field.placeholder,
5724
6155
  value: value || "",
5725
6156
  disabled: !isEnabled,
5726
- min: field.type === "date" ? fieldValidationArray.find((v) => v.type === "minDate")?.value : void 0,
5727
- max: field.type === "date" ? fieldValidationArray.find((v) => v.type === "maxDate")?.value : void 0,
5728
- pattern: patternRegex || void 0,
5729
- // Apply pattern for both email and text fields
6157
+ min: field.type === "date" ? rules.minDate : field.type === "number" ? rules.min !== void 0 ? String(rules.min) : void 0 : void 0,
6158
+ max: field.type === "date" ? rules.maxDate : field.type === "number" ? rules.max !== void 0 ? String(rules.max) : void 0 : void 0,
6159
+ pattern: !useNumericTextInput ? rules.pattern || void 0 : void 0,
5730
6160
  oninput: (e) => {
5731
- const inputValue = e.target.value;
5732
- onChange?.(inputValue);
5733
- if (validationMsg && (field.type === "date" || field.type === "email" || field.type === "text" && hasPatternValidation)) {
5734
- validateField(field, inputValue, input, validationMsg);
5735
- }
5736
- },
5737
- onchange: (e) => {
5738
- if (validationMsg && (field.type === "date" || field.type === "email" || field.type === "text" && hasPatternValidation)) {
5739
- validateField(field, e.target.value, input, validationMsg);
6161
+ const inputEl = e.target;
6162
+ let inputValue = inputEl.value;
6163
+ if (useNumericTextInput) {
6164
+ inputValue = inputValue.replace(/[eE+-]/g, "");
6165
+ inputEl.value = inputValue;
5740
6166
  }
6167
+ onChange?.(inputValue);
6168
+ runValidation();
5741
6169
  },
5742
- onblur: (e) => {
5743
- if (validationMsg && (field.type === "date" || field.type === "email" || field.type === "text" && hasPatternValidation)) {
5744
- validateField(field, e.target.value, input, validationMsg);
5745
- }
5746
- }
6170
+ onchange: () => runValidation(),
6171
+ onblur: () => runValidation()
5747
6172
  });
5748
6173
  }
5749
6174
  wrapper.appendChild(input);
@@ -5839,6 +6264,93 @@ var FieldRenderer = class {
5839
6264
  });
5840
6265
  return container;
5841
6266
  }
6267
+ /**
6268
+ * Render image field with upload, preview, and remove/replace
6269
+ */
6270
+ static renderImageField(field, imageValue, onChange, isEnabled = true) {
6271
+ const ACCEPT = "image/jpeg,image/png,image/gif,image/webp";
6272
+ const MAX_SIZE_MB = 5;
6273
+ const MAX_SIZE_BYTES = MAX_SIZE_MB * 1024 * 1024;
6274
+ const container = createElement("div", { className: "image-field-wrapper flex flex-col gap-3 w-full" });
6275
+ const previewWrap = createElement("div", {
6276
+ className: "relative rounded-md border border-input bg-gray-50 dark:bg-gray-800 overflow-hidden min-h-[120px] flex items-center justify-center"
6277
+ });
6278
+ if (imageValue) {
6279
+ const img = createElement("img", {
6280
+ src: imageValue,
6281
+ alt: field.label || "Uploaded image",
6282
+ className: "max-h-48 max-w-full object-contain"
6283
+ });
6284
+ img.onerror = () => {
6285
+ previewWrap.innerHTML = "";
6286
+ previewWrap.appendChild(createElement("p", {
6287
+ className: "text-xs text-red-500 p-4",
6288
+ text: "Failed to load image"
6289
+ }));
6290
+ };
6291
+ previewWrap.appendChild(img);
6292
+ if (isEnabled) {
6293
+ const removeBtn = createElement("button", {
6294
+ type: "button",
6295
+ className: "absolute top-2 right-2 p-1.5 bg-red-500 text-white rounded-md hover:bg-red-600 text-xs",
6296
+ title: "Remove image",
6297
+ onclick: () => onChange?.(void 0)
6298
+ });
6299
+ removeBtn.innerHTML = "\xD7";
6300
+ previewWrap.appendChild(removeBtn);
6301
+ }
6302
+ } else {
6303
+ previewWrap.appendChild(createElement("p", {
6304
+ className: "text-xs text-muted-foreground p-4",
6305
+ text: "No image uploaded"
6306
+ }));
6307
+ }
6308
+ container.appendChild(previewWrap);
6309
+ if (isEnabled) {
6310
+ const fileInput = createElement("input", {
6311
+ type: "file",
6312
+ accept: ACCEPT,
6313
+ className: "hidden",
6314
+ id: `image-upload-${field.id}`
6315
+ });
6316
+ const uploadBtn = createElement("button", {
6317
+ type: "button",
6318
+ className: "px-3 py-2 text-sm border border-gray-300 dark:border-gray-700 rounded-md hover:bg-gray-50 dark:hover:bg-gray-800 transition-colors disabled:opacity-50 disabled:cursor-not-allowed",
6319
+ text: imageValue ? "Replace" : "Upload Image",
6320
+ onclick: () => fileInput.click()
6321
+ });
6322
+ fileInput.onchange = (e) => {
6323
+ const target = e.target;
6324
+ const file = target.files?.[0];
6325
+ if (!file)
6326
+ return;
6327
+ if (!file.type.match(/^image\/(jpeg|png|gif|webp)$/)) {
6328
+ alert(`Please select a valid image (JPG, PNG, GIF, WebP)`);
6329
+ target.value = "";
6330
+ return;
6331
+ }
6332
+ if (file.size > MAX_SIZE_BYTES) {
6333
+ alert(`Image must be under ${MAX_SIZE_MB}MB`);
6334
+ target.value = "";
6335
+ return;
6336
+ }
6337
+ const reader = new FileReader();
6338
+ reader.onload = () => {
6339
+ const result = reader.result;
6340
+ if (result)
6341
+ onChange?.(result);
6342
+ };
6343
+ reader.onerror = () => {
6344
+ alert("Failed to read image");
6345
+ };
6346
+ reader.readAsDataURL(file);
6347
+ target.value = "";
6348
+ };
6349
+ container.appendChild(fileInput);
6350
+ container.appendChild(uploadBtn);
6351
+ }
6352
+ return container;
6353
+ }
5842
6354
  };
5843
6355
 
5844
6356
  // src/renderer/FormRenderer.ts
@@ -5857,6 +6369,10 @@ function convertValidationToArray(validation) {
5857
6369
  rules.push({ type: "minLength", value: obj.minLength });
5858
6370
  if (obj.maxLength !== void 0)
5859
6371
  rules.push({ type: "maxLength", value: obj.maxLength });
6372
+ if (obj.min !== void 0)
6373
+ rules.push({ type: "min", value: obj.min });
6374
+ if (obj.max !== void 0)
6375
+ rules.push({ type: "max", value: obj.max });
5860
6376
  if (obj.minSelected !== void 0)
5861
6377
  rules.push({ type: "minSelected", value: obj.minSelected });
5862
6378
  if (obj.maxSelected !== void 0)
@@ -5867,9 +6383,146 @@ function convertValidationToArray(validation) {
5867
6383
  rules.push({ type: "maxDate", value: obj.maxDate });
5868
6384
  return rules;
5869
6385
  }
6386
+ function getValidationRulesForField(field) {
6387
+ const v = field.validations;
6388
+ if (v) {
6389
+ const obj = {};
6390
+ if (v.required)
6391
+ obj.required = true;
6392
+ if (v.pattern)
6393
+ obj.regex = v.pattern;
6394
+ if (v.customErrorMessages?.pattern)
6395
+ obj.regexMessage = v.customErrorMessages.pattern;
6396
+ if (v.minLength !== void 0)
6397
+ obj.minLength = v.minLength;
6398
+ if (v.maxLength !== void 0)
6399
+ obj.maxLength = v.maxLength;
6400
+ if (v.min !== void 0)
6401
+ obj.min = v.min;
6402
+ if (v.max !== void 0)
6403
+ obj.max = v.max;
6404
+ if (v.minSelected !== void 0)
6405
+ obj.minSelected = v.minSelected;
6406
+ if (v.maxSelected !== void 0)
6407
+ obj.maxSelected = v.maxSelected;
6408
+ if (v.minDate)
6409
+ obj.minDate = v.minDate;
6410
+ if (v.maxDate)
6411
+ obj.maxDate = v.maxDate;
6412
+ return convertValidationToArray(obj);
6413
+ }
6414
+ return convertValidationToArray(field.validation);
6415
+ }
6416
+ function getFieldValidationError(field, fieldValue) {
6417
+ const isRequired = field.validations?.required ?? field.required;
6418
+ if (isRequired && (!fieldValue || fieldValue === "" || Array.isArray(fieldValue) && fieldValue.length === 0)) {
6419
+ return field.validations?.customErrorMessages?.required || "This field is required";
6420
+ }
6421
+ if ((field.type === "text" || field.type === "email" || field.type === "phone") && fieldValue) {
6422
+ const validationArray = getValidationRulesForField(field);
6423
+ const patternRule = validationArray.find((v) => v.type === "pattern");
6424
+ if (patternRule?.regex) {
6425
+ try {
6426
+ if (!new RegExp(patternRule.regex).test(String(fieldValue))) {
6427
+ return field.validations?.customErrorMessages?.pattern || patternRule.message || "Invalid format";
6428
+ }
6429
+ } catch (_e) {
6430
+ }
6431
+ }
6432
+ const minLenRule = validationArray.find((v) => v.type === "minLength");
6433
+ const maxLenRule = validationArray.find((v) => v.type === "maxLength");
6434
+ const len = String(fieldValue).length;
6435
+ if (minLenRule && typeof minLenRule.value === "number" && len < minLenRule.value) {
6436
+ return field.validations?.customErrorMessages?.minLength || `Minimum length is ${minLenRule.value}`;
6437
+ }
6438
+ if (maxLenRule && typeof maxLenRule.value === "number" && len > maxLenRule.value) {
6439
+ return field.validations?.customErrorMessages?.maxLength || `Maximum length is ${maxLenRule.value}`;
6440
+ }
6441
+ }
6442
+ if (field.type === "number" && fieldValue !== "" && fieldValue !== void 0) {
6443
+ const v = field.validations;
6444
+ const num = parseFloat(String(fieldValue));
6445
+ if (!isNaN(num)) {
6446
+ if (v?.min !== void 0 && num < v.min) {
6447
+ return v.customErrorMessages?.min || `Value must be at least ${v.min}`;
6448
+ }
6449
+ if (v?.max !== void 0 && num > v.max) {
6450
+ return v.customErrorMessages?.max || `Value must be at most ${v.max}`;
6451
+ }
6452
+ if (v?.allowNegative === false && num < 0) {
6453
+ return v.customErrorMessages?.min || "Negative values are not allowed";
6454
+ }
6455
+ }
6456
+ }
6457
+ if (field.type === "checkbox" && Array.isArray(fieldValue)) {
6458
+ const validationArray = getValidationRulesForField(field);
6459
+ const minSelectedRule = validationArray.find((v) => v.type === "minSelected");
6460
+ const maxSelectedRule = validationArray.find((v) => v.type === "maxSelected");
6461
+ const selectedCount = fieldValue.length;
6462
+ const minSelected = typeof minSelectedRule?.value === "number" ? minSelectedRule.value : void 0;
6463
+ const maxSelected = typeof maxSelectedRule?.value === "number" ? maxSelectedRule.value : void 0;
6464
+ if (minSelected !== void 0 && selectedCount < minSelected) {
6465
+ return `Please select at least ${minSelected} option(s)`;
6466
+ }
6467
+ if (maxSelected !== void 0 && selectedCount > maxSelected) {
6468
+ return `Please select at most ${maxSelected} option(s)`;
6469
+ }
6470
+ }
6471
+ return "";
6472
+ }
5870
6473
  function getModelKey(field) {
5871
6474
  return field.fieldName ?? field.id;
5872
6475
  }
6476
+ function buildFormulaValuesMap(schema, data) {
6477
+ const values = {};
6478
+ const allFields = schema.sections.flatMap((s) => s.fields);
6479
+ for (const field of allFields) {
6480
+ const modelKey = getModelKey(field);
6481
+ const val = data[modelKey];
6482
+ values[modelKey] = val;
6483
+ values[field.id] = val;
6484
+ if (field.fieldName)
6485
+ values[field.fieldName] = val;
6486
+ }
6487
+ const formulaFields = allFields.filter((f) => f.type === "number" && f.valueSource === "formula" && f.formula);
6488
+ for (let pass = 0; pass < Math.max(1, formulaFields.length); pass++) {
6489
+ for (const field of formulaFields) {
6490
+ const modelKey = getModelKey(field);
6491
+ const result = evaluateFormula(field.formula, values);
6492
+ const newVal = isNaN(result) ? void 0 : result;
6493
+ values[modelKey] = newVal;
6494
+ values[field.id] = newVal;
6495
+ if (field.fieldName)
6496
+ values[field.fieldName] = newVal;
6497
+ }
6498
+ }
6499
+ return values;
6500
+ }
6501
+ function computeFormulaValue(field, schema, data) {
6502
+ if (field.type !== "number" || field.valueSource !== "formula" || !field.formula)
6503
+ return void 0;
6504
+ const values = buildFormulaValuesMap(schema, data);
6505
+ const modelKey = getModelKey(field);
6506
+ const result = values[modelKey];
6507
+ if (typeof result !== "number")
6508
+ return void 0;
6509
+ const decimalPlaces = field.validations?.decimalPlaces ?? (field.validations?.allowDecimal ? 2 : 0);
6510
+ const rounded = decimalPlaces > 0 ? Math.round(result * Math.pow(10, decimalPlaces)) / Math.pow(10, decimalPlaces) : Math.round(result);
6511
+ return rounded;
6512
+ }
6513
+ function isFormulaDependency(schema, modelKey, fieldId) {
6514
+ for (const section of schema.sections) {
6515
+ for (const field of section.fields) {
6516
+ if (field.type === "number" && field.valueSource === "formula" && field.dependencies) {
6517
+ if (field.dependencies.includes(modelKey))
6518
+ return true;
6519
+ if (fieldId && field.dependencies.includes(fieldId))
6520
+ return true;
6521
+ }
6522
+ }
6523
+ }
6524
+ return false;
6525
+ }
5873
6526
  var FormRenderer = class {
5874
6527
  constructor(container, schema, onSubmit, onDropdownValueChange, initialData) {
5875
6528
  __publicField(this, "container");
@@ -5914,15 +6567,35 @@ var FormRenderer = class {
5914
6567
  }
5915
6568
  fieldWrapper.className = spanClass;
5916
6569
  const modelKey = getModelKey(field);
5917
- const fieldEl = FieldRenderer.render(field, this.data[modelKey], (val) => {
5918
- this.data[modelKey] = val;
5919
- if (field.type === "select" && this.onDropdownValueChange) {
5920
- this.onDropdownValueChange({
5921
- fieldId: field.id,
5922
- value: val || ""
5923
- });
5924
- }
5925
- });
6570
+ let fieldValue;
6571
+ if (field.type === "number" && field.valueSource === "formula" && field.formula) {
6572
+ const computed = computeFormulaValue(field, this.schema, this.data);
6573
+ fieldValue = computed;
6574
+ this.data[modelKey] = computed;
6575
+ } else if (field.type === "image") {
6576
+ fieldValue = this.data[modelKey] ?? field.imageUrl ?? field.defaultValue;
6577
+ } else {
6578
+ fieldValue = this.data[modelKey];
6579
+ }
6580
+ const isFormulaField = field.type === "number" && field.valueSource === "formula";
6581
+ const fieldEl = FieldRenderer.render(
6582
+ field,
6583
+ fieldValue,
6584
+ (val) => {
6585
+ this.data[modelKey] = val;
6586
+ if (field.type === "select" && this.onDropdownValueChange) {
6587
+ this.onDropdownValueChange({
6588
+ fieldId: field.id,
6589
+ value: val || ""
6590
+ });
6591
+ }
6592
+ if (isFormulaDependency(this.schema, modelKey, field.id)) {
6593
+ this.render();
6594
+ }
6595
+ },
6596
+ isFormulaField
6597
+ // Formula fields are read-only
6598
+ );
5926
6599
  fieldWrapper.appendChild(fieldEl);
5927
6600
  grid.appendChild(fieldWrapper);
5928
6601
  });
@@ -5945,107 +6618,19 @@ var FormRenderer = class {
5945
6618
  const modelKey = getModelKey(field);
5946
6619
  const fieldValue = this.data[modelKey];
5947
6620
  const fieldElement = form.querySelector(`input[id*="${field.id}"], textarea[id*="${field.id}"], select[id*="${field.id}"]`);
5948
- if (!fieldElement) {
5949
- const altElement = Array.from(form.querySelectorAll("input, textarea, select")).find((el) => {
5950
- const wrapper = el.closest("div");
5951
- return wrapper && wrapper.textContent?.includes(field.label);
5952
- });
5953
- if (altElement) {
5954
- if (field.required && (!fieldValue || fieldValue === "" || Array.isArray(fieldValue) && fieldValue.length === 0)) {
5955
- isValid2 = false;
5956
- altElement.setCustomValidity("This field is required");
5957
- altElement.reportValidity();
5958
- invalidFields.push(altElement);
5959
- } else {
5960
- altElement.setCustomValidity("");
5961
- }
5962
- if ((field.type === "text" || field.type === "email") && fieldValue) {
5963
- const validationArray = convertValidationToArray(field.validation);
5964
- const patternRule = validationArray.find((v) => v.type === "pattern");
5965
- if (patternRule?.regex) {
5966
- try {
5967
- const regex = new RegExp(patternRule.regex);
5968
- if (!regex.test(String(fieldValue))) {
5969
- isValid2 = false;
5970
- altElement.setCustomValidity(patternRule.message || "Invalid format");
5971
- altElement.reportValidity();
5972
- invalidFields.push(altElement);
5973
- } else {
5974
- altElement.setCustomValidity("");
5975
- }
5976
- } catch (e2) {
5977
- }
5978
- }
5979
- }
5980
- if (field.type === "checkbox" && Array.isArray(fieldValue)) {
5981
- const validationArray = convertValidationToArray(field.validation);
5982
- const minSelectedRule = validationArray.find((v) => v.type === "minSelected");
5983
- const maxSelectedRule = validationArray.find((v) => v.type === "maxSelected");
5984
- const selectedCount = fieldValue.length;
5985
- const minSelected = typeof minSelectedRule?.value === "number" ? minSelectedRule.value : void 0;
5986
- const maxSelected = typeof maxSelectedRule?.value === "number" ? maxSelectedRule.value : void 0;
5987
- if (minSelected !== void 0 && selectedCount < minSelected) {
5988
- isValid2 = false;
5989
- altElement.setCustomValidity(`Please select at least ${minSelected} option(s)`);
5990
- altElement.reportValidity();
5991
- invalidFields.push(altElement);
5992
- } else if (maxSelected !== void 0 && selectedCount > maxSelected) {
5993
- isValid2 = false;
5994
- altElement.setCustomValidity(`Please select at most ${maxSelected} option(s)`);
5995
- altElement.reportValidity();
5996
- invalidFields.push(altElement);
5997
- } else {
5998
- altElement.setCustomValidity("");
5999
- }
6000
- }
6001
- }
6002
- return;
6003
- }
6004
- if (field.required && (!fieldValue || fieldValue === "" || Array.isArray(fieldValue) && fieldValue.length === 0)) {
6005
- isValid2 = false;
6006
- fieldElement.setCustomValidity("This field is required");
6007
- fieldElement.reportValidity();
6008
- invalidFields.push(fieldElement);
6009
- } else {
6010
- fieldElement.setCustomValidity("");
6011
- }
6012
- if ((field.type === "text" || field.type === "email") && fieldValue) {
6013
- const validationArray = convertValidationToArray(field.validation);
6014
- const patternRule = validationArray.find((v) => v.type === "pattern");
6015
- if (patternRule?.regex) {
6016
- try {
6017
- const regex = new RegExp(patternRule.regex);
6018
- if (!regex.test(String(fieldValue))) {
6019
- isValid2 = false;
6020
- fieldElement.setCustomValidity(patternRule.message || "Invalid format");
6021
- fieldElement.reportValidity();
6022
- invalidFields.push(fieldElement);
6023
- } else {
6024
- fieldElement.setCustomValidity("");
6025
- }
6026
- } catch (e2) {
6027
- }
6028
- }
6029
- }
6030
- if (field.type === "checkbox" && Array.isArray(fieldValue)) {
6031
- const validationArray = convertValidationToArray(field.validation);
6032
- const minSelectedRule = validationArray.find((v) => v.type === "minSelected");
6033
- const maxSelectedRule = validationArray.find((v) => v.type === "maxSelected");
6034
- const selectedCount = fieldValue.length;
6035
- const minSelected = typeof minSelectedRule?.value === "number" ? minSelectedRule.value : void 0;
6036
- const maxSelected = typeof maxSelectedRule?.value === "number" ? maxSelectedRule.value : void 0;
6037
- if (minSelected !== void 0 && selectedCount < minSelected) {
6038
- isValid2 = false;
6039
- fieldElement.setCustomValidity(`Please select at least ${minSelected} option(s)`);
6040
- fieldElement.reportValidity();
6041
- invalidFields.push(fieldElement);
6042
- } else if (maxSelected !== void 0 && selectedCount > maxSelected) {
6621
+ const fieldError = getFieldValidationError(field, fieldValue);
6622
+ const element = fieldElement ?? Array.from(form.querySelectorAll("input, textarea, select")).find((el) => {
6623
+ const wrapper = el.closest("div");
6624
+ return wrapper && wrapper.textContent?.includes(field.label);
6625
+ });
6626
+ if (element) {
6627
+ if (fieldError) {
6043
6628
  isValid2 = false;
6044
- fieldElement.setCustomValidity(`Please select at most ${maxSelected} option(s)`);
6045
- fieldElement.reportValidity();
6046
- invalidFields.push(fieldElement);
6629
+ element.setCustomValidity(fieldError);
6630
+ element.reportValidity();
6631
+ invalidFields.push(element);
6047
6632
  } else {
6048
- fieldElement.setCustomValidity("");
6633
+ element.setCustomValidity("");
6049
6634
  }
6050
6635
  }
6051
6636
  });
@@ -9065,6 +9650,36 @@ var FormBuilder = class {
9065
9650
  className: "flex items-center px-3 py-2 text-sm font-medium text-[#635bff] bg-[#e7e7ff] rounded-md shadow-sm transition-colors",
9066
9651
  onclick: () => {
9067
9652
  const schema = formStore.getState().schema;
9653
+ const numericFields = schema.sections.flatMap((s) => s.fields).filter((f) => f.type === "number");
9654
+ const allIds = numericFields.map((f) => f.id);
9655
+ const allNames = numericFields.map((f) => f.fieldName ?? f.id);
9656
+ for (const field of schema.sections.flatMap((s) => s.fields)) {
9657
+ if (field.type === "number" && field.valueSource === "formula" && field.formula) {
9658
+ const validation = validateFormula(field.formula, allIds, allNames, field.id);
9659
+ if (!validation.valid) {
9660
+ alert(`Formula error in "${field.label}": ${validation.error}`);
9661
+ return;
9662
+ }
9663
+ const deps = field.dependencies ?? parseFormulaDependencies(field.formula);
9664
+ if (detectCircularDependency(schema, field.id, field.formula, deps)) {
9665
+ alert(`Circular dependency in formula for "${field.label}"`);
9666
+ return;
9667
+ }
9668
+ }
9669
+ }
9670
+ schema.sections.forEach((section) => {
9671
+ section.fields?.forEach((field) => {
9672
+ if (field.type === "number" && field.validations) {
9673
+ console.log("[Form Builder] Number field validations before save:", {
9674
+ fieldId: field.id,
9675
+ label: field.label,
9676
+ validations: field.validations,
9677
+ hasMin: "min" in field.validations,
9678
+ hasMax: "max" in field.validations
9679
+ });
9680
+ }
9681
+ });
9682
+ });
9068
9683
  console.log("[Form Builder] Schema being sent to app:", JSON.stringify(schema, null, 2));
9069
9684
  if (this.options.onSave) {
9070
9685
  this.options.onSave(schema);
@@ -9271,17 +9886,178 @@ var FormBuilder = class {
9271
9886
  }
9272
9887
  }));
9273
9888
  body.appendChild(labelGroup);
9274
- const placeholderGroup = createElement("div");
9275
- placeholderGroup.appendChild(createElement("label", { className: "block text-sm font-normal text-gray-700 dark:text-gray-300 mb-1", text: "Placeholder" }));
9276
- placeholderGroup.appendChild(createElement("input", {
9277
- className: "w-full px-3 py-2 border border-gray-200 dark:border-gray-700 rounded-md bg-transparent",
9278
- value: selectedField.placeholder || "",
9279
- "data-focus-id": `field-placeholder-${selectedField.id}`,
9280
- oninput: (e) => {
9281
- formStore.getState().updateField(selectedField.id, { placeholder: e.target.value });
9889
+ if (selectedField.type === "number") {
9890
+ const valueSourceHeader = createElement("h3", { className: "text-xs font-semibold text-gray-500 uppercase tracking-wider mb-2 mt-4", text: "Value Source" });
9891
+ body.appendChild(valueSourceHeader);
9892
+ const valueSourceGroup = createElement("div", { className: "mb-3" });
9893
+ valueSourceGroup.appendChild(createElement("label", { className: "block text-sm font-normal text-gray-700 dark:text-gray-300 mb-1", text: "Source" }));
9894
+ const valueSourceSelect = createElement("select", {
9895
+ className: "w-full px-3 py-2 border border-gray-200 dark:border-gray-700 rounded-md bg-transparent",
9896
+ value: selectedField.valueSource || "manual",
9897
+ onchange: (e) => {
9898
+ const source = e.target.value;
9899
+ const updates = { valueSource: source };
9900
+ if (source === "manual") {
9901
+ updates.formula = void 0;
9902
+ updates.dependencies = void 0;
9903
+ } else if (source === "formula") {
9904
+ updates.formula = selectedField.formula || "";
9905
+ updates.dependencies = selectedField.dependencies || [];
9906
+ }
9907
+ formStore.getState().updateField(selectedField.id, updates);
9908
+ this.render();
9909
+ }
9910
+ });
9911
+ valueSourceSelect.appendChild(createElement("option", { value: "manual", text: "Manual", selected: (selectedField.valueSource || "manual") === "manual" }));
9912
+ valueSourceSelect.appendChild(createElement("option", { value: "formula", text: "Formula", selected: selectedField.valueSource === "formula" }));
9913
+ valueSourceGroup.appendChild(valueSourceSelect);
9914
+ body.appendChild(valueSourceGroup);
9915
+ if (selectedField.valueSource === "formula") {
9916
+ const schema = formStore.getState().schema;
9917
+ const numericFields = getNumericFieldsForFormula(schema, selectedField.id);
9918
+ const availableIds = numericFields.map((f) => f.id);
9919
+ const availableNames = numericFields.map((f) => f.fieldName);
9920
+ const formulaGroup = createElement("div", { className: "mb-3" });
9921
+ formulaGroup.appendChild(createElement("label", { className: "block text-sm font-normal text-gray-700 dark:text-gray-300 mb-1", text: "Formula" }));
9922
+ const formulaInput = createElement("input", {
9923
+ type: "text",
9924
+ className: "w-full px-3 py-2 border border-gray-200 dark:border-gray-700 rounded-md bg-transparent font-mono text-sm",
9925
+ value: selectedField.formula || "",
9926
+ placeholder: "e.g. quantity * price",
9927
+ "data-focus-id": `field-formula-${selectedField.id}`,
9928
+ oninput: (e) => {
9929
+ const formula = e.target.value.trim();
9930
+ const deps = parseFormulaDependencies(formula);
9931
+ const validation = validateFormula(formula, availableIds, availableNames, selectedField.id);
9932
+ const hasCircular = deps.length > 0 && detectCircularDependency(schema, selectedField.id, formula, deps);
9933
+ const errEl = formulaGroup.querySelector(".formula-error");
9934
+ if (errEl) {
9935
+ if (validation.valid && !hasCircular) {
9936
+ errEl.textContent = "";
9937
+ errEl.classList.add("hidden");
9938
+ } else {
9939
+ errEl.textContent = !validation.valid ? validation.error : "Circular dependency detected";
9940
+ errEl.classList.remove("hidden");
9941
+ }
9942
+ }
9943
+ formStore.getState().updateField(selectedField.id, { formula, dependencies: deps });
9944
+ }
9945
+ });
9946
+ formulaGroup.appendChild(formulaInput);
9947
+ const formulaError = createElement("div", { className: "text-xs text-red-600 dark:text-red-400 mt-1 formula-error hidden" });
9948
+ formulaGroup.appendChild(formulaError);
9949
+ body.appendChild(formulaGroup);
9950
+ const insertGroup = createElement("div", { className: "mb-3" });
9951
+ insertGroup.appendChild(createElement("label", { className: "block text-sm font-normal text-gray-700 dark:text-gray-300 mb-1", text: "Insert Field" }));
9952
+ const insertSelect = createElement("select", {
9953
+ className: "w-full px-3 py-2 border border-gray-200 dark:border-gray-700 rounded-md bg-transparent",
9954
+ onchange: (e) => {
9955
+ const sel = e.target;
9956
+ const ref = sel.value;
9957
+ if (!ref)
9958
+ return;
9959
+ const current = selectedField.formula || "";
9960
+ const insert = current ? ` ${ref} ` : ref;
9961
+ const newFormula = current + insert;
9962
+ formStore.getState().updateField(selectedField.id, {
9963
+ formula: newFormula,
9964
+ dependencies: parseFormulaDependencies(newFormula)
9965
+ });
9966
+ formulaInput.value = newFormula;
9967
+ sel.value = "";
9968
+ this.render();
9969
+ }
9970
+ });
9971
+ insertSelect.appendChild(createElement("option", { value: "", text: "Select field to insert...", selected: true }));
9972
+ numericFields.forEach((f) => {
9973
+ const ref = f.fieldName !== f.id ? f.fieldName : f.id;
9974
+ insertSelect.appendChild(createElement("option", { value: ref, text: `${f.label} (${ref})` }));
9975
+ });
9976
+ insertGroup.appendChild(insertSelect);
9977
+ body.appendChild(insertGroup);
9978
+ const hintEl = createElement("p", {
9979
+ className: "text-xs text-gray-500 dark:text-gray-400 mb-2",
9980
+ text: "Use +, -, *, / and parentheses. Reference fields by their name or ID."
9981
+ });
9982
+ body.appendChild(hintEl);
9282
9983
  }
9283
- }));
9284
- body.appendChild(placeholderGroup);
9984
+ }
9985
+ if (selectedField.type !== "image") {
9986
+ const placeholderGroup = createElement("div");
9987
+ placeholderGroup.appendChild(createElement("label", { className: "block text-sm font-normal text-gray-700 dark:text-gray-300 mb-1", text: "Placeholder" }));
9988
+ placeholderGroup.appendChild(createElement("input", {
9989
+ className: "w-full px-3 py-2 border border-gray-200 dark:border-gray-700 rounded-md bg-transparent",
9990
+ value: selectedField.placeholder || "",
9991
+ "data-focus-id": `field-placeholder-${selectedField.id}`,
9992
+ oninput: (e) => {
9993
+ formStore.getState().updateField(selectedField.id, { placeholder: e.target.value });
9994
+ }
9995
+ }));
9996
+ body.appendChild(placeholderGroup);
9997
+ }
9998
+ if (selectedField.type === "image") {
9999
+ const imageUrl = selectedField.imageUrl ?? selectedField.defaultValue;
10000
+ const imageGroup = createElement("div", { className: "mb-4" });
10001
+ imageGroup.appendChild(createElement("label", { className: "block text-sm font-normal text-gray-700 dark:text-gray-300 mb-2", text: "Image" }));
10002
+ const previewWrap = createElement("div", {
10003
+ className: "rounded-md border border-gray-200 dark:border-gray-700 bg-gray-50 dark:bg-gray-800 overflow-hidden min-h-[80px] flex items-center justify-center mb-2"
10004
+ });
10005
+ if (imageUrl) {
10006
+ const img = createElement("img", {
10007
+ src: imageUrl,
10008
+ alt: selectedField.label || "Image",
10009
+ className: "max-h-32 max-w-full object-contain"
10010
+ });
10011
+ img.onerror = () => {
10012
+ previewWrap.innerHTML = "";
10013
+ previewWrap.appendChild(createElement("p", { className: "text-xs text-red-500 p-2", text: "Failed to load" }));
10014
+ };
10015
+ previewWrap.appendChild(img);
10016
+ } else {
10017
+ previewWrap.appendChild(createElement("p", { className: "text-xs text-muted-foreground p-2", text: "No image" }));
10018
+ }
10019
+ imageGroup.appendChild(previewWrap);
10020
+ const btnRow = createElement("div", { className: "flex gap-2" });
10021
+ const fileInput = createElement("input", {
10022
+ type: "file",
10023
+ accept: "image/jpeg,image/png,image/gif,image/webp",
10024
+ className: "hidden",
10025
+ id: `config-image-${selectedField.id}`
10026
+ });
10027
+ fileInput.onchange = (e) => {
10028
+ const file = e.target.files?.[0];
10029
+ if (!file || !file.type.match(/^image\/(jpeg|png|gif|webp)$/))
10030
+ return;
10031
+ if (file.size > 5 * 1024 * 1024) {
10032
+ alert("Image must be under 5MB");
10033
+ return;
10034
+ }
10035
+ const reader = new FileReader();
10036
+ reader.onload = () => {
10037
+ const base64 = reader.result;
10038
+ if (base64)
10039
+ formStore.getState().updateField(selectedField.id, { imageUrl: base64, defaultValue: base64 });
10040
+ };
10041
+ reader.readAsDataURL(file);
10042
+ e.target.value = "";
10043
+ };
10044
+ btnRow.appendChild(fileInput);
10045
+ btnRow.appendChild(createElement("button", {
10046
+ type: "button",
10047
+ className: "px-3 py-2 text-sm border border-gray-300 dark:border-gray-700 rounded-md hover:bg-gray-50 dark:hover:bg-gray-800",
10048
+ text: imageUrl ? "Replace" : "Upload",
10049
+ onclick: () => fileInput.click()
10050
+ }));
10051
+ btnRow.appendChild(createElement("button", {
10052
+ type: "button",
10053
+ className: "px-3 py-2 text-sm border border-red-200 text-red-600 rounded-md hover:bg-red-50 dark:hover:bg-red-900/20",
10054
+ text: "Remove",
10055
+ disabled: !imageUrl,
10056
+ onclick: () => formStore.getState().updateField(selectedField.id, { imageUrl: void 0, defaultValue: void 0 })
10057
+ }));
10058
+ imageGroup.appendChild(btnRow);
10059
+ body.appendChild(imageGroup);
10060
+ }
9285
10061
  const layoutGroup = createElement("div", { className: "layout-span-group" });
9286
10062
  const layoutLabelRow = createElement("div", { className: "flex items-center justify-between mb-2" });
9287
10063
  layoutLabelRow.appendChild(createElement("label", { className: "text-sm font-medium text-gray-700 dark:text-gray-300", text: "Grid Span" }));
@@ -9326,8 +10102,14 @@ var FormBuilder = class {
9326
10102
  body.appendChild(layoutGroup);
9327
10103
  body.appendChild(this.createCheckboxField(
9328
10104
  "Required",
9329
- !!selectedField.required,
9330
- (checked) => formStore.getState().updateField(selectedField.id, { required: checked }),
10105
+ !!selectedField.required || !!selectedField.validations?.required,
10106
+ (checked) => {
10107
+ const currentValidations = selectedField.validations || {};
10108
+ formStore.getState().updateField(selectedField.id, {
10109
+ required: checked,
10110
+ validations: { ...currentValidations, required: checked }
10111
+ });
10112
+ },
9331
10113
  `required-${selectedField.id}`
9332
10114
  ));
9333
10115
  body.appendChild(this.createCheckboxField(
@@ -9697,7 +10479,9 @@ var FormBuilder = class {
9697
10479
  `custom-options-${selectedField.id}`
9698
10480
  ));
9699
10481
  }
9700
- const shouldShowOptions = selectedField.type === "select" ? selectedField.customOptionsEnabled && (selectedField.optionSource === "STATIC" || !selectedField.optionSource) : true;
10482
+ const isStaticSelect = selectedField.type === "select" && (selectedField.optionSource === "STATIC" || !selectedField.optionSource);
10483
+ const hasOptions = selectedField.options && selectedField.options.length > 0;
10484
+ const shouldShowOptions = selectedField.type === "select" ? isStaticSelect && (!!selectedField.customOptionsEnabled || !!hasOptions) : true;
9701
10485
  if (shouldShowOptions) {
9702
10486
  const options = selectedField.options || [];
9703
10487
  const fieldId2 = selectedField.id;
@@ -9739,12 +10523,16 @@ var FormBuilder = class {
9739
10523
  }
9740
10524
  });
9741
10525
  const deleteBtn = createElement("button", {
10526
+ type: "button",
9742
10527
  className: "p-1.5 text-red-600 hover:bg-red-50 rounded transition-colors",
9743
10528
  title: "Delete option",
9744
- onclick: () => {
10529
+ onclick: (e) => {
10530
+ e.preventDefault();
10531
+ e.stopPropagation();
9745
10532
  const currentOptions = getCurrentOptions();
9746
- const newOptions = currentOptions.filter((_, i) => i !== index2);
10533
+ const newOptions = currentOptions.filter((o) => o.value !== opt.value);
9747
10534
  formStore.getState().updateField(fieldId2, { options: newOptions });
10535
+ this.render();
9748
10536
  }
9749
10537
  }, [getIcon("Trash2", 14)]);
9750
10538
  optionRow.appendChild(labelInput);
@@ -9768,40 +10556,67 @@ var FormBuilder = class {
9768
10556
  body.appendChild(addOptionBtn);
9769
10557
  }
9770
10558
  }
9771
- const validationObj = Array.isArray(selectedField.validation) ? (() => {
9772
- const obj = {};
9773
- selectedField.validation.forEach((rule) => {
9774
- if (rule.type === "required")
9775
- obj.required = true;
9776
- else if (rule.type === "pattern" && rule.regex) {
9777
- obj.regex = rule.regex;
9778
- obj.regexMessage = rule.message;
9779
- } else if (rule.type === "minLength" && typeof rule.value === "number")
9780
- obj.minLength = rule.value;
9781
- else if (rule.type === "maxLength" && typeof rule.value === "number")
9782
- obj.maxLength = rule.value;
9783
- else if (rule.type === "minSelected" && typeof rule.value === "number")
9784
- obj.minSelected = rule.value;
9785
- else if (rule.type === "maxSelected" && typeof rule.value === "number")
9786
- obj.maxSelected = rule.value;
9787
- else if (rule.type === "minDate" && typeof rule.value === "string")
9788
- obj.minDate = rule.value;
9789
- else if (rule.type === "maxDate" && typeof rule.value === "string")
9790
- obj.maxDate = rule.value;
9791
- });
9792
- return obj;
9793
- })() : selectedField.validation || {};
9794
- const updateValidation = (updates) => {
9795
- const newValidation = { ...validationObj, ...updates };
9796
- Object.keys(newValidation).forEach((key) => {
9797
- if (newValidation[key] === void 0) {
9798
- delete newValidation[key];
10559
+ const validationsObj = selectedField.validations || (() => {
10560
+ const v = selectedField.validation;
10561
+ if (!v)
10562
+ return {};
10563
+ if (Array.isArray(v)) {
10564
+ const obj = {};
10565
+ v.forEach((rule) => {
10566
+ if (rule.type === "required")
10567
+ obj.required = true;
10568
+ else if (rule.type === "pattern" && rule.regex) {
10569
+ obj.pattern = rule.regex;
10570
+ if (rule.message)
10571
+ obj.customErrorMessages = { ...obj.customErrorMessages, pattern: rule.message };
10572
+ } else if (rule.type === "minLength" && typeof rule.value === "number")
10573
+ obj.minLength = rule.value;
10574
+ else if (rule.type === "maxLength" && typeof rule.value === "number")
10575
+ obj.maxLength = rule.value;
10576
+ else if (rule.type === "min" && typeof rule.value === "number")
10577
+ obj.min = rule.value;
10578
+ else if (rule.type === "max" && typeof rule.value === "number")
10579
+ obj.max = rule.value;
10580
+ else if (rule.type === "minSelected" && typeof rule.value === "number")
10581
+ obj.minSelected = rule.value;
10582
+ else if (rule.type === "maxSelected" && typeof rule.value === "number")
10583
+ obj.maxSelected = rule.value;
10584
+ else if (rule.type === "minDate" && typeof rule.value === "string")
10585
+ obj.minDate = rule.value;
10586
+ else if (rule.type === "maxDate" && typeof rule.value === "string")
10587
+ obj.maxDate = rule.value;
10588
+ });
10589
+ return obj;
10590
+ }
10591
+ const o = v;
10592
+ return {
10593
+ required: o.required,
10594
+ pattern: o.regex,
10595
+ minLength: o.minLength,
10596
+ maxLength: o.maxLength,
10597
+ min: o.min,
10598
+ max: o.max,
10599
+ minSelected: o.minSelected,
10600
+ maxSelected: o.maxSelected,
10601
+ minDate: o.minDate,
10602
+ maxDate: o.maxDate,
10603
+ customErrorMessages: o.regexMessage ? { pattern: o.regexMessage } : void 0
10604
+ };
10605
+ })();
10606
+ const updateValidations = (updates) => {
10607
+ const currentField = formStore.getState().schema.sections.flatMap((s) => s.fields).find((f) => f.id === selectedField.id);
10608
+ const currentValidations = currentField?.validations ? { ...currentField.validations } : { ...validationsObj };
10609
+ const newValidations = { ...currentValidations, ...updates };
10610
+ Object.keys(newValidations).forEach((key) => {
10611
+ const v = newValidations[key];
10612
+ if (v === void 0 || v === null) {
10613
+ delete newValidations[key];
9799
10614
  }
9800
10615
  });
9801
- formStore.getState().updateField(selectedField.id, { validation: newValidation });
10616
+ formStore.getState().updateField(selectedField.id, { validations: newValidations });
9802
10617
  };
9803
- const getRuleValue = (key) => {
9804
- const value = validationObj[key];
10618
+ const getValidationsValue = (key) => {
10619
+ const value = validationsObj[key];
9805
10620
  if (value === void 0 || value === null)
9806
10621
  return "";
9807
10622
  if (typeof value === "number")
@@ -9811,17 +10626,139 @@ var FormBuilder = class {
9811
10626
  return String(value);
9812
10627
  };
9813
10628
  const validationElements = [];
9814
- if (["text", "textarea", "email", "password"].includes(selectedField.type)) {
10629
+ if (selectedField.type === "number") {
10630
+ const numValidationTypeGroup = createElement("div", { className: "mb-3" });
10631
+ numValidationTypeGroup.appendChild(createElement("label", { className: "block text-sm font-normal text-gray-700 dark:text-gray-300 mb-1", text: "Validation Type" }));
10632
+ const numValidationTypeSelect = createElement("select", {
10633
+ className: "w-full px-3 py-2 border border-gray-200 dark:border-gray-700 rounded-md bg-transparent",
10634
+ onchange: (e) => {
10635
+ const presetId = e.target.value;
10636
+ if (presetId) {
10637
+ const preset = VALIDATION_TYPE_PRESETS[presetId];
10638
+ if (preset && presetId === "amount") {
10639
+ updateValidations({ ...preset, validationType: presetId });
10640
+ }
10641
+ } else {
10642
+ updateValidations({ validationType: "custom" });
10643
+ }
10644
+ }
10645
+ });
10646
+ [
10647
+ { value: "", text: "Custom" },
10648
+ { value: "amount", text: "Amount (min 0, 2 decimals)" }
10649
+ ].forEach((opt) => {
10650
+ numValidationTypeSelect.appendChild(createElement("option", {
10651
+ value: opt.value,
10652
+ text: opt.text,
10653
+ selected: validationsObj.validationType === opt.value || !validationsObj.validationType && opt.value === ""
10654
+ }));
10655
+ });
10656
+ numValidationTypeGroup.appendChild(numValidationTypeSelect);
10657
+ validationElements.push(numValidationTypeGroup);
10658
+ const minValGroup = createElement("div", { className: "mb-3" });
10659
+ minValGroup.appendChild(createElement("label", { className: "block text-sm font-normal text-gray-700 dark:text-gray-300 mb-1", text: "Min Value" }));
10660
+ minValGroup.appendChild(createElement("input", {
10661
+ type: "number",
10662
+ className: "w-full px-3 py-2 border border-gray-200 dark:border-gray-700 rounded-md bg-transparent",
10663
+ value: getValidationsValue("min") || "",
10664
+ placeholder: "e.g. 0",
10665
+ oninput: (e) => {
10666
+ const val = e.target.value;
10667
+ updateValidations({ min: val !== "" ? parseFloat(val) : void 0 });
10668
+ }
10669
+ }));
10670
+ validationElements.push(minValGroup);
10671
+ const maxValGroup = createElement("div", { className: "mb-3" });
10672
+ maxValGroup.appendChild(createElement("label", { className: "block text-sm font-normal text-gray-700 dark:text-gray-300 mb-1", text: "Max Value" }));
10673
+ maxValGroup.appendChild(createElement("input", {
10674
+ type: "number",
10675
+ className: "w-full px-3 py-2 border border-gray-200 dark:border-gray-700 rounded-md bg-transparent",
10676
+ value: getValidationsValue("max") || "",
10677
+ placeholder: "e.g. 100",
10678
+ oninput: (e) => {
10679
+ const val = e.target.value;
10680
+ updateValidations({ max: val !== "" ? parseFloat(val) : void 0 });
10681
+ }
10682
+ }));
10683
+ validationElements.push(maxValGroup);
10684
+ validationElements.push(this.createCheckboxField(
10685
+ "Allow Decimal",
10686
+ validationsObj.allowDecimal === true,
10687
+ (checked) => updateValidations({
10688
+ allowDecimal: checked,
10689
+ // When unchecked, remove decimalPlaces so it's not in the payload
10690
+ decimalPlaces: checked ? validationsObj.decimalPlaces ?? 2 : void 0
10691
+ }),
10692
+ `allow-decimal-${selectedField.id}`
10693
+ ));
10694
+ const decimalPlacesGroup = createElement("div", { className: "mb-3" });
10695
+ decimalPlacesGroup.appendChild(createElement("label", { className: "block text-sm font-normal text-gray-700 dark:text-gray-300 mb-1", text: "Decimal Places" }));
10696
+ const decimalPlacesInput = createElement("input", {
10697
+ type: "number",
10698
+ className: "w-full px-3 py-2 border border-gray-200 dark:border-gray-700 rounded-md bg-transparent disabled:opacity-50 disabled:cursor-not-allowed",
10699
+ value: validationsObj.allowDecimal === true ? String(validationsObj.decimalPlaces ?? 2) : "",
10700
+ placeholder: "e.g. 2",
10701
+ min: "0",
10702
+ max: "10",
10703
+ disabled: validationsObj.allowDecimal !== true,
10704
+ oninput: (e) => {
10705
+ const val = e.target.value;
10706
+ updateValidations({ decimalPlaces: val !== "" ? parseInt(val) : void 0 });
10707
+ }
10708
+ });
10709
+ decimalPlacesGroup.appendChild(decimalPlacesInput);
10710
+ validationElements.push(decimalPlacesGroup);
10711
+ validationElements.push(this.createCheckboxField(
10712
+ "Allow Negative",
10713
+ validationsObj.allowNegative === true,
10714
+ (checked) => updateValidations({ allowNegative: checked }),
10715
+ `allow-negative-${selectedField.id}`
10716
+ ));
10717
+ }
10718
+ if (["text", "textarea", "email", "phone"].includes(selectedField.type)) {
10719
+ if (selectedField.type === "text" || selectedField.type === "phone") {
10720
+ const validationTypeGroup = createElement("div", { className: "mb-3" });
10721
+ validationTypeGroup.appendChild(createElement("label", { className: "block text-sm font-normal text-gray-700 dark:text-gray-300 mb-1", text: "Validation Type" }));
10722
+ const validationTypeSelect = createElement("select", {
10723
+ className: "w-full px-3 py-2 border border-gray-200 dark:border-gray-700 rounded-md bg-transparent",
10724
+ onchange: (e) => {
10725
+ const presetId = e.target.value;
10726
+ if (presetId) {
10727
+ const preset = VALIDATION_TYPE_PRESETS[presetId];
10728
+ if (preset) {
10729
+ updateValidations({ ...preset, validationType: presetId });
10730
+ }
10731
+ } else {
10732
+ updateValidations({ validationType: "custom" });
10733
+ }
10734
+ }
10735
+ });
10736
+ const options = [
10737
+ { value: "", text: "Custom" },
10738
+ { value: "postalCode", text: "Postal Code (6 digit)" },
10739
+ { value: "phoneNumber", text: "Phone Number (10 digit)" },
10740
+ { value: "otp", text: "OTP (4/6 digit)" }
10741
+ ];
10742
+ options.forEach((opt) => {
10743
+ validationTypeSelect.appendChild(createElement("option", {
10744
+ value: opt.value,
10745
+ text: opt.text,
10746
+ selected: validationsObj.validationType === opt.value || !validationsObj.validationType && opt.value === ""
10747
+ }));
10748
+ });
10749
+ validationTypeGroup.appendChild(validationTypeSelect);
10750
+ validationElements.push(validationTypeGroup);
10751
+ }
9815
10752
  const minLenGroup = createElement("div", { className: "mb-3" });
9816
10753
  minLenGroup.appendChild(createElement("label", { className: "block text-sm font-normal text-gray-700 dark:text-gray-300 mb-1", text: "Min Length" }));
9817
10754
  minLenGroup.appendChild(createElement("input", {
9818
10755
  type: "number",
9819
10756
  className: "w-full px-3 py-2 border border-gray-200 dark:border-gray-700 rounded-md bg-transparent",
9820
- value: getRuleValue("minLength") || "",
10757
+ value: getValidationsValue("minLength") || "",
9821
10758
  placeholder: "e.g. 3",
9822
- onchange: (e) => {
10759
+ oninput: (e) => {
9823
10760
  const value = e.target.value;
9824
- updateValidation({ minLength: value ? parseInt(value) : void 0 });
10761
+ updateValidations({ minLength: value !== "" ? parseInt(value) : void 0 });
9825
10762
  }
9826
10763
  }));
9827
10764
  validationElements.push(minLenGroup);
@@ -9830,11 +10767,11 @@ var FormBuilder = class {
9830
10767
  maxLenGroup.appendChild(createElement("input", {
9831
10768
  type: "number",
9832
10769
  className: "w-full px-3 py-2 border border-gray-200 dark:border-gray-700 rounded-md bg-transparent",
9833
- value: getRuleValue("maxLength") || "",
10770
+ value: getValidationsValue("maxLength") || "",
9834
10771
  placeholder: "e.g. 100",
9835
- onchange: (e) => {
10772
+ oninput: (e) => {
9836
10773
  const value = e.target.value;
9837
- updateValidation({ maxLength: value ? parseInt(value) : void 0 });
10774
+ updateValidations({ maxLength: value !== "" ? parseInt(value) : void 0 });
9838
10775
  }
9839
10776
  }));
9840
10777
  validationElements.push(maxLenGroup);
@@ -9894,10 +10831,11 @@ var FormBuilder = class {
9894
10831
  examplesContainer.appendChild(examplesList);
9895
10832
  regexGroup.appendChild(examplesContainer);
9896
10833
  }
9897
- const currentRegex = validationObj.regex || "";
10834
+ const currentRegex = validationsObj.pattern || selectedField.validation?.regex || "";
9898
10835
  const findPresetByRegex = (regex) => {
9899
10836
  return REGEX_PRESETS.find((preset) => preset.pattern === regex);
9900
10837
  };
10838
+ const regexMessage = validationsObj.customErrorMessages?.pattern || selectedField.validation?.regexMessage || "Invalid format";
9901
10839
  let currentPreset = currentRegex ? findPresetByRegex(currentRegex) : void 0;
9902
10840
  let selectedPresetId = currentPreset?.id || "";
9903
10841
  let regexInput;
@@ -9912,9 +10850,9 @@ var FormBuilder = class {
9912
10850
  selectedPresetId = presetId;
9913
10851
  const preset = REGEX_PRESETS.find((p) => p.id === presetId);
9914
10852
  if (preset) {
9915
- updateValidation({
9916
- regex: preset.pattern,
9917
- regexMessage: preset.errorMessage
10853
+ updateValidations({
10854
+ pattern: preset.pattern,
10855
+ customErrorMessages: { ...validationsObj.customErrorMessages, pattern: preset.errorMessage }
9918
10856
  });
9919
10857
  regexInput.value = preset.pattern;
9920
10858
  currentPreset = preset;
@@ -9969,9 +10907,9 @@ var FormBuilder = class {
9969
10907
  }
9970
10908
  }
9971
10909
  }
9972
- updateValidation({
9973
- regex: val || void 0,
9974
- regexMessage: currentPreset?.errorMessage || validationObj.regexMessage || "Invalid format"
10910
+ updateValidations({
10911
+ pattern: val || void 0,
10912
+ customErrorMessages: { ...validationsObj.customErrorMessages, pattern: currentPreset?.errorMessage || regexMessage || "Invalid format" }
9975
10913
  });
9976
10914
  if (examplesList) {
9977
10915
  if (currentPreset) {
@@ -9994,6 +10932,21 @@ var FormBuilder = class {
9994
10932
  updateExamples(examplesList, currentRegex);
9995
10933
  }
9996
10934
  }
10935
+ const patternMsgGroup = createElement("div", { className: "mb-3 mt-2" });
10936
+ patternMsgGroup.appendChild(createElement("label", { className: "block text-xs font-medium text-gray-600 dark:text-gray-400 mb-1", text: "Pattern Error Message" }));
10937
+ patternMsgGroup.appendChild(createElement("input", {
10938
+ type: "text",
10939
+ className: "w-full px-3 py-2 border border-gray-200 dark:border-gray-700 rounded-md bg-transparent text-sm",
10940
+ value: validationsObj.customErrorMessages?.pattern || "",
10941
+ placeholder: "e.g. Invalid format",
10942
+ oninput: (e) => {
10943
+ const val = e.target.value;
10944
+ updateValidations({
10945
+ customErrorMessages: { ...validationsObj.customErrorMessages, pattern: val || void 0 }
10946
+ });
10947
+ }
10948
+ }));
10949
+ regexGroup.appendChild(patternMsgGroup);
9997
10950
  validationElements.push(regexGroup);
9998
10951
  }
9999
10952
  if (selectedField.type === "checkbox") {
@@ -10002,12 +10955,12 @@ var FormBuilder = class {
10002
10955
  minSelectedGroup.appendChild(createElement("input", {
10003
10956
  type: "number",
10004
10957
  className: "w-full px-3 py-2 border border-gray-200 dark:border-gray-700 rounded-md bg-transparent",
10005
- value: getRuleValue("minSelected"),
10958
+ value: getValidationsValue("minSelected"),
10006
10959
  placeholder: "e.g. 1",
10007
10960
  min: "0",
10008
10961
  onchange: (e) => {
10009
10962
  const val = e.target.value;
10010
- updateValidation({ minSelected: val ? parseInt(val) : void 0 });
10963
+ updateValidations({ minSelected: val ? parseInt(val) : void 0 });
10011
10964
  }
10012
10965
  }));
10013
10966
  validationElements.push(minSelectedGroup);
@@ -10016,12 +10969,12 @@ var FormBuilder = class {
10016
10969
  maxSelectedGroup.appendChild(createElement("input", {
10017
10970
  type: "number",
10018
10971
  className: "w-full px-3 py-2 border border-gray-200 dark:border-gray-700 rounded-md bg-transparent",
10019
- value: getRuleValue("maxSelected"),
10972
+ value: getValidationsValue("maxSelected"),
10020
10973
  placeholder: "e.g. 2",
10021
10974
  min: "1",
10022
10975
  onchange: (e) => {
10023
10976
  const val = e.target.value;
10024
- updateValidation({ maxSelected: val ? parseInt(val) : void 0 });
10977
+ updateValidations({ maxSelected: val ? parseInt(val) : void 0 });
10025
10978
  }
10026
10979
  }));
10027
10980
  validationElements.push(maxSelectedGroup);
@@ -10032,10 +10985,10 @@ var FormBuilder = class {
10032
10985
  minDateGroup.appendChild(createElement("input", {
10033
10986
  type: "date",
10034
10987
  className: "w-full px-3 py-2 border border-gray-200 dark:border-gray-700 rounded-md bg-transparent",
10035
- value: validationObj.minDate || "",
10988
+ value: validationsObj.minDate || "",
10036
10989
  onchange: (e) => {
10037
10990
  const val = e.target.value;
10038
- updateValidation({ minDate: val || void 0 });
10991
+ updateValidations({ minDate: val || void 0 });
10039
10992
  }
10040
10993
  }));
10041
10994
  validationElements.push(minDateGroup);
@@ -10044,10 +10997,10 @@ var FormBuilder = class {
10044
10997
  maxDateGroup.appendChild(createElement("input", {
10045
10998
  type: "date",
10046
10999
  className: "w-full px-3 py-2 border border-gray-200 dark:border-gray-700 rounded-md bg-transparent",
10047
- value: validationObj.maxDate || "",
11000
+ value: validationsObj.maxDate || "",
10048
11001
  onchange: (e) => {
10049
11002
  const val = e.target.value;
10050
- updateValidation({ maxDate: val || void 0 });
11003
+ updateValidations({ maxDate: val || void 0 });
10051
11004
  }
10052
11005
  }));
10053
11006
  validationElements.push(maxDateGroup);
@@ -10338,6 +11291,6 @@ sortablejs/modular/sortable.esm.js:
10338
11291
  *)
10339
11292
  */
10340
11293
 
10341
- export { FormBuilder, FormRenderer, FormSchemaValidation, builderToPlatform, cleanFormSchema, convertValidationObjectToArray, formStore, getColSpanFromWidth, initFormBuilder, parseWidth, platformToBuilder };
11294
+ export { FormBuilder, FormRenderer, FormSchemaValidation, builderToPlatform, cleanFormSchema, convertValidationObjectToArray, detectCircularDependency, evaluateFormula, formStore, getColSpanFromWidth, getNumericFieldsForFormula, getValidationConfigForAngular, initFormBuilder, parseFormulaDependencies, parseWidth, platformToBuilder, validateFormula };
10342
11295
  //# sourceMappingURL=out.js.map
10343
11296
  //# sourceMappingURL=index.mjs.map