react-form-manage 1.0.8-beta.6 → 1.0.8-beta.7
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 +7 -3
- package/dist/components/Form/FormItem.d.ts +3 -1
- package/dist/components/Form/FormItem.js +6 -5
- package/dist/hooks/useFormItemControl.d.ts +1 -0
- package/dist/hooks/useFormItemControl.js +19 -4
- package/dist/providers/Form.d.ts +1 -1
- package/dist/providers/Form.js +3 -1
- package/dist/stores/formStore.js +8 -4
- package/package.json +2 -1
- package/src/App.tsx +59 -1
- package/src/components/Form/FormItem.tsx +56 -31
- package/src/components/Form/InputWrapper.tsx +5 -0
- package/src/hooks/useFormItemControl.ts +26 -3
- package/src/providers/Form.tsx +7 -2
- package/src/stores/formStore.ts +8 -2
package/CHANGELOG.md
CHANGED
|
@@ -4,10 +4,14 @@ All notable changes to this project will be documented in this file.
|
|
|
4
4
|
|
|
5
5
|
## [1.0.8-beta.3] - 2026-01-22
|
|
6
6
|
|
|
7
|
-
-
|
|
8
|
-
-
|
|
7
|
+
## [1.0.8-beta.7] - 2026-01-24
|
|
8
|
+
- Add control flag for FormItem to support rendering MUI uncontrolled components when initial value is undefined (control on init).
|
|
9
|
+
- Fix: `onReset` did not restore listener state to init.
|
|
10
|
+
- Fix: reset did not return Form submit state to `idle`.
|
|
11
|
+
- Add `hidden` prop to allow hiding components while still assigning a value.
|
|
9
12
|
|
|
10
|
-
|
|
13
|
+
Docs: Update usage notes for `FormItem` control-on-init flag and `hidden` prop.
|
|
14
|
+
- Add `UseFormItemStateWatchReturn` type export for `useFormItemStateWatch` hook
|
|
11
15
|
|
|
12
16
|
- Add isTouched field to FormItem for tracking user interaction state
|
|
13
17
|
|
|
@@ -9,5 +9,7 @@ export interface FormItemProps {
|
|
|
9
9
|
rules?: ValidationRule[];
|
|
10
10
|
valuePropName?: string;
|
|
11
11
|
getValueFromEvent?: (...args: any[]) => any;
|
|
12
|
+
controlAfterInit?: boolean;
|
|
13
|
+
hidden?: boolean;
|
|
12
14
|
}
|
|
13
|
-
export default function FormItem({ children, name, formName, initialValue, formItemId: externalFormItemId, rules, valuePropName, getValueFromEvent, }: FormItemProps):
|
|
15
|
+
export default function FormItem({ children, name, formName, initialValue, formItemId: externalFormItemId, rules, valuePropName, getValueFromEvent, controlAfterInit, hidden, }: FormItemProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { cloneElement, Fragment, useRef, useState } from "react";
|
|
2
3
|
import { v4 } from "uuid";
|
|
3
4
|
import useFormItemControl from "../../hooks/useFormItemControl";
|
|
4
|
-
function FormItem({ children, name, formName, initialValue, formItemId: externalFormItemId, rules, valuePropName = "value", getValueFromEvent }) {
|
|
5
|
+
function FormItem({ children, name, formName, initialValue, formItemId: externalFormItemId, rules, valuePropName = "value", getValueFromEvent, controlAfterInit = false, hidden }) {
|
|
5
6
|
const elRef = useRef(null);
|
|
6
7
|
const [formItemId] = useState(externalFormItemId != null ? externalFormItemId : v4());
|
|
7
|
-
const { value, onChange, errors, state, onFocus, isDirty, submitState, isTouched } = useFormItemControl({
|
|
8
|
+
const { value, onChange, errors, state, onFocus, isDirty, submitState, isTouched, isInitied } = useFormItemControl({
|
|
8
9
|
formName,
|
|
9
10
|
name,
|
|
10
11
|
initialValue,
|
|
@@ -12,7 +13,7 @@ function FormItem({ children, name, formName, initialValue, formItemId: external
|
|
|
12
13
|
rules,
|
|
13
14
|
elementRef: elRef
|
|
14
15
|
});
|
|
15
|
-
return cloneElement(children, {
|
|
16
|
+
return _jsx(Fragment, { children: !hidden && children ? cloneElement(children, {
|
|
16
17
|
name,
|
|
17
18
|
// ref: inputRef,
|
|
18
19
|
[valuePropName]: value,
|
|
@@ -41,7 +42,7 @@ function FormItem({ children, name, formName, initialValue, formItemId: external
|
|
|
41
42
|
ref: elRef,
|
|
42
43
|
submitState,
|
|
43
44
|
isTouched
|
|
44
|
-
});
|
|
45
|
+
}) : null }, `control-after-init-${Boolean(controlAfterInit && isInitied) ? "1" : "0"}-${formItemId}`);
|
|
45
46
|
}
|
|
46
47
|
export {
|
|
47
48
|
FormItem as default
|
|
@@ -20,6 +20,7 @@ export interface UseFormItemControlReturn {
|
|
|
20
20
|
isDirty?: boolean;
|
|
21
21
|
isTouched?: boolean;
|
|
22
22
|
submitState?: SubmitState;
|
|
23
|
+
isInitied?: boolean;
|
|
23
24
|
}
|
|
24
25
|
export default function useFormItemControl<T = any>({ formName, form, name, initialValue, formItemId, rules, elementRef, }: UseFormItemControlProps): UseFormItemControlReturn;
|
|
25
26
|
export {};
|
|
@@ -38,7 +38,7 @@ function useFormItemControl({ formName, form, name, initialValue, formItemId, ru
|
|
|
38
38
|
}));
|
|
39
39
|
const onInitData = (value2) => {
|
|
40
40
|
setInitData(formName || (form == null ? void 0 : form.formName) || (contextForm == null ? void 0 : contextForm.formName), name, value2);
|
|
41
|
-
onChange(value2, { notTriggerDirty: true });
|
|
41
|
+
onChange(value2, { notTriggerDirty: true, initiedData: true });
|
|
42
42
|
};
|
|
43
43
|
const onFocus = () => {
|
|
44
44
|
setListener({
|
|
@@ -60,10 +60,21 @@ function useFormItemControl({ formName, form, name, initialValue, formItemId, ru
|
|
|
60
60
|
isTouched: listener == null ? void 0 : listener.isTouched
|
|
61
61
|
});
|
|
62
62
|
}
|
|
63
|
+
if ((options == null ? void 0 : options.initiedData) === true) {
|
|
64
|
+
setListener({
|
|
65
|
+
formItemId,
|
|
66
|
+
isInitied: true
|
|
67
|
+
});
|
|
68
|
+
}
|
|
63
69
|
setData(formName || (form == null ? void 0 : form.formName) || (contextForm == null ? void 0 : contextForm.formName), name, value2);
|
|
64
70
|
};
|
|
65
71
|
const onReset = (value2) => {
|
|
66
|
-
|
|
72
|
+
setListener({
|
|
73
|
+
formItemId,
|
|
74
|
+
isDirty: false,
|
|
75
|
+
isTouched: false
|
|
76
|
+
});
|
|
77
|
+
onChange(isNil(value2) ? getInitData(formName || (form == null ? void 0 : form.formName) || (contextForm == null ? void 0 : contextForm.formName), name) : value2, { notTriggerDirty: true, initiedData: true });
|
|
67
78
|
};
|
|
68
79
|
const internalRules = useMemo(() => {
|
|
69
80
|
return rules || [];
|
|
@@ -262,7 +273,10 @@ function useFormItemControl({ formName, form, name, initialValue, formItemId, ru
|
|
|
262
273
|
onInitData(initialValue);
|
|
263
274
|
}
|
|
264
275
|
} else {
|
|
265
|
-
onChange(internalInitValue, {
|
|
276
|
+
onChange(internalInitValue, {
|
|
277
|
+
notTriggerDirty: true,
|
|
278
|
+
initiedData: true
|
|
279
|
+
});
|
|
266
280
|
}
|
|
267
281
|
}
|
|
268
282
|
return;
|
|
@@ -320,7 +334,8 @@ function useFormItemControl({ formName, form, name, initialValue, formItemId, ru
|
|
|
320
334
|
onFocus,
|
|
321
335
|
isDirty: listener == null ? void 0 : listener.isDirty,
|
|
322
336
|
isTouched: listener == null ? void 0 : listener.isTouched,
|
|
323
|
-
submitState
|
|
337
|
+
submitState,
|
|
338
|
+
isInitied: listener == null ? void 0 : listener.isInitied
|
|
324
339
|
};
|
|
325
340
|
}
|
|
326
341
|
export {
|
package/dist/providers/Form.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { ComponentType, FormHTMLAttributes, ReactNode } from "react";
|
|
2
2
|
import type { PublicFormInstance, UseFormItemStateWatchReturn } from "../types/public";
|
|
3
|
-
export type { FormFieldError, SubmitState,
|
|
3
|
+
export type { FormFieldError, SubmitState, UseFormItemStateWatchReturn, ValidationRule, } from "../types/public";
|
|
4
4
|
export declare const FormContext: import("react").Context<any>;
|
|
5
5
|
export interface FormProps<T = any> extends Omit<FormHTMLAttributes<HTMLFormElement>, "onSubmit"> {
|
|
6
6
|
children: ReactNode;
|
package/dist/providers/Form.js
CHANGED
|
@@ -5,6 +5,7 @@ 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 { SUBMIT_STATE } from "../constants/form";
|
|
8
9
|
import { useFormListeners, useFormStore } from "../stores/formStore";
|
|
9
10
|
import { getAllNoneObjStringPath } from "../utils/obj.util";
|
|
10
11
|
const FormContext = createContext(null);
|
|
@@ -167,7 +168,8 @@ function Form({ children, formName, initialValues, onFinish, onReject, onFinally
|
|
|
167
168
|
reset();
|
|
168
169
|
flushSync(setFormState({
|
|
169
170
|
formName,
|
|
170
|
-
isInitied: false
|
|
171
|
+
isInitied: false,
|
|
172
|
+
submitState: SUBMIT_STATE.IDLE
|
|
171
173
|
}));
|
|
172
174
|
const totalListenerFields = getListeners();
|
|
173
175
|
if (Array.isArray(resetOptions)) {
|
package/dist/stores/formStore.js
CHANGED
|
@@ -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 }) {
|
|
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,21 @@ 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
|
+
}
|
|
235
238
|
return;
|
|
236
239
|
}
|
|
237
240
|
storeListeners.push({
|
|
238
241
|
name,
|
|
239
242
|
formName,
|
|
240
|
-
isTouched,
|
|
241
|
-
isDirty,
|
|
243
|
+
isTouched: Boolean(isTouched),
|
|
244
|
+
isDirty: Boolean(isDirty),
|
|
242
245
|
formItemId,
|
|
243
246
|
internalErrors,
|
|
244
247
|
onChange,
|
|
245
|
-
onReset
|
|
248
|
+
onReset,
|
|
249
|
+
isInitied: Boolean(isInitied)
|
|
246
250
|
});
|
|
247
251
|
}));
|
|
248
252
|
},
|
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.7",
|
|
4
4
|
"description": "Lightweight React form management with list and listener support.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -45,6 +45,7 @@
|
|
|
45
45
|
"eslint": "^9.14.0",
|
|
46
46
|
"eslint-plugin-react-hooks": "^5.1.0",
|
|
47
47
|
"eslint-plugin-react-refresh": "^0.4.14",
|
|
48
|
+
"framer-motion": "^12.29.0",
|
|
48
49
|
"globals": "^15.12.0",
|
|
49
50
|
"react": "^19.0.0",
|
|
50
51
|
"react-dom": "^19.0.0",
|
package/src/App.tsx
CHANGED
|
@@ -1,13 +1,19 @@
|
|
|
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";
|
|
7
9
|
|
|
10
|
+
import { Form as AntdForm } from "antd";
|
|
11
|
+
|
|
8
12
|
const App = () => {
|
|
9
13
|
const [form] = useForm("form1");
|
|
10
14
|
|
|
15
|
+
const watchCheckBox = Form.useWatch("checkControlledAfterInit", "form1");
|
|
16
|
+
|
|
11
17
|
useEffect(() => {
|
|
12
18
|
if (form) {
|
|
13
19
|
// setTimeout(() => {
|
|
@@ -17,6 +23,20 @@ const App = () => {
|
|
|
17
23
|
}, [form]);
|
|
18
24
|
return (
|
|
19
25
|
<div>
|
|
26
|
+
<AntdForm>
|
|
27
|
+
<motion.div
|
|
28
|
+
initial={{ opacity: 0 }}
|
|
29
|
+
animate={{ opacity: 1 }}
|
|
30
|
+
exit={{ opacity: 0 }}
|
|
31
|
+
transition={{ duration: 1 }}
|
|
32
|
+
>
|
|
33
|
+
<AntdForm.Item name={"234"} initialValue={"23432"} label="Antd Input">
|
|
34
|
+
<Input />
|
|
35
|
+
</AntdForm.Item>
|
|
36
|
+
</motion.div>
|
|
37
|
+
</AntdForm>
|
|
38
|
+
|
|
39
|
+
{/* Hidden Test */}
|
|
20
40
|
<Form
|
|
21
41
|
initialValues={{
|
|
22
42
|
TestData: "",
|
|
@@ -27,6 +47,7 @@ const App = () => {
|
|
|
27
47
|
console.log(values);
|
|
28
48
|
}}
|
|
29
49
|
formName={"form1"}
|
|
50
|
+
// hidden
|
|
30
51
|
>
|
|
31
52
|
<FormItem
|
|
32
53
|
name={"username"}
|
|
@@ -36,12 +57,15 @@ const App = () => {
|
|
|
36
57
|
message: "Test",
|
|
37
58
|
},
|
|
38
59
|
]}
|
|
60
|
+
initialValue={"283746"}
|
|
61
|
+
// hidden
|
|
39
62
|
>
|
|
40
63
|
<InputWrapper>
|
|
41
64
|
<Input />
|
|
42
65
|
</InputWrapper>
|
|
43
66
|
</FormItem>
|
|
44
67
|
|
|
68
|
+
{/* Numberic test */}
|
|
45
69
|
<FormItem
|
|
46
70
|
name={"numericCode"}
|
|
47
71
|
rules={[
|
|
@@ -56,6 +80,20 @@ const App = () => {
|
|
|
56
80
|
<Input placeholder="Mã chỉ gồm số" style={{ width: 200 }} />
|
|
57
81
|
</InputWrapper>
|
|
58
82
|
</FormItem>
|
|
83
|
+
|
|
84
|
+
{/* Motion Test */}
|
|
85
|
+
<motion.div
|
|
86
|
+
initial={{ opacity: 0 }}
|
|
87
|
+
animate={{ opacity: 1 }}
|
|
88
|
+
exit={{ opacity: 0 }}
|
|
89
|
+
transition={{ duration: 1 }}
|
|
90
|
+
>
|
|
91
|
+
<FormItem name="motionTest" controlAfterInit initialValue={"1234134"}>
|
|
92
|
+
<InputWrapper>
|
|
93
|
+
<Input placeholder="Motion Test" style={{ width: 200 }} />
|
|
94
|
+
</InputWrapper>
|
|
95
|
+
</FormItem>
|
|
96
|
+
</motion.div>
|
|
59
97
|
<FormList
|
|
60
98
|
initialValues={[
|
|
61
99
|
{
|
|
@@ -101,12 +139,32 @@ const App = () => {
|
|
|
101
139
|
</div>
|
|
102
140
|
)}
|
|
103
141
|
</FormList>
|
|
142
|
+
<FormItem
|
|
143
|
+
valuePropName="checked"
|
|
144
|
+
getValueFromEvent={(_, checked) => checked}
|
|
145
|
+
name="checkControlledAfterInit"
|
|
146
|
+
controlAfterInit={true}
|
|
147
|
+
initialValue={true}
|
|
148
|
+
>
|
|
149
|
+
<Checkbox />
|
|
150
|
+
</FormItem>
|
|
151
|
+
<Button
|
|
152
|
+
onClick={() => {
|
|
153
|
+
const current = form?.getFieldValue("checkControlledAfterInit");
|
|
154
|
+
console.log("Toggle controlled after init: ", current);
|
|
155
|
+
form?.setFieldValue("checkControlledAfterInit", !current);
|
|
156
|
+
}}
|
|
157
|
+
>
|
|
158
|
+
Toggle
|
|
159
|
+
</Button>
|
|
104
160
|
<Button htmlType="submit">Submit</Button>
|
|
105
161
|
<Button
|
|
106
162
|
onClick={() => {
|
|
107
163
|
form?.resetFields?.();
|
|
108
164
|
}}
|
|
109
|
-
|
|
165
|
+
>
|
|
166
|
+
Reset
|
|
167
|
+
</Button>
|
|
110
168
|
</Form>
|
|
111
169
|
</div>
|
|
112
170
|
);
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { ReactElement } from "react";
|
|
2
|
-
import { cloneElement, useRef, useState } from "react";
|
|
2
|
+
import { cloneElement, Fragment, useRef, useState } from "react";
|
|
3
3
|
import { v4 } from "uuid";
|
|
4
4
|
import useFormItemControl from "../../hooks/useFormItemControl";
|
|
5
5
|
import type { ValidationRule } from "../../types/public";
|
|
@@ -13,6 +13,8 @@ export interface FormItemProps {
|
|
|
13
13
|
rules?: ValidationRule[];
|
|
14
14
|
valuePropName?: string;
|
|
15
15
|
getValueFromEvent?: (...args: any[]) => any;
|
|
16
|
+
controlAfterInit?: boolean;
|
|
17
|
+
hidden?: boolean;
|
|
16
18
|
}
|
|
17
19
|
|
|
18
20
|
export default function FormItem({
|
|
@@ -24,6 +26,8 @@ export default function FormItem({
|
|
|
24
26
|
rules,
|
|
25
27
|
valuePropName = "value",
|
|
26
28
|
getValueFromEvent,
|
|
29
|
+
controlAfterInit = false,
|
|
30
|
+
hidden,
|
|
27
31
|
}: FormItemProps) {
|
|
28
32
|
const elRef = useRef<any>(null);
|
|
29
33
|
|
|
@@ -37,6 +41,7 @@ export default function FormItem({
|
|
|
37
41
|
isDirty,
|
|
38
42
|
submitState,
|
|
39
43
|
isTouched,
|
|
44
|
+
isInitied,
|
|
40
45
|
} = useFormItemControl({
|
|
41
46
|
formName,
|
|
42
47
|
name,
|
|
@@ -51,35 +56,55 @@ export default function FormItem({
|
|
|
51
56
|
// console.log({ value });
|
|
52
57
|
// }, [value]);
|
|
53
58
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
} else {
|
|
63
|
-
const e = args[0];
|
|
64
|
-
if (e && e.target) {
|
|
65
|
-
val = e.target.value;
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
onChange(val);
|
|
69
|
-
},
|
|
70
|
-
// onFocus: () => {
|
|
71
|
-
// setIsTouched(true);
|
|
72
|
-
// },
|
|
73
|
-
// isTouched: isTouched,
|
|
74
|
-
isDirty: isDirty,
|
|
75
|
-
// errors: errors,
|
|
76
|
-
// formState,
|
|
59
|
+
// useEffect(() => {
|
|
60
|
+
// console.log("isInitied changed: ", {
|
|
61
|
+
// isInitied,
|
|
62
|
+
// name,
|
|
63
|
+
// value,
|
|
64
|
+
// controlAfterInit,
|
|
65
|
+
// });
|
|
66
|
+
// }, [isInitied]);
|
|
77
67
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
68
|
+
return (
|
|
69
|
+
<Fragment
|
|
70
|
+
key={`control-after-init-${Boolean(controlAfterInit && isInitied) ? "1" : "0"}-${formItemId}`}
|
|
71
|
+
>
|
|
72
|
+
{!hidden && children
|
|
73
|
+
? cloneElement(children, {
|
|
74
|
+
name,
|
|
75
|
+
// ref: inputRef,
|
|
76
|
+
[valuePropName]: value,
|
|
77
|
+
onChange: (...args: any[]) => {
|
|
78
|
+
let val = args[0];
|
|
79
|
+
if (
|
|
80
|
+
getValueFromEvent &&
|
|
81
|
+
typeof getValueFromEvent === "function"
|
|
82
|
+
) {
|
|
83
|
+
val = getValueFromEvent(...args);
|
|
84
|
+
} else {
|
|
85
|
+
const e = args[0];
|
|
86
|
+
if (e && e.target) {
|
|
87
|
+
val = e.target.value;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
onChange(val);
|
|
91
|
+
},
|
|
92
|
+
// onFocus: () => {
|
|
93
|
+
// setIsTouched(true);
|
|
94
|
+
// },
|
|
95
|
+
// isTouched: isTouched,
|
|
96
|
+
isDirty: isDirty,
|
|
97
|
+
// errors: errors,
|
|
98
|
+
// formState,
|
|
99
|
+
|
|
100
|
+
errors,
|
|
101
|
+
onFocus,
|
|
102
|
+
validateState: state,
|
|
103
|
+
ref: elRef,
|
|
104
|
+
submitState,
|
|
105
|
+
isTouched: isTouched,
|
|
106
|
+
} as any)
|
|
107
|
+
: null}
|
|
108
|
+
</Fragment>
|
|
109
|
+
);
|
|
85
110
|
}
|
|
@@ -13,6 +13,11 @@ const InputWrapper = ({
|
|
|
13
13
|
errors = [],
|
|
14
14
|
...props
|
|
15
15
|
}: InputWrapperProps) => {
|
|
16
|
+
// useEffect(() => {
|
|
17
|
+
// console.log("InputWrapper submitState changed: ", {
|
|
18
|
+
// submitState: props.submitState,
|
|
19
|
+
// });
|
|
20
|
+
// }, [props.submitState]);
|
|
16
21
|
return (
|
|
17
22
|
<div>
|
|
18
23
|
{cloneElement(children, props)}
|
|
@@ -52,6 +52,7 @@ export interface UseFormItemControlReturn {
|
|
|
52
52
|
isDirty?: boolean;
|
|
53
53
|
isTouched?: boolean;
|
|
54
54
|
submitState?: SubmitState;
|
|
55
|
+
isInitied?: boolean;
|
|
55
56
|
}
|
|
56
57
|
|
|
57
58
|
const VALID_PREMITIVE_TYPE = ["string", "number", "undefined"];
|
|
@@ -154,7 +155,7 @@ export default function useFormItemControl<T = any>({
|
|
|
154
155
|
name,
|
|
155
156
|
value,
|
|
156
157
|
);
|
|
157
|
-
onChange(value, { notTriggerDirty: true });
|
|
158
|
+
onChange(value, { notTriggerDirty: true, initiedData: true });
|
|
158
159
|
};
|
|
159
160
|
|
|
160
161
|
const onFocus = () => {
|
|
@@ -171,7 +172,13 @@ export default function useFormItemControl<T = any>({
|
|
|
171
172
|
}
|
|
172
173
|
};
|
|
173
174
|
|
|
174
|
-
const onChange = (
|
|
175
|
+
const onChange = (
|
|
176
|
+
value: T,
|
|
177
|
+
options?: {
|
|
178
|
+
notTriggerDirty?: boolean;
|
|
179
|
+
initiedData?: boolean;
|
|
180
|
+
},
|
|
181
|
+
) => {
|
|
175
182
|
if (options?.notTriggerDirty !== true) {
|
|
176
183
|
setListener({
|
|
177
184
|
formItemId,
|
|
@@ -179,6 +186,12 @@ export default function useFormItemControl<T = any>({
|
|
|
179
186
|
isTouched: listener?.isTouched,
|
|
180
187
|
});
|
|
181
188
|
}
|
|
189
|
+
if (options?.initiedData === true) {
|
|
190
|
+
setListener({
|
|
191
|
+
formItemId,
|
|
192
|
+
isInitied: true,
|
|
193
|
+
});
|
|
194
|
+
}
|
|
182
195
|
setData(formName || form?.formName || contextForm?.formName, name, value);
|
|
183
196
|
};
|
|
184
197
|
|
|
@@ -188,10 +201,16 @@ export default function useFormItemControl<T = any>({
|
|
|
188
201
|
value,
|
|
189
202
|
getInitData(formName || form?.formName || contextForm?.formName, name),
|
|
190
203
|
);
|
|
204
|
+
setListener({
|
|
205
|
+
formItemId,
|
|
206
|
+
isDirty: false,
|
|
207
|
+
isTouched: false,
|
|
208
|
+
});
|
|
191
209
|
onChange(
|
|
192
210
|
isNil(value)
|
|
193
211
|
? getInitData(formName || form?.formName || contextForm?.formName, name)
|
|
194
212
|
: value,
|
|
213
|
+
{ notTriggerDirty: true, initiedData: true },
|
|
195
214
|
);
|
|
196
215
|
};
|
|
197
216
|
|
|
@@ -522,7 +541,10 @@ export default function useFormItemControl<T = any>({
|
|
|
522
541
|
onInitData(initialValue);
|
|
523
542
|
}
|
|
524
543
|
} else {
|
|
525
|
-
onChange(internalInitValue, {
|
|
544
|
+
onChange(internalInitValue, {
|
|
545
|
+
notTriggerDirty: true,
|
|
546
|
+
initiedData: true,
|
|
547
|
+
});
|
|
526
548
|
}
|
|
527
549
|
}
|
|
528
550
|
return;
|
|
@@ -599,5 +621,6 @@ export default function useFormItemControl<T = any>({
|
|
|
599
621
|
isDirty: listener?.isDirty,
|
|
600
622
|
isTouched: listener?.isTouched,
|
|
601
623
|
submitState,
|
|
624
|
+
isInitied: listener?.isInitied,
|
|
602
625
|
};
|
|
603
626
|
}
|
package/src/providers/Form.tsx
CHANGED
|
@@ -5,14 +5,18 @@ import { createContext, useContext, useEffect, useState } from "react";
|
|
|
5
5
|
import { flushSync } from "react-dom";
|
|
6
6
|
import { useShallow } from "zustand/react/shallow"; // Import useShallow
|
|
7
7
|
import FormCleanUp from "../components/Form/FormCleanUp";
|
|
8
|
+
import { SUBMIT_STATE } from "../constants/form";
|
|
8
9
|
import { useFormListeners, useFormStore } from "../stores/formStore";
|
|
9
|
-
import type {
|
|
10
|
+
import type {
|
|
11
|
+
PublicFormInstance,
|
|
12
|
+
UseFormItemStateWatchReturn,
|
|
13
|
+
} from "../types/public";
|
|
10
14
|
import { getAllNoneObjStringPath } from "../utils/obj.util";
|
|
11
15
|
export type {
|
|
12
16
|
FormFieldError,
|
|
13
17
|
SubmitState,
|
|
14
|
-
ValidationRule,
|
|
15
18
|
UseFormItemStateWatchReturn,
|
|
19
|
+
ValidationRule,
|
|
16
20
|
} from "../types/public";
|
|
17
21
|
|
|
18
22
|
export const FormContext = createContext(null);
|
|
@@ -276,6 +280,7 @@ export default function Form<T = any>({
|
|
|
276
280
|
setFormState({
|
|
277
281
|
formName,
|
|
278
282
|
isInitied: false,
|
|
283
|
+
submitState: SUBMIT_STATE.IDLE,
|
|
279
284
|
}),
|
|
280
285
|
);
|
|
281
286
|
const totalListenerFields = getListeners();
|
package/src/stores/formStore.ts
CHANGED
|
@@ -375,6 +375,7 @@ export const useFormListeners = create<any>((storeSet: any, storeGet: any) => ({
|
|
|
375
375
|
internalErrors,
|
|
376
376
|
onFocus,
|
|
377
377
|
emitFocus,
|
|
378
|
+
isInitied,
|
|
378
379
|
}) {
|
|
379
380
|
return storeSet(
|
|
380
381
|
produce<any>((state: any) => {
|
|
@@ -412,17 +413,22 @@ export const useFormListeners = create<any>((storeSet: any, storeGet: any) => ({
|
|
|
412
413
|
storeListeners[findListenerIndex].emitFocus = emitFocus;
|
|
413
414
|
}
|
|
414
415
|
|
|
416
|
+
if (!isNil(isInitied)) {
|
|
417
|
+
storeListeners[findListenerIndex].isInitied = isInitied;
|
|
418
|
+
}
|
|
419
|
+
|
|
415
420
|
return;
|
|
416
421
|
}
|
|
417
422
|
storeListeners.push({
|
|
418
423
|
name,
|
|
419
424
|
formName,
|
|
420
|
-
isTouched,
|
|
421
|
-
isDirty,
|
|
425
|
+
isTouched: Boolean(isTouched),
|
|
426
|
+
isDirty: Boolean(isDirty),
|
|
422
427
|
formItemId,
|
|
423
428
|
internalErrors,
|
|
424
429
|
onChange,
|
|
425
430
|
onReset,
|
|
431
|
+
isInitied: Boolean(isInitied),
|
|
426
432
|
});
|
|
427
433
|
}),
|
|
428
434
|
);
|