@mieweb/forms-renderer 0.1.4 → 0.1.7

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 CHANGED
@@ -1,6 +1,6 @@
1
- # @mieweb/forms-renderer
1
+ # 📋 @mieweb/forms-renderer
2
2
 
3
- Read-only questionnaire renderer for displaying and filling out forms. Produces FHIR QuestionnaireResponse output.
3
+ Read-only questionnaire renderer with dual distribution: React component or Standalone Web Component.
4
4
 
5
5
  ## 📦 Installation
6
6
 
@@ -8,344 +8,197 @@ Read-only questionnaire renderer for displaying and filling out forms. Produces
8
8
  npm install @mieweb/forms-renderer
9
9
  ```
10
10
 
11
- ### Peer Dependencies
11
+ ## 🚀 Examples
12
12
 
13
- Ensure you have React 18+ installed:
13
+ See the complete working examples in this package:
14
+ - [`example-react.jsx`](./example-react.jsx) - ⚛️ React component usage
15
+ - [`example-standalone.html`](./example-standalone.html) - 🌐 Web Component usage
14
16
 
17
+ ## 💻 Usage
18
+
19
+ ### ⚛️ React Component (Recommended for React Projects)
20
+
21
+ Requires React peer dependencies:
15
22
  ```bash
16
23
  npm install react react-dom
17
24
  ```
18
25
 
19
- ### Automatic Dependencies
20
-
21
- The following is installed automatically:
22
-
23
- - `@mieweb/forms-engine` - Core form state and field components
24
-
25
- ## 🚀 Quick Start
26
-
27
- ### 1. Basic Usage
28
-
26
+ From [`example-react.jsx`](./example-react.jsx):
29
27
  ```jsx
30
28
  import { QuestionnaireRenderer } from '@mieweb/forms-renderer';
31
29
 
