react-form-manage 1.0.8-beta.2 → 1.0.8-beta.21
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 +85 -5
- package/README.md +8 -4
- package/dist/components/Form/FormCleanUp.js +3 -3
- package/dist/components/Form/FormItem.d.ts +4 -2
- package/dist/components/Form/FormItem.js +7 -5
- package/dist/components/Form/FormList.d.ts +2 -2
- package/dist/components/Form/FormList.js +2 -2
- package/dist/hooks/useFormItemControl.d.ts +1 -0
- package/dist/hooks/useFormItemControl.js +60 -23
- package/dist/hooks/useFormListControl.d.ts +2 -1
- package/dist/hooks/useFormListControl.js +60 -10
- 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 +4 -2
- package/dist/providers/Form.js +98 -28
- package/dist/stores/formStore.d.ts +27 -2
- package/dist/stores/formStore.js +25 -9
- 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/TestSelect.d.ts +6 -0
- package/dist/test/TestSelect.js +24 -0
- package/dist/types/index.d.ts +1 -1
- package/dist/types/public.d.ts +6 -1
- package/dist/utils/obj.util.d.ts +1 -1
- package/dist/utils/obj.util.js +16 -5
- package/package.json +3 -1
- package/src/App.tsx +98 -4
- package/src/components/Form/FormCleanUp.tsx +3 -7
- package/src/components/Form/FormItem.tsx +56 -31
- package/src/components/Form/FormList.tsx +17 -4
- package/src/components/Form/InputWrapper.tsx +5 -0
- package/src/hooks/useFormItemControl.ts +70 -29
- package/src/hooks/useFormListControl.ts +104 -26
- package/src/index.ts +27 -13
- package/src/providers/Form.tsx +126 -17
- package/src/stores/formStore.ts +319 -288
- package/src/test/TestDialog.tsx +52 -0
- package/src/test/TestListener.tsx +21 -0
- package/src/test/TestSelect.tsx +38 -0
- package/src/types/index.ts +1 -1
- package/src/types/public.ts +7 -1
- package/src/utils/obj.util.ts +44 -13
|
@@ -1,20 +1,16 @@
|
|
|
1
1
|
import { useEffect } from "react";
|
|
2
2
|
import { useShallow } from "zustand/react/shallow";
|
|
3
|
-
import {
|
|
4
|
-
useFormCleanUp,
|
|
5
|
-
useFormListeners,
|
|
6
|
-
useFormStore,
|
|
7
|
-
} from "../../stores/formStore";
|
|
3
|
+
import { useFormStore } from "../../stores/formStore";
|
|
8
4
|
|
|
9
5
|
const FormCleanUp = () => {
|
|
10
|
-
const { cleanUpStack, clearCleanUpStack } =
|
|
6
|
+
const { cleanUpStack, clearCleanUpStack } = useFormStore(
|
|
11
7
|
useShallow((state) => ({
|
|
12
8
|
cleanUpStack: state.cleanUpStack,
|
|
13
9
|
clearCleanUpStack: state.clearCleanUpStack,
|
|
14
10
|
})),
|
|
15
11
|
);
|
|
16
12
|
|
|
17
|
-
const { revokeListener } =
|
|
13
|
+
const { revokeListener } = useFormStore(
|
|
18
14
|
useShallow((state) => ({
|
|
19
15
|
revokeListener: state.revokeListener,
|
|
20
16
|
})),
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import type { ReactElement } from "react";
|
|
2
|
-
import { cloneElement, useRef, useState } from "react";
|
|
2
|
+
import { cloneElement, Fragment, useRef, useState } from "react";
|
|
3
3
|
import { v4 } from "uuid";
|
|
4
4
|
import useFormItemControl from "../../hooks/useFormItemControl";
|
|
5
5
|
import type { ValidationRule } from "../../types/public";
|
|
6
6
|
|
|
7
7
|
export interface FormItemProps {
|
|
8
|
-
children: ReactElement
|
|
8
|
+
children: ReactElement<any>;
|
|
9
9
|
name: string;
|
|
10
10
|
formName?: string;
|
|
11
11
|
initialValue?: any;
|
|
@@ -13,6 +13,8 @@ export interface FormItemProps {
|
|
|
13
13
|
rules?: ValidationRule[];
|
|
14
14
|
valuePropName?: string;
|
|
15
15
|
getValueFromEvent?: (...args: any[]) => any;
|
|
16
|
+
controlAfterInit?: boolean;
|
|
17
|
+
hidden?: boolean;
|
|
16
18
|
}
|
|
17
19
|
|
|
18
20
|
export default function FormItem({
|
|
@@ -24,6 +26,8 @@ export default function FormItem({
|
|
|
24
26
|
rules,
|
|
25
27
|
valuePropName = "value",
|
|
26
28
|
getValueFromEvent,
|
|
29
|
+
controlAfterInit = false,
|
|
30
|
+
hidden,
|
|
27
31
|
}: FormItemProps) {
|
|
28
32
|
const elRef = useRef<any>(null);
|
|
29
33
|
|
|
@@ -37,6 +41,7 @@ export default function FormItem({
|
|
|
37
41
|
isDirty,
|
|
38
42
|
submitState,
|
|
39
43
|
isTouched,
|
|
44
|
+
isInitied,
|
|
40
45
|
} = useFormItemControl({
|
|
41
46
|
formName,
|
|
42
47
|
name,
|
|
@@ -51,34 +56,54 @@ export default function FormItem({
|
|
|
51
56
|
// console.log({ value });
|
|
52
57
|
// }, [value]);
|
|
53
58
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
59
|
+
// useEffect(() => {
|
|
60
|
+
// console.log("isInitied changed: ", {
|
|
61
|
+
// isInitied,
|
|
62
|
+
// name,
|
|
63
|
+
// value,
|
|
64
|
+
// controlAfterInit,
|
|
65
|
+
// });
|
|
66
|
+
// }, [isInitied]);
|
|
67
|
+
return (
|
|
68
|
+
<Fragment
|
|
69
|
+
key={`control-after-init-${Boolean(controlAfterInit && isInitied) ? "1" : "0"}-${formItemId}`}
|
|
70
|
+
>
|
|
71
|
+
{!hidden && children
|
|
72
|
+
? cloneElement(children, {
|
|
73
|
+
name,
|
|
74
|
+
// ref: inputRef,
|
|
75
|
+
[valuePropName]: value,
|
|
76
|
+
onChange: (...args: any[]) => {
|
|
77
|
+
let val = args[0];
|
|
78
|
+
if (
|
|
79
|
+
getValueFromEvent &&
|
|
80
|
+
typeof getValueFromEvent === "function"
|
|
81
|
+
) {
|
|
82
|
+
val = getValueFromEvent(...args);
|
|
83
|
+
} else {
|
|
84
|
+
const e = args[0];
|
|
85
|
+
if (e && e.target) {
|
|
86
|
+
val = e.target.value;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
onChange(val);
|
|
90
|
+
},
|
|
91
|
+
// onFocus: () => {
|
|
92
|
+
// setIsTouched(true);
|
|
93
|
+
// },
|
|
94
|
+
// isTouched: isTouched,
|
|
95
|
+
isDirty: isDirty,
|
|
96
|
+
// errors: errors,
|
|
97
|
+
// formState,
|
|
76
98
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
99
|
+
errors,
|
|
100
|
+
onFocus,
|
|
101
|
+
validateState: state,
|
|
102
|
+
ref: elRef,
|
|
103
|
+
submitState,
|
|
104
|
+
isTouched: isTouched,
|
|
105
|
+
} as any)
|
|
106
|
+
: null}
|
|
107
|
+
</Fragment>
|
|
108
|
+
);
|
|
84
109
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import useFormListControl from "../../hooks/useFormListControl";
|
|
2
2
|
import type { FormInstance } from "../../stores/formStore";
|
|
3
3
|
|
|
4
4
|
export interface FormListProps<T = any> {
|
|
@@ -6,11 +6,24 @@ export interface FormListProps<T = any> {
|
|
|
6
6
|
initialValues?: T[];
|
|
7
7
|
form?: FormInstance;
|
|
8
8
|
formName?: string;
|
|
9
|
-
children: (
|
|
9
|
+
children: (
|
|
10
|
+
fields: Array<{ name: string; key: string }>,
|
|
11
|
+
operations: {
|
|
12
|
+
add: (index?: number) => void;
|
|
13
|
+
remove: (opts: { index?: number; key?: string }) => void;
|
|
14
|
+
move: (opts: { from?: number; fromKey?: string; to: number }) => void;
|
|
15
|
+
},
|
|
16
|
+
) => React.ReactNode;
|
|
10
17
|
}
|
|
11
18
|
|
|
12
|
-
const FormList = <T = any
|
|
13
|
-
|
|
19
|
+
const FormList = <T = any,>({
|
|
20
|
+
name,
|
|
21
|
+
initialValues,
|
|
22
|
+
form,
|
|
23
|
+
formName,
|
|
24
|
+
children,
|
|
25
|
+
}: FormListProps<T>) => {
|
|
26
|
+
const { listFields, ...actions } = useFormListControl({
|
|
14
27
|
name,
|
|
15
28
|
initialValues,
|
|
16
29
|
form,
|
|
@@ -13,6 +13,11 @@ const InputWrapper = ({
|
|
|
13
13
|
errors = [],
|
|
14
14
|
...props
|
|
15
15
|
}: InputWrapperProps) => {
|
|
16
|
+
// useEffect(() => {
|
|
17
|
+
// console.log("InputWrapper submitState changed: ", {
|
|
18
|
+
// submitState: props.submitState,
|
|
19
|
+
// });
|
|
20
|
+
// }, [props.submitState]);
|
|
16
21
|
return (
|
|
17
22
|
<div>
|
|
18
23
|
{cloneElement(children, props)}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { get, isNil } from "lodash";
|
|
1
|
+
import { get, has, isNil } from "lodash";
|
|
2
2
|
import { useTaskEffect } from "minh-custom-hooks-release";
|
|
3
3
|
import { useEffect, useMemo, type RefObject } from "react";
|
|
4
4
|
import { useShallow } from "zustand/react/shallow"; // Import useShallow
|
|
@@ -18,11 +18,7 @@ import {
|
|
|
18
18
|
IS_VIETNAMESE_PHONE_NUMBER_REGEX,
|
|
19
19
|
} from "../constants/validation";
|
|
20
20
|
import { useFormContext } from "../providers/Form";
|
|
21
|
-
import {
|
|
22
|
-
useFormCleanUp,
|
|
23
|
-
useFormListeners,
|
|
24
|
-
useFormStore,
|
|
25
|
-
} from "../stores/formStore";
|
|
21
|
+
import { useFormStore } from "../stores/formStore";
|
|
26
22
|
|
|
27
23
|
import type { FormInstance } from "../stores/formStore";
|
|
28
24
|
import type {
|
|
@@ -52,6 +48,7 @@ export interface UseFormItemControlReturn {
|
|
|
52
48
|
isDirty?: boolean;
|
|
53
49
|
isTouched?: boolean;
|
|
54
50
|
submitState?: SubmitState;
|
|
51
|
+
isInitied?: boolean;
|
|
55
52
|
}
|
|
56
53
|
|
|
57
54
|
const VALID_PREMITIVE_TYPE = ["string", "number", "undefined"];
|
|
@@ -71,7 +68,7 @@ export default function useFormItemControl<T = any>({
|
|
|
71
68
|
setData,
|
|
72
69
|
getCacheData,
|
|
73
70
|
getFormValues,
|
|
74
|
-
getFormState,
|
|
71
|
+
// getFormState,
|
|
75
72
|
isStateInitied,
|
|
76
73
|
submitState,
|
|
77
74
|
} = useFormStore(
|
|
@@ -84,7 +81,7 @@ export default function useFormItemControl<T = any>({
|
|
|
84
81
|
setData: state.setData,
|
|
85
82
|
getCacheData: state.getCacheData,
|
|
86
83
|
getFormValues: state.getFormValues,
|
|
87
|
-
getFormState: state.getFormState,
|
|
84
|
+
// getFormState: state.getFormState,
|
|
88
85
|
isStateInitied:
|
|
89
86
|
state.formStates?.[
|
|
90
87
|
formName || form?.formName || contextForm?.formName
|
|
@@ -97,7 +94,7 @@ export default function useFormItemControl<T = any>({
|
|
|
97
94
|
}),
|
|
98
95
|
);
|
|
99
96
|
|
|
100
|
-
const { setCleanUpStack } =
|
|
97
|
+
const { setCleanUpStack } = useFormStore(
|
|
101
98
|
useShallow((state) => ({
|
|
102
99
|
setCleanUpStack: state.setCleanUpStack,
|
|
103
100
|
})),
|
|
@@ -129,7 +126,7 @@ export default function useFormItemControl<T = any>({
|
|
|
129
126
|
}),
|
|
130
127
|
);
|
|
131
128
|
|
|
132
|
-
const { listener, setListener } =
|
|
129
|
+
const { listener, setListener } = useFormStore(
|
|
133
130
|
useShallow((state) => {
|
|
134
131
|
// console.log(
|
|
135
132
|
// "Get listener from store: ",
|
|
@@ -154,7 +151,7 @@ export default function useFormItemControl<T = any>({
|
|
|
154
151
|
name,
|
|
155
152
|
value,
|
|
156
153
|
);
|
|
157
|
-
onChange(value, { notTriggerDirty: true });
|
|
154
|
+
onChange(value, { notTriggerDirty: true, initiedData: true });
|
|
158
155
|
};
|
|
159
156
|
|
|
160
157
|
const onFocus = () => {
|
|
@@ -171,7 +168,13 @@ export default function useFormItemControl<T = any>({
|
|
|
171
168
|
}
|
|
172
169
|
};
|
|
173
170
|
|
|
174
|
-
const onChange = (
|
|
171
|
+
const onChange = (
|
|
172
|
+
value: T,
|
|
173
|
+
options?: {
|
|
174
|
+
notTriggerDirty?: boolean;
|
|
175
|
+
initiedData?: boolean;
|
|
176
|
+
},
|
|
177
|
+
) => {
|
|
175
178
|
if (options?.notTriggerDirty !== true) {
|
|
176
179
|
setListener({
|
|
177
180
|
formItemId,
|
|
@@ -179,6 +182,12 @@ export default function useFormItemControl<T = any>({
|
|
|
179
182
|
isTouched: listener?.isTouched,
|
|
180
183
|
});
|
|
181
184
|
}
|
|
185
|
+
if (options?.initiedData === true) {
|
|
186
|
+
setListener({
|
|
187
|
+
formItemId,
|
|
188
|
+
isInitied: true,
|
|
189
|
+
});
|
|
190
|
+
}
|
|
182
191
|
setData(formName || form?.formName || contextForm?.formName, name, value);
|
|
183
192
|
};
|
|
184
193
|
|
|
@@ -188,10 +197,16 @@ export default function useFormItemControl<T = any>({
|
|
|
188
197
|
value,
|
|
189
198
|
getInitData(formName || form?.formName || contextForm?.formName, name),
|
|
190
199
|
);
|
|
200
|
+
setListener({
|
|
201
|
+
formItemId,
|
|
202
|
+
isDirty: false,
|
|
203
|
+
isTouched: false,
|
|
204
|
+
});
|
|
191
205
|
onChange(
|
|
192
206
|
isNil(value)
|
|
193
207
|
? getInitData(formName || form?.formName || contextForm?.formName, name)
|
|
194
208
|
: value,
|
|
209
|
+
{ notTriggerDirty: true, initiedData: true },
|
|
195
210
|
);
|
|
196
211
|
};
|
|
197
212
|
|
|
@@ -200,8 +215,17 @@ export default function useFormItemControl<T = any>({
|
|
|
200
215
|
return rules || [];
|
|
201
216
|
}, [rules]);
|
|
202
217
|
|
|
218
|
+
useEffect(() => {
|
|
219
|
+
console.log("Rules changed: ", { name, listener });
|
|
220
|
+
}, [value, listener]);
|
|
221
|
+
|
|
203
222
|
const { data: errors, state } = useTaskEffect({
|
|
204
223
|
async task() {
|
|
224
|
+
console.log("Trigger validate for form item: ", {
|
|
225
|
+
formName: formName || form?.formName || contextForm?.formName,
|
|
226
|
+
name,
|
|
227
|
+
value,
|
|
228
|
+
});
|
|
205
229
|
const listErrors = [];
|
|
206
230
|
|
|
207
231
|
const formValues = getFormValues(
|
|
@@ -494,7 +518,9 @@ export default function useFormItemControl<T = any>({
|
|
|
494
518
|
|
|
495
519
|
return listErrors;
|
|
496
520
|
},
|
|
497
|
-
deps: [internalRules, value],
|
|
521
|
+
deps: [internalRules, value, listener?.isInitied],
|
|
522
|
+
enabled: Boolean(listener?.isInitied),
|
|
523
|
+
|
|
498
524
|
onError(err) {
|
|
499
525
|
console.log(err);
|
|
500
526
|
},
|
|
@@ -522,8 +548,16 @@ export default function useFormItemControl<T = any>({
|
|
|
522
548
|
onInitData(initialValue);
|
|
523
549
|
}
|
|
524
550
|
} else {
|
|
525
|
-
onChange(internalInitValue, {
|
|
551
|
+
onChange(internalInitValue, {
|
|
552
|
+
notTriggerDirty: true,
|
|
553
|
+
initiedData: true,
|
|
554
|
+
});
|
|
526
555
|
}
|
|
556
|
+
} else {
|
|
557
|
+
onChange(value, {
|
|
558
|
+
notTriggerDirty: true,
|
|
559
|
+
initiedData: true,
|
|
560
|
+
});
|
|
527
561
|
}
|
|
528
562
|
return;
|
|
529
563
|
}
|
|
@@ -543,6 +577,15 @@ export default function useFormItemControl<T = any>({
|
|
|
543
577
|
});
|
|
544
578
|
}
|
|
545
579
|
|
|
580
|
+
return () => {
|
|
581
|
+
if (listener) {
|
|
582
|
+
setCleanUpStack({
|
|
583
|
+
name: listener.name,
|
|
584
|
+
itemKey: listener.formItemId,
|
|
585
|
+
});
|
|
586
|
+
}
|
|
587
|
+
};
|
|
588
|
+
|
|
546
589
|
// return () => {
|
|
547
590
|
// console.log("Revoke listener", listener);
|
|
548
591
|
|
|
@@ -568,28 +611,25 @@ export default function useFormItemControl<T = any>({
|
|
|
568
611
|
// console.log("Get cache Data after list change: ", cacheData);
|
|
569
612
|
|
|
570
613
|
if (cacheData) {
|
|
614
|
+
console.log("Cache data found when form item change: ", name, cacheData);
|
|
571
615
|
const getNewDataFromCache = get(cacheData, name);
|
|
616
|
+
const isIncludeDirectoryInCache = has(cacheData, name);
|
|
572
617
|
|
|
573
618
|
// console.log("Init data when change form ite: ", name, cacheData);
|
|
574
619
|
|
|
575
|
-
if (!getNewDataFromCache) {
|
|
576
|
-
onChange(initialValue
|
|
577
|
-
|
|
620
|
+
if (!isIncludeDirectoryInCache && isNil(getNewDataFromCache)) {
|
|
621
|
+
onChange(initialValue, {
|
|
622
|
+
notTriggerDirty: true,
|
|
623
|
+
initiedData: true,
|
|
624
|
+
});
|
|
625
|
+
} else
|
|
626
|
+
onChange(getNewDataFromCache, {
|
|
627
|
+
notTriggerDirty: true,
|
|
628
|
+
initiedData: true,
|
|
629
|
+
});
|
|
578
630
|
}
|
|
579
631
|
}, [name, formName || form?.formName || contextForm?.formName]);
|
|
580
632
|
|
|
581
|
-
useEffect(() => {
|
|
582
|
-
return () => {
|
|
583
|
-
setCleanUpStack({
|
|
584
|
-
itemKey: formItemId,
|
|
585
|
-
});
|
|
586
|
-
};
|
|
587
|
-
}, []);
|
|
588
|
-
|
|
589
|
-
useEffect(() => {
|
|
590
|
-
console.log("Submit state changed in useFormItemControl: ", submitState);
|
|
591
|
-
}, [submitState]);
|
|
592
|
-
|
|
593
633
|
return {
|
|
594
634
|
value: value as T,
|
|
595
635
|
onChange,
|
|
@@ -599,5 +639,6 @@ export default function useFormItemControl<T = any>({
|
|
|
599
639
|
isDirty: listener?.isDirty,
|
|
600
640
|
isTouched: listener?.isTouched,
|
|
601
641
|
submitState,
|
|
642
|
+
isInitied: listener?.isInitied,
|
|
602
643
|
};
|
|
603
644
|
}
|
|
@@ -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,17 +29,26 @@ 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
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
35
|
+
const [listFormInitValues, setListFormInitValues] = useState<
|
|
36
|
+
any[] | undefined
|
|
37
|
+
>(undefined);
|
|
38
|
+
const { clearCacheData, setCacheData, setListener, getListener } =
|
|
39
|
+
useFormStore(
|
|
40
|
+
useShallow((state) => ({
|
|
41
|
+
// Cache
|
|
42
|
+
cacheData: state.cacheData,
|
|
43
|
+
clearCacheData: state.clearCacheData,
|
|
44
|
+
setCacheData: state.setCacheData,
|
|
45
|
+
|
|
46
|
+
// Listener
|
|
47
|
+
setListener: state.setListener,
|
|
48
|
+
getListener: state.getListener,
|
|
49
|
+
})),
|
|
50
|
+
);
|
|
51
|
+
const { setCleanUpStack } = useFormStore(
|
|
43
52
|
useShallow((state) => ({
|
|
44
53
|
setCleanUpStack: state.setCleanUpStack,
|
|
45
54
|
})),
|
|
@@ -92,9 +101,20 @@ export default function useFormListControl<T = any>({
|
|
|
92
101
|
})
|
|
93
102
|
.filter(Boolean);
|
|
94
103
|
|
|
95
|
-
const mapCurWithKey = cur.map(
|
|
96
|
-
|
|
97
|
-
|
|
104
|
+
const mapCurWithKey = cur.map((c) => {
|
|
105
|
+
const find = mapPrevWithKey.find((m) => m.key === c.key);
|
|
106
|
+
|
|
107
|
+
if (find) {
|
|
108
|
+
return {
|
|
109
|
+
key: find.key,
|
|
110
|
+
value: isNil(c.value) ? find.value : c.value,
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
return c;
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
console.log("compare prev cur", { prev, cur });
|
|
98
118
|
|
|
99
119
|
const getNewValueCache = mapCurWithKey.filter(Boolean).map((c) => c.value);
|
|
100
120
|
|
|
@@ -107,7 +127,7 @@ export default function useFormListControl<T = any>({
|
|
|
107
127
|
// console.log("Mapping Cur value with prev fields: ", mapCurWithKey);
|
|
108
128
|
// console.log("After change arr value: ", getNewValueCache);
|
|
109
129
|
|
|
110
|
-
// Nếu số phần tử trước khi thay đổi mảng lớn hơn thì đẩy
|
|
130
|
+
// 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
131
|
if (startRemoveIndex > 0) {
|
|
112
132
|
Array.from(Array(startRemoveIndex))
|
|
113
133
|
.map((_, index) => {
|
|
@@ -127,6 +147,12 @@ export default function useFormListControl<T = any>({
|
|
|
127
147
|
});
|
|
128
148
|
}
|
|
129
149
|
|
|
150
|
+
console.log("Set cache data for form list: ", {
|
|
151
|
+
formName: formName || form?.formName || contextForm?.formName,
|
|
152
|
+
name,
|
|
153
|
+
getNewValueCache,
|
|
154
|
+
});
|
|
155
|
+
|
|
130
156
|
// console.log({ getNewValueCache });
|
|
131
157
|
setCacheData(
|
|
132
158
|
formName || form?.formName || contextForm?.formName,
|
|
@@ -135,13 +161,9 @@ export default function useFormListControl<T = any>({
|
|
|
135
161
|
);
|
|
136
162
|
};
|
|
137
163
|
|
|
138
|
-
const add = (index
|
|
164
|
+
const add = (index?: number) => {
|
|
139
165
|
setListFields((prev) => {
|
|
140
|
-
if (index
|
|
141
|
-
|
|
142
|
-
if (index < 0) return prev;
|
|
143
|
-
|
|
144
|
-
if (index === prev.length) {
|
|
166
|
+
if (isNil(index) || index === prev.length) {
|
|
145
167
|
const newName = `${name}.${prev.length}`;
|
|
146
168
|
const newKey = v4();
|
|
147
169
|
const result = [
|
|
@@ -154,6 +176,9 @@ export default function useFormListControl<T = any>({
|
|
|
154
176
|
|
|
155
177
|
return result;
|
|
156
178
|
}
|
|
179
|
+
if (index > prev.length) return prev;
|
|
180
|
+
|
|
181
|
+
if (index < 0) return prev;
|
|
157
182
|
|
|
158
183
|
const clonePrev = [...prev];
|
|
159
184
|
|
|
@@ -217,9 +242,17 @@ export default function useFormListControl<T = any>({
|
|
|
217
242
|
});
|
|
218
243
|
};
|
|
219
244
|
|
|
220
|
-
const move = ({
|
|
245
|
+
const move = ({
|
|
246
|
+
from,
|
|
247
|
+
fromKey,
|
|
248
|
+
to,
|
|
249
|
+
}: {
|
|
250
|
+
from?: number;
|
|
251
|
+
fromKey?: string;
|
|
252
|
+
to: number;
|
|
253
|
+
}) => {
|
|
221
254
|
setListFields((prev) => {
|
|
222
|
-
console.log("move list item: ", { from, to });
|
|
255
|
+
// console.log("move list item: ", { from, to });
|
|
223
256
|
if (
|
|
224
257
|
from >= listFields.length ||
|
|
225
258
|
from < 0 ||
|
|
@@ -228,7 +261,7 @@ export default function useFormListControl<T = any>({
|
|
|
228
261
|
from === to
|
|
229
262
|
)
|
|
230
263
|
return prev;
|
|
231
|
-
console.log("Trigger move item: ");
|
|
264
|
+
// console.log("Trigger move item: ");
|
|
232
265
|
|
|
233
266
|
if (!isNil(fromKey)) {
|
|
234
267
|
const findItemIndex = prev.findIndex((p) => p.key === fromKey);
|
|
@@ -286,7 +319,7 @@ export default function useFormListControl<T = any>({
|
|
|
286
319
|
useEffect(() => {
|
|
287
320
|
console.log("Trigger init", formState?.isInitied, internalInitValue);
|
|
288
321
|
if (formState?.isInitied) {
|
|
289
|
-
|
|
322
|
+
if (Array.isArray(listFormInitValues)) {
|
|
290
323
|
const result = listFormInitValues?.map((_, i) => {
|
|
291
324
|
const itemName = `${name}.${i}`;
|
|
292
325
|
const key = v4();
|
|
@@ -374,5 +407,50 @@ export default function useFormListControl<T = any>({
|
|
|
374
407
|
};
|
|
375
408
|
}, [listFields]);
|
|
376
409
|
|
|
410
|
+
useEffect(() => {
|
|
411
|
+
if (!getListener(formItemId)) {
|
|
412
|
+
setListener({
|
|
413
|
+
formName: formName || form?.formName || contextForm?.formName,
|
|
414
|
+
name: name || "",
|
|
415
|
+
formItemId: formItemId,
|
|
416
|
+
type: "array",
|
|
417
|
+
onArrayChange: (newArr) => {
|
|
418
|
+
setListFields((prev) => {
|
|
419
|
+
const result = newArr.map((_, i) => {
|
|
420
|
+
const itemName = `${name}.${i}`;
|
|
421
|
+
const existingItem = prev[i];
|
|
422
|
+
return {
|
|
423
|
+
key: existingItem ? existingItem.key : v4(),
|
|
424
|
+
name: itemName,
|
|
425
|
+
};
|
|
426
|
+
});
|
|
427
|
+
|
|
428
|
+
handleCacheListField(
|
|
429
|
+
prev,
|
|
430
|
+
result.map((r, i) => {
|
|
431
|
+
return { ...r, value: newArr[i] };
|
|
432
|
+
}),
|
|
433
|
+
);
|
|
434
|
+
return result;
|
|
435
|
+
});
|
|
436
|
+
},
|
|
437
|
+
});
|
|
438
|
+
}
|
|
439
|
+
return () => {
|
|
440
|
+
// Remove listener on unmount
|
|
441
|
+
if (getListener(formItemId)) {
|
|
442
|
+
console.log("Remove listener for form list: ", {
|
|
443
|
+
formItemId,
|
|
444
|
+
});
|
|
445
|
+
setListener({
|
|
446
|
+
formName: formName || form?.formName || contextForm?.formName,
|
|
447
|
+
name: name || "",
|
|
448
|
+
formItemId: formItemId,
|
|
449
|
+
onArrayChange: undefined,
|
|
450
|
+
});
|
|
451
|
+
}
|
|
452
|
+
};
|
|
453
|
+
}, []);
|
|
454
|
+
|
|
377
455
|
return { listFields, move, add, remove };
|
|
378
456
|
}
|