@trungkhai/dynamic-form
v0.1.4
Published
Reusable schema-driven form library built on Ant Design.
Downloads
592
Readme
@trungkhai/dynamic-form
Reusable schema-driven form library built on Ant Design.
Install
pnpm add @trungkhai/dynamic-formPeer dependencies: react, react-dom, antd, @ant-design/icons, dayjs.
Supported ranges: React 18–19, Ant Design 5–6.
Quick start (v0.1 API)
import { ConfigProvider, Form } from "antd";
import {
DynamicFormProvider,
DynamicForm,
createAxiosDynamicFormClient,
} from "@trungkhai/dynamic-form";
import authInstance from "./authInstance";
const client = createAxiosDynamicFormClient(authInstance);
<ConfigProvider>
<DynamicFormProvider
client={client}
upload={{
uploadUrl: "/resources/upload",
remove: async ({ path }) => {
await authInstance.delete(path);
return true;
},
}}
i18n={{
messages: {
submit: "Lưu",
submitError: "Gửi form thất bại",
inputPlaceholder: (l) => `Nhập ${l}`,
selectPlaceholder: (l) => `Chọn ${l}`,
},
}}
cache={{ ttlMs: 60_000 }}
>
<DynamicForm formConfig={config} formInstance={form} />
</DynamicFormProvider>
</ConfigProvider>Provider groups
| Group | Purpose |
|-------|---------|
| client | HTTP transport (client.request) |
| upload | upload, remove, getPayload, uploadUrl |
| i18n | Labels, placeholders, error messages |
| parsers | optionResponse, submitResponse, viewResponse |
| renderers | fields, layout, submitActions, viewValue, link |
| transformers | normalizeInitialValues, transformFieldValue, transformSubmitValues |
| cache | In-memory TTL cache for options/view requests |
Custom field renderer
renderers={{
fields: [
{ match: "my_field_code", render: (group, ctx) => <MyInput /> },
{ match: "select", render: (group, ctx) => <CustomSelect options={ctx.options} /> },
],
}}Migration from v0.0.x
| v0.0.x | v0.1.x |
|--------|--------|
| requestClient prop | client={{ request }} or keep requestClient (deprecated) |
| uploadAdapter | upload.upload |
| deleteUploadAdapter(path) | upload.remove({ path, fieldCode, fieldGroup }) |
| messages | i18n.messages |
| optionResponseParser | parsers.optionResponse |
| customFieldRenderers map | renderers.fields array |
| onSubmitSuccess(data) | onSubmitSuccess({ values, response, data }) |
| uploadResourceUrl | uploadUrl (alias kept) |
API View Mode (MetaView)
Unified mode api replaces api_ids and api_detail:
{
"mode": "api",
"api": {
"url": "/obs/users",
"method": "POST",
"data": { "ids": "{{value}}" },
"data_path": "data.items",
"result_type": "array",
"mapping_attr": ["name", "id"],
"link": "https://example.com/{{id}}"
}
}Single object response:
{
"mode": "api",
"api": {
"url": "/obs/users/{{id}}",
"method": "GET",
"url_template": true,
"data_path": "data",
"result_type": "object",
"mapping_attr": ["name"]
}
}| Field | Description |
|-------|-------------|
| url | API endpoint (supports {{id}} when url_template: true) |
| method | HTTP method |
| data_path | Dot path to extract data from response (e.g. data.items) |
| result_type | array (list) or object (single row); auto-inferred if omitted |
| params / data | Request binding with templates {{value}}, {{id}} |
| url_template | Fill URL per value item (legacy api_detail behavior) |
| mapping_attr | Fields to join as display label |
| link | URL template from item data |
Legacy api_ids / api_detail configs still work via automatic normalization.
Performance notes
FormItemis memoized; only re-renders when its own state changes.- Option API calls are cached with TTL and abort stale requests.
- Dependency fields use targeted
Form.useWatchinstead of watching entire form. - Submit uses ref guard to prevent double-submit.
Exports
- Components:
DynamicForm,FormItem,MetaItemValue,ApiViewItem,ApiItem,ApiDetailItem - Hooks:
useViewMode,useDynamicOptions,useFieldGroups,useFieldStates,useProcessedValues - Utils:
parseFormValues,normalizeMetaForForm,resolveFieldViewValue,mapOptions - Adapters:
createAxiosDynamicFormClient
