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