@tmagic/editor 1.3.0-alpha.1 → 1.3.0-alpha.11

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 (124) hide show
  1. package/dist/style.css +46 -9
  2. package/dist/tmagic-editor.js +1764 -871
  3. package/dist/tmagic-editor.js.map +1 -1
  4. package/dist/tmagic-editor.umd.cjs +1780 -882
  5. package/dist/tmagic-editor.umd.cjs.map +1 -1
  6. package/package.json +19 -20
  7. package/src/Editor.vue +29 -3
  8. package/src/components/CodeDraftEditor.vue +5 -1
  9. package/src/components/ContentMenu.vue +30 -11
  10. package/src/components/FunctionEditor.vue +12 -5
  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 +5 -1
  19. package/src/fields/Code.vue +5 -1
  20. package/src/fields/CodeLink.vue +9 -3
  21. package/src/fields/CodeSelect.vue +8 -2
  22. package/src/fields/CodeSelectCol.vue +6 -2
  23. package/src/fields/DataSourceFields.vue +5 -1
  24. package/src/fields/DataSourceInput.vue +358 -0
  25. package/src/fields/DataSourceSelect.vue +75 -0
  26. package/src/fields/EventSelect.vue +9 -3
  27. package/src/fields/KeyValue.vue +4 -0
  28. package/src/fields/UISelect.vue +5 -1
  29. package/src/icons/AppManageIcon.vue +5 -1
  30. package/src/icons/CenterIcon.vue +13 -0
  31. package/src/icons/CodeIcon.vue +5 -1
  32. package/src/index.ts +12 -3
  33. package/src/initService.ts +73 -0
  34. package/src/layouts/AddPageBox.vue +5 -1
  35. package/src/layouts/CodeEditor.vue +34 -10
  36. package/src/layouts/Framework.vue +25 -25
  37. package/src/layouts/NavMenu.vue +5 -1
  38. package/src/layouts/PropsPanel.vue +14 -4
  39. package/src/layouts/sidebar/ComponentListPanel.vue +8 -5
  40. package/src/layouts/sidebar/LayerMenu.vue +13 -25
  41. package/src/layouts/sidebar/LayerNode.vue +40 -0
  42. package/src/layouts/sidebar/LayerPanel.vue +70 -27
  43. package/src/layouts/sidebar/Sidebar.vue +11 -7
  44. package/src/layouts/sidebar/code-block/CodeBlockEditor.vue +8 -4
  45. package/src/layouts/sidebar/code-block/CodeBlockList.vue +5 -1
  46. package/src/layouts/sidebar/data-source/DataSourceConfigPanel.vue +4 -0
  47. package/src/layouts/sidebar/data-source/DataSourceListPanel.vue +22 -2
  48. package/src/layouts/workspace/Breadcrumb.vue +5 -1
  49. package/src/layouts/workspace/PageBar.vue +5 -1
  50. package/src/layouts/workspace/PageBarScrollContainer.vue +5 -1
  51. package/src/layouts/workspace/Stage.vue +29 -7
  52. package/src/layouts/workspace/ViewerMenu.vue +15 -36
  53. package/src/layouts/workspace/Workspace.vue +9 -134
  54. package/src/services/codeBlock.ts +3 -2
  55. package/src/services/dep.ts +4 -0
  56. package/src/services/keybinding.ts +185 -0
  57. package/src/services/storage.ts +3 -2
  58. package/src/theme/content-menu.scss +1 -1
  59. package/src/theme/data-source-input.scss +18 -0
  60. package/src/theme/framework.scss +0 -3
  61. package/src/theme/layer-panel.scss +6 -0
  62. package/src/theme/layout.scss +4 -0
  63. package/src/theme/resizer.scss +25 -10
  64. package/src/theme/stage.scss +4 -0
  65. package/src/theme/theme.scss +1 -0
  66. package/src/type.ts +59 -1
  67. package/src/utils/config.ts +1 -1
  68. package/src/utils/content-menu.ts +92 -0
  69. package/src/utils/dep.ts +7 -1
  70. package/src/utils/keybinding-config.ts +120 -0
  71. package/src/utils/props.ts +34 -0
  72. package/types/Editor.vue.d.ts +7 -1
  73. package/types/components/CodeDraftEditor.vue.d.ts +6 -3
  74. package/types/components/ContentMenu.vue.d.ts +10 -5
  75. package/types/components/FunctionEditor.vue.d.ts +74 -51
  76. package/types/components/Icon.vue.d.ts +2 -2
  77. package/types/{layouts → components}/Resizer.vue.d.ts +2 -2
  78. package/types/components/ScrollBar.vue.d.ts +1 -1
  79. package/types/components/ScrollViewer.vue.d.ts +8 -5
  80. package/types/components/SearchInput.vue.d.ts +1 -1
  81. package/types/components/{Layout.vue.d.ts → SplitView.vue.d.ts} +9 -6
  82. package/types/components/ToolButton.vue.d.ts +8 -5
  83. package/types/editorProps.d.ts +4 -1
  84. package/types/fields/Code.vue.d.ts +1 -1
  85. package/types/fields/CodeLink.vue.d.ts +9 -9
  86. package/types/fields/CodeSelect.vue.d.ts +10 -7
  87. package/types/fields/CodeSelectCol.vue.d.ts +8 -5
  88. package/types/fields/DataSourceFields.vue.d.ts +8 -5
  89. package/types/fields/DataSourceInput.vue.d.ts +54 -0
  90. package/types/fields/DataSourceSelect.vue.d.ts +56 -0
  91. package/types/fields/EventSelect.vue.d.ts +3 -3
  92. package/types/fields/KeyValue.vue.d.ts +8 -5
  93. package/types/fields/UISelect.vue.d.ts +1 -1
  94. package/types/icons/AppManageIcon.vue.d.ts +1 -1
  95. package/types/icons/CenterIcon.vue.d.ts +2 -0
  96. package/types/icons/CodeIcon.vue.d.ts +1 -1
  97. package/types/index.d.ts +6 -2
  98. package/types/initService.d.ts +1 -1
  99. package/types/layouts/AddPageBox.vue.d.ts +1 -1
  100. package/types/layouts/CodeEditor.vue.d.ts +16 -10
  101. package/types/layouts/Framework.vue.d.ts +11 -32
  102. package/types/layouts/NavMenu.vue.d.ts +7 -4
  103. package/types/layouts/PropsPanel.vue.d.ts +276 -4
  104. package/types/layouts/sidebar/ComponentListPanel.vue.d.ts +4 -4
  105. package/types/layouts/sidebar/LayerMenu.vue.d.ts +2 -2
  106. package/types/layouts/sidebar/LayerNode.vue.d.ts +16 -0
  107. package/types/layouts/sidebar/LayerPanel.vue.d.ts +5 -5
  108. package/types/layouts/sidebar/Sidebar.vue.d.ts +18 -15
  109. package/types/layouts/sidebar/code-block/CodeBlockEditor.vue.d.ts +4 -4
  110. package/types/layouts/sidebar/code-block/CodeBlockList.vue.d.ts +7 -7
  111. package/types/layouts/sidebar/data-source/DataSourceConfigPanel.vue.d.ts +1 -1
  112. package/types/layouts/sidebar/data-source/DataSourceListPanel.vue.d.ts +3 -3
  113. package/types/layouts/workspace/Breadcrumb.vue.d.ts +1 -1
  114. package/types/layouts/workspace/PageBar.vue.d.ts +5 -5
  115. package/types/layouts/workspace/PageBarScrollContainer.vue.d.ts +2 -2
  116. package/types/layouts/workspace/Stage.vue.d.ts +2 -2
  117. package/types/layouts/workspace/ViewerMenu.vue.d.ts +7 -4
  118. package/types/layouts/workspace/Workspace.vue.d.ts +9 -9
  119. package/types/services/keybinding.d.ts +20 -0
  120. package/types/type.d.ts +56 -1
  121. package/types/utils/config.d.ts +1 -1
  122. package/types/utils/content-menu.d.ts +7 -0
  123. package/types/utils/keybinding-config.d.ts +3 -0
  124. package/src/layouts/Resizer.vue +0 -32
