@xbeeant/form-engine-react 0.0.3 → 0.0.4

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 (142) hide show
  1. package/dist/cjs/components/FormController.cjs +1 -1
  2. package/dist/cjs/components/NexusField.cjs +1 -1
  3. package/dist/cjs/components/NexusForm.cjs +1 -1
  4. package/dist/cjs/components/form-controller.cjs +1 -0
  5. package/dist/cjs/components/nexus-field.cjs +1 -0
  6. package/dist/cjs/components/nexus-form-provider.cjs +1 -0
  7. package/dist/cjs/components/nexus-form.cjs +1 -0
  8. package/dist/cjs/components/nexus-layout.cjs +1 -0
  9. package/dist/cjs/components/nexus-object.cjs +1 -0
  10. package/dist/cjs/contexts/field-inherit-context.cjs +1 -0
  11. package/dist/cjs/contexts/grid-context.cjs +1 -0
  12. package/dist/cjs/contexts/layout-config-context.cjs +1 -0
  13. package/dist/cjs/contexts/nexus-context.cjs +1 -0
  14. package/dist/cjs/hooks/index.cjs +1 -1
  15. package/dist/cjs/hooks/use-engine.cjs +1 -0
  16. package/dist/cjs/hooks/use-field-state.cjs +1 -0
  17. package/dist/cjs/hooks/use-field-validator.cjs +1 -0
  18. package/dist/cjs/hooks/use-field-value.cjs +1 -0
  19. package/dist/cjs/hooks/use-form-config.cjs +1 -0
  20. package/dist/cjs/hooks/use-form-data.cjs +1 -0
  21. package/dist/cjs/hooks/use-form-submitting.cjs +1 -0
  22. package/dist/cjs/hooks/use-form.cjs +1 -0
  23. package/dist/cjs/hooks/use-nexus-context.cjs +1 -0
  24. package/dist/cjs/hooks/use-watch-all.cjs +1 -0
  25. package/dist/cjs/hooks/use-watch-multiple.cjs +1 -0
  26. package/dist/cjs/hooks/use-watch-state.cjs +1 -0
  27. package/dist/cjs/hooks/use-watch.cjs +1 -0
  28. package/dist/cjs/hooks/useFormData.cjs +1 -1
  29. package/dist/cjs/hooks/useFormSubmitting.cjs +1 -0
  30. package/dist/cjs/index.cjs +1 -1
  31. package/dist/cjs/styles.css +1 -1
  32. package/dist/cjs/utils/omit-nil.cjs +1 -0
  33. package/dist/cjs/utils/omitNil.cjs +1 -0
  34. package/dist/cjs/utils/persist.cjs +1 -0
  35. package/dist/cjs/utils/render-tree-node.cjs +1 -0
  36. package/dist/cjs/utils/resolve-col-span.cjs +1 -0
  37. package/dist/es/components/FormController.d.ts +73 -19
  38. package/dist/es/components/FormController.js +222 -71
  39. package/dist/es/components/NexusField.js +25 -21
  40. package/dist/es/components/NexusForm.d.ts +33 -3
  41. package/dist/es/components/NexusForm.js +143 -96
  42. package/dist/es/components/form-controller.d.ts +129 -0
  43. package/dist/es/components/form-controller.js +310 -0
  44. package/dist/es/components/nexus-field.d.ts +9 -0
  45. package/dist/es/components/nexus-field.js +131 -0
  46. package/dist/es/components/nexus-form-provider.d.ts +12 -0
  47. package/dist/es/components/nexus-form-provider.js +18 -0
  48. package/dist/es/components/nexus-form.d.ts +114 -0
  49. package/dist/es/components/nexus-form.js +174 -0
  50. package/dist/es/components/nexus-layout.d.ts +9 -0
  51. package/dist/es/components/nexus-layout.js +48 -0
  52. package/dist/es/components/nexus-object.d.ts +16 -0
  53. package/dist/es/components/nexus-object.js +64 -0
  54. package/dist/es/contexts/NexusContext.d.ts +2 -0
  55. package/dist/es/contexts/field-inherit-context.d.ts +18 -0
  56. package/dist/es/contexts/field-inherit-context.js +5 -0
  57. package/dist/es/contexts/grid-context.d.ts +5 -0
  58. package/dist/es/contexts/grid-context.js +5 -0
  59. package/dist/es/contexts/layout-config-context.d.ts +4 -0
  60. package/dist/es/contexts/layout-config-context.js +5 -0
  61. package/dist/es/contexts/nexus-context.d.ts +29 -0
  62. package/dist/es/contexts/nexus-context.js +12 -0
  63. package/dist/es/hooks/index.d.ts +12 -11
  64. package/dist/es/hooks/index.js +20 -18
  65. package/dist/es/hooks/use-engine.d.ts +2 -0
  66. package/dist/es/hooks/use-engine.js +8 -0
  67. package/dist/es/hooks/use-field-state.d.ts +7 -0
  68. package/dist/es/hooks/use-field-state.js +13 -0
  69. package/dist/es/hooks/use-field-validator.d.ts +40 -0
  70. package/dist/es/hooks/use-field-validator.js +35 -0
  71. package/dist/es/hooks/use-field-value.d.ts +6 -0
  72. package/dist/es/hooks/use-field-value.js +13 -0
  73. package/dist/es/hooks/use-form-config.d.ts +5 -0
  74. package/dist/es/hooks/use-form-config.js +8 -0
  75. package/dist/es/hooks/use-form-data.d.ts +6 -0
  76. package/dist/es/hooks/use-form-data.js +13 -0
  77. package/dist/es/hooks/use-form-submitting.d.ts +7 -0
  78. package/dist/es/hooks/use-form-submitting.js +11 -0
  79. package/dist/es/hooks/use-form.d.ts +22 -0
  80. package/dist/es/hooks/use-form.js +12 -0
  81. package/dist/es/hooks/use-nexus-context.d.ts +11 -0
  82. package/dist/es/hooks/use-nexus-context.js +12 -0
  83. package/dist/es/hooks/use-watch-all.d.ts +19 -0
  84. package/dist/es/hooks/use-watch-all.js +29 -0
  85. package/dist/es/hooks/use-watch-multiple.d.ts +20 -0
  86. package/dist/es/hooks/use-watch-multiple.js +29 -0
  87. package/dist/es/hooks/use-watch-state.d.ts +18 -0
  88. package/dist/es/hooks/use-watch-state.js +19 -0
  89. package/dist/es/hooks/use-watch.d.ts +25 -0
  90. package/dist/es/hooks/use-watch.js +20 -0
  91. package/dist/es/hooks/useForm.d.ts +11 -4
  92. package/dist/es/hooks/useFormData.js +9 -9
  93. package/dist/es/hooks/useFormSubmitting.d.ts +7 -0
  94. package/dist/es/hooks/useFormSubmitting.js +11 -0
  95. package/dist/es/index.d.ts +26 -24
  96. package/dist/es/index.js +36 -32
  97. package/dist/es/styles.css +1 -1
  98. package/dist/es/utils/omit-nil.d.ts +9 -0
  99. package/dist/es/utils/omit-nil.js +14 -0
  100. package/dist/es/utils/omitNil.d.ts +9 -0
  101. package/dist/es/utils/omitNil.js +14 -0
  102. package/dist/es/utils/persist.d.ts +24 -0
  103. package/dist/es/utils/persist.js +43 -0
  104. package/dist/es/utils/render-tree-node.d.ts +6 -0
  105. package/dist/es/utils/render-tree-node.js +17 -0
  106. package/dist/es/utils/resolve-col-span.d.ts +5 -0
  107. package/dist/es/utils/resolve-col-span.js +9 -0
  108. package/dist/umd/index.css +1 -1
  109. package/dist/umd/index.umd.cjs +1 -1
  110. package/package.json +5 -4
  111. package/src/components/form-controller.ts +584 -0
  112. package/src/components/{NexusField.tsx → nexus-field.tsx} +57 -6
  113. package/src/components/{NexusFormProvider.tsx → nexus-form-provider.tsx} +3 -3
  114. package/src/components/{NexusForm.tsx → nexus-form.tsx} +135 -18
  115. package/src/components/{NexusLayout.tsx → nexus-layout.tsx} +5 -5
  116. package/src/components/{NexusObject.tsx → nexus-object.tsx} +3 -3
  117. package/src/contexts/{NexusContext.ts → nexus-context.ts} +3 -1
  118. package/src/hooks/index.ts +12 -11
  119. package/src/hooks/{useEngine.ts → use-engine.ts} +1 -1
  120. package/src/hooks/{useFieldState.ts → use-field-state.ts} +1 -1
  121. package/src/hooks/{useFieldValidator.ts → use-field-validator.ts} +1 -1
  122. package/src/hooks/{useFieldValue.ts → use-field-value.ts} +1 -1
  123. package/src/hooks/{useFormConfig.ts → use-form-config.ts} +2 -2
  124. package/src/hooks/{useFormData.ts → use-form-data.ts} +4 -4
  125. package/src/hooks/use-form-submitting.ts +16 -0
  126. package/src/hooks/{useForm.ts → use-form.ts} +12 -5
  127. package/src/hooks/{useNexusContext.ts → use-nexus-context.ts} +2 -2
  128. package/src/index.ts +26 -24
  129. package/src/utils/omit-nil.ts +24 -0
  130. package/src/utils/persist.ts +88 -0
  131. package/src/utils/{renderTreeNode.tsx → render-tree-node.tsx} +3 -3
  132. package/src/utils/{resolveColSpan.ts → resolve-col-span.ts} +1 -1
  133. package/dist/cjs/tailwind.css +0 -1
  134. package/dist/es/tailwind.css +0 -1
  135. package/src/components/FormController.ts +0 -278
  136. /package/src/contexts/{FieldInheritContext.ts → field-inherit-context.ts} +0 -0
  137. /package/src/contexts/{GridContext.ts → grid-context.ts} +0 -0
  138. /package/src/contexts/{LayoutConfigContext.ts → layout-config-context.ts} +0 -0
  139. /package/src/hooks/{useWatchAll.ts → use-watch-all.ts} +0 -0
  140. /package/src/hooks/{useWatchMultiple.ts → use-watch-multiple.ts} +0 -0
  141. /package/src/hooks/{useWatchState.ts → use-watch-state.ts} +0 -0
  142. /package/src/hooks/{useWatch.ts → use-watch.ts} +0 -0
