@tanstack/angular-hotkeys 0.6.0 → 0.7.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/dist/index.cjs +2 -0
- package/dist/index.d.cts +2 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.js +2 -1
- package/dist/injectHotkey.cjs +36 -6
- package/dist/injectHotkey.cjs.map +1 -1
- package/dist/injectHotkey.d.cts +2 -0
- package/dist/injectHotkey.d.ts +2 -0
- package/dist/injectHotkey.js +37 -7
- package/dist/injectHotkey.js.map +1 -1
- package/dist/injectHotkeySequence.cjs +43 -11
- package/dist/injectHotkeySequence.cjs.map +1 -1
- package/dist/injectHotkeySequence.d.cts +9 -2
- package/dist/injectHotkeySequence.d.ts +9 -2
- package/dist/injectHotkeySequence.js +45 -13
- package/dist/injectHotkeySequence.js.map +1 -1
- package/dist/injectHotkeySequences.cjs +105 -0
- package/dist/injectHotkeySequences.cjs.map +1 -0
- package/dist/injectHotkeySequences.d.cts +47 -0
- package/dist/injectHotkeySequences.d.ts +47 -0
- package/dist/injectHotkeySequences.js +105 -0
- package/dist/injectHotkeySequences.js.map +1 -0
- package/package.json +1 -1
- package/src/index.ts +1 -0
- package/src/injectHotkey.ts +43 -11
- package/src/injectHotkeySequence.ts +66 -19
- package/src/injectHotkeySequences.ts +176 -0
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
const require_hotkeys_provider = require('./hotkeys-provider.cjs');
|
|
2
|
+
let _tanstack_hotkeys = require("@tanstack/hotkeys");
|
|
3
|
+
let _angular_core = require("@angular/core");
|
|
4
|
+
|
|
5
|
+
//#region src/injectHotkeySequences.ts
|
|
6
|
+
/**
|
|
7
|
+
* Angular inject-based API for registering multiple keyboard shortcut sequences at once (Vim-style).
|
|
8
|
+
*
|
|
9
|
+
* Uses the singleton SequenceManager. Call in an injection context (e.g. constructor).
|
|
10
|
+
* Uses `effect()` to track reactive dependencies when definitions or options are getters.
|
|
11
|
+
*
|
|
12
|
+
* Options are merged in this order:
|
|
13
|
+
* provideHotkeys defaults < commonOptions < per-definition options
|
|
14
|
+
*
|
|
15
|
+
* Definitions with an empty `sequence` are skipped. Disabled sequences (`enabled: false`)
|
|
16
|
+
* remain registered so they stay visible in devtools; the core manager suppresses execution.
|
|
17
|
+
*
|
|
18
|
+
* @param sequences - Array of sequence definitions, or getter returning them
|
|
19
|
+
* @param commonOptions - Shared options for all sequences, or getter
|
|
20
|
+
*
|
|
21
|
+
* @example
|
|
22
|
+
* ```ts
|
|
23
|
+
* @Component({ ... })
|
|
24
|
+
* export class VimComponent {
|
|
25
|
+
* constructor() {
|
|
26
|
+
* injectHotkeySequences([
|
|
27
|
+
* { sequence: ['G', 'G'], callback: () => this.goTop() },
|
|
28
|
+
* { sequence: ['D', 'D'], callback: () => this.deleteLine() },
|
|
29
|
+
* ])
|
|
30
|
+
* }
|
|
31
|
+
* }
|
|
32
|
+
* ```
|
|
33
|
+
*/
|
|
34
|
+
function injectHotkeySequences(sequences, commonOptions = {}) {
|
|
35
|
+
const defaultOptions = require_hotkeys_provider.injectDefaultHotkeysOptions();
|
|
36
|
+
const manager = (0, _tanstack_hotkeys.getSequenceManager)();
|
|
37
|
+
const destroyRef = (0, _angular_core.inject)(_angular_core.DestroyRef);
|
|
38
|
+
const registrations = /* @__PURE__ */ new Map();
|
|
39
|
+
destroyRef.onDestroy(() => {
|
|
40
|
+
for (const { handle } of registrations.values()) if (handle.isActive) handle.unregister();
|
|
41
|
+
registrations.clear();
|
|
42
|
+
});
|
|
43
|
+
(0, _angular_core.effect)(() => {
|
|
44
|
+
const resolvedSequences = typeof sequences === "function" ? sequences() : sequences;
|
|
45
|
+
const resolvedCommonOptions = typeof commonOptions === "function" ? commonOptions() : commonOptions;
|
|
46
|
+
const nextKeys = /* @__PURE__ */ new Set();
|
|
47
|
+
const prepared = [];
|
|
48
|
+
for (let i = 0; i < resolvedSequences.length; i++) {
|
|
49
|
+
const def = resolvedSequences[i];
|
|
50
|
+
const resolvedSequence = typeof def.sequence === "function" ? def.sequence() : def.sequence;
|
|
51
|
+
const resolvedDefOptions = typeof def.options === "function" ? def.options() : def.options ?? {};
|
|
52
|
+
const { enabled = true, ...sequenceOpts } = {
|
|
53
|
+
...defaultOptions.hotkeySequence,
|
|
54
|
+
...resolvedCommonOptions,
|
|
55
|
+
...resolvedDefOptions
|
|
56
|
+
};
|
|
57
|
+
if (resolvedSequence.length === 0) continue;
|
|
58
|
+
const resolvedTarget = "target" in sequenceOpts ? sequenceOpts.target ?? null : typeof document !== "undefined" ? document : null;
|
|
59
|
+
if (!resolvedTarget) continue;
|
|
60
|
+
const registrationKey = `${i}:${(0, _tanstack_hotkeys.formatHotkeySequence)(resolvedSequence)}`;
|
|
61
|
+
nextKeys.add(registrationKey);
|
|
62
|
+
prepared.push({
|
|
63
|
+
registrationKey,
|
|
64
|
+
def,
|
|
65
|
+
resolvedSequence,
|
|
66
|
+
enabled,
|
|
67
|
+
sequenceOpts,
|
|
68
|
+
resolvedTarget
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
for (const [key, record] of [...registrations.entries()]) if (!nextKeys.has(key)) {
|
|
72
|
+
if (record.handle.isActive) record.handle.unregister();
|
|
73
|
+
registrations.delete(key);
|
|
74
|
+
}
|
|
75
|
+
for (const p of prepared) {
|
|
76
|
+
const existing = registrations.get(p.registrationKey);
|
|
77
|
+
if (existing?.handle.isActive && existing.target === p.resolvedTarget) {
|
|
78
|
+
existing.handle.callback = p.def.callback;
|
|
79
|
+
const { target: _target, ...optionsWithoutTarget } = p.sequenceOpts;
|
|
80
|
+
existing.handle.setOptions({
|
|
81
|
+
...optionsWithoutTarget,
|
|
82
|
+
enabled: p.enabled
|
|
83
|
+
});
|
|
84
|
+
continue;
|
|
85
|
+
}
|
|
86
|
+
if (existing) {
|
|
87
|
+
if (existing.handle.isActive) existing.handle.unregister();
|
|
88
|
+
registrations.delete(p.registrationKey);
|
|
89
|
+
}
|
|
90
|
+
const handle = manager.register(p.resolvedSequence, p.def.callback, {
|
|
91
|
+
...p.sequenceOpts,
|
|
92
|
+
enabled: p.enabled,
|
|
93
|
+
target: p.resolvedTarget
|
|
94
|
+
});
|
|
95
|
+
registrations.set(p.registrationKey, {
|
|
96
|
+
handle,
|
|
97
|
+
target: p.resolvedTarget
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
//#endregion
|
|
104
|
+
exports.injectHotkeySequences = injectHotkeySequences;
|
|
105
|
+
//# sourceMappingURL=injectHotkeySequences.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"injectHotkeySequences.cjs","names":["injectDefaultHotkeysOptions","DestroyRef"],"sources":["../src/injectHotkeySequences.ts"],"sourcesContent":["import { DestroyRef, effect, inject } from '@angular/core'\nimport { formatHotkeySequence, getSequenceManager } from '@tanstack/hotkeys'\nimport { injectDefaultHotkeysOptions } from './hotkeys-provider'\nimport type { InjectHotkeySequenceOptions } from './injectHotkeySequence'\nimport type {\n HotkeyCallback,\n HotkeySequence,\n SequenceRegistrationHandle,\n} from '@tanstack/hotkeys'\n\n/**\n * A single sequence definition for use with `injectHotkeySequences`.\n */\nexport interface InjectHotkeySequenceDefinition {\n /** Array of hotkey strings that form the sequence */\n sequence: HotkeySequence | (() => HotkeySequence)\n /** The function to call when the sequence is completed */\n callback: HotkeyCallback\n /** Per-sequence options (merged on top of commonOptions) */\n options?: InjectHotkeySequenceOptions | (() => InjectHotkeySequenceOptions)\n}\n\n/**\n * Angular inject-based API for registering multiple keyboard shortcut sequences at once (Vim-style).\n *\n * Uses the singleton SequenceManager. Call in an injection context (e.g. constructor).\n * Uses `effect()` to track reactive dependencies when definitions or options are getters.\n *\n * Options are merged in this order:\n * provideHotkeys defaults < commonOptions < per-definition options\n *\n * Definitions with an empty `sequence` are skipped. Disabled sequences (`enabled: false`)\n * remain registered so they stay visible in devtools; the core manager suppresses execution.\n *\n * @param sequences - Array of sequence definitions, or getter returning them\n * @param commonOptions - Shared options for all sequences, or getter\n *\n * @example\n * ```ts\n * @Component({ ... })\n * export class VimComponent {\n * constructor() {\n * injectHotkeySequences([\n * { sequence: ['G', 'G'], callback: () => this.goTop() },\n * { sequence: ['D', 'D'], callback: () => this.deleteLine() },\n * ])\n * }\n * }\n * ```\n */\nexport function injectHotkeySequences(\n sequences:\n | Array<InjectHotkeySequenceDefinition>\n | (() => Array<InjectHotkeySequenceDefinition>),\n commonOptions:\n | InjectHotkeySequenceOptions\n | (() => InjectHotkeySequenceOptions) = {},\n): void {\n type RegistrationRecord = {\n handle: SequenceRegistrationHandle\n target: Document | HTMLElement | Window\n }\n\n const defaultOptions = injectDefaultHotkeysOptions()\n const manager = getSequenceManager()\n const destroyRef = inject(DestroyRef)\n\n const registrations = new Map<string, RegistrationRecord>()\n\n destroyRef.onDestroy(() => {\n for (const { handle } of registrations.values()) {\n if (handle.isActive) {\n handle.unregister()\n }\n }\n registrations.clear()\n })\n\n effect(() => {\n const resolvedSequences =\n typeof sequences === 'function' ? sequences() : sequences\n const resolvedCommonOptions =\n typeof commonOptions === 'function' ? commonOptions() : commonOptions\n\n const nextKeys = new Set<string>()\n const prepared: Array<{\n registrationKey: string\n def: InjectHotkeySequenceDefinition\n resolvedSequence: HotkeySequence\n enabled: boolean\n sequenceOpts: Omit<InjectHotkeySequenceOptions, 'enabled'>\n resolvedTarget: Document | HTMLElement | Window\n }> = []\n\n for (let i = 0; i < resolvedSequences.length; i++) {\n const def = resolvedSequences[i]!\n const resolvedSequence =\n typeof def.sequence === 'function' ? def.sequence() : def.sequence\n const resolvedDefOptions =\n typeof def.options === 'function' ? def.options() : (def.options ?? {})\n\n const mergedOptions = {\n ...defaultOptions.hotkeySequence,\n ...resolvedCommonOptions,\n ...resolvedDefOptions,\n } as InjectHotkeySequenceOptions\n\n const { enabled = true, ...sequenceOpts } = mergedOptions\n\n if (resolvedSequence.length === 0) {\n continue\n }\n\n const resolvedTarget =\n 'target' in sequenceOpts\n ? (sequenceOpts.target ?? null)\n : typeof document !== 'undefined'\n ? document\n : null\n\n if (!resolvedTarget) {\n continue\n }\n\n const registrationKey = `${i}:${formatHotkeySequence(resolvedSequence)}`\n nextKeys.add(registrationKey)\n prepared.push({\n registrationKey,\n def,\n resolvedSequence,\n enabled,\n sequenceOpts,\n resolvedTarget,\n })\n }\n\n for (const [key, record] of [...registrations.entries()]) {\n if (!nextKeys.has(key)) {\n if (record.handle.isActive) {\n record.handle.unregister()\n }\n registrations.delete(key)\n }\n }\n\n for (const p of prepared) {\n const existing = registrations.get(p.registrationKey)\n if (existing?.handle.isActive && existing.target === p.resolvedTarget) {\n existing.handle.callback = p.def.callback\n const { target: _target, ...optionsWithoutTarget } = p.sequenceOpts\n existing.handle.setOptions({\n ...optionsWithoutTarget,\n enabled: p.enabled,\n })\n continue\n }\n\n if (existing) {\n if (existing.handle.isActive) {\n existing.handle.unregister()\n }\n registrations.delete(p.registrationKey)\n }\n\n const handle = manager.register(p.resolvedSequence, p.def.callback, {\n ...p.sequenceOpts,\n enabled: p.enabled,\n target: p.resolvedTarget,\n })\n registrations.set(p.registrationKey, {\n handle,\n target: p.resolvedTarget,\n })\n }\n })\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAkDA,SAAgB,sBACd,WAGA,gBAE0C,EAAE,EACtC;CAMN,MAAM,iBAAiBA,sDAA6B;CACpD,MAAM,qDAA8B;CACpC,MAAM,uCAAoBC,yBAAW;CAErC,MAAM,gCAAgB,IAAI,KAAiC;AAE3D,YAAW,gBAAgB;AACzB,OAAK,MAAM,EAAE,YAAY,cAAc,QAAQ,CAC7C,KAAI,OAAO,SACT,QAAO,YAAY;AAGvB,gBAAc,OAAO;GACrB;AAEF,iCAAa;EACX,MAAM,oBACJ,OAAO,cAAc,aAAa,WAAW,GAAG;EAClD,MAAM,wBACJ,OAAO,kBAAkB,aAAa,eAAe,GAAG;EAE1D,MAAM,2BAAW,IAAI,KAAa;EAClC,MAAM,WAOD,EAAE;AAEP,OAAK,IAAI,IAAI,GAAG,IAAI,kBAAkB,QAAQ,KAAK;GACjD,MAAM,MAAM,kBAAkB;GAC9B,MAAM,mBACJ,OAAO,IAAI,aAAa,aAAa,IAAI,UAAU,GAAG,IAAI;GAC5D,MAAM,qBACJ,OAAO,IAAI,YAAY,aAAa,IAAI,SAAS,GAAI,IAAI,WAAW,EAAE;GAQxE,MAAM,EAAE,UAAU,MAAM,GAAG,iBANL;IACpB,GAAG,eAAe;IAClB,GAAG;IACH,GAAG;IACJ;AAID,OAAI,iBAAiB,WAAW,EAC9B;GAGF,MAAM,iBACJ,YAAY,eACP,aAAa,UAAU,OACxB,OAAO,aAAa,cAClB,WACA;AAER,OAAI,CAAC,eACH;GAGF,MAAM,kBAAkB,GAAG,EAAE,+CAAwB,iBAAiB;AACtE,YAAS,IAAI,gBAAgB;AAC7B,YAAS,KAAK;IACZ;IACA;IACA;IACA;IACA;IACA;IACD,CAAC;;AAGJ,OAAK,MAAM,CAAC,KAAK,WAAW,CAAC,GAAG,cAAc,SAAS,CAAC,CACtD,KAAI,CAAC,SAAS,IAAI,IAAI,EAAE;AACtB,OAAI,OAAO,OAAO,SAChB,QAAO,OAAO,YAAY;AAE5B,iBAAc,OAAO,IAAI;;AAI7B,OAAK,MAAM,KAAK,UAAU;GACxB,MAAM,WAAW,cAAc,IAAI,EAAE,gBAAgB;AACrD,OAAI,UAAU,OAAO,YAAY,SAAS,WAAW,EAAE,gBAAgB;AACrE,aAAS,OAAO,WAAW,EAAE,IAAI;IACjC,MAAM,EAAE,QAAQ,SAAS,GAAG,yBAAyB,EAAE;AACvD,aAAS,OAAO,WAAW;KACzB,GAAG;KACH,SAAS,EAAE;KACZ,CAAC;AACF;;AAGF,OAAI,UAAU;AACZ,QAAI,SAAS,OAAO,SAClB,UAAS,OAAO,YAAY;AAE9B,kBAAc,OAAO,EAAE,gBAAgB;;GAGzC,MAAM,SAAS,QAAQ,SAAS,EAAE,kBAAkB,EAAE,IAAI,UAAU;IAClE,GAAG,EAAE;IACL,SAAS,EAAE;IACX,QAAQ,EAAE;IACX,CAAC;AACF,iBAAc,IAAI,EAAE,iBAAiB;IACnC;IACA,QAAQ,EAAE;IACX,CAAC;;GAEJ"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { InjectHotkeySequenceOptions } from "./injectHotkeySequence.cjs";
|
|
2
|
+
import { HotkeyCallback, HotkeySequence } from "@tanstack/hotkeys";
|
|
3
|
+
|
|
4
|
+
//#region src/injectHotkeySequences.d.ts
|
|
5
|
+
/**
|
|
6
|
+
* A single sequence definition for use with `injectHotkeySequences`.
|
|
7
|
+
*/
|
|
8
|
+
interface InjectHotkeySequenceDefinition {
|
|
9
|
+
/** Array of hotkey strings that form the sequence */
|
|
10
|
+
sequence: HotkeySequence | (() => HotkeySequence);
|
|
11
|
+
/** The function to call when the sequence is completed */
|
|
12
|
+
callback: HotkeyCallback;
|
|
13
|
+
/** Per-sequence options (merged on top of commonOptions) */
|
|
14
|
+
options?: InjectHotkeySequenceOptions | (() => InjectHotkeySequenceOptions);
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Angular inject-based API for registering multiple keyboard shortcut sequences at once (Vim-style).
|
|
18
|
+
*
|
|
19
|
+
* Uses the singleton SequenceManager. Call in an injection context (e.g. constructor).
|
|
20
|
+
* Uses `effect()` to track reactive dependencies when definitions or options are getters.
|
|
21
|
+
*
|
|
22
|
+
* Options are merged in this order:
|
|
23
|
+
* provideHotkeys defaults < commonOptions < per-definition options
|
|
24
|
+
*
|
|
25
|
+
* Definitions with an empty `sequence` are skipped. Disabled sequences (`enabled: false`)
|
|
26
|
+
* remain registered so they stay visible in devtools; the core manager suppresses execution.
|
|
27
|
+
*
|
|
28
|
+
* @param sequences - Array of sequence definitions, or getter returning them
|
|
29
|
+
* @param commonOptions - Shared options for all sequences, or getter
|
|
30
|
+
*
|
|
31
|
+
* @example
|
|
32
|
+
* ```ts
|
|
33
|
+
* @Component({ ... })
|
|
34
|
+
* export class VimComponent {
|
|
35
|
+
* constructor() {
|
|
36
|
+
* injectHotkeySequences([
|
|
37
|
+
* { sequence: ['G', 'G'], callback: () => this.goTop() },
|
|
38
|
+
* { sequence: ['D', 'D'], callback: () => this.deleteLine() },
|
|
39
|
+
* ])
|
|
40
|
+
* }
|
|
41
|
+
* }
|
|
42
|
+
* ```
|
|
43
|
+
*/
|
|
44
|
+
declare function injectHotkeySequences(sequences: Array<InjectHotkeySequenceDefinition> | (() => Array<InjectHotkeySequenceDefinition>), commonOptions?: InjectHotkeySequenceOptions | (() => InjectHotkeySequenceOptions)): void;
|
|
45
|
+
//#endregion
|
|
46
|
+
export { InjectHotkeySequenceDefinition, injectHotkeySequences };
|
|
47
|
+
//# sourceMappingURL=injectHotkeySequences.d.cts.map
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { InjectHotkeySequenceOptions } from "./injectHotkeySequence.js";
|
|
2
|
+
import { HotkeyCallback, HotkeySequence } from "@tanstack/hotkeys";
|
|
3
|
+
|
|
4
|
+
//#region src/injectHotkeySequences.d.ts
|
|
5
|
+
/**
|
|
6
|
+
* A single sequence definition for use with `injectHotkeySequences`.
|
|
7
|
+
*/
|
|
8
|
+
interface InjectHotkeySequenceDefinition {
|
|
9
|
+
/** Array of hotkey strings that form the sequence */
|
|
10
|
+
sequence: HotkeySequence | (() => HotkeySequence);
|
|
11
|
+
/** The function to call when the sequence is completed */
|
|
12
|
+
callback: HotkeyCallback;
|
|
13
|
+
/** Per-sequence options (merged on top of commonOptions) */
|
|
14
|
+
options?: InjectHotkeySequenceOptions | (() => InjectHotkeySequenceOptions);
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Angular inject-based API for registering multiple keyboard shortcut sequences at once (Vim-style).
|
|
18
|
+
*
|
|
19
|
+
* Uses the singleton SequenceManager. Call in an injection context (e.g. constructor).
|
|
20
|
+
* Uses `effect()` to track reactive dependencies when definitions or options are getters.
|
|
21
|
+
*
|
|
22
|
+
* Options are merged in this order:
|
|
23
|
+
* provideHotkeys defaults < commonOptions < per-definition options
|
|
24
|
+
*
|
|
25
|
+
* Definitions with an empty `sequence` are skipped. Disabled sequences (`enabled: false`)
|
|
26
|
+
* remain registered so they stay visible in devtools; the core manager suppresses execution.
|
|
27
|
+
*
|
|
28
|
+
* @param sequences - Array of sequence definitions, or getter returning them
|
|
29
|
+
* @param commonOptions - Shared options for all sequences, or getter
|
|
30
|
+
*
|
|
31
|
+
* @example
|
|
32
|
+
* ```ts
|
|
33
|
+
* @Component({ ... })
|
|
34
|
+
* export class VimComponent {
|
|
35
|
+
* constructor() {
|
|
36
|
+
* injectHotkeySequences([
|
|
37
|
+
* { sequence: ['G', 'G'], callback: () => this.goTop() },
|
|
38
|
+
* { sequence: ['D', 'D'], callback: () => this.deleteLine() },
|
|
39
|
+
* ])
|
|
40
|
+
* }
|
|
41
|
+
* }
|
|
42
|
+
* ```
|
|
43
|
+
*/
|
|
44
|
+
declare function injectHotkeySequences(sequences: Array<InjectHotkeySequenceDefinition> | (() => Array<InjectHotkeySequenceDefinition>), commonOptions?: InjectHotkeySequenceOptions | (() => InjectHotkeySequenceOptions)): void;
|
|
45
|
+
//#endregion
|
|
46
|
+
export { InjectHotkeySequenceDefinition, injectHotkeySequences };
|
|
47
|
+
//# sourceMappingURL=injectHotkeySequences.d.ts.map
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import { injectDefaultHotkeysOptions } from "./hotkeys-provider.js";
|
|
2
|
+
import { formatHotkeySequence, getSequenceManager } from "@tanstack/hotkeys";
|
|
3
|
+
import { DestroyRef, effect, inject } from "@angular/core";
|
|
4
|
+
|
|
5
|
+
//#region src/injectHotkeySequences.ts
|
|
6
|
+
/**
|
|
7
|
+
* Angular inject-based API for registering multiple keyboard shortcut sequences at once (Vim-style).
|
|
8
|
+
*
|
|
9
|
+
* Uses the singleton SequenceManager. Call in an injection context (e.g. constructor).
|
|
10
|
+
* Uses `effect()` to track reactive dependencies when definitions or options are getters.
|
|
11
|
+
*
|
|
12
|
+
* Options are merged in this order:
|
|
13
|
+
* provideHotkeys defaults < commonOptions < per-definition options
|
|
14
|
+
*
|
|
15
|
+
* Definitions with an empty `sequence` are skipped. Disabled sequences (`enabled: false`)
|
|
16
|
+
* remain registered so they stay visible in devtools; the core manager suppresses execution.
|
|
17
|
+
*
|
|
18
|
+
* @param sequences - Array of sequence definitions, or getter returning them
|
|
19
|
+
* @param commonOptions - Shared options for all sequences, or getter
|
|
20
|
+
*
|
|
21
|
+
* @example
|
|
22
|
+
* ```ts
|
|
23
|
+
* @Component({ ... })
|
|
24
|
+
* export class VimComponent {
|
|
25
|
+
* constructor() {
|
|
26
|
+
* injectHotkeySequences([
|
|
27
|
+
* { sequence: ['G', 'G'], callback: () => this.goTop() },
|
|
28
|
+
* { sequence: ['D', 'D'], callback: () => this.deleteLine() },
|
|
29
|
+
* ])
|
|
30
|
+
* }
|
|
31
|
+
* }
|
|
32
|
+
* ```
|
|
33
|
+
*/
|
|
34
|
+
function injectHotkeySequences(sequences, commonOptions = {}) {
|
|
35
|
+
const defaultOptions = injectDefaultHotkeysOptions();
|
|
36
|
+
const manager = getSequenceManager();
|
|
37
|
+
const destroyRef = inject(DestroyRef);
|
|
38
|
+
const registrations = /* @__PURE__ */ new Map();
|
|
39
|
+
destroyRef.onDestroy(() => {
|
|
40
|
+
for (const { handle } of registrations.values()) if (handle.isActive) handle.unregister();
|
|
41
|
+
registrations.clear();
|
|
42
|
+
});
|
|
43
|
+
effect(() => {
|
|
44
|
+
const resolvedSequences = typeof sequences === "function" ? sequences() : sequences;
|
|
45
|
+
const resolvedCommonOptions = typeof commonOptions === "function" ? commonOptions() : commonOptions;
|
|
46
|
+
const nextKeys = /* @__PURE__ */ new Set();
|
|
47
|
+
const prepared = [];
|
|
48
|
+
for (let i = 0; i < resolvedSequences.length; i++) {
|
|
49
|
+
const def = resolvedSequences[i];
|
|
50
|
+
const resolvedSequence = typeof def.sequence === "function" ? def.sequence() : def.sequence;
|
|
51
|
+
const resolvedDefOptions = typeof def.options === "function" ? def.options() : def.options ?? {};
|
|
52
|
+
const { enabled = true, ...sequenceOpts } = {
|
|
53
|
+
...defaultOptions.hotkeySequence,
|
|
54
|
+
...resolvedCommonOptions,
|
|
55
|
+
...resolvedDefOptions
|
|
56
|
+
};
|
|
57
|
+
if (resolvedSequence.length === 0) continue;
|
|
58
|
+
const resolvedTarget = "target" in sequenceOpts ? sequenceOpts.target ?? null : typeof document !== "undefined" ? document : null;
|
|
59
|
+
if (!resolvedTarget) continue;
|
|
60
|
+
const registrationKey = `${i}:${formatHotkeySequence(resolvedSequence)}`;
|
|
61
|
+
nextKeys.add(registrationKey);
|
|
62
|
+
prepared.push({
|
|
63
|
+
registrationKey,
|
|
64
|
+
def,
|
|
65
|
+
resolvedSequence,
|
|
66
|
+
enabled,
|
|
67
|
+
sequenceOpts,
|
|
68
|
+
resolvedTarget
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
for (const [key, record] of [...registrations.entries()]) if (!nextKeys.has(key)) {
|
|
72
|
+
if (record.handle.isActive) record.handle.unregister();
|
|
73
|
+
registrations.delete(key);
|
|
74
|
+
}
|
|
75
|
+
for (const p of prepared) {
|
|
76
|
+
const existing = registrations.get(p.registrationKey);
|
|
77
|
+
if (existing?.handle.isActive && existing.target === p.resolvedTarget) {
|
|
78
|
+
existing.handle.callback = p.def.callback;
|
|
79
|
+
const { target: _target, ...optionsWithoutTarget } = p.sequenceOpts;
|
|
80
|
+
existing.handle.setOptions({
|
|
81
|
+
...optionsWithoutTarget,
|
|
82
|
+
enabled: p.enabled
|
|
83
|
+
});
|
|
84
|
+
continue;
|
|
85
|
+
}
|
|
86
|
+
if (existing) {
|
|
87
|
+
if (existing.handle.isActive) existing.handle.unregister();
|
|
88
|
+
registrations.delete(p.registrationKey);
|
|
89
|
+
}
|
|
90
|
+
const handle = manager.register(p.resolvedSequence, p.def.callback, {
|
|
91
|
+
...p.sequenceOpts,
|
|
92
|
+
enabled: p.enabled,
|
|
93
|
+
target: p.resolvedTarget
|
|
94
|
+
});
|
|
95
|
+
registrations.set(p.registrationKey, {
|
|
96
|
+
handle,
|
|
97
|
+
target: p.resolvedTarget
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
//#endregion
|
|
104
|
+
export { injectHotkeySequences };
|
|
105
|
+
//# sourceMappingURL=injectHotkeySequences.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"injectHotkeySequences.js","names":[],"sources":["../src/injectHotkeySequences.ts"],"sourcesContent":["import { DestroyRef, effect, inject } from '@angular/core'\nimport { formatHotkeySequence, getSequenceManager } from '@tanstack/hotkeys'\nimport { injectDefaultHotkeysOptions } from './hotkeys-provider'\nimport type { InjectHotkeySequenceOptions } from './injectHotkeySequence'\nimport type {\n HotkeyCallback,\n HotkeySequence,\n SequenceRegistrationHandle,\n} from '@tanstack/hotkeys'\n\n/**\n * A single sequence definition for use with `injectHotkeySequences`.\n */\nexport interface InjectHotkeySequenceDefinition {\n /** Array of hotkey strings that form the sequence */\n sequence: HotkeySequence | (() => HotkeySequence)\n /** The function to call when the sequence is completed */\n callback: HotkeyCallback\n /** Per-sequence options (merged on top of commonOptions) */\n options?: InjectHotkeySequenceOptions | (() => InjectHotkeySequenceOptions)\n}\n\n/**\n * Angular inject-based API for registering multiple keyboard shortcut sequences at once (Vim-style).\n *\n * Uses the singleton SequenceManager. Call in an injection context (e.g. constructor).\n * Uses `effect()` to track reactive dependencies when definitions or options are getters.\n *\n * Options are merged in this order:\n * provideHotkeys defaults < commonOptions < per-definition options\n *\n * Definitions with an empty `sequence` are skipped. Disabled sequences (`enabled: false`)\n * remain registered so they stay visible in devtools; the core manager suppresses execution.\n *\n * @param sequences - Array of sequence definitions, or getter returning them\n * @param commonOptions - Shared options for all sequences, or getter\n *\n * @example\n * ```ts\n * @Component({ ... })\n * export class VimComponent {\n * constructor() {\n * injectHotkeySequences([\n * { sequence: ['G', 'G'], callback: () => this.goTop() },\n * { sequence: ['D', 'D'], callback: () => this.deleteLine() },\n * ])\n * }\n * }\n * ```\n */\nexport function injectHotkeySequences(\n sequences:\n | Array<InjectHotkeySequenceDefinition>\n | (() => Array<InjectHotkeySequenceDefinition>),\n commonOptions:\n | InjectHotkeySequenceOptions\n | (() => InjectHotkeySequenceOptions) = {},\n): void {\n type RegistrationRecord = {\n handle: SequenceRegistrationHandle\n target: Document | HTMLElement | Window\n }\n\n const defaultOptions = injectDefaultHotkeysOptions()\n const manager = getSequenceManager()\n const destroyRef = inject(DestroyRef)\n\n const registrations = new Map<string, RegistrationRecord>()\n\n destroyRef.onDestroy(() => {\n for (const { handle } of registrations.values()) {\n if (handle.isActive) {\n handle.unregister()\n }\n }\n registrations.clear()\n })\n\n effect(() => {\n const resolvedSequences =\n typeof sequences === 'function' ? sequences() : sequences\n const resolvedCommonOptions =\n typeof commonOptions === 'function' ? commonOptions() : commonOptions\n\n const nextKeys = new Set<string>()\n const prepared: Array<{\n registrationKey: string\n def: InjectHotkeySequenceDefinition\n resolvedSequence: HotkeySequence\n enabled: boolean\n sequenceOpts: Omit<InjectHotkeySequenceOptions, 'enabled'>\n resolvedTarget: Document | HTMLElement | Window\n }> = []\n\n for (let i = 0; i < resolvedSequences.length; i++) {\n const def = resolvedSequences[i]!\n const resolvedSequence =\n typeof def.sequence === 'function' ? def.sequence() : def.sequence\n const resolvedDefOptions =\n typeof def.options === 'function' ? def.options() : (def.options ?? {})\n\n const mergedOptions = {\n ...defaultOptions.hotkeySequence,\n ...resolvedCommonOptions,\n ...resolvedDefOptions,\n } as InjectHotkeySequenceOptions\n\n const { enabled = true, ...sequenceOpts } = mergedOptions\n\n if (resolvedSequence.length === 0) {\n continue\n }\n\n const resolvedTarget =\n 'target' in sequenceOpts\n ? (sequenceOpts.target ?? null)\n : typeof document !== 'undefined'\n ? document\n : null\n\n if (!resolvedTarget) {\n continue\n }\n\n const registrationKey = `${i}:${formatHotkeySequence(resolvedSequence)}`\n nextKeys.add(registrationKey)\n prepared.push({\n registrationKey,\n def,\n resolvedSequence,\n enabled,\n sequenceOpts,\n resolvedTarget,\n })\n }\n\n for (const [key, record] of [...registrations.entries()]) {\n if (!nextKeys.has(key)) {\n if (record.handle.isActive) {\n record.handle.unregister()\n }\n registrations.delete(key)\n }\n }\n\n for (const p of prepared) {\n const existing = registrations.get(p.registrationKey)\n if (existing?.handle.isActive && existing.target === p.resolvedTarget) {\n existing.handle.callback = p.def.callback\n const { target: _target, ...optionsWithoutTarget } = p.sequenceOpts\n existing.handle.setOptions({\n ...optionsWithoutTarget,\n enabled: p.enabled,\n })\n continue\n }\n\n if (existing) {\n if (existing.handle.isActive) {\n existing.handle.unregister()\n }\n registrations.delete(p.registrationKey)\n }\n\n const handle = manager.register(p.resolvedSequence, p.def.callback, {\n ...p.sequenceOpts,\n enabled: p.enabled,\n target: p.resolvedTarget,\n })\n registrations.set(p.registrationKey, {\n handle,\n target: p.resolvedTarget,\n })\n }\n })\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAkDA,SAAgB,sBACd,WAGA,gBAE0C,EAAE,EACtC;CAMN,MAAM,iBAAiB,6BAA6B;CACpD,MAAM,UAAU,oBAAoB;CACpC,MAAM,aAAa,OAAO,WAAW;CAErC,MAAM,gCAAgB,IAAI,KAAiC;AAE3D,YAAW,gBAAgB;AACzB,OAAK,MAAM,EAAE,YAAY,cAAc,QAAQ,CAC7C,KAAI,OAAO,SACT,QAAO,YAAY;AAGvB,gBAAc,OAAO;GACrB;AAEF,cAAa;EACX,MAAM,oBACJ,OAAO,cAAc,aAAa,WAAW,GAAG;EAClD,MAAM,wBACJ,OAAO,kBAAkB,aAAa,eAAe,GAAG;EAE1D,MAAM,2BAAW,IAAI,KAAa;EAClC,MAAM,WAOD,EAAE;AAEP,OAAK,IAAI,IAAI,GAAG,IAAI,kBAAkB,QAAQ,KAAK;GACjD,MAAM,MAAM,kBAAkB;GAC9B,MAAM,mBACJ,OAAO,IAAI,aAAa,aAAa,IAAI,UAAU,GAAG,IAAI;GAC5D,MAAM,qBACJ,OAAO,IAAI,YAAY,aAAa,IAAI,SAAS,GAAI,IAAI,WAAW,EAAE;GAQxE,MAAM,EAAE,UAAU,MAAM,GAAG,iBANL;IACpB,GAAG,eAAe;IAClB,GAAG;IACH,GAAG;IACJ;AAID,OAAI,iBAAiB,WAAW,EAC9B;GAGF,MAAM,iBACJ,YAAY,eACP,aAAa,UAAU,OACxB,OAAO,aAAa,cAClB,WACA;AAER,OAAI,CAAC,eACH;GAGF,MAAM,kBAAkB,GAAG,EAAE,GAAG,qBAAqB,iBAAiB;AACtE,YAAS,IAAI,gBAAgB;AAC7B,YAAS,KAAK;IACZ;IACA;IACA;IACA;IACA;IACA;IACD,CAAC;;AAGJ,OAAK,MAAM,CAAC,KAAK,WAAW,CAAC,GAAG,cAAc,SAAS,CAAC,CACtD,KAAI,CAAC,SAAS,IAAI,IAAI,EAAE;AACtB,OAAI,OAAO,OAAO,SAChB,QAAO,OAAO,YAAY;AAE5B,iBAAc,OAAO,IAAI;;AAI7B,OAAK,MAAM,KAAK,UAAU;GACxB,MAAM,WAAW,cAAc,IAAI,EAAE,gBAAgB;AACrD,OAAI,UAAU,OAAO,YAAY,SAAS,WAAW,EAAE,gBAAgB;AACrE,aAAS,OAAO,WAAW,EAAE,IAAI;IACjC,MAAM,EAAE,QAAQ,SAAS,GAAG,yBAAyB,EAAE;AACvD,aAAS,OAAO,WAAW;KACzB,GAAG;KACH,SAAS,EAAE;KACZ,CAAC;AACF;;AAGF,OAAI,UAAU;AACZ,QAAI,SAAS,OAAO,SAClB,UAAS,OAAO,YAAY;AAE9B,kBAAc,OAAO,EAAE,gBAAgB;;GAGzC,MAAM,SAAS,QAAQ,SAAS,EAAE,kBAAkB,EAAE,IAAI,UAAU;IAClE,GAAG,EAAE;IACL,SAAS,EAAE;IACX,QAAQ,EAAE;IACX,CAAC;AACF,iBAAc,IAAI,EAAE,iBAAiB;IACnC;IACA,QAAQ,EAAE;IACX,CAAC;;GAEJ"}
|
package/package.json
CHANGED
package/src/index.ts
CHANGED
|
@@ -8,6 +8,7 @@ export * from './hotkeys-provider'
|
|
|
8
8
|
export * from './injectHotkey'
|
|
9
9
|
export * from './injectHotkeys'
|
|
10
10
|
export * from './injectHotkeySequence'
|
|
11
|
+
export * from './injectHotkeySequences'
|
|
11
12
|
export * from './injectHeldKeys'
|
|
12
13
|
export * from './injectHeldKeyCodes'
|
|
13
14
|
export * from './injectKeyHold'
|
package/src/injectHotkey.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { effect } from '@angular/core'
|
|
1
|
+
import { DestroyRef, effect, inject } from '@angular/core'
|
|
2
2
|
import {
|
|
3
3
|
detectPlatform,
|
|
4
4
|
formatHotkey,
|
|
@@ -10,6 +10,7 @@ import type {
|
|
|
10
10
|
Hotkey,
|
|
11
11
|
HotkeyCallback,
|
|
12
12
|
HotkeyOptions,
|
|
13
|
+
HotkeyRegistrationHandle,
|
|
13
14
|
RegisterableHotkey,
|
|
14
15
|
} from '@tanstack/hotkeys'
|
|
15
16
|
|
|
@@ -34,6 +35,8 @@ export interface InjectHotkeyOptions extends Omit<HotkeyOptions, 'target'> {
|
|
|
34
35
|
* Call in an injection context (e.g. constructor or field initializer).
|
|
35
36
|
* Uses effect() to track reactive dependencies and update registration
|
|
36
37
|
* when options or the callback change.
|
|
38
|
+
* `enabled: false` keeps the registration (visible in devtools) and only suppresses firing; the same
|
|
39
|
+
* handle is updated instead of unregistering and re-registering when identity is unchanged.
|
|
37
40
|
*
|
|
38
41
|
* @param hotkey - The hotkey string (e.g. 'Mod+S', 'Escape') or getter function
|
|
39
42
|
* @param callback - The function to call when the hotkey is pressed
|
|
@@ -87,8 +90,22 @@ export function injectHotkey(
|
|
|
87
90
|
): void {
|
|
88
91
|
const defaultOptions = injectDefaultHotkeysOptions()
|
|
89
92
|
const manager = getHotkeyManager()
|
|
93
|
+
const destroyRef = inject(DestroyRef)
|
|
90
94
|
|
|
91
|
-
|
|
95
|
+
let registration: HotkeyRegistrationHandle | null = null
|
|
96
|
+
let lastHotkeyString: Hotkey | null = null
|
|
97
|
+
let lastTarget: HTMLElement | Document | Window | null = null
|
|
98
|
+
|
|
99
|
+
destroyRef.onDestroy(() => {
|
|
100
|
+
if (registration?.isActive) {
|
|
101
|
+
registration.unregister()
|
|
102
|
+
registration = null
|
|
103
|
+
}
|
|
104
|
+
lastHotkeyString = null
|
|
105
|
+
lastTarget = null
|
|
106
|
+
})
|
|
107
|
+
|
|
108
|
+
effect(() => {
|
|
92
109
|
// Resolve reactive values
|
|
93
110
|
const resolvedHotkey = typeof hotkey === 'function' ? hotkey() : hotkey
|
|
94
111
|
const resolvedOptions = typeof options === 'function' ? options() : options
|
|
@@ -117,29 +134,44 @@ export function injectHotkey(
|
|
|
117
134
|
: null
|
|
118
135
|
|
|
119
136
|
if (!resolvedTarget) {
|
|
137
|
+
if (registration?.isActive) {
|
|
138
|
+
registration.unregister()
|
|
139
|
+
registration = null
|
|
140
|
+
}
|
|
141
|
+
lastHotkeyString = null
|
|
142
|
+
lastTarget = null
|
|
120
143
|
return
|
|
121
144
|
}
|
|
122
145
|
|
|
123
146
|
// Extract options without target (target is handled separately)
|
|
124
147
|
const { target: _target, ...optionsWithoutTarget } = mergedOptions
|
|
125
148
|
|
|
126
|
-
|
|
127
|
-
|
|
149
|
+
if (
|
|
150
|
+
registration?.isActive &&
|
|
151
|
+
lastHotkeyString === hotkeyString &&
|
|
152
|
+
lastTarget === resolvedTarget
|
|
153
|
+
) {
|
|
154
|
+
registration.callback = callback
|
|
155
|
+
registration.setOptions(optionsWithoutTarget)
|
|
156
|
+
return
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
if (registration?.isActive) {
|
|
160
|
+
registration.unregister()
|
|
161
|
+
registration = null
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
registration = manager.register(hotkeyString, callback, {
|
|
128
165
|
...optionsWithoutTarget,
|
|
129
166
|
target: resolvedTarget,
|
|
130
167
|
})
|
|
131
168
|
|
|
132
|
-
// Update callback and options on every effect run
|
|
133
169
|
if (registration.isActive) {
|
|
134
170
|
registration.callback = callback
|
|
135
171
|
registration.setOptions(optionsWithoutTarget)
|
|
136
172
|
}
|
|
137
173
|
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
if (registration.isActive) {
|
|
141
|
-
registration.unregister()
|
|
142
|
-
}
|
|
143
|
-
})
|
|
174
|
+
lastHotkeyString = hotkeyString
|
|
175
|
+
lastTarget = resolvedTarget
|
|
144
176
|
})
|
|
145
177
|
}
|
|
@@ -1,18 +1,27 @@
|
|
|
1
|
-
import { effect } from '@angular/core'
|
|
2
|
-
import { getSequenceManager } from '@tanstack/hotkeys'
|
|
1
|
+
import { DestroyRef, effect, inject } from '@angular/core'
|
|
2
|
+
import { formatHotkeySequence, getSequenceManager } from '@tanstack/hotkeys'
|
|
3
3
|
import { injectDefaultHotkeysOptions } from './hotkeys-provider'
|
|
4
4
|
import type {
|
|
5
5
|
HotkeyCallback,
|
|
6
6
|
HotkeySequence,
|
|
7
7
|
SequenceOptions,
|
|
8
|
+
SequenceRegistrationHandle,
|
|
8
9
|
} from '@tanstack/hotkeys'
|
|
9
10
|
|
|
11
|
+
type SequenceTarget = Document | HTMLElement | Window
|
|
12
|
+
|
|
10
13
|
export interface InjectHotkeySequenceOptions extends Omit<
|
|
11
14
|
SequenceOptions,
|
|
12
|
-
'enabled'
|
|
15
|
+
'enabled' | 'target'
|
|
13
16
|
> {
|
|
14
17
|
/** Whether the sequence is enabled. Defaults to true. */
|
|
15
18
|
enabled?: boolean
|
|
19
|
+
/**
|
|
20
|
+
* The DOM element to attach the event listener to.
|
|
21
|
+
* Can be a direct DOM element, an accessor target, or null.
|
|
22
|
+
* Defaults to document when omitted.
|
|
23
|
+
*/
|
|
24
|
+
target?: HTMLElement | Document | Window | null
|
|
16
25
|
}
|
|
17
26
|
|
|
18
27
|
/**
|
|
@@ -28,7 +37,8 @@ export interface InjectHotkeySequenceOptions extends Omit<
|
|
|
28
37
|
*
|
|
29
38
|
* @param sequence - Array of hotkey strings that form the sequence (or getter function)
|
|
30
39
|
* @param callback - Function to call when the sequence is completed
|
|
31
|
-
* @param options - Options for the sequence behavior (or getter function)
|
|
40
|
+
* @param options - Options for the sequence behavior (or getter function). `enabled: false` still registers
|
|
41
|
+
* the sequence (visible in devtools); only execution is suppressed.
|
|
32
42
|
*
|
|
33
43
|
* @example
|
|
34
44
|
* ```ts
|
|
@@ -53,8 +63,23 @@ export function injectHotkeySequence(
|
|
|
53
63
|
| (() => InjectHotkeySequenceOptions) = {},
|
|
54
64
|
): void {
|
|
55
65
|
const defaultOptions = injectDefaultHotkeysOptions()
|
|
66
|
+
const manager = getSequenceManager()
|
|
67
|
+
const destroyRef = inject(DestroyRef)
|
|
68
|
+
|
|
69
|
+
let handle: SequenceRegistrationHandle | null = null
|
|
70
|
+
let lastSequenceKey: string | null = null
|
|
71
|
+
let lastTarget: SequenceTarget | null = null
|
|
56
72
|
|
|
57
|
-
|
|
73
|
+
destroyRef.onDestroy(() => {
|
|
74
|
+
if (handle?.isActive) {
|
|
75
|
+
handle.unregister()
|
|
76
|
+
handle = null
|
|
77
|
+
}
|
|
78
|
+
lastSequenceKey = null
|
|
79
|
+
lastTarget = null
|
|
80
|
+
})
|
|
81
|
+
|
|
82
|
+
effect(() => {
|
|
58
83
|
// Resolve reactive values
|
|
59
84
|
const resolvedSequence =
|
|
60
85
|
typeof sequence === 'function' ? sequence() : sequence
|
|
@@ -67,27 +92,49 @@ export function injectHotkeySequence(
|
|
|
67
92
|
|
|
68
93
|
const { enabled = true, ...sequenceOptions } = mergedOptions
|
|
69
94
|
|
|
70
|
-
|
|
95
|
+
const resolvedTarget =
|
|
96
|
+
'target' in sequenceOptions
|
|
97
|
+
? (sequenceOptions.target ?? null)
|
|
98
|
+
: typeof document !== 'undefined'
|
|
99
|
+
? document
|
|
100
|
+
: null
|
|
101
|
+
|
|
102
|
+
if (resolvedSequence.length === 0 || !resolvedTarget) {
|
|
103
|
+
if (handle?.isActive) {
|
|
104
|
+
handle.unregister()
|
|
105
|
+
handle = null
|
|
106
|
+
}
|
|
107
|
+
lastSequenceKey = null
|
|
108
|
+
lastTarget = null
|
|
71
109
|
return
|
|
72
110
|
}
|
|
73
111
|
|
|
74
|
-
const
|
|
112
|
+
const sequenceKey = formatHotkeySequence(resolvedSequence)
|
|
75
113
|
|
|
76
|
-
|
|
77
|
-
const registerOptions: SequenceOptions = {
|
|
114
|
+
const registerPayload: SequenceOptions = {
|
|
78
115
|
...sequenceOptions,
|
|
79
|
-
enabled
|
|
80
|
-
target:
|
|
81
|
-
sequenceOptions.target ??
|
|
82
|
-
(typeof document !== 'undefined' ? document : undefined),
|
|
116
|
+
enabled,
|
|
117
|
+
target: resolvedTarget,
|
|
83
118
|
}
|
|
119
|
+
const { target: _t, ...optionsWithoutTarget } = registerPayload
|
|
84
120
|
|
|
85
|
-
|
|
121
|
+
if (
|
|
122
|
+
handle?.isActive &&
|
|
123
|
+
lastSequenceKey === sequenceKey &&
|
|
124
|
+
lastTarget === resolvedTarget
|
|
125
|
+
) {
|
|
126
|
+
handle.callback = callback
|
|
127
|
+
handle.setOptions(optionsWithoutTarget)
|
|
128
|
+
return
|
|
129
|
+
}
|
|
86
130
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
131
|
+
if (handle?.isActive) {
|
|
132
|
+
handle.unregister()
|
|
133
|
+
handle = null
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
handle = manager.register(resolvedSequence, callback, registerPayload)
|
|
137
|
+
lastSequenceKey = sequenceKey
|
|
138
|
+
lastTarget = resolvedTarget
|
|
92
139
|
})
|
|
93
140
|
}
|