react-form-manage 1.0.8-beta.7 → 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 +226 -41
- 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 +39 -156
- 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 +454 -26
- 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
|
@@ -3,11 +3,11 @@ import { useEffect, useState } from "react";
|
|
|
3
3
|
import { v4 } from "uuid";
|
|
4
4
|
import { useShallow } from "zustand/react/shallow";
|
|
5
5
|
import { useFormContext } from "../providers/Form";
|
|
6
|
-
import {
|
|
6
|
+
import { useFormStore } from "../stores/formStore";
|
|
7
7
|
|
|
8
8
|
import type { FormInstance } from "../stores/formStore";
|
|
9
9
|
|
|
10
|
-
type ListField = { name: string; key: string };
|
|
10
|
+
type ListField = { name: string; key: string; value?: any };
|
|
11
11
|
|
|
12
12
|
interface UseFormListControlProps {
|
|
13
13
|
name?: string;
|
|
@@ -19,7 +19,7 @@ interface UseFormListControlProps {
|
|
|
19
19
|
interface UseFormListControlReturn {
|
|
20
20
|
listFields: ListField[];
|
|
21
21
|
move: (opts: { from?: number; fromKey?: string; to: number }) => void;
|
|
22
|
-
add: (index
|
|
22
|
+
add: (index?: number) => void;
|
|
23
23
|
remove: (opts: { index?: number; key?: string }) => void;
|
|
24
24
|
}
|
|
25
25
|
|
|
@@ -29,21 +29,34 @@ export default function useFormListControl<T = any>({
|
|
|
29
29
|
initialValues,
|
|
30
30
|
formName,
|
|
31
31
|
}: UseFormListControlProps): UseFormListControlReturn {
|
|
32
|
+
const [formItemId] = useState<string>(v4());
|
|
32
33
|
const contextForm = useFormContext();
|
|
33
34
|
const getFormValues = useFormStore((state) => state.getFormValues);
|
|
34
|
-
const [listFormInitValues, setListFormInitValues] = useState<
|
|
35
|
-
|
|
35
|
+
const [listFormInitValues, setListFormInitValues] = useState<
|
|
36
|
+
any[] | undefined
|
|
37
|
+
>(undefined);
|
|
38
|
+
const {
|
|
39
|
+
clearCacheData,
|
|
40
|
+
setCacheData,
|
|
41
|
+
setListener,
|
|
42
|
+
getListener,
|
|
43
|
+
clearArrItems,
|
|
44
|
+
} = useFormStore(
|
|
36
45
|
useShallow((state) => ({
|
|
46
|
+
// Cache
|
|
37
47
|
cacheData: state.cacheData,
|
|
38
48
|
clearCacheData: state.clearCacheData,
|
|
39
49
|
setCacheData: state.setCacheData,
|
|
50
|
+
|
|
51
|
+
// Listener
|
|
52
|
+
setListener: state.setListener,
|
|
53
|
+
getListener: state.getListener,
|
|
54
|
+
|
|
55
|
+
// Clear Arr Items
|
|
56
|
+
clearArrItems: state.clearArrItems,
|
|
40
57
|
})),
|
|
41
58
|
);
|
|
42
|
-
|
|
43
|
-
useShallow((state) => ({
|
|
44
|
-
setCleanUpStack: state.setCleanUpStack,
|
|
45
|
-
})),
|
|
46
|
-
);
|
|
59
|
+
|
|
47
60
|
const { initValue: internalInitValue, formState } = useFormStore(
|
|
48
61
|
useShallow((state) => {
|
|
49
62
|
// console.log(
|
|
@@ -92,9 +105,20 @@ export default function useFormListControl<T = any>({
|
|
|
92
105
|
})
|
|
93
106
|
.filter(Boolean);
|
|
94
107
|
|
|
95
|
-
const mapCurWithKey = cur.map(
|
|
96
|
-
|
|
97
|
-
|
|
108
|
+
const mapCurWithKey = cur.map((c) => {
|
|
109
|
+
const find = mapPrevWithKey.find((m) => m.key === c.key);
|
|
110
|
+
|
|
111
|
+
if (find) {
|
|
112
|
+
return {
|
|
113
|
+
key: find.key,
|
|
114
|
+
value: isNil(c.value) ? find.value : c.value,
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
return c;
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
console.log("compare prev cur", { prev, cur });
|
|
98
122
|
|
|
99
123
|
const getNewValueCache = mapCurWithKey.filter(Boolean).map((c) => c.value);
|
|
100
124
|
|
|
@@ -107,26 +131,25 @@ export default function useFormListControl<T = any>({
|
|
|
107
131
|
// console.log("Mapping Cur value with prev fields: ", mapCurWithKey);
|
|
108
132
|
// console.log("After change arr value: ", getNewValueCache);
|
|
109
133
|
|
|
110
|
-
// Nếu số phần tử trước khi thay đổi mảng lớn hơn thì đẩy
|
|
134
|
+
// Nếu số phần tử trước khi thay đổi mảng lớn hơn thì đẩy các phần tử còn lại vào clean up stack để clear
|
|
111
135
|
if (startRemoveIndex > 0) {
|
|
112
|
-
Array.from(Array(startRemoveIndex))
|
|
113
|
-
.
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
// });
|
|
122
|
-
setCleanUpStack({
|
|
123
|
-
formName: formName || form?.formName || contextForm?.formName,
|
|
124
|
-
name: `${name}.${index}`,
|
|
125
|
-
type: "array",
|
|
126
|
-
});
|
|
127
|
-
});
|
|
136
|
+
const clearItems = Array.from(Array(startRemoveIndex)).map((_, index) => {
|
|
137
|
+
const clearIndex = getNewValueCache.length + index;
|
|
138
|
+
|
|
139
|
+
return {
|
|
140
|
+
formName: formName || form?.formName || contextForm?.formName,
|
|
141
|
+
name: `${name}.${clearIndex}`,
|
|
142
|
+
};
|
|
143
|
+
});
|
|
144
|
+
clearArrItems(clearItems);
|
|
128
145
|
}
|
|
129
146
|
|
|
147
|
+
console.log("Set cache data for form list: ", {
|
|
148
|
+
formName: formName || form?.formName || contextForm?.formName,
|
|
149
|
+
name,
|
|
150
|
+
getNewValueCache,
|
|
151
|
+
});
|
|
152
|
+
|
|
130
153
|
// console.log({ getNewValueCache });
|
|
131
154
|
setCacheData(
|
|
132
155
|
formName || form?.formName || contextForm?.formName,
|
|
@@ -135,13 +158,9 @@ export default function useFormListControl<T = any>({
|
|
|
135
158
|
);
|
|
136
159
|
};
|
|
137
160
|
|
|
138
|
-
const add = (index
|
|
161
|
+
const add = (index?: number) => {
|
|
139
162
|
setListFields((prev) => {
|
|
140
|
-
if (index
|
|
141
|
-
|
|
142
|
-
if (index < 0) return prev;
|
|
143
|
-
|
|
144
|
-
if (index === prev.length) {
|
|
163
|
+
if (isNil(index) || index === prev.length) {
|
|
145
164
|
const newName = `${name}.${prev.length}`;
|
|
146
165
|
const newKey = v4();
|
|
147
166
|
const result = [
|
|
@@ -154,6 +173,9 @@ export default function useFormListControl<T = any>({
|
|
|
154
173
|
|
|
155
174
|
return result;
|
|
156
175
|
}
|
|
176
|
+
if (index > prev.length) return prev;
|
|
177
|
+
|
|
178
|
+
if (index < 0) return prev;
|
|
157
179
|
|
|
158
180
|
const clonePrev = [...prev];
|
|
159
181
|
|
|
@@ -217,9 +239,17 @@ export default function useFormListControl<T = any>({
|
|
|
217
239
|
});
|
|
218
240
|
};
|
|
219
241
|
|
|
220
|
-
const move = ({
|
|
242
|
+
const move = ({
|
|
243
|
+
from,
|
|
244
|
+
fromKey,
|
|
245
|
+
to,
|
|
246
|
+
}: {
|
|
247
|
+
from?: number;
|
|
248
|
+
fromKey?: string;
|
|
249
|
+
to: number;
|
|
250
|
+
}) => {
|
|
221
251
|
setListFields((prev) => {
|
|
222
|
-
console.log("move list item: ", { from, to });
|
|
252
|
+
// console.log("move list item: ", { from, to });
|
|
223
253
|
if (
|
|
224
254
|
from >= listFields.length ||
|
|
225
255
|
from < 0 ||
|
|
@@ -228,7 +258,7 @@ export default function useFormListControl<T = any>({
|
|
|
228
258
|
from === to
|
|
229
259
|
)
|
|
230
260
|
return prev;
|
|
231
|
-
console.log("Trigger move item: ");
|
|
261
|
+
// console.log("Trigger move item: ");
|
|
232
262
|
|
|
233
263
|
if (!isNil(fromKey)) {
|
|
234
264
|
const findItemIndex = prev.findIndex((p) => p.key === fromKey);
|
|
@@ -286,7 +316,7 @@ export default function useFormListControl<T = any>({
|
|
|
286
316
|
useEffect(() => {
|
|
287
317
|
console.log("Trigger init", formState?.isInitied, internalInitValue);
|
|
288
318
|
if (formState?.isInitied) {
|
|
289
|
-
|
|
319
|
+
if (Array.isArray(listFormInitValues)) {
|
|
290
320
|
const result = listFormInitValues?.map((_, i) => {
|
|
291
321
|
const itemName = `${name}.${i}`;
|
|
292
322
|
const key = v4();
|
|
@@ -304,7 +334,12 @@ export default function useFormListControl<T = any>({
|
|
|
304
334
|
name,
|
|
305
335
|
listFormInitValues,
|
|
306
336
|
);
|
|
307
|
-
|
|
337
|
+
if (getListener(formItemId)) {
|
|
338
|
+
setListener({
|
|
339
|
+
formItemId,
|
|
340
|
+
isInitied: true,
|
|
341
|
+
});
|
|
342
|
+
}
|
|
308
343
|
return;
|
|
309
344
|
}
|
|
310
345
|
|
|
@@ -322,7 +357,12 @@ export default function useFormListControl<T = any>({
|
|
|
322
357
|
|
|
323
358
|
setListFields(result);
|
|
324
359
|
setListFormInitValues(internalInitValue as any);
|
|
325
|
-
|
|
360
|
+
if (getListener(formItemId)) {
|
|
361
|
+
setListener({
|
|
362
|
+
formItemId,
|
|
363
|
+
isInitied: true,
|
|
364
|
+
});
|
|
365
|
+
}
|
|
326
366
|
return;
|
|
327
367
|
}
|
|
328
368
|
|
|
@@ -350,7 +390,12 @@ export default function useFormListControl<T = any>({
|
|
|
350
390
|
|
|
351
391
|
setListFields(result);
|
|
352
392
|
setListFormInitValues(initialValues as any);
|
|
353
|
-
|
|
393
|
+
if (getListener(formItemId)) {
|
|
394
|
+
setListener({
|
|
395
|
+
formItemId,
|
|
396
|
+
isInitied: true,
|
|
397
|
+
});
|
|
398
|
+
}
|
|
354
399
|
// console.log("Get form init values: ", internalInitValue, result);
|
|
355
400
|
|
|
356
401
|
return;
|
|
@@ -374,5 +419,50 @@ export default function useFormListControl<T = any>({
|
|
|
374
419
|
};
|
|
375
420
|
}, [listFields]);
|
|
376
421
|
|
|
422
|
+
useEffect(() => {
|
|
423
|
+
if (!getListener(formItemId)) {
|
|
424
|
+
setListener({
|
|
425
|
+
formName: formName || form?.formName || contextForm?.formName,
|
|
426
|
+
name: name || "",
|
|
427
|
+
formItemId: formItemId,
|
|
428
|
+
type: "array",
|
|
429
|
+
onArrayChange: (newArr) => {
|
|
430
|
+
setListFields((prev) => {
|
|
431
|
+
const result = newArr.map((_, i) => {
|
|
432
|
+
const itemName = `${name}.${i}`;
|
|
433
|
+
const existingItem = prev[i];
|
|
434
|
+
return {
|
|
435
|
+
key: existingItem ? existingItem.key : v4(),
|
|
436
|
+
name: itemName,
|
|
437
|
+
};
|
|
438
|
+
});
|
|
439
|
+
|
|
440
|
+
handleCacheListField(
|
|
441
|
+
prev,
|
|
442
|
+
result.map((r, i) => {
|
|
443
|
+
return { ...r, value: newArr[i] };
|
|
444
|
+
}),
|
|
445
|
+
);
|
|
446
|
+
return result;
|
|
447
|
+
});
|
|
448
|
+
},
|
|
449
|
+
});
|
|
450
|
+
}
|
|
451
|
+
return () => {
|
|
452
|
+
// Remove listener on unmount
|
|
453
|
+
if (getListener(formItemId)) {
|
|
454
|
+
console.log("Remove listener for form list: ", {
|
|
455
|
+
formItemId,
|
|
456
|
+
});
|
|
457
|
+
setListener({
|
|
458
|
+
formName: formName || form?.formName || contextForm?.formName,
|
|
459
|
+
name: name || "",
|
|
460
|
+
formItemId: formItemId,
|
|
461
|
+
onArrayChange: undefined,
|
|
462
|
+
});
|
|
463
|
+
}
|
|
464
|
+
};
|
|
465
|
+
}, []);
|
|
466
|
+
|
|
377
467
|
return { listFields, move, add, remove };
|
|
378
468
|
}
|
package/src/index.ts
CHANGED
|
@@ -1,23 +1,31 @@
|
|
|
1
|
+
import { SUBMIT_STATE } from "./constants/form";
|
|
1
2
|
import Form, {
|
|
2
3
|
useForm,
|
|
3
|
-
useWatch,
|
|
4
|
-
useSubmitDataWatch,
|
|
5
4
|
useFormStateWatch,
|
|
6
|
-
|
|
7
|
-
|
|
5
|
+
useSubmitDataWatch,
|
|
6
|
+
useWatch,
|
|
8
7
|
type FormFieldError,
|
|
8
|
+
type FormProps,
|
|
9
9
|
type SubmitState,
|
|
10
10
|
type UseFormItemStateWatchReturn,
|
|
11
|
+
type ValidationRule,
|
|
11
12
|
} from "./providers/Form";
|
|
12
|
-
import { SUBMIT_STATE } from "./constants/form";
|
|
13
13
|
|
|
14
14
|
import FormItem, { type FormItemProps } from "./components/Form/FormItem";
|
|
15
15
|
import FormList, { type FormListProps } from "./components/Form/FormList";
|
|
16
|
+
import InputWrapper, {
|
|
17
|
+
type InputWrapperProps,
|
|
18
|
+
} from "./components/Form/InputWrapper";
|
|
16
19
|
import Input from "./components/Input";
|
|
17
|
-
import InputWrapper, { type InputWrapperProps } from "./components/Form/InputWrapper";
|
|
18
20
|
|
|
19
21
|
import useFormItemControl from "./hooks/useFormItemControl";
|
|
20
22
|
import useFormListControl from "./hooks/useFormListControl";
|
|
23
|
+
import {
|
|
24
|
+
useFormStore,
|
|
25
|
+
type CleanUpItem,
|
|
26
|
+
type FormInstance,
|
|
27
|
+
type ListenerItem,
|
|
28
|
+
} from "./stores/formStore";
|
|
21
29
|
|
|
22
30
|
export {
|
|
23
31
|
Form,
|
|
@@ -25,21 +33,25 @@ export {
|
|
|
25
33
|
FormList,
|
|
26
34
|
Input,
|
|
27
35
|
InputWrapper,
|
|
36
|
+
SUBMIT_STATE,
|
|
37
|
+
useForm,
|
|
28
38
|
useFormItemControl,
|
|
29
39
|
useFormListControl,
|
|
30
|
-
useForm,
|
|
31
|
-
useWatch,
|
|
32
|
-
useSubmitDataWatch,
|
|
33
40
|
useFormStateWatch,
|
|
34
|
-
|
|
41
|
+
useFormStore,
|
|
42
|
+
useSubmitDataWatch,
|
|
43
|
+
useWatch,
|
|
44
|
+
type CleanUpItem,
|
|
45
|
+
type FormFieldError,
|
|
46
|
+
type FormInstance,
|
|
35
47
|
type FormItemProps,
|
|
36
48
|
type FormListProps,
|
|
49
|
+
type FormProps,
|
|
37
50
|
type InputWrapperProps,
|
|
38
|
-
type
|
|
39
|
-
type FormFieldError,
|
|
51
|
+
type ListenerItem,
|
|
40
52
|
type SubmitState,
|
|
41
53
|
type UseFormItemStateWatchReturn,
|
|
42
|
-
|
|
54
|
+
type ValidationRule,
|
|
43
55
|
};
|
|
44
56
|
|
|
45
57
|
export default Form;
|
package/src/main.tsx
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import React from "react";
|
|
1
2
|
import { createRoot } from "react-dom/client";
|
|
2
3
|
import App from "./App";
|
|
3
4
|
import "./index.css";
|
|
@@ -7,4 +8,8 @@ if (!container) {
|
|
|
7
8
|
throw new Error("Root container missing");
|
|
8
9
|
}
|
|
9
10
|
|
|
10
|
-
createRoot(container).render(
|
|
11
|
+
createRoot(container).render(
|
|
12
|
+
<React.StrictMode>
|
|
13
|
+
<App />
|
|
14
|
+
</React.StrictMode>,
|
|
15
|
+
);
|