@formsnip/embed 1.0.0

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/index.js ADDED
@@ -0,0 +1,524 @@
1
+ 'use strict';
2
+
3
+ var React = require('react');
4
+
5
+ const ALLOWED_FILE_EXTENSIONS = '.jpg,.jpeg,.png,.gif,.webp,.svg,.pdf,.mp4,.mpeg,.mov,.avi,.webm,.mkv,.mp3,.wav,.ogg,.aac,.flac';
6
+ const MAX_TOTAL_FILE_SIZE = 15 * 1024 * 1024; // 15MB
7
+ /**
8
+ * Upload a file to R2 via presigned URL
9
+ */
10
+ async function uploadFile(file, formId, baseUrl) {
11
+ try {
12
+ // Step 1: Get presigned upload URL
13
+ const signResponse = await fetch(`${baseUrl}/uploads/sign`, {
14
+ method: 'POST',
15
+ headers: {
16
+ 'Content-Type': 'application/json',
17
+ },
18
+ credentials: 'include',
19
+ body: JSON.stringify({
20
+ filename: file.name,
21
+ contentType: file.type,
22
+ size: file.size,
23
+ formId,
24
+ }),
25
+ });
26
+ if (!signResponse.ok) {
27
+ return {
28
+ success: false,
29
+ error: 'Failed to get upload URL',
30
+ };
31
+ }
32
+ const signData = await signResponse.json();
33
+ if (!signData.success || !signData.data) {
34
+ return {
35
+ success: false,
36
+ error: signData.message || 'Invalid upload URL response',
37
+ };
38
+ }
39
+ const { uploadUrl, fileKey } = signData.data;
40
+ // Step 2: Upload file directly to R2
41
+ const uploadResponse = await fetch(uploadUrl, {
42
+ method: 'PUT',
43
+ body: file,
44
+ headers: {
45
+ 'Content-Type': file.type,
46
+ },
47
+ });
48
+ if (!uploadResponse.ok) {
49
+ return {
50
+ success: false,
51
+ error: `Upload failed: ${uploadResponse.statusText}`,
52
+ };
53
+ }
54
+ return {
55
+ success: true,
56
+ fileKey,
57
+ };
58
+ }
59
+ catch (error) {
60
+ return {
61
+ success: false,
62
+ error: error instanceof Error ? error.message : 'Unknown error occurred',
63
+ };
64
+ }
65
+ }
66
+ /**
67
+ * Upload multiple files to R2
68
+ */
69
+ async function uploadFiles(files, formId, baseUrl) {
70
+ // Check total size
71
+ const totalSize = files.reduce((sum, file) => sum + file.size, 0);
72
+ if (totalSize > MAX_TOTAL_FILE_SIZE) {
73
+ return {
74
+ success: false,
75
+ errors: [`Total file size exceeds 15MB limit per submission`],
76
+ };
77
+ }
78
+ const results = await Promise.allSettled(files.map((file) => uploadFile(file, formId, baseUrl)));
79
+ const fileKeys = [];
80
+ const errors = [];
81
+ results.forEach((result, index) => {
82
+ if (result.status === 'fulfilled' && result.value.success && result.value.fileKey) {
83
+ fileKeys.push(result.value.fileKey);
84
+ }
85
+ else {
86
+ const error = result.status === 'fulfilled'
87
+ ? result.value.error || 'Upload failed'
88
+ : result.reason?.message || 'Upload failed';
89
+ errors.push(`${files[index].name}: ${error}`);
90
+ }
91
+ });
92
+ return {
93
+ success: fileKeys.length > 0,
94
+ fileKeys: fileKeys.length > 0 ? fileKeys : undefined,
95
+ errors: errors.length > 0 ? errors : undefined,
96
+ };
97
+ }
98
+
99
+ const FileUpload = ({ id, label, required = false, disabled = false, multiple = true, onFilesChange, uploadedFiles = [], uploading = false, error, className = '', }) => {
100
+ const fileInputRef = React.useRef(null);
101
+ const [selectedFiles, setSelectedFiles] = React.useState([]);
102
+ const handleFileSelect = (e) => {
103
+ const files = Array.from(e.target.files || []);
104
+ if (multiple) {
105
+ setSelectedFiles((prev) => [...prev, ...files]);
106
+ onFilesChange([...selectedFiles, ...files]);
107
+ }
108
+ else {
109
+ setSelectedFiles(files);
110
+ onFilesChange(files);
111
+ }
112
+ };
113
+ const removeFile = (index) => {
114
+ const newFiles = selectedFiles.filter((_, i) => i !== index);
115
+ setSelectedFiles(newFiles);
116
+ onFilesChange(newFiles);
117
+ if (fileInputRef.current) {
118
+ fileInputRef.current.value = '';
119
+ }
120
+ };
121
+ const formatFileSize = (bytes) => {
122
+ if (bytes === 0)
123
+ return '0 Bytes';
124
+ const k = 1024;
125
+ const sizes = ['Bytes', 'KB', 'MB', 'GB'];
126
+ const i = Math.floor(Math.log(bytes) / Math.log(k));
127
+ return Math.round((bytes / Math.pow(k, i)) * 100) / 100 + ' ' + sizes[i];
128
+ };
129
+ const handleDrop = (e) => {
130
+ e.preventDefault();
131
+ e.stopPropagation();
132
+ if (disabled || uploading)
133
+ return;
134
+ const files = Array.from(e.dataTransfer.files);
135
+ if (multiple) {
136
+ setSelectedFiles((prev) => [...prev, ...files]);
137
+ onFilesChange([...selectedFiles, ...files]);
138
+ }
139
+ else {
140
+ setSelectedFiles(files.slice(0, 1));
141
+ onFilesChange(files.slice(0, 1));
142
+ }
143
+ };
144
+ const handleDragOver = (e) => {
145
+ e.preventDefault();
146
+ e.stopPropagation();
147
+ };
148
+ return (React.createElement("div", { className: className },
149
+ label && (React.createElement("label", { className: "fs-text-sm fs-text-gray-700 fs-mb-1" },
150
+ label,
151
+ required && React.createElement("span", { className: "fs-text-red-500", style: { marginLeft: '0.25rem' } }, "*"))),
152
+ React.createElement("div", { onDrop: handleDrop, onDragOver: handleDragOver, className: `fs-border-2 fs-border-dashed fs-rounded-lg fs-p-6 fs-text-center ${disabled || uploading ? '' : 'fs-cursor-pointer fs-hover-border-blue-400 fs-hover-bg-blue-50'}`, style: {
153
+ borderColor: '#d1d5db',
154
+ backgroundColor: disabled || uploading ? '#f9fafb' : '#ffffff',
155
+ cursor: disabled || uploading ? 'not-allowed' : 'pointer',
156
+ }, onClick: () => !disabled && !uploading && fileInputRef.current?.click() },
157
+ React.createElement("input", { ref: fileInputRef, type: "file", id: id, multiple: multiple, onChange: handleFileSelect, className: "hidden", disabled: disabled || uploading, required: required && selectedFiles.length === 0 && uploadedFiles.length === 0, accept: ALLOWED_FILE_EXTENSIONS }),
158
+ React.createElement("div", { className: "fs-flex fs-flex-col fs-items-center" },
159
+ React.createElement("svg", { className: "fs-text-gray-400", style: { width: '3rem', height: '3rem', margin: '0 auto 0.5rem' }, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24" },
160
+ React.createElement("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M7 16a4 4 0 01-.88-7.903A5 5 0 1115.9 6L16 6a5 5 0 011 9.9M15 13l-3-3m0 0l-3 3m3-3v12" })),
161
+ React.createElement("p", { className: "fs-text-sm fs-text-gray-600 fs-mb-1" }, uploading ? (React.createElement("span", { className: "fs-text-blue-600" }, "Uploading files...")) : (React.createElement(React.Fragment, null,
162
+ React.createElement("span", { className: "fs-text-blue-600", style: { fontWeight: 500 } }, "Click to upload"),
163
+ ' or drag and drop'))),
164
+ React.createElement("p", { className: "fs-text-xs fs-text-gray-500" },
165
+ multiple ? 'Multiple files supported' : 'Single file only',
166
+ " (Images, PDFs, videos, audio - Max 15MB total)"))),
167
+ selectedFiles.length > 0 && (React.createElement("div", { className: "mt-3 space-y-2" }, selectedFiles.map((file, index) => (React.createElement("div", { key: `${file.name}-${index}`, className: "flex items-center justify-between p-2 bg-gray-50 rounded border border-gray-200" },
168
+ React.createElement("div", { className: "flex items-center space-x-2 flex-1 min-w-0" },
169
+ React.createElement("svg", { className: "w-5 h-5 text-gray-400 flex-shrink-0", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24" },
170
+ React.createElement("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z" })),
171
+ React.createElement("div", { className: "flex-1 min-w-0" },
172
+ React.createElement("p", { className: "text-sm font-medium text-gray-700 truncate" }, file.name),
173
+ React.createElement("p", { className: "text-xs text-gray-500" }, formatFileSize(file.size)))),
174
+ !uploading && (React.createElement("button", { type: "button", onClick: (e) => {
175
+ e.stopPropagation();
176
+ removeFile(index);
177
+ }, className: "ml-2 text-red-500 hover:text-red-700 flex-shrink-0" },
178
+ React.createElement("svg", { className: "w-5 h-5", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24" },
179
+ React.createElement("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M6 18L18 6M6 6l12 12" }))))))))),
180
+ uploadedFiles.length > 0 && (React.createElement("div", { className: "mt-3 space-y-2" }, uploadedFiles.map((fileKey, index) => {
181
+ const filename = fileKey.split('/').pop()?.split('-').slice(2).join('-') || fileKey;
182
+ return (React.createElement("div", { key: index, className: "flex items-center justify-between p-2 bg-green-50 rounded border border-green-200" },
183
+ React.createElement("div", { className: "flex items-center space-x-2 flex-1 min-w-0" },
184
+ React.createElement("svg", { className: "w-5 h-5 text-green-500 flex-shrink-0", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24" },
185
+ React.createElement("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z" })),
186
+ React.createElement("div", { className: "flex-1 min-w-0" },
187
+ React.createElement("p", { className: "text-sm font-medium text-green-700 truncate" }, filename),
188
+ React.createElement("p", { className: "text-xs text-green-600" }, "Uploaded")))));
189
+ }))),
190
+ error && React.createElement("p", { className: "mt-2 text-sm text-red-600" }, error)));
191
+ };
192
+
193
+ /**
194
+ * Inject base styles into the document head (same as embed script)
195
+ */
196
+ function injectBaseStyles() {
197
+ if (typeof document === 'undefined')
198
+ return;
199
+ if (document.getElementById('formsnip-base-styles'))
200
+ return;
201
+ const css = [
202
+ '.fs-flex{display:flex}',
203
+ '.fs-flex-col{flex-direction:column}',
204
+ '.fs-gap-5{gap:1.25rem}',
205
+ '.fs-relative{position:relative}',
206
+ '.fs-absolute{position:absolute}',
207
+ '.fs-right-5{right:1.25rem}',
208
+ '.fs-top-5{top:1.25rem}',
209
+ '.fs-top-half{top:50%}',
210
+ '.fs-translate-y-half{transform:translateY(-50%)}',
211
+ '.fs-w-full{width:100%}',
212
+ '.fs-p-5{padding:1.25rem}',
213
+ '.fs-pr-10{padding-right:2.5rem}',
214
+ '.fs-px-3{padding-left:0.75rem;padding-right:0.75rem}',
215
+ '.fs-py-2{padding-top:0.5rem;padding-bottom:0.5rem}',
216
+ '.fs-rounded-md{border-radius:0.375rem}',
217
+ '.fs-rounded-full{border-radius:9999px}',
218
+ '.fs-h-\\[180px\\]{height:180px}',
219
+ '.fs-resize-none{resize:none}',
220
+ '.fs-text-red-500{color:#ef4444}',
221
+ '.fs-pointer-events-none{pointer-events:none}',
222
+ '.fs-font-medium{font-weight:500}',
223
+ '.fs-text-lg{font-size:1.125rem;line-height:1.75rem}',
224
+ '.fs-border-2{border-width:2px}',
225
+ '.fs-border-dashed{border-style:dashed}',
226
+ '.fs-text-center{text-align:center}',
227
+ '.fs-cursor-pointer{cursor:pointer}',
228
+ '.fs-hover-border-blue-400:hover{border-color:#60a5fa}',
229
+ '.fs-hover-bg-blue-50:hover{background-color:#eff6ff}',
230
+ '.fs-mt-2{margin-top:0.5rem}',
231
+ '.fs-mb-1{margin-bottom:0.25rem}',
232
+ '.fs-text-xs{font-size:0.75rem;line-height:1rem}',
233
+ '.fs-text-sm{font-size:0.875rem;line-height:1.25rem}',
234
+ '.fs-text-gray-400{color:#9ca3af}',
235
+ '.fs-text-gray-500{color:#6b7280}',
236
+ '.fs-text-gray-600{color:#4b5563}',
237
+ '.fs-text-blue-600{color:#2563eb}',
238
+ '.fs-text-green-600{color:#16a34a}',
239
+ '.fs-text-red-600{color:#dc2626}',
240
+ '.fs-bg-gray-50{background-color:#f9fafb}',
241
+ '.fs-bg-green-50{background-color:#f0fdf4}',
242
+ '.fs-border-gray-200{border-color:#e5e7eb}',
243
+ '.fs-border-green-200{border-color:#bbf7d0}',
244
+ '.fs-rounded-lg{border-radius:0.5rem}',
245
+ '.fs-p-2{padding:0.5rem}',
246
+ '.fs-p-6{padding:1.5rem}',
247
+ '.fs-space-y-2>*+*{margin-top:0.5rem}',
248
+ '.fs-flex-1{flex:1 1 0%}',
249
+ '.fs-min-w-0{min-width:0}',
250
+ '.fs-truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}',
251
+ '.fs-flex-shrink-0{flex-shrink:0}',
252
+ '.fs-items-center{align-items:center}',
253
+ '.fs-justify-between{justify-content:space-between}',
254
+ '.fs-space-x-2>*+*{margin-left:0.5rem}',
255
+ ].join('');
256
+ const style = document.createElement('style');
257
+ style.id = 'formsnip-base-styles';
258
+ style.type = 'text/css';
259
+ style.appendChild(document.createTextNode(css));
260
+ document.head.appendChild(style);
261
+ }
262
+ /**
263
+ * Apply embed styles to an element (same logic as embed script)
264
+ */
265
+ function applyStyles(styles, customStyles) {
266
+ if (!customStyles)
267
+ return styles;
268
+ const result = { ...styles };
269
+ if (customStyles.backgroundColor) {
270
+ result.backgroundColor = customStyles.backgroundColor;
271
+ }
272
+ if (customStyles.color) {
273
+ result.color = customStyles.color;
274
+ }
275
+ if (customStyles.borderColor) {
276
+ result.borderColor = customStyles.borderColor;
277
+ result.border = `1px solid ${customStyles.borderColor}`;
278
+ }
279
+ if (customStyles.borderRadius !== undefined) {
280
+ result.borderRadius = `${customStyles.borderRadius}px`;
281
+ }
282
+ if (customStyles.paddingX !== undefined || customStyles.paddingY !== undefined) {
283
+ const px = customStyles.paddingX !== undefined ? customStyles.paddingX : 0;
284
+ const py = customStyles.paddingY !== undefined ? customStyles.paddingY : 0;
285
+ result.padding = `${py}px ${px}px`;
286
+ }
287
+ return result;
288
+ }
289
+ /**
290
+ * CSS class names matching embed script
291
+ */
292
+ const CLASSES = {
293
+ form: 'fs-flex fs-flex-col fs-gap-5',
294
+ field: '',
295
+ inner: 'fs-relative',
296
+ input: 'fs-p-5 fs-pr-10 fs-w-full fs-rounded-md',
297
+ textarea: 'fs-p-5 fs-pr-10 fs-h-[180px] fs-w-full fs-rounded-md fs-resize-none',
298
+ button: 'fs-p-5 fs-rounded-full fs-font-medium fs-text-lg',
299
+ };
300
+
301
+ const DEFAULT_BASE_URL = 'https://api.formsnip.com';
302
+ const FormSnip = ({ formId, baseUrl = DEFAULT_BASE_URL, onSuccess, onError, className = '', }) => {
303
+ const [form, setForm] = React.useState(null);
304
+ const [formData, setFormData] = React.useState({});
305
+ const [selectedFiles, setSelectedFiles] = React.useState({});
306
+ const [uploadingFiles, setUploadingFiles] = React.useState({});
307
+ const [uploadErrors, setUploadErrors] = React.useState({});
308
+ const [loading, setLoading] = React.useState(true);
309
+ const [error, setError] = React.useState(null);
310
+ const [submitError, setSubmitError] = React.useState(null);
311
+ const [submitSuccess, setSubmitSuccess] = React.useState(false);
312
+ const [isSubmitting, setIsSubmitting] = React.useState(false);
313
+ React.useEffect(() => {
314
+ // Inject base styles on mount (same as embed script)
315
+ injectBaseStyles();
316
+ const fetchForm = async () => {
317
+ try {
318
+ const response = await fetch(`${baseUrl}/forms/get-form/${formId}`);
319
+ if (!response.ok) {
320
+ throw new Error('Failed to load form');
321
+ }
322
+ const json = await response.json();
323
+ if (json.success && json.data) {
324
+ // Form data includes embedStyles from the database
325
+ // These styles are set in the EmbedForm page and stored in the Form model
326
+ setForm(json.data);
327
+ // Initialize form data
328
+ const initialData = json.data.fields.reduce((acc, field) => {
329
+ acc[field.id] = field.type === 'file' ? [] : '';
330
+ return acc;
331
+ }, {});
332
+ setFormData(initialData);
333
+ setSelectedFiles({});
334
+ }
335
+ else {
336
+ setError(json.message || 'Failed to load form');
337
+ }
338
+ }
339
+ catch (err) {
340
+ setError(err.message || 'Failed to load form');
341
+ if (onError) {
342
+ onError(err.message || 'Failed to load form');
343
+ }
344
+ }
345
+ finally {
346
+ setLoading(false);
347
+ }
348
+ };
349
+ fetchForm();
350
+ }, [formId, baseUrl, onError]);
351
+ const handleInputChange = (fieldId, value) => {
352
+ setFormData((prev) => ({
353
+ ...prev,
354
+ [fieldId]: value,
355
+ }));
356
+ };
357
+ const handleFilesChange = async (fieldId, files) => {
358
+ if (files.length === 0) {
359
+ setSelectedFiles((prev) => ({ ...prev, [fieldId]: [] }));
360
+ setFormData((prev) => ({ ...prev, [fieldId]: [] }));
361
+ return;
362
+ }
363
+ setSelectedFiles((prev) => ({ ...prev, [fieldId]: files }));
364
+ setUploadingFiles((prev) => ({ ...prev, [fieldId]: true }));
365
+ setUploadErrors((prev) => {
366
+ const newErrors = { ...prev };
367
+ delete newErrors[fieldId];
368
+ return newErrors;
369
+ });
370
+ const result = await uploadFiles(files, formId, baseUrl);
371
+ setUploadingFiles((prev) => ({ ...prev, [fieldId]: false }));
372
+ if (result.success && result.fileKeys && result.fileKeys.length > 0) {
373
+ const existingFileKeys = Array.isArray(formData[fieldId])
374
+ ? formData[fieldId]
375
+ : [];
376
+ setFormData((prev) => ({
377
+ ...prev,
378
+ [fieldId]: [...existingFileKeys, ...result.fileKeys],
379
+ }));
380
+ }
381
+ else {
382
+ setUploadErrors((prev) => ({
383
+ ...prev,
384
+ [fieldId]: result.errors?.join(', ') || 'Upload failed',
385
+ }));
386
+ }
387
+ };
388
+ const handleSubmit = async (e) => {
389
+ e.preventDefault();
390
+ setSubmitError(null);
391
+ setSubmitSuccess(false);
392
+ setIsSubmitting(true);
393
+ try {
394
+ const response = await fetch(`${baseUrl}/submissions/create-submission/${formId}`, {
395
+ method: 'POST',
396
+ headers: {
397
+ 'Content-Type': 'application/json',
398
+ 'X-Requested-With': 'XMLHttpRequest',
399
+ },
400
+ credentials: 'include',
401
+ body: JSON.stringify(formData),
402
+ });
403
+ const json = await response.json();
404
+ if (response.ok && (json.success === undefined || json.success === true)) {
405
+ setSubmitSuccess(true);
406
+ if (onSuccess) {
407
+ onSuccess(json.data);
408
+ }
409
+ // Reset form
410
+ const emptyData = Object.keys(formData).reduce((acc, key) => {
411
+ const field = form?.fields.find((f) => f.id === key);
412
+ acc[key] = field?.type === 'file' ? [] : '';
413
+ return acc;
414
+ }, {});
415
+ setFormData(emptyData);
416
+ setSelectedFiles({});
417
+ setUploadErrors({});
418
+ }
419
+ else {
420
+ const errorMsg = json.message || 'Submission failed';
421
+ setSubmitError(errorMsg);
422
+ if (onError) {
423
+ onError(errorMsg);
424
+ }
425
+ }
426
+ }
427
+ catch (err) {
428
+ const errorMsg = err.message || 'Failed to submit form';
429
+ setSubmitError(errorMsg);
430
+ if (onError) {
431
+ onError(errorMsg);
432
+ }
433
+ }
434
+ finally {
435
+ setIsSubmitting(false);
436
+ }
437
+ };
438
+ const renderField = (field) => {
439
+ // Use embedStyles from database (set in EmbedForm page)
440
+ const fieldStyles = form?.embedStyles?.field || {};
441
+ const isRequired = field.required === true;
442
+ const commonProps = {
443
+ id: `field-${field.id}`,
444
+ name: field.id,
445
+ value: formData[field.id] || '',
446
+ onChange: (e) => handleInputChange(field.id, e.target.value),
447
+ placeholder: field.placeholder || '',
448
+ required: isRequired,
449
+ style: applyStyles({}, fieldStyles),
450
+ className: field.type === 'textarea' ? CLASSES.textarea : CLASSES.input,
451
+ };
452
+ const wrap = (React.createElement("div", { className: CLASSES.field },
453
+ field.type !== 'checkbox' && field.type !== 'radio' && (React.createElement("label", { htmlFor: `field-${field.id}`, className: "fs-text-sm fs-text-gray-700 fs-mb-1" },
454
+ field.label,
455
+ isRequired && (React.createElement("span", { className: "fs-absolute fs-right-5 fs-top-half fs-translate-y-half fs-text-red-500 fs-pointer-events-none" }, "*")))),
456
+ React.createElement("div", { className: CLASSES.inner }, field.type === 'checkbox' ? (React.createElement("label", { className: "fs-flex fs-items-center" },
457
+ React.createElement("input", { type: "checkbox", id: `field-${field.id}`, name: field.id, checked: String(formData[field.id]) === 'true' || formData[field.id] === 'on', onChange: (e) => handleInputChange(field.id, e.target.checked ? 'true' : 'false'), required: isRequired }),
458
+ React.createElement("span", { style: { marginLeft: '0.5rem' } }, field.label || field.placeholder || 'Check this box'),
459
+ isRequired && (React.createElement("span", { className: "fs-absolute fs-right-5 fs-top-half fs-translate-y-half fs-text-red-500 fs-pointer-events-none" }, "*")))) : field.type === 'radio' ? (React.createElement(React.Fragment, null,
460
+ React.createElement("label", { className: "fs-text-sm fs-text-gray-700 fs-mb-1" }, field.label),
461
+ React.createElement("label", { className: "fs-flex fs-items-center" },
462
+ React.createElement("input", { type: "radio", id: `field-${field.id}-yes`, name: field.id, value: "yes", checked: formData[field.id] === 'yes', onChange: (e) => handleInputChange(field.id, e.target.value), required: isRequired }),
463
+ React.createElement("span", { style: { marginLeft: '0.5rem' } }, " Yes")),
464
+ React.createElement("label", { className: "fs-flex fs-items-center" },
465
+ React.createElement("input", { type: "radio", id: `field-${field.id}-no`, name: field.id, value: "no", checked: formData[field.id] === 'no', onChange: (e) => handleInputChange(field.id, e.target.value), required: isRequired }),
466
+ React.createElement("span", { style: { marginLeft: '0.5rem' } }, " No")),
467
+ isRequired && (React.createElement("span", { className: "fs-absolute fs-right-5 fs-top-half fs-translate-y-half fs-text-red-500 fs-pointer-events-none" }, "*")))) : field.type === 'file' ? (React.createElement(React.Fragment, null,
468
+ React.createElement("label", { htmlFor: `field-${field.id}`, className: "fs-text-sm fs-text-gray-700 fs-mb-1" },
469
+ field.label,
470
+ isRequired && (React.createElement("span", { className: "fs-absolute fs-right-5 fs-top-half fs-translate-y-half fs-text-red-500 fs-pointer-events-none" }, "*"))),
471
+ (() => {
472
+ const uploadedFileKeys = Array.isArray(formData[field.id])
473
+ ? formData[field.id]
474
+ : formData[field.id]
475
+ ? [formData[field.id]]
476
+ : [];
477
+ return (React.createElement(FileUpload, { id: field.id, required: isRequired, disabled: uploadingFiles[field.id], multiple: true, onFilesChange: (files) => handleFilesChange(field.id, files), uploadedFiles: uploadedFileKeys, uploading: uploadingFiles[field.id], error: uploadErrors[field.id] }));
478
+ })())) : field.type === 'textarea' ? (React.createElement(React.Fragment, null,
479
+ React.createElement("textarea", { ...commonProps, rows: 4 }),
480
+ isRequired && (React.createElement("span", { className: "fs-absolute fs-right-5 fs-top-5 fs-text-red-500 fs-pointer-events-none" }, "*")))) : (React.createElement(React.Fragment, null,
481
+ React.createElement("input", { type: field.type || 'text', ...commonProps }),
482
+ isRequired && (React.createElement("span", { className: "fs-absolute fs-right-5 fs-top-half fs-translate-y-half fs-text-red-500 fs-pointer-events-none" }, "*")))))));
483
+ return wrap;
484
+ };
485
+ if (loading) {
486
+ return (React.createElement("div", { className: className },
487
+ React.createElement("div", { className: "fs-text-center", style: { padding: '2rem 0' } },
488
+ React.createElement("p", { className: "fs-text-gray-600" }, "Loading form..."))));
489
+ }
490
+ if (error || !form) {
491
+ return (React.createElement("div", { className: className },
492
+ React.createElement("div", { className: "fs-text-center", style: { padding: '2rem 0' } },
493
+ React.createElement("p", { className: "fs-text-red-600" }, error || 'Form not found'))));
494
+ }
495
+ // Use embedStyles from database (set in EmbedForm page)
496
+ const buttonStyles = form.embedStyles?.button || {};
497
+ return (React.createElement("div", { className: className },
498
+ React.createElement("div", { id: "formsnip-message" }),
499
+ submitError && (React.createElement("div", { className: "fs-px-3 fs-py-2 fs-rounded-md", style: {
500
+ color: '#991b1b',
501
+ background: '#fee2e2',
502
+ border: '1px solid #fecaca',
503
+ marginBottom: '1rem',
504
+ } }, submitError)),
505
+ submitSuccess && (React.createElement("div", { className: "fs-px-3 fs-py-2 fs-rounded-md", style: {
506
+ color: '#166534',
507
+ background: '#dcfce7',
508
+ border: '1px solid #bbf7d0',
509
+ marginBottom: '1rem',
510
+ } }, "Thank you! Your submission has been received.")),
511
+ React.createElement("form", { id: "formsnip-form", onSubmit: handleSubmit, className: CLASSES.form },
512
+ form.fields
513
+ .filter((field) => field.isActive !== false)
514
+ .map((field) => (React.createElement(React.Fragment, { key: field.id }, renderField(field)))),
515
+ React.createElement("button", { type: "submit", disabled: isSubmitting, className: CLASSES.button, style: applyStyles({}, buttonStyles) }, isSubmitting ? 'Submitting...' : form.submitButtonText || 'Submit'))));
516
+ };
517
+
518
+ exports.ALLOWED_FILE_EXTENSIONS = ALLOWED_FILE_EXTENSIONS;
519
+ exports.FileUpload = FileUpload;
520
+ exports.FormSnip = FormSnip;
521
+ exports.MAX_TOTAL_FILE_SIZE = MAX_TOTAL_FILE_SIZE;
522
+ exports.uploadFile = uploadFile;
523
+ exports.uploadFiles = uploadFiles;
524
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sources":["../src/utils/upload.ts","../src/components/FileUpload.tsx","../src/utils/styles.ts","../src/FormSnip.tsx"],"sourcesContent":["const ALLOWED_FILE_EXTENSIONS = '.jpg,.jpeg,.png,.gif,.webp,.svg,.pdf,.mp4,.mpeg,.mov,.avi,.webm,.mkv,.mp3,.wav,.ogg,.aac,.flac';\nconst MAX_TOTAL_FILE_SIZE = 15 * 1024 * 1024; // 15MB\n\nexport interface UploadResult {\n success: boolean;\n fileKey?: string;\n error?: string;\n}\n\nexport interface UploadMultipleResult {\n success: boolean;\n fileKeys?: string[];\n errors?: string[];\n}\n\n/**\n * Upload a file to R2 via presigned URL\n */\nexport async function uploadFile(\n file: File,\n formId: string,\n baseUrl: string\n): Promise<UploadResult> {\n try {\n // Step 1: Get presigned upload URL\n const signResponse = await fetch(`${baseUrl}/uploads/sign`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n },\n credentials: 'include',\n body: JSON.stringify({\n filename: file.name,\n contentType: file.type,\n size: file.size,\n formId,\n }),\n });\n\n if (!signResponse.ok) {\n return {\n success: false,\n error: 'Failed to get upload URL',\n };\n }\n\n const signData = await signResponse.json();\n if (!signData.success || !signData.data) {\n return {\n success: false,\n error: signData.message || 'Invalid upload URL response',\n };\n }\n\n const { uploadUrl, fileKey } = signData.data;\n\n // Step 2: Upload file directly to R2\n const uploadResponse = await fetch(uploadUrl, {\n method: 'PUT',\n body: file,\n headers: {\n 'Content-Type': file.type,\n },\n });\n\n if (!uploadResponse.ok) {\n return {\n success: false,\n error: `Upload failed: ${uploadResponse.statusText}`,\n };\n }\n\n return {\n success: true,\n fileKey,\n };\n } catch (error) {\n return {\n success: false,\n error: error instanceof Error ? error.message : 'Unknown error occurred',\n };\n }\n}\n\n/**\n * Upload multiple files to R2\n */\nexport async function uploadFiles(\n files: File[],\n formId: string,\n baseUrl: string\n): Promise<UploadMultipleResult> {\n // Check total size\n const totalSize = files.reduce((sum, file) => sum + file.size, 0);\n if (totalSize > MAX_TOTAL_FILE_SIZE) {\n return {\n success: false,\n errors: [`Total file size exceeds 15MB limit per submission`],\n };\n }\n\n const results = await Promise.allSettled(\n files.map((file) => uploadFile(file, formId, baseUrl))\n );\n\n const fileKeys: string[] = [];\n const errors: string[] = [];\n\n results.forEach((result, index) => {\n if (result.status === 'fulfilled' && result.value.success && result.value.fileKey) {\n fileKeys.push(result.value.fileKey);\n } else {\n const error =\n result.status === 'fulfilled'\n ? result.value.error || 'Upload failed'\n : result.reason?.message || 'Upload failed';\n errors.push(`${files[index].name}: ${error}`);\n }\n });\n\n return {\n success: fileKeys.length > 0,\n fileKeys: fileKeys.length > 0 ? fileKeys : undefined,\n errors: errors.length > 0 ? errors : undefined,\n };\n}\n\nexport { ALLOWED_FILE_EXTENSIONS, MAX_TOTAL_FILE_SIZE };\n","import React, { useRef, useState } from 'react';\nimport { ALLOWED_FILE_EXTENSIONS } from '../utils/upload';\nimport { CLASSES } from '../utils/styles';\n\ninterface FileUploadProps {\n id: string;\n label?: string;\n required?: boolean;\n disabled?: boolean;\n multiple?: boolean;\n onFilesChange: (files: File[]) => void;\n uploadedFiles?: string[];\n uploading?: boolean;\n error?: string;\n className?: string;\n}\n\nexport const FileUpload: React.FC<FileUploadProps> = ({\n id,\n label,\n required = false,\n disabled = false,\n multiple = true,\n onFilesChange,\n uploadedFiles = [],\n uploading = false,\n error,\n className = '',\n}) => {\n const fileInputRef = useRef<HTMLInputElement>(null);\n const [selectedFiles, setSelectedFiles] = useState<File[]>([]);\n\n const handleFileSelect = (e: React.ChangeEvent<HTMLInputElement>) => {\n const files = Array.from(e.target.files || []);\n\n if (multiple) {\n setSelectedFiles((prev) => [...prev, ...files]);\n onFilesChange([...selectedFiles, ...files]);\n } else {\n setSelectedFiles(files);\n onFilesChange(files);\n }\n };\n\n const removeFile = (index: number) => {\n const newFiles = selectedFiles.filter((_, i) => i !== index);\n setSelectedFiles(newFiles);\n onFilesChange(newFiles);\n if (fileInputRef.current) {\n fileInputRef.current.value = '';\n }\n };\n\n const formatFileSize = (bytes: number): string => {\n if (bytes === 0) return '0 Bytes';\n const k = 1024;\n const sizes = ['Bytes', 'KB', 'MB', 'GB'];\n const i = Math.floor(Math.log(bytes) / Math.log(k));\n return Math.round((bytes / Math.pow(k, i)) * 100) / 100 + ' ' + sizes[i];\n };\n\n const handleDrop = (e: React.DragEvent<HTMLDivElement>) => {\n e.preventDefault();\n e.stopPropagation();\n\n if (disabled || uploading) return;\n\n const files = Array.from(e.dataTransfer.files);\n\n if (multiple) {\n setSelectedFiles((prev) => [...prev, ...files]);\n onFilesChange([...selectedFiles, ...files]);\n } else {\n setSelectedFiles(files.slice(0, 1));\n onFilesChange(files.slice(0, 1));\n }\n };\n\n const handleDragOver = (e: React.DragEvent<HTMLDivElement>) => {\n e.preventDefault();\n e.stopPropagation();\n };\n\n return (\n <div className={className}>\n {label && (\n <label className=\"fs-text-sm fs-text-gray-700 fs-mb-1\">\n {label}\n {required && <span className=\"fs-text-red-500\" style={{ marginLeft: '0.25rem' }}>*</span>}\n </label>\n )}\n\n <div\n onDrop={handleDrop}\n onDragOver={handleDragOver}\n className={`fs-border-2 fs-border-dashed fs-rounded-lg fs-p-6 fs-text-center ${\n disabled || uploading ? '' : 'fs-cursor-pointer fs-hover-border-blue-400 fs-hover-bg-blue-50'\n }`}\n style={{\n borderColor: '#d1d5db',\n backgroundColor: disabled || uploading ? '#f9fafb' : '#ffffff',\n cursor: disabled || uploading ? 'not-allowed' : 'pointer',\n }}\n onClick={() => !disabled && !uploading && fileInputRef.current?.click()}\n >\n <input\n ref={fileInputRef}\n type=\"file\"\n id={id}\n multiple={multiple}\n onChange={handleFileSelect}\n className=\"hidden\"\n disabled={disabled || uploading}\n required={required && selectedFiles.length === 0 && uploadedFiles.length === 0}\n accept={ALLOWED_FILE_EXTENSIONS}\n />\n\n <div className=\"fs-flex fs-flex-col fs-items-center\">\n <svg\n className=\"fs-text-gray-400\"\n style={{ width: '3rem', height: '3rem', margin: '0 auto 0.5rem' }}\n fill=\"none\"\n stroke=\"currentColor\"\n viewBox=\"0 0 24 24\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M7 16a4 4 0 01-.88-7.903A5 5 0 1115.9 6L16 6a5 5 0 011 9.9M15 13l-3-3m0 0l-3 3m3-3v12\"\n />\n </svg>\n <p className=\"fs-text-sm fs-text-gray-600 fs-mb-1\">\n {uploading ? (\n <span className=\"fs-text-blue-600\">Uploading files...</span>\n ) : (\n <>\n <span className=\"fs-text-blue-600\" style={{ fontWeight: 500 }}>Click to upload</span>\n {' or drag and drop'}\n </>\n )}\n </p>\n <p className=\"fs-text-xs fs-text-gray-500\">\n {multiple ? 'Multiple files supported' : 'Single file only'} (Images, PDFs, videos,\n audio - Max 15MB total)\n </p>\n </div>\n </div>\n\n {selectedFiles.length > 0 && (\n <div className=\"mt-3 space-y-2\">\n {selectedFiles.map((file, index) => (\n <div\n key={`${file.name}-${index}`}\n className=\"flex items-center justify-between p-2 bg-gray-50 rounded border border-gray-200\"\n >\n <div className=\"flex items-center space-x-2 flex-1 min-w-0\">\n <svg\n className=\"w-5 h-5 text-gray-400 flex-shrink-0\"\n fill=\"none\"\n stroke=\"currentColor\"\n viewBox=\"0 0 24 24\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z\"\n />\n </svg>\n <div className=\"flex-1 min-w-0\">\n <p className=\"text-sm font-medium text-gray-700 truncate\">{file.name}</p>\n <p className=\"text-xs text-gray-500\">{formatFileSize(file.size)}</p>\n </div>\n </div>\n {!uploading && (\n <button\n type=\"button\"\n onClick={(e) => {\n e.stopPropagation();\n removeFile(index);\n }}\n className=\"ml-2 text-red-500 hover:text-red-700 flex-shrink-0\"\n >\n <svg className=\"w-5 h-5\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M6 18L18 6M6 6l12 12\"\n />\n </svg>\n </button>\n )}\n </div>\n ))}\n </div>\n )}\n\n {uploadedFiles.length > 0 && (\n <div className=\"mt-3 space-y-2\">\n {uploadedFiles.map((fileKey, index) => {\n const filename = fileKey.split('/').pop()?.split('-').slice(2).join('-') || fileKey;\n return (\n <div\n key={index}\n className=\"flex items-center justify-between p-2 bg-green-50 rounded border border-green-200\"\n >\n <div className=\"flex items-center space-x-2 flex-1 min-w-0\">\n <svg\n className=\"w-5 h-5 text-green-500 flex-shrink-0\"\n fill=\"none\"\n stroke=\"currentColor\"\n viewBox=\"0 0 24 24\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z\"\n />\n </svg>\n <div className=\"flex-1 min-w-0\">\n <p className=\"text-sm font-medium text-green-700 truncate\">{filename}</p>\n <p className=\"text-xs text-green-600\">Uploaded</p>\n </div>\n </div>\n </div>\n );\n })}\n </div>\n )}\n\n {error && <p className=\"mt-2 text-sm text-red-600\">{error}</p>}\n </div>\n );\n};\n","/**\n * Inject base styles into the document head (same as embed script)\n */\nexport function injectBaseStyles(): void {\n if (typeof document === 'undefined') return;\n if (document.getElementById('formsnip-base-styles')) return;\n\n const css = [\n '.fs-flex{display:flex}',\n '.fs-flex-col{flex-direction:column}',\n '.fs-gap-5{gap:1.25rem}',\n '.fs-relative{position:relative}',\n '.fs-absolute{position:absolute}',\n '.fs-right-5{right:1.25rem}',\n '.fs-top-5{top:1.25rem}',\n '.fs-top-half{top:50%}',\n '.fs-translate-y-half{transform:translateY(-50%)}',\n '.fs-w-full{width:100%}',\n '.fs-p-5{padding:1.25rem}',\n '.fs-pr-10{padding-right:2.5rem}',\n '.fs-px-3{padding-left:0.75rem;padding-right:0.75rem}',\n '.fs-py-2{padding-top:0.5rem;padding-bottom:0.5rem}',\n '.fs-rounded-md{border-radius:0.375rem}',\n '.fs-rounded-full{border-radius:9999px}',\n '.fs-h-\\\\[180px\\\\]{height:180px}',\n '.fs-resize-none{resize:none}',\n '.fs-text-red-500{color:#ef4444}',\n '.fs-pointer-events-none{pointer-events:none}',\n '.fs-font-medium{font-weight:500}',\n '.fs-text-lg{font-size:1.125rem;line-height:1.75rem}',\n '.fs-border-2{border-width:2px}',\n '.fs-border-dashed{border-style:dashed}',\n '.fs-text-center{text-align:center}',\n '.fs-cursor-pointer{cursor:pointer}',\n '.fs-hover-border-blue-400:hover{border-color:#60a5fa}',\n '.fs-hover-bg-blue-50:hover{background-color:#eff6ff}',\n '.fs-mt-2{margin-top:0.5rem}',\n '.fs-mb-1{margin-bottom:0.25rem}',\n '.fs-text-xs{font-size:0.75rem;line-height:1rem}',\n '.fs-text-sm{font-size:0.875rem;line-height:1.25rem}',\n '.fs-text-gray-400{color:#9ca3af}',\n '.fs-text-gray-500{color:#6b7280}',\n '.fs-text-gray-600{color:#4b5563}',\n '.fs-text-blue-600{color:#2563eb}',\n '.fs-text-green-600{color:#16a34a}',\n '.fs-text-red-600{color:#dc2626}',\n '.fs-bg-gray-50{background-color:#f9fafb}',\n '.fs-bg-green-50{background-color:#f0fdf4}',\n '.fs-border-gray-200{border-color:#e5e7eb}',\n '.fs-border-green-200{border-color:#bbf7d0}',\n '.fs-rounded-lg{border-radius:0.5rem}',\n '.fs-p-2{padding:0.5rem}',\n '.fs-p-6{padding:1.5rem}',\n '.fs-space-y-2>*+*{margin-top:0.5rem}',\n '.fs-flex-1{flex:1 1 0%}',\n '.fs-min-w-0{min-width:0}',\n '.fs-truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}',\n '.fs-flex-shrink-0{flex-shrink:0}',\n '.fs-items-center{align-items:center}',\n '.fs-justify-between{justify-content:space-between}',\n '.fs-space-x-2>*+*{margin-left:0.5rem}',\n ].join('');\n\n const style = document.createElement('style');\n style.id = 'formsnip-base-styles';\n style.type = 'text/css';\n style.appendChild(document.createTextNode(css));\n document.head.appendChild(style);\n}\n\n/**\n * Apply embed styles to an element (same logic as embed script)\n */\nexport function applyStyles(\n styles: React.CSSProperties,\n customStyles?: {\n backgroundColor?: string;\n color?: string;\n borderColor?: string;\n borderRadius?: number;\n paddingX?: number;\n paddingY?: number;\n }\n): React.CSSProperties {\n if (!customStyles) return styles;\n\n const result = { ...styles };\n\n if (customStyles.backgroundColor) {\n result.backgroundColor = customStyles.backgroundColor;\n }\n if (customStyles.color) {\n result.color = customStyles.color;\n }\n if (customStyles.borderColor) {\n result.borderColor = customStyles.borderColor;\n result.border = `1px solid ${customStyles.borderColor}`;\n }\n if (customStyles.borderRadius !== undefined) {\n result.borderRadius = `${customStyles.borderRadius}px`;\n }\n if (customStyles.paddingX !== undefined || customStyles.paddingY !== undefined) {\n const px = customStyles.paddingX !== undefined ? customStyles.paddingX : 0;\n const py = customStyles.paddingY !== undefined ? customStyles.paddingY : 0;\n result.padding = `${py}px ${px}px`;\n }\n\n return result;\n}\n\n/**\n * CSS class names matching embed script\n */\nexport const CLASSES = {\n form: 'fs-flex fs-flex-col fs-gap-5',\n field: '',\n inner: 'fs-relative',\n input: 'fs-p-5 fs-pr-10 fs-w-full fs-rounded-md',\n textarea: 'fs-p-5 fs-pr-10 fs-h-[180px] fs-w-full fs-rounded-md fs-resize-none',\n button: 'fs-p-5 fs-rounded-full fs-font-medium fs-text-lg',\n};\n","import React, { useState, useEffect } from 'react';\nimport { Form, FormSnipProps, SubmissionResponse } from './types';\nimport { uploadFiles } from './utils/upload';\nimport { FileUpload } from './components/FileUpload';\nimport { injectBaseStyles, applyStyles, CLASSES } from './utils/styles';\n\nconst DEFAULT_BASE_URL = 'https://api.formsnip.com';\n\nexport const FormSnip: React.FC<FormSnipProps> = ({\n formId,\n baseUrl = DEFAULT_BASE_URL,\n onSuccess,\n onError,\n className = '',\n}) => {\n const [form, setForm] = useState<Form | null>(null);\n const [formData, setFormData] = useState<Record<string, string | string[]>>({});\n const [selectedFiles, setSelectedFiles] = useState<Record<string, File[]>>({});\n const [uploadingFiles, setUploadingFiles] = useState<Record<string, boolean>>({});\n const [uploadErrors, setUploadErrors] = useState<Record<string, string>>({});\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState<string | null>(null);\n const [submitError, setSubmitError] = useState<string | null>(null);\n const [submitSuccess, setSubmitSuccess] = useState(false);\n const [isSubmitting, setIsSubmitting] = useState(false);\n\n useEffect(() => {\n // Inject base styles on mount (same as embed script)\n injectBaseStyles();\n\n const fetchForm = async () => {\n try {\n const response = await fetch(`${baseUrl}/forms/get-form/${formId}`);\n if (!response.ok) {\n throw new Error('Failed to load form');\n }\n const json = await response.json();\n if (json.success && json.data) {\n // Form data includes embedStyles from the database\n // These styles are set in the EmbedForm page and stored in the Form model\n setForm(json.data);\n // Initialize form data\n const initialData = json.data.fields.reduce(\n (acc: Record<string, string | string[]>, field: Form['fields'][0]) => {\n acc[field.id] = field.type === 'file' ? [] : '';\n return acc;\n },\n {}\n );\n setFormData(initialData);\n setSelectedFiles({});\n } else {\n setError(json.message || 'Failed to load form');\n }\n } catch (err: any) {\n setError(err.message || 'Failed to load form');\n if (onError) {\n onError(err.message || 'Failed to load form');\n }\n } finally {\n setLoading(false);\n }\n };\n\n fetchForm();\n }, [formId, baseUrl, onError]);\n\n const handleInputChange = (fieldId: string, value: string) => {\n setFormData((prev) => ({\n ...prev,\n [fieldId]: value,\n }));\n };\n\n const handleFilesChange = async (fieldId: string, files: File[]) => {\n if (files.length === 0) {\n setSelectedFiles((prev) => ({ ...prev, [fieldId]: [] }));\n setFormData((prev) => ({ ...prev, [fieldId]: [] }));\n return;\n }\n\n setSelectedFiles((prev) => ({ ...prev, [fieldId]: files }));\n setUploadingFiles((prev) => ({ ...prev, [fieldId]: true }));\n setUploadErrors((prev) => {\n const newErrors = { ...prev };\n delete newErrors[fieldId];\n return newErrors;\n });\n\n const result = await uploadFiles(files, formId, baseUrl);\n\n setUploadingFiles((prev) => ({ ...prev, [fieldId]: false }));\n\n if (result.success && result.fileKeys && result.fileKeys.length > 0) {\n const existingFileKeys = Array.isArray(formData[fieldId])\n ? (formData[fieldId] as string[])\n : [];\n setFormData((prev) => ({\n ...prev,\n [fieldId]: [...existingFileKeys, ...result.fileKeys!],\n }));\n } else {\n setUploadErrors((prev) => ({\n ...prev,\n [fieldId]: result.errors?.join(', ') || 'Upload failed',\n }));\n }\n };\n\n const handleSubmit = async (e: React.FormEvent<HTMLFormElement>) => {\n e.preventDefault();\n setSubmitError(null);\n setSubmitSuccess(false);\n setIsSubmitting(true);\n\n try {\n const response = await fetch(`${baseUrl}/submissions/create-submission/${formId}`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'X-Requested-With': 'XMLHttpRequest',\n },\n credentials: 'include',\n body: JSON.stringify(formData),\n });\n\n const json: SubmissionResponse = await response.json();\n\n if (response.ok && (json.success === undefined || json.success === true)) {\n setSubmitSuccess(true);\n if (onSuccess) {\n onSuccess(json.data);\n }\n // Reset form\n const emptyData = Object.keys(formData).reduce(\n (acc: Record<string, string | string[]>, key) => {\n const field = form?.fields.find((f) => f.id === key);\n acc[key] = field?.type === 'file' ? [] : '';\n return acc;\n },\n {}\n );\n setFormData(emptyData);\n setSelectedFiles({});\n setUploadErrors({});\n } else {\n const errorMsg = json.message || 'Submission failed';\n setSubmitError(errorMsg);\n if (onError) {\n onError(errorMsg);\n }\n }\n } catch (err: any) {\n const errorMsg = err.message || 'Failed to submit form';\n setSubmitError(errorMsg);\n if (onError) {\n onError(errorMsg);\n }\n } finally {\n setIsSubmitting(false);\n }\n };\n\n const renderField = (field: Form['fields'][0]) => {\n // Use embedStyles from database (set in EmbedForm page)\n const fieldStyles = form?.embedStyles?.field || {};\n const isRequired = field.required === true;\n\n const commonProps = {\n id: `field-${field.id}`,\n name: field.id,\n value: (formData[field.id] as string) || '',\n onChange: (e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) =>\n handleInputChange(field.id, e.target.value),\n placeholder: field.placeholder || '',\n required: isRequired,\n style: applyStyles({}, fieldStyles),\n className: field.type === 'textarea' ? CLASSES.textarea : CLASSES.input,\n };\n\n const wrap = (\n <div className={CLASSES.field}>\n {field.type !== 'checkbox' && field.type !== 'radio' && (\n <label htmlFor={`field-${field.id}`} className=\"fs-text-sm fs-text-gray-700 fs-mb-1\">\n {field.label}\n {isRequired && (\n <span className=\"fs-absolute fs-right-5 fs-top-half fs-translate-y-half fs-text-red-500 fs-pointer-events-none\">\n *\n </span>\n )}\n </label>\n )}\n <div className={CLASSES.inner}>\n {field.type === 'checkbox' ? (\n <label className=\"fs-flex fs-items-center\">\n <input\n type=\"checkbox\"\n id={`field-${field.id}`}\n name={field.id}\n checked={String(formData[field.id]) === 'true' || formData[field.id] === 'on'}\n onChange={(e) => handleInputChange(field.id, e.target.checked ? 'true' : 'false')}\n required={isRequired}\n />\n <span style={{ marginLeft: '0.5rem' }}>{field.label || field.placeholder || 'Check this box'}</span>\n {isRequired && (\n <span className=\"fs-absolute fs-right-5 fs-top-half fs-translate-y-half fs-text-red-500 fs-pointer-events-none\">\n *\n </span>\n )}\n </label>\n ) : field.type === 'radio' ? (\n <>\n <label className=\"fs-text-sm fs-text-gray-700 fs-mb-1\">{field.label}</label>\n <label className=\"fs-flex fs-items-center\">\n <input\n type=\"radio\"\n id={`field-${field.id}-yes`}\n name={field.id}\n value=\"yes\"\n checked={formData[field.id] === 'yes'}\n onChange={(e) => handleInputChange(field.id, e.target.value)}\n required={isRequired}\n />\n <span style={{ marginLeft: '0.5rem' }}> Yes</span>\n </label>\n <label className=\"fs-flex fs-items-center\">\n <input\n type=\"radio\"\n id={`field-${field.id}-no`}\n name={field.id}\n value=\"no\"\n checked={formData[field.id] === 'no'}\n onChange={(e) => handleInputChange(field.id, e.target.value)}\n required={isRequired}\n />\n <span style={{ marginLeft: '0.5rem' }}> No</span>\n </label>\n {isRequired && (\n <span className=\"fs-absolute fs-right-5 fs-top-half fs-translate-y-half fs-text-red-500 fs-pointer-events-none\">\n *\n </span>\n )}\n </>\n ) : field.type === 'file' ? (\n <>\n <label htmlFor={`field-${field.id}`} className=\"fs-text-sm fs-text-gray-700 fs-mb-1\">\n {field.label}\n {isRequired && (\n <span className=\"fs-absolute fs-right-5 fs-top-half fs-translate-y-half fs-text-red-500 fs-pointer-events-none\">\n *\n </span>\n )}\n </label>\n {(() => {\n const uploadedFileKeys = Array.isArray(formData[field.id])\n ? (formData[field.id] as string[])\n : formData[field.id]\n ? [formData[field.id] as string]\n : [];\n\n return (\n <FileUpload\n id={field.id}\n required={isRequired}\n disabled={uploadingFiles[field.id]}\n multiple={true}\n onFilesChange={(files) => handleFilesChange(field.id, files)}\n uploadedFiles={uploadedFileKeys}\n uploading={uploadingFiles[field.id]}\n error={uploadErrors[field.id]}\n />\n );\n })()}\n </>\n ) : field.type === 'textarea' ? (\n <>\n <textarea {...commonProps} rows={4} />\n {isRequired && (\n <span className=\"fs-absolute fs-right-5 fs-top-5 fs-text-red-500 fs-pointer-events-none\">\n *\n </span>\n )}\n </>\n ) : (\n <>\n <input type={field.type || 'text'} {...commonProps} />\n {isRequired && (\n <span className=\"fs-absolute fs-right-5 fs-top-half fs-translate-y-half fs-text-red-500 fs-pointer-events-none\">\n *\n </span>\n )}\n </>\n )}\n </div>\n </div>\n );\n\n return wrap;\n };\n\n if (loading) {\n return (\n <div className={className}>\n <div className=\"fs-text-center\" style={{ padding: '2rem 0' }}>\n <p className=\"fs-text-gray-600\">Loading form...</p>\n </div>\n </div>\n );\n }\n\n if (error || !form) {\n return (\n <div className={className}>\n <div className=\"fs-text-center\" style={{ padding: '2rem 0' }}>\n <p className=\"fs-text-red-600\">{error || 'Form not found'}</p>\n </div>\n </div>\n );\n }\n\n // Use embedStyles from database (set in EmbedForm page)\n const buttonStyles = form.embedStyles?.button || {};\n\n return (\n <div className={className}>\n <div id=\"formsnip-message\"></div>\n {submitError && (\n <div\n className=\"fs-px-3 fs-py-2 fs-rounded-md\"\n style={{\n color: '#991b1b',\n background: '#fee2e2',\n border: '1px solid #fecaca',\n marginBottom: '1rem',\n }}\n >\n {submitError}\n </div>\n )}\n\n {submitSuccess && (\n <div\n className=\"fs-px-3 fs-py-2 fs-rounded-md\"\n style={{\n color: '#166534',\n background: '#dcfce7',\n border: '1px solid #bbf7d0',\n marginBottom: '1rem',\n }}\n >\n Thank you! Your submission has been received.\n </div>\n )}\n\n <form id=\"formsnip-form\" onSubmit={handleSubmit} className={CLASSES.form}>\n {form.fields\n .filter((field) => field.isActive !== false)\n .map((field) => (\n <React.Fragment key={field.id}>{renderField(field)}</React.Fragment>\n ))}\n\n <button\n type=\"submit\"\n disabled={isSubmitting}\n className={CLASSES.button}\n style={applyStyles({}, buttonStyles)}\n >\n {isSubmitting ? 'Submitting...' : form.submitButtonText || 'Submit'}\n </button>\n </form>\n </div>\n );\n};\n"],"names":["useRef","useState","useEffect"],"mappings":"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"}