@tmagic/editor 1.0.0-beta.13 → 1.0.0-beta.16

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 (101) hide show
  1. package/coverage/clover.xml +703 -601
  2. package/coverage/coverage-final.json +35 -33
  3. package/coverage/lcov-report/index.html +56 -56
  4. package/coverage/lcov-report/src/Editor.vue.html +1 -1
  5. package/coverage/lcov-report/{layouts/sidebar/LayerMenu.vue.html → src/components/ContentMenu.vue.html} +137 -95
  6. package/coverage/lcov-report/src/components/Icon.vue.html +5 -5
  7. package/coverage/lcov-report/src/components/ScrollViewer.vue.html +1 -1
  8. package/coverage/lcov-report/src/components/ToolButton.vue.html +180 -63
  9. package/coverage/lcov-report/src/components/index.html +34 -19
  10. package/coverage/lcov-report/src/index.html +1 -1
  11. package/coverage/lcov-report/src/layouts/AddPageBox.vue.html +1 -1
  12. package/coverage/lcov-report/src/layouts/Framework.vue.html +13 -13
  13. package/coverage/lcov-report/src/layouts/NavMenu.vue.html +1 -1
  14. package/coverage/lcov-report/src/layouts/PropsPanel.vue.html +1 -1
  15. package/coverage/lcov-report/src/layouts/Resizer.vue.html +1 -1
  16. package/coverage/lcov-report/src/layouts/index.html +15 -15
  17. package/coverage/lcov-report/src/layouts/sidebar/ComponentListPanel.vue.html +78 -12
  18. package/coverage/lcov-report/src/layouts/sidebar/LayerMenu.vue.html +149 -92
  19. package/coverage/lcov-report/src/layouts/sidebar/LayerPanel.vue.html +43 -121
  20. package/coverage/lcov-report/src/layouts/sidebar/Sidebar.vue.html +23 -140
  21. package/coverage/lcov-report/{utils/undo-redo.ts.html → src/layouts/sidebar/TabPane.vue.html} +94 -118
  22. package/coverage/lcov-report/src/layouts/sidebar/index.html +64 -49
  23. package/coverage/lcov-report/src/layouts/workspace/PageBar.vue.html +99 -12
  24. package/coverage/lcov-report/src/layouts/workspace/Stage.vue.html +86 -95
  25. package/coverage/lcov-report/src/layouts/workspace/ViewerMenu.vue.html +208 -97
  26. package/coverage/lcov-report/src/layouts/workspace/Workspace.vue.html +3 -3
  27. package/coverage/lcov-report/src/layouts/workspace/index.html +35 -35
  28. package/coverage/lcov-report/src/services/BaseService.ts.html +11 -11
  29. package/coverage/lcov-report/src/services/componentList.ts.html +1 -1
  30. package/coverage/lcov-report/src/services/editor.ts.html +103 -10
  31. package/coverage/lcov-report/src/services/events.ts.html +1 -1
  32. package/coverage/lcov-report/src/services/history.ts.html +29 -8
  33. package/coverage/lcov-report/src/services/index.html +25 -25
  34. package/coverage/lcov-report/src/services/props.ts.html +4 -7
  35. package/coverage/lcov-report/src/services/ui.ts.html +1 -1
  36. package/coverage/lcov-report/src/type.ts.html +8 -14
  37. package/coverage/lcov-report/src/utils/compose.ts.html +4 -4
  38. package/coverage/lcov-report/src/utils/config.ts.html +1 -1
  39. package/coverage/lcov-report/src/utils/editor.ts.html +2 -2
  40. package/coverage/lcov-report/src/utils/index.html +1 -1
  41. package/coverage/lcov-report/src/utils/index.ts.html +1 -1
  42. package/coverage/lcov-report/src/utils/logger.ts.html +1 -1
  43. package/coverage/lcov-report/src/utils/props.ts.html +59 -2
  44. package/coverage/lcov-report/src/utils/scroll-viewer.ts.html +1 -1
  45. package/coverage/lcov-report/src/utils/undo-redo.ts.html +1 -1
  46. package/coverage/lcov.info +1679 -1402
  47. package/dist/style.css +47 -20
  48. package/dist/tmagic-editor.es.js +732 -485
  49. package/dist/tmagic-editor.es.js.map +1 -1
  50. package/dist/tmagic-editor.umd.js +733 -485
  51. package/dist/tmagic-editor.umd.js.map +1 -1
  52. package/dist/types/src/Editor.vue.d.ts +1 -1
  53. package/dist/types/src/components/ToolButton.vue.d.ts +12 -1
  54. package/dist/types/src/fields/UISelect.vue.d.ts +4 -1
  55. package/dist/types/src/index.d.ts +1 -0
  56. package/dist/types/src/layouts/CodeEditor.vue.d.ts +13 -4
  57. package/dist/types/src/layouts/sidebar/ComponentListPanel.vue.d.ts +1 -0
  58. package/dist/types/src/layouts/sidebar/Sidebar.vue.d.ts +2 -3
  59. package/dist/types/src/layouts/sidebar/TabPane.vue.d.ts +14 -0
  60. package/dist/types/src/layouts/workspace/PageBar.vue.d.ts +2 -0
  61. package/dist/types/src/services/history.d.ts +1 -0
  62. package/dist/types/src/services/props.d.ts +2 -2
  63. package/dist/types/src/type.d.ts +6 -8
  64. package/dist/types/src/utils/polyfills.d.ts +0 -0
  65. package/package.json +15 -10
  66. package/src/components/ContentMenu.vue +107 -0
  67. package/src/components/ToolButton.vue +66 -27
  68. package/src/fields/UISelect.vue +14 -6
  69. package/src/index.ts +2 -0
  70. package/src/layouts/CodeEditor.vue +20 -10
  71. package/src/layouts/Framework.vue +6 -6
  72. package/src/layouts/sidebar/ComponentListPanel.vue +23 -1
  73. package/src/layouts/sidebar/LayerMenu.vue +91 -72
  74. package/src/layouts/sidebar/LayerPanel.vue +23 -49
  75. package/src/layouts/sidebar/Sidebar.vue +13 -52
  76. package/src/layouts/sidebar/TabPane.vue +68 -0
  77. package/src/layouts/workspace/PageBar.vue +35 -6
  78. package/src/layouts/workspace/Stage.vue +41 -44
  79. package/src/layouts/workspace/ViewerMenu.vue +104 -67
  80. package/src/layouts/workspace/Workspace.vue +2 -2
  81. package/src/services/editor.ts +33 -2
  82. package/src/services/history.ts +7 -0
  83. package/src/services/props.ts +2 -3
  84. package/src/theme/common/var.scss +1 -0
  85. package/src/theme/component-list-panel.scss +2 -0
  86. package/src/theme/content-menu.scss +33 -26
  87. package/src/theme/layer-panel.scss +1 -1
  88. package/src/theme/nav-menu.scss +6 -2
  89. package/src/theme/page-bar.scss +22 -1
  90. package/src/theme/props-panel.scss +4 -0
  91. package/src/type.ts +6 -8
  92. package/src/utils/editor.ts +1 -1
  93. package/src/utils/polyfills.ts +22 -0
  94. package/src/utils/props.ts +19 -0
  95. package/coverage/lcov-report/Icon.vue.html +0 -172
  96. package/coverage/lcov-report/ToolButton.vue.html +0 -655
  97. package/coverage/lcov-report/layouts/sidebar/index.html +0 -116
  98. package/coverage/lcov-report/utils/index.html +0 -116
  99. package/dist/types/src/layouts/sidebar/LayerPanel.vue.d.ts +0 -980
  100. package/dist/types/src/layouts/workspace/Stage.vue.d.ts +0 -188
  101. package/dist/types/src/layouts/workspace/ViewerMenu.vue.d.ts +0 -18
