react-form-manage 1.0.6-beta.0 → 1.0.6-beta.1
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 +44 -0
- package/dist/components/Form/FormCleanUp.js +46 -0
- package/dist/components/Form/FormItem.js +46 -0
- package/dist/components/Form/FormList.js +11 -0
- package/dist/components/Form/InputWrapper.js +7 -0
- package/dist/components/Input.d.ts +4 -5
- package/dist/components/Input.js +8 -0
- package/dist/constants/validation.js +33 -0
- package/dist/contexts/FormContext.js +2 -0
- package/dist/hooks/useFormItemControl.js +390 -0
- package/dist/hooks/useFormListControl.js +280 -0
- package/dist/index.d.ts +8 -185
- package/dist/index.js +9 -0
- package/dist/providers/Form.js +322 -0
- package/dist/stores/formStore.js +304 -0
- package/dist/types/index.d.ts +1 -0
- package/dist/types/index.js +1 -0
- package/dist/types/public.d.ts +51 -0
- package/dist/utils/obj.util.js +24 -0
- package/package.json +30 -45
- package/src/App.css +49 -0
- package/src/App.tsx +36 -0
- package/src/assets/react.svg +1 -0
- package/src/components/Form/FormCleanUp.tsx +57 -0
- package/src/components/Form/FormItem.tsx +60 -0
- package/src/components/Form/FormList.tsx +13 -0
- package/src/components/Form/InputWrapper.tsx +17 -0
- package/src/components/Input.jsx +13 -0
- package/src/components/Input.tsx +21 -0
- package/src/constants/validation.ts +63 -0
- package/src/contexts/FormContext.ts +3 -0
- package/src/hooks/useFormItemControl.ts +558 -0
- package/src/hooks/useFormListControl.ts +378 -0
- package/src/index.css +68 -0
- package/src/index.ts +30 -0
- package/src/main.tsx +10 -0
- package/src/providers/Form.tsx +429 -0
- package/src/stores/formStore.ts +477 -0
- package/src/types/index.ts +1 -0
- package/src/types/public.ts +50 -0
- package/src/utils/obj.util.ts +42 -0
- package/dist/App.d.ts +0 -2
- package/dist/index.cjs +0 -2
- package/dist/index.cjs.d.ts +0 -1
- package/dist/index.cjs.map +0 -1
- package/dist/index.esm.d.ts +0 -1
- package/dist/index.esm.js +0 -2
- package/dist/index.esm.js.map +0 -1
- package/src/types/components.d.ts +0 -135
- /package/dist/{main.d.ts → types/public.js} +0 -0
|
@@ -0,0 +1,322 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { cloneDeep, get, isEqual, last, set, uniq } from "lodash";
|
|
3
|
+
import { useTask } from "minh-custom-hooks-release";
|
|
4
|
+
import { createContext, useContext, useEffect, useState } from "react";
|
|
5
|
+
import { flushSync } from "react-dom";
|
|
6
|
+
import { useShallow } from "zustand/react/shallow"; // Import useShallow
|
|
7
|
+
import FormCleanUp from "../components/Form/FormCleanUp";
|
|
8
|
+
import { useFormListeners, useFormStore } from "../stores/formStore";
|
|
9
|
+
import { getAllNoneObjStringPath } from "../utils/obj.util";
|
|
10
|
+
export const FormContext = createContext(null);
|
|
11
|
+
export default function Form({ children, formName, initialValues, onFinish, onReject, onFinally, FormElement, ...props }) {
|
|
12
|
+
const { getFormItemValue, setInitData, setData, getFormValues, setFormState, setFormInstance, revokeFormInstance, setSubmitHistory, clearFormValues, clearFormInitialValues, clearFormState, } = useFormStore(useShallow((state) => ({
|
|
13
|
+
setInitData: state.setFormInitData,
|
|
14
|
+
getFormValues: state.getFormValues,
|
|
15
|
+
setFormState: state.setFormState,
|
|
16
|
+
setFormInstance: state.setFormInstance,
|
|
17
|
+
revokeFormInstance: state.revokeFormInstance,
|
|
18
|
+
setData: state.setData,
|
|
19
|
+
setSubmitHistory: state.setSubmitHistory,
|
|
20
|
+
getFormItemValue: state.getFormItemValue,
|
|
21
|
+
clearFormValues: state.clearFormValues,
|
|
22
|
+
clearFormInitialValues: state.clearFormInitialValues,
|
|
23
|
+
clearFormState: state.clearFormState,
|
|
24
|
+
// Test, nhớ xóa sau khi xong
|
|
25
|
+
formStates: state.formStates?.[formName],
|
|
26
|
+
})));
|
|
27
|
+
const { getListeners } = useFormListeners(useShallow((state) => {
|
|
28
|
+
return {
|
|
29
|
+
getListeners: state.getListeners,
|
|
30
|
+
};
|
|
31
|
+
}));
|
|
32
|
+
const setFieldValue = (name, value, options) => {
|
|
33
|
+
const listener = getListeners().find((l) => l.name === name && l.formName === formName);
|
|
34
|
+
if (listener) {
|
|
35
|
+
listener.onChange(value, options);
|
|
36
|
+
}
|
|
37
|
+
else {
|
|
38
|
+
setData(formName, name, value);
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
const setFieldValues = (values, options = { notTriggerDirty: false }) => {
|
|
42
|
+
const allStringPath = getAllNoneObjStringPath(values);
|
|
43
|
+
allStringPath.forEach((p) => {
|
|
44
|
+
const listener = getListeners().find((l) => l.name === p && l.formName === formName);
|
|
45
|
+
if (listener) {
|
|
46
|
+
listener.onChange(get(values, listener.name), options);
|
|
47
|
+
}
|
|
48
|
+
else {
|
|
49
|
+
setData(formName, p, get(values, p));
|
|
50
|
+
}
|
|
51
|
+
});
|
|
52
|
+
};
|
|
53
|
+
const getFieldValue = (name) => {
|
|
54
|
+
return getFormItemValue(formName, name);
|
|
55
|
+
};
|
|
56
|
+
const getFieldValues = (names = []) => {
|
|
57
|
+
return names.map((name) => ({
|
|
58
|
+
name,
|
|
59
|
+
value: getFormItemValue(formName, name),
|
|
60
|
+
}));
|
|
61
|
+
};
|
|
62
|
+
const setFieldFocus = (name) => {
|
|
63
|
+
const listener = getListeners().find((l) => l.name === name && l.formName === formName);
|
|
64
|
+
if (listener && typeof listener.emitFocus === "function") {
|
|
65
|
+
listener.emitFocus();
|
|
66
|
+
}
|
|
67
|
+
};
|
|
68
|
+
const getFieldErrors = (names) => {
|
|
69
|
+
const listeners = getListeners().filter((l) => names.includes(l.name) && l.formName === formName);
|
|
70
|
+
return listeners.map((l) => ({
|
|
71
|
+
name: l.name,
|
|
72
|
+
errors: l.internalErrors || [],
|
|
73
|
+
}));
|
|
74
|
+
};
|
|
75
|
+
const getAllFieldErrors = () => {
|
|
76
|
+
return getListeners()
|
|
77
|
+
?.filter((l) => {
|
|
78
|
+
return l.internalErrors?.length && l.formName === formName;
|
|
79
|
+
})
|
|
80
|
+
.map((l) => ({
|
|
81
|
+
name: l.name,
|
|
82
|
+
formName: l.formName,
|
|
83
|
+
formItemId: l.formItemId,
|
|
84
|
+
errors: l.internalErrors,
|
|
85
|
+
}));
|
|
86
|
+
};
|
|
87
|
+
// Submit data
|
|
88
|
+
const { run: runSubmit, runAsync: runSubmitAsync, state: _, reset, } = useTask({
|
|
89
|
+
async task(props) {
|
|
90
|
+
try {
|
|
91
|
+
flushSync(setFormState({ formName, submitState: "submitting" }));
|
|
92
|
+
const errorFields = getAllFieldErrors();
|
|
93
|
+
const listeners = getListeners().filter((l) => l.formName === formName);
|
|
94
|
+
const formValues = getFormValues(formName);
|
|
95
|
+
const resultValues = cloneDeep(formValues);
|
|
96
|
+
const cleanValues = {};
|
|
97
|
+
uniq(listeners, (l) => l.name).forEach((l) => {
|
|
98
|
+
set(cleanValues, l.name, get(resultValues, l.name));
|
|
99
|
+
});
|
|
100
|
+
const handleIsolateCase = async () => {
|
|
101
|
+
if (!errorFields?.length) {
|
|
102
|
+
if (typeof props?.externalFinishCallback !== "function") {
|
|
103
|
+
onFinish && (await onFinish(cleanValues, resultValues));
|
|
104
|
+
}
|
|
105
|
+
else {
|
|
106
|
+
if (props?.callBothFinish) {
|
|
107
|
+
onFinish && (await onFinish(cleanValues, resultValues));
|
|
108
|
+
await props?.externalFinishCallback(cleanValues, resultValues);
|
|
109
|
+
}
|
|
110
|
+
else {
|
|
111
|
+
await props?.externalFinishCallback(cleanValues, resultValues);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
// if (!isEqual(cleanValues, last(getSubmitHistory(formName)))) {
|
|
115
|
+
// setSubmitHistory(formName, cleanValues);
|
|
116
|
+
// }
|
|
117
|
+
setSubmitHistory(formName, cleanValues);
|
|
118
|
+
// if (
|
|
119
|
+
// !isEqual(
|
|
120
|
+
// resultValues,
|
|
121
|
+
// last(submitHistoryWithUnRegisteredValues.current)
|
|
122
|
+
// )
|
|
123
|
+
// ) {
|
|
124
|
+
// submitHistoryWithUnRegisteredValues.current = [
|
|
125
|
+
// ...submitHistoryWithUnRegisteredValues.current,
|
|
126
|
+
// resultValues,
|
|
127
|
+
// ].slice(-10, 10);
|
|
128
|
+
// }
|
|
129
|
+
// resultWatchQueue.current.forEach((l) => {
|
|
130
|
+
// l.emitSubmitTrigger(cleanValues);
|
|
131
|
+
// l.emitDataChange(cleanValues);
|
|
132
|
+
// l.emitDataWithUnRegisteredValuesChange(resultValues);
|
|
133
|
+
// l.emitSubmitTriggerWithUnRegisteredValues(resultValues);
|
|
134
|
+
// });
|
|
135
|
+
}
|
|
136
|
+
else {
|
|
137
|
+
if (typeof props?.externalRejectCallback !== "function") {
|
|
138
|
+
onReject && (await onReject(errorFields));
|
|
139
|
+
}
|
|
140
|
+
else {
|
|
141
|
+
if (props?.callBothReject) {
|
|
142
|
+
onReject && (await onReject(errorFields));
|
|
143
|
+
await props?.externalRejectCallback(errorFields);
|
|
144
|
+
}
|
|
145
|
+
else {
|
|
146
|
+
await props?.externalRejectCallback(errorFields);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
};
|
|
151
|
+
const handleFinallyCase = async () => {
|
|
152
|
+
if (typeof props?.externalFinallyCallback !== "function") {
|
|
153
|
+
onFinally &&
|
|
154
|
+
(await onFinally({
|
|
155
|
+
errorsField: errorFields,
|
|
156
|
+
values: cleanValues,
|
|
157
|
+
withUnRegisteredValues: resultValues,
|
|
158
|
+
}));
|
|
159
|
+
}
|
|
160
|
+
else {
|
|
161
|
+
if (props?.callBothFinally) {
|
|
162
|
+
onFinally &&
|
|
163
|
+
(await onFinally({
|
|
164
|
+
errorsField: errorFields,
|
|
165
|
+
values: cleanValues,
|
|
166
|
+
withUnRegisteredValues: resultValues,
|
|
167
|
+
}));
|
|
168
|
+
await props?.externalFinallyCallback({
|
|
169
|
+
errorsField: errorFields,
|
|
170
|
+
values: cleanValues,
|
|
171
|
+
withUnRegisteredValues: resultValues,
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
else {
|
|
175
|
+
await props?.externalFinallyCallback({
|
|
176
|
+
errorsField: errorFields,
|
|
177
|
+
values: cleanValues,
|
|
178
|
+
withUnRegisteredValues: resultValues,
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
};
|
|
183
|
+
await Promise.allSettled([handleIsolateCase(), handleFinallyCase()]);
|
|
184
|
+
if (errorFields?.length) {
|
|
185
|
+
setFormState({ formName, submitState: "rejected" });
|
|
186
|
+
}
|
|
187
|
+
else {
|
|
188
|
+
setFormState({ formName, submitState: "submitted" });
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
catch (error) {
|
|
192
|
+
console.error("Error in form submit: ", error);
|
|
193
|
+
setFormState({ formName, submitState: "rejected" });
|
|
194
|
+
}
|
|
195
|
+
},
|
|
196
|
+
});
|
|
197
|
+
const resetFields = (resetOptions) => {
|
|
198
|
+
reset();
|
|
199
|
+
flushSync(setFormState({
|
|
200
|
+
formName,
|
|
201
|
+
isInitied: false,
|
|
202
|
+
}));
|
|
203
|
+
const totalListenerFields = getListeners();
|
|
204
|
+
if (Array.isArray(resetOptions)) {
|
|
205
|
+
totalListenerFields.forEach((l) => {
|
|
206
|
+
const findListenerByName = resetOptions.find((o) => o.name === l.name);
|
|
207
|
+
if (findListenerByName) {
|
|
208
|
+
l.onReset(findListenerByName?.value);
|
|
209
|
+
}
|
|
210
|
+
});
|
|
211
|
+
totalListenerFields
|
|
212
|
+
.filter((l) => resetOptions.find((o) => o.name !== l.name))
|
|
213
|
+
.forEach((l) => {
|
|
214
|
+
l?.onReset?.();
|
|
215
|
+
});
|
|
216
|
+
}
|
|
217
|
+
else if (typeof resetOptions === "object") {
|
|
218
|
+
const allStringPath = getAllNoneObjStringPath(resetOptions);
|
|
219
|
+
allStringPath.forEach((p) => {
|
|
220
|
+
const listener = totalListenerFields.find((l) => l.name === p && l.formName === formName);
|
|
221
|
+
if (listener) {
|
|
222
|
+
listener.onChange(get(resetOptions, listener.name));
|
|
223
|
+
}
|
|
224
|
+
else {
|
|
225
|
+
setData(formName, p, get(resetOptions, p));
|
|
226
|
+
}
|
|
227
|
+
});
|
|
228
|
+
}
|
|
229
|
+
else {
|
|
230
|
+
totalListenerFields.forEach((l) => {
|
|
231
|
+
l?.onReset?.();
|
|
232
|
+
});
|
|
233
|
+
}
|
|
234
|
+
setFormState({
|
|
235
|
+
formName,
|
|
236
|
+
isInitied: true,
|
|
237
|
+
});
|
|
238
|
+
};
|
|
239
|
+
useEffect(() => {
|
|
240
|
+
setInitData(formName, initialValues);
|
|
241
|
+
setFormState({
|
|
242
|
+
formName,
|
|
243
|
+
isInitied: true,
|
|
244
|
+
submitState: "idle",
|
|
245
|
+
});
|
|
246
|
+
setFormInstance({
|
|
247
|
+
formName,
|
|
248
|
+
resetFields,
|
|
249
|
+
submit: runSubmit,
|
|
250
|
+
submitAsync: runSubmitAsync,
|
|
251
|
+
setFieldValue,
|
|
252
|
+
setFieldValues,
|
|
253
|
+
getFieldValue,
|
|
254
|
+
getFieldValues,
|
|
255
|
+
setFieldFocus,
|
|
256
|
+
getFieldErrors,
|
|
257
|
+
});
|
|
258
|
+
return () => {
|
|
259
|
+
revokeFormInstance({ formName });
|
|
260
|
+
clearFormInitialValues(formName);
|
|
261
|
+
clearFormValues(formName);
|
|
262
|
+
clearFormState(formName);
|
|
263
|
+
};
|
|
264
|
+
}, []);
|
|
265
|
+
return (_jsxs(FormContext.Provider, { value: {
|
|
266
|
+
formName,
|
|
267
|
+
}, children: [FormElement ? (_jsx(FormElement, { onSubmit: (e) => {
|
|
268
|
+
e.preventDefault();
|
|
269
|
+
e.stopPropagation();
|
|
270
|
+
runSubmit(undefined);
|
|
271
|
+
}, ...props, children: children })) : (_jsx("form", { onSubmit: (e) => {
|
|
272
|
+
e.preventDefault();
|
|
273
|
+
e.stopPropagation();
|
|
274
|
+
runSubmit(undefined);
|
|
275
|
+
}, ...props, children: children })), _jsx(FormCleanUp, {})] }));
|
|
276
|
+
}
|
|
277
|
+
export function useFormContext() {
|
|
278
|
+
const c = useContext(FormContext);
|
|
279
|
+
if (!c)
|
|
280
|
+
throw new Error("Must be use inside FormProvider");
|
|
281
|
+
return c;
|
|
282
|
+
}
|
|
283
|
+
export function useForm(formNameOrFormInstance) {
|
|
284
|
+
const targetFormName = typeof formNameOrFormInstance === "object" && formNameOrFormInstance !== null
|
|
285
|
+
? formNameOrFormInstance.formName
|
|
286
|
+
: formNameOrFormInstance;
|
|
287
|
+
const formInstance = useFormStore((state) => {
|
|
288
|
+
return state.formInstances.find((i) => i.formName === targetFormName);
|
|
289
|
+
});
|
|
290
|
+
return [formInstance];
|
|
291
|
+
}
|
|
292
|
+
export function useWatch(name, formNameOrFormInstance) {
|
|
293
|
+
const [formInstance] = useForm(formNameOrFormInstance);
|
|
294
|
+
const value = useFormStore((state) => {
|
|
295
|
+
return state.getFormItemValue(formInstance?.formName ?? formNameOrFormInstance, name);
|
|
296
|
+
});
|
|
297
|
+
return value;
|
|
298
|
+
}
|
|
299
|
+
export function useSubmitDataWatch({ formNameOrFormInstance, triggerWhenChange = false, mapFn, }) {
|
|
300
|
+
const [formInstance] = useForm(formNameOrFormInstance);
|
|
301
|
+
const value = useFormStore((state) => {
|
|
302
|
+
return last(get(state.submitHistory, formInstance?.formName));
|
|
303
|
+
});
|
|
304
|
+
const [submitData, setSubmitData] = useState(mapFn ? mapFn(value, null) : value);
|
|
305
|
+
useEffect(() => {
|
|
306
|
+
if (!triggerWhenChange || !isEqual(submitData, value)) {
|
|
307
|
+
setSubmitData(mapFn ? mapFn(value, submitData) : value);
|
|
308
|
+
}
|
|
309
|
+
}, [value, triggerWhenChange]);
|
|
310
|
+
return submitData;
|
|
311
|
+
}
|
|
312
|
+
export const useFormStateWatch = (formNameOrFormInstance) => {
|
|
313
|
+
const [formInstance] = useForm(formNameOrFormInstance);
|
|
314
|
+
const formState = useFormStore((state) => {
|
|
315
|
+
return state.formStates?.[formInstance?.formName];
|
|
316
|
+
});
|
|
317
|
+
return formState;
|
|
318
|
+
};
|
|
319
|
+
Form.useForm = useForm;
|
|
320
|
+
Form.useWatch = useWatch;
|
|
321
|
+
Form.useSubmitDataWatch = useSubmitDataWatch;
|
|
322
|
+
Form.useFormStateWatch = useFormStateWatch;
|
|
@@ -0,0 +1,304 @@
|
|
|
1
|
+
import { produce } from "immer";
|
|
2
|
+
import { cloneDeep, get, isNil, isNumber, last, set, unset } from "lodash";
|
|
3
|
+
import { v4 } from "uuid";
|
|
4
|
+
import { create } from "zustand";
|
|
5
|
+
import { getAllNoneObjStringPath } from "../utils/obj.util";
|
|
6
|
+
export const useFormStore = create((storeSet, storeGet) => ({
|
|
7
|
+
forms: {},
|
|
8
|
+
initialValues: {},
|
|
9
|
+
formStates: {},
|
|
10
|
+
cacheData: {},
|
|
11
|
+
formInstances: [],
|
|
12
|
+
submitHistory: {},
|
|
13
|
+
setData(formName, name, value) {
|
|
14
|
+
return storeSet(produce((state) => {
|
|
15
|
+
const oldValues = state.forms;
|
|
16
|
+
set(oldValues, `${formName}.${name}`, value);
|
|
17
|
+
}));
|
|
18
|
+
},
|
|
19
|
+
getCacheData(formName) {
|
|
20
|
+
return get(storeGet(), `cacheData.${formName}`);
|
|
21
|
+
},
|
|
22
|
+
setCacheData(formName, name, value) {
|
|
23
|
+
return storeSet(produce((state) => {
|
|
24
|
+
const oldValues = state.cacheData;
|
|
25
|
+
set(oldValues, `${formName}.${name}`, value);
|
|
26
|
+
}));
|
|
27
|
+
},
|
|
28
|
+
clearCacheData(formName) {
|
|
29
|
+
return storeSet(produce((state) => {
|
|
30
|
+
const oldValues = state.cacheData;
|
|
31
|
+
if (formName) {
|
|
32
|
+
set(oldValues, formName, {});
|
|
33
|
+
}
|
|
34
|
+
else {
|
|
35
|
+
set(oldValues, "", {});
|
|
36
|
+
}
|
|
37
|
+
}));
|
|
38
|
+
},
|
|
39
|
+
getFormItemValue(formName, name) {
|
|
40
|
+
return get(storeGet().forms?.[formName], name);
|
|
41
|
+
},
|
|
42
|
+
getFormValues(formName) {
|
|
43
|
+
return storeGet().forms?.[formName];
|
|
44
|
+
},
|
|
45
|
+
clearFormValues(formName) {
|
|
46
|
+
return storeSet(produce((state) => {
|
|
47
|
+
const oldValues = state.forms;
|
|
48
|
+
// console.log("Clear form values", formName);
|
|
49
|
+
unset(oldValues, formName);
|
|
50
|
+
// console.log(JSON.parse(JSON.stringify(oldValues)));
|
|
51
|
+
}));
|
|
52
|
+
},
|
|
53
|
+
clearFormInitialValues(formName) {
|
|
54
|
+
return storeSet(produce((state) => {
|
|
55
|
+
const oldValues = state.initialValues;
|
|
56
|
+
// console.log("Clear form initial values", formName);
|
|
57
|
+
unset(oldValues, formName);
|
|
58
|
+
// console.log(JSON.parse(JSON.stringify(oldValues)));
|
|
59
|
+
}));
|
|
60
|
+
},
|
|
61
|
+
clearObjKeyItem(formName, name) {
|
|
62
|
+
return storeSet(produce((state) => {
|
|
63
|
+
const oldValues = state.forms;
|
|
64
|
+
// console.log("Clear item value", formName, name);
|
|
65
|
+
unset(oldValues, `${formName}.${name}`);
|
|
66
|
+
// console.log(JSON.parse(JSON.stringify(oldValues)));
|
|
67
|
+
}));
|
|
68
|
+
},
|
|
69
|
+
clearArrItem(formName, name) {
|
|
70
|
+
return storeSet(produce((state) => {
|
|
71
|
+
const oldValues = state.forms;
|
|
72
|
+
console.log("Clear item array value", formName, name);
|
|
73
|
+
const arrPath = name.split(".").slice(0, -1).join(".");
|
|
74
|
+
const elPath = Number(name.split(".").slice(-1).join(""));
|
|
75
|
+
const getArrItem = get(oldValues, `${formName}.${arrPath}`);
|
|
76
|
+
if (isNumber(elPath)) {
|
|
77
|
+
getArrItem.splice(elPath, 1);
|
|
78
|
+
}
|
|
79
|
+
// console.log(JSON.parse(JSON.stringify(oldValues)));
|
|
80
|
+
}));
|
|
81
|
+
},
|
|
82
|
+
setFormState({ formName, isInitied, submitState }) {
|
|
83
|
+
return storeSet(produce((state) => {
|
|
84
|
+
const oldValues = state.formStates;
|
|
85
|
+
const getFormState = get(storeGet().formStates, formName);
|
|
86
|
+
if (isNil(getFormState)) {
|
|
87
|
+
set(oldValues, formName, { isInitied, submitState });
|
|
88
|
+
}
|
|
89
|
+
else {
|
|
90
|
+
if (!isNil(isInitied)) {
|
|
91
|
+
set(oldValues, `${formName}.isInitied`, isInitied);
|
|
92
|
+
}
|
|
93
|
+
if (!isNil(submitState)) {
|
|
94
|
+
set(oldValues, `${formName}.submitState`, submitState);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}));
|
|
98
|
+
},
|
|
99
|
+
clearFormState(formName) {
|
|
100
|
+
return storeSet(produce((state) => {
|
|
101
|
+
const oldValues = state.formStates;
|
|
102
|
+
// console.log("Clear form state", formName);
|
|
103
|
+
unset(oldValues, formName);
|
|
104
|
+
// console.log(JSON.parse(JSON.stringify(oldValues)));
|
|
105
|
+
}));
|
|
106
|
+
},
|
|
107
|
+
getFormState(formName) {
|
|
108
|
+
return get(storeGet(), `formStates.${formName}`);
|
|
109
|
+
},
|
|
110
|
+
setFormInitData(formName, initValues) {
|
|
111
|
+
return storeSet(produce((state) => {
|
|
112
|
+
const oldValues = state.initialValues;
|
|
113
|
+
const listInitPath = getAllNoneObjStringPath(initValues);
|
|
114
|
+
// console.log({ listInitPath, initValues });
|
|
115
|
+
listInitPath.forEach((k) => {
|
|
116
|
+
if (get(initValues, k)) {
|
|
117
|
+
// console.log("init form data values: ", k, get(initValues, k));
|
|
118
|
+
set(oldValues, `${formName}.${k}`, get(initValues, k));
|
|
119
|
+
}
|
|
120
|
+
});
|
|
121
|
+
}));
|
|
122
|
+
},
|
|
123
|
+
getInitData(formName, name) {
|
|
124
|
+
return get(storeGet().initialValues, `${formName}.${name}`);
|
|
125
|
+
},
|
|
126
|
+
setInitData(formName, name, value) {
|
|
127
|
+
return storeSet(produce((state) => {
|
|
128
|
+
const oldValues = state.initialValues;
|
|
129
|
+
// console.log("Inner init: ", `${formName}.${name}`, value);
|
|
130
|
+
set(oldValues, `${formName}.${name}`, value);
|
|
131
|
+
}));
|
|
132
|
+
},
|
|
133
|
+
setFormInstance({ formName, resetFields, submit, submitAsync, setFieldValue, setFieldValues, getFieldValue, getFieldValues, getFieldErrors, setFieldFocus, }) {
|
|
134
|
+
return storeSet(produce((state) => {
|
|
135
|
+
const storeListeners = state.formInstances;
|
|
136
|
+
const findListenerIndex = storeListeners.findIndex((l) => l.formName === formName);
|
|
137
|
+
if (findListenerIndex > -1) {
|
|
138
|
+
if (!isNil(resetFields)) {
|
|
139
|
+
storeListeners[findListenerIndex].resetFields = resetFields;
|
|
140
|
+
}
|
|
141
|
+
if (!isNil(submit)) {
|
|
142
|
+
storeListeners[findListenerIndex].submit = submit;
|
|
143
|
+
}
|
|
144
|
+
if (!isNil(setFieldFocus)) {
|
|
145
|
+
storeListeners[findListenerIndex].setFieldFocus = setFieldFocus;
|
|
146
|
+
}
|
|
147
|
+
if (!isNil(submitAsync)) {
|
|
148
|
+
storeListeners[findListenerIndex].submitAsync = submitAsync;
|
|
149
|
+
}
|
|
150
|
+
if (!isNil(setFieldValue)) {
|
|
151
|
+
storeListeners[findListenerIndex].setFieldValue = setFieldValue;
|
|
152
|
+
}
|
|
153
|
+
if (!isNil(setFieldValues)) {
|
|
154
|
+
storeListeners[findListenerIndex].setFieldValues = setFieldValues;
|
|
155
|
+
}
|
|
156
|
+
if (!isNil(getFieldValue)) {
|
|
157
|
+
storeListeners[findListenerIndex].getFieldValue = getFieldValue;
|
|
158
|
+
}
|
|
159
|
+
if (!isNil(getFieldValues)) {
|
|
160
|
+
storeListeners[findListenerIndex].getFieldValues = getFieldValues;
|
|
161
|
+
}
|
|
162
|
+
if (!isNil(getFieldErrors)) {
|
|
163
|
+
storeListeners[findListenerIndex].getFieldErrors = getFieldErrors;
|
|
164
|
+
}
|
|
165
|
+
return;
|
|
166
|
+
}
|
|
167
|
+
storeListeners.push({
|
|
168
|
+
formName,
|
|
169
|
+
resetFields,
|
|
170
|
+
submit,
|
|
171
|
+
submitAsync,
|
|
172
|
+
setFieldValue,
|
|
173
|
+
setFieldValues,
|
|
174
|
+
getFieldValue,
|
|
175
|
+
getFieldValues,
|
|
176
|
+
getFieldErrors,
|
|
177
|
+
setFieldFocus,
|
|
178
|
+
});
|
|
179
|
+
}));
|
|
180
|
+
},
|
|
181
|
+
revokeFormInstance({ formName }) {
|
|
182
|
+
return storeSet(produce((state) => {
|
|
183
|
+
const instances = state.formInstances;
|
|
184
|
+
const findInstanceIndex = instances.findIndex((l) => l.formName == formName);
|
|
185
|
+
// console.log("Find item for revoke: ", findListenerIndex, formItemId);
|
|
186
|
+
if (findInstanceIndex > -1) {
|
|
187
|
+
// const listenersInfo = cloneDeep(instances[findInstanceIndex]);
|
|
188
|
+
instances.splice(findInstanceIndex, 1);
|
|
189
|
+
// onAfterRevoke(
|
|
190
|
+
// listenersInfo,
|
|
191
|
+
// instances.filter(
|
|
192
|
+
// (l) =>
|
|
193
|
+
// l.name === listenersInfo.name &&
|
|
194
|
+
// l.formName === listenersInfo.formName &&
|
|
195
|
+
// l.formItemId !== listenersInfo.formItemId
|
|
196
|
+
// )
|
|
197
|
+
// );
|
|
198
|
+
}
|
|
199
|
+
}));
|
|
200
|
+
},
|
|
201
|
+
getCurrentSubmit(formName) {
|
|
202
|
+
return last(get(storeGet().submitHistory, formName)) || null;
|
|
203
|
+
},
|
|
204
|
+
getSubmitHistory(formName) {
|
|
205
|
+
return get(storeGet().submitHistory, formName);
|
|
206
|
+
},
|
|
207
|
+
setSubmitHistory(formName, submitData) {
|
|
208
|
+
return storeSet(produce((state) => {
|
|
209
|
+
const oldValues = get(state.submitHistory, formName);
|
|
210
|
+
if (oldValues) {
|
|
211
|
+
oldValues.push(submitData);
|
|
212
|
+
oldValues.splice(0, oldValues.length - 3);
|
|
213
|
+
}
|
|
214
|
+
else {
|
|
215
|
+
set(state.submitHistory, formName, [submitData]);
|
|
216
|
+
}
|
|
217
|
+
console.log("Submit history: ", formName);
|
|
218
|
+
}));
|
|
219
|
+
},
|
|
220
|
+
}));
|
|
221
|
+
export const useFormListeners = create((storeSet, storeGet) => ({
|
|
222
|
+
listeners: [],
|
|
223
|
+
getListener(formItemId) {
|
|
224
|
+
return storeGet().listeners.find((l) => l.formItemId === formItemId);
|
|
225
|
+
},
|
|
226
|
+
getListeners() {
|
|
227
|
+
return storeGet().listeners;
|
|
228
|
+
},
|
|
229
|
+
setListener({ formName, name, onChange, onReset, isTouched, isDirty, formItemId, internalErrors, onFocus, emitFocus, }) {
|
|
230
|
+
return storeSet(produce((state) => {
|
|
231
|
+
const storeListeners = state.listeners;
|
|
232
|
+
const findListenerIndex = state.listeners.findIndex((l) => l.formItemId === formItemId);
|
|
233
|
+
if (findListenerIndex > -1) {
|
|
234
|
+
if (!isNil(formName)) {
|
|
235
|
+
storeListeners[findListenerIndex].formName = formName;
|
|
236
|
+
}
|
|
237
|
+
if (!isNil(name)) {
|
|
238
|
+
storeListeners[findListenerIndex].name = name;
|
|
239
|
+
}
|
|
240
|
+
if (!isNil(onChange)) {
|
|
241
|
+
storeListeners[findListenerIndex].onChange = onChange;
|
|
242
|
+
}
|
|
243
|
+
if (!isNil(onReset)) {
|
|
244
|
+
storeListeners[findListenerIndex].onReset = onReset;
|
|
245
|
+
}
|
|
246
|
+
if (!isNil(isTouched)) {
|
|
247
|
+
storeListeners[findListenerIndex].isTouched = isTouched;
|
|
248
|
+
}
|
|
249
|
+
if (!isNil(isDirty)) {
|
|
250
|
+
storeListeners[findListenerIndex].isDirty = isDirty;
|
|
251
|
+
}
|
|
252
|
+
if (!isNil(internalErrors)) {
|
|
253
|
+
storeListeners[findListenerIndex].internalErrors = internalErrors;
|
|
254
|
+
}
|
|
255
|
+
if (!isNil(onFocus)) {
|
|
256
|
+
storeListeners[findListenerIndex].onFocus = onFocus;
|
|
257
|
+
}
|
|
258
|
+
if (!isNil(emitFocus)) {
|
|
259
|
+
storeListeners[findListenerIndex].emitFocus = emitFocus;
|
|
260
|
+
}
|
|
261
|
+
return;
|
|
262
|
+
}
|
|
263
|
+
storeListeners.push({
|
|
264
|
+
name,
|
|
265
|
+
formName,
|
|
266
|
+
isTouched,
|
|
267
|
+
isDirty,
|
|
268
|
+
formItemId,
|
|
269
|
+
internalErrors,
|
|
270
|
+
onChange,
|
|
271
|
+
onReset,
|
|
272
|
+
});
|
|
273
|
+
}));
|
|
274
|
+
},
|
|
275
|
+
revokeListener(formItemId, onAfterRevoke) {
|
|
276
|
+
return storeSet(produce((state) => {
|
|
277
|
+
const storeListeners = state.listeners;
|
|
278
|
+
const findListenerIndex = storeListeners.findIndex((l) => l.formItemId == formItemId);
|
|
279
|
+
// console.log("Find item for revoke: ", findListenerIndex, formItemId);
|
|
280
|
+
if (findListenerIndex > -1) {
|
|
281
|
+
const listenersInfo = cloneDeep(storeListeners[findListenerIndex]);
|
|
282
|
+
storeListeners.splice(findListenerIndex, 1);
|
|
283
|
+
onAfterRevoke(listenersInfo, storeListeners.filter((l) => l.name === listenersInfo.name &&
|
|
284
|
+
l.formName === listenersInfo.formName &&
|
|
285
|
+
l.formItemId !== listenersInfo.formItemId));
|
|
286
|
+
}
|
|
287
|
+
}));
|
|
288
|
+
},
|
|
289
|
+
}));
|
|
290
|
+
export const useFormCleanUp = create((storeSet) => ({
|
|
291
|
+
cleanUpStack: [],
|
|
292
|
+
setCleanUpStack({ name, type, itemKey, formName }) {
|
|
293
|
+
return storeSet(produce((state) => {
|
|
294
|
+
const oldValues = state.cleanUpStack;
|
|
295
|
+
const cleanUpKey = v4();
|
|
296
|
+
oldValues.push({ name, type, key: cleanUpKey, itemKey, formName });
|
|
297
|
+
}));
|
|
298
|
+
},
|
|
299
|
+
clearCleanUpStack() {
|
|
300
|
+
return storeSet(produce((state) => {
|
|
301
|
+
state.cleanUpStack = [];
|
|
302
|
+
}));
|
|
303
|
+
},
|
|
304
|
+
}));
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './public';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './public';
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
export type FormValues<T = any> = T;
|
|
2
|
+
export interface PublicFormInstance<T = any> {
|
|
3
|
+
formName: string;
|
|
4
|
+
resetFields?: (values?: Partial<T>) => void;
|
|
5
|
+
submit?: (values?: T) => void;
|
|
6
|
+
submitAsync?: (values?: T) => Promise<any>;
|
|
7
|
+
setFieldValue?: (name: keyof T & string, value: any) => void;
|
|
8
|
+
setFieldValues?: (values: Partial<T>) => void;
|
|
9
|
+
getFieldValue?: (name: keyof T & string) => any;
|
|
10
|
+
getFieldValues?: () => T;
|
|
11
|
+
getFieldErrors?: () => Record<string, any>;
|
|
12
|
+
}
|
|
13
|
+
export interface UseFormItemProps<T = any> {
|
|
14
|
+
formName?: string;
|
|
15
|
+
form?: PublicFormInstance<T>;
|
|
16
|
+
name?: keyof T & string;
|
|
17
|
+
initialValue?: any;
|
|
18
|
+
formItemId?: string;
|
|
19
|
+
rules?: any[];
|
|
20
|
+
}
|
|
21
|
+
export interface UseFormItemReturn<T = any> {
|
|
22
|
+
value: T | undefined;
|
|
23
|
+
onChange: (value: T, options?: any) => void;
|
|
24
|
+
state: any;
|
|
25
|
+
errors: any;
|
|
26
|
+
onFocus: () => void;
|
|
27
|
+
isDirty?: boolean;
|
|
28
|
+
}
|
|
29
|
+
export interface UseFormListProps<T = any> {
|
|
30
|
+
name?: string;
|
|
31
|
+
form?: PublicFormInstance<T>;
|
|
32
|
+
initialValues?: T[];
|
|
33
|
+
formName?: string;
|
|
34
|
+
}
|
|
35
|
+
export interface ListField {
|
|
36
|
+
name: string;
|
|
37
|
+
key: string;
|
|
38
|
+
}
|
|
39
|
+
export interface UseFormListReturn {
|
|
40
|
+
listFields: ListField[];
|
|
41
|
+
move: (opts: {
|
|
42
|
+
from?: number;
|
|
43
|
+
fromKey?: string;
|
|
44
|
+
to: number;
|
|
45
|
+
}) => void;
|
|
46
|
+
add: (index: number) => void;
|
|
47
|
+
remove: (opts: {
|
|
48
|
+
index?: number;
|
|
49
|
+
key?: string;
|
|
50
|
+
}) => void;
|
|
51
|
+
}
|