@tmagic/editor 1.3.0-alpha.2 → 1.3.0-alpha.21

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 (167) hide show
  1. package/dist/style.css +91 -120
  2. package/dist/tmagic-editor.js +4609 -3257
  3. package/dist/tmagic-editor.js.map +1 -1
  4. package/dist/tmagic-editor.umd.cjs +5708 -4337
  5. package/dist/tmagic-editor.umd.cjs.map +1 -1
  6. package/package.json +21 -22
  7. package/src/Editor.vue +29 -7
  8. package/src/components/CodeBlockEditor.vue +170 -0
  9. package/src/components/CodeParams.vue +60 -0
  10. package/src/components/ContentMenu.vue +30 -11
  11. package/src/components/Icon.vue +5 -1
  12. package/src/components/Resizer.vue +45 -0
  13. package/src/components/ScrollBar.vue +5 -1
  14. package/src/components/ScrollViewer.vue +5 -1
  15. package/src/components/SearchInput.vue +4 -0
  16. package/src/components/{Layout.vue → SplitView.vue} +8 -4
  17. package/src/components/ToolButton.vue +5 -1
  18. package/src/editorProps.ts +35 -4
  19. package/src/fields/Code.vue +28 -20
  20. package/src/fields/CodeLink.vue +15 -10
  21. package/src/fields/CodeSelect.vue +19 -10
  22. package/src/fields/CodeSelectCol.vue +67 -83
  23. package/src/fields/DataSourceFieldSelect.vue +47 -0
  24. package/src/fields/DataSourceFields.vue +24 -21
  25. package/src/fields/DataSourceInput.vue +318 -0
  26. package/src/fields/DataSourceMethodSelect.vue +136 -0
  27. package/src/fields/DataSourceMethods.vue +103 -0
  28. package/src/fields/DataSourceSelect.vue +68 -0
  29. package/src/fields/EventSelect.vue +62 -22
  30. package/src/fields/KeyValue.vue +13 -11
  31. package/src/fields/UISelect.vue +59 -15
  32. package/src/hooks/index.ts +21 -0
  33. package/src/hooks/use-code-block-edit.ts +84 -0
  34. package/src/hooks/use-data-source-method.ts +100 -0
  35. package/src/{utils/stage.ts → hooks/use-stage.ts} +4 -7
  36. package/src/icons/AppManageIcon.vue +5 -1
  37. package/src/icons/CenterIcon.vue +13 -0
  38. package/src/icons/CodeIcon.vue +5 -3
  39. package/src/index.ts +24 -3
  40. package/src/initService.ts +75 -16
  41. package/src/layouts/AddPageBox.vue +5 -1
  42. package/src/layouts/CodeEditor.vue +66 -11
  43. package/src/layouts/Framework.vue +32 -28
  44. package/src/layouts/NavMenu.vue +5 -1
  45. package/src/layouts/PropsPanel.vue +14 -4
  46. package/src/layouts/sidebar/ComponentListPanel.vue +11 -10
  47. package/src/layouts/sidebar/LayerMenu.vue +13 -25
  48. package/src/layouts/sidebar/LayerNode.vue +40 -0
  49. package/src/layouts/sidebar/LayerPanel.vue +71 -28
  50. package/src/layouts/sidebar/Sidebar.vue +13 -17
  51. package/src/layouts/sidebar/code-block/CodeBlockList.vue +84 -118
  52. package/src/layouts/sidebar/code-block/CodeBlockListPanel.vue +63 -0
  53. package/src/layouts/sidebar/data-source/DataSourceConfigPanel.vue +39 -34
  54. package/src/layouts/sidebar/data-source/DataSourceList.vue +145 -0
  55. package/src/layouts/sidebar/data-source/DataSourceListPanel.vue +17 -65
  56. package/src/layouts/workspace/Breadcrumb.vue +5 -1
  57. package/src/layouts/workspace/PageBar.vue +5 -1
  58. package/src/layouts/workspace/PageBarScrollContainer.vue +5 -1
  59. package/src/layouts/workspace/Stage.vue +30 -8
  60. package/src/layouts/workspace/ViewerMenu.vue +15 -36
  61. package/src/layouts/workspace/Workspace.vue +9 -134
  62. package/src/services/codeBlock.ts +20 -72
  63. package/src/services/dataSource.ts +17 -2
  64. package/src/services/dep.ts +23 -20
  65. package/src/services/editor.ts +3 -3
  66. package/src/services/keybinding.ts +185 -0
  67. package/src/services/props.ts +2 -2
  68. package/src/services/storage.ts +3 -2
  69. package/src/theme/code-block.scss +5 -117
  70. package/src/theme/code-editor.scss +27 -2
  71. package/src/theme/content-menu.scss +1 -1
  72. package/src/theme/data-source-input.scss +18 -0
  73. package/src/theme/data-source-methods.scss +13 -0
  74. package/src/theme/event.scss +15 -12
  75. package/src/theme/framework.scss +0 -3
  76. package/src/theme/layer-panel.scss +6 -0
  77. package/src/theme/layout.scss +4 -0
  78. package/src/theme/resizer.scss +25 -10
  79. package/src/theme/stage.scss +4 -0
  80. package/src/theme/theme.scss +2 -0
  81. package/src/type.ts +105 -7
  82. package/src/utils/config.ts +1 -1
  83. package/src/utils/content-menu.ts +92 -0
  84. package/src/utils/data-source/formConfigs/base.ts +35 -30
  85. package/src/utils/data-source/index.ts +75 -6
  86. package/src/utils/dep.ts +39 -7
  87. package/src/utils/index.ts +1 -1
  88. package/src/utils/keybinding-config.ts +120 -0
  89. package/src/utils/props.ts +298 -155
  90. package/src/utils/undo-redo.ts +1 -1
  91. package/types/Editor.vue.d.ts +37 -4
  92. package/types/components/CodeBlockEditor.vue.d.ts +23 -0
  93. package/types/components/CodeParams.vue.d.ts +26 -0
  94. package/types/components/ContentMenu.vue.d.ts +8 -3
  95. package/types/components/Icon.vue.d.ts +2 -2
  96. package/types/{layouts → components}/Resizer.vue.d.ts +2 -2
  97. package/types/components/ScrollBar.vue.d.ts +1 -1
  98. package/types/components/ScrollViewer.vue.d.ts +8 -5
  99. package/types/components/SearchInput.vue.d.ts +1 -1
  100. package/types/components/{Layout.vue.d.ts → SplitView.vue.d.ts} +9 -6
  101. package/types/components/ToolButton.vue.d.ts +10 -7
  102. package/types/editorProps.d.ts +23 -4
  103. package/types/fields/Code.vue.d.ts +23 -18
  104. package/types/fields/CodeLink.vue.d.ts +13 -22
  105. package/types/fields/CodeSelect.vue.d.ts +12 -20
  106. package/types/fields/CodeSelectCol.vue.d.ts +14 -15
  107. package/types/fields/DataSourceFieldSelect.vue.d.ts +29 -0
  108. package/types/fields/DataSourceFields.vue.d.ts +13 -21
  109. package/types/fields/DataSourceInput.vue.d.ts +34 -0
  110. package/types/fields/DataSourceMethodSelect.vue.d.ts +29 -0
  111. package/types/fields/DataSourceMethods.vue.d.ts +32 -0
  112. package/types/fields/DataSourceSelect.vue.d.ts +40 -0
  113. package/types/fields/EventSelect.vue.d.ts +3 -14
  114. package/types/fields/KeyValue.vue.d.ts +15 -27
  115. package/types/fields/UISelect.vue.d.ts +3 -12
  116. package/types/hooks/index.d.ts +3 -0
  117. package/types/hooks/use-code-block-edit.d.ts +125 -0
  118. package/types/hooks/use-data-source-method.d.ts +123 -0
  119. package/types/icons/AppManageIcon.vue.d.ts +1 -1
  120. package/types/icons/CenterIcon.vue.d.ts +2 -0
  121. package/types/icons/CodeIcon.vue.d.ts +1 -1
  122. package/types/index.d.ts +12 -2
  123. package/types/initService.d.ts +2 -2
  124. package/types/layouts/AddPageBox.vue.d.ts +1 -1
  125. package/types/layouts/CodeEditor.vue.d.ts +18 -10
  126. package/types/layouts/Framework.vue.d.ts +11 -32
  127. package/types/layouts/NavMenu.vue.d.ts +7 -4
  128. package/types/layouts/PropsPanel.vue.d.ts +276 -4
  129. package/types/layouts/sidebar/ComponentListPanel.vue.d.ts +4 -4
  130. package/types/layouts/sidebar/LayerMenu.vue.d.ts +2 -2
  131. package/types/layouts/sidebar/LayerNode.vue.d.ts +16 -0
  132. package/types/layouts/sidebar/LayerPanel.vue.d.ts +5 -5
  133. package/types/layouts/sidebar/Sidebar.vue.d.ts +16 -16
  134. package/types/layouts/sidebar/code-block/CodeBlockList.vue.d.ts +7 -12
  135. package/types/layouts/sidebar/code-block/CodeBlockListPanel.vue.d.ts +28 -0
  136. package/types/layouts/sidebar/data-source/DataSourceConfigPanel.vue.d.ts +4 -2
  137. package/types/layouts/sidebar/data-source/DataSourceList.vue.d.ts +14 -0
  138. package/types/layouts/sidebar/data-source/DataSourceListPanel.vue.d.ts +1 -11
  139. package/types/layouts/workspace/Breadcrumb.vue.d.ts +1 -1
  140. package/types/layouts/workspace/PageBar.vue.d.ts +5 -5
  141. package/types/layouts/workspace/PageBarScrollContainer.vue.d.ts +2 -2
  142. package/types/layouts/workspace/Stage.vue.d.ts +2 -2
  143. package/types/layouts/workspace/ViewerMenu.vue.d.ts +7 -4
  144. package/types/layouts/workspace/Workspace.vue.d.ts +9 -9
  145. package/types/services/codeBlock.d.ts +6 -37
  146. package/types/services/dataSource.d.ts +7 -1
  147. package/types/services/dep.d.ts +12 -21
  148. package/types/services/editor.d.ts +1 -1
  149. package/types/services/keybinding.d.ts +20 -0
  150. package/types/services/props.d.ts +10 -115
  151. package/types/type.d.ts +97 -7
  152. package/types/utils/config.d.ts +1 -1
  153. package/types/utils/content-menu.d.ts +7 -0
  154. package/types/utils/data-source/formConfigs/base.d.ts +2 -2
  155. package/types/utils/data-source/index.d.ts +7 -1
  156. package/types/utils/dep.d.ts +4 -2
  157. package/types/utils/index.d.ts +1 -1
  158. package/types/utils/keybinding-config.d.ts +3 -0
  159. package/types/utils/props.d.ts +13 -102
  160. package/src/components/CodeDraftEditor.vue +0 -144
  161. package/src/components/FunctionEditor.vue +0 -190
  162. package/src/layouts/Resizer.vue +0 -32
  163. package/src/layouts/sidebar/code-block/CodeBlockEditor.vue +0 -96
  164. package/types/components/CodeDraftEditor.vue.d.ts +0 -58
  165. package/types/components/FunctionEditor.vue.d.ts +0 -192
  166. package/types/layouts/sidebar/code-block/CodeBlockEditor.vue.d.ts +0 -25
  167. /package/types/{utils/stage.d.ts → hooks/use-stage.d.ts} +0 -0
