@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
@@ -0,0 +1,78 @@
1
+ import { jsxs as c, jsx as s } from "react/jsx-runtime";
2
+ import { Select as u, Input as f } from "antd";
3
+ import { useState as g } from "react";
4
+ function y(e) {
5
+ return e === !1 || e === "false" ? "false" : Array.isArray(e) ? "array" : typeof e == "string" && e.length > 0 ? "string" : "none";
6
+ }
7
+ const p = [
8
+ { value: "none", label: "无(使用字段路径)" },
9
+ { value: "string", label: "字符串路径" },
10
+ { value: "array", label: "字符串数组(多路径拆分)" },
11
+ { value: "false", label: "不绑定(不提交)" }
12
+ ];
13
+ function m({ value: e, onChange: t }) {
14
+ const n = y(e), [l, i] = g(
15
+ Array.isArray(e) ? e.join(`
16
+ `) : typeof e == "string" ? e : ""
17
+ ), d = (r) => {
18
+ r === "none" ? (t(void 0), i("")) : r === "string" ? (t(""), i("")) : r === "array" ? (t([]), i("")) : r === "false" && (t(!1), i(""));
19
+ }, a = () => {
20
+ if (n === "string")
21
+ t(l || void 0);
22
+ else if (n === "array") {
23
+ const r = l.split(`
24
+ `).map((o) => o.trim()).filter((o) => o.length > 0);
25
+ t(r.length > 0 ? r : void 0);
26
+ }
27
+ };
28
+ return /* @__PURE__ */ c(
29
+ "div",
30
+ {
31
+ style: {
32
+ display: "flex",
33
+ flexDirection: "column",
34
+ gap: 6,
35
+ width: "100%"
36
+ },
37
+ children: [
38
+ /* @__PURE__ */ s(
39
+ u,
40
+ {
41
+ value: n,
42
+ options: p,
43
+ onChange: d,
44
+ style: { width: "100%" }
45
+ }
46
+ ),
47
+ n === "string" && /* @__PURE__ */ s(
48
+ f,
49
+ {
50
+ placeholder: "如: user.name",
51
+ value: l,
52
+ onChange: (r) => i(r.target.value),
53
+ onBlur: a,
54
+ onPressEnter: a
55
+ }
56
+ ),
57
+ n === "array" && /* @__PURE__ */ s(
58
+ f.TextArea,
59
+ {
60
+ rows: 3,
61
+ placeholder: `如: a.b
62
+ c.d`,
63
+ value: l,
64
+ onChange: (r) => i(r.target.value),
65
+ onBlur: a
66
+ }
67
+ ),
68
+ /* @__PURE__ */ s("div", { style: { fontSize: 11, color: "#999" }, children: "提示:bind 将字段值映射到不同数据路径。string[] 表示字段值数组按顺序拆分到多个路径;false 表示字段不参与提交。" })
69
+ ]
70
+ }
71
+ );
72
+ }
73
+ const v = m;
74
+ export {
75
+ m as BindEditor,
76
+ v as bindEditorWidget
77
+ };
78
+ //# sourceMappingURL=bind-editor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bind-editor.js","sources":["../../../src/widgets/bind-editor.tsx"],"sourcesContent":["// ============================================================================\n// BindEditor — 编辑 bind 属性(路径映射)\n// 支持四种模式:无/字符串/数组/false,不同模式显示不同的子控件\n// ============================================================================\n\nimport type { WidgetProps } from '@xbeeant/form-engine-ui';\nimport { Input, Select } from 'antd';\nimport { useState } from 'react';\n\nfunction getBindMode(value: unknown): string {\n if (value === false || value === 'false') {\n return 'false';\n }\n if (Array.isArray(value)) {\n return 'array';\n }\n if (typeof value === 'string' && value.length > 0) {\n return 'string';\n }\n return 'none';\n}\n\nconst BIND_MODE_OPTIONS = [\n { value: 'none', label: '无(使用字段路径)' },\n { value: 'string', label: '字符串路径' },\n { value: 'array', label: '字符串数组(多路径拆分)' },\n { value: 'false', label: '不绑定(不提交)' },\n];\n\nexport function BindEditor({ value, onChange }: WidgetProps) {\n const mode = getBindMode(value);\n // 本地状态缓存文本值,防止每次按键都触发 onChange\n const [textValue, setTextValue] = useState<string>(\n Array.isArray(value)\n ? (value as string[]).join('\\n')\n : typeof value === 'string'\n ? value\n : '',\n );\n\n const handleModeChange = (newMode: string) => {\n if (newMode === 'none') {\n onChange(undefined);\n setTextValue('');\n } else if (newMode === 'string') {\n onChange('');\n setTextValue('');\n } else if (newMode === 'array') {\n onChange([]);\n setTextValue('');\n } else if (newMode === 'false') {\n onChange(false);\n setTextValue('');\n }\n };\n\n const handleTextCommit = () => {\n if (mode === 'string') {\n onChange(textValue || undefined);\n } else if (mode === 'array') {\n const lines = textValue\n .split('\\n')\n .map((s) => s.trim())\n .filter((s) => s.length > 0);\n onChange(lines.length > 0 ? lines : undefined);\n }\n };\n\n return (\n <div\n style={{\n display: 'flex',\n flexDirection: 'column',\n gap: 6,\n width: '100%',\n }}\n >\n <Select\n value={mode}\n options={BIND_MODE_OPTIONS}\n onChange={handleModeChange}\n style={{ width: '100%' }}\n />\n {mode === 'string' && (\n <Input\n placeholder='如: user.name'\n value={textValue}\n onChange={(e) => setTextValue(e.target.value)}\n onBlur={handleTextCommit}\n onPressEnter={handleTextCommit}\n />\n )}\n {mode === 'array' && (\n <Input.TextArea\n rows={3}\n placeholder={'如: a.b\\nc.d'}\n value={textValue}\n onChange={(e) => setTextValue(e.target.value)}\n onBlur={handleTextCommit}\n />\n )}\n <div style={{ fontSize: 11, color: '#999' }}>\n 提示:bind 将字段值映射到不同数据路径。string[]\n 表示字段值数组按顺序拆分到多个路径;false 表示字段不参与提交。\n </div>\n </div>\n );\n}\n\nexport const bindEditorWidget = BindEditor;\n"],"names":["getBindMode","value","BIND_MODE_OPTIONS","BindEditor","onChange","mode","textValue","setTextValue","useState","handleModeChange","newMode","handleTextCommit","lines","s","jsxs","jsx","Select","Input","e","bindEditorWidget"],"mappings":";;;AASA,SAASA,EAAYC,GAAwB;AAC3C,SAAIA,MAAU,MAASA,MAAU,UACxB,UAEL,MAAM,QAAQA,CAAK,IACd,UAEL,OAAOA,KAAU,YAAYA,EAAM,SAAS,IACvC,WAEF;AACT;AAEA,MAAMC,IAAoB;AAAA,EACxB,EAAE,OAAO,QAAQ,OAAO,YAAA;AAAA,EACxB,EAAE,OAAO,UAAU,OAAO,QAAA;AAAA,EAC1B,EAAE,OAAO,SAAS,OAAO,eAAA;AAAA,EACzB,EAAE,OAAO,SAAS,OAAO,WAAA;AAC3B;AAEO,SAASC,EAAW,EAAE,OAAAF,GAAO,UAAAG,KAAyB;AAC3D,QAAMC,IAAOL,EAAYC,CAAK,GAExB,CAACK,GAAWC,CAAY,IAAIC;AAAA,IAChC,MAAM,QAAQP,CAAK,IACdA,EAAmB,KAAK;AAAA,CAAI,IAC7B,OAAOA,KAAU,WACfA,IACA;AAAA,EAAA,GAGFQ,IAAmB,CAACC,MAAoB;AAC5C,IAAIA,MAAY,UACdN,EAAS,MAAS,GAClBG,EAAa,EAAE,KACNG,MAAY,YACrBN,EAAS,EAAE,GACXG,EAAa,EAAE,KACNG,MAAY,WACrBN,EAAS,CAAA,CAAE,GACXG,EAAa,EAAE,KACNG,MAAY,YACrBN,EAAS,EAAK,GACdG,EAAa,EAAE;AAAA,EAEnB,GAEMI,IAAmB,MAAM;AAC7B,QAAIN,MAAS;AACX,MAAAD,EAASE,KAAa,MAAS;AAAA,aACtBD,MAAS,SAAS;AAC3B,YAAMO,IAAQN,EACX,MAAM;AAAA,CAAI,EACV,IAAI,CAACO,MAAMA,EAAE,KAAA,CAAM,EACnB,OAAO,CAACA,MAAMA,EAAE,SAAS,CAAC;AAC7B,MAAAT,EAASQ,EAAM,SAAS,IAAIA,IAAQ,MAAS;AAAA,IAC/C;AAAA,EACF;AAEA,SACE,gBAAAE;AAAA,IAAC;AAAA,IAAA;AAAA,MACC,OAAO;AAAA,QACL,SAAS;AAAA,QACT,eAAe;AAAA,QACf,KAAK;AAAA,QACL,OAAO;AAAA,MAAA;AAAA,MAGT,UAAA;AAAA,QAAA,gBAAAC;AAAA,UAACC;AAAA,UAAA;AAAA,YACC,OAAOX;AAAA,YACP,SAASH;AAAA,YACT,UAAUO;AAAA,YACV,OAAO,EAAE,OAAO,OAAA;AAAA,UAAO;AAAA,QAAA;AAAA,QAExBJ,MAAS,YACR,gBAAAU;AAAA,UAACE;AAAA,UAAA;AAAA,YACC,aAAY;AAAA,YACZ,OAAOX;AAAA,YACP,UAAU,CAACY,MAAMX,EAAaW,EAAE,OAAO,KAAK;AAAA,YAC5C,QAAQP;AAAA,YACR,cAAcA;AAAA,UAAA;AAAA,QAAA;AAAA,QAGjBN,MAAS,WACR,gBAAAU;AAAA,UAACE,EAAM;AAAA,UAAN;AAAA,YACC,MAAM;AAAA,YACN,aAAa;AAAA;AAAA,YACb,OAAOX;AAAA,YACP,UAAU,CAACY,MAAMX,EAAaW,EAAE,OAAO,KAAK;AAAA,YAC5C,QAAQP;AAAA,UAAA;AAAA,QAAA;AAAA,QAGZ,gBAAAI,EAAC,SAAI,OAAO,EAAE,UAAU,IAAI,OAAO,OAAA,GAAU,UAAA,oEAAA,CAG7C;AAAA,MAAA;AAAA,IAAA;AAAA,EAAA;AAGN;AAEO,MAAMI,IAAmBhB;"}
@@ -0,0 +1,76 @@
1
+ import { jsxs as u, Fragment as J, jsx as e } from "react/jsx-runtime";
2
+ import { Input as N, Space as O, Button as p, Typography as z } from "antd";
3
+ import { useState as y, useMemo as C } from "react";
4
+ function E({
5
+ value: r,
6
+ onChange: l,
7
+ title: T,
8
+ description: a,
9
+ placeholder: o,
10
+ ...g
11
+ }) {
12
+ const S = g?.lines ?? 10, [i, n] = y(null), [c, d] = y(void 0), f = C(() => {
13
+ if (c !== void 0)
14
+ return c;
15
+ if (r == null)
16
+ return "";
17
+ try {
18
+ return JSON.stringify(r, null, 2);
19
+ } catch {
20
+ return String(r);
21
+ }
22
+ }, [c, r]), h = (t) => {
23
+ d(t);
24
+ const m = t.trim();
25
+ if (!m) {
26
+ n(null), l(void 0);
27
+ return;
28
+ }
29
+ try {
30
+ const s = JSON.parse(m);
31
+ n(null), l(s);
32
+ } catch (s) {
33
+ n(s instanceof Error ? s.message : "JSON 解析失败");
34
+ }
35
+ }, x = () => {
36
+ try {
37
+ const t = JSON.stringify(JSON.parse(f), null, 2);
38
+ d(t), n(null);
39
+ } catch {
40
+ }
41
+ };
42
+ return /* @__PURE__ */ u(J, { children: [
43
+ /* @__PURE__ */ e(
44
+ N.TextArea,
45
+ {
46
+ value: f,
47
+ rows: S,
48
+ onChange: (t) => h(t.target.value),
49
+ placeholder: o ? `示例:
50
+ ${typeof o == "string" ? o : JSON.stringify(o, null, 2)}` : "{}",
51
+ style: { fontFamily: "monospace", fontSize: 12 }
52
+ }
53
+ ),
54
+ /* @__PURE__ */ u(O.Compact, { style: { marginTop: 6, width: "100%" }, children: [
55
+ /* @__PURE__ */ e(p, { size: "small", onClick: x, disabled: !!i, children: "格式化" }),
56
+ /* @__PURE__ */ e(
57
+ p,
58
+ {
59
+ size: "small",
60
+ onClick: () => {
61
+ d(""), n(null), l(void 0);
62
+ },
63
+ children: "清空"
64
+ }
65
+ )
66
+ ] }),
67
+ i && /* @__PURE__ */ e(z.Text, { type: "danger", style: { fontSize: 11 }, children: i }),
68
+ a && !i && /* @__PURE__ */ e("span", { style: { fontSize: 11, color: "#999" }, children: a })
69
+ ] });
70
+ }
71
+ const P = E;
72
+ export {
73
+ E as CodeEditor,
74
+ P as codeEditorWidget
75
+ };
76
+ //# sourceMappingURL=code-editor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"code-editor.js","sources":["../../../src/widgets/code-editor.tsx"],"sourcesContent":["// ============================================================================\n// CodeEditor — 属性面板专用 JSON 编辑器\n// 供 remoteData 等对象配置使用:支持语法校验、格式化与占位符示例\n// 值格式:object | array(非法 JSON 不写回,光标处自动提示)\n// ============================================================================\n\nimport type { WidgetProps } from '@xbeeant/form-engine-ui';\nimport { Button, Input, Space, Typography } from 'antd';\nimport { useMemo, useState } from 'react';\n\nexport function CodeEditor({\n value,\n onChange,\n title,\n description,\n placeholder,\n ...rest\n}: WidgetProps) {\n const fieldProps = rest as Record<string, unknown>;\n const lines = (fieldProps?.lines as number) ?? 10;\n\n const [error, setError] = useState<string | null>(null);\n\n // 编辑态文案:初始为 JSON 字符串;解析失败时保留原文(不打断输入)\n const [draft, setDraft] = useState<string | undefined>(undefined);\n\n const text = useMemo(() => {\n if (draft !== undefined) {\n return draft;\n }\n if (value === undefined || value === null) {\n return '';\n }\n try {\n return JSON.stringify(value, null, 2);\n } catch {\n return String(value);\n }\n }, [draft, value]);\n\n const handleChange = (raw: string) => {\n setDraft(raw);\n const trimmed = raw.trim();\n if (!trimmed) {\n setError(null);\n onChange(undefined);\n return;\n }\n try {\n const parsed = JSON.parse(trimmed);\n setError(null);\n onChange(parsed);\n } catch (e) {\n setError(e instanceof Error ? e.message : 'JSON 解析失败');\n }\n };\n\n const handleFormat = () => {\n try {\n const formatted = JSON.stringify(JSON.parse(text), null, 2);\n setDraft(formatted);\n setError(null);\n } catch {\n // 语法非法时静默,保留原文\n }\n };\n\n return (\n <>\n <Input.TextArea\n value={text}\n rows={lines}\n onChange={(e) => handleChange(e.target.value)}\n placeholder={\n placeholder\n ? `示例:\\n${typeof placeholder === 'string' ? placeholder : JSON.stringify(placeholder, null, 2)}`\n : '{}'\n }\n style={{ fontFamily: 'monospace', fontSize: 12 }}\n />\n <Space.Compact style={{ marginTop: 6, width: '100%' }}>\n <Button size='small' onClick={handleFormat} disabled={!!error}>\n 格式化\n </Button>\n <Button\n size='small'\n onClick={() => {\n setDraft('');\n setError(null);\n onChange(undefined);\n }}\n >\n 清空\n </Button>\n </Space.Compact>\n {error && (\n <Typography.Text type='danger' style={{ fontSize: 11 }}>\n {error}\n </Typography.Text>\n )}\n {description && !error && (\n <span style={{ fontSize: 11, color: '#999' }}>{description}</span>\n )}\n </>\n );\n}\n\nexport const codeEditorWidget = CodeEditor;\n"],"names":["CodeEditor","value","onChange","title","description","placeholder","rest","lines","error","setError","useState","draft","setDraft","text","useMemo","handleChange","raw","trimmed","parsed","e","handleFormat","formatted","jsxs","Fragment","jsx","Input","Space","Button","Typography","codeEditorWidget"],"mappings":";;;AAUO,SAASA,EAAW;AAAA,EACzB,OAAAC;AAAA,EACA,UAAAC;AAAA,EACA,OAAAC;AAAA,EACA,aAAAC;AAAA,EACA,aAAAC;AAAA,EACA,GAAGC;AACL,GAAgB;AAEd,QAAMC,IADaD,GACQ,SAAoB,IAEzC,CAACE,GAAOC,CAAQ,IAAIC,EAAwB,IAAI,GAGhD,CAACC,GAAOC,CAAQ,IAAIF,EAA6B,MAAS,GAE1DG,IAAOC,EAAQ,MAAM;AACzB,QAAIH,MAAU;AACZ,aAAOA;AAET,QAA2BV,KAAU;AACnC,aAAO;AAET,QAAI;AACF,aAAO,KAAK,UAAUA,GAAO,MAAM,CAAC;AAAA,IACtC,QAAQ;AACN,aAAO,OAAOA,CAAK;AAAA,IACrB;AAAA,EACF,GAAG,CAACU,GAAOV,CAAK,CAAC,GAEXc,IAAe,CAACC,MAAgB;AACpC,IAAAJ,EAASI,CAAG;AACZ,UAAMC,IAAUD,EAAI,KAAA;AACpB,QAAI,CAACC,GAAS;AACZ,MAAAR,EAAS,IAAI,GACbP,EAAS,MAAS;AAClB;AAAA,IACF;AACA,QAAI;AACF,YAAMgB,IAAS,KAAK,MAAMD,CAAO;AACjC,MAAAR,EAAS,IAAI,GACbP,EAASgB,CAAM;AAAA,IACjB,SAASC,GAAG;AACV,MAAAV,EAASU,aAAa,QAAQA,EAAE,UAAU,WAAW;AAAA,IACvD;AAAA,EACF,GAEMC,IAAe,MAAM;AACzB,QAAI;AACF,YAAMC,IAAY,KAAK,UAAU,KAAK,MAAMR,CAAI,GAAG,MAAM,CAAC;AAC1D,MAAAD,EAASS,CAAS,GAClBZ,EAAS,IAAI;AAAA,IACf,QAAQ;AAAA,IAER;AAAA,EACF;AAEA,SACE,gBAAAa,EAAAC,GAAA,EACE,UAAA;AAAA,IAAA,gBAAAC;AAAA,MAACC,EAAM;AAAA,MAAN;AAAA,QACC,OAAOZ;AAAA,QACP,MAAMN;AAAA,QACN,UAAU,CAACY,MAAMJ,EAAaI,EAAE,OAAO,KAAK;AAAA,QAC5C,aACEd,IACI;AAAA,EAAQ,OAAOA,KAAgB,WAAWA,IAAc,KAAK,UAAUA,GAAa,MAAM,CAAC,CAAC,KAC5F;AAAA,QAEN,OAAO,EAAE,YAAY,aAAa,UAAU,GAAA;AAAA,MAAG;AAAA,IAAA;AAAA,IAEjD,gBAAAiB,EAACI,EAAM,SAAN,EAAc,OAAO,EAAE,WAAW,GAAG,OAAO,OAAA,GAC3C,UAAA;AAAA,MAAA,gBAAAF,EAACG,GAAA,EAAO,MAAK,SAAQ,SAASP,GAAc,UAAU,CAAC,CAACZ,GAAO,UAAA,MAAA,CAE/D;AAAA,MACA,gBAAAgB;AAAA,QAACG;AAAA,QAAA;AAAA,UACC,MAAK;AAAA,UACL,SAAS,MAAM;AACb,YAAAf,EAAS,EAAE,GACXH,EAAS,IAAI,GACbP,EAAS,MAAS;AAAA,UACpB;AAAA,UACD,UAAA;AAAA,QAAA;AAAA,MAAA;AAAA,IAED,GACF;AAAA,IACCM,KACC,gBAAAgB,EAACI,EAAW,MAAX,EAAgB,MAAK,UAAS,OAAO,EAAE,UAAU,GAAA,GAC/C,UAAApB,EAAA,CACH;AAAA,IAEDJ,KAAe,CAACI,KACf,gBAAAgB,EAAC,QAAA,EAAK,OAAO,EAAE,UAAU,IAAI,OAAO,OAAA,GAAW,UAAApB,EAAA,CAAY;AAAA,EAAA,GAE/D;AAEJ;AAEO,MAAMyB,IAAmB7B;"}
@@ -0,0 +1,50 @@
1
+ import { jsx as t } from "react/jsx-runtime";
2
+ import { Switch as l, InputNumber as a, Input as o } from "antd";
3
+ function u({ value: e, onChange: i, ...s }) {
4
+ const d = s?.dataType ?? "string";
5
+ if (d === "boolean")
6
+ return /* @__PURE__ */ t("div", { style: { width: "100%" }, children: /* @__PURE__ */ t(l, { checked: !!e, onChange: (r) => i(r) }) });
7
+ if (d === "number" || d === "integer")
8
+ return /* @__PURE__ */ t("div", { style: { width: "100%" }, children: /* @__PURE__ */ t(
9
+ a,
10
+ {
11
+ value: e,
12
+ onChange: (r) => i(r ?? void 0),
13
+ style: { width: "100%" }
14
+ }
15
+ ) });
16
+ if (d === "object" || d === "array") {
17
+ const r = e !== void 0 ? JSON.stringify(e, null, 2) : "";
18
+ return /* @__PURE__ */ t("div", { style: { width: "100%" }, children: /* @__PURE__ */ t(
19
+ o.TextArea,
20
+ {
21
+ rows: 3,
22
+ value: r,
23
+ onChange: (c) => {
24
+ const n = c.target.value.trim();
25
+ if (!n) {
26
+ i(void 0);
27
+ return;
28
+ }
29
+ try {
30
+ i(JSON.parse(n));
31
+ } catch {
32
+ }
33
+ }
34
+ }
35
+ ) });
36
+ }
37
+ return /* @__PURE__ */ t("div", { style: { width: "100%" }, children: /* @__PURE__ */ t(
38
+ o,
39
+ {
40
+ value: e ?? "",
41
+ onChange: (r) => i(r.target.value || void 0)
42
+ }
43
+ ) });
44
+ }
45
+ const y = u;
46
+ export {
47
+ u as DefaultEditor,
48
+ y as defaultEditorWidget
49
+ };
50
+ //# sourceMappingURL=default-editor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"default-editor.js","sources":["../../../src/widgets/default-editor.tsx"],"sourcesContent":["// ============================================================================\n// DefaultEditor — 按字段类型编辑默认值\n// string → Input, number/integer → InputNumber, boolean → Switch, object/array → JSON TextArea\n// ============================================================================\n\nimport type { WidgetProps } from '@xbeeant/form-engine-ui';\nimport { Input, InputNumber, Switch } from 'antd';\n\nexport function DefaultEditor({ value, onChange, ...rest }: WidgetProps) {\n const fieldProps = rest as Record<string, unknown>;\n const dataType = (fieldProps?.dataType as string) ?? 'string';\n\n if (dataType === 'boolean') {\n return (\n <div style={{ width: '100%' }}>\n <Switch checked={!!value} onChange={(v) => onChange(v)} />\n </div>\n );\n }\n\n if (dataType === 'number' || dataType === 'integer') {\n return (\n <div style={{ width: '100%' }}>\n <InputNumber\n value={value as number}\n onChange={(v) => onChange(v ?? undefined)}\n style={{ width: '100%' }}\n />\n </div>\n );\n }\n\n if (dataType === 'object' || dataType === 'array') {\n const text = value !== undefined ? JSON.stringify(value, null, 2) : '';\n return (\n <div style={{ width: '100%' }}>\n <Input.TextArea\n rows={3}\n value={text}\n onChange={(e) => {\n const t = e.target.value.trim();\n if (!t) {\n onChange(undefined);\n return;\n }\n try {\n onChange(JSON.parse(t));\n } catch {\n // JSON 解析失败时不更新\n }\n }}\n />\n </div>\n );\n }\n\n // string\n return (\n <div style={{ width: '100%' }}>\n <Input\n value={(value as string) ?? ''}\n onChange={(e) => onChange(e.target.value || undefined)}\n />\n </div>\n );\n}\n\nexport const defaultEditorWidget = DefaultEditor;\n"],"names":["DefaultEditor","value","onChange","rest","dataType","jsx","Switch","v","InputNumber","text","Input","e","t","defaultEditorWidget"],"mappings":";;AAQO,SAASA,EAAc,EAAE,OAAAC,GAAO,UAAAC,GAAU,GAAGC,KAAqB;AAEvE,QAAMC,IADaD,GACW,YAAuB;AAErD,MAAIC,MAAa;AACf,6BACG,OAAA,EAAI,OAAO,EAAE,OAAO,OAAA,GACnB,UAAA,gBAAAC,EAACC,GAAA,EAAO,SAAS,CAAC,CAACL,GAAO,UAAU,CAACM,MAAML,EAASK,CAAC,GAAG,GAC1D;AAIJ,MAAIH,MAAa,YAAYA,MAAa;AACxC,6BACG,OAAA,EAAI,OAAO,EAAE,OAAO,UACnB,UAAA,gBAAAC;AAAA,MAACG;AAAA,MAAA;AAAA,QACC,OAAAP;AAAA,QACA,UAAU,CAACM,MAAML,EAASK,KAAK,MAAS;AAAA,QACxC,OAAO,EAAE,OAAO,OAAA;AAAA,MAAO;AAAA,IAAA,GAE3B;AAIJ,MAAIH,MAAa,YAAYA,MAAa,SAAS;AACjD,UAAMK,IAAOR,MAAU,SAAY,KAAK,UAAUA,GAAO,MAAM,CAAC,IAAI;AACpE,6BACG,OAAA,EAAI,OAAO,EAAE,OAAO,UACnB,UAAA,gBAAAI;AAAA,MAACK,EAAM;AAAA,MAAN;AAAA,QACC,MAAM;AAAA,QACN,OAAOD;AAAA,QACP,UAAU,CAACE,MAAM;AACf,gBAAMC,IAAID,EAAE,OAAO,MAAM,KAAA;AACzB,cAAI,CAACC,GAAG;AACN,YAAAV,EAAS,MAAS;AAClB;AAAA,UACF;AACA,cAAI;AACF,YAAAA,EAAS,KAAK,MAAMU,CAAC,CAAC;AAAA,UACxB,QAAQ;AAAA,UAER;AAAA,QACF;AAAA,MAAA;AAAA,IAAA,GAEJ;AAAA,EAEJ;AAGA,2BACG,OAAA,EAAI,OAAO,EAAE,OAAO,UACnB,UAAA,gBAAAP;AAAA,IAACK;AAAA,IAAA;AAAA,MACC,OAAQT,KAAoB;AAAA,MAC5B,UAAU,CAACU,MAAMT,EAASS,EAAE,OAAO,SAAS,MAAS;AAAA,IAAA;AAAA,EAAA,GAEzD;AAEJ;AAEO,MAAME,IAAsBb;"}
@@ -0,0 +1,36 @@
1
+ import { jsxs as a, jsx as s } from "react/jsx-runtime";
2
+ import { Select as l } from "antd";
3
+ import { useState as y, useRef as n, useEffect as g } from "react";
4
+ import { useFormDataFieldOptions as h } from "./use-form-data-fields.js";
5
+ function A({ value: r, onChange: c }) {
6
+ const d = h(), [m, e] = y(
7
+ () => Array.isArray(r) ? [...r] : []
8
+ ), i = n(r), o = n(r);
9
+ g(() => {
10
+ i.current !== r && (i.current = r, r !== o.current && e(Array.isArray(r) ? [...r] : []));
11
+ }, [r]);
12
+ const p = (t) => {
13
+ e(t), o.current = t, c(t.length > 0 ? t : void 0);
14
+ };
15
+ return /* @__PURE__ */ a("div", { style: { width: "100%" }, children: [
16
+ /* @__PURE__ */ s(
17
+ l,
18
+ {
19
+ size: "small",
20
+ mode: "tags",
21
+ value: m,
22
+ onChange: (t) => p(t.map((f) => f.trim()).filter(Boolean)),
23
+ options: d,
24
+ placeholder: "选择或输入依赖字段路径",
25
+ style: { width: "100%" }
26
+ }
27
+ ),
28
+ /* @__PURE__ */ s("div", { style: { fontSize: 11, color: "#999", marginTop: 4 }, children: "提示:依赖字段值变化时,触发该字段重新求值与渲染。支持相对路径(如 处于 address.city 时填 province 表示 address.province)。" })
29
+ ] });
30
+ }
31
+ const j = A;
32
+ export {
33
+ A as DependenciesEditor,
34
+ j as dependenciesEditorWidget
35
+ };
36
+ //# sourceMappingURL=dependencies-editor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dependencies-editor.js","sources":["../../../src/widgets/dependencies-editor.tsx"],"sourcesContent":["// ============================================================================\n// DependenciesEditor — 编辑 dependencies 依赖字段路径(string[])\n// 通过标签选择器从表单字段中选择依赖路径,也支持手动输入自定义路径\n// ============================================================================\n\nimport type { WidgetProps } from '@xbeeant/form-engine-ui';\nimport { Select } from 'antd';\nimport { useEffect, useRef, useState } from 'react';\nimport { useFormDataFieldOptions } from './use-form-data-fields';\n\nexport function DependenciesEditor({ value, onChange }: WidgetProps) {\n const fieldOptions = useFormDataFieldOptions();\n const [tags, setTags] = useState<string[]>(() =>\n Array.isArray(value) ? [...value] : [],\n );\n const prevValueRef = useRef(value);\n const lastEmittedRef = useRef(value);\n\n // 外部 value 变化(切换节点等)时重置,自身 onChange 回传不重置\n useEffect(() => {\n if (prevValueRef.current !== value) {\n prevValueRef.current = value;\n if (value !== lastEmittedRef.current) {\n setTags(Array.isArray(value) ? [...value] : []);\n }\n }\n }, [value]);\n\n const commit = (next: string[]) => {\n setTags(next);\n lastEmittedRef.current = next;\n onChange(next.length > 0 ? next : undefined);\n };\n\n return (\n <div style={{ width: '100%' }}>\n <Select\n size='small'\n mode='tags'\n value={tags}\n onChange={(v) =>\n commit((v as string[]).map((s) => s.trim()).filter(Boolean))\n }\n options={fieldOptions}\n placeholder='选择或输入依赖字段路径'\n style={{ width: '100%' }}\n />\n <div style={{ fontSize: 11, color: '#999', marginTop: 4 }}>\n 提示:依赖字段值变化时,触发该字段重新求值与渲染。支持相对路径(如 处于\n address.city 时填 province 表示 address.province)。\n </div>\n </div>\n );\n}\n\nexport const dependenciesEditorWidget = DependenciesEditor;\n"],"names":["DependenciesEditor","value","onChange","fieldOptions","useFormDataFieldOptions","tags","setTags","useState","prevValueRef","useRef","lastEmittedRef","useEffect","commit","next","jsx","Select","v","s","dependenciesEditorWidget"],"mappings":";;;;AAUO,SAASA,EAAmB,EAAE,OAAAC,GAAO,UAAAC,KAAyB;AACnE,QAAMC,IAAeC,EAAA,GACf,CAACC,GAAMC,CAAO,IAAIC;AAAA,IAAmB,MACzC,MAAM,QAAQN,CAAK,IAAI,CAAC,GAAGA,CAAK,IAAI,CAAA;AAAA,EAAC,GAEjCO,IAAeC,EAAOR,CAAK,GAC3BS,IAAiBD,EAAOR,CAAK;AAGnC,EAAAU,EAAU,MAAM;AACd,IAAIH,EAAa,YAAYP,MAC3BO,EAAa,UAAUP,GACnBA,MAAUS,EAAe,WAC3BJ,EAAQ,MAAM,QAAQL,CAAK,IAAI,CAAC,GAAGA,CAAK,IAAI,EAAE;AAAA,EAGpD,GAAG,CAACA,CAAK,CAAC;AAEV,QAAMW,IAAS,CAACC,MAAmB;AACjC,IAAAP,EAAQO,CAAI,GACZH,EAAe,UAAUG,GACzBX,EAASW,EAAK,SAAS,IAAIA,IAAO,MAAS;AAAA,EAC7C;AAEA,2BACG,OAAA,EAAI,OAAO,EAAE,OAAO,UACnB,UAAA;AAAA,IAAA,gBAAAC;AAAA,MAACC;AAAA,MAAA;AAAA,QACC,MAAK;AAAA,QACL,MAAK;AAAA,QACL,OAAOV;AAAA,QACP,UAAU,CAACW,MACTJ,EAAQI,EAAe,IAAI,CAACC,MAAMA,EAAE,KAAA,CAAM,EAAE,OAAO,OAAO,CAAC;AAAA,QAE7D,SAASd;AAAA,QACT,aAAY;AAAA,QACZ,OAAO,EAAE,OAAO,OAAA;AAAA,MAAO;AAAA,IAAA;AAAA,IAEzB,gBAAAW,EAAC,OAAA,EAAI,OAAO,EAAE,UAAU,IAAI,OAAO,QAAQ,WAAW,KAAK,UAAA,sFAAA,CAG3D;AAAA,EAAA,GACF;AAEJ;AAEO,MAAMI,IAA2BlB;"}
@@ -0,0 +1,43 @@
1
+ import { jsxs as i, Fragment as a, jsx as o } from "react/jsx-runtime";
2
+ import { Input as n } from "antd";
3
+ function m({ value: t, onChange: e }) {
4
+ return /* @__PURE__ */ i(a, { children: [
5
+ /* @__PURE__ */ o(
6
+ n.TextArea,
7
+ {
8
+ rows: 3,
9
+ value: typeof t == "string" ? t : "",
10
+ onChange: (r) => e(r.target.value),
11
+ placeholder: "每行一个枚举值",
12
+ style: { marginBottom: 4 }
13
+ }
14
+ ),
15
+ /* @__PURE__ */ o(
16
+ "div",
17
+ {
18
+ style: { fontSize: 11, color: "#999", marginTop: -12, marginBottom: 8 },
19
+ children: "提示:枚举值用于选项的值,枚举文案见下方字段"
20
+ }
21
+ )
22
+ ] });
23
+ }
24
+ const l = m;
25
+ function s({ value: t, onChange: e }) {
26
+ return /* @__PURE__ */ o(
27
+ n.TextArea,
28
+ {
29
+ rows: 3,
30
+ value: typeof t == "string" ? t : "",
31
+ onChange: (r) => e(r.target.value),
32
+ placeholder: "每行一个枚举文案,与枚举值一一对应"
33
+ }
34
+ );
35
+ }
36
+ const u = s;
37
+ export {
38
+ m as EnumEditor,
39
+ s as EnumNamesEditor,
40
+ l as enumEditorWidget,
41
+ u as enumNamesEditorWidget
42
+ };
43
+ //# sourceMappingURL=enum-editor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"enum-editor.js","sources":["../../../src/widgets/enum-editor.tsx"],"sourcesContent":["// ============================================================================\n// EnumEditor — 编辑 enum 枚举值及 enumNames 枚举文案\n// 使用两个 TextArea,值按行分隔\n// ============================================================================\n\nimport type { WidgetProps } from '@xbeeant/form-engine-ui';\nimport { Input } from 'antd';\n\nexport function EnumEditor({ value, onChange }: WidgetProps) {\n // value 是一个包含 _enum 和 _enumNames 的对象(由 engine 传入)\n // 实际上 engine 传入的 value 是字段存储的原始值\n // 这里我们使用单独的 _enum 和 _enumNames key\n // 实际上这个 widget 对应 schema 中的 _enum 字段\n // 但 engine 只传单个 value\n\n // 这里简化处理:value 是 _enum 的序列化字符串\n // _enumNames 通过 props 或 dependValues 传递\n // 但更简洁的方式是让 schema 中有两个独立字段\n\n // 这个 widget 实际上应该对应两个字段。让我们重新考虑...\n // 在 schema 中,我们只定义了一个 _enum 字段,这个 widget 渲染时\n // value 是 _enum 的值(序列化字符串)\n\n return (\n <>\n <Input.TextArea\n rows={3}\n value={typeof value === 'string' ? value : ''}\n onChange={(e) => onChange(e.target.value)}\n placeholder='每行一个枚举值'\n style={{ marginBottom: 4 }}\n />\n <div\n style={{ fontSize: 11, color: '#999', marginTop: -12, marginBottom: 8 }}\n >\n 提示:枚举值用于选项的值,枚举文案见下方字段\n </div>\n </>\n );\n}\n\nexport const enumEditorWidget = EnumEditor;\n\n// ────────────────────────────────────────────────────────────────────────────\n// EnumNamesEditor — 编辑 enumNames(与 _enum 配对使用)\n// ────────────────────────────────────────────────────────────────────────────\n\nexport function EnumNamesEditor({ value, onChange }: WidgetProps) {\n return (\n <Input.TextArea\n rows={3}\n value={typeof value === 'string' ? value : ''}\n onChange={(e) => onChange(e.target.value)}\n placeholder='每行一个枚举文案,与枚举值一一对应'\n />\n );\n}\n\nexport const enumNamesEditorWidget = EnumNamesEditor;\n"],"names":["EnumEditor","value","onChange","jsxs","Fragment","jsx","Input","e","enumEditorWidget","EnumNamesEditor","enumNamesEditorWidget"],"mappings":";;AAQO,SAASA,EAAW,EAAE,OAAAC,GAAO,UAAAC,KAAyB;AAe3D,SACE,gBAAAC,EAAAC,GAAA,EACE,UAAA;AAAA,IAAA,gBAAAC;AAAA,MAACC,EAAM;AAAA,MAAN;AAAA,QACC,MAAM;AAAA,QACN,OAAO,OAAOL,KAAU,WAAWA,IAAQ;AAAA,QAC3C,UAAU,CAACM,MAAML,EAASK,EAAE,OAAO,KAAK;AAAA,QACxC,aAAY;AAAA,QACZ,OAAO,EAAE,cAAc,EAAA;AAAA,MAAE;AAAA,IAAA;AAAA,IAE3B,gBAAAF;AAAA,MAAC;AAAA,MAAA;AAAA,QACC,OAAO,EAAE,UAAU,IAAI,OAAO,QAAQ,WAAW,KAAK,cAAc,EAAA;AAAA,QACrE,UAAA;AAAA,MAAA;AAAA,IAAA;AAAA,EAED,GACF;AAEJ;AAEO,MAAMG,IAAmBR;AAMzB,SAASS,EAAgB,EAAE,OAAAR,GAAO,UAAAC,KAAyB;AAChE,SACE,gBAAAG;AAAA,IAACC,EAAM;AAAA,IAAN;AAAA,MACC,MAAM;AAAA,MACN,OAAO,OAAOL,KAAU,WAAWA,IAAQ;AAAA,MAC3C,UAAU,CAACM,MAAML,EAASK,EAAE,OAAO,KAAK;AAAA,MACxC,aAAY;AAAA,IAAA;AAAA,EAAA;AAGlB;AAEO,MAAMG,IAAwBD;"}