@proveanything/smartlinks-form-renderer
Version:
SmartLinks form renderer and editor — render forms from JSON schema or build them with the visual editor
357 lines (281 loc) • 8.95 kB
Markdown
# SmartLinks Forms
A flexible React package for rendering and editing forms from JSON schema — with conditional logic, validation, table fields, storage configuration, and a visual editor.
## Installation
```bash
npm install @proveanything/smartlinks-forms
```
## Subpath Imports
```tsx
// Full package (renderer + editor + types)
import { SchemaFormRenderer, useFormEditorState } from '@proveanything/smartlinks-forms';
// Renderer only (lean, public-facing)
import { SchemaFormRenderer } from '@proveanything/smartlinks-forms/renderer';
// Editor only (admin-facing)
import { useFormEditorState, useFormEditorActions } from '@proveanything/smartlinks-forms/editor';
```
## Form Renderer
### Basic Usage
```tsx
import { SchemaFormRenderer, SchemaFormConfig } from '@proveanything/smartlinks-forms';
const formConfig: SchemaFormConfig = {
title: "Contact Form",
description: "Fill in your details",
schema: {
type: "object",
properties: {
name: { type: "string", title: "Full Name" },
email: { type: "string", format: "email", title: "Email" },
},
required: ["name", "email"]
},
uiSchema: {
name: { "ui:placeholder": "Enter your full name" },
email: { "ui:placeholder": "you@example.com" },
},
storage: { name: "public", email: "private" },
settings: {
allowMultipleSubmissions: false,
requireAuthentication: false,
showProgressBar: false,
submitButtonText: "Submit",
successMessage: "Form submitted successfully!"
},
styling: { theme: "default", primaryColor: "#007bff", backgroundColor: "#ffffff" },
fieldOrder: ["name", "email"]
};
function MyForm() {
return (
<SchemaFormRenderer
config={formConfig}
onSubmit={(data) => console.log('Submitted:', data)}
initialData={{ name: "John Doe" }}
/>
);
}
```
### Props
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| `config` | `SchemaFormConfig` | Required | The form configuration object |
| `onSubmit` | `(data: Record<string, any>) => void` | Required | Called on valid submission |
| `isSubmitting` | `boolean` | `false` | Disables submit button |
| `className` | `string` | `""` | Additional CSS classes |
| `initialData` | `Record<string, any>` | `{}` | Pre-populate fields (overrides schema defaults) |
| `components` | `object` | `{}` | Custom component overrides |
## Field Types & Formats
### String Fields
- `text` (default), `email`, `textarea`, `select`, `radio`, `checkboxes`, `multiselect`, `combobox`, `file`, `date`, `date-time`
### Boolean Fields
- `checkbox` (default), `switch`
### Number / Integer Fields
- Standard number input with `minimum`/`maximum` validation
### Table Fields
- Dynamic table with typed columns, row add/remove, `minRows`/`maxRows`
## Validation
The renderer enforces validation **at submit time** with inline error messages. Both HTML attributes and JavaScript-level checks are used.
### Supported Constraints
| Constraint | Applies To | Description |
|------------|-----------|-------------|
| `required` | All types | Field must have a value (set via `schema.required[]`) |
| `minLength` | `string` | Minimum character length |
| `maxLength` | `string` | Maximum character length |
| `pattern` | `string` | Regex pattern the value must match |
| `minimum` | `number`, `integer` | Minimum numeric value |
| `maximum` | `number`, `integer` | Maximum numeric value |
| `minRows` | `table` | Minimum number of table rows |
| `maxRows` | `table` | Maximum number of table rows |
### Example
```tsx
{
age: {
type: "integer",
title: "Age",
minimum: 18,
maximum: 120
},
bio: {
type: "string",
format: "textarea",
title: "Bio",
minLength: 10,
maxLength: 500
}
}
```
## Enum Labels (`enumNames`)
Use `enumNames` as a parallel array to `enum` for human-readable labels:
```tsx
{
country: {
type: "string",
format: "select",
title: "Country",
enum: ["us", "gb", "de"],
enumNames: ["United States", "United Kingdom", "Germany"]
}
}
```
`enum[i]` is the stored value, `enumNames[i]` is the display label. Works with `select`, `radio`, `checkboxes`, `multiselect`, and `combobox` formats.
## UI Schema
Control presentation without changing the data schema:
```tsx
uiSchema: {
bio: {
"ui:placeholder": "Tell us about yourself...",
"ui:help": "This will be shown on your profile",
"ui:options": { rows: 6 },
"ui:disabled": true // Read-only field
},
avatar: {
"ui:options": { accept: "image/*" }
}
}
```
### Available UI Properties
| Property | Type | Description |
|----------|------|-------------|
| `ui:placeholder` | `string` | Placeholder text |
| `ui:help` | `string` | Help text below the field |
| `ui:disabled` | `boolean` | Disables the field (read-only) |
| `ui:widget` | `string` | Override auto-detected widget |
| `ui:options.rows` | `number` | Textarea row count |
| `ui:options.accept` | `string` | File input accept filter |
| `ui:options.label` | `boolean` | Show/hide label |
## Conditional Logic
Show/hide fields based on other field values:
```tsx
{
preferences: {
type: "string",
format: "select",
title: "Preferences",
enum: ["daily", "weekly"],
conditions: [
{ targetFieldId: "subscribe", operator: "equals", value: true }
],
showWhen: "all" // or "any"
}
}
```
### Operators
| Operator | Description | Needs `value`? |
|----------|-------------|---------------|
| `equals` | Strict equality | Yes |
| `not_equals` | Not equal | Yes |
| `contains` | String contains | Yes |
| `not_contains` | String doesn't contain | Yes |
| `greater_than` | Numeric comparison | Yes |
| `less_than` | Numeric comparison | Yes |
| `is_empty` | Value is empty/null | No |
| `is_not_empty` | Value has content | No |
| `is_true` | Value is `true` | No |
| `is_false` | Value is `false`/`null`/`undefined` | No |
## Field Ordering
```tsx
const config: SchemaFormConfig = {
fieldOrder: ["name", "email", "phone", "address"],
// ...
};
```
If `fieldOrder` is not specified, fields appear in `schema.properties` insertion order.
## Table Fields
```tsx
{
items: {
type: "table",
title: "Line Items",
columns: [
{ id: "name", title: "Item", type: "string", required: true },
{ id: "qty", title: "Quantity", type: "number", required: true },
{ id: "active", title: "Active", type: "boolean" },
{ id: "date", title: "Added", type: "date" }
],
minRows: 1,
maxRows: 10
}
}
```
## Custom Components
Override default UI primitives:
```tsx
<SchemaFormRenderer
config={formConfig}
onSubmit={handleSubmit}
components={{
Button: MyButton,
Input: MyInput,
Textarea: MyTextarea,
Select: MySelect,
Checkbox: MyCheckbox,
RadioGroup: MyRadioGroup,
Switch: MySwitch,
Label: MyLabel,
TableInput: MyTableInput,
}}
/>
```
## Storage Configuration
Define privacy levels per field:
```tsx
storage: {
name: "public", // Publicly visible
email: "private", // Private to user
ssn: "proof", // Cryptographic proof only
notes: "personal" // Personal notes
}
```
## Form Editor (Admin)
The editor hooks provide headless state management for building a form editor UI:
```tsx
import { useFormEditorState, useFormEditorActions } from '@proveanything/smartlinks-forms/editor';
function FormEditor() {
const editor = useFormEditorState({ isCreating: true });
const actions = useFormEditorActions({
formConfig: editor.formConfig,
setFormConfig: editor.setFormConfig,
});
// editor.addField(), editor.updateField(), editor.removeField(), etc.
// actions.exportSchema(), actions.importSchema()
}
```
## Configuration Reference
### SchemaFormConfig
| Property | Type | Description |
|----------|------|-------------|
| `id` | `string?` | Unique identifier |
| `title` | `string` | Form title |
| `description` | `string` | Form description |
| `schema` | `object` | JSON Schema definition |
| `uiSchema` | `object` | UI configuration |
| `storage` | `object` | Per-field storage levels |
| `settings` | `object` | Form behavior settings |
| `styling` | `object` | Theme and colours |
| `fieldOrder` | `string[]?` | Field display order |
## TypeScript
```tsx
import type {
SchemaFormConfig,
SchemaFormField,
SchemaFormRendererProps,
SchemaFormUIConfig,
SchemaFormFieldCondition,
TableColumn,
FormEditorState,
FormEditorActions,
} from '@proveanything/smartlinks-forms';
```
## License
MIT