react-form-manage 1.0.8-beta.22 → 1.0.8-beta.24

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.
@@ -1,5 +1,6 @@
1
1
  import {
2
2
  cloneDeep,
3
+ filter,
3
4
  get,
4
5
  isEqual,
5
6
  isNil,
@@ -14,8 +15,9 @@ import { createContext, useContext, useEffect, useState } from "react";
14
15
  import { flushSync } from "react-dom";
15
16
  import { useShallow } from "zustand/react/shallow"; // Import useShallow
16
17
  import FormCleanUp from "../components/Form/FormCleanUp";
18
+ import FormItem from "../components/Form/FormItem";
17
19
  import { SUBMIT_STATE } from "../constants/form";
18
- import { ListenerItem, useFormStore } from "../stores/formStore";
20
+ import { ListenerItem, SubmitProps, useFormStore } from "../stores/formStore";
19
21
  import type {
20
22
  PublicFormInstance,
21
23
  UseFormItemStateWatchReturn,
@@ -34,6 +36,7 @@ export interface FormProps<T = any> extends Omit<
34
36
  FormHTMLAttributes<HTMLFormElement>,
35
37
  "onSubmit"
36
38
  > {
39
+ collectHiddenFields?: boolean;
37
40
  children: ReactNode;
38
41
  formName: string;
39
42
  initialValues?: T;
@@ -55,6 +58,7 @@ export default function Form<T = any>({
55
58
  onReject,
56
59
  onFinally,
57
60
  FormElement,
61
+ collectHiddenFields: formCollectHiddenFields = true,
58
62
  ...props
59
63
  }: FormProps<T>) {
60
64
  const {
@@ -236,16 +240,36 @@ export default function Form<T = any>({
236
240
  state: _,
237
241
  reset,
238
242
  } = useTask({
239
- async task(props) {
243
+ async task(props?: SubmitProps<T>) {
240
244
  try {
241
245
  flushSync(setFormState({ formName, submitState: "submitting" }));
242
246
  const errorFields = getAllFieldErrors();
243
- const listeners = getListeners().filter((l) => l.formName === formName);
247
+ const listeners: ListenerItem[] = getListeners().filter(
248
+ (l) => l.formName === formName,
249
+ );
244
250
  const formValues = getFormValues(formName);
245
251
 
246
252
  const resultValues = cloneDeep(formValues);
247
253
  const cleanValues = {} as T;
248
- uniqBy(listeners, (l: any) => l.name).forEach((l) => {
254
+ uniqBy(
255
+ filter(listeners, (l: ListenerItem) => {
256
+ // console.log("Check collect field hidden: ", {
257
+ // name: l.name,
258
+ // hidden: l.hidden,
259
+ // collectOnHidden: l.collectOnHidden,
260
+ // collectHiddenFields,
261
+ // });
262
+ if (!l.hidden) return true;
263
+ if (isNil(props?.collectHiddenFields)) {
264
+ if (isNil(l.collectOnHidden)) {
265
+ return formCollectHiddenFields;
266
+ }
267
+ return Boolean(l.collectOnHidden);
268
+ }
269
+ return props.collectHiddenFields;
270
+ }),
271
+ (l) => l.name,
272
+ ).forEach((l) => {
249
273
  set(cleanValues as any, l.name, get(resultValues, l.name));
250
274
  });
251
275
 
@@ -443,6 +467,8 @@ export default function Form<T = any>({
443
467
  formName,
444
468
  }}
445
469
  >
470
+ <FormCleanUp />
471
+
446
472
  {FormElement ? (
447
473
  <FormElement
448
474
  onSubmit={(e) => {
@@ -468,7 +494,6 @@ export default function Form<T = any>({
468
494
  {children}
469
495
  </form>
470
496
  )}
471
- <FormCleanUp />
472
497
  </FormContext.Provider>
473
498
  );
474
499
  }
@@ -581,6 +606,7 @@ export const useFormItemStateWatch = <T = any,>(
581
606
  };
582
607
 
583
608
  Form.useForm = useForm;
609
+ Form.Item = FormItem;
584
610
  Form.useWatch = useWatch;
585
611
  Form.useSubmitDataWatch = useSubmitDataWatch;
586
612
  Form.useFormStateWatch = useFormStateWatch;
@@ -4,10 +4,25 @@ import { v4 } from "uuid";
4
4
  import { create } from "zustand";
5
5
  import { getAllNoneObjStringPath } from "../utils/obj.util";
6
6
  type ListenerFormItemType = "normal" | "array";
7
- export interface FormInstance {
7
+
8
+ export interface SubmitProps<T = any> {
9
+ externalFinishCallback?: (values: T, allValues?: any) => void | Promise<void>;
10
+ externalRejectCallback?: (errorFields: any[]) => void | Promise<void>;
11
+ externalFinallyCallback?: (result: {
12
+ errorsField: any[];
13
+ values: T;
14
+ withUnRegisteredValues: any;
15
+ }) => void | Promise<void>;
16
+ callBothFinish?: boolean;
17
+ callBothReject?: boolean;
18
+ callBothFinally?: boolean;
19
+ collectHiddenFields?: boolean;
20
+ }
21
+
22
+ export interface FormInstance<T = any> {
8
23
  formName: string;
9
24
  resetFields: (values?: any) => void;
10
- submit: (values?: any) => void;
25
+ submit: (props?: SubmitProps<T>) => void;
11
26
  submitAsync: (values?: any) => Promise<any>;
12
27
  setFieldValue: (name: string, value: any, options?: any) => void;
13
28
  setFieldValues: (values: Record<string, any>, options?: any) => void;
@@ -31,6 +46,8 @@ export interface ListenerItem {
31
46
  emitFocus?: any;
32
47
  isInitied?: boolean;
33
48
  type?: ListenerFormItemType;
49
+ hidden?: boolean;
50
+ collectOnHidden?: boolean;
34
51
  }
35
52
 
36
53
  export interface CleanUpItem {
@@ -362,7 +379,7 @@ const createFormStoreSlice = (storeSet: any, storeGet: any, api: any) => ({
362
379
 
363
380
  // Listeners Slice
364
381
  const createListenersSlice = (storeSet: any, storeGet: any, api: any) => ({
365
- listeners: [],
382
+ listeners: [] as ListenerItem[],
366
383
  getListener(formItemId) {
367
384
  return storeGet().listeners.find((l) => l.formItemId === formItemId);
368
385
  },
@@ -383,6 +400,8 @@ const createListenersSlice = (storeSet: any, storeGet: any, api: any) => ({
383
400
  isInitied,
384
401
  type,
385
402
  onArrayChange,
403
+ hidden,
404
+ collectOnHidden,
386
405
  }: Partial<ListenerItem> & { formItemId: string }) {
387
406
  return storeSet(
388
407
  produce<any>((state: any) => {
@@ -428,6 +447,14 @@ const createListenersSlice = (storeSet: any, storeGet: any, api: any) => ({
428
447
  storeListeners[findListenerIndex].onArrayChange = onArrayChange;
429
448
  }
430
449
 
450
+ if (!isNil(hidden)) {
451
+ storeListeners[findListenerIndex].hidden = hidden;
452
+ }
453
+
454
+ if (!isNil(collectOnHidden)) {
455
+ storeListeners[findListenerIndex].collectOnHidden = collectOnHidden;
456
+ }
457
+
431
458
  return;
432
459
  }
433
460
  storeListeners.push({
@@ -442,6 +469,10 @@ const createListenersSlice = (storeSet: any, storeGet: any, api: any) => ({
442
469
  isInitied: Boolean(isInitied),
443
470
  type: type || "normal",
444
471
  onArrayChange,
472
+ onFocus,
473
+ emitFocus,
474
+ hidden: Boolean(hidden),
475
+ collectOnHidden,
445
476
  });
446
477
  }),
447
478
  );
@@ -0,0 +1,177 @@
1
+ import { Button, Checkbox, Input } from "antd";
2
+ import { motion } from "framer-motion";
3
+ import FormItem from "../components/Form/FormItem";
4
+ import FormList from "../components/Form/FormList";
5
+ import InputWrapper from "../components/Form/InputWrapper";
6
+ import Form from "../providers/Form";
7
+
8
+ type Props = {};
9
+
10
+ function CommonTest({}: Props) {
11
+ const [form] = Form.useForm("form1");
12
+
13
+ const watchCheckBox = Form.useWatch("checkControlledAfterInit", "form1");
14
+
15
+ return (
16
+ <Form
17
+ initialValues={{
18
+ TestData: "",
19
+ numericCode: "",
20
+ // arr: [{ el: "Item 1" }, { el: "Item 2" }],
21
+ }}
22
+ onFinish={(values) => {
23
+ console.log(values);
24
+ }}
25
+ formName={"form1"}
26
+ // hidden
27
+ >
28
+ <FormItem
29
+ name={"username"}
30
+ rules={[
31
+ {
32
+ required: true,
33
+ message: "Test",
34
+ },
35
+ ]}
36
+ initialValue={"283746"}
37
+ // hidden
38
+ >
39
+ <InputWrapper>
40
+ <Input />
41
+ </InputWrapper>
42
+ </FormItem>
43
+
44
+ {/* Numberic test */}
45
+ <FormItem
46
+ name={"numericCode"}
47
+ rules={[
48
+ { required: true, message: "Vui lòng nhập mã" },
49
+ {
50
+ pattern: /^\d+$/,
51
+ message: "Chỉ cho phép chuỗi số",
52
+ },
53
+ ]}
54
+ >
55
+ <InputWrapper>
56
+ <Input placeholder="Mã chỉ gồm số" style={{ width: 200 }} />
57
+ </InputWrapper>
58
+ </FormItem>
59
+
60
+ {/* Motion Test */}
61
+ <motion.div
62
+ initial={{ opacity: 0 }}
63
+ animate={{ opacity: 1 }}
64
+ exit={{ opacity: 0 }}
65
+ transition={{ duration: 1 }}
66
+ >
67
+ <FormItem name="motionTest" controlAfterInit initialValue={"1234134"}>
68
+ <InputWrapper>
69
+ <Input placeholder="Motion Test" style={{ width: 200 }} />
70
+ </InputWrapper>
71
+ </FormItem>
72
+ </motion.div>
73
+ <FormList
74
+ initialValues={[
75
+ {
76
+ el: "sdfsdf",
77
+ d: { child: "Test Child" },
78
+ },
79
+ ]}
80
+ name="arr"
81
+ >
82
+ {(fields, { add, remove, move }) => (
83
+ <div>
84
+ {fields.map((field, index) => (
85
+ <div key={field.key} style={{ marginBottom: 8 }}>
86
+ <FormItem name={`${field.name}.el`} initialValue={"Chém gió"}>
87
+ <InputWrapper>
88
+ <Input placeholder="Item value" style={{ width: 200 }} />
89
+ </InputWrapper>
90
+ </FormItem>
91
+ <FormItem
92
+ name={`${field.name}.d.child`}
93
+ initialValue={"Con của item"}
94
+ >
95
+ <InputWrapper>
96
+ <Input placeholder="Item value" style={{ width: 200 }} />
97
+ </InputWrapper>
98
+ </FormItem>
99
+ <Button
100
+ onClick={() => remove({ index })}
101
+ style={{ marginLeft: 8 }}
102
+ >
103
+ Remove
104
+ </Button>
105
+ {index > 0 && (
106
+ <Button
107
+ onClick={() => move({ from: index, to: index - 1 })}
108
+ style={{ marginLeft: 8 }}
109
+ >
110
+ Move Up
111
+ </Button>
112
+ )}
113
+ {index < fields.length - 1 && (
114
+ <Button
115
+ onClick={() => move({ from: index, to: index + 1 })}
116
+ style={{ marginLeft: 8 }}
117
+ >
118
+ Move Down
119
+ </Button>
120
+ )}
121
+ </div>
122
+ ))}
123
+ <Button onClick={() => add(fields.length)}>Add Item</Button>
124
+ </div>
125
+ )}
126
+ </FormList>
127
+ <Button
128
+ onClick={() => {
129
+ form?.setFieldValue("arr", [
130
+ { el: "Set Item 1" },
131
+ { el: "Set Item 2" },
132
+ { el: "Set Item 3" },
133
+ ]);
134
+ }}
135
+ >
136
+ Test set array list value
137
+ </Button>
138
+ <motion.div
139
+ initial={{ opacity: 0 }}
140
+ animate={{ opacity: 1 }}
141
+ exit={{ opacity: 0 }}
142
+ transition={{ duration: 1.5 }}
143
+ >
144
+ <Form.Item
145
+ valuePropName="checked"
146
+ getValueFromEvent={(_, checked) => checked}
147
+ name="checkControlledAfterInit"
148
+ controlAfterInit={true}
149
+ initialValue={true}
150
+ hidden
151
+ >
152
+ <Checkbox />
153
+ </Form.Item>
154
+ </motion.div>
155
+ {/* <TestFormWatch /> */}
156
+ <Button
157
+ onClick={() => {
158
+ const current = form?.getFieldValue("checkControlledAfterInit");
159
+ console.log("Toggle controlled after init: ", current);
160
+ form?.setFieldValue("checkControlledAfterInit", !current);
161
+ }}
162
+ >
163
+ Toggle
164
+ </Button>
165
+ <Button htmlType="submit">Submit</Button>
166
+ <Button
167
+ onClick={() => {
168
+ form?.resetFields?.();
169
+ }}
170
+ >
171
+ Reset
172
+ </Button>
173
+ </Form>
174
+ );
175
+ }
176
+
177
+ export default CommonTest;
@@ -0,0 +1,34 @@
1
+ import { Button, Col, Input, Row } from "antd";
2
+ import { useToggle } from "minh-custom-hooks-release";
3
+ import Form from "../providers/Form";
4
+
5
+ type Props = {};
6
+
7
+ function TestWrapperFormItem({}: Props) {
8
+ const { state, toggle } = useToggle(false);
9
+ return (
10
+ <Form
11
+ onFinish={(values, all) => {
12
+ console.log(values, all);
13
+ }}
14
+ formName="testWrapper"
15
+ >
16
+ <Row>
17
+ <Form.Item
18
+ hidden={!state}
19
+ name="test"
20
+ collectOnHidden={false}
21
+ initialValue={"test"}
22
+ Component={Col}
23
+ xs={12}
24
+ >
25
+ <Input />
26
+ </Form.Item>
27
+ </Row>
28
+ <Button htmlType="submit">Submit</Button>
29
+ <Button onClick={toggle}>{state ? "Off" : "On"}</Button>
30
+ </Form>
31
+ );
32
+ }
33
+
34
+ export default TestWrapperFormItem;