@xbeeant/form-engine-designer 0.0.2 → 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 (137) hide show
  1. package/dist/es/Canvas.js +42 -46
  2. package/dist/es/Canvas.js.map +1 -1
  3. package/dist/es/Designer.js +121 -98
  4. package/dist/es/Designer.js.map +1 -1
  5. package/dist/es/DesignerContext.js +86 -73
  6. package/dist/es/DesignerContext.js.map +1 -1
  7. package/dist/es/Palette.js +3 -3
  8. package/dist/es/Palette.js.map +1 -1
  9. package/dist/es/PropertyPanel.js +97 -97
  10. package/dist/es/PropertyPanel.js.map +1 -1
  11. package/dist/es/catalog.js +19 -11
  12. package/dist/es/catalog.js.map +1 -1
  13. package/dist/es/designer-context.js +110 -0
  14. package/dist/es/designer-context.js.map +1 -0
  15. package/dist/es/history.js +73 -0
  16. package/dist/es/history.js.map +1 -0
  17. package/dist/es/index.js +3 -3
  18. package/dist/es/property/basic-property.js +6 -0
  19. package/dist/es/property/basic-property.js.map +1 -1
  20. package/dist/es/property-panel.js +294 -0
  21. package/dist/es/property-panel.js.map +1 -0
  22. package/dist/es/resizable-panel.js +103 -0
  23. package/dist/es/resizable-panel.js.map +1 -0
  24. package/dist/es/schema-utils.js +286 -0
  25. package/dist/es/schema-utils.js.map +1 -0
  26. package/dist/es/widgets/BindEditor.js +60 -49
  27. package/dist/es/widgets/BindEditor.js.map +1 -1
  28. package/dist/es/widgets/CodeEditor.js +41 -49
  29. package/dist/es/widgets/CodeEditor.js.map +1 -1
  30. package/dist/es/widgets/DefaultEditor.js +25 -30
  31. package/dist/es/widgets/DefaultEditor.js.map +1 -1
  32. package/dist/es/widgets/DependenciesEditor.js +21 -21
  33. package/dist/es/widgets/DependenciesEditor.js.map +1 -1
  34. package/dist/es/widgets/EnumEditor.js +25 -31
  35. package/dist/es/widgets/EnumEditor.js.map +1 -1
  36. package/dist/es/widgets/ExpressionSwitch.js +32 -30
  37. package/dist/es/widgets/ExpressionSwitch.js.map +1 -1
  38. package/dist/es/widgets/ReactionsEditor.js +103 -103
  39. package/dist/es/widgets/ReactionsEditor.js.map +1 -1
  40. package/dist/es/widgets/RemoteDataEditor.js +63 -63
  41. package/dist/es/widgets/RemoteDataEditor.js.map +1 -1
  42. package/dist/es/widgets/ValidateEditor.js +49 -49
  43. package/dist/es/widgets/ValidateEditor.js.map +1 -1
  44. package/dist/es/widgets/bind-editor.js +78 -0
  45. package/dist/es/widgets/bind-editor.js.map +1 -0
  46. package/dist/es/widgets/code-editor.js +76 -0
  47. package/dist/es/widgets/code-editor.js.map +1 -0
  48. package/dist/es/widgets/default-editor.js +50 -0
  49. package/dist/es/widgets/default-editor.js.map +1 -0
  50. package/dist/es/widgets/dependencies-editor.js +36 -0
  51. package/dist/es/widgets/dependencies-editor.js.map +1 -0
  52. package/dist/es/widgets/enum-editor.js +43 -0
  53. package/dist/es/widgets/enum-editor.js.map +1 -0
  54. package/dist/es/widgets/expression-builder.js +367 -0
  55. package/dist/es/widgets/expression-builder.js.map +1 -0
  56. package/dist/es/widgets/expression-model.js +340 -0
  57. package/dist/es/widgets/expression-model.js.map +1 -0
  58. package/dist/es/widgets/expression-switch.js +49 -0
  59. package/dist/es/widgets/expression-switch.js.map +1 -0
  60. package/dist/es/widgets/index.js +13 -13
  61. package/dist/es/widgets/index.js.map +1 -1
  62. package/dist/es/widgets/options-editor.js +102 -0
  63. package/dist/es/widgets/options-editor.js.map +1 -0
  64. package/dist/es/widgets/reactions-editor.js +401 -0
  65. package/dist/es/widgets/reactions-editor.js.map +1 -0
  66. package/dist/es/widgets/reactions-model.js +107 -0
  67. package/dist/es/widgets/reactions-model.js.map +1 -0
  68. package/dist/es/widgets/remote-data-editor.js +314 -0
  69. package/dist/es/widgets/remote-data-editor.js.map +1 -0
  70. package/dist/es/widgets/use-form-data-fields.js +16 -0
  71. package/dist/es/widgets/use-form-data-fields.js.map +1 -0
  72. package/dist/es/widgets/validate-editor.js +118 -0
  73. package/dist/es/widgets/validate-editor.js.map +1 -0
  74. package/package.json +4 -5
  75. package/dist/es/react/src/components/FormController.js +0 -154
  76. package/dist/es/react/src/components/FormController.js.map +0 -1
  77. package/dist/es/react/src/components/NexusField.js +0 -99
  78. package/dist/es/react/src/components/NexusField.js.map +0 -1
  79. package/dist/es/react/src/components/NexusForm.js +0 -121
  80. package/dist/es/react/src/components/NexusForm.js.map +0 -1
  81. package/dist/es/react/src/components/NexusFormProvider.js +0 -19
  82. package/dist/es/react/src/components/NexusFormProvider.js.map +0 -1
  83. package/dist/es/react/src/components/NexusLayout.js +0 -49
  84. package/dist/es/react/src/components/NexusLayout.js.map +0 -1
  85. package/dist/es/react/src/components/NexusObject.js +0 -65
  86. package/dist/es/react/src/components/NexusObject.js.map +0 -1
  87. package/dist/es/react/src/contexts/FieldInheritContext.js +0 -6
  88. package/dist/es/react/src/contexts/FieldInheritContext.js.map +0 -1
  89. package/dist/es/react/src/contexts/GridContext.js +0 -6
  90. package/dist/es/react/src/contexts/GridContext.js.map +0 -1
  91. package/dist/es/react/src/contexts/LayoutConfigContext.js +0 -6
  92. package/dist/es/react/src/contexts/LayoutConfigContext.js.map +0 -1
  93. package/dist/es/react/src/contexts/NexusContext.js +0 -13
  94. package/dist/es/react/src/contexts/NexusContext.js.map +0 -1
  95. package/dist/es/react/src/hooks/useForm.js +0 -10
  96. package/dist/es/react/src/hooks/useForm.js.map +0 -1
  97. package/dist/es/react/src/utils/renderTreeNode.js +0 -18
  98. package/dist/es/react/src/utils/renderTreeNode.js.map +0 -1
  99. package/dist/es/react/src/utils/resolveColSpan.js +0 -10
  100. package/dist/es/react/src/utils/resolveColSpan.js.map +0 -1
  101. package/dist/es/schemaUtils.test.js +0 -188
  102. package/dist/es/schemaUtils.test.js.map +0 -1
  103. package/dist/es/vite-env.d.js +0 -2
  104. package/dist/es/vite-env.d.js.map +0 -1
  105. package/dist/es/widgets/expressionModel.test.js +0 -193
  106. package/dist/es/widgets/expressionModel.test.js.map +0 -1
  107. package/src/Canvas.tsx +0 -1111
  108. package/src/Designer.css +0 -206
  109. package/src/Designer.tsx +0 -254
  110. package/src/DesignerContext.tsx +0 -192
  111. package/src/Palette.tsx +0 -261
  112. package/src/PropertyPanel.tsx +0 -486
  113. package/src/ResizablePanel.tsx +0 -210
  114. package/src/catalog.ts +0 -526
  115. package/src/index.ts +0 -25
  116. package/src/property/basic-property.ts +0 -126
  117. package/src/schemaUtils.test.ts +0 -261
  118. package/src/schemaUtils.ts +0 -627
  119. package/src/types.ts +0 -38
  120. package/src/vite-env.d.ts +0 -1
  121. package/src/widgets/BindEditor.tsx +0 -105
  122. package/src/widgets/CodeEditor.tsx +0 -114
  123. package/src/widgets/DefaultEditor.tsx +0 -73
  124. package/src/widgets/DependenciesEditor.tsx +0 -56
  125. package/src/widgets/EnumEditor.tsx +0 -66
  126. package/src/widgets/ExpressionBuilder.tsx +0 -509
  127. package/src/widgets/ExpressionSwitch.tsx +0 -62
  128. package/src/widgets/OptionsEditor.tsx +0 -141
  129. package/src/widgets/ReactionsEditor.tsx +0 -532
  130. package/src/widgets/RemoteDataEditor.tsx +0 -382
  131. package/src/widgets/ValidateEditor.tsx +0 -162
  132. package/src/widgets/expressionModel.test.ts +0 -262
  133. package/src/widgets/expressionModel.ts +0 -573
  134. package/src/widgets/index.ts +0 -45
  135. package/src/widgets/reactionsModel.ts +0 -190
  136. package/src/widgets/useFormDataFields.ts +0 -21
  137. /package/dist/es/{form-engine-designer.css → index.css} +0 -0
