@flowgram-vue/shortcuts-plugin 0.2.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.
- package/LICENSE +22 -0
- package/dist/index.cjs +289 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.ts +41 -0
- package/dist/index.js +286 -0
- package/dist/index.js.map +1 -0
- package/package.json +53 -0
- package/src/create-shortcuts-plugin.ts +28 -0
- package/src/env.d.ts +10 -0
- package/src/index.ts +7 -0
- package/src/layers/index.ts +6 -0
- package/src/layers/shortcuts-layer.ts +64 -0
- package/src/shortcuts-contribution.ts +77 -0
- package/src/shortcuts-utils.ts +186 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
|
|
4
|
+
Copyright (c) 2026 Crayon
|
|
5
|
+
|
|
6
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
7
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
8
|
+
in the Software without restriction, including without limitation the rights
|
|
9
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
10
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
11
|
+
furnished to do so, subject to the following conditions:
|
|
12
|
+
|
|
13
|
+
The above copyright notice and this permission notice shall be included in all
|
|
14
|
+
copies or substantial portions of the Software.
|
|
15
|
+
|
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
17
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
18
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
19
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
20
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
21
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
22
|
+
SOFTWARE.
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,289 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var core = require('@flowgram-vue/core');
|
|
4
|
+
var inversify = require('inversify');
|
|
5
|
+
|
|
6
|
+
var __defProp = Object.defineProperty;
|
|
7
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
8
|
+
var __decorateClass = (decorators, target, key, kind) => {
|
|
9
|
+
var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc(target, key) : target;
|
|
10
|
+
for (var i = decorators.length - 1, decorator; i >= 0; i--)
|
|
11
|
+
if (decorator = decorators[i])
|
|
12
|
+
result = (kind ? decorator(target, key, result) : decorator(result)) || result;
|
|
13
|
+
if (kind && result) __defProp(target, key, result);
|
|
14
|
+
return result;
|
|
15
|
+
};
|
|
16
|
+
var ShortcutsContribution = /* @__PURE__ */ Symbol("ShortcutsContribution");
|
|
17
|
+
exports.ShortcutsRegistry = class ShortcutsRegistry {
|
|
18
|
+
constructor() {
|
|
19
|
+
this.shortcutsHandlers = [];
|
|
20
|
+
}
|
|
21
|
+
addHandlers(...handlers) {
|
|
22
|
+
handlers.forEach((handler) => {
|
|
23
|
+
if (!this.commandRegistry.getCommand(handler.commandId)) {
|
|
24
|
+
this.commandRegistry.registerCommand(
|
|
25
|
+
{ id: handler.commandId, ...handler.commandDetail || {} },
|
|
26
|
+
{ execute: handler.execute, isEnabled: handler.isEnabled }
|
|
27
|
+
);
|
|
28
|
+
} else {
|
|
29
|
+
this.commandRegistry.registerHandler(handler.commandId, {
|
|
30
|
+
execute: handler.execute,
|
|
31
|
+
isEnabled: handler.isEnabled
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
});
|
|
35
|
+
this.shortcutsHandlers.unshift(...handlers);
|
|
36
|
+
}
|
|
37
|
+
addHandlersIfNotFound(...handlers) {
|
|
38
|
+
handlers.forEach((handler) => {
|
|
39
|
+
if (!this.has(handler.commandId)) {
|
|
40
|
+
this.addHandlers(handler);
|
|
41
|
+
}
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
removeHandler(commandId) {
|
|
45
|
+
this.shortcutsHandlers = this.shortcutsHandlers.filter(
|
|
46
|
+
(handler) => handler.commandId !== commandId
|
|
47
|
+
);
|
|
48
|
+
}
|
|
49
|
+
has(commandId) {
|
|
50
|
+
return this.shortcutsHandlers.some((handler) => handler.commandId === commandId);
|
|
51
|
+
}
|
|
52
|
+
init() {
|
|
53
|
+
this.contribs?.forEach((contrib) => contrib.registerShortcuts(this));
|
|
54
|
+
}
|
|
55
|
+
};
|
|
56
|
+
__decorateClass([
|
|
57
|
+
inversify.inject(core.ContributionProvider),
|
|
58
|
+
inversify.named(ShortcutsContribution),
|
|
59
|
+
inversify.optional()
|
|
60
|
+
], exports.ShortcutsRegistry.prototype, "contribs", 2);
|
|
61
|
+
__decorateClass([
|
|
62
|
+
inversify.inject(core.CommandRegistry)
|
|
63
|
+
], exports.ShortcutsRegistry.prototype, "commandRegistry", 2);
|
|
64
|
+
__decorateClass([
|
|
65
|
+
inversify.postConstruct()
|
|
66
|
+
], exports.ShortcutsRegistry.prototype, "init", 1);
|
|
67
|
+
exports.ShortcutsRegistry = __decorateClass([
|
|
68
|
+
inversify.injectable()
|
|
69
|
+
], exports.ShortcutsRegistry);
|
|
70
|
+
|
|
71
|
+
// src/shortcuts-utils.ts
|
|
72
|
+
var isAppleDevice = /(mac|iphone|ipod|ipad)/i.test(
|
|
73
|
+
typeof navigator !== "undefined" ? navigator?.platform : ""
|
|
74
|
+
);
|
|
75
|
+
var aliasKeyCodeMap = {
|
|
76
|
+
"0": 48,
|
|
77
|
+
"1": 49,
|
|
78
|
+
"2": 50,
|
|
79
|
+
"3": 51,
|
|
80
|
+
"4": 52,
|
|
81
|
+
"5": 53,
|
|
82
|
+
"6": 54,
|
|
83
|
+
"7": 55,
|
|
84
|
+
"8": 56,
|
|
85
|
+
"9": 57,
|
|
86
|
+
backspace: 8,
|
|
87
|
+
tab: 9,
|
|
88
|
+
enter: 13,
|
|
89
|
+
shift: 16,
|
|
90
|
+
ctrl: 17,
|
|
91
|
+
alt: 18,
|
|
92
|
+
pausebreak: 19,
|
|
93
|
+
capslock: 20,
|
|
94
|
+
esc: 27,
|
|
95
|
+
space: 32,
|
|
96
|
+
pageup: 33,
|
|
97
|
+
pagedown: 34,
|
|
98
|
+
end: 35,
|
|
99
|
+
home: 36,
|
|
100
|
+
leftarrow: 37,
|
|
101
|
+
uparrow: 38,
|
|
102
|
+
rightarrow: 39,
|
|
103
|
+
downarrow: 40,
|
|
104
|
+
insert: 45,
|
|
105
|
+
delete: 46,
|
|
106
|
+
a: 65,
|
|
107
|
+
b: 66,
|
|
108
|
+
c: 67,
|
|
109
|
+
d: 68,
|
|
110
|
+
e: 69,
|
|
111
|
+
f: 70,
|
|
112
|
+
g: 71,
|
|
113
|
+
h: 72,
|
|
114
|
+
i: 73,
|
|
115
|
+
j: 74,
|
|
116
|
+
k: 75,
|
|
117
|
+
l: 76,
|
|
118
|
+
m: 77,
|
|
119
|
+
n: 78,
|
|
120
|
+
o: 79,
|
|
121
|
+
p: 80,
|
|
122
|
+
q: 81,
|
|
123
|
+
r: 82,
|
|
124
|
+
s: 83,
|
|
125
|
+
t: 84,
|
|
126
|
+
u: 85,
|
|
127
|
+
v: 86,
|
|
128
|
+
w: 87,
|
|
129
|
+
x: 88,
|
|
130
|
+
y: 89,
|
|
131
|
+
z: 90,
|
|
132
|
+
leftwindowkey: 91,
|
|
133
|
+
rightwindowkey: 92,
|
|
134
|
+
meta: isAppleDevice ? [91, 93] : [91, 92],
|
|
135
|
+
selectkey: 93,
|
|
136
|
+
numpad0: 96,
|
|
137
|
+
numpad1: 97,
|
|
138
|
+
numpad2: 98,
|
|
139
|
+
numpad3: 99,
|
|
140
|
+
numpad4: 100,
|
|
141
|
+
numpad5: 101,
|
|
142
|
+
numpad6: 102,
|
|
143
|
+
numpad7: 103,
|
|
144
|
+
numpad8: 104,
|
|
145
|
+
numpad9: 105,
|
|
146
|
+
multiply: 106,
|
|
147
|
+
add: 107,
|
|
148
|
+
subtract: 109,
|
|
149
|
+
decimalpoint: 110,
|
|
150
|
+
divide: 111,
|
|
151
|
+
f1: 112,
|
|
152
|
+
f2: 113,
|
|
153
|
+
f3: 114,
|
|
154
|
+
f4: 115,
|
|
155
|
+
f5: 116,
|
|
156
|
+
f6: 117,
|
|
157
|
+
f7: 118,
|
|
158
|
+
f8: 119,
|
|
159
|
+
f9: 120,
|
|
160
|
+
f10: 121,
|
|
161
|
+
f11: 122,
|
|
162
|
+
f12: 123,
|
|
163
|
+
numlock: 144,
|
|
164
|
+
scrolllock: 145,
|
|
165
|
+
semicolon: 186,
|
|
166
|
+
equalsign: 187,
|
|
167
|
+
"=": 187,
|
|
168
|
+
comma: 188,
|
|
169
|
+
dash: 189,
|
|
170
|
+
"-": 189,
|
|
171
|
+
period: 190,
|
|
172
|
+
forwardslash: 191,
|
|
173
|
+
graveaccent: 192,
|
|
174
|
+
openbracket: 219,
|
|
175
|
+
backslash: 220,
|
|
176
|
+
closebracket: 221,
|
|
177
|
+
singlequote: 222
|
|
178
|
+
};
|
|
179
|
+
var modifierKey = {
|
|
180
|
+
ctrl: (event) => event.ctrlKey,
|
|
181
|
+
shift: (event) => event.shiftKey,
|
|
182
|
+
alt: (event) => event.altKey,
|
|
183
|
+
meta: (event) => {
|
|
184
|
+
if (event.type === "keyup") {
|
|
185
|
+
return aliasKeyCodeMap.meta.includes(event.keyCode);
|
|
186
|
+
}
|
|
187
|
+
return event.metaKey;
|
|
188
|
+
}
|
|
189
|
+
};
|
|
190
|
+
function countKeyByEvent(event) {
|
|
191
|
+
const countOfModifier = Object.keys(modifierKey).reduce((total, key) => {
|
|
192
|
+
if (modifierKey[key](event)) {
|
|
193
|
+
return total + 1;
|
|
194
|
+
}
|
|
195
|
+
return total;
|
|
196
|
+
}, 0);
|
|
197
|
+
return [16, 17, 18, 91, 92].includes(event.keyCode) ? countOfModifier : countOfModifier + 1;
|
|
198
|
+
}
|
|
199
|
+
function isKeyStringMatch(event, keyString, exactMatch = true) {
|
|
200
|
+
if (!event.key || !keyString) {
|
|
201
|
+
return false;
|
|
202
|
+
}
|
|
203
|
+
const genArr = keyString.split(/\s+/);
|
|
204
|
+
let genLen = 0;
|
|
205
|
+
for (const key of genArr) {
|
|
206
|
+
const genModifier = modifierKey[key];
|
|
207
|
+
const aliasKeyCode = aliasKeyCodeMap[key.toLowerCase()];
|
|
208
|
+
if (genModifier && genModifier(event) || aliasKeyCode && aliasKeyCode === event.keyCode) {
|
|
209
|
+
genLen++;
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
if (exactMatch) {
|
|
213
|
+
return genLen === genArr.length && countKeyByEvent(event) === genArr.length;
|
|
214
|
+
}
|
|
215
|
+
return genLen === genArr.length;
|
|
216
|
+
}
|
|
217
|
+
function isShortcutsMatch(event, shortcuts) {
|
|
218
|
+
return shortcuts.some((keyString) => isKeyStringMatch(event, keyString));
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
// src/layers/shortcuts-layer.ts
|
|
222
|
+
var ShortcutsLayer = class extends core.Layer {
|
|
223
|
+
onReady() {
|
|
224
|
+
this.shortcuts.addHandlersIfNotFound(
|
|
225
|
+
/**
|
|
226
|
+
* 放大
|
|
227
|
+
*/
|
|
228
|
+
{
|
|
229
|
+
commandId: core.Command.Default.ZOOM_IN,
|
|
230
|
+
shortcuts: ["meta =", "ctrl ="],
|
|
231
|
+
execute: () => {
|
|
232
|
+
this.config.zoomin();
|
|
233
|
+
}
|
|
234
|
+
},
|
|
235
|
+
/**
|
|
236
|
+
* 缩小
|
|
237
|
+
*/
|
|
238
|
+
{
|
|
239
|
+
commandId: core.Command.Default.ZOOM_OUT,
|
|
240
|
+
shortcuts: ["meta -", "ctrl -"],
|
|
241
|
+
execute: () => {
|
|
242
|
+
this.config.zoomout();
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
);
|
|
246
|
+
this.toDispose.pushAll([
|
|
247
|
+
// 监听画布鼠标移动事件
|
|
248
|
+
this.listenPlaygroundEvent("keydown", (e) => {
|
|
249
|
+
if (!this.isFocused || e.target !== this.playgroundNode) {
|
|
250
|
+
return;
|
|
251
|
+
}
|
|
252
|
+
this.shortcuts.shortcutsHandlers.some((shortcutsHandler) => {
|
|
253
|
+
if (isShortcutsMatch(e, shortcutsHandler.shortcuts) && (!shortcutsHandler.isEnabled || shortcutsHandler.isEnabled(e))) {
|
|
254
|
+
shortcutsHandler.execute(e);
|
|
255
|
+
e.preventDefault();
|
|
256
|
+
return true;
|
|
257
|
+
}
|
|
258
|
+
});
|
|
259
|
+
})
|
|
260
|
+
]);
|
|
261
|
+
}
|
|
262
|
+
};
|
|
263
|
+
ShortcutsLayer.type = "ShortcutsLayer";
|
|
264
|
+
__decorateClass([
|
|
265
|
+
inversify.inject(exports.ShortcutsRegistry)
|
|
266
|
+
], ShortcutsLayer.prototype, "shortcuts", 2);
|
|
267
|
+
__decorateClass([
|
|
268
|
+
inversify.inject(core.SelectionService)
|
|
269
|
+
], ShortcutsLayer.prototype, "selection", 2);
|
|
270
|
+
ShortcutsLayer = __decorateClass([
|
|
271
|
+
inversify.injectable()
|
|
272
|
+
], ShortcutsLayer);
|
|
273
|
+
|
|
274
|
+
// src/create-shortcuts-plugin.ts
|
|
275
|
+
var createShortcutsPlugin = core.definePluginCreator({
|
|
276
|
+
onBind: ({ bind }) => {
|
|
277
|
+
bind(exports.ShortcutsRegistry).toSelf().inSingletonScope();
|
|
278
|
+
core.bindContributionProvider(bind, ShortcutsContribution);
|
|
279
|
+
},
|
|
280
|
+
onInit: (ctx) => {
|
|
281
|
+
ctx.playground.registerLayer(ShortcutsLayer);
|
|
282
|
+
},
|
|
283
|
+
contributionKeys: [ShortcutsContribution]
|
|
284
|
+
});
|
|
285
|
+
|
|
286
|
+
exports.ShortcutsContribution = ShortcutsContribution;
|
|
287
|
+
exports.createShortcutsPlugin = createShortcutsPlugin;
|
|
288
|
+
//# sourceMappingURL=index.cjs.map
|
|
289
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/shortcuts-contribution.ts","../src/shortcuts-utils.ts","../src/layers/shortcuts-layer.ts","../src/create-shortcuts-plugin.ts"],"names":["ShortcutsRegistry","inject","ContributionProvider","named","optional","CommandRegistry","postConstruct","injectable","Layer","Command","SelectionService","definePluginCreator","bindContributionProvider"],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport { inject, injectable, named, optional, postConstruct } from 'inversify';\nimport { Command, CommandRegistry, ContributionProvider } from '@flowgram-vue/core';\n\nexport interface ShortcutsHandler {\n commandId: string;\n commandDetail?: Omit<Command, 'id'>;\n shortcuts: string[];\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n isEnabled?: (...args: any[]) => boolean;\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n execute: (...args: any[]) => void;\n}\n\nexport const ShortcutsContribution = Symbol('ShortcutsContribution');\n\nexport interface ShortcutsContribution {\n registerShortcuts: (registry: ShortcutsRegistry) => void;\n}\n\n@injectable()\nexport class ShortcutsRegistry {\n @inject(ContributionProvider)\n @named(ShortcutsContribution)\n @optional()\n protected contribs: ContributionProvider<ShortcutsContribution>;\n\n @inject(CommandRegistry) protected commandRegistry: CommandRegistry;\n\n shortcutsHandlers: ShortcutsHandler[] = [];\n\n addHandlers(...handlers: ShortcutsHandler[]): void {\n // 注册 command\n handlers.forEach((handler) => {\n if (!this.commandRegistry.getCommand(handler.commandId)) {\n this.commandRegistry.registerCommand(\n { id: handler.commandId, ...(handler.commandDetail || {}) },\n { execute: handler.execute, isEnabled: handler.isEnabled }\n );\n } else {\n this.commandRegistry.registerHandler(handler.commandId, {\n execute: handler.execute,\n isEnabled: handler.isEnabled,\n });\n }\n });\n // Insert before for override pre handlers\n this.shortcutsHandlers.unshift(...handlers);\n }\n\n addHandlersIfNotFound(...handlers: ShortcutsHandler[]): void {\n handlers.forEach((handler) => {\n if (!this.has(handler.commandId)) {\n this.addHandlers(handler);\n }\n });\n }\n\n removeHandler(commandId: string): void {\n this.shortcutsHandlers = this.shortcutsHandlers.filter(\n (handler) => handler.commandId !== commandId\n );\n }\n\n has(commandId: string): boolean {\n return this.shortcutsHandlers.some((handler) => handler.commandId === commandId);\n }\n\n @postConstruct()\n protected init(): void {\n this.contribs?.forEach((contrib) => contrib.registerShortcuts(this));\n }\n}\n","/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nconst isAppleDevice = /(mac|iphone|ipod|ipad)/i.test(\n typeof navigator !== 'undefined' ? navigator?.platform : '',\n);\n// 键盘事件 keyCode 别名\nconst aliasKeyCodeMap: Record<string, number | number[]> = {\n '0': 48,\n '1': 49,\n '2': 50,\n '3': 51,\n '4': 52,\n '5': 53,\n '6': 54,\n '7': 55,\n '8': 56,\n '9': 57,\n backspace: 8,\n tab: 9,\n enter: 13,\n shift: 16,\n ctrl: 17,\n alt: 18,\n pausebreak: 19,\n capslock: 20,\n esc: 27,\n space: 32,\n pageup: 33,\n pagedown: 34,\n end: 35,\n home: 36,\n leftarrow: 37,\n uparrow: 38,\n rightarrow: 39,\n downarrow: 40,\n insert: 45,\n delete: 46,\n a: 65,\n b: 66,\n c: 67,\n d: 68,\n e: 69,\n f: 70,\n g: 71,\n h: 72,\n i: 73,\n j: 74,\n k: 75,\n l: 76,\n m: 77,\n n: 78,\n o: 79,\n p: 80,\n q: 81,\n r: 82,\n s: 83,\n t: 84,\n u: 85,\n v: 86,\n w: 87,\n x: 88,\n y: 89,\n z: 90,\n leftwindowkey: 91,\n rightwindowkey: 92,\n meta: isAppleDevice ? [91, 93] : [91, 92],\n selectkey: 93,\n numpad0: 96,\n numpad1: 97,\n numpad2: 98,\n numpad3: 99,\n numpad4: 100,\n numpad5: 101,\n numpad6: 102,\n numpad7: 103,\n numpad8: 104,\n numpad9: 105,\n multiply: 106,\n add: 107,\n subtract: 109,\n decimalpoint: 110,\n divide: 111,\n f1: 112,\n f2: 113,\n f3: 114,\n f4: 115,\n f5: 116,\n f6: 117,\n f7: 118,\n f8: 119,\n f9: 120,\n f10: 121,\n f11: 122,\n f12: 123,\n numlock: 144,\n scrolllock: 145,\n semicolon: 186,\n equalsign: 187,\n '=': 187,\n comma: 188,\n dash: 189,\n '-': 189,\n period: 190,\n forwardslash: 191,\n graveaccent: 192,\n openbracket: 219,\n backslash: 220,\n closebracket: 221,\n singlequote: 222,\n};\n\nconst modifierKey: any = {\n ctrl: (event: KeyboardEvent) => event.ctrlKey,\n shift: (event: KeyboardEvent) => event.shiftKey,\n alt: (event: KeyboardEvent) => event.altKey,\n meta: (event: KeyboardEvent) => {\n if (event.type === 'keyup') {\n return (aliasKeyCodeMap.meta as number[]).includes(event.keyCode);\n }\n return event.metaKey;\n },\n};\n\n// 根据 event 计算激活键数量\nfunction countKeyByEvent(event: KeyboardEvent): number {\n const countOfModifier = Object.keys(modifierKey).reduce((total, key) => {\n if (modifierKey[key](event)) {\n return total + 1;\n }\n\n return total;\n }, 0);\n\n // 16 17 18 91 92 是修饰键的 keyCode,如果 keyCode 是修饰键,那么激活数量就是修饰键的数量,如果不是,那么就需要 +1\n return [16, 17, 18, 91, 92].includes(event.keyCode) ? countOfModifier : countOfModifier + 1;\n}\n\n/**\n *\n * @param event\n * @param keyString 'ctrl.s' 'meta.s'\n * @param exactMatch\n */\nfunction isKeyStringMatch(event: KeyboardEvent, keyString: string, exactMatch = true): boolean {\n // 浏览器自动补全 input 的时候,会触发 keyDown、keyUp 事件,但此时 event.key 等为空\n if (!event.key || !keyString) {\n return false;\n }\n // 字符串依次判断是否有组合键\n const genArr = keyString.split(/\\s+/);\n let genLen = 0;\n\n for (const key of genArr) {\n // 组合键\n const genModifier = modifierKey[key];\n // keyCode 别名\n const aliasKeyCode: number | number[] = aliasKeyCodeMap[key.toLowerCase()];\n\n if ((genModifier && genModifier(event)) || (aliasKeyCode && aliasKeyCode === event.keyCode)) {\n genLen++;\n }\n }\n\n /**\n * 需要判断触发的键位和监听的键位完全一致,判断方法就是触发的键位里有且等于监听的键位\n * genLen === genArr.length 能判断出来触发的键位里有监听的键位\n * countKeyByEvent(event) === genArr.length 判断出来触发的键位数量里有且等于监听的键位数量\n * 主要用来防止按组合键其子集也会触发的情况,例如监听 ctrl+a 会触发监听 ctrl 和 a 两个键的事件。\n */\n if (exactMatch) {\n return genLen === genArr.length && countKeyByEvent(event) === genArr.length;\n }\n return genLen === genArr.length;\n}\n\n/**\n * 匹配指定的快捷键\n * @param event\n * @param shortcuts\n */\nexport function isShortcutsMatch(event: KeyboardEvent, shortcuts: string[]): boolean {\n return shortcuts.some(keyString => isKeyStringMatch(event, keyString));\n}\n","/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport { inject, injectable } from 'inversify';\nimport { Layer, SelectionService, Command } from '@flowgram-vue/core';\n\nimport { isShortcutsMatch } from '../shortcuts-utils';\nimport { ShortcutsRegistry } from '../shortcuts-contribution';\n\n@injectable()\nexport class ShortcutsLayer extends Layer<object> {\n static type = 'ShortcutsLayer';\n\n @inject(ShortcutsRegistry) shortcuts: ShortcutsRegistry;\n\n @inject(SelectionService) selection: SelectionService;\n\n onReady(): void {\n this.shortcuts.addHandlersIfNotFound(\n /**\n * 放大\n */\n {\n commandId: Command.Default.ZOOM_IN,\n shortcuts: ['meta =', 'ctrl ='],\n execute: () => {\n // TODO 这里要判断 CurrentEditor\n this.config.zoomin();\n },\n },\n /**\n * 缩小\n */\n {\n commandId: Command.Default.ZOOM_OUT,\n shortcuts: ['meta -', 'ctrl -'],\n execute: () => {\n // TODO 这里要判断 CurrentEditor\n this.config.zoomout();\n },\n },\n );\n this.toDispose.pushAll([\n // 监听画布鼠标移动事件\n this.listenPlaygroundEvent('keydown', (e: KeyboardEvent) => {\n if (!this.isFocused || e.target !== this.playgroundNode) {\n return;\n }\n this.shortcuts.shortcutsHandlers.some(shortcutsHandler => {\n if (\n isShortcutsMatch(e, shortcutsHandler.shortcuts) &&\n (!shortcutsHandler.isEnabled || shortcutsHandler.isEnabled(e))\n ) {\n shortcutsHandler.execute(e);\n e.preventDefault();\n return true;\n }\n });\n }),\n ]);\n }\n}\n","/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport { bindContributionProvider, definePluginCreator } from '@flowgram-vue/core';\n\nimport { ShortcutsRegistry, ShortcutsContribution } from './shortcuts-contribution';\nimport { ShortcutsLayer } from './layers';\n\n/**\n * @param opts\n *\n * createShortcutsPlugin({\n * registerShortcuts(registry) {\n * }\n * })\n */\nexport const createShortcutsPlugin = definePluginCreator<ShortcutsContribution>({\n onBind: ({ bind }) => {\n bind(ShortcutsRegistry).toSelf().inSingletonScope();\n bindContributionProvider(bind, ShortcutsContribution);\n },\n onInit: (ctx) => {\n ctx.playground.registerLayer(ShortcutsLayer);\n },\n contributionKeys: [ShortcutsContribution],\n});\n"]}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import * as _flowgram_vue_core from '@flowgram-vue/core';
|
|
2
|
+
import { ContributionProvider, CommandRegistry, Command } from '@flowgram-vue/core';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
|
|
6
|
+
* SPDX-License-Identifier: MIT
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
interface ShortcutsHandler {
|
|
10
|
+
commandId: string;
|
|
11
|
+
commandDetail?: Omit<Command, 'id'>;
|
|
12
|
+
shortcuts: string[];
|
|
13
|
+
isEnabled?: (...args: any[]) => boolean;
|
|
14
|
+
execute: (...args: any[]) => void;
|
|
15
|
+
}
|
|
16
|
+
declare const ShortcutsContribution: unique symbol;
|
|
17
|
+
interface ShortcutsContribution {
|
|
18
|
+
registerShortcuts: (registry: ShortcutsRegistry) => void;
|
|
19
|
+
}
|
|
20
|
+
declare class ShortcutsRegistry {
|
|
21
|
+
protected contribs: ContributionProvider<ShortcutsContribution>;
|
|
22
|
+
protected commandRegistry: CommandRegistry;
|
|
23
|
+
shortcutsHandlers: ShortcutsHandler[];
|
|
24
|
+
addHandlers(...handlers: ShortcutsHandler[]): void;
|
|
25
|
+
addHandlersIfNotFound(...handlers: ShortcutsHandler[]): void;
|
|
26
|
+
removeHandler(commandId: string): void;
|
|
27
|
+
has(commandId: string): boolean;
|
|
28
|
+
protected init(): void;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* @param opts
|
|
33
|
+
*
|
|
34
|
+
* createShortcutsPlugin({
|
|
35
|
+
* registerShortcuts(registry) {
|
|
36
|
+
* }
|
|
37
|
+
* })
|
|
38
|
+
*/
|
|
39
|
+
declare const createShortcutsPlugin: _flowgram_vue_core.PluginCreator<ShortcutsContribution>;
|
|
40
|
+
|
|
41
|
+
export { ShortcutsContribution, type ShortcutsHandler, ShortcutsRegistry, createShortcutsPlugin };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,286 @@
|
|
|
1
|
+
import { ContributionProvider, CommandRegistry, SelectionService, definePluginCreator, bindContributionProvider, Layer, Command } from '@flowgram-vue/core';
|
|
2
|
+
import { inject, named, optional, postConstruct, injectable } from 'inversify';
|
|
3
|
+
|
|
4
|
+
var __defProp = Object.defineProperty;
|
|
5
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
6
|
+
var __decorateClass = (decorators, target, key, kind) => {
|
|
7
|
+
var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc(target, key) : target;
|
|
8
|
+
for (var i = decorators.length - 1, decorator; i >= 0; i--)
|
|
9
|
+
if (decorator = decorators[i])
|
|
10
|
+
result = (kind ? decorator(target, key, result) : decorator(result)) || result;
|
|
11
|
+
if (kind && result) __defProp(target, key, result);
|
|
12
|
+
return result;
|
|
13
|
+
};
|
|
14
|
+
var ShortcutsContribution = /* @__PURE__ */ Symbol("ShortcutsContribution");
|
|
15
|
+
var ShortcutsRegistry = class {
|
|
16
|
+
constructor() {
|
|
17
|
+
this.shortcutsHandlers = [];
|
|
18
|
+
}
|
|
19
|
+
addHandlers(...handlers) {
|
|
20
|
+
handlers.forEach((handler) => {
|
|
21
|
+
if (!this.commandRegistry.getCommand(handler.commandId)) {
|
|
22
|
+
this.commandRegistry.registerCommand(
|
|
23
|
+
{ id: handler.commandId, ...handler.commandDetail || {} },
|
|
24
|
+
{ execute: handler.execute, isEnabled: handler.isEnabled }
|
|
25
|
+
);
|
|
26
|
+
} else {
|
|
27
|
+
this.commandRegistry.registerHandler(handler.commandId, {
|
|
28
|
+
execute: handler.execute,
|
|
29
|
+
isEnabled: handler.isEnabled
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
this.shortcutsHandlers.unshift(...handlers);
|
|
34
|
+
}
|
|
35
|
+
addHandlersIfNotFound(...handlers) {
|
|
36
|
+
handlers.forEach((handler) => {
|
|
37
|
+
if (!this.has(handler.commandId)) {
|
|
38
|
+
this.addHandlers(handler);
|
|
39
|
+
}
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
removeHandler(commandId) {
|
|
43
|
+
this.shortcutsHandlers = this.shortcutsHandlers.filter(
|
|
44
|
+
(handler) => handler.commandId !== commandId
|
|
45
|
+
);
|
|
46
|
+
}
|
|
47
|
+
has(commandId) {
|
|
48
|
+
return this.shortcutsHandlers.some((handler) => handler.commandId === commandId);
|
|
49
|
+
}
|
|
50
|
+
init() {
|
|
51
|
+
this.contribs?.forEach((contrib) => contrib.registerShortcuts(this));
|
|
52
|
+
}
|
|
53
|
+
};
|
|
54
|
+
__decorateClass([
|
|
55
|
+
inject(ContributionProvider),
|
|
56
|
+
named(ShortcutsContribution),
|
|
57
|
+
optional()
|
|
58
|
+
], ShortcutsRegistry.prototype, "contribs", 2);
|
|
59
|
+
__decorateClass([
|
|
60
|
+
inject(CommandRegistry)
|
|
61
|
+
], ShortcutsRegistry.prototype, "commandRegistry", 2);
|
|
62
|
+
__decorateClass([
|
|
63
|
+
postConstruct()
|
|
64
|
+
], ShortcutsRegistry.prototype, "init", 1);
|
|
65
|
+
ShortcutsRegistry = __decorateClass([
|
|
66
|
+
injectable()
|
|
67
|
+
], ShortcutsRegistry);
|
|
68
|
+
|
|
69
|
+
// src/shortcuts-utils.ts
|
|
70
|
+
var isAppleDevice = /(mac|iphone|ipod|ipad)/i.test(
|
|
71
|
+
typeof navigator !== "undefined" ? navigator?.platform : ""
|
|
72
|
+
);
|
|
73
|
+
var aliasKeyCodeMap = {
|
|
74
|
+
"0": 48,
|
|
75
|
+
"1": 49,
|
|
76
|
+
"2": 50,
|
|
77
|
+
"3": 51,
|
|
78
|
+
"4": 52,
|
|
79
|
+
"5": 53,
|
|
80
|
+
"6": 54,
|
|
81
|
+
"7": 55,
|
|
82
|
+
"8": 56,
|
|
83
|
+
"9": 57,
|
|
84
|
+
backspace: 8,
|
|
85
|
+
tab: 9,
|
|
86
|
+
enter: 13,
|
|
87
|
+
shift: 16,
|
|
88
|
+
ctrl: 17,
|
|
89
|
+
alt: 18,
|
|
90
|
+
pausebreak: 19,
|
|
91
|
+
capslock: 20,
|
|
92
|
+
esc: 27,
|
|
93
|
+
space: 32,
|
|
94
|
+
pageup: 33,
|
|
95
|
+
pagedown: 34,
|
|
96
|
+
end: 35,
|
|
97
|
+
home: 36,
|
|
98
|
+
leftarrow: 37,
|
|
99
|
+
uparrow: 38,
|
|
100
|
+
rightarrow: 39,
|
|
101
|
+
downarrow: 40,
|
|
102
|
+
insert: 45,
|
|
103
|
+
delete: 46,
|
|
104
|
+
a: 65,
|
|
105
|
+
b: 66,
|
|
106
|
+
c: 67,
|
|
107
|
+
d: 68,
|
|
108
|
+
e: 69,
|
|
109
|
+
f: 70,
|
|
110
|
+
g: 71,
|
|
111
|
+
h: 72,
|
|
112
|
+
i: 73,
|
|
113
|
+
j: 74,
|
|
114
|
+
k: 75,
|
|
115
|
+
l: 76,
|
|
116
|
+
m: 77,
|
|
117
|
+
n: 78,
|
|
118
|
+
o: 79,
|
|
119
|
+
p: 80,
|
|
120
|
+
q: 81,
|
|
121
|
+
r: 82,
|
|
122
|
+
s: 83,
|
|
123
|
+
t: 84,
|
|
124
|
+
u: 85,
|
|
125
|
+
v: 86,
|
|
126
|
+
w: 87,
|
|
127
|
+
x: 88,
|
|
128
|
+
y: 89,
|
|
129
|
+
z: 90,
|
|
130
|
+
leftwindowkey: 91,
|
|
131
|
+
rightwindowkey: 92,
|
|
132
|
+
meta: isAppleDevice ? [91, 93] : [91, 92],
|
|
133
|
+
selectkey: 93,
|
|
134
|
+
numpad0: 96,
|
|
135
|
+
numpad1: 97,
|
|
136
|
+
numpad2: 98,
|
|
137
|
+
numpad3: 99,
|
|
138
|
+
numpad4: 100,
|
|
139
|
+
numpad5: 101,
|
|
140
|
+
numpad6: 102,
|
|
141
|
+
numpad7: 103,
|
|
142
|
+
numpad8: 104,
|
|
143
|
+
numpad9: 105,
|
|
144
|
+
multiply: 106,
|
|
145
|
+
add: 107,
|
|
146
|
+
subtract: 109,
|
|
147
|
+
decimalpoint: 110,
|
|
148
|
+
divide: 111,
|
|
149
|
+
f1: 112,
|
|
150
|
+
f2: 113,
|
|
151
|
+
f3: 114,
|
|
152
|
+
f4: 115,
|
|
153
|
+
f5: 116,
|
|
154
|
+
f6: 117,
|
|
155
|
+
f7: 118,
|
|
156
|
+
f8: 119,
|
|
157
|
+
f9: 120,
|
|
158
|
+
f10: 121,
|
|
159
|
+
f11: 122,
|
|
160
|
+
f12: 123,
|
|
161
|
+
numlock: 144,
|
|
162
|
+
scrolllock: 145,
|
|
163
|
+
semicolon: 186,
|
|
164
|
+
equalsign: 187,
|
|
165
|
+
"=": 187,
|
|
166
|
+
comma: 188,
|
|
167
|
+
dash: 189,
|
|
168
|
+
"-": 189,
|
|
169
|
+
period: 190,
|
|
170
|
+
forwardslash: 191,
|
|
171
|
+
graveaccent: 192,
|
|
172
|
+
openbracket: 219,
|
|
173
|
+
backslash: 220,
|
|
174
|
+
closebracket: 221,
|
|
175
|
+
singlequote: 222
|
|
176
|
+
};
|
|
177
|
+
var modifierKey = {
|
|
178
|
+
ctrl: (event) => event.ctrlKey,
|
|
179
|
+
shift: (event) => event.shiftKey,
|
|
180
|
+
alt: (event) => event.altKey,
|
|
181
|
+
meta: (event) => {
|
|
182
|
+
if (event.type === "keyup") {
|
|
183
|
+
return aliasKeyCodeMap.meta.includes(event.keyCode);
|
|
184
|
+
}
|
|
185
|
+
return event.metaKey;
|
|
186
|
+
}
|
|
187
|
+
};
|
|
188
|
+
function countKeyByEvent(event) {
|
|
189
|
+
const countOfModifier = Object.keys(modifierKey).reduce((total, key) => {
|
|
190
|
+
if (modifierKey[key](event)) {
|
|
191
|
+
return total + 1;
|
|
192
|
+
}
|
|
193
|
+
return total;
|
|
194
|
+
}, 0);
|
|
195
|
+
return [16, 17, 18, 91, 92].includes(event.keyCode) ? countOfModifier : countOfModifier + 1;
|
|
196
|
+
}
|
|
197
|
+
function isKeyStringMatch(event, keyString, exactMatch = true) {
|
|
198
|
+
if (!event.key || !keyString) {
|
|
199
|
+
return false;
|
|
200
|
+
}
|
|
201
|
+
const genArr = keyString.split(/\s+/);
|
|
202
|
+
let genLen = 0;
|
|
203
|
+
for (const key of genArr) {
|
|
204
|
+
const genModifier = modifierKey[key];
|
|
205
|
+
const aliasKeyCode = aliasKeyCodeMap[key.toLowerCase()];
|
|
206
|
+
if (genModifier && genModifier(event) || aliasKeyCode && aliasKeyCode === event.keyCode) {
|
|
207
|
+
genLen++;
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
if (exactMatch) {
|
|
211
|
+
return genLen === genArr.length && countKeyByEvent(event) === genArr.length;
|
|
212
|
+
}
|
|
213
|
+
return genLen === genArr.length;
|
|
214
|
+
}
|
|
215
|
+
function isShortcutsMatch(event, shortcuts) {
|
|
216
|
+
return shortcuts.some((keyString) => isKeyStringMatch(event, keyString));
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
// src/layers/shortcuts-layer.ts
|
|
220
|
+
var ShortcutsLayer = class extends Layer {
|
|
221
|
+
onReady() {
|
|
222
|
+
this.shortcuts.addHandlersIfNotFound(
|
|
223
|
+
/**
|
|
224
|
+
* 放大
|
|
225
|
+
*/
|
|
226
|
+
{
|
|
227
|
+
commandId: Command.Default.ZOOM_IN,
|
|
228
|
+
shortcuts: ["meta =", "ctrl ="],
|
|
229
|
+
execute: () => {
|
|
230
|
+
this.config.zoomin();
|
|
231
|
+
}
|
|
232
|
+
},
|
|
233
|
+
/**
|
|
234
|
+
* 缩小
|
|
235
|
+
*/
|
|
236
|
+
{
|
|
237
|
+
commandId: Command.Default.ZOOM_OUT,
|
|
238
|
+
shortcuts: ["meta -", "ctrl -"],
|
|
239
|
+
execute: () => {
|
|
240
|
+
this.config.zoomout();
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
);
|
|
244
|
+
this.toDispose.pushAll([
|
|
245
|
+
// 监听画布鼠标移动事件
|
|
246
|
+
this.listenPlaygroundEvent("keydown", (e) => {
|
|
247
|
+
if (!this.isFocused || e.target !== this.playgroundNode) {
|
|
248
|
+
return;
|
|
249
|
+
}
|
|
250
|
+
this.shortcuts.shortcutsHandlers.some((shortcutsHandler) => {
|
|
251
|
+
if (isShortcutsMatch(e, shortcutsHandler.shortcuts) && (!shortcutsHandler.isEnabled || shortcutsHandler.isEnabled(e))) {
|
|
252
|
+
shortcutsHandler.execute(e);
|
|
253
|
+
e.preventDefault();
|
|
254
|
+
return true;
|
|
255
|
+
}
|
|
256
|
+
});
|
|
257
|
+
})
|
|
258
|
+
]);
|
|
259
|
+
}
|
|
260
|
+
};
|
|
261
|
+
ShortcutsLayer.type = "ShortcutsLayer";
|
|
262
|
+
__decorateClass([
|
|
263
|
+
inject(ShortcutsRegistry)
|
|
264
|
+
], ShortcutsLayer.prototype, "shortcuts", 2);
|
|
265
|
+
__decorateClass([
|
|
266
|
+
inject(SelectionService)
|
|
267
|
+
], ShortcutsLayer.prototype, "selection", 2);
|
|
268
|
+
ShortcutsLayer = __decorateClass([
|
|
269
|
+
injectable()
|
|
270
|
+
], ShortcutsLayer);
|
|
271
|
+
|
|
272
|
+
// src/create-shortcuts-plugin.ts
|
|
273
|
+
var createShortcutsPlugin = definePluginCreator({
|
|
274
|
+
onBind: ({ bind }) => {
|
|
275
|
+
bind(ShortcutsRegistry).toSelf().inSingletonScope();
|
|
276
|
+
bindContributionProvider(bind, ShortcutsContribution);
|
|
277
|
+
},
|
|
278
|
+
onInit: (ctx) => {
|
|
279
|
+
ctx.playground.registerLayer(ShortcutsLayer);
|
|
280
|
+
},
|
|
281
|
+
contributionKeys: [ShortcutsContribution]
|
|
282
|
+
});
|
|
283
|
+
|
|
284
|
+
export { ShortcutsContribution, ShortcutsRegistry, createShortcutsPlugin };
|
|
285
|
+
//# sourceMappingURL=index.js.map
|
|
286
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/shortcuts-contribution.ts","../src/shortcuts-utils.ts","../src/layers/shortcuts-layer.ts","../src/create-shortcuts-plugin.ts"],"names":["Command","inject","injectable"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport { inject, injectable, named, optional, postConstruct } from 'inversify';\nimport { Command, CommandRegistry, ContributionProvider } from '@flowgram-vue/core';\n\nexport interface ShortcutsHandler {\n commandId: string;\n commandDetail?: Omit<Command, 'id'>;\n shortcuts: string[];\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n isEnabled?: (...args: any[]) => boolean;\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n execute: (...args: any[]) => void;\n}\n\nexport const ShortcutsContribution = Symbol('ShortcutsContribution');\n\nexport interface ShortcutsContribution {\n registerShortcuts: (registry: ShortcutsRegistry) => void;\n}\n\n@injectable()\nexport class ShortcutsRegistry {\n @inject(ContributionProvider)\n @named(ShortcutsContribution)\n @optional()\n protected contribs: ContributionProvider<ShortcutsContribution>;\n\n @inject(CommandRegistry) protected commandRegistry: CommandRegistry;\n\n shortcutsHandlers: ShortcutsHandler[] = [];\n\n addHandlers(...handlers: ShortcutsHandler[]): void {\n // 注册 command\n handlers.forEach((handler) => {\n if (!this.commandRegistry.getCommand(handler.commandId)) {\n this.commandRegistry.registerCommand(\n { id: handler.commandId, ...(handler.commandDetail || {}) },\n { execute: handler.execute, isEnabled: handler.isEnabled }\n );\n } else {\n this.commandRegistry.registerHandler(handler.commandId, {\n execute: handler.execute,\n isEnabled: handler.isEnabled,\n });\n }\n });\n // Insert before for override pre handlers\n this.shortcutsHandlers.unshift(...handlers);\n }\n\n addHandlersIfNotFound(...handlers: ShortcutsHandler[]): void {\n handlers.forEach((handler) => {\n if (!this.has(handler.commandId)) {\n this.addHandlers(handler);\n }\n });\n }\n\n removeHandler(commandId: string): void {\n this.shortcutsHandlers = this.shortcutsHandlers.filter(\n (handler) => handler.commandId !== commandId\n );\n }\n\n has(commandId: string): boolean {\n return this.shortcutsHandlers.some((handler) => handler.commandId === commandId);\n }\n\n @postConstruct()\n protected init(): void {\n this.contribs?.forEach((contrib) => contrib.registerShortcuts(this));\n }\n}\n","/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nconst isAppleDevice = /(mac|iphone|ipod|ipad)/i.test(\n typeof navigator !== 'undefined' ? navigator?.platform : '',\n);\n// 键盘事件 keyCode 别名\nconst aliasKeyCodeMap: Record<string, number | number[]> = {\n '0': 48,\n '1': 49,\n '2': 50,\n '3': 51,\n '4': 52,\n '5': 53,\n '6': 54,\n '7': 55,\n '8': 56,\n '9': 57,\n backspace: 8,\n tab: 9,\n enter: 13,\n shift: 16,\n ctrl: 17,\n alt: 18,\n pausebreak: 19,\n capslock: 20,\n esc: 27,\n space: 32,\n pageup: 33,\n pagedown: 34,\n end: 35,\n home: 36,\n leftarrow: 37,\n uparrow: 38,\n rightarrow: 39,\n downarrow: 40,\n insert: 45,\n delete: 46,\n a: 65,\n b: 66,\n c: 67,\n d: 68,\n e: 69,\n f: 70,\n g: 71,\n h: 72,\n i: 73,\n j: 74,\n k: 75,\n l: 76,\n m: 77,\n n: 78,\n o: 79,\n p: 80,\n q: 81,\n r: 82,\n s: 83,\n t: 84,\n u: 85,\n v: 86,\n w: 87,\n x: 88,\n y: 89,\n z: 90,\n leftwindowkey: 91,\n rightwindowkey: 92,\n meta: isAppleDevice ? [91, 93] : [91, 92],\n selectkey: 93,\n numpad0: 96,\n numpad1: 97,\n numpad2: 98,\n numpad3: 99,\n numpad4: 100,\n numpad5: 101,\n numpad6: 102,\n numpad7: 103,\n numpad8: 104,\n numpad9: 105,\n multiply: 106,\n add: 107,\n subtract: 109,\n decimalpoint: 110,\n divide: 111,\n f1: 112,\n f2: 113,\n f3: 114,\n f4: 115,\n f5: 116,\n f6: 117,\n f7: 118,\n f8: 119,\n f9: 120,\n f10: 121,\n f11: 122,\n f12: 123,\n numlock: 144,\n scrolllock: 145,\n semicolon: 186,\n equalsign: 187,\n '=': 187,\n comma: 188,\n dash: 189,\n '-': 189,\n period: 190,\n forwardslash: 191,\n graveaccent: 192,\n openbracket: 219,\n backslash: 220,\n closebracket: 221,\n singlequote: 222,\n};\n\nconst modifierKey: any = {\n ctrl: (event: KeyboardEvent) => event.ctrlKey,\n shift: (event: KeyboardEvent) => event.shiftKey,\n alt: (event: KeyboardEvent) => event.altKey,\n meta: (event: KeyboardEvent) => {\n if (event.type === 'keyup') {\n return (aliasKeyCodeMap.meta as number[]).includes(event.keyCode);\n }\n return event.metaKey;\n },\n};\n\n// 根据 event 计算激活键数量\nfunction countKeyByEvent(event: KeyboardEvent): number {\n const countOfModifier = Object.keys(modifierKey).reduce((total, key) => {\n if (modifierKey[key](event)) {\n return total + 1;\n }\n\n return total;\n }, 0);\n\n // 16 17 18 91 92 是修饰键的 keyCode,如果 keyCode 是修饰键,那么激活数量就是修饰键的数量,如果不是,那么就需要 +1\n return [16, 17, 18, 91, 92].includes(event.keyCode) ? countOfModifier : countOfModifier + 1;\n}\n\n/**\n *\n * @param event\n * @param keyString 'ctrl.s' 'meta.s'\n * @param exactMatch\n */\nfunction isKeyStringMatch(event: KeyboardEvent, keyString: string, exactMatch = true): boolean {\n // 浏览器自动补全 input 的时候,会触发 keyDown、keyUp 事件,但此时 event.key 等为空\n if (!event.key || !keyString) {\n return false;\n }\n // 字符串依次判断是否有组合键\n const genArr = keyString.split(/\\s+/);\n let genLen = 0;\n\n for (const key of genArr) {\n // 组合键\n const genModifier = modifierKey[key];\n // keyCode 别名\n const aliasKeyCode: number | number[] = aliasKeyCodeMap[key.toLowerCase()];\n\n if ((genModifier && genModifier(event)) || (aliasKeyCode && aliasKeyCode === event.keyCode)) {\n genLen++;\n }\n }\n\n /**\n * 需要判断触发的键位和监听的键位完全一致,判断方法就是触发的键位里有且等于监听的键位\n * genLen === genArr.length 能判断出来触发的键位里有监听的键位\n * countKeyByEvent(event) === genArr.length 判断出来触发的键位数量里有且等于监听的键位数量\n * 主要用来防止按组合键其子集也会触发的情况,例如监听 ctrl+a 会触发监听 ctrl 和 a 两个键的事件。\n */\n if (exactMatch) {\n return genLen === genArr.length && countKeyByEvent(event) === genArr.length;\n }\n return genLen === genArr.length;\n}\n\n/**\n * 匹配指定的快捷键\n * @param event\n * @param shortcuts\n */\nexport function isShortcutsMatch(event: KeyboardEvent, shortcuts: string[]): boolean {\n return shortcuts.some(keyString => isKeyStringMatch(event, keyString));\n}\n","/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport { inject, injectable } from 'inversify';\nimport { Layer, SelectionService, Command } from '@flowgram-vue/core';\n\nimport { isShortcutsMatch } from '../shortcuts-utils';\nimport { ShortcutsRegistry } from '../shortcuts-contribution';\n\n@injectable()\nexport class ShortcutsLayer extends Layer<object> {\n static type = 'ShortcutsLayer';\n\n @inject(ShortcutsRegistry) shortcuts: ShortcutsRegistry;\n\n @inject(SelectionService) selection: SelectionService;\n\n onReady(): void {\n this.shortcuts.addHandlersIfNotFound(\n /**\n * 放大\n */\n {\n commandId: Command.Default.ZOOM_IN,\n shortcuts: ['meta =', 'ctrl ='],\n execute: () => {\n // TODO 这里要判断 CurrentEditor\n this.config.zoomin();\n },\n },\n /**\n * 缩小\n */\n {\n commandId: Command.Default.ZOOM_OUT,\n shortcuts: ['meta -', 'ctrl -'],\n execute: () => {\n // TODO 这里要判断 CurrentEditor\n this.config.zoomout();\n },\n },\n );\n this.toDispose.pushAll([\n // 监听画布鼠标移动事件\n this.listenPlaygroundEvent('keydown', (e: KeyboardEvent) => {\n if (!this.isFocused || e.target !== this.playgroundNode) {\n return;\n }\n this.shortcuts.shortcutsHandlers.some(shortcutsHandler => {\n if (\n isShortcutsMatch(e, shortcutsHandler.shortcuts) &&\n (!shortcutsHandler.isEnabled || shortcutsHandler.isEnabled(e))\n ) {\n shortcutsHandler.execute(e);\n e.preventDefault();\n return true;\n }\n });\n }),\n ]);\n }\n}\n","/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport { bindContributionProvider, definePluginCreator } from '@flowgram-vue/core';\n\nimport { ShortcutsRegistry, ShortcutsContribution } from './shortcuts-contribution';\nimport { ShortcutsLayer } from './layers';\n\n/**\n * @param opts\n *\n * createShortcutsPlugin({\n * registerShortcuts(registry) {\n * }\n * })\n */\nexport const createShortcutsPlugin = definePluginCreator<ShortcutsContribution>({\n onBind: ({ bind }) => {\n bind(ShortcutsRegistry).toSelf().inSingletonScope();\n bindContributionProvider(bind, ShortcutsContribution);\n },\n onInit: (ctx) => {\n ctx.playground.registerLayer(ShortcutsLayer);\n },\n contributionKeys: [ShortcutsContribution],\n});\n"]}
|
package/package.json
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@flowgram-vue/shortcuts-plugin",
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"homepage": "https://flowgram.ai/",
|
|
7
|
+
"repository": "https://github.com/Crayon-hua/flowgram-vue",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"import": "./dist/index.js",
|
|
12
|
+
"require": "./dist/index.cjs"
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
"main": "./dist/index.cjs",
|
|
16
|
+
"module": "./dist/index.js",
|
|
17
|
+
"types": "./dist/index.d.ts",
|
|
18
|
+
"files": [
|
|
19
|
+
"src",
|
|
20
|
+
"dist"
|
|
21
|
+
],
|
|
22
|
+
"dependencies": {
|
|
23
|
+
"inversify": "^6.0.1",
|
|
24
|
+
"reflect-metadata": "~0.2.2",
|
|
25
|
+
"@flowgram-vue/core": "0.2.0"
|
|
26
|
+
},
|
|
27
|
+
"peerDependencies": {
|
|
28
|
+
"vue": "^3.3.0"
|
|
29
|
+
},
|
|
30
|
+
"devDependencies": {
|
|
31
|
+
"@types/node": "^20",
|
|
32
|
+
"eslint": "^9.0.0",
|
|
33
|
+
"typescript": "^5.8.3",
|
|
34
|
+
"vitest": "^3.2.4",
|
|
35
|
+
"vue": "^3.5.18",
|
|
36
|
+
"@flowgram-vue/ts-config": "0.2.0",
|
|
37
|
+
"@flowgram-vue/eslint-config": "0.2.0",
|
|
38
|
+
"@flowgram-vue/build-config": "0.2.0"
|
|
39
|
+
},
|
|
40
|
+
"publishConfig": {
|
|
41
|
+
"access": "public",
|
|
42
|
+
"registry": "https://registry.npmjs.org/"
|
|
43
|
+
},
|
|
44
|
+
"scripts": {
|
|
45
|
+
"build": "flowgram-build",
|
|
46
|
+
"test": "exit 0",
|
|
47
|
+
"test:cov": "exit 0",
|
|
48
|
+
"lint": "eslint .",
|
|
49
|
+
"ts-check": "tsc --noEmit",
|
|
50
|
+
"build:fast": "flowgram-build --fast",
|
|
51
|
+
"build:watch": "flowgram-build --watch"
|
|
52
|
+
}
|
|
53
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
|
|
3
|
+
* SPDX-License-Identifier: MIT
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { bindContributionProvider, definePluginCreator } from '@flowgram-vue/core';
|
|
7
|
+
|
|
8
|
+
import { ShortcutsRegistry, ShortcutsContribution } from './shortcuts-contribution';
|
|
9
|
+
import { ShortcutsLayer } from './layers';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* @param opts
|
|
13
|
+
*
|
|
14
|
+
* createShortcutsPlugin({
|
|
15
|
+
* registerShortcuts(registry) {
|
|
16
|
+
* }
|
|
17
|
+
* })
|
|
18
|
+
*/
|
|
19
|
+
export const createShortcutsPlugin = definePluginCreator<ShortcutsContribution>({
|
|
20
|
+
onBind: ({ bind }) => {
|
|
21
|
+
bind(ShortcutsRegistry).toSelf().inSingletonScope();
|
|
22
|
+
bindContributionProvider(bind, ShortcutsContribution);
|
|
23
|
+
},
|
|
24
|
+
onInit: (ctx) => {
|
|
25
|
+
ctx.playground.registerLayer(ShortcutsLayer);
|
|
26
|
+
},
|
|
27
|
+
contributionKeys: [ShortcutsContribution],
|
|
28
|
+
});
|
package/src/env.d.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
|
|
3
|
+
* SPDX-License-Identifier: MIT
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
declare module '*.vue' {
|
|
7
|
+
import type { DefineComponent } from 'vue';
|
|
8
|
+
const component: DefineComponent<object, object, unknown>;
|
|
9
|
+
export default component;
|
|
10
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
|
|
3
|
+
* SPDX-License-Identifier: MIT
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { inject, injectable } from 'inversify';
|
|
7
|
+
import { Layer, SelectionService, Command } from '@flowgram-vue/core';
|
|
8
|
+
|
|
9
|
+
import { isShortcutsMatch } from '../shortcuts-utils';
|
|
10
|
+
import { ShortcutsRegistry } from '../shortcuts-contribution';
|
|
11
|
+
|
|
12
|
+
@injectable()
|
|
13
|
+
export class ShortcutsLayer extends Layer<object> {
|
|
14
|
+
static type = 'ShortcutsLayer';
|
|
15
|
+
|
|
16
|
+
@inject(ShortcutsRegistry) shortcuts: ShortcutsRegistry;
|
|
17
|
+
|
|
18
|
+
@inject(SelectionService) selection: SelectionService;
|
|
19
|
+
|
|
20
|
+
onReady(): void {
|
|
21
|
+
this.shortcuts.addHandlersIfNotFound(
|
|
22
|
+
/**
|
|
23
|
+
* 放大
|
|
24
|
+
*/
|
|
25
|
+
{
|
|
26
|
+
commandId: Command.Default.ZOOM_IN,
|
|
27
|
+
shortcuts: ['meta =', 'ctrl ='],
|
|
28
|
+
execute: () => {
|
|
29
|
+
// TODO 这里要判断 CurrentEditor
|
|
30
|
+
this.config.zoomin();
|
|
31
|
+
},
|
|
32
|
+
},
|
|
33
|
+
/**
|
|
34
|
+
* 缩小
|
|
35
|
+
*/
|
|
36
|
+
{
|
|
37
|
+
commandId: Command.Default.ZOOM_OUT,
|
|
38
|
+
shortcuts: ['meta -', 'ctrl -'],
|
|
39
|
+
execute: () => {
|
|
40
|
+
// TODO 这里要判断 CurrentEditor
|
|
41
|
+
this.config.zoomout();
|
|
42
|
+
},
|
|
43
|
+
},
|
|
44
|
+
);
|
|
45
|
+
this.toDispose.pushAll([
|
|
46
|
+
// 监听画布鼠标移动事件
|
|
47
|
+
this.listenPlaygroundEvent('keydown', (e: KeyboardEvent) => {
|
|
48
|
+
if (!this.isFocused || e.target !== this.playgroundNode) {
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
this.shortcuts.shortcutsHandlers.some(shortcutsHandler => {
|
|
52
|
+
if (
|
|
53
|
+
isShortcutsMatch(e, shortcutsHandler.shortcuts) &&
|
|
54
|
+
(!shortcutsHandler.isEnabled || shortcutsHandler.isEnabled(e))
|
|
55
|
+
) {
|
|
56
|
+
shortcutsHandler.execute(e);
|
|
57
|
+
e.preventDefault();
|
|
58
|
+
return true;
|
|
59
|
+
}
|
|
60
|
+
});
|
|
61
|
+
}),
|
|
62
|
+
]);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
|
|
3
|
+
* SPDX-License-Identifier: MIT
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { inject, injectable, named, optional, postConstruct } from 'inversify';
|
|
7
|
+
import { Command, CommandRegistry, ContributionProvider } from '@flowgram-vue/core';
|
|
8
|
+
|
|
9
|
+
export interface ShortcutsHandler {
|
|
10
|
+
commandId: string;
|
|
11
|
+
commandDetail?: Omit<Command, 'id'>;
|
|
12
|
+
shortcuts: string[];
|
|
13
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
14
|
+
isEnabled?: (...args: any[]) => boolean;
|
|
15
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
16
|
+
execute: (...args: any[]) => void;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export const ShortcutsContribution = Symbol('ShortcutsContribution');
|
|
20
|
+
|
|
21
|
+
export interface ShortcutsContribution {
|
|
22
|
+
registerShortcuts: (registry: ShortcutsRegistry) => void;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
@injectable()
|
|
26
|
+
export class ShortcutsRegistry {
|
|
27
|
+
@inject(ContributionProvider)
|
|
28
|
+
@named(ShortcutsContribution)
|
|
29
|
+
@optional()
|
|
30
|
+
protected contribs: ContributionProvider<ShortcutsContribution>;
|
|
31
|
+
|
|
32
|
+
@inject(CommandRegistry) protected commandRegistry: CommandRegistry;
|
|
33
|
+
|
|
34
|
+
shortcutsHandlers: ShortcutsHandler[] = [];
|
|
35
|
+
|
|
36
|
+
addHandlers(...handlers: ShortcutsHandler[]): void {
|
|
37
|
+
// 注册 command
|
|
38
|
+
handlers.forEach((handler) => {
|
|
39
|
+
if (!this.commandRegistry.getCommand(handler.commandId)) {
|
|
40
|
+
this.commandRegistry.registerCommand(
|
|
41
|
+
{ id: handler.commandId, ...(handler.commandDetail || {}) },
|
|
42
|
+
{ execute: handler.execute, isEnabled: handler.isEnabled }
|
|
43
|
+
);
|
|
44
|
+
} else {
|
|
45
|
+
this.commandRegistry.registerHandler(handler.commandId, {
|
|
46
|
+
execute: handler.execute,
|
|
47
|
+
isEnabled: handler.isEnabled,
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
});
|
|
51
|
+
// Insert before for override pre handlers
|
|
52
|
+
this.shortcutsHandlers.unshift(...handlers);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
addHandlersIfNotFound(...handlers: ShortcutsHandler[]): void {
|
|
56
|
+
handlers.forEach((handler) => {
|
|
57
|
+
if (!this.has(handler.commandId)) {
|
|
58
|
+
this.addHandlers(handler);
|
|
59
|
+
}
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
removeHandler(commandId: string): void {
|
|
64
|
+
this.shortcutsHandlers = this.shortcutsHandlers.filter(
|
|
65
|
+
(handler) => handler.commandId !== commandId
|
|
66
|
+
);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
has(commandId: string): boolean {
|
|
70
|
+
return this.shortcutsHandlers.some((handler) => handler.commandId === commandId);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
@postConstruct()
|
|
74
|
+
protected init(): void {
|
|
75
|
+
this.contribs?.forEach((contrib) => contrib.registerShortcuts(this));
|
|
76
|
+
}
|
|
77
|
+
}
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
|
|
3
|
+
* SPDX-License-Identifier: MIT
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
const isAppleDevice = /(mac|iphone|ipod|ipad)/i.test(
|
|
7
|
+
typeof navigator !== 'undefined' ? navigator?.platform : '',
|
|
8
|
+
);
|
|
9
|
+
// 键盘事件 keyCode 别名
|
|
10
|
+
const aliasKeyCodeMap: Record<string, number | number[]> = {
|
|
11
|
+
'0': 48,
|
|
12
|
+
'1': 49,
|
|
13
|
+
'2': 50,
|
|
14
|
+
'3': 51,
|
|
15
|
+
'4': 52,
|
|
16
|
+
'5': 53,
|
|
17
|
+
'6': 54,
|
|
18
|
+
'7': 55,
|
|
19
|
+
'8': 56,
|
|
20
|
+
'9': 57,
|
|
21
|
+
backspace: 8,
|
|
22
|
+
tab: 9,
|
|
23
|
+
enter: 13,
|
|
24
|
+
shift: 16,
|
|
25
|
+
ctrl: 17,
|
|
26
|
+
alt: 18,
|
|
27
|
+
pausebreak: 19,
|
|
28
|
+
capslock: 20,
|
|
29
|
+
esc: 27,
|
|
30
|
+
space: 32,
|
|
31
|
+
pageup: 33,
|
|
32
|
+
pagedown: 34,
|
|
33
|
+
end: 35,
|
|
34
|
+
home: 36,
|
|
35
|
+
leftarrow: 37,
|
|
36
|
+
uparrow: 38,
|
|
37
|
+
rightarrow: 39,
|
|
38
|
+
downarrow: 40,
|
|
39
|
+
insert: 45,
|
|
40
|
+
delete: 46,
|
|
41
|
+
a: 65,
|
|
42
|
+
b: 66,
|
|
43
|
+
c: 67,
|
|
44
|
+
d: 68,
|
|
45
|
+
e: 69,
|
|
46
|
+
f: 70,
|
|
47
|
+
g: 71,
|
|
48
|
+
h: 72,
|
|
49
|
+
i: 73,
|
|
50
|
+
j: 74,
|
|
51
|
+
k: 75,
|
|
52
|
+
l: 76,
|
|
53
|
+
m: 77,
|
|
54
|
+
n: 78,
|
|
55
|
+
o: 79,
|
|
56
|
+
p: 80,
|
|
57
|
+
q: 81,
|
|
58
|
+
r: 82,
|
|
59
|
+
s: 83,
|
|
60
|
+
t: 84,
|
|
61
|
+
u: 85,
|
|
62
|
+
v: 86,
|
|
63
|
+
w: 87,
|
|
64
|
+
x: 88,
|
|
65
|
+
y: 89,
|
|
66
|
+
z: 90,
|
|
67
|
+
leftwindowkey: 91,
|
|
68
|
+
rightwindowkey: 92,
|
|
69
|
+
meta: isAppleDevice ? [91, 93] : [91, 92],
|
|
70
|
+
selectkey: 93,
|
|
71
|
+
numpad0: 96,
|
|
72
|
+
numpad1: 97,
|
|
73
|
+
numpad2: 98,
|
|
74
|
+
numpad3: 99,
|
|
75
|
+
numpad4: 100,
|
|
76
|
+
numpad5: 101,
|
|
77
|
+
numpad6: 102,
|
|
78
|
+
numpad7: 103,
|
|
79
|
+
numpad8: 104,
|
|
80
|
+
numpad9: 105,
|
|
81
|
+
multiply: 106,
|
|
82
|
+
add: 107,
|
|
83
|
+
subtract: 109,
|
|
84
|
+
decimalpoint: 110,
|
|
85
|
+
divide: 111,
|
|
86
|
+
f1: 112,
|
|
87
|
+
f2: 113,
|
|
88
|
+
f3: 114,
|
|
89
|
+
f4: 115,
|
|
90
|
+
f5: 116,
|
|
91
|
+
f6: 117,
|
|
92
|
+
f7: 118,
|
|
93
|
+
f8: 119,
|
|
94
|
+
f9: 120,
|
|
95
|
+
f10: 121,
|
|
96
|
+
f11: 122,
|
|
97
|
+
f12: 123,
|
|
98
|
+
numlock: 144,
|
|
99
|
+
scrolllock: 145,
|
|
100
|
+
semicolon: 186,
|
|
101
|
+
equalsign: 187,
|
|
102
|
+
'=': 187,
|
|
103
|
+
comma: 188,
|
|
104
|
+
dash: 189,
|
|
105
|
+
'-': 189,
|
|
106
|
+
period: 190,
|
|
107
|
+
forwardslash: 191,
|
|
108
|
+
graveaccent: 192,
|
|
109
|
+
openbracket: 219,
|
|
110
|
+
backslash: 220,
|
|
111
|
+
closebracket: 221,
|
|
112
|
+
singlequote: 222,
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
const modifierKey: any = {
|
|
116
|
+
ctrl: (event: KeyboardEvent) => event.ctrlKey,
|
|
117
|
+
shift: (event: KeyboardEvent) => event.shiftKey,
|
|
118
|
+
alt: (event: KeyboardEvent) => event.altKey,
|
|
119
|
+
meta: (event: KeyboardEvent) => {
|
|
120
|
+
if (event.type === 'keyup') {
|
|
121
|
+
return (aliasKeyCodeMap.meta as number[]).includes(event.keyCode);
|
|
122
|
+
}
|
|
123
|
+
return event.metaKey;
|
|
124
|
+
},
|
|
125
|
+
};
|
|
126
|
+
|
|
127
|
+
// 根据 event 计算激活键数量
|
|
128
|
+
function countKeyByEvent(event: KeyboardEvent): number {
|
|
129
|
+
const countOfModifier = Object.keys(modifierKey).reduce((total, key) => {
|
|
130
|
+
if (modifierKey[key](event)) {
|
|
131
|
+
return total + 1;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
return total;
|
|
135
|
+
}, 0);
|
|
136
|
+
|
|
137
|
+
// 16 17 18 91 92 是修饰键的 keyCode,如果 keyCode 是修饰键,那么激活数量就是修饰键的数量,如果不是,那么就需要 +1
|
|
138
|
+
return [16, 17, 18, 91, 92].includes(event.keyCode) ? countOfModifier : countOfModifier + 1;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
*
|
|
143
|
+
* @param event
|
|
144
|
+
* @param keyString 'ctrl.s' 'meta.s'
|
|
145
|
+
* @param exactMatch
|
|
146
|
+
*/
|
|
147
|
+
function isKeyStringMatch(event: KeyboardEvent, keyString: string, exactMatch = true): boolean {
|
|
148
|
+
// 浏览器自动补全 input 的时候,会触发 keyDown、keyUp 事件,但此时 event.key 等为空
|
|
149
|
+
if (!event.key || !keyString) {
|
|
150
|
+
return false;
|
|
151
|
+
}
|
|
152
|
+
// 字符串依次判断是否有组合键
|
|
153
|
+
const genArr = keyString.split(/\s+/);
|
|
154
|
+
let genLen = 0;
|
|
155
|
+
|
|
156
|
+
for (const key of genArr) {
|
|
157
|
+
// 组合键
|
|
158
|
+
const genModifier = modifierKey[key];
|
|
159
|
+
// keyCode 别名
|
|
160
|
+
const aliasKeyCode: number | number[] = aliasKeyCodeMap[key.toLowerCase()];
|
|
161
|
+
|
|
162
|
+
if ((genModifier && genModifier(event)) || (aliasKeyCode && aliasKeyCode === event.keyCode)) {
|
|
163
|
+
genLen++;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* 需要判断触发的键位和监听的键位完全一致,判断方法就是触发的键位里有且等于监听的键位
|
|
169
|
+
* genLen === genArr.length 能判断出来触发的键位里有监听的键位
|
|
170
|
+
* countKeyByEvent(event) === genArr.length 判断出来触发的键位数量里有且等于监听的键位数量
|
|
171
|
+
* 主要用来防止按组合键其子集也会触发的情况,例如监听 ctrl+a 会触发监听 ctrl 和 a 两个键的事件。
|
|
172
|
+
*/
|
|
173
|
+
if (exactMatch) {
|
|
174
|
+
return genLen === genArr.length && countKeyByEvent(event) === genArr.length;
|
|
175
|
+
}
|
|
176
|
+
return genLen === genArr.length;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* 匹配指定的快捷键
|
|
181
|
+
* @param event
|
|
182
|
+
* @param shortcuts
|
|
183
|
+
*/
|
|
184
|
+
export function isShortcutsMatch(event: KeyboardEvent, shortcuts: string[]): boolean {
|
|
185
|
+
return shortcuts.some(keyString => isKeyStringMatch(event, keyString));
|
|
186
|
+
}
|