@xbeeant/form-engine-designer 0.0.3 → 0.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (131) hide show
  1. package/dist/es/Canvas.js +42 -47
  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 +99 -100
  10. package/dist/es/PropertyPanel.js.map +1 -1
  11. package/dist/es/catalog.js +17 -10
  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.css +1 -1
  18. package/dist/es/index.js +3 -3
  19. package/dist/es/property/basic-property.js +6 -0
  20. package/dist/es/property/basic-property.js.map +1 -1
  21. package/dist/es/property-panel.js +294 -0
  22. package/dist/es/property-panel.js.map +1 -0
  23. package/dist/es/resizable-panel.js +103 -0
  24. package/dist/es/resizable-panel.js.map +1 -0
  25. package/dist/es/schema-utils.js +286 -0
  26. package/dist/es/schema-utils.js.map +1 -0
  27. package/dist/es/widgets/BindEditor.js +60 -49
  28. package/dist/es/widgets/BindEditor.js.map +1 -1
  29. package/dist/es/widgets/CodeEditor.js +41 -49
  30. package/dist/es/widgets/CodeEditor.js.map +1 -1
  31. package/dist/es/widgets/DefaultEditor.js +25 -30
  32. package/dist/es/widgets/DefaultEditor.js.map +1 -1
  33. package/dist/es/widgets/DependenciesEditor.js +21 -21
  34. package/dist/es/widgets/DependenciesEditor.js.map +1 -1
  35. package/dist/es/widgets/EnumEditor.js +25 -31
  36. package/dist/es/widgets/EnumEditor.js.map +1 -1
  37. package/dist/es/widgets/ExpressionSwitch.js +32 -30
  38. package/dist/es/widgets/ExpressionSwitch.js.map +1 -1
  39. package/dist/es/widgets/ReactionsEditor.js +103 -103
  40. package/dist/es/widgets/ReactionsEditor.js.map +1 -1
  41. package/dist/es/widgets/RemoteDataEditor.js +63 -63
  42. package/dist/es/widgets/RemoteDataEditor.js.map +1 -1
  43. package/dist/es/widgets/ValidateEditor.js +49 -49
  44. package/dist/es/widgets/ValidateEditor.js.map +1 -1
  45. package/dist/es/widgets/bind-editor.js +78 -0
  46. package/dist/es/widgets/bind-editor.js.map +1 -0
  47. package/dist/es/widgets/code-editor.js +76 -0
  48. package/dist/es/widgets/code-editor.js.map +1 -0
  49. package/dist/es/widgets/default-editor.js +50 -0
  50. package/dist/es/widgets/default-editor.js.map +1 -0
  51. package/dist/es/widgets/dependencies-editor.js +36 -0
  52. package/dist/es/widgets/dependencies-editor.js.map +1 -0
  53. package/dist/es/widgets/enum-editor.js +43 -0
  54. package/dist/es/widgets/enum-editor.js.map +1 -0
  55. package/dist/es/widgets/expression-builder.js +367 -0
  56. package/dist/es/widgets/expression-builder.js.map +1 -0
  57. package/dist/es/widgets/expression-model.js +340 -0
  58. package/dist/es/widgets/expression-model.js.map +1 -0
  59. package/dist/es/widgets/expression-switch.js +49 -0
  60. package/dist/es/widgets/expression-switch.js.map +1 -0
  61. package/dist/es/widgets/index.js +13 -13
  62. package/dist/es/widgets/index.js.map +1 -1
  63. package/dist/es/widgets/options-editor.js +102 -0
  64. package/dist/es/widgets/options-editor.js.map +1 -0
  65. package/dist/es/widgets/reactions-editor.js +401 -0
  66. package/dist/es/widgets/reactions-editor.js.map +1 -0
  67. package/dist/es/widgets/reactions-model.js +107 -0
  68. package/dist/es/widgets/reactions-model.js.map +1 -0
  69. package/dist/es/widgets/remote-data-editor.js +314 -0
  70. package/dist/es/widgets/remote-data-editor.js.map +1 -0
  71. package/dist/es/widgets/use-form-data-fields.js +16 -0
  72. package/dist/es/widgets/use-form-data-fields.js.map +1 -0
  73. package/dist/es/widgets/validate-editor.js +118 -0
  74. package/dist/es/widgets/validate-editor.js.map +1 -0
  75. package/package.json +4 -5
  76. package/dist/es/react/src/components/FormController.js +0 -160
  77. package/dist/es/react/src/components/FormController.js.map +0 -1
  78. package/dist/es/react/src/components/NexusField.js +0 -98
  79. package/dist/es/react/src/components/NexusField.js.map +0 -1
  80. package/dist/es/react/src/components/NexusForm.js +0 -128
  81. package/dist/es/react/src/components/NexusForm.js.map +0 -1
  82. package/dist/es/react/src/components/NexusFormProvider.js +0 -19
  83. package/dist/es/react/src/components/NexusFormProvider.js.map +0 -1
  84. package/dist/es/react/src/components/NexusLayout.js +0 -49
  85. package/dist/es/react/src/components/NexusLayout.js.map +0 -1
  86. package/dist/es/react/src/components/NexusObject.js +0 -65
  87. package/dist/es/react/src/components/NexusObject.js.map +0 -1
  88. package/dist/es/react/src/contexts/FieldInheritContext.js +0 -6
  89. package/dist/es/react/src/contexts/FieldInheritContext.js.map +0 -1
  90. package/dist/es/react/src/contexts/GridContext.js +0 -6
  91. package/dist/es/react/src/contexts/GridContext.js.map +0 -1
  92. package/dist/es/react/src/contexts/LayoutConfigContext.js +0 -6
  93. package/dist/es/react/src/contexts/LayoutConfigContext.js.map +0 -1
  94. package/dist/es/react/src/contexts/NexusContext.js +0 -13
  95. package/dist/es/react/src/contexts/NexusContext.js.map +0 -1
  96. package/dist/es/react/src/hooks/useForm.js +0 -13
  97. package/dist/es/react/src/hooks/useForm.js.map +0 -1
  98. package/dist/es/react/src/utils/renderTreeNode.js +0 -18
  99. package/dist/es/react/src/utils/renderTreeNode.js.map +0 -1
  100. package/dist/es/react/src/utils/resolveColSpan.js +0 -10
  101. package/dist/es/react/src/utils/resolveColSpan.js.map +0 -1
  102. package/src/Canvas.tsx +0 -1111
  103. package/src/Designer.css +0 -206
  104. package/src/Designer.tsx +0 -254
  105. package/src/DesignerContext.tsx +0 -192
  106. package/src/Palette.tsx +0 -261
  107. package/src/PropertyPanel.tsx +0 -486
  108. package/src/ResizablePanel.tsx +0 -210
  109. package/src/catalog.ts +0 -527
  110. package/src/index.ts +0 -25
  111. package/src/property/basic-property.ts +0 -126
  112. package/src/schemaUtils.test.ts +0 -261
  113. package/src/schemaUtils.ts +0 -627
  114. package/src/types.ts +0 -38
  115. package/src/vite-env.d.ts +0 -1
  116. package/src/widgets/BindEditor.tsx +0 -105
  117. package/src/widgets/CodeEditor.tsx +0 -114
  118. package/src/widgets/DefaultEditor.tsx +0 -73
  119. package/src/widgets/DependenciesEditor.tsx +0 -56
  120. package/src/widgets/EnumEditor.tsx +0 -66
  121. package/src/widgets/ExpressionBuilder.tsx +0 -509
  122. package/src/widgets/ExpressionSwitch.tsx +0 -62
  123. package/src/widgets/OptionsEditor.tsx +0 -141
  124. package/src/widgets/ReactionsEditor.tsx +0 -532
  125. package/src/widgets/RemoteDataEditor.tsx +0 -382
  126. package/src/widgets/ValidateEditor.tsx +0 -162
  127. package/src/widgets/expressionModel.test.ts +0 -262
  128. package/src/widgets/expressionModel.ts +0 -573
  129. package/src/widgets/index.ts +0 -45
  130. package/src/widgets/reactionsModel.ts +0 -190
  131. package/src/widgets/useFormDataFields.ts +0 -21
