@fairys/valtio-form-basic 0.0.13 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/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": "0.0.13",
6
+ "version": "1.0.0",
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.mountRules = {}; //由表单项挂载规则,(根据表单项的字段存储路径对应校验规则)
50
- this.nameToPaths = {}; //表单项名称到路径映射
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.state = proxy<T>({} as T); //表单值
158
- this.errorState = proxy<Record<PropertyKey, string[]>>({}); //错误信息
159
- this.hideState = proxy<Record<PropertyKey, boolean>>({}); //隐藏状态
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 (fields?: PropertyKey[], isReturn: boolean = true): Promise<ValidateFieldsError | Values> => {
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> = object>(instance?: FairysValtioFormInstance<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> = object>() {
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> = object>() {
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> = object>() {
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 路径
@@ -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> = object> {
12
+ export interface FairysValtioFormItemAttrsProps<T extends MObject<T> = Record<string, any>> {
13
13
  /**平台*/
14
14
  platform?: 'pc' | 'rn' | 'taro';
15
15
  /**
@@ -81,6 +81,11 @@ export interface FairysValtioFormItemAttrsProps<T extends MObject<T> = object> {
81
81
  isJoinParentField?: boolean;
82
82
  /**校验规则*/
83
83
  rules?: RuleItem[];
84
+
85
+ /**卸载移除数据值
86
+ * @default true
87
+ */
88
+ isRemoveValueOnUnmount?: boolean;
84
89
  }
85
90
 
86
91
  /**
@@ -126,7 +131,9 @@ export const FormItem = (props: FormItemProps) => {
126
131
  * ```
127
132
  *
128
133
  */
129
- export function useFairysValtioFormItemAttrs<T extends MObject<T> = object>(props: FairysValtioFormItemAttrsProps<T>) {
134
+ export function useFairysValtioFormItemAttrs<T extends MObject<T> = Record<string, any>>(
135
+ props: FairysValtioFormItemAttrsProps<T>,
136
+ ) {
130
137
  const [layoutAttrs] = useFairysValtioFormLayoutContext();
131
138
  const colCount = layoutAttrs.colCount || 1;
132
139
  const parent_borderedType = layoutAttrs.itemBorderType || 'bottom';
@@ -173,6 +180,7 @@ export function useFairysValtioFormItemAttrs<T extends MObject<T> = object>(prop
173
180
  isJoinParentField = true,
174
181
  rules,
175
182
  platform = parent_platform,
183
+ isRemoveValueOnUnmount = true,
176
184
  } = props;
177
185
 
178
186
  const {
@@ -217,6 +225,14 @@ export function useFairysValtioFormItemAttrs<T extends MObject<T> = object>(prop
217
225
  }
218
226
  };
219
227
 
228
+ useEffect(() => {
229
+ return () => {
230
+ if (isRemoveValueOnUnmount) {
231
+ formInstance.removeValueByPaths(_name);
232
+ }
233
+ };
234
+ }, []);
235
+
220
236
  /**基础组件参数*/
221
237
  const baseControl = {
222
238
  ...attrs,
@@ -420,7 +436,7 @@ export function useFairysValtioFormItemAttrs<T extends MObject<T> = object>(prop
420
436
  } as FairysValtioFormItemAttrsReturn<T>;
421
437
  }
422
438
 
423
- export interface FairysValtioFormItemAttrsReturn<T extends MObject<T> = object> {
439
+ export interface FairysValtioFormItemAttrsReturn<T extends MObject<T> = Record<string, any>> {
424
440
  /**表单项值*/
425
441
  value?: any;
426
442
  /**是否校验错误*/
@@ -507,7 +523,7 @@ export const FormItem = (props: FormItemProps) => {
507
523
  }
508
524
  * ```
509
525
  */
510
- export function useFairysValtioFormItemNoStyleAttrs<T extends MObject<T> = object>(
526
+ export function useFairysValtioFormItemNoStyleAttrs<T extends MObject<T> = Record<string, any>>(
511
527
  props: FairysValtioFormItemAttrsProps<T>,
512
528
  ) {
513
529
  const {
@@ -522,6 +538,7 @@ export function useFairysValtioFormItemNoStyleAttrs<T extends MObject<T> = objec
522
538
  attrs = {},
523
539
  isJoinParentField = true,
524
540
  rules,
541
+ isRemoveValueOnUnmount = true,
525
542
  } = props;
526
543
  const [state, errorState, formInstance] = useFairysValtioFormInstanceContextState<T>();
527
544
  const {
@@ -563,6 +580,13 @@ export function useFairysValtioFormItemNoStyleAttrs<T extends MObject<T> = objec
563
580
  onAfterUpdate(_value, formInstance, event);
564
581
  }
565
582
  };
583
+ useEffect(() => {
584
+ return () => {
585
+ if (isRemoveValueOnUnmount) {
586
+ formInstance.removeValueByPaths(_name);
587
+ }
588
+ };
589
+ }, []);
566
590
  /**基础组件参数*/
567
591
  const baseControl = {
568
592
  ...attrs,
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> = object> extends FairysValtioFormLayoutAttrsProps {
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> = object>(
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);