@tmagic/editor 1.0.0-beta.8 → 1.0.0-rc.2

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 (121) hide show
  1. package/README.md +1 -0
  2. package/coverage/clover.xml +1556 -0
  3. package/coverage/coverage-final.json +36 -0
  4. package/coverage/lcov-report/base.css +224 -0
  5. package/coverage/lcov-report/block-navigation.js +87 -0
  6. package/coverage/lcov-report/favicon.png +0 -0
  7. package/coverage/lcov-report/index.html +206 -0
  8. package/coverage/lcov-report/prettify.css +1 -0
  9. package/coverage/lcov-report/prettify.js +2 -0
  10. package/coverage/lcov-report/sort-arrow-sprite.png +0 -0
  11. package/coverage/lcov-report/sorter.js +196 -0
  12. package/coverage/lcov-report/src/Editor.vue.html +802 -0
  13. package/coverage/lcov-report/src/components/ContentMenu.vue.html +406 -0
  14. package/coverage/lcov-report/src/components/Icon.vue.html +172 -0
  15. package/coverage/lcov-report/src/components/ScrollViewer.vue.html +283 -0
  16. package/coverage/lcov-report/src/components/ToolButton.vue.html +772 -0
  17. package/coverage/lcov-report/src/components/index.html +161 -0
  18. package/coverage/lcov-report/src/index.html +131 -0
  19. package/coverage/lcov-report/src/layouts/AddPageBox.vue.html +214 -0
  20. package/coverage/lcov-report/src/layouts/Framework.vue.html +343 -0
  21. package/coverage/lcov-report/src/layouts/NavMenu.vue.html +208 -0
  22. package/coverage/lcov-report/src/layouts/PropsPanel.vue.html +319 -0
  23. package/coverage/lcov-report/src/layouts/Resizer.vue.html +268 -0
  24. package/coverage/lcov-report/src/layouts/index.html +176 -0
  25. package/coverage/lcov-report/src/layouts/sidebar/ComponentListPanel.vue.html +358 -0
  26. package/coverage/lcov-report/src/layouts/sidebar/LayerMenu.vue.html +421 -0
  27. package/coverage/lcov-report/src/layouts/sidebar/LayerPanel.vue.html +775 -0
  28. package/coverage/lcov-report/src/layouts/sidebar/Sidebar.vue.html +226 -0
  29. package/coverage/lcov-report/src/layouts/sidebar/TabPane.vue.html +289 -0
  30. package/coverage/lcov-report/src/layouts/sidebar/index.html +176 -0
  31. package/coverage/lcov-report/src/layouts/workspace/PageBar.vue.html +718 -0
  32. package/coverage/lcov-report/src/layouts/workspace/Stage.vue.html +760 -0
  33. package/coverage/lcov-report/src/layouts/workspace/ViewerMenu.vue.html +532 -0
  34. package/coverage/lcov-report/src/layouts/workspace/Workspace.vue.html +598 -0
  35. package/coverage/lcov-report/src/layouts/workspace/index.html +161 -0
  36. package/coverage/lcov-report/src/services/BaseService.ts.html +643 -0
  37. package/coverage/lcov-report/src/services/componentList.ts.html +229 -0
  38. package/coverage/lcov-report/src/services/editor.ts.html +2077 -0
  39. package/coverage/lcov-report/src/services/events.ts.html +331 -0
  40. package/coverage/lcov-report/src/services/history.ts.html +478 -0
  41. package/coverage/lcov-report/src/services/index.html +206 -0
  42. package/coverage/lcov-report/src/services/props.ts.html +415 -0
  43. package/coverage/lcov-report/src/services/ui.ts.html +580 -0
  44. package/coverage/lcov-report/src/type.ts.html +850 -0
  45. package/coverage/lcov-report/src/utils/compose.ts.html +184 -0
  46. package/coverage/lcov-report/src/utils/config.ts.html +172 -0
  47. package/coverage/lcov-report/src/utils/editor.ts.html +838 -0
  48. package/coverage/lcov-report/src/utils/index.html +221 -0
  49. package/coverage/lcov-report/src/utils/index.ts.html +151 -0
  50. package/coverage/lcov-report/src/utils/logger.ts.html +226 -0
  51. package/coverage/lcov-report/src/utils/props.ts.html +796 -0
  52. package/coverage/lcov-report/src/utils/scroll-viewer.ts.html +733 -0
  53. package/coverage/lcov-report/src/utils/undo-redo.ts.html +313 -0
  54. package/coverage/lcov.info +3747 -0
  55. package/dist/style.css +91 -45
  56. package/dist/tmagic-editor.es.js +1462 -2003
  57. package/dist/tmagic-editor.es.js.map +1 -1
  58. package/dist/tmagic-editor.umd.js +1461 -2003
  59. package/dist/tmagic-editor.umd.js.map +1 -1
  60. package/dist/types/src/Editor.vue.d.ts +10 -1
  61. package/dist/types/src/components/ToolButton.vue.d.ts +12 -1
  62. package/dist/types/src/fields/UISelect.vue.d.ts +4 -1
  63. package/dist/types/src/index.d.ts +1 -0
  64. package/dist/types/src/layouts/CodeEditor.vue.d.ts +13 -4
  65. package/dist/types/src/layouts/Framework.vue.d.ts +15 -3
  66. package/dist/types/src/layouts/PropsPanel.vue.d.ts +2 -1
  67. package/dist/types/src/layouts/sidebar/ComponentListPanel.vue.d.ts +2 -1
  68. package/dist/types/src/layouts/sidebar/Sidebar.vue.d.ts +2 -3
  69. package/dist/types/src/layouts/sidebar/TabPane.vue.d.ts +14 -0
  70. package/dist/types/src/layouts/workspace/PageBar.vue.d.ts +10 -3
  71. package/dist/types/src/layouts/workspace/Workspace.vue.d.ts +4 -6
  72. package/dist/types/src/services/BaseService.d.ts +4 -1
  73. package/dist/types/src/services/editor.d.ts +16 -6
  74. package/dist/types/src/services/history.d.ts +1 -0
  75. package/dist/types/src/services/props.d.ts +2 -2
  76. package/dist/types/src/services/ui.d.ts +2 -0
  77. package/dist/types/src/type.d.ts +16 -9
  78. package/dist/types/src/utils/editor.d.ts +5 -4
  79. package/dist/types/src/utils/polyfills.d.ts +0 -0
  80. package/package.json +44 -12
  81. package/src/Editor.vue +6 -1
  82. package/src/components/ContentMenu.vue +107 -0
  83. package/src/components/ScrollViewer.vue +1 -1
  84. package/src/components/ToolButton.vue +72 -31
  85. package/src/fields/UISelect.vue +14 -6
  86. package/src/index.ts +2 -0
  87. package/src/layouts/AddPageBox.vue +3 -1
  88. package/src/layouts/CodeEditor.vue +20 -13
  89. package/src/layouts/Framework.vue +20 -7
  90. package/src/layouts/PropsPanel.vue +5 -4
  91. package/src/layouts/sidebar/ComponentListPanel.vue +25 -3
  92. package/src/layouts/sidebar/LayerMenu.vue +91 -96
  93. package/src/layouts/sidebar/LayerPanel.vue +80 -59
  94. package/src/layouts/sidebar/Sidebar.vue +13 -52
  95. package/src/layouts/sidebar/TabPane.vue +68 -0
  96. package/src/layouts/workspace/PageBar.vue +145 -17
  97. package/src/layouts/workspace/Stage.vue +56 -64
  98. package/src/layouts/workspace/ViewerMenu.vue +107 -68
  99. package/src/layouts/workspace/Workspace.vue +110 -18
  100. package/src/services/BaseService.ts +70 -22
  101. package/src/services/editor.ts +197 -64
  102. package/src/services/history.ts +7 -0
  103. package/src/services/props.ts +3 -3
  104. package/src/services/ui.ts +35 -5
  105. package/src/theme/common/var.scss +3 -2
  106. package/src/theme/component-list-panel.scss +2 -0
  107. package/src/theme/content-menu.scss +33 -26
  108. package/src/theme/layer-panel.scss +10 -0
  109. package/src/theme/nav-menu.scss +6 -2
  110. package/src/theme/page-bar.scss +42 -2
  111. package/src/theme/props-panel.scss +19 -17
  112. package/src/type.ts +17 -9
  113. package/src/utils/editor.ts +35 -9
  114. package/src/utils/polyfills.ts +8 -0
  115. package/src/utils/props.ts +20 -1
  116. package/dist/types/src/layouts/sidebar/LayerMenu.vue.d.ts +0 -31
  117. package/dist/types/src/layouts/sidebar/LayerPanel.vue.d.ts +0 -973
  118. package/dist/types/src/layouts/workspace/Stage.vue.d.ts +0 -192
  119. package/dist/types/src/layouts/workspace/ViewerMenu.vue.d.ts +0 -18
  120. package/tsconfig.json +0 -9
  121. package/vite.config.ts +0 -30
