@tmagic/editor 1.1.0-beta.10 → 1.1.0-beta.13
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/dist/style.css +46 -0
- package/dist/tmagic-editor.mjs +862 -740
- package/dist/tmagic-editor.mjs.map +1 -1
- package/dist/tmagic-editor.umd.js +864 -739
- package/dist/tmagic-editor.umd.js.map +1 -1
- package/package.json +10 -10
- package/src/Editor.vue +4 -3
- package/src/components/ContentMenu.vue +4 -4
- package/src/components/Icon.vue +6 -20
- package/src/components/ScrollBar.vue +147 -0
- package/src/components/ScrollViewer.vue +89 -44
- package/src/components/ToolButton.vue +40 -138
- package/src/fields/UISelect.vue +2 -2
- package/src/index.ts +2 -0
- package/src/layouts/NavMenu.vue +156 -23
- package/src/layouts/sidebar/LayerMenu.vue +3 -3
- package/src/layouts/sidebar/LayerPanel.vue +39 -8
- package/src/layouts/workspace/PageBar.vue +1 -1
- package/src/layouts/workspace/Stage.vue +8 -90
- package/src/layouts/workspace/ViewerMenu.vue +3 -3
- package/src/layouts/workspace/Workspace.vue +133 -138
- package/src/services/editor.ts +17 -6
- package/src/services/props.ts +26 -53
- package/src/services/ui.ts +16 -20
- package/src/theme/nav-menu.scss +6 -0
- package/src/type.ts +26 -10
- package/src/utils/index.ts +1 -0
- package/src/utils/operator.ts +1 -1
- package/src/utils/props.ts +0 -3
- package/src/utils/scroll-viewer.ts +90 -158
- package/src/utils/stage.ts +91 -0
- package/types/Editor.vue.d.ts +7 -7
- package/types/components/ContentMenu.vue.d.ts +8 -8
- package/types/components/Icon.vue.d.ts +62 -12
- package/types/components/ScrollBar.vue.d.ts +83 -0
- package/types/components/ScrollViewer.vue.d.ts +131 -19
- package/types/components/ToolButton.vue.d.ts +56 -59
- package/types/index.d.ts +2 -0
- package/types/layouts/NavMenu.vue.d.ts +92 -23
- package/types/layouts/sidebar/LayerMenu.vue.d.ts +7 -7
- package/types/layouts/sidebar/LayerPanel.vue.d.ts +17 -15
- package/types/layouts/workspace/Workspace.vue.d.ts +54 -4
- package/types/services/editor.d.ts +1 -0
- package/types/services/props.d.ts +40 -9
- package/types/services/ui.d.ts +1 -1
- package/types/type.d.ts +23 -10
- package/types/utils/index.d.ts +1 -0
- package/types/utils/props.d.ts +0 -1
- package/types/utils/scroll-viewer.d.ts +16 -18
- package/types/utils/stage.d.ts +3 -0
package/src/index.ts
CHANGED
|
@@ -44,6 +44,8 @@ export { default as ComponentListPanel } from './layouts/sidebar/ComponentListPa
|
|
|
44
44
|
export { default as LayerPanel } from './layouts/sidebar/LayerPanel.vue';
|
|
45
45
|
export { default as PropsPanel } from './layouts/PropsPanel.vue';
|
|
46
46
|
export { default as ToolButton } from './components/ToolButton.vue';
|
|
47
|
+
export { default as ContentMenu } from './components/ContentMenu.vue';
|
|
48
|
+
export { default as Icon } from './components/Icon.vue';
|
|
47
49
|
|
|
48
50
|
const defaultInstallOpt: InstallOptions = {
|
|
49
51
|
// @todo, 自定义图片上传方法等编辑器依赖的外部选项
|
package/src/layouts/NavMenu.vue
CHANGED
|
@@ -1,41 +1,174 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div class="m-editor-nav-menu" :style="{ height: `${height}px` }">
|
|
3
3
|
<div v-for="key in keys" :class="`menu-${key}`" :key="key" :style="`width: ${columnWidth?.[key]}px`">
|
|
4
|
-
<tool-button :data="item" v-for="(item, index) in
|
|
4
|
+
<tool-button :data="item" v-for="(item, index) in buttons[key]" :key="index"></tool-button>
|
|
5
5
|
</div>
|
|
6
6
|
</div>
|
|
7
7
|
</template>
|
|
8
8
|
|
|
9
|
-
<script lang="ts">
|
|
10
|
-
import { computed,
|
|
9
|
+
<script lang="ts" setup>
|
|
10
|
+
import { computed, inject, markRaw } from 'vue';
|
|
11
|
+
import { Back, Delete, FullScreen, Grid, Memo, Right, ScaleToOriginal, ZoomIn, ZoomOut } from '@element-plus/icons-vue';
|
|
12
|
+
|
|
13
|
+
import { NodeType } from '@tmagic/schema';
|
|
11
14
|
|
|
12
15
|
import ToolButton from '../components/ToolButton.vue';
|
|
13
|
-
import { GetColumnWidth, MenuBarData, Services } from '../type';
|
|
16
|
+
import { ColumnLayout, GetColumnWidth, MenuBarData, MenuButton, MenuComponent, MenuItem, Services } from '../type';
|
|
14
17
|
|
|
15
|
-
|
|
16
|
-
|
|
18
|
+
const props = withDefaults(
|
|
19
|
+
defineProps<{
|
|
20
|
+
data?: MenuBarData;
|
|
21
|
+
height?: number;
|
|
22
|
+
}>(),
|
|
23
|
+
{
|
|
24
|
+
data: () => ({}),
|
|
25
|
+
height: 35,
|
|
26
|
+
},
|
|
27
|
+
);
|
|
17
28
|
|
|
18
|
-
|
|
29
|
+
const services = inject<Services>('services');
|
|
30
|
+
const uiService = services?.uiService;
|
|
19
31
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
type: Object as PropType<MenuBarData>,
|
|
23
|
-
default: () => ({}),
|
|
24
|
-
},
|
|
32
|
+
const columnWidth = computed(() => services?.uiService.get<GetColumnWidth>('columnWidth'));
|
|
33
|
+
const keys = Object.values(ColumnLayout);
|
|
25
34
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
},
|
|
35
|
+
const showGuides = computed((): boolean => uiService?.get<boolean>('showGuides') ?? true);
|
|
36
|
+
const showRule = computed((): boolean => uiService?.get<boolean>('showRule') ?? true);
|
|
37
|
+
const zoom = computed((): number => uiService?.get<number>('zoom') ?? 1);
|
|
30
38
|
|
|
31
|
-
|
|
32
|
-
|
|
39
|
+
const isMac = /mac os x/.test(navigator.userAgent.toLowerCase());
|
|
40
|
+
const ctrl = isMac ? 'Command' : 'Ctrl';
|
|
33
41
|
|
|
34
|
-
|
|
35
|
-
|
|
42
|
+
const getConfig = (item: MenuItem): (MenuButton | MenuComponent)[] => {
|
|
43
|
+
if (typeof item !== 'string') {
|
|
44
|
+
return [item];
|
|
45
|
+
}
|
|
46
|
+
const config: (MenuButton | MenuComponent)[] = [];
|
|
47
|
+
switch (item) {
|
|
48
|
+
case '/':
|
|
49
|
+
config.push({
|
|
50
|
+
type: 'divider',
|
|
51
|
+
className: 'divider',
|
|
52
|
+
});
|
|
53
|
+
break;
|
|
54
|
+
case 'zoom':
|
|
55
|
+
config.push(
|
|
56
|
+
...getConfig('zoom-out'),
|
|
57
|
+
...getConfig(`${parseInt(`${zoom.value * 100}`, 10)}%`),
|
|
58
|
+
...getConfig('zoom-in'),
|
|
59
|
+
...getConfig('scale-to-original'),
|
|
60
|
+
...getConfig('scale-to-fit'),
|
|
61
|
+
);
|
|
62
|
+
break;
|
|
63
|
+
case 'delete':
|
|
64
|
+
config.push({
|
|
65
|
+
type: 'button',
|
|
66
|
+
className: 'delete',
|
|
67
|
+
icon: markRaw(Delete),
|
|
68
|
+
tooltip: `刪除(Delete)`,
|
|
69
|
+
disabled: () => services?.editorService.get('node')?.type === NodeType.PAGE,
|
|
70
|
+
handler: () => services?.editorService.remove(services?.editorService.get('node')),
|
|
71
|
+
});
|
|
72
|
+
break;
|
|
73
|
+
case 'undo':
|
|
74
|
+
config.push({
|
|
75
|
+
type: 'button',
|
|
76
|
+
className: 'undo',
|
|
77
|
+
icon: markRaw(Back),
|
|
78
|
+
tooltip: `后退(${ctrl}+z)`,
|
|
79
|
+
disabled: () => !services?.historyService.state.canUndo,
|
|
80
|
+
handler: () => services?.editorService.undo(),
|
|
81
|
+
});
|
|
82
|
+
break;
|
|
83
|
+
case 'redo':
|
|
84
|
+
config.push({
|
|
85
|
+
type: 'button',
|
|
86
|
+
className: 'redo',
|
|
87
|
+
icon: markRaw(Right),
|
|
88
|
+
tooltip: `前进(${ctrl}+Shift+z)`,
|
|
89
|
+
disabled: () => !services?.historyService.state.canRedo,
|
|
90
|
+
handler: () => services?.editorService.redo(),
|
|
91
|
+
});
|
|
92
|
+
break;
|
|
93
|
+
case 'zoom-in':
|
|
94
|
+
config.push({
|
|
95
|
+
type: 'button',
|
|
96
|
+
className: 'zoom-in',
|
|
97
|
+
icon: markRaw(ZoomIn),
|
|
98
|
+
tooltip: `放大(${ctrl}+=)`,
|
|
99
|
+
handler: () => uiService?.zoom(0.1),
|
|
100
|
+
});
|
|
101
|
+
break;
|
|
102
|
+
case 'zoom-out':
|
|
103
|
+
config.push({
|
|
104
|
+
type: 'button',
|
|
105
|
+
className: 'zoom-out',
|
|
106
|
+
icon: markRaw(ZoomOut),
|
|
107
|
+
tooltip: `縮小(${ctrl}+-)`,
|
|
108
|
+
handler: () => uiService?.zoom(-0.1),
|
|
109
|
+
});
|
|
110
|
+
break;
|
|
111
|
+
case 'scale-to-original':
|
|
112
|
+
config.push({
|
|
113
|
+
type: 'button',
|
|
114
|
+
className: 'scale-to-original',
|
|
115
|
+
icon: markRaw(ScaleToOriginal),
|
|
116
|
+
tooltip: `缩放到实际大小(${ctrl}+1)`,
|
|
117
|
+
handler: () => uiService?.set('zoom', 1),
|
|
118
|
+
});
|
|
119
|
+
break;
|
|
120
|
+
case 'scale-to-fit':
|
|
121
|
+
config.push({
|
|
122
|
+
type: 'button',
|
|
123
|
+
className: 'scale-to-fit',
|
|
124
|
+
icon: markRaw(FullScreen),
|
|
125
|
+
tooltip: `缩放以适应(${ctrl}+0)`,
|
|
126
|
+
handler: () => uiService?.set('zoom', uiService.calcZoom()),
|
|
127
|
+
});
|
|
128
|
+
break;
|
|
129
|
+
case 'rule':
|
|
130
|
+
config.push({
|
|
131
|
+
type: 'button',
|
|
132
|
+
className: 'rule',
|
|
133
|
+
icon: markRaw(Memo),
|
|
134
|
+
tooltip: showRule.value ? '隐藏标尺' : '显示标尺',
|
|
135
|
+
handler: () => uiService?.set('showRule', !showRule.value),
|
|
136
|
+
});
|
|
137
|
+
break;
|
|
138
|
+
case 'guides':
|
|
139
|
+
config.push({
|
|
140
|
+
type: 'button',
|
|
141
|
+
className: 'guides',
|
|
142
|
+
icon: markRaw(Grid),
|
|
143
|
+
tooltip: showGuides.value ? '隐藏参考线' : '显示参考线',
|
|
144
|
+
handler: () => uiService?.set('showGuides', !showGuides.value),
|
|
145
|
+
});
|
|
146
|
+
break;
|
|
147
|
+
default:
|
|
148
|
+
config.push({
|
|
149
|
+
type: 'text',
|
|
150
|
+
text: item,
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
return config;
|
|
154
|
+
};
|
|
36
155
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
156
|
+
const buttons = computed(() => {
|
|
157
|
+
const data: {
|
|
158
|
+
[ColumnLayout.LEFT]: (MenuButton | MenuComponent)[];
|
|
159
|
+
[ColumnLayout.CENTER]: (MenuButton | MenuComponent)[];
|
|
160
|
+
[ColumnLayout.RIGHT]: (MenuButton | MenuComponent)[];
|
|
161
|
+
} = {
|
|
162
|
+
[ColumnLayout.LEFT]: [],
|
|
163
|
+
[ColumnLayout.CENTER]: [],
|
|
164
|
+
[ColumnLayout.RIGHT]: [],
|
|
165
|
+
};
|
|
166
|
+
keys.forEach((key) => {
|
|
167
|
+
const items = props.data[key] || [];
|
|
168
|
+
items.forEach((item) => {
|
|
169
|
+
data[key].push(...getConfig(item));
|
|
170
|
+
});
|
|
171
|
+
});
|
|
172
|
+
return data;
|
|
40
173
|
});
|
|
41
174
|
</script>
|
|
@@ -9,7 +9,7 @@ import { Delete, DocumentCopy, Files, Plus } from '@element-plus/icons-vue';
|
|
|
9
9
|
import { NodeType } from '@tmagic/schema';
|
|
10
10
|
|
|
11
11
|
import ContentMenu from '../../components/ContentMenu.vue';
|
|
12
|
-
import type { ComponentGroup, MenuButton,
|
|
12
|
+
import type { ComponentGroup, MenuButton, MenuComponent, Services } from '../../type';
|
|
13
13
|
|
|
14
14
|
export default defineComponent({
|
|
15
15
|
components: { ContentMenu },
|
|
@@ -22,7 +22,7 @@ export default defineComponent({
|
|
|
22
22
|
const isPage = computed(() => node.value?.type === NodeType.PAGE);
|
|
23
23
|
const componentList = computed(() => services?.componentListService.getList() || []);
|
|
24
24
|
|
|
25
|
-
const layerContentMenu = inject<
|
|
25
|
+
const layerContentMenu = inject<(MenuComponent | MenuButton)[]>('layerContentMenu', []);
|
|
26
26
|
|
|
27
27
|
const createMenuItems = (group: ComponentGroup): MenuButton[] =>
|
|
28
28
|
group.items.map((component) => ({
|
|
@@ -77,7 +77,7 @@ export default defineComponent({
|
|
|
77
77
|
|
|
78
78
|
return {
|
|
79
79
|
menu,
|
|
80
|
-
menuData: computed<
|
|
80
|
+
menuData: computed<(MenuButton | MenuComponent)[]>(() => [
|
|
81
81
|
{
|
|
82
82
|
type: 'button',
|
|
83
83
|
text: '新增',
|
|
@@ -15,6 +15,7 @@
|
|
|
15
15
|
v-if="values.length"
|
|
16
16
|
ref="tree"
|
|
17
17
|
node-key="id"
|
|
18
|
+
empty-text="页面空荡荡的"
|
|
18
19
|
draggable
|
|
19
20
|
:default-expanded-keys="expandedKeys"
|
|
20
21
|
:load="loadItems"
|
|
@@ -29,7 +30,8 @@
|
|
|
29
30
|
@node-click="clickHandler"
|
|
30
31
|
@node-contextmenu="contextmenu"
|
|
31
32
|
@node-drag-end="handleDragEnd"
|
|
32
|
-
|
|
33
|
+
@node-collapse="handleCollapse"
|
|
34
|
+
@node-expand="handleExpand"
|
|
33
35
|
>
|
|
34
36
|
<template #default="{ node, data }">
|
|
35
37
|
<div
|
|
@@ -60,7 +62,7 @@ import { computed, defineComponent, inject, Ref, ref, watchEffect } from 'vue';
|
|
|
60
62
|
import type { ElTree } from 'element-plus';
|
|
61
63
|
import { throttle } from 'lodash-es';
|
|
62
64
|
|
|
63
|
-
import type { MNode, MPage } from '@tmagic/schema';
|
|
65
|
+
import type { Id, MNode, MPage } from '@tmagic/schema';
|
|
64
66
|
import { MContainer, NodeType } from '@tmagic/schema';
|
|
65
67
|
import StageCore from '@tmagic/stage';
|
|
66
68
|
|
|
@@ -122,22 +124,41 @@ const useDrop = (tree: Ref<InstanceType<typeof ElTree> | undefined>, editorServi
|
|
|
122
124
|
});
|
|
123
125
|
|
|
124
126
|
const useStatus = (tree: Ref<InstanceType<typeof ElTree> | undefined>, editorService?: EditorService) => {
|
|
125
|
-
const highlightNode = ref<MNode>();
|
|
126
127
|
const node = ref<MNode>();
|
|
127
128
|
const page = computed(() => editorService?.get('page'));
|
|
129
|
+
const expandedKeys = new Map<Id, Id>();
|
|
130
|
+
|
|
131
|
+
const expandNodes = () => {
|
|
132
|
+
expandedKeys.forEach((key) => {
|
|
133
|
+
if (!tree.value) return;
|
|
134
|
+
tree.value.getNode(key)?.expand();
|
|
135
|
+
});
|
|
136
|
+
};
|
|
128
137
|
|
|
129
138
|
watchEffect(() => {
|
|
130
139
|
if (!tree.value) return;
|
|
131
|
-
|
|
132
|
-
node.value
|
|
140
|
+
if (!editorService) return;
|
|
141
|
+
node.value = editorService.get('node');
|
|
142
|
+
|
|
143
|
+
if (!node.value) return;
|
|
133
144
|
|
|
134
|
-
|
|
145
|
+
tree.value.setCurrentKey(node.value.id, true);
|
|
146
|
+
|
|
147
|
+
const parent = editorService.get('parent');
|
|
135
148
|
if (!parent?.id) return;
|
|
136
149
|
|
|
137
150
|
const treeNode = tree.value.getNode(parent.id);
|
|
138
151
|
treeNode?.updateChildren();
|
|
139
152
|
|
|
140
|
-
|
|
153
|
+
setTimeout(() => {
|
|
154
|
+
tree.value &&
|
|
155
|
+
Object.entries(tree.value.store.nodesMap).forEach(([id, node]) => {
|
|
156
|
+
if (node.expanded && node.data.items) {
|
|
157
|
+
expandedKeys.set(id, id);
|
|
158
|
+
}
|
|
159
|
+
});
|
|
160
|
+
expandNodes();
|
|
161
|
+
});
|
|
141
162
|
});
|
|
142
163
|
|
|
143
164
|
return {
|
|
@@ -153,9 +174,19 @@ const useStatus = (tree: Ref<InstanceType<typeof ElTree> | undefined>, editorSer
|
|
|
153
174
|
resolve([]);
|
|
154
175
|
},
|
|
155
176
|
|
|
156
|
-
highlightNode,
|
|
177
|
+
highlightNode: computed(() => editorService?.get('highlightNode')),
|
|
157
178
|
clickNode: node,
|
|
158
179
|
expandedKeys: computed(() => (node.value ? [node.value.id] : [])),
|
|
180
|
+
|
|
181
|
+
handleCollapse: (data: MNode) => {
|
|
182
|
+
expandedKeys.delete(data.id);
|
|
183
|
+
},
|
|
184
|
+
|
|
185
|
+
handleExpand: (data: MNode) => {
|
|
186
|
+
const parent = editorService?.getParentById(data.id);
|
|
187
|
+
if (!parent?.id) return;
|
|
188
|
+
expandedKeys.set(parent.id, parent.id);
|
|
189
|
+
},
|
|
159
190
|
};
|
|
160
191
|
};
|
|
161
192
|
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
<div class="m-editor-page-bar-title">
|
|
11
11
|
<slot name="page-bar-title" :page="item">
|
|
12
12
|
<el-tooltip effect="dark" placement="top-start" :content="item.name">
|
|
13
|
-
<span>{{ item.name }}</span>
|
|
13
|
+
<span>{{ item.name || item.id }}</span>
|
|
14
14
|
</el-tooltip>
|
|
15
15
|
</slot>
|
|
16
16
|
</div>
|
|
@@ -4,12 +4,14 @@
|
|
|
4
4
|
ref="stageWrap"
|
|
5
5
|
:width="stageRect?.width"
|
|
6
6
|
:height="stageRect?.height"
|
|
7
|
+
:wrap-width="stageContainerRect?.width"
|
|
8
|
+
:wrap-height="stageContainerRect?.height"
|
|
7
9
|
:zoom="zoom"
|
|
8
10
|
>
|
|
9
11
|
<div
|
|
10
12
|
class="m-editor-stage-container"
|
|
11
13
|
ref="stageContainer"
|
|
12
|
-
:style="`transform: scale(${zoom})
|
|
14
|
+
:style="`transform: scale(${zoom});`"
|
|
13
15
|
@contextmenu="contextmenuHandler"
|
|
14
16
|
@drop="dropHandler"
|
|
15
17
|
@dragover="dragoverHandler"
|
|
@@ -25,25 +27,11 @@ import { computed, inject, markRaw, onMounted, onUnmounted, ref, toRaw, watch, w
|
|
|
25
27
|
import { cloneDeep } from 'lodash-es';
|
|
26
28
|
|
|
27
29
|
import type { MApp, MContainer, MNode, MPage } from '@tmagic/schema';
|
|
28
|
-
import StageCore, {
|
|
29
|
-
calcValueByFontsize,
|
|
30
|
-
getOffset,
|
|
31
|
-
GuidesType,
|
|
32
|
-
Runtime,
|
|
33
|
-
SortEventData,
|
|
34
|
-
UpdateEventData,
|
|
35
|
-
} from '@tmagic/stage';
|
|
30
|
+
import StageCore, { calcValueByFontsize, getOffset, Runtime } from '@tmagic/stage';
|
|
36
31
|
|
|
37
32
|
import ScrollViewer from '../../components/ScrollViewer.vue';
|
|
38
|
-
import {
|
|
39
|
-
|
|
40
|
-
Layout,
|
|
41
|
-
Services,
|
|
42
|
-
StageOptions,
|
|
43
|
-
StageRect,
|
|
44
|
-
V_GUIDE_LINE_STORAGE_KEY,
|
|
45
|
-
} from '../../type';
|
|
46
|
-
import { getGuideLineFromCache } from '../../utils';
|
|
33
|
+
import { Layout, Services, StageOptions, StageRect } from '../../type';
|
|
34
|
+
import { useStage } from '../../utils/stage';
|
|
47
35
|
|
|
48
36
|
import ViewerMenu from './ViewerMenu.vue';
|
|
49
37
|
|
|
@@ -59,94 +47,24 @@ const menu = ref<InstanceType<typeof ViewerMenu>>();
|
|
|
59
47
|
|
|
60
48
|
const isMultiSelect = computed(() => services?.editorService.get('nodes')?.length > 1);
|
|
61
49
|
const stageRect = computed(() => services?.uiService.get<StageRect>('stageRect'));
|
|
62
|
-
const
|
|
50
|
+
const stageContainerRect = computed(() => services?.uiService.get<StageRect>('stageContainerRect'));
|
|
63
51
|
const root = computed(() => services?.editorService.get<MApp>('root'));
|
|
64
52
|
const page = computed(() => services?.editorService.get<MPage>('page'));
|
|
65
53
|
const zoom = computed(() => services?.uiService.get<number>('zoom') || 1);
|
|
66
54
|
const node = computed(() => services?.editorService.get<MNode>('node'));
|
|
67
55
|
|
|
68
|
-
const getGuideLineKey = (key: string) => `${key}_${root.value?.id}_${page.value?.id}`;
|
|
69
|
-
|
|
70
56
|
watchEffect(() => {
|
|
71
57
|
if (stage) return;
|
|
72
58
|
|
|
73
59
|
if (!stageContainer.value) return;
|
|
74
60
|
if (!(stageOptions?.runtimeUrl || stageOptions?.render) || !root.value) return;
|
|
75
61
|
|
|
76
|
-
stage =
|
|
77
|
-
render: stageOptions.render,
|
|
78
|
-
runtimeUrl: stageOptions.runtimeUrl,
|
|
79
|
-
zoom: zoom.value,
|
|
80
|
-
autoScrollIntoView: stageOptions.autoScrollIntoView,
|
|
81
|
-
isContainer: stageOptions.isContainer,
|
|
82
|
-
containerHighlightClassName: stageOptions.containerHighlightClassName,
|
|
83
|
-
containerHighlightDuration: stageOptions.containerHighlightDuration,
|
|
84
|
-
containerHighlightType: stageOptions.containerHighlightType,
|
|
85
|
-
canSelect: (el, event, stop) => {
|
|
86
|
-
const elCanSelect = stageOptions.canSelect(el);
|
|
87
|
-
// 在组件联动过程中不能再往下选择,返回并触发 ui-select
|
|
88
|
-
if (uiSelectMode.value && elCanSelect && event.type === 'mousedown') {
|
|
89
|
-
document.dispatchEvent(new CustomEvent('ui-select', { detail: el }));
|
|
90
|
-
return stop();
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
return elCanSelect;
|
|
94
|
-
},
|
|
95
|
-
moveableOptions: stageOptions.moveableOptions,
|
|
96
|
-
updateDragEl: stageOptions.updateDragEl,
|
|
97
|
-
});
|
|
62
|
+
stage = useStage(stageOptions);
|
|
98
63
|
|
|
99
64
|
services?.editorService.set('stage', markRaw(stage));
|
|
100
65
|
|
|
101
66
|
stage?.mount(stageContainer.value);
|
|
102
67
|
|
|
103
|
-
stage.mask.setGuides([
|
|
104
|
-
getGuideLineFromCache(getGuideLineKey(H_GUIDE_LINE_STORAGE_KEY)),
|
|
105
|
-
getGuideLineFromCache(getGuideLineKey(V_GUIDE_LINE_STORAGE_KEY)),
|
|
106
|
-
]);
|
|
107
|
-
|
|
108
|
-
stage?.on('select', (el: HTMLElement) => {
|
|
109
|
-
services?.editorService.select(el.id);
|
|
110
|
-
});
|
|
111
|
-
|
|
112
|
-
stage?.on('highlight', (el: HTMLElement) => {
|
|
113
|
-
services?.editorService.highlight(el.id);
|
|
114
|
-
});
|
|
115
|
-
|
|
116
|
-
stage?.on('multiSelect', (els: HTMLElement[]) => {
|
|
117
|
-
services?.editorService.multiSelect(els.map((el) => el.id));
|
|
118
|
-
});
|
|
119
|
-
|
|
120
|
-
stage?.on('update', (ev: UpdateEventData) => {
|
|
121
|
-
if (ev.parentEl) {
|
|
122
|
-
for (const data of ev.data) {
|
|
123
|
-
services?.editorService.moveToContainer({ id: data.el.id, style: data.style }, ev.parentEl.id);
|
|
124
|
-
}
|
|
125
|
-
return;
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
services?.editorService.update(ev.data.map((data) => ({ id: data.el.id, style: data.style })));
|
|
129
|
-
});
|
|
130
|
-
|
|
131
|
-
stage?.on('sort', (ev: SortEventData) => {
|
|
132
|
-
services?.editorService.sort(ev.src, ev.dist);
|
|
133
|
-
});
|
|
134
|
-
|
|
135
|
-
stage?.on('changeGuides', (e) => {
|
|
136
|
-
services?.uiService.set('showGuides', true);
|
|
137
|
-
|
|
138
|
-
if (!root.value || !page.value) return;
|
|
139
|
-
|
|
140
|
-
const storageKey = getGuideLineKey(
|
|
141
|
-
e.type === GuidesType.HORIZONTAL ? H_GUIDE_LINE_STORAGE_KEY : V_GUIDE_LINE_STORAGE_KEY,
|
|
142
|
-
);
|
|
143
|
-
if (e.guides.length) {
|
|
144
|
-
globalThis.localStorage.setItem(storageKey, JSON.stringify(e.guides));
|
|
145
|
-
} else {
|
|
146
|
-
globalThis.localStorage.removeItem(storageKey);
|
|
147
|
-
}
|
|
148
|
-
});
|
|
149
|
-
|
|
150
68
|
if (!node.value?.id) return;
|
|
151
69
|
stage?.on('runtime-ready', (rt) => {
|
|
152
70
|
runtime = rt;
|
|
@@ -12,7 +12,7 @@ import { isPage } from '@tmagic/utils';
|
|
|
12
12
|
|
|
13
13
|
import ContentMenu from '../../components/ContentMenu.vue';
|
|
14
14
|
import storageService from '../../services/storage';
|
|
15
|
-
import { LayerOffset, Layout,
|
|
15
|
+
import { LayerOffset, Layout, MenuButton, MenuComponent, Services } from '../../type';
|
|
16
16
|
import { COPY_STORAGE_KEY } from '../../utils/editor';
|
|
17
17
|
|
|
18
18
|
const props = withDefaults(defineProps<{ isMultiSelect?: boolean }>(), { isMultiSelect: false });
|
|
@@ -28,9 +28,9 @@ const nodes = computed(() => editorService?.get<MNode[]>('nodes'));
|
|
|
28
28
|
const parent = computed(() => editorService?.get('parent'));
|
|
29
29
|
const stage = computed(() => editorService?.get<StageCore>('stage'));
|
|
30
30
|
|
|
31
|
-
const stageContentMenu = inject<
|
|
31
|
+
const stageContentMenu = inject<(MenuButton | MenuComponent)[]>('stageContentMenu', []);
|
|
32
32
|
|
|
33
|
-
const menuData = reactive<
|
|
33
|
+
const menuData = reactive<(MenuButton | MenuComponent)[]>([
|
|
34
34
|
{
|
|
35
35
|
type: 'button',
|
|
36
36
|
text: '水平居中',
|