@@ -0,0 +1,174 @@
1
+ import { jsx as S, jsxs as A } from "react/jsx-runtime";
2
+ import { useId as de, useMemo as f, useRef as i, useEffect as u, useSyncExternalStore as fe, useCallback as B } from "react";
3
+ import "../contexts/nexus-context.js";
4
+ import "@xbeeant/form-engine";
5
+ import { useFormSubmitting as pe } from "../hooks/use-form-submitting.js";
6
+ import { loadPersisted as be, savePersisted as ge, clearPersisted as ye } from "../utils/persist.js";
7
+ import { renderTreeNode as me } from "../utils/render-tree-node.js";
8
+ import { NexusFormProvider as Re } from "./nexus-form-provider.js";
9
+ function T() {
10
+ }
11
+ function je({
12
+ form: o,
13
+ schema: n,
14
+ initialValues: G,
15
+ widgets: p,
16
+ layouts: b,
17
+ fieldWrapper: g,
18
+ onFinish: J,
19
+ onFinishFailed: Q,
20
+ onMount: x,
21
+ footer: y = !1,
22
+ className: U,
23
+ style: X,
24
+ children: Y,
25
+ labelCol: m,
26
+ labelWidth: Z,
27
+ colon: H,
28
+ label: ee,
29
+ displayType: te,
30
+ readOnly: C,
31
+ column: ne,
32
+ watch: v,
33
+ onValuesChange: L,
34
+ removeHiddenData: h = !0,
35
+ omitNil: j = !1,
36
+ locale: re,
37
+ persist: c
38
+ }) {
39
+ const l = de(), e = f(
40
+ () => o._useInstance(l),
41
+ [o, l]
42
+ ), k = i(null), a = i(c);
43
+ a.current = c;
44
+ const E = te ?? n?.displayType ?? "row", I = ee ?? n?.label ?? !0, N = H ?? n?.colon, s = Z ?? n?.labelWidth, O = C ?? n?.readOnly ?? !1, d = ne ?? n?.column, P = re ?? n?.locale ?? e.getLocale();
45
+ u(() => {
46
+ p && e.registerWidgets(p), g && e.registerFieldWrapper(g), b && e.registerLayouts(b);
47
+ }, [e, p, b, g]);
48
+ const _ = i(!0), oe = i(G);
49
+ u(() => {
50
+ if (n)
51
+ if (_.current) {
52
+ const t = a.current ? be(a.current) : void 0;
53
+ e.init(n, t ?? oe.current), _.current = !1;
54
+ } else
55
+ e.init(n, e.getFormData());
56
+ }, [e, n]);
57
+ const $ = c ? `${c.storage ?? "localStorage"}:${c.key}` : null;
58
+ u(() => {
59
+ const t = $ ? a.current : void 0;
60
+ if (!t)
61
+ return;
62
+ let r = null;
63
+ const F = t.debounce ?? 300, ae = e.subscribeStore(() => {
64
+ r && clearTimeout(r), r = setTimeout(() => {
65
+ ge(t, e.getFormData());
66
+ }, F);
67
+ });
68
+ return () => {
69
+ r && clearTimeout(r), ae();
70
+ };
71
+ }, [e, $]);
72
+ const D = i(x);
73
+ D.current = x;
74
+ const V = i(!1), W = !n || typeof n == "object" && Object.keys(n).length === 0;
75
+ u(() => {
76
+ V.current || W || (V.current = !0, D.current?.());
77
+ }, [W]);
78
+ const M = i(T), K = i(T);
79
+ M.current = (t) => {
80
+ const r = a.current;
81
+ return r && r.clearOnSubmit !== !1 && ye(r), J?.(t);
82
+ }, K.current = Q ?? T, u(() => {
83
+ o._bind(
84
+ l,
85
+ k.current,
86
+ () => M.current,
87
+ () => K.current
88
+ );
89
+ }, [o, l]);
90
+ const q = i(L);
91
+ q.current = L, u(() => {
92
+ o._syncConfig(l, {
93
+ removeHiddenData: h,
94
+ omitNil: j,
95
+ watch: v,
96
+ onValuesChange: (t, r, F) => q.current?.(t, r, F)
97
+ });
98
+ }, [o, l, h, j, v]);
99
+ const ie = fe(
100
+ (t) => e.subscribeRender(t),
101
+ () => e.getRenderSnapshot(),
102
+ () => e.getRenderSnapshot()
103
+ ), se = f(() => e.getRenderTree(), [e, ie]), le = B(
104
+ async (t) => {
105
+ t.preventDefault(), await o.submit();
106
+ },
107
+ [o]
108
+ ), ue = B(() => {
109
+ o.resetFields();
110
+ }, [o]), w = pe(o);
111
+ let R = null;
112
+ y === !0 ? R = /* @__PURE__ */ A("div", { className: "mt-4", children: [
113
+ /* @__PURE__ */ S("button", { type: "submit", disabled: w, children: w ? "提交中..." : "提交" }),
114
+ " ",
115
+ /* @__PURE__ */ S("button", { type: "button", onClick: ue, children: "重置" })
116
+ ] }) : y && (R = y);
117
+ const z = f(() => {
118
+ if (m)
119
+ return m;
120
+ if (s)
121
+ return {
122
+ style: {
123
+ width: typeof s == "number" ? `${s}px` : s
124
+ }
125
+ };
126
+ }, [m, s]), ce = f(
127
+ () => ({
128
+ labelCol: z,
129
+ labelWidth: s,
130
+ colon: N,
131
+ label: I,
132
+ displayType: E,
133
+ readOnly: O,
134
+ column: d,
135
+ locale: P
136
+ }),
137
+ [
138
+ z,
139
+ s,
140
+ N,
141
+ I,
142
+ E,
143
+ O,
144
+ d,
145
+ P
146
+ ]
147
+ );
148
+ return /* @__PURE__ */ S(Re, { engine: e, config: ce, form: o, children: /* @__PURE__ */ A(
149
+ "form",
150
+ {
151
+ ref: k,
152
+ onSubmit: le,
153
+ className: U,
154
+ style: {
155
+ ...X,
156
+ // 当配置了 column 时,使用 CSS Grid 布局
157
+ ...d && d > 1 ? {
158
+ display: "grid",
159
+ gridTemplateColumns: `repeat(${d}, 1fr)`,
160
+ gap: "0 16px"
161
+ } : {}
162
+ },
163
+ noValidate: !0,
164
+ children: [
165
+ se.map((t, r) => me(t, r)),
166
+ !C && R,
167
+ Y
168
+ ]
169
+ }
170
+ ) });
171
+ }
172
+ export {
173
+ je as NexusForm
174
+ };
@@ -0,0 +1,9 @@
1
+ import { RenderLayoutNode } from '@xbeeant/form-engine';
2
+ interface NexusLayoutProps {
3
+ node: RenderLayoutNode;
4
+ }
5
+ /**
6
+ * NexusLayout — 布局容器渲染器
7
+ */
8
+ export declare function NexusLayout({ node }: NexusLayoutProps): import("react").JSX.Element;
9
+ export {};
@@ -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/grid-context.js";
4
+ import { LayoutConfigContext as p } from "../contexts/layout-config-context.js";
5
+ import { useNexusContext as v } from "../contexts/nexus-context.js";
6
+ import { renderTreeNode as x } from "../utils/render-tree-node.js";
7
+ import { resolveColSpan as C } from "../utils/resolve-col-span.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/field-inherit-context.js";
4
+ import { useNexusContext as y } from "../contexts/nexus-context.js";
5
+ import { renderTreeNode as C } from "../utils/render-tree-node.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
+ };
@@ -16,6 +16,8 @@ export interface NexusFormConfig {
16
16
  readOnly?: boolean;
17
17
  /** 表单每行显示多少列 */
18
18
  column?: number;
19
+ /** 表单语言标识(如 'zh-CN' / 'en-US',ui 层消费:antd locale + 内置文案) */
20
+ locale?: string;
19
21
  }
