@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.
- package/README.md +1 -0
- package/coverage/clover.xml +1556 -0
- package/coverage/coverage-final.json +36 -0
- package/coverage/lcov-report/base.css +224 -0
- package/coverage/lcov-report/block-navigation.js +87 -0
- package/coverage/lcov-report/favicon.png +0 -0
- package/coverage/lcov-report/index.html +206 -0
- package/coverage/lcov-report/prettify.css +1 -0
- package/coverage/lcov-report/prettify.js +2 -0
- package/coverage/lcov-report/sort-arrow-sprite.png +0 -0
- package/coverage/lcov-report/sorter.js +196 -0
- package/coverage/lcov-report/src/Editor.vue.html +802 -0
- package/coverage/lcov-report/src/components/ContentMenu.vue.html +406 -0
- package/coverage/lcov-report/src/components/Icon.vue.html +172 -0
- package/coverage/lcov-report/src/components/ScrollViewer.vue.html +283 -0
- package/coverage/lcov-report/src/components/ToolButton.vue.html +772 -0
- package/coverage/lcov-report/src/components/index.html +161 -0
- package/coverage/lcov-report/src/index.html +131 -0
- package/coverage/lcov-report/src/layouts/AddPageBox.vue.html +214 -0
- package/coverage/lcov-report/src/layouts/Framework.vue.html +343 -0
- package/coverage/lcov-report/src/layouts/NavMenu.vue.html +208 -0
- package/coverage/lcov-report/src/layouts/PropsPanel.vue.html +319 -0
- package/coverage/lcov-report/src/layouts/Resizer.vue.html +268 -0
- package/coverage/lcov-report/src/layouts/index.html +176 -0
- package/coverage/lcov-report/src/layouts/sidebar/ComponentListPanel.vue.html +358 -0
- package/coverage/lcov-report/src/layouts/sidebar/LayerMenu.vue.html +421 -0
- package/coverage/lcov-report/src/layouts/sidebar/LayerPanel.vue.html +775 -0
- package/coverage/lcov-report/src/layouts/sidebar/Sidebar.vue.html +226 -0
- package/coverage/lcov-report/src/layouts/sidebar/TabPane.vue.html +289 -0
- package/coverage/lcov-report/src/layouts/sidebar/index.html +176 -0
- package/coverage/lcov-report/src/layouts/workspace/PageBar.vue.html +718 -0
- package/coverage/lcov-report/src/layouts/workspace/Stage.vue.html +760 -0
- package/coverage/lcov-report/src/layouts/workspace/ViewerMenu.vue.html +532 -0
- package/coverage/lcov-report/src/layouts/workspace/Workspace.vue.html +598 -0
- package/coverage/lcov-report/src/layouts/workspace/index.html +161 -0
- package/coverage/lcov-report/src/services/BaseService.ts.html +643 -0
- package/coverage/lcov-report/src/services/componentList.ts.html +229 -0
- package/coverage/lcov-report/src/services/editor.ts.html +2077 -0
- package/coverage/lcov-report/src/services/events.ts.html +331 -0
- package/coverage/lcov-report/src/services/history.ts.html +478 -0
- package/coverage/lcov-report/src/services/index.html +206 -0
- package/coverage/lcov-report/src/services/props.ts.html +415 -0
- package/coverage/lcov-report/src/services/ui.ts.html +580 -0
- package/coverage/lcov-report/src/type.ts.html +850 -0
- package/coverage/lcov-report/src/utils/compose.ts.html +184 -0
- package/coverage/lcov-report/src/utils/config.ts.html +172 -0
- package/coverage/lcov-report/src/utils/editor.ts.html +838 -0
- package/coverage/lcov-report/src/utils/index.html +221 -0
- package/coverage/lcov-report/src/utils/index.ts.html +151 -0
- package/coverage/lcov-report/src/utils/logger.ts.html +226 -0
- package/coverage/lcov-report/src/utils/props.ts.html +796 -0
- package/coverage/lcov-report/src/utils/scroll-viewer.ts.html +733 -0
- package/coverage/lcov-report/src/utils/undo-redo.ts.html +313 -0
- package/coverage/lcov.info +3747 -0
- package/dist/style.css +91 -45
- package/dist/tmagic-editor.es.js +1462 -2003
- package/dist/tmagic-editor.es.js.map +1 -1
- package/dist/tmagic-editor.umd.js +1461 -2003
- package/dist/tmagic-editor.umd.js.map +1 -1
- package/dist/types/src/Editor.vue.d.ts +10 -1
- package/dist/types/src/components/ToolButton.vue.d.ts +12 -1
- package/dist/types/src/fields/UISelect.vue.d.ts +4 -1
- package/dist/types/src/index.d.ts +1 -0
- package/dist/types/src/layouts/CodeEditor.vue.d.ts +13 -4
- package/dist/types/src/layouts/Framework.vue.d.ts +15 -3
- package/dist/types/src/layouts/PropsPanel.vue.d.ts +2 -1
- package/dist/types/src/layouts/sidebar/ComponentListPanel.vue.d.ts +2 -1
- package/dist/types/src/layouts/sidebar/Sidebar.vue.d.ts +2 -3
- package/dist/types/src/layouts/sidebar/TabPane.vue.d.ts +14 -0
- package/dist/types/src/layouts/workspace/PageBar.vue.d.ts +10 -3
- package/dist/types/src/layouts/workspace/Workspace.vue.d.ts +4 -6
- package/dist/types/src/services/BaseService.d.ts +4 -1
- package/dist/types/src/services/editor.d.ts +16 -6
- package/dist/types/src/services/history.d.ts +1 -0
- package/dist/types/src/services/props.d.ts +2 -2
- package/dist/types/src/services/ui.d.ts +2 -0
- package/dist/types/src/type.d.ts +16 -9
- package/dist/types/src/utils/editor.d.ts +5 -4
- package/dist/types/src/utils/polyfills.d.ts +0 -0
- package/package.json +44 -12
- package/src/Editor.vue +6 -1
- package/src/components/ContentMenu.vue +107 -0
- package/src/components/ScrollViewer.vue +1 -1
- package/src/components/ToolButton.vue +72 -31
- package/src/fields/UISelect.vue +14 -6
- package/src/index.ts +2 -0
- package/src/layouts/AddPageBox.vue +3 -1
- package/src/layouts/CodeEditor.vue +20 -13
- package/src/layouts/Framework.vue +20 -7
- package/src/layouts/PropsPanel.vue +5 -4
- package/src/layouts/sidebar/ComponentListPanel.vue +25 -3
- package/src/layouts/sidebar/LayerMenu.vue +91 -96
- package/src/layouts/sidebar/LayerPanel.vue +80 -59
- package/src/layouts/sidebar/Sidebar.vue +13 -52
- package/src/layouts/sidebar/TabPane.vue +68 -0
- package/src/layouts/workspace/PageBar.vue +145 -17
- package/src/layouts/workspace/Stage.vue +56 -64
- package/src/layouts/workspace/ViewerMenu.vue +107 -68
- package/src/layouts/workspace/Workspace.vue +110 -18
- package/src/services/BaseService.ts +70 -22
- package/src/services/editor.ts +197 -64
- package/src/services/history.ts +7 -0
- package/src/services/props.ts +3 -3
- package/src/services/ui.ts +35 -5
- package/src/theme/common/var.scss +3 -2
- package/src/theme/component-list-panel.scss +2 -0
- package/src/theme/content-menu.scss +33 -26
- package/src/theme/layer-panel.scss +10 -0
- package/src/theme/nav-menu.scss +6 -2
- package/src/theme/page-bar.scss +42 -2
- package/src/theme/props-panel.scss +19 -17
- package/src/type.ts +17 -9
- package/src/utils/editor.ts +35 -9
- package/src/utils/polyfills.ts +8 -0
- package/src/utils/props.ts +20 -1
- package/dist/types/src/layouts/sidebar/LayerMenu.vue.d.ts +0 -31
- package/dist/types/src/layouts/sidebar/LayerPanel.vue.d.ts +0 -973
- package/dist/types/src/layouts/workspace/Stage.vue.d.ts +0 -192
- package/dist/types/src/layouts/workspace/ViewerMenu.vue.d.ts +0 -18
- package/tsconfig.json +0 -9
- package/vite.config.ts +0 -30
|
@@ -1,115 +1,110 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<
|
|
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,
|
|
6
|
+
import { computed, defineComponent, inject, markRaw, ref } from 'vue';
|
|
7
|
+
import { Delete, DocumentCopy, Files, Plus } from '@element-plus/icons';
|
|
63
8
|
|
|
64
|
-
import
|
|
9
|
+
import { NodeType } from '@tmagic/schema';
|
|
65
10
|
|
|
66
|
-
|
|
67
|
-
|
|
11
|
+
import ContentMenu from '@editor/components/ContentMenu.vue';
|
|
12
|
+
import type { ComponentGroup, MenuButton, MenuItem, Services } from '@editor/type';
|
|
68
13
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
type: Array as PropType<ComponentGroup[]>,
|
|
72
|
-
default: () => [],
|
|
73
|
-
},
|
|
74
|
-
},
|
|
14
|
+
export default defineComponent({
|
|
15
|
+
components: { ContentMenu },
|
|
75
16
|
|
|
76
|
-
setup(
|
|
17
|
+
setup() {
|
|
77
18
|
const services = inject<Services>('services');
|
|
78
|
-
const
|
|
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
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
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
|
-
|
|
87
|
-
|
|
39
|
+
const getSubMenuData = computed<MenuButton[]>(() => {
|
|
40
|
+
if (node.value?.type === 'tabs') {
|
|
41
|
+
return [
|
|
88
42
|
{
|
|
89
|
-
|
|
90
|
-
|
|
43
|
+
text: '标签页',
|
|
44
|
+
type: 'button',
|
|
45
|
+
icon: Files,
|
|
46
|
+
handler: () => {
|
|
47
|
+
services?.editorService.add({
|
|
48
|
+
type: 'tab-pane',
|
|
49
|
+
});
|
|
50
|
+
},
|
|
91
51
|
},
|
|
92
|
-
]
|
|
93
|
-
|
|
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
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
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
|
-
|
|
112
|
-
|
|
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
|
-
<
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
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
|
|
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,
|
|
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
|
|
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 !==
|
|
73
|
-
if (ingType ===
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
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 {
|
|
22
|
-
import { Coin, Files } from '@element-plus/icons';
|
|
14
|
+
import { defineComponent, PropType, ref, watch } from 'vue';
|
|
23
15
|
|
|
24
|
-
import
|
|
25
|
-
import { SideBarData, SideComponent } from '@editor/type';
|
|
16
|
+
import { SideBarData } from '@editor/type';
|
|
26
17
|
|
|
27
|
-
import
|
|
28
|
-
import LayerPanel from './LayerPanel.vue';
|
|
18
|
+
import TabPane from './TabPane.vue';
|
|
29
19
|
|
|
30
20
|
export default defineComponent({
|
|
31
|
-
|
|
21
|
+
components: { TabPane },
|
|
32
22
|
|
|
33
|
-
|
|
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>
|