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.
Files changed (94) hide show
  1. package/CHANGELOG.md +173 -4
  2. package/README.md +8 -4
  3. package/dist/components/Form/FormCleanUp.js +3 -3
  4. package/dist/components/Form/FormItem.d.ts +10 -4
  5. package/dist/components/Form/FormItem.js +52 -14
  6. package/dist/components/Form/FormList.d.ts +2 -2
  7. package/dist/components/Form/FormList.js +2 -2
  8. package/dist/constants/form.d.ts +1 -1
  9. package/dist/hooks/useFormItemControl.d.ts +8 -3
  10. package/dist/hooks/useFormItemControl.js +64 -28
  11. package/dist/hooks/useFormListControl.d.ts +2 -1
  12. package/dist/hooks/useFormListControl.js +85 -19
  13. package/dist/index.cjs.d.ts +1 -0
  14. package/dist/index.d.ts +4 -3
  15. package/dist/index.esm.d.ts +1 -0
  16. package/dist/index.js +4 -2
  17. package/dist/providers/Form.d.ts +15 -2
  18. package/dist/providers/Form.js +197 -22
  19. package/dist/stores/formStore.d.ts +44 -4
  20. package/dist/stores/formStore.js +42 -7
  21. package/dist/test/CommonTest.d.ts +3 -0
  22. package/dist/test/CommonTest.js +49 -0
  23. package/dist/test/TestDialog.d.ts +3 -0
  24. package/dist/test/TestDialog.js +21 -0
  25. package/dist/test/TestListener.d.ts +3 -0
  26. package/dist/test/TestListener.js +17 -0
  27. package/dist/test/TestNotFormWrapper.d.ts +3 -0
  28. package/dist/test/TestNotFormWrapper.js +15 -0
  29. package/dist/test/TestSelect.d.ts +6 -0
  30. package/dist/test/TestSelect.js +24 -0
  31. package/dist/test/TestWatchNormalize.d.ts +3 -0
  32. package/dist/test/TestWatchNormalize.js +23 -0
  33. package/dist/test/TestWrapperFormItem.d.ts +3 -0
  34. package/dist/test/TestWrapperFormItem.js +13 -0
  35. package/dist/test/testSetValue/TestCase10_SetFieldValues_ComplexNested.d.ts +21 -0
  36. package/dist/test/testSetValue/TestCase10_SetFieldValues_ComplexNested.js +61 -0
  37. package/dist/test/testSetValue/TestCase1_PlainObjectToPrimitives.d.ts +16 -0
  38. package/dist/test/testSetValue/TestCase1_PlainObjectToPrimitives.js +18 -0
  39. package/dist/test/testSetValue/TestCase2_PlainObjectToFormList.d.ts +21 -0
  40. package/dist/test/testSetValue/TestCase2_PlainObjectToFormList.js +33 -0
  41. package/dist/test/testSetValue/TestCase3_ArrayNonListenerToPrimitives.d.ts +21 -0
  42. package/dist/test/testSetValue/TestCase3_ArrayNonListenerToPrimitives.js +26 -0
  43. package/dist/test/testSetValue/TestCase4_PlainObjectRemovedFields.d.ts +20 -0
  44. package/dist/test/testSetValue/TestCase4_PlainObjectRemovedFields.js +32 -0
  45. package/dist/test/testSetValue/TestCase5_FormListRemovedItems.d.ts +22 -0
  46. package/dist/test/testSetValue/TestCase5_FormListRemovedItems.js +29 -0
  47. package/dist/test/testSetValue/TestCase6_NestedFormListRemoved.d.ts +28 -0
  48. package/dist/test/testSetValue/TestCase6_NestedFormListRemoved.js +36 -0
  49. package/dist/test/testSetValue/TestCase7_SetFieldValues_MixedStructure.d.ts +17 -0
  50. package/dist/test/testSetValue/TestCase7_SetFieldValues_MixedStructure.js +33 -0
  51. package/dist/test/testSetValue/TestCase8_SetFieldValues_NestedObject.d.ts +27 -0
  52. package/dist/test/testSetValue/TestCase8_SetFieldValues_NestedObject.js +57 -0
  53. package/dist/test/testSetValue/TestCase9_SetFieldValues_MultipleArrays.d.ts +25 -0
  54. package/dist/test/testSetValue/TestCase9_SetFieldValues_MultipleArrays.js +46 -0
  55. package/dist/test/testSetValue/index.d.ts +2 -0
  56. package/dist/test/testSetValue/index.js +28 -0
  57. package/dist/types/index.d.ts +1 -1
  58. package/dist/types/public.d.ts +1 -1
  59. package/dist/utils/obj.util.d.ts +29 -1
  60. package/dist/utils/obj.util.js +59 -5
  61. package/package.json +2 -1
  62. package/src/App.tsx +38 -163
  63. package/src/DEEP_TRIGGER_LOGIC.md +573 -0
  64. package/src/components/Form/FormCleanUp.tsx +4 -8
  65. package/src/components/Form/FormItem.tsx +174 -57
  66. package/src/components/Form/FormList.tsx +17 -4
  67. package/src/constants/form.ts +1 -1
  68. package/src/hooks/useFormItemControl.ts +78 -32
  69. package/src/hooks/useFormListControl.ts +133 -43
  70. package/src/index.ts +25 -13
  71. package/src/main.tsx +6 -1
  72. package/src/providers/Form.tsx +451 -23
  73. package/src/stores/formStore.ts +363 -283
  74. package/src/test/CommonTest.tsx +177 -0
  75. package/src/test/TestDialog.tsx +52 -0
  76. package/src/test/TestListener.tsx +21 -0
  77. package/src/test/TestNotFormWrapper.tsx +43 -0
  78. package/src/test/TestSelect.tsx +38 -0
  79. package/src/test/TestWatchNormalize.tsx +32 -0
  80. package/src/test/TestWrapperFormItem.tsx +34 -0
  81. package/src/test/testSetValue/TestCase10_SetFieldValues_ComplexNested.tsx +203 -0
  82. package/src/test/testSetValue/TestCase1_PlainObjectToPrimitives.tsx +72 -0
  83. package/src/test/testSetValue/TestCase2_PlainObjectToFormList.tsx +114 -0
  84. package/src/test/testSetValue/TestCase3_ArrayNonListenerToPrimitives.tsx +99 -0
  85. package/src/test/testSetValue/TestCase4_PlainObjectRemovedFields.tsx +112 -0
  86. package/src/test/testSetValue/TestCase5_FormListRemovedItems.tsx +119 -0
  87. package/src/test/testSetValue/TestCase6_NestedFormListRemoved.tsx +185 -0
  88. package/src/test/testSetValue/TestCase7_SetFieldValues_MixedStructure.tsx +110 -0
  89. package/src/test/testSetValue/TestCase8_SetFieldValues_NestedObject.tsx +162 -0
  90. package/src/test/testSetValue/TestCase9_SetFieldValues_MultipleArrays.tsx +169 -0
  91. package/src/test/testSetValue/index.tsx +100 -0
  92. package/src/types/index.ts +1 -1
  93. package/src/types/public.ts +1 -1
  94. package/src/utils/obj.util.ts +153 -13
@@ -1,22 +1,162 @@
1
- import { filter, isNil, join } from "lodash";
1
+ import { filter, isNil, isPlainObject, join } from "lodash";
2
2
 
3
- export function getAllNoneObjStringPath(value: any, prevPath: string = "") {
4
- if (typeof value === "object") {
5
- return Object.keys(value).reduce((prev, cur) => {
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
- value[cur],
30
+ item,
11
31
  join(
12
- filter([prevPath, cur], (v) => !isNil(v) && v !== ""),
13
- "."
14
- )
32
+ filter([prevPath, String(index)], (v) => !isNil(v) && v !== ""),
33
+ ".",
34
+ ),
15
35
  ),
16
36
  ];
17
37
  }, []);
18
38
  }
19
- return [prevPath];
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
  }, []);