@dmitryvim/form-builder 0.1.1 → 0.1.5
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 +34 -125
- package/dist/README.md +193 -0
- package/dist/example.html +108 -0
- package/dist/form-builder.js +972 -0
- package/dist/index.html +446 -171
- package/dist/sample.html +1615 -0
- package/docs/13_form_builder.html +663 -0
- package/docs/REQUIREMENTS.md +281 -0
- package/docs/integration.md +445 -0
- package/docs/schema.md +425 -0
- package/package.json +9 -4
package/README.md
CHANGED
|
@@ -2,35 +2,43 @@
|
|
|
2
2
|
|
|
3
3
|
JSON Schema → Dynamic Forms → Structured Output
|
|
4
4
|
|
|
5
|
+
A reusable, zero-dependency form generation library that converts JSON schemas into dynamic, interactive forms with real-time validation and file upload support.
|
|
6
|
+
|
|
5
7
|
## Live Demo
|
|
6
8
|
|
|
7
9
|
Try it now: **[https://picazru.github.io/form-builder/dist/index.html](https://picazru.github.io/form-builder/dist/index.html)**
|
|
8
10
|
|
|
9
11
|
## Quick Start
|
|
10
12
|
|
|
11
|
-
###
|
|
13
|
+
### CDN Integration
|
|
12
14
|
|
|
13
15
|
```html
|
|
14
|
-
<!--
|
|
16
|
+
<!-- Embed via iframe -->
|
|
15
17
|
<iframe src="https://picazru.github.io/form-builder/dist/index.html"
|
|
16
|
-
width="100%" height="600px"
|
|
17
|
-
frameborder="0"
|
|
18
|
-
style="border-radius: 8px;"></iframe>
|
|
18
|
+
width="100%" height="600px" frameborder="0"></iframe>
|
|
19
19
|
|
|
20
|
-
<!-- With custom schema
|
|
21
|
-
<iframe src="https://picazru.github.io/form-builder/dist/index.html?schema=
|
|
20
|
+
<!-- With custom schema -->
|
|
21
|
+
<iframe src="https://picazru.github.io/form-builder/dist/index.html?schema=BASE64_SCHEMA"
|
|
22
22
|
width="100%" height="600px"></iframe>
|
|
23
23
|
```
|
|
24
24
|
|
|
25
|
-
###
|
|
25
|
+
### NPM Installation
|
|
26
26
|
|
|
27
27
|
```bash
|
|
28
|
-
npm install @
|
|
28
|
+
npm install @dmitryvim/form-builder
|
|
29
29
|
```
|
|
30
30
|
|
|
31
|
-
##
|
|
31
|
+
## Core Features
|
|
32
|
+
|
|
33
|
+
- **Schema-driven forms**: JSON Schema v0.3 → Interactive forms
|
|
34
|
+
- **File uploads**: Built-in support with configurable handlers
|
|
35
|
+
- **Real-time validation**: Client-side validation with error display
|
|
36
|
+
- **Framework agnostic**: Works with any web stack
|
|
37
|
+
- **Zero dependencies**: Self-contained HTML/CSS/JavaScript
|
|
38
|
+
- **Read-only mode**: Display form data without editing
|
|
39
|
+
- **Draft saving**: Save incomplete forms without validation
|
|
32
40
|
|
|
33
|
-
|
|
41
|
+
## Basic Example
|
|
34
42
|
|
|
35
43
|
```json
|
|
36
44
|
{
|
|
@@ -44,131 +52,32 @@ npm install @picazru/form-builder
|
|
|
44
52
|
"required": true
|
|
45
53
|
},
|
|
46
54
|
{
|
|
47
|
-
"type": "
|
|
48
|
-
"key": "
|
|
49
|
-
"label": "
|
|
55
|
+
"type": "files",
|
|
56
|
+
"key": "attachments",
|
|
57
|
+
"label": "Attachments",
|
|
58
|
+
"maxCount": 3,
|
|
50
59
|
"accept": {
|
|
51
|
-
"extensions": ["jpg", "png"]
|
|
60
|
+
"extensions": ["pdf", "jpg", "png"]
|
|
52
61
|
}
|
|
53
62
|
}
|
|
54
63
|
]
|
|
55
64
|
}
|
|
56
65
|
```
|
|
57
66
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
When embedding the form builder, configure file upload handlers on your page:
|
|
61
|
-
|
|
62
|
-
```html
|
|
63
|
-
<!DOCTYPE html>
|
|
64
|
-
<html>
|
|
65
|
-
<head>
|
|
66
|
-
<title>My App with Form Builder</title>
|
|
67
|
-
</head>
|
|
68
|
-
<body>
|
|
69
|
-
<!-- Embed the form builder -->
|
|
70
|
-
<iframe id="formBuilder"
|
|
71
|
-
src="https://picazru.github.io/form-builder/dist/index.html"
|
|
72
|
-
width="100%" height="600px"></iframe>
|
|
73
|
-
|
|
74
|
-
<script>
|
|
75
|
-
// Configure file upload handlers
|
|
76
|
-
window.addEventListener('message', (event) => {
|
|
77
|
-
if (event.origin !== 'https://picazru.github.io') return;
|
|
78
|
-
|
|
79
|
-
if (event.data.type === 'formBuilderReady') {
|
|
80
|
-
// Send configuration to the iframe
|
|
81
|
-
const iframe = document.getElementById('formBuilder');
|
|
82
|
-
iframe.contentWindow.postMessage({
|
|
83
|
-
type: 'configure',
|
|
84
|
-
config: {
|
|
85
|
-
uploadHandler: async (file) => {
|
|
86
|
-
// Your S3 upload logic
|
|
87
|
-
const formData = new FormData();
|
|
88
|
-
formData.append('file', file);
|
|
89
|
-
|
|
90
|
-
const response = await fetch('/api/upload', {
|
|
91
|
-
method: 'POST',
|
|
92
|
-
body: formData
|
|
93
|
-
});
|
|
94
|
-
|
|
95
|
-
const result = await response.json();
|
|
96
|
-
return result.fileUrl;
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
}, 'https://picazru.github.io');
|
|
100
|
-
}
|
|
101
|
-
});
|
|
102
|
-
</script>
|
|
103
|
-
</body>
|
|
104
|
-
</html>
|
|
105
|
-
```
|
|
106
|
-
|
|
107
|
-
### Direct Page Integration
|
|
108
|
-
|
|
109
|
-
If you want to integrate directly on your page (not iframe):
|
|
67
|
+
## Integration Options
|
|
110
68
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
const config = event.detail;
|
|
115
|
-
|
|
116
|
-
// Upload files to S3
|
|
117
|
-
config.setUploadHandler(async (file) => {
|
|
118
|
-
const formData = new FormData();
|
|
119
|
-
formData.append('file', file);
|
|
120
|
-
|
|
121
|
-
const response = await fetch('/api/upload', {
|
|
122
|
-
method: 'POST',
|
|
123
|
-
body: formData
|
|
124
|
-
});
|
|
125
|
-
|
|
126
|
-
const result = await response.json();
|
|
127
|
-
return result.fileUrl; // Return S3 URL or resource ID
|
|
128
|
-
});
|
|
129
|
-
|
|
130
|
-
// Download files
|
|
131
|
-
config.setDownloadHandler(async (resourceId) => {
|
|
132
|
-
window.open(`/api/download/${resourceId}`, '_blank');
|
|
133
|
-
});
|
|
134
|
-
|
|
135
|
-
// Generate thumbnails
|
|
136
|
-
config.setThumbnailHandler(async (resourceId) => {
|
|
137
|
-
return `/api/thumbnail/${resourceId}`;
|
|
138
|
-
});
|
|
139
|
-
});
|
|
140
|
-
</script>
|
|
141
|
-
```
|
|
69
|
+
- **CDN**: Direct iframe embedding
|
|
70
|
+
- **NPM**: Import as module
|
|
71
|
+
- **Direct**: Self-hosted deployment
|
|
142
72
|
|
|
143
|
-
|
|
73
|
+
See [Integration Guide](docs/integration.md) for complete setup instructions.
|
|
144
74
|
|
|
145
|
-
|
|
146
|
-
- **textarea** - Multi-line text
|
|
147
|
-
- **number** - Numeric input with min/max
|
|
148
|
-
- **select** - Dropdown with options
|
|
149
|
-
- **file** - Single file upload with preview
|
|
150
|
-
- **files** - Multiple file uploads
|
|
151
|
-
- **group** - Nested objects with repeat support
|
|
75
|
+
## Documentation
|
|
152
76
|
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
"name": "John Doe",
|
|
158
|
-
"avatar": "https://bucket.s3.amazonaws.com/files/avatar.jpg"
|
|
159
|
-
}
|
|
160
|
-
```
|
|
161
|
-
|
|
162
|
-
## Development
|
|
163
|
-
|
|
164
|
-
```bash
|
|
165
|
-
git clone https://github.com/picazru/form-builder.git
|
|
166
|
-
cd form-builder
|
|
167
|
-
npm install
|
|
168
|
-
npm run dev # Start development server
|
|
169
|
-
npm test # Run tests
|
|
170
|
-
npm run build # Build for production
|
|
171
|
-
```
|
|
77
|
+
- [Integration Guide](docs/integration.md) - How to use and integrate
|
|
78
|
+
- [Schema Reference](docs/schema.md) - Complete schema documentation
|
|
79
|
+
- [Requirements](docs/requirements.md) - Product and business requirements
|
|
80
|
+
- [Development Guide](development.md) - Development and testing
|
|
172
81
|
|
|
173
82
|
## License
|
|
174
83
|
|
package/dist/README.md
ADDED
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
# Form Builder Library
|
|
2
|
+
|
|
3
|
+
A reusable JavaScript library for generating dynamic forms from JSON schemas.
|
|
4
|
+
|
|
5
|
+
## Quick Start
|
|
6
|
+
|
|
7
|
+
### 1. Include the Library
|
|
8
|
+
|
|
9
|
+
```html
|
|
10
|
+
<script src="https://unpkg.com/@dmitryvim/form-builder@latest/dist/form-builder.js"></script>
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
Or via npm:
|
|
14
|
+
```bash
|
|
15
|
+
npm install @dmitryvim/form-builder
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
### 2. Basic Usage
|
|
19
|
+
|
|
20
|
+
```javascript
|
|
21
|
+
// Define your schema
|
|
22
|
+
const schema = {
|
|
23
|
+
"version": "0.3",
|
|
24
|
+
"title": "User Registration",
|
|
25
|
+
"elements": [
|
|
26
|
+
{
|
|
27
|
+
"type": "text",
|
|
28
|
+
"key": "name",
|
|
29
|
+
"label": "Full Name",
|
|
30
|
+
"required": true
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
"type": "text",
|
|
34
|
+
"key": "email",
|
|
35
|
+
"label": "Email",
|
|
36
|
+
"required": true
|
|
37
|
+
}
|
|
38
|
+
]
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
// Get container element
|
|
42
|
+
const container = document.getElementById('form-container');
|
|
43
|
+
|
|
44
|
+
// Render the form
|
|
45
|
+
const form = FormBuilder.renderForm(schema, container, {
|
|
46
|
+
onSubmit: (data) => {
|
|
47
|
+
console.log('Form submitted:', data);
|
|
48
|
+
},
|
|
49
|
+
onDraft: (data) => {
|
|
50
|
+
console.log('Draft saved:', data);
|
|
51
|
+
},
|
|
52
|
+
onError: (errors) => {
|
|
53
|
+
console.log('Validation errors:', errors);
|
|
54
|
+
}
|
|
55
|
+
});
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
## API Reference
|
|
59
|
+
|
|
60
|
+
### FormBuilder.renderForm(schema, container, options)
|
|
61
|
+
|
|
62
|
+
Renders a form in the specified container.
|
|
63
|
+
|
|
64
|
+
**Parameters:**
|
|
65
|
+
- `schema` - JSON schema object (v0.3)
|
|
66
|
+
- `container` - DOM element to render form in
|
|
67
|
+
- `options` - Configuration object
|
|
68
|
+
|
|
69
|
+
**Options:**
|
|
70
|
+
- `prefill` - Object with prefilled values
|
|
71
|
+
- `readonly` - Boolean, renders form in read-only mode
|
|
72
|
+
- `onSubmit` - Callback for form submission
|
|
73
|
+
- `onDraft` - Callback for draft saving
|
|
74
|
+
- `onError` - Callback for validation errors
|
|
75
|
+
|
|
76
|
+
### FormBuilder.validateSchema(schema)
|
|
77
|
+
|
|
78
|
+
Validates a JSON schema and returns array of errors.
|
|
79
|
+
|
|
80
|
+
### FormBuilder.setUploadHandler(uploadFn)
|
|
81
|
+
|
|
82
|
+
Sets custom file upload handler:
|
|
83
|
+
```javascript
|
|
84
|
+
FormBuilder.setUploadHandler(async (file) => {
|
|
85
|
+
// Upload file to your backend
|
|
86
|
+
const response = await fetch('/upload', {
|
|
87
|
+
method: 'POST',
|
|
88
|
+
body: file
|
|
89
|
+
});
|
|
90
|
+
const result = await response.json();
|
|
91
|
+
return result.resourceId; // Return resource ID
|
|
92
|
+
});
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
### FormBuilder.setDownloadHandler(downloadFn)
|
|
96
|
+
|
|
97
|
+
Sets custom file download handler:
|
|
98
|
+
```javascript
|
|
99
|
+
FormBuilder.setDownloadHandler(async (resourceId, fileName) => {
|
|
100
|
+
window.open(`/download/${resourceId}`, '_blank');
|
|
101
|
+
});
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
## Supported Field Types
|
|
105
|
+
|
|
106
|
+
- `text` - Single line text input
|
|
107
|
+
- `textarea` - Multi-line text input
|
|
108
|
+
- `number` - Numeric input with constraints
|
|
109
|
+
- `select` - Dropdown selection
|
|
110
|
+
- `file` - Single file upload
|
|
111
|
+
- `files` - Multiple file upload
|
|
112
|
+
- `group` - Nested objects with optional repeat
|
|
113
|
+
|
|
114
|
+
## Complete Example
|
|
115
|
+
|
|
116
|
+
```javascript
|
|
117
|
+
const schema = {
|
|
118
|
+
"version": "0.3",
|
|
119
|
+
"title": "Product Form",
|
|
120
|
+
"elements": [
|
|
121
|
+
{
|
|
122
|
+
"type": "file",
|
|
123
|
+
"key": "cover",
|
|
124
|
+
"label": "Cover Image",
|
|
125
|
+
"required": true,
|
|
126
|
+
"accept": {
|
|
127
|
+
"extensions": ["jpg", "png"],
|
|
128
|
+
"mime": ["image/jpeg", "image/png"]
|
|
129
|
+
},
|
|
130
|
+
"maxSizeMB": 5
|
|
131
|
+
},
|
|
132
|
+
{
|
|
133
|
+
"type": "text",
|
|
134
|
+
"key": "title",
|
|
135
|
+
"label": "Product Title",
|
|
136
|
+
"required": true,
|
|
137
|
+
"maxLength": 100
|
|
138
|
+
},
|
|
139
|
+
{
|
|
140
|
+
"type": "group",
|
|
141
|
+
"key": "features",
|
|
142
|
+
"label": "Features",
|
|
143
|
+
"repeat": {
|
|
144
|
+
"min": 1,
|
|
145
|
+
"max": 5
|
|
146
|
+
},
|
|
147
|
+
"elements": [
|
|
148
|
+
{
|
|
149
|
+
"type": "text",
|
|
150
|
+
"key": "name",
|
|
151
|
+
"label": "Feature Name",
|
|
152
|
+
"required": true
|
|
153
|
+
}
|
|
154
|
+
]
|
|
155
|
+
}
|
|
156
|
+
]
|
|
157
|
+
};
|
|
158
|
+
|
|
159
|
+
// Configure file upload
|
|
160
|
+
FormBuilder.setUploadHandler(async (file) => {
|
|
161
|
+
const formData = new FormData();
|
|
162
|
+
formData.append('file', file);
|
|
163
|
+
|
|
164
|
+
const response = await fetch('/api/upload', {
|
|
165
|
+
method: 'POST',
|
|
166
|
+
body: formData
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
const result = await response.json();
|
|
170
|
+
return result.resourceId;
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
// Render form
|
|
174
|
+
FormBuilder.renderForm(schema, document.getElementById('form'), {
|
|
175
|
+
onSubmit: async (data) => {
|
|
176
|
+
const response = await fetch('/api/submit', {
|
|
177
|
+
method: 'POST',
|
|
178
|
+
headers: { 'Content-Type': 'application/json' },
|
|
179
|
+
body: JSON.stringify(data)
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
if (response.ok) {
|
|
183
|
+
alert('Form submitted successfully!');
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
});
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
## Files
|
|
190
|
+
|
|
191
|
+
- `form-builder.js` - Main library file
|
|
192
|
+
- `sample.html` - Interactive demo page
|
|
193
|
+
- Complete documentation at `/docs/`
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
+
<title>Form Builder - Simple Example</title>
|
|
7
|
+
<script src="https://cdn.tailwindcss.com"></script>
|
|
8
|
+
</head>
|
|
9
|
+
<body class="bg-gray-50 p-8">
|
|
10
|
+
<div class="max-w-2xl mx-auto">
|
|
11
|
+
<h1 class="text-3xl font-bold mb-8">Form Builder Library Example</h1>
|
|
12
|
+
|
|
13
|
+
<div class="bg-white rounded-lg shadow p-6 mb-8">
|
|
14
|
+
<h2 class="text-xl font-semibold mb-4">Generated Form</h2>
|
|
15
|
+
<div id="form-container"></div>
|
|
16
|
+
</div>
|
|
17
|
+
|
|
18
|
+
<div class="bg-white rounded-lg shadow p-6">
|
|
19
|
+
<h2 class="text-xl font-semibold mb-4">Form Output</h2>
|
|
20
|
+
<pre id="output" class="bg-gray-100 p-4 rounded text-sm overflow-auto">Submit the form to see output...</pre>
|
|
21
|
+
</div>
|
|
22
|
+
</div>
|
|
23
|
+
|
|
24
|
+
<script src="form-builder.js"></script>
|
|
25
|
+
<script>
|
|
26
|
+
// Example schema
|
|
27
|
+
const schema = {
|
|
28
|
+
"version": "0.3",
|
|
29
|
+
"title": "Contact Form",
|
|
30
|
+
"elements": [
|
|
31
|
+
{
|
|
32
|
+
"type": "text",
|
|
33
|
+
"key": "name",
|
|
34
|
+
"label": "Full Name",
|
|
35
|
+
"required": true,
|
|
36
|
+
"minLength": 2,
|
|
37
|
+
"maxLength": 50
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
"type": "text",
|
|
41
|
+
"key": "email",
|
|
42
|
+
"label": "Email Address",
|
|
43
|
+
"required": true,
|
|
44
|
+
"pattern": "^[^@\\s]+@[^@\\s]+\\.[^@\\s]+$"
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
"type": "select",
|
|
48
|
+
"key": "category",
|
|
49
|
+
"label": "Category",
|
|
50
|
+
"required": true,
|
|
51
|
+
"options": [
|
|
52
|
+
{ "value": "general", "label": "General Inquiry" },
|
|
53
|
+
{ "value": "support", "label": "Technical Support" },
|
|
54
|
+
{ "value": "billing", "label": "Billing Question" }
|
|
55
|
+
]
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
"type": "textarea",
|
|
59
|
+
"key": "message",
|
|
60
|
+
"label": "Message",
|
|
61
|
+
"required": true,
|
|
62
|
+
"maxLength": 1000
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
"type": "file",
|
|
66
|
+
"key": "attachment",
|
|
67
|
+
"label": "Attachment (Optional)",
|
|
68
|
+
"required": false,
|
|
69
|
+
"accept": {
|
|
70
|
+
"extensions": ["pdf", "doc", "docx", "txt"],
|
|
71
|
+
"mime": ["application/pdf", "application/msword", "text/plain"]
|
|
72
|
+
},
|
|
73
|
+
"maxSizeMB": 5
|
|
74
|
+
}
|
|
75
|
+
]
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
// Configure file upload simulation
|
|
79
|
+
FormBuilder.setUploadHandler(async (file) => {
|
|
80
|
+
// Simulate upload delay
|
|
81
|
+
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
82
|
+
|
|
83
|
+
// Generate fake resource ID
|
|
84
|
+
const resourceId = 'res_' + Math.random().toString(36).substr(2, 12);
|
|
85
|
+
console.log(`File "${file.name}" uploaded with ID: ${resourceId}`);
|
|
86
|
+
return resourceId;
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
// Render the form
|
|
90
|
+
const container = document.getElementById('form-container');
|
|
91
|
+
const output = document.getElementById('output');
|
|
92
|
+
|
|
93
|
+
FormBuilder.renderForm(schema, container, {
|
|
94
|
+
onSubmit: (data) => {
|
|
95
|
+
output.textContent = JSON.stringify(data, null, 2);
|
|
96
|
+
alert('Form submitted successfully! Check the output below.');
|
|
97
|
+
},
|
|
98
|
+
onDraft: (data) => {
|
|
99
|
+
output.textContent = 'DRAFT:\n' + JSON.stringify(data, null, 2);
|
|
100
|
+
console.log('Draft saved:', data);
|
|
101
|
+
},
|
|
102
|
+
onError: (errors) => {
|
|
103
|
+
alert('Validation errors: ' + errors.join(', '));
|
|
104
|
+
}
|
|
105
|
+
});
|
|
106
|
+
</script>
|
|
107
|
+
</body>
|
|
108
|
+
</html>
|