@nextlyhq/plugin-form-builder 0.0.2-alpha.5 → 0.0.2-alpha.50
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 +12 -5
- package/dist/admin/index.d.ts +123 -331
- package/dist/admin/index.js +3809 -3419
- package/dist/admin/index.js.map +1 -1
- package/dist/chunk-WVI7N3QO.js +559 -0
- package/dist/chunk-WVI7N3QO.js.map +1 -0
- package/dist/index.d.ts +12 -11
- package/dist/index.js +579 -663
- package/dist/index.js.map +1 -1
- package/dist/{index-C0kBvYjm.d.ts → types-r8uBeB0u.d.ts} +126 -125
- package/package.json +28 -30
- package/dist/CheckboxFieldEditor-K4T6QX52.js +0 -121
- package/dist/CheckboxFieldEditor-K4T6QX52.js.map +0 -1
- package/dist/DateFieldEditor-JFJFAVOH.js +0 -187
- package/dist/DateFieldEditor-JFJFAVOH.js.map +0 -1
- package/dist/EmailFieldEditor-MMOXXL7P.js +0 -138
- package/dist/EmailFieldEditor-MMOXXL7P.js.map +0 -1
- package/dist/NumberFieldEditor-UISAYR6Z.js +0 -175
- package/dist/NumberFieldEditor-UISAYR6Z.js.map +0 -1
- package/dist/RadioFieldEditor-6UQFH4WT.js +0 -165
- package/dist/RadioFieldEditor-6UQFH4WT.js.map +0 -1
- package/dist/SelectFieldEditor-PSO4KHV4.js +0 -213
- package/dist/SelectFieldEditor-PSO4KHV4.js.map +0 -1
- package/dist/TextFieldEditor-5EU64EA5.js +0 -187
- package/dist/TextFieldEditor-5EU64EA5.js.map +0 -1
- package/dist/TextareaFieldEditor-773G3LNM.js +0 -190
- package/dist/TextareaFieldEditor-773G3LNM.js.map +0 -1
- package/dist/admin/index.css +0 -934
- package/dist/admin/index.css.map +0 -1
- package/dist/chunk-ABNZFTQK.js +0 -586
- package/dist/chunk-ABNZFTQK.js.map +0 -1
- package/dist/chunk-XTCEPJ7B.js +0 -256
- package/dist/chunk-XTCEPJ7B.js.map +0 -1
- package/dist/components/index.d.ts +0 -3
- package/dist/components/index.js +0 -9
- package/dist/components/index.js.map +0 -1
- package/dist/styles/form-builder.css +0 -1150
- package/dist/styles/submissions-filter.css +0 -75
|
@@ -0,0 +1,559 @@
|
|
|
1
|
+
// src/utils/evaluate-conditions.ts
|
|
2
|
+
function isEmptyValue(value) {
|
|
3
|
+
if (value === void 0 || value === null) {
|
|
4
|
+
return true;
|
|
5
|
+
}
|
|
6
|
+
if (typeof value === "string" && value.trim() === "") {
|
|
7
|
+
return true;
|
|
8
|
+
}
|
|
9
|
+
if (Array.isArray(value) && value.length === 0) {
|
|
10
|
+
return true;
|
|
11
|
+
}
|
|
12
|
+
return false;
|
|
13
|
+
}
|
|
14
|
+
function toNumber(value) {
|
|
15
|
+
if (typeof value === "number") {
|
|
16
|
+
return value;
|
|
17
|
+
}
|
|
18
|
+
if (typeof value === "string") {
|
|
19
|
+
const trimmed = value.trim();
|
|
20
|
+
if (trimmed === "") {
|
|
21
|
+
return NaN;
|
|
22
|
+
}
|
|
23
|
+
return Number(trimmed);
|
|
24
|
+
}
|
|
25
|
+
return NaN;
|
|
26
|
+
}
|
|
27
|
+
function toString(value) {
|
|
28
|
+
if (value === void 0 || value === null) {
|
|
29
|
+
return "";
|
|
30
|
+
}
|
|
31
|
+
if (typeof value === "string") {
|
|
32
|
+
return value;
|
|
33
|
+
}
|
|
34
|
+
if (Array.isArray(value)) {
|
|
35
|
+
return value.join(", ");
|
|
36
|
+
}
|
|
37
|
+
if (typeof value === "object") {
|
|
38
|
+
return JSON.stringify(value);
|
|
39
|
+
}
|
|
40
|
+
return String(value);
|
|
41
|
+
}
|
|
42
|
+
function compareValues(operator, fieldValue, conditionValue) {
|
|
43
|
+
switch (operator) {
|
|
44
|
+
case "equals": {
|
|
45
|
+
if (Array.isArray(fieldValue)) {
|
|
46
|
+
if (Array.isArray(conditionValue)) {
|
|
47
|
+
if (fieldValue.length !== conditionValue.length) {
|
|
48
|
+
return false;
|
|
49
|
+
}
|
|
50
|
+
return fieldValue.every((v, i) => v === conditionValue[i]);
|
|
51
|
+
}
|
|
52
|
+
return fieldValue.includes(conditionValue);
|
|
53
|
+
}
|
|
54
|
+
return toString(fieldValue) === toString(conditionValue);
|
|
55
|
+
}
|
|
56
|
+
case "notEquals": {
|
|
57
|
+
if (Array.isArray(fieldValue)) {
|
|
58
|
+
if (Array.isArray(conditionValue)) {
|
|
59
|
+
if (fieldValue.length !== conditionValue.length) {
|
|
60
|
+
return true;
|
|
61
|
+
}
|
|
62
|
+
return !fieldValue.every((v, i) => v === conditionValue[i]);
|
|
63
|
+
}
|
|
64
|
+
return !fieldValue.includes(conditionValue);
|
|
65
|
+
}
|
|
66
|
+
return toString(fieldValue) !== toString(conditionValue);
|
|
67
|
+
}
|
|
68
|
+
case "contains": {
|
|
69
|
+
const fieldStr = toString(fieldValue).toLowerCase();
|
|
70
|
+
const conditionStr = toString(conditionValue).toLowerCase();
|
|
71
|
+
if (Array.isArray(fieldValue)) {
|
|
72
|
+
return fieldValue.some(
|
|
73
|
+
(v) => toString(v).toLowerCase().includes(conditionStr)
|
|
74
|
+
);
|
|
75
|
+
}
|
|
76
|
+
return fieldStr.includes(conditionStr);
|
|
77
|
+
}
|
|
78
|
+
case "isEmpty": {
|
|
79
|
+
return isEmptyValue(fieldValue);
|
|
80
|
+
}
|
|
81
|
+
case "isNotEmpty": {
|
|
82
|
+
return !isEmptyValue(fieldValue);
|
|
83
|
+
}
|
|
84
|
+
case "greaterThan": {
|
|
85
|
+
const fieldNum = toNumber(fieldValue);
|
|
86
|
+
const conditionNum = toNumber(conditionValue);
|
|
87
|
+
if (!Number.isNaN(fieldNum) && !Number.isNaN(conditionNum)) {
|
|
88
|
+
return fieldNum > conditionNum;
|
|
89
|
+
}
|
|
90
|
+
return toString(fieldValue) > toString(conditionValue);
|
|
91
|
+
}
|
|
92
|
+
case "lessThan": {
|
|
93
|
+
const fieldNum = toNumber(fieldValue);
|
|
94
|
+
const conditionNum = toNumber(conditionValue);
|
|
95
|
+
if (!Number.isNaN(fieldNum) && !Number.isNaN(conditionNum)) {
|
|
96
|
+
return fieldNum < conditionNum;
|
|
97
|
+
}
|
|
98
|
+
return toString(fieldValue) < toString(conditionValue);
|
|
99
|
+
}
|
|
100
|
+
default: {
|
|
101
|
+
console.warn(
|
|
102
|
+
`[evaluateConditions] Unknown comparison operator: ${String(operator)}`
|
|
103
|
+
);
|
|
104
|
+
return false;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
function evaluateSingleCondition(condition, formData) {
|
|
109
|
+
const { field, comparison, value: conditionValue } = condition;
|
|
110
|
+
const fieldValue = getNestedValue(formData, field);
|
|
111
|
+
return compareValues(comparison, fieldValue, conditionValue);
|
|
112
|
+
}
|
|
113
|
+
function getNestedValue(obj, path) {
|
|
114
|
+
if (!path) {
|
|
115
|
+
return void 0;
|
|
116
|
+
}
|
|
117
|
+
if (!path.includes(".")) {
|
|
118
|
+
return obj[path];
|
|
119
|
+
}
|
|
120
|
+
const parts = path.split(".");
|
|
121
|
+
let current = obj;
|
|
122
|
+
for (const part of parts) {
|
|
123
|
+
if (current === void 0 || current === null) {
|
|
124
|
+
return void 0;
|
|
125
|
+
}
|
|
126
|
+
if (typeof current !== "object") {
|
|
127
|
+
return void 0;
|
|
128
|
+
}
|
|
129
|
+
current = current[part];
|
|
130
|
+
}
|
|
131
|
+
return current;
|
|
132
|
+
}
|
|
133
|
+
function evaluateConditions(logic, formData) {
|
|
134
|
+
if (!logic || !logic.enabled) {
|
|
135
|
+
return true;
|
|
136
|
+
}
|
|
137
|
+
const { action, operator, conditions } = logic;
|
|
138
|
+
if (!conditions || conditions.length === 0) {
|
|
139
|
+
return true;
|
|
140
|
+
}
|
|
141
|
+
const results = conditions.map(
|
|
142
|
+
(condition) => evaluateSingleCondition(condition, formData)
|
|
143
|
+
);
|
|
144
|
+
let conditionsMet;
|
|
145
|
+
if (operator === "OR") {
|
|
146
|
+
conditionsMet = results.some((result) => result);
|
|
147
|
+
} else {
|
|
148
|
+
conditionsMet = results.every((result) => result);
|
|
149
|
+
}
|
|
150
|
+
if (action === "hide") {
|
|
151
|
+
return !conditionsMet;
|
|
152
|
+
}
|
|
153
|
+
return conditionsMet;
|
|
154
|
+
}
|
|
155
|
+
function isValidComparisonOperator(operator) {
|
|
156
|
+
const validOperators = [
|
|
157
|
+
"equals",
|
|
158
|
+
"notEquals",
|
|
159
|
+
"contains",
|
|
160
|
+
"isEmpty",
|
|
161
|
+
"isNotEmpty",
|
|
162
|
+
"greaterThan",
|
|
163
|
+
"lessThan"
|
|
164
|
+
];
|
|
165
|
+
return validOperators.includes(operator);
|
|
166
|
+
}
|
|
167
|
+
function getSupportedComparisonOperators() {
|
|
168
|
+
return [
|
|
169
|
+
"equals",
|
|
170
|
+
"notEquals",
|
|
171
|
+
"contains",
|
|
172
|
+
"isEmpty",
|
|
173
|
+
"isNotEmpty",
|
|
174
|
+
"greaterThan",
|
|
175
|
+
"lessThan"
|
|
176
|
+
];
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
// src/utils/export-formats.ts
|
|
180
|
+
var UTF8_BOM = "\uFEFF";
|
|
181
|
+
function safeString(value) {
|
|
182
|
+
if (typeof value === "object" && value !== null) {
|
|
183
|
+
return JSON.stringify(value);
|
|
184
|
+
}
|
|
185
|
+
return String(value);
|
|
186
|
+
}
|
|
187
|
+
function formatExportValue(value, field) {
|
|
188
|
+
if (value === null || value === void 0) {
|
|
189
|
+
return "";
|
|
190
|
+
}
|
|
191
|
+
if (field) {
|
|
192
|
+
switch (field.type) {
|
|
193
|
+
case "checkbox":
|
|
194
|
+
return value ? "Yes" : "No";
|
|
195
|
+
case "select":
|
|
196
|
+
if (Array.isArray(value)) {
|
|
197
|
+
return value.join(", ");
|
|
198
|
+
}
|
|
199
|
+
return safeString(value);
|
|
200
|
+
case "file":
|
|
201
|
+
if (Array.isArray(value)) {
|
|
202
|
+
return value.map((v) => safeString(v)).join(", ");
|
|
203
|
+
}
|
|
204
|
+
return safeString(value);
|
|
205
|
+
case "date":
|
|
206
|
+
if (value instanceof Date) {
|
|
207
|
+
return value.toISOString().split("T")[0];
|
|
208
|
+
}
|
|
209
|
+
if (typeof value === "string") {
|
|
210
|
+
const parsed = new Date(value);
|
|
211
|
+
if (!isNaN(parsed.getTime())) {
|
|
212
|
+
return parsed.toISOString().split("T")[0];
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
return safeString(value);
|
|
216
|
+
case "time":
|
|
217
|
+
return safeString(value);
|
|
218
|
+
case "hidden":
|
|
219
|
+
return safeString(value);
|
|
220
|
+
default:
|
|
221
|
+
break;
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
if (Array.isArray(value)) {
|
|
225
|
+
return value.join(", ");
|
|
226
|
+
}
|
|
227
|
+
if (typeof value === "boolean") {
|
|
228
|
+
return value ? "Yes" : "No";
|
|
229
|
+
}
|
|
230
|
+
if (value instanceof Date) {
|
|
231
|
+
return value.toISOString();
|
|
232
|
+
}
|
|
233
|
+
return safeString(value);
|
|
234
|
+
}
|
|
235
|
+
function formatDate(date, format = "iso") {
|
|
236
|
+
if (!date) return "";
|
|
237
|
+
const d = typeof date === "string" ? new Date(date) : date;
|
|
238
|
+
if (isNaN(d.getTime())) {
|
|
239
|
+
return "";
|
|
240
|
+
}
|
|
241
|
+
return format === "iso" ? d.toISOString() : d.toLocaleString();
|
|
242
|
+
}
|
|
243
|
+
function escapeCSVValue(value, delimiter = ",") {
|
|
244
|
+
const isFormulaLike = /^[=+\-@\t\r]/.test(value) && !/^-?\d+(\.\d+)?$/.test(value);
|
|
245
|
+
const escapedFormula = isFormulaLike ? `'${value}` : value;
|
|
246
|
+
const needsQuoting = escapedFormula.includes(delimiter) || escapedFormula.includes('"') || escapedFormula.includes("\n") || escapedFormula.includes("\r");
|
|
247
|
+
if (!needsQuoting) {
|
|
248
|
+
return escapedFormula;
|
|
249
|
+
}
|
|
250
|
+
const escaped = escapedFormula.replace(/"/g, '""');
|
|
251
|
+
return `"${escaped}"`;
|
|
252
|
+
}
|
|
253
|
+
function exportToCSV(submissions, form, options = {}) {
|
|
254
|
+
const {
|
|
255
|
+
includeMetadata = true,
|
|
256
|
+
delimiter = ",",
|
|
257
|
+
includeBOM = true,
|
|
258
|
+
dateFormat = "iso"
|
|
259
|
+
} = options;
|
|
260
|
+
const exportableFields = form.fields;
|
|
261
|
+
const headers = [];
|
|
262
|
+
for (const field of exportableFields) {
|
|
263
|
+
headers.push(field.label);
|
|
264
|
+
}
|
|
265
|
+
if (includeMetadata) {
|
|
266
|
+
headers.push("ID", "Status", "Submitted At", "IP Address", "User Agent");
|
|
267
|
+
}
|
|
268
|
+
const rows = [];
|
|
269
|
+
for (const submission of submissions) {
|
|
270
|
+
const row = [];
|
|
271
|
+
const data = submission.data;
|
|
272
|
+
for (const field of exportableFields) {
|
|
273
|
+
const value = data[field.name];
|
|
274
|
+
const formatted = formatExportValue(value, field);
|
|
275
|
+
row.push(escapeCSVValue(formatted, delimiter));
|
|
276
|
+
}
|
|
277
|
+
if (includeMetadata) {
|
|
278
|
+
row.push(escapeCSVValue(submission.id, delimiter));
|
|
279
|
+
row.push(escapeCSVValue(submission.status, delimiter));
|
|
280
|
+
row.push(
|
|
281
|
+
escapeCSVValue(
|
|
282
|
+
formatDate(submission.submittedAt, dateFormat),
|
|
283
|
+
delimiter
|
|
284
|
+
)
|
|
285
|
+
);
|
|
286
|
+
row.push(escapeCSVValue(submission.ipAddress || "", delimiter));
|
|
287
|
+
row.push(escapeCSVValue(submission.userAgent || "", delimiter));
|
|
288
|
+
}
|
|
289
|
+
rows.push(row);
|
|
290
|
+
}
|
|
291
|
+
const escapedHeaders = headers.map((h) => escapeCSVValue(h, delimiter));
|
|
292
|
+
const lines = [
|
|
293
|
+
escapedHeaders.join(delimiter),
|
|
294
|
+
...rows.map((row) => row.join(delimiter))
|
|
295
|
+
];
|
|
296
|
+
const csvContent = lines.join("\r\n");
|
|
297
|
+
return includeBOM ? UTF8_BOM + csvContent : csvContent;
|
|
298
|
+
}
|
|
299
|
+
function exportToJSON(submissions, form, options = {}) {
|
|
300
|
+
const {
|
|
301
|
+
includeMetadata = true,
|
|
302
|
+
includeFormDefinition = true,
|
|
303
|
+
indent = 2
|
|
304
|
+
} = options;
|
|
305
|
+
const exportableFields = form.fields;
|
|
306
|
+
const formDefinition = includeFormDefinition ? {
|
|
307
|
+
id: form.id,
|
|
308
|
+
name: form.name,
|
|
309
|
+
slug: form.slug,
|
|
310
|
+
fields: exportableFields.map((f) => ({
|
|
311
|
+
name: f.name,
|
|
312
|
+
label: f.label,
|
|
313
|
+
type: f.type
|
|
314
|
+
}))
|
|
315
|
+
} : void 0;
|
|
316
|
+
const exportedSubmissions = submissions.map((submission) => {
|
|
317
|
+
const data = submission.data;
|
|
318
|
+
const fieldData = {};
|
|
319
|
+
for (const field of exportableFields) {
|
|
320
|
+
const value = data[field.name];
|
|
321
|
+
fieldData[field.name] = value;
|
|
322
|
+
}
|
|
323
|
+
if (includeMetadata) {
|
|
324
|
+
return {
|
|
325
|
+
...fieldData,
|
|
326
|
+
_metadata: {
|
|
327
|
+
id: submission.id,
|
|
328
|
+
status: submission.status,
|
|
329
|
+
submittedAt: submission.submittedAt,
|
|
330
|
+
ipAddress: submission.ipAddress || null,
|
|
331
|
+
userAgent: submission.userAgent || null,
|
|
332
|
+
createdAt: submission.createdAt,
|
|
333
|
+
updatedAt: submission.updatedAt
|
|
334
|
+
}
|
|
335
|
+
};
|
|
336
|
+
}
|
|
337
|
+
return fieldData;
|
|
338
|
+
});
|
|
339
|
+
const exportData = {
|
|
340
|
+
exportedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
341
|
+
totalSubmissions: submissions.length,
|
|
342
|
+
submissions: exportedSubmissions
|
|
343
|
+
};
|
|
344
|
+
if (formDefinition) {
|
|
345
|
+
exportData.form = formDefinition;
|
|
346
|
+
}
|
|
347
|
+
return JSON.stringify(exportData, null, indent);
|
|
348
|
+
}
|
|
349
|
+
function downloadFile(content, filename, mimeType) {
|
|
350
|
+
if (typeof window === "undefined" || typeof document === "undefined") {
|
|
351
|
+
throw new Error("downloadFile is only available in browser environments");
|
|
352
|
+
}
|
|
353
|
+
const blob = new Blob([content], { type: mimeType });
|
|
354
|
+
const url = URL.createObjectURL(blob);
|
|
355
|
+
const link = document.createElement("a");
|
|
356
|
+
link.href = url;
|
|
357
|
+
link.download = filename;
|
|
358
|
+
document.body.appendChild(link);
|
|
359
|
+
link.click();
|
|
360
|
+
document.body.removeChild(link);
|
|
361
|
+
URL.revokeObjectURL(url);
|
|
362
|
+
}
|
|
363
|
+
function generateExportFilename(formSlug, format) {
|
|
364
|
+
const safeSlug = formSlug.toLowerCase().replace(/[^a-z0-9_-]+/g, "-") || "form";
|
|
365
|
+
const date = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
|
|
366
|
+
return `${safeSlug}-submissions-${date}.${format}`;
|
|
367
|
+
}
|
|
368
|
+
function exportAndDownload(submissions, form, format, options) {
|
|
369
|
+
const filename = generateExportFilename(form.slug, format);
|
|
370
|
+
if (format === "csv") {
|
|
371
|
+
const content = exportToCSV(submissions, form, options);
|
|
372
|
+
downloadFile(content, filename, "text/csv;charset=utf-8");
|
|
373
|
+
} else {
|
|
374
|
+
const content = exportToJSON(submissions, form, options);
|
|
375
|
+
downloadFile(content, filename, "application/json");
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
// src/types.ts
|
|
380
|
+
var BUILT_IN_FORM_FIELD_TYPES = [
|
|
381
|
+
"text",
|
|
382
|
+
"email",
|
|
383
|
+
"number",
|
|
384
|
+
"phone",
|
|
385
|
+
"url",
|
|
386
|
+
"textarea",
|
|
387
|
+
"select",
|
|
388
|
+
"checkbox",
|
|
389
|
+
"radio",
|
|
390
|
+
"file",
|
|
391
|
+
"date",
|
|
392
|
+
"time",
|
|
393
|
+
"hidden"
|
|
394
|
+
];
|
|
395
|
+
var BUILT_IN_FORM_FIELD_TYPES_SET = new Set(
|
|
396
|
+
BUILT_IN_FORM_FIELD_TYPES
|
|
397
|
+
);
|
|
398
|
+
function isKnownFormField(field) {
|
|
399
|
+
return BUILT_IN_FORM_FIELD_TYPES_SET.has(field.type);
|
|
400
|
+
}
|
|
401
|
+
function isFormField(value) {
|
|
402
|
+
return typeof value === "object" && value !== null && "type" in value && "name" in value && "label" in value;
|
|
403
|
+
}
|
|
404
|
+
function isFormFieldType(field, type) {
|
|
405
|
+
return field.type === type;
|
|
406
|
+
}
|
|
407
|
+
function isTextFormField(field) {
|
|
408
|
+
return field.type === "text";
|
|
409
|
+
}
|
|
410
|
+
function isEmailFormField(field) {
|
|
411
|
+
return field.type === "email";
|
|
412
|
+
}
|
|
413
|
+
function isSelectFormField(field) {
|
|
414
|
+
return field.type === "select";
|
|
415
|
+
}
|
|
416
|
+
function isCheckboxFormField(field) {
|
|
417
|
+
return field.type === "checkbox";
|
|
418
|
+
}
|
|
419
|
+
function isFileFormField(field) {
|
|
420
|
+
return field.type === "file";
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
// src/config/defaults.ts
|
|
424
|
+
var DEFAULT_FORM_SETTINGS = {
|
|
425
|
+
submitButtonText: "Submit",
|
|
426
|
+
confirmationType: "message",
|
|
427
|
+
successMessage: "Thank you for your submission!",
|
|
428
|
+
allowMultipleSubmissions: true
|
|
429
|
+
};
|
|
430
|
+
var DEFAULT_NOTIFICATION_SETTINGS = {
|
|
431
|
+
enabled: true,
|
|
432
|
+
replyTo: true
|
|
433
|
+
};
|
|
434
|
+
function toTitleCase(str) {
|
|
435
|
+
return str.replace(/[-_]/g, " ").replace(/\b\w/g, (char) => char.toUpperCase());
|
|
436
|
+
}
|
|
437
|
+
function pluralize(singular) {
|
|
438
|
+
if (singular.endsWith("y") && !/[aeiou]y$/i.test(singular)) {
|
|
439
|
+
return singular.slice(0, -1) + "ies";
|
|
440
|
+
}
|
|
441
|
+
if (singular.endsWith("s") || singular.endsWith("x") || singular.endsWith("z") || singular.endsWith("ch") || singular.endsWith("sh")) {
|
|
442
|
+
return singular + "es";
|
|
443
|
+
}
|
|
444
|
+
return singular + "s";
|
|
445
|
+
}
|
|
446
|
+
function applyFormDefaults(config) {
|
|
447
|
+
const singularLabel = config.labels?.singular || toTitleCase(config.slug);
|
|
448
|
+
return {
|
|
449
|
+
...config,
|
|
450
|
+
// Generate labels from slug if not provided
|
|
451
|
+
labels: {
|
|
452
|
+
singular: singularLabel,
|
|
453
|
+
plural: config.labels?.plural || pluralize(singularLabel)
|
|
454
|
+
},
|
|
455
|
+
// Apply settings defaults
|
|
456
|
+
settings: {
|
|
457
|
+
submitButtonText: config.settings?.submitButtonText || DEFAULT_FORM_SETTINGS.submitButtonText,
|
|
458
|
+
confirmationType: config.settings?.confirmationType || DEFAULT_FORM_SETTINGS.confirmationType,
|
|
459
|
+
successMessage: config.settings?.successMessage || DEFAULT_FORM_SETTINGS.successMessage,
|
|
460
|
+
allowMultipleSubmissions: config.settings?.allowMultipleSubmissions ?? DEFAULT_FORM_SETTINGS.allowMultipleSubmissions,
|
|
461
|
+
// Preserve other settings that don't have defaults
|
|
462
|
+
redirectUrl: config.settings?.redirectUrl,
|
|
463
|
+
redirectRelation: config.settings?.redirectRelation,
|
|
464
|
+
honeypotEnabled: config.settings?.honeypotEnabled,
|
|
465
|
+
captchaEnabled: config.settings?.captchaEnabled,
|
|
466
|
+
captchaSiteKey: config.settings?.captchaSiteKey
|
|
467
|
+
},
|
|
468
|
+
// Apply notification defaults if notifications are configured
|
|
469
|
+
notifications: config.notifications ? {
|
|
470
|
+
enabled: config.notifications.enabled ?? DEFAULT_NOTIFICATION_SETTINGS.enabled,
|
|
471
|
+
recipients: config.notifications.recipients || [],
|
|
472
|
+
subject: config.notifications.subject || `New submission for ${singularLabel}`,
|
|
473
|
+
replyTo: config.notifications.replyTo ?? DEFAULT_NOTIFICATION_SETTINGS.replyTo,
|
|
474
|
+
template: config.notifications.template
|
|
475
|
+
} : void 0,
|
|
476
|
+
// Apply access defaults
|
|
477
|
+
access: {
|
|
478
|
+
// Default: anyone can submit the form
|
|
479
|
+
submit: config.access?.submit || (() => true),
|
|
480
|
+
// Default: only authenticated users can view submissions
|
|
481
|
+
read: config.access?.read || (({ req }) => !!req.user)
|
|
482
|
+
}
|
|
483
|
+
};
|
|
484
|
+
}
|
|
485
|
+
function applyFieldDefaults(field) {
|
|
486
|
+
const label = field.label || (field.name ? toTitleCase(field.name.replace(/([A-Z])/g, " $1").trim()) : "");
|
|
487
|
+
return {
|
|
488
|
+
...field,
|
|
489
|
+
label,
|
|
490
|
+
required: field.required ?? false
|
|
491
|
+
};
|
|
492
|
+
}
|
|
493
|
+
function createFormConfig(slug, fields, options) {
|
|
494
|
+
return applyFormDefaults({
|
|
495
|
+
slug,
|
|
496
|
+
fields,
|
|
497
|
+
...options
|
|
498
|
+
});
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
// src/utils/form-settings.ts
|
|
502
|
+
function asOptionalBoolean(value) {
|
|
503
|
+
return typeof value === "boolean" ? value : void 0;
|
|
504
|
+
}
|
|
505
|
+
function asOptionalString(value) {
|
|
506
|
+
return typeof value === "string" && value !== "" ? value : void 0;
|
|
507
|
+
}
|
|
508
|
+
function normalizeFormSettings(raw) {
|
|
509
|
+
if (!raw || typeof raw !== "object" || Array.isArray(raw)) {
|
|
510
|
+
return { ...DEFAULT_FORM_SETTINGS };
|
|
511
|
+
}
|
|
512
|
+
const source = raw;
|
|
513
|
+
const legacyMessage = asOptionalString(source.confirmationMessage);
|
|
514
|
+
const legacyCaptcha = source.captcha && typeof source.captcha === "object" ? source.captcha : void 0;
|
|
515
|
+
const confirmationType = source.confirmationType === "redirect" || source.confirmationType === "relationship" ? source.confirmationType : "message";
|
|
516
|
+
return {
|
|
517
|
+
submitButtonText: asOptionalString(source.submitButtonText) ?? DEFAULT_FORM_SETTINGS.submitButtonText,
|
|
518
|
+
confirmationType,
|
|
519
|
+
successMessage: asOptionalString(source.successMessage) ?? legacyMessage ?? DEFAULT_FORM_SETTINGS.successMessage,
|
|
520
|
+
redirectUrl: asOptionalString(source.redirectUrl),
|
|
521
|
+
redirectPage: source.redirectPage ?? void 0,
|
|
522
|
+
redirectRelation: source.redirectRelation && typeof source.redirectRelation === "object" ? source.redirectRelation : void 0,
|
|
523
|
+
allowMultipleSubmissions: asOptionalBoolean(source.allowMultipleSubmissions) ?? DEFAULT_FORM_SETTINGS.allowMultipleSubmissions,
|
|
524
|
+
honeypotEnabled: asOptionalBoolean(source.honeypotEnabled),
|
|
525
|
+
captchaEnabled: asOptionalBoolean(source.captchaEnabled) ?? asOptionalBoolean(legacyCaptcha?.enabled),
|
|
526
|
+
captchaSiteKey: asOptionalString(source.captchaSiteKey) ?? asOptionalString(legacyCaptcha?.siteKey)
|
|
527
|
+
};
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
export {
|
|
531
|
+
evaluateSingleCondition,
|
|
532
|
+
evaluateConditions,
|
|
533
|
+
isValidComparisonOperator,
|
|
534
|
+
getSupportedComparisonOperators,
|
|
535
|
+
formatExportValue,
|
|
536
|
+
exportToCSV,
|
|
537
|
+
exportToJSON,
|
|
538
|
+
downloadFile,
|
|
539
|
+
generateExportFilename,
|
|
540
|
+
exportAndDownload,
|
|
541
|
+
BUILT_IN_FORM_FIELD_TYPES,
|
|
542
|
+
isKnownFormField,
|
|
543
|
+
isFormField,
|
|
544
|
+
isFormFieldType,
|
|
545
|
+
isTextFormField,
|
|
546
|
+
isEmailFormField,
|
|
547
|
+
isSelectFormField,
|
|
548
|
+
isCheckboxFormField,
|
|
549
|
+
isFileFormField,
|
|
550
|
+
DEFAULT_FORM_SETTINGS,
|
|
551
|
+
DEFAULT_NOTIFICATION_SETTINGS,
|
|
552
|
+
toTitleCase,
|
|
553
|
+
pluralize,
|
|
554
|
+
applyFormDefaults,
|
|
555
|
+
applyFieldDefaults,
|
|
556
|
+
createFormConfig,
|
|
557
|
+
normalizeFormSettings
|
|
558
|
+
};
|
|
559
|
+
//# sourceMappingURL=chunk-WVI7N3QO.js.map
|