129 lines
8.0 KiB
Markdown
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.
|
|
|