@flowgram.ai/shortcuts-plugin 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,291 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
3
+ var __decorateClass = (decorators, target, key, kind) => {
4
+ var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc(target, key) : target;
5
+ for (var i = decorators.length - 1, decorator; i >= 0; i--)
6
+ if (decorator = decorators[i])
7
+ result = (kind ? decorator(target, key, result) : decorator(result)) || result;
8
+ if (kind && result) __defProp(target, key, result);
9
+ return result;
10
+ };
11
+
12
+ // src/create-shortcuts-plugin.ts
13
+ import { bindContributionProvider, definePluginCreator } from "@flowgram.ai/core";
14
+
15
+ // src/shortcuts-contribution.ts
16
+ import { inject, injectable, named, optional, postConstruct } from "inversify";
17
+ import { CommandRegistry, ContributionProvider } from "@flowgram.ai/core";
18
+ var ShortcutsContribution = Symbol("ShortcutsContribution");
19
+ var ShortcutsRegistry = class {
20
+ constructor() {
21
+ this.shortcutsHandlers = [];
22
+ }
23
+ addHandlers(...handlers) {
24
+ handlers.forEach((handler) => {
25
+ if (!this.commandRegistry.getCommand(handler.commandId)) {
26
+ this.commandRegistry.registerCommand(
27
+ { id: handler.commandId, ...handler.commandDetail || {} },
28
+ { execute: handler.execute, isEnabled: handler.isEnabled }
29
+ );
30
+ } else {
31
+ this.commandRegistry.registerHandler(handler.commandId, {
32
+ execute: handler.execute,
33
+ isEnabled: handler.isEnabled
34
+ });
35
+ }
36
+ });
37
+ this.shortcutsHandlers.push(...handlers);
38
+ }
39
+ addHandlersIfNotFound(...handlers) {
40
+ handlers.forEach((handler) => {
41
+ if (!this.has(handler.commandId)) {
42
+ this.addHandlers(handler);
43
+ }
44
+ });
45
+ }
46
+ has(commandId) {
47
+ return this.shortcutsHandlers.some((handler) => handler.commandId === commandId);
48
+ }
49
+ init() {
50
+ this.contribs?.forEach((contrib) => contrib.registerShortcuts(this));
51
+ }
52
+ };
53
+ __decorateClass([
54
+ inject(ContributionProvider),
55
+ named(ShortcutsContribution),
56
+ optional()
57
+ ], ShortcutsRegistry.prototype, "contribs", 2);
58
+ __decorateClass([
59
+ inject(CommandRegistry)
60
+ ], ShortcutsRegistry.prototype, "commandRegistry", 2);
61
+ __decorateClass([
62
+ postConstruct()
63
+ ], ShortcutsRegistry.prototype, "init", 1);
64
+ ShortcutsRegistry = __decorateClass([
65
+ injectable()
66
+ ], ShortcutsRegistry);
67
+
68
+ // src/layers/shortcuts-layer.tsx
69
+ import { inject as inject2, injectable as injectable2 } from "inversify";
70
+ import { Layer, SelectionService, Command as Command2 } from "@flowgram.ai/core";
71
+
72
+ // src/shortcuts-utils.ts
73
+ var isAppleDevice = /(mac|iphone|ipod|ipad)/i.test(
74
+ typeof navigator !== "undefined" ? navigator?.platform : ""
75
+ );
76
+ var aliasKeyCodeMap = {
77
+ "0": 48,
78
+ "1": 49,
79
+ "2": 50,
80
+ "3": 51,
81
+ "4": 52,
82
+ "5": 53,
83
+ "6": 54,
84
+ "7": 55,
85
+ "8": 56,
86
+ "9": 57,
87
+ backspace: 8,
88
+ tab: 9,
89
+ enter: 13,
90
+ shift: 16,
91
+ ctrl: 17,
92
+ alt: 18,
93
+ pausebreak: 19,
94
+ capslock: 20,
95
+ esc: 27,
96
+ space: 32,
97
+ pageup: 33,
98
+ pagedown: 34,
99
+ end: 35,
100
+ home: 36,
101
+ leftarrow: 37,
102
+ uparrow: 38,
103
+ rightarrow: 39,
104
+ downarrow: 40,
105
+ insert: 45,
106
+ delete: 46,
107
+ a: 65,
108
+ b: 66,
109
+ c: 67,
110
+ d: 68,
111
+ e: 69,
112
+ f: 70,
113
+ g: 71,
114
+ h: 72,
115
+ i: 73,
116
+ j: 74,
117
+ k: 75,
118
+ l: 76,
119
+ m: 77,
120
+ n: 78,
121
+ o: 79,
122
+ p: 80,
123
+ q: 81,
124
+ r: 82,
125
+ s: 83,
126
+ t: 84,
127
+ u: 85,
128
+ v: 86,
129
+ w: 87,
130
+ x: 88,
131
+ y: 89,
132
+ z: 90,
133
+ leftwindowkey: 91,
134
+ rightwindowkey: 92,
135
+ meta: isAppleDevice ? [91, 93] : [91, 92],
136
+ selectkey: 93,
137
+ numpad0: 96,
138
+ numpad1: 97,
139
+ numpad2: 98,
140
+ numpad3: 99,
141
+ numpad4: 100,
142
+ numpad5: 101,
143
+ numpad6: 102,
144
+ numpad7: 103,
145
+ numpad8: 104,
146
+ numpad9: 105,
147
+ multiply: 106,
148
+ add: 107,
149
+ subtract: 109,
150
+ decimalpoint: 110,
151
+ divide: 111,
152
+ f1: 112,
153
+ f2: 113,
154
+ f3: 114,
155
+ f4: 115,
156
+ f5: 116,
157
+ f6: 117,
158
+ f7: 118,
159
+ f8: 119,
160
+ f9: 120,
161
+ f10: 121,
162
+ f11: 122,
163
+ f12: 123,
164
+ numlock: 144,
165
+ scrolllock: 145,
166
+ semicolon: 186,
167
+ equalsign: 187,
168
+ "=": 187,
169
+ comma: 188,
170
+ dash: 189,
171
+ "-": 189,
172
+ period: 190,
173
+ forwardslash: 191,
174
+ graveaccent: 192,
175
+ openbracket: 219,
176
+ backslash: 220,
177
+ closebracket: 221,
178
+ singlequote: 222
179
+ };
180
+ var modifierKey = {
181
+ ctrl: (event) => event.ctrlKey,
182
+ shift: (event) => event.shiftKey,
183
+ alt: (event) => event.altKey,
184
+ meta: (event) => {
185
+ if (event.type === "keyup") {
186
+ return aliasKeyCodeMap.meta.includes(event.keyCode);
187
+ }
188
+ return event.metaKey;
189
+ }
190
+ };
191
+ function countKeyByEvent(event) {
192
+ const countOfModifier = Object.keys(modifierKey).reduce((total, key) => {
193
+ if (modifierKey[key](event)) {
194
+ return total + 1;
195
+ }
196
+ return total;
197
+ }, 0);
198
+ return [16, 17, 18, 91, 92].includes(event.keyCode) ? countOfModifier : countOfModifier + 1;
199
+ }
200
+ function isKeyStringMatch(event, keyString, exactMatch = true) {
201
+ if (!event.key || !keyString) {
202
+ return false;
203
+ }
204
+ const genArr = keyString.split(/\s+/);
205
+ let genLen = 0;
206
+ for (const key of genArr) {
207
+ const genModifier = modifierKey[key];
208
+ const aliasKeyCode = aliasKeyCodeMap[key.toLowerCase()];
209
+ if (genModifier && genModifier(event) || aliasKeyCode && aliasKeyCode === event.keyCode) {
210
+ genLen++;
211
+ }
212
+ }
213
+ if (exactMatch) {
214
+ return genLen === genArr.length && countKeyByEvent(event) === genArr.length;
215
+ }
216
+ return genLen === genArr.length;
217
+ }
218
+ function isShortcutsMatch(event, shortcuts) {
219
+ return shortcuts.some((keyString) => isKeyStringMatch(event, keyString));
220
+ }
221
+
222
+ // src/layers/shortcuts-layer.tsx
223
+ var ShortcutsLayer = class extends Layer {
224
+ onReady() {
225
+ this.shortcuts.addHandlersIfNotFound(
226
+ /**
227
+ * 放大
228
+ */
229
+ {
230
+ commandId: Command2.Default.ZOOM_IN,
231
+ shortcuts: ["meta =", "ctrl ="],
232
+ execute: () => {
233
+ this.config.zoomin();
234
+ }
235
+ },
236
+ /**
237
+ * 缩小
238
+ */
239
+ {
240
+ commandId: Command2.Default.ZOOM_OUT,
241
+ shortcuts: ["meta -", "ctrl -"],
242
+ execute: () => {
243
+ this.config.zoomout();
244
+ }
245
+ }
246
+ );
247
+ this.toDispose.pushAll([
248
+ // 监听画布鼠标移动事件
249
+ this.listenPlaygroundEvent("keydown", (e) => {
250
+ if (!this.isFocused || e.target !== this.playgroundNode) {
251
+ return;
252
+ }
253
+ this.shortcuts.shortcutsHandlers.some((shortcutsHandler) => {
254
+ if (isShortcutsMatch(e, shortcutsHandler.shortcuts) && (!shortcutsHandler.isEnabled || shortcutsHandler.isEnabled(e))) {
255
+ shortcutsHandler.execute(e);
256
+ e.preventDefault();
257
+ return true;
258
+ }
259
+ });
260
+ })
261
+ ]);
262
+ }
263
+ };
264
+ ShortcutsLayer.type = "ShortcutsLayer";
265
+ __decorateClass([
266
+ inject2(ShortcutsRegistry)
267
+ ], ShortcutsLayer.prototype, "shortcuts", 2);
268
+ __decorateClass([
269
+ inject2(SelectionService)
270
+ ], ShortcutsLayer.prototype, "selection", 2);
271
+ ShortcutsLayer = __decorateClass([
272
+ injectable2()
273
+ ], ShortcutsLayer);
274
+
275
+ // src/create-shortcuts-plugin.ts
276
+ var createShortcutsPlugin = definePluginCreator({
277
+ onBind: ({ bind }) => {
278
+ bind(ShortcutsRegistry).toSelf().inSingletonScope();
279
+ bindContributionProvider(bind, ShortcutsContribution);
280
+ },
281
+ onInit: (ctx) => {
282
+ ctx.playground.registerLayer(ShortcutsLayer);
283
+ },
284
+ contributionKeys: [ShortcutsContribution]
285
+ });
286
+ export {
287
+ ShortcutsContribution,
288
+ ShortcutsRegistry,
289
+ createShortcutsPlugin
290
+ };
291
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/create-shortcuts-plugin.ts","../../src/shortcuts-contribution.ts","../../src/layers/shortcuts-layer.tsx","../../src/shortcuts-utils.ts"],"sourcesContent":["import { bindContributionProvider, definePluginCreator } from '@flowgram.ai/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","import { inject, injectable, named, optional, postConstruct } from 'inversify';\nimport { Command, CommandRegistry, ContributionProvider } from '@flowgram.ai/core';\n\ninterface 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 readonly 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 this.shortcutsHandlers.push(...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 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","import { inject, injectable } from 'inversify';\nimport { Layer, SelectionService, Command } from '@flowgram.ai/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","const 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"],"mappings":"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","names":["inject","injectable","Command","Command","inject","injectable"]}
@@ -0,0 +1,35 @@
1
+ import * as _flowgram_ai_core from '@flowgram.ai/core';
2
+ import { ContributionProvider, CommandRegistry, Command } from '@flowgram.ai/core';
3
+
4
+ interface ShortcutsHandler {
5
+ commandId: string;
6
+ commandDetail?: Omit<Command, 'id'>;
7
+ shortcuts: string[];
8
+ isEnabled?: (...args: any[]) => boolean;
9
+ execute: (...args: any[]) => void;
10
+ }
11
+ declare const ShortcutsContribution: unique symbol;
12
+ interface ShortcutsContribution {
13
+ registerShortcuts: (registry: ShortcutsRegistry) => void;
14
+ }
15
+ declare class ShortcutsRegistry {
16
+ protected contribs: ContributionProvider<ShortcutsContribution>;
17
+ protected commandRegistry: CommandRegistry;
18
+ readonly shortcutsHandlers: ShortcutsHandler[];
19
+ addHandlers(...handlers: ShortcutsHandler[]): void;
20
+ addHandlersIfNotFound(...handlers: ShortcutsHandler[]): void;
21
+ has(commandId: string): boolean;
22
+ protected init(): void;
23
+ }
24
+
25
+ /**
26
+ * @param opts
27
+ *
28
+ * createShortcutsPlugin({
29
+ * registerShortcuts(registry) {
30
+ * }
31
+ * })
32
+ */
33
+ declare const createShortcutsPlugin: _flowgram_ai_core.PluginCreator<ShortcutsContribution>;
34
+
35
+ export { ShortcutsContribution, ShortcutsRegistry, createShortcutsPlugin };
@@ -0,0 +1,35 @@
1
+ import * as _flowgram_ai_core from '@flowgram.ai/core';
2
+ import { ContributionProvider, CommandRegistry, Command } from '@flowgram.ai/core';
3
+
4
+ interface ShortcutsHandler {
5
+ commandId: string;
6
+ commandDetail?: Omit<Command, 'id'>;
7
+ shortcuts: string[];
8
+ isEnabled?: (...args: any[]) => boolean;
9
+ execute: (...args: any[]) => void;
10
+ }
11
+ declare const ShortcutsContribution: unique symbol;
12
+ interface ShortcutsContribution {
13
+ registerShortcuts: (registry: ShortcutsRegistry) => void;
14
+ }
15
+ declare class ShortcutsRegistry {
16
+ protected contribs: ContributionProvider<ShortcutsContribution>;
17
+ protected commandRegistry: CommandRegistry;
18
+ readonly shortcutsHandlers: ShortcutsHandler[];
19
+ addHandlers(...handlers: ShortcutsHandler[]): void;
20
+ addHandlersIfNotFound(...handlers: ShortcutsHandler[]): void;
21
+ has(commandId: string): boolean;
22
+ protected init(): void;
23
+ }
24
+
25
+ /**
26
+ * @param opts
27
+ *
28
+ * createShortcutsPlugin({
29
+ * registerShortcuts(registry) {
30
+ * }
31
+ * })
32
+ */
33
+ declare const createShortcutsPlugin: _flowgram_ai_core.PluginCreator<ShortcutsContribution>;
34
+
35
+ export { ShortcutsContribution, ShortcutsRegistry, createShortcutsPlugin };
package/dist/index.js ADDED
@@ -0,0 +1,317 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+ var __decorateClass = (decorators, target, key, kind) => {
20
+ var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc(target, key) : target;
21
+ for (var i = decorators.length - 1, decorator; i >= 0; i--)
22
+ if (decorator = decorators[i])
23
+ result = (kind ? decorator(target, key, result) : decorator(result)) || result;
24
+ if (kind && result) __defProp(target, key, result);
25
+ return result;
26
+ };
27
+
28
+ // src/index.ts
29
+ var src_exports = {};
30
+ __export(src_exports, {
31
+ ShortcutsContribution: () => ShortcutsContribution,
32
+ ShortcutsRegistry: () => ShortcutsRegistry,
33
+ createShortcutsPlugin: () => createShortcutsPlugin
34
+ });
35
+ module.exports = __toCommonJS(src_exports);
36
+
37
+ // src/create-shortcuts-plugin.ts
38
+ var import_core3 = require("@flowgram.ai/core");
39
+
40
+ // src/shortcuts-contribution.ts
41
+ var import_inversify = require("inversify");
42
+ var import_core = require("@flowgram.ai/core");
43
+ var ShortcutsContribution = Symbol("ShortcutsContribution");
44
+ var ShortcutsRegistry = class {
45
+ constructor() {
46
+ this.shortcutsHandlers = [];
47
+ }
48
+ addHandlers(...handlers) {
49
+ handlers.forEach((handler) => {
50
+ if (!this.commandRegistry.getCommand(handler.commandId)) {
51
+ this.commandRegistry.registerCommand(
52
+ { id: handler.commandId, ...handler.commandDetail || {} },
53
+ { execute: handler.execute, isEnabled: handler.isEnabled }
54
+ );
55
+ } else {
56
+ this.commandRegistry.registerHandler(handler.commandId, {
57
+ execute: handler.execute,
58
+ isEnabled: handler.isEnabled
59
+ });
60
+ }
61
+ });
62
+ this.shortcutsHandlers.push(...handlers);
63
+ }
64
+ addHandlersIfNotFound(...handlers) {
65
+ handlers.forEach((handler) => {
66
+ if (!this.has(handler.commandId)) {
67
+ this.addHandlers(handler);
68
+ }
69
+ });
70
+ }
71
+ has(commandId) {
72
+ return this.shortcutsHandlers.some((handler) => handler.commandId === commandId);
73
+ }
74
+ init() {
75
+ this.contribs?.forEach((contrib) => contrib.registerShortcuts(this));
76
+ }
77
+ };
78
+ __decorateClass([
79
+ (0, import_inversify.inject)(import_core.ContributionProvider),
80
+ (0, import_inversify.named)(ShortcutsContribution),
81
+ (0, import_inversify.optional)()
82
+ ], ShortcutsRegistry.prototype, "contribs", 2);
83
+ __decorateClass([
84
+ (0, import_inversify.inject)(import_core.CommandRegistry)
85
+ ], ShortcutsRegistry.prototype, "commandRegistry", 2);
86
+ __decorateClass([
87
+ (0, import_inversify.postConstruct)()
88
+ ], ShortcutsRegistry.prototype, "init", 1);
89
+ ShortcutsRegistry = __decorateClass([
90
+ (0, import_inversify.injectable)()
91
+ ], ShortcutsRegistry);
92
+
93
+ // src/layers/shortcuts-layer.tsx
94
+ var import_inversify2 = require("inversify");
95
+ var import_core2 = require("@flowgram.ai/core");
96
+
97
+ // src/shortcuts-utils.ts
98
+ var isAppleDevice = /(mac|iphone|ipod|ipad)/i.test(
99
+ typeof navigator !== "undefined" ? navigator?.platform : ""
100
+ );
101
+ var aliasKeyCodeMap = {
102
+ "0": 48,
103
+ "1": 49,
104
+ "2": 50,
105
+ "3": 51,
106
+ "4": 52,
107
+ "5": 53,
108
+ "6": 54,
109
+ "7": 55,
110
+ "8": 56,
111
+ "9": 57,
112
+ backspace: 8,
113
+ tab: 9,
114
+ enter: 13,
115
+ shift: 16,
116
+ ctrl: 17,
117
+ alt: 18,
118
+ pausebreak: 19,
119
+ capslock: 20,
120
+ esc: 27,
121
+ space: 32,
122
+ pageup: 33,
123
+ pagedown: 34,
124
+ end: 35,
125
+ home: 36,
126
+ leftarrow: 37,
127
+ uparrow: 38,
128
+ rightarrow: 39,
129
+ downarrow: 40,
130
+ insert: 45,
131
+ delete: 46,
132
+ a: 65,
133
+ b: 66,
134
+ c: 67,
135
+ d: 68,
136
+ e: 69,
137
+ f: 70,
138
+ g: 71,
139
+ h: 72,
140
+ i: 73,
141
+ j: 74,
142
+ k: 75,
143
+ l: 76,
144
+ m: 77,
145
+ n: 78,
146
+ o: 79,
147
+ p: 80,
148
+ q: 81,
149
+ r: 82,
150
+ s: 83,
151
+ t: 84,
152
+ u: 85,
153
+ v: 86,
154
+ w: 87,
155
+ x: 88,
156
+ y: 89,
157
+ z: 90,
158
+ leftwindowkey: 91,
159
+ rightwindowkey: 92,
160
+ meta: isAppleDevice ? [91, 93] : [91, 92],
161
+ selectkey: 93,
162
+ numpad0: 96,
163
+ numpad1: 97,
164
+ numpad2: 98,
165
+ numpad3: 99,
166
+ numpad4: 100,
167
+ numpad5: 101,
168
+ numpad6: 102,
169
+ numpad7: 103,
170
+ numpad8: 104,
171
+ numpad9: 105,
172
+ multiply: 106,
173
+ add: 107,
174
+ subtract: 109,
175
+ decimalpoint: 110,
176
+ divide: 111,
177
+ f1: 112,
178
+ f2: 113,
179
+ f3: 114,
180
+ f4: 115,
181
+ f5: 116,
182
+ f6: 117,
183
+ f7: 118,
184
+ f8: 119,
185
+ f9: 120,
186
+ f10: 121,
187
+ f11: 122,
188
+ f12: 123,
189
+ numlock: 144,
190
+ scrolllock: 145,
191
+ semicolon: 186,
192
+ equalsign: 187,
193
+ "=": 187,
194
+ comma: 188,
195
+ dash: 189,
196
+ "-": 189,
197
+ period: 190,
198
+ forwardslash: 191,
199
+ graveaccent: 192,
200
+ openbracket: 219,
201
+ backslash: 220,
202
+ closebracket: 221,
203
+ singlequote: 222
204
+ };
205
+ var modifierKey = {
206
+ ctrl: (event) => event.ctrlKey,
207
+ shift: (event) => event.shiftKey,
208
+ alt: (event) => event.altKey,
209
+ meta: (event) => {
210
+ if (event.type === "keyup") {
211
+ return aliasKeyCodeMap.meta.includes(event.keyCode);
212
+ }
213
+ return event.metaKey;
214
+ }
215
+ };
216
+ function countKeyByEvent(event) {
217
+ const countOfModifier = Object.keys(modifierKey).reduce((total, key) => {
218
+ if (modifierKey[key](event)) {
219
+ return total + 1;
220
+ }
221
+ return total;
222
+ }, 0);
223
+ return [16, 17, 18, 91, 92].includes(event.keyCode) ? countOfModifier : countOfModifier + 1;
224
+ }
225
+ function isKeyStringMatch(event, keyString, exactMatch = true) {
226
+ if (!event.key || !keyString) {
227
+ return false;
228
+ }
229
+ const genArr = keyString.split(/\s+/);
230
+ let genLen = 0;
231
+ for (const key of genArr) {
232
+ const genModifier = modifierKey[key];
233
+ const aliasKeyCode = aliasKeyCodeMap[key.toLowerCase()];
234
+ if (genModifier && genModifier(event) || aliasKeyCode && aliasKeyCode === event.keyCode) {
235
+ genLen++;
236
+ }
237
+ }
238
+ if (exactMatch) {
239
+ return genLen === genArr.length && countKeyByEvent(event) === genArr.length;
240
+ }
241
+ return genLen === genArr.length;
242
+ }
243
+ function isShortcutsMatch(event, shortcuts) {
244
+ return shortcuts.some((keyString) => isKeyStringMatch(event, keyString));
245
+ }
246
+
247
+ // src/layers/shortcuts-layer.tsx
248
+ var ShortcutsLayer = class extends import_core2.Layer {
249
+ onReady() {
250
+ this.shortcuts.addHandlersIfNotFound(
251
+ /**
252
+ * 放大
253
+ */
254
+ {
255
+ commandId: import_core2.Command.Default.ZOOM_IN,
256
+ shortcuts: ["meta =", "ctrl ="],
257
+ execute: () => {
258
+ this.config.zoomin();
259
+ }
260
+ },
261
+ /**
262
+ * 缩小
263
+ */
264
+ {
265
+ commandId: import_core2.Command.Default.ZOOM_OUT,
266
+ shortcuts: ["meta -", "ctrl -"],
267
+ execute: () => {
268
+ this.config.zoomout();
269
+ }
270
+ }
271
+ );
272
+ this.toDispose.pushAll([
273
+ // 监听画布鼠标移动事件
274
+ this.listenPlaygroundEvent("keydown", (e) => {
275
+ if (!this.isFocused || e.target !== this.playgroundNode) {
276
+ return;
277
+ }
278
+ this.shortcuts.shortcutsHandlers.some((shortcutsHandler) => {
279
+ if (isShortcutsMatch(e, shortcutsHandler.shortcuts) && (!shortcutsHandler.isEnabled || shortcutsHandler.isEnabled(e))) {
280
+ shortcutsHandler.execute(e);
281
+ e.preventDefault();
282
+ return true;
283
+ }
284
+ });
285
+ })
286
+ ]);
287
+ }
288
+ };
289
+ ShortcutsLayer.type = "ShortcutsLayer";
290
+ __decorateClass([
291
+ (0, import_inversify2.inject)(ShortcutsRegistry)
292
+ ], ShortcutsLayer.prototype, "shortcuts", 2);
293
+ __decorateClass([
294
+ (0, import_inversify2.inject)(import_core2.SelectionService)
295
+ ], ShortcutsLayer.prototype, "selection", 2);
296
+ ShortcutsLayer = __decorateClass([
297
+ (0, import_inversify2.injectable)()
298
+ ], ShortcutsLayer);
299
+
300
+ // src/create-shortcuts-plugin.ts
301
+ var createShortcutsPlugin = (0, import_core3.definePluginCreator)({
302
+ onBind: ({ bind }) => {
303
+ bind(ShortcutsRegistry).toSelf().inSingletonScope();
304
+ (0, import_core3.bindContributionProvider)(bind, ShortcutsContribution);
305
+ },
306
+ onInit: (ctx) => {
307
+ ctx.playground.registerLayer(ShortcutsLayer);
308
+ },
309
+ contributionKeys: [ShortcutsContribution]
310
+ });
311
+ // Annotate the CommonJS export names for ESM import in node:
312
+ 0 && (module.exports = {
313
+ ShortcutsContribution,
314
+ ShortcutsRegistry,
315
+ createShortcutsPlugin
316
+ });
317
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts","../src/create-shortcuts-plugin.ts","../src/shortcuts-contribution.ts","../src/layers/shortcuts-layer.tsx","../src/shortcuts-utils.ts"],"sourcesContent":["export * from './create-shortcuts-plugin';\nexport * from './shortcuts-contribution';\n","import { bindContributionProvider, definePluginCreator } from '@flowgram.ai/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","import { inject, injectable, named, optional, postConstruct } from 'inversify';\nimport { Command, CommandRegistry, ContributionProvider } from '@flowgram.ai/core';\n\ninterface 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 readonly 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 this.shortcutsHandlers.push(...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 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","import { inject, injectable } from 'inversify';\nimport { Layer, SelectionService, Command } from '@flowgram.ai/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","const 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"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAA,IAAAA,eAA8D;;;ACA9D,uBAAmE;AACnE,kBAA+D;AAYxD,IAAM,wBAAwB,OAAO,uBAAuB;AAO5D,IAAM,oBAAN,MAAwB;AAAA,EAAxB;AAQL,SAAS,oBAAwC,CAAC;AAAA;AAAA,EAElD,eAAe,UAAoC;AAEjD,aAAS,QAAQ,CAAC,YAAY;AAC5B,UAAI,CAAC,KAAK,gBAAgB,WAAW,QAAQ,SAAS,GAAG;AACvD,aAAK,gBAAgB;AAAA,UACnB,EAAE,IAAI,QAAQ,WAAW,GAAI,QAAQ,iBAAiB,CAAC,EAAG;AAAA,UAC1D,EAAE,SAAS,QAAQ,SAAS,WAAW,QAAQ,UAAU;AAAA,QAC3D;AAAA,MACF,OAAO;AACL,aAAK,gBAAgB,gBAAgB,QAAQ,WAAW;AAAA,UACtD,SAAS,QAAQ;AAAA,UACjB,WAAW,QAAQ;AAAA,QACrB,CAAC;AAAA,MACH;AAAA,IACF,CAAC;AACD,SAAK,kBAAkB,KAAK,GAAG,QAAQ;AAAA,EACzC;AAAA,EAEA,yBAAyB,UAAoC;AAC3D,aAAS,QAAQ,CAAC,YAAY;AAC5B,UAAI,CAAC,KAAK,IAAI,QAAQ,SAAS,GAAG;AAChC,aAAK,YAAY,OAAO;AAAA,MAC1B;AAAA,IACF,CAAC;AAAA,EACH;AAAA,EAEA,IAAI,WAA4B;AAC9B,WAAO,KAAK,kBAAkB,KAAK,CAAC,YAAY,QAAQ,cAAc,SAAS;AAAA,EACjF;AAAA,EAGU,OAAa;AACrB,SAAK,UAAU,QAAQ,CAAC,YAAY,QAAQ,kBAAkB,IAAI,CAAC;AAAA,EACrE;AACF;AAxCY;AAAA,MAHT,yBAAO,gCAAoB;AAAA,MAC3B,wBAAM,qBAAqB;AAAA,MAC3B,2BAAS;AAAA,GAHC,kBAID;AAEyB;AAAA,MAAlC,yBAAO,2BAAe;AAAA,GANZ,kBAMwB;AAmCzB;AAAA,MADT,gCAAc;AAAA,GAxCJ,kBAyCD;AAzCC,oBAAN;AAAA,MADN,6BAAW;AAAA,GACC;;;ACpBb,IAAAC,oBAAmC;AACnC,IAAAC,eAAiD;;;ACDjD,IAAM,gBAAgB,0BAA0B;AAAA,EAC9C,OAAO,cAAc,cAAc,WAAW,WAAW;AAC3D;AAEA,IAAM,kBAAqD;AAAA,EACzD,KAAK;AAAA,EACL,KAAK;AAAA,EACL,KAAK;AAAA,EACL,KAAK;AAAA,EACL,KAAK;AAAA,EACL,KAAK;AAAA,EACL,KAAK;AAAA,EACL,KAAK;AAAA,EACL,KAAK;AAAA,EACL,KAAK;AAAA,EACL,WAAW;AAAA,EACX,KAAK;AAAA,EACL,OAAO;AAAA,EACP,OAAO;AAAA,EACP,MAAM;AAAA,EACN,KAAK;AAAA,EACL,YAAY;AAAA,EACZ,UAAU;AAAA,EACV,KAAK;AAAA,EACL,OAAO;AAAA,EACP,QAAQ;AAAA,EACR,UAAU;AAAA,EACV,KAAK;AAAA,EACL,MAAM;AAAA,EACN,WAAW;AAAA,EACX,SAAS;AAAA,EACT,YAAY;AAAA,EACZ,WAAW;AAAA,EACX,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,GAAG;AAAA,EACH,GAAG;AAAA,EACH,GAAG;AAAA,EACH,GAAG;AAAA,EACH,GAAG;AAAA,EACH,GAAG;AAAA,EACH,GAAG;AAAA,EACH,GAAG;AAAA,EACH,GAAG;AAAA,EACH,GAAG;AAAA,EACH,GAAG;AAAA,EACH,GAAG;AAAA,EACH,GAAG;AAAA,EACH,GAAG;AAAA,EACH,GAAG;AAAA,EACH,GAAG;AAAA,EACH,GAAG;AAAA,EACH,GAAG;AAAA,EACH,GAAG;AAAA,EACH,GAAG;AAAA,EACH,GAAG;AAAA,EACH,GAAG;AAAA,EACH,GAAG;AAAA,EACH,GAAG;AAAA,EACH,GAAG;AAAA,EACH,GAAG;AAAA,EACH,eAAe;AAAA,EACf,gBAAgB;AAAA,EAChB,MAAM,gBAAgB,CAAC,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE;AAAA,EACxC,WAAW;AAAA,EACX,SAAS;AAAA,EACT,SAAS;AAAA,EACT,SAAS;AAAA,EACT,SAAS;AAAA,EACT,SAAS;AAAA,EACT,SAAS;AAAA,EACT,SAAS;AAAA,EACT,SAAS;AAAA,EACT,SAAS;AAAA,EACT,SAAS;AAAA,EACT,UAAU;AAAA,EACV,KAAK;AAAA,EACL,UAAU;AAAA,EACV,cAAc;AAAA,EACd,QAAQ;AAAA,EACR,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,KAAK;AAAA,EACL,KAAK;AAAA,EACL,KAAK;AAAA,EACL,SAAS;AAAA,EACT,YAAY;AAAA,EACZ,WAAW;AAAA,EACX,WAAW;AAAA,EACX,KAAK;AAAA,EACL,OAAO;AAAA,EACP,MAAM;AAAA,EACN,KAAK;AAAA,EACL,QAAQ;AAAA,EACR,cAAc;AAAA,EACd,aAAa;AAAA,EACb,aAAa;AAAA,EACb,WAAW;AAAA,EACX,cAAc;AAAA,EACd,aAAa;AACf;AAEA,IAAM,cAAmB;AAAA,EACvB,MAAM,CAAC,UAAyB,MAAM;AAAA,EACtC,OAAO,CAAC,UAAyB,MAAM;AAAA,EACvC,KAAK,CAAC,UAAyB,MAAM;AAAA,EACrC,MAAM,CAAC,UAAyB;AAC9B,QAAI,MAAM,SAAS,SAAS;AAC1B,aAAQ,gBAAgB,KAAkB,SAAS,MAAM,OAAO;AAAA,IAClE;AACA,WAAO,MAAM;AAAA,EACf;AACF;AAGA,SAAS,gBAAgB,OAA8B;AACrD,QAAM,kBAAkB,OAAO,KAAK,WAAW,EAAE,OAAO,CAAC,OAAO,QAAQ;AACtE,QAAI,YAAY,GAAG,EAAE,KAAK,GAAG;AAC3B,aAAO,QAAQ;AAAA,IACjB;AAEA,WAAO;AAAA,EACT,GAAG,CAAC;AAGJ,SAAO,CAAC,IAAI,IAAI,IAAI,IAAI,EAAE,EAAE,SAAS,MAAM,OAAO,IAAI,kBAAkB,kBAAkB;AAC5F;AAQA,SAAS,iBAAiB,OAAsB,WAAmB,aAAa,MAAe;AAE7F,MAAI,CAAC,MAAM,OAAO,CAAC,WAAW;AAC5B,WAAO;AAAA,EACT;AAEA,QAAM,SAAS,UAAU,MAAM,KAAK;AACpC,MAAI,SAAS;AAEb,aAAW,OAAO,QAAQ;AAExB,UAAM,cAAc,YAAY,GAAG;AAEnC,UAAM,eAAkC,gBAAgB,IAAI,YAAY,CAAC;AAEzE,QAAK,eAAe,YAAY,KAAK,KAAO,gBAAgB,iBAAiB,MAAM,SAAU;AAC3F;AAAA,IACF;AAAA,EACF;AAQA,MAAI,YAAY;AACd,WAAO,WAAW,OAAO,UAAU,gBAAgB,KAAK,MAAM,OAAO;AAAA,EACvE;AACA,SAAO,WAAW,OAAO;AAC3B;AAOO,SAAS,iBAAiB,OAAsB,WAA8B;AACnF,SAAO,UAAU,KAAK,eAAa,iBAAiB,OAAO,SAAS,CAAC;AACvE;;;AD7KO,IAAM,iBAAN,cAA6B,mBAAc;AAAA,EAOhD,UAAgB;AACd,SAAK,UAAU;AAAA;AAAA;AAAA;AAAA,MAIb;AAAA,QACE,WAAW,qBAAQ,QAAQ;AAAA,QAC3B,WAAW,CAAC,UAAU,QAAQ;AAAA,QAC9B,SAAS,MAAM;AAEb,eAAK,OAAO,OAAO;AAAA,QACrB;AAAA,MACF;AAAA;AAAA;AAAA;AAAA,MAIA;AAAA,QACE,WAAW,qBAAQ,QAAQ;AAAA,QAC3B,WAAW,CAAC,UAAU,QAAQ;AAAA,QAC9B,SAAS,MAAM;AAEb,eAAK,OAAO,QAAQ;AAAA,QACtB;AAAA,MACF;AAAA,IACF;AACA,SAAK,UAAU,QAAQ;AAAA;AAAA,MAErB,KAAK,sBAAsB,WAAW,CAAC,MAAqB;AAC1D,YAAI,CAAC,KAAK,aAAa,EAAE,WAAW,KAAK,gBAAgB;AACvD;AAAA,QACF;AACA,aAAK,UAAU,kBAAkB,KAAK,sBAAoB;AACxD,cACE,iBAAiB,GAAG,iBAAiB,SAAS,MAC7C,CAAC,iBAAiB,aAAa,iBAAiB,UAAU,CAAC,IAC5D;AACA,6BAAiB,QAAQ,CAAC;AAC1B,cAAE,eAAe;AACjB,mBAAO;AAAA,UACT;AAAA,QACF,CAAC;AAAA,MACH,CAAC;AAAA,IACH,CAAC;AAAA,EACH;AACF;AAnDa,eACJ,OAAO;AAEa;AAAA,MAA1B,0BAAO,iBAAiB;AAAA,GAHd,eAGgB;AAED;AAAA,MAAzB,0BAAO,6BAAgB;AAAA,GALb,eAKe;AALf,iBAAN;AAAA,MADN,8BAAW;AAAA,GACC;;;AFMN,IAAM,4BAAwB,kCAA2C;AAAA,EAC9E,QAAQ,CAAC,EAAE,KAAK,MAAM;AACpB,SAAK,iBAAiB,EAAE,OAAO,EAAE,iBAAiB;AAClD,+CAAyB,MAAM,qBAAqB;AAAA,EACtD;AAAA,EACA,QAAQ,CAAC,QAAQ;AACf,QAAI,WAAW,cAAc,cAAc;AAAA,EAC7C;AAAA,EACA,kBAAkB,CAAC,qBAAqB;AAC1C,CAAC;","names":["import_core","import_inversify","import_core"]}
package/package.json ADDED
@@ -0,0 +1,46 @@
1
+ {
2
+ "name": "@flowgram.ai/shortcuts-plugin",
3
+ "version": "0.1.0",
4
+ "license": "MIT",
5
+ "exports": {
6
+ "types": "./dist/index.d.ts",
7
+ "import": "./dist/esm/index.js",
8
+ "require": "./dist/index.js"
9
+ },
10
+ "main": "./dist/index.js",
11
+ "module": "./dist/esm/index.js",
12
+ "types": "./dist/index.d.ts",
13
+ "files": [
14
+ "dist"
15
+ ],
16
+ "dependencies": {
17
+ "inversify": "^6.0.1",
18
+ "styled-components": "^5",
19
+ "@flowgram.ai/document": "0.1.0",
20
+ "@flowgram.ai/utils": "0.1.0",
21
+ "@flowgram.ai/core": "0.1.0"
22
+ },
23
+ "devDependencies": {
24
+ "@vitest/coverage-v8": "^0.32.0",
25
+ "eslint": "^8.54.0",
26
+ "tsup": "^8.0.1",
27
+ "typescript": "^5.0.4",
28
+ "vitest": "^0.34.6",
29
+ "@flowgram.ai/eslint-config": "0.1.0",
30
+ "@flowgram.ai/ts-config": "0.1.0"
31
+ },
32
+ "publishConfig": {
33
+ "access": "public",
34
+ "registry": "https://registry.npmjs.org/"
35
+ },
36
+ "scripts": {
37
+ "build": "npm run build:fast -- --dts-resolve",
38
+ "build:fast": "tsup src/index.ts --format cjs,esm --sourcemap --legacy-output",
39
+ "build:watch": "npm run build:fast -- --dts-resolve",
40
+ "clean": "rimraf dist",
41
+ "test": "exit 0",
42
+ "test:cov": "exit 0",
43
+ "ts-check": "tsc --noEmit",
44
+ "watch": "npm run build:fast -- --dts-resolve --watch --ignore-watch dist"
45
+ }
46
+ }