react-form-manage 1.0.8-beta.26 → 1.0.8-beta.28

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 (50) hide show
  1. package/CHANGELOG.md +35 -0
  2. package/dist/constants/form.d.ts +1 -1
  3. package/dist/hooks/useFormItemControl.d.ts +5 -2
  4. package/dist/providers/Form.d.ts +11 -1
  5. package/dist/providers/Form.js +160 -41
  6. package/dist/test/TestWatchNormalize.d.ts +3 -0
  7. package/dist/test/TestWatchNormalize.js +23 -0
  8. package/dist/test/testSetValue/TestCase10_SetFieldValues_ComplexNested.d.ts +21 -0
  9. package/dist/test/testSetValue/TestCase10_SetFieldValues_ComplexNested.js +61 -0
  10. package/dist/test/testSetValue/TestCase1_PlainObjectToPrimitives.d.ts +16 -0
  11. package/dist/test/testSetValue/TestCase1_PlainObjectToPrimitives.js +18 -0
  12. package/dist/test/testSetValue/TestCase2_PlainObjectToFormList.d.ts +21 -0
  13. package/dist/test/testSetValue/TestCase2_PlainObjectToFormList.js +33 -0
  14. package/dist/test/testSetValue/TestCase3_ArrayNonListenerToPrimitives.d.ts +21 -0
  15. package/dist/test/testSetValue/TestCase3_ArrayNonListenerToPrimitives.js +26 -0
  16. package/dist/test/testSetValue/TestCase4_PlainObjectRemovedFields.d.ts +20 -0
  17. package/dist/test/testSetValue/TestCase4_PlainObjectRemovedFields.js +32 -0
  18. package/dist/test/testSetValue/TestCase5_FormListRemovedItems.d.ts +22 -0
  19. package/dist/test/testSetValue/TestCase5_FormListRemovedItems.js +29 -0
  20. package/dist/test/testSetValue/TestCase6_NestedFormListRemoved.d.ts +28 -0
  21. package/dist/test/testSetValue/TestCase6_NestedFormListRemoved.js +36 -0
  22. package/dist/test/testSetValue/TestCase7_SetFieldValues_MixedStructure.d.ts +17 -0
  23. package/dist/test/testSetValue/TestCase7_SetFieldValues_MixedStructure.js +33 -0
  24. package/dist/test/testSetValue/TestCase8_SetFieldValues_NestedObject.d.ts +27 -0
  25. package/dist/test/testSetValue/TestCase8_SetFieldValues_NestedObject.js +57 -0
  26. package/dist/test/testSetValue/TestCase9_SetFieldValues_MultipleArrays.d.ts +25 -0
  27. package/dist/test/testSetValue/TestCase9_SetFieldValues_MultipleArrays.js +46 -0
  28. package/dist/test/testSetValue/index.d.ts +2 -0
  29. package/dist/test/testSetValue/index.js +28 -0
  30. package/dist/utils/obj.util.d.ts +28 -0
  31. package/dist/utils/obj.util.js +43 -0
  32. package/package.json +1 -1
  33. package/src/App.tsx +30 -18
  34. package/src/DEEP_TRIGGER_LOGIC.md +573 -0
  35. package/src/constants/form.ts +1 -1
  36. package/src/hooks/useFormItemControl.ts +6 -1
  37. package/src/providers/Form.tsx +384 -52
  38. package/src/test/TestWatchNormalize.tsx +32 -0
  39. package/src/test/testSetValue/TestCase10_SetFieldValues_ComplexNested.tsx +206 -0
  40. package/src/test/testSetValue/TestCase1_PlainObjectToPrimitives.tsx +72 -0
  41. package/src/test/testSetValue/TestCase2_PlainObjectToFormList.tsx +114 -0
  42. package/src/test/testSetValue/TestCase3_ArrayNonListenerToPrimitives.tsx +99 -0
  43. package/src/test/testSetValue/TestCase4_PlainObjectRemovedFields.tsx +112 -0
  44. package/src/test/testSetValue/TestCase5_FormListRemovedItems.tsx +119 -0
  45. package/src/test/testSetValue/TestCase6_NestedFormListRemoved.tsx +185 -0
  46. package/src/test/testSetValue/TestCase7_SetFieldValues_MixedStructure.tsx +110 -0
  47. package/src/test/testSetValue/TestCase8_SetFieldValues_NestedObject.tsx +162 -0
  48. package/src/test/testSetValue/TestCase9_SetFieldValues_MultipleArrays.tsx +173 -0
  49. package/src/test/testSetValue/index.tsx +100 -0
  50. package/src/utils/obj.util.ts +109 -0
package/CHANGELOG.md CHANGED
@@ -2,6 +2,41 @@
2
2
 
3
3
  All notable changes to this project will be documented in this file.
4
4
 
