react-form-manage 1.0.8-beta.9 → 1.0.8
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 +173 -4
- package/README.md +8 -4
- package/dist/components/Form/FormCleanUp.js +3 -3
- package/dist/components/Form/FormItem.d.ts +10 -4
- package/dist/components/Form/FormItem.js +52 -14
- package/dist/components/Form/FormList.d.ts +2 -2
- package/dist/components/Form/FormList.js +2 -2
- package/dist/constants/form.d.ts +1 -1
- package/dist/hooks/useFormItemControl.d.ts +8 -3
- package/dist/hooks/useFormItemControl.js +64 -28
- package/dist/hooks/useFormListControl.d.ts +2 -1
- package/dist/hooks/useFormListControl.js +85 -19
- package/dist/index.cjs.d.ts +1 -0
- package/dist/index.d.ts +4 -3
- package/dist/index.esm.d.ts +1 -0
- package/dist/index.js +4 -2
- package/dist/providers/Form.d.ts +15 -2
- package/dist/providers/Form.js +197 -22
- package/dist/stores/formStore.d.ts +44 -4
- package/dist/stores/formStore.js +42 -7
- package/dist/test/CommonTest.d.ts +3 -0
- package/dist/test/CommonTest.js +49 -0
- package/dist/test/TestDialog.d.ts +3 -0
- package/dist/test/TestDialog.js +21 -0
- package/dist/test/TestListener.d.ts +3 -0
- package/dist/test/TestListener.js +17 -0
- package/dist/test/TestNotFormWrapper.d.ts +3 -0
- package/dist/test/TestNotFormWrapper.js +15 -0
- package/dist/test/TestSelect.d.ts +6 -0
- package/dist/test/TestSelect.js +24 -0
- package/dist/test/TestWatchNormalize.d.ts +3 -0
- package/dist/test/TestWatchNormalize.js +23 -0
- package/dist/test/TestWrapperFormItem.d.ts +3 -0
- package/dist/test/TestWrapperFormItem.js +13 -0
- package/dist/test/testSetValue/TestCase10_SetFieldValues_ComplexNested.d.ts +21 -0
- package/dist/test/testSetValue/TestCase10_SetFieldValues_ComplexNested.js +61 -0
- package/dist/test/testSetValue/TestCase1_PlainObjectToPrimitives.d.ts +16 -0
- package/dist/test/testSetValue/TestCase1_PlainObjectToPrimitives.js +18 -0
- package/dist/test/testSetValue/TestCase2_PlainObjectToFormList.d.ts +21 -0
- package/dist/test/testSetValue/TestCase2_PlainObjectToFormList.js +33 -0
- package/dist/test/testSetValue/TestCase3_ArrayNonListenerToPrimitives.d.ts +21 -0
- package/dist/test/testSetValue/TestCase3_ArrayNonListenerToPrimitives.js +26 -0
- package/dist/test/testSetValue/TestCase4_PlainObjectRemovedFields.d.ts +20 -0
- package/dist/test/testSetValue/TestCase4_PlainObjectRemovedFields.js +32 -0
- package/dist/test/testSetValue/TestCase5_FormListRemovedItems.d.ts +22 -0
- package/dist/test/testSetValue/TestCase5_FormListRemovedItems.js +29 -0
- package/dist/test/testSetValue/TestCase6_NestedFormListRemoved.d.ts +28 -0
- package/dist/test/testSetValue/TestCase6_NestedFormListRemoved.js +36 -0
- package/dist/test/testSetValue/TestCase7_SetFieldValues_MixedStructure.d.ts +17 -0
- package/dist/test/testSetValue/TestCase7_SetFieldValues_MixedStructure.js +33 -0
- package/dist/test/testSetValue/TestCase8_SetFieldValues_NestedObject.d.ts +27 -0
- package/dist/test/testSetValue/TestCase8_SetFieldValues_NestedObject.js +57 -0
- package/dist/test/testSetValue/TestCase9_SetFieldValues_MultipleArrays.d.ts +25 -0
- package/dist/test/testSetValue/TestCase9_SetFieldValues_MultipleArrays.js +46 -0
- package/dist/test/testSetValue/index.d.ts +2 -0
- package/dist/test/testSetValue/index.js +28 -0
- package/dist/types/index.d.ts +1 -1
- package/dist/types/public.d.ts +1 -1
- package/dist/utils/obj.util.d.ts +29 -1
- package/dist/utils/obj.util.js +59 -5
- package/package.json +2 -1
- package/src/App.tsx +38 -163
- package/src/DEEP_TRIGGER_LOGIC.md +573 -0
- package/src/components/Form/FormCleanUp.tsx +4 -8
- package/src/components/Form/FormItem.tsx +174 -57
- package/src/components/Form/FormList.tsx +17 -4
- package/src/constants/form.ts +1 -1
- package/src/hooks/useFormItemControl.ts +78 -32
- package/src/hooks/useFormListControl.ts +133 -43
- package/src/index.ts +25 -13
- package/src/main.tsx +6 -1
- package/src/providers/Form.tsx +451 -23
- package/src/stores/formStore.ts +363 -283
- package/src/test/CommonTest.tsx +177 -0
- package/src/test/TestDialog.tsx +52 -0
- package/src/test/TestListener.tsx +21 -0
- package/src/test/TestNotFormWrapper.tsx +43 -0
- package/src/test/TestSelect.tsx +38 -0
- package/src/test/TestWatchNormalize.tsx +32 -0
- package/src/test/TestWrapperFormItem.tsx +34 -0
- package/src/test/testSetValue/TestCase10_SetFieldValues_ComplexNested.tsx +203 -0
- package/src/test/testSetValue/TestCase1_PlainObjectToPrimitives.tsx +72 -0
- package/src/test/testSetValue/TestCase2_PlainObjectToFormList.tsx +114 -0
- package/src/test/testSetValue/TestCase3_ArrayNonListenerToPrimitives.tsx +99 -0
- package/src/test/testSetValue/TestCase4_PlainObjectRemovedFields.tsx +112 -0
- package/src/test/testSetValue/TestCase5_FormListRemovedItems.tsx +119 -0
- package/src/test/testSetValue/TestCase6_NestedFormListRemoved.tsx +185 -0
- package/src/test/testSetValue/TestCase7_SetFieldValues_MixedStructure.tsx +110 -0
- package/src/test/testSetValue/TestCase8_SetFieldValues_NestedObject.tsx +162 -0
- package/src/test/testSetValue/TestCase9_SetFieldValues_MultipleArrays.tsx +169 -0
- package/src/test/testSetValue/index.tsx +100 -0
- package/src/types/index.ts +1 -1
- package/src/types/public.ts +1 -1
- package/src/utils/obj.util.ts +153 -13
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
import { Button, Checkbox, Input } from "antd";
|
|
2
|
+
import { motion } from "framer-motion";
|
|
3
|
+
import FormItem from "../components/Form/FormItem";
|
|
4
|
+
import FormList from "../components/Form/FormList";
|
|
5
|
+
import InputWrapper from "../components/Form/InputWrapper";
|
|
6
|
+
import Form from "../providers/Form";
|
|
7
|
+
|
|
8
|
+
type Props = {};
|
|
9
|
+
|
|
10
|
+
function CommonTest({}: Props) {
|
|
11
|
+
const [form] = Form.useForm("form1");
|
|
12
|
+
|
|
13
|
+
const watchCheckBox = Form.useWatch("checkControlledAfterInit", "form1");
|
|
14
|
+
|
|
15
|
+
return (
|
|
16
|
+
<Form
|
|
17
|
+
initialValues={{
|
|
18
|
+
TestData: "",
|
|
19
|
+
numericCode: "",
|
|
20
|
+
// arr: [{ el: "Item 1" }, { el: "Item 2" }],
|
|
21
|
+
}}
|
|
22
|
+
onFinish={(values) => {
|
|
23
|
+
console.log(values);
|
|
24
|
+
}}
|
|
25
|
+
formName={"form1"}
|
|
26
|
+
// hidden
|
|
27
|
+
>
|
|
28
|
+
<FormItem
|
|
29
|
+
name={"username"}
|
|
30
|
+
rules={[
|
|
31
|
+
{
|
|
32
|
+
required: true,
|
|
33
|
+
message: "Test",
|
|
34
|
+
},
|
|
35
|
+
]}
|
|
36
|
+
initialValue={"283746"}
|
|
37
|
+
// hidden
|
|
38
|
+
>
|
|
39
|
+
<InputWrapper>
|
|
40
|
+
<Input />
|
|
41
|
+
</InputWrapper>
|
|
42
|
+
</FormItem>
|
|
43
|
+
|
|
44
|
+
{/* Numberic test */}
|
|
45
|
+
<FormItem
|
|
46
|
+
name={"numericCode"}
|
|
47
|
+
rules={[
|
|
48
|
+
{ required: true, message: "Vui lòng nhập mã" },
|
|
49
|
+
{
|
|
50
|
+
pattern: /^\d+$/,
|
|
51
|
+
message: "Chỉ cho phép chuỗi số",
|
|
52
|
+
},
|
|
53
|
+
]}
|
|
54
|
+
>
|
|
55
|
+
<InputWrapper>
|
|
56
|
+
<Input placeholder="Mã chỉ gồm số" style={{ width: 200 }} />
|
|
57
|
+
</InputWrapper>
|
|
58
|
+
</FormItem>
|
|
59
|
+
|
|
60
|
+
{/* Motion Test */}
|
|
61
|
+
<motion.div
|
|
62
|
+
initial={{ opacity: 0 }}
|
|
63
|
+
animate={{ opacity: 1 }}
|
|
64
|
+
exit={{ opacity: 0 }}
|
|
65
|
+
transition={{ duration: 1 }}
|
|
66
|
+
>
|
|
67
|
+
<FormItem name="motionTest" controlAfterInit initialValue={"1234134"}>
|
|
68
|
+
<InputWrapper>
|
|
69
|
+
<Input placeholder="Motion Test" style={{ width: 200 }} />
|
|
70
|
+
</InputWrapper>
|
|
71
|
+
</FormItem>
|
|
72
|
+
</motion.div>
|
|
73
|
+
<FormList
|
|
74
|
+
initialValues={[
|
|
75
|
+
{
|
|
76
|
+
el: "sdfsdf",
|
|
77
|
+
d: { child: "Test Child" },
|
|
78
|
+
},
|
|
79
|
+
]}
|
|
80
|
+
name="arr"
|
|
81
|
+
>
|
|
82
|
+
{(fields, { add, remove, move }) => (
|
|
83
|
+
<div>
|
|
84
|
+
{fields.map((field, index) => (
|
|
85
|
+
<div key={field.key} style={{ marginBottom: 8 }}>
|
|
86
|
+
<FormItem name={`${field.name}.el`} initialValue={"Chém gió"}>
|
|
87
|
+
<InputWrapper>
|
|
88
|
+
<Input placeholder="Item value" style={{ width: 200 }} />
|
|
89
|
+
</InputWrapper>
|
|
90
|
+
</FormItem>
|
|
91
|
+
<FormItem
|
|
92
|
+
name={`${field.name}.d.child`}
|
|
93
|
+
initialValue={"Con của item"}
|
|
94
|
+
>
|
|
95
|
+
<InputWrapper>
|
|
96
|
+
<Input placeholder="Item value" style={{ width: 200 }} />
|
|
97
|
+
</InputWrapper>
|
|
98
|
+
</FormItem>
|
|
99
|
+
<Button
|
|
100
|
+
onClick={() => remove({ index })}
|
|
101
|
+
style={{ marginLeft: 8 }}
|
|
102
|
+
>
|
|
103
|
+
Remove
|
|
104
|
+
</Button>
|
|
105
|
+
{index > 0 && (
|
|
106
|
+
<Button
|
|
107
|
+
onClick={() => move({ from: index, to: index - 1 })}
|
|
108
|
+
style={{ marginLeft: 8 }}
|
|
109
|
+
>
|
|
110
|
+
Move Up
|
|
111
|
+
</Button>
|
|
112
|
+
)}
|
|
113
|
+
{index < fields.length - 1 && (
|
|
114
|
+
<Button
|
|
115
|
+
onClick={() => move({ from: index, to: index + 1 })}
|
|
116
|
+
style={{ marginLeft: 8 }}
|
|
117
|
+
>
|
|
118
|
+
Move Down
|
|
119
|
+
</Button>
|
|
120
|
+
)}
|
|
121
|
+
</div>
|
|
122
|
+
))}
|
|
123
|
+
<Button onClick={() => add(fields.length)}>Add Item</Button>
|
|
124
|
+
</div>
|
|
125
|
+
)}
|
|
126
|
+
</FormList>
|
|
127
|
+
<Button
|
|
128
|
+
onClick={() => {
|
|
129
|
+
form?.setFieldValue("arr", [
|
|
130
|
+
{ el: "Set Item 1" },
|
|
131
|
+
{ el: "Set Item 2" },
|
|
132
|
+
{ el: "Set Item 3" },
|
|
133
|
+
]);
|
|
134
|
+
}}
|
|
135
|
+
>
|
|
136
|
+
Test set array list value
|
|
137
|
+
</Button>
|
|
138
|
+
<motion.div
|
|
139
|
+
initial={{ opacity: 0 }}
|
|
140
|
+
animate={{ opacity: 1 }}
|
|
141
|
+
exit={{ opacity: 0 }}
|
|
142
|
+
transition={{ duration: 1.5 }}
|
|
143
|
+
>
|
|
144
|
+
<Form.Item
|
|
145
|
+
valuePropName="checked"
|
|
146
|
+
getValueFromEvent={(_, checked) => checked}
|
|
147
|
+
name="checkControlledAfterInit"
|
|
148
|
+
controlAfterInit={true}
|
|
149
|
+
initialValue={true}
|
|
150
|
+
hidden
|
|
151
|
+
>
|
|
152
|
+
<Checkbox />
|
|
153
|
+
</Form.Item>
|
|
154
|
+
</motion.div>
|
|
155
|
+
{/* <TestFormWatch /> */}
|
|
156
|
+
<Button
|
|
157
|
+
onClick={() => {
|
|
158
|
+
const current = form?.getFieldValue("checkControlledAfterInit");
|
|
159
|
+
console.log("Toggle controlled after init: ", current);
|
|
160
|
+
form?.setFieldValue("checkControlledAfterInit", !current);
|
|
161
|
+
}}
|
|
162
|
+
>
|
|
163
|
+
Toggle
|
|
164
|
+
</Button>
|
|
165
|
+
<Button htmlType="submit">Submit</Button>
|
|
166
|
+
<Button
|
|
167
|
+
onClick={() => {
|
|
168
|
+
form?.resetFields?.();
|
|
169
|
+
}}
|
|
170
|
+
>
|
|
171
|
+
Reset
|
|
172
|
+
</Button>
|
|
173
|
+
</Form>
|
|
174
|
+
);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
export default CommonTest;
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Button,
|
|
3
|
+
Dialog,
|
|
4
|
+
DialogContent,
|
|
5
|
+
DialogContentText,
|
|
6
|
+
DialogTitle,
|
|
7
|
+
TextField,
|
|
8
|
+
} from "@mui/material";
|
|
9
|
+
import { Box } from "@mui/system";
|
|
10
|
+
import { useToggle } from "minh-custom-hooks-release";
|
|
11
|
+
import FormItem from "../components/Form/FormItem";
|
|
12
|
+
import TestSelect from "./TestSelect";
|
|
13
|
+
|
|
14
|
+
type Props = {};
|
|
15
|
+
|
|
16
|
+
function TestDialog({}: Props) {
|
|
17
|
+
const { state: open, toggle } = useToggle();
|
|
18
|
+
return (
|
|
19
|
+
<Box>
|
|
20
|
+
<Dialog open={open} onClose={toggle}>
|
|
21
|
+
<DialogTitle>Test Dialog</DialogTitle>
|
|
22
|
+
<DialogContent>
|
|
23
|
+
<DialogContentText>This is a test dialog.</DialogContentText>
|
|
24
|
+
<FormItem
|
|
25
|
+
rules={[
|
|
26
|
+
{
|
|
27
|
+
handler(value) {
|
|
28
|
+
console.log("Validating in dialog: ", value);
|
|
29
|
+
return Boolean(value);
|
|
30
|
+
},
|
|
31
|
+
message: "Testt",
|
|
32
|
+
},
|
|
33
|
+
]}
|
|
34
|
+
controlAfterInit
|
|
35
|
+
initialValue={null}
|
|
36
|
+
name="testSelectInsideDialog"
|
|
37
|
+
>
|
|
38
|
+
<TestSelect />
|
|
39
|
+
</FormItem>
|
|
40
|
+
<FormItem controlAfterInit initialValue={""} name="anotherField">
|
|
41
|
+
<TextField />
|
|
42
|
+
</FormItem>
|
|
43
|
+
</DialogContent>
|
|
44
|
+
</Dialog>
|
|
45
|
+
<Button variant="contained" onClick={toggle}>
|
|
46
|
+
Open Test Dialog
|
|
47
|
+
</Button>
|
|
48
|
+
</Box>
|
|
49
|
+
);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export default TestDialog;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { cloneDeep } from "lodash";
|
|
2
|
+
import { useEffect } from "react";
|
|
3
|
+
import { useShallow } from "zustand/react/shallow";
|
|
4
|
+
import { useFormStore } from "../stores/formStore";
|
|
5
|
+
|
|
6
|
+
type Props = {};
|
|
7
|
+
|
|
8
|
+
function TestListener({}: Props) {
|
|
9
|
+
const { listeners } = useFormStore(
|
|
10
|
+
useShallow((state) => ({
|
|
11
|
+
listeners: state.listeners,
|
|
12
|
+
})),
|
|
13
|
+
);
|
|
14
|
+
|
|
15
|
+
useEffect(() => {
|
|
16
|
+
console.log("Listeners updated: ", cloneDeep(listeners));
|
|
17
|
+
}, [listeners]);
|
|
18
|
+
return <div>TestListener</div>;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export default TestListener;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { Button, Input } from "antd";
|
|
2
|
+
|
|
3
|
+
type Props = {};
|
|
4
|
+
|
|
5
|
+
function TestNotFormWrapper({}: Props) {
|
|
6
|
+
return (
|
|
7
|
+
<div
|
|
8
|
+
onSubmit={(e) => {
|
|
9
|
+
e.preventDefault();
|
|
10
|
+
console.log("Div Submit");
|
|
11
|
+
}}
|
|
12
|
+
>
|
|
13
|
+
<form
|
|
14
|
+
id="not-form"
|
|
15
|
+
onSubmit={(e) => {
|
|
16
|
+
e.preventDefault();
|
|
17
|
+
console.log("Form Submit");
|
|
18
|
+
}}
|
|
19
|
+
>
|
|
20
|
+
<div
|
|
21
|
+
id="child-form"
|
|
22
|
+
onSubmit={(e) => {
|
|
23
|
+
e.preventDefault();
|
|
24
|
+
|
|
25
|
+
console.log("Child Form Submit");
|
|
26
|
+
}}
|
|
27
|
+
>
|
|
28
|
+
<Input />
|
|
29
|
+
<Button htmlType="submit" form="child-form">
|
|
30
|
+
Child Form Submit
|
|
31
|
+
</Button>
|
|
32
|
+
</div>
|
|
33
|
+
<Input />
|
|
34
|
+
|
|
35
|
+
<Button htmlType="submit" form="not-form">
|
|
36
|
+
Submit
|
|
37
|
+
</Button>
|
|
38
|
+
</form>
|
|
39
|
+
</div>
|
|
40
|
+
);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export default TestNotFormWrapper;
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { Autocomplete, TextField } from "@mui/material";
|
|
2
|
+
|
|
3
|
+
type Props = {
|
|
4
|
+
value?: any;
|
|
5
|
+
onChange?: (value: any) => void;
|
|
6
|
+
};
|
|
7
|
+
|
|
8
|
+
function TestSelect({ value = null, onChange }: Props) {
|
|
9
|
+
return (
|
|
10
|
+
<Autocomplete
|
|
11
|
+
value={value}
|
|
12
|
+
onChange={(_, newValue) => {
|
|
13
|
+
onChange?.(newValue);
|
|
14
|
+
}}
|
|
15
|
+
renderInput={(params) => <TextField {...params} />}
|
|
16
|
+
options={[
|
|
17
|
+
{
|
|
18
|
+
value: "option1",
|
|
19
|
+
label: "Option 1",
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
value: "option2",
|
|
23
|
+
label: "Option 2",
|
|
24
|
+
},
|
|
25
|
+
]}
|
|
26
|
+
getOptionKey={(o) => {
|
|
27
|
+
// console.log("Option get key: ", o);
|
|
28
|
+
return o?.value;
|
|
29
|
+
}}
|
|
30
|
+
getOptionLabel={(o) => {
|
|
31
|
+
// console.log("Option get label: ", o);
|
|
32
|
+
return o?.label;
|
|
33
|
+
}}
|
|
34
|
+
/>
|
|
35
|
+
);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export default TestSelect;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { Input } from "antd";
|
|
2
|
+
import React from "react";
|
|
3
|
+
import Form from "../providers/Form";
|
|
4
|
+
|
|
5
|
+
type Props = {};
|
|
6
|
+
|
|
7
|
+
function TestWatchNormalize({}: Props) {
|
|
8
|
+
const normalizeData = Form.useWatchNormalized({
|
|
9
|
+
name: "normalizeItem",
|
|
10
|
+
formNameOrFormInstance: "testNormalize",
|
|
11
|
+
normalizeFn: (value) => {
|
|
12
|
+
if (typeof value === "string") {
|
|
13
|
+
return value.toUpperCase();
|
|
14
|
+
}
|
|
15
|
+
return value;
|
|
16
|
+
},
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
React.useEffect(() => {
|
|
20
|
+
console.log("Normalized Data: ", normalizeData);
|
|
21
|
+
}, [normalizeData]);
|
|
22
|
+
return (
|
|
23
|
+
<Form formName="testNormalize">
|
|
24
|
+
Test Watch Normalize
|
|
25
|
+
<Form.Item name="normalizeItem">
|
|
26
|
+
<Input />
|
|
27
|
+
</Form.Item>
|
|
28
|
+
</Form>
|
|
29
|
+
);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export default TestWatchNormalize;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { Button, Col, Input, Row } from "antd";
|
|
2
|
+
import { useToggle } from "minh-custom-hooks-release";
|
|
3
|
+
import Form from "../providers/Form";
|
|
4
|
+
|
|
5
|
+
type Props = {};
|
|
6
|
+
|
|
7
|
+
function TestWrapperFormItem({}: Props) {
|
|
8
|
+
const { state, toggle } = useToggle(false);
|
|
9
|
+
return (
|
|
10
|
+
<Form
|
|
11
|
+
onFinish={(values, all) => {
|
|
12
|
+
console.log(values, all);
|
|
13
|
+
}}
|
|
14
|
+
formName="testWrapper"
|
|
15
|
+
>
|
|
16
|
+
<Row>
|
|
17
|
+
<Form.Item
|
|
18
|
+
hidden={!state}
|
|
19
|
+
name="test"
|
|
20
|
+
collectOnHidden={false}
|
|
21
|
+
initialValue={"test"}
|
|
22
|
+
Component={Col}
|
|
23
|
+
xs={12}
|
|
24
|
+
>
|
|
25
|
+
<Input />
|
|
26
|
+
</Form.Item>
|
|
27
|
+
</Row>
|
|
28
|
+
<Button htmlType="submit">Submit</Button>
|
|
29
|
+
<Button onClick={toggle}>{state ? "Off" : "On"}</Button>
|
|
30
|
+
</Form>
|
|
31
|
+
);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export default TestWrapperFormItem;
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
import { Box } from "@mui/material";
|
|
2
|
+
import { Button, Input, Typography } from "antd";
|
|
3
|
+
import FormList from "../../components/Form/FormList";
|
|
4
|
+
import Form from "../../providers/Form";
|
|
5
|
+
|
|
6
|
+
type Props = {};
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Test Case 10: setFieldValues với Complex Nested Structure
|
|
10
|
+
*
|
|
11
|
+
* Cấu trúc phức tạp:
|
|
12
|
+
* - config.appName (string)
|
|
13
|
+
* - config.version (string)
|
|
14
|
+
* - config.features (array) - deepTrigger
|
|
15
|
+
* - users (FormList array) - deepTrigger
|
|
16
|
+
* - users.0.name (string)
|
|
17
|
+
* - users.0.roles (array) - nested array trong FormList
|
|
18
|
+
*
|
|
19
|
+
* Test: setFieldValues với structure phức tạp nhiều cấp
|
|
20
|
+
*
|
|
21
|
+
* Kỳ vọng:
|
|
22
|
+
* - Primitives trigger onChange
|
|
23
|
+
* - Arrays ở mọi level đều gọi handleDeepTriggerSet
|
|
24
|
+
* - Nested arrays trong FormList được xử lý đúng
|
|
25
|
+
*/
|
|
26
|
+
function TestCase10_SetFieldValues_ComplexNested({}: Props) {
|
|
27
|
+
const [form] = Form.useForm("testCase10");
|
|
28
|
+
|
|
29
|
+
const handleTestSetFieldValues = () => {
|
|
30
|
+
form?.setFieldValues({
|
|
31
|
+
config: {
|
|
32
|
+
appName: "My App",
|
|
33
|
+
version: "1.0.0",
|
|
34
|
+
features: ["auth", "api", "ui"],
|
|
35
|
+
},
|
|
36
|
+
users: [
|
|
37
|
+
{ name: "John", roles: ["admin", "editor"] },
|
|
38
|
+
{ name: "Jane", roles: ["viewer"] },
|
|
39
|
+
],
|
|
40
|
+
});
|
|
41
|
+
console.log("✅ Called setFieldValues with complex nested structure");
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
const handleTestUpdateStructure = () => {
|
|
45
|
+
form?.setFieldValues({
|
|
46
|
+
config: {
|
|
47
|
+
appName: "Updated App",
|
|
48
|
+
version: "2.0.0",
|
|
49
|
+
features: ["auth", "api"], // removed "ui"
|
|
50
|
+
},
|
|
51
|
+
users: [
|
|
52
|
+
{ name: "John", roles: ["admin"] }, // removed editor role + removed Jane user
|
|
53
|
+
],
|
|
54
|
+
});
|
|
55
|
+
console.log("✅ Updated structure (cleanup nested arrays)");
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
const handleClear = () => {
|
|
59
|
+
form?.setFieldValues({
|
|
60
|
+
config: {
|
|
61
|
+
appName: "",
|
|
62
|
+
version: "",
|
|
63
|
+
features: [],
|
|
64
|
+
},
|
|
65
|
+
users: [],
|
|
66
|
+
});
|
|
67
|
+
console.log("✅ Cleared all fields");
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
return (
|
|
71
|
+
<Box sx={{ p: 2 }}>
|
|
72
|
+
<Typography.Title level={4}>
|
|
73
|
+
Test Case 10: setFieldValues - Complex Nested
|
|
74
|
+
</Typography.Title>
|
|
75
|
+
<Typography.Paragraph>
|
|
76
|
+
Test setFieldValues với structure phức tạp: nested objects + arrays +
|
|
77
|
+
FormList
|
|
78
|
+
</Typography.Paragraph>
|
|
79
|
+
|
|
80
|
+
<Form formName="testCase10">
|
|
81
|
+
{/* Config section */}
|
|
82
|
+
<Box sx={{ border: "2px solid #1890ff", p: 2, mb: 2, borderRadius: 1 }}>
|
|
83
|
+
<Typography.Text strong style={{ fontSize: 16 }}>
|
|
84
|
+
Config
|
|
85
|
+
</Typography.Text>
|
|
86
|
+
|
|
87
|
+
<Form.Item name="config.appName" label="App Name">
|
|
88
|
+
<Input placeholder="Enter app name" />
|
|
89
|
+
</Form.Item>
|
|
90
|
+
|
|
91
|
+
<Form.Item name="config.version" label="Version">
|
|
92
|
+
<Input placeholder="Enter version" />
|
|
93
|
+
</Form.Item>
|
|
94
|
+
|
|
95
|
+
<Box sx={{ mt: 1 }}>
|
|
96
|
+
<Typography.Text>Features (Array):</Typography.Text>
|
|
97
|
+
<Form.Item name="config.features.0">
|
|
98
|
+
<Input placeholder="Feature 1" />
|
|
99
|
+
</Form.Item>
|
|
100
|
+
<Form.Item name="config.features.1">
|
|
101
|
+
<Input placeholder="Feature 2" />
|
|
102
|
+
</Form.Item>
|
|
103
|
+
<Form.Item name="config.features.2">
|
|
104
|
+
<Input placeholder="Feature 3" />
|
|
105
|
+
</Form.Item>
|
|
106
|
+
</Box>
|
|
107
|
+
</Box>
|
|
108
|
+
|
|
109
|
+
{/* Users FormList with nested roles array */}
|
|
110
|
+
<Box sx={{ border: "2px solid #52c41a", p: 2, mb: 2, borderRadius: 1 }}>
|
|
111
|
+
<Typography.Text strong style={{ fontSize: 16 }}>
|
|
112
|
+
Users (FormList)
|
|
113
|
+
</Typography.Text>
|
|
114
|
+
|
|
115
|
+
<FormList name="users">
|
|
116
|
+
{(fields, { add, remove }) => (
|
|
117
|
+
<Box>
|
|
118
|
+
{fields.map((field, index) => (
|
|
119
|
+
<Box
|
|
120
|
+
key={field.key}
|
|
121
|
+
sx={{
|
|
122
|
+
border: "1px dashed #52c41a",
|
|
123
|
+
p: 1,
|
|
124
|
+
mb: 1,
|
|
125
|
+
borderRadius: 1,
|
|
126
|
+
}}
|
|
127
|
+
>
|
|
128
|
+
<Typography.Text>User {index + 1}</Typography.Text>
|
|
129
|
+
|
|
130
|
+
<Form.Item name={`users.${index}.name`} label="Name">
|
|
131
|
+
<Input placeholder="User name" />
|
|
132
|
+
</Form.Item>
|
|
133
|
+
|
|
134
|
+
<Box
|
|
135
|
+
sx={{ ml: 2, bgcolor: "#f6ffed", p: 1, borderRadius: 1 }}
|
|
136
|
+
>
|
|
137
|
+
<Typography.Text>Roles (Nested Array):</Typography.Text>
|
|
138
|
+
<Form.Item name={`users.${index}.roles.0`}>
|
|
139
|
+
<Input placeholder="Role 1" />
|
|
140
|
+
</Form.Item>
|
|
141
|
+
<Form.Item name={`users.${index}.roles.1`}>
|
|
142
|
+
<Input placeholder="Role 2" />
|
|
143
|
+
</Form.Item>
|
|
144
|
+
</Box>
|
|
145
|
+
|
|
146
|
+
<Button
|
|
147
|
+
danger
|
|
148
|
+
size="small"
|
|
149
|
+
onClick={() => remove({ key: field.key })}
|
|
150
|
+
>
|
|
151
|
+
Remove User
|
|
152
|
+
</Button>
|
|
153
|
+
</Box>
|
|
154
|
+
))}
|
|
155
|
+
<Button type="dashed" onClick={() => add()}>
|
|
156
|
+
Add User
|
|
157
|
+
</Button>
|
|
158
|
+
</Box>
|
|
159
|
+
)}
|
|
160
|
+
</FormList>
|
|
161
|
+
</Box>
|
|
162
|
+
|
|
163
|
+
<Box sx={{ mt: 2, display: "flex", gap: 2, flexDirection: "column" }}>
|
|
164
|
+
<Button type="primary" onClick={handleTestSetFieldValues}>
|
|
165
|
+
1. Set Complex Structure
|
|
166
|
+
</Button>
|
|
167
|
+
<Button onClick={handleTestUpdateStructure}>
|
|
168
|
+
2. Update with Cleanup
|
|
169
|
+
</Button>
|
|
170
|
+
<Button danger onClick={handleClear}>
|
|
171
|
+
3. Clear All
|
|
172
|
+
</Button>
|
|
173
|
+
</Box>
|
|
174
|
+
|
|
175
|
+
<Box
|
|
176
|
+
sx={{
|
|
177
|
+
mt: 2,
|
|
178
|
+
p: 2,
|
|
179
|
+
bgcolor: "#e6fffb",
|
|
180
|
+
border: "1px solid #13c2c2",
|
|
181
|
+
borderRadius: 1,
|
|
182
|
+
}}
|
|
183
|
+
>
|
|
184
|
+
<Typography.Text strong>Expected Behavior:</Typography.Text>
|
|
185
|
+
<Typography.Paragraph>
|
|
186
|
+
<strong>setFieldValues logic:</strong>
|
|
187
|
+
<br />- Traverse object, dừng tại mỗi array
|
|
188
|
+
<br />- Primitives: trigger onChange
|
|
189
|
+
<br />- Arrays: gọi handleDeepTriggerSet
|
|
190
|
+
<br />
|
|
191
|
+
<br />
|
|
192
|
+
<strong>Update with Cleanup:</strong>
|
|
193
|
+
<br />- config.features.2 → undefined (removed)
|
|
194
|
+
<br />- users.1 → undefined (Jane removed)
|
|
195
|
+
<br />- users.0.roles.1 → undefined (editor removed)
|
|
196
|
+
</Typography.Paragraph>
|
|
197
|
+
</Box>
|
|
198
|
+
</Form>
|
|
199
|
+
</Box>
|
|
200
|
+
);
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
export default TestCase10_SetFieldValues_ComplexNested;
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { Box } from "@mui/material";
|
|
2
|
+
import { Button, Input, Typography } from "antd";
|
|
3
|
+
import Form from "../../providers/Form";
|
|
4
|
+
|
|
5
|
+
type Props = {};
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Test Case 1: Plain Object → Primitive Listeners
|
|
9
|
+
*
|
|
10
|
+
* Cấu trúc:
|
|
11
|
+
* - user.name (string)
|
|
12
|
+
* - user.age (number)
|
|
13
|
+
*
|
|
14
|
+
* Test: setFieldValue("user", {name: "John", age: 30}, {deepTrigger: true})
|
|
15
|
+
* Kỳ vọng:
|
|
16
|
+
* - Trigger "user" listener (nếu có)
|
|
17
|
+
* - Trigger "user.name" listener
|
|
18
|
+
* - Trigger "user.age" listener
|
|
19
|
+
*/
|
|
20
|
+
function TestCase1_PlainObjectToPrimitives({}: Props) {
|
|
21
|
+
const [form] = Form.useForm("testCase1");
|
|
22
|
+
|
|
23
|
+
const handleTestDeepTrigger = () => {
|
|
24
|
+
form?.setFieldValue(
|
|
25
|
+
"user",
|
|
26
|
+
{ name: "John Doe", age: 30 },
|
|
27
|
+
{ deepTrigger: true },
|
|
28
|
+
);
|
|
29
|
+
console.log("✅ Called setFieldValue with deepTrigger=true");
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
const handleTestNormalSet = () => {
|
|
33
|
+
form?.setFieldValue("user", { name: "Jane Doe", age: 25 });
|
|
34
|
+
console.log("✅ Called setFieldValue without deepTrigger");
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
return (
|
|
38
|
+
<Box sx={{ p: 2 }}>
|
|
39
|
+
<Typography.Title level={4}>
|
|
40
|
+
Test Case 1: Plain Object → Primitive Listeners
|
|
41
|
+
</Typography.Title>
|
|
42
|
+
<Typography.Paragraph>
|
|
43
|
+
Test setFieldValue("user", {"{name, age}"}) với deepTrigger=true
|
|
44
|
+
</Typography.Paragraph>
|
|
45
|
+
|
|
46
|
+
<Form formName="testCase1">
|
|
47
|
+
{/* User object listener - should be triggered */}
|
|
48
|
+
<Form.Item name="user">
|
|
49
|
+
<Input placeholder="User Object (JSON)" disabled />
|
|
50
|
+
</Form.Item>
|
|
51
|
+
|
|
52
|
+
{/* Nested primitive listeners */}
|
|
53
|
+
<Form.Item name="user.name" label="Name">
|
|
54
|
+
<Input placeholder="Enter name" />
|
|
55
|
+
</Form.Item>
|
|
56
|
+
|
|
57
|
+
<Form.Item name="user.age" label="Age">
|
|
58
|
+
<Input type="number" placeholder="Enter age" />
|
|
59
|
+
</Form.Item>
|
|
60
|
+
|
|
61
|
+
<Box sx={{ mt: 2, display: "flex", gap: 2 }}>
|
|
62
|
+
<Button type="primary" onClick={handleTestDeepTrigger}>
|
|
63
|
+
Test Deep Trigger
|
|
64
|
+
</Button>
|
|
65
|
+
<Button onClick={handleTestNormalSet}>Test Normal Set</Button>
|
|
66
|
+
</Box>
|
|
67
|
+
</Form>
|
|
68
|
+
</Box>
|
|
69
|
+
);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export default TestCase1_PlainObjectToPrimitives;
|