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.
Files changed (46) hide show
  1. package/CHANGELOG.md +85 -5
  2. package/README.md +8 -4
  3. package/dist/components/Form/FormCleanUp.js +3 -3
  4. package/dist/components/Form/FormItem.d.ts +4 -2
  5. package/dist/components/Form/FormItem.js +7 -5
  6. package/dist/components/Form/FormList.d.ts +2 -2
  7. package/dist/components/Form/FormList.js +2 -2
  8. package/dist/hooks/useFormItemControl.d.ts +1 -0
  9. package/dist/hooks/useFormItemControl.js +60 -23
  10. package/dist/hooks/useFormListControl.d.ts +2 -1
  11. package/dist/hooks/useFormListControl.js +60 -10
  12. package/dist/index.cjs.d.ts +1 -0
  13. package/dist/index.d.ts +4 -3
  14. package/dist/index.esm.d.ts +1 -0
  15. package/dist/index.js +4 -2
  16. package/dist/providers/Form.d.ts +4 -2
  17. package/dist/providers/Form.js +98 -28
  18. package/dist/stores/formStore.d.ts +27 -2
  19. package/dist/stores/formStore.js +25 -9
  20. package/dist/test/TestDialog.d.ts +3 -0
  21. package/dist/test/TestDialog.js +21 -0
  22. package/dist/test/TestListener.d.ts +3 -0
  23. package/dist/test/TestListener.js +17 -0
  24. package/dist/test/TestSelect.d.ts +6 -0
  25. package/dist/test/TestSelect.js +24 -0
  26. package/dist/types/index.d.ts +1 -1
  27. package/dist/types/public.d.ts +6 -1
  28. package/dist/utils/obj.util.d.ts +1 -1
  29. package/dist/utils/obj.util.js +16 -5
  30. package/package.json +3 -1
  31. package/src/App.tsx +98 -4
  32. package/src/components/Form/FormCleanUp.tsx +3 -7
  33. package/src/components/Form/FormItem.tsx +56 -31
  34. package/src/components/Form/FormList.tsx +17 -4
  35. package/src/components/Form/InputWrapper.tsx +5 -0
  36. package/src/hooks/useFormItemControl.ts +70 -29
  37. package/src/hooks/useFormListControl.ts +104 -26
  38. package/src/index.ts +27 -13
  39. package/src/providers/Form.tsx +126 -17
  40. package/src/stores/formStore.ts +319 -288
  41. package/src/test/TestDialog.tsx +52 -0
  42. package/src/test/TestListener.tsx +21 -0
  43. package/src/test/TestSelect.tsx +38 -0
  44. package/src/types/index.ts +1 -1
  45. package/src/types/public.ts +7 -1
  46. package/src/utils/obj.util.ts +44 -13
@@ -1,34 +1,45 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { cloneDeep, get, isEqual, last, set, uniq } from "lodash";
2
+ import { cloneDeep, get, isEqual, isNil, isPlainObject, last, set, uniqBy } from "lodash";
3
3
  import { useTask } from "minh-custom-hooks-release";
4
4
  import { createContext, useContext, useEffect, useState } from "react";
5
5
  import { flushSync } from "react-dom";
6
6
  import { useShallow } from "zustand/react/shallow";
7
7
  import FormCleanUp from "../components/Form/FormCleanUp";
8
- import { useFormListeners, useFormStore } from "../stores/formStore";
8
+ import { SUBMIT_STATE } from "../constants/form";
9
+ import { useFormStore } from "../stores/formStore";
9
10
  import { getAllNoneObjStringPath } from "../utils/obj.util";
10
11
  const FormContext = createContext(null);
