@dmitryvim/form-builder 0.5.3 → 0.6.4
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 +8 -2
- package/dist/browser/formbuilder.min.js +129 -147
- package/dist/browser/formbuilder.v0.6.4.min.js +1472 -0
- package/dist/cjs/index.cjs +544 -489
- package/dist/cjs/index.cjs.map +1 -1
- package/dist/esm/index.js +483 -445
- package/dist/esm/index.js.map +1 -1
- package/dist/form-builder.js +129 -147
- package/dist/types/components/container.d.ts +1 -8
- package/dist/types/components/index.d.ts +1 -2
- package/dist/types/instance/FormBuilderInstance.d.ts +36 -5
- package/dist/types/instance/state.d.ts +8 -0
- package/dist/types/types/component-operations.d.ts +15 -0
- package/dist/types/types/config.d.ts +2 -0
- package/dist/types/types/state.d.ts +15 -0
- package/dist/types/utils/helpers.d.ts +33 -4
- package/dist/types/utils/styles.d.ts +13 -7
- package/package.json +1 -1
- package/dist/browser/formbuilder.v0.5.3.min.js +0 -1490
package/dist/cjs/index.cjs
CHANGED
|
@@ -4,15 +4,16 @@ Object.defineProperty(exports, '__esModule', { value: true });
|
|
|
4
4
|
|
|
5
5
|
// src/utils/translation.ts
|
|
6
6
|
function t(key, state, params) {
|
|
7
|
+
var _a, _b;
|
|
7
8
|
const locale = state.config.locale || "en";
|
|
8
9
|
const localeTranslations = state.config.translations[locale];
|
|
9
10
|
const fallbackTranslations = state.config.translations.en;
|
|
10
|
-
let text = (localeTranslations == null ? void 0 : localeTranslations[key])
|
|
11
|
+
let text = (_b = (_a = localeTranslations == null ? void 0 : localeTranslations[key]) != null ? _a : fallbackTranslations == null ? void 0 : fallbackTranslations[key]) != null ? _b : key;
|
|
11
12
|
if (params) {
|
|
12
13
|
for (const [paramKey, paramValue] of Object.entries(params)) {
|
|
13
14
|
text = text.replace(
|
|
14
15
|
new RegExp(`\\{${paramKey}\\}`, "g"),
|
|
15
|
-
String(paramValue)
|
|
16
|
+
() => String(paramValue)
|
|
16
17
|
);
|
|
17
18
|
}
|
|
18
19
|
}
|
|
@@ -27,9 +28,7 @@ function isPlainObject(obj) {
|
|
|
27
28
|
return obj && typeof obj === "object" && obj.constructor === Object;
|
|
28
29
|
}
|
|
29
30
|
function escapeHtml(text) {
|
|
30
|
-
|
|
31
|
-
div.textContent = text;
|
|
32
|
-
return div.innerHTML;
|
|
31
|
+
return text.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
33
32
|
}
|
|
34
33
|
function getElementLookupKey(element, state) {
|
|
35
34
|
if (element.key) {
|
|
@@ -64,8 +63,8 @@ function formatFileSize(bytes) {
|
|
|
64
63
|
return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
|
|
65
64
|
}
|
|
66
65
|
function serializeHiddenValue(value) {
|
|
67
|
-
if (value ===
|
|
68
|
-
return
|
|
66
|
+
if (value === void 0) return "";
|
|
67
|
+
return JSON.stringify(value);
|
|
69
68
|
}
|
|
70
69
|
function deserializeHiddenValue(raw) {
|
|
71
70
|
if (raw === "") return null;
|
|
@@ -75,6 +74,23 @@ function deserializeHiddenValue(raw) {
|
|
|
75
74
|
return raw;
|
|
76
75
|
}
|
|
77
76
|
}
|
|
77
|
+
function readTypedInputValue(input) {
|
|
78
|
+
if (input instanceof HTMLInputElement) {
|
|
79
|
+
if (input.type === "checkbox") return input.checked;
|
|
80
|
+
if (input.dataset.hiddenField) return deserializeHiddenValue(input.value);
|
|
81
|
+
if (input.dataset.booleanField) return input.value === "true";
|
|
82
|
+
if (input.type === "number" || input.type === "range") {
|
|
83
|
+
if (input.value === "") return null;
|
|
84
|
+
const parsed = parseFloat(input.value);
|
|
85
|
+
const decimals = input.dataset.decimals;
|
|
86
|
+
return decimals !== void 0 ? Number(parsed.toFixed(parseInt(decimals, 10))) : parsed;
|
|
87
|
+
}
|
|
88
|
+
if (input.dataset.colourField) {
|
|
89
|
+
return input.value.toUpperCase();
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
return input.value === "" ? null : input.value;
|
|
93
|
+
}
|
|
78
94
|
function createHiddenInput(name, value) {
|
|
79
95
|
const input = document.createElement("input");
|
|
80
96
|
input.type = "hidden";
|
|
@@ -316,6 +332,14 @@ function validateSchema(schema) {
|
|
|
316
332
|
}
|
|
317
333
|
}
|
|
318
334
|
function validateElements(elements, path) {
|
|
335
|
+
const seenKeys = /* @__PURE__ */ new Set();
|
|
336
|
+
elements.forEach((element, index) => {
|
|
337
|
+
if (!element.key) return;
|
|
338
|
+
if (seenKeys.has(element.key)) {
|
|
339
|
+
errors.push(`${path}[${index}]: duplicate key "${element.key}"`);
|
|
340
|
+
}
|
|
341
|
+
seenKeys.add(element.key);
|
|
342
|
+
});
|
|
319
343
|
elements.forEach((element, index) => {
|
|
320
344
|
const elementPath = `${path}[${index}]`;
|
|
321
345
|
if (!element.type) {
|
|
@@ -325,6 +349,14 @@ function validateSchema(schema) {
|
|
|
325
349
|
errors.push(`${elementPath}: missing key`);
|
|
326
350
|
}
|
|
327
351
|
validateCountBounds(element, elementPath, errors);
|
|
352
|
+
if (element.type === "number" && "decimals" in element) {
|
|
353
|
+
const decimals = element.decimals;
|
|
354
|
+
if (decimals !== void 0 && (!Number.isInteger(decimals) || decimals < 0)) {
|
|
355
|
+
errors.push(
|
|
356
|
+
`${elementPath}: decimals must be a non-negative integer (got ${JSON.stringify(decimals)})`
|
|
357
|
+
);
|
|
358
|
+
}
|
|
359
|
+
}
|
|
328
360
|
if (element.type === "markdown") {
|
|
329
361
|
const content = element.content;
|
|
330
362
|
if (typeof content !== "string") {
|
|
@@ -476,12 +508,58 @@ function deepEqual(a, b) {
|
|
|
476
508
|
}
|
|
477
509
|
|
|
478
510
|
// src/utils/styles.ts
|
|
479
|
-
function
|
|
511
|
+
function findErrorAnchor(input) {
|
|
512
|
+
var _a, _b, _c, _d;
|
|
513
|
+
return (_d = (_c = (_a = input.closest) == null ? void 0 : _a.call(input, ".fb-chip")) != null ? _c : (_b = input.closest) == null ? void 0 : _b.call(input, ".slider-container")) != null ? _d : input;
|
|
514
|
+
}
|
|
515
|
+
function findErrorNode(input) {
|
|
516
|
+
const anchor = findErrorAnchor(input);
|
|
480
517
|
const name = input.getAttribute("name");
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
518
|
+
const parent = anchor.parentElement;
|
|
519
|
+
if (name && parent) {
|
|
520
|
+
for (const child of Array.from(parent.children)) {
|
|
521
|
+
if (child.classList.contains("error-message") && child.getAttribute("data-error-for") === name) {
|
|
522
|
+
return child;
|
|
523
|
+
}
|
|
524
|
+
}
|
|
525
|
+
}
|
|
526
|
+
const sibling = anchor.nextElementSibling;
|
|
527
|
+
return sibling && sibling.classList.contains("error-message") ? sibling : null;
|
|
528
|
+
}
|
|
529
|
+
function markFieldValidity(input, errorMessage) {
|
|
530
|
+
var _a, _b, _c, _d;
|
|
531
|
+
if (!input) return;
|
|
532
|
+
if (errorMessage == null) {
|
|
533
|
+
input.classList.remove("invalid");
|
|
534
|
+
input.title = "";
|
|
535
|
+
(_a = findErrorNode(input)) == null ? void 0 : _a.remove();
|
|
536
|
+
return;
|
|
537
|
+
}
|
|
538
|
+
input.classList.add("invalid");
|
|
539
|
+
input.title = errorMessage;
|
|
540
|
+
if (errorMessage === "") {
|
|
541
|
+
(_b = findErrorNode(input)) == null ? void 0 : _b.remove();
|
|
542
|
+
return;
|
|
543
|
+
}
|
|
544
|
+
let errorElement = findErrorNode(input);
|
|
545
|
+
if (!errorElement) {
|
|
546
|
+
const anchor = findErrorAnchor(input);
|
|
547
|
+
errorElement = document.createElement("div");
|
|
548
|
+
errorElement.className = "error-message";
|
|
549
|
+
errorElement.style.cssText = `
|
|
550
|
+
color: var(--fb-error-color);
|
|
551
|
+
font-size: var(--fb-font-size-small);
|
|
552
|
+
margin-top: 0.25rem;
|
|
553
|
+
`;
|
|
554
|
+
(_c = anchor.parentNode) == null ? void 0 : _c.insertBefore(errorElement, anchor.nextSibling);
|
|
555
|
+
}
|
|
556
|
+
errorElement.setAttribute("data-error-for", (_d = input.getAttribute("name")) != null ? _d : "");
|
|
557
|
+
errorElement.textContent = errorMessage;
|
|
558
|
+
errorElement.style.display = "block";
|
|
559
|
+
}
|
|
560
|
+
function clearFieldError(input) {
|
|
561
|
+
var _a;
|
|
562
|
+
(_a = findErrorNode(input)) == null ? void 0 : _a.remove();
|
|
485
563
|
}
|
|
486
564
|
var BIN_ICON_SVG = '<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><polyline points="3 6 5 6 21 6"/><path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6"/><path d="M10 11v6"/><path d="M14 11v6"/><path d="M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"/></svg>';
|
|
487
565
|
function ensureThemingHooks(doc) {
|
|
@@ -603,8 +681,8 @@ function ensureThemingHooks(doc) {
|
|
|
603
681
|
`;
|
|
604
682
|
doc.head.appendChild(style);
|
|
605
683
|
}
|
|
606
|
-
function applyAutoExpand(textarea, options
|
|
607
|
-
var _a;
|
|
684
|
+
function applyAutoExpand(textarea, options) {
|
|
685
|
+
var _a, _b;
|
|
608
686
|
textarea.style.overflow = "hidden";
|
|
609
687
|
textarea.style.resize = "none";
|
|
610
688
|
const minRows = Math.max(1, (_a = options.minRows) != null ? _a : 1);
|
|
@@ -632,18 +710,20 @@ function applyAutoExpand(textarea, options = {}) {
|
|
|
632
710
|
if (typeof ResizeObserver === "undefined") return;
|
|
633
711
|
let lastWidth = -1;
|
|
634
712
|
const ro = new ResizeObserver((entries) => {
|
|
635
|
-
var _a2,
|
|
713
|
+
var _a2, _b2, _c, _d, _e, _f;
|
|
636
714
|
if (!textarea.isConnected) {
|
|
637
715
|
ro.disconnect();
|
|
716
|
+
(_a2 = options.observers) == null ? void 0 : _a2.delete(ro);
|
|
638
717
|
return;
|
|
639
718
|
}
|
|
640
719
|
const entry = entries[0];
|
|
641
|
-
const w = (
|
|
720
|
+
const w = (_f = (_e = (_c = (_b2 = entry == null ? void 0 : entry.contentBoxSize) == null ? void 0 : _b2[0]) == null ? void 0 : _c.inlineSize) != null ? _e : (_d = entry == null ? void 0 : entry.contentRect) == null ? void 0 : _d.width) != null ? _f : 0;
|
|
642
721
|
if (w === lastWidth) return;
|
|
643
722
|
lastWidth = w;
|
|
644
723
|
resize();
|
|
645
724
|
});
|
|
646
725
|
ro.observe(textarea);
|
|
726
|
+
(_b = options.observers) == null ? void 0 : _b.add(ro);
|
|
647
727
|
}
|
|
648
728
|
function applySingleLineMode(textarea) {
|
|
649
729
|
textarea.addEventListener("keydown", (e) => {
|
|
@@ -931,7 +1011,7 @@ function createCharCounter(element, input) {
|
|
|
931
1011
|
return counter;
|
|
932
1012
|
}
|
|
933
1013
|
function renderTextElement(element, ctx, wrapper, pathKey) {
|
|
934
|
-
var _a;
|
|
1014
|
+
var _a, _b, _c;
|
|
935
1015
|
const state = ctx.state;
|
|
936
1016
|
const readonly = isElementReadonly(element, state, ctx);
|
|
937
1017
|
const inputWrapper = document.createElement("div");
|
|
@@ -958,11 +1038,11 @@ function renderTextElement(element, ctx, wrapper, pathKey) {
|
|
|
958
1038
|
overflow-wrap: anywhere;
|
|
959
1039
|
`;
|
|
960
1040
|
textInput.name = pathKey;
|
|
961
|
-
textInput.placeholder = (_a = element.placeholder) != null ? _a : "
|
|
962
|
-
textInput.value = ctx.prefill[element.key]
|
|
1041
|
+
textInput.placeholder = (_a = element.placeholder) != null ? _a : t("placeholderText", state);
|
|
1042
|
+
textInput.value = (_c = (_b = ctx.prefill[element.key]) != null ? _b : element.default) != null ? _c : "";
|
|
963
1043
|
textInput.readOnly = readonly;
|
|
964
1044
|
applySingleLineMode(textInput);
|
|
965
|
-
applyAutoExpand(textInput);
|
|
1045
|
+
applyAutoExpand(textInput, { observers: state.autoExpandObservers });
|
|
966
1046
|
if (!readonly) {
|
|
967
1047
|
textInput.addEventListener("focus", () => {
|
|
968
1048
|
textInput.style.borderColor = "var(--fb-border-focus-color)";
|
|
@@ -1021,11 +1101,12 @@ function renderMultipleTextElement(element, ctx, wrapper, pathKey) {
|
|
|
1021
1101
|
const chip = input.closest(".fb-chip");
|
|
1022
1102
|
const sib = chip == null ? void 0 : chip.nextElementSibling;
|
|
1023
1103
|
if (sib && sib.classList.contains("error-message")) {
|
|
1024
|
-
sib.
|
|
1104
|
+
sib.setAttribute("data-error-for", input.name);
|
|
1025
1105
|
}
|
|
1026
1106
|
});
|
|
1027
1107
|
}
|
|
1028
1108
|
function addChip(value = "") {
|
|
1109
|
+
var _a2;
|
|
1029
1110
|
const chip = document.createElement("div");
|
|
1030
1111
|
chip.className = "fb-chip";
|
|
1031
1112
|
const dot = document.createElement("span");
|
|
@@ -1036,7 +1117,7 @@ function renderMultipleTextElement(element, ctx, wrapper, pathKey) {
|
|
|
1036
1117
|
input.rows = 1;
|
|
1037
1118
|
input.className = "fb-chip-input";
|
|
1038
1119
|
input.value = value;
|
|
1039
|
-
input.placeholder = element.placeholder
|
|
1120
|
+
input.placeholder = (_a2 = element.placeholder) != null ? _a2 : t("placeholderText", state);
|
|
1040
1121
|
input.readOnly = readonly;
|
|
1041
1122
|
chip.appendChild(input);
|
|
1042
1123
|
if (!readonly && ctx.instance) {
|
|
@@ -1050,7 +1131,7 @@ function renderMultipleTextElement(element, ctx, wrapper, pathKey) {
|
|
|
1050
1131
|
input.addEventListener("input", handleChange);
|
|
1051
1132
|
}
|
|
1052
1133
|
applySingleLineMode(input);
|
|
1053
|
-
applyAutoExpand(input);
|
|
1134
|
+
applyAutoExpand(input, { observers: state.autoExpandObservers });
|
|
1054
1135
|
if (!readonly) {
|
|
1055
1136
|
const rem = document.createElement("button");
|
|
1056
1137
|
rem.type = "button";
|
|
@@ -1058,6 +1139,7 @@ function renderMultipleTextElement(element, ctx, wrapper, pathKey) {
|
|
|
1058
1139
|
rem.setAttribute("aria-label", t("removeElement", state));
|
|
1059
1140
|
rem.innerHTML = BIN_ICON_SVG;
|
|
1060
1141
|
rem.onclick = () => {
|
|
1142
|
+
var _a3;
|
|
1061
1143
|
const chips = list.querySelectorAll(".fb-chip");
|
|
1062
1144
|
const idx = Array.prototype.indexOf.call(chips, chip);
|
|
1063
1145
|
if (idx < 0) return;
|
|
@@ -1071,6 +1153,7 @@ function renderMultipleTextElement(element, ctx, wrapper, pathKey) {
|
|
|
1071
1153
|
updateIndices();
|
|
1072
1154
|
updateAddButton();
|
|
1073
1155
|
updateRemoveButtons();
|
|
1156
|
+
(_a3 = ctx.instance) == null ? void 0 : _a3.triggerOnChange(pathKey);
|
|
1074
1157
|
};
|
|
1075
1158
|
chip.appendChild(rem);
|
|
1076
1159
|
}
|
|
@@ -1091,10 +1174,12 @@ function renderMultipleTextElement(element, ctx, wrapper, pathKey) {
|
|
|
1091
1174
|
const handle = createAddItemRow(
|
|
1092
1175
|
"text",
|
|
1093
1176
|
() => {
|
|
1177
|
+
var _a2;
|
|
1094
1178
|
values.push(element.default || "");
|
|
1095
1179
|
addChip(element.default || "");
|
|
1096
1180
|
updateAddButton();
|
|
1097
1181
|
updateRemoveButtons();
|
|
1182
|
+
(_a2 = ctx.instance) == null ? void 0 : _a2.triggerOnChange(pathKey);
|
|
1098
1183
|
},
|
|
1099
1184
|
{ label: element.addLabel }
|
|
1100
1185
|
);
|
|
@@ -1113,41 +1198,6 @@ function validateTextElement(element, key, context) {
|
|
|
1113
1198
|
var _a, _b, _c;
|
|
1114
1199
|
const errors = [];
|
|
1115
1200
|
const { scopeRoot, skipValidation } = context;
|
|
1116
|
-
const markValidity = (input, errorMessage) => {
|
|
1117
|
-
var _a2, _b2, _c2;
|
|
1118
|
-
if (!input) return;
|
|
1119
|
-
const errorId = `error-${input.getAttribute("name") || Math.random().toString(36).substring(7)}`;
|
|
1120
|
-
let errorElement = document.getElementById(errorId);
|
|
1121
|
-
if (errorMessage) {
|
|
1122
|
-
input.classList.add("invalid");
|
|
1123
|
-
input.title = errorMessage;
|
|
1124
|
-
if (!errorElement) {
|
|
1125
|
-
errorElement = document.createElement("div");
|
|
1126
|
-
errorElement.id = errorId;
|
|
1127
|
-
errorElement.className = "error-message";
|
|
1128
|
-
errorElement.style.cssText = `
|
|
1129
|
-
color: var(--fb-error-color);
|
|
1130
|
-
font-size: var(--fb-font-size-small);
|
|
1131
|
-
margin-top: 0.25rem;
|
|
1132
|
-
`;
|
|
1133
|
-
const chipAncestor = (_a2 = input.closest) == null ? void 0 : _a2.call(input, ".fb-chip");
|
|
1134
|
-
const anchor = chipAncestor || input;
|
|
1135
|
-
if (anchor.nextSibling) {
|
|
1136
|
-
(_b2 = anchor.parentNode) == null ? void 0 : _b2.insertBefore(errorElement, anchor.nextSibling);
|
|
1137
|
-
} else {
|
|
1138
|
-
(_c2 = anchor.parentNode) == null ? void 0 : _c2.appendChild(errorElement);
|
|
1139
|
-
}
|
|
1140
|
-
}
|
|
1141
|
-
errorElement.textContent = errorMessage;
|
|
1142
|
-
errorElement.style.display = "block";
|
|
1143
|
-
} else {
|
|
1144
|
-
input.classList.remove("invalid");
|
|
1145
|
-
input.title = "";
|
|
1146
|
-
if (errorElement) {
|
|
1147
|
-
errorElement.remove();
|
|
1148
|
-
}
|
|
1149
|
-
}
|
|
1150
|
-
};
|
|
1151
1201
|
const validateTextInput = (input, val, fieldKey) => {
|
|
1152
1202
|
let hasError = false;
|
|
1153
1203
|
const { state } = context;
|
|
@@ -1155,12 +1205,12 @@ function validateTextElement(element, key, context) {
|
|
|
1155
1205
|
if (element.minLength !== void 0 && element.minLength !== null && val.length < element.minLength) {
|
|
1156
1206
|
const msg = t("minLength", state, { min: element.minLength });
|
|
1157
1207
|
errors.push(`${fieldKey}: ${msg}`);
|
|
1158
|
-
|
|
1208
|
+
markFieldValidity(input, msg);
|
|
1159
1209
|
hasError = true;
|
|
1160
1210
|
} else if (element.maxLength !== void 0 && element.maxLength !== null && val.length > element.maxLength) {
|
|
1161
1211
|
const msg = t("maxLength", state, { max: element.maxLength });
|
|
1162
1212
|
errors.push(`${fieldKey}: ${msg}`);
|
|
1163
|
-
|
|
1213
|
+
markFieldValidity(input, msg);
|
|
1164
1214
|
hasError = true;
|
|
1165
1215
|
} else if (element.pattern) {
|
|
1166
1216
|
try {
|
|
@@ -1168,19 +1218,19 @@ function validateTextElement(element, key, context) {
|
|
|
1168
1218
|
if (!re.test(val)) {
|
|
1169
1219
|
const msg = t("patternMismatch", state);
|
|
1170
1220
|
errors.push(`${fieldKey}: ${msg}`);
|
|
1171
|
-
|
|
1221
|
+
markFieldValidity(input, msg);
|
|
1172
1222
|
hasError = true;
|
|
1173
1223
|
}
|
|
1174
1224
|
} catch {
|
|
1175
1225
|
const msg = t("invalidPattern", state);
|
|
1176
1226
|
errors.push(`${fieldKey}: ${msg}`);
|
|
1177
|
-
|
|
1227
|
+
markFieldValidity(input, msg);
|
|
1178
1228
|
hasError = true;
|
|
1179
1229
|
}
|
|
1180
1230
|
}
|
|
1181
1231
|
}
|
|
1182
1232
|
if (!hasError) {
|
|
1183
|
-
|
|
1233
|
+
markFieldValidity(input, null);
|
|
1184
1234
|
}
|
|
1185
1235
|
};
|
|
1186
1236
|
if (element.multiple) {
|
|
@@ -1211,12 +1261,12 @@ function validateTextElement(element, key, context) {
|
|
|
1211
1261
|
}
|
|
1212
1262
|
return { value: values, errors };
|
|
1213
1263
|
} else {
|
|
1214
|
-
const input = scopeRoot.querySelector(`[name
|
|
1264
|
+
const input = scopeRoot.querySelector(`[name="${key}"]`);
|
|
1215
1265
|
const val = (_c = input == null ? void 0 : input.value) != null ? _c : "";
|
|
1216
1266
|
if (!skipValidation && element.required && val === "") {
|
|
1217
1267
|
const msg = t("required", context.state);
|
|
1218
1268
|
errors.push(`${key}: ${msg}`);
|
|
1219
|
-
|
|
1269
|
+
markFieldValidity(input, msg);
|
|
1220
1270
|
return { value: null, errors };
|
|
1221
1271
|
}
|
|
1222
1272
|
if (input) {
|
|
@@ -1265,7 +1315,7 @@ function updateTextField(element, fieldPath, value, context) {
|
|
|
1265
1315
|
|
|
1266
1316
|
// src/components/textarea.ts
|
|
1267
1317
|
function renderTextareaElement(element, ctx, wrapper, pathKey) {
|
|
1268
|
-
var _a, _b;
|
|
1318
|
+
var _a, _b, _c, _d;
|
|
1269
1319
|
const state = ctx.state;
|
|
1270
1320
|
const readonly = isElementReadonly(element, state, ctx);
|
|
1271
1321
|
const textareaWrapper = document.createElement("div");
|
|
@@ -1279,8 +1329,8 @@ function renderTextareaElement(element, ctx, wrapper, pathKey) {
|
|
|
1279
1329
|
line-height: var(--fb-line-height, 1.5);
|
|
1280
1330
|
`;
|
|
1281
1331
|
textareaInput.name = pathKey;
|
|
1282
|
-
textareaInput.placeholder = (_a = element.placeholder) != null ? _a : "
|
|
1283
|
-
textareaInput.value = ctx.prefill[element.key]
|
|
1332
|
+
textareaInput.placeholder = (_a = element.placeholder) != null ? _a : t("placeholderText", state);
|
|
1333
|
+
textareaInput.value = (_c = (_b = ctx.prefill[element.key]) != null ? _b : element.default) != null ? _c : "";
|
|
1284
1334
|
textareaInput.readOnly = readonly;
|
|
1285
1335
|
if (!readonly && ctx.instance) {
|
|
1286
1336
|
const handleChange = () => {
|
|
@@ -1290,7 +1340,10 @@ function renderTextareaElement(element, ctx, wrapper, pathKey) {
|
|
|
1290
1340
|
textareaInput.addEventListener("blur", handleChange);
|
|
1291
1341
|
textareaInput.addEventListener("input", handleChange);
|
|
1292
1342
|
}
|
|
1293
|
-
applyAutoExpand(textareaInput, {
|
|
1343
|
+
applyAutoExpand(textareaInput, {
|
|
1344
|
+
minRows: (_d = element.rows) != null ? _d : 1,
|
|
1345
|
+
observers: state.autoExpandObservers
|
|
1346
|
+
});
|
|
1294
1347
|
textareaWrapper.appendChild(textareaInput);
|
|
1295
1348
|
if (!readonly && (element.minLength != null || element.maxLength != null)) {
|
|
1296
1349
|
const counter = createCharCounter(element, textareaInput);
|
|
@@ -1322,7 +1375,7 @@ function renderMultipleTextareaElement(element, ctx, wrapper, pathKey) {
|
|
|
1322
1375
|
});
|
|
1323
1376
|
}
|
|
1324
1377
|
function addTextareaItem(value = "", index = -1) {
|
|
1325
|
-
var _a2;
|
|
1378
|
+
var _a2, _b2;
|
|
1326
1379
|
const itemWrapper = document.createElement("div");
|
|
1327
1380
|
itemWrapper.className = "multiple-textarea-item";
|
|
1328
1381
|
const textareaContainer = document.createElement("div");
|
|
@@ -1335,7 +1388,7 @@ function renderMultipleTextareaElement(element, ctx, wrapper, pathKey) {
|
|
|
1335
1388
|
font-family: var(--fb-font-family);
|
|
1336
1389
|
line-height: var(--fb-line-height, 1.5);
|
|
1337
1390
|
`;
|
|
1338
|
-
textareaInput.placeholder = element.placeholder
|
|
1391
|
+
textareaInput.placeholder = (_a2 = element.placeholder) != null ? _a2 : t("placeholderText", state);
|
|
1339
1392
|
textareaInput.value = value;
|
|
1340
1393
|
textareaInput.readOnly = readonly;
|
|
1341
1394
|
if (!readonly && ctx.instance) {
|
|
@@ -1346,7 +1399,10 @@ function renderMultipleTextareaElement(element, ctx, wrapper, pathKey) {
|
|
|
1346
1399
|
textareaInput.addEventListener("blur", handleChange);
|
|
1347
1400
|
textareaInput.addEventListener("input", handleChange);
|
|
1348
1401
|
}
|
|
1349
|
-
applyAutoExpand(textareaInput, {
|
|
1402
|
+
applyAutoExpand(textareaInput, {
|
|
1403
|
+
minRows: (_b2 = element.rows) != null ? _b2 : 1,
|
|
1404
|
+
observers: state.autoExpandObservers
|
|
1405
|
+
});
|
|
1350
1406
|
textareaContainer.appendChild(textareaInput);
|
|
1351
1407
|
if (!readonly && (element.minLength != null || element.maxLength != null)) {
|
|
1352
1408
|
const counter = createCharCounter(element, textareaInput);
|
|
@@ -1375,6 +1431,7 @@ function renderMultipleTextareaElement(element, ctx, wrapper, pathKey) {
|
|
|
1375
1431
|
removeBtn.className = "remove-item-btn mt-1 px-2 py-1 text-red-600 hover:bg-red-50 rounded text-sm";
|
|
1376
1432
|
removeBtn.innerHTML = "\u2715";
|
|
1377
1433
|
removeBtn.onclick = () => {
|
|
1434
|
+
var _a2;
|
|
1378
1435
|
const currentIndex = Array.from(container.children).indexOf(
|
|
1379
1436
|
item
|
|
1380
1437
|
);
|
|
@@ -1384,6 +1441,7 @@ function renderMultipleTextareaElement(element, ctx, wrapper, pathKey) {
|
|
|
1384
1441
|
updateIndices();
|
|
1385
1442
|
updateAddButton();
|
|
1386
1443
|
updateRemoveButtons();
|
|
1444
|
+
(_a2 = ctx.instance) == null ? void 0 : _a2.triggerOnChange(pathKey);
|
|
1387
1445
|
}
|
|
1388
1446
|
};
|
|
1389
1447
|
item.appendChild(removeBtn);
|
|
@@ -1399,10 +1457,12 @@ function renderMultipleTextareaElement(element, ctx, wrapper, pathKey) {
|
|
|
1399
1457
|
const handle = createAddItemRow(
|
|
1400
1458
|
"textarea",
|
|
1401
1459
|
() => {
|
|
1460
|
+
var _a2;
|
|
1402
1461
|
values.push(element.default || "");
|
|
1403
1462
|
addTextareaItem(element.default || "");
|
|
1404
1463
|
updateAddButton();
|
|
1405
1464
|
updateRemoveButtons();
|
|
1465
|
+
(_a2 = ctx.instance) == null ? void 0 : _a2.triggerOnChange(pathKey);
|
|
1406
1466
|
},
|
|
1407
1467
|
{ label: element.addLabel }
|
|
1408
1468
|
);
|
|
@@ -1565,7 +1625,19 @@ function createNumberRangeHint(element, input) {
|
|
|
1565
1625
|
updateColor();
|
|
1566
1626
|
return hint;
|
|
1567
1627
|
}
|
|
1628
|
+
function numberStepAttr(element) {
|
|
1629
|
+
if (element.step !== void 0) return element.step.toString();
|
|
1630
|
+
if (element.decimals !== void 0)
|
|
1631
|
+
return (10 ** -element.decimals).toString();
|
|
1632
|
+
return "any";
|
|
1633
|
+
}
|
|
1634
|
+
function applyDecimalsMarker(input, element) {
|
|
1635
|
+
if (element.decimals !== void 0) {
|
|
1636
|
+
input.setAttribute("data-decimals", String(element.decimals));
|
|
1637
|
+
}
|
|
1638
|
+
}
|
|
1568
1639
|
function renderNumberElement(element, ctx, wrapper, pathKey) {
|
|
1640
|
+
var _a, _b, _c;
|
|
1569
1641
|
const state = ctx.state;
|
|
1570
1642
|
const readonly = isElementReadonly(element, state, ctx);
|
|
1571
1643
|
const inputWrapper = document.createElement("div");
|
|
@@ -1573,11 +1645,12 @@ function renderNumberElement(element, ctx, wrapper, pathKey) {
|
|
|
1573
1645
|
const numberInput = document.createElement("input");
|
|
1574
1646
|
numberInput.type = "number";
|
|
1575
1647
|
numberInput.name = pathKey;
|
|
1576
|
-
numberInput.placeholder = element.placeholder
|
|
1648
|
+
numberInput.placeholder = (_a = element.placeholder) != null ? _a : "0";
|
|
1577
1649
|
if (element.min !== void 0) numberInput.min = element.min.toString();
|
|
1578
1650
|
if (element.max !== void 0) numberInput.max = element.max.toString();
|
|
1579
|
-
|
|
1580
|
-
numberInput
|
|
1651
|
+
numberInput.step = numberStepAttr(element);
|
|
1652
|
+
applyDecimalsMarker(numberInput, element);
|
|
1653
|
+
numberInput.value = (_c = (_b = ctx.prefill[element.key]) != null ? _b : element.default) != null ? _c : "";
|
|
1581
1654
|
numberInput.readOnly = readonly;
|
|
1582
1655
|
if (!element.stepper) {
|
|
1583
1656
|
numberInput.className = "w-full border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500";
|
|
@@ -1609,7 +1682,7 @@ function renderNumberElement(element, ctx, wrapper, pathKey) {
|
|
|
1609
1682
|
wrapper.appendChild(inputWrapper);
|
|
1610
1683
|
}
|
|
1611
1684
|
function renderMultipleNumberElement(element, ctx, wrapper, pathKey) {
|
|
1612
|
-
var _a, _b;
|
|
1685
|
+
var _a, _b, _c;
|
|
1613
1686
|
const state = ctx.state;
|
|
1614
1687
|
const readonly = isElementReadonly(element, state, ctx);
|
|
1615
1688
|
const prefillValues = ctx.prefill[element.key] || [];
|
|
@@ -1617,7 +1690,7 @@ function renderMultipleNumberElement(element, ctx, wrapper, pathKey) {
|
|
|
1617
1690
|
const minCount = (_a = element.minCount) != null ? _a : element.required ? 1 : 0;
|
|
1618
1691
|
const maxCount = (_b = element.maxCount) != null ? _b : Infinity;
|
|
1619
1692
|
while (values.length < minCount) {
|
|
1620
|
-
values.push(element.default
|
|
1693
|
+
values.push((_c = element.default) != null ? _c : "");
|
|
1621
1694
|
}
|
|
1622
1695
|
const container = document.createElement("div");
|
|
1623
1696
|
container.className = "fb-row";
|
|
@@ -1632,6 +1705,7 @@ function renderMultipleNumberElement(element, ctx, wrapper, pathKey) {
|
|
|
1632
1705
|
});
|
|
1633
1706
|
}
|
|
1634
1707
|
function addNumberItem(value = "", index = -1) {
|
|
1708
|
+
var _a2;
|
|
1635
1709
|
const itemWrapper = document.createElement("div");
|
|
1636
1710
|
itemWrapper.className = "multiple-number-item flex items-center gap-2";
|
|
1637
1711
|
const inputContainer = document.createElement("div");
|
|
@@ -1646,10 +1720,11 @@ function renderMultipleNumberElement(element, ctx, wrapper, pathKey) {
|
|
|
1646
1720
|
width: 100%;
|
|
1647
1721
|
box-sizing: border-box;
|
|
1648
1722
|
`;
|
|
1649
|
-
numberInput.placeholder = element.placeholder
|
|
1723
|
+
numberInput.placeholder = (_a2 = element.placeholder) != null ? _a2 : "0";
|
|
1650
1724
|
if (element.min !== void 0) numberInput.min = element.min.toString();
|
|
1651
1725
|
if (element.max !== void 0) numberInput.max = element.max.toString();
|
|
1652
|
-
|
|
1726
|
+
numberInput.step = numberStepAttr(element);
|
|
1727
|
+
applyDecimalsMarker(numberInput, element);
|
|
1653
1728
|
numberInput.value = value.toString();
|
|
1654
1729
|
numberInput.readOnly = readonly;
|
|
1655
1730
|
if (!readonly && ctx.instance) {
|
|
@@ -1688,6 +1763,7 @@ function renderMultipleNumberElement(element, ctx, wrapper, pathKey) {
|
|
|
1688
1763
|
removeBtn.className = "remove-item-btn px-2 py-1 text-red-600 hover:bg-red-50 rounded";
|
|
1689
1764
|
removeBtn.innerHTML = "\u2715";
|
|
1690
1765
|
removeBtn.onclick = () => {
|
|
1766
|
+
var _a2;
|
|
1691
1767
|
const currentIndex = Array.from(container.children).indexOf(
|
|
1692
1768
|
item
|
|
1693
1769
|
);
|
|
@@ -1697,6 +1773,7 @@ function renderMultipleNumberElement(element, ctx, wrapper, pathKey) {
|
|
|
1697
1773
|
updateIndices();
|
|
1698
1774
|
updateAddButton();
|
|
1699
1775
|
updateRemoveButtons();
|
|
1776
|
+
(_a2 = ctx.instance) == null ? void 0 : _a2.triggerOnChange(pathKey);
|
|
1700
1777
|
}
|
|
1701
1778
|
};
|
|
1702
1779
|
item.appendChild(removeBtn);
|
|
@@ -1712,10 +1789,12 @@ function renderMultipleNumberElement(element, ctx, wrapper, pathKey) {
|
|
|
1712
1789
|
const handle = createAddItemRow(
|
|
1713
1790
|
"number",
|
|
1714
1791
|
() => {
|
|
1715
|
-
|
|
1716
|
-
|
|
1792
|
+
var _a2, _b2, _c2;
|
|
1793
|
+
values.push((_a2 = element.default) != null ? _a2 : "");
|
|
1794
|
+
addNumberItem((_b2 = element.default) != null ? _b2 : "");
|
|
1717
1795
|
updateAddButton();
|
|
1718
1796
|
updateRemoveButtons();
|
|
1797
|
+
(_c2 = ctx.instance) == null ? void 0 : _c2.triggerOnChange(pathKey);
|
|
1719
1798
|
},
|
|
1720
1799
|
{ label: element.addLabel }
|
|
1721
1800
|
);
|
|
@@ -1731,58 +1810,25 @@ function renderMultipleNumberElement(element, ctx, wrapper, pathKey) {
|
|
|
1731
1810
|
updateRemoveButtons();
|
|
1732
1811
|
}
|
|
1733
1812
|
function validateNumberElement(element, key, context) {
|
|
1734
|
-
var _a, _b, _c
|
|
1813
|
+
var _a, _b, _c;
|
|
1735
1814
|
const errors = [];
|
|
1736
1815
|
const { scopeRoot, skipValidation } = context;
|
|
1737
|
-
const markValidity = (input, errorMessage) => {
|
|
1738
|
-
var _a2, _b2;
|
|
1739
|
-
if (!input) return;
|
|
1740
|
-
const errorId = `error-${input.getAttribute("name") || Math.random().toString(36).substring(7)}`;
|
|
1741
|
-
let errorElement = document.getElementById(errorId);
|
|
1742
|
-
if (errorMessage) {
|
|
1743
|
-
input.classList.add("invalid");
|
|
1744
|
-
input.title = errorMessage;
|
|
1745
|
-
if (!errorElement) {
|
|
1746
|
-
errorElement = document.createElement("div");
|
|
1747
|
-
errorElement.id = errorId;
|
|
1748
|
-
errorElement.className = "error-message";
|
|
1749
|
-
errorElement.style.cssText = `
|
|
1750
|
-
color: var(--fb-error-color);
|
|
1751
|
-
font-size: var(--fb-font-size-small);
|
|
1752
|
-
margin-top: 0.25rem;
|
|
1753
|
-
`;
|
|
1754
|
-
if (input.nextSibling) {
|
|
1755
|
-
(_a2 = input.parentNode) == null ? void 0 : _a2.insertBefore(errorElement, input.nextSibling);
|
|
1756
|
-
} else {
|
|
1757
|
-
(_b2 = input.parentNode) == null ? void 0 : _b2.appendChild(errorElement);
|
|
1758
|
-
}
|
|
1759
|
-
}
|
|
1760
|
-
errorElement.textContent = errorMessage;
|
|
1761
|
-
errorElement.style.display = "block";
|
|
1762
|
-
} else {
|
|
1763
|
-
input.classList.remove("invalid");
|
|
1764
|
-
input.title = "";
|
|
1765
|
-
if (errorElement) {
|
|
1766
|
-
errorElement.remove();
|
|
1767
|
-
}
|
|
1768
|
-
}
|
|
1769
|
-
};
|
|
1770
1816
|
const validateNumberInput = (input, v, fieldKey) => {
|
|
1771
1817
|
let hasError = false;
|
|
1772
1818
|
const { state } = context;
|
|
1773
1819
|
if (!skipValidation && element.min !== void 0 && element.min !== null && v < element.min) {
|
|
1774
1820
|
const msg = t("minValue", state, { min: element.min });
|
|
1775
1821
|
errors.push(`${fieldKey}: ${msg}`);
|
|
1776
|
-
|
|
1822
|
+
markFieldValidity(input, msg);
|
|
1777
1823
|
hasError = true;
|
|
1778
1824
|
} else if (!skipValidation && element.max !== void 0 && element.max !== null && v > element.max) {
|
|
1779
1825
|
const msg = t("maxValue", state, { max: element.max });
|
|
1780
1826
|
errors.push(`${fieldKey}: ${msg}`);
|
|
1781
|
-
|
|
1827
|
+
markFieldValidity(input, msg);
|
|
1782
1828
|
hasError = true;
|
|
1783
1829
|
}
|
|
1784
1830
|
if (!hasError) {
|
|
1785
|
-
|
|
1831
|
+
markFieldValidity(input, null);
|
|
1786
1832
|
}
|
|
1787
1833
|
};
|
|
1788
1834
|
if (element.multiple) {
|
|
@@ -1791,24 +1837,23 @@ function validateNumberElement(element, key, context) {
|
|
|
1791
1837
|
);
|
|
1792
1838
|
const values = [];
|
|
1793
1839
|
inputs.forEach((input, index) => {
|
|
1794
|
-
var _a2
|
|
1840
|
+
var _a2;
|
|
1795
1841
|
const raw = (_a2 = input == null ? void 0 : input.value) != null ? _a2 : "";
|
|
1796
1842
|
if (raw === "") {
|
|
1797
1843
|
values.push(null);
|
|
1798
|
-
|
|
1844
|
+
markFieldValidity(input, null);
|
|
1799
1845
|
return;
|
|
1800
1846
|
}
|
|
1801
1847
|
const v = parseFloat(raw);
|
|
1802
1848
|
if (!skipValidation && !Number.isFinite(v)) {
|
|
1803
1849
|
const msg = t("notANumber", context.state);
|
|
1804
1850
|
errors.push(`${key}[${index}]: ${msg}`);
|
|
1805
|
-
|
|
1851
|
+
markFieldValidity(input, msg);
|
|
1806
1852
|
values.push(null);
|
|
1807
1853
|
return;
|
|
1808
1854
|
}
|
|
1809
1855
|
validateNumberInput(input, v, `${key}[${index}]`);
|
|
1810
|
-
|
|
1811
|
-
values.push(Number(v.toFixed(d)));
|
|
1856
|
+
values.push(applyDecimals(v, element.decimals));
|
|
1812
1857
|
});
|
|
1813
1858
|
if (!skipValidation) {
|
|
1814
1859
|
const { state } = context;
|
|
@@ -1827,31 +1872,34 @@ function validateNumberElement(element, key, context) {
|
|
|
1827
1872
|
}
|
|
1828
1873
|
return { value: values, errors };
|
|
1829
1874
|
} else {
|
|
1830
|
-
const input = scopeRoot.querySelector(`[name
|
|
1875
|
+
const input = scopeRoot.querySelector(`[name="${key}"]`);
|
|
1831
1876
|
const raw = (_c = input == null ? void 0 : input.value) != null ? _c : "";
|
|
1832
1877
|
const { state } = context;
|
|
1833
1878
|
if (!skipValidation && element.required && raw === "") {
|
|
1834
1879
|
const msg = t("required", state);
|
|
1835
1880
|
errors.push(`${key}: ${msg}`);
|
|
1836
|
-
|
|
1881
|
+
markFieldValidity(input, msg);
|
|
1837
1882
|
return { value: null, errors };
|
|
1838
1883
|
}
|
|
1839
1884
|
if (raw === "") {
|
|
1840
|
-
|
|
1885
|
+
markFieldValidity(input, null);
|
|
1841
1886
|
return { value: null, errors };
|
|
1842
1887
|
}
|
|
1843
1888
|
const v = parseFloat(raw);
|
|
1844
1889
|
if (!skipValidation && !Number.isFinite(v)) {
|
|
1845
1890
|
const msg = t("notANumber", state);
|
|
1846
1891
|
errors.push(`${key}: ${msg}`);
|
|
1847
|
-
|
|
1892
|
+
markFieldValidity(input, msg);
|
|
1848
1893
|
return { value: null, errors };
|
|
1849
1894
|
}
|
|
1850
1895
|
validateNumberInput(input, v, key);
|
|
1851
|
-
|
|
1852
|
-
return { value: Number(v.toFixed(d)), errors };
|
|
1896
|
+
return { value: applyDecimals(v, element.decimals), errors };
|
|
1853
1897
|
}
|
|
1854
1898
|
}
|
|
1899
|
+
function applyDecimals(v, decimals) {
|
|
1900
|
+
if (!Number.isInteger(decimals) || decimals < 0) return v;
|
|
1901
|
+
return Number(v.toFixed(decimals));
|
|
1902
|
+
}
|
|
1855
1903
|
function updateNumberField(element, fieldPath, value, context) {
|
|
1856
1904
|
const { scopeRoot } = context;
|
|
1857
1905
|
if (element.multiple) {
|
|
@@ -1891,7 +1939,41 @@ function updateNumberField(element, fieldPath, value, context) {
|
|
|
1891
1939
|
}
|
|
1892
1940
|
|
|
1893
1941
|
// src/components/select.ts
|
|
1942
|
+
function appendSelectOptions(select, element, selectedValue, state) {
|
|
1943
|
+
var _a;
|
|
1944
|
+
const options = element.options || [];
|
|
1945
|
+
if (!options.some((option) => option.value === "")) {
|
|
1946
|
+
const emptyOption = document.createElement("option");
|
|
1947
|
+
emptyOption.value = "";
|
|
1948
|
+
emptyOption.textContent = (_a = element.placeholder) != null ? _a : t("selectPlaceholder", state);
|
|
1949
|
+
select.appendChild(emptyOption);
|
|
1950
|
+
}
|
|
1951
|
+
const strSelected = selectedValue == null ? null : String(selectedValue);
|
|
1952
|
+
let anySelected = false;
|
|
1953
|
+
options.forEach((option) => {
|
|
1954
|
+
const optionEl = document.createElement("option");
|
|
1955
|
+
optionEl.value = option.value;
|
|
1956
|
+
optionEl.textContent = option.label;
|
|
1957
|
+
if (strSelected === option.value) {
|
|
1958
|
+
optionEl.selected = true;
|
|
1959
|
+
anySelected = true;
|
|
1960
|
+
}
|
|
1961
|
+
select.appendChild(optionEl);
|
|
1962
|
+
});
|
|
1963
|
+
if (!anySelected && strSelected !== null && strSelected !== "") {
|
|
1964
|
+
console.warn(
|
|
1965
|
+
`select "${element.key}": prefill value "${strSelected}" is not among the options; leaving the field unselected`
|
|
1966
|
+
);
|
|
1967
|
+
}
|
|
1968
|
+
if (!anySelected) {
|
|
1969
|
+
const empty = Array.from(select.options).find(
|
|
1970
|
+
(option) => option.value === ""
|
|
1971
|
+
);
|
|
1972
|
+
if (empty) empty.selected = true;
|
|
1973
|
+
}
|
|
1974
|
+
}
|
|
1894
1975
|
function renderSelectElement(element, ctx, wrapper, pathKey) {
|
|
1976
|
+
var _a;
|
|
1895
1977
|
const state = ctx.state;
|
|
1896
1978
|
const readonly = isElementReadonly(element, state, ctx);
|
|
1897
1979
|
const selectInput = document.createElement("select");
|
|
@@ -1903,18 +1985,18 @@ function renderSelectElement(element, ctx, wrapper, pathKey) {
|
|
|
1903
1985
|
`;
|
|
1904
1986
|
selectInput.name = pathKey;
|
|
1905
1987
|
selectInput.disabled = readonly;
|
|
1906
|
-
(
|
|
1907
|
-
|
|
1908
|
-
|
|
1909
|
-
|
|
1910
|
-
|
|
1911
|
-
|
|
1912
|
-
}
|
|
1913
|
-
selectInput.appendChild(optionEl);
|
|
1914
|
-
});
|
|
1988
|
+
appendSelectOptions(
|
|
1989
|
+
selectInput,
|
|
1990
|
+
element,
|
|
1991
|
+
(_a = ctx.prefill[element.key]) != null ? _a : element.default,
|
|
1992
|
+
state
|
|
1993
|
+
);
|
|
1915
1994
|
if (!readonly && ctx.instance) {
|
|
1916
1995
|
const handleChange = () => {
|
|
1917
|
-
ctx.instance.triggerOnChange(
|
|
1996
|
+
ctx.instance.triggerOnChange(
|
|
1997
|
+
pathKey,
|
|
1998
|
+
selectInput.value === "" ? null : selectInput.value
|
|
1999
|
+
);
|
|
1918
2000
|
};
|
|
1919
2001
|
selectInput.addEventListener("change", handleChange);
|
|
1920
2002
|
}
|
|
@@ -1927,7 +2009,7 @@ function renderSelectElement(element, ctx, wrapper, pathKey) {
|
|
|
1927
2009
|
}
|
|
1928
2010
|
}
|
|
1929
2011
|
function renderMultipleSelectElement(element, ctx, wrapper, pathKey) {
|
|
1930
|
-
var _a, _b, _c
|
|
2012
|
+
var _a, _b, _c;
|
|
1931
2013
|
const state = ctx.state;
|
|
1932
2014
|
const readonly = isElementReadonly(element, state, ctx);
|
|
1933
2015
|
const prefillValues = ctx.prefill[element.key] || [];
|
|
@@ -1935,7 +2017,7 @@ function renderMultipleSelectElement(element, ctx, wrapper, pathKey) {
|
|
|
1935
2017
|
const minCount = (_a = element.minCount) != null ? _a : element.required ? 1 : 0;
|
|
1936
2018
|
const maxCount = (_b = element.maxCount) != null ? _b : Infinity;
|
|
1937
2019
|
while (values.length < minCount) {
|
|
1938
|
-
values.push(
|
|
2020
|
+
values.push((_c = element.default) != null ? _c : "");
|
|
1939
2021
|
}
|
|
1940
2022
|
const container = document.createElement("div");
|
|
1941
2023
|
container.className = "fb-row";
|
|
@@ -1960,15 +2042,7 @@ function renderMultipleSelectElement(element, ctx, wrapper, pathKey) {
|
|
|
1960
2042
|
font-family: var(--fb-font-family);
|
|
1961
2043
|
`;
|
|
1962
2044
|
selectInput.disabled = readonly;
|
|
1963
|
-
(element
|
|
1964
|
-
const optionElement = document.createElement("option");
|
|
1965
|
-
optionElement.value = option.value;
|
|
1966
|
-
optionElement.textContent = option.label;
|
|
1967
|
-
if (value === option.value) {
|
|
1968
|
-
optionElement.selected = true;
|
|
1969
|
-
}
|
|
1970
|
-
selectInput.appendChild(optionElement);
|
|
1971
|
-
});
|
|
2045
|
+
appendSelectOptions(selectInput, element, value, state);
|
|
1972
2046
|
if (!readonly && ctx.instance) {
|
|
1973
2047
|
const handleChange = () => {
|
|
1974
2048
|
ctx.instance.triggerOnChange(selectInput.name, selectInput.value);
|
|
@@ -1998,6 +2072,7 @@ function renderMultipleSelectElement(element, ctx, wrapper, pathKey) {
|
|
|
1998
2072
|
removeBtn.className = "remove-item-btn px-2 py-1 text-red-600 hover:bg-red-50 rounded";
|
|
1999
2073
|
removeBtn.innerHTML = "\u2715";
|
|
2000
2074
|
removeBtn.onclick = () => {
|
|
2075
|
+
var _a2;
|
|
2001
2076
|
const currentIndex = Array.from(container.children).indexOf(item);
|
|
2002
2077
|
if (container.children.length > minCount) {
|
|
2003
2078
|
values.splice(currentIndex, 1);
|
|
@@ -2005,6 +2080,7 @@ function renderMultipleSelectElement(element, ctx, wrapper, pathKey) {
|
|
|
2005
2080
|
updateIndices();
|
|
2006
2081
|
updateAddButton();
|
|
2007
2082
|
updateRemoveButtons();
|
|
2083
|
+
(_a2 = ctx.instance) == null ? void 0 : _a2.triggerOnChange(pathKey);
|
|
2008
2084
|
}
|
|
2009
2085
|
};
|
|
2010
2086
|
item.appendChild(removeBtn);
|
|
@@ -2021,11 +2097,12 @@ function renderMultipleSelectElement(element, ctx, wrapper, pathKey) {
|
|
|
2021
2097
|
"select",
|
|
2022
2098
|
() => {
|
|
2023
2099
|
var _a2, _b2;
|
|
2024
|
-
const defaultValue =
|
|
2100
|
+
const defaultValue = (_a2 = element.default) != null ? _a2 : "";
|
|
2025
2101
|
values.push(defaultValue);
|
|
2026
2102
|
addSelectItem(defaultValue);
|
|
2027
2103
|
updateAddButton();
|
|
2028
2104
|
updateRemoveButtons();
|
|
2105
|
+
(_b2 = ctx.instance) == null ? void 0 : _b2.triggerOnChange(pathKey);
|
|
2029
2106
|
},
|
|
2030
2107
|
{ label: element.addLabel }
|
|
2031
2108
|
);
|
|
@@ -2050,39 +2127,6 @@ function validateSelectElement(element, key, context) {
|
|
|
2050
2127
|
var _a;
|
|
2051
2128
|
const errors = [];
|
|
2052
2129
|
const { scopeRoot, skipValidation } = context;
|
|
2053
|
-
const markValidity = (input, errorMessage) => {
|
|
2054
|
-
var _a2, _b;
|
|
2055
|
-
if (!input) return;
|
|
2056
|
-
const errorId = `error-${input.getAttribute("name") || Math.random().toString(36).substring(7)}`;
|
|
2057
|
-
let errorElement = document.getElementById(errorId);
|
|
2058
|
-
if (errorMessage) {
|
|
2059
|
-
input.classList.add("invalid");
|
|
2060
|
-
input.title = errorMessage;
|
|
2061
|
-
if (!errorElement) {
|
|
2062
|
-
errorElement = document.createElement("div");
|
|
2063
|
-
errorElement.id = errorId;
|
|
2064
|
-
errorElement.className = "error-message";
|
|
2065
|
-
errorElement.style.cssText = `
|
|
2066
|
-
color: var(--fb-error-color);
|
|
2067
|
-
font-size: var(--fb-font-size-small);
|
|
2068
|
-
margin-top: 0.25rem;
|
|
2069
|
-
`;
|
|
2070
|
-
if (input.nextSibling) {
|
|
2071
|
-
(_a2 = input.parentNode) == null ? void 0 : _a2.insertBefore(errorElement, input.nextSibling);
|
|
2072
|
-
} else {
|
|
2073
|
-
(_b = input.parentNode) == null ? void 0 : _b.appendChild(errorElement);
|
|
2074
|
-
}
|
|
2075
|
-
}
|
|
2076
|
-
errorElement.textContent = errorMessage;
|
|
2077
|
-
errorElement.style.display = "block";
|
|
2078
|
-
} else {
|
|
2079
|
-
input.classList.remove("invalid");
|
|
2080
|
-
input.title = "";
|
|
2081
|
-
if (errorElement) {
|
|
2082
|
-
errorElement.remove();
|
|
2083
|
-
}
|
|
2084
|
-
}
|
|
2085
|
-
};
|
|
2086
2130
|
const validateMultipleCount = (key2, values, element2, filterFn) => {
|
|
2087
2131
|
var _a2, _b;
|
|
2088
2132
|
if (skipValidation) return;
|
|
@@ -2108,27 +2152,36 @@ function validateSelectElement(element, key, context) {
|
|
|
2108
2152
|
inputs.forEach((input) => {
|
|
2109
2153
|
var _a2;
|
|
2110
2154
|
const val = (_a2 = input == null ? void 0 : input.value) != null ? _a2 : "";
|
|
2111
|
-
values.push(val);
|
|
2112
|
-
|
|
2155
|
+
values.push(val === "" ? null : val);
|
|
2156
|
+
markFieldValidity(input, null);
|
|
2113
2157
|
});
|
|
2114
|
-
validateMultipleCount(key, values, element, (v) => v
|
|
2158
|
+
validateMultipleCount(key, values, element, (v) => v != null);
|
|
2115
2159
|
return { value: values, errors };
|
|
2116
2160
|
} else {
|
|
2117
|
-
const input = scopeRoot.querySelector(
|
|
2118
|
-
`[name$="${key}"]`
|
|
2119
|
-
);
|
|
2161
|
+
const input = scopeRoot.querySelector(`[name="${key}"]`);
|
|
2120
2162
|
const val = (_a = input == null ? void 0 : input.value) != null ? _a : "";
|
|
2121
2163
|
if (!skipValidation && element.required && val === "") {
|
|
2122
2164
|
const msg = t("required", context.state);
|
|
2123
2165
|
errors.push(`${key}: ${msg}`);
|
|
2124
|
-
|
|
2166
|
+
markFieldValidity(input, msg);
|
|
2125
2167
|
return { value: null, errors };
|
|
2126
2168
|
} else {
|
|
2127
|
-
|
|
2169
|
+
markFieldValidity(input, null);
|
|
2128
2170
|
}
|
|
2129
2171
|
return { value: val === "" ? null : val, errors };
|
|
2130
2172
|
}
|
|
2131
2173
|
}
|
|
2174
|
+
function assertValueInOptions(select, strValue, fieldPath) {
|
|
2175
|
+
if (strValue === "") return;
|
|
2176
|
+
const match = Array.from(select.options).some(
|
|
2177
|
+
(option) => option.value === strValue
|
|
2178
|
+
);
|
|
2179
|
+
if (!match) {
|
|
2180
|
+
throw new Error(
|
|
2181
|
+
`updateSelectField: value "${strValue}" is not among the options of "${fieldPath}"`
|
|
2182
|
+
);
|
|
2183
|
+
}
|
|
2184
|
+
}
|
|
2132
2185
|
function updateSelectField(element, fieldPath, value, context) {
|
|
2133
2186
|
const { scopeRoot } = context;
|
|
2134
2187
|
if ("multiple" in element && element.multiple) {
|
|
@@ -2143,10 +2196,17 @@ function updateSelectField(element, fieldPath, value, context) {
|
|
|
2143
2196
|
);
|
|
2144
2197
|
selects.forEach((select, index) => {
|
|
2145
2198
|
if (index < value.length) {
|
|
2146
|
-
|
|
2199
|
+
const strValue = value[index] != null ? String(value[index]) : "";
|
|
2200
|
+
assertValueInOptions(select, strValue, `${fieldPath}[${index}]`);
|
|
2201
|
+
}
|
|
2202
|
+
});
|
|
2203
|
+
selects.forEach((select, index) => {
|
|
2204
|
+
if (index < value.length) {
|
|
2205
|
+
const strValue = value[index] != null ? String(value[index]) : "";
|
|
2206
|
+
select.value = strValue;
|
|
2147
2207
|
const options = select.querySelectorAll("option");
|
|
2148
2208
|
options.forEach((option) => {
|
|
2149
|
-
option.selected = option.value ===
|
|
2209
|
+
option.selected = option.value === strValue;
|
|
2150
2210
|
});
|
|
2151
2211
|
select.classList.remove("invalid");
|
|
2152
2212
|
select.title = "";
|
|
@@ -2163,10 +2223,12 @@ function updateSelectField(element, fieldPath, value, context) {
|
|
|
2163
2223
|
`[name="${fieldPath}"]`
|
|
2164
2224
|
);
|
|
2165
2225
|
if (select) {
|
|
2166
|
-
|
|
2226
|
+
const strValue = value != null ? String(value) : "";
|
|
2227
|
+
assertValueInOptions(select, strValue, fieldPath);
|
|
2228
|
+
select.value = strValue;
|
|
2167
2229
|
const options = select.querySelectorAll("option");
|
|
2168
2230
|
options.forEach((option) => {
|
|
2169
|
-
option.selected = option.value ===
|
|
2231
|
+
option.selected = option.value === strValue;
|
|
2170
2232
|
});
|
|
2171
2233
|
select.classList.remove("invalid");
|
|
2172
2234
|
select.title = "";
|
|
@@ -2364,14 +2426,14 @@ function renderSwitcherElement(element, ctx, wrapper, pathKey) {
|
|
|
2364
2426
|
}
|
|
2365
2427
|
}
|
|
2366
2428
|
function renderMultipleSwitcherElement(element, ctx, wrapper, pathKey) {
|
|
2367
|
-
var _a, _b, _c
|
|
2429
|
+
var _a, _b, _c;
|
|
2368
2430
|
const state = ctx.state;
|
|
2369
2431
|
const prefillValues = ctx.prefill[element.key] || [];
|
|
2370
2432
|
const values = Array.isArray(prefillValues) ? [...prefillValues] : [];
|
|
2371
2433
|
const minCount = (_a = element.minCount) != null ? _a : element.required ? 1 : 0;
|
|
2372
2434
|
const maxCount = (_b = element.maxCount) != null ? _b : Infinity;
|
|
2373
2435
|
while (values.length < minCount) {
|
|
2374
|
-
values.push(
|
|
2436
|
+
values.push((_c = element.default) != null ? _c : "");
|
|
2375
2437
|
}
|
|
2376
2438
|
const readonly = isElementReadonly(element, state, ctx);
|
|
2377
2439
|
const container = document.createElement("div");
|
|
@@ -2440,6 +2502,7 @@ function renderMultipleSwitcherElement(element, ctx, wrapper, pathKey) {
|
|
|
2440
2502
|
removeBtn.style.backgroundColor = "transparent";
|
|
2441
2503
|
});
|
|
2442
2504
|
removeBtn.onclick = () => {
|
|
2505
|
+
var _a2;
|
|
2443
2506
|
const currentIndex = Array.from(container.children).indexOf(
|
|
2444
2507
|
item
|
|
2445
2508
|
);
|
|
@@ -2449,6 +2512,7 @@ function renderMultipleSwitcherElement(element, ctx, wrapper, pathKey) {
|
|
|
2449
2512
|
updateIndices();
|
|
2450
2513
|
updateAddButton();
|
|
2451
2514
|
updateRemoveButtons();
|
|
2515
|
+
(_a2 = ctx.instance) == null ? void 0 : _a2.triggerOnChange(pathKey);
|
|
2452
2516
|
}
|
|
2453
2517
|
};
|
|
2454
2518
|
item.appendChild(removeBtn);
|
|
@@ -2465,11 +2529,12 @@ function renderMultipleSwitcherElement(element, ctx, wrapper, pathKey) {
|
|
|
2465
2529
|
"switcher",
|
|
2466
2530
|
() => {
|
|
2467
2531
|
var _a2, _b2;
|
|
2468
|
-
const defaultValue =
|
|
2532
|
+
const defaultValue = (_a2 = element.default) != null ? _a2 : "";
|
|
2469
2533
|
values.push(defaultValue);
|
|
2470
2534
|
addSwitcherItem(defaultValue);
|
|
2471
2535
|
updateAddButton();
|
|
2472
2536
|
updateRemoveButtons();
|
|
2537
|
+
(_b2 = ctx.instance) == null ? void 0 : _b2.triggerOnChange(pathKey);
|
|
2473
2538
|
},
|
|
2474
2539
|
{ label: element.addLabel }
|
|
2475
2540
|
);
|
|
@@ -2494,39 +2559,6 @@ function validateSwitcherElement(element, key, context) {
|
|
|
2494
2559
|
var _a;
|
|
2495
2560
|
const errors = [];
|
|
2496
2561
|
const { scopeRoot, skipValidation } = context;
|
|
2497
|
-
const markValidity = (input, errorMessage) => {
|
|
2498
|
-
var _a2, _b;
|
|
2499
|
-
if (!input) return;
|
|
2500
|
-
const errorId = `error-${input.getAttribute("name") || Math.random().toString(36).substring(7)}`;
|
|
2501
|
-
let errorElement = document.getElementById(errorId);
|
|
2502
|
-
if (errorMessage) {
|
|
2503
|
-
input.classList.add("invalid");
|
|
2504
|
-
input.title = errorMessage;
|
|
2505
|
-
if (!errorElement) {
|
|
2506
|
-
errorElement = document.createElement("div");
|
|
2507
|
-
errorElement.id = errorId;
|
|
2508
|
-
errorElement.className = "error-message";
|
|
2509
|
-
errorElement.style.cssText = `
|
|
2510
|
-
color: var(--fb-error-color);
|
|
2511
|
-
font-size: var(--fb-font-size-small);
|
|
2512
|
-
margin-top: 0.25rem;
|
|
2513
|
-
`;
|
|
2514
|
-
if (input.nextSibling) {
|
|
2515
|
-
(_a2 = input.parentNode) == null ? void 0 : _a2.insertBefore(errorElement, input.nextSibling);
|
|
2516
|
-
} else {
|
|
2517
|
-
(_b = input.parentNode) == null ? void 0 : _b.appendChild(errorElement);
|
|
2518
|
-
}
|
|
2519
|
-
}
|
|
2520
|
-
errorElement.textContent = errorMessage;
|
|
2521
|
-
errorElement.style.display = "block";
|
|
2522
|
-
} else {
|
|
2523
|
-
input.classList.remove("invalid");
|
|
2524
|
-
input.title = "";
|
|
2525
|
-
if (errorElement) {
|
|
2526
|
-
errorElement.remove();
|
|
2527
|
-
}
|
|
2528
|
-
}
|
|
2529
|
-
};
|
|
2530
2562
|
const validateMultipleCount = (fieldKey, values, el, filterFn) => {
|
|
2531
2563
|
var _a2, _b;
|
|
2532
2564
|
if (skipValidation) return;
|
|
@@ -2555,35 +2587,35 @@ function validateSwitcherElement(element, key, context) {
|
|
|
2555
2587
|
inputs.forEach((input) => {
|
|
2556
2588
|
var _a2;
|
|
2557
2589
|
const val = (_a2 = input == null ? void 0 : input.value) != null ? _a2 : "";
|
|
2558
|
-
values.push(val);
|
|
2590
|
+
values.push(val === "" ? null : val);
|
|
2559
2591
|
if (!skipValidation && val !== "" && !validOptionValues.has(val)) {
|
|
2560
2592
|
const msg = t("invalidOption", context.state);
|
|
2561
|
-
|
|
2593
|
+
markFieldValidity(input, msg);
|
|
2562
2594
|
errors.push(`${key}: ${msg}`);
|
|
2563
2595
|
} else {
|
|
2564
|
-
|
|
2596
|
+
markFieldValidity(input, null);
|
|
2565
2597
|
}
|
|
2566
2598
|
});
|
|
2567
|
-
validateMultipleCount(key, values, element, (v) => v
|
|
2599
|
+
validateMultipleCount(key, values, element, (v) => v != null);
|
|
2568
2600
|
return { value: values, errors };
|
|
2569
2601
|
} else {
|
|
2570
2602
|
const input = scopeRoot.querySelector(
|
|
2571
|
-
`input[type="hidden"][name
|
|
2603
|
+
`input[type="hidden"][name="${key}"]`
|
|
2572
2604
|
);
|
|
2573
2605
|
const val = (_a = input == null ? void 0 : input.value) != null ? _a : "";
|
|
2574
2606
|
if (!skipValidation && element.required && val === "") {
|
|
2575
2607
|
const msg = t("required", context.state);
|
|
2576
2608
|
errors.push(`${key}: ${msg}`);
|
|
2577
|
-
|
|
2609
|
+
markFieldValidity(input, msg);
|
|
2578
2610
|
return { value: null, errors };
|
|
2579
2611
|
}
|
|
2580
2612
|
if (!skipValidation && val !== "" && !validOptionValues.has(val)) {
|
|
2581
2613
|
const msg = t("invalidOption", context.state);
|
|
2582
2614
|
errors.push(`${key}: ${msg}`);
|
|
2583
|
-
|
|
2615
|
+
markFieldValidity(input, msg);
|
|
2584
2616
|
return { value: null, errors };
|
|
2585
2617
|
}
|
|
2586
|
-
|
|
2618
|
+
markFieldValidity(input, null);
|
|
2587
2619
|
return { value: val === "" ? null : val, errors };
|
|
2588
2620
|
}
|
|
2589
2621
|
}
|
|
@@ -2758,6 +2790,7 @@ function renderBooleanElement(element, ctx, wrapper, pathKey) {
|
|
|
2758
2790
|
const hiddenInput = document.createElement("input");
|
|
2759
2791
|
hiddenInput.type = "hidden";
|
|
2760
2792
|
hiddenInput.name = pathKey;
|
|
2793
|
+
hiddenInput.setAttribute("data-boolean-field", "true");
|
|
2761
2794
|
hiddenInput.value = initial ? "true" : "false";
|
|
2762
2795
|
const row = document.createElement("div");
|
|
2763
2796
|
row.className = "fb-toggle-row";
|
|
@@ -5664,7 +5697,7 @@ function validateSingleFile(element, key, context) {
|
|
|
5664
5697
|
const { scopeRoot, skipValidation, state } = context;
|
|
5665
5698
|
const errors = [];
|
|
5666
5699
|
const input = scopeRoot.querySelector(
|
|
5667
|
-
`input[name
|
|
5700
|
+
`input[name="${key}"][type="hidden"]`
|
|
5668
5701
|
);
|
|
5669
5702
|
const rid = (_a = input == null ? void 0 : input.value) != null ? _a : "";
|
|
5670
5703
|
if (!skipValidation && element.required && rid === "") {
|
|
@@ -5884,7 +5917,7 @@ function createReadonlyColourUI(value) {
|
|
|
5884
5917
|
container.appendChild(hexText);
|
|
5885
5918
|
return container;
|
|
5886
5919
|
}
|
|
5887
|
-
function createEditColourUI(value, pathKey, ctx) {
|
|
5920
|
+
function createEditColourUI(value, pathKey, ctx, placeholder) {
|
|
5888
5921
|
const normalizedValue = normalizeColourValue(value);
|
|
5889
5922
|
const pickerWrapper = document.createElement("div");
|
|
5890
5923
|
pickerWrapper.className = "colour-picker-wrapper";
|
|
@@ -5908,9 +5941,10 @@ function createEditColourUI(value, pathKey, ctx) {
|
|
|
5908
5941
|
const hexInput = document.createElement("input");
|
|
5909
5942
|
hexInput.type = "text";
|
|
5910
5943
|
hexInput.className = "colour-hex-input";
|
|
5944
|
+
hexInput.setAttribute("data-colour-field", "true");
|
|
5911
5945
|
hexInput.name = pathKey;
|
|
5912
5946
|
hexInput.value = normalizedValue;
|
|
5913
|
-
hexInput.placeholder = "#000000";
|
|
5947
|
+
hexInput.placeholder = placeholder != null ? placeholder : "#000000";
|
|
5914
5948
|
hexInput.style.cssText = `
|
|
5915
5949
|
width: 100px;
|
|
5916
5950
|
padding: var(--fb-input-padding-y) var(--fb-input-padding-x);
|
|
@@ -5997,14 +6031,20 @@ function createEditColourUI(value, pathKey, ctx) {
|
|
|
5997
6031
|
return pickerWrapper;
|
|
5998
6032
|
}
|
|
5999
6033
|
function renderColourElement(element, ctx, wrapper, pathKey) {
|
|
6034
|
+
var _a, _b;
|
|
6000
6035
|
const state = ctx.state;
|
|
6001
6036
|
const readonly = isElementReadonly(element, state, ctx);
|
|
6002
|
-
const initialValue = ctx.prefill[element.key]
|
|
6037
|
+
const initialValue = (_b = (_a = ctx.prefill[element.key]) != null ? _a : element.default) != null ? _b : "#000000";
|
|
6003
6038
|
if (readonly) {
|
|
6004
6039
|
const readonlyUI = createReadonlyColourUI(initialValue);
|
|
6005
6040
|
wrapper.appendChild(readonlyUI);
|
|
6006
6041
|
} else {
|
|
6007
|
-
const editUI = createEditColourUI(
|
|
6042
|
+
const editUI = createEditColourUI(
|
|
6043
|
+
initialValue,
|
|
6044
|
+
pathKey,
|
|
6045
|
+
ctx,
|
|
6046
|
+
element.placeholder
|
|
6047
|
+
);
|
|
6008
6048
|
wrapper.appendChild(editUI);
|
|
6009
6049
|
}
|
|
6010
6050
|
if (!readonly) {
|
|
@@ -6019,7 +6059,7 @@ function renderColourElement(element, ctx, wrapper, pathKey) {
|
|
|
6019
6059
|
}
|
|
6020
6060
|
}
|
|
6021
6061
|
function renderMultipleColourElement(element, ctx, wrapper, pathKey) {
|
|
6022
|
-
var _a, _b;
|
|
6062
|
+
var _a, _b, _c;
|
|
6023
6063
|
const state = ctx.state;
|
|
6024
6064
|
const readonly = isElementReadonly(element, state, ctx);
|
|
6025
6065
|
const prefillValues = ctx.prefill[element.key] || [];
|
|
@@ -6027,7 +6067,7 @@ function renderMultipleColourElement(element, ctx, wrapper, pathKey) {
|
|
|
6027
6067
|
const minCount = (_a = element.minCount) != null ? _a : element.required ? 1 : 0;
|
|
6028
6068
|
const maxCount = (_b = element.maxCount) != null ? _b : Infinity;
|
|
6029
6069
|
while (values.length < minCount) {
|
|
6030
|
-
values.push(element.default
|
|
6070
|
+
values.push((_c = element.default) != null ? _c : "#000000");
|
|
6031
6071
|
}
|
|
6032
6072
|
const container = document.createElement("div");
|
|
6033
6073
|
container.className = "fb-row";
|
|
@@ -6051,7 +6091,12 @@ function renderMultipleColourElement(element, ctx, wrapper, pathKey) {
|
|
|
6051
6091
|
}
|
|
6052
6092
|
} else {
|
|
6053
6093
|
const tempPathKey = `${pathKey}[${container.children.length}]`;
|
|
6054
|
-
const editUI = createEditColourUI(
|
|
6094
|
+
const editUI = createEditColourUI(
|
|
6095
|
+
value,
|
|
6096
|
+
tempPathKey,
|
|
6097
|
+
ctx,
|
|
6098
|
+
element.placeholder
|
|
6099
|
+
);
|
|
6055
6100
|
editUI.style.flex = "1";
|
|
6056
6101
|
itemWrapper.appendChild(editUI);
|
|
6057
6102
|
}
|
|
@@ -6088,6 +6133,7 @@ function renderMultipleColourElement(element, ctx, wrapper, pathKey) {
|
|
|
6088
6133
|
removeBtn.style.backgroundColor = "transparent";
|
|
6089
6134
|
});
|
|
6090
6135
|
removeBtn.onclick = () => {
|
|
6136
|
+
var _a2;
|
|
6091
6137
|
const currentIndex = Array.from(container.children).indexOf(
|
|
6092
6138
|
item
|
|
6093
6139
|
);
|
|
@@ -6097,6 +6143,7 @@ function renderMultipleColourElement(element, ctx, wrapper, pathKey) {
|
|
|
6097
6143
|
updateIndices();
|
|
6098
6144
|
updateAddButton();
|
|
6099
6145
|
updateRemoveButtons();
|
|
6146
|
+
(_a2 = ctx.instance) == null ? void 0 : _a2.triggerOnChange(pathKey);
|
|
6100
6147
|
}
|
|
6101
6148
|
};
|
|
6102
6149
|
item.appendChild(removeBtn);
|
|
@@ -6112,11 +6159,13 @@ function renderMultipleColourElement(element, ctx, wrapper, pathKey) {
|
|
|
6112
6159
|
const handle = createAddItemRow(
|
|
6113
6160
|
"colour",
|
|
6114
6161
|
() => {
|
|
6115
|
-
|
|
6162
|
+
var _a2, _b2;
|
|
6163
|
+
const defaultColour = (_a2 = element.default) != null ? _a2 : "#000000";
|
|
6116
6164
|
values.push(defaultColour);
|
|
6117
6165
|
addColourItem(defaultColour);
|
|
6118
6166
|
updateAddButton();
|
|
6119
6167
|
updateRemoveButtons();
|
|
6168
|
+
(_b2 = ctx.instance) == null ? void 0 : _b2.triggerOnChange(pathKey);
|
|
6120
6169
|
},
|
|
6121
6170
|
{ label: element.addLabel }
|
|
6122
6171
|
);
|
|
@@ -6145,59 +6194,26 @@ function validateColourElement(element, key, context) {
|
|
|
6145
6194
|
var _a, _b, _c;
|
|
6146
6195
|
const errors = [];
|
|
6147
6196
|
const { scopeRoot, skipValidation } = context;
|
|
6148
|
-
const markValidity = (input, errorMessage) => {
|
|
6149
|
-
var _a2, _b2;
|
|
6150
|
-
if (!input) return;
|
|
6151
|
-
const errorId = `error-${input.getAttribute("name") || Math.random().toString(36).substring(7)}`;
|
|
6152
|
-
let errorElement = document.getElementById(errorId);
|
|
6153
|
-
if (errorMessage) {
|
|
6154
|
-
input.classList.add("invalid");
|
|
6155
|
-
input.title = errorMessage;
|
|
6156
|
-
if (!errorElement) {
|
|
6157
|
-
errorElement = document.createElement("div");
|
|
6158
|
-
errorElement.id = errorId;
|
|
6159
|
-
errorElement.className = "error-message";
|
|
6160
|
-
errorElement.style.cssText = `
|
|
6161
|
-
color: var(--fb-error-color);
|
|
6162
|
-
font-size: var(--fb-font-size-small);
|
|
6163
|
-
margin-top: 0.25rem;
|
|
6164
|
-
`;
|
|
6165
|
-
if (input.nextSibling) {
|
|
6166
|
-
(_a2 = input.parentNode) == null ? void 0 : _a2.insertBefore(errorElement, input.nextSibling);
|
|
6167
|
-
} else {
|
|
6168
|
-
(_b2 = input.parentNode) == null ? void 0 : _b2.appendChild(errorElement);
|
|
6169
|
-
}
|
|
6170
|
-
}
|
|
6171
|
-
errorElement.textContent = errorMessage;
|
|
6172
|
-
errorElement.style.display = "block";
|
|
6173
|
-
} else {
|
|
6174
|
-
input.classList.remove("invalid");
|
|
6175
|
-
input.title = "";
|
|
6176
|
-
if (errorElement) {
|
|
6177
|
-
errorElement.remove();
|
|
6178
|
-
}
|
|
6179
|
-
}
|
|
6180
|
-
};
|
|
6181
6197
|
const validateColourValue = (input, val, fieldKey) => {
|
|
6182
6198
|
const { state } = context;
|
|
6183
6199
|
if (!val) {
|
|
6184
6200
|
if (!skipValidation && element.required) {
|
|
6185
6201
|
const msg = t("required", state);
|
|
6186
6202
|
errors.push(`${fieldKey}: ${msg}`);
|
|
6187
|
-
|
|
6203
|
+
markFieldValidity(input, msg);
|
|
6188
6204
|
return "";
|
|
6189
6205
|
}
|
|
6190
|
-
|
|
6206
|
+
markFieldValidity(input, null);
|
|
6191
6207
|
return "";
|
|
6192
6208
|
}
|
|
6193
6209
|
const normalized = normalizeColourValue(val);
|
|
6194
6210
|
if (!skipValidation && !isValidHexColour(normalized)) {
|
|
6195
6211
|
const msg = t("invalidHexColour", state);
|
|
6196
6212
|
errors.push(`${fieldKey}: ${msg}`);
|
|
6197
|
-
|
|
6213
|
+
markFieldValidity(input, msg);
|
|
6198
6214
|
return val;
|
|
6199
6215
|
}
|
|
6200
|
-
|
|
6216
|
+
markFieldValidity(input, null);
|
|
6201
6217
|
return normalized;
|
|
6202
6218
|
};
|
|
6203
6219
|
if (element.multiple) {
|
|
@@ -6235,7 +6251,7 @@ function validateColourElement(element, key, context) {
|
|
|
6235
6251
|
if (!skipValidation && element.required && val === "") {
|
|
6236
6252
|
const msg = t("required", context.state);
|
|
6237
6253
|
errors.push(`${key}: ${msg}`);
|
|
6238
|
-
|
|
6254
|
+
markFieldValidity(hexInput, msg);
|
|
6239
6255
|
return { value: "", errors };
|
|
6240
6256
|
}
|
|
6241
6257
|
const validated = validateColourValue(hexInput, val, key);
|
|
@@ -6550,6 +6566,7 @@ function renderMultipleSliderElement(element, ctx, wrapper, pathKey) {
|
|
|
6550
6566
|
removeBtn.style.backgroundColor = "transparent";
|
|
6551
6567
|
});
|
|
6552
6568
|
removeBtn.onclick = () => {
|
|
6569
|
+
var _a2;
|
|
6553
6570
|
const currentIndex = Array.from(container.children).indexOf(
|
|
6554
6571
|
item
|
|
6555
6572
|
);
|
|
@@ -6559,6 +6576,7 @@ function renderMultipleSliderElement(element, ctx, wrapper, pathKey) {
|
|
|
6559
6576
|
updateIndices();
|
|
6560
6577
|
updateAddButton();
|
|
6561
6578
|
updateRemoveButtons();
|
|
6579
|
+
(_a2 = ctx.instance) == null ? void 0 : _a2.triggerOnChange(pathKey);
|
|
6562
6580
|
}
|
|
6563
6581
|
};
|
|
6564
6582
|
item.appendChild(removeBtn);
|
|
@@ -6574,10 +6592,12 @@ function renderMultipleSliderElement(element, ctx, wrapper, pathKey) {
|
|
|
6574
6592
|
const handle = createAddItemRow(
|
|
6575
6593
|
"slider",
|
|
6576
6594
|
() => {
|
|
6595
|
+
var _a2;
|
|
6577
6596
|
values.push(defaultValue);
|
|
6578
6597
|
addSliderItem(defaultValue);
|
|
6579
6598
|
updateAddButton();
|
|
6580
6599
|
updateRemoveButtons();
|
|
6600
|
+
(_a2 = ctx.instance) == null ? void 0 : _a2.triggerOnChange(pathKey);
|
|
6581
6601
|
},
|
|
6582
6602
|
{ label: element.addLabel }
|
|
6583
6603
|
);
|
|
@@ -6620,43 +6640,6 @@ function validateSliderElement(element, key, context) {
|
|
|
6620
6640
|
const max = element.max;
|
|
6621
6641
|
const step = (_a = element.step) != null ? _a : 1;
|
|
6622
6642
|
const scale = element.scale || "linear";
|
|
6623
|
-
const markValidity = (input, errorMessage) => {
|
|
6624
|
-
var _a2, _b2;
|
|
6625
|
-
if (!input) return;
|
|
6626
|
-
const errorId = `error-${input.getAttribute("name") || Math.random().toString(36).substring(7)}`;
|
|
6627
|
-
let errorElement = document.getElementById(errorId);
|
|
6628
|
-
if (errorMessage) {
|
|
6629
|
-
input.classList.add("invalid");
|
|
6630
|
-
input.title = errorMessage;
|
|
6631
|
-
if (!errorElement) {
|
|
6632
|
-
errorElement = document.createElement("div");
|
|
6633
|
-
errorElement.id = errorId;
|
|
6634
|
-
errorElement.className = "error-message";
|
|
6635
|
-
errorElement.style.cssText = `
|
|
6636
|
-
color: var(--fb-error-color);
|
|
6637
|
-
font-size: var(--fb-font-size-small);
|
|
6638
|
-
margin-top: 0.25rem;
|
|
6639
|
-
`;
|
|
6640
|
-
const sliderContainer = input.closest(".slider-container");
|
|
6641
|
-
if (sliderContainer && sliderContainer.nextSibling) {
|
|
6642
|
-
(_a2 = sliderContainer.parentNode) == null ? void 0 : _a2.insertBefore(
|
|
6643
|
-
errorElement,
|
|
6644
|
-
sliderContainer.nextSibling
|
|
6645
|
-
);
|
|
6646
|
-
} else if (sliderContainer) {
|
|
6647
|
-
(_b2 = sliderContainer.parentNode) == null ? void 0 : _b2.appendChild(errorElement);
|
|
6648
|
-
}
|
|
6649
|
-
}
|
|
6650
|
-
errorElement.textContent = errorMessage;
|
|
6651
|
-
errorElement.style.display = "block";
|
|
6652
|
-
} else {
|
|
6653
|
-
input.classList.remove("invalid");
|
|
6654
|
-
input.title = "";
|
|
6655
|
-
if (errorElement) {
|
|
6656
|
-
errorElement.remove();
|
|
6657
|
-
}
|
|
6658
|
-
}
|
|
6659
|
-
};
|
|
6660
6643
|
const validateSliderValue = (slider, fieldKey) => {
|
|
6661
6644
|
const { state } = context;
|
|
6662
6645
|
const rawValue = slider.value;
|
|
@@ -6664,10 +6647,10 @@ function validateSliderElement(element, key, context) {
|
|
|
6664
6647
|
if (!skipValidation && element.required) {
|
|
6665
6648
|
const msg = t("required", state);
|
|
6666
6649
|
errors.push(`${fieldKey}: ${msg}`);
|
|
6667
|
-
|
|
6650
|
+
markFieldValidity(slider, msg);
|
|
6668
6651
|
return null;
|
|
6669
6652
|
}
|
|
6670
|
-
|
|
6653
|
+
markFieldValidity(slider, null);
|
|
6671
6654
|
return null;
|
|
6672
6655
|
}
|
|
6673
6656
|
let value;
|
|
@@ -6683,17 +6666,17 @@ function validateSliderElement(element, key, context) {
|
|
|
6683
6666
|
if (value < min) {
|
|
6684
6667
|
const msg = t("minValue", state, { min });
|
|
6685
6668
|
errors.push(`${fieldKey}: ${msg}`);
|
|
6686
|
-
|
|
6669
|
+
markFieldValidity(slider, msg);
|
|
6687
6670
|
return value;
|
|
6688
6671
|
}
|
|
6689
6672
|
if (value > max) {
|
|
6690
6673
|
const msg = t("maxValue", state, { max });
|
|
6691
6674
|
errors.push(`${fieldKey}: ${msg}`);
|
|
6692
|
-
|
|
6675
|
+
markFieldValidity(slider, msg);
|
|
6693
6676
|
return value;
|
|
6694
6677
|
}
|
|
6695
6678
|
}
|
|
6696
|
-
|
|
6679
|
+
markFieldValidity(slider, null);
|
|
6697
6680
|
return value;
|
|
6698
6681
|
};
|
|
6699
6682
|
if (element.multiple) {
|
|
@@ -6839,20 +6822,12 @@ function extractRootFormData(formRoot) {
|
|
|
6839
6822
|
inputs.forEach((input) => {
|
|
6840
6823
|
const fieldName = input.getAttribute("name");
|
|
6841
6824
|
if (fieldName && !fieldName.includes("[") && !fieldName.includes(".")) {
|
|
6842
|
-
if (input instanceof
|
|
6843
|
-
|
|
6844
|
-
} else if (input instanceof HTMLInputElement) {
|
|
6845
|
-
if (input.type === "checkbox") {
|
|
6846
|
-
data[fieldName] = input.checked;
|
|
6847
|
-
} else if (input.type === "radio") {
|
|
6848
|
-
if (input.checked) {
|
|
6849
|
-
data[fieldName] = input.value;
|
|
6850
|
-
}
|
|
6851
|
-
} else {
|
|
6825
|
+
if (input instanceof HTMLInputElement && input.type === "radio") {
|
|
6826
|
+
if (input.checked) {
|
|
6852
6827
|
data[fieldName] = input.value;
|
|
6853
6828
|
}
|
|
6854
|
-
} else
|
|
6855
|
-
data[fieldName] = input
|
|
6829
|
+
} else {
|
|
6830
|
+
data[fieldName] = readTypedInputValue(input);
|
|
6856
6831
|
}
|
|
6857
6832
|
}
|
|
6858
6833
|
});
|
|
@@ -6921,9 +6896,9 @@ function renderSingleContainerElement(element, ctx, wrapper, pathKey) {
|
|
|
6921
6896
|
inheritedReadonly: containerIsReadonly || ctx.inheritedReadonly
|
|
6922
6897
|
};
|
|
6923
6898
|
element.elements.forEach((child) => {
|
|
6924
|
-
var _a2
|
|
6899
|
+
var _a2;
|
|
6925
6900
|
if (child.type !== "markdown" && (child.hidden || child.type === "hidden")) {
|
|
6926
|
-
const prefillVal =
|
|
6901
|
+
const prefillVal = child.key in containerPrefill ? containerPrefill[child.key] : (_a2 = "default" in child ? child.default : null) != null ? _a2 : null;
|
|
6927
6902
|
itemsWrap.appendChild(
|
|
6928
6903
|
createHiddenInput(pathJoin(subCtx.path, child.key), prefillVal)
|
|
6929
6904
|
);
|
|
@@ -6968,7 +6943,7 @@ function mountRemoveButton(item, onRemove, state, containerLabel) {
|
|
|
6968
6943
|
item.classList.add("fb-row-removable");
|
|
6969
6944
|
item.insertBefore(rem, item.firstChild);
|
|
6970
6945
|
}
|
|
6971
|
-
function renderMultipleContainerElement(element, ctx, wrapper,
|
|
6946
|
+
function renderMultipleContainerElement(element, ctx, wrapper, pathKey) {
|
|
6972
6947
|
var _a, _b, _c, _d;
|
|
6973
6948
|
const state = ctx.state;
|
|
6974
6949
|
const containerIsReadonly = isElementReadonly(element, state, ctx);
|
|
@@ -6999,9 +6974,11 @@ function renderMultipleContainerElement(element, ctx, wrapper, _pathKey) {
|
|
|
6999
6974
|
);
|
|
7000
6975
|
const countItems = () => directRows().length;
|
|
7001
6976
|
const handleRemoveItem = (item) => {
|
|
6977
|
+
var _a2;
|
|
7002
6978
|
if (countItems() <= min) return;
|
|
7003
6979
|
item.remove();
|
|
7004
6980
|
updateAddButton();
|
|
6981
|
+
(_a2 = ctx.instance) == null ? void 0 : _a2.triggerOnChange(pathKey);
|
|
7005
6982
|
};
|
|
7006
6983
|
const createContainerItem = (idx, rowPrefill, formData) => {
|
|
7007
6984
|
const subCtx = {
|
|
@@ -7023,9 +7000,9 @@ function renderMultipleContainerElement(element, ctx, wrapper, _pathKey) {
|
|
|
7023
7000
|
isSlides ? void 0 : element.columns
|
|
7024
7001
|
);
|
|
7025
7002
|
element.elements.forEach((child) => {
|
|
7026
|
-
var _a2
|
|
7003
|
+
var _a2;
|
|
7027
7004
|
if (child.type !== "markdown" && (child.hidden || child.type === "hidden")) {
|
|
7028
|
-
const hiddenValue =
|
|
7005
|
+
const hiddenValue = rowPrefill && child.key in rowPrefill ? rowPrefill[child.key] : (_a2 = "default" in child ? child.default : null) != null ? _a2 : null;
|
|
7029
7006
|
childWrapper.appendChild(
|
|
7030
7007
|
createHiddenInput(pathJoin(subCtx.path, child.key), hiddenValue)
|
|
7031
7008
|
);
|
|
@@ -7045,6 +7022,7 @@ function renderMultipleContainerElement(element, ctx, wrapper, _pathKey) {
|
|
|
7045
7022
|
return item;
|
|
7046
7023
|
};
|
|
7047
7024
|
const handleAddItem = () => {
|
|
7025
|
+
var _a2;
|
|
7048
7026
|
if (countItems() >= max) return;
|
|
7049
7027
|
const item = createContainerItem(
|
|
7050
7028
|
takeRowIndex(),
|
|
@@ -7059,6 +7037,7 @@ function renderMultipleContainerElement(element, ctx, wrapper, _pathKey) {
|
|
|
7059
7037
|
itemsWrap.appendChild(item);
|
|
7060
7038
|
}
|
|
7061
7039
|
updateAddButton();
|
|
7040
|
+
(_a2 = ctx.instance) == null ? void 0 : _a2.triggerOnChange(pathKey);
|
|
7062
7041
|
};
|
|
7063
7042
|
let slideAddTile = null;
|
|
7064
7043
|
let slideAddUpdate = null;
|
|
@@ -7134,19 +7113,16 @@ function renderMultipleContainerElement(element, ctx, wrapper, _pathKey) {
|
|
|
7134
7113
|
}
|
|
7135
7114
|
}
|
|
7136
7115
|
}
|
|
7137
|
-
|
|
7138
|
-
|
|
7139
|
-
validateElementFunc = fn;
|
|
7140
|
-
}
|
|
7141
|
-
function validateElement(element, ctx, customScopeRoot) {
|
|
7142
|
-
if (!validateElementFunc) {
|
|
7116
|
+
function requireValidateElement(context) {
|
|
7117
|
+
if (!context.validateElement) {
|
|
7143
7118
|
throw new Error(
|
|
7144
|
-
"validateElement
|
|
7119
|
+
"validateContainerElement: context.validateElement missing \u2014 container validation requires the instance validator"
|
|
7145
7120
|
);
|
|
7146
7121
|
}
|
|
7147
|
-
return
|
|
7122
|
+
return context.validateElement;
|
|
7148
7123
|
}
|
|
7149
7124
|
function validateContainerElement(element, key, context) {
|
|
7125
|
+
const validateChild = requireValidateElement(context);
|
|
7150
7126
|
const errors = [];
|
|
7151
7127
|
const { scopeRoot, skipValidation, path } = context;
|
|
7152
7128
|
if (!("elements" in element)) {
|
|
@@ -7199,7 +7175,7 @@ function validateContainerElement(element, key, context) {
|
|
|
7199
7175
|
}
|
|
7200
7176
|
}
|
|
7201
7177
|
const childKey = `${key}[${domIndex}].${child.key}`;
|
|
7202
|
-
const childResult =
|
|
7178
|
+
const childResult = validateChild(
|
|
7203
7179
|
{ ...child, key: childKey },
|
|
7204
7180
|
{ path },
|
|
7205
7181
|
itemContainer
|
|
@@ -7241,7 +7217,7 @@ function validateContainerElement(element, key, context) {
|
|
|
7241
7217
|
}
|
|
7242
7218
|
{
|
|
7243
7219
|
const childKey = `${key}.${child.key}`;
|
|
7244
|
-
const childResult =
|
|
7220
|
+
const childResult = validateChild(
|
|
7245
7221
|
{ ...child, key: childKey },
|
|
7246
7222
|
{ path },
|
|
7247
7223
|
containerContainer
|
|
@@ -7360,7 +7336,7 @@ function renderGroupElement(element, ctx, wrapper, pathKey) {
|
|
|
7360
7336
|
maxCount: (_b = element.repeat) == null ? void 0 : _b.max
|
|
7361
7337
|
};
|
|
7362
7338
|
if (containerElement.multiple) {
|
|
7363
|
-
renderMultipleContainerElement(containerElement, ctx, wrapper);
|
|
7339
|
+
renderMultipleContainerElement(containerElement, ctx, wrapper, pathKey);
|
|
7364
7340
|
} else {
|
|
7365
7341
|
renderSingleContainerElement(containerElement, ctx, wrapper, pathKey);
|
|
7366
7342
|
}
|
|
@@ -7744,7 +7720,7 @@ function renderEditTable(element, initialData, pathKey, ctx, wrapper) {
|
|
|
7744
7720
|
rebuild();
|
|
7745
7721
|
} catch (e) {
|
|
7746
7722
|
const errMsg = e instanceof Error ? e.message : String(e);
|
|
7747
|
-
console.error(t("tableImportError", state
|
|
7723
|
+
console.error(t("tableImportError", state, { error: errMsg }));
|
|
7748
7724
|
} finally {
|
|
7749
7725
|
overlay.remove();
|
|
7750
7726
|
}
|
|
@@ -8704,7 +8680,7 @@ function updateTableField(element, fieldPath, value, context) {
|
|
|
8704
8680
|
}
|
|
8705
8681
|
|
|
8706
8682
|
// src/components/richinput.ts
|
|
8707
|
-
function applyAutoExpand2(textarea, backdrop) {
|
|
8683
|
+
function applyAutoExpand2(textarea, backdrop, observers) {
|
|
8708
8684
|
textarea.style.overflow = "hidden";
|
|
8709
8685
|
textarea.style.resize = "none";
|
|
8710
8686
|
const lineCount = (textarea.value.match(/\n/g) || []).length + 1;
|
|
@@ -8727,6 +8703,7 @@ function applyAutoExpand2(textarea, backdrop) {
|
|
|
8727
8703
|
var _a, _b, _c, _d, _e;
|
|
8728
8704
|
if (!textarea.isConnected) {
|
|
8729
8705
|
ro.disconnect();
|
|
8706
|
+
observers.delete(ro);
|
|
8730
8707
|
return;
|
|
8731
8708
|
}
|
|
8732
8709
|
const entry = entries[0];
|
|
@@ -8736,6 +8713,7 @@ function applyAutoExpand2(textarea, backdrop) {
|
|
|
8736
8713
|
resize();
|
|
8737
8714
|
});
|
|
8738
8715
|
ro.observe(textarea);
|
|
8716
|
+
observers.add(ro);
|
|
8739
8717
|
}
|
|
8740
8718
|
function buildFileLabels(files, state) {
|
|
8741
8719
|
var _a, _b, _c, _d;
|
|
@@ -9164,7 +9142,7 @@ function filterFilesForDropdown(query, files, labels) {
|
|
|
9164
9142
|
var TEXTAREA_FONT = "font-size: var(--fb-font-size, 14px); font-family: var(--fb-font-family, inherit); line-height: 1.6;";
|
|
9165
9143
|
var TEXTAREA_PADDING = "padding: 8px 40px 8px 10px;";
|
|
9166
9144
|
function renderEditMode(element, ctx, wrapper, pathKey, initialValue) {
|
|
9167
|
-
var _a;
|
|
9145
|
+
var _a, _b;
|
|
9168
9146
|
const state = ctx.state;
|
|
9169
9147
|
const files = [...initialValue.files];
|
|
9170
9148
|
const dropdownState = {
|
|
@@ -9178,12 +9156,12 @@ function renderEditMode(element, ctx, wrapper, pathKey, initialValue) {
|
|
|
9178
9156
|
hiddenInput.type = "hidden";
|
|
9179
9157
|
hiddenInput.name = pathKey;
|
|
9180
9158
|
function getCurrentValue() {
|
|
9181
|
-
var _a2,
|
|
9159
|
+
var _a2, _b2;
|
|
9182
9160
|
const rawText = textarea.value;
|
|
9183
9161
|
const nameToRid = buildNameToRid(files, state);
|
|
9184
9162
|
const submissionText = rawText ? replaceFilenamesWithRids(rawText, nameToRid) : null;
|
|
9185
9163
|
const textKey = (_a2 = element.textKey) != null ? _a2 : "text";
|
|
9186
|
-
const filesKey = (
|
|
9164
|
+
const filesKey = (_b2 = element.filesKey) != null ? _b2 : "files";
|
|
9187
9165
|
return {
|
|
9188
9166
|
[textKey]: rawText === "" ? null : submissionText,
|
|
9189
9167
|
[filesKey]: [...files]
|
|
@@ -9265,14 +9243,14 @@ function renderEditMode(element, ctx, wrapper, pathKey, initialValue) {
|
|
|
9265
9243
|
}
|
|
9266
9244
|
});
|
|
9267
9245
|
outerDiv.addEventListener("drop", (e) => {
|
|
9268
|
-
var _a2,
|
|
9246
|
+
var _a2, _b2;
|
|
9269
9247
|
e.preventDefault();
|
|
9270
9248
|
dragCounter = 0;
|
|
9271
9249
|
outerDiv.style.borderColor = "var(--fb-border-color, #d1d5db)";
|
|
9272
9250
|
outerDiv.style.boxShadow = "none";
|
|
9273
9251
|
const droppedFiles = (_a2 = e.dataTransfer) == null ? void 0 : _a2.files;
|
|
9274
9252
|
if (!droppedFiles || !state.config.uploadFile) return;
|
|
9275
|
-
const maxFiles = (
|
|
9253
|
+
const maxFiles = (_b2 = element.maxFiles) != null ? _b2 : Infinity;
|
|
9276
9254
|
for (let i = 0; i < droppedFiles.length; i++) {
|
|
9277
9255
|
if (files.length >= maxFiles) {
|
|
9278
9256
|
showUploadError(
|
|
@@ -9321,8 +9299,8 @@ function renderEditMode(element, ctx, wrapper, pathKey, initialValue) {
|
|
|
9321
9299
|
`;
|
|
9322
9300
|
const textarea = document.createElement("textarea");
|
|
9323
9301
|
textarea.name = `${pathKey}__text`;
|
|
9324
|
-
textarea.placeholder = element.placeholder
|
|
9325
|
-
const rawInitialText = (
|
|
9302
|
+
textarea.placeholder = (_a = element.placeholder) != null ? _a : t("richinputPlaceholder", state);
|
|
9303
|
+
const rawInitialText = (_b = initialValue.text) != null ? _b : "";
|
|
9326
9304
|
textarea.value = rawInitialText ? replaceRidsWithFilenames(rawInitialText, files, state) : "";
|
|
9327
9305
|
textarea.style.cssText = `
|
|
9328
9306
|
width: 100%;
|
|
@@ -9338,14 +9316,14 @@ function renderEditMode(element, ctx, wrapper, pathKey, initialValue) {
|
|
|
9338
9316
|
z-index: 1;
|
|
9339
9317
|
caret-color: var(--fb-text-color, #111827);
|
|
9340
9318
|
`;
|
|
9341
|
-
applyAutoExpand2(textarea, backdrop);
|
|
9319
|
+
applyAutoExpand2(textarea, backdrop, ctx.state.autoExpandObservers);
|
|
9342
9320
|
textarea.addEventListener("scroll", () => {
|
|
9343
9321
|
backdrop.scrollTop = textarea.scrollTop;
|
|
9344
9322
|
});
|
|
9345
9323
|
let mentionTooltip = null;
|
|
9346
9324
|
backdrop.addEventListener("mouseover", (e) => {
|
|
9347
|
-
var _a2,
|
|
9348
|
-
const mark = (
|
|
9325
|
+
var _a2, _b2;
|
|
9326
|
+
const mark = (_b2 = (_a2 = e.target).closest) == null ? void 0 : _b2.call(
|
|
9349
9327
|
_a2,
|
|
9350
9328
|
"mark"
|
|
9351
9329
|
);
|
|
@@ -9354,8 +9332,8 @@ function renderEditMode(element, ctx, wrapper, pathKey, initialValue) {
|
|
|
9354
9332
|
mentionTooltip = showMentionTooltip(mark, mark.dataset.rid, state);
|
|
9355
9333
|
});
|
|
9356
9334
|
backdrop.addEventListener("mouseout", (e) => {
|
|
9357
|
-
var _a2,
|
|
9358
|
-
const mark = (
|
|
9335
|
+
var _a2, _b2, _c;
|
|
9336
|
+
const mark = (_b2 = (_a2 = e.target).closest) == null ? void 0 : _b2.call(
|
|
9359
9337
|
_a2,
|
|
9360
9338
|
"mark"
|
|
9361
9339
|
);
|
|
@@ -9365,8 +9343,8 @@ function renderEditMode(element, ctx, wrapper, pathKey, initialValue) {
|
|
|
9365
9343
|
mentionTooltip = removePortalTooltip(mentionTooltip);
|
|
9366
9344
|
});
|
|
9367
9345
|
backdrop.addEventListener("mousedown", (e) => {
|
|
9368
|
-
var _a2,
|
|
9369
|
-
const mark = (
|
|
9346
|
+
var _a2, _b2;
|
|
9347
|
+
const mark = (_b2 = (_a2 = e.target).closest) == null ? void 0 : _b2.call(
|
|
9370
9348
|
_a2,
|
|
9371
9349
|
"mark"
|
|
9372
9350
|
);
|
|
@@ -9539,8 +9517,8 @@ function renderEditMode(element, ctx, wrapper, pathKey, initialValue) {
|
|
|
9539
9517
|
dropdown.appendChild(item);
|
|
9540
9518
|
});
|
|
9541
9519
|
dropdown.onmousemove = (e) => {
|
|
9542
|
-
var _a2,
|
|
9543
|
-
const target = (
|
|
9520
|
+
var _a2, _b2, _c;
|
|
9521
|
+
const target = (_b2 = (_a2 = e.target).closest) == null ? void 0 : _b2.call(
|
|
9544
9522
|
_a2,
|
|
9545
9523
|
".fb-richinput-dropdown-item"
|
|
9546
9524
|
);
|
|
@@ -9556,10 +9534,10 @@ function renderEditMode(element, ctx, wrapper, pathKey, initialValue) {
|
|
|
9556
9534
|
dropdownState.selectedIndex = newIdx;
|
|
9557
9535
|
};
|
|
9558
9536
|
dropdown.onmousedown = (e) => {
|
|
9559
|
-
var _a2,
|
|
9537
|
+
var _a2, _b2;
|
|
9560
9538
|
e.preventDefault();
|
|
9561
9539
|
e.stopPropagation();
|
|
9562
|
-
const target = (
|
|
9540
|
+
const target = (_b2 = (_a2 = e.target).closest) == null ? void 0 : _b2.call(
|
|
9563
9541
|
_a2,
|
|
9564
9542
|
".fb-richinput-dropdown-item"
|
|
9565
9543
|
);
|
|
@@ -9587,9 +9565,9 @@ function renderEditMode(element, ctx, wrapper, pathKey, initialValue) {
|
|
|
9587
9565
|
dropdownState.open = false;
|
|
9588
9566
|
}
|
|
9589
9567
|
function insertMention(rid) {
|
|
9590
|
-
var _a2,
|
|
9568
|
+
var _a2, _b2, _c, _d;
|
|
9591
9569
|
const labels = buildFileLabelsFromClosure();
|
|
9592
|
-
const label = (_c = (
|
|
9570
|
+
const label = (_c = (_b2 = labels.get(rid)) != null ? _b2 : (_a2 = state.resourceIndex.get(rid)) == null ? void 0 : _a2.name) != null ? _c : rid;
|
|
9593
9571
|
const cursorPos = (_d = textarea.selectionStart) != null ? _d : 0;
|
|
9594
9572
|
const before = textarea.value.slice(0, dropdownState.triggerPos);
|
|
9595
9573
|
const after = textarea.value.slice(cursorPos);
|
|
@@ -9681,10 +9659,10 @@ function renderEditMode(element, ctx, wrapper, pathKey, initialValue) {
|
|
|
9681
9659
|
thumbWrapper.appendChild(thumbInner);
|
|
9682
9660
|
const tooltipHandle = createTooltipHandle();
|
|
9683
9661
|
const doMention = () => {
|
|
9684
|
-
var _a2,
|
|
9662
|
+
var _a2, _b2, _c;
|
|
9685
9663
|
const cursorPos = (_a2 = textarea.selectionStart) != null ? _a2 : textarea.value.length;
|
|
9686
9664
|
const labels = buildFileLabelsFromClosure();
|
|
9687
|
-
const label = (_c = (
|
|
9665
|
+
const label = (_c = (_b2 = labels.get(rid)) != null ? _b2 : meta == null ? void 0 : meta.name) != null ? _c : rid;
|
|
9688
9666
|
const before = textarea.value.slice(0, cursorPos);
|
|
9689
9667
|
const after = textarea.value.slice(cursorPos);
|
|
9690
9668
|
const prefix = before.length > 0 && !/[\s\n]$/.test(before) ? "\n" : "";
|
|
@@ -9762,12 +9740,12 @@ function renderEditMode(element, ctx, wrapper, pathKey, initialValue) {
|
|
|
9762
9740
|
writeHidden();
|
|
9763
9741
|
(_a2 = ctx.instance) == null ? void 0 : _a2.triggerOnChange(pathKey, getCurrentValue());
|
|
9764
9742
|
}).catch((err) => {
|
|
9765
|
-
var _a2,
|
|
9743
|
+
var _a2, _b2;
|
|
9766
9744
|
const idx = files.indexOf(tempId);
|
|
9767
9745
|
if (idx !== -1) files.splice(idx, 1);
|
|
9768
9746
|
state.resourceIndex.delete(tempId);
|
|
9769
9747
|
renderFilesRow();
|
|
9770
|
-
(
|
|
9748
|
+
(_b2 = (_a2 = state.config).onUploadError) == null ? void 0 : _b2.call(_a2, err, file);
|
|
9771
9749
|
});
|
|
9772
9750
|
}
|
|
9773
9751
|
fileInput.addEventListener("change", () => {
|
|
@@ -10339,12 +10317,7 @@ function validateHiddenElement(element, key, context) {
|
|
|
10339
10317
|
const input = scopeRoot.querySelector(
|
|
10340
10318
|
`input[type="hidden"][data-hidden-field="true"][name="${key}"]`
|
|
10341
10319
|
);
|
|
10342
|
-
|
|
10343
|
-
if (raw === "") {
|
|
10344
|
-
const defaultVal = "default" in element ? element.default : null;
|
|
10345
|
-
return { value: defaultVal !== void 0 ? defaultVal : null, errors: [] };
|
|
10346
|
-
}
|
|
10347
|
-
return { value: deserializeHiddenValue(raw), errors: [] };
|
|
10320
|
+
return { value: deserializeHiddenValue((_a = input == null ? void 0 : input.value) != null ? _a : ""), errors: [] };
|
|
10348
10321
|
}
|
|
10349
10322
|
function updateHiddenField(_element, fieldPath, value, context) {
|
|
10350
10323
|
const { scopeRoot } = context;
|
|
@@ -10428,15 +10401,19 @@ var componentRegistry = {
|
|
|
10428
10401
|
function getComponentOperations(elementType) {
|
|
10429
10402
|
return componentRegistry[elementType] || null;
|
|
10430
10403
|
}
|
|
10404
|
+
function resolveOperations(element) {
|
|
10405
|
+
const isHiddenField = element.type !== "markdown" && (element.type === "hidden" || Boolean(element.hidden));
|
|
10406
|
+
return isHiddenField ? componentRegistry.hidden : getComponentOperations(element.type);
|
|
10407
|
+
}
|
|
10431
10408
|
function validateElementWithComponent(element, key, context) {
|
|
10432
|
-
const ops =
|
|
10409
|
+
const ops = resolveOperations(element);
|
|
10433
10410
|
if (ops && ops.validate) {
|
|
10434
10411
|
return ops.validate(element, key, context);
|
|
10435
10412
|
}
|
|
10436
10413
|
return null;
|
|
10437
10414
|
}
|
|
10438
10415
|
function updateElementWithComponent(element, fieldPath, value, context) {
|
|
10439
|
-
const ops =
|
|
10416
|
+
const ops = resolveOperations(element);
|
|
10440
10417
|
if (ops && ops.update) {
|
|
10441
10418
|
ops.update(element, fieldPath, value, context);
|
|
10442
10419
|
return true;
|
|
@@ -10448,6 +10425,10 @@ function updateElementWithComponent(element, fieldPath, value, context) {
|
|
|
10448
10425
|
function showTooltip(tooltipId, button) {
|
|
10449
10426
|
const tooltip = document.getElementById(tooltipId);
|
|
10450
10427
|
if (!tooltip) return;
|
|
10428
|
+
if (!button.isConnected) {
|
|
10429
|
+
tooltip.remove();
|
|
10430
|
+
return;
|
|
10431
|
+
}
|
|
10451
10432
|
const isCurrentlyVisible = !tooltip.classList.contains("hidden");
|
|
10452
10433
|
document.querySelectorAll('[id^="tooltip-"]').forEach((t2) => {
|
|
10453
10434
|
t2.classList.add("hidden");
|
|
@@ -10528,23 +10509,13 @@ function extractDOMValue(fieldPath, formRoot) {
|
|
|
10528
10509
|
if (!input) {
|
|
10529
10510
|
return void 0;
|
|
10530
10511
|
}
|
|
10531
|
-
if (input instanceof
|
|
10532
|
-
|
|
10533
|
-
|
|
10534
|
-
|
|
10535
|
-
|
|
10536
|
-
} else if (input.type === "radio") {
|
|
10537
|
-
const checked = formRoot.querySelector(
|
|
10538
|
-
`[name="${fieldPath}"]:checked`
|
|
10539
|
-
);
|
|
10540
|
-
return checked ? checked.value : void 0;
|
|
10541
|
-
} else {
|
|
10542
|
-
return input.value;
|
|
10543
|
-
}
|
|
10544
|
-
} else if (input instanceof HTMLTextAreaElement) {
|
|
10545
|
-
return input.value;
|
|
10512
|
+
if (input instanceof HTMLInputElement && input.type === "radio") {
|
|
10513
|
+
const checked = formRoot.querySelector(
|
|
10514
|
+
`[name="${fieldPath}"]:checked`
|
|
10515
|
+
);
|
|
10516
|
+
return checked ? checked.value : void 0;
|
|
10546
10517
|
}
|
|
10547
|
-
return
|
|
10518
|
+
return readTypedInputValue(input);
|
|
10548
10519
|
}
|
|
10549
10520
|
function buildScopedDataAtPath(path, value) {
|
|
10550
10521
|
const segments = path.match(/[^.[\]]+|\[\d+\]/g);
|
|
@@ -10676,11 +10647,19 @@ function createFieldLabel(element) {
|
|
|
10676
10647
|
}
|
|
10677
10648
|
return title;
|
|
10678
10649
|
}
|
|
10679
|
-
function
|
|
10650
|
+
function ensureTooltipStyles(doc) {
|
|
10651
|
+
if (doc.head.querySelector("[data-fb-tooltip-styles]")) return;
|
|
10652
|
+
const style = doc.createElement("style");
|
|
10653
|
+
style.setAttribute("data-fb-tooltip-styles", "");
|
|
10654
|
+
style.textContent = `[id^="tooltip-"].hidden { display: none; }`;
|
|
10655
|
+
doc.head.appendChild(style);
|
|
10656
|
+
}
|
|
10657
|
+
function createInfoButton(element, state) {
|
|
10680
10658
|
const infoBtn = document.createElement("button");
|
|
10681
10659
|
infoBtn.type = "button";
|
|
10682
10660
|
infoBtn.className = "ml-2 text-gray-400 hover:text-gray-600";
|
|
10683
10661
|
infoBtn.innerHTML = '<svg class="w-4 h-4" fill="currentColor" viewBox="0 0 24 24"><path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 15h-2v-6h2v6zm0-8h-2V7h2v2z"/></svg>';
|
|
10662
|
+
ensureTooltipStyles(document);
|
|
10684
10663
|
const tooltipId = `tooltip-${element.key}-${Math.random().toString(36).substr(2, 9)}`;
|
|
10685
10664
|
const tooltip = document.createElement("div");
|
|
10686
10665
|
tooltip.id = tooltipId;
|
|
@@ -10688,6 +10667,7 @@ function createInfoButton(element) {
|
|
|
10688
10667
|
tooltip.style.position = "fixed";
|
|
10689
10668
|
tooltip.textContent = element.description || element.hint || "Field information";
|
|
10690
10669
|
document.body.appendChild(tooltip);
|
|
10670
|
+
state.tooltipElements.add(tooltip);
|
|
10691
10671
|
infoBtn.onclick = (e) => {
|
|
10692
10672
|
e.preventDefault();
|
|
10693
10673
|
e.stopPropagation();
|
|
@@ -10695,7 +10675,7 @@ function createInfoButton(element) {
|
|
|
10695
10675
|
};
|
|
10696
10676
|
return infoBtn;
|
|
10697
10677
|
}
|
|
10698
|
-
function createLabelContainer(element) {
|
|
10678
|
+
function createLabelContainer(element, state) {
|
|
10699
10679
|
const label = document.createElement("div");
|
|
10700
10680
|
label.className = "flex items-center";
|
|
10701
10681
|
label.style.marginBottom = "var(--fb-label-margin-bottom, 2px)";
|
|
@@ -10703,7 +10683,7 @@ function createLabelContainer(element) {
|
|
|
10703
10683
|
const title = createFieldLabel(element);
|
|
10704
10684
|
label.appendChild(title);
|
|
10705
10685
|
if (element.description || element.hint) {
|
|
10706
|
-
const infoBtn = createInfoButton(element);
|
|
10686
|
+
const infoBtn = createInfoButton(element, state);
|
|
10707
10687
|
label.appendChild(infoBtn);
|
|
10708
10688
|
}
|
|
10709
10689
|
return label;
|
|
@@ -10778,7 +10758,7 @@ function dispatchToRenderer(element, ctx, wrapper, pathKey) {
|
|
|
10778
10758
|
break;
|
|
10779
10759
|
case "container":
|
|
10780
10760
|
if (isMultiple) {
|
|
10781
|
-
renderMultipleContainerElement(element, ctx, wrapper);
|
|
10761
|
+
renderMultipleContainerElement(element, ctx, wrapper, pathKey);
|
|
10782
10762
|
} else {
|
|
10783
10763
|
renderSingleContainerElement(element, ctx, wrapper, pathKey);
|
|
10784
10764
|
}
|
|
@@ -10831,7 +10811,7 @@ function renderElement2(element, ctx) {
|
|
|
10831
10811
|
wrapper.setAttribute("data-fb-width", element.width || "full");
|
|
10832
10812
|
const ops = getComponentOperations(element.type);
|
|
10833
10813
|
if (!(ops == null ? void 0 : ops.ownsLabel)) {
|
|
10834
|
-
const label = createLabelContainer(element);
|
|
10814
|
+
const label = createLabelContainer(element, ctx.state);
|
|
10835
10815
|
wrapper.appendChild(label);
|
|
10836
10816
|
}
|
|
10837
10817
|
const pathKey = pathJoin(ctx.path, element.key);
|
|
@@ -10860,6 +10840,7 @@ var defaultConfig = {
|
|
|
10860
10840
|
onDownloadError: null,
|
|
10861
10841
|
debounceMs: 300,
|
|
10862
10842
|
verboseErrors: false,
|
|
10843
|
+
postMessageTarget: null,
|
|
10863
10844
|
enableFilePreview: true,
|
|
10864
10845
|
maxPreviewSize: "200px",
|
|
10865
10846
|
readonly: false,
|
|
@@ -10881,6 +10862,7 @@ var defaultConfig = {
|
|
|
10881
10862
|
openInNewTab: "Open in new tab",
|
|
10882
10863
|
changeButton: "Change",
|
|
10883
10864
|
placeholderText: "Enter text",
|
|
10865
|
+
selectPlaceholder: "Select\u2026",
|
|
10884
10866
|
previewAlt: "Preview",
|
|
10885
10867
|
previewUnavailable: "Preview unavailable",
|
|
10886
10868
|
previewError: "Preview error",
|
|
@@ -10956,6 +10938,7 @@ var defaultConfig = {
|
|
|
10956
10938
|
openInNewTab: "\u041E\u0442\u043A\u0440\u044B\u0442\u044C \u0432 \u043D\u043E\u0432\u043E\u0439 \u0432\u043A\u043B\u0430\u0434\u043A\u0435",
|
|
10957
10939
|
changeButton: "\u0418\u0437\u043C\u0435\u043D\u0438\u0442\u044C",
|
|
10958
10940
|
placeholderText: "\u0412\u0432\u0435\u0434\u0438\u0442\u0435 \u0442\u0435\u043A\u0441\u0442",
|
|
10941
|
+
selectPlaceholder: "\u0412\u044B\u0431\u0435\u0440\u0438\u0442\u0435\u2026",
|
|
10959
10942
|
previewAlt: "\u041F\u0440\u0435\u0434\u043F\u0440\u043E\u0441\u043C\u043E\u0442\u0440",
|
|
10960
10943
|
previewUnavailable: "\u041F\u0440\u0435\u0434\u043F\u0440\u043E\u0441\u043C\u043E\u0442\u0440 \u043D\u0435\u0434\u043E\u0441\u0442\u0443\u043F\u0435\u043D",
|
|
10961
10944
|
previewError: "\u041E\u0448\u0438\u0431\u043A\u0430 \u043F\u0440\u0435\u0434\u043F\u0440\u043E\u0441\u043C\u043E\u0442\u0440\u0430",
|
|
@@ -11020,20 +11003,23 @@ var defaultConfig = {
|
|
|
11020
11003
|
},
|
|
11021
11004
|
theme: {}
|
|
11022
11005
|
};
|
|
11023
|
-
function
|
|
11024
|
-
const
|
|
11025
|
-
|
|
11026
|
-
|
|
11027
|
-
|
|
11028
|
-
|
|
11029
|
-
config.translations
|
|
11030
|
-
)) {
|
|
11031
|
-
mergedTranslations[locale] = {
|
|
11032
|
-
...defaultConfig.translations[locale] || {},
|
|
11006
|
+
function mergeTranslations(base, overrides) {
|
|
11007
|
+
const merged = { ...base };
|
|
11008
|
+
if (overrides) {
|
|
11009
|
+
for (const [locale, userTranslations] of Object.entries(overrides)) {
|
|
11010
|
+
merged[locale] = {
|
|
11011
|
+
...base[locale] || {},
|
|
11033
11012
|
...userTranslations
|
|
11034
11013
|
};
|
|
11035
11014
|
}
|
|
11036
11015
|
}
|
|
11016
|
+
return merged;
|
|
11017
|
+
}
|
|
11018
|
+
function createInstanceState(config) {
|
|
11019
|
+
const mergedTranslations = mergeTranslations(
|
|
11020
|
+
defaultConfig.translations,
|
|
11021
|
+
config == null ? void 0 : config.translations
|
|
11022
|
+
);
|
|
11037
11023
|
return {
|
|
11038
11024
|
schema: null,
|
|
11039
11025
|
formRoot: null,
|
|
@@ -11049,7 +11035,9 @@ function createInstanceState(config) {
|
|
|
11049
11035
|
prefill: {},
|
|
11050
11036
|
syntheticElementIds: /* @__PURE__ */ new WeakMap(),
|
|
11051
11037
|
syntheticElementIdCounter: 0,
|
|
11052
|
-
enableIfObservers: /* @__PURE__ */ new Set()
|
|
11038
|
+
enableIfObservers: /* @__PURE__ */ new Set(),
|
|
11039
|
+
autoExpandObservers: /* @__PURE__ */ new Set(),
|
|
11040
|
+
tooltipElements: /* @__PURE__ */ new Set()
|
|
11053
11041
|
};
|
|
11054
11042
|
}
|
|
11055
11043
|
function generateInstanceId() {
|
|
@@ -11350,6 +11338,11 @@ function findOwnField(scope, lookupKey, ownBoundary) {
|
|
|
11350
11338
|
}
|
|
11351
11339
|
var FormBuilderInstance = class {
|
|
11352
11340
|
constructor(config) {
|
|
11341
|
+
// The bound prefill-hint click handler currently attached to the form root.
|
|
11342
|
+
// Kept so renderForm()/destroy() can remove it — re-binding on every render
|
|
11343
|
+
// stacked listeners (hint clicks applied values N times) and destroy()
|
|
11344
|
+
// left the last one on the host-owned root, retaining the instance.
|
|
11345
|
+
this.prefillHintHandler = null;
|
|
11353
11346
|
this.instanceId = generateInstanceId();
|
|
11354
11347
|
this.state = createInstanceState(config);
|
|
11355
11348
|
if (this.state.config.verboseErrors) {
|
|
@@ -11383,10 +11376,21 @@ var FormBuilderInstance = class {
|
|
|
11383
11376
|
this.state.formRoot = element;
|
|
11384
11377
|
}
|
|
11385
11378
|
/**
|
|
11386
|
-
* Configure the form builder
|
|
11379
|
+
* Configure the form builder. Translations deep-merge per locale (same as
|
|
11380
|
+
* the constructor); a locale without translations — configured or default —
|
|
11381
|
+
* is rejected, matching setLocale.
|
|
11387
11382
|
*/
|
|
11388
11383
|
configure(config) {
|
|
11389
|
-
|
|
11384
|
+
const translations = mergeTranslations(
|
|
11385
|
+
this.state.config.translations,
|
|
11386
|
+
config.translations
|
|
11387
|
+
);
|
|
11388
|
+
if (config.locale !== void 0 && !translations[config.locale]) {
|
|
11389
|
+
throw new Error(
|
|
11390
|
+
`configure: no translations configured for locale "${config.locale}"`
|
|
11391
|
+
);
|
|
11392
|
+
}
|
|
11393
|
+
Object.assign(this.state.config, config, { translations });
|
|
11390
11394
|
}
|
|
11391
11395
|
/**
|
|
11392
11396
|
* Set file upload handler
|
|
@@ -11419,17 +11423,25 @@ var FormBuilderInstance = class {
|
|
|
11419
11423
|
this.state.config.readonly = mode === "readonly";
|
|
11420
11424
|
}
|
|
11421
11425
|
/**
|
|
11422
|
-
* Set locale
|
|
11426
|
+
* Set locale. Custom locales are allowed — their translations must have
|
|
11427
|
+
* been provided via the constructor or configure() first.
|
|
11423
11428
|
*/
|
|
11424
11429
|
setLocale(locale) {
|
|
11425
|
-
if (this.state.config.translations[locale]) {
|
|
11426
|
-
|
|
11430
|
+
if (!this.state.config.translations[locale]) {
|
|
11431
|
+
throw new Error(
|
|
11432
|
+
`setLocale: no translations configured for locale "${locale}"`
|
|
11433
|
+
);
|
|
11427
11434
|
}
|
|
11435
|
+
this.state.config.locale = locale;
|
|
11428
11436
|
}
|
|
11429
11437
|
/**
|
|
11430
11438
|
* Trigger onChange callbacks with debouncing
|
|
11431
11439
|
* @param fieldPath - Optional field path for field-specific change events
|
|
11432
|
-
* @param fieldValue - Optional field value for field-specific change events
|
|
11440
|
+
* @param fieldValue - Optional field value for field-specific change events.
|
|
11441
|
+
* When omitted while fieldPath is given, the value is read from the
|
|
11442
|
+
* freshly extracted form data at debounce time — used by structural
|
|
11443
|
+
* changes (multi-item add/remove), where the handler has no cheap
|
|
11444
|
+
* current value but the array is trivially derivable after the fact.
|
|
11433
11445
|
*/
|
|
11434
11446
|
triggerOnChange(fieldPath, fieldValue) {
|
|
11435
11447
|
if (this.state.config.readonly) return;
|
|
@@ -11442,12 +11454,49 @@ var FormBuilderInstance = class {
|
|
|
11442
11454
|
if (this.state.config.onChange) {
|
|
11443
11455
|
this.state.config.onChange(formData);
|
|
11444
11456
|
}
|
|
11445
|
-
if (this.state.config.onFieldChange && fieldPath !== void 0
|
|
11446
|
-
this.
|
|
11457
|
+
if (this.state.config.onFieldChange && fieldPath !== void 0) {
|
|
11458
|
+
const resolvedValue = fieldValue !== void 0 ? fieldValue : this.resolveDomPathValue(formData.data, fieldPath);
|
|
11459
|
+
this.state.config.onFieldChange(fieldPath, resolvedValue, formData);
|
|
11447
11460
|
}
|
|
11448
11461
|
this.state.debounceTimer = null;
|
|
11449
11462
|
}, this.state.config.debounceMs);
|
|
11450
11463
|
}
|
|
11464
|
+
/**
|
|
11465
|
+
* Resolve a DOM field path against the extracted form data.
|
|
11466
|
+
*
|
|
11467
|
+
* A plain getValueByPath is wrong for paths inside a multiple container:
|
|
11468
|
+
* row markers keep gaps after a deletion (`s[2]` may be the first surviving
|
|
11469
|
+
* row) while the extracted array is re-packed contiguously — the naive
|
|
11470
|
+
* lookup would read a different row, or nothing. Each `[N]` segment is
|
|
11471
|
+
* mapped from its marker to the row's position among the container's
|
|
11472
|
+
* rendered rows, the same DOM order extraction used to build the array.
|
|
11473
|
+
* A bracketed segment that is not a container marker (a multi-value leaf
|
|
11474
|
+
* like `tags[1]`, whose indices are contiguous) falls back to the index.
|
|
11475
|
+
*/
|
|
11476
|
+
resolveDomPathValue(data, domPath) {
|
|
11477
|
+
let cur = data;
|
|
11478
|
+
let domPrefix = "";
|
|
11479
|
+
for (const seg of domPath.split(".")) {
|
|
11480
|
+
if (cur === null || cur === void 0) return void 0;
|
|
11481
|
+
const marker = seg.match(/^(.+)\[(\d+)\]$/);
|
|
11482
|
+
if (!marker) {
|
|
11483
|
+
domPrefix = domPrefix ? `${domPrefix}.${seg}` : seg;
|
|
11484
|
+
cur = cur[seg];
|
|
11485
|
+
continue;
|
|
11486
|
+
}
|
|
11487
|
+
const key = marker[1];
|
|
11488
|
+
domPrefix = domPrefix ? `${domPrefix}.${key}` : key;
|
|
11489
|
+
const arr = cur[key];
|
|
11490
|
+
if (!Array.isArray(arr)) return void 0;
|
|
11491
|
+
const rows = this.state.formRoot ? findDirectContainerRows(this.state.formRoot, domPrefix) : [];
|
|
11492
|
+
domPrefix = `${domPrefix}[${marker[2]}]`;
|
|
11493
|
+
const pos = rows.findIndex(
|
|
11494
|
+
(row) => row.getAttribute("data-container-item") === domPrefix
|
|
11495
|
+
);
|
|
11496
|
+
cur = pos >= 0 ? arr[pos] : arr[parseInt(marker[2], 10)];
|
|
11497
|
+
}
|
|
11498
|
+
return cur;
|
|
11499
|
+
}
|
|
11451
11500
|
/**
|
|
11452
11501
|
* Register an external action that will be displayed as a button
|
|
11453
11502
|
* External actions can be form-level (no related_field) or field-level (with related_field)
|
|
@@ -11487,21 +11536,10 @@ var FormBuilderInstance = class {
|
|
|
11487
11536
|
*/
|
|
11488
11537
|
findFormElementByFieldPath(fieldPath) {
|
|
11489
11538
|
if (!this.state.formRoot) return null;
|
|
11490
|
-
|
|
11539
|
+
const element = this.state.formRoot.querySelector(
|
|
11491
11540
|
`[name="${fieldPath}"]`
|
|
11492
11541
|
);
|
|
11493
11542
|
if (element) return element;
|
|
11494
|
-
const variations = [
|
|
11495
|
-
fieldPath,
|
|
11496
|
-
fieldPath.replace(/\[(\d+)\]/g, "[$1]"),
|
|
11497
|
-
fieldPath.replace(/\./g, "[") + "]".repeat((fieldPath.match(/\./g) || []).length)
|
|
11498
|
-
];
|
|
11499
|
-
for (const variation of variations) {
|
|
11500
|
-
element = this.state.formRoot.querySelector(
|
|
11501
|
-
`[name="${variation}"]`
|
|
11502
|
-
);
|
|
11503
|
-
if (element) return element;
|
|
11504
|
-
}
|
|
11505
11543
|
const schemaElement = this.findSchemaElement(fieldPath);
|
|
11506
11544
|
if (!schemaElement) return null;
|
|
11507
11545
|
const fieldWrappers = this.state.formRoot.querySelectorAll(".fb-field-wrapper");
|
|
@@ -11747,10 +11785,13 @@ var FormBuilderInstance = class {
|
|
|
11747
11785
|
renderForm(root, schema, prefill, actions) {
|
|
11748
11786
|
const errors = validateSchema(schema);
|
|
11749
11787
|
if (errors.length > 0) {
|
|
11750
|
-
|
|
11751
|
-
|
|
11788
|
+
throw new Error(`renderForm: invalid schema:
|
|
11789
|
+
- ${errors.join("\n- ")}`);
|
|
11752
11790
|
}
|
|
11753
11791
|
this.disconnectEnableIfObservers();
|
|
11792
|
+
this.disconnectAutoExpandObservers();
|
|
11793
|
+
this.removeTooltipElements();
|
|
11794
|
+
this.removePrefillHintListener();
|
|
11754
11795
|
this.state.formRoot = root;
|
|
11755
11796
|
this.state.schema = schema;
|
|
11756
11797
|
this.state.externalActions = actions || null;
|
|
@@ -11772,9 +11813,9 @@ var FormBuilderInstance = class {
|
|
|
11772
11813
|
fieldsWrapper.className = `grid grid-cols-${columns} gap-2`;
|
|
11773
11814
|
}
|
|
11774
11815
|
schema.elements.forEach((element) => {
|
|
11775
|
-
var _a
|
|
11816
|
+
var _a;
|
|
11776
11817
|
if (element.type !== "markdown" && (element.hidden || element.type === "hidden")) {
|
|
11777
|
-
const val =
|
|
11818
|
+
const val = prefill && element.key in prefill ? prefill[element.key] : (_a = element.default) != null ? _a : null;
|
|
11778
11819
|
fieldsWrapper.appendChild(createHiddenInput(element.key, val));
|
|
11779
11820
|
return;
|
|
11780
11821
|
}
|
|
@@ -11791,7 +11832,10 @@ var FormBuilderInstance = class {
|
|
|
11791
11832
|
rootContainer.appendChild(fieldsWrapper);
|
|
11792
11833
|
root.appendChild(rootContainer);
|
|
11793
11834
|
if (!this.state.config.readonly) {
|
|
11794
|
-
|
|
11835
|
+
this.prefillHintHandler = this.handlePrefillHintClick.bind(
|
|
11836
|
+
this
|
|
11837
|
+
);
|
|
11838
|
+
root.addEventListener("click", this.prefillHintHandler);
|
|
11795
11839
|
}
|
|
11796
11840
|
if (this.state.config.readonly && this.state.externalActions && Array.isArray(this.state.externalActions)) {
|
|
11797
11841
|
this.renderExternalActions();
|
|
@@ -11807,7 +11851,7 @@ var FormBuilderInstance = class {
|
|
|
11807
11851
|
return { valid: true, errors: [], data: {} };
|
|
11808
11852
|
const errors = [];
|
|
11809
11853
|
const data = {};
|
|
11810
|
-
const
|
|
11854
|
+
const validateElement = (element, ctx, customScopeRoot = null) => {
|
|
11811
11855
|
var _a;
|
|
11812
11856
|
const key = (_a = element.key) != null ? _a : "";
|
|
11813
11857
|
const scopeRoot = customScopeRoot || this.state.formRoot;
|
|
@@ -11816,7 +11860,10 @@ var FormBuilderInstance = class {
|
|
|
11816
11860
|
state: this.state,
|
|
11817
11861
|
instance: this,
|
|
11818
11862
|
path: ctx.path,
|
|
11819
|
-
skipValidation
|
|
11863
|
+
skipValidation,
|
|
11864
|
+
// Containers recurse into their children through this — threaded per
|
|
11865
|
+
// pass, never module state (see ComponentContext.validateElement).
|
|
11866
|
+
validateElement
|
|
11820
11867
|
};
|
|
11821
11868
|
const componentResult = validateElementWithComponent(
|
|
11822
11869
|
element,
|
|
@@ -11834,9 +11881,7 @@ var FormBuilderInstance = class {
|
|
|
11834
11881
|
console.warn(`Unknown field type "${element.type}" for key "${key}"`);
|
|
11835
11882
|
return { value: null, spread: false };
|
|
11836
11883
|
};
|
|
11837
|
-
setValidateElement(validateElement2);
|
|
11838
11884
|
this.state.schema.elements.forEach((element) => {
|
|
11839
|
-
var _a;
|
|
11840
11885
|
if (element.enableIf) {
|
|
11841
11886
|
try {
|
|
11842
11887
|
const shouldEnable = evaluateEnableCondition(element.enableIf, data);
|
|
@@ -11853,24 +11898,12 @@ var FormBuilderInstance = class {
|
|
|
11853
11898
|
if (element.type === "markdown") {
|
|
11854
11899
|
return;
|
|
11855
11900
|
}
|
|
11856
|
-
|
|
11857
|
-
|
|
11858
|
-
|
|
11859
|
-
);
|
|
11860
|
-
|
|
11861
|
-
|
|
11862
|
-
data[element.key] = deserializeHiddenValue(raw);
|
|
11863
|
-
} else {
|
|
11864
|
-
data[element.key] = element.default !== void 0 ? element.default : null;
|
|
11865
|
-
}
|
|
11866
|
-
} else {
|
|
11867
|
-
const result = validateElement2(element, { path: "" });
|
|
11868
|
-
if (result.skip) return;
|
|
11869
|
-
if (result.spread && result.value !== null && typeof result.value === "object") {
|
|
11870
|
-
Object.assign(data, result.value);
|
|
11871
|
-
} else if (element.key) {
|
|
11872
|
-
data[element.key] = result.value;
|
|
11873
|
-
}
|
|
11901
|
+
const result = validateElement(element, { path: "" });
|
|
11902
|
+
if (result.skip) return;
|
|
11903
|
+
if (result.spread && result.value !== null && typeof result.value === "object") {
|
|
11904
|
+
Object.assign(data, result.value);
|
|
11905
|
+
} else if (element.key) {
|
|
11906
|
+
data[element.key] = result.value;
|
|
11874
11907
|
}
|
|
11875
11908
|
});
|
|
11876
11909
|
return {
|
|
@@ -11891,16 +11924,7 @@ var FormBuilderInstance = class {
|
|
|
11891
11924
|
submitForm() {
|
|
11892
11925
|
const result = this.validateForm(false);
|
|
11893
11926
|
if (result.valid) {
|
|
11894
|
-
|
|
11895
|
-
window.parent.postMessage(
|
|
11896
|
-
{
|
|
11897
|
-
type: "formSubmit",
|
|
11898
|
-
data: result.data,
|
|
11899
|
-
schema: this.state.schema
|
|
11900
|
-
},
|
|
11901
|
-
"*"
|
|
11902
|
-
);
|
|
11903
|
-
}
|
|
11927
|
+
this.postToParent("formSubmit", result.data);
|
|
11904
11928
|
}
|
|
11905
11929
|
return result;
|
|
11906
11930
|
}
|
|
@@ -11909,17 +11933,27 @@ var FormBuilderInstance = class {
|
|
|
11909
11933
|
*/
|
|
11910
11934
|
saveDraft() {
|
|
11911
11935
|
const result = this.validateForm(true);
|
|
11912
|
-
|
|
11913
|
-
|
|
11914
|
-
|
|
11915
|
-
|
|
11916
|
-
|
|
11917
|
-
|
|
11918
|
-
|
|
11919
|
-
|
|
11936
|
+
this.postToParent("formDraft", result.data);
|
|
11937
|
+
return result;
|
|
11938
|
+
}
|
|
11939
|
+
/**
|
|
11940
|
+
* Post form data to the parent frame — only when the host opted in via
|
|
11941
|
+
* `postMessageTarget`. Outside an iframe `window.parent === window`, so an
|
|
11942
|
+
* unconditional post broadcast form data and the full schema to any
|
|
11943
|
+
* embedding page (targetOrigin "*") on every submit. See CHANGELOG 0.6.0.
|
|
11944
|
+
*/
|
|
11945
|
+
postToParent(type, data) {
|
|
11946
|
+
const target = this.state.config.postMessageTarget;
|
|
11947
|
+
if (target === "") {
|
|
11948
|
+
throw new Error(
|
|
11949
|
+
'postMessageTarget: "" is not a valid target origin \u2014 use null to disable posting or "*" to knowingly broadcast'
|
|
11920
11950
|
);
|
|
11921
11951
|
}
|
|
11922
|
-
return
|
|
11952
|
+
if (!target || typeof window === "undefined" || !window.parent) return;
|
|
11953
|
+
window.parent.postMessage(
|
|
11954
|
+
{ type, data, schema: this.state.schema },
|
|
11955
|
+
target
|
|
11956
|
+
);
|
|
11923
11957
|
}
|
|
11924
11958
|
/**
|
|
11925
11959
|
* Clear the form - reset all field values to empty while preserving form structure
|
|
@@ -12193,6 +12227,9 @@ var FormBuilderInstance = class {
|
|
|
12193
12227
|
this.state.debounceTimer = null;
|
|
12194
12228
|
}
|
|
12195
12229
|
this.disconnectEnableIfObservers();
|
|
12230
|
+
this.disconnectAutoExpandObservers();
|
|
12231
|
+
this.removeTooltipElements();
|
|
12232
|
+
this.removePrefillHintListener();
|
|
12196
12233
|
this.state.resourceIndex.clear();
|
|
12197
12234
|
if (this.state.formRoot) {
|
|
12198
12235
|
clear(this.state.formRoot);
|
|
@@ -12210,6 +12247,24 @@ var FormBuilderInstance = class {
|
|
|
12210
12247
|
}
|
|
12211
12248
|
this.state.enableIfObservers.clear();
|
|
12212
12249
|
}
|
|
12250
|
+
disconnectAutoExpandObservers() {
|
|
12251
|
+
for (const observer of this.state.autoExpandObservers) {
|
|
12252
|
+
observer.disconnect();
|
|
12253
|
+
}
|
|
12254
|
+
this.state.autoExpandObservers.clear();
|
|
12255
|
+
}
|
|
12256
|
+
removePrefillHintListener() {
|
|
12257
|
+
if (this.prefillHintHandler && this.state.formRoot) {
|
|
12258
|
+
this.state.formRoot.removeEventListener("click", this.prefillHintHandler);
|
|
12259
|
+
}
|
|
12260
|
+
this.prefillHintHandler = null;
|
|
12261
|
+
}
|
|
12262
|
+
removeTooltipElements() {
|
|
12263
|
+
for (const tooltip of this.state.tooltipElements) {
|
|
12264
|
+
tooltip.remove();
|
|
12265
|
+
}
|
|
12266
|
+
this.state.tooltipElements.clear();
|
|
12267
|
+
}
|
|
12213
12268
|
};
|
|
12214
12269
|
|
|
12215
12270
|
// src/index.ts
|