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.
- package/CHANGELOG.md +173 -4
- package/README.md +8 -4
- package/dist/components/Form/FormCleanUp.js +3 -3
- package/dist/components/Form/FormItem.d.ts +10 -4
- package/dist/components/Form/FormItem.js +52 -14
- package/dist/components/Form/FormList.d.ts +2 -2
- package/dist/components/Form/FormList.js +2 -2
- package/dist/constants/form.d.ts +1 -1
- package/dist/hooks/useFormItemControl.d.ts +8 -3
- package/dist/hooks/useFormItemControl.js +64 -28
- package/dist/hooks/useFormListControl.d.ts +2 -1
- package/dist/hooks/useFormListControl.js +85 -19
- package/dist/index.cjs.d.ts +1 -0
- package/dist/index.d.ts +4 -3
- package/dist/index.esm.d.ts +1 -0
- package/dist/index.js +4 -2
- package/dist/providers/Form.d.ts +15 -2
- package/dist/providers/Form.js +226 -41
- package/dist/stores/formStore.d.ts +44 -4
- package/dist/stores/formStore.js +42 -7
- package/dist/test/CommonTest.d.ts +3 -0
- package/dist/test/CommonTest.js +49 -0
- package/dist/test/TestDialog.d.ts +3 -0
- package/dist/test/TestDialog.js +21 -0
- package/dist/test/TestListener.d.ts +3 -0
- package/dist/test/TestListener.js +17 -0
- package/dist/test/TestNotFormWrapper.d.ts +3 -0
- package/dist/test/TestNotFormWrapper.js +15 -0
- package/dist/test/TestSelect.d.ts +6 -0
- package/dist/test/TestSelect.js +24 -0
- package/dist/test/TestWatchNormalize.d.ts +3 -0
- package/dist/test/TestWatchNormalize.js +23 -0
- package/dist/test/TestWrapperFormItem.d.ts +3 -0
- package/dist/test/TestWrapperFormItem.js +13 -0
- package/dist/test/testSetValue/TestCase10_SetFieldValues_ComplexNested.d.ts +21 -0
- package/dist/test/testSetValue/TestCase10_SetFieldValues_ComplexNested.js +61 -0
- package/dist/test/testSetValue/TestCase1_PlainObjectToPrimitives.d.ts +16 -0
- package/dist/test/testSetValue/TestCase1_PlainObjectToPrimitives.js +18 -0
- package/dist/test/testSetValue/TestCase2_PlainObjectToFormList.d.ts +21 -0
- package/dist/test/testSetValue/TestCase2_PlainObjectToFormList.js +33 -0
- package/dist/test/testSetValue/TestCase3_ArrayNonListenerToPrimitives.d.ts +21 -0
- package/dist/test/testSetValue/TestCase3_ArrayNonListenerToPrimitives.js +26 -0
- package/dist/test/testSetValue/TestCase4_PlainObjectRemovedFields.d.ts +20 -0
- package/dist/test/testSetValue/TestCase4_PlainObjectRemovedFields.js +32 -0
- package/dist/test/testSetValue/TestCase5_FormListRemovedItems.d.ts +22 -0
- package/dist/test/testSetValue/TestCase5_FormListRemovedItems.js +29 -0
- package/dist/test/testSetValue/TestCase6_NestedFormListRemoved.d.ts +28 -0
- package/dist/test/testSetValue/TestCase6_NestedFormListRemoved.js +36 -0
- package/dist/test/testSetValue/TestCase7_SetFieldValues_MixedStructure.d.ts +17 -0
- package/dist/test/testSetValue/TestCase7_SetFieldValues_MixedStructure.js +33 -0
- package/dist/test/testSetValue/TestCase8_SetFieldValues_NestedObject.d.ts +27 -0
- package/dist/test/testSetValue/TestCase8_SetFieldValues_NestedObject.js +57 -0
- package/dist/test/testSetValue/TestCase9_SetFieldValues_MultipleArrays.d.ts +25 -0
- package/dist/test/testSetValue/TestCase9_SetFieldValues_MultipleArrays.js +46 -0
- package/dist/test/testSetValue/index.d.ts +2 -0
- package/dist/test/testSetValue/index.js +28 -0
- package/dist/types/index.d.ts +1 -1
- package/dist/types/public.d.ts +1 -1
- package/dist/utils/obj.util.d.ts +29 -1
- package/dist/utils/obj.util.js +59 -5
- package/package.json +2 -1
- package/src/App.tsx +39 -156
- package/src/DEEP_TRIGGER_LOGIC.md +573 -0
- package/src/components/Form/FormCleanUp.tsx +4 -8
- package/src/components/Form/FormItem.tsx +174 -57
- package/src/components/Form/FormList.tsx +17 -4
- package/src/constants/form.ts +1 -1
- package/src/hooks/useFormItemControl.ts +78 -32
- package/src/hooks/useFormListControl.ts +133 -43
- package/src/index.ts +25 -13
- package/src/main.tsx +6 -1
- package/src/providers/Form.tsx +454 -26
- package/src/stores/formStore.ts +363 -283
- package/src/test/CommonTest.tsx +177 -0
- package/src/test/TestDialog.tsx +52 -0
- package/src/test/TestListener.tsx +21 -0
- package/src/test/TestNotFormWrapper.tsx +43 -0
- package/src/test/TestSelect.tsx +38 -0
- package/src/test/TestWatchNormalize.tsx +32 -0
- package/src/test/TestWrapperFormItem.tsx +34 -0
- package/src/test/testSetValue/TestCase10_SetFieldValues_ComplexNested.tsx +203 -0
- package/src/test/testSetValue/TestCase1_PlainObjectToPrimitives.tsx +72 -0
- package/src/test/testSetValue/TestCase2_PlainObjectToFormList.tsx +114 -0
- package/src/test/testSetValue/TestCase3_ArrayNonListenerToPrimitives.tsx +99 -0
- package/src/test/testSetValue/TestCase4_PlainObjectRemovedFields.tsx +112 -0
- package/src/test/testSetValue/TestCase5_FormListRemovedItems.tsx +119 -0
- package/src/test/testSetValue/TestCase6_NestedFormListRemoved.tsx +185 -0
- package/src/test/testSetValue/TestCase7_SetFieldValues_MixedStructure.tsx +110 -0
- package/src/test/testSetValue/TestCase8_SetFieldValues_NestedObject.tsx +162 -0
- package/src/test/testSetValue/TestCase9_SetFieldValues_MultipleArrays.tsx +169 -0
- package/src/test/testSetValue/index.tsx +100 -0
- package/src/types/index.ts +1 -1
- package/src/types/public.ts +1 -1
- 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 {
|
|
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
|
-
|
|
17
|
-
|
|
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) =>
|
|
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
|
-
|
|
46
|
-
|
|
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}.${
|
|
50
|
-
|
|
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
|
|
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
|
-
|
|
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
|
};
|
package/dist/providers/Form.d.ts
CHANGED
|
@@ -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
|
|
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;
|
package/dist/providers/Form.js
CHANGED
|
@@ -1,40 +1,50 @@
|
|
|
1
|
-
import { jsx as _jsx
|
|
2
|
-
import { cloneDeep, get, isEqual, last, set,
|
|
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
|
|
7
|
+
import FormItem from "../components/Form/FormItem";
|
|
8
8
|
import { SUBMIT_STATE } from "../constants/form";
|
|
9
|
-
import {
|
|
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 {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
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
|
|
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
|
|
47
|
-
|
|
48
|
-
const
|
|
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(
|
|
210
|
+
listener.onChange(pathValue, options);
|
|
51
211
|
} else {
|
|
52
|
-
setData(formName,
|
|
212
|
+
setData(formName, path, pathValue);
|
|
53
213
|
}
|
|
54
214
|
});
|
|
55
215
|
};
|
|
56
|
-
|
|
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
|
-
|
|
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
|
|
408
|
+
return _jsx(FormContext.Provider, { value: {
|
|
239
409
|
formName
|
|
240
|
-
}, children:
|
|
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 })
|
|
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
|
|
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
|
-
|
|
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: (
|
|
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<
|
|
27
|
-
export declare const useFormCleanUp: import("zustand").UseBoundStore<import("zustand").StoreApi<
|
|
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 {};
|