@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.
Files changed (107) hide show
  1. package/README.md +69 -0
  2. package/dist/cjs/components/FormController.cjs +1 -0
  3. package/dist/cjs/components/NexusField.cjs +1 -0
  4. package/dist/cjs/components/NexusForm.cjs +1 -0
  5. package/dist/cjs/components/NexusFormProvider.cjs +1 -0
  6. package/dist/cjs/components/NexusLayout.cjs +1 -0
  7. package/dist/cjs/components/NexusObject.cjs +1 -0
  8. package/dist/cjs/contexts/FieldInheritContext.cjs +1 -0
  9. package/dist/cjs/contexts/GridContext.cjs +1 -0
  10. package/dist/cjs/contexts/LayoutConfigContext.cjs +1 -0
  11. package/dist/cjs/contexts/NexusContext.cjs +1 -0
  12. package/dist/cjs/hooks/index.cjs +1 -0
  13. package/dist/cjs/hooks/useEngine.cjs +1 -0
  14. package/dist/cjs/hooks/useFieldState.cjs +1 -0
  15. package/dist/cjs/hooks/useFieldValidator.cjs +1 -0
  16. package/dist/cjs/hooks/useFieldValue.cjs +1 -0
  17. package/dist/cjs/hooks/useForm.cjs +1 -0
  18. package/dist/cjs/hooks/useFormConfig.cjs +1 -0
  19. package/dist/cjs/hooks/useFormData.cjs +1 -0
  20. package/dist/cjs/hooks/useNexusContext.cjs +1 -0
  21. package/dist/cjs/hooks/useWatch.cjs +1 -0
  22. package/dist/cjs/hooks/useWatchAll.cjs +1 -0
  23. package/dist/cjs/hooks/useWatchMultiple.cjs +1 -0
  24. package/dist/cjs/hooks/useWatchState.cjs +1 -0
  25. package/dist/cjs/index.cjs +1 -0
  26. package/dist/cjs/utils/renderTreeNode.cjs +1 -0
  27. package/dist/cjs/utils/resolveColSpan.cjs +1 -0
  28. package/dist/es/components/FormController.d.ts +71 -0
  29. package/dist/es/components/FormController.js +153 -0
  30. package/dist/es/components/NexusField.d.ts +9 -0
  31. package/dist/es/components/NexusField.js +98 -0
  32. package/dist/es/components/NexusForm.d.ts +77 -0
  33. package/dist/es/components/NexusForm.js +120 -0
  34. package/dist/es/components/NexusFormProvider.d.ts +12 -0
  35. package/dist/es/components/NexusFormProvider.js +18 -0
  36. package/dist/es/components/NexusLayout.d.ts +9 -0
  37. package/dist/es/components/NexusLayout.js +48 -0
  38. package/dist/es/components/NexusObject.d.ts +16 -0
  39. package/dist/es/components/NexusObject.js +64 -0
  40. package/dist/es/contexts/FieldInheritContext.d.ts +18 -0
  41. package/dist/es/contexts/FieldInheritContext.js +5 -0
  42. package/dist/es/contexts/GridContext.d.ts +5 -0
  43. package/dist/es/contexts/GridContext.js +5 -0
  44. package/dist/es/contexts/LayoutConfigContext.d.ts +4 -0
  45. package/dist/es/contexts/LayoutConfigContext.js +5 -0
  46. package/dist/es/contexts/NexusContext.d.ts +27 -0
  47. package/dist/es/contexts/NexusContext.js +12 -0
  48. package/dist/es/hooks/index.d.ts +11 -0
  49. package/dist/es/hooks/index.js +24 -0
  50. package/dist/es/hooks/useEngine.d.ts +2 -0
  51. package/dist/es/hooks/useEngine.js +8 -0
  52. package/dist/es/hooks/useFieldState.d.ts +7 -0
  53. package/dist/es/hooks/useFieldState.js +13 -0
  54. package/dist/es/hooks/useFieldValidator.d.ts +40 -0
  55. package/dist/es/hooks/useFieldValidator.js +35 -0
  56. package/dist/es/hooks/useFieldValue.d.ts +6 -0
  57. package/dist/es/hooks/useFieldValue.js +13 -0
  58. package/dist/es/hooks/useForm.d.ts +6 -0
  59. package/dist/es/hooks/useForm.js +9 -0
  60. package/dist/es/hooks/useFormConfig.d.ts +5 -0
  61. package/dist/es/hooks/useFormConfig.js +8 -0
  62. package/dist/es/hooks/useFormData.d.ts +6 -0
  63. package/dist/es/hooks/useFormData.js +13 -0
  64. package/dist/es/hooks/useNexusContext.d.ts +11 -0
  65. package/dist/es/hooks/useNexusContext.js +12 -0
  66. package/dist/es/hooks/useWatch.d.ts +25 -0
  67. package/dist/es/hooks/useWatch.js +20 -0
  68. package/dist/es/hooks/useWatchAll.d.ts +19 -0
  69. package/dist/es/hooks/useWatchAll.js +29 -0
  70. package/dist/es/hooks/useWatchMultiple.d.ts +20 -0
  71. package/dist/es/hooks/useWatchMultiple.js +29 -0
  72. package/dist/es/hooks/useWatchState.d.ts +18 -0
  73. package/dist/es/hooks/useWatchState.js +19 -0
  74. package/dist/es/index.d.ts +24 -0
  75. package/dist/es/index.js +42 -0
  76. package/dist/es/utils/renderTreeNode.d.ts +6 -0
  77. package/dist/es/utils/renderTreeNode.js +17 -0
  78. package/dist/es/utils/resolveColSpan.d.ts +5 -0
  79. package/dist/es/utils/resolveColSpan.js +9 -0
  80. package/dist/umd/index.umd.cjs +1 -0
  81. package/package.json +75 -0
  82. package/src/components/FormController.ts +271 -0
  83. package/src/components/NexusField.tsx +182 -0
  84. package/src/components/NexusForm.tsx +290 -0
  85. package/src/components/NexusFormProvider.tsx +28 -0
  86. package/src/components/NexusLayout.tsx +81 -0
  87. package/src/components/NexusObject.tsx +93 -0
  88. package/src/contexts/FieldInheritContext.ts +21 -0
  89. package/src/contexts/GridContext.ts +8 -0
  90. package/src/contexts/LayoutConfigContext.ts +6 -0
  91. package/src/contexts/NexusContext.ts +41 -0
  92. package/src/hooks/index.ts +11 -0
  93. package/src/hooks/useEngine.ts +8 -0
  94. package/src/hooks/useFieldState.ts +21 -0
  95. package/src/hooks/useFieldValidator.ts +123 -0
  96. package/src/hooks/useFieldValue.ts +20 -0
  97. package/src/hooks/useForm.ts +15 -0
  98. package/src/hooks/useFormConfig.ts +10 -0
  99. package/src/hooks/useFormData.ts +20 -0
  100. package/src/hooks/useNexusContext.ts +24 -0
  101. package/src/hooks/useWatch.ts +83 -0
  102. package/src/hooks/useWatchAll.ts +77 -0
  103. package/src/hooks/useWatchMultiple.ts +86 -0
  104. package/src/hooks/useWatchState.ts +54 -0
  105. package/src/index.ts +30 -0
  106. package/src/utils/renderTreeNode.tsx +30 -0
  107. package/src/utils/resolveColSpan.ts +18 -0