20
22
  interface NexusContextValue {
21
23
  engine: NexusEngine;
@@ -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,5 @@
1
+ import { createContext as t } from "react";
2
+ const o = t({});
3
+ export {
4
+ o as FieldInheritContext
5
+ };
@@ -0,0 +1,5 @@
1
+ export interface GridContextValue {
2
+ /** 当前 grid 的列数(tailwind colSpan 基准) */
3
+ column: number;
4
+ }
5
+ export declare const GridContext: import('react').Context<GridContextValue | null>;
@@ -0,0 +1,5 @@
1
+ import { createContext as t } from "react";
2
+ const e = t(null);
3
+ export {
4
+ e as GridContext
5
+ };
@@ -0,0 +1,4 @@
1
+ export interface LayoutConfigContextValue {
2
+ removeHidden?: boolean;
3
+ }
4
+ export declare const LayoutConfigContext: import('react').Context<LayoutConfigContextValue>;
@@ -0,0 +1,5 @@
1
+ import { createContext as t } from "react";
2
+ const e = t({});
3
+ export {
4
+ e as LayoutConfigContext
5
+ };
@@ -0,0 +1,29 @@
1
+ import { NexusEngine } from '@xbeeant/form-engine';
2
+ import { ReactNode } from 'react';
3
+ import { FormController } from '../components/form-controller';
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
+ /** 表单语言标识(如 'zh-CN' / 'en-US',ui 层消费:antd locale + 内置文案) */
20
+ locale?: string;
21
+ }
22
+ interface NexusContextValue {
23
+ engine: NexusEngine;
24
+ config: NexusFormConfig;
25
+ form: FormController;
26
+ }
27
+ export declare const NexusContext: import('react').Context<NexusContextValue | null>;
28
+ export declare function useNexusContext(): NexusContextValue;
29
+ 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
+ };
@@ -1,11 +1,12 @@
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';
1
+ export { useEngine } from './use-engine';
2
+ export { useFieldState } from './use-field-state';
3
+ export { useFieldValidator } from './use-field-validator';
4
+ export { useFieldValue } from './use-field-value';
5
+ export { useForm } from './use-form';
6
+ export { useFormConfig } from './use-form-config';
7
+ export { useFormData } from './use-form-data';
8
+ export { useFormSubmitting } from './use-form-submitting';
9
+ export { useWatch } from './use-watch';
10
+ export { useWatchAll } from './use-watch-all';
11
+ export { useWatchMultiple } from './use-watch-multiple';
12
+ export { useWatchState } from './use-watch-state';
@@ -1,24 +1,26 @@
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";
1
+ import { useEngine as r } from "./use-engine.js";
2
+ import { useFieldState as m } from "./use-field-state.js";
3
+ import { useFieldValidator as f } from "./use-field-validator.js";
4
+ import { useFieldValue as s } from "./use-field-value.js";
5
+ import { useForm as a } from "./use-form.js";
6
+ import { useFormConfig as l } from "./use-form-config.js";
7
+ import { useFormData as c } from "./use-form-data.js";
8
+ import { useFormSubmitting as h } from "./use-form-submitting.js";
9
+ import { useWatch as W } from "./use-watch.js";
10
+ import { useWatchAll as S } from "./use-watch-all.js";
11
+ import { useWatchMultiple as b } from "./use-watch-multiple.js";
12
+ import { useWatchState as C } from "./use-watch-state.js";
12
13
  export {
13
14
  r as useEngine,
14
15
  m as useFieldState,
15
16
  f as useFieldValidator,
16
- a as useFieldValue,
17
- x as useForm,
18
- i as useFormConfig,
17
+ s as useFieldValue,
18
+ a as useForm,
19
+ l as useFormConfig,
19
20
  c as useFormData,
20
- h as useWatch,
21
- n as useWatchAll,
22
- S as useWatchMultiple,
23
- A as useWatchState
21
+ h as useFormSubmitting,
22
+ W as useWatch,
23
+ S as useWatchAll,
24
+ b as useWatchMultiple,
25
+ C as useWatchState
24
26
  };