32
- function App({ fields }) {
33
- const handleChange = (updatedFields) => {
34
- console.log('Form data:', updatedFields);
35
- };
36
-
37
- const handleSubmit = (fhirResponse) => {
38
- console.log('FHIR QuestionnaireResponse:', fhirResponse);
39
- // Send to your backend
40
- };
30
+ function App() {
31
+ const [fields] = React.useState([
32
+ {
33
+ id: 'sec-1',
34
+ fieldType: 'section',
35
+ title: 'Personal Information',
36
+ fields: [
37
+ {
38
+ id: 'q-name',
39
+ fieldType: 'input',
40
+ question: 'What is your full name?',
41
+ answer: ''
42
+ },
43
+ {
44
+ id: 'q-gender',
45
+ fieldType: 'radio',
46
+ question: 'Biological sex',
47
+ options: [
48
+ { id: 'gender-male', value: 'Male' },
49
+ { id: 'gender-female', value: 'Female' }
50
+ ],
51
+ selected: null
52
+ }
53
+ ]
54
+ }
55
+ ]);
41
56
 
42
57
  return (
43
58
  <QuestionnaireRenderer
59
+ questionnaireId="demo-questionnaire"
44
60
  fields={fields}
45
- onChange={handleChange}
46
- onSubmit={handleSubmit}
47
- questionnaireId="patient-intake-v1"
48
- subjectId="patient-12345"
61
+ onChange={(updatedFields) => console.log('Changed:', updatedFields)}
62
+ onSubmit={(fhirResponse) => console.log('Submitted:', fhirResponse)}
49
63
  />
50
64
  );
51
65
  }
52
66
  ```
53
67
 
54
- ### 2. Field Structure
55
-
56
- The `fields` prop accepts any data source (API, database, local storage) that matches this JSON structure:
57
-
58
- ```js
59
- // Example: Simple questionnaire data
60
- [
61
- {
62
- id: '1',
63
- fieldType: 'input',
64
- question: 'What is your name?',
65
- answer: ''
66
- },
67
- {
68
- id: '2',
69
- fieldType: 'radio',
70
- question: 'Select your role',
71
- options: ['Developer', 'Designer', 'Manager'],
72
- selected: null
73
- }
74
- ]
75
-
76
- // Example: Complex medical screening with sections and conditional logic
77
- [
78
- {
79
- fieldType: "section",
80
- title: "Patient Information",
81
- id: "sec-patient-info",
82
- fields: [
83
- { fieldType: "input", question: "First name", answer: "", id: "pi-first-name" },
84
- { fieldType: "input", question: "Last name", answer: "", id: "pi-last-name" },
85
- {
86
- fieldType: "selection",
87
- question: "Biological sex",
88
- options: [
89
- { id: "pi-sex-m", value: "Male" },
90
- { id: "pi-sex-f", value: "Female" }
91
- ],
92
- selected: null,
93
- id: "pi-sex"
94
- }
95
- ]
96
- },
97
- {
98
- fieldType: "section",
99
- title: "Pregnancy & OB",
100
- id: "sec-pregnancy",
101
- enableWhen: {
102
- logic: "AND",
103
- conditions: [
104
- { targetId: "pi-sex", operator: "equals", value: "pi-sex-f" }
105
- ]
106
- },
107
- fields: [
108
- {
109
- fieldType: "radio",
110
- question: "Are you currently pregnant?",
111
- options: [
112
- { id: "preg-yes", value: "Yes" },
113
- { id: "preg-no", value: "No" }
114
- ],
115
- selected: null,
116
- id: "preg-status"
117
- }
118
- ]
119
- }
120
- ]
121
- ```
122
-
123
- **Any JSON object matching this structure works** - whether from your backend API, a database query, local storage, or a CMS.
124
-
125
- ## 📖 Props
126
-
127
- ### `QuestionnaireRenderer`
128
-
129
- | Prop | Type | Default | Description |
130
- |------|------|---------|-------------|
131
- | `fields` | `Array` | **Required** | Questionnaire definition from your data source (API, database, etc.) |
132
- | `onChange` | `Function` | `undefined` | Callback when answers change: `(fields) => void` |
133
- | `onSubmit` | `Function` | `undefined` | Callback on submit: `(fhirResponse) => void` |
134
- | `questionnaireId` | `String` | `'questionnaire-1'` | ID for FHIR Questionnaire reference |
135
- | `subjectId` | `String` | `undefined` | Patient/subject ID for FHIR response |
136
- | `className` | `String` | `''` | Additional CSS classes |
137
- | `fullHeight` | `Boolean` | `false` | Use full viewport height |
138
-
139
- ## ✨ Features
140
-
141
- ### ✅ Read-Only Display
142
-
143
- - Displays questionnaire fields without editing controls
144
- - Users can **fill out** the form but **cannot add/remove/reorder** fields
145
-
146
- ### 📋 Supported Field Types
147
-
148
- - **Text Input** - Single-line text entry
149
- - **Radio Buttons** - Single choice selection
150
- - **Checkboxes** - Multiple choice selection
151
- - **Dropdown** - Select menu
152
- - **Section** - Grouped fields with collapse/expand
153
-
154
- ### 🔀 Conditional Logic (enableWhen)
155
-
156
- Automatically shows/hides fields based on answers:
157
-
158
- ```jsx
159
- const fields = [
160
- {
161
- id: '1',
162
- fieldType: 'radio',
163
- question: 'Do you have symptoms?',
164
- options: ['Yes', 'No'],
165
- selected: null
166
- },
167
- {
168
- id: '2',
169
- fieldType: 'input',
170
- question: 'Describe your symptoms',
171
- answer: '',
172
- enableWhen: [
173
- {
174
- question: '1', // ID of field to check
175
- operator: 'equals',
176
- answer: 'Yes'
177
- }
178
- ]
179
- }
180
- ];
181
- ```
182
-
183
- Field `2` only appears when field `1` is answered with "Yes".
68
+ ### 🌐 Standalone Web Component (Framework-Agnostic)
184
69
 
185
- ### 🏥 FHIR QuestionnaireResponse
70
+ Zero dependencies - works with any framework or vanilla JS.
186
71
 
187
- On submit, generates a standard FHIR R4 QuestionnaireResponse:
188
-
189
- ```js
190
- {
191
- resourceType: "QuestionnaireResponse",
192
- id: "response-uuid",
193
- questionnaire: "questionnaire-1",
194
- status: "completed",
195
- authored: "2025-10-02T10:30:00Z",
196
- subject: {
197
- reference: "Patient/patient-12345"
198
- },
199
- item: [
72
+ From [`example-standalone.html`](./example-standalone.html):
73
+ ```html
74
+ <script type="module">
75
+ import './package/dist/standalone.js';
76
+
77
+ const renderer = document.querySelector('questionnaire-renderer');
78
+ renderer.fields = [
200
79
  {
201
- linkId: "1",
202
- text: "What is your name?",
203
- answer: [
80
+ id: 'sec-1',
81
+ fieldType: 'section',
82
+ title: 'Patient Information',
83
+ fields: [
84
+ {
85
+ id: 'q-name',
86
+ fieldType: 'input',
87
+ question: 'Full Name',
88
+ answer: ''
89
+ },
204
90
  {
205
- valueString: "John Doe"
91
+ id: 'q-gender',
92
+ fieldType: 'radio',
93
+ question: 'Biological sex',
94
+ options: [
95
+ { id: 'gender-male', value: 'Male' },
96
+ { id: 'gender-female', value: 'Female' }
97
+ ],
98
+ selected: null
206
99
  }
207
100
  ]
208
101
  }
209
- // ... more items
210
- ]
211
- }
212
- ```
213
-
214
- ## 🎯 Usage Examples
215
-
216
- ### Saving Responses
217
-
218
- ```jsx
219
- import { QuestionnaireRenderer } from '@mieweb/forms-renderer';
220
- import { useState } from 'react';
221
-
222
- function FormPage() {
223
- const [responses, setResponses] = useState([]);
224
-
225
- const handleSubmit = async (fhirResponse) => {
226
- // Save to backend
227
- await fetch('/api/responses', {
228
- method: 'POST',
229
- headers: { 'Content-Type': 'application/json' },
230
- body: JSON.stringify(fhirResponse)
231
- });
232
-
233
- setResponses([...responses, fhirResponse]);
234
- alert('Form submitted successfully!');
102
+ ];
103
+
104
+ renderer.onSubmit = (fhirResponse) => {
105
+ console.log('Form submitted:', fhirResponse);
235
106
  };
107
+ </script>
236
108
 
237
- return (
238
- <QuestionnaireRenderer
239
- fields={fields}
240
- onSubmit={handleSubmit}
241
- questionnaireId="patient-intake"
242
- subjectId="patient-67890"
243
- />
244
- );
245
- }
246
- ```
247
-
248
- ### Pre-filled Form
249
-
250
- ```jsx
251
- const prefilledFields = [
252
- {
253
- id: '1',
254
- fieldType: 'input',
255
- question: 'Full Name',
256
- answer: 'Jane Doe' // Pre-filled
257
- },
258
- {
259
- id: '2',
260
- fieldType: 'radio',
261
- question: 'Gender',
262
- options: ['Male', 'Female', 'Other'],
263
- selected: 'Female' // Pre-filled
264
- }
265
- ];
266
-
267
- <QuestionnaireRenderer fields={prefilledFields} />
109
+ <questionnaire-renderer
110
+ questionnaire-id="standalone-demo"
111
+ full-height>
112
+ </questionnaire-renderer>
268
113
  ```
269
114
 
270
- ### Real-time Validation
115
+ ## ⚙️ Props/Attributes
271
116
 
272
- ```jsx
273
- function ValidatedForm() {
274
- const [errors, setErrors] = useState({});
117
+ ### ⚛️ React Component
118
+ - `fields` - Questionnaire definition array
119
+ - `onChange` - Callback when answers change
120
+ - `onSubmit` - Callback on form submit
121
+ - `questionnaireId` - FHIR Questionnaire ID
122
+ - `subjectId` - Patient/subject ID
123
+ - `className` - CSS classes
124
+ - `fullHeight` - Full viewport height
275
125
 
276
- const handleChange = (fields) => {
277
- const newErrors = {};
278
-
279
- fields.forEach(field => {
280
- if (field.required && !field.answer && !field.selected) {
281
- newErrors[field.id] = 'This field is required';
282
- }
283
- });
126
+ ### 🌐 Web Component
127
+ - `questionnaire-id` - FHIR Questionnaire ID (attribute)
128
+ - `full-height` - Full viewport height (attribute)
129
+ - `fields` - Questionnaire definition (property)
130
+ - `onChange` - Change callback (property)
131
+ - `onSubmit` - Submit callback (property)
284
132
 
285
- setErrors(newErrors);
286
- };
133
+ ## 🔧 Field Types
287
134
 
288
- return (
289
- <div>
290
- <QuestionnaireRenderer
291
- fields={fields}
292
- onChange={handleChange}
293
- />
294
- {Object.values(errors).map(err => (
295
- <p className="text-red-500">{err}</p>
296
- ))}
297
- </div>
298
- );
299
- }
300
- ```
135
+ - `input` - 📝 Text input field
136
+ - `radio` - 🔘 Single selection radio buttons
137
+ - `check` - ☑️ Multiple selection checkboxes
138
+ - `selection` - 📋 Dropdown selection
139
+ - `section` - 📂 Container for grouping fields
301
140
 
302
- ## 🔧 Field Structure
141
+ ## 🔀 Conditional Logic (enableWhen)
303
142
 
304
- Fields use the same structure as `@mieweb/forms-editor`:
143
+ Fields can be shown/hidden based on other field values. Both examples include conditional logic:
305
144
 
306
- ```js
145
+ From [`example-react.jsx`](./example-react.jsx):
146
+ ```javascript
307
147
  {
308
- id: 'unique-id',
309
- fieldType: 'input' | 'radio' | 'check' | 'dropdown' | 'section',
310
- question: 'Your question text',
311
- answer: '', // For input
312
- options: [], // For radio/check/dropdown
313
- selected: null, // For radio
314
- selectedOptions: [], // For check
315
- fields: [], // For section
316
- enableWhen: [] // Conditional logic
148
+ id: 'sec-pregnancy',
149
+ fieldType: 'section',
150
+ title: 'Pregnancy Information',
151
+ enableWhen: {
152
+ logic: 'AND',
153
+ conditions: [
154
+ { targetId: 'q-gender', operator: 'equals', value: 'gender-female' }
155
+ ]
156
+ },
157
+ fields: [
158
+ {
159
+ id: 'q-weeks',
160
+ fieldType: 'input',
161
+ question: 'Weeks gestation (if known)',
162
+ answer: '',
163
+ enableWhen: {
164
+ logic: 'AND',
165
+ conditions: [
166
+ { targetId: 'q-pregnant', operator: 'equals', value: 'preg-yes' }
167
+ ]
168
+ }
169
+ }
170
+ ]
317
171
  }
318
172
  ```
319
173
 
320
- ## 📦 Bundle Size
321
-
322
- - **4.85 KB** (ESM, uncompressed)
323
- - Very lightweight - perfect for embedding in patient portals
324
-
325
- ## 🎨 Styling
326
-
327
- **CSS is automatically included** when you import the package! The styles come bundled via the `@mieweb/forms-engine` dependency.
328
-
329
- Override with custom CSS:
174
+ ## 🏥 FHIR Output
330
175
 
331
- ```css
332
- .qr-renderer-root {
333
- max-width: 800px;
334
- margin: 0 auto;
335
- }
176
+ The `onSubmit` callback receives a FHIR QuestionnaireResponse:
336
177
 
337
- .qr-submit-btn {
338
- background: #10b981;
339
- color: white;
340
- padding: 0.75rem 2rem;
178
+ ```javascript
179
+ {
180
+ resourceType: 'QuestionnaireResponse',
181
+ questionnaire: 'demo-1',
182
+ status: 'completed',
183
+ authored: '2023-01-01T12:00:00Z',
184
+ item: [
185
+ {
186
+ linkId: 'q1',
187
+ text: 'What is your name?',
188
+ answer: [{ valueString: 'John Doe' }]
189
+ }
190
+ ]
341
191
  }
342
192
  ```
343
193
 
344
- ## 🔗 Related Packages
194
+ ## 📊 Bundle Sizes
345
195
 
346
- - **@mieweb/forms-engine** - Core form primitives (auto-installed)
347
- - **@mieweb/forms-editor** - Full questionnaire editor UI
196
+ - **⚛️ React version**: ~24 KB (requires peer deps)
197
+ - **🌐 Standalone version**: ~819 KB (zero dependencies)
348
198
 
349
- ## 📄 License
199
+ ## 📚 Documentation
350
200
 
351
- MIT
201
+ - [📖 Migration Guide](./docs/MIGRATION.md)
202
+ - [🚀 Meteor/Blaze Guide](./docs/METEOR-BLAZE-GUIDE.md)
203
+ - [🌐 Web Component Summary](./docs/WEB-COMPONENT-SUMMARY.md)
204
+ - [🏗️ Architecture](./docs/ARCHITECTURE.md)