@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.
Files changed (117) hide show
  1. package/README.md +69 -0
  2. package/dist/es/Canvas.js +636 -0
  3. package/dist/es/Canvas.js.map +1 -0
  4. package/dist/es/Designer.js +162 -0
  5. package/dist/es/Designer.js.map +1 -0
  6. package/dist/es/DesignerContext.js +97 -0
  7. package/dist/es/DesignerContext.js.map +1 -0
  8. package/dist/es/Palette.js +148 -0
  9. package/dist/es/Palette.js.map +1 -0
  10. package/dist/es/PropertyPanel.js +294 -0
  11. package/dist/es/PropertyPanel.js.map +1 -0
  12. package/dist/es/ResizablePanel.js +103 -0
  13. package/dist/es/ResizablePanel.js.map +1 -0
  14. package/dist/es/catalog.js +514 -0
  15. package/dist/es/catalog.js.map +1 -0
  16. package/dist/es/form-engine-designer.css +1 -0
  17. package/dist/es/index.js +20 -0
  18. package/dist/es/index.js.map +1 -0
  19. package/dist/es/property/basic-property.js +115 -0
  20. package/dist/es/property/basic-property.js.map +1 -0
  21. package/dist/es/react/src/components/FormController.js +154 -0
  22. package/dist/es/react/src/components/FormController.js.map +1 -0
  23. package/dist/es/react/src/components/NexusField.js +99 -0
  24. package/dist/es/react/src/components/NexusField.js.map +1 -0
  25. package/dist/es/react/src/components/NexusForm.js +121 -0
  26. package/dist/es/react/src/components/NexusForm.js.map +1 -0
  27. package/dist/es/react/src/components/NexusFormProvider.js +19 -0
  28. package/dist/es/react/src/components/NexusFormProvider.js.map +1 -0
  29. package/dist/es/react/src/components/NexusLayout.js +49 -0
  30. package/dist/es/react/src/components/NexusLayout.js.map +1 -0
  31. package/dist/es/react/src/components/NexusObject.js +65 -0
  32. package/dist/es/react/src/components/NexusObject.js.map +1 -0
  33. package/dist/es/react/src/contexts/FieldInheritContext.js +6 -0
  34. package/dist/es/react/src/contexts/FieldInheritContext.js.map +1 -0
  35. package/dist/es/react/src/contexts/GridContext.js +6 -0
  36. package/dist/es/react/src/contexts/GridContext.js.map +1 -0
  37. package/dist/es/react/src/contexts/LayoutConfigContext.js +6 -0
  38. package/dist/es/react/src/contexts/LayoutConfigContext.js.map +1 -0
  39. package/dist/es/react/src/contexts/NexusContext.js +13 -0
  40. package/dist/es/react/src/contexts/NexusContext.js.map +1 -0
  41. package/dist/es/react/src/hooks/useForm.js +10 -0
  42. package/dist/es/react/src/hooks/useForm.js.map +1 -0
  43. package/dist/es/react/src/utils/renderTreeNode.js +18 -0
  44. package/dist/es/react/src/utils/renderTreeNode.js.map +1 -0
  45. package/dist/es/react/src/utils/resolveColSpan.js +10 -0
  46. package/dist/es/react/src/utils/resolveColSpan.js.map +1 -0
  47. package/dist/es/schemaUtils.js +286 -0
  48. package/dist/es/schemaUtils.js.map +1 -0
  49. package/dist/es/schemaUtils.test.js +188 -0
  50. package/dist/es/schemaUtils.test.js.map +1 -0
  51. package/dist/es/types.js +2 -0
  52. package/dist/es/types.js.map +1 -0
  53. package/dist/es/vite-env.d.js +2 -0
  54. package/dist/es/vite-env.d.js.map +1 -0
  55. package/dist/es/widgets/BindEditor.js +67 -0
  56. package/dist/es/widgets/BindEditor.js.map +1 -0
  57. package/dist/es/widgets/CodeEditor.js +84 -0
  58. package/dist/es/widgets/CodeEditor.js.map +1 -0
  59. package/dist/es/widgets/DefaultEditor.js +55 -0
  60. package/dist/es/widgets/DefaultEditor.js.map +1 -0
  61. package/dist/es/widgets/DependenciesEditor.js +36 -0
  62. package/dist/es/widgets/DependenciesEditor.js.map +1 -0
  63. package/dist/es/widgets/EnumEditor.js +49 -0
  64. package/dist/es/widgets/EnumEditor.js.map +1 -0
  65. package/dist/es/widgets/ExpressionBuilder.js +367 -0
  66. package/dist/es/widgets/ExpressionBuilder.js.map +1 -0
  67. package/dist/es/widgets/ExpressionSwitch.js +47 -0
  68. package/dist/es/widgets/ExpressionSwitch.js.map +1 -0
  69. package/dist/es/widgets/OptionsEditor.js +102 -0
  70. package/dist/es/widgets/OptionsEditor.js.map +1 -0
  71. package/dist/es/widgets/ReactionsEditor.js +401 -0
  72. package/dist/es/widgets/ReactionsEditor.js.map +1 -0
  73. package/dist/es/widgets/RemoteDataEditor.js +314 -0
  74. package/dist/es/widgets/RemoteDataEditor.js.map +1 -0
  75. package/dist/es/widgets/ValidateEditor.js +118 -0
  76. package/dist/es/widgets/ValidateEditor.js.map +1 -0
  77. package/dist/es/widgets/expressionModel.js +340 -0
  78. package/dist/es/widgets/expressionModel.js.map +1 -0
  79. package/dist/es/widgets/expressionModel.test.js +193 -0
  80. package/dist/es/widgets/expressionModel.test.js.map +1 -0
  81. package/dist/es/widgets/index.js +57 -0
  82. package/dist/es/widgets/index.js.map +1 -0
  83. package/dist/es/widgets/reactionsModel.js +107 -0
  84. package/dist/es/widgets/reactionsModel.js.map +1 -0
  85. package/dist/es/widgets/useFormDataFields.js +16 -0
  86. package/dist/es/widgets/useFormDataFields.js.map +1 -0
  87. package/package.json +62 -0
  88. package/src/Canvas.tsx +1111 -0
  89. package/src/Designer.css +206 -0
  90. package/src/Designer.tsx +254 -0
  91. package/src/DesignerContext.tsx +192 -0
  92. package/src/Palette.tsx +261 -0
  93. package/src/PropertyPanel.tsx +486 -0
  94. package/src/ResizablePanel.tsx +210 -0
  95. package/src/catalog.ts +526 -0
  96. package/src/index.ts +25 -0
  97. package/src/property/basic-property.ts +126 -0
  98. package/src/schemaUtils.test.ts +261 -0
  99. package/src/schemaUtils.ts +627 -0
  100. package/src/types.ts +38 -0
  101. package/src/vite-env.d.ts +1 -0
  102. package/src/widgets/BindEditor.tsx +105 -0
  103. package/src/widgets/CodeEditor.tsx +114 -0
  104. package/src/widgets/DefaultEditor.tsx +73 -0
  105. package/src/widgets/DependenciesEditor.tsx +56 -0
  106. package/src/widgets/EnumEditor.tsx +66 -0
  107. package/src/widgets/ExpressionBuilder.tsx +509 -0
  108. package/src/widgets/ExpressionSwitch.tsx +62 -0
  109. package/src/widgets/OptionsEditor.tsx +141 -0
  110. package/src/widgets/ReactionsEditor.tsx +532 -0
  111. package/src/widgets/RemoteDataEditor.tsx +382 -0
  112. package/src/widgets/ValidateEditor.tsx +162 -0
  113. package/src/widgets/expressionModel.test.ts +262 -0
  114. package/src/widgets/expressionModel.ts +573 -0
  115. package/src/widgets/index.ts +45 -0
  116. package/src/widgets/reactionsModel.ts +190 -0
  117. package/src/widgets/useFormDataFields.ts +21 -0