@@ -7,9 +7,14 @@ import type { CodeBlockContent, DataSourceSchema, Id, MApp, MNode, MPage } from
7
7
  import { getNodes } from '@tmagic/utils';
8
8
 
9
9
  import type { Target } from './services/dep';
10
- import { createCodeBlockTarget, createDataSourceTarget } from './utils/dep';
10
+ import {
11
+ createCodeBlockTarget,
12
+ createDataSourceCondTarget,
13
+ createDataSourceMethodTarget,
14
+ createDataSourceTarget,
15
+ } from './utils/dep';
11
16
  import editorProps from './editorProps';
12
- import type { Services } from './type';
17
+ import { DepTargetType, Services } from './type';
13
18
 
14
19
  export declare type LooseRequired<T> = {
15
20
  [P in string & keyof T]: T[P];
@@ -25,6 +30,8 @@ export const initServiceState = (
25
30
  eventsService,
26
31
  uiService,
27
32
  codeBlockService,
33
+ keybindingService,
34
+ dataSourceService,
28
35
  }: Services,
29
36
  ) => {
30
37
  // 初始值变化,重新设置节点信息
@@ -46,6 +53,14 @@ export const initServiceState = (
46
53
  },
47
54
  );
48
55
 
56
+ watch(
57
+ () => props.datasourceList,
58
+ (datasourceList) => dataSourceService.set('datasourceTypeList', datasourceList),
59
+ {
60
+ immediate: true,
61
+ },
62
+ );
63
+
49
64
  watch(
50
65
  () => props.propsConfigs,
51
66
  (configs) => propsService.setPropsConfigs(configs),
@@ -81,6 +96,30 @@ export const initServiceState = (
81
96
  },
82
97
  );