5
+ ## [1.0.8-beta.28] - 2026-02-09
6
+
7
+ ### Features
8
+
9
+ - **Deep Trigger Set Value**: Implement recursive value setting with comprehensive listener triggering
10
+ - `setFieldValue` with `deepTrigger: true` option for recursive listener notification
11
+ - Support for plain objects, arrays, FormLists, and nested structures
12
+ - Proper cleanup for removed fields and array items
13
+ - Edge case handling: removed object fields, nested FormList items
14
+ - **Enhanced setFieldValues**: Improved batch value setting logic
15
+ - Automatically detects arrays and uses deep trigger
16
+ - Traverses object structure and stops at arrays
17
+ - Primitives trigger onChange, arrays use handleDeepTriggerSet
18
+ - **Utility Functions**: New path collection utilities in obj.util.ts
19
+ - `getAllPathsIncludingContainers`: Get all paths including intermediate containers
20
+ - `getAllPathsStopAtArray`: Get paths but stop traversal at arrays
21
+ - **Array Index Notation**: Changed from `[index]` to `.index` notation for consistency
22
+ - **Documentation**: Added comprehensive DEEP_TRIGGER_LOGIC.md with 6 detailed case studies
23
+ - **Test Suite**: Created 10 test cases covering all deep trigger scenarios
24
+
25
+ ### Technical Details
26
+
27
+ - Deep trigger handles 5 core value types: primitives, plain objects, array listeners (FormList), non-listener arrays, and class instances
28
+ - Hierarchical trigger order: field level → item/index level → property level
29
+ - Recursive cleanup for removed nested structures
30
+ - Options support for controlling dirty state triggering
31
+
32
+ ## [1.0.8-beta.27] - 2026-02-04
33
+
34
+ ### Features
35
+
36
+ - Add `useWatchNormalize` hook for watching and normalizing form data
37
+ - Support custom normalization functions for automatic value transformation
38
+ - Simplifies data format conversion during form value watching
39
+
5
40
  ## [1.0.8-beta.25] - 2026-02-04
6
41
 
7
42
  ### Changes
@@ -4,4 +4,4 @@ export declare const SUBMIT_STATE: {
4
4
  readonly SUBMITTED: "submitted";
5
5
  readonly REJECTED: "rejected";
6
6
  };
7
- export type SubmitState = typeof SUBMIT_STATE[keyof typeof SUBMIT_STATE];
7
+ export type SubmitState = (typeof SUBMIT_STATE)[keyof typeof SUBMIT_STATE];
@@ -1,7 +1,6 @@
1
1
  import { type RefObject } from "react";
2
2
  import type { FormInstance } from "../stores/formStore";
3
3
  import type { FormFieldError, SubmitState, ValidationRule } from "../types/public";
