react-form-manage 1.0.8-beta.2 → 1.0.8-beta.21
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 +85 -5
- package/README.md +8 -4
- package/dist/components/Form/FormCleanUp.js +3 -3
- package/dist/components/Form/FormItem.d.ts +4 -2
- package/dist/components/Form/FormItem.js +7 -5
- package/dist/components/Form/FormList.d.ts +2 -2
- package/dist/components/Form/FormList.js +2 -2
- package/dist/hooks/useFormItemControl.d.ts +1 -0
- package/dist/hooks/useFormItemControl.js +60 -23
- package/dist/hooks/useFormListControl.d.ts +2 -1
- package/dist/hooks/useFormListControl.js +60 -10
- 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 +4 -2
- package/dist/providers/Form.js +98 -28
- package/dist/stores/formStore.d.ts +27 -2
- package/dist/stores/formStore.js +25 -9
- 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/TestSelect.d.ts +6 -0
- package/dist/test/TestSelect.js +24 -0
- package/dist/types/index.d.ts +1 -1
- package/dist/types/public.d.ts +6 -1
- package/dist/utils/obj.util.d.ts +1 -1
- package/dist/utils/obj.util.js +16 -5
- package/package.json +3 -1
- package/src/App.tsx +98 -4
- package/src/components/Form/FormCleanUp.tsx +3 -7
- package/src/components/Form/FormItem.tsx +56 -31
- package/src/components/Form/FormList.tsx +17 -4
- package/src/components/Form/InputWrapper.tsx +5 -0
- package/src/hooks/useFormItemControl.ts +70 -29
- package/src/hooks/useFormListControl.ts +104 -26
- package/src/index.ts +27 -13
- package/src/providers/Form.tsx +126 -17
- package/src/stores/formStore.ts +319 -288
- package/src/test/TestDialog.tsx +52 -0
- package/src/test/TestListener.tsx +21 -0
- package/src/test/TestSelect.tsx +38 -0
- package/src/types/index.ts +1 -1
- package/src/types/public.ts +7 -1
- package/src/utils/obj.util.ts +44 -13
package/dist/providers/Form.js
CHANGED
|
@@ -1,34 +1,45 @@
|
|
|
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, isPlainObject, 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
|
-
import {
|
|
8
|
+
import { SUBMIT_STATE } from "../constants/form";
|
|
9
|
+
import { useFormStore } from "../stores/formStore";
|
|
9
10
|
import { getAllNoneObjStringPath } from "../utils/obj.util";
|
|
10
11
|
const FormContext = createContext(null);
|
|
11
12
|
function Form({ children, formName, initialValues, onFinish, onReject, onFinally, FormElement, ...props }) {
|
|
12
|
-
const {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
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) => {
|
|
32
43
|
return {
|
|
33
44
|
getListeners: state.getListeners
|
|
34
45
|
};
|
|
@@ -36,9 +47,36 @@ function Form({ children, formName, initialValues, onFinish, onReject, onFinally
|
|
|
36
47
|
const setFieldValue = (name, value, options) => {
|
|
37
48
|
const listener = getListeners().find((l) => l.name === name && l.formName === formName);
|
|
38
49
|
if (listener) {
|
|
39
|
-
listener.
|
|
50
|
+
if (listener.type === "array") {
|
|
51
|
+
if (!isEqual(getFormItemValue(formName, name), value)) {
|
|
52
|
+
listener.onArrayChange(value, options);
|
|
53
|
+
const allStringPath = getAllNoneObjStringPath(value);
|
|
54
|
+
allStringPath.forEach((p) => {
|
|
55
|
+
const findListener = getListeners().find((l) => l.name === `${name}.${p}` && l.formName === formName);
|
|
56
|
+
if (findListener) {
|
|
57
|
+
findListener.onChange(get(value, p), options);
|
|
58
|
+
} else {
|
|
59
|
+
setData(formName, `${name}.${p}`, get(value, p));
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
} else {
|
|
64
|
+
listener.onChange(value, options);
|
|
65
|
+
}
|
|
40
66
|
} else {
|
|
41
|
-
|
|
67
|
+
if (isPlainObject(value) || Array.isArray(value)) {
|
|
68
|
+
const allStringPath = getAllNoneObjStringPath(value);
|
|
69
|
+
allStringPath.forEach((p) => {
|
|
70
|
+
const findListener = getListeners().find((l) => l.name === `${name}.${p}` && l.formName === formName);
|
|
71
|
+
if (findListener) {
|
|
72
|
+
findListener.onChange(get(value, p), options);
|
|
73
|
+
} else {
|
|
74
|
+
setData(formName, `${name}.${p}`, get(value, p));
|
|
75
|
+
}
|
|
76
|
+
});
|
|
77
|
+
} else {
|
|
78
|
+
setData(formName, name, value);
|
|
79
|
+
}
|
|
42
80
|
}
|
|
43
81
|
};
|
|
44
82
|
const setFieldValues = (values, options = { notTriggerDirty: false }) => {
|
|
@@ -46,7 +84,24 @@ function Form({ children, formName, initialValues, onFinish, onReject, onFinally
|
|
|
46
84
|
allStringPath.forEach((p) => {
|
|
47
85
|
const listener = getListeners().find((l) => l.name === p && l.formName === formName);
|
|
48
86
|
if (listener) {
|
|
49
|
-
listener.
|
|
87
|
+
if (listener.type === "array") {
|
|
88
|
+
if (!isEqual(getFormItemValue(formName, p), get(values, p))) {
|
|
89
|
+
listener.onArrayChange(get(values, listener.name), options);
|
|
90
|
+
const nestedAllStringPath = getAllNoneObjStringPath(get(values, p));
|
|
91
|
+
nestedAllStringPath.forEach((np) => {
|
|
92
|
+
{
|
|
93
|
+
const findListener = getListeners().find((l) => l.name === `${p}.${np}` && l.formName === formName);
|
|
94
|
+
if (findListener) {
|
|
95
|
+
findListener.onChange(get(values, `${p}.${np}`), options);
|
|
96
|
+
} else {
|
|
97
|
+
setData(formName, `${p}.${np}`, get(values, `${p}.${np}`));
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
} else {
|
|
103
|
+
listener.onChange(get(values, listener.name), options);
|
|
104
|
+
}
|
|
50
105
|
} else {
|
|
51
106
|
setData(formName, p, get(values, p));
|
|
52
107
|
}
|
|
@@ -95,7 +150,7 @@ function Form({ children, formName, initialValues, onFinish, onReject, onFinally
|
|
|
95
150
|
const formValues = getFormValues(formName);
|
|
96
151
|
const resultValues = cloneDeep(formValues);
|
|
97
152
|
const cleanValues = {};
|
|
98
|
-
|
|
153
|
+
uniqBy(listeners, (l) => l.name).forEach((l) => {
|
|
99
154
|
set(cleanValues, l.name, get(resultValues, l.name));
|
|
100
155
|
});
|
|
101
156
|
const handleIsolateCase = async () => {
|
|
@@ -167,7 +222,8 @@ function Form({ children, formName, initialValues, onFinish, onReject, onFinally
|
|
|
167
222
|
reset();
|
|
168
223
|
flushSync(setFormState({
|
|
169
224
|
formName,
|
|
170
|
-
isInitied: false
|
|
225
|
+
isInitied: false,
|
|
226
|
+
submitState: SUBMIT_STATE.IDLE
|
|
171
227
|
}));
|
|
172
228
|
const totalListenerFields = getListeners();
|
|
173
229
|
if (Array.isArray(resetOptions)) {
|
|
@@ -252,7 +308,8 @@ function useFormContext() {
|
|
|
252
308
|
return c;
|
|
253
309
|
}
|
|
254
310
|
function useForm(formNameOrFormInstance) {
|
|
255
|
-
const
|
|
311
|
+
const formContext = useContext(FormContext);
|
|
312
|
+
const targetFormName = isNil(formNameOrFormInstance) ? formContext == null ? void 0 : formContext.formName : typeof formNameOrFormInstance === "object" && formNameOrFormInstance !== null ? formNameOrFormInstance.formName : formNameOrFormInstance;
|
|
256
313
|
const formInstance = useFormStore((state) => {
|
|
257
314
|
return state.formInstances.find((i) => i.formName === targetFormName);
|
|
258
315
|
});
|
|
@@ -287,15 +344,28 @@ const useFormStateWatch = (formNameOrFormInstance) => {
|
|
|
287
344
|
});
|
|
288
345
|
return formState;
|
|
289
346
|
};
|
|
347
|
+
const useFormItemStateWatch = (nameOrFormItemId, formNameOrFormInstance) => {
|
|
348
|
+
const [formInstance] = useForm(formNameOrFormInstance);
|
|
349
|
+
const listener = useFormStore((state) => {
|
|
350
|
+
return state.getListeners().find((l) => l.formName === (formInstance == null ? void 0 : formInstance.formName) && (l.name === nameOrFormItemId || l.formItemId === nameOrFormItemId));
|
|
351
|
+
});
|
|
352
|
+
return {
|
|
353
|
+
isTouched: listener == null ? void 0 : listener.isTouched,
|
|
354
|
+
isDirty: listener == null ? void 0 : listener.isDirty,
|
|
355
|
+
errors: (listener == null ? void 0 : listener.internalErrors) || []
|
|
356
|
+
};
|
|
357
|
+
};
|
|
290
358
|
Form.useForm = useForm;
|
|
291
359
|
Form.useWatch = useWatch;
|
|
292
360
|
Form.useSubmitDataWatch = useSubmitDataWatch;
|
|
293
361
|
Form.useFormStateWatch = useFormStateWatch;
|
|
362
|
+
Form.useFormItemStateWatch = useFormItemStateWatch;
|
|
294
363
|
export {
|
|
295
364
|
FormContext,
|
|
296
365
|
Form as default,
|
|
297
366
|
useForm,
|
|
298
367
|
useFormContext,
|
|
368
|
+
useFormItemStateWatch,
|
|
299
369
|
useFormStateWatch,
|
|
300
370
|
useSubmitDataWatch,
|
|
301
371
|
useWatch
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
type ListenerFormItemType = "normal" | "array";
|
|
1
2
|
export interface FormInstance {
|
|
2
3
|
formName: string;
|
|
3
4
|
resetFields: (values?: any) => void;
|
|
@@ -13,6 +14,28 @@ export interface FormInstance {
|
|
|
13
14
|
getFieldErrors: () => Record<string, any>;
|
|
14
15
|
setFieldFocus: (name: string) => void;
|
|
15
16
|
}
|
|
17
|
+
export interface ListenerItem {
|
|
18
|
+
name?: string;
|
|
19
|
+
formName?: string;
|
|
20
|
+
isTouched?: boolean;
|
|
21
|
+
isDirty?: boolean;
|
|
22
|
+
formItemId?: string;
|
|
23
|
+
internalErrors?: any;
|
|
24
|
+
onArrayChange?: any;
|
|
25
|
+
onChange?: any;
|
|
26
|
+
onReset?: any;
|
|
27
|
+
onFocus?: any;
|
|
28
|
+
emitFocus?: any;
|
|
29
|
+
isInitied?: boolean;
|
|
30
|
+
type?: ListenerFormItemType;
|
|
31
|
+
}
|
|
32
|
+
export interface CleanUpItem {
|
|
33
|
+
name?: string;
|
|
34
|
+
type?: string;
|
|
35
|
+
key: string;
|
|
36
|
+
itemKey?: string;
|
|
37
|
+
formName?: string;
|
|
38
|
+
}
|
|
16
39
|
interface FormStoreState {
|
|
17
40
|
forms: Record<string, any>;
|
|
18
41
|
initialValues: Record<string, any>;
|
|
@@ -20,9 +43,11 @@ interface FormStoreState {
|
|
|
20
43
|
cacheData: Record<string, any>;
|
|
21
44
|
formInstances: FormInstance[];
|
|
22
45
|
submitHistory: Record<string, any[]>;
|
|
46
|
+
listeners: ListenerItem[];
|
|
47
|
+
cleanUpStack: CleanUpItem[];
|
|
23
48
|
[key: string]: any;
|
|
24
49
|
}
|
|
25
50
|
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<
|
|
51
|
+
export declare const useFormListeners: import("zustand").UseBoundStore<import("zustand").StoreApi<FormStoreState>>;
|
|
52
|
+
export declare const useFormCleanUp: import("zustand").UseBoundStore<import("zustand").StoreApi<FormStoreState>>;
|
|
28
53
|
export {};
|
package/dist/stores/formStore.js
CHANGED
|
@@ -3,7 +3,7 @@ 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: {},
|
|
@@ -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);
|
|
@@ -200,7 +200,7 @@ const useFormListeners = create((storeSet, storeGet) => ({
|
|
|
200
200
|
getListeners() {
|
|
201
201
|
return storeGet().listeners;
|
|
202
202
|
},
|
|
203
|
-
setListener({ formName, name, onChange, onReset, isTouched, isDirty, formItemId, internalErrors, onFocus, emitFocus }) {
|
|
203
|
+
setListener({ formName, name, onChange, onReset, isTouched, isDirty, formItemId, internalErrors, onFocus, emitFocus, isInitied, type, onArrayChange }) {
|
|
204
204
|
return storeSet(produce((state) => {
|
|
205
205
|
const storeListeners = state.listeners;
|
|
206
206
|
const findListenerIndex = state.listeners.findIndex((l) => l.formItemId === formItemId);
|
|
@@ -232,17 +232,26 @@ const useFormListeners = create((storeSet, storeGet) => ({
|
|
|
232
232
|
if (!isNil(emitFocus)) {
|
|
233
233
|
storeListeners[findListenerIndex].emitFocus = emitFocus;
|
|
234
234
|
}
|
|
235
|
+
if (!isNil(isInitied)) {
|
|
236
|
+
storeListeners[findListenerIndex].isInitied = isInitied;
|
|
237
|
+
}
|
|
238
|
+
if (!isNil(onArrayChange)) {
|
|
239
|
+
storeListeners[findListenerIndex].onArrayChange = onArrayChange;
|
|
240
|
+
}
|
|
235
241
|
return;
|
|
236
242
|
}
|
|
237
243
|
storeListeners.push({
|
|
238
244
|
name,
|
|
239
245
|
formName,
|
|
240
|
-
isTouched,
|
|
241
|
-
isDirty,
|
|
246
|
+
isTouched: Boolean(isTouched),
|
|
247
|
+
isDirty: Boolean(isDirty),
|
|
242
248
|
formItemId,
|
|
243
249
|
internalErrors,
|
|
244
250
|
onChange,
|
|
245
|
-
onReset
|
|
251
|
+
onReset,
|
|
252
|
+
isInitied: Boolean(isInitied),
|
|
253
|
+
type: type || "normal",
|
|
254
|
+
onArrayChange
|
|
246
255
|
});
|
|
247
256
|
}));
|
|
248
257
|
},
|
|
@@ -257,8 +266,8 @@ const useFormListeners = create((storeSet, storeGet) => ({
|
|
|
257
266
|
}
|
|
258
267
|
}));
|
|
259
268
|
}
|
|
260
|
-
})
|
|
261
|
-
const
|
|
269
|
+
});
|
|
270
|
+
const createCleanUpSlice = (storeSet, storeGet, api) => ({
|
|
262
271
|
cleanUpStack: [],
|
|
263
272
|
setCleanUpStack({ name, type, itemKey, formName }) {
|
|
264
273
|
return storeSet(produce((state) => {
|
|
@@ -272,7 +281,14 @@ const useFormCleanUp = create((storeSet) => ({
|
|
|
272
281
|
state.cleanUpStack = [];
|
|
273
282
|
}));
|
|
274
283
|
}
|
|
284
|
+
});
|
|
285
|
+
const useFormStore = create((...a) => ({
|
|
286
|
+
...createFormStoreSlice(...a),
|
|
287
|
+
...createListenersSlice(...a),
|
|
288
|
+
...createCleanUpSlice(...a)
|
|
275
289
|
}));
|
|
290
|
+
const useFormListeners = useFormStore;
|
|
291
|
+
const useFormCleanUp = useFormStore;
|
|
276
292
|
export {
|
|
277
293
|
useFormCleanUp,
|
|
278
294
|
useFormListeners,
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Button, Dialog, DialogContent, DialogContentText, DialogTitle, TextField } from "@mui/material";
|
|
3
|
+
import { Box } from "@mui/system";
|
|
4
|
+
import { useToggle } from "minh-custom-hooks-release";
|
|
5
|
+
import FormItem from "../components/Form/FormItem";
|
|
6
|
+
import TestSelect from "./TestSelect";
|
|
7
|
+
function TestDialog({}) {
|
|
8
|
+
const { state: open, toggle } = useToggle();
|
|
9
|
+
return _jsxs(Box, { children: [_jsxs(Dialog, { open, onClose: toggle, children: [_jsx(DialogTitle, { children: "Test Dialog" }), _jsxs(DialogContent, { children: [_jsx(DialogContentText, { children: "This is a test dialog." }), _jsx(FormItem, { rules: [
|
|
10
|
+
{
|
|
11
|
+
handler(value) {
|
|
12
|
+
return Boolean(value);
|
|
13
|
+
},
|
|
14
|
+
message: "Testt"
|
|
15
|
+
}
|
|
16
|
+
], controlAfterInit: true, initialValue: null, name: "testSelectInsideDialog", children: _jsx(TestSelect, {}) }), _jsx(FormItem, { controlAfterInit: true, initialValue: "", name: "anotherField", children: _jsx(TextField, {}) })] })] }), _jsx(Button, { variant: "contained", onClick: toggle, children: "Open Test Dialog" })] });
|
|
17
|
+
}
|
|
18
|
+
var stdin_default = TestDialog;
|
|
19
|
+
export {
|
|
20
|
+
stdin_default as default
|
|
21
|
+
};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { cloneDeep } from "lodash";
|
|
3
|
+
import { useEffect } from "react";
|
|
4
|
+
import { useShallow } from "zustand/react/shallow";
|
|
5
|
+
import { useFormStore } from "../stores/formStore";
|
|
6
|
+
function TestListener({}) {
|
|
7
|
+
const { listeners } = useFormStore(useShallow((state) => ({
|
|
8
|
+
listeners: state.listeners
|
|
9
|
+
})));
|
|
10
|
+
useEffect(() => {
|
|
11
|
+
}, [listeners]);
|
|
12
|
+
return _jsx("div", { children: "TestListener" });
|
|
13
|
+
}
|
|
14
|
+
var stdin_default = TestListener;
|
|
15
|
+
export {
|
|
16
|
+
stdin_default as default
|
|
17
|
+
};
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { Autocomplete, TextField } from "@mui/material";
|
|
3
|
+
function TestSelect({ value = null, onChange }) {
|
|
4
|
+
return _jsx(Autocomplete, { value, onChange: (_, newValue) => {
|
|
5
|
+
onChange == null ? void 0 : onChange(newValue);
|
|
6
|
+
}, renderInput: (params) => _jsx(TextField, { ...params }), options: [
|
|
7
|
+
{
|
|
8
|
+
value: "option1",
|
|
9
|
+
label: "Option 1"
|
|
10
|
+
},
|
|
11
|
+
{
|
|
12
|
+
value: "option2",
|
|
13
|
+
label: "Option 2"
|
|
14
|
+
}
|
|
15
|
+
], getOptionKey: (o) => {
|
|
16
|
+
return o == null ? void 0 : o.value;
|
|
17
|
+
}, getOptionLabel: (o) => {
|
|
18
|
+
return o == null ? void 0 : o.label;
|
|
19
|
+
} });
|
|
20
|
+
}
|
|
21
|
+
var stdin_default = TestSelect;
|
|
22
|
+
export {
|
|
23
|
+
stdin_default as default
|
|
24
|
+
};
|
package/dist/types/index.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export * from
|
|
1
|
+
export * from "./public";
|
package/dist/types/public.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type { GetConstantType } from "./util";
|
|
2
1
|
import type { SUBMIT_STATE } from "../constants/form";
|
|
2
|
+
import type { GetConstantType } from "./util";
|
|
3
3
|
export type FormValues<T = any> = T;
|
|
4
4
|
export interface FormFieldError {
|
|
5
5
|
ruleName: string | number;
|
|
@@ -61,6 +61,11 @@ export interface UseFormItemReturn<T = any> {
|
|
|
61
61
|
isDirty?: boolean;
|
|
62
62
|
submitState?: SubmitState;
|
|
63
63
|
}
|
|
64
|
+
export interface UseFormItemStateWatchReturn {
|
|
65
|
+
isTouched?: boolean;
|
|
66
|
+
isDirty?: boolean;
|
|
67
|
+
errors: FormFieldError[];
|
|
68
|
+
}
|
|
64
69
|
export interface UseFormListProps<T = any> {
|
|
65
70
|
name?: string;
|
|
66
71
|
form?: PublicFormInstance<T>;
|
package/dist/utils/obj.util.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export declare function getAllNoneObjStringPath(value: any, prevPath?: string):
|
|
1
|
+
export declare function getAllNoneObjStringPath(value: any, prevPath?: string): string[];
|
|
2
2
|
export declare function getAllStringPath(value: any, prevPath?: string): any;
|
package/dist/utils/obj.util.js
CHANGED
|
@@ -1,14 +1,25 @@
|
|
|
1
|
-
import { filter, isNil, join } from "lodash";
|
|
1
|
+
import { filter, isNil, isPlainObject, join } from "lodash";
|
|
2
2
|
function getAllNoneObjStringPath(value, prevPath = "") {
|
|
3
|
-
if (
|
|
4
|
-
return
|
|
3
|
+
if (value === null || value === void 0 || typeof value !== "object" || typeof value === "function") {
|
|
4
|
+
return [prevPath];
|
|
5
|
+
}
|
|
6
|
+
if (Array.isArray(value)) {
|
|
7
|
+
return value.reduce((prev, item, index) => {
|
|
5
8
|
return [
|
|
6
9
|
...prev,
|
|
7
|
-
...getAllNoneObjStringPath(
|
|
10
|
+
...getAllNoneObjStringPath(item, join(filter([prevPath, String(index)], (v) => !isNil(v) && v !== ""), "."))
|
|
8
11
|
];
|
|
9
12
|
}, []);
|
|
10
13
|
}
|
|
11
|
-
|
|
14
|
+
if (!isPlainObject(value)) {
|
|
15
|
+
return [prevPath];
|
|
16
|
+
}
|
|
17
|
+
return Object.keys(value).reduce((prev, cur) => {
|
|
18
|
+
return [
|
|
19
|
+
...prev,
|
|
20
|
+
...getAllNoneObjStringPath(value[cur], join(filter([prevPath, cur], (v) => !isNil(v) && v !== ""), "."))
|
|
21
|
+
];
|
|
22
|
+
}, []);
|
|
12
23
|
}
|
|
13
24
|
function getAllStringPath(value, prevPath = "") {
|
|
14
25
|
if (typeof value === "object") {
|
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.21",
|
|
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",
|
|
@@ -45,6 +46,7 @@
|
|
|
45
46
|
"eslint": "^9.14.0",
|
|
46
47
|
"eslint-plugin-react-hooks": "^5.1.0",
|
|
47
48
|
"eslint-plugin-react-refresh": "^0.4.14",
|
|
49
|
+
"framer-motion": "^12.29.0",
|
|
48
50
|
"globals": "^15.12.0",
|
|
49
51
|
"react": "^19.0.0",
|
|
50
52
|
"react-dom": "^19.0.0",
|
package/src/App.tsx
CHANGED
|
@@ -1,13 +1,26 @@
|
|
|
1
|
+
import { Checkbox } from "@mui/material";
|
|
1
2
|
import { Button, Input } from "antd";
|
|
3
|
+
import { motion } from "framer-motion";
|
|
2
4
|
import { useEffect } from "react";
|
|
3
5
|
import FormItem from "./components/Form/FormItem";
|
|
4
6
|
import FormList from "./components/Form/FormList";
|
|
5
7
|
import InputWrapper from "./components/Form/InputWrapper";
|
|
6
8
|
import Form, { useForm } from "./providers/Form";
|
|
9
|
+
import TestDialog from "./test/TestDialog";
|
|
10
|
+
|
|
11
|
+
import { Form as AntdForm } from "antd";
|
|
12
|
+
|
|
13
|
+
function TestFormWatch() {
|
|
14
|
+
const watchValue = Form.useWatch("numericCode");
|
|
15
|
+
|
|
16
|
+
return <div>TestFormWatch</div>;
|
|
17
|
+
}
|
|
7
18
|
|
|
8
19
|
const App = () => {
|
|
9
20
|
const [form] = useForm("form1");
|
|
10
21
|
|
|
22
|
+
const watchCheckBox = Form.useWatch("checkControlledAfterInit", "form1");
|
|
23
|
+
|
|
11
24
|
useEffect(() => {
|
|
12
25
|
if (form) {
|
|
13
26
|
// setTimeout(() => {
|
|
@@ -17,16 +30,31 @@ const App = () => {
|
|
|
17
30
|
}, [form]);
|
|
18
31
|
return (
|
|
19
32
|
<div>
|
|
33
|
+
<AntdForm>
|
|
34
|
+
<motion.div
|
|
35
|
+
initial={{ opacity: 0 }}
|
|
36
|
+
animate={{ opacity: 1 }}
|
|
37
|
+
exit={{ opacity: 0 }}
|
|
38
|
+
transition={{ duration: 1 }}
|
|
39
|
+
>
|
|
40
|
+
<AntdForm.Item name={"234"} initialValue={"23432"} label="Antd Input">
|
|
41
|
+
<Input />
|
|
42
|
+
</AntdForm.Item>
|
|
43
|
+
</motion.div>
|
|
44
|
+
</AntdForm>
|
|
45
|
+
|
|
46
|
+
{/* Hidden Test */}
|
|
20
47
|
<Form
|
|
21
48
|
initialValues={{
|
|
22
49
|
TestData: "",
|
|
23
50
|
numericCode: "",
|
|
24
|
-
arr: [{ el: "Item 1" }, { el: "Item 2" }],
|
|
51
|
+
// arr: [{ el: "Item 1" }, { el: "Item 2" }],
|
|
25
52
|
}}
|
|
26
53
|
onFinish={(values) => {
|
|
27
54
|
console.log(values);
|
|
28
55
|
}}
|
|
29
56
|
formName={"form1"}
|
|
57
|
+
// hidden
|
|
30
58
|
>
|
|
31
59
|
<FormItem
|
|
32
60
|
name={"username"}
|
|
@@ -36,12 +64,15 @@ const App = () => {
|
|
|
36
64
|
message: "Test",
|
|
37
65
|
},
|
|
38
66
|
]}
|
|
67
|
+
initialValue={"283746"}
|
|
68
|
+
// hidden
|
|
39
69
|
>
|
|
40
70
|
<InputWrapper>
|
|
41
71
|
<Input />
|
|
42
72
|
</InputWrapper>
|
|
43
73
|
</FormItem>
|
|
44
74
|
|
|
75
|
+
{/* Numberic test */}
|
|
45
76
|
<FormItem
|
|
46
77
|
name={"numericCode"}
|
|
47
78
|
rules={[
|
|
@@ -56,10 +87,25 @@ const App = () => {
|
|
|
56
87
|
<Input placeholder="Mã chỉ gồm số" style={{ width: 200 }} />
|
|
57
88
|
</InputWrapper>
|
|
58
89
|
</FormItem>
|
|
90
|
+
|
|
91
|
+
{/* Motion Test */}
|
|
92
|
+
<motion.div
|
|
93
|
+
initial={{ opacity: 0 }}
|
|
94
|
+
animate={{ opacity: 1 }}
|
|
95
|
+
exit={{ opacity: 0 }}
|
|
96
|
+
transition={{ duration: 1 }}
|
|
97
|
+
>
|
|
98
|
+
<FormItem name="motionTest" controlAfterInit initialValue={"1234134"}>
|
|
99
|
+
<InputWrapper>
|
|
100
|
+
<Input placeholder="Motion Test" style={{ width: 200 }} />
|
|
101
|
+
</InputWrapper>
|
|
102
|
+
</FormItem>
|
|
103
|
+
</motion.div>
|
|
59
104
|
<FormList
|
|
60
105
|
initialValues={[
|
|
61
106
|
{
|
|
62
|
-
el: "",
|
|
107
|
+
el: "sdfsdf",
|
|
108
|
+
d: { child: "Test Child" },
|
|
63
109
|
},
|
|
64
110
|
]}
|
|
65
111
|
name="arr"
|
|
@@ -68,7 +114,15 @@ const App = () => {
|
|
|
68
114
|
<div>
|
|
69
115
|
{fields.map((field, index) => (
|
|
70
116
|
<div key={field.key} style={{ marginBottom: 8 }}>
|
|
71
|
-
<FormItem name={`${field.name}.el`}>
|
|
117
|
+
<FormItem name={`${field.name}.el`} initialValue={"Chém gió"}>
|
|
118
|
+
<InputWrapper>
|
|
119
|
+
<Input placeholder="Item value" style={{ width: 200 }} />
|
|
120
|
+
</InputWrapper>
|
|
121
|
+
</FormItem>
|
|
122
|
+
<FormItem
|
|
123
|
+
name={`${field.name}.d.child`}
|
|
124
|
+
initialValue={"Con của item"}
|
|
125
|
+
>
|
|
72
126
|
<InputWrapper>
|
|
73
127
|
<Input placeholder="Item value" style={{ width: 200 }} />
|
|
74
128
|
</InputWrapper>
|
|
@@ -101,12 +155,52 @@ const App = () => {
|
|
|
101
155
|
</div>
|
|
102
156
|
)}
|
|
103
157
|
</FormList>
|
|
158
|
+
<TestDialog />
|
|
159
|
+
<Button
|
|
160
|
+
onClick={() => {
|
|
161
|
+
form?.setFieldValue("arr", [
|
|
162
|
+
{ el: "Set Item 1" },
|
|
163
|
+
{ el: "Set Item 2" },
|
|
164
|
+
{ el: "Set Item 3" },
|
|
165
|
+
]);
|
|
166
|
+
}}
|
|
167
|
+
>
|
|
168
|
+
Test set array list value
|
|
169
|
+
</Button>
|
|
170
|
+
<motion.div
|
|
171
|
+
initial={{ opacity: 0 }}
|
|
172
|
+
animate={{ opacity: 1 }}
|
|
173
|
+
exit={{ opacity: 0 }}
|
|
174
|
+
transition={{ duration: 1.5 }}
|
|
175
|
+
>
|
|
176
|
+
<FormItem
|
|
177
|
+
valuePropName="checked"
|
|
178
|
+
getValueFromEvent={(_, checked) => checked}
|
|
179
|
+
name="checkControlledAfterInit"
|
|
180
|
+
controlAfterInit={true}
|
|
181
|
+
initialValue={true}
|
|
182
|
+
>
|
|
183
|
+
<Checkbox />
|
|
184
|
+
</FormItem>
|
|
185
|
+
</motion.div>
|
|
186
|
+
<TestFormWatch />
|
|
187
|
+
<Button
|
|
188
|
+
onClick={() => {
|
|
189
|
+
const current = form?.getFieldValue("checkControlledAfterInit");
|
|
190
|
+
console.log("Toggle controlled after init: ", current);
|
|
191
|
+
form?.setFieldValue("checkControlledAfterInit", !current);
|
|
192
|
+
}}
|
|
193
|
+
>
|
|
194
|
+
Toggle
|
|
195
|
+
</Button>
|
|
104
196
|
<Button htmlType="submit">Submit</Button>
|
|
105
197
|
<Button
|
|
106
198
|
onClick={() => {
|
|
107
199
|
form?.resetFields?.();
|
|
108
200
|
}}
|
|
109
|
-
|
|
201
|
+
>
|
|
202
|
+
Reset
|
|
203
|
+
</Button>
|
|
110
204
|
</Form>
|
|
111
205
|
</div>
|
|
112
206
|
);
|