react-form-manage 1.0.8-beta.7 → 1.0.8

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 (94) hide show
  1. package/CHANGELOG.md +173 -4
  2. package/README.md +8 -4
  3. package/dist/components/Form/FormCleanUp.js +3 -3
  4. package/dist/components/Form/FormItem.d.ts +10 -4
  5. package/dist/components/Form/FormItem.js +52 -14
  6. package/dist/components/Form/FormList.d.ts +2 -2
  7. package/dist/components/Form/FormList.js +2 -2
  8. package/dist/constants/form.d.ts +1 -1
  9. package/dist/hooks/useFormItemControl.d.ts +8 -3
  10. package/dist/hooks/useFormItemControl.js +64 -28
  11. package/dist/hooks/useFormListControl.d.ts +2 -1
  12. package/dist/hooks/useFormListControl.js +85 -19
  13. package/dist/index.cjs.d.ts +1 -0
  14. package/dist/index.d.ts +4 -3
  15. package/dist/index.esm.d.ts +1 -0
  16. package/dist/index.js +4 -2
  17. package/dist/providers/Form.d.ts +15 -2
  18. package/dist/providers/Form.js +226 -41
  19. package/dist/stores/formStore.d.ts +44 -4
  20. package/dist/stores/formStore.js +42 -7
  21. package/dist/test/CommonTest.d.ts +3 -0
  22. package/dist/test/CommonTest.js +49 -0
  23. package/dist/test/TestDialog.d.ts +3 -0
  24. package/dist/test/TestDialog.js +21 -0
  25. package/dist/test/TestListener.d.ts +3 -0
  26. package/dist/test/TestListener.js +17 -0
  27. package/dist/test/TestNotFormWrapper.d.ts +3 -0
  28. package/dist/test/TestNotFormWrapper.js +15 -0
  29. package/dist/test/TestSelect.d.ts +6 -0
  30. package/dist/test/TestSelect.js +24 -0
  31. package/dist/test/TestWatchNormalize.d.ts +3 -0
  32. package/dist/test/TestWatchNormalize.js +23 -0
  33. package/dist/test/TestWrapperFormItem.d.ts +3 -0
  34. package/dist/test/TestWrapperFormItem.js +13 -0
  35. package/dist/test/testSetValue/TestCase10_SetFieldValues_ComplexNested.d.ts +21 -0
  36. package/dist/test/testSetValue/TestCase10_SetFieldValues_ComplexNested.js +61 -0
  37. package/dist/test/testSetValue/TestCase1_PlainObjectToPrimitives.d.ts +16 -0
  38. package/dist/test/testSetValue/TestCase1_PlainObjectToPrimitives.js +18 -0
  39. package/dist/test/testSetValue/TestCase2_PlainObjectToFormList.d.ts +21 -0
  40. package/dist/test/testSetValue/TestCase2_PlainObjectToFormList.js +33 -0
  41. package/dist/test/testSetValue/TestCase3_ArrayNonListenerToPrimitives.d.ts +21 -0
  42. package/dist/test/testSetValue/TestCase3_ArrayNonListenerToPrimitives.js +26 -0
  43. package/dist/test/testSetValue/TestCase4_PlainObjectRemovedFields.d.ts +20 -0
  44. package/dist/test/testSetValue/TestCase4_PlainObjectRemovedFields.js +32 -0
  45. package/dist/test/testSetValue/TestCase5_FormListRemovedItems.d.ts +22 -0
  46. package/dist/test/testSetValue/TestCase5_FormListRemovedItems.js +29 -0
  47. package/dist/test/testSetValue/TestCase6_NestedFormListRemoved.d.ts +28 -0
  48. package/dist/test/testSetValue/TestCase6_NestedFormListRemoved.js +36 -0
  49. package/dist/test/testSetValue/TestCase7_SetFieldValues_MixedStructure.d.ts +17 -0
  50. package/dist/test/testSetValue/TestCase7_SetFieldValues_MixedStructure.js +33 -0
  51. package/dist/test/testSetValue/TestCase8_SetFieldValues_NestedObject.d.ts +27 -0
  52. package/dist/test/testSetValue/TestCase8_SetFieldValues_NestedObject.js +57 -0
  53. package/dist/test/testSetValue/TestCase9_SetFieldValues_MultipleArrays.d.ts +25 -0
  54. package/dist/test/testSetValue/TestCase9_SetFieldValues_MultipleArrays.js +46 -0
  55. package/dist/test/testSetValue/index.d.ts +2 -0
  56. package/dist/test/testSetValue/index.js +28 -0
  57. package/dist/types/index.d.ts +1 -1
  58. package/dist/types/public.d.ts +1 -1
  59. package/dist/utils/obj.util.d.ts +29 -1
  60. package/dist/utils/obj.util.js +59 -5
  61. package/package.json +2 -1
  62. package/src/App.tsx +39 -156
  63. package/src/DEEP_TRIGGER_LOGIC.md +573 -0
  64. package/src/components/Form/FormCleanUp.tsx +4 -8
  65. package/src/components/Form/FormItem.tsx +174 -57
  66. package/src/components/Form/FormList.tsx +17 -4
  67. package/src/constants/form.ts +1 -1
  68. package/src/hooks/useFormItemControl.ts +78 -32
  69. package/src/hooks/useFormListControl.ts +133 -43
  70. package/src/index.ts +25 -13
  71. package/src/main.tsx +6 -1
  72. package/src/providers/Form.tsx +454 -26
  73. package/src/stores/formStore.ts +363 -283
  74. package/src/test/CommonTest.tsx +177 -0
  75. package/src/test/TestDialog.tsx +52 -0
  76. package/src/test/TestListener.tsx +21 -0
  77. package/src/test/TestNotFormWrapper.tsx +43 -0
  78. package/src/test/TestSelect.tsx +38 -0
  79. package/src/test/TestWatchNormalize.tsx +32 -0
  80. package/src/test/TestWrapperFormItem.tsx +34 -0
  81. package/src/test/testSetValue/TestCase10_SetFieldValues_ComplexNested.tsx +203 -0
  82. package/src/test/testSetValue/TestCase1_PlainObjectToPrimitives.tsx +72 -0
  83. package/src/test/testSetValue/TestCase2_PlainObjectToFormList.tsx +114 -0
  84. package/src/test/testSetValue/TestCase3_ArrayNonListenerToPrimitives.tsx +99 -0
  85. package/src/test/testSetValue/TestCase4_PlainObjectRemovedFields.tsx +112 -0
  86. package/src/test/testSetValue/TestCase5_FormListRemovedItems.tsx +119 -0
  87. package/src/test/testSetValue/TestCase6_NestedFormListRemoved.tsx +185 -0
  88. package/src/test/testSetValue/TestCase7_SetFieldValues_MixedStructure.tsx +110 -0
  89. package/src/test/testSetValue/TestCase8_SetFieldValues_NestedObject.tsx +162 -0
  90. package/src/test/testSetValue/TestCase9_SetFieldValues_MultipleArrays.tsx +169 -0
  91. package/src/test/testSetValue/index.tsx +100 -0
  92. package/src/types/index.ts +1 -1
  93. package/src/types/public.ts +1 -1
  94. package/src/utils/obj.util.ts +153 -13
