@tmagic/editor 1.1.0-beta.9 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (59) hide show
  1. package/dist/style.css +46 -0
  2. package/dist/tmagic-editor.mjs +971 -794
  3. package/dist/tmagic-editor.mjs.map +1 -1
  4. package/dist/tmagic-editor.umd.js +974 -794
  5. package/dist/tmagic-editor.umd.js.map +1 -1
  6. package/package.json +10 -10
  7. package/src/Editor.vue +15 -5
  8. package/src/components/ContentMenu.vue +4 -4
  9. package/src/components/Icon.vue +6 -20
  10. package/src/components/ScrollBar.vue +147 -0
  11. package/src/components/ScrollViewer.vue +89 -44
  12. package/src/components/ToolButton.vue +40 -138
  13. package/src/fields/UISelect.vue +2 -2
  14. package/src/index.ts +2 -0
  15. package/src/layouts/NavMenu.vue +156 -23
  16. package/src/layouts/PropsPanel.vue +49 -51
  17. package/src/layouts/sidebar/LayerMenu.vue +3 -3
  18. package/src/layouts/sidebar/LayerPanel.vue +39 -8
  19. package/src/layouts/workspace/PageBar.vue +1 -1
  20. package/src/layouts/workspace/Stage.vue +8 -90
  21. package/src/layouts/workspace/ViewerMenu.vue +3 -3
  22. package/src/layouts/workspace/Workspace.vue +133 -138
  23. package/src/services/componentList.ts +5 -0
  24. package/src/services/editor.ts +56 -19
  25. package/src/services/events.ts +8 -2
  26. package/src/services/props.ts +31 -52
  27. package/src/services/storage.ts +4 -0
  28. package/src/services/ui.ts +32 -30
  29. package/src/theme/nav-menu.scss +6 -0
  30. package/src/type.ts +26 -10
  31. package/src/utils/index.ts +1 -0
  32. package/src/utils/operator.ts +3 -3
  33. package/src/utils/props.ts +0 -3
  34. package/src/utils/scroll-viewer.ts +90 -158
  35. package/src/utils/stage.ts +91 -0
  36. package/types/Editor.vue.d.ts +7 -7
  37. package/types/components/ContentMenu.vue.d.ts +8 -8
  38. package/types/components/Icon.vue.d.ts +62 -12
  39. package/types/components/ScrollBar.vue.d.ts +83 -0
  40. package/types/components/ScrollViewer.vue.d.ts +131 -19
  41. package/types/components/ToolButton.vue.d.ts +56 -59
  42. package/types/index.d.ts +2 -0
  43. package/types/layouts/NavMenu.vue.d.ts +92 -23
  44. package/types/layouts/PropsPanel.vue.d.ts +25 -208
  45. package/types/layouts/sidebar/LayerMenu.vue.d.ts +7 -7
  46. package/types/layouts/sidebar/LayerPanel.vue.d.ts +17 -15
  47. package/types/layouts/workspace/Workspace.vue.d.ts +54 -4
  48. package/types/services/componentList.d.ts +1 -0
  49. package/types/services/editor.d.ts +1 -0
  50. package/types/services/events.d.ts +1 -0
  51. package/types/services/props.d.ts +41 -9
  52. package/types/services/storage.d.ts +1 -0
  53. package/types/services/ui.d.ts +3 -1
  54. package/types/type.d.ts +23 -10
  55. package/types/utils/index.d.ts +1 -0
  56. package/types/utils/operator.d.ts +1 -1
  57. package/types/utils/props.d.ts +0 -1
  58. package/types/utils/scroll-viewer.d.ts +16 -18
  59. package/types/utils/stage.d.ts +3 -0
@@ -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
- empty-text="页面空荡荡的"
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
- node.value = editorService?.get('node');
132
- node.value && tree.value.setCurrentKey(node.value.id, true);
140
+ if (!editorService) return;
141
+ node.value = editorService.get('node');
142
+
143
+ if (!node.value) return;
133
144
 