@@ -4,6 +4,7 @@
4
4
 
5
5
  <script lang="ts">
6
6
  import { defineComponent, onMounted, onUnmounted, ref, watch } from 'vue';
7
+ import { throttle } from 'lodash-es';
7
8
  import * as monaco from 'monaco-editor';
8
9
  import serialize from 'serialize-javascript';
9
10
 
@@ -36,14 +37,19 @@ export default defineComponent({
36
37
  },
37
38
 
38
39
  type: {
39
- type: [String],
40
+ type: String,
40
41
  default: () => '',
41
42
  },
42
43
 
43
44
  language: {
44
- type: [String],
45
+ type: String,
45
46
  default: () => 'javascript',
46
47
  },
48
+
49
+ options: {
50
+ type: Object,
51
+ default: () => ({}),
52
+ },
47
53
  },
48
54
 
49
55
  emits: ['initd', 'save'],
@@ -51,10 +57,18 @@ export default defineComponent({
51
57
  setup(props, { emit }) {
52
58
  let vsEditor: monaco.editor.IStandaloneCodeEditor | null = null;
53
59
  let vsDiffEditor: monaco.editor.IStandaloneDiffEditor | null = null;
60
+
54
61
  const values = ref('');
55
62
  const loading = ref(false);
56
63
  const codeEditor = ref<HTMLDivElement>();
57
64
 
65
+ const resizeObserver = new globalThis.ResizeObserver(
66
+ throttle((): void => {
67
+ vsEditor?.layout();
68
+ vsDiffEditor?.layout();
69
+ }, 300),
70
+ );
71
+
58
72
  const setEditorValue = (v: string | any, m: string | any) => {
59
73
  values.value = toString(v, props.language);
60
74
 
@@ -71,11 +85,6 @@ export default defineComponent({
71
85
  return vsEditor?.setValue(values.value);
72
86
  };
73
87
 
74
- const resizeHandler = () => {
75
- vsEditor?.layout();
76
- vsDiffEditor?.layout();
77
- };
78
-
79
88
  const getEditorValue = () =>
80
89
  props.type === 'diff' ? vsDiffEditor?.getModifiedEditor().getValue() : vsEditor?.getValue();
81
90
 
@@ -88,8 +97,9 @@ export default defineComponent({
88
97
  tabSize: 2,
89
98
  theme: 'vs-dark',
90
99
  fontFamily: 'dm, Menlo, Monaco, "Courier New", monospace',
91
- fontSize: 15,
100
+ fontSize: 14,
92
101
  formatOnPaste: true,
102
+ ...props.options,
93
103
  };
94
104
 
95
105
  if (props.type === 'diff') {
@@ -117,7 +127,7 @@ export default defineComponent({
117
127
  });
118
128
  }
119
129
 
120
- globalThis.addEventListener('resize', resizeHandler);
130
+ resizeObserver.observe(codeEditor.value);
121
131
  };
122
132
 
123
133
  watch(
@@ -140,7 +150,7 @@ export default defineComponent({
140
150
  });
141
151
 
142
152
  onUnmounted(() => {
143
- globalThis.removeEventListener('resize', resizeHandler);
153
+ resizeObserver.disconnect();
144
154
  });
145
155
 
146
156
  return {
@@ -49,20 +49,20 @@ export default defineComponent({
49
49
  },
50
50
 
51
51
  setup() {
52
- const services = inject<Services>('services');
52
+ const { editorService, uiService } = inject<Services>('services') || {};
53
53
 
54
- const root = computed(() => services?.editorService.get<MApp>('root'));
54
+ const root = computed(() => editorService?.get<MApp>('root'));
55
55
 
56
56
  return {
57
57
  root,
58
- pageLength: computed(() => root.value?.items?.length || 0),
59
- showSrc: computed(() => services?.uiService.get<boolean>('showSrc')),
60
- columnWidth: computed(() => services?.uiService.get<GetColumnWidth>('columnWidth')),
58
+ pageLength: computed(() => editorService?.get<number>('pageLength') || 0),
59
+ showSrc: computed(() => uiService?.get<boolean>('showSrc')),
60
+ columnWidth: computed(() => uiService?.get<GetColumnWidth>('columnWidth')),
61
61
 
62
62
  saveCode(value: string) {
63
63
  try {
64
64
  // eslint-disable-next-line no-eval
65
- services?.editorService.set('root', eval(value));
65
+ editorService?.set('root', eval(value));
66
66
  } catch (e: any) {
67
67
  console.error(e);
68
68
  }
@@ -12,7 +12,14 @@
12
12
  <template v-for="(group, index) in list">
13
13
  <el-collapse-item v-if="group.items && group.items.length" :key="index" :name="index">
14
14
  <template #title><i class="el-icon-s-grid"></i>{{ group.title }}</template>
15
- <div class="component-item" v-for="item in group.items" :key="item.type" @click="appendComponent(item)">
15
+ <div
16
+ class="component-item"
17
+ v-for="item in group.items"
18
+ draggable="true"
19
+ :key="item.type"
20
+ @click="appendComponent(item)"
21
+ @dragstart="dragstartHandler(item, $event)"
22
+ >
16
23
  <m-icon :icon="item.icon"></m-icon>
17
24
 
18
25
  <el-tooltip effect="dark" placement="bottom" :content="item.text">
@@ -27,6 +34,7 @@
27
34
 
28
35
  <script lang="ts">
29
36
  import { computed, defineComponent, inject, ref } from 'vue';
37
+ import serialize from 'serialize-javascript';
30
38
 
31
39
  import MIcon from '@editor/components/Icon.vue';
32
40
  import type { ComponentGroup, ComponentItem, Services } from '@editor/type';
@@ -63,6 +71,20 @@ export default defineComponent({
63
71
  ...data,
64
72
  });
65
73
  },
74
+
75
+ dragstartHandler({ text, type, data = {} }: ComponentItem, e: DragEvent) {
76
+ if (e.dataTransfer) {
77
+ e.dataTransfer.effectAllowed = 'move';
78
+ e.dataTransfer.setData(
79
+ 'data',
80
+ serialize({
81
+ name: text,
82
+ type,
83
+ ...data,
84
+ }).replace(/"(\w+)":\s/g, '$1: '),
85
+ );
86
+ }
87
+ },
66
88
  };
67
89
  },
68
90
  });
@@ -1,91 +1,110 @@
1
1
  <template>
2
- <div v-if="node" class="magic-editor-content-menu">
3
- <div
4
- v-if="node.items"
5
- class="magic-editor-content-menu-item"
6
- @mouseenter="setSubVisitable(true)"
7
- @mouseleave="setSubVisitable(false)"
8
- >
9
- 新增
10
- </div>
11
- <div v-if="node.type !== 'app'" class="magic-editor-content-menu-item" @click="() => copy(node)">复制</div>
12
- <div
13
- v-if="node.type !== 'app' && node.type !== 'page'"
14
- class="magic-editor-content-menu-item"
15
- @click="() => remove()"
16
- >
17
- 删除
18
- </div>
19
- <div class="subMenu" v-show="subVisible" @mouseenter="setSubVisitable(true)" @mouseleave="setSubVisitable(false)">
20
- <el-scrollbar>
21
- <template v-if="node.type === 'tabs'">
22
- <div
23
- class="magic-editor-content-menu-item"
24
- @click="
25
- () =>
26
- append({
27
- type: 'tab-pane',
28
- })
29
- "
30
- >
31
- 标签
32
- </div>
33
- </template>
34
- <template v-else-if="node.items">
35
- <div v-for="list in componentGroupList" :key="list.title">
36
- <template v-for="item in list.items">
37
- <div class="magic-editor-content-menu-item" v-if="item" :key="item.type" @click="() => append(item)">
38
- {{ item.text }}
39
- </div>
40
- </template>
41
- <div class="separation"></div>
42
- </div>
43
- </template>
44
- </el-scrollbar>
45
- </div>
46
- </div>
2
+ <content-menu :menu-data="menuData" ref="menu" style="overflow: initial"></content-menu>
47
3
  </template>
48
4
 
49
5
  <script lang="ts">
50
- import { computed, defineComponent, inject, ref } from 'vue';
6
+ import { computed, defineComponent, inject, markRaw, ref } from 'vue';
7
+ import { Delete, DocumentCopy, Files, Plus } from '@element-plus/icons';
51
8
 
52
- import type { MNode } from '@tmagic/schema';
9
+ import { NodeType } from '@tmagic/schema';
53
10
 
54
- import type { AddMNode, Services } from '@editor/type';
11
+ import ContentMenu from '@editor/components/ContentMenu.vue';
12
+ import type { ComponentGroup, MenuButton, MenuItem, Services } from '@editor/type';
55
13
 
56
14
  export default defineComponent({
57
- name: 'magic-editor-content-menu',
15
+ components: { ContentMenu },
58
16
 
59
17
  setup() {
60
18
  const services = inject<Services>('services');
61
- const subVisible = ref(false);
19
+ const menu = ref<InstanceType<typeof ContentMenu>>();
62
20
  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);
23
+ const componentList = computed(() => services?.componentListService.getList() || []);
63
24
 
64
- return {
65
- subVisible,
66
-
67
- node,
68
-
69
- componentGroupList: computed(() => services?.componentListService.getList()),
70
-
71
- append(config: AddMNode) {
72
- services?.editorService.add({
73
- name: config.text,
74
- type: config.type,
75
- ...(config.data || {}),
76
- });
77
- },
25
+ const createMenuItems = (group: ComponentGroup): MenuButton[] =>
26
+ group.items.map((component) => ({
27
+ text: component.text,
28
+ type: 'button',
29
+ icon: component.icon,
30
+ handler: () => {
31
+ services?.editorService.add({
32
+ name: component.text,
33
+ type: component.type,
34
+ ...(component.data || {}),
35
+ });
36
+ },
37
+ }));
78
38
 
79
- remove() {
80
- node.value && services?.editorService.remove(node.value);
81
- },
39
+ const getSubMenuData = computed<MenuButton[]>(() => {
40
+ if (node.value?.type === 'tabs') {
41
+ return [
42
+ {
43
+ text: '标签页',
44
+ type: 'button',
45
+ icon: Files,
46
+ handler: () => {
47
+ services?.editorService.add({
48
+ type: 'tab-pane',
49
+ });
50
+ },
51
+ },
52
+ ];
53
+ }
54
+ if (node.value?.items) {
55
+ return (
56
+ componentList.value.reduce(
57
+ (subMenuData: MenuButton[], group: ComponentGroup, index) =>
58
+ subMenuData.concat(
59
+ createMenuItems(group),
60
+ index < componentList.value.length - 1
61
+ ? [
62
+ {
63
+ type: 'divider',
64
+ direction: 'horizontal',
65
+ },
66
+ ]
67
+ : [],
68
+ ),
69
+ [],
70
+ ) || []
71
+ );
72
+ }
73
+ return [];
74
+ });
82
75
 
83
- copy(node?: MNode) {
84
- node && services?.editorService.copy(node);
85
- },
76
+ return {
77
+ menu,
78
+ menuData: computed<MenuItem[]>(() => [
79
+ {
80
+ type: 'button',
81
+ text: '新增',
82
+ icon: markRaw(Plus),
83
+ display: () => node.value?.items,
84
+ items: getSubMenuData.value,
85
+ },
86
+ {
87
+ type: 'button',
88
+ text: '复制',
89
+ icon: markRaw(DocumentCopy),
90
+ display: () => !isRoot.value,
91
+ handler: () => {
92
+ node.value && services?.editorService.copy(node.value);
93
+ },
94
+ },
95
+ {
96
+ type: 'button',
97
+ text: '删除',
98
+ icon: markRaw(Delete),
99
+ display: () => !isRoot.value && !isPage.value,
100
+ handler: () => {
101
+ node.value && services?.editorService.remove(node.value);
102
+ },
103
+ },
104
+ ]),
86
105
 
87
- setSubVisitable(v: boolean) {
88
- subVisible.value = v;
106
+ show(e: MouseEvent) {
107
+ menu.value?.show(e);
89
108
  },
90
109
  };
91
110
  },
@@ -33,8 +33,8 @@
33
33
  <div
34
34
  :id="data.id"
35
35
  class="cus-tree-node"
36
- @mousedown="toogleClickFlag"
37
- @mouseup="toogleClickFlag"
36
+ @mousedown="toggleClickFlag"
37
+ @mouseup="toggleClickFlag"
38
38
  @mouseenter="highlightHandler(data)"
39
39
  :class="{ 'cus-tree-node-hover': canHighlight && data.id === highlightNode?.id }"
40
40
  >
@@ -48,13 +48,13 @@
48
48
  </el-tree>
49
49
 
50
50
  <teleport to="body">
51
- <layer-menu :style="menuStyle"></layer-menu>
51
+ <layer-menu ref="menu"></layer-menu>
52
52
  </teleport>
53
53
  </el-scrollbar>
54
54
  </template>
55
55
 
56
56
  <script lang="ts">
57
- import { computed, defineComponent, inject, onMounted, Ref, ref, watchEffect } from 'vue';
57
+ import { computed, defineComponent, inject, Ref, ref, watchEffect } from 'vue';
58
58
  import type { ElTree } from 'element-plus';
59
59
  import { throttle } from 'lodash-es';
60
60
 
@@ -169,46 +169,6 @@ const useFilter = (tree: Ref<InstanceType<typeof ElTree> | undefined>) => ({
169
169
  },
170
170
  });
171
171
 
172
- const useContentMenu = (editorService?: EditorService) => {
173
- const menuStyle = ref({
174
- position: 'absolute',
175
- left: '0',
176
- top: '0',
177
- display: 'none',
178
- });
179
-
180
- onMounted(() => {
181
- document.addEventListener(
182
- 'click',
183
- () => {
184
- menuStyle.value.display = 'none';
185
- },
186
- true,
187
- );
188
- });
189
-
190
- return {
191
- menuStyle,
192
-
193
- contextmenu(event: MouseEvent, data: MNode) {
194
- const bodyHeight = globalThis.document.body.clientHeight;
195
-
196
- const left = `${event.clientX + 20}px`;
197
- let top = `${event.clientY - 10}px`;
198
-
199
- if (event.clientY + 300 > bodyHeight) {
200
- top = `${bodyHeight - 300}px`;
201
- }
202
-
203
- menuStyle.value.left = left;
204
- menuStyle.value.top = top;
205
- menuStyle.value.display = '';
206
-
207
- select(data, editorService);
208
- },
209
- };
210
- };
211
-
212
172
  export default defineComponent({
213
173
  name: 'magic-editor-layer-panel',
214
174
 
@@ -217,13 +177,14 @@ export default defineComponent({
217
177
  setup() {
218
178
  const services = inject<Services>('services');
219
179
  const tree = ref<InstanceType<typeof ElTree>>();
180
+ const menu = ref<InstanceType<typeof LayerMenu>>();
220
181
  const clicked = ref(false);
221
182
  const editorService = services?.editorService;
222
183
  const highlightHandler = throttle((data: MNode) => {
223
184
  highlight(data, editorService);
224
185
  }, throttleTime);
225
186
 
226
- const toogleClickFlag = () => {
187
+ const toggleClickFlag = () => {
227
188
  clicked.value = !clicked.value;
228
189
  };
229
190
 
@@ -232,12 +193,22 @@ export default defineComponent({
232
193
  () => statusData.highlightNode.value?.id !== statusData.clickNode.value?.id && !clicked.value,
233
194
  );
234
195
 
196
+ editorService?.on('remove', () => {
197
+ setTimeout(() => {
198
+ tree.value?.getNode(editorService.get('node').id)?.updateChildren();
199
+ }, 0);
200
+ });
201
+
235
202
  return {
236
203
  tree,
204
+ menu,
237
205
  ...statusData,
238
206
  ...useDrop(tree, editorService),
239
207
  ...useFilter(tree),
240
- ...useContentMenu(editorService),
208
+
209
+ highlightHandler,
210
+ toggleClickFlag,
211
+ canHighlight,
241
212
 
242
213
  clickHandler(data: MNode): void {
243
214
  if (services?.uiService.get<boolean>('uiSelectMode')) {
@@ -247,9 +218,12 @@ export default defineComponent({
247
218
  tree.value?.setCurrentKey(data.id);
248
219
  select(data, editorService);
249
220
  },
250
- highlightHandler,
251
- toogleClickFlag,
252
- canHighlight,
221
+
222
+ async contextmenu(event: MouseEvent, data: MNode) {
223
+ event.preventDefault();
224
+ await select(data, editorService);
225
+ menu.value?.show(event);
226
+ },
253
227
  };
254
228
  },
255
229
  });
@@ -1,36 +1,26 @@
1
1
  <template>
2
- <el-tabs v-if="data.type === 'tabs'" class="m-editor-sidebar" v-model="activeTabName" type="card" tab-position="left">
3
- <el-tab-pane v-for="item in items" :key="item.text" :name="item.text">
4
- <template #label>
5
- <span>
6
- <m-icon v-if="item.icon" :icon="item.icon"></m-icon>
7
- <div v-if="item.text" class="magic-editor-tab-panel-title">{{ item.text }}</div>
8
- </span>
9
- </template>
10
-
11
- <component :is="item.component" v-bind="item.props || {}" v-on="item.listeners || {}">
12
- <template #layer-node-content="{ data, node }" v-if="item.slots?.layerNodeContent">
13
- <component :is="item.slots.layerNodeContent" :data="data" :node="node" />
14
- </template>
15
- </component>
16
- </el-tab-pane>
2
+ <el-tabs
3
+ v-if="data.type === 'tabs' && data.items.length"
4
+ class="m-editor-sidebar"
5
+ v-model="activeTabName"
6
+ type="card"
7
+ tab-position="left"
8
+ >
9
+ <tab-pane v-for="(item, index) in data.items" :key="index" :data="item"></tab-pane>
17
10
  </el-tabs>
18
11
  </template>
19
12
 
20
13
  <script lang="ts">
21
- import { computed, defineComponent, PropType, ref, watch } from 'vue';
22
- import { Coin, Files } from '@element-plus/icons';
14
+ import { defineComponent, PropType, ref, watch } from 'vue';
23
15
 
24
- import MIcon from '@editor/components/Icon.vue';
25
- import { SideBarData, SideComponent } from '@editor/type';
16
+ import { SideBarData } from '@editor/type';
26
17
 
27
- import ComponentListPanel from './ComponentListPanel.vue';
28
- import LayerPanel from './LayerPanel.vue';
18
+ import TabPane from './TabPane.vue';
29
19
 
30
20
  export default defineComponent({
31
- name: 'm-sidebar',
21
+ components: { TabPane },
32
22
 
33
- components: { MIcon },
23
+ name: 'm-sidebar',
34
24
 
35
25
  props: {
36
26
  data: {
@@ -51,35 +41,6 @@ export default defineComponent({
51
41
 
52
42
  return {
53
43
  activeTabName,
54
-
55
- items: computed<SideComponent[] | Record<string, any>[]>(() =>
56
- props.data?.items.map((item) => {
57
- if (typeof item !== 'string') {
58
- return item;
59
- }
60
-
61
- switch (item) {
62
- case 'component-list':
63
- return {
64
- type: 'component',
65
- icon: Coin,
66
- text: '组件',
67
- component: ComponentListPanel,
68
- slots: {},
69
- };
70
- case 'layer':
71
- return {
72
- type: 'component',
73
- icon: Files,
74
- text: '已选组件',
75
- component: LayerPanel,
76
- slots: {},
77
- };
78
- default:
79
- return {};
80
- }
81
- }),
82
- ),
83
44
  };
84
45
  },
85
46
  });
@@ -0,0 +1,68 @@
1
+ <template>
2
+ <el-tab-pane v-if="config" :name="config.text">
3
+ <template #label>
4
+ <div :key="config.text">
5
+ <m-icon v-if="config.icon" :icon="config.icon"></m-icon>
6
+ <div v-if="config.text" class="magic-editor-tab-panel-title">{{ config.text }}</div>
7
+ </div>
8
+ </template>
9
+
10
+ <component :is="config.component" v-bind="config.props || {}" v-on="config?.listeners || {}">
11
+ <template #layer-node-content="{ data, node }" v-if="config.slots?.layerNodeContent">
12
+ <component :is="config.slots?.layerNodeContent" :data="data" :node="node" />
13
+ </template>
14
+ </component>
15
+ </el-tab-pane>
16
+ </template>
17
+
18
+ <script lang="ts">
19
+ import { computed, defineComponent, PropType } from 'vue';
20
+ import { Coin, Files } from '@element-plus/icons';
21
+
22
+ import MIcon from '@editor/components/Icon.vue';
23
+ import { SideComponent, SideItem } from '@editor/type';
24
+
25
+ import ComponentListPanel from './ComponentListPanel.vue';
26
+ import LayerPanel from './LayerPanel.vue';
27
+
28
+ export default defineComponent({
29
+ components: { MIcon },
30
+
31
+ props: {
32
+ data: {
33
+ type: Object as PropType<SideItem>,
34
+ },
35
+ },
36
+
37
+ setup(props) {
38
+ return {
39
+ config: computed<SideComponent | undefined>(() => {
40
+ if (typeof props.data !== 'string') {
41
+ return props.data;
42
+ }
43
+
44
+ switch (props.data) {
45
+ case 'component-list':
46
+ return {
47
+ type: 'component',
48
+ icon: Coin,
49
+ text: '组件',
50
+ component: ComponentListPanel,
51
+ slots: {},
52
+ };
53
+ case 'layer':
54
+ return {
55
+ type: 'component',
56
+ icon: Files,
57
+ text: '已选组件',
58
+ component: LayerPanel,
59
+ slots: {},
60
+ };
61
+ default:
62
+ return undefined;
63
+ }
64
+ }),
65
+ };
66
+ },
67
+ });
68
+ </script>