@@ -1,261 +0,0 @@
1
- import type { NexusSchema, SchemaNode } from '@xbeeant/form-engine';
2
- import { NexusEngine } from '@xbeeant/form-engine';
3
- import { describe, expect, it } from 'vitest';
4
- import {
5
- addChildToSchema,
6
- collectDataFieldOptions,
7
- diffPropertyPatch,
8
- extractFormLevelConfig,
9
- flattenNodeForPropertyEditor,
10
- updateNodeWithNesting,
11
- } from './schemaUtils';
12
-
13
- const radioNode: SchemaNode = {
14
- type: 'string',
15
- widget: 'radio',
16
- title: '单选',
17
- enum: ['a', 'b'],
18
- enumNames: ['选项A', '选项B'],
19
- };
20
-
21
- describe('diffPropertyPatch', () => {
22
- it('filters out empty-string defaults for untouched fields', () => {
23
- const initial = {
24
- title: '单选',
25
- options: [
26
- { value: 'a', label: '选项A' },
27
- { value: 'b', label: '选项B' },
28
- ],
29
- };
30
- const allValues = {
31
- title: '单选',
32
- description: '',
33
- placeholder: '',
34
- default: '',
35
- disabled: '',
36
- readOnly: '',
37
- hidden: '',
38
- required: '',
39
- pattern: '',
40
- bind: '',
41
- dependencies: '',
42
- options: [
43
- { value: 'a', label: '选项A' },
44
- { value: 'b', label: '选项B' },
45
- ],
46
- };
47
- const patch = diffPropertyPatch(initial, allValues);
48
- expect(patch).toEqual({});
49
- });
50
-
51
- it('keeps genuinely changed values', () => {
52
- const initial = { title: '单选', options: [{ value: 'a', label: 'A' }] };
53
- const allValues = {
54
- title: '新标题',
55
- options: [
56
- { value: 'a', label: 'A' },
57
- { value: 'b', label: 'B' },
58
- ],
59
- };
60
- const patch = diffPropertyPatch(initial, allValues);
61
- expect(patch).toEqual(allValues);
62
- });
63
-
64
- it('empty string is treated as unassigned and never written to schema', () => {
65
- const initial = { title: '单选', description: '说明', bind: 'user.name' };
66
- const allValues = { title: '单选', description: '', bind: '' };
67
- const patch = diffPropertyPatch(initial, allValues);
68
- expect(patch).toEqual({});
69
- });
70
-
71
- it('user-cleared field is written back as undefined for deletion', () => {
72
- const initial = { title: '单选', variant: 'outlined', description: '说明' };
73
- const allValues = { title: '单选', variant: '', description: '' };
74
- const changed = new Set(['variant']);
75
- const patch = diffPropertyPatch(initial, allValues, changed);
76
- expect(patch).toEqual({ variant: undefined });
77
- });
78
-
79
- it('untouched empty fields stay skipped even with changedFields set', () => {
80
- const initial = { title: '单选' };
81
- const allValues = { title: '单选', description: '', placeholder: '' };
82
- const changed = new Set(['title']);
83
- const patch = diffPropertyPatch(initial, allValues, changed);
84
- expect(patch).toEqual({});
85
- });
86
- });
87
-
88
- describe('updateNodeWithNesting deletion semantics', () => {
89
- it('cleared UI prop is removed from node.props instead of written as undefined', () => {
90
- const schema: NexusSchema = {
91
- type: 'object',
92
- properties: {
93
- card: {
94
- type: 'card',
95
- title: '卡片',
96
- props: { variant: 'outlined', hoverable: true },
97
- properties: {},
98
- },
99
- },
100
- };
101
- const next = updateNodeWithNesting(schema, ['card'], {
102
- variant: undefined,
103
- });
104
- const node = next.properties.card as Record<string, unknown>;
105
- expect((node.props as Record<string, unknown>).variant).toBeUndefined();
106
- expect('variant' in (node.props as Record<string, unknown>)).toBe(false);
107
- expect((node.props as Record<string, unknown>).hoverable).toBe(true);
108
- });
109
-
110
- it('cleared schema-level key is removed from the node', () => {
111
- const schema: NexusSchema = {
112
- type: 'object',
113
- properties: {
114
- gender: { ...radioNode, bind: 'user.gender' },
115
- },
116
- };
117
- const next = updateNodeWithNesting(schema, ['gender'], { bind: undefined });
118
- const node = next.properties.gender as Record<string, unknown>;
119
- expect(node.bind).toBeUndefined();
120
- expect('bind' in node).toBe(false);
121
- expect(node.title).toBe('单选');
122
- });
123
-
124
- it('widget display format is written into node.props (antd passthrough)', () => {
125
- // date 等控件的 format 是显示格式,必须走 props 通道才能被 widget 消费;
126
- // 顶层 node.format 保留给 JSON Schema 校验语义(email/url)
127
- const schema: NexusSchema = {
128
- type: 'object',
129
- properties: {
130
- birthday: { type: 'string', widget: 'date', title: '出生日期' },
131
- },
132
- };
133
- const next = updateNodeWithNesting(schema, ['birthday'], {
134
- format: 'YYYY/MM/DD',
135
- });
136
- const node = next.properties.birthday as Record<string, unknown>;
137
- expect(node.format).toBeUndefined();
138
- expect('format' in node).toBe(false);
139
- expect((node.props as Record<string, unknown>).format).toBe('YYYY/MM/DD');
140
- });
141
- });
142
-
143
- describe('designer full property-panel patch', () => {
144
- it('empty defaults are not written, radio key preserved in formData', () => {
145
- let schema: NexusSchema = { type: 'object', properties: {} };
146
- schema = addChildToSchema(schema, [], 'gender', radioNode);
147
-
148
- // simulate property form allValues (includes empty-string defaults) + diff filter
149
- const initial = flattenNodeForPropertyEditor(
150
- schema.properties.gender as never,
151
- );
152
- const allValues = {
153
- title: '单选',
154
- description: '',
155
- placeholder: '',
156
- default: '',
157
- extra: '',
158
- disabled: '',
159
- readOnly: '',
160
- readOnlyWidget: '',
161
- hidden: '',
162
- width: '',
163
- options: [
164
- { value: 'a', label: '选项A' },
165
- { value: 'b', label: '选项B' },
166
- ],
167
- optionType: '',
168
- buttonStyle: '',
169
- required: '',
170
- pattern: '',
171
- validate: '',
172
- bind: '',
173
- dependencies: '',
174
- };
175
- const patch = diffPropertyPatch(initial, allValues);
176
- expect(patch.bind).toBeUndefined();
177
-
178
- schema = updateNodeWithNesting(schema, ['gender'], patch);
179
-
180
- const engine = new NexusEngine();
181
- engine.init(schema);
182
- engine.setFieldValue('gender', 'a');
183
- expect(engine.getFormData()).toEqual({ gender: 'a' });
184
- });
185
- });
186
-
187
- describe('extractFormLevelConfig', () => {
188
- it('only extracts top-level form config keys, not the whole schema', () => {
189
- const schema: NexusSchema = {
190
- type: 'object',
191
- displayType: 'row',
192
- colon: true,
193
- properties: { gender: radioNode },
194
- };
195
- const keys = [
196
- 'displayType',
197
- 'labelWidth',
198
- 'colon',
199
- 'label',
200
- 'readOnly',
201
- 'column',
202
- ];
203
- const config = extractFormLevelConfig(
204
- schema as unknown as Record<string, unknown>,
205
- keys,
206
- );
207
- expect(config).toEqual({ displayType: 'row', colon: true });
208
- expect('properties' in config).toBe(false);
209
- expect('type' in config).toBe(false);
210
- });
211
-
212
- it('omits form-level keys that are not set on the schema', () => {
213
- const schema: NexusSchema = { type: 'object', properties: {} };
214
- const config = extractFormLevelConfig(
215
- schema as unknown as Record<string, unknown>,
216
- ['labelWidth', 'column'],
217
- );
218
- expect(config).toEqual({});
219
- });
220
- });
221
-
222
- describe('collectDataFieldOptions', () => {
223
- it('labels options with field title, values with path key', () => {
224
- const schema: NexusSchema = {
225
- type: 'object',
226
- properties: {
227
- user: {
228
- type: 'object',
229
- properties: {
230
- name: { type: 'string', title: '姓名' },
231
- gender: { type: 'string', widget: 'radio', title: '性别' },
232
- },
233
- },
234
- tags: {
235
- type: 'array',
236
- widget: 'list',
237
- items: { type: 'string', widget: 'input', title: '标签项' },
238
- },
239
- },
240
- };
241
- const options = collectDataFieldOptions(schema);
242
- expect(options).toEqual([
243
- { value: 'user.name', label: '姓名' },
244
- { value: 'user.gender', label: '性别' },
245
- { value: 'tags', label: 'tags' },
246
- { value: 'tags[0]', label: '标签项' },
247
- ]);
248
- });
249
-
250
- it('falls back to key when title is missing', () => {
251
- const schema: NexusSchema = {
252
- type: 'object',
253
- properties: {
254
- birthday: { type: 'string', widget: 'date' },
255
- },
256
- };
257
- expect(collectDataFieldOptions(schema)).toEqual([
258
- { value: 'birthday', label: 'birthday' },
259
- ]);
260
- });
261
- });