form-builder-pro 1.3.4 → 1.3.6

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.js CHANGED
@@ -4117,6 +4117,7 @@ var FIELD_TYPES = [
4117
4117
  { type: "email", label: "Email", icon: "Mail" },
4118
4118
  { type: "phone", label: "Phone", icon: "Phone" },
4119
4119
  { type: "date", label: "Date Picker", icon: "Calendar" },
4120
+ { type: "datetime", label: "Date & Time", icon: "Clock" },
4120
4121
  { type: "select", label: "Dropdown", icon: "ListBullet" },
4121
4122
  { type: "checkbox", label: "Checkbox", icon: "CheckSquare" },
4122
4123
  { type: "radio", label: "Radio Group", icon: "CircleDot" },
@@ -4146,6 +4147,7 @@ var DEFAULT_FIELD_CONFIG = {
4146
4147
  }
4147
4148
  },
4148
4149
  date: { label: "Date", width: "50%", enabled: true, visible: true },
4150
+ datetime: { label: "Date & Time", placeholder: "Select date and time", width: "50%", enabled: true, visible: true },
4149
4151
  select: { label: "Dropdown", options: [], width: "100%", enabled: true, visible: true, optionSource: "STATIC" },
4150
4152
  checkbox: { label: "Checkbox", options: [], width: "100%", enabled: true, visible: true },
4151
4153
  radio: { label: "Radio Group", options: [], width: "100%", enabled: true, visible: true },
@@ -4362,6 +4364,10 @@ function validationsToValidationObject(v) {
4362
4364
  obj.minDate = v.minDate;
4363
4365
  if (v.maxDate)
4364
4366
  obj.maxDate = v.maxDate;
4367
+ if (v.minDateTime)
4368
+ obj.minDateTime = v.minDateTime;
4369
+ if (v.maxDateTime)
4370
+ obj.maxDateTime = v.maxDateTime;
4365
4371
  return Object.keys(obj).length > 0 ? obj : void 0;
4366
4372
  }
4367
4373
  function validationObjectToValidations(v) {
@@ -4394,6 +4400,10 @@ function validationObjectToValidations(v) {
4394
4400
  validations.minDate = v.minDate;
4395
4401
  if (v.maxDate)
4396
4402
  validations.maxDate = v.maxDate;
4403
+ if (vAny.minDateTime)
4404
+ validations.minDateTime = vAny.minDateTime;
4405
+ if (vAny.maxDateTime)
4406
+ validations.maxDateTime = vAny.maxDateTime;
4397
4407
  return Object.keys(validations).length > 0 ? validations : void 0;
4398
4408
  }
4399
4409
  function convertValidationObjectToArray(validationObj) {
@@ -4404,7 +4414,7 @@ function convertValidationObjectToArray(validationObj) {
4404
4414
  }
4405
4415
  const rules = [];
4406
4416
  const obj = validationObj;
4407
- 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);
4417
+ 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 || obj.minDate || obj.maxDate || obj.minDateTime || obj.maxDateTime);
4408
4418
  const isRequired = obj.required === true || hasValidationProperties && obj.required !== false;