83
98
 
99
+ watch(
100
+ () => props.datasourceConfigs,
101
+ (configs) => {
102
+ Object.entries(configs).forEach(([key, value]) => {
103
+ dataSourceService.setFormConfig(key, value);
104
+ });
105
+ },
106
+ {
107
+ immediate: true,
108
+ },
109
+ );
110
+
111
+ watch(
112
+ () => props.datasourceValues,
113
+ (values) => {
114
+ Object.entries(values).forEach(([key, value]) => {
115
+ dataSourceService.setFormValue(key, value);
116
+ });
117
+ },
118
+ {
119
+ immediate: true,
120
+ },
121
+ );
122
+
84
123
  watch(
85
124
  () => props.defaultSelected,
86
125
  (defaultSelected) => defaultSelected && editorService.select(defaultSelected),
@@ -104,6 +143,7 @@ export const initServiceState = (
104
143
  uiService.resetState();
105
144
  componentListService.resetState();
106
145
  codeBlockService.resetState();
146
+ keybindingService.reset();
107
147
  });
108
148
  };
109
149
 
@@ -137,6 +177,7 @@ export const initServiceEvents = (
137
177
 
138
178
  if (app.dsl) {
139
179
  app.dsl.dataSourceDeps = root.dataSourceDeps;
180
+ app.dsl.dataSourceCondDeps = root.dataSourceCondDeps;
140
181
  app.dsl.dataSources = root.dataSources;
141
182
  }
142
183
 
@@ -157,23 +198,34 @@ export const initServiceEvents = (
157
198
  };
158
199
 
159
200
  const targetAddHandler = (target: Target) => {
160
- if (target.type !== 'data-source') return;
161
-
162
201
  const root = editorService.get('root');
163
202
  if (!root) return;
164
203
 
165
- if (!root.dataSourceDeps) {
166
- root.dataSourceDeps = {};
204
+ if (target.type === DepTargetType.DATA_SOURCE) {
205
+ if (!root.dataSourceDeps) {
206
+ root.dataSourceDeps = {};
207
+ }
208
+ root.dataSourceDeps[target.id] = target.deps;
167
209
  }
168
210
 
169
- root.dataSourceDeps[target.id] = target.deps;
211
+ if (target.type === DepTargetType.DATA_SOURCE_COND) {
212
+ if (!root.dataSourceCondDeps) {
213
+ root.dataSourceCondDeps = {};
214
+ }
215
+ root.dataSourceCondDeps[target.id] = target.deps;
216
+ }
170
217
  };
171
218
 
172
219
  const targetRemoveHandler = (id: string | number) => {
173
220
  const root = editorService.get('root');
174
- if (!root?.dataSourceDeps) return;
175
221
 
176
- delete root.dataSourceDeps[id];
222
+ if (root?.dataSourceDeps) {
223
+ delete root.dataSourceDeps[id];
224
+ }
225
+
226
+ if (root?.dataSourceCondDeps) {
227
+ delete root.dataSourceCondDeps[id];
228
+ }
177
229
  };
178
230
 
179
231
  const depUpdateHandler = (node: MNode) => {
@@ -189,6 +241,12 @@ export const initServiceEvents = (
189
241
  depService.on('dep-update', depUpdateHandler);
190
242
  depService.on('collected', collectedHandler);
191
243
 
244
+ const initDataSourceDepTarget = (ds: DataSourceSchema) => {
245
+ depService.addTarget(createDataSourceTarget(ds.id));
246
+ depService.addTarget(createDataSourceMethodTarget(ds.id));
247
+ depService.addTarget(createDataSourceCondTarget(ds.id));
248
+ };
249
+
192
250
  const rootChangeHandler = async (value: MApp, preValue?: MApp | null) => {
193
251
  const nodeId = editorService.get('node')?.id || props.defaultSelected;
194
252
  let node;
@@ -216,14 +274,14 @@ export const initServiceEvents = (
216
274
  codeBlockService.setCodeDsl(value.codeBlocks);
217
275
  dataSourceService.set('dataSources', value.dataSources);
218
276
 
219
- depService.removeTargets('code-block');
277
+ depService.removeTargets(DepTargetType.CODE_BLOCK);
220
278
 
221
279
  Object.entries(value.codeBlocks).forEach(([id, code]) => {
222
280
  depService.addTarget(createCodeBlockTarget(id, code));
223
281
  });
224
282
 
225
283
  value.dataSources.forEach((ds) => {
226
- depService.addTarget(createDataSourceTarget(ds.id, ds));
284
+ initDataSourceDepTarget(ds);
227
285
  });
228
286
 
229
287
  if (value && Array.isArray(value.items)) {
@@ -234,18 +292,22 @@ export const initServiceEvents = (
234
292
  }
235
293
  };
236
294
 
295
+ // 新增节点,收集依赖
237
296
  const nodeAddHandler = (nodes: MNode[]) => {
238
297
  depService.collect(nodes);
239
298
  };
240
299
 
300
+ // 节点更新,收集依赖
241
301
  const nodeUpdateHandler = (nodes: MNode[]) => {
242
302
  depService.collect(nodes);
243
303
  };
244
304
 
305
+ // 节点删除,清除对齐的依赖收集
245
306
  const nodeRemoveHandler = (nodes: MNode[]) => {
246
307
  depService.clear(nodes);
247
308
  };
248
309
 
310
+ // 由于历史记录变化是更新整个page,所以历史记录变化时,需要重新收集依赖
249
311
  const historyChangeHandler = (page: MPage) => {
250
312
  depService.collect([page], true);
251
313
  };
@@ -273,17 +335,14 @@ export const initServiceEvents = (
273
335
  codeBlockService.on('remove', codeBlockRemoveHandler);
274
336
 
275
337
  const dataSourceAddHandler = (config: DataSourceSchema) => {
276
- depService.addTarget(createDataSourceTarget(config.id, config));
338
+ initDataSourceDepTarget(config);
277
339
  getApp()?.dataSourceManager?.addDataSource(config);
278
340
  };
279
341
 
280
342
  const dataSourceUpdateHandler = (config: DataSourceSchema) => {
281
- if (config.title) {
282
- depService.getTarget(config.id)!.name = config.title;
283
- }
284
343
  const root = editorService.get('root');
285
344
 
286
- const targets = depService.getTargets('data-source');
345
+ const targets = depService.getTargets(DepTargetType.DATA_SOURCE);
287
346
 
288
347
  const nodes = getNodes(Object.keys(targets[config.id].deps), root?.items);
289
348
 
@@ -11,7 +11,7 @@
11
11
  </div>
12
12
  </template>
13
13
 
14
- <script lang="ts" setup name="MEditorAddPageBox">
14
+ <script lang="ts" setup>
15
15
  import { inject, toRaw } from 'vue';
16
16
  import { Plus } from '@element-plus/icons-vue';
17
17
 
@@ -21,6 +21,10 @@ import MIcon from '@editor/components/Icon.vue';
21
21
  import type { Services } from '@editor/type';
22
22
  import { generatePageNameByApp } from '@editor/utils';
23
23
 
24
+ defineOptions({
25
+ name: 'MEditorAddPageBox',
26
+ });
27
+
24
28
  const services = inject<Services>('services');
25
29
 
26
30
  const clickHandler = () => {
@@ -1,22 +1,46 @@
1
1
  <template>
2
- <div ref="codeEditor" class="magic-code-editor"></div>
2
+ <div :class="`magic-code-editor`">
3
+ <Teleport to="body" :disabled="!fullScreen">
4
+ <div
5
+ :class="`magic-code-editor-wrapper${fullScreen ? ' full-screen' : ''}`"
6
+ :style="!fullScreen && height ? `height: ${height}` : '100%'"
7
+ >
8
+ <TMagicButton
9
+ class="magic-code-editor-full-screen-icon"
10
+ circle
11
+ size="small"
12
+ :icon="FullScreen"
13
+ @click="fullScreenHandler"
14
+ ></TMagicButton>
15
+ <div ref="codeEditor" class="magic-code-editor-content"></div>
16
+ </div>
17
+ </Teleport>
18
+ </div>
3
19
  </template>
4
20
 
5
- <script lang="ts" setup name="MEditorCodeEditor">
21
+ <script lang="ts" setup>
6
22
  import { onMounted, onUnmounted, ref, watch } from 'vue';
23
+ import { FullScreen } from '@element-plus/icons-vue';
7
24
  import { throttle } from 'lodash-es';
8
25
  import * as monaco from 'monaco-editor';
9
26
  import serialize from 'serialize-javascript';
10
27
 
28
+ import { TMagicButton } from '@tmagic/design';
29
+
30
+ defineOptions({
31
+ name: 'MEditorCodeEditor',
32
+ });
33
+
11
34
  const props = withDefaults(
12
35
  defineProps<{
13
- initValues?: string | Object;
14
- modifiedValues?: string | Object;
36
+ initValues?: string | Record<string | number, any> | null;
37
+ modifiedValues?: string | Record<string | number, any> | null;
15
38
  type?: 'diff';
16
39
  language?: string;
17
40
  options?: {
18
41
  [key: string]: any;
19
42
  };
43
+ height?: string;
20
44
  autoSave?: boolean;
21
45
  }>(),
22
46
  {
@@ -33,10 +57,14 @@ const emit = defineEmits(['initd', 'save']);
33
57
  const toString = (v: string | any, language: string): string => {
34
58
  let value = '';
35
59
  if (typeof v !== 'string') {
36
- value = serialize(v, {
37
- space: 2,
38
- unsafe: true,
39
- }).replace(/"(\w+)":\s/g, '$1: ');
60
+ if (props.language.toLocaleLowerCase() === 'json') {
61
+ value = JSON.stringify(v, null, 2);
62
+ } else {
63
+ value = serialize(v, {
64
+ space: 2,
65
+ unsafe: true,
66
+ }).replace(/"(\w+)":\s/g, '$1: ');
67
+ }
40
68
  } else {
41
69
  value = v;
42
70
  }
@@ -77,7 +105,7 @@ const setEditorValue = (v: string | any, m: string | any) => {
77
105
  };
78
106
 
79
107
  const getEditorValue = () =>
80
- props.type === 'diff' ? vsDiffEditor?.getModifiedEditor().getValue() : vsEditor?.getValue();
108
+ (props.type === 'diff' ? vsDiffEditor?.getModifiedEditor().getValue() : vsEditor?.getValue()) || '';
81
109
 
82
110
  const init = async () => {
83
111
  if (!codeEditor.value) return;
@@ -105,13 +133,19 @@ const init = async () => {
105
133
  if (e.keyCode === 83 && (navigator.platform.match('Mac') ? e.metaKey : e.ctrlKey)) {
106
134
  e.preventDefault();
107
135
  e.stopPropagation();
108
- emit('save', getEditorValue());
136
+ const newValue = getEditorValue();
137
+ values.value = newValue;
138
+ emit('save', newValue);
109
139
  }
110
140
  });
111
141
 
112
142
  if (props.type !== 'diff' && props.autoSave) {
113
143
  vsEditor?.onDidBlurEditorWidget(() => {
114
- emit('save', getEditorValue());
144
+ const newValue = getEditorValue();
145
+ if (values.value !== newValue) {
146
+ values.value = newValue;
147
+ emit('save', newValue);
148
+ }
115
149
  });
116
150
  }
117
151
 
@@ -141,11 +175,32 @@ onUnmounted(() => {
141
175
  resizeObserver.disconnect();
142
176
  });
143
177
 
178
+ const fullScreen = ref(false);
179
+ const fullScreenHandler = () => {
180
+ fullScreen.value = !fullScreen.value;
181
+ setTimeout(() => {
182
+ vsEditor?.focus();
183
+ vsEditor?.layout();
184
+ vsDiffEditor?.focus();
185
+ vsDiffEditor?.layout();
186
+ });
187
+ };
188
+
144
189
  defineExpose({
190
+ values,
191
+
145
192
  getEditor() {
146
193
  return vsEditor || vsDiffEditor;
147
194
  },
148
195
 
196
+ getVsEditor() {
197
+ return vsEditor;
198
+ },
199
+
200
+ getVsDiffEditor() {
201
+ return vsDiffEditor;
202
+ },
203
+
149
204
  setEditorValue,
150
205
 
151
206
  focus() {
@@ -1,16 +1,16 @@
1
1
  <template>
2
- <div class="m-editor">
3
- <slot name="nav" class="m-editor-nav-menu"></slot>
2
+ <div class="m-editor" ref="content">
3
+ <slot name="header"></slot>
4
4
 
5
- <magic-code-editor
6
- v-if="showSrc"
7
- class="m-editor-content"
8
- :init-values="root"
9
- :options="codeOptions"
10
- @save="saveCode"
11
- ></magic-code-editor>
5
+ <slot name="nav"></slot>
6
+
7
+ <slot name="content-before"></slot>
8
+
9
+ <slot name="src-code" v-if="showSrc">
10
+ <CodeEditor class="m-editor-content" :init-values="root" :options="codeOptions" @save="saveCode"></CodeEditor>
11
+ </slot>
12
12
 
13
- <Layout
13
+ <SplitView
14
14
  v-else
15
15
  class="m-editor-content"
16
16
  left-class="m-editor-framework-left"
@@ -33,41 +33,43 @@
33
33
  </slot>
34
34
  </template>
35
35
 
36
- <template v-if="pageLength > 0 && nodes.length === 1" #right>
36
+ <template v-if="pageLength > 0" #right>
37
37
  <TMagicScrollbar>
38
38
  <slot name="props-panel"></slot>
39
39
  </TMagicScrollbar>
40
40
  </template>
41
- </Layout>
41
+ </SplitView>
42
+
43
+ <slot name="content-after"></slot>
44
+ <slot name="footer"></slot>
42
45
  </div>
43
46
  </template>
44
47
 
45
- <script lang="ts" setup name="MEditorFramework">
48
+ <script lang="ts" setup>
46
49
  import { computed, inject, ref, watch } from 'vue';
47
50
 
48
51
  import { TMagicScrollbar } from '@tmagic/design';
49
52
 
50
- import Layout from '@editor/components/Layout.vue';
53
+ import SplitView from '@editor/components/SplitView.vue';
51
54
  import type { GetColumnWidth, Services } from '@editor/type';
55
+ import { getConfig } from '@editor/utils/config';
52
56
 
53
57
  import AddPageBox from './AddPageBox.vue';
58
+ import CodeEditor from './CodeEditor.vue';
59
+
60
+ defineOptions({
61
+ name: 'MEditorFramework',
62
+ });
54
63
 
55
64
  const DEFAULT_LEFT_COLUMN_WIDTH = 310;
56
65
  const DEFAULT_RIGHT_COLUMN_WIDTH = 480;
57
66
 
58
- withDefaults(
59
- defineProps<{
60
- codeOptions?: Record<string, any>;
61
- }>(),
62
- {
63
- codeOptions: () => ({}),
64
- },
65
- );
66
-
67
+ const codeOptions = inject('codeOptions', {});
67
68
  const { editorService, uiService } = inject<Services>('services') || {};
68
69
 
70
+ const content = ref<HTMLDivElement>();
71
+
69
72
  const root = computed(() => editorService?.get('root'));
70
- const nodes = computed(() => editorService?.get('nodes') || []);
71
73
 
72
74
  const pageLength = computed(() => editorService?.get('pageLength') || 0);
73
75
  const showSrc = computed(() => uiService?.get('showSrc'));
@@ -91,13 +93,15 @@ watch(
91
93
 
92
94
  columnWidth.value.left = left;
93
95
 
96
+ const container = content.value || document.body;
97
+
94
98
  if (length <= 0) {
95
99
  columnWidth.value.right = undefined;
96
- columnWidth.value.center = globalThis.document.body.clientWidth - left;
100
+ columnWidth.value.center = container.clientWidth - left;
97
101
  } else {
98
102
  const right = columnWidth.value.right || RightColumnWidthCacheData || DEFAULT_RIGHT_COLUMN_WIDTH;
99
103
  columnWidth.value.right = right;
100
- columnWidth.value.center = globalThis.document.body.clientWidth - left - right;
104
+ columnWidth.value.center = container.clientWidth - left - right;
101
105
  }
102
106
 
103
107
  uiService?.set('columnWidth', columnWidth.value as GetColumnWidth);
@@ -131,8 +135,8 @@ const columnWidthChange = (columnW: GetColumnWidth) => {
131
135
 
132
136
  const saveCode = (value: string) => {
133
137
  try {
134
- // eslint-disable-next-line no-eval
135
- editorService?.set('root', eval(value));
138
+ const parseDSL = getConfig('parseDSL');
139
+ editorService?.set('root', parseDSL(value));
136
140
  } catch (e: any) {
137
141
  console.error(e);
138
142
  }
@@ -6,7 +6,7 @@
6
6
  </div>
7
7
  </template>
8
8
 
9
- <script lang="ts" setup name="MEditorNavMenu">
9
+ <script lang="ts" setup>
10
10
  import { computed, inject, markRaw } from 'vue';
11
11
  import { Back, Delete, FullScreen, Grid, Memo, Right, ScaleToOriginal, ZoomIn, ZoomOut } from '@element-plus/icons-vue';
12
12
 
@@ -15,6 +15,10 @@ import { NodeType } from '@tmagic/schema';
15
15
  import ToolButton from '@editor/components/ToolButton.vue';
16
16
  import { ColumnLayout, MenuBarData, MenuButton, MenuComponent, MenuItem, Services } from '@editor/type';
17
17
 
18
+ defineOptions({
19
+ name: 'MEditorNavMenu',
20
+ });
21
+
18
22
  const props = withDefaults(
19
23
  defineProps<{
20
24
  data?: MenuBarData;
@@ -1,5 +1,5 @@
1
1
  <template>
2
- <div class="m-editor-props-panel">
2
+ <div class="m-editor-props-panel" v-show="nodes.length === 1">
3
3
  <slot name="props-panel-header"></slot>
4
4
  <MForm
5
5
  ref="configForm"
@@ -8,20 +8,29 @@
8
8
  :size="propsPanelSize"
9
9
  :init-values="values"
10
10
  :config="curFormConfig"
11
+ :extend-state="extendState"
11
12
  @change="submit"
12
13
  ></MForm>
13
14
  </div>
14
15
  </template>
15
16
 
16
- <script lang="ts" setup name="MEditorPropsPanel">
17
+ <script lang="ts" setup>
17
18
  import { computed, getCurrentInstance, inject, onMounted, onUnmounted, ref, watchEffect } from 'vue';
18
19
 
19
20
  import { tMagicMessage } from '@tmagic/design';
20
- import type { FormValue } from '@tmagic/form';
21
+ import type { FormState, FormValue } from '@tmagic/form';
21
22
  import { MForm } from '@tmagic/form';
22
23
 
23
24
  import type { Services } from '@editor/type';
24
25
 
26
+ defineOptions({
27
+ name: 'MEditorPropsPanel',
28
+ });
29
+
30
+ defineProps<{
31
+ extendState?: (state: FormState) => Record<string, any> | Promise<Record<string, any>>;
32
+ }>();
33
+
25
34
  const emit = defineEmits(['mounted']);
26
35
 
27
36
  const internalInstance = getCurrentInstance();
@@ -31,6 +40,7 @@ const configForm = ref<InstanceType<typeof MForm>>();
31
40
  const curFormConfig = ref<any>([]);
32
41
  const services = inject<Services>('services');
33
42
  const node = computed(() => services?.editorService.get('node'));
43
+ const nodes = computed(() => services?.editorService.get('nodes') || []);
34
44
  const propsPanelSize = computed(() => services?.uiService.get('propsPanelSize') || 'small');
35
45
  const stage = computed(() => services?.editorService.get('stage'));
36
46
 
@@ -73,5 +83,5 @@ const submit = async () => {
73
83
  }
74
84
  };
75
85
 
76
- defineExpose({ submit });
86
+ defineExpose({ configForm, submit });
77
87
  </script>
@@ -18,11 +18,9 @@
18
18
  @drag="dragHandler"
19
19
  >
20
20
  <slot name="component-list-item" :component="item">
21
- <MIcon :icon="item.icon"></MIcon>
21
+ <MIcon :title="item.text" :icon="item.icon"></MIcon>
22
22
 
23
- <TMagicTooltip effect="dark" placement="bottom" :content="item.text">
24
- <span>{{ item.text }}</span>
25
- </TMagicTooltip>
23
+ <span :title="item.text">{{ item.text }}</span>
26
24
  </slot>
27
25
  </div>
28
26
  </TMagicCollapseItem>
@@ -31,18 +29,22 @@
31
29
  </TMagicScrollbar>
32
30
  </template>
33
31
 
34
- <script lang="ts" setup name="MEditorComponentListPanel">
32
+ <script lang="ts" setup>
35
33
  import { computed, inject, ref } from 'vue';
36
34
  import { Grid } from '@element-plus/icons-vue';
37
35
  import serialize from 'serialize-javascript';
38
36
 
39
- import { TMagicCollapse, TMagicCollapseItem, TMagicScrollbar, TMagicTooltip } from '@tmagic/design';
37
+ import { TMagicCollapse, TMagicCollapseItem, TMagicScrollbar } from '@tmagic/design';
40
38
  import { removeClassNameByClassName } from '@tmagic/utils';
41
39
 
42
40
  import MIcon from '@editor/components/Icon.vue';
43
41
  import SearchInput from '@editor/components/SearchInput.vue';
44
42
  import type { ComponentGroup, ComponentItem, Services, StageOptions } from '@editor/type';
45
43
 
44
+ defineOptions({
45
+ name: 'MEditorComponentListPanel',
46
+ });
47
+
46
48
  const searchText = ref('');
47
49
 
48
50
  const filterTextChangeHandler = (v: string) => {
@@ -79,14 +81,13 @@ const appendComponent = ({ text, type, data = {} }: ComponentItem): void => {
79
81
 
80
82
  const dragstartHandler = ({ text, type, data = {} }: ComponentItem, e: DragEvent) => {
81
83
  if (e.dataTransfer) {
82
- e.dataTransfer.effectAllowed = 'move';
83
84
  e.dataTransfer.setData(
84
- 'data',
85
+ 'text/json',
85
86
  serialize({
86
87
  name: text,
87
88
  type,
88
89
  ...data,
89
- }).replace(/"(\w+)":\s/g, '$1: '),
90
+ }),
90
91
  );
91
92
  }
92
93
  };
@@ -117,6 +118,6 @@ const dragHandler = (e: DragEvent) => {
117
118
 
118
119
  if (timeout || !stage.value) return;
119
120
 
120
- timeout = stage.value.getAddContainerHighlightClassNameTimeout(e);
121
+ timeout = stage.value.delayedMarkContainer(e);
121
122
  };
122
123
  </script>
@@ -2,14 +2,17 @@
2
2
  <ContentMenu :menu-data="menuData" ref="menu" style="overflow: initial"></ContentMenu>
3
3
  </template>
4
4
 
5
- <script lang="ts" setup name="MEditorLayerMenu">
5
+ <script lang="ts" setup>
6
6
  import { computed, inject, markRaw, ref } from 'vue';
7
- import { CopyDocument, Delete, Files, Plus } from '@element-plus/icons-vue';
8
-
9
- import { NodeType } from '@tmagic/schema';
7
+ import { Files, Plus } from '@element-plus/icons-vue';
10
8
 
11
9
  import ContentMenu from '@editor/components/ContentMenu.vue';
12
10
  import type { ComponentGroup, MenuButton, MenuComponent, Services } from '@editor/type';
11
+ import { useCopyMenu, useDeleteMenu, useMoveToMenu, usePasteMenu } from '@editor/utils/content-menu';
12
+
13
+ defineOptions({
14
+ name: 'MEditorLayerMenu',
15
+ });
13
16
 
14
17
  const props = defineProps<{
15
18
  layerContentMenu: (MenuButton | MenuComponent)[];
@@ -18,8 +21,7 @@ const props = defineProps<{
18
21
  const services = inject<Services>('services');
19
22
  const menu = ref<InstanceType<typeof ContentMenu>>();
20
23
  const node = computed(() => services?.editorService.get('node'));
21
- const isRoot = computed(() => node.value?.type === NodeType.ROOT);
22
- const isPage = computed(() => node.value?.type === NodeType.PAGE);
24
+ const nodes = computed(() => services?.editorService.get('nodes'));
23
25
  const componentList = computed(() => services?.componentListService.getList() || []);
24
26
 
25
27
  const createMenuItems = (group: ComponentGroup): MenuButton[] =>
@@ -78,27 +80,13 @@ const menuData = computed<(MenuButton | MenuComponent)[]>(() => [
78
80
  type: 'button',
79
81
  text: '新增',
80
82
  icon: markRaw(Plus),
81
- display: () => node.value?.items,
83
+ display: () => node.value?.items && nodes.value?.length === 1,
82
84
  items: getSubMenuData.value,
83
85
  },
84
- {
85
- type: 'button',
86
- text: '复制',
87
- icon: markRaw(CopyDocument),
88
- display: () => !isRoot.value,
89
- handler: () => {
90
- node.value && services?.editorService.copy(node.value);
91
- },
92
- },
93
- {
94
- type: 'button',
95
- text: '删除',
96
- icon: markRaw(Delete),
97
- display: () => !isRoot.value && !isPage.value,
98
- handler: () => {
99
- node.value && services?.editorService.remove(node.value);
100
- },
101
- },
86
+ useCopyMenu(),
87
+ usePasteMenu(),
88
+ useDeleteMenu(),
89
+ useMoveToMenu(services),
102
90
  ...props.layerContentMenu,
103
91
  ]);
104
92