form-builder-pro 1.3.1 → 1.3.3
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 +4 -0
- package/dist/index.d.mts +9 -1
- package/dist/index.d.ts +9 -1
- package/dist/index.js +322 -9
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +322 -9
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
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
|
};
|
|
@@ -4346,11 +4367,13 @@ function validationsToValidationObject(v) {
|
|
|
4346
4367
|
function validationObjectToValidations(v) {
|
|
4347
4368
|
if (!v)
|
|
4348
4369
|
return void 0;
|
|
4370
|
+
const vAny = v;
|
|
4349
4371
|
const validations = {};
|
|
4350
4372
|
if (v.required !== void 0)
|
|
4351
4373
|
validations.required = v.required;
|
|
4352
|
-
|
|
4353
|
-
|
|
4374
|
+
const patternVal = v.regex || vAny.pattern;
|
|
4375
|
+
if (patternVal)
|
|
4376
|
+
validations.pattern = patternVal;
|
|
4354
4377
|
if (v.minLength !== void 0)
|
|
4355
4378
|
validations.minLength = v.minLength;
|
|
4356
4379
|
if (v.maxLength !== void 0)
|
|
@@ -4359,8 +4382,9 @@ function validationObjectToValidations(v) {
|
|
|
4359
4382
|
validations.min = v.min;
|
|
4360
4383
|
if (v.max !== void 0)
|
|
4361
4384
|
validations.max = v.max;
|
|
4362
|
-
|
|
4363
|
-
|
|
4385
|
+
const patternMsg = v.regexMessage || vAny.customErrorMessages?.pattern;
|
|
4386
|
+
if (patternMsg) {
|
|
4387
|
+
validations.customErrorMessages = { ...validations.customErrorMessages, pattern: patternMsg };
|
|
4364
4388
|
}
|
|
4365
4389
|
if (v.minSelected !== void 0)
|
|
4366
4390
|
validations.minSelected = v.minSelected;
|
|
@@ -4421,12 +4445,17 @@ function convertSpanToWidth(span, totalColumns = 12) {
|
|
|
4421
4445
|
function normalizeFieldType(type) {
|
|
4422
4446
|
if (!type)
|
|
4423
4447
|
return "text";
|
|
4424
|
-
const
|
|
4448
|
+
const str = String(type);
|
|
4449
|
+
const normalized = str.toLowerCase().replace(/_/g, "");
|
|
4425
4450
|
if (normalized === "decimal")
|
|
4426
4451
|
return "number";
|
|
4427
4452
|
if (["phonenumber", "telephone", "mobile"].includes(normalized))
|
|
4428
4453
|
return "phone";
|
|
4429
|
-
|
|
4454
|
+
if (str === "BINARY_CHOICE" || normalized === "binarychoice")
|
|
4455
|
+
return "binary_choice";
|
|
4456
|
+
if (str === "REPEATER" || normalized === "repeater")
|
|
4457
|
+
return "repeater";
|
|
4458
|
+
return str.toLowerCase();
|
|
4430
4459
|
}
|
|
4431
4460
|
function transformField(field) {
|
|
4432
4461
|
const fieldId = field.id || field.fieldId;
|
|
@@ -4529,6 +4558,22 @@ function transformField(field) {
|
|
|
4529
4558
|
transformed.validation = { required: field.required };
|
|
4530
4559
|
transformed.validations = { required: field.required };
|
|
4531
4560
|
}
|
|
4561
|
+
if (normalizedType === "email" && transformed.validations && !transformed.validations.pattern) {
|
|
4562
|
+
const emailDefault = DEFAULT_FIELD_CONFIG.email?.validation;
|
|
4563
|
+
if (Array.isArray(emailDefault)) {
|
|
4564
|
+
const patternRule = emailDefault.find((r) => r.type === "pattern" && r.regex);
|
|
4565
|
+
if (patternRule) {
|
|
4566
|
+
transformed.validations = {
|
|
4567
|
+
...transformed.validations,
|
|
4568
|
+
pattern: patternRule.regex,
|
|
4569
|
+
customErrorMessages: { ...transformed.validations.customErrorMessages, pattern: patternRule.message || "Invalid email format" }
|
|
4570
|
+
};
|
|
4571
|
+
transformed.validation = transformed.validation || {};
|
|
4572
|
+
transformed.validation.regex = patternRule.regex;
|
|
4573
|
+
transformed.validation.regexMessage = patternRule.message || "Invalid email format";
|
|
4574
|
+
}
|
|
4575
|
+
}
|
|
4576
|
+
}
|
|
4532
4577
|
if (normalizedType === "select") {
|
|
4533
4578
|
if (field.multiSelect !== void 0) {
|
|
4534
4579
|
transformed.multiSelect = field.multiSelect;
|
|
@@ -4604,6 +4649,24 @@ function transformField(field) {
|
|
|
4604
4649
|
transformed.formula = field.formula;
|
|
4605
4650
|
if (field.dependencies !== void 0 && Array.isArray(field.dependencies))
|
|
4606
4651
|
transformed.dependencies = field.dependencies;
|
|
4652
|
+
if (field.optionOnLabel !== void 0)
|
|
4653
|
+
transformed.optionOnLabel = field.optionOnLabel;
|
|
4654
|
+
if (field.optionOffLabel !== void 0)
|
|
4655
|
+
transformed.optionOffLabel = field.optionOffLabel;
|
|
4656
|
+
if (field.valueOn !== void 0)
|
|
4657
|
+
transformed.valueOn = field.valueOn;
|
|
4658
|
+
if (field.valueOff !== void 0)
|
|
4659
|
+
transformed.valueOff = field.valueOff;
|
|
4660
|
+
if (field.showWhenValueOnFields !== void 0 && Array.isArray(field.showWhenValueOnFields)) {
|
|
4661
|
+
transformed.showWhenValueOnFields = field.showWhenValueOnFields;
|
|
4662
|
+
}
|
|
4663
|
+
if (field.showWhenValueOffFields !== void 0 && Array.isArray(field.showWhenValueOffFields)) {
|
|
4664
|
+
transformed.showWhenValueOffFields = field.showWhenValueOffFields;
|
|
4665
|
+
}
|
|
4666
|
+
if (field.repeatItemLabel !== void 0)
|
|
4667
|
+
transformed.repeatItemLabel = field.repeatItemLabel;
|
|
4668
|
+
if (field.repeatIncrementEnabled !== void 0)
|
|
4669
|
+
transformed.repeatIncrementEnabled = field.repeatIncrementEnabled;
|
|
4607
4670
|
if (field.css !== void 0)
|
|
4608
4671
|
transformed.css = field.css;
|
|
4609
4672
|
if (field.optionsSource !== void 0)
|
|
@@ -4757,7 +4820,17 @@ function fieldToPayload(field) {
|
|
|
4757
4820
|
payload.required = true;
|
|
4758
4821
|
}
|
|
4759
4822
|
}
|
|
4760
|
-
|
|
4823
|
+
const baseValidation = field.validations ? validationsToValidationObject(field.validations) : convertValidationArrayToObject(field.validation);
|
|
4824
|
+
payload.validation = baseValidation;
|
|
4825
|
+
const pattern = baseValidation?.regex ?? field.validations?.pattern;
|
|
4826
|
+
const patternMsg = baseValidation?.regexMessage ?? field.validations?.customErrorMessages?.pattern;
|
|
4827
|
+
if (baseValidation && pattern) {
|
|
4828
|
+
payload.validation = {
|
|
4829
|
+
...baseValidation,
|
|
4830
|
+
pattern,
|
|
4831
|
+
...patternMsg && { customErrorMessages: { pattern: patternMsg } }
|
|
4832
|
+
};
|
|
4833
|
+
}
|
|
4761
4834
|
if (payload.validation?.required || payload.validations?.required) {
|
|
4762
4835
|
payload.required = true;
|
|
4763
4836
|
}
|
|
@@ -4807,6 +4880,34 @@ function fieldToPayload(field) {
|
|
|
4807
4880
|
if ((field.type === "select" || field.type === "radio" || field.type === "checkbox") && field.options && Array.isArray(field.options)) {
|
|
4808
4881
|
payload.options = field.options.map((opt) => ({ label: opt.label, value: opt.value }));
|
|
4809
4882
|
}
|
|
4883
|
+
if (field.type === "binary_choice") {
|
|
4884
|
+
payload.fieldType = "BINARY_CHOICE";
|
|
4885
|
+
payload.type = "binary_choice";
|
|
4886
|
+
payload.optionOnLabel = field.optionOnLabel ?? "YES";
|
|
4887
|
+
payload.optionOffLabel = field.optionOffLabel ?? "NO";
|
|
4888
|
+
payload.valueOn = field.valueOn ?? field.optionOnLabel ?? "YES";
|
|
4889
|
+
payload.valueOff = field.valueOff ?? field.optionOffLabel ?? "NO";
|
|
4890
|
+
if (field.showWhenValueOnFields && field.showWhenValueOnFields.length > 0) {
|
|
4891
|
+
payload.showWhenValueOnFields = field.showWhenValueOnFields;
|
|
4892
|
+
}
|
|
4893
|
+
if (field.showWhenValueOffFields && field.showWhenValueOffFields.length > 0) {
|
|
4894
|
+
payload.showWhenValueOffFields = field.showWhenValueOffFields;
|
|
4895
|
+
}
|
|
4896
|
+
}
|
|
4897
|
+
if (field.type === "repeater") {
|
|
4898
|
+
payload.fieldType = "REPEATER";
|
|
4899
|
+
payload.type = "number";
|
|
4900
|
+
payload.repeatItemLabel = field.repeatItemLabel ?? "Item";
|
|
4901
|
+
payload.repeatIncrementEnabled = field.repeatIncrementEnabled ?? false;
|
|
4902
|
+
if (field.validations?.min !== void 0 || field.validations?.max !== void 0) {
|
|
4903
|
+
const v = payload.validation || {};
|
|
4904
|
+
if (field.validations.min !== void 0)
|
|
4905
|
+
v.min = field.validations.min;
|
|
4906
|
+
if (field.validations.max !== void 0)
|
|
4907
|
+
v.max = field.validations.max;
|
|
4908
|
+
payload.validation = v;
|
|
4909
|
+
}
|
|
4910
|
+
}
|
|
4810
4911
|
return payload;
|
|
4811
4912
|
}
|
|
4812
4913
|
var builderToPlatform = (builderSchema) => {
|
|
@@ -5913,7 +6014,7 @@ var FieldRenderer = class {
|
|
|
5913
6014
|
static render(field, value, onChange, readOnly = false) {
|
|
5914
6015
|
const wrapper = createElement("div", { className: "w-full form-row" });
|
|
5915
6016
|
const isEnabled = field.enabled !== false && !readOnly;
|
|
5916
|
-
if (field.type !== "checkbox" && field.type !== "toggle") {
|
|
6017
|
+
if (field.type !== "checkbox" && field.type !== "toggle" && field.type !== "binary_choice") {
|
|
5917
6018
|
const label = createElement("label", {
|
|
5918
6019
|
className: "text-xs sm:text-sm font-medium leading-none mb-2 block text-gray-900 dark:text-gray-100",
|
|
5919
6020
|
text: field.label
|
|
@@ -5931,7 +6032,7 @@ var FieldRenderer = class {
|
|
|
5931
6032
|
label.appendChild(createElement("span", { className: "text-red-500 ml-1", text: "*" }));
|
|
5932
6033
|
}
|
|
5933
6034
|
wrapper.appendChild(label);
|
|
5934
|
-
} else if (field.type === "toggle") {
|
|
6035
|
+
} else if (field.type === "toggle" || field.type === "binary_choice") {
|
|
5935
6036
|
const label = createElement("label", {
|
|
5936
6037
|
className: "text-xs sm:text-sm font-medium leading-none mb-2 block text-gray-900 dark:text-gray-100",
|
|
5937
6038
|
text: field.label
|
|
@@ -6138,6 +6239,81 @@ var FieldRenderer = class {
|
|
|
6138
6239
|
toggleLabel.appendChild(toggleSlider);
|
|
6139
6240
|
input.appendChild(toggleLabel);
|
|
6140
6241
|
break;
|
|
6242
|
+
case "binary_choice": {
|
|
6243
|
+
const bcValueOn = field.valueOn ?? field.optionOnLabel ?? "YES";
|
|
6244
|
+
const bcValueOff = field.valueOff ?? field.optionOffLabel ?? "NO";
|
|
6245
|
+
const bcIsOn = value === bcValueOn || value === true || value !== bcValueOff && value !== false && !!value;
|
|
6246
|
+
input = createElement("div", { className: "flex items-center gap-3" });
|
|
6247
|
+
const bcOptionOff = field.optionOffLabel ?? "NO";
|
|
6248
|
+
const bcOptionOn = field.optionOnLabel ?? "YES";
|
|
6249
|
+
const offSpan = createElement("span", {
|
|
6250
|
+
className: `text-sm font-medium ${!bcIsOn ? "text-gray-900 dark:text-white" : "text-gray-500 dark:text-gray-400"}`,
|
|
6251
|
+
text: bcOptionOff
|
|
6252
|
+
});
|
|
6253
|
+
const bcToggleLabel = createElement("label", { className: "relative inline-flex items-center cursor-pointer" });
|
|
6254
|
+
const bcToggleInput = createElement("input", {
|
|
6255
|
+
type: "checkbox",
|
|
6256
|
+
className: "sr-only peer",
|
|
6257
|
+
checked: bcIsOn,
|
|
6258
|
+
disabled: !isEnabled,
|
|
6259
|
+
onchange: (e) => {
|
|
6260
|
+
const checked = e.target.checked;
|
|
6261
|
+
onChange?.(checked ? bcValueOn : bcValueOff);
|
|
6262
|
+
}
|
|
6263
|
+
});
|
|
6264
|
+
const bcToggleSlider = createElement("div", {
|
|
6265
|
+
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" : ""}`
|
|
6266
|
+
});
|
|
6267
|
+
bcToggleLabel.appendChild(bcToggleInput);
|
|
6268
|
+
bcToggleLabel.appendChild(bcToggleSlider);
|
|
6269
|
+
const onSpan = createElement("span", {
|
|
6270
|
+
className: `text-sm font-medium ${bcIsOn ? "text-gray-900 dark:text-white" : "text-gray-500 dark:text-gray-400"}`,
|
|
6271
|
+
text: bcOptionOn
|
|
6272
|
+
});
|
|
6273
|
+
input.appendChild(offSpan);
|
|
6274
|
+
input.appendChild(bcToggleLabel);
|
|
6275
|
+
input.appendChild(onSpan);
|
|
6276
|
+
break;
|
|
6277
|
+
}
|
|
6278
|
+
case "repeater":
|
|
6279
|
+
const minCount = field.validations?.min ?? 0;
|
|
6280
|
+
const maxCount = field.validations?.max ?? 999;
|
|
6281
|
+
const itemLabel = field.repeatItemLabel ?? "Item";
|
|
6282
|
+
const currentCount = Array.isArray(value) ? value.length : typeof value === "number" ? value : 0;
|
|
6283
|
+
const repeaterContainer = createElement("div", { className: "repeater-field border border-gray-200 dark:border-gray-700 rounded-md p-4" });
|
|
6284
|
+
const repeaterHeader = createElement("div", { className: "flex items-center justify-between mb-3" });
|
|
6285
|
+
repeaterHeader.appendChild(createElement("span", { className: "text-sm font-medium text-gray-700 dark:text-gray-300", text: `${itemLabel}s (${currentCount})` }));
|
|
6286
|
+
const repeaterControls = createElement("div", { className: "flex gap-2" });
|
|
6287
|
+
const addBtn = createElement("button", {
|
|
6288
|
+
type: "button",
|
|
6289
|
+
className: "px-2 py-1 text-xs text-white bg-[#019FA2] rounded hover:bg-[#018a8d] disabled:opacity-50 disabled:cursor-not-allowed",
|
|
6290
|
+
text: "Add",
|
|
6291
|
+
disabled: !isEnabled || currentCount >= maxCount,
|
|
6292
|
+
onclick: () => {
|
|
6293
|
+
const newCount = currentCount + 1;
|
|
6294
|
+
onChange?.(Array.isArray(value) ? [...value, {}] : newCount);
|
|
6295
|
+
}
|
|
6296
|
+
});
|
|
6297
|
+
const removeBtn = createElement("button", {
|
|
6298
|
+
type: "button",
|
|
6299
|
+
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",
|
|
6300
|
+
text: "Remove",
|
|
6301
|
+
disabled: !isEnabled || currentCount <= minCount,
|
|
6302
|
+
onclick: () => {
|
|
6303
|
+
const newCount = Math.max(minCount, currentCount - 1);
|
|
6304
|
+
onChange?.(Array.isArray(value) ? value.slice(0, -1) : newCount);
|
|
6305
|
+
}
|
|
6306
|
+
});
|
|
6307
|
+
repeaterControls.appendChild(addBtn);
|
|
6308
|
+
repeaterControls.appendChild(removeBtn);
|
|
6309
|
+
repeaterHeader.appendChild(repeaterControls);
|
|
6310
|
+
repeaterContainer.appendChild(repeaterHeader);
|
|
6311
|
+
repeaterContainer.appendChild(createElement("p", {
|
|
6312
|
+
className: "text-xs text-gray-500 dark:text-gray-400",
|
|
6313
|
+
text: `Min: ${minCount}, Max: ${maxCount}`
|
|
6314
|
+
}));
|
|
6315
|
+
input = repeaterContainer;
|
|
6316
|
+
break;
|
|
6141
6317
|
case "phone":
|
|
6142
6318
|
input = this.renderPhoneField(field, value, onChange, isEnabled);
|
|
6143
6319
|
break;
|
|
@@ -10130,6 +10306,113 @@ var FormBuilder = class {
|
|
|
10130
10306
|
(checked) => formStore.getState().updateField(selectedField.id, { visible: checked }),
|
|
10131
10307
|
`visible-${selectedField.id}`
|
|
10132
10308
|
));
|
|
10309
|
+
if (selectedField.type === "binary_choice") {
|
|
10310
|
+
const bcHeader = createElement("h3", { className: "text-xs font-semibold text-gray-500 uppercase tracking-wider mb-3 mt-6", text: "Yes/No Toggle Settings" });
|
|
10311
|
+
body.appendChild(bcHeader);
|
|
10312
|
+
const firstLabelGroup = createElement("div", { className: "mb-3" });
|
|
10313
|
+
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)" }));
|
|
10314
|
+
firstLabelGroup.appendChild(createElement("input", {
|
|
10315
|
+
type: "text",
|
|
10316
|
+
className: "w-full px-3 py-2 border border-gray-200 dark:border-gray-700 rounded-md bg-transparent",
|
|
10317
|
+
value: selectedField.optionOnLabel ?? "YES",
|
|
10318
|
+
placeholder: "YES",
|
|
10319
|
+
oninput: (e) => {
|
|
10320
|
+
const v = e.target.value;
|
|
10321
|
+
formStore.getState().updateField(selectedField.id, { optionOnLabel: v || "YES", valueOn: v || "YES" });
|
|
10322
|
+
}
|
|
10323
|
+
}));
|
|
10324
|
+
body.appendChild(firstLabelGroup);
|
|
10325
|
+
const secondLabelGroup = createElement("div", { className: "mb-3" });
|
|
10326
|
+
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)" }));
|
|
10327
|
+
secondLabelGroup.appendChild(createElement("input", {
|
|
10328
|
+
type: "text",
|
|
10329
|
+
className: "w-full px-3 py-2 border border-gray-200 dark:border-gray-700 rounded-md bg-transparent",
|
|
10330
|
+
value: selectedField.optionOffLabel ?? "NO",
|
|
10331
|
+
placeholder: "NO",
|
|
10332
|
+
oninput: (e) => {
|
|
10333
|
+
const v = e.target.value;
|
|
10334
|
+
formStore.getState().updateField(selectedField.id, { optionOffLabel: v || "NO", valueOff: v || "NO" });
|
|
10335
|
+
}
|
|
10336
|
+
}));
|
|
10337
|
+
body.appendChild(secondLabelGroup);
|
|
10338
|
+
const defaultSelGroup = createElement("div", { className: "mb-3" });
|
|
10339
|
+
defaultSelGroup.appendChild(createElement("label", { className: "block text-sm font-normal text-gray-700 dark:text-gray-300 mb-1", text: "Default Selection" }));
|
|
10340
|
+
const defaultSelSelect = createElement("select", {
|
|
10341
|
+
className: "w-full px-3 py-2 border border-gray-200 dark:border-gray-700 rounded-md bg-transparent",
|
|
10342
|
+
onchange: (e) => {
|
|
10343
|
+
const val = e.target.value;
|
|
10344
|
+
const valueOn2 = selectedField.valueOn ?? selectedField.optionOnLabel ?? "YES";
|
|
10345
|
+
const valueOff2 = selectedField.valueOff ?? selectedField.optionOffLabel ?? "NO";
|
|
10346
|
+
formStore.getState().updateField(selectedField.id, { defaultValue: val === "YES" ? valueOn2 : valueOff2 });
|
|
10347
|
+
}
|
|
10348
|
+
});
|
|
10349
|
+
const valueOn = selectedField.valueOn ?? selectedField.optionOnLabel ?? "YES";
|
|
10350
|
+
const valueOff = selectedField.valueOff ?? selectedField.optionOffLabel ?? "NO";
|
|
10351
|
+
const currentDefault = selectedField.defaultValue;
|
|
10352
|
+
defaultSelSelect.appendChild(createElement("option", { value: "YES", text: "Yes", selected: currentDefault === valueOn }));
|
|
10353
|
+
defaultSelSelect.appendChild(createElement("option", { value: "NO", text: "No", selected: currentDefault === valueOff || currentDefault === void 0 }));
|
|
10354
|
+
defaultSelGroup.appendChild(defaultSelSelect);
|
|
10355
|
+
body.appendChild(defaultSelGroup);
|
|
10356
|
+
const allFields = state.schema.sections.flatMap((s) => s.fields).filter((f) => f.id !== selectedField.id);
|
|
10357
|
+
const showWhenYesGroup = createElement("div", { className: "mb-3" });
|
|
10358
|
+
showWhenYesGroup.appendChild(createElement("label", { className: "block text-sm font-normal text-gray-700 dark:text-gray-300 mb-1", text: "Show when Toggle = Yes" }));
|
|
10359
|
+
const showWhenYesSelect = createElement("select", {
|
|
10360
|
+
multiple: true,
|
|
10361
|
+
className: "w-full px-3 py-2 border border-gray-200 dark:border-gray-700 rounded-md bg-transparent min-h-[80px]",
|
|
10362
|
+
onchange: () => {
|
|
10363
|
+
const opts = Array.from(showWhenYesSelect.selectedOptions).map((o) => o.value);
|
|
10364
|
+
formStore.getState().updateField(selectedField.id, { showWhenValueOnFields: opts });
|
|
10365
|
+
}
|
|
10366
|
+
});
|
|
10367
|
+
allFields.forEach((f) => {
|
|
10368
|
+
const opt = createElement("option", { value: f.id, text: f.label || f.id });
|
|
10369
|
+
if ((selectedField.showWhenValueOnFields || []).includes(f.id))
|
|
10370
|
+
opt.selected = true;
|
|
10371
|
+
showWhenYesSelect.appendChild(opt);
|
|
10372
|
+
});
|
|
10373
|
+
showWhenYesGroup.appendChild(createElement("p", { className: "text-xs text-gray-500 mt-1", text: "Hold Ctrl/Cmd to select multiple" }));
|
|
10374
|
+
showWhenYesGroup.appendChild(showWhenYesSelect);
|
|
10375
|
+
body.appendChild(showWhenYesGroup);
|
|
10376
|
+
const showWhenNoGroup = createElement("div", { className: "mb-3" });
|
|
10377
|
+
showWhenNoGroup.appendChild(createElement("label", { className: "block text-sm font-normal text-gray-700 dark:text-gray-300 mb-1", text: "Show when Toggle = No" }));
|
|
10378
|
+
const showWhenNoSelect = createElement("select", {
|
|
10379
|
+
multiple: true,
|
|
10380
|
+
className: "w-full px-3 py-2 border border-gray-200 dark:border-gray-700 rounded-md bg-transparent min-h-[80px]",
|
|
10381
|
+
onchange: () => {
|
|
10382
|
+
const opts = Array.from(showWhenNoSelect.selectedOptions).map((o) => o.value);
|
|
10383
|
+
formStore.getState().updateField(selectedField.id, { showWhenValueOffFields: opts });
|
|
10384
|
+
}
|
|
10385
|
+
});
|
|
10386
|
+
allFields.forEach((f) => {
|
|
10387
|
+
const opt = createElement("option", { value: f.id, text: f.label || f.id });
|
|
10388
|
+
if ((selectedField.showWhenValueOffFields || []).includes(f.id))
|
|
10389
|
+
opt.selected = true;
|
|
10390
|
+
showWhenNoSelect.appendChild(opt);
|
|
10391
|
+
});
|
|
10392
|
+
showWhenNoGroup.appendChild(createElement("p", { className: "text-xs text-gray-500 mt-1", text: "Hold Ctrl/Cmd to select multiple" }));
|
|
10393
|
+
showWhenNoGroup.appendChild(showWhenNoSelect);
|
|
10394
|
+
body.appendChild(showWhenNoGroup);
|
|
10395
|
+
}
|
|
10396
|
+
if (selectedField.type === "repeater") {
|
|
10397
|
+
const repHeader = createElement("h3", { className: "text-xs font-semibold text-gray-500 uppercase tracking-wider mb-3 mt-6", text: "Repeater Settings" });
|
|
10398
|
+
body.appendChild(repHeader);
|
|
10399
|
+
const repItemLabelGroup = createElement("div", { className: "mb-3" });
|
|
10400
|
+
repItemLabelGroup.appendChild(createElement("label", { className: "block text-sm font-normal text-gray-700 dark:text-gray-300 mb-1", text: "Item Label" }));
|
|
10401
|
+
repItemLabelGroup.appendChild(createElement("input", {
|
|
10402
|
+
type: "text",
|
|
10403
|
+
className: "w-full px-3 py-2 border border-gray-200 dark:border-gray-700 rounded-md bg-transparent",
|
|
10404
|
+
value: selectedField.repeatItemLabel ?? "Item",
|
|
10405
|
+
placeholder: "Item",
|
|
10406
|
+
oninput: (e) => formStore.getState().updateField(selectedField.id, { repeatItemLabel: e.target.value || "Item" })
|
|
10407
|
+
}));
|
|
10408
|
+
body.appendChild(repItemLabelGroup);
|
|
10409
|
+
body.appendChild(this.createCheckboxField(
|
|
10410
|
+
"Repeat Increment Enabled",
|
|
10411
|
+
selectedField.repeatIncrementEnabled === true,
|
|
10412
|
+
(checked) => formStore.getState().updateField(selectedField.id, { repeatIncrementEnabled: checked }),
|
|
10413
|
+
`repeat-increment-${selectedField.id}`
|
|
10414
|
+
));
|
|
10415
|
+
}
|
|
10133
10416
|
if (selectedField.type === "phone") {
|
|
10134
10417
|
const isdHeader = createElement("h3", { className: "text-xs font-semibold text-gray-500 uppercase tracking-wider mb-3 mt-6", text: "Phone ISD Settings" });
|
|
10135
10418
|
body.appendChild(isdHeader);
|
|
@@ -10627,6 +10910,36 @@ var FormBuilder = class {
|
|
|
10627
10910
|
return String(value);
|
|
10628
10911
|
};
|
|
10629
10912
|
const validationElements = [];
|
|
10913
|
+
if (selectedField.type === "repeater") {
|
|
10914
|
+
const repMinValGroup = createElement("div", { className: "mb-3" });
|
|
10915
|
+
repMinValGroup.appendChild(createElement("label", { className: "block text-sm font-normal text-gray-700 dark:text-gray-300 mb-1", text: "Min Items" }));
|
|
10916
|
+
repMinValGroup.appendChild(createElement("input", {
|
|
10917
|
+
type: "number",
|
|
10918
|
+
className: "w-full px-3 py-2 border border-gray-200 dark:border-gray-700 rounded-md bg-transparent",
|
|
10919
|
+
value: getValidationsValue("min") || "",
|
|
10920
|
+
placeholder: "e.g. 2",
|
|
10921
|
+
min: "0",
|
|
10922
|
+
oninput: (e) => {
|
|
10923
|
+
const val = e.target.value;
|
|
10924
|
+
updateValidations({ min: val !== "" ? parseInt(val) : void 0 });
|
|
10925
|
+
}
|
|
10926
|
+
}));
|
|
10927
|
+
validationElements.push(repMinValGroup);
|
|
10928
|
+
const repMaxValGroup = createElement("div", { className: "mb-3" });
|
|
10929
|
+
repMaxValGroup.appendChild(createElement("label", { className: "block text-sm font-normal text-gray-700 dark:text-gray-300 mb-1", text: "Max Items" }));
|
|
10930
|
+
repMaxValGroup.appendChild(createElement("input", {
|
|
10931
|
+
type: "number",
|
|
10932
|
+
className: "w-full px-3 py-2 border border-gray-200 dark:border-gray-700 rounded-md bg-transparent",
|
|
10933
|
+
value: getValidationsValue("max") || "",
|
|
10934
|
+
placeholder: "e.g. 4",
|
|
10935
|
+
min: "1",
|
|
10936
|
+
oninput: (e) => {
|
|
10937
|
+
const val = e.target.value;
|
|
10938
|
+
updateValidations({ max: val !== "" ? parseInt(val) : void 0 });
|
|
10939
|
+
}
|
|
10940
|
+
}));
|
|
10941
|
+
validationElements.push(repMaxValGroup);
|
|
10942
|
+
}
|
|
10630
10943
|
if (selectedField.type === "number") {
|
|
10631
10944
|
const numValidationTypeGroup = createElement("div", { className: "mb-3" });
|
|
10632
10945
|
numValidationTypeGroup.appendChild(createElement("label", { className: "block text-sm font-normal text-gray-700 dark:text-gray-300 mb-1", text: "Validation Type" }));
|