@fairys/taro-tools-simple-form-ui 0.0.5

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.
Files changed (68) hide show
  1. package/README.md +0 -0
  2. package/esm/components/calendar/index.d.ts +10 -0
  3. package/esm/components/calendar/index.js +35 -0
  4. package/esm/components/cascader/index.d.ts +10 -0
  5. package/esm/components/cascader/index.js +85 -0
  6. package/esm/components/checkbox.group/index.d.ts +5 -0
  7. package/esm/components/checkbox.group/index.js +14 -0
  8. package/esm/components/clear/index.d.ts +21 -0
  9. package/esm/components/clear/index.js +31 -0
  10. package/esm/components/date.picker/index.d.ts +18 -0
  11. package/esm/components/date.picker/index.js +122 -0
  12. package/esm/components/index.d.ts +8 -0
  13. package/esm/components/index.js +8 -0
  14. package/esm/components/picker/index.d.ts +9 -0
  15. package/esm/components/picker/index.js +45 -0
  16. package/esm/components/popup.search/base.d.ts +2 -0
  17. package/esm/components/popup.search/base.js +70 -0
  18. package/esm/components/popup.search/index.d.ts +9 -0
  19. package/esm/components/popup.search/index.js +157 -0
  20. package/esm/components/popup.search/instance.d.ts +127 -0
  21. package/esm/components/popup.search/instance.js +319 -0
  22. package/esm/components/popup.search/list.table.d.ts +1 -0
  23. package/esm/components/popup.search/list.table.js +91 -0
  24. package/esm/components/popup.search/list.virtual.d.ts +1 -0
  25. package/esm/components/popup.search/list.virtual.js +71 -0
  26. package/esm/components/radio.group/index.d.ts +5 -0
  27. package/esm/components/radio.group/index.js +13 -0
  28. package/esm/form/form.d.ts +30 -0
  29. package/esm/form/form.item.d.ts +54 -0
  30. package/esm/form/form.item.js +172 -0
  31. package/esm/form/form.js +31 -0
  32. package/esm/form/instance/index.d.ts +63 -0
  33. package/esm/form/instance/index.js +141 -0
  34. package/esm/form/item.config.d.ts +87 -0
  35. package/esm/form/item.config.js +105 -0
  36. package/esm/form/layout.d.ts +1784 -0
  37. package/esm/form/layout.js +134 -0
  38. package/esm/index.d.ts +5 -0
  39. package/esm/index.js +5 -0
  40. package/esm/interface.d.ts +4 -0
  41. package/esm/interface.js +0 -0
  42. package/esm/item.config.d.ts +0 -0
  43. package/esm/item.config.js +0 -0
  44. package/esm/styles/index.css +352 -0
  45. package/lib/index.js +96 -0
  46. package/package.json +38 -0
  47. package/src/components/calendar/index.tsx +45 -0
  48. package/src/components/cascader/index.tsx +127 -0
  49. package/src/components/checkbox.group/index.tsx +16 -0
  50. package/src/components/clear/index.tsx +49 -0
  51. package/src/components/date.picker/index.tsx +167 -0
  52. package/src/components/index.ts +8 -0
  53. package/src/components/picker/index.tsx +57 -0
  54. package/src/components/popup.search/base.tsx +51 -0
  55. package/src/components/popup.search/index.tsx +198 -0
  56. package/src/components/popup.search/instance.ts +440 -0
  57. package/src/components/popup.search/list.table.tsx +92 -0
  58. package/src/components/popup.search/list.virtual.tsx +84 -0
  59. package/src/components/radio.group/index.tsx +16 -0
  60. package/src/form/form.item.tsx +280 -0
  61. package/src/form/form.tsx +54 -0
  62. package/src/form/instance/index.ts +222 -0
  63. package/src/form/item.config.tsx +189 -0
  64. package/src/form/layout.tsx +232 -0
  65. package/src/index.tsx +5 -0
  66. package/src/interface.ts +4 -0
  67. package/src/item.config.tsx +202 -0
  68. package/src/styles/index.css +39 -0
