react-form-manage 1.0.8-beta.9 → 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 +197 -22
- 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 +38 -163
- 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 +451 -23
- 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,15 +1,15 @@
|
|
|
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 }) {
|
|
12
|
+
function Form({ children, formName, initialValues, onFinish, onReject, onFinally, FormElement, collectHiddenFields: formCollectHiddenFields = true, ...props }) {
|
|
13
13
|
const {
|
|
14
14
|
// appInitValue,
|
|
15
15
|
getFormItemValue,
|
|
@@ -39,12 +39,12 @@ function Form({ children, formName, initialValues, onFinish, onReject, onFinally
|
|
|
39
39
|
// Test, nhớ xóa sau khi xong
|
|
40
40
|
// formStates: state.formStates?.[formName],
|
|
41
41
|
})));
|
|
42
|
-
const { getListeners } =
|
|
42
|
+
const { getListeners } = useFormStore(useShallow((state) => {
|
|
43
43
|
return {
|
|
44
44
|
getListeners: state.getListeners
|
|
45
45
|
};
|
|
46
46
|
}));
|
|
47
|
-
const
|
|
47
|
+
const handlePrimitiveValue = (name, value, options) => {
|
|
48
48
|
const listener = getListeners().find((l) => l.name === name && l.formName === formName);
|
|
49
49
|
if (listener) {
|
|
50
50
|
listener.onChange(value, options);
|
|
@@ -52,20 +52,170 @@ function Form({ children, formName, initialValues, onFinish, onReject, onFinally
|
|
|
52
52
|
setData(formName, name, value);
|
|
53
53
|
}
|
|
54
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
|
+
};
|
|
55
200
|
const setFieldValues = (values, options = { notTriggerDirty: false }) => {
|
|
56
|
-
const
|
|
57
|
-
|
|
58
|
-
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);
|
|
59
209
|
if (listener) {
|
|
60
|
-
listener.onChange(
|
|
210
|
+
listener.onChange(pathValue, options);
|
|
61
211
|
} else {
|
|
62
|
-
setData(formName,
|
|
212
|
+
setData(formName, path, pathValue);
|
|
63
213
|
}
|
|
64
214
|
});
|
|
65
215
|
};
|
|
66
|
-
|
|
216
|
+
function getFieldValue(name) {
|
|
67
217
|
return getFormItemValue(formName, name);
|
|
68
|
-
}
|
|
218
|
+
}
|
|
69
219
|
const getFieldValues = (names = []) => {
|
|
70
220
|
return names.map((name) => ({
|
|
71
221
|
name,
|
|
@@ -106,7 +256,17 @@ function Form({ children, formName, initialValues, onFinish, onReject, onFinally
|
|
|
106
256
|
const formValues = getFormValues(formName);
|
|
107
257
|
const resultValues = cloneDeep(formValues);
|
|
108
258
|
const cleanValues = {};
|
|
109
|
-
|
|
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) => {
|
|
110
270
|
set(cleanValues, l.name, get(resultValues, l.name));
|
|
111
271
|
});
|
|
112
272
|
const handleIsolateCase = async () => {
|
|
@@ -245,9 +405,9 @@ function Form({ children, formName, initialValues, onFinish, onReject, onFinally
|
|
|
245
405
|
clearFormState(formName);
|
|
246
406
|
};
|
|
247
407
|
}, []);
|
|
248
|
-
return
|
|
408
|
+
return _jsx(FormContext.Provider, { value: {
|
|
249
409
|
formName
|
|
250
|
-
}, children:
|
|
410
|
+
}, children: FormElement ? _jsx(FormElement, { onSubmit: (e) => {
|
|
251
411
|
e.preventDefault();
|
|
252
412
|
e.stopPropagation();
|
|
253
413
|
runSubmit(void 0);
|
|
@@ -255,7 +415,7 @@ function Form({ children, formName, initialValues, onFinish, onReject, onFinally
|
|
|
255
415
|
e.preventDefault();
|
|
256
416
|
e.stopPropagation();
|
|
257
417
|
runSubmit(void 0);
|
|
258
|
-
}, ...props, children })
|
|
418
|
+
}, ...props, children }) });
|
|
259
419
|
}
|
|
260
420
|
function useFormContext() {
|
|
261
421
|
const c = useContext(FormContext);
|
|
@@ -264,7 +424,8 @@ function useFormContext() {
|
|
|
264
424
|
return c;
|
|
265
425
|
}
|
|
266
426
|
function useForm(formNameOrFormInstance) {
|
|
267
|
-
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;
|
|
268
429
|
const formInstance = useFormStore((state) => {
|
|
269
430
|
return state.formInstances.find((i) => i.formName === targetFormName);
|
|
270
431
|
});
|
|
@@ -278,6 +439,17 @@ function useWatch(name, formNameOrFormInstance) {
|
|
|
278
439
|
});
|
|
279
440
|
return value;
|
|
280
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
|
+
}
|
|
281
453
|
function useSubmitDataWatch({ formNameOrFormInstance, triggerWhenChange = false, mapFn }) {
|
|
282
454
|
const [formInstance] = useForm(formNameOrFormInstance);
|
|
283
455
|
const value = useFormStore((state) => {
|
|
@@ -311,7 +483,9 @@ const useFormItemStateWatch = (nameOrFormItemId, formNameOrFormInstance) => {
|
|
|
311
483
|
};
|
|
312
484
|
};
|
|
313
485
|
Form.useForm = useForm;
|
|
486
|
+
Form.Item = FormItem;
|
|
314
487
|
Form.useWatch = useWatch;
|
|
488
|
+
Form.useWatchNormalized = useWatchNormalized;
|
|
315
489
|
Form.useSubmitDataWatch = useSubmitDataWatch;
|
|
316
490
|
Form.useFormStateWatch = useFormStateWatch;
|
|
317
491
|
Form.useFormItemStateWatch = useFormItemStateWatch;
|
|
@@ -323,5 +497,6 @@ export {
|
|
|
323
497
|
useFormItemStateWatch,
|
|
324
498
|
useFormStateWatch,
|
|
325
499
|
useSubmitDataWatch,
|
|
326
|
-
useWatch
|
|
500
|
+
useWatch,
|
|
501
|
+
useWatchNormalized
|
|
327
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 {};
|