@@ -0,0 +1,190 @@
1
+ // ============================================================================
2
+ // reactionsModel — ReactionsEditor 的纯数据模型(无 React / DOM 依赖)
3
+ // Reaction ↔ 可编辑卡片(Card)之间的双向转换,以及补丁值解析
4
+ // ============================================================================
5
+
6
+ import type { Reaction } from '@xbeeant/form-engine';
7
+
8
+ export const BOOLEAN_STATE_KEYS = new Set([
9
+ 'visible',
10
+ 'hidden',
11
+ 'disabled',
12
+ 'readOnly',
13
+ 'required',
14
+ 'loading',
15
+ ]);
16
+
17
+ export const PROPS_KEY = '__props';
18
+
19
+ export const STATE_KEY_OPTIONS: Array<{ label: string; value: string }> = [
20
+ { label: '计算值(value)', value: 'value' },
21
+ { label: '显示(visible)', value: 'visible' },
22
+ { label: '隐藏(hidden)', value: 'hidden' },
23
+ { label: '禁用(disabled)', value: 'disabled' },
24
+ { label: '只读(readOnly)', value: 'readOnly' },
25
+ { label: '必填(required)', value: 'required' },
26
+ { label: '加载中(loading)', value: 'loading' },
27
+ { label: '标题(title)', value: 'title' },
28
+ { label: '描述(description)', value: 'description' },
29
+ { label: '组件属性(props.*)', value: PROPS_KEY },
30
+ ];
31
+
32
+ export interface PatchRow {
33
+ key: string;
34
+ value: unknown;
35
+ }
36
+
37
+ export interface Card {
38
+ id: string;
39
+ deps: string;
40
+ when: string;
41
+ fulfillEnabled: boolean;
42
+ fulfillRows: PatchRow[];
43
+ fulfillSchema: string;
44
+ otherwiseEnabled: boolean;
45
+ otherwiseRows: PatchRow[];
46
+ otherwiseSchema: string;
47
+ }
48
+
49
+ export function genId(): string {
50
+ return Math.random().toString(36).slice(2, 8);
51
+ }
52
+
53
+ /** 文本 → 补丁值:true/false 转布尔、数字转 number,其余(含 {{ }} 表达式)保留字符串 */
54
+ export function parsePatchValue(text: string): unknown {
55
+ const t = text.trim();
56
+ if (t === 'true') {
57
+ return true;
58
+ }
59
+ if (t === 'false') {
60
+ return false;
61
+ }
62
+ if (/^-?\d+(\.\d+)?$/.test(t)) {
63
+ return Number(t);
64
+ }
65
+ return text;
66
+ }
67
+
68
+ export function rowsToState(
69
+ rows: PatchRow[],
70
+ ): Record<string, unknown> | undefined {
71
+ const state: Record<string, unknown> = {};
72
+ for (const r of rows) {
73
+ const key = r.key.trim();
74
+ if (!key) {
75
+ continue;
76
+ }
77
+ if (r.value === undefined || r.value === '') {
78
+ continue;
79
+ }
80
+ state[key] = r.value;
81
+ }
82
+ return Object.keys(state).length > 0 ? state : undefined;
83
+ }
84
+
85
+ export function stateToRows(state: object | undefined): PatchRow[] {
86
+ return state
87
+ ? Object.entries(state).map(([key, value]) => ({ key, value }))
88
+ : [];
89
+ }
90
+
91
+ export function parseSchemaText(
92
+ text: string,
93
+ ): Record<string, unknown> | undefined {
94
+ const t = text.trim();
95
+ if (!t) {
96
+ return undefined;
97
+ }
98
+ try {
99
+ const parsed = JSON.parse(t) as unknown;
100
+ if (parsed && typeof parsed === 'object' && !Array.isArray(parsed)) {
101
+ return parsed as Record<string, unknown>;
102
+ }
103
+ } catch {
104
+ // 非法 JSON:忽略本次提交,等待用户修正
105
+ }
106
+ return undefined;
107
+ }
108
+
109
+ export function schemaToText(
110
+ schema: Record<string, unknown> | undefined,
111
+ ): string {
112
+ if (!schema || Object.keys(schema).length === 0) {
113
+ return '';
114
+ }
115
+ try {
116
+ return JSON.stringify(schema, null, 2);
117
+ } catch {
118
+ return '';
119
+ }
120
+ }
121
+
122
+ export function reactionToCard(r: Reaction): Card {
123
+ return {
124
+ id: genId(),
125
+ deps: (r.dependencies ?? []).join(', '),
126
+ when: r.when ?? '',
127
+ fulfillEnabled: !!r.fulfill,
128
+ fulfillRows: stateToRows(r.fulfill?.state),
129
+ fulfillSchema: schemaToText(r.fulfill?.schema),
130
+ otherwiseEnabled: !!r.otherwise,
131
+ otherwiseRows: stateToRows(r.otherwise?.state),
132
+ otherwiseSchema: schemaToText(r.otherwise?.schema),
133
+ };
134
+ }
135
+
136
+ function buildBranch(
137
+ card: Card,
138
+ branch: 'fulfill' | 'otherwise',
139
+ ):
140
+ | { state?: Record<string, unknown>; schema?: Record<string, unknown> }
141
+ | undefined {
142
+ const enabled =
143
+ branch === 'fulfill' ? card.fulfillEnabled : card.otherwiseEnabled;
144
+ if (!enabled) {
145
+ return undefined;
146
+ }
147
+ const rows = branch === 'fulfill' ? card.fulfillRows : card.otherwiseRows;
148
+ const schemaText =
149
+ branch === 'fulfill' ? card.fulfillSchema : card.otherwiseSchema;
150
+ const state = rowsToState(rows);
151
+ const schema = parseSchemaText(schemaText);
152
+ if (state === undefined && schema === undefined) {
153
+ return undefined;
154
+ }
155
+ return {
156
+ ...(state !== undefined ? { state } : {}),
157
+ ...(schema !== undefined ? { schema } : {}),
158
+ };
159
+ }
160
+
161
+ export function cardToReaction(card: Card): Reaction {
162
+ const reaction: Reaction = {
163
+ dependencies: card.deps
164
+ .split(',')
165
+ .map((s) => s.trim())
166
+ .filter(Boolean),
167
+ };
168
+ const when = card.when.trim();
169
+ if (when) {
170
+ reaction.when = when;
171
+ }
172
+ const fulfill = buildBranch(card, 'fulfill');
173
+ const otherwise = buildBranch(card, 'otherwise');
174
+ if (fulfill) {
175
+ reaction.fulfill = fulfill;
176
+ }
177
+ if (otherwise) {
178
+ reaction.otherwise = otherwise;
179
+ }
180
+ return reaction;
181
+ }
182
+
183
+ export function toManualReactions(value: unknown): Reaction[] {
184
+ if (!Array.isArray(value)) {
185
+ return [];
186
+ }
187
+ return value.filter(
188
+ (r): r is Reaction => !!r && (r as Reaction)._autoExpr !== true,
189
+ );
190
+ }
@@ -0,0 +1,21 @@
1
+ // ============================================================================
2
+ // useFormDataFields — 从当前设计器 schema 收集 formData 字段(供变量/依赖选择)
3
+ // ============================================================================
4
+
5
+ import { useMemo } from 'react';
6
+ import { useDesigner } from '../DesignerContext';
7
+ import { collectDataFieldOptions, collectDataFieldPaths } from '../schemaUtils';
8
+
9
+ export function useFormDataFields(): string[] {
10
+ const { schema } = useDesigner();
11
+ return useMemo(() => collectDataFieldPaths(schema), [schema]);
12
+ }
13
+
14
+ /** 带字段标题的选项列表:显示 title,值为路径 key(供 dependencies 等选择器) */
15
+ export function useFormDataFieldOptions(): Array<{
16
+ value: string;
17
+ label: string;
18
+ }> {
19
+ const { schema } = useDesigner();
20
+ return useMemo(() => collectDataFieldOptions(schema), [schema]);
21
+ }