@@ -1,162 +1,185 @@
1
- import { jsx as t, jsxs as d } from "react/jsx-runtime";
2
- import { widgetSchemas as A, registerAntdUI as B } from "@xbeeant/form-engine-ui";
3
- import { Typography as P, Space as k, Radio as f, Button as y, Popconfirm as E, Input as J, message as x } from "antd";
4
- import { useMemo as v, useState as b } from "react";
5
- import { Canvas as L } from "./Canvas.js";
6
- /* empty css */
7
- import { layoutCatalog as U, widgetCatalog as W } from "./catalog.js";
8
- import { DesignerProvider as D, useDesigner as M } from "./DesignerContext.js";
9
- import { Palette as z } from "./Palette.js";
10
- import { PropertyPanel as F } from "./PropertyPanel.js";
11
- import { ResizablePanel as w } from "./ResizablePanel.js";
12
- const S = {
1
+ import { jsx as t, jsxs as m } from "react/jsx-runtime";
2
+ import { widgetSchemas as O, registerAntdUI as P } from "@xbeeant/form-engine-ui";
3
+ import { Typography as U, Space as B, Radio as u, Button as f, Popconfirm as J, Input as W, message as S } from "antd";
4
+ import { useMemo as w, useState as x, useEffect as K } from "react";
5
+ import { Canvas as M } from "./canvas.js";
6
+ /* empty css */
7
+ import { layoutCatalog as z, widgetCatalog as I } from "./catalog.js";
8
+ import { DesignerProvider as F, useDesigner as G } from "./designer-context.js";
9
+ import { Palette as H } from "./palette.js";
10
+ import { PropertyPanel as X } from "./property-panel.js";
11
+ import { ResizablePanel as N } from "./resizable-panel.js";
12
+ const C = {
13
13
  type: "object",
14
14
  displayType: "row",
15
15
  properties: {}
16
16
  };
17
- function ee({
18
- schema: o,
19
- propertySchemaMap: n = A,
20
- onSchemaChange: i,
21
- registerUI: l = B,
22
- fields: m,
23
- widgetCatalog: r,
24
- layoutCatalog: c
17
+ function ae({
18
+ schema: i,
19
+ propertySchemaMap: l = O,
20
+ onSchemaChange: c,
21
+ registerUI: s = P,
22
+ fields: h,
23
+ widgetCatalog: a,
24
+ layoutCatalog: d
25
25
  }) {
26
- const u = v(
27
- () => o ?? S,
28
- [o]
29
- ), p = v(
30
- () => C(W, r, "widget"),
31
- [r]
32
- ), g = v(
33
- () => C(U, c, "layoutType"),
34
- [c]
26
+ const g = w(
27
+ () => i ?? C,
28
+ [i]
29
+ ), y = w(
30
+ () => T(I, a, "widget"),
31
+ [a]
32
+ ), p = w(
33
+ () => T(z, d, "layoutType"),
34
+ [d]
35
35
  );
36
36
  return /* @__PURE__ */ t(
37
- D,
37
+ F,
38
38
  {
39
- initialSchema: u,
40
- onSchemaChange: i,
41
- registerUI: l,
42
- fields: m,
43
- propertySchemaMap: n,
44
- widgetCatalog: p,
45
- layoutCatalog: g,
46
- children: /* @__PURE__ */ t(I, {})
39
+ initialSchema: g,
40
+ onSchemaChange: c,
41
+ registerUI: s,
42
+ fields: h,
43
+ propertySchemaMap: l,
44
+ widgetCatalog: y,
45
+ layoutCatalog: p,
46
+ children: /* @__PURE__ */ t(Z, {})
47
47
  }
48
48
  );
49
49
  }
50
- function C(o, n, i) {
51
- if (!n || n.length === 0)
52
- return o;
53
- const l = new Set(n.map((r) => r[i]).filter(Boolean));
54
- return [...o.filter((r) => !l.has(r[i])), ...n];
50
+ function T(i, l, c) {
51
+ if (!l || l.length === 0)
52
+ return i;
53
+ const s = new Set(l.map((a) => a[c]).filter(Boolean));
54
+ return [...i.filter((a) => !s.has(a[c])), ...l];
55
55
  }
56
- function I() {
57
- const { mode: o, setMode: n, schema: i, setSchema: l, selectNode: m } = M(), [r, c] = b(""), [u, p] = b(!1), g = () => {
58
- l(S), m(null), o === "schema" && c(JSON.stringify(S, null, 2));
59
- }, j = () => {
60
- c(JSON.stringify(i, null, 2)), p(!0);
61
- }, N = () => {
62
- if (u) {
56
+ function Z() {
57
+ const {
58
+ mode: i,
59
+ setMode: l,
60
+ schema: c,
61
+ setSchema: s,
62
+ selectNode: h,
63
+ undo: a,
64
+ redo: d,
65
+ canUndo: g,
66
+ canRedo: y
67
+ } = G(), [p, v] = x(""), [j, b] = x(!1);
68
+ K(() => {
69
+ const e = (n) => {
70
+ const o = n.target;
71
+ if (o && (o.tagName === "INPUT" || o.tagName === "TEXTAREA" || o.isContentEditable) || !(n.metaKey || n.ctrlKey))
72
+ return;
73
+ const r = n.key.toLowerCase();
74
+ r === "z" ? (n.preventDefault(), n.shiftKey ? d() : a()) : r === "y" && (n.preventDefault(), d());
75
+ };
76
+ return window.addEventListener("keydown", e), () => window.removeEventListener("keydown", e);
77
+ }, [a, d]);
78
+ const k = () => {
79
+ s(C), h(null), i === "schema" && v(JSON.stringify(C, null, 2));
80
+ }, E = () => {
81
+ v(JSON.stringify(c, null, 2)), b(!0);
82
+ }, R = () => {
83
+ if (j) {
63
84
  try {
64
- const e = JSON.parse(r);
65
- e && e.type === "object" && e.properties ? l(e) : x.warning('Schema 必须包含 type: "object" 和 properties');
85
+ const e = JSON.parse(p);
86
+ e && e.type === "object" && e.properties ? s(e) : S.warning('Schema 必须包含 type: "object" 和 properties');
66
87
  } catch {
67
- x.error("JSON 格式错误,无法解析");
88
+ S.error("JSON 格式错误,无法解析");
68
89
  }
69
- p(!1);
90
+ b(!1);
70
91
  }
71
- }, T = (e) => {
72
- e === "schema" ? j() : N(), n(e);
73
- }, O = () => {
74
- const e = JSON.stringify(i, null, 2), h = new Blob([e], { type: "application/json" }), s = URL.createObjectURL(h), a = document.createElement("a");
75
- a.href = s, a.download = "schema.json", a.click(), URL.revokeObjectURL(s);
76
- }, R = () => {
92
+ }, A = (e) => {
93
+ e === "schema" ? E() : R(), l(e);
94
+ }, L = () => {
95
+ const e = JSON.stringify(c, null, 2), n = new Blob([e], { type: "application/json" }), o = URL.createObjectURL(n), r = document.createElement("a");
96
+ r.href = o, r.download = "schema.json", r.click(), URL.revokeObjectURL(o);
97
+ }, D = () => {
77
98
  const e = document.createElement("input");
78
99
  e.type = "file", e.accept = "application/json", e.onchange = () => {
79
- const h = e.files?.[0];
80
- if (!h)
100
+ const n = e.files?.[0];
101
+ if (!n)
81
102
  return;
82
- const s = new FileReader();
83
- s.onload = () => {
103
+ const o = new FileReader();
104
+ o.onload = () => {
84
105
  try {
85
- const a = JSON.parse(s.result);
86
- a && a.type === "object" && a.properties && l(a);
106
+ const r = JSON.parse(o.result);
107
+ r && r.type === "object" && r.properties && s(r);
87
108
  } catch {
88
109
  }
89
- }, s.readAsText(h);
110
+ }, o.readAsText(n);
90
111
  }, e.click();
91
112
  };
92
- return /* @__PURE__ */ d("div", { className: "flex flex-col h-full bg-white", children: [
93
- /* @__PURE__ */ d("div", { className: "flex items-center justify-between px-4 py-2 border-b border-[#f0f0f0] bg-[#fafafa]", children: [
94
- /* @__PURE__ */ t(P.Text, { strong: !0, children: "Nexus 表单设计器" }),
95
- /* @__PURE__ */ d(k, { children: [
96
- /* @__PURE__ */ d(
97
- f.Group,
113
+ return /* @__PURE__ */ m("div", { className: "flex flex-col h-full bg-white", children: [
114
+ /* @__PURE__ */ m("div", { className: "flex items-center justify-between px-4 py-2 border-b border-[#f0f0f0] bg-[#fafafa]", children: [
115
+ /* @__PURE__ */ t(U.Text, { strong: !0, children: "Nexus 表单设计器" }),
116
+ /* @__PURE__ */ m(B, { children: [
117
+ /* @__PURE__ */ m(
118
+ u.Group,
98
119
  {
99
- value: o,
100
- onChange: (e) => T(e.target.value),
120
+ value: i,
121
+ onChange: (e) => A(e.target.value),
101
122
  children: [
102
- /* @__PURE__ */ t(f.Button, { value: "design", children: "设计" }),
103
- /* @__PURE__ */ t(f.Button, { value: "preview", children: "预览" }),
104
- /* @__PURE__ */ t(f.Button, { value: "schema", children: "Schema" })
123
+ /* @__PURE__ */ t(u.Button, { value: "design", children: "设计" }),
124
+ /* @__PURE__ */ t(u.Button, { value: "preview", children: "预览" }),
125
+ /* @__PURE__ */ t(u.Button, { value: "schema", children: "Schema" })
105
126
  ]
106
127
  }
107
128
  ),
108
- /* @__PURE__ */ t(y, { onClick: R, children: "导入" }),
109
- /* @__PURE__ */ t(y, { onClick: O, children: "导出" }),
129
+ /* @__PURE__ */ t(f, { onClick: D, children: "导入" }),
130
+ /* @__PURE__ */ t(f, { onClick: L, children: "导出" }),
131
+ /* @__PURE__ */ t(f, { disabled: !g, onClick: a, children: "撤销" }),
132
+ /* @__PURE__ */ t(f, { disabled: !y, onClick: d, children: "重做" }),
110
133
  /* @__PURE__ */ t(
111
- E,
134
+ J,
112
135
  {
113
136
  title: "清空画布",
114
- description: "将移除画布上所有组件,此操作不可撤销",
137
+ description: "将移除画布上所有组件,可使用 Ctrl/Cmd+Z 撤销",
115
138
  okText: "清空",
116
139
  cancelText: "取消",
117
140
  okButtonProps: { danger: !0 },
118
- onConfirm: g,
119
- children: /* @__PURE__ */ t(y, { danger: !0, children: "清空" })
141
+ onConfirm: k,
142
+ children: /* @__PURE__ */ t(f, { danger: !0, children: "清空" })
120
143
  }
121
144
  )
122
145
  ] })
123
146
  ] }),
124
- o === "schema" ? /* @__PURE__ */ t("div", { className: "flex-1 overflow-auto p-4 bg-[#1e1e1e]", children: /* @__PURE__ */ t(
125
- J.TextArea,
147
+ i === "schema" ? /* @__PURE__ */ t("div", { className: "flex-1 overflow-auto p-4 bg-[#1e1e1e]", children: /* @__PURE__ */ t(
148
+ W.TextArea,
126
149
  {
127
- value: r,
128
- onChange: (e) => c(e.target.value),
150
+ value: p,
151
+ onChange: (e) => v(e.target.value),
129
152
  autoSize: { minRows: 20 },
130
153
  className: "font-mono! text-[13px]! leading-[1.6]! bg-[#1e1e1e]! text-[#d4d4d4]! border-[#3e3e42]!"
131
154
  }
132
- ) }) : /* @__PURE__ */ d("div", { className: "flex flex-1 overflow-hidden", children: [
155
+ ) }) : /* @__PURE__ */ m("div", { className: "flex flex-1 overflow-hidden", children: [
133
156
  /* @__PURE__ */ t(
134
- w,
157
+ N,
135
158
  {
136
159
  side: "left",
137
- defaultWidth: 240,
160
+ defaultWidth: 320,
138
161
  minWidth: 160,
139
162
  maxWidth: 420,
140
163
  collapsedTitle: "组件面板",
141
- children: /* @__PURE__ */ t(z, {})
164
+ children: /* @__PURE__ */ t(H, {})
142
165
  }
143
166
  ),
144
- /* @__PURE__ */ t(L, {}),
167
+ /* @__PURE__ */ t(M, {}),
145
168
  /* @__PURE__ */ t(
146
- w,
169
+ N,
147
170
  {
148
171
  side: "right",
149
172
  defaultWidth: 320,
150
173
  minWidth: 240,
151
- maxWidth: 560,
174
+ maxWidth: 800,
152
175
  collapsedTitle: "属性面板",
153
- children: /* @__PURE__ */ t(F, {})
176
+ children: /* @__PURE__ */ t(X, {})
154
177
  }
155
178
  )
156
179
  ] })
157
180
  ] });
158
181
  }
159
182
  export {
160
- ee as Designer
183
+ ae as Designer
161
184
  };
162
- //# sourceMappingURL=Designer.js.map
185
+ //# sourceMappingURL=designer.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"Designer.js","sources":["../../src/Designer.tsx"],"sourcesContent":["// ============================================================================\n// @xbeeant/form-engine-designer — 主组件\n// ============================================================================\n\nimport type { NexusEngine, NexusSchema } from '@xbeeant/form-engine';\nimport type { PropertySchemaMap } from '@xbeeant/form-engine-ui';\nimport { registerAntdUI, widgetSchemas } from '@xbeeant/form-engine-ui';\nimport {\n Button,\n Input,\n message,\n Popconfirm,\n Radio,\n Space,\n Typography,\n} from 'antd';\nimport { useMemo, useState } from 'react';\nimport { Canvas } from './Canvas';\nimport './Designer.css';\nimport { layoutCatalog, widgetCatalog } from './catalog';\nimport { DesignerProvider, useDesigner } from './DesignerContext';\nimport { Palette } from './Palette';\nimport { PropertyPanel } from './PropertyPanel';\nimport { ResizablePanel } from './ResizablePanel';\nimport type { CatalogItem, DesignerMode, FieldDef } from './types';\n\nconst DEFAULT_SCHEMA: NexusSchema = {\n type: 'object',\n displayType: 'row',\n properties: {},\n};\n\nexport interface DesignerProps {\n schema?: NexusSchema;\n /**\n * widget 名 → 属性描述符映射,决定属性面板「组件属性」分区展示哪些配置项。\n * 默认使用 @xbeeant/form-engine-ui 的 widgetSchemas(antd 组件全覆盖);\n * 传入自定义映射可整体替换,也可在默认基础上按 widget 名覆盖(如\n * `{ ...widgetSchemas, input: myInputSchema }`)。\n */\n propertySchemaMap?: PropertySchemaMap;\n onSchemaChange?: (schema: NexusSchema) => void;\n /**\n * UI 注册函数,向引擎注册 widgets 和 layouts。\n * 默认使用 @xbeeant/form-engine-ui 的 registerAntdUI;接入其它 UI 库时传入自定义注册函数。\n */\n registerUI?: (engine: NexusEngine) => void;\n /** 外部字段列表,传入后左侧 palette 多一个「字段列表」分组 */\n fields?: FieldDef[];\n /** 额外的 widget 目录项,与内置 widgetCatalog 合并(同 widget 名时外部覆盖内置) */\n widgetCatalog?: CatalogItem[];\n /** 额外的 layout 目录项,与内置 layoutCatalog 合并(同 layoutType 时外部覆盖内置) */\n layoutCatalog?: CatalogItem[];\n}\n\nexport function Designer({\n schema,\n propertySchemaMap = widgetSchemas,\n onSchemaChange,\n registerUI = registerAntdUI,\n fields,\n widgetCatalog: extraWidgetCatalog,\n layoutCatalog: extraLayoutCatalog,\n}: DesignerProps) {\n const initialSchema = useMemo<NexusSchema>(\n () => schema ?? DEFAULT_SCHEMA,\n [schema],\n );\n\n // 合并内置 catalog 与外部传入的 catalog:外部同名项覆盖内置\n const mergedWidgetCatalog = useMemo(\n () => mergeCatalog(widgetCatalog, extraWidgetCatalog, 'widget'),\n [extraWidgetCatalog],\n );\n const mergedLayoutCatalog = useMemo(\n () => mergeCatalog(layoutCatalog, extraLayoutCatalog, 'layoutType'),\n [extraLayoutCatalog],\n );\n\n return (\n <DesignerProvider\n initialSchema={initialSchema}\n onSchemaChange={onSchemaChange}\n registerUI={registerUI}\n fields={fields}\n propertySchemaMap={propertySchemaMap}\n widgetCatalog={mergedWidgetCatalog}\n layoutCatalog={mergedLayoutCatalog}\n >\n <DesignerForm />\n </DesignerProvider>\n );\n}\n\n// 合并内置与外部 catalog:外部项按 key 覆盖内置同名项,其余追加到末尾\nfunction mergeCatalog(\n builtIn: CatalogItem[],\n extra: CatalogItem[] | undefined,\n keyField: 'widget' | 'layoutType',\n): CatalogItem[] {\n if (!extra || extra.length === 0) {\n return builtIn;\n }\n const extraKeys = new Set(extra.map((c) => c[keyField]).filter(Boolean));\n const preserved = builtIn.filter((c) => !extraKeys.has(c[keyField]));\n return [...preserved, ...extra];\n}\n\nfunction DesignerForm() {\n const { mode, setMode, schema, setSchema, selectNode } = useDesigner();\n const [schemaText, setSchemaText] = useState('');\n const [schemaActive, setSchemaActive] = useState(false);\n\n // 清空画布:重置为空 schema 并取消选中(必须新建对象,保证触发重渲染)\n const handleClearSchema = () => {\n setSchema(DEFAULT_SCHEMA);\n selectNode(null);\n if (mode === 'schema') {\n setSchemaText(JSON.stringify(DEFAULT_SCHEMA, null, 2));\n }\n };\n\n // 进入 schema 模式时同步当前 schema 到编辑框\n const handleEnterSchema = () => {\n setSchemaText(JSON.stringify(schema, null, 2));\n setSchemaActive(true);\n };\n\n // 离开 schema 模式时尝试解析并写回\n const handleLeaveSchema = () => {\n if (!schemaActive) {\n return;\n }\n try {\n const parsed = JSON.parse(schemaText) as NexusSchema;\n if (parsed && parsed.type === 'object' && parsed.properties) {\n setSchema(parsed);\n } else {\n message.warning('Schema 必须包含 type: \"object\" 和 properties');\n }\n } catch {\n message.error('JSON 格式错误,无法解析');\n }\n setSchemaActive(false);\n };\n\n // Radio.Group 切换\n const handleModeChange = (value: DesignerMode) => {\n if (value === 'schema') {\n handleEnterSchema();\n } else {\n handleLeaveSchema();\n }\n setMode(value);\n };\n\n const handleExport = () => {\n const json = JSON.stringify(schema, null, 2);\n const blob = new Blob([json], { type: 'application/json' });\n const url = URL.createObjectURL(blob);\n const a = document.createElement('a');\n a.href = url;\n a.download = 'schema.json';\n a.click();\n URL.revokeObjectURL(url);\n };\n\n const handleImport = () => {\n const input = document.createElement('input');\n input.type = 'file';\n input.accept = 'application/json';\n input.onchange = () => {\n const file = input.files?.[0];\n if (!file) {\n return;\n }\n const reader = new FileReader();\n reader.onload = () => {\n try {\n const parsed = JSON.parse(reader.result as string) as NexusSchema;\n if (parsed && parsed.type === 'object' && parsed.properties) {\n setSchema(parsed);\n }\n } catch {\n // 忽略非法 JSON\n }\n };\n reader.readAsText(file);\n };\n input.click();\n };\n\n return (\n <div className='flex flex-col h-full bg-white'>\n <div className='flex items-center justify-between px-4 py-2 border-b border-[#f0f0f0] bg-[#fafafa]'>\n <Typography.Text strong>Nexus 表单设计器</Typography.Text>\n <Space>\n <Radio.Group\n value={mode}\n onChange={(e) => handleModeChange(e.target.value as DesignerMode)}\n >\n <Radio.Button value='design'>设计</Radio.Button>\n <Radio.Button value='preview'>预览</Radio.Button>\n <Radio.Button value='schema'>Schema</Radio.Button>\n </Radio.Group>\n <Button onClick={handleImport}>导入</Button>\n <Button onClick={handleExport}>导出</Button>\n <Popconfirm\n title='清空画布'\n description='将移除画布上所有组件,此操作不可撤销'\n okText='清空'\n cancelText='取消'\n okButtonProps={{ danger: true }}\n onConfirm={handleClearSchema}\n >\n <Button danger>清空</Button>\n </Popconfirm>\n </Space>\n </div>\n {mode === 'schema' ? (\n <div className='flex-1 overflow-auto p-4 bg-[#1e1e1e]'>\n <Input.TextArea\n value={schemaText}\n onChange={(e) => setSchemaText(e.target.value)}\n autoSize={{ minRows: 20 }}\n className='font-mono! text-[13px]! leading-[1.6]! bg-[#1e1e1e]! text-[#d4d4d4]! border-[#3e3e42]!'\n />\n </div>\n ) : (\n <div className='flex flex-1 overflow-hidden'>\n <ResizablePanel\n side='left'\n defaultWidth={240}\n minWidth={160}\n maxWidth={420}\n collapsedTitle='组件面板'\n >\n <Palette />\n </ResizablePanel>\n <Canvas />\n <ResizablePanel\n side='right'\n defaultWidth={320}\n minWidth={240}\n maxWidth={560}\n collapsedTitle='属性面板'\n >\n <PropertyPanel />\n </ResizablePanel>\n </div>\n )}\n </div>\n );\n}\n"],"names":["DEFAULT_SCHEMA","Designer","schema","propertySchemaMap","widgetSchemas","onSchemaChange","registerUI","registerAntdUI","fields","extraWidgetCatalog","extraLayoutCatalog","initialSchema","useMemo","mergedWidgetCatalog","mergeCatalog","widgetCatalog","mergedLayoutCatalog","layoutCatalog","jsx","DesignerProvider","DesignerForm","builtIn","extra","keyField","extraKeys","c","mode","setMode","setSchema","selectNode","useDesigner","schemaText","setSchemaText","useState","schemaActive","setSchemaActive","handleClearSchema","handleEnterSchema","handleLeaveSchema","parsed","message","handleModeChange","value","handleExport","json","blob","url","handleImport","input","file","reader","jsxs","Typography","Space","Radio","Button","Popconfirm","Input","ResizablePanel","Palette","Canvas","PropertyPanel"],"mappings":";;;;;;;;;;;AA0BA,MAAMA,IAA8B;AAAA,EAClC,MAAM;AAAA,EACN,aAAa;AAAA,EACb,YAAY,CAAA;AACd;AAyBO,SAASC,GAAS;AAAA,EACvB,QAAAC;AAAA,EACA,mBAAAC,IAAoBC;AAAA,EACpB,gBAAAC;AAAA,EACA,YAAAC,IAAaC;AAAA,EACb,QAAAC;AAAA,EACA,eAAeC;AAAA,EACf,eAAeC;AACjB,GAAkB;AAChB,QAAMC,IAAgBC;AAAA,IACpB,MAAMV,KAAUF;AAAA,IAChB,CAACE,CAAM;AAAA,EAAA,GAIHW,IAAsBD;AAAA,IAC1B,MAAME,EAAaC,GAAeN,GAAoB,QAAQ;AAAA,IAC9D,CAACA,CAAkB;AAAA,EAAA,GAEfO,IAAsBJ;AAAA,IAC1B,MAAME,EAAaG,GAAeP,GAAoB,YAAY;AAAA,IAClE,CAACA,CAAkB;AAAA,EAAA;AAGrB,SACE,gBAAAQ;AAAA,IAACC;AAAA,IAAA;AAAA,MACC,eAAAR;AAAA,MACA,gBAAAN;AAAA,MACA,YAAAC;AAAA,MACA,QAAAE;AAAA,MACA,mBAAAL;AAAA,MACA,eAAeU;AAAA,MACf,eAAeG;AAAA,MAEf,4BAACI,GAAA,CAAA,CAAa;AAAA,IAAA;AAAA,EAAA;AAGpB;AAGA,SAASN,EACPO,GACAC,GACAC,GACe;AACf,MAAI,CAACD,KAASA,EAAM,WAAW;AAC7B,WAAOD;AAET,QAAMG,IAAY,IAAI,IAAIF,EAAM,IAAI,CAACG,MAAMA,EAAEF,CAAQ,CAAC,EAAE,OAAO,OAAO,CAAC;AAEvE,SAAO,CAAC,GADUF,EAAQ,OAAO,CAACI,MAAM,CAACD,EAAU,IAAIC,EAAEF,CAAQ,CAAC,CAAC,GAC7C,GAAGD,CAAK;AAChC;AAEA,SAASF,IAAe;AACtB,QAAM,EAAE,MAAAM,GAAM,SAAAC,GAAS,QAAAzB,GAAQ,WAAA0B,GAAW,YAAAC,EAAA,IAAeC,EAAA,GACnD,CAACC,GAAYC,CAAa,IAAIC,EAAS,EAAE,GACzC,CAACC,GAAcC,CAAe,IAAIF,EAAS,EAAK,GAGhDG,IAAoB,MAAM;AAC9B,IAAAR,EAAU5B,CAAc,GACxB6B,EAAW,IAAI,GACXH,MAAS,YACXM,EAAc,KAAK,UAAUhC,GAAgB,MAAM,CAAC,CAAC;AAAA,EAEzD,GAGMqC,IAAoB,MAAM;AAC9B,IAAAL,EAAc,KAAK,UAAU9B,GAAQ,MAAM,CAAC,CAAC,GAC7CiC,EAAgB,EAAI;AAAA,EACtB,GAGMG,IAAoB,MAAM;AAC9B,QAAKJ,GAGL;AAAA,UAAI;AACF,cAAMK,IAAS,KAAK,MAAMR,CAAU;AACpC,QAAIQ,KAAUA,EAAO,SAAS,YAAYA,EAAO,aAC/CX,EAAUW,CAAM,IAEhBC,EAAQ,QAAQ,yCAAyC;AAAA,MAE7D,QAAQ;AACN,QAAAA,EAAQ,MAAM,gBAAgB;AAAA,MAChC;AACA,MAAAL,EAAgB,EAAK;AAAA;AAAA,EACvB,GAGMM,IAAmB,CAACC,MAAwB;AAChD,IAAIA,MAAU,WACZL,EAAA,IAEAC,EAAA,GAEFX,EAAQe,CAAK;AAAA,EACf,GAEMC,IAAe,MAAM;AACzB,UAAMC,IAAO,KAAK,UAAU1C,GAAQ,MAAM,CAAC,GACrC2C,IAAO,IAAI,KAAK,CAACD,CAAI,GAAG,EAAE,MAAM,oBAAoB,GACpDE,IAAM,IAAI,gBAAgBD,CAAI,GAC9B,IAAI,SAAS,cAAc,GAAG;AACpC,MAAE,OAAOC,GACT,EAAE,WAAW,eACb,EAAE,MAAA,GACF,IAAI,gBAAgBA,CAAG;AAAA,EACzB,GAEMC,IAAe,MAAM;AACzB,UAAMC,IAAQ,SAAS,cAAc,OAAO;AAC5C,IAAAA,EAAM,OAAO,QACbA,EAAM,SAAS,oBACfA,EAAM,WAAW,MAAM;AACrB,YAAMC,IAAOD,EAAM,QAAQ,CAAC;AAC5B,UAAI,CAACC;AACH;AAEF,YAAMC,IAAS,IAAI,WAAA;AACnB,MAAAA,EAAO,SAAS,MAAM;AACpB,YAAI;AACF,gBAAMX,IAAS,KAAK,MAAMW,EAAO,MAAgB;AACjD,UAAIX,KAAUA,EAAO,SAAS,YAAYA,EAAO,cAC/CX,EAAUW,CAAM;AAAA,QAEpB,QAAQ;AAAA,QAER;AAAA,MACF,GACAW,EAAO,WAAWD,CAAI;AAAA,IACxB,GACAD,EAAM,MAAA;AAAA,EACR;AAEA,SACE,gBAAAG,EAAC,OAAA,EAAI,WAAU,iCACb,UAAA;AAAA,IAAA,gBAAAA,EAAC,OAAA,EAAI,WAAU,sFACb,UAAA;AAAA,MAAA,gBAAAjC,EAACkC,EAAW,MAAX,EAAgB,QAAM,IAAC,UAAA,eAAW;AAAA,wBAClCC,GAAA,EACC,UAAA;AAAA,QAAA,gBAAAF;AAAA,UAACG,EAAM;AAAA,UAAN;AAAA,YACC,OAAO5B;AAAA,YACP,UAAU,CAAC,MAAMe,EAAiB,EAAE,OAAO,KAAqB;AAAA,YAEhE,UAAA;AAAA,cAAA,gBAAAvB,EAACoC,EAAM,QAAN,EAAa,OAAM,UAAS,UAAA,MAAE;AAAA,gCAC9BA,EAAM,QAAN,EAAa,OAAM,WAAU,UAAA,MAAE;AAAA,gCAC/BA,EAAM,QAAN,EAAa,OAAM,UAAS,UAAA,SAAA,CAAM;AAAA,YAAA;AAAA,UAAA;AAAA,QAAA;AAAA,QAErC,gBAAApC,EAACqC,GAAA,EAAO,SAASR,GAAc,UAAA,MAAE;AAAA,QACjC,gBAAA7B,EAACqC,GAAA,EAAO,SAASZ,GAAc,UAAA,MAAE;AAAA,QACjC,gBAAAzB;AAAA,UAACsC;AAAA,UAAA;AAAA,YACC,OAAM;AAAA,YACN,aAAY;AAAA,YACZ,QAAO;AAAA,YACP,YAAW;AAAA,YACX,eAAe,EAAE,QAAQ,GAAA;AAAA,YACzB,WAAWpB;AAAA,YAEX,UAAA,gBAAAlB,EAACqC,GAAA,EAAO,QAAM,IAAC,UAAA,KAAA,CAAE;AAAA,UAAA;AAAA,QAAA;AAAA,MACnB,EAAA,CACF;AAAA,IAAA,GACF;AAAA,IACC7B,MAAS,WACR,gBAAAR,EAAC,OAAA,EAAI,WAAU,yCACb,UAAA,gBAAAA;AAAA,MAACuC,EAAM;AAAA,MAAN;AAAA,QACC,OAAO1B;AAAA,QACP,UAAU,CAAC,MAAMC,EAAc,EAAE,OAAO,KAAK;AAAA,QAC7C,UAAU,EAAE,SAAS,GAAA;AAAA,QACrB,WAAU;AAAA,MAAA;AAAA,IAAA,EACZ,CACF,IAEA,gBAAAmB,EAAC,OAAA,EAAI,WAAU,+BACb,UAAA;AAAA,MAAA,gBAAAjC;AAAA,QAACwC;AAAA,QAAA;AAAA,UACC,MAAK;AAAA,UACL,cAAc;AAAA,UACd,UAAU;AAAA,UACV,UAAU;AAAA,UACV,gBAAe;AAAA,UAEf,4BAACC,GAAA,CAAA,CAAQ;AAAA,QAAA;AAAA,MAAA;AAAA,wBAEVC,GAAA,EAAO;AAAA,MACR,gBAAA1C;AAAA,QAACwC;AAAA,QAAA;AAAA,UACC,MAAK;AAAA,UACL,cAAc;AAAA,UACd,UAAU;AAAA,UACV,UAAU;AAAA,UACV,gBAAe;AAAA,UAEf,4BAACG,GAAA,CAAA,CAAc;AAAA,QAAA;AAAA,MAAA;AAAA,IACjB,EAAA,CACF;AAAA,EAAA,GAEJ;AAEJ;"}
1
+ {"version":3,"file":"designer.js","sources":["../../src/designer.tsx"],"sourcesContent":["// ============================================================================\n// @xbeeant/form-engine-designer — 主组件\n// ============================================================================\n\nimport type { NexusEngine, NexusSchema } from '@xbeeant/form-engine';\nimport type { PropertySchemaMap } from '@xbeeant/form-engine-ui';\nimport { registerAntdUI, widgetSchemas } from '@xbeeant/form-engine-ui';\nimport {\n Button,\n Input,\n message,\n Popconfirm,\n Radio,\n Space,\n Typography,\n} from 'antd';\nimport { useEffect, useMemo, useState } from 'react';\nimport { Canvas } from './canvas';\nimport './Designer.css';\nimport { layoutCatalog, widgetCatalog } from './catalog';\nimport { DesignerProvider, useDesigner } from './designer-context';\nimport { Palette } from './palette';\nimport { PropertyPanel } from './property-panel';\nimport { ResizablePanel } from './resizable-panel';\nimport type { CatalogItem, DesignerMode, FieldDef } from './types';\n\nconst DEFAULT_SCHEMA: NexusSchema = {\n type: 'object',\n displayType: 'row',\n properties: {},\n};\n\nexport interface DesignerProps {\n schema?: NexusSchema;\n /**\n * widget 名 → 属性描述符映射,决定属性面板「组件属性」分区展示哪些配置项。\n * 默认使用 @xbeeant/form-engine-ui 的 widgetSchemas(antd 组件全覆盖);\n * 传入自定义映射可整体替换,也可在默认基础上按 widget 名覆盖(如\n * `{ ...widgetSchemas, input: myInputSchema }`)。\n */\n propertySchemaMap?: PropertySchemaMap;\n onSchemaChange?: (schema: NexusSchema) => void;\n /**\n * UI 注册函数,向引擎注册 widgets 和 layouts。\n * 默认使用 @xbeeant/form-engine-ui 的 registerAntdUI;接入其它 UI 库时传入自定义注册函数。\n */\n registerUI?: (engine: NexusEngine) => void;\n /** 外部字段列表,传入后左侧 palette 多一个「字段列表」分组 */\n fields?: FieldDef[];\n /** 额外的 widget 目录项,与内置 widgetCatalog 合并(同 widget 名时外部覆盖内置) */\n widgetCatalog?: CatalogItem[];\n /** 额外的 layout 目录项,与内置 layoutCatalog 合并(同 layoutType 时外部覆盖内置) */\n layoutCatalog?: CatalogItem[];\n}\n\nexport function Designer({\n schema,\n propertySchemaMap = widgetSchemas,\n onSchemaChange,\n registerUI = registerAntdUI,\n fields,\n widgetCatalog: extraWidgetCatalog,\n layoutCatalog: extraLayoutCatalog,\n}: DesignerProps) {\n const initialSchema = useMemo<NexusSchema>(\n () => schema ?? DEFAULT_SCHEMA,\n [schema],\n );\n\n // 合并内置 catalog 与外部传入的 catalog:外部同名项覆盖内置\n const mergedWidgetCatalog = useMemo(\n () => mergeCatalog(widgetCatalog, extraWidgetCatalog, 'widget'),\n [extraWidgetCatalog],\n );\n const mergedLayoutCatalog = useMemo(\n () => mergeCatalog(layoutCatalog, extraLayoutCatalog, 'layoutType'),\n [extraLayoutCatalog],\n );\n\n return (\n <DesignerProvider\n initialSchema={initialSchema}\n onSchemaChange={onSchemaChange}\n registerUI={registerUI}\n fields={fields}\n propertySchemaMap={propertySchemaMap}\n widgetCatalog={mergedWidgetCatalog}\n layoutCatalog={mergedLayoutCatalog}\n >\n <DesignerForm />\n </DesignerProvider>\n );\n}\n\n// 合并内置与外部 catalog:外部项按 key 覆盖内置同名项,其余追加到末尾\nfunction mergeCatalog(\n builtIn: CatalogItem[],\n extra: CatalogItem[] | undefined,\n keyField: 'widget' | 'layoutType',\n): CatalogItem[] {\n if (!extra || extra.length === 0) {\n return builtIn;\n }\n const extraKeys = new Set(extra.map((c) => c[keyField]).filter(Boolean));\n const preserved = builtIn.filter((c) => !extraKeys.has(c[keyField]));\n return [...preserved, ...extra];\n}\n\nfunction DesignerForm() {\n const {\n mode,\n setMode,\n schema,\n setSchema,\n selectNode,\n undo,\n redo,\n canUndo,\n canRedo,\n } = useDesigner();\n const [schemaText, setSchemaText] = useState('');\n const [schemaActive, setSchemaActive] = useState(false);\n\n // 全局快捷键:Cmd/Ctrl+Z 撤销、+Shift+Z 或 Ctrl+Y 重做。\n // 输入框/文本域内不拦截(保留原生文本撤销)\n useEffect(() => {\n const onKeyDown = (e: KeyboardEvent) => {\n const target = e.target as HTMLElement | null;\n if (\n target &&\n (target.tagName === 'INPUT' ||\n target.tagName === 'TEXTAREA' ||\n target.isContentEditable)\n ) {\n return;\n }\n if (!(e.metaKey || e.ctrlKey)) {\n return;\n }\n const key = e.key.toLowerCase();\n if (key === 'z') {\n e.preventDefault();\n if (e.shiftKey) {\n redo();\n } else {\n undo();\n }\n } else if (key === 'y') {\n e.preventDefault();\n redo();\n }\n };\n window.addEventListener('keydown', onKeyDown);\n return () => window.removeEventListener('keydown', onKeyDown);\n }, [undo, redo]);\n\n // 清空画布:重置为空 schema 并取消选中(必须新建对象,保证触发重渲染)\n const handleClearSchema = () => {\n setSchema(DEFAULT_SCHEMA);\n selectNode(null);\n if (mode === 'schema') {\n setSchemaText(JSON.stringify(DEFAULT_SCHEMA, null, 2));\n }\n };\n\n // 进入 schema 模式时同步当前 schema 到编辑框\n const handleEnterSchema = () => {\n setSchemaText(JSON.stringify(schema, null, 2));\n setSchemaActive(true);\n };\n\n // 离开 schema 模式时尝试解析并写回\n const handleLeaveSchema = () => {\n if (!schemaActive) {\n return;\n }\n try {\n const parsed = JSON.parse(schemaText) as NexusSchema;\n if (parsed && parsed.type === 'object' && parsed.properties) {\n setSchema(parsed);\n } else {\n message.warning('Schema 必须包含 type: \"object\" 和 properties');\n }\n } catch {\n message.error('JSON 格式错误,无法解析');\n }\n setSchemaActive(false);\n };\n\n // Radio.Group 切换\n const handleModeChange = (value: DesignerMode) => {\n if (value === 'schema') {\n handleEnterSchema();\n } else {\n handleLeaveSchema();\n }\n setMode(value);\n };\n\n const handleExport = () => {\n const json = JSON.stringify(schema, null, 2);\n const blob = new Blob([json], { type: 'application/json' });\n const url = URL.createObjectURL(blob);\n const a = document.createElement('a');\n a.href = url;\n a.download = 'schema.json';\n a.click();\n URL.revokeObjectURL(url);\n };\n\n const handleImport = () => {\n const input = document.createElement('input');\n input.type = 'file';\n input.accept = 'application/json';\n input.onchange = () => {\n const file = input.files?.[0];\n if (!file) {\n return;\n }\n const reader = new FileReader();\n reader.onload = () => {\n try {\n const parsed = JSON.parse(reader.result as string) as NexusSchema;\n if (parsed && parsed.type === 'object' && parsed.properties) {\n setSchema(parsed);\n }\n } catch {\n // 忽略非法 JSON\n }\n };\n reader.readAsText(file);\n };\n input.click();\n };\n\n return (\n <div className='flex flex-col h-full bg-white'>\n <div className='flex items-center justify-between px-4 py-2 border-b border-[#f0f0f0] bg-[#fafafa]'>\n <Typography.Text strong>Nexus 表单设计器</Typography.Text>\n <Space>\n <Radio.Group\n value={mode}\n onChange={(e) => handleModeChange(e.target.value as DesignerMode)}\n >\n <Radio.Button value='design'>设计</Radio.Button>\n <Radio.Button value='preview'>预览</Radio.Button>\n <Radio.Button value='schema'>Schema</Radio.Button>\n </Radio.Group>\n <Button onClick={handleImport}>导入</Button>\n <Button onClick={handleExport}>导出</Button>\n <Button disabled={!canUndo} onClick={undo}>\n 撤销\n </Button>\n <Button disabled={!canRedo} onClick={redo}>\n 重做\n </Button>\n <Popconfirm\n title='清空画布'\n description='将移除画布上所有组件,可使用 Ctrl/Cmd+Z 撤销'\n okText='清空'\n cancelText='取消'\n okButtonProps={{ danger: true }}\n onConfirm={handleClearSchema}\n >\n <Button danger>清空</Button>\n </Popconfirm>\n </Space>\n </div>\n {mode === 'schema' ? (\n <div className='flex-1 overflow-auto p-4 bg-[#1e1e1e]'>\n <Input.TextArea\n value={schemaText}\n onChange={(e) => setSchemaText(e.target.value)}\n autoSize={{ minRows: 20 }}\n className='font-mono! text-[13px]! leading-[1.6]! bg-[#1e1e1e]! text-[#d4d4d4]! border-[#3e3e42]!'\n />\n </div>\n ) : (\n <div className='flex flex-1 overflow-hidden'>\n <ResizablePanel\n side='left'\n defaultWidth={320}\n minWidth={160}\n maxWidth={420}\n collapsedTitle='组件面板'\n >\n <Palette />\n </ResizablePanel>\n <Canvas />\n <ResizablePanel\n side='right'\n defaultWidth={320}\n minWidth={240}\n maxWidth={800}\n collapsedTitle='属性面板'\n >\n <PropertyPanel />\n </ResizablePanel>\n </div>\n )}\n </div>\n );\n}\n"],"names":["DEFAULT_SCHEMA","Designer","schema","propertySchemaMap","widgetSchemas","onSchemaChange","registerUI","registerAntdUI","fields","extraWidgetCatalog","extraLayoutCatalog","initialSchema","useMemo","mergedWidgetCatalog","mergeCatalog","widgetCatalog","mergedLayoutCatalog","layoutCatalog","jsx","DesignerProvider","DesignerForm","builtIn","extra","keyField","extraKeys","c","mode","setMode","setSchema","selectNode","undo","redo","canUndo","canRedo","useDesigner","schemaText","setSchemaText","useState","schemaActive","setSchemaActive","useEffect","onKeyDown","e","target","key","handleClearSchema","handleEnterSchema","handleLeaveSchema","parsed","message","handleModeChange","value","handleExport","json","blob","url","a","handleImport","input","file","reader","jsxs","Typography","Space","Radio","Button","Popconfirm","Input","ResizablePanel","Palette","Canvas","PropertyPanel"],"mappings":"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"}
@@ -1,97 +1,110 @@
1
- import { jsx as F } from "react/jsx-runtime";
2
- import { createContext as I, useState as m, useCallback as n, useMemo as M, useContext as T } from "react";
3
- import { addChildToSchema as W, removeNodeFromSchema as q, updateNodeWithNesting as z, moveNodeInSchema as A, renameNodeInSchema as B } from "./schemaUtils.js";
4
- const C = I(null);
5
- function K({
6
- initialSchema: c,
7
- propertySchemaMap: i,
8
- onSchemaChange: u,
9
- registerUI: a,
10
- fields: h,
11
- widgetCatalog: N,
12
- layoutCatalog: l,
13
- children: b
1
+ import { jsx as T } from "react/jsx-runtime";
2
+ import { createContext as U, useState as u, useRef as W, useCallback as n, useMemo as _, useContext as q } from "react";
3
+ import { SchemaHistory as z } from "./history.js";
4
+ import { addChildToSchema as A, removeNodeFromSchema as B, updateNodeWithNesting as G, moveNodeInSchema as J, renameNodeInSchema as K } from "./schemaUtils.js";
5
+ const k = U(null);
6
+ function Z({
7
+ initialSchema: i,
8
+ propertySchemaMap: N,
9
+ onSchemaChange: s,
10
+ registerUI: f,
11
+ fields: v,
12
+ widgetCatalog: h,
13
+ layoutCatalog: P,
14
+ children: E
14
15
  }) {
15
- const [o, j] = m(c), [v, d] = m(null), [S, k] = m("design"), t = n(
16
- (e) => {
17
- j(e), u?.(e);
16
+ const [t, m] = u(i), [p, l] = u(null), [x, F] = u("design"), d = W(new z()), [L, a] = u(0), r = n(
17
+ (e, o = "replace", c = null) => {
18
+ d.current.push(t, o, c), a((M) => M + 1), m(e), s?.(e);
18
19
  },
19
- [u]
20
- ), P = n((e) => t(e), [t]), f = n((e) => {
21
- d(e);
22
- }, []), x = n(
23
- (e, s, r) => {
24
- t(W(o, e, s, r));
20
+ [t, s]
21
+ ), D = n(() => {
22
+ const e = d.current.undo(t);
23
+ e !== null && (a((o) => o + 1), m(e), s?.(e));
24
+ }, [t, s]), R = n(() => {
25
+ const e = d.current.redo();
26
+ e !== null && (a((o) => o + 1), m(e), s?.(e));
27
+ }, [s]), S = n((e) => r(e), [r]), w = n((e) => {
28
+ l(e);
29
+ }, []), j = n(
30
+ (e, o, c) => {
31
+ r(A(t, e, o, c), "edit");
25
32
  },
26
- [o, t]
27
- ), D = n(
33
+ [t, r]
34
+ ), y = n(
28
35
  (e) => {
29
- t(q(o, e)), d(null);
36
+ r(B(t, e), "edit"), l(null);
30
37
  },
31
- [o, t]
32
- ), p = n(
33
- (e, s) => {
34
- t(z(o, e, s));
38
+ [t, r]
39
+ ), H = n(
40
+ (e, o) => {
41
+ r(G(t, e, o), "edit", e.join("."));
35
42
  },
36
- [o, t]
37
- ), g = n(
38
- (e, s) => {
39
- t(A(o, e, s));
43
+ [t, r]
44
+ ), V = n(
45
+ (e, o) => {
46
+ r(J(t, e, o), "edit");
40
47
  },
41
- [o, t]
42
- ), w = n(
43
- (e, s) => {
44
- const r = B(o, e, s);
45
- t(r.schema), d(r.newPath);
48
+ [t, r]
49
+ ), b = n(
50
+ (e, o) => {
51
+ const c = K(t, e, o);
52
+ r(c.schema, "edit"), l(c.newPath);
46
53
  },
47
- [o, t]
48
- ), E = M(
54
+ [t, r]
55
+ ), I = _(
49
56
  () => ({
50
- schema: o,
51
- selectedPath: v,
52
- mode: S,
53
- registerUI: a,
54
- fields: h,
55
- widgetCatalog: N,
56
- layoutCatalog: l,
57
- propertySchemaMap: i,
58
- setSchema: P,
59
- selectNode: f,
60
- setMode: k,
61
- addNode: x,
62
- removeNode: D,
63
- updateNode: p,
64
- moveNode: g,
65
- renameNode: w
57
+ schema: t,
58
+ selectedPath: p,
59
+ mode: x,
60
+ registerUI: f,
61
+ fields: v,
62
+ widgetCatalog: h,
63
+ layoutCatalog: P,
64
+ propertySchemaMap: N,
65
+ setSchema: S,
66
+ selectNode: w,
67
+ setMode: F,
68
+ addNode: j,
69
+ removeNode: y,
70
+ updateNode: H,
71
+ moveNode: V,
72
+ renameNode: b,
73
+ undo: D,
74
+ redo: R,
75
+ canUndo: d.current.canUndo,
76
+ canRedo: d.current.canRedo
66
77
  }),
67
78
  [
68
- o,
69
- i,
79
+ t,
80
+ N,
81
+ p,
82
+ x,
83
+ f,
70
84
  v,
71
- S,
72
- a,
73
85
  h,
74
- N,
75
- l,
76
86
  P,
77
- f,
78
- x,
87
+ S,
88
+ j,
89
+ y,
90
+ H,
91
+ V,
92
+ b,
79
93
  D,
80
- p,
81
- g,
94
+ R,
82
95
  w
83
96
  ]
84
97
  );
85
- return /* @__PURE__ */ F(C.Provider, { value: E, children: b });
98
+ return /* @__PURE__ */ T(k.Provider, { value: I, children: E });
86
99
  }
87
- function L() {
88
- const c = T(C);
89
- if (!c)
100
+ function $() {
101
+ const i = q(k);
102
+ if (!i)
90
103
  throw new Error("useDesigner 必须在 <DesignerProvider> 内使用");
91
- return c;
104
+ return i;
92
105
  }
93
106
  export {
94
- K as DesignerProvider,
95
- L as useDesigner
107
+ Z as DesignerProvider,
108
+ $ as useDesigner
96
109
  };
97
110
  //# sourceMappingURL=DesignerContext.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"DesignerContext.js","sources":["../../src/DesignerContext.tsx"],"sourcesContent":["// ============================================================================\n// @xbeeant/form-engine-designer — 设计器状态上下文\n// ============================================================================\n\nimport type {\n NexusEngine,\n NexusSchema,\n SchemaNode,\n} from '@xbeeant/form-engine';\nimport type { PropertySchemaMap } from '@xbeeant/form-engine-ui';\nimport type { ReactNode } from 'react';\nimport {\n createContext,\n useCallback,\n useContext,\n useMemo,\n useState,\n} from 'react';\nimport {\n addChildToSchema,\n moveNodeInSchema,\n removeNodeFromSchema,\n renameNodeInSchema,\n updateNodeWithNesting,\n} from './schemaUtils';\nimport type { CatalogItem, DesignerMode, FieldDef } from './types';\n\n/** 设计器内部状态 */\nexport interface DesignerState {\n schema: NexusSchema;\n selectedPath: string[] | null;\n mode: DesignerMode;\n}\n\nexport interface DesignerContextValue {\n schema: NexusSchema;\n propertySchemaMap: PropertySchemaMap;\n selectedPath: string[] | null;\n mode: DesignerMode;\n /** UI 注册函数,向引擎注册 widgets/layouts */\n registerUI?: (engine: NexusEngine) => void;\n /** 外部字段列表 */\n fields?: FieldDef[];\n /** 合并后的 widget 目录(内置 + 外部传入) */\n widgetCatalog: CatalogItem[];\n /** 合并后的 layout 目录(内置 + 外部传入) */\n layoutCatalog: CatalogItem[];\n setSchema: (schema: NexusSchema) => void;\n selectNode: (path: string[] | null) => void;\n setMode: (mode: DesignerMode) => void;\n addNode: (parentPath: string[], key: string, node: SchemaNode) => void;\n removeNode: (path: string[]) => void;\n updateNode: (path: string[], patch: Record<string, unknown>) => void;\n moveNode: (fromPath: string[], toParentPath: string[]) => void;\n /** 重命名节点 key(schema 结构级操作,保留节点在父级中的位置) */\n renameNode: (path: string[], newKey: string) => void;\n}\n\ninterface DesignerProviderProps {\n initialSchema: NexusSchema;\n propertySchemaMap: PropertySchemaMap;\n onSchemaChange?: (schema: NexusSchema) => void;\n registerUI?: (engine: NexusEngine) => void;\n fields?: FieldDef[];\n widgetCatalog: CatalogItem[];\n layoutCatalog: CatalogItem[];\n children: ReactNode;\n}\n\nconst DesignerContext = createContext<DesignerContextValue | null>(null);\n\nexport function DesignerProvider({\n initialSchema,\n propertySchemaMap,\n onSchemaChange,\n registerUI,\n fields,\n widgetCatalog,\n layoutCatalog,\n children,\n}: DesignerProviderProps) {\n const [schema, setSchemaState] = useState<NexusSchema>(initialSchema);\n const [selectedPath, setSelectedPath] = useState<string[] | null>(null);\n const [mode, setMode] = useState<DesignerMode>('design');\n\n // 写入 schema 并同步通知外部\n const emit = useCallback(\n (next: NexusSchema) => {\n setSchemaState(next);\n onSchemaChange?.(next);\n },\n [onSchemaChange],\n );\n\n const setSchema = useCallback((next: NexusSchema) => emit(next), [emit]);\n\n const selectNode = useCallback((path: string[] | null) => {\n setSelectedPath(path);\n }, []);\n\n // setMode 直接复用 useState 的 setter(稳定引用,无需额外包裹)\n\n const addNode = useCallback(\n (parentPath: string[], key: string, node: SchemaNode) => {\n emit(addChildToSchema(schema, parentPath, key, node));\n },\n [schema, emit],\n );\n\n const removeNode = useCallback(\n (path: string[]) => {\n emit(removeNodeFromSchema(schema, path));\n setSelectedPath(null);\n },\n [schema, emit],\n );\n\n const updateNode = useCallback(\n (path: string[], patch: Record<string, unknown>) => {\n emit(updateNodeWithNesting(schema, path, patch));\n },\n [schema, emit],\n );\n\n const moveNode = useCallback(\n (fromPath: string[], toParentPath: string[]) => {\n emit(moveNodeInSchema(schema, fromPath, toParentPath));\n },\n [schema, emit],\n );\n\n const renameNode = useCallback(\n (path: string[], newKey: string) => {\n const result = renameNodeInSchema(schema, path, newKey);\n emit(result.schema);\n setSelectedPath(result.newPath);\n },\n [schema, emit],\n );\n\n const value = useMemo<DesignerContextValue>(\n () => ({\n schema,\n selectedPath,\n mode,\n registerUI,\n fields,\n widgetCatalog,\n layoutCatalog,\n propertySchemaMap,\n setSchema,\n selectNode,\n setMode,\n addNode,\n removeNode,\n updateNode,\n moveNode,\n renameNode,\n }),\n [\n schema,\n propertySchemaMap,\n selectedPath,\n mode,\n registerUI,\n fields,\n widgetCatalog,\n layoutCatalog,\n setSchema,\n selectNode,\n addNode,\n removeNode,\n updateNode,\n moveNode,\n renameNode,\n ],\n );\n\n return (\n <DesignerContext.Provider value={value}>\n {children}\n </DesignerContext.Provider>\n );\n}\n\nexport function useDesigner(): DesignerContextValue {\n const ctx = useContext(DesignerContext);\n if (!ctx) {\n throw new Error('useDesigner 必须在 <DesignerProvider> 内使用');\n }\n return ctx;\n}\n"],"names":["DesignerContext","createContext","DesignerProvider","initialSchema","propertySchemaMap","onSchemaChange","registerUI","fields","widgetCatalog","layoutCatalog","children","schema","setSchemaState","useState","selectedPath","setSelectedPath","mode","setMode","emit","useCallback","next","setSchema","selectNode","path","addNode","parentPath","key","node","addChildToSchema","removeNode","removeNodeFromSchema","updateNode","patch","updateNodeWithNesting","moveNode","fromPath","toParentPath","moveNodeInSchema","renameNode","newKey","result","renameNodeInSchema","value","useMemo","jsx","useDesigner","ctx","useContext"],"mappings":"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"}
1
+ {"version":3,"file":"DesignerContext.js","sources":["../../src/DesignerContext.tsx"],"sourcesContent":["// ============================================================================\n// @xbeeant/form-engine-designer — 设计器状态上下文\n// ============================================================================\n\nimport type {\n NexusEngine,\n NexusSchema,\n SchemaNode,\n} from '@xbeeant/form-engine';\nimport type { PropertySchemaMap } from '@xbeeant/form-engine-ui';\nimport type { ReactNode } from 'react';\nimport {\n createContext,\n useCallback,\n useContext,\n useMemo,\n useRef,\n useState,\n} from 'react';\nimport { SchemaHistory } from './history';\nimport {\n addChildToSchema,\n moveNodeInSchema,\n removeNodeFromSchema,\n renameNodeInSchema,\n updateNodeWithNesting,\n} from './schemaUtils';\nimport type { CatalogItem, DesignerMode, FieldDef } from './types';\n\n/** 设计器内部状态 */\nexport interface DesignerState {\n schema: NexusSchema;\n selectedPath: string[] | null;\n mode: DesignerMode;\n}\n\nexport interface DesignerContextValue {\n schema: NexusSchema;\n propertySchemaMap: PropertySchemaMap;\n selectedPath: string[] | null;\n mode: DesignerMode;\n /** UI 注册函数,向引擎注册 widgets/layouts */\n registerUI?: (engine: NexusEngine) => void;\n /** 外部字段列表 */\n fields?: FieldDef[];\n /** 合并后的 widget 目录(内置 + 外部传入) */\n widgetCatalog: CatalogItem[];\n /** 合并后的 layout 目录(内置 + 外部传入) */\n layoutCatalog: CatalogItem[];\n setSchema: (schema: NexusSchema) => void;\n selectNode: (path: string[] | null) => void;\n setMode: (mode: DesignerMode) => void;\n addNode: (parentPath: string[], key: string, node: SchemaNode) => void;\n removeNode: (path: string[]) => void;\n updateNode: (path: string[], patch: Record<string, unknown>) => void;\n moveNode: (fromPath: string[], toParentPath: string[]) => void;\n /** 重命名节点 key(schema 结构级操作,保留节点在父级中的位置) */\n renameNode: (path: string[], newKey: string) => void;\n /** 撤销:恢复最近一次结构/属性变更 */\n undo: () => void;\n /** 重做:恢复最近一次撤销 */\n redo: () => void;\n canUndo: boolean;\n canRedo: boolean;\n}\n\ninterface DesignerProviderProps {\n initialSchema: NexusSchema;\n propertySchemaMap: PropertySchemaMap;\n onSchemaChange?: (schema: NexusSchema) => void;\n registerUI?: (engine: NexusEngine) => void;\n fields?: FieldDef[];\n widgetCatalog: CatalogItem[];\n layoutCatalog: CatalogItem[];\n children: ReactNode;\n}\n\nconst DesignerContext = createContext<DesignerContextValue | null>(null);\n\nexport function DesignerProvider({\n initialSchema,\n propertySchemaMap,\n onSchemaChange,\n registerUI,\n fields,\n widgetCatalog,\n layoutCatalog,\n children,\n}: DesignerProviderProps) {\n const [schema, setSchemaState] = useState<NexusSchema>(initialSchema);\n const [selectedPath, setSelectedPath] = useState<string[] | null>(null);\n const [mode, setMode] = useState<DesignerMode>('design');\n const historyRef = useRef(new SchemaHistory());\n // 历史栈版本:驱动 canUndo/canRedo 的消费方重渲染\n const [_historyVersion, setHistoryVersion] = useState(0);\n\n // 写入 schema 并同步通知外部;历史记录由 SchemaHistory 统一管理\n const emit = useCallback(\n (\n next: NexusSchema,\n kind: 'edit' | 'replace' = 'replace',\n path: string | null = null,\n ) => {\n historyRef.current.push(schema, kind, path);\n setHistoryVersion((v) => v + 1);\n setSchemaState(next);\n onSchemaChange?.(next);\n },\n [schema, onSchemaChange],\n );\n\n const undo = useCallback(() => {\n const restored = historyRef.current.undo(schema);\n if (restored === null) {\n return;\n }\n setHistoryVersion((v) => v + 1);\n setSchemaState(restored);\n onSchemaChange?.(restored);\n }, [schema, onSchemaChange]);\n\n const redo = useCallback(() => {\n const restored = historyRef.current.redo();\n if (restored === null) {\n return;\n }\n setHistoryVersion((v) => v + 1);\n setSchemaState(restored);\n onSchemaChange?.(restored);\n }, [onSchemaChange]);\n\n const setSchema = useCallback((next: NexusSchema) => emit(next), [emit]);\n\n const selectNode = useCallback((path: string[] | null) => {\n setSelectedPath(path);\n }, []);\n\n // setMode 直接复用 useState 的 setter(稳定引用,无需额外包裹)\n\n const addNode = useCallback(\n (parentPath: string[], key: string, node: SchemaNode) => {\n emit(addChildToSchema(schema, parentPath, key, node), 'edit');\n },\n [schema, emit],\n );\n\n const removeNode = useCallback(\n (path: string[]) => {\n emit(removeNodeFromSchema(schema, path), 'edit');\n setSelectedPath(null);\n },\n [schema, emit],\n );\n\n const updateNode = useCallback(\n (path: string[], patch: Record<string, unknown>) => {\n // 同路径的连续属性编辑由 SchemaHistory 合并(COALESCE_MS 窗口)\n emit(updateNodeWithNesting(schema, path, patch), 'edit', path.join('.'));\n },\n [schema, emit],\n );\n\n const moveNode = useCallback(\n (fromPath: string[], toParentPath: string[]) => {\n emit(moveNodeInSchema(schema, fromPath, toParentPath), 'edit');\n },\n [schema, emit],\n );\n\n const renameNode = useCallback(\n (path: string[], newKey: string) => {\n const result = renameNodeInSchema(schema, path, newKey);\n emit(result.schema, 'edit');\n setSelectedPath(result.newPath);\n },\n [schema, emit],\n );\n\n const value = useMemo<DesignerContextValue>(\n () => ({\n schema,\n selectedPath,\n mode,\n registerUI,\n fields,\n widgetCatalog,\n layoutCatalog,\n propertySchemaMap,\n setSchema,\n selectNode,\n setMode,\n addNode,\n removeNode,\n updateNode,\n moveNode,\n renameNode,\n undo,\n redo,\n canUndo: historyRef.current.canUndo,\n canRedo: historyRef.current.canRedo,\n }),\n [\n schema,\n propertySchemaMap,\n selectedPath,\n mode,\n registerUI,\n fields,\n widgetCatalog,\n layoutCatalog,\n setSchema,\n addNode,\n removeNode,\n updateNode,\n moveNode,\n renameNode,\n undo,\n redo,\n selectNode,\n ],\n );\n\n return (\n <DesignerContext.Provider value={value}>\n {children}\n </DesignerContext.Provider>\n );\n}\n\nexport function useDesigner(): DesignerContextValue {\n const ctx = useContext(DesignerContext);\n if (!ctx) {\n throw new Error('useDesigner 必须在 <DesignerProvider> 内使用');\n }\n return ctx;\n}\n"],"names":["DesignerContext","createContext","DesignerProvider","initialSchema","propertySchemaMap","onSchemaChange","registerUI","fields","widgetCatalog","layoutCatalog","children","schema","setSchemaState","useState","selectedPath","setSelectedPath","mode","setMode","historyRef","useRef","SchemaHistory","_historyVersion","setHistoryVersion","emit","useCallback","next","kind","path","v","undo","restored","redo","setSchema","selectNode","addNode","parentPath","key","node","addChildToSchema","removeNode","removeNodeFromSchema","updateNode","patch","updateNodeWithNesting","moveNode","fromPath","toParentPath","moveNodeInSchema","renameNode","newKey","result","renameNodeInSchema","value","useMemo","jsx","useDesigner","ctx","useContext"],"mappings":"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"}
@@ -1,8 +1,8 @@
1
1
  import { jsx as t, jsxs as o } from "react/jsx-runtime";
2
2
  import { Input as j, Collapse as A } from "antd";
3
3
  import { useState as S, useCallback as _, useMemo as g } from "react";
4
- import { useDesigner as L } from "./DesignerContext.js";
5
- import { getNodeAtProperties as $, getPropertiesOf as E, generateKey as v } from "./schemaUtils.js";
4
+ import { useDesigner as L } from "./designer-context.js";
5
+ import { getNodeAtProperties as $, getPropertiesOf as E, generateKey as v } from "./schema-utils.js";
6
6
  const h = {
7
7
  tabPane: "tabs",
8
8
  collapsePanel: "collapse",
@@ -145,4 +145,4 @@ function G() {
145
145
  export {
146
146
  G as Palette
147
147
  };
148
- //# sourceMappingURL=Palette.js.map
148
+ //# sourceMappingURL=palette.js.map