react-form-manage 1.0.8-beta.18 → 1.0.8-beta.20
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 +12 -0
- package/dist/hooks/useFormItemControl.js +28 -8
- package/dist/stores/formStore.js +13 -15
- package/dist/test/TestDialog.d.ts +3 -0
- package/dist/test/TestDialog.js +21 -0
- package/dist/test/TestSelect.d.ts +6 -0
- package/dist/test/TestSelect.js +24 -0
- package/package.json +1 -1
- package/src/App.tsx +2 -0
- package/src/hooks/useFormItemControl.ts +27 -10
- package/src/stores/formStore.ts +13 -15
- package/src/test/TestDialog.tsx +52 -0
- package/src/test/TestSelect.tsx +38 -0
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,18 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
|
|
5
|
+
## [1.0.8-beta.19] - 2026-02-02
|
|
6
|
+
|
|
7
|
+
### Features
|
|
8
|
+
- Trigger `initied` flag for onChange in `useFormItemControl` to properly mark form items as initialized
|
|
9
|
+
|
|
10
|
+
## [1.0.8-beta.18] - 2026-02-01
|
|
11
|
+
|
|
12
|
+
### Features
|
|
13
|
+
- Avoid deep traversal into class instances/functions in path collection
|
|
14
|
+
- `getAllNoneObjStringPath` now skips non-plain objects and functions, only traverses arrays and plain objects
|
|
15
|
+
- Improves performance and prevents accidental property access on class instances
|
|
16
|
+
|
|
5
17
|
## [1.0.8-beta.17] - 2026-02-01
|
|
6
18
|
|
|
7
19
|
### Features
|
|
@@ -8,14 +8,22 @@ import { useFormStore } from "../stores/formStore";
|
|
|
8
8
|
const VALID_PREMITIVE_TYPE = ["string", "number", "undefined"];
|
|
9
9
|
function useFormItemControl({ formName, form, name, initialValue, formItemId, rules, elementRef }) {
|
|
10
10
|
const contextForm = useFormContext();
|
|
11
|
-
const {
|
|
11
|
+
const {
|
|
12
|
+
value,
|
|
13
|
+
setData,
|
|
14
|
+
getCacheData,
|
|
15
|
+
getFormValues,
|
|
16
|
+
// getFormState,
|
|
17
|
+
isStateInitied,
|
|
18
|
+
submitState
|
|
19
|
+
} = useFormStore(useShallow((state2) => {
|
|
12
20
|
var _a, _b, _c, _d;
|
|
13
21
|
return {
|
|
14
22
|
value: get(state2.forms, `${formName || (form == null ? void 0 : form.formName) || (contextForm == null ? void 0 : contextForm.formName)}.${name}`),
|
|
15
23
|
setData: state2.setData,
|
|
16
24
|
getCacheData: state2.getCacheData,
|
|
17
25
|
getFormValues: state2.getFormValues,
|
|
18
|
-
getFormState:
|
|
26
|
+
// getFormState: state.getFormState,
|
|
19
27
|
isStateInitied: (_b = (_a = state2.formStates) == null ? void 0 : _a[formName || (form == null ? void 0 : form.formName) || (contextForm == null ? void 0 : contextForm.formName)]) == null ? void 0 : _b.isInitied,
|
|
20
28
|
submitState: (_d = (_c = state2.formStates) == null ? void 0 : _c[formName || (form == null ? void 0 : form.formName) || (contextForm == null ? void 0 : contextForm.formName)]) == null ? void 0 : _d.submitState
|
|
21
29
|
};
|
|
@@ -79,6 +87,8 @@ function useFormItemControl({ formName, form, name, initialValue, formItemId, ru
|
|
|
79
87
|
const internalRules = useMemo(() => {
|
|
80
88
|
return rules || [];
|
|
81
89
|
}, [rules]);
|
|
90
|
+
useEffect(() => {
|
|
91
|
+
}, [value, listener]);
|
|
82
92
|
const { data: errors, state } = useTaskEffect({
|
|
83
93
|
async task() {
|
|
84
94
|
const listErrors = [];
|
|
@@ -258,10 +268,13 @@ function useFormItemControl({ formName, form, name, initialValue, formItemId, ru
|
|
|
258
268
|
for (const rAsync of ruleToTask) {
|
|
259
269
|
await rAsync();
|
|
260
270
|
}
|
|
261
|
-
setListener({ formItemId, internalErrors: listErrors });
|
|
262
271
|
return listErrors;
|
|
263
272
|
},
|
|
264
|
-
deps: [internalRules, value],
|
|
273
|
+
deps: [internalRules, value, listener == null ? void 0 : listener.isInitied],
|
|
274
|
+
enabled: Boolean(listener == null ? void 0 : listener.isInitied),
|
|
275
|
+
onSuccess(result) {
|
|
276
|
+
setListener({ formItemId, internalErrors: result });
|
|
277
|
+
},
|
|
265
278
|
onError(err) {
|
|
266
279
|
}
|
|
267
280
|
});
|
|
@@ -278,6 +291,11 @@ function useFormItemControl({ formName, form, name, initialValue, formItemId, ru
|
|
|
278
291
|
initiedData: true
|
|
279
292
|
});
|
|
280
293
|
}
|
|
294
|
+
} else {
|
|
295
|
+
onChange(value, {
|
|
296
|
+
notTriggerDirty: true,
|
|
297
|
+
initiedData: true
|
|
298
|
+
});
|
|
281
299
|
}
|
|
282
300
|
return;
|
|
283
301
|
}
|
|
@@ -322,14 +340,16 @@ function useFormItemControl({ formName, form, name, initialValue, formItemId, ru
|
|
|
322
340
|
const isIncludeDirectoryInCache = has(cacheData, name);
|
|
323
341
|
if (!isIncludeDirectoryInCache && isNil(getNewDataFromCache)) {
|
|
324
342
|
onChange(initialValue, {
|
|
325
|
-
notTriggerDirty: true
|
|
343
|
+
notTriggerDirty: true,
|
|
344
|
+
initiedData: true
|
|
326
345
|
});
|
|
327
346
|
} else
|
|
328
|
-
onChange(getNewDataFromCache, {
|
|
347
|
+
onChange(getNewDataFromCache, {
|
|
348
|
+
notTriggerDirty: true,
|
|
349
|
+
initiedData: true
|
|
350
|
+
});
|
|
329
351
|
}
|
|
330
352
|
}, [name, formName || (form == null ? void 0 : form.formName) || (contextForm == null ? void 0 : contextForm.formName)]);
|
|
331
|
-
useEffect(() => {
|
|
332
|
-
}, [submitState]);
|
|
333
353
|
return {
|
|
334
354
|
value,
|
|
335
355
|
onChange,
|
package/dist/stores/formStore.js
CHANGED
|
@@ -240,21 +240,19 @@ const createListenersSlice = (storeSet, storeGet, api) => ({
|
|
|
240
240
|
}
|
|
241
241
|
return;
|
|
242
242
|
}
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
});
|
|
257
|
-
}
|
|
243
|
+
storeListeners.push({
|
|
244
|
+
name,
|
|
245
|
+
formName,
|
|
246
|
+
isTouched: Boolean(isTouched),
|
|
247
|
+
isDirty: Boolean(isDirty),
|
|
248
|
+
formItemId,
|
|
249
|
+
internalErrors,
|
|
250
|
+
onChange,
|
|
251
|
+
onReset,
|
|
252
|
+
isInitied: Boolean(isInitied),
|
|
253
|
+
type: type || "normal",
|
|
254
|
+
onArrayChange
|
|
255
|
+
});
|
|
258
256
|
}));
|
|
259
257
|
},
|
|
260
258
|
revokeListener(formItemId, onAfterRevoke) {
|
|
@@ -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,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
|
+
};
|
package/package.json
CHANGED
package/src/App.tsx
CHANGED
|
@@ -6,6 +6,7 @@ import FormItem from "./components/Form/FormItem";
|
|
|
6
6
|
import FormList from "./components/Form/FormList";
|
|
7
7
|
import InputWrapper from "./components/Form/InputWrapper";
|
|
8
8
|
import Form, { useForm } from "./providers/Form";
|
|
9
|
+
import TestDialog from "./test/TestDialog";
|
|
9
10
|
|
|
10
11
|
import { Form as AntdForm } from "antd";
|
|
11
12
|
|
|
@@ -154,6 +155,7 @@ const App = () => {
|
|
|
154
155
|
</div>
|
|
155
156
|
)}
|
|
156
157
|
</FormList>
|
|
158
|
+
<TestDialog />
|
|
157
159
|
<Button
|
|
158
160
|
onClick={() => {
|
|
159
161
|
form?.setFieldValue("arr", [
|
|
@@ -68,7 +68,7 @@ export default function useFormItemControl<T = any>({
|
|
|
68
68
|
setData,
|
|
69
69
|
getCacheData,
|
|
70
70
|
getFormValues,
|
|
71
|
-
getFormState,
|
|
71
|
+
// getFormState,
|
|
72
72
|
isStateInitied,
|
|
73
73
|
submitState,
|
|
74
74
|
} = useFormStore(
|
|
@@ -81,7 +81,7 @@ export default function useFormItemControl<T = any>({
|
|
|
81
81
|
setData: state.setData,
|
|
82
82
|
getCacheData: state.getCacheData,
|
|
83
83
|
getFormValues: state.getFormValues,
|
|
84
|
-
getFormState: state.getFormState,
|
|
84
|
+
// getFormState: state.getFormState,
|
|
85
85
|
isStateInitied:
|
|
86
86
|
state.formStates?.[
|
|
87
87
|
formName || form?.formName || contextForm?.formName
|
|
@@ -215,8 +215,17 @@ export default function useFormItemControl<T = any>({
|
|
|
215
215
|
return rules || [];
|
|
216
216
|
}, [rules]);
|
|
217
217
|
|
|
218
|
+
useEffect(() => {
|
|
219
|
+
console.log("Rules changed: ", { name, listener });
|
|
220
|
+
}, [value, listener]);
|
|
221
|
+
|
|
218
222
|
const { data: errors, state } = useTaskEffect({
|
|
219
223
|
async task() {
|
|
224
|
+
console.log("Trigger validate for form item: ", {
|
|
225
|
+
formName: formName || form?.formName || contextForm?.formName,
|
|
226
|
+
name,
|
|
227
|
+
value,
|
|
228
|
+
});
|
|
220
229
|
const listErrors = [];
|
|
221
230
|
|
|
222
231
|
const formValues = getFormValues(
|
|
@@ -505,11 +514,13 @@ export default function useFormItemControl<T = any>({
|
|
|
505
514
|
await rAsync();
|
|
506
515
|
}
|
|
507
516
|
|
|
508
|
-
setListener({ formItemId, internalErrors: listErrors });
|
|
509
|
-
|
|
510
517
|
return listErrors;
|
|
511
518
|
},
|
|
512
|
-
deps: [internalRules, value],
|
|
519
|
+
deps: [internalRules, value, listener?.isInitied],
|
|
520
|
+
enabled: Boolean(listener?.isInitied),
|
|
521
|
+
onSuccess(result) {
|
|
522
|
+
setListener({ formItemId, internalErrors: result });
|
|
523
|
+
},
|
|
513
524
|
onError(err) {
|
|
514
525
|
console.log(err);
|
|
515
526
|
},
|
|
@@ -542,6 +553,11 @@ export default function useFormItemControl<T = any>({
|
|
|
542
553
|
initiedData: true,
|
|
543
554
|
});
|
|
544
555
|
}
|
|
556
|
+
} else {
|
|
557
|
+
onChange(value, {
|
|
558
|
+
notTriggerDirty: true,
|
|
559
|
+
initiedData: true,
|
|
560
|
+
});
|
|
545
561
|
}
|
|
546
562
|
return;
|
|
547
563
|
}
|
|
@@ -604,15 +620,16 @@ export default function useFormItemControl<T = any>({
|
|
|
604
620
|
if (!isIncludeDirectoryInCache && isNil(getNewDataFromCache)) {
|
|
605
621
|
onChange(initialValue, {
|
|
606
622
|
notTriggerDirty: true,
|
|
623
|
+
initiedData: true,
|
|
624
|
+
});
|
|
625
|
+
} else
|
|
626
|
+
onChange(getNewDataFromCache, {
|
|
627
|
+
notTriggerDirty: true,
|
|
628
|
+
initiedData: true,
|
|
607
629
|
});
|
|
608
|
-
} else onChange(getNewDataFromCache, { notTriggerDirty: true });
|
|
609
630
|
}
|
|
610
631
|
}, [name, formName || form?.formName || contextForm?.formName]);
|
|
611
632
|
|
|
612
|
-
useEffect(() => {
|
|
613
|
-
console.log("Submit state changed in useFormItemControl: ", submitState);
|
|
614
|
-
}, [submitState]);
|
|
615
|
-
|
|
616
633
|
return {
|
|
617
634
|
value: value as T,
|
|
618
635
|
onChange,
|
package/src/stores/formStore.ts
CHANGED
|
@@ -430,21 +430,19 @@ const createListenersSlice = (storeSet: any, storeGet: any, api: any) => ({
|
|
|
430
430
|
|
|
431
431
|
return;
|
|
432
432
|
}
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
});
|
|
447
|
-
}
|
|
433
|
+
storeListeners.push({
|
|
434
|
+
name,
|
|
435
|
+
formName,
|
|
436
|
+
isTouched: Boolean(isTouched),
|
|
437
|
+
isDirty: Boolean(isDirty),
|
|
438
|
+
formItemId,
|
|
439
|
+
internalErrors,
|
|
440
|
+
onChange,
|
|
441
|
+
onReset,
|
|
442
|
+
isInitied: Boolean(isInitied),
|
|
443
|
+
type: type || "normal",
|
|
444
|
+
onArrayChange,
|
|
445
|
+
});
|
|
448
446
|
}),
|
|
449
447
|
);
|
|
450
448
|
},
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Button,
|
|
3
|
+
Dialog,
|
|
4
|
+
DialogContent,
|
|
5
|
+
DialogContentText,
|
|
6
|
+
DialogTitle,
|
|
7
|
+
TextField,
|
|
8
|
+
} from "@mui/material";
|
|
9
|
+
import { Box } from "@mui/system";
|
|
10
|
+
import { useToggle } from "minh-custom-hooks-release";
|
|
11
|
+
import FormItem from "../components/Form/FormItem";
|
|
12
|
+
import TestSelect from "./TestSelect";
|
|
13
|
+
|
|
14
|
+
type Props = {};
|
|
15
|
+
|
|
16
|
+
function TestDialog({}: Props) {
|
|
17
|
+
const { state: open, toggle } = useToggle();
|
|
18
|
+
return (
|
|
19
|
+
<Box>
|
|
20
|
+
<Dialog open={open} onClose={toggle}>
|
|
21
|
+
<DialogTitle>Test Dialog</DialogTitle>
|
|
22
|
+
<DialogContent>
|
|
23
|
+
<DialogContentText>This is a test dialog.</DialogContentText>
|
|
24
|
+
<FormItem
|
|
25
|
+
rules={[
|
|
26
|
+
{
|
|
27
|
+
handler(value) {
|
|
28
|
+
console.log("Validating in dialog: ", value);
|
|
29
|
+
return Boolean(value);
|
|
30
|
+
},
|
|
31
|
+
message: "Testt",
|
|
32
|
+
},
|
|
33
|
+
]}
|
|
34
|
+
controlAfterInit
|
|
35
|
+
initialValue={null}
|
|
36
|
+
name="testSelectInsideDialog"
|
|
37
|
+
>
|
|
38
|
+
<TestSelect />
|
|
39
|
+
</FormItem>
|
|
40
|
+
<FormItem controlAfterInit initialValue={""} name="anotherField">
|
|
41
|
+
<TextField />
|
|
42
|
+
</FormItem>
|
|
43
|
+
</DialogContent>
|
|
44
|
+
</Dialog>
|
|
45
|
+
<Button variant="contained" onClick={toggle}>
|
|
46
|
+
Open Test Dialog
|
|
47
|
+
</Button>
|
|
48
|
+
</Box>
|
|
49
|
+
);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export default TestDialog;
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { Autocomplete, TextField } from "@mui/material";
|
|
2
|
+
|
|
3
|
+
type Props = {
|
|
4
|
+
value?: any;
|
|
5
|
+
onChange?: (value: any) => void;
|
|
6
|
+
};
|
|
7
|
+
|
|
8
|
+
function TestSelect({ value = null, onChange }: Props) {
|
|
9
|
+
return (
|
|
10
|
+
<Autocomplete
|
|
11
|
+
value={value}
|
|
12
|
+
onChange={(_, newValue) => {
|
|
13
|
+
onChange?.(newValue);
|
|
14
|
+
}}
|
|
15
|
+
renderInput={(params) => <TextField {...params} />}
|
|
16
|
+
options={[
|
|
17
|
+
{
|
|
18
|
+
value: "option1",
|
|
19
|
+
label: "Option 1",
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
value: "option2",
|
|
23
|
+
label: "Option 2",
|
|
24
|
+
},
|
|
25
|
+
]}
|
|
26
|
+
getOptionKey={(o) => {
|
|
27
|
+
// console.log("Option get key: ", o);
|
|
28
|
+
return o?.value;
|
|
29
|
+
}}
|
|
30
|
+
getOptionLabel={(o) => {
|
|
31
|
+
// console.log("Option get label: ", o);
|
|
32
|
+
return o?.label;
|
|
33
|
+
}}
|
|
34
|
+
/>
|
|
35
|
+
);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export default TestSelect;
|