@fairys/valtio-form-basic 0.0.13 → 1.0.1
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 +933 -2
- package/esm/common/instance/index.d.ts +25 -5
- package/esm/common/instance/index.js +33 -13
- package/esm/common/utils/index.d.ts +6 -0
- package/esm/common/utils/index.js +10 -1
- package/esm/form/form.d.ts +8 -32
- package/esm/form/form.item.d.ts +35 -13
- package/esm/form/form.item.js +27 -2
- package/esm/form/form.js +2 -1
- package/lib/common/instance/index.d.ts +25 -5
- package/lib/common/instance/index.js +42 -16
- package/lib/common/utils/index.d.ts +6 -0
- package/lib/common/utils/index.js +12 -0
- package/lib/form/form.d.ts +8 -32
- package/lib/form/form.item.d.ts +35 -13
- package/lib/form/form.item.js +27 -2
- package/lib/form/form.js +2 -1
- package/package.json +1 -1
- package/src/common/instance/index.ts +69 -18
- package/src/common/utils/index.ts +19 -0
- package/src/form/form.item.tsx +88 -5
- package/src/form/form.tsx +17 -3
package/lib/form/form.d.ts
CHANGED
|
@@ -3,7 +3,7 @@ import { FairysValtioFormInstance } from '../common/instance';
|
|
|
3
3
|
import { type ReactNode } from 'react';
|
|
4
4
|
import { FairysValtioFormLayoutAttrsProps } from './layout';
|
|
5
5
|
import { RuleItem } from 'async-validator';
|
|
6
|
-
export interface FairysValtioFormAttrsProps<T extends MObject<T> =
|
|
6
|
+
export interface FairysValtioFormAttrsProps<T extends MObject<T> = Record<string, any>> extends FairysValtioFormLayoutAttrsProps {
|
|
7
7
|
/**表单实例*/
|
|
8
8
|
form?: FairysValtioFormInstance<T>;
|
|
9
9
|
/**子元素*/
|
|
@@ -20,6 +20,12 @@ export interface FairysValtioFormAttrsProps<T extends MObject<T> = object> exten
|
|
|
20
20
|
* - immutable:直接使用对象(注意:当传递的不是`valtio`的`proxy`对象时,会使用`valtio`中的`proxy`声明)
|
|
21
21
|
*/
|
|
22
22
|
initFormDataType?: 'deepCopy' | 'immutable';
|
|
23
|
+
/**
|
|
24
|
+
* 表单值改变时回调
|
|
25
|
+
* @param path 表单项路径
|
|
26
|
+
* @param value 表单项值
|
|
27
|
+
*/
|
|
28
|
+
onValuesChange?: (path: PropertyKey, value: any) => void;
|
|
23
29
|
}
|
|
24
30
|
/**
|
|
25
31
|
* 表单属性处理
|
|
@@ -41,36 +47,6 @@ export const Form = (props: FormProps) => {
|
|
|
41
47
|
}
|
|
42
48
|
* ```
|
|
43
49
|
*/
|
|
44
|
-
export declare function useFairysValtioForm<T extends MObject<T> =
|
|
50
|
+
export declare function useFairysValtioForm<T extends MObject<T> = Record<string, any>>(props: FairysValtioFormAttrsProps<T>, ref: React.Ref<FairysValtioFormInstance<T>>): Omit<FairysValtioFormAttrsProps<T>, "initFormDataType" | "form" | "rules" | "formData" | "hideState" | "onValuesChange"> & {
|
|
45
51
|
formInstance: FairysValtioFormInstance<T>;
|
|
46
|
-
/**子元素*/
|
|
47
|
-
children: ReactNode;
|
|
48
|
-
gap?: string | number;
|
|
49
|
-
title?: React.ReactNode;
|
|
50
|
-
extra?: React.ReactNode;
|
|
51
|
-
isAllColSpan?: boolean;
|
|
52
|
-
className?: string;
|
|
53
|
-
style?: React.CSSProperties;
|
|
54
|
-
headerClassName?: string;
|
|
55
|
-
headerStyle?: React.CSSProperties;
|
|
56
|
-
bodyClassName?: string;
|
|
57
|
-
bodyStyle?: React.CSSProperties;
|
|
58
|
-
bordered?: boolean;
|
|
59
|
-
boxShadow?: boolean;
|
|
60
|
-
lastItemBordered?: boolean;
|
|
61
|
-
platform?: "pc" | "rn" | "taro";
|
|
62
|
-
colCount?: number;
|
|
63
|
-
errorLayout?: "bottom-left" | "bottom-right" | "top-right" | "top-left" | "left-border-top" | "right-border-top";
|
|
64
|
-
labelMode?: "left" | "top" | "between";
|
|
65
|
-
formItemClassName?: string;
|
|
66
|
-
formItemStyle?: React.CSSProperties;
|
|
67
|
-
formItemLabelClassName?: string;
|
|
68
|
-
formItemLabelStyle?: React.CSSProperties;
|
|
69
|
-
formItemBodyClassName?: string;
|
|
70
|
-
formItemBodyStyle?: React.CSSProperties;
|
|
71
|
-
itemBorderType?: "bottom" | "body" | "none";
|
|
72
|
-
itemBorderColor?: React.CSSProperties["borderColor"];
|
|
73
|
-
isInvalidBorderRed?: boolean;
|
|
74
|
-
isInvalidTextRed?: boolean;
|
|
75
|
-
showColon?: boolean;
|
|
76
52
|
};
|
package/lib/form/form.item.d.ts
CHANGED
|
@@ -5,7 +5,7 @@ import { FairysValtioFormInstance } from '../common/instance';
|
|
|
5
5
|
import { FairysValtioFormLayoutContextOptions } from './layout';
|
|
6
6
|
import { FairysValtioFormParentAttrs } from '../common/hooks';
|
|
7
7
|
import { RuleItem } from 'async-validator';
|
|
8
|
-
export interface FairysValtioFormItemAttrsProps<T extends MObject<T> =
|
|
8
|
+
export interface FairysValtioFormItemAttrsProps<T extends MObject<T> = Record<string, any>> {
|
|
9
9
|
/**平台*/
|
|
10
10
|
platform?: 'pc' | 'rn' | 'taro';
|
|
11
11
|
/**
|
|
@@ -77,6 +77,10 @@ export interface FairysValtioFormItemAttrsProps<T extends MObject<T> = object> {
|
|
|
77
77
|
isJoinParentField?: boolean;
|
|
78
78
|
/**校验规则*/
|
|
79
79
|
rules?: RuleItem[];
|
|
80
|
+
/**卸载移除数据值
|
|
81
|
+
* @default true
|
|
82
|
+
*/
|
|
83
|
+
isRemoveValueOnUnmount?: boolean;
|
|
80
84
|
}
|
|
81
85
|
/**
|
|
82
86
|
* 处理表单表单项属性
|
|
@@ -121,8 +125,8 @@ export const FormItem = (props: FormItemProps) => {
|
|
|
121
125
|
* ```
|
|
122
126
|
*
|
|
123
127
|
*/
|
|
124
|
-
export declare function useFairysValtioFormItemAttrs<T extends MObject<T> =
|
|
125
|
-
export interface FairysValtioFormItemAttrsReturn<T extends MObject<T> =
|
|
128
|
+
export declare function useFairysValtioFormItemAttrs<T extends MObject<T> = Record<string, any>>(props: FairysValtioFormItemAttrsProps<T>): FairysValtioFormItemAttrsReturn<T>;
|
|
129
|
+
export interface FairysValtioFormItemAttrsReturn<T extends MObject<T> = Record<string, any>> {
|
|
126
130
|
/**表单项值*/
|
|
127
131
|
value?: any;
|
|
128
132
|
/**是否校验错误*/
|
|
@@ -207,18 +211,36 @@ export const FormItem = (props: FormItemProps) => {
|
|
|
207
211
|
}
|
|
208
212
|
* ```
|
|
209
213
|
*/
|
|
210
|
-
export declare function useFairysValtioFormItemNoStyleAttrs<T extends MObject<T> =
|
|
211
|
-
|
|
212
|
-
|
|
214
|
+
export declare function useFairysValtioFormItemNoStyleAttrs<T extends MObject<T> = Record<string, any>>(props: FairysValtioFormItemAttrsProps<T>): FairysValtioFormItemNoStyleAttrsReturn<T>;
|
|
215
|
+
export interface FairysValtioFormItemNoStyleAttrsReturn<T extends MObject<T> = Record<string, any>> {
|
|
216
|
+
/**表单项值*/
|
|
217
|
+
value?: any;
|
|
218
|
+
/**是否校验错误*/
|
|
219
|
+
isInvalid: boolean;
|
|
220
|
+
/**是否必填*/
|
|
221
|
+
isRequired: boolean;
|
|
222
|
+
/**错误信息*/
|
|
223
|
+
error?: string[];
|
|
224
|
+
/**值改变事件*/
|
|
213
225
|
onValueChange: (event: any) => void;
|
|
226
|
+
/**表单状态*/
|
|
214
227
|
state: T;
|
|
228
|
+
/**错误状态*/
|
|
215
229
|
errorState: Record<PropertyKey, string[]>;
|
|
230
|
+
/**表单实例*/
|
|
216
231
|
formInstance: FairysValtioFormInstance<T>;
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
232
|
+
/**拼接父级字段名后得到的表单项名称*/
|
|
233
|
+
_name?: string;
|
|
234
|
+
/**表单项名称*/
|
|
235
|
+
name?: string;
|
|
236
|
+
/**表单项ID*/
|
|
237
|
+
id?: string;
|
|
238
|
+
/**表单项路径*/
|
|
239
|
+
paths?: (string | number)[];
|
|
240
|
+
/**父级字段名*/
|
|
241
|
+
parentName?: string;
|
|
242
|
+
/**表单属性名实例*/
|
|
222
243
|
formAttrsNameInstance: FairysValtioFormParentAttrs;
|
|
223
|
-
|
|
224
|
-
|
|
244
|
+
/**子元素*/
|
|
245
|
+
children?: React.ReactNode;
|
|
246
|
+
}
|
package/lib/form/form.item.js
CHANGED
|
@@ -61,7 +61,7 @@ function useFairysValtioFormItemAttrs(props) {
|
|
|
61
61
|
const parent_isInvalidTextRed = layoutAttrs.isInvalidTextRed;
|
|
62
62
|
const parent_showColon = layoutAttrs.showColon;
|
|
63
63
|
const parent_platform = layoutAttrs.platform;
|
|
64
|
-
const { name, valuePropName = 'value', getValuePath = valuePropName, getValueFromEvent, formatValue, onAfterUpdate, trigger = 'onChange', className, style, labelClassName, labelStyle, bodyClassName, bodyStyle, children, labelMode = parent_labelMode, errorLayout = parent_errorLayout, colSpan = 1, rowSpan = 1, isRequired: _isRequired, itemBorderType = parent_borderedType, attrs = {}, showColon = parent_showColon, itemBorderColor = parent_itemBorderColor, isInvalidBorderRed = parent_isInvalidBorderRed, isInvalidTextRed = parent_isInvalidTextRed, isJoinParentField = true, rules, platform = parent_platform } = props;
|
|
64
|
+
const { name, valuePropName = 'value', getValuePath = valuePropName, getValueFromEvent, formatValue, onAfterUpdate, trigger = 'onChange', className, style, labelClassName, labelStyle, bodyClassName, bodyStyle, children, labelMode = parent_labelMode, errorLayout = parent_errorLayout, colSpan = 1, rowSpan = 1, isRequired: _isRequired, itemBorderType = parent_borderedType, attrs = {}, showColon = parent_showColon, itemBorderColor = parent_itemBorderColor, isInvalidBorderRed = parent_isInvalidBorderRed, isInvalidTextRed = parent_isInvalidTextRed, isJoinParentField = true, rules, platform = parent_platform, isRemoveValueOnUnmount = true } = props;
|
|
65
65
|
const { name: _name, paths, parentName, formAttrsNameInstance } = (0, hooks_index_js_namespaceObject.useFairysValtioFormAttrsName)({
|
|
66
66
|
name,
|
|
67
67
|
isJoinParentField
|
|
@@ -94,6 +94,9 @@ function useFairysValtioFormItemAttrs(props) {
|
|
|
94
94
|
formInstance.updatedValueByPaths(_name, _value);
|
|
95
95
|
if ('function' == typeof onAfterUpdate) onAfterUpdate(_value, formInstance, event);
|
|
96
96
|
};
|
|
97
|
+
(0, external_react_namespaceObject.useEffect)(()=>()=>{
|
|
98
|
+
if (isRemoveValueOnUnmount) formInstance.removeValueByPaths(_name);
|
|
99
|
+
}, []);
|
|
97
100
|
const baseControl = {
|
|
98
101
|
...attrs,
|
|
99
102
|
name,
|
|
@@ -253,7 +256,7 @@ function useFairysValtioFormItemAttrs(props) {
|
|
|
253
256
|
};
|
|
254
257
|
}
|
|
255
258
|
function useFairysValtioFormItemNoStyleAttrs(props) {
|
|
256
|
-
const { name, valuePropName = 'value', getValuePath = valuePropName, getValueFromEvent, formatValue, onAfterUpdate, trigger = 'onChange', children, attrs = {}, isJoinParentField = true, rules } = props;
|
|
259
|
+
const { name, valuePropName = 'value', getValuePath = valuePropName, getValueFromEvent, formatValue, onAfterUpdate, trigger = 'onChange', children, attrs = {}, isJoinParentField = true, rules, isRemoveValueOnUnmount = true, isRequired: _isRequired } = props;
|
|
257
260
|
const [state, errorState, formInstance] = (0, index_js_namespaceObject.useFairysValtioFormInstanceContextState)();
|
|
258
261
|
const { name: _name, paths, parentName, formAttrsNameInstance } = (0, hooks_index_js_namespaceObject.useFairysValtioFormAttrsName)({
|
|
259
262
|
name,
|
|
@@ -266,6 +269,7 @@ function useFairysValtioFormItemNoStyleAttrs(props) {
|
|
|
266
269
|
]);
|
|
267
270
|
const error = errorState[_name];
|
|
268
271
|
formInstance.nameToPaths[_name] = paths;
|
|
272
|
+
const _formItemRules = formInstance.rules?.[_name];
|
|
269
273
|
(0, external_react_namespaceObject.useEffect)(()=>{
|
|
270
274
|
if (Array.isArray(rules) && rules.length) formInstance.mountRules[_name] = rules;
|
|
271
275
|
return ()=>{
|
|
@@ -285,6 +289,9 @@ function useFairysValtioFormItemNoStyleAttrs(props) {
|
|
|
285
289
|
formInstance.updatedValueByPaths(_name, _value);
|
|
286
290
|
if ('function' == typeof onAfterUpdate) onAfterUpdate(_value, formInstance, event);
|
|
287
291
|
};
|
|
292
|
+
(0, external_react_namespaceObject.useEffect)(()=>()=>{
|
|
293
|
+
if (isRemoveValueOnUnmount) formInstance.removeValueByPaths(_name);
|
|
294
|
+
}, []);
|
|
288
295
|
const baseControl = {
|
|
289
296
|
...attrs,
|
|
290
297
|
name,
|
|
@@ -292,8 +299,26 @@ function useFairysValtioFormItemNoStyleAttrs(props) {
|
|
|
292
299
|
[valuePropName]: value,
|
|
293
300
|
[trigger]: onValueChange
|
|
294
301
|
};
|
|
302
|
+
const isRequired = (0, external_react_namespaceObject.useMemo)(()=>{
|
|
303
|
+
if (_isRequired) return _isRequired;
|
|
304
|
+
if (Array.isArray(rules) && rules.length) return rules.some((rule)=>rule.required);
|
|
305
|
+
if (_formItemRules && Array.isArray(_formItemRules) && _formItemRules.length) return _formItemRules.some((rule)=>rule.required);
|
|
306
|
+
return false;
|
|
307
|
+
}, [
|
|
308
|
+
rules,
|
|
309
|
+
formInstance,
|
|
310
|
+
_formItemRules
|
|
311
|
+
]);
|
|
312
|
+
const isInvalid = (0, external_react_namespaceObject.useMemo)(()=>{
|
|
313
|
+
if (Array.isArray(error) && error.length) return true;
|
|
314
|
+
return false;
|
|
315
|
+
}, [
|
|
316
|
+
error
|
|
317
|
+
]);
|
|
295
318
|
return {
|
|
296
319
|
value,
|
|
320
|
+
isInvalid,
|
|
321
|
+
isRequired,
|
|
297
322
|
error,
|
|
298
323
|
onValueChange,
|
|
299
324
|
state,
|
package/lib/form/form.js
CHANGED
|
@@ -29,9 +29,10 @@ __webpack_require__.d(__webpack_exports__, {
|
|
|
29
29
|
const index_js_namespaceObject = require("../common/instance/index.js");
|
|
30
30
|
const external_react_namespaceObject = require("react");
|
|
31
31
|
function useFairysValtioForm(props, ref) {
|
|
32
|
-
const { form, rules, formData, hideState, initFormDataType = 'deepCopy', ...rest } = props;
|
|
32
|
+
const { form, rules, formData, hideState, initFormDataType = 'deepCopy', onValuesChange, ...rest } = props;
|
|
33
33
|
const formInstance = (0, index_js_namespaceObject.useFairysValtioFormInstance)(form);
|
|
34
34
|
formInstance.rules = rules;
|
|
35
|
+
formInstance.onValuesChange = onValuesChange;
|
|
35
36
|
(0, external_react_namespaceObject.useMemo)(()=>formInstance.ctor({
|
|
36
37
|
formData,
|
|
37
38
|
hideState,
|
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"author": "SunLxy <1011771396@qq.com>",
|
|
4
4
|
"description": "使用 valtio 实现的表单基础库, 使其更加便捷,同时支持`PC`、`H5`、`Taro`,同时也更加灵活。",
|
|
5
5
|
"homepage": "https://github.com/autumn-fairy-tales/valtio-form-basic",
|
|
6
|
-
"version": "
|
|
6
|
+
"version": "1.0.1",
|
|
7
7
|
"main": "lib/index.js",
|
|
8
8
|
"types": "esm/index.d.ts",
|
|
9
9
|
"module": "esm/index.js",
|
|
@@ -3,11 +3,17 @@ import { createContext, useContext, useRef } from 'react';
|
|
|
3
3
|
import { proxy, ref, snapshot, useSnapshot, unstable_getInternalStates } from 'valtio';
|
|
4
4
|
import AsyncValidator, { RuleItem, ValidateFieldsError, Values } from 'async-validator';
|
|
5
5
|
import { copy } from 'fast-copy';
|
|
6
|
-
import { formatePath, get, set, isObject } from 'common/utils';
|
|
6
|
+
import { formatePath, get, set, isObject, removeValueByPaths } from 'common/utils';
|
|
7
7
|
import { FairysValtioFormAttrsProps } from 'form/form';
|
|
8
8
|
|
|
9
9
|
/**表单实例*/
|
|
10
10
|
export class FairysValtioFormInstance<T extends MObject<T> = Record<string, any>> {
|
|
11
|
+
/**
|
|
12
|
+
* 表单值改变时回调
|
|
13
|
+
* @param path 表单项路径
|
|
14
|
+
* @param value 表单项值
|
|
15
|
+
*/
|
|
16
|
+
onValuesChange?: (path: PropertyKey, value: any) => void;
|
|
11
17
|
/***
|
|
12
18
|
* 判断值是否为代理对象
|
|
13
19
|
* @param value 值
|
|
@@ -46,25 +52,26 @@ export class FairysValtioFormInstance<T extends MObject<T> = Record<string, any>
|
|
|
46
52
|
initFormDataType?: FairysValtioFormAttrsProps['initFormDataType'];
|
|
47
53
|
}) => {
|
|
48
54
|
const { formData, hideState, initFormDataType = 'deepCopy' } = options || {};
|
|
49
|
-
this.
|
|
50
|
-
this.
|
|
51
|
-
// 如果是 isProxy,则直接赋值
|
|
52
|
-
this.errorState = proxy<Record<PropertyKey, string[]>>({});
|
|
53
|
-
this.hideState = proxy<Record<PropertyKey, boolean>>(hideState ? copy(hideState) : {});
|
|
55
|
+
this.clear();
|
|
56
|
+
this.updatedHideInfo(hideState ? copy(hideState) : {});
|
|
54
57
|
// 判断是否是代理对象
|
|
55
58
|
const isValtioProxy = this.isValtioProxy(formData);
|
|
56
59
|
if (isValtioProxy) {
|
|
57
60
|
if (initFormDataType === 'deepCopy') {
|
|
58
|
-
this.state = proxy(copy(snapshot(formData)) as T);
|
|
61
|
+
// this.state = proxy(copy(snapshot(formData)) as T);
|
|
62
|
+
this.updated(copy(snapshot(formData)) as T, false);
|
|
59
63
|
} else {
|
|
60
|
-
this.state = formData as T;
|
|
64
|
+
// this.state = formData as T;
|
|
65
|
+
this.updated(formData as T, false);
|
|
61
66
|
}
|
|
62
67
|
} else {
|
|
63
68
|
if (initFormDataType === 'deepCopy') {
|
|
64
|
-
this.state = proxy(copy(formData || {}) as T);
|
|
69
|
+
// this.state = proxy(copy(formData || {}) as T);
|
|
70
|
+
this.updated(copy(formData || {}) as T, false);
|
|
65
71
|
}
|
|
66
72
|
{
|
|
67
|
-
this.state = proxy((formData || {}) as T);
|
|
73
|
+
// this.state = proxy((formData || {}) as T);
|
|
74
|
+
this.updated((formData || {}) as T, false);
|
|
68
75
|
}
|
|
69
76
|
}
|
|
70
77
|
};
|
|
@@ -91,7 +98,28 @@ export class FairysValtioFormInstance<T extends MObject<T> = Record<string, any>
|
|
|
91
98
|
updatedValueByPaths = (path: PropertyKey, value: any) => {
|
|
92
99
|
set(this.state, formatePath(path), value);
|
|
93
100
|
this.validate([path], false);
|
|
101
|
+
this.onValuesChange?.(path, value);
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
/**表单项卸载移除保存值*/
|
|
105
|
+
removeValueByPaths = (path: PropertyKey) => {
|
|
106
|
+
removeValueByPaths(this.state, formatePath(path));
|
|
94
107
|
};
|
|
108
|
+
/**
|
|
109
|
+
* 清理值
|
|
110
|
+
*/
|
|
111
|
+
clearValue = (fields?: PropertyKey[]) => {
|
|
112
|
+
let _fields = fields;
|
|
113
|
+
if (!Array.isArray(fields)) {
|
|
114
|
+
_fields = Object.keys(this.state) as PropertyKey[];
|
|
115
|
+
}
|
|
116
|
+
for (let index = 0; index < _fields.length; index++) {
|
|
117
|
+
const field = _fields[index];
|
|
118
|
+
delete this.state[field];
|
|
119
|
+
}
|
|
120
|
+
return this;
|
|
121
|
+
};
|
|
122
|
+
|
|
95
123
|
// ===================================================隐藏状态================================================================
|
|
96
124
|
/**
|
|
97
125
|
* 更新行数据的隐藏信息
|
|
@@ -154,9 +182,9 @@ export class FairysValtioFormInstance<T extends MObject<T> = Record<string, any>
|
|
|
154
182
|
* 清理所有数据
|
|
155
183
|
*/
|
|
156
184
|
clear = () => {
|
|
157
|
-
this.
|
|
158
|
-
this.
|
|
159
|
-
this.
|
|
185
|
+
this.clearValue();
|
|
186
|
+
this.clearHideInfo();
|
|
187
|
+
this.clearErrorInfo();
|
|
160
188
|
this.mountRules = {}; //由表单项挂载规则,(根据表单项的字段存储路径对应校验规则)
|
|
161
189
|
this.rules = {}; //表单项规则
|
|
162
190
|
this.nameToPaths = {}; //表单项名称到路径映射
|
|
@@ -177,7 +205,10 @@ export class FairysValtioFormInstance<T extends MObject<T> = Record<string, any>
|
|
|
177
205
|
* @param fields 要验证的字段(可选)
|
|
178
206
|
* @param isReturn 是否返回验证结果(可选)
|
|
179
207
|
*/
|
|
180
|
-
validate = async (
|
|
208
|
+
validate = async (
|
|
209
|
+
fields?: PropertyKey[],
|
|
210
|
+
isReturn: boolean = true,
|
|
211
|
+
): Promise<ValidateFieldsError | Values | Partial<T>> => {
|
|
181
212
|
const rules = {
|
|
182
213
|
...this.rules,
|
|
183
214
|
...this.mountRules,
|
|
@@ -251,7 +282,9 @@ export class FairysValtioFormInstance<T extends MObject<T> = Record<string, any>
|
|
|
251
282
|
}
|
|
252
283
|
|
|
253
284
|
/**声明实例*/
|
|
254
|
-
export function useFairysValtioFormInstance<T extends MObject<T> =
|
|
285
|
+
export function useFairysValtioFormInstance<T extends MObject<T> = Record<string, any>>(
|
|
286
|
+
instance?: FairysValtioFormInstance<T>,
|
|
287
|
+
) {
|
|
255
288
|
const ref = useRef<FairysValtioFormInstance<T>>();
|
|
256
289
|
if (!ref.current) {
|
|
257
290
|
if (instance) {
|
|
@@ -269,12 +302,12 @@ export const FairysValtioFormInstanceContext = createContext<FairysValtioFormIns
|
|
|
269
302
|
);
|
|
270
303
|
|
|
271
304
|
/**表单实例上下文*/
|
|
272
|
-
export function useFairysValtioFormInstanceContext<T extends MObject<T> =
|
|
305
|
+
export function useFairysValtioFormInstanceContext<T extends MObject<T> = Record<string, any>>() {
|
|
273
306
|
return useContext(FairysValtioFormInstanceContext) as FairysValtioFormInstance<T>;
|
|
274
307
|
}
|
|
275
308
|
|
|
276
309
|
/**状态取值*/
|
|
277
|
-
export function useFairysValtioFormInstanceContextState<T extends MObject<T> =
|
|
310
|
+
export function useFairysValtioFormInstanceContextState<T extends MObject<T> = Record<string, any>>() {
|
|
278
311
|
const instance = useFairysValtioFormInstanceContext<T>();
|
|
279
312
|
const state = useSnapshot(instance.state) as T;
|
|
280
313
|
const errorState = useSnapshot(instance.errorState) as Record<PropertyKey, string[]>;
|
|
@@ -288,7 +321,7 @@ export function useFairysValtioFormInstanceContextState<T extends MObject<T> = o
|
|
|
288
321
|
}
|
|
289
322
|
|
|
290
323
|
/**隐藏组件状态取值*/
|
|
291
|
-
export function useFairysValtioFormInstanceContextHideState<T extends MObject<T> =
|
|
324
|
+
export function useFairysValtioFormInstanceContextHideState<T extends MObject<T> = Record<string, any>>() {
|
|
292
325
|
const instance = useFairysValtioFormInstanceContext<T>();
|
|
293
326
|
const hideState = useSnapshot(instance.hideState) as Record<PropertyKey, boolean>;
|
|
294
327
|
return [hideState, instance, (hideState as any).__defaultValue] as [
|
|
@@ -297,3 +330,21 @@ export function useFairysValtioFormInstanceContextHideState<T extends MObject<T>
|
|
|
297
330
|
any,
|
|
298
331
|
];
|
|
299
332
|
}
|
|
333
|
+
/**
|
|
334
|
+
* 传递表单实例获取状态
|
|
335
|
+
*/
|
|
336
|
+
export function useFairysValtioFormInstanceToState<T extends MObject<T> = Record<string, any>>(
|
|
337
|
+
formInstance: FairysValtioFormInstance<T>,
|
|
338
|
+
) {
|
|
339
|
+
const state = useSnapshot(formInstance.state) as T;
|
|
340
|
+
return state as T;
|
|
341
|
+
}
|
|
342
|
+
/**
|
|
343
|
+
* 传递表单实例获取隐藏状态
|
|
344
|
+
*/
|
|
345
|
+
export function useFairysValtioFormInstanceToHideState<T extends MObject<T> = Record<string, any>>(
|
|
346
|
+
formInstance: FairysValtioFormInstance<T>,
|
|
347
|
+
) {
|
|
348
|
+
const hideState = useSnapshot(formInstance.hideState) as Record<PropertyKey, boolean>;
|
|
349
|
+
return hideState as Record<PropertyKey, boolean>;
|
|
350
|
+
}
|
|
@@ -50,6 +50,25 @@ export function get<TDefault = unknown>(value: any, segments: PropertyKey[]): TD
|
|
|
50
50
|
return current;
|
|
51
51
|
}
|
|
52
52
|
|
|
53
|
+
/***
|
|
54
|
+
* 移除值
|
|
55
|
+
* @param value 任意值
|
|
56
|
+
* @param segments 键路径
|
|
57
|
+
*/
|
|
58
|
+
export function removeValueByPaths(value: any, segments: PropertyKey[]) {
|
|
59
|
+
// 移除字段
|
|
60
|
+
let current: any = value;
|
|
61
|
+
const lg = segments.length;
|
|
62
|
+
for (let index = 0; index < lg; index++) {
|
|
63
|
+
const key = segments[index];
|
|
64
|
+
if (index === lg - 1) {
|
|
65
|
+
delete current[key];
|
|
66
|
+
} else {
|
|
67
|
+
current = current?.[key];
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
53
72
|
/***
|
|
54
73
|
* 格式化路径,将路径中的数组索引转换为数字
|
|
55
74
|
* @param path 路径
|
package/src/form/form.item.tsx
CHANGED
|
@@ -9,7 +9,7 @@ import { FairysValtioFormParentAttrs, useFairysValtioFormAttrsName, useId } from
|
|
|
9
9
|
import { formatePath, get } from 'common/utils';
|
|
10
10
|
import { RuleItem } from 'async-validator';
|
|
11
11
|
|
|
12
|
-
export interface FairysValtioFormItemAttrsProps<T extends MObject<T> =
|
|
12
|
+
export interface FairysValtioFormItemAttrsProps<T extends MObject<T> = Record<string, any>> {
|
|
13
13
|
/**平台*/
|
|
14
14
|
platform?: 'pc' | 'rn' | 'taro';
|
|
15
15
|
/**
|
|
@@ -81,6 +81,10 @@ export interface FairysValtioFormItemAttrsProps<T extends MObject<T> = object> {
|
|
|
81
81
|
isJoinParentField?: boolean;
|
|
82
82
|
/**校验规则*/
|
|
83
83
|
rules?: RuleItem[];
|
|
84
|
+
/**卸载移除数据值
|
|
85
|
+
* @default true
|
|
86
|
+
*/
|
|
87
|
+
isRemoveValueOnUnmount?: boolean;
|
|
84
88
|
}
|
|
85
89
|
|
|
86
90
|
/**
|
|
@@ -126,7 +130,9 @@ export const FormItem = (props: FormItemProps) => {
|
|
|
126
130
|
* ```
|
|
127
131
|
*
|
|
128
132
|
*/
|
|
129
|
-
export function useFairysValtioFormItemAttrs<T extends MObject<T> =
|
|
133
|
+
export function useFairysValtioFormItemAttrs<T extends MObject<T> = Record<string, any>>(
|
|
134
|
+
props: FairysValtioFormItemAttrsProps<T>,
|
|
135
|
+
) {
|
|
130
136
|
const [layoutAttrs] = useFairysValtioFormLayoutContext();
|
|
131
137
|
const colCount = layoutAttrs.colCount || 1;
|
|
132
138
|
const parent_borderedType = layoutAttrs.itemBorderType || 'bottom';
|
|
@@ -173,6 +179,7 @@ export function useFairysValtioFormItemAttrs<T extends MObject<T> = object>(prop
|
|
|
173
179
|
isJoinParentField = true,
|
|
174
180
|
rules,
|
|
175
181
|
platform = parent_platform,
|
|
182
|
+
isRemoveValueOnUnmount = true,
|
|
176
183
|
} = props;
|
|
177
184
|
|
|
178
185
|
const {
|
|
@@ -217,6 +224,14 @@ export function useFairysValtioFormItemAttrs<T extends MObject<T> = object>(prop
|
|
|
217
224
|
}
|
|
218
225
|
};
|
|
219
226
|
|
|
227
|
+
useEffect(() => {
|
|
228
|
+
return () => {
|
|
229
|
+
if (isRemoveValueOnUnmount) {
|
|
230
|
+
formInstance.removeValueByPaths(_name);
|
|
231
|
+
}
|
|
232
|
+
};
|
|
233
|
+
}, []);
|
|
234
|
+
|
|
220
235
|
/**基础组件参数*/
|
|
221
236
|
const baseControl = {
|
|
222
237
|
...attrs,
|
|
@@ -420,7 +435,7 @@ export function useFairysValtioFormItemAttrs<T extends MObject<T> = object>(prop
|
|
|
420
435
|
} as FairysValtioFormItemAttrsReturn<T>;
|
|
421
436
|
}
|
|
422
437
|
|
|
423
|
-
export interface FairysValtioFormItemAttrsReturn<T extends MObject<T> =
|
|
438
|
+
export interface FairysValtioFormItemAttrsReturn<T extends MObject<T> = Record<string, any>> {
|
|
424
439
|
/**表单项值*/
|
|
425
440
|
value?: any;
|
|
426
441
|
/**是否校验错误*/
|
|
@@ -507,7 +522,7 @@ export const FormItem = (props: FormItemProps) => {
|
|
|
507
522
|
}
|
|
508
523
|
* ```
|
|
509
524
|
*/
|
|
510
|
-
export function useFairysValtioFormItemNoStyleAttrs<T extends MObject<T> =
|
|
525
|
+
export function useFairysValtioFormItemNoStyleAttrs<T extends MObject<T> = Record<string, any>>(
|
|
511
526
|
props: FairysValtioFormItemAttrsProps<T>,
|
|
512
527
|
) {
|
|
513
528
|
const {
|
|
@@ -522,6 +537,8 @@ export function useFairysValtioFormItemNoStyleAttrs<T extends MObject<T> = objec
|
|
|
522
537
|
attrs = {},
|
|
523
538
|
isJoinParentField = true,
|
|
524
539
|
rules,
|
|
540
|
+
isRemoveValueOnUnmount = true,
|
|
541
|
+
isRequired: _isRequired,
|
|
525
542
|
} = props;
|
|
526
543
|
const [state, errorState, formInstance] = useFairysValtioFormInstanceContextState<T>();
|
|
527
544
|
const {
|
|
@@ -534,6 +551,8 @@ export function useFairysValtioFormItemNoStyleAttrs<T extends MObject<T> = objec
|
|
|
534
551
|
const value = useMemo(() => get(state, paths), [state, paths]);
|
|
535
552
|
const error = errorState[_name];
|
|
536
553
|
formInstance.nameToPaths[_name] = paths;
|
|
554
|
+
// 使用从 Form 中设置的规则
|
|
555
|
+
const _formItemRules = formInstance.rules?.[_name];
|
|
537
556
|
|
|
538
557
|
useEffect(() => {
|
|
539
558
|
if (Array.isArray(rules) && rules.length) {
|
|
@@ -563,6 +582,15 @@ export function useFairysValtioFormItemNoStyleAttrs<T extends MObject<T> = objec
|
|
|
563
582
|
onAfterUpdate(_value, formInstance, event);
|
|
564
583
|
}
|
|
565
584
|
};
|
|
585
|
+
|
|
586
|
+
useEffect(() => {
|
|
587
|
+
return () => {
|
|
588
|
+
if (isRemoveValueOnUnmount) {
|
|
589
|
+
formInstance.removeValueByPaths(_name);
|
|
590
|
+
}
|
|
591
|
+
};
|
|
592
|
+
}, []);
|
|
593
|
+
|
|
566
594
|
/**基础组件参数*/
|
|
567
595
|
const baseControl = {
|
|
568
596
|
...attrs,
|
|
@@ -571,8 +599,30 @@ export function useFairysValtioFormItemNoStyleAttrs<T extends MObject<T> = objec
|
|
|
571
599
|
[valuePropName]: value,
|
|
572
600
|
[trigger]: onValueChange,
|
|
573
601
|
};
|
|
602
|
+
|
|
603
|
+
/**判断是否必填*/
|
|
604
|
+
const isRequired = useMemo(() => {
|
|
605
|
+
if (_isRequired) {
|
|
606
|
+
return _isRequired;
|
|
607
|
+
} else if (Array.isArray(rules) && rules.length) {
|
|
608
|
+
return rules.some((rule) => rule.required);
|
|
609
|
+
} else if (_formItemRules && Array.isArray(_formItemRules) && _formItemRules.length) {
|
|
610
|
+
return _formItemRules.some((rule) => rule.required);
|
|
611
|
+
}
|
|
612
|
+
return false;
|
|
613
|
+
}, [rules, formInstance, _formItemRules]);
|
|
614
|
+
|
|
615
|
+
/**校验是否存在错误信息*/
|
|
616
|
+
const isInvalid = useMemo(() => {
|
|
617
|
+
if (Array.isArray(error) && error.length) {
|
|
618
|
+
return true;
|
|
619
|
+
}
|
|
620
|
+
return false;
|
|
621
|
+
}, [error]);
|
|
574
622
|
return {
|
|
575
623
|
value,
|
|
624
|
+
isInvalid,
|
|
625
|
+
isRequired,
|
|
576
626
|
error,
|
|
577
627
|
onValueChange,
|
|
578
628
|
state,
|
|
@@ -585,5 +635,38 @@ export function useFairysValtioFormItemNoStyleAttrs<T extends MObject<T> = objec
|
|
|
585
635
|
parentName,
|
|
586
636
|
formAttrsNameInstance,
|
|
587
637
|
children: React.isValidElement(children) ? React.cloneElement(children, { ...baseControl }) : children,
|
|
588
|
-
}
|
|
638
|
+
} as FairysValtioFormItemNoStyleAttrsReturn<T>;
|
|
639
|
+
}
|
|
640
|
+
|
|
641
|
+
export interface FairysValtioFormItemNoStyleAttrsReturn<T extends MObject<T> = Record<string, any>> {
|
|
642
|
+
/**表单项值*/
|
|
643
|
+
value?: any;
|
|
644
|
+
/**是否校验错误*/
|
|
645
|
+
isInvalid: boolean;
|
|
646
|
+
/**是否必填*/
|
|
647
|
+
isRequired: boolean;
|
|
648
|
+
/**错误信息*/
|
|
649
|
+
error?: string[];
|
|
650
|
+
/**值改变事件*/
|
|
651
|
+
onValueChange: (event: any) => void;
|
|
652
|
+
/**表单状态*/
|
|
653
|
+
state: T;
|
|
654
|
+
/**错误状态*/
|
|
655
|
+
errorState: Record<PropertyKey, string[]>;
|
|
656
|
+
/**表单实例*/
|
|
657
|
+
formInstance: FairysValtioFormInstance<T>;
|
|
658
|
+
/**拼接父级字段名后得到的表单项名称*/
|
|
659
|
+
_name?: string;
|
|
660
|
+
/**表单项名称*/
|
|
661
|
+
name?: string;
|
|
662
|
+
/**表单项ID*/
|
|
663
|
+
id?: string;
|
|
664
|
+
/**表单项路径*/
|
|
665
|
+
paths?: (string | number)[];
|
|
666
|
+
/**父级字段名*/
|
|
667
|
+
parentName?: string;
|
|
668
|
+
/**表单属性名实例*/
|
|
669
|
+
formAttrsNameInstance: FairysValtioFormParentAttrs;
|
|
670
|
+
/**子元素*/
|
|
671
|
+
children?: React.ReactNode;
|
|
589
672
|
}
|
package/src/form/form.tsx
CHANGED
|
@@ -4,7 +4,8 @@ import { useImperativeHandle, useMemo, type ReactNode, useEffect } from 'react';
|
|
|
4
4
|
import { FairysValtioFormLayoutAttrsProps } from './layout';
|
|
5
5
|
import { RuleItem } from 'async-validator';
|
|
6
6
|
|
|
7
|
-
export interface FairysValtioFormAttrsProps<T extends MObject<T> =
|
|
7
|
+
export interface FairysValtioFormAttrsProps<T extends MObject<T> = Record<string, any>>
|
|
8
|
+
extends FairysValtioFormLayoutAttrsProps {
|
|
8
9
|
/**表单实例*/
|
|
9
10
|
form?: FairysValtioFormInstance<T>;
|
|
10
11
|
/**子元素*/
|
|
@@ -21,6 +22,12 @@ export interface FairysValtioFormAttrsProps<T extends MObject<T> = object> exten
|
|
|
21
22
|
* - immutable:直接使用对象(注意:当传递的不是`valtio`的`proxy`对象时,会使用`valtio`中的`proxy`声明)
|
|
22
23
|
*/
|
|
23
24
|
initFormDataType?: 'deepCopy' | 'immutable';
|
|
25
|
+
/**
|
|
26
|
+
* 表单值改变时回调
|
|
27
|
+
* @param path 表单项路径
|
|
28
|
+
* @param value 表单项值
|
|
29
|
+
*/
|
|
30
|
+
onValuesChange?: (path: PropertyKey, value: any) => void;
|
|
24
31
|
}
|
|
25
32
|
|
|
26
33
|
/**
|
|
@@ -43,14 +50,16 @@ export const Form = (props: FormProps) => {
|
|
|
43
50
|
}
|
|
44
51
|
* ```
|
|
45
52
|
*/
|
|
46
|
-
export function useFairysValtioForm<T extends MObject<T> =
|
|
53
|
+
export function useFairysValtioForm<T extends MObject<T> = Record<string, any>>(
|
|
47
54
|
props: FairysValtioFormAttrsProps<T>,
|
|
48
55
|
ref: React.Ref<FairysValtioFormInstance<T>>,
|
|
49
56
|
) {
|
|
50
|
-
const { form, rules, formData, hideState, initFormDataType = 'deepCopy', ...rest } = props;
|
|
57
|
+
const { form, rules, formData, hideState, initFormDataType = 'deepCopy', onValuesChange, ...rest } = props;
|
|
51
58
|
const formInstance = useFairysValtioFormInstance(form);
|
|
52
59
|
/**表单规则*/
|
|
53
60
|
formInstance.rules = rules;
|
|
61
|
+
/**表单值改变时回调*/
|
|
62
|
+
formInstance.onValuesChange = onValuesChange;
|
|
54
63
|
/**初始化表单值*/
|
|
55
64
|
useMemo(() => formInstance.ctor({ formData, hideState, initFormDataType }), []);
|
|
56
65
|
useImperativeHandle(ref, () => formInstance);
|
|
@@ -59,5 +68,10 @@ export function useFairysValtioForm<T extends MObject<T> = object>(
|
|
|
59
68
|
return {
|
|
60
69
|
...rest,
|
|
61
70
|
formInstance,
|
|
71
|
+
} as Omit<
|
|
72
|
+
FairysValtioFormAttrsProps<T>,
|
|
73
|
+
'initFormDataType' | 'form' | 'rules' | 'formData' | 'hideState' | 'onValuesChange'
|
|
74
|
+
> & {
|
|
75
|
+
formInstance: FairysValtioFormInstance<T>;
|
|
62
76
|
};
|
|
63
77
|
}
|