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
package/src/utils/obj.util.ts
CHANGED
|
@@ -1,22 +1,162 @@
|
|
|
1
|
-
import { filter, isNil, join } from "lodash";
|
|
1
|
+
import { filter, isNil, isPlainObject, join } from "lodash";
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
/**
|
|
4
|
+
* Lấy tất cả các path đến các leaf nodes (primitive values)
|
|
5
|
+
* Không bao gồm intermediate object/array paths
|
|
6
|
+
*
|
|
7
|
+
* Ví dụ: {user: {name: "John", age: 30}}
|
|
8
|
+
* Kết quả: ["user.name", "user.age"]
|
|
9
|
+
*/
|
|
10
|
+
export function getAllNoneObjStringPath(
|
|
11
|
+
value: any,
|
|
12
|
+
prevPath: string = "",
|
|
13
|
+
): string[] {
|
|
14
|
+
// primitive / function / null / undefined => dừng
|
|
15
|
+
if (
|
|
16
|
+
value === null ||
|
|
17
|
+
value === undefined ||
|
|
18
|
+
typeof value !== "object" ||
|
|
19
|
+
typeof value === "function"
|
|
20
|
+
) {
|
|
21
|
+
return [prevPath];
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// array thì đi sâu
|
|
25
|
+
if (Array.isArray(value)) {
|
|
26
|
+
return value.reduce((prev: string[], item, index) => {
|
|
6
27
|
return [
|
|
7
28
|
...prev,
|
|
8
|
-
|
|
9
29
|
...getAllNoneObjStringPath(
|
|
10
|
-
|
|
30
|
+
item,
|
|
11
31
|
join(
|
|
12
|
-
filter([prevPath,
|
|
13
|
-
"."
|
|
14
|
-
)
|
|
32
|
+
filter([prevPath, String(index)], (v) => !isNil(v) && v !== ""),
|
|
33
|
+
".",
|
|
34
|
+
),
|
|
15
35
|
),
|
|
16
36
|
];
|
|
17
37
|
}, []);
|
|
18
38
|
}
|
|
19
|
-
|
|
39
|
+
|
|
40
|
+
// class instance (non-plain object) => dừng
|
|
41
|
+
if (!isPlainObject(value)) {
|
|
42
|
+
return [prevPath];
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// plain object => đi sâu
|
|
46
|
+
return Object.keys(value).reduce((prev: string[], cur) => {
|
|
47
|
+
return [
|
|
48
|
+
...prev,
|
|
49
|
+
...getAllNoneObjStringPath(
|
|
50
|
+
value[cur],
|
|
51
|
+
join(
|
|
52
|
+
filter([prevPath, cur], (v) => !isNil(v) && v !== ""),
|
|
53
|
+
".",
|
|
54
|
+
),
|
|
55
|
+
),
|
|
56
|
+
];
|
|
57
|
+
}, []);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Lấy tất cả các path bao gồm cả intermediate containers (object/array level)
|
|
62
|
+
* Dùng để detect listener được đăng ký trên plain object, array, hoặc array item level
|
|
63
|
+
*
|
|
64
|
+
* Ví dụ: {user: {name: "John", age: 30}, items: [{id: 1}]}
|
|
65
|
+
* Kết quả: [
|
|
66
|
+
* "user", "user.name", "user.age",
|
|
67
|
+
* "items", "items[0]", "items[0].id"
|
|
68
|
+
* ]
|
|
69
|
+
*/
|
|
70
|
+
export function getAllPathsIncludingContainers(
|
|
71
|
+
value: any,
|
|
72
|
+
prevPath: string = "",
|
|
73
|
+
): string[] {
|
|
74
|
+
const results: string[] = [];
|
|
75
|
+
|
|
76
|
+
// Thêm path hiện tại nếu không rỗng (là container level)
|
|
77
|
+
if (prevPath !== "") {
|
|
78
|
+
results.push(prevPath);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// primitive / function / null / undefined => dừng
|
|
82
|
+
if (
|
|
83
|
+
value === null ||
|
|
84
|
+
value === undefined ||
|
|
85
|
+
typeof value !== "object" ||
|
|
86
|
+
typeof value === "function"
|
|
87
|
+
) {
|
|
88
|
+
return results;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// class instance (non-plain object) => dừng (chỉ thêm path hiện tại)
|
|
92
|
+
if (!isPlainObject(value) && !Array.isArray(value)) {
|
|
93
|
+
return results;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// array => đi sâu vào từng item
|
|
97
|
+
if (Array.isArray(value)) {
|
|
98
|
+
value.forEach((item, index) => {
|
|
99
|
+
const itemPath = join(
|
|
100
|
+
filter([prevPath, String(index)], (v) => !isNil(v) && v !== ""),
|
|
101
|
+
".",
|
|
102
|
+
);
|
|
103
|
+
const nestedPaths = getAllPathsIncludingContainers(item, itemPath);
|
|
104
|
+
results.push(...nestedPaths);
|
|
105
|
+
});
|
|
106
|
+
return results;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// plain object => đi sâu vào từng property
|
|
110
|
+
Object.keys(value).forEach((key) => {
|
|
111
|
+
const nestedPath = join(
|
|
112
|
+
filter([prevPath, key], (v) => !isNil(v) && v !== ""),
|
|
113
|
+
".",
|
|
114
|
+
);
|
|
115
|
+
const nestedPaths = getAllPathsIncludingContainers(value[key], nestedPath);
|
|
116
|
+
results.push(...nestedPaths);
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
return results;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Lấy tất cả paths từ object, dừng khi gặp array
|
|
124
|
+
* Kết quả bao gồm:
|
|
125
|
+
* - Paths đến primitive values (leaf nodes)
|
|
126
|
+
* - Paths đến array (dừng tại array, không đi sâu vào)
|
|
127
|
+
*
|
|
128
|
+
* Ví dụ: {user: {name: "John", items: [1,2,3]}}
|
|
129
|
+
* Kết quả: ["user.name", "user.items"]
|
|
130
|
+
*/
|
|
131
|
+
export function getAllPathsStopAtArray(
|
|
132
|
+
value: any,
|
|
133
|
+
prevPath: string = "",
|
|
134
|
+
): string[] {
|
|
135
|
+
// Primitive values => dừng
|
|
136
|
+
if (
|
|
137
|
+
value === null ||
|
|
138
|
+
value === undefined ||
|
|
139
|
+
typeof value !== "object" ||
|
|
140
|
+
typeof value === "function"
|
|
141
|
+
) {
|
|
142
|
+
return [prevPath];
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// Array => dừng tại đây, trả về path của array
|
|
146
|
+
if (Array.isArray(value)) {
|
|
147
|
+
return [prevPath];
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
// Class instance (non-plain object) => dừng
|
|
151
|
+
if (!isPlainObject(value)) {
|
|
152
|
+
return [prevPath];
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
// Plain object => đi sâu vào
|
|
156
|
+
return Object.keys(value).reduce((prev: string[], key) => {
|
|
157
|
+
const fullPath = prevPath ? `${prevPath}.${key}` : key;
|
|
158
|
+
return [...prev, ...getAllPathsStopAtArray(value[key], fullPath)];
|
|
159
|
+
}, []);
|
|
20
160
|
}
|
|
21
161
|
|
|
22
162
|
export function getAllStringPath(value: any, prevPath: string = "") {
|
|
@@ -26,14 +166,14 @@ export function getAllStringPath(value: any, prevPath: string = "") {
|
|
|
26
166
|
...prev,
|
|
27
167
|
join(
|
|
28
168
|
filter([prevPath, cur], (v) => !isNil(v) && v !== ""),
|
|
29
|
-
"."
|
|
169
|
+
".",
|
|
30
170
|
),
|
|
31
171
|
...getAllStringPath(
|
|
32
172
|
value[cur],
|
|
33
173
|
join(
|
|
34
174
|
filter([prevPath, cur], (v) => !isNil(v) && v !== ""),
|
|
35
|
-
"."
|
|
36
|
-
)
|
|
175
|
+
".",
|
|
176
|
+
),
|
|
37
177
|
),
|
|
38
178
|
];
|
|
39
179
|
}, []);
|