@mieweb/forms-editor 0.1.6 → 0.1.8
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 +51 -208
- package/dist/index.js +819 -759
- package/dist/index.js.map +1 -1
- package/package.json +5 -4
- package/dist/index.css +0 -1
package/README.md
CHANGED
|
@@ -1,237 +1,80 @@
|
|
|
1
|
-
# @mieweb/forms-editor
|
|
1
|
+
# @mieweb/forms-editor
|
|
2
2
|
|
|
3
|
-
Embeddable questionnaire editor
|
|
4
|
-
|
|
5
|
-
## 📦 Installation
|
|
3
|
+
Embeddable questionnaire editor with FHIR export and conditional logic.
|
|
6
4
|
|
|
7
5
|
```bash
|
|
8
|
-
npm install @mieweb/forms-editor
|
|
6
|
+
npm install @mieweb/forms-editor react react-dom
|
|
9
7
|
```
|
|
10
8
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
You must install React 18+ in your project:
|
|
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
|
-
### Basic Usage
|
|
9
|
+
## Quick Start
|
|
30
10
|
|
|
31
11
|
```jsx
|
|
32
12
|
import { QuestionnaireEditor } from '@mieweb/forms-editor';
|
|
33
|
-
import { createRoot } from 'react-dom/client';
|
|
34
|
-
import './index.css';
|
|
35
13
|
|
|
36
14
|
function App() {
|
|
37
15
|
const [fields, setFields] = React.useState([
|
|
38
16
|
{ id: 'section-1', fieldType: 'section', title: 'Section 1', fields: [] },
|
|
39
|
-
{ id: 'name', fieldType: '
|
|
40
|
-
{ id: 'gender', fieldType: 'radio', question: 'Gender',
|
|
17
|
+
{ id: 'name', fieldType: 'text', question: 'Your Name', required: true },
|
|
18
|
+
{ id: 'gender', fieldType: 'radio', question: 'Gender',
|
|
19
|
+
options: [{ value: 'Male' }, { value: 'Female' }], selected: null },
|
|
41
20
|
]);
|
|
42
21
|
|
|
43
22
|
return (
|
|
44
|
-
<
|
|
45
|
-
<div className="absolute inset-0 overflow-auto">
|
|
46
|
-
<QuestionnaireEditor
|
|
47
|
-
initialFields={fields}
|
|
48
|
-
onChange={setFields}
|
|
49
|
-
/>
|
|
50
|
-
</div>
|
|
51
|
-
</div>
|
|
52
|
-
);
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
createRoot(document.getElementById('root')).render(<App />);
|
|
56
|
-
```
|
|
57
|
-
|
|
58
|
-
### With State Persistence
|
|
59
|
-
|
|
60
|
-
```jsx
|
|
61
|
-
function App() {
|
|
62
|
-
const [fields, setFields] = React.useState(() => {
|
|
63
|
-
const saved = localStorage.getItem('questionnaire');
|
|
64
|
-
return saved ? JSON.parse(saved) : [];
|
|
65
|
-
});
|
|
66
|
-
|
|
67
|
-
const handleChange = (newFields) => {
|
|
68
|
-
setFields(newFields);
|
|
69
|
-
localStorage.setItem('questionnaire', JSON.stringify(newFields));
|
|
70
|
-
};
|
|
71
|
-
|
|
72
|
-
return (
|
|
73
|
-
<div className="absolute inset-0 overflow-auto">
|
|
74
|
-
<QuestionnaireEditor
|
|
75
|
-
initialFields={fields}
|
|
76
|
-
onChange={handleChange}
|
|
77
|
-
/>
|
|
78
|
-
</div>
|
|
23
|
+
<QuestionnaireEditor initialFields={fields} onChange={setFields} />
|
|
79
24
|
);
|
|
80
25
|
}
|
|
81
26
|
```
|
|
82
27
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
## 📖 Props
|
|
86
|
-
|
|
87
|
-
### `QuestionnaireEditor`
|
|
88
|
-
|
|
89
|
-
| Prop | Type | Default | Description |
|
|
90
|
-
|------|------|---------|-------------|
|
|
91
|
-
| `initialFields` | `Array` | `[]` | Initial questionnaire fields |
|
|
92
|
-
| `onChange` | `Function` | `undefined` | Callback when fields change: `(fields) => void` |
|
|
93
|
-
| `className` | `String` | `''` | Additional CSS classes |
|
|
94
|
-
| `showHeader` | `Boolean` | `true` | Show/hide the header with actions |
|
|
95
|
-
| `showMobileToolbar` | `Boolean` | `true` | Show/hide mobile toolbar |
|
|
96
|
-
| `startInPreview` | `Boolean` | `false` | Start in preview mode |
|
|
97
|
-
|
|
98
|
-
## ✨ Features
|
|
99
|
-
|
|
100
|
-
### 🎨 Add & Edit Fields
|
|
101
|
-
|
|
102
|
-
Add fields from the toolbar:
|
|
103
|
-
- **Text Input** - Single-line text
|
|
104
|
-
- **Radio Buttons** - Single choice
|
|
105
|
-
- **Checkboxes** - Multiple choice
|
|
106
|
-
- **Dropdown** - Select menu
|
|
107
|
-
- **Section** - Group fields together
|
|
108
|
-
|
|
109
|
-
### 🔄 Import/Export
|
|
110
|
-
|
|
111
|
-
Built-in support for:
|
|
112
|
-
- **JSON** - Questionnaire data format
|
|
113
|
-
- **FHIR** - FHIR Questionnaire standard
|
|
114
|
-
- **YAML** - Human-readable format
|
|
115
|
-
|
|
116
|
-
```jsx
|
|
117
|
-
import { useFormStore } from '@mieweb/forms-engine';
|
|
118
|
-
|
|
119
|
-
function ExportButtons() {
|
|
120
|
-
const fields = useFormStore(state => state.flatArray());
|
|
121
|
-
|
|
122
|
-
const exportJSON = () => {
|
|
123
|
-
const json = JSON.stringify(fields, null, 2);
|
|
124
|
-
// Download or save
|
|
125
|
-
};
|
|
126
|
-
|
|
127
|
-
return <button onClick={exportJSON}>Export JSON</button>;
|
|
128
|
-
}
|
|
129
|
-
```
|
|
130
|
-
|
|
131
|
-
### 🔀 Conditional Logic (enableWhen)
|
|
132
|
-
|
|
133
|
-
Show/hide fields based on answers to other fields:
|
|
134
|
-
|
|
135
|
-
1. Select a field
|
|
136
|
-
2. Click "Logic" in the edit panel
|
|
137
|
-
3. Add conditions (e.g., "Show when Question 1 equals 'Yes'")
|
|
28
|
+
## Props
|
|
138
29
|
|
|
139
|
-
|
|
30
|
+
- `initialFields` - Array of field objects
|
|
31
|
+
- `onChange` - Callback when fields change
|
|
32
|
+
- `startInPreview` - Start in preview mode (default: false)
|
|
33
|
+
- `hideUnsupportedFields` - Hide unsupported field types (default: false)
|
|
34
|
+
- `showHeader` - Show editor header (default: true)
|
|
35
|
+
- `showMobileToolbar` - Show mobile toolbar (default: true)
|
|
36
|
+
- `className` - Additional CSS classes
|
|
140
37
|
|
|
141
|
-
|
|
142
|
-
- Mobile: Swipeable modal for field editing
|
|
38
|
+
## Features
|
|
143
39
|
|
|
144
|
-
###
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
### Custom Styling
|
|
155
|
-
|
|
156
|
-
```jsx
|
|
157
|
-
<div className="absolute inset-0 overflow-auto">
|
|
158
|
-
<QuestionnaireEditor
|
|
159
|
-
className="custom-editor"
|
|
160
|
-
initialFields={fields}
|
|
161
|
-
onChange={setFields}
|
|
162
|
-
/>
|
|
163
|
-
</div>
|
|
164
|
-
```
|
|
165
|
-
|
|
166
|
-
### Start in Preview Mode
|
|
167
|
-
|
|
168
|
-
```jsx
|
|
169
|
-
<QuestionnaireEditor
|
|
170
|
-
initialFields={fields}
|
|
171
|
-
onChange={setFields}
|
|
172
|
-
startInPreview={true}
|
|
173
|
-
/>
|
|
174
|
-
```
|
|
40
|
+
### Field Types
|
|
41
|
+
- `text` - Single-line text input
|
|
42
|
+
- `longtext` - Multi-line text area
|
|
43
|
+
- `multitext` - Multiple labeled text inputs
|
|
44
|
+
- `boolean` - Yes/No button selection
|
|
45
|
+
- `radio` - Radio buttons
|
|
46
|
+
- `check` - Checkboxes
|
|
47
|
+
- `dropdown` - Dropdown selection
|
|
48
|
+
- `section` - Field container
|
|
49
|
+
- `unsupported` - Placeholder (can be hidden with `hideUnsupportedFields` prop)
|
|
175
50
|
|
|
176
|
-
###
|
|
51
|
+
### Conditional Logic
|
|
52
|
+
Show/hide fields based on answers via the Logic panel.
|
|
177
53
|
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
initialFields={fields}
|
|
181
|
-
onChange={setFields}
|
|
182
|
-
showHeader={false}
|
|
183
|
-
showMobileToolbar={false}
|
|
184
|
-
/>
|
|
185
|
-
```
|
|
54
|
+
### Import/Export
|
|
55
|
+
- JSON, YAML, FHIR formats
|
|
186
56
|
|
|
187
|
-
|
|
57
|
+
### Mobile Support
|
|
58
|
+
Responsive with swipeable modal editing.
|
|
188
59
|
|
|
189
|
-
|
|
60
|
+
## Field Structure
|
|
190
61
|
|
|
191
|
-
```
|
|
62
|
+
```javascript
|
|
192
63
|
{
|
|
193
|
-
id: 'unique-id',
|
|
194
|
-
fieldType: '
|
|
195
|
-
question: '
|
|
196
|
-
answer: '',
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
64
|
+
id: 'unique-id',
|
|
65
|
+
fieldType: 'text', // 'longtext', 'multitext', 'boolean', 'radio', 'check', 'dropdown', 'section'
|
|
66
|
+
question: 'What is your name?',
|
|
67
|
+
answer: '',
|
|
68
|
+
required: false,
|
|
69
|
+
enableWhen: {
|
|
70
|
+
logic: 'AND', // or 'OR'
|
|
71
|
+
conditions: [
|
|
72
|
+
{
|
|
73
|
+
targetId: 'other-field-id',
|
|
74
|
+
operator: 'equals', // 'contains', 'includes'
|
|
75
|
+
value: 'expected-value'
|
|
76
|
+
}
|
|
77
|
+
]
|
|
78
|
+
}
|
|
208
79
|
}
|
|
209
|
-
```
|
|
210
|
-
|
|
211
|
-
## 📦 Bundle Size
|
|
212
|
-
|
|
213
|
-
- **ESM format** with tree-shaking support
|
|
214
|
-
- **TypeScript definitions** included
|
|
215
|
-
- **CSS automatically injected** - no manual imports needed
|
|
216
|
-
- Dependencies: `@mieweb/forms-engine`, `framer-motion`, `js-yaml`
|
|
217
|
-
- Peer dependencies: React 18+
|
|
218
|
-
|
|
219
|
-
## 🎨 Theming
|
|
220
|
-
|
|
221
|
-
**CSS is automatically included** when you import the package! The Tailwind CSS styles are bundled directly into the JavaScript.
|
|
222
|
-
|
|
223
|
-
Override styles by importing your custom CSS after the component:
|
|
224
|
-
|
|
225
|
-
```jsx
|
|
226
|
-
import { QuestionnaireEditor } from '@mieweb/forms-editor';
|
|
227
|
-
import './my-overrides.css'; // Your custom styles
|
|
228
|
-
```
|
|
229
|
-
|
|
230
|
-
## 🔗 Related Packages
|
|
231
|
-
|
|
232
|
-
- **@mieweb/forms-engine** - Core form primitives (auto-installed)
|
|
233
|
-
- **@mieweb/forms-renderer** - Read-only renderer for filled forms
|
|
234
|
-
|
|
235
|
-
## 📄 License
|
|
236
|
-
|
|
237
|
-
MIT
|
|
80
|
+
```
|