@tmagic/editor 1.0.0-beta.11 → 1.0.0-beta.14
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 +1540 -0
- package/coverage/coverage-final.json +35 -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 +787 -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 +304 -0
- package/coverage/lcov-report/src/layouts/NavMenu.vue.html +208 -0
- package/coverage/lcov-report/src/layouts/PropsPanel.vue.html +316 -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 +343 -0
- package/coverage/lcov-report/src/layouts/sidebar/index.html +161 -0
- package/coverage/lcov-report/src/layouts/workspace/PageBar.vue.html +718 -0
- package/coverage/lcov-report/src/layouts/workspace/Stage.vue.html +757 -0
- package/coverage/lcov-report/src/layouts/workspace/ViewerMenu.vue.html +532 -0
- package/coverage/lcov-report/src/layouts/workspace/Workspace.vue.html +586 -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 +514 -0
- package/coverage/lcov-report/src/type.ts.html +844 -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 +3676 -0
- package/dist/style.css +42 -20
- package/dist/tmagic-editor.es.js +972 -599
- package/dist/tmagic-editor.es.js.map +1 -1
- package/dist/tmagic-editor.umd.js +974 -601
- package/dist/tmagic-editor.umd.js.map +1 -1
- package/dist/types/src/Editor.vue.d.ts +1 -1
- package/dist/types/src/components/ToolButton.vue.d.ts +12 -1
- package/dist/types/src/index.d.ts +1 -0
- package/dist/types/src/layouts/sidebar/ComponentListPanel.vue.d.ts +2 -1
- package/dist/types/src/layouts/workspace/PageBar.vue.d.ts +2 -0
- package/dist/types/src/layouts/workspace/Workspace.vue.d.ts +2 -1
- package/dist/types/src/services/editor.d.ts +5 -2
- 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 +1 -0
- package/dist/types/src/type.d.ts +9 -9
- package/dist/types/src/utils/editor.d.ts +4 -3
- package/dist/types/src/utils/polyfills.d.ts +0 -0
- package/package.json +29 -9
- package/src/components/ContentMenu.vue +107 -0
- package/src/components/ScrollViewer.vue +1 -1
- package/src/components/ToolButton.vue +69 -30
- package/src/index.ts +2 -0
- package/src/layouts/Framework.vue +6 -6
- package/src/layouts/PropsPanel.vue +1 -1
- package/src/layouts/sidebar/ComponentListPanel.vue +25 -3
- package/src/layouts/sidebar/LayerMenu.vue +91 -71
- package/src/layouts/sidebar/LayerPanel.vue +23 -49
- package/src/layouts/workspace/PageBar.vue +35 -6
- package/src/layouts/workspace/Stage.vue +41 -44
- package/src/layouts/workspace/ViewerMenu.vue +104 -67
- package/src/layouts/workspace/Workspace.vue +106 -3
- package/src/services/BaseService.ts +1 -1
- package/src/services/editor.ts +104 -12
- package/src/services/history.ts +7 -0
- package/src/services/props.ts +3 -3
- package/src/services/ui.ts +5 -0
- package/src/theme/common/var.scss +1 -0
- package/src/theme/component-list-panel.scss +2 -0
- package/src/theme/content-menu.scss +33 -26
- package/src/theme/layer-panel.scss +2 -1
- package/src/theme/page-bar.scss +22 -1
- package/src/type.ts +9 -9
- package/src/utils/editor.ts +31 -6
- package/{vite.config.ts → src/utils/polyfills.ts} +4 -12
- package/src/utils/props.ts +20 -1
- package/dist/types/src/layouts/sidebar/LayerPanel.vue.d.ts +0 -980
- package/dist/types/src/layouts/workspace/Stage.vue.d.ts +0 -188
- package/dist/types/src/layouts/workspace/ViewerMenu.vue.d.ts +0 -18
- package/tsconfig.json +0 -9
|
@@ -1,47 +1,31 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<
|
|
3
|
-
<div>
|
|
4
|
-
<div class="magic-editor-content-menu-item" @click="() => center()" v-if="canCenter">水平居中</div>
|
|
5
|
-
<div class="magic-editor-content-menu-item" @click="() => copy()">复制</div>
|
|
6
|
-
<div class="magic-editor-content-menu-item" @click="paste" v-if="canPaste">粘贴</div>
|
|
7
|
-
<template v-if="canMoveZPos">
|
|
8
|
-
<div class="separation"></div>
|
|
9
|
-
<div class="magic-editor-content-menu-item" @click="topItem">上移一层</div>
|
|
10
|
-
<div class="magic-editor-content-menu-item" @click="bottomItem">下移一层</div>
|
|
11
|
-
<div class="magic-editor-content-menu-item" @click="top">置顶</div>
|
|
12
|
-
<div class="magic-editor-content-menu-item" @click="bottom">置底</div>
|
|
13
|
-
</template>
|
|
14
|
-
<template v-if="canDelete">
|
|
15
|
-
<div class="separation"></div>
|
|
16
|
-
<div class="magic-editor-content-menu-item" @click="() => remove()">删除</div>
|
|
17
|
-
</template>
|
|
18
|
-
<div class="separation"></div>
|
|
19
|
-
<div class="magic-editor-content-menu-item" @click="clearGuides">清空参考线</div>
|
|
20
|
-
</div>
|
|
21
|
-
</div>
|
|
2
|
+
<content-menu :menu-data="menuData" ref="menu"></content-menu>
|
|
22
3
|
</template>
|
|
23
4
|
|
|
24
5
|
<script lang="ts">
|
|
25
|
-
import { computed, defineComponent, inject, onMounted, ref, watch } from 'vue';
|
|
6
|
+
import { computed, defineComponent, inject, markRaw, onMounted, reactive, ref, watch } from 'vue';
|
|
7
|
+
import { Bottom, Delete, DocumentCopy, Top } from '@element-plus/icons';
|
|
26
8
|
|
|
27
9
|
import { NodeType } from '@tmagic/schema';
|
|
28
10
|
import type StageCore from '@tmagic/stage';
|
|
29
11
|
|
|
30
|
-
import
|
|
12
|
+
import ContentMenu from '@editor/components/ContentMenu.vue';
|
|
13
|
+
import { LayerOffset, Layout, MenuItem, Services } from '@editor/type';
|
|
31
14
|
import { COPY_STORAGE_KEY } from '@editor/utils/editor';
|
|
32
15
|
|
|
33
16
|
export default defineComponent({
|
|
34
|
-
|
|
17
|
+
components: { ContentMenu },
|
|
35
18
|
|
|
36
19
|
setup() {
|
|
37
20
|
const services = inject<Services>('services');
|
|
38
21
|
const editorService = services?.editorService;
|
|
39
|
-
const menu = ref<
|
|
22
|
+
const menu = ref<InstanceType<typeof ContentMenu>>();
|
|
40
23
|
const canPaste = ref(false);
|
|
41
24
|
const canCenter = ref(false);
|
|
42
25
|
|
|
43
26
|
const node = computed(() => editorService?.get('node'));
|
|
44
27
|
const parent = computed(() => editorService?.get('parent'));
|
|
28
|
+
const isPage = computed(() => node.value?.type === NodeType.PAGE);
|
|
45
29
|
|
|
46
30
|
onMounted(() => {
|
|
47
31
|
const data = globalThis.localStorage.getItem(COPY_STORAGE_KEY);
|
|
@@ -62,49 +46,102 @@ export default defineComponent({
|
|
|
62
46
|
|
|
63
47
|
return {
|
|
64
48
|
menu,
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
49
|
+
menuData: reactive<MenuItem[]>([
|
|
50
|
+
{
|
|
51
|
+
type: 'button',
|
|
52
|
+
text: '水平居中',
|
|
53
|
+
display: () => canCenter.value,
|
|
54
|
+
handler: () => {
|
|
55
|
+
node.value && editorService?.alignCenter(node.value);
|
|
56
|
+
},
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
type: 'button',
|
|
60
|
+
text: '复制',
|
|
61
|
+
icon: markRaw(DocumentCopy),
|
|
62
|
+
handler: () => {
|
|
63
|
+
node.value && editorService?.copy(node.value);
|
|
64
|
+
canPaste.value = true;
|
|
65
|
+
},
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
type: 'button',
|
|
69
|
+
text: '粘贴',
|
|
70
|
+
display: () => canPaste.value,
|
|
71
|
+
handler: () => {
|
|
72
|
+
const top = menu.value?.$el.offsetTop || 0;
|
|
73
|
+
const left = menu.value?.$el.offsetLeft || 0;
|
|
74
|
+
editorService?.paste({ left, top });
|
|
75
|
+
},
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
type: 'divider',
|
|
79
|
+
direction: 'horizontal',
|
|
80
|
+
display: () => !isPage.value,
|
|
81
|
+
},
|
|
82
|
+
{
|
|
83
|
+
type: 'button',
|
|
84
|
+
text: '上移一层',
|
|
85
|
+
icon: markRaw(Top),
|
|
86
|
+
display: () => !isPage.value,
|
|
87
|
+
handler: () => {
|
|
88
|
+
editorService?.moveLayer(1);
|
|
89
|
+
},
|
|
90
|
+
},
|
|
91
|
+
{
|
|
92
|
+
type: 'button',
|
|
93
|
+
text: '下移一层',
|
|
94
|
+
icon: markRaw(Bottom),
|
|
95
|
+
display: () => !isPage.value,
|
|
96
|
+
handler: () => {
|
|
97
|
+
editorService?.moveLayer(-1);
|
|
98
|
+
},
|
|
99
|
+
},
|
|
100
|
+
{
|
|
101
|
+
type: 'button',
|
|
102
|
+
text: '置顶',
|
|
103
|
+
display: () => !isPage.value,
|
|
104
|
+
handler: () => {
|
|
105
|
+
editorService?.moveLayer(LayerOffset.TOP);
|
|
106
|
+
},
|
|
107
|
+
},
|
|
108
|
+
{
|
|
109
|
+
type: 'button',
|
|
110
|
+
text: '置底',
|
|
111
|
+
display: () => !isPage.value,
|
|
112
|
+
handler: () => {
|
|
113
|
+
editorService?.moveLayer(LayerOffset.BOTTOM);
|
|
114
|
+
},
|
|
115
|
+
},
|
|
116
|
+
{
|
|
117
|
+
type: 'divider',
|
|
118
|
+
direction: 'horizontal',
|
|
119
|
+
display: () => !isPage.value,
|
|
120
|
+
},
|
|
121
|
+
{
|
|
122
|
+
type: 'button',
|
|
123
|
+
text: '删除',
|
|
124
|
+
icon: Delete,
|
|
125
|
+
display: () => !isPage.value,
|
|
126
|
+
handler: () => {
|
|
127
|
+
node.value && editorService?.remove(node.value);
|
|
128
|
+
},
|
|
129
|
+
},
|
|
130
|
+
{
|
|
131
|
+
type: 'divider',
|
|
132
|
+
direction: 'horizontal',
|
|
133
|
+
},
|
|
134
|
+
{
|
|
135
|
+
type: 'button',
|
|
136
|
+
text: '清空参考线',
|
|
137
|
+
handler: () => {
|
|
138
|
+
editorService?.get<StageCore>('stage').clearGuides();
|
|
139
|
+
},
|
|
140
|
+
},
|
|
141
|
+
]),
|
|
142
|
+
|
|
143
|
+
show(e: MouseEvent) {
|
|
144
|
+
menu.value?.show(e);
|
|
108
145
|
},
|
|
109
146
|
};
|
|
110
147
|
},
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<div class="m-editor-workspace">
|
|
2
|
+
<div class="m-editor-workspace" tabindex="1" ref="workspace">
|
|
3
3
|
<magic-stage
|
|
4
4
|
:key="page?.id"
|
|
5
5
|
:runtime-url="runtimeUrl"
|
|
@@ -18,11 +18,13 @@
|
|
|
18
18
|
</template>
|
|
19
19
|
|
|
20
20
|
<script lang="ts">
|
|
21
|
-
import { computed, defineComponent, inject, PropType } from 'vue';
|
|
21
|
+
import { computed, defineComponent, inject, onMounted, onUnmounted, PropType, ref } from 'vue';
|
|
22
|
+
import KeyController from 'keycon';
|
|
22
23
|
|
|
23
|
-
import type { MPage } from '@tmagic/schema';
|
|
24
|
+
import type { MNode, MPage } from '@tmagic/schema';
|
|
24
25
|
import type { MoveableOptions } from '@tmagic/stage';
|
|
25
26
|
import StageCore from '@tmagic/stage';
|
|
27
|
+
import { isPage } from '@tmagic/utils';
|
|
26
28
|
|
|
27
29
|
import type { Services } from '@editor/type';
|
|
28
30
|
|
|
@@ -55,8 +57,109 @@ export default defineComponent({
|
|
|
55
57
|
|
|
56
58
|
setup() {
|
|
57
59
|
const services = inject<Services>('services');
|
|
60
|
+
const workspace = ref<HTMLDivElement>();
|
|
61
|
+
const node = computed(() => services?.editorService.get<MNode>('node'));
|
|
62
|
+
let keycon: KeyController;
|
|
63
|
+
|
|
64
|
+
const mouseenterHandler = () => {
|
|
65
|
+
workspace.value?.focus();
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
onMounted(() => {
|
|
69
|
+
workspace.value?.addEventListener('mouseenter', mouseenterHandler);
|
|
70
|
+
|
|
71
|
+
keycon = new KeyController(workspace.value);
|
|
72
|
+
|
|
73
|
+
const isMac = /mac os x/.test(navigator.userAgent.toLowerCase());
|
|
74
|
+
|
|
75
|
+
const ctrl = isMac ? 'meta' : 'ctrl';
|
|
76
|
+
|
|
77
|
+
keycon
|
|
78
|
+
.keyup('delete', (e) => {
|
|
79
|
+
e.inputEvent.preventDefault();
|
|
80
|
+
if (!node.value || isPage(node.value)) return;
|
|
81
|
+
services?.editorService.remove(node.value);
|
|
82
|
+
})
|
|
83
|
+
.keydown([ctrl, 'c'], (e) => {
|
|
84
|
+
e.inputEvent.preventDefault();
|
|
85
|
+
node.value && services?.editorService.copy(node.value);
|
|
86
|
+
})
|
|
87
|
+
.keydown([ctrl, 'v'], (e) => {
|
|
88
|
+
e.inputEvent.preventDefault();
|
|
89
|
+
node.value && services?.editorService.paste();
|
|
90
|
+
})
|
|
91
|
+
.keydown([ctrl, 'x'], (e) => {
|
|
92
|
+
e.inputEvent.preventDefault();
|
|
93
|
+
if (!node.value || isPage(node.value)) return;
|
|
94
|
+
services?.editorService.copy(node.value);
|
|
95
|
+
services?.editorService.remove(node.value);
|
|
96
|
+
})
|
|
97
|
+
.keydown([ctrl, 'z'], (e) => {
|
|
98
|
+
e.inputEvent.preventDefault();
|
|
99
|
+
services?.editorService.undo();
|
|
100
|
+
})
|
|
101
|
+
.keydown([ctrl, 'shift', 'z'], (e) => {
|
|
102
|
+
e.inputEvent.preventDefault();
|
|
103
|
+
services?.editorService.redo();
|
|
104
|
+
})
|
|
105
|
+
.keydown('up', (e) => {
|
|
106
|
+
e.inputEvent.preventDefault();
|
|
107
|
+
services?.editorService.move(0, -1);
|
|
108
|
+
})
|
|
109
|
+
.keydown('down', (e) => {
|
|
110
|
+
e.inputEvent.preventDefault();
|
|
111
|
+
services?.editorService.move(0, 1);
|
|
112
|
+
})
|
|
113
|
+
.keydown('left', (e) => {
|
|
114
|
+
e.inputEvent.preventDefault();
|
|
115
|
+
services?.editorService.move(-1, 0);
|
|
116
|
+
})
|
|
117
|
+
.keydown('right', (e) => {
|
|
118
|
+
e.inputEvent.preventDefault();
|
|
119
|
+
services?.editorService.move(1, 0);
|
|
120
|
+
})
|
|
121
|
+
.keydown([ctrl, 'up'], (e) => {
|
|
122
|
+
e.inputEvent.preventDefault();
|
|
123
|
+
services?.editorService.move(0, -10);
|
|
124
|
+
})
|
|
125
|
+
.keydown([ctrl, 'down'], (e) => {
|
|
126
|
+
e.inputEvent.preventDefault();
|
|
127
|
+
services?.editorService.move(0, 10);
|
|
128
|
+
})
|
|
129
|
+
.keydown([ctrl, 'left'], (e) => {
|
|
130
|
+
e.inputEvent.preventDefault();
|
|
131
|
+
services?.editorService.move(-10, 0);
|
|
132
|
+
})
|
|
133
|
+
.keydown([ctrl, 'right'], (e) => {
|
|
134
|
+
e.inputEvent.preventDefault();
|
|
135
|
+
services?.editorService.move(10, 0);
|
|
136
|
+
})
|
|
137
|
+
.keydown('tab', (e) => {
|
|
138
|
+
e.inputEvent.preventDefault();
|
|
139
|
+
services?.editorService.selectNextNode();
|
|
140
|
+
})
|
|
141
|
+
.keydown([ctrl, 'tab'], (e) => {
|
|
142
|
+
e.inputEvent.preventDefault();
|
|
143
|
+
services?.editorService.selectNextPage();
|
|
144
|
+
})
|
|
145
|
+
.keydown([ctrl, '='], (e) => {
|
|
146
|
+
e.inputEvent.preventDefault();
|
|
147
|
+
services?.uiService.zoom(0.1);
|
|
148
|
+
})
|
|
149
|
+
.keydown([ctrl, '-'], (e) => {
|
|
150
|
+
e.inputEvent.preventDefault();
|
|
151
|
+
services?.uiService.zoom(-0.1);
|
|
152
|
+
});
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
onUnmounted(() => {
|
|
156
|
+
workspace.value?.removeEventListener('mouseenter', mouseenterHandler);
|
|
157
|
+
keycon.destroy();
|
|
158
|
+
});
|
|
58
159
|
|
|
59
160
|
return {
|
|
161
|
+
workspace,
|
|
162
|
+
|
|
60
163
|
page: computed(() => services?.editorService.get<MPage>('page')),
|
|
61
164
|
};
|
|
62
165
|
},
|
|
@@ -53,7 +53,7 @@ const doAction = async (
|
|
|
53
53
|
let returnValue: any = await fn(beforeArgs, sourceMethod.bind(scope));
|
|
54
54
|
|
|
55
55
|
for (const afterMethod of scope.pluginOptionsList[afterMethodName]) {
|
|
56
|
-
returnValue = await afterMethod(...beforeArgs
|
|
56
|
+
returnValue = await afterMethod(returnValue, ...beforeArgs);
|
|
57
57
|
|
|
58
58
|
if (isError(returnValue)) throw returnValue;
|
|
59
59
|
}
|
package/src/services/editor.ts
CHANGED
|
@@ -22,8 +22,8 @@ import serialize from 'serialize-javascript';
|
|
|
22
22
|
|
|
23
23
|
import type { Id, MApp, MComponent, MContainer, MNode, MPage } from '@tmagic/schema';
|
|
24
24
|
import { NodeType } from '@tmagic/schema';
|
|
25
|
-
import
|
|
26
|
-
import { getNodePath, isPop } from '@tmagic/utils';
|
|
25
|
+
import StageCore from '@tmagic/stage';
|
|
26
|
+
import { getNodePath, isNumber, isPage, isPop } from '@tmagic/utils';
|
|
27
27
|
|
|
28
28
|
import historyService, { StepValue } from '@editor/services/history';
|
|
29
29
|
import propsService from '@editor/services/props';
|
|
@@ -54,6 +54,7 @@ class Editor extends BaseService {
|
|
|
54
54
|
stage: null,
|
|
55
55
|
highlightNode: null,
|
|
56
56
|
modifiedNodeIds: new Map(),
|
|
57
|
+
pageLength: 0,
|
|
57
58
|
});
|
|
58
59
|
|
|
59
60
|
constructor() {
|
|
@@ -69,6 +70,7 @@ class Editor extends BaseService {
|
|
|
69
70
|
'paste',
|
|
70
71
|
'alignCenter',
|
|
71
72
|
'moveLayer',
|
|
73
|
+
'move',
|
|
72
74
|
'undo',
|
|
73
75
|
'redo',
|
|
74
76
|
'highlight',
|
|
@@ -89,6 +91,7 @@ class Editor extends BaseService {
|
|
|
89
91
|
log('store set ', name, ' ', value);
|
|
90
92
|
|
|
91
93
|
if (name === 'root') {
|
|
94
|
+
this.state.pageLength = (value as unknown as MApp)?.items?.length || 0;
|
|
92
95
|
this.emit('root-change', value);
|
|
93
96
|
}
|
|
94
97
|
}
|
|
@@ -108,7 +111,7 @@ class Editor extends BaseService {
|
|
|
108
111
|
* @returns {EditorNodeInfo}
|
|
109
112
|
*/
|
|
110
113
|
public getNodeInfo(id: Id): EditorNodeInfo {
|
|
111
|
-
const root = this.get<MApp | null>('root');
|
|
114
|
+
const root = toRaw(this.get<MApp | null>('root'));
|
|
112
115
|
if (!root) return {};
|
|
113
116
|
|
|
114
117
|
if (id === root.id) {
|
|
@@ -159,13 +162,15 @@ class Editor extends BaseService {
|
|
|
159
162
|
/**
|
|
160
163
|
* 只有容器拥有布局
|
|
161
164
|
*/
|
|
162
|
-
public async getLayout(
|
|
163
|
-
if (node
|
|
164
|
-
|
|
165
|
+
public async getLayout(parent: MNode, node?: MNode): Promise<Layout> {
|
|
166
|
+
if (node && typeof node !== 'function' && isFixed(node)) return Layout.FIXED;
|
|
167
|
+
|
|
168
|
+
if (parent.layout) {
|
|
169
|
+
return parent.layout;
|
|
165
170
|
}
|
|
166
171
|
|
|
167
172
|
// 如果该节点没有设置position,则认为是流式布局,例如获取root的布局时
|
|
168
|
-
if (!
|
|
173
|
+
if (!parent.style?.position) {
|
|
169
174
|
return Layout.RELATIVE;
|
|
170
175
|
}
|
|
171
176
|
|
|
@@ -188,9 +193,45 @@ class Editor extends BaseService {
|
|
|
188
193
|
} else {
|
|
189
194
|
historyService.empty();
|
|
190
195
|
}
|
|
196
|
+
|
|
197
|
+
this.emit('select', node);
|
|
198
|
+
|
|
191
199
|
return node!;
|
|
192
200
|
}
|
|
193
201
|
|
|
202
|
+
public async selectNextNode(): Promise<MNode> | never {
|
|
203
|
+
const node = toRaw(this.get('node'));
|
|
204
|
+
|
|
205
|
+
if (!node || isPage(node) || node.type === NodeType.ROOT) return node;
|
|
206
|
+
|
|
207
|
+
const parent = toRaw(this.getParentById(node.id));
|
|
208
|
+
|
|
209
|
+
if (!parent) return node;
|
|
210
|
+
|
|
211
|
+
const index = getNodeIndex(node, parent);
|
|
212
|
+
|
|
213
|
+
const nextNode = parent.items[index + 1] || parent.items[0];
|
|
214
|
+
|
|
215
|
+
await this.select(nextNode);
|
|
216
|
+
this.get<StageCore>('stage')?.select(nextNode.id);
|
|
217
|
+
|
|
218
|
+
return nextNode;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
public async selectNextPage(): Promise<MNode> | never {
|
|
222
|
+
const root = toRaw(this.get<MApp>('root'));
|
|
223
|
+
const page = toRaw(this.get('page'));
|
|
224
|
+
|
|
225
|
+
const index = getNodeIndex(page, root);
|
|
226
|
+
|
|
227
|
+
const nextPage = root.items[index + 1] || root.items[0];
|
|
228
|
+
|
|
229
|
+
await this.select(nextPage);
|
|
230
|
+
this.get<StageCore>('stage')?.select(nextPage.id);
|
|
231
|
+
|
|
232
|
+
return nextPage;
|
|
233
|
+
}
|
|
234
|
+
|
|
194
235
|
/**
|
|
195
236
|
* 高亮指定节点
|
|
196
237
|
* @param config 指定节点配置或者ID
|
|
@@ -209,12 +250,14 @@ class Editor extends BaseService {
|
|
|
209
250
|
* @param parent 要添加到的容器组件节点配置,如果不设置,默认为当前选中的组件的父节点
|
|
210
251
|
* @returns 添加后的节点
|
|
211
252
|
*/
|
|
212
|
-
public async add(
|
|
253
|
+
public async add(addNode: AddMNode, parent?: MContainer | null): Promise<MNode> {
|
|
254
|
+
const { type, ...config } = addNode;
|
|
213
255
|
const curNode = this.get<MContainer>('node');
|
|
214
256
|
|
|
215
257
|
let parentNode: MNode | undefined;
|
|
258
|
+
const isPage = type === NodeType.PAGE;
|
|
216
259
|
|
|
217
|
-
if (
|
|
260
|
+
if (isPage) {
|
|
218
261
|
parentNode = this.get<MApp>('root');
|
|
219
262
|
// 由于支持中间件扩展,在parent参数为undefined时,parent会变成next函数
|
|
220
263
|
} else if (parent && typeof parent !== 'function') {
|
|
@@ -227,8 +270,13 @@ class Editor extends BaseService {
|
|
|
227
270
|
|
|
228
271
|
if (!parentNode) throw new Error('未找到父元素');
|
|
229
272
|
|
|
230
|
-
const layout = await this.getLayout(parentNode);
|
|
231
|
-
const newNode = initPosition(
|
|
273
|
+
const layout = await this.getLayout(toRaw(parentNode), addNode as MNode);
|
|
274
|
+
const newNode = initPosition(
|
|
275
|
+
{ ...toRaw(await propsService.getPropsValue(type, config)) },
|
|
276
|
+
layout,
|
|
277
|
+
parentNode,
|
|
278
|
+
this.get<StageCore>('stage'),
|
|
279
|
+
);
|
|
232
280
|
|
|
233
281
|
if ((parentNode?.type === NodeType.ROOT || curNode.type === NodeType.ROOT) && newNode.type !== NodeType.PAGE) {
|
|
234
282
|
throw new Error('app下不能添加组件');
|
|
@@ -249,6 +297,12 @@ class Editor extends BaseService {
|
|
|
249
297
|
|
|
250
298
|
stage?.select(newNode.id);
|
|
251
299
|
|
|
300
|
+
if (isPage) {
|
|
301
|
+
this.state.pageLength += 1;
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
this.emit('add', newNode);
|
|
305
|
+
|
|
252
306
|
return newNode;
|
|
253
307
|
}
|
|
254
308
|
|
|
@@ -277,9 +331,23 @@ class Editor extends BaseService {
|
|
|
277
331
|
stage?.remove({ id: node.id, root: this.get('root') });
|
|
278
332
|
|
|
279
333
|
if (node.type === NodeType.PAGE) {
|
|
334
|
+
this.state.pageLength -= 1;
|
|
335
|
+
|
|
280
336
|
if (root.items[0]) {
|
|
281
337
|
await this.select(root.items[0]);
|
|
282
338
|
stage?.select(root.items[0].id);
|
|
339
|
+
} else {
|
|
340
|
+
this.set('node', null);
|
|
341
|
+
this.set('parent', null);
|
|
342
|
+
this.set('page', null);
|
|
343
|
+
this.set('stage', null);
|
|
344
|
+
this.set('highlightNode', null);
|
|
345
|
+
this.resetModifiedNodeId();
|
|
346
|
+
historyService.reset();
|
|
347
|
+
|
|
348
|
+
this.emit('remove', node);
|
|
349
|
+
|
|
350
|
+
return node;
|
|
283
351
|
}
|
|
284
352
|
} else {
|
|
285
353
|
await this.select(parent);
|
|
@@ -289,6 +357,8 @@ class Editor extends BaseService {
|
|
|
289
357
|
this.addModifiedNodeId(parent.id);
|
|
290
358
|
this.pushHistoryState();
|
|
291
359
|
|
|
360
|
+
this.emit('remove', node);
|
|
361
|
+
|
|
292
362
|
return node;
|
|
293
363
|
}
|
|
294
364
|
|
|
@@ -350,6 +420,8 @@ class Editor extends BaseService {
|
|
|
350
420
|
this.addModifiedNodeId(newConfig.id);
|
|
351
421
|
this.pushHistoryState();
|
|
352
422
|
|
|
423
|
+
this.emit('update', newConfig);
|
|
424
|
+
|
|
353
425
|
return newConfig;
|
|
354
426
|
}
|
|
355
427
|
|
|
@@ -427,7 +499,7 @@ class Editor extends BaseService {
|
|
|
427
499
|
public async alignCenter(config: MNode): Promise<MNode | void> {
|
|
428
500
|
const parent = this.get<MContainer>('parent');
|
|
429
501
|
const node = this.get<MNode>('node');
|
|
430
|
-
const layout = await this.getLayout(parent);
|
|
502
|
+
const layout = await this.getLayout(toRaw(parent), toRaw(node));
|
|
431
503
|
if (layout === Layout.RELATIVE) {
|
|
432
504
|
return;
|
|
433
505
|
}
|
|
@@ -485,6 +557,26 @@ class Editor extends BaseService {
|
|
|
485
557
|
return value;
|
|
486
558
|
}
|
|
487
559
|
|
|
560
|
+
public async move(left: number, top: number) {
|
|
561
|
+
const node = toRaw(this.get('node'));
|
|
562
|
+
if (!node || isPage(node)) return;
|
|
563
|
+
|
|
564
|
+
const { style, id } = node;
|
|
565
|
+
if (!style || style.position !== 'absolute') return;
|
|
566
|
+
|
|
567
|
+
if (top && !isNumber(style.top)) return;
|
|
568
|
+
if (left && !isNumber(style.left)) return;
|
|
569
|
+
|
|
570
|
+
this.update({
|
|
571
|
+
id,
|
|
572
|
+
style: {
|
|
573
|
+
...style,
|
|
574
|
+
left: Number(style.left) + left,
|
|
575
|
+
top: Number(style.top) + top,
|
|
576
|
+
},
|
|
577
|
+
});
|
|
578
|
+
}
|
|
579
|
+
|
|
488
580
|
public destroy() {
|
|
489
581
|
this.removeAllListeners();
|
|
490
582
|
this.set('root', null);
|
package/src/services/history.ts
CHANGED
|
@@ -51,6 +51,13 @@ class History extends BaseService {
|
|
|
51
51
|
this.on('change', this.setCanUndoRedo);
|
|
52
52
|
}
|
|
53
53
|
|
|
54
|
+
public reset() {
|
|
55
|
+
this.state.pageSteps = {};
|
|
56
|
+
this.state.pageId = undefined;
|
|
57
|
+
this.state.canRedo = false;
|
|
58
|
+
this.state.canUndo = false;
|
|
59
|
+
}
|
|
60
|
+
|
|
54
61
|
public changePage(page: MPage): void {
|
|
55
62
|
if (!page) return;
|
|
56
63
|
|
package/src/services/props.ts
CHANGED
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
*/
|
|
18
18
|
|
|
19
19
|
import { reactive } from 'vue';
|
|
20
|
-
import { cloneDeep } from 'lodash-es';
|
|
20
|
+
import { cloneDeep, mergeWith } from 'lodash-es';
|
|
21
21
|
|
|
22
22
|
import type { FormConfig } from '@tmagic/form';
|
|
23
23
|
import type { MComponent, MNode } from '@tmagic/schema';
|
|
@@ -87,7 +87,7 @@ class Props extends BaseService {
|
|
|
87
87
|
* @param type 组件类型
|
|
88
88
|
* @returns 组件初始值
|
|
89
89
|
*/
|
|
90
|
-
public async getPropsValue(type: string) {
|
|
90
|
+
public async getPropsValue(type: string, defaultValue = {}) {
|
|
91
91
|
if (type === 'area') {
|
|
92
92
|
const value = (await this.getPropsValue('button')) as MComponent;
|
|
93
93
|
value.className = 'action-area';
|
|
@@ -100,7 +100,7 @@ class Props extends BaseService {
|
|
|
100
100
|
|
|
101
101
|
return cloneDeep({
|
|
102
102
|
...getDefaultPropsValue(type),
|
|
103
|
-
...(this.state.propsValueMap[type] || {}),
|
|
103
|
+
...mergeWith(this.state.propsValueMap[type] || {}, defaultValue),
|
|
104
104
|
});
|
|
105
105
|
}
|
|
106
106
|
}
|
package/src/services/ui.ts
CHANGED
|
@@ -91,6 +91,11 @@ class Ui extends BaseService {
|
|
|
91
91
|
return (state as any)[name];
|
|
92
92
|
}
|
|
93
93
|
|
|
94
|
+
public zoom(zoom: number) {
|
|
95
|
+
this.set('zoom', (this.get<number>('zoom') * 100 + zoom * 100) / 100);
|
|
96
|
+
if (this.get<number>('zoom') < 0.1) this.set('zoom', 0.1);
|
|
97
|
+
}
|
|
98
|
+
|
|
94
99
|
private setColumnWidth({ left, center, right }: SetColumnWidth) {
|
|
95
100
|
const columnWidth = {
|
|
96
101
|
...toRaw(this.get<GetColumnWidth>('columnWidth')),
|
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
top: 0;
|
|
13
13
|
left: 0;
|
|
14
14
|
box-sizing: border-box;
|
|
15
|
+
z-index: 1;
|
|
15
16
|
|
|
16
17
|
.el-input__prefix {
|
|
17
18
|
padding: 10px;
|
|
@@ -62,6 +63,7 @@
|
|
|
62
63
|
color: $--font-color;
|
|
63
64
|
flex-direction: column;
|
|
64
65
|
width: 42px;
|
|
66
|
+
cursor: pointer;
|
|
65
67
|
|
|
66
68
|
i {
|
|
67
69
|
font-size: 20px;
|