@@ -0,0 +1,2 @@
1
+ import { NexusEngine } from '@xbeeant/form-engine';
2
+ export declare function useEngine(): NexusEngine;
@@ -0,0 +1,8 @@
1
+ import { useNexusContext as n } from "../contexts/nexus-context.js";
2
+ function o() {
3
+ const { engine: e } = n();
4
+ return e;
5
+ }
6
+ export {
7
+ o as useEngine
8
+ };
@@ -0,0 +1,7 @@
1
+ import { FieldState } from '@xbeeant/form-engine';
2
+ /**
3
+ * useFieldState — 精准订阅单个字段状态
4
+ *
5
+ * 按路径精准订阅:只在该字段版本变化时触发重渲染,避免全局订阅拖垮表单
6
+ */
7
+ export declare function useFieldState(path: string): FieldState | undefined;
@@ -0,0 +1,13 @@
1
+ import { useSyncExternalStore as r } from "react";
2
+ import { useNexusContext as n } from "../contexts/nexus-context.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/nexus-context.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,6 @@
1
+ /**
2
+ * useFieldValue — 精准订阅单个字段值
3
+ *
4
+ * 按路径精准订阅:仅该字段版本变化时重渲染
5
+ */
6
+ export declare function useFieldValue<T = unknown>(path: string): T | undefined;
@@ -0,0 +1,13 @@
1
+ import { useSyncExternalStore as r } from "react";
2
+ import { useEngine as o } from "./use-engine.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,5 @@
1
+ import { NexusFormConfig } from '../components/nexus-form';
2
+ /**
3
+ * useFormConfig — 获取表单布局配置
4
+ */
5
+ export declare function useFormConfig(): NexusFormConfig;
@@ -0,0 +1,8 @@
1
+ import { useNexusContext as n } from "../contexts/nexus-context.js";
2
+ function e() {
3
+ const { config: o } = n();
4
+ return o;
5
+ }
6
+ export {
7
+ e as useFormConfig
8
+ };
@@ -0,0 +1,6 @@
1
+ /**
2
+ * useFormData — 订阅整个表单数据
3
+ *
4
+ * 用 version 作为快照依赖,避免 getFormData() 每次返回新对象引用导致的无谓重渲染
5
+ */
6
+ export declare function useFormData(): Record<string, unknown>;
@@ -0,0 +1,13 @@
1
+ import { useSyncExternalStore as n, useMemo as r } from "react";
2
+ import { useEngine as s } from "./use-engine.js";
3
+ function m() {
4
+ const e = s(), t = n(
5
+ (o) => e.subscribeStore(o),
6
+ () => e.getSnapshot(),
7
+ () => e.getSnapshot()
8
+ );
9
+ return r(() => e.getFormData(), [e, t]);
10
+ }
11
+ export {
12
+ m as useFormData
13
+ };