@@ -3,18 +3,22 @@ import { useEffect, useState } from "react";
3
3
  import { v4 } from "uuid";
4
4
  import { useShallow } from "zustand/react/shallow";
5
5
  import { useFormContext } from "../providers/Form";
6
- import { useFormCleanUp, useFormStore } from "../stores/formStore";
6
+ import { useFormStore } from "../stores/formStore";
7
7
  function useFormListControl({ name, form, initialValues, formName }) {
8
+ const [formItemId] = useState(v4());
8
9
  const contextForm = useFormContext();
9
10
  const getFormValues = useFormStore((state) => state.getFormValues);
10
11
  const [listFormInitValues, setListFormInitValues] = useState(void 0);
11
- const { clearCacheData, setCacheData } = useFormStore(useShallow((state) => ({
12
+ const { clearCacheData, setCacheData, setListener, getListener, clearArrItems } = useFormStore(useShallow((state) => ({
13
+ // Cache
12
14
  cacheData: state.cacheData,
13
15
  clearCacheData: state.clearCacheData,
14
- setCacheData: state.setCacheData
15
- })));
16
- const { setCleanUpStack } = useFormCleanUp(useShallow((state) => ({
17
- setCleanUpStack: state.setCleanUpStack
16
+ setCacheData: state.setCacheData,
17
+ // Listener
18
+ setListener: state.setListener,
19
+ getListener: state.getListener,
20
+ // Clear Arr Items
21
+ clearArrItems: state.clearArrItems
18
22
  })));
19
23
  const { initValue: internalInitValue, formState } = useFormStore(useShallow((state) => {
20
24
  return {
@@ -37,29 +41,33 @@ function useFormListControl({ name, form, initialValues, formName }) {
37
41
  value: d
38
42
  };
39
43
  }).filter(Boolean);
40
- const mapCurWithKey = cur.map((c) => mapPrevWithKey.find((m) => m.key === c.key) || c);
44
+ const mapCurWithKey = cur.map((c) => {
45
+ const find = mapPrevWithKey.find((m) => m.key === c.key);
46
+ if (find) {
47
+ return {
48
+ key: find.key,
49
+ value: isNil(c.value) ? find.value : c.value
50
+ };
51
+ }
52
+ return c;
53
+ });
41
54
  const getNewValueCache = mapCurWithKey.filter(Boolean).map((c) => c.value);
42
55
  const startRemoveIndex = formDataBeforeChange.length - getNewValueCache.length;
43
56
  if (startRemoveIndex > 0) {
44
- Array.from(Array(startRemoveIndex)).map((_, index) => {
45
- return getNewValueCache.length + index;
46
- }).forEach((index) => {
47
- setCleanUpStack({
57
+ const clearItems = Array.from(Array(startRemoveIndex)).map((_, index) => {
58
+ const clearIndex = getNewValueCache.length + index;
59
+ return {
48
60
  formName: formName || (form == null ? void 0 : form.formName) || (contextForm == null ? void 0 : contextForm.formName),
49
- name: `${name}.${index}`,
50
- type: "array"
51
- });
61
+ name: `${name}.${clearIndex}`
62
+ };
52
63
  });
64
+ clearArrItems(clearItems);
53
65
  }
54
66
  setCacheData(formName || (form == null ? void 0 : form.formName) || (contextForm == null ? void 0 : contextForm.formName), name, getNewValueCache);
55
67
  };
56
68
  const add = (index) => {
57
69
  setListFields((prev) => {
58
- if (index > prev.length)
59
- return prev;
60
- if (index < 0)
61
- return prev;
62
- if (index === prev.length) {
70
+ if (isNil(index) || index === prev.length) {
63
71
  const newName = `${name}.${prev.length}`;
64
72
  const newKey = v4();
65
73
  const result2 = [
@@ -71,6 +79,10 @@ function useFormListControl({ name, form, initialValues, formName }) {
71
79
  ];
72
80
  return result2;
73
81
  }
82
+ if (index > prev.length)
83
+ return prev;
84
+ if (index < 0)
85
+ return prev;
74
86
  const clonePrev = [...prev];
75
87
  const result = clonePrev.reduce((prev2, cur, curIndex) => {
76
88
  const newKey = v4();
@@ -180,6 +192,12 @@ function useFormListControl({ name, form, initialValues, formName }) {
180
192
  });
181
193
  setListFields(result);
182
194
  setCacheData(formName || (form == null ? void 0 : form.formName) || (contextForm == null ? void 0 : contextForm.formName), name, listFormInitValues);
195
+ if (getListener(formItemId)) {
196
+ setListener({
197
+ formItemId,
198
+ isInitied: true
199
+ });
200
+ }
183
201
  return;
184
202
  }
185
203
  if (Array.isArray(internalInitValue)) {
@@ -193,6 +211,12 @@ function useFormListControl({ name, form, initialValues, formName }) {
193
211
  });
194
212
  setListFields(result);
195
213
  setListFormInitValues(internalInitValue);
214
+ if (getListener(formItemId)) {
215
+ setListener({
216
+ formItemId,
217
+ isInitied: true
218
+ });
219
+ }
196
220
  return;
197
221
  }
198
222
  if (Array.isArray(initialValues)) {
@@ -209,6 +233,12 @@ function useFormListControl({ name, form, initialValues, formName }) {
209
233
  }
210
234
  setListFields(result);
211
235
  setListFormInitValues(initialValues);
236
+ if (getListener(formItemId)) {
237
+ setListener({
238
+ formItemId,
239
+ isInitied: true
240
+ });
241
+ }
212
242
  return;
213
243
  }
214
244
  }
@@ -218,6 +248,42 @@ function useFormListControl({ name, form, initialValues, formName }) {
218
248
  clearCacheData();
219
249
  };
220
250
  }, [listFields]);
251
+ useEffect(() => {
252
+ if (!getListener(formItemId)) {
253
+ setListener({
254
+ formName: formName || (form == null ? void 0 : form.formName) || (contextForm == null ? void 0 : contextForm.formName),
255
+ name: name || "",
256
+ formItemId,
257
+ type: "array",
258
+ onArrayChange: (newArr) => {
259
+ setListFields((prev) => {
260
+ const result = newArr.map((_, i) => {
261
+ const itemName = `${name}.${i}`;
262
+ const existingItem = prev[i];
263
+ return {
264
+ key: existingItem ? existingItem.key : v4(),
265
+ name: itemName
266
+ };
267
+ });
268
+ handleCacheListField(prev, result.map((r, i) => {
269
+ return { ...r, value: newArr[i] };
270
+ }));
271
+ return result;
272
+ });
273
+ }
274
+ });
275
+ }
276
+ return () => {
277
+ if (getListener(formItemId)) {
278
+ setListener({
279
+ formName: formName || (form == null ? void 0 : form.formName) || (contextForm == null ? void 0 : contextForm.formName),
280
+ name: name || "",
281
+ formItemId,
282
+ onArrayChange: void 0
283
+ });
284
+ }
285
+ };
286
+ }, []);
221
287
  return { listFields, move, add, remove };
222
288
  }
223
289
  export {
@@ -0,0 +1 @@
1
+ export * from "./index";
package/dist/index.d.ts CHANGED
@@ -1,10 +1,11 @@
1
- import Form, { useForm, useWatch, useSubmitDataWatch, useFormStateWatch, type FormProps, type ValidationRule, type FormFieldError, type SubmitState, type UseFormItemStateWatchReturn } from "./providers/Form";
2
1
  import { SUBMIT_STATE } from "./constants/form";
2
+ import Form, { useForm, useFormStateWatch, useSubmitDataWatch, useWatch, type FormFieldError, type FormProps, type SubmitState, type UseFormItemStateWatchReturn, type ValidationRule } from "./providers/Form";
3
3
  import FormItem, { type FormItemProps } from "./components/Form/FormItem";
4
4
  import FormList, { type FormListProps } from "./components/Form/FormList";
5
- import Input from "./components/Input";
6
5
  import InputWrapper, { type InputWrapperProps } from "./components/Form/InputWrapper";
6
+ import Input from "./components/Input";
7
7
  import useFormItemControl from "./hooks/useFormItemControl";
8
8
  import useFormListControl from "./hooks/useFormListControl";
9
- export { Form, FormItem, FormList, Input, InputWrapper, useFormItemControl, useFormListControl, useForm, useWatch, useSubmitDataWatch, useFormStateWatch, type FormProps, type FormItemProps, type FormListProps, type InputWrapperProps, type ValidationRule, type FormFieldError, type SubmitState, type UseFormItemStateWatchReturn, SUBMIT_STATE, };
9
+ import { useFormStore, type CleanUpItem, type FormInstance, type ListenerItem } from "./stores/formStore";
10
+ export { Form, FormItem, FormList, Input, InputWrapper, SUBMIT_STATE, useForm, useFormItemControl, useFormListControl, useFormStateWatch, useFormStore, useSubmitDataWatch, useWatch, type CleanUpItem, type FormFieldError, type FormInstance, type FormItemProps, type FormListProps, type FormProps, type InputWrapperProps, type ListenerItem, type SubmitState, type UseFormItemStateWatchReturn, type ValidationRule, };
10
11
  export default Form;
@@ -0,0 +1 @@
1
+ export * from "./index";
package/dist/index.js CHANGED
@@ -1,11 +1,12 @@
1
- import Form, { useForm, useWatch, useSubmitDataWatch, useFormStateWatch } from "./providers/Form";
2
1
  import { SUBMIT_STATE } from "./constants/form";
2
+ import Form, { useForm, useFormStateWatch, useSubmitDataWatch, useWatch } from "./providers/Form";
3
3
  import FormItem from "./components/Form/FormItem";
4
4
  import FormList from "./components/Form/FormList";
5
- import Input from "./components/Input";
6
5
  import InputWrapper from "./components/Form/InputWrapper";
6
+ import Input from "./components/Input";
7
7
  import useFormItemControl from "./hooks/useFormItemControl";
8
8
  import useFormListControl from "./hooks/useFormListControl";
9
+ import { useFormStore } from "./stores/formStore";
9
10
  var stdin_default = Form;
10
11
  export {
11
12
  Form,
@@ -19,6 +20,7 @@ export {
19
20
  useFormItemControl,
20
21
  useFormListControl,
21
22
  useFormStateWatch,
23
+ useFormStore,
22
24
  useSubmitDataWatch,
23
25
  useWatch
24
26
  };
@@ -1,8 +1,14 @@
1
1
  import type { ComponentType, FormHTMLAttributes, ReactNode } from "react";
2
+ import FormItem from "../components/Form/FormItem";
3
+ import { OnChangeOptions } from "../hooks/useFormItemControl";
2
4
  import type { PublicFormInstance, UseFormItemStateWatchReturn } from "../types/public";
3
- export type { FormFieldError, SubmitState, UseFormItemStateWatchReturn, ValidationRule, } from "../types/public";
5
+ export type { FormFieldError, SubmitState, UseFormItemStateWatchReturn, ValidationRule } from "../types/public";
4
6
  export declare const FormContext: import("react").Context<any>;
7
+ export interface SetFieldValueOptions extends OnChangeOptions {
8
+ deepTrigger?: boolean;
9
+ }
5
10
  export interface FormProps<T = any> extends Omit<FormHTMLAttributes<HTMLFormElement>, "onSubmit"> {
11
+ collectHiddenFields?: boolean;
6
12
  children: ReactNode;
7
13
  formName: string;
8
14
  initialValues?: T;
@@ -15,10 +21,12 @@ export interface FormProps<T = any> extends Omit<FormHTMLAttributes<HTMLFormElem
15
21
  }) => void | Promise<void>;
16
22
  FormElement?: ComponentType<any>;
17
23
  }
18
- declare function Form<T = any>({ children, formName, initialValues, onFinish, onReject, onFinally, FormElement, ...props }: FormProps<T>): import("react/jsx-runtime").JSX.Element;
24
+ declare function Form<T = any>({ children, formName, initialValues, onFinish, onReject, onFinally, FormElement, collectHiddenFields: formCollectHiddenFields, ...props }: FormProps<T>): import("react/jsx-runtime").JSX.Element;
19
25
  declare namespace Form {
20
26
  var useForm: typeof import("./Form").useForm;
27
+ var Item: typeof FormItem;
21
28
  var useWatch: typeof import("./Form").useWatch;
29
+ var useWatchNormalized: typeof import("./Form").useWatchNormalized;
22
30
  var useSubmitDataWatch: typeof import("./Form").useSubmitDataWatch;
23
31
  var useFormStateWatch: <T = any>(formNameOrFormInstance?: string | PublicFormInstance<T>) => any;
24
32
  var useFormItemStateWatch: <T = any>(nameOrFormItemId: string, formNameOrFormInstance?: string | PublicFormInstance<T>) => UseFormItemStateWatchReturn;
@@ -27,6 +35,11 @@ export default Form;
27
35
  export declare function useFormContext(): any;
28
36
  export declare function useForm<T = any>(formNameOrFormInstance?: string | PublicFormInstance<T>): PublicFormInstance<T>[];
29
37
  export declare function useWatch<T = any>(name: keyof T & string, formNameOrFormInstance?: string | PublicFormInstance<T>): T[keyof T] | undefined;
38
+ export declare function useWatchNormalized<T, TFn extends (v: any) => any>({ name, normalizeFn, formNameOrFormInstance, }: {
39
+ name: keyof T & string;
40
+ normalizeFn: TFn;
41
+ formNameOrFormInstance?: string | PublicFormInstance<T>;
42
+ }): ReturnType<TFn>;
30
43
  export declare function useSubmitDataWatch<T = any>({ formNameOrFormInstance, triggerWhenChange, mapFn, }: {
31
44
  formNameOrFormInstance?: string | PublicFormInstance<T>;
32
45
  triggerWhenChange?: boolean;
@@ -1,40 +1,50 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { cloneDeep, get, isEqual, last, set, uniq } from "lodash";
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { cloneDeep, filter, get, isArray, isEqual, isNil, isPlainObject, last, set, uniqBy } from "lodash";
3
3
  import { useTask } from "minh-custom-hooks-release";
4
- import { createContext, useContext, useEffect, useState } from "react";
4
+ import { createContext, useContext, useEffect, useMemo, useState } from "react";
5
5
  import { flushSync } from "react-dom";
6
6
  import { useShallow } from "zustand/react/shallow";
7
- import FormCleanUp from "../components/Form/FormCleanUp";
7
+ import FormItem from "../components/Form/FormItem";
8
8
  import { SUBMIT_STATE } from "../constants/form";
9
- import { useFormListeners, useFormStore } from "../stores/formStore";
10
- import { getAllNoneObjStringPath } from "../utils/obj.util";
9
+ import { useFormStore } from "../stores/formStore";
10
+ import { getAllNoneObjStringPath, getAllPathsIncludingContainers, getAllPathsStopAtArray } from "../utils/obj.util";
11
11
  const FormContext = createContext(null);
12
- function Form({ children, formName, initialValues, onFinish, onReject, onFinally, FormElement, ...props }) {
13
- const { appInitValue, getFormItemValue, setInitData, setData, getFormValues, setFormState, setFormInstance, revokeFormInstance, setSubmitHistory, clearFormValues, clearFormInitialValues, clearFormState } = useFormStore(useShallow((state) => {
14
- var _a;
15
- return {
16
- appInitValue: state.initialValues,
17
- setInitData: state.setInitData,
18
- getFormValues: state.getFormValues,
19
- setFormState: state.setFormState,
20
- setFormInstance: state.setFormInstance,
21
- revokeFormInstance: state.revokeFormInstance,
22
- setData: state.setData,
23
- setSubmitHistory: state.setSubmitHistory,
24
- getFormItemValue: state.getFormItemValue,
25
- clearFormValues: state.clearFormValues,
26
- clearFormInitialValues: state.clearFormInitialValues,
27
- clearFormState: state.clearFormState,
28
- // Test, nhớ xóa sau khi xong
29
- formStates: (_a = state.formStates) == null ? void 0 : _a[formName]
30
- };
31
- }));
32
- const { getListeners } = useFormListeners(useShallow((state) => {
12
+ function Form({ children, formName, initialValues, onFinish, onReject, onFinally, FormElement, collectHiddenFields: formCollectHiddenFields = true, ...props }) {
13
+ const {
14
+ // appInitValue,
15
+ getFormItemValue,
16
+ setInitData,
17
+ setData,
18
+ getFormValues,
19
+ setFormState,
20
+ setFormInstance,
21
+ revokeFormInstance,
22
+ setSubmitHistory,
23
+ clearFormValues,
24
+ clearFormInitialValues,
25
+ clearFormState
26
+ } = useFormStore(useShallow((state) => ({
27
+ // appInitValue: state.initialValues,
28
+ setInitData: state.setInitData,
29
+ getFormValues: state.getFormValues,
30
+ setFormState: state.setFormState,
31
+ setFormInstance: state.setFormInstance,
32
+ revokeFormInstance: state.revokeFormInstance,
33
+ setData: state.setData,
34
+ setSubmitHistory: state.setSubmitHistory,
35
+ getFormItemValue: state.getFormItemValue,
36
+ clearFormValues: state.clearFormValues,
37
+ clearFormInitialValues: state.clearFormInitialValues,
38
+ clearFormState: state.clearFormState
39
+ // Test, nhớ xóa sau khi xong
40
+ // formStates: state.formStates?.[formName],
41
+ })));
42
+ const { getListeners } = useFormStore(useShallow((state) => {
33
43
  return {
34
44
  getListeners: state.getListeners
35
45
  };
36
46
  }));
37
- const setFieldValue = (name, value, options) => {
47
+ const handlePrimitiveValue = (name, value, options) => {
38
48
  const listener = getListeners().find((l) => l.name === name && l.formName === formName);
39
49
  if (listener) {
40
50
  listener.onChange(value, options);
@@ -42,20 +52,170 @@ function Form({ children, formName, initialValues, onFinish, onReject, onFinally
42
52
  setData(formName, name, value);
43
53
  }
44
54
  };
55
+ const handleArrayListener = (name, value, options, coreRecursive) => {
56
+ const listener = getListeners().find((l) => l.name === name && l.formName === formName);
57
+ if (!listener)
58
+ return;
59
+ const currentValue = getFormItemValue(formName, name);
60
+ if (!isEqual(currentValue, value)) {
61
+ listener.onArrayChange(value, options);
62
+ value.forEach((item, index) => {
63
+ const itemName = `${name}.${index}`;
64
+ const itemListener = getListeners().find((l) => l.name === itemName && l.formName === formName);
65
+ if (itemListener) {
66
+ itemListener.onChange(item, options);
67
+ }
68
+ const nestedPaths = getAllPathsIncludingContainers(item);
69
+ nestedPaths.forEach((p) => {
70
+ if (coreRecursive) {
71
+ coreRecursive(`${itemName}.${p}`, get(item, p), options);
72
+ }
73
+ });
74
+ });
75
+ if (isArray(currentValue) && currentValue.length > value.length) {
76
+ for (let index = value.length; index < currentValue.length; index++) {
77
+ const itemName = `${name}.${index}`;
78
+ if (coreRecursive) {
79
+ coreRecursive(itemName, void 0, options);
80
+ }
81
+ }
82
+ }
83
+ }
84
+ };
85
+ const handlePlainObject = (name, value, options, coreRecursive) => {
86
+ const listener = getListeners().find((l) => l.name === name && l.formName === formName);
87
+ if (listener && listener.type !== "array") {
88
+ listener.onChange(value, options);
89
+ }
90
+ const allPaths = getAllPathsIncludingContainers(value);
91
+ allPaths.forEach((p) => {
92
+ if (coreRecursive) {
93
+ const fullPath = `${name}.${p}`;
94
+ coreRecursive(fullPath, get(value, p), options);
95
+ }
96
+ });
97
+ const previousValue = getFieldValue(name);
98
+ if (isPlainObject(previousValue)) {
99
+ const previousKeys = Object.keys(previousValue);
100
+ const newKeys = Object.keys(value);
101
+ const removedKeys = previousKeys.filter((k) => !newKeys.includes(k));
102
+ removedKeys.forEach((key) => {
103
+ if (coreRecursive) {
104
+ coreRecursive(`${name}.${key}`, void 0, options);
105
+ }
106
+ });
107
+ }
108
+ };
109
+ const handleNonListenerArray = (name, value, options, coreRecursive) => {
110
+ const previousValues = getFieldValue(name);
111
+ if (isArray(previousValues)) {
112
+ if (previousValues.length !== value.length || !isEqual(previousValues, value)) {
113
+ setData(formName, name, value);
114
+ }
115
+ value.forEach((item, index) => {
116
+ if (!isEqual(previousValues[index], item)) {
117
+ const itemName = `${name}.${index}`;
118
+ const itemListener = getListeners().find((l) => l.name === itemName && l.formName === formName);
119
+ if (itemListener) {
120
+ itemListener.onChange(item, options);
121
+ }
122
+ const nestedPaths = getAllPathsIncludingContainers(item);
123
+ nestedPaths.forEach((p) => {
124
+ if (coreRecursive) {
125
+ coreRecursive(`${itemName}.${p}`, get(item, p), options);
126
+ }
127
+ });
128
+ }
129
+ });
130
+ if (previousValues.length > value.length) {
131
+ for (let index = value.length; index < previousValues.length; index++) {
132
+ const itemName = `${name}.${index}`;
133
+ const removedItem = previousValues[index];
134
+ const nestedPaths = getAllPathsIncludingContainers(removedItem);
135
+ nestedPaths.forEach((p) => {
136
+ if (coreRecursive) {
137
+ coreRecursive(`${itemName}.${p}`, void 0, options);
138
+ }
139
+ });
140
+ if (coreRecursive) {
141
+ coreRecursive(itemName, void 0, options);
142
+ }
143
+ }
144
+ }
145
+ }
146
+ };
147
+ const deepTriggerSetCore = (name, value, options) => {
148
+ if (typeof value === "string" || typeof value === "number" || typeof value === "boolean" || value === null || value === void 0) {
149
+ handlePrimitiveValue(name, value, options);
150
+ return;
151
+ }
152
+ if (isPlainObject(value)) {
153
+ const listener = getListeners().find((l) => l.name === name && l.formName === formName);
154
+ handlePlainObject(name, value, options, deepTriggerSetCore);
155
+ return;
156
+ }
157
+ if (Array.isArray(value)) {
158
+ const listener = getListeners().find((l) => l.name === name && l.formName === formName);
159
+ if (listener && listener.type === "array") {
160
+ handleArrayListener(name, value, options, deepTriggerSetCore);
161
+ } else if (!listener) {
162
+ handleNonListenerArray(name, value, options, deepTriggerSetCore);
163
+ } else {
164
+ handlePlainObject(name, value, options, deepTriggerSetCore);
165
+ }
166
+ return;
167
+ }
168
+ handlePrimitiveValue(name, value, options);
169
+ };
170
+ const handleDeepTriggerSet = (name, value, options) => {
171
+ deepTriggerSetCore(name, value, options);
172
+ };
173
+ const setFieldValue = (name, value, options) => {
174
+ if (options == null ? void 0 : options.deepTrigger) {
175
+ handleDeepTriggerSet(name, value, options);
176
+ return;
177
+ }
178
+ const listener = getListeners().find((l) => l.name === name && l.formName === formName);
179
+ if (listener) {
180
+ if (listener.type === "array") {
181
+ if (!isEqual(getFormItemValue(formName, name), value)) {
182
+ listener.onArrayChange(value, options);
183
+ const allStringPath = getAllNoneObjStringPath(value);
184
+ allStringPath.forEach((p) => {
185
+ const findListener = getListeners().find((l) => l.name === `${name}.${p}` && l.formName === formName);
186
+ if (findListener) {
187
+ findListener.onChange(get(value, p), options);
188
+ } else {
189
+ setData(formName, `${name}.${p}`, get(value, p));
190
+ }
191
+ });
192
+ }
193
+ } else {
194
+ listener.onChange(value, options);
195
+ }
196
+ } else {
197
+ setData(formName, name, value);
198
+ }
199
+ };
45
200
  const setFieldValues = (values, options = { notTriggerDirty: false }) => {
46
- const allStringPath = getAllNoneObjStringPath(values);
47
- allStringPath.forEach((p) => {
48
- const listener = getListeners().find((l) => l.name === p && l.formName === formName);
201
+ const allPaths = getAllPathsStopAtArray(values);
202
+ allPaths.forEach((path) => {
203
+ const pathValue = get(values, path);
204
+ if (Array.isArray(pathValue)) {
205
+ handleDeepTriggerSet(path, pathValue, options);
206
+ return;
207
+ }
208
+ const listener = getListeners().find((l) => l.name === path && l.formName === formName);
49
209
  if (listener) {
50
- listener.onChange(get(values, listener.name), options);
210
+ listener.onChange(pathValue, options);
51
211
  } else {
52
- setData(formName, p, get(values, p));
212
+ setData(formName, path, pathValue);
53
213
  }
54
214
  });
55
215
  };
56
- const getFieldValue = (name) => {
216
+ function getFieldValue(name) {
57
217
  return getFormItemValue(formName, name);
58
- };
218
+ }
59
219
  const getFieldValues = (names = []) => {
60
220
  return names.map((name) => ({
61
221
  name,
@@ -96,7 +256,17 @@ function Form({ children, formName, initialValues, onFinish, onReject, onFinally
96
256
  const formValues = getFormValues(formName);
97
257
  const resultValues = cloneDeep(formValues);
98
258
  const cleanValues = {};
99
- uniq(listeners, (l) => l.name).forEach((l) => {
259
+ uniqBy(filter(listeners, (l) => {
260
+ if (!l.hidden)
261
+ return true;
262
+ if (isNil(props2 == null ? void 0 : props2.collectHiddenFields)) {
263
+ if (isNil(l.collectOnHidden)) {
264
+ return formCollectHiddenFields;
265
+ }
266
+ return Boolean(l.collectOnHidden);
267
+ }
268
+ return props2.collectHiddenFields;
269
+ }), (l) => l.name).forEach((l) => {
100
270
  set(cleanValues, l.name, get(resultValues, l.name));
101
271
  });
102
272
  const handleIsolateCase = async () => {
@@ -235,9 +405,9 @@ function Form({ children, formName, initialValues, onFinish, onReject, onFinally
235
405
  clearFormState(formName);
236
406
  };
237
407
  }, []);
238
- return _jsxs(FormContext.Provider, { value: {
408
+ return _jsx(FormContext.Provider, { value: {
239
409
  formName
240
- }, children: [FormElement ? _jsx(FormElement, { onSubmit: (e) => {
410
+ }, children: FormElement ? _jsx(FormElement, { onSubmit: (e) => {
241
411
  e.preventDefault();
242
412
  e.stopPropagation();
243
413
  runSubmit(void 0);
@@ -245,7 +415,7 @@ function Form({ children, formName, initialValues, onFinish, onReject, onFinally
245
415
  e.preventDefault();
246
416
  e.stopPropagation();
247
417
  runSubmit(void 0);
248
- }, ...props, children }), _jsx(FormCleanUp, {})] });
418
+ }, ...props, children }) });
249
419
  }
250
420
  function useFormContext() {
251
421
  const c = useContext(FormContext);
@@ -254,7 +424,8 @@ function useFormContext() {
254
424
  return c;
255
425
  }
256
426
  function useForm(formNameOrFormInstance) {
257
- const targetFormName = typeof formNameOrFormInstance === "object" && formNameOrFormInstance !== null ? formNameOrFormInstance.formName : formNameOrFormInstance;
427
+ const formContext = useContext(FormContext);
428
+ const targetFormName = isNil(formNameOrFormInstance) ? formContext == null ? void 0 : formContext.formName : typeof formNameOrFormInstance === "object" && formNameOrFormInstance !== null ? formNameOrFormInstance.formName : formNameOrFormInstance;
258
429
  const formInstance = useFormStore((state) => {
259
430
  return state.formInstances.find((i) => i.formName === targetFormName);
260
431
  });
@@ -268,6 +439,17 @@ function useWatch(name, formNameOrFormInstance) {
268
439
  });
269
440
  return value;
270
441
  }
442
+ function useWatchNormalized({ name, normalizeFn, formNameOrFormInstance }) {
443
+ const [formInstance] = useForm(formNameOrFormInstance);
444
+ const rawValue = useFormStore((state) => {
445
+ var _a;
446
+ return state.getFormItemValue((_a = formInstance == null ? void 0 : formInstance.formName) != null ? _a : formNameOrFormInstance, name);
447
+ });
448
+ const normalizedValue = useMemo(() => {
449
+ return normalizeFn(rawValue);
450
+ }, [rawValue, normalizeFn]);
451
+ return normalizedValue;
452
+ }
271
453
  function useSubmitDataWatch({ formNameOrFormInstance, triggerWhenChange = false, mapFn }) {
272
454
  const [formInstance] = useForm(formNameOrFormInstance);
273
455
  const value = useFormStore((state) => {
@@ -301,7 +483,9 @@ const useFormItemStateWatch = (nameOrFormItemId, formNameOrFormInstance) => {
301
483
  };
302
484
  };
303
485
  Form.useForm = useForm;
486
+ Form.Item = FormItem;
304
487
  Form.useWatch = useWatch;
488
+ Form.useWatchNormalized = useWatchNormalized;
305
489
  Form.useSubmitDataWatch = useSubmitDataWatch;
306
490
  Form.useFormStateWatch = useFormStateWatch;
307
491
  Form.useFormItemStateWatch = useFormItemStateWatch;
@@ -313,5 +497,6 @@ export {
313
497
  useFormItemStateWatch,
314
498
  useFormStateWatch,
315
499
  useSubmitDataWatch,
316
- useWatch
500
+ useWatch,
501
+ useWatchNormalized
317
502
  };
@@ -1,7 +1,21 @@
1
- export interface FormInstance {
1
+ type ListenerFormItemType = "normal" | "array";
2
+ export interface SubmitProps<T = any> {
3
+ externalFinishCallback?: (values: T, allValues?: any) => void | Promise<void>;
4
+ externalRejectCallback?: (errorFields: any[]) => void | Promise<void>;
5
+ externalFinallyCallback?: (result: {
6
+ errorsField: any[];
7
+ values: T;
8
+ withUnRegisteredValues: any;
9
+ }) => void | Promise<void>;
10
+ callBothFinish?: boolean;
11
+ callBothReject?: boolean;
12
+ callBothFinally?: boolean;
13
+ collectHiddenFields?: boolean;
14
+ }
15
+ export interface FormInstance<T = any> {
2
16
  formName: string;
3
17
  resetFields: (values?: any) => void;
4
- submit: (values?: any) => void;
18
+ submit: (props?: SubmitProps<T>) => void;
5
19
  submitAsync: (values?: any) => Promise<any>;
6
20
  setFieldValue: (name: string, value: any, options?: any) => void;
7
21
  setFieldValues: (values: Record<string, any>, options?: any) => void;
@@ -13,6 +27,30 @@ export interface FormInstance {
13
27
  getFieldErrors: () => Record<string, any>;
14
28
  setFieldFocus: (name: string) => void;
15
29
  }
30
+ export interface ListenerItem {
31
+ name?: string;
32
+ formName?: string;
33
+ isTouched?: boolean;
34
+ isDirty?: boolean;
35
+ formItemId?: string;
36
+ internalErrors?: any;
37
+ onArrayChange?: any;
38
+ onChange?: any;
39
+ onReset?: any;
40
+ onFocus?: any;
41
+ emitFocus?: any;
42
+ isInitied?: boolean;
43
+ type?: ListenerFormItemType;
44
+ hidden?: boolean;
45
+ collectOnHidden?: boolean;
46
+ }
47
+ export interface CleanUpItem {
48
+ name?: string;
49
+ type?: string;
50
+ key: string;
51
+ itemKey?: string;
52
+ formName?: string;
53
+ }
16
54
  interface FormStoreState {
17
55
  forms: Record<string, any>;
18
56
  initialValues: Record<string, any>;
@@ -20,9 +58,11 @@ interface FormStoreState {
20
58
  cacheData: Record<string, any>;
21
59
  formInstances: FormInstance[];
22
60
  submitHistory: Record<string, any[]>;
61
+ listeners: ListenerItem[];
62
+ cleanUpStack: CleanUpItem[];
23
63
  [key: string]: any;
24
64
  }
25
65
  export declare const useFormStore: import("zustand").UseBoundStore<import("zustand").StoreApi<FormStoreState>>;
26
- export declare const useFormListeners: import("zustand").UseBoundStore<import("zustand").StoreApi<any>>;
27
- export declare const useFormCleanUp: import("zustand").UseBoundStore<import("zustand").StoreApi<any>>;
66
+ export declare const useFormListeners: import("zustand").UseBoundStore<import("zustand").StoreApi<FormStoreState>>;
67
+ export declare const useFormCleanUp: import("zustand").UseBoundStore<import("zustand").StoreApi<FormStoreState>>;
28
68
  export {};