@hi-ui/form 4.3.2 → 4.3.4
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/CHANGELOG.md +14 -0
- package/lib/cjs/use-form-field.js +14 -1
- package/lib/cjs/use-form.js +34 -8
- package/lib/cjs/utils/index.js +60 -0
- package/lib/esm/use-form-field.js +15 -2
- package/lib/esm/use-form.js +35 -9
- package/lib/esm/utils/index.js +60 -1
- package/lib/types/utils/index.d.ts +4 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,19 @@
|
|
|
1
1
|
# @hi-ui/form
|
|
2
2
|
|
|
3
|
+
## 4.3.4
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- [#3476](https://github.com/XiaoMi/hiui/pull/3476) [`b12cd78`](https://github.com/XiaoMi/hiui/commit/b12cd78a3e701a0efaacc6f14705a0afcb0fae08) Thanks [@zyprepare](https://github.com/zyprepare)! - fix(form): 修复当 initialValues 为 {} 时无法正常重置表单问题 (#3475)
|
|
8
|
+
|
|
9
|
+
## 4.3.3
|
|
10
|
+
|
|
11
|
+
### Patch Changes
|
|
12
|
+
|
|
13
|
+
- [#3277](https://github.com/XiaoMi/hiui/pull/3277) [`93df0aaff`](https://github.com/XiaoMi/hiui/commit/93df0aafff09be59faeb4bad0ceea57a00df5ccf) Thanks [@zyprepare](https://github.com/zyprepare)! - fix(form): 处理规则消息为空的情况,将其设置为 undefined (#3276)
|
|
14
|
+
|
|
15
|
+
- [#3275](https://github.com/XiaoMi/hiui/pull/3275) [`b2b66a9e7`](https://github.com/XiaoMi/hiui/commit/b2b66a9e73a1a92d6b0604dc2ad711895154e518) Thanks [@zyprepare](https://github.com/zyprepare)! - fix(form): 优化 valueType 为 number 情况下的校验逻辑 (#3274)
|
|
16
|
+
|
|
3
17
|
## 4.3.2
|
|
4
18
|
|
|
5
19
|
### Patch Changes
|
|
@@ -63,6 +63,9 @@ var useFormField = function useFormField(props) {
|
|
|
63
63
|
// TODO: rules 处理成 Async Validate 的指定结构
|
|
64
64
|
var fieldMD5 = index.stringify(field);
|
|
65
65
|
var modifiedFieldRules = fieldRules.map(function (rule) {
|
|
66
|
+
if (rule.message === null || rule.message === '') {
|
|
67
|
+
rule.message = undefined;
|
|
68
|
+
}
|
|
66
69
|
// 重写 rule 的 validator 函数,正则匹配 validatorRule 中的 field 和 fullField,消除 field 和 fullField 中的双引号
|
|
67
70
|
// issue:https://github.com/XiaoMi/hiui/issues/2931
|
|
68
71
|
if (rule.validator) {
|
|
@@ -79,7 +82,17 @@ var useFormField = function useFormField(props) {
|
|
|
79
82
|
} else return Object.assign({}, rule);
|
|
80
83
|
});
|
|
81
84
|
var validater = new Validater__default["default"]((_Validater = {}, _Validater[fieldMD5] = modifiedFieldRules, _Validater));
|
|
82
|
-
|
|
85
|
+
var valueToValidate = value;
|
|
86
|
+
if (valueType === 'number') {
|
|
87
|
+
if (typeAssertion.isNullish(value) || value === '') {
|
|
88
|
+
valueToValidate = value;
|
|
89
|
+
} else if (isNaN(value)) {
|
|
90
|
+
valueToValidate = value;
|
|
91
|
+
} else {
|
|
92
|
+
valueToValidate = Number(value);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
return validater.validate((_validater$validate = {}, _validater$validate[fieldMD5] = valueToValidate, _validater$validate), {
|
|
83
96
|
firstFields: true
|
|
84
97
|
});
|
|
85
98
|
}, [fieldRules, field, valueType]);
|
package/lib/cjs/use-form.js
CHANGED
|
@@ -365,7 +365,7 @@ var useForm = function useForm(_a) {
|
|
|
365
365
|
var onResetLatestRef = useLatest.useLatestRef(onReset);
|
|
366
366
|
var resetForm = React.useCallback(function (nextState) {
|
|
367
367
|
return tslib.__awaiter(void 0, void 0, void 0, /*#__PURE__*/_regeneratorRuntime__default["default"].mark(function _callee2() {
|
|
368
|
-
var values, errors, touched, submitting, validating, dispatchFn;
|
|
368
|
+
var values, errors, touched, registeredKeys, formValues, submitting, validating, dispatchFn;
|
|
369
369
|
return _regeneratorRuntime__default["default"].wrap(function _callee2$(_context2) {
|
|
370
370
|
while (1) {
|
|
371
371
|
switch (_context2.prev = _context2.next) {
|
|
@@ -373,6 +373,32 @@ var useForm = function useForm(_a) {
|
|
|
373
373
|
values = nextState && nextState.values ? nextState.values : initialValuesRef.current;
|
|
374
374
|
errors = nextState && nextState.errors ? nextState.errors : initialErrorsRef.current;
|
|
375
375
|
touched = nextState && nextState.touched ? nextState.touched : initialTouchedRef.current;
|
|
376
|
+
registeredKeys = getRegisteredKeys();
|
|
377
|
+
formValues = formState.values; // 处理缺失的字段:如果 registeredKeys 中的字段在 values 中不存在,
|
|
378
|
+
// 则根据 formValues 中对应字段的类型设置对应的空值
|
|
379
|
+
if (registeredKeys.length > 0) {
|
|
380
|
+
// 确保 values 是一个对象
|
|
381
|
+
if (!values || _typeof(values) !== 'object' || typeAssertion.isArray(values)) {
|
|
382
|
+
values = {};
|
|
383
|
+
} else {
|
|
384
|
+
// 浅拷贝 values 避免修改原始对象
|
|
385
|
+
values = Object.assign({}, values);
|
|
386
|
+
}
|
|
387
|
+
registeredKeys.forEach(function (field) {
|
|
388
|
+
// 检查字段是否存在于 values 中
|
|
389
|
+
var valueInReset = objectUtils.getNested(values, field);
|
|
390
|
+
// 如果字段不存在(undefined),则根据 formValues 中的类型设置空值
|
|
391
|
+
if (valueInReset === undefined) {
|
|
392
|
+
var currentValue = objectUtils.getNested(formValues, field);
|
|
393
|
+
// 如果当前值存在(包括 null),根据其类型设置对应的空值
|
|
394
|
+
if (currentValue !== undefined) {
|
|
395
|
+
var emptyValue = index.getEmptyValueByType(currentValue);
|
|
396
|
+
// setNested 返回新对象,需要重新赋值
|
|
397
|
+
values = objectUtils.setNested(values, field, emptyValue);
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
});
|
|
401
|
+
}
|
|
376
402
|
initialValuesRef.current = values;
|
|
377
403
|
// @ts-ignore
|
|
378
404
|
initialErrorsRef.current = errors;
|
|
@@ -392,25 +418,25 @@ var useForm = function useForm(_a) {
|
|
|
392
418
|
});
|
|
393
419
|
};
|
|
394
420
|
if (!onResetLatestRef.current) {
|
|
395
|
-
_context2.next =
|
|
421
|
+
_context2.next = 18;
|
|
396
422
|
break;
|
|
397
423
|
}
|
|
398
|
-
_context2.next =
|
|
424
|
+
_context2.next = 15;
|
|
399
425
|
return onResetLatestRef.current(formState.values);
|
|
400
|
-
case
|
|
426
|
+
case 15:
|
|
401
427
|
dispatchFn();
|
|
402
|
-
_context2.next =
|
|
428
|
+
_context2.next = 19;
|
|
403
429
|
break;
|
|
404
|
-
case
|
|
430
|
+
case 18:
|
|
405
431
|
dispatchFn();
|
|
406
|
-
case
|
|
432
|
+
case 19:
|
|
407
433
|
case "end":
|
|
408
434
|
return _context2.stop();
|
|
409
435
|
}
|
|
410
436
|
}
|
|
411
437
|
}, _callee2);
|
|
412
438
|
}));
|
|
413
|
-
}, [
|
|
439
|
+
}, [formState.values, getRegisteredKeys, onResetLatestRef]);
|
|
414
440
|
/**
|
|
415
441
|
* 表单提交
|
|
416
442
|
*/
|
package/lib/cjs/utils/index.js
CHANGED
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
*/
|
|
10
10
|
'use strict';
|
|
11
11
|
|
|
12
|
+
var _typeof = require("@babel/runtime/helpers/typeof");
|
|
12
13
|
Object.defineProperty(exports, '__esModule', {
|
|
13
14
|
value: true
|
|
14
15
|
});
|
|
@@ -40,6 +41,65 @@ var mergeValues = function mergeValues(source, override) {
|
|
|
40
41
|
}
|
|
41
42
|
return target;
|
|
42
43
|
};
|
|
44
|
+
/**
|
|
45
|
+
* 根据值的类型返回对应的空值
|
|
46
|
+
*/
|
|
47
|
+
var getEmptyValueByType = function getEmptyValueByType(value) {
|
|
48
|
+
// 优先处理特殊对象类型(instanceof 检查)
|
|
49
|
+
if (typeAssertion.isArray(value)) {
|
|
50
|
+
return [];
|
|
51
|
+
}
|
|
52
|
+
if (value instanceof Date) {
|
|
53
|
+
return null;
|
|
54
|
+
}
|
|
55
|
+
if (value instanceof RegExp) {
|
|
56
|
+
return /(?:)/;
|
|
57
|
+
}
|
|
58
|
+
if (value instanceof Map) {
|
|
59
|
+
return new Map();
|
|
60
|
+
}
|
|
61
|
+
if (value instanceof Set) {
|
|
62
|
+
return new Set();
|
|
63
|
+
}
|
|
64
|
+
// 注意:WeakMap 和 WeakSet 无法创建空实例,返回 null
|
|
65
|
+
if (value instanceof WeakMap) {
|
|
66
|
+
return null;
|
|
67
|
+
}
|
|
68
|
+
if (value instanceof WeakSet) {
|
|
69
|
+
return null;
|
|
70
|
+
}
|
|
71
|
+
// 处理基本类型(typeof 检查)
|
|
72
|
+
if (_typeof(value) === 'symbol') {
|
|
73
|
+
return Symbol('');
|
|
74
|
+
}
|
|
75
|
+
if (typeof value === 'bigint') {
|
|
76
|
+
return BigInt(0);
|
|
77
|
+
}
|
|
78
|
+
if (typeof value === 'string') {
|
|
79
|
+
return '';
|
|
80
|
+
}
|
|
81
|
+
if (typeof value === 'number') {
|
|
82
|
+
return null;
|
|
83
|
+
}
|
|
84
|
+
if (typeof value === 'boolean') {
|
|
85
|
+
return false;
|
|
86
|
+
}
|
|
87
|
+
if (typeof value === 'function') {
|
|
88
|
+
// 函数类型重置为 undefined,因为函数不应该作为表单值
|
|
89
|
+
return undefined;
|
|
90
|
+
}
|
|
91
|
+
// 对于 null 值,保持为 null
|
|
92
|
+
if (value === null) {
|
|
93
|
+
return null;
|
|
94
|
+
}
|
|
95
|
+
// 处理普通对象(必须在所有 instanceof 检查之后)
|
|
96
|
+
if (_typeof(value) === 'object') {
|
|
97
|
+
return {};
|
|
98
|
+
}
|
|
99
|
+
// 其他类型(包括 undefined)默认返回 undefined
|
|
100
|
+
return undefined;
|
|
101
|
+
};
|
|
102
|
+
exports.getEmptyValueByType = getEmptyValueByType;
|
|
43
103
|
exports.isValidField = isValidField;
|
|
44
104
|
exports.mergeValues = mergeValues;
|
|
45
105
|
exports.parse = parse;
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
*/
|
|
10
10
|
import { useMemo, useCallback, useEffect } from 'react';
|
|
11
11
|
import { useFormContext } from './context.js';
|
|
12
|
-
import { isArrayNonEmpty } from '@hi-ui/type-assertion';
|
|
12
|
+
import { isArrayNonEmpty, isNullish } from '@hi-ui/type-assertion';
|
|
13
13
|
import Validater from 'async-validator';
|
|
14
14
|
import { normalizeArray } from '@hi-ui/array-utils';
|
|
15
15
|
import { stringify, isValidField } from './utils/index.js';
|
|
@@ -51,6 +51,9 @@ var useFormField = function useFormField(props) {
|
|
|
51
51
|
// TODO: rules 处理成 Async Validate 的指定结构
|
|
52
52
|
var fieldMD5 = stringify(field);
|
|
53
53
|
var modifiedFieldRules = fieldRules.map(function (rule) {
|
|
54
|
+
if (rule.message === null || rule.message === '') {
|
|
55
|
+
rule.message = undefined;
|
|
56
|
+
}
|
|
54
57
|
// 重写 rule 的 validator 函数,正则匹配 validatorRule 中的 field 和 fullField,消除 field 和 fullField 中的双引号
|
|
55
58
|
// issue:https://github.com/XiaoMi/hiui/issues/2931
|
|
56
59
|
if (rule.validator) {
|
|
@@ -67,7 +70,17 @@ var useFormField = function useFormField(props) {
|
|
|
67
70
|
} else return Object.assign({}, rule);
|
|
68
71
|
});
|
|
69
72
|
var validater = new Validater((_Validater = {}, _Validater[fieldMD5] = modifiedFieldRules, _Validater));
|
|
70
|
-
|
|
73
|
+
var valueToValidate = value;
|
|
74
|
+
if (valueType === 'number') {
|
|
75
|
+
if (isNullish(value) || value === '') {
|
|
76
|
+
valueToValidate = value;
|
|
77
|
+
} else if (isNaN(value)) {
|
|
78
|
+
valueToValidate = value;
|
|
79
|
+
} else {
|
|
80
|
+
valueToValidate = Number(value);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
return validater.validate((_validater$validate = {}, _validater$validate[fieldMD5] = valueToValidate, _validater$validate), {
|
|
71
84
|
firstFields: true
|
|
72
85
|
});
|
|
73
86
|
}, [fieldRules, field, valueType]);
|
package/lib/esm/use-form.js
CHANGED
|
@@ -10,7 +10,7 @@ import _typeof from "@babel/runtime/helpers/esm/typeof";
|
|
|
10
10
|
*/
|
|
11
11
|
import _regeneratorRuntime from '@babel/runtime/regenerator';
|
|
12
12
|
import { __rest, __awaiter } from 'tslib';
|
|
13
|
-
import { stringify, parse, mergeValues, isValidField } from './utils/index.js';
|
|
13
|
+
import { stringify, parse, mergeValues, getEmptyValueByType, isValidField } from './utils/index.js';
|
|
14
14
|
import React, { useMemo, useRef, useReducer, useCallback } from 'react';
|
|
15
15
|
import scrollIntoView from 'scroll-into-view-if-needed';
|
|
16
16
|
import { useLatestRef, useLatestCallback } from '@hi-ui/use-latest';
|
|
@@ -352,7 +352,7 @@ var useForm = function useForm(_a) {
|
|
|
352
352
|
var onResetLatestRef = useLatestRef(onReset);
|
|
353
353
|
var resetForm = useCallback(function (nextState) {
|
|
354
354
|
return __awaiter(void 0, void 0, void 0, /*#__PURE__*/_regeneratorRuntime.mark(function _callee2() {
|
|
355
|
-
var values, errors, touched, submitting, validating, dispatchFn;
|
|
355
|
+
var values, errors, touched, registeredKeys, formValues, submitting, validating, dispatchFn;
|
|
356
356
|
return _regeneratorRuntime.wrap(function _callee2$(_context2) {
|
|
357
357
|
while (1) {
|
|
358
358
|
switch (_context2.prev = _context2.next) {
|
|
@@ -360,6 +360,32 @@ var useForm = function useForm(_a) {
|
|
|
360
360
|
values = nextState && nextState.values ? nextState.values : initialValuesRef.current;
|
|
361
361
|
errors = nextState && nextState.errors ? nextState.errors : initialErrorsRef.current;
|
|
362
362
|
touched = nextState && nextState.touched ? nextState.touched : initialTouchedRef.current;
|
|
363
|
+
registeredKeys = getRegisteredKeys();
|
|
364
|
+
formValues = formState.values; // 处理缺失的字段:如果 registeredKeys 中的字段在 values 中不存在,
|
|
365
|
+
// 则根据 formValues 中对应字段的类型设置对应的空值
|
|
366
|
+
if (registeredKeys.length > 0) {
|
|
367
|
+
// 确保 values 是一个对象
|
|
368
|
+
if (!values || _typeof(values) !== 'object' || isArray(values)) {
|
|
369
|
+
values = {};
|
|
370
|
+
} else {
|
|
371
|
+
// 浅拷贝 values 避免修改原始对象
|
|
372
|
+
values = Object.assign({}, values);
|
|
373
|
+
}
|
|
374
|
+
registeredKeys.forEach(function (field) {
|
|
375
|
+
// 检查字段是否存在于 values 中
|
|
376
|
+
var valueInReset = getNested(values, field);
|
|
377
|
+
// 如果字段不存在(undefined),则根据 formValues 中的类型设置空值
|
|
378
|
+
if (valueInReset === undefined) {
|
|
379
|
+
var currentValue = getNested(formValues, field);
|
|
380
|
+
// 如果当前值存在(包括 null),根据其类型设置对应的空值
|
|
381
|
+
if (currentValue !== undefined) {
|
|
382
|
+
var emptyValue = getEmptyValueByType(currentValue);
|
|
383
|
+
// setNested 返回新对象,需要重新赋值
|
|
384
|
+
values = setNested(values, field, emptyValue);
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
});
|
|
388
|
+
}
|
|
363
389
|
initialValuesRef.current = values;
|
|
364
390
|
// @ts-ignore
|
|
365
391
|
initialErrorsRef.current = errors;
|
|
@@ -379,25 +405,25 @@ var useForm = function useForm(_a) {
|
|
|
379
405
|
});
|
|
380
406
|
};
|
|
381
407
|
if (!onResetLatestRef.current) {
|
|
382
|
-
_context2.next =
|
|
408
|
+
_context2.next = 18;
|
|
383
409
|
break;
|
|
384
410
|
}
|
|
385
|
-
_context2.next =
|
|
411
|
+
_context2.next = 15;
|
|
386
412
|
return onResetLatestRef.current(formState.values);
|
|
387
|
-
case
|
|
413
|
+
case 15:
|
|
388
414
|
dispatchFn();
|
|
389
|
-
_context2.next =
|
|
415
|
+
_context2.next = 19;
|
|
390
416
|
break;
|
|
391
|
-
case
|
|
417
|
+
case 18:
|
|
392
418
|
dispatchFn();
|
|
393
|
-
case
|
|
419
|
+
case 19:
|
|
394
420
|
case "end":
|
|
395
421
|
return _context2.stop();
|
|
396
422
|
}
|
|
397
423
|
}
|
|
398
424
|
}, _callee2);
|
|
399
425
|
}));
|
|
400
|
-
}, [
|
|
426
|
+
}, [formState.values, getRegisteredKeys, onResetLatestRef]);
|
|
401
427
|
/**
|
|
402
428
|
* 表单提交
|
|
403
429
|
*/
|
package/lib/esm/utils/index.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import _typeof from "@babel/runtime/helpers/esm/typeof";
|
|
1
2
|
/** @LICENSE
|
|
2
3
|
* @hi-ui/form
|
|
3
4
|
* https://github.com/XiaoMi/hiui/tree/master/packages/ui/form#readme
|
|
@@ -35,4 +36,62 @@ var mergeValues = function mergeValues(source, override) {
|
|
|
35
36
|
}
|
|
36
37
|
return target;
|
|
37
38
|
};
|
|
38
|
-
|
|
39
|
+
/**
|
|
40
|
+
* 根据值的类型返回对应的空值
|
|
41
|
+
*/
|
|
42
|
+
var getEmptyValueByType = function getEmptyValueByType(value) {
|
|
43
|
+
// 优先处理特殊对象类型(instanceof 检查)
|
|
44
|
+
if (isArray(value)) {
|
|
45
|
+
return [];
|
|
46
|
+
}
|
|
47
|
+
if (value instanceof Date) {
|
|
48
|
+
return null;
|
|
49
|
+
}
|
|
50
|
+
if (value instanceof RegExp) {
|
|
51
|
+
return /(?:)/;
|
|
52
|
+
}
|
|
53
|
+
if (value instanceof Map) {
|
|
54
|
+
return new Map();
|
|
55
|
+
}
|
|
56
|
+
if (value instanceof Set) {
|
|
57
|
+
return new Set();
|
|
58
|
+
}
|
|
59
|
+
// 注意:WeakMap 和 WeakSet 无法创建空实例,返回 null
|
|
60
|
+
if (value instanceof WeakMap) {
|
|
61
|
+
return null;
|
|
62
|
+
}
|
|
63
|
+
if (value instanceof WeakSet) {
|
|
64
|
+
return null;
|
|
65
|
+
}
|
|
66
|
+
// 处理基本类型(typeof 检查)
|
|
67
|
+
if (_typeof(value) === 'symbol') {
|
|
68
|
+
return Symbol('');
|
|
69
|
+
}
|
|
70
|
+
if (typeof value === 'bigint') {
|
|
71
|
+
return BigInt(0);
|
|
72
|
+
}
|
|
73
|
+
if (typeof value === 'string') {
|
|
74
|
+
return '';
|
|
75
|
+
}
|
|
76
|
+
if (typeof value === 'number') {
|
|
77
|
+
return null;
|
|
78
|
+
}
|
|
79
|
+
if (typeof value === 'boolean') {
|
|
80
|
+
return false;
|
|
81
|
+
}
|
|
82
|
+
if (typeof value === 'function') {
|
|
83
|
+
// 函数类型重置为 undefined,因为函数不应该作为表单值
|
|
84
|
+
return undefined;
|
|
85
|
+
}
|
|
86
|
+
// 对于 null 值,保持为 null
|
|
87
|
+
if (value === null) {
|
|
88
|
+
return null;
|
|
89
|
+
}
|
|
90
|
+
// 处理普通对象(必须在所有 instanceof 检查之后)
|
|
91
|
+
if (_typeof(value) === 'object') {
|
|
92
|
+
return {};
|
|
93
|
+
}
|
|
94
|
+
// 其他类型(包括 undefined)默认返回 undefined
|
|
95
|
+
return undefined;
|
|
96
|
+
};
|
|
97
|
+
export { getEmptyValueByType, isValidField, mergeValues, parse, stringify };
|
|
@@ -3,3 +3,7 @@ export declare const stringify: (field: FormFieldPath) => string;
|
|
|
3
3
|
export declare const parse: (fieldStr: string) => FormFieldPath;
|
|
4
4
|
export declare const isValidField: (field: FormFieldPath | undefined) => field is FormFieldPath;
|
|
5
5
|
export declare const mergeValues: <T extends Object, E extends T>(source: T, override: E | null | undefined) => T;
|
|
6
|
+
/**
|
|
7
|
+
* 根据值的类型返回对应的空值
|
|
8
|
+
*/
|
|
9
|
+
export declare const getEmptyValueByType: (value: any) => any;
|