@@ -1,115 +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="setSubVisiable(true)"
7
- @mouseleave="setSubVisiable(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="setSubVisiable(true)" @mouseleave="setSubVisiable(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
-
35
- <template v-else-if="node.type === 'app'">
36
- <div
37
- class="magic-editor-content-menu-item"
38
- v-for="item in menu.app"
39
- :key="item.type"
40
- @click="() => append(item)"
41
- >
42
- {{ item.text }}
43
- </div>
44
- </template>
45
-
46
- <template v-else-if="node.items">
47
- <div v-for="list in menu.component" :key="list.title">
48
- <template v-for="item in list.items">
49
- <div class="magic-editor-content-menu-item" v-if="item" :key="item.type" @click="() => append(item)">
50
- {{ item.text }}
51
- </div>
52
- </template>
53
- <div class="separation"></div>
54
- </div>
55
- </template>
56
- </el-scrollbar>
57
- </div>
58
- </div>
2
+ <content-menu :menu-data="menuData" ref="menu" style="overflow: initial"></content-menu>
59
3
  </template>
60
4
 
61
5
  <script lang="ts">
62
- import { computed, defineComponent, inject, PropType, ref } from 'vue';
6
+ import { computed, defineComponent, inject, markRaw, ref } from 'vue';
7
+ import { Delete, DocumentCopy, Files, Plus } from '@element-plus/icons';
63
8
 
64
- import type { ComponentGroup, Services } from '@editor/type';
9
+ import { NodeType } from '@tmagic/schema';
65
10
 
66
- export default defineComponent({
67
- name: 'magic-editor-content-menu',
11
+ import ContentMenu from '@editor/components/ContentMenu.vue';
12
+ import type { ComponentGroup, MenuButton, MenuItem, Services } from '@editor/type';
68
13
 
69
- props: {
70
- componentGroupList: {
71
- type: Array as PropType<ComponentGroup[]>,
72
- default: () => [],
73
- },
74
- },
14
+ export default defineComponent({
15
+ components: { ContentMenu },
75
16
 
76
- setup(props) {
17
+ setup() {
77
18
  const services = inject<Services>('services');
78
- const subVisible = ref(false);
19
+ const menu = ref<InstanceType<typeof ContentMenu>>();
79
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() || []);
80
24
 
81
- return {
82
- subVisible,
83
-
84
- node,
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
+ }));
85
38
 
86
- menu: computed(() => ({
87
- app: [
39
+ const getSubMenuData = computed<MenuButton[]>(() => {
40
+ if (node.value?.type === 'tabs') {
41
+ return [
88
42
  {
89
- type: 'page',
90
- text: '页面',
43
+ text: '标签页',
44
+ type: 'button',
45
+ icon: Files,
46
+ handler: () => {
47
+ services?.editorService.add({
48
+ type: 'tab-pane',
49
+ });
50
+ },
91
51
  },
92
- ],
93
- component: props.componentGroupList,
94
- })),
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
+ });
95
75
 
96
- append(config: any) {
97
- services?.editorService.add({
98
- name: config.text,
99
- type: config.type,
100
- });
101
- },
102
-
103
- remove() {
104
- node.value && services?.editorService.remove(node.value);
105
- },
106
-
107
- copy(node: any) {
108
- services?.editorService.copy(node);
109
- },
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
+ ]),
110
105
 
111
- setSubVisiable(v: any) {
112
- subVisible.value = v;
106
+ show(e: MouseEvent) {
107
+ menu.value?.show(e);
113
108
  },
114
109
  };
115
110
  },
@@ -14,6 +14,7 @@
14
14
  ref="tree"
15
15
  node-key="id"
16
16
  draggable
17
+ :default-expanded-keys="expandedKeys"
17
18
  :load="loadItems"
18
19
  :data="values"
19
20
  :expand-on-click-node="false"
@@ -29,37 +30,60 @@
29
30
  empty-text="页面空荡荡的"
30
31
  >
31
32
  <template #default="{ node, data }">
32
- <slot name="layer-node-content" :node="node" :data="data">
33
- <span>
34
- {{ `${data.name} (${data.id})` }}
35
- </span>
36
- </slot>
33
+ <div
34
+ :id="data.id"
35
+ class="cus-tree-node"
36
+ @mousedown="toggleClickFlag"
37
+ @mouseup="toggleClickFlag"
38
+ @mouseenter="highlightHandler(data)"
39
+ :class="{ 'cus-tree-node-hover': canHighlight && data.id === highlightNode?.id }"
40
+ >
41
+ <slot name="layer-node-content" :node="node" :data="data">
42
+ <span>
43
+ {{ `${data.name} (${data.id})` }}
44
+ </span>
45
+ </slot>
46
+ </div>
37
47
  </template>
38
48
  </el-tree>
39
49
 
40
50
  <teleport to="body">
41
- <layer-menu :style="menuStyle"></layer-menu>
51
+ <layer-menu ref="menu"></layer-menu>
42
52
  </teleport>
43
53
  </el-scrollbar>
44
54
  </template>
45
55
 
46
56
  <script lang="ts">
47
- import { computed, defineComponent, inject, onMounted, Ref, ref, watchEffect } from 'vue';
57
+ import { computed, defineComponent, inject, Ref, ref, watchEffect } from 'vue';
48
58
  import type { ElTree } from 'element-plus';
59
+ import { throttle } from 'lodash-es';
49
60
 
50
61
  import type { MNode, MPage } from '@tmagic/schema';
62
+ import { NodeType } from '@tmagic/schema';
63
+ import StageCore from '@tmagic/stage';
51
64
 
52
65
  import type { EditorService } from '@editor/services/editor';
53
66
  import type { Services } from '@editor/type';
54
67
 
55
68
  import LayerMenu from './LayerMenu.vue';
56
69
 
57
- const select = (data: MNode, editorService?: EditorService) => {
70
+ const throttleTime = 150;
71
+
72
+ const select = async (data: MNode, editorService?: EditorService) => {
58
73
  if (!data.id) {
59
74
  throw new Error('没有id');
60
75
  }
61
76
 
62
- editorService?.select(data);
77
+ await editorService?.select(data);
78
+ editorService?.get<StageCore>('stage')?.select(data.id);
79
+ };
80
+
81
+ const highlight = (data: MNode, editorService?: EditorService) => {
82
+ if (!data?.id) {
83
+ throw new Error('没有id');
84
+ }
85
+ editorService?.highlight(data);
86
+ editorService?.get<StageCore>('stage')?.highlight(data.id);
63
87
  };
64
88
 
65
89
  const useDrop = (tree: Ref<InstanceType<typeof ElTree> | undefined>, editorService?: EditorService) => ({
@@ -69,8 +93,8 @@ const useDrop = (tree: Ref<InstanceType<typeof ElTree> | undefined>, editorServi
69
93
 
70
94
  const { type: ingType } = ingData;
71
95
 
72
- if (ingType !== 'page' && data.type === 'page') return false;
73
- if (ingType === 'page' && data.type !== 'page') return false;
96
+ if (ingType !== NodeType.PAGE && data.type === NodeType.PAGE) return false;
97
+ if (ingType === NodeType.PAGE && data.type !== NodeType.PAGE) return false;
74
98
  if (!data || !data.type) return false;
75
99
  if (['prev', 'next'].includes(type)) return true;
76
100
  if (data.items || data.type === 'container') return true;
@@ -87,19 +111,22 @@ const useDrop = (tree: Ref<InstanceType<typeof ElTree> | undefined>, editorServi
87
111
  });
88
112
 
89
113
  const useStatus = (tree: Ref<InstanceType<typeof ElTree> | undefined>, editorService?: EditorService) => {
114
+ const highlightNode = ref<MNode>();
115
+ const node = ref<MNode>();
90
116
  const page = computed(() => editorService?.get('page'));
91
117
 
92
118
  watchEffect(() => {
93
119
  if (!tree.value) return;
94
-
95
- const node = editorService?.get('node');
96
- node && tree.value.setCurrentKey(node.id, true);
120
+ node.value = editorService?.get('node');
121
+ node.value && tree.value.setCurrentKey(node.value.id, true);
97
122
 
98
123
  const parent = editorService?.get('parent');
99
124
  if (!parent?.id) return;
100
125
 
101
126
  const treeNode = tree.value.getNode(parent.id);
102
127
  treeNode?.updateChildren();
128
+
129
+ highlightNode.value = editorService?.get('highlightNode');
103
130
  });
104
131
 
105
132
  return {
@@ -114,6 +141,10 @@ const useStatus = (tree: Ref<InstanceType<typeof ElTree> | undefined>, editorSer
114
141
  }
115
142
  resolve([]);
116
143
  },
144
+
145
+ highlightNode,
146
+ clickNode: node,
147
+ expandedKeys: computed(() => (node.value ? [node.value.id] : [])),
117
148
  };
118
149
  };
119
150
 
@@ -127,12 +158,10 @@ const useFilter = (tree: Ref<InstanceType<typeof ElTree> | undefined>) => ({
127
158
  let name = '';
128
159
  if (data.name) {
129
160
  name = data.name;
130
- } else if (data.type) {
131
- name = data.type;
132
161
  } else if (data.items) {
133
162
  name = 'container';
134
163
  }
135
- return name.indexOf(value) !== -1;
164
+ return `${data.id}${name}${data.type}`.indexOf(value) !== -1;
136
165
  },
137
166
 
138
167
  filterTextChangeHandler(val: string) {
@@ -140,46 +169,6 @@ const useFilter = (tree: Ref<InstanceType<typeof ElTree> | undefined>) => ({
140
169
  },
141
170
  });
142
171
 
143
- const useContentMenu = (editorService?: EditorService) => {
144
- const menuStyle = ref({
145
- position: 'absolute',
146
- left: '0',
147
- top: '0',
148
- display: 'none',
149
- });
150
-
151
- onMounted(() => {
152
- document.addEventListener(
153
- 'click',
154
- () => {
155
- menuStyle.value.display = 'none';
156
- },
157
- true,
158
- );
159
- });
160
-
161
- return {
162
- menuStyle,
163
-
164
- contextmenu(event: MouseEvent, data: MNode) {
165
- const bodyHeight = globalThis.document.body.clientHeight;
166
-
167
- const left = `${event.clientX + 20}px`;
168
- let top = `${event.clientY - 10}px`;
169
-
170
- if (event.clientY + 300 > bodyHeight) {
171
- top = `${bodyHeight - 300}px`;
172
- }
173
-
174
- menuStyle.value.left = left;
175
- menuStyle.value.top = top;
176
- menuStyle.value.display = '';
177
-
178
- select(data, editorService);
179
- },
180
- };
181
- };
182
-
183
172
  export default defineComponent({
184
173
  name: 'magic-editor-layer-panel',
185
174
 
@@ -188,21 +177,53 @@ export default defineComponent({
188
177
  setup() {
189
178
  const services = inject<Services>('services');
190
179
  const tree = ref<InstanceType<typeof ElTree>>();
180
+ const menu = ref<InstanceType<typeof LayerMenu>>();
181
+ const clicked = ref(false);
191
182
  const editorService = services?.editorService;
183
+ const highlightHandler = throttle((data: MNode) => {
184
+ highlight(data, editorService);
185
+ }, throttleTime);
186
+
187
+ const toggleClickFlag = () => {
188
+ clicked.value = !clicked.value;
189
+ };
190
+
191
+ const statusData = useStatus(tree, editorService);
192
+ const canHighlight = computed(
193
+ () => statusData.highlightNode.value?.id !== statusData.clickNode.value?.id && !clicked.value,
194
+ );
195
+
196
+ editorService?.on('remove', () => {
197
+ setTimeout(() => {
198
+ tree.value?.getNode(editorService.get('node').id)?.updateChildren();
199
+ }, 0);
200
+ });
201
+
192
202
  return {
193
203
  tree,
204
+ menu,
205
+ ...statusData,
194
206
  ...useDrop(tree, editorService),
195
- ...useStatus(tree, editorService),
196
207
  ...useFilter(tree),
197
- ...useContentMenu(editorService),
208
+
209
+ highlightHandler,
210
+ toggleClickFlag,
211
+ canHighlight,
198
212
 
199
213
  clickHandler(data: MNode): void {
200
214
  if (services?.uiService.get<boolean>('uiSelectMode')) {
201
215
  document.dispatchEvent(new CustomEvent('ui-select', { detail: data }));
202
216
  return;
203
217
  }
218
+ tree.value?.setCurrentKey(data.id);
204
219
  select(data, editorService);
205
220
  },
221
+
222
+ async contextmenu(event: MouseEvent, data: MNode) {
223
+ event.preventDefault();
224
+ await select(data, editorService);
225
+ menu.value?.show(event);
226
+ },
206
227
  };
207
228
  },
208
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>