mirror of
https://github.com/Tencent/tmagic-editor.git
synced 2025-06-24 11:19:17 +08:00
feat(editor): 完善快捷键注册机制
This commit is contained in:
parent
b37568b440
commit
9716aceabf
@ -100,6 +100,7 @@ import keybindingService from './services/keybinding';
|
||||
import propsService from './services/props';
|
||||
import storageService from './services/storage';
|
||||
import uiService from './services/ui';
|
||||
import keybindingConfig from './utils/keybinding-config';
|
||||
import editorProps from './editorProps';
|
||||
import { initServiceEvents, initServiceState } from './initService';
|
||||
import type { Services } from './type';
|
||||
@ -136,6 +137,8 @@ export default defineComponent({
|
||||
|
||||
initServiceEvents(props, emit, services);
|
||||
initServiceState(props, services);
|
||||
keybindingService.registe(keybindingConfig);
|
||||
keybindingService.registeEl('global');
|
||||
|
||||
provide('services', services);
|
||||
|
||||
|
@ -25,6 +25,7 @@ export const initServiceState = (
|
||||
eventsService,
|
||||
uiService,
|
||||
codeBlockService,
|
||||
keybindingService,
|
||||
}: Services,
|
||||
) => {
|
||||
// 初始值变化,重新设置节点信息
|
||||
@ -104,6 +105,7 @@ export const initServiceState = (
|
||||
uiService.resetState();
|
||||
componentListService.resetState();
|
||||
codeBlockService.resetState();
|
||||
keybindingService.reset();
|
||||
});
|
||||
};
|
||||
|
||||
|
@ -50,8 +50,7 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed, inject, onMounted, onUnmounted, ref, watch } from 'vue';
|
||||
import KeyController from 'keycon';
|
||||
import { computed, inject, onBeforeUnmount, onMounted, onUnmounted, ref, watch } from 'vue';
|
||||
import { difference, throttle, union } from 'lodash-es';
|
||||
|
||||
import { TMagicScrollbar, TMagicTree } from '@tmagic/design';
|
||||
@ -248,53 +247,73 @@ const windowBlurHandler = () => {
|
||||
isCtrlKeyDown.value = false;
|
||||
};
|
||||
|
||||
const globalKeyupHandler = () => {
|
||||
if (document.activeElement !== tree.value?.$el) {
|
||||
keybindingService?.registeCommand('layer-panel-not-ctrl-keydown', (e) => {
|
||||
if (e.key !== keybindingService.ctrlKey) {
|
||||
isCtrlKeyDown.value = false;
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
let keycon: KeyController | undefined;
|
||||
keybindingService?.registeCommand('layer-panel-ctrl-keydown', () => {
|
||||
isCtrlKeyDown.value = true;
|
||||
});
|
||||
|
||||
keybindingService?.registeCommand('layer-panel-ctrl-keyup', () => {
|
||||
isCtrlKeyDown.value = false;
|
||||
});
|
||||
|
||||
keybindingService?.registeCommand('layer-panel-global-keydwon', () => {
|
||||
if (!tree.value?.$el.contains(document.activeElement)) {
|
||||
isCtrlKeyDown.value = false;
|
||||
}
|
||||
});
|
||||
|
||||
keybindingService?.registe([
|
||||
{
|
||||
command: 'layer-panel-not-ctrl-keydown',
|
||||
when: [['layer-panel', 'keydown']],
|
||||
},
|
||||
{
|
||||
command: 'layer-panel-ctrl-keydown',
|
||||
keybinding: 'ctrl',
|
||||
when: [['layer-panel', 'keydown']],
|
||||
},
|
||||
{
|
||||
command: 'layer-panel-ctrl-keyup',
|
||||
keybinding: 'ctrl',
|
||||
when: [['layer-panel', 'keyup']],
|
||||
},
|
||||
{
|
||||
command: 'layer-panel-global-keydwon',
|
||||
keybinding: 'ctrl',
|
||||
when: [['global', 'keydown']],
|
||||
},
|
||||
]);
|
||||
|
||||
watch(tree, () => {
|
||||
if (tree.value?.$el) {
|
||||
keybindingService?.registeEl('layer-panel', tree.value.$el);
|
||||
|
||||
tree.value.$el.addEventListener('blur', windowBlurHandler);
|
||||
} else {
|
||||
keybindingService?.unregisteEl('layer-panel');
|
||||
}
|
||||
});
|
||||
|
||||
onMounted(() => {
|
||||
editorService?.on('remove', editorServiceRemoveHandler);
|
||||
|
||||
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 ctrl = isMac ? 'meta' : 'ctrl';
|
||||
|
||||
keycon
|
||||
.keydown((e) => {
|
||||
if (e.key !== ctrl) {
|
||||
isCtrlKeyDown.value = false;
|
||||
}
|
||||
})
|
||||
.keydown(ctrl, () => {
|
||||
isCtrlKeyDown.value = true;
|
||||
})
|
||||
.keyup(ctrl, () => {
|
||||
isCtrlKeyDown.value = false;
|
||||
});
|
||||
|
||||
tree.value.$el.addEventListener('blur', windowBlurHandler);
|
||||
}
|
||||
|
||||
globalThis.addEventListener('blur', windowBlurHandler);
|
||||
});
|
||||
|
||||
onUnmounted(() => {
|
||||
keycon?.destroy();
|
||||
|
||||
editorService?.off('remove', editorServiceRemoveHandler);
|
||||
keybindingService?.off('keyup', globalKeyupHandler);
|
||||
globalThis.removeEventListener('blur', windowBlurHandler);
|
||||
onBeforeUnmount(() => {
|
||||
tree.value?.$el.removeEventListener('blur', windowBlurHandler);
|
||||
});
|
||||
|
||||
onUnmounted(() => {
|
||||
editorService?.off('remove', editorServiceRemoveHandler);
|
||||
globalThis.removeEventListener('blur', windowBlurHandler);
|
||||
});
|
||||
|
||||
// 鼠标在组件树移动触发高亮
|
||||
const highlightHandler = throttle((data: MNode) => {
|
||||
highlight(data);
|
||||
|
@ -2,6 +2,7 @@
|
||||
<ScrollViewer
|
||||
class="m-editor-stage"
|
||||
ref="stageWrap"
|
||||
tabindex="-1"
|
||||
:width="stageRect?.width"
|
||||
:height="stageRect?.height"
|
||||
:wrap-width="stageContainerRect?.width"
|
||||
@ -74,6 +75,10 @@ watchEffect(() => {
|
||||
|
||||
stage = useStage(stageOptions);
|
||||
|
||||
stage.on('select', () => {
|
||||
stageWrap.value?.container?.focus();
|
||||
});
|
||||
|
||||
services?.editorService.set('stage', markRaw(stage));
|
||||
|
||||
stage?.mount(stageContainer.value);
|
||||
@ -120,13 +125,17 @@ const resizeObserver = new ResizeObserver((entries) => {
|
||||
});
|
||||
|
||||
onMounted(() => {
|
||||
stageWrap.value?.container && resizeObserver.observe(stageWrap.value.container);
|
||||
if (stageWrap.value?.container) {
|
||||
resizeObserver.observe(stageWrap.value.container);
|
||||
services?.keybindingService.registeEl('stage', stageWrap.value.container);
|
||||
}
|
||||
});
|
||||
|
||||
onUnmounted(() => {
|
||||
stage?.destroy();
|
||||
resizeObserver.disconnect();
|
||||
services?.editorService.set('stage', null);
|
||||
services?.keybindingService.unregisteEl('stage');
|
||||
});
|
||||
|
||||
const contextmenuHandler = (e: MouseEvent) => {
|
||||
|
@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div class="m-editor-workspace" tabindex="-1">
|
||||
<div class="m-editor-workspace">
|
||||
<Breadcrumb></Breadcrumb>
|
||||
|
||||
<slot name="stage">
|
||||
@ -18,7 +18,7 @@
|
||||
<script lang="ts" setup>
|
||||
import { computed, inject } from 'vue';
|
||||
|
||||
import type { MenuButton, MenuComponent, Services } from '@editor/type';
|
||||
import { MenuButton, MenuComponent, Services } from '@editor/type';
|
||||
|
||||
import Breadcrumb from './Breadcrumb.vue';
|
||||
import PageBar from './PageBar.vue';
|
||||
|
@ -1,237 +1,182 @@
|
||||
import KeyController from 'keycon';
|
||||
import KeyController, { KeyControllerEvent } from 'keycon';
|
||||
|
||||
import { isPage } from '@tmagic/utils';
|
||||
|
||||
import { KeyBindingCacheItem, KeyBindingCommand, KeyBindingItem } from '@editor/type';
|
||||
|
||||
import BaseService from './BaseService';
|
||||
import editorService from './editor';
|
||||
import uiService from './ui';
|
||||
|
||||
class Keybinding extends BaseService {
|
||||
private keycon = new KeyController();
|
||||
public ctrlKey = /mac os x/.test(navigator.userAgent.toLowerCase()) ? 'meta' : 'ctrl';
|
||||
|
||||
private ctrlKey = /mac os x/.test(navigator.userAgent.toLowerCase()) ? 'meta' : 'ctrl';
|
||||
private controllers = new Map<string, KeyController>();
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
private bindingList: KeyBindingCacheItem[] = [];
|
||||
|
||||
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();
|
||||
private commands: Record<KeyBindingCommand | string, (e: KeyboardEvent) => void | Promise<void>> = {
|
||||
[KeyBindingCommand.DELETE_NODE]: () => {
|
||||
const nodes = editorService.get('nodes');
|
||||
|
||||
if (!nodes || isPage(nodes[0])) return;
|
||||
editorService.remove(nodes);
|
||||
},
|
||||
[KeyBindingCommand.COPY_NODE]: () => {
|
||||
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;
|
||||
}
|
||||
|
||||
},
|
||||
[KeyBindingCommand.CUT_NODE]: () => {
|
||||
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();
|
||||
},
|
||||
[KeyBindingCommand.PASTE_NODE]: () => {
|
||||
const nodes = editorService.get('nodes');
|
||||
nodes && editorService.paste({ offsetX: 10, offsetY: 10 });
|
||||
},
|
||||
[KeyBindingCommand.UNDO]: () => {
|
||||
editorService.undo();
|
||||
})
|
||||
.keydown([this.ctrlKey, 'shift', 'z'], (e) => {
|
||||
if (this.isDisabledKeyEvent(e.inputEvent.target)) {
|
||||
return;
|
||||
}
|
||||
|
||||
e.inputEvent.preventDefault();
|
||||
},
|
||||
[KeyBindingCommand.REDO]: () => {
|
||||
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();
|
||||
},
|
||||
[KeyBindingCommand.ZOOM_IN]: () => {
|
||||
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();
|
||||
},
|
||||
[KeyBindingCommand.ZOOM_OUT]: () => {
|
||||
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();
|
||||
},
|
||||
[KeyBindingCommand.ZOOM_RESET]: () => {
|
||||
uiService.set('zoom', 1);
|
||||
},
|
||||
[KeyBindingCommand.ZOOM_FIT]: async () => {
|
||||
uiService.set('zoom', await uiService.calcZoom());
|
||||
},
|
||||
[KeyBindingCommand.MOVE_UP_1]: () => {
|
||||
editorService.move(0, -1);
|
||||
},
|
||||
[KeyBindingCommand.MOVE_DOWN_1]: () => {
|
||||
editorService.move(0, 1);
|
||||
},
|
||||
[KeyBindingCommand.MOVE_LEFT_1]: () => {
|
||||
editorService.move(-1, 0);
|
||||
},
|
||||
[KeyBindingCommand.MOVE_RIGHT_1]: () => {
|
||||
editorService.move(1, 0);
|
||||
},
|
||||
[KeyBindingCommand.MOVE_UP_10]: () => {
|
||||
editorService.move(0, -10);
|
||||
},
|
||||
[KeyBindingCommand.MOVE_DOWN_10]: () => {
|
||||
editorService.move(0, 10);
|
||||
},
|
||||
[KeyBindingCommand.MOVE_LEFT_10]: () => {
|
||||
editorService.move(-10, 0);
|
||||
},
|
||||
[KeyBindingCommand.MOVE_RIGHT_10]: () => {
|
||||
editorService.move(10, 0);
|
||||
},
|
||||
[KeyBindingCommand.SWITCH_NODE]: () => {
|
||||
editorService.selectNextNode();
|
||||
},
|
||||
};
|
||||
|
||||
public registeCommand(command: string, handler: (e: KeyboardEvent) => void | Promise<void>) {
|
||||
this.commands[command] = handler;
|
||||
}
|
||||
|
||||
public unregisteCommand(command: string) {
|
||||
delete this.commands[command];
|
||||
}
|
||||
|
||||
public registeEl(name: string, el?: HTMLElement) {
|
||||
if (name !== 'global' && !el) {
|
||||
throw new Error('只有name为global可以不传el');
|
||||
}
|
||||
|
||||
const keycon = new KeyController(el);
|
||||
this.controllers.set(name, keycon);
|
||||
this.bind(name);
|
||||
}
|
||||
|
||||
public unregisteEl(name: string) {
|
||||
this.controllers.get(name)?.destroy();
|
||||
this.controllers.delete(name);
|
||||
this.bindingList.forEach((item) => {
|
||||
item.binded = false;
|
||||
});
|
||||
}
|
||||
|
||||
public registe(maps: KeyBindingItem[]) {
|
||||
for (const keybindingItem of maps) {
|
||||
const { command, keybinding, when } = keybindingItem;
|
||||
|
||||
for (const [type = '', eventType = 'keydown'] of when) {
|
||||
const cacheItem: KeyBindingCacheItem = { type, command, keybinding, eventType, binded: false };
|
||||
|
||||
this.bindingList.push(cacheItem);
|
||||
}
|
||||
}
|
||||
|
||||
this.bind();
|
||||
}
|
||||
|
||||
public reset() {
|
||||
this.controllers.forEach((keycon) => {
|
||||
keycon.destroy();
|
||||
});
|
||||
this.controllers.clear();
|
||||
this.bindingList = [];
|
||||
}
|
||||
|
||||
public destroy() {
|
||||
this.keycon.destroy();
|
||||
this.reset();
|
||||
}
|
||||
|
||||
private isDisabledKeyEvent(node: EventTarget | null) {
|
||||
const el = node as HTMLElement | null;
|
||||
private bind(name?: string) {
|
||||
for (const item of this.bindingList) {
|
||||
const { type, eventType, command, keybinding, binded } = item;
|
||||
|
||||
if (!el) return false;
|
||||
|
||||
// 当前是在输入框中,禁止响应画布快捷键
|
||||
return el.tagName === 'INPUT' || el.tagName === 'TEXTAREA' || el.isContentEditable;
|
||||
if (name && name !== type) {
|
||||
continue;
|
||||
}
|
||||
|
||||
private removeNode() {
|
||||
const nodes = editorService.get('nodes');
|
||||
if (binded) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!nodes || isPage(nodes[0])) return;
|
||||
editorService.remove(nodes);
|
||||
const keycon = this.controllers.get(type);
|
||||
if (!keycon) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const handler = (e: KeyControllerEvent) => {
|
||||
e.inputEvent.preventDefault();
|
||||
|
||||
this.commands[command]?.(e.inputEvent);
|
||||
};
|
||||
this.getKeyconKeys(keybinding).forEach((keys) => {
|
||||
if (keys[0]) {
|
||||
keycon[eventType](keys, handler);
|
||||
} else {
|
||||
keycon[eventType](handler);
|
||||
}
|
||||
});
|
||||
|
||||
item.binded = true;
|
||||
}
|
||||
}
|
||||
|
||||
private getKeyconKeys(keybinding: string | string[] = '') {
|
||||
const splitKey = (key: string) => key.split('+').map((k) => (k === 'ctrl' ? this.ctrlKey : k));
|
||||
|
||||
if (Array.isArray(keybinding)) {
|
||||
return keybinding.map((key) => splitKey(key));
|
||||
}
|
||||
return [splitKey(keybinding)];
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -6,6 +6,10 @@
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
|
||||
&:focus-visible {
|
||||
outline: none;
|
||||
}
|
||||
}
|
||||
|
||||
.m-editor-stage-container {
|
||||
|
@ -429,3 +429,58 @@ export interface EventSelectConfig {
|
||||
/** 联动代码配置 */
|
||||
codeActionConfig?: FormItem;
|
||||
}
|
||||
|
||||
export enum KeyBindingCommand {
|
||||
/** 复制 */
|
||||
COPY_NODE = 'tmagic-system-copy-node',
|
||||
/** 粘贴 */
|
||||
PASTE_NODE = 'tmagic-system-paste-node',
|
||||
/** 删除 */
|
||||
DELETE_NODE = 'tmagic-system-delete-node',
|
||||
/** 剪切 */
|
||||
CUT_NODE = 'tmagic-system-cut-node',
|
||||
/** 撤销 */
|
||||
UNDO = 'tmagic-system-undo',
|
||||
/** 重做 */
|
||||
REDO = 'tmagic-system-redo',
|
||||
/** 放大 */
|
||||
ZOOM_IN = 'tmagic-system-zoom-in',
|
||||
/** 缩小 */
|
||||
ZOOM_OUT = 'tmagic-system-zoom-out',
|
||||
/** 缩放到实际大小 */
|
||||
ZOOM_RESET = 'tmagic-system-zoom-reset',
|
||||
/** 缩放以适应 */
|
||||
ZOOM_FIT = 'tmagic-system-zoom-fit',
|
||||
/** 向上移动1px */
|
||||
MOVE_UP_1 = 'tmagic-system-move-up-1',
|
||||
/** 向下移动1px */
|
||||
MOVE_DOWN_1 = 'tmagic-system-move-down-1',
|
||||
/** 向左移动1px */
|
||||
MOVE_LEFT_1 = 'tmagic-system-move-left-1',
|
||||
/** 向右移动1px */
|
||||
MOVE_RIGHT_1 = 'tmagic-system-move-right-1',
|
||||
/** 向上移动10px */
|
||||
MOVE_UP_10 = 'tmagic-system-move-up-10',
|
||||
/** 向下移动10px */
|
||||
MOVE_DOWN_10 = 'tmagic-system-move-down-10',
|
||||
/** 向左移动10px */
|
||||
MOVE_LEFT_10 = 'tmagic-system-move-left-10',
|
||||
/** 向右移动10px */
|
||||
MOVE_RIGHT_10 = 'tmagic-system-move-right-10',
|
||||
/** 切换组件 */
|
||||
SWITCH_NODE = 'tmagic-system-switch-node',
|
||||
}
|
||||
|
||||
export interface KeyBindingItem {
|
||||
command: KeyBindingCommand | string;
|
||||
keybinding?: string | string[];
|
||||
when: [string, 'keyup' | 'keydown'][];
|
||||
}
|
||||
|
||||
export interface KeyBindingCacheItem {
|
||||
type: string;
|
||||
command: KeyBindingCommand | string;
|
||||
keybinding?: string | string[];
|
||||
eventType: 'keyup' | 'keydown';
|
||||
binded: boolean;
|
||||
}
|
||||
|
120
packages/editor/src/utils/keybinding-config.ts
Normal file
120
packages/editor/src/utils/keybinding-config.ts
Normal file
@ -0,0 +1,120 @@
|
||||
import { KeyBindingCommand, KeyBindingItem } from '@editor/type';
|
||||
|
||||
export default [
|
||||
{
|
||||
command: KeyBindingCommand.DELETE_NODE,
|
||||
keybinding: ['delete', 'backspace'],
|
||||
when: [
|
||||
['stage', 'keyup'],
|
||||
['layer-panel', 'keydown'],
|
||||
],
|
||||
},
|
||||
{
|
||||
command: KeyBindingCommand.COPY_NODE,
|
||||
keybinding: 'ctrl+c',
|
||||
when: [
|
||||
['stage', 'keydown'],
|
||||
['layer-panel', 'keydown'],
|
||||
],
|
||||
},
|
||||
{
|
||||
command: KeyBindingCommand.PASTE_NODE,
|
||||
keybinding: 'ctrl+v',
|
||||
when: [
|
||||
['stage', 'keydown'],
|
||||
['layer-panel', 'keydown'],
|
||||
],
|
||||
},
|
||||
{
|
||||
command: KeyBindingCommand.CUT_NODE,
|
||||
keybinding: 'ctrl+x',
|
||||
when: [
|
||||
['stage', 'keydown'],
|
||||
['layer-panel', 'keydown'],
|
||||
],
|
||||
},
|
||||
{
|
||||
command: KeyBindingCommand.UNDO,
|
||||
keybinding: 'ctrl+z',
|
||||
when: [
|
||||
['stage', 'keydown'],
|
||||
['layer-panel', 'keydown'],
|
||||
],
|
||||
},
|
||||
{
|
||||
command: KeyBindingCommand.REDO,
|
||||
keybinding: 'ctrl+shift+z',
|
||||
when: [
|
||||
['stage', 'keydown'],
|
||||
['layer-panel', 'keydown'],
|
||||
],
|
||||
},
|
||||
{
|
||||
command: KeyBindingCommand.MOVE_UP_1,
|
||||
keybinding: 'up',
|
||||
when: [['stage', 'keydown']],
|
||||
},
|
||||
{
|
||||
command: KeyBindingCommand.MOVE_DOWN_1,
|
||||
keybinding: 'down',
|
||||
when: [['stage', 'keydown']],
|
||||
},
|
||||
{
|
||||
command: KeyBindingCommand.MOVE_LEFT_1,
|
||||
keybinding: 'left',
|
||||
when: [['stage', 'keydown']],
|
||||
},
|
||||
{
|
||||
command: KeyBindingCommand.MOVE_RIGHT_1,
|
||||
keybinding: 'right',
|
||||
when: [['stage', 'keydown']],
|
||||
},
|
||||
{
|
||||
command: KeyBindingCommand.MOVE_UP_10,
|
||||
keybinding: 'ctrl+up',
|
||||
when: [['stage', 'keydown']],
|
||||
},
|
||||
{
|
||||
command: KeyBindingCommand.MOVE_DOWN_10,
|
||||
keybinding: 'ctrl+down',
|
||||
when: [['stage', 'keydown']],
|
||||
},
|
||||
{
|
||||
command: KeyBindingCommand.MOVE_LEFT_10,
|
||||
keybinding: 'ctrl+left',
|
||||
when: [['stage', 'keydown']],
|
||||
},
|
||||
{
|
||||
command: KeyBindingCommand.MOVE_RIGHT_10,
|
||||
keybinding: 'ctrl+right',
|
||||
when: [['stage', 'keydown']],
|
||||
},
|
||||
{
|
||||
command: KeyBindingCommand.SWITCH_NODE,
|
||||
keybinding: 'tab',
|
||||
when: [
|
||||
['stage', 'keydown'],
|
||||
['layer-panel', 'keydown'],
|
||||
],
|
||||
},
|
||||
{
|
||||
command: KeyBindingCommand.ZOOM_IN,
|
||||
keybinding: ['ctrl+=', 'ctrl+numpadplus'],
|
||||
when: [['stage', 'keydown']],
|
||||
},
|
||||
{
|
||||
command: KeyBindingCommand.ZOOM_OUT,
|
||||
keybinding: ['ctrl+-', 'ctrl+numpad-'],
|
||||
when: [['stage', 'keydown']],
|
||||
},
|
||||
{
|
||||
command: KeyBindingCommand.ZOOM_FIT,
|
||||
keybinding: 'ctrl+0',
|
||||
when: [['stage', 'keydown']],
|
||||
},
|
||||
{
|
||||
command: KeyBindingCommand.ZOOM_RESET,
|
||||
keybinding: 'ctrl+1',
|
||||
when: [['stage', 'keydown']],
|
||||
},
|
||||
] as KeyBindingItem[];
|
Loading…
x
Reference in New Issue
Block a user