@mieweb/forms-renderer 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 +356 -0
- package/dist/index.js +130 -0
- package/package.json +27 -0
package/README.md
ADDED
|
@@ -0,0 +1,356 @@
|
|
|
1
|
+
# @mieweb/forms-renderer
|
|
2
|
+
|
|
3
|
+
Read-only questionnaire renderer for displaying and filling out forms. Produces FHIR QuestionnaireResponse output.
|
|
4
|
+
|
|
5
|
+
## 📦 Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @mieweb/forms-renderer
|
|
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 is installed automatically:
|
|
22
|
+
|
|
23
|
+
- `@mieweb/forms-engine` - Core form state and field components
|
|
24
|
+
|
|
25
|
+
## 🚀 Quick Start
|
|
26
|
+
|
|
27
|
+
### 1. Basic Usage
|
|
28
|
+
|
|
29
|
+
```jsx
|
|
30
|
+
import { QuestionnaireRenderer } from '@mieweb/forms-renderer';
|
|
31
|
+
import '@mieweb/forms-engine/styles.css'; // Import styles
|
|
32
|
+
|
|
33
|
+
function App({ fields }) {
|
|
34
|
+
const handleChange = (updatedFields) => {
|
|
35
|
+
console.log('Form data:', updatedFields);
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
const handleSubmit = (fhirResponse) => {
|
|
39
|
+
console.log('FHIR QuestionnaireResponse:', fhirResponse);
|
|
40
|
+
// Send to your backend
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
return (
|
|
44
|
+
<QuestionnaireRenderer
|
|
45
|
+
fields={fields}
|
|
46
|
+
onChange={handleChange}
|
|
47
|
+
onSubmit={handleSubmit}
|
|
48
|
+
questionnaireId="patient-intake-v1"
|
|
49
|
+
subjectId="patient-12345"
|
|
50
|
+
/>
|
|
51
|
+
);
|
|
52
|
+
}
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
### 2. Field Structure
|
|
56
|
+
|
|
57
|
+
The `fields` prop accepts any data source (API, database, local storage) that matches this JSON structure:
|
|
58
|
+
|
|
59
|
+
```js
|
|
60
|
+
// Example: Simple questionnaire data
|
|
61
|
+
[
|
|
62
|
+
{
|
|
63
|
+
id: '1',
|
|
64
|
+
fieldType: 'input',
|
|
65
|
+
question: 'What is your name?',
|
|
66
|
+
answer: ''
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
id: '2',
|
|
70
|
+
fieldType: 'radio',
|
|
71
|
+
question: 'Select your role',
|
|
72
|
+
options: ['Developer', 'Designer', 'Manager'],
|
|
73
|
+
selected: null
|
|
74
|
+
}
|
|
75
|
+
]
|
|
76
|
+
|
|
77
|
+
// Example: Complex medical screening with sections and conditional logic
|
|
78
|
+
[
|
|
79
|
+
{
|
|
80
|
+
fieldType: "section",
|
|
81
|
+
title: "Patient Information",
|
|
82
|
+
id: "sec-patient-info",
|
|
83
|
+
fields: [
|
|
84
|
+
{ fieldType: "input", question: "First name", answer: "", id: "pi-first-name" },
|
|
85
|
+
{ fieldType: "input", question: "Last name", answer: "", id: "pi-last-name" },
|
|
86
|
+
{
|
|
87
|
+
fieldType: "selection",
|
|
88
|
+
question: "Biological sex",
|
|
89
|
+
options: [
|
|
90
|
+
{ id: "pi-sex-m", value: "Male" },
|
|
91
|
+
{ id: "pi-sex-f", value: "Female" }
|
|
92
|
+
],
|
|
93
|
+
selected: null,
|
|
94
|
+
id: "pi-sex"
|
|
95
|
+
}
|
|
96
|
+
]
|
|
97
|
+
},
|
|
98
|
+
{
|
|
99
|
+
fieldType: "section",
|
|
100
|
+
title: "Pregnancy & OB",
|
|
101
|
+
id: "sec-pregnancy",
|
|
102
|
+
enableWhen: {
|
|
103
|
+
logic: "AND",
|
|
104
|
+
conditions: [
|
|
105
|
+
{ targetId: "pi-sex", operator: "equals", value: "pi-sex-f" }
|
|
106
|
+
]
|
|
107
|
+
},
|
|
108
|
+
fields: [
|
|
109
|
+
{
|
|
110
|
+
fieldType: "radio",
|
|
111
|
+
question: "Are you currently pregnant?",
|
|
112
|
+
options: [
|
|
113
|
+
{ id: "preg-yes", value: "Yes" },
|
|
114
|
+
{ id: "preg-no", value: "No" }
|
|
115
|
+
],
|
|
116
|
+
selected: null,
|
|
117
|
+
id: "preg-status"
|
|
118
|
+
}
|
|
119
|
+
]
|
|
120
|
+
}
|
|
121
|
+
]
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
**Any JSON object matching this structure works** - whether from your backend API, a database query, local storage, or a CMS.
|
|
125
|
+
|
|
126
|
+
## 📖 Props
|
|
127
|
+
|
|
128
|
+
### `QuestionnaireRenderer`
|
|
129
|
+
|
|
130
|
+
| Prop | Type | Default | Description |
|
|
131
|
+
|------|------|---------|-------------|
|
|
132
|
+
| `fields` | `Array` | **Required** | Questionnaire definition from your data source (API, database, etc.) |
|
|
133
|
+
| `onChange` | `Function` | `undefined` | Callback when answers change: `(fields) => void` |
|
|
134
|
+
| `onSubmit` | `Function` | `undefined` | Callback on submit: `(fhirResponse) => void` |
|
|
135
|
+
| `questionnaireId` | `String` | `'questionnaire-1'` | ID for FHIR Questionnaire reference |
|
|
136
|
+
| `subjectId` | `String` | `undefined` | Patient/subject ID for FHIR response |
|
|
137
|
+
| `className` | `String` | `''` | Additional CSS classes |
|
|
138
|
+
| `fullHeight` | `Boolean` | `false` | Use full viewport height |
|
|
139
|
+
|
|
140
|
+
## ✨ Features
|
|
141
|
+
|
|
142
|
+
### ✅ Read-Only Display
|
|
143
|
+
|
|
144
|
+
- Displays questionnaire fields without editing controls
|
|
145
|
+
- Users can **fill out** the form but **cannot add/remove/reorder** fields
|
|
146
|
+
|
|
147
|
+
### 📋 Supported Field Types
|
|
148
|
+
|
|
149
|
+
- **Text Input** - Single-line text entry
|
|
150
|
+
- **Radio Buttons** - Single choice selection
|
|
151
|
+
- **Checkboxes** - Multiple choice selection
|
|
152
|
+
- **Dropdown** - Select menu
|
|
153
|
+
- **Section** - Grouped fields with collapse/expand
|
|
154
|
+
|
|
155
|
+
### 🔀 Conditional Logic (enableWhen)
|
|
156
|
+
|
|
157
|
+
Automatically shows/hides fields based on answers:
|
|
158
|
+
|
|
159
|
+
```jsx
|
|
160
|
+
const fields = [
|
|
161
|
+
{
|
|
162
|
+
id: '1',
|
|
163
|
+
fieldType: 'radio',
|
|
164
|
+
question: 'Do you have symptoms?',
|
|
165
|
+
options: ['Yes', 'No'],
|
|
166
|
+
selected: null
|
|
167
|
+
},
|
|
168
|
+
{
|
|
169
|
+
id: '2',
|
|
170
|
+
fieldType: 'input',
|
|
171
|
+
question: 'Describe your symptoms',
|
|
172
|
+
answer: '',
|
|
173
|
+
enableWhen: [
|
|
174
|
+
{
|
|
175
|
+
question: '1', // ID of field to check
|
|
176
|
+
operator: 'equals',
|
|
177
|
+
answer: 'Yes'
|
|
178
|
+
}
|
|
179
|
+
]
|
|
180
|
+
}
|
|
181
|
+
];
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
Field `2` only appears when field `1` is answered with "Yes".
|
|
185
|
+
|
|
186
|
+
### 🏥 FHIR QuestionnaireResponse
|
|
187
|
+
|
|
188
|
+
On submit, generates a standard FHIR R4 QuestionnaireResponse:
|
|
189
|
+
|
|
190
|
+
```js
|
|
191
|
+
{
|
|
192
|
+
resourceType: "QuestionnaireResponse",
|
|
193
|
+
id: "response-uuid",
|
|
194
|
+
questionnaire: "questionnaire-1",
|
|
195
|
+
status: "completed",
|
|
196
|
+
authored: "2025-10-02T10:30:00Z",
|
|
197
|
+
subject: {
|
|
198
|
+
reference: "Patient/patient-12345"
|
|
199
|
+
},
|
|
200
|
+
item: [
|
|
201
|
+
{
|
|
202
|
+
linkId: "1",
|
|
203
|
+
text: "What is your name?",
|
|
204
|
+
answer: [
|
|
205
|
+
{
|
|
206
|
+
valueString: "John Doe"
|
|
207
|
+
}
|
|
208
|
+
]
|
|
209
|
+
}
|
|
210
|
+
// ... more items
|
|
211
|
+
]
|
|
212
|
+
}
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
## 🎯 Usage Examples
|
|
216
|
+
|
|
217
|
+
### Saving Responses
|
|
218
|
+
|
|
219
|
+
```jsx
|
|
220
|
+
import { QuestionnaireRenderer } from '@mieweb/forms-renderer';
|
|
221
|
+
import { useState } from 'react';
|
|
222
|
+
|
|
223
|
+
function FormPage() {
|
|
224
|
+
const [responses, setResponses] = useState([]);
|
|
225
|
+
|
|
226
|
+
const handleSubmit = async (fhirResponse) => {
|
|
227
|
+
// Save to backend
|
|
228
|
+
await fetch('/api/responses', {
|
|
229
|
+
method: 'POST',
|
|
230
|
+
headers: { 'Content-Type': 'application/json' },
|
|
231
|
+
body: JSON.stringify(fhirResponse)
|
|
232
|
+
});
|
|
233
|
+
|
|
234
|
+
setResponses([...responses, fhirResponse]);
|
|
235
|
+
alert('Form submitted successfully!');
|
|
236
|
+
};
|
|
237
|
+
|
|
238
|
+
return (
|
|
239
|
+
<QuestionnaireRenderer
|
|
240
|
+
fields={fields}
|
|
241
|
+
onSubmit={handleSubmit}
|
|
242
|
+
questionnaireId="patient-intake"
|
|
243
|
+
subjectId="patient-67890"
|
|
244
|
+
/>
|
|
245
|
+
);
|
|
246
|
+
}
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
### Pre-filled Form
|
|
250
|
+
|
|
251
|
+
```jsx
|
|
252
|
+
const prefilledFields = [
|
|
253
|
+
{
|
|
254
|
+
id: '1',
|
|
255
|
+
fieldType: 'input',
|
|
256
|
+
question: 'Full Name',
|
|
257
|
+
answer: 'Jane Doe' // Pre-filled
|
|
258
|
+
},
|
|
259
|
+
{
|
|
260
|
+
id: '2',
|
|
261
|
+
fieldType: 'radio',
|
|
262
|
+
question: 'Gender',
|
|
263
|
+
options: ['Male', 'Female', 'Other'],
|
|
264
|
+
selected: 'Female' // Pre-filled
|
|
265
|
+
}
|
|
266
|
+
];
|
|
267
|
+
|
|
268
|
+
<QuestionnaireRenderer fields={prefilledFields} />
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
### Real-time Validation
|
|
272
|
+
|
|
273
|
+
```jsx
|
|
274
|
+
function ValidatedForm() {
|
|
275
|
+
const [errors, setErrors] = useState({});
|
|
276
|
+
|
|
277
|
+
const handleChange = (fields) => {
|
|
278
|
+
const newErrors = {};
|
|
279
|
+
|
|
280
|
+
fields.forEach(field => {
|
|
281
|
+
if (field.required && !field.answer && !field.selected) {
|
|
282
|
+
newErrors[field.id] = 'This field is required';
|
|
283
|
+
}
|
|
284
|
+
});
|
|
285
|
+
|
|
286
|
+
setErrors(newErrors);
|
|
287
|
+
};
|
|
288
|
+
|
|
289
|
+
return (
|
|
290
|
+
<div>
|
|
291
|
+
<QuestionnaireRenderer
|
|
292
|
+
fields={fields}
|
|
293
|
+
onChange={handleChange}
|
|
294
|
+
/>
|
|
295
|
+
{Object.values(errors).map(err => (
|
|
296
|
+
<p className="text-red-500">{err}</p>
|
|
297
|
+
))}
|
|
298
|
+
</div>
|
|
299
|
+
);
|
|
300
|
+
}
|
|
301
|
+
```
|
|
302
|
+
|
|
303
|
+
## 🔧 Field Structure
|
|
304
|
+
|
|
305
|
+
Fields use the same structure as `@mieweb/forms-editor`:
|
|
306
|
+
|
|
307
|
+
```js
|
|
308
|
+
{
|
|
309
|
+
id: 'unique-id',
|
|
310
|
+
fieldType: 'input' | 'radio' | 'check' | 'dropdown' | 'section',
|
|
311
|
+
question: 'Your question text',
|
|
312
|
+
answer: '', // For input
|
|
313
|
+
options: [], // For radio/check/dropdown
|
|
314
|
+
selected: null, // For radio
|
|
315
|
+
selectedOptions: [], // For check
|
|
316
|
+
fields: [], // For section
|
|
317
|
+
enableWhen: [] // Conditional logic
|
|
318
|
+
}
|
|
319
|
+
```
|
|
320
|
+
|
|
321
|
+
## 📦 Bundle Size
|
|
322
|
+
|
|
323
|
+
- **4.85 KB** (ESM, uncompressed)
|
|
324
|
+
- Very lightweight - perfect for embedding in patient portals
|
|
325
|
+
|
|
326
|
+
## 🎨 Styling
|
|
327
|
+
|
|
328
|
+
Import the base styles from `forms-engine`:
|
|
329
|
+
|
|
330
|
+
```jsx
|
|
331
|
+
import '@mieweb/forms-engine/styles.css';
|
|
332
|
+
```
|
|
333
|
+
|
|
334
|
+
Override with custom CSS:
|
|
335
|
+
|
|
336
|
+
```css
|
|
337
|
+
.qr-renderer-root {
|
|
338
|
+
max-width: 800px;
|
|
339
|
+
margin: 0 auto;
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
.qr-submit-btn {
|
|
343
|
+
background: #10b981;
|
|
344
|
+
color: white;
|
|
345
|
+
padding: 0.75rem 2rem;
|
|
346
|
+
}
|
|
347
|
+
```
|
|
348
|
+
|
|
349
|
+
## 🔗 Related Packages
|
|
350
|
+
|
|
351
|
+
- **@mieweb/forms-engine** - Core form primitives (auto-installed)
|
|
352
|
+
- **@mieweb/forms-editor** - Full questionnaire editor UI
|
|
353
|
+
|
|
354
|
+
## 📄 License
|
|
355
|
+
|
|
356
|
+
MIT
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
// src/QuestionnaireRenderer.jsx
|
|
2
|
+
import React from "react";
|
|
3
|
+
import { useFormStore, useUIApi, useFieldsArray, getFieldComponent, isVisible } from "@mieweb/forms-engine";
|
|
4
|
+
import "@mieweb/forms-engine/styles.css";
|
|
5
|
+
function QuestionnaireRenderer({
|
|
6
|
+
fields,
|
|
7
|
+
onChange,
|
|
8
|
+
onSubmit,
|
|
9
|
+
questionnaireId = "questionnaire-1",
|
|
10
|
+
subjectId,
|
|
11
|
+
className = "",
|
|
12
|
+
fullHeight = false
|
|
13
|
+
}) {
|
|
14
|
+
const initializedRef = React.useRef(false);
|
|
15
|
+
const ui = useUIApi();
|
|
16
|
+
React.useEffect(() => {
|
|
17
|
+
if (initializedRef.current || !Array.isArray(fields)) return;
|
|
18
|
+
const sectionChildIds = /* @__PURE__ */ new Set();
|
|
19
|
+
fields.forEach((f) => {
|
|
20
|
+
if ((f == null ? void 0 : f.fieldType) === "section" && Array.isArray(f.fields)) {
|
|
21
|
+
f.fields.forEach((ch) => (ch == null ? void 0 : ch.id) && sectionChildIds.add(ch.id));
|
|
22
|
+
}
|
|
23
|
+
});
|
|
24
|
+
const topOnly = fields.filter((f) => !sectionChildIds.has(f.id));
|
|
25
|
+
useFormStore.getState().replaceAll(topOnly);
|
|
26
|
+
ui.preview.set(true);
|
|
27
|
+
initializedRef.current = true;
|
|
28
|
+
}, [fields, ui.preview]);
|
|
29
|
+
React.useEffect(() => {
|
|
30
|
+
if (!onChange) return;
|
|
31
|
+
const unsub = useFormStore.subscribe((s) => {
|
|
32
|
+
const arr = s.flatArray ? s.flatArray() : Object.values(s.byId);
|
|
33
|
+
onChange(arr);
|
|
34
|
+
});
|
|
35
|
+
return unsub;
|
|
36
|
+
}, [onChange]);
|
|
37
|
+
const all = useFieldsArray();
|
|
38
|
+
const buildQuestionnaireResponse = React.useCallback(() => {
|
|
39
|
+
const items = [];
|
|
40
|
+
(all || []).forEach((f) => {
|
|
41
|
+
if (f.fieldType === "section" && Array.isArray(f.fields)) {
|
|
42
|
+
f.fields.forEach((ch) => {
|
|
43
|
+
if (!ch) return;
|
|
44
|
+
items.push({
|
|
45
|
+
linkId: ch.id,
|
|
46
|
+
text: ch.question || ch.title || "",
|
|
47
|
+
answer: toFhirAnswers(ch)
|
|
48
|
+
});
|
|
49
|
+
});
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
if (f.fieldType !== "section") {
|
|
53
|
+
items.push({
|
|
54
|
+
linkId: f.id,
|
|
55
|
+
text: f.question || f.title || "",
|
|
56
|
+
answer: toFhirAnswers(f)
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
});
|
|
60
|
+
return {
|
|
61
|
+
resourceType: "QuestionnaireResponse",
|
|
62
|
+
questionnaire: questionnaireId,
|
|
63
|
+
status: "in-progress",
|
|
64
|
+
subject: subjectId ? { reference: `Patient/${subjectId}` } : void 0,
|
|
65
|
+
item: items
|
|
66
|
+
};
|
|
67
|
+
}, [all, questionnaireId, subjectId]);
|
|
68
|
+
const handleSubmit = (e) => {
|
|
69
|
+
e.preventDefault();
|
|
70
|
+
const qr = buildQuestionnaireResponse();
|
|
71
|
+
onSubmit == null ? void 0 : onSubmit(qr);
|
|
72
|
+
};
|
|
73
|
+
const rootClasses = [
|
|
74
|
+
"qb-render-root",
|
|
75
|
+
"bg-gray-100",
|
|
76
|
+
"font-titillium",
|
|
77
|
+
fullHeight ? "min-h-screen" : "",
|
|
78
|
+
className
|
|
79
|
+
].filter(Boolean).join(" ");
|
|
80
|
+
return /* @__PURE__ */ React.createElement("div", { className: rootClasses }, /* @__PURE__ */ React.createElement("form", { onSubmit: handleSubmit, className: "max-w-4xl mx-auto px-2 pb-8 pt-4" }, /* @__PURE__ */ React.createElement(RendererBody, null), /* @__PURE__ */ React.createElement("div", { className: "pt-2" }, /* @__PURE__ */ React.createElement("button", { type: "submit", className: "px-4 py-2 rounded bg-[#0076a8] text-white shadow hover:bg-[#00628a] transition-colors" }, "Submit"))));
|
|
81
|
+
}
|
|
82
|
+
function toFhirAnswers(field) {
|
|
83
|
+
switch (field.fieldType) {
|
|
84
|
+
case "input":
|
|
85
|
+
return field.answer ? [{ valueString: String(field.answer) }] : [];
|
|
86
|
+
case "radio":
|
|
87
|
+
return field.selected ? [{ valueString: optionValue(field, field.selected) }] : [];
|
|
88
|
+
case "check":
|
|
89
|
+
return (field.selected || []).map((id) => ({ valueString: optionValue(field, id) }));
|
|
90
|
+
case "selection":
|
|
91
|
+
return field.selected ? [{ valueString: optionValue(field, field.selected) }] : [];
|
|
92
|
+
default:
|
|
93
|
+
return [];
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
function optionValue(field, optionId) {
|
|
97
|
+
const opt = (field.options || []).find((o) => o.id === optionId || o.value === optionId);
|
|
98
|
+
return opt ? opt.value : "";
|
|
99
|
+
}
|
|
100
|
+
function RendererBody() {
|
|
101
|
+
const ui = useUIApi();
|
|
102
|
+
const fields = useFieldsArray() || [];
|
|
103
|
+
const flat = React.useMemo(() => {
|
|
104
|
+
const out = [];
|
|
105
|
+
fields.forEach((f) => {
|
|
106
|
+
out.push(f);
|
|
107
|
+
if ((f == null ? void 0 : f.fieldType) === "section" && Array.isArray(f.fields)) out.push(...f.fields);
|
|
108
|
+
});
|
|
109
|
+
return out;
|
|
110
|
+
}, [fields]);
|
|
111
|
+
const visible = React.useMemo(() => {
|
|
112
|
+
if (!ui.state.isPreview) return fields;
|
|
113
|
+
return fields.filter((f) => isVisible(f, flat));
|
|
114
|
+
}, [fields, flat, ui.state.isPreview]);
|
|
115
|
+
return /* @__PURE__ */ React.createElement("div", null, visible.map((f) => /* @__PURE__ */ React.createElement(FieldNode, { key: f.id, field: f, allFlat: flat })));
|
|
116
|
+
}
|
|
117
|
+
function FieldNode({ field, allFlat }) {
|
|
118
|
+
const ui = useUIApi();
|
|
119
|
+
const Comp = getFieldComponent(field.fieldType);
|
|
120
|
+
if (!Comp) return null;
|
|
121
|
+
if (field.fieldType === "section" && ui.state.isPreview && Array.isArray(field.fields)) {
|
|
122
|
+
const visibleChildren = field.fields.filter((ch) => isVisible(ch, allFlat));
|
|
123
|
+
const filteredSection = { ...field, fields: visibleChildren };
|
|
124
|
+
return /* @__PURE__ */ React.createElement(Comp, { field: filteredSection });
|
|
125
|
+
}
|
|
126
|
+
return /* @__PURE__ */ React.createElement(Comp, { field });
|
|
127
|
+
}
|
|
128
|
+
export {
|
|
129
|
+
QuestionnaireRenderer
|
|
130
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@mieweb/forms-renderer",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Read-only questionnaire form renderer producing FHIR QuestionnaireResponse",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"module": "./dist/index.js",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"import": "./dist/index.js",
|
|
11
|
+
"types": "./dist/index.d.ts"
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
"files": ["dist", "README.md"],
|
|
15
|
+
"scripts": {
|
|
16
|
+
"build": "tsup index.js --format esm --external react --external react-dom --external @mieweb/forms-engine"
|
|
17
|
+
},
|
|
18
|
+
"sideEffects": false,
|
|
19
|
+
"peerDependencies": {
|
|
20
|
+
"react": ">=18.0.0",
|
|
21
|
+
"react-dom": ">=18.0.0"
|
|
22
|
+
},
|
|
23
|
+
"dependencies": {
|
|
24
|
+
"@mieweb/forms-engine": "0.1.0"
|
|
25
|
+
},
|
|
26
|
+
"publishConfig": { "access": "public" }
|
|
27
|
+
}
|