react-form-manage 1.0.8 → 1.1.0-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.
Files changed (34) hide show
  1. package/CHANGELOG.md +45 -0
  2. package/dist/providers/Form.d.ts +30 -15
  3. package/dist/providers/Form.js +142 -25
  4. package/dist/stores/formStore.js +3 -0
  5. package/dist/test/testFormInstance/TestCase1_FormWithInstance.d.ts +14 -0
  6. package/dist/test/testFormInstance/TestCase1_FormWithInstance.js +21 -0
  7. package/dist/test/testFormInstance/TestCase2_AutoGenerateFormName.d.ts +14 -0
  8. package/dist/test/testFormInstance/TestCase2_AutoGenerateFormName.js +23 -0
  9. package/dist/test/testFormInstance/TestCase3_SafeFormMethods.d.ts +14 -0
  10. package/dist/test/testFormInstance/TestCase3_SafeFormMethods.js +66 -0
  11. package/dist/test/testFormInstance/TestCase4_UseFormStatusFlag.d.ts +15 -0
  12. package/dist/test/testFormInstance/TestCase4_UseFormStatusFlag.js +59 -0
  13. package/dist/test/testFormInstance/TestCase5_UseFormUtils.d.ts +1 -0
  14. package/dist/test/testFormInstance/TestCase5_UseFormUtils.js +65 -0
  15. package/dist/test/testFormInstance/TestCase6_FormWithoutWrapper.d.ts +15 -0
  16. package/dist/test/testFormInstance/TestCase6_FormWithoutWrapper.js +45 -0
  17. package/dist/test/testFormInstance/index.d.ts +12 -0
  18. package/dist/test/testFormInstance/index.js +49 -0
  19. package/dist/test/testSetValue/TestSetValueInEffect.d.ts +3 -0
  20. package/dist/test/testSetValue/TestSetValueInEffect.js +30 -0
  21. package/dist/types/public.d.ts +1 -1
  22. package/package.json +2 -1
  23. package/src/App.tsx +7 -7
  24. package/src/providers/Form.tsx +247 -28
  25. package/src/stores/formStore.ts +3 -1
  26. package/src/test/testFormInstance/TestCase1_FormWithInstance.tsx +112 -0
  27. package/src/test/testFormInstance/TestCase2_AutoGenerateFormName.tsx +139 -0
  28. package/src/test/testFormInstance/TestCase3_SafeFormMethods.tsx +203 -0
  29. package/src/test/testFormInstance/TestCase4_UseFormStatusFlag.tsx +252 -0
  30. package/src/test/testFormInstance/TestCase5_UseFormUtils.tsx +224 -0
  31. package/src/test/testFormInstance/TestCase6_FormWithoutWrapper.tsx +204 -0
  32. package/src/test/testFormInstance/index.tsx +116 -0
  33. package/src/test/testSetValue/TestSetValueInEffect.tsx +54 -0
  34. package/src/types/public.ts +1 -1
