@xbeeant/form-engine-react 0.0.1
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/README.md +69 -0
- package/dist/cjs/components/FormController.cjs +1 -0
- package/dist/cjs/components/NexusField.cjs +1 -0
- package/dist/cjs/components/NexusForm.cjs +1 -0
- package/dist/cjs/components/NexusFormProvider.cjs +1 -0
- package/dist/cjs/components/NexusLayout.cjs +1 -0
- package/dist/cjs/components/NexusObject.cjs +1 -0
- package/dist/cjs/contexts/FieldInheritContext.cjs +1 -0
- package/dist/cjs/contexts/GridContext.cjs +1 -0
- package/dist/cjs/contexts/LayoutConfigContext.cjs +1 -0
- package/dist/cjs/contexts/NexusContext.cjs +1 -0
- package/dist/cjs/hooks/index.cjs +1 -0
- package/dist/cjs/hooks/useEngine.cjs +1 -0
- package/dist/cjs/hooks/useFieldState.cjs +1 -0
- package/dist/cjs/hooks/useFieldValidator.cjs +1 -0
- package/dist/cjs/hooks/useFieldValue.cjs +1 -0
- package/dist/cjs/hooks/useForm.cjs +1 -0
- package/dist/cjs/hooks/useFormConfig.cjs +1 -0
- package/dist/cjs/hooks/useFormData.cjs +1 -0
- package/dist/cjs/hooks/useNexusContext.cjs +1 -0
- package/dist/cjs/hooks/useWatch.cjs +1 -0
- package/dist/cjs/hooks/useWatchAll.cjs +1 -0
- package/dist/cjs/hooks/useWatchMultiple.cjs +1 -0
- package/dist/cjs/hooks/useWatchState.cjs +1 -0
- package/dist/cjs/index.cjs +1 -0
- package/dist/cjs/utils/renderTreeNode.cjs +1 -0
- package/dist/cjs/utils/resolveColSpan.cjs +1 -0
- package/dist/es/components/FormController.d.ts +71 -0
- package/dist/es/components/FormController.js +153 -0
- package/dist/es/components/NexusField.d.ts +9 -0
- package/dist/es/components/NexusField.js +98 -0
- package/dist/es/components/NexusForm.d.ts +77 -0
- package/dist/es/components/NexusForm.js +120 -0
- package/dist/es/components/NexusFormProvider.d.ts +12 -0
- package/dist/es/components/NexusFormProvider.js +18 -0
- package/dist/es/components/NexusLayout.d.ts +9 -0
- package/dist/es/components/NexusLayout.js +48 -0
- package/dist/es/components/NexusObject.d.ts +16 -0
- package/dist/es/components/NexusObject.js +64 -0
- package/dist/es/contexts/FieldInheritContext.d.ts +18 -0
- package/dist/es/contexts/FieldInheritContext.js +5 -0
- package/dist/es/contexts/GridContext.d.ts +5 -0
- package/dist/es/contexts/GridContext.js +5 -0
- package/dist/es/contexts/LayoutConfigContext.d.ts +4 -0
- package/dist/es/contexts/LayoutConfigContext.js +5 -0
- package/dist/es/contexts/NexusContext.d.ts +27 -0
- package/dist/es/contexts/NexusContext.js +12 -0
- package/dist/es/hooks/index.d.ts +11 -0
- package/dist/es/hooks/index.js +24 -0
- package/dist/es/hooks/useEngine.d.ts +2 -0
- package/dist/es/hooks/useEngine.js +8 -0
- package/dist/es/hooks/useFieldState.d.ts +7 -0
- package/dist/es/hooks/useFieldState.js +13 -0
- package/dist/es/hooks/useFieldValidator.d.ts +40 -0
- package/dist/es/hooks/useFieldValidator.js +35 -0
- package/dist/es/hooks/useFieldValue.d.ts +6 -0
- package/dist/es/hooks/useFieldValue.js +13 -0
- package/dist/es/hooks/useForm.d.ts +6 -0
- package/dist/es/hooks/useForm.js +9 -0
- package/dist/es/hooks/useFormConfig.d.ts +5 -0
- package/dist/es/hooks/useFormConfig.js +8 -0
- package/dist/es/hooks/useFormData.d.ts +6 -0
- package/dist/es/hooks/useFormData.js +13 -0
- package/dist/es/hooks/useNexusContext.d.ts +11 -0
- package/dist/es/hooks/useNexusContext.js +12 -0
- package/dist/es/hooks/useWatch.d.ts +25 -0
- package/dist/es/hooks/useWatch.js +20 -0
- package/dist/es/hooks/useWatchAll.d.ts +19 -0
- package/dist/es/hooks/useWatchAll.js +29 -0
- package/dist/es/hooks/useWatchMultiple.d.ts +20 -0
- package/dist/es/hooks/useWatchMultiple.js +29 -0
- package/dist/es/hooks/useWatchState.d.ts +18 -0
- package/dist/es/hooks/useWatchState.js +19 -0
- package/dist/es/index.d.ts +24 -0
- package/dist/es/index.js +42 -0
- package/dist/es/utils/renderTreeNode.d.ts +6 -0
- package/dist/es/utils/renderTreeNode.js +17 -0
- package/dist/es/utils/resolveColSpan.d.ts +5 -0
- package/dist/es/utils/resolveColSpan.js +9 -0
- package/dist/umd/index.umd.cjs +1 -0
- package/package.json +75 -0
- package/src/components/FormController.ts +271 -0
- package/src/components/NexusField.tsx +182 -0
- package/src/components/NexusForm.tsx +290 -0
- package/src/components/NexusFormProvider.tsx +28 -0
- package/src/components/NexusLayout.tsx +81 -0
- package/src/components/NexusObject.tsx +93 -0
- package/src/contexts/FieldInheritContext.ts +21 -0
- package/src/contexts/GridContext.ts +8 -0
- package/src/contexts/LayoutConfigContext.ts +6 -0
- package/src/contexts/NexusContext.ts +41 -0
- package/src/hooks/index.ts +11 -0
- package/src/hooks/useEngine.ts +8 -0
- package/src/hooks/useFieldState.ts +21 -0
- package/src/hooks/useFieldValidator.ts +123 -0
- package/src/hooks/useFieldValue.ts +20 -0
- package/src/hooks/useForm.ts +15 -0
- package/src/hooks/useFormConfig.ts +10 -0
- package/src/hooks/useFormData.ts +20 -0
- package/src/hooks/useNexusContext.ts +24 -0
- package/src/hooks/useWatch.ts +83 -0
- package/src/hooks/useWatchAll.ts +77 -0
- package/src/hooks/useWatchMultiple.ts +86 -0
- package/src/hooks/useWatchState.ts +54 -0
- package/src/index.ts +30 -0
- package/src/utils/renderTreeNode.tsx +30 -0
- package/src/utils/resolveColSpan.ts +18 -0
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import { jsx as b, jsxs as L } from "react/jsx-runtime";
|
|
2
|
+
import { useRef as l, useEffect as o, useSyncExternalStore as Q, useMemo as y, useCallback as W } from "react";
|
|
3
|
+
import { renderTreeNode as U } from "../utils/renderTreeNode.js";
|
|
4
|
+
import { NexusFormProvider as X } from "./NexusFormProvider.js";
|
|
5
|
+
function s() {
|
|
6
|
+
}
|
|
7
|
+
function ne({
|
|
8
|
+
form: n,
|
|
9
|
+
schema: t,
|
|
10
|
+
initialValues: _,
|
|
11
|
+
widgets: u,
|
|
12
|
+
layouts: c,
|
|
13
|
+
onFinish: j,
|
|
14
|
+
onFinishFailed: k,
|
|
15
|
+
footer: a = !1,
|
|
16
|
+
className: D,
|
|
17
|
+
style: O,
|
|
18
|
+
children: V,
|
|
19
|
+
labelCol: f,
|
|
20
|
+
labelWidth: $,
|
|
21
|
+
colon: I,
|
|
22
|
+
label: M,
|
|
23
|
+
displayType: P,
|
|
24
|
+
readOnly: g,
|
|
25
|
+
column: q,
|
|
26
|
+
watch: m,
|
|
27
|
+
removeHiddenData: R = !0
|
|
28
|
+
}) {
|
|
29
|
+
const e = n._getEngine(), x = l(null), F = P ?? t?.displayType ?? "row", C = M ?? t?.label ?? !0, S = I ?? t?.colon, r = $ ?? t?.labelWidth, T = g ?? t?.readOnly ?? !1, i = q ?? t?.column;
|
|
30
|
+
o(() => {
|
|
31
|
+
u && e.registerWidgets(u), c && e.registerLayouts(c);
|
|
32
|
+
}, [e, u, c]);
|
|
33
|
+
const h = l(!0), w = l(_);
|
|
34
|
+
o(() => {
|
|
35
|
+
t && (h.current ? (e.init(t, w.current), h.current = !1) : e.init(t, e.getFormData()));
|
|
36
|
+
}, [e, t]);
|
|
37
|
+
const N = l(s), v = l(s);
|
|
38
|
+
N.current = j ?? s, v.current = k ?? s, o(() => {
|
|
39
|
+
n._bind(
|
|
40
|
+
x.current,
|
|
41
|
+
() => N.current,
|
|
42
|
+
() => v.current
|
|
43
|
+
);
|
|
44
|
+
}, [n]), o(() => {
|
|
45
|
+
n._syncConfig({ removeHiddenData: R, watch: m });
|
|
46
|
+
}, [n, R, m]);
|
|
47
|
+
const z = Q(
|
|
48
|
+
e.subscribeStore,
|
|
49
|
+
e.getSnapshot,
|
|
50
|
+
e.getSnapshot
|
|
51
|
+
), A = y(() => e.getRenderTree(), [e, z]), B = W(
|
|
52
|
+
async (p) => {
|
|
53
|
+
p.preventDefault(), await n.submit();
|
|
54
|
+
},
|
|
55
|
+
[n]
|
|
56
|
+
), G = W(() => {
|
|
57
|
+
n.resetFields();
|
|
58
|
+
}, [n]);
|
|
59
|
+
let d = null;
|
|
60
|
+
a === !0 ? d = /* @__PURE__ */ L("div", { className: "mt-4", children: [
|
|
61
|
+
/* @__PURE__ */ b("button", { type: "submit", children: "提交" }),
|
|
62
|
+
" ",
|
|
63
|
+
/* @__PURE__ */ b("button", { type: "button", onClick: G, children: "重置" })
|
|
64
|
+
] }) : a && (d = a);
|
|
65
|
+
const E = y(() => {
|
|
66
|
+
if (f)
|
|
67
|
+
return f;
|
|
68
|
+
if (r)
|
|
69
|
+
return {
|
|
70
|
+
style: {
|
|
71
|
+
width: typeof r == "number" ? `${r}px` : r
|
|
72
|
+
}
|
|
73
|
+
};
|
|
74
|
+
}, [f, r]), J = y(
|
|
75
|
+
() => ({
|
|
76
|
+
labelCol: E,
|
|
77
|
+
labelWidth: r,
|
|
78
|
+
colon: S,
|
|
79
|
+
label: C,
|
|
80
|
+
displayType: F,
|
|
81
|
+
readOnly: T,
|
|
82
|
+
column: i
|
|
83
|
+
}),
|
|
84
|
+
[
|
|
85
|
+
E,
|
|
86
|
+
r,
|
|
87
|
+
S,
|
|
88
|
+
C,
|
|
89
|
+
F,
|
|
90
|
+
T,
|
|
91
|
+
i
|
|
92
|
+
]
|
|
93
|
+
);
|
|
94
|
+
return /* @__PURE__ */ b(X, { engine: e, config: J, form: n, children: /* @__PURE__ */ L(
|
|
95
|
+
"form",
|
|
96
|
+
{
|
|
97
|
+
ref: x,
|
|
98
|
+
onSubmit: B,
|
|
99
|
+
className: D,
|
|
100
|
+
style: {
|
|
101
|
+
...O,
|
|
102
|
+
// 当配置了 column 时,使用 CSS Grid 布局
|
|
103
|
+
...i && i > 1 ? {
|
|
104
|
+
display: "grid",
|
|
105
|
+
gridTemplateColumns: `repeat(${i}, 1fr)`,
|
|
106
|
+
gap: "0 16px"
|
|
107
|
+
} : {}
|
|
108
|
+
},
|
|
109
|
+
noValidate: !0,
|
|
110
|
+
children: [
|
|
111
|
+
A.map((p, K) => U(p, K)),
|
|
112
|
+
!g && d,
|
|
113
|
+
V
|
|
114
|
+
]
|
|
115
|
+
}
|
|
116
|
+
) });
|
|
117
|
+
}
|
|
118
|
+
export {
|
|
119
|
+
ne as NexusForm
|
|
120
|
+
};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { NexusEngine } from '@xbeeant/form-engine';
|
|
2
|
+
import { ReactNode } from 'react';
|
|
3
|
+
import { FormController } from './FormController';
|
|
4
|
+
import { NexusFormConfig } from './NexusForm';
|
|
5
|
+
interface NexusFormProviderProps {
|
|
6
|
+
engine: NexusEngine;
|
|
7
|
+
config: NexusFormConfig;
|
|
8
|
+
form: FormController;
|
|
9
|
+
children: ReactNode;
|
|
10
|
+
}
|
|
11
|
+
export declare function NexusFormProvider({ engine, config, form, children, }: NexusFormProviderProps): import("react").JSX.Element;
|
|
12
|
+
export {};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { jsx as u } from "react/jsx-runtime";
|
|
2
|
+
import { useMemo as s } from "react";
|
|
3
|
+
import { NexusContext as x } from "../contexts/NexusContext.js";
|
|
4
|
+
function d({
|
|
5
|
+
engine: r,
|
|
6
|
+
config: o,
|
|
7
|
+
form: t,
|
|
8
|
+
children: e
|
|
9
|
+
}) {
|
|
10
|
+
const m = s(
|
|
11
|
+
() => ({ engine: r, config: o, form: t }),
|
|
12
|
+
[r, o, t]
|
|
13
|
+
);
|
|
14
|
+
return /* @__PURE__ */ u(x.Provider, { value: m, children: e });
|
|
15
|
+
}
|
|
16
|
+
export {
|
|
17
|
+
d as NexusFormProvider
|
|
18
|
+
};
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { jsx as e, jsxs as u } from "react/jsx-runtime";
|
|
2
|
+
import { useContext as y, useMemo as f } from "react";
|
|
3
|
+
import { GridContext as h } from "../contexts/GridContext.js";
|
|
4
|
+
import { LayoutConfigContext as p } from "../contexts/LayoutConfigContext.js";
|
|
5
|
+
import { useNexusContext as v } from "../contexts/NexusContext.js";
|
|
6
|
+
import { renderTreeNode as x } from "../utils/renderTreeNode.js";
|
|
7
|
+
import { resolveColSpan as C } from "../utils/resolveColSpan.js";
|
|
8
|
+
function O({ node: t }) {
|
|
9
|
+
const { engine: n } = v(), r = n.getLayout(t.type), i = t.children.map(
|
|
10
|
+
(c, d) => x(c, d)
|
|
11
|
+
), a = y(h), l = C(t.props.colSpan, a), o = {
|
|
12
|
+
...l ? { gridColumn: `span ${l}` } : {},
|
|
13
|
+
...t.props.width ? { width: t.props.width, flexShrink: 0 } : {}
|
|
14
|
+
}, s = f(
|
|
15
|
+
() => ({ removeHidden: t.props.removeHidden }),
|
|
16
|
+
[t.props.removeHidden]
|
|
17
|
+
);
|
|
18
|
+
if (!r)
|
|
19
|
+
return /* @__PURE__ */ e(p.Provider, { value: s, children: /* @__PURE__ */ u(
|
|
20
|
+
"div",
|
|
21
|
+
{
|
|
22
|
+
"data-nexus-layout": t.type,
|
|
23
|
+
className: "mb-4",
|
|
24
|
+
style: Object.keys(o).length > 0 ? o : void 0,
|
|
25
|
+
children: [
|
|
26
|
+
t.title && /* @__PURE__ */ e("div", { className: "mb-2 font-bold", children: t.title }),
|
|
27
|
+
i
|
|
28
|
+
]
|
|
29
|
+
}
|
|
30
|
+
) });
|
|
31
|
+
const {
|
|
32
|
+
displayType: g,
|
|
33
|
+
labelWidth: w,
|
|
34
|
+
colSpan: b,
|
|
35
|
+
width: S,
|
|
36
|
+
...m
|
|
37
|
+
} = t.props;
|
|
38
|
+
return /* @__PURE__ */ e(p.Provider, { value: s, children: /* @__PURE__ */ e(
|
|
39
|
+
"div",
|
|
40
|
+
{
|
|
41
|
+
style: Object.keys(o).length > 0 ? o : void 0,
|
|
42
|
+
children: /* @__PURE__ */ e(r, { ...m, node: t, title: t.title, children: i })
|
|
43
|
+
}
|
|
44
|
+
) });
|
|
45
|
+
}
|
|
46
|
+
export {
|
|
47
|
+
O as NexusLayout
|
|
48
|
+
};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { RenderObjectNode } from '@xbeeant/form-engine';
|
|
2
|
+
interface NexusObjectProps {
|
|
3
|
+
node: RenderObjectNode;
|
|
4
|
+
}
|
|
5
|
+
/**
|
|
6
|
+
* NexusObject — 数据对象容器(可折叠,支持 disabled/hidden/readOnly 属性配置)
|
|
7
|
+
*
|
|
8
|
+
* 点击 title 折叠/展开 children。
|
|
9
|
+
* 折叠时仅以 display:none 隐藏 children,并不销毁(字段状态与订阅保持存活)。
|
|
10
|
+
*
|
|
11
|
+
* 属性继承:容器自身(Schema 布尔值 / 表达式 / setFieldState)配置的
|
|
12
|
+
* disabled / readOnly / hidden 会经 FieldInheritContext 下发给子树,
|
|
13
|
+
* 子树中的字段继承对应状态(disabled/readOnly 仅父级激活时生效)。
|
|
14
|
+
*/
|
|
15
|
+
export declare function NexusObject({ node }: NexusObjectProps): import("react").JSX.Element;
|
|
16
|
+
export {};
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { jsx as r, jsxs as u } from "react/jsx-runtime";
|
|
2
|
+
import { useContext as g, useSyncExternalStore as v, useState as x } from "react";
|
|
3
|
+
import { FieldInheritContext as h } from "../contexts/FieldInheritContext.js";
|
|
4
|
+
import { useNexusContext as y } from "../contexts/NexusContext.js";
|
|
5
|
+
import { renderTreeNode as C } from "../utils/renderTreeNode.js";
|
|
6
|
+
function O({ node: e }) {
|
|
7
|
+
const { engine: i, config: a } = y(), s = g(h);
|
|
8
|
+
v(
|
|
9
|
+
(t) => i.subscribeField(e.dataPath, t),
|
|
10
|
+
() => i.getFieldVersion(e.dataPath),
|
|
11
|
+
() => i.getFieldVersion(e.dataPath)
|
|
12
|
+
);
|
|
13
|
+
const n = i.getFieldState(e.dataPath), [o, m] = x(!1), l = (a.column ?? 1) > 1, d = l ? { gridTemplateColumns: `repeat(${a.column}, 1fr)` } : {}, c = {
|
|
14
|
+
disabled: s.disabled ?? (n?.disabled === !0 ? !0 : void 0),
|
|
15
|
+
readOnly: s.readOnly ?? (n?.readOnly === !0 ? !0 : void 0),
|
|
16
|
+
visible: s.visible === !1 || n?.visible === !1 ? !1 : void 0
|
|
17
|
+
}, p = c.visible === !1, b = () => m((t) => !t);
|
|
18
|
+
return /* @__PURE__ */ r(h.Provider, { value: c, children: /* @__PURE__ */ u(
|
|
19
|
+
"div",
|
|
20
|
+
{
|
|
21
|
+
"data-nexus-object": e.dataPath,
|
|
22
|
+
className: `mb-4 ${p ? "hidden" : ""}`,
|
|
23
|
+
children: [
|
|
24
|
+
e.title && /* @__PURE__ */ u(
|
|
25
|
+
"div",
|
|
26
|
+
{
|
|
27
|
+
onClick: b,
|
|
28
|
+
className: "flex gap-1 mb-2 cursor-pointer select-none border-none bg-transparent p-0 font-bold",
|
|
29
|
+
children: [
|
|
30
|
+
/* @__PURE__ */ r(
|
|
31
|
+
"svg",
|
|
32
|
+
{
|
|
33
|
+
width: "12",
|
|
34
|
+
height: "12",
|
|
35
|
+
viewBox: "0 0 24 24",
|
|
36
|
+
fill: "none",
|
|
37
|
+
stroke: "currentColor",
|
|
38
|
+
strokeWidth: "2",
|
|
39
|
+
strokeLinecap: "round",
|
|
40
|
+
strokeLinejoin: "round",
|
|
41
|
+
className: `align-middle transition-transform duration-200 ease-in-out ${o ? "rotate-0" : "rotate-90"}`,
|
|
42
|
+
"aria-hidden": "true",
|
|
43
|
+
children: /* @__PURE__ */ r("polyline", { points: "9 18 15 12 9 6" })
|
|
44
|
+
}
|
|
45
|
+
),
|
|
46
|
+
e.title
|
|
47
|
+
]
|
|
48
|
+
}
|
|
49
|
+
),
|
|
50
|
+
/* @__PURE__ */ r(
|
|
51
|
+
"div",
|
|
52
|
+
{
|
|
53
|
+
className: `${l ? "grid gap-x-4" : ""} ${o ? "hidden" : ""}`,
|
|
54
|
+
style: Object.keys(d).length > 0 ? d : void 0,
|
|
55
|
+
children: e.children.map((t, f) => C(t, f))
|
|
56
|
+
}
|
|
57
|
+
)
|
|
58
|
+
]
|
|
59
|
+
}
|
|
60
|
+
) });
|
|
61
|
+
}
|
|
62
|
+
export {
|
|
63
|
+
O as NexusObject
|
|
64
|
+
};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 字段继承上下文 — 数据对象容器(NexusObject)向下游字段下发继承属性
|
|
3
|
+
*
|
|
4
|
+
* 语义:
|
|
5
|
+
* - 仅「激活」状态被下发:disabled/readOnly 只在父容器显式启用时
|
|
6
|
+
* 携带 true(父级未设置时上下文不存在该键),子字段自行合并
|
|
7
|
+
* - visible 为 false 表示祖先对象容器隐藏,子树整体不可见
|
|
8
|
+
* - 合并优先级:祖先(已激活) > 字段自身状态 > 默认值
|
|
9
|
+
*/
|
|
10
|
+
export interface FieldInheritValue {
|
|
11
|
+
/** 祖先对象容器禁用(仅 true 存在) */
|
|
12
|
+
disabled?: boolean;
|
|
13
|
+
/** 祖先对象容器只读(仅 true 存在) */
|
|
14
|
+
readOnly?: boolean;
|
|
15
|
+
/** 祖先对象容器隐藏 → 子树不可见(false 存在时子树全部隐藏) */
|
|
16
|
+
visible?: boolean;
|
|
17
|
+
}
|
|
18
|
+
export declare const FieldInheritContext: import('react').Context<FieldInheritValue>;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { NexusEngine } from '@xbeeant/form-engine';
|
|
2
|
+
import { ReactNode } from 'react';
|
|
3
|
+
import { FormController } from '../components/FormController';
|
|
4
|
+
export interface NexusFormConfig {
|
|
5
|
+
/** label 列配置(由 ui 层 Form.Item 消费) */
|
|
6
|
+
labelCol?: Record<string, unknown>;
|
|
7
|
+
/** label 宽度(px 或 %),快捷方式 — 映射到 labelCol.style.width */
|
|
8
|
+
labelWidth?: number | string;
|
|
9
|
+
/** 是否显示冒号 */
|
|
10
|
+
colon?: boolean | ReactNode;
|
|
11
|
+
/** 是否显示 label(默认 true) */
|
|
12
|
+
label?: boolean;
|
|
13
|
+
/** 表单布局方向 */
|
|
14
|
+
displayType?: 'row' | 'column' | 'inline';
|
|
15
|
+
/** 整个表单只读,所有字段以文本展示 */
|
|
16
|
+
readOnly?: boolean;
|
|
17
|
+
/** 表单每行显示多少列 */
|
|
18
|
+
column?: number;
|
|
19
|
+
}
|
|
20
|
+
interface NexusContextValue {
|
|
21
|
+
engine: NexusEngine;
|
|
22
|
+
config: NexusFormConfig;
|
|
23
|
+
form: FormController;
|
|
24
|
+
}
|
|
25
|
+
export declare const NexusContext: import('react').Context<NexusContextValue | null>;
|
|
26
|
+
export declare function useNexusContext(): NexusContextValue;
|
|
27
|
+
export {};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { createContext as t, useContext as o } from "react";
|
|
2
|
+
const r = t(null);
|
|
3
|
+
function u() {
|
|
4
|
+
const e = o(r);
|
|
5
|
+
if (!e)
|
|
6
|
+
throw new Error("[NexusField] Must be used within <NexusFormProvider>");
|
|
7
|
+
return e;
|
|
8
|
+
}
|
|
9
|
+
export {
|
|
10
|
+
r as NexusContext,
|
|
11
|
+
u as useNexusContext
|
|
12
|
+
};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export { useEngine } from './useEngine';
|
|
2
|
+
export { useFieldState } from './useFieldState';
|
|
3
|
+
export { useFieldValidator } from './useFieldValidator';
|
|
4
|
+
export { useFieldValue } from './useFieldValue';
|
|
5
|
+
export { useForm } from './useForm';
|
|
6
|
+
export { useFormConfig } from './useFormConfig';
|
|
7
|
+
export { useFormData } from './useFormData';
|
|
8
|
+
export { useWatch } from './useWatch';
|
|
9
|
+
export { useWatchAll } from './useWatchAll';
|
|
10
|
+
export { useWatchMultiple } from './useWatchMultiple';
|
|
11
|
+
export { useWatchState } from './useWatchState';
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { useEngine as r } from "./useEngine.js";
|
|
2
|
+
import { useFieldState as m } from "./useFieldState.js";
|
|
3
|
+
import { useFieldValidator as f } from "./useFieldValidator.js";
|
|
4
|
+
import { useFieldValue as a } from "./useFieldValue.js";
|
|
5
|
+
import { useForm as x } from "./useForm.js";
|
|
6
|
+
import { useFormConfig as i } from "./useFormConfig.js";
|
|
7
|
+
import { useFormData as c } from "./useFormData.js";
|
|
8
|
+
import { useWatch as h } from "./useWatch.js";
|
|
9
|
+
import { useWatchAll as n } from "./useWatchAll.js";
|
|
10
|
+
import { useWatchMultiple as S } from "./useWatchMultiple.js";
|
|
11
|
+
import { useWatchState as A } from "./useWatchState.js";
|
|
12
|
+
export {
|
|
13
|
+
r as useEngine,
|
|
14
|
+
m as useFieldState,
|
|
15
|
+
f as useFieldValidator,
|
|
16
|
+
a as useFieldValue,
|
|
17
|
+
x as useForm,
|
|
18
|
+
i as useFormConfig,
|
|
19
|
+
c as useFormData,
|
|
20
|
+
h as useWatch,
|
|
21
|
+
n as useWatchAll,
|
|
22
|
+
S as useWatchMultiple,
|
|
23
|
+
A as useWatchState
|
|
24
|
+
};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { useSyncExternalStore as r } from "react";
|
|
2
|
+
import { useNexusContext as n } from "../contexts/NexusContext.js";
|
|
3
|
+
function u(e) {
|
|
4
|
+
const { engine: t } = n();
|
|
5
|
+
return r(
|
|
6
|
+
(i) => t.subscribeField(e, i),
|
|
7
|
+
() => t.getFieldVersion(e),
|
|
8
|
+
() => t.getFieldVersion(e)
|
|
9
|
+
), t.getFieldState(e);
|
|
10
|
+
}
|
|
11
|
+
export {
|
|
12
|
+
u as useFieldState
|
|
13
|
+
};
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { NexusFormInstance } from '@xbeeant/form-engine';
|
|
2
|
+
export type FieldValidator = (value: unknown, formData: Record<string, unknown>) => string[] | Promise<string[]>;
|
|
3
|
+
export interface UseFieldValidatorOptions {
|
|
4
|
+
/**
|
|
5
|
+
* 依赖字段路径列表。这些字段变化时自动对目标字段重校验,
|
|
6
|
+
* 实现「组件内注册的跨字段校验」与依赖字段的实时联动
|
|
7
|
+
* (等价于 schema 中 validate 表达式的依赖图联动)。
|
|
8
|
+
*/
|
|
9
|
+
dependsOn?: string[];
|
|
10
|
+
/**
|
|
11
|
+
* 校验器闭包依赖的组件 state(useEffect 语义)。
|
|
12
|
+
* 任意依赖值变化时,校验器会重新注册,新闭包捕获最新的组件 state,
|
|
13
|
+
* 保证校验逻辑读到的是当前渲染的 state,而不是注册时刻的陈旧值。
|
|
14
|
+
*
|
|
15
|
+
* 用法:
|
|
16
|
+
* ```tsx
|
|
17
|
+
* const [strict, setStrict] = useState(false);
|
|
18
|
+
* useFieldValidator(form, dataPath, (val, formData) => {
|
|
19
|
+
* if (strict && val && val !== formData.password) { ... }
|
|
20
|
+
* }, { deps: [strict] });
|
|
21
|
+
* ```
|
|
22
|
+
*/
|
|
23
|
+
deps?: ReadonlyArray<unknown>;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* 在 widget 组件内注册字段校验规则
|
|
27
|
+
*
|
|
28
|
+
* - 挂载时调用 form.registerValidator(path, validator)
|
|
29
|
+
* - 卸载时调用 form.unregisterValidator 清理,避免校验器累积
|
|
30
|
+
* - validator 通过 ref 持有最新闭包;deps 变化时 effect 重跑,
|
|
31
|
+
* 重新注册捕获最新组件 state 的新闭包(useEffect 语义),
|
|
32
|
+
* 校验逻辑总能读到当前渲染的组件 state
|
|
33
|
+
* - 传入 dependsOn 时,订阅依赖字段变化并实时重校验目标字段
|
|
34
|
+
*
|
|
35
|
+
* @param form - 表单实例(widget 的 props.form)
|
|
36
|
+
* @param path - 字段路径(widget 的 props.dataPath)
|
|
37
|
+
* @param validator - 校验函数,返回错误消息数组(空数组 = 通过)
|
|
38
|
+
* @param options - 配置(dependsOn 依赖字段联动 / deps 闭包依赖的组件 state)
|
|
39
|
+
*/
|
|
40
|
+
export declare function useFieldValidator(form: NexusFormInstance | undefined, path: string | undefined, validator: FieldValidator, options?: UseFieldValidatorOptions): void;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { useRef as o, useEffect as f } from "react";
|
|
2
|
+
import { useNexusContext as b } from "../contexts/NexusContext.js";
|
|
3
|
+
function R(r, e, c, s) {
|
|
4
|
+
const { engine: i } = b(), d = o(c);
|
|
5
|
+
d.current = c;
|
|
6
|
+
const t = o(s?.dependsOn);
|
|
7
|
+
t.current = s?.dependsOn;
|
|
8
|
+
const l = s?.deps;
|
|
9
|
+
f(() => {
|
|
10
|
+
if (!r || !e)
|
|
11
|
+
return;
|
|
12
|
+
const n = d.current;
|
|
13
|
+
return r.registerValidator(e, n), () => {
|
|
14
|
+
r.unregisterValidator(e, n);
|
|
15
|
+
};
|
|
16
|
+
}, [r, e, ...l ?? []]), f(() => {
|
|
17
|
+
if (!e || !t.current || t.current.length === 0)
|
|
18
|
+
return;
|
|
19
|
+
const n = i;
|
|
20
|
+
if (!n)
|
|
21
|
+
return;
|
|
22
|
+
const g = e, a = t.current.map(
|
|
23
|
+
(u) => n.subscribeField(u, () => {
|
|
24
|
+
r?.revalidateField(g);
|
|
25
|
+
})
|
|
26
|
+
);
|
|
27
|
+
return () => {
|
|
28
|
+
for (const u of a)
|
|
29
|
+
u();
|
|
30
|
+
};
|
|
31
|
+
}, [i, r, e]);
|
|
32
|
+
}
|
|
33
|
+
export {
|
|
34
|
+
R as useFieldValidator
|
|
35
|
+
};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { useSyncExternalStore as r } from "react";
|
|
2
|
+
import { useEngine as o } from "./useEngine.js";
|
|
3
|
+
function t(e) {
|
|
4
|
+
const i = o();
|
|
5
|
+
return r(
|
|
6
|
+
(n) => i.subscribeField(e, n),
|
|
7
|
+
() => i.getFieldVersion(e),
|
|
8
|
+
() => i.getFieldVersion(e)
|
|
9
|
+
), i.getFieldValue(e);
|
|
10
|
+
}
|
|
11
|
+
export {
|
|
12
|
+
t as useFieldValue
|
|
13
|
+
};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { useSyncExternalStore as o, useMemo as n } from "react";
|
|
2
|
+
import { useEngine as r } from "./useEngine.js";
|
|
3
|
+
function i() {
|
|
4
|
+
const e = r(), t = o(
|
|
5
|
+
e.subscribeStore,
|
|
6
|
+
e.getSnapshot,
|
|
7
|
+
e.getSnapshot
|
|
8
|
+
);
|
|
9
|
+
return n(() => e.getFormData(), [e, t]);
|
|
10
|
+
}
|
|
11
|
+
export {
|
|
12
|
+
i as useFormData
|
|
13
|
+
};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { NexusEngine } from '@xbeeant/form-engine';
|
|
2
|
+
import { FormController } from '../components/FormController';
|
|
3
|
+
import { NexusFormConfig } from '../components/NexusForm';
|
|
4
|
+
interface NexusContextValue {
|
|
5
|
+
engine: NexusEngine;
|
|
6
|
+
config: NexusFormConfig;
|
|
7
|
+
form: FormController;
|
|
8
|
+
}
|
|
9
|
+
export declare const NexusContext: import('react').Context<NexusContextValue | null>;
|
|
10
|
+
export declare function useNexusContext(): NexusContextValue;
|
|
11
|
+
export {};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { createContext as t, useContext as o } from "react";
|
|
2
|
+
const r = t(null);
|
|
3
|
+
function u() {
|
|
4
|
+
const e = o(r);
|
|
5
|
+
if (!e)
|
|
6
|
+
throw new Error("[NexusField] Must be used within <NexusFormProvider>");
|
|
7
|
+
return e;
|
|
8
|
+
}
|
|
9
|
+
export {
|
|
10
|
+
r as NexusContext,
|
|
11
|
+
u as useNexusContext
|
|
12
|
+
};
|