@dmitryvim/form-builder 0.2.9 → 0.2.11

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/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.displayIf) {
73
- const displayIf = element.displayIf;
74
- if (!displayIf.key || typeof displayIf.key !== "string") {
107
+ if (element.enableIf) {
108
+ const enableIf = element.enableIf;
109
+ if (!enableIf.key || typeof enableIf.key !== "string") {
75
110
  errors.push(
76
- `${elementPath}: displayIf must have a 'key' property of type string`
111
+ `${elementPath}: enableIf must have a 'key' property of type string`
77
112
  );
78
113
  }
79
- const hasOperator = "equals" in displayIf;
114
+ const hasOperator = "equals" in enableIf;
80
115
  if (!hasOperator) {
81
116
  errors.push(
82
- `${elementPath}: displayIf must have at least one operator (equals, etc.)`
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/display-conditions.ts
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 evaluateDisplayCondition(condition, formData) {
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
- "Invalid displayIf condition: must have a 'key' property"
233
+ `Invalid enableIf scope: must be "relative" or "absolute" (got "${scope}")`
190
234
  );
191
235
  }
192
- const actualValue = getValueByPath(formData, condition.key);
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 displayIf condition: no recognized operator (equals, etc.)`
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 displayIf comparison, using reference equality"
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
- ctx.instance.triggerOnChange(pathKey, textInput.value);
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
- ctx.instance.triggerOnChange(textInput.name, textInput.value);
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);
@@ -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
- values.push(val);
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 = values.filter((v) => v.trim() !== "");
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: "", errors };
583
+ return { value: null, errors };
540
584
  }
541
- validateTextInput(input, val, key);
542
- return { value: val, errors };
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
- ctx.instance.triggerOnChange(pathKey, textareaInput.value);
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
- ctx.instance.triggerOnChange(textareaInput.name, textareaInput.value);
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);
@@ -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(".change-file-btn");
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(".delete-file-btn");
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(document.createTextNode("Your browser does not support the video tag."));
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(container, resourceId, fileName, meta, state);
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(document.createTextNode(` ${t("dragDropText", state)}`));
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(files[0], fileContainer, pathKey, state, deps, ctx.instance);
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(picker.files[0], fileContainer, pathKey, state, deps, ctx.instance);
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(filesContainer, initialFiles, state, updateFilesList2, pathKey, ctx.instance);
2162
- setupFilesPickerHandler(filesPicker, initialFiles, state, updateFilesList2, pathKey, ctx.instance);
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(filesContainer, initialFiles, state, updateFilesDisplay, pathKey, ctx.instance);
2225
- setupFilesPickerHandler(filesPicker, initialFiles, state, updateFilesDisplay, pathKey, ctx.instance);
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
  }
@@ -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(".colour-picker-hidden");
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(".colour-picker-hidden");
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(
@@ -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(errorElement, sliderContainer.nextSibling);
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 displayIf evaluation
3497
+ // Complete root data for enableIf evaluation
3376
3498
  state: ctx.state
3377
3499
  };
3378
3500
  element.elements.forEach((child) => {
@@ -3427,12 +3549,13 @@ function renderMultipleContainerElement(element, ctx, wrapper, _pathKey) {
3427
3549
  add.onclick = () => {
3428
3550
  if (countItems() < max) {
3429
3551
  const idx = countItems();
3552
+ const currentFormData = state.formRoot ? extractRootFormData(state.formRoot) : {};
3430
3553
  const subCtx = {
3431
3554
  state: ctx.state,
3432
3555
  path: pathJoin(ctx.path, `${element.key}[${idx}]`),
3433
3556
  prefill: {},
3434
- formData: ctx.formData ?? ctx.prefill
3435
- // Complete root data for displayIf
3557
+ formData: currentFormData
3558
+ // Current root data from DOM for enableIf
3436
3559
  };
3437
3560
  const item = document.createElement("div");
3438
3561
  item.className = "containerItem border border-gray-300 rounded-lg p-4 bg-white";
@@ -3481,7 +3604,9 @@ function renderMultipleContainerElement(element, ctx, wrapper, _pathKey) {
3481
3604
  };
3482
3605
  const updateAddButton = () => {
3483
3606
  const currentCount = countItems();
3484
- const existingAddBtn = containerWrap.querySelector(".add-container-btn");
3607
+ const existingAddBtn = containerWrap.querySelector(
3608
+ ".add-container-btn"
3609
+ );
3485
3610
  if (existingAddBtn) {
3486
3611
  existingAddBtn.disabled = currentCount >= max;
3487
3612
  existingAddBtn.style.opacity = currentCount >= max ? "0.5" : "1";
@@ -3496,7 +3621,7 @@ function renderMultipleContainerElement(element, ctx, wrapper, _pathKey) {
3496
3621
  path: pathJoin(ctx.path, `${element.key}[${idx}]`),
3497
3622
  prefill: prefillObj || {},
3498
3623
  formData: ctx.formData ?? ctx.prefill
3499
- // Complete root data for displayIf
3624
+ // Complete root data for enableIf
3500
3625
  };
3501
3626
  const item = document.createElement("div");
3502
3627
  item.className = "containerItem border border-gray-300 rounded-lg p-4 bg-white";
@@ -3548,7 +3673,7 @@ function renderMultipleContainerElement(element, ctx, wrapper, _pathKey) {
3548
3673
  path: pathJoin(ctx.path, `${element.key}[${idx}]`),
3549
3674
  prefill: {},
3550
3675
  formData: ctx.formData ?? ctx.prefill
3551
- // Complete root data for displayIf
3676
+ // Complete root data for enableIf
3552
3677
  };
3553
3678
  const item = document.createElement("div");
3554
3679
  item.className = "containerItem border border-gray-300 rounded-lg p-4 bg-white";
@@ -3647,6 +3772,26 @@ function validateContainerElement(element, key, context) {
3647
3772
  `[data-container-item="${key}[${i}]"]`
3648
3773
  ) || scopeRoot;
3649
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
+ }
3650
3795
  if (child.hidden || child.type === "hidden") {
3651
3796
  itemData[child.key] = child.default !== void 0 ? child.default : null;
3652
3797
  } else {
@@ -3666,6 +3811,26 @@ function validateContainerElement(element, key, context) {
3666
3811
  const containerData = {};
3667
3812
  const containerContainer = scopeRoot.querySelector(`[data-container="${key}"]`) || scopeRoot;
3668
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
+ }
3669
3834
  if (child.hidden || child.type === "hidden") {
3670
3835
  containerData[child.key] = child.default !== void 0 ? child.default : null;
3671
3836
  } else {
@@ -3850,31 +4015,180 @@ if (typeof document !== "undefined") {
3850
4015
  }
3851
4016
  });
3852
4017
  }
3853
- function checkDisplayCondition(element, ctx) {
3854
- if (!element.displayIf) {
3855
- return null;
4018
+ function shouldDisableElement(element, ctx) {
4019
+ if (!element.enableIf) {
4020
+ return false;
3856
4021
  }
3857
4022
  try {
3858
- const dataForCondition = ctx.formData ?? ctx.prefill;
3859
- const shouldDisplay = evaluateDisplayCondition(
3860
- element.displayIf,
3861
- dataForCondition
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
3862
4029
  );
3863
- if (!shouldDisplay) {
3864
- const hiddenWrapper = document.createElement("div");
3865
- hiddenWrapper.className = "fb-field-wrapper-hidden";
3866
- hiddenWrapper.style.display = "none";
3867
- hiddenWrapper.setAttribute("data-field-key", element.key);
3868
- hiddenWrapper.setAttribute("data-conditionally-hidden", "true");
3869
- return hiddenWrapper;
3870
- }
4030
+ return !shouldEnable;
3871
4031
  } catch (error) {
3872
4032
  console.error(
3873
- `Error evaluating displayIf for field "${element.key}":`,
4033
+ `Error evaluating enableIf for field "${element.key}":`,
3874
4034
  error
3875
4035
  );
3876
4036
  }
3877
- return null;
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
+ });
3878
4192
  }
3879
4193
  function createFieldLabel(element) {
3880
4194
  const title = document.createElement("label");
@@ -3992,10 +4306,7 @@ function dispatchToRenderer(element, ctx, wrapper, pathKey) {
3992
4306
  }
3993
4307
  }
3994
4308
  function renderElement2(element, ctx) {
3995
- const hiddenElement = checkDisplayCondition(element, ctx);
3996
- if (hiddenElement) {
3997
- return hiddenElement;
3998
- }
4309
+ const initiallyDisabled = shouldDisableElement(element, ctx);
3999
4310
  const wrapper = document.createElement("div");
4000
4311
  wrapper.className = "mb-6 fb-field-wrapper";
4001
4312
  wrapper.setAttribute("data-field-key", element.key);
@@ -4003,6 +4314,12 @@ function renderElement2(element, ctx) {
4003
4314
  wrapper.appendChild(label);
4004
4315
  const pathKey = pathJoin(ctx.path, element.key);
4005
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);
4006
4323
  return wrapper;
4007
4324
  }
4008
4325
  setRenderElement(renderElement2);
@@ -4661,15 +4978,16 @@ var FormBuilderInstance = class {
4661
4978
  event.preventDefault();
4662
4979
  event.stopPropagation();
4663
4980
  const hintValuesJson = target.getAttribute("data-hint-values");
4981
+ const isRootHint = target.getAttribute("data-root-hint") === "true";
4664
4982
  const containerKey = target.getAttribute("data-container-key");
4665
- if (!hintValuesJson || !containerKey) {
4983
+ if (!hintValuesJson || !isRootHint && !containerKey) {
4666
4984
  console.warn("Prefill hint missing required data attributes");
4667
4985
  return;
4668
4986
  }
4669
4987
  try {
4670
4988
  const hintValues = JSON.parse(hintValuesJson);
4671
4989
  for (const fieldKey in hintValues) {
4672
- const fullPath = `${containerKey}.${fieldKey}`;
4990
+ const fullPath = isRootHint ? fieldKey : `${containerKey}.${fieldKey}`;
4673
4991
  const value = hintValues[fieldKey];
4674
4992
  this.updateField(fullPath, value);
4675
4993
  }
@@ -4677,6 +4995,27 @@ var FormBuilderInstance = class {
4677
4995
  console.error("Error parsing prefill hint values:", error);
4678
4996
  }
4679
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
+ }
4680
5019
  /**
4681
5020
  * Render form from schema
4682
5021
  */
@@ -4692,8 +5031,19 @@ var FormBuilderInstance = class {
4692
5031
  clear(root);
4693
5032
  root.setAttribute("data-fb-root", "true");
4694
5033
  injectThemeVariables(root, this.state.config.theme);
4695
- const formEl = document.createElement("div");
4696
- formEl.className = "space-y-6";
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
+ }
4697
5047
  schema.elements.forEach((element) => {
4698
5048
  if (element.hidden) {
4699
5049
  return;
@@ -4702,13 +5052,14 @@ var FormBuilderInstance = class {
4702
5052
  path: "",
4703
5053
  prefill: prefill || {},
4704
5054
  formData: prefill || {},
4705
- // Pass complete root data for displayIf evaluation
5055
+ // Pass complete root data for enableIf evaluation
4706
5056
  state: this.state,
4707
5057
  instance: this
4708
5058
  });
4709
- formEl.appendChild(block);
5059
+ fieldsWrapper.appendChild(block);
4710
5060
  });
4711
- root.appendChild(formEl);
5061
+ rootContainer.appendChild(fieldsWrapper);
5062
+ root.appendChild(rootContainer);
4712
5063
  if (!this.state.config.readonly) {
4713
5064
  root.addEventListener("click", this.handlePrefillHintClick.bind(this));
4714
5065
  }
@@ -4750,15 +5101,18 @@ var FormBuilderInstance = class {
4750
5101
  };
4751
5102
  setValidateElement(validateElement2);
4752
5103
  this.state.schema.elements.forEach((element) => {
4753
- if (element.displayIf) {
5104
+ if (element.enableIf) {
4754
5105
  try {
4755
- const shouldDisplay = evaluateDisplayCondition(element.displayIf, data);
4756
- if (!shouldDisplay) {
5106
+ const shouldEnable = evaluateEnableCondition(
5107
+ element.enableIf,
5108
+ data
5109
+ );
5110
+ if (!shouldEnable) {
4757
5111
  return;
4758
5112
  }
4759
5113
  } catch (error) {
4760
5114
  console.error(
4761
- `Error evaluating displayIf for field "${element.key}" during validation:`,
5115
+ `Error evaluating enableIf for field "${element.key}" during validation:`,
4762
5116
  error
4763
5117
  );
4764
5118
  }
@@ -4846,7 +5200,9 @@ var FormBuilderInstance = class {
4846
5200
  }
4847
5201
  if (element.type === "container" || element.type === "group") {
4848
5202
  const containerElement = element;
4849
- const nestedData = this.buildHiddenFieldsData(containerElement.elements);
5203
+ const nestedData = this.buildHiddenFieldsData(
5204
+ containerElement.elements
5205
+ );
4850
5206
  if (Object.keys(nestedData).length > 0) {
4851
5207
  if (!(key in data)) {
4852
5208
  data[key] = nestedData;
@@ -4864,7 +5220,9 @@ var FormBuilderInstance = class {
4864
5220
  */
4865
5221
  setFormData(data) {
4866
5222
  if (!this.state.schema || !this.state.formRoot) {
4867
- console.warn("setFormData: Form not initialized. Call renderForm() first.");
5223
+ console.warn(
5224
+ "setFormData: Form not initialized. Call renderForm() first."
5225
+ );
4868
5226
  return;
4869
5227
  }
4870
5228
  for (const fieldPath in data) {
@@ -4878,20 +5236,27 @@ var FormBuilderInstance = class {
4878
5236
  */
4879
5237
  updateField(fieldPath, value) {
4880
5238
  if (!this.state.schema || !this.state.formRoot) {
4881
- console.warn("updateField: Form not initialized. Call renderForm() first.");
5239
+ console.warn(
5240
+ "updateField: Form not initialized. Call renderForm() first."
5241
+ );
4882
5242
  return;
4883
5243
  }
4884
5244
  const schemaElement = this.findSchemaElement(fieldPath);
4885
5245
  if (!schemaElement) {
4886
- console.warn(`updateField: Schema element not found for path "${fieldPath}"`);
5246
+ console.warn(
5247
+ `updateField: Schema element not found for path "${fieldPath}"`
5248
+ );
4887
5249
  return;
4888
5250
  }
4889
5251
  const domElement = this.findFormElementByFieldPath(fieldPath);
4890
5252
  if (!domElement) {
4891
- console.warn(`updateField: DOM element not found for path "${fieldPath}"`);
5253
+ console.warn(
5254
+ `updateField: DOM element not found for path "${fieldPath}"`
5255
+ );
4892
5256
  return;
4893
5257
  }
4894
5258
  this.updateFieldValue(domElement, schemaElement, fieldPath, value);
5259
+ this.reevaluateConditionalFields();
4895
5260
  if (this.state.config.onChange || this.state.config.onFieldChange) {
4896
5261
  this.triggerOnChange(fieldPath, value);
4897
5262
  }
@@ -4920,7 +5285,7 @@ var FormBuilderInstance = class {
4920
5285
  }
4921
5286
  }
4922
5287
  /**
4923
- * Re-evaluate all conditional fields (displayIf) based on current form data
5288
+ * Re-evaluate all conditional fields (enableIf) based on current form data
4924
5289
  * This is called automatically when form data changes (via onChange events)
4925
5290
  */
4926
5291
  reevaluateConditionalFields() {
@@ -4929,45 +5294,80 @@ var FormBuilderInstance = class {
4929
5294
  const checkElements = (elements, currentPath) => {
4930
5295
  elements.forEach((element) => {
4931
5296
  const fullPath = currentPath ? `${currentPath}.${element.key}` : element.key;
4932
- if (element.displayIf) {
4933
- const fieldWrappers = this.state.formRoot.querySelectorAll(
4934
- `[data-field-key="${element.key}"]`
4935
- );
4936
- fieldWrappers.forEach((wrapper) => {
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;
4937
5329
  try {
4938
- const shouldDisplay = evaluateDisplayCondition(
4939
- element.displayIf,
4940
- formData
4941
- // Use complete formData for condition evaluation
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
4942
5341
  );
4943
- const isCurrentlyHidden = wrapper.getAttribute("data-conditionally-hidden") === "true";
4944
- if (shouldDisplay && isCurrentlyHidden) {
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 : {};
4945
5346
  const newWrapper = renderElement2(element, {
4946
- path: fullPath,
4947
- // Use accumulated path
4948
- prefill: formData,
4949
- // Use complete formData for root-level elements
5347
+ path: currentPath,
5348
+ // Use container path (empty string for root-level)
5349
+ prefill: prefillContext,
4950
5350
  formData,
4951
- // Pass complete formData for displayIf evaluation
5351
+ // Pass complete formData for enableIf evaluation
4952
5352
  state: this.state,
4953
5353
  instance: this
4954
5354
  });
4955
5355
  wrapper.parentNode?.replaceChild(newWrapper, wrapper);
4956
- } else if (!shouldDisplay && !isCurrentlyHidden) {
4957
- const hiddenWrapper = document.createElement("div");
4958
- hiddenWrapper.className = "fb-field-wrapper-hidden";
4959
- hiddenWrapper.style.display = "none";
4960
- hiddenWrapper.setAttribute("data-field-key", element.key);
4961
- hiddenWrapper.setAttribute("data-conditionally-hidden", "true");
4962
- wrapper.parentNode?.replaceChild(hiddenWrapper, wrapper);
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);
4963
5363
  }
4964
5364
  } catch (error) {
4965
5365
  console.error(
4966
- `Error re-evaluating displayIf for field "${element.key}":`,
5366
+ `Error re-evaluating enableIf for field "${element.key}" at path "${fullPath}":`,
4967
5367
  error
4968
5368
  );
4969
5369
  }
4970
- });
5370
+ }
4971
5371
  }
4972
5372
  if ((element.type === "container" || element.type === "group") && "elements" in element && element.elements) {
4973
5373
  const containerData = formData?.[element.key];