4
- type AnyObject = Record<string, any>;
5
4
  interface UseFormItemControlProps {
6
5
  formName?: string;
7
6
  form?: FormInstance;
@@ -13,9 +12,13 @@ interface UseFormItemControlProps {
13
12
  hidden?: boolean;
14
13
  collectOnHidden?: boolean;
15
14
  }
15
+ export interface OnChangeOptions {
16
+ notTriggerDirty?: boolean;
17
+ initiedData?: boolean;
18
+ }
16
19
  export interface UseFormItemControlReturn {
17
20
  value: any;
18
- onChange: (value: any, options?: AnyObject) => void;
21
+ onChange: (value: any, options?: OnChangeOptions) => void;
19
22
  state: any;
20
23
  errors: FormFieldError[];
21
24
  onFocus: () => void;
@@ -1,8 +1,12 @@
1
1
  import type { ComponentType, FormHTMLAttributes, ReactNode } from "react";
2
2
  import FormItem from "../components/Form/FormItem";
3
+ import { OnChangeOptions } from "../hooks/useFormItemControl";
3
4
  import type { PublicFormInstance, UseFormItemStateWatchReturn } from "../types/public";
4
- export type { FormFieldError, SubmitState, UseFormItemStateWatchReturn, ValidationRule, } from "../types/public";
5
+ export type { FormFieldError, SubmitState, UseFormItemStateWatchReturn, ValidationRule } from "../types/public";
5
6
  export declare const FormContext: import("react").Context<any>;
7
+ export interface SetFieldValueOptions extends OnChangeOptions {
8
+ deepTrigger?: boolean;
9
+ }
6
10
  export interface FormProps<T = any> extends Omit<FormHTMLAttributes<HTMLFormElement>, "onSubmit"> {
7
11
  collectHiddenFields?: boolean;
8
12
  children: ReactNode;
@@ -22,6 +26,7 @@ declare namespace Form {
22
26
  var useForm: typeof import("./Form").useForm;
23
27
  var Item: typeof FormItem;
24
28
  var useWatch: typeof import("./Form").useWatch;
29
+ var useWatchNormalized: typeof import("./Form").useWatchNormalized;
25
30
  var useSubmitDataWatch: typeof import("./Form").useSubmitDataWatch;
26
31
  var useFormStateWatch: <T = any>(formNameOrFormInstance?: string | PublicFormInstance<T>) => any;
27
32
  var useFormItemStateWatch: <T = any>(nameOrFormItemId: string, formNameOrFormInstance?: string | PublicFormInstance<T>) => UseFormItemStateWatchReturn;
@@ -30,6 +35,11 @@ export default Form;
30
35
  export declare function useFormContext(): any;
31
36
  export declare function useForm<T = any>(formNameOrFormInstance?: string | PublicFormInstance<T>): PublicFormInstance<T>[];
32
37
  export declare function useWatch<T = any>(name: keyof T & string, formNameOrFormInstance?: string | PublicFormInstance<T>): T[keyof T] | undefined;
38
+ export declare function useWatchNormalized<T, TFn extends (v: any) => any>({ name, normalizeFn, formNameOrFormInstance, }: {
39
+ name: keyof T & string;
40
+ normalizeFn: TFn;
41
+ formNameOrFormInstance?: string | PublicFormInstance<T>;
42
+ }): ReturnType<TFn>;
33
43
  export declare function useSubmitDataWatch<T = any>({ formNameOrFormInstance, triggerWhenChange, mapFn, }: {
34
44
  formNameOrFormInstance?: string | PublicFormInstance<T>;
35
45
  triggerWhenChange?: boolean;
@@ -1,13 +1,13 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
- import { cloneDeep, filter, get, isEqual, isNil, isPlainObject, last, set, uniqBy } from "lodash";
2
+ import { cloneDeep, filter, get, isArray, isEqual, isNil, isPlainObject, last, set, uniqBy } from "lodash";
3
3
  import { useTask } from "minh-custom-hooks-release";
4
- import { createContext, useContext, useEffect, useState } from "react";
4
+ import { createContext, useContext, useEffect, useMemo, useState } from "react";
5
5
  import { flushSync } from "react-dom";
6
6
  import { useShallow } from "zustand/react/shallow";
7
7
  import FormItem from "../components/Form/FormItem";
8
8
  import { SUBMIT_STATE } from "../constants/form";
9
9
  import { useFormStore } from "../stores/formStore";
10
- import { getAllNoneObjStringPath } from "../utils/obj.util";
10
+ import { getAllNoneObjStringPath, getAllPathsIncludingContainers, getAllPathsStopAtArray } from "../utils/obj.util";
11
11
  const FormContext = createContext(null);
12
12
  function Form({ children, formName, initialValues, onFinish, onReject, onFinally, FormElement, collectHiddenFields: formCollectHiddenFields = true, ...props }) {
13
13
  const {
@@ -44,7 +44,137 @@ function Form({ children, formName, initialValues, onFinish, onReject, onFinally
44
44
  getListeners: state.getListeners
45
45
  };
46
46
  }));
47
+ const handlePrimitiveValue = (name, value, options) => {
48
+ const listener = getListeners().find((l) => l.name === name && l.formName === formName);
49
+ if (listener) {
50
+ listener.onChange(value, options);
51
+ } else {
52
+ setData(formName, name, value);
53
+ }
54
+ };
55
+ const handleArrayListener = (name, value, options, coreRecursive) => {
56
+ const listener = getListeners().find((l) => l.name === name && l.formName === formName);
57
+ if (!listener)
58
+ return;
59
+ const currentValue = getFormItemValue(formName, name);
60
+ if (!isEqual(currentValue, value)) {
61
+ listener.onArrayChange(value, options);
62
+ value.forEach((item, index) => {
63
+ const itemName = `${name}.${index}`;
64
+ const itemListener = getListeners().find((l) => l.name === itemName && l.formName === formName);
65
+ if (itemListener) {
66
+ itemListener.onChange(item, options);
67
+ }
68
+ const nestedPaths = getAllPathsIncludingContainers(item);
69
+ nestedPaths.forEach((p) => {
70
+ if (coreRecursive) {
71
+ coreRecursive(`${itemName}.${p}`, get(item, p), options);
72
+ }
73
+ });
74
+ });
75
+ if (isArray(currentValue) && currentValue.length > value.length) {
76
+ for (let index = value.length; index < currentValue.length; index++) {
77
+ const itemName = `${name}.${index}`;
78
+ if (coreRecursive) {
79
+ coreRecursive(itemName, void 0, options);
80
+ }
81
+ }
82
+ }
83
+ }
84
+ };
85
+ const handlePlainObject = (name, value, options, coreRecursive) => {
86
+ const listener = getListeners().find((l) => l.name === name && l.formName === formName);
87
+ if (listener && listener.type !== "array") {
88
+ listener.onChange(value, options);
89
+ }
90
+ const allPaths = getAllPathsIncludingContainers(value);
91
+ allPaths.forEach((p) => {
92
+ if (coreRecursive) {
93
+ const fullPath = `${name}.${p}`;
94
+ coreRecursive(fullPath, get(value, p), options);
95
+ }
96
+ });
97
+ const previousValue = getFieldValue(name);
98
+ if (isPlainObject(previousValue)) {
99
+ const previousKeys = Object.keys(previousValue);
100
+ const newKeys = Object.keys(value);
101
+ const removedKeys = previousKeys.filter((k) => !newKeys.includes(k));
102
+ removedKeys.forEach((key) => {
103
+ if (coreRecursive) {
104
+ coreRecursive(`${name}.${key}`, void 0, options);
105
+ }
106
+ });
107
+ }
108
+ };
109
+ const handleNonListenerArray = (name, value, options, coreRecursive) => {
110
+ const previousValues = getFieldValue(name);
111
+ if (isArray(previousValues)) {
112
+ if (previousValues.length !== value.length || !isEqual(previousValues, value)) {
113
+ setData(formName, name, value);
114
+ }
115
+ value.forEach((item, index) => {
116
+ if (!isEqual(previousValues[index], item)) {
117
+ const itemName = `${name}.${index}`;
118
+ const itemListener = getListeners().find((l) => l.name === itemName && l.formName === formName);
119
+ if (itemListener) {
120
+ itemListener.onChange(item, options);
121
+ }
122
+ const nestedPaths = getAllPathsIncludingContainers(item);
123
+ nestedPaths.forEach((p) => {
124
+ if (coreRecursive) {
125
+ coreRecursive(`${itemName}.${p}`, get(item, p), options);
126
+ }
127
+ });
128
+ }
129
+ });
130
+ if (previousValues.length > value.length) {
131
+ for (let index = value.length; index < previousValues.length; index++) {
132
+ const itemName = `${name}.${index}`;
133
+ const removedItem = previousValues[index];
134
+ const nestedPaths = getAllPathsIncludingContainers(removedItem);
135
+ nestedPaths.forEach((p) => {
136
+ if (coreRecursive) {
137
+ coreRecursive(`${itemName}.${p}`, void 0, options);
138
+ }
139
+ });
140
+ if (coreRecursive) {
141
+ coreRecursive(itemName, void 0, options);
142
+ }
143
+ }
144
+ }
145
+ }
146
+ };
147
+ const deepTriggerSetCore = (name, value, options) => {
148
+ if (typeof value === "string" || typeof value === "number" || typeof value === "boolean" || value === null || value === void 0) {
149
+ handlePrimitiveValue(name, value, options);
150
+ return;
151
+ }
152
+ if (isPlainObject(value)) {
153
+ const listener = getListeners().find((l) => l.name === name && l.formName === formName);
154
+ handlePlainObject(name, value, options, deepTriggerSetCore);
155
+ return;
156
+ }
157
+ if (Array.isArray(value)) {
158
+ const listener = getListeners().find((l) => l.name === name && l.formName === formName);
159
+ if (listener && listener.type === "array") {
160
+ handleArrayListener(name, value, options, deepTriggerSetCore);
161
+ } else if (!listener) {
162
+ handleNonListenerArray(name, value, options, deepTriggerSetCore);
163
+ } else {
164
+ handlePlainObject(name, value, options, deepTriggerSetCore);
165
+ }
166
+ return;
167
+ }
168
+ handlePrimitiveValue(name, value, options);
169
+ };
170
+ const handleDeepTriggerSet = (name, value, options) => {
171
+ deepTriggerSetCore(name, value, options);
172
+ };
47
173
  const setFieldValue = (name, value, options) => {
174
+ if (options == null ? void 0 : options.deepTrigger) {
175
+ handleDeepTriggerSet(name, value, options);
176
+ return;
177
+ }
48
178
  const listener = getListeners().find((l) => l.name === name && l.formName === formName);
49
179
  if (listener) {
50
180
  if (listener.type === "array") {
@@ -64,52 +194,28 @@ function Form({ children, formName, initialValues, onFinish, onReject, onFinally
64
194
  listener.onChange(value, options);
65
195
  }
66
196
  } else {
67
- if (isPlainObject(value) || Array.isArray(value)) {
68
- const allStringPath = getAllNoneObjStringPath(value);
69
- allStringPath.forEach((p) => {
70
- const findListener = getListeners().find((l) => l.name === `${name}.${p}` && l.formName === formName);
71
- if (findListener) {
72
- findListener.onChange(get(value, p), options);
73
- } else {
74
- setData(formName, `${name}.${p}`, get(value, p));
75
- }
76
- });
77
- } else {
78
- setData(formName, name, value);
79
- }
197
+ setData(formName, name, value);
80
198
  }
81
199
  };
82
200
  const setFieldValues = (values, options = { notTriggerDirty: false }) => {
83
- const allStringPath = getAllNoneObjStringPath(values);
84
- allStringPath.forEach((p) => {
85
- const listener = getListeners().find((l) => l.name === p && l.formName === formName);
201
+ const allPaths = getAllPathsStopAtArray(values);
202
+ allPaths.forEach((path) => {
203
+ const pathValue = get(values, path);
204
+ if (Array.isArray(pathValue)) {
205
+ handleDeepTriggerSet(path, pathValue, options);
206
+ return;
207
+ }
208
+ const listener = getListeners().find((l) => l.name === path && l.formName === formName);
86
209
  if (listener) {
87
- if (listener.type === "array") {
88
- if (!isEqual(getFormItemValue(formName, p), get(values, p))) {
89
- listener.onArrayChange(get(values, listener.name), options);
90
- const nestedAllStringPath = getAllNoneObjStringPath(get(values, p));
91
- nestedAllStringPath.forEach((np) => {
92
- {
93
- const findListener = getListeners().find((l) => l.name === `${p}.${np}` && l.formName === formName);
94
- if (findListener) {
95
- findListener.onChange(get(values, `${p}.${np}`), options);
96
- } else {
97
- setData(formName, `${p}.${np}`, get(values, `${p}.${np}`));
98
- }
99
- }
100
- });
101
- }
102
- } else {
103
- listener.onChange(get(values, listener.name), options);
104
- }
210
+ listener.onChange(pathValue, options);
105
211
  } else {
106
- setData(formName, p, get(values, p));
212
+ setData(formName, path, pathValue);
107
213
  }
108
214
  });
109
215
  };
110
- const getFieldValue = (name) => {
216
+ function getFieldValue(name) {
111
217
  return getFormItemValue(formName, name);
112
- };
218
+ }
113
219
  const getFieldValues = (names = []) => {
114
220
  return names.map((name) => ({
115
221
  name,
@@ -333,6 +439,17 @@ function useWatch(name, formNameOrFormInstance) {
333
439
  });
334
440
  return value;
335
441
  }
442
+ function useWatchNormalized({ name, normalizeFn, formNameOrFormInstance }) {
443
+ const [formInstance] = useForm(formNameOrFormInstance);
444
+ const rawValue = useFormStore((state) => {
445
+ var _a;
446
+ return state.getFormItemValue((_a = formInstance == null ? void 0 : formInstance.formName) != null ? _a : formNameOrFormInstance, name);
447
+ });
448
+ const normalizedValue = useMemo(() => {
449
+ return normalizeFn(rawValue);
450
+ }, [rawValue, normalizeFn]);
451
+ return normalizedValue;
452
+ }
336
453
  function useSubmitDataWatch({ formNameOrFormInstance, triggerWhenChange = false, mapFn }) {
337
454
  const [formInstance] = useForm(formNameOrFormInstance);
338
455
  const value = useFormStore((state) => {
@@ -368,6 +485,7 @@ const useFormItemStateWatch = (nameOrFormItemId, formNameOrFormInstance) => {
368
485
  Form.useForm = useForm;
369
486
  Form.Item = FormItem;
370
487
  Form.useWatch = useWatch;
488
+ Form.useWatchNormalized = useWatchNormalized;
371
489
  Form.useSubmitDataWatch = useSubmitDataWatch;
372
490
  Form.useFormStateWatch = useFormStateWatch;
373
491
  Form.useFormItemStateWatch = useFormItemStateWatch;
@@ -379,5 +497,6 @@ export {
379
497
  useFormItemStateWatch,
380
498
  useFormStateWatch,
381
499
  useSubmitDataWatch,
382
- useWatch
500
+ useWatch,
501
+ useWatchNormalized
383
502
  };
@@ -0,0 +1,3 @@
1
+ type Props = {};
2
+ declare function TestWatchNormalize({}: Props): import("react/jsx-runtime").JSX.Element;
3
+ export default TestWatchNormalize;
@@ -0,0 +1,23 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Input } from "antd";
3
+ import React from "react";
4
+ import Form from "../providers/Form";
5
+ function TestWatchNormalize({}) {
6
+ const normalizeData = Form.useWatchNormalized({
7
+ name: "normalizeItem",
8
+ formNameOrFormInstance: "testNormalize",
9
+ normalizeFn: (value) => {
10
+ if (typeof value === "string") {
11
+ return value.toUpperCase();
12
+ }
13
+ return value;
14
+ }
15
+ });
16
+ React.useEffect(() => {
17
+ }, [normalizeData]);
18
+ return _jsxs(Form, { formName: "testNormalize", children: ["Test Watch Normalize", _jsx(Form.Item, { name: "normalizeItem", children: _jsx(Input, {}) })] });
19
+ }
20
+ var stdin_default = TestWatchNormalize;
21
+ export {
22
+ stdin_default as default
23
+ };
@@ -0,0 +1,21 @@
1
+ type Props = {};
2
+ /**
3
+ * Test Case 10: setFieldValues với Complex Nested Structure
4
+ *
5
+ * Cấu trúc phức tạp:
6
+ * - config.appName (string)
7
+ * - config.version (string)
8
+ * - config.features (array) - deepTrigger
9
+ * - users (FormList array) - deepTrigger
10
+ * - users.0.name (string)
11
+ * - users.0.roles (array) - nested array trong FormList
12
+ *
13
+ * Test: setFieldValues với structure phức tạp nhiều cấp
14
+ *
15
+ * Kỳ vọng:
16
+ * - Primitives trigger onChange
17
+ * - Arrays ở mọi level đều gọi handleDeepTriggerSet
18
+ * - Nested arrays trong FormList được xử lý đúng
19
+ */
20
+ declare function TestCase10_SetFieldValues_ComplexNested({}: Props): import("react/jsx-runtime").JSX.Element;
21
+ export default TestCase10_SetFieldValues_ComplexNested;
@@ -0,0 +1,61 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Box } from "@mui/material";
3
+ import { Button, Input, Typography } from "antd";
4
+ import FormList from "../../components/Form/FormList";
5
+ import Form from "../../providers/Form";
6
+ function TestCase10_SetFieldValues_ComplexNested({}) {
7
+ const [form] = Form.useForm("testCase10");
8
+ const handleTestSetFieldValues = () => {
9
+ form == null ? void 0 : form.setFieldValues({
10
+ config: {
11
+ appName: "My App",
12
+ version: "1.0.0",
13
+ features: ["auth", "api", "ui"]
14
+ },
15
+ users: [
16
+ { name: "John", roles: ["admin", "editor"] },
17
+ { name: "Jane", roles: ["viewer"] }
18
+ ]
19
+ });
20
+ };
21
+ const handleTestUpdateStructure = () => {
22
+ form == null ? void 0 : form.setFieldValues({
23
+ config: {
24
+ appName: "Updated App",
25
+ version: "2.0.0",
26
+ features: ["auth", "api"]
27
+ // removed "ui"
28
+ },
29
+ users: [
30
+ { name: "John", roles: ["admin"] }
31
+ // removed editor role + removed Jane user
32
+ ]
33
+ });
34
+ };
35
+ const handleClear = () => {
36
+ form == null ? void 0 : form.setFieldValues({
37
+ config: {
38
+ appName: "",
39
+ version: "",
40
+ features: []
41
+ },
42
+ users: []
43
+ });
44
+ };
45
+ return _jsxs(Box, { sx: { p: 2 }, children: [_jsx(Typography.Title, { level: 4, children: "Test Case 10: setFieldValues - Complex Nested" }), _jsx(Typography.Paragraph, { children: "Test setFieldValues v\u1EDBi structure ph\u1EE9c t\u1EA1p: nested objects + arrays + FormList" }), _jsxs(Form, { formName: "testCase10", children: [_jsxs(Box, { sx: { border: "2px solid #1890ff", p: 2, mb: 2, borderRadius: 1 }, children: [_jsx(Typography.Text, { strong: true, style: { fontSize: 16 }, children: "Config" }), _jsx(Form.Item, { name: "config.appName", label: "App Name", children: _jsx(Input, { placeholder: "Enter app name" }) }), _jsx(Form.Item, { name: "config.version", label: "Version", children: _jsx(Input, { placeholder: "Enter version" }) }), _jsxs(Box, { sx: { mt: 1 }, children: [_jsx(Typography.Text, { children: "Features (Array):" }), _jsx(Form.Item, { name: "config.features.0", children: _jsx(Input, { placeholder: "Feature 1" }) }), _jsx(Form.Item, { name: "config.features.1", children: _jsx(Input, { placeholder: "Feature 2" }) }), _jsx(Form.Item, { name: "config.features.2", children: _jsx(Input, { placeholder: "Feature 3" }) })] })] }), _jsxs(Box, { sx: { border: "2px solid #52c41a", p: 2, mb: 2, borderRadius: 1 }, children: [_jsx(Typography.Text, { strong: true, style: { fontSize: 16 }, children: "Users (FormList)" }), _jsx(FormList, { name: "users", children: (fields, { add, remove }) => _jsxs(Box, { children: [fields.map((field, index) => _jsxs(Box, { sx: {
46
+ border: "1px dashed #52c41a",
47
+ p: 1,
48
+ mb: 1,
49
+ borderRadius: 1
50
+ }, children: [_jsxs(Typography.Text, { children: ["User ", index + 1] }), _jsx(Form.Item, { name: `users.${index}.name`, label: "Name", children: _jsx(Input, { placeholder: "User name" }) }), _jsxs(Box, { sx: { ml: 2, bgcolor: "#f6ffed", p: 1, borderRadius: 1 }, children: [_jsx(Typography.Text, { children: "Roles (Nested Array):" }), _jsx(Form.Item, { name: `users.${index}.roles.0`, children: _jsx(Input, { placeholder: "Role 1" }) }), _jsx(Form.Item, { name: `users.${index}.roles.1`, children: _jsx(Input, { placeholder: "Role 2" }) })] }), _jsx(Button, { danger: true, size: "small", onClick: () => remove({ key: field.key }), children: "Remove User" })] }, field.key)), _jsx(Button, { type: "dashed", onClick: () => add(), children: "Add User" })] }) })] }), _jsxs(Box, { sx: { mt: 2, display: "flex", gap: 2, flexDirection: "column" }, children: [_jsx(Button, { type: "primary", onClick: handleTestSetFieldValues, children: "1. Set Complex Structure" }), _jsx(Button, { onClick: handleTestUpdateStructure, children: "2. Update with Cleanup" }), _jsx(Button, { danger: true, onClick: handleClear, children: "3. Clear All" })] }), _jsxs(Box, { sx: {
51
+ mt: 2,
52
+ p: 2,
53
+ bgcolor: "#e6fffb",
54
+ border: "1px solid #13c2c2",
55
+ borderRadius: 1
56
+ }, children: [_jsx(Typography.Text, { strong: true, children: "Expected Behavior:" }), _jsxs(Typography.Paragraph, { children: [_jsx("strong", { children: "setFieldValues logic:" }), _jsx("br", {}), "- Traverse object, d\u1EEBng t\u1EA1i m\u1ED7i array", _jsx("br", {}), "- Primitives: trigger onChange", _jsx("br", {}), "- Arrays: g\u1ECDi handleDeepTriggerSet", _jsx("br", {}), _jsx("br", {}), _jsx("strong", { children: "Update with Cleanup:" }), _jsx("br", {}), "- config.features.2 \u2192 undefined (removed)", _jsx("br", {}), "- users.1 \u2192 undefined (Jane removed)", _jsx("br", {}), "- users.0.roles.1 \u2192 undefined (editor removed)"] })] })] })] });
57
+ }
58
+ var stdin_default = TestCase10_SetFieldValues_ComplexNested;
59
+ export {
60
+ stdin_default as default
61
+ };
@@ -0,0 +1,16 @@
1
+ type Props = {};
2
+ /**
3
+ * Test Case 1: Plain Object → Primitive Listeners
4
+ *
5
+ * Cấu trúc:
6
+ * - user.name (string)
7
+ * - user.age (number)
8
+ *
9
+ * Test: setFieldValue("user", {name: "John", age: 30}, {deepTrigger: true})
10
+ * Kỳ vọng:
11
+ * - Trigger "user" listener (nếu có)
12
+ * - Trigger "user.name" listener
13
+ * - Trigger "user.age" listener
14
+ */
15
+ declare function TestCase1_PlainObjectToPrimitives({}: Props): import("react/jsx-runtime").JSX.Element;
16
+ export default TestCase1_PlainObjectToPrimitives;
@@ -0,0 +1,18 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Box } from "@mui/material";
3
+ import { Button, Input, Typography } from "antd";
4
+ import Form from "../../providers/Form";
5
+ function TestCase1_PlainObjectToPrimitives({}) {
6
+ const [form] = Form.useForm("testCase1");
7
+ const handleTestDeepTrigger = () => {
8
+ form == null ? void 0 : form.setFieldValue("user", { name: "John Doe", age: 30 }, { deepTrigger: true });
9
+ };
10
+ const handleTestNormalSet = () => {
11
+ form == null ? void 0 : form.setFieldValue("user", { name: "Jane Doe", age: 25 });
12
+ };
13
+ return _jsxs(Box, { sx: { p: 2 }, children: [_jsx(Typography.Title, { level: 4, children: "Test Case 1: Plain Object \u2192 Primitive Listeners" }), _jsxs(Typography.Paragraph, { children: ['Test setFieldValue("user", ', "{name, age}", ") v\u1EDBi deepTrigger=true"] }), _jsxs(Form, { formName: "testCase1", children: [_jsx(Form.Item, { name: "user", children: _jsx(Input, { placeholder: "User Object (JSON)", disabled: true }) }), _jsx(Form.Item, { name: "user.name", label: "Name", children: _jsx(Input, { placeholder: "Enter name" }) }), _jsx(Form.Item, { name: "user.age", label: "Age", children: _jsx(Input, { type: "number", placeholder: "Enter age" }) }), _jsxs(Box, { sx: { mt: 2, display: "flex", gap: 2 }, children: [_jsx(Button, { type: "primary", onClick: handleTestDeepTrigger, children: "Test Deep Trigger" }), _jsx(Button, { onClick: handleTestNormalSet, children: "Test Normal Set" })] })] })] });
14
+ }
15
+ var stdin_default = TestCase1_PlainObjectToPrimitives;
16
+ export {
17
+ stdin_default as default
18
+ };
@@ -0,0 +1,21 @@
1
+ type Props = {};
2
+ /**
3
+ * Test Case 2: Plain Object → Array Listener (FormList) → Primitives
4
+ *
5
+ * Cấu trúc:
6
+ * - user.name (string)
7
+ * - user.items (array - FormList)
8
+ * - user.items.0.id (number)
9
+ * - user.items.0.title (string)
10
+ *
11
+ * Test: setFieldValue("user", {name: "John", items: [{id: 1, title: "Item 1"}]}, {deepTrigger: true})
12
+ * Kỳ vọng:
13
+ * - Trigger "user" listener
14
+ * - Trigger "user.name" listener
15
+ * - Trigger "user.items" onArrayChange
16
+ * - Trigger "user.items.0" listener
17
+ * - Trigger "user.items.0.id" listener
18
+ * - Trigger "user.items.0.title" listener
19
+ */
20
+ declare function TestCase2_PlainObjectToFormList({}: Props): import("react/jsx-runtime").JSX.Element;
21
+ export default TestCase2_PlainObjectToFormList;
@@ -0,0 +1,33 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Box } from "@mui/material";
3
+ import { Button, Input, Typography } from "antd";
4
+ import FormList from "../../components/Form/FormList";
5
+ import Form from "../../providers/Form";
6
+ function TestCase2_PlainObjectToFormList({}) {
7
+ const [form] = Form.useForm("testCase2");
8
+ const handleTestDeepTrigger = () => {
9
+ form == null ? void 0 : form.setFieldValue("user", {
10
+ name: "John Doe",
11
+ items: [
12
+ { id: 1, title: "Item 1" },
13
+ { id: 2, title: "Item 2" }
14
+ ]
15
+ }, { deepTrigger: true });
16
+ };
17
+ const handleTestNormalSet = () => {
18
+ form == null ? void 0 : form.setFieldValue("user", {
19
+ name: "Jane Doe",
20
+ items: [{ id: 3, title: "Item 3" }]
21
+ });
22
+ };
23
+ return _jsxs(Box, { sx: { p: 2 }, children: [_jsx(Typography.Title, { level: 4, children: "Test Case 2: Plain Object \u2192 FormList \u2192 Primitives" }), _jsxs(Typography.Paragraph, { children: ['Test setFieldValue("user", ', "{name, items: [...]}", ") v\u1EDBi nested FormList"] }), _jsxs(Form, { formName: "testCase2", children: [_jsx(Form.Item, { name: "user.name", label: "User Name", children: _jsx(Input, { placeholder: "Enter user name" }) }), _jsx(FormList, { name: "user.items", children: (fields, { add, remove }) => _jsxs(Box, { children: [fields.map((field, index) => _jsxs(Box, { sx: {
24
+ border: "1px solid #d9d9d9",
25
+ p: 2,
26
+ mb: 2,
27
+ borderRadius: 1
28
+ }, children: [_jsxs(Typography.Text, { strong: true, children: ["Item ", index + 1] }), _jsx(Form.Item, { name: `user.items.${index}.id`, label: "ID", children: _jsx(Input, { placeholder: "Item ID" }) }), _jsx(Form.Item, { name: `user.items.${index}.title`, label: "Title", children: _jsx(Input, { placeholder: "Item title" }) }), _jsx(Button, { danger: true, onClick: () => remove({ key: field.key }), children: "Remove" })] }, field.key)), _jsx(Button, { type: "dashed", onClick: () => add(), children: "Add Item" })] }) }), _jsxs(Box, { sx: { mt: 2, display: "flex", gap: 2 }, children: [_jsx(Button, { type: "primary", onClick: handleTestDeepTrigger, children: "Test Deep Trigger" }), _jsx(Button, { onClick: handleTestNormalSet, children: "Test Normal Set" })] })] })] });
29
+ }
30
+ var stdin_default = TestCase2_PlainObjectToFormList;
31
+ export {
32
+ stdin_default as default
33
+ };
@@ -0,0 +1,21 @@
1
+ type Props = {};
2
+ /**
3
+ * Test Case 3: Array Non-Listener → Primitives
4
+ *
5
+ * Cấu trúc:
6
+ * - data (array - KHÔNG phải FormList, chỉ là field bình thường)
7
+ * - data.0.name (string)
8
+ * - data.0.value (number)
9
+ *
10
+ * Test: setFieldValue("data", [{name: "A", value: 1}, {name: "B", value: 2}], {deepTrigger: true})
11
+ * Kỳ vọng:
12
+ * - Set data array vào store
13
+ * - Trigger "data.0" listener (nếu có)
14
+ * - Trigger "data.0.name" listener
15
+ * - Trigger "data.0.value" listener
16
+ * - Trigger "data.1" listener (nếu có)
17
+ * - Trigger "data.1.name" listener
18
+ * - Trigger "data.1.value" listener
19
+ */
20
+ declare function TestCase3_ArrayNonListenerToPrimitives({}: Props): import("react/jsx-runtime").JSX.Element;
21
+ export default TestCase3_ArrayNonListenerToPrimitives;
@@ -0,0 +1,26 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Box } from "@mui/material";
3
+ import { Button, Input, Typography } from "antd";
4
+ import Form from "../../providers/Form";
5
+ function TestCase3_ArrayNonListenerToPrimitives({}) {
6
+ const [form] = Form.useForm("testCase3");
7
+ const handleTestDeepTrigger = () => {
8
+ form == null ? void 0 : form.setFieldValue("data", [
9
+ { name: "Item A", value: 100 },
10
+ { name: "Item B", value: 200 }
11
+ ], { deepTrigger: true });
12
+ };
13
+ const handleTestRemoveItems = () => {
14
+ form == null ? void 0 : form.setFieldValue("data", [{ name: "Item A", value: 100 }], {
15
+ deepTrigger: true
16
+ });
17
+ };
18
+ const handleTestNormalSet = () => {
19
+ form == null ? void 0 : form.setFieldValue("data", [{ name: "Item C", value: 300 }]);
20
+ };
21
+ return _jsxs(Box, { sx: { p: 2 }, children: [_jsx(Typography.Title, { level: 4, children: "Test Case 3: Array Non-Listener \u2192 Primitives" }), _jsxs(Typography.Paragraph, { children: ['Test setFieldValue("data", ', "[{name, value}, ...]", ") v\u1EDBi array kh\xF4ng ph\u1EA3i FormList"] }), _jsxs(Form, { formName: "testCase3", children: [_jsxs(Box, { sx: { border: "1px solid #d9d9d9", p: 2, mb: 2, borderRadius: 1 }, children: [_jsx(Typography.Text, { strong: true, children: "Item 0" }), _jsx(Form.Item, { name: "data.0.name", label: "Name", children: _jsx(Input, { placeholder: "Item 0 name" }) }), _jsx(Form.Item, { name: "data.0.value", label: "Value", children: _jsx(Input, { type: "number", placeholder: "Item 0 value" }) })] }), _jsxs(Box, { sx: { border: "1px solid #d9d9d9", p: 2, mb: 2, borderRadius: 1 }, children: [_jsx(Typography.Text, { strong: true, children: "Item 1" }), _jsx(Form.Item, { name: "data.1.name", label: "Name", children: _jsx(Input, { placeholder: "Item 1 name" }) }), _jsx(Form.Item, { name: "data.1.value", label: "Value", children: _jsx(Input, { type: "number", placeholder: "Item 1 value" }) })] }), _jsxs(Box, { sx: { mt: 2, display: "flex", gap: 2 }, children: [_jsx(Button, { type: "primary", onClick: handleTestDeepTrigger, children: "Test Deep Trigger (2 items)" }), _jsx(Button, { onClick: handleTestRemoveItems, children: "Test Remove Items (1 item)" }), _jsx(Button, { onClick: handleTestNormalSet, children: "Test Normal Set" })] })] })] });
22
+ }
23
+ var stdin_default = TestCase3_ArrayNonListenerToPrimitives;
24
+ export {
25
+ stdin_default as default
26
+ };
@@ -0,0 +1,20 @@
1
+ type Props = {};
2
+ /**
3
+ * Test Case 4: Plain Object with Removed Fields (Edge Case)
4
+ *
5
+ * Cấu trúc ban đầu:
6
+ * - profile.name (string)
7
+ * - profile.city (string)
8
+ * - profile.country (string)
9
+ *
10
+ * Test:
11
+ * 1. Set initial: {name: "John", city: "NY", country: "USA"}
12
+ * 2. Set removed: {name: "John"} (city và country bị xóa)
13
+ *
14
+ * Kỳ vọng:
15
+ * - Trigger "profile.name" với "John"
16
+ * - Trigger "profile.city" với undefined (cleanup)
17
+ * - Trigger "profile.country" với undefined (cleanup)
18
+ */
19
+ declare function TestCase4_PlainObjectRemovedFields({}: Props): import("react/jsx-runtime").JSX.Element;
20
+ export default TestCase4_PlainObjectRemovedFields;