@tmagic/editor 1.0.0-rc.1 → 1.0.0-rc.12
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 +7 -3
- package/dist/tmagic-editor.es.js +304 -1405
- package/dist/tmagic-editor.es.js.map +1 -1
- package/dist/tmagic-editor.umd.js +304 -1407
- package/dist/tmagic-editor.umd.js.map +1 -1
- package/dist/types/src/Editor.vue.d.ts +42 -1
- package/dist/types/src/fields/Code.vue.d.ts +4 -4
- package/dist/types/src/fields/CodeLink.vue.d.ts +1 -3
- package/dist/types/src/layouts/Framework.vue.d.ts +15 -3
- package/dist/types/src/layouts/PropsPanel.vue.d.ts +2 -4
- package/dist/types/src/layouts/workspace/Workspace.vue.d.ts +3 -27
- package/dist/types/src/services/BaseService.d.ts +1 -1
- package/dist/types/src/services/editor.d.ts +6 -3
- package/dist/types/src/services/history.d.ts +1 -18
- package/dist/types/src/services/props.d.ts +8 -2
- package/dist/types/src/type.d.ts +9 -0
- package/dist/types/src/utils/editor.d.ts +0 -6
- package/dist/types/src/utils/props.d.ts +10 -1
- package/package.json +17 -18
- package/src/Editor.vue +41 -9
- package/src/components/ContentMenu.vue +59 -26
- package/src/layouts/CodeEditor.vue +1 -4
- package/src/layouts/Framework.vue +14 -1
- package/src/layouts/PropsPanel.vue +1 -1
- package/src/layouts/sidebar/LayerMenu.vue +3 -0
- package/src/layouts/sidebar/TabPane.vue +1 -1
- package/src/layouts/workspace/Stage.vue +14 -31
- package/src/layouts/workspace/ViewerMenu.vue +17 -2
- package/src/layouts/workspace/Workspace.vue +21 -26
- package/src/services/BaseService.ts +1 -1
- package/src/services/editor.ts +49 -14
- package/src/services/props.ts +64 -9
- package/src/theme/page-bar.scss +1 -0
- package/src/theme/props-panel.scss +6 -4
- package/src/theme/workspace.scss +4 -0
- package/src/type.ts +10 -0
- package/src/utils/editor.ts +7 -52
- package/src/utils/polyfills.ts +5 -19
- package/src/utils/props.ts +31 -7
- package/LICENSE +0 -5432
- package/coverage/clover.xml +0 -1560
- package/coverage/coverage-final.json +0 -36
- package/coverage/lcov-report/base.css +0 -224
- package/coverage/lcov-report/block-navigation.js +0 -87
- package/coverage/lcov-report/favicon.png +0 -0
- package/coverage/lcov-report/index.html +0 -206
- package/coverage/lcov-report/prettify.css +0 -1
- package/coverage/lcov-report/prettify.js +0 -2
- package/coverage/lcov-report/sort-arrow-sprite.png +0 -0
- package/coverage/lcov-report/sorter.js +0 -196
- package/coverage/lcov-report/src/Editor.vue.html +0 -787
- package/coverage/lcov-report/src/components/ContentMenu.vue.html +0 -406
- package/coverage/lcov-report/src/components/Icon.vue.html +0 -172
- package/coverage/lcov-report/src/components/ScrollViewer.vue.html +0 -283
- package/coverage/lcov-report/src/components/ToolButton.vue.html +0 -772
- package/coverage/lcov-report/src/components/index.html +0 -161
- package/coverage/lcov-report/src/index.html +0 -131
- package/coverage/lcov-report/src/layouts/AddPageBox.vue.html +0 -214
- package/coverage/lcov-report/src/layouts/Framework.vue.html +0 -304
- package/coverage/lcov-report/src/layouts/NavMenu.vue.html +0 -208
- package/coverage/lcov-report/src/layouts/PropsPanel.vue.html +0 -319
- package/coverage/lcov-report/src/layouts/Resizer.vue.html +0 -268
- package/coverage/lcov-report/src/layouts/index.html +0 -176
- package/coverage/lcov-report/src/layouts/sidebar/ComponentListPanel.vue.html +0 -358
- package/coverage/lcov-report/src/layouts/sidebar/LayerMenu.vue.html +0 -421
- package/coverage/lcov-report/src/layouts/sidebar/LayerPanel.vue.html +0 -775
- package/coverage/lcov-report/src/layouts/sidebar/Sidebar.vue.html +0 -226
- package/coverage/lcov-report/src/layouts/sidebar/TabPane.vue.html +0 -289
- package/coverage/lcov-report/src/layouts/sidebar/index.html +0 -176
- package/coverage/lcov-report/src/layouts/workspace/PageBar.vue.html +0 -718
- package/coverage/lcov-report/src/layouts/workspace/Stage.vue.html +0 -757
- package/coverage/lcov-report/src/layouts/workspace/ViewerMenu.vue.html +0 -532
- package/coverage/lcov-report/src/layouts/workspace/Workspace.vue.html +0 -586
- package/coverage/lcov-report/src/layouts/workspace/index.html +0 -161
- package/coverage/lcov-report/src/services/BaseService.ts.html +0 -643
- package/coverage/lcov-report/src/services/componentList.ts.html +0 -229
- package/coverage/lcov-report/src/services/editor.ts.html +0 -2077
- package/coverage/lcov-report/src/services/events.ts.html +0 -331
- package/coverage/lcov-report/src/services/history.ts.html +0 -478
- package/coverage/lcov-report/src/services/index.html +0 -206
- package/coverage/lcov-report/src/services/props.ts.html +0 -415
- package/coverage/lcov-report/src/services/ui.ts.html +0 -580
- package/coverage/lcov-report/src/type.ts.html +0 -850
- package/coverage/lcov-report/src/utils/compose.ts.html +0 -184
- package/coverage/lcov-report/src/utils/config.ts.html +0 -172
- package/coverage/lcov-report/src/utils/editor.ts.html +0 -838
- package/coverage/lcov-report/src/utils/index.html +0 -221
- package/coverage/lcov-report/src/utils/index.ts.html +0 -151
- package/coverage/lcov-report/src/utils/logger.ts.html +0 -226
- package/coverage/lcov-report/src/utils/props.ts.html +0 -796
- package/coverage/lcov-report/src/utils/scroll-viewer.ts.html +0 -733
- package/coverage/lcov-report/src/utils/undo-redo.ts.html +0 -313
- package/coverage/lcov.info +0 -3708
- package/dist/types/src/components/ToolButton.vue.d.ts +0 -46
- package/dist/types/src/fields/UISelect.vue.d.ts +0 -35
- package/dist/types/src/layouts/workspace/PageBar.vue.d.ts +0 -18
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<div v-if="menuData.length
|
|
2
|
+
<div v-if="menuData.length && visible" class="magic-editor-content-menu" ref="menu" :style="menuStyle">
|
|
3
3
|
<div>
|
|
4
4
|
<tool-button
|
|
5
5
|
v-for="(item, index) in menuData"
|
|
@@ -11,13 +11,19 @@
|
|
|
11
11
|
></tool-button>
|
|
12
12
|
</div>
|
|
13
13
|
<teleport to="body">
|
|
14
|
-
<content-menu
|
|
14
|
+
<content-menu
|
|
15
|
+
class="sub-menu"
|
|
16
|
+
ref="subMenu"
|
|
17
|
+
:menu-data="subMenuData"
|
|
18
|
+
:is-sub-menu="true"
|
|
19
|
+
@hide="hide"
|
|
20
|
+
></content-menu>
|
|
15
21
|
</teleport>
|
|
16
22
|
</div>
|
|
17
23
|
</template>
|
|
18
24
|
|
|
19
25
|
<script lang="ts">
|
|
20
|
-
import { defineComponent, nextTick, onMounted, PropType, ref } from 'vue';
|
|
26
|
+
import { defineComponent, nextTick, onMounted, onUnmounted, PropType, ref } from 'vue';
|
|
21
27
|
|
|
22
28
|
import { MenuButton, MenuItem } from '@editor/type';
|
|
23
29
|
|
|
@@ -31,9 +37,16 @@ export default defineComponent({
|
|
|
31
37
|
type: Array as PropType<MenuItem[]>,
|
|
32
38
|
default: () => [],
|
|
33
39
|
},
|
|
40
|
+
|
|
41
|
+
isSubMenu: {
|
|
42
|
+
type: Boolean,
|
|
43
|
+
default: false,
|
|
44
|
+
},
|
|
34
45
|
},
|
|
35
46
|
|
|
36
|
-
|
|
47
|
+
emits: ['hide', 'show'],
|
|
48
|
+
|
|
49
|
+
setup(props, { emit }) {
|
|
37
50
|
const menu = ref<HTMLDivElement>();
|
|
38
51
|
const subMenu = ref<any>();
|
|
39
52
|
const visible = ref(false);
|
|
@@ -44,20 +57,35 @@ export default defineComponent({
|
|
|
44
57
|
});
|
|
45
58
|
|
|
46
59
|
const hide = () => {
|
|
60
|
+
if (!visible.value) return;
|
|
61
|
+
|
|
47
62
|
visible.value = false;
|
|
63
|
+
subMenu.value?.hide();
|
|
64
|
+
|
|
65
|
+
emit('hide');
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
const hideHandler = (e: MouseEvent) => {
|
|
69
|
+
const target = e.target as HTMLElement | undefined;
|
|
70
|
+
if (!visible.value || !target) {
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
if (menu.value?.contains(target) || subMenu.value?.$el?.contains(target)) {
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
hide();
|
|
48
77
|
};
|
|
49
78
|
|
|
50
79
|
onMounted(() => {
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
);
|
|
80
|
+
if (props.isSubMenu) return;
|
|
81
|
+
|
|
82
|
+
globalThis.addEventListener('mousedown', hideHandler, true);
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
onUnmounted(() => {
|
|
86
|
+
if (props.isSubMenu) return;
|
|
87
|
+
|
|
88
|
+
globalThis.removeEventListener('mousedown', hideHandler, true);
|
|
61
89
|
});
|
|
62
90
|
|
|
63
91
|
return {
|
|
@@ -70,21 +98,26 @@ export default defineComponent({
|
|
|
70
98
|
hide,
|
|
71
99
|
|
|
72
100
|
show(e: MouseEvent) {
|
|
73
|
-
|
|
101
|
+
// 加settimeout是以为,如果菜单中的按钮监听的是mouseup,那么菜单显示出来时鼠标如果正好在菜单上就会马上触发按钮的mouseup
|
|
102
|
+
setTimeout(() => {
|
|
103
|
+
visible.value = true;
|
|
104
|
+
|
|
105
|
+
nextTick(() => {
|
|
106
|
+
const menuHeight = menu.value?.clientHeight || 0;
|
|
74
107
|
|
|
75
|
-
|
|
76
|
-
|
|
108
|
+
let top = e.clientY;
|
|
109
|
+
if (menuHeight + e.clientY > document.body.clientHeight) {
|
|
110
|
+
top = document.body.clientHeight - menuHeight;
|
|
111
|
+
}
|
|
77
112
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
113
|
+
menuStyle.value = {
|
|
114
|
+
top: `${top}px`,
|
|
115
|
+
left: `${e.clientX}px`,
|
|
116
|
+
};
|
|
82
117
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
};
|
|
87
|
-
});
|
|
118
|
+
emit('show');
|
|
119
|
+
});
|
|
120
|
+
}, 300);
|
|
88
121
|
},
|
|
89
122
|
|
|
90
123
|
showSubMenu(item: MenuItem) {
|
|
@@ -94,11 +94,7 @@ export default defineComponent({
|
|
|
94
94
|
const options = {
|
|
95
95
|
value: values.value,
|
|
96
96
|
language: props.language,
|
|
97
|
-
tabSize: 2,
|
|
98
97
|
theme: 'vs-dark',
|
|
99
|
-
fontFamily: 'dm, Menlo, Monaco, "Courier New", monospace',
|
|
100
|
-
fontSize: 14,
|
|
101
|
-
formatOnPaste: true,
|
|
102
98
|
...props.options,
|
|
103
99
|
};
|
|
104
100
|
|
|
@@ -117,6 +113,7 @@ export default defineComponent({
|
|
|
117
113
|
codeEditor.value.addEventListener('keydown', (e) => {
|
|
118
114
|
if (e.keyCode === 83 && (navigator.platform.match('Mac') ? e.metaKey : e.ctrlKey)) {
|
|
119
115
|
e.preventDefault();
|
|
116
|
+
e.stopPropagation();
|
|
120
117
|
emit('save', getEditorValue());
|
|
121
118
|
}
|
|
122
119
|
});
|
|
@@ -2,7 +2,13 @@
|
|
|
2
2
|
<div class="m-editor">
|
|
3
3
|
<slot name="nav" class="m-editor-nav-menu"></slot>
|
|
4
4
|
|
|
5
|
-
<magic-code-editor
|
|
5
|
+
<magic-code-editor
|
|
6
|
+
v-if="showSrc"
|
|
7
|
+
class="m-editor-content"
|
|
8
|
+
:init-values="root"
|
|
9
|
+
:options="codeOptions"
|
|
10
|
+
@save="saveCode"
|
|
11
|
+
></magic-code-editor>
|
|
6
12
|
|
|
7
13
|
<div class="m-editor-content" v-else>
|
|
8
14
|
<div class="m-editor-framework-left" :style="`width: ${columnWidth?.left}px`">
|
|
@@ -48,6 +54,13 @@ export default defineComponent({
|
|
|
48
54
|
Resizer,
|
|
49
55
|
},
|
|
50
56
|
|
|
57
|
+
props: {
|
|
58
|
+
codeOptions: {
|
|
59
|
+
type: Object,
|
|
60
|
+
default: () => ({}),
|
|
61
|
+
},
|
|
62
|
+
},
|
|
63
|
+
|
|
51
64
|
setup() {
|
|
52
65
|
const { editorService, uiService } = inject<Services>('services') || {};
|
|
53
66
|
|
|
@@ -22,6 +22,8 @@ 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<MenuItem[]>('layerContentMenu', []);
|
|
26
|
+
|
|
25
27
|
const createMenuItems = (group: ComponentGroup): MenuButton[] =>
|
|
26
28
|
group.items.map((component) => ({
|
|
27
29
|
text: component.text,
|
|
@@ -101,6 +103,7 @@ export default defineComponent({
|
|
|
101
103
|
node.value && services?.editorService.remove(node.value);
|
|
102
104
|
},
|
|
103
105
|
},
|
|
106
|
+
...layerContentMenu,
|
|
104
107
|
]),
|
|
105
108
|
|
|
106
109
|
show(e: MouseEvent) {
|
|
@@ -28,7 +28,6 @@ import {
|
|
|
28
28
|
markRaw,
|
|
29
29
|
onMounted,
|
|
30
30
|
onUnmounted,
|
|
31
|
-
PropType,
|
|
32
31
|
ref,
|
|
33
32
|
toRaw,
|
|
34
33
|
watch,
|
|
@@ -37,11 +36,11 @@ import {
|
|
|
37
36
|
import { cloneDeep } from 'lodash-es';
|
|
38
37
|
|
|
39
38
|
import type { MApp, MNode, MPage } from '@tmagic/schema';
|
|
40
|
-
import type {
|
|
39
|
+
import type { Runtime, SortEventData, UpdateEventData } from '@tmagic/stage';
|
|
41
40
|
import StageCore from '@tmagic/stage';
|
|
42
41
|
|
|
43
42
|
import ScrollViewer from '@editor/components/ScrollViewer.vue';
|
|
44
|
-
import { Layout, Services, StageRect } from '@editor/type';
|
|
43
|
+
import { Layout, Services, StageOptions, StageRect } from '@editor/type';
|
|
45
44
|
|
|
46
45
|
import ViewerMenu from './ViewerMenu.vue';
|
|
47
46
|
|
|
@@ -53,28 +52,9 @@ export default defineComponent({
|
|
|
53
52
|
ScrollViewer,
|
|
54
53
|
},
|
|
55
54
|
|
|
56
|
-
|
|
57
|
-
render: {
|
|
58
|
-
type: Function as PropType<() => HTMLDivElement>,
|
|
59
|
-
},
|
|
60
|
-
|
|
61
|
-
runtimeUrl: String,
|
|
62
|
-
|
|
63
|
-
canSelect: {
|
|
64
|
-
type: Function as PropType<(el: HTMLElement) => boolean | Promise<boolean>>,
|
|
65
|
-
default: (el: HTMLElement) => Boolean(el.id),
|
|
66
|
-
},
|
|
67
|
-
|
|
68
|
-
moveableOptions: {
|
|
69
|
-
type: [Object, Function] as PropType<MoveableOptions | ((core?: StageCore) => MoveableOptions)>,
|
|
70
|
-
default: () => (core?: StageCore) => ({
|
|
71
|
-
container: core?.renderer?.contentWindow?.document.getElementById('app'),
|
|
72
|
-
}),
|
|
73
|
-
},
|
|
74
|
-
},
|
|
75
|
-
|
|
76
|
-
setup(props) {
|
|
55
|
+
setup() {
|
|
77
56
|
const services = inject<Services>('services');
|
|
57
|
+
const stageOptions = inject<StageOptions>('stageOptions');
|
|
78
58
|
|
|
79
59
|
const stageWrap = ref<InstanceType<typeof ScrollViewer>>();
|
|
80
60
|
const stageContainer = ref<HTMLDivElement>();
|
|
@@ -94,14 +74,15 @@ export default defineComponent({
|
|
|
94
74
|
if (stage) return;
|
|
95
75
|
|
|
96
76
|
if (!stageContainer.value) return;
|
|
97
|
-
if (!(
|
|
77
|
+
if (!(stageOptions?.runtimeUrl || stageOptions?.render) || !root.value) return;
|
|
98
78
|
|
|
99
79
|
stage = new StageCore({
|
|
100
|
-
render:
|
|
101
|
-
runtimeUrl:
|
|
80
|
+
render: stageOptions.render,
|
|
81
|
+
runtimeUrl: stageOptions.runtimeUrl,
|
|
102
82
|
zoom: zoom.value,
|
|
83
|
+
autoScrollIntoView: stageOptions.autoScrollIntoView,
|
|
103
84
|
canSelect: (el, event, stop) => {
|
|
104
|
-
const elCanSelect =
|
|
85
|
+
const elCanSelect = stageOptions.canSelect(el);
|
|
105
86
|
// 在组件联动过程中不能再往下选择,返回并触发 ui-select
|
|
106
87
|
if (uiSelectMode.value && elCanSelect && event.type === 'mousedown') {
|
|
107
88
|
document.dispatchEvent(new CustomEvent('ui-select', { detail: el }));
|
|
@@ -110,7 +91,8 @@ export default defineComponent({
|
|
|
110
91
|
|
|
111
92
|
return elCanSelect;
|
|
112
93
|
},
|
|
113
|
-
moveableOptions:
|
|
94
|
+
moveableOptions: stageOptions.moveableOptions,
|
|
95
|
+
updateDragEl: stageOptions.updateDragEl,
|
|
114
96
|
});
|
|
115
97
|
|
|
116
98
|
services?.editorService.set('stage', markRaw(stage));
|
|
@@ -141,7 +123,7 @@ export default defineComponent({
|
|
|
141
123
|
stage?.on('runtime-ready', (rt) => {
|
|
142
124
|
runtime = rt;
|
|
143
125
|
// toRaw返回的值是一个引用而非快照,需要cloneDeep
|
|
144
|
-
root.value && runtime?.updateRootConfig(cloneDeep(toRaw(root.value)));
|
|
126
|
+
root.value && runtime?.updateRootConfig?.(cloneDeep(toRaw(root.value)));
|
|
145
127
|
page.value?.id && runtime?.updatePageId?.(page.value.id);
|
|
146
128
|
setTimeout(() => {
|
|
147
129
|
node.value && stage?.select(toRaw(node.value.id));
|
|
@@ -156,7 +138,7 @@ export default defineComponent({
|
|
|
156
138
|
|
|
157
139
|
watch(root, (root) => {
|
|
158
140
|
if (runtime && root) {
|
|
159
|
-
runtime.updateRootConfig(cloneDeep(toRaw(root)));
|
|
141
|
+
runtime.updateRootConfig?.(cloneDeep(toRaw(root)));
|
|
160
142
|
}
|
|
161
143
|
});
|
|
162
144
|
|
|
@@ -209,6 +191,7 @@ export default defineComponent({
|
|
|
209
191
|
const { scrollTop, scrollLeft } = stage.mask;
|
|
210
192
|
if (layout === Layout.ABSOLUTE) {
|
|
211
193
|
config.style = {
|
|
194
|
+
...(config.style || {}),
|
|
212
195
|
position: 'absolute',
|
|
213
196
|
top: e.clientY - containerRect.top + scrollTop,
|
|
214
197
|
left: e.clientX - containerRect.left + scrollLeft,
|
|
@@ -27,6 +27,8 @@ export default defineComponent({
|
|
|
27
27
|
const parent = computed(() => editorService?.get('parent'));
|
|
28
28
|
const isPage = computed(() => node.value?.type === NodeType.PAGE);
|
|
29
29
|
|
|
30
|
+
const stageContentMenu = inject<MenuItem[]>('stageContentMenu', []);
|
|
31
|
+
|
|
30
32
|
onMounted(() => {
|
|
31
33
|
const data = globalThis.localStorage.getItem(COPY_STORAGE_KEY);
|
|
32
34
|
canPaste.value = data !== 'undefined' && !!data;
|
|
@@ -69,8 +71,20 @@ export default defineComponent({
|
|
|
69
71
|
text: '粘贴',
|
|
70
72
|
display: () => canPaste.value,
|
|
71
73
|
handler: () => {
|
|
72
|
-
const
|
|
73
|
-
|
|
74
|
+
const stage = editorService?.get<StageCore>('stage');
|
|
75
|
+
|
|
76
|
+
const rect = menu.value?.$el.getBoundingClientRect();
|
|
77
|
+
const parentRect = stage?.container?.getBoundingClientRect();
|
|
78
|
+
let left = (rect?.left || 0) - (parentRect?.left || 0);
|
|
79
|
+
let top = (rect?.top || 0) - (parentRect?.top || 0);
|
|
80
|
+
|
|
81
|
+
if (node.value?.items && stage) {
|
|
82
|
+
const parentEl = stage.renderer.contentWindow?.document.getElementById(`${node.value.id}`);
|
|
83
|
+
const parentElRect = parentEl?.getBoundingClientRect();
|
|
84
|
+
left = left - (parentElRect?.left || 0);
|
|
85
|
+
top = top - (parentElRect?.top || 0);
|
|
86
|
+
}
|
|
87
|
+
|
|
74
88
|
editorService?.paste({ left, top });
|
|
75
89
|
},
|
|
76
90
|
},
|
|
@@ -138,6 +152,7 @@ export default defineComponent({
|
|
|
138
152
|
editorService?.get<StageCore>('stage').clearGuides();
|
|
139
153
|
},
|
|
140
154
|
},
|
|
155
|
+
...stageContentMenu,
|
|
141
156
|
]),
|
|
142
157
|
|
|
143
158
|
show(e: MouseEvent) {
|
|
@@ -1,12 +1,6 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div class="m-editor-workspace" tabindex="1" ref="workspace">
|
|
3
|
-
<magic-stage
|
|
4
|
-
:key="page?.id"
|
|
5
|
-
:runtime-url="runtimeUrl"
|
|
6
|
-
:render="render"
|
|
7
|
-
:moveable-options="moveableOptions"
|
|
8
|
-
:can-select="canSelect"
|
|
9
|
-
></magic-stage>
|
|
3
|
+
<magic-stage :key="page?.id"></magic-stage>
|
|
10
4
|
|
|
11
5
|
<slot name="workspace-content"></slot>
|
|
12
6
|
|
|
@@ -18,12 +12,10 @@
|
|
|
18
12
|
</template>
|
|
19
13
|
|
|
20
14
|
<script lang="ts">
|
|
21
|
-
import { computed, defineComponent, inject, onMounted, onUnmounted,
|
|
15
|
+
import { computed, defineComponent, inject, onMounted, onUnmounted, ref } from 'vue';
|
|
22
16
|
import KeyController from 'keycon';
|
|
23
17
|
|
|
24
18
|
import type { MNode, MPage } from '@tmagic/schema';
|
|
25
|
-
import type { MoveableOptions } from '@tmagic/stage';
|
|
26
|
-
import StageCore from '@tmagic/stage';
|
|
27
19
|
import { isPage } from '@tmagic/utils';
|
|
28
20
|
|
|
29
21
|
import type { Services } from '@editor/type';
|
|
@@ -39,22 +31,6 @@ export default defineComponent({
|
|
|
39
31
|
MagicStage,
|
|
40
32
|
},
|
|
41
33
|
|
|
42
|
-
props: {
|
|
43
|
-
runtimeUrl: String,
|
|
44
|
-
|
|
45
|
-
render: {
|
|
46
|
-
type: Function as PropType<() => HTMLDivElement>,
|
|
47
|
-
},
|
|
48
|
-
|
|
49
|
-
moveableOptions: {
|
|
50
|
-
type: [Object, Function] as PropType<MoveableOptions | ((core?: StageCore) => MoveableOptions)>,
|
|
51
|
-
},
|
|
52
|
-
|
|
53
|
-
canSelect: {
|
|
54
|
-
type: Function as PropType<(el: HTMLElement) => boolean | Promise<boolean>>,
|
|
55
|
-
},
|
|
56
|
-
},
|
|
57
|
-
|
|
58
34
|
setup() {
|
|
59
35
|
const services = inject<Services>('services');
|
|
60
36
|
const workspace = ref<HTMLDivElement>();
|
|
@@ -65,8 +41,13 @@ export default defineComponent({
|
|
|
65
41
|
workspace.value?.focus();
|
|
66
42
|
};
|
|
67
43
|
|
|
44
|
+
const mouseleaveHandler = () => {
|
|
45
|
+
workspace.value?.blur();
|
|
46
|
+
};
|
|
47
|
+
|
|
68
48
|
onMounted(() => {
|
|
69
49
|
workspace.value?.addEventListener('mouseenter', mouseenterHandler);
|
|
50
|
+
workspace.value?.addEventListener('mouseleave', mouseleaveHandler);
|
|
70
51
|
|
|
71
52
|
keycon = new KeyController(workspace.value);
|
|
72
53
|
|
|
@@ -80,6 +61,11 @@ export default defineComponent({
|
|
|
80
61
|
if (!node.value || isPage(node.value)) return;
|
|
81
62
|
services?.editorService.remove(node.value);
|
|
82
63
|
})
|
|
64
|
+
.keyup('backspace', (e) => {
|
|
65
|
+
e.inputEvent.preventDefault();
|
|
66
|
+
if (!node.value || isPage(node.value)) return;
|
|
67
|
+
services?.editorService.remove(node.value);
|
|
68
|
+
})
|
|
83
69
|
.keydown([ctrl, 'c'], (e) => {
|
|
84
70
|
e.inputEvent.preventDefault();
|
|
85
71
|
node.value && services?.editorService.copy(node.value);
|
|
@@ -146,14 +132,23 @@ export default defineComponent({
|
|
|
146
132
|
e.inputEvent.preventDefault();
|
|
147
133
|
services?.uiService.zoom(0.1);
|
|
148
134
|
})
|
|
135
|
+
.keydown([ctrl, 'numpadplus'], (e) => {
|
|
136
|
+
e.inputEvent.preventDefault();
|
|
137
|
+
services?.uiService.zoom(0.1);
|
|
138
|
+
})
|
|
149
139
|
.keydown([ctrl, '-'], (e) => {
|
|
150
140
|
e.inputEvent.preventDefault();
|
|
151
141
|
services?.uiService.zoom(-0.1);
|
|
142
|
+
})
|
|
143
|
+
.keydown([ctrl, 'numpad-'], (e) => {
|
|
144
|
+
e.inputEvent.preventDefault();
|
|
145
|
+
services?.uiService.zoom(-0.1);
|
|
152
146
|
});
|
|
153
147
|
});
|
|
154
148
|
|
|
155
149
|
onUnmounted(() => {
|
|
156
150
|
workspace.value?.removeEventListener('mouseenter', mouseenterHandler);
|
|
151
|
+
workspace.value?.removeEventListener('mouseleave', mouseleaveHandler);
|
|
157
152
|
keycon.destroy();
|
|
158
153
|
});
|
|
159
154
|
|
|
@@ -91,7 +91,7 @@ const doAction = async (
|
|
|
91
91
|
* editorService.afterAdd();
|
|
92
92
|
* }
|
|
93
93
|
*
|
|
94
|
-
* 调用时的参数会透传到before方法的参数中, 然后before的return 会作为原方法的参数和after的参数,after
|
|
94
|
+
* 调用时的参数会透传到before方法的参数中, 然后before的return 会作为原方法的参数和after的参数,after第一个参数则是原方法的return值;
|
|
95
95
|
* 如需终止后续方法调用可以return new Error();
|
|
96
96
|
*
|
|
97
97
|
* 方法2:
|
package/src/services/editor.ts
CHANGED
|
@@ -33,11 +33,11 @@ import {
|
|
|
33
33
|
change2Fixed,
|
|
34
34
|
COPY_STORAGE_KEY,
|
|
35
35
|
Fixed2Other,
|
|
36
|
+
generatePageNameByApp,
|
|
36
37
|
getNodeIndex,
|
|
37
38
|
initPosition,
|
|
38
39
|
isFixed,
|
|
39
40
|
setLayout,
|
|
40
|
-
setNewItemId,
|
|
41
41
|
} from '@editor/utils/editor';
|
|
42
42
|
import { log } from '@editor/utils/logger';
|
|
43
43
|
|
|
@@ -108,10 +108,14 @@ class Editor extends BaseService {
|
|
|
108
108
|
/**
|
|
109
109
|
* 根据id获取组件、组件的父组件以及组件所属的页面节点
|
|
110
110
|
* @param {number | string} id 组件id
|
|
111
|
+
* @param {boolean} raw 是否使用toRaw
|
|
111
112
|
* @returns {EditorNodeInfo}
|
|
112
113
|
*/
|
|
113
|
-
public getNodeInfo(id: Id): EditorNodeInfo {
|
|
114
|
-
|
|
114
|
+
public getNodeInfo(id: Id, raw = true): EditorNodeInfo {
|
|
115
|
+
let root = this.get<MApp | null>('root');
|
|
116
|
+
if (raw) {
|
|
117
|
+
root = toRaw(root);
|
|
118
|
+
}
|
|
115
119
|
if (!root) return {};
|
|
116
120
|
|
|
117
121
|
if (id === root.id) {
|
|
@@ -141,21 +145,23 @@ class Editor extends BaseService {
|
|
|
141
145
|
/**
|
|
142
146
|
* 根据ID获取指点节点配置
|
|
143
147
|
* @param id 组件ID
|
|
148
|
+
* @param {boolean} raw 是否使用toRaw
|
|
144
149
|
* @returns 组件节点配置
|
|
145
150
|
*/
|
|
146
|
-
public getNodeById(id: Id): MNode | undefined {
|
|
147
|
-
const { node } = this.getNodeInfo(id);
|
|
151
|
+
public getNodeById(id: Id, raw = true): MNode | undefined {
|
|
152
|
+
const { node } = this.getNodeInfo(id, raw);
|
|
148
153
|
return node;
|
|
149
154
|
}
|
|
150
155
|
|
|
151
156
|
/**
|
|
152
157
|
* 根据ID获取指点节点的父节点配置
|
|
153
158
|
* @param id 组件ID
|
|
159
|
+
* @param {boolean} raw 是否使用toRaw
|
|
154
160
|
* @returns 指点组件的父节点配置
|
|
155
161
|
*/
|
|
156
|
-
public getParentById(id: Id): MContainer | undefined {
|
|
162
|
+
public getParentById(id: Id, raw = true): MContainer | undefined {
|
|
157
163
|
if (!this.get<MApp | null>('root')) return;
|
|
158
|
-
const { parent } = this.getNodeInfo(id);
|
|
164
|
+
const { parent } = this.getNodeInfo(id, raw);
|
|
159
165
|
return parent;
|
|
160
166
|
}
|
|
161
167
|
|
|
@@ -194,6 +200,20 @@ class Editor extends BaseService {
|
|
|
194
200
|
historyService.empty();
|
|
195
201
|
}
|
|
196
202
|
|
|
203
|
+
if (node?.id) {
|
|
204
|
+
this.get<StageCore>('stage')
|
|
205
|
+
?.renderer.runtime?.getApp?.()
|
|
206
|
+
?.emit(
|
|
207
|
+
'editor:select',
|
|
208
|
+
{
|
|
209
|
+
node,
|
|
210
|
+
page,
|
|
211
|
+
parent,
|
|
212
|
+
},
|
|
213
|
+
getNodePath(node.id, this.get<MApp>('root').items),
|
|
214
|
+
);
|
|
215
|
+
}
|
|
216
|
+
|
|
197
217
|
this.emit('select', node);
|
|
198
218
|
|
|
199
219
|
return node!;
|
|
@@ -265,7 +285,7 @@ class Editor extends BaseService {
|
|
|
265
285
|
} else if (curNode.items) {
|
|
266
286
|
parentNode = curNode;
|
|
267
287
|
} else {
|
|
268
|
-
parentNode = this.getParentById(curNode.id);
|
|
288
|
+
parentNode = this.getParentById(curNode.id, false);
|
|
269
289
|
}
|
|
270
290
|
|
|
271
291
|
if (!parentNode) throw new Error('未找到父元素');
|
|
@@ -318,7 +338,7 @@ class Editor extends BaseService {
|
|
|
318
338
|
|
|
319
339
|
if (!root) throw new Error('没有root');
|
|
320
340
|
|
|
321
|
-
const { parent, node: curNode } = this.getNodeInfo(node.id);
|
|
341
|
+
const { parent, node: curNode } = this.getNodeInfo(node.id, false);
|
|
322
342
|
|
|
323
343
|
if (!parent || !curNode) throw new Error('找不要删除的节点');
|
|
324
344
|
|
|
@@ -370,7 +390,7 @@ class Editor extends BaseService {
|
|
|
370
390
|
public async update(config: MNode): Promise<MNode> {
|
|
371
391
|
if (!config?.id) throw new Error('没有配置或者配置缺少id值');
|
|
372
392
|
|
|
373
|
-
const info = this.getNodeInfo(config.id);
|
|
393
|
+
const info = this.getNodeInfo(config.id, false);
|
|
374
394
|
|
|
375
395
|
if (!info.node) throw new Error(`获取不到id为${config.id}的节点`);
|
|
376
396
|
|
|
@@ -480,7 +500,7 @@ class Editor extends BaseService {
|
|
|
480
500
|
return;
|
|
481
501
|
}
|
|
482
502
|
|
|
483
|
-
setNewItemId(config, this.get('root'));
|
|
503
|
+
await propsService.setNewItemId(config, this.get('root'));
|
|
484
504
|
if (config.style) {
|
|
485
505
|
config.style = {
|
|
486
506
|
...config.style,
|
|
@@ -488,6 +508,10 @@ class Editor extends BaseService {
|
|
|
488
508
|
};
|
|
489
509
|
}
|
|
490
510
|
|
|
511
|
+
if (isPage(config)) {
|
|
512
|
+
config.name = generatePageNameByApp(this.get('root'));
|
|
513
|
+
}
|
|
514
|
+
|
|
491
515
|
return await this.add(config);
|
|
492
516
|
}
|
|
493
517
|
|
|
@@ -504,7 +528,18 @@ class Editor extends BaseService {
|
|
|
504
528
|
return;
|
|
505
529
|
}
|
|
506
530
|
|
|
507
|
-
if (
|
|
531
|
+
if (!node.style) return;
|
|
532
|
+
|
|
533
|
+
const stage = this.get<StageCore>('stage');
|
|
534
|
+
const doc = stage?.renderer.contentWindow?.document;
|
|
535
|
+
|
|
536
|
+
if (doc) {
|
|
537
|
+
const parentEl = doc.getElementById(`${parent.id}`);
|
|
538
|
+
const el = doc.getElementById(`${node.id}`);
|
|
539
|
+
if (parentEl && el) {
|
|
540
|
+
node.style.left = (parentEl.clientWidth - el.clientWidth) / 2;
|
|
541
|
+
}
|
|
542
|
+
} else if (parent.style && isNumber(parent.style?.width) && isNumber(node.style?.width)) {
|
|
508
543
|
node.style.left = (parent.style.width - node.style.width) / 2;
|
|
509
544
|
}
|
|
510
545
|
|
|
@@ -526,9 +561,9 @@ class Editor extends BaseService {
|
|
|
526
561
|
const brothers: MNode[] = parent?.items || [];
|
|
527
562
|
const index = brothers.findIndex((item) => `${item.id}` === `${node?.id}`);
|
|
528
563
|
|
|
529
|
-
if (offset === LayerOffset.
|
|
564
|
+
if (offset === LayerOffset.TOP) {
|
|
530
565
|
brothers.splice(brothers.length - 1, 0, brothers.splice(index, 1)[0]);
|
|
531
|
-
} else if (offset === LayerOffset.
|
|
566
|
+
} else if (offset === LayerOffset.BOTTOM) {
|
|
532
567
|
brothers.splice(0, 0, brothers.splice(index, 1)[0]);
|
|
533
568
|
} else {
|
|
534
569
|
brothers.splice(index + parseInt(`${offset}`, 10), 0, brothers.splice(index, 1)[0]);
|