mirror of
https://github.com/Tencent/tmagic-editor.git
synced 2025-06-23 10:19:17 +08:00
feat(editor): 优化快捷键操作
This commit is contained in:
parent
567b054b32
commit
06d289aff3
@ -96,6 +96,7 @@ import depService from './services/dep';
|
|||||||
import editorService from './services/editor';
|
import editorService from './services/editor';
|
||||||
import eventsService from './services/events';
|
import eventsService from './services/events';
|
||||||
import historyService from './services/history';
|
import historyService from './services/history';
|
||||||
|
import keybindingService from './services/keybinding';
|
||||||
import propsService from './services/props';
|
import propsService from './services/props';
|
||||||
import storageService from './services/storage';
|
import storageService from './services/storage';
|
||||||
import uiService from './services/ui';
|
import uiService from './services/ui';
|
||||||
@ -130,6 +131,7 @@ export default defineComponent({
|
|||||||
codeBlockService,
|
codeBlockService,
|
||||||
depService,
|
depService,
|
||||||
dataSourceService,
|
dataSourceService,
|
||||||
|
keybindingService,
|
||||||
};
|
};
|
||||||
|
|
||||||
initServiceEvents(props, emit, services);
|
initServiceEvents(props, emit, services);
|
||||||
|
@ -10,6 +10,7 @@
|
|||||||
ref="tree"
|
ref="tree"
|
||||||
node-key="id"
|
node-key="id"
|
||||||
empty-text="页面空荡荡的"
|
empty-text="页面空荡荡的"
|
||||||
|
tabindex="-1"
|
||||||
draggable
|
draggable
|
||||||
:default-expanded-keys="expandedKeys"
|
:default-expanded-keys="expandedKeys"
|
||||||
:default-checked-keys="checkedKeys"
|
:default-checked-keys="checkedKeys"
|
||||||
@ -75,6 +76,7 @@ defineProps<{
|
|||||||
const throttleTime = 150;
|
const throttleTime = 150;
|
||||||
const services = inject<Services>('services');
|
const services = inject<Services>('services');
|
||||||
const editorService = services?.editorService;
|
const editorService = services?.editorService;
|
||||||
|
const keybindingService = services?.keybindingService;
|
||||||
|
|
||||||
const tree = ref<InstanceType<typeof TMagicTree>>();
|
const tree = ref<InstanceType<typeof TMagicTree>>();
|
||||||
const menu = ref<InstanceType<typeof LayerMenu>>();
|
const menu = ref<InstanceType<typeof LayerMenu>>();
|
||||||
@ -246,12 +248,22 @@ const windowBlurHandler = () => {
|
|||||||
isCtrlKeyDown.value = false;
|
isCtrlKeyDown.value = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const globalKeyupHandler = () => {
|
||||||
|
if (document.activeElement !== tree.value?.$el) {
|
||||||
|
isCtrlKeyDown.value = false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
let keycon: KeyController;
|
let keycon: KeyController;
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
editorService?.on('remove', editorServiceRemoveHandler);
|
editorService?.on('remove', editorServiceRemoveHandler);
|
||||||
|
|
||||||
keycon = new KeyController();
|
if (tree.value?.$el) {
|
||||||
|
// 如果是在树上按下ctrl,那么在树外松开ctrl时,也要触发松开事件
|
||||||
|
keybindingService?.on('keyup', globalKeyupHandler);
|
||||||
|
|
||||||
|
keycon = new KeyController(tree.value.$el);
|
||||||
const isMac = /mac os x/.test(navigator.userAgent.toLowerCase());
|
const isMac = /mac os x/.test(navigator.userAgent.toLowerCase());
|
||||||
const ctrl = isMac ? 'meta' : 'ctrl';
|
const ctrl = isMac ? 'meta' : 'ctrl';
|
||||||
|
|
||||||
@ -268,6 +280,9 @@ onMounted(() => {
|
|||||||
isCtrlKeyDown.value = false;
|
isCtrlKeyDown.value = false;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
tree.value.$el.addEventListener('blur', windowBlurHandler);
|
||||||
|
}
|
||||||
|
|
||||||
globalThis.addEventListener('blur', windowBlurHandler);
|
globalThis.addEventListener('blur', windowBlurHandler);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -275,7 +290,9 @@ onUnmounted(() => {
|
|||||||
keycon.destroy();
|
keycon.destroy();
|
||||||
|
|
||||||
editorService?.off('remove', editorServiceRemoveHandler);
|
editorService?.off('remove', editorServiceRemoveHandler);
|
||||||
|
keybindingService?.off('keyup', globalKeyupHandler);
|
||||||
globalThis.removeEventListener('blur', windowBlurHandler);
|
globalThis.removeEventListener('blur', windowBlurHandler);
|
||||||
|
tree.value?.$el.removeEventListener('blur', windowBlurHandler);
|
||||||
});
|
});
|
||||||
|
|
||||||
// 鼠标在组件树移动触发高亮
|
// 鼠标在组件树移动触发高亮
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="m-editor-workspace" tabindex="-1" ref="workspace">
|
<div class="m-editor-workspace" tabindex="-1">
|
||||||
<Breadcrumb></Breadcrumb>
|
<Breadcrumb></Breadcrumb>
|
||||||
|
|
||||||
<slot name="stage">
|
<slot name="stage">
|
||||||
@ -16,10 +16,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { computed, inject, onMounted, onUnmounted, ref } from 'vue';
|
import { computed, inject } from 'vue';
|
||||||
import KeyController from 'keycon';
|
|
||||||
|
|
||||||
import { isPage } from '@tmagic/utils';
|
|
||||||
|
|
||||||
import type { MenuButton, MenuComponent, Services } from '@editor/type';
|
import type { MenuButton, MenuComponent, Services } from '@editor/type';
|
||||||
|
|
||||||
@ -36,132 +33,6 @@ defineProps<{
|
|||||||
}>();
|
}>();
|
||||||
|
|
||||||
const services = inject<Services>('services');
|
const services = inject<Services>('services');
|
||||||
const workspace = ref<HTMLDivElement>();
|
|
||||||
const nodes = computed(() => services?.editorService.get('nodes'));
|
|
||||||
const page = computed(() => services?.editorService.get('page'));
|
const page = computed(() => services?.editorService.get('page'));
|
||||||
|
|
||||||
const mouseenterHandler = () => {
|
|
||||||
workspace.value?.focus();
|
|
||||||
};
|
|
||||||
|
|
||||||
const mouseleaveHandler = () => {
|
|
||||||
workspace.value?.blur();
|
|
||||||
};
|
|
||||||
|
|
||||||
let keycon: KeyController;
|
|
||||||
|
|
||||||
onMounted(() => {
|
|
||||||
workspace.value?.addEventListener('mouseenter', mouseenterHandler);
|
|
||||||
workspace.value?.addEventListener('mouseleave', mouseleaveHandler);
|
|
||||||
|
|
||||||
keycon = new KeyController(workspace.value);
|
|
||||||
|
|
||||||
const isMac = /mac os x/.test(navigator.userAgent.toLowerCase());
|
|
||||||
|
|
||||||
const ctrl = isMac ? 'meta' : 'ctrl';
|
|
||||||
|
|
||||||
keycon
|
|
||||||
.keyup('delete', (e) => {
|
|
||||||
e.inputEvent.preventDefault();
|
|
||||||
if (!nodes.value || isPage(nodes.value[0])) return;
|
|
||||||
services?.editorService.remove(nodes.value);
|
|
||||||
})
|
|
||||||
.keyup('backspace', (e) => {
|
|
||||||
e.inputEvent.preventDefault();
|
|
||||||
if (!nodes.value || isPage(nodes.value[0])) return;
|
|
||||||
services?.editorService.remove(nodes.value);
|
|
||||||
})
|
|
||||||
.keydown([ctrl, 'c'], (e) => {
|
|
||||||
e.inputEvent.preventDefault();
|
|
||||||
nodes.value && services?.editorService.copy(nodes.value);
|
|
||||||
})
|
|
||||||
.keydown([ctrl, 'v'], (e) => {
|
|
||||||
e.inputEvent.preventDefault();
|
|
||||||
nodes.value && services?.editorService.paste({ offsetX: 10, offsetY: 10 });
|
|
||||||
})
|
|
||||||
.keydown([ctrl, 'x'], (e) => {
|
|
||||||
e.inputEvent.preventDefault();
|
|
||||||
if (!nodes.value || isPage(nodes.value[0])) return;
|
|
||||||
services?.editorService.copy(nodes.value);
|
|
||||||
services?.editorService.remove(nodes.value);
|
|
||||||
})
|
|
||||||
.keydown([ctrl, 'z'], (e) => {
|
|
||||||
e.inputEvent.preventDefault();
|
|
||||||
services?.editorService.undo();
|
|
||||||
})
|
|
||||||
.keydown([ctrl, 'shift', 'z'], (e) => {
|
|
||||||
e.inputEvent.preventDefault();
|
|
||||||
services?.editorService.redo();
|
|
||||||
})
|
|
||||||
.keydown('up', (e) => {
|
|
||||||
e.inputEvent.preventDefault();
|
|
||||||
services?.editorService.move(0, -1);
|
|
||||||
})
|
|
||||||
.keydown('down', (e) => {
|
|
||||||
e.inputEvent.preventDefault();
|
|
||||||
services?.editorService.move(0, 1);
|
|
||||||
})
|
|
||||||
.keydown('left', (e) => {
|
|
||||||
e.inputEvent.preventDefault();
|
|
||||||
services?.editorService.move(-1, 0);
|
|
||||||
})
|
|
||||||
.keydown('right', (e) => {
|
|
||||||
e.inputEvent.preventDefault();
|
|
||||||
services?.editorService.move(1, 0);
|
|
||||||
})
|
|
||||||
.keydown([ctrl, 'up'], (e) => {
|
|
||||||
e.inputEvent.preventDefault();
|
|
||||||
services?.editorService.move(0, -10);
|
|
||||||
})
|
|
||||||
.keydown([ctrl, 'down'], (e) => {
|
|
||||||
e.inputEvent.preventDefault();
|
|
||||||
services?.editorService.move(0, 10);
|
|
||||||
})
|
|
||||||
.keydown([ctrl, 'left'], (e) => {
|
|
||||||
e.inputEvent.preventDefault();
|
|
||||||
services?.editorService.move(-10, 0);
|
|
||||||
})
|
|
||||||
.keydown([ctrl, 'right'], (e) => {
|
|
||||||
e.inputEvent.preventDefault();
|
|
||||||
services?.editorService.move(10, 0);
|
|
||||||
})
|
|
||||||
.keydown('tab', (e) => {
|
|
||||||
e.inputEvent.preventDefault();
|
|
||||||
services?.editorService.selectNextNode();
|
|
||||||
})
|
|
||||||
.keydown([ctrl, 'tab'], (e) => {
|
|
||||||
e.inputEvent.preventDefault();
|
|
||||||
services?.editorService.selectNextPage();
|
|
||||||
})
|
|
||||||
.keydown([ctrl, '='], (e) => {
|
|
||||||
e.inputEvent.preventDefault();
|
|
||||||
services?.uiService.zoom(0.1);
|
|
||||||
})
|
|
||||||
.keydown([ctrl, 'numpadplus'], (e) => {
|
|
||||||
e.inputEvent.preventDefault();
|
|
||||||
services?.uiService.zoom(0.1);
|
|
||||||
})
|
|
||||||
.keydown([ctrl, '-'], (e) => {
|
|
||||||
e.inputEvent.preventDefault();
|
|
||||||
services?.uiService.zoom(-0.1);
|
|
||||||
})
|
|
||||||
.keydown([ctrl, 'numpad-'], (e) => {
|
|
||||||
e.inputEvent.preventDefault();
|
|
||||||
services?.uiService.zoom(-0.1);
|
|
||||||
})
|
|
||||||
.keydown([ctrl, '0'], async (e) => {
|
|
||||||
e.inputEvent.preventDefault();
|
|
||||||
services?.uiService.set('zoom', await services.uiService.calcZoom());
|
|
||||||
})
|
|
||||||
.keydown([ctrl, '1'], (e) => {
|
|
||||||
e.inputEvent.preventDefault();
|
|
||||||
services?.uiService.set('zoom', 1);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
onUnmounted(() => {
|
|
||||||
workspace.value?.removeEventListener('mouseenter', mouseenterHandler);
|
|
||||||
workspace.value?.removeEventListener('mouseleave', mouseleaveHandler);
|
|
||||||
keycon.destroy();
|
|
||||||
});
|
|
||||||
</script>
|
</script>
|
||||||
|
240
packages/editor/src/services/keybinding.ts
Normal file
240
packages/editor/src/services/keybinding.ts
Normal file
@ -0,0 +1,240 @@
|
|||||||
|
import KeyController from 'keycon';
|
||||||
|
|
||||||
|
import { isPage } from '@tmagic/utils';
|
||||||
|
|
||||||
|
import BaseService from './BaseService';
|
||||||
|
import editorService from './editor';
|
||||||
|
import uiService from './ui';
|
||||||
|
|
||||||
|
class Keybinding extends BaseService {
|
||||||
|
private keycon = new KeyController();
|
||||||
|
|
||||||
|
private ctrlKey = /mac os x/.test(navigator.userAgent.toLowerCase()) ? 'meta' : 'ctrl';
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
|
||||||
|
this.keycon
|
||||||
|
.keyup((e) => {
|
||||||
|
this.emit('keyup', e.inputEvent);
|
||||||
|
})
|
||||||
|
.keyup('delete', (e) => {
|
||||||
|
if (this.isDisabledKeyEvent(e.inputEvent.target)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
e.inputEvent.preventDefault();
|
||||||
|
|
||||||
|
this.removeNode();
|
||||||
|
})
|
||||||
|
.keyup('backspace', (e) => {
|
||||||
|
if (this.isDisabledKeyEvent(e.inputEvent.target)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
e.inputEvent.preventDefault();
|
||||||
|
|
||||||
|
this.removeNode();
|
||||||
|
})
|
||||||
|
.keydown([this.ctrlKey, 'c'], (e) => {
|
||||||
|
if (this.isDisabledKeyEvent(e.inputEvent.target)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
e.inputEvent.preventDefault();
|
||||||
|
|
||||||
|
const nodes = editorService.get('nodes');
|
||||||
|
nodes && editorService.copy(nodes);
|
||||||
|
})
|
||||||
|
.keydown([this.ctrlKey, 'v'], (e) => {
|
||||||
|
if (this.isDisabledKeyEvent(e.inputEvent.target)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
e.inputEvent.preventDefault();
|
||||||
|
|
||||||
|
const nodes = editorService.get('nodes');
|
||||||
|
nodes && editorService.paste({ offsetX: 10, offsetY: 10 });
|
||||||
|
})
|
||||||
|
.keydown([this.ctrlKey, 'x'], (e) => {
|
||||||
|
if (this.isDisabledKeyEvent(e.inputEvent.target)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
e.inputEvent.preventDefault();
|
||||||
|
if (this.isDisabledKeyEvent(e.inputEvent.target)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const nodes = editorService.get('nodes');
|
||||||
|
|
||||||
|
if (!nodes || isPage(nodes[0])) return;
|
||||||
|
editorService.copy(nodes);
|
||||||
|
editorService.remove(nodes);
|
||||||
|
})
|
||||||
|
.keydown([this.ctrlKey, 'z'], (e) => {
|
||||||
|
if (this.isDisabledKeyEvent(e.inputEvent.target)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
e.inputEvent.preventDefault();
|
||||||
|
editorService.undo();
|
||||||
|
})
|
||||||
|
.keydown([this.ctrlKey, 'shift', 'z'], (e) => {
|
||||||
|
if (this.isDisabledKeyEvent(e.inputEvent.target)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
e.inputEvent.preventDefault();
|
||||||
|
editorService.redo();
|
||||||
|
})
|
||||||
|
.keydown('up', (e) => {
|
||||||
|
if (this.isDisabledKeyEvent(e.inputEvent.target)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
e.inputEvent.preventDefault();
|
||||||
|
editorService.move(0, -1);
|
||||||
|
})
|
||||||
|
.keydown('down', (e) => {
|
||||||
|
if (this.isDisabledKeyEvent(e.inputEvent.target)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
e.inputEvent.preventDefault();
|
||||||
|
editorService.move(0, 1);
|
||||||
|
})
|
||||||
|
.keydown('left', (e) => {
|
||||||
|
if (this.isDisabledKeyEvent(e.inputEvent.target)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
e.inputEvent.preventDefault();
|
||||||
|
editorService.move(-1, 0);
|
||||||
|
})
|
||||||
|
.keydown('right', (e) => {
|
||||||
|
if (this.isDisabledKeyEvent(e.inputEvent.target)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
e.inputEvent.preventDefault();
|
||||||
|
editorService.move(1, 0);
|
||||||
|
})
|
||||||
|
.keydown([this.ctrlKey, 'up'], (e) => {
|
||||||
|
if (this.isDisabledKeyEvent(e.inputEvent.target)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
e.inputEvent.preventDefault();
|
||||||
|
editorService.move(0, -10);
|
||||||
|
})
|
||||||
|
.keydown([this.ctrlKey, 'down'], (e) => {
|
||||||
|
if (this.isDisabledKeyEvent(e.inputEvent.target)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
e.inputEvent.preventDefault();
|
||||||
|
editorService.move(0, 10);
|
||||||
|
})
|
||||||
|
.keydown([this.ctrlKey, 'left'], (e) => {
|
||||||
|
if (this.isDisabledKeyEvent(e.inputEvent.target)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
e.inputEvent.preventDefault();
|
||||||
|
editorService.move(-10, 0);
|
||||||
|
})
|
||||||
|
.keydown([this.ctrlKey, 'right'], (e) => {
|
||||||
|
e.inputEvent.preventDefault();
|
||||||
|
editorService.move(10, 0);
|
||||||
|
})
|
||||||
|
.keydown('tab', (e) => {
|
||||||
|
if (this.isDisabledKeyEvent(e.inputEvent.target)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
e.inputEvent.preventDefault();
|
||||||
|
editorService.selectNextNode();
|
||||||
|
})
|
||||||
|
.keydown([this.ctrlKey, 'tab'], (e) => {
|
||||||
|
if (this.isDisabledKeyEvent(e.inputEvent.target)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
e.inputEvent.preventDefault();
|
||||||
|
editorService.selectNextPage();
|
||||||
|
})
|
||||||
|
.keydown([this.ctrlKey, '='], (e) => {
|
||||||
|
if (this.isDisabledKeyEvent(e.inputEvent.target)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
e.inputEvent.preventDefault();
|
||||||
|
uiService.zoom(0.1);
|
||||||
|
})
|
||||||
|
.keydown([this.ctrlKey, 'numpadplus'], (e) => {
|
||||||
|
if (this.isDisabledKeyEvent(e.inputEvent.target)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
e.inputEvent.preventDefault();
|
||||||
|
uiService.zoom(0.1);
|
||||||
|
})
|
||||||
|
.keydown([this.ctrlKey, '-'], (e) => {
|
||||||
|
if (this.isDisabledKeyEvent(e.inputEvent.target)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
e.inputEvent.preventDefault();
|
||||||
|
uiService.zoom(-0.1);
|
||||||
|
})
|
||||||
|
.keydown([this.ctrlKey, 'numpad-'], (e) => {
|
||||||
|
if (this.isDisabledKeyEvent(e.inputEvent.target)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
e.inputEvent.preventDefault();
|
||||||
|
uiService.zoom(-0.1);
|
||||||
|
})
|
||||||
|
.keydown([this.ctrlKey, '0'], async (e) => {
|
||||||
|
if (this.isDisabledKeyEvent(e.inputEvent.target)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
e.inputEvent.preventDefault();
|
||||||
|
uiService.set('zoom', await uiService.calcZoom());
|
||||||
|
})
|
||||||
|
.keydown([this.ctrlKey, '1'], (e) => {
|
||||||
|
if (this.isDisabledKeyEvent(e.inputEvent.target)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
e.inputEvent.preventDefault();
|
||||||
|
uiService.set('zoom', 1);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public destroy() {
|
||||||
|
this.keycon.destroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
private isDisabledKeyEvent(node: EventTarget | null) {
|
||||||
|
const el = node as HTMLElement | null;
|
||||||
|
|
||||||
|
if (!el) return false;
|
||||||
|
|
||||||
|
// 当前是在输入框中,禁止响应画布快捷键
|
||||||
|
return el.tagName === 'INPUT' || el.tagName === 'TEXTAREA' || el.isContentEditable;
|
||||||
|
}
|
||||||
|
|
||||||
|
private removeNode() {
|
||||||
|
const nodes = editorService.get('nodes');
|
||||||
|
|
||||||
|
if (!nodes || isPage(nodes[0])) return;
|
||||||
|
editorService.remove(nodes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export type KeybindingService = Keybinding;
|
||||||
|
|
||||||
|
export default new Keybinding();
|
@ -30,11 +30,12 @@ import type {
|
|||||||
|
|
||||||
import type { CodeBlockService } from './services/codeBlock';
|
import type { CodeBlockService } from './services/codeBlock';
|
||||||
import type { ComponentListService } from './services/componentList';
|
import type { ComponentListService } from './services/componentList';
|
||||||
import { DataSourceService } from './services/dataSource';
|
import type { DataSourceService } from './services/dataSource';
|
||||||
import type { DepService } from './services/dep';
|
import type { DepService } from './services/dep';
|
||||||
import type { EditorService } from './services/editor';
|
import type { EditorService } from './services/editor';
|
||||||
import type { EventsService } from './services/events';
|
import type { EventsService } from './services/events';
|
||||||
import type { HistoryService } from './services/history';
|
import type { HistoryService } from './services/history';
|
||||||
|
import type { KeybindingService } from './services/keybinding';
|
||||||
import type { PropsService } from './services/props';
|
import type { PropsService } from './services/props';
|
||||||
import type { StorageService } from './services/storage';
|
import type { StorageService } from './services/storage';
|
||||||
import type { UiService } from './services/ui';
|
import type { UiService } from './services/ui';
|
||||||
@ -58,6 +59,7 @@ export interface Services {
|
|||||||
codeBlockService: CodeBlockService;
|
codeBlockService: CodeBlockService;
|
||||||
depService: DepService;
|
depService: DepService;
|
||||||
dataSourceService: DataSourceService;
|
dataSourceService: DataSourceService;
|
||||||
|
keybindingService: KeybindingService;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface StageOptions {
|
export interface StageOptions {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user