react-data-form
The form registry
addForm, getForm, and why the registry has to be a singleton.
Most forms are written where they are used and never need a name. Some have to be found by something that does not know them at compile time — a page builder offering block types, or a resource view looking up the form for the type it just fetched. That is what the registry is for.
What it is for#
- The page builder.
FormArrayInputControllerbuilds its palette by asking the registry for every form tagged with a given@for. - Resource views. react-resource-view stores resources in the very same registry, which is how a record's type resolves to the form that edits it.
- Forms that arrive at runtime. A description fetched from an API can be registered on arrival and used like any other.
addForm and getForm#
import { addForm, getForm } from "react-data-form"
addForm("block.hero", {
name: "Hero",
"@for": ["page-block"],
inputs: {
title: { label: "Title", required: true },
subtitle: { label: "Subtitle" },
},
})
// Later, anywhere in the application:
const hero = getForm({ type: "page-block" })| Name | Type | Default | Description |
|---|---|---|---|
addForm(name, form) | (string, FormInterface & { "@for"?: string[] }) => FormInterface | — | Stores the form under name, stamping @id and @type: \"form\" on it. |
getForm({ type }) | ({ type: string }) => FormResourceItem | undefined | — | Finds a form whose @for contains type. |
getForms(fors?) | (string[]?) => FormResourceItem[] | — | Every registered form, or those matching one of the given tags. |
getFormType(form) | (FormResourceItem) => string | — | The tag to store on an item so getForm can find this form again — the first @for, falling back to the @id. |
getFormLabel(form) | (FormResourceItem) => string | — | A human-readable name for palettes and block headers. |
upsertForm / updateForm | utilities | — | Merge a description into an existing one, for a form assembled from several sources. |
@for is a tag, not a type
Several forms can share a tag: that is what makes a palette a list rather than a single entry. getForm returns one of them; getForms returns all of them.
Listing what is registered#
import { getForms, getFormLabel, getFormType } from "react-data-form"
// Every registered form
getForms()
// Only those tagged for the page builder
getForms(["page-block"]).map((form) => ({
type: getFormType(form), // the @for tag, or the @id
label: getFormLabel(form), // name, or label.title, or the type
}))One registry, or none at all#
addForm and createResource write into the same store, which lives in resource-registry as a module-level singleton.
// ✅ Both halves write into the same registry.
import { addForm } from "react-data-form"
import { createResource } from "resource-registry"
// ❌ Keeping a copy of createResource in your own code gives you a second
// registry, and searchMetaData stops connecting a resource to its form.Two copies is the failure mode to know
If resource-registry resolves twice in node_modules, you get two stores. Forms registered on one side become invisible from the other, and nothing errors — the palette is simply empty, and the lookup simply returns undefined.
That is why it is a peer dependency, and why you should import createResource from it rather than re-exporting a copy.