Files
suaveplan/packages/ui/forms/form-builder/README.md
2026-05-27 23:47:53 +01:00

129 lines
8.0 KiB
Markdown

# @suaveplan/form-builder - Universal dynamic form schema engine with conditional logic, async validation, dependency graph, undo/redo, Zod-schema generation, OTel instrumentation, and pluggable field-type registry.
Universal dynamic form schema engine. Renderer-agnostic — no DOM, no
React, no Node-specific globals. Drives every dynamic form surface in the
Suaveplan.
<!-- begin:auto-docs -->
## Documentation tree
- [form-builder](./src/builder/form-builder/form-builder.md) — `form-builder.ts` exposes the top-level `FormBuilder` class — the public entry point for `@suaveplan/form-builder`. The…
- [form-builder](./src/builder/form-builder/form-builder.md) — `form-builder.ts` exposes the top-level `FormBuilder` class — the public entry point for `@suaveplan/form-builder`. The…
- [conditional](./src/conditional/conditional/conditional.md) — `conditional.ts` is the rule-evaluation engine for `FieldDefinition.conditional`. It supports nine leaf operators (`eq`…
- [conditional](./src/conditional/conditional/conditional.md) — `conditional.ts` is the rule-evaluation engine for `FieldDefinition.conditional`. It supports nine leaf operators (`eq`…
- [dependency-graph](./src/conditional/dependency-graph/dependency-graph.md) — `dependency-graph.ts` builds a directed acyclic graph of field-id dependencies derived from `FieldDefinition.conditiona…
- [dependency-graph](./src/conditional/dependency-graph/dependency-graph.md) — `dependency-graph.ts` builds a directed acyclic graph of field-id dependencies derived from `FieldDefinition.conditiona…
- [form-error](./src/errors/form-error/form-error.md) — `form-error.ts` owns the stable error-code registry and the typed `FormError` class for the entire `@suaveplan/form-bui…
- [form-error](./src/errors/form-error/form-error.md) — `form-error.ts` owns the stable error-code registry and the typed `FormError` class for the entire `@suaveplan/form-bui…
- [field-registry](./src/fields/field-registry/field-registry.md) — `field-registry.ts` is the extensible registry of field-type descriptors used by `FormBuilder`. It ships seventeen buil…
- [field-registry](./src/fields/field-registry/field-registry.md) — `field-registry.ts` is the extensible registry of field-type descriptors used by `FormBuilder`. It ships seventeen buil…
- [instruments](./src/otel/instruments/instruments.md) — `instruments.ts` lazily resolves the OpenTelemetry meter and the five instruments emitted across the package: three cou…
- [instruments](./src/otel/instruments/instruments.md) — `instruments.ts` lazily resolves the OpenTelemetry meter and the five instruments emitted across the package: three cou…
- [schema](./src/schema/schema/schema.md) — `schema.ts` is the Zod boundary for the public `FormSchema`, `FieldDefinition`, and `FormSection` types. It exposes par…
- [schema](./src/schema/schema/schema.md) — `schema.ts` is the Zod boundary for the public `FormSchema`, `FieldDefinition`, and `FormSection` types. It exposes par…
- [serialise](./src/serialise/serialise/serialise.md) — `serialise.ts` provides versioned JSON round-trip for `FormSchema`. It is the bridge between the in-memory schema engin…
- [serialise](./src/serialise/serialise/serialise.md) — `serialise.ts` provides versioned JSON round-trip for `FormSchema`. It is the bridge between the in-memory schema engin…
- [form-state](./src/state/form-state/form-state.md) — `form-state.ts` is the mutable holder for the runtime state of a form instance: the current value map, the most recent…
- [form-state](./src/state/form-state/form-state.md) — `form-state.ts` is the mutable holder for the runtime state of a form instance: the current value map, the most recent…
- [undo-redo](./src/state/undo-redo/undo-redo.md) — `undo-redo.ts` is a bounded LIFO of reverse-ops with redo support. It is the substrate for `FormBuilder.enableHistory`…
- [undo-redo](./src/state/undo-redo/undo-redo.md) — `undo-redo.ts` is a bounded LIFO of reverse-ops with redo support. It is the substrate for `FormBuilder.enableHistory`…
- [submission](./src/submission/submission/submission.md) — `submission.ts` is the orchestration layer that runs the canonical `prepare → validate → transform → submit` pipeline f…
- [submission](./src/submission/submission/submission.md) — `submission.ts` is the orchestration layer that runs the canonical `prepare → validate → transform → submit` pipeline f…
- [validation](./src/validation/validation/validation.md) — `validation.ts` is the iteration layer that runs every rule attached to a field or form and aggregates the resulting `V…
- [validation](./src/validation/validation/validation.md) — `validation.ts` is the iteration layer that runs every rule attached to a field or form and aggregates the resulting `V…
- [validators](./src/validation/validators/validators.md) — `validators.ts` provides the eleven built-in rule runners used by the validation engine. Each runner takes the candidat…
- [validators](./src/validation/validators/validators.md) — `validators.ts` provides the eleven built-in rule runners used by the validation engine. Each runner takes the candidat…
- [zod-schema](./src/zod-schema/zod-schema/zod-schema.md) — `zod-schema.ts` exposes `toZodSchema(form)` — a function that compiles a `FormSchema` into a `z.ZodObject` whose `safeP…
- [zod-schema](./src/zod-schema/zod-schema/zod-schema.md) — `zod-schema.ts` exposes `toZodSchema(form)` — a function that compiles a `FormSchema` into a `z.ZodObject` whose `safeP…
<!-- end:auto-docs -->
## Features
- 17 built-in field types (`text`, `number`, `email`, `url`, `tel`,
`password`, `select`, `multiselect`, `checkbox`, `radio`, `textarea`,
`date`, `file`, `range`, `hidden`, `group`, `array`) via an extensible
`FieldRegistry`.
- 11 built-in validation rules (`required`, `minLength`, `maxLength`, `min`,
`max`, `pattern`, `email`, `url`, `oneOf`, `equalsField`, `custom`).
Async-friendly via `Promise<boolean>` predicates.
- Conditional logic with 9 leaf operators (`eq`, `neq`, `in`, `notIn`,
`gt`, `lt`, `gte`, `lte`, `contains`) and boolean composition
(`and` / `or` / `not`).
- Field-level dependency graph with topological evaluation and cycle
detection (`FORM_BUILDER.CYCLIC_DEPENDENCY`).
- Bounded undo / redo on schema mutations.
- Typed event bus via `EventBus<FormEventMap>` from `@suaveplan/events`.
- Versioned JSON serialise / deserialise round-trip.
- `toZodSchema(form)` generator for `react-hook-form` consumers.
- Submission pipeline: `prepare → validate → transform → submit`.
- Six stable `FORM_BUILDER.*` error codes via `defineCodes`.
- Three OTel counters and two histograms emitted on every code path.
- Injectable `Clock` + `IdGenerator` for deterministic tests.
## Install
```bash
bun add @suaveplan/form-builder
```
## Usage
```ts
import { FormBuilder } from "@suaveplan/form-builder";
const builder = new FormBuilder().enableHistory();
builder.addField({
id: "name",
name: "name",
label: "Name",
type: "text",
validations: [{ type: "required" }],
});
builder.addField({
id: "subscribe",
name: "subscribe",
label: "Subscribe to newsletter",
type: "checkbox",
});
builder.addField({
id: "frequency",
name: "frequency",
label: "Frequency",
type: "select",
options: [
{ label: "Weekly", value: "weekly" },
{ label: "Monthly", value: "monthly" },
],
conditional: { field: "subscribe", operator: "eq", value: true },
});
builder.bus.on("values.changed", (values) =>
console.log("changed", values)
);
const schema = builder.createSchema("signup", "Sign-up form");
```
## Submission
```ts
import { submit } from "@suaveplan/form-builder";
await submit({
fields: schema.fields,
values: { name: "alice", subscribe: true, frequency: "weekly" },
submitter: async (values, signal) =>
fetch("/api/forms", {
method: "POST",
signal,
body: JSON.stringify(values),
}),
});
```
## License
MIT.