@xbeeant/form-engine-designer 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +69 -0
- package/dist/es/Canvas.js +636 -0
- package/dist/es/Canvas.js.map +1 -0
- package/dist/es/Designer.js +162 -0
- package/dist/es/Designer.js.map +1 -0
- package/dist/es/DesignerContext.js +97 -0
- package/dist/es/DesignerContext.js.map +1 -0
- package/dist/es/Palette.js +148 -0
- package/dist/es/Palette.js.map +1 -0
- package/dist/es/PropertyPanel.js +294 -0
- package/dist/es/PropertyPanel.js.map +1 -0
- package/dist/es/ResizablePanel.js +103 -0
- package/dist/es/ResizablePanel.js.map +1 -0
- package/dist/es/catalog.js +514 -0
- package/dist/es/catalog.js.map +1 -0
- package/dist/es/form-engine-designer.css +1 -0
- package/dist/es/index.js +20 -0
- package/dist/es/index.js.map +1 -0
- package/dist/es/property/basic-property.js +115 -0
- package/dist/es/property/basic-property.js.map +1 -0
- package/dist/es/react/src/components/FormController.js +154 -0
- package/dist/es/react/src/components/FormController.js.map +1 -0
- package/dist/es/react/src/components/NexusField.js +99 -0
- package/dist/es/react/src/components/NexusField.js.map +1 -0
- package/dist/es/react/src/components/NexusForm.js +121 -0
- package/dist/es/react/src/components/NexusForm.js.map +1 -0
- package/dist/es/react/src/components/NexusFormProvider.js +19 -0
- package/dist/es/react/src/components/NexusFormProvider.js.map +1 -0
- package/dist/es/react/src/components/NexusLayout.js +49 -0
- package/dist/es/react/src/components/NexusLayout.js.map +1 -0
- package/dist/es/react/src/components/NexusObject.js +65 -0
- package/dist/es/react/src/components/NexusObject.js.map +1 -0
- package/dist/es/react/src/contexts/FieldInheritContext.js +6 -0
- package/dist/es/react/src/contexts/FieldInheritContext.js.map +1 -0
- package/dist/es/react/src/contexts/GridContext.js +6 -0
- package/dist/es/react/src/contexts/GridContext.js.map +1 -0
- package/dist/es/react/src/contexts/LayoutConfigContext.js +6 -0
- package/dist/es/react/src/contexts/LayoutConfigContext.js.map +1 -0
- package/dist/es/react/src/contexts/NexusContext.js +13 -0
- package/dist/es/react/src/contexts/NexusContext.js.map +1 -0
- package/dist/es/react/src/hooks/useForm.js +10 -0
- package/dist/es/react/src/hooks/useForm.js.map +1 -0
- package/dist/es/react/src/utils/renderTreeNode.js +18 -0
- package/dist/es/react/src/utils/renderTreeNode.js.map +1 -0
- package/dist/es/react/src/utils/resolveColSpan.js +10 -0
- package/dist/es/react/src/utils/resolveColSpan.js.map +1 -0
- package/dist/es/schemaUtils.js +286 -0
- package/dist/es/schemaUtils.js.map +1 -0
- package/dist/es/schemaUtils.test.js +188 -0
- package/dist/es/schemaUtils.test.js.map +1 -0
- package/dist/es/types.js +2 -0
- package/dist/es/types.js.map +1 -0
- package/dist/es/vite-env.d.js +2 -0
- package/dist/es/vite-env.d.js.map +1 -0
- package/dist/es/widgets/BindEditor.js +67 -0
- package/dist/es/widgets/BindEditor.js.map +1 -0
- package/dist/es/widgets/CodeEditor.js +84 -0
- package/dist/es/widgets/CodeEditor.js.map +1 -0
- package/dist/es/widgets/DefaultEditor.js +55 -0
- package/dist/es/widgets/DefaultEditor.js.map +1 -0
- package/dist/es/widgets/DependenciesEditor.js +36 -0
- package/dist/es/widgets/DependenciesEditor.js.map +1 -0
- package/dist/es/widgets/EnumEditor.js +49 -0
- package/dist/es/widgets/EnumEditor.js.map +1 -0
- package/dist/es/widgets/ExpressionBuilder.js +367 -0
- package/dist/es/widgets/ExpressionBuilder.js.map +1 -0
- package/dist/es/widgets/ExpressionSwitch.js +47 -0
- package/dist/es/widgets/ExpressionSwitch.js.map +1 -0
- package/dist/es/widgets/OptionsEditor.js +102 -0
- package/dist/es/widgets/OptionsEditor.js.map +1 -0
- package/dist/es/widgets/ReactionsEditor.js +401 -0
- package/dist/es/widgets/ReactionsEditor.js.map +1 -0
- package/dist/es/widgets/RemoteDataEditor.js +314 -0
- package/dist/es/widgets/RemoteDataEditor.js.map +1 -0
- package/dist/es/widgets/ValidateEditor.js +118 -0
- package/dist/es/widgets/ValidateEditor.js.map +1 -0
- package/dist/es/widgets/expressionModel.js +340 -0
- package/dist/es/widgets/expressionModel.js.map +1 -0
- package/dist/es/widgets/expressionModel.test.js +193 -0
- package/dist/es/widgets/expressionModel.test.js.map +1 -0
- package/dist/es/widgets/index.js +57 -0
- package/dist/es/widgets/index.js.map +1 -0
- package/dist/es/widgets/reactionsModel.js +107 -0
- package/dist/es/widgets/reactionsModel.js.map +1 -0
- package/dist/es/widgets/useFormDataFields.js +16 -0
- package/dist/es/widgets/useFormDataFields.js.map +1 -0
- package/package.json +62 -0
- package/src/Canvas.tsx +1111 -0
- package/src/Designer.css +206 -0
- package/src/Designer.tsx +254 -0
- package/src/DesignerContext.tsx +192 -0
- package/src/Palette.tsx +261 -0
- package/src/PropertyPanel.tsx +486 -0
- package/src/ResizablePanel.tsx +210 -0
- package/src/catalog.ts +526 -0
- package/src/index.ts +25 -0
- package/src/property/basic-property.ts +126 -0
- package/src/schemaUtils.test.ts +261 -0
- package/src/schemaUtils.ts +627 -0
- package/src/types.ts +38 -0
- package/src/vite-env.d.ts +1 -0
- package/src/widgets/BindEditor.tsx +105 -0
- package/src/widgets/CodeEditor.tsx +114 -0
- package/src/widgets/DefaultEditor.tsx +73 -0
- package/src/widgets/DependenciesEditor.tsx +56 -0
- package/src/widgets/EnumEditor.tsx +66 -0
- package/src/widgets/ExpressionBuilder.tsx +509 -0
- package/src/widgets/ExpressionSwitch.tsx +62 -0
- package/src/widgets/OptionsEditor.tsx +141 -0
- package/src/widgets/ReactionsEditor.tsx +532 -0
- package/src/widgets/RemoteDataEditor.tsx +382 -0
- package/src/widgets/ValidateEditor.tsx +162 -0
- package/src/widgets/expressionModel.test.ts +262 -0
- package/src/widgets/expressionModel.ts +573 -0
- package/src/widgets/index.ts +45 -0
- package/src/widgets/reactionsModel.ts +190 -0
- package/src/widgets/useFormDataFields.ts +21 -0
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
import { NexusEngine as h } from "@xbeeant/form-engine";
|
|
2
|
+
import { describe as s, it as n, expect as t } from "/Users/amybee/Codes/xbeeant/nexus-form-engine/node_modules/.bun/vitest@4.1.10+0a9a94c82e2ce81a/node_modules/vitest/dist/index.js";
|
|
3
|
+
import { diffPropertyPatch as l, updateNodeWithNesting as r, addChildToSchema as m, flattenNodeForPropertyEditor as y, extractFormLevelConfig as c, collectDataFieldOptions as u } from "./schemaUtils.js";
|
|
4
|
+
const p = {
|
|
5
|
+
type: "string",
|
|
6
|
+
widget: "radio",
|
|
7
|
+
title: "单选",
|
|
8
|
+
enum: ["a", "b"],
|
|
9
|
+
enumNames: ["选项A", "选项B"]
|
|
10
|
+
};
|
|
11
|
+
s("diffPropertyPatch", () => {
|
|
12
|
+
n("filters out empty-string defaults for untouched fields", () => {
|
|
13
|
+
const e = l({
|
|
14
|
+
title: "单选",
|
|
15
|
+
options: [
|
|
16
|
+
{ value: "a", label: "选项A" },
|
|
17
|
+
{ value: "b", label: "选项B" }
|
|
18
|
+
]
|
|
19
|
+
}, {
|
|
20
|
+
title: "单选",
|
|
21
|
+
description: "",
|
|
22
|
+
placeholder: "",
|
|
23
|
+
default: "",
|
|
24
|
+
disabled: "",
|
|
25
|
+
readOnly: "",
|
|
26
|
+
hidden: "",
|
|
27
|
+
required: "",
|
|
28
|
+
pattern: "",
|
|
29
|
+
bind: "",
|
|
30
|
+
dependencies: "",
|
|
31
|
+
options: [
|
|
32
|
+
{ value: "a", label: "选项A" },
|
|
33
|
+
{ value: "b", label: "选项B" }
|
|
34
|
+
]
|
|
35
|
+
});
|
|
36
|
+
t(e).toEqual({});
|
|
37
|
+
}), n("keeps genuinely changed values", () => {
|
|
38
|
+
const a = { title: "单选", options: [{ value: "a", label: "A" }] }, i = {
|
|
39
|
+
title: "新标题",
|
|
40
|
+
options: [
|
|
41
|
+
{ value: "a", label: "A" },
|
|
42
|
+
{ value: "b", label: "B" }
|
|
43
|
+
]
|
|
44
|
+
}, e = l(a, i);
|
|
45
|
+
t(e).toEqual(i);
|
|
46
|
+
}), n("empty string is treated as unassigned and never written to schema", () => {
|
|
47
|
+
const e = l({ title: "单选", description: "说明", bind: "user.name" }, { title: "单选", description: "", bind: "" });
|
|
48
|
+
t(e).toEqual({});
|
|
49
|
+
}), n("user-cleared field is written back as undefined for deletion", () => {
|
|
50
|
+
const o = l({ title: "单选", variant: "outlined", description: "说明" }, { title: "单选", variant: "", description: "" }, /* @__PURE__ */ new Set(["variant"]));
|
|
51
|
+
t(o).toEqual({ variant: void 0 });
|
|
52
|
+
}), n("untouched empty fields stay skipped even with changedFields set", () => {
|
|
53
|
+
const o = l({ title: "单选" }, { title: "单选", description: "", placeholder: "" }, /* @__PURE__ */ new Set(["title"]));
|
|
54
|
+
t(o).toEqual({});
|
|
55
|
+
});
|
|
56
|
+
});
|
|
57
|
+
s("updateNodeWithNesting deletion semantics", () => {
|
|
58
|
+
n("cleared UI prop is removed from node.props instead of written as undefined", () => {
|
|
59
|
+
const e = r({
|
|
60
|
+
type: "object",
|
|
61
|
+
properties: {
|
|
62
|
+
card: {
|
|
63
|
+
type: "card",
|
|
64
|
+
title: "卡片",
|
|
65
|
+
props: { variant: "outlined", hoverable: !0 },
|
|
66
|
+
properties: {}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}, ["card"], {
|
|
70
|
+
variant: void 0
|
|
71
|
+
}).properties.card;
|
|
72
|
+
t(e.props.variant).toBeUndefined(), t("variant" in e.props).toBe(!1), t(e.props.hoverable).toBe(!0);
|
|
73
|
+
}), n("cleared schema-level key is removed from the node", () => {
|
|
74
|
+
const a = {
|
|
75
|
+
type: "object",
|
|
76
|
+
properties: {
|
|
77
|
+
gender: { ...p, bind: "user.gender" }
|
|
78
|
+
}
|
|
79
|
+
}, e = r(a, ["gender"], { bind: void 0 }).properties.gender;
|
|
80
|
+
t(e.bind).toBeUndefined(), t("bind" in e).toBe(!1), t(e.title).toBe("单选");
|
|
81
|
+
}), n("widget display format is written into node.props (antd passthrough)", () => {
|
|
82
|
+
const e = r({
|
|
83
|
+
type: "object",
|
|
84
|
+
properties: {
|
|
85
|
+
birthday: { type: "string", widget: "date", title: "出生日期" }
|
|
86
|
+
}
|
|
87
|
+
}, ["birthday"], {
|
|
88
|
+
format: "YYYY/MM/DD"
|
|
89
|
+
}).properties.birthday;
|
|
90
|
+
t(e.format).toBeUndefined(), t("format" in e).toBe(!1), t(e.props.format).toBe("YYYY/MM/DD");
|
|
91
|
+
});
|
|
92
|
+
});
|
|
93
|
+
s("designer full property-panel patch", () => {
|
|
94
|
+
n("empty defaults are not written, radio key preserved in formData", () => {
|
|
95
|
+
let a = { type: "object", properties: {} };
|
|
96
|
+
a = m(a, [], "gender", p);
|
|
97
|
+
const i = y(
|
|
98
|
+
a.properties.gender
|
|
99
|
+
), o = l(i, {
|
|
100
|
+
title: "单选",
|
|
101
|
+
description: "",
|
|
102
|
+
placeholder: "",
|
|
103
|
+
default: "",
|
|
104
|
+
extra: "",
|
|
105
|
+
disabled: "",
|
|
106
|
+
readOnly: "",
|
|
107
|
+
readOnlyWidget: "",
|
|
108
|
+
hidden: "",
|
|
109
|
+
width: "",
|
|
110
|
+
options: [
|
|
111
|
+
{ value: "a", label: "选项A" },
|
|
112
|
+
{ value: "b", label: "选项B" }
|
|
113
|
+
],
|
|
114
|
+
optionType: "",
|
|
115
|
+
buttonStyle: "",
|
|
116
|
+
required: "",
|
|
117
|
+
pattern: "",
|
|
118
|
+
validate: "",
|
|
119
|
+
bind: "",
|
|
120
|
+
dependencies: ""
|
|
121
|
+
});
|
|
122
|
+
t(o.bind).toBeUndefined(), a = r(a, ["gender"], o);
|
|
123
|
+
const d = new h();
|
|
124
|
+
d.init(a), d.setFieldValue("gender", "a"), t(d.getFormData()).toEqual({ gender: "a" });
|
|
125
|
+
});
|
|
126
|
+
});
|
|
127
|
+
s("extractFormLevelConfig", () => {
|
|
128
|
+
n("only extracts top-level form config keys, not the whole schema", () => {
|
|
129
|
+
const e = c(
|
|
130
|
+
{
|
|
131
|
+
type: "object",
|
|
132
|
+
displayType: "row",
|
|
133
|
+
colon: !0,
|
|
134
|
+
properties: { gender: p }
|
|
135
|
+
},
|
|
136
|
+
[
|
|
137
|
+
"displayType",
|
|
138
|
+
"labelWidth",
|
|
139
|
+
"colon",
|
|
140
|
+
"label",
|
|
141
|
+
"readOnly",
|
|
142
|
+
"column"
|
|
143
|
+
]
|
|
144
|
+
);
|
|
145
|
+
t(e).toEqual({ displayType: "row", colon: !0 }), t("properties" in e).toBe(!1), t("type" in e).toBe(!1);
|
|
146
|
+
}), n("omits form-level keys that are not set on the schema", () => {
|
|
147
|
+
const i = c(
|
|
148
|
+
{ type: "object", properties: {} },
|
|
149
|
+
["labelWidth", "column"]
|
|
150
|
+
);
|
|
151
|
+
t(i).toEqual({});
|
|
152
|
+
});
|
|
153
|
+
});
|
|
154
|
+
s("collectDataFieldOptions", () => {
|
|
155
|
+
n("labels options with field title, values with path key", () => {
|
|
156
|
+
const i = u({
|
|
157
|
+
properties: {
|
|
158
|
+
user: {
|
|
159
|
+
type: "object",
|
|
160
|
+
properties: {
|
|
161
|
+
name: { type: "string", title: "姓名" },
|
|
162
|
+
gender: { type: "string", widget: "radio", title: "性别" }
|
|
163
|
+
}
|
|
164
|
+
},
|
|
165
|
+
tags: {
|
|
166
|
+
type: "array",
|
|
167
|
+
widget: "list",
|
|
168
|
+
items: { type: "string", widget: "input", title: "标签项" }
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
});
|
|
172
|
+
t(i).toEqual([
|
|
173
|
+
{ value: "user.name", label: "姓名" },
|
|
174
|
+
{ value: "user.gender", label: "性别" },
|
|
175
|
+
{ value: "tags", label: "tags" },
|
|
176
|
+
{ value: "tags[0]", label: "标签项" }
|
|
177
|
+
]);
|
|
178
|
+
}), n("falls back to key when title is missing", () => {
|
|
179
|
+
t(u({
|
|
180
|
+
properties: {
|
|
181
|
+
birthday: { type: "string", widget: "date" }
|
|
182
|
+
}
|
|
183
|
+
})).toEqual([
|
|
184
|
+
{ value: "birthday", label: "birthday" }
|
|
185
|
+
]);
|
|
186
|
+
});
|
|
187
|
+
});
|
|
188
|
+
//# sourceMappingURL=schemaUtils.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schemaUtils.test.js","sources":["../../src/schemaUtils.test.ts"],"sourcesContent":["import type { NexusSchema, SchemaNode } from '@xbeeant/form-engine';\nimport { NexusEngine } from '@xbeeant/form-engine';\nimport { describe, expect, it } from 'vitest';\nimport {\n addChildToSchema,\n collectDataFieldOptions,\n diffPropertyPatch,\n extractFormLevelConfig,\n flattenNodeForPropertyEditor,\n updateNodeWithNesting,\n} from './schemaUtils';\n\nconst radioNode: SchemaNode = {\n type: 'string',\n widget: 'radio',\n title: '单选',\n enum: ['a', 'b'],\n enumNames: ['选项A', '选项B'],\n};\n\ndescribe('diffPropertyPatch', () => {\n it('filters out empty-string defaults for untouched fields', () => {\n const initial = {\n title: '单选',\n options: [\n { value: 'a', label: '选项A' },\n { value: 'b', label: '选项B' },\n ],\n };\n const allValues = {\n title: '单选',\n description: '',\n placeholder: '',\n default: '',\n disabled: '',\n readOnly: '',\n hidden: '',\n required: '',\n pattern: '',\n bind: '',\n dependencies: '',\n options: [\n { value: 'a', label: '选项A' },\n { value: 'b', label: '选项B' },\n ],\n };\n const patch = diffPropertyPatch(initial, allValues);\n expect(patch).toEqual({});\n });\n\n it('keeps genuinely changed values', () => {\n const initial = { title: '单选', options: [{ value: 'a', label: 'A' }] };\n const allValues = {\n title: '新标题',\n options: [\n { value: 'a', label: 'A' },\n { value: 'b', label: 'B' },\n ],\n };\n const patch = diffPropertyPatch(initial, allValues);\n expect(patch).toEqual(allValues);\n });\n\n it('empty string is treated as unassigned and never written to schema', () => {\n const initial = { title: '单选', description: '说明', bind: 'user.name' };\n const allValues = { title: '单选', description: '', bind: '' };\n const patch = diffPropertyPatch(initial, allValues);\n expect(patch).toEqual({});\n });\n\n it('user-cleared field is written back as undefined for deletion', () => {\n const initial = { title: '单选', variant: 'outlined', description: '说明' };\n const allValues = { title: '单选', variant: '', description: '' };\n const changed = new Set(['variant']);\n const patch = diffPropertyPatch(initial, allValues, changed);\n expect(patch).toEqual({ variant: undefined });\n });\n\n it('untouched empty fields stay skipped even with changedFields set', () => {\n const initial = { title: '单选' };\n const allValues = { title: '单选', description: '', placeholder: '' };\n const changed = new Set(['title']);\n const patch = diffPropertyPatch(initial, allValues, changed);\n expect(patch).toEqual({});\n });\n});\n\ndescribe('updateNodeWithNesting deletion semantics', () => {\n it('cleared UI prop is removed from node.props instead of written as undefined', () => {\n const schema: NexusSchema = {\n type: 'object',\n properties: {\n card: {\n type: 'card',\n title: '卡片',\n props: { variant: 'outlined', hoverable: true },\n properties: {},\n },\n },\n };\n const next = updateNodeWithNesting(schema, ['card'], {\n variant: undefined,\n });\n const node = next.properties.card as Record<string, unknown>;\n expect((node.props as Record<string, unknown>).variant).toBeUndefined();\n expect('variant' in (node.props as Record<string, unknown>)).toBe(false);\n expect((node.props as Record<string, unknown>).hoverable).toBe(true);\n });\n\n it('cleared schema-level key is removed from the node', () => {\n const schema: NexusSchema = {\n type: 'object',\n properties: {\n gender: { ...radioNode, bind: 'user.gender' },\n },\n };\n const next = updateNodeWithNesting(schema, ['gender'], { bind: undefined });\n const node = next.properties.gender as Record<string, unknown>;\n expect(node.bind).toBeUndefined();\n expect('bind' in node).toBe(false);\n expect(node.title).toBe('单选');\n });\n\n it('widget display format is written into node.props (antd passthrough)', () => {\n // date 等控件的 format 是显示格式,必须走 props 通道才能被 widget 消费;\n // 顶层 node.format 保留给 JSON Schema 校验语义(email/url)\n const schema: NexusSchema = {\n type: 'object',\n properties: {\n birthday: { type: 'string', widget: 'date', title: '出生日期' },\n },\n };\n const next = updateNodeWithNesting(schema, ['birthday'], {\n format: 'YYYY/MM/DD',\n });\n const node = next.properties.birthday as Record<string, unknown>;\n expect(node.format).toBeUndefined();\n expect('format' in node).toBe(false);\n expect((node.props as Record<string, unknown>).format).toBe('YYYY/MM/DD');\n });\n});\n\ndescribe('designer full property-panel patch', () => {\n it('empty defaults are not written, radio key preserved in formData', () => {\n let schema: NexusSchema = { type: 'object', properties: {} };\n schema = addChildToSchema(schema, [], 'gender', radioNode);\n\n // simulate property form allValues (includes empty-string defaults) + diff filter\n const initial = flattenNodeForPropertyEditor(\n schema.properties.gender as never,\n );\n const allValues = {\n title: '单选',\n description: '',\n placeholder: '',\n default: '',\n extra: '',\n disabled: '',\n readOnly: '',\n readOnlyWidget: '',\n hidden: '',\n width: '',\n options: [\n { value: 'a', label: '选项A' },\n { value: 'b', label: '选项B' },\n ],\n optionType: '',\n buttonStyle: '',\n required: '',\n pattern: '',\n validate: '',\n bind: '',\n dependencies: '',\n };\n const patch = diffPropertyPatch(initial, allValues);\n expect(patch.bind).toBeUndefined();\n\n schema = updateNodeWithNesting(schema, ['gender'], patch);\n\n const engine = new NexusEngine();\n engine.init(schema);\n engine.setFieldValue('gender', 'a');\n expect(engine.getFormData()).toEqual({ gender: 'a' });\n });\n});\n\ndescribe('extractFormLevelConfig', () => {\n it('only extracts top-level form config keys, not the whole schema', () => {\n const schema: NexusSchema = {\n type: 'object',\n displayType: 'row',\n colon: true,\n properties: { gender: radioNode },\n };\n const keys = [\n 'displayType',\n 'labelWidth',\n 'colon',\n 'label',\n 'readOnly',\n 'column',\n ];\n const config = extractFormLevelConfig(\n schema as unknown as Record<string, unknown>,\n keys,\n );\n expect(config).toEqual({ displayType: 'row', colon: true });\n expect('properties' in config).toBe(false);\n expect('type' in config).toBe(false);\n });\n\n it('omits form-level keys that are not set on the schema', () => {\n const schema: NexusSchema = { type: 'object', properties: {} };\n const config = extractFormLevelConfig(\n schema as unknown as Record<string, unknown>,\n ['labelWidth', 'column'],\n );\n expect(config).toEqual({});\n });\n});\n\ndescribe('collectDataFieldOptions', () => {\n it('labels options with field title, values with path key', () => {\n const schema: NexusSchema = {\n type: 'object',\n properties: {\n user: {\n type: 'object',\n properties: {\n name: { type: 'string', title: '姓名' },\n gender: { type: 'string', widget: 'radio', title: '性别' },\n },\n },\n tags: {\n type: 'array',\n widget: 'list',\n items: { type: 'string', widget: 'input', title: '标签项' },\n },\n },\n };\n const options = collectDataFieldOptions(schema);\n expect(options).toEqual([\n { value: 'user.name', label: '姓名' },\n { value: 'user.gender', label: '性别' },\n { value: 'tags', label: 'tags' },\n { value: 'tags[0]', label: '标签项' },\n ]);\n });\n\n it('falls back to key when title is missing', () => {\n const schema: NexusSchema = {\n type: 'object',\n properties: {\n birthday: { type: 'string', widget: 'date' },\n },\n };\n expect(collectDataFieldOptions(schema)).toEqual([\n { value: 'birthday', label: 'birthday' },\n ]);\n });\n});\n"],"names":["radioNode","describe","it","patch","diffPropertyPatch","expect","initial","allValues","node","updateNodeWithNesting","schema","addChildToSchema","flattenNodeForPropertyEditor","engine","NexusEngine","config","extractFormLevelConfig","options","collectDataFieldOptions"],"mappings":"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"}
|
package/dist/es/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sources":[],"sourcesContent":[],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"vite-env.d.js","sources":[],"sourcesContent":[],"names":[],"mappings":""}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { jsx as n, jsxs as u } from "react/jsx-runtime";
|
|
2
|
+
import { Form as y, Select as g, Input as f } from "antd";
|
|
3
|
+
import { useState as m } from "react";
|
|
4
|
+
function p(e) {
|
|
5
|
+
return e === !1 || e === "false" ? "false" : Array.isArray(e) ? "array" : typeof e == "string" && e.length > 0 ? "string" : "none";
|
|
6
|
+
}
|
|
7
|
+
const h = [
|
|
8
|
+
{ value: "none", label: "无(使用字段路径)" },
|
|
9
|
+
{ value: "string", label: "字符串路径" },
|
|
10
|
+
{ value: "array", label: "字符串数组(多路径拆分)" },
|
|
11
|
+
{ value: "false", label: "不绑定(不提交)" }
|
|
12
|
+
];
|
|
13
|
+
function x({ value: e, onChange: r, title: d }) {
|
|
14
|
+
const l = p(e), [s, i] = m(
|
|
15
|
+
Array.isArray(e) ? e.join(`
|
|
16
|
+
`) : typeof e == "string" ? e : ""
|
|
17
|
+
), c = (t) => {
|
|
18
|
+
t === "none" ? (r(void 0), i("")) : t === "string" ? (r(""), i("")) : t === "array" ? (r([]), i("")) : t === "false" && (r(!1), i(""));
|
|
19
|
+
}, a = () => {
|
|
20
|
+
if (l === "string")
|
|
21
|
+
r(s || void 0);
|
|
22
|
+
else if (l === "array") {
|
|
23
|
+
const t = s.split(`
|
|
24
|
+
`).map((o) => o.trim()).filter((o) => o.length > 0);
|
|
25
|
+
r(t.length > 0 ? t : void 0);
|
|
26
|
+
}
|
|
27
|
+
};
|
|
28
|
+
return /* @__PURE__ */ n(y.Item, { layout: "vertical", label: d, style: { width: "100%" }, children: /* @__PURE__ */ u("div", { style: { display: "flex", flexDirection: "column", gap: 6 }, children: [
|
|
29
|
+
/* @__PURE__ */ n(
|
|
30
|
+
g,
|
|
31
|
+
{
|
|
32
|
+
value: l,
|
|
33
|
+
options: h,
|
|
34
|
+
onChange: c,
|
|
35
|
+
style: { width: "100%" }
|
|
36
|
+
}
|
|
37
|
+
),
|
|
38
|
+
l === "string" && /* @__PURE__ */ n(
|
|
39
|
+
f,
|
|
40
|
+
{
|
|
41
|
+
placeholder: "如: user.name",
|
|
42
|
+
value: s,
|
|
43
|
+
onChange: (t) => i(t.target.value),
|
|
44
|
+
onBlur: a,
|
|
45
|
+
onPressEnter: a
|
|
46
|
+
}
|
|
47
|
+
),
|
|
48
|
+
l === "array" && /* @__PURE__ */ n(
|
|
49
|
+
f.TextArea,
|
|
50
|
+
{
|
|
51
|
+
rows: 3,
|
|
52
|
+
placeholder: `如: a.b
|
|
53
|
+
c.d`,
|
|
54
|
+
value: s,
|
|
55
|
+
onChange: (t) => i(t.target.value),
|
|
56
|
+
onBlur: a
|
|
57
|
+
}
|
|
58
|
+
),
|
|
59
|
+
/* @__PURE__ */ n("div", { style: { fontSize: 11, color: "#999" }, children: "提示:bind 将字段值映射到不同数据路径。string[] 表示字段值数组按顺序拆分到多个路径;false 表示字段不参与提交。" })
|
|
60
|
+
] }) });
|
|
61
|
+
}
|
|
62
|
+
const B = x;
|
|
63
|
+
export {
|
|
64
|
+
x as BindEditor,
|
|
65
|
+
B as bindEditorWidget
|
|
66
|
+
};
|
|
67
|
+
//# sourceMappingURL=BindEditor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"BindEditor.js","sources":["../../../src/widgets/BindEditor.tsx"],"sourcesContent":["// ============================================================================\n// BindEditor — 编辑 bind 属性(路径映射)\n// 支持四种模式:无/字符串/数组/false,不同模式显示不同的子控件\n// ============================================================================\n\nimport type { WidgetProps } from '@xbeeant/form-engine-ui';\nimport { Form, 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, title }: 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 <Form.Item layout={'vertical'} label={title} style={{ width: '100%' }}>\n <div style={{ display: 'flex', flexDirection: 'column', gap: 6 }}>\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 </Form.Item>\n );\n}\n\nexport const bindEditorWidget = BindEditor;\n"],"names":["getBindMode","value","BIND_MODE_OPTIONS","BindEditor","onChange","title","mode","textValue","setTextValue","useState","handleModeChange","newMode","handleTextCommit","lines","s","jsx","Form","jsxs","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,GAAU,OAAAC,KAAsB;AAClE,QAAMC,IAAON,EAAYC,CAAK,GAExB,CAACM,GAAWC,CAAY,IAAIC;AAAA,IAChC,MAAM,QAAQR,CAAK,IACdA,EAAmB,KAAK;AAAA,CAAI,IAC7B,OAAOA,KAAU,WACfA,IACA;AAAA,EAAA,GAGFS,IAAmB,CAACC,MAAoB;AAC5C,IAAIA,MAAY,UACdP,EAAS,MAAS,GAClBI,EAAa,EAAE,KACNG,MAAY,YACrBP,EAAS,EAAE,GACXI,EAAa,EAAE,KACNG,MAAY,WACrBP,EAAS,CAAA,CAAE,GACXI,EAAa,EAAE,KACNG,MAAY,YACrBP,EAAS,EAAK,GACdI,EAAa,EAAE;AAAA,EAEnB,GAEMI,IAAmB,MAAM;AAC7B,QAAIN,MAAS;AACX,MAAAF,EAASG,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,MAAAV,EAASS,EAAM,SAAS,IAAIA,IAAQ,MAAS;AAAA,IAC/C;AAAA,EACF;AAEA,SACE,gBAAAE,EAACC,EAAK,MAAL,EAAU,QAAQ,YAAY,OAAOX,GAAO,OAAO,EAAE,OAAO,UAC3D,UAAA,gBAAAY,EAAC,OAAA,EAAI,OAAO,EAAE,SAAS,QAAQ,eAAe,UAAU,KAAK,EAAA,GAC3D,UAAA;AAAA,IAAA,gBAAAF;AAAA,MAACG;AAAA,MAAA;AAAA,QACC,OAAOZ;AAAA,QACP,SAASJ;AAAA,QACT,UAAUQ;AAAA,QACV,OAAO,EAAE,OAAO,OAAA;AAAA,MAAO;AAAA,IAAA;AAAA,IAExBJ,MAAS,YACR,gBAAAS;AAAA,MAACI;AAAA,MAAA;AAAA,QACC,aAAY;AAAA,QACZ,OAAOZ;AAAA,QACP,UAAU,CAACa,MAAMZ,EAAaY,EAAE,OAAO,KAAK;AAAA,QAC5C,QAAQR;AAAA,QACR,cAAcA;AAAA,MAAA;AAAA,IAAA;AAAA,IAGjBN,MAAS,WACR,gBAAAS;AAAA,MAACI,EAAM;AAAA,MAAN;AAAA,QACC,MAAM;AAAA,QACN,aAAa;AAAA;AAAA,QACb,OAAOZ;AAAA,QACP,UAAU,CAACa,MAAMZ,EAAaY,EAAE,OAAO,KAAK;AAAA,QAC5C,QAAQR;AAAA,MAAA;AAAA,IAAA;AAAA,IAGZ,gBAAAG,EAAC,SAAI,OAAO,EAAE,UAAU,IAAI,OAAO,OAAA,GAAU,UAAA,oEAAA,CAG7C;AAAA,EAAA,EAAA,CACF,EAAA,CACF;AAEJ;AAEO,MAAMM,IAAmBlB;"}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { jsxs as u, jsx as n } from "react/jsx-runtime";
|
|
2
|
+
import { Form as J, 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: h,
|
|
8
|
+
description: d,
|
|
9
|
+
placeholder: o,
|
|
10
|
+
...S
|
|
11
|
+
}) {
|
|
12
|
+
const g = S?.lines ?? 10, [i, e] = y(null), [c, a] = 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]), v = (t) => {
|
|
23
|
+
a(t);
|
|
24
|
+
const m = t.trim();
|
|
25
|
+
if (!m) {
|
|
26
|
+
e(null), l(void 0);
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
try {
|
|
30
|
+
const s = JSON.parse(m);
|
|
31
|
+
e(null), l(s);
|
|
32
|
+
} catch (s) {
|
|
33
|
+
e(s instanceof Error ? s.message : "JSON 解析失败");
|
|
34
|
+
}
|
|
35
|
+
}, x = () => {
|
|
36
|
+
try {
|
|
37
|
+
const t = JSON.stringify(JSON.parse(f), null, 2);
|
|
38
|
+
a(t), e(null);
|
|
39
|
+
} catch {
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
return /* @__PURE__ */ u(
|
|
43
|
+
J.Item,
|
|
44
|
+
{
|
|
45
|
+
label: h,
|
|
46
|
+
layout: "vertical",
|
|
47
|
+
style: { width: "100%" },
|
|
48
|
+
help: i ? /* @__PURE__ */ n(z.Text, { type: "danger", style: { fontSize: 11 }, children: i }) : d ? /* @__PURE__ */ n("span", { style: { fontSize: 11, color: "#999" }, children: d }) : void 0,
|
|
49
|
+
validateStatus: i ? "error" : void 0,
|
|
50
|
+
children: [
|
|
51
|
+
/* @__PURE__ */ n(
|
|
52
|
+
N.TextArea,
|
|
53
|
+
{
|
|
54
|
+
value: f,
|
|
55
|
+
rows: g,
|
|
56
|
+
onChange: (t) => v(t.target.value),
|
|
57
|
+
placeholder: o ? `示例:
|
|
58
|
+
${typeof o == "string" ? o : JSON.stringify(o, null, 2)}` : "{}",
|
|
59
|
+
style: { fontFamily: "monospace", fontSize: 12 }
|
|
60
|
+
}
|
|
61
|
+
),
|
|
62
|
+
/* @__PURE__ */ u(O.Compact, { style: { marginTop: 6, width: "100%" }, children: [
|
|
63
|
+
/* @__PURE__ */ n(p, { size: "small", onClick: x, disabled: !!i, children: "格式化" }),
|
|
64
|
+
/* @__PURE__ */ n(
|
|
65
|
+
p,
|
|
66
|
+
{
|
|
67
|
+
size: "small",
|
|
68
|
+
onClick: () => {
|
|
69
|
+
a(""), e(null), l(void 0);
|
|
70
|
+
},
|
|
71
|
+
children: "清空"
|
|
72
|
+
}
|
|
73
|
+
)
|
|
74
|
+
] })
|
|
75
|
+
]
|
|
76
|
+
}
|
|
77
|
+
);
|
|
78
|
+
}
|
|
79
|
+
const k = E;
|
|
80
|
+
export {
|
|
81
|
+
E as CodeEditor,
|
|
82
|
+
k as codeEditorWidget
|
|
83
|
+
};
|
|
84
|
+
//# sourceMappingURL=CodeEditor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CodeEditor.js","sources":["../../../src/widgets/CodeEditor.tsx"],"sourcesContent":["// ============================================================================\n// CodeEditor — 属性面板专用 JSON 编辑器\n// 供 remoteData 等对象配置使用:支持语法校验、格式化与占位符示例\n// 值格式:object | array(非法 JSON 不写回,光标处自动提示)\n// ============================================================================\n\nimport type { WidgetProps } from '@xbeeant/form-engine-ui';\nimport { Button, Form, 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 <Form.Item\n label={title}\n layout={'vertical'}\n style={{ width: '100%' }}\n help={\n error ? (\n <Typography.Text type='danger' style={{ fontSize: 11 }}>\n {error}\n </Typography.Text>\n ) : description ? (\n <span style={{ fontSize: 11, color: '#999' }}>{description}</span>\n ) : undefined\n }\n validateStatus={error ? 'error' : undefined}\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 </Form.Item>\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","Form","jsx","Typography","Input","Space","Button","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;AAAA,IAACC,EAAK;AAAA,IAAL;AAAA,MACC,OAAOpB;AAAA,MACP,QAAQ;AAAA,MACR,OAAO,EAAE,OAAO,OAAA;AAAA,MAChB,MACEK,IACE,gBAAAgB,EAACC,EAAW,MAAX,EAAgB,MAAK,UAAS,OAAO,EAAE,UAAU,GAAA,GAC/C,aACH,IACErB,IACF,gBAAAoB,EAAC,QAAA,EAAK,OAAO,EAAE,UAAU,IAAI,OAAO,OAAA,GAAW,UAAApB,EAAA,CAAY,IACzD;AAAA,MAEN,gBAAgBI,IAAQ,UAAU;AAAA,MAElC,UAAA;AAAA,QAAA,gBAAAgB;AAAA,UAACE,EAAM;AAAA,UAAN;AAAA,YACC,OAAOb;AAAA,YACP,MAAMN;AAAA,YACN,UAAU,CAACY,MAAMJ,EAAaI,EAAE,OAAO,KAAK;AAAA,YAC5C,aACEd,IACI;AAAA,EAAQ,OAAOA,KAAgB,WAAWA,IAAc,KAAK,UAAUA,GAAa,MAAM,CAAC,CAAC,KAC5F;AAAA,YAEN,OAAO,EAAE,YAAY,aAAa,UAAU,GAAA;AAAA,UAAG;AAAA,QAAA;AAAA,QAEjD,gBAAAiB,EAACK,EAAM,SAAN,EAAc,OAAO,EAAE,WAAW,GAAG,OAAO,OAAA,GAC3C,UAAA;AAAA,UAAA,gBAAAH,EAACI,GAAA,EAAO,MAAK,SAAQ,SAASR,GAAc,UAAU,CAAC,CAACZ,GAAO,UAAA,MAAA,CAE/D;AAAA,UACA,gBAAAgB;AAAA,YAACI;AAAA,YAAA;AAAA,cACC,MAAK;AAAA,cACL,SAAS,MAAM;AACb,gBAAAhB,EAAS,EAAE,GACXH,EAAS,IAAI,GACbP,EAAS,MAAS;AAAA,cACpB;AAAA,cACD,UAAA;AAAA,YAAA;AAAA,UAAA;AAAA,QAED,EAAA,CACF;AAAA,MAAA;AAAA,IAAA;AAAA,EAAA;AAGN;AAEO,MAAM2B,IAAmB7B;"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { jsx as t } from "react/jsx-runtime";
|
|
2
|
+
import { Form as d, Switch as u, InputNumber as f, Input as a } from "antd";
|
|
3
|
+
function h({
|
|
4
|
+
value: r,
|
|
5
|
+
onChange: i,
|
|
6
|
+
title: o,
|
|
7
|
+
...s
|
|
8
|
+
}) {
|
|
9
|
+
const n = s?.dataType ?? "string";
|
|
10
|
+
if (n === "boolean")
|
|
11
|
+
return /* @__PURE__ */ t(d.Item, { label: o, style: { width: "100%" }, children: /* @__PURE__ */ t(u, { checked: !!r, onChange: (e) => i(e) }) });
|
|
12
|
+
if (n === "number" || n === "integer")
|
|
13
|
+
return /* @__PURE__ */ t(d.Item, { label: o, style: { width: "100%" }, children: /* @__PURE__ */ t(
|
|
14
|
+
f,
|
|
15
|
+
{
|
|
16
|
+
value: r,
|
|
17
|
+
onChange: (e) => i(e ?? void 0),
|
|
18
|
+
style: { width: "100%" }
|
|
19
|
+
}
|
|
20
|
+
) });
|
|
21
|
+
if (n === "object" || n === "array") {
|
|
22
|
+
const e = r !== void 0 ? JSON.stringify(r, null, 2) : "";
|
|
23
|
+
return /* @__PURE__ */ t(d.Item, { label: `${o}(JSON)`, style: { width: "100%" }, children: /* @__PURE__ */ t(
|
|
24
|
+
a.TextArea,
|
|
25
|
+
{
|
|
26
|
+
rows: 3,
|
|
27
|
+
value: e,
|
|
28
|
+
onChange: (c) => {
|
|
29
|
+
const l = c.target.value.trim();
|
|
30
|
+
if (!l) {
|
|
31
|
+
i(void 0);
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
try {
|
|
35
|
+
i(JSON.parse(l));
|
|
36
|
+
} catch {
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
) });
|
|
41
|
+
}
|
|
42
|
+
return /* @__PURE__ */ t(d.Item, { label: o, style: { width: "100%" }, children: /* @__PURE__ */ t(
|
|
43
|
+
a,
|
|
44
|
+
{
|
|
45
|
+
value: r ?? "",
|
|
46
|
+
onChange: (e) => i(e.target.value || void 0)
|
|
47
|
+
}
|
|
48
|
+
) });
|
|
49
|
+
}
|
|
50
|
+
const b = h;
|
|
51
|
+
export {
|
|
52
|
+
h as DefaultEditor,
|
|
53
|
+
b as defaultEditorWidget
|
|
54
|
+
};
|
|
55
|
+
//# sourceMappingURL=DefaultEditor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DefaultEditor.js","sources":["../../../src/widgets/DefaultEditor.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 { Form, Input, InputNumber, Switch } from 'antd';\n\nexport function DefaultEditor({\n value,\n onChange,\n title,\n ...rest\n}: 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 <Form.Item label={title} style={{ width: '100%' }}>\n <Switch checked={!!value} onChange={(v) => onChange(v)} />\n </Form.Item>\n );\n }\n\n if (dataType === 'number' || dataType === 'integer') {\n return (\n <Form.Item label={title} style={{ width: '100%' }}>\n <InputNumber\n value={value as number}\n onChange={(v) => onChange(v ?? undefined)}\n style={{ width: '100%' }}\n />\n </Form.Item>\n );\n }\n\n if (dataType === 'object' || dataType === 'array') {\n const text = value !== undefined ? JSON.stringify(value, null, 2) : '';\n return (\n <Form.Item label={`${title}(JSON)`} 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 </Form.Item>\n );\n }\n\n // string\n return (\n <Form.Item label={title} style={{ width: '100%' }}>\n <Input\n value={(value as string) ?? ''}\n onChange={(e) => onChange(e.target.value || undefined)}\n />\n </Form.Item>\n );\n}\n\nexport const defaultEditorWidget = DefaultEditor;\n"],"names":["DefaultEditor","value","onChange","title","rest","dataType","jsx","Form","Switch","v","InputNumber","text","Input","e","t","defaultEditorWidget"],"mappings":";;AAQO,SAASA,EAAc;AAAA,EAC5B,OAAAC;AAAA,EACA,UAAAC;AAAA,EACA,OAAAC;AAAA,EACA,GAAGC;AACL,GAAgB;AAEd,QAAMC,IADaD,GACW,YAAuB;AAErD,MAAIC,MAAa;AACf,WACE,gBAAAC,EAACC,EAAK,MAAL,EAAU,OAAOJ,GAAO,OAAO,EAAE,OAAO,OAAA,GACvC,4BAACK,GAAA,EAAO,SAAS,CAAC,CAACP,GAAO,UAAU,CAACQ,MAAMP,EAASO,CAAC,EAAA,CAAG,EAAA,CAC1D;AAIJ,MAAIJ,MAAa,YAAYA,MAAa;AACxC,WACE,gBAAAC,EAACC,EAAK,MAAL,EAAU,OAAOJ,GAAO,OAAO,EAAE,OAAO,OAAA,GACvC,UAAA,gBAAAG;AAAA,MAACI;AAAA,MAAA;AAAA,QACC,OAAAT;AAAA,QACA,UAAU,CAACQ,MAAMP,EAASO,KAAK,MAAS;AAAA,QACxC,OAAO,EAAE,OAAO,OAAA;AAAA,MAAO;AAAA,IAAA,GAE3B;AAIJ,MAAIJ,MAAa,YAAYA,MAAa,SAAS;AACjD,UAAMM,IAAOV,MAAU,SAAY,KAAK,UAAUA,GAAO,MAAM,CAAC,IAAI;AACpE,WACE,gBAAAK,EAACC,EAAK,MAAL,EAAU,OAAO,GAAGJ,CAAK,UAAU,OAAO,EAAE,OAAO,OAAA,GAClD,UAAA,gBAAAG;AAAA,MAACM,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,YAAAZ,EAAS,MAAS;AAClB;AAAA,UACF;AACA,cAAI;AACF,YAAAA,EAAS,KAAK,MAAMY,CAAC,CAAC;AAAA,UACxB,QAAQ;AAAA,UAER;AAAA,QACF;AAAA,MAAA;AAAA,IAAA,GAEJ;AAAA,EAEJ;AAGA,SACE,gBAAAR,EAACC,EAAK,MAAL,EAAU,OAAOJ,GAAO,OAAO,EAAE,OAAO,OAAA,GACvC,UAAA,gBAAAG;AAAA,IAACM;AAAA,IAAA;AAAA,MACC,OAAQX,KAAoB;AAAA,MAC5B,UAAU,CAAC,MAAMC,EAAS,EAAE,OAAO,SAAS,MAAS;AAAA,IAAA;AAAA,EAAA,GAEzD;AAEJ;AAEO,MAAMa,IAAsBf;"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { jsxs as l, jsx as s } from "react/jsx-runtime";
|
|
2
|
+
import { Form as y, Select as g } from "antd";
|
|
3
|
+
import { useState as h, useRef as n, useEffect as u } from "react";
|
|
4
|
+
import { useFormDataFieldOptions as A } from "./useFormDataFields.js";
|
|
5
|
+
function E({ value: t, onChange: c, title: d }) {
|
|
6
|
+
const m = A(), [p, e] = h(
|
|
7
|
+
() => Array.isArray(t) ? [...t] : []
|
|
8
|
+
), o = n(t), i = n(t);
|
|
9
|
+
u(() => {
|
|
10
|
+
o.current !== t && (o.current = t, t !== i.current && e(Array.isArray(t) ? [...t] : []));
|
|
11
|
+
}, [t]);
|
|
12
|
+
const a = (r) => {
|
|
13
|
+
e(r), i.current = r, c(r.length > 0 ? r : void 0);
|
|
14
|
+
};
|
|
15
|
+
return /* @__PURE__ */ l(y.Item, { layout: "vertical", label: d, style: { width: "100%" }, children: [
|
|
16
|
+
/* @__PURE__ */ s(
|
|
17
|
+
g,
|
|
18
|
+
{
|
|
19
|
+
size: "small",
|
|
20
|
+
mode: "tags",
|
|
21
|
+
value: p,
|
|
22
|
+
onChange: (r) => a(r.map((f) => f.trim()).filter(Boolean)),
|
|
23
|
+
options: m,
|
|
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 w = E;
|
|
32
|
+
export {
|
|
33
|
+
E as DependenciesEditor,
|
|
34
|
+
w as dependenciesEditorWidget
|
|
35
|
+
};
|
|
36
|
+
//# sourceMappingURL=DependenciesEditor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DependenciesEditor.js","sources":["../../../src/widgets/DependenciesEditor.tsx"],"sourcesContent":["// ============================================================================\n// DependenciesEditor — 编辑 dependencies 依赖字段路径(string[])\n// 通过标签选择器从表单字段中选择依赖路径,也支持手动输入自定义路径\n// ============================================================================\n\nimport type { WidgetProps } from '@xbeeant/form-engine-ui';\nimport { Form, Select } from 'antd';\nimport { useEffect, useRef, useState } from 'react';\nimport { useFormDataFieldOptions } from './useFormDataFields';\n\nexport function DependenciesEditor({ value, onChange, title }: 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 <Form.Item layout={'vertical'} label={title} 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 </Form.Item>\n );\n}\n\nexport const dependenciesEditorWidget = DependenciesEditor;\n"],"names":["DependenciesEditor","value","onChange","title","fieldOptions","useFormDataFieldOptions","tags","setTags","useState","prevValueRef","useRef","lastEmittedRef","useEffect","commit","next","jsxs","Form","jsx","Select","v","s","dependenciesEditorWidget"],"mappings":";;;;AAUO,SAASA,EAAmB,EAAE,OAAAC,GAAO,UAAAC,GAAU,OAAAC,KAAsB;AAC1E,QAAMC,IAAeC,EAAA,GACf,CAACC,GAAMC,CAAO,IAAIC;AAAA,IAAmB,MACzC,MAAM,QAAQP,CAAK,IAAI,CAAC,GAAGA,CAAK,IAAI,CAAA;AAAA,EAAC,GAEjCQ,IAAeC,EAAOT,CAAK,GAC3BU,IAAiBD,EAAOT,CAAK;AAGnC,EAAAW,EAAU,MAAM;AACd,IAAIH,EAAa,YAAYR,MAC3BQ,EAAa,UAAUR,GACnBA,MAAUU,EAAe,WAC3BJ,EAAQ,MAAM,QAAQN,CAAK,IAAI,CAAC,GAAGA,CAAK,IAAI,EAAE;AAAA,EAGpD,GAAG,CAACA,CAAK,CAAC;AAEV,QAAMY,IAAS,CAACC,MAAmB;AACjC,IAAAP,EAAQO,CAAI,GACZH,EAAe,UAAUG,GACzBZ,EAASY,EAAK,SAAS,IAAIA,IAAO,MAAS;AAAA,EAC7C;AAEA,SACE,gBAAAC,EAACC,EAAK,MAAL,EAAU,QAAQ,YAAY,OAAOb,GAAO,OAAO,EAAE,OAAO,OAAA,GAC3D,UAAA;AAAA,IAAA,gBAAAc;AAAA,MAACC;AAAA,MAAA;AAAA,QACC,MAAK;AAAA,QACL,MAAK;AAAA,QACL,OAAOZ;AAAA,QACP,UAAU,CAACa,MACTN,EAAQM,EAAe,IAAI,CAACC,MAAMA,EAAE,KAAA,CAAM,EAAE,OAAO,OAAO,CAAC;AAAA,QAE7D,SAAShB;AAAA,QACT,aAAY;AAAA,QACZ,OAAO,EAAE,OAAO,OAAA;AAAA,MAAO;AAAA,IAAA;AAAA,IAEzB,gBAAAa,EAAC,OAAA,EAAI,OAAO,EAAE,UAAU,IAAI,OAAO,QAAQ,WAAW,KAAK,UAAA,sFAAA,CAG3D;AAAA,EAAA,GACF;AAEJ;AAEO,MAAMI,IAA2BrB;"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { jsxs as m, Fragment as a, jsx as t } from "react/jsx-runtime";
|
|
2
|
+
import { Form as o, Input as i } from "antd";
|
|
3
|
+
function l({ value: e, onChange: r }) {
|
|
4
|
+
return /* @__PURE__ */ m(a, { children: [
|
|
5
|
+
/* @__PURE__ */ t(o.Item, { label: "枚举值(enum,每行一个)", style: { width: "100%" }, children: /* @__PURE__ */ t(
|
|
6
|
+
i.TextArea,
|
|
7
|
+
{
|
|
8
|
+
rows: 3,
|
|
9
|
+
value: typeof e == "string" ? e : "",
|
|
10
|
+
onChange: (n) => r(n.target.value),
|
|
11
|
+
placeholder: "每行一个枚举值"
|
|
12
|
+
}
|
|
13
|
+
) }),
|
|
14
|
+
/* @__PURE__ */ t(
|
|
15
|
+
"div",
|
|
16
|
+
{
|
|
17
|
+
style: { fontSize: 11, color: "#999", marginTop: -12, marginBottom: 8 },
|
|
18
|
+
children: "提示:枚举值用于选项的值,枚举文案见下方字段"
|
|
19
|
+
}
|
|
20
|
+
)
|
|
21
|
+
] });
|
|
22
|
+
}
|
|
23
|
+
const c = l;
|
|
24
|
+
function d({ value: e, onChange: r }) {
|
|
25
|
+
return /* @__PURE__ */ t(
|
|
26
|
+
o.Item,
|
|
27
|
+
{
|
|
28
|
+
label: "枚举文案(enumNames,每行一个)",
|
|
29
|
+
style: { width: "100%" },
|
|
30
|
+
children: /* @__PURE__ */ t(
|
|
31
|
+
i.TextArea,
|
|
32
|
+
{
|
|
33
|
+
rows: 3,
|
|
34
|
+
value: typeof e == "string" ? e : "",
|
|
35
|
+
onChange: (n) => r(n.target.value),
|
|
36
|
+
placeholder: "每行一个枚举文案,与枚举值一一对应"
|
|
37
|
+
}
|
|
38
|
+
)
|
|
39
|
+
}
|
|
40
|
+
);
|
|
41
|
+
}
|
|
42
|
+
const g = d;
|
|
43
|
+
export {
|
|
44
|
+
l as EnumEditor,
|
|
45
|
+
d as EnumNamesEditor,
|
|
46
|
+
c as enumEditorWidget,
|
|
47
|
+
g as enumNamesEditorWidget
|
|
48
|
+
};
|
|
49
|
+
//# sourceMappingURL=EnumEditor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"EnumEditor.js","sources":["../../../src/widgets/EnumEditor.tsx"],"sourcesContent":["// ============================================================================\n// EnumEditor — 编辑 enum 枚举值及 enumNames 枚举文案\n// 使用两个 TextArea,值按行分隔\n// ============================================================================\n\nimport type { WidgetProps } from '@xbeeant/form-engine-ui';\nimport { Form, 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 <Form.Item label='枚举值(enum,每行一个)' style={{ width: '100%' }}>\n <Input.TextArea\n rows={3}\n value={typeof value === 'string' ? value : ''}\n onChange={(e) => onChange(e.target.value)}\n placeholder='每行一个枚举值'\n />\n </Form.Item>\n {/* _enumNames 由调用方通过额外逻辑处理 */}\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 <Form.Item\n label='枚举文案(enumNames,每行一个)'\n style={{ width: '100%' }}\n >\n <Input.TextArea\n rows={3}\n value={typeof value === 'string' ? value : ''}\n onChange={(e) => onChange(e.target.value)}\n placeholder='每行一个枚举文案,与枚举值一一对应'\n />\n </Form.Item>\n );\n}\n\nexport const enumNamesEditorWidget = EnumNamesEditor;\n"],"names":["EnumEditor","value","onChange","jsxs","Fragment","jsx","Form","Input","e","enumEditorWidget","EnumNamesEditor","enumNamesEditorWidget"],"mappings":";;AAQO,SAASA,EAAW,EAAE,OAAAC,GAAO,UAAAC,KAAyB;AAe3D,SACE,gBAAAC,EAAAC,GAAA,EACE,UAAA;AAAA,IAAA,gBAAAC,EAACC,EAAK,MAAL,EAAU,OAAM,kBAAiB,OAAO,EAAE,OAAO,OAAA,GAChD,UAAA,gBAAAD;AAAA,MAACE,EAAM;AAAA,MAAN;AAAA,QACC,MAAM;AAAA,QACN,OAAO,OAAON,KAAU,WAAWA,IAAQ;AAAA,QAC3C,UAAU,CAACO,MAAMN,EAASM,EAAE,OAAO,KAAK;AAAA,QACxC,aAAY;AAAA,MAAA;AAAA,IAAA,GAEhB;AAAA,IAEA,gBAAAH;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,MAAMI,IAAmBT;AAMzB,SAASU,EAAgB,EAAE,OAAAT,GAAO,UAAAC,KAAyB;AAChE,SACE,gBAAAG;AAAA,IAACC,EAAK;AAAA,IAAL;AAAA,MACC,OAAM;AAAA,MACN,OAAO,EAAE,OAAO,OAAA;AAAA,MAEhB,UAAA,gBAAAD;AAAA,QAACE,EAAM;AAAA,QAAN;AAAA,UACC,MAAM;AAAA,UACN,OAAO,OAAON,KAAU,WAAWA,IAAQ;AAAA,UAC3C,UAAU,CAACO,MAAMN,EAASM,EAAE,OAAO,KAAK;AAAA,UACxC,aAAY;AAAA,QAAA;AAAA,MAAA;AAAA,IACd;AAAA,EAAA;AAGN;AAEO,MAAMG,IAAwBD;"}
|