@bluprynt/forms-viewer 1.0.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 +279 -0
- package/dist/index.cjs +488 -0
- package/dist/index.d.cts +194 -0
- package/dist/index.d.cts.map +1 -0
- package/dist/index.d.mts +194 -0
- package/dist/index.d.mts.map +1 -0
- package/dist/index.mjs +470 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +53 -0
package/README.md
ADDED
|
@@ -0,0 +1,279 @@
|
|
|
1
|
+
# @bluprynt/forms-viewer
|
|
2
|
+
|
|
3
|
+
Headless React components for rendering and editing JSON-driven dynamic forms. Pairs with `@bluprynt/forms-core` to handle visibility, validation, and section navigation — you supply the UI components, the viewer wires everything together.
|
|
4
|
+
|
|
5
|
+
## Key Capabilities
|
|
6
|
+
|
|
7
|
+
- **Read-only rendering** — `FormViewer` renders a form from a definition and document using your custom view components, with automatic visibility and validation display.
|
|
8
|
+
- **Editable forms** — `FormEditor` renders an editable form with per-field `onChange` handlers, array item manipulation (add, remove, move), and live re-validation on every change.
|
|
9
|
+
- **Section navigation** — `FormSections` enumerates visible top-level sections (including a synthetic root for ungrouped fields) and tracks the active section.
|
|
10
|
+
- **Validation display** — `FormFieldsValidation` groups field-level errors by field; `FormDocumentValidation` renders document-level errors (schema mismatch, missing `submittedAt`, etc.).
|
|
11
|
+
- **Headless architecture** — all rendering is delegated to component maps you provide (`ViewerComponentMap`, `EditorComponentMap`), so the package has zero UI opinions.
|
|
12
|
+
|
|
13
|
+
## Installation
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
npm install @bluprynt/forms-viewer @bluprynt/forms-core ajv react react-dom
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
`@bluprynt/forms-core`, `react`, and `react-dom` are peer dependencies and must be installed in your project.
|
|
20
|
+
|
|
21
|
+
## Quick Start
|
|
22
|
+
|
|
23
|
+
### Setting Up the Form Provider
|
|
24
|
+
|
|
25
|
+
The `Form` component compiles the definition, computes visibility, runs validation, and exposes everything via context.
|
|
26
|
+
|
|
27
|
+
```tsx
|
|
28
|
+
import type { FC } from 'react'
|
|
29
|
+
import { Form } from '@bluprynt/forms-viewer'
|
|
30
|
+
import type { FormDefinition, FormDocument } from '@bluprynt/forms-viewer'
|
|
31
|
+
|
|
32
|
+
const definition: FormDefinition = { /* ... */ }
|
|
33
|
+
const document: FormDocument = { /* ... */ }
|
|
34
|
+
|
|
35
|
+
const App: FC = () => {
|
|
36
|
+
return (
|
|
37
|
+
<Form definition={definition} data={document}>
|
|
38
|
+
{/* FormViewer, FormEditor, FormSections, etc. */}
|
|
39
|
+
</Form>
|
|
40
|
+
)
|
|
41
|
+
}
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
`Form` props:
|
|
45
|
+
|
|
46
|
+
| Prop | Type | Default | Description |
|
|
47
|
+
|------|------|---------|-------------|
|
|
48
|
+
| `definition` | `FormDefinition` | — | The form schema |
|
|
49
|
+
| `data` | `FormDocument` | — | The form values document |
|
|
50
|
+
| `section` | `ROOT \| number` | — | Active section id (use `ROOT` for ungrouped fields) |
|
|
51
|
+
| `showInlineValidation` | `boolean` | `true` | Whether field components receive validation errors |
|
|
52
|
+
| `children` | `ReactNode` | — | Child components |
|
|
53
|
+
|
|
54
|
+
### Using FormViewer (Read-Only)
|
|
55
|
+
|
|
56
|
+
Use `FormViewer` when you only need to display submitted form values without editing. It renders each field through your component map in a read-only mode, applying visibility rules and showing validation state.
|
|
57
|
+
|
|
58
|
+
```tsx
|
|
59
|
+
import type { FC } from 'react'
|
|
60
|
+
import { Form, FormViewer } from '@bluprynt/forms-viewer'
|
|
61
|
+
import type { ViewerComponentMap } from '@bluprynt/forms-viewer'
|
|
62
|
+
|
|
63
|
+
const components: ViewerComponentMap = {
|
|
64
|
+
string: ({ field, value }) => <p>{field.label}: {value}</p>,
|
|
65
|
+
number: ({ field, value }) => <p>{field.label}: {value}</p>,
|
|
66
|
+
boolean: ({ field, value }) => <p>{field.label}: {value ? 'Yes' : 'No'}</p>,
|
|
67
|
+
date: ({ field, value }) => <p>{field.label}: {value}</p>,
|
|
68
|
+
select: ({ field, value, options }) => (
|
|
69
|
+
<p>{field.label}: {options.find(o => o.value === value)?.label}</p>
|
|
70
|
+
),
|
|
71
|
+
array: ({ field, children }) => <div>{field.label}: {children}</div>,
|
|
72
|
+
file: ({ field, value }) => <p>{field.label}: {value?.name}</p>,
|
|
73
|
+
section: ({ section, children }) => (
|
|
74
|
+
<fieldset>
|
|
75
|
+
<legend>{section.title}</legend>
|
|
76
|
+
{children}
|
|
77
|
+
</fieldset>
|
|
78
|
+
),
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
const ReadOnlyForm: FC = () => {
|
|
82
|
+
return (
|
|
83
|
+
<Form definition={definition} data={document}>
|
|
84
|
+
<FormViewer components={components} />
|
|
85
|
+
</Form>
|
|
86
|
+
)
|
|
87
|
+
}
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
### Using FormEditor (Editable)
|
|
91
|
+
|
|
92
|
+
Use `FormEditor` when users need to fill in or edit a form. It provides per-field `onChange` handlers and fires a callback on every change with the updated `FormDocument` JSON and current validation result.
|
|
93
|
+
|
|
94
|
+
```tsx
|
|
95
|
+
import { useState, type FC } from 'react'
|
|
96
|
+
import { Form, FormEditor } from '@bluprynt/forms-viewer'
|
|
97
|
+
import type { EditorComponentMap, FormDocument, FormValidationResult } from '@bluprynt/forms-viewer'
|
|
98
|
+
|
|
99
|
+
const components: EditorComponentMap = {
|
|
100
|
+
string: ({ field, value, onChange }) => (
|
|
101
|
+
<input value={value ?? ''} onChange={e => onChange(e.target.value)} />
|
|
102
|
+
),
|
|
103
|
+
number: ({ field, value, onChange }) => (
|
|
104
|
+
<input type="number" value={value ?? ''} onChange={e => onChange(Number(e.target.value))} />
|
|
105
|
+
),
|
|
106
|
+
boolean: ({ field, value, onChange }) => (
|
|
107
|
+
<input type="checkbox" checked={value ?? false} onChange={e => onChange(e.target.checked)} />
|
|
108
|
+
),
|
|
109
|
+
date: ({ field, value, onChange }) => (
|
|
110
|
+
<input type="date" value={value ?? ''} onChange={e => onChange(e.target.value)} />
|
|
111
|
+
),
|
|
112
|
+
select: ({ field, value, options, onChange }) => (
|
|
113
|
+
<select value={value ?? ''} onChange={e => onChange(e.target.value)}>
|
|
114
|
+
{options.map(o => <option key={o.value} value={o.value}>{o.label}</option>)}
|
|
115
|
+
</select>
|
|
116
|
+
),
|
|
117
|
+
array: ({ field, children, onAddItem }) => (
|
|
118
|
+
<div>
|
|
119
|
+
{children}
|
|
120
|
+
<button onClick={onAddItem}>Add item</button>
|
|
121
|
+
</div>
|
|
122
|
+
),
|
|
123
|
+
file: ({ field, value, onChange }) => (
|
|
124
|
+
<input type="file" onChange={e => { /* handle file */ }} />
|
|
125
|
+
),
|
|
126
|
+
section: ({ section, children }) => (
|
|
127
|
+
<fieldset>
|
|
128
|
+
<legend>{section.title}</legend>
|
|
129
|
+
{children}
|
|
130
|
+
</fieldset>
|
|
131
|
+
),
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
const EditableForm: FC = () => {
|
|
135
|
+
const [data, setData] = useState<FormDocument>(initialDocument)
|
|
136
|
+
|
|
137
|
+
const handleChange = (doc: FormDocument, validation: FormValidationResult) => {
|
|
138
|
+
setData(doc)
|
|
139
|
+
// validation.valid, validation.fieldErrors, etc.
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
return (
|
|
143
|
+
<Form definition={definition} data={data}>
|
|
144
|
+
<FormEditor components={components} onChange={handleChange} />
|
|
145
|
+
</Form>
|
|
146
|
+
)
|
|
147
|
+
}
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
### Using FormSections for Navigation
|
|
151
|
+
|
|
152
|
+
Use `FormSections` to render form sections as tabs, a sidebar menu, or any other navigation UI and let users switch between them. It enumerates visible top-level sections and tracks the active one.
|
|
153
|
+
|
|
154
|
+
```tsx
|
|
155
|
+
import { useState, type FC } from 'react'
|
|
156
|
+
import { Form, FormViewer, FormSections, ROOT } from '@bluprynt/forms-viewer'
|
|
157
|
+
|
|
158
|
+
const FormWithSections: FC = () => {
|
|
159
|
+
const [activeSection, setActiveSection] = useState<typeof ROOT | number>(ROOT)
|
|
160
|
+
|
|
161
|
+
return (
|
|
162
|
+
<Form definition={definition} data={document} section={activeSection}>
|
|
163
|
+
<FormSections
|
|
164
|
+
container={({ children }) => <nav>{children}</nav>}
|
|
165
|
+
item={({ section, active, select }) => (
|
|
166
|
+
<button onClick={select} style={{ fontWeight: active ? 'bold' : 'normal' }}>
|
|
167
|
+
{section.title}
|
|
168
|
+
</button>
|
|
169
|
+
)}
|
|
170
|
+
defaultSectionTitle="General"
|
|
171
|
+
onSelect={setActiveSection}
|
|
172
|
+
/>
|
|
173
|
+
<FormViewer components={viewerComponents} />
|
|
174
|
+
</Form>
|
|
175
|
+
)
|
|
176
|
+
}
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
### Using FormFieldsValidation and FormDocumentValidation
|
|
180
|
+
|
|
181
|
+
Use `FormDocumentValidation` to display document-level errors — schema mismatch, invalid version, missing `submittedAt`, and similar structural issues. Use `FormFieldsValidation` to display field-level errors — values that don't match validation rules defined in the form (required, min/max, pattern, etc.).
|
|
182
|
+
|
|
183
|
+
```tsx
|
|
184
|
+
import type { FC } from 'react'
|
|
185
|
+
import { Form, FormFieldsValidation, FormDocumentValidation } from '@bluprynt/forms-viewer'
|
|
186
|
+
|
|
187
|
+
const ValidationSummary: FC = () => {
|
|
188
|
+
return (
|
|
189
|
+
<Form definition={definition} data={document}>
|
|
190
|
+
<FormDocumentValidation
|
|
191
|
+
container={({ children }) => <div className="doc-errors">{children}</div>}
|
|
192
|
+
error={({ code, message }) => <p>{message} ({code})</p>}
|
|
193
|
+
/>
|
|
194
|
+
<FormFieldsValidation
|
|
195
|
+
container={({ children }) => <div className="field-errors">{children}</div>}
|
|
196
|
+
field={({ field, errors, children }) => (
|
|
197
|
+
<div>
|
|
198
|
+
<strong>{field?.label}</strong>
|
|
199
|
+
{children}
|
|
200
|
+
</div>
|
|
201
|
+
)}
|
|
202
|
+
error={({ message, rule }) => <p>{message} [{rule}]</p>}
|
|
203
|
+
/>
|
|
204
|
+
</Form>
|
|
205
|
+
)
|
|
206
|
+
}
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
## Component Map Types
|
|
210
|
+
|
|
211
|
+
### ViewerComponentMap
|
|
212
|
+
|
|
213
|
+
Component map for read-only rendering. Each key maps a field type to a React component.
|
|
214
|
+
|
|
215
|
+
| Key | Props Type | Description |
|
|
216
|
+
|-----|-----------|-------------|
|
|
217
|
+
| `string` | `StringViewProps` | Text field display |
|
|
218
|
+
| `number` | `NumberViewProps` | Numeric field display |
|
|
219
|
+
| `boolean` | `BooleanViewProps` | Boolean field display |
|
|
220
|
+
| `date` | `DateViewProps` | Date field display |
|
|
221
|
+
| `select` | `SelectViewProps` | Select field display (receives `options`) |
|
|
222
|
+
| `array` | `ArrayViewProps` | Array field display (receives `children` for items, `itemDef`) |
|
|
223
|
+
| `file` | `FileViewProps` | File field display |
|
|
224
|
+
| `section` | `SectionViewProps` | Section wrapper (receives `children`) |
|
|
225
|
+
| `error?` | `ErrorProps` | Optional inline error renderer |
|
|
226
|
+
|
|
227
|
+
All view field props extend `BaseViewFieldProps` which provides `field: FieldContentItem` and `errors: FieldValidationError[]`.
|
|
228
|
+
|
|
229
|
+
### EditorComponentMap
|
|
230
|
+
|
|
231
|
+
Component map for editable rendering. Extends view props with mutation callbacks.
|
|
232
|
+
|
|
233
|
+
| Key | Props Type | Description |
|
|
234
|
+
|-----|-----------|-------------|
|
|
235
|
+
| `string` | `StringEditProps` | Text input with `onChange(value)` |
|
|
236
|
+
| `number` | `NumberEditProps` | Numeric input with `onChange(value)` |
|
|
237
|
+
| `boolean` | `BooleanEditProps` | Boolean input with `onChange(value)` |
|
|
238
|
+
| `date` | `DateEditProps` | Date input with `onChange(value)` |
|
|
239
|
+
| `select` | `SelectEditProps` | Select input with `onChange(value)` and `options` |
|
|
240
|
+
| `array` | `ArrayEditProps` | Array editor with `onAddItem`, `onRemoveItem(index)`, `onMoveItem(from, to)` |
|
|
241
|
+
| `file` | `FileEditProps` | File input with `onChange(value)` |
|
|
242
|
+
| `section` | `SectionEditProps` | Section wrapper (receives `children`) |
|
|
243
|
+
| `error?` | `ErrorProps` | Optional inline error renderer |
|
|
244
|
+
|
|
245
|
+
All edit field props extend `BaseEditFieldProps` which adds `onChange(value)` to the base view props.
|
|
246
|
+
|
|
247
|
+
## Exported API
|
|
248
|
+
|
|
249
|
+
| Export | Kind | Description |
|
|
250
|
+
|--------|------|-------------|
|
|
251
|
+
| `Form` | Component | Context provider — compiles definition, computes visibility and validation |
|
|
252
|
+
| `useFormContext` | Hook | Access form context (definition, data, engine, visibility, validation) |
|
|
253
|
+
| `FormViewer` | Component | Read-only form renderer |
|
|
254
|
+
| `FormEditor` | Component | Editable form renderer with change callbacks |
|
|
255
|
+
| `FormSections` | Component | Section navigation list |
|
|
256
|
+
| `FormFieldsValidation` | Component | Field-level validation error display |
|
|
257
|
+
| `FormDocumentValidation` | Component | Document-level validation error display |
|
|
258
|
+
| `ROOT` | Symbol | Identifies the root (ungrouped fields) section |
|
|
259
|
+
| `ViewerComponentMap` | Type | Component map for `FormViewer` |
|
|
260
|
+
| `EditorComponentMap` | Type | Component map for `FormEditor` |
|
|
261
|
+
| `BaseViewFieldProps` | Type | Base props for view field components |
|
|
262
|
+
| `BaseEditFieldProps` | Type | Base props for edit field components |
|
|
263
|
+
| `ErrorProps` | Type | Props for inline error components |
|
|
264
|
+
| `FormSectionEntry` | Type | Section entry in `FormSections` |
|
|
265
|
+
| `FormSectionItemProps` | Type | Props for section item renderer |
|
|
266
|
+
| `FieldValidationFieldEntry` | Type | Field + errors group in `FormFieldsValidation` |
|
|
267
|
+
| `FormValuesEditor` | Class | Fluent editor for reading and writing form values against a definition |
|
|
268
|
+
| `DocumentError` | Class | Error representing a document-level validation failure |
|
|
269
|
+
| `FormDefinition` | Type | JSON schema describing form structure, fields, sections, and rules |
|
|
270
|
+
| `FormDocument` | Type | JSON document containing user-submitted form values |
|
|
271
|
+
| `FormValidationResult` | Type | Validation outcome with document-level and field-level errors |
|
|
272
|
+
| `FieldType` | Type | Union of supported field types (`string`, `number`, `boolean`, `date`, `select`, `array`, `file`) |
|
|
273
|
+
| `FileValue` | Type | File field value containing name, MIME type, size, and URL |
|
|
274
|
+
|
|
275
|
+
## Documentation
|
|
276
|
+
|
|
277
|
+
- [API Reference](docs/api-reference.md) — detailed description of all exported components, hooks, and types
|
|
278
|
+
- [Architecture](docs/architecture.md) — internal design, data flow, and component structure
|
|
279
|
+
- [Development Guide](docs/development-guide.md) — setup, testing, and contribution guidelines
|