134
- const parent = editorService?.get('parent');
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
- highlightNode.value = editorService?.get('highlightNode');
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
- H_GUIDE_LINE_STORAGE_KEY,
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 uiSelectMode = computed(() => services?.uiService.get<boolean>('uiSelectMode'));
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 = new StageCore({
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, MenuItem, Services } from '../../type';
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<MenuItem[]>('stageContentMenu', []);
31
+ const stageContentMenu = inject<(MenuButton | MenuComponent)[]>('stageContentMenu', []);
32
32
 
33
- const menuData = reactive<MenuItem[]>([
33
+ const menuData = reactive<(MenuButton | MenuComponent)[]>([
34
34
  {
35
35
  type: 'button',
36
36
  text: '水平居中',
@@ -1,18 +1,20 @@
1
1
  <template>
2
2
  <div class="m-editor-workspace" tabindex="1" ref="workspace">
3
- <magic-stage :key="page?.id"></magic-stage>
3
+ <slot name="stage">
4
+ <MagicStage :key="page?.id"></MagicStage>
5
+ </slot>
4
6
 
5
7
  <slot name="workspace-content"></slot>
6
8
 
7
- <page-bar>
9
+ <PageBar>
8
10
  <template #page-bar-title="{ page }"><slot name="page-bar-title" :page="page"></slot></template>
9
11
  <template #page-bar-popover="{ page }"><slot name="page-bar-popover" :page="page"></slot></template>
10
- </page-bar>
12
+ </PageBar>
11
13
  </div>
12
14
  </template>
13
15
 
14
- <script lang="ts">
15
- import { computed, defineComponent, inject, onMounted, onUnmounted, ref } from 'vue';
16
+ <script lang="ts" setup>
17
+ import { computed, inject, onMounted, onUnmounted, ref } from 'vue';
16
18
  import KeyController from 'keycon';
17
19
 
18
20
  import type { MNode, MPage } from '@tmagic/schema';
@@ -23,140 +25,133 @@ import type { Services } from '../../type';
23
25
  import PageBar from './PageBar.vue';
24
26
  import MagicStage from './Stage.vue';
25
27
 
26
- export default defineComponent({
27
- name: 'm-editor-workspace',
28
-
29
- components: {
30
- PageBar,
31
- MagicStage,
32
- },
33
-
34
- setup() {
35
- const services = inject<Services>('services');
36
- const workspace = ref<HTMLDivElement>();
37
- const nodes = computed(() => services?.editorService.get<MNode[]>('nodes'));
38
- let keycon: KeyController;
39
-
40
- const mouseenterHandler = () => {
41
- workspace.value?.focus();
42
- };
43
-
44
- const mouseleaveHandler = () => {
45
- workspace.value?.blur();
46
- };
47
-
48
- onMounted(() => {
49
- workspace.value?.addEventListener('mouseenter', mouseenterHandler);
50
- workspace.value?.addEventListener('mouseleave', mouseleaveHandler);
51
-
52
- keycon = new KeyController(workspace.value);
53
-
54
- const isMac = /mac os x/.test(navigator.userAgent.toLowerCase());
55
-
56
- const ctrl = isMac ? 'meta' : 'ctrl';
57
-
58
- keycon
59
- .keyup('delete', (e) => {
60
- e.inputEvent.preventDefault();
61
- if (!nodes.value || isPage(nodes.value[0])) return;
62
- services?.editorService.remove(nodes.value);
63
- })
64
- .keyup('backspace', (e) => {
65
- e.inputEvent.preventDefault();
66
- if (!nodes.value || isPage(nodes.value[0])) return;
67
- services?.editorService.remove(nodes.value);
68
- })
69
- .keydown([ctrl, 'c'], (e) => {
70
- e.inputEvent.preventDefault();
71
- nodes.value && services?.editorService.copy(nodes.value);
72
- })
73
- .keydown([ctrl, 'v'], (e) => {
74
- e.inputEvent.preventDefault();
75
- nodes.value && services?.editorService.paste({ offsetX: 10, offsetY: 10 });
76
- })
77
- .keydown([ctrl, 'x'], (e) => {
78
- e.inputEvent.preventDefault();
79
- if (!nodes.value || isPage(nodes.value[0])) return;
80
- services?.editorService.copy(nodes.value);
81
- services?.editorService.remove(nodes.value);
82
- })
83
- .keydown([ctrl, 'z'], (e) => {
84
- e.inputEvent.preventDefault();
85
- services?.editorService.undo();
86
- })
87
- .keydown([ctrl, 'shift', 'z'], (e) => {
88
- e.inputEvent.preventDefault();
89
- services?.editorService.redo();
90
- })
91
- .keydown('up', (e) => {
92
- e.inputEvent.preventDefault();
93
- services?.editorService.move(0, -1);
94
- })
95
- .keydown('down', (e) => {
96
- e.inputEvent.preventDefault();
97
- services?.editorService.move(0, 1);
98
- })
99
- .keydown('left', (e) => {
100
- e.inputEvent.preventDefault();
101
- services?.editorService.move(-1, 0);
102
- })
103
- .keydown('right', (e) => {
104
- e.inputEvent.preventDefault();
105
- services?.editorService.move(1, 0);
106
- })
107
- .keydown([ctrl, 'up'], (e) => {
108
- e.inputEvent.preventDefault();
109
- services?.editorService.move(0, -10);
110
- })
111
- .keydown([ctrl, 'down'], (e) => {
112
- e.inputEvent.preventDefault();
113
- services?.editorService.move(0, 10);
114
- })
115
- .keydown([ctrl, 'left'], (e) => {
116
- e.inputEvent.preventDefault();
117
- services?.editorService.move(-10, 0);
118
- })
119
- .keydown([ctrl, 'right'], (e) => {
120
- e.inputEvent.preventDefault();
121
- services?.editorService.move(10, 0);
122
- })
123
- .keydown('tab', (e) => {
124
- e.inputEvent.preventDefault();
125
- services?.editorService.selectNextNode();
126
- })
127
- .keydown([ctrl, 'tab'], (e) => {
128
- e.inputEvent.preventDefault();
129
- services?.editorService.selectNextPage();
130
- })
131
- .keydown([ctrl, '='], (e) => {
132
- e.inputEvent.preventDefault();
133
- services?.uiService.zoom(0.1);
134
- })
135
- .keydown([ctrl, 'numpadplus'], (e) => {
136
- e.inputEvent.preventDefault();
137
- services?.uiService.zoom(0.1);
138
- })
139
- .keydown([ctrl, '-'], (e) => {
140
- e.inputEvent.preventDefault();
141
- services?.uiService.zoom(-0.1);
142
- })
143
- .keydown([ctrl, 'numpad-'], (e) => {
144
- e.inputEvent.preventDefault();
145
- services?.uiService.zoom(-0.1);
146
- });
28
+ const services = inject<Services>('services');
29
+ const workspace = ref<HTMLDivElement>();
30
+ const nodes = computed(() => services?.editorService.get<MNode[]>('nodes'));
31
+ const page = computed(() => services?.editorService.get<MPage>('page'));
32
+
33
+ const mouseenterHandler = () => {
34
+ workspace.value?.focus();
35
+ };
36
+
37
+ const mouseleaveHandler = () => {
38
+ workspace.value?.blur();
39
+ };
40
+
41
+ let keycon: KeyController;
42
+
43
+ onMounted(() => {
44
+ workspace.value?.addEventListener('mouseenter', mouseenterHandler);
45
+ workspace.value?.addEventListener('mouseleave', mouseleaveHandler);
46
+
47
+ keycon = new KeyController(workspace.value);
48
+
49
+ const isMac = /mac os x/.test(navigator.userAgent.toLowerCase());
50
+
51
+ const ctrl = isMac ? 'meta' : 'ctrl';
52
+
53
+ keycon
54
+ .keyup('delete', (e) => {
55
+ e.inputEvent.preventDefault();
56
+ if (!nodes.value || isPage(nodes.value[0])) return;
57
+ services?.editorService.remove(nodes.value);
58
+ })
59
+ .keyup('backspace', (e) => {
60
+ e.inputEvent.preventDefault();
61
+ if (!nodes.value || isPage(nodes.value[0])) return;
62
+ services?.editorService.remove(nodes.value);
63
+ })
64
+ .keydown([ctrl, 'c'], (e) => {
65
+ e.inputEvent.preventDefault();
66
+ nodes.value && services?.editorService.copy(nodes.value);
67
+ })
68
+ .keydown([ctrl, 'v'], (e) => {
69
+ e.inputEvent.preventDefault();
70
+ nodes.value && services?.editorService.paste({ offsetX: 10, offsetY: 10 });
71
+ })
72
+ .keydown([ctrl, 'x'], (e) => {
73
+ e.inputEvent.preventDefault();
74
+ if (!nodes.value || isPage(nodes.value[0])) return;
75
+ services?.editorService.copy(nodes.value);
76
+ services?.editorService.remove(nodes.value);
77
+ })
78
+ .keydown([ctrl, 'z'], (e) => {
79
+ e.inputEvent.preventDefault();
80
+ services?.editorService.undo();
81
+ })
82
+ .keydown([ctrl, 'shift', 'z'], (e) => {
83
+ e.inputEvent.preventDefault();
84
+ services?.editorService.redo();
85
+ })
86
+ .keydown('up', (e) => {
87
+ e.inputEvent.preventDefault();
88
+ services?.editorService.move(0, -1);
89
+ })
90
+ .keydown('down', (e) => {
91
+ e.inputEvent.preventDefault();
92
+ services?.editorService.move(0, 1);
93
+ })
94
+ .keydown('left', (e) => {
95
+ e.inputEvent.preventDefault();
96
+ services?.editorService.move(-1, 0);
97
+ })
98
+ .keydown('right', (e) => {
99
+ e.inputEvent.preventDefault();
100
+ services?.editorService.move(1, 0);
101
+ })
102
+ .keydown([ctrl, 'up'], (e) => {
103
+ e.inputEvent.preventDefault();
104
+ services?.editorService.move(0, -10);
105
+ })
106
+ .keydown([ctrl, 'down'], (e) => {
107
+ e.inputEvent.preventDefault();
108
+ services?.editorService.move(0, 10);
109
+ })
110
+ .keydown([ctrl, 'left'], (e) => {
111
+ e.inputEvent.preventDefault();
112
+ services?.editorService.move(-10, 0);
113
+ })
114
+ .keydown([ctrl, 'right'], (e) => {
115
+ e.inputEvent.preventDefault();
116
+ services?.editorService.move(10, 0);
117
+ })
118
+ .keydown('tab', (e) => {
119
+ e.inputEvent.preventDefault();
120
+ services?.editorService.selectNextNode();
121
+ })
122
+ .keydown([ctrl, 'tab'], (e) => {
123
+ e.inputEvent.preventDefault();
124
+ services?.editorService.selectNextPage();
125
+ })
126
+ .keydown([ctrl, '='], (e) => {
127
+ e.inputEvent.preventDefault();
128
+ services?.uiService.zoom(0.1);
129
+ })
130
+ .keydown([ctrl, 'numpadplus'], (e) => {
131
+ e.inputEvent.preventDefault();
132
+ services?.uiService.zoom(0.1);
133
+ })
134
+ .keydown([ctrl, '-'], (e) => {
135
+ e.inputEvent.preventDefault();
136
+ services?.uiService.zoom(-0.1);
137
+ })
138
+ .keydown([ctrl, 'numpad-'], (e) => {
139
+ e.inputEvent.preventDefault();
140
+ services?.uiService.zoom(-0.1);
141
+ })
142
+ .keydown([ctrl, '0'], (e) => {
143
+ e.inputEvent.preventDefault();
144
+ services?.uiService.set('zoom', services.uiService.calcZoom());
145
+ })
146
+ .keydown([ctrl, '1'], (e) => {
147
+ e.inputEvent.preventDefault();
148
+ services?.uiService.set('zoom', 1);
147
149
  });
150
+ });
148
151
 
149
- onUnmounted(() => {
150
- workspace.value?.removeEventListener('mouseenter', mouseenterHandler);
151
- workspace.value?.removeEventListener('mouseleave', mouseleaveHandler);
152
- keycon.destroy();
153
- });
154
-
155
- return {
156
- workspace,
157
-
158
- page: computed(() => services?.editorService.get<MPage>('page')),
159
- };
160
- },
152
+ onUnmounted(() => {
153
+ workspace.value?.removeEventListener('mouseenter', mouseenterHandler);
154
+ workspace.value?.removeEventListener('mouseleave', mouseleaveHandler);
155
+ keycon.destroy();
161
156
  });
162
157
  </script>
@@ -41,6 +41,11 @@ class ComponentList extends BaseService {
41
41
  public getList(): ComponentGroup[] {
42
42
  return this.state.list;
43
43
  }
44
+
45
+ public destroy() {
46
+ this.state.list = [];
47
+ this.removeAllListeners();
48
+ }
44
49
  }
45
50
 
46
51
  export type ComponentListService = ComponentList;