@@ -1,8 +1,10 @@
1
1
  import type { ExtractPropTypes } from 'vue';
2
2
  import { onUnmounted, toRaw, watch } from 'vue';
3
+ import { cloneDeep } from 'lodash-es';
3
4
 
4
5
  import type { EventOption } from '@tmagic/core';
5
6
  import type { CodeBlockContent, DataSourceSchema, Id, MApp, MNode, MPage } from '@tmagic/schema';
7
+ import { getNodes } from '@tmagic/utils';
6
8
 
7
9
  import type { Target } from './services/dep';
8
10
  import { createCodeBlockTarget, createDataSourceTarget } from './utils/dep';
@@ -23,6 +25,7 @@ export const initServiceState = (
23
25
  eventsService,
24
26
  uiService,
25
27
  codeBlockService,
28
+ keybindingService,
26
29
  }: Services,
27
30
  ) => {
28
31
  // 初始值变化,重新设置节点信息
@@ -102,6 +105,7 @@ export const initServiceState = (
102
105
  uiService.resetState();
103
106
  componentListService.resetState();
104
107
  codeBlockService.resetState();
108
+ keybindingService.reset();
105
109
  });
106
110
  };
107
111
 
@@ -110,6 +114,50 @@ export const initServiceEvents = (
110
114
  emit: (event: 'props-panel-mounted' | 'update:modelValue', ...args: any[]) => void,
111
115
  { editorService, codeBlockService, dataSourceService, depService }: Services,
112
116
  ) => {
117
+ const getApp = () => {
118
+ const stage = editorService.get('stage');
119
+ return stage?.renderer.runtime?.getApp?.();
120
+ };
121
+
122
+ const updateDataSoucreSchema = () => {
123
+ const root = editorService.get('root');
124
+
125
+ if (root?.dataSources) {
126
+ getApp()?.dataSourceManager?.updateSchema(root.dataSources);
127
+ }
128
+ };
129
+
130
+ const upateNodeWhenDataSourceChange = (nodes: MNode[]) => {
131
+ const root = editorService.get('root');
132
+ const stage = editorService.get('stage');
133
+
134
+ if (!root || !stage) return;
135
+
136
+ const app = getApp();
137
+
138
+ if (!app) return;
139
+
140
+ if (app.dsl) {
141
+ app.dsl.dataSourceDeps = root.dataSourceDeps;
142
+ app.dsl.dataSources = root.dataSources;
143
+ }
144
+
145
+ updateDataSoucreSchema();
146
+
147
+ nodes.forEach((node) => {
148
+ const deps = Object.values(root.dataSourceDeps || {});
149
+ deps.forEach((dep) => {
150
+ if (dep[node.id]) {
151
+ stage.update({
152
+ config: cloneDeep(node),
153
+ parentId: editorService.getParentById(node.id)?.id,
154
+ root: cloneDeep(root),
155
+ });
156
+ }
157
+ });
158
+ });
159
+ };
160
+
113
161
  const targetAddHandler = (target: Target) => {
114
162
  if (target.type !== 'data-source') return;
115
163
 
@@ -130,8 +178,18 @@ export const initServiceEvents = (
130
178
  delete root.dataSourceDeps[id];
131
179
  };
132
180
 
181
+ const depUpdateHandler = (node: MNode) => {
182
+ upateNodeWhenDataSourceChange([node]);
183
+ };
184
+
185
+ const collectedHandler = (nodes: MNode[]) => {
186
+ upateNodeWhenDataSourceChange(nodes);
187
+ };
188
+
133
189
  depService.on('add-target', targetAddHandler);
134
190
  depService.on('remove-target', targetRemoveHandler);
191
+ depService.on('dep-update', depUpdateHandler);
192
+ depService.on('collected', collectedHandler);
135
193
 
136
194
  const rootChangeHandler = async (value: MApp, preValue?: MApp | null) => {
137
195
  const nodeId = editorService.get('node')?.id || props.defaultSelected;
@@ -178,18 +236,22 @@ export const initServiceEvents = (
178
236
  }
179
237
  };
180
238
 
239
+ // 新增节点,收集依赖
181
240
  const nodeAddHandler = (nodes: MNode[]) => {
182
241
  depService.collect(nodes);
183
242
  };
184
243
 
244
+ // 节点更新,收集依赖
185
245
  const nodeUpdateHandler = (nodes: MNode[]) => {
186
246
  depService.collect(nodes);
187
247
  };
188
248
 
249
+ // 节点删除,清除对齐的依赖收集
189
250
  const nodeRemoveHandler = (nodes: MNode[]) => {
190
251
  depService.clear(nodes);
191
252
  };
192
253
 
254
+ // 由于历史记录变化是更新整个page,所以历史记录变化时,需要重新收集依赖
193
255
  const historyChangeHandler = (page: MPage) => {
194
256
  depService.collect([page], true);
195
257
  };
@@ -218,16 +280,25 @@ export const initServiceEvents = (
218
280
 
219
281
  const dataSourceAddHandler = (config: DataSourceSchema) => {
220
282
  depService.addTarget(createDataSourceTarget(config.id, config));
283
+ getApp()?.dataSourceManager?.addDataSource(config);
221
284
  };
222
285
 
223
286
  const dataSourceUpdateHandler = (config: DataSourceSchema) => {
224
287
  if (config.title) {
225
288
  depService.getTarget(config.id)!.name = config.title;
226
289
  }
290
+ const root = editorService.get('root');
291
+
292
+ const targets = depService.getTargets('data-source');
293
+
294
+ const nodes = getNodes(Object.keys(targets[config.id].deps), root?.items);
295
+
296
+ upateNodeWhenDataSourceChange(nodes);
227
297
  };
228
298
 
229
299
  const dataSourceRemoveHandler = (id: string) => {
230
300
  depService.removeTarget(id);
301
+ getApp()?.dataSourceManager?.removeDataSource(id);
231
302
  };
232
303
 
233
304
  dataSourceService.on('add', dataSourceAddHandler);
@@ -237,6 +308,8 @@ export const initServiceEvents = (
237
308
  onUnmounted(() => {
238
309
  depService.off('add-target', targetAddHandler);
239
310
  depService.off('remove-target', targetRemoveHandler);
311
+ depService.off('dep-update', depUpdateHandler);
312
+ depService.off('collected', collectedHandler);
240
313
 
241
314
  editorService.off('history-change', historyChangeHandler);
242
315
  editorService.off('root-change', rootChangeHandler);
@@ -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 = () => {
@@ -2,16 +2,20 @@
2
2
  <div ref="codeEditor" class="magic-code-editor"></div>
3
3
  </template>
4
4
 
5
- <script lang="ts" setup name="MEditorCodeEditor">
5
+ <script lang="ts" setup>
6
6
  import { onMounted, onUnmounted, ref, watch } from 'vue';
7
7
  import { throttle } from 'lodash-es';
8
8
  import * as monaco from 'monaco-editor';
9
9
  import serialize from 'serialize-javascript';
10
10
 
11
+ defineOptions({
12
+ name: 'MEditorCodeEditor',
13
+ });
14
+
11
15
  const props = withDefaults(
12
16
  defineProps<{
13
- initValues?: string | Object;
14
- modifiedValues?: string | Object;
17
+ initValues?: string | Record<string | number, any> | null;
18
+ modifiedValues?: string | Record<string | number, any> | null;
15
19
  type?: 'diff';
16
20
  language?: string;
17
21
  options?: {
@@ -33,10 +37,14 @@ const emit = defineEmits(['initd', 'save']);
33
37
  const toString = (v: string | any, language: string): string => {
34
38
  let value = '';
35
39
  if (typeof v !== 'string') {
36
- value = serialize(v, {
37
- space: 2,
38
- unsafe: true,
39
- }).replace(/"(\w+)":\s/g, '$1: ');
40
+ if (props.language.toLocaleLowerCase() === 'json') {
41
+ value = JSON.stringify(v, null, 2);
42
+ } else {
43
+ value = serialize(v, {
44
+ space: 2,
45
+ unsafe: true,
46
+ }).replace(/"(\w+)":\s/g, '$1: ');
47
+ }
40
48
  } else {
41
49
  value = v;
42
50
  }
@@ -77,7 +85,7 @@ const setEditorValue = (v: string | any, m: string | any) => {
77
85
  };
78
86
 
79
87
  const getEditorValue = () =>
80
- props.type === 'diff' ? vsDiffEditor?.getModifiedEditor().getValue() : vsEditor?.getValue();
88
+ (props.type === 'diff' ? vsDiffEditor?.getModifiedEditor().getValue() : vsEditor?.getValue()) || '';
81
89
 
82
90
  const init = async () => {
83
91
  if (!codeEditor.value) return;
@@ -105,13 +113,19 @@ const init = async () => {
105
113
  if (e.keyCode === 83 && (navigator.platform.match('Mac') ? e.metaKey : e.ctrlKey)) {
106
114
  e.preventDefault();
107
115
  e.stopPropagation();
108
- emit('save', getEditorValue());
116
+ const newValue = getEditorValue();
117
+ values.value = newValue;
118
+ emit('save', newValue);
109
119
  }
110
120
  });
111
121
 
112
122
  if (props.type !== 'diff' && props.autoSave) {
113
123
  vsEditor?.onDidBlurEditorWidget(() => {
114
- emit('save', getEditorValue());
124
+ const newValue = getEditorValue();
125
+ if (values.value !== newValue) {
126
+ values.value = newValue;
127
+ emit('save', newValue);
128
+ }
115
129
  });
116
130
  }
117
131
 
@@ -142,10 +156,20 @@ onUnmounted(() => {
142
156
  });
143
157
 
144
158
  defineExpose({
159
+ values,
160
+
145
161
  getEditor() {
146
162
  return vsEditor || vsDiffEditor;
147
163
  },
148
164
 
165
+ getVsEditor() {
166
+ return vsEditor;
167
+ },
168
+
169
+ getVsDiffEditor() {
170
+ return vsDiffEditor;
171
+ },
172
+
149
173
  setEditorValue,
150
174
 
151
175
  focus() {
@@ -1,16 +1,16 @@
1
1
  <template>
2
2
  <div class="m-editor">
3
- <slot name="nav" class="m-editor-nav-menu"></slot>
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,41 @@
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
 
69
70
  const root = computed(() => editorService?.get('root'));
70
- const nodes = computed(() => editorService?.get('nodes') || []);
71
71
 
72
72
  const pageLength = computed(() => editorService?.get('pageLength') || 0);
73
73
  const showSrc = computed(() => uiService?.get('showSrc'));
@@ -131,8 +131,8 @@ const columnWidthChange = (columnW: GetColumnWidth) => {
131
131
 
132
132
  const saveCode = (value: string) => {
133
133
  try {
134
- // eslint-disable-next-line no-eval
135
- editorService?.set('root', eval(value));
134
+ const parseDSL = getConfig('parseDSL');
135
+ editorService?.set('root', parseDSL(value));
136
136
  } catch (e: any) {
137
137
  console.error(e);
138
138
  }
@@ -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>
@@ -31,7 +31,7 @@
31
31
  </TMagicScrollbar>
32
32
  </template>
33
33
 
34
- <script lang="ts" setup name="MEditorComponentListPanel">
34
+ <script lang="ts" setup>
35
35
  import { computed, inject, ref } from 'vue';
36
36
  import { Grid } from '@element-plus/icons-vue';
37
37
  import serialize from 'serialize-javascript';
@@ -43,6 +43,10 @@ import MIcon from '@editor/components/Icon.vue';
43
43
  import SearchInput from '@editor/components/SearchInput.vue';
44
44
  import type { ComponentGroup, ComponentItem, Services, StageOptions } from '@editor/type';
45
45
 
46
+ defineOptions({
47
+ name: 'MEditorComponentListPanel',
48
+ });
49
+
46
50
  const searchText = ref('');
47
51
 
48
52
  const filterTextChangeHandler = (v: string) => {
@@ -79,14 +83,13 @@ const appendComponent = ({ text, type, data = {} }: ComponentItem): void => {
79
83
 
80
84
  const dragstartHandler = ({ text, type, data = {} }: ComponentItem, e: DragEvent) => {
81
85
  if (e.dataTransfer) {
82
- e.dataTransfer.effectAllowed = 'move';
83
86
  e.dataTransfer.setData(
84
- 'data',
87
+ 'text/html',
85
88
  serialize({
86
89
  name: text,
87
90
  type,
88
91
  ...data,
89
- }).replace(/"(\w+)":\s/g, '$1: '),
92
+ }),
90
93
  );
91
94
  }
92
95
  };
@@ -117,6 +120,6 @@ const dragHandler = (e: DragEvent) => {
117
120
 
118
121
  if (timeout || !stage.value) return;
119
122
 
120
- timeout = stage.value.getAddContainerHighlightClassNameTimeout(e);
123
+ timeout = stage.value.delayedMarkContainer(e);
121
124
  };
122
125
  </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
 
@@ -0,0 +1,40 @@
1
+ <template>
2
+ <div>
3
+ {{ `${data.name} (${data.id})` }}
4
+ </div>
5
+ <div class="layer-node-tool">
6
+ <template v-if="data.type !== 'page'">
7
+ <el-icon v-if="data.visible === false" @click.stop="setNodeVisible(true)" title="点击显示">
8
+ <Hide />
9
+ </el-icon>
10
+ <el-icon v-else @click.stop="setNodeVisible(false)" class="node-lock" title="点击隐藏">
11
+ <View />
12
+ </el-icon>
13
+ </template>
14
+ </div>
15
+ </template>
16
+
17
+ <script lang="ts" setup>
18
+ import { inject } from 'vue';
19
+ import { Hide, View } from '@element-plus/icons-vue';
20
+
21
+ import { MNode } from '@tmagic/schema';
22
+
23
+ import { Services } from '@editor/type';
24
+
25
+ const props = defineProps<{
26
+ data: MNode;
27
+ }>();
28
+
29
+ const services = inject<Services>('services');
30
+ const editorService = services?.editorService;
31
+
32
+ const setNodeVisible = (visible: boolean) => {
33
+ if (!editorService) return;
34
+
35
+ editorService.update({
36
+ id: props.data.id,
37
+ visible,
38
+ });
39
+ };
40
+ </script>