@mieweb/forms-editor 0.1.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 +256 -0
- package/dist/index.css +6 -0
- package/dist/index.js +1120 -0
- package/package.json +36 -0
- package/src/index.css +14 -0
package/README.md
ADDED
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
# @mieweb/forms-editor
|
|
2
|
+
|
|
3
|
+
Embeddable questionnaire editor component with drag-and-drop, FHIR export, and conditional logic support.
|
|
4
|
+
|
|
5
|
+
## 📦 Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @mieweb/forms-editor
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
### Peer Dependencies
|
|
12
|
+
|
|
13
|
+
Ensure you have React 18+ installed:
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
npm install react react-dom
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
### Automatic Dependencies
|
|
20
|
+
|
|
21
|
+
The following are installed automatically:
|
|
22
|
+
|
|
23
|
+
- `@mieweb/forms-engine` - Core form state and field components
|
|
24
|
+
- `framer-motion` - Animations
|
|
25
|
+
- `js-yaml` - YAML import/export
|
|
26
|
+
|
|
27
|
+
## 🚀 Quick Start
|
|
28
|
+
|
|
29
|
+
### 1. Import Styles
|
|
30
|
+
|
|
31
|
+
```jsx
|
|
32
|
+
import '@mieweb/forms-editor/styles.css';
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
### 2. Basic Usage
|
|
36
|
+
|
|
37
|
+
```jsx
|
|
38
|
+
import { QuestionnaireEditor } from '@mieweb/forms-editor';
|
|
39
|
+
|
|
40
|
+
function App() {
|
|
41
|
+
const handleChange = (fields) => {
|
|
42
|
+
console.log('Form updated:', fields);
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
return (
|
|
46
|
+
<QuestionnaireEditor
|
|
47
|
+
onChange={handleChange}
|
|
48
|
+
/>
|
|
49
|
+
);
|
|
50
|
+
}
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
### 3. With Initial Data
|
|
54
|
+
|
|
55
|
+
```jsx
|
|
56
|
+
import { QuestionnaireEditor } from '@mieweb/forms-editor';
|
|
57
|
+
|
|
58
|
+
const initialFields = [
|
|
59
|
+
{
|
|
60
|
+
id: '1',
|
|
61
|
+
fieldType: 'input',
|
|
62
|
+
question: 'What is your name?',
|
|
63
|
+
answer: ''
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
id: '2',
|
|
67
|
+
fieldType: 'radio',
|
|
68
|
+
question: 'Select your role',
|
|
69
|
+
options: ['Developer', 'Designer', 'Manager'],
|
|
70
|
+
selected: null
|
|
71
|
+
}
|
|
72
|
+
];
|
|
73
|
+
|
|
74
|
+
function App() {
|
|
75
|
+
return (
|
|
76
|
+
<QuestionnaireEditor
|
|
77
|
+
initialFields={initialFields}
|
|
78
|
+
onChange={(fields) => console.log(fields)}
|
|
79
|
+
/>
|
|
80
|
+
);
|
|
81
|
+
}
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
## 📖 Props
|
|
85
|
+
|
|
86
|
+
### `QuestionnaireEditor`
|
|
87
|
+
|
|
88
|
+
| Prop | Type | Default | Description |
|
|
89
|
+
|------|------|---------|-------------|
|
|
90
|
+
| `initialFields` | `Array` | `[]` | Initial questionnaire fields |
|
|
91
|
+
| `onChange` | `Function` | `undefined` | Callback when fields change: `(fields) => void` |
|
|
92
|
+
| `className` | `String` | `''` | Additional CSS classes |
|
|
93
|
+
| `showHeader` | `Boolean` | `true` | Show/hide the header with actions |
|
|
94
|
+
| `showMobileToolbar` | `Boolean` | `true` | Show/hide mobile toolbar |
|
|
95
|
+
| `startInPreview` | `Boolean` | `false` | Start in preview mode |
|
|
96
|
+
|
|
97
|
+
## ✨ Features
|
|
98
|
+
|
|
99
|
+
### 🎨 Add & Edit Fields
|
|
100
|
+
|
|
101
|
+
Add fields from the toolbar:
|
|
102
|
+
- **Text Input** - Single-line text
|
|
103
|
+
- **Radio Buttons** - Single choice
|
|
104
|
+
- **Checkboxes** - Multiple choice
|
|
105
|
+
- **Dropdown** - Select menu
|
|
106
|
+
- **Section** - Group fields together
|
|
107
|
+
|
|
108
|
+
### 🔄 Import/Export
|
|
109
|
+
|
|
110
|
+
Built-in support for:
|
|
111
|
+
- **JSON** - Questionnaire data format
|
|
112
|
+
- **FHIR** - FHIR Questionnaire standard
|
|
113
|
+
- **YAML** - Human-readable format
|
|
114
|
+
|
|
115
|
+
```jsx
|
|
116
|
+
import { useFormStore } from '@mieweb/forms-engine';
|
|
117
|
+
|
|
118
|
+
function ExportButtons() {
|
|
119
|
+
const fields = useFormStore(state => state.flatArray());
|
|
120
|
+
|
|
121
|
+
const exportJSON = () => {
|
|
122
|
+
const json = JSON.stringify(fields, null, 2);
|
|
123
|
+
// Download or save
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
return <button onClick={exportJSON}>Export JSON</button>;
|
|
127
|
+
}
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
### 🔀 Conditional Logic (enableWhen)
|
|
131
|
+
|
|
132
|
+
Show/hide fields based on answers to other fields:
|
|
133
|
+
|
|
134
|
+
1. Select a field
|
|
135
|
+
2. Click "Logic" in the edit panel
|
|
136
|
+
3. Add conditions (e.g., "Show when Question 1 equals 'Yes'")
|
|
137
|
+
|
|
138
|
+
### 📱 Mobile Responsive
|
|
139
|
+
|
|
140
|
+
- Desktop: Side-by-side editor and preview
|
|
141
|
+
- Mobile: Swipeable modal for field editing
|
|
142
|
+
|
|
143
|
+
### 🎠Preview Mode
|
|
144
|
+
|
|
145
|
+
Toggle preview mode to see how the form looks to end users:
|
|
146
|
+
|
|
147
|
+
```jsx
|
|
148
|
+
<QuestionnaireEditor startInPreview={true} />
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
## 🎯 Advanced Usage
|
|
152
|
+
|
|
153
|
+
### Custom Styling
|
|
154
|
+
|
|
155
|
+
```jsx
|
|
156
|
+
<QuestionnaireEditor
|
|
157
|
+
className="my-custom-editor"
|
|
158
|
+
onChange={handleChange}
|
|
159
|
+
/>
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
```css
|
|
163
|
+
.my-custom-editor {
|
|
164
|
+
--primary-color: #3b82f6;
|
|
165
|
+
--border-radius: 0.5rem;
|
|
166
|
+
}
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
### Controlled State
|
|
170
|
+
|
|
171
|
+
```jsx
|
|
172
|
+
import { QuestionnaireEditor } from '@mieweb/forms-editor';
|
|
173
|
+
import { useFormStore } from '@mieweb/forms-engine';
|
|
174
|
+
import { useEffect } from 'react';
|
|
175
|
+
|
|
176
|
+
function ControlledEditor() {
|
|
177
|
+
const [savedFields, setSavedFields] = useState([]);
|
|
178
|
+
|
|
179
|
+
const handleChange = (fields) => {
|
|
180
|
+
setSavedFields(fields);
|
|
181
|
+
localStorage.setItem('questionnaire', JSON.stringify(fields));
|
|
182
|
+
};
|
|
183
|
+
|
|
184
|
+
return (
|
|
185
|
+
<QuestionnaireEditor
|
|
186
|
+
initialFields={savedFields}
|
|
187
|
+
onChange={handleChange}
|
|
188
|
+
/>
|
|
189
|
+
);
|
|
190
|
+
}
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
### Accessing Internal State
|
|
194
|
+
|
|
195
|
+
```jsx
|
|
196
|
+
import { useFormStore, useUIStore } from '@mieweb/forms-engine';
|
|
197
|
+
|
|
198
|
+
function EditorWithStatus() {
|
|
199
|
+
const fieldCount = useFormStore(state => Object.keys(state.byId).length);
|
|
200
|
+
const isPreview = useUIStore(state => state.preview);
|
|
201
|
+
|
|
202
|
+
return (
|
|
203
|
+
<div>
|
|
204
|
+
<p>{fieldCount} fields | Mode: {isPreview ? 'Preview' : 'Edit'}</p>
|
|
205
|
+
<QuestionnaireEditor />
|
|
206
|
+
</div>
|
|
207
|
+
);
|
|
208
|
+
}
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
## 🔧 Field Structure
|
|
212
|
+
|
|
213
|
+
Each field follows this structure:
|
|
214
|
+
|
|
215
|
+
```js
|
|
216
|
+
{
|
|
217
|
+
id: 'unique-id', // Required: unique identifier
|
|
218
|
+
fieldType: 'input', // Required: 'input', 'radio', 'check', 'dropdown', 'section'
|
|
219
|
+
question: 'Your question?', // Required: field label
|
|
220
|
+
answer: '', // For input fields
|
|
221
|
+
options: ['A', 'B', 'C'], // For radio/check/dropdown
|
|
222
|
+
selected: null, // For radio (single choice)
|
|
223
|
+
selectedOptions: [], // For check (multiple choice)
|
|
224
|
+
fields: [], // For section (nested fields)
|
|
225
|
+
enableWhen: [ // Optional: conditional logic
|
|
226
|
+
{
|
|
227
|
+
question: 'field-id',
|
|
228
|
+
operator: 'equals',
|
|
229
|
+
answer: 'Yes'
|
|
230
|
+
}
|
|
231
|
+
]
|
|
232
|
+
}
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
## 📦 Bundle Size
|
|
236
|
+
|
|
237
|
+
- **48.13 KB** (ESM, uncompressed)
|
|
238
|
+
- **489 B** CSS
|
|
239
|
+
|
|
240
|
+
## 🎨 Theming
|
|
241
|
+
|
|
242
|
+
The editor uses Tailwind CSS under the hood. Import your own Tailwind config or override classes:
|
|
243
|
+
|
|
244
|
+
```jsx
|
|
245
|
+
import '@mieweb/forms-editor/styles.css';
|
|
246
|
+
import './my-overrides.css'; // Your custom styles
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
## 🔗 Related Packages
|
|
250
|
+
|
|
251
|
+
- **@mieweb/forms-engine** - Core form primitives (auto-installed)
|
|
252
|
+
- **@mieweb/forms-renderer** - Read-only renderer for filled forms
|
|
253
|
+
|
|
254
|
+
## 📄 License
|
|
255
|
+
|
|
256
|
+
MIT
|
package/dist/index.css
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
@import "https://fonts.googleapis.com/css2?family=Titillium+Web:ital,wght@0,200;0,300;0,400;0,600;0,700;0,900;1,200;1,300;1,400;1,600;1,700&display=swap";
|
|
2
|
+
@import "tailwindcss";
|
|
3
|
+
|
|
4
|
+
/* src/index.css */
|
|
5
|
+
@theme { --font-titillium: "Titillium Web", sans-serif; }
|
|
6
|
+
@utility custom-scrollbar { @apply [&::-webkit-scrollbar]:w-1.5 [&::-webkit-scrollbar-track]:rounded-full [&::-webkit-scrollbar-track]:bg-gray-100 [&::-webkit-scrollbar-thumb]:rounded-full [&::-webkit-scrollbar-thumb]:bg-gray-500 }
|