@fairys/valtio-form-basic 0.0.8 → 0.0.10
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/esm/form/form.d.ts +9 -4
- package/esm/form/form.item.d.ts +88 -21
- package/esm/form/form.item.js +124 -32
- package/esm/form/hooks/index.d.ts +34 -0
- package/esm/form/hooks/index.js +57 -0
- package/esm/form/instance/index.d.ts +21 -4
- package/esm/form/instance/index.js +52 -23
- package/esm/form/layout.d.ts +17 -5
- package/esm/form/layout.js +26 -14
- package/esm/form/utils/index.d.ts +24 -0
- package/esm/form/utils/index.js +60 -0
- package/esm/index.d.ts +1 -0
- package/esm/index.js +1 -0
- package/esm/styles/index.css +36 -10
- package/lib/index.js +21 -12
- package/package.json +2 -2
- package/src/form/form.item.tsx +236 -52
- package/src/form/form.tsx +3 -18
- package/src/form/hooks/index.tsx +78 -0
- package/src/form/instance/index.ts +69 -33
- package/src/form/layout.tsx +47 -17
- package/src/form/utils/index.ts +108 -0
- package/src/index.tsx +1 -0
- package/src/styles/index.css +18 -4
package/src/form/form.item.tsx
CHANGED
|
@@ -1,14 +1,27 @@
|
|
|
1
1
|
/**表单项*/
|
|
2
2
|
|
|
3
3
|
import { MObject } from 'interface';
|
|
4
|
-
import React, { useMemo } from 'react';
|
|
4
|
+
import React, { useEffect, useMemo } from 'react';
|
|
5
5
|
import clsx from 'clsx';
|
|
6
6
|
import { useFairysValtioFormInstanceContextState, FairysValtioFormInstance } from './instance';
|
|
7
7
|
import { useFairysValtioFormLayoutContext, FairysValtioFormLayoutContextOptions } from './layout';
|
|
8
|
+
import { FairysValtioFormParentAttrs, useFairysValtioFormAttrsName } from './hooks';
|
|
9
|
+
import { get } from './utils';
|
|
10
|
+
import { RuleItem } from 'async-validator';
|
|
8
11
|
|
|
9
12
|
export interface FairysValtioFormItemAttrsProps<T extends MObject<T> = object> {
|
|
10
|
-
|
|
11
|
-
|
|
13
|
+
/**
|
|
14
|
+
* 表单项名称 ,字段需要和存储的字段路径一致
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* 路径中的值为 number 类型时,会创建一个空数组。路径中的值为 string 类型时,会创建一个空对象。最后一个直接赋值
|
|
18
|
+
*
|
|
19
|
+
* 默认:"name"
|
|
20
|
+
* 嵌套字段:"name.a.doc" ===> { name: { a: { doc: undefined } } }
|
|
21
|
+
* 嵌套字段:"name[1].a.doc" ===> { name: [{}, { a: { doc: undefined } }] }
|
|
22
|
+
* 嵌套字段:"name.a[2].doc" ===> { name: { a: [{}, {}, { doc: undefined }] } }
|
|
23
|
+
*/
|
|
24
|
+
name?: string;
|
|
12
25
|
/**表单项标签*/
|
|
13
26
|
label?: string;
|
|
14
27
|
/**传递组件字段*/
|
|
@@ -29,9 +42,9 @@ export interface FairysValtioFormItemAttrsProps<T extends MObject<T> = object> {
|
|
|
29
42
|
bodyStyle?: React.CSSProperties;
|
|
30
43
|
children?: React.ReactNode;
|
|
31
44
|
/**规则校验失败错误提示位置*/
|
|
32
|
-
errorLayout?: '
|
|
45
|
+
errorLayout?: FairysValtioFormLayoutContextOptions['errorLayout'];
|
|
33
46
|
/**label显示模式*/
|
|
34
|
-
labelMode?: '
|
|
47
|
+
labelMode?: FairysValtioFormLayoutContextOptions['labelMode'];
|
|
35
48
|
/**额外内容*/
|
|
36
49
|
extra?: React.ReactNode;
|
|
37
50
|
/**底部提示内容*/
|
|
@@ -51,9 +64,19 @@ export interface FairysValtioFormItemAttrsProps<T extends MObject<T> = object> {
|
|
|
51
64
|
/**是否显示冒号*/
|
|
52
65
|
showColon?: boolean;
|
|
53
66
|
/**底部显示边框*/
|
|
54
|
-
|
|
67
|
+
itemBorderType?: FairysValtioFormLayoutContextOptions['itemBorderType'];
|
|
68
|
+
/**边框颜色*/
|
|
69
|
+
itemBorderColor?: React.CSSProperties['borderColor'];
|
|
70
|
+
/**是否校验失败时显示红色边框*/
|
|
71
|
+
isInvalidBorderRed?: boolean;
|
|
72
|
+
/**是否校验失败时显示红色文本*/
|
|
73
|
+
isInvalidTextRed?: boolean;
|
|
55
74
|
/**输入框属性*/
|
|
56
75
|
attrs?: any;
|
|
76
|
+
/**是否拼接父级字段名*/
|
|
77
|
+
isJoinParentField?: boolean;
|
|
78
|
+
/**校验规则*/
|
|
79
|
+
rules?: RuleItem[];
|
|
57
80
|
}
|
|
58
81
|
|
|
59
82
|
/**
|
|
@@ -63,7 +86,7 @@ export interface FairysValtioFormItemAttrsProps<T extends MObject<T> = object> {
|
|
|
63
86
|
*
|
|
64
87
|
* ```tsx
|
|
65
88
|
import { Fragment } from 'react'
|
|
66
|
-
import { useFairysValtioFormItemAttrs } from "@fairys/valtio-form"
|
|
89
|
+
import { useFairysValtioFormItemAttrs , FairysValtioFormParentAttrsContext } from "@fairys/valtio-form"
|
|
67
90
|
import type { FairysValtioFormItemAttrsProps } from "@fairys/valtio-form"
|
|
68
91
|
export interface FormItemProps extends FairysValtioFormItemAttrsProps{}
|
|
69
92
|
|
|
@@ -72,10 +95,11 @@ export const FormItem = (props: FormItemProps) => {
|
|
|
72
95
|
const {
|
|
73
96
|
itemClassName, itemStyle, containerClassName, itemLabelClassName, itemLabelStyle,
|
|
74
97
|
itemBodyClassName, itemBodyStyle, itemInputClassName, itemExtraClassName, errorClassName, helpClassName,
|
|
75
|
-
isInvalid,
|
|
98
|
+
isInvalid, itemBorderType, children, error,formAttrsNameInstance
|
|
76
99
|
} = useFairysValtioFormItemAttrs(props)
|
|
77
100
|
|
|
78
101
|
return (
|
|
102
|
+
<FairysValtioFormParentAttrsContext.Provider value={formAttrsNameInstance}>
|
|
79
103
|
<View className={itemClassName} style={itemStyle}>
|
|
80
104
|
<View className={containerClassName}>
|
|
81
105
|
<View className={itemLabelClassName} style={itemLabelStyle}>
|
|
@@ -86,12 +110,13 @@ export const FormItem = (props: FormItemProps) => {
|
|
|
86
110
|
{children}
|
|
87
111
|
</View>
|
|
88
112
|
{extra ? <View className={itemExtraClassName}>{extra}</View> : <Fragment />}
|
|
89
|
-
{
|
|
113
|
+
{itemBorderType === 'body' && isInvalid ? <View className={errorClassName}>{error}</View> : <Fragment />}
|
|
90
114
|
</View>
|
|
91
115
|
</View>
|
|
92
116
|
{helpText ? <View className={helpClassName}>{helpText}</View> : <Fragment />}
|
|
93
|
-
{isInvalid &&
|
|
117
|
+
{isInvalid && itemBorderType !== 'body' ? <View className={errorClassName}>{error}</View> : <Fragment />}
|
|
94
118
|
</View>
|
|
119
|
+
</FairysValtioFormParentAttrsContext.Provider>
|
|
95
120
|
);
|
|
96
121
|
}
|
|
97
122
|
* ```
|
|
@@ -100,8 +125,8 @@ export const FormItem = (props: FormItemProps) => {
|
|
|
100
125
|
export function useFairysValtioFormItemAttrs<T extends MObject<T> = object>(props: FairysValtioFormItemAttrsProps<T>) {
|
|
101
126
|
const [layoutAttrs] = useFairysValtioFormLayoutContext();
|
|
102
127
|
const colCount = layoutAttrs.colCount || 1;
|
|
103
|
-
const parent_borderedType = layoutAttrs.
|
|
104
|
-
const parent_errorLayout = layoutAttrs.errorLayout || 'right
|
|
128
|
+
const parent_borderedType = layoutAttrs.itemBorderType || 'bottom';
|
|
129
|
+
const parent_errorLayout = layoutAttrs.errorLayout || 'bottom-right';
|
|
105
130
|
const parent_formItemClassName = layoutAttrs.formItemClassName;
|
|
106
131
|
const parent_formItemLabelClassName = layoutAttrs.formItemLabelClassName;
|
|
107
132
|
const parent_formItemLabelStyle = layoutAttrs.formItemLabelStyle;
|
|
@@ -109,6 +134,11 @@ export function useFairysValtioFormItemAttrs<T extends MObject<T> = object>(prop
|
|
|
109
134
|
const parent_formItemBodyClassName = layoutAttrs.formItemBodyClassName;
|
|
110
135
|
const parent_formItemBodyStyle = layoutAttrs.formItemBodyStyle;
|
|
111
136
|
const parent_labelMode = layoutAttrs.labelMode || 'between';
|
|
137
|
+
const parent_itemBorderColor = layoutAttrs.itemBorderColor;
|
|
138
|
+
const parent_isInvalidBorderRed = layoutAttrs.isInvalidBorderRed;
|
|
139
|
+
const parent_isInvalidTextRed = layoutAttrs.isInvalidTextRed;
|
|
140
|
+
const parent_showColon = layoutAttrs.showColon;
|
|
141
|
+
|
|
112
142
|
const {
|
|
113
143
|
name,
|
|
114
144
|
valuePropName = 'value',
|
|
@@ -128,14 +158,38 @@ export function useFairysValtioFormItemAttrs<T extends MObject<T> = object>(prop
|
|
|
128
158
|
colSpan = 1,
|
|
129
159
|
rowSpan = 1,
|
|
130
160
|
isRequired: _isRequired,
|
|
131
|
-
|
|
161
|
+
itemBorderType = parent_borderedType,
|
|
132
162
|
attrs = {},
|
|
133
|
-
showColon =
|
|
163
|
+
showColon = parent_showColon,
|
|
164
|
+
itemBorderColor = parent_itemBorderColor,
|
|
165
|
+
isInvalidBorderRed = parent_isInvalidBorderRed,
|
|
166
|
+
isInvalidTextRed = parent_isInvalidTextRed,
|
|
167
|
+
isJoinParentField = true,
|
|
168
|
+
rules,
|
|
134
169
|
} = props;
|
|
170
|
+
|
|
171
|
+
const {
|
|
172
|
+
name: _name,
|
|
173
|
+
paths,
|
|
174
|
+
parentName,
|
|
175
|
+
formAttrsNameInstance,
|
|
176
|
+
} = useFairysValtioFormAttrsName({ name, isJoinParentField });
|
|
135
177
|
const [state, errorState, formInstance] = useFairysValtioFormInstanceContextState<T>();
|
|
136
|
-
const
|
|
137
|
-
const
|
|
138
|
-
|
|
178
|
+
const value = useMemo(() => get(state, paths), [state, paths]);
|
|
179
|
+
const error = errorState[_name];
|
|
180
|
+
// 使用从 Form 中设置的规则
|
|
181
|
+
const _formItemRules = formInstance.rules?.[_name];
|
|
182
|
+
|
|
183
|
+
formInstance.nameToPaths[_name] = paths;
|
|
184
|
+
/**挂载校验规则*/
|
|
185
|
+
if (Array.isArray(rules) && rules.length) {
|
|
186
|
+
formInstance.mountRules[_name] = rules;
|
|
187
|
+
}
|
|
188
|
+
useEffect(() => {
|
|
189
|
+
return () => {
|
|
190
|
+
formInstance.removeRules(_name);
|
|
191
|
+
};
|
|
192
|
+
}, [_name]);
|
|
139
193
|
|
|
140
194
|
const onValueChange = (event: any) => {
|
|
141
195
|
let value = event;
|
|
@@ -148,7 +202,7 @@ export function useFairysValtioFormItemAttrs<T extends MObject<T> = object>(prop
|
|
|
148
202
|
if (typeof formatValue === 'function') {
|
|
149
203
|
value = formatValue(value, formInstance, event);
|
|
150
204
|
}
|
|
151
|
-
formInstance.
|
|
205
|
+
formInstance.updatedValueByPaths(_name, value);
|
|
152
206
|
if (typeof onAfterUpdate === 'function') {
|
|
153
207
|
onAfterUpdate(value, formInstance, event);
|
|
154
208
|
}
|
|
@@ -168,9 +222,11 @@ export function useFairysValtioFormItemAttrs<T extends MObject<T> = object>(prop
|
|
|
168
222
|
return _isRequired;
|
|
169
223
|
} else if (Array.isArray(rules) && rules.length) {
|
|
170
224
|
return rules.some((rule) => rule.required);
|
|
225
|
+
} else if (_formItemRules && Array.isArray(_formItemRules) && _formItemRules.length) {
|
|
226
|
+
return _formItemRules.some((rule) => rule.required);
|
|
171
227
|
}
|
|
172
228
|
return false;
|
|
173
|
-
}, [rules, formInstance]);
|
|
229
|
+
}, [rules, formInstance, _formItemRules]);
|
|
174
230
|
|
|
175
231
|
/**校验是否存在错误信息*/
|
|
176
232
|
const isInvalid = useMemo(() => {
|
|
@@ -183,22 +239,25 @@ export function useFairysValtioFormItemAttrs<T extends MObject<T> = object>(prop
|
|
|
183
239
|
/**表单项类名*/
|
|
184
240
|
const item_cls = useMemo(() => {
|
|
185
241
|
return clsx(
|
|
186
|
-
'fairys-valtio-form-item fairystaroform__p-[4px] fairystaroform__text-[12px] fairystaroform__relative fairystaroform__flex fairystaroform__flex-col fairystaroform__box-border fairystaroform__break-all',
|
|
242
|
+
'fairys-valtio-form-item fairystaroform__transition-all fairystaroform__duration-300 fairystaroform__p-[4px] fairystaroform__text-[12px] fairystaroform__relative fairystaroform__flex fairystaroform__flex-col fairystaroform__box-border fairystaroform__break-all',
|
|
187
243
|
{
|
|
244
|
+
'fairys-valtio-form-item-invalid': isInvalid,
|
|
245
|
+
'fairys-valtio-form-item-invalid-text-red': isInvalid && isInvalidTextRed,
|
|
246
|
+
'fairys-valtio-form-item-invalid-border-red': isInvalid && isInvalidBorderRed && itemBorderType === 'bottom',
|
|
188
247
|
'fairystaroform__border-b fairystaroform__border-b-solid fairystaroform__border-b-gray-200':
|
|
189
|
-
|
|
248
|
+
itemBorderType === 'bottom',
|
|
190
249
|
[labelMode]: labelMode,
|
|
191
250
|
},
|
|
192
|
-
className,
|
|
193
251
|
parent_formItemClassName,
|
|
252
|
+
className,
|
|
194
253
|
);
|
|
195
|
-
}, [className, parent_formItemClassName, labelMode,
|
|
254
|
+
}, [className, parent_formItemClassName, labelMode, itemBorderType, isInvalid, isInvalidBorderRed]);
|
|
196
255
|
|
|
197
256
|
/**表单项容器类名*/
|
|
198
257
|
const itemContainer_cls = useMemo(() => {
|
|
199
258
|
// 默认两端显示
|
|
200
259
|
return clsx(
|
|
201
|
-
'fairys-valtio-form-item-container fairystaroform__flex-1 fairystaroform__h-full fairystaroform__flex fairystaroform__box-border',
|
|
260
|
+
'fairys-valtio-form-item-container fairystaroform__transition-all fairystaroform__duration-300 fairystaroform__flex-1 fairystaroform__h-full fairystaroform__flex fairystaroform__box-border',
|
|
202
261
|
{
|
|
203
262
|
'fairystaroform__flex-row fairystaroform__items-center fairystaroform__justify-between fairystaroform__gap-[8px]':
|
|
204
263
|
labelMode === 'between',
|
|
@@ -213,7 +272,7 @@ export function useFairysValtioFormItemAttrs<T extends MObject<T> = object>(prop
|
|
|
213
272
|
const itemLabel_cls = useMemo(() => {
|
|
214
273
|
// 默认两端显示
|
|
215
274
|
return clsx(
|
|
216
|
-
'fairys-valtio-form-item-label fairystaroform__text-gray-800 fairystaroform__flex fairystaroform__items-center fairystaroform__relative fairystaroform__box-border',
|
|
275
|
+
'fairys-valtio-form-item-label fairystaroform__transition-all fairystaroform__duration-300 fairystaroform__text-gray-800 fairystaroform__flex fairystaroform__items-center fairystaroform__relative fairystaroform__box-border',
|
|
217
276
|
{
|
|
218
277
|
'fairystaroform__justify-start': labelMode !== 'left',
|
|
219
278
|
'fairystaroform__justify-end': labelMode === 'left',
|
|
@@ -229,23 +288,24 @@ export function useFairysValtioFormItemAttrs<T extends MObject<T> = object>(prop
|
|
|
229
288
|
const itemBody_cls = useMemo(() => {
|
|
230
289
|
// 默认两端显示
|
|
231
290
|
return clsx(
|
|
232
|
-
'fairys-valtio-form-item-body fairystaroform__relative fairystaroform__flex-1 fairystaroform__flex fairystaroform__box-border',
|
|
291
|
+
'fairys-valtio-form-item-body fairystaroform__transition-all fairystaroform__duration-300 fairystaroform__relative fairystaroform__flex-1 fairystaroform__flex fairystaroform__box-border',
|
|
233
292
|
{
|
|
234
293
|
'fairystaroform__flex-row fairystaroform__justify-start': labelMode === 'left',
|
|
235
294
|
'fairystaroform__flex-row fairystaroform__justify-end': labelMode === 'between' || labelMode === 'top',
|
|
236
295
|
'fairystaroform__flex-row': labelMode === 'top',
|
|
237
296
|
'fairystaroform__border-b fairystaroform__border-b-solid fairystaroform__border-b-gray-200 ':
|
|
238
|
-
|
|
297
|
+
itemBorderType === 'body',
|
|
298
|
+
'fairys-valtio-form-item-invalid-border-red': isInvalid && isInvalidBorderRed && itemBorderType === 'body',
|
|
239
299
|
},
|
|
240
|
-
bodyClassName,
|
|
241
300
|
parent_formItemBodyClassName,
|
|
301
|
+
bodyClassName,
|
|
242
302
|
);
|
|
243
|
-
}, [bodyClassName, labelMode,
|
|
303
|
+
}, [bodyClassName, labelMode, itemBorderType, parent_formItemBodyClassName, isInvalid, isInvalidBorderRed]);
|
|
244
304
|
|
|
245
305
|
// 表单项输入类名
|
|
246
306
|
const itemInput_cls = useMemo(() => {
|
|
247
307
|
return clsx(
|
|
248
|
-
'fairys-valtio-form-item-body fairystaroform__flex fairystaroform__flex-row fairystaroform__flex-1 fairystaroform__box-border',
|
|
308
|
+
'fairys-valtio-form-item-body-input fairystaroform__transition-all fairystaroform__duration-300 fairystaroform__min-h-[32px] fairystaroform__flex fairystaroform__flex-row fairystaroform__items-center fairystaroform__flex-1 fairystaroform__box-border',
|
|
249
309
|
{
|
|
250
310
|
'fairystaroform__justify-end fairystaroform__text-right': labelMode === 'between',
|
|
251
311
|
'fairystaroform__justify-start fairystaroform__text-left fairystaroform__items-center': labelMode !== 'between',
|
|
@@ -256,28 +316,34 @@ export function useFairysValtioFormItemAttrs<T extends MObject<T> = object>(prop
|
|
|
256
316
|
/**表单项额外内容类名*/
|
|
257
317
|
const itemExtra_cls = useMemo(() => {
|
|
258
318
|
return clsx(
|
|
259
|
-
'fairys-valtio-form-item-body-extra fairystaroform__box-border fairystaroform__flex fairystaroform__items-center fairystaroform__justify-center',
|
|
319
|
+
'fairys-valtio-form-item-body-extra fairystaroform__transition-all fairystaroform__duration-300 fairystaroform__box-border fairystaroform__flex fairystaroform__items-center fairystaroform__justify-center',
|
|
260
320
|
);
|
|
261
321
|
}, []);
|
|
262
322
|
|
|
263
323
|
/**表单项底部提示内容类名*/
|
|
264
324
|
const itemHelp_cls = useMemo(() => {
|
|
265
325
|
return clsx(
|
|
266
|
-
'fairys-valtio-form-item-body-help fairystaroform__text-[10px] fairystaroform__w-full fairystaroform__box-border',
|
|
326
|
+
'fairys-valtio-form-item-body-help fairystaroform__transition-all fairystaroform__duration-300 fairystaroform__text-[10px] fairystaroform__w-full fairystaroform__box-border',
|
|
267
327
|
);
|
|
268
328
|
}, []);
|
|
269
329
|
|
|
270
330
|
/**表单项错误提示类名*/
|
|
271
331
|
const itemError_cls = useMemo(() => {
|
|
272
332
|
return clsx(
|
|
273
|
-
'fairys-valtio-form-item-body-error
|
|
333
|
+
'fairys-valtio-form-item-body-error fairystaroform__transition-all fairystaroform__duration-300 fairystaroform__w-full fairystaroform__flex fairystaroform__flex-row fairystaroform__box-border fairystaroform__text-red fairystaroform__absolute fairystaroform__text-[10px] fairystaroform__z-10',
|
|
274
334
|
{
|
|
275
335
|
'fairystaroform__bottom-[-14px] fairystaroform__left-0 fairystaroform__justify-start':
|
|
276
|
-
errorLayout === 'left
|
|
336
|
+
errorLayout === 'bottom-left',
|
|
277
337
|
'fairystaroform__bottom-[-14px] fairystaroform__right-0 fairystaroform__justify-end':
|
|
278
|
-
errorLayout === 'right
|
|
279
|
-
'fairystaroform__top-[-
|
|
280
|
-
'fairystaroform__top-[-
|
|
338
|
+
errorLayout === 'bottom-right',
|
|
339
|
+
'fairystaroform__top-[-4px] fairystaroform__right-0 fairystaroform__justify-end': errorLayout === 'top-right',
|
|
340
|
+
'fairystaroform__top-[-4px] fairystaroform__left-0 fairystaroform__justify-start': errorLayout === 'top-left',
|
|
341
|
+
/**边框底部提示*/
|
|
342
|
+
'fairystaroform__left-0 fairystaroform__bottom-[-2px] fairystaroform__justify-start':
|
|
343
|
+
errorLayout === 'left-border-top',
|
|
344
|
+
/**边框顶部提示*/
|
|
345
|
+
'fairystaroform__right-0 fairystaroform__bottom-[-2px] fairystaroform__justify-end':
|
|
346
|
+
errorLayout === 'right-border-top',
|
|
281
347
|
},
|
|
282
348
|
);
|
|
283
349
|
}, [errorLayout]);
|
|
@@ -297,7 +363,7 @@ export function useFairysValtioFormItemAttrs<T extends MObject<T> = object>(prop
|
|
|
297
363
|
return {
|
|
298
364
|
value,
|
|
299
365
|
isInvalid,
|
|
300
|
-
|
|
366
|
+
itemBorderType,
|
|
301
367
|
onValueChange,
|
|
302
368
|
colSpan,
|
|
303
369
|
rowSpan,
|
|
@@ -309,14 +375,28 @@ export function useFairysValtioFormItemAttrs<T extends MObject<T> = object>(prop
|
|
|
309
375
|
errorState,
|
|
310
376
|
formInstance,
|
|
311
377
|
error,
|
|
378
|
+
_name,
|
|
379
|
+
name,
|
|
380
|
+
paths,
|
|
381
|
+
parentName,
|
|
382
|
+
formAttrsNameInstance,
|
|
312
383
|
// ================================================================================
|
|
313
384
|
itemClassName: item_cls,
|
|
314
|
-
itemStyle: {
|
|
385
|
+
itemStyle: {
|
|
386
|
+
...(itemBorderColor && itemBorderType === 'bottom' ? { borderBottomColor: itemBorderColor } : {}),
|
|
387
|
+
...(parent_formItemStyle || {}),
|
|
388
|
+
...styleBase,
|
|
389
|
+
...(style || {}),
|
|
390
|
+
},
|
|
315
391
|
containerClassName: itemContainer_cls,
|
|
316
392
|
itemLabelClassName: itemLabel_cls,
|
|
317
393
|
itemLabelStyle: { ...(parent_formItemLabelStyle || {}), ...(labelStyle || {}) },
|
|
318
394
|
itemBodyClassName: itemBody_cls,
|
|
319
|
-
itemBodyStyle: {
|
|
395
|
+
itemBodyStyle: {
|
|
396
|
+
...(itemBorderColor && itemBorderType === 'body' ? { borderBottomColor: itemBorderColor } : {}),
|
|
397
|
+
...(parent_formItemBodyStyle || {}),
|
|
398
|
+
...(bodyStyle || {}),
|
|
399
|
+
},
|
|
320
400
|
itemInputClassName: itemInput_cls,
|
|
321
401
|
itemExtraClassName: itemExtra_cls,
|
|
322
402
|
errorClassName: itemError_cls,
|
|
@@ -329,31 +409,41 @@ export interface FairysValtioFormItemAttrsReturn<T extends MObject<T> = object>
|
|
|
329
409
|
/**表单项值*/
|
|
330
410
|
value?: any;
|
|
331
411
|
/**是否校验错误*/
|
|
332
|
-
isInvalid
|
|
412
|
+
isInvalid: boolean;
|
|
333
413
|
/**边框类型*/
|
|
334
|
-
|
|
414
|
+
itemBorderType: FairysValtioFormLayoutContextOptions['itemBorderType'];
|
|
335
415
|
/**值改变事件*/
|
|
336
|
-
onValueChange
|
|
416
|
+
onValueChange: (event: any) => void;
|
|
337
417
|
/**当前表单项占据列数*/
|
|
338
|
-
colSpan
|
|
418
|
+
colSpan: number;
|
|
339
419
|
/**当前表单项占据行数*/
|
|
340
|
-
rowSpan
|
|
420
|
+
rowSpan: number;
|
|
341
421
|
/**列数*/
|
|
342
|
-
colCount
|
|
422
|
+
colCount: number;
|
|
343
423
|
/**标签显示模式*/
|
|
344
|
-
labelMode
|
|
424
|
+
labelMode: FairysValtioFormLayoutContextOptions['labelMode'];
|
|
345
425
|
/**错误提示位置*/
|
|
346
|
-
errorLayout
|
|
426
|
+
errorLayout: FairysValtioFormLayoutContextOptions['errorLayout'];
|
|
347
427
|
/**是否必填*/
|
|
348
|
-
isRequired
|
|
428
|
+
isRequired: boolean;
|
|
349
429
|
/**表单状态*/
|
|
350
|
-
state
|
|
430
|
+
state: T;
|
|
351
431
|
/**错误状态*/
|
|
352
|
-
errorState
|
|
432
|
+
errorState: Record<PropertyKey, string[]>;
|
|
353
433
|
/**表单实例*/
|
|
354
|
-
formInstance
|
|
434
|
+
formInstance: FairysValtioFormInstance<T>;
|
|
355
435
|
/**错误信息*/
|
|
356
436
|
error?: string[];
|
|
437
|
+
/**拼接父级字段名后得到的表单项名称*/
|
|
438
|
+
_name?: string;
|
|
439
|
+
/**表单项名称*/
|
|
440
|
+
name?: string;
|
|
441
|
+
/**表单项路径*/
|
|
442
|
+
paths?: (string | number)[];
|
|
443
|
+
/**父级字段名*/
|
|
444
|
+
parentName?: string;
|
|
445
|
+
/**表单属性名实例*/
|
|
446
|
+
formAttrsNameInstance: FairysValtioFormParentAttrs;
|
|
357
447
|
// =========================================
|
|
358
448
|
/**表单项类名*/
|
|
359
449
|
itemClassName: string;
|
|
@@ -380,3 +470,97 @@ export interface FairysValtioFormItemAttrsReturn<T extends MObject<T> = object>
|
|
|
380
470
|
/**子元素*/
|
|
381
471
|
children?: React.ReactNode;
|
|
382
472
|
}
|
|
473
|
+
|
|
474
|
+
/**
|
|
475
|
+
* 没有样式的表单项属性,仅返回基础输入组件参数
|
|
476
|
+
*
|
|
477
|
+
* @example
|
|
478
|
+
*
|
|
479
|
+
*```tsx
|
|
480
|
+
import { Fragment } from 'react'
|
|
481
|
+
import { useFairysValtioFormItemAttrs, FairysValtioFormParentAttrsContext } from "@fairys/valtio-form"
|
|
482
|
+
import type { FairysValtioFormItemAttrsProps } from "@fairys/valtio-form"
|
|
483
|
+
export interface FormItemProps extends FairysValtioFormItemAttrsProps{}
|
|
484
|
+
|
|
485
|
+
export const FormItem = (props: FormItemProps) => {
|
|
486
|
+
const { children , formAttrsNameInstance } = useFairysValtioFormItemNoStyleAttrs(props)
|
|
487
|
+
return <FairysValtioFormParentAttrsContext.Provider value={formAttrsNameInstance}>
|
|
488
|
+
{children}
|
|
489
|
+
</FairysValtioFormParentAttrsContext.Provider>
|
|
490
|
+
}
|
|
491
|
+
* ```
|
|
492
|
+
*/
|
|
493
|
+
export function useFairysValtioFormItemNoStyleAttrs<T extends MObject<T> = object>(
|
|
494
|
+
props: FairysValtioFormItemAttrsProps<T>,
|
|
495
|
+
) {
|
|
496
|
+
const {
|
|
497
|
+
name,
|
|
498
|
+
valuePropName = 'value',
|
|
499
|
+
getValueFromEvent,
|
|
500
|
+
formatValue,
|
|
501
|
+
onAfterUpdate,
|
|
502
|
+
trigger = 'onChange',
|
|
503
|
+
children,
|
|
504
|
+
attrs = {},
|
|
505
|
+
isJoinParentField = true,
|
|
506
|
+
rules,
|
|
507
|
+
} = props;
|
|
508
|
+
const [state, errorState, formInstance] = useFairysValtioFormInstanceContextState<T>();
|
|
509
|
+
const {
|
|
510
|
+
name: _name,
|
|
511
|
+
paths,
|
|
512
|
+
parentName,
|
|
513
|
+
formAttrsNameInstance,
|
|
514
|
+
} = useFairysValtioFormAttrsName({ name, isJoinParentField });
|
|
515
|
+
const value = useMemo(() => get(state, paths), [state, paths]);
|
|
516
|
+
const error = errorState[_name];
|
|
517
|
+
formInstance.nameToPaths[_name] = paths;
|
|
518
|
+
/**挂载校验规则*/
|
|
519
|
+
if (Array.isArray(rules) && rules.length) {
|
|
520
|
+
formInstance.mountRules[_name] = rules;
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
useEffect(() => {
|
|
524
|
+
return () => {
|
|
525
|
+
formInstance.removeRules(_name);
|
|
526
|
+
};
|
|
527
|
+
}, [_name]);
|
|
528
|
+
|
|
529
|
+
const onValueChange = (event: any) => {
|
|
530
|
+
let value = event;
|
|
531
|
+
const target = event?.detail || event?.target;
|
|
532
|
+
if (typeof getValueFromEvent === 'function') {
|
|
533
|
+
value = getValueFromEvent(event, formInstance);
|
|
534
|
+
} else if (event && target && typeof target === 'object' && valuePropName in target) {
|
|
535
|
+
value = target.valuePropName;
|
|
536
|
+
}
|
|
537
|
+
if (typeof formatValue === 'function') {
|
|
538
|
+
value = formatValue(value, formInstance, event);
|
|
539
|
+
}
|
|
540
|
+
formInstance.updatedValueByPaths(_name, value);
|
|
541
|
+
if (typeof onAfterUpdate === 'function') {
|
|
542
|
+
onAfterUpdate(value, formInstance, event);
|
|
543
|
+
}
|
|
544
|
+
};
|
|
545
|
+
/**基础组件参数*/
|
|
546
|
+
const baseControl = {
|
|
547
|
+
...attrs,
|
|
548
|
+
name,
|
|
549
|
+
[valuePropName]: value,
|
|
550
|
+
[trigger]: onValueChange,
|
|
551
|
+
};
|
|
552
|
+
return {
|
|
553
|
+
value,
|
|
554
|
+
error,
|
|
555
|
+
onValueChange,
|
|
556
|
+
state,
|
|
557
|
+
errorState,
|
|
558
|
+
formInstance,
|
|
559
|
+
_name,
|
|
560
|
+
name,
|
|
561
|
+
paths,
|
|
562
|
+
parentName,
|
|
563
|
+
formAttrsNameInstance,
|
|
564
|
+
children: React.isValidElement(children) ? React.cloneElement(children, { ...baseControl }) : children,
|
|
565
|
+
};
|
|
566
|
+
}
|
package/src/form/form.tsx
CHANGED
|
@@ -2,14 +2,15 @@ import { MObject } from 'interface';
|
|
|
2
2
|
import { FairysValtioFormInstance, useFairysValtioFormInstance } from './instance';
|
|
3
3
|
import { useMemo, type ReactNode } from 'react';
|
|
4
4
|
import { FairysValtioFormLayoutAttrsProps } from './layout';
|
|
5
|
+
import { RuleItem } from 'async-validator';
|
|
5
6
|
|
|
6
7
|
export interface FairysValtioFormAttrsProps<T extends MObject<T> = object> extends FairysValtioFormLayoutAttrsProps {
|
|
7
8
|
/**表单实例*/
|
|
8
9
|
form?: FairysValtioFormInstance<T>;
|
|
9
10
|
/**子元素*/
|
|
10
11
|
children: ReactNode;
|
|
11
|
-
|
|
12
|
-
rules?:
|
|
12
|
+
/**表单项规则(如果表单项没有指定规则,则使用全局规则,如果表单项指定规则,则使用表单项规则)*/
|
|
13
|
+
rules?: Record<PropertyKey, RuleItem[]>;
|
|
13
14
|
/**表单初始值*/
|
|
14
15
|
formData?: FairysValtioFormInstance<T>['state'];
|
|
15
16
|
/**表单隐藏状态*/
|
|
@@ -49,20 +50,4 @@ export function useFairysValtioForm<T extends MObject<T> = object>(props: Fairys
|
|
|
49
50
|
...rest,
|
|
50
51
|
formInstance,
|
|
51
52
|
};
|
|
52
|
-
// return (
|
|
53
|
-
// <FairysValtioFormInstanceContext.Provider value={formInstance}>
|
|
54
|
-
// <FairysValtioFormLayout {...rest}>{children}</FairysValtioFormLayout>
|
|
55
|
-
// </FairysValtioFormInstanceContext.Provider>
|
|
56
|
-
// );
|
|
57
53
|
}
|
|
58
|
-
|
|
59
|
-
// /**初始化实例*/
|
|
60
|
-
// FairysValtioForm.useForm = useFairysValtioFormInstance;
|
|
61
|
-
// /**获取状态*/
|
|
62
|
-
// FairysValtioForm.useFormState = useFairysValtioFormInstanceContextState;
|
|
63
|
-
// /**获取隐藏状态*/
|
|
64
|
-
// FairysValtioForm.useFormHideState = useFairysValtioFormInstanceContextHideState;
|
|
65
|
-
// /**获取上下文实例*/
|
|
66
|
-
// FairysValtioForm.useFormInstance = useFairysValtioFormInstanceContext;
|
|
67
|
-
// /**表单项*/
|
|
68
|
-
// FairysValtioForm.useFormItemAttrs = useFairysValtioFormItemAttrs;
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { useRef, createContext, useContext, useMemo } from 'react';
|
|
2
|
+
import { proxy, useSnapshot } from 'valtio';
|
|
3
|
+
import { formatePath, formateName } from 'form/utils';
|
|
4
|
+
export interface FairysValtioFormParentAttrsState {
|
|
5
|
+
name?: string;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
/***
|
|
9
|
+
* 父级属性
|
|
10
|
+
*/
|
|
11
|
+
export class FairysValtioFormParentAttrs {
|
|
12
|
+
state = proxy<FairysValtioFormParentAttrsState>({
|
|
13
|
+
name: '',
|
|
14
|
+
});
|
|
15
|
+
// ===================================================更新状态================================================================
|
|
16
|
+
updated = (attrs: Record<string, any>) => {
|
|
17
|
+
this.state = { ...this.state, ...attrs };
|
|
18
|
+
};
|
|
19
|
+
/***更新父级字段值*/
|
|
20
|
+
updatedName = (name?: string, parentName?: string) => {
|
|
21
|
+
this.state.name = formateName(name, parentName);
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**初始化父级属性*/
|
|
26
|
+
export const useFairysValtioFormParentAttrs = (instance?: FairysValtioFormParentAttrs) => {
|
|
27
|
+
const parentAttrs = useRef<FairysValtioFormParentAttrs>();
|
|
28
|
+
if (!parentAttrs.current) {
|
|
29
|
+
if (instance) {
|
|
30
|
+
parentAttrs.current = instance;
|
|
31
|
+
} else {
|
|
32
|
+
parentAttrs.current = new FairysValtioFormParentAttrs();
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
return parentAttrs.current;
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
/***父级属性上下文*/
|
|
39
|
+
export const FairysValtioFormParentAttrsContext = createContext<FairysValtioFormParentAttrs>(
|
|
40
|
+
new FairysValtioFormParentAttrs(),
|
|
41
|
+
);
|
|
42
|
+
|
|
43
|
+
/***获取父级属性实例*/
|
|
44
|
+
export const useFairysValtioFormParentAttrsContext = () => useContext(FairysValtioFormParentAttrsContext);
|
|
45
|
+
|
|
46
|
+
/***获取父级属性状态*/
|
|
47
|
+
export const useFairysValtioFormParentAttrsState = () => {
|
|
48
|
+
const instance = useFairysValtioFormParentAttrsContext();
|
|
49
|
+
const state = useSnapshot(instance.state);
|
|
50
|
+
return [state, instance] as const;
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
export interface FairysValtioFormAttrsNameOptions {
|
|
54
|
+
name?: string;
|
|
55
|
+
/**是否拼接父级字段名*/
|
|
56
|
+
isJoinParentField?: boolean;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/***获取属性名和路径*/
|
|
60
|
+
export const useFairysValtioFormAttrsName = (options: FairysValtioFormAttrsNameOptions = {}) => {
|
|
61
|
+
const { name, isJoinParentField = true } = options;
|
|
62
|
+
const formAttrsNameInstance = useFairysValtioFormParentAttrs();
|
|
63
|
+
const [state] = useFairysValtioFormParentAttrsState();
|
|
64
|
+
const parentName = state.name;
|
|
65
|
+
const _name = useMemo(
|
|
66
|
+
() => (isJoinParentField ? formateName(name, parentName) : name),
|
|
67
|
+
[name, parentName, isJoinParentField],
|
|
68
|
+
);
|
|
69
|
+
const _paths = useMemo(() => formatePath(_name), [_name]);
|
|
70
|
+
useMemo(() => formAttrsNameInstance.updatedName(_name), [_name]);
|
|
71
|
+
|
|
72
|
+
return {
|
|
73
|
+
formAttrsNameInstance,
|
|
74
|
+
parentName,
|
|
75
|
+
name: _name,
|
|
76
|
+
paths: _paths,
|
|
77
|
+
};
|
|
78
|
+
};
|