4409
4419
  if (isRequired) {
4410
4420
  rules.push({ type: "required", value: true });
@@ -4434,6 +4444,18 @@ function convertValidationObjectToArray(validationObj) {
4434
4444
  if (obj.maxSelected !== void 0) {
4435
4445
  rules.push({ type: "maxSelected", value: obj.maxSelected });
4436
4446
  }
4447
+ if (obj.minDate && typeof obj.minDate === "string") {
4448
+ rules.push({ type: "minDate", value: obj.minDate });
4449
+ }
4450
+ if (obj.maxDate && typeof obj.maxDate === "string") {
4451
+ rules.push({ type: "maxDate", value: obj.maxDate });
4452
+ }
4453
+ if (obj.minDateTime && typeof obj.minDateTime === "string") {
4454
+ rules.push({ type: "minDateTime", value: obj.minDateTime });
4455
+ }
4456
+ if (obj.maxDateTime && typeof obj.maxDateTime === "string") {
4457
+ rules.push({ type: "maxDateTime", value: obj.maxDateTime });
4458
+ }
4437
4459
  return rules;
4438
4460
  }
4439
4461
  function convertSpanToWidth(span, totalColumns = 12) {
@@ -4442,6 +4464,14 @@ function convertSpanToWidth(span, totalColumns = 12) {
4442
4464
  const percentage = span / totalColumns * 100;
4443
4465
  return Math.max(10, Math.min(100, Math.round(percentage)));
4444
4466
  }
4467
+ var EMAIL_REGEX = "^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$";
4468
+ var EMAIL_REGEX_MESSAGE = "Invalid email format";
4469
+ function isEmailLikeField(field) {
4470
+ const label = (field.label || "").toLowerCase();
4471
+ const fieldName = (field.fieldName || field.name || "").toLowerCase();
4472
+ const placeholder = (field.placeholder || "").toLowerCase();
4473
+ return /email/.test(label) || /email/.test(fieldName) || /@/.test(placeholder) || /email/.test(placeholder);
4474
+ }
4445
4475
  function normalizeFieldType(type) {
4446
4476
  if (!type)
4447
4477
  return "text";
@@ -4455,12 +4485,17 @@ function normalizeFieldType(type) {
4455
4485
  return "binary_choice";
4456
4486
  if (str === "REPEATER" || normalized === "repeater")
4457
4487
  return "repeater";
4488
+ if (str === "DATETIME" || normalized === "datetime")
4489
+ return "datetime";
4458
4490
  return str.toLowerCase();
4459
4491
  }
4460
4492
  function transformField(field) {
4461
4493
  const fieldId = field.id || field.fieldId;
4462
4494
  const fieldType = field.type || field.fieldType;
4463
- const normalizedType = normalizeFieldType(fieldType);
4495
+ let normalizedType = normalizeFieldType(fieldType);
4496
+ if (normalizedType === "text" && isEmailLikeField(field)) {
4497
+ normalizedType = "email";
4498
+ }
4464
4499
  const transformed = {
4465
4500
  id: fieldId,
4466
4501
  type: normalizedType,
@@ -4539,6 +4574,10 @@ function transformField(field) {
4539
4574
  validationObj.minDate = rule.value;
4540
4575
  } else if (rule.type === "maxDate" && typeof rule.value === "string") {
4541
4576
  validationObj.maxDate = rule.value;
4577
+ } else if (rule.type === "minDateTime" && typeof rule.value === "string") {
4578
+ validationObj.minDateTime = rule.value;
4579
+ } else if (rule.type === "maxDateTime" && typeof rule.value === "string") {
4580
+ validationObj.maxDateTime = rule.value;
4542
4581
  }
4543
4582
  });
4544
4583
  transformed.validation = validationObj;
@@ -4667,6 +4706,8 @@ function transformField(field) {
4667
4706
  transformed.repeatItemLabel = field.repeatItemLabel;
4668
4707
  if (field.repeatIncrementEnabled !== void 0)
4669
4708
  transformed.repeatIncrementEnabled = field.repeatIncrementEnabled;
4709
+ if (field.dateConstraints !== void 0)
4710
+ transformed.dateConstraints = field.dateConstraints;
4670
4711
  if (field.css !== void 0)
4671
4712
  transformed.css = field.css;
4672
4713
  if (field.optionsSource !== void 0)
@@ -4772,6 +4813,10 @@ function convertValidationArrayToObject(validation) {
4772
4813
  obj.minDate = rule.value;
4773
4814
  } else if (rule.type === "maxDate" && typeof rule.value === "string") {
4774
4815
  obj.maxDate = rule.value;
4816
+ } else if (rule.type === "minDateTime" && typeof rule.value === "string") {
4817
+ obj.minDateTime = rule.value;
4818
+ } else if (rule.type === "maxDateTime" && typeof rule.value === "string") {
4819
+ obj.maxDateTime = rule.value;
4775
4820
  }
4776
4821
  });
4777
4822
  return Object.keys(obj).length > 0 ? obj : void 0;
@@ -4783,9 +4828,19 @@ function convertWidthToSpan(width, totalColumns = 12) {
4783
4828
  return Math.max(1, Math.min(12, Math.round(widthNum / 100 * totalColumns)));
4784
4829
  }
4785
4830
  function fieldToPayload(field) {
4831
+ let outputType = field.type;
4832
+ let outputValidations = field.validations ? { ...field.validations } : void 0;
4833
+ if (field.type === "text" && isEmailLikeField(field)) {
4834
+ outputType = "email";
4835
+ outputValidations = field.validations ? { ...field.validations } : {};
4836
+ if (!outputValidations.pattern) {
4837
+ outputValidations.pattern = EMAIL_REGEX;
4838
+ outputValidations.customErrorMessages = { ...outputValidations.customErrorMessages, pattern: EMAIL_REGEX_MESSAGE };
4839
+ }
4840
+ }
4786
4841
  const payload = {
4787
4842
  id: field.id,
4788
- type: field.type,
4843
+ type: outputType,
4789
4844
  label: field.label,
4790
4845
  name: field.fieldName || field.id,
4791
4846
  // Model key for binding (API / host app)
@@ -4810,17 +4865,18 @@ function fieldToPayload(field) {
4810
4865
  span: 12
4811
4866
  };
4812
4867
  }
4813
- if (field.validations) {
4814
- let validations = { ...field.validations };
4868
+ const validationsToUse = outputValidations ?? field.validations;
4869
+ if (validationsToUse) {
4870
+ let validations = { ...validationsToUse };
4815
4871
  if (validations.validationType === "age") {
4816
4872
  validations = { ...validations, validationType: "custom" };
4817
4873
  }
4818
4874
  payload.validations = validations;
4819
- if (field.validations.required) {
4875
+ if (validationsToUse.required) {
4820
4876
  payload.required = true;
4821
4877
  }
4822
4878
  }
4823
- const baseValidation = field.validations ? validationsToValidationObject(field.validations) : convertValidationArrayToObject(field.validation);
4879
+ const baseValidation = validationsToUse ? validationsToValidationObject(validationsToUse) : convertValidationArrayToObject(field.validation);
4824
4880
  payload.validation = baseValidation;
4825
4881
  const pattern = baseValidation?.regex ?? field.validations?.pattern;
4826
4882
  const patternMsg = baseValidation?.regexMessage ?? field.validations?.customErrorMessages?.pattern;
@@ -4880,6 +4936,11 @@ function fieldToPayload(field) {
4880
4936
  if ((field.type === "select" || field.type === "radio" || field.type === "checkbox") && field.options && Array.isArray(field.options)) {
4881
4937
  payload.options = field.options.map((opt) => ({ label: opt.label, value: opt.value }));
4882
4938
  }
4939
+ if (field.dateConstraints !== void 0)
4940
+ payload.dateConstraints = field.dateConstraints;
4941
+ if (field.type === "datetime") {
4942
+ payload.fieldType = "DATETIME";
4943
+ }
4883
4944
  if (field.type === "binary_choice") {
4884
4945
  payload.fieldType = "BINARY_CHOICE";
4885
4946
  payload.type = "binary_choice";
@@ -5964,7 +6025,9 @@ function getValidationRules(field) {
5964
6025
  min: v.min,
5965
6026
  max: v.max,
5966
6027
  minDate: v.minDate,
5967
- maxDate: v.maxDate
6028
+ maxDate: v.maxDate,
6029
+ minDateTime: v.minDateTime,
6030
+ maxDateTime: v.maxDateTime
5968
6031
  };
5969
6032
  }
5970
6033
  const val = field.validation;
@@ -5990,6 +6053,10 @@ function getValidationRules(field) {
5990
6053
  rules.minDate = r.value;
5991
6054
  else if (r.type === "maxDate")
5992
6055
  rules.maxDate = r.value;
6056
+ else if (r.type === "minDateTime")
6057
+ rules.minDateTime = r.value;
6058
+ else if (r.type === "maxDateTime")
6059
+ rules.maxDateTime = r.value;
5993
6060
  });
5994
6061
  return rules;
5995
6062
  }
@@ -6003,15 +6070,108 @@ function getValidationRules(field) {
6003
6070
  min: o.min,
6004
6071
  max: o.max,
6005
6072
  minDate: o.minDate,
6006
- maxDate: o.maxDate
6073
+ maxDate: o.maxDate,
6074
+ minDateTime: o.minDateTime,
6075
+ maxDateTime: o.maxDateTime
6007
6076
  };
6008
6077
  }
6009
6078
  function isNumericTextField(field) {
6010
6079
  const v = field.validations;
6011
6080
  return !!(v?.validationType && ["postalCode", "phoneNumber", "otp"].includes(v.validationType));
6012
6081
  }
6082
+ function toDateString(d) {
6083
+ return d.toISOString().split("T")[0];
6084
+ }
6085
+ function toDatetimeString(d) {
6086
+ const pad = (n) => String(n).padStart(2, "0");
6087
+ return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())}T${pad(d.getHours())}:${pad(d.getMinutes())}`;
6088
+ }
6089
+ function resolveDateConstraintBounds(field, allFields, formData) {
6090
+ const constraint = field.dateConstraints;
6091
+ if (!constraint)
6092
+ return null;
6093
+ const isDatetime = field.type === "datetime";
6094
+ let constraintDate = null;
6095
+ if (constraint.compareWith === "CURRENT_DATE") {
6096
+ constraintDate = /* @__PURE__ */ new Date();
6097
+ if (!isDatetime)
6098
+ constraintDate.setHours(0, 0, 0, 0);
6099
+ } else if (constraint.compareWith === "FIELD" && constraint.fieldName) {
6100
+ const refField = allFields?.find(
6101
+ (f) => f.fieldName === constraint.fieldName || f.id === constraint.fieldName
6102
+ );
6103
+ if (refField && formData) {
6104
+ const key = refField.fieldName ?? refField.id;
6105
+ const raw = formData[key];
6106
+ if (raw)
6107
+ constraintDate = new Date(raw);
6108
+ }
6109
+ }
6110
+ if (!constraintDate || isNaN(constraintDate.getTime()))
6111
+ return null;
6112
+ const MS_MIN = 6e4;
6113
+ const MS_DAY = 864e5;
6114
+ const { operator } = constraint;
6115
+ if (isDatetime) {
6116
+ if (operator === "LESS_THAN")
6117
+ return { max: toDatetimeString(new Date(constraintDate.getTime() - MS_MIN)) };
6118
+ if (operator === "LESS_THAN_EQUAL")
6119
+ return { max: toDatetimeString(constraintDate) };
6120
+ if (operator === "GREATER_THAN")
6121
+ return { min: toDatetimeString(new Date(constraintDate.getTime() + MS_MIN)) };
6122
+ return { min: toDatetimeString(constraintDate) };
6123
+ } else {
6124
+ if (operator === "LESS_THAN")
6125
+ return { max: toDateString(new Date(constraintDate.getTime() - MS_DAY)) };
6126
+ if (operator === "LESS_THAN_EQUAL")
6127
+ return { max: toDateString(constraintDate) };
6128
+ if (operator === "GREATER_THAN")
6129
+ return { min: toDateString(new Date(constraintDate.getTime() + MS_DAY)) };
6130
+ return { min: toDateString(constraintDate) };
6131
+ }
6132
+ }
6133
+ function validateDateConstraint(field, value, allFields, formData) {
6134
+ const constraint = field.dateConstraints;
6135
+ if (!constraint || !value)
6136
+ return "";
6137
+ const inputDate = new Date(value);
6138
+ if (isNaN(inputDate.getTime()))
6139
+ return "";
6140
+ let constraintDate = null;
6141
+ let constraintLabel = "";
6142
+ if (constraint.compareWith === "CURRENT_DATE") {
6143
+ constraintDate = /* @__PURE__ */ new Date();
6144
+ if (field.type === "date")
6145
+ constraintDate.setHours(0, 0, 0, 0);
6146
+ constraintLabel = "today's date";
6147
+ } else if (constraint.compareWith === "FIELD" && constraint.fieldName) {
6148
+ const refField = allFields?.find(
6149
+ (f) => f.fieldName === constraint.fieldName || f.id === constraint.fieldName
6150
+ );
6151
+ if (refField && formData) {
6152
+ const key = refField.fieldName ?? refField.id;
6153
+ const raw = formData[key];
6154
+ if (raw) {
6155
+ constraintDate = new Date(raw);
6156
+ constraintLabel = `"${refField.label || constraint.fieldName}"`;
6157
+ }
6158
+ }
6159
+ }
6160
+ if (!constraintDate || isNaN(constraintDate.getTime()))
6161
+ return "";
6162
+ const { operator } = constraint;
6163
+ if (operator === "LESS_THAN" && !(inputDate < constraintDate))
6164
+ return `Date must be before ${constraintLabel}`;
6165
+ if (operator === "LESS_THAN_EQUAL" && !(inputDate <= constraintDate))
6166
+ return `Date must be on or before ${constraintLabel}`;
6167
+ if (operator === "GREATER_THAN" && !(inputDate > constraintDate))
6168
+ return `Date must be after ${constraintLabel}`;
6169
+ if (operator === "GREATER_THAN_EQUAL" && !(inputDate >= constraintDate))
6170
+ return `Date must be on or after ${constraintLabel}`;
6171
+ return "";
6172
+ }
6013
6173
  var FieldRenderer = class {
6014
- static render(field, value, onChange, readOnly = false) {
6174
+ static render(field, value, onChange, readOnly = false, allFields, formData) {
6015
6175
  const wrapper = createElement("div", { className: "w-full form-row" });
6016
6176
  const isEnabled = field.enabled !== false && !readOnly;
6017
6177
  if (field.type !== "checkbox" && field.type !== "toggle" && field.type !== "binary_choice") {
@@ -6047,7 +6207,7 @@ var FieldRenderer = class {
6047
6207
  const validationRules = getValidationRules(field);
6048
6208
  const hasPatternValidation = !!validationRules.pattern;
6049
6209
  const hasNumericTextValidation = isNumericTextField(field);
6050
- if (field.type === "date" || field.type === "email" || field.type === "number" || field.type === "text" && (hasPatternValidation || hasNumericTextValidation || validationRules.minLength !== void 0 || validationRules.maxLength !== void 0)) {
6210
+ if (field.type === "date" || field.type === "datetime" || field.type === "email" || field.type === "number" || field.type === "text" && (hasPatternValidation || hasNumericTextValidation || validationRules.minLength !== void 0 || validationRules.maxLength !== void 0)) {
6051
6211
  validationMsg = createElement("div", { className: "text-xs text-red-600 dark:text-red-400 mt-1 hidden", id: `validation-${field.id}` });
6052
6212
  }
6053
6213
  const validateField = (f, value2, inputElement, msgEl) => {
@@ -6072,6 +6232,26 @@ var FieldRenderer = class {
6072
6232
  }
6073
6233
  }
6074
6234
  }
6235
+ if (!errorMessage && f.type === "datetime" && value2) {
6236
+ const inputDateTime = new Date(value2);
6237
+ const minDt = rules.minDateTime ?? rules.minDate;
6238
+ const maxDt = rules.maxDateTime ?? rules.maxDate;
6239
+ if (minDt) {
6240
+ const minDateTime = new Date(minDt);
6241
+ if (inputDateTime < minDateTime) {
6242
+ errorMessage = "Date & time must be after the minimum";
6243
+ }
6244
+ }
6245
+ if (!errorMessage && maxDt) {
6246
+ const maxDateTime = new Date(maxDt);
6247
+ if (inputDateTime > maxDateTime) {
6248
+ errorMessage = "Date & time must be before the maximum";
6249
+ }
6250
+ }
6251
+ }
6252
+ if (!errorMessage && (f.type === "date" || f.type === "datetime") && value2 && f.dateConstraints) {
6253
+ errorMessage = validateDateConstraint(f, value2, allFields, formData);
6254
+ }
6075
6255
  if (!errorMessage && (f.type === "email" || f.type === "text" || f.type === "phone") && value2 && rules.pattern) {
6076
6256
  try {
6077
6257
  if (!new RegExp(rules.pattern).test(value2)) {
@@ -6323,12 +6503,23 @@ var FieldRenderer = class {
6323
6503
  default:
6324
6504
  const rules = getValidationRules(field);
6325
6505
  const useNumericTextInput = field.type === "text" && isNumericTextField(field);
6326
- const inputType = useNumericTextInput ? "text" : field.type === "number" ? "number" : field.type;
6506
+ const inputType = useNumericTextInput ? "text" : field.type === "number" ? "number" : field.type === "datetime" ? "datetime-local" : field.type;
6327
6507
  const runValidation = () => {
6328
- if (validationMsg && (field.type === "date" || field.type === "email" || field.type === "text" || field.type === "number")) {
6508
+ if (validationMsg && (field.type === "date" || field.type === "datetime" || field.type === "email" || field.type === "text" || field.type === "number")) {
6329
6509
  validateField(field, input.value, input, validationMsg);
6330
6510
  }
6331
6511
  };
6512
+ let minVal = field.type === "datetime" ? rules.minDateTime ?? rules.minDate : field.type === "date" ? rules.minDate : field.type === "number" && rules.min !== void 0 ? String(rules.min) : void 0;
6513
+ let maxVal = field.type === "datetime" ? rules.maxDateTime ?? rules.maxDate : field.type === "date" ? rules.maxDate : field.type === "number" && rules.max !== void 0 ? String(rules.max) : void 0;
6514
+ if (field.type === "date" || field.type === "datetime") {
6515
+ const bounds = resolveDateConstraintBounds(field, allFields, formData);
6516
+ if (bounds) {
6517
+ if (bounds.min !== void 0)
6518
+ minVal = bounds.min;
6519
+ if (bounds.max !== void 0)
6520
+ maxVal = bounds.max;
6521
+ }
6522
+ }
6332
6523
  input = createElement("input", {
6333
6524
  type: inputType,
6334
6525
  ...useNumericTextInput && { inputmode: "numeric" },
@@ -6336,8 +6527,8 @@ var FieldRenderer = class {
6336
6527
  placeholder: field.placeholder,
6337
6528
  value: value || "",
6338
6529
  disabled: !isEnabled,
6339
- min: field.type === "date" ? rules.minDate : field.type === "number" ? rules.min !== void 0 ? String(rules.min) : void 0 : void 0,
6340
- max: field.type === "date" ? rules.maxDate : field.type === "number" ? rules.max !== void 0 ? String(rules.max) : void 0 : void 0,
6530
+ min: minVal,
6531
+ max: maxVal,
6341
6532
  pattern: !useNumericTextInput ? rules.pattern || void 0 : void 0,
6342
6533
  oninput: (e) => {
6343
6534
  const inputEl = e.target;
@@ -6595,7 +6786,7 @@ function getValidationRulesForField(field) {
6595
6786
  }
6596
6787
  return convertValidationToArray(field.validation);
6597
6788
  }
6598
- function getFieldValidationError(field, fieldValue) {
6789
+ function getFieldValidationError(field, fieldValue, allFields, formData) {
6599
6790
  const isRequired = field.validations?.required ?? field.required;
6600
6791
  if (isRequired && (!fieldValue || fieldValue === "" || Array.isArray(fieldValue) && fieldValue.length === 0)) {
6601
6792
  return field.validations?.customErrorMessages?.required || "This field is required";
@@ -6636,6 +6827,53 @@ function getFieldValidationError(field, fieldValue) {
6636
6827
  }
6637
6828
  }
6638
6829
  }
6830
+ if (field.type === "datetime" && fieldValue) {
6831
+ const v = field.validations;
6832
+ const minDt = v?.minDateTime ?? v?.minDate;
6833
+ const maxDt = v?.maxDateTime ?? v?.maxDate;
6834
+ const inputDt = new Date(fieldValue);
6835
+ if (minDt && inputDt < new Date(minDt)) {
6836
+ return "Date & time must be after the minimum";
6837
+ }
6838
+ if (maxDt && inputDt > new Date(maxDt)) {
6839
+ return "Date & time must be before the maximum";
6840
+ }
6841
+ }
6842
+ if ((field.type === "date" || field.type === "datetime") && fieldValue && field.dateConstraints) {
6843
+ const constraint = field.dateConstraints;
6844
+ const inputDate = new Date(fieldValue);
6845
+ let constraintDate = null;
6846
+ let constraintLabel = "";
6847
+ if (constraint.compareWith === "CURRENT_DATE") {
6848
+ constraintDate = /* @__PURE__ */ new Date();
6849
+ if (field.type === "date")
6850
+ constraintDate.setHours(0, 0, 0, 0);
6851
+ constraintLabel = "today's date";
6852
+ } else if (constraint.compareWith === "FIELD" && constraint.fieldName && allFields && formData) {
6853
+ const refField = allFields.find(
6854
+ (f) => f.fieldName === constraint.fieldName || f.id === constraint.fieldName
6855
+ );
6856
+ if (refField) {
6857
+ const key = refField.fieldName ?? refField.id;
6858
+ const raw = formData[key];
6859
+ if (raw) {
6860
+ constraintDate = new Date(raw);
6861
+ constraintLabel = `"${refField.label || constraint.fieldName}"`;
6862
+ }
6863
+ }
6864
+ }
6865
+ if (constraintDate && !isNaN(constraintDate.getTime())) {
6866
+ const { operator } = constraint;
6867
+ if (operator === "LESS_THAN" && !(inputDate < constraintDate))
6868
+ return `Date must be before ${constraintLabel}`;
6869
+ if (operator === "LESS_THAN_EQUAL" && !(inputDate <= constraintDate))
6870
+ return `Date must be on or before ${constraintLabel}`;
6871
+ if (operator === "GREATER_THAN" && !(inputDate > constraintDate))
6872
+ return `Date must be after ${constraintLabel}`;
6873
+ if (operator === "GREATER_THAN_EQUAL" && !(inputDate >= constraintDate))
6874
+ return `Date must be on or after ${constraintLabel}`;
6875
+ }
6876
+ }
6639
6877
  if (field.type === "checkbox" && Array.isArray(fieldValue)) {
6640
6878
  const validationArray = getValidationRulesForField(field);
6641
6879
  const minSelectedRule = validationArray.find((v) => v.type === "minSelected");
@@ -6705,6 +6943,20 @@ function isFormulaDependency(schema, modelKey, fieldId) {
6705
6943
  }
6706
6944
  return false;
6707
6945
  }
6946
+ function isDateConstraintDependency(schema, modelKey, fieldId) {
6947
+ for (const section of schema.sections) {
6948
+ for (const field of section.fields) {
6949
+ const c = field.dateConstraints;
6950
+ if (c && c.compareWith === "FIELD" && c.fieldName) {
6951
+ if (c.fieldName === modelKey)
6952
+ return true;
6953
+ if (fieldId && c.fieldName === fieldId)
6954
+ return true;
6955
+ }
6956
+ }
6957
+ }
6958
+ return false;
6959
+ }
6708
6960
  var FormRenderer = class {
6709
6961
  constructor(container, schema, onSubmit, onDropdownValueChange, initialData) {
6710
6962
  __publicField(this, "container");
@@ -6729,6 +6981,7 @@ var FormRenderer = class {
6729
6981
  this.container.innerHTML = "";
6730
6982
  const form = createElement("form", { className: "space-y-6 md:space-y-8" });
6731
6983
  form.appendChild(createElement("h1", { className: "text-2xl font-semibold mb-2 text-[#3b497e] ", text: this.schema.title }));
6984
+ const allFields = this.schema.sections.flatMap((s) => s.fields);
6732
6985
  this.schema.sections.forEach((section) => {
6733
6986
  const sectionEl = createElement("div", { className: "space-y-3 md:space-y-4 !m-0" });
6734
6987
  sectionEl.appendChild(createElement("h2", { className: "text-xl font-semibold text-[#3b497e] dark:text-gray-200 border-b pb-2", text: section.title }));
@@ -6773,10 +7026,16 @@ var FormRenderer = class {
6773
7026
  }
6774
7027
  if (isFormulaDependency(this.schema, modelKey, field.id)) {
6775
7028
  this.render();
7029
+ return;
7030
+ }
7031
+ if (isDateConstraintDependency(this.schema, modelKey, field.id)) {
7032
+ this.render();
6776
7033
  }
6777
7034
  },
6778
- isFormulaField
7035
+ isFormulaField,
6779
7036
  // Formula fields are read-only
7037
+ allFields,
7038
+ this.data
6780
7039
  );
6781
7040
  fieldWrapper.appendChild(fieldEl);
6782
7041
  grid.appendChild(fieldWrapper);
@@ -6800,7 +7059,7 @@ var FormRenderer = class {
6800
7059
  const modelKey = getModelKey(field);
6801
7060
  const fieldValue = this.data[modelKey];
6802
7061
  const fieldElement = form.querySelector(`input[id*="${field.id}"], textarea[id*="${field.id}"], select[id*="${field.id}"]`);
6803
- const fieldError = getFieldValidationError(field, fieldValue);
7062
+ const fieldError = getFieldValidationError(field, fieldValue, allFields, this.data);
6804
7063
  const element = fieldElement ?? Array.from(form.querySelectorAll("input, textarea, select")).find((el) => {
6805
7064
  const wrapper = el.closest("div");
6806
7065
  return wrapper && wrapper.textContent?.includes(field.label);
@@ -10869,6 +11128,10 @@ var FormBuilder = class {
10869
11128
  obj.minDate = rule.value;
10870
11129
  else if (rule.type === "maxDate" && typeof rule.value === "string")
10871
11130
  obj.maxDate = rule.value;
11131
+ else if (rule.type === "minDateTime" && typeof rule.value === "string")
11132
+ obj.minDateTime = rule.value;
11133
+ else if (rule.type === "maxDateTime" && typeof rule.value === "string")
11134
+ obj.maxDateTime = rule.value;
10872
11135
  });
10873
11136
  return obj;
10874
11137
  }
@@ -10884,6 +11147,8 @@ var FormBuilder = class {
10884
11147
  maxSelected: o.maxSelected,
10885
11148
  minDate: o.minDate,
10886
11149
  maxDate: o.maxDate,
11150
+ minDateTime: o.minDateTime,
11151
+ maxDateTime: o.maxDateTime,
10887
11152
  customErrorMessages: o.regexMessage ? { pattern: o.regexMessage } : void 0
10888
11153
  };
10889
11154
  })();
@@ -11319,11 +11584,136 @@ var FormBuilder = class {
11319
11584
  }));
11320
11585
  validationElements.push(maxDateGroup);
11321
11586
  }
11587
+ if (selectedField.type === "datetime") {
11588
+ const minMaxDt = validationsObj;
11589
+ const minDateTimeGroup = createElement("div", { className: "mb-3" });
11590
+ minDateTimeGroup.appendChild(createElement("label", { className: "block text-sm font-normal text-gray-700 dark:text-gray-300 mb-1", text: "Minimum Date & Time" }));
11591
+ minDateTimeGroup.appendChild(createElement("input", {
11592
+ type: "datetime-local",
11593
+ className: "w-full px-3 py-2 border border-gray-200 dark:border-gray-700 rounded-md bg-transparent",
11594
+ value: minMaxDt.minDateTime || minMaxDt.minDate || "",
11595
+ onchange: (e) => {
11596
+ const val = e.target.value;
11597
+ updateValidations({ minDateTime: val || void 0 });
11598
+ }
11599
+ }));
11600
+ validationElements.push(minDateTimeGroup);
11601
+ const maxDateTimeGroup = createElement("div", { className: "mb-3" });
11602
+ maxDateTimeGroup.appendChild(createElement("label", { className: "block text-sm font-normal text-gray-700 dark:text-gray-300 mb-1", text: "Maximum Date & Time" }));
11603
+ maxDateTimeGroup.appendChild(createElement("input", {
11604
+ type: "datetime-local",
11605
+ className: "w-full px-3 py-2 border border-gray-200 dark:border-gray-700 rounded-md bg-transparent",
11606
+ value: minMaxDt.maxDateTime || minMaxDt.maxDate || "",
11607
+ onchange: (e) => {
11608
+ const val = e.target.value;
11609
+ updateValidations({ maxDateTime: val || void 0 });
11610
+ }
11611
+ }));
11612
+ validationElements.push(maxDateTimeGroup);
11613
+ }
11322
11614
  if (validationElements.length > 0) {
11323
11615
  const validationHeader = createElement("h3", { className: "text-xs font-semibold text-gray-500 uppercase tracking-wider mb-3 mt-6", text: "Validation Rules" });
11324
11616
  body.appendChild(validationHeader);
11325
11617
  validationElements.forEach((el) => body.appendChild(el));
11326
11618
  }
11619
+ if (selectedField.type === "date" || selectedField.type === "datetime") {
11620
+ const constraintHeader = createElement("h3", { className: "text-xs font-semibold text-gray-500 uppercase tracking-wider mb-3 mt-6", text: "Date Constraint" });
11621
+ body.appendChild(constraintHeader);
11622
+ const getConstraint = () => {
11623
+ const f = formStore.getState().schema.sections.flatMap((s) => s.fields).find((f2) => f2.id === selectedField.id);
11624
+ return f?.dateConstraints;
11625
+ };
11626
+ const updateConstraint = (patch) => {
11627
+ if (patch === null) {
11628
+ formStore.getState().updateField(selectedField.id, { dateConstraints: void 0 });
11629
+ return;
11630
+ }
11631
+ const current = getConstraint() || {};
11632
+ const next = { ...current, ...patch };
11633
+ formStore.getState().updateField(selectedField.id, { dateConstraints: next });
11634
+ };
11635
+ const currentConstraint = getConstraint();
11636
+ const operatorGroup = createElement("div", { className: "mb-3" });
11637
+ operatorGroup.appendChild(createElement("label", { className: "block text-sm font-normal text-gray-700 dark:text-gray-300 mb-1", text: "Operator" }));
11638
+ const operatorSelect = createElement("select", {
11639
+ className: "w-full px-3 py-2 border border-gray-200 dark:border-gray-700 rounded-md bg-transparent text-sm",
11640
+ onchange: (e) => {
11641
+ const val = e.target.value;
11642
+ if (!val) {
11643
+ updateConstraint(null);
11644
+ } else {
11645
+ updateConstraint({ operator: val, compareWith: getConstraint()?.compareWith || "CURRENT_DATE" });
11646
+ }
11647
+ this.render();
11648
+ }
11649
+ });
11650
+ [
11651
+ { value: "", label: "None (no constraint)" },
11652
+ { value: "LESS_THAN", label: "Less than (<)" },
11653
+ { value: "LESS_THAN_EQUAL", label: "Less than or equal (\u2264)" },
11654
+ { value: "GREATER_THAN", label: "Greater than (>)" },
11655
+ { value: "GREATER_THAN_EQUAL", label: "Greater than or equal (\u2265)" }
11656
+ ].forEach((opt) => {
11657
+ const option2 = createElement("option", { value: opt.value, text: opt.label });
11658
+ if ((currentConstraint?.operator || "") === opt.value)
11659
+ option2.selected = true;
11660
+ operatorSelect.appendChild(option2);
11661
+ });
11662
+ operatorGroup.appendChild(operatorSelect);
11663
+ body.appendChild(operatorGroup);
11664
+ if (currentConstraint?.operator) {
11665
+ const compareGroup = createElement("div", { className: "mb-3" });
11666
+ compareGroup.appendChild(createElement("label", { className: "block text-sm font-normal text-gray-700 dark:text-gray-300 mb-1", text: "Compare With" }));
11667
+ const compareSelect = createElement("select", {
11668
+ className: "w-full px-3 py-2 border border-gray-200 dark:border-gray-700 rounded-md bg-transparent text-sm",
11669
+ onchange: (e) => {
11670
+ const val = e.target.value;
11671
+ updateConstraint({ compareWith: val, fieldName: val === "CURRENT_DATE" ? void 0 : getConstraint()?.fieldName });
11672
+ this.render();
11673
+ }
11674
+ });
11675
+ [
11676
+ { value: "CURRENT_DATE", label: "Current date (today)" },
11677
+ { value: "FIELD", label: "Another date/datetime field" }
11678
+ ].forEach((opt) => {
11679
+ const option2 = createElement("option", { value: opt.value, text: opt.label });
11680
+ if ((currentConstraint?.compareWith || "CURRENT_DATE") === opt.value)
11681
+ option2.selected = true;
11682
+ compareSelect.appendChild(option2);
11683
+ });
11684
+ compareGroup.appendChild(compareSelect);
11685
+ body.appendChild(compareGroup);
11686
+ if ((currentConstraint?.compareWith || "CURRENT_DATE") === "FIELD") {
11687
+ const otherDateFields = formStore.getState().schema.sections.flatMap((s) => s.fields).filter((f) => (f.type === "date" || f.type === "datetime") && f.id !== selectedField.id);
11688
+ const fieldGroup = createElement("div", { className: "mb-3" });
11689
+ fieldGroup.appendChild(createElement("label", { className: "block text-sm font-normal text-gray-700 dark:text-gray-300 mb-1", text: "Reference Field" }));
11690
+ if (otherDateFields.length === 0) {
11691
+ fieldGroup.appendChild(createElement("p", {
11692
+ className: "text-xs text-gray-400 dark:text-gray-500 italic",
11693
+ text: "No other date or datetime fields in this form."
11694
+ }));
11695
+ } else {
11696
+ const fieldSelect = createElement("select", {
11697
+ className: "w-full px-3 py-2 border border-gray-200 dark:border-gray-700 rounded-md bg-transparent text-sm",
11698
+ onchange: (e) => {
11699
+ const val = e.target.value;
11700
+ updateConstraint({ fieldName: val || void 0 });
11701
+ }
11702
+ });
11703
+ fieldSelect.appendChild(createElement("option", { value: "", text: "\u2014 Select a field \u2014" }));
11704
+ otherDateFields.forEach((f) => {
11705
+ const refKey = f.fieldName || f.id;
11706
+ const option2 = createElement("option", { value: refKey, text: `${f.label} (${f.type})` });
11707
+ if (currentConstraint?.fieldName === refKey)
11708
+ option2.selected = true;
11709
+ fieldSelect.appendChild(option2);
11710
+ });
11711
+ fieldGroup.appendChild(fieldSelect);
11712
+ }
11713
+ body.appendChild(fieldGroup);
11714
+ }
11715
+ }
11716
+ }
11327
11717
  const cssHeader = createElement("h3", { className: "text-xs font-semibold text-gray-500 uppercase tracking-wider mb-3 mt-6", text: "Styling" });
11328
11718
  body.appendChild(cssHeader);
11329
11719
  const getStyleValue = (prop) => selectedField.css?.style?.[prop] || "";