@gofranz/formshive-submit 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 +619 -0
- package/dist/client.d.ts +22 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/field-errors.d.ts +95 -0
- package/dist/field-errors.d.ts.map +1 -0
- package/dist/file-handler.d.ts +43 -0
- package/dist/file-handler.d.ts.map +1 -0
- package/dist/formshive-submit.cjs +1714 -0
- package/dist/formshive-submit.cjs.map +1 -0
- package/dist/formshive-submit.esm.js +1644 -0
- package/dist/formshive-submit.esm.js.map +1 -0
- package/dist/formshive-submit.js +1720 -0
- package/dist/formshive-submit.js.map +1 -0
- package/dist/formshive-submit.min.js +2 -0
- package/dist/formshive-submit.min.js.map +1 -0
- package/dist/main.d.ts +66 -0
- package/dist/main.d.ts.map +1 -0
- package/dist/retry.d.ts +73 -0
- package/dist/retry.d.ts.map +1 -0
- package/dist/submit.d.ts +49 -0
- package/dist/submit.d.ts.map +1 -0
- package/dist/test.html +1074 -0
- package/dist/types.d.ts +145 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/utils.d.ts +115 -0
- package/dist/utils.d.ts.map +1 -0
- package/package.json +52 -0
package/README.md
ADDED
|
@@ -0,0 +1,619 @@
|
|
|
1
|
+
# Formshive Submit
|
|
2
|
+
|
|
3
|
+
A robust JavaScript/TypeScript library for submitting forms to Formshive with advanced features including retry logic, file uploads, progress tracking, and flexible HTTP client support.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- 🚀 **Easy to use** - Simple API for form submissions
|
|
8
|
+
- 🔄 **Smart retry logic** - Exponential backoff with configurable settings
|
|
9
|
+
- 📁 **File upload support** - Handle single and multiple file uploads with progress tracking
|
|
10
|
+
- 🔌 **Flexible HTTP clients** - Works with both fetch and axios
|
|
11
|
+
- 💪 **TypeScript support** - Fully typed for better development experience
|
|
12
|
+
- 🎯 **Callback system** - Success, error, retry, and progress callbacks
|
|
13
|
+
- 🔧 **Configurable** - Extensive configuration options for different use cases
|
|
14
|
+
- 🌐 **Universal** - Works in browser and Node.js environments
|
|
15
|
+
- ⚡ **Lightweight** - Minimal dependencies, tree-shakeable
|
|
16
|
+
|
|
17
|
+
## Installation
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
npm install @gofranz/formshive-submit
|
|
21
|
+
# or
|
|
22
|
+
yarn add @gofranz/formshive-submit
|
|
23
|
+
# or
|
|
24
|
+
pnpm add @gofranz/formshive-submit
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
For browser usage via CDN:
|
|
28
|
+
|
|
29
|
+
```html
|
|
30
|
+
<script src="https://unpkg.com/@gofranz/formshive-submit/dist/formshive-submit.min.js"></script>
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## Quick Start
|
|
34
|
+
|
|
35
|
+
### Basic Form Submission
|
|
36
|
+
|
|
37
|
+
```javascript
|
|
38
|
+
import { submitFormSimple } from '@gofranz/formshive-submit';
|
|
39
|
+
|
|
40
|
+
// Simple form submission
|
|
41
|
+
const response = await submitFormSimple('your-form-id', {
|
|
42
|
+
name: 'John Doe',
|
|
43
|
+
email: 'john@example.com',
|
|
44
|
+
message: 'Hello from Formshive Submit!'
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
console.log('Form submitted successfully:', response);
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
### With Error Handling
|
|
51
|
+
|
|
52
|
+
```javascript
|
|
53
|
+
import { submitForm } from '@gofranz/formshive-submit';
|
|
54
|
+
|
|
55
|
+
try {
|
|
56
|
+
const response = await submitForm({
|
|
57
|
+
formId: 'your-form-id',
|
|
58
|
+
data: {
|
|
59
|
+
name: 'Jane Smith',
|
|
60
|
+
email: 'jane@example.com',
|
|
61
|
+
subject: 'Contact Form',
|
|
62
|
+
message: 'This is a test message.'
|
|
63
|
+
},
|
|
64
|
+
callbacks: {
|
|
65
|
+
onSuccess: (response) => {
|
|
66
|
+
console.log('Success!', response);
|
|
67
|
+
},
|
|
68
|
+
onError: (error) => {
|
|
69
|
+
console.error('Submission failed:', error);
|
|
70
|
+
},
|
|
71
|
+
onRetry: (attempt, maxAttempts) => {
|
|
72
|
+
console.log(`Retrying... ${attempt}/${maxAttempts}`);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
});
|
|
76
|
+
} catch (error) {
|
|
77
|
+
console.error('Final error:', error);
|
|
78
|
+
}
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
## File Upload
|
|
82
|
+
|
|
83
|
+
### Single File Upload
|
|
84
|
+
|
|
85
|
+
```javascript
|
|
86
|
+
import { submitForm } from '@gofranz/formshive-submit';
|
|
87
|
+
|
|
88
|
+
const fileInput = document.getElementById('fileInput');
|
|
89
|
+
const formData = new FormData();
|
|
90
|
+
|
|
91
|
+
formData.append('name', 'John Doe');
|
|
92
|
+
formData.append('file', fileInput.files[0]);
|
|
93
|
+
|
|
94
|
+
const response = await submitForm({
|
|
95
|
+
formId: 'file-upload-form',
|
|
96
|
+
data: formData,
|
|
97
|
+
callbacks: {
|
|
98
|
+
onProgress: (percent, loaded, total) => {
|
|
99
|
+
console.log(`Upload progress: ${percent}%`);
|
|
100
|
+
document.getElementById('progress').style.width = percent + '%';
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
});
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
### Multiple Files with Validation
|
|
107
|
+
|
|
108
|
+
```javascript
|
|
109
|
+
import { submitForm } from '@gofranz/formshive-submit';
|
|
110
|
+
|
|
111
|
+
const files = document.getElementById('multipleFiles').files;
|
|
112
|
+
const formData = new FormData();
|
|
113
|
+
|
|
114
|
+
formData.append('title', 'Multiple File Upload');
|
|
115
|
+
for (let i = 0; i < files.length; i++) {
|
|
116
|
+
formData.append(`file_${i}`, files[i]);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
const response = await submitForm({
|
|
120
|
+
formId: 'multi-file-form',
|
|
121
|
+
data: formData,
|
|
122
|
+
files: {
|
|
123
|
+
maxFileSize: 10 * 1024 * 1024, // 10MB per file
|
|
124
|
+
allowedTypes: ['image/jpeg', 'image/png', 'application/pdf'],
|
|
125
|
+
trackProgress: true
|
|
126
|
+
},
|
|
127
|
+
callbacks: {
|
|
128
|
+
onProgress: (percent) => updateProgressBar(percent)
|
|
129
|
+
}
|
|
130
|
+
});
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
## Configuration Options
|
|
134
|
+
|
|
135
|
+
### Retry Configuration
|
|
136
|
+
|
|
137
|
+
```javascript
|
|
138
|
+
import { submitForm, RetryPresets } from '@gofranz/formshive-submit';
|
|
139
|
+
|
|
140
|
+
const response = await submitForm({
|
|
141
|
+
formId: 'your-form-id',
|
|
142
|
+
data: { message: 'Hello' },
|
|
143
|
+
retry: {
|
|
144
|
+
maxAttempts: 5,
|
|
145
|
+
baseDelay: 2000, // 2 seconds
|
|
146
|
+
maxDelay: 30000, // 30 seconds max
|
|
147
|
+
enableJitter: true, // Add randomness to delays
|
|
148
|
+
backoffMultiplier: 2 // Exponential backoff factor
|
|
149
|
+
}
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
// Or use presets
|
|
153
|
+
const response2 = await submitForm({
|
|
154
|
+
formId: 'your-form-id',
|
|
155
|
+
data: { message: 'Hello' },
|
|
156
|
+
retry: RetryPresets.patient() // More retries, longer delays
|
|
157
|
+
});
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
### Using Axios Instead of Fetch
|
|
161
|
+
|
|
162
|
+
```javascript
|
|
163
|
+
import axios from 'axios';
|
|
164
|
+
import { submitForm } from '@gofranz/formshive-submit';
|
|
165
|
+
|
|
166
|
+
// Option 1: Use string identifier
|
|
167
|
+
const response = await submitForm({
|
|
168
|
+
formId: 'your-form-id',
|
|
169
|
+
data: { message: 'Hello' },
|
|
170
|
+
httpClient: 'axios' // Requires axios to be installed
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
// Option 2: Use custom axios instance
|
|
174
|
+
const customAxios = axios.create({
|
|
175
|
+
timeout: 10000,
|
|
176
|
+
headers: {
|
|
177
|
+
'Custom-Header': 'value'
|
|
178
|
+
}
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
const response2 = await submitForm({
|
|
182
|
+
formId: 'your-form-id',
|
|
183
|
+
data: { message: 'Hello' },
|
|
184
|
+
httpClient: customAxios
|
|
185
|
+
});
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
### Custom Endpoint and Headers
|
|
189
|
+
|
|
190
|
+
```javascript
|
|
191
|
+
const response = await submitForm({
|
|
192
|
+
formId: 'your-form-id',
|
|
193
|
+
data: { message: 'Hello' },
|
|
194
|
+
endpoint: 'https://your-custom-domain.com/api/v1',
|
|
195
|
+
headers: {
|
|
196
|
+
'Authorization': 'Bearer your-token',
|
|
197
|
+
'Custom-Header': 'custom-value'
|
|
198
|
+
},
|
|
199
|
+
timeout: 15000 // 15 seconds
|
|
200
|
+
});
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
## Advanced Usage
|
|
204
|
+
|
|
205
|
+
### Form Validation
|
|
206
|
+
|
|
207
|
+
```javascript
|
|
208
|
+
import { validateFormData, submitForm } from '@gofranz/formshive-submit';
|
|
209
|
+
|
|
210
|
+
const data = {
|
|
211
|
+
name: '',
|
|
212
|
+
email: 'invalid-email',
|
|
213
|
+
message: 'Hello'
|
|
214
|
+
};
|
|
215
|
+
|
|
216
|
+
const validation = validateFormData(data);
|
|
217
|
+
if (!validation.isValid) {
|
|
218
|
+
console.log('Validation errors:', validation.errors);
|
|
219
|
+
console.log('Warnings:', validation.warnings);
|
|
220
|
+
return;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
const response = await submitForm({
|
|
224
|
+
formId: 'validated-form',
|
|
225
|
+
data: data
|
|
226
|
+
});
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
### Reusable Form Submitter
|
|
230
|
+
|
|
231
|
+
```javascript
|
|
232
|
+
import { FormSubmitter } from '@gofranz/formshive-submit';
|
|
233
|
+
|
|
234
|
+
// Create a submitter with default configuration
|
|
235
|
+
const submitter = new FormSubmitter({
|
|
236
|
+
endpoint: 'https://api.myapp.com/v1',
|
|
237
|
+
retry: {
|
|
238
|
+
maxAttempts: 5,
|
|
239
|
+
baseDelay: 1000
|
|
240
|
+
},
|
|
241
|
+
debug: true
|
|
242
|
+
});
|
|
243
|
+
|
|
244
|
+
// Submit multiple forms using the same configuration
|
|
245
|
+
const response1 = await submitter.submit('contact-form', {
|
|
246
|
+
name: 'John',
|
|
247
|
+
email: 'john@example.com'
|
|
248
|
+
});
|
|
249
|
+
|
|
250
|
+
const response2 = await submitter.submit('feedback-form', {
|
|
251
|
+
rating: 5,
|
|
252
|
+
comment: 'Great service!'
|
|
253
|
+
});
|
|
254
|
+
|
|
255
|
+
// Test connection
|
|
256
|
+
const isConnected = await submitter.testConnection();
|
|
257
|
+
console.log('API is reachable:', isConnected);
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
### Progress Tracking
|
|
261
|
+
|
|
262
|
+
```javascript
|
|
263
|
+
import { submitForm, formatFileSize } from '@gofranz/formshive-submit';
|
|
264
|
+
|
|
265
|
+
const response = await submitForm({
|
|
266
|
+
formId: 'upload-form',
|
|
267
|
+
data: formData,
|
|
268
|
+
callbacks: {
|
|
269
|
+
onStart: () => {
|
|
270
|
+
console.log('Upload starting...');
|
|
271
|
+
showProgressBar(true);
|
|
272
|
+
},
|
|
273
|
+
onProgress: (percent, loaded, total) => {
|
|
274
|
+
const loadedSize = formatFileSize(loaded);
|
|
275
|
+
const totalSize = formatFileSize(total);
|
|
276
|
+
console.log(`${percent}% - ${loadedSize}/${totalSize}`);
|
|
277
|
+
updateProgress(percent);
|
|
278
|
+
},
|
|
279
|
+
onSuccess: (response) => {
|
|
280
|
+
console.log('Upload complete!');
|
|
281
|
+
hideProgressBar();
|
|
282
|
+
},
|
|
283
|
+
onError: (error) => {
|
|
284
|
+
console.error('Upload failed:', error);
|
|
285
|
+
showError(error.message);
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
});
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
## Browser Usage (CDN)
|
|
292
|
+
|
|
293
|
+
```html
|
|
294
|
+
<!DOCTYPE html>
|
|
295
|
+
<html>
|
|
296
|
+
<head>
|
|
297
|
+
<title>Formshive Submit Example</title>
|
|
298
|
+
</head>
|
|
299
|
+
<body>
|
|
300
|
+
<form id="myForm">
|
|
301
|
+
<input type="text" name="name" placeholder="Name" required>
|
|
302
|
+
<input type="email" name="email" placeholder="Email" required>
|
|
303
|
+
<textarea name="message" placeholder="Message"></textarea>
|
|
304
|
+
<input type="file" name="file" multiple>
|
|
305
|
+
<button type="submit">Submit</button>
|
|
306
|
+
</form>
|
|
307
|
+
|
|
308
|
+
<script src="https://unpkg.com/@gofranz/formshive-submit/dist/formshive-submit.min.js"></script>
|
|
309
|
+
<script>
|
|
310
|
+
document.getElementById('myForm').addEventListener('submit', async (e) => {
|
|
311
|
+
e.preventDefault();
|
|
312
|
+
|
|
313
|
+
const formData = new FormData(e.target);
|
|
314
|
+
|
|
315
|
+
try {
|
|
316
|
+
const response = await FormshiveSubmit.submitForm({
|
|
317
|
+
formId: 'my-form-id',
|
|
318
|
+
data: formData,
|
|
319
|
+
callbacks: {
|
|
320
|
+
onSuccess: (response) => {
|
|
321
|
+
alert('Form submitted successfully!');
|
|
322
|
+
},
|
|
323
|
+
onError: (error) => {
|
|
324
|
+
alert('Error: ' + error.message);
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
});
|
|
328
|
+
} catch (error) {
|
|
329
|
+
console.error('Submission error:', error);
|
|
330
|
+
}
|
|
331
|
+
});
|
|
332
|
+
</script>
|
|
333
|
+
</body>
|
|
334
|
+
</html>
|
|
335
|
+
```
|
|
336
|
+
|
|
337
|
+
## API Reference
|
|
338
|
+
|
|
339
|
+
### Functions
|
|
340
|
+
|
|
341
|
+
#### `submitForm(options: FormshiveSubmitOptions): Promise<SubmitResponse>`
|
|
342
|
+
|
|
343
|
+
Main form submission function with full configuration options.
|
|
344
|
+
|
|
345
|
+
#### `submitFormSimple(formId: string, data: Record<string, any> | FormData, options?: Partial<FormshiveSubmitOptions>): Promise<SubmitResponse>`
|
|
346
|
+
|
|
347
|
+
Simplified submission function for basic use cases.
|
|
348
|
+
|
|
349
|
+
#### `validateFormData(data: Record<string, any> | FormData): ValidationResult`
|
|
350
|
+
|
|
351
|
+
Validates form data before submission.
|
|
352
|
+
|
|
353
|
+
### Classes
|
|
354
|
+
|
|
355
|
+
#### `FormSubmitter`
|
|
356
|
+
|
|
357
|
+
Reusable form submitter with configurable defaults.
|
|
358
|
+
|
|
359
|
+
```javascript
|
|
360
|
+
const submitter = new FormSubmitter(defaultOptions);
|
|
361
|
+
await submitter.submit(formId, data, overrideOptions);
|
|
362
|
+
```
|
|
363
|
+
|
|
364
|
+
### Types
|
|
365
|
+
|
|
366
|
+
#### `FormshiveSubmitOptions`
|
|
367
|
+
|
|
368
|
+
```typescript
|
|
369
|
+
interface FormshiveSubmitOptions {
|
|
370
|
+
formId: string; // Required: Formshive form ID
|
|
371
|
+
data: Record<string, any> | FormData; // Required: Form data
|
|
372
|
+
endpoint?: string; // API endpoint (default: api.formshive.com)
|
|
373
|
+
httpClient?: HttpClient; // 'fetch', 'axios', or axios instance
|
|
374
|
+
retry?: RetryConfig; // Retry configuration
|
|
375
|
+
files?: FileConfig; // File upload configuration
|
|
376
|
+
callbacks?: FormshiveCallbacks; // Success/error/progress callbacks
|
|
377
|
+
headers?: Record<string, string>; // Additional HTTP headers
|
|
378
|
+
timeout?: number; // Request timeout in milliseconds
|
|
379
|
+
debug?: boolean; // Enable debug logging
|
|
380
|
+
}
|
|
381
|
+
```
|
|
382
|
+
|
|
383
|
+
#### `SubmitResponse`
|
|
384
|
+
|
|
385
|
+
```typescript
|
|
386
|
+
interface SubmitResponse {
|
|
387
|
+
success: boolean;
|
|
388
|
+
data?: any;
|
|
389
|
+
statusCode: number;
|
|
390
|
+
headers?: Record<string, string>;
|
|
391
|
+
redirectUrl?: string;
|
|
392
|
+
attempt: number;
|
|
393
|
+
duration: number;
|
|
394
|
+
}
|
|
395
|
+
```
|
|
396
|
+
|
|
397
|
+
#### `SubmitError`
|
|
398
|
+
|
|
399
|
+
```typescript
|
|
400
|
+
interface SubmitError extends Error {
|
|
401
|
+
code: string;
|
|
402
|
+
statusCode?: number;
|
|
403
|
+
response?: any;
|
|
404
|
+
attempt: number;
|
|
405
|
+
isRetryable: boolean;
|
|
406
|
+
originalError?: Error;
|
|
407
|
+
fieldErrors?: FieldValidationError[];
|
|
408
|
+
validationResponse?: FieldValidationErrorResponse;
|
|
409
|
+
}
|
|
410
|
+
```
|
|
411
|
+
|
|
412
|
+
## Error Handling
|
|
413
|
+
|
|
414
|
+
The library provides detailed error information with specific error codes:
|
|
415
|
+
|
|
416
|
+
- `NETWORK_ERROR` - Network connectivity issues
|
|
417
|
+
- `TIMEOUT_ERROR` - Request timeout
|
|
418
|
+
- `VALIDATION_ERROR` - Form validation failed
|
|
419
|
+
- `FILE_TOO_LARGE` - File exceeds size limit
|
|
420
|
+
- `INVALID_FILE_TYPE` - File type not allowed
|
|
421
|
+
- `FORM_NOT_FOUND` - Form ID not found
|
|
422
|
+
- `SERVER_ERROR` - Server-side error (5xx)
|
|
423
|
+
- `RATE_LIMITED` - Too many requests (429)
|
|
424
|
+
|
|
425
|
+
```javascript
|
|
426
|
+
try {
|
|
427
|
+
const response = await submitForm(options);
|
|
428
|
+
} catch (error) {
|
|
429
|
+
switch (error.code) {
|
|
430
|
+
case 'FORM_NOT_FOUND':
|
|
431
|
+
console.error('Form not found. Check your form ID.');
|
|
432
|
+
break;
|
|
433
|
+
case 'FILE_TOO_LARGE':
|
|
434
|
+
console.error('File is too large. Please choose a smaller file.');
|
|
435
|
+
break;
|
|
436
|
+
case 'NETWORK_ERROR':
|
|
437
|
+
console.error('Network error. Please check your connection.');
|
|
438
|
+
break;
|
|
439
|
+
default:
|
|
440
|
+
console.error('Unexpected error:', error.message);
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
```
|
|
444
|
+
|
|
445
|
+
### Field Validation Errors
|
|
446
|
+
|
|
447
|
+
When form validation fails (400 Bad Request), Formshive returns structured field-level validation errors that you can use to display specific error messages for each form field.
|
|
448
|
+
|
|
449
|
+
#### Checking for Field Validation Errors
|
|
450
|
+
|
|
451
|
+
```javascript
|
|
452
|
+
import { submitForm, isFieldValidationError, getFieldErrors } from '@gofranz/formshive-submit';
|
|
453
|
+
|
|
454
|
+
try {
|
|
455
|
+
const response = await submitForm({
|
|
456
|
+
formId: 'contact-form',
|
|
457
|
+
data: {
|
|
458
|
+
name: '', // Missing required field
|
|
459
|
+
email: 'invalid-email', // Invalid format
|
|
460
|
+
message: 'Hello'
|
|
461
|
+
}
|
|
462
|
+
});
|
|
463
|
+
} catch (error) {
|
|
464
|
+
if (isFieldValidationError(error)) {
|
|
465
|
+
console.log('Form has validation errors');
|
|
466
|
+
const fieldErrors = getFieldErrors(error);
|
|
467
|
+
|
|
468
|
+
fieldErrors.forEach(fieldError => {
|
|
469
|
+
console.log(`Field: ${fieldError.field}`);
|
|
470
|
+
console.log(`Error: ${fieldError.message}`);
|
|
471
|
+
console.log(`Code: ${fieldError.code}`);
|
|
472
|
+
});
|
|
473
|
+
} else {
|
|
474
|
+
console.error('Non-validation error:', error.message);
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
```
|
|
478
|
+
|
|
479
|
+
#### Using Field Error Helpers for UI
|
|
480
|
+
|
|
481
|
+
The library provides helper functions to make it easy to display field errors in your forms:
|
|
482
|
+
|
|
483
|
+
```javascript
|
|
484
|
+
import { createFieldErrorHelpers, submitForm } from '@gofranz/formshive-submit';
|
|
485
|
+
|
|
486
|
+
let currentError = null;
|
|
487
|
+
|
|
488
|
+
// Create helpers for easy UI integration
|
|
489
|
+
const errorHelpers = createFieldErrorHelpers(currentError);
|
|
490
|
+
|
|
491
|
+
// Check if a field has an error
|
|
492
|
+
if (errorHelpers.hasError('email')) {
|
|
493
|
+
document.getElementById('email').classList.add('input-error');
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
// Get error message for a field
|
|
497
|
+
const emailErrorMsg = errorHelpers.getMessage('email');
|
|
498
|
+
if (emailErrorMsg) {
|
|
499
|
+
document.getElementById('email-error').textContent = emailErrorMsg;
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
// Get CSS class for field error state
|
|
503
|
+
const fieldClass = errorHelpers.getFieldClass('email', 'has-error');
|
|
504
|
+
document.getElementById('email').className = fieldClass;
|
|
505
|
+
```
|
|
506
|
+
|
|
507
|
+
#### Complete Field Validation Example
|
|
508
|
+
|
|
509
|
+
```javascript
|
|
510
|
+
import {
|
|
511
|
+
submitForm,
|
|
512
|
+
isFieldValidationError,
|
|
513
|
+
createFieldErrorHelpers,
|
|
514
|
+
getValidationErrorSummary
|
|
515
|
+
} from '@gofranz/formshive-submit';
|
|
516
|
+
|
|
517
|
+
async function handleFormSubmit(formData) {
|
|
518
|
+
let currentError = null;
|
|
519
|
+
|
|
520
|
+
try {
|
|
521
|
+
const response = await submitForm({
|
|
522
|
+
formId: 'registration-form',
|
|
523
|
+
data: formData
|
|
524
|
+
});
|
|
525
|
+
|
|
526
|
+
// Success - clear any previous errors
|
|
527
|
+
clearFieldErrors();
|
|
528
|
+
showSuccessMessage();
|
|
529
|
+
|
|
530
|
+
} catch (error) {
|
|
531
|
+
currentError = error;
|
|
532
|
+
|
|
533
|
+
if (isFieldValidationError(error)) {
|
|
534
|
+
// Handle field-specific validation errors
|
|
535
|
+
displayFieldErrors(error);
|
|
536
|
+
|
|
537
|
+
// Show general validation summary
|
|
538
|
+
const summary = getValidationErrorSummary(error);
|
|
539
|
+
showErrorMessage(summary);
|
|
540
|
+
|
|
541
|
+
} else {
|
|
542
|
+
// Handle other types of errors
|
|
543
|
+
showErrorMessage(error.message || 'An unexpected error occurred');
|
|
544
|
+
}
|
|
545
|
+
}
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
function displayFieldErrors(error) {
|
|
549
|
+
const helpers = createFieldErrorHelpers(error, 'field-error');
|
|
550
|
+
const fieldNames = ['name', 'email', 'phone', 'message'];
|
|
551
|
+
|
|
552
|
+
fieldNames.forEach(fieldName => {
|
|
553
|
+
const input = document.getElementById(fieldName);
|
|
554
|
+
const errorDiv = document.getElementById(`${fieldName}-error`);
|
|
555
|
+
|
|
556
|
+
if (helpers.hasError(fieldName)) {
|
|
557
|
+
// Add error styling
|
|
558
|
+
input.classList.add('field-error');
|
|
559
|
+
|
|
560
|
+
// Show error message
|
|
561
|
+
errorDiv.textContent = helpers.getMessage(fieldName);
|
|
562
|
+
errorDiv.style.display = 'block';
|
|
563
|
+
} else {
|
|
564
|
+
// Clear error state
|
|
565
|
+
input.classList.remove('field-error');
|
|
566
|
+
errorDiv.style.display = 'none';
|
|
567
|
+
}
|
|
568
|
+
});
|
|
569
|
+
}
|
|
570
|
+
```
|
|
571
|
+
|
|
572
|
+
#### Field Validation Error Types
|
|
573
|
+
|
|
574
|
+
```typescript
|
|
575
|
+
interface FieldValidationError {
|
|
576
|
+
field: string; // Field name (e.g., 'email')
|
|
577
|
+
code: string; // Error code (e.g., 'required', 'invalid_format')
|
|
578
|
+
message: string; // User-friendly error message
|
|
579
|
+
params: Record<string, any>; // Additional error parameters
|
|
580
|
+
}
|
|
581
|
+
|
|
582
|
+
interface FieldValidationErrorResponse {
|
|
583
|
+
error: string; // Always 'validation_error'
|
|
584
|
+
action?: string; // Optional action hint
|
|
585
|
+
message: string; // General validation error message
|
|
586
|
+
errors: FieldValidationError[]; // Array of field-specific errors
|
|
587
|
+
}
|
|
588
|
+
```
|
|
589
|
+
|
|
590
|
+
#### Available Field Error Utility Functions
|
|
591
|
+
|
|
592
|
+
The library exports many utility functions for working with field validation errors:
|
|
593
|
+
|
|
594
|
+
- `isFieldValidationError(error)` - Check if error contains field validation errors
|
|
595
|
+
- `getFieldErrors(error)` - Get array of all field validation errors
|
|
596
|
+
- `getFieldError(error, fieldName)` - Get validation error for specific field
|
|
597
|
+
- `hasFieldError(error, fieldName)` - Check if specific field has error
|
|
598
|
+
- `getErrorFieldNames(error)` - Get names of all fields with errors
|
|
599
|
+
- `formatFieldErrors(error)` - Get simple object mapping field names to error messages
|
|
600
|
+
- `createFieldErrorHelpers(error)` - Create helper object for UI integration
|
|
601
|
+
- `getValidationErrorSummary(error)` - Get human-readable error summary
|
|
602
|
+
- `hasErrorCode(error, code)` - Check if any field has specific error code
|
|
603
|
+
- `getErrorsByCode(error, code)` - Get all errors with specific code
|
|
604
|
+
|
|
605
|
+
## Contributing
|
|
606
|
+
|
|
607
|
+
Contributions are welcome! Please read our contributing guidelines and submit pull requests for any improvements.
|
|
608
|
+
|
|
609
|
+
## License
|
|
610
|
+
|
|
611
|
+
MIT License - see LICENSE file for details.
|
|
612
|
+
|
|
613
|
+
## Support
|
|
614
|
+
|
|
615
|
+
For issues and questions, please visit our GitHub repository or contact support at support@formshive.com.
|
|
616
|
+
|
|
617
|
+
---
|
|
618
|
+
|
|
619
|
+
**Formshive Submit** - Making form submissions robust and reliable. ✨
|
package/dist/client.d.ts
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* HTTP Client abstraction for both fetch and axios
|
|
3
|
+
*/
|
|
4
|
+
import type { HttpClient, HttpClientAdapter, SubmitError } from './types';
|
|
5
|
+
import { ERROR_CODES } from './types';
|
|
6
|
+
/**
|
|
7
|
+
* Create HTTP client adapter based on the provided client type
|
|
8
|
+
*/
|
|
9
|
+
export declare function createHttpClient(client: HttpClient): HttpClientAdapter;
|
|
10
|
+
/**
|
|
11
|
+
* Create a SubmitError from various error types
|
|
12
|
+
*/
|
|
13
|
+
export declare function createSubmitError(error: any, attempt: number, code?: keyof typeof ERROR_CODES): SubmitError;
|
|
14
|
+
/**
|
|
15
|
+
* Check if an error is retryable
|
|
16
|
+
*/
|
|
17
|
+
export declare function isRetryableError(error: any): boolean;
|
|
18
|
+
/**
|
|
19
|
+
* Get user-friendly error message based on error type
|
|
20
|
+
*/
|
|
21
|
+
export declare function getErrorMessage(error: SubmitError): string;
|
|
22
|
+
//# sourceMappingURL=client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,KAAK,EACV,UAAU,EACV,iBAAiB,EAGjB,WAAW,EAGZ,MAAM,SAAS,CAAC;AACjB,OAAO,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAkGtC;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,UAAU,GAAG,iBAAiB,CAqBtE;AA2BD;;GAEG;AACH,wBAAgB,iBAAiB,CAC/B,KAAK,EAAE,GAAG,EACV,OAAO,EAAE,MAAM,EACf,IAAI,GAAE,MAAM,OAAO,WAA6B,GAC/C,WAAW,CA6Gb;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,GAAG,GAAG,OAAO,CAgCpD;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,WAAW,GAAG,MAAM,CAqB1D"}
|