dynamicformdjx-react 0.0.4 → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +269 -15
- package/dist/antd/AdDynamicForm.d.ts +18 -0
- package/dist/antd/hooks/renderForm.d.ts +5 -0
- package/dist/antd/index.cjs +173 -0
- package/dist/antd/index.d.ts +6 -0
- package/dist/antd/index.mjs +15197 -0
- package/dist/constants/index.d.ts +1 -0
- package/dist/hooks/useDyForm.d.ts +26 -0
- package/dist/index.cjs +1 -1
- package/dist/index.css +1 -1
- package/dist/index.d.ts +3 -0
- package/dist/index.mjs +473 -304
- package/dist/types/form.d.ts +65 -0
- package/dist/types/index.d.ts +7 -0
- package/dist/utils/tools.d.ts +4 -1
- package/package.json +10 -3
package/README.md
CHANGED
|
@@ -2,12 +2,19 @@
|
|
|
2
2
|
|
|
3
3
|
基于 **React** 的动态表单输入组件。
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
[Document](https://xczcdjx.github.io/dynamicFormDoc/react/install.html)
|
|
6
6
|
|
|
7
|
-
Vue3 版本
|
|
7
|
+
[Vue3 版本](https://www.npmjs.com/package/dynamicformdjx)
|
|
8
8
|
|
|
9
|
-
[Vue2 版本](https://www.npmjs.com/package/dynamicformdjx-vue2) (
|
|
9
|
+
[Vue2 版本](https://www.npmjs.com/package/dynamicformdjx-vue2) (后续适配)
|
|
10
10
|
|
|
11
|
+
## 概述
|
|
12
|
+
|
|
13
|
+
`DynamicForm` 一个灵活且动态的表单组件,使用数组,简化模版操作,提供多种hook快速操作表单等。
|
|
14
|
+
|
|
15
|
+
- 简化节点代码,快速处理表单
|
|
16
|
+
- 提供render2函数渲染表单项,使用函数渲染值或自定义Component函数
|
|
17
|
+
- 提供多种hooks函数,快速处理数据值
|
|
11
18
|
|
|
12
19
|
## 安装
|
|
13
20
|
|
|
@@ -20,22 +27,267 @@ yarn add dynamicformdjx-react
|
|
|
20
27
|
pnpm add dynamicformdjx-react
|
|
21
28
|
```
|
|
22
29
|
|
|
23
|
-
###
|
|
30
|
+
### 动态表单
|
|
31
|
+
|
|
32
|
+
#### 与Antd配合
|
|
33
|
+
|
|
34
|
+
> 需配合antd v5+ 版本以上
|
|
35
|
+
|
|
36
|
+
##### 简单表单
|
|
37
|
+
|
|
38
|
+
> 更多render函数请等待后续更新,可直接使用下方自定义渲染
|
|
39
|
+
|
|
40
|
+
```tsx
|
|
41
|
+
import {useRef, useState} from "react";
|
|
42
|
+
import {Button, Input, Radio} from "antd";
|
|
43
|
+
import {AdDynamicForm, type adDynamicFormRef, renderInput} from "dynamicformdjx-react/antd";
|
|
44
|
+
import {omitFormCommonKey, OmitValue, useDyForm, useReactiveForm} from "dynamicformdjx-react";
|
|
45
|
+
import type {PresetType} from "dynamicformdjx-react/types";
|
|
46
|
+
import type {Rule} from "antd/es/form";
|
|
47
|
+
|
|
48
|
+
type RowProps = {
|
|
49
|
+
username: string
|
|
50
|
+
password: string
|
|
51
|
+
desc: string
|
|
52
|
+
preset: string
|
|
53
|
+
}
|
|
54
|
+
const SimpleForm = () => {
|
|
55
|
+
const [presetType, setPresetType] = useState<PresetType>('fullRow')
|
|
56
|
+
const [formItems, setFormItems] = useReactiveForm<RowProps, Rule | Rule[]>([
|
|
57
|
+
{
|
|
58
|
+
key: "username",
|
|
59
|
+
label: "用户名",
|
|
60
|
+
value: "",
|
|
61
|
+
allowClear: true,
|
|
62
|
+
rule: [{required: true, message: 'Please input your username!', validateTrigger: 'onBlur'}],
|
|
63
|
+
render2: f => renderInput({}, f),
|
|
64
|
+
span: 12
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
key: "password",
|
|
68
|
+
label: "密码",
|
|
69
|
+
required: true,
|
|
70
|
+
value: "",
|
|
71
|
+
render2: (f) => <Input.Password placeholder="请输入密码" {...OmitValue(f, omitFormCommonKey)}/>,
|
|
72
|
+
span: 8,
|
|
73
|
+
offset: 2,
|
|
74
|
+
sort: 0
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
key: "preset",
|
|
78
|
+
label: "表格预设",
|
|
79
|
+
value: "fullRow",
|
|
80
|
+
render2: (f) => <Radio.Group
|
|
81
|
+
value={f.value}
|
|
82
|
+
options={[
|
|
83
|
+
{value: 'fullRow', label: 'row'},
|
|
84
|
+
{value: 'grid', label: 'grid'},
|
|
85
|
+
]}
|
|
86
|
+
onChange={(v) => {
|
|
87
|
+
setPresetType(v.target.value)
|
|
88
|
+
}}
|
|
89
|
+
/>,
|
|
90
|
+
}
|
|
91
|
+
])
|
|
92
|
+
const useForm = useDyForm([formItems, setFormItems])
|
|
93
|
+
const antdFormRef = useRef<adDynamicFormRef>(null)
|
|
94
|
+
const rules: Partial<Record<keyof RowProps, Rule | Rule[]>> = {
|
|
95
|
+
desc: [{required: true, message: '请输入详情'}]
|
|
96
|
+
}
|
|
97
|
+
return (
|
|
98
|
+
<div className='dynamicFormTest'>
|
|
99
|
+
<AdDynamicForm ref={antdFormRef} rules={rules} validateTrigger={null} items={formItems}
|
|
100
|
+
preset={presetType}/>
|
|
101
|
+
<div className="footer" style={{
|
|
102
|
+
display: 'flex',
|
|
103
|
+
gap: '5px'
|
|
104
|
+
}}>
|
|
105
|
+
<Button color={'green'} variant={'outlined'} onClick={() => {
|
|
106
|
+
// const res=antdFormRef.current?.getResult?.()
|
|
107
|
+
const res = useForm.getValues()
|
|
108
|
+
console.log(res)
|
|
109
|
+
}}>getData</Button>
|
|
110
|
+
<Button color={'orange'} variant={'outlined'} onClick={() => {
|
|
111
|
+
useForm.setValues({
|
|
112
|
+
username: 'antd',
|
|
113
|
+
password: 'I love you'
|
|
114
|
+
})
|
|
115
|
+
}}>setData</Button>
|
|
116
|
+
<Button color={'blue'} variant={'outlined'} onClick={() => {
|
|
117
|
+
antdFormRef.current?.validator().then(v => {
|
|
118
|
+
console.log(v)
|
|
119
|
+
}).catch(r => {
|
|
120
|
+
console.log(r)
|
|
121
|
+
})
|
|
122
|
+
}}>validator</Button>
|
|
123
|
+
<Button color={'red'} variant={'outlined'} onClick={() => {
|
|
124
|
+
useForm.onReset()
|
|
125
|
+
}}>reset</Button>
|
|
126
|
+
<Button variant={'outlined'} onClick={() => {
|
|
127
|
+
useForm.setDisabled(true)
|
|
128
|
+
}}>setDisabled</Button>
|
|
129
|
+
</div>
|
|
130
|
+
</div>
|
|
131
|
+
);
|
|
132
|
+
};
|
|
133
|
+
|
|
134
|
+
export default SimpleForm;
|
|
135
|
+
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
##### 自定义表单
|
|
139
|
+
|
|
140
|
+
```tsx
|
|
141
|
+
import {useRef} from "react";
|
|
142
|
+
import {Button, Input, Select} from "antd";
|
|
143
|
+
import {
|
|
144
|
+
DynamicInput,
|
|
145
|
+
type dynamicInputRef,
|
|
146
|
+
omitFormCommonKey,
|
|
147
|
+
OmitValue,
|
|
148
|
+
useDyForm,
|
|
149
|
+
useReactiveForm
|
|
150
|
+
} from "dynamicformdjx-react";
|
|
151
|
+
import {AdDynamicForm, type adDynamicFormRef} from "dynamicformdjx-react/antd";
|
|
152
|
+
import type {Rule} from "antd/es/form";
|
|
153
|
+
|
|
154
|
+
type RowProps = {
|
|
155
|
+
username: string
|
|
156
|
+
job: string
|
|
157
|
+
json: object
|
|
158
|
+
}
|
|
159
|
+
const CustomForm = () => {
|
|
160
|
+
const [formItems, setFormItems] = useReactiveForm<RowProps, Rule | Rule[]>([
|
|
161
|
+
{
|
|
162
|
+
key: "username",
|
|
163
|
+
label: "用户名",
|
|
164
|
+
value: "",
|
|
165
|
+
allowClear: true,
|
|
166
|
+
render2: (f) => <Input placeholder="请输入姓名" {...OmitValue(f, omitFormCommonKey)}/>,
|
|
167
|
+
rule: [
|
|
168
|
+
{
|
|
169
|
+
required: true,
|
|
170
|
+
message: 'Please confirm your username!',
|
|
171
|
+
},
|
|
172
|
+
{
|
|
173
|
+
validator: async (_, value) => {
|
|
174
|
+
if (!value) return; // 交给 required 处理
|
|
175
|
+
if (value.length < 3) {
|
|
176
|
+
throw new Error('至少 3 个字符');
|
|
177
|
+
}
|
|
178
|
+
},
|
|
179
|
+
}
|
|
180
|
+
],
|
|
181
|
+
},
|
|
182
|
+
{
|
|
183
|
+
key: "job",
|
|
184
|
+
label: "职位",
|
|
185
|
+
value: "",
|
|
186
|
+
required: true,
|
|
187
|
+
render2: (f) => <Select
|
|
188
|
+
style={{
|
|
189
|
+
width: '100%'
|
|
190
|
+
}}
|
|
191
|
+
options={[
|
|
192
|
+
{value: 'jack', label: 'Jack'},
|
|
193
|
+
{value: 'lucy', label: 'Lucy'},
|
|
194
|
+
{value: 'Yiminghe', label: 'yiminghe'},
|
|
195
|
+
{value: 'disabled', label: 'Disabled', disabled: true},
|
|
196
|
+
]}
|
|
197
|
+
/>,
|
|
198
|
+
},
|
|
199
|
+
{
|
|
200
|
+
key: "json",
|
|
201
|
+
label: "Json",
|
|
202
|
+
value: {},
|
|
203
|
+
isCustom: true,
|
|
204
|
+
rule: [
|
|
205
|
+
{
|
|
206
|
+
required: true,
|
|
207
|
+
message: 'json 不能为空'
|
|
208
|
+
},
|
|
209
|
+
{
|
|
210
|
+
validator: async (_, value) => {
|
|
211
|
+
if (!value || Object.keys(value).length === 0) {
|
|
212
|
+
throw new Error('json 不能为空');
|
|
213
|
+
}
|
|
214
|
+
},
|
|
215
|
+
}
|
|
216
|
+
],
|
|
217
|
+
render2: f => {
|
|
218
|
+
return <DynamicInput ref={dynamicInputRef} value={f.value} onChange={(v: object) => {
|
|
219
|
+
f.value = v
|
|
220
|
+
}} isController/>
|
|
221
|
+
},
|
|
222
|
+
},
|
|
223
|
+
])
|
|
224
|
+
const useForm = useDyForm([formItems, setFormItems])
|
|
225
|
+
const antdFormRef = useRef<adDynamicFormRef>(null)
|
|
226
|
+
const dynamicInputRef = useRef<dynamicInputRef>(null)
|
|
227
|
+
return (
|
|
228
|
+
<div className='dynamicFormTest'>
|
|
229
|
+
<AdDynamicForm ref={antdFormRef} items={formItems}/>
|
|
230
|
+
<div className="footer" style={{
|
|
231
|
+
display: 'flex',
|
|
232
|
+
gap: '5px'
|
|
233
|
+
}}>
|
|
234
|
+
<Button color={'green'} variant={'outlined'} onClick={() => {
|
|
235
|
+
// const res=antdFormRef.current?.getResult?.()
|
|
236
|
+
const res = useForm.getValues()
|
|
237
|
+
console.log(res)
|
|
238
|
+
}}>getData</Button>
|
|
239
|
+
<Button color={'orange'} variant={'outlined'} onClick={() => {
|
|
240
|
+
useForm.setValues({
|
|
241
|
+
username: 'antd',
|
|
242
|
+
job: 'jack'
|
|
243
|
+
})
|
|
244
|
+
dynamicInputRef.current?.onSet?.({
|
|
245
|
+
a: 'Hello world',
|
|
246
|
+
b: 1314,
|
|
247
|
+
c: [5, 2, 0]
|
|
248
|
+
})
|
|
249
|
+
}}>setData</Button>
|
|
250
|
+
<Button color={'blue'} variant={'outlined'} onClick={() => {
|
|
251
|
+
antdFormRef.current?.validator().then(v => {
|
|
252
|
+
console.log(v)
|
|
253
|
+
}).catch(r => {
|
|
254
|
+
console.error(r)
|
|
255
|
+
})
|
|
256
|
+
}}>validator</Button>
|
|
257
|
+
<Button color={'red'} variant={'outlined'} onClick={() => {
|
|
258
|
+
useForm.onReset()
|
|
259
|
+
dynamicInputRef.current?.onSet?.({})
|
|
260
|
+
}}>reset</Button>
|
|
261
|
+
</div>
|
|
262
|
+
</div>
|
|
263
|
+
);
|
|
264
|
+
};
|
|
265
|
+
|
|
266
|
+
export default CustomForm;
|
|
267
|
+
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
### 动态录入
|
|
271
|
+
|
|
272
|
+
> 此录入无需组件库依赖
|
|
273
|
+
|
|
274
|
+
### 1.单组件
|
|
275
|
+
|
|
24
276
|
```tsx
|
|
25
277
|
import {useState} from "react";
|
|
26
|
-
import {DynamicInput,dynamicFormRef} from "dynamicformdjx-react";
|
|
278
|
+
import {DynamicInput, dynamicFormRef} from "dynamicformdjx-react";
|
|
27
279
|
|
|
28
280
|
function App() {
|
|
29
|
-
const [obj,setObj]=useState<Record<string, any>>({
|
|
281
|
+
const [obj, setObj] = useState<Record<string, any>>({
|
|
30
282
|
a: 'Hello world',
|
|
31
283
|
b: 1314,
|
|
32
284
|
c: [5, 2, 0]
|
|
33
285
|
});
|
|
34
|
-
const dynamicInputRef=useRef<dynamicFormRef>(null)
|
|
286
|
+
const dynamicInputRef = useRef<dynamicFormRef>(null)
|
|
35
287
|
return (<div>
|
|
36
288
|
<DynamicInput ref={dynamicInputRef} isController value={obj} onChange={(e) => setObj(e)}/>
|
|
37
289
|
<pre>
|
|
38
|
-
{JSON.stringify(obj,null, 2)}
|
|
290
|
+
{JSON.stringify(obj, null, 2)}
|
|
39
291
|
</pre>
|
|
40
292
|
<div>
|
|
41
293
|
<button onClick={() => {
|
|
@@ -51,12 +303,14 @@ function App() {
|
|
|
51
303
|
export default App
|
|
52
304
|
```
|
|
53
305
|
|
|
54
|
-
###
|
|
306
|
+
### 2.级联基本使用
|
|
307
|
+
|
|
55
308
|
```tsx
|
|
56
309
|
import {useState} from "react";
|
|
57
|
-
import {DynamicCascadeInput,dynamicCascadeInputRef} from "dynamicformdjx-react";
|
|
58
|
-
|
|
59
|
-
|
|
310
|
+
import {DynamicCascadeInput, dynamicCascadeInputRef} from "dynamicformdjx-react";
|
|
311
|
+
|
|
312
|
+
const App = () => {
|
|
313
|
+
const [obj, setObj] = useState<Record<string, any>>({
|
|
60
314
|
a: {
|
|
61
315
|
b: {
|
|
62
316
|
c: {
|
|
@@ -69,16 +323,16 @@ const App=()=>{
|
|
|
69
323
|
aa: [5, 2, 0],
|
|
70
324
|
aaa: 1314
|
|
71
325
|
});
|
|
72
|
-
const dynamicInputRef=useRef<dynamicCascadeInputRef>(null)
|
|
326
|
+
const dynamicInputRef = useRef<dynamicCascadeInputRef>(null)
|
|
73
327
|
return (<div>
|
|
74
328
|
<DynamicCascadeInput ref={dynamicInputRef} isController value={obj} onChange={(e) => setObj(e)}/>
|
|
75
329
|
<pre>
|
|
76
|
-
{JSON.stringify(obj,null, 2)}
|
|
330
|
+
{JSON.stringify(obj, null, 2)}
|
|
77
331
|
</pre>
|
|
78
332
|
<div>
|
|
79
333
|
<button onClick={() => {
|
|
80
334
|
dynamicInputRef.current?.onSet?.({
|
|
81
|
-
test:'hello world'
|
|
335
|
+
test: 'hello world'
|
|
82
336
|
})
|
|
83
337
|
}}>setData
|
|
84
338
|
</button>
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { ReactNode } from 'react';
|
|
2
|
+
import { FormProps, RowProps } from 'antd';
|
|
3
|
+
import { Rule } from 'antd/es/form';
|
|
4
|
+
import { DyFormItem } from '../types/form';
|
|
5
|
+
import { ExposeDyFType, PresetType } from '../types';
|
|
6
|
+
type RulesMap = Record<string, Rule | Rule[]>;
|
|
7
|
+
type AdDynamicFormProps = {
|
|
8
|
+
header?: () => ReactNode;
|
|
9
|
+
footer?: () => ReactNode;
|
|
10
|
+
items: DyFormItem[];
|
|
11
|
+
preset?: PresetType;
|
|
12
|
+
formConfig?: FormProps;
|
|
13
|
+
gridConfig?: RowProps;
|
|
14
|
+
validateTrigger?: string | null;
|
|
15
|
+
rules?: RulesMap;
|
|
16
|
+
};
|
|
17
|
+
declare const AdDynamicForm: import('react').ForwardRefExoticComponent<AdDynamicFormProps & import('react').RefAttributes<ExposeDyFType>>;
|
|
18
|
+
export default AdDynamicForm;
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { DyFormItem } from '../../types/form';
|
|
2
|
+
import { PasswordProps, TextAreaProps, InputProps } from 'antd/es/input';
|
|
3
|
+
export declare function renderInput(optionProps: PasswordProps, rf?: DyFormItem): JSX.Element;
|
|
4
|
+
export declare function renderInput(optionProps: TextAreaProps, rf?: DyFormItem): JSX.Element;
|
|
5
|
+
export declare function renderInput(optionProps?: InputProps, rf?: DyFormItem): JSX.Element;
|