@clayer/forms
v1.1.1
Published
Schema-driven form primitives for `@clayer` applications.
Readme
@clayer/forms
Schema-driven form primitives for @clayer applications.
This package provides a config-driven form engine that fits the existing @clayer/theme token system and current monorepo package conventions.
Exports
DynamicFormFormClient- form types from
src/types.ts formStateAPI
Install
pnpm add @clayer/forms @clayer/theme @clayer/uiThe consumer app must also:
- import
@clayer/theme/styles.css - wrap the app with
ThemeProvider - include
@clayer/theme/tailwind-preset
Core usage
import "@clayer/theme/styles.css";
import { ThemeProvider } from "@clayer/theme";
import { DynamicForm, type FormConfig } from "@clayer/forms";
const form: FormConfig = {
formName: "profile",
fields: [
{ name: "full_name", label: "Full name", type: "text", required: true },
{ name: "bio", label: "Bio", type: "textarea" },
{
name: "role",
label: "Role",
type: "dropdown",
options: [
{ value: "admin", label: "Admin" },
{ value: "editor", label: "Editor" },
],
},
],
};
export function App() {
return (
<ThemeProvider>
<DynamicForm
form={form}
onSubmit={(data) => {
console.log(data);
}}
/>
</ThemeProvider>
);
}FormClient
Use FormClient when the form script should be lazy-loaded:
<FormClient
form={form}
dataObject={prefill}
loadScript={() => import("./profile-form-script")}
onSubmit={handleSubmit}
/>loadScript may resolve either:
- a default export
- or a plain module object containing script handlers
Supported field types
Current package field coverage:
textnumbertextareadropdownradiodatetogglecheckbox-listlisttablesearchfiledynamic-valuesinforich-text
Config model
FormConfig
type FormConfig = {
formName: string;
type?: string;
modelFormat?: string;
fields: Field[];
additional_fields?: string[];
events?: Record<string, string>;
};Field
Important properties:
namelabeltypeplaceholderdescriptionrequireddisabledhiddenvalidationmultiSelectmultipleoptionsoptionDescriptionscolumnsmessageformatsmaxSizeselectableuploadConfiginfoItemsinfoVariantinfoColumnsminRowsmaxRowsaddLabelevents
Script and event model
Both forms and individual fields can dispatch named handlers into a provided script object.
Form-level events
events: {
onLoad: "onFormLoad",
onSubmit: "beforeSubmit",
}Field-level events
{
name: "category",
label: "Category",
type: "dropdown",
events: {
onChange: "onCategoryChange",
},
}Each script handler receives ScriptArgs, including:
formFieldsformDatadataObjectupdateFieldValuefieldEventsformStategetValues
This keeps parity with the reference dynamic-form workflow while avoiding app-specific service coupling.
Upload adapter
File fields do not hardcode backend upload logic. Consumers supply an adapter.
type UploadAdapter = {
uploadFiles: (
files: File[],
context: {
field: Field;
values: FormDataModel;
}
) => Promise<UploadedFile[]>;
deleteFile?: (
file: UploadedFile,
context: {
field: Field;
values: FormDataModel;
}
) => Promise<void>;
};Pass it to either DynamicForm or FormClient:
<DynamicForm form={form} uploadAdapter={uploadAdapter} onSubmit={handleSubmit} />Theming
@clayer/forms reads from theme.advanced.DynamicForm.
Current style keys used by the package include:
rootsectionfieldfieldLabelfieldErroractionsinputselectselectControlselectValueContainerselectPlaceholderselectInputselectSingleValueselectMultiValueselectMultiValueLabelselectMultiValueRemoveselectIndicatorsselectClearIndicatorselectDropdownIndicatorselectMenuselectMenuListselectOptionselectEmptyselectLoading
Current status
The package is functional and used in the playground. The main remaining work is parity depth and polish:
- richer editor behavior
- production upload adapter examples
- more formalized consumer docs for backend-integrated uploads
See the playground forms page for the current package demo and the ref/formModule/DataPage.tsx sample for the original migration target.
