@dmitryvim/form-builder 0.2.8 → 0.2.10
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/README.md +104 -40
- package/dist/browser/formbuilder.min.js +71 -53
- package/dist/browser/formbuilder.v0.2.10.min.js +322 -0
- package/dist/cjs/index.cjs +610 -164
- package/dist/cjs/index.cjs.map +1 -1
- package/dist/esm/index.js +602 -160
- package/dist/esm/index.js.map +1 -1
- package/dist/form-builder.js +71 -53
- package/dist/types/instance/FormBuilderInstance.d.ts +5 -1
- package/dist/types/types/index.d.ts +1 -1
- package/dist/types/types/schema.d.ts +6 -3
- package/dist/types/utils/enable-conditions.d.ts +18 -0
- package/package.json +1 -1
- package/dist/browser/formbuilder.v0.2.8.min.js +0 -304
- package/dist/types/utils/display-conditions.d.ts +0 -17
package/dist/esm/index.js
CHANGED
|
@@ -60,6 +60,41 @@ function validateSchema(schema) {
|
|
|
60
60
|
errors.push("Schema missing elements array");
|
|
61
61
|
return errors;
|
|
62
62
|
}
|
|
63
|
+
if ("columns" in schema && schema.columns !== void 0) {
|
|
64
|
+
const columns = schema.columns;
|
|
65
|
+
const validColumns = [1, 2, 3, 4];
|
|
66
|
+
if (!Number.isInteger(columns) || !validColumns.includes(columns)) {
|
|
67
|
+
errors.push(`schema.columns must be 1, 2, 3, or 4 (got ${columns})`);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
if ("prefillHints" in schema && schema.prefillHints) {
|
|
71
|
+
const prefillHints = schema.prefillHints;
|
|
72
|
+
if (Array.isArray(prefillHints)) {
|
|
73
|
+
prefillHints.forEach((hint, hintIndex) => {
|
|
74
|
+
if (!hint.label || typeof hint.label !== "string") {
|
|
75
|
+
errors.push(
|
|
76
|
+
`schema.prefillHints[${hintIndex}] must have a 'label' property of type string`
|
|
77
|
+
);
|
|
78
|
+
}
|
|
79
|
+
if (!hint.values || typeof hint.values !== "object") {
|
|
80
|
+
errors.push(
|
|
81
|
+
`schema.prefillHints[${hintIndex}] must have a 'values' property of type object`
|
|
82
|
+
);
|
|
83
|
+
} else {
|
|
84
|
+
for (const fieldKey in hint.values) {
|
|
85
|
+
const fieldExists = schema.elements.some(
|
|
86
|
+
(element) => element.key === fieldKey
|
|
87
|
+
);
|
|
88
|
+
if (!fieldExists) {
|
|
89
|
+
errors.push(
|
|
90
|
+
`schema.prefillHints[${hintIndex}] references non-existent field "${fieldKey}"`
|
|
91
|
+
);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
}
|
|
63
98
|
function validateElements(elements, path) {
|
|
64
99
|
elements.forEach((element, index) => {
|
|
65
100
|
const elementPath = `${path}[${index}]`;
|
|
@@ -69,17 +104,17 @@ function validateSchema(schema) {
|
|
|
69
104
|
if (!element.key) {
|
|
70
105
|
errors.push(`${elementPath}: missing key`);
|
|
71
106
|
}
|
|
72
|
-
if (element.
|
|
73
|
-
const
|
|
74
|
-
if (!
|
|
107
|
+
if (element.enableIf) {
|
|
108
|
+
const enableIf = element.enableIf;
|
|
109
|
+
if (!enableIf.key || typeof enableIf.key !== "string") {
|
|
75
110
|
errors.push(
|
|
76
|
-
`${elementPath}:
|
|
111
|
+
`${elementPath}: enableIf must have a 'key' property of type string`
|
|
77
112
|
);
|
|
78
113
|
}
|
|
79
|
-
const hasOperator = "equals" in
|
|
114
|
+
const hasOperator = "equals" in enableIf;
|
|
80
115
|
if (!hasOperator) {
|
|
81
116
|
errors.push(
|
|
82
|
-
`${elementPath}:
|
|
117
|
+
`${elementPath}: enableIf must have at least one operator (equals, etc.)`
|
|
83
118
|
);
|
|
84
119
|
}
|
|
85
120
|
}
|
|
@@ -157,7 +192,7 @@ function clear(node) {
|
|
|
157
192
|
while (node.firstChild) node.removeChild(node.firstChild);
|
|
158
193
|
}
|
|
159
194
|
|
|
160
|
-
// src/utils/
|
|
195
|
+
// src/utils/enable-conditions.ts
|
|
161
196
|
function getValueByPath(data, path) {
|
|
162
197
|
if (!data || typeof data !== "object") {
|
|
163
198
|
return void 0;
|
|
@@ -183,18 +218,27 @@ function getValueByPath(data, path) {
|
|
|
183
218
|
}
|
|
184
219
|
return current;
|
|
185
220
|
}
|
|
186
|
-
function
|
|
221
|
+
function evaluateEnableCondition(condition, formData, containerData) {
|
|
187
222
|
if (!condition || !condition.key) {
|
|
223
|
+
throw new Error("Invalid enableIf condition: must have a 'key' property");
|
|
224
|
+
}
|
|
225
|
+
const scope = condition.scope ?? "relative";
|
|
226
|
+
let dataSource;
|
|
227
|
+
if (scope === "relative") {
|
|
228
|
+
dataSource = containerData ?? formData;
|
|
229
|
+
} else if (scope === "absolute") {
|
|
230
|
+
dataSource = formData;
|
|
231
|
+
} else {
|
|
188
232
|
throw new Error(
|
|
189
|
-
|
|
233
|
+
`Invalid enableIf scope: must be "relative" or "absolute" (got "${scope}")`
|
|
190
234
|
);
|
|
191
235
|
}
|
|
192
|
-
const actualValue = getValueByPath(
|
|
236
|
+
const actualValue = getValueByPath(dataSource, condition.key);
|
|
193
237
|
if ("equals" in condition) {
|
|
194
238
|
return deepEqual(actualValue, condition.equals);
|
|
195
239
|
}
|
|
196
240
|
throw new Error(
|
|
197
|
-
`Invalid
|
|
241
|
+
`Invalid enableIf condition: no recognized operator (equals, etc.)`
|
|
198
242
|
);
|
|
199
243
|
}
|
|
200
244
|
function deepEqual(a, b) {
|
|
@@ -207,7 +251,7 @@ function deepEqual(a, b) {
|
|
|
207
251
|
} catch (e) {
|
|
208
252
|
if (e instanceof TypeError && (e.message.includes("circular") || e.message.includes("cyclic"))) {
|
|
209
253
|
console.warn(
|
|
210
|
-
"deepEqual: Circular reference detected in
|
|
254
|
+
"deepEqual: Circular reference detected in enableIf comparison, using reference equality"
|
|
211
255
|
);
|
|
212
256
|
return a === b;
|
|
213
257
|
}
|
|
@@ -260,7 +304,8 @@ function renderTextElement(element, ctx, wrapper, pathKey) {
|
|
|
260
304
|
}
|
|
261
305
|
if (!state.config.readonly && ctx.instance) {
|
|
262
306
|
const handleChange = () => {
|
|
263
|
-
|
|
307
|
+
const value = textInput.value === "" ? null : textInput.value;
|
|
308
|
+
ctx.instance.triggerOnChange(pathKey, value);
|
|
264
309
|
};
|
|
265
310
|
textInput.addEventListener("blur", handleChange);
|
|
266
311
|
textInput.addEventListener("input", handleChange);
|
|
@@ -338,7 +383,8 @@ function renderMultipleTextElement(element, ctx, wrapper, pathKey) {
|
|
|
338
383
|
}
|
|
339
384
|
if (!state.config.readonly && ctx.instance) {
|
|
340
385
|
const handleChange = () => {
|
|
341
|
-
|
|
386
|
+
const value2 = textInput.value === "" ? null : textInput.value;
|
|
387
|
+
ctx.instance.triggerOnChange(textInput.name, value2);
|
|
342
388
|
};
|
|
343
389
|
textInput.addEventListener("blur", handleChange);
|
|
344
390
|
textInput.addEventListener("input", handleChange);
|
|
@@ -410,7 +456,7 @@ function renderMultipleTextElement(element, ctx, wrapper, pathKey) {
|
|
|
410
456
|
font-size: var(--fb-font-size);
|
|
411
457
|
transition: all var(--fb-transition-duration);
|
|
412
458
|
`;
|
|
413
|
-
addBtn.textContent =
|
|
459
|
+
addBtn.textContent = "+";
|
|
414
460
|
addBtn.addEventListener("mouseenter", () => {
|
|
415
461
|
addBtn.style.backgroundColor = "var(--fb-background-hover-color)";
|
|
416
462
|
});
|
|
@@ -504,19 +550,19 @@ function validateTextElement(element, key, context) {
|
|
|
504
550
|
}
|
|
505
551
|
};
|
|
506
552
|
if (element.multiple) {
|
|
507
|
-
const inputs = scopeRoot.querySelectorAll(
|
|
508
|
-
`[name^="${key}["]`
|
|
509
|
-
);
|
|
553
|
+
const inputs = scopeRoot.querySelectorAll(`[name^="${key}["]`);
|
|
510
554
|
const values = [];
|
|
555
|
+
const rawValues = [];
|
|
511
556
|
inputs.forEach((input, index) => {
|
|
512
557
|
const val = input?.value ?? "";
|
|
513
|
-
|
|
558
|
+
rawValues.push(val);
|
|
559
|
+
values.push(val === "" ? null : val);
|
|
514
560
|
validateTextInput(input, val, `${key}[${index}]`);
|
|
515
561
|
});
|
|
516
562
|
if (!skipValidation) {
|
|
517
563
|
const minCount = element.minCount ?? 1;
|
|
518
564
|
const maxCount = element.maxCount ?? Infinity;
|
|
519
|
-
const filteredValues =
|
|
565
|
+
const filteredValues = rawValues.filter((v) => v.trim() !== "");
|
|
520
566
|
if (element.required && filteredValues.length === 0) {
|
|
521
567
|
errors.push(`${key}: required`);
|
|
522
568
|
}
|
|
@@ -529,17 +575,17 @@ function validateTextElement(element, key, context) {
|
|
|
529
575
|
}
|
|
530
576
|
return { value: values, errors };
|
|
531
577
|
} else {
|
|
532
|
-
const input = scopeRoot.querySelector(
|
|
533
|
-
`[name$="${key}"]`
|
|
534
|
-
);
|
|
578
|
+
const input = scopeRoot.querySelector(`[name$="${key}"]`);
|
|
535
579
|
const val = input?.value ?? "";
|
|
536
580
|
if (!skipValidation && element.required && val === "") {
|
|
537
581
|
errors.push(`${key}: required`);
|
|
538
582
|
markValidity(input, "required");
|
|
539
|
-
return { value:
|
|
583
|
+
return { value: null, errors };
|
|
540
584
|
}
|
|
541
|
-
|
|
542
|
-
|
|
585
|
+
if (input) {
|
|
586
|
+
validateTextInput(input, val, key);
|
|
587
|
+
}
|
|
588
|
+
return { value: val === "" ? null : val, errors };
|
|
543
589
|
}
|
|
544
590
|
}
|
|
545
591
|
function updateTextField(element, fieldPath, value, context) {
|
|
@@ -551,9 +597,7 @@ function updateTextField(element, fieldPath, value, context) {
|
|
|
551
597
|
);
|
|
552
598
|
return;
|
|
553
599
|
}
|
|
554
|
-
const inputs = scopeRoot.querySelectorAll(
|
|
555
|
-
`[name^="${fieldPath}["]`
|
|
556
|
-
);
|
|
600
|
+
const inputs = scopeRoot.querySelectorAll(`[name^="${fieldPath}["]`);
|
|
557
601
|
inputs.forEach((input, index) => {
|
|
558
602
|
if (index < value.length) {
|
|
559
603
|
input.value = value[index] != null ? String(value[index]) : "";
|
|
@@ -567,9 +611,7 @@ function updateTextField(element, fieldPath, value, context) {
|
|
|
567
611
|
);
|
|
568
612
|
}
|
|
569
613
|
} else {
|
|
570
|
-
const input = scopeRoot.querySelector(
|
|
571
|
-
`[name="${fieldPath}"]`
|
|
572
|
-
);
|
|
614
|
+
const input = scopeRoot.querySelector(`[name="${fieldPath}"]`);
|
|
573
615
|
if (input) {
|
|
574
616
|
input.value = value != null ? String(value) : "";
|
|
575
617
|
input.classList.remove("invalid");
|
|
@@ -590,7 +632,8 @@ function renderTextareaElement(element, ctx, wrapper, pathKey) {
|
|
|
590
632
|
textareaInput.readOnly = state.config.readonly;
|
|
591
633
|
if (!state.config.readonly && ctx.instance) {
|
|
592
634
|
const handleChange = () => {
|
|
593
|
-
|
|
635
|
+
const value = textareaInput.value === "" ? null : textareaInput.value;
|
|
636
|
+
ctx.instance.triggerOnChange(pathKey, value);
|
|
594
637
|
};
|
|
595
638
|
textareaInput.addEventListener("blur", handleChange);
|
|
596
639
|
textareaInput.addEventListener("input", handleChange);
|
|
@@ -633,7 +676,8 @@ function renderMultipleTextareaElement(element, ctx, wrapper, pathKey) {
|
|
|
633
676
|
textareaInput.readOnly = state.config.readonly;
|
|
634
677
|
if (!state.config.readonly && ctx.instance) {
|
|
635
678
|
const handleChange = () => {
|
|
636
|
-
|
|
679
|
+
const value2 = textareaInput.value === "" ? null : textareaInput.value;
|
|
680
|
+
ctx.instance.triggerOnChange(textareaInput.name, value2);
|
|
637
681
|
};
|
|
638
682
|
textareaInput.addEventListener("blur", handleChange);
|
|
639
683
|
textareaInput.addEventListener("input", handleChange);
|
|
@@ -659,7 +703,7 @@ function renderMultipleTextareaElement(element, ctx, wrapper, pathKey) {
|
|
|
659
703
|
removeBtn = document.createElement("button");
|
|
660
704
|
removeBtn.type = "button";
|
|
661
705
|
removeBtn.className = "remove-item-btn mt-1 px-2 py-1 text-red-600 hover:bg-red-50 rounded text-sm";
|
|
662
|
-
removeBtn.innerHTML = "\u2715
|
|
706
|
+
removeBtn.innerHTML = "\u2715";
|
|
663
707
|
removeBtn.onclick = () => {
|
|
664
708
|
const currentIndex = Array.from(container.children).indexOf(
|
|
665
709
|
item
|
|
@@ -687,7 +731,7 @@ function renderMultipleTextareaElement(element, ctx, wrapper, pathKey) {
|
|
|
687
731
|
const addBtn = document.createElement("button");
|
|
688
732
|
addBtn.type = "button";
|
|
689
733
|
addBtn.className = "add-textarea-btn mt-2 px-3 py-1 text-blue-600 border border-blue-300 rounded hover:bg-blue-50 text-sm";
|
|
690
|
-
addBtn.textContent =
|
|
734
|
+
addBtn.textContent = "+";
|
|
691
735
|
addBtn.onclick = () => {
|
|
692
736
|
values.push(element.default || "");
|
|
693
737
|
addTextareaItem(element.default || "");
|
|
@@ -829,7 +873,7 @@ function renderMultipleNumberElement(element, ctx, wrapper, pathKey) {
|
|
|
829
873
|
const addBtn = document.createElement("button");
|
|
830
874
|
addBtn.type = "button";
|
|
831
875
|
addBtn.className = "add-number-btn mt-2 px-3 py-1 text-blue-600 border border-blue-300 rounded hover:bg-blue-50 text-sm";
|
|
832
|
-
addBtn.textContent =
|
|
876
|
+
addBtn.textContent = "+";
|
|
833
877
|
addBtn.onclick = () => {
|
|
834
878
|
values.push(element.default || "");
|
|
835
879
|
addNumberItem(element.default || "");
|
|
@@ -1111,7 +1155,7 @@ function renderMultipleSelectElement(element, ctx, wrapper, pathKey) {
|
|
|
1111
1155
|
const addBtn = document.createElement("button");
|
|
1112
1156
|
addBtn.type = "button";
|
|
1113
1157
|
addBtn.className = "add-select-btn mt-2 px-3 py-1 text-blue-600 border border-blue-300 rounded hover:bg-blue-50 text-sm";
|
|
1114
|
-
addBtn.textContent =
|
|
1158
|
+
addBtn.textContent = "+";
|
|
1115
1159
|
addBtn.onclick = () => {
|
|
1116
1160
|
const defaultValue = element.default || element.options?.[0]?.value || "";
|
|
1117
1161
|
values.push(defaultValue);
|
|
@@ -1297,7 +1341,9 @@ function renderLocalVideoPreview(container, file, videoType, resourceId, state,
|
|
|
1297
1341
|
return newContainer;
|
|
1298
1342
|
}
|
|
1299
1343
|
function attachVideoButtonHandlers(container, resourceId, state, deps) {
|
|
1300
|
-
const changeBtn = container.querySelector(
|
|
1344
|
+
const changeBtn = container.querySelector(
|
|
1345
|
+
".change-file-btn"
|
|
1346
|
+
);
|
|
1301
1347
|
if (changeBtn) {
|
|
1302
1348
|
changeBtn.onclick = (e) => {
|
|
1303
1349
|
e.stopPropagation();
|
|
@@ -1306,7 +1352,9 @@ function attachVideoButtonHandlers(container, resourceId, state, deps) {
|
|
|
1306
1352
|
}
|
|
1307
1353
|
};
|
|
1308
1354
|
}
|
|
1309
|
-
const deleteBtn = container.querySelector(
|
|
1355
|
+
const deleteBtn = container.querySelector(
|
|
1356
|
+
".delete-file-btn"
|
|
1357
|
+
);
|
|
1310
1358
|
if (deleteBtn) {
|
|
1311
1359
|
deleteBtn.onclick = (e) => {
|
|
1312
1360
|
e.stopPropagation();
|
|
@@ -1347,7 +1395,9 @@ function renderUploadedVideoPreview(container, thumbnailUrl, videoType) {
|
|
|
1347
1395
|
source.src = thumbnailUrl;
|
|
1348
1396
|
source.type = videoType;
|
|
1349
1397
|
video.appendChild(source);
|
|
1350
|
-
video.appendChild(
|
|
1398
|
+
video.appendChild(
|
|
1399
|
+
document.createTextNode("Your browser does not support the video tag.")
|
|
1400
|
+
);
|
|
1351
1401
|
container.appendChild(video);
|
|
1352
1402
|
}
|
|
1353
1403
|
function renderDeleteButton(container, resourceId, state) {
|
|
@@ -1448,7 +1498,13 @@ async function renderFilePreview(container, resourceId, state, options = {}) {
|
|
|
1448
1498
|
deps
|
|
1449
1499
|
);
|
|
1450
1500
|
} else {
|
|
1451
|
-
await renderUploadedFilePreview(
|
|
1501
|
+
await renderUploadedFilePreview(
|
|
1502
|
+
container,
|
|
1503
|
+
resourceId,
|
|
1504
|
+
fileName,
|
|
1505
|
+
meta,
|
|
1506
|
+
state
|
|
1507
|
+
);
|
|
1452
1508
|
}
|
|
1453
1509
|
}
|
|
1454
1510
|
async function renderFilePreviewReadonly(resourceId, state, fileName) {
|
|
@@ -1606,7 +1662,9 @@ function renderResourcePills(container, rids, state, onRemove) {
|
|
|
1606
1662
|
if (fileInput) fileInput.click();
|
|
1607
1663
|
};
|
|
1608
1664
|
textContainer.appendChild(uploadLink);
|
|
1609
|
-
textContainer.appendChild(
|
|
1665
|
+
textContainer.appendChild(
|
|
1666
|
+
document.createTextNode(` ${t("dragDropText", state)}`)
|
|
1667
|
+
);
|
|
1610
1668
|
container.appendChild(gridContainer);
|
|
1611
1669
|
container.appendChild(textContainer);
|
|
1612
1670
|
return;
|
|
@@ -2069,7 +2127,14 @@ function renderFileElement(element, ctx, wrapper, pathKey) {
|
|
|
2069
2127
|
const dragHandler = (files) => {
|
|
2070
2128
|
if (files.length > 0) {
|
|
2071
2129
|
const deps = { picker, fileUploadHandler, dragHandler };
|
|
2072
|
-
handleFileSelect(
|
|
2130
|
+
handleFileSelect(
|
|
2131
|
+
files[0],
|
|
2132
|
+
fileContainer,
|
|
2133
|
+
pathKey,
|
|
2134
|
+
state,
|
|
2135
|
+
deps,
|
|
2136
|
+
ctx.instance
|
|
2137
|
+
);
|
|
2073
2138
|
}
|
|
2074
2139
|
};
|
|
2075
2140
|
if (initial) {
|
|
@@ -2093,7 +2158,14 @@ function renderFileElement(element, ctx, wrapper, pathKey) {
|
|
|
2093
2158
|
picker.onchange = () => {
|
|
2094
2159
|
if (picker.files && picker.files.length > 0) {
|
|
2095
2160
|
const deps = { picker, fileUploadHandler, dragHandler };
|
|
2096
|
-
handleFileSelect(
|
|
2161
|
+
handleFileSelect(
|
|
2162
|
+
picker.files[0],
|
|
2163
|
+
fileContainer,
|
|
2164
|
+
pathKey,
|
|
2165
|
+
state,
|
|
2166
|
+
deps,
|
|
2167
|
+
ctx.instance
|
|
2168
|
+
);
|
|
2097
2169
|
}
|
|
2098
2170
|
};
|
|
2099
2171
|
fileWrapper.appendChild(fileContainer);
|
|
@@ -2158,8 +2230,22 @@ function renderFilesElement(element, ctx, wrapper, pathKey) {
|
|
|
2158
2230
|
const initialFiles = ctx.prefill[element.key] || [];
|
|
2159
2231
|
addPrefillFilesToIndex(initialFiles, state);
|
|
2160
2232
|
updateFilesList2();
|
|
2161
|
-
setupFilesDropHandler(
|
|
2162
|
-
|
|
2233
|
+
setupFilesDropHandler(
|
|
2234
|
+
filesContainer,
|
|
2235
|
+
initialFiles,
|
|
2236
|
+
state,
|
|
2237
|
+
updateFilesList2,
|
|
2238
|
+
pathKey,
|
|
2239
|
+
ctx.instance
|
|
2240
|
+
);
|
|
2241
|
+
setupFilesPickerHandler(
|
|
2242
|
+
filesPicker,
|
|
2243
|
+
initialFiles,
|
|
2244
|
+
state,
|
|
2245
|
+
updateFilesList2,
|
|
2246
|
+
pathKey,
|
|
2247
|
+
ctx.instance
|
|
2248
|
+
);
|
|
2163
2249
|
filesContainer.appendChild(list);
|
|
2164
2250
|
filesWrapper.appendChild(filesContainer);
|
|
2165
2251
|
filesWrapper.appendChild(filesPicker);
|
|
@@ -2221,8 +2307,22 @@ function renderMultipleFileElement(element, ctx, wrapper, pathKey) {
|
|
|
2221
2307
|
if (existingCount) existingCount.remove();
|
|
2222
2308
|
filesWrapper.appendChild(countInfo);
|
|
2223
2309
|
};
|
|
2224
|
-
setupFilesDropHandler(
|
|
2225
|
-
|
|
2310
|
+
setupFilesDropHandler(
|
|
2311
|
+
filesContainer,
|
|
2312
|
+
initialFiles,
|
|
2313
|
+
state,
|
|
2314
|
+
updateFilesDisplay,
|
|
2315
|
+
pathKey,
|
|
2316
|
+
ctx.instance
|
|
2317
|
+
);
|
|
2318
|
+
setupFilesPickerHandler(
|
|
2319
|
+
filesPicker,
|
|
2320
|
+
initialFiles,
|
|
2321
|
+
state,
|
|
2322
|
+
updateFilesDisplay,
|
|
2323
|
+
pathKey,
|
|
2324
|
+
ctx.instance
|
|
2325
|
+
);
|
|
2226
2326
|
updateFilesDisplay();
|
|
2227
2327
|
wrapper.appendChild(filesWrapper);
|
|
2228
2328
|
}
|
|
@@ -2621,7 +2721,7 @@ function renderMultipleColourElement(element, ctx, wrapper, pathKey) {
|
|
|
2621
2721
|
font-size: var(--fb-font-size);
|
|
2622
2722
|
transition: all var(--fb-transition-duration);
|
|
2623
2723
|
`;
|
|
2624
|
-
addBtn.textContent =
|
|
2724
|
+
addBtn.textContent = "+";
|
|
2625
2725
|
addBtn.addEventListener("mouseenter", () => {
|
|
2626
2726
|
addBtn.style.backgroundColor = "var(--fb-background-hover-color)";
|
|
2627
2727
|
});
|
|
@@ -2705,9 +2805,7 @@ function validateColourElement(element, key, context) {
|
|
|
2705
2805
|
return normalized;
|
|
2706
2806
|
};
|
|
2707
2807
|
if (element.multiple) {
|
|
2708
|
-
const hexInputs = scopeRoot.querySelectorAll(
|
|
2709
|
-
`.colour-hex-input`
|
|
2710
|
-
);
|
|
2808
|
+
const hexInputs = scopeRoot.querySelectorAll(`[name^="${key}["].colour-hex-input`);
|
|
2711
2809
|
const values = [];
|
|
2712
2810
|
hexInputs.forEach((input, index) => {
|
|
2713
2811
|
const val = input?.value ?? "";
|
|
@@ -2752,9 +2850,7 @@ function updateColourField(element, fieldPath, value, context) {
|
|
|
2752
2850
|
);
|
|
2753
2851
|
return;
|
|
2754
2852
|
}
|
|
2755
|
-
const hexInputs = scopeRoot.querySelectorAll(
|
|
2756
|
-
`.colour-hex-input`
|
|
2757
|
-
);
|
|
2853
|
+
const hexInputs = scopeRoot.querySelectorAll(`[name^="${fieldPath}["].colour-hex-input`);
|
|
2758
2854
|
hexInputs.forEach((hexInput, index) => {
|
|
2759
2855
|
if (index < value.length) {
|
|
2760
2856
|
const normalized = normalizeColourValue(value[index]);
|
|
@@ -2764,7 +2860,9 @@ function updateColourField(element, fieldPath, value, context) {
|
|
|
2764
2860
|
const wrapper = hexInput.closest(".colour-picker-wrapper");
|
|
2765
2861
|
if (wrapper) {
|
|
2766
2862
|
const swatch = wrapper.querySelector(".colour-swatch");
|
|
2767
|
-
const colourInput = wrapper.querySelector(
|
|
2863
|
+
const colourInput = wrapper.querySelector(
|
|
2864
|
+
".colour-picker-hidden"
|
|
2865
|
+
);
|
|
2768
2866
|
if (swatch) {
|
|
2769
2867
|
swatch.style.backgroundColor = normalized;
|
|
2770
2868
|
}
|
|
@@ -2791,7 +2889,9 @@ function updateColourField(element, fieldPath, value, context) {
|
|
|
2791
2889
|
const wrapper = hexInput.closest(".colour-picker-wrapper");
|
|
2792
2890
|
if (wrapper) {
|
|
2793
2891
|
const swatch = wrapper.querySelector(".colour-swatch");
|
|
2794
|
-
const colourInput = wrapper.querySelector(
|
|
2892
|
+
const colourInput = wrapper.querySelector(
|
|
2893
|
+
".colour-picker-hidden"
|
|
2894
|
+
);
|
|
2795
2895
|
if (swatch) {
|
|
2796
2896
|
swatch.style.backgroundColor = normalized;
|
|
2797
2897
|
}
|
|
@@ -2929,14 +3029,10 @@ function createSliderUI(value, pathKey, element, ctx, readonly) {
|
|
|
2929
3029
|
}
|
|
2930
3030
|
function renderSliderElement(element, ctx, wrapper, pathKey) {
|
|
2931
3031
|
if (element.min === void 0 || element.min === null) {
|
|
2932
|
-
throw new Error(
|
|
2933
|
-
`Slider field "${element.key}" requires "min" property`
|
|
2934
|
-
);
|
|
3032
|
+
throw new Error(`Slider field "${element.key}" requires "min" property`);
|
|
2935
3033
|
}
|
|
2936
3034
|
if (element.max === void 0 || element.max === null) {
|
|
2937
|
-
throw new Error(
|
|
2938
|
-
`Slider field "${element.key}" requires "max" property`
|
|
2939
|
-
);
|
|
3035
|
+
throw new Error(`Slider field "${element.key}" requires "max" property`);
|
|
2940
3036
|
}
|
|
2941
3037
|
if (element.min >= element.max) {
|
|
2942
3038
|
throw new Error(
|
|
@@ -2965,14 +3061,10 @@ function renderSliderElement(element, ctx, wrapper, pathKey) {
|
|
|
2965
3061
|
}
|
|
2966
3062
|
function renderMultipleSliderElement(element, ctx, wrapper, pathKey) {
|
|
2967
3063
|
if (element.min === void 0 || element.min === null) {
|
|
2968
|
-
throw new Error(
|
|
2969
|
-
`Slider field "${element.key}" requires "min" property`
|
|
2970
|
-
);
|
|
3064
|
+
throw new Error(`Slider field "${element.key}" requires "min" property`);
|
|
2971
3065
|
}
|
|
2972
3066
|
if (element.max === void 0 || element.max === null) {
|
|
2973
|
-
throw new Error(
|
|
2974
|
-
`Slider field "${element.key}" requires "max" property`
|
|
2975
|
-
);
|
|
3067
|
+
throw new Error(`Slider field "${element.key}" requires "max" property`);
|
|
2976
3068
|
}
|
|
2977
3069
|
if (element.min >= element.max) {
|
|
2978
3070
|
throw new Error(
|
|
@@ -3080,7 +3172,7 @@ function renderMultipleSliderElement(element, ctx, wrapper, pathKey) {
|
|
|
3080
3172
|
font-size: var(--fb-font-size);
|
|
3081
3173
|
transition: all var(--fb-transition-duration);
|
|
3082
3174
|
`;
|
|
3083
|
-
addBtn.textContent =
|
|
3175
|
+
addBtn.textContent = "+";
|
|
3084
3176
|
addBtn.addEventListener("mouseenter", () => {
|
|
3085
3177
|
addBtn.style.backgroundColor = "var(--fb-background-hover-color)";
|
|
3086
3178
|
});
|
|
@@ -3143,7 +3235,10 @@ function validateSliderElement(element, key, context) {
|
|
|
3143
3235
|
`;
|
|
3144
3236
|
const sliderContainer = input.closest(".slider-container");
|
|
3145
3237
|
if (sliderContainer && sliderContainer.nextSibling) {
|
|
3146
|
-
sliderContainer.parentNode?.insertBefore(
|
|
3238
|
+
sliderContainer.parentNode?.insertBefore(
|
|
3239
|
+
errorElement,
|
|
3240
|
+
sliderContainer.nextSibling
|
|
3241
|
+
);
|
|
3147
3242
|
} else if (sliderContainer) {
|
|
3148
3243
|
sliderContainer.parentNode?.appendChild(errorElement);
|
|
3149
3244
|
}
|
|
@@ -3314,6 +3409,33 @@ function updateSliderField(element, fieldPath, value, context) {
|
|
|
3314
3409
|
}
|
|
3315
3410
|
|
|
3316
3411
|
// src/components/container.ts
|
|
3412
|
+
function extractRootFormData(formRoot) {
|
|
3413
|
+
const data = {};
|
|
3414
|
+
const inputs = formRoot.querySelectorAll(
|
|
3415
|
+
"input, select, textarea"
|
|
3416
|
+
);
|
|
3417
|
+
inputs.forEach((input) => {
|
|
3418
|
+
const fieldName = input.getAttribute("name");
|
|
3419
|
+
if (fieldName && !fieldName.includes("[") && !fieldName.includes(".")) {
|
|
3420
|
+
if (input instanceof HTMLSelectElement) {
|
|
3421
|
+
data[fieldName] = input.value;
|
|
3422
|
+
} else if (input instanceof HTMLInputElement) {
|
|
3423
|
+
if (input.type === "checkbox") {
|
|
3424
|
+
data[fieldName] = input.checked;
|
|
3425
|
+
} else if (input.type === "radio") {
|
|
3426
|
+
if (input.checked) {
|
|
3427
|
+
data[fieldName] = input.value;
|
|
3428
|
+
}
|
|
3429
|
+
} else {
|
|
3430
|
+
data[fieldName] = input.value;
|
|
3431
|
+
}
|
|
3432
|
+
} else if (input instanceof HTMLTextAreaElement) {
|
|
3433
|
+
data[fieldName] = input.value;
|
|
3434
|
+
}
|
|
3435
|
+
}
|
|
3436
|
+
});
|
|
3437
|
+
return data;
|
|
3438
|
+
}
|
|
3317
3439
|
var renderElementFunc = null;
|
|
3318
3440
|
function setRenderElement(fn) {
|
|
3319
3441
|
renderElementFunc = fn;
|
|
@@ -3372,7 +3494,7 @@ function renderSingleContainerElement(element, ctx, wrapper, pathKey) {
|
|
|
3372
3494
|
prefill: ctx.prefill?.[element.key] || {},
|
|
3373
3495
|
// Sliced data for value population
|
|
3374
3496
|
formData: ctx.formData ?? ctx.prefill,
|
|
3375
|
-
// Complete root data for
|
|
3497
|
+
// Complete root data for enableIf evaluation
|
|
3376
3498
|
state: ctx.state
|
|
3377
3499
|
};
|
|
3378
3500
|
element.elements.forEach((child) => {
|
|
@@ -3392,15 +3514,10 @@ function renderMultipleContainerElement(element, ctx, wrapper, _pathKey) {
|
|
|
3392
3514
|
header.className = "flex justify-between items-center mb-4";
|
|
3393
3515
|
const left = document.createElement("div");
|
|
3394
3516
|
left.className = "flex-1";
|
|
3395
|
-
const right = document.createElement("div");
|
|
3396
|
-
right.className = "flex gap-2";
|
|
3397
3517
|
const itemsWrap = document.createElement("div");
|
|
3398
3518
|
itemsWrap.className = "space-y-4";
|
|
3399
3519
|
containerWrap.appendChild(header);
|
|
3400
3520
|
header.appendChild(left);
|
|
3401
|
-
if (!state.config.readonly) {
|
|
3402
|
-
header.appendChild(right);
|
|
3403
|
-
}
|
|
3404
3521
|
if (!ctx.state.config.readonly) {
|
|
3405
3522
|
const hintsElement = createPrefillHints(element, element.key);
|
|
3406
3523
|
if (hintsElement) {
|
|
@@ -3414,17 +3531,31 @@ function renderMultipleContainerElement(element, ctx, wrapper, _pathKey) {
|
|
|
3414
3531
|
const createAddButton = () => {
|
|
3415
3532
|
const add = document.createElement("button");
|
|
3416
3533
|
add.type = "button";
|
|
3417
|
-
add.className = "
|
|
3418
|
-
add.
|
|
3534
|
+
add.className = "add-container-btn mt-2 px-3 py-1 rounded";
|
|
3535
|
+
add.style.cssText = `
|
|
3536
|
+
color: var(--fb-primary-color);
|
|
3537
|
+
border: var(--fb-border-width) solid var(--fb-primary-color);
|
|
3538
|
+
background-color: transparent;
|
|
3539
|
+
font-size: var(--fb-font-size);
|
|
3540
|
+
transition: all var(--fb-transition-duration);
|
|
3541
|
+
`;
|
|
3542
|
+
add.textContent = "+";
|
|
3543
|
+
add.addEventListener("mouseenter", () => {
|
|
3544
|
+
add.style.backgroundColor = "var(--fb-background-hover-color)";
|
|
3545
|
+
});
|
|
3546
|
+
add.addEventListener("mouseleave", () => {
|
|
3547
|
+
add.style.backgroundColor = "transparent";
|
|
3548
|
+
});
|
|
3419
3549
|
add.onclick = () => {
|
|
3420
3550
|
if (countItems() < max) {
|
|
3421
3551
|
const idx = countItems();
|
|
3552
|
+
const currentFormData = state.formRoot ? extractRootFormData(state.formRoot) : {};
|
|
3422
3553
|
const subCtx = {
|
|
3423
3554
|
state: ctx.state,
|
|
3424
3555
|
path: pathJoin(ctx.path, `${element.key}[${idx}]`),
|
|
3425
3556
|
prefill: {},
|
|
3426
|
-
formData:
|
|
3427
|
-
//
|
|
3557
|
+
formData: currentFormData
|
|
3558
|
+
// Current root data from DOM for enableIf
|
|
3428
3559
|
};
|
|
3429
3560
|
const item = document.createElement("div");
|
|
3430
3561
|
item.className = "containerItem border border-gray-300 rounded-lg p-4 bg-white";
|
|
@@ -3445,8 +3576,19 @@ function renderMultipleContainerElement(element, ctx, wrapper, _pathKey) {
|
|
|
3445
3576
|
if (!state.config.readonly) {
|
|
3446
3577
|
const rem = document.createElement("button");
|
|
3447
3578
|
rem.type = "button";
|
|
3448
|
-
rem.className = "absolute top-2 right-2
|
|
3449
|
-
rem.
|
|
3579
|
+
rem.className = "absolute top-2 right-2 px-2 py-1 rounded";
|
|
3580
|
+
rem.style.cssText = `
|
|
3581
|
+
color: var(--fb-error-color);
|
|
3582
|
+
background-color: transparent;
|
|
3583
|
+
transition: background-color var(--fb-transition-duration);
|
|
3584
|
+
`;
|
|
3585
|
+
rem.textContent = "\u2715";
|
|
3586
|
+
rem.addEventListener("mouseenter", () => {
|
|
3587
|
+
rem.style.backgroundColor = "var(--fb-background-hover-color)";
|
|
3588
|
+
});
|
|
3589
|
+
rem.addEventListener("mouseleave", () => {
|
|
3590
|
+
rem.style.backgroundColor = "transparent";
|
|
3591
|
+
});
|
|
3450
3592
|
rem.onclick = () => {
|
|
3451
3593
|
item.remove();
|
|
3452
3594
|
updateAddButton();
|
|
@@ -3462,16 +3604,16 @@ function renderMultipleContainerElement(element, ctx, wrapper, _pathKey) {
|
|
|
3462
3604
|
};
|
|
3463
3605
|
const updateAddButton = () => {
|
|
3464
3606
|
const currentCount = countItems();
|
|
3465
|
-
const
|
|
3466
|
-
|
|
3467
|
-
|
|
3468
|
-
|
|
3607
|
+
const existingAddBtn = containerWrap.querySelector(
|
|
3608
|
+
".add-container-btn"
|
|
3609
|
+
);
|
|
3610
|
+
if (existingAddBtn) {
|
|
3611
|
+
existingAddBtn.disabled = currentCount >= max;
|
|
3612
|
+
existingAddBtn.style.opacity = currentCount >= max ? "0.5" : "1";
|
|
3613
|
+
existingAddBtn.style.pointerEvents = currentCount >= max ? "none" : "auto";
|
|
3469
3614
|
}
|
|
3470
3615
|
left.innerHTML = `<span>${element.label || element.key}</span> <span class="text-sm text-gray-500">(${currentCount}/${max === Infinity ? "\u221E" : max})</span>`;
|
|
3471
3616
|
};
|
|
3472
|
-
if (!state.config.readonly) {
|
|
3473
|
-
right.appendChild(createAddButton());
|
|
3474
|
-
}
|
|
3475
3617
|
if (pre && Array.isArray(pre)) {
|
|
3476
3618
|
pre.forEach((prefillObj, idx) => {
|
|
3477
3619
|
const subCtx = {
|
|
@@ -3479,7 +3621,7 @@ function renderMultipleContainerElement(element, ctx, wrapper, _pathKey) {
|
|
|
3479
3621
|
path: pathJoin(ctx.path, `${element.key}[${idx}]`),
|
|
3480
3622
|
prefill: prefillObj || {},
|
|
3481
3623
|
formData: ctx.formData ?? ctx.prefill
|
|
3482
|
-
// Complete root data for
|
|
3624
|
+
// Complete root data for enableIf
|
|
3483
3625
|
};
|
|
3484
3626
|
const item = document.createElement("div");
|
|
3485
3627
|
item.className = "containerItem border border-gray-300 rounded-lg p-4 bg-white";
|
|
@@ -3500,8 +3642,19 @@ function renderMultipleContainerElement(element, ctx, wrapper, _pathKey) {
|
|
|
3500
3642
|
if (!state.config.readonly) {
|
|
3501
3643
|
const rem = document.createElement("button");
|
|
3502
3644
|
rem.type = "button";
|
|
3503
|
-
rem.className = "absolute top-2 right-2
|
|
3504
|
-
rem.
|
|
3645
|
+
rem.className = "absolute top-2 right-2 px-2 py-1 rounded";
|
|
3646
|
+
rem.style.cssText = `
|
|
3647
|
+
color: var(--fb-error-color);
|
|
3648
|
+
background-color: transparent;
|
|
3649
|
+
transition: background-color var(--fb-transition-duration);
|
|
3650
|
+
`;
|
|
3651
|
+
rem.textContent = "\u2715";
|
|
3652
|
+
rem.addEventListener("mouseenter", () => {
|
|
3653
|
+
rem.style.backgroundColor = "var(--fb-background-hover-color)";
|
|
3654
|
+
});
|
|
3655
|
+
rem.addEventListener("mouseleave", () => {
|
|
3656
|
+
rem.style.backgroundColor = "transparent";
|
|
3657
|
+
});
|
|
3505
3658
|
rem.onclick = () => {
|
|
3506
3659
|
item.remove();
|
|
3507
3660
|
updateAddButton();
|
|
@@ -3520,7 +3673,7 @@ function renderMultipleContainerElement(element, ctx, wrapper, _pathKey) {
|
|
|
3520
3673
|
path: pathJoin(ctx.path, `${element.key}[${idx}]`),
|
|
3521
3674
|
prefill: {},
|
|
3522
3675
|
formData: ctx.formData ?? ctx.prefill
|
|
3523
|
-
// Complete root data for
|
|
3676
|
+
// Complete root data for enableIf
|
|
3524
3677
|
};
|
|
3525
3678
|
const item = document.createElement("div");
|
|
3526
3679
|
item.className = "containerItem border border-gray-300 rounded-lg p-4 bg-white";
|
|
@@ -3540,8 +3693,19 @@ function renderMultipleContainerElement(element, ctx, wrapper, _pathKey) {
|
|
|
3540
3693
|
item.appendChild(childWrapper);
|
|
3541
3694
|
const rem = document.createElement("button");
|
|
3542
3695
|
rem.type = "button";
|
|
3543
|
-
rem.className = "absolute top-2 right-2
|
|
3544
|
-
rem.
|
|
3696
|
+
rem.className = "absolute top-2 right-2 px-2 py-1 rounded";
|
|
3697
|
+
rem.style.cssText = `
|
|
3698
|
+
color: var(--fb-error-color);
|
|
3699
|
+
background-color: transparent;
|
|
3700
|
+
transition: background-color var(--fb-transition-duration);
|
|
3701
|
+
`;
|
|
3702
|
+
rem.textContent = "\u2715";
|
|
3703
|
+
rem.addEventListener("mouseenter", () => {
|
|
3704
|
+
rem.style.backgroundColor = "var(--fb-background-hover-color)";
|
|
3705
|
+
});
|
|
3706
|
+
rem.addEventListener("mouseleave", () => {
|
|
3707
|
+
rem.style.backgroundColor = "transparent";
|
|
3708
|
+
});
|
|
3545
3709
|
rem.onclick = () => {
|
|
3546
3710
|
if (countItems() > min) {
|
|
3547
3711
|
item.remove();
|
|
@@ -3554,6 +3718,9 @@ function renderMultipleContainerElement(element, ctx, wrapper, _pathKey) {
|
|
|
3554
3718
|
}
|
|
3555
3719
|
}
|
|
3556
3720
|
containerWrap.appendChild(itemsWrap);
|
|
3721
|
+
if (!state.config.readonly) {
|
|
3722
|
+
containerWrap.appendChild(createAddButton());
|
|
3723
|
+
}
|
|
3557
3724
|
updateAddButton();
|
|
3558
3725
|
wrapper.appendChild(containerWrap);
|
|
3559
3726
|
}
|
|
@@ -3605,6 +3772,26 @@ function validateContainerElement(element, key, context) {
|
|
|
3605
3772
|
`[data-container-item="${key}[${i}]"]`
|
|
3606
3773
|
) || scopeRoot;
|
|
3607
3774
|
element.elements.forEach((child) => {
|
|
3775
|
+
if (child.enableIf) {
|
|
3776
|
+
try {
|
|
3777
|
+
const rootFormData = context.instance?.getState().formRoot ? extractRootFormData(context.instance.getState().formRoot) : {};
|
|
3778
|
+
const shouldEnable = evaluateEnableCondition(
|
|
3779
|
+
child.enableIf,
|
|
3780
|
+
rootFormData,
|
|
3781
|
+
// Root form data for absolute scope
|
|
3782
|
+
itemData
|
|
3783
|
+
// Container data for relative scope
|
|
3784
|
+
);
|
|
3785
|
+
if (!shouldEnable) {
|
|
3786
|
+
return;
|
|
3787
|
+
}
|
|
3788
|
+
} catch (error) {
|
|
3789
|
+
console.error(
|
|
3790
|
+
`Error evaluating enableIf for field "${child.key}" in container "${key}[${i}]":`,
|
|
3791
|
+
error
|
|
3792
|
+
);
|
|
3793
|
+
}
|
|
3794
|
+
}
|
|
3608
3795
|
if (child.hidden || child.type === "hidden") {
|
|
3609
3796
|
itemData[child.key] = child.default !== void 0 ? child.default : null;
|
|
3610
3797
|
} else {
|
|
@@ -3624,6 +3811,26 @@ function validateContainerElement(element, key, context) {
|
|
|
3624
3811
|
const containerData = {};
|
|
3625
3812
|
const containerContainer = scopeRoot.querySelector(`[data-container="${key}"]`) || scopeRoot;
|
|
3626
3813
|
element.elements.forEach((child) => {
|
|
3814
|
+
if (child.enableIf) {
|
|
3815
|
+
try {
|
|
3816
|
+
const rootFormData = context.instance?.getState().formRoot ? extractRootFormData(context.instance.getState().formRoot) : {};
|
|
3817
|
+
const shouldEnable = evaluateEnableCondition(
|
|
3818
|
+
child.enableIf,
|
|
3819
|
+
rootFormData,
|
|
3820
|
+
// Root form data for absolute scope
|
|
3821
|
+
containerData
|
|
3822
|
+
// Container data for relative scope
|
|
3823
|
+
);
|
|
3824
|
+
if (!shouldEnable) {
|
|
3825
|
+
return;
|
|
3826
|
+
}
|
|
3827
|
+
} catch (error) {
|
|
3828
|
+
console.error(
|
|
3829
|
+
`Error evaluating enableIf for field "${child.key}" in container "${key}":`,
|
|
3830
|
+
error
|
|
3831
|
+
);
|
|
3832
|
+
}
|
|
3833
|
+
}
|
|
3627
3834
|
if (child.hidden || child.type === "hidden") {
|
|
3628
3835
|
containerData[child.key] = child.default !== void 0 ? child.default : null;
|
|
3629
3836
|
} else {
|
|
@@ -3808,31 +4015,180 @@ if (typeof document !== "undefined") {
|
|
|
3808
4015
|
}
|
|
3809
4016
|
});
|
|
3810
4017
|
}
|
|
3811
|
-
function
|
|
3812
|
-
if (!element.
|
|
3813
|
-
return
|
|
4018
|
+
function shouldDisableElement(element, ctx) {
|
|
4019
|
+
if (!element.enableIf) {
|
|
4020
|
+
return false;
|
|
3814
4021
|
}
|
|
3815
4022
|
try {
|
|
3816
|
-
const
|
|
3817
|
-
const
|
|
3818
|
-
|
|
3819
|
-
|
|
4023
|
+
const rootFormData = ctx.formData ?? ctx.prefill ?? {};
|
|
4024
|
+
const containerData = ctx.path ? getValueByPath(rootFormData, ctx.path) : void 0;
|
|
4025
|
+
const shouldEnable = evaluateEnableCondition(
|
|
4026
|
+
element.enableIf,
|
|
4027
|
+
rootFormData,
|
|
4028
|
+
containerData
|
|
3820
4029
|
);
|
|
3821
|
-
|
|
3822
|
-
const hiddenWrapper = document.createElement("div");
|
|
3823
|
-
hiddenWrapper.className = "fb-field-wrapper-hidden";
|
|
3824
|
-
hiddenWrapper.style.display = "none";
|
|
3825
|
-
hiddenWrapper.setAttribute("data-field-key", element.key);
|
|
3826
|
-
hiddenWrapper.setAttribute("data-conditionally-hidden", "true");
|
|
3827
|
-
return hiddenWrapper;
|
|
3828
|
-
}
|
|
4030
|
+
return !shouldEnable;
|
|
3829
4031
|
} catch (error) {
|
|
3830
4032
|
console.error(
|
|
3831
|
-
`Error evaluating
|
|
4033
|
+
`Error evaluating enableIf for field "${element.key}":`,
|
|
3832
4034
|
error
|
|
3833
4035
|
);
|
|
3834
4036
|
}
|
|
3835
|
-
return
|
|
4037
|
+
return false;
|
|
4038
|
+
}
|
|
4039
|
+
function extractDOMValue(fieldPath, formRoot) {
|
|
4040
|
+
const input = formRoot.querySelector(
|
|
4041
|
+
`[name="${fieldPath}"]`
|
|
4042
|
+
);
|
|
4043
|
+
if (!input) {
|
|
4044
|
+
return void 0;
|
|
4045
|
+
}
|
|
4046
|
+
if (input instanceof HTMLSelectElement) {
|
|
4047
|
+
return input.value;
|
|
4048
|
+
} else if (input instanceof HTMLInputElement) {
|
|
4049
|
+
if (input.type === "checkbox") {
|
|
4050
|
+
return input.checked;
|
|
4051
|
+
} else if (input.type === "radio") {
|
|
4052
|
+
const checked = formRoot.querySelector(
|
|
4053
|
+
`[name="${fieldPath}"]:checked`
|
|
4054
|
+
);
|
|
4055
|
+
return checked ? checked.value : void 0;
|
|
4056
|
+
} else {
|
|
4057
|
+
return input.value;
|
|
4058
|
+
}
|
|
4059
|
+
} else if (input instanceof HTMLTextAreaElement) {
|
|
4060
|
+
return input.value;
|
|
4061
|
+
}
|
|
4062
|
+
return void 0;
|
|
4063
|
+
}
|
|
4064
|
+
function reevaluateEnableIf(wrapper, element, ctx) {
|
|
4065
|
+
if (!element.enableIf) {
|
|
4066
|
+
return;
|
|
4067
|
+
}
|
|
4068
|
+
const formRoot = ctx.state.formRoot;
|
|
4069
|
+
if (!formRoot) {
|
|
4070
|
+
console.error(`Cannot re-evaluate enableIf: formRoot is null`);
|
|
4071
|
+
return;
|
|
4072
|
+
}
|
|
4073
|
+
const condition = element.enableIf;
|
|
4074
|
+
const scope = condition.scope ?? "relative";
|
|
4075
|
+
let rootFormData = {};
|
|
4076
|
+
const containerData = {};
|
|
4077
|
+
const effectiveScope = !ctx.path || ctx.path === "" ? "absolute" : scope;
|
|
4078
|
+
if (effectiveScope === "relative" && ctx.path) {
|
|
4079
|
+
const containerMatch = ctx.path.match(/^(.+)\[(\d+)\]$/);
|
|
4080
|
+
if (containerMatch) {
|
|
4081
|
+
const containerKey = containerMatch[1];
|
|
4082
|
+
const containerIndex = parseInt(containerMatch[2], 10);
|
|
4083
|
+
const containerItemElement = formRoot.querySelector(
|
|
4084
|
+
`[data-container-item="${containerKey}[${containerIndex}]"]`
|
|
4085
|
+
);
|
|
4086
|
+
if (containerItemElement) {
|
|
4087
|
+
const inputs = containerItemElement.querySelectorAll(
|
|
4088
|
+
"input, select, textarea"
|
|
4089
|
+
);
|
|
4090
|
+
inputs.forEach((input) => {
|
|
4091
|
+
const fieldName = input.getAttribute("name");
|
|
4092
|
+
if (fieldName) {
|
|
4093
|
+
const fieldKeyMatch = fieldName.match(/\.([^.[\]]+)$/);
|
|
4094
|
+
if (fieldKeyMatch) {
|
|
4095
|
+
const fieldKey = fieldKeyMatch[1];
|
|
4096
|
+
if (input instanceof HTMLSelectElement) {
|
|
4097
|
+
containerData[fieldKey] = input.value;
|
|
4098
|
+
} else if (input instanceof HTMLInputElement) {
|
|
4099
|
+
if (input.type === "checkbox") {
|
|
4100
|
+
containerData[fieldKey] = input.checked;
|
|
4101
|
+
} else if (input.type === "radio") {
|
|
4102
|
+
if (input.checked) {
|
|
4103
|
+
containerData[fieldKey] = input.value;
|
|
4104
|
+
}
|
|
4105
|
+
} else {
|
|
4106
|
+
containerData[fieldKey] = input.value;
|
|
4107
|
+
}
|
|
4108
|
+
} else if (input instanceof HTMLTextAreaElement) {
|
|
4109
|
+
containerData[fieldKey] = input.value;
|
|
4110
|
+
}
|
|
4111
|
+
}
|
|
4112
|
+
}
|
|
4113
|
+
});
|
|
4114
|
+
}
|
|
4115
|
+
}
|
|
4116
|
+
} else {
|
|
4117
|
+
const dependencyKey = condition.key;
|
|
4118
|
+
const dependencyValue = extractDOMValue(dependencyKey, formRoot);
|
|
4119
|
+
if (dependencyValue !== void 0) {
|
|
4120
|
+
rootFormData[dependencyKey] = dependencyValue;
|
|
4121
|
+
} else {
|
|
4122
|
+
rootFormData = ctx.formData ?? ctx.prefill;
|
|
4123
|
+
}
|
|
4124
|
+
}
|
|
4125
|
+
try {
|
|
4126
|
+
const shouldEnable = evaluateEnableCondition(
|
|
4127
|
+
condition,
|
|
4128
|
+
rootFormData,
|
|
4129
|
+
containerData
|
|
4130
|
+
);
|
|
4131
|
+
if (shouldEnable) {
|
|
4132
|
+
wrapper.style.display = "";
|
|
4133
|
+
wrapper.classList.remove("fb-field-wrapper-disabled");
|
|
4134
|
+
wrapper.removeAttribute("data-conditionally-disabled");
|
|
4135
|
+
} else {
|
|
4136
|
+
wrapper.style.display = "none";
|
|
4137
|
+
wrapper.classList.add("fb-field-wrapper-disabled");
|
|
4138
|
+
wrapper.setAttribute("data-conditionally-disabled", "true");
|
|
4139
|
+
}
|
|
4140
|
+
} catch (error) {
|
|
4141
|
+
console.error(`Error re-evaluating enableIf for field "${element.key}":`, error);
|
|
4142
|
+
}
|
|
4143
|
+
}
|
|
4144
|
+
function setupEnableIfListeners(wrapper, element, ctx) {
|
|
4145
|
+
if (!element.enableIf) {
|
|
4146
|
+
return;
|
|
4147
|
+
}
|
|
4148
|
+
const formRoot = ctx.state.formRoot;
|
|
4149
|
+
if (!formRoot) {
|
|
4150
|
+
console.error(`Cannot setup enableIf listeners: formRoot is null`);
|
|
4151
|
+
return;
|
|
4152
|
+
}
|
|
4153
|
+
const condition = element.enableIf;
|
|
4154
|
+
const scope = condition.scope ?? "relative";
|
|
4155
|
+
const dependencyKey = condition.key;
|
|
4156
|
+
let dependencyFieldPath;
|
|
4157
|
+
if (scope === "relative" && ctx.path) {
|
|
4158
|
+
dependencyFieldPath = `${ctx.path}.${dependencyKey}`;
|
|
4159
|
+
} else {
|
|
4160
|
+
dependencyFieldPath = dependencyKey;
|
|
4161
|
+
}
|
|
4162
|
+
const dependencyInput = formRoot.querySelector(
|
|
4163
|
+
`[name="${dependencyFieldPath}"]`
|
|
4164
|
+
);
|
|
4165
|
+
if (!dependencyInput) {
|
|
4166
|
+
const observer = new MutationObserver(() => {
|
|
4167
|
+
const input = formRoot.querySelector(
|
|
4168
|
+
`[name="${dependencyFieldPath}"]`
|
|
4169
|
+
);
|
|
4170
|
+
if (input) {
|
|
4171
|
+
input.addEventListener("change", () => {
|
|
4172
|
+
reevaluateEnableIf(wrapper, element, ctx);
|
|
4173
|
+
});
|
|
4174
|
+
input.addEventListener("input", () => {
|
|
4175
|
+
reevaluateEnableIf(wrapper, element, ctx);
|
|
4176
|
+
});
|
|
4177
|
+
observer.disconnect();
|
|
4178
|
+
}
|
|
4179
|
+
});
|
|
4180
|
+
observer.observe(formRoot, {
|
|
4181
|
+
childList: true,
|
|
4182
|
+
subtree: true
|
|
4183
|
+
});
|
|
4184
|
+
return;
|
|
4185
|
+
}
|
|
4186
|
+
dependencyInput.addEventListener("change", () => {
|
|
4187
|
+
reevaluateEnableIf(wrapper, element, ctx);
|
|
4188
|
+
});
|
|
4189
|
+
dependencyInput.addEventListener("input", () => {
|
|
4190
|
+
reevaluateEnableIf(wrapper, element, ctx);
|
|
4191
|
+
});
|
|
3836
4192
|
}
|
|
3837
4193
|
function createFieldLabel(element) {
|
|
3838
4194
|
const title = document.createElement("label");
|
|
@@ -3950,10 +4306,7 @@ function dispatchToRenderer(element, ctx, wrapper, pathKey) {
|
|
|
3950
4306
|
}
|
|
3951
4307
|
}
|
|
3952
4308
|
function renderElement2(element, ctx) {
|
|
3953
|
-
const
|
|
3954
|
-
if (hiddenElement) {
|
|
3955
|
-
return hiddenElement;
|
|
3956
|
-
}
|
|
4309
|
+
const initiallyDisabled = shouldDisableElement(element, ctx);
|
|
3957
4310
|
const wrapper = document.createElement("div");
|
|
3958
4311
|
wrapper.className = "mb-6 fb-field-wrapper";
|
|
3959
4312
|
wrapper.setAttribute("data-field-key", element.key);
|
|
@@ -3961,6 +4314,12 @@ function renderElement2(element, ctx) {
|
|
|
3961
4314
|
wrapper.appendChild(label);
|
|
3962
4315
|
const pathKey = pathJoin(ctx.path, element.key);
|
|
3963
4316
|
dispatchToRenderer(element, ctx, wrapper, pathKey);
|
|
4317
|
+
if (initiallyDisabled) {
|
|
4318
|
+
wrapper.style.display = "none";
|
|
4319
|
+
wrapper.classList.add("fb-field-wrapper-disabled");
|
|
4320
|
+
wrapper.setAttribute("data-conditionally-disabled", "true");
|
|
4321
|
+
}
|
|
4322
|
+
setupEnableIfListeners(wrapper, element, ctx);
|
|
3964
4323
|
return wrapper;
|
|
3965
4324
|
}
|
|
3966
4325
|
setRenderElement(renderElement2);
|
|
@@ -4619,15 +4978,16 @@ var FormBuilderInstance = class {
|
|
|
4619
4978
|
event.preventDefault();
|
|
4620
4979
|
event.stopPropagation();
|
|
4621
4980
|
const hintValuesJson = target.getAttribute("data-hint-values");
|
|
4981
|
+
const isRootHint = target.getAttribute("data-root-hint") === "true";
|
|
4622
4982
|
const containerKey = target.getAttribute("data-container-key");
|
|
4623
|
-
if (!hintValuesJson || !containerKey) {
|
|
4983
|
+
if (!hintValuesJson || !isRootHint && !containerKey) {
|
|
4624
4984
|
console.warn("Prefill hint missing required data attributes");
|
|
4625
4985
|
return;
|
|
4626
4986
|
}
|
|
4627
4987
|
try {
|
|
4628
4988
|
const hintValues = JSON.parse(hintValuesJson);
|
|
4629
4989
|
for (const fieldKey in hintValues) {
|
|
4630
|
-
const fullPath = `${containerKey}.${fieldKey}`;
|
|
4990
|
+
const fullPath = isRootHint ? fieldKey : `${containerKey}.${fieldKey}`;
|
|
4631
4991
|
const value = hintValues[fieldKey];
|
|
4632
4992
|
this.updateField(fullPath, value);
|
|
4633
4993
|
}
|
|
@@ -4635,6 +4995,27 @@ var FormBuilderInstance = class {
|
|
|
4635
4995
|
console.error("Error parsing prefill hint values:", error);
|
|
4636
4996
|
}
|
|
4637
4997
|
}
|
|
4998
|
+
/**
|
|
4999
|
+
* Create root-level prefill hints UI
|
|
5000
|
+
*/
|
|
5001
|
+
createRootPrefillHints(hints) {
|
|
5002
|
+
const hintsContainer = document.createElement("div");
|
|
5003
|
+
hintsContainer.className = "fb-prefill-hints flex flex-wrap gap-2 mb-4";
|
|
5004
|
+
hints.forEach((hint) => {
|
|
5005
|
+
const hintButton = document.createElement("button");
|
|
5006
|
+
hintButton.type = "button";
|
|
5007
|
+
hintButton.className = "fb-prefill-hint";
|
|
5008
|
+
if (hint.icon) {
|
|
5009
|
+
hintButton.textContent = `${hint.icon} ${hint.label}`;
|
|
5010
|
+
} else {
|
|
5011
|
+
hintButton.textContent = hint.label;
|
|
5012
|
+
}
|
|
5013
|
+
hintButton.setAttribute("data-hint-values", JSON.stringify(hint.values));
|
|
5014
|
+
hintButton.setAttribute("data-root-hint", "true");
|
|
5015
|
+
hintsContainer.appendChild(hintButton);
|
|
5016
|
+
});
|
|
5017
|
+
return hintsContainer;
|
|
5018
|
+
}
|
|
4638
5019
|
/**
|
|
4639
5020
|
* Render form from schema
|
|
4640
5021
|
*/
|
|
@@ -4650,8 +5031,19 @@ var FormBuilderInstance = class {
|
|
|
4650
5031
|
clear(root);
|
|
4651
5032
|
root.setAttribute("data-fb-root", "true");
|
|
4652
5033
|
injectThemeVariables(root, this.state.config.theme);
|
|
4653
|
-
const
|
|
4654
|
-
|
|
5034
|
+
const rootContainer = document.createElement("div");
|
|
5035
|
+
rootContainer.className = "space-y-6";
|
|
5036
|
+
if (schema.prefillHints && !this.state.config.readonly) {
|
|
5037
|
+
const hintsContainer = this.createRootPrefillHints(schema.prefillHints);
|
|
5038
|
+
rootContainer.appendChild(hintsContainer);
|
|
5039
|
+
}
|
|
5040
|
+
const fieldsWrapper = document.createElement("div");
|
|
5041
|
+
const columns = schema.columns || 1;
|
|
5042
|
+
if (columns === 1) {
|
|
5043
|
+
fieldsWrapper.className = "space-y-4";
|
|
5044
|
+
} else {
|
|
5045
|
+
fieldsWrapper.className = `grid grid-cols-${columns} gap-4`;
|
|
5046
|
+
}
|
|
4655
5047
|
schema.elements.forEach((element) => {
|
|
4656
5048
|
if (element.hidden) {
|
|
4657
5049
|
return;
|
|
@@ -4660,13 +5052,14 @@ var FormBuilderInstance = class {
|
|
|
4660
5052
|
path: "",
|
|
4661
5053
|
prefill: prefill || {},
|
|
4662
5054
|
formData: prefill || {},
|
|
4663
|
-
// Pass complete root data for
|
|
5055
|
+
// Pass complete root data for enableIf evaluation
|
|
4664
5056
|
state: this.state,
|
|
4665
5057
|
instance: this
|
|
4666
5058
|
});
|
|
4667
|
-
|
|
5059
|
+
fieldsWrapper.appendChild(block);
|
|
4668
5060
|
});
|
|
4669
|
-
|
|
5061
|
+
rootContainer.appendChild(fieldsWrapper);
|
|
5062
|
+
root.appendChild(rootContainer);
|
|
4670
5063
|
if (!this.state.config.readonly) {
|
|
4671
5064
|
root.addEventListener("click", this.handlePrefillHintClick.bind(this));
|
|
4672
5065
|
}
|
|
@@ -4708,15 +5101,18 @@ var FormBuilderInstance = class {
|
|
|
4708
5101
|
};
|
|
4709
5102
|
setValidateElement(validateElement2);
|
|
4710
5103
|
this.state.schema.elements.forEach((element) => {
|
|
4711
|
-
if (element.
|
|
5104
|
+
if (element.enableIf) {
|
|
4712
5105
|
try {
|
|
4713
|
-
const
|
|
4714
|
-
|
|
5106
|
+
const shouldEnable = evaluateEnableCondition(
|
|
5107
|
+
element.enableIf,
|
|
5108
|
+
data
|
|
5109
|
+
);
|
|
5110
|
+
if (!shouldEnable) {
|
|
4715
5111
|
return;
|
|
4716
5112
|
}
|
|
4717
5113
|
} catch (error) {
|
|
4718
5114
|
console.error(
|
|
4719
|
-
`Error evaluating
|
|
5115
|
+
`Error evaluating enableIf for field "${element.key}" during validation:`,
|
|
4720
5116
|
error
|
|
4721
5117
|
);
|
|
4722
5118
|
}
|
|
@@ -4804,7 +5200,9 @@ var FormBuilderInstance = class {
|
|
|
4804
5200
|
}
|
|
4805
5201
|
if (element.type === "container" || element.type === "group") {
|
|
4806
5202
|
const containerElement = element;
|
|
4807
|
-
const nestedData = this.buildHiddenFieldsData(
|
|
5203
|
+
const nestedData = this.buildHiddenFieldsData(
|
|
5204
|
+
containerElement.elements
|
|
5205
|
+
);
|
|
4808
5206
|
if (Object.keys(nestedData).length > 0) {
|
|
4809
5207
|
if (!(key in data)) {
|
|
4810
5208
|
data[key] = nestedData;
|
|
@@ -4822,7 +5220,9 @@ var FormBuilderInstance = class {
|
|
|
4822
5220
|
*/
|
|
4823
5221
|
setFormData(data) {
|
|
4824
5222
|
if (!this.state.schema || !this.state.formRoot) {
|
|
4825
|
-
console.warn(
|
|
5223
|
+
console.warn(
|
|
5224
|
+
"setFormData: Form not initialized. Call renderForm() first."
|
|
5225
|
+
);
|
|
4826
5226
|
return;
|
|
4827
5227
|
}
|
|
4828
5228
|
for (const fieldPath in data) {
|
|
@@ -4836,20 +5236,27 @@ var FormBuilderInstance = class {
|
|
|
4836
5236
|
*/
|
|
4837
5237
|
updateField(fieldPath, value) {
|
|
4838
5238
|
if (!this.state.schema || !this.state.formRoot) {
|
|
4839
|
-
console.warn(
|
|
5239
|
+
console.warn(
|
|
5240
|
+
"updateField: Form not initialized. Call renderForm() first."
|
|
5241
|
+
);
|
|
4840
5242
|
return;
|
|
4841
5243
|
}
|
|
4842
5244
|
const schemaElement = this.findSchemaElement(fieldPath);
|
|
4843
5245
|
if (!schemaElement) {
|
|
4844
|
-
console.warn(
|
|
5246
|
+
console.warn(
|
|
5247
|
+
`updateField: Schema element not found for path "${fieldPath}"`
|
|
5248
|
+
);
|
|
4845
5249
|
return;
|
|
4846
5250
|
}
|
|
4847
5251
|
const domElement = this.findFormElementByFieldPath(fieldPath);
|
|
4848
5252
|
if (!domElement) {
|
|
4849
|
-
console.warn(
|
|
5253
|
+
console.warn(
|
|
5254
|
+
`updateField: DOM element not found for path "${fieldPath}"`
|
|
5255
|
+
);
|
|
4850
5256
|
return;
|
|
4851
5257
|
}
|
|
4852
5258
|
this.updateFieldValue(domElement, schemaElement, fieldPath, value);
|
|
5259
|
+
this.reevaluateConditionalFields();
|
|
4853
5260
|
if (this.state.config.onChange || this.state.config.onFieldChange) {
|
|
4854
5261
|
this.triggerOnChange(fieldPath, value);
|
|
4855
5262
|
}
|
|
@@ -4878,7 +5285,7 @@ var FormBuilderInstance = class {
|
|
|
4878
5285
|
}
|
|
4879
5286
|
}
|
|
4880
5287
|
/**
|
|
4881
|
-
* Re-evaluate all conditional fields (
|
|
5288
|
+
* Re-evaluate all conditional fields (enableIf) based on current form data
|
|
4882
5289
|
* This is called automatically when form data changes (via onChange events)
|
|
4883
5290
|
*/
|
|
4884
5291
|
reevaluateConditionalFields() {
|
|
@@ -4887,45 +5294,80 @@ var FormBuilderInstance = class {
|
|
|
4887
5294
|
const checkElements = (elements, currentPath) => {
|
|
4888
5295
|
elements.forEach((element) => {
|
|
4889
5296
|
const fullPath = currentPath ? `${currentPath}.${element.key}` : element.key;
|
|
4890
|
-
if (element.
|
|
4891
|
-
|
|
4892
|
-
|
|
4893
|
-
|
|
4894
|
-
|
|
5297
|
+
if (element.enableIf) {
|
|
5298
|
+
let fieldWrapper = null;
|
|
5299
|
+
if (currentPath) {
|
|
5300
|
+
const pathMatch = currentPath.match(/^(.+)\[(\d+)\]$/);
|
|
5301
|
+
if (pathMatch) {
|
|
5302
|
+
const containerKey = pathMatch[1];
|
|
5303
|
+
const containerIndex = pathMatch[2];
|
|
5304
|
+
const containerElement = this.state.formRoot.querySelector(
|
|
5305
|
+
`[data-container-item="${containerKey}[${containerIndex}]"]`
|
|
5306
|
+
);
|
|
5307
|
+
if (containerElement) {
|
|
5308
|
+
fieldWrapper = containerElement.querySelector(
|
|
5309
|
+
`[data-field-key="${element.key}"]`
|
|
5310
|
+
);
|
|
5311
|
+
}
|
|
5312
|
+
} else {
|
|
5313
|
+
const containerElement = this.state.formRoot.querySelector(
|
|
5314
|
+
`[data-container="${currentPath}"]`
|
|
5315
|
+
);
|
|
5316
|
+
if (containerElement) {
|
|
5317
|
+
fieldWrapper = containerElement.querySelector(
|
|
5318
|
+
`[data-field-key="${element.key}"]`
|
|
5319
|
+
);
|
|
5320
|
+
}
|
|
5321
|
+
}
|
|
5322
|
+
} else {
|
|
5323
|
+
fieldWrapper = this.state.formRoot.querySelector(
|
|
5324
|
+
`[data-field-key="${element.key}"]`
|
|
5325
|
+
);
|
|
5326
|
+
}
|
|
5327
|
+
if (fieldWrapper) {
|
|
5328
|
+
const wrapper = fieldWrapper;
|
|
4895
5329
|
try {
|
|
4896
|
-
|
|
4897
|
-
|
|
4898
|
-
|
|
4899
|
-
|
|
5330
|
+
let containerData = void 0;
|
|
5331
|
+
const scope = element.enableIf.scope ?? "relative";
|
|
5332
|
+
if (scope === "relative" && currentPath) {
|
|
5333
|
+
containerData = getValueByPath(formData, currentPath);
|
|
5334
|
+
}
|
|
5335
|
+
const shouldEnable = evaluateEnableCondition(
|
|
5336
|
+
element.enableIf,
|
|
5337
|
+
formData,
|
|
5338
|
+
// Use complete formData for absolute scope
|
|
5339
|
+
containerData
|
|
5340
|
+
// Use container-specific data for relative scope
|
|
4900
5341
|
);
|
|
4901
|
-
const
|
|
4902
|
-
if (
|
|
5342
|
+
const isCurrentlyDisabled = wrapper.getAttribute("data-conditionally-disabled") === "true";
|
|
5343
|
+
if (shouldEnable && isCurrentlyDisabled) {
|
|
5344
|
+
const containerPrefill = currentPath ? getValueByPath(formData, currentPath) : formData;
|
|
5345
|
+
const prefillContext = containerPrefill && typeof containerPrefill === "object" ? containerPrefill : {};
|
|
4903
5346
|
const newWrapper = renderElement2(element, {
|
|
4904
|
-
path:
|
|
4905
|
-
// Use
|
|
4906
|
-
prefill:
|
|
4907
|
-
// Use complete formData for root-level elements
|
|
5347
|
+
path: currentPath,
|
|
5348
|
+
// Use container path (empty string for root-level)
|
|
5349
|
+
prefill: prefillContext,
|
|
4908
5350
|
formData,
|
|
4909
|
-
// Pass complete formData for
|
|
5351
|
+
// Pass complete formData for enableIf evaluation
|
|
4910
5352
|
state: this.state,
|
|
4911
5353
|
instance: this
|
|
4912
5354
|
});
|
|
4913
5355
|
wrapper.parentNode?.replaceChild(newWrapper, wrapper);
|
|
4914
|
-
} else if (!
|
|
4915
|
-
const
|
|
4916
|
-
|
|
4917
|
-
|
|
4918
|
-
|
|
4919
|
-
|
|
4920
|
-
wrapper.parentNode?.replaceChild(
|
|
5356
|
+
} else if (!shouldEnable && !isCurrentlyDisabled) {
|
|
5357
|
+
const disabledWrapper = document.createElement("div");
|
|
5358
|
+
disabledWrapper.className = "fb-field-wrapper-disabled";
|
|
5359
|
+
disabledWrapper.style.display = "none";
|
|
5360
|
+
disabledWrapper.setAttribute("data-field-key", element.key);
|
|
5361
|
+
disabledWrapper.setAttribute("data-conditionally-disabled", "true");
|
|
5362
|
+
wrapper.parentNode?.replaceChild(disabledWrapper, wrapper);
|
|
4921
5363
|
}
|
|
4922
5364
|
} catch (error) {
|
|
4923
5365
|
console.error(
|
|
4924
|
-
`Error re-evaluating
|
|
5366
|
+
`Error re-evaluating enableIf for field "${element.key}" at path "${fullPath}":`,
|
|
4925
5367
|
error
|
|
4926
5368
|
);
|
|
4927
5369
|
}
|
|
4928
|
-
}
|
|
5370
|
+
}
|
|
4929
5371
|
}
|
|
4930
5372
|
if ((element.type === "container" || element.type === "group") && "elements" in element && element.elements) {
|
|
4931
5373
|
const containerData = formData?.[element.key];
|