@dmitryvim/form-builder 0.2.22 → 0.2.24
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/browser/formbuilder.min.js +120 -116
- package/dist/browser/formbuilder.v0.2.24.min.js +606 -0
- package/dist/cjs/index.cjs +524 -58
- package/dist/cjs/index.cjs.map +1 -1
- package/dist/esm/index.js +504 -55
- package/dist/esm/index.js.map +1 -1
- package/dist/form-builder.js +120 -116
- package/dist/types/components/container.d.ts +4 -1
- package/dist/types/components/file.d.ts +5 -0
- package/dist/types/instance/FormBuilderInstance.d.ts +5 -0
- package/dist/types/types/component-operations.d.ts +2 -0
- package/dist/types/types/config.d.ts +3 -0
- package/dist/types/types/schema.d.ts +9 -1
- package/dist/types/types/state.d.ts +1 -0
- package/dist/types/utils/helpers.d.ts +14 -0
- package/package.json +1 -1
- package/dist/browser/formbuilder.v0.2.22.min.js +0 -602
package/dist/cjs/index.cjs
CHANGED
|
@@ -122,6 +122,49 @@ function validateSchema(schema) {
|
|
|
122
122
|
});
|
|
123
123
|
}
|
|
124
124
|
}
|
|
125
|
+
function checkFlatOutputCollisions(elements, scopePath) {
|
|
126
|
+
var _a, _b;
|
|
127
|
+
const allOutputKeys = /* @__PURE__ */ new Set();
|
|
128
|
+
for (const el of elements) {
|
|
129
|
+
if (el.type === "richinput" && el.flatOutput) {
|
|
130
|
+
const richEl = el;
|
|
131
|
+
const textKey = (_a = richEl.textKey) != null ? _a : "text";
|
|
132
|
+
const filesKey = (_b = richEl.filesKey) != null ? _b : "files";
|
|
133
|
+
for (const otherEl of elements) {
|
|
134
|
+
if (otherEl === el) continue;
|
|
135
|
+
if (otherEl.key === textKey) {
|
|
136
|
+
errors.push(
|
|
137
|
+
`${scopePath}: RichInput "${el.key}" flatOutput textKey "${textKey}" collides with element key "${otherEl.key}"`
|
|
138
|
+
);
|
|
139
|
+
}
|
|
140
|
+
if (otherEl.key === filesKey) {
|
|
141
|
+
errors.push(
|
|
142
|
+
`${scopePath}: RichInput "${el.key}" flatOutput filesKey "${filesKey}" collides with element key "${otherEl.key}"`
|
|
143
|
+
);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
if (allOutputKeys.has(textKey)) {
|
|
147
|
+
errors.push(
|
|
148
|
+
`${scopePath}: RichInput "${el.key}" flatOutput textKey "${textKey}" collides with another flatOutput key`
|
|
149
|
+
);
|
|
150
|
+
}
|
|
151
|
+
if (allOutputKeys.has(filesKey)) {
|
|
152
|
+
errors.push(
|
|
153
|
+
`${scopePath}: RichInput "${el.key}" flatOutput filesKey "${filesKey}" collides with another flatOutput key`
|
|
154
|
+
);
|
|
155
|
+
}
|
|
156
|
+
allOutputKeys.add(textKey);
|
|
157
|
+
allOutputKeys.add(filesKey);
|
|
158
|
+
} else {
|
|
159
|
+
if (allOutputKeys.has(el.key)) {
|
|
160
|
+
errors.push(
|
|
161
|
+
`${scopePath}: Element key "${el.key}" collides with a flatOutput richinput key`
|
|
162
|
+
);
|
|
163
|
+
}
|
|
164
|
+
allOutputKeys.add(el.key);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
}
|
|
125
168
|
function validateElements(elements, path) {
|
|
126
169
|
elements.forEach((element, index) => {
|
|
127
170
|
const elementPath = `${path}[${index}]`;
|
|
@@ -187,6 +230,7 @@ function validateSchema(schema) {
|
|
|
187
230
|
}
|
|
188
231
|
}
|
|
189
232
|
validateElements(element.elements, `${elementPath}.elements`);
|
|
233
|
+
checkFlatOutputCollisions(element.elements, `${elementPath}.elements`);
|
|
190
234
|
}
|
|
191
235
|
if (element.type === "select" && element.options) {
|
|
192
236
|
const defaultValue = element.default;
|
|
@@ -203,8 +247,10 @@ function validateSchema(schema) {
|
|
|
203
247
|
}
|
|
204
248
|
});
|
|
205
249
|
}
|
|
206
|
-
if (Array.isArray(schema.elements))
|
|
250
|
+
if (Array.isArray(schema.elements)) {
|
|
207
251
|
validateElements(schema.elements, "elements");
|
|
252
|
+
checkFlatOutputCollisions(schema.elements, "elements");
|
|
253
|
+
}
|
|
208
254
|
return errors;
|
|
209
255
|
}
|
|
210
256
|
|
|
@@ -228,6 +274,26 @@ function formatFileSize(bytes) {
|
|
|
228
274
|
if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
|
|
229
275
|
return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
|
|
230
276
|
}
|
|
277
|
+
function serializeHiddenValue(value) {
|
|
278
|
+
if (value === null || value === void 0) return "";
|
|
279
|
+
return typeof value === "object" ? JSON.stringify(value) : String(value);
|
|
280
|
+
}
|
|
281
|
+
function deserializeHiddenValue(raw) {
|
|
282
|
+
if (raw === "") return null;
|
|
283
|
+
try {
|
|
284
|
+
return JSON.parse(raw);
|
|
285
|
+
} catch {
|
|
286
|
+
return raw;
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
function createHiddenInput(name, value) {
|
|
290
|
+
const input = document.createElement("input");
|
|
291
|
+
input.type = "hidden";
|
|
292
|
+
input.name = name;
|
|
293
|
+
input.setAttribute("data-hidden-field", "true");
|
|
294
|
+
input.value = serializeHiddenValue(value);
|
|
295
|
+
return input;
|
|
296
|
+
}
|
|
231
297
|
|
|
232
298
|
// src/utils/enable-conditions.ts
|
|
233
299
|
function getValueByPath(data, path) {
|
|
@@ -2036,6 +2102,26 @@ function updateSwitcherField(element, fieldPath, value, context) {
|
|
|
2036
2102
|
}
|
|
2037
2103
|
|
|
2038
2104
|
// src/components/file.ts
|
|
2105
|
+
function getAllowedExtensions(accept) {
|
|
2106
|
+
if (!accept) return [];
|
|
2107
|
+
if (typeof accept === "object" && Array.isArray(accept.extensions)) {
|
|
2108
|
+
return accept.extensions.map((ext) => ext.toLowerCase());
|
|
2109
|
+
}
|
|
2110
|
+
if (typeof accept === "string") {
|
|
2111
|
+
return accept.split(",").map((s) => s.trim()).filter((s) => s.startsWith(".")).map((s) => s.substring(1).toLowerCase());
|
|
2112
|
+
}
|
|
2113
|
+
return [];
|
|
2114
|
+
}
|
|
2115
|
+
function isFileExtensionAllowed(fileName, allowedExtensions) {
|
|
2116
|
+
var _a;
|
|
2117
|
+
if (allowedExtensions.length === 0) return true;
|
|
2118
|
+
const ext = ((_a = fileName.split(".").pop()) == null ? void 0 : _a.toLowerCase()) || "";
|
|
2119
|
+
return allowedExtensions.includes(ext);
|
|
2120
|
+
}
|
|
2121
|
+
function isFileSizeAllowed(file, maxSizeMB) {
|
|
2122
|
+
if (maxSizeMB === Infinity) return true;
|
|
2123
|
+
return file.size <= maxSizeMB * 1024 * 1024;
|
|
2124
|
+
}
|
|
2039
2125
|
function renderLocalImagePreview(container, file, fileName, state) {
|
|
2040
2126
|
const img = document.createElement("img");
|
|
2041
2127
|
img.className = "w-full h-full object-contain";
|
|
@@ -2571,8 +2657,43 @@ function setEmptyFileContainer(fileContainer, state, hint) {
|
|
|
2571
2657
|
</div>
|
|
2572
2658
|
`;
|
|
2573
2659
|
}
|
|
2574
|
-
|
|
2660
|
+
function showFileError(container, message) {
|
|
2575
2661
|
var _a, _b;
|
|
2662
|
+
const existing = (_a = container.closest(".space-y-2")) == null ? void 0 : _a.querySelector(".file-error-message");
|
|
2663
|
+
if (existing) existing.remove();
|
|
2664
|
+
const errorEl = document.createElement("div");
|
|
2665
|
+
errorEl.className = "file-error-message error-message";
|
|
2666
|
+
errorEl.style.cssText = `
|
|
2667
|
+
color: var(--fb-error-color);
|
|
2668
|
+
font-size: var(--fb-font-size-small);
|
|
2669
|
+
margin-top: 0.25rem;
|
|
2670
|
+
`;
|
|
2671
|
+
errorEl.textContent = message;
|
|
2672
|
+
(_b = container.closest(".space-y-2")) == null ? void 0 : _b.appendChild(errorEl);
|
|
2673
|
+
}
|
|
2674
|
+
function clearFileError(container) {
|
|
2675
|
+
var _a;
|
|
2676
|
+
const existing = (_a = container.closest(".space-y-2")) == null ? void 0 : _a.querySelector(".file-error-message");
|
|
2677
|
+
if (existing) existing.remove();
|
|
2678
|
+
}
|
|
2679
|
+
async function handleFileSelect(file, container, fieldName, state, deps = null, instance, allowedExtensions = [], maxSizeMB = Infinity) {
|
|
2680
|
+
var _a, _b;
|
|
2681
|
+
if (!isFileExtensionAllowed(file.name, allowedExtensions)) {
|
|
2682
|
+
const formats = allowedExtensions.join(", ");
|
|
2683
|
+
showFileError(
|
|
2684
|
+
container,
|
|
2685
|
+
t("invalidFileExtension", state, { name: file.name, formats })
|
|
2686
|
+
);
|
|
2687
|
+
return;
|
|
2688
|
+
}
|
|
2689
|
+
if (!isFileSizeAllowed(file, maxSizeMB)) {
|
|
2690
|
+
showFileError(
|
|
2691
|
+
container,
|
|
2692
|
+
t("fileTooLarge", state, { name: file.name, maxSize: maxSizeMB })
|
|
2693
|
+
);
|
|
2694
|
+
return;
|
|
2695
|
+
}
|
|
2696
|
+
clearFileError(container);
|
|
2576
2697
|
let rid;
|
|
2577
2698
|
if (state.config.uploadFile) {
|
|
2578
2699
|
try {
|
|
@@ -2778,9 +2899,51 @@ function handleInitialFileData(initial, fileContainer, pathKey, fileWrapper, sta
|
|
|
2778
2899
|
hiddenInput.value = initial;
|
|
2779
2900
|
fileWrapper.appendChild(hiddenInput);
|
|
2780
2901
|
}
|
|
2781
|
-
function setupFilesDropHandler(filesContainer, initialFiles, state, updateCallback, pathKey, instance) {
|
|
2902
|
+
function setupFilesDropHandler(filesContainer, initialFiles, state, updateCallback, constraints, pathKey, instance) {
|
|
2782
2903
|
setupDragAndDrop(filesContainer, async (files) => {
|
|
2783
|
-
const
|
|
2904
|
+
const allFiles = Array.from(files);
|
|
2905
|
+
const rejectedByExtension = allFiles.filter(
|
|
2906
|
+
(f) => !isFileExtensionAllowed(f.name, constraints.allowedExtensions)
|
|
2907
|
+
);
|
|
2908
|
+
const afterExtension = allFiles.filter(
|
|
2909
|
+
(f) => isFileExtensionAllowed(f.name, constraints.allowedExtensions)
|
|
2910
|
+
);
|
|
2911
|
+
const rejectedBySize = afterExtension.filter(
|
|
2912
|
+
(f) => !isFileSizeAllowed(f, constraints.maxSize)
|
|
2913
|
+
);
|
|
2914
|
+
const validFiles = afterExtension.filter(
|
|
2915
|
+
(f) => isFileSizeAllowed(f, constraints.maxSize)
|
|
2916
|
+
);
|
|
2917
|
+
const remaining = constraints.maxCount === Infinity ? validFiles.length : Math.max(0, constraints.maxCount - initialFiles.length);
|
|
2918
|
+
const arr = validFiles.slice(0, remaining);
|
|
2919
|
+
const skippedByCount = validFiles.length - arr.length;
|
|
2920
|
+
const errorParts = [];
|
|
2921
|
+
if (rejectedByExtension.length > 0) {
|
|
2922
|
+
const formats = constraints.allowedExtensions.join(", ");
|
|
2923
|
+
const names = rejectedByExtension.map((f) => f.name).join(", ");
|
|
2924
|
+
errorParts.push(
|
|
2925
|
+
t("invalidFileExtension", state, { name: names, formats })
|
|
2926
|
+
);
|
|
2927
|
+
}
|
|
2928
|
+
if (rejectedBySize.length > 0) {
|
|
2929
|
+
const names = rejectedBySize.map((f) => f.name).join(", ");
|
|
2930
|
+
errorParts.push(
|
|
2931
|
+
t("fileTooLarge", state, { name: names, maxSize: constraints.maxSize })
|
|
2932
|
+
);
|
|
2933
|
+
}
|
|
2934
|
+
if (skippedByCount > 0) {
|
|
2935
|
+
errorParts.push(
|
|
2936
|
+
t("filesLimitExceeded", state, {
|
|
2937
|
+
skipped: skippedByCount,
|
|
2938
|
+
max: constraints.maxCount
|
|
2939
|
+
})
|
|
2940
|
+
);
|
|
2941
|
+
}
|
|
2942
|
+
if (errorParts.length > 0) {
|
|
2943
|
+
showFileError(filesContainer, errorParts.join(" \u2022 "));
|
|
2944
|
+
} else {
|
|
2945
|
+
clearFileError(filesContainer);
|
|
2946
|
+
}
|
|
2784
2947
|
for (const file of arr) {
|
|
2785
2948
|
const rid = await uploadSingleFile(file, state);
|
|
2786
2949
|
state.resourceIndex.set(rid, {
|
|
@@ -2798,10 +2961,57 @@ function setupFilesDropHandler(filesContainer, initialFiles, state, updateCallba
|
|
|
2798
2961
|
}
|
|
2799
2962
|
});
|
|
2800
2963
|
}
|
|
2801
|
-
function setupFilesPickerHandler(filesPicker, initialFiles, state, updateCallback, pathKey, instance) {
|
|
2964
|
+
function setupFilesPickerHandler(filesPicker, initialFiles, state, updateCallback, constraints, pathKey, instance) {
|
|
2802
2965
|
filesPicker.onchange = async () => {
|
|
2803
2966
|
if (filesPicker.files) {
|
|
2804
|
-
|
|
2967
|
+
const allFiles = Array.from(filesPicker.files);
|
|
2968
|
+
const rejectedByExtension = allFiles.filter(
|
|
2969
|
+
(f) => !isFileExtensionAllowed(f.name, constraints.allowedExtensions)
|
|
2970
|
+
);
|
|
2971
|
+
const afterExtension = allFiles.filter(
|
|
2972
|
+
(f) => isFileExtensionAllowed(f.name, constraints.allowedExtensions)
|
|
2973
|
+
);
|
|
2974
|
+
const rejectedBySize = afterExtension.filter(
|
|
2975
|
+
(f) => !isFileSizeAllowed(f, constraints.maxSize)
|
|
2976
|
+
);
|
|
2977
|
+
const validFiles = afterExtension.filter(
|
|
2978
|
+
(f) => isFileSizeAllowed(f, constraints.maxSize)
|
|
2979
|
+
);
|
|
2980
|
+
const remaining = constraints.maxCount === Infinity ? validFiles.length : Math.max(0, constraints.maxCount - initialFiles.length);
|
|
2981
|
+
const arr = validFiles.slice(0, remaining);
|
|
2982
|
+
const skippedByCount = validFiles.length - arr.length;
|
|
2983
|
+
const errorParts = [];
|
|
2984
|
+
if (rejectedByExtension.length > 0) {
|
|
2985
|
+
const formats = constraints.allowedExtensions.join(", ");
|
|
2986
|
+
const names = rejectedByExtension.map((f) => f.name).join(", ");
|
|
2987
|
+
errorParts.push(
|
|
2988
|
+
t("invalidFileExtension", state, { name: names, formats })
|
|
2989
|
+
);
|
|
2990
|
+
}
|
|
2991
|
+
if (rejectedBySize.length > 0) {
|
|
2992
|
+
const names = rejectedBySize.map((f) => f.name).join(", ");
|
|
2993
|
+
errorParts.push(
|
|
2994
|
+
t("fileTooLarge", state, {
|
|
2995
|
+
name: names,
|
|
2996
|
+
maxSize: constraints.maxSize
|
|
2997
|
+
})
|
|
2998
|
+
);
|
|
2999
|
+
}
|
|
3000
|
+
if (skippedByCount > 0) {
|
|
3001
|
+
errorParts.push(
|
|
3002
|
+
t("filesLimitExceeded", state, {
|
|
3003
|
+
skipped: skippedByCount,
|
|
3004
|
+
max: constraints.maxCount
|
|
3005
|
+
})
|
|
3006
|
+
);
|
|
3007
|
+
}
|
|
3008
|
+
const wrapper = filesPicker.closest(".space-y-2") || filesPicker.parentElement;
|
|
3009
|
+
if (errorParts.length > 0 && wrapper) {
|
|
3010
|
+
showFileError(wrapper, errorParts.join(" \u2022 "));
|
|
3011
|
+
} else if (wrapper) {
|
|
3012
|
+
clearFileError(wrapper);
|
|
3013
|
+
}
|
|
3014
|
+
for (const file of arr) {
|
|
2805
3015
|
const rid = await uploadSingleFile(file, state);
|
|
2806
3016
|
state.resourceIndex.set(rid, {
|
|
2807
3017
|
name: file.name,
|
|
@@ -2821,7 +3031,7 @@ function setupFilesPickerHandler(filesPicker, initialFiles, state, updateCallbac
|
|
|
2821
3031
|
};
|
|
2822
3032
|
}
|
|
2823
3033
|
function renderFileElement(element, ctx, wrapper, pathKey) {
|
|
2824
|
-
var _a;
|
|
3034
|
+
var _a, _b;
|
|
2825
3035
|
const state = ctx.state;
|
|
2826
3036
|
if (state.config.readonly) {
|
|
2827
3037
|
const initial = ctx.prefill[element.key];
|
|
@@ -2854,6 +3064,8 @@ function renderFileElement(element, ctx, wrapper, pathKey) {
|
|
|
2854
3064
|
const fileContainer = document.createElement("div");
|
|
2855
3065
|
fileContainer.className = "file-preview-container w-full aspect-square max-w-xs bg-gray-100 rounded-lg overflow-hidden relative group cursor-pointer";
|
|
2856
3066
|
const initial = ctx.prefill[element.key];
|
|
3067
|
+
const allowedExts = getAllowedExtensions(element.accept);
|
|
3068
|
+
const maxSizeMB = (_b = element.maxSize) != null ? _b : Infinity;
|
|
2857
3069
|
const fileUploadHandler = () => picker.click();
|
|
2858
3070
|
const dragHandler = (files) => {
|
|
2859
3071
|
if (files.length > 0) {
|
|
@@ -2864,7 +3076,9 @@ function renderFileElement(element, ctx, wrapper, pathKey) {
|
|
|
2864
3076
|
pathKey,
|
|
2865
3077
|
state,
|
|
2866
3078
|
deps,
|
|
2867
|
-
ctx.instance
|
|
3079
|
+
ctx.instance,
|
|
3080
|
+
allowedExts,
|
|
3081
|
+
maxSizeMB
|
|
2868
3082
|
);
|
|
2869
3083
|
}
|
|
2870
3084
|
};
|
|
@@ -2896,7 +3110,9 @@ function renderFileElement(element, ctx, wrapper, pathKey) {
|
|
|
2896
3110
|
pathKey,
|
|
2897
3111
|
state,
|
|
2898
3112
|
deps,
|
|
2899
|
-
ctx.instance
|
|
3113
|
+
ctx.instance,
|
|
3114
|
+
allowedExts,
|
|
3115
|
+
maxSizeMB
|
|
2900
3116
|
);
|
|
2901
3117
|
}
|
|
2902
3118
|
};
|
|
@@ -2906,7 +3122,7 @@ function renderFileElement(element, ctx, wrapper, pathKey) {
|
|
|
2906
3122
|
}
|
|
2907
3123
|
}
|
|
2908
3124
|
function renderFilesElement(element, ctx, wrapper, pathKey) {
|
|
2909
|
-
var _a;
|
|
3125
|
+
var _a, _b;
|
|
2910
3126
|
const state = ctx.state;
|
|
2911
3127
|
if (state.config.readonly) {
|
|
2912
3128
|
const resultsWrapper = document.createElement("div");
|
|
@@ -2957,12 +3173,18 @@ function renderFilesElement(element, ctx, wrapper, pathKey) {
|
|
|
2957
3173
|
const initialFiles = ctx.prefill[element.key] || [];
|
|
2958
3174
|
addPrefillFilesToIndex(initialFiles, state);
|
|
2959
3175
|
const filesFieldHint = makeFieldHint(element, state);
|
|
3176
|
+
const filesConstraints = {
|
|
3177
|
+
maxCount: Infinity,
|
|
3178
|
+
allowedExtensions: getAllowedExtensions(element.accept),
|
|
3179
|
+
maxSize: (_b = element.maxSize) != null ? _b : Infinity
|
|
3180
|
+
};
|
|
2960
3181
|
updateFilesList2();
|
|
2961
3182
|
setupFilesDropHandler(
|
|
2962
3183
|
filesContainer,
|
|
2963
3184
|
initialFiles,
|
|
2964
3185
|
state,
|
|
2965
3186
|
updateFilesList2,
|
|
3187
|
+
filesConstraints,
|
|
2966
3188
|
pathKey,
|
|
2967
3189
|
ctx.instance
|
|
2968
3190
|
);
|
|
@@ -2971,6 +3193,7 @@ function renderFilesElement(element, ctx, wrapper, pathKey) {
|
|
|
2971
3193
|
initialFiles,
|
|
2972
3194
|
state,
|
|
2973
3195
|
updateFilesList2,
|
|
3196
|
+
filesConstraints,
|
|
2974
3197
|
pathKey,
|
|
2975
3198
|
ctx.instance
|
|
2976
3199
|
);
|
|
@@ -2981,7 +3204,7 @@ function renderFilesElement(element, ctx, wrapper, pathKey) {
|
|
|
2981
3204
|
}
|
|
2982
3205
|
}
|
|
2983
3206
|
function renderMultipleFileElement(element, ctx, wrapper, pathKey) {
|
|
2984
|
-
var _a, _b, _c;
|
|
3207
|
+
var _a, _b, _c, _d;
|
|
2985
3208
|
const state = ctx.state;
|
|
2986
3209
|
const minFiles = (_a = element.minCount) != null ? _a : 0;
|
|
2987
3210
|
const maxFiles = (_b = element.maxCount) != null ? _b : Infinity;
|
|
@@ -3019,6 +3242,11 @@ function renderMultipleFileElement(element, ctx, wrapper, pathKey) {
|
|
|
3019
3242
|
const initialFiles = Array.isArray(ctx.prefill[element.key]) ? [...ctx.prefill[element.key]] : [];
|
|
3020
3243
|
addPrefillFilesToIndex(initialFiles, state);
|
|
3021
3244
|
const multipleFilesHint = makeFieldHint(element, state);
|
|
3245
|
+
const multipleConstraints = {
|
|
3246
|
+
maxCount: maxFiles,
|
|
3247
|
+
allowedExtensions: getAllowedExtensions(element.accept),
|
|
3248
|
+
maxSize: (_d = element.maxSize) != null ? _d : Infinity
|
|
3249
|
+
};
|
|
3022
3250
|
const buildCountInfo = () => {
|
|
3023
3251
|
const countText = initialFiles.length === 1 ? t("fileCountSingle", state, { count: initialFiles.length }) : t("fileCountPlural", state, { count: initialFiles.length });
|
|
3024
3252
|
const minMaxText = minFiles > 0 || maxFiles < Infinity ? ` ${t("fileCountRange", state, { min: minFiles, max: maxFiles })}` : "";
|
|
@@ -3042,6 +3270,7 @@ function renderMultipleFileElement(element, ctx, wrapper, pathKey) {
|
|
|
3042
3270
|
initialFiles,
|
|
3043
3271
|
state,
|
|
3044
3272
|
updateFilesDisplay,
|
|
3273
|
+
multipleConstraints,
|
|
3045
3274
|
pathKey,
|
|
3046
3275
|
ctx.instance
|
|
3047
3276
|
);
|
|
@@ -3050,6 +3279,7 @@ function renderMultipleFileElement(element, ctx, wrapper, pathKey) {
|
|
|
3050
3279
|
initialFiles,
|
|
3051
3280
|
state,
|
|
3052
3281
|
updateFilesDisplay,
|
|
3282
|
+
multipleConstraints,
|
|
3053
3283
|
pathKey,
|
|
3054
3284
|
ctx.instance
|
|
3055
3285
|
);
|
|
@@ -3078,6 +3308,40 @@ function validateFileElement(element, key, context) {
|
|
|
3078
3308
|
errors.push(`${key2}: ${t("maxFiles", state, { max: maxFiles })}`);
|
|
3079
3309
|
}
|
|
3080
3310
|
};
|
|
3311
|
+
const validateFileExtensions = (key2, resourceIds, element2) => {
|
|
3312
|
+
var _a2;
|
|
3313
|
+
if (skipValidation) return;
|
|
3314
|
+
const { state } = context;
|
|
3315
|
+
const acceptField = "accept" in element2 ? element2.accept : void 0;
|
|
3316
|
+
const allowedExtensions = getAllowedExtensions(acceptField);
|
|
3317
|
+
if (allowedExtensions.length === 0) return;
|
|
3318
|
+
const formats = allowedExtensions.join(", ");
|
|
3319
|
+
for (const rid of resourceIds) {
|
|
3320
|
+
const meta = state.resourceIndex.get(rid);
|
|
3321
|
+
const fileName = (_a2 = meta == null ? void 0 : meta.name) != null ? _a2 : rid;
|
|
3322
|
+
if (!isFileExtensionAllowed(fileName, allowedExtensions)) {
|
|
3323
|
+
errors.push(
|
|
3324
|
+
`${key2}: ${t("invalidFileExtension", state, { name: fileName, formats })}`
|
|
3325
|
+
);
|
|
3326
|
+
}
|
|
3327
|
+
}
|
|
3328
|
+
};
|
|
3329
|
+
const validateFileSizes = (key2, resourceIds, element2) => {
|
|
3330
|
+
var _a2;
|
|
3331
|
+
if (skipValidation) return;
|
|
3332
|
+
const { state } = context;
|
|
3333
|
+
const maxSizeMB = "maxSize" in element2 ? (_a2 = element2.maxSize) != null ? _a2 : Infinity : Infinity;
|
|
3334
|
+
if (maxSizeMB === Infinity) return;
|
|
3335
|
+
for (const rid of resourceIds) {
|
|
3336
|
+
const meta = state.resourceIndex.get(rid);
|
|
3337
|
+
if (!meta) continue;
|
|
3338
|
+
if (meta.size > maxSizeMB * 1024 * 1024) {
|
|
3339
|
+
errors.push(
|
|
3340
|
+
`${key2}: ${t("fileTooLarge", state, { name: meta.name, maxSize: maxSizeMB })}`
|
|
3341
|
+
);
|
|
3342
|
+
}
|
|
3343
|
+
}
|
|
3344
|
+
};
|
|
3081
3345
|
if (isMultipleField) {
|
|
3082
3346
|
const fullKey = pathJoin(path, key);
|
|
3083
3347
|
const pickerInput = scopeRoot.querySelector(
|
|
@@ -3096,6 +3360,8 @@ function validateFileElement(element, key, context) {
|
|
|
3096
3360
|
});
|
|
3097
3361
|
}
|
|
3098
3362
|
validateFileCount(key, resourceIds, element);
|
|
3363
|
+
validateFileExtensions(key, resourceIds, element);
|
|
3364
|
+
validateFileSizes(key, resourceIds, element);
|
|
3099
3365
|
return { value: resourceIds, errors };
|
|
3100
3366
|
} else {
|
|
3101
3367
|
const input = scopeRoot.querySelector(
|
|
@@ -3106,6 +3372,10 @@ function validateFileElement(element, key, context) {
|
|
|
3106
3372
|
errors.push(`${key}: ${t("required", context.state)}`);
|
|
3107
3373
|
return { value: null, errors };
|
|
3108
3374
|
}
|
|
3375
|
+
if (!skipValidation && rid !== "") {
|
|
3376
|
+
validateFileExtensions(key, [rid], element);
|
|
3377
|
+
validateFileSizes(key, [rid], element);
|
|
3378
|
+
}
|
|
3109
3379
|
return { value: rid || null, errors };
|
|
3110
3380
|
}
|
|
3111
3381
|
}
|
|
@@ -4306,7 +4576,11 @@ function renderSingleContainerElement(element, ctx, wrapper, pathKey) {
|
|
|
4306
4576
|
state: ctx.state
|
|
4307
4577
|
};
|
|
4308
4578
|
element.elements.forEach((child) => {
|
|
4309
|
-
|
|
4579
|
+
var _a2, _b2;
|
|
4580
|
+
if (child.hidden || child.type === "hidden") {
|
|
4581
|
+
const prefillVal = (_b2 = (_a2 = containerPrefill[child.key]) != null ? _a2 : child.default) != null ? _b2 : null;
|
|
4582
|
+
itemsWrap.appendChild(createHiddenInput(pathJoin(subCtx.path, child.key), prefillVal));
|
|
4583
|
+
} else {
|
|
4310
4584
|
itemsWrap.appendChild(renderElement(child, subCtx));
|
|
4311
4585
|
}
|
|
4312
4586
|
});
|
|
@@ -4374,7 +4648,10 @@ function renderMultipleContainerElement(element, ctx, wrapper, _pathKey) {
|
|
|
4374
4648
|
childWrapper.className = `grid grid-cols-${columns} gap-4`;
|
|
4375
4649
|
}
|
|
4376
4650
|
element.elements.forEach((child) => {
|
|
4377
|
-
|
|
4651
|
+
var _a2;
|
|
4652
|
+
if (child.hidden || child.type === "hidden") {
|
|
4653
|
+
childWrapper.appendChild(createHiddenInput(pathJoin(subCtx.path, child.key), (_a2 = child.default) != null ? _a2 : null));
|
|
4654
|
+
} else {
|
|
4378
4655
|
childWrapper.appendChild(renderElement(child, subCtx));
|
|
4379
4656
|
}
|
|
4380
4657
|
});
|
|
@@ -4444,7 +4721,11 @@ function renderMultipleContainerElement(element, ctx, wrapper, _pathKey) {
|
|
|
4444
4721
|
childWrapper.className = `grid grid-cols-${columns} gap-4`;
|
|
4445
4722
|
}
|
|
4446
4723
|
element.elements.forEach((child) => {
|
|
4447
|
-
|
|
4724
|
+
var _a3, _b2;
|
|
4725
|
+
if (child.hidden || child.type === "hidden") {
|
|
4726
|
+
const prefillVal = (_b2 = (_a3 = prefillObj == null ? void 0 : prefillObj[child.key]) != null ? _a3 : child.default) != null ? _b2 : null;
|
|
4727
|
+
childWrapper.appendChild(createHiddenInput(pathJoin(subCtx.path, child.key), prefillVal));
|
|
4728
|
+
} else {
|
|
4448
4729
|
childWrapper.appendChild(renderElement(child, subCtx));
|
|
4449
4730
|
}
|
|
4450
4731
|
});
|
|
@@ -4494,7 +4775,10 @@ function renderMultipleContainerElement(element, ctx, wrapper, _pathKey) {
|
|
|
4494
4775
|
childWrapper.className = `grid grid-cols-${columns} gap-4`;
|
|
4495
4776
|
}
|
|
4496
4777
|
element.elements.forEach((child) => {
|
|
4497
|
-
|
|
4778
|
+
var _a2;
|
|
4779
|
+
if (child.hidden || child.type === "hidden") {
|
|
4780
|
+
childWrapper.appendChild(createHiddenInput(pathJoin(subCtx.path, child.key), (_a2 = child.default) != null ? _a2 : null));
|
|
4781
|
+
} else {
|
|
4498
4782
|
childWrapper.appendChild(renderElement(child, subCtx));
|
|
4499
4783
|
}
|
|
4500
4784
|
});
|
|
@@ -4607,15 +4891,16 @@ function validateContainerElement(element, key, context) {
|
|
|
4607
4891
|
);
|
|
4608
4892
|
}
|
|
4609
4893
|
}
|
|
4610
|
-
|
|
4611
|
-
|
|
4894
|
+
const childKey = `${key}[${domIndex}].${child.key}`;
|
|
4895
|
+
const childResult = validateElement(
|
|
4896
|
+
{ ...child, key: childKey },
|
|
4897
|
+
{ path },
|
|
4898
|
+
itemContainer
|
|
4899
|
+
);
|
|
4900
|
+
if (childResult.spread && childResult.value !== null && typeof childResult.value === "object") {
|
|
4901
|
+
Object.assign(itemData, childResult.value);
|
|
4612
4902
|
} else {
|
|
4613
|
-
|
|
4614
|
-
itemData[child.key] = validateElement(
|
|
4615
|
-
{ ...child, key: childKey },
|
|
4616
|
-
{ path },
|
|
4617
|
-
itemContainer
|
|
4618
|
-
);
|
|
4903
|
+
itemData[child.key] = childResult.value;
|
|
4619
4904
|
}
|
|
4620
4905
|
});
|
|
4621
4906
|
items.push(itemData);
|
|
@@ -4647,15 +4932,18 @@ function validateContainerElement(element, key, context) {
|
|
|
4647
4932
|
);
|
|
4648
4933
|
}
|
|
4649
4934
|
}
|
|
4650
|
-
|
|
4651
|
-
containerData[child.key] = child.default !== void 0 ? child.default : null;
|
|
4652
|
-
} else {
|
|
4935
|
+
{
|
|
4653
4936
|
const childKey = `${key}.${child.key}`;
|
|
4654
|
-
|
|
4937
|
+
const childResult = validateElement(
|
|
4655
4938
|
{ ...child, key: childKey },
|
|
4656
4939
|
{ path },
|
|
4657
4940
|
containerContainer
|
|
4658
4941
|
);
|
|
4942
|
+
if (childResult.spread && childResult.value !== null && typeof childResult.value === "object") {
|
|
4943
|
+
Object.assign(containerData, childResult.value);
|
|
4944
|
+
} else {
|
|
4945
|
+
containerData[child.key] = childResult.value;
|
|
4946
|
+
}
|
|
4659
4947
|
}
|
|
4660
4948
|
});
|
|
4661
4949
|
return { value: containerData, errors };
|
|
@@ -4676,11 +4964,24 @@ function updateContainerField(element, fieldPath, value, context) {
|
|
|
4676
4964
|
value.forEach((itemValue, index) => {
|
|
4677
4965
|
if (isPlainObject(itemValue)) {
|
|
4678
4966
|
element.elements.forEach((childElement) => {
|
|
4679
|
-
|
|
4680
|
-
const childPath = `${fieldPath}[${index}].${
|
|
4681
|
-
|
|
4682
|
-
|
|
4683
|
-
|
|
4967
|
+
var _a, _b;
|
|
4968
|
+
const childPath = `${fieldPath}[${index}].${childElement.key}`;
|
|
4969
|
+
if (childElement.type === "richinput" && childElement.flatOutput) {
|
|
4970
|
+
const richChild = childElement;
|
|
4971
|
+
const textKey = (_a = richChild.textKey) != null ? _a : "text";
|
|
4972
|
+
const filesKey = (_b = richChild.filesKey) != null ? _b : "files";
|
|
4973
|
+
const containerValue = itemValue;
|
|
4974
|
+
const compositeValue = {};
|
|
4975
|
+
if (textKey in containerValue) compositeValue[textKey] = containerValue[textKey];
|
|
4976
|
+
if (filesKey in containerValue) compositeValue[filesKey] = containerValue[filesKey];
|
|
4977
|
+
if (Object.keys(compositeValue).length > 0) {
|
|
4978
|
+
instance.updateField(childPath, compositeValue);
|
|
4979
|
+
}
|
|
4980
|
+
} else {
|
|
4981
|
+
const childValue = itemValue[childElement.key];
|
|
4982
|
+
if (childValue !== void 0) {
|
|
4983
|
+
instance.updateField(childPath, childValue);
|
|
4984
|
+
}
|
|
4684
4985
|
}
|
|
4685
4986
|
});
|
|
4686
4987
|
}
|
|
@@ -4701,11 +5002,24 @@ function updateContainerField(element, fieldPath, value, context) {
|
|
|
4701
5002
|
return;
|
|
4702
5003
|
}
|
|
4703
5004
|
element.elements.forEach((childElement) => {
|
|
4704
|
-
|
|
4705
|
-
const childPath = `${fieldPath}.${
|
|
4706
|
-
|
|
4707
|
-
|
|
4708
|
-
|
|
5005
|
+
var _a, _b;
|
|
5006
|
+
const childPath = `${fieldPath}.${childElement.key}`;
|
|
5007
|
+
if (childElement.type === "richinput" && childElement.flatOutput) {
|
|
5008
|
+
const richChild = childElement;
|
|
5009
|
+
const textKey = (_a = richChild.textKey) != null ? _a : "text";
|
|
5010
|
+
const filesKey = (_b = richChild.filesKey) != null ? _b : "files";
|
|
5011
|
+
const containerValue = value;
|
|
5012
|
+
const compositeValue = {};
|
|
5013
|
+
if (textKey in containerValue) compositeValue[textKey] = containerValue[textKey];
|
|
5014
|
+
if (filesKey in containerValue) compositeValue[filesKey] = containerValue[filesKey];
|
|
5015
|
+
if (Object.keys(compositeValue).length > 0) {
|
|
5016
|
+
instance.updateField(childPath, compositeValue);
|
|
5017
|
+
}
|
|
5018
|
+
} else {
|
|
5019
|
+
const childValue = value[childElement.key];
|
|
5020
|
+
if (childValue !== void 0) {
|
|
5021
|
+
instance.updateField(childPath, childValue);
|
|
5022
|
+
}
|
|
4709
5023
|
}
|
|
4710
5024
|
});
|
|
4711
5025
|
}
|
|
@@ -6540,6 +6854,42 @@ function renderEditMode(element, ctx, wrapper, pathKey, initialValue) {
|
|
|
6540
6854
|
outerDiv.style.borderColor = "var(--fb-border-color, #d1d5db)";
|
|
6541
6855
|
outerDiv.style.boxShadow = "none";
|
|
6542
6856
|
});
|
|
6857
|
+
const errorEl = document.createElement("div");
|
|
6858
|
+
errorEl.className = "fb-richinput-error";
|
|
6859
|
+
errorEl.style.cssText = "display: none; color: var(--fb-error-color, #ef4444); font-size: var(--fb-font-size-small, 12px); padding: 4px 14px 8px;";
|
|
6860
|
+
let errorTimer = null;
|
|
6861
|
+
function showUploadError(message) {
|
|
6862
|
+
errorEl.textContent = message;
|
|
6863
|
+
errorEl.style.display = "block";
|
|
6864
|
+
if (errorTimer) clearTimeout(errorTimer);
|
|
6865
|
+
errorTimer = setTimeout(() => {
|
|
6866
|
+
errorEl.style.display = "none";
|
|
6867
|
+
errorEl.textContent = "";
|
|
6868
|
+
errorTimer = null;
|
|
6869
|
+
}, 5e3);
|
|
6870
|
+
}
|
|
6871
|
+
function validateFileForUpload(file) {
|
|
6872
|
+
var _a2;
|
|
6873
|
+
const allowedExtensions = getAllowedExtensions(element.accept);
|
|
6874
|
+
if (!isFileExtensionAllowed(file.name, allowedExtensions)) {
|
|
6875
|
+
const formats = allowedExtensions.join(", ");
|
|
6876
|
+
showUploadError(
|
|
6877
|
+
t("invalidFileExtension", state, { name: file.name, formats })
|
|
6878
|
+
);
|
|
6879
|
+
return false;
|
|
6880
|
+
}
|
|
6881
|
+
const maxSizeMB = (_a2 = element.maxSize) != null ? _a2 : Infinity;
|
|
6882
|
+
if (!isFileSizeAllowed(file, maxSizeMB)) {
|
|
6883
|
+
showUploadError(
|
|
6884
|
+
t("fileTooLarge", state, {
|
|
6885
|
+
name: file.name,
|
|
6886
|
+
maxSize: maxSizeMB
|
|
6887
|
+
})
|
|
6888
|
+
);
|
|
6889
|
+
return false;
|
|
6890
|
+
}
|
|
6891
|
+
return true;
|
|
6892
|
+
}
|
|
6543
6893
|
let dragCounter = 0;
|
|
6544
6894
|
outerDiv.addEventListener("dragenter", (e) => {
|
|
6545
6895
|
e.preventDefault();
|
|
@@ -6568,7 +6918,17 @@ function renderEditMode(element, ctx, wrapper, pathKey, initialValue) {
|
|
|
6568
6918
|
const droppedFiles = (_a2 = e.dataTransfer) == null ? void 0 : _a2.files;
|
|
6569
6919
|
if (!droppedFiles || !state.config.uploadFile) return;
|
|
6570
6920
|
const maxFiles = (_b = element.maxFiles) != null ? _b : Infinity;
|
|
6571
|
-
for (let i = 0; i < droppedFiles.length
|
|
6921
|
+
for (let i = 0; i < droppedFiles.length; i++) {
|
|
6922
|
+
if (files.length >= maxFiles) {
|
|
6923
|
+
showUploadError(
|
|
6924
|
+
t("filesLimitExceeded", state, {
|
|
6925
|
+
skipped: droppedFiles.length - i,
|
|
6926
|
+
max: maxFiles
|
|
6927
|
+
})
|
|
6928
|
+
);
|
|
6929
|
+
break;
|
|
6930
|
+
}
|
|
6931
|
+
if (!validateFileForUpload(droppedFiles[i])) continue;
|
|
6572
6932
|
uploadFile(droppedFiles[i]);
|
|
6573
6933
|
}
|
|
6574
6934
|
});
|
|
@@ -6728,9 +7088,13 @@ function renderEditMode(element, ctx, wrapper, pathKey, initialValue) {
|
|
|
6728
7088
|
paperclipBtn.addEventListener("click", () => {
|
|
6729
7089
|
var _a2;
|
|
6730
7090
|
const maxFiles = (_a2 = element.maxFiles) != null ? _a2 : Infinity;
|
|
6731
|
-
if (files.length
|
|
6732
|
-
|
|
7091
|
+
if (files.length >= maxFiles) {
|
|
7092
|
+
showUploadError(
|
|
7093
|
+
t("filesLimitExceeded", state, { skipped: 1, max: maxFiles })
|
|
7094
|
+
);
|
|
7095
|
+
return;
|
|
6733
7096
|
}
|
|
7097
|
+
fileInput.click();
|
|
6734
7098
|
});
|
|
6735
7099
|
const dropdown = document.createElement("div");
|
|
6736
7100
|
dropdown.className = "fb-richinput-dropdown";
|
|
@@ -7051,7 +7415,17 @@ function renderEditMode(element, ctx, wrapper, pathKey, initialValue) {
|
|
|
7051
7415
|
const selected = fileInput.files;
|
|
7052
7416
|
if (!selected || selected.length === 0) return;
|
|
7053
7417
|
const maxFiles = (_a2 = element.maxFiles) != null ? _a2 : Infinity;
|
|
7054
|
-
for (let i = 0; i < selected.length
|
|
7418
|
+
for (let i = 0; i < selected.length; i++) {
|
|
7419
|
+
if (files.length >= maxFiles) {
|
|
7420
|
+
showUploadError(
|
|
7421
|
+
t("filesLimitExceeded", state, {
|
|
7422
|
+
skipped: selected.length - i,
|
|
7423
|
+
max: maxFiles
|
|
7424
|
+
})
|
|
7425
|
+
);
|
|
7426
|
+
break;
|
|
7427
|
+
}
|
|
7428
|
+
if (!validateFileForUpload(selected[i])) continue;
|
|
7055
7429
|
uploadFile(selected[i]);
|
|
7056
7430
|
}
|
|
7057
7431
|
fileInput.value = "";
|
|
@@ -7062,6 +7436,7 @@ function renderEditMode(element, ctx, wrapper, pathKey, initialValue) {
|
|
|
7062
7436
|
textareaArea.appendChild(dropdown);
|
|
7063
7437
|
outerDiv.appendChild(filesRow);
|
|
7064
7438
|
outerDiv.appendChild(textareaArea);
|
|
7439
|
+
outerDiv.appendChild(errorEl);
|
|
7065
7440
|
if (element.minLength != null || element.maxLength != null) {
|
|
7066
7441
|
const counterRow = document.createElement("div");
|
|
7067
7442
|
counterRow.style.cssText = "position: relative; padding: 2px 14px 6px; text-align: right;";
|
|
@@ -7224,20 +7599,29 @@ function renderRichInputElement(element, ctx, wrapper, pathKey) {
|
|
|
7224
7599
|
const state = ctx.state;
|
|
7225
7600
|
const textKey = (_a = element.textKey) != null ? _a : "text";
|
|
7226
7601
|
const filesKey = (_b = element.filesKey) != null ? _b : "files";
|
|
7227
|
-
const rawPrefill = ctx.prefill[element.key];
|
|
7228
7602
|
let initialValue;
|
|
7229
|
-
if (
|
|
7230
|
-
const
|
|
7231
|
-
const
|
|
7232
|
-
const filesVal = (_d = obj[filesKey]) != null ? _d : obj["files"];
|
|
7603
|
+
if (element.flatOutput) {
|
|
7604
|
+
const textVal = ctx.prefill[textKey];
|
|
7605
|
+
const filesVal = ctx.prefill[filesKey];
|
|
7233
7606
|
initialValue = {
|
|
7234
7607
|
text: typeof textVal === "string" ? textVal : null,
|
|
7235
7608
|
files: Array.isArray(filesVal) ? filesVal : []
|
|
7236
7609
|
};
|
|
7237
|
-
} else if (typeof rawPrefill === "string") {
|
|
7238
|
-
initialValue = { text: rawPrefill || null, files: [] };
|
|
7239
7610
|
} else {
|
|
7240
|
-
|
|
7611
|
+
const rawPrefill = ctx.prefill[element.key];
|
|
7612
|
+
if (rawPrefill && typeof rawPrefill === "object" && !Array.isArray(rawPrefill)) {
|
|
7613
|
+
const obj = rawPrefill;
|
|
7614
|
+
const textVal = (_c = obj[textKey]) != null ? _c : obj["text"];
|
|
7615
|
+
const filesVal = (_d = obj[filesKey]) != null ? _d : obj["files"];
|
|
7616
|
+
initialValue = {
|
|
7617
|
+
text: typeof textVal === "string" ? textVal : null,
|
|
7618
|
+
files: Array.isArray(filesVal) ? filesVal : []
|
|
7619
|
+
};
|
|
7620
|
+
} else if (typeof rawPrefill === "string") {
|
|
7621
|
+
initialValue = { text: rawPrefill || null, files: [] };
|
|
7622
|
+
} else {
|
|
7623
|
+
initialValue = { text: null, files: [] };
|
|
7624
|
+
}
|
|
7241
7625
|
}
|
|
7242
7626
|
for (const rid of initialValue.files) {
|
|
7243
7627
|
if (!state.resourceIndex.has(rid)) {
|
|
@@ -7318,7 +7702,7 @@ function validateRichInputElement(element, key, context) {
|
|
|
7318
7702
|
);
|
|
7319
7703
|
}
|
|
7320
7704
|
}
|
|
7321
|
-
return { value, errors };
|
|
7705
|
+
return { value, errors, spread: !!element.flatOutput };
|
|
7322
7706
|
}
|
|
7323
7707
|
function updateRichInputField(element, fieldPath, value, context) {
|
|
7324
7708
|
var _a, _b, _c, _d;
|
|
@@ -7798,6 +8182,9 @@ var defaultConfig = {
|
|
|
7798
8182
|
invalidHexColour: "Invalid hex color",
|
|
7799
8183
|
minFiles: "Minimum {min} files required",
|
|
7800
8184
|
maxFiles: "Maximum {max} files allowed",
|
|
8185
|
+
invalidFileExtension: 'File "{name}" has unsupported format. Allowed: {formats}',
|
|
8186
|
+
fileTooLarge: 'File "{name}" exceeds maximum size of {maxSize}MB',
|
|
8187
|
+
filesLimitExceeded: "{skipped} file(s) skipped: maximum {max} files allowed",
|
|
7801
8188
|
unsupportedFieldType: "Unsupported field type: {type}",
|
|
7802
8189
|
invalidOption: "Invalid option",
|
|
7803
8190
|
tableAddRow: "Add row",
|
|
@@ -7857,6 +8244,9 @@ var defaultConfig = {
|
|
|
7857
8244
|
invalidHexColour: "\u041D\u0435\u0432\u0435\u0440\u043D\u044B\u0439 \u0444\u043E\u0440\u043C\u0430\u0442 \u0446\u0432\u0435\u0442\u0430",
|
|
7858
8245
|
minFiles: "\u041C\u0438\u043D\u0438\u043C\u0443\u043C {min} \u0444\u0430\u0439\u043B\u043E\u0432",
|
|
7859
8246
|
maxFiles: "\u041C\u0430\u043A\u0441\u0438\u043C\u0443\u043C {max} \u0444\u0430\u0439\u043B\u043E\u0432",
|
|
8247
|
+
invalidFileExtension: '\u0424\u0430\u0439\u043B "{name}" \u0438\u043C\u0435\u0435\u0442 \u043D\u0435\u043F\u043E\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u043C\u044B\u0439 \u0444\u043E\u0440\u043C\u0430\u0442. \u0414\u043E\u043F\u0443\u0441\u0442\u0438\u043C\u044B\u0435: {formats}',
|
|
8248
|
+
fileTooLarge: '\u0424\u0430\u0439\u043B "{name}" \u043F\u0440\u0435\u0432\u044B\u0448\u0430\u0435\u0442 \u043C\u0430\u043A\u0441\u0438\u043C\u0430\u043B\u044C\u043D\u044B\u0439 \u0440\u0430\u0437\u043C\u0435\u0440 {maxSize}\u041C\u0411',
|
|
8249
|
+
filesLimitExceeded: "{skipped} \u0444\u0430\u0439\u043B(\u043E\u0432) \u043F\u0440\u043E\u043F\u0443\u0449\u0435\u043D\u043E: \u043C\u0430\u043A\u0441\u0438\u043C\u0443\u043C {max} \u0444\u0430\u0439\u043B\u043E\u0432",
|
|
7860
8250
|
unsupportedFieldType: "\u041D\u0435\u043F\u043E\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u043C\u044B\u0439 \u0442\u0438\u043F \u043F\u043E\u043B\u044F: {type}",
|
|
7861
8251
|
invalidOption: "\u041D\u0435\u0434\u043E\u043F\u0443\u0441\u0442\u0438\u043C\u043E\u0435 \u0437\u043D\u0430\u0447\u0435\u043D\u0438\u0435",
|
|
7862
8252
|
tableAddRow: "\u0414\u043E\u0431\u0430\u0432\u0438\u0442\u044C \u0441\u0442\u0440\u043E\u043A\u0443",
|
|
@@ -7901,7 +8291,8 @@ function createInstanceState(config) {
|
|
|
7901
8291
|
...config,
|
|
7902
8292
|
translations: mergedTranslations
|
|
7903
8293
|
},
|
|
7904
|
-
debounceTimer: null
|
|
8294
|
+
debounceTimer: null,
|
|
8295
|
+
prefill: {}
|
|
7905
8296
|
};
|
|
7906
8297
|
}
|
|
7907
8298
|
function generateInstanceId() {
|
|
@@ -8099,6 +8490,27 @@ function applyActionButtonStyles(button, isFormLevel = false) {
|
|
|
8099
8490
|
}
|
|
8100
8491
|
|
|
8101
8492
|
// src/components/registry.ts
|
|
8493
|
+
function validateHiddenElement(element, key, context) {
|
|
8494
|
+
var _a;
|
|
8495
|
+
const { scopeRoot } = context;
|
|
8496
|
+
const input = scopeRoot.querySelector(
|
|
8497
|
+
`input[type="hidden"][data-hidden-field="true"][name="${key}"]`
|
|
8498
|
+
);
|
|
8499
|
+
const raw = (_a = input == null ? void 0 : input.value) != null ? _a : "";
|
|
8500
|
+
if (raw === "") {
|
|
8501
|
+
const defaultVal = "default" in element ? element.default : null;
|
|
8502
|
+
return { value: defaultVal !== void 0 ? defaultVal : null, errors: [] };
|
|
8503
|
+
}
|
|
8504
|
+
return { value: deserializeHiddenValue(raw), errors: [] };
|
|
8505
|
+
}
|
|
8506
|
+
function updateHiddenField(_element, fieldPath, value, context) {
|
|
8507
|
+
const { scopeRoot } = context;
|
|
8508
|
+
const input = scopeRoot.querySelector(
|
|
8509
|
+
`input[type="hidden"][data-hidden-field="true"][name="${fieldPath}"]`
|
|
8510
|
+
);
|
|
8511
|
+
if (!input) return;
|
|
8512
|
+
input.value = serializeHiddenValue(value);
|
|
8513
|
+
}
|
|
8102
8514
|
var componentRegistry = {
|
|
8103
8515
|
text: {
|
|
8104
8516
|
validate: validateTextElement,
|
|
@@ -8153,6 +8565,11 @@ var componentRegistry = {
|
|
|
8153
8565
|
richinput: {
|
|
8154
8566
|
validate: validateRichInputElement,
|
|
8155
8567
|
update: updateRichInputField
|
|
8568
|
+
},
|
|
8569
|
+
hidden: {
|
|
8570
|
+
// Legacy type: `type: "hidden"` — reads/writes DOM <input type="hidden"> element
|
|
8571
|
+
validate: validateHiddenElement,
|
|
8572
|
+
update: updateHiddenField
|
|
8156
8573
|
}
|
|
8157
8574
|
};
|
|
8158
8575
|
function getComponentOperations(elementType) {
|
|
@@ -8562,6 +8979,7 @@ var FormBuilderInstance = class {
|
|
|
8562
8979
|
this.state.formRoot = root;
|
|
8563
8980
|
this.state.schema = schema;
|
|
8564
8981
|
this.state.externalActions = actions || null;
|
|
8982
|
+
this.state.prefill = prefill || {};
|
|
8565
8983
|
clear(root);
|
|
8566
8984
|
root.setAttribute("data-fb-root", "true");
|
|
8567
8985
|
injectThemeVariables(root, this.state.config.theme);
|
|
@@ -8579,7 +8997,10 @@ var FormBuilderInstance = class {
|
|
|
8579
8997
|
fieldsWrapper.className = `grid grid-cols-${columns} gap-4`;
|
|
8580
8998
|
}
|
|
8581
8999
|
schema.elements.forEach((element) => {
|
|
8582
|
-
|
|
9000
|
+
var _a, _b;
|
|
9001
|
+
if (element.hidden || element.type === "hidden") {
|
|
9002
|
+
const val = (_b = (_a = prefill == null ? void 0 : prefill[element.key]) != null ? _a : element.default) != null ? _b : null;
|
|
9003
|
+
fieldsWrapper.appendChild(createHiddenInput(element.key, val));
|
|
8583
9004
|
return;
|
|
8584
9005
|
}
|
|
8585
9006
|
const block = renderElement2(element, {
|
|
@@ -8628,13 +9049,14 @@ var FormBuilderInstance = class {
|
|
|
8628
9049
|
);
|
|
8629
9050
|
if (componentResult !== null) {
|
|
8630
9051
|
errors.push(...componentResult.errors);
|
|
8631
|
-
return componentResult.value;
|
|
9052
|
+
return { value: componentResult.value, spread: !!componentResult.spread };
|
|
8632
9053
|
}
|
|
8633
9054
|
console.warn(`Unknown field type "${element.type}" for key "${key}"`);
|
|
8634
|
-
return null;
|
|
9055
|
+
return { value: null, spread: false };
|
|
8635
9056
|
};
|
|
8636
9057
|
setValidateElement(validateElement2);
|
|
8637
9058
|
this.state.schema.elements.forEach((element) => {
|
|
9059
|
+
var _a;
|
|
8638
9060
|
if (element.enableIf) {
|
|
8639
9061
|
try {
|
|
8640
9062
|
const shouldEnable = evaluateEnableCondition(
|
|
@@ -8651,10 +9073,23 @@ var FormBuilderInstance = class {
|
|
|
8651
9073
|
);
|
|
8652
9074
|
}
|
|
8653
9075
|
}
|
|
8654
|
-
if (element.hidden) {
|
|
8655
|
-
|
|
9076
|
+
if (element.hidden || element.type === "hidden") {
|
|
9077
|
+
const hiddenInput = this.state.formRoot.querySelector(
|
|
9078
|
+
`input[type="hidden"][data-hidden-field="true"][name="${element.key}"]`
|
|
9079
|
+
);
|
|
9080
|
+
const raw = (_a = hiddenInput == null ? void 0 : hiddenInput.value) != null ? _a : "";
|
|
9081
|
+
if (raw !== "") {
|
|
9082
|
+
data[element.key] = deserializeHiddenValue(raw);
|
|
9083
|
+
} else {
|
|
9084
|
+
data[element.key] = element.default !== void 0 ? element.default : null;
|
|
9085
|
+
}
|
|
8656
9086
|
} else {
|
|
8657
|
-
|
|
9087
|
+
const result = validateElement2(element, { path: "" });
|
|
9088
|
+
if (result.spread && result.value !== null && typeof result.value === "object") {
|
|
9089
|
+
Object.assign(data, result.value);
|
|
9090
|
+
} else {
|
|
9091
|
+
data[element.key] = result.value;
|
|
9092
|
+
}
|
|
8658
9093
|
}
|
|
8659
9094
|
});
|
|
8660
9095
|
return {
|
|
@@ -8748,6 +9183,24 @@ var FormBuilderInstance = class {
|
|
|
8748
9183
|
}
|
|
8749
9184
|
return data;
|
|
8750
9185
|
}
|
|
9186
|
+
/**
|
|
9187
|
+
* Build a map from flat output keys (textKey/filesKey) to the richinput schema element info.
|
|
9188
|
+
* Used by setFormData to detect flat richinput keys and remap them to their composite values.
|
|
9189
|
+
*/
|
|
9190
|
+
buildFlatKeyMap(elements) {
|
|
9191
|
+
var _a, _b;
|
|
9192
|
+
const map = /* @__PURE__ */ new Map();
|
|
9193
|
+
for (const el of elements) {
|
|
9194
|
+
if (el.type === "richinput" && el.flatOutput) {
|
|
9195
|
+
const richEl = el;
|
|
9196
|
+
const textKey = (_a = richEl.textKey) != null ? _a : "text";
|
|
9197
|
+
const filesKey = (_b = richEl.filesKey) != null ? _b : "files";
|
|
9198
|
+
map.set(textKey, { schemaKey: el.key, role: "text" });
|
|
9199
|
+
map.set(filesKey, { schemaKey: el.key, role: "files" });
|
|
9200
|
+
}
|
|
9201
|
+
}
|
|
9202
|
+
return map;
|
|
9203
|
+
}
|
|
8751
9204
|
/**
|
|
8752
9205
|
* Set form data - update multiple fields without full re-render
|
|
8753
9206
|
* @param data - Object with field paths and their values
|
|
@@ -8759,8 +9212,21 @@ var FormBuilderInstance = class {
|
|
|
8759
9212
|
);
|
|
8760
9213
|
return;
|
|
8761
9214
|
}
|
|
9215
|
+
const flatKeyMap = this.buildFlatKeyMap(this.state.schema.elements);
|
|
9216
|
+
const flatUpdates = /* @__PURE__ */ new Map();
|
|
8762
9217
|
for (const fieldPath in data) {
|
|
8763
|
-
|
|
9218
|
+
const flatInfo = flatKeyMap.get(fieldPath);
|
|
9219
|
+
if (flatInfo) {
|
|
9220
|
+
if (!flatUpdates.has(flatInfo.schemaKey)) {
|
|
9221
|
+
flatUpdates.set(flatInfo.schemaKey, {});
|
|
9222
|
+
}
|
|
9223
|
+
flatUpdates.get(flatInfo.schemaKey)[fieldPath] = data[fieldPath];
|
|
9224
|
+
} else {
|
|
9225
|
+
this.updateField(fieldPath, data[fieldPath]);
|
|
9226
|
+
}
|
|
9227
|
+
}
|
|
9228
|
+
for (const [schemaKey, compositeValue] of flatUpdates) {
|
|
9229
|
+
this.updateField(schemaKey, compositeValue);
|
|
8764
9230
|
}
|
|
8765
9231
|
}
|
|
8766
9232
|
/**
|