form-builder-pro 1.3.1 → 1.3.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.css CHANGED
@@ -1242,6 +1242,10 @@ body {
1242
1242
  --tw-border-opacity: 1;
1243
1243
  border-color: rgb(254 202 202 / var(--tw-border-opacity, 1));
1244
1244
  }
1245
+ .border-red-300 {
1246
+ --tw-border-opacity: 1;
1247
+ border-color: rgb(252 165 165 / var(--tw-border-opacity, 1));
1248
+ }
1245
1249
  .border-red-500 {
1246
1250
  --tw-border-opacity: 1;
1247
1251
  border-color: rgb(239 68 68 / var(--tw-border-opacity, 1));
package/dist/index.d.mts CHANGED
@@ -1,7 +1,7 @@
1
1
  import { z } from 'zod';
2
2
  import * as zustand_vanilla from 'zustand/vanilla';
3
3
 
4
- type FieldType = 'text' | 'textarea' | 'number' | 'date' | 'select' | 'checkbox' | 'radio' | 'toggle' | 'file' | 'image' | 'email' | 'phone';
4
+ type FieldType = 'text' | 'textarea' | 'number' | 'date' | 'select' | 'checkbox' | 'radio' | 'toggle' | 'binary_choice' | 'repeater' | 'file' | 'image' | 'email' | 'phone';
5
5
  type FieldWidth = '25%' | '33%' | '50%' | '66%' | '75%' | '100%' | number;
6
6
  declare function parseWidth(width: FieldWidth): number;
7
7
  declare function getColSpanFromWidth(width: FieldWidth): string;
@@ -110,6 +110,14 @@ interface FormField {
110
110
  valueSource?: 'manual' | 'formula';
111
111
  formula?: string;
112
112
  dependencies?: string[];
113
+ optionOnLabel?: string;
114
+ optionOffLabel?: string;
115
+ valueOn?: string;
116
+ valueOff?: string;
117
+ showWhenValueOnFields?: string[];
118
+ showWhenValueOffFields?: string[];
119
+ repeatItemLabel?: string;
120
+ repeatIncrementEnabled?: boolean;
113
121
  }
114
122
  /**
115
123
  * ISD (International Subscriber Dialing) configuration for phone fields
package/dist/index.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import { z } from 'zod';
2
2
  import * as zustand_vanilla from 'zustand/vanilla';
3
3
 
4
- type FieldType = 'text' | 'textarea' | 'number' | 'date' | 'select' | 'checkbox' | 'radio' | 'toggle' | 'file' | 'image' | 'email' | 'phone';
4
+ type FieldType = 'text' | 'textarea' | 'number' | 'date' | 'select' | 'checkbox' | 'radio' | 'toggle' | 'binary_choice' | 'repeater' | 'file' | 'image' | 'email' | 'phone';
5
5
  type FieldWidth = '25%' | '33%' | '50%' | '66%' | '75%' | '100%' | number;
6
6
  declare function parseWidth(width: FieldWidth): number;
7
7
  declare function getColSpanFromWidth(width: FieldWidth): string;
@@ -110,6 +110,14 @@ interface FormField {
110
110
  valueSource?: 'manual' | 'formula';
111
111
  formula?: string;
112
112
  dependencies?: string[];
113
+ optionOnLabel?: string;
114
+ optionOffLabel?: string;
115
+ valueOn?: string;
116
+ valueOff?: string;
117
+ showWhenValueOnFields?: string[];
118
+ showWhenValueOffFields?: string[];
119
+ repeatItemLabel?: string;
120
+ repeatIncrementEnabled?: boolean;
113
121
  }
114
122
  /**
115
123
  * ISD (International Subscriber Dialing) configuration for phone fields
package/dist/index.js CHANGED
@@ -4121,6 +4121,8 @@ var FIELD_TYPES = [
4121
4121
  { type: "checkbox", label: "Checkbox", icon: "CheckSquare" },
4122
4122
  { type: "radio", label: "Radio Group", icon: "CircleDot" },
4123
4123
  { type: "toggle", label: "Toggle", icon: "ToggleSwitch" },
4124
+ { type: "binary_choice", label: "Yes/No Toggle", icon: "ToggleLeft" },
4125
+ { type: "repeater", label: "Repeater", icon: "Copy" },
4124
4126
  { type: "file", label: "File Upload", icon: "Upload" },
4125
4127
  { type: "image", label: "Image", icon: "Image" }
4126
4128
  ];
@@ -4148,6 +4150,25 @@ var DEFAULT_FIELD_CONFIG = {
4148
4150
  checkbox: { label: "Checkbox", options: [], width: "100%", enabled: true, visible: true },
4149
4151
  radio: { label: "Radio Group", options: [], width: "100%", enabled: true, visible: true },
4150
4152
  toggle: { label: "Toggle", width: "50%", enabled: true, visible: true },
4153
+ binary_choice: {
4154
+ label: "Yes/No Toggle",
4155
+ width: "50%",
4156
+ enabled: true,
4157
+ visible: true,
4158
+ optionOnLabel: "YES",
4159
+ optionOffLabel: "NO",
4160
+ valueOn: "YES",
4161
+ valueOff: "NO",
4162
+ defaultValue: "NO"
4163
+ },
4164
+ repeater: {
4165
+ label: "Repeater",
4166
+ width: "100%",
4167
+ enabled: true,
4168
+ visible: true,
4169
+ repeatItemLabel: "Item",
4170
+ repeatIncrementEnabled: false
4171
+ },
4151
4172
  file: { label: "File Upload", width: "100%", enabled: true, visible: true },
4152
4173
  image: { label: "Image", width: "50%", enabled: true, visible: true }
4153
4174
  };
@@ -4421,12 +4442,17 @@ function convertSpanToWidth(span, totalColumns = 12) {
4421
4442
  function normalizeFieldType(type) {
4422
4443
  if (!type)
4423
4444
  return "text";
4424
- const normalized = String(type).toLowerCase().replace(/_/g, "");
4445
+ const str = String(type);
4446
+ const normalized = str.toLowerCase().replace(/_/g, "");
4425
4447
  if (normalized === "decimal")
4426
4448
  return "number";
4427
4449
  if (["phonenumber", "telephone", "mobile"].includes(normalized))
4428
4450
  return "phone";
4429
- return String(type).toLowerCase();
4451
+ if (str === "BINARY_CHOICE" || normalized === "binarychoice")
4452
+ return "binary_choice";
4453
+ if (str === "REPEATER" || normalized === "repeater")
4454
+ return "repeater";
4455
+ return str.toLowerCase();
4430
4456
  }
4431
4457
  function transformField(field) {
4432
4458
  const fieldId = field.id || field.fieldId;
@@ -4604,6 +4630,24 @@ function transformField(field) {
4604
4630
  transformed.formula = field.formula;
4605
4631
  if (field.dependencies !== void 0 && Array.isArray(field.dependencies))
4606
4632
  transformed.dependencies = field.dependencies;
4633
+ if (field.optionOnLabel !== void 0)
4634
+ transformed.optionOnLabel = field.optionOnLabel;
4635
+ if (field.optionOffLabel !== void 0)
4636
+ transformed.optionOffLabel = field.optionOffLabel;
4637
+ if (field.valueOn !== void 0)
4638
+ transformed.valueOn = field.valueOn;
4639
+ if (field.valueOff !== void 0)
4640
+ transformed.valueOff = field.valueOff;
4641
+ if (field.showWhenValueOnFields !== void 0 && Array.isArray(field.showWhenValueOnFields)) {
4642
+ transformed.showWhenValueOnFields = field.showWhenValueOnFields;
4643
+ }
4644
+ if (field.showWhenValueOffFields !== void 0 && Array.isArray(field.showWhenValueOffFields)) {
4645
+ transformed.showWhenValueOffFields = field.showWhenValueOffFields;
4646
+ }
4647
+ if (field.repeatItemLabel !== void 0)
4648
+ transformed.repeatItemLabel = field.repeatItemLabel;
4649
+ if (field.repeatIncrementEnabled !== void 0)
4650
+ transformed.repeatIncrementEnabled = field.repeatIncrementEnabled;
4607
4651
  if (field.css !== void 0)
4608
4652
  transformed.css = field.css;
4609
4653
  if (field.optionsSource !== void 0)
@@ -4807,6 +4851,34 @@ function fieldToPayload(field) {
4807
4851
  if ((field.type === "select" || field.type === "radio" || field.type === "checkbox") && field.options && Array.isArray(field.options)) {
4808
4852
  payload.options = field.options.map((opt) => ({ label: opt.label, value: opt.value }));
4809
4853
  }
4854
+ if (field.type === "binary_choice") {
4855
+ payload.fieldType = "BINARY_CHOICE";
4856
+ payload.type = "binary_choice";
4857
+ payload.optionOnLabel = field.optionOnLabel ?? "YES";
4858
+ payload.optionOffLabel = field.optionOffLabel ?? "NO";
4859
+ payload.valueOn = field.valueOn ?? field.optionOnLabel ?? "YES";
4860
+ payload.valueOff = field.valueOff ?? field.optionOffLabel ?? "NO";
4861
+ if (field.showWhenValueOnFields && field.showWhenValueOnFields.length > 0) {
4862
+ payload.showWhenValueOnFields = field.showWhenValueOnFields;
4863
+ }
4864
+ if (field.showWhenValueOffFields && field.showWhenValueOffFields.length > 0) {
4865
+ payload.showWhenValueOffFields = field.showWhenValueOffFields;
4866
+ }
4867
+ }
4868
+ if (field.type === "repeater") {
4869
+ payload.fieldType = "REPEATER";
4870
+ payload.type = "number";
4871
+ payload.repeatItemLabel = field.repeatItemLabel ?? "Item";
4872
+ payload.repeatIncrementEnabled = field.repeatIncrementEnabled ?? false;
4873
+ if (field.validations?.min !== void 0 || field.validations?.max !== void 0) {
4874
+ const v = payload.validation || {};
4875
+ if (field.validations.min !== void 0)
4876
+ v.min = field.validations.min;
4877
+ if (field.validations.max !== void 0)
4878
+ v.max = field.validations.max;
4879
+ payload.validation = v;
4880
+ }
4881
+ }
4810
4882
  return payload;
4811
4883
  }
4812
4884
  var builderToPlatform = (builderSchema) => {
@@ -5913,7 +5985,7 @@ var FieldRenderer = class {
5913
5985
  static render(field, value, onChange, readOnly = false) {
5914
5986
  const wrapper = createElement("div", { className: "w-full form-row" });
5915
5987
  const isEnabled = field.enabled !== false && !readOnly;
5916
- if (field.type !== "checkbox" && field.type !== "toggle") {
5988
+ if (field.type !== "checkbox" && field.type !== "toggle" && field.type !== "binary_choice") {
5917
5989
  const label = createElement("label", {
5918
5990
  className: "text-xs sm:text-sm font-medium leading-none mb-2 block text-gray-900 dark:text-gray-100",
5919
5991
  text: field.label
@@ -5931,7 +6003,7 @@ var FieldRenderer = class {
5931
6003
  label.appendChild(createElement("span", { className: "text-red-500 ml-1", text: "*" }));
5932
6004
  }
5933
6005
  wrapper.appendChild(label);
5934
- } else if (field.type === "toggle") {
6006
+ } else if (field.type === "toggle" || field.type === "binary_choice") {
5935
6007
  const label = createElement("label", {
5936
6008
  className: "text-xs sm:text-sm font-medium leading-none mb-2 block text-gray-900 dark:text-gray-100",
5937
6009
  text: field.label
@@ -6138,6 +6210,81 @@ var FieldRenderer = class {
6138
6210
  toggleLabel.appendChild(toggleSlider);
6139
6211
  input.appendChild(toggleLabel);
6140
6212
  break;
6213
+ case "binary_choice": {
6214
+ const bcValueOn = field.valueOn ?? field.optionOnLabel ?? "YES";
6215
+ const bcValueOff = field.valueOff ?? field.optionOffLabel ?? "NO";
6216
+ const bcIsOn = value === bcValueOn || value === true || value !== bcValueOff && value !== false && !!value;
6217
+ input = createElement("div", { className: "flex items-center gap-3" });
6218
+ const bcOptionOff = field.optionOffLabel ?? "NO";
6219
+ const bcOptionOn = field.optionOnLabel ?? "YES";
6220
+ const offSpan = createElement("span", {
6221
+ className: `text-sm font-medium ${!bcIsOn ? "text-gray-900 dark:text-white" : "text-gray-500 dark:text-gray-400"}`,
6222
+ text: bcOptionOff
6223
+ });
6224
+ const bcToggleLabel = createElement("label", { className: "relative inline-flex items-center cursor-pointer" });
6225
+ const bcToggleInput = createElement("input", {
6226
+ type: "checkbox",
6227
+ className: "sr-only peer",
6228
+ checked: bcIsOn,
6229
+ disabled: !isEnabled,
6230
+ onchange: (e) => {
6231
+ const checked = e.target.checked;
6232
+ onChange?.(checked ? bcValueOn : bcValueOff);
6233
+ }
6234
+ });
6235
+ const bcToggleSlider = createElement("div", {
6236
+ className: `w-11 h-6 bg-gray-200 peer-focus:outline-none shadow-none rounded-full peer dark:bg-gray-700 peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-5 after:w-5 after:transition-all dark:border-gray-600 peer-checked:bg-[#019FA2] ${!isEnabled ? "opacity-50 cursor-not-allowed" : ""}`
6237
+ });
6238
+ bcToggleLabel.appendChild(bcToggleInput);
6239
+ bcToggleLabel.appendChild(bcToggleSlider);
6240
+ const onSpan = createElement("span", {
6241
+ className: `text-sm font-medium ${bcIsOn ? "text-gray-900 dark:text-white" : "text-gray-500 dark:text-gray-400"}`,
6242
+ text: bcOptionOn
6243
+ });
6244
+ input.appendChild(offSpan);
6245
+ input.appendChild(bcToggleLabel);
6246
+ input.appendChild(onSpan);
6247
+ break;
6248
+ }
6249
+ case "repeater":
6250
+ const minCount = field.validations?.min ?? 0;
6251
+ const maxCount = field.validations?.max ?? 999;
6252
+ const itemLabel = field.repeatItemLabel ?? "Item";
6253
+ const currentCount = Array.isArray(value) ? value.length : typeof value === "number" ? value : 0;
6254
+ const repeaterContainer = createElement("div", { className: "repeater-field border border-gray-200 dark:border-gray-700 rounded-md p-4" });
6255
+ const repeaterHeader = createElement("div", { className: "flex items-center justify-between mb-3" });
6256
+ repeaterHeader.appendChild(createElement("span", { className: "text-sm font-medium text-gray-700 dark:text-gray-300", text: `${itemLabel}s (${currentCount})` }));
6257
+ const repeaterControls = createElement("div", { className: "flex gap-2" });
6258
+ const addBtn = createElement("button", {
6259
+ type: "button",
6260
+ className: "px-2 py-1 text-xs text-white bg-[#019FA2] rounded hover:bg-[#018a8d] disabled:opacity-50 disabled:cursor-not-allowed",
6261
+ text: "Add",
6262
+ disabled: !isEnabled || currentCount >= maxCount,
6263
+ onclick: () => {
6264
+ const newCount = currentCount + 1;
6265
+ onChange?.(Array.isArray(value) ? [...value, {}] : newCount);
6266
+ }
6267
+ });
6268
+ const removeBtn = createElement("button", {
6269
+ type: "button",
6270
+ className: "px-2 py-1 text-xs text-red-600 border border-red-300 rounded hover:bg-red-50 dark:hover:bg-red-900/20 disabled:opacity-50 disabled:cursor-not-allowed",
6271
+ text: "Remove",
6272
+ disabled: !isEnabled || currentCount <= minCount,
6273
+ onclick: () => {
6274
+ const newCount = Math.max(minCount, currentCount - 1);
6275
+ onChange?.(Array.isArray(value) ? value.slice(0, -1) : newCount);
6276
+ }
6277
+ });
6278
+ repeaterControls.appendChild(addBtn);
6279
+ repeaterControls.appendChild(removeBtn);
6280
+ repeaterHeader.appendChild(repeaterControls);
6281
+ repeaterContainer.appendChild(repeaterHeader);
6282
+ repeaterContainer.appendChild(createElement("p", {
6283
+ className: "text-xs text-gray-500 dark:text-gray-400",
6284
+ text: `Min: ${minCount}, Max: ${maxCount}`
6285
+ }));
6286
+ input = repeaterContainer;
6287
+ break;
6141
6288
  case "phone":
6142
6289
  input = this.renderPhoneField(field, value, onChange, isEnabled);
6143
6290
  break;
@@ -10130,6 +10277,113 @@ var FormBuilder = class {
10130
10277
  (checked) => formStore.getState().updateField(selectedField.id, { visible: checked }),
10131
10278
  `visible-${selectedField.id}`
10132
10279
  ));
10280
+ if (selectedField.type === "binary_choice") {
10281
+ const bcHeader = createElement("h3", { className: "text-xs font-semibold text-gray-500 uppercase tracking-wider mb-3 mt-6", text: "Yes/No Toggle Settings" });
10282
+ body.appendChild(bcHeader);
10283
+ const firstLabelGroup = createElement("div", { className: "mb-3" });
10284
+ firstLabelGroup.appendChild(createElement("label", { className: "block text-sm font-normal text-gray-700 dark:text-gray-300 mb-1", text: "First Label (e.g. YES / ON)" }));
10285
+ firstLabelGroup.appendChild(createElement("input", {
10286
+ type: "text",
10287
+ className: "w-full px-3 py-2 border border-gray-200 dark:border-gray-700 rounded-md bg-transparent",
10288
+ value: selectedField.optionOnLabel ?? "YES",
10289
+ placeholder: "YES",
10290
+ oninput: (e) => {
10291
+ const v = e.target.value;
10292
+ formStore.getState().updateField(selectedField.id, { optionOnLabel: v || "YES", valueOn: v || "YES" });
10293
+ }
10294
+ }));
10295
+ body.appendChild(firstLabelGroup);
10296
+ const secondLabelGroup = createElement("div", { className: "mb-3" });
10297
+ secondLabelGroup.appendChild(createElement("label", { className: "block text-sm font-normal text-gray-700 dark:text-gray-300 mb-1", text: "Second Label (e.g. NO / OFF)" }));
10298
+ secondLabelGroup.appendChild(createElement("input", {
10299
+ type: "text",
10300
+ className: "w-full px-3 py-2 border border-gray-200 dark:border-gray-700 rounded-md bg-transparent",
10301
+ value: selectedField.optionOffLabel ?? "NO",
10302
+ placeholder: "NO",
10303
+ oninput: (e) => {
10304
+ const v = e.target.value;
10305
+ formStore.getState().updateField(selectedField.id, { optionOffLabel: v || "NO", valueOff: v || "NO" });
10306
+ }
10307
+ }));
10308
+ body.appendChild(secondLabelGroup);
10309
+ const defaultSelGroup = createElement("div", { className: "mb-3" });
10310
+ defaultSelGroup.appendChild(createElement("label", { className: "block text-sm font-normal text-gray-700 dark:text-gray-300 mb-1", text: "Default Selection" }));
10311
+ const defaultSelSelect = createElement("select", {
10312
+ className: "w-full px-3 py-2 border border-gray-200 dark:border-gray-700 rounded-md bg-transparent",
10313
+ onchange: (e) => {
10314
+ const val = e.target.value;
10315
+ const valueOn2 = selectedField.valueOn ?? selectedField.optionOnLabel ?? "YES";
10316
+ const valueOff2 = selectedField.valueOff ?? selectedField.optionOffLabel ?? "NO";
10317
+ formStore.getState().updateField(selectedField.id, { defaultValue: val === "YES" ? valueOn2 : valueOff2 });
10318
+ }
10319
+ });
10320
+ const valueOn = selectedField.valueOn ?? selectedField.optionOnLabel ?? "YES";
10321
+ const valueOff = selectedField.valueOff ?? selectedField.optionOffLabel ?? "NO";
10322
+ const currentDefault = selectedField.defaultValue;
10323
+ defaultSelSelect.appendChild(createElement("option", { value: "YES", text: "Yes", selected: currentDefault === valueOn }));
10324
+ defaultSelSelect.appendChild(createElement("option", { value: "NO", text: "No", selected: currentDefault === valueOff || currentDefault === void 0 }));
10325
+ defaultSelGroup.appendChild(defaultSelSelect);
10326
+ body.appendChild(defaultSelGroup);
10327
+ const allFields = state.schema.sections.flatMap((s) => s.fields).filter((f) => f.id !== selectedField.id);
10328
+ const showWhenYesGroup = createElement("div", { className: "mb-3" });
10329
+ showWhenYesGroup.appendChild(createElement("label", { className: "block text-sm font-normal text-gray-700 dark:text-gray-300 mb-1", text: "Show when Toggle = Yes" }));
10330
+ const showWhenYesSelect = createElement("select", {
10331
+ multiple: true,
10332
+ className: "w-full px-3 py-2 border border-gray-200 dark:border-gray-700 rounded-md bg-transparent min-h-[80px]",
10333
+ onchange: () => {
10334
+ const opts = Array.from(showWhenYesSelect.selectedOptions).map((o) => o.value);
10335
+ formStore.getState().updateField(selectedField.id, { showWhenValueOnFields: opts });
10336
+ }
10337
+ });
10338
+ allFields.forEach((f) => {
10339
+ const opt = createElement("option", { value: f.id, text: f.label || f.id });
10340
+ if ((selectedField.showWhenValueOnFields || []).includes(f.id))
10341
+ opt.selected = true;
10342
+ showWhenYesSelect.appendChild(opt);
10343
+ });
10344
+ showWhenYesGroup.appendChild(createElement("p", { className: "text-xs text-gray-500 mt-1", text: "Hold Ctrl/Cmd to select multiple" }));
10345
+ showWhenYesGroup.appendChild(showWhenYesSelect);
10346
+ body.appendChild(showWhenYesGroup);
10347
+ const showWhenNoGroup = createElement("div", { className: "mb-3" });
10348
+ showWhenNoGroup.appendChild(createElement("label", { className: "block text-sm font-normal text-gray-700 dark:text-gray-300 mb-1", text: "Show when Toggle = No" }));
10349
+ const showWhenNoSelect = createElement("select", {
10350
+ multiple: true,
10351
+ className: "w-full px-3 py-2 border border-gray-200 dark:border-gray-700 rounded-md bg-transparent min-h-[80px]",
10352
+ onchange: () => {
10353
+ const opts = Array.from(showWhenNoSelect.selectedOptions).map((o) => o.value);
10354
+ formStore.getState().updateField(selectedField.id, { showWhenValueOffFields: opts });
10355
+ }
10356
+ });
10357
+ allFields.forEach((f) => {
10358
+ const opt = createElement("option", { value: f.id, text: f.label || f.id });
10359
+ if ((selectedField.showWhenValueOffFields || []).includes(f.id))
10360
+ opt.selected = true;
10361
+ showWhenNoSelect.appendChild(opt);
10362
+ });
10363
+ showWhenNoGroup.appendChild(createElement("p", { className: "text-xs text-gray-500 mt-1", text: "Hold Ctrl/Cmd to select multiple" }));
10364
+ showWhenNoGroup.appendChild(showWhenNoSelect);
10365
+ body.appendChild(showWhenNoGroup);
10366
+ }
10367
+ if (selectedField.type === "repeater") {
10368
+ const repHeader = createElement("h3", { className: "text-xs font-semibold text-gray-500 uppercase tracking-wider mb-3 mt-6", text: "Repeater Settings" });
10369
+ body.appendChild(repHeader);
10370
+ const repItemLabelGroup = createElement("div", { className: "mb-3" });
10371
+ repItemLabelGroup.appendChild(createElement("label", { className: "block text-sm font-normal text-gray-700 dark:text-gray-300 mb-1", text: "Item Label" }));
10372
+ repItemLabelGroup.appendChild(createElement("input", {
10373
+ type: "text",
10374
+ className: "w-full px-3 py-2 border border-gray-200 dark:border-gray-700 rounded-md bg-transparent",
10375
+ value: selectedField.repeatItemLabel ?? "Item",
10376
+ placeholder: "Item",
10377
+ oninput: (e) => formStore.getState().updateField(selectedField.id, { repeatItemLabel: e.target.value || "Item" })
10378
+ }));
10379
+ body.appendChild(repItemLabelGroup);
10380
+ body.appendChild(this.createCheckboxField(
10381
+ "Repeat Increment Enabled",
10382
+ selectedField.repeatIncrementEnabled === true,
10383
+ (checked) => formStore.getState().updateField(selectedField.id, { repeatIncrementEnabled: checked }),
10384
+ `repeat-increment-${selectedField.id}`
10385
+ ));
10386
+ }
10133
10387
  if (selectedField.type === "phone") {
10134
10388
  const isdHeader = createElement("h3", { className: "text-xs font-semibold text-gray-500 uppercase tracking-wider mb-3 mt-6", text: "Phone ISD Settings" });
10135
10389
  body.appendChild(isdHeader);
@@ -10627,6 +10881,36 @@ var FormBuilder = class {
10627
10881
  return String(value);
10628
10882
  };
10629
10883
  const validationElements = [];
10884
+ if (selectedField.type === "repeater") {
10885
+ const repMinValGroup = createElement("div", { className: "mb-3" });
10886
+ repMinValGroup.appendChild(createElement("label", { className: "block text-sm font-normal text-gray-700 dark:text-gray-300 mb-1", text: "Min Items" }));
10887
+ repMinValGroup.appendChild(createElement("input", {
10888
+ type: "number",
10889
+ className: "w-full px-3 py-2 border border-gray-200 dark:border-gray-700 rounded-md bg-transparent",
10890
+ value: getValidationsValue("min") || "",
10891
+ placeholder: "e.g. 2",
10892
+ min: "0",
10893
+ oninput: (e) => {
10894
+ const val = e.target.value;
10895
+ updateValidations({ min: val !== "" ? parseInt(val) : void 0 });
10896
+ }
10897
+ }));
10898
+ validationElements.push(repMinValGroup);
10899
+ const repMaxValGroup = createElement("div", { className: "mb-3" });
10900
+ repMaxValGroup.appendChild(createElement("label", { className: "block text-sm font-normal text-gray-700 dark:text-gray-300 mb-1", text: "Max Items" }));
10901
+ repMaxValGroup.appendChild(createElement("input", {
10902
+ type: "number",
10903
+ className: "w-full px-3 py-2 border border-gray-200 dark:border-gray-700 rounded-md bg-transparent",
10904
+ value: getValidationsValue("max") || "",
10905
+ placeholder: "e.g. 4",
10906
+ min: "1",
10907
+ oninput: (e) => {
10908
+ const val = e.target.value;
10909
+ updateValidations({ max: val !== "" ? parseInt(val) : void 0 });
10910
+ }
10911
+ }));
10912
+ validationElements.push(repMaxValGroup);
10913
+ }
10630
10914
  if (selectedField.type === "number") {
10631
10915
  const numValidationTypeGroup = createElement("div", { className: "mb-3" });
10632
10916
  numValidationTypeGroup.appendChild(createElement("label", { className: "block text-sm font-normal text-gray-700 dark:text-gray-300 mb-1", text: "Validation Type" }));