@@ -0,0 +1,25 @@
1
+ import { NexusEngine } from '@xbeeant/form-engine';
2
+ /**
3
+ * useWatch Hook - 监听单个字段值变化
4
+ *
5
+ * @param engine - NexusEngine实例
6
+ * @param path - 字段路径
7
+ * @param callback - 变化回调函数
8
+ * @param deep - 是否深度比较值(默认false,仅浅比较)
9
+ *
10
+ * @example
11
+ * ```tsx
12
+ * // 监听单个字段
13
+ * const name = useWatch(engine, 'profile.name', (value) => {
14
+ * console.log('Name changed:', value);
15
+ * });
16
+ *
17
+ * // 深度比较对象
18
+ * const profile = useWatch(engine, 'profile', (value) => {
19
+ * console.log('Profile changed:', value);
20
+ * }, { deep: true });
21
+ * ```
22
+ */
23
+ export declare function useWatch(engine: NexusEngine | null, path: string, callback: (value: unknown) => void, options?: {
24
+ deep?: boolean;
25
+ }): unknown;
@@ -0,0 +1,20 @@
1
+ import { useRef as f, useEffect as d } from "react";
2
+ function J(e, c, o, i) {
3
+ const { deep: n = !1 } = i || {}, r = f(void 0), s = f(o);
4
+ return s.current = o, d(() => {
5
+ if (!e)
6
+ return;
7
+ const t = e.getFieldValue(c);
8
+ r.current === void 0 && (r.current = t), (n ? JSON.stringify(t) !== JSON.stringify(r.current) : t !== r.current) && (r.current = t, s.current(t));
9
+ const l = e.subscribe(c, (a) => {
10
+ const u = a.value;
11
+ (n ? JSON.stringify(u) !== JSON.stringify(r.current) : u !== r.current) && (r.current = u, s.current(u));
12
+ });
13
+ return () => {
14
+ l();
15
+ };
16
+ }, [e, c, n]), r.current;
17
+ }
18
+ export {
19
+ J as useWatch
20
+ };
@@ -0,0 +1,19 @@
1
+ import { NexusEngine } from '@xbeeant/form-engine';
2
+ /**
3
+ * useWatchAll Hook - 监听整个表单数据变化
4
+ *
5
+ * @param engine - NexusEngine实例
6
+ * @param callback - 变化回调函数
7
+ * @param deep - 是否深度比较值(默认false,仅浅比较)
8
+ *
9
+ * @example
10
+ * ```tsx
11
+ * // 监听整个表单
12
+ * useWatchAll(engine, (formData) => {
13
+ * console.log('Form data changed:', formData);
14
+ * }, { deep: true });
15
+ * ```
16
+ */
17
+ export declare function useWatchAll(engine: NexusEngine | null, callback: (formData: Record<string, unknown>) => void, options?: {
18
+ deep?: boolean;
19
+ }): Record<string, unknown>;
@@ -0,0 +1,29 @@
1
+ import { useRef as n, useEffect as h } from "react";
2
+ function g(c, i, b) {
3
+ const { deep: l = !1 } = b || {}, t = n({}), e = n({}), u = n(i);
4
+ return u.current = i, h(() => {
5
+ if (!c)
6
+ return;
7
+ const s = c.getFormData();
8
+ t.current = s, e.current = s, u.current(s);
9
+ const d = c.subscribeAll((r) => {
10
+ if (l)
11
+ JSON.stringify(r) !== JSON.stringify(t.current) && (t.current = r, e.current = r, u.current(r));
12
+ else {
13
+ let f = !1;
14
+ for (const o in r)
15
+ if (r[o] !== t.current[o]) {
16
+ f = !0;
17
+ break;
18
+ }
19
+ f && (t.current = r, e.current = r, u.current(r));
20
+ }
21
+ });
22
+ return () => {
23
+ d();
24
+ };
25
+ }, [c, l]), e.current;
26
+ }
27
+ export {
28
+ g as useWatchAll
29
+ };
@@ -0,0 +1,20 @@
1
+ import { NexusEngine } from '@xbeeant/form-engine';
2
+ /**
3
+ * useWatchMultiple Hook - 监听多个字段值变化
4
+ *
5
+ * @param engine - NexusEngine实例
6
+ * @param paths - 字段路径数组
7
+ * @param callback - 变化回调函数
8
+ * @param deep - 是否深度比较值(默认false,仅浅比较)
9
+ *
10
+ * @example
11
+ * ```tsx
12
+ * // 监听多个字段
13
+ * const values = useWatchMultiple(engine, ['name', 'email', 'age'], (values) => {
14
+ * console.log('Values changed:', values);
15
+ * }, { deep: true });
16
+ * ```
17
+ */
18
+ export declare function useWatchMultiple(engine: NexusEngine | null, paths: string[], callback: (values: Record<string, unknown>) => void, options?: {
19
+ deep?: boolean;
20
+ }): Record<string, unknown>;
@@ -0,0 +1,29 @@
1
+ import { useRef as s, useEffect as p } from "react";
2
+ function v(r, u, a, R) {
3
+ const { deep: l = !1 } = R || {}, o = s({}), e = s({}), f = s(a);
4
+ f.current = a;
5
+ const i = s(u);
6
+ i.current = u;
7
+ const V = [...u].sort().join(",");
8
+ return p(() => {
9
+ if (!r)
10
+ return;
11
+ const b = i.current, c = {};
12
+ for (const t of b)
13
+ c[t] = r.getFieldValue(t);
14
+ o.current = c, e.current = c, f.current(c);
15
+ const h = b.map(
16
+ (t) => r.subscribe(t, (m) => {
17
+ const n = m.value, d = o.current[t];
18
+ (l ? JSON.stringify(n) !== JSON.stringify(d) : n !== d) && (o.current[t] = n, e.current = { [t]: n }, f.current(e.current));
19
+ })
20
+ );
21
+ return () => {
22
+ for (const t of h)
23
+ t();
24
+ };
25
+ }, [r, l, V]), e.current;
26
+ }
27
+ export {
28
+ v as useWatchMultiple
29
+ };
@@ -0,0 +1,18 @@
1
+ import { FieldState, NexusEngine } from '@xbeeant/form-engine';
2
+ /**
3
+ * useWatchState Hook - 监听单个字段状态变化
4
+ *
5
+ * @param engine - NexusEngine实例
6
+ * @param path - 字段路径
7
+ * @param callback - 状态变化回调函数
8
+ *
9
+ * @example
10
+ * ```tsx
11
+ * // 监听字段状态(visible/disabled/loading等)
12
+ * const isDisabled = useWatchState(engine, 'email', (state) => {
13
+ * console.log('Disabled:', state.disabled);
14
+ * console.log('Loading:', state.loading);
15
+ * });
16
+ * ```
17
+ */
18
+ export declare function useWatchState(engine: NexusEngine | null, path: string, callback: (state: FieldState) => void): FieldState;
@@ -0,0 +1,19 @@
1
+ import { useRef as n, useEffect as i } from "react";
2
+ function R(r, t, s) {
3
+ const e = n(void 0), u = n(s);
4
+ return u.current = s, i(() => {
5
+ if (!r)
6
+ return;
7
+ const c = r.getFieldState(t);
8
+ e.current = c, c && u.current(c);
9
+ const o = r.subscribe(t, (f) => {
10
+ e.current = f, u.current(f);
11
+ });
12
+ return () => {
13
+ o();
14
+ };
15
+ }, [r, t]), e.current || {};
16
+ }
17
+ export {
18
+ R as useWatchState
19
+ };
@@ -0,0 +1,24 @@
1
+ export { FormController } from './components/FormController';
2
+ export { NexusField } from './components/NexusField';
3
+ export type { NexusFormConfig } from './components/NexusForm';
4
+ export { NexusForm } from './components/NexusForm';
5
+ export { NexusFormProvider } from './components/NexusFormProvider';
6
+ export { NexusLayout } from './components/NexusLayout';
7
+ export { NexusObject } from './components/NexusObject';
8
+ export type { FieldInheritValue } from './contexts/FieldInheritContext';
9
+ export { FieldInheritContext } from './contexts/FieldInheritContext';
10
+ export type { GridContextValue } from './contexts/GridContext';
11
+ export { GridContext } from './contexts/GridContext';
12
+ export type { LayoutConfigContextValue } from './contexts/LayoutConfigContext';
13
+ export { LayoutConfigContext } from './contexts/LayoutConfigContext';
14
+ export { useEngine } from './hooks/useEngine';
15
+ export { useFieldState } from './hooks/useFieldState';
16
+ export { useFieldValidator } from './hooks/useFieldValidator';
17
+ export { useFieldValue } from './hooks/useFieldValue';
18
+ export { useForm } from './hooks/useForm';
19
+ export { useFormConfig } from './hooks/useFormConfig';
20
+ export { useFormData } from './hooks/useFormData';
21
+ export { useWatch } from './hooks/useWatch';
22
+ export { useWatchAll } from './hooks/useWatchAll';
23
+ export { useWatchMultiple } from './hooks/useWatchMultiple';
24
+ export { useWatchState } from './hooks/useWatchState';
@@ -0,0 +1,42 @@
1
+ import { FormController as r } from "./components/FormController.js";
2
+ import { NexusField as x } from "./components/NexusField.js";
3
+ import { NexusForm as f } from "./components/NexusForm.js";
4
+ import { NexusFormProvider as u } from "./components/NexusFormProvider.js";
5
+ import { NexusLayout as a } from "./components/NexusLayout.js";
6
+ import { NexusObject as l } from "./components/NexusObject.js";
7
+ import { FieldInheritContext as n } from "./contexts/FieldInheritContext.js";
8
+ import { GridContext as C } from "./contexts/GridContext.js";
9
+ import { LayoutConfigContext as h } from "./contexts/LayoutConfigContext.js";
10
+ import { useEngine as W } from "./hooks/useEngine.js";
11
+ import { useFieldState as y } from "./hooks/useFieldState.js";
12
+ import { useFieldValidator as S } from "./hooks/useFieldValidator.js";
13
+ import { useFieldValue as b } from "./hooks/useFieldValue.js";
14
+ import { useForm as v } from "./hooks/useForm.js";
15
+ import { useFormConfig as D } from "./hooks/useFormConfig.js";
16
+ import { useFormData as G } from "./hooks/useFormData.js";
17
+ import { useWatch as M } from "./hooks/useWatch.js";
18
+ import { useWatchAll as P } from "./hooks/useWatchAll.js";
19
+ import { useWatchMultiple as q } from "./hooks/useWatchMultiple.js";
20
+ import { useWatchState as z } from "./hooks/useWatchState.js";
21
+ export {
22
+ n as FieldInheritContext,
23
+ r as FormController,
24
+ C as GridContext,
25
+ h as LayoutConfigContext,
26
+ x as NexusField,
27
+ f as NexusForm,
28
+ u as NexusFormProvider,
29
+ a as NexusLayout,
30
+ l as NexusObject,
31
+ W as useEngine,
32
+ y as useFieldState,
33
+ S as useFieldValidator,
34
+ b as useFieldValue,
35
+ v as useForm,
36
+ D as useFormConfig,
37
+ G as useFormData,
38
+ M as useWatch,
39
+ P as useWatchAll,
40
+ q as useWatchMultiple,
41
+ z as useWatchState
42
+ };
@@ -0,0 +1,6 @@
1
+ import { RenderTreeNode } from '@xbeeant/form-engine';
2
+ import { ReactElement } from 'react';
3
+ /**
4
+ * renderTreeNode — 递归渲染
5
+ */
6
+ export declare function renderTreeNode(node: RenderTreeNode, index: number): ReactElement;
@@ -0,0 +1,17 @@
1
+ import { jsx as r } from "react/jsx-runtime";
2
+ import { NexusField as e } from "../components/NexusField.js";
3
+ import { NexusLayout as u } from "../components/NexusLayout.js";
4
+ import { NexusObject as y } from "../components/NexusObject.js";
5
+ function p(t, a) {
6
+ return t.type === "field" ? /* @__PURE__ */ r(
7
+ e,
8
+ {
9
+ dataPath: t.dataPath,
10
+ layoutKey: t.layoutKey
11
+ },
12
+ t.layoutKey || t.dataPath
13
+ ) : t.type === "object" ? /* @__PURE__ */ r(y, { node: t }, `object-${t.layoutKey}-${a}`) : /* @__PURE__ */ r(u, { node: t }, `layout-${t.type}-${a}`);
14
+ }
15
+ export {
16
+ p as renderTreeNode
17
+ };
@@ -0,0 +1,5 @@
1
+ import { GridContextValue } from '../contexts/GridContext';
2
+ /**
3
+ * resolveColSpan — 统一解析子项在父 Grid 中的跨列数
4
+ */
5
+ export declare function resolveColSpan(colSpan: number | undefined, gridCtx: GridContextValue | null): number | undefined;
@@ -0,0 +1,9 @@
1
+ function u(o, n) {
2
+ if (o !== void 0)
3
+ return o;
4
+ if (n && n.column > 0)
5
+ return Math.max(1, Math.round(n.column / 24));
6
+ }
7
+ export {
8
+ u as resolveColSpan
9
+ };
@@ -0,0 +1 @@
1
+ (function(a,N){typeof exports=="object"&&typeof module<"u"?N(exports,require("@xbeeant/form-engine"),require("react/jsx-runtime"),require("react")):typeof define=="function"&&define.amd?define(["exports","@xbeeant/form-engine","react/jsx-runtime","react"],N):(a=typeof globalThis<"u"?globalThis:a||self,N(a.NexusFormEngineReact={},a.formEngine,a.jsxRuntime,a.react))})(this,(function(a,N,c,s){"use strict";class P{engine;formElementRef;getOnFinish;getOnFinishFailed;removeHiddenData=!0;watchers=new Map;globalWatcher=null;constructor(t){this.engine=t??new N.NexusEngine,this.engine.hasPlugin("async-validator")||this.engine.use(new N.AsyncValidatorPlugin(this.engine)),this.formElementRef={current:null},this.getOnFinish=()=>()=>{},this.getOnFinishFailed=()=>()=>{}}_bind(t,i,r){this.formElementRef.current=t,this.getOnFinish=i,this.getOnFinishFailed=r,this.engine.registerOnFieldValueChange((l,n)=>this._onFieldValueChange(l,n))}_syncConfig(t){if(t.removeHiddenData!==void 0&&(this.removeHiddenData=t.removeHiddenData),t.watch){this.watchers.clear(),this.globalWatcher=null;for(const[i,r]of Object.entries(t.watch))i==="#"?this.globalWatcher=r:this.watchers.set(i,r)}}_onFieldValueChange(t,i){const r=this.engine.getFormData(),l=this.removeHiddenData?r:this.engine.getAllFormData();this.globalWatcher&&this.globalWatcher(l,l,t);const n=this.watchers.get(t);n&&n(i,l)}_getEngine(){return this.engine}async submit(){const t=await this.engine.validate();if(t.size>0){this.focusFirstError(t),this.getOnFinishFailed()?.(t);return}const i=this.removeHiddenData?this.engine.getFormData():this.engine.getAllFormData();await this.getOnFinish()?.(i)}focusFirstError(t){const i=this.formElementRef.current;if(!i||t.size===0)return;const r=new Set(t.keys());requestAnimationFrame(()=>{const n=i.querySelectorAll("[data-nexus-field]");for(const o of Array.from(n)){const u=o.getAttribute("data-nexus-field");if(!u||!r.has(u))continue;o.scrollIntoView({behavior:"smooth",block:"center"}),o.querySelector('input:not([disabled]), select:not([disabled]), textarea:not([disabled]), [tabindex]:not([tabindex="-1"])')?.focus();return}})}resetFields(){this.engine.reset()}setErrorFields(t){this.engine.setErrorFields(t)}setValues(t){this.engine.setFieldValues(t)}setValueByPath(t,i){this.engine.setFieldValue(t,i)}setSchemaByPath(t,i){this.engine.setSchemaByPath(t,i)}setSchema(t){this.engine.setSchema(t)}getValues(t){return this.engine.getFormData(t)}getHiddenValues(){return this.engine.getHiddenValues()}getAllValues(){return this.engine.getAllFormData()}getValueByPath(t){return this.engine.getFieldValue(t)}registerValidator(t,i){this.engine.registerFieldValidator(t,i)}unregisterValidator(t,i){this.engine.unregisterFieldValidator(t,i)}revalidateField(t){this.engine.validateField(t,{trigger:"change"})}getSchema(){return this.engine.getSchema()}removeErrorField(t){this.engine.removeErrorField(t)}scrollToPath(t){this.formElementRef.current?.querySelector(`[data-nexus-field="${t}"]`)?.scrollIntoView({behavior:"smooth",block:"center"})}getFieldError(t){return this.engine.getFieldError(t)}getFieldsError(){return this.engine.getFieldsError()}validateFields(t){return this.engine.validate(t)}getFieldState(t){return this.engine.getFieldState(t)}}const R=s.createContext({}),M=s.createContext(null),k=s.createContext({}),H=s.createContext(null);function S(){const e=s.useContext(H);if(!e)throw new Error("[NexusField] Must be used within <NexusFormProvider>");return e}function q(e,t){if(e!==void 0)return e;if(t&&t.column>0)return Math.max(1,Math.round(t.column/24))}function J({dataPath:e,layoutKey:t}){const{engine:i,config:r,form:l}=S();s.useSyncExternalStore(y=>i.subscribeField(e,y),()=>i.getFieldVersion(e),()=>i.getFieldVersion(e));const n=i.getFieldState(e),o=s.useContext(M),u=s.useContext(k),g=s.useContext(R),f=s.useCallback(y=>{i.setFieldValue(e,y)},[i,e]),b=s.useCallback(y=>{y.currentTarget.contains(y.relatedTarget)||i.validateField(e,{trigger:"blur"})},[i,e]),d=s.useMemo(()=>n?.meta.enum?n.meta.enum.map((y,E)=>({value:y,label:n.meta.enumNames?.[E]??String(y)})):n?.props.options,[n?.meta.enum,n?.meta.enumNames,n?.props.options]),F=s.useMemo(()=>{const y={};if(n?.reactions){for(const E of n.reactions)if(E.dependencies)for(const p of E.dependencies)y[p]=i.getFieldValue(p)}return y},[n?.reactions,i]);if(!n)return i.getSnapshot()>0&&console.warn(`[NexusField] Field not found: ${e}`),null;if(g.visible===!1||!n.visible)return u.removeHidden===!0?null:c.jsx("div",{className:"hidden","data-nexus-hidden":e});const h=r.readOnly||g.readOnly===!0||n.readOnly,C=g.disabled===!0||n.disabled,v=h&&!!n.meta.readOnlyWidget,x=v?n.meta.readOnlyWidget:n.meta.widget;let V=i.getWidget(x);if(!V&&v&&(V=i.getWidget(n.meta.widget)),!V)return c.jsxs("div",{className:"text-xs text-red-500","data-nexus-field":e,children:['⚠️ Widget "',n.meta.widget,'" 未注册 (path: ',e,")"]});const j=n.meta.displayType??r.displayType,D=n.meta.labelWidth??r.labelWidth,m=n.meta.column??r.column,O=q(n.meta.colSpan,o),w={...n.meta.width?{width:n.meta.width,flexShrink:0}:{},...O?{gridColumn:`span ${O}`}:{}};return c.jsx("div",{"data-nexus-field":e,onBlur:b,style:Object.keys(w).length>0?w:void 0,children:c.jsx(V,{dataPath:e,path:e,value:n.value,onChange:f,disabled:C,readOnly:h,loading:n.loading,required:n.required,title:n.meta.title,description:n.meta.description,placeholder:n.meta.placeholder,label:n.meta.label,options:d,errors:n.errors,extra:n.meta.extra,displayType:j,labelWidth:D,column:m,form:l,dependValues:F,items:n.meta.items,...n.props},t)})}function B({node:e}){const{engine:t}=S(),i=t.getLayout(e.type),r=e.children.map((h,C)=>$(h,C)),l=s.useContext(M),n=q(e.props.colSpan,l),o={...n?{gridColumn:`span ${n}`}:{},...e.props.width?{width:e.props.width,flexShrink:0}:{}},u=s.useMemo(()=>({removeHidden:e.props.removeHidden}),[e.props.removeHidden]);if(!i)return c.jsx(k.Provider,{value:u,children:c.jsxs("div",{"data-nexus-layout":e.type,className:"mb-4",style:Object.keys(o).length>0?o:void 0,children:[e.title&&c.jsx("div",{className:"mb-2 font-bold",children:e.title}),r]})});const{displayType:g,labelWidth:f,colSpan:b,width:d,...F}=e.props;return c.jsx(k.Provider,{value:u,children:c.jsx("div",{style:Object.keys(o).length>0?o:void 0,children:c.jsx(i,{...F,node:e,title:e.title,children:r})})})}function I({node:e}){const{engine:t,config:i}=S(),r=s.useContext(R);s.useSyncExternalStore(F=>t.subscribeField(e.dataPath,F),()=>t.getFieldVersion(e.dataPath),()=>t.getFieldVersion(e.dataPath));const l=t.getFieldState(e.dataPath),[n,o]=s.useState(!1),u=(i.column??1)>1,g=u?{gridTemplateColumns:`repeat(${i.column}, 1fr)`}:{},f={disabled:r.disabled??(l?.disabled===!0?!0:void 0),readOnly:r.readOnly??(l?.readOnly===!0?!0:void 0),visible:r.visible===!1||l?.visible===!1?!1:void 0},b=f.visible===!1,d=()=>o(F=>!F);return c.jsx(R.Provider,{value:f,children:c.jsxs("div",{"data-nexus-object":e.dataPath,className:`mb-4 ${b?"hidden":""}`,children:[e.title&&c.jsxs("div",{onClick:d,className:"flex gap-1 mb-2 cursor-pointer select-none border-none bg-transparent p-0 font-bold",children:[c.jsx("svg",{width:"12",height:"12",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",className:`align-middle transition-transform duration-200 ease-in-out ${n?"rotate-0":"rotate-90"}`,"aria-hidden":"true",children:c.jsx("polyline",{points:"9 18 15 12 9 6"})}),e.title]}),c.jsx("div",{className:`${u?"grid gap-x-4":""} ${n?"hidden":""}`,style:Object.keys(g).length>0?g:void 0,children:e.children.map((F,h)=>$(F,h))})]})})}function $(e,t){return e.type==="field"?c.jsx(J,{dataPath:e.dataPath,layoutKey:e.layoutKey},e.layoutKey||e.dataPath):e.type==="object"?c.jsx(I,{node:e},`object-${e.layoutKey}-${t}`):c.jsx(B,{node:e},`layout-${e.type}-${t}`)}function K({engine:e,config:t,form:i,children:r}){const l=s.useMemo(()=>({engine:e,config:t,form:i}),[e,t,i]);return c.jsx(H.Provider,{value:l,children:r})}function T(){}function Y({form:e,schema:t,initialValues:i,widgets:r,layouts:l,onFinish:n,onFinishFailed:o,footer:u=!1,className:g,style:f,children:b,labelCol:d,labelWidth:F,colon:h,label:C,displayType:v,readOnly:x,column:V,watch:j,removeHiddenData:D=!0}){const m=e._getEngine(),O=s.useRef(null),w=v??t?.displayType??"row",y=C??t?.label??!0,E=h??t?.colon,p=F??t?.labelWidth,G=x??t?.readOnly??!1,W=V??t?.column;s.useEffect(()=>{r&&m.registerWidgets(r),l&&m.registerLayouts(l)},[m,r,l]);const z=s.useRef(!0),ae=s.useRef(i);s.useEffect(()=>{t&&(z.current?(m.init(t,ae.current),z.current=!1):m.init(t,m.getFormData()))},[m,t]);const U=s.useRef(T),Q=s.useRef(T);U.current=n??T,Q.current=o??T,s.useEffect(()=>{e._bind(O.current,()=>U.current,()=>Q.current)},[e]),s.useEffect(()=>{e._syncConfig({removeHiddenData:D,watch:j})},[e,D,j]);const ce=s.useSyncExternalStore(m.subscribeStore,m.getSnapshot,m.getSnapshot),de=s.useMemo(()=>m.getRenderTree(),[m,ce]),fe=s.useCallback(async A=>{A.preventDefault(),await e.submit()},[e]),ge=s.useCallback(()=>{e.resetFields()},[e]);let L=null;u===!0?L=c.jsxs("div",{className:"mt-4",children:[c.jsx("button",{type:"submit",children:"提交"})," ",c.jsx("button",{type:"button",onClick:ge,children:"重置"})]}):u&&(L=u);const X=s.useMemo(()=>{if(d)return d;if(p)return{style:{width:typeof p=="number"?`${p}px`:p}}},[d,p]),he=s.useMemo(()=>({labelCol:X,labelWidth:p,colon:E,label:y,displayType:w,readOnly:G,column:W}),[X,p,E,y,w,G,W]);return c.jsx(K,{engine:m,config:he,form:e,children:c.jsxs("form",{ref:O,onSubmit:fe,className:g,style:{...f,...W&&W>1?{display:"grid",gridTemplateColumns:`repeat(${W}, 1fr)`,gap:"0 16px"}:{}},noValidate:!0,children:[de.map((A,be)=>$(A,be)),!x&&L,b]})})}function _(){const{engine:e}=S();return e}function Z(e){const{engine:t}=S();return s.useSyncExternalStore(i=>t.subscribeField(e,i),()=>t.getFieldVersion(e),()=>t.getFieldVersion(e)),t.getFieldState(e)}function ee(e,t,i,r){const{engine:l}=S(),n=s.useRef(i);n.current=i;const o=s.useRef(r?.dependsOn);o.current=r?.dependsOn;const u=r?.deps;s.useEffect(()=>{if(!e||!t)return;const g=n.current;return e.registerValidator(t,g),()=>{e.unregisterValidator(t,g)}},[e,t,...u??[]]),s.useEffect(()=>{if(!t||!o.current||o.current.length===0)return;const g=l;if(!g)return;const f=t,b=o.current.map(d=>g.subscribeField(d,()=>{e?.revalidateField(f)}));return()=>{for(const d of b)d()}},[l,e,t])}function te(e){const t=_();return s.useSyncExternalStore(i=>t.subscribeField(e,i),()=>t.getFieldVersion(e),()=>t.getFieldVersion(e)),t.getFieldValue(e)}function ne(e){const t=s.useRef(null);return t.current||(t.current=new P(e)),[t.current]}function ie(){const{config:e}=S();return e}function se(){const e=_(),t=s.useSyncExternalStore(e.subscribeStore,e.getSnapshot,e.getSnapshot);return s.useMemo(()=>e.getFormData(),[e,t])}function re(e,t,i,r){const{deep:l=!1}=r||{},n=s.useRef(void 0),o=s.useRef(i);return o.current=i,s.useEffect(()=>{if(!e)return;const u=e.getFieldValue(t);n.current===void 0&&(n.current=u),(l?JSON.stringify(u)!==JSON.stringify(n.current):u!==n.current)&&(n.current=u,o.current(u));const f=e.subscribe(t,b=>{const d=b.value;(l?JSON.stringify(d)!==JSON.stringify(n.current):d!==n.current)&&(n.current=d,o.current(d))});return()=>{f()}},[e,t,l]),n.current}function le(e,t,i){const{deep:r=!1}=i||{},l=s.useRef({}),n=s.useRef({}),o=s.useRef(t);return o.current=t,s.useEffect(()=>{if(!e)return;const u=e.getFormData();l.current=u,n.current=u,o.current(u);const g=e.subscribeAll(f=>{if(r)JSON.stringify(f)!==JSON.stringify(l.current)&&(l.current=f,n.current=f,o.current(f));else{let b=!1;for(const d in f)if(f[d]!==l.current[d]){b=!0;break}b&&(l.current=f,n.current=f,o.current(f))}});return()=>{g()}},[e,r]),n.current}function oe(e,t,i,r){const{deep:l=!1}=r||{},n=s.useRef({}),o=s.useRef({}),u=s.useRef(i);u.current=i;const g=s.useRef(t);g.current=t;const f=[...t].sort().join(",");return s.useEffect(()=>{if(!e)return;const b=g.current,d={};for(const h of b)d[h]=e.getFieldValue(h);n.current=d,o.current=d,u.current(d);const F=b.map(h=>e.subscribe(h,C=>{const v=C.value,x=n.current[h];(l?JSON.stringify(v)!==JSON.stringify(x):v!==x)&&(n.current[h]=v,o.current={[h]:v},u.current(o.current))}));return()=>{for(const h of F)h()}},[e,l,f]),o.current}function ue(e,t,i){const r=s.useRef(void 0),l=s.useRef(i);return l.current=i,s.useEffect(()=>{if(!e)return;const n=e.getFieldState(t);r.current=n,n&&l.current(n);const o=e.subscribe(t,u=>{r.current=u,l.current(u)});return()=>{o()}},[e,t]),r.current||{}}a.FieldInheritContext=R,a.FormController=P,a.GridContext=M,a.LayoutConfigContext=k,a.NexusField=J,a.NexusForm=Y,a.NexusFormProvider=K,a.NexusLayout=B,a.NexusObject=I,a.useEngine=_,a.useFieldState=Z,a.useFieldValidator=ee,a.useFieldValue=te,a.useForm=ne,a.useFormConfig=ie,a.useFormData=se,a.useWatch=re,a.useWatchAll=le,a.useWatchMultiple=oe,a.useWatchState=ue,Object.defineProperty(a,Symbol.toStringTag,{value:"Module"})}));
package/package.json ADDED
@@ -0,0 +1,75 @@
1
+ {
2
+ "name": "@xbeeant/form-engine-react",
3
+ "version": "0.0.1",
4
+ "publishConfig": {
5
+ "access": "public",
6
+ "registry": "https://registry.npmjs.org/"
7
+ },
8
+ "type": "module",
9
+ "main": "./dist/es/index.js",
10
+ "module": "./dist/es/index.js",
11
+ "types": "./dist/es/index.d.ts",
12
+ "unpkg": "./dist/umd/index.umd.cjs",
13
+ "jsdelivr": "./dist/umd/index.umd.cjs",
14
+ "exports": {
15
+ ".": {
16
+ "types": "./dist/es/index.d.ts",
17
+ "import": "./dist/es/index.js",
18
+ "require": "./dist/cjs/index.cjs"
19
+ },
20
+ "./components/*": {
21
+ "types": "./dist/es/components/*.d.ts",
22
+ "import": "./dist/es/components/*.js",
23
+ "require": "./dist/cjs/components/*.cjs"
24
+ },
25
+ "./hooks/*": {
26
+ "types": "./dist/es/hooks/*.d.ts",
27
+ "import": "./dist/es/hooks/*.js",
28
+ "require": "./dist/cjs/hooks/*.cjs"
29
+ },
30
+ "./contexts/*": {
31
+ "types": "./dist/es/contexts/*.d.ts",
32
+ "import": "./dist/es/contexts/*.js",
33
+ "require": "./dist/cjs/contexts/*.cjs"
34
+ },
35
+ "./utils/*": {
36
+ "types": "./dist/es/utils/*.d.ts",
37
+ "import": "./dist/es/utils/*.js",
38
+ "require": "./dist/cjs/utils/*.cjs"
39
+ },
40
+ "./package.json": "./package.json"
41
+ },
42
+ "files": [
43
+ "dist",
44
+ "src",
45
+ "README.md",
46
+ "!**/*.map"
47
+ ],
48
+ "sideEffects": [
49
+ "**/*.css"
50
+ ],
51
+ "scripts": {
52
+ "build": "npm run build:es && npm run build:cjs && npm run build:umd",
53
+ "prepublishOnly": "npm run build",
54
+ "build:es": "tsc -b && vite build -f es",
55
+ "build:cjs": "vite build -f cjs",
56
+ "build:umd": "vite build -f umd",
57
+ "lint": "biome check .",
58
+ "lint:fix": "biome check --write ."
59
+ },
60
+ "peerDependencies": {
61
+ "react": ">=18.0.0",
62
+ "react-dom": ">=18.0.0"
63
+ },
64
+ "peerDependenciesMeta": {
65
+ "react": {
66
+ "optional": false
67
+ },
68
+ "react-dom": {
69
+ "optional": false
70
+ }
71
+ },
72
+ "dependencies": {
73
+ "@xbeeant/form-engine": "^0.0.1"
74
+ }
75
+ }