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.
Files changed (40) hide show
  1. package/CHANGELOG.md +77 -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 +69 -0
  11. package/dist/test/testFormInstance/TestCase4_UseFormStatusFlag.d.ts +15 -0
  12. package/dist/test/testFormInstance/TestCase4_UseFormStatusFlag.js +68 -0
  13. package/dist/test/testFormInstance/TestCase5_UseFormUtils.d.ts +1 -0
  14. package/dist/test/testFormInstance/TestCase5_UseFormUtils.js +70 -0
  15. package/dist/test/testFormInstance/TestCase6_FormWithoutWrapper.d.ts +15 -0
  16. package/dist/test/testFormInstance/TestCase6_FormWithoutWrapper.js +55 -0
  17. package/dist/test/testFormInstance/TestCase7_SetValueInEffect.d.ts +1 -0
  18. package/dist/test/testFormInstance/TestCase7_SetValueInEffect.js +76 -0
  19. package/dist/test/testFormInstance/TestCase8_TypeSafetyImprovements.d.ts +1 -0
  20. package/dist/test/testFormInstance/TestCase8_TypeSafetyImprovements.js +102 -0
  21. package/dist/test/testFormInstance/index.d.ts +14 -0
  22. package/dist/test/testFormInstance/index.js +66 -0
  23. package/dist/test/testSetValue/TestSetValueInEffect.d.ts +3 -0
  24. package/dist/test/testSetValue/TestSetValueInEffect.js +30 -0
  25. package/dist/types/public.d.ts +12 -8
  26. package/package.json +3 -2
  27. package/src/App.tsx +7 -7
  28. package/src/providers/Form.tsx +247 -28
  29. package/src/stores/formStore.ts +3 -1
  30. package/src/test/testFormInstance/TestCase1_FormWithInstance.tsx +116 -0
  31. package/src/test/testFormInstance/TestCase2_AutoGenerateFormName.tsx +142 -0
  32. package/src/test/testFormInstance/TestCase3_SafeFormMethods.tsx +220 -0
  33. package/src/test/testFormInstance/TestCase4_UseFormStatusFlag.tsx +278 -0
  34. package/src/test/testFormInstance/TestCase5_UseFormUtils.tsx +242 -0
  35. package/src/test/testFormInstance/TestCase6_FormWithoutWrapper.tsx +238 -0
  36. package/src/test/testFormInstance/TestCase7_SetValueInEffect.tsx +307 -0
  37. package/src/test/testFormInstance/TestCase8_TypeSafetyImprovements.tsx +390 -0
  38. package/src/test/testFormInstance/index.tsx +155 -0
  39. package/src/test/testSetValue/TestSetValueInEffect.tsx +54 -0
  40. 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&lt;void&gt;</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;
@@ -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<any>;
41
- setFieldValue: (name: keyof T & string, value: any, options?: any) => void;
42
- setFieldValues: (values: Partial<T>, options?: any) => void;
43
- getFieldValue: (name: keyof T & string) => any;
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 & string>,
50
+ names?: Array<keyof T | (string & {})>,
46
51
  ) => Array<{ name: string; value: any }>;
47
- getFieldErrors: () => Record<string, any>;
48
- setFieldFocus: (name: keyof T & string) => void;
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 & string;
61
+ name?: keyof T | (string & {});
55
62
  initialValue?: any;
56
63
  formItemId?: string;
57
64
  rules?: ValidationRule<any, T>[];