react-form-manage 1.0.8 → 1.1.0-beta.2
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 +77 -0
- package/dist/providers/Form.d.ts +30 -15
- package/dist/providers/Form.js +142 -25
- package/dist/stores/formStore.js +3 -0
- package/dist/test/testFormInstance/TestCase1_FormWithInstance.d.ts +14 -0
- package/dist/test/testFormInstance/TestCase1_FormWithInstance.js +21 -0
- package/dist/test/testFormInstance/TestCase2_AutoGenerateFormName.d.ts +14 -0
- package/dist/test/testFormInstance/TestCase2_AutoGenerateFormName.js +23 -0
- package/dist/test/testFormInstance/TestCase3_SafeFormMethods.d.ts +14 -0
- package/dist/test/testFormInstance/TestCase3_SafeFormMethods.js +69 -0
- package/dist/test/testFormInstance/TestCase4_UseFormStatusFlag.d.ts +15 -0
- package/dist/test/testFormInstance/TestCase4_UseFormStatusFlag.js +68 -0
- package/dist/test/testFormInstance/TestCase5_UseFormUtils.d.ts +1 -0
- package/dist/test/testFormInstance/TestCase5_UseFormUtils.js +70 -0
- package/dist/test/testFormInstance/TestCase6_FormWithoutWrapper.d.ts +15 -0
- package/dist/test/testFormInstance/TestCase6_FormWithoutWrapper.js +55 -0
- package/dist/test/testFormInstance/TestCase7_SetValueInEffect.d.ts +1 -0
- package/dist/test/testFormInstance/TestCase7_SetValueInEffect.js +76 -0
- package/dist/test/testFormInstance/TestCase8_TypeSafetyImprovements.d.ts +1 -0
- package/dist/test/testFormInstance/TestCase8_TypeSafetyImprovements.js +102 -0
- package/dist/test/testFormInstance/index.d.ts +14 -0
- package/dist/test/testFormInstance/index.js +66 -0
- package/dist/test/testSetValue/TestSetValueInEffect.d.ts +3 -0
- package/dist/test/testSetValue/TestSetValueInEffect.js +30 -0
- package/dist/types/public.d.ts +12 -8
- package/package.json +3 -2
- package/src/App.tsx +7 -7
- package/src/providers/Form.tsx +247 -28
- package/src/stores/formStore.ts +3 -1
- package/src/test/testFormInstance/TestCase1_FormWithInstance.tsx +116 -0
- package/src/test/testFormInstance/TestCase2_AutoGenerateFormName.tsx +142 -0
- package/src/test/testFormInstance/TestCase3_SafeFormMethods.tsx +220 -0
- package/src/test/testFormInstance/TestCase4_UseFormStatusFlag.tsx +278 -0
- package/src/test/testFormInstance/TestCase5_UseFormUtils.tsx +242 -0
- package/src/test/testFormInstance/TestCase6_FormWithoutWrapper.tsx +238 -0
- package/src/test/testFormInstance/TestCase7_SetValueInEffect.tsx +307 -0
- package/src/test/testFormInstance/TestCase8_TypeSafetyImprovements.tsx +390 -0
- package/src/test/testFormInstance/index.tsx +155 -0
- package/src/test/testSetValue/TestSetValueInEffect.tsx +54 -0
- package/src/types/public.ts +15 -8
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
import { Tabs, Typography } from "antd";
|
|
2
|
+
import { useState } from "react";
|
|
3
|
+
import TestCase1_FormWithInstance from "./TestCase1_FormWithInstance";
|
|
4
|
+
import TestCase2_AutoGenerateFormName from "./TestCase2_AutoGenerateFormName";
|
|
5
|
+
import TestCase3_SafeFormMethods from "./TestCase3_SafeFormMethods";
|
|
6
|
+
import TestCase4_UseFormStatusFlag from "./TestCase4_UseFormStatusFlag";
|
|
7
|
+
import TestCase5_UseFormUtils from "./TestCase5_UseFormUtils";
|
|
8
|
+
import TestCase6_FormWithoutWrapper from "./TestCase6_FormWithoutWrapper";
|
|
9
|
+
import TestCase7_SetValueInEffect from "./TestCase7_SetValueInEffect";
|
|
10
|
+
import TestCase8_TypeSafetyImprovements from "./TestCase8_TypeSafetyImprovements";
|
|
11
|
+
|
|
12
|
+
const { Title, Paragraph, Text } = Typography;
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Form Instance Test Suite
|
|
16
|
+
*
|
|
17
|
+
* Test suite cho breaking changes và new features liên quan đến Form Instance:
|
|
18
|
+
* - Form component nhận prop "form" thay vì chỉ có "formName"
|
|
19
|
+
* - Auto-generate UUID cho formName
|
|
20
|
+
* - Safe form methods với proxy instance
|
|
21
|
+
* - useForm trả về [instance, isReady] tuple
|
|
22
|
+
* - useFormUtils hook mới
|
|
23
|
+
* - Form instance hoạt động độc lập như state manager
|
|
24
|
+
* - setValue trong useEffect với setTimeout (async behavior)
|
|
25
|
+
* - Type safety improvements (dynamic field names, getFieldErrors type, submitAsync type)
|
|
26
|
+
*/
|
|
27
|
+
|
|
28
|
+
export default function FormInstanceTestSuite() {
|
|
29
|
+
const [activeTab, setActiveTab] = useState("1");
|
|
30
|
+
|
|
31
|
+
const items = [
|
|
32
|
+
{
|
|
33
|
+
key: "1",
|
|
34
|
+
label: "TestCase1: Form with Instance",
|
|
35
|
+
children: <TestCase1_FormWithInstance />,
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
key: "2",
|
|
39
|
+
label: "TestCase2: Auto-generate FormName",
|
|
40
|
+
children: <TestCase2_AutoGenerateFormName />,
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
key: "3",
|
|
44
|
+
label: "TestCase3: Safe Form Methods",
|
|
45
|
+
children: <TestCase3_SafeFormMethods />,
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
key: "4",
|
|
49
|
+
label: "TestCase4: useForm Status Flag",
|
|
50
|
+
children: <TestCase4_UseFormStatusFlag />,
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
key: "5",
|
|
54
|
+
label: "TestCase5: useFormUtils Hook",
|
|
55
|
+
children: <TestCase5_UseFormUtils />,
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
key: "6",
|
|
59
|
+
label: "TestCase6: Form Without Wrapper",
|
|
60
|
+
children: <TestCase6_FormWithoutWrapper />,
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
key: "7",
|
|
64
|
+
label: "TestCase7: Set Value in Effect",
|
|
65
|
+
children: <TestCase7_SetValueInEffect />,
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
key: "8",
|
|
69
|
+
label: "TestCase8: Type Safety",
|
|
70
|
+
children: <TestCase8_TypeSafetyImprovements />,
|
|
71
|
+
},
|
|
72
|
+
];
|
|
73
|
+
|
|
74
|
+
return (
|
|
75
|
+
<div style={{ padding: 24, maxWidth: 1400, margin: "0 auto" }}>
|
|
76
|
+
<div style={{ marginBottom: 32 }}>
|
|
77
|
+
<Title level={2}>🧪 Form Instance Test Suite</Title>
|
|
78
|
+
<Paragraph>
|
|
79
|
+
<Text>
|
|
80
|
+
Test suite cho breaking changes và new features trong version mới.
|
|
81
|
+
Mỗi test case cover một aspect cụ thể của Form Instance behavior.
|
|
82
|
+
</Text>
|
|
83
|
+
</Paragraph>
|
|
84
|
+
</div>
|
|
85
|
+
|
|
86
|
+
<div
|
|
87
|
+
style={{
|
|
88
|
+
marginBottom: 24,
|
|
89
|
+
padding: 16,
|
|
90
|
+
background: "#e6f7ff",
|
|
91
|
+
border: "1px solid #91d5ff",
|
|
92
|
+
}}
|
|
93
|
+
>
|
|
94
|
+
<Title level={4}>📋 Breaking Changes & New Features:</Title>
|
|
95
|
+
<ul style={{ marginBottom: 0 }}>
|
|
96
|
+
<li>
|
|
97
|
+
<Text strong>Form Prop "form":</Text> Form component có thể nhận{" "}
|
|
98
|
+
<Text code>form</Text> instance thay vì <Text code>formName</Text>
|
|
99
|
+
</li>
|
|
100
|
+
<li>
|
|
101
|
+
<Text strong>Auto-generate FormName:</Text> Form.useForm() tự động
|
|
102
|
+
tạo UUID nếu không truyền tham số
|
|
103
|
+
</li>
|
|
104
|
+
<li>
|
|
105
|
+
<Text strong>Safe Methods:</Text> Form methods có thể gọi an toàn
|
|
106
|
+
trước khi Form mount (proxy instance)
|
|
107
|
+
</li>
|
|
108
|
+
<li>
|
|
109
|
+
<Text strong>useForm Tuple:</Text> useForm() trả về{" "}
|
|
110
|
+
<Text code>[instance, isReady]</Text> thay vì chỉ{" "}
|
|
111
|
+
<Text code>[instance]</Text>
|
|
112
|
+
</li>
|
|
113
|
+
<li>
|
|
114
|
+
<Text strong>useFormUtils Hook:</Text> Hook mới cho phép thao tác
|
|
115
|
+
form từ bên ngoài component
|
|
116
|
+
</li>
|
|
117
|
+
<li>
|
|
118
|
+
<Text strong>Headless Forms:</Text> Form instance hoạt động độc lập
|
|
119
|
+
như state manager
|
|
120
|
+
</li>
|
|
121
|
+
<li>
|
|
122
|
+
<Text strong>Async Behavior:</Text> Form methods hoạt động với async
|
|
123
|
+
callbacks (setTimeout, Promise, etc.)
|
|
124
|
+
</li>
|
|
125
|
+
<li>
|
|
126
|
+
<Text strong>Type Improvements:</Text> Dynamic field names{" "}
|
|
127
|
+
<Text code>{`keyof T | (string & {})`}</Text>, proper getFieldErrors return
|
|
128
|
+
type, submitAsync <Text code>Promise<void></Text>
|
|
129
|
+
</li>
|
|
130
|
+
</ul>
|
|
131
|
+
</div>
|
|
132
|
+
|
|
133
|
+
<Tabs
|
|
134
|
+
activeKey={activeTab}
|
|
135
|
+
onChange={setActiveTab}
|
|
136
|
+
items={items}
|
|
137
|
+
size="large"
|
|
138
|
+
type="card"
|
|
139
|
+
/>
|
|
140
|
+
|
|
141
|
+
<div style={{ marginTop: 32, padding: 16, background: "#f5f5f5" }}>
|
|
142
|
+
<Title level={5}>💡 Testing Tips:</Title>
|
|
143
|
+
<ul style={{ marginBottom: 0 }}>
|
|
144
|
+
<li>Mở Browser Console để xem detailed logs và warnings</li>
|
|
145
|
+
<li>Mỗi test case có Expected Results section để verify behavior</li>
|
|
146
|
+
<li>Test cases có thể test độc lập, không ảnh hưởng lẫn nhau</li>
|
|
147
|
+
<li>
|
|
148
|
+
Chú ý các warning messages khi form methods được gọi sai timing
|
|
149
|
+
</li>
|
|
150
|
+
<li>Use Cases sections giải thích khi nào nên dùng feature đó</li>
|
|
151
|
+
</ul>
|
|
152
|
+
</div>
|
|
153
|
+
</div>
|
|
154
|
+
);
|
|
155
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { Button, Input } from "antd";
|
|
2
|
+
import axios from "axios";
|
|
3
|
+
import { useEffect, useEffectEvent, useState } from "react";
|
|
4
|
+
import { useShallow } from "zustand/react/shallow";
|
|
5
|
+
import Form from "../../providers/Form";
|
|
6
|
+
import { useFormStore } from "../../stores/formStore";
|
|
7
|
+
import { PublicFormInstance } from "../../types";
|
|
8
|
+
|
|
9
|
+
type Props = {};
|
|
10
|
+
|
|
11
|
+
function TestSetValueInEffect({}: Props) {
|
|
12
|
+
const { getFormInstance } = useFormStore(
|
|
13
|
+
useShallow((state) => ({
|
|
14
|
+
getFormInstance: state.getFormInstance,
|
|
15
|
+
})),
|
|
16
|
+
);
|
|
17
|
+
const [stateRender, setStateRender] = useState(1);
|
|
18
|
+
const [form] = Form.useForm("testFormMounted");
|
|
19
|
+
|
|
20
|
+
const setDataEvent = useEffectEvent((form?: PublicFormInstance) => {
|
|
21
|
+
console.log("Effect Event Triggered with form: ", form);
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
useEffect(() => {
|
|
25
|
+
setTimeout(() => {
|
|
26
|
+
console.log("Form Mounted", getFormInstance("testFormMounted"));
|
|
27
|
+
}, 1000);
|
|
28
|
+
|
|
29
|
+
setDataEvent(form);
|
|
30
|
+
|
|
31
|
+
axios
|
|
32
|
+
.get("https://jsonplaceholder.typicode.com/todos/1")
|
|
33
|
+
.then((response) => {});
|
|
34
|
+
}, []);
|
|
35
|
+
return (
|
|
36
|
+
<div>
|
|
37
|
+
<Form formName="testFormMounted">
|
|
38
|
+
<Form.Item name="test" initialValue={"initial value"}>
|
|
39
|
+
<Input />
|
|
40
|
+
</Form.Item>
|
|
41
|
+
</Form>
|
|
42
|
+
|
|
43
|
+
<Button
|
|
44
|
+
onClick={() => {
|
|
45
|
+
setStateRender((prev) => prev + 1);
|
|
46
|
+
}}
|
|
47
|
+
>
|
|
48
|
+
Counter: {stateRender}
|
|
49
|
+
</Button>
|
|
50
|
+
</div>
|
|
51
|
+
);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export default TestSetValueInEffect;
|
package/src/types/public.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { SUBMIT_STATE } from "../constants/form";
|
|
2
|
+
import { SetFieldValueOptions } from "../providers/Form";
|
|
2
3
|
import type { GetConstantType } from "./util";
|
|
3
4
|
|
|
4
5
|
export type FormValues<T = any> = T;
|
|
@@ -37,21 +38,27 @@ export interface PublicFormInstance<T = any> {
|
|
|
37
38
|
formName: string;
|
|
38
39
|
resetFields: (values?: Partial<T>) => void;
|
|
39
40
|
submit: (values?: T) => void;
|
|
40
|
-
submitAsync: (values?: T) => Promise<
|
|
41
|
-
setFieldValue: (
|
|
42
|
-
|
|
43
|
-
|
|
41
|
+
submitAsync: (values?: T) => Promise<void>;
|
|
42
|
+
setFieldValue: (
|
|
43
|
+
name: keyof T | (string & {}),
|
|
44
|
+
value: any,
|
|
45
|
+
options?: SetFieldValueOptions,
|
|
46
|
+
) => void;
|
|
47
|
+
setFieldValues: (values: Partial<T>, options?: SetFieldValueOptions) => void;
|
|
48
|
+
getFieldValue: (name: keyof T | (string & {})) => any;
|
|
44
49
|
getFieldValues: (
|
|
45
|
-
names?: Array<keyof T &
|
|
50
|
+
names?: Array<keyof T | (string & {})>,
|
|
46
51
|
) => Array<{ name: string; value: any }>;
|
|
47
|
-
getFieldErrors: (
|
|
48
|
-
|
|
52
|
+
getFieldErrors: (
|
|
53
|
+
names?: Array<keyof T | (string & {})>,
|
|
54
|
+
) => Array<{ name: string; errors: FormFieldError[] }>;
|
|
55
|
+
setFieldFocus: (name: keyof T | (string & {})) => void;
|
|
49
56
|
}
|
|
50
57
|
|
|
51
58
|
export interface UseFormItemProps<T = any> {
|
|
52
59
|
formName?: string;
|
|
53
60
|
form?: PublicFormInstance<T>;
|
|
54
|
-
name?: keyof T &
|
|
61
|
+
name?: keyof T | (string & {});
|
|
55
62
|
initialValue?: any;
|
|
56
63
|
formItemId?: string;
|
|
57
64
|
rules?: ValidationRule<any, T>[];
|