react-form-manage 1.0.8-beta.10 → 1.0.8-beta.12
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 +5 -0
- package/README.md +7 -4
- package/dist/components/Form/FormCleanUp.js +3 -3
- package/dist/components/Form/FormList.d.ts +1 -1
- package/dist/components/Form/FormList.js +2 -2
- package/dist/hooks/useFormItemControl.js +3 -3
- package/dist/hooks/useFormListControl.d.ts +1 -1
- package/dist/hooks/useFormListControl.js +7 -7
- package/dist/index.d.ts +2 -1
- package/dist/index.js +2 -0
- package/dist/providers/Form.d.ts +6 -0
- package/dist/providers/Form.js +20 -7
- package/dist/stores/formStore.d.ts +25 -3
- package/dist/stores/formStore.js +13 -6
- package/package.json +2 -1
- package/src/App.tsx +41 -3
- package/src/components/Form/FormCleanUp.tsx +3 -7
- package/src/components/Form/FormList.tsx +17 -4
- package/src/hooks/useFormItemControl.ts +3 -7
- package/src/hooks/useFormListControl.ts +21 -12
- package/src/index.ts +11 -0
- package/src/providers/Form.tsx +35 -9
- package/src/stores/formStore.ts +38 -23
package/CHANGELOG.md
CHANGED
|
@@ -15,6 +15,11 @@ Docs: Update usage notes for `FormItem` control-on-init flag and `hidden` prop.
|
|
|
15
15
|
|
|
16
16
|
- Add isTouched field to FormItem for tracking user interaction state
|
|
17
17
|
|
|
18
|
+
## [1.0.8-beta.10] - 2026-01-27
|
|
19
|
+
- `useForm()` giờ có thể trả về form instance từ provider lân cận nếu không truyền `formName` (không còn bắt buộc truyền tên form khi đã wrap trong `Form`).
|
|
20
|
+
- `FormList.add` khi không truyền `index` sẽ mặc định append vào cuối danh sách.
|
|
21
|
+
- Docs: cập nhật hướng dẫn cho `useForm` và `FormList.add`.
|
|
22
|
+
|
|
18
23
|
## [1.0.8-beta.1] - 2026-01-22
|
|
19
24
|
|
|
20
25
|
- Fix UseFormItemControlReturn errors type to properly export FormFieldError[]
|
package/README.md
CHANGED
|
@@ -2,8 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
Thư viện form nhẹ dành cho React — hỗ trợ form, field, list (array fields), và cơ chế listener để giảm re-render.
|
|
4
4
|
|
|
5
|
-
Phiên bản này xuất phát từ mã nguồn JS. Typings (.d.ts) được cung cấp trong `src/types/components.d.ts`.
|
|
6
|
-
|
|
7
5
|
---
|
|
8
6
|
|
|
9
7
|
## Cài đặt
|
|
@@ -80,6 +78,8 @@ export default Example;
|
|
|
80
78
|
|
|
81
79
|
Bạn có thể lấy instance form để gọi phương thức chương trình như `submit`, `resetFields`, `setFieldValue`…
|
|
82
80
|
|
|
81
|
+
`useForm` ưu tiên lấy instance từ provider gần nhất nếu không truyền `formName`, giúp bạn không cần truyền tên form khi đã bọc trong `Form`.
|
|
82
|
+
|
|
83
83
|
Ví dụ sử dụng hook attached trên `Form`:
|
|
84
84
|
|
|
85
85
|
```jsx
|
|
@@ -87,7 +87,7 @@ import React from "react";
|
|
|
87
87
|
import Form from "react-form-manage";
|
|
88
88
|
|
|
89
89
|
function CtrlExample() {
|
|
90
|
-
const [form] = Form.useForm(
|
|
90
|
+
const [form] = Form.useForm(); // hoặc Form.useForm('myForm') khi muốn chỉ định form khác
|
|
91
91
|
|
|
92
92
|
return (
|
|
93
93
|
<div>
|
|
@@ -156,6 +156,9 @@ Custom validator (async):
|
|
|
156
156
|
|
|
157
157
|
`FormList` là render-prop component cung cấp `listFields` và các action `add`, `remove`, `move`.
|
|
158
158
|
|
|
159
|
+
Ghi chú:
|
|
160
|
+
- `add()` nếu không truyền `index` sẽ tự động append phần tử mới vào cuối danh sách.
|
|
161
|
+
|
|
159
162
|
Ví dụ:
|
|
160
163
|
|
|
161
164
|
```jsx
|
|
@@ -192,7 +195,7 @@ Lưu ý: `FormList` quản lý các `key` nội bộ và push các mục cần c
|
|
|
192
195
|
|
|
193
196
|
## Hooks (tóm tắt)
|
|
194
197
|
|
|
195
|
-
- `useForm(formNameOrFormInstance)` —
|
|
198
|
+
- `useForm(formNameOrFormInstance?)` — nếu không truyền thì lấy instance từ `Form` provider gần nhất; nếu truyền `formName` thì chọn form tương ứng.
|
|
196
199
|
- `useWatch(name, formNameOrFormInstance)` — subscribe giá trị field.
|
|
197
200
|
- `useSubmitDataWatch` — watch dữ liệu submit cuối cùng.
|
|
198
201
|
- `useFormStateWatch` — watch state của form (isInitied, submitState…).
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import { Fragment as _Fragment, jsx as _jsx } from "react/jsx-runtime";
|
|
2
2
|
import { useEffect } from "react";
|
|
3
3
|
import { useShallow } from "zustand/react/shallow";
|
|
4
|
-
import {
|
|
4
|
+
import { useFormStore } from "../../stores/formStore";
|
|
5
5
|
const FormCleanUp = () => {
|
|
6
|
-
const { cleanUpStack, clearCleanUpStack } =
|
|
6
|
+
const { cleanUpStack, clearCleanUpStack } = useFormStore(useShallow((state) => ({
|
|
7
7
|
cleanUpStack: state.cleanUpStack,
|
|
8
8
|
clearCleanUpStack: state.clearCleanUpStack
|
|
9
9
|
})));
|
|
10
|
-
const { revokeListener } =
|
|
10
|
+
const { revokeListener } = useFormStore(useShallow((state) => ({
|
|
11
11
|
revokeListener: state.revokeListener
|
|
12
12
|
})));
|
|
13
13
|
const { clearObjKeyItem, clearArrItem } = useFormStore(useShallow((state) => {
|
|
@@ -20,5 +20,5 @@ export interface FormListProps<T = any> {
|
|
|
20
20
|
}) => void;
|
|
21
21
|
}) => React.ReactNode;
|
|
22
22
|
}
|
|
23
|
-
declare const FormList: <T = any>({ name, initialValues, form, formName, children }: FormListProps<T>) => import("react").ReactNode;
|
|
23
|
+
declare const FormList: <T = any>({ name, initialValues, form, formName, children, }: FormListProps<T>) => import("react").ReactNode;
|
|
24
24
|
export default FormList;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import
|
|
1
|
+
import useFormListControl from "../../hooks/useFormListControl";
|
|
2
2
|
const FormList = ({ name, initialValues, form, formName, children }) => {
|
|
3
|
-
const { listFields, ...actions } =
|
|
3
|
+
const { listFields, ...actions } = useFormListControl({
|
|
4
4
|
name,
|
|
5
5
|
initialValues,
|
|
6
6
|
form,
|
|
@@ -4,7 +4,7 @@ import { useEffect, useMemo } from "react";
|
|
|
4
4
|
import { useShallow } from "zustand/react/shallow";
|
|
5
5
|
import { IS_ALPHABET_STRING_AND_NUMBER_REGEX, IS_EMAIL_REGEX, IS_NAME_REGEX, IS_NO_SPACE_ALPHABET_STRING_AND_NUMBER_REGEX, IS_NO_SPACE_ALPHABET_STRING_REGEX, IS_NOSPACE_STRING_AND_NUMBER_REGEX, IS_PASSWORD_REGEX, IS_POSITIVE_INTEGER_STRING_NUMBER_REGEX, IS_POSITIVE_STRING_NUMBER_REGEX, IS_STRING_AND_NUMBER_REGEX, IS_STRING_NUMBER_REGEX, IS_USERNAME_REGEX, IS_VIETNAMESE_PHONE_NUMBER_REGEX } from "../constants/validation";
|
|
6
6
|
import { useFormContext } from "../providers/Form";
|
|
7
|
-
import {
|
|
7
|
+
import { useFormStore } from "../stores/formStore";
|
|
8
8
|
const VALID_PREMITIVE_TYPE = ["string", "number", "undefined"];
|
|
9
9
|
function useFormItemControl({ formName, form, name, initialValue, formItemId, rules, elementRef }) {
|
|
10
10
|
const contextForm = useFormContext();
|
|
@@ -20,7 +20,7 @@ function useFormItemControl({ formName, form, name, initialValue, formItemId, ru
|
|
|
20
20
|
submitState: (_d = (_c = state2.formStates) == null ? void 0 : _c[formName || (form == null ? void 0 : form.formName) || (contextForm == null ? void 0 : contextForm.formName)]) == null ? void 0 : _d.submitState
|
|
21
21
|
};
|
|
22
22
|
}));
|
|
23
|
-
const { setCleanUpStack } =
|
|
23
|
+
const { setCleanUpStack } = useFormStore(useShallow((state2) => ({
|
|
24
24
|
setCleanUpStack: state2.setCleanUpStack
|
|
25
25
|
})));
|
|
26
26
|
const { initValue: internalInitValue, setInitData, getInitData } = useFormStore(useShallow((state2) => {
|
|
@@ -30,7 +30,7 @@ function useFormItemControl({ formName, form, name, initialValue, formItemId, ru
|
|
|
30
30
|
getInitData: state2.getInitData
|
|
31
31
|
};
|
|
32
32
|
}));
|
|
33
|
-
const { listener, setListener } =
|
|
33
|
+
const { listener, setListener } = useFormStore(useShallow((state2) => {
|
|
34
34
|
return {
|
|
35
35
|
listener: state2.listeners.find((l) => l.formItemId === formItemId),
|
|
36
36
|
setListener: state2.setListener
|
|
@@ -3,7 +3,7 @@ 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
8
|
const contextForm = useFormContext();
|
|
9
9
|
const getFormValues = useFormStore((state) => state.getFormValues);
|
|
@@ -13,7 +13,7 @@ function useFormListControl({ name, form, initialValues, formName }) {
|
|
|
13
13
|
clearCacheData: state.clearCacheData,
|
|
14
14
|
setCacheData: state.setCacheData
|
|
15
15
|
})));
|
|
16
|
-
const { setCleanUpStack } =
|
|
16
|
+
const { setCleanUpStack } = useFormStore(useShallow((state) => ({
|
|
17
17
|
setCleanUpStack: state.setCleanUpStack
|
|
18
18
|
})));
|
|
19
19
|
const { initValue: internalInitValue, formState } = useFormStore(useShallow((state) => {
|
|
@@ -55,11 +55,7 @@ function useFormListControl({ name, form, initialValues, formName }) {
|
|
|
55
55
|
};
|
|
56
56
|
const add = (index) => {
|
|
57
57
|
setListFields((prev) => {
|
|
58
|
-
if (index
|
|
59
|
-
return prev;
|
|
60
|
-
if (index < 0)
|
|
61
|
-
return prev;
|
|
62
|
-
if (index === prev.length) {
|
|
58
|
+
if (isNil(index) || index === prev.length) {
|
|
63
59
|
const newName = `${name}.${prev.length}`;
|
|
64
60
|
const newKey = v4();
|
|
65
61
|
const result2 = [
|
|
@@ -71,6 +67,10 @@ function useFormListControl({ name, form, initialValues, formName }) {
|
|
|
71
67
|
];
|
|
72
68
|
return result2;
|
|
73
69
|
}
|
|
70
|
+
if (index > prev.length)
|
|
71
|
+
return prev;
|
|
72
|
+
if (index < 0)
|
|
73
|
+
return prev;
|
|
74
74
|
const clonePrev = [...prev];
|
|
75
75
|
const result = clonePrev.reduce((prev2, cur, curIndex) => {
|
|
76
76
|
const newKey = v4();
|
package/dist/index.d.ts
CHANGED
|
@@ -6,5 +6,6 @@ import Input from "./components/Input";
|
|
|
6
6
|
import InputWrapper, { type InputWrapperProps } from "./components/Form/InputWrapper";
|
|
7
7
|
import useFormItemControl from "./hooks/useFormItemControl";
|
|
8
8
|
import useFormListControl from "./hooks/useFormListControl";
|
|
9
|
-
|
|
9
|
+
import { useFormStore, type FormInstance, type ListenerItem, type CleanUpItem } from "./stores/formStore";
|
|
10
|
+
export { Form, FormItem, FormList, Input, InputWrapper, useFormItemControl, useFormListControl, useForm, useWatch, useSubmitDataWatch, useFormStateWatch, useFormStore, type FormProps, type FormItemProps, type FormListProps, type InputWrapperProps, type ValidationRule, type FormFieldError, type SubmitState, type UseFormItemStateWatchReturn, type FormInstance, type ListenerItem, type CleanUpItem, SUBMIT_STATE, };
|
|
10
11
|
export default Form;
|
package/dist/index.js
CHANGED
|
@@ -6,6 +6,7 @@ import Input from "./components/Input";
|
|
|
6
6
|
import InputWrapper from "./components/Form/InputWrapper";
|
|
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
|
@@ -22,6 +22,9 @@ declare namespace Form {
|
|
|
22
22
|
var useSubmitDataWatch: typeof import("./Form").useSubmitDataWatch;
|
|
23
23
|
var useFormStateWatch: <T = any>(formNameOrFormInstance?: string | PublicFormInstance<T>) => any;
|
|
24
24
|
var useFormItemStateWatch: <T = any>(nameOrFormItemId: string, formNameOrFormInstance?: string | PublicFormInstance<T>) => UseFormItemStateWatchReturn;
|
|
25
|
+
var useWatchFormListeners: <T = any>(formNameOrFormInstance?: string | PublicFormInstance<T>) => {
|
|
26
|
+
listeners: import("../stores/formStore").ListenerItem[];
|
|
27
|
+
};
|
|
25
28
|
}
|
|
26
29
|
export default Form;
|
|
27
30
|
export declare function useFormContext(): any;
|
|
@@ -34,3 +37,6 @@ export declare function useSubmitDataWatch<T = any>({ formNameOrFormInstance, tr
|
|
|
34
37
|
}): T | undefined;
|
|
35
38
|
export declare const useFormStateWatch: <T = any>(formNameOrFormInstance?: string | PublicFormInstance<T>) => any;
|
|
36
39
|
export declare const useFormItemStateWatch: <T = any>(nameOrFormItemId: string, formNameOrFormInstance?: string | PublicFormInstance<T>) => UseFormItemStateWatchReturn;
|
|
40
|
+
export declare const useWatchFormListeners: <T = any>(formNameOrFormInstance?: string | PublicFormInstance<T>) => {
|
|
41
|
+
listeners: import("../stores/formStore").ListenerItem[];
|
|
42
|
+
};
|
package/dist/providers/Form.js
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { cloneDeep, get, isEqual, last, set,
|
|
2
|
+
import { cloneDeep, get, isEqual, isNil, last, set, uniqBy } from "lodash";
|
|
3
3
|
import { useTask } from "minh-custom-hooks-release";
|
|
4
4
|
import { createContext, useContext, useEffect, useState } from "react";
|
|
5
5
|
import { flushSync } from "react-dom";
|
|
6
6
|
import { useShallow } from "zustand/react/shallow";
|
|
7
7
|
import FormCleanUp from "../components/Form/FormCleanUp";
|
|
8
8
|
import { SUBMIT_STATE } from "../constants/form";
|
|
9
|
-
import {
|
|
9
|
+
import { useFormStore } from "../stores/formStore";
|
|
10
10
|
import { getAllNoneObjStringPath } from "../utils/obj.util";
|
|
11
11
|
const FormContext = createContext(null);
|
|
12
12
|
function Form({ children, formName, initialValues, onFinish, onReject, onFinally, FormElement, ...props }) {
|
|
@@ -39,7 +39,7 @@ 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
|
};
|
|
@@ -106,7 +106,7 @@ function Form({ children, formName, initialValues, onFinish, onReject, onFinally
|
|
|
106
106
|
const formValues = getFormValues(formName);
|
|
107
107
|
const resultValues = cloneDeep(formValues);
|
|
108
108
|
const cleanValues = {};
|
|
109
|
-
|
|
109
|
+
uniqBy(listeners, (l) => l.name).forEach((l) => {
|
|
110
110
|
set(cleanValues, l.name, get(resultValues, l.name));
|
|
111
111
|
});
|
|
112
112
|
const handleIsolateCase = async () => {
|
|
@@ -264,9 +264,10 @@ function useFormContext() {
|
|
|
264
264
|
return c;
|
|
265
265
|
}
|
|
266
266
|
function useForm(formNameOrFormInstance) {
|
|
267
|
-
const
|
|
267
|
+
const formContext = useContext(FormContext);
|
|
268
|
+
const targetFormName = isNil(formNameOrFormInstance) ? formContext == null ? void 0 : formContext.formName : typeof formNameOrFormInstance === "object" && formNameOrFormInstance !== null ? formNameOrFormInstance.formName : formNameOrFormInstance;
|
|
268
269
|
const formInstance = useFormStore((state) => {
|
|
269
|
-
return state.formInstances.find((i) => i.formName === targetFormName);
|
|
270
|
+
return Object.values(state.formInstances).find((i) => i.formName === targetFormName);
|
|
270
271
|
});
|
|
271
272
|
return [formInstance];
|
|
272
273
|
}
|
|
@@ -310,11 +311,22 @@ const useFormItemStateWatch = (nameOrFormItemId, formNameOrFormInstance) => {
|
|
|
310
311
|
errors: (listener == null ? void 0 : listener.internalErrors) || []
|
|
311
312
|
};
|
|
312
313
|
};
|
|
314
|
+
const useWatchFormListeners = (formNameOrFormInstance) => {
|
|
315
|
+
const [formInstance] = useForm(formNameOrFormInstance);
|
|
316
|
+
const listeners = useFormStore(useShallow((state) => {
|
|
317
|
+
const allListeners = state.listeners;
|
|
318
|
+
return {
|
|
319
|
+
listeners: allListeners.filter((l) => !isNil(formNameOrFormInstance) ? true : l.formName === (formInstance == null ? void 0 : formInstance.formName))
|
|
320
|
+
};
|
|
321
|
+
}));
|
|
322
|
+
return listeners;
|
|
323
|
+
};
|
|
313
324
|
Form.useForm = useForm;
|
|
314
325
|
Form.useWatch = useWatch;
|
|
315
326
|
Form.useSubmitDataWatch = useSubmitDataWatch;
|
|
316
327
|
Form.useFormStateWatch = useFormStateWatch;
|
|
317
328
|
Form.useFormItemStateWatch = useFormItemStateWatch;
|
|
329
|
+
Form.useWatchFormListeners = useWatchFormListeners;
|
|
318
330
|
export {
|
|
319
331
|
FormContext,
|
|
320
332
|
Form as default,
|
|
@@ -323,5 +335,6 @@ export {
|
|
|
323
335
|
useFormItemStateWatch,
|
|
324
336
|
useFormStateWatch,
|
|
325
337
|
useSubmitDataWatch,
|
|
326
|
-
useWatch
|
|
338
|
+
useWatch,
|
|
339
|
+
useWatchFormListeners
|
|
327
340
|
};
|
|
@@ -13,16 +13,38 @@ export interface FormInstance {
|
|
|
13
13
|
getFieldErrors: () => Record<string, any>;
|
|
14
14
|
setFieldFocus: (name: string) => void;
|
|
15
15
|
}
|
|
16
|
+
export interface ListenerItem {
|
|
17
|
+
name?: string;
|
|
18
|
+
formName?: string;
|
|
19
|
+
isTouched?: boolean;
|
|
20
|
+
isDirty?: boolean;
|
|
21
|
+
formItemId?: string;
|
|
22
|
+
internalErrors?: any;
|
|
23
|
+
onChange?: any;
|
|
24
|
+
onReset?: any;
|
|
25
|
+
onFocus?: any;
|
|
26
|
+
emitFocus?: any;
|
|
27
|
+
isInitied?: boolean;
|
|
28
|
+
}
|
|
29
|
+
export interface CleanUpItem {
|
|
30
|
+
name?: string;
|
|
31
|
+
type?: string;
|
|
32
|
+
key: string;
|
|
33
|
+
itemKey?: string;
|
|
34
|
+
formName?: string;
|
|
35
|
+
}
|
|
16
36
|
interface FormStoreState {
|
|
17
37
|
forms: Record<string, any>;
|
|
18
38
|
initialValues: Record<string, any>;
|
|
19
39
|
formStates: Record<string, any>;
|
|
20
40
|
cacheData: Record<string, any>;
|
|
21
|
-
formInstances: FormInstance
|
|
41
|
+
formInstances: Record<string, FormInstance>;
|
|
22
42
|
submitHistory: Record<string, any[]>;
|
|
43
|
+
listeners: ListenerItem[];
|
|
44
|
+
cleanUpStack: CleanUpItem[];
|
|
23
45
|
[key: string]: any;
|
|
24
46
|
}
|
|
25
47
|
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<
|
|
48
|
+
export declare const useFormListeners: import("zustand").UseBoundStore<import("zustand").StoreApi<FormStoreState>>;
|
|
49
|
+
export declare const useFormCleanUp: import("zustand").UseBoundStore<import("zustand").StoreApi<FormStoreState>>;
|
|
28
50
|
export {};
|
package/dist/stores/formStore.js
CHANGED
|
@@ -3,12 +3,12 @@ import { cloneDeep, get, isNil, isNumber, last, set, unset } from "lodash";
|
|
|
3
3
|
import { v4 } from "uuid";
|
|
4
4
|
import { create } from "zustand";
|
|
5
5
|
import { getAllNoneObjStringPath } from "../utils/obj.util";
|
|
6
|
-
const
|
|
6
|
+
const createFormStoreSlice = (storeSet, storeGet, api) => ({
|
|
7
7
|
forms: {},
|
|
8
8
|
initialValues: {},
|
|
9
9
|
formStates: {},
|
|
10
10
|
cacheData: {},
|
|
11
|
-
formInstances:
|
|
11
|
+
formInstances: {},
|
|
12
12
|
submitHistory: {},
|
|
13
13
|
setData(formName, name, value) {
|
|
14
14
|
return storeSet(produce((state) => {
|
|
@@ -191,8 +191,8 @@ const useFormStore = create((storeSet, storeGet) => ({
|
|
|
191
191
|
}
|
|
192
192
|
}));
|
|
193
193
|
}
|
|
194
|
-
})
|
|
195
|
-
const
|
|
194
|
+
});
|
|
195
|
+
const createListenersSlice = (storeSet, storeGet, api) => ({
|
|
196
196
|
listeners: [],
|
|
197
197
|
getListener(formItemId) {
|
|
198
198
|
return storeGet().listeners.find((l) => l.formItemId === formItemId);
|
|
@@ -261,8 +261,8 @@ const useFormListeners = create((storeSet, storeGet) => ({
|
|
|
261
261
|
}
|
|
262
262
|
}));
|
|
263
263
|
}
|
|
264
|
-
})
|
|
265
|
-
const
|
|
264
|
+
});
|
|
265
|
+
const createCleanUpSlice = (storeSet, storeGet, api) => ({
|
|
266
266
|
cleanUpStack: [],
|
|
267
267
|
setCleanUpStack({ name, type, itemKey, formName }) {
|
|
268
268
|
return storeSet(produce((state) => {
|
|
@@ -276,7 +276,14 @@ const useFormCleanUp = create((storeSet) => ({
|
|
|
276
276
|
state.cleanUpStack = [];
|
|
277
277
|
}));
|
|
278
278
|
}
|
|
279
|
+
});
|
|
280
|
+
const useFormStore = create((...a) => ({
|
|
281
|
+
...createFormStoreSlice(...a),
|
|
282
|
+
...createListenersSlice(...a),
|
|
283
|
+
...createCleanUpSlice(...a)
|
|
279
284
|
}));
|
|
285
|
+
const useFormListeners = useFormStore;
|
|
286
|
+
const useFormCleanUp = useFormStore;
|
|
280
287
|
export {
|
|
281
288
|
useFormCleanUp,
|
|
282
289
|
useFormListeners,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-form-manage",
|
|
3
|
-
"version": "1.0.8-beta.
|
|
3
|
+
"version": "1.0.8-beta.12",
|
|
4
4
|
"description": "Lightweight React form management with list and listener support.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -36,6 +36,7 @@
|
|
|
36
36
|
"@emotion/styled": "^11.14.1",
|
|
37
37
|
"@eslint/js": "^9.14.0",
|
|
38
38
|
"@mui/material": "^7.3.7",
|
|
39
|
+
"@types/lodash": "^4.17.23",
|
|
39
40
|
"@types/node": "^22.9.3",
|
|
40
41
|
"@types/react": "^19.2.9",
|
|
41
42
|
"@types/react-dom": "^19.2.3",
|
package/src/App.tsx
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Checkbox } from "@mui/material";
|
|
1
|
+
import { Checkbox, Dialog, DialogContent, TextField } from "@mui/material";
|
|
2
2
|
import { Button, Input } from "antd";
|
|
3
3
|
import { motion } from "framer-motion";
|
|
4
4
|
import { useEffect } from "react";
|
|
@@ -8,10 +8,45 @@ import InputWrapper from "./components/Form/InputWrapper";
|
|
|
8
8
|
import Form, { useForm } from "./providers/Form";
|
|
9
9
|
|
|
10
10
|
import { Form as AntdForm } from "antd";
|
|
11
|
+
import { useToggle } from "minh-custom-hooks-release";
|
|
12
|
+
|
|
13
|
+
function TestFormWatch() {
|
|
14
|
+
const watchValue = Form.useWatch("numericCode");
|
|
15
|
+
|
|
16
|
+
return <div>TestFormWatch</div>;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function TestMuiDialog({
|
|
20
|
+
open,
|
|
21
|
+
onClose,
|
|
22
|
+
}: {
|
|
23
|
+
open: boolean;
|
|
24
|
+
onClose: () => void;
|
|
25
|
+
}) {
|
|
26
|
+
return (
|
|
27
|
+
<Dialog open={open} onClose={onClose}>
|
|
28
|
+
<DialogContent>
|
|
29
|
+
{" "}
|
|
30
|
+
<Form
|
|
31
|
+
onFinish={(values) => {
|
|
32
|
+
console.log("Mui Dialog Form Values: ", values);
|
|
33
|
+
}}
|
|
34
|
+
formName="ADD_FORM"
|
|
35
|
+
>
|
|
36
|
+
<FormItem name="oooo">
|
|
37
|
+
<TextField />
|
|
38
|
+
</FormItem>
|
|
39
|
+
|
|
40
|
+
<Button htmlType="submit">Submit</Button>
|
|
41
|
+
</Form>
|
|
42
|
+
</DialogContent>
|
|
43
|
+
</Dialog>
|
|
44
|
+
);
|
|
45
|
+
}
|
|
11
46
|
|
|
12
47
|
const App = () => {
|
|
13
48
|
const [form] = useForm("form1");
|
|
14
|
-
|
|
49
|
+
const { state: open, toggle } = useToggle(false);
|
|
15
50
|
const watchCheckBox = Form.useWatch("checkControlledAfterInit", "form1");
|
|
16
51
|
|
|
17
52
|
useEffect(() => {
|
|
@@ -155,7 +190,7 @@ const App = () => {
|
|
|
155
190
|
<Checkbox />
|
|
156
191
|
</FormItem>
|
|
157
192
|
</motion.div>
|
|
158
|
-
|
|
193
|
+
<TestFormWatch />
|
|
159
194
|
<Button
|
|
160
195
|
onClick={() => {
|
|
161
196
|
const current = form?.getFieldValue("checkControlledAfterInit");
|
|
@@ -174,6 +209,9 @@ const App = () => {
|
|
|
174
209
|
Reset
|
|
175
210
|
</Button>
|
|
176
211
|
</Form>
|
|
212
|
+
|
|
213
|
+
<Button onClick={toggle}>Toggle Dialog</Button>
|
|
214
|
+
<TestMuiDialog onClose={toggle} open={open} />
|
|
177
215
|
</div>
|
|
178
216
|
);
|
|
179
217
|
};
|
|
@@ -1,20 +1,16 @@
|
|
|
1
1
|
import { useEffect } from "react";
|
|
2
2
|
import { useShallow } from "zustand/react/shallow";
|
|
3
|
-
import {
|
|
4
|
-
useFormCleanUp,
|
|
5
|
-
useFormListeners,
|
|
6
|
-
useFormStore,
|
|
7
|
-
} from "../../stores/formStore";
|
|
3
|
+
import { useFormStore } from "../../stores/formStore";
|
|
8
4
|
|
|
9
5
|
const FormCleanUp = () => {
|
|
10
|
-
const { cleanUpStack, clearCleanUpStack } =
|
|
6
|
+
const { cleanUpStack, clearCleanUpStack } = useFormStore(
|
|
11
7
|
useShallow((state) => ({
|
|
12
8
|
cleanUpStack: state.cleanUpStack,
|
|
13
9
|
clearCleanUpStack: state.clearCleanUpStack,
|
|
14
10
|
})),
|
|
15
11
|
);
|
|
16
12
|
|
|
17
|
-
const { revokeListener } =
|
|
13
|
+
const { revokeListener } = useFormStore(
|
|
18
14
|
useShallow((state) => ({
|
|
19
15
|
revokeListener: state.revokeListener,
|
|
20
16
|
})),
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import useFormListControl from "../../hooks/useFormListControl";
|
|
2
2
|
import type { FormInstance } from "../../stores/formStore";
|
|
3
3
|
|
|
4
4
|
export interface FormListProps<T = any> {
|
|
@@ -6,11 +6,24 @@ export interface FormListProps<T = any> {
|
|
|
6
6
|
initialValues?: T[];
|
|
7
7
|
form?: FormInstance;
|
|
8
8
|
formName?: string;
|
|
9
|
-
children: (
|
|
9
|
+
children: (
|
|
10
|
+
fields: Array<{ name: string; key: string }>,
|
|
11
|
+
operations: {
|
|
12
|
+
add: (index: number) => void;
|
|
13
|
+
remove: (opts: { index?: number; key?: string }) => void;
|
|
14
|
+
move: (opts: { from?: number; fromKey?: string; to: number }) => void;
|
|
15
|
+
},
|
|
16
|
+
) => React.ReactNode;
|
|
10
17
|
}
|
|
11
18
|
|
|
12
|
-
const FormList = <T = any
|
|
13
|
-
|
|
19
|
+
const FormList = <T = any,>({
|
|
20
|
+
name,
|
|
21
|
+
initialValues,
|
|
22
|
+
form,
|
|
23
|
+
formName,
|
|
24
|
+
children,
|
|
25
|
+
}: FormListProps<T>) => {
|
|
26
|
+
const { listFields, ...actions } = useFormListControl({
|
|
14
27
|
name,
|
|
15
28
|
initialValues,
|
|
16
29
|
form,
|
|
@@ -18,11 +18,7 @@ import {
|
|
|
18
18
|
IS_VIETNAMESE_PHONE_NUMBER_REGEX,
|
|
19
19
|
} from "../constants/validation";
|
|
20
20
|
import { useFormContext } from "../providers/Form";
|
|
21
|
-
import {
|
|
22
|
-
useFormCleanUp,
|
|
23
|
-
useFormListeners,
|
|
24
|
-
useFormStore,
|
|
25
|
-
} from "../stores/formStore";
|
|
21
|
+
import { useFormStore } from "../stores/formStore";
|
|
26
22
|
|
|
27
23
|
import type { FormInstance } from "../stores/formStore";
|
|
28
24
|
import type {
|
|
@@ -98,7 +94,7 @@ export default function useFormItemControl<T = any>({
|
|
|
98
94
|
}),
|
|
99
95
|
);
|
|
100
96
|
|
|
101
|
-
const { setCleanUpStack } =
|
|
97
|
+
const { setCleanUpStack } = useFormStore(
|
|
102
98
|
useShallow((state) => ({
|
|
103
99
|
setCleanUpStack: state.setCleanUpStack,
|
|
104
100
|
})),
|
|
@@ -130,7 +126,7 @@ export default function useFormItemControl<T = any>({
|
|
|
130
126
|
}),
|
|
131
127
|
);
|
|
132
128
|
|
|
133
|
-
const { listener, setListener } =
|
|
129
|
+
const { listener, setListener } = useFormStore(
|
|
134
130
|
useShallow((state) => {
|
|
135
131
|
// console.log(
|
|
136
132
|
// "Get listener from store: ",
|
|
@@ -3,7 +3,7 @@ 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
|
|
|
8
8
|
import type { FormInstance } from "../stores/formStore";
|
|
9
9
|
|
|
@@ -19,7 +19,7 @@ interface UseFormListControlProps {
|
|
|
19
19
|
interface UseFormListControlReturn {
|
|
20
20
|
listFields: ListField[];
|
|
21
21
|
move: (opts: { from?: number; fromKey?: string; to: number }) => void;
|
|
22
|
-
add: (index
|
|
22
|
+
add: (index?: number) => void;
|
|
23
23
|
remove: (opts: { index?: number; key?: string }) => void;
|
|
24
24
|
}
|
|
25
25
|
|
|
@@ -31,7 +31,9 @@ export default function useFormListControl<T = any>({
|
|
|
31
31
|
}: UseFormListControlProps): UseFormListControlReturn {
|
|
32
32
|
const contextForm = useFormContext();
|
|
33
33
|
const getFormValues = useFormStore((state) => state.getFormValues);
|
|
34
|
-
const [listFormInitValues, setListFormInitValues] = useState<
|
|
34
|
+
const [listFormInitValues, setListFormInitValues] = useState<
|
|
35
|
+
any[] | undefined
|
|
36
|
+
>(undefined);
|
|
35
37
|
const { clearCacheData, setCacheData } = useFormStore(
|
|
36
38
|
useShallow((state) => ({
|
|
37
39
|
cacheData: state.cacheData,
|
|
@@ -39,7 +41,7 @@ export default function useFormListControl<T = any>({
|
|
|
39
41
|
setCacheData: state.setCacheData,
|
|
40
42
|
})),
|
|
41
43
|
);
|
|
42
|
-
const { setCleanUpStack } =
|
|
44
|
+
const { setCleanUpStack } = useFormStore(
|
|
43
45
|
useShallow((state) => ({
|
|
44
46
|
setCleanUpStack: state.setCleanUpStack,
|
|
45
47
|
})),
|
|
@@ -135,13 +137,9 @@ export default function useFormListControl<T = any>({
|
|
|
135
137
|
);
|
|
136
138
|
};
|
|
137
139
|
|
|
138
|
-
const add = (index
|
|
140
|
+
const add = (index?: number) => {
|
|
139
141
|
setListFields((prev) => {
|
|
140
|
-
if (index
|
|
141
|
-
|
|
142
|
-
if (index < 0) return prev;
|
|
143
|
-
|
|
144
|
-
if (index === prev.length) {
|
|
142
|
+
if (isNil(index) || index === prev.length) {
|
|
145
143
|
const newName = `${name}.${prev.length}`;
|
|
146
144
|
const newKey = v4();
|
|
147
145
|
const result = [
|
|
@@ -154,6 +152,9 @@ export default function useFormListControl<T = any>({
|
|
|
154
152
|
|
|
155
153
|
return result;
|
|
156
154
|
}
|
|
155
|
+
if (index > prev.length) return prev;
|
|
156
|
+
|
|
157
|
+
if (index < 0) return prev;
|
|
157
158
|
|
|
158
159
|
const clonePrev = [...prev];
|
|
159
160
|
|
|
@@ -217,7 +218,15 @@ export default function useFormListControl<T = any>({
|
|
|
217
218
|
});
|
|
218
219
|
};
|
|
219
220
|
|
|
220
|
-
const move = ({
|
|
221
|
+
const move = ({
|
|
222
|
+
from,
|
|
223
|
+
fromKey,
|
|
224
|
+
to,
|
|
225
|
+
}: {
|
|
226
|
+
from?: number;
|
|
227
|
+
fromKey?: string;
|
|
228
|
+
to: number;
|
|
229
|
+
}) => {
|
|
221
230
|
setListFields((prev) => {
|
|
222
231
|
console.log("move list item: ", { from, to });
|
|
223
232
|
if (
|
|
@@ -286,7 +295,7 @@ export default function useFormListControl<T = any>({
|
|
|
286
295
|
useEffect(() => {
|
|
287
296
|
console.log("Trigger init", formState?.isInitied, internalInitValue);
|
|
288
297
|
if (formState?.isInitied) {
|
|
289
|
-
|
|
298
|
+
if (Array.isArray(listFormInitValues)) {
|
|
290
299
|
const result = listFormInitValues?.map((_, i) => {
|
|
291
300
|
const itemName = `${name}.${i}`;
|
|
292
301
|
const key = v4();
|
package/src/index.ts
CHANGED
|
@@ -19,6 +19,13 @@ import InputWrapper, { type InputWrapperProps } from "./components/Form/InputWra
|
|
|
19
19
|
import useFormItemControl from "./hooks/useFormItemControl";
|
|
20
20
|
import useFormListControl from "./hooks/useFormListControl";
|
|
21
21
|
|
|
22
|
+
import {
|
|
23
|
+
useFormStore,
|
|
24
|
+
type FormInstance,
|
|
25
|
+
type ListenerItem,
|
|
26
|
+
type CleanUpItem
|
|
27
|
+
} from "./stores/formStore";
|
|
28
|
+
|
|
22
29
|
export {
|
|
23
30
|
Form,
|
|
24
31
|
FormItem,
|
|
@@ -31,6 +38,7 @@ export {
|
|
|
31
38
|
useWatch,
|
|
32
39
|
useSubmitDataWatch,
|
|
33
40
|
useFormStateWatch,
|
|
41
|
+
useFormStore,
|
|
34
42
|
type FormProps,
|
|
35
43
|
type FormItemProps,
|
|
36
44
|
type FormListProps,
|
|
@@ -39,6 +47,9 @@ export {
|
|
|
39
47
|
type FormFieldError,
|
|
40
48
|
type SubmitState,
|
|
41
49
|
type UseFormItemStateWatchReturn,
|
|
50
|
+
type FormInstance,
|
|
51
|
+
type ListenerItem,
|
|
52
|
+
type CleanUpItem,
|
|
42
53
|
SUBMIT_STATE,
|
|
43
54
|
};
|
|
44
55
|
|
package/src/providers/Form.tsx
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { cloneDeep, get, isEqual, last, set,
|
|
1
|
+
import { cloneDeep, get, isEqual, isNil, last, set, uniqBy } from "lodash";
|
|
2
2
|
import { useTask } from "minh-custom-hooks-release";
|
|
3
3
|
import type { ComponentType, FormHTMLAttributes, ReactNode } from "react";
|
|
4
4
|
import { createContext, useContext, useEffect, useState } from "react";
|
|
@@ -6,7 +6,7 @@ import { flushSync } from "react-dom";
|
|
|
6
6
|
import { useShallow } from "zustand/react/shallow"; // Import useShallow
|
|
7
7
|
import FormCleanUp from "../components/Form/FormCleanUp";
|
|
8
8
|
import { SUBMIT_STATE } from "../constants/form";
|
|
9
|
-
import {
|
|
9
|
+
import { useFormStore } from "../stores/formStore";
|
|
10
10
|
import type {
|
|
11
11
|
PublicFormInstance,
|
|
12
12
|
UseFormItemStateWatchReturn,
|
|
@@ -81,7 +81,7 @@ export default function Form<T = any>({
|
|
|
81
81
|
})),
|
|
82
82
|
);
|
|
83
83
|
|
|
84
|
-
const { getListeners } =
|
|
84
|
+
const { getListeners } = useFormStore(
|
|
85
85
|
useShallow((state) => {
|
|
86
86
|
return {
|
|
87
87
|
getListeners: state.getListeners,
|
|
@@ -174,8 +174,8 @@ export default function Form<T = any>({
|
|
|
174
174
|
|
|
175
175
|
const resultValues = cloneDeep(formValues);
|
|
176
176
|
const cleanValues = {} as T;
|
|
177
|
-
|
|
178
|
-
set(cleanValues, l.name, get(resultValues, l.name));
|
|
177
|
+
uniqBy(listeners, (l: any) => l.name).forEach((l) => {
|
|
178
|
+
set(cleanValues as any, l.name, get(resultValues, l.name));
|
|
179
179
|
});
|
|
180
180
|
|
|
181
181
|
const handleIsolateCase = async () => {
|
|
@@ -413,14 +413,18 @@ export function useFormContext() {
|
|
|
413
413
|
export function useForm<T = any>(
|
|
414
414
|
formNameOrFormInstance?: string | PublicFormInstance<T>,
|
|
415
415
|
) {
|
|
416
|
-
const
|
|
417
|
-
|
|
418
|
-
|
|
416
|
+
const formContext = useContext(FormContext);
|
|
417
|
+
const targetFormName = isNil(formNameOrFormInstance)
|
|
418
|
+
? formContext?.formName
|
|
419
|
+
: typeof formNameOrFormInstance === "object" &&
|
|
420
|
+
formNameOrFormInstance !== null
|
|
419
421
|
? (formNameOrFormInstance as PublicFormInstance<T>).formName
|
|
420
422
|
: (formNameOrFormInstance as string | undefined);
|
|
421
423
|
|
|
422
424
|
const formInstance = useFormStore((state) => {
|
|
423
|
-
return state.formInstances.find(
|
|
425
|
+
return Object.values(state.formInstances).find(
|
|
426
|
+
(i) => i.formName === targetFormName,
|
|
427
|
+
);
|
|
424
428
|
}) as PublicFormInstance<T> | undefined;
|
|
425
429
|
|
|
426
430
|
return [formInstance];
|
|
@@ -507,8 +511,30 @@ export const useFormItemStateWatch = <T = any,>(
|
|
|
507
511
|
};
|
|
508
512
|
};
|
|
509
513
|
|
|
514
|
+
export const useWatchFormListeners = <T = any,>(
|
|
515
|
+
formNameOrFormInstance?: string | PublicFormInstance<T>,
|
|
516
|
+
) => {
|
|
517
|
+
const [formInstance] = useForm<T>(formNameOrFormInstance as any);
|
|
518
|
+
|
|
519
|
+
const listeners = useFormStore(
|
|
520
|
+
useShallow((state) => {
|
|
521
|
+
const allListeners = state.listeners;
|
|
522
|
+
return {
|
|
523
|
+
listeners: allListeners.filter((l) =>
|
|
524
|
+
!isNil(formNameOrFormInstance)
|
|
525
|
+
? true
|
|
526
|
+
: l.formName === formInstance?.formName,
|
|
527
|
+
),
|
|
528
|
+
};
|
|
529
|
+
}),
|
|
530
|
+
);
|
|
531
|
+
|
|
532
|
+
return listeners;
|
|
533
|
+
};
|
|
534
|
+
|
|
510
535
|
Form.useForm = useForm;
|
|
511
536
|
Form.useWatch = useWatch;
|
|
512
537
|
Form.useSubmitDataWatch = useSubmitDataWatch;
|
|
513
538
|
Form.useFormStateWatch = useFormStateWatch;
|
|
514
539
|
Form.useFormItemStateWatch = useFormItemStateWatch;
|
|
540
|
+
Form.useWatchFormListeners = useWatchFormListeners;
|
package/src/stores/formStore.ts
CHANGED
|
@@ -17,7 +17,7 @@ export interface FormInstance {
|
|
|
17
17
|
setFieldFocus: (name: string) => void;
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
-
interface ListenerItem {
|
|
20
|
+
export interface ListenerItem {
|
|
21
21
|
name?: string;
|
|
22
22
|
formName?: string;
|
|
23
23
|
isTouched?: boolean;
|
|
@@ -28,9 +28,10 @@ interface ListenerItem {
|
|
|
28
28
|
onReset?: any;
|
|
29
29
|
onFocus?: any;
|
|
30
30
|
emitFocus?: any;
|
|
31
|
+
isInitied?: boolean;
|
|
31
32
|
}
|
|
32
33
|
|
|
33
|
-
interface CleanUpItem {
|
|
34
|
+
export interface CleanUpItem {
|
|
34
35
|
name?: string;
|
|
35
36
|
type?: string;
|
|
36
37
|
key: string;
|
|
@@ -43,19 +44,23 @@ interface FormStoreState {
|
|
|
43
44
|
initialValues: Record<string, any>;
|
|
44
45
|
formStates: Record<string, any>;
|
|
45
46
|
cacheData: Record<string, any>;
|
|
46
|
-
formInstances: FormInstance
|
|
47
|
+
formInstances: Record<string, FormInstance>;
|
|
47
48
|
submitHistory: Record<string, any[]>;
|
|
49
|
+
listeners: ListenerItem[];
|
|
50
|
+
cleanUpStack: CleanUpItem[];
|
|
48
51
|
// methods (loose typed for incremental migration)
|
|
49
52
|
[key: string]: any;
|
|
50
53
|
}
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
54
|
+
|
|
55
|
+
// Combined store containing all form-related state
|
|
56
|
+
// Form Store Slice
|
|
57
|
+
const createFormStoreSlice = (storeSet: any, storeGet: any, api: any) => ({
|
|
58
|
+
forms: {},
|
|
59
|
+
initialValues: {},
|
|
60
|
+
formStates: {},
|
|
61
|
+
cacheData: {},
|
|
62
|
+
formInstances: {},
|
|
63
|
+
submitHistory: {},
|
|
59
64
|
setData(formName, name, value) {
|
|
60
65
|
return storeSet(
|
|
61
66
|
produce<any>((state: any) => {
|
|
@@ -353,13 +358,13 @@ export const useFormStore = create<FormStoreState>(
|
|
|
353
358
|
}),
|
|
354
359
|
);
|
|
355
360
|
},
|
|
356
|
-
|
|
357
|
-
);
|
|
361
|
+
});
|
|
358
362
|
|
|
359
|
-
|
|
363
|
+
// Listeners Slice
|
|
364
|
+
const createListenersSlice = (storeSet: any, storeGet: any, api: any) => ({
|
|
360
365
|
listeners: [],
|
|
361
|
-
getListener(formItemId) {
|
|
362
|
-
return storeGet().listeners.find((l) => l.formItemId === formItemId);
|
|
366
|
+
getListener(formItemId: string) {
|
|
367
|
+
return storeGet().listeners.find((l: any) => l.formItemId === formItemId);
|
|
363
368
|
},
|
|
364
369
|
getListeners() {
|
|
365
370
|
return storeGet().listeners;
|
|
@@ -376,7 +381,7 @@ export const useFormListeners = create<any>((storeSet: any, storeGet: any) => ({
|
|
|
376
381
|
onFocus,
|
|
377
382
|
emitFocus,
|
|
378
383
|
isInitied,
|
|
379
|
-
}) {
|
|
384
|
+
}: any) {
|
|
380
385
|
return storeSet(
|
|
381
386
|
produce<any>((state: any) => {
|
|
382
387
|
const storeListeners = state.listeners;
|
|
@@ -433,7 +438,7 @@ export const useFormListeners = create<any>((storeSet: any, storeGet: any) => ({
|
|
|
433
438
|
}),
|
|
434
439
|
);
|
|
435
440
|
},
|
|
436
|
-
revokeListener(formItemId, onAfterRevoke) {
|
|
441
|
+
revokeListener(formItemId: string, onAfterRevoke: any) {
|
|
437
442
|
return storeSet(
|
|
438
443
|
produce<any>((state: any) => {
|
|
439
444
|
const storeListeners = state.listeners;
|
|
@@ -442,8 +447,6 @@ export const useFormListeners = create<any>((storeSet: any, storeGet: any) => ({
|
|
|
442
447
|
(l: any) => l.formItemId == formItemId,
|
|
443
448
|
);
|
|
444
449
|
|
|
445
|
-
// console.log("Find item for revoke: ", findListenerIndex, formItemId);
|
|
446
|
-
|
|
447
450
|
if (findListenerIndex > -1) {
|
|
448
451
|
const listenersInfo = cloneDeep(storeListeners[findListenerIndex]);
|
|
449
452
|
|
|
@@ -462,11 +465,12 @@ export const useFormListeners = create<any>((storeSet: any, storeGet: any) => ({
|
|
|
462
465
|
}),
|
|
463
466
|
);
|
|
464
467
|
},
|
|
465
|
-
})
|
|
468
|
+
});
|
|
466
469
|
|
|
467
|
-
|
|
470
|
+
// CleanUp Slice
|
|
471
|
+
const createCleanUpSlice = (storeSet: any, storeGet: any, api: any) => ({
|
|
468
472
|
cleanUpStack: [],
|
|
469
|
-
setCleanUpStack({ name, type, itemKey, formName }) {
|
|
473
|
+
setCleanUpStack({ name, type, itemKey, formName }: any) {
|
|
470
474
|
return storeSet(
|
|
471
475
|
produce<any>((state: any) => {
|
|
472
476
|
const oldValues = state.cleanUpStack;
|
|
@@ -482,4 +486,15 @@ export const useFormCleanUp = create<any>((storeSet: any) => ({
|
|
|
482
486
|
}),
|
|
483
487
|
);
|
|
484
488
|
},
|
|
489
|
+
});
|
|
490
|
+
|
|
491
|
+
// Combined Store
|
|
492
|
+
export const useFormStore = create<FormStoreState>((...a) => ({
|
|
493
|
+
...createFormStoreSlice(...a),
|
|
494
|
+
...createListenersSlice(...a),
|
|
495
|
+
...createCleanUpSlice(...a),
|
|
485
496
|
}));
|
|
497
|
+
|
|
498
|
+
// Deprecated exports - use useFormStore instead
|
|
499
|
+
export const useFormListeners = useFormStore;
|
|
500
|
+
export const useFormCleanUp = useFormStore;
|