@@ -0,0 +1,112 @@
1
+ import { Button, Space, Typography } from "antd";
2
+ import Form from "../../providers/Form";
3
+
4
+ const { Title, Paragraph, Text } = Typography;
5
+
6
+ /**
7
+ * TestCase1: Form with Instance Prop
8
+ *
9
+ * Mô tả:
10
+ * - Test breaking change: Form component nhận prop "form" thay vì chỉ có "formName"
11
+ * - Form instance được tạo trước bằng Form.useForm()
12
+ * - Các methods được bind vào instance trước khi Form mount
13
+ *
14
+ * Expected Behavior:
15
+ * - Có thể gọi form.setFieldValue() trước khi Form render
16
+ * - Form sử dụng formName từ instance
17
+ * - Instance được persist và rebind methods khi Form mount
18
+ */
19
+
20
+ export default function TestCase1_FormWithInstance() {
21
+ const [form] = Form.useForm<{ username: string; email: string }>();
22
+
23
+ const handleSetValueBeforeMount = () => {
24
+ // Test: Gọi setFieldValue trước khi Form mount
25
+ form.setFieldValue("username", "admin");
26
+ form.setFieldValue("email", "admin@example.com");
27
+ console.log("✅ Set values before mount:", {
28
+ username: form.getFieldValue("username"),
29
+ email: form.getFieldValue("email"),
30
+ });
31
+ };
32
+
33
+ const handleGetValues = () => {
34
+ console.log("Current values:", {
35
+ username: form.getFieldValue("username"),
36
+ email: form.getFieldValue("email"),
37
+ });
38
+ };
39
+
40
+ const handleReset = () => {
41
+ form.resetFields();
42
+ console.log("Form reset");
43
+ };
44
+
45
+ return (
46
+ <div style={{ padding: 24 }}>
47
+ <Title level={3}>TestCase1: Form with Instance Prop</Title>
48
+
49
+ <Paragraph>
50
+ <Text strong>Breaking Change:</Text> Form component có thể nhận prop <Text code>form</Text> thay vì <Text code>formName</Text>
51
+ </Paragraph>
52
+
53
+ <Paragraph>
54
+ <Text type="secondary">
55
+ Form instance được tạo bằng Form.useForm() và truyền vào Form component.
56
+ Instance này có thể được sử dụng trước khi Form mount.
57
+ </Text>
58
+ </Paragraph>
59
+
60
+ <Space style={{ marginBottom: 24 }}>
61
+ <Button onClick={handleSetValueBeforeMount} type="primary">
62
+ Set Values Before Mount
63
+ </Button>
64
+ <Button onClick={handleGetValues}>
65
+ Get Current Values (Check Console)
66
+ </Button>
67
+ <Button onClick={handleReset} danger>
68
+ Reset Form
69
+ </Button>
70
+ </Space>
71
+
72
+ <Form
73
+ form={form}
74
+ initialValues={{ username: "", email: "" }}
75
+ onFinish={(values) => {
76
+ console.log("Form submitted:", values);
77
+ }}
78
+ >
79
+ <Form.Item name="username" label="Username">
80
+ <input
81
+ type="text"
82
+ placeholder="Username"
83
+ style={{ padding: 8, width: 300 }}
84
+ />
85
+ </Form.Item>
86
+
87
+ <Form.Item name="email" label="Email">
88
+ <input
89
+ type="email"
90
+ placeholder="Email"
91
+ style={{ padding: 8, width: 300 }}
92
+ />
93
+ </Form.Item>
94
+
95
+ <Button type="primary" htmlType="submit">
96
+ Submit
97
+ </Button>
98
+ </Form>
99
+
100
+ <div style={{ marginTop: 24, padding: 16, background: "#f5f5f5" }}>
101
+ <Title level={5}>Expected Results:</Title>
102
+ <ul>
103
+ <li>✅ Click "Set Values Before Mount" → Values được set và log ra console</li>
104
+ <li>✅ Click "Get Current Values" → Values hiện tại được log ra</li>
105
+ <li>✅ Form render với values đã set</li>
106
+ <li>✅ Click "Reset Form" → Form reset về initialValues</li>
107
+ <li>✅ Submit form → Console log submitted values</li>
108
+ </ul>
109
+ </div>
110
+ </div>
111
+ );
112
+ }
@@ -0,0 +1,139 @@
1
+ import { Button, Space, Typography } from "antd";
2
+ import { useState } from "react";
3
+ import Form from "../../providers/Form";
4
+
5
+ const { Title, Paragraph, Text } = Typography;
6
+
7
+ /**
8
+ * TestCase2: Auto-generate FormName
9
+ *
10
+ * Mô tả:
11
+ * - Test feature: Form.useForm() tự động generate UUID nếu không truyền tham số
12
+ * - Mỗi lần gọi Form.useForm() sẽ tạo ra một formName unique
13
+ * - Form component có thể hoạt động mà không cần truyền formName prop
14
+ *
15
+ * Expected Behavior:
16
+ * - Form hoạt động bình thường với auto-generated formName
17
+ * - FormName là UUID duy nhất
18
+ * - Multiple forms có thể coexist với auto-generated names
19
+ */
20
+
21
+ export default function TestCase2_AutoGenerateFormName() {
22
+ const [form1] = Form.useForm<{ name: string }>();
23
+ const [form2] = Form.useForm<{ email: string }>();
24
+ const [showForm1, setShowForm1] = useState(true);
25
+ const [showForm2, setShowForm2] = useState(true);
26
+
27
+ const handleLogFormNames = () => {
28
+ console.log("Form 1 Name:", form1.formName);
29
+ console.log("Form 2 Name:", form2.formName);
30
+ console.log("Form 1 Value:", form1.getFieldValue("name"));
31
+ console.log("Form 2 Value:", form2.getFieldValue("email"));
32
+ };
33
+
34
+ const handleSetValues = () => {
35
+ form1.setFieldValue("name", "John Doe");
36
+ form2.setFieldValue("email", "john@example.com");
37
+ console.log("✅ Values set for both forms");
38
+ };
39
+
40
+ return (
41
+ <div style={{ padding: 24 }}>
42
+ <Title level={3}>TestCase2: Auto-generate FormName</Title>
43
+
44
+ <Paragraph>
45
+ <Text strong>New Feature:</Text> Form.useForm() tự động tạo UUID làm formName nếu không có tham số
46
+ </Paragraph>
47
+
48
+ <Paragraph>
49
+ <Text type="secondary">
50
+ Mỗi form instance có một UUID duy nhất, không cần phải manually quản lý formName.
51
+ Multiple forms có thể coexist mà không lo bị conflict.
52
+ </Text>
53
+ </Paragraph>
54
+
55
+ <Space style={{ marginBottom: 24 }}>
56
+ <Button onClick={handleLogFormNames} type="primary">
57
+ Log Form Names (Check Console)
58
+ </Button>
59
+ <Button onClick={handleSetValues}>
60
+ Set Values for Both Forms
61
+ </Button>
62
+ <Button onClick={() => setShowForm1(!showForm1)}>
63
+ Toggle Form 1 {showForm1 ? "Hide" : "Show"}
64
+ </Button>
65
+ <Button onClick={() => setShowForm2(!showForm2)}>
66
+ Toggle Form 2 {showForm2 ? "Hide" : "Show"}
67
+ </Button>
68
+ </Space>
69
+
70
+ <div style={{ display: "flex", gap: 24 }}>
71
+ {showForm1 && (
72
+ <div style={{ flex: 1, border: "1px solid #d9d9d9", padding: 16 }}>
73
+ <Title level={5}>Form 1 (Auto-generated Name)</Title>
74
+ <Text type="secondary">FormName: {form1.formName}</Text>
75
+
76
+ <Form
77
+ form={form1}
78
+ initialValues={{ name: "" }}
79
+ onFinish={(values) => {
80
+ console.log("Form 1 submitted:", values);
81
+ }}
82
+ >
83
+ <Form.Item name="name" label="Name">
84
+ <input
85
+ type="text"
86
+ placeholder="Your name"
87
+ style={{ padding: 8, width: "100%" }}
88
+ />
89
+ </Form.Item>
90
+
91
+ <Button type="primary" htmlType="submit">
92
+ Submit Form 1
93
+ </Button>
94
+ </Form>
95
+ </div>
96
+ )}
97
+
98
+ {showForm2 && (
99
+ <div style={{ flex: 1, border: "1px solid #d9d9d9", padding: 16 }}>
100
+ <Title level={5}>Form 2 (Auto-generated Name)</Title>
101
+ <Text type="secondary">FormName: {form2.formName}</Text>
102
+
103
+ <Form
104
+ form={form2}
105
+ initialValues={{ email: "" }}
106
+ onFinish={(values) => {
107
+ console.log("Form 2 submitted:", values);
108
+ }}
109
+ >
110
+ <Form.Item name="email" label="Email">
111
+ <input
112
+ type="email"
113
+ placeholder="Your email"
114
+ style={{ padding: 8, width: "100%" }}
115
+ />
116
+ </Form.Item>
117
+
118
+ <Button type="primary" htmlType="submit">
119
+ Submit Form 2
120
+ </Button>
121
+ </Form>
122
+ </div>
123
+ )}
124
+ </div>
125
+
126
+ <div style={{ marginTop: 24, padding: 16, background: "#f5f5f5" }}>
127
+ <Title level={5}>Expected Results:</Title>
128
+ <ul>
129
+ <li>✅ Click "Log Form Names" → Console show 2 different UUIDs</li>
130
+ <li>✅ Click "Set Values for Both Forms" → Both forms update correctly</li>
131
+ <li>✅ Toggle forms → Forms can unmount/remount without losing instance</li>
132
+ <li>✅ FormName displays unique UUIDs under each form title</li>
133
+ <li>✅ Both forms work independently without conflicts</li>
134
+ <li>✅ Submit each form → Console logs correct values</li>
135
+ </ul>
136
+ </div>
137
+ </div>
138
+ );
139
+ }
@@ -0,0 +1,203 @@
1
+ import { Button, Space, Typography } from "antd";
2
+ import { useState } from "react";
3
+ import Form from "../../providers/Form";
4
+
5
+ const { Title, Paragraph, Text } = Typography;
6
+
7
+ /**
8
+ * TestCase3: Safe Form Methods
9
+ *
10
+ * Mô tả:
11
+ * - Test feature: Form instance methods có thể gọi an toàn trước khi Form mount
12
+ * - Proxy instance tự động tìm real instance khi Form mount
13
+ * - Warning được log nếu method được gọi khi Form chưa mount
14
+ *
15
+ * Expected Behavior:
16
+ * - Gọi methods trước khi mount → Log warning
17
+ * - Sau khi mount → Methods hoạt động bình thường
18
+ * - Unmount form → Methods lại log warning
19
+ */
20
+
21
+ export default function TestCase3_SafeFormMethods() {
22
+ const [form] = Form.useForm<{ username: string; password: string }>();
23
+ const [formMounted, setFormMounted] = useState(false);
24
+ const [logs, setLogs] = useState<string[]>([]);
25
+
26
+ const addLog = (message: string) => {
27
+ setLogs((prev) => [...prev, `[${new Date().toLocaleTimeString()}] ${message}`]);
28
+ };
29
+
30
+ const handleSetValueBeforeMount = () => {
31
+ addLog("🔴 Calling setFieldValue BEFORE Form mount");
32
+ form.setFieldValue("username", "admin");
33
+ addLog("Check console for warning");
34
+ };
35
+
36
+ const handleSetValueAfterMount = () => {
37
+ addLog("🟢 Calling setFieldValue AFTER Form mount");
38
+ form.setFieldValue("username", "user123");
39
+ form.setFieldValue("password", "secret");
40
+ addLog("Values should be set successfully");
41
+ };
42
+
43
+ const handleGetValue = () => {
44
+ const username = form.getFieldValue("username");
45
+ const password = form.getFieldValue("password");
46
+ addLog(`Get values: username=${username}, password=${password}`);
47
+ };
48
+
49
+ const handleSubmit = () => {
50
+ addLog("🔵 Calling form.submit()");
51
+ form.submit();
52
+ };
53
+
54
+ const handleMountForm = () => {
55
+ setFormMounted(true);
56
+ addLog("✅ Form mounted");
57
+ };
58
+
59
+ const handleUnmountForm = () => {
60
+ setFormMounted(false);
61
+ addLog("❌ Form unmounted");
62
+ };
63
+
64
+ const clearLogs = () => {
65
+ setLogs([]);
66
+ };
67
+
68
+ return (
69
+ <div style={{ padding: 24 }}>
70
+ <Title level={3}>TestCase3: Safe Form Methods</Title>
71
+
72
+ <Paragraph>
73
+ <Text strong>New Feature:</Text> Form methods có thể được gọi an toàn bất cứ lúc nào
74
+ </Paragraph>
75
+
76
+ <Paragraph>
77
+ <Text type="secondary">
78
+ Proxy instance tự động proxy các method calls. Nếu Form chưa mount,
79
+ sẽ log warning thay vì throw error. Khi Form mount, methods hoạt động bình thường.
80
+ </Text>
81
+ </Paragraph>
82
+
83
+ <Space style={{ marginBottom: 16 }} wrap>
84
+ <Button onClick={handleSetValueBeforeMount} danger={!formMounted}>
85
+ Set Value {!formMounted && "(Form Not Mounted)"}
86
+ </Button>
87
+ <Button onClick={handleSetValueAfterMount} type="primary" disabled={!formMounted}>
88
+ Set Value After Mount
89
+ </Button>
90
+ <Button onClick={handleGetValue}>
91
+ Get Values
92
+ </Button>
93
+ <Button onClick={handleSubmit} type="dashed">
94
+ Submit Form
95
+ </Button>
96
+ </Space>
97
+
98
+ <Space style={{ marginBottom: 24 }}>
99
+ {!formMounted ? (
100
+ <Button onClick={handleMountForm} type="primary">
101
+ Mount Form
102
+ </Button>
103
+ ) : (
104
+ <Button onClick={handleUnmountForm} danger>
105
+ Unmount Form
106
+ </Button>
107
+ )}
108
+ <Button onClick={clearLogs}>Clear Logs</Button>
109
+ </Space>
110
+
111
+ <div style={{ display: "flex", gap: 24 }}>
112
+ {/* Logs Panel */}
113
+ <div style={{ flex: 1 }}>
114
+ <Title level={5}>Action Logs:</Title>
115
+ <div
116
+ style={{
117
+ border: "1px solid #d9d9d9",
118
+ padding: 16,
119
+ height: 300,
120
+ overflow: "auto",
121
+ background: "#fafafa",
122
+ fontFamily: "monospace",
123
+ fontSize: 12,
124
+ }}
125
+ >
126
+ {logs.length === 0 ? (
127
+ <Text type="secondary">No logs yet...</Text>
128
+ ) : (
129
+ logs.map((log, index) => (
130
+ <div key={index} style={{ marginBottom: 4 }}>
131
+ {log}
132
+ </div>
133
+ ))
134
+ )}
135
+ </div>
136
+ </div>
137
+
138
+ {/* Form Panel */}
139
+ <div style={{ flex: 1 }}>
140
+ <Title level={5}>Form (Status: {formMounted ? "Mounted" : "Unmounted"}):</Title>
141
+ {formMounted ? (
142
+ <div style={{ border: "1px solid #52c41a", padding: 16 }}>
143
+ <Form
144
+ form={form}
145
+ initialValues={{ username: "", password: "" }}
146
+ onFinish={(values) => {
147
+ addLog(`✅ Form submitted: ${JSON.stringify(values)}`);
148
+ }}
149
+ >
150
+ <Form.Item name="username" label="Username">
151
+ <input
152
+ type="text"
153
+ placeholder="Username"
154
+ style={{ padding: 8, width: "100%" }}
155
+ />
156
+ </Form.Item>
157
+
158
+ <Form.Item name="password" label="Password">
159
+ <input
160
+ type="password"
161
+ placeholder="Password"
162
+ style={{ padding: 8, width: "100%" }}
163
+ />
164
+ </Form.Item>
165
+
166
+ <Button type="primary" htmlType="submit">
167
+ Submit
168
+ </Button>
169
+ </Form>
170
+ </div>
171
+ ) : (
172
+ <div
173
+ style={{
174
+ border: "1px dashed #d9d9d9",
175
+ padding: 16,
176
+ height: 200,
177
+ display: "flex",
178
+ alignItems: "center",
179
+ justifyContent: "center",
180
+ background: "#fafafa",
181
+ }}
182
+ >
183
+ <Text type="secondary">Form is not mounted</Text>
184
+ </div>
185
+ )}
186
+ </div>
187
+ </div>
188
+
189
+ <div style={{ marginTop: 24, padding: 16, background: "#f5f5f5" }}>
190
+ <Title level={5}>Expected Results:</Title>
191
+ <ul>
192
+ <li>✅ Click "Set Value (Form Not Mounted)" → Console shows warning</li>
193
+ <li>✅ Click "Mount Form" → Form appears</li>
194
+ <li>✅ Click "Set Value After Mount" → Form values update without warning</li>
195
+ <li>✅ Click "Get Values" → Shows current values in logs</li>
196
+ <li>✅ Click "Unmount Form" → Form disappears</li>
197
+ <li>✅ Click "Set Value (Form Not Mounted)" again → Warning appears again</li>
198
+ <li>⚠️ Check browser console for detailed warnings</li>
199
+ </ul>
200
+ </div>
201
+ </div>
202
+ );
203
+ }