@jack-ui/j-form
v0.1.3
Published
Schema-driven React form package built on Ant Design with runtime API, search form, async options, and modal/drawer submit pages.
Maintainers
Readme
@jack-ui/j-form
面向 Ant Design 的 schema 驱动 React 表单系统,统一覆盖:
- 通用业务表单
- 查询 / 搜索区表单
- 异步选项字段
- 弹窗与抽屉提交页
为什么是 JForm
很多表单体系最终会拆成几块互相割裂的能力:
- 常规表单一套渲染方式
- 查询表单再包一层
- 命令式控制另起一套 API
- 弹窗 / 抽屉表单再独立实现一次
@jack-ui/j-form 的目标是把这些表面能力压在同一套运行时模型上。
产品能力面
| 能力面 | 最适合解决的问题 |
| --- | --- |
| JForm | 通用 schema 驱动业务表单 |
| JSearchForm | 查询区、折叠区、内联操作区、横向 label |
| createJFormApi() / useJForm() | 运行时编排、schema 变更、校验、重置、订阅 |
| optionsSource | 防抖、缓存、远程选项加载 |
| submit-page | 多步、默认底栏动作、service 打开的弹窗 / 抽屉提交页 |
30 秒开始
安装
pnpm add @jack-ui/j-form antd @ant-design/icons react react-dom导入样式
import '@jack-ui/j-form/styles.css';
import '@jack-ui/j-form/submit-page/styles.css'; // 只有使用 submit-page 时才需要渲染一个表单
import '@jack-ui/j-form/styles.css';
import { JForm } from '@jack-ui/j-form';
type ProjectValues = {
name?: string;
status?: string;
budget?: number;
};
export function ProjectForm() {
return (
<JForm<ProjectValues>
gridColumns={2}
layout="vertical"
onSubmit={async (values) => {
console.log(values);
}}
schema={[
{ name: 'name', label: '项目名称', required: true },
{
name: 'status',
kind: 'select',
label: '状态',
options: [
{ label: '草稿', value: 'draft' },
{ label: '已审批', value: 'approved' },
],
},
{ name: 'budget', kind: 'number', label: '预算' },
]}
/>
);
}导入入口
核心表单运行时:
import {
JForm,
JSearchForm,
createJFormApi,
useJForm,
useJFormSelector,
} from '@jack-ui/j-form';提交页运行时:
import {
JFormSubmitPage,
useJFormSubmitPage,
} from '@jack-ui/j-form/submit-page';
import {
JFormSubmitPageProvider,
useJFormSubmitPageService,
} from '@jack-ui/j-form/submit-page/service';说明:
submit-page运行时代码通过子路径拆分。submit-page的 TypeScript 类型仍然从@jack-ui/j-form根入口导出。- 样式不会由 JS 自动注入,必须显式导入。
该选哪一层能力
JForm
通用录入表单使用 JForm。
<JForm
gridColumns={3}
schema={[
{ name: 'name', label: '名称', required: true },
{ name: 'owner', label: '负责人' },
{ name: 'summary', kind: 'textarea', label: '说明', span: 24 },
]}
/>JSearchForm
查询区场景使用 JSearchForm。
它在 JForm 基础上额外提供:
- 固定查询态
- 默认横向布局
- 折叠 / 展开能力
- 最后一行末尾的内联操作区
- 隐藏校验字段需要暴露时自动展开
<JSearchForm
collapsedRows={1}
gridColumns={4}
schema={[
{ name: 'keyword', label: '关键字' },
{ name: 'status', kind: 'select', label: '状态' },
{ name: 'city', kind: 'select', label: '城市' },
{ name: 'owner', label: '负责人', required: true },
]}
/>submit-page
当表单放在弹窗或抽屉里时,使用 JFormSubmitPage。
import '@jack-ui/j-form/submit-page/styles.css';
import { JFormSubmitPage } from '@jack-ui/j-form/submit-page';
<JFormSubmitPage
defaultOpen
mode="drawer"
drawer={{ width: '60%' }}
schema={[
{ name: 'name', label: '名称', required: true },
{ name: 'summary', kind: 'textarea', label: '说明' },
]}
title="新建项目"
/>;运行时控制
useJForm()
在 React 里,如果你需要稳定的 formApi,使用它。
import { JForm, useJForm } from '@jack-ui/j-form';
export function ControlledForm() {
const formApi = useJForm({
values: {
status: 'draft',
},
});
return (
<JForm
formApi={formApi}
schema={[{ name: 'status', label: '状态' }]}
/>
);
}createJFormApi()
如果你需要 React 外部的独立运行时控制器,使用它。
import { createJFormApi } from '@jack-ui/j-form';
const formApi = createJFormApi({
schema: [{ name: 'name', label: '名称' }],
values: { name: '初始值' },
});
formApi.setFieldValue('name', '更新后的值');
console.log(formApi.getValues());JFormApi 重点方法
状态和值:
setValues(values)replaceValues(values)setFieldValue(name, value)getValues()getFieldValue(name)getSnapshot()subscribe(listener)
Schema:
setSchema(schema)getSchema()updateSchema(name, updater)appendSchemaByField(name, fields)removeSchemaByField(name)removeSchemaByFields(names)setVisibleFields(names)
校验与提交:
validate(names?)validateResult(names?)validateField(name)validateFieldResult(name)isFieldValid(name)clearErrors(names?)clearValidate(names?)reset()resetForm(values?)submit()submitForm()validateAndSubmitForm()
事件:
submitresetlazy-options-startlazy-options-successlazy-options-errorlazy-options-end
Schema 模型
常用字段属性
| 属性 | 说明 |
| --- | --- |
| name | 字段名,支持点路径,例如 user.name |
| kind | 内建字段类型 |
| label | 表单项标题 |
| required | 是否必填 |
| rules | Ant Design 校验规则 |
| defaultValue | 字段加入时若当前值缺失则应用默认值 |
| span | 手动覆盖字段宽度 |
| width | 控件显式宽度 |
| options | 静态选项 |
| optionsSource | 异步选项配置 |
| dependsOn | 依赖驱动 hidden / disabled / required / rules / componentProps |
| component | 自定义字段组件 |
| render | 自定义字段渲染函数 |
| componentProps | 透传给控件的 props |
| itemProps | 透传给 Form.Item 的 props |
| normalize | 值标准化钩子 |
内建字段类型
inputpasswordtextareaselectdatedatetimedaterangedatetimerangemonthyeartimetimerangenumberswitchradioradio-buttoncheckboxcustom
依赖联动字段
依赖联动可以推导:
hiddendisabledrequiredrulescomponentProps
{
name: 'reviewer',
label: '审批人',
dependsOn: {
watch: ['status'],
hidden: ({ values }) => values.status !== 'approved',
required: ({ values }) => values.status === 'approved',
},
}自定义字段上下文
自定义 component / render 会拿到:
apifieldvaluesvaluesetValue(value, { rawData })optionsloadingdisabledonSearch(keyword)getPopupContainer()
异步选项
optionsSource
支持字段:
triggersdebounceMscachecacheMaxEntriescacheTtlMscacheKeyminKeywordLengthpreserveOnErrorclearBeforeLoadoncemapOptionsload(context)
{
name: 'city',
kind: 'select',
label: '城市',
optionsSource: {
triggers: ['search'],
debounceMs: 300,
cache: true,
minKeywordLength: 2,
async load({ keyword, signal }) {
const response = await fetch(`/api/cities?q=${keyword}`, { signal });
const data = await response.json();
return {
options: data.items,
raw: data,
};
},
},
}远程 helper
根入口提供这些 helper:
createJFormOptionsSource()createJFormRemoteOptionsSource()createJFormRemoteSearchParams()mapJFormRemoteOptionList()mapJFormTreeOptions()resolveJFormOptionsArray()
import { createJFormRemoteOptionsSource } from '@jack-ui/j-form';
const cityOptionsSource = createJFormRemoteOptionsSource({
cache: true,
trigger: 'search',
async request({ keyword, signal }) {
const response = await fetch(`/api/cities?q=${keyword}`, { signal });
return response.json();
},
});Submit-page 子系统
submit-page 是一个统一抽象,可以渲染成弹窗或抽屉。
声明式
import { JFormSubmitPage } from '@jack-ui/j-form/submit-page';
<JFormSubmitPage
defaultOpen
mode="modal"
schema={[{ name: 'name', label: '名称', required: true }]}
title="新建项目"
/>;Hook
import { Button } from 'antd';
import { useJFormSubmitPage } from '@jack-ui/j-form/submit-page';
export function HookDemo() {
const { controller, node } = useJFormSubmitPage({
schema: [{ name: 'name', label: '名称', required: true }],
title: 'Hook 提交页',
});
return (
<>
<Button onClick={() => controller.open()}>打开</Button>
{node}
</>
);
}Service
import { Button } from 'antd';
import {
JFormSubmitPageProvider,
useJFormSubmitPageService,
} from '@jack-ui/j-form/submit-page/service';
function Trigger() {
const service = useJFormSubmitPageService();
return (
<Button
onClick={() => {
const handle = service.open({
mode: 'drawer',
drawer: { width: '60%' },
schema: [{ name: 'name', label: '名称', required: true }],
title: 'Service 提交页',
});
void handle.closed.then((result) => {
console.log(result.reason, result.values);
});
}}
>
打开
</Button>
);
}
export function ServiceDemo() {
return (
<JFormSubmitPageProvider>
<Trigger />
</JFormSubmitPageProvider>
);
}Submit-page API 重点
主 props:
modeschemastepsformApiopen/defaultOpentitleheaderfootershowStepHeaderstepTransitionMsresetOnCloseresetOnSubmitbeforeCloseonCancelonOpenChangeonStepChangeonSubmitSuccessmodaldrawer
Footer 行为:
- 默认底栏按钮会自动构建
footer.actions默认是追加- 设置
footer.showDefaultActions = false可以关闭默认按钮 - 内建 action 支持
text: null的图标按钮形式
Controller API:
open()close(reason?)toggle(open?)setOpen(open, reason?)getOpen()getStep()getTotalSteps()goToStep(step)next()prev()getFormApi()
Service handle API:
idcontrollerformApiupdate(partialOptions)close(reason?)closed
国际化与主题
文案覆盖
import { JFormConfigProvider } from '@jack-ui/j-form';
const localeText = {
submit: '保存',
reset: '清空',
query: '查询',
expand: '展开',
collapse: '收起',
};
export function App() {
return (
<JFormConfigProvider localeText={localeText}>
{/* app */}
</JFormConfigProvider>
);
}主题 token
j-form 会跟随外层 Ant Design token。需要在自定义组件中读取时,可以使用 useJFormTokens()。
CSS 策略
@jack-ui/j-form/styles.css:JForm和JSearchForm基础样式@jack-ui/j-form/submit-page/styles.css:submit-page 样式- 根运行时入口没有隐式样式副作用
相关链接
- npm: @jack-ui/j-form
- GitHub 仓库: jackBoVip/jack-ui
- 英文文档: README.md