11
12
  function Form({ children, formName, initialValues, onFinish, onReject, onFinally, FormElement, ...props }) {
12
- const { appInitValue, getFormItemValue, setInitData, setData, getFormValues, setFormState, setFormInstance, revokeFormInstance, setSubmitHistory, clearFormValues, clearFormInitialValues, clearFormState } = useFormStore(useShallow((state) => {
13
- var _a;
14
- return {
15
- appInitValue: state.initialValues,
16
- setInitData: state.setInitData,
17
- getFormValues: state.getFormValues,
18
- setFormState: state.setFormState,
19
- setFormInstance: state.setFormInstance,
20
- revokeFormInstance: state.revokeFormInstance,
21
- setData: state.setData,
22
- setSubmitHistory: state.setSubmitHistory,
23
- getFormItemValue: state.getFormItemValue,
24
- clearFormValues: state.clearFormValues,
25
- clearFormInitialValues: state.clearFormInitialValues,
26
- clearFormState: state.clearFormState,
27
- // Test, nhớ xóa sau khi xong
28
- formStates: (_a = state.formStates) == null ? void 0 : _a[formName]
29
- };
30
- }));
31
- const { getListeners } = useFormListeners(useShallow((state) => {
13
+ const {
14
+ // appInitValue,
15
+ getFormItemValue,
16
+ setInitData,
17
+ setData,
18
+ getFormValues,
19
+ setFormState,
20
+ setFormInstance,
21
+ revokeFormInstance,
22
+ setSubmitHistory,
23
+ clearFormValues,
24
+ clearFormInitialValues,
25
+ clearFormState
26
+ } = useFormStore(useShallow((state) => ({
27
+ // appInitValue: state.initialValues,
28
+ setInitData: state.setInitData,
29
+ getFormValues: state.getFormValues,
30
+ setFormState: state.setFormState,
31
+ setFormInstance: state.setFormInstance,
32
+ revokeFormInstance: state.revokeFormInstance,
33
+ setData: state.setData,
34
+ setSubmitHistory: state.setSubmitHistory,
35
+ getFormItemValue: state.getFormItemValue,
36
+ clearFormValues: state.clearFormValues,
37
+ clearFormInitialValues: state.clearFormInitialValues,
38
+ clearFormState: state.clearFormState
39
+ // Test, nhớ xóa sau khi xong
40
+ // formStates: state.formStates?.[formName],
41
+ })));
42
+ const { getListeners } = useFormStore(useShallow((state) => {
32
43
  return {
33
44
  getListeners: state.getListeners
34
45
  };
@@ -36,9 +47,36 @@ function Form({ children, formName, initialValues, onFinish, onReject, onFinally
36
47
  const setFieldValue = (name, value, options) => {
37
48
  const listener = getListeners().find((l) => l.name === name && l.formName === formName);
38
49
  if (listener) {
39
- listener.onChange(value, options);
50
+ if (listener.type === "array") {
51
+ if (!isEqual(getFormItemValue(formName, name), value)) {
52
+ listener.onArrayChange(value, options);
53
+ const allStringPath = getAllNoneObjStringPath(value);
54
+ allStringPath.forEach((p) => {
55
+ const findListener = getListeners().find((l) => l.name === `${name}.${p}` && l.formName === formName);
56
+ if (findListener) {
57
+ findListener.onChange(get(value, p), options);
58
+ } else {
59
+ setData(formName, `${name}.${p}`, get(value, p));
60
+ }
61
+ });
62
+ }
63
+ } else {
64
+ listener.onChange(value, options);
65
+ }
40
66
  } else {
41
- setData(formName, name, value);
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
+ }
42
80
  }
43
81
  };
44
82
  const setFieldValues = (values, options = { notTriggerDirty: false }) => {
@@ -46,7 +84,24 @@ function Form({ children, formName, initialValues, onFinish, onReject, onFinally
46
84
  allStringPath.forEach((p) => {
47
85
  const listener = getListeners().find((l) => l.name === p && l.formName === formName);
48
86
  if (listener) {
49
- listener.onChange(get(values, listener.name), options);
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
+ }
50
105
  } else {
51
106
  setData(formName, p, get(values, p));
52
107
  }
@@ -95,7 +150,7 @@ function Form({ children, formName, initialValues, onFinish, onReject, onFinally
95
150
  const formValues = getFormValues(formName);
96
151
  const resultValues = cloneDeep(formValues);
97
152
  const cleanValues = {};
98
- uniq(listeners, (l) => l.name).forEach((l) => {
153
+ uniqBy(listeners, (l) => l.name).forEach((l) => {
99
154
  set(cleanValues, l.name, get(resultValues, l.name));
100
155
  });
101
156
  const handleIsolateCase = async () => {
@@ -167,7 +222,8 @@ function Form({ children, formName, initialValues, onFinish, onReject, onFinally
167
222
  reset();
168
223
  flushSync(setFormState({
169
224
  formName,
170
- isInitied: false
225
+ isInitied: false,
226
+ submitState: SUBMIT_STATE.IDLE
171
227
  }));
172
228
  const totalListenerFields = getListeners();
173
229
  if (Array.isArray(resetOptions)) {
@@ -252,7 +308,8 @@ function useFormContext() {
252
308
  return c;
253
309
  }
254
310
  function useForm(formNameOrFormInstance) {
255
- const targetFormName = typeof formNameOrFormInstance === "object" && formNameOrFormInstance !== null ? formNameOrFormInstance.formName : formNameOrFormInstance;
311
+ const formContext = useContext(FormContext);
312
+ const targetFormName = isNil(formNameOrFormInstance) ? formContext == null ? void 0 : formContext.formName : typeof formNameOrFormInstance === "object" && formNameOrFormInstance !== null ? formNameOrFormInstance.formName : formNameOrFormInstance;
256
313
  const formInstance = useFormStore((state) => {
257
314
  return state.formInstances.find((i) => i.formName === targetFormName);
258
315
  });
@@ -287,15 +344,28 @@ const useFormStateWatch = (formNameOrFormInstance) => {
287
344
  });
288
345
  return formState;
289
346
  };
347
+ const useFormItemStateWatch = (nameOrFormItemId, formNameOrFormInstance) => {
348
+ const [formInstance] = useForm(formNameOrFormInstance);
349
+ const listener = useFormStore((state) => {
350
+ return state.getListeners().find((l) => l.formName === (formInstance == null ? void 0 : formInstance.formName) && (l.name === nameOrFormItemId || l.formItemId === nameOrFormItemId));
351
+ });
352
+ return {
353
+ isTouched: listener == null ? void 0 : listener.isTouched,
354
+ isDirty: listener == null ? void 0 : listener.isDirty,
355
+ errors: (listener == null ? void 0 : listener.internalErrors) || []
356
+ };
357
+ };
290
358
  Form.useForm = useForm;
291
359
  Form.useWatch = useWatch;
292
360
  Form.useSubmitDataWatch = useSubmitDataWatch;
293
361
  Form.useFormStateWatch = useFormStateWatch;
362
+ Form.useFormItemStateWatch = useFormItemStateWatch;
294
363
  export {
295
364
  FormContext,
296
365
  Form as default,
297
366
  useForm,
298
367
  useFormContext,
368
+ useFormItemStateWatch,
299
369
  useFormStateWatch,
300
370
  useSubmitDataWatch,
301
371
  useWatch
@@ -1,3 +1,4 @@
1
+ type ListenerFormItemType = "normal" | "array";
1
2
  export interface FormInstance {
2
3
  formName: string;
3
4
  resetFields: (values?: any) => void;
@@ -13,6 +14,28 @@ export interface FormInstance {
13
14
  getFieldErrors: () => Record<string, any>;
14
15
  setFieldFocus: (name: string) => void;
15
16
  }
17
+ export interface ListenerItem {
18
+ name?: string;
19
+ formName?: string;
20
+ isTouched?: boolean;
21
+ isDirty?: boolean;
22
+ formItemId?: string;
23
+ internalErrors?: any;
24
+ onArrayChange?: any;
25
+ onChange?: any;
26
+ onReset?: any;
27
+ onFocus?: any;
28
+ emitFocus?: any;
29
+ isInitied?: boolean;
30
+ type?: ListenerFormItemType;
31
+ }
32
+ export interface CleanUpItem {
33
+ name?: string;
34
+ type?: string;
35
+ key: string;
36
+ itemKey?: string;
37
+ formName?: string;
38
+ }
16
39
  interface FormStoreState {
17
40
  forms: Record<string, any>;
18
41
  initialValues: Record<string, any>;
@@ -20,9 +43,11 @@ interface FormStoreState {
20
43
  cacheData: Record<string, any>;
21
44
  formInstances: FormInstance[];
22
45
  submitHistory: Record<string, any[]>;
46
+ listeners: ListenerItem[];
47
+ cleanUpStack: CleanUpItem[];
23
48
  [key: string]: any;
24
49
  }
25
50
  export declare const useFormStore: import("zustand").UseBoundStore<import("zustand").StoreApi<FormStoreState>>;
26
- export declare const useFormListeners: import("zustand").UseBoundStore<import("zustand").StoreApi<any>>;
27
- export declare const useFormCleanUp: import("zustand").UseBoundStore<import("zustand").StoreApi<any>>;
51
+ export declare const useFormListeners: import("zustand").UseBoundStore<import("zustand").StoreApi<FormStoreState>>;
52
+ export declare const useFormCleanUp: import("zustand").UseBoundStore<import("zustand").StoreApi<FormStoreState>>;
28
53
  export {};
@@ -3,7 +3,7 @@ import { cloneDeep, get, isNil, isNumber, last, set, unset } from "lodash";
3
3
  import { v4 } from "uuid";
4
4
  import { create } from "zustand";
5
5
  import { getAllNoneObjStringPath } from "../utils/obj.util";
6
- const useFormStore = create((storeSet, storeGet) => ({
6
+ const createFormStoreSlice = (storeSet, storeGet, api) => ({
7
7
  forms: {},
8
8
  initialValues: {},
9
9
  formStates: {},
@@ -191,8 +191,8 @@ const useFormStore = create((storeSet, storeGet) => ({
191
191
  }
192
192
  }));
193
193
  }
194
- }));
195
- const useFormListeners = create((storeSet, storeGet) => ({
194
+ });
195
+ const createListenersSlice = (storeSet, storeGet, api) => ({
196
196
  listeners: [],
197
197
  getListener(formItemId) {
198
198
  return storeGet().listeners.find((l) => l.formItemId === formItemId);
@@ -200,7 +200,7 @@ const useFormListeners = create((storeSet, storeGet) => ({
200
200
  getListeners() {
201
201
  return storeGet().listeners;
202
202
  },
203
- setListener({ formName, name, onChange, onReset, isTouched, isDirty, formItemId, internalErrors, onFocus, emitFocus }) {
203
+ setListener({ formName, name, onChange, onReset, isTouched, isDirty, formItemId, internalErrors, onFocus, emitFocus, isInitied, type, onArrayChange }) {
204
204
  return storeSet(produce((state) => {
205
205
  const storeListeners = state.listeners;
206
206
  const findListenerIndex = state.listeners.findIndex((l) => l.formItemId === formItemId);
@@ -232,17 +232,26 @@ const useFormListeners = create((storeSet, storeGet) => ({
232
232
  if (!isNil(emitFocus)) {
233
233
  storeListeners[findListenerIndex].emitFocus = emitFocus;
234
234
  }
235
+ if (!isNil(isInitied)) {
236
+ storeListeners[findListenerIndex].isInitied = isInitied;
237
+ }
238
+ if (!isNil(onArrayChange)) {
239
+ storeListeners[findListenerIndex].onArrayChange = onArrayChange;
240
+ }
235
241
  return;
236
242
  }
237
243
  storeListeners.push({
238
244
  name,
239
245
  formName,
240
- isTouched,
241
- isDirty,
246
+ isTouched: Boolean(isTouched),
247
+ isDirty: Boolean(isDirty),
242
248
  formItemId,
243
249
  internalErrors,
244
250
  onChange,
245
- onReset
251
+ onReset,
252
+ isInitied: Boolean(isInitied),
253
+ type: type || "normal",
254
+ onArrayChange
246
255
  });
247
256
  }));
248
257
  },
@@ -257,8 +266,8 @@ const useFormListeners = create((storeSet, storeGet) => ({
257
266
  }
258
267
  }));
259
268
  }
260
- }));
261
- const useFormCleanUp = create((storeSet) => ({
269
+ });
270
+ const createCleanUpSlice = (storeSet, storeGet, api) => ({
262
271
  cleanUpStack: [],
263
272
  setCleanUpStack({ name, type, itemKey, formName }) {
264
273
  return storeSet(produce((state) => {
@@ -272,7 +281,14 @@ const useFormCleanUp = create((storeSet) => ({
272
281
  state.cleanUpStack = [];
273
282
  }));
274
283
  }
284
+ });
285
+ const useFormStore = create((...a) => ({
286
+ ...createFormStoreSlice(...a),
287
+ ...createListenersSlice(...a),
288
+ ...createCleanUpSlice(...a)
275
289
  }));
290
+ const useFormListeners = useFormStore;
291
+ const useFormCleanUp = useFormStore;
276
292
  export {
277
293
  useFormCleanUp,
278
294
  useFormListeners,
@@ -0,0 +1,3 @@
1
+ type Props = {};
2
+ declare function TestDialog({}: Props): import("react/jsx-runtime").JSX.Element;
3
+ export default TestDialog;
@@ -0,0 +1,21 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Button, Dialog, DialogContent, DialogContentText, DialogTitle, TextField } from "@mui/material";
3
+ import { Box } from "@mui/system";
4
+ import { useToggle } from "minh-custom-hooks-release";
5
+ import FormItem from "../components/Form/FormItem";
6
+ import TestSelect from "./TestSelect";
7
+ function TestDialog({}) {
8
+ const { state: open, toggle } = useToggle();
9
+ return _jsxs(Box, { children: [_jsxs(Dialog, { open, onClose: toggle, children: [_jsx(DialogTitle, { children: "Test Dialog" }), _jsxs(DialogContent, { children: [_jsx(DialogContentText, { children: "This is a test dialog." }), _jsx(FormItem, { rules: [
10
+ {
11
+ handler(value) {
12
+ return Boolean(value);
13
+ },
14
+ message: "Testt"
15
+ }
16
+ ], controlAfterInit: true, initialValue: null, name: "testSelectInsideDialog", children: _jsx(TestSelect, {}) }), _jsx(FormItem, { controlAfterInit: true, initialValue: "", name: "anotherField", children: _jsx(TextField, {}) })] })] }), _jsx(Button, { variant: "contained", onClick: toggle, children: "Open Test Dialog" })] });
17
+ }
18
+ var stdin_default = TestDialog;
19
+ export {
20
+ stdin_default as default
21
+ };
@@ -0,0 +1,3 @@
1
+ type Props = {};
2
+ declare function TestListener({}: Props): import("react/jsx-runtime").JSX.Element;
3
+ export default TestListener;
@@ -0,0 +1,17 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { cloneDeep } from "lodash";
3
+ import { useEffect } from "react";
4
+ import { useShallow } from "zustand/react/shallow";
5
+ import { useFormStore } from "../stores/formStore";
6
+ function TestListener({}) {
7
+ const { listeners } = useFormStore(useShallow((state) => ({
8
+ listeners: state.listeners
9
+ })));
10
+ useEffect(() => {
11
+ }, [listeners]);
12
+ return _jsx("div", { children: "TestListener" });
13
+ }
14
+ var stdin_default = TestListener;
15
+ export {
16
+ stdin_default as default
17
+ };
@@ -0,0 +1,6 @@
1
+ type Props = {
2
+ value?: any;
3
+ onChange?: (value: any) => void;
4
+ };
5
+ declare function TestSelect({ value, onChange }: Props): import("react/jsx-runtime").JSX.Element;
6
+ export default TestSelect;
@@ -0,0 +1,24 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { Autocomplete, TextField } from "@mui/material";
3
+ function TestSelect({ value = null, onChange }) {
4
+ return _jsx(Autocomplete, { value, onChange: (_, newValue) => {
5
+ onChange == null ? void 0 : onChange(newValue);
6
+ }, renderInput: (params) => _jsx(TextField, { ...params }), options: [
7
+ {
8
+ value: "option1",
9
+ label: "Option 1"
10
+ },
11
+ {
12
+ value: "option2",
13
+ label: "Option 2"
14
+ }
15
+ ], getOptionKey: (o) => {
16
+ return o == null ? void 0 : o.value;
17
+ }, getOptionLabel: (o) => {
18
+ return o == null ? void 0 : o.label;
19
+ } });
20
+ }
21
+ var stdin_default = TestSelect;
22
+ export {
23
+ stdin_default as default
24
+ };
@@ -1 +1 @@
1
- export * from './public';
1
+ export * from "./public";
@@ -1,5 +1,5 @@
1
- import type { GetConstantType } from "./util";
2
1
  import type { SUBMIT_STATE } from "../constants/form";
2
+ import type { GetConstantType } from "./util";
3
3
  export type FormValues<T = any> = T;
4
4
  export interface FormFieldError {
5
5
  ruleName: string | number;
@@ -61,6 +61,11 @@ export interface UseFormItemReturn<T = any> {
61
61
  isDirty?: boolean;
62
62
  submitState?: SubmitState;
63
63
  }
64
+ export interface UseFormItemStateWatchReturn {
65
+ isTouched?: boolean;
66
+ isDirty?: boolean;
67
+ errors: FormFieldError[];
68
+ }
64
69
  export interface UseFormListProps<T = any> {
65
70
  name?: string;
66
71
  form?: PublicFormInstance<T>;
@@ -1,2 +1,2 @@
1
- export declare function getAllNoneObjStringPath(value: any, prevPath?: string): any;
1
+ export declare function getAllNoneObjStringPath(value: any, prevPath?: string): string[];
2
2
  export declare function getAllStringPath(value: any, prevPath?: string): any;
@@ -1,14 +1,25 @@
1
- import { filter, isNil, join } from "lodash";
1
+ import { filter, isNil, isPlainObject, join } from "lodash";
2
2
  function getAllNoneObjStringPath(value, prevPath = "") {
3
- if (typeof value === "object") {
4
- return Object.keys(value).reduce((prev, cur) => {
3
+ if (value === null || value === void 0 || typeof value !== "object" || typeof value === "function") {
4
+ return [prevPath];
5
+ }
6
+ if (Array.isArray(value)) {
7
+ return value.reduce((prev, item, index) => {
5
8
  return [
6
9
  ...prev,
7
- ...getAllNoneObjStringPath(value[cur], join(filter([prevPath, cur], (v) => !isNil(v) && v !== ""), "."))
10
+ ...getAllNoneObjStringPath(item, join(filter([prevPath, String(index)], (v) => !isNil(v) && v !== ""), "."))
8
11
  ];
9
12
  }, []);
10
13
  }
11
- return [prevPath];
14
+ if (!isPlainObject(value)) {
15
+ return [prevPath];
16
+ }
17
+ return Object.keys(value).reduce((prev, cur) => {
18
+ return [
19
+ ...prev,
20
+ ...getAllNoneObjStringPath(value[cur], join(filter([prevPath, cur], (v) => !isNil(v) && v !== ""), "."))
21
+ ];
22
+ }, []);
12
23
  }
13
24
  function getAllStringPath(value, prevPath = "") {
14
25
  if (typeof value === "object") {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-form-manage",
3
- "version": "1.0.8-beta.2",
3
+ "version": "1.0.8-beta.21",
4
4
  "description": "Lightweight React form management with list and listener support.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -36,6 +36,7 @@
36
36
  "@emotion/styled": "^11.14.1",
37
37
  "@eslint/js": "^9.14.0",
38
38
  "@mui/material": "^7.3.7",
39
+ "@types/lodash": "^4.17.23",
39
40
  "@types/node": "^22.9.3",
40
41
  "@types/react": "^19.2.9",
41
42
  "@types/react-dom": "^19.2.3",
@@ -45,6 +46,7 @@
45
46
  "eslint": "^9.14.0",
46
47
  "eslint-plugin-react-hooks": "^5.1.0",
47
48
  "eslint-plugin-react-refresh": "^0.4.14",
49
+ "framer-motion": "^12.29.0",
48
50
  "globals": "^15.12.0",
49
51
  "react": "^19.0.0",
50
52
  "react-dom": "^19.0.0",
package/src/App.tsx CHANGED
@@ -1,13 +1,26 @@
1
+ import { Checkbox } from "@mui/material";
1
2
  import { Button, Input } from "antd";
3
+ import { motion } from "framer-motion";
2
4
  import { useEffect } from "react";
3
5
  import FormItem from "./components/Form/FormItem";
4
6
  import FormList from "./components/Form/FormList";
5
7
  import InputWrapper from "./components/Form/InputWrapper";
6
8
  import Form, { useForm } from "./providers/Form";
9
+ import TestDialog from "./test/TestDialog";
10
+
11
+ import { Form as AntdForm } from "antd";
12
+
13
+ function TestFormWatch() {
14
+ const watchValue = Form.useWatch("numericCode");
15
+
16
+ return <div>TestFormWatch</div>;
17
+ }
7
18
 
8
19
  const App = () => {
9
20
  const [form] = useForm("form1");
10
21
 
22
+ const watchCheckBox = Form.useWatch("checkControlledAfterInit", "form1");
23
+
11
24
  useEffect(() => {
12
25
  if (form) {
13
26
  // setTimeout(() => {
@@ -17,16 +30,31 @@ const App = () => {
17
30
  }, [form]);
18
31
  return (
19
32
  <div>
33
+ <AntdForm>
34
+ <motion.div
35
+ initial={{ opacity: 0 }}
36
+ animate={{ opacity: 1 }}
37
+ exit={{ opacity: 0 }}
38
+ transition={{ duration: 1 }}
39
+ >
40
+ <AntdForm.Item name={"234"} initialValue={"23432"} label="Antd Input">
41
+ <Input />
42
+ </AntdForm.Item>
43
+ </motion.div>
44
+ </AntdForm>
45
+
46
+ {/* Hidden Test */}
20
47
  <Form
21
48
  initialValues={{
22
49
  TestData: "",
23
50
  numericCode: "",
24
- arr: [{ el: "Item 1" }, { el: "Item 2" }],
51
+ // arr: [{ el: "Item 1" }, { el: "Item 2" }],
25
52
  }}
26
53
  onFinish={(values) => {
27
54
  console.log(values);
28
55
  }}
29
56
  formName={"form1"}
57
+ // hidden
30
58
  >
31
59
  <FormItem
32
60
  name={"username"}
@@ -36,12 +64,15 @@ const App = () => {
36
64
  message: "Test",
37
65
  },
38
66
  ]}
67
+ initialValue={"283746"}
68
+ // hidden
39
69
  >
40
70
  <InputWrapper>
41
71
  <Input />
42
72
  </InputWrapper>
43
73
  </FormItem>
44
74
 
75
+ {/* Numberic test */}
45
76
  <FormItem
46
77
  name={"numericCode"}
47
78
  rules={[
@@ -56,10 +87,25 @@ const App = () => {
56
87
  <Input placeholder="Mã chỉ gồm số" style={{ width: 200 }} />
57
88
  </InputWrapper>
58
89
  </FormItem>
90
+
91
+ {/* Motion Test */}
92
+ <motion.div
93
+ initial={{ opacity: 0 }}
94
+ animate={{ opacity: 1 }}
95
+ exit={{ opacity: 0 }}
96
+ transition={{ duration: 1 }}
97
+ >
98
+ <FormItem name="motionTest" controlAfterInit initialValue={"1234134"}>
99
+ <InputWrapper>
100
+ <Input placeholder="Motion Test" style={{ width: 200 }} />
101
+ </InputWrapper>
102
+ </FormItem>
103
+ </motion.div>
59
104
  <FormList
60
105
  initialValues={[
61
106
  {
62
- el: "",
107
+ el: "sdfsdf",
108
+ d: { child: "Test Child" },
63
109
  },
64
110
  ]}
65
111
  name="arr"
@@ -68,7 +114,15 @@ const App = () => {
68
114
  <div>
69
115
  {fields.map((field, index) => (
70
116
  <div key={field.key} style={{ marginBottom: 8 }}>
71
- <FormItem name={`${field.name}.el`}>
117
+ <FormItem name={`${field.name}.el`} initialValue={"Chém gió"}>
118
+ <InputWrapper>
119
+ <Input placeholder="Item value" style={{ width: 200 }} />
120
+ </InputWrapper>
121
+ </FormItem>
122
+ <FormItem
123
+ name={`${field.name}.d.child`}
124
+ initialValue={"Con của item"}
125
+ >
72
126
  <InputWrapper>
73
127
  <Input placeholder="Item value" style={{ width: 200 }} />
74
128
  </InputWrapper>
@@ -101,12 +155,52 @@ const App = () => {
101
155
  </div>
102
156
  )}
103
157
  </FormList>
158
+ <TestDialog />
159
+ <Button
160
+ onClick={() => {
161
+ form?.setFieldValue("arr", [
162
+ { el: "Set Item 1" },
163
+ { el: "Set Item 2" },
164
+ { el: "Set Item 3" },
165
+ ]);
166
+ }}
167
+ >
168
+ Test set array list value
169
+ </Button>
170
+ <motion.div
171
+ initial={{ opacity: 0 }}
172
+ animate={{ opacity: 1 }}
173
+ exit={{ opacity: 0 }}
174
+ transition={{ duration: 1.5 }}
175
+ >
176
+ <FormItem
177
+ valuePropName="checked"
178
+ getValueFromEvent={(_, checked) => checked}
179
+ name="checkControlledAfterInit"
180
+ controlAfterInit={true}
181
+ initialValue={true}
182
+ >
183
+ <Checkbox />
184
+ </FormItem>
185
+ </motion.div>
186
+ <TestFormWatch />
187
+ <Button
188
+ onClick={() => {
189
+ const current = form?.getFieldValue("checkControlledAfterInit");
190
+ console.log("Toggle controlled after init: ", current);
191
+ form?.setFieldValue("checkControlledAfterInit", !current);
192
+ }}
193
+ >
194
+ Toggle
195
+ </Button>
104
196
  <Button htmlType="submit">Submit</Button>
105
197
  <Button
106
198
  onClick={() => {
107
199
  form?.resetFields?.();
108
200
  }}
109
- ></Button>
201
+ >
202
+ Reset
203
+ </Button>
110
204
  </Form>
111
205
  </div>
112
206
  );