@@ -0,0 +1,280 @@
1
+ /**表单项*/
2
+
3
+ import { MObject } from 'interface';
4
+ import { View } from '@tarojs/components';
5
+ import type { ViewProps } from '@tarojs/components';
6
+ import React, { Fragment, useMemo } from 'react';
7
+ import clsx from 'clsx';
8
+ import {
9
+ useFairysTaroValtioFormInstanceContextState,
10
+ FairysTaroValtioFormInstance,
11
+ useFairysTaroValtioFormInstanceContextHideState,
12
+ } from './instance';
13
+ import { useFairysTaroValtioFormLayoutContext } from './layout';
14
+
15
+ export interface FairysTaroValtioFormItemProps<T extends MObject<T> = object> extends ViewProps {
16
+ /**表单项名称*/
17
+ name: string;
18
+ /**表单项标签*/
19
+ label?: string;
20
+ /**是否使用样式*/
21
+ noStyle?: boolean;
22
+ /**传递组件字段*/
23
+ valuePropName?: string;
24
+ /**自定义获取值*/
25
+ getValueFromEvent?: (event: any, form: FairysTaroValtioFormInstance<T>) => any;
26
+ /**值格式化*/
27
+ formatValue?: (value: any, form: FairysTaroValtioFormInstance<T>, event: any) => any;
28
+ /**触发数据更新之后触发(用于数据联动之类的)*/
29
+ onAfterUpdate?: (value: any, form: FairysTaroValtioFormInstance<T>, event: any) => void;
30
+ /**事件名称*/
31
+ trigger?: string;
32
+ style?: React.CSSProperties;
33
+ labelClassName?: string;
34
+ labelStyle?: React.CSSProperties;
35
+ bodyClassName?: string;
36
+ bodyStyle?: React.CSSProperties;
37
+ /**规则校验失败错误提示位置*/
38
+ errorLayout?: 'left-bottom' | 'right-bottom' | 'top-right' | 'top-left';
39
+ /**label显示模式*/
40
+ labelMode?: 'left' | 'top' | 'between';
41
+ /**额外内容*/
42
+ extra?: React.ReactNode;
43
+ /**底部提示内容*/
44
+ helpText?: React.ReactNode;
45
+ /**
46
+ * 表单项占据列数
47
+ * @default 1
48
+ */
49
+ colSpan?: number;
50
+ /**
51
+ * 表单项占据行数
52
+ * @default 1
53
+ */
54
+ rowSpan?: number;
55
+ /**是否必填*/
56
+ isRequired?: boolean;
57
+ /**底部显示边框*/
58
+ bottomBordered?: boolean;
59
+ /**输入框属性*/
60
+ attrs?: any;
61
+ }
62
+
63
+ export function FairysTaroValtioFormItem<T extends MObject<T> = object>(props: FairysTaroValtioFormItemProps<T>) {
64
+ const [layoutAttrs] = useFairysTaroValtioFormLayoutContext();
65
+ const colCount = layoutAttrs.colCount || 1;
66
+ const parent_bottomBordered = layoutAttrs.bottomBordered || true;
67
+ const parent_errorLayout = layoutAttrs.errorLayout || 'right-bottom';
68
+ const parent_formItemClassName = layoutAttrs.formItemClassName;
69
+ const parent_formItemLabelClassName = layoutAttrs.formItemLabelClassName;
70
+ const parent_formItemLabelStyle = layoutAttrs.formItemLabelStyle;
71
+ const parent_formItemStyle = layoutAttrs.formItemStyle;
72
+ const parent_labelMode = layoutAttrs.labelMode || 'between';
73
+ const {
74
+ name,
75
+ label,
76
+ noStyle,
77
+ valuePropName = 'value',
78
+ getValueFromEvent,
79
+ formatValue,
80
+ onAfterUpdate,
81
+ trigger = 'onChange',
82
+ className,
83
+ style,
84
+ labelClassName,
85
+ labelStyle,
86
+ bodyClassName,
87
+ bodyStyle,
88
+ children,
89
+ labelMode = parent_labelMode,
90
+ errorLayout = parent_errorLayout,
91
+ extra,
92
+ helpText,
93
+ colSpan = 1,
94
+ rowSpan = 1,
95
+ isRequired: _isRequired,
96
+ bottomBordered = parent_bottomBordered,
97
+ attrs = {},
98
+ ...rest
99
+ } = props;
100
+ const [state, errorState, formInstance] = useFairysTaroValtioFormInstanceContextState<T>();
101
+ const rules = formInstance.rules?.[name];
102
+ const value = state[name];
103
+ const error = errorState[name];
104
+
105
+ const onValueChange = (event: any) => {
106
+ let value = event;
107
+ const target = event?.detail || event?.target;
108
+ if (typeof getValueFromEvent === 'function') {
109
+ value = getValueFromEvent(event, formInstance);
110
+ } else if (event && target && typeof target === 'object' && valuePropName in target) {
111
+ value = target.valuePropName;
112
+ }
113
+ if (typeof formatValue === 'function') {
114
+ value = formatValue(value, formInstance, event);
115
+ }
116
+ formInstance.updated({ [name]: value });
117
+ };
118
+ /**基础组件参数*/
119
+ const baseControl = {
120
+ ...attrs,
121
+ name,
122
+ [valuePropName]: value,
123
+ [trigger]: onValueChange,
124
+ };
125
+
126
+ /**判断是否必填*/
127
+ const isRequired = useMemo(() => {
128
+ if (_isRequired) {
129
+ return _isRequired;
130
+ } else if (Array.isArray(rules) && rules.length) {
131
+ return rules.some((rule) => rule.required);
132
+ }
133
+ return false;
134
+ }, [rules, formInstance]);
135
+
136
+ /**校验是否存在错误信息*/
137
+ const isInvalid = useMemo(() => {
138
+ if (Array.isArray(error) && error.length) {
139
+ return true;
140
+ }
141
+ return false;
142
+ }, [error]);
143
+
144
+ /**表单项类名*/
145
+ const item_cls = useMemo(() => {
146
+ return clsx(
147
+ 'fairys-taro-valtio-form-item fairystaroform__p-[0.2rem] fairystaroform__text-[0.6rem] fairystaroform__relative fairystaroform__flex fairystaroform__flex-col fairystaroform__box-border fairystaroform__break-all',
148
+ {
149
+ 'fairystaroform__border-b fairystaroform__border-b-solid fairystaroform__border-b-gray-100 ': bottomBordered,
150
+ },
151
+ className,
152
+ parent_formItemClassName,
153
+ );
154
+ }, [className, parent_formItemClassName, labelMode, bottomBordered]);
155
+
156
+ /**表单项容器类名*/
157
+ const itemContainer_cls = useMemo(() => {
158
+ // 默认两端显示
159
+ return clsx(
160
+ 'fairys-taro-valtio-form-item-container fairystaroform__flex-1 fairystaroform__h-full fairystaroform__flex fairystaroform__box-border',
161
+ {
162
+ 'fairystaroform__flex-row fairystaroform__items-center fairystaroform__justify-between fairystaroform__gap-[0.4rem]':
163
+ labelMode === 'between',
164
+ 'fairystaroform__flex-col fairystaroform__gap-[0.2rem]': labelMode === 'top',
165
+ 'fairystaroform__flex-row fairystaroform__gap-[0.4rem]': labelMode === 'left',
166
+ },
167
+ labelClassName,
168
+ );
169
+ }, [labelClassName, labelMode]);
170
+
171
+ /**表单项标签类名*/
172
+ const itemLabel_cls = useMemo(() => {
173
+ // 默认两端显示
174
+ return clsx(
175
+ 'fairys-taro-valtio-form-item-label fairystaroform__text-gray-800 fairystaroform__text-[0.75rem] fairystaroform__min-h-[1.4rem] fairystaroform__flex fairystaroform__items-center fairystaroform__relative fairystaroform__box-border',
176
+ {
177
+ 'fairystaroform__justify-start': labelMode !== 'left',
178
+ 'fairystaroform__justify-end': labelMode === 'left',
179
+ required: isRequired,
180
+ },
181
+ labelClassName,
182
+ parent_formItemLabelClassName,
183
+ );
184
+ }, [labelClassName, parent_formItemLabelClassName, labelMode, isRequired]);
185
+
186
+ /**表单项主体类名*/
187
+ const itemBody_cls = useMemo(() => {
188
+ // 默认两端显示
189
+ return clsx(
190
+ 'fairys-taro-valtio-form-item-body fairystaroform__flex fairystaroform__box-border',
191
+ {
192
+ 'fairystaroform__flex-row fairystaroform__justify-start': labelMode === 'left',
193
+ 'fairystaroform__flex-row fairystaroform__justify-end': labelMode === 'between' || labelMode === 'top',
194
+ 'fairystaroform__flex-row': labelMode === 'top',
195
+ },
196
+ bodyClassName,
197
+ );
198
+ }, [bodyClassName, labelMode]);
199
+
200
+ // 表单项输入类名
201
+ const itemInput_cls = useMemo(() => {
202
+ return clsx(
203
+ 'fairys-taro-valtio-form-item-body fairystaroform__flex fairystaroform__flex-row fairystaroform__flex-1 fairystaroform__box-border',
204
+ {
205
+ 'fairystaroform__justify-end fairystaroform__text-right': labelMode === 'between',
206
+ 'fairystaroform__justify-start fairystaroform__text-left fairystaroform__items-center': labelMode !== 'between',
207
+ },
208
+ );
209
+ }, [labelMode]);
210
+
211
+ /**表单项额外内容类名*/
212
+ const itemExtra_cls = useMemo(() => {
213
+ return clsx(
214
+ 'fairys-taro-valtio-form-item-body-extra fairystaroform__box-border fairystaroform__flex fairystaroform__items-center fairystaroform__justify-center',
215
+ );
216
+ }, []);
217
+
218
+ /**表单项底部提示内容类名*/
219
+ const itemHelp_cls = useMemo(() => {
220
+ return clsx(
221
+ 'fairys-taro-valtio-form-item-body-help fairystaroform__text-[0.5rem] fairystaroform__w-full fairystaroform__box-border',
222
+ );
223
+ }, []);
224
+
225
+ /**表单项错误提示类名*/
226
+ const itemError_cls = useMemo(() => {
227
+ return clsx(
228
+ 'fairys-taro-valtio-form-item-body-error fairystaroform__px-[0.2rem] fairystaroform__w-full fairystaroform__flex fairystaroform__flex-row fairystaroform__box-border fairystaroform__text-red fairystaroform__absolute fairystaroform__text-[0.5rem] fairystaroform__z-10',
229
+ {
230
+ 'fairystaroform__bottom-[-0.7rem] fairystaroform__left-0 fairystaroform__justify-start':
231
+ errorLayout === 'left-bottom',
232
+ 'fairystaroform__bottom-[-0.7rem] fairystaroform__right-0 fairystaroform__justify-end':
233
+ errorLayout === 'right-bottom',
234
+ 'fairystaroform__top-[-0.7rem] fairystaroform__right-0 fairystaroform__justify-end':
235
+ errorLayout === 'top-right',
236
+ 'fairystaroform__top-[-0.7rem] fairystaroform__left-0 fairystaroform__justify-start':
237
+ errorLayout === 'top-left',
238
+ },
239
+ );
240
+ }, [errorLayout]);
241
+
242
+ const styleBase = useMemo(() => {
243
+ const css: React.CSSProperties = {};
244
+ if (colSpan) {
245
+ const end = colCount > colSpan ? colSpan : colCount;
246
+ css.gridColumnEnd = `span ${end}`;
247
+ }
248
+ if (rowSpan) {
249
+ css.gridRowEnd = `span ${rowSpan}`;
250
+ }
251
+ return css;
252
+ }, [colSpan, rowSpan, colCount]);
253
+
254
+ return (
255
+ <View {...rest} className={item_cls} style={{ ...(parent_formItemStyle || {}), ...styleBase, ...(style || {}) }}>
256
+ <View className={itemContainer_cls}>
257
+ <View className={itemLabel_cls} style={{ ...(parent_formItemLabelStyle || {}), ...(labelStyle || {}) }}>
258
+ {label}
259
+ </View>
260
+ <View className={itemBody_cls} style={bodyStyle}>
261
+ <View className={itemInput_cls}>
262
+ {React.isValidElement(children) ? React.cloneElement(children, { ...baseControl }) : children}
263
+ </View>
264
+ {extra ? <View className={itemExtra_cls}>{extra}</View> : <Fragment />}
265
+ </View>
266
+ </View>
267
+ {helpText ? <View className={itemHelp_cls}>{helpText}</View> : <Fragment />}
268
+ {isInvalid ? <View className={itemError_cls}>{error}</View> : <Fragment />}
269
+ </View>
270
+ );
271
+ }
272
+
273
+ export function FairysTaroValtioFormHideItem<T extends MObject<T> = object>(props: FairysTaroValtioFormItemProps<T>) {
274
+ const [state] = useFairysTaroValtioFormInstanceContextHideState();
275
+ const isHide = state[props.name];
276
+ if (isHide) {
277
+ return <Fragment />;
278
+ }
279
+ return <FairysTaroValtioFormItem<T> {...props} />;
280
+ }
@@ -0,0 +1,54 @@
1
+ import { MObject } from 'interface';
2
+ import {
3
+ FairysTaroValtioFormInstance,
4
+ FairysTaroValtioFormInstanceContext,
5
+ useFairysTaroValtioFormInstance,
6
+ useFairysTaroValtioFormInstanceContext,
7
+ useFairysTaroValtioFormInstanceContextState,
8
+ } from './instance';
9
+ import { useMemo, type ReactNode } from 'react';
10
+ import { FairysTaroValtioFormLayout, FairysTaroValtioFormLayoutProps } from './layout';
11
+ import { FairysTaroValtioFormItem, FairysTaroValtioFormHideItem } from './form.item';
12
+ import { FairysTaroValtioFormConfigListItem, FairysTaroValtioFormConfigItem } from './item.config';
13
+ export * from './item.config';
14
+
15
+ export interface FairysTaroValtioFormProps<T extends MObject<T> = object> extends FairysTaroValtioFormLayoutProps {
16
+ /**表单实例*/
17
+ form?: FairysTaroValtioFormInstance<T>;
18
+ /**子元素*/
19
+ children: ReactNode;
20
+ /**表单项规则*/
21
+ rules?: FairysTaroValtioFormInstance<T>['rules'];
22
+ /**表单初始值*/
23
+ formData?: FairysTaroValtioFormInstance<T>['state'];
24
+ /**表单隐藏状态*/
25
+ hideState?: FairysTaroValtioFormInstance<T>['hideState'];
26
+ }
27
+
28
+ export function FairysTaroValtioForm<T extends MObject<T> = object>(props: FairysTaroValtioFormProps<T>) {
29
+ const { form, children, rules, formData, hideState, ...rest } = props;
30
+ const formInstance = useFairysTaroValtioFormInstance(form);
31
+ /**表单规则*/
32
+ formInstance.rules = rules;
33
+ /**初始化表单值*/
34
+ useMemo(() => formInstance.ctor({ formData, hideState }), []);
35
+ return (
36
+ <FairysTaroValtioFormInstanceContext.Provider value={formInstance}>
37
+ <FairysTaroValtioFormLayout {...rest}>{children}</FairysTaroValtioFormLayout>
38
+ </FairysTaroValtioFormInstanceContext.Provider>
39
+ );
40
+ }
41
+ /**初始化实例*/
42
+ FairysTaroValtioForm.useForm = useFairysTaroValtioFormInstance;
43
+ /**获取状态*/
44
+ FairysTaroValtioForm.useFormState = useFairysTaroValtioFormInstanceContextState;
45
+ /**获取上下文实例*/
46
+ FairysTaroValtioForm.useFormInstance = useFairysTaroValtioFormInstanceContext;
47
+ /**多个配置项*/
48
+ FairysTaroValtioForm.FormItemListItem = FairysTaroValtioFormConfigListItem;
49
+ /**单个配置项*/
50
+ FairysTaroValtioForm.FormItemConfig = FairysTaroValtioFormConfigItem;
51
+ /**表单项*/
52
+ FairysTaroValtioForm.FormItem = FairysTaroValtioFormItem;
53
+ /**隐藏表单想*/
54
+ FairysTaroValtioForm.FormHideItem = FairysTaroValtioFormHideItem;
@@ -0,0 +1,222 @@
1
+ import { MObject } from 'interface';
2
+ import { createContext, useContext, useRef } from 'react';
3
+ import { proxy, ref, snapshot, useSnapshot } from 'valtio';
4
+ import AsyncValidator, { RuleItem, ValidateFieldsError, Values } from 'async-validator';
5
+ import { copy } from 'fast-copy';
6
+
7
+ /**表单实例*/
8
+ export class FairysTaroValtioFormInstance<T extends MObject<T> = Record<string, any>> {
9
+ /**状态*/
10
+ state = proxy<T>({} as T);
11
+ /**
12
+ * 错误信息
13
+ */
14
+ errorState = proxy<Record<PropertyKey, string[]>>({} as Record<PropertyKey, string[]>);
15
+ /**隐藏状态*/
16
+ hideState = proxy<Record<PropertyKey, boolean>>({} as Record<PropertyKey, boolean>);
17
+ /**初始化表单值*/
18
+ ctor = (options?: { formData?: Partial<T>; hideState?: Partial<Record<PropertyKey, boolean>> }) => {
19
+ const { formData, hideState } = options || {};
20
+ this.state = proxy<T>({} as T);
21
+ this.errorState = proxy<Record<PropertyKey, string[]>>({} as Record<PropertyKey, string[]>);
22
+ this.hideState = proxy<Record<PropertyKey, boolean>>({} as Record<PropertyKey, boolean>);
23
+ if (formData) {
24
+ this.updated(copy(formData));
25
+ }
26
+ if (hideState) {
27
+ this.updatedHideInfo(copy(hideState));
28
+ }
29
+ };
30
+ /**
31
+ * 更新数据
32
+ * @param state 更新数据对象
33
+ * @param isValidate 是否验证(可选)
34
+ */
35
+ updated = <M = T>(state: Partial<M>, isValidate?: boolean) => {
36
+ const keys = Object.keys(state);
37
+ for (let index = 0; index < keys.length; index++) {
38
+ const key = keys[index];
39
+ this.state[key] = state[key];
40
+ }
41
+ if (isValidate) {
42
+ this.validate(keys, false);
43
+ }
44
+ };
45
+
46
+ // ===================================================隐藏状态================================================================
47
+ /**
48
+ * 更新行数据的隐藏信息
49
+ * @param objectHideInfo 行数据隐藏信息对象
50
+ */
51
+ updatedHideInfo = (objectHideInfo: Record<PropertyKey, boolean>) => {
52
+ const keys = Object.keys(objectHideInfo);
53
+ for (let index = 0; index < keys.length; index++) {
54
+ const field = keys[index];
55
+ this.hideState[field] = objectHideInfo[field];
56
+ }
57
+ return this;
58
+ };
59
+ /**
60
+ * 清理隐藏信息
61
+ */
62
+ clearHideInfo = (fields?: PropertyKey[]) => {
63
+ let _fields = fields;
64
+ if (!Array.isArray(fields)) {
65
+ _fields = Object.keys(this.hideState) as PropertyKey[];
66
+ }
67
+ for (let index = 0; index < _fields.length; index++) {
68
+ const field = _fields[index];
69
+ delete this.hideState[field];
70
+ }
71
+ return this;
72
+ };
73
+ // ===================================================隐藏状态===================================================================
74
+
75
+ // ===================================================错误信息处理================================================================
76
+ /**
77
+ * 更新行数据的错误信息
78
+ * @param objectErrorInfo 行数据错误信息对象
79
+ */
80
+ updatedErrorInfo = (objectErrorInfo: Record<PropertyKey, string[]>) => {
81
+ const keys = Object.keys(objectErrorInfo);
82
+ for (let index = 0; index < keys.length; index++) {
83
+ const field = keys[index];
84
+ this.errorState[field] = objectErrorInfo[field];
85
+ }
86
+ return this;
87
+ };
88
+ /**
89
+ * 清理错误信息
90
+ */
91
+ clearErrorInfo = (fields?: PropertyKey[]) => {
92
+ let _fields = fields;
93
+ if (!Array.isArray(fields)) {
94
+ _fields = Object.keys(this.errorState) as PropertyKey[];
95
+ }
96
+ for (let index = 0; index < _fields.length; index++) {
97
+ const field = _fields[index];
98
+ delete this.errorState[field];
99
+ }
100
+ return this;
101
+ };
102
+ // ===================================================错误信息处理================================================================
103
+
104
+ /**
105
+ * 清理所有数据
106
+ */
107
+ clear = () => {
108
+ this.state = proxy<T>({} as T);
109
+ this.errorState = proxy<Record<PropertyKey, string[]>>({} as Record<keyof T, string[]>);
110
+ this.hideState = proxy<Record<PropertyKey, boolean>>({} as Record<keyof T, boolean>);
111
+ };
112
+
113
+ // ===================================================规则处理================================================================
114
+ /**列规则 */
115
+ rules: Record<
116
+ PropertyKey,
117
+ ((formData: T, instance: FairysTaroValtioFormInstance<T>) => RuleItem[] | Promise<RuleItem[]>) | RuleItem[]
118
+ > = {};
119
+ /**规则验证
120
+ * @param fields 列字段数组(可选)
121
+ * @param isReturn 是否返回验证结果(可选)
122
+ */
123
+ validate = async (fields?: PropertyKey[], isReturn: boolean = true): Promise<ValidateFieldsError | Values> => {
124
+ let _fields = fields;
125
+ const _formData = snapshot(this.state) as T;
126
+ // 没有规则,直接返回数据
127
+ if (!this.rules) {
128
+ return Promise.resolve({ ..._formData });
129
+ }
130
+ const rules: Record<PropertyKey, RuleItem[]> = {};
131
+ let isNeedValidate = false;
132
+ // 没有 fields 值,验证所有
133
+ if (!fields || (Array.isArray(fields) && fields.length === 0)) {
134
+ _fields = Object.keys(this.rules);
135
+ }
136
+ for (let index = 0; index < _fields.length; index++) {
137
+ isNeedValidate = true;
138
+ const element = _fields[index];
139
+ const rule = this.rules[element];
140
+ if (typeof rule === 'function') {
141
+ const _rules = await rule(_formData, this);
142
+ rules[element] = _rules;
143
+ } else if (Array.isArray(rule)) {
144
+ rules[element] = rule;
145
+ }
146
+ }
147
+ if (!isNeedValidate) {
148
+ console.warn('no rules to validate');
149
+ return Promise.resolve({ ..._formData });
150
+ }
151
+ return new Promise((resolve, reject) => {
152
+ new AsyncValidator({ ...rules }).validate({ ..._formData }, (errors, fields) => {
153
+ for (let index = 0; index < _fields.length; index++) {
154
+ const field = _fields[index];
155
+ const fidError = Array.isArray(errors) ? errors.filter((item) => item.field === field) : undefined;
156
+ if (fidError) {
157
+ this.errorState[field] = ref(fidError.map((item) => item.message || ''));
158
+ } else {
159
+ delete this.errorState[field];
160
+ }
161
+ }
162
+ if (isReturn) {
163
+ if (errors) {
164
+ reject({ errors, fields });
165
+ } else {
166
+ resolve(fields);
167
+ }
168
+ }
169
+ });
170
+ });
171
+ };
172
+ }
173
+
174
+ /**声明实例*/
175
+ export function useFairysTaroValtioFormInstance<T extends MObject<T> = object>(
176
+ instance?: FairysTaroValtioFormInstance<T>,
177
+ ) {
178
+ const ref = useRef<FairysTaroValtioFormInstance<T>>();
179
+ if (!ref.current) {
180
+ if (instance) {
181
+ ref.current = instance;
182
+ } else {
183
+ ref.current = new FairysTaroValtioFormInstance<T>();
184
+ }
185
+ }
186
+ return ref.current;
187
+ }
188
+
189
+ /**表单实例上下文*/
190
+ export const FairysTaroValtioFormInstanceContext = createContext<FairysTaroValtioFormInstance<any>>(
191
+ new FairysTaroValtioFormInstance<any>(),
192
+ );
193
+
194
+ /**表单实例上下文*/
195
+ export function useFairysTaroValtioFormInstanceContext<T extends MObject<T> = object>() {
196
+ return useContext(FairysTaroValtioFormInstanceContext) as FairysTaroValtioFormInstance<T>;
197
+ }
198
+
199
+ /**状态取值*/
200
+ export function useFairysTaroValtioFormInstanceContextState<T extends MObject<T> = object>() {
201
+ const instance = useFairysTaroValtioFormInstanceContext<T>();
202
+ const state = useSnapshot(instance.state) as T;
203
+ const errorState = useSnapshot(instance.errorState) as Record<PropertyKey, string[]>;
204
+ return [state, errorState, instance, (state as any).__defaultValue, errorState.__defaultValue] as [
205
+ T,
206
+ Record<PropertyKey, string[]>,
207
+ FairysTaroValtioFormInstance<T>,
208
+ any,
209
+ any,
210
+ ];
211
+ }
212
+
213
+ /**隐藏组件状态取值*/
214
+ export function useFairysTaroValtioFormInstanceContextHideState<T extends MObject<T> = object>() {
215
+ const instance = useFairysTaroValtioFormInstanceContext<T>();
216
+ const hideState = useSnapshot(instance.hideState) as Record<PropertyKey, boolean>;
217
+ return [hideState, instance, (hideState as any).__defaultValue] as [
218
+ Record<PropertyKey, boolean>,
219
+ FairysTaroValtioFormInstance<T>,
220
+ any,
221
+ ];
222
+ }