@tmagic/editor 1.3.0-alpha.5 → 1.3.0-alpha.7
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 +23 -5
- package/dist/tmagic-editor.js +502 -246
- package/dist/tmagic-editor.js.map +1 -1
- package/dist/tmagic-editor.umd.cjs +505 -247
- package/dist/tmagic-editor.umd.cjs.map +1 -1
- package/package.json +10 -10
- package/src/Editor.vue +5 -0
- package/src/components/ContentMenu.vue +15 -8
- package/src/components/FunctionEditor.vue +6 -4
- package/src/{layouts → components}/Resizer.vue +15 -6
- package/src/components/{Layout.vue → SplitView.vue} +1 -1
- package/src/fields/CodeLink.vue +4 -2
- package/src/index.ts +5 -3
- package/src/initService.ts +2 -0
- package/src/layouts/Framework.vue +6 -5
- package/src/layouts/sidebar/LayerPanel.vue +58 -22
- package/src/layouts/sidebar/code-block/CodeBlockEditor.vue +3 -3
- package/src/layouts/workspace/Stage.vue +13 -3
- package/src/layouts/workspace/Workspace.vue +4 -133
- package/src/services/codeBlock.ts +3 -2
- package/src/services/keybinding.ts +185 -0
- package/src/services/storage.ts +3 -2
- package/src/theme/resizer.scss +25 -10
- package/src/theme/stage.scss +4 -0
- package/src/type.ts +59 -1
- package/src/utils/config.ts +1 -1
- package/src/utils/keybinding-config.ts +120 -0
- package/types/components/ContentMenu.vue.d.ts +2 -0
- package/types/index.d.ts +3 -2
- package/types/initService.d.ts +1 -1
- package/types/layouts/workspace/Workspace.vue.d.ts +1 -1
- package/types/services/keybinding.d.ts +20 -0
- package/types/type.d.ts +56 -1
- package/types/utils/config.d.ts +1 -1
- package/types/utils/keybinding-config.d.ts +3 -0
- /package/types/{layouts → components}/Resizer.vue.d.ts +0 -0
- /package/types/components/{Layout.vue.d.ts → SplitView.vue.d.ts} +0 -0
package/package.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "1.3.0-alpha.
|
|
2
|
+
"version": "1.3.0-alpha.7",
|
|
3
3
|
"name": "@tmagic/editor",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"sideEffects": [
|
|
@@ -46,13 +46,13 @@
|
|
|
46
46
|
"dependencies": {
|
|
47
47
|
"@babel/core": "^7.18.0",
|
|
48
48
|
"@element-plus/icons-vue": "^2.0.9",
|
|
49
|
-
"@tmagic/core": "1.3.0-alpha.
|
|
50
|
-
"@tmagic/design": "1.3.0-alpha.
|
|
51
|
-
"@tmagic/form": "1.3.0-alpha.
|
|
52
|
-
"@tmagic/schema": "1.3.0-alpha.
|
|
53
|
-
"@tmagic/stage": "1.3.0-alpha.
|
|
54
|
-
"@tmagic/table": "1.3.0-alpha.
|
|
55
|
-
"@tmagic/utils": "1.3.0-alpha.
|
|
49
|
+
"@tmagic/core": "1.3.0-alpha.7",
|
|
50
|
+
"@tmagic/design": "1.3.0-alpha.7",
|
|
51
|
+
"@tmagic/form": "1.3.0-alpha.7",
|
|
52
|
+
"@tmagic/schema": "1.3.0-alpha.7",
|
|
53
|
+
"@tmagic/stage": "1.3.0-alpha.7",
|
|
54
|
+
"@tmagic/table": "1.3.0-alpha.7",
|
|
55
|
+
"@tmagic/utils": "1.3.0-alpha.7",
|
|
56
56
|
"buffer": "^6.0.3",
|
|
57
57
|
"color": "^3.1.3",
|
|
58
58
|
"events": "^3.3.0",
|
|
@@ -64,8 +64,8 @@
|
|
|
64
64
|
"vue": "^3.3.4"
|
|
65
65
|
},
|
|
66
66
|
"peerDependencies": {
|
|
67
|
-
"@tmagic/design": "1.3.0-alpha.
|
|
68
|
-
"@tmagic/form": "1.3.0-alpha.
|
|
67
|
+
"@tmagic/design": "1.3.0-alpha.7",
|
|
68
|
+
"@tmagic/form": "1.3.0-alpha.7",
|
|
69
69
|
"monaco-editor": "^0.34.0",
|
|
70
70
|
"vue": "^3.3.4"
|
|
71
71
|
},
|
package/src/Editor.vue
CHANGED
|
@@ -96,9 +96,11 @@ import depService from './services/dep';
|
|
|
96
96
|
import editorService from './services/editor';
|
|
97
97
|
import eventsService from './services/events';
|
|
98
98
|
import historyService from './services/history';
|
|
99
|
+
import keybindingService from './services/keybinding';
|
|
99
100
|
import propsService from './services/props';
|
|
100
101
|
import storageService from './services/storage';
|
|
101
102
|
import uiService from './services/ui';
|
|
103
|
+
import keybindingConfig from './utils/keybinding-config';
|
|
102
104
|
import editorProps from './editorProps';
|
|
103
105
|
import { initServiceEvents, initServiceState } from './initService';
|
|
104
106
|
import type { Services } from './type';
|
|
@@ -130,10 +132,13 @@ export default defineComponent({
|
|
|
130
132
|
codeBlockService,
|
|
131
133
|
depService,
|
|
132
134
|
dataSourceService,
|
|
135
|
+
keybindingService,
|
|
133
136
|
};
|
|
134
137
|
|
|
135
138
|
initServiceEvents(props, emit, services);
|
|
136
139
|
initServiceState(props, services);
|
|
140
|
+
keybindingService.registe(keybindingConfig);
|
|
141
|
+
keybindingService.registeEl('global');
|
|
137
142
|
|
|
138
143
|
provide('services', services);
|
|
139
144
|
|
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
</div>
|
|
13
13
|
<teleport to="body">
|
|
14
14
|
<content-menu
|
|
15
|
+
v-if="subMenuData.length"
|
|
15
16
|
class="sub-menu"
|
|
16
17
|
ref="subMenu"
|
|
17
18
|
:menu-data="subMenuData"
|
|
@@ -55,6 +56,8 @@ const menuStyle = ref({
|
|
|
55
56
|
top: '0',
|
|
56
57
|
});
|
|
57
58
|
|
|
59
|
+
const contains = (el: HTMLElement) => menu.value?.contains(el) || subMenu.value?.contains(el);
|
|
60
|
+
|
|
58
61
|
const hide = () => {
|
|
59
62
|
if (!visible.value) return;
|
|
60
63
|
|
|
@@ -69,7 +72,7 @@ const hideHandler = (e: MouseEvent) => {
|
|
|
69
72
|
if (!visible.value || !target) {
|
|
70
73
|
return;
|
|
71
74
|
}
|
|
72
|
-
if (
|
|
75
|
+
if (contains(target)) {
|
|
73
76
|
return;
|
|
74
77
|
}
|
|
75
78
|
hide();
|
|
@@ -104,13 +107,15 @@ const showSubMenu = (item: MenuButton | MenuComponent) => {
|
|
|
104
107
|
return;
|
|
105
108
|
}
|
|
106
109
|
|
|
107
|
-
subMenuData.value = menuItem.items;
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
110
|
+
subMenuData.value = menuItem.items || [];
|
|
111
|
+
setTimeout(() => {
|
|
112
|
+
if (menu.value) {
|
|
113
|
+
subMenu.value?.show({
|
|
114
|
+
clientX: menu.value.offsetLeft + menu.value.clientWidth,
|
|
115
|
+
clientY: menu.value.offsetTop,
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
}, 0);
|
|
114
119
|
};
|
|
115
120
|
|
|
116
121
|
onMounted(() => {
|
|
@@ -126,7 +131,9 @@ onUnmounted(() => {
|
|
|
126
131
|
});
|
|
127
132
|
|
|
128
133
|
defineExpose({
|
|
134
|
+
menu,
|
|
129
135
|
hide,
|
|
130
136
|
show,
|
|
137
|
+
contains,
|
|
131
138
|
});
|
|
132
139
|
</script>
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
</TMagicCard>
|
|
34
34
|
</template>
|
|
35
35
|
<script lang="ts" setup>
|
|
36
|
-
import { inject, ref, watchEffect } from 'vue';
|
|
36
|
+
import { inject, provide, ref, watchEffect } from 'vue';
|
|
37
37
|
import { cloneDeep } from 'lodash-es';
|
|
38
38
|
|
|
39
39
|
import { TMagicCard, TMagicInput, tMagicMessage } from '@tmagic/design';
|
|
@@ -41,6 +41,7 @@ import { ColumnConfig, TableConfig } from '@tmagic/form';
|
|
|
41
41
|
import { CodeParam, Id } from '@tmagic/schema';
|
|
42
42
|
|
|
43
43
|
import type { Services } from '@editor/type';
|
|
44
|
+
import { getConfig } from '@editor/utils/config';
|
|
44
45
|
|
|
45
46
|
import CodeDraftEditor from './CodeDraftEditor.vue';
|
|
46
47
|
|
|
@@ -48,6 +49,8 @@ defineOptions({
|
|
|
48
49
|
name: 'MEditorFunctionEditor',
|
|
49
50
|
});
|
|
50
51
|
|
|
52
|
+
provide('mForm', {});
|
|
53
|
+
|
|
51
54
|
const defaultParamColConfig: ColumnConfig = {
|
|
52
55
|
type: 'row',
|
|
53
56
|
label: '参数类型',
|
|
@@ -147,9 +150,8 @@ initTableModel();
|
|
|
147
150
|
// 保存前钩子
|
|
148
151
|
const beforeSave = (codeValue: string): boolean => {
|
|
149
152
|
try {
|
|
150
|
-
//
|
|
151
|
-
|
|
152
|
-
eval(codeValue);
|
|
153
|
+
// 检测js代码是否存在语法错误
|
|
154
|
+
getConfig('parseDSL')(codeValue);
|
|
153
155
|
return true;
|
|
154
156
|
} catch (e: any) {
|
|
155
157
|
tMagicMessage.error(e.stack);
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<span ref="target" class="m-editor-resizer">
|
|
2
|
+
<span ref="target" class="m-editor-resizer" :class="{ 'm-editor-resizer-draging': isDraging }">
|
|
3
3
|
<slot></slot>
|
|
4
4
|
</span>
|
|
5
5
|
</template>
|
|
@@ -15,6 +15,7 @@ defineOptions({
|
|
|
15
15
|
const emit = defineEmits(['change']);
|
|
16
16
|
|
|
17
17
|
const target = ref<HTMLSpanElement>();
|
|
18
|
+
const isDraging = ref(false);
|
|
18
19
|
|
|
19
20
|
let getso: Gesto;
|
|
20
21
|
|
|
@@ -23,14 +24,22 @@ onMounted(() => {
|
|
|
23
24
|
getso = new Gesto(target.value, {
|
|
24
25
|
container: window,
|
|
25
26
|
pinchOutside: true,
|
|
26
|
-
})
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
27
|
+
})
|
|
28
|
+
.on('drag', (e) => {
|
|
29
|
+
if (!target.value) return;
|
|
30
|
+
|
|
31
|
+
emit('change', e.deltaX);
|
|
32
|
+
})
|
|
33
|
+
.on('dragStart', () => {
|
|
34
|
+
isDraging.value = true;
|
|
35
|
+
})
|
|
36
|
+
.on('dragEnd', () => {
|
|
37
|
+
isDraging.value = false;
|
|
38
|
+
});
|
|
31
39
|
});
|
|
32
40
|
|
|
33
41
|
onUnmounted(() => {
|
|
34
42
|
getso?.unset();
|
|
43
|
+
isDraging.value = false;
|
|
35
44
|
});
|
|
36
45
|
</script>
|
package/src/fields/CodeLink.vue
CHANGED
|
@@ -6,6 +6,8 @@
|
|
|
6
6
|
import { computed, reactive, watch } from 'vue';
|
|
7
7
|
import serialize from 'serialize-javascript';
|
|
8
8
|
|
|
9
|
+
import { getConfig } from '@editor/utils/config';
|
|
10
|
+
|
|
9
11
|
defineOptions({
|
|
10
12
|
name: 'MEditorCodeLink',
|
|
11
13
|
});
|
|
@@ -69,8 +71,8 @@ const changeHandler = (v: Record<string, any>) => {
|
|
|
69
71
|
if (!props.name || !props.model) return;
|
|
70
72
|
|
|
71
73
|
try {
|
|
72
|
-
|
|
73
|
-
props.model[props.name] =
|
|
74
|
+
const parseDSL = getConfig('parseDSL');
|
|
75
|
+
props.model[props.name] = parseDSL(`(${v[props.name]})`);
|
|
74
76
|
emit('change', props.model[props.name]);
|
|
75
77
|
} catch (e) {
|
|
76
78
|
console.error(e);
|
package/src/index.ts
CHANGED
|
@@ -60,14 +60,16 @@ export { default as PropsPanel } from './layouts/PropsPanel.vue';
|
|
|
60
60
|
export { default as ToolButton } from './components/ToolButton.vue';
|
|
61
61
|
export { default as ContentMenu } from './components/ContentMenu.vue';
|
|
62
62
|
export { default as Icon } from './components/Icon.vue';
|
|
63
|
-
export { default as LayoutContainer } from './components/
|
|
63
|
+
export { default as LayoutContainer } from './components/SplitView.vue';
|
|
64
|
+
export { default as SplitView } from './components/SplitView.vue';
|
|
64
65
|
|
|
65
66
|
const defaultInstallOpt: InstallOptions = {
|
|
66
|
-
//
|
|
67
|
+
// eslint-disable-next-line no-eval
|
|
68
|
+
parseDSL: (dsl: string) => eval(dsl),
|
|
67
69
|
};
|
|
68
70
|
|
|
69
71
|
export default {
|
|
70
|
-
install: (app: App, opt?: InstallOptions): void => {
|
|
72
|
+
install: (app: App, opt?: Partial<InstallOptions>): void => {
|
|
71
73
|
const option = Object.assign(defaultInstallOpt, opt || {});
|
|
72
74
|
|
|
73
75
|
// eslint-disable-next-line no-param-reassign
|
package/src/initService.ts
CHANGED
|
@@ -25,6 +25,7 @@ export const initServiceState = (
|
|
|
25
25
|
eventsService,
|
|
26
26
|
uiService,
|
|
27
27
|
codeBlockService,
|
|
28
|
+
keybindingService,
|
|
28
29
|
}: Services,
|
|
29
30
|
) => {
|
|
30
31
|
// 初始值变化,重新设置节点信息
|
|
@@ -104,6 +105,7 @@ export const initServiceState = (
|
|
|
104
105
|
uiService.resetState();
|
|
105
106
|
componentListService.resetState();
|
|
106
107
|
codeBlockService.resetState();
|
|
108
|
+
keybindingService.reset();
|
|
107
109
|
});
|
|
108
110
|
};
|
|
109
111
|
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
<CodeEditor class="m-editor-content" :init-values="root" :options="codeOptions" @save="saveCode"></CodeEditor>
|
|
11
11
|
</slot>
|
|
12
12
|
|
|
13
|
-
<
|
|
13
|
+
<SplitView
|
|
14
14
|
v-else
|
|
15
15
|
class="m-editor-content"
|
|
16
16
|
left-class="m-editor-framework-left"
|
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
<slot name="props-panel"></slot>
|
|
39
39
|
</TMagicScrollbar>
|
|
40
40
|
</template>
|
|
41
|
-
</
|
|
41
|
+
</SplitView>
|
|
42
42
|
|
|
43
43
|
<slot name="content-after"></slot>
|
|
44
44
|
<slot name="footer"></slot>
|
|
@@ -50,8 +50,9 @@ import { computed, inject, ref, watch } from 'vue';
|
|
|
50
50
|
|
|
51
51
|
import { TMagicScrollbar } from '@tmagic/design';
|
|
52
52
|
|
|
53
|
-
import
|
|
53
|
+
import SplitView from '@editor/components/SplitView.vue';
|
|
54
54
|
import type { GetColumnWidth, Services } from '@editor/type';
|
|
55
|
+
import { getConfig } from '@editor/utils/config';
|
|
55
56
|
|
|
56
57
|
import AddPageBox from './AddPageBox.vue';
|
|
57
58
|
import CodeEditor from './CodeEditor.vue';
|
|
@@ -131,8 +132,8 @@ const columnWidthChange = (columnW: GetColumnWidth) => {
|
|
|
131
132
|
|
|
132
133
|
const saveCode = (value: string) => {
|
|
133
134
|
try {
|
|
134
|
-
|
|
135
|
-
editorService?.set('root',
|
|
135
|
+
const parseDSL = getConfig('parseDSL');
|
|
136
|
+
editorService?.set('root', parseDSL(value));
|
|
136
137
|
} catch (e: any) {
|
|
137
138
|
console.error(e);
|
|
138
139
|
}
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
ref="tree"
|
|
11
11
|
node-key="id"
|
|
12
12
|
empty-text="页面空荡荡的"
|
|
13
|
+
tabindex="-1"
|
|
13
14
|
draggable
|
|
14
15
|
:default-expanded-keys="expandedKeys"
|
|
15
16
|
:default-checked-keys="checkedKeys"
|
|
@@ -49,8 +50,7 @@
|
|
|
49
50
|
</template>
|
|
50
51
|
|
|
51
52
|
<script lang="ts" setup>
|
|
52
|
-
import { computed, inject, onMounted, onUnmounted, ref, watch } from 'vue';
|
|
53
|
-
import KeyController from 'keycon';
|
|
53
|
+
import { computed, inject, onBeforeUnmount, onMounted, onUnmounted, ref, watch } from 'vue';
|
|
54
54
|
import { difference, throttle, union } from 'lodash-es';
|
|
55
55
|
|
|
56
56
|
import { TMagicScrollbar, TMagicTree } from '@tmagic/design';
|
|
@@ -75,6 +75,7 @@ defineProps<{
|
|
|
75
75
|
const throttleTime = 150;
|
|
76
76
|
const services = inject<Services>('services');
|
|
77
77
|
const editorService = services?.editorService;
|
|
78
|
+
const keybindingService = services?.keybindingService;
|
|
78
79
|
|
|
79
80
|
const tree = ref<InstanceType<typeof TMagicTree>>();
|
|
80
81
|
const menu = ref<InstanceType<typeof LayerMenu>>();
|
|
@@ -246,34 +247,69 @@ const windowBlurHandler = () => {
|
|
|
246
247
|
isCtrlKeyDown.value = false;
|
|
247
248
|
};
|
|
248
249
|
|
|
249
|
-
|
|
250
|
+
keybindingService?.registeCommand('layer-panel-not-ctrl-keydown', (e) => {
|
|
251
|
+
if (e.key !== keybindingService.ctrlKey) {
|
|
252
|
+
isCtrlKeyDown.value = false;
|
|
253
|
+
}
|
|
254
|
+
});
|
|
255
|
+
|
|
256
|
+
keybindingService?.registeCommand('layer-panel-ctrl-keydown', () => {
|
|
257
|
+
isCtrlKeyDown.value = true;
|
|
258
|
+
});
|
|
259
|
+
|
|
260
|
+
keybindingService?.registeCommand('layer-panel-ctrl-keyup', () => {
|
|
261
|
+
isCtrlKeyDown.value = false;
|
|
262
|
+
});
|
|
263
|
+
|
|
264
|
+
keybindingService?.registeCommand('layer-panel-global-keydwon', () => {
|
|
265
|
+
if (!tree.value?.$el.contains(document.activeElement)) {
|
|
266
|
+
isCtrlKeyDown.value = false;
|
|
267
|
+
}
|
|
268
|
+
});
|
|
269
|
+
|
|
270
|
+
keybindingService?.registe([
|
|
271
|
+
{
|
|
272
|
+
command: 'layer-panel-not-ctrl-keydown',
|
|
273
|
+
when: [['layer-panel', 'keydown']],
|
|
274
|
+
},
|
|
275
|
+
{
|
|
276
|
+
command: 'layer-panel-ctrl-keydown',
|
|
277
|
+
keybinding: 'ctrl',
|
|
278
|
+
when: [['layer-panel', 'keydown']],
|
|
279
|
+
},
|
|
280
|
+
{
|
|
281
|
+
command: 'layer-panel-ctrl-keyup',
|
|
282
|
+
keybinding: 'ctrl',
|
|
283
|
+
when: [['layer-panel', 'keyup']],
|
|
284
|
+
},
|
|
285
|
+
{
|
|
286
|
+
command: 'layer-panel-global-keydwon',
|
|
287
|
+
keybinding: 'ctrl',
|
|
288
|
+
when: [['global', 'keydown']],
|
|
289
|
+
},
|
|
290
|
+
]);
|
|
291
|
+
|
|
292
|
+
watch(tree, () => {
|
|
293
|
+
if (tree.value?.$el) {
|
|
294
|
+
keybindingService?.registeEl('layer-panel', tree.value.$el);
|
|
295
|
+
|
|
296
|
+
tree.value.$el.addEventListener('blur', windowBlurHandler);
|
|
297
|
+
} else {
|
|
298
|
+
keybindingService?.unregisteEl('layer-panel');
|
|
299
|
+
}
|
|
300
|
+
});
|
|
250
301
|
|
|
251
302
|
onMounted(() => {
|
|
252
303
|
editorService?.on('remove', editorServiceRemoveHandler);
|
|
253
304
|
|
|
254
|
-
keycon = new KeyController();
|
|
255
|
-
const isMac = /mac os x/.test(navigator.userAgent.toLowerCase());
|
|
256
|
-
const ctrl = isMac ? 'meta' : 'ctrl';
|
|
257
|
-
|
|
258
|
-
keycon
|
|
259
|
-
.keydown((e) => {
|
|
260
|
-
if (e.key !== ctrl) {
|
|
261
|
-
isCtrlKeyDown.value = false;
|
|
262
|
-
}
|
|
263
|
-
})
|
|
264
|
-
.keydown(ctrl, () => {
|
|
265
|
-
isCtrlKeyDown.value = true;
|
|
266
|
-
})
|
|
267
|
-
.keyup(ctrl, () => {
|
|
268
|
-
isCtrlKeyDown.value = false;
|
|
269
|
-
});
|
|
270
|
-
|
|
271
305
|
globalThis.addEventListener('blur', windowBlurHandler);
|
|
272
306
|
});
|
|
273
307
|
|
|
274
|
-
|
|
275
|
-
|
|
308
|
+
onBeforeUnmount(() => {
|
|
309
|
+
tree.value?.$el.removeEventListener('blur', windowBlurHandler);
|
|
310
|
+
});
|
|
276
311
|
|
|
312
|
+
onUnmounted(() => {
|
|
277
313
|
editorService?.off('remove', editorServiceRemoveHandler);
|
|
278
314
|
globalThis.removeEventListener('blur', windowBlurHandler);
|
|
279
315
|
});
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
:size="size"
|
|
11
11
|
:before-close="handleClose"
|
|
12
12
|
>
|
|
13
|
-
<
|
|
13
|
+
<SplitView v-model:left="left" :min-left="45" class="code-editor-layout">
|
|
14
14
|
<!-- 右侧区域 -->
|
|
15
15
|
<template #center>
|
|
16
16
|
<div v-if="!isEmpty(codeConfig)" class="m-editor-code-block-editor-panel">
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
></FunctionEditor>
|
|
29
29
|
</div>
|
|
30
30
|
</template>
|
|
31
|
-
</
|
|
31
|
+
</SplitView>
|
|
32
32
|
</TMagicDrawer>
|
|
33
33
|
</template>
|
|
34
34
|
|
|
@@ -41,7 +41,7 @@ import { ColumnConfig } from '@tmagic/form';
|
|
|
41
41
|
import { CodeBlockContent } from '@tmagic/schema';
|
|
42
42
|
|
|
43
43
|
import FunctionEditor from '@editor/components/FunctionEditor.vue';
|
|
44
|
-
import
|
|
44
|
+
import SplitView from '@editor/components/SplitView.vue';
|
|
45
45
|
import type { ListState, Services } from '@editor/type';
|
|
46
46
|
import { serializeConfig } from '@editor/utils/editor';
|
|
47
47
|
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
<ScrollViewer
|
|
3
3
|
class="m-editor-stage"
|
|
4
4
|
ref="stageWrap"
|
|
5
|
+
tabindex="-1"
|
|
5
6
|
:width="stageRect?.width"
|
|
6
7
|
:height="stageRect?.height"
|
|
7
8
|
:wrap-width="stageContainerRect?.width"
|
|
@@ -35,6 +36,7 @@ import StageCore, { calcValueByFontsize, getOffset, Runtime } from '@tmagic/stag
|
|
|
35
36
|
|
|
36
37
|
import ScrollViewer from '@editor/components/ScrollViewer.vue';
|
|
37
38
|
import { Layout, MenuButton, MenuComponent, Services, StageOptions } from '@editor/type';
|
|
39
|
+
import { getConfig } from '@editor/utils/config';
|
|
38
40
|
import { useStage } from '@editor/utils/stage';
|
|
39
41
|
|
|
40
42
|
import ViewerMenu from './ViewerMenu.vue';
|
|
@@ -74,6 +76,10 @@ watchEffect(() => {
|
|
|
74
76
|
|
|
75
77
|
stage = useStage(stageOptions);
|
|
76
78
|
|
|
79
|
+
stage.on('select', () => {
|
|
80
|
+
stageWrap.value?.container?.focus();
|
|
81
|
+
});
|
|
82
|
+
|
|
77
83
|
services?.editorService.set('stage', markRaw(stage));
|
|
78
84
|
|
|
79
85
|
stage?.mount(stageContainer.value);
|
|
@@ -120,13 +126,17 @@ const resizeObserver = new ResizeObserver((entries) => {
|
|
|
120
126
|
});
|
|
121
127
|
|
|
122
128
|
onMounted(() => {
|
|
123
|
-
|
|
129
|
+
if (stageWrap.value?.container) {
|
|
130
|
+
resizeObserver.observe(stageWrap.value.container);
|
|
131
|
+
services?.keybindingService.registeEl('stage', stageWrap.value.container);
|
|
132
|
+
}
|
|
124
133
|
});
|
|
125
134
|
|
|
126
135
|
onUnmounted(() => {
|
|
127
136
|
stage?.destroy();
|
|
128
137
|
resizeObserver.disconnect();
|
|
129
138
|
services?.editorService.set('stage', null);
|
|
139
|
+
services?.keybindingService.unregisteEl('stage');
|
|
130
140
|
});
|
|
131
141
|
|
|
132
142
|
const contextmenuHandler = (e: MouseEvent) => {
|
|
@@ -153,8 +163,8 @@ const dropHandler = async (e: DragEvent) => {
|
|
|
153
163
|
}
|
|
154
164
|
|
|
155
165
|
if (e.dataTransfer && parent && stageContainer.value && stage) {
|
|
156
|
-
|
|
157
|
-
const config =
|
|
166
|
+
const parseDSL = getConfig('parseDSL');
|
|
167
|
+
const config = parseDSL(`(${e.dataTransfer.getData('data')})`);
|
|
158
168
|
const layout = await services?.editorService.getLayout(parent);
|
|
159
169
|
|
|
160
170
|
const containerRect = stageContainer.value.getBoundingClientRect();
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<div class="m-editor-workspace"
|
|
2
|
+
<div class="m-editor-workspace">
|
|
3
3
|
<Breadcrumb></Breadcrumb>
|
|
4
4
|
|
|
5
5
|
<slot name="stage">
|
|
@@ -16,12 +16,9 @@
|
|
|
16
16
|
</template>
|
|
17
17
|
|
|
18
18
|
<script lang="ts" setup>
|
|
19
|
-
import { computed, inject
|
|
20
|
-
import KeyController from 'keycon';
|
|
19
|
+
import { computed, inject } from 'vue';
|
|
21
20
|
|
|
22
|
-
import {
|
|
23
|
-
|
|
24
|
-
import type { MenuButton, MenuComponent, Services } from '@editor/type';
|
|
21
|
+
import { MenuButton, MenuComponent, Services } from '@editor/type';
|
|
25
22
|
|
|
26
23
|
import Breadcrumb from './Breadcrumb.vue';
|
|
27
24
|
import PageBar from './PageBar.vue';
|
|
@@ -36,132 +33,6 @@ defineProps<{
|
|
|
36
33
|
}>();
|
|
37
34
|
|
|
38
35
|
const services = inject<Services>('services');
|
|
39
|
-
const workspace = ref<HTMLDivElement>();
|
|
40
|
-
const nodes = computed(() => services?.editorService.get('nodes'));
|
|
41
|
-
const page = computed(() => services?.editorService.get('page'));
|
|
42
|
-
|
|
43
|
-
const mouseenterHandler = () => {
|
|
44
|
-
workspace.value?.focus();
|
|
45
|
-
};
|
|
46
|
-
|
|
47
|
-
const mouseleaveHandler = () => {
|
|
48
|
-
workspace.value?.blur();
|
|
49
|
-
};
|
|
50
|
-
|
|
51
|
-
let keycon: KeyController;
|
|
52
|
-
|
|
53
|
-
onMounted(() => {
|
|
54
|
-
workspace.value?.addEventListener('mouseenter', mouseenterHandler);
|
|
55
|
-
workspace.value?.addEventListener('mouseleave', mouseleaveHandler);
|
|
56
|
-
|
|
57
|
-
keycon = new KeyController(workspace.value);
|
|
58
36
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
const ctrl = isMac ? 'meta' : 'ctrl';
|
|
62
|
-
|
|
63
|
-
keycon
|
|
64
|
-
.keyup('delete', (e) => {
|
|
65
|
-
e.inputEvent.preventDefault();
|
|
66
|
-
if (!nodes.value || isPage(nodes.value[0])) return;
|
|
67
|
-
services?.editorService.remove(nodes.value);
|
|
68
|
-
})
|
|
69
|
-
.keyup('backspace', (e) => {
|
|
70
|
-
e.inputEvent.preventDefault();
|
|
71
|
-
if (!nodes.value || isPage(nodes.value[0])) return;
|
|
72
|
-
services?.editorService.remove(nodes.value);
|
|
73
|
-
})
|
|
74
|
-
.keydown([ctrl, 'c'], (e) => {
|
|
75
|
-
e.inputEvent.preventDefault();
|
|
76
|
-
nodes.value && services?.editorService.copy(nodes.value);
|
|
77
|
-
})
|
|
78
|
-
.keydown([ctrl, 'v'], (e) => {
|
|
79
|
-
e.inputEvent.preventDefault();
|
|
80
|
-
nodes.value && services?.editorService.paste({ offsetX: 10, offsetY: 10 });
|
|
81
|
-
})
|
|
82
|
-
.keydown([ctrl, 'x'], (e) => {
|
|
83
|
-
e.inputEvent.preventDefault();
|
|
84
|
-
if (!nodes.value || isPage(nodes.value[0])) return;
|
|
85
|
-
services?.editorService.copy(nodes.value);
|
|
86
|
-
services?.editorService.remove(nodes.value);
|
|
87
|
-
})
|
|
88
|
-
.keydown([ctrl, 'z'], (e) => {
|
|
89
|
-
e.inputEvent.preventDefault();
|
|
90
|
-
services?.editorService.undo();
|
|
91
|
-
})
|
|
92
|
-
.keydown([ctrl, 'shift', 'z'], (e) => {
|
|
93
|
-
e.inputEvent.preventDefault();
|
|
94
|
-
services?.editorService.redo();
|
|
95
|
-
})
|
|
96
|
-
.keydown('up', (e) => {
|
|
97
|
-
e.inputEvent.preventDefault();
|
|
98
|
-
services?.editorService.move(0, -1);
|
|
99
|
-
})
|
|
100
|
-
.keydown('down', (e) => {
|
|
101
|
-
e.inputEvent.preventDefault();
|
|
102
|
-
services?.editorService.move(0, 1);
|
|
103
|
-
})
|
|
104
|
-
.keydown('left', (e) => {
|
|
105
|
-
e.inputEvent.preventDefault();
|
|
106
|
-
services?.editorService.move(-1, 0);
|
|
107
|
-
})
|
|
108
|
-
.keydown('right', (e) => {
|
|
109
|
-
e.inputEvent.preventDefault();
|
|
110
|
-
services?.editorService.move(1, 0);
|
|
111
|
-
})
|
|
112
|
-
.keydown([ctrl, 'up'], (e) => {
|
|
113
|
-
e.inputEvent.preventDefault();
|
|
114
|
-
services?.editorService.move(0, -10);
|
|
115
|
-
})
|
|
116
|
-
.keydown([ctrl, 'down'], (e) => {
|
|
117
|
-
e.inputEvent.preventDefault();
|
|
118
|
-
services?.editorService.move(0, 10);
|
|
119
|
-
})
|
|
120
|
-
.keydown([ctrl, 'left'], (e) => {
|
|
121
|
-
e.inputEvent.preventDefault();
|
|
122
|
-
services?.editorService.move(-10, 0);
|
|
123
|
-
})
|
|
124
|
-
.keydown([ctrl, 'right'], (e) => {
|
|
125
|
-
e.inputEvent.preventDefault();
|
|
126
|
-
services?.editorService.move(10, 0);
|
|
127
|
-
})
|
|
128
|
-
.keydown('tab', (e) => {
|
|
129
|
-
e.inputEvent.preventDefault();
|
|
130
|
-
services?.editorService.selectNextNode();
|
|
131
|
-
})
|
|
132
|
-
.keydown([ctrl, 'tab'], (e) => {
|
|
133
|
-
e.inputEvent.preventDefault();
|
|
134
|
-
services?.editorService.selectNextPage();
|
|
135
|
-
})
|
|
136
|
-
.keydown([ctrl, '='], (e) => {
|
|
137
|
-
e.inputEvent.preventDefault();
|
|
138
|
-
services?.uiService.zoom(0.1);
|
|
139
|
-
})
|
|
140
|
-
.keydown([ctrl, 'numpadplus'], (e) => {
|
|
141
|
-
e.inputEvent.preventDefault();
|
|
142
|
-
services?.uiService.zoom(0.1);
|
|
143
|
-
})
|
|
144
|
-
.keydown([ctrl, '-'], (e) => {
|
|
145
|
-
e.inputEvent.preventDefault();
|
|
146
|
-
services?.uiService.zoom(-0.1);
|
|
147
|
-
})
|
|
148
|
-
.keydown([ctrl, 'numpad-'], (e) => {
|
|
149
|
-
e.inputEvent.preventDefault();
|
|
150
|
-
services?.uiService.zoom(-0.1);
|
|
151
|
-
})
|
|
152
|
-
.keydown([ctrl, '0'], async (e) => {
|
|
153
|
-
e.inputEvent.preventDefault();
|
|
154
|
-
services?.uiService.set('zoom', await services.uiService.calcZoom());
|
|
155
|
-
})
|
|
156
|
-
.keydown([ctrl, '1'], (e) => {
|
|
157
|
-
e.inputEvent.preventDefault();
|
|
158
|
-
services?.uiService.set('zoom', 1);
|
|
159
|
-
});
|
|
160
|
-
});
|
|
161
|
-
|
|
162
|
-
onUnmounted(() => {
|
|
163
|
-
workspace.value?.removeEventListener('mouseenter', mouseenterHandler);
|
|
164
|
-
workspace.value?.removeEventListener('mouseleave', mouseleaveHandler);
|
|
165
|
-
keycon.destroy();
|
|
166
|
-
});
|
|
37
|
+
const page = computed(() => services?.editorService.get('page'));
|
|
167
38
|
</script>
|